@circle-fin/app-kit 1.8.0 → 1.8.1

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/estimateSwap.mjs CHANGED
@@ -8557,13 +8557,20 @@ const swapTokenEnumSchema = z.enum([
8557
8557
  symbol: 'EURC',
8558
8558
  decimals: 6,
8559
8559
  locators: {
8560
+ // =========================================================================
8561
+ // Mainnets
8562
+ // =========================================================================
8560
8563
  [Blockchain.Avalanche]: '0xc891EB4cbdEFf6e073e859e987815Ed1505c2ACD',
8561
8564
  [Blockchain.Base]: '0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42',
8562
8565
  [Blockchain.Ethereum]: '0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c',
8563
8566
  [Blockchain.Solana]: 'HzwqbKZw8HxMN6bF2yFZNrht3c2iXXzpKcFu7uBEDKtr',
8564
8567
  [Blockchain.World_Chain]: '0x1C60ba0A0eD1019e8Eb035E6daF4155A5cE2380B',
8568
+ // =========================================================================
8565
8569
  // Testnets
8566
- [Blockchain.Arc_Testnet]: '0x89B50855Aa3bE2F677cD6303Cec089B5F319D72a'
8570
+ // =========================================================================
8571
+ [Blockchain.Arc_Testnet]: '0x89B50855Aa3bE2F677cD6303Cec089B5F319D72a',
8572
+ [Blockchain.Base_Sepolia]: '0x808456652fdb597867f38412077A9182bf77359F',
8573
+ [Blockchain.Ethereum_Sepolia]: '0x08210F9170F89Ab7658F0B5E3fF39b0E03C594D4'
8567
8574
  }
8568
8575
  };
8569
8576
 
@@ -8773,8 +8780,7 @@ const swapTokenEnumSchema = z.enum([
8773
8780
  * cirBTC (Circle Bitcoin) token definition with addresses and metadata.
8774
8781
  *
8775
8782
  * @remarks
8776
- * Built-in cirBTC definition for the TokenRegistry. Currently deployed
8777
- * on Arc Testnet.
8783
+ * Built-in cirBTC definition for the TokenRegistry.
8778
8784
  *
8779
8785
  * @example
8780
8786
  * ```typescript
@@ -8790,7 +8796,15 @@ const swapTokenEnumSchema = z.enum([
8790
8796
  symbol: 'cirBTC',
8791
8797
  decimals: 8,
8792
8798
  locators: {
8793
- [Blockchain.Arc_Testnet]: '0xf0C4a4CE82A5746AbAAd9425360Ab04fbBA432BF'
8799
+ // =========================================================================
8800
+ // Mainnets
8801
+ // =========================================================================
8802
+ [Blockchain.Ethereum]: '0x72DFB2E44f59C5AD2bAFE84314E5b99a7cd5075E',
8803
+ // =========================================================================
8804
+ // Testnets
8805
+ // =========================================================================
8806
+ [Blockchain.Arc_Testnet]: '0xf0C4a4CE82A5746AbAAd9425360Ab04fbBA432BF',
8807
+ [Blockchain.Ethereum_Sepolia]: '0x3a3fe695F684Bf9b9e43CF43C2b895Ea5e392bB3'
8794
8808
  }
8795
8809
  };
8796
8810
 
@@ -9742,7 +9756,7 @@ const swapTokenEnumSchema = z.enum([
9742
9756
  }
9743
9757
 
9744
9758
  var name$2 = "@circle-fin/bridge-kit";
9745
- var version$2 = "1.11.0";
9759
+ var version$2 = "1.11.1";
9746
9760
  var pkg$2 = {
9747
9761
  name: name$2,
9748
9762
  version: version$2};
@@ -10632,7 +10646,7 @@ var TransferSpeed;
10632
10646
  registerKit(`${pkg$2.name}/${pkg$2.version}`);
10633
10647
 
10634
10648
  var name$1 = "@circle-fin/swap-kit";
10635
- var version$1 = "1.3.0";
10649
+ var version$1 = "1.3.1";
10636
10650
  var pkg$1 = {
10637
10651
  name: name$1,
10638
10652
  version: version$1};
@@ -15038,6 +15052,19 @@ const TOKEN_REGISTRY = createTokenRegistry();
15038
15052
  *
15039
15053
  * @internal
15040
15054
  */ const SUPPORTED_CHAINS = getSwapSupportedChains(Chains);
15055
+ /**
15056
+ * Inter-poll delays (ms) for the same-chain `amountOut` enrichment loop.
15057
+ *
15058
+ * A same-chain swap is already terminal `DONE` once its source transaction
15059
+ * confirms; this short, escalating budget (~5s total across up to four polls)
15060
+ * gives the service a brief window to resolve the output amount before
15061
+ * `swap()` returns. The loop exits the instant `amountOut` is available.
15062
+ */ const SAME_CHAIN_AMOUNT_OUT_POLL_DELAYS_MS = [
15063
+ 1_000,
15064
+ 2_000,
15065
+ 2_000
15066
+ ];
15067
+ const sleep$2 = async (ms)=>new Promise((resolve)=>setTimeout(resolve, ms));
15041
15068
  function buildSwapProgress(statusResult) {
15042
15069
  return {
15043
15070
  status: statusResult.status,
@@ -15057,29 +15084,46 @@ async function fetchSameChainStatusSnapshot({ isCrossChainSwap, txHash, chain, a
15057
15084
  }
15058
15085
  };
15059
15086
  }
15060
- try {
15061
- const statusResult = await getSwapStatus$1({
15062
- txHash,
15063
- chain: chain.chain,
15064
- apiKey
15065
- });
15066
- const progress = buildSwapProgress(statusResult);
15067
- if (statusResult.status === 'DONE' && statusResult.amountOut !== undefined) {
15087
+ // A same-chain swap completes atomically in the source transaction, which
15088
+ // has already been confirmed (and receipt-checked for revert) by the time we
15089
+ // get here. Its terminal status is therefore `DONE`. We briefly poll the
15090
+ // status endpoint to enrich `amountOut`, which the service usually resolves
15091
+ // within a few seconds. A non-DONE/erroneous peek never downgrades the
15092
+ // status — once the short budget is exhausted we return `DONE` without
15093
+ // `amountOut`, and the caller can fetch it later via `getSwapStatus`.
15094
+ for(let attempt = 0;; attempt += 1){
15095
+ try {
15096
+ const statusResult = await getSwapStatus$1({
15097
+ txHash,
15098
+ chain: chain.chain,
15099
+ apiKey
15100
+ });
15101
+ if (statusResult.status === 'DONE' && statusResult.amountOut !== undefined) {
15102
+ return {
15103
+ progress: buildSwapProgress(statusResult),
15104
+ amountOut: statusResult.amountOut
15105
+ };
15106
+ }
15107
+ } catch {
15108
+ // Reachability/parse failure during enrichment — non-fatal; the swap
15109
+ // already succeeded on-chain. `getSwapStatus` already retried transient
15110
+ // network errors internally, so further polling is unlikely to help.
15068
15111
  return {
15069
- progress,
15070
- amountOut: statusResult.amountOut
15112
+ progress: {
15113
+ status: 'DONE'
15114
+ }
15071
15115
  };
15072
15116
  }
15073
- return {
15074
- progress
15075
- };
15076
- } catch {
15077
- // Non-fatal — the swap already succeeded on-chain. status stays PENDING.
15078
- return {
15079
- progress: {
15080
- status: 'PENDING'
15081
- }
15082
- };
15117
+ const delayMs = SAME_CHAIN_AMOUNT_OUT_POLL_DELAYS_MS[attempt];
15118
+ if (delayMs === undefined) {
15119
+ // Budget exhausted — terminal `DONE`, `amountOut` not yet available.
15120
+ return {
15121
+ progress: {
15122
+ status: 'DONE'
15123
+ }
15124
+ };
15125
+ }
15126
+ await sleep$2(delayMs);
15083
15127
  }
15084
15128
  }
15085
15129
  /**
@@ -15957,14 +16001,14 @@ async function fetchSameChainStatusSnapshot({ isCrossChainSwap, txHash, chain, a
15957
16001
  }
15958
16002
  // Build swap fees with adapter-backed formatting for unregistered tokens
15959
16003
  const swapResultFees = serviceResponse.fees ? await this.buildFormattedFees(serviceResponse.fees, chain, destinationChain, adapter, config?.customFee?.recipientAddress) : undefined;
15960
- // Best-effort enrichment: fetch amountOut and provider-reported status.
15961
- // Only performed for same-chain swaps they typically reach DONE within
15962
- // a few seconds of source-tx confirmation, so the peek is useful UX and
15963
- // adds minimal latency. Cross-chain swaps are skipped because the
15964
- // destination mint takes minutes (CCTPv2 attestation), meaning the peek
15965
- // would always return PENDING/WAIT_DESTINATION_TRANSACTION while still
15966
- // burning up to 30s of the load balancer's server-side wait. Callers
15967
- // should use `kit.getSwapStatus()` to poll cross-chain swaps to DONE.
16004
+ // Best-effort enrichment: briefly poll for amountOut on same-chain swaps.
16005
+ // They complete atomically in the (already-confirmed) source tx, so the
16006
+ // result is terminal `DONE` regardless; the short poll only adds amountOut
16007
+ // once the service has resolved it. Cross-chain swaps are skipped because
16008
+ // the destination mint takes minutes (CCTPv2 attestation), so polling would
16009
+ // always return PENDING/WAIT_DESTINATION_TRANSACTION while burning the
16010
+ // budget. Callers should use `kit.getSwapStatus()` to poll cross-chain
16011
+ // swaps to DONE.
15968
16012
  const statusSnapshot = await fetchSameChainStatusSnapshot({
15969
16013
  isCrossChainSwap,
15970
16014
  txHash,
@@ -20266,7 +20310,7 @@ registerKit(`${pkg$1.name}/${pkg$1.version}`);
20266
20310
  };
20267
20311
 
20268
20312
  var name = "@circle-fin/earn-kit";
20269
- var version = "1.2.0";
20313
+ var version = "1.2.1";
20270
20314
  var pkg = {
20271
20315
  name: name,
20272
20316
  version: version};
@@ -20305,20 +20349,7 @@ var pkg = {
20305
20349
  */ ({
20306
20350
  [Blockchain.Arc_Testnet]: CHAIN_TO_API[Blockchain.Arc_Testnet]
20307
20351
  });
20308
- /**
20309
- * Expected EIP-712 domain of the ERC-3009 authorization token per source
20310
- * chain.
20311
- *
20312
- * Cross-chain Earn deposits are USDC-only, but USDC deployments differ on the
20313
- * EIP-712 domain name: newer deployments use `USDC` while older ones (for
20314
- * example Arbitrum Sepolia) kept `USD Coin` from the FiatToken V2 upgrade.
20315
- * These values mirror the bridge service's per-chain domain table and the
20316
- * on-chain `DOMAIN_SEPARATOR` inputs. Asserted before signing so a tampered
20317
- * prepare response cannot point the signature at another token. The
20318
- * `satisfies` check forces a domain entry whenever a source chain is added.
20319
- *
20320
- * @internal
20321
- */ ({
20352
+ ({
20322
20353
  [Blockchain.Arbitrum_Sepolia]: {
20323
20354
  },
20324
20355
  [Blockchain.Base_Sepolia]: {
@@ -20354,6 +20385,7 @@ const hexSignatureSchema = evmSignatureSchema;
20354
20385
  const hexAddressSchema = evmAddressSchema;
20355
20386
  // '0x' prefix + 32 bytes * 2 hex chars.
20356
20387
  const BYTES32_HEX_LENGTH = 66;
20388
+ const bridgeFeeTokenSchema = hexAddressSchema;
20357
20389
  /**
20358
20390
  * Zod schema for a non-negative uint256-like value.
20359
20391
  *
@@ -20640,14 +20672,12 @@ const eip712DomainSchema = eip712DomainSchema$1.extend({
20640
20672
  *
20641
20673
  * The bridge prepare path returns one item per collected source fee (e.g.
20642
20674
  * `PRE_FINALITY` for the fast-burn fee and `FORWARD` for the destination
20643
- * forward fee), all denominated in the shared `feeToken`. The signed
20644
- * authorization `value` is `principal + sum(items[].amount)`, so the pre-sign
20645
- * guard parses these to recompute the expected value. Each item's `amount` is
20646
- * a base-unit decimal string in `feeToken` units.
20675
+ * forward fee), all denominated in the shared `feeToken`. Each item's `amount`
20676
+ * is a base-unit decimal string in `feeToken` units.
20647
20677
  *
20648
20678
  * @internal
20649
20679
  */ const bridgeFeeQuoteSchema = z.object({
20650
- feeToken: hexAddressSchema,
20680
+ feeToken: bridgeFeeTokenSchema,
20651
20681
  items: z.array(z.object({
20652
20682
  type: z.string(),
20653
20683
  amount: uint256LikeSchema
@@ -20663,6 +20693,12 @@ const eip712DomainSchema = eip712DomainSchema$1.extend({
20663
20693
  erc3009TypedData: erc3009TypedDataSchema,
20664
20694
  feeQuote: bridgeFeeQuoteSchema
20665
20695
  }).passthrough();
20696
+ const bridgeDepositPrepareReviewSchema = z.object({
20697
+ sourceChain: z.string(),
20698
+ destinationChain: z.string(),
20699
+ amount: amountJsonSchema,
20700
+ vaultAddress: hexAddressSchema
20701
+ }).passthrough();
20666
20702
  /**
20667
20703
  * Zod schema for the bridge deposit prepare payload.
20668
20704
  *
@@ -20674,7 +20710,7 @@ const eip712DomainSchema = eip712DomainSchema$1.extend({
20674
20710
  execId: bridgeDepositExecIdSchema,
20675
20711
  erc3009TypedData: bridgeDepositPreparedBundleSchema,
20676
20712
  expiresAt: z.string().datetime(),
20677
- review: z.unknown().optional()
20713
+ review: bridgeDepositPrepareReviewSchema
20678
20714
  });
20679
20715
  /**
20680
20716
  * Zod schema for the `POST /v1/earnKit/bridge/deposit/prepare` API response.
@@ -20953,6 +20989,10 @@ const eip712DomainSchema = eip712DomainSchema$1.extend({
20953
20989
  data: exploreVaultsPayloadSchema
20954
20990
  });
20955
20991
 
20992
+ // Intentionally built-ins-only: Earn bridge support is limited to SDK-known
20993
+ // token contracts plus the explicit ERC-3009 domain allowlist below.
20994
+ createTokenRegistry();
20995
+
20956
20996
  /**
20957
20997
  * Shared UTF-8 encoder for building the keccak input in
20958
20998
  * {@link isValidEip55Checksum}, hoisted to module scope to avoid allocating a
@@ -21075,10 +21115,9 @@ const sourceAdapterContextSchema = z.object({
21075
21115
  * Schema for validating human-readable decimal amount strings.
21076
21116
  *
21077
21117
  * Accept positive decimal strings like '100', '100.50', '0.001'. Reject
21078
- * zero, negative, non-numeric, and non-canonical strings. EarnKit
21079
- * same-chain amounts are USDC/EURC (6 decimals), so precision is capped at
21080
- * 6 to match the Earn Service and fail fast locally instead of leaking
21081
- * 7+ decimal-place inputs to the server.
21118
+ * zero, negative, non-numeric, and non-canonical strings. Same-chain
21119
+ * EarnKit vaults can use different asset precisions, so the service enforces
21120
+ * the vault-specific decimal cap after resolving the vault asset.
21082
21121
  *
21083
21122
  * @internal
21084
21123
  */ const amountSchema = z.string({
@@ -21087,32 +21126,15 @@ const sourceAdapterContextSchema = z.object({
21087
21126
  allowZero: false,
21088
21127
  regexMessage: AMOUNT_FORMAT_ERROR_MESSAGE,
21089
21128
  attributeName: 'amount',
21090
- maxDecimals: 6
21091
- })(z.string())).refine((value)=>CANONICAL_AMOUNT_REGEX.test(value), AMOUNT_FORMAT_ERROR_MESSAGE);
21092
- /**
21093
- * Schema for cross-chain deposit amount strings.
21094
- *
21095
- * Cross-chain Earn deposits are USDC-only, and the signed ERC-3009 value is
21096
- * denominated in USDC's 6 decimals. Reject more precise inputs up front so
21097
- * the signed value always equals the requested amount instead of a silent
21098
- * truncation. Non-canonical forms (leading dot, leading zeros) are rejected
21099
- * too, matching the Earn Service.
21100
- *
21101
- * @internal
21102
- */ const crossChainAmountSchema = z.string({
21103
- required_error: 'amount is required'
21104
- }).min(1, 'amount is required').pipe(createDecimalStringValidator({
21105
- allowZero: false,
21106
- regexMessage: AMOUNT_FORMAT_ERROR_MESSAGE,
21107
- attributeName: 'amount',
21108
- maxDecimals: 6
21129
+ maxDecimals: 18
21109
21130
  })(z.string())).refine((value)=>CANONICAL_AMOUNT_REGEX.test(value), AMOUNT_FORMAT_ERROR_MESSAGE);
21110
21131
  /**
21111
21132
  * Schema for cross-chain source fee caps.
21112
21133
  *
21113
- * Cross-chain source fees are denominated in USDC base units. Zero is valid
21114
- * when the quote contains no source-collected fees; otherwise the cap should be
21115
- * the caller-accepted total from a recent quote.
21134
+ * Cross-chain source fees are denominated in the quote's fee token. Zero is
21135
+ * valid when the quote contains no source-collected fees; otherwise the cap
21136
+ * should be the caller-accepted total from a recent quote. The provider
21137
+ * enforces the prepared bundle's fee-token precision before signing.
21116
21138
  *
21117
21139
  * @internal
21118
21140
  */ const crossChainMaxFeeSchema = z.string({
@@ -21121,7 +21143,7 @@ const sourceAdapterContextSchema = z.object({
21121
21143
  allowZero: true,
21122
21144
  regexMessage: AMOUNT_FORMAT_ERROR_MESSAGE,
21123
21145
  attributeName: 'maxFee',
21124
- maxDecimals: 6
21146
+ maxDecimals: 18
21125
21147
  })(z.string())).refine((value)=>CANONICAL_AMOUNT_REGEX.test(value), AMOUNT_FORMAT_ERROR_MESSAGE);
21126
21148
  /**
21127
21149
  * Build a schema for an optional non-negative decimal filter string.
@@ -21282,7 +21304,7 @@ const crossChainDepositDestinationSchema = z.object({
21282
21304
  from: sourceAdapterContextSchema,
21283
21305
  to: crossChainDepositDestinationSchema,
21284
21306
  vaultAddress: vaultAddressSchema,
21285
- amount: crossChainAmountSchema,
21307
+ amount: amountSchema,
21286
21308
  maxFee: crossChainMaxFeeSchema,
21287
21309
  transferSpeed: z.enum([
21288
21310
  'FAST',