@circle-fin/app-kit 1.0.1 → 1.2.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/index.cjs CHANGED
@@ -3225,6 +3225,8 @@ exports.Blockchain = void 0;
3225
3225
  Blockchain["Celo_Alfajores_Testnet"] = "Celo_Alfajores_Testnet";
3226
3226
  Blockchain["Codex"] = "Codex";
3227
3227
  Blockchain["Codex_Testnet"] = "Codex_Testnet";
3228
+ Blockchain["Edge"] = "Edge";
3229
+ Blockchain["Edge_Testnet"] = "Edge_Testnet";
3228
3230
  Blockchain["Ethereum"] = "Ethereum";
3229
3231
  Blockchain["Ethereum_Sepolia"] = "Ethereum_Sepolia";
3230
3232
  Blockchain["Hedera"] = "Hedera";
@@ -3237,6 +3239,8 @@ exports.Blockchain = void 0;
3237
3239
  Blockchain["Linea_Sepolia"] = "Linea_Sepolia";
3238
3240
  Blockchain["Monad"] = "Monad";
3239
3241
  Blockchain["Monad_Testnet"] = "Monad_Testnet";
3242
+ Blockchain["Morph"] = "Morph";
3243
+ Blockchain["Morph_Testnet"] = "Morph_Testnet";
3240
3244
  Blockchain["NEAR"] = "NEAR";
3241
3245
  Blockchain["NEAR_Testnet"] = "NEAR_Testnet";
3242
3246
  Blockchain["Noble"] = "Noble";
@@ -3440,11 +3444,13 @@ exports.BridgeChain = void 0;
3440
3444
  BridgeChain["Avalanche"] = "Avalanche";
3441
3445
  BridgeChain["Base"] = "Base";
3442
3446
  BridgeChain["Codex"] = "Codex";
3447
+ BridgeChain["Edge"] = "Edge";
3443
3448
  BridgeChain["Ethereum"] = "Ethereum";
3444
3449
  BridgeChain["HyperEVM"] = "HyperEVM";
3445
3450
  BridgeChain["Ink"] = "Ink";
3446
3451
  BridgeChain["Linea"] = "Linea";
3447
3452
  BridgeChain["Monad"] = "Monad";
3453
+ BridgeChain["Morph"] = "Morph";
3448
3454
  BridgeChain["Optimism"] = "Optimism";
3449
3455
  BridgeChain["Plume"] = "Plume";
3450
3456
  BridgeChain["Polygon"] = "Polygon";
@@ -3460,11 +3466,13 @@ exports.BridgeChain = void 0;
3460
3466
  BridgeChain["Avalanche_Fuji"] = "Avalanche_Fuji";
3461
3467
  BridgeChain["Base_Sepolia"] = "Base_Sepolia";
3462
3468
  BridgeChain["Codex_Testnet"] = "Codex_Testnet";
3469
+ BridgeChain["Edge_Testnet"] = "Edge_Testnet";
3463
3470
  BridgeChain["Ethereum_Sepolia"] = "Ethereum_Sepolia";
3464
3471
  BridgeChain["HyperEVM_Testnet"] = "HyperEVM_Testnet";
3465
3472
  BridgeChain["Ink_Testnet"] = "Ink_Testnet";
3466
3473
  BridgeChain["Linea_Sepolia"] = "Linea_Sepolia";
3467
3474
  BridgeChain["Monad_Testnet"] = "Monad_Testnet";
3475
+ BridgeChain["Morph_Testnet"] = "Morph_Testnet";
3468
3476
  BridgeChain["Optimism_Sepolia"] = "Optimism_Sepolia";
3469
3477
  BridgeChain["Plume_Testnet"] = "Plume_Testnet";
3470
3478
  BridgeChain["Polygon_Amoy_Testnet"] = "Polygon_Amoy_Testnet";
@@ -4223,7 +4231,7 @@ const Codex = defineChain({
4223
4231
  },
4224
4232
  forwarderSupported: {
4225
4233
  source: true,
4226
- destination: false,
4234
+ destination: true,
4227
4235
  },
4228
4236
  },
