@circle-fin/app-kit 1.4.1 → 1.4.2

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
@@ -3419,6 +3419,8 @@ exports.Blockchain = void 0;
3419
3419
  Blockchain["Noble_Testnet"] = "Noble_Testnet";
3420
3420
  Blockchain["Optimism"] = "Optimism";
3421
3421
  Blockchain["Optimism_Sepolia"] = "Optimism_Sepolia";
3422
+ Blockchain["Pharos"] = "Pharos";
3423
+ Blockchain["Pharos_Testnet"] = "Pharos_Testnet";
3422
3424
  Blockchain["Polkadot_Asset_Hub"] = "Polkadot_Asset_Hub";
3423
3425
  Blockchain["Polkadot_Westmint"] = "Polkadot_Westmint";
3424
3426
  Blockchain["Plume"] = "Plume";
@@ -3627,6 +3629,7 @@ exports.BridgeChain = void 0;
3627
3629
  BridgeChain["Monad"] = "Monad";
3628
3630
  BridgeChain["Morph"] = "Morph";
3629
3631
  BridgeChain["Optimism"] = "Optimism";
3632
+ BridgeChain["Pharos"] = "Pharos";
3630
3633
  BridgeChain["Plume"] = "Plume";
3631
3634
  BridgeChain["Polygon"] = "Polygon";
3632
3635
  BridgeChain["Sei"] = "Sei";
@@ -3649,6 +3652,7 @@ exports.BridgeChain = void 0;
3649
3652
  BridgeChain["Monad_Testnet"] = "Monad_Testnet";
3650
3653
  BridgeChain["Morph_Testnet"] = "Morph_Testnet";
3651
3654
  BridgeChain["Optimism_Sepolia"] = "Optimism_Sepolia";
3655
+ BridgeChain["Pharos_Testnet"] = "Pharos_Testnet";
3652
3656
  BridgeChain["Plume_Testnet"] = "Plume_Testnet";
3653
3657
  BridgeChain["Polygon_Amoy_Testnet"] = "Polygon_Amoy_Testnet";
3654
3658
  BridgeChain["Sei_Testnet"] = "Sei_Testnet";
@@ -3994,6 +3998,12 @@ const SWAP_TOKEN_REGISTRY = {
3994
3998
  category: 'wrapped',
3995
3999
  description: 'Wrapped Polygon',
3996
4000
  },
4001
+ CIRBTC: {
4002
+ symbol: 'CIRBTC',
4003
+ decimals: 8,
4004
+ category: 'wrapped',
4005
+ description: 'Circle Bitcoin',
4006
+ },
3997
4007
  };
