@circle-fin/provider-cctp-v2 1.4.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.d.ts CHANGED
@@ -33,7 +33,6 @@ import { TransactionInstruction, Signer, AddressLookupTableAccount } from '@sola
33
33
  */
34
34
  /**
35
35
  * Represents basic information about a currency or token.
36
- * @interface Currency
37
36
  * @category Types
38
37
  * @description Provides the essential properties of a cryptocurrency or token.
39
38
  * @example
@@ -65,7 +64,6 @@ interface Currency {
65
64
  }
66
65
  /**
67
66
  * Base information that all chain definitions must include.
68
- * @interface BaseChainDefinition
69
67
  * @category Types
70
68
  * @description Provides the common properties shared by all blockchain definitions.
71
69
  * @example
@@ -125,6 +123,11 @@ interface BaseChainDefinition {
125
123
  * @description Its presence indicates that USDC is supported.
126
124
  */
127
125
  usdcAddress: string | null;
126
+ /**
127
+ * The contract address for USDT.
128
+ * @description Its presence indicates that USDT is supported.
129
+ */
130
+ usdtAddress: string | null;
128
131
  /**
129
132
  * Optional CCTP configuration.
130
133
  * @description If provided, the chain supports CCTP.
@@ -166,7 +169,6 @@ interface BaseChainDefinition {
166
169
  }
167
170
  /**
168
171
  * Represents chain definitions for Ethereum Virtual Machine (EVM) compatible blockchains.
169
- * @interface EVMChainDefinition
170
172
  * @extends BaseChainDefinition
171
173
  * @category Types
172
174
  * @description Adds properties specific to EVM chains.
@@ -198,7 +200,6 @@ interface EVMChainDefinition extends BaseChainDefinition {
198
200
  }
199
201
  /**
200
202
  * Represents chain definitions for non-EVM blockchains.
201
- * @interface NonEVMChainDefinition
202
203
  * @extends BaseChainDefinition
203
204
  * @category Types
204
205
  * @description Contains properties for blockchains that do not use the EVM.
@@ -251,6 +252,7 @@ type ChainType = EVMChainDefinition['type'] | NonEVMChainDefinition['type'];
251
252
  * rpcEndpoints: ['https://eth.example.com'],
252
253
  * eurcAddress: null,
253
254
  * usdcAddress: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
255
+ * usdtAddress: '0xdac17f958d2ee523a2206206994597c13d831ec7',
254
256
  * cctp: {
255
257
  * domain: 0,
256
258
  * contracts: {
@@ -314,17 +316,74 @@ type ChainDefinitionWithCCTPv2 = ChainDefinition & {
314
316
  * - A string literal of the blockchain value (e.g., "Ethereum")
315
317
  */
316
318
  type ChainIdentifier$1 = ChainDefinition | Blockchain | `${Blockchain}`;
319
+ /**
320
+ * Split CCTP contract configuration.
321
+ *
322
+ * Used by chains that deploy separate TokenMessenger and MessageTransmitter contracts.
323
+ * This is the traditional CCTP architecture used by most EVM chains.
324
+ *
325
+ * @example
326
+ * ```typescript
327
+ * const splitConfig: CCTPSplitConfig = {
328
+ * type: 'split',
329
+ * tokenMessenger: '0x1234567890abcdef1234567890abcdef12345678',
330
+ * messageTransmitter: '0xabcdef1234567890abcdef1234567890abcdef12',
331
+ * confirmations: 12
332
+ * }
333
+ * ```
334
+ */
317
335
  interface CCTPSplitConfig {
318
336
  type: 'split';
319
337
  tokenMessenger: string;
320
338
  messageTransmitter: string;
321
339
  confirmations: number;
322
340
  }
341
+ /**
342
+ * Merged CCTP contract configuration.
343
+ *
344
+ * Used by chains that deploy a single unified CCTP contract.
345
+ * This simplified architecture is used by newer chain integrations.
346
+ *
347
+ * @example
348
+ * ```typescript
349
+ * const mergedConfig: CCTPMergedConfig = {
350
+ * type: 'merged',
351
+ * contract: '0x9876543210fedcba9876543210fedcba98765432',
352
+ * confirmations: 1
353
+ * }
354
+ * ```
355
+ */
323
356
  interface CCTPMergedConfig {
324
357
  type: 'merged';
325
358
  contract: string;
326
359
  confirmations: number;
327
360
  }