4229
4237
  kitContracts: {
@@ -4266,7 +4274,95 @@ const CodexTestnet = defineChain({
4266
4274
  },
4267
4275
  forwarderSupported: {
4268
4276
  source: true,
4269
- destination: false,
4277
+ destination: true,
4278
+ },
4279
+ },
4280
+ kitContracts: {
4281
+ bridge: BRIDGE_CONTRACT_EVM_TESTNET,
4282
+ },
4283
+ });
4284
+
4285
+ /**
4286
+ * Edge Mainnet chain definition
4287
+ * @remarks
4288
+ * This represents the official production network for the Edge blockchain.
4289
+ * Edge is an EVM-compatible blockchain.
4290
+ */
4291
+ const Edge = defineChain({
4292
+ type: 'evm',
4293
+ chain: exports.Blockchain.Edge,
4294
+ name: 'Edge',
4295
+ title: 'Edge Mainnet',
4296
+ nativeCurrency: {
4297
+ name: 'Ether',
4298
+ symbol: 'ETH',
4299
+ decimals: 18,
4300
+ },
4301
+ chainId: 3343,
4302
+ isTestnet: false,
4303
+ explorerUrl: 'https://pro.edgex.exchange/en-US/explorer/tx/{hash}',
4304
+ rpcEndpoints: ['https://edge-mainnet.g.alchemy.com/public'],
4305
+ eurcAddress: null,
4306
+ usdcAddress: '0x98d2919b9A214E6Fa5384AC81E6864bA686Ad74c',
4307
+ usdtAddress: null,
4308
+ cctp: {
4309
+ domain: 28,
4310
+ contracts: {
4311
+ v2: {
4312
+ type: 'split',
4313
+ tokenMessenger: '0x98706A006bc632Df31CAdFCBD43F38887ce2ca5c',
4314
+ messageTransmitter: '0x5b61381Fc9e58E70EfC13a4A97516997019198ee',
4315
+ confirmations: 65,
4316
+ fastConfirmations: 1,
4317
+ },
4318
+ },
4319
+ forwarderSupported: {
4320
+ source: true,
4321
+ destination: true,
4322
+ },
4323
+ },
4324
+ kitContracts: {
4325
+ bridge: '0x6D1AaE1c34Aeb582022916a67f2A655C6f4eDFF2', //Unique bridge address as CCTP address for Edge is also unique
4326
+ },
4327
+ });
4328
+
4329
+ /**
4330
+ * Edge Testnet chain definition
4331
+ * @remarks
4332
+ * This represents the official test network for the Edge blockchain.
4333
+ * Edge is an EVM-compatible blockchain.
4334
+ */
4335
+ const EdgeTestnet = defineChain({
4336
+ type: 'evm',
4337
+ chain: exports.Blockchain.Edge_Testnet,
4338
+ name: 'Edge Testnet',
4339
+ title: 'Edge Testnet',
4340
+ nativeCurrency: {
4341
+ name: 'Ether',
4342
+ symbol: 'ETH',
4343
+ decimals: 18,
4344
+ },
4345
+ chainId: 33431,
4346
+ isTestnet: true,
4347
+ explorerUrl: 'https://edge-testnet.explorer.alchemy.com/tx/{hash}',
4348
+ rpcEndpoints: ['https://edge-testnet.g.alchemy.com/public'],
4349
+ eurcAddress: null,
4350
+ usdcAddress: '0x2d9F7CAD728051AA35Ecdc472a14cf8cDF5CFD6B',
4351
+ usdtAddress: null,
4352
+ cctp: {
4353
+ domain: 28,
4354
+ contracts: {
4355
+ v2: {
4356
+ type: 'split',
4357
+ tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
4358
+ messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
4359
+ confirmations: 65,
4360
+ fastConfirmations: 1,
4361
+ },
4362
+ },
4363
+ forwarderSupported: {
4364
+ source: true,
4365
+ destination: true,
4270
4366
  },
4271
4367
  },
4272
4368
  kitContracts: {
@@ -4440,7 +4536,7 @@ const HyperEVM = defineChain({
4440
4536
  },
4441
4537
  chainId: 999,
4442
4538
  isTestnet: false,
4443
- explorerUrl: 'https://hyperevmscan.io/tx/{hash}',
4539
+ explorerUrl: 'https://app.hyperliquid.xyz/explorer/tx/{hash}',
4444
4540
  rpcEndpoints: ['https://rpc.hyperliquid.xyz/evm'],
4445
4541
  eurcAddress: null,
4446
4542
  usdcAddress: '0xb88339CB7199b77E23DB6E890353E22632Ba630f',
@@ -4485,7 +4581,7 @@ const HyperEVMTestnet = defineChain({
4485
4581
  },
4486
4582
  chainId: 998,
4487
4583
  isTestnet: true,
4488
- explorerUrl: 'https://testnet.hyperliquid.xyz/explorer/tx/{hash}',
4584
+ explorerUrl: 'https://app.hyperliquid-testnet.xyz/explorer/tx/{hash}',
4489
4585
  rpcEndpoints: ['https://rpc.hyperliquid-testnet.xyz/evm'],
4490
4586
  eurcAddress: null,
4491
4587
  usdcAddress: '0x2B3370eE501B4a559b57D449569354196457D8Ab',
@@ -4785,6 +4881,94 @@ const MonadTestnet = defineChain({
4785
4881
  },
4786
4882
  });
4787
4883
 
4884
+ /**
4885
+ * Morph Mainnet chain definition
4886
+ * @remarks
4887
+ * This represents the official production network for the Morph blockchain.
4888
+ * Morph is an EVM-compatible Layer-2 blockchain built on the OP Stack.
4889
+ */
4890
+ const Morph = defineChain({
4891
+ type: 'evm',
4892
+ chain: exports.Blockchain.Morph,
4893
+ name: 'Morph',
4894
+ title: 'Morph Mainnet',
4895
+ nativeCurrency: {
4896
+ name: 'Ether',
4897
+ symbol: 'ETH',
4898
+ decimals: 18,
4899
+ },
4900
+ chainId: 2818,
4901
+ isTestnet: false,
4902
+ explorerUrl: 'https://explorer.morph.network/tx/{hash}',
4903
+ rpcEndpoints: ['https://rpc.morphl2.io'],
4904
+ eurcAddress: null,
4905
+ usdcAddress: '0xCfb1186F4e93D60E60a8bDd997427D1F33bc372B',
4906
+ usdtAddress: null,
4907
+ cctp: {
4908
+ domain: 30,
4909
+ contracts: {
4910
+ v2: {
4911
+ type: 'split',
4912
+ tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
4913
+ messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
4914
+ confirmations: 64,
4915
+ fastConfirmations: 1,
4916
+ },
4917
+ },
4918
+ forwarderSupported: {
4919
+ source: false,
4920
+ destination: false,
4921
+ },
4922
+ },
4923
+ kitContracts: {
4924
+ bridge: BRIDGE_CONTRACT_EVM_MAINNET,
4925
+ },
4926
+ });
4927
+
4928
+ /**
4929
+ * Morph Hoodi Testnet chain definition
4930
+ * @remarks
4931
+ * This represents the official test network for the Morph blockchain.
4932
+ * Morph is an EVM-compatible Layer-2 blockchain built on the OP Stack.
4933
+ */
4934
+ const MorphTestnet = defineChain({
4935
+ type: 'evm',
4936
+ chain: exports.Blockchain.Morph_Testnet,
4937
+ name: 'Morph Hoodi',
4938
+ title: 'Morph Hoodi Testnet',
4939
+ nativeCurrency: {
4940
+ name: 'Ether',
4941
+ symbol: 'ETH',
4942
+ decimals: 18,
4943
+ },
4944
+ chainId: 2910,
4945
+ isTestnet: true,
4946
+ explorerUrl: 'https://explorer-hoodi.morphl2.io/tx/{hash}',
4947
+ rpcEndpoints: ['https://rpc-hoodi.morphl2.io'],
4948
+ eurcAddress: null,
4949
+ usdcAddress: '0x7433b41C6c5e1d58D4Da99483609520255ab661B',
4950
+ usdtAddress: null,
4951
+ cctp: {
4952
+ domain: 30,
4953
+ contracts: {
4954
+ v2: {
4955
+ type: 'split',
4956
+ tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
4957
+ messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
4958
+ confirmations: 64,
4959
+ fastConfirmations: 1,
4960
+ },
4961
+ },
4962
+ forwarderSupported: {
4963
+ source: false,
4964
+ destination: false,
4965
+ },
4966
+ },
4967
+ kitContracts: {
4968
+ bridge: BRIDGE_CONTRACT_EVM_TESTNET,
4969
+ },
4970
+ });
4971
+
4788
4972
  /**
4789
4973
  * NEAR Protocol Mainnet chain definition
4790
4974
  * @remarks
@@ -5043,7 +5227,7 @@ const Plume = defineChain({
5043
5227
  },
5044
5228
  forwarderSupported: {
5045
5229
  source: true,
5046
- destination: false,
5230
+ destination: true,
5047
5231
  },
5048
5232
  },
5049
5233
  kitContracts: {
@@ -5088,7 +5272,7 @@ const PlumeTestnet = defineChain({
5088
5272
  },
5089
5273
  forwarderSupported: {
5090
5274
  source: true,
5091
- destination: false,
5275
+ destination: true,
5092
5276
  },
5093
5277
  },
5094
5278
  kitContracts: {
@@ -5866,7 +6050,7 @@ const XDC = defineChain({
5866
6050
  },
5867
6051
  forwarderSupported: {
5868
6052
  source: true,
5869
- destination: false,
6053
+ destination: true,
5870
6054
  },
5871
6055
  },
5872
6056
  kitContracts: {
@@ -5910,7 +6094,7 @@ const XDCApothem = defineChain({
5910
6094
  },
5911
6095
  forwarderSupported: {
5912
6096
  source: true,
5913
- destination: false,
6097
+ destination: true,
5914
6098
  },
5915
6099
  },
5916
6100
  kitContracts: {
@@ -5985,6 +6169,8 @@ var Chains = {
5985
6169
  CeloAlfajoresTestnet: CeloAlfajoresTestnet,
5986
6170
  Codex: Codex,
5987
6171
  CodexTestnet: CodexTestnet,
6172
+ Edge: Edge,
6173
+ EdgeTestnet: EdgeTestnet,
5988
6174
  Ethereum: Ethereum,
5989
6175
  EthereumSepolia: EthereumSepolia,
5990
6176
  Hedera: Hedera,
@@ -5997,6 +6183,8 @@ var Chains = {
5997
6183
  LineaSepolia: LineaSepolia,
5998
6184
  Monad: Monad,
5999
6185
  MonadTestnet: MonadTestnet,
6186
+ Morph: Morph,
6187
+ MorphTestnet: MorphTestnet,
6000
6188
  NEAR: NEAR,
6001
6189
  NEARTestnet: NEARTestnet,
6002
6190
  Noble: Noble,
@@ -7993,12 +8181,14 @@ const USDC = {
7993
8181
  [exports.Blockchain.Base]: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
7994
8182
  [exports.Blockchain.Celo]: '0xcebA9300f2b948710d2653dD7B07f33A8B32118C',
7995
8183
  [exports.Blockchain.Codex]: '0xd996633a415985DBd7D6D12f4A4343E31f5037cf',
8184
+ [exports.Blockchain.Edge]: '0x98d2919b9A214E6Fa5384AC81E6864bA686Ad74c',
7996
8185
  [exports.Blockchain.Ethereum]: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
7997
8186
  [exports.Blockchain.Hedera]: '0.0.456858',
7998
8187
  [exports.Blockchain.HyperEVM]: '0xb88339CB7199b77E23DB6E890353E22632Ba630f',
7999
8188
  [exports.Blockchain.Ink]: '0x2D270e6886d130D724215A266106e6832161EAEd',
8000
8189
  [exports.Blockchain.Linea]: '0x176211869ca2b568f2a7d4ee941e073a821ee1ff',
8001
8190
  [exports.Blockchain.Monad]: '0x754704Bc059F8C67012fEd69BC8A327a5aafb603',
8191
+ [exports.Blockchain.Morph]: '0xCfb1186F4e93D60E60a8bDd997427D1F33bc372B',
8002
8192
  [exports.Blockchain.NEAR]: '17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1',
8003
8193
  [exports.Blockchain.Noble]: 'uusdc',
8004
8194
  [exports.Blockchain.Optimism]: '0x0b2c639c533813f4aa9d7837caf62653d097ff85',
@@ -8021,12 +8211,14 @@ const USDC = {
8021
8211
  [exports.Blockchain.Avalanche_Fuji]: '0x5425890298aed601595a70AB815c96711a31Bc65',
8022
8212
  [exports.Blockchain.Base_Sepolia]: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',
8023
8213
  [exports.Blockchain.Codex_Testnet]: '0x6d7f141b6819C2c9CC2f818e6ad549E7Ca090F8f',
8214
+ [exports.Blockchain.Edge_Testnet]: '0x2d9F7CAD728051AA35Ecdc472a14cf8cDF5CFD6B',
8024
8215
  [exports.Blockchain.Ethereum_Sepolia]: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',
8025
8216
  [exports.Blockchain.Hedera_Testnet]: '0.0.429274',
8026
8217
  [exports.Blockchain.HyperEVM_Testnet]: '0x2B3370eE501B4a559b57D449569354196457D8Ab',
8027
8218
  [exports.Blockchain.Ink_Testnet]: '0xFabab97dCE620294D2B0b0e46C68964e326300Ac',
8028
8219
  [exports.Blockchain.Linea_Sepolia]: '0xfece4462d57bd51a6a552365a011b95f0e16d9b7',
8029
8220
  [exports.Blockchain.Monad_Testnet]: '0x534b2f3A21130d7a60830c2Df862319e593943A3',
8221
+ [exports.Blockchain.Morph_Testnet]: '0x7433b41C6c5e1d58D4Da99483609520255ab661B',
8030
8222
  [exports.Blockchain.NEAR_Testnet]: '3e2210e1184b45b64c8a434c0a7e7b23cc04ea7eb7a6c3c32520d03d4afcb8af',
8031
8223
  [exports.Blockchain.Noble_Testnet]: 'uusdc',
8032
8224
  [exports.Blockchain.Optimism_Sepolia]: '0x5fd84259d66Cd46123540766Be93DFE6D43130D7',
@@ -9015,7 +9207,7 @@ function buildForwardingHookData() {
9015
9207
  }
9016
9208
 
9017
9209
  var name$1 = "@circle-fin/bridge-kit";
9018
- var version$2 = "1.6.1";
9210
+ var version$2 = "1.8.0";
9019
9211
  var pkg$2 = {
9020
9212
  name: name$1,
9021
9213
  version: version$2};
@@ -13105,7 +13297,184 @@ function dispatchStepEvent(name, step, provider, invocation) {
13105
13297
  }
13106
13298
  }
13107
13299
 
13108
- var version$1 = "1.4.1";
13300
+ /**
13301
+ * Check whether the source adapter supports EIP-5792 atomic batching and
13302
+ * the consumer has not explicitly opted out via `config.batchTransactions`.
13303
+ *
13304
+ * @param params - Bridge parameters (used for adapter and config access).
13305
+ * @returns `true` when batched execution should be attempted.
13306
+ *
13307
+ * @example
13308
+ * ```typescript
13309
+ * const useBatched = await shouldUseBatchedExecution(params)
13310
+ * if (useBatched) {
13311
+ * // take the batched approve + burn path
13312
+ * }
13313
+ * ```
13314
+ */
13315
+ async function shouldUseBatchedExecution(params) {
13316
+ if (params.config?.batchTransactions === false) {
13317
+ return false;
13318
+ }
13319
+ const { chain } = params.source;
13320
+ if (chain.type !== 'evm') {
13321
+ return false;
13322
+ }
13323
+ const adapter = params.source
13324
+ .adapter;
13325
+ if (typeof adapter.supportsAtomicBatch !== 'function' ||
13326
+ typeof adapter.batchExecute !== 'function') {
13327
+ return false;
13328
+ }
13329
+ try {
13330
+ return await adapter.supportsAtomicBatch(chain);
13331
+ }
13332
+ catch {
13333
+ return false;
13334
+ }
13335
+ }
13336
+ /**
13337
+ * Execute the approve and burn steps as a single EIP-5792 batched call.
13338
+ *
13339
+ * Prepare both `PreparedChainRequest` objects upfront, extract their raw
13340
+ * call data via `getCallData()`, submit both via `adapter.batchExecute()`,
13341
+ * then map the individual receipts back to standard {@link BridgeStep}
13342
+ * objects so downstream consumers (event callbacks, result tracking) are
13343
+ * unaffected.
13344
+ *
13345
+ * @param params - The CCTP v2 bridge parameters.
13346
+ * @param provider - The CCTP v2 bridging provider.
13347
+ * @returns Approve and burn steps with a shared context containing the burn tx hash.
13348
+ * @throws {@link KitError} when the source chain is not EVM.
13349
+ * @throws {@link KitError} when calldata extraction (`getCallData`) is not supported
13350
+ * by the prepared requests.
13351
+ * @remarks
13352
+ * Errors that occur after the batch has been submitted to the wallet
13353
+ * (e.g. polling timeout, insufficient receipts) are **not thrown** — they
13354
+ * are captured as `state: 'error'` on the returned steps to prevent
13355
+ * accidental double-spend on retry.
13356
+ *
13357
+ * @example
13358
+ * ```typescript
13359
+ * const { approveStep, burnStep, context } = await executeBatchedApproveAndBurn(
13360
+ * params,
13361
+ * provider,
13362
+ * )
13363
+ * result.steps.push(approveStep, burnStep)
13364
+ * ```
13365
+ */
13366
+ async function executeBatchedApproveAndBurn(params, provider) {
13367
+ // Double-unknown cast: Adapter<TFrom> has no structural overlap with
13368
+ // BatchCapableAdapter (a duck-typed interface for EIP-5792 methods).
13369
+ // A direct cast fails because TS cannot prove the intersection; the
13370
+ // runtime capability check below guards against unsupported adapters.
13371
+ const adapter = params.source.adapter;
13372
+ const sourceChain = params.source.chain;
13373
+ if (sourceChain.type !== 'evm') {
13374
+ throw new KitError({
13375
+ ...InputError.INVALID_CHAIN,
13376
+ recoverability: 'FATAL',
13377
+ message: 'Batched execution is only supported on EVM chains.',
13378
+ });
13379
+ }
13380
+ const chain = sourceChain;
13381
+ // customFee.value is in base units (integer string) at this point.
13382
+ const customFee = BigInt(params.config?.customFee?.value ?? '0');
13383
+ const amountBigInt = BigInt(params.amount);
13384
+ const approvalAmount = (amountBigInt + customFee).toString();
13385
+ const [approveRequest, burnRequest] = await Promise.all([
13386
+ provider.approve(params.source, approvalAmount),
13387
+ provider.burn(params),
13388
+ ]);
13389
+ if (approveRequest.type !== 'evm' ||
13390
+ burnRequest.type !== 'evm' ||
13391
+ !approveRequest.getCallData ||
13392
+ !burnRequest.getCallData) {
13393
+ throw new KitError({
13394
+ ...InputError.UNSUPPORTED_ACTION,
13395
+ recoverability: 'FATAL',
13396
+ message: 'Batched execution requires EVM prepared requests with getCallData() support.',
13397
+ });
13398
+ }
13399
+ const approveCallData = approveRequest.getCallData();
13400
+ const burnCallData = burnRequest.getCallData();
13401
+ // batchExecute may throw before submission (wallet declined) but never
13402
+ // after — post-submission errors are returned as empty receipts.
13403
+ const batchResult = await adapter.batchExecute([approveCallData, burnCallData], chain);
13404
+ const approveReceipt = batchResult.receipts[0];
13405
+ const burnReceipt = batchResult.receipts[1];
13406
+ const approveStep = await buildBatchedStep('approve', approveReceipt, batchResult.batchId, adapter, chain);
13407
+ const burnStep = await buildBatchedStep('burn', burnReceipt, batchResult.batchId, adapter, chain);
13408
+ if (burnStep.state !== 'error' && !burnStep.txHash) {
13409
+ burnStep.state = 'error';
13410
+ burnStep.errorMessage =
13411
+ 'Batched burn step completed but no transaction hash was returned.';
13412
+ }
13413
+ const context = { burnTxHash: burnStep.txHash ?? '' };
13414
+ return { approveStep, burnStep, context };
13415
+ }
13416
+ /**
13417
+ * Build a {@link BridgeStep} from a single receipt within a batch.
13418
+ *
13419
+ * Map the raw receipt from `batchExecute` into a standard `BridgeStep`,
13420
+ * waiting for on-chain confirmation via `adapter.waitForTransaction`.
13421
+ * All errors are captured on the step (never thrown) so the caller
13422
+ * can inspect each step independently.
13423
+ *
13424
+ * @param name - Human-readable step name (e.g. `'approve'`, `'burn'`).
13425
+ * @param receipt - Per-call receipt from `batchExecute`, or `undefined`
13426
+ * when the wallet returned fewer receipts than submitted calls.
13427
+ * @param batchId - Wallet-assigned batch identifier.
13428
+ * @param adapter - The batch-capable adapter (used for confirmation).
13429
+ * @param chain - The EVM chain the batch was executed on.
13430
+ * @returns A fully-populated bridge step with state, tx hash and explorer URL.
13431
+ *
13432
+ * @internal
13433
+ */
13434
+ async function buildBatchedStep(name, receipt, batchId, adapter, chain) {
13435
+ const step = {
13436
+ name,
13437
+ state: 'pending',
13438
+ batched: true,
13439
+ batchId,
13440
+ };
13441
+ if (!receipt) {
13442
+ step.state = 'error';
13443
+ step.errorMessage = `No receipt returned for ${name} in batch ${batchId}.`;
13444
+ return step;
13445
+ }
13446
+ step.txHash = receipt.txHash;
13447
+ if (receipt.txHash) {
13448
+ step.explorerUrl = buildExplorerUrl(chain, receipt.txHash);
13449
+ }
13450
+ if (receipt.status !== 'success') {
13451
+ step.state = 'error';
13452
+ step.errorMessage = `${name} call failed within batch ${batchId}.`;
13453
+ return step;
13454
+ }
13455
+ if (!receipt.txHash) {
13456
+ step.state = 'error';
13457
+ step.errorMessage = `${name} succeeded in batch but returned an empty transaction hash.`;
13458
+ return step;
13459
+ }
13460
+ try {
13461
+ const transaction = await adapter.waitForTransaction(receipt.txHash, { confirmations: 1 }, chain);
13462
+ step.state = transaction.blockNumber === undefined ? 'error' : 'success';
13463
+ step.data = transaction;
13464
+ if (transaction.blockNumber === undefined) {
13465
+ step.errorMessage = 'Transaction was not confirmed on-chain.';
13466
+ }
13467
+ }
13468
+ catch (err) {
13469
+ step.state = 'error';
13470
+ step.error = err;
13471
+ step.errorMessage =
13472
+ err instanceof Error ? err.message : 'Unknown error during confirmation.';
13473
+ }
13474
+ return step;
13475
+ }
13476
+
13477
+ var version$1 = "1.6.0";
13109
13478
  var pkg$1 = {
13110
13479
  version: version$1};
13111
13480
 
@@ -13134,6 +13503,67 @@ function resolveBridgeInvocation(invocationMeta) {
13134
13503
  };
13135
13504
  return extendInvocationContext(resolveInvocationContext(invocationMeta, defaults), BRIDGE_CALLER);
13136
13505
  }
13506
+ /**
13507
+ * Execute the batched approve + burn path via EIP-5792.
13508
+ *
13509
+ * Mutate `result` with step data and error state as needed. Return the
13510
+ * batch context on success, or `undefined` when the batch failed (in
13511
+ * which case `result.state` is set to `'error'`).
13512
+ *
13513
+ * @internal
13514
+ * @param params - Bridge parameters (read-only).
13515
+ * @param provider - The CCTP v2 bridging provider (read-only).
13516
+ * @param result - Bridge result object — **mutated in place** with step
13517
+ * data and, on failure, `state: 'error'` plus an `error` payload.
13518
+ * @param invocation - Invocation context for telemetry (read-only).
13519
+ * @returns The step context on success, or `undefined` when the batch failed.
13520
+ */
13521
+ async function executeBatchedPath(params, provider, result, invocation) {
13522
+ // IMPORTANT: once executeBatchedApproveAndBurn is called, we NEVER
13523
+ // fall back to sequential. The wallet may have already signed &
13524
+ // submitted the batch; retrying as individual txs would double-spend.
13525
+ try {
13526
+ const { approveStep, burnStep, context: batchContext, } = await executeBatchedApproveAndBurn(params, provider);
13527
+ for (const step of [approveStep, burnStep]) {
13528
+ const stepName = step.name;
13529
+ if (step.state === 'error') {
13530
+ ensureStepErrorMessage(step.name, step);
13531
+ result.steps.push(step);
13532
+ result.state = 'error';
13533
+ dispatchStepEvent(stepName, step, provider, invocation);
13534
+ return undefined;
13535
+ }
13536
+ dispatchStepEvent(stepName, step, provider, invocation);
13537
+ result.steps.push(step);
13538
+ }
13539
+ return batchContext;
13540
+ }
13541
+ catch (error_) {
13542
+ // Only handles pre-submission failures (prepare rejected, wallet
13543
+ // declined, etc.). batchExecute never throws after sendCalls succeeds.
13544
+ result.state = 'error';
13545
+ result.steps.push({
13546
+ name: 'batch',
13547
+ state: 'error',
13548
+ batched: true,
13549
+ error: error_,
13550
+ errorMessage: error_ instanceof Error
13551
+ ? error_.message
13552
+ : 'Batched approve + burn failed.',
13553
+ });
13554
+ return undefined;
13555
+ }
13556
+ }
13557
+ /**
13558
+ * Ensure `step.errorMessage` is populated when an error object exists.
13559
+ *
13560
+ * @internal
13561
+ */
13562
+ function ensureStepErrorMessage(name, step) {
13563
+ if (!step.errorMessage && step.error) {
13564
+ step.errorMessage = `${name} step failed: ${getErrorMessage(step.error)}`;
13565
+ }
13566
+ }
13137
13567
  /**
13138
13568
  * Execute a cross-chain USDC bridge using the CCTP v2 protocol.
13139
13569
  *
@@ -13167,9 +13597,7 @@ function resolveBridgeInvocation(invocationMeta) {
13167
13597
  * ```
13168
13598
  */
13169
13599
  async function bridge$1(params, provider) {
13170
- // Check if forwarder is enabled (on destination)
13171
13600
  const useForwarder = params.destination.useForwarder === true;
13172
- // Resolve invocation metadata to full context for event dispatching
13173
13601
  const invocation = resolveBridgeInvocation(params.invocationMeta);
13174
13602
  const result = {
13175
13603
  state: 'pending',
@@ -13182,11 +13610,9 @@ async function bridge$1(params, provider) {
13182
13610
  destination: {
13183
13611
  address: params.destination.address,
13184
13612
  chain: params.destination.chain,
13185
- // Preserve recipientAddress
13186
13613
  ...(params.destination.recipientAddress && {
13187
13614
  recipientAddress: params.destination.recipientAddress,
13188
13615
  }),
13189
- // Preserve useForwarder
13190
13616
  ...(useForwarder && {
13191
13617
  useForwarder: true,
13192
13618
  }),
@@ -13195,29 +13621,38 @@ async function bridge$1(params, provider) {
13195
13621
  config: params.config,
13196
13622
  provider: provider.name,
13197
13623
  };
13198
- // Context shared between steps
13199
13624
  let context = undefined;
13200
- // Create step executors based on useForwarder config
13625
+ let useBatched = false;
13626
+ try {
13627
+ useBatched = await shouldUseBatchedExecution(params);
13628
+ }
13629
+ catch {
13630
+ // Silently fall back to sequential
13631
+ }
13201
13632
  const executors = createStepExecutors(useForwarder);
13202
- // Execute each step in sequence
13203
- for (const { name, executor, updateContext } of executors) {
13633
+ if (useBatched) {
13634
+ const batchContext = await executeBatchedPath(params, provider, result, invocation);
13635
+ if (result.state === 'error') {
13636
+ return result;
13637
+ }
13638
+ context = batchContext;
13639
+ }
13640
+ const stepsToRun = useBatched
13641
+ ? executors.filter(({ name }) => name !== 'approve' && name !== 'burn')
13642
+ : executors;
13643
+ for (const { name, executor, updateContext } of stepsToRun) {
13204
13644
  try {
13205
13645
  const step = await executor(params, provider, context);
13206
13646
  if (step.state === 'error') {
13207
- // Ensure errorMessage is set with proper formatting if not already present
13208
- if (!step.errorMessage && step.error) {
13209
- step.errorMessage = `${name} step failed: ${getErrorMessage(step.error)}`;
13210
- }
13647
+ ensureStepErrorMessage(name, step);
13211
13648
  result.steps.push(step);
13212
13649
  result.state = 'error';
13213
- // Dispatch event even for error steps
13214
13650
  dispatchStepEvent(name, step, provider, invocation);
13215
13651
  return result;
13216
13652
  }
13217
- // Merge new context with existing context to preserve data from previous steps
13218
13653
  const newContext = updateContext?.(step);
13219
13654
  if (newContext) {
13220
- context = { ...(context ?? {}), ...newContext };
13655
+ context = { ...context, ...newContext };
13221
13656
  }
13222
13657
  dispatchStepEvent(name, step, provider, invocation);
13223
13658
  result.steps.push(step);
@@ -15849,7 +16284,7 @@ const createBridgeKit = (context) => {
15849
16284
  };
15850
16285
 
15851
16286
  var name = "@circle-fin/swap-kit";
15852
- var version = "1.0.0";
16287
+ var version = "1.0.2";
15853
16288
  var pkg = {
15854
16289
  name: name,
15855
16290
  version: version};
@@ -24834,8 +25269,8 @@ const adapterContextSchema = zod.z.object({
24834
25269
  * Schema for validating send parameters.
24835
25270
  * Ensure required fields are present and properly typed. Parameters must include:
24836
25271
  * - A valid `amount` (non-empty numeric string \> 0; supports "," or "." decimal separators and thousands separators).
24837
- * - A valid `from` context (an adapter or full adapter context).
24838
- * - A valid `to` context (an adapter or a destination chain identifier string).
25272
+ * - A valid `from` context (an adapter context with `adapter` and `chain`).
25273
+ * - A valid `to` destination (an adapter instance or a wallet address string).
24839
25274
  * - An optional `token` selection: 'USDC' (default), 'USDT', 'NATIVE', or a custom token address string.
24840
25275
  *
24841
25276
  * @returns Zod schema validating a send parameters object.
@@ -24848,7 +25283,7 @@ const adapterContextSchema = zod.z.object({
24848
25283
  * const params = {
24849
25284
  * amount: '100.50',
24850
25285
  * from: { adapter: sourceAdapter, chain: 'Ethereum' },
24851
- * to: 'Avalanche', // or { adapter: destAdapter, chain: 'Avalanche' }
25286
+ * to: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e', // or destAdapter
24852
25287
  * token: 'USDC',
24853
25288
  * }
24854
25289
  *
@@ -24907,7 +25342,7 @@ const sendParamsSchema = zod.z.object({
24907
25342
  * The validation includes:
24908
25343
  * - Basic parameter structure and types.
24909
25344
  * - Amount validation (non-empty decimal string strictly greater than 0).
24910
- * - Recipient validation (either an address string or an adapter+chain object).
25345
+ * - Recipient validation (either an address string or an adapter instance).
24911
25346
  * - Adapter shape validation (required methods present).
24912
25347
  * - Optional config validation (when provided).
24913
25348
  *
@@ -24918,7 +25353,7 @@ const sendParamsSchema = zod.z.object({
24918
25353
  * ```typescript
24919
25354
  * // Narrow unknown input to SendParams
24920
25355
  * const input: unknown = {
24921
- * from: sourceAdapter,
25356
+ * from: { adapter: sourceAdapter, chain: 'Ethereum' },
24922
25357
  * to: '0x742d35Cc6634C0532925a3b8D1a7aDBa359cfA7',
24923
25358
  * amount: '1'
24924
25359
  * }
@@ -24937,7 +25372,7 @@ const tokens = createTokenRegistry();
24937
25372
  * Prepare a chain request to send USDC, USDT, native gas tokens, or custom ERC-20/SPL tokens.
24938
25373
  *
24939
25374
  * Validate inputs, obtain the sender address from the `from` adapter, resolve the recipient
24940
- * from `to` (explicit address string or adapter context), and normalize the human‑readable
25375
+ * from `to` (explicit address string or adapter), and normalize the human‑readable
24941
25376
  * `amount` into token units.
24942
25377
  *
24943
25378
  * For known token aliases, uses dedicated transfer actions
@@ -25048,7 +25483,7 @@ const prepareSend = async (params) => {
25048
25483
  * For custom token addresses, uses the generic token.transfer action with dynamically
25049
25484
  * fetched decimals.
25050
25485
  *
25051
- * @param params - The send parameters: source context, destination (address or adapter context),
25486
+ * @param params - The send parameters: source context, destination (address or adapter),
25052
25487
  * human-readable `amount`, and optional `token` ('USDC' | 'USDT' | 'NATIVE' or custom address, defaults to 'USDC').
25053
25488
  * @returns A BridgeStep object with transaction details including hash, status, and explorer URL.
25054
25489
  * @throws KitError INPUT_VALIDATION_FAILED if parameters are invalid.
@@ -25110,17 +25545,17 @@ const send = async (params) => {
25110
25545
  * Estimate the network fees to send USDC, USDT, or a supported native token.
25111
25546
  *
25112
25547
  * Prepare the send operation (including validating inputs and resolving the recipient when
25113
- * provided as an adapter context) and return an {@link EstimatedGas} object. This function does
25548
+ * provided as an adapter) and return an {@link EstimatedGas} object. This function does
25114
25549
  * not submit any transaction.
25115
25550
  *
25116
25551
  * @remarks
25117
25552
  * - Selects the transfer handler based on `token` ('USDC' by default, 'USDT', or 'NATIVE').
25118
- * - When `to` is an adapter context, the recipient address is derived from the adapter.
25553
+ * - When `to` is an {@link Adapter}, the recipient address is derived from the adapter.
25119
25554
  * - Rejects transfers where the resolved `to` equals the source `from` address.
25120
25555
  * - Interprets `amount` as a human-readable decimal string (USDC and USDT scaled to 6 decimals,
25121
25556
  * native EVM value typically scaled to 18 decimals).
25122
25557
  *
25123
- * @param params - The send parameters: source context, destination (address or adapter context),
25558
+ * @param params - The send parameters: source context, destination (address or adapter),
25124
25559
  * human-readable `amount`, and optional `token` ('USDC' | 'USDT' | 'NATIVE', defaults to 'USDC').
25125
25560
  * @returns The estimated gas information including `gas`, `gasPrice`, and total `fee`.
25126
25561
  * @throws Error If parameters are invalid.
@@ -25522,10 +25957,10 @@ class AppKit {
25522
25957
  *
25523
25958
  * @example
25524
25959
  * ```typescript
25525
- * // Send USDC to another adapter
25960
+ * // Send USDC to a recipient adapter (same chain)
25526
25961
  * const result = await kit.send({
25527
- * from: sourceAdapter,
25528
- * to: { adapter: destAdapter, chain: 'Polygon' },
25962
+ * from: { adapter: sourceAdapter, chain: 'Ethereum' },
25963
+ * to: recipientAdapter,
25529
25964
  * amount: '100.50',
25530
25965
  * token: 'USDC'
25531
25966
  * })
@@ -25536,7 +25971,7 @@ class AppKit {
25536
25971
  * ```typescript
25537
25972
  * // Send a custom token to an explicit address
25538
25973
  * const result = await kit.send({
25539
- * from: sourceAdapter,
25974
+ * from: { adapter: sourceAdapter, chain: 'Ethereum' },
25540
25975
  * to: '0x742d35Cc4634C0532925a3b8D1d7',
25541
25976
  * amount: '100.50',
25542
25977
  * token: '0x6B175474E89094C44Da98b954EedeAC495271d0F' // DAI on Ethereum
@@ -25548,8 +25983,8 @@ class AppKit {
25548
25983
  * ```typescript
25549
25984
  * // Send USDT to an explicit address
25550
25985
  * const result = await kit.send({
25551
- * from: sourceAdapter,
25552
- * to: { address: '0x742d35Cc4634C0532925a3b8D1d7', chain: 'Polygon' },
25986
+ * from: { adapter: sourceAdapter, chain: 'Ethereum' },
25987
+ * to: '0x742d35Cc4634C0532925a3b8D1d7',
25553
25988
  * amount: '50.25',
25554
25989
  * token: 'USDT'
25555
25990
  * })
@@ -25575,8 +26010,8 @@ class AppKit {
25575
26010
  * @example
25576
26011
  * ```typescript
25577
26012
  * const estimate = await kit.estimateSend({
25578
- * from: sourceAdapter,
25579
- * to: { adapter: destAdapter, chain: 'Polygon' },
26013
+ * from: { adapter: sourceAdapter, chain: 'Ethereum' },
26014
+ * to: recipientAdapter,
25580
26015
  * amount: '100.50',
25581
26016
  * token: 'USDC'
25582
26017
  * })
@@ -25587,8 +26022,8 @@ class AppKit {
25587
26022
  * @example
25588
26023
  * ```typescript
25589
26024
  * const estimate = await kit.estimateSend({
25590
- * from: sourceAdapter,
25591
- * to: { adapter: destAdapter, chain: 'Polygon' },
26025
+ * from: { adapter: sourceAdapter, chain: 'Ethereum' },
26026
+ * to: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
25592
26027
  * amount: '50.0',
25593
26028
  * token: 'USDT'
25594
26029
  * })