@circle-fin/app-kit 1.17.0 → 1.18.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@circle-fin/app-kit",
3
- "version": "1.17.0",
3
+ "version": "1.18.0",
4
4
  "description": "A one-stop Circle SDK solution for building stablecoin (e.g. USDC) applications, with bridging, swapping, and more on-chain operations",
5
5
  "keywords": [
6
6
  "circle",
@@ -36,13 +36,13 @@
36
36
  "module": "./index.mjs",
37
37
  "types": "./index.d.cts",
38
38
  "dependencies": {
39
- "@circle-fin/onramp-kit": "1.0.4",
40
- "@circle-fin/unified-balance-kit": "1.8.1",
41
- "@circle-fin/provider-gateway-v1": "1.5.2",
42
- "@circle-fin/earn-kit": "1.9.0",
43
- "@circle-fin/borrow-kit": "1.1.0",
44
- "@circle-fin/bridge-kit": "1.15.3",
45
- "@circle-fin/swap-kit": "1.8.0",
39
+ "@circle-fin/onramp-kit": "1.0.5",
40
+ "@circle-fin/unified-balance-kit": "1.8.2",
41
+ "@circle-fin/provider-gateway-v1": "1.5.3",
42
+ "@circle-fin/earn-kit": "1.10.0",
43
+ "@circle-fin/borrow-kit": "1.1.1",
44
+ "@circle-fin/bridge-kit": "1.16.0",
45
+ "@circle-fin/swap-kit": "1.8.1",
46
46
  "@coral-xyz/anchor": "^0.31.1",
47
47
  "@noble/curves": "1.4.2",
48
48
  "bn.js": "^5.2.3",
package/server.cjs CHANGED
@@ -1900,14 +1900,14 @@ var BorrowChain;
1900
1900
  symbol: 'USDC',
1901
1901
  // Arc uses native USDC with 18 decimals for gas payments (EVM standard).
1902
1902
  // Note: The ERC-20 USDC contract at usdcAddress uses 6 decimals.
1903
- // See: https://docs.arc.network/arc/references/contract-addresses
1903
+ // See: https://docs.arc.io/arc/references/contract-addresses
1904
1904
  decimals: 18
1905
1905
  },
1906
1906
  chainId: 5042002,
1907
1907
  isTestnet: true,
1908
1908
  explorerUrl: 'https://testnet.arcscan.app/tx/{hash}',
1909
1909
  rpcEndpoints: [
1910
- 'https://rpc.testnet.arc.network/'
1910
+ 'https://rpc.testnet.arc.io'
1911
1911
  ],
1912
1912
  eurcAddress: '0x89B50855Aa3bE2F677cD6303Cec089B5F319D72a',
1913
1913
  usdcAddress: '0x3600000000000000000000000000000000000000',
@@ -8755,7 +8755,7 @@ const swapTokenEnumSchema = zod.z.enum([
8755
8755
  return kit;
8756
8756
  }
8757
8757
 
8758
- var version = "1.0.4";
8758
+ var version = "1.0.5";
8759
8759
  var pkg = {
8760
8760
  version: version};
8761
8761
 
package/server.mjs CHANGED
@@ -1894,14 +1894,14 @@ var BorrowChain;
1894
1894
  symbol: 'USDC',
1895
1895
  // Arc uses native USDC with 18 decimals for gas payments (EVM standard).
1896
1896
  // Note: The ERC-20 USDC contract at usdcAddress uses 6 decimals.
1897
- // See: https://docs.arc.network/arc/references/contract-addresses
1897
+ // See: https://docs.arc.io/arc/references/contract-addresses
1898
1898
  decimals: 18
1899
1899
  },
1900
1900
  chainId: 5042002,
1901
1901
  isTestnet: true,
1902
1902
  explorerUrl: 'https://testnet.arcscan.app/tx/{hash}',
1903
1903
  rpcEndpoints: [
1904
- 'https://rpc.testnet.arc.network/'
1904
+ 'https://rpc.testnet.arc.io'
1905
1905
  ],
1906
1906
  eurcAddress: '0x89B50855Aa3bE2F677cD6303Cec089B5F319D72a',
1907
1907
  usdcAddress: '0x3600000000000000000000000000000000000000',
@@ -8749,7 +8749,7 @@ const swapTokenEnumSchema = z.enum([
8749
8749
  return kit;
8750
8750
  }
8751
8751
 
8752
- var version = "1.0.4";
8752
+ var version = "1.0.5";
8753
8753
  var pkg = {
8754
8754
  version: version};
8755
8755
 
package/swap.cjs CHANGED
@@ -3895,14 +3895,14 @@ var BorrowChain;
3895
3895
  symbol: 'USDC',
3896
3896
  // Arc uses native USDC with 18 decimals for gas payments (EVM standard).
3897
3897
  // Note: The ERC-20 USDC contract at usdcAddress uses 6 decimals.
3898
- // See: https://docs.arc.network/arc/references/contract-addresses
3898
+ // See: https://docs.arc.io/arc/references/contract-addresses
3899
3899
  decimals: 18
3900
3900
  },
3901
3901
  chainId: 5042002,
3902
3902
  isTestnet: true,
3903
3903
  explorerUrl: 'https://testnet.arcscan.app/tx/{hash}',
3904
3904
  rpcEndpoints: [
3905
- 'https://rpc.testnet.arc.network/'
3905
+ 'https://rpc.testnet.arc.io'
3906
3906
  ],
3907
3907
  eurcAddress: '0x89B50855Aa3bE2F677cD6303Cec089B5F319D72a',
3908
3908
  usdcAddress: '0x3600000000000000000000000000000000000000',
@@ -10848,7 +10848,7 @@ const swapTokenEnumSchema = zod.z.enum([
10848
10848
  }
10849
10849
 
10850
10850
  var name$3 = "@circle-fin/bridge-kit";
10851
- var version$3 = "1.15.3";
10851
+ var version$3 = "1.16.0";
10852
10852
  var pkg$3 = {
10853
10853
  name: name$3,
10854
10854
  version: version$3};
@@ -12503,7 +12503,7 @@ const validateQuoteItemSchema = zod.z.object({
12503
12503
  registerKit(`${pkg$3.name}/${pkg$3.version}`);
12504
12504
 
12505
12505
  var name$2 = "@circle-fin/swap-kit";
12506
- var version$2 = "1.8.0";
12506
+ var version$2 = "1.8.1";
12507
12507
  var pkg$2 = {
12508
12508
  name: name$2,
12509
12509
  version: version$2};
@@ -23176,7 +23176,7 @@ registerKit(`${pkg$2.name}/${pkg$2.version}`);
23176
23176
  };
23177
23177
 
23178
23178
  var name$1 = "@circle-fin/earn-kit";
23179
- var version$1 = "1.9.0";
23179
+ var version$1 = "1.10.0";
23180
23180
  var pkg$1 = {
23181
23181
  name: name$1,
23182
23182
  version: version$1};
@@ -24616,7 +24616,7 @@ function hasCrossChainDepositQuoteShape(params) {
24616
24616
  registerKit(`${pkg$1.name}/${pkg$1.version}`);
24617
24617
 
24618
24618
  var name = "@circle-fin/borrow-kit";
24619
- var version = "1.1.0";
24619
+ var version = "1.1.1";
24620
24620
  var pkg = {
24621
24621
  name: name,
24622
24622
  version: version};
package/swap.d.cts CHANGED
@@ -8568,11 +8568,11 @@ interface AppKitContext {
8568
8568
  */
8569
8569
  actions: Record<'bridge' | 'earn' | 'borrow', Record<string, ((payload: unknown) => void)[]>>;
8570
8570
  /**
8571
- * Disable success analytics for the underlying EarnKit, SwapKit,
8571
+ * Disable success analytics for the underlying BridgeKit, EarnKit, SwapKit,
8572
8572
  * BorrowKit, and UnifiedBalanceKit.
8573
8573
  *
8574
- * When `true`, completed earn, swap, borrow, and unified balance operations
8575
- * will not POST analytics events. This does not disable error reporting; use
8574
+ * When `true`, completed bridge, earn, swap, borrow, and unified balance
8575
+ * operations will not POST analytics events. This does not disable error reporting; use
8576
8576
  * {@link AppKitContext.disableErrorReporting} for that. Defaults to `false`.
8577
8577
  *
8578
8578
  * @defaultValue false
package/swap.d.mts CHANGED
@@ -8568,11 +8568,11 @@ interface AppKitContext {
8568
8568
  */
8569
8569
  actions: Record<'bridge' | 'earn' | 'borrow', Record<string, ((payload: unknown) => void)[]>>;
8570
8570
  /**
8571
- * Disable success analytics for the underlying EarnKit, SwapKit,
8571
+ * Disable success analytics for the underlying BridgeKit, EarnKit, SwapKit,
8572
8572
  * BorrowKit, and UnifiedBalanceKit.
8573
8573
  *
8574
- * When `true`, completed earn, swap, borrow, and unified balance operations
8575
- * will not POST analytics events. This does not disable error reporting; use
8574
+ * When `true`, completed bridge, earn, swap, borrow, and unified balance
8575
+ * operations will not POST analytics events. This does not disable error reporting; use
8576
8576
  * {@link AppKitContext.disableErrorReporting} for that. Defaults to `false`.
8577
8577
  *
8578
8578
  * @defaultValue false
package/swap.d.ts CHANGED
@@ -8568,11 +8568,11 @@ interface AppKitContext {
8568
8568
  */
8569
8569
  actions: Record<'bridge' | 'earn' | 'borrow', Record<string, ((payload: unknown) => void)[]>>;
8570
8570
  /**
8571
- * Disable success analytics for the underlying EarnKit, SwapKit,
8571
+ * Disable success analytics for the underlying BridgeKit, EarnKit, SwapKit,
8572
8572
  * BorrowKit, and UnifiedBalanceKit.
8573
8573
  *
8574
- * When `true`, completed earn, swap, borrow, and unified balance operations
8575
- * will not POST analytics events. This does not disable error reporting; use
8574
+ * When `true`, completed bridge, earn, swap, borrow, and unified balance
8575
+ * operations will not POST analytics events. This does not disable error reporting; use
8576
8576
  * {@link AppKitContext.disableErrorReporting} for that. Defaults to `false`.
8577
8577
  *
8578
8578
  * @defaultValue false
package/swap.mjs CHANGED
@@ -3888,14 +3888,14 @@ var BorrowChain;
3888
3888
  symbol: 'USDC',
3889
3889
  // Arc uses native USDC with 18 decimals for gas payments (EVM standard).
3890
3890
  // Note: The ERC-20 USDC contract at usdcAddress uses 6 decimals.
3891
- // See: https://docs.arc.network/arc/references/contract-addresses
3891
+ // See: https://docs.arc.io/arc/references/contract-addresses
3892
3892
  decimals: 18
3893
3893
  },
3894
3894
  chainId: 5042002,
3895
3895
  isTestnet: true,
3896
3896
  explorerUrl: 'https://testnet.arcscan.app/tx/{hash}',
3897
3897
  rpcEndpoints: [
3898
- 'https://rpc.testnet.arc.network/'
3898
+ 'https://rpc.testnet.arc.io'
3899
3899
  ],
3900
3900
  eurcAddress: '0x89B50855Aa3bE2F677cD6303Cec089B5F319D72a',
3901
3901
  usdcAddress: '0x3600000000000000000000000000000000000000',
@@ -10841,7 +10841,7 @@ const swapTokenEnumSchema = z.enum([
10841
10841
  }
10842
10842
 
10843
10843
  var name$3 = "@circle-fin/bridge-kit";
10844
- var version$3 = "1.15.3";
10844
+ var version$3 = "1.16.0";
10845
10845
  var pkg$3 = {
10846
10846
  name: name$3,
10847
10847
  version: version$3};
@@ -12496,7 +12496,7 @@ const validateQuoteItemSchema = z.object({
12496
12496
  registerKit(`${pkg$3.name}/${pkg$3.version}`);
12497
12497
 
12498
12498
  var name$2 = "@circle-fin/swap-kit";
12499
- var version$2 = "1.8.0";
12499
+ var version$2 = "1.8.1";
12500
12500
  var pkg$2 = {
12501
12501
  name: name$2,
12502
12502
  version: version$2};
@@ -23169,7 +23169,7 @@ registerKit(`${pkg$2.name}/${pkg$2.version}`);
23169
23169
  };
23170
23170
 
23171
23171
  var name$1 = "@circle-fin/earn-kit";
23172
- var version$1 = "1.9.0";
23172
+ var version$1 = "1.10.0";
23173
23173
  var pkg$1 = {
23174
23174
  name: name$1,
23175
23175
  version: version$1};
@@ -24609,7 +24609,7 @@ function hasCrossChainDepositQuoteShape(params) {
24609
24609
  registerKit(`${pkg$1.name}/${pkg$1.version}`);
24610
24610
 
24611
24611
  var name = "@circle-fin/borrow-kit";
24612
- var version = "1.1.0";
24612
+ var version = "1.1.1";
24613
24613
  var pkg = {
24614
24614
  name: name,
24615
24615
  version: version};
@@ -4394,14 +4394,14 @@ var BorrowChain;
4394
4394
  symbol: 'USDC',
4395
4395
  // Arc uses native USDC with 18 decimals for gas payments (EVM standard).
4396
4396
  // Note: The ERC-20 USDC contract at usdcAddress uses 6 decimals.
4397
- // See: https://docs.arc.network/arc/references/contract-addresses
4397
+ // See: https://docs.arc.io/arc/references/contract-addresses
4398
4398
  decimals: 18
4399
4399
  },
4400
4400
  chainId: 5042002,
4401
4401
  isTestnet: true,
4402
4402
  explorerUrl: 'https://testnet.arcscan.app/tx/{hash}',
4403
4403
  rpcEndpoints: [
4404
- 'https://rpc.testnet.arc.network/'
4404
+ 'https://rpc.testnet.arc.io'
4405
4405
  ],
4406
4406
  eurcAddress: '0x89B50855Aa3bE2F677cD6303Cec089B5F319D72a',
4407
4407
  usdcAddress: '0x3600000000000000000000000000000000000000',
@@ -11958,7 +11958,7 @@ function resolveOptions(options) {
11958
11958
  }
11959
11959
 
11960
11960
  var name = "@circle-fin/unified-balance-kit";
11961
- var version$1 = "1.8.1";
11961
+ var version$1 = "1.8.2";
11962
11962
  var pkg$1 = {
11963
11963
  name: name,
11964
11964
  version: version$1};
@@ -26551,6 +26551,24 @@ const FAST_TIER_FINALITY_THRESHOLD = 1000;
26551
26551
  }
26552
26552
  };
26553
26553
 
26554
+ /**
26555
+ * Check whether a forwarded burn to the given destination asks Circle's
26556
+ * Forwarding Service to set up the recipient's token account before minting.
26557
+ *
26558
+ * Must return `true` exactly for the destinations where
26559
+ * {@link getForwarderHookData} emits the `createAta` frame, so the forwarding
26560
+ * fee quote includes the setup rent whenever the burn requests it.
26561
+ *
26562
+ * @internal
26563
+ * @param chainType - The destination blockchain type.
26564
+ * @returns `true` for Solana destinations, `false` otherwise.
26565
+ *
26566
+ * @example
26567
+ * ```typescript
26568
+ * requiresRecipientSetup('solana') // true
26569
+ * requiresRecipientSetup('evm') // false
26570
+ * ```
26571
+ */ const requiresRecipientSetup = (chainType)=>chainType === 'solana';
26554
26572
  /**
26555
26573
  * Build the forwarding `hookData` for a forwarded (Orbit-relayed) CCTP v2 burn,
26556
26574
  * tailored to the destination chain.
@@ -26901,10 +26919,12 @@ const FAST_TIER_FINALITY_THRESHOLD = 1000;
26901
26919
  * @param sourceDomain - The source domain
26902
26920
  * @param destinationDomain - The destination domain
26903
26921
  * @param isTestnet - Whether the request is for a testnet chain
26922
+ * @param includeRecipientSetup - Whether the quote includes recipient account setup rent
26904
26923
  * @returns The complete API URL with forward=true query parameter
26905
- */ function buildForwardingFeeUrl(sourceDomain, destinationDomain, isTestnet) {
26924
+ */ function buildForwardingFeeUrl(sourceDomain, destinationDomain, isTestnet, includeRecipientSetup) {
26906
26925
  const baseUrl = isTestnet ? IRIS_API_SANDBOX_BASE_URL : IRIS_API_BASE_URL;
26907
- return `${baseUrl}/v2/burn/USDC/fees/${sourceDomain.toString()}/${destinationDomain.toString()}?forward=true`;
26926
+ const recipientSetupQuery = includeRecipientSetup ? '&includeRecipientSetup=true' : '';
26927
+ return `${baseUrl}/v2/burn/USDC/fees/${sourceDomain.toString()}/${destinationDomain.toString()}?forward=true${recipientSetupQuery}`;
26908
26928
  }
26909
26929
  /**
26910
26930
  * Fetches the forwarding fee for a USDC transfer operation with retry and timeout handling.
@@ -26921,6 +26941,10 @@ const FAST_TIER_FINALITY_THRESHOLD = 1000;
26921
26941
  *
26922
26942
  * The high fee tier is always used to provide buffer for destination gas fluctuations.
26923
26943
  *
26944
+ * Pass `includeRecipientSetup: true` when the burn asks the Forwarding Service to create
26945
+ * the recipient's token account (Solana destinations). The quote then includes the
26946
+ * account rent, which the quote without this flag leaves out.
26947
+ *
26924
26948
  * Implements timeout and retry logic to handle network issues and temporary API failures.
26925
26949
  * Each HTTP request is given a maximum of 2 seconds before it is aborted.
26926
26950
  * We retry up to 10 times, waiting 200ms between attempts.
@@ -26929,6 +26953,8 @@ const FAST_TIER_FINALITY_THRESHOLD = 1000;
26929
26953
  * @param destinationDomain - The destination domain
26930
26954
  * @param isTestnet - Whether the request is for a testnet chain
26931
26955
  * @param finalityThreshold - The finality threshold to select the fee tier (1000 for FAST, 2000 for SLOW)
26956
+ * @param includeRecipientSetup - Whether to include recipient account setup rent in the
26957
+ * quote. Defaults to `false`.
26932
26958
  * @returns The high-tier forwarding fee in USDC minor units (6 decimals)
26933
26959
  * @throws Error if the input domains are invalid, the API request fails, returns invalid data, or network errors occur
26934
26960
  *
@@ -26940,8 +26966,11 @@ const FAST_TIER_FINALITY_THRESHOLD = 1000;
26940
26966
  *
26941
26967
  * // SLOW transfer - use 2000ms finality threshold
26942
26968
  * const slowForwardingFee = await fetchForwardingFee(0, 6, false, 2000)
26969
+ *
26970
+ * // Ethereum -> Solana: include the recipient token account rent
26971
+ * const solanaForwardingFee = await fetchForwardingFee(0, 5, false, 1000, true)
26943
26972
  * ```
26944
- */ async function fetchForwardingFee(sourceDomain, destinationDomain, isTestnet, finalityThreshold) {
26973
+ */ async function fetchForwardingFee(sourceDomain, destinationDomain, isTestnet, finalityThreshold, includeRecipientSetup = false) {
26945
26974
  // Validate source domain
26946
26975
  if (!Number.isInteger(sourceDomain) || sourceDomain < 0) {
26947
26976
  throw new KitError({
@@ -26969,7 +26998,7 @@ const FAST_TIER_FINALITY_THRESHOLD = 1000;
26969
26998
  });
26970
26999
  }
26971
27000
  // Fetch the fee tiers from the API with forward=true
26972
- const url = buildForwardingFeeUrl(sourceDomain, destinationDomain, isTestnet);
27001
+ const url = buildForwardingFeeUrl(sourceDomain, destinationDomain, isTestnet, includeRecipientSetup);
26973
27002
  const response = await pollApiGet(url, isForwardingFeeResponse, DEFAULT_CONFIG$1);
26974
27003
  // Validate that we have at least one fee tier
26975
27004
  if (response.length === 0) {
@@ -29305,7 +29334,7 @@ const mockAttestationMessage = {
29305
29334
  return step;
29306
29335
  }
29307
29336
 
29308
- var version = "1.14.2";
29337
+ var version = "1.14.3";
29309
29338
  var pkg = {
29310
29339
  version: version};
29311
29340
 
@@ -30224,9 +30253,34 @@ function assertCCTPV2Config(config) {
30224
30253
  tokenAddress: source.chain.usdcAddress,
30225
30254
  operationContext: sourceOperationContext
30226
30255
  });
30256
+ await this.assertAmountCoversRecipientSetupFee(params);
30227
30257
  return bridge(params, this);
30228
30258
  }
30229
30259
  /**
30260
+ * Reject a forwarded transfer to Solana whose amount does not exceed the fee.
30261
+ *
30262
+ * CCTP v2 reverts a burn whose `maxFee` is not less than its amount, and the Solana
30263
+ * forwarding fee includes the recipient token account rent. Checking before the
30264
+ * approval avoids sending a transaction that can never be followed by a burn.
30265
+ * Skipped when the caller provides `config.maxFee`.
30266
+ *
30267
+ * @param params - The validated CCTP v2 bridge parameters.
30268
+ * @returns A promise that resolves when the amount covers the fee.
30269
+ * @throws {KitError} INPUT_INVALID_AMOUNT (FATAL) when the fee is greater than or equal
30270
+ * to the amount.
30271
+ */ async assertAmountCoversRecipientSetupFee(params) {
30272
+ const { destination, amount, config } = params;
30273
+ if (destination.useForwarder !== true || config.maxFee !== undefined || !requiresRecipientSetup(destination.chain.type)) {
30274
+ return;
30275
+ }
30276
+ const { providerFee, forwarderFee } = await this.getMaxFee(params);
30277
+ const maxFee = providerFee + forwarderFee;
30278
+ if (maxFee >= BigInt(amount)) {
30279
+ // Amounts and fees are in USDC minor units (6 decimals)
30280
+ throw createInvalidAmountError(formatUnits(amount, 6), `Amount must be greater than the ${formatUnits(String(maxFee), 6)} USDC fee for forwarded transfers to ${destination.chain.name}, which includes creating the recipient's token account`);
30281
+ }
30282
+ }
30283
+ /**
30230
30284
  * Retry a failed or incomplete CCTP v2 bridge operation.
30231
30285
  *
30232
30286
  * Analyzes the bridge result to determine where to continue and executes
@@ -30943,6 +30997,9 @@ function assertCCTPV2Config(config) {
30943
30997
  * | FAST | true | No | maxFee = calculatedBurnFee + forwardingFee |
30944
30998
  * | FAST | true | Yes | maxFee = config.maxFee |
30945
30999
  *
31000
+ * For forwarded burns to Solana, the forwarding fee includes the rent for creating the
31001
+ * recipient's token account. A caller-provided `maxFee` must cover it too.
31002
+ *
30946
31003
  * @param params - The bridge parameters object containing:
30947
31004
  * - `source`: The source wallet context with chain definition and adapter
30948
31005
  * - `destination`: The destination wallet context with chain definition and adapter
@@ -30981,6 +31038,7 @@ function assertCCTPV2Config(config) {
30981
31038
  }
30982
31039
  // Get the min finality threshold based on the transfer speed
30983
31040
  const minFinalityThreshold = CCTPv2MinFinalityThreshold[transferSpeed];
31041
+ const includeRecipientSetup = requiresRecipientSetup(destination.chain.type);
30984
31042
  // SLOW transfer without forwarder: no fee
30985
31043
  if (transferSpeed === TransferSpeed.SLOW && !useForwarder) {
30986
31044
  return {
@@ -30990,7 +31048,7 @@ function assertCCTPV2Config(config) {
30990
31048
  }
30991
31049
  // SLOW transfer with forwarder: only forwarding fee
30992
31050
  if (transferSpeed === TransferSpeed.SLOW && useForwarder) {
30993
- const forwarderFee = await fetchForwardingFee(source.chain.cctp.domain, destination.chain.cctp.domain, source.chain.isTestnet, minFinalityThreshold);
31051
+ const forwarderFee = await fetchForwardingFee(source.chain.cctp.domain, destination.chain.cctp.domain, source.chain.isTestnet, minFinalityThreshold, includeRecipientSetup);
30994
31052
  return {
30995
31053
  providerFee: 0n,
30996
31054
  forwarderFee
@@ -31000,7 +31058,7 @@ function assertCCTPV2Config(config) {
31000
31058
  // Fetch fees in parallel when forwarder is enabled
31001
31059
  const [scaledBps, forwarderFee] = await Promise.all([
31002
31060
  fetchUsdcFastBurnFee(source.chain.cctp.domain, destination.chain.cctp.domain, source.chain.isTestnet),
31003
- useForwarder ? fetchForwardingFee(source.chain.cctp.domain, destination.chain.cctp.domain, source.chain.isTestnet, minFinalityThreshold) : Promise.resolve(0n)
31061
+ useForwarder ? fetchForwardingFee(source.chain.cctp.domain, destination.chain.cctp.domain, source.chain.isTestnet, minFinalityThreshold, includeRecipientSetup) : Promise.resolve(0n)
31004
31062
  ]);
31005
31063
  // Calculate fee proportional to the transfer amount
31006
31064
  const amountInMinorUnits = BigInt(amount);
@@ -4387,14 +4387,14 @@ var BorrowChain;
4387
4387
  symbol: 'USDC',
4388
4388
  // Arc uses native USDC with 18 decimals for gas payments (EVM standard).
4389
4389
  // Note: The ERC-20 USDC contract at usdcAddress uses 6 decimals.
4390
- // See: https://docs.arc.network/arc/references/contract-addresses
4390
+ // See: https://docs.arc.io/arc/references/contract-addresses
4391
4391
  decimals: 18
4392
4392
  },
4393
4393
  chainId: 5042002,
4394
4394
  isTestnet: true,
4395
4395
  explorerUrl: 'https://testnet.arcscan.app/tx/{hash}',
4396
4396
  rpcEndpoints: [
4397
- 'https://rpc.testnet.arc.network/'
4397
+ 'https://rpc.testnet.arc.io'
4398
4398
  ],
4399
4399
  eurcAddress: '0x89B50855Aa3bE2F677cD6303Cec089B5F319D72a',
4400
4400
  usdcAddress: '0x3600000000000000000000000000000000000000',
@@ -11951,7 +11951,7 @@ function resolveOptions(options) {
11951
11951
  }
11952
11952
 
11953
11953
  var name = "@circle-fin/unified-balance-kit";
11954
- var version$1 = "1.8.1";
11954
+ var version$1 = "1.8.2";
11955
11955
  var pkg$1 = {
11956
11956
  name: name,
11957
11957
  version: version$1};
@@ -26544,6 +26544,24 @@ const FAST_TIER_FINALITY_THRESHOLD = 1000;
26544
26544
  }
26545
26545
  };
26546
26546
 
26547
+ /**
26548
+ * Check whether a forwarded burn to the given destination asks Circle's
26549
+ * Forwarding Service to set up the recipient's token account before minting.
26550
+ *
26551
+ * Must return `true` exactly for the destinations where
26552
+ * {@link getForwarderHookData} emits the `createAta` frame, so the forwarding
26553
+ * fee quote includes the setup rent whenever the burn requests it.
26554
+ *
26555
+ * @internal
26556
+ * @param chainType - The destination blockchain type.
26557
+ * @returns `true` for Solana destinations, `false` otherwise.
26558
+ *
26559
+ * @example
26560
+ * ```typescript
26561
+ * requiresRecipientSetup('solana') // true
26562
+ * requiresRecipientSetup('evm') // false
26563
+ * ```
26564
+ */ const requiresRecipientSetup = (chainType)=>chainType === 'solana';
26547
26565
  /**
26548
26566
  * Build the forwarding `hookData` for a forwarded (Orbit-relayed) CCTP v2 burn,
26549
26567
  * tailored to the destination chain.
@@ -26894,10 +26912,12 @@ const FAST_TIER_FINALITY_THRESHOLD = 1000;
26894
26912
  * @param sourceDomain - The source domain
26895
26913
  * @param destinationDomain - The destination domain
26896
26914
  * @param isTestnet - Whether the request is for a testnet chain
26915
+ * @param includeRecipientSetup - Whether the quote includes recipient account setup rent
26897
26916
  * @returns The complete API URL with forward=true query parameter
26898
- */ function buildForwardingFeeUrl(sourceDomain, destinationDomain, isTestnet) {
26917
+ */ function buildForwardingFeeUrl(sourceDomain, destinationDomain, isTestnet, includeRecipientSetup) {
26899
26918
  const baseUrl = isTestnet ? IRIS_API_SANDBOX_BASE_URL : IRIS_API_BASE_URL;
26900
- return `${baseUrl}/v2/burn/USDC/fees/${sourceDomain.toString()}/${destinationDomain.toString()}?forward=true`;
26919
+ const recipientSetupQuery = includeRecipientSetup ? '&includeRecipientSetup=true' : '';
26920
+ return `${baseUrl}/v2/burn/USDC/fees/${sourceDomain.toString()}/${destinationDomain.toString()}?forward=true${recipientSetupQuery}`;
26901
26921
  }
26902
26922
  /**
26903
26923
  * Fetches the forwarding fee for a USDC transfer operation with retry and timeout handling.
@@ -26914,6 +26934,10 @@ const FAST_TIER_FINALITY_THRESHOLD = 1000;
26914
26934
  *
26915
26935
  * The high fee tier is always used to provide buffer for destination gas fluctuations.
26916
26936
  *
26937
+ * Pass `includeRecipientSetup: true` when the burn asks the Forwarding Service to create
26938
+ * the recipient's token account (Solana destinations). The quote then includes the
26939
+ * account rent, which the quote without this flag leaves out.
26940
+ *
26917
26941
  * Implements timeout and retry logic to handle network issues and temporary API failures.
26918
26942
  * Each HTTP request is given a maximum of 2 seconds before it is aborted.
26919
26943
  * We retry up to 10 times, waiting 200ms between attempts.
@@ -26922,6 +26946,8 @@ const FAST_TIER_FINALITY_THRESHOLD = 1000;
26922
26946
  * @param destinationDomain - The destination domain
26923
26947
  * @param isTestnet - Whether the request is for a testnet chain
26924
26948
  * @param finalityThreshold - The finality threshold to select the fee tier (1000 for FAST, 2000 for SLOW)
26949
+ * @param includeRecipientSetup - Whether to include recipient account setup rent in the
26950
+ * quote. Defaults to `false`.
26925
26951
  * @returns The high-tier forwarding fee in USDC minor units (6 decimals)
26926
26952
  * @throws Error if the input domains are invalid, the API request fails, returns invalid data, or network errors occur
26927
26953
  *
@@ -26933,8 +26959,11 @@ const FAST_TIER_FINALITY_THRESHOLD = 1000;
26933
26959
  *
26934
26960
  * // SLOW transfer - use 2000ms finality threshold
26935
26961
  * const slowForwardingFee = await fetchForwardingFee(0, 6, false, 2000)
26962
+ *
26963
+ * // Ethereum -> Solana: include the recipient token account rent
26964
+ * const solanaForwardingFee = await fetchForwardingFee(0, 5, false, 1000, true)
26936
26965
  * ```
26937
- */ async function fetchForwardingFee(sourceDomain, destinationDomain, isTestnet, finalityThreshold) {
26966
+ */ async function fetchForwardingFee(sourceDomain, destinationDomain, isTestnet, finalityThreshold, includeRecipientSetup = false) {
26938
26967
  // Validate source domain
26939
26968
  if (!Number.isInteger(sourceDomain) || sourceDomain < 0) {
26940
26969
  throw new KitError({
@@ -26962,7 +26991,7 @@ const FAST_TIER_FINALITY_THRESHOLD = 1000;
26962
26991
  });
26963
26992
  }
26964
26993
  // Fetch the fee tiers from the API with forward=true
26965
- const url = buildForwardingFeeUrl(sourceDomain, destinationDomain, isTestnet);
26994
+ const url = buildForwardingFeeUrl(sourceDomain, destinationDomain, isTestnet, includeRecipientSetup);
26966
26995
  const response = await pollApiGet(url, isForwardingFeeResponse, DEFAULT_CONFIG$1);
26967
26996
  // Validate that we have at least one fee tier
26968
26997
  if (response.length === 0) {
@@ -29298,7 +29327,7 @@ const mockAttestationMessage = {
29298
29327
  return step;
29299
29328
  }
29300
29329
 
29301
- var version = "1.14.2";
29330
+ var version = "1.14.3";
29302
29331
  var pkg = {
29303
29332
  version: version};
29304
29333
 
@@ -30217,9 +30246,34 @@ function assertCCTPV2Config(config) {
30217
30246
  tokenAddress: source.chain.usdcAddress,
30218
30247
  operationContext: sourceOperationContext
30219
30248
  });
30249
+ await this.assertAmountCoversRecipientSetupFee(params);
30220
30250
  return bridge(params, this);
30221
30251
  }
30222
30252
  /**
30253
+ * Reject a forwarded transfer to Solana whose amount does not exceed the fee.
30254
+ *
30255
+ * CCTP v2 reverts a burn whose `maxFee` is not less than its amount, and the Solana
30256
+ * forwarding fee includes the recipient token account rent. Checking before the
30257
+ * approval avoids sending a transaction that can never be followed by a burn.
30258
+ * Skipped when the caller provides `config.maxFee`.
30259
+ *
30260
+ * @param params - The validated CCTP v2 bridge parameters.
30261
+ * @returns A promise that resolves when the amount covers the fee.
30262
+ * @throws {KitError} INPUT_INVALID_AMOUNT (FATAL) when the fee is greater than or equal
30263
+ * to the amount.
30264
+ */ async assertAmountCoversRecipientSetupFee(params) {
30265
+ const { destination, amount, config } = params;
30266
+ if (destination.useForwarder !== true || config.maxFee !== undefined || !requiresRecipientSetup(destination.chain.type)) {
30267
+ return;
30268
+ }
30269
+ const { providerFee, forwarderFee } = await this.getMaxFee(params);
30270
+ const maxFee = providerFee + forwarderFee;
30271
+ if (maxFee >= BigInt(amount)) {
30272
+ // Amounts and fees are in USDC minor units (6 decimals)
30273
+ throw createInvalidAmountError(formatUnits(amount, 6), `Amount must be greater than the ${formatUnits(String(maxFee), 6)} USDC fee for forwarded transfers to ${destination.chain.name}, which includes creating the recipient's token account`);
30274
+ }
30275
+ }
30276
+ /**
30223
30277
  * Retry a failed or incomplete CCTP v2 bridge operation.
30224
30278
  *
30225
30279
  * Analyzes the bridge result to determine where to continue and executes
@@ -30936,6 +30990,9 @@ function assertCCTPV2Config(config) {
30936
30990
  * | FAST | true | No | maxFee = calculatedBurnFee + forwardingFee |
30937
30991
  * | FAST | true | Yes | maxFee = config.maxFee |
30938
30992
  *
30993
+ * For forwarded burns to Solana, the forwarding fee includes the rent for creating the
30994
+ * recipient's token account. A caller-provided `maxFee` must cover it too.
30995
+ *
30939
30996
  * @param params - The bridge parameters object containing:
30940
30997
  * - `source`: The source wallet context with chain definition and adapter
30941
30998
  * - `destination`: The destination wallet context with chain definition and adapter
@@ -30974,6 +31031,7 @@ function assertCCTPV2Config(config) {
30974
31031
  }
30975
31032
  // Get the min finality threshold based on the transfer speed
30976
31033
  const minFinalityThreshold = CCTPv2MinFinalityThreshold[transferSpeed];
31034
+ const includeRecipientSetup = requiresRecipientSetup(destination.chain.type);
30977
31035
  // SLOW transfer without forwarder: no fee
30978
31036
  if (transferSpeed === TransferSpeed.SLOW && !useForwarder) {
30979
31037
  return {
@@ -30983,7 +31041,7 @@ function assertCCTPV2Config(config) {
30983
31041
  }
30984
31042
  // SLOW transfer with forwarder: only forwarding fee
30985
31043
  if (transferSpeed === TransferSpeed.SLOW && useForwarder) {
30986
- const forwarderFee = await fetchForwardingFee(source.chain.cctp.domain, destination.chain.cctp.domain, source.chain.isTestnet, minFinalityThreshold);
31044
+ const forwarderFee = await fetchForwardingFee(source.chain.cctp.domain, destination.chain.cctp.domain, source.chain.isTestnet, minFinalityThreshold, includeRecipientSetup);
30987
31045
  return {
30988
31046
  providerFee: 0n,
30989
31047
  forwarderFee
@@ -30993,7 +31051,7 @@ function assertCCTPV2Config(config) {
30993
31051
  // Fetch fees in parallel when forwarder is enabled
30994
31052
  const [scaledBps, forwarderFee] = await Promise.all([
30995
31053
  fetchUsdcFastBurnFee(source.chain.cctp.domain, destination.chain.cctp.domain, source.chain.isTestnet),
30996
- useForwarder ? fetchForwardingFee(source.chain.cctp.domain, destination.chain.cctp.domain, source.chain.isTestnet, minFinalityThreshold) : Promise.resolve(0n)
31054
+ useForwarder ? fetchForwardingFee(source.chain.cctp.domain, destination.chain.cctp.domain, source.chain.isTestnet, minFinalityThreshold, includeRecipientSetup) : Promise.resolve(0n)
30997
31055
  ]);
30998
31056
  // Calculate fee proportional to the transfer amount
30999
31057
  const amountInMinorUnits = BigInt(amount);