@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.mjs CHANGED
@@ -3218,6 +3218,8 @@ var Blockchain;
3218
3218
  Blockchain["Celo_Alfajores_Testnet"] = "Celo_Alfajores_Testnet";
3219
3219
  Blockchain["Codex"] = "Codex";
3220
3220
  Blockchain["Codex_Testnet"] = "Codex_Testnet";
3221
+ Blockchain["Edge"] = "Edge";
3222
+ Blockchain["Edge_Testnet"] = "Edge_Testnet";
3221
3223
  Blockchain["Ethereum"] = "Ethereum";
3222
3224
  Blockchain["Ethereum_Sepolia"] = "Ethereum_Sepolia";
3223
3225
  Blockchain["Hedera"] = "Hedera";
@@ -3230,6 +3232,8 @@ var Blockchain;
3230
3232
  Blockchain["Linea_Sepolia"] = "Linea_Sepolia";
3231
3233
  Blockchain["Monad"] = "Monad";
3232
3234
  Blockchain["Monad_Testnet"] = "Monad_Testnet";
3235
+ Blockchain["Morph"] = "Morph";
3236
+ Blockchain["Morph_Testnet"] = "Morph_Testnet";
3233
3237
  Blockchain["NEAR"] = "NEAR";
3234
3238
  Blockchain["NEAR_Testnet"] = "NEAR_Testnet";
3235
3239
  Blockchain["Noble"] = "Noble";
@@ -3433,11 +3437,13 @@ var BridgeChain;
3433
3437
  BridgeChain["Avalanche"] = "Avalanche";
3434
3438
  BridgeChain["Base"] = "Base";
3435
3439
  BridgeChain["Codex"] = "Codex";
3440
+ BridgeChain["Edge"] = "Edge";
3436
3441
  BridgeChain["Ethereum"] = "Ethereum";
3437
3442
  BridgeChain["HyperEVM"] = "HyperEVM";
3438
3443
  BridgeChain["Ink"] = "Ink";
3439
3444
  BridgeChain["Linea"] = "Linea";
3440
3445
  BridgeChain["Monad"] = "Monad";
3446
+ BridgeChain["Morph"] = "Morph";
3441
3447
  BridgeChain["Optimism"] = "Optimism";
3442
3448
  BridgeChain["Plume"] = "Plume";
3443
3449
  BridgeChain["Polygon"] = "Polygon";
@@ -3453,11 +3459,13 @@ var BridgeChain;
3453
3459
  BridgeChain["Avalanche_Fuji"] = "Avalanche_Fuji";
3454
3460
  BridgeChain["Base_Sepolia"] = "Base_Sepolia";
3455
3461
  BridgeChain["Codex_Testnet"] = "Codex_Testnet";
3462
+ BridgeChain["Edge_Testnet"] = "Edge_Testnet";
3456
3463
  BridgeChain["Ethereum_Sepolia"] = "Ethereum_Sepolia";
3457
3464
  BridgeChain["HyperEVM_Testnet"] = "HyperEVM_Testnet";
3458
3465
  BridgeChain["Ink_Testnet"] = "Ink_Testnet";
3459
3466
  BridgeChain["Linea_Sepolia"] = "Linea_Sepolia";
3460
3467
  BridgeChain["Monad_Testnet"] = "Monad_Testnet";
3468
+ BridgeChain["Morph_Testnet"] = "Morph_Testnet";
3461
3469
  BridgeChain["Optimism_Sepolia"] = "Optimism_Sepolia";
3462
3470
  BridgeChain["Plume_Testnet"] = "Plume_Testnet";
3463
3471
  BridgeChain["Polygon_Amoy_Testnet"] = "Polygon_Amoy_Testnet";
@@ -4216,7 +4224,7 @@ const Codex = defineChain({
4216
4224
  },
4217
4225
  forwarderSupported: {
4218
4226
  source: true,
4219
- destination: false,
4227
+ destination: true,
4220
4228
  },
4221
4229
  },
