@circle-fin/app-kit 1.11.0 → 1.12.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.
@@ -38,6 +38,7 @@ import { PublicKey } from '@solana/web3.js';
38
38
  import 'bn.js';
39
39
  import '@coral-xyz/anchor';
40
40
  import '@noble/curves/ed25519';
41
+ import 'viem';
41
42
  import { keccak256 } from '@ethersproject/keccak256';
42
43
 
43
44
  // Import global type declarations
@@ -2555,6 +2556,8 @@ class KitError extends Error {
2555
2556
  Blockchain["World_Chain_Sepolia"] = "World_Chain_Sepolia";
2556
2557
  Blockchain["XDC"] = "XDC";
2557
2558
  Blockchain["XDC_Apothem"] = "XDC_Apothem";
2559
+ Blockchain["X_Layer"] = "X_Layer";
2560
+ Blockchain["X_Layer_Testnet"] = "X_Layer_Testnet";
2558
2561
  Blockchain["ZKSync_Era"] = "ZKSync_Era";
2559
2562
  Blockchain["ZKSync_Sepolia"] = "ZKSync_Sepolia";
2560
2563
  })(Blockchain || (Blockchain = {}));
@@ -2608,6 +2611,7 @@ var BridgeChain;
2608
2611
  BridgeChain["Unichain"] = "Unichain";
2609
2612
  BridgeChain["World_Chain"] = "World_Chain";
2610
2613
  BridgeChain["XDC"] = "XDC";
2614
+ BridgeChain["X_Layer"] = "X_Layer";
2611
2615
  // Testnet chains with CCTPv2 support
2612
2616
  BridgeChain["Arc_Testnet"] = "Arc_Testnet";
2613
2617
  BridgeChain["Arbitrum_Sepolia"] = "Arbitrum_Sepolia";
@@ -2633,6 +2637,7 @@ var BridgeChain;
2633
2637
  BridgeChain["Unichain_Sepolia"] = "Unichain_Sepolia";
2634
2638
  BridgeChain["World_Chain_Sepolia"] = "World_Chain_Sepolia";
2635
2639
  BridgeChain["XDC_Apothem"] = "XDC_Apothem";
2640
+ BridgeChain["X_Layer_Testnet"] = "X_Layer_Testnet";
2636
2641
  })(BridgeChain || (BridgeChain = {}));
2637
2642
  var UnifiedBalanceChain;
2638
2643
  (function(UnifiedBalanceChain) {
@@ -5170,7 +5175,8 @@ var EarnChain;
5170
5175
  isTestnet: true,
5171
5176
  explorerUrl: 'https://amoy.polygonscan.com/tx/{hash}',
5172
5177
  rpcEndpoints: [
5173
- 'https://rpc-amoy.polygon.technology'
5178
+ 'https://polygon-amoy-bor-rpc.publicnode.com',
5179
+ 'https://polygon-amoy.drpc.org'
5174
5180
  ],
5175
5181
  eurcAddress: null,
5176
5182
  usdcAddress: '0x41e94eb019c0762f9bfcf9fb1e58725bfb0e7582',
@@ -6035,6 +6041,104 @@ var EarnChain;
6035
6041
  }
6036
6042
  });
6037
6043
 
