@circle-fin/app-kit 1.10.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.
package/context.d.cts CHANGED
@@ -740,6 +740,8 @@ declare enum Blockchain {
740
740
  World_Chain_Sepolia = "World_Chain_Sepolia",
741
741
  XDC = "XDC",
742
742
  XDC_Apothem = "XDC_Apothem",
743
+ X_Layer = "X_Layer",
744
+ X_Layer_Testnet = "X_Layer_Testnet",
743
745
  ZKSync_Era = "ZKSync_Era",
744
746
  ZKSync_Sepolia = "ZKSync_Sepolia"
745
747
  }
@@ -952,6 +954,7 @@ declare enum BridgeChain {
952
954
  Unichain = "Unichain",
953
955
  World_Chain = "World_Chain",
954
956
  XDC = "XDC",
957
+ X_Layer = "X_Layer",
955
958
  Arc_Testnet = "Arc_Testnet",
956
959
  Arbitrum_Sepolia = "Arbitrum_Sepolia",
957
960
  Avalanche_Fuji = "Avalanche_Fuji",
@@ -975,7 +978,8 @@ declare enum BridgeChain {
975
978
  Sonic_Testnet = "Sonic_Testnet",
976
979
  Unichain_Sepolia = "Unichain_Sepolia",
977
980
  World_Chain_Sepolia = "World_Chain_Sepolia",
978
- XDC_Apothem = "XDC_Apothem"
981
+ XDC_Apothem = "XDC_Apothem",
982
+ X_Layer_Testnet = "X_Layer_Testnet"
979
983
  }
980
984
  /**
981
985
  * Type representing valid bridge chain identifiers.
@@ -5260,6 +5264,132 @@ declare enum TransferSpeed {
5260
5264
  /** Standard burn mode - normal transfer time with standard fees */
5261
5265
  SLOW = "SLOW"
5262
5266
  }
