import { type PollingBlockTracker, TransactionController } from "@toruslabs/ethereum-controllers"; import { type SafeEventEmitterProvider } from "@web3auth/auth"; import { type LoggerConfig } from "../../../core"; import { type IFoxKeyring } from "../keyring"; /** * Input to {@link createEvmControllerStack}. The stack is the minimal set of * toruslabs pieces `ControllerEVMWalletClient` delegates to for a production- * grade transaction lifecycle (nonce locking, pending/dropped detection, * resubmission, tiered gas-fee estimation) without pulling in * `NetworkController` or `PreferencesController` — those are browser-wallet * concerns (chain switching, auth-backed preferences, visibility-gated * polling) that a single-chain Node CLI doesn't need. * * `GasFeeController` is wired in on-demand only (no polling). Its primary * estimation source is MetaMask's public gas API * (`gas-api.metaswap.codefi.network`) on the chain ids the controller * hardcodes as supported (mainnet + the 8 major L1s/L2s); every other chain * — and any API failure on a supported chain — falls back to * `eth_feeHistory`. Either way, the speed knob on `prepareTransaction` * produces real low/medium/high tiers. Endpoints are overridable via * {@link ControllerStackOpts.gasApiEndpoints}. * * The callbacks TransactionController expects (`getCurrentChainId`, * `getSelectedAddress`, `getEIP1559GasFeeEstimates`, …) are wired as plain * closures over the constructor args. This is the same pattern toruslabs * themselves use in their TransactionController unit tests. * * Each stack is bound to exactly **one** `chainId` + `rpcUrl`: * - share one `keyring` across stacks (it's chain-agnostic), * - construct one stack per chain you actually transact on; spawn a read-only * viem `PublicClient` for chains you only read from, * - runtime chain switching on a single stack is intentionally not supported * (see README "Multi-chain" for the integration recipe). */ export type ControllerStackOpts = LoggerConfig & { keyring: IFoxKeyring; address: `0x${string}`; rpcUrl: string; chainId: number; /** * Block-tracker poll interval in seconds. Controls how often * `PendingTransactionTracker.resubmitPendingTxs` runs against the RPC. * Defaults to 10s — aggressive enough to catch stuck nonces quickly, cheap * enough to not hammer the provider. */ pollingIntervalSeconds?: number; /** * When `false`, gas-fee estimation uses the legacy gas-price API path and * reports the network as non–EIP-1559 for controller callbacks. Defaults to * `true` (EIP-1559 / fee-market path). */ eip1559?: boolean; /** * Optional overrides for the gas-fee API endpoints `GasFeeController` * consults before falling back to `eth_feeHistory`. * * Defaults point at MetaMask's public gas API * (`gas-api.metaswap.codefi.network`). The `` placeholder is * substituted by the controller with the decimal chain id at request * time. * * Important: even with these set, the API is only consulted on the chain * ids `GasFeeController` hardcodes in `API_SUPPORTED_CHAINIDS` (mainnet, * goerli, arbitrum, avalanche, base, bsc, fantom, optimism, polygon). * Every other chain still goes straight to `eth_feeHistory` — see the * comment on the controller construction below. * * Override these to point at an internal mirror, a staging gas API, or * — by setting them to a URL that always errors — to force the * `eth_feeHistory` path on every chain (the controller's try/catch * swallows the throw and falls through). */ gasApiEndpoints?: { eip1559?: string; legacy?: string; }; }; export type ControllerStack = { keyring: IFoxKeyring; transaction: TransactionController; provider: SafeEventEmitterProvider; blockTracker: PollingBlockTracker; address: `0x${string}`; chainId: number; /** * Tear down listeners so a Node CLI process can exit cleanly. * * Note: `PollingBlockTracker` internally uses `PollingManager` which * schedules its next tick via `setTimeout`. Removing listeners stops * further scheduling but an in-flight timer can delay `process.exit(0)` * by up to `pollingIntervalSeconds`. For hard-exit semantics callers * should `process.exit()` after `dispose()`. */ dispose(): void; }; export declare function createEvmControllerStack(opts: ControllerStackOpts): ControllerStack;