3998
4008
  /**
3999
4009
  * Special NATIVE token constant for swap operations.
@@ -5690,6 +5700,96 @@ const OptimismSepolia = defineChain({
5690
5700
  },
5691
5701
  });
5692
5702
 
5703
+ /**
5704
+ * Pharos Mainnet chain definition
5705
+ * @remarks
5706
+ * This represents the official production network for the Pharos blockchain.
5707
+ * Pharos is a modular, full-stack parallel Layer 1 blockchain with
5708
+ * sub-second finality and EVM compatibility.
5709
+ */
5710
+ const Pharos = defineChain({
5711
+ type: 'evm',
5712
+ chain: exports.Blockchain.Pharos,
5713
+ name: 'Pharos',
5714
+ title: 'Pharos Mainnet',
5715
+ nativeCurrency: {
5716
+ name: 'Pharos',
5717
+ symbol: 'PHAROS',
5718
+ decimals: 18,
5719
+ },
5720
+ chainId: 1672,
5721
+ isTestnet: false,
5722
+ explorerUrl: 'https://pharos.socialscan.io/tx/{hash}',
5723
+ rpcEndpoints: ['https://rpc.pharos.xyz'],
5724
+ eurcAddress: null,
5725
+ usdcAddress: '0xC879C018dB60520F4355C26eD1a6D572cdAC1815',
5726
+ usdtAddress: null,
5727
+ cctp: {
5728
+ domain: 31,
5729
+ contracts: {
5730
+ v2: {
5731
+ type: 'split',
5732
+ tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
5733
+ messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
5734
+ confirmations: 1,
5735
+ fastConfirmations: 1,
5736
+ },
5737
+ },
5738
+ forwarderSupported: {
5739
+ source: false,
5740
+ destination: false,
5741
+ },
5742
+ },
5743
+ kitContracts: {
5744
+ bridge: BRIDGE_CONTRACT_EVM_MAINNET,
5745
+ },
5746
+ });
5747
+
5748
+ /**
5749
+ * Pharos Atlantic Testnet chain definition
5750
+ * @remarks
5751
+ * This represents the official test network for the Pharos blockchain.
5752
+ * Pharos is a modular, full-stack parallel Layer 1 blockchain with
5753
+ * sub-second finality and EVM compatibility.
5754
+ */
5755
+ const PharosTestnet = defineChain({
5756
+ type: 'evm',
5757
+ chain: exports.Blockchain.Pharos_Testnet,
5758
+ name: 'Pharos Atlantic',
5759
+ title: 'Pharos Atlantic Testnet',
5760
+ nativeCurrency: {
5761
+ name: 'Pharos',
5762
+ symbol: 'PHAROS',
5763
+ decimals: 18,
5764
+ },
5765
+ chainId: 688689,
5766
+ isTestnet: true,
5767
+ explorerUrl: 'https://atlantic.pharosscan.xyz/tx/{hash}',
5768
+ rpcEndpoints: ['https://atlantic.dplabs-internal.com'],
5769
+ eurcAddress: null,
5770
+ usdcAddress: '0xcfC8330f4BCAB529c625D12781b1C19466A9Fc8B',
5771
+ usdtAddress: null,
5772
+ cctp: {
5773
+ domain: 31,
5774
+ contracts: {
5775
+ v2: {
5776
+ type: 'split',
5777
+ tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
5778
+ messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
5779
+ confirmations: 1,
5780
+ fastConfirmations: 1,
5781
+ },
5782
+ },
5783
+ forwarderSupported: {
5784
+ source: false,
5785
+ destination: false,
5786
+ },
5787
+ },
5788
+ kitContracts: {
5789
+ bridge: BRIDGE_CONTRACT_EVM_TESTNET,
5790
+ },
5791
+ });
5792
+
5693
5793
  /**
5694
5794
  * Plume Mainnet chain definition
5695
5795
  * @remarks
@@ -5972,7 +6072,7 @@ const Sei = defineChain({
5972
6072
  },
5973
6073
  chainId: 1329,
5974
6074
  isTestnet: false,
5975
- explorerUrl: 'https://seitrace.com/tx/{hash}?chain=pacific-1',
6075
+ explorerUrl: 'https://seiscan.io/tx/{hash}',
5976
6076
  rpcEndpoints: ['https://evm-rpc.sei-apis.com'],
5977
6077
  eurcAddress: null,
5978
6078
  usdcAddress: '0xe15fC38F6D8c56aF07bbCBe3BAf5708A2Bf42392',
@@ -6030,7 +6130,7 @@ const SeiTestnet = defineChain({
6030
6130
  },
6031
6131
  chainId: 1328,
6032
6132
  isTestnet: true,
6033
- explorerUrl: 'https://seitrace.com/tx/{hash}?chain=atlantic-2',
6133
+ explorerUrl: 'https://testnet.seiscan.io/tx/{hash}',
6034
6134
  rpcEndpoints: ['https://evm-rpc-testnet.sei-apis.com'],
6035
6135
  eurcAddress: null,
6036
6136
  usdcAddress: '0x4fCF1784B31630811181f670Aea7A7bEF803eaED',
@@ -6847,6 +6947,8 @@ var Chains = {
6847
6947
  NobleTestnet: NobleTestnet,
6848
6948
  Optimism: Optimism,
6849
6949
  OptimismSepolia: OptimismSepolia,
6950
+ Pharos: Pharos,
6951
+ PharosTestnet: PharosTestnet,
6850
6952
  Plume: Plume,
6851
6953
  PlumeTestnet: PlumeTestnet,
6852
6954
  PolkadotAssetHub: PolkadotAssetHub,
@@ -9115,6 +9217,7 @@ const USDC = {
9115
9217
  [exports.Blockchain.NEAR]: '17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1',
9116
9218
  [exports.Blockchain.Noble]: 'uusdc',
9117
9219
  [exports.Blockchain.Optimism]: '0x0b2c639c533813f4aa9d7837caf62653d097ff85',
9220
+ [exports.Blockchain.Pharos]: '0xC879C018dB60520F4355C26eD1a6D572cdAC1815',
9118
9221
  [exports.Blockchain.Plume]: '0x222365EF19F7947e5484218551B56bb3965Aa7aF',
9119
9222
  [exports.Blockchain.Polkadot_Asset_Hub]: '1337',
9120
9223
  [exports.Blockchain.Polygon]: '0x3c499c542cef5e3811e1192ce70d8cc03d5c3359',
@@ -9146,6 +9249,7 @@ const USDC = {
9146
9249
  [exports.Blockchain.NEAR_Testnet]: '3e2210e1184b45b64c8a434c0a7e7b23cc04ea7eb7a6c3c32520d03d4afcb8af',
9147
9250
  [exports.Blockchain.Noble_Testnet]: 'uusdc',
9148
9251
  [exports.Blockchain.Optimism_Sepolia]: '0x5fd84259d66Cd46123540766Be93DFE6D43130D7',
9252
+ [exports.Blockchain.Pharos_Testnet]: '0xcfC8330f4BCAB529c625D12781b1C19466A9Fc8B',
9149
9253
  [exports.Blockchain.Plume_Testnet]: '0xcB5f30e335672893c7eb944B374c196392C19D18',
9150
9254
  [exports.Blockchain.Polkadot_Westmint]: '31337',
9151
9255
  [exports.Blockchain.Polygon_Amoy_Testnet]: '0x41e94eb019c0762f9bfcf9fb1e58725bfb0e7582',
@@ -9426,6 +9530,32 @@ const MON = {
9426
9530
  },
9427
9531
  };
9428
9532
 
9533
+ /**
9534
+ * cirBTC (Circle Bitcoin) token definition with addresses and metadata.
9535
+ *
9536
+ * @remarks
9537
+ * Built-in cirBTC definition for the TokenRegistry. Currently deployed
9538
+ * on Arc Testnet.
9539
+ *
9540
+ * @example
9541
+ * ```typescript
9542
+ * import { CIRBTC } from '@core/tokens'
9543
+ * import { Blockchain } from '@core/chains'
9544
+ *
9545
+ * console.log(CIRBTC.symbol) // 'cirBTC'
9546
+ * console.log(CIRBTC.decimals) // 8
9547
+ * console.log(CIRBTC.locators[Blockchain.Arc_Testnet])
9548
+ * // '0xf0C4a4CE82A5746AbAAd9425360Ab04fbBA432BF'
9549
+ * ```
9550
+ */
9551
+ const CIRBTC = {
9552
+ symbol: 'cirBTC',
9553
+ decimals: 8,
9554
+ locators: {
9555
+ [exports.Blockchain.Arc_Testnet]: '0xf0C4a4CE82A5746AbAAd9425360Ab04fbBA432BF',
9556
+ },
9557
+ };
9558
+
9429
9559
  // Re-export for consumers
