/** * Copyright (c) 2026, Circle Internet Group, Inc. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { Abi } from 'abitype'; import { TransactionInstruction, Signer } from '@solana/web3.js'; /** * @packageDocumentation * @module ChainDefinitions * * This module provides a complete type system for blockchain chain definitions. * It supports both EVM and non‑EVM chains, token configurations, and multiple * versions of the Cross-Chain Transfer Protocol (CCTP). Additionally, utility types * are provided to extract subsets of chains (e.g. chains supporting USDC, EURC, or specific * CCTP versions) from a provided collection. * * All types are fully documented with TSDoc to maximize developer experience. */ /** * Represents basic information about a currency or token. * @interface Currency * @category Types * @description Provides the essential properties of a cryptocurrency or token. * @example * ```typescript * const ethCurrency: Currency = { * name: "Ether", * symbol: "ETH", * decimals: 18 * }; * ``` */ interface Currency { /** * The full name of the currency. * @example "Ether", "USDC" */ name: string; /** * The symbol or ticker of the currency. * @example "ETH", "USDC" */ symbol: string; /** * The number of decimal places for the currency. * @description Defines the divisibility of the currency (e.g., 1 ETH = 10^18 wei). * @example 18 for ETH, 6 for USDC */ decimals: number; } /** * Base information that all chain definitions must include. * @interface BaseChainDefinition * @category Types * @description Provides the common properties shared by all blockchain definitions. * @example * ```typescript * const baseChain: BaseChainDefinition = { * chain: Blockchain.Ethereum, * name: "Ethereum", * nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 }, * isTestnet: false * }; * ``` */ interface BaseChainDefinition { /** * The blockchain identifier from the {@link Blockchain} enum. */ chain: Blockchain; /** * The display name of the blockchain. * @example "Ethereum", "Solana", "Avalanche" */ name: string; /** * Optional title or alternative name for the blockchain. * @example "Ethereum Mainnet", "Solana Mainnet" */ title?: string; /** * Information about the native currency of the blockchain. */ nativeCurrency: Currency; /** * Indicates whether this is a testnet or mainnet. * @description Used to differentiate between production and testing environments. */ isTestnet: boolean; /** * Template URL for the blockchain explorer to view transactions. * @description URL template with a `\{hash\}` placeholder for transaction hash. * @example "https://etherscan.io/tx/\{hash\}", "https://sepolia.etherscan.io/tx/\{hash\}" */ explorerUrl: string; /** * Default RPC endpoints for connecting to the blockchain network. * @description Array of reliable public RPC endpoints that can be used for read and write operations. * The first endpoint in the array is considered the primary endpoint. * @example ["https://cloudflare-eth.com", "https://ethereum.publicnode.com"] */ rpcEndpoints: readonly string[]; /** * The contract address for EURC. * @description Its presence indicates that EURC is supported. */ eurcAddress: string | null; /** * The contract address for USDC. * @description Its presence indicates that USDC is supported. */ usdcAddress: string | null; /** * Optional CCTP configuration. * @description If provided, the chain supports CCTP. */ cctp: CCTPConfig | null; /** * Optional kit-specific contract addresses for enhanced chain functionality. * * @description When provided, the chain supports additional kit-specific logic in addition * to standard CCTP. This enables hybrid flows where both standard approve/burn/mint * and enhanced custom features are available. When undefined, the chain uses only * the standard CCTP flow. * * The address format varies by blockchain: * - EVM chains: 40-character hexadecimal with 0x prefix (e.g., "0x1234...") * - Solana: Base58-encoded 32-byte address (e.g., "9WzDX...") * - Other chains: Platform-specific address formats * * @example * ```typescript * // EVM chain with bridge contract * const evmChain: ChainDefinition = { * // ... other properties * kitContracts: { * bridge: "0x1234567890abcdef1234567890abcdef12345678" * } * } * * // Solana chain with bridge contract * const solanaChain: ChainDefinition = { * // ... other properties * kitContracts: { * bridge: "9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM" * } * } * ``` */ kitContracts?: KitContracts; } /** * Represents chain definitions for Ethereum Virtual Machine (EVM) compatible blockchains. * @interface EVMChainDefinition * @extends BaseChainDefinition * @category Types * @description Adds properties specific to EVM chains. * @example * ```typescript * const ethereum: EVMChainDefinition = { * type: 'evm', * chain: Blockchain.Ethereum, * chainId: 1, * name: 'Ethereum', * title: 'Ethereum Mainnet', * nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 }, * isTestnet: false * }; * ``` */ interface EVMChainDefinition extends BaseChainDefinition { /** * Discriminator for EVM chains. * @description Used for type narrowing when handling different chain types. */ type: 'evm'; /** * The unique identifier for the blockchain. * @description Standard EVM chain ID as defined in EIP-155. * @example 1 for Ethereum Mainnet, 137 for Polygon. */ chainId: number; } /** * Represents chain definitions for non-EVM blockchains. * @interface NonEVMChainDefinition * @extends BaseChainDefinition * @category Types * @description Contains properties for blockchains that do not use the EVM. * @example * ```typescript * const solana: NonEVMChainDefinition = { * type: 'solana', * chain: Blockchain.Solana, * name: 'Solana', * nativeCurrency: { name: 'Solana', symbol: 'SOL', decimals: 9 }, * isTestnet: false * }; * ``` */ interface NonEVMChainDefinition extends BaseChainDefinition { /** * Discriminator for non-EVM chains. * @description Identifies the specific blockchain platform. */ type: 'algorand' | 'avalanche' | 'solana' | 'aptos' | 'near' | 'stellar' | 'sui' | 'hedera' | 'noble' | 'polkadot'; } /** * The type of chain. * @alias ChainType * @category Types * @description Represents the type of chain. * @example * ```typescript * const chainType: ChainType = 'evm' * ``` */ type ChainType = EVMChainDefinition['type'] | NonEVMChainDefinition['type']; /** * Public chain definition type. * @alias ChainDefinition * @category Types * @description Represents either an EVM-based or non-EVM-based blockchain definition. * This type is used by developers to define chain configurations. * @example * ```typescript * // Standard chain with CCTP support only * const ethereumChain: ChainDefinition = { * type: 'evm', * chain: Blockchain.Ethereum, * chainId: 1, * name: 'Ethereum', * nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 }, * isTestnet: false, * explorerUrl: 'https://etherscan.io/tx/{hash}', * rpcEndpoints: ['https://eth.example.com'], * eurcAddress: null, * usdcAddress: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', * cctp: { * domain: 0, * contracts: { * v2: { * type: 'split', * tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d', * messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64', * confirmations: 65, * fastConfirmations: 2 * } * } * }, * kitContracts: undefined * }; * * // Chain with custom contract support (hybrid flow) * const customChain: ChainDefinition = { * ...ethereumChain, * kitContracts: { * bridge: '0x1234567890abcdef1234567890abcdef12345678' * } * }; * ``` */ type ChainDefinition = EVMChainDefinition | NonEVMChainDefinition; /** * Chain definition with CCTPv2 configuration. * @alias ChainDefinitionWithCCTPv2 * @extends ChainDefinition * @category Types * @description Represents a chain definition that includes CCTPv2 configuration. This is useful for typescript consumers to narrow down the type of chain definition to a chain that supports CCTPv2. * @example * ```typescript * const ethereumWithCCTPv2: ChainDefinitionWithCCTPv2 = { * ...ethereum, * cctp: { * domain: 0, * contracts: { * v2: { * type: 'merged', * contract: '0x123...' * } * } * } * }; * ``` */ type ChainDefinitionWithCCTPv2 = ChainDefinition & { cctp: CCTPConfig & { contracts: { v2: VersionConfig; }; }; usdcAddress: string; }; /** * Chain identifier that can be used in transfer parameters and factory functions. * This can be either: * - A ChainDefinition object * - A Blockchain enum value (e.g., Blockchain.Ethereum) * - A string literal of the blockchain value (e.g., "Ethereum") */ type ChainIdentifier = ChainDefinition | Blockchain | `${Blockchain}`; interface CCTPSplitConfig { type: 'split'; tokenMessenger: string; messageTransmitter: string; confirmations: number; } interface CCTPMergedConfig { type: 'merged'; contract: string; confirmations: number; } type VersionConfig = CCTPSplitConfig | CCTPMergedConfig; type CCTPContracts = Partial<{ v1: VersionConfig; v2: VersionConfig & { fastConfirmations: number; }; }>; /** * Configuration for the Cross-Chain Transfer Protocol (CCTP). * @interface CCTPConfig * @category Types * @description Contains the domain and required contract addresses for CCTP support. * @example * ``` * const cctpConfig: CCTPConfig = { * domain: 0, * contracts: { * TokenMessenger: '0xabc', * MessageReceiver: '0xdef' * } * }; * ``` */ interface CCTPConfig { /** * The CCTP domain identifier. */ domain: number; /** * The contracts required for CCTP. */ contracts: CCTPContracts; } /** * Available kit contract types for enhanced chain functionality. * * @description Defines the valid contract types that can be deployed on chains * to provide additional features beyond standard CCTP functionality. * * @example * ```typescript * import type { KitContractType } from '@core/chains' * * const contractType: KitContractType = 'bridge' // Valid * const invalidType: KitContractType = 'invalid' // TypeScript error * ``` */ type KitContractType = 'bridge'; /** * Kit-specific contract addresses for enhanced chain functionality. * * @description Maps contract types to their addresses on a specific chain. * All contract types are optional, allowing chains to selectively support * specific kit features. * * @example * ```typescript * import type { KitContracts } from '@core/chains' * * const contracts: KitContracts = { * bridge: "0x1234567890abcdef1234567890abcdef12345678" * } * * // Future example with multiple contract types: * const futureContracts: KitContracts = { * bridge: "0x1234567890abcdef1234567890abcdef12345678", * // Note: other contract types would be added to KitContractType union * // customType: "0xabcdef1234567890abcdef1234567890abcdef12" * } * ``` */ type KitContracts = Partial>; /** * Enumeration of all blockchains known to this library. * * This enum contains every blockchain that has a chain definition, regardless * of whether bridging is currently supported. For chains that support bridging * via CCTPv2, see {@link BridgeChain}. * * @enum * @category Enums * @description Provides string identifiers for each blockchain with a definition. * @see {@link BridgeChain} for the subset of chains that support CCTPv2 bridging. */ declare enum Blockchain { Algorand = "Algorand", Algorand_Testnet = "Algorand_Testnet", Aptos = "Aptos", Aptos_Testnet = "Aptos_Testnet", Arc_Testnet = "Arc_Testnet", Arbitrum = "Arbitrum", Arbitrum_Sepolia = "Arbitrum_Sepolia", Avalanche = "Avalanche", Avalanche_Fuji = "Avalanche_Fuji", Base = "Base", Base_Sepolia = "Base_Sepolia", Celo = "Celo", Celo_Alfajores_Testnet = "Celo_Alfajores_Testnet", Codex = "Codex", Codex_Testnet = "Codex_Testnet", Ethereum = "Ethereum", Ethereum_Sepolia = "Ethereum_Sepolia", Hedera = "Hedera", Hedera_Testnet = "Hedera_Testnet", HyperEVM = "HyperEVM", HyperEVM_Testnet = "HyperEVM_Testnet", Ink = "Ink", Ink_Testnet = "Ink_Testnet", Linea = "Linea", Linea_Sepolia = "Linea_Sepolia", NEAR = "NEAR", NEAR_Testnet = "NEAR_Testnet", Noble = "Noble", Noble_Testnet = "Noble_Testnet", Optimism = "Optimism", Optimism_Sepolia = "Optimism_Sepolia", Polkadot_Asset_Hub = "Polkadot_Asset_Hub", Polkadot_Westmint = "Polkadot_Westmint", Plume = "Plume", Plume_Testnet = "Plume_Testnet", Polygon = "Polygon", Polygon_Amoy_Testnet = "Polygon_Amoy_Testnet", Sei = "Sei", Sei_Testnet = "Sei_Testnet", Solana = "Solana", Solana_Devnet = "Solana_Devnet", Sonic = "Sonic", Sonic_Testnet = "Sonic_Testnet", Stellar = "Stellar", Stellar_Testnet = "Stellar_Testnet", Sui = "Sui", Sui_Testnet = "Sui_Testnet", Unichain = "Unichain", Unichain_Sepolia = "Unichain_Sepolia", World_Chain = "World_Chain", World_Chain_Sepolia = "World_Chain_Sepolia", XDC = "XDC", XDC_Apothem = "XDC_Apothem", ZKSync_Era = "ZKSync_Era", ZKSync_Sepolia = "ZKSync_Sepolia" } /** * Core type definitions for blockchain transaction execution and gas estimation. * * This module provides TypeScript interfaces and types for handling blockchain * transactions across different networks, with a focus on EVM-compatible chains * and gas estimation. * * @module types */ /** * Estimated gas information for a blockchain transaction. * * This interface provides a unified way to represent gas costs across different * blockchain networks, supporting both EVM-style gas calculations and other * fee models. * * @interface EstimatedGas * @category Types * @example * ```typescript * // EVM chain example * const evmGas: EstimatedGas = { * gas: 21000n, * gasPrice: 1000000000n, // 1 Gwei * fee: (21000n * 1000000000n).toString() // Total fee in wei * }; * * // Solana example * const solanaGas: EstimatedGas = { * gas: 5000n, // Lamports for compute units * fee: '5000' // Total fee in Lamports * }; * ``` */ interface EstimatedGas { /** * The amount of gas estimated for the transaction. * For EVM chains, this represents the gas units. * For other chains, this might represent compute units or similar metrics. * * @example 21000n, 5000n */ gas: bigint; /** * The estimated price per unit of gas. * This is primarily used in EVM chains where gas price is a separate metric. * * @example 1000000000n */ gasPrice: bigint; /** * The total estimated fee as a string. * This field is useful for chains where gas/gasPrice isn't the whole story * or when the total fee needs to be represented in a different format. * For EVM chains, this is the total fee in wei (gas * gasPrice). * * @example "21000000000000", "5000" */ fee: string; } /** * Override parameters for EVM gas estimation. * * These parameters allow customization of gas estimation behavior * for EVM-compatible chains. * * @interface EvmEstimateOverrides */ interface EvmEstimateOverrides { /** * The sender's address for the transaction. * @example "0x742d35Cc6634C0532925a3b844Bc454e4438f44e" */ from?: string; /** * The value to be sent with the transaction in wei. * @example 1000000000000000000n // 1 ETH */ value?: bigint; /** * The block tag to use for estimation. * @example "latest", "safe", "finalized" */ blockTag?: 'latest' | 'earliest' | 'pending' | 'safe' | 'finalized'; /** * The maximum gas limit for the transaction. * @example 3000000 */ gasLimit?: number; /** * The maximum fee per gas unit (EIP-1559). * @example 20000000000n // 20 Gwei */ maxFeePerGas?: bigint; /** * The maximum priority fee per gas unit (EIP-1559). * @example 1500000000n // 1.5 Gwei */ maxPriorityFeePerGas?: bigint; } /** * Extended override parameters for EVM transaction execution. * * Includes all estimation overrides plus additional parameters * specific to transaction execution. * * @interface EvmExecuteOverrides * @extends EvmEstimateOverrides */ interface EvmExecuteOverrides extends EvmEstimateOverrides { /** * The nonce to use for the transaction. * If not provided, the current nonce of the sender will be used. * @example 42 */ nonce?: number; } /** * Prepared contract execution for EVM chains. * * Represents a prepared contract execution that can be estimated * and executed on EVM-compatible chains. * * @interface EvmPreparedChainRequest */ interface EvmPreparedChainRequest { /** The type of the prepared execution. */ type: 'evm'; /** * Estimate the gas cost for the contract execution. * * @param overrides - Optional parameters to override the default estimation behavior * @param fallback - Optional fallback gas information to use if the estimation fails * @returns A promise that resolves to the estimated gas information * @throws If the estimation fails */ estimate(overrides?: EvmEstimateOverrides, fallback?: EstimatedGas): Promise; /** * Execute the prepared contract call. * * @param overrides - Optional parameters to override the default execution behavior * @returns A promise that resolves to the transaction hash * @throws If the execution fails */ execute(overrides?: EvmExecuteOverrides): Promise; } /** * Union type for all supported prepared contract executions. * Currently only supports EVM chains, but can be extended for other chains. */ type PreparedChainRequest = EvmPreparedChainRequest | SolanaPreparedChainRequest | NoopPreparedChainRequest; /** * Parameters for preparing an EVM contract execution. */ type EvmPreparedChainRequestParams = { /** The type of the prepared execution. */ type: 'evm'; /** The ABI of the contract. */ abi: Abi | string[]; /** The address of the contract. */ address: `0x${string}`; /** The name of the function to call. */ functionName: string; /** The arguments to pass to the function. */ args: unknown[]; } & Partial; /** * Solana-specific parameters for preparing a transaction. * @interface SolanaPreparedChainRequestParams */ interface SolanaPreparedChainRequestParams { /** * The array of instructions to include in the transaction. */ instructions: TransactionInstruction[]; /** * Additional signers besides the Adapter’s wallet (e.g. program-derived authorities). */ signers?: Signer[]; /** * Optional override for how many compute units this transaction may consume. * If omitted, the network’s default compute budget applies. */ computeUnitLimit?: number; } /** * Solana-specific configuration for transaction estimation. * @interface SolanaEstimateOverrides */ interface SolanaEstimateOverrides { /** Optional compute unit limit for the transaction. */ computeUnitLimit?: number; } /** * Solana-specific configuration for transaction execution. * @interface SolanaExecuteOverrides * @extends SolanaEstimateOverrides */ interface SolanaExecuteOverrides extends SolanaEstimateOverrides { /** The commitment level for the transaction. */ preflightCommitment?: 'processed' | 'confirmed' | 'finalized'; /** The maximum number of retries for the transaction. */ maxRetries?: number; /** Whether to skip the preflight check. */ skipPreflight?: boolean; } /** * Solana-specific prepared chain request. * @interface SolanaPreparedChainRequest */ interface SolanaPreparedChainRequest { /** The type of the chain request. */ type: 'solana'; /** Estimate the compute units and fee for the transaction. */ estimate(overrides?: SolanaEstimateOverrides, fallback?: EstimatedGas): Promise; /** Execute the prepared transaction. */ execute(overrides?: SolanaExecuteOverrides): Promise; } /** * No-op prepared chain request for unsupported operations. * * This interface represents a prepared chain request that performs no operation. * It is returned when an action is not supported by the target chain or when * no actual blockchain interaction is required. * * @remarks * The estimate and execute methods return placeholder values since no actual * transaction is performed. This allows the calling code to handle unsupported * operations gracefully without breaking the expected interface contract. * * @example * ```typescript * const noopRequest: NoopPreparedChainRequest = { * type: 'noop', * estimate: async () => ({ gasLimit: 0n, gasPrice: 0n, totalFee: 0n }), * execute: async () => '0x0000000000000000000000000000000000000000000000000000000000000000' * } * ``` */ interface NoopPreparedChainRequest { /** The type of the prepared request. */ type: 'noop'; /** * Placeholder for the estimate method. * @returns The estimated gas cost. */ estimate: (overrides?: EvmEstimateOverrides | SolanaEstimateOverrides, fallback?: EstimatedGas) => Promise; /** * Placeholder for the execute method. * @returns The transaction hash. */ execute: () => Promise; } /** * Union type for all supported contract execution parameters. * Currently only supports EVM chains, but can be extended for other chains. */ type PreparedChainRequestParams = EvmPreparedChainRequestParams | SolanaPreparedChainRequestParams; /** * Response from waiting for a transaction to be mined and confirmed on the blockchain. * * @interface WaitForTransactionResponse */ interface WaitForTransactionResponse { /** * The transaction hash identifier. * @example "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef" */ txHash: string; /** * The final status of the transaction execution. * Indicates whether the transaction was successfully executed or reverted. * @example "success", "reverted" */ status: 'success' | 'reverted'; /** * The total amount of gas used by all transactions in the block up to and including this transaction. * Represents the cumulative gas consumption within the block. * @example 2100000n */ cumulativeGasUsed?: bigint; /** * The amount of gas actually consumed by this specific transaction. * This value is always less than or equal to the gas limit set for the transaction. * @example 21000n */ gasUsed?: bigint; /** * The block number where the transaction was mined. * Represents the sequential position of the block in the blockchain. * @example 18500000n */ blockNumber?: bigint; /** * The hash of the block containing this transaction. * Provides a unique identifier for the block where the transaction was included. * @example "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890" */ blockHash?: string; /** * The zero-based index position of the transaction within the block. * Indicates the order in which this transaction appears in the block. * @example 5 */ transactionIndex?: number; /** * The actual gas price paid per unit of gas for this transaction. * For EIP-1559 transactions, this reflects the base fee plus priority fee. * @example 15000000000n // 15 Gwei */ effectiveGasPrice?: bigint; } interface WaitForTransactionConfig { /** * The timeout for the transaction to be mined and confirmed on the blockchain. * @example 10000 */ timeout?: number | undefined; /** * The number of confirmations to wait for the transaction to be mined and confirmed on the blockchain. * @example 1 */ confirmations?: number; /** * The maximum supported transaction version for getTransaction. * Defaults to 0 if not provided. * @example 0 */ maxSupportedTransactionVersion?: number; } /** * Type utility to extract the address context from adapter capabilities. * * @typeParam TAdapterCapabilities - The adapter capabilities type * @returns The address context type or never if capabilities are undefined */ type ExtractAddressContext = TAdapterCapabilities extends { addressContext: infer TContext; } ? TContext : never; type AddressField = TAddressContext extends 'user-controlled' ? { /** * ℹ️ Address is forbidden for user-controlled adapters. * * User-controlled adapters (like browser wallets or private key adapters) * automatically resolve the address from the connected wallet or signer. * Providing an explicit address would conflict with this behavior. * * @example * ```typescript * // ℹ️ This will cause a TypeScript error: * const context: AdapterContext<{ addressContext: 'user-controlled' }> = { * adapter: userAdapter, * chain: 'Ethereum', * address: '0x123...' // Error: Address is forbidden for user-controlled adapters * } * ``` */ address?: never; } : TAddressContext extends 'developer-controlled' ? { /** * ℹ️ Address is required for developer-controlled adapters. * * Developer-controlled adapters (like enterprise providers or server-side adapters) * require an explicit address for each operation since they don't have a single * connected wallet. The address must be provided for every operation. * * @example * ```typescript * // ℹ️ This is required: * const context: AdapterContext<{ addressContext: 'developer-controlled' }> = { * adapter: devAdapter, * chain: 'Ethereum', * address: '0x123...' // Required for developer-controlled adapters * } * * // ℹ️ This will cause a TypeScript error: * const context: AdapterContext<{ addressContext: 'developer-controlled' }> = { * adapter: devAdapter, * chain: 'Ethereum' * // Error: Address is required for developer-controlled adapters * } * ``` */ address: string; } : { /** * Address is optional for legacy adapters. * * Legacy adapters without defined capabilities maintain backward compatibility * by allowing optional address specification. */ address?: string; }; /** * Generic operation context for adapter methods with compile-time address validation. * * This type provides compile-time enforcement of address requirements based on the * adapter's capabilities. The address field behavior is determined by the adapter's * address control model: * * - **User-controlled adapters** (default): The `address` field is forbidden (never) because * the address is automatically resolved from the connected wallet or signer. * - **Developer-controlled adapters**: The `address` field is required (string) because * each operation must explicitly specify which address to use. * - **Legacy adapters**: The `address` field remains optional for backward compatibility. * * @typeParam TAdapterCapabilities - The adapter capabilities type to derive address requirements from * * @example * ```typescript * import { OperationContext } from '@core/adapter' * * // User-controlled adapter context (default - address forbidden) * type UserContext = OperationContext<{ addressContext: 'user-controlled', supportedChains: [] }> * const userCtx: UserContext = { * chain: 'Ethereum' * // address: '0x123...' // ❌ TypeScript error: address not allowed * } * * // Developer-controlled adapter context (explicit - address required) * type DevContext = OperationContext<{ addressContext: 'developer-controlled', supportedChains: [] }> * const devCtx: DevContext = { * chain: 'Ethereum', * address: '0x123...' // ✅ Required for developer-controlled * } * ``` */ type OperationContext = { /** * The blockchain network to use for this operation. */ chain: ChainIdentifier; } & AddressField>; /** * Fully resolved context for an adapter operation, with concrete chain and address. * * This interface guarantees that both the blockchain network (`chain`) and the account * address (`address`) are present and valid. It is produced by resolving an {@link OperationContext}, * which may have optional or conditional fields, into a form suitable for internal logic and action handlers. * * - `chain`: A fully resolved {@link ChainDefinition}, either explicitly provided or inferred from the adapter. * - `address`: A string representing the resolved account address, determined by the context or adapter, * depending on the address control model (developer- or user-controlled). * * Use this type when an operation requires both the chain and address to be unambiguous and available. * * @example * ```ts * import { ResolvedOperationContext} from "@core/adapter" * import { Solana, ChainDefinition } from '@core/chains'; * * const context: ResolvedOperationContext = { * chain: Solana, * address: '7Gk1v...abc123', // a valid Solana address * }; * * // Use context.chain and context.address in adapter operations * ``` */ interface ResolvedOperationContext { /** * The chain identifier for this operation. * Guaranteed to be defined - either from context or adapter default. */ chain: ChainDefinition; /** * The address for this operation. * Guaranteed to be defined - either specified (developer-controlled) or resolved (user-controlled). */ address: string; } /** * Base interface for all action parameter objects. * * Provide a compile-time marker to explicitly identify objects that represent * action parameters (leaf nodes) versus namespace containers that should be * traversed during type recursion. * * @remarks * This marker property exists only at the type level and is stripped away * during compilation. It serves as a deterministic way to identify action * parameter objects without relying on property name heuristics. * * All action parameter objects must extend this interface to be properly * recognized by the recursive utility types in the action system. */ interface ActionParameters { /** * Compile-time marker identifying this as an action parameter object. * * This property is used by the type system to distinguish between * namespace containers and action parameter definitions. It does not * exist at runtime and is purely for TypeScript's type checking. */ readonly __isActionParams: true; } /** * EIP-2612 permit signature parameters for gasless token approvals. * * Contains the signature components and deadline required for permit-based * token spending authorization without requiring separate approval transactions. * * @example * ```typescript * const permitParams: PermitParams = { * deadline: BigInt(Math.floor(Date.now() / 1000) + 3600), // 1 hour from now * v: 27, * r: '0x1234567890abcdef...', * s: '0xfedcba0987654321...' * } * ``` */ interface PermitParams { /** * Permit expiration timestamp (Unix timestamp in seconds). * * The permit signature becomes invalid after this timestamp. * Must be greater than the current block timestamp. */ deadline: bigint; /** * Recovery parameter of the ECDSA signature (27 or 28). * * Used to recover the public key from the signature components. */ v: number; /** * R component of the ECDSA signature. * * First 32 bytes of the signature as a hex string. */ r: string; /** * S component of the ECDSA signature. * * Second 32 bytes of the signature as a hex string. */ s: string; } /** * Action map for Circle's Cross-Chain Transfer Protocol (CCTP) version 2 operations. * * Define the parameter schemas for CCTP v2 actions that enable native USDC * transfers between supported blockchain networks. Use Circle's attestation * service to verify and complete cross-chain transactions with cryptographic * proof of burn and mint operations. * * @remarks * CCTP v2 represents Circle's native cross-chain transfer protocol that allows * USDC to move between chains without traditional lock-and-mint bridging. * Instead, USDC is burned on the source chain and minted natively on the * destination chain using cryptographic attestations. * * The protocol supports both "slow" (free) and "fast" (fee-based) transfer * modes, with configurable finality thresholds and destination execution * parameters for advanced use cases. * * @example * ```typescript * import type { CCTPv2ActionMap } from '@core/adapter/actions/cctp/v2' * import { mainnet, polygon } from '@core/chains' * * // Deposit and burn USDC for cross-chain transfer * const burnParams: CCTPv2ActionMap['depositForBurn'] = { * amount: '1000000', // 1 USDC (6 decimals) * mintRecipient: '0x742d35Cc6634C0532925a3b8D8E5e8d8D8e5e8d8D8e5e8', * maxFee: '1000', // 0.001 USDC fast fee * minFinalityThreshold: 65, * fromChain: mainnet, * toChain: polygon * } * * // Receive and mint USDC on destination chain * const receiveParams: CCTPv2ActionMap['receiveMessage'] = { * eventNonce: '0x123abc...', * attestation: '0xdef456...', * message: '0x789012...', * fromChain: mainnet, * toChain: polygon * } * ``` * * @see {@link ChainDefinitionWithCCTPv2} for supported chain definitions */ interface CCTPv2ActionMap { /** * Initiate a cross-chain USDC transfer by depositing and burning tokens on the source chain. * * Burn USDC tokens on the source chain and generate a message for attestation * by Circle's infrastructure. The burned tokens will be minted on the destination * chain once the attestation is obtained and the receive message is executed. * * @remarks * This action represents the first step in a CCTP cross-chain transfer. After * execution, you must wait for Circle's attestation service to observe the burn * event and provide a cryptographic attestation that can be used to mint the * equivalent amount on the destination chain. * * The `maxFee` parameter enables fast transfers through Circle's fast liquidity * network, where liquidity providers can fulfill transfers immediately in exchange * for a fee. Set to "0" for slower, free transfers that wait for full finality. */ depositForBurn: ActionParameters & { /** * Amount of USDC to deposit and burn (in token's smallest unit). * * Specify the amount in the token's atomic units (e.g., for USDC with * 6 decimals, "1000000" represents 1 USDC). This amount will be burned * on the source chain and minted on the destination chain. */ amount: bigint; /** * Address of the recipient who will receive minted tokens on the destination chain. * * Provide the destination address as a 32-byte hex string (bytes32 format). */ mintRecipient: string; /** * Address authorized to call receiveMessage on the destination chain. * * Restrict who can execute the final minting step on the destination chain. * If not specified or set to bytes32(0), any address can call receiveMessage. * Use this for advanced integrations requiring specific execution control. * * @defaultValue bytes32(0) - allows any address to complete the transfer */ destinationCaller?: string; /** * Maximum fee to pay for fast transfer fulfillment. * * Specify the maximum amount (in the same units as `amount`) you're willing * to pay for immediate liquidity. Set to "0" for free transfers that wait * for full chain finality. Higher fees increase the likelihood of fast * fulfillment. */ maxFee: bigint; /** * Minimum finality threshold for attestation eligibility. * * Set the number of confirmations required before Circle's attestation * service will observe and attest to the burn event. Higher values * provide stronger finality guarantees but increase transfer time. * Typical values: 1000 for fast transfers, 2000 for maximum security. */ minFinalityThreshold: number; /** * Source chain definition where tokens will be burned. */ fromChain: ChainDefinitionWithCCTPv2; /** * Destination chain definition where tokens will be minted. */ toChain: ChainDefinitionWithCCTPv2; }; /** * Complete a cross-chain transfer by receiving and processing an attested message. * * Execute the final step of a CCTP transfer by submitting Circle's attestation * and the original message to mint USDC tokens on the destination chain. * This action consumes the attestation and delivers tokens to the specified * recipient from the original burn operation. * * @remarks * This action must be called after obtaining a valid attestation from Circle's * API for a corresponding `depositForBurn` operation. The attestation proves * that tokens were burned on the source chain and authorizes minting the * equivalent amount on the destination chain. * * The message parameter contains the original burn message data, while the * attestation provides the cryptographic proof. Both must match exactly * with Circle's records for the transaction to succeed. */ receiveMessage: ActionParameters & { /** * Unique nonce identifying the specific burn event. * * Provide the event nonce from the MessageSent event emitted by the * depositForBurn transaction. This must be a 0x-prefixed 64-character * hex string representing the 32-byte nonce value. */ readonly eventNonce: string; /** * Cryptographic attestation from Circle's infrastructure. * * Submit the attestation obtained from Circle's API that proves the * corresponding burn event occurred and was observed. This must be * a valid 0x-prefixed hex string containing Circle's signature data. */ readonly attestation: string; /** * Original message bytes from the source chain burn event. * * Provide the raw message data emitted in the MessageSent event from * the depositForBurn transaction. This 0x-prefixed hex string contains * the encoded transfer details that will be verified against the attestation. */ readonly message: string; /** * Source chain definition where the original burn occurred. */ readonly fromChain: ChainDefinitionWithCCTPv2; /** * Destination chain definition where tokens will be minted. */ readonly toChain: ChainDefinitionWithCCTPv2; /** * Optional destination wallet address on the destination chain to receive minted USDC. * * When provided (e.g., for Solana), the mint instruction will derive the * recipient's Associated Token Account (ATA) from this address instead of * the adapter's default address. */ readonly destinationAddress?: string; /** * The mint recipient address from the decoded CCTP message. * * This is the actual address encoded in the burn message where tokens will be minted. * For Solana, this is already the Associated Token Account (ATA) address, not the owner. * For EVM chains, this is the recipient's wallet address. */ readonly mintRecipient?: string; }; /** * Initiate a cross-chain USDC transfer using a custom bridge contract with preapproval funnel. * * This action combines token approval and burning into a single transaction using * a custom bridge contract that supports preapproval functionality. It provides * enhanced gas efficiency by eliminating separate approval transactions while * maintaining the same developer interface as standard CCTP transfers. * * @remarks * This action is only available on chains that support custom bridge contracts, * as determined by `hasCustomContractSupport(chain, 'bridge')`. The custom bridge * handles token approval internally and supports advanced features like protocol * fees and custom routing logic. * * For basic use cases, this provides the same interface as `depositForBurn`. * For advanced use cases, optional protocol fee parameters enable custom fee * collection and revenue sharing models. * * @example * ```typescript * // Basic usage (same as depositForBurn) * await adapter.action('cctp.v2.customBurn', { * amount: BigInt('1000000'), * mintRecipient: '0x...', * maxFee: BigInt('1000'), * minFinalityThreshold: 65 * }) * * // Advanced usage with protocol fees * await adapter.action('cctp.v2.customBurn', { * amount: BigInt('1000000'), * mintRecipient: '0x...', * maxFee: BigInt('1000'), * minFinalityThreshold: 65, * protocolFee: BigInt('100'), * feeRecipient: '0xFeeRecipientAddress' * }) * ``` */ customBurn: ActionParameters & { /** * Amount of USDC to burn (in token's smallest unit). * * Specify the amount in the token's atomic units (e.g., for USDC with * 6 decimals, 1000000n represents 1 USDC). This amount will be burned * on the source chain and minted on the destination chain. */ amount: bigint; /** * Address of the recipient who will receive minted tokens on the destination chain. * * Provide the destination address as a 32-byte hex string (bytes32 format). */ mintRecipient: string; /** * Address authorized to call receiveMessage on the destination chain. * * Restrict who can execute the final minting step on the destination chain. * If not specified or set to bytes32(0), any address can call receiveMessage. * Use this for advanced integrations requiring specific execution control. * * @defaultValue bytes32(0) - allows any address to complete the transfer */ destinationCaller?: string; /** * Maximum fee to pay for fast transfer fulfillment. * * Specify the maximum amount (in the same units as `amount`) you're willing * to pay for immediate liquidity. Set to "0" for free transfers that wait * for full chain finality. Higher fees increase the likelihood of fast * fulfillment. */ maxFee: bigint; /** * Minimum finality threshold for attestation eligibility. * * Set the number of confirmations required before Circle's attestation * service will observe and attest to the burn event. Higher values * provide stronger finality guarantees but increase transfer time. * Typical values: 65 for standard transfers, 2000 for maximum security. */ minFinalityThreshold: number; /** * Protocol fee amount (in token's smallest unit). * * Additional fee charged by the custom bridge for enhanced functionality. * This fee is separate from the Circle fast transfer fee and is paid to * the specified fee recipient. Enables custom fee collection and revenue * sharing models for bridge operators. * * @defaultValue 0n - no protocol fee for basic usage */ protocolFee?: bigint | undefined; /** * Address to receive the protocol fee. * * Wallet address where the protocol fee will be sent. This enables * custom fee collection and revenue sharing models for bridge operators. * Only relevant when protocolFee is greater than 0. * * @defaultValue bridge contract address - safe fallback for zero fees */ feeRecipient?: string | undefined; /** * Source chain definition where tokens will be burned. */ fromChain: ChainDefinitionWithCCTPv2; /** * Destination chain definition where tokens will be minted. */ toChain: ChainDefinitionWithCCTPv2; /** * Permit parameters for the custom bridge contract. */ permitParams?: PermitParams; }; } /** * Central registry for Cross-Chain Transfer Protocol (CCTP) action namespaces. * * Define versioned action maps for CCTP operations across different protocol * versions. Each version key represents a specific CCTP implementation with * its own parameter schemas and operational requirements. * * @remarks * CCTP actions enable cross-chain USDC transfers through Circle's native * bridging protocol. Each version namespace contains actions specific to * that protocol iteration, allowing for protocol upgrades while maintaining * backward compatibility in the action system. * * This interface follows the same pattern as other action namespaces but * is organized by protocol version rather than token type. * * @see {@link CCTPv2ActionMap} for version 2 action definitions */ interface CCTPActionMap { /** CCTP version 2 operations for cross-chain USDC transfers. */ readonly v2: CCTPv2ActionMap; } interface TokenActionMap { /** * Set an allowance for a delegate to spend tokens on behalf of the wallet. * * On chains without native allowance support, this may return a noop result * indicating the step can be safely skipped. */ approve: ActionParameters & { /** * The contract address of the token. */ tokenAddress: string; /** * The address that will be approved to spend the tokens. */ delegate: string; /** * The amount of tokens to approve for spending (in token's smallest unit). */ amount: bigint; }; /** * Check the current allowance between an owner and spender for any token. * * On chains without allowance support, this typically returns the maximum * possible value to indicate unlimited spending capability. */ allowance: ActionParameters & { /** * The contract address of the token. */ tokenAddress: string; /** * The address of the wallet that owns the tokens. If not provided, it will be * automatically derived from the adapter context. */ walletAddress?: string | undefined; /** * The address to check the allowance for. */ delegate: string; }; /** * Transfer tokens directly from the wallet to another address. */ transfer: ActionParameters & { /** * The contract address of the token. */ tokenAddress: string; /** * The address to send the tokens to. */ to: string; /** * The amount of tokens to transfer (in token's smallest unit). */ amount: bigint; }; /** * Transfer tokens from one address to another using a pre-approved allowance. * * On chains without allowance support, this may behave differently or throw * an error if the operation is not supported. */ transferFrom: ActionParameters & { /** * The contract address of the token. */ tokenAddress: string; /** * The address to transfer tokens from (must have given allowance to the caller). */ from: string; /** * The address to send the tokens to. */ to: string; /** * The amount of tokens to transfer (in token's smallest unit). */ amount: bigint; }; /** * Get the current token balance for a wallet address. */ balanceOf: ActionParameters & { /** * The contract address of the token. */ tokenAddress: string; /** * The address to check the balance for. If not provided, it will be * automatically derived from the adapter context. */ walletAddress?: string | undefined; }; } /** * USDC-specific operations that automatically resolve the token address. * * These include all standard ERC20 operations plus additional safety functions * that USDC supports. The interface provides the same core operations as * {@link TokenActionMap} but without requiring a `tokenAddress` parameter, * plus additional USDC-specific extensions. * * @example * ```typescript * // USDC operations (address auto-resolved) * await adapter.action('usdc.approve', { * delegate: '0x1234...', * amount: '1000000' // 1 USDC * }) * * // USDC-specific safe allowance functions * await adapter.action('usdc.increaseAllowance', { * delegate: '0x1234...', * amount: '500000' // increase by 0.5 USDC * }) * * // vs. general token operations (address required) * await adapter.action('token.approve', { * tokenAddress: '0xA0b86a33E6441c8C1c7C16e4c5e3e5b5e4c5e3e5b5e4c5e', * delegate: '0x1234...', * amount: '1000000' * }) * ``` */ type BaseUSDCActions = { [K in keyof TokenActionMap]: Omit; }; /** * USDC action map with both standard ERC20 operations and USDC-specific extensions. * * This provides all standard token operations plus additional safety functions * that USDC implements beyond the base ERC20 standard. */ interface USDCActionMap { /** * Set an allowance for a delegate to spend USDC tokens on behalf of the wallet. * * Automatically uses the USDC contract address for the current chain. * On chains without native allowance support, this may return a noop result. */ approve: BaseUSDCActions['approve']; /** * Check the current allowance between an owner and spender for USDC tokens. * * Automatically uses the USDC contract address for the current chain. * This is a read-only operation. */ allowance: BaseUSDCActions['allowance']; /** * Safely increase the allowance for a delegate to spend USDC tokens. * * This is a USDC-specific function that provides safer allowance management * compared to direct approve() calls. Automatically uses the USDC contract * address for the current chain. */ increaseAllowance: ActionParameters & { /** * The address that will have their allowance increased. */ delegate: string; /** * The amount to increase the allowance by (in USDC's smallest unit). */ amount: bigint; /** * The chain definition for the current chain. */ chain?: ChainDefinition; }; /** * Safely decrease the allowance for a delegate to spend USDC tokens. * * This is a USDC-specific function that provides safer allowance management. * Automatically uses the USDC contract address for the current chain. */ decreaseAllowance: ActionParameters & { /** * The address that will have their allowance decreased. */ delegate: string; /** * The amount to decrease the allowance by (in USDC's smallest unit). */ amount: bigint; }; /** * Transfer USDC tokens directly from the wallet to another address. * * Automatically uses the USDC contract address for the current chain. */ transfer: BaseUSDCActions['transfer']; /** * Transfer USDC tokens from one address to another using a pre-approved allowance. * * Automatically uses the USDC contract address for the current chain. * The caller must have sufficient allowance from the 'from' address. */ transferFrom: BaseUSDCActions['transferFrom']; /** * Get the current USDC balance for a wallet address. * * Automatically uses the USDC contract address for the current chain. * This is a read-only operation. */ balanceOf: Omit; } /** * Central registry of all available action namespaces and their operations. * * Define the complete action map structure used throughout the bridge kit. * Each top-level key represents a namespace (e.g., 'token', 'usdc') containing * related operations. The structure supports arbitrary nesting depth through * the recursive utility types provided in this module. * * @remarks * This interface serves as the foundation for type-safe action dispatching * and provides compile-time validation of action keys and payload types. * All action-related utility types derive from this central definition. * * @see {@link ActionKeys} for dot-notation action paths * @see {@link ActionPayload} for extracting payload types */ interface ActionMap { /** CCTP-specific operations with automatic address resolution. */ readonly cctp: CCTPActionMap; /** General token operations requiring explicit token addresses. */ readonly token: TokenActionMap; /** USDC-specific operations with automatic address resolution. */ readonly usdc: USDCActionMap; } /** * Determine if a type represents an action parameter object (leaf node). * * Check whether a type extends the ActionParameters interface, which provides * an explicit marker for identifying action parameter objects versus namespace * containers that should be traversed during type recursion. * * @typeParam T - The type to examine for parameter object characteristics * * @remarks * This utility type provides deterministic leaf detection for the recursive * type system. By requiring all action parameter objects to extend the * ActionParameters interface, we eliminate the need for property name * heuristics and make the system more maintainable. * * @see {@link ActionParameters} for the base interface * @see {@link NestedKeys} for usage in path extraction */ type IsActionParameterObject = T extends ActionParameters ? true : false; /** * Recursively extract all nested keys from an object type as dot-notation string literals. * * Traverse object structures of arbitrary depth and generate string literal * types representing all possible paths through the structure using dot * notation. Stop recursion when encountering action parameter objects (leaves). * * @typeParam T - The object type to extract nested keys from * * @remarks * This type is the foundation for generating type-safe action paths in * dot notation. It automatically adapts to changes in the ActionMap * structure and supports unlimited nesting depth for future extensibility. * * The recursion stops when it encounters objects that match the * {@link IsActionParameterObject} criteria, ensuring that only valid * action paths are generated. * * @see {@link ActionKeys} for ActionMap-specific paths * @see {@link NestedValue} for extracting types at specific paths * @see {@link IsActionParameterObject} for leaf detection logic */ type NestedKeys = { [K in Extract]: IsActionParameterObject extends true ? K : T[K] extends object ? `${K}.${NestedKeys}` : never; }[Extract]; /** * Recursively extract the value type at a given dot-notation path. * * Navigate through nested object types using a dot-notation string path * and return the type of the value at that location. Parse the path * recursively by splitting on dots and traversing the object structure. * * @typeParam T - The object type to navigate through * @typeParam K - The dot-notation path as a string literal type * * @remarks * This utility type enables type-safe access to deeply nested object * properties using dot notation paths. It forms the foundation for * extracting payload types from action paths in the ActionMap. * * @see {@link ActionPayload} for ActionMap-specific value extraction * @see {@link NestedKeys} for generating valid path types */ type NestedValue = K extends `${infer First}.${infer Rest}` ? First extends keyof T ? NestedValue : never : K extends keyof T ? T[K] : never; /** * Union type of all nested action keys in dot notation. * * Generate string literal types for all possible action paths in the * ActionMap structure. Automatically adapt to changes in the ActionMap * and support arbitrary levels of nesting for future extensibility. * * @remarks * This type serves as the canonical source for all valid action identifiers * in the bridge kit. It ensures compile-time validation of action keys * and enables type-safe action dispatching throughout the application. * * @see {@link ActionPayload} for extracting parameter types * @see {@link NamespaceActions} for namespace-specific actions * @see {@link ActionMap} for the underlying structure */ type ActionKeys = NestedKeys; /** * Extract the payload type for a specific action based on its dot-notation key. * * Resolve the parameter type for any action by providing its complete path * in dot notation. Leverage the recursive NestedValue type to navigate to * the correct payload type regardless of nesting depth. The internal * ActionParameters marker is automatically removed from the result. * * @typeParam T - The action key in dot notation (must extend ActionKeys) * * @remarks * This utility type enables type-safe parameter passing for action * dispatching. It automatically infers the correct parameter shape * based on the action key, providing compile-time validation and * excellent IntelliSense support. * * The internal `__isActionParams` marker used for type system recursion * is automatically omitted from the resulting type, providing clean * parameter objects for consumers. * * @see {@link ActionKeys} for available action identifiers * @see {@link NestedValue} for the underlying path resolution logic */ type ActionPayload = Omit, '__isActionParams'>; /** * Type-safe action handler function signature for specific action types. * * Defines the contract for functions that process action payloads and return * prepared chain requests. Each handler is strongly typed to accept only the * payload structure corresponding to its specific action key. * * @typeParam TActionKey - The specific action key this handler processes. * @param params - The action payload matching the specified action key. * @param context - The resolved operation context with concrete chain and address values. * @returns A promise resolving to a prepared chain request. * * @example * ```typescript * import type { ActionHandler } from '@core/adapter' * * const depositHandler: ActionHandler<'cctp.v2.depositForBurn'> = async (params, context) => { * // context is always defined and has concrete chain and address values * console.log(context.chain.name); * console.log(context.address); * // ... handler logic ... * return preparedRequest; * } * ``` */ type ActionHandler = (params: ActionPayload, context: ResolvedOperationContext) => Promise; /** * Type-safe mapping of all available action keys to their corresponding handlers. * * This type defines a registry object where each key is a valid action key * (as defined by {@link ActionKeys}) and each value is an {@link ActionHandler} * capable of processing the payload for that action. This enables strongly-typed * handler registration and lookup for all supported actions in the Stablecoin Kits. * * @remarks * Each handler is typed as {@link ActionHandler}, which means the handler * must accept the payload type for the specific action key it is registered under. * This provides type safety for handler registration and execution, but does not * enforce per-key handler parameterization at the type level. For stricter per-key * typing, consider using mapped types or generic registry patterns. * * @example * ```typescript * import type { ActionHandlers } from '@core/adapter' * import type { ActionHandler } from '@core/adapter' * * const handlers: ActionHandlers = { * 'cctp.v2.depositForBurn': async (params, resolved) => { * // params is correctly typed for 'cctp.v2.depositForBurn' * // resolved has concrete chain and address values * // ...handler logic... * }, * 'usdc.approve': async (params, resolved) => { * // params is correctly typed for 'usdc.approve' * // resolved has concrete chain and address values * // ...handler logic... * } * } * ``` */ type ActionHandlers = { [K in ActionKeys]?: ActionHandler; }; /** * Type-safe registry for managing and executing blockchain action handlers. * * Provides a centralized system for registering action handlers with full * TypeScript type safety, ensuring that handlers can only be registered * with compatible action keys and payload types. Supports both individual * handler registration and batch registration operations. * * @remarks * The registry uses a Map internally for O(1) lookups and maintains type * safety through generic constraints and careful type assertions. All * type assertions are validated at registration time to ensure runtime * type safety matches compile-time guarantees. */ declare class ActionRegistry { readonly actionHandlers: Map>; /** * Register a type-safe action handler for a specific action key. * * Associates an action handler function with its corresponding action key, * ensuring compile-time type safety between the action and its expected * payload structure. The handler will be available for execution via * {@link executeAction}. * * @typeParam TActionKey - The specific action key being registered. * @param action - The action key to register the handler for. * @param handler - The handler function for processing this action type. * @returns Void. * * @throws Error When action parameter is not a valid string. * @throws TypeError When handler parameter is not a function. * * @example * ```typescript * import { ActionRegistry } from '@core/adapter' * import type { ActionHandler } from '@core/adapter' * * const registry = new ActionRegistry() * * // Register a CCTP deposit handler * const depositHandler: ActionHandler<'cctp.v2.depositForBurn'> = async (params, resolved) => { * console.log('Processing deposit:', params.amount) * return { * chainId: params.chainId, * data: '0x...', * to: '0x...', * value: '0' * } * } * * registry.registerHandler('cctp.v2.depositForBurn', depositHandler) * ``` */ registerHandler(action: TActionKey, handler: ActionHandler): void; /** * Register multiple action handlers in a single operation. * * Efficiently register multiple handlers from a record object, where keys * are action identifiers and values are their corresponding handler * functions. Provides a convenient way to bulk-register handlers while * maintaining type safety. * * @param handlers - A record mapping action keys to their handler functions. * @returns Void. * * @throws {Error} When handlers parameter is not a valid object. * @throws {Error} When any individual handler registration fails. * * @example * ```typescript * import { ActionRegistry } from '@core/adapter' * import type { ActionHandler, ActionHandlers } from '@core/adapter' * * const registry = new ActionRegistry() * * // Register multiple handlers at once * const tokenHandlers: ActionHandlers = { * 'token.approve': async (params, resolved) => ({ * chainId: resolved.chain, * data: '0x095ea7b3...', * to: params.tokenAddress, * value: '0' * }), * 'token.transfer': async (params, resolved) => ({ * chainId: resolved.chain, * data: '0xa9059cbb...', * to: params.tokenAddress, * value: '0' * }) * } * * registry.registerHandlers(tokenHandlers) * console.log('Registered multiple token handlers') * ``` */ registerHandlers(handlers: ActionHandlers): void; /** * Check whether a specific action is supported by this registry. * * Determine if a handler has been registered for the given action key. * Use this method to conditionally execute actions or provide appropriate * error messages when actions are not available. * * @param action - The action key to check for support. * @returns True if the action is supported, false otherwise. * * @throws {Error} When action parameter is not a valid string. * * @example * ```typescript * import { ActionRegistry } from '@core/adapter' * * const registry = new ActionRegistry() * * // Check if actions are supported before attempting to use them * if (registry.supportsAction('token.approve')) { * console.log('Token approval is supported') * } else { * console.log('Token approval not available') * } * * // Conditional logic based on support * const action = 'cctp.v2.depositForBurn' * if (registry.supportsAction(action)) { * // Safe to execute * console.log(`${action} is available`) * } else { * console.warn(`${action} is not registered`) * } * ``` */ supportsAction(action: ActionKeys): boolean; /** * Execute a registered action handler with type-safe parameters. * * Look up and execute the handler associated with the given action key, * passing the provided parameters and context, returning the resulting prepared * chain request. TypeScript ensures the parameters match the expected * structure for the specified action. * * @typeParam TActionKey - The specific action key being executed. * @param action - The action key identifying which handler to execute. * @param params - The parameters to pass to the action handler. * @param context - The resolved operation context with concrete chain and address values. * @returns A promise resolving to the prepared chain request. * @throws {KitError} When the handler execution fails with a structured error. * @throws {Error} When no handler is registered for the specified action. * @throws {Error} When the handler execution fails with an unstructured error. * * @example * ```typescript * import { ActionRegistry } from '@core/adapter' * import type { ChainEnum } from '@core/chains' * * const registry = new ActionRegistry() * * // First register a handler * registry.registerHandler('token.approve', async (params, context) => ({ * chainId: context.chain, // Always defined * data: '0x095ea7b3...', * to: params.tokenAddress, * value: '0' * })) * * // Execute the action with resolved context (typically called from adapter.prepareAction) * const resolvedContext = { chain: 'Base', address: '0x123...' } * const result = await registry.executeAction('token.approve', { * chainId: ChainEnum.Ethereum, * tokenAddress: '0xA0b86a33E6441c8C1c7C16e4c5e3e5b5e4c5e3e5b5e4c5e', * delegate: '0x1234567890123456789012345678901234567890', * amount: '1000000' * }, resolvedContext) * * console.log('Transaction prepared:', result.data) * ``` */ executeAction(action: TActionKey, params: ActionPayload, context: ResolvedOperationContext): Promise; } /** * Defines the capabilities of an adapter, including address handling patterns and supported chains. * * @interface TAdapterCapabilities * @category Types * @description * This interface specifies how an adapter manages address control and which blockchain networks it supports. * It is used for capability discovery, validation, and to inform consumers about the adapter's operational model. * * The `addressContext` property determines both address selection behavior and bridge API requirements: * - `'user-controlled'`: User controls addresses through wallet UI, address optional in operations * - `'developer-controlled'`: Service manages addresses programmatically, address required in operations * * @example * ```typescript * // Browser wallet adapter (user-controlled) * const capabilities: AdapterCapabilities = { * addressContext: 'user-controlled', // User selects address in wallet UI * supportedChains: [Ethereum, Base, Polygon] * } * * // Enterprise provider adapter (developer-controlled) * const capabilities: AdapterCapabilities = { * addressContext: 'developer-controlled', // Address must be specified per operation * supportedChains: [Ethereum, Base, Solana] * } * ``` */ interface AdapterCapabilities { /** * Defines who controls address selection for wallet operations. * * - `'user-controlled'`: User controls addresses through wallet UI (browser wallets, hardware wallets) * - Address is implicit in bridge operations (uses wallet's current address) * - Adapter may listen for accountsChanged/chainChanged events * - Suitable for MetaMask, Coinbase Wallet, WalletConnect, private keys, etc. * * - `'developer-controlled'`: Service manages addresses programmatically (enterprise providers) * - Address must be explicitly provided in bridge operations * - No event listening (addresses controlled programmatically) * - Suitable for Fireblocks, Circle Wallets, institutional custody, etc. */ addressContext: 'user-controlled' | 'developer-controlled'; /** * The set of blockchain networks this adapter supports. * Used for validation, capability discovery, and to restrict operations to supported chains. */ supportedChains: ChainDefinition[]; } /** * Abstract class defining the standard interface for an adapter that interacts with a specific blockchain. * * A `Adapter` is responsible for encapsulating chain-specific logic necessary to * perform operations like sending transactions, querying balances, or interacting with smart contracts. * Implementations of this class will provide concrete logic for a particular blockchain protocol. * * This abstraction allows the Stablecoin Kits to work with multiple blockchains in a uniform way. * * @typeParam TAdapterCapabilities - The adapter capabilities type for compile-time address validation. * When provided, enables strict typing of operation context based on the adapter's address control model. */ declare abstract class Adapter { /** * The type of the chain for this adapter. * * - For concrete adapters, this should be a real chain type (e.g., `'evm'`, `'solana'`, etc.) from the ChainType union. * - For hybrid adapters (adapters that route to concrete adapters supporting multiple ecosystems), * set this property to the string literal `'hybrid'`. * * Note: `'hybrid'` is not a legal ChainType and should only be used as a marker for multi-ecosystem adapters. * Hybrid adapters do not interact directly with any chain, but instead route requests to a concrete underlying adapter. * * @example * // For an EVM-only adapter: * chainType = 'evm' * * // For a hybrid adapter: * chainType = 'hybrid' */ abstract chainType: ChainType | 'hybrid'; /** * Capabilities of this adapter, defining address control model and supported chains. * * This property determines how the adapter behaves, especially for address selection * and bridge API requirements. The `addressContext` must match the adapter's type parameter. * * @remarks * The `addressContext` value must align with the adapter's generic type parameter for proper * type safety in bridge operations. * * @example * ```typescript * // User-controlled adapter (private key, browser wallet) * capabilities = { * addressContext: 'user-controlled', // Address implicit in bridge operations * supportedChains: [Ethereum, Base, Polygon] * } * * // Developer-controlled adapter (enterprise provider) * capabilities = { * addressContext: 'developer-controlled', // Address required in bridge operations * supportedChains: [Ethereum, Base, Solana] * } * ``` */ capabilities?: TAdapterCapabilities; /** * Registry of available actions for this adapter. * * The {@link ActionRegistry} provides a catalog of supported operations * (such as token transfers, approvals, etc.) that can be performed by this adapter * on the connected blockchain. This enables dynamic discovery and invocation * of chain-specific or cross-chain actions in a type-safe manner. * * @readonly */ readonly actionRegistry: ActionRegistry; /** * Prepares (but does not execute) an action for the connected blockchain. * * This method looks up the appropriate action handler for the given action key * and prepares the transaction request using the provided parameters. The returned * {@link PreparedChainRequest} allows developers to estimate gas costs and execute * the transaction at a later time, enabling pre-flight simulation and deferred execution. * * **Compile-time Address Validation**: When used with typed adapters that have capabilities, * this method enforces address requirements at compile time: * - **User-controlled adapters**: The `address` field is forbidden in the context * - **Developer-controlled adapters**: The `address` field is required in the context * - **Legacy adapters**: The `address` field remains optional for backward compatibility * * @remarks * This method does not send any transaction to the network. Instead, it returns a * prepared request object with `estimate()` and `execute()` methods, allowing * developers to inspect, simulate, or submit the transaction as needed. * * @param action - The action key identifying which handler to use for preparation. * @param params - The parameters to pass to the action handler. * @param ctx - Operation context with compile-time validated address requirements based on adapter capabilities. * @returns A promise that resolves to a {@link PreparedChainRequest} for estimation and execution. * @throws Error If the specified action key does not correspond to a registered handler. * @throws Error If the provided parameters are invalid for the action. * @throws Error If the operation context cannot be resolved. * * @example * ```typescript * // User-controlled adapter (address forbidden) * const userAdapter: Adapter<{ addressContext: 'user-controlled', supportedChains: [] }> * await userAdapter.prepareAction('token.approve', params, { * chain: 'Ethereum' * // address: '0x123...' // ❌ TypeScript error: address not allowed * }) * * // Developer-controlled adapter (address required) * const devAdapter: Adapter<{ addressContext: 'developer-controlled', supportedChains: [] }> * await devAdapter.prepareAction('token.approve', params, { * chain: 'Ethereum', * address: '0x123...' // ✅ Required for developer-controlled * }) * ``` */ prepareAction(action: TActionKey, params: ActionPayload, ctx: OperationContext): Promise; /** * Prepares a transaction for future gas estimation and execution. * * This method should handle any preliminary steps required before a transaction * can be estimated or sent. This might include things like serializing transaction * data, but it should NOT yet send anything to the network. * * The returned object contains two functions: * - `estimate()`: Asynchronously calculates and returns the {@link EstimatedGas} for the prepared transaction. * - `execute()`: Asynchronously executes the prepared transaction and returns a promise that resolves * with the transaction result (e.g., a transaction hash, receipt, or other chain-specific response). * * **Compile-time Address Validation**: When used with typed adapters that have capabilities, * this method enforces address requirements at compile time: * - **User-controlled adapters**: The `address` field is forbidden in the context * - **Developer-controlled adapters**: The `address` field is required in the context * - **Legacy adapters**: The `address` field remains optional for backward compatibility * * @remarks * The specific parameters for `prepare` might vary greatly between chain implementations. * Consider defining a generic type or a base type for `transactionRequest` if common patterns emerge, * or allow `...args: any[]` if extreme flexibility is needed by implementers. * For this abstract definition, we keep it parameter-less, assuming implementations will add specific * parameters as needed for their `prepare` method (e.g. `prepare(txDetails: MyChainTxDetails)`). * * @param params - The prepared chain request parameters for the specific blockchain. * @param ctx - Operation context with compile-time validated address requirements based on adapter capabilities. * @returns An object containing `estimate` and `execute` methods for the prepared transaction. * * @example * ```typescript * // User-controlled adapter (address forbidden) * const userAdapter: Adapter<{ addressContext: 'user-controlled', supportedChains: [] }> * await userAdapter.prepare(params, { * chain: 'Ethereum' * // address: '0x123...' // ❌ TypeScript error: address not allowed * }) * * // Developer-controlled adapter (address required) * const devAdapter: Adapter<{ addressContext: 'developer-controlled', supportedChains: [] }> * await devAdapter.prepare(params, { * chain: 'Ethereum', * address: '0x123...' // ✅ Required for developer-controlled * }) * ``` */ abstract prepare(params: PreparedChainRequestParams, ctx: OperationContext): Promise; /** * Retrieves the public address of the connected wallet. * * This address is used as the default sender for transactions * and interactions initiated by this adapter. * * @param chain - The chain to use for address resolution. * @returns A promise that resolves to the blockchain address as a string. */ abstract getAddress(chain: ChainDefinition): Promise; /** * Switches the adapter to operate on the specified chain. * * This abstract method must be implemented by concrete adapters to handle their specific * chain switching logic. The behavior varies by adapter type: * - **Private key adapters**: Recreate clients with new RPC endpoints * - **Browser wallet adapters**: Request chain switch via EIP-1193 or equivalent * - **Multi-entity adapters**: Typically a no-op (operations are contextual) * * @param chain - The target chain to switch to. * @returns A promise that resolves when the chain switch is complete. * @throws When the chain switching fails or is not supported. * * @remarks * This method is called by `ensureChain()` after validation is complete. * Implementations should focus only on the actual switching logic, not validation. * * @example * ```typescript * // EVM adapter implementation * protected async switchToChain(chain: ChainDefinition): Promise { * if (chain.type !== 'evm') { * throw new Error('Only EVM chains supported') * } * await this.recreateWalletClient(chain) * } * * // Multi-entity adapter implementation * protected async switchToChain(chain: ChainDefinition): Promise { * // No-op - operations are contextual * return * } * ``` */ abstract switchToChain(chain: ChainDefinition): Promise; /** * Ensures the adapter is operating on the specified chain, switching if necessary. * * This method provides a unified interface for establishing chain preconditions across different adapter types. * The behavior varies based on the adapter's capabilities: * - **Private key adapters**: Recreate clients with new RPC endpoints * - **Browser wallet adapters**: Request chain switch via EIP-1193 or equivalent * - **Multi-entity adapters**: Validate chain support (operations are contextual) * * @param chain - The target chain for operations. * @returns A promise that resolves when the adapter is operating on the specified chain. * @throws When the target chain is not supported or chain switching fails. * * @remarks * This method always calls `switchToChain()` to ensure consistency across all adapter types. * The underlying implementations handle idempotent switching efficiently (e.g., browser wallets * gracefully handle switching to the current chain, private key adapters recreate lightweight clients). * * @example * ```typescript * // Private key adapter - switches chains seamlessly * await privateKeyAdapter.ensureChain(Base) * * // Browser wallet - requests user to switch chains * await metamaskAdapter.ensureChain(Polygon) * * // Multi-entity adapter - validates chain is supported * await circleWalletsAdapter.ensureChain(Ethereum) * ``` */ ensureChain(targetChain: ChainDefinition): Promise; /** * Validate that the target chain is supported by this adapter. * * @param targetChain - The chain to validate. * @throws KitError with INVALID_CHAIN code if the chain is not supported by this adapter. */ validateChainSupport(targetChain: ChainDefinition): void; /** * Waits for a transaction to be mined and confirmed on the blockchain. * * This method should block until the transaction is confirmed on the blockchain. * The response includes comprehensive transaction details for the confirmed transaction. * * @param txHash - The hash of the transaction to wait for. * @param config - Optional configuration for waiting behavior including timeout and confirmations. * @param chain - The chain definition where the transaction was submitted. * @returns Promise resolving to comprehensive transaction details. */ abstract waitForTransaction(txHash: string, config: WaitForTransactionConfig | undefined, chain: ChainDefinition): Promise; /** * Calculate the total transaction fee including compute cost and buffer for the configured chain. * * This method computes the fee by multiplying the base compute units by the current * fee rate, then adds a configurable buffer to account for fee fluctuations and ensure * transaction success. The buffer is specified in basis points (1 basis point = 0.01%). * * @param baseComputeUnits - The base compute units for the transaction (gas for EVM, compute units for Solana, etc.). * @param bufferBasisPoints - The buffer to add as basis points (e.g., 500 = 5%). Defaults to implementation-specific value. * @param chain - The chain definition to calculate fees for. * @returns A promise that resolves to the total transaction fee as a bigint. */ abstract calculateTransactionFee(baseComputeUnits: bigint, bufferBasisPoints: bigint | undefined, chain: ChainDefinition): Promise; } /** * Configuration options for the API polling utility. * * @remarks * These settings control the behavior of the API polling process: * - timeout: Maximum time (ms) to wait for each request before aborting * - maxRetries: Maximum number of retry attempts for failed requests * - retryDelay: Time (ms) to wait between retry attempts * - headers: Optional HTTP headers to include with each request */ interface ApiPollingConfig { /** Maximum time in milliseconds to wait for each request */ timeout: number; /** Maximum number of retry attempts for failed requests */ maxRetries: number; /** Time in milliseconds to wait between retry attempts */ retryDelay: number; /** Optional HTTP headers to include with requests */ headers?: Record | undefined; } /** * A type-safe event emitter for managing action-based event subscriptions. * * Actionable provides a strongly-typed publish/subscribe pattern for events, * where each event (action) has its own specific payload type. Handlers can * subscribe to specific events or use a wildcard to receive all events. * * @typeParam AllActions - A record mapping action names to their payload types. * * @example * ```typescript * import { Actionable } from '@circle-fin/bridge-kit/utils'; * * // Define your action types * type TransferActions = { * started: { txHash: string; amount: string }; * completed: { txHash: string; destinationTxHash: string }; * failed: { error: Error }; * }; * * // Create an actionable instance * const transferEvents = new Actionable(); * * // Subscribe to a specific event * transferEvents.on('completed', (payload) => { * console.log(`Transfer completed with hash: ${payload.destinationTxHash}`); * }); * * // Subscribe to all events * transferEvents.on('*', (payload) => { * console.log('Event received:', payload); * }); * * // Dispatch an event * transferEvents.dispatch('completed', { * txHash: '0x123', * destinationTxHash: '0xabc' * }); * ``` */ declare class Actionable { private readonly handlers; private readonly wildcard; /** * Register a handler for a specific action. * * @param action - The specific action key to listen for. * @param handler - The callback function to execute when the action occurs. * * @example * ```typescript * const events = new Actionable<{ dataReceived: string }>(); * * events.on('dataReceived', (data) => { * console.log(`Received: ${data}`); * }); * ``` */ on(action: Action, handler: (payload: AllActions[Action]) => void): void; /** * Register a handler for all actions using the wildcard '*'. * * @param action - The wildcard '*' signifying interest in all actions. * @param handler - The callback function to execute for any action. * * @example * ```typescript * const events = new Actionable<{ started: boolean; completed: string }>(); * * events.on('*', (payload) => { * console.log('Action occurred:', payload); * }); * ``` */ on(action: '*', handler: (payload: AllActions[keyof AllActions]) => void): void; /** * Remove a previously registered handler for a specific action. * * @param action - The specific action key to unregister from. * @param handler - The callback function to remove. * * @example * ```typescript * const events = new Actionable<{ dataReceived: string }>(); * * const handler = (data: string) => console.log(data); * events.on('dataReceived', handler); * * // Later, to remove the handler: * events.off('dataReceived', handler); * ``` */ off(action: Action, handler: (payload: AllActions[Action]) => void): void; /** * Remove a previously registered wildcard handler. * * @param action - The wildcard '*' signifying removal from all actions. * @param handler - The callback function to remove. * * @example * ```typescript * const events = new Actionable<{ started: boolean; completed: string }>(); * * const globalHandler = (payload: any) => console.log(payload); * events.on('*', globalHandler); * * // Later, to remove the handler: * events.off('*', globalHandler); * ``` */ off(action: '*', handler: (payload: AllActions[keyof AllActions]) => void): void; /** * Dispatch an action with its payload to all registered handlers. * * This method notifies both: * - Handlers registered specifically for this action * - Wildcard handlers registered for all actions * * @param action - The action key identifying the event type. * @param payload - The data associated with the action. * * @example * ```typescript * type Actions = { * transferStarted: { amount: string; destination: string }; * transferComplete: { txHash: string }; * }; * * const events = new Actionable(); * * // Dispatch an event * events.dispatch('transferStarted', { * amount: '100', * destination: '0xABC123' * }); * ``` */ dispatch(action: K, payload: AllActions[K]): void; } /** * Transfer speed options for cross-chain operations. * * Defines the available speed modes for CCTPv2 transfers, affecting * both transfer time and potential fee implications. */ declare enum TransferSpeed { /** Fast burn mode - reduces transfer time but may have different fee implications */ FAST = "FAST", /** Standard burn mode - normal transfer time with standard fees */ SLOW = "SLOW" } /** * Context object representing a wallet and signing authority on a specific blockchain network. * * Combines a wallet or contract address, the blockchain it resides on, and the adapter (signer) * responsible for authorizing transactions. Used to specify the source or destination in cross-chain * transfer operations. * * @remarks * The `adapter` (signer) and `address` do not always have to belong to the same entity. For example, * in minting or withdrawal scenarios, the signing adapter may authorize a transaction that credits * funds to a different recipient address. This context is essential for cross-chain operations, * ensuring that both the address and the associated adapter are correctly paired with the intended * blockchain, but not necessarily with each other. * * @example * ```typescript * import type { WalletContext } from '@core/provider' * import { adapter, blockchain } from './setup' * * const wallet: WalletContext = { * adapter, * address: '0x1234...abcd', * chain: blockchain, * } * ``` */ interface WalletContext { /** * The adapter (signer) for the wallet on the specified chain. * * Responsible for authorizing transactions and signing messages on behalf of the wallet or * for a different recipient, depending on the use case. */ adapter: Adapter; /** * The wallet or contract address. * * Must be a valid address format for the specified blockchain. May differ from the adapter's * own address in scenarios such as relayed transactions or third-party minting. */ address: string; /** * The blockchain network where the wallet or contract address resides. * * Determines the context and format for the address and adapter. */ chain: TChainDefinition; } /** * Wallet context for bridge destinations with optional custom recipient. * * Extends WalletContext to support scenarios where the recipient address * differs from the signer address (e.g., bridging to a third-party wallet). * The signer address is used for transaction authorization, while the * recipient address specifies where the minted funds should be sent. * * @typeParam TAdapterCapabilities - The adapter capabilities type to use for the wallet context. * @typeParam TChainDefinition - The chain definition type to use for the wallet context. * * @example * ```typescript * import type { DestinationWalletContext } from '@core/provider' * import { adapter, blockchain } from './setup' * * // Bridge to a custom recipient address * const destination: DestinationWalletContext = { * adapter, * address: '0x1234...abcd', // Signer address * chain: blockchain, * recipientAddress: '0x9876...fedc' // Custom recipient * } * ``` */ interface DestinationWalletContext extends WalletContext { /** * Optional custom recipient address for minted funds. * * When provided, minted tokens will be sent to this address instead of * the address specified in the wallet context. The wallet context address * is still used for transaction signing and authorization. * * Must be a valid address format for the specified blockchain. */ recipientAddress?: string; } /** * Parameters for executing a cross-chain bridge operation. */ interface BridgeParams { /** The source adapter containing wallet and chain information */ source: WalletContext; /** The destination adapter containing wallet and chain information */ destination: DestinationWalletContext; /** The amount to transfer (as a string to avoid precision issues) */ amount: string; /** The token to transfer (currently only USDC is supported) */ token: 'USDC'; /** Bridge configuration (e.g., fast burn settings) */ config: BridgeConfig; } /** * A step in the bridge process. * * @remarks * This interface represents a single step in the bridge process, * such as approval, burn, or mint. * * @example * ```typescript * const step: BridgeStep = { * name: 'Approve', * state: 'success', * txHash: '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef', * explorerUrl: 'https://etherscan.io/tx/0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef', * } * ``` */ interface BridgeStep { /** Human-readable name of the step (e.g., "Approve", "Burn", "Mint") */ name: string; /** The state of the step */ state: 'pending' | 'success' | 'error' | 'noop'; /** Optional transaction hash for this step (if applicable) */ txHash?: string; /** Optional explorer URL for viewing this transaction on a block explorer */ explorerUrl?: string; /** Optional data for the step */ data?: unknown; /** Optional human-readable error message */ errorMessage?: string; /** Optional raw error object (can be Viem/Ethers/Chain error) */ error?: unknown; } /** * Result object returned after a successful cross-chain bridge operation. * * This interface contains all the details about a completed bridge, including * the bridge parameters, source and destination information, * and the sequence of steps that were executed. * * @example * ```typescript * const result: BridgeResult = await provider.bridge(source, dest, '100') * console.log(`Transferred ${result.amount} ${result.token}`) * console.log(`Steps executed: ${result.steps.length}`) * ``` */ interface BridgeResult { /** The amount that was transferred (as a string to avoid precision issues) */ amount: string; /** The token that was transferred (currently only USDC is supported) */ token: 'USDC'; /** The state of the transfer */ state: 'pending' | 'success' | 'error'; /** The bridge configuration that was used for this operation */ config?: BridgeConfig; /** The provider that was used for this operation */ provider: string; /** Information about the source chain and address */ source: { /** The source wallet/contract address */ address: string; /** The source blockchain network */ chain: ChainDefinition; }; /** Information about the destination chain and address */ destination: { /** The destination wallet/contract address */ address: string; /** The destination blockchain network */ chain: ChainDefinition; /** * Optional custom recipient address for minted funds. * * When provided during the bridge operation, minted tokens are sent to this * address instead of the destination address. This field is preserved in the * result for retry operations to maintain consistency with the original burn. */ recipientAddress?: string; }; /** Array of steps that were executed during the bridge process */ steps: BridgeStep[]; } /** * Cost estimation result for a cross-chain transfer operation. * * This interface provides detailed information about the expected costs * for a transfer, including gas fees on different chains and protocol fees. * It also includes the input context (token, amount, source, destination) to * provide a complete view of the transfer being estimated. * * @example * ```typescript * const estimate: EstimateResult = await provider.estimate(source, dest, '100') * console.log('Estimating transfer of', estimate.amount, estimate.token) * console.log('From', estimate.source.chain.name, 'to', estimate.destination.chain.name) * console.log('Total gas fees:', estimate.gasFees.length) * console.log('Protocol fees:', estimate.fees.length) * ``` */ interface EstimateResult { /** The token being transferred */ token: 'USDC'; /** The amount being transferred */ amount: string; /** Information about the source chain and address */ source: { /** The source wallet/contract address */ address: string; /** The source blockchain network */ chain: Blockchain; }; /** Information about the destination chain and address */ destination: { /** The destination wallet/contract address */ address: string; /** The destination blockchain network */ chain: Blockchain; /** Optional custom recipient address for minted funds. */ recipientAddress?: string; }; /** Array of gas fees required for the transfer on different blockchains */ gasFees: { /** The name of the step */ name: string; /** The token used to pay gas fees (e.g., "ETH", "MATIC") */ token: string; /** The blockchain where this gas fee applies */ blockchain: Blockchain; /** The estimated gas fee amount (as a string to avoid precision issues) */ fees: EstimatedGas | null; /** Optional error object if the estimate failed */ error?: unknown; }[]; /** Array of protocol and service fees for the transfer */ fees: { /** The type of fee - either from the bridge kit or the underlying provider */ type: 'kit' | 'provider'; /** The token in which the fee is charged (currently only USDC) */ token: 'USDC'; /** The fee amount (as a string to avoid precision issues) */ amount: string | null; /** Optional error object if the estimate failed */ error?: unknown; }[]; } /** * Configuration options for customizing bridge behavior. * * @remarks * This interface is currently incomplete and will be expanded in future versions * to include additional configuration options such as slippage tolerance, * deadline settings, and other bridge parameters. * */ interface BridgeConfig { /** * The transfer speed mode for CCTPv2 transfers. * * Controls whether to use fast burn mode (FAST) or standard mode (SLOW). * Fast burn may reduce transfer time but could have different fee implications. * * @defaultValue TransferSpeed.FAST */ transferSpeed?: TransferSpeed | `${TransferSpeed}` | undefined; /** * The maximum fee to pay for the burn operation. * * Provide the amount as a base-10 numeric string representing the * token amount in human-readable format. For example: to set a maximum * fee of 1 USDC, pass `"1"`. Decimal values are supported (e.g., `"0.5"` * for half a USDC). * * @defaultValue `"0"` * * @example * ```typescript * import type { BridgeConfig, TransferSpeed } from '@core/provider' * * const config: BridgeConfig = { * transferSpeed: TransferSpeed.FAST, * maxFee: "1", // 1 USDC maximum fee * customFee: { * value: "0.5", // 0.5 USDC developer fee * recipientAddress: "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0" * } * } * ``` */ maxFee?: string; /** * The custom fee to charge for the transfer. * * Whatever value you provide here is **added on top of the transfer amount**. The user must have * enough balance for `amount + customFee`, and the wallet signs for that total on the source * chain. The custom fee is split automatically: * * - 10% routes to Circle. * - 90% routes to your `recipientAddress`. * * The original transfer amount proceeds through CCTPv2 unchanged, and the protocol fee (1–14 bps * in FAST mode, 0% in STANDARD) is taken from that transfer amount. * * @example * ```typescript * import type { BridgeConfig } from '@core/provider' * * const config: BridgeConfig = { * customFee: { * value: '5', // 5 USDC developer fee * recipientAddress: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0', * }, * } * * // Fee flow for a 100 USDC transfer with 5 USDC custom fee: * // Source chain (Ethereum): * // - Wallet debits: 105 USDC total (100 transfer + 5 custom fee) * // - Custom fee split: 0.5 USDC (10%) → Circle, 4.5 USDC (90%) → your recipientAddress * // - Amount sent to CCTPv2: 100 USDC (unchanged) * // * // Destination chain (Base): * // - CCTPv2 FAST fee (example: 1 bps): ~0.01 USDC deducted * // - User receives: ~99.99 USDC * // * // Note: Actual CCTP fees vary by route (1-14 bps for FAST, 0 bps for STANDARD) * ``` */ customFee?: CustomFee | undefined; } /** * Custom fee configuration charged by the integrator. * * Use to charge an absolute fee on the source chain in human-readable * token amounts. * * @remarks * This is an absolute amount, not a percentage. The `recipientAddress` must be * a valid address for the source chain of the transfer. * * @example * ```typescript * import type { CustomFee } from '@core/provider' * * const config: CustomFee = { * value: '1', // 1 USDC * recipientAddress: '0x1234567890123456789012345678901234567890', * } * ``` */ interface CustomFee { /** * The absolute fee to charge for the transfer. * * Provide the amount as a base-10 numeric string representing the token * amount in human-readable format. For example: to charge 1 USDC, pass * `"1"`. Decimal values are supported (e.g., `"0.5"` for half a USDC). * This is not a percentage. * * Note: passing `"0"` results in no fee being charged. */ value?: string | undefined; /** * The fee recipient for the bridge transfer. * * This is the address that will receive the fee on the source chain of the * bridge transfer. The fee recipient address **must be a valid address for * the source chain** of the bridge transfer. * * @remarks * Circle automatically receives 10% of every custom fee; the remaining 90% is * sent to this `recipientAddress`. * * For example: if bridging from Ethereum to Solana, pass an EVM address like * `"0x1234567890123456789012345678901234567890"` because the source chain * is Ethereum. */ recipientAddress?: string | undefined; } /** * Context for retry operations containing source and destination adapter contexts. * * This interface provides the necessary context for retry operations, including * both the source adapter context (where the retry originates) and the destination * adapter context (where the retry is targeted). This ensures that retry operations * have access to both the source and destination chain information needed for * validation and execution. * * @example * ```typescript * const retryContext: RetryContext = { * from: { adapter: sourceAdapter, chain: 'Ethereum' }, * to: { adapter: destAdapter, chain: 'Base' } * } * ``` */ interface RetryContext { /** The source adapter context for the retry operation */ from: Adapter; /** The destination adapter context for the retry operation */ to: Adapter; } /** * Result of analyzing bridge steps to determine retry feasibility and continuation point. * * This interface provides comprehensive information about the state of bridge steps, * including which steps have completed, which have failed, and whether the operation * can be retried from a specific point. It also includes the reason for failure * and identifies the next step to continue from. * * @example * ```typescript * const analysis: StepAnalysisResult = { * continuationStep: 'Burn', * isRetryable: true, * completedSteps: ['Approve'], * failedSteps: ['Burn'], * reason: 'Transaction timeout' * } * ``` */ interface StepAnalysisResult { /** The next step to continue from, or null if no continuation is possible */ continuationStep: string | null; /** Whether the flow requires user action (false for pending states that need waiting) */ isActionable: boolean; /** Array of step names that have completed successfully */ completedSteps: string[]; /** Array of step names that have failed */ failedSteps: string[]; /** Optional reason for failure or retry decision */ reason?: string; } /** * Abstract base class for bridging providers that implement cross-chain bridging protocols. * * This class defines the standard interface that all bridging providers must implement * to support cross-chain bridging. It provides a standardized way to check route * support, estimate costs, and execute bridge operations across different protocols. * * Bridging providers are responsible for: * - Validating bridge parameters and route support * - Estimating gas costs and protocol fees * - Executing the actual bridge operations * - Handling protocol-specific logic and error conditions * * @example * ```typescript * class CustomBridgingProvider extends BridgingProvider { * async supportsRoute(source: Chain, destination: Chain, token: TokenType): Promise { * // Implementation specific logic * return true * } * * async estimate(params: BridgeParams): Promise { * // Cost estimation logic * return { ... } * } * * async bridge(params: BridgeParams): Promise { * // Bridge execution logic * return { ... } * } * } * ``` */ declare abstract class BridgingProvider> { /** The name of the provider */ abstract name: string; /** * The chains that this provider supports. */ abstract supportedChains: ChainDefinition[]; /** * The action dispatcher for this provider. * * This property holds a reference to an action dispatcher that can be used to * dispatch events or actions during the transfer process. It is optional and * can be null if no dispatcher is registered. */ actionDispatcher?: Actionable | null; /** * Type-level map of action names to their payload types. * This property exists only at the type level and is used for TypeScript inference. */ readonly actions: TProviderActions; /** * Determines if this provider supports transfers between the specified source and destination chains. * * This method should check if the provider can handle transfers between the given chains, * typically by verifying that both chains have the necessary contract deployments and * configurations for the provider's protocol. * * @param source - The source chain definition * @param destination - The destination chain definition * @param token - The token to transfer (currently only USDC is supported) * @returns `true` if the provider supports this route, `false` otherwise * * @example * ```typescript * const provider = new CCTPV2Provider() * const canTransfer = provider.supportsRoute(Ethereum, Base) * if (canTransfer) { * console.log('CCTP v2 transfer is supported between Ethereum and Base') * } * ``` */ abstract supportsRoute(source: ChainDefinition, destination: ChainDefinition, token: 'USDC'): boolean; /** * Executes a cross-chain bridge operation between the specified source and destination chains. * * This method performs the actual bridge operation by coordinating with the underlying * protocol contracts and handling the multi-step process required for cross-chain * bridging. The implementation details vary by protocol but typically involve * burning/locking tokens on the source chain and minting/unlocking on the destination. * * @param params - The bridge parameters containing source, destination, amount, and configuration * @param token - The token to bridge (currently only USDC is supported) * @param config - Optional bridge configuration including speed and fee settings * @returns Promise resolving to the bridge result with transaction details and steps * @throws {KitError} If the parameters are invalid * @throws {UnsupportedRouteError} If the route is not supported * @throws {BridgeError} If the bridge operation fails * * @example * ```typescript * const result = await provider.bridge({ * source: { adapter: sourceAdapter, chain: 'Ethereum' }, * destination: { adapter: destAdapter, chain: 'Base' }, * amount: '10.50', * token: 'USDC' * }) * ``` */ abstract bridge(params: BridgeParams): Promise; /** * Estimates the cost and fees for a cross-chain bridge operation without executing it. * * This method calculates the expected gas costs and protocol fees for a bridge * operation, allowing users to understand the total cost before committing to * the transaction. The estimation should be as accurate as possible but may * vary slightly from actual execution due to network conditions. * * @param params - The bridge parameters for cost estimation * @returns Promise resolving to the cost estimate including gas and protocol fees * @throws {KitError} If the parameters are invalid * @throws {UnsupportedRouteError} If the route is not supported * * @example * ```typescript * const estimate = await provider.estimate({ * source: { adapter: sourceAdapter, chain: 'Ethereum' }, * destination: { adapter: destAdapter, chain: 'Base' }, * amount: '10.50', * token: 'USDC' * }) * console.log('Estimated cost:', estimate.totalCost) * ``` */ abstract estimate(params: BridgeParams): Promise; /** * Get all destination chains that are supported for transfers from the given source chain. * * This method filters the provider's supported chains to return only those that are * compatible with the source chain. Compatibility is determined by matching testnet * status (mainnet chains can only transfer to mainnet chains, testnets to testnets) * and excluding the source chain itself. * * @param source - The source chain definition to find compatible destinations for * @returns Array of chain definitions that can serve as destinations for the given source * * @example * ```typescript * const provider = new BridgingProvider() * const destinations = provider.getSupportedDestinationsFor(Ethereum) * console.log('Available destinations from Ethereum:', destinations.map(d => d.name)) * ``` */ getSupportedDestinationsFor(source: ChainDefinition): ChainDefinition[]; /** * Register an event dispatcher for handling provider-specific actions and events. * * * @param dispatcher - The event dispatcher implementing the Actionable interface * * @example * ```typescript * const provider = new BridgingProvider() * * const actionDispatcher = new Actionable() * * provider.registerDispatcher(actionDispatcher) * * // Now provider actions will be dispatched to the action dispatcher * await provider.bridge(transferParams) * ``` */ registerDispatcher(dispatcher: Actionable): void; /** * Determines if this provider supports retry operations for the given bridge result. * * This method checks whether the provider can retry a failed bridge operation. * By default, all providers return false unless explicitly implemented. * Providers that support retry should override this method to return true * when retry is feasible for the given result. * * @param result - The bridge result to check for retry support * @returns `true` if retry is supported for this result, `false` otherwise * * @example * ```typescript * const result = await provider.bridge(params) * if (provider.supportsRetry(result)) { * const retryResult = await provider.retry(result, retryContext) * } * ``` */ supportsRetry(result: BridgeResult): boolean; /** * Retries a failed bridge operation from the point of failure. * * This method attempts to retry a bridge operation that has previously failed, * continuing from the appropriate step based on the analysis of completed and * failed steps. By default, this method throws an error indicating that retry * is not supported. Providers that support retry should override this method. * * @param result - The failed bridge result to retry * @param context - The retry context containing source and destination adapter contexts * @returns Promise resolving to the retry bridge result * @throws {Error} If retry is not supported by this provider * * @example * ```typescript * const result = await provider.bridge(params) * if (result.state === 'error' && provider.supportsRetry(result)) { * const retryContext: RetryContext = { * from: { adapter: sourceAdapter, chain: 'Ethereum' }, * to: { adapter: destAdapter, chain: 'Base' } * } * const retryResult = await provider.retry(result, retryContext) * } * ``` */ retry(result: BridgeResult, context: RetryContext): Promise; /** * Analyzes bridge steps to determine retry feasibility and continuation point. * * This method examines the steps of a bridge operation to determine which steps * have completed, which have failed, and whether the operation can be retried * from a specific point. By default, this method throws an error indicating that * step analysis is not supported. Providers that support retry should override * this method to provide step analysis capabilities. * * @param steps - Array of bridge steps to analyze * @returns StepAnalysisResult containing retry analysis information * @throws Error If step analysis is not supported by this provider * * @example * ```typescript * const result = await provider.bridge(params) * if (result.state === 'error') { * const analysis = provider.analyzeStepsForRetry(result.steps) * if (analysis.isRetryable) { * console.log(`Can retry from step: ${analysis.continuationStep}`) * } * } * ``` */ analyzeStepsForRetry(steps: BridgeStep[]): StepAnalysisResult; } /** * Represents the decoded message body in an attestation response. * @interface DecodedMessageBody * @category Types * @description Contains the detailed information about a CCTP message body after decoding. */ interface DecodedMessageBody { /** * The address of the token being burned. * @example "0x1234..." */ burnToken: string; /** * The address of the recipient who will receive the minted tokens. * @example "0xabcd..." */ mintRecipient: string; /** * The amount of tokens being transferred. * @description The raw amount in the token's smallest unit. * @example "1000000" // For USDC, this would be 1 USDC */ amount: string; /** * The address of the account that initiated the message. * @example "0x5678..." */ messageSender: string; /** * The maximum fee that can be charged for the transfer. * @description Optional parameter for fee-based transfers. */ maxFee?: string; /** * The actual fee that was executed for the transfer. * @description Optional parameter tracking the actual fee charged. */ feeExecuted?: string; /** * The block number after which this message expires. * @description Optional parameter for time-bound messages. */ expirationBlock?: string; /** * Additional data passed to the destination chain's hook. * @description Optional parameter for custom hook execution. */ hookData?: string | null; } /** * Represents the decoded message in an attestation response. * @interface DecodedMessage * @category Types * @description Contains the complete decoded CCTP message including routing information. */ interface DecodedMessage { /** * The domain identifier of the source chain. * @description Unique identifier for the chain where the message originated. */ sourceDomain: string; /** * The domain identifier of the destination chain. * @description Unique identifier for the chain where the message will be received. */ destinationDomain: string; /** * A unique identifier for the message. * @description Used to prevent message replay and track message status. */ nonce: string; /** * The address of the sender on the source chain. * @example "0x1234..." */ sender: string; /** * The address of the recipient on the destination chain. * @example "0xabcd..." */ recipient: string; /** * The address allowed to execute the message on the destination chain. * @example "0x5678..." */ destinationCaller: string; /** * The raw message body before decoding. * @description Hex-encoded message payload. */ messageBody: string; /** * The decoded contents of the message body. */ decodedMessageBody: DecodedMessageBody; /** * The minimum finality threshold for the message. */ minFinalityThreshold: string; /** * The finality threshold that was executed. */ finalityThresholdExecuted: string; } /** * Represents a single message in the attestation response. * @interface AttestationMessage * @category Types * @description Contains the complete information about a CCTP message and its attestation. */ interface AttestationMessage { /** * The raw message data. * @description Hex-encoded message that was attested. */ message: string; /** * The nonce of the event that triggered this attestation. * @description Used to track the attestation in the CCTP system. */ eventNonce: string; /** * The attestation signature. * @description Cryptographic proof provided by the attestation service. */ attestation: string; /** * The decoded message data. */ decodedMessage: DecodedMessage; /** * The version of CCTP used for this message. * @description Indicates which version of the CCTP protocol was used. */ cctpVersion: number; /** * The current status of the attestation. * @description Indicates the processing state of the attestation. * @example "complete", "pending" */ status: string; /** * The delay reason if the attestation is delayed. */ delayReason?: string | null; } /** * The step type for the fetch attestation step of the CCTP v2 transfer process. * * @description The step type for the fetch attestation step of the CCTP v2 transfer process. * @extends TransferStep */ type BridgeFetchAttestationStep = BridgeStep & /** * The success state of the fetch attestation step. */ ({ state: 'success'; data: AttestationMessage; } /** * The pending state of the fetch attestation step. */ | { state: 'pending'; txHash?: string; data?: undefined; } /** * The error state of the fetch attestation step. */ | { state: 'error'; error: unknown; data?: undefined; }); /** * CCTPv2 bridge parameters. * * @remarks * This type extends the base BridgeParams type to include CCTPv2 specific * wallet context and chain definition. */ type CCTPV2BridgeParams = BridgeParams & { /** * The source wallet context containing the chain definition and wallet address. */ source: WalletContext; /** * The destination wallet context containing the chain definition and wallet address. */ destination: DestinationWalletContext; /** * The bridge configuration for the CCTPv2 transfer. */ config: BridgeConfig; }; /** * Action types supported by the CCTP v2 provider. * * @remarks * This interface defines the structure of actions that can be dispatched during * CCTP v2 transfer operations. Each action includes protocol metadata and a * `values` field containing the full bridge step with transaction details. * * All transaction-based steps (approve, burn, mint) include `txHash` and * `explorerUrl` fields for direct links to block explorers. * * @example * ```typescript * // Action structure received by event listeners * const burnAction: CCTPV2Actions['burn'] = { * protocol: 'cctp', * version: 'v2', * method: 'burn', * values: { * name: 'burn', * state: 'success', * txHash: '0x2ed454c5cfab41f0a58ad0c55bf6c326eb97067d2b02fa046dc5698bfc5530f1', * explorerUrl: 'https://sepolia.etherscan.io/tx/0x2ed454...', * data: { ... } * } * } * ``` */ interface CCTPV2Actions { /** * Approval action for CCTP v2 transfers. * Used to approve token spending before initiating a burn operation. */ approve: { protocol: 'cctp'; version: 'v2'; method: 'approve'; values: BridgeStep; }; /** * Burn action for CCTP v2 transfers. * Used to burn tokens on the source chain to initiate a cross-chain transfer. */ burn: { protocol: 'cctp'; version: 'v2'; method: 'burn'; values: BridgeStep; }; /** * Attestation action for CCTP v2 transfers. * Used to fetch the attestation message for the source wallet. */ fetchAttestation: { protocol: 'cctp'; version: 'v2'; method: 'fetchAttestation'; values: BridgeFetchAttestationStep; }; /** * Mint action for CCTP v2 transfers. * Used to mint tokens on the destination chain after a successful burn. */ mint: { protocol: 'cctp'; version: 'v2'; method: 'mint'; values: BridgeStep; }; } /** * CCTPv2 bridging provider interface. * * @remarks * This interface extends the base BridgingProvider interface to include CCTPv2 specific * methods for approving, depositing for burn, fetching attestation, and minting tokens. */ interface ICCTPV2BridgingProvider extends BridgingProvider { /** * Approves the amount of tokens for the source wallet. * * @param source - The source wallet context containing the chain definition and wallet address. * @param amount - The amount of tokens to approve. * @returns A promise that resolves to the prepared chain request. */ approve(source: BridgeParams['source'], amount: string, chain?: ChainDefinitionWithCCTPv2): Promise; /** * Deposits the amount of tokens for the source wallet. * * @param params - The bridge parameters containing source, destination, amount and optional config * @returns A promise that resolves to the prepared chain request. */ burn(params: BridgeParams): Promise; /** * Fetches the attestation message for the source wallet. * * @param source - The source wallet context containing the chain definition and wallet address. * @param txHash - The transaction hash of the deposit for burn transaction. * @returns A promise that resolves to the attestation message. */ fetchAttestation(source: BridgeParams['source'], txHash: string, config?: Partial): Promise; /** * Requests a fresh attestation for an expired attestation. * * This method is used when the original attestation has expired before the mint * transaction could be completed. It fetches the existing attestation data to * extract the nonce, requests re-attestation from Circle's API, and then polls * for the fresh attestation. * * @param source - The source wallet context containing the chain definition and wallet address. * @param txHash - The transaction hash of the original burn transaction. * @param config - Optional polling configuration overrides. * @returns A promise that resolves to the fresh attestation message. */ reAttest(source: BridgeParams['source'], txHash: string, config?: Partial): Promise; /** * Mints the amount of tokens for the destination wallet. * * @param destination - The destination wallet context containing the chain definition and wallet address. * @param messageBytes - The message bytes to mint. * @param attestation - The attestation message. * @returns A promise that resolves to the prepared chain request. */ mint(source: BridgeParams['source'], destination: BridgeParams['destination'], attestation: AttestationMessage): Promise; } /** * Configuration options for the CCTP v2 provider. * * @remarks * This interface defines all configurable aspects of the CCTP v2 provider: * - attestation: Settings for the attestation fetching process */ interface CCTPV2Config { /** Configuration for the attestation fetching process */ attestation?: Partial; } /** * Concrete implementation of BridgingProvider for Circle's Cross-Chain Transfer Protocol (CCTP) version 2. * * This provider handles cross-chain bridging using CCTP v2 contracts, which enable native USDC * bridging between supported blockchain networks. The provider supports burn-and-mint operations * with built-in validation, fee estimation, and transaction monitoring. * * The CCTPv2 provider is designed to be: * - **Type-safe**: Full TypeScript support with comprehensive validation * - **Flexible**: Support for both FAST and SLOW bridge configurations * - **Reliable**: Built-in error handling and recovery mechanisms * - **Observable**: Rich event emission for monitoring and debugging * * @example * ```typescript * import { CCTPV2BridgingProvider } from '@circle-fin/provider-cctp-v2' * import { createEvmAdapter } from '@circle-fin/adapter-viem-v2' * * const provider = new CCTPV2BridgingProvider() * * // Check route support * const isSupported = provider.supportsRoute('Ethereum', 'Base', 'USDC') * * // Create adapters * const sourceAdapter = createEvmAdapter({ privateKey: '0x...' }) * const destAdapter = createEvmAdapter({ privateKey: '0x...' }) * * // Prepare bridge parameters * const params: BridgeParams = { * source: { adapter: sourceAdapter, chain: 'Ethereum' }, * destination: { adapter: destAdapter, chain: 'Base' }, * amount: '10.50', * token: 'USDC', * config: { * transferSpeed: 'FAST', * }, * } * * // Estimate bridge costs * const estimate = await provider.estimate(params) * console.log('Estimated cost:', estimate.totalCost) * * // Execute bridge operation (when implemented) * const result = await provider.bridge(params) * console.log('Bridge completed!') * ``` */ declare class CCTPV2BridgingProvider extends BridgingProvider implements ICCTPV2BridgingProvider { /** The name of the provider */ readonly name = "CCTPV2BridgingProvider"; /** * The chains that this provider supports. */ supportedChains: ChainDefinition[]; /** * The provider's configuration. */ private readonly config; /** * Creates a new instance of the CCTP v2 bridging provider. * * @param config - Optional configuration overrides for the provider */ constructor(config?: CCTPV2Config); /** * Execute a cross-chain USDC bridge operation using the CCTP v2 protocol. * * This method orchestrates the complete CCTP v2 bridge flow including validation, * token approval, burning on source chain, attestation retrieval, and minting on * destination chain. The process is atomic and will revert if any step fails. * * This method performs the full CCTP v2 bridge flow by validating parameters and delegating * to the core bridge logic. It handles token approval, burning, attestation fetching, and minting. * * The bridge operation consists of these sequential steps: * 1. **Approval**: Approve USDC spending (if needed) * 2. **Burn**: Burn USDC on source chain * 3. **Attestation**: Fetch attestation from Circle's API * 4. **Mint**: Mint USDC on destination chain * * @param params - The bridge parameters containing source, destination, amount, and optional config. * @returns A promise resolving to the bridge result, including transaction details, step states, and explorer URLs. * @throws {KitError} When the parameters are invalid. * @throws {BridgeError} When the bridge operation fails. * @throws {UnsupportedRouteError} When the route is not supported. * * @example * ```typescript * const result = await provider.bridge({ * source: { adapter: sourceAdapter, chain: 'Ethereum' }, * destination: { adapter: destAdapter, chain: 'Base' }, * amount: '10.50', * token: 'USDC', * config: { transferSpeed: 'FAST' } * }) * * console.log('Bridge completed!') * console.log('Source tx:', result.steps.burn.transactionHash) * console.log('Destination tx:', result.steps.mint.transactionHash) * ``` */ bridge(params: CCTPV2BridgeParams): Promise; /** * Retry a failed or incomplete CCTP v2 bridge operation. * * Analyzes the bridge result to determine where to continue and executes * remaining steps from that point. Handles transaction failures, network * issues, and incomplete multi-step flows. * * @param result - The bridge result containing step history and current state. * @param context - The retry context with fresh adapter instances. * @returns Updated bridge result after retry execution. * * @throws Error when the result is not actionable or retry fails. * * @example * ```typescript * const retryResult = await provider.retry(failedResult, retryContext) * ``` */ retry(result: BridgeResult, context: RetryContext): Promise; /** * Estimate the cost and fees for a CCTP v2 cross-chain bridge operation. * * This method validates parameters and calculates the expected gas and protocol fees for a bridge * operation without executing it. The estimation includes gas costs for both source and destination * chains, as well as any applicable protocol fees. * * @param params - The bridge parameters containing source, destination, amount, and optional config. * @returns Promise resolving to detailed cost breakdown including: * - `gasFees`: Array of gas estimates for each step (Approve, Burn, Mint) * - Gas amounts in native token smallest units (wei for ETH, lamports for SOL, etc.) * - `fees`: Array of protocol and kit fees * - Provider fees in USDC decimal units (e.g., "0.1" USDC) * - Kit fees in USDC decimal units if configured * @throws {KitError} When the parameters are invalid. * @throws {UnsupportedRouteError} When the route is not supported. * * @example * ```typescript * const estimate = await provider.estimate({ * source: { adapter: sourceAdapter, chain: 'Ethereum' }, * destination: { adapter: destAdapter, chain: 'Base' }, * amount: '10.50', * token: 'USDC' * }) * * console.log('Total cost:', estimate.totalCost) * console.log('Source gas:', estimate.sourceGas) * console.log('Destination gas:', estimate.destinationGas) * ``` */ estimate(params: CCTPV2BridgeParams): Promise; /** * Extracts OperationContext from bridge parameters for a given wallet context. * * This method extracts the chain and address information from the wallet context * to construct an OperationContext for use with adapter method calls. * * @param walletContext - The wallet context to extract operation context from * @returns The operation context with chain and address information */ private extractOperationContext; /** * Helper method to add gas fee estimates to the result. */ private addGasFeeEstimate; /** * Helper method to add provider fee estimates to the result. */ private addProviderFeeEstimate; /** * Helper method to add kit fee to the result. */ private addKitFeeEstimate; /** * Prepares a USDC token approval transaction for CCTP v2 transfers. * * This method creates a prepared transaction that approves the CCTP v2 contract * to spend a specified amount of USDC tokens. The approval is required before * initiating a cross-chain burn operation. * * @param adapter - The adapter for transaction preparation and execution * @param amount - The amount of USDC to approve (as string to avoid precision issues) * @returns Promise resolving to a prepared chain request ready for gas estimation and execution * * @throws Error when adapter is not provided * @throws Error when amount is invalid (empty, negative, or malformed) * @throws Error when chain does not support CCTP v2 * @throws Error when chain does not have USDC configured * @throws Error when CCTP v2 contracts are missing or misconfigured * * @example * ```typescript * const provider = new CCTPV2BridgingProvider() * const prepared = await provider.approve(adapter, '1000000') // 1 USDC (6 decimals) * * // Estimate gas cost * const gasEstimate = await prepared.estimate() * console.log('Gas required:', gasEstimate.gas) * * // Execute the approval * const txHash = await prepared.execute() * console.log('Approval transaction:', txHash) * ``` */ approve(source: WalletContext, amount: string): Promise; /** * Prepares a CCTP v2 token minting transaction on the destination chain. * * This method creates a prepared transaction that calls the receiveMessage function * on the CCTP v2 MessageTransmitter contract to finalize the cross-chain transfer. * It's used to mint tokens on the destination chain after a successful burn operation * on the source chain. * * @param adapter - The adapter for transaction preparation and execution * @param messageBytes - The encoded message bytes from the source chain burn transaction * @param attestation - The attestation signature from Circle proving the burn happened * @returns Promise resolving to a prepared chain request ready for gas estimation and execution * * @throws Error when adapter is not provided * @throws Error when messageBytes is invalid (empty or malformed) * @throws Error when attestation is invalid (empty or malformed) * @throws Error when chain does not support CCTP v2 * @throws Error when CCTP v2 contracts are missing or misconfigured * * @example * ```typescript * const provider = new CCTPV2BridgingProvider() * const prepared = await provider.mint( * destAdapter, * '0x1234...', // message bytes from burn transaction * '0xabcd...' // attestation from Circle * ) * * // Estimate gas cost * const gasEstimate = await prepared.estimate() * console.log('Gas required:', gasEstimate.gas) * * // Execute the mint transaction * const txHash = await prepared.execute() * console.log('Mint transaction:', txHash) * ``` */ mint(source: WalletContext, destination: BridgeParams['destination'], attestation: AttestationMessage): Promise; /** * Fetches attestation data for a burn transaction from the IRIS API. * * This method retrieves the attestation data required to complete a mint operation * after a successful burn. It includes retry logic and timeout handling to ensure * reliable attestation fetching. * * @param sourceDomainId - The CCTP domain ID of the source chain * @param transactionHash - The transaction hash of the burn operation * @param isTestnet - Whether this is for a testnet chain (true) or mainnet chain (false) * @param config - Optional configuration overrides for this specific request * @returns Promise resolving to the first attestation message * @throws Error If no attestation is found for the transaction * @throws Error If the request times out after retries * @throws Error If the IRIS API returns an error response * @throws Error If the response format is invalid * * @example * ```typescript * const provider = new CCTPV2BridgingProvider({ * attestation: { maxRetries: 5 } // Global config * }) * * try { * // Use global config for mainnet * const result1 = await provider.fetchAttestation(1, '0x123...', false) * * // Override for this specific call on testnet * const result2 = await provider.fetchAttestation(1, '0x456...', true, { * timeout: 5000 // Override just the timeout * }) * } catch (error) { * if (error.message.includes('No attestation found')) { * // Handle missing attestation * } else if (error.message.includes('Request timed out')) { * // Handle timeout * } else if (error.message.includes('HTTP 4')) { * // Handle API error * } else { * // Handle other errors * } * } * ``` */ fetchAttestation(source: WalletContext, transactionHash: string, config?: Partial): Promise; /** * Requests a fresh attestation for an expired attestation. * * This method is used when the original attestation has expired before the mint * transaction could be completed. It performs three steps: * 1. Fetches the existing attestation data to extract the nonce * 2. Requests re-attestation from Circle's API using the nonce * 3. Polls for the fresh attestation and returns it * * @typeParam TFromAdapterCapabilities - The type representing the capabilities of the source adapter * @param source - The source wallet context containing the chain definition and wallet address * @param transactionHash - The transaction hash of the original burn transaction * @param config - Optional polling configuration overrides for timeout, retries, and delay * @returns A promise that resolves to the fresh attestation message * @throws {Error} With "Failed to re-attest: No nonce found for transaction" if the original * attestation cannot be found or has no nonce * @throws {Error} With "Failed to re-attest: No attestation found after re-attestation request" * if the fresh attestation cannot be retrieved * @throws {Error} With "Failed to re-attest: {details}" for other errors * * @example * ```typescript * import { CCTPV2BridgingProvider } from '@circle-fin/provider-cctp-v2' * import { Chains } from '@core/chains' * * const provider = new CCTPV2BridgingProvider() * * // After a mint fails due to expired attestation, request a fresh one * const source = { * adapter: viemAdapter, * chain: Chains.EthereumSepolia, * address: '0x1234...' * } * * try { * const freshAttestation = await provider.reAttest( * source, * '0xabc123...', // Original burn transaction hash * { timeout: 10000, maxRetries: 5 } * ) * * // Use the fresh attestation to retry the mint * const mintRequest = await provider.mint(source, destination, freshAttestation) * const result = await mintRequest.execute() * } catch (error) { * console.error('Re-attestation failed:', error.message) * } * ``` */ reAttest(source: WalletContext, transactionHash: string, config?: Partial): Promise; /** * Checks if both source and destination chains support CCTP v2 transfers. * * This method validates that both chains have CCTP v2 contracts deployed and configured. * It uses the `isCCTPV2Supported` guard function to check each chain individually. * * @param source - The source chain definition to check for CCTP v2 support * @param destination - The destination chain definition to check for CCTP v2 support * @returns `true` if both chains support CCTP v2, `false` otherwise * * @example * ```typescript * const provider = new CCTPV2BridgingProvider() * const canTransfer = provider.supportsRoute(Ethereum, Base) * * if (canTransfer) { * console.log('CCTP v2 transfer is supported between these chains') * } else { * console.log('One or both chains do not support CCTP v2') * } * ``` */ supportsRoute(source: ChainDefinition, destination: ChainDefinition, token: 'USDC'): boolean; /** * Determines the appropriate maximum fee for a cross-chain bridge operation. * * For FAST bridge operations, it calculates a dynamic fee based on the bridge amount * and fast bridge burn fee, or uses a provided maxFee if specified. * * For SLOW bridge operations, it returns 0 as there are no additional fees. * * @param params - The bridge parameters object containing: * - `source`: The source wallet context with chain definition and adapter * - `destination`: The destination wallet context with chain definition and adapter * - `amount`: The bridge amount in minor units (e.g., "1000000" for 1 USDC) * - `config`: Optional bridge configuration including transferSpeed and maxFee settings. * When used via BridgeKit, fee values are automatically converted from human-readable * format (e.g., "1") to smallest units (e.g., "1000000"). * @returns The maximum fee to be used for the bridge operation in minor units * * @example * ```typescript * const maxFee = await provider.getMaxFee({ * source: { adapter: sourceAdapter, chain: Chains.Ethereum, address: '0x...' }, * destination: { adapter: destAdapter, chain: Chains.Base, address: '0x...' }, * amount: '1000000', // 1 USDC in minor units * token: 'USDC', * config: { * transferSpeed: TransferSpeed.FAST, * maxFee: '1000000' // Provider receives values in smallest units * } * }) * console.log('Max fee:', maxFee) * ``` */ getMaxFee(params: BridgeParams): Promise; /** * Prepares a CCTP v2 burn operation to initiate a cross-chain bridge operation. * * This method creates the necessary transaction data for burning USDC tokens on the source * chain as part of the CCTP v2 bridge flow. The burn operation locks the tokens and emits * a message that can be used to mint equivalent tokens on the destination chain. * * @param params - The bridge parameters including source, destination, amount, and config * @returns Promise resolving to the prepared burn transaction data * * @example * ```typescript * const preparedBurn = await provider.burn( * { * source: { adapter, chain: "Ethereum_Sepolia" }, * destination: { adapter, chain: "Base_Sepolia" }, * amount: '1000000', // 1 USDC * token: 'USDC', * config: { transferSpeed: 'FAST' } * } * ) * await preparedBurn.execute() * ``` */ burn(params: BridgeParams): Promise; /** * Waits for a transaction to be mined and confirmed on the blockchain. * * This method should block until the transaction is confirmed on the blockchain. * * @param adapter - The adapter to use for transaction waiting * @param txHash - The hash of the transaction to wait for * @param chain - The chain definition where the transaction was executed * @param config - Optional configuration for transaction waiting (confirmations, timeout) * @returns The hash of the confirmed transaction * @example * ```typescript * const provider = new CCTPV2BridgingProvider() * const txHash = await provider.waitForTransaction( * adapter, * '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef', * Ethereum, * ) * console.log('Transaction confirmed:', txHash) * ``` */ waitForTransaction(adapter: Adapter, txHash: string, chain: ChainDefinition, config?: WaitForTransactionConfig): Promise; } /** * Get the token account address where USDC will be minted for the recipient. * * For EVM chains, the recipient address directly holds ERC20 tokens, so the raw * address is returned as-is. For Solana, USDC is held in Associated Token Accounts * (ATAs), so this function derives the ATA address for the given owner and USDC mint. * * @param chainType - The type of blockchain ('evm' or 'solana'). * @param rawAddress - The recipient's wallet address on the destination chain. * @param mint - The USDC mint address (only used for Solana chains). * @returns The address where USDC tokens will be minted (raw address for EVM, ATA for Solana). * * @example * ```typescript * import { getMintRecipientAccount } from './getMintRecipientAccount' * * // EVM: returns the same address * const evmAccount = await getMintRecipientAccount( * 'evm', * '0x742d35Cc6634C0532925a3b8D89C7DA5C3cfa', * 'N/A' * ) * * // Solana: derives the Associated Token Account * const solanaAccount = await getMintRecipientAccount( * 'solana', * '9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM', * 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v' * ) * ``` */ declare const getMintRecipientAccount: ( /** The blockchain type - determines how token accounts are handled */ chainType: ChainType, /** The recipient's wallet address (hex format for EVM, base58 for Solana) */ rawAddress: string, /** The USDC mint address (ignored for EVM chains, required base58 address for Solana) */ mintAddress: string) => Promise; export { CCTPV2BridgingProvider, getMintRecipientAccount }; export type { CCTPV2Config };