6044
+ /**
6045
+ * X Layer Mainnet chain definition
6046
+ * @remarks
6047
+ * This represents the official production network for the X Layer blockchain.
6048
+ * X Layer is an EVM-compatible OP Stack Layer-2 blockchain built by OKX,
6049
+ * using OKB as its native gas token. (Migrated from Polygon zkEVM/CDK to the
6050
+ * OP Stack on 2025-10-27; older docs describing it as zkEVM are obsolete.)
6051
+ */ const XLayer = defineChain({
6052
+ type: 'evm',
6053
+ chain: Blockchain.X_Layer,
6054
+ name: 'X Layer',
6055
+ title: 'X Layer Mainnet',
6056
+ nativeCurrency: {
6057
+ name: 'OKB',
6058
+ symbol: 'OKB',
6059
+ decimals: 18
6060
+ },
6061
+ chainId: 196,
6062
+ isTestnet: false,
6063
+ explorerUrl: 'https://www.oklink.com/xlayer/tx/{hash}',
6064
+ rpcEndpoints: [
6065
+ 'https://xlayerrpc.okx.com'
6066
+ ],
6067
+ eurcAddress: null,
6068
+ usdcAddress: '0xB6CEceAB302E2E4948951eE7843FC24E92933061',
6069
+ usdtAddress: null,
6070
+ cctp: {
6071
+ domain: 37,
6072
+ contracts: {
6073
+ v2: {
6074
+ type: 'split',
6075
+ tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
6076
+ messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
6077
+ confirmations: 65,
6078
+ fastConfirmations: 1
6079
+ }
6080
+ },
6081
+ forwarderSupported: {
6082
+ source: false,
6083
+ destination: false
6084
+ }
6085
+ },
6086
+ kitContracts: {
6087
+ bridge: BRIDGE_CONTRACT_EVM_MAINNET
6088
+ }
6089
+ });
6090
+
6091
+ /**
6092
+ * X Layer Testnet chain definition
6093
+ * @remarks
6094
+ * This represents the official test network for the X Layer blockchain.
6095
+ * X Layer is an EVM-compatible OP Stack Layer-2 blockchain built by OKX,
6096
+ * using OKB as its native gas token. (Migrated from Polygon zkEVM/CDK to the
6097
+ * OP Stack on 2025-10-27; older docs describing it as zkEVM are obsolete.)
6098
+ */ const XLayerTestnet = defineChain({
6099
+ type: 'evm',
6100
+ chain: Blockchain.X_Layer_Testnet,
6101
+ name: 'X Layer Testnet',
6102
+ title: 'X Layer Testnet',
6103
+ nativeCurrency: {
6104
+ name: 'OKB',
6105
+ symbol: 'OKB',
6106
+ decimals: 18
6107
+ },
6108
+ chainId: 1952,
6109
+ isTestnet: true,
6110
+ // Deliberately not oklink.com (used for mainnet): viem's bundled OKLink
6111
+ // testnet URL targets the deprecated pre-rebrand chain ID 195, not this
6112
+ // chain's ID (1952). Verified against the internal chain-expansion-scripts
6113
+ // config (`v2config.sandbox.yml`) — do not "normalize" this to match mainnet.
6114
+ explorerUrl: 'https://web3.okx.com/explorer/x-layer-testnet/tx/{hash}',
6115
+ rpcEndpoints: [
6116
+ 'https://testrpc.xlayer.tech'
6117
+ ],
6118
+ eurcAddress: null,
6119
+ usdcAddress: '0xDec90b78111Ba2fc6FC6d84d8B9ec159A2d4b9B3',
6120
+ usdtAddress: null,
6121
+ cctp: {
6122
+ domain: 37,
6123
+ contracts: {
6124
+ v2: {
6125
+ type: 'split',
6126
+ tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
6127
+ messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
6128
+ confirmations: 65,
6129
+ fastConfirmations: 1
6130
+ }
6131
+ },
6132
+ forwarderSupported: {
6133
+ source: false,
6134
+ destination: false
6135
+ }
6136
+ },
6137
+ kitContracts: {
6138
+ bridge: BRIDGE_CONTRACT_EVM_TESTNET
6139
+ }
6140
+ });
6141
+
6038
6142
  /**
6039
6143
  * ZKSync Era Mainnet chain definition
6040
6144
  * @remarks
@@ -6154,6 +6258,8 @@ var Chains = /*#__PURE__*/Object.freeze({
6154
6258
  WorldChainSepolia: WorldChainSepolia,
6155
6259
  XDC: XDC,
6156
6260
  XDCApothem: XDCApothem,
6261
+ XLayer: XLayer,
6262
+ XLayerTestnet: XLayerTestnet,
6157
6263
  ZKSyncEra: ZKSyncEra,
6158
6264
  ZKSyncEraSepolia: ZKSyncEraSepolia
6159
6265
  });
@@ -8208,6 +8314,7 @@ const swapTokenEnumSchema = z.enum([
8208
8314
  [Blockchain.Unichain]: '0x078D782b760474a361dDA0AF3839290b0EF57AD6',
8209
8315
  [Blockchain.World_Chain]: '0x79A02482A880bCE3F13e09Da970dC34db4CD24d1',
8210
8316
  [Blockchain.XDC]: '0xfA2958CB79b0491CC627c1557F441eF849Ca8eb1',
8317
+ [Blockchain.X_Layer]: '0xB6CEceAB302E2E4948951eE7843FC24E92933061',
8211
8318
  [Blockchain.ZKSync_Era]: '0x1d17CBcF0D6D143135aE902365D2E5e2A16538D4',
8212
8319
  // =========================================================================
8213
8320
  // Testnets (alphabetically sorted)
@@ -8242,6 +8349,7 @@ const swapTokenEnumSchema = z.enum([
8242
8349
  [Blockchain.Unichain_Sepolia]: '0x31d0220469e10c4E71834a79b1f276d740d3768F',
8243
8350
  [Blockchain.World_Chain_Sepolia]: '0x66145f38cBAC35Ca6F1Dfb4914dF98F1614aeA88',
8244
8351
  [Blockchain.XDC_Apothem]: '0xb5AB69F7bBada22B28e79C8FFAECe55eF1c771D4',
8352
+ [Blockchain.X_Layer_Testnet]: '0xDec90b78111Ba2fc6FC6d84d8B9ec159A2d4b9B3',
8245
8353
  [Blockchain.ZKSync_Sepolia]: '0xAe045DE5638162fa134807Cb558E15A3F5A7F853'
8246
8354
  }
8247
8355
  };
@@ -9653,7 +9761,7 @@ function resolveOptions(options) {
9653
9761
  }
9654
9762
 
9655
9763
  var name$2 = "@circle-fin/bridge-kit";
9656
- var version$3 = "1.12.2";
9764
+ var version$3 = "1.13.0";
9657
9765
  var pkg$3 = {
9658
9766
  name: name$2,
9659
9767
  version: version$3};
@@ -9690,13 +9798,21 @@ const assertCustomFeePolicySymbol = Symbol('assertCustomFeePolicy');
9690
9798
  computeFee: z.function().returns(z.string().or(z.promise(z.string()))).optional(),
9691
9799
  calculateFee: z.function().returns(z.string().or(z.promise(z.string()))).optional(),
9692
9800
  resolveFeeRecipientAddress: z.function().returns(z.string().or(z.promise(z.string())))
9693
- }).strict().refine((data)=>{
9801
+ }).strict().superRefine((data, ctx)=>{
9694
9802
  const hasComputeFee = data.computeFee !== undefined;
9695
9803
  const hasCalculateFee = data.calculateFee !== undefined;
9696
- // XOR: exactly one must be provided
9697
- return hasComputeFee !== hasCalculateFee;
9698
- }, {
9699
- message: 'Provide either computeFee or calculateFee, not both. Use computeFee (recommended) for human-readable amounts.'
9804
+ if (hasComputeFee && hasCalculateFee) {
9805
+ ctx.addIssue({
9806
+ code: z.ZodIssueCode.custom,
9807
+ message: 'Provide either computeFee or calculateFee, not both. Use computeFee (recommended) for human-readable amounts.'
9808
+ });
9809
+ }
9810
+ if (!hasComputeFee && !hasCalculateFee) {
9811
+ ctx.addIssue({
9812
+ code: z.ZodIssueCode.custom,
9813
+ message: 'Provide either computeFee or calculateFee. Use computeFee (recommended) for human-readable amounts.'
9814
+ });
9815
+ }
9700
9816
  });
