@circle-fin/adapter-ethers-v6 0.0.2-alpha.6 → 1.0.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.
Files changed (5) hide show
  1. package/README.md +466 -162
  2. package/index.cjs.js +8395 -6251
  3. package/index.d.ts +1049 -320
  4. package/index.mjs +8397 -6254
  5. package/package.json +5 -5
package/index.d.ts CHANGED
@@ -423,6 +423,10 @@ declare enum Blockchain {
423
423
  Ethereum_Sepolia = "Ethereum_Sepolia",
424
424
  Hedera = "Hedera",
425
425
  Hedera_Testnet = "Hedera_Testnet",
426
+ HyperEVM = "HyperEVM",
427
+ HyperEVM_Testnet = "HyperEVM_Testnet",
428
+ Ink = "Ink",
429
+ Ink_Testnet = "Ink_Testnet",
426
430
  Linea = "Linea",
427
431
  Linea_Sepolia = "Linea_Sepolia",
428
432
  NEAR = "NEAR",
@@ -433,6 +437,8 @@ declare enum Blockchain {
433
437
  Optimism_Sepolia = "Optimism_Sepolia",
434
438
  Polkadot_Asset_Hub = "Polkadot_Asset_Hub",
435
439
  Polkadot_Westmint = "Polkadot_Westmint",
440
+ Plume = "Plume",
441
+ Plume_Testnet = "Plume_Testnet",
436
442
  Polygon = "Polygon",
437
443
  Polygon_Amoy_Testnet = "Polygon_Amoy_Testnet",
438
444
  Sei = "Sei",
@@ -449,6 +455,8 @@ declare enum Blockchain {
449
455
  Unichain_Sepolia = "Unichain_Sepolia",
450
456
  World_Chain = "World_Chain",
451
457
  World_Chain_Sepolia = "World_Chain_Sepolia",
458
+ XDC = "XDC",
459
+ XDC_Apothem = "XDC_Apothem",
452
460
  ZKSync_Era = "ZKSync_Era",
453
461
  ZKSync_Sepolia = "ZKSync_Sepolia"
454
462
  }
@@ -618,10 +626,6 @@ type EvmPreparedChainRequestParams = {
618
626
  functionName: string;
619
627
  /** The arguments to pass to the function. */
620
628
  args: unknown[];
621
- /**
622
- * The chain the prepared request should be executed on.
623
- */
624
- chain: EVMChainDefinition;
625
629
  } & Partial<EvmEstimateOverrides>;
626
630
  /**
627
631
  * Solana-specific parameters for preparing a transaction.
@@ -787,6 +791,147 @@ interface WaitForTransactionConfig {
787
791
  */
788
792
  maxSupportedTransactionVersion?: number;
789
793
  }
794
+ /**
795
+ * Type utility to extract the address context from adapter capabilities.
796
+ *
797
+ * @typeParam TAdapterCapabilities - The adapter capabilities type
798
+ * @returns The address context type or never if capabilities are undefined
799
+ */
800
+ type ExtractAddressContext<TAdapterCapabilities extends AdapterCapabilities> = TAdapterCapabilities extends {
801
+ addressContext: infer TContext;
802
+ } ? TContext : never;
803
+ type AddressField<TAddressContext> = TAddressContext extends 'user-controlled' ? {
804
+ /**
805
+ * ℹ️ Address is forbidden for user-controlled adapters.
806
+ *
807
+ * User-controlled adapters (like browser wallets or private key adapters)
808
+ * automatically resolve the address from the connected wallet or signer.
809
+ * Providing an explicit address would conflict with this behavior.
810
+ *
811
+ * @example
812
+ * ```typescript
813
+ * // ℹ️ This will cause a TypeScript error:
814
+ * const context: AdapterContext<{ addressContext: 'user-controlled' }> = {
815
+ * adapter: userAdapter,
816
+ * chain: 'Ethereum',
817
+ * address: '0x123...' // Error: Address is forbidden for user-controlled adapters
818
+ * }
819
+ * ```
820
+ */
821
+ address?: never;
822
+ } : TAddressContext extends 'developer-controlled' ? {
823
+ /**
824
+ * ℹ️ Address is required for developer-controlled adapters.
825
+ *
826
+ * Developer-controlled adapters (like enterprise providers or server-side adapters)
827
+ * require an explicit address for each operation since they don't have a single
828
+ * connected wallet. The address must be provided for every operation.
829
+ *
830
+ * @example
831
+ * ```typescript
832
+ * // ℹ️ This is required:
833
+ * const context: AdapterContext<{ addressContext: 'developer-controlled' }> = {
834
+ * adapter: devAdapter,
835
+ * chain: 'Ethereum',
836
+ * address: '0x123...' // Required for developer-controlled adapters
837
+ * }
838
+ *
839
+ * // ℹ️ This will cause a TypeScript error:
840
+ * const context: AdapterContext<{ addressContext: 'developer-controlled' }> = {
841
+ * adapter: devAdapter,
842
+ * chain: 'Ethereum'
843
+ * // Error: Address is required for developer-controlled adapters
844
+ * }
845
+ * ```
846
+ */
847
+ address: string;
848
+ } : {
849
+ /**
850
+ * Address is optional for legacy adapters.
851
+ *
852
+ * Legacy adapters without defined capabilities maintain backward compatibility
853
+ * by allowing optional address specification.
854
+ */
855
+ address?: string;
856
+ };
857
+ /**
858
+ * Generic operation context for adapter methods with compile-time address validation.
859
+ *
860
+ * This type provides compile-time enforcement of address requirements based on the
861
+ * adapter's capabilities. The address field behavior is determined by the adapter's
862
+ * address control model:
863
+ *
864
+ * - **User-controlled adapters** (default): The `address` field is forbidden (never) because
865
+ * the address is automatically resolved from the connected wallet or signer.
866
+ * - **Developer-controlled adapters**: The `address` field is required (string) because
867
+ * each operation must explicitly specify which address to use.
868
+ * - **Legacy adapters**: The `address` field remains optional for backward compatibility.
869
+ *
870
+ * @typeParam TAdapterCapabilities - The adapter capabilities type to derive address requirements from
871
+ *
872
+ * @example
873
+ * ```typescript
874
+ * import { OperationContext } from '@core/adapter'
875
+ *
876
+ * // User-controlled adapter context (default - address forbidden)
877
+ * type UserContext = OperationContext<{ addressContext: 'user-controlled', supportedChains: [] }>
878
+ * const userCtx: UserContext = {
879
+ * chain: 'Ethereum'
880
+ * // address: '0x123...' // ❌ TypeScript error: address not allowed
881
+ * }
882
+ *
883
+ * // Developer-controlled adapter context (explicit - address required)
884
+ * type DevContext = OperationContext<{ addressContext: 'developer-controlled', supportedChains: [] }>
885
+ * const devCtx: DevContext = {
886
+ * chain: 'Ethereum',
887
+ * address: '0x123...' // ✅ Required for developer-controlled
888
+ * }
889
+ * ```
890
+ */
891
+ type OperationContext<TAdapterCapabilities extends AdapterCapabilities = AdapterCapabilities> = {
892
+ /**
893
+ * The blockchain network to use for this operation.
894
+ */
895
+ chain: ChainIdentifier;
896
+ } & AddressField<ExtractAddressContext<TAdapterCapabilities>>;
897
+ /**
898
+ * Fully resolved context for an adapter operation, with concrete chain and address.
899
+ *
900
+ * This interface guarantees that both the blockchain network (`chain`) and the account
901
+ * address (`address`) are present and valid. It is produced by resolving an {@link OperationContext},
902
+ * which may have optional or conditional fields, into a form suitable for internal logic and action handlers.
903
+ *
904
+ * - `chain`: A fully resolved {@link ChainDefinition}, either explicitly provided or inferred from the adapter.
905
+ * - `address`: A string representing the resolved account address, determined by the context or adapter,
906
+ * depending on the address control model (developer- or user-controlled).
907
+ *
908
+ * Use this type when an operation requires both the chain and address to be unambiguous and available.
909
+ *
910
+ * @example
911
+ * ```ts
912
+ * import { ResolvedOperationContext} from "@core/adapter"
913
+ * import { Solana, ChainDefinition } from '@core/chains';
914
+ *
915
+ * const context: ResolvedOperationContext = {
916
+ * chain: Solana,
917
+ * address: '7Gk1v...abc123', // a valid Solana address
918
+ * };
919
+ *
920
+ * // Use context.chain and context.address in adapter operations
921
+ * ```
922
+ */
923
+ interface ResolvedOperationContext {
924
+ /**
925
+ * The chain identifier for this operation.
926
+ * Guaranteed to be defined - either from context or adapter default.
927
+ */
928
+ chain: ChainDefinition;
929
+ /**
930
+ * The address for this operation.
931
+ * Guaranteed to be defined - either specified (developer-controlled) or resolved (user-controlled).
932
+ */
933
+ address: string;
934
+ }
790
935
 
791
936
  /**
792
937
  * Base interface for all action parameter objects.
@@ -1023,6 +1168,14 @@ interface CCTPv2ActionMap {
1023
1168
  * Destination chain definition where tokens will be minted.
1024
1169
  */
1025
1170
  readonly toChain: ChainDefinitionWithCCTPv2;
1171
+ /**
1172
+ * Optional destination wallet address on the destination chain to receive minted USDC.
1173
+ *
1174
+ * When provided (e.g., for Solana), the mint instruction will derive the
1175
+ * recipient's Associated Token Account (ATA) from this address instead of
1176
+ * the adapter's default address.
1177
+ */
1178
+ readonly destinationAddress?: string;
1026
1179
  };
1027
1180
  /**
1028
1181
  * Initiate a cross-chain USDC transfer using a custom bridge contract with preapproval funnel.
@@ -1116,7 +1269,7 @@ interface CCTPv2ActionMap {
1116
1269
  *
1117
1270
  * @defaultValue 0n - no protocol fee for basic usage
1118
1271
  */
1119
- protocolFee?: bigint;
1272
+ protocolFee?: bigint | undefined;
1120
1273
  /**
1121
1274
  * Address to receive the protocol fee.
1122
1275
  *
@@ -1126,7 +1279,7 @@ interface CCTPv2ActionMap {
1126
1279
  *
1127
1280
  * @defaultValue bridge contract address - safe fallback for zero fees
1128
1281
  */
1129
- feeRecipient?: string;
1282
+ feeRecipient?: string | undefined;
1130
1283
  /**
1131
1284
  * Source chain definition where tokens will be burned.
1132
1285
  */