5267
+ /**
5268
+ * Context object representing a wallet and signing authority on a specific blockchain network.
5269
+ *
5270
+ * Combines a wallet or contract address, the blockchain it resides on, and the adapter (signer)
5271
+ * responsible for authorizing transactions. Used to specify the source or destination in cross-chain
5272
+ * transfer operations.
5273
+ *
5274
+ * @remarks
5275
+ * The `adapter` (signer) and `address` do not always have to belong to the same entity. For example,
5276
+ * in minting or withdrawal scenarios, the signing adapter may authorize a transaction that credits
5277
+ * funds to a different recipient address. This context is essential for cross-chain operations,
5278
+ * ensuring that both the address and the associated adapter are correctly paired with the intended
5279
+ * blockchain, but not necessarily with each other.
5280
+ *
5281
+ * @example
5282
+ * ```typescript
5283
+ * import type { WalletContext } from '@core/provider'
5284
+ * import { adapter, blockchain } from './setup'
5285
+ *
5286
+ * const wallet: WalletContext = {
5287
+ * adapter,
5288
+ * address: '0x1234...abcd',
5289
+ * chain: blockchain,
5290
+ * }
5291
+ * ```
5292
+ */
5293
+ interface WalletContext<TAdapterCapabilities extends AdapterCapabilities = AdapterCapabilities,
5294
+ /**
5295
+ * The chain definition type to use for the wallet context.
5296
+ *
5297
+ * @defaultValue ChainDefinition
5298
+ */
5299
+ TChainDefinition extends ChainDefinition = ChainDefinition> {
5300
+ /**
5301
+ * The adapter (signer) for the wallet on the specified chain.
5302
+ *
5303
+ * Responsible for authorizing transactions and signing messages on behalf of the wallet or
5304
+ * for a different recipient, depending on the use case.
5305
+ */
5306
+ adapter: Adapter<TAdapterCapabilities>;
5307
+ /**
5308
+ * The wallet or contract address.
5309
+ *
5310
+ * Must be a valid address format for the specified blockchain. May differ from the adapter's
5311
+ * own address in scenarios such as relayed transactions or third-party minting.
5312
+ */
5313
+ address: string;
5314
+ /**
5315
+ * The blockchain network where the wallet or contract address resides.
5316
+ *
5317
+ * Determines the context and format for the address and adapter.
5318
+ */
5319
+ chain: TChainDefinition;
5320
+ }
5321
+ /**
5322
+ * Wallet context for bridge destinations with optional custom recipient.
5323
+ *
5324
+ * Extends WalletContext to support scenarios where the recipient address
5325
+ * differs from the signer address (e.g., bridging to a third-party wallet).
5326
+ * The signer address is used for transaction authorization, while the
5327
+ * recipient address specifies where the minted funds should be sent.
5328
+ *
5329
+ * @typeParam TAdapterCapabilities - The adapter capabilities type to use for the wallet context.
5330
+ * @typeParam TChainDefinition - The chain definition type to use for the wallet context.
5331
+ *
5332
+ * @example
5333
+ * ```typescript
5334
+ * import type { DestinationWalletContext } from '@core/provider'
5335
+ * import { adapter, blockchain } from './setup'
5336
+ *
5337
+ * // Bridge to a custom recipient address
5338
+ * const destination: DestinationWalletContext = {
5339
+ * adapter,
5340
+ * address: '0x1234...abcd', // Signer address
5341
+ * chain: blockchain,
5342
+ * recipientAddress: '0x9876...fedc' // Custom recipient
5343
+ * }
5344
+ * ```
5345
+ */
5346
+ interface DestinationWalletContext<TAdapterCapabilities extends AdapterCapabilities = AdapterCapabilities,
5347
+ /**
5348
+ * The chain definition type to use for the wallet context.
5349
+ *
5350
+ * @defaultValue ChainDefinition
5351
+ */
5352
+ TChainDefinition extends ChainDefinition = ChainDefinition> extends WalletContext<TAdapterCapabilities, TChainDefinition> {
5353
+ /**
5354
+ * Optional custom recipient address for minted funds.
5355
+ *
5356
+ * When provided, minted tokens will be sent to this address instead of
5357
+ * the address specified in the wallet context. The wallet context address
5358
+ * is still used for transaction signing and authorization.
5359
+ *
5360
+ * Must be a valid address format for the specified blockchain.
5361
+ */
5362
+ recipientAddress?: string;
5363
+ }
5364
+ /**
5365
+ * Parameters for executing a cross-chain bridge operation.
5366
+ */
5367
+ interface BridgeParams$1<TFromCapabilities extends AdapterCapabilities = AdapterCapabilities, TToCapabilities extends AdapterCapabilities = AdapterCapabilities,
5368
+ /**
5369
+ * The chain definition type to use for the wallet context.
5370
+ *
5371
+ * @defaultValue ChainDefinition
5372
+ */
5373
+ TChainDefinition extends ChainDefinition = ChainDefinition> {
5374
+ /** The source adapter containing wallet and chain information */
5375
+ source: WalletContext<TFromCapabilities, TChainDefinition>;
5376
+ /** The destination adapter containing wallet and chain information */
5377
+ destination: DestinationWalletContext<TToCapabilities, TChainDefinition>;
5378
+ /** The amount to transfer (as a string to avoid precision issues) */
5379
+ amount: string;
5380
+ /** The token to transfer (currently only USDC is supported) */
5381
+ token: 'USDC';
5382
+ /** Bridge configuration (e.g., fast burn settings) */
5383
+ config: BridgeConfig;
5384
+ /**
5385
+ * Optional invocation metadata for tracing and correlation.
5386
+ *
5387
+ * When provided, the `traceId` is used to correlate all events emitted during
5388
+ * the bridge operation. If not provided, an OpenTelemetry-compatible traceId
5389
+ * will be auto-generated.
5390
+ */
5391
+ invocationMeta?: InvocationMeta;
5392
+ }
5263
5393
  /**
5264
5394
  * Configuration options for customizing bridge behavior.
5265
5395
  *
@@ -5567,6 +5697,91 @@ type BridgeDestination<TAdapterCapabilities extends AdapterCapabilities = Adapte
5567
5697
  useForwarder?: boolean;
5568
5698
  }) | ForwarderDestination<TChainIdentifier>;
5569
5699
 
5700
+ type FeeFunction<TFromAdapterCapabilities extends AdapterCapabilities, TToAdapterCapabilities extends AdapterCapabilities> = (params: BridgeParams$1<TFromAdapterCapabilities, TToAdapterCapabilities>) => Promise<string> | string;
5701
+ type FeeRecipientFunction<TFromAdapterCapabilities extends AdapterCapabilities, TToAdapterCapabilities extends AdapterCapabilities> = (feePayoutChain: ChainDefinition, params: BridgeParams$1<TFromAdapterCapabilities, TToAdapterCapabilities>) => Promise<string> | string;
5702
+ /**
5703
+ * Custom fee policy for BridgeKit.
5704
+ *
5705
+ * Provides hooks to calculate an absolute custom fee and resolve the fee recipient address
5706
+ * on the source chain. The returned fee is **added on top of the transfer amount** (the wallet signs for
5707
+ * `amount + customFee`). Once collected, the custom fee is split:
5708
+ *
5709
+ * - **10%** automatically routes to Circle.
5710
+ * - **90%** routes to your supplied `recipientAddress`.
5711
+ *
5712
+ * The entire transfer amount still flows through CCTPv2, which then charges its own protocol fee.
5713
+ *
5714
+ * Use `computeFee` (recommended) for human-readable amounts, or `calculateFee` (deprecated)
5715
+ * for smallest-unit amounts. Only one should be provided.
5716
+ *
5717
+ * @example
5718
+ * ```typescript
5719
+ * import type { CustomFeePolicy, BridgeParams } from '@circle-fin/bridge-kit'
5720
+ *
5721
+ * const policy: CustomFeePolicy = {
5722
+ * // computeFee receives human-readable amounts (e.g., '100' for 100 USDC)
5723
+ * computeFee: (params: BridgeParams) => {
5724
+ * const amount = parseFloat(params.amount)
5725
+ *
5726
+ * // 1% fee, capped between 5-50 USDC
5727
+ * const fee = Math.min(Math.max(amount * 0.01, 5), 50)
5728
+ * return fee.toFixed(6)
5729
+ * },
5730
+ * resolveFeeRecipientAddress: (feePayoutChain) =>
5731
+ * feePayoutChain.type === 'solana'
5732
+ * ? 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'
5733
+ * : '0x1234567890123456789012345678901234567890',
5734
+ * }
5735
+ * ```
5736
+ */
5737
+ type CustomFeePolicy$2 = {
5738
+ /**
5739
+ * A function that returns the fee to charge for the bridge transfer.
5740
+ * The value returned from the function represents an absolute fee.
5741
+ * The returned fee is **added on top of the transfer amount**. For example, returning
5742
+ * `'5'` (5 USDC) for a 100 USDC transfer causes the wallet to debit 105 USDC total.
5743
+ * CCTPv2 still processes the full 100 USDC transfer amount, while the custom fee is split
5744
+ * 10%/90% between Circle and your fee recipient.
5745
+ *
5746
+ * @example
5747
+ * ```typescript
5748
+ * computeFee: (params) => {
5749
+ * const amount = parseFloat(params.amount)
5750
+ * return (amount * 0.01).toString() // 1% fee
5751
+ * }
5752
+ * ```
5753
+ */
5754
+ computeFee: FeeFunction<AdapterCapabilities, AdapterCapabilities>;
5755
+ calculateFee?: never;
5756
+ /**
5757
+ * A function that returns the fee recipient for a bridge transfer.
5758
+ * The value returned from the function represents the address that will receive the fee on the source chain of the bridge transfer.
5759
+ * The fee recipient address **must be a valid address for the source chain** of the bridge transfer.
5760
+ *
5761
+ * For example: if you are bridging from Ethereum to Solana you would return `'0x1234567890123456789012345678901234567890'`,
5762
+ * because the source chain of the bridge transfer is Ethereum.
5763
+ */
5764
+ resolveFeeRecipientAddress: FeeRecipientFunction<AdapterCapabilities, AdapterCapabilities>;
5765
+ } | {
5766
+ computeFee?: never;
5767
+ /**
5768
+ * Calculate the fee to charge for the bridge transfer using smallest-unit amounts.
5769
+ *
5770
+ * @deprecated Use `computeFee` instead, which receives human-readable amounts.
5771
+ *
5772
+ * The `params.amount` is in smallest units (e.g., `'100000000'` for 100 USDC).
5773
+ */
5774
+ calculateFee: FeeFunction<AdapterCapabilities, AdapterCapabilities>;
5775
+ /**
5776
+ * A function that returns the fee recipient for a bridge transfer.
5777
+ * The value returned from the function represents the address that will receive the fee on the source chain of the bridge transfer.
5778
+ * The fee recipient address **must be a valid address for the source chain** of the bridge transfer.
5779
+ *
5780
+ * For example: if you are bridging from Ethereum to Solana you would return `'0x1234567890123456789012345678901234567890'`,
5781
+ * because the source chain of the bridge transfer is Ethereum.
5782
+ */
5783
+ resolveFeeRecipientAddress: FeeRecipientFunction<AdapterCapabilities, AdapterCapabilities>;
5784
+ };
5570
5785
  /**
5571
5786
  * Parameters for initiating a cross-chain USDC bridge transfer.
5572
5787
  *
@@ -5671,6 +5886,463 @@ interface BridgeParams<TFromAdapterCapabilities extends AdapterCapabilities = Ad
5671
5886
  invocationMeta?: InvocationMeta;
5672
5887
  }
5673
5888
 
5889
+ /**
5890
+ * Allowance strategy for token approvals during swap operations.
5891
+ *
5892
+ * Defines how token allowances should be granted to the swap contract:
5893
+ * - `permit`: Use EIP-2612 permit signature (gas-efficient, no approval transaction)
5894
+ * - `approve`: Traditional approval transaction
5895
+ *
5896
+ * The default strategy is `permit` with fallback to `approve` if permit is not supported.
5897
+ */
5898
+ type AllowanceStrategy$1 = 'permit' | 'approve';
5899
+ /**
5900
+ * Configuration options for swap operations.
5901
+ *
5902
+ * Controls swap behavior including allowance strategy, slippage tolerance,
5903
+ * minimum output amounts, custom fees, and kit identification.
5904
+ *
5905
+ * @example
5906
+ * ```typescript
5907
+ * import type { ServiceSwapConfig } from '@circle-fin/provider-stablecoin-service-swap'
5908
+ *
5909
+ * // Percentage-based fee
5910
+ * const config: ServiceSwapConfig = {
5911
+ * allowanceStrategy: 'permit',
5912
+ * slippageBps: 300, // 3%
5913
+ * stopLimit: '950000', // Minimum 0.95 USDC output
5914
+ * customFee: {
5915
+ * percentageBps: 1000, // 10% fee
5916
+ * recipientAddress: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e'
5917
+ * }
5918
+ * }
5919
+ * ```
5920
+ *
5921
+ * @example
5922
+ * ```typescript
5923
+ * // Absolute amount fee (from callback)
5924
+ * const config: ServiceSwapConfig = {
5925
+ * allowanceStrategy: 'permit',
5926
+ * customFee: {
5927
+ * amount: '10000', // 0.01 USDC fee (absolute)
5928
+ * recipientAddress: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e'
5929
+ * }
5930
+ * }
5931
+ * ```
5932
+ */
5933
+ interface ServiceSwapConfig {
5934
+ /**
5935
+ * Strategy for granting token allowances to the swap contract.
5936
+ *
5937
+ * Defaults to 'permit' with fallback to 'approve'.
5938
+ */
5939
+ allowanceStrategy?: AllowanceStrategy$1;
5940
+ /**
5941
+ * Maximum acceptable slippage in basis points (BPS).
5942
+ *
5943
+ * 1 BPS = 0.01%, so 300 BPS = 3% slippage.
5944
+ * Defaults to 300 BPS (3%).
5945
+ */
5946
+ slippageBps?: number;
5947
+ /**
5948
+ * Minimum acceptable output amount in smallest units (stop-limit).
5949
+ *
5950
+ * If the estimated output falls below this value, the swap will fail.
5951
+ * Expressed as a string to avoid precision issues.
5952
+ */
5953
+ stopLimit?: string;
5954
+ /**
5955
+ * Custom fee configuration for this swap.
5956
+ *
5957
+ * Supports two mutually exclusive approaches:
5958
+ * 1. Percentage-based: Use `percentageBps` field (simple)
5959
+ * 2. Absolute amount: Use `amount` field (from callback)
5960
+ *
5961
+ * If both are set, validation will fail. Transaction-level percentage
5962
+ * takes precedence over kit-level callback policy.
5963
+ */
5964
+ customFee?: {
5965
+ /**
5966
+ * Fee percentage in basis points (NEW).
5967
+ *
5968
+ * 100 bps = 1%, 1000 bps = 10%, 10000 bps = 100%
5969
+ *
5970
+ * Service calculates fee using `estimatedAmount` for same-chain output fees
5971
+ * and the input amount for cross-chain swaps.
5972
+ * Must be greater than 0 and less than or equal to 10000 (maximum 100%).
5973
+ * Mutually exclusive with `amount`.
5974
+ *
5975
+ * @example 1000 // 10% fee
5976
+ */
5977
+ percentageBps?: number;
5978
+ /**
5979
+ * Fee amount in smallest units (for callback results).
5980
+ *
5981
+ * Absolute fee amount calculated by callback function.
5982
+ * Mutually exclusive with `percentageBps`.
5983
+ *
5984
+ * @example '10000' // 0.01 USDC (6 decimals)
5985
+ */
5986
+ amount?: string;
5987
+ /**
5988
+ * Address that will receive the developer's 90% fee share.
5989
+ *
5990
+ * Required whenever a custom fee is submitted to the provider. Optional at
5991
+ * the type level so SDK callback flows can represent partial fee state
5992
+ * before final validation.
5993
+ *
5994
+ * Must be valid on the fee payout chain: source chain for input-side fees
5995
+ * and cross-chain swaps, destination chain for same-chain output-side fees.
5996
+ *
5997
+ * @example '0x742d35Cc6634C0532925a3b844Bc454e4438f44e'
5998
+ */
5999
+ recipientAddress?: string;
6000
+ };
6001
+ /**
6002
+ * Stablecoin Service Kit Key used to authenticate service-backed swap
6003
+ * requests.
6004
+ *
6005
+ * Treat this value as a credential. Do not log it, embed it in client-side
6006
+ * source, or expose it in telemetry.
6007
+ */
6008
+ kitKey?: string;
6009
+ /**
6010
+ * DEX aggregator identifier used to source the swap route.
6011
+ *
6012
+ * @example 'lifi', 'paraswap'
6013
+ */
6014
+ provider?: string;
6015
+ /**
6016
+ * Whether to fuse the ERC-20 approval and the swap into a single atomic
6017
+ * batch when the adapter supports it (EIP-5792, or a signing strategy that
6018
+ * declares atomic batching).
6019
+ *
6020
+ * @remarks
6021
+ * Defaults to `true`. When batching is available this collapses the two
6022
+ * sequential transactions of the on-chain approval path into one atomic
6023
+ * submission — a single signing challenge for a smart-contract wallet. Set
6024
+ * to `false` to force the sequential approve-then-swap path. Has no effect on
6025
+ * the gasless permit path (already a single transaction) or on native-token
6026
+ * swaps (no approval needed).
6027
+ *
6028
+ * The batch path relies on the wallet's own gas estimation for the swap call:
6029
+ * the service-provided gas floor and pre-flight simulation that the sequential
6030
+ * path applies are not conveyed through the batch. For a complex/multi-hop
6031
+ * swap whose wallet-side estimate under-shoots, this can out-of-gas-revert the
6032
+ * atomic batch where the sequential path would succeed — set `false` to fall
6033
+ * back to the service-floored sequential path if you hit this.
6034
+ *
6035
+ * @defaultValue true
6036
+ */
6037
+ batchTransactions?: boolean;
6038
+ }
6039
+ /**
6040
+ * Parameters for initiating a swap operation through the Stablecoin Service.
6041
+ *
6042
+ * This type is used as the primary input to provider swap operations, allowing users to specify
6043
+ * the source context, input/output tokens, swap amount, destination address, and optional configuration.
6044
+ *
6045
+ * @typeParam TFromAdapterCapabilities - The adapter capabilities type for the source adapter.
6046
+ *
6047
+ * @example
6048
+ * ```typescript
6049
+ * import type { ServiceSwapParams } from '@circle-fin/provider-stablecoin-service-swap'
6050
+ * import { createAdapterFromPrivateKey } from '@circle-fin/adapter-viem-v2'
6051
+ * import { Ethereum } from '@core/chains'
6052
+ *
6053
+ * const adapter = createAdapterFromPrivateKey({
6054
+ * privateKey: process.env.PRIVATE_KEY,
6055
+ * })
6056
+ *
6057
+ * const params: ServiceSwapParams = {
6058
+ * from: { adapter, chain: Ethereum },
6059
+ * tokenIn: 'USDC', // Alias resolves to chain-specific address
6060
+ * tokenOut: 'USDT', // Alias resolves to chain-specific address
6061
+ * amountIn: '100500000', // 100.50 USDC in base units
6062
+ * to: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
6063
+ * config: {
6064
+ * slippageBps: 300, // 3% slippage
6065
+ * allowanceStrategy: 'permit'
6066
+ * }
6067
+ * }
6068
+ * ```
6069
+ */
6070
+ interface ServiceSwapParams<TFromAdapterCapabilities extends AdapterCapabilities = AdapterCapabilities,
6071
+ /**
6072
+ * The chain definition type to use for the wallet context.
6073
+ *
6074
+ * @defaultValue ChainDefinition
6075
+ */
6076
+ TChainDefinition extends ChainDefinition = ChainDefinition> {
6077
+ /**
6078
+ * The source adapter context (wallet and chain) for the swap.
6079
+ */
6080
+ from: WalletContext<TFromAdapterCapabilities, TChainDefinition>;
6081
+ /**
6082
+ * The input token address or alias to swap from.
6083
+ *
6084
+ * **Supported formats:**
6085
+ * - Token alias: `"USDC"`, `"USDT"`, `"NATIVE"` (case-insensitive)
6086
+ * - EVM address: `'0x'` prefixed hex (e.g., `'0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'`)
6087
+ * - Solana address: Base58-encoded (e.g., `'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'`)
6088
+ *
6089
+ * Token aliases are automatically resolved to the chain-specific contract address.
6090
+ *
6091
+ * @example 'USDC' // Recommended: use alias
6092
+ * @example '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' // Or full address
6093
+ */
6094
+ tokenIn: string;
6095
+ /**
6096
+ * The output token address or alias to swap to.
6097
+ *
6098
+ * **Supported formats:**
6099
+ * - Token alias: `"USDC"`, `"USDT"`, `"NATIVE"` (case-insensitive)
6100
+ * - EVM address: `'0x'` prefixed hex (e.g., `'0xdAC17F958D2ee523a2206206994597C13D831ec7'`)
6101
+ * - Solana address: Base58-encoded (e.g., `'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB'`)
6102
+ *
6103
+ * Token aliases are automatically resolved to the chain-specific contract address.
6104
+ *
6105
+ * @example 'USDT' // Recommended: use alias
6106
+ * @example '0xdAC17F958D2ee523a2206206994597C13D831ec7' // Or full address
6107
+ */
6108
+ tokenOut: string;
6109
+ /**
6110
+ * The amount of input token to swap in base units.
6111
+ *
6112
+ * SwapKit converts human-readable amounts to base units before passing to the provider.
6113
+ *
6114
+ * @example '100500000' for 100.50 USDC (6 decimals)
6115
+ */
6116
+ amountIn: string;
6117
+ /**
6118
+ * The destination address where the swapped tokens will be sent.
6119
+ *
6120
+ * @example '0x742d35Cc6634C0532925a3b844Bc454e4438f44e'
6121
+ */
6122
+ to: string;
6123
+ /**
6124
+ * Optional destination chain for cross-chain swaps.
6125
+ *
6126
+ * Defaults to `from.chain` for same-chain swaps.
6127
+ */
6128
+ toChain?: TChainDefinition;
6129
+ /**
6130
+ * Optional configuration for swap behavior.
6131
+ *
6132
+ * If omitted, defaults will be used:
6133
+ * - allowanceStrategy: 'permit' (fallback to 'approve')
6134
+ * - slippageBps: 300 (3%)
6135
+ */
6136
+ config?: ServiceSwapConfig;
6137
+ }
6138
+
6139
+ /**
6140
+ * Fee context when fee is taken from INPUT token.
6141
+ *
6142
+ * Used for swaps where the fee is collected from the input token, including
6143
+ * all cross-chain swaps.
6144
+ * Extends the resolved swap parameters with a discriminator to indicate input fee scenario.
6145
+ *
6146
+ * @typeParam TFromAdapterCapabilities - The adapter capabilities type for the source adapter
6147
+ *
6148
+ * @example
6149
+ * ```typescript
6150
+ * // USDC → RandomToken swap (fee from input)
6151
+ * const context: SwapInputFeeContext = {
6152
+ * type: 'input',
6153
+ * from: {
6154
+ * adapter: viemAdapter,
6155
+ * chain: Ethereum,
6156
+ * address: '0x...'
6157
+ * },
6158
+ * tokenIn: 'USDC',
6159
+ * tokenOut: 'RandomToken',
6160
+ * amountIn: '100000000', // 100 USDC in base units
6161
+ * to: '0x...'
6162
+ * }
6163
+ * ```
6164
+ */
6165
+ interface SwapInputFeeContext<TFromAdapterCapabilities extends AdapterCapabilities = AdapterCapabilities> extends ResolvedSwapParams<TFromAdapterCapabilities> {
6166
+ /**
6167
+ * Fee source discriminator - input token.
6168
+ */
6169
+ type: 'input';
6170
+ }
6171
+ /**
6172
+ * Fee context when fee is taken from OUTPUT token.
6173
+ *
6174
+ * Used for swaps where the output token is supported for fee collection.
6175
+ * Extends the resolved swap parameters with output amounts and discriminator.
6176
+ *
6177
+ * @typeParam TFromAdapterCapabilities - The adapter capabilities type for the source adapter
6178
+ *
6179
+ * @remarks
6180
+ * If using `estimatedAmount` in callback and quote cache expires,
6181
+ * calculated fee may not match fresh quote. Use `minAmount` for
6182
+ * predictability at the cost of potentially lower fees.
6183
+ *
6184
+ * @example
6185
+ * ```typescript
6186
+ * // RandomToken → USDC swap (fee from output)
6187
+ * const context: SwapOutputFeeContext = {
6188
+ * type: 'output',
6189
+ * from: {
6190
+ * adapter: viemAdapter,
6191
+ * chain: Ethereum,
6192
+ * address: '0x...'
6193
+ * },
6194
+ * tokenIn: 'RandomToken',
6195
+ * tokenOut: 'USDC',
6196
+ * amountIn: '100000000',
6197
+ * to: '0x...',
6198
+ * minAmount: '50000000', // 50 USDC guaranteed minimum
6199
+ * estimatedAmount: '55000000' // 55 USDC expected output
6200
+ * }
6201
+ * ```
6202
+ */
6203
+ interface SwapOutputFeeContext<TFromAdapterCapabilities extends AdapterCapabilities = AdapterCapabilities> extends ResolvedSwapParams<TFromAdapterCapabilities> {
6204
+ /**
6205
+ * Fee source discriminator - output token.
6206
+ */
6207
+ type: 'output';
6208
+ /**
6209
+ * Guaranteed minimum output amount in base units.
6210
+ *
6211
+ * More stable but lower than estimatedAmount. Use this for
6212
+ * predictable fee calculations.
6213
+ */
6214
+ minAmount: string;
6215
+ /**
6216
+ * Estimated output amount in base units.
6217
+ *
6218
+ * Expected output based on current market conditions. May be
6219
+ * higher than minAmount. Subject to change if quote expires.
6220
+ */
6221
+ estimatedAmount: string;
6222
+ }
6223
+ /**
6224
+ * Discriminated union for swap fee contexts.
6225
+ *
6226
+ * Provides different context based on whether fee is from input or output token.
6227
+ * Discriminated by the `type` field: 'input' for fees from input token, 'output' for output token.
6228
+ *
6229
+ * Includes full swap parameters (adapter, chain, tokens, amounts) for maximum flexibility
6230
+ * in fee calculation logic.
6231
+ *
6232
+ * @typeParam TFromAdapterCapabilities - The adapter capabilities type for the source adapter
6233
+ */
6234
+ type SwapFeeContext<TFromAdapterCapabilities extends AdapterCapabilities = AdapterCapabilities> = SwapInputFeeContext<TFromAdapterCapabilities> | SwapOutputFeeContext<TFromAdapterCapabilities>;
6235
+ /**
6236
+ * Custom fee policy for SwapKit (callback-based approach).
6237
+ *
6238
+ * Provides hooks to calculate an absolute fee amount and resolve the fee
6239
+ * recipient address. The callback receives a discriminated context with
6240
+ * different fields based on operation type (bridge vs swap) and fee source
6241
+ * (input vs output).
6242
+ *
6243
+ * @remarks
6244
+ * This is mutually exclusive with transaction-level percentage fees.
6245
+ * If both are set, the transaction-level percentage takes precedence.
6246
+ *
6247
+ * The callback approach makes two API calls for same-chain output fees:
6248
+ * 1. GET /quote - retrieve fee context and quote
6249
+ * 2. POST /swap - execute with calculated fee
6250
+ *
6251
+ * Cross-chain swaps always use input fees on the source chain, so callbacks
6252
+ * receive `type: 'input'` for those routes.
6253
+ *
6254
+ * @example
6255
+ * ```typescript
6256
+ * import type { CustomFeePolicy } from '@circle-fin/swap-kit'
6257
+ *
6258
+ * const policy: CustomFeePolicy = {
6259
+ * computeFee: async (ctx) => {
6260
+ * // Discriminate by fee source (input vs output)
6261
+ * if (ctx.type === 'input') {
6262
+ * // Simple percentage for input fees
6263
+ * return (parseFloat(ctx.amountIn) * 0.1).toString()
6264
+ * } else {
6265
+ * // Complex logic for output fees (VIP tiers, etc.)
6266
+ * const user = await database.getUser(...)
6267
+ * if (user.isVIP) {
6268
+ * return (parseFloat(ctx.minAmount) * 0.05).toString()
6269
+ * }
6270
+ * return (parseFloat(ctx.estimatedAmount) * 0.1).toString()
6271
+ * }
6272
+ * },
6273
+ * resolveFeeRecipientAddress: (chain) => {
6274
+ * return chain.type === 'solana'
6275
+ * ? 'SolanaAddress...'
6276
+ * : '0xEVMAddress...'
6277
+ * },
6278
+ * }
6279
+ * ```
6280
+ */
6281
+ interface CustomFeePolicy$1 {
6282
+ /**
6283
+ * Calculate custom fee amount based on swap context.
6284
+ *
6285
+ * Receives full swap parameters including adapter, chain, tokens, and amounts.
6286
+ * Context is discriminated by `type` field:
6287
+ * - 'input': Fee from input token (OK → Any swaps and all cross-chain swaps)
6288
+ * - 'output': Fee from output token (same-chain Any → OK swaps), includes minAmount and estimatedAmount
6289
+ *
6290
+ * The wrapper automatically converts amounts to/from base units, so your
6291
+ * callback works with human-readable numbers (e.g., '0.1' for 0.1 USDC).
6292
+ *
6293
+ * @typeParam TFromAdapterCapabilities - The adapter capabilities type for the source adapter
6294
+ * @param context - Discriminated swap fee context with full swap parameters
6295
+ * @returns Absolute fee amount as string in human-readable format
6296
+ *
6297
+ * @example
6298
+ * ```typescript
6299
+ * computeFee: async (ctx) => {
6300
+ * if (ctx.type === 'output') {
6301
+ * // Output fee scenario
6302
+ * // Use estimatedAmount or minAmount for calculation
6303
+ * return (parseFloat(ctx.estimatedAmount) * 0.01).toString()
6304
+ * }
6305
+ * // Input fee scenario
6306
+ * return (parseFloat(ctx.amountIn) * 0.01).toString()
6307
+ * }
6308
+ * ```
6309
+ *
6310
+ * @example
6311
+ * ```typescript
6312
+ * computeFee: async (ctx) => {
6313
+ * if (ctx.type === 'output') {
6314
+ * // Use minAmount for predictable fees
6315
+ * return (parseFloat(ctx.minAmount) * 0.01).toString()
6316
+ * }
6317
+ * return (parseFloat(ctx.amountIn) * 0.01).toString()
6318
+ * }
6319
+ * ```
6320
+ */
6321
+ computeFee: <TFromAdapterCapabilities extends AdapterCapabilities>(context: SwapFeeContext<TFromAdapterCapabilities>) => Promise<string> | string;
6322
+ /**
6323
+ * Resolve fee recipient address for the chain where fee is collected.
6324
+ *
6325
+ * Called with the chain where fee will be paid. For cross-chain swaps this
6326
+ * is always the source chain. Must return a valid address format for that
6327
+ * chain type (EVM or Solana).
6328
+ *
6329
+ * @param feePayoutChain - Chain definition where fee is collected
6330
+ * @param context - The swap fee context with full parameters
6331
+ * @returns Fee recipient address for the chain
6332
+ *
6333
+ * @example
6334
+ * ```typescript
6335
+ * resolveFeeRecipientAddress: (chain, ctx) => {
6336
+ * // Chain-based routing
6337
+ * if (chain.type === 'solana') {
6338
+ * return 'SolanaAddress...'
6339
+ * }
6340
+ * return '0xEVMAddress...'
6341
+ * }
6342
+ * ```
6343
+ */
6344
+ resolveFeeRecipientAddress: <TFromAdapterCapabilities extends AdapterCapabilities>(feePayoutChain: ChainDefinition, context: SwapFeeContext<TFromAdapterCapabilities>) => Promise<string> | string;
6345
+ }
5674
6346
  /**
5675
6347
  * Adapter context constrained to swap-supported chains.
5676
6348
  */