9430
9560
  /**
9431
9561
  * All default token definitions.
@@ -9434,7 +9564,7 @@ const MON = {
9434
9564
  * These tokens are automatically included in the TokenRegistry when created
9435
9565
  * without explicit defaults. Extensions can override these definitions.
9436
9566
  * Includes USDC, USDT, EURC, DAI, USDE, PYUSD, WETH, WBTC, WSOL, WAVAX,
9437
- * WPOL, ETH, POL, PLUME, and MON.
9567
+ * WPOL, ETH, POL, PLUME, MON, and cirBTC.
9438
9568
  *
9439
9569
  * @example
9440
9570
  * ```typescript
@@ -9465,6 +9595,7 @@ const DEFAULT_TOKENS = [
9465
9595
  POL,
9466
9596
  PLUME,
9467
9597
  MON,
9598
+ CIRBTC,
9468
9599
  ];
9469
9600
  /**
9470
9601
  * Uppercased token symbols approved for swap fee collection.
@@ -10213,7 +10344,7 @@ async function retryAsync(fn, options) {
10213
10344
  }
10214
10345
 
10215
10346
  var name$2 = "@circle-fin/bridge-kit";
10216
- var version$3 = "1.8.3";
10347
+ var version$3 = "1.9.0";
10217
10348
  var pkg$3 = {
10218
10349
  name: name$2,
10219
10350
  version: version$3};
@@ -14344,11 +14475,18 @@ async function executePreparedChainRequest({ name, request, adapter, chain, conf
14344
14475
  step.explorerUrl = buildExplorerUrl(chain, txHash);
14345
14476
  if (outcome.errorMessage) {
14346
14477
  step.errorMessage = outcome.errorMessage;
14478
+ // Transaction was mined but reverted on-chain.
14479
+ step.errorCategory = 'chain_revert';
14347
14480
  }
14348
14481
  }
14349
14482
  catch (err) {
14350
14483
  step.state = 'error';
14351
14484
  step.error = err;
14485
+ // Sequential path does not yet attempt fine-grained classification of
14486
+ // pre-submission errors (user_rejected, capability errors, etc.). Mark
14487
+ // as `unknown` so consumers can at least detect the category is
14488
+ // populated uniformly across batched and sequential flows.
14489
+ step.errorCategory = 'unknown';
14352
14490
  // Optionally parse for common blockchain error formats
14353
14491
  if (err instanceof Error) {
14354
14492
  step.errorMessage = err.message;
@@ -15014,16 +15152,70 @@ async function executeBatchedApproveAndBurn(params, provider) {
15014
15152
  const batchResult = await adapter.batchExecute([approveCallData, burnCallData], chain);
15015
15153
  const approveReceipt = batchResult.receipts[0];
15016
15154
  const burnReceipt = batchResult.receipts[1];
15017
- const approveStep = await buildBatchedStep('approve', approveReceipt, batchResult.batchId, adapter, chain);
15018
- const burnStep = await buildBatchedStep('burn', burnReceipt, batchResult.batchId, adapter, chain);
15155
+ const approveStep = await buildBatchedStep('approve', approveReceipt, batchResult.batchId, adapter, chain, batchResult.statusCode, batchResult.error);
15156
+ const burnStep = await buildBatchedStep('burn', burnReceipt, batchResult.batchId, adapter, chain, batchResult.statusCode, batchResult.error);
15019
15157
  if (burnStep.state !== 'error' && !burnStep.txHash) {
15020
15158
  burnStep.state = 'error';
15021
15159
  burnStep.errorMessage =
15022
15160
  'Batched burn step completed but no transaction hash was returned.';
15161
+ burnStep.errorCategory = 'unknown';
15023
15162
  }
15024
15163
  const context = { burnTxHash: burnStep.txHash ?? '' };
15025
15164
  return { approveStep, burnStep, context };
15026
15165
  }
15166
+ /**
15167
+ * Derive a {@link BridgeStepErrorCategory} for a missing receipt.
15168
+ *
15169
+ * Combines the EIP-5792 `statusCode` (when present) with the underlying
15170
+ * polling error (when set) to produce the most specific category available.
15171
+ * Falls back to `'unknown'` when neither signal is conclusive.
15172
+ *
15173
+ * @param statusCode - The terminal `statusCode` from `wallet_getCallsStatus`, if any.
15174
+ * @param batchError - The polling error from `batchExecute`, if any.
15175
+ * @returns The derived error category for a missing-receipt step.
15176
+ *
15177
+ * @internal
15178
+ */
15179
+ function categorizeMissingReceipt(statusCode, batchError) {
15180
+ if (statusCode === 400)
15181
+ return 'failed_offchain';
15182
+ if (statusCode === 500)
15183
+ return 'reverted_onchain';
15184
+ if (statusCode === 600)
15185
+ return 'partial_reverted';
15186
+ if (batchError instanceof KitError &&
15187
+ batchError.code === NetworkError.TIMEOUT.code) {
15188
+ return 'polling_timeout';
15189
+ }
15190
+ return 'unknown';
15191
+ }
15192
+ /**
15193
+ * Derive a {@link BridgeStepErrorCategory} for a receipt that was returned
15194
+ * but whose per-call `status` is not `'success'`.
15195
+ *
15196
+ * A numeric EIP-5792 `statusCode` of 500 or 600 tells us the whole batch
15197
+ * reverted on-chain (completely or partially); otherwise the receipt
15198
+ * itself signalled a revert without a distinguishing code, so classify
15199
+ * as a plain on-chain revert.
15200
+ *
15201
+ * @param statusCode - The terminal `statusCode` from `wallet_getCallsStatus`, if any.
15202
+ * @returns The derived error category for a failed-receipt step.
15203
+ *
15204
+ * @internal
15205
+ */
15206
+ function categorizeFailedReceipt(statusCode) {
15207
+ // Mirror categorizeMissingReceipt: if the wallet's terminal status is
15208
+ // 400 ("batch not included onchain"), that judgement is authoritative
15209
+ // even when a non-success receipt is attached. Without this, a wrapped
15210
+ // 400 receipt would fall through to `chain_revert` and mislead UX.
15211
+ if (statusCode === 400)
15212
+ return 'failed_offchain';
15213
+ if (statusCode === 600)
15214
+ return 'partial_reverted';
15215
+ if (statusCode === 500)
15216
+ return 'reverted_onchain';
15217
+ return 'chain_revert';
15218
+ }
15027
15219
  /**
15028
15220
  * Build a {@link BridgeStep} from a single receipt within a batch.
15029
15221
  *
@@ -15038,11 +15230,17 @@ async function executeBatchedApproveAndBurn(params, provider) {
15038
15230
  * @param batchId - Wallet-assigned batch identifier.
15039
15231
  * @param adapter - The batch-capable adapter (used for confirmation).
15040
15232
  * @param chain - The EVM chain the batch was executed on.
15233
+ * @param statusCode - Optional EIP-5792 `statusCode` for the batch.
15234
+ * Used to classify the step's error category when the receipt is
15235
+ * missing or failed.
15236
+ * @param batchError - Optional polling error from `batchExecute`.
15237
+ * Preserved on the step so callers can inspect underlying timeouts
15238
+ * or RPC failures.
15041
15239
  * @returns A fully-populated bridge step with state, tx hash and explorer URL.
15042
15240
  *
15043
15241
  * @internal
15044
15242
  */