@@ -1380,7 +1533,7 @@ interface USDCActionMap {
1380
1533
  /**
1381
1534
  * Central registry of all available action namespaces and their operations.
1382
1535
  *
1383
- * Define the complete action map structure used throughout the bridging kit.
1536
+ * Define the complete action map structure used throughout the bridge kit.
1384
1537
  * Each top-level key represents a namespace (e.g., 'token', 'usdc') containing
1385
1538
  * related operations. The structure supports arbitrary nesting depth through
1386
1539
  * the recursive utility types provided in this module.
@@ -1473,7 +1626,7 @@ type NestedValue<T, K extends string> = K extends `${infer First}.${infer Rest}`
1473
1626
  *
1474
1627
  * @remarks
1475
1628
  * This type serves as the canonical source for all valid action identifiers
1476
- * in the bridging kit. It ensures compile-time validation of action keys
1629
+ * in the bridge kit. It ensures compile-time validation of action keys
1477
1630
  * and enables type-safe action dispatching throughout the application.
1478
1631
  *
1479
1632
  * @see {@link ActionPayload} for extracting parameter types
@@ -1515,18 +1668,23 @@ type ActionPayload<T extends ActionKeys> = Omit<NestedValue<ActionMap, T>, '__is
1515
1668
  *
1516
1669
  * @typeParam TActionKey - The specific action key this handler processes.
1517
1670
  * @param params - The action payload matching the specified action key.
1671
+ * @param context - The resolved operation context with concrete chain and address values.
1518
1672
  * @returns A promise resolving to a prepared chain request.
1519
1673
  *
1520
1674
  * @example
1521
1675
  * ```typescript
1522
1676
  * import type { ActionHandler } from '@core/adapter'
1523
1677
  *
1524
- * const depositHandler: ActionHandler<'cctp.v2.depositForBurn'> = async (params) => {
1525
- * // Handler logic here
1678
+ * const depositHandler: ActionHandler<'cctp.v2.depositForBurn'> = async (params, context) => {
1679
+ * // context is always defined and has concrete chain and address values
1680
+ * console.log(context.chain.name);
1681
+ * console.log(context.address);
1682
+ * // ... handler logic ...
1683
+ * return preparedRequest;
1526
1684
  * }
1527
1685
  * ```
1528
1686
  */
1529
- type ActionHandler<TActionKey extends ActionKeys> = (params: ActionPayload<TActionKey>) => Promise<PreparedChainRequest>;
1687
+ type ActionHandler<TActionKey extends ActionKeys> = (params: ActionPayload<TActionKey>, context: ResolvedOperationContext) => Promise<PreparedChainRequest>;
1530
1688
  /**
1531
1689
  * Type-safe mapping of all available action keys to their corresponding handlers.
1532
1690
  *
@@ -1536,7 +1694,7 @@ type ActionHandler<TActionKey extends ActionKeys> = (params: ActionPayload<TActi
1536
1694
  * handler registration and lookup for all supported actions in the Stablecoin Kits.
1537
1695
  *
1538
1696
  * @remarks
1539
- * Each handler is typed as {@link ActionHandler<ActionKeys>}, which means the handler
1697
+ * Each handler is typed as {@link ActionHandler}, which means the handler
1540
1698
  * must accept the payload type for the specific action key it is registered under.
1541
1699
  * This provides type safety for handler registration and execution, but does not
1542
1700
  * enforce per-key handler parameterization at the type level. For stricter per-key
@@ -1548,12 +1706,14 @@ type ActionHandler<TActionKey extends ActionKeys> = (params: ActionPayload<TActi
1548
1706
  * import type { ActionHandler } from '@core/adapter'
1549
1707
  *
1550
1708
  * const handlers: ActionHandlers = {
1551
- * 'cctp.v2.depositForBurn': async (params) => {
1709
+ * 'cctp.v2.depositForBurn': async (params, resolved) => {
1552
1710
  * // params is correctly typed for 'cctp.v2.depositForBurn'
1711
+ * // resolved has concrete chain and address values
1553
1712
  * // ...handler logic...
1554
1713
  * },
1555
- * 'usdc.approve': async (params) => {
1714
+ * 'usdc.approve': async (params, resolved) => {
1556
1715
  * // params is correctly typed for 'usdc.approve'
1716
+ * // resolved has concrete chain and address values
1557
1717
  * // ...handler logic...
1558
1718
  * }
1559
1719
  * }
@@ -1591,8 +1751,8 @@ declare class ActionRegistry {
1591
1751
  * @param handler - The handler function for processing this action type.
1592
1752
  * @returns Void.
1593
1753
  *
1594
- * @throws {Error} When action parameter is not a valid string.
1595
- * @throws {TypeError} When handler parameter is not a function.
1754
+ * @throws Error When action parameter is not a valid string.
1755
+ * @throws TypeError When handler parameter is not a function.
1596
1756
  *
1597
1757
  * @example
1598
1758
  * ```typescript
@@ -1602,7 +1762,7 @@ declare class ActionRegistry {
1602
1762
  * const registry = new ActionRegistry()
1603
1763
  *
1604
1764
  * // Register a CCTP deposit handler
1605
- * const depositHandler: ActionHandler<'cctp.v2.depositForBurn'> = async (params) => {
1765
+ * const depositHandler: ActionHandler<'cctp.v2.depositForBurn'> = async (params, resolved) => {
1606
1766
  * console.log('Processing deposit:', params.amount)
1607
1767
  * return {
1608
1768
  * chainId: params.chainId,
@@ -1639,14 +1799,14 @@ declare class ActionRegistry {
1639
1799
  *
1640
1800
  * // Register multiple handlers at once
1641
1801
  * const tokenHandlers: ActionHandlers = {
1642
- * 'token.approve': async (params) => ({
1643
- * chainId: params.chainId,
1802
+ * 'token.approve': async (params, resolved) => ({
1803
+ * chainId: resolved.chain,
1644
1804
  * data: '0x095ea7b3...',
1645
1805
  * to: params.tokenAddress,
1646
1806
  * value: '0'
1647
1807
  * }),
1648
- * 'token.transfer': async (params) => ({
1649
- * chainId: params.chainId,
1808
+ * 'token.transfer': async (params, resolved) => ({
1809
+ * chainId: resolved.chain,
1650
1810
  * data: '0xa9059cbb...',
1651
1811
  * to: params.tokenAddress,
1652
1812
  * value: '0'
@@ -1698,13 +1858,14 @@ declare class ActionRegistry {
1698
1858
  * Execute a registered action handler with type-safe parameters.
1699
1859
  *
1700
1860
  * Look up and execute the handler associated with the given action key,
1701
- * passing the provided parameters and returning the resulting prepared
1861
+ * passing the provided parameters and context, returning the resulting prepared
1702
1862
  * chain request. TypeScript ensures the parameters match the expected
1703
1863
  * structure for the specified action.
1704
1864
  *
1705
1865
  * @typeParam TActionKey - The specific action key being executed.
1706
1866
  * @param action - The action key identifying which handler to execute.
1707
1867
  * @param params - The parameters to pass to the action handler.
1868
+ * @param context - The resolved operation context with concrete chain and address values.
1708
1869
  * @returns A promise resolving to the prepared chain request.
1709
1870
  *
1710
1871
  * @throws {Error} When action parameter is not a valid string.
@@ -1719,78 +1880,76 @@ declare class ActionRegistry {
1719
1880
  * const registry = new ActionRegistry()
1720
1881
  *
1721
1882
  * // First register a handler
1722
- * registry.registerHandler('token.approve', async (params) => ({
1723
- * chainId: params.chainId,
1883
+ * registry.registerHandler('token.approve', async (params, context) => ({
1884
+ * chainId: context.chain, // Always defined
1724
1885
  * data: '0x095ea7b3...',
1725
1886
  * to: params.tokenAddress,
1726
1887
  * value: '0'
1727
1888
  * }))
1728
1889
  *
1729
- * // Execute the action with type-safe parameters
1890
+ * // Execute the action with resolved context (typically called from adapter.prepareAction)
1891
+ * const resolvedContext = { chain: 'Base', address: '0x123...' }
1730
1892
  * const result = await registry.executeAction('token.approve', {
1731
1893
  * chainId: ChainEnum.Ethereum,
1732
1894
  * tokenAddress: '0xA0b86a33E6441c8C1c7C16e4c5e3e5b5e4c5e3e5b5e4c5e',
1733
1895
  * delegate: '0x1234567890123456789012345678901234567890',
1734
1896
  * amount: '1000000'
1735
- * })
1897
+ * }, resolvedContext)
1736
1898
  *
1737
1899
  * console.log('Transaction prepared:', result.data)
1738
1900
  * ```
1739
1901
  */
1740
- executeAction<TActionKey extends ActionKeys>(action: TActionKey, params: ActionPayload<TActionKey>): Promise<PreparedChainRequest>;
1902
+ executeAction<TActionKey extends ActionKeys>(action: TActionKey, params: ActionPayload<TActionKey>, context: ResolvedOperationContext): Promise<PreparedChainRequest>;
1741
1903
  }
1742
1904
 
1743
1905
  /**
1744
1906
  * Defines the capabilities of an adapter, including address handling patterns and supported chains.
1745
1907
  *
1746
- * @interface AdapterCapabilities
1908
+ * @interface TAdapterCapabilities
1747
1909
  * @category Types
1748
1910
  * @description
1749
- * This interface helps determine the behavior of an adapter, especially how it handles
1750
- * address resolution and chain operations. Different adapter types have different
1751
- * requirements for explicit context in operations.
1911
+ * This interface specifies how an adapter manages address control and which blockchain networks it supports.
1912
+ * It is used for capability discovery, validation, and to inform consumers about the adapter's operational model.
1913
+ *
1914
+ * The `addressContext` property determines both address selection behavior and bridge API requirements:
1915
+ * - `'user-controlled'`: User controls addresses through wallet UI, address optional in operations
1916
+ * - `'developer-controlled'`: Service manages addresses programmatically, address required in operations
1752
1917
  *
1753
1918
  * @example
1754
1919
  * ```typescript
1755
- * // Single address adapter (private key)
1920
+ * // Browser wallet adapter (user-controlled)
1756
1921
  * const capabilities: AdapterCapabilities = {
1757
- * addressContext: 'single',
1758
- * supportedChains: [Ethereum, Base, Polygon],
1759
- * availableAddresses: ['0x123...']
1922
+ * addressContext: 'user-controlled', // User selects address in wallet UI
1923
+ * supportedChains: [Ethereum, Base, Polygon]
1760
1924
  * }
1761
1925
  *
1762
- * // Multi-entity adapter (institutional)
1926
+ * // Enterprise provider adapter (developer-controlled)
1763
1927
  * const capabilities: AdapterCapabilities = {
1764
- * addressContext: 'multi-entity',
1765
- * supportedChains: [Ethereum, Base, Solana],
1766
- * availableAddresses: undefined // Too many to fetch
1928
+ * addressContext: 'developer-controlled', // Address must be specified per operation
1929
+ * supportedChains: [Ethereum, Base, Solana]
1767
1930
  * }
1768
1931
  * ```
1769
1932
  */
1770
1933
  interface AdapterCapabilities {
1771
1934
  /**
1772
- * Defines how the adapter handles addresses.
1935
+ * Defines who controls address selection for wallet operations.
1773
1936
  *
1774
- * - `'single'`: Adapter controls exactly one address (e.g., private key adapter)
1775
- * - `'user-accounts'`: Adapter controls user's personal addresses (e.g., MetaMask)
1776
- * - `'multi-entity'`: Adapter manages addresses for multiple entities (e.g., Circle Wallets)
1937
+ * - `'user-controlled'`: User controls addresses through wallet UI (browser wallets, hardware wallets)
1938
+ * - Address is implicit in bridge operations (uses wallet's current address)
1939
+ * - Adapter may listen for accountsChanged/chainChanged events
1940
+ * - Suitable for MetaMask, Coinbase Wallet, WalletConnect, private keys, etc.
1941
+ *
1942
+ * - `'developer-controlled'`: Service manages addresses programmatically (enterprise providers)
1943
+ * - Address must be explicitly provided in bridge operations
1944
+ * - No event listening (addresses controlled programmatically)
1945
+ * - Suitable for Fireblocks, Circle Wallets, institutional custody, etc.
1777
1946
  */
1778
- addressContext: 'single' | 'user-accounts' | 'multi-entity';
1947
+ addressContext: 'user-controlled' | 'developer-controlled';
1779
1948
  /**
1780
- * List of blockchain networks that this adapter can interact with.
1781
- * Used for validation and capability discovery.
1949
+ * The set of blockchain networks this adapter supports.
1950
+ * Used for validation, capability discovery, and to restrict operations to supported chains.
1782
1951
  */
1783
1952
  supportedChains: ChainDefinition[];
1784
- /**
1785
- * Available addresses for single and user-accounts adapters.
1786
- *
1787
- * - For `single` adapters: Contains exactly one address
1788
- * - For `user-accounts` adapters: Contains user's available addresses
1789
- * - For `multi-entity` adapters: Should be undefined (too many addresses to list)
1790
- *
1791
- * This is populated during adapter creation to avoid repeated network calls.
1792
- */
1793
- availableAddresses?: string[];
1794
1953
  }
1795
1954
  /**
1796
1955
  * Abstract class defining the standard interface for an adapter that interacts with a specific blockchain.
@@ -1801,63 +1960,41 @@ interface AdapterCapabilities {
1801
1960
  *
1802
1961
  * This abstraction allows the Stablecoin Kits to work with multiple blockchains in a uniform way.
1803
1962
  *
1963
+ * @typeParam TAdapterCapabilities - The adapter capabilities type for compile-time address validation.
1964
+ * When provided, enables strict typing of operation context based on the adapter's address control model.
1804
1965
  */