@@ -5818,6 +6490,45 @@ interface SwapConfig {
5818
6490
  */
5819
6491
  kitKey?: string;
5820
6492
  }
6493
+ /**
6494
+ * Resolved parameters for swap operations after validation and normalization.
6495
+ *
6496
+ * Internal type used by SwapKit operations after `resolveSwapParams()` has:
6497
+ * - Validated the input parameters
6498
+ * - Resolved chain identifiers to full ChainDefinition objects
6499
+ * - Extracted and validated wallet addresses
6500
+ *
6501
+ * Note: Raw user input is validated first, then `tokenIn` and `tokenOut` may
6502
+ * be canonicalized for downstream routing (for example, Arc Testnet
6503
+ * `NATIVE` → `USDC`). Address resolution is handled by the provider layer.
6504
+ *
6505
+ * This type is consumed by swap providers and internal operations but is not
6506
+ * exposed to end users. It extends ServiceSwapParams which is the format expected
6507
+ * by the StablecoinServiceSwapProvider.
6508
+ *
6509
+ * @typeParam TFromAdapterCapabilities - The adapter capabilities type for the source adapter.
6510
+ *
6511
+ * @example
6512
+ * ```typescript
6513
+ * // After resolution, SwapParams becomes ResolvedSwapParams:
6514
+ * const resolved: ResolvedSwapParams = {
6515
+ * from: {
6516
+ * adapter: viemAdapter,
6517
+ * chain: Ethereum, // Full chain definition
6518
+ * address: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e'
6519
+ * },
6520
+ * tokenIn: 'USDC', // Canonicalized for provider routing
6521
+ * tokenOut: 'USDT', // Canonicalized for provider routing
6522
+ * amountIn: '100500000', // Converted to base units (100.5 USDC with 6 decimals)
6523
+ * to: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
6524
+ * config: {
6525
+ * slippageBps: 300,
6526
+ * allowanceStrategy: 'permit'
6527
+ * }
6528
+ * }
6529
+ * ```
6530
+ */
6531
+ type ResolvedSwapParams<TFromAdapterCapabilities extends AdapterCapabilities = AdapterCapabilities> = ServiceSwapParams<TFromAdapterCapabilities>;
5821
6532
  interface SwapParams<TFromAdapterCapabilities extends AdapterCapabilities = AdapterCapabilities> {
5822
6533
  /**
5823
6534
  * The source adapter context (wallet and chain) for the swap.
@@ -5930,6 +6641,24 @@ interface EarnConfig {
5930
6641
  * Format: `KIT_KEY:<keyId>:<keySecret>`
5931
6642
  */
5932
6643
  readonly kitKey?: string | undefined;
6644
+ /**
6645
+ * Optional base URL override for the Earn Service API.
6646
+ *
6647
+ * Defaults to `https://api.circle.com` when omitted. Override for testing
6648
+ * against staging or local environments.
6649
+ */
6650
+ readonly baseUrl?: string | undefined;
6651
+ /**
6652
+ * Enable or disable atomic batched transaction execution.
6653
+ *
6654
+ * When `true` (or `undefined` / omitted), same-chain deposit and withdraw
6655
+ * bundle the approve and execute calls into one adapter-native atomic batch
6656
+ * when the connected wallet supports it. Set to `false` to force the
6657
+ * sequential approve → execute flow.
6658
+ *
6659
+ * @defaultValue `undefined` (batching attempted when the wallet supports it)
6660
+ */
6661
+ readonly batchTransactions?: boolean | undefined;
5933
6662
  }