361
+ /**
362
+ * Version configuration for CCTP contracts.
363
+ *
364
+ * Defines whether the chain uses split or merged CCTP contract architecture.
365
+ * Split configuration uses separate TokenMessenger and MessageTransmitter contracts,
366
+ * while merged configuration uses a single unified contract.
367
+ *
368
+ * @example Split configuration (most EVM chains)
369
+ * ```typescript
370
+ * const splitConfig: VersionConfig = {
371
+ * type: 'split',
372
+ * tokenMessenger: '0x1234567890abcdef1234567890abcdef12345678',
373
+ * messageTransmitter: '0xabcdef1234567890abcdef1234567890abcdef12',
374
+ * confirmations: 12
375
+ * }
376
+ * ```
377
+ *
378
+ * @example Merged configuration (newer chains)
379
+ * ```typescript
380
+ * const mergedConfig: VersionConfig = {
381
+ * type: 'merged',
382
+ * contract: '0x9876543210fedcba9876543210fedcba98765432',
383
+ * confirmations: 1
384
+ * }
385
+ * ```
386
+ */
328
387
  type VersionConfig = CCTPSplitConfig | CCTPMergedConfig;
329
388
  type CCTPContracts = Partial<{
330
389
  v1: VersionConfig;
@@ -334,7 +393,6 @@ type CCTPContracts = Partial<{
334
393
  }>;
335
394
  /**
336
395
  * Configuration for the Cross-Chain Transfer Protocol (CCTP).
337
- * @interface CCTPConfig
338
396
  * @category Types
339
397
  * @description Contains the domain and required contract addresses for CCTP support.
340
398
  * @example
@@ -388,7 +446,7 @@ interface CCTPConfig {
388
446
  * const invalidType: KitContractType = 'invalid' // TypeScript error
389
447
  * ```
390
448
  */
391
- type KitContractType = 'bridge';
449
+ type KitContractType = 'bridge' | 'adapter';
392
450
  /**
393
451
  * Kit-specific contract addresses for enhanced chain functionality.
394
452
  *
@@ -441,6 +499,8 @@ declare enum Blockchain {
441
499
  Celo_Alfajores_Testnet = "Celo_Alfajores_Testnet",
442
500
  Codex = "Codex",
443
501
  Codex_Testnet = "Codex_Testnet",
502
+ Edge = "Edge",
503
+ Edge_Testnet = "Edge_Testnet",
444
504
  Ethereum = "Ethereum",
445
505
  Ethereum_Sepolia = "Ethereum_Sepolia",
446
506
  Hedera = "Hedera",
@@ -453,6 +513,8 @@ declare enum Blockchain {
453
513
  Linea_Sepolia = "Linea_Sepolia",
454
514
  Monad = "Monad",
455
515
  Monad_Testnet = "Monad_Testnet",
516
+ Morph = "Morph",
517
+ Morph_Testnet = "Morph_Testnet",
456
518
  NEAR = "NEAR",
457
519
  NEAR_Testnet = "NEAR_Testnet",
458
520
  Noble = "Noble",
@@ -659,8 +721,20 @@ type EvmPreparedChainRequestParams = {
659
721
  interface SolanaPreparedChainRequestParams {
660
722
  /**
661
723
  * The array of instructions to include in the transaction.
724
+ *
725
+ * @remarks
726
+ * Used for instruction-based transaction building. Mutually exclusive with
727
+ * `serializedTransaction`.
728
+ */
729
+ instructions?: TransactionInstruction[];
730
+ /**
731
+ * A pre-serialized transaction as a Uint8Array (e.g., from a service like Jupiter).
732
+ *
733
+ * @remarks
734
+ * Used for executing pre-built transactions from external services.
735
+ * The transaction may be partially signed. Mutually exclusive with `instructions`.
662
736
  */
663
- instructions: TransactionInstruction[];
737
+ serializedTransaction?: Uint8Array;
664
738
  /**
665
739
  * Additional signers besides the Adapter's wallet (e.g. program-derived authorities).
666
740
  */
@@ -1457,31 +1531,443 @@ interface CCTPActionMap {
1457
1531
  }
1458
1532
 
1459
1533
  /**
1460
- * Action map for native token operations (ETH, SOL, MATIC, etc.).
1534
+ * Permit signature standards for gasless token approvals.
1461
1535
  *
1462
- * Native tokens are the primary currency of each blockchain network,
1463
- * used for paying transaction fees and as a store of value.
1464
- * These actions operate on the native token without requiring
1465
- * a separate token contract address.
1536
+ * Defines the permit types that can be used to approve token spending
1537
+ * without requiring a separate approval transaction.
1466
1538
  *
1467
1539
  * @remarks
1468
- * Native token operations differ from ERC-20/SPL token operations
1469
- * in that they don't require contract interactions for basic transfers
1470
- * and balance checks.
1540
+ * - NONE: No permit, tokens must be pre-approved via separate transaction
1541
+ * - EIP2612: Standard ERC-20 permit (USDC, DAI v2, and most modern tokens)
1542
+ */
1543
+ declare enum PermitType {
1544
+ /** No permit required - tokens must be pre-approved */
1545
+ NONE = 0,
1546
+ /** EIP-2612 standard permit */
1547
+ EIP2612 = 1
1548
+ }
1549
+ /**
1550
+ * Token input with permit signature for gasless approval.
1471
1551
  *
1472
- * @see {@link ActionMap} for the complete action structure
1552
+ * The Adapter Contract uses this to pull tokens from the user's wallet
1553
+ * using permit signatures instead of requiring separate approval transactions.
1554
+ *
1555
+ * @example
1556
+ * ```typescript
1557
+ * const tokenInput: TokenInput = {
1558
+ * permitType: PermitType.EIP2612,
1559
+ * token: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC
1560
+ * from: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
1561
+ * amount: 1000000n, // 1 USDC
1562
+ * permitCalldata: '0x...' // Encoded permit(value, deadline, v, r, s)
1563
+ * }
1564
+ * ```
1473
1565
  */
1474
- interface NativeActionMap {
1566
+ interface TokenInput {
1475
1567
  /**
1476
- * Get the native token balance (SOL, ETH, etc.) for a wallet address.
1568
+ * Type of permit to execute.
1477
1569
  */
1478
- balanceOf: ActionParameters & {
1479
- /**
1480
- * The address to check the native balance for. If not provided, it will be
1481
- * automatically derived from the adapter context.
1482
- */
1483
- walletAddress?: string | undefined;
1484
- };
1570
+ permitType: PermitType;
1571
+ /**
1572
+ * Token contract address to pull from user.
1573
+ */
1574
+ token: `0x${string}`;
1575
+ /**
1576
+ * Amount of tokens to pull via permit.
1577
+ */
1578
+ amount: bigint;
1579
+ /**
1580
+ * ABI-encoded permit calldata.
1581
+ *
1582
+ * For EIP-2612: encode(value, deadline, v, r, s)
1583
+ * For Permit2: encode(permit, signature)
1584
+ *
1585
+ * @example '0x0000000000000000000000000000000000000000000000000000000000989680...'
1586
+ */
1587
+ permitCalldata: `0x${string}`;
1588
+ }
1589
+ /**
1590
+ * Single instruction to execute within the Adapter Contract.
1591
+ *
1592
+ * Each instruction represents a contract call (swap, fee collection, etc.)
1593
+ * with pre-execution approval and post-execution validation.
1594
+ *
1595
+ * @example
1596
+ * ```typescript
1597
+ * const swapInstruction: Instruction = {
1598
+ * target: '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE', // LiFi Diamond
1599
+ * data: '0x...', // LiFi swap calldata
1600
+ * value: 0n,
1601
+ * tokenIn: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC
1602
+ * amountToApprove: 1000000000n, // 1000 USDC to approve
1603
+ * tokenOut: '0xdAC17F958D2ee523a2206206994597C13D831ec7', // USDT
1604
+ * minTokenOut: 995000000n // 995 USDT minimum (0.5% slippage)
1605
+ * }
1606
+ * ```
1607
+ */
1608
+ interface Instruction {
1609
+ /**
1610
+ * Target contract address to call.
1611
+ *
1612
+ * Can be a DEX router, fee taker contract, or token contract.
1613
+ */
1614
+ target: `0x${string}`;
1615
+ /**
1616
+ * ABI-encoded calldata for the target contract.
1617
+ */
1618
+ data: `0x${string}`;
1619
+ /**
1620
+ * ETH value to send with the call (for native token operations).
1621
+ *
1622
+ * @defaultValue 0n
1623
+ */
1624
+ value: bigint;
1625
+ /**
1626
+ * Token to approve to target before executing instruction.
1627
+ *
1628
+ * Set to zero address (0x00...00) to disable pre-approval.
1629
+ */
1630
+ tokenIn: `0x${string}`;
1631
+ /**
1632
+ * Amount of tokenIn to approve to target before executing instruction.
1633
+ *
1634
+ * @remarks
1635
+ * Field name matches the adapter contract's `amountToApprove` parameter exactly.
1636
+ *
1637
+ * @defaultValue 0n if tokenIn is zero address
1638
+ */
1639
+ amountToApprove: bigint;
1640
+ /**
1641
+ * Token to validate minimum balance after instruction.
1642
+ *
1643
+ * Set to zero address (0x00...00) to disable post-validation.
1644
+ */
1645
+ tokenOut: `0x${string}`;
1646
+ /**
1647
+ * Minimum required balance of tokenOut after instruction.
1648
+ *
1649
+ * @defaultValue 0n if tokenOut is zero address
1650
+ */
1651
+ minTokenOut: bigint;
1652
+ }
1653
+ /**
1654
+ * Token recipient for residual sweep.
1655
+ *
1656
+ * After all instructions complete, the Adapter Contract sweeps
1657
+ * any remaining balances to the specified beneficiaries.
1658
+ */
1659
+ interface TokenRecipient {
1660
+ /**
1661
+ * Token contract address to sweep.
1662
+ */
1663
+ token: `0x${string}`;
1664
+ /**
1665
+ * Address to receive swept tokens.
1666
+ */
1667
+ beneficiary: `0x${string}`;
1668
+ }
1669
+ /**
1670
+ * Execution parameters for the Adapter Contract.
1671
+ *
1672
+ * This struct is signed via EIP-712 by the Circle proxy and verified
1673
+ * on-chain to ensure the execution is authorized.
1674
+ *
1675
+ * @remarks
1676
+ * The executeParams are provided by the stablecoin-service and must be
1677
+ * passed to the Adapter Contract exactly as received (no modification).
1678
+ *
1679
+ * @example
1680
+ * ```typescript
1681
+ * const executeParams: ExecuteParams = {
1682
+ * instructions: [
1683
+ * { target: dexRouter, data: swapCalldata, ... }
1684
+ * ],
1685
+ * tokens: [
1686
+ * { token: USDC, beneficiary: userAddress },
1687
+ * { token: USDT, beneficiary: userAddress }
1688
+ * ],
1689
+ * execId: 123456789n,
1690
+ * deadline: BigInt(Math.floor(Date.now() / 1000) + 1800),
1691
+ * metadata: '0x'
1692
+ * }
1693
+ * ```
1694
+ */
1695
+ interface ExecuteParams {
1696
+ /**
1697
+ * Array of instructions to execute sequentially.
1698
+ *
1699
+ * Each instruction can be a swap, fee collection, or other contract call.
1700
+ */
1701
+ instructions: Instruction[];
1702
+ /**
1703
+ * Token recipients for residual sweep.
1704
+ *
1705
+ * Typically a 2-tuple: [tokenIn recipient, tokenOut recipient]
1706
+ */
1707
+ tokens: TokenRecipient[];
1708
+ /**
1709
+ * Unique execution identifier for replay protection.
1710
+ *
1711
+ * Must be globally unique and is marked as used after execution.
1712
+ */
1713
+ execId: bigint;
1714
+ /**
1715
+ * Execution deadline timestamp (Unix seconds).
1716
+ *
1717
+ * Transaction reverts if block.timestamp is greater than deadline.
1718
+ */
1719
+ deadline: bigint;
1720
+ /**
1721
+ * Optional metadata for tracking and analytics.
1722
+ */
1723
+ metadata: `0x${string}`;
1724
+ }
1725
+ /**
1726
+ * Parameters for executing a swap transaction via the Adapter smart contract.
1727
+ *
1728
+ * This action executes swap transactions through the Adapter Contract, which
1729
+ * handles token approvals via permits (EIP-2612, Permit2, etc.) and executes
1730
+ * multi-step swap instructions atomically on-chain.
1731
+ *
1732
+ * @remarks
1733
+ * The swap flow uses the Adapter Contract pattern:
1734
+ * 1. Service provides `executeParams` and `signature` (proxy-signed EIP-712)
1735
+ * 2. SDK builds `tokenInputs` with permit signatures for gasless approvals
1736
+ * 3. SDK calls AdapterContract.execute(executeParams, tokenInputs, signature)
1737
+ * 4. Adapter Contract pulls tokens via permits, executes swaps, validates outputs
1738
+ *
1739
+ * This enables:
1740
+ * - Single atomic transaction (permit + swap in one tx)
1741
+ * - Gasless approvals via EIP-2612/Permit2
1742
+ * - Slippage protection enforced on-chain
1743
+ * - Multi-step instructions (swap + fees) atomically
1744
+ *
1745
+ * **Permit Support**: The SDK constructs `TokenInput` with `permitCalldata`
1746
+ * containing the encoded permit signature. The Adapter Contract executes
1747
+ * the permit on-chain before pulling tokens.
1748
+ *
1749
+ * @example
1750
+ * ```typescript
1751
+ * import type { ExecuteSwapParams } from '@core/adapter'
1752
+ * import { createSwap } from '@core/service-client'
1753
+ * import { PermitType } from '@core/adapter'
1754
+ *
1755
+ * // Get swap transaction from service
1756
+ * const swapResponse = await createSwap({
1757
+ * tokenInAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
1758
+ * tokenOutAddress: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
1759
+ * tokenInChain: 'Ethereum',
1760
+ * fromAddress: '0x...',
1761
+ * toAddress: '0x...',
1762
+ * amount: '1000000',
1763
+ * apiKey: 'KIT_KEY:...',
1764
+ * })
1765
+ *
1766
+ * // Build token inputs with permit
1767
+ * const tokenInputs: TokenInput[] = [{
1768
+ * permitType: PermitType.EIP2612,
1769
+ * token: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
1770
+ * from: userAddress,
1771
+ * amount: 1000000n,
1772
+ * permitCalldata: '0x...' // Encoded permit signature
1773
+ * }]
1774
+ *
1775
+ * // Prepare action parameters
1776
+ * const params: ExecuteSwapParams = {
1777
+ * executeParams: swapResponse.transaction.executeParams,
1778
+ * tokenInputs,
1779
+ * signature: swapResponse.transaction.signature,
1780
+ * inputAmount: BigInt(swapResponse.amount),
1781
+ * tokenInAddress: swapResponse.tokenInAddress as `0x${string}`
1782
+ * }
1783
+ * ```
1784
+ */
1785
+ interface ExecuteSwapEVMParams extends ActionParameters {
1786
+ /**
1787
+ * Execution parameters from the stablecoin-service.
1788
+ *
1789
+ * Contains instructions, token recipients, execution ID, deadline, and metadata.
1790
+ * This is an EIP-712 signed struct that the Adapter Contract validates.
1791
+ *
1792
+ * Provided by the service - do not modify.
1793
+ */
1794
+ executeParams: ExecuteParams;
1795
+ /**
1796
+ * Token inputs with permit signatures for gasless approvals.
1797
+ *
1798
+ * The SDK constructs this array with permit data for each token that needs
1799
+ * to be pulled from the user's wallet. The Adapter Contract executes these
1800
+ * permits on-chain before executing swap instructions.
1801
+ *
1802
+ * @remarks
1803
+ * For EIP-2612 permits, the SDK must:
1804
+ * 1. Build typed data with token, spender (Adapter), amount, nonce, deadline
1805
+ * 2. Get user signature via `adapter.signTypedData()`
1806
+ * 3. Encode as permitCalldata: encode(value, deadline, v, r, s)
1807
+ *
1808
+ * @example
1809
+ * ```typescript
1810
+ * [{
1811
+ * permitType: PermitType.EIP2612,
1812
+ * token: '0xUSDC',
1813
+ * from: userAddress,
1814
+ * amount: 1000000n,
1815
+ * permitCalldata: '0x...'
1816
+ * }]
1817
+ * ```
1818
+ */
1819
+ tokenInputs: TokenInput[];
1820
+ /**
1821
+ * EIP-712 signature from the Circle proxy service.
1822
+ *
1823
+ * The service signs the executeParams to authorize the execution.
1824
+ * The Adapter Contract verifies this signature on-chain.
1825
+ *
1826
+ * Provided by the service - do not modify.
1827
+ */
1828
+ signature: `0x${string}`;
1829
+ /**
1830
+ * Swap input amount in base units.
1831
+ *
1832
+ * @remarks
1833
+ * The amount of tokens being swapped, provided in the token's base units (e.g., wei for ETH,
1834
+ * smallest denomination for ERC20 tokens). This value should be extracted from the service
1835
+ * response, as it represents the authoritative swap amount for the operation.
1836
+ *
1837
+ * For native currency swaps (ETH → USDC), this amount is sent as the transaction `value`.
1838
+ * For ERC20 swaps (USDC → USDT), this amount determines the permit or approval quantity.
1839
+ *
1840
+ * @see CreateSwapResponse.amount - Service response field containing this value
1841
+ *
1842
+ * @example
1843
+ * ```typescript
1844
+ * import { createSwap } from '@core/service-client'
1845
+ *
1846
+ * // Get swap transaction from service
1847
+ * const response = await createSwap({
1848
+ * tokenInAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
1849
+ * amount: '1000000', // 1 USDC (6 decimals)
1850
+ * ...
1851
+ * })
1852
+ *
1853
+ * // Prepare swap execution using service response amount
1854
+ * await adapter.prepareAction('swap.execute', {
1855
+ * executeParams: response.transaction.executeParams,
1856
+ * tokenInputs,
1857
+ * signature: response.transaction.signature,
1858
+ * inputAmount: BigInt(response.amount),
1859
+ * tokenInAddress: response.tokenInAddress,
1860
+ * }, context)
1861
+ * ```
1862
+ */
1863
+ inputAmount: bigint;
1864
+ /**
1865
+ * Token address being swapped from.
1866
+ *
1867
+ * @remarks
1868
+ * Used to determine if the swap involves native currency (ETH, MATIC, etc.) or ERC20 tokens.
1869
+ * When tokenInAddress is NATIVE_TOKEN_ADDRESS (0xEeee...), the inputAmount is sent as tx.value.
1870
+ *
1871
+ * @see CreateSwapResponse.tokenInAddress - Service response field containing this value
1872
+ *
1873
+ * @example '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE' for ETH
1874
+ * @example '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' for USDC
1875
+ */
1876
+ tokenInAddress: `0x${string}`;
1877
+ }
1878
+ /**
1879
+ * Parameters for executing a swap transaction on Solana.
1880
+ *
1881
+ * This action executes swap transactions on Solana chains by deserializing
1882
+ * and executing a pre-built transaction provided by the stablecoin-service.
1883
+ *
1884
+ * @remarks
1885
+ * Unlike EVM chains that use the Adapter Contract pattern, Solana swaps
1886
+ * execute a fully serialized transaction provided by the service. The
1887
+ * transaction is base64-encoded and contains all necessary instructions
1888
+ * for the swap operation.
1889
+ *
1890
+ * The service handles:
1891
+ * - DEX aggregator routing (Jupiter, etc.)
1892
+ * - Fee collection
1893
+ * - Slippage protection
1894
+ * - Token account management
1895
+ *
1896
+ * @example
1897
+ * ```typescript
1898
+ * import type { ExecuteSwapSolanaParams } from '@core/adapter'
1899
+ * import { createSwap } from '@core/service-client'
1900
+ *
1901
+ * // Get swap transaction from service
1902
+ * const swapResponse = await createSwap({
1903
+ * tokenInAddress: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
1904
+ * tokenOutAddress: 'HzwqbKZw8HxMN6bF2yFZNrht3c2iXXzpKcFu7uBEDKtr',
1905
+ * tokenInChain: 'Solana',
1906
+ * fromAddress: 'YubQzu18FDqJRyNfG8JqHmsdbxhnoQqcKUHBdUkN6tP',
1907
+ * toAddress: 'YubQzu18FDqJRyNfG8JqHmsdbxhnoQqcKUHBdUkN6tP',
1908
+ * amount: '1000000',
1909
+ * apiKey: 'KIT_KEY:...',
1910
+ * })
1911
+ *
1912
+ * // Prepare action parameters
1913
+ * const params: ExecuteSwapSolanaParams = {
1914
+ * serializedTransaction: swapResponse.transaction.data
1915
+ * }
1916
+ * ```
1917
+ */
1918
+ interface ExecuteSwapSolanaParams extends ActionParameters {
1919
+ /**
1920
+ * Base64-encoded serialized Solana transaction.
1921
+ *
1922
+ * This transaction is fully constructed by the stablecoin-service and
1923
+ * contains all swap instructions, fee payments, and token account setup.
1924
+ * The transaction must be deserialized, signed, and submitted to the network.
1925
+ *
1926
+ * Provided by the service - do not modify.
1927
+ *
1928
+ * @example 'AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAQAJFQg...'
1929
+ */
1930
+ serializedTransaction: string;
1931
+ }
1932
+ /**
1933
+ * Parameters accepted by the swap.execute action, supporting both EVM and Solana chains.
1934
+ *
1935
+ * @remarks
1936
+ * This union type covers all chain-specific swap execution parameter interfaces
1937
+ * currently supported by the App Kit. Extend this union to support
1938
+ * additional blockchains as needed. Each member provides all fields required
1939
+ * to prepare and execute a pre-built swap transaction on its respective chain.
1940
+ *
1941
+ * **Type Narrowing**: The correct parameter type is inferred from the chain type
1942
+ * in the `OperationContext` passed to `adapter.prepareAction()`. Action handlers
1943
+ * use property-based type guards (checking for `executeParams`/`tokenInputs` for EVM
1944
+ * or `serializedTransaction` for Solana) to narrow the union type at runtime.
1945
+ *
1946
+ * - {@link ExecuteSwapEVMParams} - For EVM chains (has `executeParams` and `tokenInputs`)
1947
+ * - {@link ExecuteSwapSolanaParams} - For Solana chains (has `serializedTransaction`)
1948
+ */
1949
+ type ExecuteSwapParams = ExecuteSwapEVMParams | ExecuteSwapSolanaParams;
1950
+ /**
1951
+ * Action map for swap operations on EVM chains.
1952
+ *
1953
+ * This namespace contains actions related to token swapping operations.
1954
+ * These actions handle the execution of pre-built swap transactions from
1955
+ * DEX aggregators and routing services.
1956
+ *
1957
+ * @remarks
1958
+ * The swap namespace is designed to be extensible for future swap-related
1959
+ * operations such as multi-hop swaps, batched swaps, or swap-and-bridge
1960
+ * compositions.
1961
+ */
1962
+ interface SwapActionMap {
1963
+ /**
1964
+ * Execute a pre-built swap transaction.
1965
+ *
1966
+ * This action prepares and executes swap transactions constructed by the
1967
+ * stablecoin-service API. It accepts transaction parameters (to, data, value)
1968
+ * and returns a prepared chain request suitable for gas estimation or execution.
1969
+ */
1970
+ readonly execute: ExecuteSwapParams;
1485
1971
  }
1486
1972
 
1487
1973
  interface TokenActionMap {
@@ -1696,6 +2182,81 @@ interface USDCActionMap {
1696
2182
  balanceOf: Omit<BaseUSDCActions['balanceOf'], 'tokenAddress'>;
1697
2183
  }
1698
2184
 
2185
+ /**
2186
+ * USDT-specific operations that automatically resolve the token address.
2187
+ *
2188
+ * These include standard ERC20 operations. The interface provides the same core
2189
+ * operations as {@link TokenActionMap} but without requiring a `tokenAddress`
2190
+ * parameter.
2191
+ *
2192
+ * @example
2193
+ * ```typescript
2194
+ * // USDT operations (address auto-resolved)
2195
+ * await adapter.action('usdt.transfer', {
2196
+ * to: '0x1234...',
2197
+ * amount: '1000000' // 1 USDT
2198
+ * })
2199
+ *
2200
+ * // vs. general token operations (address required)
2201
+ * await adapter.action('token.transfer', {
2202
+ * tokenAddress: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
2203
+ * to: '0x1234...',
2204
+ * amount: '1000000'
2205
+ * })
2206
+ * ```
2207
+ */
2208
+ type BaseUSDTActions = {
2209
+ [K in keyof TokenActionMap]: Omit<TokenActionMap[K], 'tokenAddress'>;
2210
+ };
2211
+ /**
2212
+ * USDT action map with standard ERC20 operations.
2213
+ *
2214
+ * This provides standard token operations for USDT transfers.
2215
+ */
2216
+ interface USDTActionMap {
2217
+ /**
2218
+ * Transfer USDT tokens directly from the wallet to another address.
2219
+ *
2220
+ * Automatically uses the USDT contract address for the current chain.
2221
+ */
2222
+ transfer: BaseUSDTActions['transfer'];
2223
+ }
2224
+
2225
+ /**
2226
+ * Native token-related action maps for the bridge kit.
2227
+ *
2228
+ * This module provides action definitions for native token operations.
2229
+ */
2230
+ interface NativeActionMap {
2231
+ /**
2232
+ * Transfer native tokens directly from the wallet to another address.
2233
+ */
2234
+ transfer: ActionParameters & {
2235
+ /**
2236
+ * The chain to transfer the native tokens on.
2237
+ */
2238
+ chain?: ChainIdentifier$1;
2239
+ /**
2240
+ * The address to send the native tokens to.
2241
+ */
2242
+ to: string;
2243
+ /**
2244
+ * The amount of native tokens to transfer.
2245
+ */
2246
+ amount: bigint;
2247
+ };
2248
+ /**
2249
+ * Get the native token balance (SOL, ETH, etc.) for a wallet address.
2250
+ */
2251
+ balanceOf: ActionParameters & {
2252
+ /**
2253
+ * The address to check the native balance for. If not provided, it will be
2254
+ * automatically derived from the adapter context.
2255
+ */
2256
+ walletAddress?: string | undefined;
2257
+ };
2258
+ }
2259
+
1699
2260
  /**
1700
2261
  * Central registry of all available action namespaces and their operations.
1701
2262
  *
@@ -1715,12 +2276,16 @@ interface USDCActionMap {
1715
2276
  interface ActionMap {
1716
2277
  /** CCTP-specific operations with automatic address resolution. */
1717
2278
  readonly cctp: CCTPActionMap;
1718
- /** Native token operations (ETH, SOL, MATIC, etc.). */
1719
- readonly native: NativeActionMap;
1720
2279
  /** General token operations requiring explicit token addresses. */
1721
2280
  readonly token: TokenActionMap;
1722
2281
  /** USDC-specific operations with automatic address resolution. */
1723
2282
  readonly usdc: USDCActionMap;
2283
+ /** USDT-specific operations with automatic address resolution. */
2284
+ readonly usdt: USDTActionMap;
2285
+ /** Native token operations. */
2286
+ readonly native: NativeActionMap;
2287
+ /** Swap operations for DEX aggregator integrations. */
2288
+ readonly swap: SwapActionMap;
1724
2289
  }
1725
2290
  /**
1726
2291
  * Determine if a type represents an action parameter object (leaf node).
@@ -1859,7 +2424,7 @@ type ActionHandler<TActionKey extends ActionKeys> = (params: ActionPayload<TActi
1859
2424
  * This type defines a registry object where each key is a valid action key
1860
2425
  * (as defined by {@link ActionKeys}) and each value is an {@link ActionHandler}
1861
2426
  * capable of processing the payload for that action. This enables strongly-typed
1862
- * handler registration and lookup for all supported actions in the Stablecoin Kits.
2427
+ * handler registration and lookup for all supported actions in the App Kits.
1863
2428
  *
1864
2429
  * @remarks
1865
2430
  * Each handler is typed as {@link ActionHandler}, which means the handler
@@ -2121,11 +2686,11 @@ interface AdapterCapabilities {
2121
2686
  /**
2122
2687
  * Abstract class defining the standard interface for an adapter that interacts with a specific blockchain.
2123
2688
  *
2124
- * A `Adapter` is responsible for encapsulating chain-specific logic necessary to
2689
+ * An `Adapter` is responsible for encapsulating chain-specific logic necessary to
2125
2690
  * perform operations like sending transactions, querying balances, or interacting with smart contracts.
2126
2691
  * Implementations of this class will provide concrete logic for a particular blockchain protocol.
2127
2692
  *
2128
- * This abstraction allows the Stablecoin Kits to work with multiple blockchains in a uniform way.
2693
+ * This abstraction allows the App Kit to work with multiple blockchains in a uniform way.
2129
2694
  *
2130
2695
  * @typeParam TAdapterCapabilities - The adapter capabilities type for compile-time address validation.
2131
2696
  * When provided, enables strict typing of operation context based on the adapter's address control model.
@@ -2386,6 +2951,35 @@ declare abstract class Adapter<TAdapterCapabilities extends AdapterCapabilities
2386
2951
  * @returns A promise that resolves to the total transaction fee as a bigint.
2387
2952
  */
2388
2953
  abstract calculateTransactionFee(baseComputeUnits: bigint, bufferBasisPoints: bigint | undefined, chain: ChainDefinition): Promise<EstimatedGas>;
2954
+ /**
2955
+ * Get the decimal places for a token address on a given chain.
2956
+ *
2957
+ * This method fetches the number of decimal places from a token contract.
2958
+ * Different chain types implement this differently:
2959
+ * - EVM: Calls the `decimals()` function on ERC-20 contracts
2960
+ * - Solana: Reads the `decimals` field from the SPL token mint account
2961
+ *
2962
+ * @param tokenAddress - The token contract address (EVM) or mint address (Solana)
2963
+ * @param chain - The chain definition where the token is deployed
2964
+ * @returns Promise resolving to the number of decimal places for the token
2965
+ * @throws Error when the token contract doesn't exist or decimals cannot be fetched
2966
+ *
2967
+ * @example
2968
+ * ```typescript
2969
+ * import { EthersAdapter } from '@circle-fin/adapter-ethers-v6'
2970
+ * import { Ethereum } from '@core/chains'
2971
+ *
2972
+ * const adapter = new EthersAdapter({ signer })
2973
+ *
2974
+ * // Fetch decimals for DAI token
2975
+ * const decimals = await adapter.getTokenDecimals(
2976
+ * '0x6B175474E89094C44Da98b954EedeAC495271d0F',
2977
+ * Ethereum
2978
+ * )
2979
+ * console.log(decimals) // 18
2980
+ * ```
2981
+ */
2982
+ abstract getTokenDecimals(tokenAddress: string, chain: ChainDefinition): Promise<number>;
2389
2983
  }
2390
2984
 
2391
2985
  /**
@@ -2578,6 +3172,20 @@ declare module './types' {
2578
3172
  */
2579
3173
  interface TokenSymbolRegistry {
2580
3174
  USDC: true;
3175
+ USDT: true;
3176
+ EURC: true;
3177
+ DAI: true;
3178
+ USDE: true;
3179
+ PYUSD: true;
3180
+ WETH: true;
3181
+ WBTC: true;
3182
+ WSOL: true;
3183
+ WAVAX: true;
3184
+ WPOL: true;
3185
+ ETH: true;
3186
+ POL: true;
3187
+ PLUME: true;
3188
+ MON: true;
2581
3189
  }
2582
3190
  }