1805
- declare abstract class Adapter {
1966
+ declare abstract class Adapter<TAdapterCapabilities extends AdapterCapabilities = AdapterCapabilities> {
1806
1967
  /**
1807
1968
  * The type of the chain.
1808
1969
  * @example 'evm', 'solana'
1809
1970
  */
1810
1971
  abstract chainType: ChainType;
1811
1972
  /**
1812
- * Capabilities of this adapter, defining address handling patterns and supported chains.
1973
+ * Capabilities of this adapter, defining address control model and supported chains.
1813
1974
  *
1814
- * This property helps determine how the adapter behaves, especially for address resolution
1815
- * and chain operations. Different adapter types have different requirements for explicit
1816
- * context in operations.
1975
+ * This property determines how the adapter behaves, especially for address selection
1976
+ * and bridge API requirements. The `addressContext` must match the adapter's type parameter.
1817
1977
  *
1818
1978
  * @remarks
1819
- * This is optional for backward compatibility during the migration period.
1820
- * New adapters should always define this property.
1979
+ * The `addressContext` value must align with the adapter's generic type parameter for proper
1980
+ * type safety in bridge operations.
1821
1981
  *
1822
1982
  * @example
1823
1983
  * ```typescript
1824
- * // Private key adapter
1984
+ * // User-controlled adapter (private key, browser wallet)
1825
1985
  * capabilities = {
1826
- * addressContext: 'single',
1827
- * supportedChains: [Ethereum, Base],
1828
- * availableAddresses: ['0x123...']
1986
+ * addressContext: 'user-controlled', // Address implicit in bridge operations
1987
+ * supportedChains: [Ethereum, Base, Polygon]
1829
1988
  * }
1830
1989
  *
1831
- * // Browser wallet adapter
1990
+ * // Developer-controlled adapter (enterprise provider)
1832
1991
  * capabilities = {
1833
- * addressContext: 'user-accounts',
1834
- * supportedChains: [Ethereum, Base, Polygon],
1835
- * availableAddresses: ['0x123...', '0x456...']
1992
+ * addressContext: 'developer-controlled', // Address required in bridge operations
1993
+ * supportedChains: [Ethereum, Base, Solana]
1836
1994
  * }
1837
1995
  * ```
1838
1996
  */
1839
- capabilities?: AdapterCapabilities;
1840
- /**
1841
- * Default chain for operations when none is explicitly provided.
1842
- *
1843
- * This allows adapters to have sensible defaults for chain operations,
1844
- * reducing the need for explicit chain specification in every call.
1845
- * Multi-entity adapters typically don't have a default chain.
1846
- *
1847
- * @remarks
1848
- * This is optional for backward compatibility and because some adapter types
1849
- * (like multi-entity adapters) may not have meaningful defaults.
1850
- *
1851
- * @example
1852
- * ```typescript
1853
- * // Private key adapter with default chain
1854
- * defaultChain = Ethereum
1855
- *
1856
- * // Multi-entity adapter (no default)
1857
- * defaultChain = undefined
1858
- * ```
1859
- */
1860
- defaultChain?: ChainDefinition;
1997
+ capabilities?: TAdapterCapabilities;
1861
1998
  /**
1862
1999
  * Registry of available actions for this adapter.
1863
2000
  *
@@ -1877,6 +2014,12 @@ declare abstract class Adapter {
1877
2014
  * {@link PreparedChainRequest} allows developers to estimate gas costs and execute
1878
2015
  * the transaction at a later time, enabling pre-flight simulation and deferred execution.
1879
2016
  *
2017
+ * **Compile-time Address Validation**: When used with typed adapters that have capabilities,
2018
+ * this method enforces address requirements at compile time:
2019
+ * - **User-controlled adapters**: The `address` field is forbidden in the context
2020
+ * - **Developer-controlled adapters**: The `address` field is required in the context
2021
+ * - **Legacy adapters**: The `address` field remains optional for backward compatibility
2022
+ *
1880
2023
  * @remarks
1881
2024
  * This method does not send any transaction to the network. Instead, it returns a
1882
2025
  * prepared request object with `estimate()` and `execute()` methods, allowing
@@ -1884,9 +2027,30 @@ declare abstract class Adapter {
1884
2027
  *
1885
2028
  * @param action - The action key identifying which handler to use for preparation.
1886
2029
  * @param params - The parameters to pass to the action handler.
2030
+ * @param ctx - Operation context with compile-time validated address requirements based on adapter capabilities.
1887
2031
  * @returns A promise that resolves to a {@link PreparedChainRequest} for estimation and execution.
2032
+ * @throws Error If the specified action key does not correspond to a registered handler.
2033
+ * @throws Error If the provided parameters are invalid for the action.
2034
+ * @throws Error If the operation context cannot be resolved.
2035
+ *
2036
+ * @example
2037
+ * ```typescript
2038
+ * // User-controlled adapter (address forbidden)
2039
+ * const userAdapter: Adapter<{ addressContext: 'user-controlled', supportedChains: [] }>
2040
+ * await userAdapter.prepareAction('token.approve', params, {
2041
+ * chain: 'Ethereum'
2042
+ * // address: '0x123...' // ❌ TypeScript error: address not allowed
2043
+ * })
2044
+ *
2045
+ * // Developer-controlled adapter (address required)
2046
+ * const devAdapter: Adapter<{ addressContext: 'developer-controlled', supportedChains: [] }>
2047
+ * await devAdapter.prepareAction('token.approve', params, {
2048
+ * chain: 'Ethereum',
2049
+ * address: '0x123...' // ✅ Required for developer-controlled
2050
+ * })
2051
+ * ```
1888
2052
  */
1889
- prepareAction<TActionKey extends ActionKeys>(action: TActionKey, params: ActionPayload<TActionKey>): Promise<PreparedChainRequest>;
2053
+ prepareAction<TActionKey extends ActionKeys>(action: TActionKey, params: ActionPayload<TActionKey>, ctx?: OperationContext<TAdapterCapabilities>): Promise<PreparedChainRequest>;
1890
2054
  /**
1891
2055
  * Prepares a transaction for future gas estimation and execution.
1892
2056
  *
@@ -1899,6 +2063,12 @@ declare abstract class Adapter {
1899
2063
  * - `execute()`: Asynchronously executes the prepared transaction and returns a promise that resolves
1900
2064
  * with the transaction result (e.g., a transaction hash, receipt, or other chain-specific response).
1901
2065
  *
2066
+ * **Compile-time Address Validation**: When used with typed adapters that have capabilities,
2067
+ * this method enforces address requirements at compile time:
2068
+ * - **User-controlled adapters**: The `address` field is forbidden in the context
2069
+ * - **Developer-controlled adapters**: The `address` field is required in the context
2070
+ * - **Legacy adapters**: The `address` field remains optional for backward compatibility
2071
+ *
1902
2072
  * @remarks
1903
2073
  * The specific parameters for `prepare` might vary greatly between chain implementations.
1904
2074
  * Consider defining a generic type or a base type for `transactionRequest` if common patterns emerge,
@@ -1906,28 +2076,38 @@ declare abstract class Adapter {
1906
2076
  * For this abstract definition, we keep it parameter-less, assuming implementations will add specific
1907
2077
  * parameters as needed for their `prepare` method (e.g. `prepare(txDetails: MyChainTxDetails)`).
1908
2078
  *
2079
+ * @param params - The prepared chain request parameters for the specific blockchain.
2080
+ * @param ctx - Operation context with compile-time validated address requirements based on adapter capabilities.
1909
2081
  * @returns An object containing `estimate` and `execute` methods for the prepared transaction.
2082
+ *
2083
+ * @example
2084
+ * ```typescript
2085
+ * // User-controlled adapter (address forbidden)
2086
+ * const userAdapter: Adapter<{ addressContext: 'user-controlled', supportedChains: [] }>
2087
+ * await userAdapter.prepare(params, {
2088
+ * chain: 'Ethereum'
2089
+ * // address: '0x123...' // ❌ TypeScript error: address not allowed
2090
+ * })
2091
+ *
2092
+ * // Developer-controlled adapter (address required)
2093
+ * const devAdapter: Adapter<{ addressContext: 'developer-controlled', supportedChains: [] }>
2094
+ * await devAdapter.prepare(params, {
2095
+ * chain: 'Ethereum',
2096
+ * address: '0x123...' // ✅ Required for developer-controlled
2097
+ * })
2098
+ * ```
1910
2099
  */
1911
- abstract prepare(params: PreparedChainRequestParams): Promise<PreparedChainRequest>;
2100
+ abstract prepare(params: PreparedChainRequestParams, ctx: OperationContext<TAdapterCapabilities>): Promise<PreparedChainRequest>;
1912
2101
  /**
1913
2102
  * Retrieves the public address of the connected wallet.
1914
2103
  *
1915
2104
  * This address is used as the default sender for transactions
1916
2105
  * and interactions initiated by this adapter.
1917
2106
  *
2107
+ * @param chain - Optional chain definition for chain-specific address resolution (used by EVM adapters)
1918
2108
  * @returns A promise that resolves to the blockchain address as a string.
1919
2109
  */
1920
- abstract getAddress(): Promise<string>;
1921
- /**
1922
- * Retrieves the {@link ChainDefinition} object that describes the blockchain
1923
- * this adapter is configured to interact with.
1924
- *
1925
- * This includes information such as the chain ID, name, native currency, etc.,
1926
- * as defined by the `ChainDefinition` type.
1927
- *
1928
- * @returns A promise that resolves to the {@link ChainDefinition} for the current chain.
1929
- */
1930
- abstract getChain(): Promise<ChainDefinition>;
2110
+ abstract getAddress(chain?: ChainDefinition): Promise<string>;
1931
2111
  /**
1932
2112
  * Switches the adapter to operate on the specified chain.
1933
2113
  *
@@ -1972,17 +2152,14 @@ declare abstract class Adapter {
1972
2152
  * - **Browser wallet adapters**: Request chain switch via EIP-1193 or equivalent
1973
2153
  * - **Multi-entity adapters**: Validate chain support (operations are contextual)
1974
2154
  *
1975
- * @param chain - The target chain for operations. If not provided, uses the adapter's defaultChain.
2155
+ * @param chain - The target chain for operations.
1976
2156
  * @returns A promise that resolves when the adapter is operating on the specified chain.
1977
2157
  * @throws When the target chain is not supported or chain switching fails.
1978
2158
  *
1979
2159
  * @remarks
1980
- * This method replaces the pattern of calling `getChain()` to check current chain and then
1981
- * manually switching. It provides a declarative "ensure this chain" interface for operations.
1982
- *
1983
- * **Backward Compatibility**: The default implementation provides basic validation but
1984
- * doesn't perform actual chain switching. Concrete adapter implementations should override
1985
- * this method to provide proper chain switching logic.
2160
+ * This method always calls `switchToChain()` to ensure consistency across all adapter types.
2161
+ * The underlying implementations handle idempotent switching efficiently (e.g., browser wallets
2162
+ * gracefully handle switching to the current chain, private key adapters recreate lightweight clients).
1986
2163
  *
1987
2164
  * @example
1988
2165
  * ```typescript
@@ -1996,7 +2173,7 @@ declare abstract class Adapter {
1996
2173
  * await circleWalletsAdapter.ensureChain(Ethereum)
1997
2174
  * ```
1998
2175
  */
1999
- ensureChain(chain?: ChainDefinition): Promise<void>;
2176
+ ensureChain(targetChain: ChainDefinition): Promise<void>;
2000
2177
  /**
2001
2178
  * Validate that the target chain is supported by this adapter.
2002
2179
  *
@@ -2012,9 +2189,10 @@ declare abstract class Adapter {
2012
2189
  *
2013
2190
  * @param txHash - The hash of the transaction to wait for.
2014
2191
  * @param config - Optional configuration for waiting behavior including timeout and confirmations.
2192
+ * @param chain - The chain definition where the transaction was submitted.
2015
2193
  * @returns Promise resolving to comprehensive transaction details.
2016
2194
  */
2017
- abstract waitForTransaction(txHash: string, config?: WaitForTransactionConfig): Promise<WaitForTransactionResponse>;
2195
+ abstract waitForTransaction(txHash: string, config: WaitForTransactionConfig | undefined, chain: ChainDefinition): Promise<WaitForTransactionResponse>;
2018
2196
  /**
2019
2197
  * Calculate the total transaction fee including compute cost and buffer for the configured chain.
2020
2198
  *
@@ -2024,11 +2202,25 @@ declare abstract class Adapter {
2024
2202
  *
2025
2203
  * @param baseComputeUnits - The base compute units for the transaction (gas for EVM, compute units for Solana, etc.).
2026
2204
  * @param bufferBasisPoints - The buffer to add as basis points (e.g., 500 = 5%). Defaults to implementation-specific value.
2205
+ * @param chain - The chain definition to calculate fees for.
2027
2206
  * @returns A promise that resolves to the total transaction fee as a bigint.
2028
2207
  */
2029
- abstract calculateTransactionFee(baseComputeUnits: bigint, bufferBasisPoints?: bigint): Promise<EstimatedGas>;
2208
+ abstract calculateTransactionFee(baseComputeUnits: bigint, bufferBasisPoints: bigint | undefined, chain: ChainDefinition): Promise<EstimatedGas>;
2030
2209
  }
2031
2210
 
2211
+ /**
2212
+ * Type utility that infers the final adapter capabilities from partial overrides.
2213
+ * This provides clean type inference without complex conditional types.
2214
+ */
2215
+ type InferAdapterCapabilities<T extends Partial<AdapterCapabilities>> = T & {
2216
+ addressContext: T extends {
2217
+ addressContext: infer A;
2218
+ } ? A : 'user-controlled';
2219
+ supportedChains: T extends {
2220
+ supportedChains: infer S;
2221
+ } ? S : ChainDefinition[];
2222
+ };
2223
+
2032
2224
  /**
2033
2225
  * EIP-712 domain structure for typed data signing.
2034
2226
  *
@@ -2160,12 +2352,19 @@ interface ReadContractParams {
2160
2352
  * The signTypedData method uses a generic TypedData interface from the signTypedData module,
2161
2353
  * making it compatible with any EIP-712 standard (EIP-2612, EIP-7597, ERC-3009, etc.) while
2162
2354
  * maintaining type safety throughout the signing process.
2355
+ *
2356
+ * Includes caching and synchronization capabilities for provider-based adapters that need
2357
+ * to respond to account and chain changes from external wallets (e.g., MetaMask).
2163
2358
  */
2164
- declare abstract class EvmAdapter extends Adapter {
2359
+ declare abstract class EvmAdapter<TAdapterCapabilities extends AdapterCapabilities = AdapterCapabilities> extends Adapter<TAdapterCapabilities> {
2165
2360
  /**
2166
2361
  * The type of chain this adapter is for.
2167
2362
  */
2168
2363
  chainType: ChainType;
2364
+ /**
2365
+ * Cached gas price for the current network.
2366
+ */
2367
+ cachedGasPrice?: bigint;
2169
2368
  /**
2170
2369
  * The constructor for the EVM adapter.
2171
2370
  *
@@ -2183,8 +2382,10 @@ declare abstract class EvmAdapter extends Adapter {
2183
2382
  * @typeParam Types - The EIP-712 types definition for the standard being signed
2184
2383
  * @typeParam Message - The message structure for the standard being signed
2185
2384
  * @param typedData - The EIP-712 typed data to sign with full type safety
2385
+ * @param ctx - Required operation context specifying the chain and address for this operation
2186
2386
  * @returns Promise resolving to the signature as a hex string
2187
2387
  * @throws Error when the wallet client is not available or signing fails
2388
+ * @throws Error when OperationContext resolution fails
2188
2389
  *
2189
2390
  * @example
2190
2391
  * ```typescript
@@ -2192,10 +2393,12 @@ declare abstract class EvmAdapter extends Adapter {
2192
2393
  * import { buildEIP2612TypedData } from '@core/adapter-evm'
2193
2394
  *
2194
2395
  * const typedData = await buildEIP2612TypedData(meta, adapter, options)
2195
- * const signature = await adapter.signTypedData(typedData)
2396
+ * const signature = await adapter.signTypedData(typedData, {
2397
+ * chain: 'Base' // Chain specified in context
2398
+ * })
2196
2399
  * ```
2197
2400
  */
2198
- abstract signTypedData<Types extends Record<string, TypedDataField[]>, Message extends Record<string, unknown>>(typedData: TypedData<Types, Message>): Promise<`0x${string}`>;
2401
+ abstract signTypedData<Types extends Record<string, TypedDataField[]>, Message extends Record<string, unknown>>(typedData: TypedData<Types, Message>, ctx: OperationContext<TAdapterCapabilities>): Promise<`0x${string}`>;
2199
2402
  /**
2200
2403
  * Fetches the current EIP-2612 nonce for a token owner.
2201
2404
  *
@@ -2217,15 +2420,59 @@ declare abstract class EvmAdapter extends Adapter {
2217
2420
  * )
2218
2421
  * ```
2219
2422
  */
2220
- fetchEIP2612Nonce(tokenAddress: `0x${string}`, ownerAddress: `0x${string}`): Promise<bigint>;
2423
+ fetchEIP2612Nonce(tokenAddress: `0x${string}`, ownerAddress: `0x${string}`, ctx: OperationContext<TAdapterCapabilities>): Promise<bigint>;
2221
2424
  /**
2222
2425
  * Read a contract function.
2223
2426
  *
2224
2427
  * @typeParam TReturnType - The expected return type of the contract function.
2225
2428
  * @param params - The parameters for the contract function read.
2429
+ * @param chain - The chain definition where the contract is deployed.
2226
2430
  * @returns A promise that resolves to the result of the contract function read.
2227
2431
  */
2228
- abstract readContract<TReturnType = unknown>(params: ReadContractParams): Promise<TReturnType>;
2432
+ abstract readContract<TReturnType = unknown>(params: ReadContractParams, chain: EVMChainDefinition): Promise<TReturnType>;
2433
+ /**
2434
+ * Fetches the current gas price from the network, bypassing cache.
2435
+ *
2436
+ * This abstract method must be implemented by concrete adapters to fetch
2437
+ * the current gas price using their specific client libraries. This method
2438
+ * should not implement caching - caching is handled by the base class.
2439
+ *
2440
+ * @param chain - The chain definition to fetch gas price for.
2441
+ * @returns Promise resolving to the current gas price in wei
2442
+ * @throws Error when gas price retrieval fails
2443
+ */
2444
+ abstract fetchGasPrice(chain: EVMChainDefinition): Promise<bigint>;
2445
+ /**
2446
+ * Calculate the total transaction fee including compute cost and buffer for the configured chain.
2447
+ *
2448
+ * This method computes the fee by multiplying the estimated compute units by the
2449
+ * current gas price, then adds a configurable buffer to account for fee fluctuations
2450
+ * and ensure transaction success. The buffer is specified in basis points (1 basis
2451
+ * point = 0.01%).
2452
+ *
2453
+ * @param baseComputeUnits - The base compute units for the transaction.
2454
+ * @param bufferBasisPoints - The buffer to add as basis points (e.g., 500 = 5%). Defaults to DEFAULT_BUFFER_BASIS_POINTS (5%).
2455
+ * @param chain - The chain definition to fetch gas price for.
2456
+ * @returns A promise that resolves to the estimated gas cost including buffer.
2457
+ * @throws Error when gas price retrieval fails.
2458
+ *
2459
+ * @example
2460
+ * ```typescript
2461
+ * import { ViemAdapter } from '@circle-fin/adapter-viem-v2'
2462
+ * import { Ethereum } from '@core/chains'
2463
+ *
2464
+ * const adapter = new ViemAdapter({ publicClient, walletClient })
2465
+ *
2466
+ * // Calculate transaction fee with default 5% buffer
2467
+ * const fee = await adapter.calculateTransactionFee(1000000000n, undefined, Ethereum)
2468
+ * console.log('Transaction fee:', fee.toString(), 'wei')
2469
+ *
2470
+ * // Calculate transaction fee with custom 10% buffer
2471
+ * const feeWithCustomBuffer = await adapter.calculateTransactionFee(1000000000n, 1000n, Ethereum)
2472
+ * console.log('Transaction fee with custom buffer:', feeWithCustomBuffer.toString(), 'wei')
2473
+ * ```
2474
+ */
2475
+ calculateTransactionFee(baseComputeUnits: bigint, bufferBasisPoints: bigint | undefined, chain: EVMChainDefinition): Promise<EstimatedGas>;
2229
2476
  }
2230
2477
 
2231
2478
  /**
@@ -2234,7 +2481,7 @@ declare abstract class EvmAdapter extends Adapter {
2234
2481
  *
2235
2482
  * A concrete EVM adapter implementation backed by the `ethers` library.
2236
2483
  * It provides functionality for gas estimation, contract interaction,
2237
- * and transaction execution.
2484
+ * and transaction execution with explicit capabilities and OperationContext support.
2238
2485
  */
2239
2486
  /**
2240
2487
  * Direct client configuration for EthersAdapter using pre-configured Ethers.js clients.
@@ -2262,31 +2509,81 @@ interface EthersAdapterOptions {
2262
2509
  signer: Signer$1;
2263
2510
  }
2264
2511
  /**
2265
- * Creates a new EthersAdapter instance.
2512
+ * Creates a new EthersAdapter instance with explicit capabilities and OperationContext support.
2266
2513
  *
2267
- * @param options - Configuration options for the adapter.
2514
+ * This constructor is typically not called directly. Instead, use the factory functions
2515
+ * {@link createAdapterFromPrivateKey} or {@link createAdapterFromProvider} which provide
2516
+ * smart defaults and better developer experience.
2517
+ *
2518
+ * @remarks
2519
+ * The constructor requires both configuration options and explicit capabilities to ensure
2520
+ * consistent behavior across all EVM adapters following the OperationContext pattern.
2521
+ *
2522
+ * **Capabilities Configuration:**
2523
+ * - `addressContext`: Defines address control model (`'user-controlled'` or `'developer-controlled'`)
2524
+ * - `supportedChains`: Array of EVM chains this adapter can operate on
2525
+ *
2526
+ * **Factory Functions (Recommended):**
2527
+ * - {@link createAdapterFromPrivateKey} - For server-side/programmatic use with private keys
2528
+ * - {@link createAdapterFromProvider} - For browser wallets (MetaMask, WalletConnect, etc.)
2529
+ *
2530
+ * @param options - Configuration options including provider getter and signer
2531
+ * @param capabilities - Adapter capabilities defining address control and supported chains
2532
+ *
2533
+ * @example
2534
+ * ```typescript
2535
+ * import { EthersAdapter } from '@circle-fin/adapter-ethers-v6'
2536
+ * import { Wallet, JsonRpcProvider } from 'ethers'
2537
+ * import { Ethereum, Base } from '@core/chains'
2538
+ *
2539
+ * // Direct construction (advanced usage)
2540
+ * const adapter = new EthersAdapter({
2541
+ * getProvider: ({ chain }) => new JsonRpcProvider('https://...'),
2542
+ * signer: new Wallet('0x...', new JsonRpcProvider('https://...'))
2543
+ * }, {
2544
+ * addressContext: 'user-controlled',
2545
+ * supportedChains: [Ethereum, Base]
2546
+ * })
2547
+ * ```
2548
+ *
2549
+ * @example
2550
+ * ```typescript
2551
+ * // Recommended: Use factory functions instead
2552
+ * import { createAdapterFromPrivateKey } from '@circle-fin/adapter-ethers-v6'
2553
+ *
2554
+ * // Minimal configuration with default capabilities
2555
+ * const adapter = createAdapterFromPrivateKey({
2556
+ * privateKey: '0x...'
2557
+ * // Defaults: user-controlled + all EVM chains
2558
+ * })
2559
+ * ```
2268
2560
  */
2269
- declare class EthersAdapter extends EvmAdapter {
2561
+ declare class EthersAdapter<TAdapterCapabilities extends AdapterCapabilities = AdapterCapabilities> extends EvmAdapter<TAdapterCapabilities> {
2270
2562
  /** The configuration options for this adapter instance. */
2271
2563
  options: EthersAdapterOptions;
2272
2564
  /** Cached Ethers Signer instance. */
2273
2565
  private _signer;
2274
- /** Cached address of the connected wallet. */
2275
- private cachedAddress?;
2276
2566
  /** Cached providers for different chains. */
2277
2567
  private readonly cachedProviders;
2278
- /** Cached gas price for the current network. */
2279
- private cachedGasPrice?;
2280
- /** Cached chain definition for the connected provider. */
2281
- private cachedChain;
2282
- /** The resolved chain definition that this adapter was created for. */
2283
- private resolvedChain;
2284
- constructor(options: EthersAdapterOptions);
2568
+ constructor(options: EthersAdapterOptions, capabilities: TAdapterCapabilities);
2285
2569
  /**
2286
- * Sets the resolved chain for this adapter.
2287
- * @internal
2570
+ * Resets all cached state in the adapter, including Ethers-specific caches.
2571
+ *
2572
+ * This method extends the base class resetState() to also clear Ethers-specific
2573
+ * caches like providers and gas prices. It ensures a clean state when
2574
+ * the adapter needs to be reinitialized (e.g., after chain or account changes).
2575
+ *
2576
+ * @override
2577
+ * @example
2578
+ * ```typescript
2579
+ * // Called automatically during chain switches or account changes
2580
+ * adapter.resetState()
2581
+ *
2582
+ * // Or called manually to clear all caches
2583
+ * adapter.resetState()
2584
+ * ```
2288
2585
  */
2289
- setResolvedChain(chain: EVMChainDefinition): void;
2586
+ resetState(): void;
2290
2587
  /**
2291
2588
  * Switches the adapter to operate on the specified chain.
2292
2589
  *
@@ -2300,8 +2597,21 @@ declare class EthersAdapter extends EvmAdapter {
2300
2597
  switchToChain(chain: ChainDefinition): Promise<void>;
2301
2598
  /**
2302
2599
  * Gets the cached Provider or initializes it from options if not already cached.
2600
+ *
2601
+ * @param chain - The chain definition for which to get the Provider (required).
2602
+ * @returns The Ethers Provider instance.
2603
+ * @remarks
2604
+ * This method ensures we only store one instance of the Provider per chain.
2605
+ * The chain parameter is required to prevent accidentally using the wrong chain,
2606
+ * which could lead to serious issues and real costs for users.
2607
+ * @example
2608
+ * ```typescript
2609
+ * const adapter = new EthersAdapter(options, capabilities);
2610
+ * const provider = await adapter.getProvider(Ethereum);
2611
+ * const blockNumber = await provider.getBlockNumber();
2612
+ * ```
2303
2613
  */
2304
- getProvider(chain?: EVMChainDefinition): Promise<Provider>;
2614
+ getProvider(chain: EVMChainDefinition): Promise<Provider>;
2305
2615
  /** Gets the current Signer instance used by the adapter. */
2306
2616
  getSigner(): Signer$1;
2307
2617
  /**
@@ -2314,225 +2624,498 @@ declare class EthersAdapter extends EvmAdapter {
2314
2624
  private simulateFunctionCall;
2315
2625
  /**
2316
2626
  * Estimates the gas required for executing a contract function call.
2627
+ *
2628
+ * @param contract - The contract instance to estimate gas for.
2629
+ * @param functionName - The name of the contract function.
2630
+ * @param args - The arguments to pass to the contract function.
2631
+ * @param chain - The chain definition to use for gas price retrieval (prevents race conditions).
2632
+ * @param overrides - Optional estimate overrides.
2633
+ * @returns Promise resolving to the estimated gas, gas price, and total fee.
2317
2634
  */
2318
2635
  private estimateGasForFunction;
2319
2636
  /**
2320
2637
  * Executes a contract function as a transaction on the blockchain.
2638
+ *
2639
+ * @remarks
2640
+ * This method executes a transaction on the blockchain.
2641
+ * - If `overrides.nonce` is provided, it is used verbatim and local allocation is skipped.
2642
+ * - Otherwise, allocates the next process-local nonce for (chainId, fromAddress) to avoid
2643
+ * collisions under concurrent sends.
2644
+ * - On common nonce errors (e.g., "nonce too low", "already known", "replacement fee too low"),
2645
+ * re-syncs from provider pending nonce and retries once with a freshly allocated nonce.
2646
+ *
2647
+ * @param contract - The contract instance to execute the function on.
2648
+ * @param functionName - The name of the contract function to execute.
2649
+ * @param args - The arguments to pass to the contract function.
2650
+ * @param fromAddress - The address to send the transaction from (prevents race conditions).
2651
+ * @param chain - The chain definition to use for this operation (prevents race conditions).
2652
+ * @param overrides - Optional transaction overrides including nonce, gas settings, etc.
2653
+ * @returns The transaction hash as a hex string.
2654
+ *
2655
+ * @throws When the contract function is not found or callable.
2656
+ * @throws When transaction population fails.
2657
+ * @throws When transaction execution fails after retry attempts.
2321
2658
  */
2322
2659
  private executeTransaction;
2323
2660
  /**
2324
- * Prepares a chain request for execution.
2661
+ * Prepares a contract function call for gas estimation and execution with OperationContext.
2662
+ *
2663
+ * This method follows the OperationContext approach, requiring explicit chain specification
2664
+ * for every operation. The chain is provided via the required OperationContext parameter,
2665
+ * enabling seamless multi-chain operations with a single adapter instance.
2666
+ *
2667
+ * @remarks
2668
+ * **Operation Flow:**
2669
+ * 1. Validates parameters and resolves chain from OperationContext
2670
+ * 2. Switches adapter to target chain if necessary
2671
+ * 3. Resolves address based on adapter's addressContext capability
2672
+ * 4. Creates contract instance and simulates the function call
2673
+ * 5. Returns prepared request with `estimate()` and `execute()` methods
2674
+ *
2675
+ * **Address Resolution:**
2676
+ * - `'user-controlled'`: Address automatically resolved from connected signer
2677
+ * - `'developer-controlled'`: Address must be provided explicitly in OperationContext
2678
+ *
2679
+ * **Read-Only Functions:**
2680
+ * View and pure functions are automatically detected and handled with noop gas estimation.
2681
+ *
2682
+ * @param params - The EVM contract function call parameters
2683
+ * @param ctx - Required operation context specifying the chain for this operation
2684
+ * @returns A promise that resolves to a prepared chain request for estimation and execution
2685
+ * @throws Error when parameters are invalid or function simulation fails
2686
+ * @throws Error when OperationContext resolution fails
2687
+ *
2688
+ * @example
2689
+ * ```typescript
2690
+ * import { createAdapterFromPrivateKey } from '@circle-fin/adapter-ethers-v6'
2691
+ * import { parseAbi } from 'ethers'
2692
+ *
2693
+ * const adapter = createAdapterFromPrivateKey({
2694
+ * privateKey: process.env.PRIVATE_KEY
2695
+ * })
2696
+ *
2697
+ * // Basic usage - OperationContext specifies the chain
2698
+ * const prepared = await adapter.prepare({
2699
+ * address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC on Ethereum
2700
+ * abi: parseAbi(['function transfer(address to, uint256 amount) returns (bool)']),
2701
+ * functionName: 'transfer',
2702
+ * args: ['0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb', '1000000']
2703
+ * }, { chain: 'Ethereum' }) // Chain specified in context
2704
+ *
2705
+ * // Estimate gas
2706
+ * const gasEstimate = await prepared.estimate()
2707
+ * console.log('Estimated gas:', gasEstimate.gas)
2708
+ *
2709
+ * // Execute transaction
2710
+ * const txHash = await prepared.execute()
2711
+ * console.log('Transaction hash:', txHash)
2712
+ * ```
2713
+ *
2714
+ * @example
2715
+ * ```typescript
2716
+ * // Multi-chain usage with same adapter instance
2717
+ * const adapter = createAdapterFromPrivateKey({
2718
+ * privateKey: process.env.PRIVATE_KEY
2719
+ * })
2720
+ *
2721
+ * // Transfer USDC on Ethereum
2722
+ * const preparedEthereum = await adapter.prepare({
2723
+ * address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
2724
+ * abi: usdcAbi,
2725
+ * functionName: 'transfer',
2726
+ * args: ['0xrecipient', '1000000']
2727
+ * }, { chain: 'Ethereum' })
2728
+ *
2729
+ * // Transfer USDC on Base using the same adapter
2730
+ * const preparedBase = await adapter.prepare({
2731
+ * address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
2732
+ * abi: usdcAbi,
2733
+ * functionName: 'transfer',
2734
+ * args: ['0xrecipient', '1000000']
2735
+ * }, { chain: 'Base' })
2736
+ *
2737
+ * // Execute both transfers
2738
+ * await preparedEthereum.execute()
2739
+ * await preparedBase.execute()
2740
+ * ```
2741
+ *
2742
+ * @example
2743
+ * ```typescript
2744
+ * // Address resolution patterns
2745
+ * import { createAdapterFromProvider } from '@circle-fin/adapter-ethers-v6'
2746
+ *
2747
+ * const adapter = await createAdapterFromProvider({
2748
+ * provider: window.ethereum
2749
+ * // Defaults to user-controlled address context
2750
+ * })
2751
+ *
2752
+ * // Address is automatically resolved from the signer
2753
+ * const prepared = await adapter.prepare({
2754
+ * address: '0xcontract',
2755
+ * abi: contractAbi,
2756
+ * functionName: 'approve',
2757
+ * args: ['0xspender', '1000000']
2758
+ * }, {
2759
+ * chain: 'Polygon'
2760
+ * // No need to specify 'address' - comes from signer automatically
2761
+ * })
2762
+ * ```
2763
+ *
2764
+ * @example
2765
+ * ```typescript
2766
+ * // Read-only functions (view/pure) - automatic noop estimation
2767
+ * const prepared = await adapter.prepare({
2768
+ * address: '0xcontract',
2769
+ * abi: parseAbi(['function balanceOf(address account) view returns (uint256)']),
2770
+ * functionName: 'balanceOf',
2771
+ * args: ['0xaccount']
2772
+ * }, { chain: 'Ethereum' })
2773
+ *
2774
+ * // estimate() returns noop for read-only functions
2775
+ * const estimate = await prepared.estimate() // { gas: 0n, fee: '0', gasPrice: 0n }
2776
+ *
2777
+ * // execute() returns the result as a string
2778
+ * const balance = await prepared.execute() // '1000000'
2779
+ * ```
2780
+ */
2781
+ prepare(params: EvmPreparedChainRequestParams, ctx: OperationContext<TAdapterCapabilities>): Promise<EvmPreparedChainRequest>;
2782
+ /**
2783
+ * Gets the address associated with this adapter.
2784
+ *
2785
+ * @remarks
2786
+ * This method is primarily used internally by the OperationContext resolution system.
2787
+ * In user-facing code, addresses are typically resolved automatically based on the
2788
+ * adapter's addressContext capability.
2789
+ *
2790
+ * **With OperationContext Pattern:**
2791
+ * - The chain parameter is provided automatically by `resolveOperationContext()`
2792
+ * - For `'user-controlled'` adapters: address is derived from the signer/wallet
2793
+ * - For `'developer-controlled'` adapters: address must be provided explicitly in context
2794
+ *
2795
+ * **Implementation Note:**
2796
+ * While the chain parameter is typed as optional for compatibility with the base
2797
+ * adapter interface, it is effectively required and enforced at runtime. This ensures
2798
+ * the adapter is connected to the correct chain before querying the signer.
2799
+ *
2800
+ * @param chain - The chain to use for address resolution (provided by OperationContext)
2801
+ * @returns A promise that resolves to the signer's address
2802
+ * @throws Error when no chain is provided
2803
+ *
2804
+ * @example
2805
+ * ```typescript
2806
+ * import { Ethereum } from '@core/chains'
2807
+ *
2808
+ * // Typically called internally by resolveOperationContext
2809
+ * const address = await adapter.getAddress(Ethereum)
2810
+ * console.log('Wallet address:', address)
2811
+ * ```
2812
+ *
2813
+ * @example
2814
+ * ```typescript
2815
+ * // In practice, address resolution happens automatically
2816
+ * const prepared = await adapter.prepare(params, {
2817
+ * chain: 'Ethereum'
2818
+ * // Address automatically resolved via getAddress() internally
2819
+ * })
2820
+ * ```
2325
2821
  */
2326
- prepare(params: EvmPreparedChainRequestParams): Promise<EvmPreparedChainRequest>;
2327
- /** Gets the address of the connected wallet. */
2328
- getAddress(): Promise<string>;
2329
- /** Gets the current chain definition. */
2330
- getChain(): Promise<ChainDefinition>;
2822
+ getAddress(chain?: EVMChainDefinition): Promise<string>;
2331
2823
  /**
2332
2824
  * Waits for a transaction to be mined and confirmed on the blockchain.
2825
+ *
2826
+ * @param txHash - The transaction hash to wait for.
2827
+ * @param config - Optional configuration for confirmations and timeout.
2828
+ * @param chain - The chain definition where the transaction was submitted.
2829
+ * @returns Promise resolving to the transaction receipt details.
2830
+ * @throws Error when transaction is not found or times out.
2333
2831
  */
2334
- waitForTransaction(txHash: string, config?: WaitForTransactionConfig): Promise<WaitForTransactionResponse>;
2832
+ waitForTransaction(txHash: string, config: WaitForTransactionConfig | undefined, chain: EVMChainDefinition): Promise<WaitForTransactionResponse>;
2335
2833
  /**
2336
- * Calculate the total transaction fee including compute cost and buffer for the configured chain.
2834
+ * Fetches the current gas price from the network.
2835
+ *
2836
+ * @param chain - The chain definition to fetch gas price for.
2837
+ * @returns Promise resolving to the current gas price in wei
2838
+ * @throws Error when gas price retrieval fails
2839
+ */
2840
+ fetchGasPrice(chain: EVMChainDefinition): Promise<bigint>;
2841
+ /**
2842
+ * Signs EIP-712 typed data using the configured signer with OperationContext.
2843
+ *
2844
+ * This method signs structured typed data following the EIP-712 standard, enabling
2845
+ * secure off-chain signatures for permit approvals, meta-transactions, and other
2846
+ * gasless operations. The chain must be specified via the required OperationContext
2847
+ * parameter to ensure signatures are valid for the correct network.
2848
+ *
2849
+ * @remarks
2850
+ * **Operation Flow:**
2851
+ * 1. Validates the typed data structure
2852
+ * 2. Resolves chain from OperationContext and switches if necessary
2853
+ * 3. Resolves signer address based on adapter's addressContext
2854
+ * 4. Signs the typed data using the configured signer
2855
+ * 5. Returns the signature as a hex string
2856
+ *
2857
+ * **Use Cases:**
2858
+ * - ERC-2612 permit approvals (gasless token approvals)
2859
+ * - Meta-transactions and gasless operations
2860
+ * - Off-chain order signing for DEX protocols
2861
+ * - DAO voting signatures
2862
+ *
2863
+ * @typeParam Types - The EIP-712 types definition for the data being signed
2864
+ * @typeParam Message - The message structure being signed
2865
+ * @param typedData - The EIP-712 typed data to sign with full type safety
2866
+ * @param ctx - Required operation context specifying the chain for this operation
2867
+ * @returns Promise resolving to the signature as a hex string
2868
+ * @throws Error when typedData validation fails
2869
+ * @throws Error when no signer is configured
2870
+ * @throws Error when OperationContext resolution fails
2871
+ *
2872
+ * @example
2873
+ * ```typescript
2874
+ * import { createAdapterFromPrivateKey } from '@circle-fin/adapter-ethers-v6'
2875
+ *
2876
+ * const adapter = createAdapterFromPrivateKey({
2877
+ * privateKey: process.env.PRIVATE_KEY
2878
+ * })
2879
+ *
2880
+ * // Sign ERC-2612 permit (gasless token approval)
2881
+ * const signature = await adapter.signTypedData({
2882
+ * domain: {
2883
+ * name: 'USD Coin',
2884
+ * version: '2',
2885
+ * chainId: 1,
2886
+ * verifyingContract: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'
2887
+ * },
2888
+ * types: {
2889
+ * Permit: [
2890
+ * { name: 'owner', type: 'address' },
2891
+ * { name: 'spender', type: 'address' },
2892
+ * { name: 'value', type: 'uint256' },
2893
+ * { name: 'nonce', type: 'uint256' },
2894
+ * { name: 'deadline', type: 'uint256' }
2895
+ * ]
2896
+ * },
2897
+ * primaryType: 'Permit',
2898
+ * message: {
2899
+ * owner: '0xowner',
2900
+ * spender: '0xspender',
2901
+ * value: '1000000',
2902
+ * nonce: '0',
2903
+ * deadline: '1735689600'
2904
+ * }
2905
+ * }, { chain: 'Ethereum' }) // Chain must be specified
2906
+ *
2907
+ * console.log('Signature:', signature)
2908
+ * // '0x...' - can be used for permit approval
2909
+ * ```
2910
+ *
2911
+ * @example
2912
+ * ```typescript
2913
+ * // Multi-chain permit signing with same adapter
2914
+ * const adapter = createAdapterFromPrivateKey({
2915
+ * privateKey: process.env.PRIVATE_KEY
2916
+ * })
2917
+ *
2918
+ * // Sign permit for USDC on Ethereum
2919
+ * const ethSignature = await adapter.signTypedData(permitData, {
2920
+ * chain: 'Ethereum'
2921
+ * })
2922
+ *
2923
+ * // Sign permit for USDC on Base - same adapter!
2924
+ * const baseSignature = await adapter.signTypedData(permitData, {
2925
+ * chain: 'Base'
2926
+ * })
2927
+ * ```
2928
+ *
2929
+ * @example
2930
+ * ```typescript
2931
+ * // Browser wallet usage
2932
+ * import { createAdapterFromProvider } from '@circle-fin/adapter-ethers-v6'
2933
+ *
2934
+ * const adapter = await createAdapterFromProvider({
2935
+ * provider: window.ethereum
2936
+ * })
2937
+ *
2938
+ * // User will see signature request in wallet
2939
+ * const signature = await adapter.signTypedData(typedData, {
2940
+ * chain: 'Polygon'
2941
+ * })
2942
+ * ```
2337
2943
  */
2338
- calculateTransactionFee(baseComputeUnits: bigint, bufferBasisPoints?: bigint): Promise<EstimatedGas>;
2944
+ signTypedData<Types extends Record<string, TypedDataField[]>, Message extends Record<string, unknown>>(typedData: TypedData<Types, Message>, ctx: OperationContext<TAdapterCapabilities>): Promise<`0x${string}`>;
2339
2945
  /**
2340
- * Signs EIP-712 typed data using the configured signer.
2946
+ * Handle read-only function execution with noop estimation.
2947
+ *
2948
+ * @param params - The EVM prepared chain request parameters.
2949
+ * @param signer - The Ethers signer instance.
2950
+ * @param provider - The Ethers provider instance.
2951
+ * @param walletAddress - The wallet address (prevents race conditions in concurrent requests).
2952
+ * @returns A prepared chain request for read-only function execution.
2953
+ */
2954
+ private handleReadOnlyFunction;
2955
+ /**
2956
+ * Reads a contract function using Ethers v6.
2957
+ *
2958
+ * @param params - The read contract parameters including address, ABI, function name, and args.
2959
+ * @param chain - The chain definition where the contract is deployed.
2960
+ * @returns Promise resolving to the contract function return value.
2961
+ * @throws Error when contract read fails.
2341
2962
  */
2342
- signTypedData<Types extends Record<string, TypedDataField[]>, Message extends Record<string, unknown>>(typedData: TypedData<Types, Message>): Promise<`0x${string}`>;
2343
- /** Reads a contract function using Ethers v6. */
2344
- readContract<TReturnType = unknown>(params: ReadContractParams): Promise<TReturnType>;
2963
+ readContract<TReturnType = unknown>(params: ReadContractParams, chain: EVMChainDefinition): Promise<TReturnType>;
2345
2964
  }
2346
2965
 
2347
2966
  /**
2348
2967
  * Parameters for creating an {@link EthersAdapter} from a private key.
2349
2968
  *
2350
- * @interface CreateAdapterFromPrivateKeyParams
2351
- * @category Types
2352
- * @description
2353
- * Defines the configuration required to instantiate an {@link EthersAdapter}
2354
- * using a raw private key for server-side or programmatic wallet operations.
2355
- *
2356
- * This is intended for secure, backend, or automated environments where direct
2357
- * control of the private key is possible and safe. Do not use this pattern in
2358
- * browser or client-side code.
2359
- *
2360
- * @example
2361
- * ```typescript
2362
- * import { createAdapterFromPrivateKey } from '@circle-fin/adapter-ethers-v6'
2363
- * import { Blockchain } from '@core/chains'
2364
- *
2365
- * // Using a chain identifier (enum, string, or ChainDefinition)
2366
- * const adapter = createAdapterFromPrivateKey({
2367
- * privateKey: '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef',
2368
- * defaultChain: Blockchain.Ethereum,
2369
- * })
2370
- *
2371
- * // Advanced: custom provider logic (e.g., for custom endpoints or retry logic)
2372
- * const adapter2 = createAdapterFromPrivateKey({
2373
- * privateKey: '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef',
2374
- * defaultChain: 'Ethereum',
2375
- * getProvider: ({ chain }) => new JsonRpcProvider('https://...'),
2376
- * })
2377
- * ```
2378
- *
2379
- * @remarks
2380
- * Supported parameter combinations:
2381
- * - Provide `privateKey` and `defaultChain` (uses default provider logic).
2382
- * - Optionally provide a custom `getProvider` function for advanced provider instantiation.
2383
- *
2384
- * The `privateKey` must be a valid 32-byte hex string prefixed with `0x`.
2385
- * The `defaultChain` can be a {@link ChainDefinition}, a supported chain enum, or a string literal.
2386
- * The `getProvider` function, if supplied, receives an object with a `chain` parameter.
2969
+ * @typeParam TCapabilities - The adapter capabilities type for compile-time address validation
2387
2970
  */
2388
- interface CreateAdapterFromPrivateKeyParams {
2389
- /**
2390
- * The private key for wallet operations.
2391
- * @remarks
2392
- * Must be a valid 32-byte hex string prefixed with '0x'. This should be:
2393
- * - A securely generated private key
2394
- * - Kept confidential and never exposed in client-side code
2395
- * - Used only in server-side or secure environments
2396
- *
2397
- * The private key will be used to sign transactions and authenticate
2398
- * with the blockchain network.
2399
- */
2400
- privateKey: `0x${string}`;
2971
+ interface CreateAdapterFromPrivateKeyParams<TCapabilities extends Partial<AdapterCapabilities> = AdapterCapabilities> {
2401
2972
  /**
2402
- * The default blockchain network to connect to.
2403
- * @remarks
2404
- * Accepts a {@link ChainDefinition}, a supported chain enum, or a string literal representing the chain.
2405
- * This determines which EVM-compatible network the adapter will operate on by default.
2406
- * The adapter will use the canonical RPC URL for the specified chain unless a custom provider is supplied.
2407
- * Examples: `Blockchain.Ethereum`, `'Ethereum'`, or a `ChainDefinition` object.
2973
+ * The private key to use for wallet derivation.
2974
+ * Must be a valid 32-byte hex string, with or without '0x' prefix.
2975
+ * If the prefix is omitted, it will be added automatically during validation.
2408
2976
  */
2409
- defaultChain: ChainIdentifier;
2977
+ privateKey: string;
2410
2978
  /**
2411
- * Optional function to provide a custom Ethers Provider instance.
2412
- * @remarks
2413
- * If not provided, a default Provider will be created using the chain's RPC endpoints.
2414
- * Use this to inject custom provider logic, such as:
2415
- * - Custom retry or caching strategies
2416
- * - Enhanced logging or monitoring
2417
- * - Support for non-standard transports
2418
- *
2419
- * @param chain - The chain definition for which to create the provider.
2420
- * @returns A configured Provider instance.
2979
+ * Optional function to create providers for different chains.
2980
+ * If not provided, a default implementation using JsonRpcProvider will be used.
2421
2981
  */
2422
2982
  getProvider?: (params: {
2423
2983
  chain: ChainDefinition;
2424
2984
  }) => Provider;
2985
+ /**
2986
+ * Optional adapter capabilities configuration.
2987
+ * Defines address control model and supported chains.
2988
+ * If not provided, defaults to user-controlled with all EVM chains supported.
2989
+ *
2990
+ * @example
2991
+ * ```typescript
2992
+ * // Minimal configuration with default capabilities
2993
+ * createAdapterFromPrivateKey({
2994
+ * privateKey: '0x...'
2995
+ * // Capabilities default to:
2996
+ * // { addressContext: 'user-controlled', supportedChains: [all EVM chains] }
2997
+ * })
2998
+ * ```
2999
+ *
3000
+ * @example
3001
+ * ```typescript
3002
+ * // Custom supported chains
3003
+ * createAdapterFromPrivateKey({
3004
+ * privateKey: '0x...',
3005
+ * capabilities: {
3006
+ * supportedChains: [Ethereum, Base, Polygon]
3007
+ * }
3008
+ * })
3009
+ * ```
3010
+ */
3011
+ capabilities?: TCapabilities;
2425
3012
  }
2426
3013
  /**
2427
- * Creates an EthersAdapter instance from a private key.
3014
+ * Creates an EthersAdapter instance from a private key with automatic type inference.
2428
3015
  *
2429
3016
  * This function creates an EthersAdapter for server-side or programmatic use
2430
- * by deriving a wallet from the provided private key and connecting it to the specified chain.
2431
- * It's ideal for automated systems, backend services, or scenarios where you have direct
2432
- * control over the private key.
3017
+ * by deriving a wallet from the provided private key. It uses lazy initialization
3018
+ * where the wallet is created without a provider and is connected to chain-specific
3019
+ * providers on-demand during operations. This matches the Viem adapter pattern and
3020
+ * enables seamless multi-chain operations with a single adapter instance.
2433
3021
  *
2434
3022
  * @remarks
2435
3023
  * The function performs the following operations:
2436
3024
  * 1. Validates the input parameters at runtime
2437
- * 2. Resolves the chain identifier to a ChainDefinition
2438
- * 3. Determines the canonical RPC URL for the specified chain
2439
- * 4. Creates a JsonRpcProvider using the resolved RPC URL (or a custom provider if getProvider is supplied)
2440
- * 5. Instantiates a Wallet with the private key and provider
2441
- * 6. Returns a configured EthersAdapter instance
3025
+ * 2. Creates a Wallet from the private key (without provider - lazy initialization)
3026
+ * 3. Applies smart defaults for capabilities (user-controlled + all EVM chains)
3027
+ * 4. Returns a configured EthersAdapter instance
2442
3028
  *
2443
- * The adapter will be ready to use immediately after creation with the
2444
- * specified provider and wallet active. If a custom provider factory is provided,
2445
- * those settings will be respected for all operations.
3029
+ * Chain context is provided through OperationContext during individual operations.
3030
+ * The wallet will be connected to a provider when ensureChain() is called in prepare().
3031
+ *
3032
+ * **Default Configuration:**
3033
+ * - `addressContext`: `'user-controlled'` (address derived from private key automatically)
3034
+ * - `supportedChains`: All EVM-compatible chains (~29 networks)
3035
+ * - Lazy initialization: Chain connection deferred until first operation
2446
3036
  *
2447
3037
  * **Security Warning:** Never use this function in client-side code or expose
2448
3038
  * private keys in any way. This function is intended for server-side use only.
3039
+ * Store private keys securely using environment variables or secret management systems.
2449
3040
  *
3041
+ * @typeParam TCapabilities - The adapter capabilities type for compile-time address validation
2450
3042
  * @param params - Configuration parameters for creating the adapter
2451
- * @returns A configured EthersAdapter instance
2452
- * @throws Error when validation fails or wallet creation fails
3043
+ * @returns A configured EthersAdapter instance with automatically inferred capabilities
3044
+ * @throws Error when validation fails or wallet derivation fails
2453
3045
  *
2454
3046
  * @example
2455
3047
  * ```typescript
2456
3048
  * import { createAdapterFromPrivateKey } from '@circle-fin/adapter-ethers-v6'
2457
- * import { Blockchain, Ethereum } from '@core/chains'
2458
3049
  *
2459
- * // Using ChainDefinition object
3050
+ * // Both private key formats are supported (with or without '0x' prefix):
2460
3051
  * const adapter1 = createAdapterFromPrivateKey({
2461
- * privateKey: '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef',
2462
- * defaultChain: Ethereum,
3052
+ * privateKey: '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef' // With prefix
2463
3053
  * })
2464
3054
  *
2465
- * // Using Blockchain enum
2466
3055
  * const adapter2 = createAdapterFromPrivateKey({
2467
- * privateKey: '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef',
2468
- * defaultChain: Blockchain.Ethereum,
3056
+ * privateKey: '1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef' // Without prefix (automatically normalized)
2469
3057
  * })
2470
3058
  *
2471
- * // Using string literal
2472
- * const adapter3 = createAdapterFromPrivateKey({
2473
- * privateKey: '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef',
2474
- * defaultChain: 'Ethereum',
2475
- * })
3059
+ * // Chain specified per-operation via OperationContext
3060
+ * const prepared = await adapter1.prepare({
3061
+ * address: '0x...',
3062
+ * abi: contractAbi,
3063
+ * functionName: 'transfer',
3064
+ * args: ['0xto', '1000']
3065
+ * }, { chain: 'Ethereum' })
2476
3066
  * ```
2477
3067
  *
2478
3068
  * @example
2479
3069
  * ```typescript
2480
3070
  * import { createAdapterFromPrivateKey } from '@circle-fin/adapter-ethers-v6'
2481
- * import { JsonRpcProvider } from 'ethers'
2482
3071
  *
2483
- * // Advanced usage with custom provider logic
3072
+ * // Multi-chain usage with same adapter instance
2484
3073
  * const adapter = createAdapterFromPrivateKey({
2485
- * privateKey: process.env.PRIVATE_KEY,
2486
- * defaultChain: 'Ethereum',
2487
- * getProvider: ({ chain }) => new JsonRpcProvider('https://...'),
3074
+ * privateKey: process.env.PRIVATE_KEY as `0x${string}`
2488
3075
  * })
3076
+ *
3077
+ * // Transfer USDC on Ethereum
3078
+ * await adapter.prepare(params, { chain: 'Ethereum' })
3079
+ *
3080
+ * // Transfer USDC on Base using the same adapter
3081
+ * await adapter.prepare(params, { chain: 'Base' })
2489
3082
  * ```
2490
3083
  *
2491
3084
  * @example
2492
3085
  * ```typescript
2493
- * // Cross-chain transfer using a single adapter
2494
3086
  * import { createAdapterFromPrivateKey } from '@circle-fin/adapter-ethers-v6'
2495
- * import { BridgingKit } from '@circle-fin/bridging-kit'
3087
+ * import { Ethereum, Base, Polygon } from '@core/chains'
2496
3088
  *
3089
+ * // Custom capabilities configuration
2497
3090
  * const adapter = createAdapterFromPrivateKey({
2498
- * privateKey: process.env.PRIVATE_KEY,
2499
- * defaultChain: 'Ethereum',
2500
- * })
2501
- *
2502
- * const kit = new BridgingKit()
2503
- *
2504
- * // Use the same adapter for both source and destination
2505
- * const result = await kit.bridge({
2506
- * from: { adapter, chain: 'Ethereum' },
2507
- * to: { adapter, chain: 'Base' },
2508
- * amount: '100.50'
3091
+ * privateKey: process.env.PRIVATE_KEY as `0x${string}`,
3092
+ * capabilities: {
3093
+ * supportedChains: [Ethereum, Base, Polygon]
3094
+ * }
2509
3095
  * })
2510
3096
  * ```
2511
3097
  *
2512
3098
  * @example
2513
3099
  * ```typescript
2514
3100
  * import { createAdapterFromPrivateKey } from '@circle-fin/adapter-ethers-v6'
3101
+ * import { JsonRpcProvider } from 'ethers'
2515
3102
  *
2516
- * // Error handling example
2517
- * try {
2518
- * const adapter = createAdapterFromPrivateKey({
2519
- * privateKey: '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef',
2520
- * defaultChain: 'Polygon',
2521
- * })
2522
- *
2523
- * // Adapter is ready to use immediately
2524
- * const balance = await adapter.getBalance()
2525
- * console.log('Balance:', balance)
2526
- * } catch (error) {
2527
- * if (error.message.includes('Private key')) {
2528
- * console.error('Invalid private key format')
2529
- * } else {
2530
- * console.error('Failed to create adapter:', error.message)
3103
+ * // Custom provider configuration with explicit chain mapping
3104
+ * const adapter = createAdapterFromPrivateKey({
3105
+ * privateKey: process.env.PRIVATE_KEY as `0x${string}`,
3106
+ * getProvider: ({ chain }) => {
3107
+ * const rpcEndpoints: Record<string, string> = {
3108
+ * 'Ethereum': `https://eth-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_KEY}`,
3109
+ * 'Base': `https://base-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_KEY}`
3110
+ * }
3111
+ * const endpoint = rpcEndpoints[chain.name]
3112
+ * if (!endpoint) throw new Error(`RPC not configured for ${chain.name}`)
3113
+ * return new JsonRpcProvider(endpoint, chain.chainId)
2531
3114
  * }
2532
- * }
3115
+ * })
2533
3116
  * ```
2534
3117
  */
2535
- declare const createAdapterFromPrivateKey: (params: CreateAdapterFromPrivateKeyParams) => EthersAdapter;
3118
+ declare function createAdapterFromPrivateKey<const TCapabilities extends Partial<AdapterCapabilities> = object>(params: CreateAdapterFromPrivateKeyParams<TCapabilities>): EthersAdapter<InferAdapterCapabilities<TCapabilities>>;
2536
3119
 
2537
3120
  /**
2538
3121
  * Parameters for creating an {@link EthersAdapter} from an EIP-1193 provider.
@@ -2541,43 +3124,46 @@ declare const createAdapterFromPrivateKey: (params: CreateAdapterFromPrivateKeyP
2541
3124
  * @category Types
2542
3125
  * @description
2543
3126
  * Defines the parameters required to instantiate an {@link EthersAdapter} using an EIP-1193-compatible provider
2544
- * (such as MetaMask, WalletConnect, or any injected browser wallet), and to specify the intended blockchain network.
3127
+ * (such as MetaMask, WalletConnect, or any injected browser wallet).
2545
3128
  *
2546
3129
  * @example
2547
3130
  * ```typescript
2548
3131
  * import { createAdapterFromProvider } from '@circle-fin/adapter-ethers-v6'
2549
3132
  *
2550
- * // Basic usage with injected provider and explicit chain
3133
+ * // Basic browser wallet setup
2551
3134
  * const adapter = await createAdapterFromProvider({
2552
- * provider: window.ethereum,
2553
- * chain: 'Ethereum_Sepolia',
3135
+ * provider: window.ethereum
3136
+ * // Smart defaults applied:
3137
+ * // - addressContext: 'user-controlled'
3138
+ * // - supportedChains: all EVM chains
2554
3139
  * })
2555
3140
  * ```
2556
3141
  *
2557
3142
  * @example
2558
3143
  * ```typescript
2559
3144
  * import { createAdapterFromProvider } from '@circle-fin/adapter-ethers-v6'
2560
- * import { JsonRpcProvider } from 'ethers'
3145
+ * import { Ethereum, Base, Polygon } from '@core/chains'
2561
3146
  *
2562
- * // Advanced: custom provider logic for a specific chain
3147
+ * // Advanced: custom capabilities
2563
3148
  * const adapter = await createAdapterFromProvider({
2564
3149
  * provider: window.ethereum,
2565
- * chain: 'Base_Sepolia',
2566
- * getProvider: ({ chain }) => new JsonRpcProvider('https://...'),
3150
+ * capabilities: {
3151
+ * supportedChains: [Ethereum, Base, Polygon]
3152
+ * }
2567
3153
  * })
2568
3154
  * ```
2569
3155
  *
2570
3156
  * @remarks
2571
3157
  * Required parameters:
2572
3158
  * - `provider`: A valid EIP-1193 provider (e.g., MetaMask, WalletConnect, etc.).
2573
- * - `chain`: The blockchain network to use for the adapter. Accepts a chain identifier string, enum, or chain definition.
2574
3159
  *
2575
3160
  * Optional:
2576
3161
  * - `getProvider`: A custom function to instantiate an Ethers Provider for the specified chain.
2577
3162
  * Receives an object with a `chain` property of type {@link EVMChainDefinition}.
3163
+ * - `capabilities`: Adapter capabilities defining address control and supported chains.
2578
3164
  *
2579
- * The `chain` parameter determines which network the adapter will operate on, regardless of the wallet's current network.
2580
- * This enables cross-chain workflows and explicit network targeting.
3165
+ * With OperationContext pattern, chain is specified per-operation rather than at factory creation.
3166
+ * This enables cross-chain workflows with a single adapter instance.
2581
3167
  */
2582
3168
  interface CreateAdapterFromProviderParams {
2583
3169
  /**
@@ -2593,13 +3179,6 @@ interface CreateAdapterFromProviderParams {
2593
3179
  * - `enable()` or equivalent for requesting account access
2594
3180
  */
2595
3181
  provider: Eip1193Provider;
2596
- /**
2597
- * The blockchain network to use for the adapter.
2598
- * @remarks
2599
- * This chain will be used as the intended chain for the adapter.
2600
- * The adapter will use this chain instead of the wallet's current network.
2601
- */
2602
- chain: ChainIdentifier;
2603
3182
  /**
2604
3183
  * Optional function to provide a custom Ethers Provider instance.
2605
3184
  * @remarks
@@ -2615,48 +3194,115 @@ interface CreateAdapterFromProviderParams {
2615
3194
  getProvider?: (params: {
2616
3195
  chain: EVMChainDefinition;
2617
3196
  }) => Provider;
3197
+ /**
3198
+ * Optional capabilities configuration for the adapter.
3199
+ * @remarks
3200
+ * Defines the adapter's address control model and supported chains.
3201
+ * If not provided, defaults to user-controlled address context with all EVM chains supported.
3202
+ *
3203
+ * - `addressContext`: Determines address control model ('user-controlled' or 'developer-controlled')
3204
+ * - `supportedChains`: Array of supported blockchain networks
3205
+ *
3206
+ * For EIP-1193 provider adapters, typically uses 'user-controlled' since addresses are managed
3207
+ * through the wallet UI and user interaction.
3208
+ *
3209
+ * @example
3210
+ * ```typescript
3211
+ * // Minimal configuration with smart defaults
3212
+ * createAdapterFromProvider({
3213
+ * provider: window.ethereum
3214
+ * // Capabilities default to:
3215
+ * // { addressContext: 'user-controlled', supportedChains: [all EVM chains] }
3216
+ * })
3217
+ * ```
3218
+ *
3219
+ * @example
3220
+ * ```typescript
3221
+ * // Override supported chains only
3222
+ * createAdapterFromProvider({
3223
+ * provider: window.ethereum,
3224
+ * capabilities: {
3225
+ * supportedChains: [Ethereum, Base, Polygon]
3226
+ * // addressContext still defaults to 'user-controlled'
3227
+ * }
3228
+ * })
3229
+ * ```
3230
+ */
3231
+ capabilities?: Partial<AdapterCapabilities>;
2618
3232
  }
2619
3233
  /**
2620
- * Creates an EthersAdapter instance from an EIP-1193 provider.
3234
+ * Creates an EthersAdapter instance from an EIP-1193 provider with smart default capabilities.
2621
3235
  *
2622
3236
  * This function creates an EthersAdapter for browser or injected wallet use
2623
- * by connecting to the provided EIP-1193-compatible provider.
2624
- * It's ideal for dApps, browser-based integrations, or scenarios where the user controls the wallet.
3237
+ * by connecting to the provided EIP-1193-compatible provider (such as MetaMask,
3238
+ * WalletConnect, or any browser wallet). The adapter is automatically configured
3239
+ * with user-controlled address context and support for all EVM-compatible chains.
2625
3240
  *
2626
3241
  * @remarks
2627
3242
  * The function performs the following operations:
2628
3243
  * 1. Validates the input parameters at runtime
2629
- * 2. Creates a cached provider factory (or uses a custom one if provided)
2630
- * 3. Instantiates a BrowserProvider for the injected provider
2631
- * 4. Requests account access and retrieves the signer
2632
- * 5. Returns a configured EthersAdapter instance
3244
+ * 2. Creates a BrowserProvider for the injected provider
3245
+ * 3. Requests account access from the user (wallet prompt appears here)
3246
+ * 4. Retrieves the signer from the connected wallet
3247
+ * 5. Applies smart defaults for capabilities (user-controlled + all EVM chains)
3248
+ * 6. Returns a configured EthersAdapter instance ready for immediate use
2633
3249
  *
2634
3250
  * The adapter will be ready to use immediately after creation with the
2635
- * specified provider and signer active. If a custom provider factory is provided,
2636
- * those settings will be respected for all operations.
3251
+ * specified provider and signer active. Chain context is provided through
3252
+ * OperationContext during individual operations.
3253
+ *
3254
+ * **Smart Defaults:**
3255
+ * - `addressContext`: `'user-controlled'` (addresses managed through wallet UI)
3256
+ * - `supportedChains`: All EVM-compatible chains (~29 networks) for maximum flexibility
3257
+ * - OperationContext support for per-operation chain specification
2637
3258
  *
2638
- * **Supported parameter combinations:**
2639
- * - Provide `provider` and `chain` (uses default provider logic).
2640
- * - Provide `provider`, `chain`, and a custom `getProvider` function (for advanced provider instantiation).
3259
+ * **Account Access:**
3260
+ * Note: Unlike Viem, Ethers requires eager signer initialization because:
3261
+ * - Ethers Signer objects are chain-specific and must be recreated during chain switches
3262
+ * - The switchChain utility requires an initialized Signer as input
3263
+ * - This is an architectural difference between Ethers and Viem, not a limitation
3264
+ * The user will be prompted for account access when this factory is called (before adapter is returned).
2641
3265
  *
2642
3266
  * **Security Note:** This function is intended for use with injected/browser wallets.
2643
3267
  * Do not use in server-side code with private keys.
2644
3268
  *
2645
- * @param params - Configuration parameters for creating the adapter. Must include:
2646
- * - `provider`: An EIP-1193-compatible provider (e.g., MetaMask, WalletConnect, etc.)
2647
- * - `chain`: The blockchain network identifier (string, enum, or ChainDefinition)
2648
- * - `getProvider` (optional): A custom function to create a JsonRpcProvider
3269
+ * @param params - Configuration parameters for creating the adapter
2649
3270
  * @returns A configured EthersAdapter instance
2650
- * @throws Error when validation fails or provider/signing fails
3271
+ * @throws Error when validation fails, user rejects connection, or provider initialization fails
3272
+ *
3273
+ * @example
3274
+ * ```typescript
3275
+ * import { createAdapterFromProvider } from '@circle-fin/adapter-ethers-v6'
3276
+ *
3277
+ * // Minimal browser wallet configuration
3278
+ * const adapter = await createAdapterFromProvider({
3279
+ * provider: window.ethereum
3280
+ * // Smart defaults applied:
3281
+ * // - addressContext: 'user-controlled'
3282
+ * // - supportedChains: all EVM chains (~29 networks)
3283
+ * })
3284
+ *
3285
+ * // Use with OperationContext pattern
3286
+ * const prepared = await adapter.prepare({
3287
+ * address: '0x...',
3288
+ * abi: contractAbi,
3289
+ * functionName: 'transfer',
3290
+ * args: ['0xto', '1000']
3291
+ * }, { chain: 'Ethereum' }) // Chain specified in context
3292
+ * ```
2651
3293
  *
2652
3294
  * @example
2653
3295
  * ```typescript
2654
3296
  * import { createAdapterFromProvider } from '@circle-fin/adapter-ethers-v6'
3297
+ * import { Ethereum, Base, Polygon } from '@core/chains'
2655
3298
  *
2656
- * // Basic usage with default provider
3299
+ * // Advanced: custom capabilities for production use
2657
3300
  * const adapter = await createAdapterFromProvider({
2658
3301
  * provider: window.ethereum,
2659
- * chain: 'Ethereum'
3302
+ * capabilities: {
3303
+ * supportedChains: [Ethereum, Base, Polygon] // Restrict to specific chains
3304
+ * // addressContext still defaults to 'user-controlled'
3305
+ * }
2660
3306
  * })
2661
3307
  * ```
2662
3308
  *
@@ -2665,15 +3311,98 @@ interface CreateAdapterFromProviderParams {
2665
3311
  * import { createAdapterFromProvider } from '@circle-fin/adapter-ethers-v6'
2666
3312
  * import { JsonRpcProvider } from 'ethers'
2667
3313
  *
2668
- * // Advanced usage with custom provider logic
3314
+ * // Advanced usage with custom provider logic for production
2669
3315
  * const adapter = await createAdapterFromProvider({
2670
3316
  * provider: window.ethereum,
2671
- * chain: 'Ethereum',
2672
- * getProvider: ({ chain }) => new JsonRpcProvider('https://...')
3317
+ * getProvider: ({ chain }) => new JsonRpcProvider(
3318
+ * `https://eth-mainnet.alchemyapi.io/v2/${process.env.ALCHEMY_KEY}`,
3319
+ * { name: chain.name, chainId: chain.chainId }
3320
+ * )
3321
+ * })
3322
+ *
3323
+ * // Address is automatically resolved from connected wallet
3324
+ * const prepared = await adapter.prepare(params, {
3325
+ * chain: 'Polygon' // Address comes from wallet UI
3326
+ * })
3327
+ * ```
3328
+ *
3329
+ * @example
3330
+ * ```typescript
3331
+ * // Cross-chain transfer using a single adapter
3332
+ * import { createAdapterFromProvider } from '@circle-fin/adapter-ethers-v6'
3333
+ * import { BridgeKit } from '@circle-fin/bridge-kit'
3334
+ *
3335
+ * const adapter = await createAdapterFromProvider({
3336
+ * provider: window.ethereum
3337
+ * })
3338
+ *
3339
+ * const kit = new BridgeKit()
3340
+ *
3341
+ * // Use the same adapter for both source and destination
3342
+ * const result = await kit.bridge({
3343
+ * from: { adapter, chain: 'Ethereum' },
3344
+ * to: { adapter, chain: 'Base' },
3345
+ * amount: '100.50'
2673
3346
  * })
2674
3347
  * ```
3348
+ *
3349
+ * @example
3350
+ * ```typescript
3351
+ * import { createAdapterFromProvider } from '@circle-fin/adapter-ethers-v6'
3352
+ *
3353
+ * // Error handling example - wallet prompt occurs during factory creation
3354
+ * try {
3355
+ * const adapter = await createAdapterFromProvider({
3356
+ * provider: window.ethereum
3357
+ * })
3358
+ *
3359
+ * // Adapter is ready to use immediately
3360
+ * console.log('Adapter connected successfully')
3361
+ * } catch (error) {
3362
+ * if (error.message.includes('User rejected')) {
3363
+ * console.error('User rejected connection request')
3364
+ * } else if (error.message.includes('Failed to initialize')) {
3365
+ * console.error('Could not initialize wallet connection')
3366
+ * } else {
3367
+ * console.error('Failed to create adapter:', error.message)
3368
+ * }
3369
+ * }
3370
+ * ```
2675
3371
  */
2676
3372
  declare const createAdapterFromProvider: (params: CreateAdapterFromProviderParams) => Promise<EthersAdapter>;
2677
3373
 
2678
- export { EthersAdapter, createAdapterFromPrivateKey, createAdapterFromProvider };
3374
+ /**
3375
+ * Validates adapter capabilities for EthersAdapter.
3376
+ *
3377
+ * This function ensures that the adapter capabilities meet the requirements for the
3378
+ * OperationContext pattern by validating the addressContext property and optionally
3379
+ * checking the supportedChains property for EVM compatibility.
3380
+ *
3381
+ * @param capabilities - The adapter capabilities to validate
3382
+ * @throws ValidationError when capabilities validation fails
3383
+ *
3384
+ * @example
3385
+ * ```typescript
3386
+ * import { validateAdapterCapabilities } from '@circle-fin/adapter-ethers-v6/validation'
3387
+ * import { Ethereum, Base } from '@core/chains'
3388
+ *
3389
+ * // Valid capabilities for user-controlled adapter
3390
+ * const userCapabilities = {
3391
+ * addressContext: 'user-controlled',
3392
+ * supportedChains: [Ethereum, Base]
3393
+ * }
3394
+ *
3395
+ * // Valid capabilities for developer-controlled adapter
3396
+ * const devCapabilities = {
3397
+ * addressContext: 'developer-controlled',
3398
+ * supportedChains: [Ethereum]
3399
+ * }
3400
+ *
3401
+ * validateAdapterCapabilities(userCapabilities) // passes validation
3402
+ * validateAdapterCapabilities(devCapabilities) // passes validation
3403
+ * ```
3404
+ */
3405
+ declare function validateAdapterCapabilities(capabilities: AdapterCapabilities): void;
3406
+
3407
+ export { Blockchain, EthersAdapter, createAdapterFromPrivateKey, createAdapterFromProvider, validateAdapterCapabilities };
2679
3408
  export type { ChainIdentifier, CreateAdapterFromPrivateKeyParams, CreateAdapterFromProviderParams, EthersAdapterOptions };