5934
6663
  /**
5935
6664
  * Parameters for fetching vault information.
@@ -6362,6 +7091,122 @@ interface GetClaimRewardsQuoteParams<TFromAdapterCapabilities extends AdapterCap
6362
7091
  */
6363
7092
  type EarnOperationParams = AnyDepositParams | WithdrawParams | ClaimRewardsParams | GetVaultsParams | ExploreVaultsParams | ExploreVaultsIteratorParams | GetPositionParams | GetDepositQuoteParams | GetWithdrawalQuoteParams | GetClaimRewardsQuoteParams;
6364
7093
 
7094
+ interface CustomFeeConfig {
7095
+ recipientAddress: string;
7096
+ value: string;
7097
+ }
7098
+ /**
7099
+ * Data needed to retry a mint that failed after the transfer was
7100
+ * already committed (funds locked).
7101
+ *
7102
+ * Obtain these values from the KitError (TRANSACTION_REVERTED) thrown when
7103
+ * the on-chain mint step fails. The attestation and signature are available
7104
+ * in `error.cause.trace`.
7105
+ */
7106
+ interface RetryMintConfig {
7107
+ /** The attestation hex string returned by the Gateway `/v1/transfer` API. */
7108
+ attestation: string;
7109
+ /** The attestation signature hex string returned by `/v1/transfer`. */
7110
+ signature: string;
7111
+ }
7112
+ interface SpendConfig {
7113
+ customFee?: CustomFeeConfig;
7114
+ /**
7115
+ * When provided, skips the estimate/sign/transfer steps and proceeds
7116
+ * directly to the on-chain mint using a previously obtained attestation.
7117
+ *
7118
+ * Use this to retry a mint that failed due to an RPC or network issue
7119
+ * after the transfer was already committed.
7120
+ *
7121
+ * @remarks
7122
+ * The `useForwarder` flag on the destination is ignored during retry
7123
+ * because the attestation was already issued — the Forwarding Service
7124
+ * is only involved in the initial transfer, not re-mints.
7125
+ */
7126
+ retry?: RetryMintConfig;
7127
+ }
7128
+ interface ResolvedAllocation {
7129
+ amount: string;
7130
+ chain: ChainDefinition;
7131
+ }
7132
+ interface ResolvedSpendSource<TAdapterCapabilities extends AdapterCapabilities = AdapterCapabilities> {
7133
+ adapter: Adapter<TAdapterCapabilities>;
7134
+ allocations: ResolvedAllocation[];
7135
+ address?: string;
7136
+ sourceAccount?: string;
7137
+ }
7138
+ interface ResolvedSpendDestination<TAdapterCapabilities extends AdapterCapabilities = AdapterCapabilities> {
7139
+ adapter?: Adapter<TAdapterCapabilities>;
7140
+ chain: ChainDefinition;
7141
+ recipientAddress?: string;
7142
+ address?: string;
7143
+ useForwarder?: boolean;
7144
+ }
7145
+ interface ResolvedSpendParams<TFromAdapterCapabilities extends AdapterCapabilities = AdapterCapabilities, TToAdapterCapabilities extends AdapterCapabilities = AdapterCapabilities> {
7146
+ from: ResolvedSpendSource<TFromAdapterCapabilities>[];
7147
+ to: ResolvedSpendDestination<TToAdapterCapabilities>;
7148
+ token: SupportedToken;
7149
+ config?: SpendConfig;
7150
+ }
7151
+ /**
7152
+ * Function that computes the fee amount (in human-readable units, e.g. "10.5")
7153
+ * given the resolved spend parameters.
7154
+ */
7155
+ type SpendFeeFunction = (params: ResolvedSpendParams) => Promise<string> | string;
7156
+ /**
7157
+ * Function that resolves the fee recipient address for a spend.
7158
+ * Called once per spend, against the resolved **destination** chain —
7159
+ * every fee burn intent in a spend mints to that single chain
7160
+ * regardless of which source chain(s) funded it, so only one
7161
+ * recipient address (valid on the destination chain) is ever needed.
7162
+ */
7163
+ type SpendFeeRecipientFunction = (destinationChain: ChainDefinition, params: ResolvedSpendParams) => Promise<string> | string;
7164
+ /**
7165
+ * Policy for computing and routing custom developer fees.
7166
+ *
7167
+ * **Important:** When the kit invokes `computeFee` and
7168
+ * `resolveFeeRecipientAddress`, the `params` argument may be the
7169
+ * **raw, unresolved** `SpendParams` (cast to `ResolvedSpendParams`).
7170
+ * Fields that only exist after resolution (e.g. per-source allocations)
7171
+ * may be `undefined`. Implementations should only rely on top-level
7172
+ * fields such as `to`, `token`, and `amount`.
7173
+ *
7174
+ * @remarks
7175
+ * `resolveFeeRecipientAddress` is optional when you configure
7176
+ * {@link UnifiedBalanceKit.setFeeRecipients} instead — the declarative
7177
+ * map takes priority over this callback when both are present. Provide
7178
+ * exactly one of the two; a policy with neither throws at spend time.
7179
+ */
7180
+ interface CustomFeePolicy {
7181
+ computeFee: SpendFeeFunction;
7182
+ resolveFeeRecipientAddress?: SpendFeeRecipientFunction;
7183
+ }
7184
+
7185
+ /**
7186
+ * Runtime array of token identifiers supported by the unified-balance-kit.
7187
+ *
7188
+ * @example
7189
+ * ```typescript
7190
+ * import { SUPPORTED_TOKENS } from '@circle-fin/unified-balance-kit'
7191
+ *
7192
+ * if (SUPPORTED_TOKENS.includes('USDC')) {
7193
+ * console.log('USDC is supported')
7194
+ * }
7195
+ * ```
7196
+ */
7197
+ declare const SUPPORTED_TOKENS: readonly ["USDC"];
7198
+ /**
7199
+ * Token identifiers supported by the unified-balance-kit.
7200
+ *
7201
+ * @example
7202
+ * ```typescript
7203
+ * import type { SupportedToken } from '@circle-fin/unified-balance-kit'
7204
+ *
7205
+ * const token: SupportedToken = 'USDC'
7206
+ * ```
7207
+ */
7208
+ type SupportedToken = (typeof SUPPORTED_TOKENS)[number];
7209
+
6365
7210
  /**
6366
7211
  * Operation types that support the `getFee`/`getFeeRecipient` hooks.
6367
7212
  */