2583
3191
 
@@ -2755,7 +3363,8 @@ interface TokenDefinition {
2755
3363
  */
2756
3364
  readonly symbol: string;
2757
3365
  /**
2758
- * The number of decimal places for the token.
3366
+ * The default number of decimal places for the token.
3367
+ * Used when no chain-specific override exists in {@link chainDecimals}.
2759
3368
  * @example 6 for USDC, 18 for most ERC20 tokens
2760
3369
  */
2761
3370
  readonly decimals: number;
@@ -2765,6 +3374,15 @@ interface TokenDefinition {
2765
3374
  * Not all chains need to be present - tokens may only exist on a subset of chains.
2766
3375
  */
2767
3376
  readonly locators: Partial<ChainLocatorMap>;
3377
+ /**
3378
+ * Optional per-chain decimal overrides.
3379
+ *
3380
+ * Some tokens have different decimal places on different chains
3381
+ * (e.g., USDe is 18 decimals on EVM but 9 decimals on Solana).
3382
+ * When present, the value for a specific chain takes precedence
3383
+ * over the default {@link decimals}.
3384
+ */
3385
+ readonly chainDecimals?: Partial<Record<ChainIdentifier, number>>;
2768
3386
  }
2769
3387
  /**
2770
3388
  * A raw token locator selector with explicit decimals.
@@ -2923,6 +3541,15 @@ interface TokenRegistry {
2923
3541
  * @throws When the token cannot be resolved (unknown symbol, missing decimals, etc.).
2924
3542
  */
2925
3543
  resolve(selector: TokenSelector, chainId: ChainIdentifier): ResolvedToken;
3544
+ /**
3545
+ * Resolve a token by chain-specific locator (address/program ID).
3546
+ *
3547
+ * @param address - The token locator to resolve.
3548
+ * @param chainId - The chain identifier to resolve for.
3549
+ * @returns The resolved token information.
3550
+ * @throws When no registry token matches the locator on the chain.
3551
+ */
3552
+ resolveByAddress(address: string, chainId: ChainIdentifier): ResolvedToken;
2926
3553
  /**
2927
3554
  * Get a token definition by symbol.
2928
3555
  *
@@ -3288,7 +3915,7 @@ interface Timer {
3288
3915
  * ```typescript
3289
3916
  * // Create a scoped metrics instance
3290
3917
  * const appMetrics = metrics.child({
3291
- * service: 'stablecoin-kit',
3918
+ * service: 'app-kit',
3292
3919
  * version: '1.0.0',
3293
3920
  * })
3294
3921
  *