4222
4230
  kitContracts: {
@@ -4259,7 +4267,95 @@ const CodexTestnet = defineChain({
4259
4267
  },
4260
4268
  forwarderSupported: {
4261
4269
  source: true,
4262
- destination: false,
4270
+ destination: true,
4271
+ },
4272
+ },
4273
+ kitContracts: {
4274
+ bridge: BRIDGE_CONTRACT_EVM_TESTNET,
4275
+ },
4276
+ });
4277
+
4278
+ /**
4279
+ * Edge Mainnet chain definition
4280
+ * @remarks
4281
+ * This represents the official production network for the Edge blockchain.
4282
+ * Edge is an EVM-compatible blockchain.
4283
+ */
4284
+ const Edge = defineChain({
4285
+ type: 'evm',
4286
+ chain: Blockchain.Edge,
4287
+ name: 'Edge',
4288
+ title: 'Edge Mainnet',
4289
+ nativeCurrency: {
4290
+ name: 'Ether',
4291
+ symbol: 'ETH',
4292
+ decimals: 18,
4293
+ },
4294
+ chainId: 3343,
4295
+ isTestnet: false,
4296
+ explorerUrl: 'https://pro.edgex.exchange/en-US/explorer/tx/{hash}',
4297
+ rpcEndpoints: ['https://edge-mainnet.g.alchemy.com/public'],
4298
+ eurcAddress: null,
4299
+ usdcAddress: '0x98d2919b9A214E6Fa5384AC81E6864bA686Ad74c',
4300
+ usdtAddress: null,
4301
+ cctp: {
4302
+ domain: 28,
4303
+ contracts: {
4304
+ v2: {
4305
+ type: 'split',
4306
+ tokenMessenger: '0x98706A006bc632Df31CAdFCBD43F38887ce2ca5c',
4307
+ messageTransmitter: '0x5b61381Fc9e58E70EfC13a4A97516997019198ee',
4308
+ confirmations: 65,
4309
+ fastConfirmations: 1,
4310
+ },
4311
+ },
4312
+ forwarderSupported: {
4313
+ source: true,
4314
+ destination: true,
4315
+ },
4316
+ },
4317
+ kitContracts: {
4318
+ bridge: '0x6D1AaE1c34Aeb582022916a67f2A655C6f4eDFF2', //Unique bridge address as CCTP address for Edge is also unique
4319
+ },
4320
+ });
4321
+
4322
+ /**
4323
+ * Edge Testnet chain definition
4324
+ * @remarks
4325
+ * This represents the official test network for the Edge blockchain.
4326
+ * Edge is an EVM-compatible blockchain.
4327
+ */
4328
+ const EdgeTestnet = defineChain({
4329
+ type: 'evm',
4330
+ chain: Blockchain.Edge_Testnet,
4331
+ name: 'Edge Testnet',
4332
+ title: 'Edge Testnet',
4333
+ nativeCurrency: {
4334
+ name: 'Ether',
4335
+ symbol: 'ETH',
4336
+ decimals: 18,
4337
+ },
4338
+ chainId: 33431,
4339
+ isTestnet: true,
4340
+ explorerUrl: 'https://edge-testnet.explorer.alchemy.com/tx/{hash}',
4341
+ rpcEndpoints: ['https://edge-testnet.g.alchemy.com/public'],
4342
+ eurcAddress: null,
4343
+ usdcAddress: '0x2d9F7CAD728051AA35Ecdc472a14cf8cDF5CFD6B',
4344
+ usdtAddress: null,
4345
+ cctp: {
4346
+ domain: 28,
4347
+ contracts: {
4348
+ v2: {
4349
+ type: 'split',
4350
+ tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
4351
+ messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
4352
+ confirmations: 65,
4353
+ fastConfirmations: 1,
4354
+ },
4355
+ },
4356
+ forwarderSupported: {
4357
+ source: true,
4358
+ destination: true,
4263
4359
  },
4264
4360
  },
4265
4361
  kitContracts: {
@@ -4433,7 +4529,7 @@ const HyperEVM = defineChain({
4433
4529
  },
4434
4530
  chainId: 999,
4435
4531
  isTestnet: false,
4436
- explorerUrl: 'https://hyperevmscan.io/tx/{hash}',
4532
+ explorerUrl: 'https://app.hyperliquid.xyz/explorer/tx/{hash}',
4437
4533
  rpcEndpoints: ['https://rpc.hyperliquid.xyz/evm'],
4438
4534
  eurcAddress: null,
4439
4535
  usdcAddress: '0xb88339CB7199b77E23DB6E890353E22632Ba630f',
@@ -4478,7 +4574,7 @@ const HyperEVMTestnet = defineChain({
4478
4574
  },
4479
4575
  chainId: 998,
4480
4576
  isTestnet: true,
4481
- explorerUrl: 'https://testnet.hyperliquid.xyz/explorer/tx/{hash}',
4577
+ explorerUrl: 'https://app.hyperliquid-testnet.xyz/explorer/tx/{hash}',
4482
4578
  rpcEndpoints: ['https://rpc.hyperliquid-testnet.xyz/evm'],
4483
4579
  eurcAddress: null,
4484
4580
  usdcAddress: '0x2B3370eE501B4a559b57D449569354196457D8Ab',
@@ -4778,6 +4874,94 @@ const MonadTestnet = defineChain({
4778
4874
  },
4779
4875
  });
4780
4876
 
4877
+ /**
4878
+ * Morph Mainnet chain definition
4879
+ * @remarks
4880
+ * This represents the official production network for the Morph blockchain.
4881
+ * Morph is an EVM-compatible Layer-2 blockchain built on the OP Stack.
4882
+ */
4883
+ const Morph = defineChain({
4884
+ type: 'evm',
4885
+ chain: Blockchain.Morph,
4886
+ name: 'Morph',
4887
+ title: 'Morph Mainnet',
4888
+ nativeCurrency: {
4889
+ name: 'Ether',
4890
+ symbol: 'ETH',
4891
+ decimals: 18,
4892
+ },
4893
+ chainId: 2818,
4894
+ isTestnet: false,
4895
+ explorerUrl: 'https://explorer.morph.network/tx/{hash}',
4896
+ rpcEndpoints: ['https://rpc.morphl2.io'],
4897
+ eurcAddress: null,
4898
+ usdcAddress: '0xCfb1186F4e93D60E60a8bDd997427D1F33bc372B',
4899
+ usdtAddress: null,
4900
+ cctp: {
4901
+ domain: 30,
4902
+ contracts: {
4903
+ v2: {
4904
+ type: 'split',
4905
+ tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
4906
+ messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
4907
+ confirmations: 64,
4908
+ fastConfirmations: 1,
4909
+ },
4910
+ },
4911
+ forwarderSupported: {
4912
+ source: false,
4913
+ destination: false,
4914
+ },
4915
+ },
4916
+ kitContracts: {
4917
+ bridge: BRIDGE_CONTRACT_EVM_MAINNET,
4918
+ },
4919
+ });
4920
+
4921
+ /**
4922
+ * Morph Hoodi Testnet chain definition
4923
+ * @remarks
4924
+ * This represents the official test network for the Morph blockchain.
4925
+ * Morph is an EVM-compatible Layer-2 blockchain built on the OP Stack.
4926
+ */
4927
+ const MorphTestnet = defineChain({
4928
+ type: 'evm',
4929
+ chain: Blockchain.Morph_Testnet,
4930
+ name: 'Morph Hoodi',
4931
+ title: 'Morph Hoodi Testnet',
4932
+ nativeCurrency: {
4933
+ name: 'Ether',
4934
+ symbol: 'ETH',
4935
+ decimals: 18,
4936
+ },
4937
+ chainId: 2910,
4938
+ isTestnet: true,
4939
+ explorerUrl: 'https://explorer-hoodi.morphl2.io/tx/{hash}',
4940
+ rpcEndpoints: ['https://rpc-hoodi.morphl2.io'],
4941
+ eurcAddress: null,
4942
+ usdcAddress: '0x7433b41C6c5e1d58D4Da99483609520255ab661B',
4943
+ usdtAddress: null,
4944
+ cctp: {
4945
+ domain: 30,
4946
+ contracts: {
4947
+ v2: {
4948
+ type: 'split',
4949
+ tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
4950
+ messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
4951
+ confirmations: 64,
4952
+ fastConfirmations: 1,
4953
+ },
4954
+ },
4955
+ forwarderSupported: {
4956
+ source: false,
4957
+ destination: false,
4958
+ },
4959
+ },
4960
+ kitContracts: {
4961
+ bridge: BRIDGE_CONTRACT_EVM_TESTNET,
4962
+ },
4963
+ });
4964
+
4781
4965
  /**
4782
4966
  * NEAR Protocol Mainnet chain definition
4783
4967
  * @remarks
@@ -5036,7 +5220,7 @@ const Plume = defineChain({
5036
5220
  },
5037
5221
  forwarderSupported: {
5038
5222
  source: true,
5039
- destination: false,
5223
+ destination: true,
5040
5224
  },
5041
5225
  },
5042
5226
  kitContracts: {
@@ -5081,7 +5265,7 @@ const PlumeTestnet = defineChain({
5081
5265
  },
5082
5266
  forwarderSupported: {
5083
5267
  source: true,
5084
- destination: false,
5268
+ destination: true,
5085
5269
  },
5086
5270
  },
5087
5271
  kitContracts: {
@@ -5859,7 +6043,7 @@ const XDC = defineChain({
5859
6043
  },
5860
6044
  forwarderSupported: {
5861
6045
  source: true,
5862
- destination: false,
6046
+ destination: true,
5863
6047
  },
5864
6048
  },
5865
6049
  kitContracts: {
@@ -5903,7 +6087,7 @@ const XDCApothem = defineChain({
5903
6087
  },
5904
6088
  forwarderSupported: {
5905
6089
  source: true,
5906
- destination: false,
6090
+ destination: true,
5907
6091
  },
5908
6092
  },
5909
6093
  kitContracts: {
@@ -5978,6 +6162,8 @@ var Chains = /*#__PURE__*/Object.freeze({
5978
6162
  CeloAlfajoresTestnet: CeloAlfajoresTestnet,
5979
6163
  Codex: Codex,
5980
6164
  CodexTestnet: CodexTestnet,
6165
+ Edge: Edge,
6166
+ EdgeTestnet: EdgeTestnet,
5981
6167
  Ethereum: Ethereum,
5982
6168
  EthereumSepolia: EthereumSepolia,
5983
6169
  Hedera: Hedera,
@@ -5990,6 +6176,8 @@ var Chains = /*#__PURE__*/Object.freeze({
5990
6176
  LineaSepolia: LineaSepolia,
5991
6177
  Monad: Monad,
5992
6178
  MonadTestnet: MonadTestnet,
6179
+ Morph: Morph,
6180
+ MorphTestnet: MorphTestnet,
5993
6181
  NEAR: NEAR,
5994
6182
  NEARTestnet: NEARTestnet,
5995
6183
  Noble: Noble,
@@ -7986,12 +8174,14 @@ const USDC = {
7986
8174
  [Blockchain.Base]: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
7987
8175
  [Blockchain.Celo]: '0xcebA9300f2b948710d2653dD7B07f33A8B32118C',
7988
8176
  [Blockchain.Codex]: '0xd996633a415985DBd7D6D12f4A4343E31f5037cf',
8177
+ [Blockchain.Edge]: '0x98d2919b9A214E6Fa5384AC81E6864bA686Ad74c',
7989
8178
  [Blockchain.Ethereum]: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
7990
8179
  [Blockchain.Hedera]: '0.0.456858',
7991
8180
  [Blockchain.HyperEVM]: '0xb88339CB7199b77E23DB6E890353E22632Ba630f',
7992
8181
  [Blockchain.Ink]: '0x2D270e6886d130D724215A266106e6832161EAEd',
7993
8182
  [Blockchain.Linea]: '0x176211869ca2b568f2a7d4ee941e073a821ee1ff',
7994
8183
  [Blockchain.Monad]: '0x754704Bc059F8C67012fEd69BC8A327a5aafb603',
8184
+ [Blockchain.Morph]: '0xCfb1186F4e93D60E60a8bDd997427D1F33bc372B',
7995
8185
  [Blockchain.NEAR]: '17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1',
7996
8186
  [Blockchain.Noble]: 'uusdc',
7997
8187
  [Blockchain.Optimism]: '0x0b2c639c533813f4aa9d7837caf62653d097ff85',
@@ -8014,12 +8204,14 @@ const USDC = {
8014
8204
  [Blockchain.Avalanche_Fuji]: '0x5425890298aed601595a70AB815c96711a31Bc65',
8015
8205
  [Blockchain.Base_Sepolia]: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',
8016
8206
  [Blockchain.Codex_Testnet]: '0x6d7f141b6819C2c9CC2f818e6ad549E7Ca090F8f',
8207
+ [Blockchain.Edge_Testnet]: '0x2d9F7CAD728051AA35Ecdc472a14cf8cDF5CFD6B',
8017
8208
  [Blockchain.Ethereum_Sepolia]: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',
8018
8209
  [Blockchain.Hedera_Testnet]: '0.0.429274',
8019
8210
  [Blockchain.HyperEVM_Testnet]: '0x2B3370eE501B4a559b57D449569354196457D8Ab',
8020
8211
  [Blockchain.Ink_Testnet]: '0xFabab97dCE620294D2B0b0e46C68964e326300Ac',
8021
8212
  [Blockchain.Linea_Sepolia]: '0xfece4462d57bd51a6a552365a011b95f0e16d9b7',
8022
8213
  [Blockchain.Monad_Testnet]: '0x534b2f3A21130d7a60830c2Df862319e593943A3',
8214
+ [Blockchain.Morph_Testnet]: '0x7433b41C6c5e1d58D4Da99483609520255ab661B',
8023
8215
  [Blockchain.NEAR_Testnet]: '3e2210e1184b45b64c8a434c0a7e7b23cc04ea7eb7a6c3c32520d03d4afcb8af',
8024
8216
  [Blockchain.Noble_Testnet]: 'uusdc',
8025
8217
  [Blockchain.Optimism_Sepolia]: '0x5fd84259d66Cd46123540766Be93DFE6D43130D7',
@@ -9008,7 +9200,7 @@ function buildForwardingHookData() {
9008
9200
  }
9009
9201
 
9010
9202
  var name$1 = "@circle-fin/bridge-kit";
9011
- var version$2 = "1.6.1";
9203
+ var version$2 = "1.8.0";
9012
9204
  var pkg$2 = {
9013
9205
  name: name$1,
9014
9206
  version: version$2};
@@ -13098,7 +13290,184 @@ function dispatchStepEvent(name, step, provider, invocation) {
13098
13290
  }
13099
13291
  }
13100
13292
 
13101
- var version$1 = "1.4.1";
13293
+ /**
13294
+ * Check whether the source adapter supports EIP-5792 atomic batching and
13295
+ * the consumer has not explicitly opted out via `config.batchTransactions`.
13296
+ *
13297
+ * @param params - Bridge parameters (used for adapter and config access).
13298
+ * @returns `true` when batched execution should be attempted.
13299
+ *
13300
+ * @example
13301
+ * ```typescript
13302
+ * const useBatched = await shouldUseBatchedExecution(params)
13303
+ * if (useBatched) {
13304
+ * // take the batched approve + burn path
13305
+ * }
13306
+ * ```
13307
+ */
13308
+ async function shouldUseBatchedExecution(params) {
13309
+ if (params.config?.batchTransactions === false) {
13310
+ return false;
13311
+ }
13312
+ const { chain } = params.source;
13313
+ if (chain.type !== 'evm') {
13314
+ return false;
13315
+ }
13316
+ const adapter = params.source
13317
+ .adapter;
13318
+ if (typeof adapter.supportsAtomicBatch !== 'function' ||
13319
+ typeof adapter.batchExecute !== 'function') {
13320
+ return false;
13321
+ }
13322
+ try {
13323
+ return await adapter.supportsAtomicBatch(chain);
13324
+ }
13325
+ catch {
13326
+ return false;
13327
+ }
13328
+ }
13329
+ /**
13330
+ * Execute the approve and burn steps as a single EIP-5792 batched call.
13331
+ *
13332
+ * Prepare both `PreparedChainRequest` objects upfront, extract their raw
13333
+ * call data via `getCallData()`, submit both via `adapter.batchExecute()`,
13334
+ * then map the individual receipts back to standard {@link BridgeStep}
13335
+ * objects so downstream consumers (event callbacks, result tracking) are
13336
+ * unaffected.
13337
+ *
13338
+ * @param params - The CCTP v2 bridge parameters.
13339
+ * @param provider - The CCTP v2 bridging provider.
13340
+ * @returns Approve and burn steps with a shared context containing the burn tx hash.
13341
+ * @throws {@link KitError} when the source chain is not EVM.
13342
+ * @throws {@link KitError} when calldata extraction (`getCallData`) is not supported
13343
+ * by the prepared requests.
13344
+ * @remarks
13345
+ * Errors that occur after the batch has been submitted to the wallet
13346
+ * (e.g. polling timeout, insufficient receipts) are **not thrown** — they
13347
+ * are captured as `state: 'error'` on the returned steps to prevent
13348
+ * accidental double-spend on retry.
13349
+ *
13350
+ * @example
13351
+ * ```typescript
13352
+ * const { approveStep, burnStep, context } = await executeBatchedApproveAndBurn(
13353
+ * params,
13354
+ * provider,
13355
+ * )
13356
+ * result.steps.push(approveStep, burnStep)
13357
+ * ```
13358
+ */
13359
+ async function executeBatchedApproveAndBurn(params, provider) {
13360
+ // Double-unknown cast: Adapter<TFrom> has no structural overlap with
13361
+ // BatchCapableAdapter (a duck-typed interface for EIP-5792 methods).
13362
+ // A direct cast fails because TS cannot prove the intersection; the
13363
+ // runtime capability check below guards against unsupported adapters.
13364
+ const adapter = params.source.adapter;
13365
+ const sourceChain = params.source.chain;
13366
+ if (sourceChain.type !== 'evm') {
13367
+ throw new KitError({
13368
+ ...InputError.INVALID_CHAIN,
13369
+ recoverability: 'FATAL',
13370
+ message: 'Batched execution is only supported on EVM chains.',
13371
+ });
13372
+ }
13373
+ const chain = sourceChain;
13374
+ // customFee.value is in base units (integer string) at this point.
13375
+ const customFee = BigInt(params.config?.customFee?.value ?? '0');
13376
+ const amountBigInt = BigInt(params.amount);
13377
+ const approvalAmount = (amountBigInt + customFee).toString();
13378
+ const [approveRequest, burnRequest] = await Promise.all([
13379
+ provider.approve(params.source, approvalAmount),
13380
+ provider.burn(params),
13381
+ ]);
13382
+ if (approveRequest.type !== 'evm' ||
13383
+ burnRequest.type !== 'evm' ||
13384
+ !approveRequest.getCallData ||
13385
+ !burnRequest.getCallData) {
13386
+ throw new KitError({
13387
+ ...InputError.UNSUPPORTED_ACTION,
13388
+ recoverability: 'FATAL',
13389
+ message: 'Batched execution requires EVM prepared requests with getCallData() support.',
13390
+ });
13391
+ }
13392
+ const approveCallData = approveRequest.getCallData();
13393
+ const burnCallData = burnRequest.getCallData();
13394
+ // batchExecute may throw before submission (wallet declined) but never
13395
+ // after — post-submission errors are returned as empty receipts.
13396
+ const batchResult = await adapter.batchExecute([approveCallData, burnCallData], chain);
13397
+ const approveReceipt = batchResult.receipts[0];
13398
+ const burnReceipt = batchResult.receipts[1];
13399
+ const approveStep = await buildBatchedStep('approve', approveReceipt, batchResult.batchId, adapter, chain);
13400
+ const burnStep = await buildBatchedStep('burn', burnReceipt, batchResult.batchId, adapter, chain);
13401
+ if (burnStep.state !== 'error' && !burnStep.txHash) {
13402
+ burnStep.state = 'error';
13403
+ burnStep.errorMessage =
13404
+ 'Batched burn step completed but no transaction hash was returned.';
13405
+ }
13406
+ const context = { burnTxHash: burnStep.txHash ?? '' };
13407
+ return { approveStep, burnStep, context };
13408
+ }
13409
+ /**
13410
+ * Build a {@link BridgeStep} from a single receipt within a batch.
13411
+ *
13412
+ * Map the raw receipt from `batchExecute` into a standard `BridgeStep`,
13413
+ * waiting for on-chain confirmation via `adapter.waitForTransaction`.
13414
+ * All errors are captured on the step (never thrown) so the caller
13415
+ * can inspect each step independently.
13416
+ *
13417
+ * @param name - Human-readable step name (e.g. `'approve'`, `'burn'`).
13418
+ * @param receipt - Per-call receipt from `batchExecute`, or `undefined`
13419
+ * when the wallet returned fewer receipts than submitted calls.
13420
+ * @param batchId - Wallet-assigned batch identifier.
13421
+ * @param adapter - The batch-capable adapter (used for confirmation).
13422
+ * @param chain - The EVM chain the batch was executed on.
13423
+ * @returns A fully-populated bridge step with state, tx hash and explorer URL.
13424
+ *
13425
+ * @internal
13426
+ */
13427
+ async function buildBatchedStep(name, receipt, batchId, adapter, chain) {
13428
+ const step = {
13429
+ name,
13430
+ state: 'pending',
13431
+ batched: true,
13432
+ batchId,
13433
+ };
13434
+ if (!receipt) {
13435
+ step.state = 'error';
13436
+ step.errorMessage = `No receipt returned for ${name} in batch ${batchId}.`;
13437
+ return step;
13438
+ }
13439
+ step.txHash = receipt.txHash;
13440
+ if (receipt.txHash) {
13441
+ step.explorerUrl = buildExplorerUrl(chain, receipt.txHash);
13442
+ }
13443
+ if (receipt.status !== 'success') {
13444
+ step.state = 'error';
13445
+ step.errorMessage = `${name} call failed within batch ${batchId}.`;
13446
+ return step;
13447
+ }
13448
+ if (!receipt.txHash) {
13449
+ step.state = 'error';
13450
+ step.errorMessage = `${name} succeeded in batch but returned an empty transaction hash.`;
13451
+ return step;
13452
+ }
13453
+ try {
13454
+ const transaction = await adapter.waitForTransaction(receipt.txHash, { confirmations: 1 }, chain);
13455
+ step.state = transaction.blockNumber === undefined ? 'error' : 'success';
13456
+ step.data = transaction;
13457
+ if (transaction.blockNumber === undefined) {
13458
+ step.errorMessage = 'Transaction was not confirmed on-chain.';
13459
+ }
13460
+ }
13461
+ catch (err) {
13462
+ step.state = 'error';
13463
+ step.error = err;
13464
+ step.errorMessage =
13465
+ err instanceof Error ? err.message : 'Unknown error during confirmation.';
13466
+ }
13467
+ return step;
13468
+ }
13469
+
13470
+ var version$1 = "1.6.0";
13102
13471
  var pkg$1 = {
13103
13472
  version: version$1};
13104
13473
 
@@ -13127,6 +13496,67 @@ function resolveBridgeInvocation(invocationMeta) {
13127
13496
  };
13128
13497
  return extendInvocationContext(resolveInvocationContext(invocationMeta, defaults), BRIDGE_CALLER);
13129
13498
  }
13499
+ /**
13500
+ * Execute the batched approve + burn path via EIP-5792.
13501
+ *
13502
+ * Mutate `result` with step data and error state as needed. Return the
13503
+ * batch context on success, or `undefined` when the batch failed (in
13504
+ * which case `result.state` is set to `'error'`).
13505
+ *
13506
+ * @internal
13507
+ * @param params - Bridge parameters (read-only).
13508
+ * @param provider - The CCTP v2 bridging provider (read-only).
13509
+ * @param result - Bridge result object — **mutated in place** with step
13510
+ * data and, on failure, `state: 'error'` plus an `error` payload.
13511
+ * @param invocation - Invocation context for telemetry (read-only).
13512
+ * @returns The step context on success, or `undefined` when the batch failed.
13513
+ */
13514
+ async function executeBatchedPath(params, provider, result, invocation) {
13515
+ // IMPORTANT: once executeBatchedApproveAndBurn is called, we NEVER
13516
+ // fall back to sequential. The wallet may have already signed &
13517
+ // submitted the batch; retrying as individual txs would double-spend.
13518
+ try {
13519
+ const { approveStep, burnStep, context: batchContext, } = await executeBatchedApproveAndBurn(params, provider);
13520
+ for (const step of [approveStep, burnStep]) {
13521
+ const stepName = step.name;
13522
+ if (step.state === 'error') {
13523
+ ensureStepErrorMessage(step.name, step);
13524
+ result.steps.push(step);
13525
+ result.state = 'error';
13526
+ dispatchStepEvent(stepName, step, provider, invocation);
13527
+ return undefined;
13528
+ }
13529
+ dispatchStepEvent(stepName, step, provider, invocation);
13530
+ result.steps.push(step);
13531
+ }
13532
+ return batchContext;
13533
+ }
13534
+ catch (error_) {
13535
+ // Only handles pre-submission failures (prepare rejected, wallet
13536
+ // declined, etc.). batchExecute never throws after sendCalls succeeds.
13537
+ result.state = 'error';
13538
+ result.steps.push({
13539
+ name: 'batch',
13540
+ state: 'error',
13541
+ batched: true,
13542
+ error: error_,
13543
+ errorMessage: error_ instanceof Error
13544
+ ? error_.message
13545
+ : 'Batched approve + burn failed.',
13546
+ });
13547
+ return undefined;
13548
+ }
13549
+ }
13550
+ /**
13551
+ * Ensure `step.errorMessage` is populated when an error object exists.
13552
+ *
13553
+ * @internal
13554
+ */
13555
+ function ensureStepErrorMessage(name, step) {
13556
+ if (!step.errorMessage && step.error) {
13557
+ step.errorMessage = `${name} step failed: ${getErrorMessage(step.error)}`;
13558
+ }
13559
+ }
13130
13560
  /**
13131
13561
  * Execute a cross-chain USDC bridge using the CCTP v2 protocol.
13132
13562
  *
@@ -13160,9 +13590,7 @@ function resolveBridgeInvocation(invocationMeta) {
13160
13590
  * ```
13161
13591
  */
13162
13592
  async function bridge$1(params, provider) {
13163
- // Check if forwarder is enabled (on destination)
13164
13593
  const useForwarder = params.destination.useForwarder === true;
13165
- // Resolve invocation metadata to full context for event dispatching
13166
13594
  const invocation = resolveBridgeInvocation(params.invocationMeta);
13167
13595
  const result = {
13168
13596
  state: 'pending',
@@ -13175,11 +13603,9 @@ async function bridge$1(params, provider) {
13175
13603
  destination: {
13176
13604
  address: params.destination.address,
13177
13605
  chain: params.destination.chain,
13178
- // Preserve recipientAddress
13179
13606
  ...(params.destination.recipientAddress && {
13180
13607
  recipientAddress: params.destination.recipientAddress,
13181
13608
  }),
13182
- // Preserve useForwarder
13183
13609
  ...(useForwarder && {
13184
13610
  useForwarder: true,
13185
13611
  }),
@@ -13188,29 +13614,38 @@ async function bridge$1(params, provider) {
13188
13614
  config: params.config,
13189
13615
  provider: provider.name,
13190
13616
  };
13191
- // Context shared between steps
13192
13617
  let context = undefined;
13193
- // Create step executors based on useForwarder config
13618
+ let useBatched = false;
13619
+ try {
13620
+ useBatched = await shouldUseBatchedExecution(params);
13621
+ }
13622
+ catch {
13623
+ // Silently fall back to sequential
13624
+ }
13194
13625
  const executors = createStepExecutors(useForwarder);
13195
- // Execute each step in sequence
13196
- for (const { name, executor, updateContext } of executors) {
13626
+ if (useBatched) {
13627
+ const batchContext = await executeBatchedPath(params, provider, result, invocation);
13628
+ if (result.state === 'error') {
13629
+ return result;
13630
+ }
13631
+ context = batchContext;
13632
+ }
13633
+ const stepsToRun = useBatched
13634
+ ? executors.filter(({ name }) => name !== 'approve' && name !== 'burn')
13635
+ : executors;
13636
+ for (const { name, executor, updateContext } of stepsToRun) {
13197
13637
  try {
13198
13638
  const step = await executor(params, provider, context);
13199
13639
  if (step.state === 'error') {
13200
- // Ensure errorMessage is set with proper formatting if not already present
13201
- if (!step.errorMessage && step.error) {
13202
- step.errorMessage = `${name} step failed: ${getErrorMessage(step.error)}`;
13203
- }
13640
+ ensureStepErrorMessage(name, step);
13204
13641
  result.steps.push(step);
13205
13642
  result.state = 'error';
13206
- // Dispatch event even for error steps
13207
13643
  dispatchStepEvent(name, step, provider, invocation);
13208
13644
  return result;
13209
13645
  }
13210
- // Merge new context with existing context to preserve data from previous steps
13211
13646
  const newContext = updateContext?.(step);
13212
13647
  if (newContext) {
13213
- context = { ...(context ?? {}), ...newContext };
13648
+ context = { ...context, ...newContext };
13214
13649
  }
13215
13650
  dispatchStepEvent(name, step, provider, invocation);
13216
13651
  result.steps.push(step);
@@ -15842,7 +16277,7 @@ const createBridgeKit = (context) => {
15842
16277
  };
15843
16278
 
15844
16279
  var name = "@circle-fin/swap-kit";
15845
- var version = "1.0.0";
16280
+ var version = "1.0.2";
15846
16281
  var pkg = {
15847
16282
  name: name,
15848
16283
  version: version};
@@ -24827,8 +25262,8 @@ const adapterContextSchema = z.object({
24827
25262
  * Schema for validating send parameters.
24828
25263
  * Ensure required fields are present and properly typed. Parameters must include:
24829
25264
  * - A valid `amount` (non-empty numeric string \> 0; supports "," or "." decimal separators and thousands separators).
24830
- * - A valid `from` context (an adapter or full adapter context).
24831
- * - A valid `to` context (an adapter or a destination chain identifier string).
25265
+ * - A valid `from` context (an adapter context with `adapter` and `chain`).
25266
+ * - A valid `to` destination (an adapter instance or a wallet address string).
24832
25267
  * - An optional `token` selection: 'USDC' (default), 'USDT', 'NATIVE', or a custom token address string.
24833
25268
  *
24834
25269
  * @returns Zod schema validating a send parameters object.
@@ -24841,7 +25276,7 @@ const adapterContextSchema = z.object({
24841
25276
  * const params = {
24842
25277
  * amount: '100.50',
24843
25278
  * from: { adapter: sourceAdapter, chain: 'Ethereum' },
24844
- * to: 'Avalanche', // or { adapter: destAdapter, chain: 'Avalanche' }
25279
+ * to: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e', // or destAdapter
24845
25280
  * token: 'USDC',
24846
25281
  * }
24847
25282
  *
@@ -24900,7 +25335,7 @@ const sendParamsSchema = z.object({
24900
25335
  * The validation includes:
24901
25336
  * - Basic parameter structure and types.
24902
25337
  * - Amount validation (non-empty decimal string strictly greater than 0).
24903
- * - Recipient validation (either an address string or an adapter+chain object).
25338
+ * - Recipient validation (either an address string or an adapter instance).
24904
25339
  * - Adapter shape validation (required methods present).
24905
25340
  * - Optional config validation (when provided).
24906
25341
  *
@@ -24911,7 +25346,7 @@ const sendParamsSchema = z.object({
24911
25346
  * ```typescript
24912
25347
  * // Narrow unknown input to SendParams
24913
25348
  * const input: unknown = {
24914
- * from: sourceAdapter,
25349
+ * from: { adapter: sourceAdapter, chain: 'Ethereum' },
24915
25350
  * to: '0x742d35Cc6634C0532925a3b8D1a7aDBa359cfA7',
24916
25351
  * amount: '1'
24917
25352
  * }
@@ -24930,7 +25365,7 @@ const tokens = createTokenRegistry();
24930
25365
  * Prepare a chain request to send USDC, USDT, native gas tokens, or custom ERC-20/SPL tokens.
24931
25366
  *
24932
25367
  * Validate inputs, obtain the sender address from the `from` adapter, resolve the recipient
24933
- * from `to` (explicit address string or adapter context), and normalize the human‑readable
25368
+ * from `to` (explicit address string or adapter), and normalize the human‑readable
24934
25369
  * `amount` into token units.
24935
25370
  *
24936
25371
  * For known token aliases, uses dedicated transfer actions
@@ -25041,7 +25476,7 @@ const prepareSend = async (params) => {
25041
25476
  * For custom token addresses, uses the generic token.transfer action with dynamically
25042
25477
  * fetched decimals.
25043
25478
  *
25044
- * @param params - The send parameters: source context, destination (address or adapter context),
25479
+ * @param params - The send parameters: source context, destination (address or adapter),
25045
25480
  * human-readable `amount`, and optional `token` ('USDC' | 'USDT' | 'NATIVE' or custom address, defaults to 'USDC').
25046
25481
  * @returns A BridgeStep object with transaction details including hash, status, and explorer URL.
25047
25482
  * @throws KitError INPUT_VALIDATION_FAILED if parameters are invalid.
@@ -25103,17 +25538,17 @@ const send = async (params) => {
25103
25538
  * Estimate the network fees to send USDC, USDT, or a supported native token.
25104
25539
  *
25105
25540
  * Prepare the send operation (including validating inputs and resolving the recipient when
25106
- * provided as an adapter context) and return an {@link EstimatedGas} object. This function does
25541
+ * provided as an adapter) and return an {@link EstimatedGas} object. This function does
25107
25542
  * not submit any transaction.
25108
25543
  *
25109
25544
  * @remarks
25110
25545
  * - Selects the transfer handler based on `token` ('USDC' by default, 'USDT', or 'NATIVE').
25111
- * - When `to` is an adapter context, the recipient address is derived from the adapter.
25546
+ * - When `to` is an {@link Adapter}, the recipient address is derived from the adapter.
25112
25547
  * - Rejects transfers where the resolved `to` equals the source `from` address.
25113
25548
  * - Interprets `amount` as a human-readable decimal string (USDC and USDT scaled to 6 decimals,
25114
25549
  * native EVM value typically scaled to 18 decimals).
25115
25550
  *
25116
- * @param params - The send parameters: source context, destination (address or adapter context),
25551
+ * @param params - The send parameters: source context, destination (address or adapter),
25117
25552
  * human-readable `amount`, and optional `token` ('USDC' | 'USDT' | 'NATIVE', defaults to 'USDC').
25118
25553
  * @returns The estimated gas information including `gas`, `gasPrice`, and total `fee`.
25119
25554
  * @throws Error If parameters are invalid.
@@ -25515,10 +25950,10 @@ class AppKit {
25515
25950
  *
25516
25951
  * @example
25517
25952
  * ```typescript
25518
- * // Send USDC to another adapter
25953
+ * // Send USDC to a recipient adapter (same chain)
25519
25954
  * const result = await kit.send({
25520
- * from: sourceAdapter,
25521
- * to: { adapter: destAdapter, chain: 'Polygon' },
25955
+ * from: { adapter: sourceAdapter, chain: 'Ethereum' },
25956
+ * to: recipientAdapter,
25522
25957
  * amount: '100.50',
25523
25958
  * token: 'USDC'
25524
25959
  * })
@@ -25529,7 +25964,7 @@ class AppKit {
25529
25964
  * ```typescript
25530
25965
  * // Send a custom token to an explicit address
25531
25966
  * const result = await kit.send({
25532
- * from: sourceAdapter,
25967
+ * from: { adapter: sourceAdapter, chain: 'Ethereum' },
25533
25968
  * to: '0x742d35Cc4634C0532925a3b8D1d7',
25534
25969
  * amount: '100.50',
25535
25970
  * token: '0x6B175474E89094C44Da98b954EedeAC495271d0F' // DAI on Ethereum
@@ -25541,8 +25976,8 @@ class AppKit {
25541
25976
  * ```typescript
25542
25977
  * // Send USDT to an explicit address
25543
25978
  * const result = await kit.send({
25544
- * from: sourceAdapter,
25545
- * to: { address: '0x742d35Cc4634C0532925a3b8D1d7', chain: 'Polygon' },
25979
+ * from: { adapter: sourceAdapter, chain: 'Ethereum' },
25980
+ * to: '0x742d35Cc4634C0532925a3b8D1d7',
25546
25981
  * amount: '50.25',
25547
25982
  * token: 'USDT'
25548
25983
  * })
@@ -25568,8 +26003,8 @@ class AppKit {
25568
26003
  * @example
25569
26004
  * ```typescript
25570
26005
  * const estimate = await kit.estimateSend({
25571
- * from: sourceAdapter,
25572
- * to: { adapter: destAdapter, chain: 'Polygon' },
26006
+ * from: { adapter: sourceAdapter, chain: 'Ethereum' },
26007
+ * to: recipientAdapter,
25573
26008
  * amount: '100.50',
25574
26009
  * token: 'USDC'
25575
26010
  * })
@@ -25580,8 +26015,8 @@ class AppKit {
25580
26015
  * @example
25581
26016
  * ```typescript
25582
26017
  * const estimate = await kit.estimateSend({
25583
- * from: sourceAdapter,
25584
- * to: { adapter: destAdapter, chain: 'Polygon' },
26018
+ * from: { adapter: sourceAdapter, chain: 'Ethereum' },
26019
+ * to: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
25585
26020
  * amount: '50.0',
25586
26021
  * token: 'USDT'
25587
26022
  * })