@@ -6392,6 +7237,31 @@ interface OperationParamsMap {
6392
7237
  swap: SwapParams;
6393
7238
  earn: EarnOperationParams;
6394
7239
  }
7240
+ /**
7241
+ * Operation-scoped custom fee policies configured at the AppKit level.
7242
+ *
7243
+ * Each property is optional so consumers can enable custom fees only for the
7244
+ * operation they use. AppKit forwards the supplied policy to the matching
7245
+ * underlying kit when that operation runs.
7246
+ *
7247
+ * @example
7248
+ * ```typescript
7249
+ * const policy: AppKitCustomFeePolicy = {
7250
+ * bridge: {
7251
+ * computeFee: () => '1.00',
7252
+ * resolveFeeRecipientAddress: () => '0x1234567890123456789012345678901234567890',
7253
+ * },
7254
+ * }
7255
+ * ```
7256
+ */
7257
+ interface AppKitCustomFeePolicy {
7258
+ /** Custom fee policy forwarded to BridgeKit bridge operations. */
7259
+ bridge?: CustomFeePolicy$2;
7260
+ /** Custom fee policy forwarded to SwapKit swap operations. */
7261
+ swap?: CustomFeePolicy$1;
7262
+ /** Custom fee policy forwarded to UnifiedBalanceKit spend operations. */
7263
+ unifiedBalance?: CustomFeePolicy;
7264
+ }
6395
7265
  /**
6396
7266
  * Context interface for the AppKit with strongly typed getFee method.
6397
7267
  *
@@ -6479,6 +7349,14 @@ interface AppKitContext {
6479
7349
  chain: ChainDefinition;
6480
7350
  params: OperationParamsMap[T];
6481
7351
  }): Promise<string>;
7352
+ /**
7353
+ * Operation-scoped custom fee policies.
7354
+ *
7355
+ * Prefer {@link AppKit.setCustomFeePolicy} for runtime configuration. This
7356
+ * context property is read by the internal kit factories when AppKit creates
7357
+ * BridgeKit and SwapKit instances for each operation.
7358
+ */
7359
+ customFeePolicy?: AppKitCustomFeePolicy;
6482
7360
  /**
6483
7361
  * Event handlers registered for AppKit operations.
6484
7362
  *
@@ -6505,10 +7383,21 @@ interface AppKitContext {
6505
7383
  * ```
6506
7384
  */
6507
7385
  actions: Record<'bridge' | 'earn', Record<string, ((payload: unknown) => void)[]>>;
7386
+ /**
7387
+ * Disable success analytics for the underlying EarnKit, SwapKit, and
7388
+ * UnifiedBalanceKit.
7389
+ *
7390
+ * When `true`, completed earn, swap, and unified balance operations will not
7391
+ * POST analytics events. This does not disable error reporting; use
7392
+ * {@link AppKitContext.disableErrorReporting} for that. Defaults to `false`.
7393
+ *
7394
+ * @defaultValue false
7395
+ */
7396
+ disableAnalytics?: boolean;
6508
7397
  /**
6509
7398
  * Disable error telemetry for all sub-kits.
6510
7399
  *
6511
- * When `true`, none of the underlying kits (BridgeKit, SwapKit,
7400
+ * When `true`, none of the underlying kits (BridgeKit, SwapKit, EarnKit,
6512
7401
  * UnifiedBalanceKit) will POST error details to the telemetry
6513
7402
  * endpoint when operations throw. Defaults to `false` (enabled).
6514
7403
  *