@lifi/sdk 3.4.2 → 3.5.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/_cjs/constants.js +4 -2
- package/src/_cjs/constants.js.map +1 -1
- package/src/_cjs/core/EVM/EVM.js +0 -4
- package/src/_cjs/core/EVM/EVM.js.map +1 -1
- package/src/_cjs/core/EVM/EVMStepExecutor.js +96 -74
- package/src/_cjs/core/EVM/EVMStepExecutor.js.map +1 -1
- package/src/_cjs/core/EVM/abi.js +36 -43
- package/src/_cjs/core/EVM/abi.js.map +1 -1
- package/src/_cjs/core/EVM/checkAllowance.js +36 -30
- package/src/_cjs/core/EVM/checkAllowance.js.map +1 -1
- package/src/_cjs/core/EVM/getAllowance.js.map +1 -1
- package/src/_cjs/core/EVM/getEVMBalance.js.map +1 -1
- package/src/_cjs/core/EVM/getNativePermit.js +90 -0
- package/src/_cjs/core/EVM/getNativePermit.js.map +1 -0
- package/src/_cjs/core/EVM/parseEVMErrors.js +3 -0
- package/src/_cjs/core/EVM/parseEVMErrors.js.map +1 -1
- package/src/_cjs/core/EVM/permit2/allowanceTransfer.js +100 -0
- package/src/_cjs/core/EVM/permit2/allowanceTransfer.js.map +1 -0
- package/src/_cjs/core/EVM/permit2/constants.js +12 -0
- package/src/_cjs/core/EVM/permit2/constants.js.map +1 -0
- package/src/_cjs/core/EVM/permit2/domain.js +12 -0
- package/src/_cjs/core/EVM/permit2/domain.js.map +1 -0
- package/src/_cjs/core/EVM/permit2/signatureTransfer.js +121 -0
- package/src/_cjs/core/EVM/permit2/signatureTransfer.js.map +1 -0
- package/src/_cjs/core/EVM/setAllowance.js +3 -4
- package/src/_cjs/core/EVM/setAllowance.js.map +1 -1
- package/src/_cjs/core/EVM/signPermitMessage.js +168 -0
- package/src/_cjs/core/EVM/signPermitMessage.js.map +1 -0
- package/src/_cjs/core/EVM/types.js.map +1 -1
- package/src/_cjs/core/EVM/utils.js +2 -1
- package/src/_cjs/core/EVM/utils.js.map +1 -1
- package/src/_cjs/core/EVM/waitForBatchTransactionReceipt.js +29 -0
- package/src/_cjs/core/EVM/waitForBatchTransactionReceipt.js.map +1 -0
- package/src/_cjs/core/checkBalance.js +3 -3
- package/src/_cjs/core/checkBalance.js.map +1 -1
- package/src/_cjs/index.js.map +1 -1
- package/src/_cjs/utils/invariant.js +17 -0
- package/src/_cjs/utils/invariant.js.map +1 -0
- package/src/_cjs/version.js +1 -1
- package/src/_cjs/version.js.map +1 -1
- package/src/_esm/constants.js +3 -1
- package/src/_esm/constants.js.map +1 -1
- package/src/_esm/core/EVM/EVM.js +0 -4
- package/src/_esm/core/EVM/EVM.js.map +1 -1
- package/src/_esm/core/EVM/EVMStepExecutor.js +124 -84
- package/src/_esm/core/EVM/EVMStepExecutor.js.map +1 -1
- package/src/_esm/core/EVM/abi.js +37 -42
- package/src/_esm/core/EVM/abi.js.map +1 -1
- package/src/_esm/core/EVM/checkAllowance.js +41 -32
- package/src/_esm/core/EVM/checkAllowance.js.map +1 -1
- package/src/_esm/core/EVM/getAllowance.js.map +1 -1
- package/src/_esm/core/EVM/getEVMBalance.js.map +1 -1
- package/src/_esm/core/EVM/getNativePermit.js +95 -0
- package/src/_esm/core/EVM/getNativePermit.js.map +1 -0
- package/src/_esm/core/EVM/parseEVMErrors.js +8 -0
- package/src/_esm/core/EVM/parseEVMErrors.js.map +1 -1
- package/src/_esm/core/EVM/permit2/allowanceTransfer.js +93 -0
- package/src/_esm/core/EVM/permit2/allowanceTransfer.js.map +1 -0
- package/src/_esm/core/EVM/permit2/constants.js +9 -0
- package/src/_esm/core/EVM/permit2/constants.js.map +1 -0
- package/src/_esm/core/EVM/permit2/domain.js +9 -0
- package/src/_esm/core/EVM/permit2/domain.js.map +1 -0
- package/src/_esm/core/EVM/permit2/signatureTransfer.js +117 -0
- package/src/_esm/core/EVM/permit2/signatureTransfer.js.map +1 -0
- package/src/_esm/core/EVM/setAllowance.js +3 -4
- package/src/_esm/core/EVM/setAllowance.js.map +1 -1
- package/src/_esm/core/EVM/signPermitMessage.js +162 -0
- package/src/_esm/core/EVM/signPermitMessage.js.map +1 -0
- package/src/_esm/core/EVM/types.js.map +1 -1
- package/src/_esm/core/EVM/utils.js +2 -1
- package/src/_esm/core/EVM/utils.js.map +1 -1
- package/src/_esm/core/EVM/waitForBatchTransactionReceipt.js +25 -0
- package/src/_esm/core/EVM/waitForBatchTransactionReceipt.js.map +1 -0
- package/src/_esm/core/checkBalance.js +3 -3
- package/src/_esm/core/checkBalance.js.map +1 -1
- package/src/_esm/index.js.map +1 -1
- package/src/_esm/utils/invariant.js +43 -0
- package/src/_esm/utils/invariant.js.map +1 -0
- package/src/_esm/version.js +1 -1
- package/src/_esm/version.js.map +1 -1
- package/src/_types/constants.d.ts +3 -1
- package/src/_types/constants.d.ts.map +1 -1
- package/src/_types/core/EVM/EVM.d.ts.map +1 -1
- package/src/_types/core/EVM/EVMStepExecutor.d.ts +7 -4
- package/src/_types/core/EVM/EVMStepExecutor.d.ts.map +1 -1
- package/src/_types/core/EVM/abi.d.ts +202 -5
- package/src/_types/core/EVM/abi.d.ts.map +1 -1
- package/src/_types/core/EVM/checkAllowance.d.ts +12 -2
- package/src/_types/core/EVM/checkAllowance.d.ts.map +1 -1
- package/src/_types/core/EVM/getAllowance.d.ts +5 -4
- package/src/_types/core/EVM/getAllowance.d.ts.map +1 -1
- package/src/_types/core/EVM/getEVMBalance.d.ts +2 -1
- package/src/_types/core/EVM/getEVMBalance.d.ts.map +1 -1
- package/src/_types/core/EVM/getNativePermit.d.ts +18 -0
- package/src/_types/core/EVM/getNativePermit.d.ts.map +1 -0
- package/src/_types/core/EVM/permit2/allowanceTransfer.d.ts +41 -0
- package/src/_types/core/EVM/permit2/allowanceTransfer.d.ts.map +1 -0
- package/src/_types/core/EVM/permit2/constants.d.ts +8 -0
- package/src/_types/core/EVM/permit2/constants.d.ts.map +1 -0
- package/src/_types/core/EVM/permit2/domain.d.ts +8 -0
- package/src/_types/core/EVM/permit2/domain.d.ts.map +1 -0
- package/src/_types/core/EVM/permit2/signatureTransfer.d.ts +42 -0
- package/src/_types/core/EVM/permit2/signatureTransfer.d.ts.map +1 -0
- package/src/_types/core/EVM/setAllowance.d.ts +2 -2
- package/src/_types/core/EVM/setAllowance.d.ts.map +1 -1
- package/src/_types/core/EVM/signPermitMessage.d.ts +22 -0
- package/src/_types/core/EVM/signPermitMessage.d.ts.map +1 -0
- package/src/_types/core/EVM/types.d.ts +1 -18
- package/src/_types/core/EVM/types.d.ts.map +1 -1
- package/src/_types/core/EVM/utils.d.ts +2 -2
- package/src/_types/core/EVM/utils.d.ts.map +1 -1
- package/src/_types/core/EVM/waitForBatchTransactionReceipt.d.ts +4 -0
- package/src/_types/core/EVM/waitForBatchTransactionReceipt.d.ts.map +1 -0
- package/src/_types/core/checkBalance.d.ts.map +1 -1
- package/src/_types/index.d.ts +1 -1
- package/src/_types/index.d.ts.map +1 -1
- package/src/_types/utils/invariant.d.ts +22 -0
- package/src/_types/utils/invariant.d.ts.map +1 -0
- package/src/_types/version.d.ts +1 -1
- package/src/_types/version.d.ts.map +1 -1
- package/src/constants.ts +6 -1
- package/src/core/EVM/EVM.ts +0 -4
- package/src/core/EVM/EVMStepExecutor.ts +177 -134
- package/src/core/EVM/abi.ts +40 -43
- package/src/core/EVM/checkAllowance.ts +96 -92
- package/src/core/EVM/getAllowance.ts +8 -8
- package/src/core/EVM/getEVMBalance.ts +2 -2
- package/src/core/EVM/getNativePermit.ts +113 -0
- package/src/core/EVM/parseEVMErrors.ts +8 -0
- package/src/core/EVM/permit2/allowanceTransfer.ts +168 -0
- package/src/core/EVM/permit2/constants.ts +11 -0
- package/src/core/EVM/permit2/domain.ts +20 -0
- package/src/core/EVM/permit2/signatureTransfer.ts +214 -0
- package/src/core/EVM/setAllowance.ts +14 -15
- package/src/core/EVM/signPermitMessage.ts +248 -0
- package/src/core/EVM/types.ts +1 -27
- package/src/core/EVM/utils.ts +4 -3
- package/src/core/EVM/waitForBatchTransactionReceipt.ts +49 -0
- package/src/core/checkBalance.ts +6 -3
- package/src/index.ts +0 -3
- package/src/utils/invariant.ts +51 -0
- package/src/version.ts +1 -1
- package/src/_cjs/core/EVM/multisig.js +0 -29
- package/src/_cjs/core/EVM/multisig.js.map +0 -1
- package/src/_esm/core/EVM/multisig.js +0 -25
- package/src/_esm/core/EVM/multisig.js.map +0 -1
- package/src/_types/core/EVM/multisig.d.ts +0 -6
- package/src/_types/core/EVM/multisig.d.ts.map +0 -1
- package/src/core/EVM/multisig.ts +0 -54
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ExtendedChain, LiFiStep, Process, ProcessType } from '@lifi/types'
|
|
2
2
|
import type { Address, Client, Hash } from 'viem'
|
|
3
|
+
import { MaxUint256 } from '../../constants.js'
|
|
3
4
|
import type { StatusManager } from '../StatusManager.js'
|
|
4
5
|
import type { ExecutionOptions } from '../types.js'
|
|
5
6
|
import { getAllowance } from './getAllowance.js'
|
|
@@ -7,108 +8,107 @@ import { parseEVMErrors } from './parseEVMErrors.js'
|
|
|
7
8
|
import { setAllowance } from './setAllowance.js'
|
|
8
9
|
import { waitForTransactionReceipt } from './waitForTransactionReceipt.js'
|
|
9
10
|
|
|
10
|
-
export
|
|
11
|
-
client: Client
|
|
12
|
-
chain:
|
|
13
|
-
step: LiFiStep
|
|
14
|
-
statusManager: StatusManager
|
|
15
|
-
|
|
11
|
+
export type CheckAllowanceParams = {
|
|
12
|
+
client: Client
|
|
13
|
+
chain: ExtendedChain
|
|
14
|
+
step: LiFiStep
|
|
15
|
+
statusManager: StatusManager
|
|
16
|
+
executionOptions?: ExecutionOptions
|
|
17
|
+
allowUserInteraction?: boolean
|
|
18
|
+
atomicBatchSupported?: boolean
|
|
19
|
+
permit2Supported?: boolean
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const checkAllowance = async ({
|
|
23
|
+
client,
|
|
24
|
+
chain,
|
|
25
|
+
step,
|
|
26
|
+
statusManager,
|
|
27
|
+
executionOptions,
|
|
16
28
|
allowUserInteraction = false,
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
29
|
+
atomicBatchSupported = false,
|
|
30
|
+
permit2Supported = false,
|
|
31
|
+
}: CheckAllowanceParams): Promise<Hash | void> => {
|
|
32
|
+
// Find existing or create new allowance process
|
|
33
|
+
const allowanceProcess: Process = statusManager.findOrCreateProcess({
|
|
21
34
|
step,
|
|
22
35
|
type: 'TOKEN_ALLOWANCE',
|
|
23
36
|
chainId: step.action.fromChainId,
|
|
24
37
|
})
|
|
25
38
|
|
|
26
|
-
// Check allowance
|
|
27
39
|
try {
|
|
40
|
+
// Handle existing pending transaction
|
|
28
41
|
if (allowanceProcess.txHash && allowanceProcess.status !== 'DONE') {
|
|
29
42
|
await waitForApprovalTransaction(
|
|
30
43
|
client,
|
|
31
|
-
allowanceProcess.txHash
|
|
44
|
+
allowanceProcess.txHash as Address,
|
|
32
45
|
allowanceProcess.type,
|
|
33
46
|
step,
|
|
34
47
|
chain,
|
|
35
48
|
statusManager
|
|
36
49
|
)
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
step,
|
|
40
|
-
allowanceProcess.type,
|
|
41
|
-
'STARTED'
|
|
42
|
-
)
|
|
50
|
+
return
|
|
51
|
+
}
|
|
43
52
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
step.action.fromToken.address,
|
|
47
|
-
client.account!.address,
|
|
48
|
-
step.estimate.approvalAddress
|
|
49
|
-
)
|
|
53
|
+
// Start new allowance check
|
|
54
|
+
statusManager.updateProcess(step, allowanceProcess.type, 'STARTED')
|
|
50
55
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
allowanceProcess = statusManager.updateProcess(
|
|
69
|
-
step,
|
|
70
|
-
allowanceProcess.type,
|
|
71
|
-
'DONE'
|
|
72
|
-
)
|
|
73
|
-
|
|
74
|
-
return approveTxHash
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const approveTxHash = await setAllowance(
|
|
78
|
-
client,
|
|
79
|
-
step.action.fromToken.address,
|
|
80
|
-
step.estimate.approvalAddress,
|
|
81
|
-
fromAmount
|
|
82
|
-
)
|
|
83
|
-
await waitForApprovalTransaction(
|
|
84
|
-
client,
|
|
85
|
-
approveTxHash,
|
|
86
|
-
allowanceProcess.type,
|
|
87
|
-
step,
|
|
88
|
-
chain,
|
|
89
|
-
statusManager
|
|
90
|
-
)
|
|
91
|
-
} else {
|
|
92
|
-
allowanceProcess = statusManager.updateProcess(
|
|
93
|
-
step,
|
|
94
|
-
allowanceProcess.type,
|
|
95
|
-
'DONE'
|
|
96
|
-
)
|
|
97
|
-
}
|
|
56
|
+
const spenderAddress = permit2Supported
|
|
57
|
+
? chain.permit2
|
|
58
|
+
: step.estimate.approvalAddress
|
|
59
|
+
const fromAmount = BigInt(step.action.fromAmount)
|
|
60
|
+
|
|
61
|
+
const approved = await getAllowance(
|
|
62
|
+
chain.id,
|
|
63
|
+
step.action.fromToken.address as Address,
|
|
64
|
+
client.account!.address,
|
|
65
|
+
spenderAddress as Address
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
// Return early if already approved
|
|
69
|
+
if (fromAmount <= approved) {
|
|
70
|
+
statusManager.updateProcess(step, allowanceProcess.type, 'DONE')
|
|
71
|
+
return
|
|
98
72
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
73
|
+
|
|
74
|
+
if (!allowUserInteraction) {
|
|
75
|
+
return
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
statusManager.updateProcess(step, allowanceProcess.type, 'ACTION_REQUIRED')
|
|
79
|
+
|
|
80
|
+
// Set new allowance
|
|
81
|
+
const approveAmount = permit2Supported ? MaxUint256 : fromAmount
|
|
82
|
+
const approveTxHash = await setAllowance(
|
|
83
|
+
client,
|
|
84
|
+
step.action.fromToken.address as Address,
|
|
85
|
+
spenderAddress as Address,
|
|
86
|
+
approveAmount,
|
|
87
|
+
executionOptions,
|
|
88
|
+
atomicBatchSupported
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
if (atomicBatchSupported) {
|
|
92
|
+
statusManager.updateProcess(step, allowanceProcess.type, 'DONE')
|
|
93
|
+
return approveTxHash
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
await waitForApprovalTransaction(
|
|
97
|
+
client,
|
|
98
|
+
approveTxHash,
|
|
103
99
|
allowanceProcess.type,
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
message: error.cause.message,
|
|
108
|
-
code: error.code,
|
|
109
|
-
},
|
|
110
|
-
}
|
|
100
|
+
step,
|
|
101
|
+
chain,
|
|
102
|
+
statusManager
|
|
111
103
|
)
|
|
104
|
+
} catch (e: any) {
|
|
105
|
+
const error = await parseEVMErrors(e, step, allowanceProcess)
|
|
106
|
+
statusManager.updateProcess(step, allowanceProcess.type, 'FAILED', {
|
|
107
|
+
error: {
|
|
108
|
+
message: error.cause.message,
|
|
109
|
+
code: error.code,
|
|
110
|
+
},
|
|
111
|
+
})
|
|
112
112
|
statusManager.updateExecution(step, 'FAILED')
|
|
113
113
|
throw error
|
|
114
114
|
}
|
|
@@ -119,29 +119,33 @@ const waitForApprovalTransaction = async (
|
|
|
119
119
|
txHash: Hash,
|
|
120
120
|
processType: ProcessType,
|
|
121
121
|
step: LiFiStep,
|
|
122
|
-
chain:
|
|
122
|
+
chain: ExtendedChain,
|
|
123
123
|
statusManager: StatusManager
|
|
124
124
|
) => {
|
|
125
|
+
const baseExplorerUrl = chain.metamask.blockExplorerUrls[0]
|
|
126
|
+
const getTxLink = (hash: Hash) => `${baseExplorerUrl}tx/${hash}`
|
|
127
|
+
|
|
125
128
|
statusManager.updateProcess(step, processType, 'PENDING', {
|
|
126
129
|
txHash,
|
|
127
|
-
txLink:
|
|
130
|
+
txLink: getTxLink(txHash),
|
|
128
131
|
})
|
|
129
132
|
|
|
130
133
|
const transactionReceipt = await waitForTransactionReceipt({
|
|
131
|
-
client
|
|
134
|
+
client,
|
|
132
135
|
chainId: chain.id,
|
|
133
|
-
txHash
|
|
136
|
+
txHash,
|
|
134
137
|
onReplaced(response) {
|
|
138
|
+
const newHash = response.transaction.hash
|
|
135
139
|
statusManager.updateProcess(step, processType, 'PENDING', {
|
|
136
|
-
txHash:
|
|
137
|
-
txLink:
|
|
140
|
+
txHash: newHash,
|
|
141
|
+
txLink: getTxLink(newHash),
|
|
138
142
|
})
|
|
139
143
|
},
|
|
140
144
|
})
|
|
141
145
|
|
|
142
|
-
const
|
|
146
|
+
const finalHash = transactionReceipt?.transactionHash || txHash
|
|
143
147
|
statusManager.updateProcess(step, processType, 'DONE', {
|
|
144
|
-
txHash:
|
|
145
|
-
txLink:
|
|
148
|
+
txHash: finalHash,
|
|
149
|
+
txLink: getTxLink(finalHash),
|
|
146
150
|
})
|
|
147
151
|
}
|
|
@@ -13,9 +13,9 @@ import { getMulticallAddress } from './utils.js'
|
|
|
13
13
|
|
|
14
14
|
export const getAllowance = async (
|
|
15
15
|
chainId: ChainId,
|
|
16
|
-
tokenAddress:
|
|
17
|
-
ownerAddress:
|
|
18
|
-
spenderAddress:
|
|
16
|
+
tokenAddress: Address,
|
|
17
|
+
ownerAddress: Address,
|
|
18
|
+
spenderAddress: Address
|
|
19
19
|
): Promise<bigint> => {
|
|
20
20
|
const client = await getPublicClient(chainId)
|
|
21
21
|
try {
|
|
@@ -34,7 +34,7 @@ export const getAllowance = async (
|
|
|
34
34
|
export const getAllowanceMulticall = async (
|
|
35
35
|
chainId: ChainId,
|
|
36
36
|
tokens: TokenSpender[],
|
|
37
|
-
ownerAddress:
|
|
37
|
+
ownerAddress: Address
|
|
38
38
|
): Promise<TokenSpenderAllowance[]> => {
|
|
39
39
|
if (!tokens.length) {
|
|
40
40
|
return []
|
|
@@ -80,8 +80,8 @@ export const getAllowanceMulticall = async (
|
|
|
80
80
|
*/
|
|
81
81
|
export const getTokenAllowance = async (
|
|
82
82
|
token: BaseToken,
|
|
83
|
-
ownerAddress:
|
|
84
|
-
spenderAddress:
|
|
83
|
+
ownerAddress: Address,
|
|
84
|
+
spenderAddress: Address
|
|
85
85
|
): Promise<bigint | undefined> => {
|
|
86
86
|
// native token don't need approval
|
|
87
87
|
if (isNativeTokenAddress(token.address)) {
|
|
@@ -90,7 +90,7 @@ export const getTokenAllowance = async (
|
|
|
90
90
|
|
|
91
91
|
const approved = await getAllowance(
|
|
92
92
|
token.chainId,
|
|
93
|
-
token.address,
|
|
93
|
+
token.address as Address,
|
|
94
94
|
ownerAddress,
|
|
95
95
|
spenderAddress
|
|
96
96
|
)
|
|
@@ -104,7 +104,7 @@ export const getTokenAllowance = async (
|
|
|
104
104
|
* @returns Returns array of tokens and their allowance
|
|
105
105
|
*/
|
|
106
106
|
export const getTokenAllowanceMulticall = async (
|
|
107
|
-
ownerAddress:
|
|
107
|
+
ownerAddress: Address,
|
|
108
108
|
tokens: TokenSpender[]
|
|
109
109
|
): Promise<TokenAllowance[]> => {
|
|
110
110
|
// filter out native tokens
|
|
@@ -12,7 +12,7 @@ import { getPublicClient } from './publicClient.js'
|
|
|
12
12
|
import { getMulticallAddress } from './utils.js'
|
|
13
13
|
|
|
14
14
|
export const getEVMBalance = async (
|
|
15
|
-
walletAddress:
|
|
15
|
+
walletAddress: Address,
|
|
16
16
|
tokens: Token[]
|
|
17
17
|
): Promise<TokenAmount[]> => {
|
|
18
18
|
if (tokens.length === 0) {
|
|
@@ -85,7 +85,7 @@ const getEVMBalanceMulticall = async (
|
|
|
85
85
|
const getEVMBalanceDefault = async (
|
|
86
86
|
chainId: ChainId,
|
|
87
87
|
tokens: Token[],
|
|
88
|
-
walletAddress:
|
|
88
|
+
walletAddress: Address
|
|
89
89
|
): Promise<TokenAmount[]> => {
|
|
90
90
|
const client = await getPublicClient(chainId)
|
|
91
91
|
const blockNumber = await getBlockNumber(client)
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import type { ExtendedChain } from '@lifi/types'
|
|
2
|
+
import type { Address, Client } from 'viem'
|
|
3
|
+
import { multicall, readContract } from 'viem/actions'
|
|
4
|
+
import { eip2612Abi } from './abi.js'
|
|
5
|
+
import { getMulticallAddress } from './utils.js'
|
|
6
|
+
|
|
7
|
+
export type NativePermitData = {
|
|
8
|
+
name: string
|
|
9
|
+
version: string
|
|
10
|
+
nonce: bigint
|
|
11
|
+
supported: boolean
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Retrieves native permit data (EIP-2612) for a token on a specific chain
|
|
15
|
+
* @link https://eips.ethereum.org/EIPS/eip-2612
|
|
16
|
+
* @param client - The Viem client instance
|
|
17
|
+
* @param chain - The extended chain object containing chain details
|
|
18
|
+
* @param tokenAddress - The address of the token to check for permit support
|
|
19
|
+
* @returns {Promise<NativePermitData>} Object containing permit data including name, version, nonce and support status
|
|
20
|
+
*/
|
|
21
|
+
export const getNativePermit = async (
|
|
22
|
+
client: Client,
|
|
23
|
+
chain: ExtendedChain,
|
|
24
|
+
tokenAddress: Address
|
|
25
|
+
): Promise<NativePermitData> => {
|
|
26
|
+
try {
|
|
27
|
+
const multicallAddress = await getMulticallAddress(chain.id)
|
|
28
|
+
|
|
29
|
+
if (multicallAddress) {
|
|
30
|
+
const [nameResult, domainSeparatorResult, noncesResult, versionResult] =
|
|
31
|
+
await multicall(client, {
|
|
32
|
+
contracts: [
|
|
33
|
+
{
|
|
34
|
+
address: tokenAddress,
|
|
35
|
+
abi: eip2612Abi,
|
|
36
|
+
functionName: 'name',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
address: tokenAddress,
|
|
40
|
+
abi: eip2612Abi,
|
|
41
|
+
functionName: 'DOMAIN_SEPARATOR',
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
address: tokenAddress,
|
|
45
|
+
abi: eip2612Abi,
|
|
46
|
+
functionName: 'nonces',
|
|
47
|
+
args: [client.account!.address],
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
address: tokenAddress,
|
|
51
|
+
abi: eip2612Abi,
|
|
52
|
+
functionName: 'version',
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
multicallAddress,
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
const supported =
|
|
59
|
+
nameResult.status === 'success' &&
|
|
60
|
+
domainSeparatorResult.status === 'success' &&
|
|
61
|
+
noncesResult.status === 'success' &&
|
|
62
|
+
!!nameResult.result &&
|
|
63
|
+
!!domainSeparatorResult.result &&
|
|
64
|
+
noncesResult.result !== undefined
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
name: nameResult.result!,
|
|
68
|
+
version: versionResult.result ?? '1',
|
|
69
|
+
nonce: noncesResult.result!,
|
|
70
|
+
supported,
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Fallback to individual calls
|
|
75
|
+
const [name, domainSeparator, nonce, version] = await Promise.all([
|
|
76
|
+
readContract(client, {
|
|
77
|
+
address: tokenAddress,
|
|
78
|
+
abi: eip2612Abi,
|
|
79
|
+
functionName: 'name',
|
|
80
|
+
}),
|
|
81
|
+
readContract(client, {
|
|
82
|
+
address: tokenAddress,
|
|
83
|
+
abi: eip2612Abi,
|
|
84
|
+
functionName: 'DOMAIN_SEPARATOR',
|
|
85
|
+
}),
|
|
86
|
+
readContract(client, {
|
|
87
|
+
address: tokenAddress,
|
|
88
|
+
abi: eip2612Abi,
|
|
89
|
+
functionName: 'nonces',
|
|
90
|
+
args: [client.account!.address],
|
|
91
|
+
}),
|
|
92
|
+
readContract(client, {
|
|
93
|
+
address: tokenAddress,
|
|
94
|
+
abi: eip2612Abi,
|
|
95
|
+
functionName: 'version',
|
|
96
|
+
}),
|
|
97
|
+
])
|
|
98
|
+
|
|
99
|
+
return {
|
|
100
|
+
name,
|
|
101
|
+
version: version ?? '1',
|
|
102
|
+
nonce,
|
|
103
|
+
supported: !!name && !!domainSeparator && nonce !== undefined,
|
|
104
|
+
}
|
|
105
|
+
} catch {
|
|
106
|
+
return {
|
|
107
|
+
name: '',
|
|
108
|
+
version: '1',
|
|
109
|
+
nonce: 0n,
|
|
110
|
+
supported: false,
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
@@ -29,6 +29,14 @@ const handleSpecificErrors = async (
|
|
|
29
29
|
if (e.cause?.name === 'UserRejectedRequestError') {
|
|
30
30
|
return new TransactionError(LiFiErrorCode.SignatureRejected, e.message, e)
|
|
31
31
|
}
|
|
32
|
+
// Safe Wallet via WalletConnect returns -32000 code when user rejects the signature
|
|
33
|
+
// {
|
|
34
|
+
// code: -32000,
|
|
35
|
+
// message: 'User rejected transaction',
|
|
36
|
+
// }
|
|
37
|
+
if (e.cause?.code === -32000) {
|
|
38
|
+
return new TransactionError(LiFiErrorCode.SignatureRejected, e.message, e)
|
|
39
|
+
}
|
|
32
40
|
|
|
33
41
|
if (
|
|
34
42
|
step &&
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type Address,
|
|
3
|
+
type TypedData,
|
|
4
|
+
type TypedDataDomain,
|
|
5
|
+
hashTypedData,
|
|
6
|
+
} from 'viem'
|
|
7
|
+
import { MaxUint48, MaxUint160 } from '../../../constants.js'
|
|
8
|
+
import { invariant } from '../../../utils/invariant.js'
|
|
9
|
+
import { MaxSigDeadline } from './constants.js'
|
|
10
|
+
import { permit2Domain } from './domain.js'
|
|
11
|
+
|
|
12
|
+
export const MaxAllowanceTransferAmount = MaxUint160
|
|
13
|
+
export const MaxAllowanceExpiration = MaxUint48
|
|
14
|
+
export const MaxOrderedNonce = MaxUint48
|
|
15
|
+
|
|
16
|
+
export interface PermitDetails {
|
|
17
|
+
token: Address
|
|
18
|
+
amount: bigint
|
|
19
|
+
expiration: number
|
|
20
|
+
nonce: number
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface PermitSingle {
|
|
24
|
+
details: PermitDetails
|
|
25
|
+
spender: Address
|
|
26
|
+
sigDeadline: bigint
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface PermitBatch {
|
|
30
|
+
details: PermitDetails[]
|
|
31
|
+
spender: Address
|
|
32
|
+
sigDeadline: bigint
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export type PermitSingleData = {
|
|
36
|
+
domain: TypedDataDomain
|
|
37
|
+
types: TypedData
|
|
38
|
+
values: PermitSingle
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export type PermitBatchData = {
|
|
42
|
+
domain: TypedDataDomain
|
|
43
|
+
types: TypedData
|
|
44
|
+
values: PermitBatch
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const PERMIT_DETAILS = [
|
|
48
|
+
{ name: 'token', type: 'address' },
|
|
49
|
+
{ name: 'amount', type: 'uint160' },
|
|
50
|
+
{ name: 'expiration', type: 'uint48' },
|
|
51
|
+
{ name: 'nonce', type: 'uint48' },
|
|
52
|
+
] as const
|
|
53
|
+
|
|
54
|
+
const PERMIT_TYPES = {
|
|
55
|
+
PermitDetails: PERMIT_DETAILS,
|
|
56
|
+
PermitSingle: [
|
|
57
|
+
{ name: 'details', type: 'PermitDetails' },
|
|
58
|
+
{ name: 'spender', type: 'address' },
|
|
59
|
+
{ name: 'sigDeadline', type: 'uint256' },
|
|
60
|
+
],
|
|
61
|
+
} as const
|
|
62
|
+
|
|
63
|
+
const PERMIT_BATCH_TYPES = {
|
|
64
|
+
PermitDetails: PERMIT_DETAILS,
|
|
65
|
+
PermitBatch: [
|
|
66
|
+
{ name: 'details', type: 'PermitDetails[]' },
|
|
67
|
+
{ name: 'spender', type: 'address' },
|
|
68
|
+
{ name: 'sigDeadline', type: 'uint256' },
|
|
69
|
+
],
|
|
70
|
+
} as const
|
|
71
|
+
|
|
72
|
+
function isPermit(permit: PermitSingle | PermitBatch): permit is PermitSingle {
|
|
73
|
+
return !Array.isArray(permit.details)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function getPermitSingleData(
|
|
77
|
+
permit: PermitSingle,
|
|
78
|
+
permit2Address: Address,
|
|
79
|
+
chainId: number
|
|
80
|
+
) {
|
|
81
|
+
invariant(MaxSigDeadline >= permit.sigDeadline, 'SIG_DEADLINE_OUT_OF_RANGE')
|
|
82
|
+
|
|
83
|
+
const domain = permit2Domain(permit2Address, chainId)
|
|
84
|
+
validatePermitDetails(permit.details)
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
domain,
|
|
88
|
+
values: permit,
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function getPermitBatchData(
|
|
93
|
+
permit: PermitBatch,
|
|
94
|
+
permit2Address: Address,
|
|
95
|
+
chainId: number
|
|
96
|
+
) {
|
|
97
|
+
invariant(MaxSigDeadline >= permit.sigDeadline, 'SIG_DEADLINE_OUT_OF_RANGE')
|
|
98
|
+
|
|
99
|
+
const domain = permit2Domain(permit2Address, chainId)
|
|
100
|
+
permit.details.forEach(validatePermitDetails)
|
|
101
|
+
|
|
102
|
+
return {
|
|
103
|
+
domain,
|
|
104
|
+
values: permit,
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function getPermitData(
|
|
109
|
+
permit: PermitSingle | PermitBatch,
|
|
110
|
+
permit2Address: Address,
|
|
111
|
+
chainId: number
|
|
112
|
+
): PermitSingleData | PermitBatchData {
|
|
113
|
+
invariant(MaxSigDeadline >= permit.sigDeadline, 'SIG_DEADLINE_OUT_OF_RANGE')
|
|
114
|
+
|
|
115
|
+
const domain = permit2Domain(permit2Address, chainId)
|
|
116
|
+
if (isPermit(permit)) {
|
|
117
|
+
validatePermitDetails(permit.details)
|
|
118
|
+
return {
|
|
119
|
+
domain,
|
|
120
|
+
types: PERMIT_TYPES,
|
|
121
|
+
values: permit,
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
permit.details.forEach(validatePermitDetails)
|
|
125
|
+
return {
|
|
126
|
+
domain,
|
|
127
|
+
types: PERMIT_BATCH_TYPES,
|
|
128
|
+
values: permit,
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export function hash(
|
|
133
|
+
permit: PermitSingle | PermitBatch,
|
|
134
|
+
permit2Address: Address,
|
|
135
|
+
chainId: number
|
|
136
|
+
): string {
|
|
137
|
+
if (isPermit(permit)) {
|
|
138
|
+
const { domain, values } = getPermitSingleData(
|
|
139
|
+
permit,
|
|
140
|
+
permit2Address,
|
|
141
|
+
chainId
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
return hashTypedData({
|
|
145
|
+
domain,
|
|
146
|
+
types: PERMIT_TYPES,
|
|
147
|
+
primaryType: 'PermitSingle',
|
|
148
|
+
message: values,
|
|
149
|
+
})
|
|
150
|
+
}
|
|
151
|
+
const { domain, values } = getPermitBatchData(permit, permit2Address, chainId)
|
|
152
|
+
|
|
153
|
+
return hashTypedData({
|
|
154
|
+
domain,
|
|
155
|
+
types: PERMIT_BATCH_TYPES,
|
|
156
|
+
primaryType: 'PermitBatch',
|
|
157
|
+
message: values,
|
|
158
|
+
})
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function validatePermitDetails(details: PermitDetails) {
|
|
162
|
+
invariant(MaxOrderedNonce >= details.nonce, 'NONCE_OUT_OF_RANGE')
|
|
163
|
+
invariant(MaxAllowanceTransferAmount >= details.amount, 'AMOUNT_OUT_OF_RANGE')
|
|
164
|
+
invariant(
|
|
165
|
+
MaxAllowanceExpiration >= details.expiration,
|
|
166
|
+
'EXPIRATION_OUT_OF_RANGE'
|
|
167
|
+
)
|
|
168
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { MaxUint48, MaxUint160, MaxUint256 } from '../../../constants.js'
|
|
2
|
+
|
|
3
|
+
export const MaxAllowanceTransferAmount = MaxUint160
|
|
4
|
+
export const MaxAllowanceExpiration = MaxUint48
|
|
5
|
+
export const MaxOrderedNonce = MaxUint48
|
|
6
|
+
|
|
7
|
+
export const MaxSignatureTransferAmount = MaxUint256
|
|
8
|
+
export const MaxUnorderedNonce = MaxUint256
|
|
9
|
+
export const MaxSigDeadline = MaxUint256
|
|
10
|
+
|
|
11
|
+
export const InstantExpiration = 0n
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Address, TypedData, TypedDataDomain } from 'viem'
|
|
2
|
+
|
|
3
|
+
const PERMIT2_DOMAIN_NAME = 'Permit2'
|
|
4
|
+
|
|
5
|
+
export function permit2Domain(
|
|
6
|
+
permit2Address: Address,
|
|
7
|
+
chainId: number
|
|
8
|
+
): TypedDataDomain {
|
|
9
|
+
return {
|
|
10
|
+
name: PERMIT2_DOMAIN_NAME,
|
|
11
|
+
chainId,
|
|
12
|
+
verifyingContract: permit2Address,
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export type PermitData = {
|
|
17
|
+
domain: TypedDataDomain
|
|
18
|
+
types: TypedData
|
|
19
|
+
values: any
|
|
20
|
+
}
|