@fastxyz/allset-sdk 0.1.11 → 1.0.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 +339 -266
- package/dist/index.d.ts +658 -5
- package/dist/index.js +927 -7
- package/package.json +21 -47
- package/dist/browser/index.d.ts +0 -2
- package/dist/browser/index.d.ts.map +0 -1
- package/dist/browser/index.js +0 -1
- package/dist/core/address.d.ts +0 -5
- package/dist/core/address.d.ts.map +0 -1
- package/dist/core/address.js +0 -29
- package/dist/core/deposit.d.ts +0 -59
- package/dist/core/deposit.d.ts.map +0 -1
- package/dist/core/deposit.js +0 -92
- package/dist/core/index.d.ts +0 -6
- package/dist/core/index.d.ts.map +0 -1
- package/dist/core/index.js +0 -3
- package/dist/default-config.d.ts +0 -78
- package/dist/default-config.d.ts.map +0 -1
- package/dist/default-config.js +0 -78
- package/dist/index.d.ts.map +0 -1
- package/dist/intents.d.ts +0 -94
- package/dist/intents.d.ts.map +0 -1
- package/dist/intents.js +0 -119
- package/dist/node/bridge.d.ts +0 -38
- package/dist/node/bridge.d.ts.map +0 -1
- package/dist/node/bridge.js +0 -519
- package/dist/node/config.d.ts +0 -45
- package/dist/node/config.d.ts.map +0 -1
- package/dist/node/config.js +0 -48
- package/dist/node/eip7702.d.ts +0 -47
- package/dist/node/eip7702.d.ts.map +0 -1
- package/dist/node/eip7702.js +0 -189
- package/dist/node/evm-executor.d.ts +0 -130
- package/dist/node/evm-executor.d.ts.map +0 -1
- package/dist/node/evm-executor.js +0 -160
- package/dist/node/index.d.ts +0 -15
- package/dist/node/index.d.ts.map +0 -1
- package/dist/node/index.js +0 -17
- package/dist/node/provider.d.ts +0 -162
- package/dist/node/provider.d.ts.map +0 -1
- package/dist/node/provider.js +0 -272
- package/dist/node/types.d.ts +0 -110
- package/dist/node/types.d.ts.map +0 -1
- package/dist/node/types.js +0 -4
package/dist/index.js
CHANGED
|
@@ -1,7 +1,927 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
// src/address.ts
|
|
2
|
+
import { fromFastAddress, toHex } from "@fastxyz/sdk";
|
|
3
|
+
function fastAddressToBytes(address) {
|
|
4
|
+
try {
|
|
5
|
+
return fromFastAddress(address);
|
|
6
|
+
} catch (err) {
|
|
7
|
+
throw new Error(`Invalid Fast address "${address}": ${err.message}`);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
function fastAddressToBytes32(address) {
|
|
11
|
+
return toHex(fastAddressToBytes(address));
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// src/claims.ts
|
|
15
|
+
import { encodeAbiParameters, keccak256 } from "viem";
|
|
16
|
+
function hexToUint8Array(hex) {
|
|
17
|
+
const clean = hex.startsWith("0x") ? hex.slice(2) : hex;
|
|
18
|
+
const bytes = new Uint8Array(clean.length / 2);
|
|
19
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
20
|
+
bytes[i] = parseInt(clean.slice(i * 2, i * 2 + 2), 16);
|
|
21
|
+
}
|
|
22
|
+
return bytes;
|
|
23
|
+
}
|
|
24
|
+
var TRANSFER_CLAIM_ABI_PARAMS = [
|
|
25
|
+
{
|
|
26
|
+
type: "tuple",
|
|
27
|
+
components: [
|
|
28
|
+
{ name: "from", type: "string" },
|
|
29
|
+
{ name: "nonce", type: "uint256" },
|
|
30
|
+
{ name: "asset", type: "string" },
|
|
31
|
+
{ name: "amount", type: "uint256" },
|
|
32
|
+
{ name: "to", type: "string" }
|
|
33
|
+
]
|
|
34
|
+
}
|
|
35
|
+
];
|
|
36
|
+
var INTENT_CLAIM_ABI_PARAMS = [
|
|
37
|
+
{
|
|
38
|
+
type: "tuple",
|
|
39
|
+
components: [
|
|
40
|
+
{ name: "transferFastTxId", type: "bytes32" },
|
|
41
|
+
{ name: "deadline", type: "uint256" },
|
|
42
|
+
{
|
|
43
|
+
name: "intents",
|
|
44
|
+
type: "tuple[]",
|
|
45
|
+
components: [
|
|
46
|
+
{ name: "action", type: "uint8" },
|
|
47
|
+
{ name: "payload", type: "bytes" },
|
|
48
|
+
{ name: "value", type: "uint256" }
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
}
|
|
53
|
+
];
|
|
54
|
+
function encodeTransferClaim(params) {
|
|
55
|
+
return encodeAbiParameters(TRANSFER_CLAIM_ABI_PARAMS, [
|
|
56
|
+
{
|
|
57
|
+
from: params.from.toLowerCase(),
|
|
58
|
+
nonce: BigInt(params.nonce),
|
|
59
|
+
asset: params.asset,
|
|
60
|
+
amount: params.amount,
|
|
61
|
+
to: params.to
|
|
62
|
+
}
|
|
63
|
+
]);
|
|
64
|
+
}
|
|
65
|
+
function hashTransferClaim(params) {
|
|
66
|
+
return keccak256(encodeTransferClaim(params));
|
|
67
|
+
}
|
|
68
|
+
function encodeIntentClaim(params) {
|
|
69
|
+
return encodeAbiParameters(INTENT_CLAIM_ABI_PARAMS, [
|
|
70
|
+
{
|
|
71
|
+
transferFastTxId: params.transferFastTxId,
|
|
72
|
+
deadline: params.deadline,
|
|
73
|
+
intents: params.intents.map((i) => ({
|
|
74
|
+
action: i.action,
|
|
75
|
+
payload: i.payload,
|
|
76
|
+
value: i.value
|
|
77
|
+
}))
|
|
78
|
+
}
|
|
79
|
+
]);
|
|
80
|
+
}
|
|
81
|
+
function buildIntentClaimBytes(params) {
|
|
82
|
+
const deadline = params.deadline ?? BigInt(Math.floor(Date.now() / 1e3) + 3600);
|
|
83
|
+
const encoded = encodeIntentClaim({
|
|
84
|
+
transferFastTxId: params.transferFastTxId,
|
|
85
|
+
deadline,
|
|
86
|
+
intents: params.intents
|
|
87
|
+
});
|
|
88
|
+
return hexToUint8Array(encoded);
|
|
89
|
+
}
|
|
90
|
+
function extractClaimId(crossSignTransaction) {
|
|
91
|
+
const bytes = new Uint8Array(crossSignTransaction.slice(32, 64));
|
|
92
|
+
return `0x${Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("")}`;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// src/deposit.ts
|
|
96
|
+
import { encodeFunctionData } from "viem";
|
|
97
|
+
var BRIDGE_DEPOSIT_ABI = [
|
|
98
|
+
{
|
|
99
|
+
type: "function",
|
|
100
|
+
name: "deposit",
|
|
101
|
+
inputs: [
|
|
102
|
+
{ name: "token", type: "address" },
|
|
103
|
+
{ name: "amount", type: "uint256" },
|
|
104
|
+
{ name: "receiver", type: "bytes32" }
|
|
105
|
+
],
|
|
106
|
+
outputs: [],
|
|
107
|
+
stateMutability: "payable"
|
|
108
|
+
}
|
|
109
|
+
];
|
|
110
|
+
function encodeDepositCalldata(params) {
|
|
111
|
+
return encodeFunctionData({
|
|
112
|
+
abi: BRIDGE_DEPOSIT_ABI,
|
|
113
|
+
functionName: "deposit",
|
|
114
|
+
args: [params.tokenAddress, params.amount, params.receiverBytes32]
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
function buildDepositTransaction(params) {
|
|
118
|
+
const receiverBytes32 = fastAddressToBytes32(params.receiver);
|
|
119
|
+
return {
|
|
120
|
+
chainId: params.chainId,
|
|
121
|
+
to: params.bridgeContract,
|
|
122
|
+
data: encodeDepositCalldata({
|
|
123
|
+
tokenAddress: params.tokenAddress,
|
|
124
|
+
amount: params.amount,
|
|
125
|
+
receiverBytes32
|
|
126
|
+
}),
|
|
127
|
+
value: params.isNative ? params.amount : 0n,
|
|
128
|
+
receiverBytes32
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// src/eip7702.ts
|
|
133
|
+
import {
|
|
134
|
+
createPublicClient,
|
|
135
|
+
encodeAbiParameters as encodeAbiParameters2,
|
|
136
|
+
http,
|
|
137
|
+
keccak256 as keccak2562,
|
|
138
|
+
parseAbi
|
|
139
|
+
} from "viem";
|
|
140
|
+
import { privateKeyToAccount } from "viem/accounts";
|
|
141
|
+
import { getUserOperationTypedData } from "viem/account-abstraction";
|
|
142
|
+
var ENTRY_POINT_V08 = "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108";
|
|
143
|
+
var TRUSTED_DELEGATES = /* @__PURE__ */ new Set([
|
|
144
|
+
"0xe6cae83bde06e4c305530e199d7217f42808555b"
|
|
145
|
+
// Simple7702Account v0.8
|
|
146
|
+
]);
|
|
147
|
+
var ERC20_BALANCEOF_ABI = parseAbi([
|
|
148
|
+
"function balanceOf(address account) view returns (uint256)"
|
|
149
|
+
]);
|
|
150
|
+
function toEvenHex(n) {
|
|
151
|
+
let h = n.toString(16);
|
|
152
|
+
if (h.length % 2 !== 0) h = `0${h}`;
|
|
153
|
+
return `0x${h}`;
|
|
154
|
+
}
|
|
155
|
+
async function postJson(url, body, timeoutMs) {
|
|
156
|
+
const ac = new AbortController();
|
|
157
|
+
const timer = setTimeout(() => ac.abort(), timeoutMs);
|
|
158
|
+
try {
|
|
159
|
+
const res = await fetch(url, {
|
|
160
|
+
method: "POST",
|
|
161
|
+
headers: { "Content-Type": "application/json" },
|
|
162
|
+
body: JSON.stringify(body),
|
|
163
|
+
signal: ac.signal
|
|
164
|
+
});
|
|
165
|
+
if (!res.ok) {
|
|
166
|
+
const err = await res.text();
|
|
167
|
+
throw new Error(`POST ${url} failed (${res.status}): ${err}`);
|
|
168
|
+
}
|
|
169
|
+
return await res.json();
|
|
170
|
+
} catch (e) {
|
|
171
|
+
if (e.name === "AbortError") {
|
|
172
|
+
throw new Error(`POST ${url} timed out after ${timeoutMs}ms`);
|
|
173
|
+
}
|
|
174
|
+
throw e;
|
|
175
|
+
} finally {
|
|
176
|
+
clearTimeout(timer);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
var InsufficientBalanceError = class extends Error {
|
|
180
|
+
constructor(balance, required, tokenAddress) {
|
|
181
|
+
super(
|
|
182
|
+
`Insufficient token balance: have ${balance}, need ${required} (token ${tokenAddress})`
|
|
183
|
+
);
|
|
184
|
+
this.balance = balance;
|
|
185
|
+
this.required = required;
|
|
186
|
+
this.tokenAddress = tokenAddress;
|
|
187
|
+
this.name = "InsufficientBalanceError";
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
function parseUserOp(raw) {
|
|
191
|
+
return {
|
|
192
|
+
sender: raw.sender,
|
|
193
|
+
nonce: BigInt(raw.nonce),
|
|
194
|
+
callData: raw.callData,
|
|
195
|
+
callGasLimit: BigInt(raw.callGasLimit),
|
|
196
|
+
verificationGasLimit: BigInt(raw.verificationGasLimit),
|
|
197
|
+
preVerificationGas: BigInt(raw.preVerificationGas),
|
|
198
|
+
maxFeePerGas: BigInt(raw.maxFeePerGas),
|
|
199
|
+
maxPriorityFeePerGas: BigInt(raw.maxPriorityFeePerGas),
|
|
200
|
+
...raw.paymaster && { paymaster: raw.paymaster },
|
|
201
|
+
...raw.paymasterVerificationGasLimit && {
|
|
202
|
+
paymasterVerificationGasLimit: BigInt(raw.paymasterVerificationGasLimit)
|
|
203
|
+
},
|
|
204
|
+
...raw.paymasterPostOpGasLimit && {
|
|
205
|
+
paymasterPostOpGasLimit: BigInt(raw.paymasterPostOpGasLimit)
|
|
206
|
+
},
|
|
207
|
+
...raw.paymasterData && { paymasterData: raw.paymasterData },
|
|
208
|
+
...raw.factory && { factory: raw.factory },
|
|
209
|
+
...raw.factoryData && { factoryData: raw.factoryData },
|
|
210
|
+
signature: "0x"
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
function serializeUserOp(op) {
|
|
214
|
+
const toHex2 = (n) => `0x${n.toString(16)}`;
|
|
215
|
+
return {
|
|
216
|
+
sender: op.sender,
|
|
217
|
+
nonce: toHex2(op.nonce),
|
|
218
|
+
callData: op.callData,
|
|
219
|
+
callGasLimit: toHex2(op.callGasLimit),
|
|
220
|
+
verificationGasLimit: toHex2(op.verificationGasLimit),
|
|
221
|
+
preVerificationGas: toHex2(op.preVerificationGas),
|
|
222
|
+
maxFeePerGas: toHex2(op.maxFeePerGas),
|
|
223
|
+
maxPriorityFeePerGas: toHex2(op.maxPriorityFeePerGas),
|
|
224
|
+
...op.paymaster && { paymaster: op.paymaster },
|
|
225
|
+
...op.paymasterVerificationGasLimit !== void 0 && {
|
|
226
|
+
paymasterVerificationGasLimit: toHex2(op.paymasterVerificationGasLimit)
|
|
227
|
+
},
|
|
228
|
+
...op.paymasterPostOpGasLimit !== void 0 && {
|
|
229
|
+
paymasterPostOpGasLimit: toHex2(op.paymasterPostOpGasLimit)
|
|
230
|
+
},
|
|
231
|
+
...op.paymasterData && { paymasterData: op.paymasterData },
|
|
232
|
+
...op.factory && { factory: op.factory },
|
|
233
|
+
...op.factoryData && { factoryData: op.factoryData },
|
|
234
|
+
...op.signature && { signature: op.signature }
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
async function smartDeposit(params) {
|
|
238
|
+
const {
|
|
239
|
+
privateKey,
|
|
240
|
+
rpcUrl,
|
|
241
|
+
allsetApiUrl,
|
|
242
|
+
tokenAddress,
|
|
243
|
+
amount,
|
|
244
|
+
bridgeAddress,
|
|
245
|
+
depositCalldata,
|
|
246
|
+
requestTimeoutMs = 6e4
|
|
247
|
+
} = params;
|
|
248
|
+
const eoa = privateKeyToAccount(privateKey);
|
|
249
|
+
const publicClient = createPublicClient({ transport: http(rpcUrl) });
|
|
250
|
+
const tokenBalance = await publicClient.readContract({
|
|
251
|
+
address: tokenAddress,
|
|
252
|
+
abi: ERC20_BALANCEOF_ABI,
|
|
253
|
+
functionName: "balanceOf",
|
|
254
|
+
args: [eoa.address]
|
|
255
|
+
});
|
|
256
|
+
if (tokenBalance < amount) {
|
|
257
|
+
throw new InsufficientBalanceError(tokenBalance, amount, tokenAddress);
|
|
258
|
+
}
|
|
259
|
+
const chainId = await publicClient.getChainId();
|
|
260
|
+
const timestamp = Math.floor(Date.now() / 1e3);
|
|
261
|
+
const nonceBytes = crypto.getRandomValues(new Uint8Array(32));
|
|
262
|
+
const nonce = `0x${Array.from(nonceBytes, (b) => b.toString(16).padStart(2, "0")).join("")}`;
|
|
263
|
+
const DOMAIN_TAG = "AllSet Portal authSig v1";
|
|
264
|
+
const msgHash = keccak2562(
|
|
265
|
+
encodeAbiParameters2(
|
|
266
|
+
[
|
|
267
|
+
{ type: "string" },
|
|
268
|
+
{ type: "uint256" },
|
|
269
|
+
{ type: "bytes32" },
|
|
270
|
+
{ type: "address" },
|
|
271
|
+
{ type: "address" },
|
|
272
|
+
{ type: "uint256" },
|
|
273
|
+
{ type: "address" },
|
|
274
|
+
{ type: "bytes" },
|
|
275
|
+
{ type: "uint256" }
|
|
276
|
+
],
|
|
277
|
+
[
|
|
278
|
+
DOMAIN_TAG,
|
|
279
|
+
BigInt(chainId),
|
|
280
|
+
nonce,
|
|
281
|
+
eoa.address,
|
|
282
|
+
tokenAddress,
|
|
283
|
+
amount,
|
|
284
|
+
bridgeAddress,
|
|
285
|
+
depositCalldata,
|
|
286
|
+
BigInt(timestamp)
|
|
287
|
+
]
|
|
288
|
+
)
|
|
289
|
+
);
|
|
290
|
+
const authSig = await eoa.signMessage({ message: { raw: msgHash } });
|
|
291
|
+
const prepareReq = {
|
|
292
|
+
rpcUrl,
|
|
293
|
+
from: eoa.address,
|
|
294
|
+
tokenAddress,
|
|
295
|
+
amount: amount.toString(),
|
|
296
|
+
bridgeAddress,
|
|
297
|
+
depositCalldata,
|
|
298
|
+
chainId,
|
|
299
|
+
nonce,
|
|
300
|
+
timestamp,
|
|
301
|
+
authSig
|
|
302
|
+
};
|
|
303
|
+
const PREPARE_DELAYS = [0, 500, 1500];
|
|
304
|
+
let prepared;
|
|
305
|
+
for (let attempt = 0; attempt < PREPARE_DELAYS.length; attempt++) {
|
|
306
|
+
if (PREPARE_DELAYS[attempt] > 0) {
|
|
307
|
+
await new Promise((r) => setTimeout(r, PREPARE_DELAYS[attempt]));
|
|
308
|
+
}
|
|
309
|
+
try {
|
|
310
|
+
prepared = await postJson(
|
|
311
|
+
`${allsetApiUrl}/userop/prepare`,
|
|
312
|
+
prepareReq,
|
|
313
|
+
requestTimeoutMs
|
|
314
|
+
);
|
|
315
|
+
break;
|
|
316
|
+
} catch (e) {
|
|
317
|
+
const isLast = attempt === PREPARE_DELAYS.length - 1;
|
|
318
|
+
const msg = e.message ?? "";
|
|
319
|
+
const isRetryable = !msg.match(/POST .+ failed \([1-4][0-9]{2}\)/) || msg.includes("(429)") || msg.includes("(5");
|
|
320
|
+
if (isLast || !isRetryable) throw e;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
if (!TRUSTED_DELEGATES.has(prepared.delegate7702Address.toLowerCase())) {
|
|
324
|
+
throw new Error(
|
|
325
|
+
`smartDeposit: untrusted delegate address returned by backend: ${prepared.delegate7702Address}`
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
let eip7702Auth;
|
|
329
|
+
if (prepared.needsAuthorization) {
|
|
330
|
+
const accountNonce = await publicClient.getTransactionCount({
|
|
331
|
+
address: eoa.address,
|
|
332
|
+
blockTag: "pending"
|
|
333
|
+
});
|
|
334
|
+
const signed = await eoa.signAuthorization({
|
|
335
|
+
address: prepared.delegate7702Address,
|
|
336
|
+
chainId,
|
|
337
|
+
nonce: accountNonce
|
|
338
|
+
});
|
|
339
|
+
const yParity = signed.yParity ?? 0;
|
|
340
|
+
eip7702Auth = {
|
|
341
|
+
address: prepared.delegate7702Address,
|
|
342
|
+
chainId: toEvenHex(chainId),
|
|
343
|
+
nonce: toEvenHex(accountNonce),
|
|
344
|
+
yParity: toEvenHex(yParity),
|
|
345
|
+
r: `0x${BigInt(signed.r).toString(16).padStart(64, "0")}`,
|
|
346
|
+
s: `0x${BigInt(signed.s).toString(16).padStart(64, "0")}`
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
const userOpToSign = parseUserOp(prepared.unsignedUserOp);
|
|
350
|
+
const typedData = getUserOperationTypedData({
|
|
351
|
+
chainId,
|
|
352
|
+
entryPointAddress: ENTRY_POINT_V08,
|
|
353
|
+
userOperation: { ...userOpToSign, signature: "0x" }
|
|
354
|
+
});
|
|
355
|
+
const signature = await eoa.signTypedData(typedData);
|
|
356
|
+
const signedUserOp = { ...userOpToSign, signature };
|
|
357
|
+
const serialized = serializeUserOp(signedUserOp);
|
|
358
|
+
if (eip7702Auth) {
|
|
359
|
+
serialized.eip7702Auth = eip7702Auth;
|
|
360
|
+
}
|
|
361
|
+
const submitReq = {
|
|
362
|
+
rpcUrl,
|
|
363
|
+
signedUserOp: serialized
|
|
364
|
+
};
|
|
365
|
+
const { txHash, userOpHash: returnedUserOpHash } = await postJson(
|
|
366
|
+
`${allsetApiUrl}/userop/submit`,
|
|
367
|
+
submitReq,
|
|
368
|
+
requestTimeoutMs
|
|
369
|
+
);
|
|
370
|
+
return {
|
|
371
|
+
txHash,
|
|
372
|
+
userOpHash: returnedUserOpHash,
|
|
373
|
+
userAddress: eoa.address
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// src/evm.ts
|
|
378
|
+
import { createPublicClient as createPublicClient2, createWalletClient, http as http2, parseAbi as parseAbi2 } from "viem";
|
|
379
|
+
import { generatePrivateKey, privateKeyToAccount as privateKeyToAccount2 } from "viem/accounts";
|
|
380
|
+
import { arbitrum, arbitrumSepolia, base, mainnet as ethereum, sepolia } from "viem/chains";
|
|
381
|
+
function normalizePrivateKey(privateKey) {
|
|
382
|
+
return privateKey.startsWith("0x") ? privateKey : `0x${privateKey}`;
|
|
383
|
+
}
|
|
384
|
+
function createEvmWallet(privateKey) {
|
|
385
|
+
const key = privateKey ? normalizePrivateKey(privateKey) : generatePrivateKey();
|
|
386
|
+
return Object.assign(privateKeyToAccount2(key), { privateKey: key });
|
|
387
|
+
}
|
|
388
|
+
var ERC20_ABI = parseAbi2([
|
|
389
|
+
"function approve(address spender, uint256 amount) returns (bool)",
|
|
390
|
+
"function allowance(address owner, address spender) view returns (uint256)",
|
|
391
|
+
"function balanceOf(address owner) view returns (uint256)"
|
|
392
|
+
]);
|
|
393
|
+
var CHAIN_MAP = {
|
|
394
|
+
1: ethereum,
|
|
395
|
+
11155111: sepolia,
|
|
396
|
+
421614: arbitrumSepolia,
|
|
397
|
+
42161: arbitrum,
|
|
398
|
+
8453: base
|
|
399
|
+
};
|
|
400
|
+
function createEvmExecutor(account, rpcUrl, chainOrId) {
|
|
401
|
+
const chain = typeof chainOrId === "number" ? resolveChain(chainOrId) : chainOrId;
|
|
402
|
+
const walletClient = createWalletClient({
|
|
403
|
+
account,
|
|
404
|
+
chain,
|
|
405
|
+
transport: http2(rpcUrl)
|
|
406
|
+
});
|
|
407
|
+
const publicClient = createPublicClient2({
|
|
408
|
+
chain,
|
|
409
|
+
transport: http2(rpcUrl)
|
|
410
|
+
});
|
|
411
|
+
return { walletClient, publicClient };
|
|
412
|
+
}
|
|
413
|
+
function resolveChain(chainId) {
|
|
414
|
+
const chain = CHAIN_MAP[chainId];
|
|
415
|
+
if (!chain) {
|
|
416
|
+
throw new Error(
|
|
417
|
+
`Unsupported EVM chain ID: ${chainId}. Supported: ${Object.keys(CHAIN_MAP).join(", ")}. Pass a viem Chain object directly to avoid this restriction.`
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
return chain;
|
|
421
|
+
}
|
|
422
|
+
async function getEvmErc20Balance(rpcUrl, tokenAddress, ownerAddress) {
|
|
423
|
+
const client = createPublicClient2({ transport: http2(rpcUrl) });
|
|
424
|
+
return client.readContract({
|
|
425
|
+
address: tokenAddress,
|
|
426
|
+
abi: ERC20_ABI,
|
|
427
|
+
functionName: "balanceOf",
|
|
428
|
+
args: [ownerAddress]
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
async function getEvmNativeBalance(rpcUrl, address) {
|
|
432
|
+
const client = createPublicClient2({ transport: http2(rpcUrl) });
|
|
433
|
+
return client.getBalance({ address });
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// src/intents.ts
|
|
437
|
+
import { encodeAbiParameters as encodeAbiParameters3 } from "viem";
|
|
438
|
+
var IntentAction = /* @__PURE__ */ ((IntentAction2) => {
|
|
439
|
+
IntentAction2[IntentAction2["Execute"] = 0] = "Execute";
|
|
440
|
+
IntentAction2[IntentAction2["DynamicTransfer"] = 1] = "DynamicTransfer";
|
|
441
|
+
IntentAction2[IntentAction2["DynamicDeposit"] = 2] = "DynamicDeposit";
|
|
442
|
+
IntentAction2[IntentAction2["Revoke"] = 3] = "Revoke";
|
|
443
|
+
return IntentAction2;
|
|
444
|
+
})(IntentAction || {});
|
|
445
|
+
function buildTransferIntent(token, receiver) {
|
|
446
|
+
const payload = encodeAbiParameters3([{ type: "address" }, { type: "address" }], [token, receiver]);
|
|
447
|
+
return {
|
|
448
|
+
action: 1 /* DynamicTransfer */,
|
|
449
|
+
payload,
|
|
450
|
+
value: 0n
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
function buildExecuteIntent(target, calldata, value = 0n) {
|
|
454
|
+
const payload = encodeAbiParameters3([{ type: "address" }, { type: "bytes" }], [target, calldata]);
|
|
455
|
+
return {
|
|
456
|
+
action: 0 /* Execute */,
|
|
457
|
+
payload,
|
|
458
|
+
value
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
function buildDepositBackIntent(token, fastReceiver) {
|
|
462
|
+
const receiverBytes = fastAddressToBytes32(fastReceiver);
|
|
463
|
+
const payload = encodeAbiParameters3([{ type: "address" }, { type: "bytes32" }], [token, receiverBytes]);
|
|
464
|
+
return {
|
|
465
|
+
action: 2 /* DynamicDeposit */,
|
|
466
|
+
payload,
|
|
467
|
+
value: 0n
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
function buildRevokeIntent() {
|
|
471
|
+
return {
|
|
472
|
+
action: 3 /* Revoke */,
|
|
473
|
+
payload: "0x",
|
|
474
|
+
value: 0n
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// src/bridge.ts
|
|
479
|
+
import { TransactionCertificateFromRpc } from "@fastxyz/schema";
|
|
480
|
+
import { TransactionBuilder } from "@fastxyz/sdk";
|
|
481
|
+
import { Schema } from "effect";
|
|
482
|
+
import { decodeAbiParameters } from "viem";
|
|
483
|
+
|
|
484
|
+
// src/errors.ts
|
|
485
|
+
var FastError = class extends Error {
|
|
486
|
+
code;
|
|
487
|
+
note;
|
|
488
|
+
constructor(code, message, opts) {
|
|
489
|
+
super(message);
|
|
490
|
+
this.name = "FastError";
|
|
491
|
+
this.code = code;
|
|
492
|
+
this.note = opts?.note ?? "";
|
|
493
|
+
}
|
|
494
|
+
toJSON() {
|
|
495
|
+
return { name: this.name, code: this.code, message: this.message, note: this.note };
|
|
496
|
+
}
|
|
497
|
+
};
|
|
498
|
+
|
|
499
|
+
// src/relay.ts
|
|
500
|
+
async function relayExecute(params) {
|
|
501
|
+
const {
|
|
502
|
+
relayerUrl,
|
|
503
|
+
encodedTransferClaim,
|
|
504
|
+
transferProof,
|
|
505
|
+
transferFastTxId,
|
|
506
|
+
fastsetAddress,
|
|
507
|
+
externalAddress,
|
|
508
|
+
encodedIntentClaim,
|
|
509
|
+
intentProof,
|
|
510
|
+
intentFastTxId,
|
|
511
|
+
intentClaimId,
|
|
512
|
+
externalTokenAddress
|
|
513
|
+
} = params;
|
|
514
|
+
const body = {
|
|
515
|
+
encoded_transfer_claim: encodedTransferClaim,
|
|
516
|
+
transfer_proof: transferProof,
|
|
517
|
+
transfer_fast_tx_id: transferFastTxId,
|
|
518
|
+
transfer_claim_id: transferFastTxId,
|
|
519
|
+
fastset_address: fastsetAddress,
|
|
520
|
+
external_address: externalAddress
|
|
521
|
+
};
|
|
522
|
+
if (encodedIntentClaim && intentProof) {
|
|
523
|
+
body.encoded_intent_claim = encodedIntentClaim;
|
|
524
|
+
body.intent_proof = intentProof;
|
|
525
|
+
}
|
|
526
|
+
if (intentFastTxId) {
|
|
527
|
+
body.intent_fast_tx_id = intentFastTxId;
|
|
528
|
+
}
|
|
529
|
+
if (intentClaimId) {
|
|
530
|
+
body.intent_claim_id = intentClaimId;
|
|
531
|
+
}
|
|
532
|
+
if (externalTokenAddress) {
|
|
533
|
+
body.external_token_address = externalTokenAddress;
|
|
534
|
+
}
|
|
535
|
+
const relayRes = await fetch(`${relayerUrl.replace(/\/$/, "")}/relay`, {
|
|
536
|
+
method: "POST",
|
|
537
|
+
headers: { "Content-Type": "application/json" },
|
|
538
|
+
body: JSON.stringify(body)
|
|
539
|
+
});
|
|
540
|
+
if (!relayRes.ok) {
|
|
541
|
+
const text = await relayRes.text();
|
|
542
|
+
throw new FastError("TX_FAILED", `Relayer request failed (${relayRes.status}): ${text}`, {
|
|
543
|
+
note: "The intent was submitted to Fast network but the relayer rejected it. Try again."
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
return { success: true };
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
// src/bridge.ts
|
|
550
|
+
function hexToUint8Array2(hex) {
|
|
551
|
+
const clean = hex.startsWith("0x") ? hex.slice(2) : hex;
|
|
552
|
+
const bytes = new Uint8Array(clean.length / 2);
|
|
553
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
554
|
+
bytes[i] = parseInt(clean.slice(i * 2, i * 2 + 2), 16);
|
|
555
|
+
}
|
|
556
|
+
return bytes;
|
|
557
|
+
}
|
|
558
|
+
function bigIntToNumber(obj) {
|
|
559
|
+
if (typeof obj === "bigint") return Number(obj);
|
|
560
|
+
if (obj instanceof Uint8Array) return Array.from(obj);
|
|
561
|
+
if (Array.isArray(obj)) return obj.map(bigIntToNumber);
|
|
562
|
+
if (obj !== null && typeof obj === "object") {
|
|
563
|
+
const result = {};
|
|
564
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
565
|
+
result[key] = bigIntToNumber(value);
|
|
566
|
+
}
|
|
567
|
+
return result;
|
|
568
|
+
}
|
|
569
|
+
return obj;
|
|
570
|
+
}
|
|
571
|
+
function resolveExternalAddress(intents, externalAddressOverride) {
|
|
572
|
+
if (externalAddressOverride) return externalAddressOverride;
|
|
573
|
+
for (const intent of intents) {
|
|
574
|
+
if (intent.action === 1 /* DynamicTransfer */) {
|
|
575
|
+
try {
|
|
576
|
+
const [, receiver] = decodeAbiParameters(
|
|
577
|
+
[{ type: "address" }, { type: "address" }],
|
|
578
|
+
intent.payload
|
|
579
|
+
);
|
|
580
|
+
return receiver;
|
|
581
|
+
} catch {
|
|
582
|
+
continue;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
if (intent.action === 0 /* Execute */) {
|
|
586
|
+
try {
|
|
587
|
+
const [target] = decodeAbiParameters(
|
|
588
|
+
[{ type: "address" }, { type: "bytes" }],
|
|
589
|
+
intent.payload
|
|
590
|
+
);
|
|
591
|
+
return target;
|
|
592
|
+
} catch {
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
return null;
|
|
597
|
+
}
|
|
598
|
+
async function sendTx(clients, tx) {
|
|
599
|
+
const walletClient = clients.walletClient;
|
|
600
|
+
const hash = await walletClient.sendTransaction({
|
|
601
|
+
to: tx.to,
|
|
602
|
+
data: tx.data,
|
|
603
|
+
value: BigInt(tx.value),
|
|
604
|
+
gas: tx.gas ? BigInt(tx.gas) : void 0
|
|
605
|
+
});
|
|
606
|
+
const receipt = await clients.publicClient.waitForTransactionReceipt({
|
|
607
|
+
hash
|
|
608
|
+
});
|
|
609
|
+
return {
|
|
610
|
+
txHash: hash,
|
|
611
|
+
status: receipt.status === "success" ? "success" : "reverted"
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
async function checkAllowance(clients, token, spender, owner) {
|
|
615
|
+
return clients.publicClient.readContract({
|
|
616
|
+
address: token,
|
|
617
|
+
abi: ERC20_ABI,
|
|
618
|
+
functionName: "allowance",
|
|
619
|
+
args: [owner, spender]
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
async function approveErc20(clients, token, spender, amount) {
|
|
623
|
+
const walletClient = clients.walletClient;
|
|
624
|
+
const hash = await walletClient.writeContract({
|
|
625
|
+
address: token,
|
|
626
|
+
abi: ERC20_ABI,
|
|
627
|
+
functionName: "approve",
|
|
628
|
+
args: [spender, BigInt(amount)]
|
|
629
|
+
});
|
|
630
|
+
const receipt = await clients.publicClient.waitForTransactionReceipt({ hash });
|
|
631
|
+
if (receipt.status === "reverted") {
|
|
632
|
+
throw new FastError(
|
|
633
|
+
"TX_FAILED",
|
|
634
|
+
`ERC-20 approve transaction reverted: ${hash}`,
|
|
635
|
+
{
|
|
636
|
+
note: "Check that you have sufficient ETH for gas fees."
|
|
637
|
+
}
|
|
638
|
+
);
|
|
639
|
+
}
|
|
640
|
+
const amountBig = BigInt(amount);
|
|
641
|
+
const walletAddress = walletClient.account?.address;
|
|
642
|
+
for (let attempt = 0; attempt < 10; attempt++) {
|
|
643
|
+
const current = await checkAllowance(clients, token, spender, walletAddress);
|
|
644
|
+
if (current >= amountBig) break;
|
|
645
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
async function evmSign(certificate, crossSignUrl) {
|
|
649
|
+
const wireFormat = Schema.encodeSync(TransactionCertificateFromRpc)(
|
|
650
|
+
certificate
|
|
651
|
+
);
|
|
652
|
+
const serialized = bigIntToNumber(wireFormat);
|
|
653
|
+
const res = await fetch(crossSignUrl, {
|
|
654
|
+
method: "POST",
|
|
655
|
+
headers: { "Content-Type": "application/json" },
|
|
656
|
+
body: JSON.stringify({
|
|
657
|
+
jsonrpc: "2.0",
|
|
658
|
+
id: 1,
|
|
659
|
+
method: "crossSign_evmSignCertificate",
|
|
660
|
+
params: { certificate: serialized }
|
|
661
|
+
})
|
|
662
|
+
});
|
|
663
|
+
if (!res.ok) {
|
|
664
|
+
throw new FastError(
|
|
665
|
+
"TX_FAILED",
|
|
666
|
+
`Cross-sign request failed: ${res.status}`,
|
|
667
|
+
{
|
|
668
|
+
note: "The AllSet cross-sign service rejected the request."
|
|
669
|
+
}
|
|
670
|
+
);
|
|
671
|
+
}
|
|
672
|
+
const json = await res.json();
|
|
673
|
+
if (json.error) {
|
|
674
|
+
throw new FastError(
|
|
675
|
+
"TX_FAILED",
|
|
676
|
+
`Cross-sign error: ${json.error.message}`,
|
|
677
|
+
{
|
|
678
|
+
note: "The certificate could not be cross-signed."
|
|
679
|
+
}
|
|
680
|
+
);
|
|
681
|
+
}
|
|
682
|
+
if (!json.result?.transaction || !json.result?.signature) {
|
|
683
|
+
throw new FastError("TX_FAILED", "Cross-sign returned invalid response", {
|
|
684
|
+
note: "Missing transaction or signature in response."
|
|
685
|
+
});
|
|
686
|
+
}
|
|
687
|
+
return json.result;
|
|
688
|
+
}
|
|
689
|
+
async function executeDeposit(params) {
|
|
690
|
+
const {
|
|
691
|
+
chainId,
|
|
692
|
+
bridgeContract,
|
|
693
|
+
tokenAddress,
|
|
694
|
+
isNative = false,
|
|
695
|
+
amount,
|
|
696
|
+
receiverAddress,
|
|
697
|
+
evmClients
|
|
698
|
+
} = params;
|
|
699
|
+
let depositPlan;
|
|
700
|
+
try {
|
|
701
|
+
depositPlan = buildDepositTransaction({
|
|
702
|
+
chainId,
|
|
703
|
+
bridgeContract,
|
|
704
|
+
tokenAddress,
|
|
705
|
+
isNative,
|
|
706
|
+
amount: BigInt(amount),
|
|
707
|
+
receiver: receiverAddress
|
|
708
|
+
});
|
|
709
|
+
} catch (err) {
|
|
710
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
711
|
+
throw new FastError(
|
|
712
|
+
"INVALID_ADDRESS",
|
|
713
|
+
`Failed to decode Fast receiver address "${receiverAddress}": ${msg}`,
|
|
714
|
+
{
|
|
715
|
+
note: "The receiver address must be a valid Fast network bech32m address (fast1...)."
|
|
716
|
+
}
|
|
717
|
+
);
|
|
718
|
+
}
|
|
719
|
+
let txHash;
|
|
720
|
+
if (isNative) {
|
|
721
|
+
const receipt = await sendTx(evmClients, {
|
|
722
|
+
to: depositPlan.to,
|
|
723
|
+
data: depositPlan.data,
|
|
724
|
+
value: depositPlan.value.toString()
|
|
725
|
+
});
|
|
726
|
+
if (receipt.status === "reverted") {
|
|
727
|
+
throw new FastError(
|
|
728
|
+
"TX_FAILED",
|
|
729
|
+
`Deposit transaction reverted: ${receipt.txHash}`,
|
|
730
|
+
{
|
|
731
|
+
note: "Check that you have sufficient ETH balance."
|
|
732
|
+
}
|
|
733
|
+
);
|
|
734
|
+
}
|
|
735
|
+
txHash = receipt.txHash;
|
|
736
|
+
} else {
|
|
737
|
+
await approveErc20(evmClients, tokenAddress, bridgeContract, amount);
|
|
738
|
+
const receipt = await sendTx(evmClients, {
|
|
739
|
+
to: depositPlan.to,
|
|
740
|
+
data: depositPlan.data,
|
|
741
|
+
value: depositPlan.value.toString()
|
|
742
|
+
});
|
|
743
|
+
if (receipt.status === "reverted") {
|
|
744
|
+
throw new FastError(
|
|
745
|
+
"TX_FAILED",
|
|
746
|
+
`Deposit transaction reverted: ${receipt.txHash}`,
|
|
747
|
+
{
|
|
748
|
+
note: "Check that you have sufficient token balance and the approval succeeded."
|
|
749
|
+
}
|
|
750
|
+
);
|
|
751
|
+
}
|
|
752
|
+
txHash = receipt.txHash;
|
|
753
|
+
}
|
|
754
|
+
return { txHash, orderId: txHash, estimatedTime: "1-5 minutes" };
|
|
755
|
+
}
|
|
756
|
+
async function executeIntent(params) {
|
|
757
|
+
const {
|
|
758
|
+
fastBridgeAddress,
|
|
759
|
+
relayerUrl,
|
|
760
|
+
crossSignUrl,
|
|
761
|
+
tokenEvmAddress,
|
|
762
|
+
tokenFastTokenId,
|
|
763
|
+
amount,
|
|
764
|
+
intents,
|
|
765
|
+
externalAddress: externalAddressOverride,
|
|
766
|
+
deadlineSeconds = 3600,
|
|
767
|
+
signer,
|
|
768
|
+
provider,
|
|
769
|
+
networkId
|
|
770
|
+
} = params;
|
|
771
|
+
if (!intents || intents.length === 0) {
|
|
772
|
+
throw new FastError(
|
|
773
|
+
"INVALID_PARAMS",
|
|
774
|
+
"executeIntent requires at least one intent",
|
|
775
|
+
{
|
|
776
|
+
note: "Use intent builders like buildTransferIntent(), buildExecuteIntent(), etc."
|
|
777
|
+
}
|
|
778
|
+
);
|
|
779
|
+
}
|
|
780
|
+
if (externalAddressOverride && !externalAddressOverride.startsWith("0x")) {
|
|
781
|
+
throw new FastError(
|
|
782
|
+
"INVALID_PARAMS",
|
|
783
|
+
"executeIntent externalAddress must be an EVM address",
|
|
784
|
+
{
|
|
785
|
+
note: "Pass a 0x-prefixed address for the relayer target."
|
|
786
|
+
}
|
|
787
|
+
);
|
|
788
|
+
}
|
|
789
|
+
const tokenId = hexToUint8Array2(tokenFastTokenId);
|
|
790
|
+
const publicKey = await signer.getPublicKey();
|
|
791
|
+
const fastAddress = await signer.getFastAddress();
|
|
792
|
+
const accountInfo1 = await provider.getAccountInfo({
|
|
793
|
+
address: publicKey,
|
|
794
|
+
tokenBalancesFilter: null,
|
|
795
|
+
stateKeyFilter: null,
|
|
796
|
+
certificateByNonce: null
|
|
797
|
+
});
|
|
798
|
+
const transferEnvelope = await new TransactionBuilder({
|
|
799
|
+
networkId,
|
|
800
|
+
signer,
|
|
801
|
+
nonce: accountInfo1.nextNonce
|
|
802
|
+
}).addTokenTransfer({
|
|
803
|
+
tokenId,
|
|
804
|
+
recipient: fastAddressToBytes(fastBridgeAddress),
|
|
805
|
+
amount: BigInt(amount),
|
|
806
|
+
userData: null
|
|
807
|
+
}).sign();
|
|
808
|
+
const transferResult = await provider.submitTransaction(transferEnvelope);
|
|
809
|
+
if (transferResult.type !== "Success") {
|
|
810
|
+
throw new FastError(
|
|
811
|
+
"TX_FAILED",
|
|
812
|
+
`Token transfer submission incomplete: ${transferResult.type}`,
|
|
813
|
+
{
|
|
814
|
+
note: "The transfer transaction was not fully confirmed. Try again."
|
|
815
|
+
}
|
|
816
|
+
);
|
|
817
|
+
}
|
|
818
|
+
const transferCrossSign = await evmSign(transferResult.value, crossSignUrl);
|
|
819
|
+
const transferFastTxId = extractClaimId(transferCrossSign.transaction);
|
|
820
|
+
const deadline = BigInt(Math.floor(Date.now() / 1e3) + deadlineSeconds);
|
|
821
|
+
const intentClaimEncoded = encodeIntentClaim({
|
|
822
|
+
transferFastTxId,
|
|
823
|
+
deadline,
|
|
824
|
+
intents
|
|
825
|
+
});
|
|
826
|
+
const intentBytes = hexToUint8Array2(intentClaimEncoded);
|
|
827
|
+
const accountInfo2 = await provider.getAccountInfo({
|
|
828
|
+
address: publicKey,
|
|
829
|
+
tokenBalancesFilter: null,
|
|
830
|
+
stateKeyFilter: null,
|
|
831
|
+
certificateByNonce: null
|
|
832
|
+
});
|
|
833
|
+
const intentEnvelope = await new TransactionBuilder({
|
|
834
|
+
networkId,
|
|
835
|
+
signer,
|
|
836
|
+
nonce: accountInfo2.nextNonce
|
|
837
|
+
}).addExternalClaim({
|
|
838
|
+
claim: {
|
|
839
|
+
verifierCommittee: [],
|
|
840
|
+
verifierQuorum: 0,
|
|
841
|
+
claimData: intentBytes
|
|
842
|
+
},
|
|
843
|
+
signatures: []
|
|
844
|
+
}).sign();
|
|
845
|
+
const intentResult = await provider.submitTransaction(intentEnvelope);
|
|
846
|
+
if (intentResult.type !== "Success") {
|
|
847
|
+
throw new FastError(
|
|
848
|
+
"TX_FAILED",
|
|
849
|
+
`Intent claim submission incomplete: ${intentResult.type}`,
|
|
850
|
+
{
|
|
851
|
+
note: "The intent claim transaction was not fully confirmed. Try again."
|
|
852
|
+
}
|
|
853
|
+
);
|
|
854
|
+
}
|
|
855
|
+
const intentCrossSign = await evmSign(intentResult.value, crossSignUrl);
|
|
856
|
+
const intentFastTxId = extractClaimId(intentCrossSign.transaction);
|
|
857
|
+
const externalAddress = resolveExternalAddress(
|
|
858
|
+
intents,
|
|
859
|
+
externalAddressOverride
|
|
860
|
+
);
|
|
861
|
+
if (!externalAddress) {
|
|
862
|
+
throw new FastError(
|
|
863
|
+
"INVALID_PARAMS",
|
|
864
|
+
"executeIntent requires externalAddress when intents do not include a transfer recipient or execute target",
|
|
865
|
+
{
|
|
866
|
+
note: "Pass externalAddress for flows like buildDepositBackIntent() or buildRevokeIntent()."
|
|
867
|
+
}
|
|
868
|
+
);
|
|
869
|
+
}
|
|
870
|
+
await relayExecute({
|
|
871
|
+
relayerUrl,
|
|
872
|
+
encodedTransferClaim: Array.from(
|
|
873
|
+
new Uint8Array(transferCrossSign.transaction.map(Number))
|
|
874
|
+
),
|
|
875
|
+
transferProof: transferCrossSign.signature,
|
|
876
|
+
transferFastTxId,
|
|
877
|
+
fastsetAddress: fastAddress,
|
|
878
|
+
externalAddress,
|
|
879
|
+
encodedIntentClaim: Array.from(
|
|
880
|
+
new Uint8Array(intentCrossSign.transaction.map(Number))
|
|
881
|
+
),
|
|
882
|
+
intentProof: intentCrossSign.signature,
|
|
883
|
+
intentFastTxId,
|
|
884
|
+
intentClaimId: intentFastTxId,
|
|
885
|
+
externalTokenAddress: tokenEvmAddress
|
|
886
|
+
});
|
|
887
|
+
return {
|
|
888
|
+
txHash: transferFastTxId,
|
|
889
|
+
orderId: transferFastTxId,
|
|
890
|
+
estimatedTime: "1-5 minutes"
|
|
891
|
+
};
|
|
892
|
+
}
|
|
893
|
+
async function executeWithdraw(params) {
|
|
894
|
+
const { receiverEvmAddress, tokenEvmAddress, ...rest } = params;
|
|
895
|
+
const intent = buildTransferIntent(tokenEvmAddress, receiverEvmAddress);
|
|
896
|
+
return executeIntent({ ...rest, tokenEvmAddress, intents: [intent] });
|
|
897
|
+
}
|
|
898
|
+
export {
|
|
899
|
+
CHAIN_MAP,
|
|
900
|
+
ERC20_ABI,
|
|
901
|
+
FastError,
|
|
902
|
+
InsufficientBalanceError,
|
|
903
|
+
IntentAction,
|
|
904
|
+
buildDepositBackIntent,
|
|
905
|
+
buildDepositTransaction,
|
|
906
|
+
buildExecuteIntent,
|
|
907
|
+
buildIntentClaimBytes,
|
|
908
|
+
buildRevokeIntent,
|
|
909
|
+
buildTransferIntent,
|
|
910
|
+
createEvmExecutor,
|
|
911
|
+
createEvmWallet,
|
|
912
|
+
encodeDepositCalldata,
|
|
913
|
+
encodeIntentClaim,
|
|
914
|
+
encodeTransferClaim,
|
|
915
|
+
evmSign,
|
|
916
|
+
executeDeposit,
|
|
917
|
+
executeIntent,
|
|
918
|
+
executeWithdraw,
|
|
919
|
+
extractClaimId,
|
|
920
|
+
fastAddressToBytes,
|
|
921
|
+
fastAddressToBytes32,
|
|
922
|
+
getEvmErc20Balance,
|
|
923
|
+
getEvmNativeBalance,
|
|
924
|
+
hashTransferClaim,
|
|
925
|
+
relayExecute,
|
|
926
|
+
smartDeposit
|
|
927
|
+
};
|