@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/intents.js
DELETED
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* intents.ts — Intent builders for AllSet external execution
|
|
3
|
-
*
|
|
4
|
-
* Intents define what actions to perform on EVM chains after
|
|
5
|
-
* transferring tokens from Fast network.
|
|
6
|
-
*/
|
|
7
|
-
import { encodeAbiParameters } from 'viem';
|
|
8
|
-
import { fastAddressToBytes32 } from './core/address.js';
|
|
9
|
-
// ---------------------------------------------------------------------------
|
|
10
|
-
// Types
|
|
11
|
-
// ---------------------------------------------------------------------------
|
|
12
|
-
/**
|
|
13
|
-
* Intent action types supported by AllSet bridge.
|
|
14
|
-
*/
|
|
15
|
-
export var IntentAction;
|
|
16
|
-
(function (IntentAction) {
|
|
17
|
-
/** Generic contract call */
|
|
18
|
-
IntentAction[IntentAction["Execute"] = 0] = "Execute";
|
|
19
|
-
/** ERC-20 transfer to address */
|
|
20
|
-
IntentAction[IntentAction["DynamicTransfer"] = 1] = "DynamicTransfer";
|
|
21
|
-
/** Deposit tokens back to Fast network */
|
|
22
|
-
IntentAction[IntentAction["DynamicDeposit"] = 2] = "DynamicDeposit";
|
|
23
|
-
/** Cancel/revoke pending intent */
|
|
24
|
-
IntentAction[IntentAction["Revoke"] = 3] = "Revoke";
|
|
25
|
-
})(IntentAction || (IntentAction = {}));
|
|
26
|
-
// ---------------------------------------------------------------------------
|
|
27
|
-
// Intent Builders
|
|
28
|
-
// ---------------------------------------------------------------------------
|
|
29
|
-
/**
|
|
30
|
-
* Build a transfer intent to send ERC-20 tokens to an address.
|
|
31
|
-
*
|
|
32
|
-
* @param token - ERC-20 token contract address
|
|
33
|
-
* @param receiver - Recipient EVM address
|
|
34
|
-
* @returns Intent for DynamicTransfer action
|
|
35
|
-
*
|
|
36
|
-
* @example
|
|
37
|
-
* ```ts
|
|
38
|
-
* const intent = buildTransferIntent(
|
|
39
|
-
* '0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d', // USDC
|
|
40
|
-
* '0xRecipientAddress'
|
|
41
|
-
* );
|
|
42
|
-
* ```
|
|
43
|
-
*/
|
|
44
|
-
export function buildTransferIntent(token, receiver) {
|
|
45
|
-
const payload = encodeAbiParameters([{ type: 'address' }, { type: 'address' }], [token, receiver]);
|
|
46
|
-
return {
|
|
47
|
-
action: IntentAction.DynamicTransfer,
|
|
48
|
-
payload,
|
|
49
|
-
value: 0n,
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Build a generic execute intent for arbitrary contract calls.
|
|
54
|
-
*
|
|
55
|
-
* @param target - Target contract address
|
|
56
|
-
* @param calldata - ABI-encoded function call data
|
|
57
|
-
* @param value - Native token value to send (default: 0)
|
|
58
|
-
* @returns Intent for Execute action
|
|
59
|
-
*
|
|
60
|
-
* @example
|
|
61
|
-
* ```ts
|
|
62
|
-
* // Call a contract function
|
|
63
|
-
* const calldata = encodeFunctionData({
|
|
64
|
-
* abi: contractAbi,
|
|
65
|
-
* functionName: 'someFunction',
|
|
66
|
-
* args: [arg1, arg2],
|
|
67
|
-
* });
|
|
68
|
-
* const intent = buildExecuteIntent('0xContractAddress', calldata);
|
|
69
|
-
* ```
|
|
70
|
-
*/
|
|
71
|
-
export function buildExecuteIntent(target, calldata, value = 0n) {
|
|
72
|
-
const payload = encodeAbiParameters([{ type: 'address' }, { type: 'bytes' }], [target, calldata]);
|
|
73
|
-
return {
|
|
74
|
-
action: IntentAction.Execute,
|
|
75
|
-
payload,
|
|
76
|
-
value,
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* Build an intent to deposit tokens back to Fast network.
|
|
81
|
-
*
|
|
82
|
-
* @param token - ERC-20 token contract address on EVM
|
|
83
|
-
* @param fastReceiver - Fast network recipient address (fast1...)
|
|
84
|
-
* @returns Intent for DynamicDeposit action
|
|
85
|
-
*
|
|
86
|
-
* @example
|
|
87
|
-
* ```ts
|
|
88
|
-
* const intent = buildDepositBackIntent(
|
|
89
|
-
* '0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d', // USDC
|
|
90
|
-
* 'fast1recipientaddress...'
|
|
91
|
-
* );
|
|
92
|
-
* ```
|
|
93
|
-
*/
|
|
94
|
-
export function buildDepositBackIntent(token, fastReceiver) {
|
|
95
|
-
const receiverBytes = fastAddressToBytes32(fastReceiver);
|
|
96
|
-
const payload = encodeAbiParameters([{ type: 'address' }, { type: 'bytes32' }], [token, receiverBytes]);
|
|
97
|
-
return {
|
|
98
|
-
action: IntentAction.DynamicDeposit,
|
|
99
|
-
payload,
|
|
100
|
-
value: 0n,
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
/**
|
|
104
|
-
* Build a revoke intent to cancel pending operations.
|
|
105
|
-
*
|
|
106
|
-
* @returns Intent for Revoke action
|
|
107
|
-
*
|
|
108
|
-
* @example
|
|
109
|
-
* ```ts
|
|
110
|
-
* const intent = buildRevokeIntent();
|
|
111
|
-
* ```
|
|
112
|
-
*/
|
|
113
|
-
export function buildRevokeIntent() {
|
|
114
|
-
return {
|
|
115
|
-
action: IntentAction.Revoke,
|
|
116
|
-
payload: '0x',
|
|
117
|
-
value: 0n,
|
|
118
|
-
};
|
|
119
|
-
}
|
package/dist/node/bridge.d.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* bridge.ts — AllSet bridge provider
|
|
3
|
-
*
|
|
4
|
-
* Bridges between Fast network and the SDK's supported EVM routes.
|
|
5
|
-
*
|
|
6
|
-
* Two directions:
|
|
7
|
-
* Deposit (EVM → Fast): call bridge.deposit(token, amount, receiver) on the EVM bridge contract
|
|
8
|
-
* Withdraw (Fast → EVM): transfer on Fast network + submit ExternalClaim intent + POST to relayer
|
|
9
|
-
*/
|
|
10
|
-
import type { BridgeParams, BridgeResult, ExecuteIntentParams } from './types.js';
|
|
11
|
-
import { type ChainConfig, type TokenConfig } from './config.js';
|
|
12
|
-
interface BridgeProviderConfig {
|
|
13
|
-
network: 'testnet' | 'mainnet';
|
|
14
|
-
crossSignUrl?: string;
|
|
15
|
-
getChainConfig(chain: string): ChainConfig | null;
|
|
16
|
-
getTokenConfig(chain: string, token: string): TokenConfig | null;
|
|
17
|
-
getNetworkConfig?(): {
|
|
18
|
-
chains: Record<string, ChainConfig>;
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
export interface EvmSignResult {
|
|
22
|
-
transaction: number[];
|
|
23
|
-
signature: string;
|
|
24
|
-
}
|
|
25
|
-
export declare function evmSign(certificate: unknown, crossSignUrl?: string): Promise<EvmSignResult>;
|
|
26
|
-
/**
|
|
27
|
-
* Execute a bridge operation with optional provider configuration.
|
|
28
|
-
* Called by AllSetProvider.bridge() or directly for low-level usage.
|
|
29
|
-
*/
|
|
30
|
-
export declare function executeBridge(params: BridgeParams, provider?: BridgeProviderConfig): Promise<BridgeResult>;
|
|
31
|
-
/**
|
|
32
|
-
* Execute intents on an EVM chain after transferring tokens from Fast network.
|
|
33
|
-
* This is the core function used by sendToExternal and can be used directly for
|
|
34
|
-
* advanced use cases like swaps, multi-step operations, etc.
|
|
35
|
-
*/
|
|
36
|
-
export declare function executeIntent(params: ExecuteIntentParams, provider?: BridgeProviderConfig): Promise<BridgeResult>;
|
|
37
|
-
export {};
|
|
38
|
-
//# sourceMappingURL=bridge.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../../src/node/bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAsC,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEtH,OAAO,EAAoD,KAAK,WAAW,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AA0GnH,UAAU,oBAAoB;IAC5B,OAAO,EAAE,SAAS,GAAG,SAAS,CAAC;IAC/B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAAC;IAClD,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAAC;IACjE,gBAAgB,CAAC,IAAI;QAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;KAAE,CAAC;CAC9D;AAiKD,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB;AAwCD,wBAAsB,OAAO,CAC3B,WAAW,EAAE,OAAO,EACpB,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,aAAa,CAAC,CA6CxB;AAID;;;GAGG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE,YAAY,EAAE,QAAQ,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,YAAY,CAAC,CAiChH;AAqID;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,mBAAmB,EAC3B,QAAQ,CAAC,EAAE,oBAAoB,GAC9B,OAAO,CAAC,YAAY,CAAC,CAuLvB"}
|
package/dist/node/bridge.js
DELETED
|
@@ -1,519 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* bridge.ts — AllSet bridge provider
|
|
3
|
-
*
|
|
4
|
-
* Bridges between Fast network and the SDK's supported EVM routes.
|
|
5
|
-
*
|
|
6
|
-
* Two directions:
|
|
7
|
-
* Deposit (EVM → Fast): call bridge.deposit(token, amount, receiver) on the EVM bridge contract
|
|
8
|
-
* Withdraw (Fast → EVM): transfer on Fast network + submit ExternalClaim intent + POST to relayer
|
|
9
|
-
*/
|
|
10
|
-
import { decodeAbiParameters, encodeAbiParameters } from 'viem';
|
|
11
|
-
import { fastAddressToBytes } from '../core/address.js';
|
|
12
|
-
import { getNetworkConfig, getChainConfig, getTokenConfig } from './config.js';
|
|
13
|
-
import { buildDepositTransactionFromRoute } from '../core/deposit.js';
|
|
14
|
-
import { IntentAction, buildTransferIntent } from '../intents.js';
|
|
15
|
-
import { ERC20_ABI } from './evm-executor.js';
|
|
16
|
-
// ─── Constants ────────────────────────────────────────────────────────────────
|
|
17
|
-
// Default network (can be overridden via environment variable)
|
|
18
|
-
const DEFAULT_NETWORK = process.env.ALLSET_NETWORK || 'testnet';
|
|
19
|
-
class LocalFastError extends Error {
|
|
20
|
-
code;
|
|
21
|
-
note;
|
|
22
|
-
constructor(code, message, opts) {
|
|
23
|
-
super(message);
|
|
24
|
-
this.name = 'FastError';
|
|
25
|
-
this.code = code;
|
|
26
|
-
this.note = opts?.note ?? '';
|
|
27
|
-
}
|
|
28
|
-
toJSON() {
|
|
29
|
-
return {
|
|
30
|
-
error: true,
|
|
31
|
-
code: this.code,
|
|
32
|
-
message: this.message,
|
|
33
|
-
note: this.note,
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
let sdkFastErrorPromise = null;
|
|
38
|
-
// Keep @fastxyz/sdk runtime-optional for deposit-only consumers.
|
|
39
|
-
async function loadFastErrorConstructor() {
|
|
40
|
-
sdkFastErrorPromise ??= import('@fastxyz/sdk')
|
|
41
|
-
.then((mod) => (typeof mod.FastError === 'function' ? mod.FastError : null))
|
|
42
|
-
.catch(() => null);
|
|
43
|
-
return sdkFastErrorPromise;
|
|
44
|
-
}
|
|
45
|
-
async function createFastError(code, message, opts) {
|
|
46
|
-
const FastError = await loadFastErrorConstructor();
|
|
47
|
-
return FastError ? new FastError(code, message, opts) : new LocalFastError(code, message, opts);
|
|
48
|
-
}
|
|
49
|
-
function isFastError(err) {
|
|
50
|
-
return (err instanceof Error &&
|
|
51
|
-
err.name === 'FastError' &&
|
|
52
|
-
typeof err.code === 'string' &&
|
|
53
|
-
typeof err.note === 'string');
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Convert decimal amount string to hex for BCS serialization.
|
|
57
|
-
* The Fast network BCS expects amounts as hex strings.
|
|
58
|
-
*/
|
|
59
|
-
function amountToHex(amount) {
|
|
60
|
-
return BigInt(amount).toString(16);
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Convert ChainConfig from config.ts to AllSetChainConfig used internally.
|
|
64
|
-
*/
|
|
65
|
-
function toAllSetChainConfig(config) {
|
|
66
|
-
return {
|
|
67
|
-
chainId: config.chainId,
|
|
68
|
-
bridgeContract: config.bridgeContract,
|
|
69
|
-
fastsetBridgeAddress: config.fastBridgeAddress,
|
|
70
|
-
relayerUrl: config.relayerUrl,
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Convert TokenConfig from config.ts to AllSetTokenInfo used internally.
|
|
75
|
-
*/
|
|
76
|
-
function toAllSetTokenInfo(config) {
|
|
77
|
-
return {
|
|
78
|
-
evmAddress: config.evmAddress,
|
|
79
|
-
fastsetTokenId: hexToUint8Array(config.fastTokenId),
|
|
80
|
-
decimals: config.decimals,
|
|
81
|
-
isNative: false,
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
function resolveChainConfig(chain, network = DEFAULT_NETWORK, provider) {
|
|
85
|
-
return provider?.getChainConfig(chain) ?? getChainConfig(chain, network);
|
|
86
|
-
}
|
|
87
|
-
function resolveTokenConfig(chain, token, network = DEFAULT_NETWORK, provider) {
|
|
88
|
-
return provider?.getTokenConfig(chain, token) ?? getTokenConfig(chain, token, network);
|
|
89
|
-
}
|
|
90
|
-
function getSupportedChains(network = DEFAULT_NETWORK, provider) {
|
|
91
|
-
return Object.keys(provider?.getNetworkConfig?.().chains ?? getNetworkConfig(network).chains);
|
|
92
|
-
}
|
|
93
|
-
function resolveAllSetToken(token, evmChain, network = DEFAULT_NETWORK, provider) {
|
|
94
|
-
// Normalize token name - testUSDC on Fast testnet maps to USDC on EVM
|
|
95
|
-
const lowerToken = token.toLowerCase();
|
|
96
|
-
const normalizedToken = (lowerToken === 'fastusdc' || lowerToken === 'testusdc') ? 'USDC' : token;
|
|
97
|
-
// Try exact match first
|
|
98
|
-
const tokenConfig = resolveTokenConfig(evmChain, normalizedToken, network, provider);
|
|
99
|
-
if (tokenConfig) {
|
|
100
|
-
return toAllSetTokenInfo(tokenConfig);
|
|
101
|
-
}
|
|
102
|
-
// Try uppercase
|
|
103
|
-
const upperConfig = resolveTokenConfig(evmChain, normalizedToken.toUpperCase(), network, provider);
|
|
104
|
-
if (upperConfig) {
|
|
105
|
-
return toAllSetTokenInfo(upperConfig);
|
|
106
|
-
}
|
|
107
|
-
// Try matching by EVM address
|
|
108
|
-
const chainConfig = resolveChainConfig(evmChain, network, provider);
|
|
109
|
-
if (chainConfig) {
|
|
110
|
-
for (const [, info] of Object.entries(chainConfig.tokens)) {
|
|
111
|
-
if (info.evmAddress.toLowerCase() === token.toLowerCase()) {
|
|
112
|
-
return toAllSetTokenInfo(info);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
return null;
|
|
117
|
-
}
|
|
118
|
-
function hexToUint8Array(hex) {
|
|
119
|
-
const clean = hex.startsWith('0x') ? hex.slice(2) : hex;
|
|
120
|
-
const bytes = new Uint8Array(clean.length / 2);
|
|
121
|
-
for (let i = 0; i < bytes.length; i += 1) {
|
|
122
|
-
bytes[i] = parseInt(clean.slice(i * 2, i * 2 + 2), 16);
|
|
123
|
-
}
|
|
124
|
-
return bytes;
|
|
125
|
-
}
|
|
126
|
-
// ─── EVM Transaction Helpers ──────────────────────────────────────────────────
|
|
127
|
-
async function sendTx(clients, tx) {
|
|
128
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
129
|
-
const walletClient = clients.walletClient;
|
|
130
|
-
const hash = await walletClient.sendTransaction({
|
|
131
|
-
to: tx.to,
|
|
132
|
-
data: tx.data,
|
|
133
|
-
value: BigInt(tx.value),
|
|
134
|
-
gas: tx.gas ? BigInt(tx.gas) : undefined,
|
|
135
|
-
});
|
|
136
|
-
const receipt = await clients.publicClient.waitForTransactionReceipt({ hash });
|
|
137
|
-
return {
|
|
138
|
-
txHash: hash,
|
|
139
|
-
status: receipt.status === 'success' ? 'success' : 'reverted',
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
async function checkAllowance(clients, token, spender, owner) {
|
|
143
|
-
const allowance = await clients.publicClient.readContract({
|
|
144
|
-
address: token,
|
|
145
|
-
abi: ERC20_ABI,
|
|
146
|
-
functionName: 'allowance',
|
|
147
|
-
args: [owner, spender],
|
|
148
|
-
});
|
|
149
|
-
return allowance;
|
|
150
|
-
}
|
|
151
|
-
async function approveErc20(clients, token, spender, amount) {
|
|
152
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
153
|
-
const walletClient = clients.walletClient;
|
|
154
|
-
const hash = await walletClient.writeContract({
|
|
155
|
-
address: token,
|
|
156
|
-
abi: ERC20_ABI,
|
|
157
|
-
functionName: 'approve',
|
|
158
|
-
args: [spender, BigInt(amount)],
|
|
159
|
-
});
|
|
160
|
-
await clients.publicClient.waitForTransactionReceipt({ hash });
|
|
161
|
-
return hash;
|
|
162
|
-
}
|
|
163
|
-
function resolveExternalAddress(intents, externalAddressOverride) {
|
|
164
|
-
if (externalAddressOverride) {
|
|
165
|
-
return externalAddressOverride;
|
|
166
|
-
}
|
|
167
|
-
for (const intent of intents) {
|
|
168
|
-
if (intent.action === IntentAction.DynamicTransfer) {
|
|
169
|
-
try {
|
|
170
|
-
const [, receiver] = decodeAbiParameters([{ type: 'address' }, { type: 'address' }], intent.payload);
|
|
171
|
-
return receiver;
|
|
172
|
-
}
|
|
173
|
-
catch {
|
|
174
|
-
continue;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
if (intent.action === IntentAction.Execute) {
|
|
178
|
-
try {
|
|
179
|
-
const [target] = decodeAbiParameters([{ type: 'address' }, { type: 'bytes' }], intent.payload);
|
|
180
|
-
return target;
|
|
181
|
-
}
|
|
182
|
-
catch {
|
|
183
|
-
continue;
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
return null;
|
|
188
|
-
}
|
|
189
|
-
/**
|
|
190
|
-
* Request EVM cross-signing for a Fast network certificate.
|
|
191
|
-
*
|
|
192
|
-
* This is an AllSet-specific operation that requests the AllSet committee
|
|
193
|
-
* to sign a certificate for verification on EVM chains.
|
|
194
|
-
*
|
|
195
|
-
* @param certificate - The certificate from a FastWallet.send() or FastWallet.submit() call
|
|
196
|
-
* @param crossSignUrl - Optional custom cross-sign service URL
|
|
197
|
-
* @returns The signed transaction bytes and signature for relayer submission
|
|
198
|
-
*
|
|
199
|
-
* @example
|
|
200
|
-
* ```ts
|
|
201
|
-
* const result = await fastWallet.send({ to: bridgeAddress, amount: '1000000', token: 'USDC' });
|
|
202
|
-
* const signed = await evmSign(result.certificate);
|
|
203
|
-
* // Use signed.transaction and signed.signature with the relayer
|
|
204
|
-
* ```
|
|
205
|
-
*/
|
|
206
|
-
/**
|
|
207
|
-
* Convert BigInt values to numbers recursively for JSON serialization.
|
|
208
|
-
* The cross-sign service expects numbers, not BigInt strings.
|
|
209
|
-
*/
|
|
210
|
-
function bigIntToNumber(obj) {
|
|
211
|
-
if (typeof obj === 'bigint') {
|
|
212
|
-
return Number(obj);
|
|
213
|
-
}
|
|
214
|
-
if (Array.isArray(obj)) {
|
|
215
|
-
return obj.map(bigIntToNumber);
|
|
216
|
-
}
|
|
217
|
-
if (obj !== null && typeof obj === 'object') {
|
|
218
|
-
const result = {};
|
|
219
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
220
|
-
result[key] = bigIntToNumber(value);
|
|
221
|
-
}
|
|
222
|
-
return result;
|
|
223
|
-
}
|
|
224
|
-
return obj;
|
|
225
|
-
}
|
|
226
|
-
export async function evmSign(certificate, crossSignUrl) {
|
|
227
|
-
const url = crossSignUrl ?? getNetworkConfig(DEFAULT_NETWORK).crossSignUrl;
|
|
228
|
-
// Convert BigInt values to numbers for cross-sign compatibility
|
|
229
|
-
const serializedCertificate = bigIntToNumber(certificate);
|
|
230
|
-
const res = await fetch(url, {
|
|
231
|
-
method: 'POST',
|
|
232
|
-
headers: { 'Content-Type': 'application/json' },
|
|
233
|
-
body: JSON.stringify({
|
|
234
|
-
jsonrpc: '2.0',
|
|
235
|
-
id: 1,
|
|
236
|
-
method: 'crossSign_evmSignCertificate',
|
|
237
|
-
params: { certificate: serializedCertificate },
|
|
238
|
-
}),
|
|
239
|
-
});
|
|
240
|
-
if (!res.ok) {
|
|
241
|
-
throw await createFastError('TX_FAILED', `Cross-sign request failed: ${res.status}`, { note: 'The AllSet cross-sign service rejected the request.' });
|
|
242
|
-
}
|
|
243
|
-
const json = await res.json();
|
|
244
|
-
if (json.error) {
|
|
245
|
-
throw await createFastError('TX_FAILED', `Cross-sign error: ${json.error.message}`, { note: 'The certificate could not be cross-signed.' });
|
|
246
|
-
}
|
|
247
|
-
if (!json.result?.transaction || !json.result?.signature) {
|
|
248
|
-
throw await createFastError('TX_FAILED', 'Cross-sign returned invalid response', { note: 'Missing transaction or signature in response.' });
|
|
249
|
-
}
|
|
250
|
-
return json.result;
|
|
251
|
-
}
|
|
252
|
-
// ─── Bridge Execution ─────────────────────────────────────────────────────────
|
|
253
|
-
/**
|
|
254
|
-
* Execute a bridge operation with optional provider configuration.
|
|
255
|
-
* Called by AllSetProvider.bridge() or directly for low-level usage.
|
|
256
|
-
*/
|
|
257
|
-
export async function executeBridge(params, provider) {
|
|
258
|
-
const network = provider?.network ?? DEFAULT_NETWORK;
|
|
259
|
-
try {
|
|
260
|
-
const isDeposit = params.fromChain !== 'fast' && params.toChain === 'fast';
|
|
261
|
-
const isWithdraw = params.fromChain === 'fast';
|
|
262
|
-
if (!isDeposit && !isWithdraw) {
|
|
263
|
-
throw await createFastError('UNSUPPORTED_OPERATION', `AllSet only supports bridging between Fast network and configured EVM chains (${getSupportedChains(network, provider).join(', ') || 'none'}). Got: ${params.fromChain} → ${params.toChain}`, {
|
|
264
|
-
note: 'Use fromChain: "fast" for withdrawals, or toChain: "fast" for deposits.\n Example: await allset.bridge({ fromChain: "base", toChain: "fast", fromToken: "USDC", toToken: "USDC", amount: "1000000", senderAddress: "0x...", receiverAddress: "fast1..." })',
|
|
265
|
-
});
|
|
266
|
-
}
|
|
267
|
-
if (isDeposit) {
|
|
268
|
-
return await handleDeposit(params, network, provider);
|
|
269
|
-
}
|
|
270
|
-
return await handleWithdraw(params, network, provider);
|
|
271
|
-
}
|
|
272
|
-
catch (err) {
|
|
273
|
-
if (isFastError(err))
|
|
274
|
-
throw err;
|
|
275
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
276
|
-
throw await createFastError('TX_FAILED', `AllSet bridge failed: ${msg}`, {
|
|
277
|
-
note: 'Check that both chains are configured and have sufficient balance.',
|
|
278
|
-
});
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
// ─── Deposit (EVM → Fast) ─────────────────────────────────────────────────────
|
|
282
|
-
async function handleDeposit(params, network = DEFAULT_NETWORK, provider) {
|
|
283
|
-
if (!params.evmClients) {
|
|
284
|
-
throw await createFastError('INVALID_PARAMS', 'AllSet deposit (EVM → Fast) requires evmClients', {
|
|
285
|
-
note: 'Provide evmClients created with createEvmExecutor().\n Example: const account = createEvmWallet(path); const clients = createEvmExecutor(account, rpcUrl, chainId)',
|
|
286
|
-
});
|
|
287
|
-
}
|
|
288
|
-
const chainConfigRaw = resolveChainConfig(params.fromChain, network, provider);
|
|
289
|
-
if (!chainConfigRaw) {
|
|
290
|
-
throw await createFastError('UNSUPPORTED_OPERATION', `AllSet does not support EVM chain "${params.fromChain}". Supported: ${getSupportedChains(network, provider).join(', ')}`, {
|
|
291
|
-
note: 'Use one of the configured EVM chains as the source chain for AllSet deposits.',
|
|
292
|
-
});
|
|
293
|
-
}
|
|
294
|
-
const chainConfig = toAllSetChainConfig(chainConfigRaw);
|
|
295
|
-
let tokenInfo = resolveAllSetToken(params.fromToken, params.fromChain, network, provider);
|
|
296
|
-
if (!tokenInfo) {
|
|
297
|
-
tokenInfo = resolveAllSetToken(params.toToken, params.fromChain, network, provider);
|
|
298
|
-
}
|
|
299
|
-
if (!tokenInfo) {
|
|
300
|
-
throw await createFastError('TOKEN_NOT_FOUND', `Cannot resolve token "${params.fromToken}" on AllSet for chain "${params.fromChain}".`, {
|
|
301
|
-
note: 'Supported tokens: USDC (mainnet), testUSDC (testnet).\n Example: await allset.bridge({ fromChain: "base", toChain: "fast", fromToken: "USDC", toToken: "USDC", amount: "1000000", senderAddress: "0x...", receiverAddress: "fast1..." })',
|
|
302
|
-
});
|
|
303
|
-
}
|
|
304
|
-
let depositPlan;
|
|
305
|
-
try {
|
|
306
|
-
depositPlan = buildDepositTransactionFromRoute({
|
|
307
|
-
network,
|
|
308
|
-
chain: params.fromChain,
|
|
309
|
-
token: params.fromToken,
|
|
310
|
-
chainId: chainConfig.chainId,
|
|
311
|
-
bridgeAddress: chainConfig.bridgeContract,
|
|
312
|
-
tokenAddress: tokenInfo.evmAddress,
|
|
313
|
-
decimals: tokenInfo.decimals,
|
|
314
|
-
isNative: tokenInfo.isNative,
|
|
315
|
-
}, BigInt(params.amount), params.receiverAddress);
|
|
316
|
-
}
|
|
317
|
-
catch (err) {
|
|
318
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
319
|
-
throw await createFastError('INVALID_ADDRESS', `Failed to decode Fast network receiver address "${params.receiverAddress}": ${msg}`, {
|
|
320
|
-
note: 'The receiver address must be a valid Fast network bech32m address (fast1...).\n Example: fast1abc...',
|
|
321
|
-
});
|
|
322
|
-
}
|
|
323
|
-
let txHash;
|
|
324
|
-
if (depositPlan.route.isNative) {
|
|
325
|
-
const receipt = await sendTx(params.evmClients, {
|
|
326
|
-
to: depositPlan.to,
|
|
327
|
-
data: depositPlan.data,
|
|
328
|
-
value: depositPlan.value.toString(),
|
|
329
|
-
});
|
|
330
|
-
if (receipt.status === 'reverted') {
|
|
331
|
-
throw await createFastError('TX_FAILED', `AllSet deposit transaction reverted: ${receipt.txHash}`, {
|
|
332
|
-
note: 'The deposit transaction was reverted. Check that you have sufficient ETH balance.',
|
|
333
|
-
});
|
|
334
|
-
}
|
|
335
|
-
txHash = receipt.txHash;
|
|
336
|
-
}
|
|
337
|
-
else {
|
|
338
|
-
const requiredAmount = BigInt(params.amount);
|
|
339
|
-
const currentAllowance = await checkAllowance(params.evmClients, depositPlan.route.tokenAddress, depositPlan.to, params.senderAddress);
|
|
340
|
-
if (currentAllowance < requiredAmount) {
|
|
341
|
-
await approveErc20(params.evmClients, depositPlan.route.tokenAddress, depositPlan.to, params.amount);
|
|
342
|
-
}
|
|
343
|
-
const receipt = await sendTx(params.evmClients, {
|
|
344
|
-
to: depositPlan.to,
|
|
345
|
-
data: depositPlan.data,
|
|
346
|
-
value: depositPlan.value.toString(),
|
|
347
|
-
});
|
|
348
|
-
if (receipt.status === 'reverted') {
|
|
349
|
-
throw await createFastError('TX_FAILED', `AllSet deposit transaction reverted: ${receipt.txHash}`, {
|
|
350
|
-
note: 'The deposit transaction was reverted. Check that you have sufficient token balance and the approval succeeded.',
|
|
351
|
-
});
|
|
352
|
-
}
|
|
353
|
-
txHash = receipt.txHash;
|
|
354
|
-
}
|
|
355
|
-
return {
|
|
356
|
-
txHash,
|
|
357
|
-
orderId: txHash,
|
|
358
|
-
estimatedTime: '1-5 minutes',
|
|
359
|
-
};
|
|
360
|
-
}
|
|
361
|
-
// ─── Execute Intent (Core) ────────────────────────────────────────────────────
|
|
362
|
-
/**
|
|
363
|
-
* Execute intents on an EVM chain after transferring tokens from Fast network.
|
|
364
|
-
* This is the core function used by sendToExternal and can be used directly for
|
|
365
|
-
* advanced use cases like swaps, multi-step operations, etc.
|
|
366
|
-
*/
|
|
367
|
-
export async function executeIntent(params, provider) {
|
|
368
|
-
const network = provider?.network ?? DEFAULT_NETWORK;
|
|
369
|
-
const crossSignUrl = provider?.crossSignUrl;
|
|
370
|
-
const { fastWallet, chain, token, amount, intents, externalAddress: externalAddressOverride, deadlineSeconds = 3600, } = params;
|
|
371
|
-
if (!fastWallet) {
|
|
372
|
-
throw await createFastError('INVALID_PARAMS', 'executeIntent requires fastWallet', {
|
|
373
|
-
note: 'Provide a compatible Fast wallet.\n Example: const wallet = await FastWallet.fromKeyfile("~/.fast/keys/default.json", provider)',
|
|
374
|
-
});
|
|
375
|
-
}
|
|
376
|
-
if (!intents || intents.length === 0) {
|
|
377
|
-
throw await createFastError('INVALID_PARAMS', 'executeIntent requires at least one intent', {
|
|
378
|
-
note: 'Use intent builders like buildTransferIntent(), buildExecuteIntent(), etc.',
|
|
379
|
-
});
|
|
380
|
-
}
|
|
381
|
-
if (externalAddressOverride && !externalAddressOverride.startsWith('0x')) {
|
|
382
|
-
throw await createFastError('INVALID_PARAMS', 'executeIntent externalAddress must be an EVM address', {
|
|
383
|
-
note: 'Pass a 0x-prefixed address for the relayer target.',
|
|
384
|
-
});
|
|
385
|
-
}
|
|
386
|
-
const chainConfigRaw = resolveChainConfig(chain, network, provider);
|
|
387
|
-
if (!chainConfigRaw) {
|
|
388
|
-
throw await createFastError('UNSUPPORTED_OPERATION', `AllSet does not support EVM chain "${chain}". Supported: ${getSupportedChains(network, provider).join(', ')}`, {
|
|
389
|
-
note: 'Use one of the configured EVM chains.',
|
|
390
|
-
});
|
|
391
|
-
}
|
|
392
|
-
const chainConfig = toAllSetChainConfig(chainConfigRaw);
|
|
393
|
-
const tokenInfo = resolveAllSetToken(token, chain, network, provider);
|
|
394
|
-
if (!tokenInfo) {
|
|
395
|
-
throw await createFastError('TOKEN_NOT_FOUND', `Cannot resolve token "${token}" on AllSet for chain "${chain}".`, {
|
|
396
|
-
note: 'Supported tokens: USDC (mainnet), testUSDC (testnet).',
|
|
397
|
-
});
|
|
398
|
-
}
|
|
399
|
-
// Step 1: Transfer tokens to bridge address on Fast network
|
|
400
|
-
const transferResult = await fastWallet.submit({
|
|
401
|
-
claim: {
|
|
402
|
-
TokenTransfer: {
|
|
403
|
-
token_id: tokenInfo.fastsetTokenId,
|
|
404
|
-
recipient: fastAddressToBytes(chainConfig.fastsetBridgeAddress),
|
|
405
|
-
amount: amountToHex(amount),
|
|
406
|
-
user_data: null,
|
|
407
|
-
},
|
|
408
|
-
},
|
|
409
|
-
});
|
|
410
|
-
// Step 2: Cross-sign the transfer certificate
|
|
411
|
-
const transferCrossSign = await evmSign(transferResult.certificate, crossSignUrl);
|
|
412
|
-
// Use SDK's txHash directly - proven to match cross-sign bytes[32:64] exactly
|
|
413
|
-
// See: https://github.com/fastxyz/allset-sdk/pull/26 (20/20 test transactions matched)
|
|
414
|
-
const transferFastTxId = transferResult.txHash;
|
|
415
|
-
// Step 3: Build intent claim with provided intents
|
|
416
|
-
const deadline = BigInt(Math.floor(Date.now() / 1000) + deadlineSeconds);
|
|
417
|
-
const intentClaimEncoded = encodeAbiParameters([{
|
|
418
|
-
type: 'tuple',
|
|
419
|
-
components: [
|
|
420
|
-
{ name: 'transferFastTxId', type: 'bytes32' },
|
|
421
|
-
{ name: 'deadline', type: 'uint256' },
|
|
422
|
-
{
|
|
423
|
-
name: 'intents',
|
|
424
|
-
type: 'tuple[]',
|
|
425
|
-
components: [
|
|
426
|
-
{ name: 'action', type: 'uint8' },
|
|
427
|
-
{ name: 'payload', type: 'bytes' },
|
|
428
|
-
{ name: 'value', type: 'uint256' },
|
|
429
|
-
],
|
|
430
|
-
},
|
|
431
|
-
],
|
|
432
|
-
}], [{
|
|
433
|
-
transferFastTxId,
|
|
434
|
-
deadline,
|
|
435
|
-
intents: intents.map(i => ({
|
|
436
|
-
action: i.action,
|
|
437
|
-
payload: i.payload,
|
|
438
|
-
value: i.value,
|
|
439
|
-
})),
|
|
440
|
-
}]);
|
|
441
|
-
const intentBytes = hexToUint8Array(intentClaimEncoded);
|
|
442
|
-
// Step 4: Submit intent claim on Fast
|
|
443
|
-
const intentResult = await fastWallet.submit({
|
|
444
|
-
claim: {
|
|
445
|
-
ExternalClaim: {
|
|
446
|
-
claim: {
|
|
447
|
-
verifier_committee: [],
|
|
448
|
-
verifier_quorum: 0,
|
|
449
|
-
claim_data: Array.from(intentBytes),
|
|
450
|
-
},
|
|
451
|
-
signatures: [],
|
|
452
|
-
},
|
|
453
|
-
},
|
|
454
|
-
});
|
|
455
|
-
// Step 5: Cross-sign the intent certificate
|
|
456
|
-
const intentCrossSign = await evmSign(intentResult.certificate, crossSignUrl);
|
|
457
|
-
// Step 6: Submit to relayer
|
|
458
|
-
const externalAddress = resolveExternalAddress(intents, externalAddressOverride);
|
|
459
|
-
if (!externalAddress) {
|
|
460
|
-
throw await createFastError('INVALID_PARAMS', 'executeIntent requires externalAddress when intents do not include a transfer recipient or execute target', {
|
|
461
|
-
note: 'Pass externalAddress for flows like buildDepositBackIntent() or buildRevokeIntent().',
|
|
462
|
-
});
|
|
463
|
-
}
|
|
464
|
-
const relayerBody = {
|
|
465
|
-
encoded_transfer_claim: Array.from(new Uint8Array(transferCrossSign.transaction.map(Number))),
|
|
466
|
-
transfer_proof: transferCrossSign.signature,
|
|
467
|
-
transfer_fast_tx_id: transferResult.txHash,
|
|
468
|
-
transfer_claim_id: transferResult.txHash,
|
|
469
|
-
fastset_address: fastWallet.address,
|
|
470
|
-
external_address: externalAddress,
|
|
471
|
-
encoded_intent_claim: Array.from(new Uint8Array(intentCrossSign.transaction.map(Number))),
|
|
472
|
-
intent_proof: intentCrossSign.signature,
|
|
473
|
-
intent_fast_tx_id: intentResult.txHash,
|
|
474
|
-
intent_claim_id: intentResult.txHash,
|
|
475
|
-
external_token_address: tokenInfo.evmAddress,
|
|
476
|
-
};
|
|
477
|
-
const relayRes = await fetch(`${chainConfig.relayerUrl}/relay`, {
|
|
478
|
-
method: 'POST',
|
|
479
|
-
headers: { 'Content-Type': 'application/json' },
|
|
480
|
-
body: JSON.stringify(relayerBody),
|
|
481
|
-
});
|
|
482
|
-
if (!relayRes.ok) {
|
|
483
|
-
const text = await relayRes.text();
|
|
484
|
-
throw await createFastError('TX_FAILED', `AllSet relayer request failed (${relayRes.status}): ${text}`, {
|
|
485
|
-
note: 'The intent was submitted to Fast network but the relayer rejected it. Try again.',
|
|
486
|
-
});
|
|
487
|
-
}
|
|
488
|
-
return {
|
|
489
|
-
txHash: transferResult.txHash,
|
|
490
|
-
orderId: transferFastTxId,
|
|
491
|
-
estimatedTime: '1-5 minutes',
|
|
492
|
-
};
|
|
493
|
-
}
|
|
494
|
-
// ─── Withdraw (Fast → EVM) ────────────────────────────────────────────────────
|
|
495
|
-
async function handleWithdraw(params, network = DEFAULT_NETWORK, provider) {
|
|
496
|
-
if (!params.fastWallet) {
|
|
497
|
-
throw await createFastError('INVALID_PARAMS', 'AllSet withdrawal (Fast → EVM) requires fastWallet', {
|
|
498
|
-
note: 'Provide a compatible Fast wallet.\n Example: const wallet = await FastWallet.fromKeyfile("~/.fast/keys/default.json", provider)',
|
|
499
|
-
});
|
|
500
|
-
}
|
|
501
|
-
// Resolve token to get EVM address for the transfer intent
|
|
502
|
-
const tokenInfo = resolveAllSetToken(params.fromToken, params.toChain, network, provider)
|
|
503
|
-
?? resolveAllSetToken(params.toToken, params.toChain, network, provider);
|
|
504
|
-
if (!tokenInfo) {
|
|
505
|
-
throw await createFastError('TOKEN_NOT_FOUND', `Cannot resolve token "${params.fromToken}" on AllSet for destination chain "${params.toChain}".`, {
|
|
506
|
-
note: 'Supported tokens: USDC (mainnet), testUSDC (testnet).',
|
|
507
|
-
});
|
|
508
|
-
}
|
|
509
|
-
// Build a simple transfer intent
|
|
510
|
-
const transferIntent = buildTransferIntent(tokenInfo.evmAddress, params.receiverAddress);
|
|
511
|
-
// Execute the intent
|
|
512
|
-
return executeIntent({
|
|
513
|
-
chain: params.toChain,
|
|
514
|
-
fastWallet: params.fastWallet,
|
|
515
|
-
token: params.fromToken,
|
|
516
|
-
amount: params.amount,
|
|
517
|
-
intents: [transferIntent],
|
|
518
|
-
}, provider);
|
|
519
|
-
}
|