@chainlink/ccip-sdk 0.95.0 → 0.96.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/README.md +2 -2
- package/dist/all-chains.d.ts +23 -0
- package/dist/all-chains.d.ts.map +1 -0
- package/dist/all-chains.js +24 -0
- package/dist/all-chains.js.map +1 -0
- package/dist/api/index.d.ts +15 -12
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +20 -16
- package/dist/api/index.js.map +1 -1
- package/dist/api/types.d.ts +25 -29
- package/dist/api/types.d.ts.map +1 -1
- package/dist/aptos/index.d.ts +33 -8
- package/dist/aptos/index.d.ts.map +1 -1
- package/dist/aptos/index.js +74 -41
- package/dist/aptos/index.js.map +1 -1
- package/dist/chain.d.ts +220 -41
- package/dist/chain.d.ts.map +1 -1
- package/dist/chain.js +105 -15
- package/dist/chain.js.map +1 -1
- package/dist/errors/codes.d.ts +2 -0
- package/dist/errors/codes.d.ts.map +1 -1
- package/dist/errors/codes.js +2 -0
- package/dist/errors/codes.js.map +1 -1
- package/dist/errors/index.d.ts +1 -1
- package/dist/errors/index.d.ts.map +1 -1
- package/dist/errors/index.js +1 -1
- package/dist/errors/index.js.map +1 -1
- package/dist/errors/recovery.d.ts.map +1 -1
- package/dist/errors/recovery.js +2 -0
- package/dist/errors/recovery.js.map +1 -1
- package/dist/errors/specialized.d.ts +12 -6
- package/dist/errors/specialized.d.ts.map +1 -1
- package/dist/errors/specialized.js +19 -7
- package/dist/errors/specialized.js.map +1 -1
- package/dist/evm/extra-args.d.ts +25 -0
- package/dist/evm/extra-args.d.ts.map +1 -0
- package/dist/evm/extra-args.js +328 -0
- package/dist/evm/extra-args.js.map +1 -0
- package/dist/evm/gas.d.ts.map +1 -1
- package/dist/evm/gas.js +7 -12
- package/dist/evm/gas.js.map +1 -1
- package/dist/evm/index.d.ts +70 -24
- package/dist/evm/index.d.ts.map +1 -1
- package/dist/evm/index.js +72 -91
- package/dist/evm/index.js.map +1 -1
- package/dist/execution.d.ts.map +1 -1
- package/dist/execution.js +16 -2
- package/dist/execution.js.map +1 -1
- package/dist/extra-args.d.ts +103 -4
- package/dist/extra-args.d.ts.map +1 -1
- package/dist/extra-args.js +28 -3
- package/dist/extra-args.js.map +1 -1
- package/dist/gas.d.ts +6 -3
- package/dist/gas.d.ts.map +1 -1
- package/dist/gas.js +14 -6
- package/dist/gas.js.map +1 -1
- package/dist/index.d.ts +10 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -8
- package/dist/index.js.map +1 -1
- package/dist/requests.d.ts +17 -9
- package/dist/requests.d.ts.map +1 -1
- package/dist/requests.js +17 -9
- package/dist/requests.js.map +1 -1
- package/dist/selectors.d.ts.map +1 -1
- package/dist/selectors.js +12 -0
- package/dist/selectors.js.map +1 -1
- package/dist/solana/index.d.ts +70 -15
- package/dist/solana/index.d.ts.map +1 -1
- package/dist/solana/index.js +72 -16
- package/dist/solana/index.js.map +1 -1
- package/dist/sui/index.d.ts +37 -9
- package/dist/sui/index.d.ts.map +1 -1
- package/dist/sui/index.js +40 -11
- package/dist/sui/index.js.map +1 -1
- package/dist/ton/index.d.ts +65 -19
- package/dist/ton/index.d.ts.map +1 -1
- package/dist/ton/index.js +155 -25
- package/dist/ton/index.js.map +1 -1
- package/dist/ton/send.d.ts +52 -0
- package/dist/ton/send.d.ts.map +1 -0
- package/dist/ton/send.js +166 -0
- package/dist/ton/send.js.map +1 -0
- package/dist/types.d.ts +102 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils.d.ts +15 -3
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +19 -6
- package/dist/utils.js.map +1 -1
- package/package.json +12 -7
- package/src/all-chains.ts +26 -0
- package/src/api/index.ts +26 -25
- package/src/api/types.ts +25 -30
- package/src/aptos/index.ts +79 -43
- package/src/chain.ts +274 -46
- package/src/errors/codes.ts +2 -0
- package/src/errors/index.ts +1 -1
- package/src/errors/recovery.ts +2 -0
- package/src/errors/specialized.ts +24 -7
- package/src/evm/extra-args.ts +377 -0
- package/src/evm/gas.ts +14 -13
- package/src/evm/index.ts +76 -125
- package/src/execution.ts +18 -2
- package/src/extra-args.ts +108 -4
- package/src/gas.ts +16 -9
- package/src/index.ts +12 -9
- package/src/requests.ts +17 -9
- package/src/selectors.ts +12 -0
- package/src/solana/index.ts +72 -16
- package/src/sui/index.ts +40 -11
- package/src/ton/index.ts +192 -27
- package/src/ton/send.ts +222 -0
- package/src/types.ts +103 -1
- package/src/utils.ts +19 -6
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type BytesLike,
|
|
3
|
+
Result,
|
|
4
|
+
concat,
|
|
5
|
+
dataSlice,
|
|
6
|
+
encodeBase58,
|
|
7
|
+
getAddress,
|
|
8
|
+
hexlify,
|
|
9
|
+
toBeHex,
|
|
10
|
+
toBigInt,
|
|
11
|
+
toNumber,
|
|
12
|
+
zeroPadValue,
|
|
13
|
+
} from 'ethers'
|
|
14
|
+
|
|
15
|
+
import {
|
|
16
|
+
type EVMExtraArgsV1,
|
|
17
|
+
type EVMExtraArgsV2,
|
|
18
|
+
type ExtraArgs,
|
|
19
|
+
type GenericExtraArgsV3,
|
|
20
|
+
type SVMExtraArgsV1,
|
|
21
|
+
type SuiExtraArgsV1,
|
|
22
|
+
EVMExtraArgsV1Tag,
|
|
23
|
+
EVMExtraArgsV2Tag,
|
|
24
|
+
GenericExtraArgsV3Tag,
|
|
25
|
+
SVMExtraArgsV1Tag,
|
|
26
|
+
SuiExtraArgsV1Tag,
|
|
27
|
+
} from '../extra-args.ts'
|
|
28
|
+
import { getAddressBytes, getDataBytes } from '../utils.ts'
|
|
29
|
+
import { DEFAULT_GAS_LIMIT, defaultAbiCoder } from './const.ts'
|
|
30
|
+
|
|
31
|
+
// ABI type strings for extra args encoding
|
|
32
|
+
const EVMExtraArgsV1ABI = 'tuple(uint256 gasLimit)'
|
|
33
|
+
const EVMExtraArgsV2ABI = 'tuple(uint256 gasLimit, bool allowOutOfOrderExecution)'
|
|
34
|
+
const SVMExtraArgsV1ABI =
|
|
35
|
+
'tuple(uint32 computeUnits, uint64 accountIsWritableBitmap, bool allowOutOfOrderExecution, bytes32 tokenReceiver, bytes32[] accounts)'
|
|
36
|
+
const SuiExtraArgsV1ABI =
|
|
37
|
+
'tuple(uint256 gasLimit, bool allowOutOfOrderExecution, bytes32 tokenReceiver, bytes32[] receiverObjectIds)'
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Converts an ethers Result to a plain object.
|
|
41
|
+
* @internal
|
|
42
|
+
*/
|
|
43
|
+
function resultToObject<T>(o: T): T {
|
|
44
|
+
if (o instanceof Promise) return o.then(resultToObject) as T
|
|
45
|
+
if (!(o instanceof Result)) return o
|
|
46
|
+
if (o.length === 0) return o.toArray() as T
|
|
47
|
+
try {
|
|
48
|
+
const obj = o.toObject()
|
|
49
|
+
if (!Object.keys(obj).every((k) => /^_+\d*$/.test(k)))
|
|
50
|
+
return Object.fromEntries(Object.entries(obj).map(([k, v]) => [k, resultToObject(v)])) as T
|
|
51
|
+
} catch (_) {
|
|
52
|
+
// fallthrough
|
|
53
|
+
}
|
|
54
|
+
return o.toArray().map(resultToObject) as T
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Encodes GenericExtraArgsV3 using tightly packed binary format.
|
|
59
|
+
*
|
|
60
|
+
* Binary format:
|
|
61
|
+
* - tag (4 bytes): 0x302326cb
|
|
62
|
+
* - gasLimit (4 bytes): uint32 big-endian
|
|
63
|
+
* - blockConfirmations (2 bytes): uint16 big-endian
|
|
64
|
+
* - ccvsLength (1 byte): uint8
|
|
65
|
+
* - For each CCV:
|
|
66
|
+
* - ccvAddressLength (1 byte): 0 or 20
|
|
67
|
+
* - ccvAddress (0 or 20 bytes)
|
|
68
|
+
* - ccvArgsLength (2 bytes): uint16 big-endian
|
|
69
|
+
* - ccvArgs (variable)
|
|
70
|
+
* - executorLength (1 byte): 0 or 20
|
|
71
|
+
* - executor (0 or 20 bytes)
|
|
72
|
+
* - executorArgsLength (2 bytes): uint16 big-endian
|
|
73
|
+
* - executorArgs (variable)
|
|
74
|
+
* - tokenReceiverLength (1 byte): uint8
|
|
75
|
+
* - tokenReceiver (variable)
|
|
76
|
+
* - tokenArgsLength (2 bytes): uint16 big-endian
|
|
77
|
+
* - tokenArgs (variable)
|
|
78
|
+
*/
|
|
79
|
+
function encodeExtraArgsV3(args: GenericExtraArgsV3): string {
|
|
80
|
+
const parts: Uint8Array[] = []
|
|
81
|
+
|
|
82
|
+
// Tag (4 bytes)
|
|
83
|
+
parts.push(getDataBytes(GenericExtraArgsV3Tag))
|
|
84
|
+
|
|
85
|
+
// gasLimit (4 bytes, uint32 big-endian)
|
|
86
|
+
parts.push(getDataBytes(toBeHex(args.gasLimit, 4)))
|
|
87
|
+
|
|
88
|
+
// blockConfirmations (2 bytes, uint16 big-endian)
|
|
89
|
+
parts.push(getDataBytes(toBeHex(args.blockConfirmations, 2)))
|
|
90
|
+
|
|
91
|
+
// ccvsLength (1 byte)
|
|
92
|
+
parts.push(new Uint8Array([args.ccvs.length]))
|
|
93
|
+
|
|
94
|
+
// For each CCV
|
|
95
|
+
for (let i = 0; i < args.ccvs.length; i++) {
|
|
96
|
+
const ccvAddress = args.ccvs[i]!
|
|
97
|
+
const ccvArgsBytes = getDataBytes(args.ccvArgs[i] ?? '0x')
|
|
98
|
+
|
|
99
|
+
if (ccvAddress && ccvAddress !== '' && ccvAddress !== '0x') {
|
|
100
|
+
// ccvAddressLength = 20
|
|
101
|
+
parts.push(new Uint8Array([20]))
|
|
102
|
+
// ccvAddress (20 bytes)
|
|
103
|
+
parts.push(getDataBytes(ccvAddress))
|
|
104
|
+
} else {
|
|
105
|
+
// ccvAddressLength = 0
|
|
106
|
+
parts.push(new Uint8Array([0]))
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// ccvArgsLength (2 bytes, uint16 big-endian)
|
|
110
|
+
parts.push(getDataBytes(toBeHex(ccvArgsBytes.length, 2)))
|
|
111
|
+
|
|
112
|
+
// ccvArgs (variable)
|
|
113
|
+
if (ccvArgsBytes.length > 0) {
|
|
114
|
+
parts.push(ccvArgsBytes)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// executorLength (1 byte)
|
|
119
|
+
if (args.executor && args.executor !== '' && args.executor !== '0x') {
|
|
120
|
+
parts.push(new Uint8Array([20]))
|
|
121
|
+
parts.push(getDataBytes(args.executor))
|
|
122
|
+
} else {
|
|
123
|
+
parts.push(new Uint8Array([0]))
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Convert BytesLike fields to Uint8Array
|
|
127
|
+
const executorArgsBytes = getDataBytes(args.executorArgs)
|
|
128
|
+
const tokenReceiverBytes = getDataBytes(args.tokenReceiver)
|
|
129
|
+
const tokenArgsBytes = getDataBytes(args.tokenArgs)
|
|
130
|
+
|
|
131
|
+
// executorArgsLength (2 bytes, uint16 big-endian)
|
|
132
|
+
parts.push(getDataBytes(toBeHex(executorArgsBytes.length, 2)))
|
|
133
|
+
|
|
134
|
+
// executorArgs (variable)
|
|
135
|
+
if (executorArgsBytes.length > 0) {
|
|
136
|
+
parts.push(executorArgsBytes)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// tokenReceiverLength (1 byte)
|
|
140
|
+
parts.push(new Uint8Array([tokenReceiverBytes.length]))
|
|
141
|
+
|
|
142
|
+
// tokenReceiver (variable)
|
|
143
|
+
if (tokenReceiverBytes.length > 0) {
|
|
144
|
+
parts.push(tokenReceiverBytes)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// tokenArgsLength (2 bytes, uint16 big-endian)
|
|
148
|
+
parts.push(getDataBytes(toBeHex(tokenArgsBytes.length, 2)))
|
|
149
|
+
|
|
150
|
+
// tokenArgs (variable)
|
|
151
|
+
if (tokenArgsBytes.length > 0) {
|
|
152
|
+
parts.push(tokenArgsBytes)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return hexlify(concat(parts))
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Decodes GenericExtraArgsV3 from tightly packed binary format.
|
|
160
|
+
* @param data - Bytes to decode (without the tag prefix).
|
|
161
|
+
* @returns Decoded GenericExtraArgsV3 or undefined if parsing fails.
|
|
162
|
+
*/
|
|
163
|
+
function decodeExtraArgsV3(data: Uint8Array): GenericExtraArgsV3 | undefined {
|
|
164
|
+
let offset = 0
|
|
165
|
+
|
|
166
|
+
// gasLimit (4 bytes, uint32 big-endian)
|
|
167
|
+
if (offset + 4 > data.length) return undefined
|
|
168
|
+
const gasLimit = toBigInt(data.subarray(offset, offset + 4))
|
|
169
|
+
offset += 4
|
|
170
|
+
|
|
171
|
+
// blockConfirmations (2 bytes, uint16 big-endian)
|
|
172
|
+
if (offset + 2 > data.length) return undefined
|
|
173
|
+
const blockConfirmations = toNumber(data.subarray(offset, offset + 2))
|
|
174
|
+
offset += 2
|
|
175
|
+
|
|
176
|
+
// ccvsLength (1 byte)
|
|
177
|
+
if (offset + 1 > data.length) return undefined
|
|
178
|
+
const ccvsLength = data[offset]!
|
|
179
|
+
offset += 1
|
|
180
|
+
|
|
181
|
+
const ccvs: string[] = []
|
|
182
|
+
const ccvArgs: string[] = []
|
|
183
|
+
|
|
184
|
+
// For each CCV
|
|
185
|
+
for (let i = 0; i < ccvsLength; i++) {
|
|
186
|
+
// ccvAddressLength (1 byte)
|
|
187
|
+
if (offset + 1 > data.length) return undefined
|
|
188
|
+
const ccvAddrLen = data[offset]!
|
|
189
|
+
offset += 1
|
|
190
|
+
|
|
191
|
+
// ccvAddress (0 or 20 bytes)
|
|
192
|
+
if (ccvAddrLen === 20) {
|
|
193
|
+
if (offset + 20 > data.length) return undefined
|
|
194
|
+
ccvs.push(getAddress(hexlify(data.slice(offset, offset + 20))))
|
|
195
|
+
offset += 20
|
|
196
|
+
} else if (ccvAddrLen === 0) {
|
|
197
|
+
ccvs.push('')
|
|
198
|
+
} else {
|
|
199
|
+
return undefined // Invalid address length
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// ccvArgsLength (2 bytes, uint16 big-endian)
|
|
203
|
+
if (offset + 2 > data.length) return undefined
|
|
204
|
+
const ccvArgsLen = toNumber(data.subarray(offset, offset + 2))
|
|
205
|
+
offset += 2
|
|
206
|
+
|
|
207
|
+
// ccvArgs (variable)
|
|
208
|
+
if (offset + ccvArgsLen > data.length) return undefined
|
|
209
|
+
ccvArgs.push(hexlify(data.slice(offset, offset + ccvArgsLen)))
|
|
210
|
+
offset += ccvArgsLen
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// executorLength (1 byte)
|
|
214
|
+
if (offset + 1 > data.length) return undefined
|
|
215
|
+
const executorLen = data[offset]!
|
|
216
|
+
offset += 1
|
|
217
|
+
|
|
218
|
+
// executor (0 or 20 bytes)
|
|
219
|
+
let executor = ''
|
|
220
|
+
if (executorLen === 20) {
|
|
221
|
+
if (offset + 20 > data.length) return undefined
|
|
222
|
+
executor = getAddress(hexlify(data.slice(offset, offset + 20)))
|
|
223
|
+
offset += 20
|
|
224
|
+
} else if (executorLen !== 0) {
|
|
225
|
+
return undefined // Invalid executor length
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// executorArgsLength (2 bytes, uint16 big-endian)
|
|
229
|
+
if (offset + 2 > data.length) return undefined
|
|
230
|
+
const executorArgsLen = toNumber(data.subarray(offset, offset + 2))
|
|
231
|
+
offset += 2
|
|
232
|
+
|
|
233
|
+
// executorArgs (variable)
|
|
234
|
+
if (offset + executorArgsLen > data.length) return undefined
|
|
235
|
+
const executorArgs = hexlify(data.slice(offset, offset + executorArgsLen))
|
|
236
|
+
offset += executorArgsLen
|
|
237
|
+
|
|
238
|
+
// tokenReceiverLength (1 byte)
|
|
239
|
+
if (offset + 1 > data.length) return undefined
|
|
240
|
+
const tokenReceiverLen = data[offset]!
|
|
241
|
+
offset += 1
|
|
242
|
+
|
|
243
|
+
// tokenReceiver (variable)
|
|
244
|
+
if (offset + tokenReceiverLen > data.length) return undefined
|
|
245
|
+
const tokenReceiverBytes = data.slice(offset, offset + tokenReceiverLen)
|
|
246
|
+
offset += tokenReceiverLen
|
|
247
|
+
|
|
248
|
+
// Convert tokenReceiver bytes to string
|
|
249
|
+
let tokenReceiver: string
|
|
250
|
+
if (tokenReceiverLen === 0) {
|
|
251
|
+
tokenReceiver = ''
|
|
252
|
+
} else if (tokenReceiverLen === 20) {
|
|
253
|
+
// 20 bytes = EVM address, return checksummed
|
|
254
|
+
tokenReceiver = getAddress(hexlify(tokenReceiverBytes))
|
|
255
|
+
} else {
|
|
256
|
+
// Other lengths: return as hex string
|
|
257
|
+
tokenReceiver = hexlify(tokenReceiverBytes)
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// tokenArgsLength (2 bytes, uint16 big-endian)
|
|
261
|
+
if (offset + 2 > data.length) return undefined
|
|
262
|
+
const tokenArgsLen = toNumber(data.subarray(offset, offset + 2))
|
|
263
|
+
offset += 2
|
|
264
|
+
|
|
265
|
+
// tokenArgs (variable)
|
|
266
|
+
if (offset + tokenArgsLen > data.length) return undefined
|
|
267
|
+
const tokenArgs = hexlify(data.slice(offset, offset + tokenArgsLen))
|
|
268
|
+
offset += tokenArgsLen
|
|
269
|
+
|
|
270
|
+
return {
|
|
271
|
+
gasLimit,
|
|
272
|
+
blockConfirmations,
|
|
273
|
+
ccvs,
|
|
274
|
+
ccvArgs,
|
|
275
|
+
executor,
|
|
276
|
+
executorArgs,
|
|
277
|
+
tokenReceiver,
|
|
278
|
+
tokenArgs,
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Decodes extra arguments from a CCIP message.
|
|
284
|
+
* @param extraArgs - Encoded extra arguments bytes.
|
|
285
|
+
* @returns Decoded extra arguments with tag, or undefined if unknown format.
|
|
286
|
+
*/
|
|
287
|
+
export function decodeExtraArgs(
|
|
288
|
+
extraArgs: BytesLike,
|
|
289
|
+
):
|
|
290
|
+
| (EVMExtraArgsV1 & { _tag: 'EVMExtraArgsV1' })
|
|
291
|
+
| (EVMExtraArgsV2 & { _tag: 'EVMExtraArgsV2' })
|
|
292
|
+
| (GenericExtraArgsV3 & { _tag: 'GenericExtraArgsV3' })
|
|
293
|
+
| (SVMExtraArgsV1 & { _tag: 'SVMExtraArgsV1' })
|
|
294
|
+
| (SuiExtraArgsV1 & { _tag: 'SuiExtraArgsV1' })
|
|
295
|
+
| undefined {
|
|
296
|
+
const data = getDataBytes(extraArgs),
|
|
297
|
+
tag = dataSlice(data, 0, 4)
|
|
298
|
+
switch (tag) {
|
|
299
|
+
case EVMExtraArgsV1Tag: {
|
|
300
|
+
const args = defaultAbiCoder.decode([EVMExtraArgsV1ABI], dataSlice(data, 4))
|
|
301
|
+
return { ...(resultToObject(args[0]) as EVMExtraArgsV1), _tag: 'EVMExtraArgsV1' }
|
|
302
|
+
}
|
|
303
|
+
case EVMExtraArgsV2Tag: {
|
|
304
|
+
const args = defaultAbiCoder.decode([EVMExtraArgsV2ABI], dataSlice(data, 4))
|
|
305
|
+
return { ...(resultToObject(args[0]) as EVMExtraArgsV2), _tag: 'EVMExtraArgsV2' }
|
|
306
|
+
}
|
|
307
|
+
case GenericExtraArgsV3Tag: {
|
|
308
|
+
const parsed = decodeExtraArgsV3(data.slice(4))
|
|
309
|
+
if (!parsed) return undefined
|
|
310
|
+
return { ...parsed, _tag: 'GenericExtraArgsV3' }
|
|
311
|
+
}
|
|
312
|
+
case SVMExtraArgsV1Tag: {
|
|
313
|
+
const args = defaultAbiCoder.decode([SVMExtraArgsV1ABI], dataSlice(data, 4))
|
|
314
|
+
const parsed = resultToObject(args[0]) as SVMExtraArgsV1
|
|
315
|
+
parsed.tokenReceiver = encodeBase58(parsed.tokenReceiver)
|
|
316
|
+
parsed.accounts = parsed.accounts.map((a: string) => encodeBase58(a))
|
|
317
|
+
return { ...parsed, _tag: 'SVMExtraArgsV1' }
|
|
318
|
+
}
|
|
319
|
+
case SuiExtraArgsV1Tag: {
|
|
320
|
+
const args = defaultAbiCoder.decode([SuiExtraArgsV1ABI], dataSlice(data, 4))
|
|
321
|
+
const parsed = resultToObject(args[0]) as SuiExtraArgsV1
|
|
322
|
+
return {
|
|
323
|
+
...parsed,
|
|
324
|
+
_tag: 'SuiExtraArgsV1',
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
default:
|
|
328
|
+
return undefined
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Encodes extra arguments for a CCIP message.
|
|
334
|
+
* @param args - Extra arguments to encode.
|
|
335
|
+
* @returns Encoded extra arguments as hex string.
|
|
336
|
+
*/
|
|
337
|
+
export function encodeExtraArgs(args: ExtraArgs | undefined): string {
|
|
338
|
+
if (!args) return '0x'
|
|
339
|
+
if ('blockConfirmations' in args) {
|
|
340
|
+
// GenericExtraArgsV3 - tightly packed binary encoding
|
|
341
|
+
return encodeExtraArgsV3(args)
|
|
342
|
+
} else if ('computeUnits' in args) {
|
|
343
|
+
return concat([
|
|
344
|
+
SVMExtraArgsV1Tag,
|
|
345
|
+
defaultAbiCoder.encode(
|
|
346
|
+
[SVMExtraArgsV1ABI],
|
|
347
|
+
[
|
|
348
|
+
{
|
|
349
|
+
...args,
|
|
350
|
+
tokenReceiver: getAddressBytes(args.tokenReceiver),
|
|
351
|
+
accounts: args.accounts.map((a) => getAddressBytes(a)),
|
|
352
|
+
},
|
|
353
|
+
],
|
|
354
|
+
),
|
|
355
|
+
])
|
|
356
|
+
} else if ('receiverObjectIds' in args) {
|
|
357
|
+
return concat([
|
|
358
|
+
SuiExtraArgsV1Tag,
|
|
359
|
+
defaultAbiCoder.encode(
|
|
360
|
+
[SuiExtraArgsV1ABI],
|
|
361
|
+
[
|
|
362
|
+
{
|
|
363
|
+
...args,
|
|
364
|
+
tokenReceiver: zeroPadValue(getAddressBytes(args.tokenReceiver), 32),
|
|
365
|
+
receiverObjectIds: args.receiverObjectIds.map((a) => getDataBytes(a)),
|
|
366
|
+
},
|
|
367
|
+
],
|
|
368
|
+
),
|
|
369
|
+
])
|
|
370
|
+
} else if ('allowOutOfOrderExecution' in args) {
|
|
371
|
+
if ((args as Partial<typeof args>).gasLimit == null) args.gasLimit = DEFAULT_GAS_LIMIT
|
|
372
|
+
return concat([EVMExtraArgsV2Tag, defaultAbiCoder.encode([EVMExtraArgsV2ABI], [args])])
|
|
373
|
+
} else if ((args as Partial<typeof args>).gasLimit != null) {
|
|
374
|
+
return concat([EVMExtraArgsV1Tag, defaultAbiCoder.encode([EVMExtraArgsV1ABI], [args])])
|
|
375
|
+
}
|
|
376
|
+
return '0x'
|
|
377
|
+
}
|
package/src/evm/gas.ts
CHANGED
|
@@ -32,33 +32,34 @@ const ccipReceive = FunctionFragment.from({
|
|
|
32
32
|
})
|
|
33
33
|
type Any2EVMMessage = Parameters<TypedContract<typeof RouterABI>['routeMessage']>[0]
|
|
34
34
|
|
|
35
|
-
const transferFragment = interfaces.Token.getFunction('transfer')!
|
|
36
|
-
|
|
37
35
|
/**
|
|
38
36
|
* Finds suitable token balance slot by simulating a fake transfer between 2 non-existent accounts,
|
|
39
37
|
* with state overrides for the holders' balance, which reverts if override slot is wrong
|
|
40
38
|
*/
|
|
41
39
|
const findBalancesSlot = memoize(
|
|
42
|
-
async function findBalancesSlot_(
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
40
|
+
async function findBalancesSlot_(
|
|
41
|
+
token: string,
|
|
42
|
+
provider: JsonRpcApiProvider,
|
|
43
|
+
holder: string = getAddress(hexlify(randomBytes(20))),
|
|
44
|
+
recipient: string = getAddress(hexlify(randomBytes(20))),
|
|
45
|
+
): Promise<number> {
|
|
46
|
+
const contract = new Contract(token, interfaces.Token, provider) as unknown as TypedContract<
|
|
47
|
+
typeof TokenABI
|
|
48
|
+
>
|
|
49
|
+
const fakeAmount = (await contract.totalSupply()) + 1n
|
|
50
|
+
const calldata = interfaces.Token.encodeFunctionData('transfer', [recipient, fakeAmount])
|
|
46
51
|
|
|
47
|
-
const calldata = concat([
|
|
48
|
-
transferFragment.selector,
|
|
49
|
-
defaultAbiCoder.encode(transferFragment.inputs, [fakeRecipient, fakeAmount]),
|
|
50
|
-
])
|
|
51
52
|
let firstErr
|
|
52
53
|
// try range(0..15), but start with most probable 0 (common ERC20) and 9 (USDC)
|
|
53
54
|
for (const slot of [0, 9, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15]) {
|
|
54
55
|
try {
|
|
55
56
|
await provider.send('eth_estimateGas', [
|
|
56
|
-
{ from:
|
|
57
|
+
{ from: holder, to: token, data: calldata },
|
|
57
58
|
'latest',
|
|
58
59
|
{
|
|
59
60
|
[token]: {
|
|
60
61
|
stateDiff: {
|
|
61
|
-
[solidityPackedKeccak256(['uint256', 'uint256'], [
|
|
62
|
+
[solidityPackedKeccak256(['uint256', 'uint256'], [holder, slot])]: toBeHex(
|
|
62
63
|
fakeAmount,
|
|
63
64
|
32,
|
|
64
65
|
),
|
|
@@ -109,7 +110,7 @@ export async function estimateExecGas({
|
|
|
109
110
|
destAmounts[token] = currentBalance
|
|
110
111
|
}
|
|
111
112
|
destAmounts[token]! += amount
|
|
112
|
-
const balancesSlot = await findBalancesSlot(token, provider)
|
|
113
|
+
const balancesSlot = await findBalancesSlot(token, provider, receiver, router)
|
|
113
114
|
stateOverrides[token] = {
|
|
114
115
|
stateDiff: {
|
|
115
116
|
[solidityPackedKeccak256(['uint256', 'uint256'], [receiver, balancesSlot])]: toBeHex(
|