@circle-fin/provider-cctp-v2 1.4.1 → 1.6.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/CHANGELOG.md +17 -0
- package/README.md +7 -7
- package/index.cjs +459 -24
- package/index.d.ts +85 -0
- package/index.mjs +459 -24
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -66,6 +66,8 @@ var Blockchain;
|
|
|
66
66
|
Blockchain["Celo_Alfajores_Testnet"] = "Celo_Alfajores_Testnet";
|
|
67
67
|
Blockchain["Codex"] = "Codex";
|
|
68
68
|
Blockchain["Codex_Testnet"] = "Codex_Testnet";
|
|
69
|
+
Blockchain["Edge"] = "Edge";
|
|
70
|
+
Blockchain["Edge_Testnet"] = "Edge_Testnet";
|
|
69
71
|
Blockchain["Ethereum"] = "Ethereum";
|
|
70
72
|
Blockchain["Ethereum_Sepolia"] = "Ethereum_Sepolia";
|
|
71
73
|
Blockchain["Hedera"] = "Hedera";
|
|
@@ -78,6 +80,8 @@ var Blockchain;
|
|
|
78
80
|
Blockchain["Linea_Sepolia"] = "Linea_Sepolia";
|
|
79
81
|
Blockchain["Monad"] = "Monad";
|
|
80
82
|
Blockchain["Monad_Testnet"] = "Monad_Testnet";
|
|
83
|
+
Blockchain["Morph"] = "Morph";
|
|
84
|
+
Blockchain["Morph_Testnet"] = "Morph_Testnet";
|
|
81
85
|
Blockchain["NEAR"] = "NEAR";
|
|
82
86
|
Blockchain["NEAR_Testnet"] = "NEAR_Testnet";
|
|
83
87
|
Blockchain["Noble"] = "Noble";
|
|
@@ -281,11 +285,13 @@ var BridgeChain;
|
|
|
281
285
|
BridgeChain["Avalanche"] = "Avalanche";
|
|
282
286
|
BridgeChain["Base"] = "Base";
|
|
283
287
|
BridgeChain["Codex"] = "Codex";
|
|
288
|
+
BridgeChain["Edge"] = "Edge";
|
|
284
289
|
BridgeChain["Ethereum"] = "Ethereum";
|
|
285
290
|
BridgeChain["HyperEVM"] = "HyperEVM";
|
|
286
291
|
BridgeChain["Ink"] = "Ink";
|
|
287
292
|
BridgeChain["Linea"] = "Linea";
|
|
288
293
|
BridgeChain["Monad"] = "Monad";
|
|
294
|
+
BridgeChain["Morph"] = "Morph";
|
|
289
295
|
BridgeChain["Optimism"] = "Optimism";
|
|
290
296
|
BridgeChain["Plume"] = "Plume";
|
|
291
297
|
BridgeChain["Polygon"] = "Polygon";
|
|
@@ -301,11 +307,13 @@ var BridgeChain;
|
|
|
301
307
|
BridgeChain["Avalanche_Fuji"] = "Avalanche_Fuji";
|
|
302
308
|
BridgeChain["Base_Sepolia"] = "Base_Sepolia";
|
|
303
309
|
BridgeChain["Codex_Testnet"] = "Codex_Testnet";
|
|
310
|
+
BridgeChain["Edge_Testnet"] = "Edge_Testnet";
|
|
304
311
|
BridgeChain["Ethereum_Sepolia"] = "Ethereum_Sepolia";
|
|
305
312
|
BridgeChain["HyperEVM_Testnet"] = "HyperEVM_Testnet";
|
|
306
313
|
BridgeChain["Ink_Testnet"] = "Ink_Testnet";
|
|
307
314
|
BridgeChain["Linea_Sepolia"] = "Linea_Sepolia";
|
|
308
315
|
BridgeChain["Monad_Testnet"] = "Monad_Testnet";
|
|
316
|
+
BridgeChain["Morph_Testnet"] = "Morph_Testnet";
|
|
309
317
|
BridgeChain["Optimism_Sepolia"] = "Optimism_Sepolia";
|
|
310
318
|
BridgeChain["Plume_Testnet"] = "Plume_Testnet";
|
|
311
319
|
BridgeChain["Polygon_Amoy_Testnet"] = "Polygon_Amoy_Testnet";
|
|
@@ -1051,7 +1059,7 @@ const Codex = defineChain({
|
|
|
1051
1059
|
},
|
|
1052
1060
|
forwarderSupported: {
|
|
1053
1061
|
source: true,
|
|
1054
|
-
destination:
|
|
1062
|
+
destination: true,
|
|
1055
1063
|
},
|
|
1056
1064
|
},
|
|
1057
1065
|
kitContracts: {
|
|
@@ -1094,7 +1102,95 @@ const CodexTestnet = defineChain({
|
|
|
1094
1102
|
},
|
|
1095
1103
|
forwarderSupported: {
|
|
1096
1104
|
source: true,
|
|
1097
|
-
destination:
|
|
1105
|
+
destination: true,
|
|
1106
|
+
},
|
|
1107
|
+
},
|
|
1108
|
+
kitContracts: {
|
|
1109
|
+
bridge: BRIDGE_CONTRACT_EVM_TESTNET,
|
|
1110
|
+
},
|
|
1111
|
+
});
|
|
1112
|
+
|
|
1113
|
+
/**
|
|
1114
|
+
* Edge Mainnet chain definition
|
|
1115
|
+
* @remarks
|
|
1116
|
+
* This represents the official production network for the Edge blockchain.
|
|
1117
|
+
* Edge is an EVM-compatible blockchain.
|
|
1118
|
+
*/
|
|
1119
|
+
const Edge = defineChain({
|
|
1120
|
+
type: 'evm',
|
|
1121
|
+
chain: Blockchain.Edge,
|
|
1122
|
+
name: 'Edge',
|
|
1123
|
+
title: 'Edge Mainnet',
|
|
1124
|
+
nativeCurrency: {
|
|
1125
|
+
name: 'Ether',
|
|
1126
|
+
symbol: 'ETH',
|
|
1127
|
+
decimals: 18,
|
|
1128
|
+
},
|
|
1129
|
+
chainId: 3343,
|
|
1130
|
+
isTestnet: false,
|
|
1131
|
+
explorerUrl: 'https://pro.edgex.exchange/en-US/explorer/tx/{hash}',
|
|
1132
|
+
rpcEndpoints: ['https://edge-mainnet.g.alchemy.com/public'],
|
|
1133
|
+
eurcAddress: null,
|
|
1134
|
+
usdcAddress: '0x98d2919b9A214E6Fa5384AC81E6864bA686Ad74c',
|
|
1135
|
+
usdtAddress: null,
|
|
1136
|
+
cctp: {
|
|
1137
|
+
domain: 28,
|
|
1138
|
+
contracts: {
|
|
1139
|
+
v2: {
|
|
1140
|
+
type: 'split',
|
|
1141
|
+
tokenMessenger: '0x98706A006bc632Df31CAdFCBD43F38887ce2ca5c',
|
|
1142
|
+
messageTransmitter: '0x5b61381Fc9e58E70EfC13a4A97516997019198ee',
|
|
1143
|
+
confirmations: 65,
|
|
1144
|
+
fastConfirmations: 1,
|
|
1145
|
+
},
|
|
1146
|
+
},
|
|
1147
|
+
forwarderSupported: {
|
|
1148
|
+
source: true,
|
|
1149
|
+
destination: true,
|
|
1150
|
+
},
|
|
1151
|
+
},
|
|
1152
|
+
kitContracts: {
|
|
1153
|
+
bridge: '0x6D1AaE1c34Aeb582022916a67f2A655C6f4eDFF2', //Unique bridge address as CCTP address for Edge is also unique
|
|
1154
|
+
},
|
|
1155
|
+
});
|
|
1156
|
+
|
|
1157
|
+
/**
|
|
1158
|
+
* Edge Testnet chain definition
|
|
1159
|
+
* @remarks
|
|
1160
|
+
* This represents the official test network for the Edge blockchain.
|
|
1161
|
+
* Edge is an EVM-compatible blockchain.
|
|
1162
|
+
*/
|
|
1163
|
+
const EdgeTestnet = defineChain({
|
|
1164
|
+
type: 'evm',
|
|
1165
|
+
chain: Blockchain.Edge_Testnet,
|
|
1166
|
+
name: 'Edge Testnet',
|
|
1167
|
+
title: 'Edge Testnet',
|
|
1168
|
+
nativeCurrency: {
|
|
1169
|
+
name: 'Ether',
|
|
1170
|
+
symbol: 'ETH',
|
|
1171
|
+
decimals: 18,
|
|
1172
|
+
},
|
|
1173
|
+
chainId: 33431,
|
|
1174
|
+
isTestnet: true,
|
|
1175
|
+
explorerUrl: 'https://edge-testnet.explorer.alchemy.com/tx/{hash}',
|
|
1176
|
+
rpcEndpoints: ['https://edge-testnet.g.alchemy.com/public'],
|
|
1177
|
+
eurcAddress: null,
|
|
1178
|
+
usdcAddress: '0x2d9F7CAD728051AA35Ecdc472a14cf8cDF5CFD6B',
|
|
1179
|
+
usdtAddress: null,
|
|
1180
|
+
cctp: {
|
|
1181
|
+
domain: 28,
|
|
1182
|
+
contracts: {
|
|
1183
|
+
v2: {
|
|
1184
|
+
type: 'split',
|
|
1185
|
+
tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
|
|
1186
|
+
messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
|
|
1187
|
+
confirmations: 65,
|
|
1188
|
+
fastConfirmations: 1,
|
|
1189
|
+
},
|
|
1190
|
+
},
|
|
1191
|
+
forwarderSupported: {
|
|
1192
|
+
source: true,
|
|
1193
|
+
destination: true,
|
|
1098
1194
|
},
|
|
1099
1195
|
},
|
|
1100
1196
|
kitContracts: {
|
|
@@ -1268,7 +1364,7 @@ const HyperEVM = defineChain({
|
|
|
1268
1364
|
},
|
|
1269
1365
|
chainId: 999,
|
|
1270
1366
|
isTestnet: false,
|
|
1271
|
-
explorerUrl: 'https://
|
|
1367
|
+
explorerUrl: 'https://app.hyperliquid.xyz/explorer/tx/{hash}',
|
|
1272
1368
|
rpcEndpoints: ['https://rpc.hyperliquid.xyz/evm'],
|
|
1273
1369
|
eurcAddress: null,
|
|
1274
1370
|
usdcAddress: '0xb88339CB7199b77E23DB6E890353E22632Ba630f',
|
|
@@ -1313,7 +1409,7 @@ const HyperEVMTestnet = defineChain({
|
|
|
1313
1409
|
},
|
|
1314
1410
|
chainId: 998,
|
|
1315
1411
|
isTestnet: true,
|
|
1316
|
-
explorerUrl: 'https://
|
|
1412
|
+
explorerUrl: 'https://app.hyperliquid-testnet.xyz/explorer/tx/{hash}',
|
|
1317
1413
|
rpcEndpoints: ['https://rpc.hyperliquid-testnet.xyz/evm'],
|
|
1318
1414
|
eurcAddress: null,
|
|
1319
1415
|
usdcAddress: '0x2B3370eE501B4a559b57D449569354196457D8Ab',
|
|
@@ -1613,6 +1709,94 @@ const MonadTestnet = defineChain({
|
|
|
1613
1709
|
},
|
|
1614
1710
|
});
|
|
1615
1711
|
|
|
1712
|
+
/**
|
|
1713
|
+
* Morph Mainnet chain definition
|
|
1714
|
+
* @remarks
|
|
1715
|
+
* This represents the official production network for the Morph blockchain.
|
|
1716
|
+
* Morph is an EVM-compatible Layer-2 blockchain built on the OP Stack.
|
|
1717
|
+
*/
|
|
1718
|
+
const Morph = defineChain({
|
|
1719
|
+
type: 'evm',
|
|
1720
|
+
chain: Blockchain.Morph,
|
|
1721
|
+
name: 'Morph',
|
|
1722
|
+
title: 'Morph Mainnet',
|
|
1723
|
+
nativeCurrency: {
|
|
1724
|
+
name: 'Ether',
|
|
1725
|
+
symbol: 'ETH',
|
|
1726
|
+
decimals: 18,
|
|
1727
|
+
},
|
|
1728
|
+
chainId: 2818,
|
|
1729
|
+
isTestnet: false,
|
|
1730
|
+
explorerUrl: 'https://explorer.morph.network/tx/{hash}',
|
|
1731
|
+
rpcEndpoints: ['https://rpc.morphl2.io'],
|
|
1732
|
+
eurcAddress: null,
|
|
1733
|
+
usdcAddress: '0xCfb1186F4e93D60E60a8bDd997427D1F33bc372B',
|
|
1734
|
+
usdtAddress: null,
|
|
1735
|
+
cctp: {
|
|
1736
|
+
domain: 30,
|
|
1737
|
+
contracts: {
|
|
1738
|
+
v2: {
|
|
1739
|
+
type: 'split',
|
|
1740
|
+
tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
|
|
1741
|
+
messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
|
|
1742
|
+
confirmations: 64,
|
|
1743
|
+
fastConfirmations: 1,
|
|
1744
|
+
},
|
|
1745
|
+
},
|
|
1746
|
+
forwarderSupported: {
|
|
1747
|
+
source: false,
|
|
1748
|
+
destination: false,
|
|
1749
|
+
},
|
|
1750
|
+
},
|
|
1751
|
+
kitContracts: {
|
|
1752
|
+
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
1753
|
+
},
|
|
1754
|
+
});
|
|
1755
|
+
|
|
1756
|
+
/**
|
|
1757
|
+
* Morph Hoodi Testnet chain definition
|
|
1758
|
+
* @remarks
|
|
1759
|
+
* This represents the official test network for the Morph blockchain.
|
|
1760
|
+
* Morph is an EVM-compatible Layer-2 blockchain built on the OP Stack.
|
|
1761
|
+
*/
|
|
1762
|
+
const MorphTestnet = defineChain({
|
|
1763
|
+
type: 'evm',
|
|
1764
|
+
chain: Blockchain.Morph_Testnet,
|
|
1765
|
+
name: 'Morph Hoodi',
|
|
1766
|
+
title: 'Morph Hoodi Testnet',
|
|
1767
|
+
nativeCurrency: {
|
|
1768
|
+
name: 'Ether',
|
|
1769
|
+
symbol: 'ETH',
|
|
1770
|
+
decimals: 18,
|
|
1771
|
+
},
|
|
1772
|
+
chainId: 2910,
|
|
1773
|
+
isTestnet: true,
|
|
1774
|
+
explorerUrl: 'https://explorer-hoodi.morphl2.io/tx/{hash}',
|
|
1775
|
+
rpcEndpoints: ['https://rpc-hoodi.morphl2.io'],
|
|
1776
|
+
eurcAddress: null,
|
|
1777
|
+
usdcAddress: '0x7433b41C6c5e1d58D4Da99483609520255ab661B',
|
|
1778
|
+
usdtAddress: null,
|
|
1779
|
+
cctp: {
|
|
1780
|
+
domain: 30,
|
|
1781
|
+
contracts: {
|
|
1782
|
+
v2: {
|
|
1783
|
+
type: 'split',
|
|
1784
|
+
tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
|
|
1785
|
+
messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
|
|
1786
|
+
confirmations: 64,
|
|
1787
|
+
fastConfirmations: 1,
|
|
1788
|
+
},
|
|
1789
|
+
},
|
|
1790
|
+
forwarderSupported: {
|
|
1791
|
+
source: false,
|
|
1792
|
+
destination: false,
|
|
1793
|
+
},
|
|
1794
|
+
},
|
|
1795
|
+
kitContracts: {
|
|
1796
|
+
bridge: BRIDGE_CONTRACT_EVM_TESTNET,
|
|
1797
|
+
},
|
|
1798
|
+
});
|
|
1799
|
+
|
|
1616
1800
|
/**
|
|
1617
1801
|
* NEAR Protocol Mainnet chain definition
|
|
1618
1802
|
* @remarks
|
|
@@ -1871,7 +2055,7 @@ const Plume = defineChain({
|
|
|
1871
2055
|
},
|
|
1872
2056
|
forwarderSupported: {
|
|
1873
2057
|
source: true,
|
|
1874
|
-
destination:
|
|
2058
|
+
destination: true,
|
|
1875
2059
|
},
|
|
1876
2060
|
},
|
|
1877
2061
|
kitContracts: {
|
|
@@ -1916,7 +2100,7 @@ const PlumeTestnet = defineChain({
|
|
|
1916
2100
|
},
|
|
1917
2101
|
forwarderSupported: {
|
|
1918
2102
|
source: true,
|
|
1919
|
-
destination:
|
|
2103
|
+
destination: true,
|
|
1920
2104
|
},
|
|
1921
2105
|
},
|
|
1922
2106
|
kitContracts: {
|
|
@@ -2694,7 +2878,7 @@ const XDC = defineChain({
|
|
|
2694
2878
|
},
|
|
2695
2879
|
forwarderSupported: {
|
|
2696
2880
|
source: true,
|
|
2697
|
-
destination:
|
|
2881
|
+
destination: true,
|
|
2698
2882
|
},
|
|
2699
2883
|
},
|
|
2700
2884
|
kitContracts: {
|
|
@@ -2738,7 +2922,7 @@ const XDCApothem = defineChain({
|
|
|
2738
2922
|
},
|
|
2739
2923
|
forwarderSupported: {
|
|
2740
2924
|
source: true,
|
|
2741
|
-
destination:
|
|
2925
|
+
destination: true,
|
|
2742
2926
|
},
|
|
2743
2927
|
},
|
|
2744
2928
|
kitContracts: {
|
|
@@ -2813,6 +2997,8 @@ var Chains = /*#__PURE__*/Object.freeze({
|
|
|
2813
2997
|
CeloAlfajoresTestnet: CeloAlfajoresTestnet,
|
|
2814
2998
|
Codex: Codex,
|
|
2815
2999
|
CodexTestnet: CodexTestnet,
|
|
3000
|
+
Edge: Edge,
|
|
3001
|
+
EdgeTestnet: EdgeTestnet,
|
|
2816
3002
|
Ethereum: Ethereum,
|
|
2817
3003
|
EthereumSepolia: EthereumSepolia,
|
|
2818
3004
|
Hedera: Hedera,
|
|
@@ -2825,6 +3011,8 @@ var Chains = /*#__PURE__*/Object.freeze({
|
|
|
2825
3011
|
LineaSepolia: LineaSepolia,
|
|
2826
3012
|
Monad: Monad,
|
|
2827
3013
|
MonadTestnet: MonadTestnet,
|
|
3014
|
+
Morph: Morph,
|
|
3015
|
+
MorphTestnet: MorphTestnet,
|
|
2828
3016
|
NEAR: NEAR,
|
|
2829
3017
|
NEARTestnet: NEARTestnet,
|
|
2830
3018
|
Noble: Noble,
|
|
@@ -5416,12 +5604,14 @@ const USDC = {
|
|
|
5416
5604
|
[Blockchain.Base]: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
|
|
5417
5605
|
[Blockchain.Celo]: '0xcebA9300f2b948710d2653dD7B07f33A8B32118C',
|
|
5418
5606
|
[Blockchain.Codex]: '0xd996633a415985DBd7D6D12f4A4343E31f5037cf',
|
|
5607
|
+
[Blockchain.Edge]: '0x98d2919b9A214E6Fa5384AC81E6864bA686Ad74c',
|
|
5419
5608
|
[Blockchain.Ethereum]: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
|
5420
5609
|
[Blockchain.Hedera]: '0.0.456858',
|
|
5421
5610
|
[Blockchain.HyperEVM]: '0xb88339CB7199b77E23DB6E890353E22632Ba630f',
|
|
5422
5611
|
[Blockchain.Ink]: '0x2D270e6886d130D724215A266106e6832161EAEd',
|
|
5423
5612
|
[Blockchain.Linea]: '0x176211869ca2b568f2a7d4ee941e073a821ee1ff',
|
|
5424
5613
|
[Blockchain.Monad]: '0x754704Bc059F8C67012fEd69BC8A327a5aafb603',
|
|
5614
|
+
[Blockchain.Morph]: '0xCfb1186F4e93D60E60a8bDd997427D1F33bc372B',
|
|
5425
5615
|
[Blockchain.NEAR]: '17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1',
|
|
5426
5616
|
[Blockchain.Noble]: 'uusdc',
|
|
5427
5617
|
[Blockchain.Optimism]: '0x0b2c639c533813f4aa9d7837caf62653d097ff85',
|
|
@@ -5444,12 +5634,14 @@ const USDC = {
|
|
|
5444
5634
|
[Blockchain.Avalanche_Fuji]: '0x5425890298aed601595a70AB815c96711a31Bc65',
|
|
5445
5635
|
[Blockchain.Base_Sepolia]: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',
|
|
5446
5636
|
[Blockchain.Codex_Testnet]: '0x6d7f141b6819C2c9CC2f818e6ad549E7Ca090F8f',
|
|
5637
|
+
[Blockchain.Edge_Testnet]: '0x2d9F7CAD728051AA35Ecdc472a14cf8cDF5CFD6B',
|
|
5447
5638
|
[Blockchain.Ethereum_Sepolia]: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',
|
|
5448
5639
|
[Blockchain.Hedera_Testnet]: '0.0.429274',
|
|
5449
5640
|
[Blockchain.HyperEVM_Testnet]: '0x2B3370eE501B4a559b57D449569354196457D8Ab',
|
|
5450
5641
|
[Blockchain.Ink_Testnet]: '0xFabab97dCE620294D2B0b0e46C68964e326300Ac',
|
|
5451
5642
|
[Blockchain.Linea_Sepolia]: '0xfece4462d57bd51a6a552365a011b95f0e16d9b7',
|
|
5452
5643
|
[Blockchain.Monad_Testnet]: '0x534b2f3A21130d7a60830c2Df862319e593943A3',
|
|
5644
|
+
[Blockchain.Morph_Testnet]: '0x7433b41C6c5e1d58D4Da99483609520255ab661B',
|
|
5453
5645
|
[Blockchain.NEAR_Testnet]: '3e2210e1184b45b64c8a434c0a7e7b23cc04ea7eb7a6c3c32520d03d4afcb8af',
|
|
5454
5646
|
[Blockchain.Noble_Testnet]: 'uusdc',
|
|
5455
5647
|
[Blockchain.Optimism_Sepolia]: '0x5fd84259d66Cd46123540766Be93DFE6D43130D7',
|
|
@@ -9310,7 +9502,184 @@ z
|
|
|
9310
9502
|
})
|
|
9311
9503
|
.passthrough();
|
|
9312
9504
|
|
|
9313
|
-
|
|
9505
|
+
/**
|
|
9506
|
+
* Check whether the source adapter supports EIP-5792 atomic batching and
|
|
9507
|
+
* the consumer has not explicitly opted out via `config.batchTransactions`.
|
|
9508
|
+
*
|
|
9509
|
+
* @param params - Bridge parameters (used for adapter and config access).
|
|
9510
|
+
* @returns `true` when batched execution should be attempted.
|
|
9511
|
+
*
|
|
9512
|
+
* @example
|
|
9513
|
+
* ```typescript
|
|
9514
|
+
* const useBatched = await shouldUseBatchedExecution(params)
|
|
9515
|
+
* if (useBatched) {
|
|
9516
|
+
* // take the batched approve + burn path
|
|
9517
|
+
* }
|
|
9518
|
+
* ```
|
|
9519
|
+
*/
|
|
9520
|
+
async function shouldUseBatchedExecution(params) {
|
|
9521
|
+
if (params.config?.batchTransactions === false) {
|
|
9522
|
+
return false;
|
|
9523
|
+
}
|
|
9524
|
+
const { chain } = params.source;
|
|
9525
|
+
if (chain.type !== 'evm') {
|
|
9526
|
+
return false;
|
|
9527
|
+
}
|
|
9528
|
+
const adapter = params.source
|
|
9529
|
+
.adapter;
|
|
9530
|
+
if (typeof adapter.supportsAtomicBatch !== 'function' ||
|
|
9531
|
+
typeof adapter.batchExecute !== 'function') {
|
|
9532
|
+
return false;
|
|
9533
|
+
}
|
|
9534
|
+
try {
|
|
9535
|
+
return await adapter.supportsAtomicBatch(chain);
|
|
9536
|
+
}
|
|
9537
|
+
catch {
|
|
9538
|
+
return false;
|
|
9539
|
+
}
|
|
9540
|
+
}
|
|
9541
|
+
/**
|
|
9542
|
+
* Execute the approve and burn steps as a single EIP-5792 batched call.
|
|
9543
|
+
*
|
|
9544
|
+
* Prepare both `PreparedChainRequest` objects upfront, extract their raw
|
|
9545
|
+
* call data via `getCallData()`, submit both via `adapter.batchExecute()`,
|
|
9546
|
+
* then map the individual receipts back to standard {@link BridgeStep}
|
|
9547
|
+
* objects so downstream consumers (event callbacks, result tracking) are
|
|
9548
|
+
* unaffected.
|
|
9549
|
+
*
|
|
9550
|
+
* @param params - The CCTP v2 bridge parameters.
|
|
9551
|
+
* @param provider - The CCTP v2 bridging provider.
|
|
9552
|
+
* @returns Approve and burn steps with a shared context containing the burn tx hash.
|
|
9553
|
+
* @throws {@link KitError} when the source chain is not EVM.
|
|
9554
|
+
* @throws {@link KitError} when calldata extraction (`getCallData`) is not supported
|
|
9555
|
+
* by the prepared requests.
|
|
9556
|
+
* @remarks
|
|
9557
|
+
* Errors that occur after the batch has been submitted to the wallet
|
|
9558
|
+
* (e.g. polling timeout, insufficient receipts) are **not thrown** — they
|
|
9559
|
+
* are captured as `state: 'error'` on the returned steps to prevent
|
|
9560
|
+
* accidental double-spend on retry.
|
|
9561
|
+
*
|
|
9562
|
+
* @example
|
|
9563
|
+
* ```typescript
|
|
9564
|
+
* const { approveStep, burnStep, context } = await executeBatchedApproveAndBurn(
|
|
9565
|
+
* params,
|
|
9566
|
+
* provider,
|
|
9567
|
+
* )
|
|
9568
|
+
* result.steps.push(approveStep, burnStep)
|
|
9569
|
+
* ```
|
|
9570
|
+
*/
|
|
9571
|
+
async function executeBatchedApproveAndBurn(params, provider) {
|
|
9572
|
+
// Double-unknown cast: Adapter<TFrom> has no structural overlap with
|
|
9573
|
+
// BatchCapableAdapter (a duck-typed interface for EIP-5792 methods).
|
|
9574
|
+
// A direct cast fails because TS cannot prove the intersection; the
|
|
9575
|
+
// runtime capability check below guards against unsupported adapters.
|
|
9576
|
+
const adapter = params.source.adapter;
|
|
9577
|
+
const sourceChain = params.source.chain;
|
|
9578
|
+
if (sourceChain.type !== 'evm') {
|
|
9579
|
+
throw new KitError({
|
|
9580
|
+
...InputError.INVALID_CHAIN,
|
|
9581
|
+
recoverability: 'FATAL',
|
|
9582
|
+
message: 'Batched execution is only supported on EVM chains.',
|
|
9583
|
+
});
|
|
9584
|
+
}
|
|
9585
|
+
const chain = sourceChain;
|
|
9586
|
+
// customFee.value is in base units (integer string) at this point.
|
|
9587
|
+
const customFee = BigInt(params.config?.customFee?.value ?? '0');
|
|
9588
|
+
const amountBigInt = BigInt(params.amount);
|
|
9589
|
+
const approvalAmount = (amountBigInt + customFee).toString();
|
|
9590
|
+
const [approveRequest, burnRequest] = await Promise.all([
|
|
9591
|
+
provider.approve(params.source, approvalAmount),
|
|
9592
|
+
provider.burn(params),
|
|
9593
|
+
]);
|
|
9594
|
+
if (approveRequest.type !== 'evm' ||
|
|
9595
|
+
burnRequest.type !== 'evm' ||
|
|
9596
|
+
!approveRequest.getCallData ||
|
|
9597
|
+
!burnRequest.getCallData) {
|
|
9598
|
+
throw new KitError({
|
|
9599
|
+
...InputError.UNSUPPORTED_ACTION,
|
|
9600
|
+
recoverability: 'FATAL',
|
|
9601
|
+
message: 'Batched execution requires EVM prepared requests with getCallData() support.',
|
|
9602
|
+
});
|
|
9603
|
+
}
|
|
9604
|
+
const approveCallData = approveRequest.getCallData();
|
|
9605
|
+
const burnCallData = burnRequest.getCallData();
|
|
9606
|
+
// batchExecute may throw before submission (wallet declined) but never
|
|
9607
|
+
// after — post-submission errors are returned as empty receipts.
|
|
9608
|
+
const batchResult = await adapter.batchExecute([approveCallData, burnCallData], chain);
|
|
9609
|
+
const approveReceipt = batchResult.receipts[0];
|
|
9610
|
+
const burnReceipt = batchResult.receipts[1];
|
|
9611
|
+
const approveStep = await buildBatchedStep('approve', approveReceipt, batchResult.batchId, adapter, chain);
|
|
9612
|
+
const burnStep = await buildBatchedStep('burn', burnReceipt, batchResult.batchId, adapter, chain);
|
|
9613
|
+
if (burnStep.state !== 'error' && !burnStep.txHash) {
|
|
9614
|
+
burnStep.state = 'error';
|
|
9615
|
+
burnStep.errorMessage =
|
|
9616
|
+
'Batched burn step completed but no transaction hash was returned.';
|
|
9617
|
+
}
|
|
9618
|
+
const context = { burnTxHash: burnStep.txHash ?? '' };
|
|
9619
|
+
return { approveStep, burnStep, context };
|
|
9620
|
+
}
|
|
9621
|
+
/**
|
|
9622
|
+
* Build a {@link BridgeStep} from a single receipt within a batch.
|
|
9623
|
+
*
|
|
9624
|
+
* Map the raw receipt from `batchExecute` into a standard `BridgeStep`,
|
|
9625
|
+
* waiting for on-chain confirmation via `adapter.waitForTransaction`.
|
|
9626
|
+
* All errors are captured on the step (never thrown) so the caller
|
|
9627
|
+
* can inspect each step independently.
|
|
9628
|
+
*
|
|
9629
|
+
* @param name - Human-readable step name (e.g. `'approve'`, `'burn'`).
|
|
9630
|
+
* @param receipt - Per-call receipt from `batchExecute`, or `undefined`
|
|
9631
|
+
* when the wallet returned fewer receipts than submitted calls.
|
|
9632
|
+
* @param batchId - Wallet-assigned batch identifier.
|
|
9633
|
+
* @param adapter - The batch-capable adapter (used for confirmation).
|
|
9634
|
+
* @param chain - The EVM chain the batch was executed on.
|
|
9635
|
+
* @returns A fully-populated bridge step with state, tx hash and explorer URL.
|
|
9636
|
+
*
|
|
9637
|
+
* @internal
|
|
9638
|
+
*/
|
|
9639
|
+
async function buildBatchedStep(name, receipt, batchId, adapter, chain) {
|
|
9640
|
+
const step = {
|
|
9641
|
+
name,
|
|
9642
|
+
state: 'pending',
|
|
9643
|
+
batched: true,
|
|
9644
|
+
batchId,
|
|
9645
|
+
};
|
|
9646
|
+
if (!receipt) {
|
|
9647
|
+
step.state = 'error';
|
|
9648
|
+
step.errorMessage = `No receipt returned for ${name} in batch ${batchId}.`;
|
|
9649
|
+
return step;
|
|
9650
|
+
}
|
|
9651
|
+
step.txHash = receipt.txHash;
|
|
9652
|
+
if (receipt.txHash) {
|
|
9653
|
+
step.explorerUrl = buildExplorerUrl(chain, receipt.txHash);
|
|
9654
|
+
}
|
|
9655
|
+
if (receipt.status !== 'success') {
|
|
9656
|
+
step.state = 'error';
|
|
9657
|
+
step.errorMessage = `${name} call failed within batch ${batchId}.`;
|
|
9658
|
+
return step;
|
|
9659
|
+
}
|
|
9660
|
+
if (!receipt.txHash) {
|
|
9661
|
+
step.state = 'error';
|
|
9662
|
+
step.errorMessage = `${name} succeeded in batch but returned an empty transaction hash.`;
|
|
9663
|
+
return step;
|
|
9664
|
+
}
|
|
9665
|
+
try {
|
|
9666
|
+
const transaction = await adapter.waitForTransaction(receipt.txHash, { confirmations: 1 }, chain);
|
|
9667
|
+
step.state = transaction.blockNumber === undefined ? 'error' : 'success';
|
|
9668
|
+
step.data = transaction;
|
|
9669
|
+
if (transaction.blockNumber === undefined) {
|
|
9670
|
+
step.errorMessage = 'Transaction was not confirmed on-chain.';
|
|
9671
|
+
}
|
|
9672
|
+
}
|
|
9673
|
+
catch (err) {
|
|
9674
|
+
step.state = 'error';
|
|
9675
|
+
step.error = err;
|
|
9676
|
+
step.errorMessage =
|
|
9677
|
+
err instanceof Error ? err.message : 'Unknown error during confirmation.';
|
|
9678
|
+
}
|
|
9679
|
+
return step;
|
|
9680
|
+
}
|
|
9681
|
+
|
|
9682
|
+
var version = "1.6.0";
|
|
9314
9683
|
var pkg = {
|
|
9315
9684
|
version: version};
|
|
9316
9685
|
|
|
@@ -9339,6 +9708,67 @@ function resolveBridgeInvocation(invocationMeta) {
|
|
|
9339
9708
|
};
|
|
9340
9709
|
return extendInvocationContext(resolveInvocationContext(invocationMeta, defaults), BRIDGE_CALLER);
|
|
9341
9710
|
}
|
|
9711
|
+
/**
|
|
9712
|
+
* Execute the batched approve + burn path via EIP-5792.
|
|
9713
|
+
*
|
|
9714
|
+
* Mutate `result` with step data and error state as needed. Return the
|
|
9715
|
+
* batch context on success, or `undefined` when the batch failed (in
|
|
9716
|
+
* which case `result.state` is set to `'error'`).
|
|
9717
|
+
*
|
|
9718
|
+
* @internal
|
|
9719
|
+
* @param params - Bridge parameters (read-only).
|
|
9720
|
+
* @param provider - The CCTP v2 bridging provider (read-only).
|
|
9721
|
+
* @param result - Bridge result object — **mutated in place** with step
|
|
9722
|
+
* data and, on failure, `state: 'error'` plus an `error` payload.
|
|
9723
|
+
* @param invocation - Invocation context for telemetry (read-only).
|
|
9724
|
+
* @returns The step context on success, or `undefined` when the batch failed.
|
|
9725
|
+
*/
|
|
9726
|
+
async function executeBatchedPath(params, provider, result, invocation) {
|
|
9727
|
+
// IMPORTANT: once executeBatchedApproveAndBurn is called, we NEVER
|
|
9728
|
+
// fall back to sequential. The wallet may have already signed &
|
|
9729
|
+
// submitted the batch; retrying as individual txs would double-spend.
|
|
9730
|
+
try {
|
|
9731
|
+
const { approveStep, burnStep, context: batchContext, } = await executeBatchedApproveAndBurn(params, provider);
|
|
9732
|
+
for (const step of [approveStep, burnStep]) {
|
|
9733
|
+
const stepName = step.name;
|
|
9734
|
+
if (step.state === 'error') {
|
|
9735
|
+
ensureStepErrorMessage(step.name, step);
|
|
9736
|
+
result.steps.push(step);
|
|
9737
|
+
result.state = 'error';
|
|
9738
|
+
dispatchStepEvent(stepName, step, provider, invocation);
|
|
9739
|
+
return undefined;
|
|
9740
|
+
}
|
|
9741
|
+
dispatchStepEvent(stepName, step, provider, invocation);
|
|
9742
|
+
result.steps.push(step);
|
|
9743
|
+
}
|
|
9744
|
+
return batchContext;
|
|
9745
|
+
}
|
|
9746
|
+
catch (error_) {
|
|
9747
|
+
// Only handles pre-submission failures (prepare rejected, wallet
|
|
9748
|
+
// declined, etc.). batchExecute never throws after sendCalls succeeds.
|
|
9749
|
+
result.state = 'error';
|
|
9750
|
+
result.steps.push({
|
|
9751
|
+
name: 'batch',
|
|
9752
|
+
state: 'error',
|
|
9753
|
+
batched: true,
|
|
9754
|
+
error: error_,
|
|
9755
|
+
errorMessage: error_ instanceof Error
|
|
9756
|
+
? error_.message
|
|
9757
|
+
: 'Batched approve + burn failed.',
|
|
9758
|
+
});
|
|
9759
|
+
return undefined;
|
|
9760
|
+
}
|
|
9761
|
+
}
|
|
9762
|
+
/**
|
|
9763
|
+
* Ensure `step.errorMessage` is populated when an error object exists.
|
|
9764
|
+
*
|
|
9765
|
+
* @internal
|
|
9766
|
+
*/
|
|
9767
|
+
function ensureStepErrorMessage(name, step) {
|
|
9768
|
+
if (!step.errorMessage && step.error) {
|
|
9769
|
+
step.errorMessage = `${name} step failed: ${getErrorMessage(step.error)}`;
|
|
9770
|
+
}
|
|
9771
|
+
}
|
|
9342
9772
|
/**
|
|
9343
9773
|
* Execute a cross-chain USDC bridge using the CCTP v2 protocol.
|
|
9344
9774
|
*
|
|
@@ -9372,9 +9802,7 @@ function resolveBridgeInvocation(invocationMeta) {
|
|
|
9372
9802
|
* ```
|
|
9373
9803
|
*/
|
|
9374
9804
|
async function bridge(params, provider) {
|
|
9375
|
-
// Check if forwarder is enabled (on destination)
|
|
9376
9805
|
const useForwarder = params.destination.useForwarder === true;
|
|
9377
|
-
// Resolve invocation metadata to full context for event dispatching
|
|
9378
9806
|
const invocation = resolveBridgeInvocation(params.invocationMeta);
|
|
9379
9807
|
const result = {
|
|
9380
9808
|
state: 'pending',
|
|
@@ -9387,11 +9815,9 @@ async function bridge(params, provider) {
|
|
|
9387
9815
|
destination: {
|
|
9388
9816
|
address: params.destination.address,
|
|
9389
9817
|
chain: params.destination.chain,
|
|
9390
|
-
// Preserve recipientAddress
|
|
9391
9818
|
...(params.destination.recipientAddress && {
|
|
9392
9819
|
recipientAddress: params.destination.recipientAddress,
|
|
9393
9820
|
}),
|
|
9394
|
-
// Preserve useForwarder
|
|
9395
9821
|
...(useForwarder && {
|
|
9396
9822
|
useForwarder: true,
|
|
9397
9823
|
}),
|
|
@@ -9400,29 +9826,38 @@ async function bridge(params, provider) {
|
|
|
9400
9826
|
config: params.config,
|
|
9401
9827
|
provider: provider.name,
|
|
9402
9828
|
};
|
|
9403
|
-
// Context shared between steps
|
|
9404
9829
|
let context = undefined;
|
|
9405
|
-
|
|
9830
|
+
let useBatched = false;
|
|
9831
|
+
try {
|
|
9832
|
+
useBatched = await shouldUseBatchedExecution(params);
|
|
9833
|
+
}
|
|
9834
|
+
catch {
|
|
9835
|
+
// Silently fall back to sequential
|
|
9836
|
+
}
|
|
9406
9837
|
const executors = createStepExecutors(useForwarder);
|
|
9407
|
-
|
|
9408
|
-
|
|
9838
|
+
if (useBatched) {
|
|
9839
|
+
const batchContext = await executeBatchedPath(params, provider, result, invocation);
|
|
9840
|
+
if (result.state === 'error') {
|
|
9841
|
+
return result;
|
|
9842
|
+
}
|
|
9843
|
+
context = batchContext;
|
|
9844
|
+
}
|
|
9845
|
+
const stepsToRun = useBatched
|
|
9846
|
+
? executors.filter(({ name }) => name !== 'approve' && name !== 'burn')
|
|
9847
|
+
: executors;
|
|
9848
|
+
for (const { name, executor, updateContext } of stepsToRun) {
|
|
9409
9849
|
try {
|
|
9410
9850
|
const step = await executor(params, provider, context);
|
|
9411
9851
|
if (step.state === 'error') {
|
|
9412
|
-
|
|
9413
|
-
if (!step.errorMessage && step.error) {
|
|
9414
|
-
step.errorMessage = `${name} step failed: ${getErrorMessage(step.error)}`;
|
|
9415
|
-
}
|
|
9852
|
+
ensureStepErrorMessage(name, step);
|
|
9416
9853
|
result.steps.push(step);
|
|
9417
9854
|
result.state = 'error';
|
|
9418
|
-
// Dispatch event even for error steps
|
|
9419
9855
|
dispatchStepEvent(name, step, provider, invocation);
|
|
9420
9856
|
return result;
|
|
9421
9857
|
}
|
|
9422
|
-
// Merge new context with existing context to preserve data from previous steps
|
|
9423
9858
|
const newContext = updateContext?.(step);
|
|
9424
9859
|
if (newContext) {
|
|
9425
|
-
context = { ...
|
|
9860
|
+
context = { ...context, ...newContext };
|
|
9426
9861
|
}
|
|
9427
9862
|
dispatchStepEvent(name, step, provider, invocation);
|
|
9428
9863
|
result.steps.push(step);
|