Skip to content

Commit a063f5b

Browse files
authored
SOV-3922: fix typedData functionality for smart router (#907)
* wip: reworking permits * wip: reworking permits * feat: reworking permits on smart router * chore: add changeset * chore: update readme * chore: remove console log
1 parent cbe838f commit a063f5b

File tree

21 files changed

+331
-237
lines changed

21 files changed

+331
-237
lines changed

.changeset/modern-boxes-enjoy.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@sovryn/sdk': patch
3+
---
4+
5+
SOV-3922: move typedData / permits to smart router

apps/frontend/src/app/3_organisms/TransactionStepDialog/TransactionStepDialog.types.ts

+8-2
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ export enum TransactionType {
5050
signTypedData = 'signTypedData',
5151
signTransaction = 'signTransaction',
5252
signTransactionData = 'signTransactionData',
53+
/**
54+
* @deprecated Use `signTypedData` instead.
55+
*/
5356
signPermit = 'signPermit',
5457
}
5558

@@ -64,9 +67,12 @@ export type SignTypedDataRequest = {
6467
signer: JsonRpcSigner;
6568
domain: TypedDataDomain;
6669
types: Record<string, Array<TypedDataField>>;
67-
value: Record<string, any>;
70+
values: Record<string, any>;
6871
};
6972

73+
/**
74+
* @deprecated Use TypedDataTransactionRequest instead
75+
*/
7076
export type SignPermitRequest = {
7177
type: TransactionType.signPermit;
7278
signer: JsonRpcSigner;
@@ -115,5 +121,5 @@ export enum TransactionReceiptStatus {
115121
export type TransactionReceipt = {
116122
status: TransactionReceiptStatus;
117123
request: TransactionRequest;
118-
response?: string | PermitTransactionResponse;
124+
response?: string;
119125
};

apps/frontend/src/app/3_organisms/TransactionStepDialog/components/TransactionSteps/TransactionSteps.tsx

+15-24
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import { translations } from '../../../../../locales/i18n';
2222
import { findNativeAsset } from '../../../../../utils/asset';
2323
import { sleep } from '../../../../../utils/helpers';
2424
import { fromWei, toWei } from '../../../../../utils/math';
25-
import { signERC2612Permit } from '../../../../../utils/permit/permit';
2625
import {
2726
Transaction,
2827
TransactionReceiptStatus,
@@ -32,7 +31,6 @@ import {
3231
} from '../../TransactionStepDialog.types';
3332
import {
3433
isMessageSignatureRequest,
35-
isPermitRequest,
3634
isSignTransactionDataRequest,
3735
isTransactionRequest,
3836
isTypedDataRequest,
@@ -267,37 +265,30 @@ export const TransactionSteps: FC<TransactionStepsProps> = ({
267265
const signature = await request.signer._signTypedData(
268266
request.domain,
269267
request.types,
270-
request.value,
268+
request.values,
271269
);
272270

273-
transactions[i].onChangeStatus?.(StatusType.success);
274-
transactions[i].onComplete?.(signature);
275-
276-
updateReceipt(i, {
277-
status: TransactionReceiptStatus.success,
278-
request,
279-
response: signature,
280-
});
281-
282-
await handleUpdates();
283-
} else if (isPermitRequest(request)) {
284-
const response = await signERC2612Permit(
285-
request.signer,
286-
request.token,
287-
request.owner,
288-
request.spender,
289-
request.value,
290-
request.deadline,
291-
request.nonce,
271+
const verifiedAddress = ethers.utils.verifyTypedData(
272+
request.domain,
273+
request.types,
274+
request.values,
275+
signature,
292276
);
293277

278+
if (
279+
verifiedAddress.toLowerCase() !==
280+
(await request.signer.getAddress()).toLowerCase()
281+
) {
282+
throw new Error('Failed to verify signature. ');
283+
}
284+
294285
transactions[i].onChangeStatus?.(StatusType.success);
295-
transactions[i].onComplete?.(response);
286+
transactions[i].onComplete?.(signature);
296287

297288
updateReceipt(i, {
298289
status: TransactionReceiptStatus.success,
299290
request,
300-
response,
291+
response: signature,
301292
});
302293

303294
await handleUpdates();

apps/frontend/src/app/3_organisms/TransactionStepDialog/helpers.ts

-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import {
22
SignMessageRequest,
3-
SignPermitRequest,
43
SignTransactionDataRequest,
54
SignTransactionRequest,
65
SignTypedDataRequest,
@@ -27,7 +26,3 @@ export const isSignTransactionDataRequest = (
2726
request: TransactionRequest,
2827
): request is SignTransactionDataRequest =>
2928
request.type === TransactionType.signTransactionData;
30-
31-
export const isPermitRequest = (
32-
request: TransactionRequest,
33-
): request is SignPermitRequest => request.type === TransactionType.signPermit;

apps/frontend/src/app/5_pages/ConvertPage/ConvertPage.constants.ts

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export const SWAP_ROUTES = [
1616
smartRoutes.myntFixedRateRoute,
1717
smartRoutes.mocIntegrationSwapRoute,
1818
smartRoutes.ambientRoute,
19+
smartRoutes.zeroRedemptionSwapRoute,
1920
];
2021

2122
export const SMART_ROUTER_RSK = new SmartRouter(

apps/frontend/src/app/5_pages/ConvertPage/hooks/useHandleConversion.ts

+35-98
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
import { PERMIT2_ADDRESS, PermitTransferFrom } from '@uniswap/permit2-sdk';
2-
31
import { useCallback } from 'react';
42

53
import { BigNumber, ethers } from 'ethers';
64
import { t } from 'i18next';
75

86
import { getAssetData, getProtocolContract } from '@sovryn/contracts';
9-
import { PermitTransactionResponse, SwapRoute } from '@sovryn/sdk';
7+
import { SwapRoute } from '@sovryn/sdk';
108

119
import {
1210
Transaction,
@@ -19,18 +17,13 @@ import { useTransactionContext } from '../../../../contexts/TransactionContext';
1917
import { useAccount } from '../../../../hooks/useAccount';
2018
import { useCurrentChain } from '../../../../hooks/useChainStore';
2119
import { translations } from '../../../../locales/i18n';
22-
import { COMMON_SYMBOLS } from '../../../../utils/asset';
2320
import {
2421
DEFAULT_SIGNATURE,
2522
EMPTY_PERMIT_TRANSFER_FROM,
26-
getPermitTransferFrom,
2723
permitHandler,
2824
prepareApproveTransaction,
29-
preparePermit2Transaction,
30-
preparePermitTransaction,
31-
UNSIGNED_PERMIT,
25+
prepareTypedDataTransaction,
3226
} from '../../../../utils/transactions';
33-
import { getRouteContract } from '../ConvertPage.utils';
3427

3528
export const useHandleConversion = (
3629
sourceToken: string,
@@ -138,91 +131,49 @@ export const useHandleConversion = (
138131
return;
139132
}
140133

141-
const requiresPermit2 =
142-
!!route && ['ZeroRedemption', 'MocIntegration'].includes(route.name);
143-
144134
const [sourceTokenDetails, destinationTokenDetails] = await Promise.all([
145135
getAssetData(sourceToken, currentChainId),
146136
getAssetData(destinationToken, currentChainId),
147137
]);
148138

149-
const approveTxData = await route.approve(
150-
sourceTokenDetails.address,
151-
destinationTokenDetails.address,
152-
weiAmount,
153-
account,
154-
);
155-
156139
const transactions: Transaction[] = [];
157140

158-
if (requiresPermit2) {
159-
const approveTx = await prepareApproveTransaction({
160-
token: COMMON_SYMBOLS.DLLR,
161-
spender: PERMIT2_ADDRESS,
162-
amount: weiAmount,
163-
signer,
164-
approveMaximumAmount: true,
165-
});
166-
167-
if (approveTx) {
168-
transactions.push(approveTx);
169-
}
170-
}
171-
172-
if (
173-
!requiresPermit2 &&
174-
approveTxData &&
175-
approveTxData.to &&
176-
approveTxData.data
177-
) {
178-
transactions.push({
179-
title: t(translations.convertPage.txDialog.approve, {
180-
asset: getTokenDisplayName(sourceToken),
181-
}),
182-
request: {
183-
type: TransactionType.signTransactionData,
184-
signer: signer,
185-
to: approveTxData.to,
186-
data: approveTxData.data,
187-
gasLimit: approveTxData.gasLimit ?? GAS_LIMIT.APPROVE,
188-
},
189-
onComplete,
190-
});
191-
}
192-
193141
const permitTxData = await route.permit(
194142
sourceTokenDetails.address,
195143
destinationTokenDetails.address,
196144
weiAmount,
197145
account,
198146
);
199147

200-
if (!requiresPermit2 && permitTxData) {
148+
if (permitTxData) {
201149
transactions.push(
202-
await preparePermitTransaction({
203-
token: sourceTokenDetails.symbol,
204-
signer,
205-
spender: permitTxData.spender,
206-
value: permitTxData.value?.toString(),
207-
deadline: permitTxData.deadline,
208-
nonce: permitTxData.nonce,
209-
}),
150+
await prepareTypedDataTransaction(permitTxData, signer),
210151
);
211152
}
212153

213-
let permitTransferFrom: PermitTransferFrom;
214-
215-
if (requiresPermit2) {
216-
const contract = await getRouteContract(route, signer);
217-
218-
permitTransferFrom = await getPermitTransferFrom(
219-
contract.address,
220-
weiAmount.toString(),
154+
if (!permitTxData || permitTxData.approvalRequired) {
155+
const approveTxData = await route.approve(
156+
sourceTokenDetails.address,
157+
destinationTokenDetails.address,
158+
weiAmount,
159+
account,
221160
);
222161

223-
transactions.push(
224-
await preparePermit2Transaction(permitTransferFrom, signer),
225-
);
162+
if (approveTxData) {
163+
transactions.push({
164+
title: t(translations.convertPage.txDialog.approve, {
165+
asset: getTokenDisplayName(sourceToken),
166+
}),
167+
request: {
168+
type: TransactionType.signTransactionData,
169+
signer: signer,
170+
to: approveTxData.to!,
171+
data: approveTxData.data!,
172+
gasLimit: approveTxData.gasLimit ?? GAS_LIMIT.APPROVE,
173+
},
174+
onComplete,
175+
});
176+
}
226177
}
227178

228179
const txData = await route.swap(
@@ -231,59 +182,45 @@ export const useHandleConversion = (
231182
weiAmount,
232183
account,
233184
{
234-
permit: permitTxData ? UNSIGNED_PERMIT : undefined,
235-
permitTransferFrom: requiresPermit2
236-
? EMPTY_PERMIT_TRANSFER_FROM
237-
: undefined,
238-
signature: DEFAULT_SIGNATURE,
185+
typedDataValue: permitTxData
186+
? permitTxData.typedData.values
187+
: EMPTY_PERMIT_TRANSFER_FROM,
188+
typedDataSignature: DEFAULT_SIGNATURE,
239189
slippage: Number(slippageTolerance) * 100,
240190
},
241191
);
242192

243-
if (txData && txData.to && txData.data) {
193+
if (txData) {
244194
transactions.push({
245195
title: t(translations.convertPage.txDialog.convert, {
246196
asset: getTokenDisplayName(sourceToken),
247197
}),
248198
request: {
249199
type: TransactionType.signTransactionData,
250200
signer: signer,
251-
to: txData.to,
252-
data: txData.data,
201+
to: txData.to!,
202+
data: txData.data!,
253203
value: txData.value,
254204
gasLimit: txData?.gasLimit ?? GAS_LIMIT.CONVERT,
255205
gasPrice: txData?.gasPrice?.toString(),
256206
},
257207
onComplete,
258208
updateHandler: permitHandler(async (req, res) => {
259209
if (isSignTransactionDataRequest(req)) {
260-
if (!requiresPermit2 && !!permitTxData) {
210+
if (!!permitTxData) {
261211
const { data } = await route.swap(
262212
sourceTokenDetails.address,
263213
destinationTokenDetails.address,
264214
weiAmount,
265215
account,
266216
{
267-
permit: res as PermitTransactionResponse,
217+
typedDataValue: permitTxData.typedData.values,
218+
typedDataSignature: res as string,
268219
slippage: Number(slippageTolerance) * 100,
269220
},
270221
);
271222
req.data = data!;
272223
}
273-
274-
if (requiresPermit2 && !!permitTransferFrom) {
275-
const { data } = await route.swap(
276-
sourceTokenDetails.address,
277-
destinationTokenDetails.address,
278-
weiAmount,
279-
account,
280-
{
281-
permitTransferFrom,
282-
signature: typeof res === 'string' ? res : '',
283-
},
284-
);
285-
req.data = data!;
286-
}
287224
}
288225
return req;
289226
}),

apps/frontend/src/utils/graphql/bob/generated.tsx

-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { gql } from '@apollo/client';
22
import * as Apollo from '@apollo/client';
3-
43
export type Maybe<T> = T | null;
54
export type InputMaybe<T> = Maybe<T>;
65
export type Exact<T extends { [key: string]: unknown }> = {

apps/frontend/src/utils/graphql/mynt/generated.tsx

-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { gql } from '@apollo/client';
22
import * as Apollo from '@apollo/client';
3-
43
export type Maybe<T> = T | null;
54
export type InputMaybe<T> = Maybe<T>;
65
export type Exact<T extends { [key: string]: unknown }> = {

apps/frontend/src/utils/graphql/rsk/generated.tsx

-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { gql } from '@apollo/client';
22
import * as Apollo from '@apollo/client';
3-
43
export type Maybe<T> = T | null;
54
export type InputMaybe<T> = Maybe<T>;
65
export type Exact<T extends { [key: string]: unknown }> = {

apps/frontend/src/utils/graphql/zero/generated.tsx

-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { gql } from '@apollo/client';
22
import * as Apollo from '@apollo/client';
3-
43
export type Maybe<T> = T | null;
54
export type InputMaybe<T> = Maybe<T>;
65
export type Exact<T extends { [key: string]: unknown }> = {

0 commit comments

Comments
 (0)