@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.cjs
CHANGED
|
@@ -73,6 +73,8 @@ var Blockchain;
|
|
|
73
73
|
Blockchain["Celo_Alfajores_Testnet"] = "Celo_Alfajores_Testnet";
|
|
74
74
|
Blockchain["Codex"] = "Codex";
|
|
75
75
|
Blockchain["Codex_Testnet"] = "Codex_Testnet";
|
|
76
|
+
Blockchain["Edge"] = "Edge";
|
|
77
|
+
Blockchain["Edge_Testnet"] = "Edge_Testnet";
|
|
76
78
|
Blockchain["Ethereum"] = "Ethereum";
|
|
77
79
|
Blockchain["Ethereum_Sepolia"] = "Ethereum_Sepolia";
|
|
78
80
|
Blockchain["Hedera"] = "Hedera";
|
|
@@ -85,6 +87,8 @@ var Blockchain;
|
|
|
85
87
|
Blockchain["Linea_Sepolia"] = "Linea_Sepolia";
|
|
86
88
|
Blockchain["Monad"] = "Monad";
|
|
87
89
|
Blockchain["Monad_Testnet"] = "Monad_Testnet";
|
|
90
|
+
Blockchain["Morph"] = "Morph";
|
|
91
|
+
Blockchain["Morph_Testnet"] = "Morph_Testnet";
|
|
88
92
|
Blockchain["NEAR"] = "NEAR";
|
|
89
93
|
Blockchain["NEAR_Testnet"] = "NEAR_Testnet";
|
|
90
94
|
Blockchain["Noble"] = "Noble";
|
|
@@ -288,11 +292,13 @@ var BridgeChain;
|
|
|
288
292
|
BridgeChain["Avalanche"] = "Avalanche";
|
|
289
293
|
BridgeChain["Base"] = "Base";
|
|
290
294
|
BridgeChain["Codex"] = "Codex";
|
|
295
|
+
BridgeChain["Edge"] = "Edge";
|
|
291
296
|
BridgeChain["Ethereum"] = "Ethereum";
|
|
292
297
|
BridgeChain["HyperEVM"] = "HyperEVM";
|
|
293
298
|
BridgeChain["Ink"] = "Ink";
|
|
294
299
|
BridgeChain["Linea"] = "Linea";
|
|
295
300
|
BridgeChain["Monad"] = "Monad";
|
|
301
|
+
BridgeChain["Morph"] = "Morph";
|
|
296
302
|
BridgeChain["Optimism"] = "Optimism";
|
|
297
303
|
BridgeChain["Plume"] = "Plume";
|
|
298
304
|
BridgeChain["Polygon"] = "Polygon";
|
|
@@ -308,11 +314,13 @@ var BridgeChain;
|
|
|
308
314
|
BridgeChain["Avalanche_Fuji"] = "Avalanche_Fuji";
|
|
309
315
|
BridgeChain["Base_Sepolia"] = "Base_Sepolia";
|
|
310
316
|
BridgeChain["Codex_Testnet"] = "Codex_Testnet";
|
|
317
|
+
BridgeChain["Edge_Testnet"] = "Edge_Testnet";
|
|
311
318
|
BridgeChain["Ethereum_Sepolia"] = "Ethereum_Sepolia";
|
|
312
319
|
BridgeChain["HyperEVM_Testnet"] = "HyperEVM_Testnet";
|
|
313
320
|
BridgeChain["Ink_Testnet"] = "Ink_Testnet";
|
|
314
321
|
BridgeChain["Linea_Sepolia"] = "Linea_Sepolia";
|
|
315
322
|
BridgeChain["Monad_Testnet"] = "Monad_Testnet";
|
|
323
|
+
BridgeChain["Morph_Testnet"] = "Morph_Testnet";
|
|
316
324
|
BridgeChain["Optimism_Sepolia"] = "Optimism_Sepolia";
|
|
317
325
|
BridgeChain["Plume_Testnet"] = "Plume_Testnet";
|
|
318
326
|
BridgeChain["Polygon_Amoy_Testnet"] = "Polygon_Amoy_Testnet";
|
|
@@ -1058,7 +1066,7 @@ const Codex = defineChain({
|
|
|
1058
1066
|
},
|
|
1059
1067
|
forwarderSupported: {
|
|
1060
1068
|
source: true,
|
|
1061
|
-
destination:
|
|
1069
|
+
destination: true,
|
|
1062
1070
|
},
|
|
1063
1071
|
},
|
|
1064
1072
|
kitContracts: {
|
|
@@ -1101,7 +1109,95 @@ const CodexTestnet = defineChain({
|
|
|
1101
1109
|
},
|
|
1102
1110
|
forwarderSupported: {
|
|
1103
1111
|
source: true,
|
|
1104
|
-
destination:
|
|
1112
|
+
destination: true,
|
|
1113
|
+
},
|
|
1114
|
+
},
|
|
1115
|
+
kitContracts: {
|
|
1116
|
+
bridge: BRIDGE_CONTRACT_EVM_TESTNET,
|
|
1117
|
+
},
|
|
1118
|
+
});
|
|
1119
|
+
|
|
1120
|
+
/**
|
|
1121
|
+
* Edge Mainnet chain definition
|
|
1122
|
+
* @remarks
|
|
1123
|
+
* This represents the official production network for the Edge blockchain.
|
|
1124
|
+
* Edge is an EVM-compatible blockchain.
|
|
1125
|
+
*/
|
|
1126
|
+
const Edge = defineChain({
|
|
1127
|
+
type: 'evm',
|
|
1128
|
+
chain: Blockchain.Edge,
|
|
1129
|
+
name: 'Edge',
|
|
1130
|
+
title: 'Edge Mainnet',
|
|
1131
|
+
nativeCurrency: {
|
|
1132
|
+
name: 'Ether',
|
|
1133
|
+
symbol: 'ETH',
|
|
1134
|
+
decimals: 18,
|
|
1135
|
+
},
|
|
1136
|
+
chainId: 3343,
|
|
1137
|
+
isTestnet: false,
|
|
1138
|
+
explorerUrl: 'https://pro.edgex.exchange/en-US/explorer/tx/{hash}',
|
|
1139
|
+
rpcEndpoints: ['https://edge-mainnet.g.alchemy.com/public'],
|
|
1140
|
+
eurcAddress: null,
|
|
1141
|
+
usdcAddress: '0x98d2919b9A214E6Fa5384AC81E6864bA686Ad74c',
|
|
1142
|
+
usdtAddress: null,
|
|
1143
|
+
cctp: {
|
|
1144
|
+
domain: 28,
|
|
1145
|
+
contracts: {
|
|
1146
|
+
v2: {
|
|
1147
|
+
type: 'split',
|
|
1148
|
+
tokenMessenger: '0x98706A006bc632Df31CAdFCBD43F38887ce2ca5c',
|
|
1149
|
+
messageTransmitter: '0x5b61381Fc9e58E70EfC13a4A97516997019198ee',
|
|
1150
|
+
confirmations: 65,
|
|
1151
|
+
fastConfirmations: 1,
|
|
1152
|
+
},
|
|
1153
|
+
},
|
|
1154
|
+
forwarderSupported: {
|
|
1155
|
+
source: true,
|
|
1156
|
+
destination: true,
|
|
1157
|
+
},
|
|
1158
|
+
},
|
|
1159
|
+
kitContracts: {
|
|
1160
|
+
bridge: '0x6D1AaE1c34Aeb582022916a67f2A655C6f4eDFF2', //Unique bridge address as CCTP address for Edge is also unique
|
|
1161
|
+
},
|
|
1162
|
+
});
|
|
1163
|
+
|
|
1164
|
+
/**
|
|
1165
|
+
* Edge Testnet chain definition
|
|
1166
|
+
* @remarks
|
|
1167
|
+
* This represents the official test network for the Edge blockchain.
|
|
1168
|
+
* Edge is an EVM-compatible blockchain.
|
|
1169
|
+
*/
|
|
1170
|
+
const EdgeTestnet = defineChain({
|
|
1171
|
+
type: 'evm',
|
|
1172
|
+
chain: Blockchain.Edge_Testnet,
|
|
1173
|
+
name: 'Edge Testnet',
|
|
1174
|
+
title: 'Edge Testnet',
|
|
1175
|
+
nativeCurrency: {
|
|
1176
|
+
name: 'Ether',
|
|
1177
|
+
symbol: 'ETH',
|
|
1178
|
+
decimals: 18,
|
|
1179
|
+
},
|
|
1180
|
+
chainId: 33431,
|
|
1181
|
+
isTestnet: true,
|
|
1182
|
+
explorerUrl: 'https://edge-testnet.explorer.alchemy.com/tx/{hash}',
|
|
1183
|
+
rpcEndpoints: ['https://edge-testnet.g.alchemy.com/public'],
|
|
1184
|
+
eurcAddress: null,
|
|
1185
|
+
usdcAddress: '0x2d9F7CAD728051AA35Ecdc472a14cf8cDF5CFD6B',
|
|
1186
|
+
usdtAddress: null,
|
|
1187
|
+
cctp: {
|
|
1188
|
+
domain: 28,
|
|
1189
|
+
contracts: {
|
|
1190
|
+
v2: {
|
|
1191
|
+
type: 'split',
|
|
1192
|
+
tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
|
|
1193
|
+
messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
|
|
1194
|
+
confirmations: 65,
|
|
1195
|
+
fastConfirmations: 1,
|
|
1196
|
+
},
|
|
1197
|
+
},
|
|
1198
|
+
forwarderSupported: {
|
|
1199
|
+
source: true,
|
|
1200
|
+
destination: true,
|
|
1105
1201
|
},
|
|
1106
1202
|
},
|
|
1107
1203
|
kitContracts: {
|
|
@@ -1275,7 +1371,7 @@ const HyperEVM = defineChain({
|
|
|
1275
1371
|
},
|
|
1276
1372
|
chainId: 999,
|
|
1277
1373
|
isTestnet: false,
|
|
1278
|
-
explorerUrl: 'https://
|
|
1374
|
+
explorerUrl: 'https://app.hyperliquid.xyz/explorer/tx/{hash}',
|
|
1279
1375
|
rpcEndpoints: ['https://rpc.hyperliquid.xyz/evm'],
|
|
1280
1376
|
eurcAddress: null,
|
|
1281
1377
|
usdcAddress: '0xb88339CB7199b77E23DB6E890353E22632Ba630f',
|
|
@@ -1320,7 +1416,7 @@ const HyperEVMTestnet = defineChain({
|
|
|
1320
1416
|
},
|
|
1321
1417
|
chainId: 998,
|
|
1322
1418
|
isTestnet: true,
|
|
1323
|
-
explorerUrl: 'https://
|
|
1419
|
+
explorerUrl: 'https://app.hyperliquid-testnet.xyz/explorer/tx/{hash}',
|
|
1324
1420
|
rpcEndpoints: ['https://rpc.hyperliquid-testnet.xyz/evm'],
|
|
1325
1421
|
eurcAddress: null,
|
|
1326
1422
|
usdcAddress: '0x2B3370eE501B4a559b57D449569354196457D8Ab',
|
|
@@ -1620,6 +1716,94 @@ const MonadTestnet = defineChain({
|
|
|
1620
1716
|
},
|
|
1621
1717
|
});
|
|
1622
1718
|
|
|
1719
|
+
/**
|
|
1720
|
+
* Morph Mainnet chain definition
|
|
1721
|
+
* @remarks
|
|
1722
|
+
* This represents the official production network for the Morph blockchain.
|
|
1723
|
+
* Morph is an EVM-compatible Layer-2 blockchain built on the OP Stack.
|
|
1724
|
+
*/
|
|
1725
|
+
const Morph = defineChain({
|
|
1726
|
+
type: 'evm',
|
|
1727
|
+
chain: Blockchain.Morph,
|
|
1728
|
+
name: 'Morph',
|
|
1729
|
+
title: 'Morph Mainnet',
|
|
1730
|
+
nativeCurrency: {
|
|
1731
|
+
name: 'Ether',
|
|
1732
|
+
symbol: 'ETH',
|
|
1733
|
+
decimals: 18,
|
|
1734
|
+
},
|
|
1735
|
+
chainId: 2818,
|
|
1736
|
+
isTestnet: false,
|
|
1737
|
+
explorerUrl: 'https://explorer.morph.network/tx/{hash}',
|
|
1738
|
+
rpcEndpoints: ['https://rpc.morphl2.io'],
|
|
1739
|
+
eurcAddress: null,
|
|
1740
|
+
usdcAddress: '0xCfb1186F4e93D60E60a8bDd997427D1F33bc372B',
|
|
1741
|
+
usdtAddress: null,
|
|
1742
|
+
cctp: {
|
|
1743
|
+
domain: 30,
|
|
1744
|
+
contracts: {
|
|
1745
|
+
v2: {
|
|
1746
|
+
type: 'split',
|
|
1747
|
+
tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
|
|
1748
|
+
messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
|
|
1749
|
+
confirmations: 64,
|
|
1750
|
+
fastConfirmations: 1,
|
|
1751
|
+
},
|
|
1752
|
+
},
|
|
1753
|
+
forwarderSupported: {
|
|
1754
|
+
source: false,
|
|
1755
|
+
destination: false,
|
|
1756
|
+
},
|
|
1757
|
+
},
|
|
1758
|
+
kitContracts: {
|
|
1759
|
+
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
1760
|
+
},
|
|
1761
|
+
});
|
|
1762
|
+
|
|
1763
|
+
/**
|
|
1764
|
+
* Morph Hoodi Testnet chain definition
|
|
1765
|
+
* @remarks
|
|
1766
|
+
* This represents the official test network for the Morph blockchain.
|
|
1767
|
+
* Morph is an EVM-compatible Layer-2 blockchain built on the OP Stack.
|
|
1768
|
+
*/
|
|
1769
|
+
const MorphTestnet = defineChain({
|
|
1770
|
+
type: 'evm',
|
|
1771
|
+
chain: Blockchain.Morph_Testnet,
|
|
1772
|
+
name: 'Morph Hoodi',
|
|
1773
|
+
title: 'Morph Hoodi Testnet',
|
|
1774
|
+
nativeCurrency: {
|
|
1775
|
+
name: 'Ether',
|
|
1776
|
+
symbol: 'ETH',
|
|
1777
|
+
decimals: 18,
|
|
1778
|
+
},
|
|
1779
|
+
chainId: 2910,
|
|
1780
|
+
isTestnet: true,
|
|
1781
|
+
explorerUrl: 'https://explorer-hoodi.morphl2.io/tx/{hash}',
|
|
1782
|
+
rpcEndpoints: ['https://rpc-hoodi.morphl2.io'],
|
|
1783
|
+
eurcAddress: null,
|
|
1784
|
+
usdcAddress: '0x7433b41C6c5e1d58D4Da99483609520255ab661B',
|
|
1785
|
+
usdtAddress: null,
|
|
1786
|
+
cctp: {
|
|
1787
|
+
domain: 30,
|
|
1788
|
+
contracts: {
|
|
1789
|
+
v2: {
|
|
1790
|
+
type: 'split',
|
|
1791
|
+
tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
|
|
1792
|
+
messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
|
|
1793
|
+
confirmations: 64,
|
|
1794
|
+
fastConfirmations: 1,
|
|
1795
|
+
},
|
|
1796
|
+
},
|
|
1797
|
+
forwarderSupported: {
|
|
1798
|
+
source: false,
|
|
1799
|
+
destination: false,
|
|
1800
|
+
},
|
|
1801
|
+
},
|
|
1802
|
+
kitContracts: {
|
|
1803
|
+
bridge: BRIDGE_CONTRACT_EVM_TESTNET,
|
|
1804
|
+
},
|
|
1805
|
+
});
|
|
1806
|
+
|
|
1623
1807
|
/**
|
|
1624
1808
|
* NEAR Protocol Mainnet chain definition
|
|
1625
1809
|
* @remarks
|
|
@@ -1878,7 +2062,7 @@ const Plume = defineChain({
|
|
|
1878
2062
|
},
|
|
1879
2063
|
forwarderSupported: {
|
|
1880
2064
|
source: true,
|
|
1881
|
-
destination:
|
|
2065
|
+
destination: true,
|
|
1882
2066
|
},
|
|
1883
2067
|
},
|
|
1884
2068
|
kitContracts: {
|
|
@@ -1923,7 +2107,7 @@ const PlumeTestnet = defineChain({
|
|
|
1923
2107
|
},
|
|
1924
2108
|
forwarderSupported: {
|
|
1925
2109
|
source: true,
|
|
1926
|
-
destination:
|
|
2110
|
+
destination: true,
|
|
1927
2111
|
},
|
|
1928
2112
|
},
|
|
1929
2113
|
kitContracts: {
|
|
@@ -2701,7 +2885,7 @@ const XDC = defineChain({
|
|
|
2701
2885
|
},
|
|
2702
2886
|
forwarderSupported: {
|
|
2703
2887
|
source: true,
|
|
2704
|
-
destination:
|
|
2888
|
+
destination: true,
|
|
2705
2889
|
},
|
|
2706
2890
|
},
|
|
2707
2891
|
kitContracts: {
|
|
@@ -2745,7 +2929,7 @@ const XDCApothem = defineChain({
|
|
|
2745
2929
|
},
|
|
2746
2930
|
forwarderSupported: {
|
|
2747
2931
|
source: true,
|
|
2748
|
-
destination:
|
|
2932
|
+
destination: true,
|
|
2749
2933
|
},
|
|
2750
2934
|
},
|
|
2751
2935
|
kitContracts: {
|
|
@@ -2820,6 +3004,8 @@ var Chains = {
|
|
|
2820
3004
|
CeloAlfajoresTestnet: CeloAlfajoresTestnet,
|
|
2821
3005
|
Codex: Codex,
|
|
2822
3006
|
CodexTestnet: CodexTestnet,
|
|
3007
|
+
Edge: Edge,
|
|
3008
|
+
EdgeTestnet: EdgeTestnet,
|
|
2823
3009
|
Ethereum: Ethereum,
|
|
2824
3010
|
EthereumSepolia: EthereumSepolia,
|
|
2825
3011
|
Hedera: Hedera,
|
|
@@ -2832,6 +3018,8 @@ var Chains = {
|
|
|
2832
3018
|
LineaSepolia: LineaSepolia,
|
|
2833
3019
|
Monad: Monad,
|
|
2834
3020
|
MonadTestnet: MonadTestnet,
|
|
3021
|
+
Morph: Morph,
|
|
3022
|
+
MorphTestnet: MorphTestnet,
|
|
2835
3023
|
NEAR: NEAR,
|
|
2836
3024
|
NEARTestnet: NEARTestnet,
|
|
2837
3025
|
Noble: Noble,
|
|
@@ -5423,12 +5611,14 @@ const USDC = {
|
|
|
5423
5611
|
[Blockchain.Base]: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
|
|
5424
5612
|
[Blockchain.Celo]: '0xcebA9300f2b948710d2653dD7B07f33A8B32118C',
|
|
5425
5613
|
[Blockchain.Codex]: '0xd996633a415985DBd7D6D12f4A4343E31f5037cf',
|
|
5614
|
+
[Blockchain.Edge]: '0x98d2919b9A214E6Fa5384AC81E6864bA686Ad74c',
|
|
5426
5615
|
[Blockchain.Ethereum]: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
|
5427
5616
|
[Blockchain.Hedera]: '0.0.456858',
|
|
5428
5617
|
[Blockchain.HyperEVM]: '0xb88339CB7199b77E23DB6E890353E22632Ba630f',
|
|
5429
5618
|
[Blockchain.Ink]: '0x2D270e6886d130D724215A266106e6832161EAEd',
|
|
5430
5619
|
[Blockchain.Linea]: '0x176211869ca2b568f2a7d4ee941e073a821ee1ff',
|
|
5431
5620
|
[Blockchain.Monad]: '0x754704Bc059F8C67012fEd69BC8A327a5aafb603',
|
|
5621
|
+
[Blockchain.Morph]: '0xCfb1186F4e93D60E60a8bDd997427D1F33bc372B',
|
|
5432
5622
|
[Blockchain.NEAR]: '17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1',
|
|
5433
5623
|
[Blockchain.Noble]: 'uusdc',
|
|
5434
5624
|
[Blockchain.Optimism]: '0x0b2c639c533813f4aa9d7837caf62653d097ff85',
|
|
@@ -5451,12 +5641,14 @@ const USDC = {
|
|
|
5451
5641
|
[Blockchain.Avalanche_Fuji]: '0x5425890298aed601595a70AB815c96711a31Bc65',
|
|
5452
5642
|
[Blockchain.Base_Sepolia]: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',
|
|
5453
5643
|
[Blockchain.Codex_Testnet]: '0x6d7f141b6819C2c9CC2f818e6ad549E7Ca090F8f',
|
|
5644
|
+
[Blockchain.Edge_Testnet]: '0x2d9F7CAD728051AA35Ecdc472a14cf8cDF5CFD6B',
|
|
5454
5645
|
[Blockchain.Ethereum_Sepolia]: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',
|
|
5455
5646
|
[Blockchain.Hedera_Testnet]: '0.0.429274',
|
|
5456
5647
|
[Blockchain.HyperEVM_Testnet]: '0x2B3370eE501B4a559b57D449569354196457D8Ab',
|
|
5457
5648
|
[Blockchain.Ink_Testnet]: '0xFabab97dCE620294D2B0b0e46C68964e326300Ac',
|
|
5458
5649
|
[Blockchain.Linea_Sepolia]: '0xfece4462d57bd51a6a552365a011b95f0e16d9b7',
|
|
5459
5650
|
[Blockchain.Monad_Testnet]: '0x534b2f3A21130d7a60830c2Df862319e593943A3',
|
|
5651
|
+
[Blockchain.Morph_Testnet]: '0x7433b41C6c5e1d58D4Da99483609520255ab661B',
|
|
5460
5652
|
[Blockchain.NEAR_Testnet]: '3e2210e1184b45b64c8a434c0a7e7b23cc04ea7eb7a6c3c32520d03d4afcb8af',
|
|
5461
5653
|
[Blockchain.Noble_Testnet]: 'uusdc',
|
|
5462
5654
|
[Blockchain.Optimism_Sepolia]: '0x5fd84259d66Cd46123540766Be93DFE6D43130D7',
|
|
@@ -9317,7 +9509,184 @@ zod.z
|
|
|
9317
9509
|
})
|
|
9318
9510
|
.passthrough();
|
|
9319
9511
|
|
|
9320
|
-
|
|
9512
|
+
/**
|
|
9513
|
+
* Check whether the source adapter supports EIP-5792 atomic batching and
|
|
9514
|
+
* the consumer has not explicitly opted out via `config.batchTransactions`.
|
|
9515
|
+
*
|
|
9516
|
+
* @param params - Bridge parameters (used for adapter and config access).
|
|
9517
|
+
* @returns `true` when batched execution should be attempted.
|
|
9518
|
+
*
|
|
9519
|
+
* @example
|
|
9520
|
+
* ```typescript
|
|
9521
|
+
* const useBatched = await shouldUseBatchedExecution(params)
|
|
9522
|
+
* if (useBatched) {
|
|
9523
|
+
* // take the batched approve + burn path
|
|
9524
|
+
* }
|
|
9525
|
+
* ```
|
|
9526
|
+
*/
|
|
9527
|
+
async function shouldUseBatchedExecution(params) {
|
|
9528
|
+
if (params.config?.batchTransactions === false) {
|
|
9529
|
+
return false;
|
|
9530
|
+
}
|
|
9531
|
+
const { chain } = params.source;
|
|
9532
|
+
if (chain.type !== 'evm') {
|
|
9533
|
+
return false;
|
|
9534
|
+
}
|
|
9535
|
+
const adapter = params.source
|
|
9536
|
+
.adapter;
|
|
9537
|
+
if (typeof adapter.supportsAtomicBatch !== 'function' ||
|
|
9538
|
+
typeof adapter.batchExecute !== 'function') {
|
|
9539
|
+
return false;
|
|
9540
|
+
}
|
|
9541
|
+
try {
|
|
9542
|
+
return await adapter.supportsAtomicBatch(chain);
|
|
9543
|
+
}
|
|
9544
|
+
catch {
|
|
9545
|
+
return false;
|
|
9546
|
+
}
|
|
9547
|
+
}
|
|
9548
|
+
/**
|
|
9549
|
+
* Execute the approve and burn steps as a single EIP-5792 batched call.
|
|
9550
|
+
*
|
|
9551
|
+
* Prepare both `PreparedChainRequest` objects upfront, extract their raw
|
|
9552
|
+
* call data via `getCallData()`, submit both via `adapter.batchExecute()`,
|
|
9553
|
+
* then map the individual receipts back to standard {@link BridgeStep}
|
|
9554
|
+
* objects so downstream consumers (event callbacks, result tracking) are
|
|
9555
|
+
* unaffected.
|
|
9556
|
+
*
|
|
9557
|
+
* @param params - The CCTP v2 bridge parameters.
|
|
9558
|
+
* @param provider - The CCTP v2 bridging provider.
|
|
9559
|
+
* @returns Approve and burn steps with a shared context containing the burn tx hash.
|
|
9560
|
+
* @throws {@link KitError} when the source chain is not EVM.
|
|
9561
|
+
* @throws {@link KitError} when calldata extraction (`getCallData`) is not supported
|
|
9562
|
+
* by the prepared requests.
|
|
9563
|
+
* @remarks
|
|
9564
|
+
* Errors that occur after the batch has been submitted to the wallet
|
|
9565
|
+
* (e.g. polling timeout, insufficient receipts) are **not thrown** — they
|
|
9566
|
+
* are captured as `state: 'error'` on the returned steps to prevent
|
|
9567
|
+
* accidental double-spend on retry.
|
|
9568
|
+
*
|
|
9569
|
+
* @example
|
|
9570
|
+
* ```typescript
|
|
9571
|
+
* const { approveStep, burnStep, context } = await executeBatchedApproveAndBurn(
|
|
9572
|
+
* params,
|
|
9573
|
+
* provider,
|
|
9574
|
+
* )
|
|
9575
|
+
* result.steps.push(approveStep, burnStep)
|
|
9576
|
+
* ```
|
|
9577
|
+
*/
|
|
9578
|
+
async function executeBatchedApproveAndBurn(params, provider) {
|
|
9579
|
+
// Double-unknown cast: Adapter<TFrom> has no structural overlap with
|
|
9580
|
+
// BatchCapableAdapter (a duck-typed interface for EIP-5792 methods).
|
|
9581
|
+
// A direct cast fails because TS cannot prove the intersection; the
|
|
9582
|
+
// runtime capability check below guards against unsupported adapters.
|
|
9583
|
+
const adapter = params.source.adapter;
|
|
9584
|
+
const sourceChain = params.source.chain;
|
|
9585
|
+
if (sourceChain.type !== 'evm') {
|
|
9586
|
+
throw new KitError({
|
|
9587
|
+
...InputError.INVALID_CHAIN,
|
|
9588
|
+
recoverability: 'FATAL',
|
|
9589
|
+
message: 'Batched execution is only supported on EVM chains.',
|
|
9590
|
+
});
|
|
9591
|
+
}
|
|
9592
|
+
const chain = sourceChain;
|
|
9593
|
+
// customFee.value is in base units (integer string) at this point.
|
|
9594
|
+
const customFee = BigInt(params.config?.customFee?.value ?? '0');
|
|
9595
|
+
const amountBigInt = BigInt(params.amount);
|
|
9596
|
+
const approvalAmount = (amountBigInt + customFee).toString();
|
|
9597
|
+
const [approveRequest, burnRequest] = await Promise.all([
|
|
9598
|
+
provider.approve(params.source, approvalAmount),
|
|
9599
|
+
provider.burn(params),
|
|
9600
|
+
]);
|
|
9601
|
+
if (approveRequest.type !== 'evm' ||
|
|
9602
|
+
burnRequest.type !== 'evm' ||
|
|
9603
|
+
!approveRequest.getCallData ||
|
|
9604
|
+
!burnRequest.getCallData) {
|
|
9605
|
+
throw new KitError({
|
|
9606
|
+
...InputError.UNSUPPORTED_ACTION,
|
|
9607
|
+
recoverability: 'FATAL',
|
|
9608
|
+
message: 'Batched execution requires EVM prepared requests with getCallData() support.',
|
|
9609
|
+
});
|
|
9610
|
+
}
|
|
9611
|
+
const approveCallData = approveRequest.getCallData();
|
|
9612
|
+
const burnCallData = burnRequest.getCallData();
|
|
9613
|
+
// batchExecute may throw before submission (wallet declined) but never
|
|
9614
|
+
// after — post-submission errors are returned as empty receipts.
|
|
9615
|
+
const batchResult = await adapter.batchExecute([approveCallData, burnCallData], chain);
|
|
9616
|
+
const approveReceipt = batchResult.receipts[0];
|
|
9617
|
+
const burnReceipt = batchResult.receipts[1];
|
|
9618
|
+
const approveStep = await buildBatchedStep('approve', approveReceipt, batchResult.batchId, adapter, chain);
|
|
9619
|
+
const burnStep = await buildBatchedStep('burn', burnReceipt, batchResult.batchId, adapter, chain);
|
|
9620
|
+
if (burnStep.state !== 'error' && !burnStep.txHash) {
|
|
9621
|
+
burnStep.state = 'error';
|
|
9622
|
+
burnStep.errorMessage =
|
|
9623
|
+
'Batched burn step completed but no transaction hash was returned.';
|
|
9624
|
+
}
|
|
9625
|
+
const context = { burnTxHash: burnStep.txHash ?? '' };
|
|
9626
|
+
return { approveStep, burnStep, context };
|
|
9627
|
+
}
|
|
9628
|
+
/**
|
|
9629
|
+
* Build a {@link BridgeStep} from a single receipt within a batch.
|
|
9630
|
+
*
|
|
9631
|
+
* Map the raw receipt from `batchExecute` into a standard `BridgeStep`,
|
|
9632
|
+
* waiting for on-chain confirmation via `adapter.waitForTransaction`.
|
|
9633
|
+
* All errors are captured on the step (never thrown) so the caller
|
|
9634
|
+
* can inspect each step independently.
|
|
9635
|
+
*
|
|
9636
|
+
* @param name - Human-readable step name (e.g. `'approve'`, `'burn'`).
|
|
9637
|
+
* @param receipt - Per-call receipt from `batchExecute`, or `undefined`
|
|
9638
|
+
* when the wallet returned fewer receipts than submitted calls.
|
|
9639
|
+
* @param batchId - Wallet-assigned batch identifier.
|
|
9640
|
+
* @param adapter - The batch-capable adapter (used for confirmation).
|
|
9641
|
+
* @param chain - The EVM chain the batch was executed on.
|
|
9642
|
+
* @returns A fully-populated bridge step with state, tx hash and explorer URL.
|
|
9643
|
+
*
|
|
9644
|
+
* @internal
|
|
9645
|
+
*/
|
|
9646
|
+
async function buildBatchedStep(name, receipt, batchId, adapter, chain) {
|
|
9647
|
+
const step = {
|
|
9648
|
+
name,
|
|
9649
|
+
state: 'pending',
|
|
9650
|
+
batched: true,
|
|
9651
|
+
batchId,
|
|
9652
|
+
};
|
|
9653
|
+
if (!receipt) {
|
|
9654
|
+
step.state = 'error';
|
|
9655
|
+
step.errorMessage = `No receipt returned for ${name} in batch ${batchId}.`;
|
|
9656
|
+
return step;
|
|
9657
|
+
}
|
|
9658
|
+
step.txHash = receipt.txHash;
|
|
9659
|
+
if (receipt.txHash) {
|
|
9660
|
+
step.explorerUrl = buildExplorerUrl(chain, receipt.txHash);
|
|
9661
|
+
}
|
|
9662
|
+
if (receipt.status !== 'success') {
|
|
9663
|
+
step.state = 'error';
|
|
9664
|
+
step.errorMessage = `${name} call failed within batch ${batchId}.`;
|
|
9665
|
+
return step;
|
|
9666
|
+
}
|
|
9667
|
+
if (!receipt.txHash) {
|
|
9668
|
+
step.state = 'error';
|
|
9669
|
+
step.errorMessage = `${name} succeeded in batch but returned an empty transaction hash.`;
|
|
9670
|
+
return step;
|
|
9671
|
+
}
|
|
9672
|
+
try {
|
|
9673
|
+
const transaction = await adapter.waitForTransaction(receipt.txHash, { confirmations: 1 }, chain);
|
|
9674
|
+
step.state = transaction.blockNumber === undefined ? 'error' : 'success';
|
|
9675
|
+
step.data = transaction;
|
|
9676
|
+
if (transaction.blockNumber === undefined) {
|
|
9677
|
+
step.errorMessage = 'Transaction was not confirmed on-chain.';
|
|
9678
|
+
}
|
|
9679
|
+
}
|
|
9680
|
+
catch (err) {
|
|
9681
|
+
step.state = 'error';
|
|
9682
|
+
step.error = err;
|
|
9683
|
+
step.errorMessage =
|
|
9684
|
+
err instanceof Error ? err.message : 'Unknown error during confirmation.';
|
|
9685
|
+
}
|
|
9686
|
+
return step;
|
|
9687
|
+
}
|
|
9688
|
+
|
|
9689
|
+
var version = "1.6.0";
|
|
9321
9690
|
var pkg = {
|
|
9322
9691
|
version: version};
|
|
9323
9692
|
|
|
@@ -9346,6 +9715,67 @@ function resolveBridgeInvocation(invocationMeta) {
|
|
|
9346
9715
|
};
|
|
9347
9716
|
return extendInvocationContext(resolveInvocationContext(invocationMeta, defaults), BRIDGE_CALLER);
|
|
9348
9717
|
}
|
|
9718
|
+
/**
|
|
9719
|
+
* Execute the batched approve + burn path via EIP-5792.
|
|
9720
|
+
*
|
|
9721
|
+
* Mutate `result` with step data and error state as needed. Return the
|
|
9722
|
+
* batch context on success, or `undefined` when the batch failed (in
|
|
9723
|
+
* which case `result.state` is set to `'error'`).
|
|
9724
|
+
*
|
|
9725
|
+
* @internal
|
|
9726
|
+
* @param params - Bridge parameters (read-only).
|
|
9727
|
+
* @param provider - The CCTP v2 bridging provider (read-only).
|
|
9728
|
+
* @param result - Bridge result object — **mutated in place** with step
|
|
9729
|
+
* data and, on failure, `state: 'error'` plus an `error` payload.
|
|
9730
|
+
* @param invocation - Invocation context for telemetry (read-only).
|
|
9731
|
+
* @returns The step context on success, or `undefined` when the batch failed.
|
|
9732
|
+
*/
|
|
9733
|
+
async function executeBatchedPath(params, provider, result, invocation) {
|
|
9734
|
+
// IMPORTANT: once executeBatchedApproveAndBurn is called, we NEVER
|
|
9735
|
+
// fall back to sequential. The wallet may have already signed &
|
|
9736
|
+
// submitted the batch; retrying as individual txs would double-spend.
|
|
9737
|
+
try {
|
|
9738
|
+
const { approveStep, burnStep, context: batchContext, } = await executeBatchedApproveAndBurn(params, provider);
|
|
9739
|
+
for (const step of [approveStep, burnStep]) {
|
|
9740
|
+
const stepName = step.name;
|
|
9741
|
+
if (step.state === 'error') {
|
|
9742
|
+
ensureStepErrorMessage(step.name, step);
|
|
9743
|
+
result.steps.push(step);
|
|
9744
|
+
result.state = 'error';
|
|
9745
|
+
dispatchStepEvent(stepName, step, provider, invocation);
|
|
9746
|
+
return undefined;
|
|
9747
|
+
}
|
|
9748
|
+
dispatchStepEvent(stepName, step, provider, invocation);
|
|
9749
|
+
result.steps.push(step);
|
|
9750
|
+
}
|
|
9751
|
+
return batchContext;
|
|
9752
|
+
}
|
|
9753
|
+
catch (error_) {
|
|
9754
|
+
// Only handles pre-submission failures (prepare rejected, wallet
|
|
9755
|
+
// declined, etc.). batchExecute never throws after sendCalls succeeds.
|
|
9756
|
+
result.state = 'error';
|
|
9757
|
+
result.steps.push({
|
|
9758
|
+
name: 'batch',
|
|
9759
|
+
state: 'error',
|
|
9760
|
+
batched: true,
|
|
9761
|
+
error: error_,
|
|
9762
|
+
errorMessage: error_ instanceof Error
|
|
9763
|
+
? error_.message
|
|
9764
|
+
: 'Batched approve + burn failed.',
|
|
9765
|
+
});
|
|
9766
|
+
return undefined;
|
|
9767
|
+
}
|
|
9768
|
+
}
|
|
9769
|
+
/**
|
|
9770
|
+
* Ensure `step.errorMessage` is populated when an error object exists.
|
|
9771
|
+
*
|
|
9772
|
+
* @internal
|
|
9773
|
+
*/
|
|
9774
|
+
function ensureStepErrorMessage(name, step) {
|
|
9775
|
+
if (!step.errorMessage && step.error) {
|
|
9776
|
+
step.errorMessage = `${name} step failed: ${getErrorMessage(step.error)}`;
|
|
9777
|
+
}
|
|
9778
|
+
}
|
|
9349
9779
|
/**
|
|
9350
9780
|
* Execute a cross-chain USDC bridge using the CCTP v2 protocol.
|
|
9351
9781
|
*
|
|
@@ -9379,9 +9809,7 @@ function resolveBridgeInvocation(invocationMeta) {
|
|
|
9379
9809
|
* ```
|
|
9380
9810
|
*/
|
|
9381
9811
|
async function bridge(params, provider) {
|
|
9382
|
-
// Check if forwarder is enabled (on destination)
|
|
9383
9812
|
const useForwarder = params.destination.useForwarder === true;
|
|
9384
|
-
// Resolve invocation metadata to full context for event dispatching
|
|
9385
9813
|
const invocation = resolveBridgeInvocation(params.invocationMeta);
|
|
9386
9814
|
const result = {
|
|
9387
9815
|
state: 'pending',
|
|
@@ -9394,11 +9822,9 @@ async function bridge(params, provider) {
|
|
|
9394
9822
|
destination: {
|
|
9395
9823
|
address: params.destination.address,
|
|
9396
9824
|
chain: params.destination.chain,
|
|
9397
|
-
// Preserve recipientAddress
|
|
9398
9825
|
...(params.destination.recipientAddress && {
|
|
9399
9826
|
recipientAddress: params.destination.recipientAddress,
|
|
9400
9827
|
}),
|
|
9401
|
-
// Preserve useForwarder
|
|
9402
9828
|
...(useForwarder && {
|
|
9403
9829
|
useForwarder: true,
|
|
9404
9830
|
}),
|
|
@@ -9407,29 +9833,38 @@ async function bridge(params, provider) {
|
|
|
9407
9833
|
config: params.config,
|
|
9408
9834
|
provider: provider.name,
|
|
9409
9835
|
};
|
|
9410
|
-
// Context shared between steps
|
|
9411
9836
|
let context = undefined;
|
|
9412
|
-
|
|
9837
|
+
let useBatched = false;
|
|
9838
|
+
try {
|
|
9839
|
+
useBatched = await shouldUseBatchedExecution(params);
|
|
9840
|
+
}
|
|
9841
|
+
catch {
|
|
9842
|
+
// Silently fall back to sequential
|
|
9843
|
+
}
|
|
9413
9844
|
const executors = createStepExecutors(useForwarder);
|
|
9414
|
-
|
|
9415
|
-
|
|
9845
|
+
if (useBatched) {
|
|
9846
|
+
const batchContext = await executeBatchedPath(params, provider, result, invocation);
|
|
9847
|
+
if (result.state === 'error') {
|
|
9848
|
+
return result;
|
|
9849
|
+
}
|
|
9850
|
+
context = batchContext;
|
|
9851
|
+
}
|
|
9852
|
+
const stepsToRun = useBatched
|
|
9853
|
+
? executors.filter(({ name }) => name !== 'approve' && name !== 'burn')
|
|
9854
|
+
: executors;
|
|
9855
|
+
for (const { name, executor, updateContext } of stepsToRun) {
|
|
9416
9856
|
try {
|
|
9417
9857
|
const step = await executor(params, provider, context);
|
|
9418
9858
|
if (step.state === 'error') {
|
|
9419
|
-
|
|
9420
|
-
if (!step.errorMessage && step.error) {
|
|
9421
|
-
step.errorMessage = `${name} step failed: ${getErrorMessage(step.error)}`;
|
|
9422
|
-
}
|
|
9859
|
+
ensureStepErrorMessage(name, step);
|
|
9423
9860
|
result.steps.push(step);
|
|
9424
9861
|
result.state = 'error';
|
|
9425
|
-
// Dispatch event even for error steps
|
|
9426
9862
|
dispatchStepEvent(name, step, provider, invocation);
|
|
9427
9863
|
return result;
|
|
9428
9864
|
}
|
|
9429
|
-
// Merge new context with existing context to preserve data from previous steps
|
|
9430
9865
|
const newContext = updateContext?.(step);
|
|
9431
9866
|
if (newContext) {
|
|
9432
|
-
context = { ...
|
|
9867
|
+
context = { ...context, ...newContext };
|
|
9433
9868
|
}
|
|
9434
9869
|
dispatchStepEvent(name, step, provider, invocation);
|
|
9435
9870
|
result.steps.push(step);
|