9701
9817
  /**
9702
9818
  * Assert that the provided value conforms to {@link CustomFeePolicy}.
@@ -12457,14 +12573,32 @@ const CUSTOM_BURN_GAS_ESTIMATE_EVM = 201_525n // p99 and max are same here: 201_
12457
12573
  ;
12458
12574
  const RECEIVE_MESSAGE_GAS_ESTIMATE_EVM = 237_401n // (99p: 163_963n + max: 310_839n) / 2 = 237_401n
12459
12575
  ;
12460
- // Hard execution caps: observed max + ~30% buffer, used as gasLimit overrides on
12461
- // chains whose eth_estimateGas under-reports (e.g. Cronos EIP-7623 calldata floor).
12462
- // Kept separate from the fee-estimate averages above.
12463
- const APPROVE_GAS_LIMIT_EVM = 100_000n // ERC-20 approve observed max ~46k
12576
+ // Gas FLOORS, not ceilings kept separate from the fee-estimate averages
12577
+ // above. `executePreparedChainRequest` submits
12578
+ // max(estimate * buffer, floor), so a chain whose real cost exceeds the floor
12579
+ // is covered by its own estimate, and a chain whose estimator under-reports
12580
+ // (Cronos: returns 30_600 where the EIP-7623 calldata floor is 45_000) is
12581
+ // covered by the floor.
12582
+ //
12583
+ // Two distinct chain surcharges drive these numbers, both measured live:
12584
+ // Sei — ~+51_500 per NEWLY CREATED storage slot (73_595 vs vanilla 22_100);
12585
+ // no flat per-tx surcharge (31_535, identical to Base).
12586
+ // Edge — ~+53_200 flat on EVERY tx (84_751 vs Base 31_535); storage priced
12587
+ // normally. Edge therefore fails warm as well as cold.
12588
+ // A floor must clear the worst COLD cost, since a slot that exists at estimate
12589
+ // time can be consumed before inclusion and cost a full step more on execution.
12590
+ // Each floor is therefore derived from the worst observed estimate *after* the
12591
+ // 1.25x buffer, plus headroom — sizing it below the buffered value would leave
12592
+ // the estimate governing and defeat the point of the floor.
12593
+ //
12594
+ // The `*_GAS_LIMIT_EVM` names are kept despite these being floors: they are
12595
+ // exported, so renaming to `*_GAS_FLOOR_EVM` would be a breaking change for
12596
+ // consumers. Read "LIMIT" here as "the limit we submit", never as a ceiling.
12597
+ const APPROVE_GAS_LIMIT_EVM = 150_000n // buffered worst cold 149_355 (Edge Testnet 119_484 x 1.25) + drift headroom
12464
12598
  ;
12465
- const DEPOSIT_FOR_BURN_GAS_LIMIT_EVM = 300_000n // observed max 226_506 + ~30%
12599
+ const DEPOSIT_FOR_BURN_GAS_LIMIT_EVM = 500_000n // buffered worst 474_078 (Sei 379_263 x 1.25) + ~26k headroom
12466
12600
  ;
12467
- const RECEIVE_MESSAGE_GAS_LIMIT_EVM = 400_000n // observed max 310_839 + ~30%
12601
+ const RECEIVE_MESSAGE_GAS_LIMIT_EVM = 400_000n // observed max 310_839; clears Cronos' calldata floor ~10x
12468
12602
  ;
12469
12603
  /**
12470
12604
  * The minimum finality threshold for CCTPv2 transfers.
@@ -13929,6 +14063,63 @@ function hasPendingState(analysis, result) {
13929
14063
  return waitForPendingTransaction(pendingStep, adapter, chain);
13930
14064
  }
13931
14065
 
14066
+ /**
14067
+ * Multiplier applied to a successful gas estimate before it is submitted.
14068
+ *
14069
+ * Estimates are exact, not padded: Sei returns 109_739 for an approve that
14070
+ * consumes 107_717 (1.9% headroom). Chains that price storage in large steps
14071
+ * can exceed the estimate if state changes between estimation and inclusion,
14072
+ * so the estimate is padded before use.
14073
+ *
14074
+ * @remarks
14075
+ * This buffer alone does NOT cover Sei's ~51_500 per-new-slot step at approve
14076
+ * scale (25% of ~110_000 is only ~27_500). For approve, the FLOOR is what
14077
+ * covers a slot that exists at estimation time and is consumed before
14078
+ * inclusion — so do not lower `APPROVE_GAS_LIMIT_EVM` on the reasoning that
14079
+ * the estimate covers it. For burn the buffer does cover a step (25% of
14080
+ * ~300_000 exceeds 51_500).
14081
+ */ const GAS_ESTIMATE_BUFFER_PERCENT = 125n;
14082
+ /**
14083
+ * Resolve the gas limit for an EVM request as `max(estimate * buffer, floor)`.
14084
+ *
14085
+ * Estimates first so chains whose real cost exceeds the floor are covered by
14086
+ * their own measurement, and falls back to the floor whenever estimation is
14087
+ * unavailable or under-reports. Estimation failure is never fatal here: before
14088
+ * floors existed these requests were submitted with a pinned limit and no
14089
+ * estimate at all, so degrading to the floor is never worse than the previous
14090
+ * behaviour.
14091
+ *
14092
+ * @param request - The prepared EVM request to size a gas limit for
14093
+ * @param gasFloor - The minimum gas limit to submit, in gas units
14094
+ * @returns The gas limit to submit, in gas units
14095
+ * @throws Never — estimation failures degrade to `gasFloor`
14096
+ *
14097
+ * @example
14098
+ * ```typescript
14099
+ * const gasLimit = await resolveGasLimit(request, 150_000)
14100
+ * ```
14101
+ */ const resolveGasLimit = async (request, gasFloor)=>{
14102
+ try {
14103
+ // Deliberately called without a `fallback`: both the viem and ethers
14104
+ // adapters *return* the supplied fallback object when estimation reverts
14105
+ // rather than throwing, which would set the estimate to the floor and then
14106
+ // multiply it by the buffer below. Omitting it routes reverts through the
14107
+ // catch, so a failed estimate degrades to exactly the floor.
14108
+ const estimate = await request.estimate();
14109
+ // The arithmetic stays inside the try on purpose. `EstimatedGas.gas` is
14110
+ // typed `bigint`, but adapters are a public extension point and may be
14111
+ // implemented in plain JS, so a non-bigint `gas` would throw here
14112
+ // ("Cannot mix BigInt and other types"). Guarding it keeps the documented
14113
+ // contract — estimation never aborts a step, it degrades to the floor.
14114
+ const buffered = estimate.gas * GAS_ESTIMATE_BUFFER_PERCENT / 100n;
14115
+ // Convert before comparing: Math.max throws on BigInt operands, and gas
14116
+ // units are far below Number.MAX_SAFE_INTEGER so the narrowing is lossless.
14117
+ return Math.max(Number(buffered), gasFloor);
14118
+ } catch {
14119
+ // Estimation is best-effort; the floor is the known-safe value.
14120
+ return gasFloor;
14121
+ }
14122
+ };
13932
14123
  /**
13933
14124
  * Executes a prepared chain request and returns the result as a bridge step.
13934
14125
  *
@@ -13942,8 +14133,8 @@ function hasPendingState(analysis, result) {
13942
14133
  * - `adapter`: The adapter that will execute the transaction
13943
14134
  * - `confirmations`: The number of confirmations to wait for (defaults to 1)
13944
14135
  * - `timeout`: The timeout for the request in milliseconds
13945
- * - `gasLimit`: Optional explicit gas limit (number) forwarded to EVM execute,
13946
- * bypassing `eth_estimateGas`; ignored for non-EVM requests
14136
+ * - `gasFloor`: Optional minimum gas limit (number); the request is submitted
14137
+ * with `max(estimate * 1.25, gasFloor)`. Ignored for non-EVM requests
13947
14138
  * @returns The bridge step with the transaction details and explorer URL
13948
14139
  * @throws If the transaction execution fails
13949
14140
  *
@@ -13958,7 +14149,7 @@ function hasPendingState(analysis, result) {
13958
14149
  * })
13959
14150
  * console.log('Transaction hash:', step.txHash)
13960
14151
  * ```
13961
- */ async function executePreparedChainRequest({ name, request, adapter, chain, confirmations = 1, timeout, gasLimit }) {
14152
+ */ async function executePreparedChainRequest({ name, request, adapter, chain, confirmations = 1, timeout, gasFloor }) {
13962
14153
  const step = {
13963
14154
  name,
13964
14155
  state: 'pending'
@@ -13971,8 +14162,8 @@ function hasPendingState(analysis, result) {
13971
14162
  step.state = 'noop';
13972
14163
  return step;
13973
14164
  }
13974
- const txHash = request.type === 'evm' && gasLimit !== undefined ? await request.execute({
13975
- gasLimit
14165
+ const txHash = request.type === 'evm' && gasFloor !== undefined ? await request.execute({
14166
+ gasLimit: await resolveGasLimit(request, gasFloor)
13976
14167
  }) : await request.execute();
13977
14168
  step.txHash = txHash;
13978
14169
  const retryOptions = {
@@ -14046,7 +14237,7 @@ function hasPendingState(analysis, result) {
14046
14237
  adapter: params.source.adapter,
14047
14238
  chain: params.source.chain,
14048
14239
  request: await provider.approve(params.source, approvalAmount),
14049
- gasLimit: Number(APPROVE_GAS_LIMIT_EVM)
14240
+ gasFloor: Number(APPROVE_GAS_LIMIT_EVM)
14050
14241
  });
14051
14242
  }
14052
14243
 
@@ -14074,7 +14265,7 @@ function hasPendingState(analysis, result) {
14074
14265
  adapter: params.source.adapter,
14075
14266
  chain: params.source.chain,
14076
14267
  request: await provider.burn(params),
14077
- gasLimit: Number(DEPOSIT_FOR_BURN_GAS_LIMIT_EVM)
14268
+ gasFloor: Number(DEPOSIT_FOR_BURN_GAS_LIMIT_EVM)
14078
14269
  });
14079
14270
  }
14080
14271
 
@@ -14168,10 +14359,9 @@ function hasPendingState(analysis, result) {
14168
14359
  request: mintRequest,
14169
14360
  // Some chains (e.g. Cronos) enforce an EIP-7623 calldata gas floor that
14170
14361
  // eth_estimateGas does not account for, returning a below-floor value
14171
- // without reverting. Pinning to a value above the observed execution max
14172
- // (310_839) bypasses re-estimation and guarantees we clear both the floor
14173
- // and the actual execution cost.
14174
- gasLimit: Number(RECEIVE_MESSAGE_GAS_LIMIT_EVM)
14362
+ // without reverting. The floor covers those; chains that cost more than the
14363
+ // floor are covered by their own estimate.
14364
+ gasFloor: Number(RECEIVE_MESSAGE_GAS_LIMIT_EVM)
14175
14365
  });
14176
14366
  // Add forwarded: false for non-relayer mints
14177
14367
  return {
@@ -14694,7 +14884,7 @@ const mockAttestationMessage = {
14694
14884
  return step;
14695
14885
  }
14696
14886
 
14697
- var version$2 = "1.10.1";
14887
+ var version$2 = "1.10.2";
14698
14888
  var pkg$2 = {
14699
14889
  version: version$2};
14700
14890
 
@@ -17292,7 +17482,9 @@ registerKit(`${pkg$3.name}/${pkg$3.version}`);
17292
17482
  headers: context.headers
17293
17483
  }
17294
17484
  });