15045
- async function buildBatchedStep(name, receipt, batchId, adapter, chain) {
15243
+ async function buildBatchedStep(name, receipt, batchId, adapter, chain, statusCode, batchError) {
15046
15244
  const step = {
15047
15245
  name,
15048
15246
  state: 'pending',
@@ -15052,6 +15250,10 @@ async function buildBatchedStep(name, receipt, batchId, adapter, chain) {
15052
15250
  if (!receipt) {
15053
15251
  step.state = 'error';
15054
15252
  step.errorMessage = `No receipt returned for ${name} in batch ${batchId}.`;
15253
+ step.errorCategory = categorizeMissingReceipt(statusCode, batchError);
15254
+ if (batchError !== undefined) {
15255
+ step.error = batchError;
15256
+ }
15055
15257
  return step;
15056
15258
  }
15057
15259
  step.txHash = receipt.txHash;
@@ -15061,11 +15263,13 @@ async function buildBatchedStep(name, receipt, batchId, adapter, chain) {
15061
15263
  if (receipt.status !== 'success') {
15062
15264
  step.state = 'error';
15063
15265
  step.errorMessage = `${name} call failed within batch ${batchId}.`;
15266
+ step.errorCategory = categorizeFailedReceipt(statusCode);
15064
15267
  return step;
15065
15268
  }
15066
15269
  if (!receipt.txHash) {
15067
15270
  step.state = 'error';
15068
15271
  step.errorMessage = `${name} succeeded in batch but returned an empty transaction hash.`;
15272
+ step.errorCategory = 'unknown';
15069
15273
  return step;
15070
15274
  }
15071
15275
  try {
@@ -15080,6 +15284,7 @@ async function buildBatchedStep(name, receipt, batchId, adapter, chain) {
15080
15284
  step.data = transaction;
15081
15285
  if (outcome.errorMessage) {
15082
15286
  step.errorMessage = outcome.errorMessage;
15287
+ step.errorCategory = 'chain_revert';
15083
15288
  }
15084
15289
  }
15085
15290
  catch (err) {
@@ -15087,11 +15292,12 @@ async function buildBatchedStep(name, receipt, batchId, adapter, chain) {
15087
15292
  step.error = err;
15088
15293
  step.errorMessage =
15089
15294
  err instanceof Error ? err.message : 'Unknown error during confirmation.';
15295
+ step.errorCategory = 'unknown';
15090
15296
  }
15091
15297
  return step;
15092
15298
  }
15093
15299
 
15094
- var version$2 = "1.6.3";
15300
+ var version$2 = "1.7.0";
15095
15301
  var pkg$2 = {
15096
15302
  version: version$2};
15097
15303
 
@@ -15167,6 +15373,7 @@ async function executeBatchedPath(params, provider, result, invocation) {
15167
15373
  errorMessage: error_ instanceof Error
15168
15374
  ? error_.message
15169
15375
  : 'Batched approve + burn failed.',
15376
+ errorCategory: classifyPreSubmissionError(error_),
15170
15377
  });
15171
15378
  return undefined;
15172
15379
  }
@@ -15181,6 +15388,89 @@ function ensureStepErrorMessage(name, step) {
15181
15388
  step.errorMessage = `${name} step failed: ${getErrorMessage(step.error)}`;
15182
15389
  }
15183
15390
  }
15391
+ /**
15392
+ * Coerce a raw JSON-RPC `code` to a number.
15393
+ *
15394
+ * Some wallet SDKs serialize the JSON-RPC `code` as a string ("4001")
15395
+ * after round-tripping through JSON; accept both shapes so strict `===`
15396
+ * comparisons downstream still classify 5720/5730/5740 correctly — those
15397
+ * codes have no message-pattern fallback.
15398
+ *
15399
+ * @param rawCode - The raw `code` extracted from the error object.
15400
+ * @returns The numeric code, or `undefined` if the value cannot be parsed.
15401
+ *
15402
+ * @internal
15403
+ */
15404
+ function coerceRpcCode(rawCode) {
15405
+ if (typeof rawCode === 'number') {
15406
+ return rawCode;
15407
+ }
15408
+ if (typeof rawCode === 'string') {
15409
+ return Number.parseInt(rawCode, 10);
15410
+ }
15411
+ return undefined;
15412
+ }
15413
+ /**
15414
+ * Classify a pre-submission error thrown during `wallet_sendCalls`.
15415
+ *
15416
+ * Inspect the error's JSON-RPC `code` (falling back to message pattern
15417
+ * matching for wrapper errors like viem's `ChainMismatchError`) and map
15418
+ * it to a {@link BridgeStepErrorCategory}. This lets downstream consumers
15419
+ * distinguish user rejections, wallet capability gaps, and unknown
15420
+ * failures without parsing error messages.
15421
+ *
15422
+ * @remarks
15423
+ * Does NOT alter control flow — the SDK continues to surface a
15424
+ * `state: 'error'` step. Auto-fallback to sequential execution is
15425
+ * intentionally out of scope for this helper.
15426
+ *
15427
+ * @param err - The error thrown by `wallet_sendCalls`.
15428
+ * @returns The derived error category, or `'unknown'` if no match.
15429
+ *
15430
+ * @internal
15431
+ */
15432
+ function classifyPreSubmissionError(err) {
15433
+ // Cross-realm-safe duck typing: `instanceof Error` returns false for
15434
+ // errors thrown in a different JavaScript realm (e.g., a wallet
15435
+ // provider running inside an iframe, which is common with WalletConnect
15436
+ // and the Coinbase Wallet SDK).
15437
+ if (typeof err !== 'object' || err === null || !('message' in err)) {
15438
+ return 'unknown';
15439
+ }
15440
+ const code = coerceRpcCode(err.code);
15441
+ const message = String(err.message);
15442
+ // Numeric JSON-RPC codes are authoritative; check them before falling
15443
+ // back to message-pattern matching. Order matters: an error carrying
15444
+ // `code === 5750` with a message like "user rejected the upgrade"
15445
+ // is a capability problem, not a plain user rejection.
15446
+ if (code === 4001) {
15447
+ return 'user_rejected';
15448
+ }
15449
+ if (code === 5700 || code === 5710 || code === 5750) {
15450
+ return 'atomic_unsupported';
15451
+ }
15452
+ if (code === 5720) {
15453
+ return 'duplicate_batch_id';
15454
+ }
15455
+ if (code === 5730) {
15456
+ return 'unknown_bundle';
15457
+ }
15458
+ if (code === 5740) {
15459
+ return 'batch_too_large';
15460
+ }
15461
+ // Fall back to message patterns when no specific code is available —
15462
+ // viem (and other wrapper layers) sometimes strip the numeric code
15463
+ // while preserving the original wallet message in `Details:`.
15464
+ if (/EIP-7702 not supported/i.test(message) ||
15465
+ /does not support the requested chain/i.test(message) ||
15466
+ /rejected the upgrade/i.test(message)) {
15467
+ return 'atomic_unsupported';
15468
+ }
15469
+ if (/user rejected/i.test(message)) {
15470
+ return 'user_rejected';
15471
+ }
15472
+ return 'unknown';
15473
+ }
15184
15474
  /**
15185
15475
  * Execute a cross-chain USDC bridge using the CCTP v2 protocol.
15186
15476
  *
@@ -17324,7 +17614,7 @@ const createBridgeKit = (context) => {
17324
17614
  };
17325
17615
 
17326
17616
  var name$1 = "@circle-fin/swap-kit";
17327
- var version$1 = "1.1.0";
17617
+ var version$1 = "1.1.1";
17328
17618
  var pkg$1 = {
17329
17619
  name: name$1,
17330
17620
  version: version$1};
@@ -28698,7 +28988,7 @@ const prepareSend = async (params) => {
28698
28988
  const fromContext = params.from;
28699
28989
  const fromAdapter = fromContext.adapter;
28700
28990
  const fromChain = resolveChainIdentifier(fromContext.chain);
28701
- const fromAddress = await fromAdapter.getAddress(fromChain);
28991
+ const fromAddress = fromContext.address ?? (await fromAdapter.getAddress(fromChain));
28702
28992
  // resolve input parameters
28703
28993
  const token = params.token ?? 'USDC';
28704
28994
  // Validate token and determine if it's an alias or custom address
@@ -29143,7 +29433,7 @@ const getSupportedChains$2 = (context, operationType, unifiedBalance) => {
29143
29433
  };
29144
29434
 
29145
29435
  var name = "@circle-fin/unified-balance-kit";
29146
- var version = "1.0.1";
29436
+ var version = "1.0.2";
29147
29437
  var pkg = {
29148
29438
  name: name,
29149
29439
  version: version};