17295
- if (hasBoth) {
17485
+ if (context.customFeePolicy?.bridge != null) {
17486
+ kit.setCustomFeePolicy(context.customFeePolicy.bridge);
17487
+ } else if (hasBoth) {
17296
17488
  kit.setCustomFeePolicy({
17297
17489
  calculateFee: async (params)=>{
17298
17490
  const feeStr = await getFee('bridge', params);
@@ -17308,7 +17500,7 @@ registerKit(`${pkg$3.name}/${pkg$3.version}`);
17308
17500
  };
17309
17501
 
17310
17502
  var name$1 = "@circle-fin/swap-kit";
17311
- var version$1 = "1.5.0";
17503
+ var version$1 = "1.5.1";
17312
17504
  var pkg$1 = {
17313
17505
  name: name$1,
17314
17506
  version: version$1};
@@ -19251,7 +19443,7 @@ new Set(Object.values(Blockchain));
19251
19443
  registerKit(`${pkg$1.name}/${pkg$1.version}`);
19252
19444
 
19253
19445
  var name = "@circle-fin/earn-kit";
19254
- var version = "1.4.0";
19446
+ var version = "1.5.0";
19255
19447
  var pkg = {
19256
19448
  name: name,
19257
19449
  version: version};
@@ -20262,11 +20454,16 @@ const sourceAdapterContextSchema = z.object({
20262
20454
  *
20263
20455
  * Validate the optional Kit Key field using the standard `apiKeySchema`
20264
20456
  * format (`KIT_KEY:<keyId>:<keySecret>`). When omitted, the SDK
20265
- * operates in permissionless mode.
20457
+ * operates in permissionless mode. `baseUrl` overrides the Earn Service
20458
+ * endpoint (e.g. staging); `batchTransactions: false` opts out of atomic
20459
+ * batched execution. Both are forwarded to the provider, so this `.strict()`
20460
+ * schema must accept them or a valid config object is rejected.
20266
20461
  *
20267
20462
  * @internal
20268
20463
  */ const earnConfigSchema = z.object({
20269
- kitKey: apiKeySchema.optional()
20464
+ kitKey: apiKeySchema.optional(),
20465
+ baseUrl: z.string().optional(),
20466
+ batchTransactions: z.boolean().optional()
20270
20467
  }).strict();
20271
20468
  /**
20272
20469
  * Canonical decimal form: a leading digit with no leading zeros (a single
package/estimateSwap.cjs CHANGED
@@ -40,6 +40,7 @@ require('@coral-xyz/anchor');
40
40
  var bs58 = require('bs58');
41
41
  require('@noble/curves/ed25519');
42
42
  var units = require('@ethersproject/units');
43
+ require('viem');
43
44
  var keccak256 = require('@ethersproject/keccak256');
44
45
 
45
46
  function _interopDefault (e) { return e && e.__esModule ? e.default : e; }
@@ -3008,6 +3009,8 @@ class KitError extends Error {
3008
3009
  Blockchain["World_Chain_Sepolia"] = "World_Chain_Sepolia";
3009
3010
  Blockchain["XDC"] = "XDC";
3010
3011
  Blockchain["XDC_Apothem"] = "XDC_Apothem";
3012
+ Blockchain["X_Layer"] = "X_Layer";
3013
+ Blockchain["X_Layer_Testnet"] = "X_Layer_Testnet";
3011
3014
  Blockchain["ZKSync_Era"] = "ZKSync_Era";
3012
3015
  Blockchain["ZKSync_Sepolia"] = "ZKSync_Sepolia";
3013
3016
  })(Blockchain || (Blockchain = {}));
@@ -3061,6 +3064,7 @@ var BridgeChain;
3061
3064
  BridgeChain["Unichain"] = "Unichain";
3062
3065
  BridgeChain["World_Chain"] = "World_Chain";
3063
3066
  BridgeChain["XDC"] = "XDC";
3067
+ BridgeChain["X_Layer"] = "X_Layer";
3064
3068
  // Testnet chains with CCTPv2 support
3065
3069
  BridgeChain["Arc_Testnet"] = "Arc_Testnet";
3066
3070
  BridgeChain["Arbitrum_Sepolia"] = "Arbitrum_Sepolia";
@@ -3086,6 +3090,7 @@ var BridgeChain;
3086
3090
  BridgeChain["Unichain_Sepolia"] = "Unichain_Sepolia";
3087
3091
  BridgeChain["World_Chain_Sepolia"] = "World_Chain_Sepolia";
3088
3092
  BridgeChain["XDC_Apothem"] = "XDC_Apothem";
3093
+ BridgeChain["X_Layer_Testnet"] = "X_Layer_Testnet";
3089
3094
  })(BridgeChain || (BridgeChain = {}));
3090
3095
  var UnifiedBalanceChain;
3091
3096
  (function(UnifiedBalanceChain) {
@@ -5634,7 +5639,8 @@ var EarnChain;
5634
5639
  isTestnet: true,
5635
5640
  explorerUrl: 'https://amoy.polygonscan.com/tx/{hash}',
5636
5641
  rpcEndpoints: [
5637
- 'https://rpc-amoy.polygon.technology'
5642
+ 'https://polygon-amoy-bor-rpc.publicnode.com',
5643
+ 'https://polygon-amoy.drpc.org'
5638
5644
  ],
5639
5645
  eurcAddress: null,
5640
5646
  usdcAddress: '0x41e94eb019c0762f9bfcf9fb1e58725bfb0e7582',
@@ -6499,6 +6505,104 @@ var EarnChain;
6499
6505
  }
6500
6506
  });
6501
6507
 
6508
+ /**
6509
+ * X Layer Mainnet chain definition
6510
+ * @remarks
6511
+ * This represents the official production network for the X Layer blockchain.
6512
+ * X Layer is an EVM-compatible OP Stack Layer-2 blockchain built by OKX,
6513
+ * using OKB as its native gas token. (Migrated from Polygon zkEVM/CDK to the
6514
+ * OP Stack on 2025-10-27; older docs describing it as zkEVM are obsolete.)
6515
+ */ const XLayer = defineChain({
6516
+ type: 'evm',
6517
+ chain: Blockchain.X_Layer,
6518
+ name: 'X Layer',
6519
+ title: 'X Layer Mainnet',
6520
+ nativeCurrency: {
6521
+ name: 'OKB',
6522
+ symbol: 'OKB',
6523
+ decimals: 18
6524
+ },
6525
+ chainId: 196,
6526
+ isTestnet: false,
6527
+ explorerUrl: 'https://www.oklink.com/xlayer/tx/{hash}',
6528
+ rpcEndpoints: [
6529
+ 'https://xlayerrpc.okx.com'
6530
+ ],
6531
+ eurcAddress: null,
6532
+ usdcAddress: '0xB6CEceAB302E2E4948951eE7843FC24E92933061',
6533
+ usdtAddress: null,
6534
+ cctp: {
6535
+ domain: 37,
6536
+ contracts: {
6537
+ v2: {
6538
+ type: 'split',
6539
+ tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
6540
+ messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
6541
+ confirmations: 65,
6542
+ fastConfirmations: 1
6543
+ }
6544
+ },
6545
+ forwarderSupported: {
6546
+ source: false,
6547
+ destination: false
6548
+ }
6549
+ },
6550
+ kitContracts: {
6551
+ bridge: BRIDGE_CONTRACT_EVM_MAINNET
6552
+ }
6553
+ });
6554
+
6555
+ /**
6556
+ * X Layer Testnet chain definition
6557
+ * @remarks
6558
+ * This represents the official test network for the X Layer blockchain.
6559
+ * X Layer is an EVM-compatible OP Stack Layer-2 blockchain built by OKX,
6560
+ * using OKB as its native gas token. (Migrated from Polygon zkEVM/CDK to the
6561
+ * OP Stack on 2025-10-27; older docs describing it as zkEVM are obsolete.)
6562
+ */ const XLayerTestnet = defineChain({
6563
+ type: 'evm',
6564
+ chain: Blockchain.X_Layer_Testnet,
6565
+ name: 'X Layer Testnet',
6566
+ title: 'X Layer Testnet',
6567
+ nativeCurrency: {
6568
+ name: 'OKB',
6569
+ symbol: 'OKB',
6570
+ decimals: 18
6571
+ },
6572
+ chainId: 1952,
6573
+ isTestnet: true,
6574
+ // Deliberately not oklink.com (used for mainnet): viem's bundled OKLink
6575
+ // testnet URL targets the deprecated pre-rebrand chain ID 195, not this
6576
+ // chain's ID (1952). Verified against the internal chain-expansion-scripts
6577
+ // config (`v2config.sandbox.yml`) — do not "normalize" this to match mainnet.
6578
+ explorerUrl: 'https://web3.okx.com/explorer/x-layer-testnet/tx/{hash}',
6579
+ rpcEndpoints: [
6580
+ 'https://testrpc.xlayer.tech'
6581
+ ],
6582
+ eurcAddress: null,
6583
+ usdcAddress: '0xDec90b78111Ba2fc6FC6d84d8B9ec159A2d4b9B3',
6584
+ usdtAddress: null,
6585
+ cctp: {
6586
+ domain: 37,
6587
+ contracts: {
6588
+ v2: {
6589
+ type: 'split',
6590
+ tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
6591
+ messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
6592
+ confirmations: 65,
6593
+ fastConfirmations: 1
6594
+ }
6595
+ },
6596
+ forwarderSupported: {
6597
+ source: false,
6598
+ destination: false
6599
+ }
6600
+ },
6601
+ kitContracts: {
6602
+ bridge: BRIDGE_CONTRACT_EVM_TESTNET
6603
+ }
6604
+ });
6605
+
6502
6606
  /**
6503
6607
  * ZKSync Era Mainnet chain definition
6504
6608
  * @remarks
@@ -6618,6 +6722,8 @@ var Chains = {
6618
6722
  WorldChainSepolia: WorldChainSepolia,
6619
6723
  XDC: XDC,
6620
6724
  XDCApothem: XDCApothem,
6725
+ XLayer: XLayer,
6726
+ XLayerTestnet: XLayerTestnet,
6621
6727
  ZKSyncEra: ZKSyncEra,
6622
6728
  ZKSyncEraSepolia: ZKSyncEraSepolia
6623
6729
  };
@@ -8646,6 +8752,7 @@ const swapTokenEnumSchema = zod.z.enum([
8646
8752
  [Blockchain.Unichain]: '0x078D782b760474a361dDA0AF3839290b0EF57AD6',
8647
8753
  [Blockchain.World_Chain]: '0x79A02482A880bCE3F13e09Da970dC34db4CD24d1',
8648
8754
  [Blockchain.XDC]: '0xfA2958CB79b0491CC627c1557F441eF849Ca8eb1',
8755
+ [Blockchain.X_Layer]: '0xB6CEceAB302E2E4948951eE7843FC24E92933061',
8649
8756
  [Blockchain.ZKSync_Era]: '0x1d17CBcF0D6D143135aE902365D2E5e2A16538D4',
8650
8757
  // =========================================================================
8651
8758
  // Testnets (alphabetically sorted)
@@ -8680,6 +8787,7 @@ const swapTokenEnumSchema = zod.z.enum([
8680
8787
  [Blockchain.Unichain_Sepolia]: '0x31d0220469e10c4E71834a79b1f276d740d3768F',
8681
8788
  [Blockchain.World_Chain_Sepolia]: '0x66145f38cBAC35Ca6F1Dfb4914dF98F1614aeA88',
8682
8789
  [Blockchain.XDC_Apothem]: '0xb5AB69F7bBada22B28e79C8FFAECe55eF1c771D4',
8790
+ [Blockchain.X_Layer_Testnet]: '0xDec90b78111Ba2fc6FC6d84d8B9ec159A2d4b9B3',
8683
8791
  [Blockchain.ZKSync_Sepolia]: '0xAe045DE5638162fa134807Cb558E15A3F5A7F853'
8684
8792
  }
8685
8793
  };
@@ -9967,7 +10075,7 @@ const swapTokenEnumSchema = zod.z.enum([
9967
10075
  }
9968
10076
 
9969
10077
  var name$2 = "@circle-fin/bridge-kit";
9970
- var version$2 = "1.12.2";
10078
+ var version$2 = "1.13.0";
9971
10079
  var pkg$2 = {
9972
10080
  name: name$2,
9973
10081
  version: version$2};
@@ -10003,13 +10111,21 @@ var pkg$2 = {
10003
10111
  computeFee: zod.z.function().returns(zod.z.string().or(zod.z.promise(zod.z.string()))).optional(),
10004
10112
  calculateFee: zod.z.function().returns(zod.z.string().or(zod.z.promise(zod.z.string()))).optional(),
10005
10113
  resolveFeeRecipientAddress: zod.z.function().returns(zod.z.string().or(zod.z.promise(zod.z.string())))
10006
- }).strict().refine((data)=>{
10114
+ }).strict().superRefine((data, ctx)=>{
10007
10115
  const hasComputeFee = data.computeFee !== undefined;
10008
10116
  const hasCalculateFee = data.calculateFee !== undefined;
10009
- // XOR: exactly one must be provided
10010
- return hasComputeFee !== hasCalculateFee;
10011
- }, {
10012
- message: 'Provide either computeFee or calculateFee, not both. Use computeFee (recommended) for human-readable amounts.'
10117
+ if (hasComputeFee && hasCalculateFee) {
10118
+ ctx.addIssue({
10119
+ code: zod.z.ZodIssueCode.custom,
10120
+ message: 'Provide either computeFee or calculateFee, not both. Use computeFee (recommended) for human-readable amounts.'
10121
+ });
10122
+ }
10123
+ if (!hasComputeFee && !hasCalculateFee) {
10124
+ ctx.addIssue({
10125
+ code: zod.z.ZodIssueCode.custom,
10126
+ message: 'Provide either computeFee or calculateFee. Use computeFee (recommended) for human-readable amounts.'
10127
+ });
10128
+ }
10013
10129
  });
10014
10130
 
10015
10131
  /**
@@ -10868,7 +10984,7 @@ var TransferSpeed;
10868
10984
  registerKit(`${pkg$2.name}/${pkg$2.version}`);
10869
10985
 
10870
10986
  var name$1 = "@circle-fin/swap-kit";
10871
- var version$1 = "1.5.0";
10987
+ var version$1 = "1.5.1";
10872
10988
  var pkg$1 = {
10873
10989
  name: name$1,
10874
10990
  version: version$1};
@@ -21073,7 +21189,9 @@ registerKit(`${pkg$1.name}/${pkg$1.version}`);
21073
21189
  disableAnalytics: context.disableAnalytics
21074
21190
  }
21075
21191
  });
21076
- if (hasBoth) {
21192
+ if (context.customFeePolicy?.swap != null) {
21193
+ kit.setCustomFeePolicy(context.customFeePolicy.swap);
21194
+ } else if (hasBoth) {
21077
21195
  kit.setCustomFeePolicy({
21078
21196
  computeFee: async (params)=>{
21079
21197
  // Adapt provider-level params (with tokenIn/tokenOut)
@@ -21132,7 +21250,7 @@ registerKit(`${pkg$1.name}/${pkg$1.version}`);
21132
21250
  };
21133
21251
 
21134
21252
  var name = "@circle-fin/earn-kit";
21135
- var version = "1.4.0";
21253
+ var version = "1.5.0";
21136
21254
  var pkg = {
21137
21255
  name: name,
21138
21256
  version: version};
@@ -22143,11 +22261,16 @@ const sourceAdapterContextSchema = zod.z.object({
22143
22261
  *
22144
22262
  * Validate the optional Kit Key field using the standard `apiKeySchema`
22145
22263
  * format (`KIT_KEY:<keyId>:<keySecret>`). When omitted, the SDK
22146
- * operates in permissionless mode.
22264
+ * operates in permissionless mode. `baseUrl` overrides the Earn Service
22265
+ * endpoint (e.g. staging); `batchTransactions: false` opts out of atomic
22266
+ * batched execution. Both are forwarded to the provider, so this `.strict()`
22267
+ * schema must accept them or a valid config object is rejected.
22147
22268
  *
22148
22269
  * @internal
22149
22270
  */ const earnConfigSchema = zod.z.object({
22150
- kitKey: apiKeySchema.optional()
22271
+ kitKey: apiKeySchema.optional(),
22272
+ baseUrl: zod.z.string().optional(),
22273
+ batchTransactions: zod.z.boolean().optional()
22151
22274
  }).strict();
22152
22275
  /**
22153
22276
  * Canonical decimal form: a leading digit with no leading zeros (a single