/** * @b402ai/sdk — Private DeFi execution for agents * * Usage: * import { B402 } from '@b402ai/sdk' * * const b402 = new B402({ privateKey: '0x...' }) * * await b402.swap({ from: 'USDC', to: 'WETH', amount: '10' }) * await b402.lend({ token: 'USDC', amount: '100', vault: 'steakhouse' }) * await b402.redeem({ vault: 'steakhouse' }) * const info = await b402.status() * * Gasless — b402 facilitator handles gas. User only needs a private key. */ import { ethers } from 'ethers'; import { type ChainContracts } from './config/chains'; export interface B402Config { /** Operator private key — derives anonymous smart wallet. Provide this OR signer. */ privateKey?: string; /** Ethers signer — alternative to privateKey. Any signer that can signMessage(). */ signer?: ethers.Signer; /** 0x API key for swap quotes (required for swap only) */ zeroXApiKey?: string; /** Chain ID (default: 8453 / Base). Supported: 8453 (Base), 56 (BSC), 42161 (Arbitrum). */ chainId?: number; /** RPC URL (default: chain-specific RPC from B402_CHAINS) */ rpcUrl?: string; /** b402 facilitator URL (default: production) */ facilitatorUrl?: string; /** * Backend API URL for UTXO/merkle-proof queries. * Resolution order: this option → env `B402_BACKEND_API_URL` / * `{BASE,BSC,ARB}_BACKEND_API_URL` → chain-specific production default. * Use to point at a replica or self-hosted indexer. */ backendApiUrl?: string; /** Progress callback — receives step updates */ onProgress?: (event: ProgressEvent) => void; } export interface ProgressEvent { type: 'step' | 'done' | 'info'; step?: number; totalSteps?: number; title: string; message: string; } export interface SwapParams { from: string; to: string; amount: string; slippageBps?: number; } export interface SwapResult { txHash: string; amountIn: string; amountOut: string; tokenIn: string; tokenOut: string; } export interface LendParams { token: string; amount: string; vault?: string; } export interface LendResult { txHash: string; amount: string; vault: string; } export interface RedeemParams { vault?: string; shares?: string; } export interface RedeemResult { txHash: string; assetsReceived: string; vault: string; } export interface UnshieldParams { /** Token to unshield from privacy pool (USDC, WETH, DAI) */ token: string; /** Amount to unshield (human-readable) */ amount: string; /** Recipient address. If provided, unshields directly to this address instead of smart wallet. */ to?: string; } export interface UnshieldResult { txHash: string; /** Time spent generating ZK proof in seconds */ proofTimeSeconds: number; } export interface FundIncognitoParams { /** Token to fund with (default: USDC) */ token: string; /** Amount to unshield to incognito EOA (human-readable, e.g. '5.00') */ amount: string; } export interface FundIncognitoResult { /** On-chain transaction hash */ txHash: string; /** Time spent generating ZK proof */ proofTimeSeconds: number; /** Amount funded (human-readable) */ amount: string; /** Incognito EOA address that received the tokens */ incognitoAddress: string; } export interface ShieldParams { token: string; amount: string; /** * Optional — pull USDC from this address (EOA or smart wallet) instead of master EOA. * When set, `auth` must also be provided. Used for "shield on behalf of buyer" flows * (e.g. ACP private_transfer) where the buyer signs an EIP-3009 authorization off-chain * and the seller atomically submits pull+shield as one b402-facilitator-sponsored userOp. */ from?: string; /** * Optional — pre-signed EIP-3009 TransferWithAuthorization payload from `from` * authorizing transfer to the b402 shield wallet. Required when `from` is set. */ auth?: { validAfter: number; validBefore: number; nonce: string; v: number; r: string; s: string; }; } export interface ShieldResult { txHash: string; indexed: boolean; } export interface StatusResult { ownerEOA: string; smartWallet: string; deployed: boolean; /** Chain name e.g. "base", "arbitrum", "bsc" */ chain: string; /** Chain ID (8453 = Base, 42161 = Arbitrum, 56 = BSC) */ chainId: number; balances: { token: string; balance: string; }[]; shieldedBalances: { token: string; balance: string; }[]; positions: { vault: string; shares: string; assets: string; apyEstimate: string; tvl?: string; }[]; lpPositions: LPPosition[]; } export interface ConsolidateResult { /** Final shield TX hash */ txHash: string; /** Number of UTXOs consumed */ utxosConsumed: number; /** Total amount consolidated (human-readable) */ amount: string; } export interface RebalanceResult { action: 'rebalanced' | 'no-change'; currentVault?: string; bestVault?: string; txHash?: string; } export interface PrivateSwapParams { /** Token to swap from (symbol or address) */ from: string; /** Token to swap to (symbol or address) */ to: string; /** Amount to swap (human-readable) */ amount: string; /** Slippage tolerance in basis points (default 50 = 0.5%) */ slippageBps?: number; } export interface PrivateSwapResult { txHash: string; amountIn: string; amountOut: string; tokenIn: string; tokenOut: string; } export interface PrivateLendParams { /** Token to deposit (default: USDC) */ token?: string; /** Amount to deposit (human-readable) */ amount: string; /** Vault name or address (default: steakhouse) */ vault?: string; } export interface PrivateLendResult { txHash: string; amount: string; vault: string; } export interface PrivateRedeemParams { /** Vault name or address (default: steakhouse) */ vault?: string; /** Shares to redeem (human-readable). Omit to redeem all. */ shares?: string; } export interface PrivateRedeemResult { txHash: string; assetsReceived: string; vault: string; } export interface PrivateCrossChainParams { /** Destination chain (ID or alias: 'arbitrum', 'base', 'bsc') */ toChain: number | string; /** Source token (symbol or address) on current chain */ fromToken: string; /** Destination token (symbol or address); same as fromToken for pure bridge */ toToken: string; /** Amount to send (human-readable, in fromToken decimals) */ amount: string; /** Destination recipient address (EOA on destination chain). Funds land here; user shields later with b402.shieldFromEOA on dest chain. */ destinationAddress: string; /** Slippage tolerance in basis points (default 50 = 0.5%) */ slippageBps?: number; /** Optional LI.FI API key (higher rate limit) */ lifiApiKey?: string; } export interface PrivateCrossChainResult { txHash: string; tool: string; fromChain: string; toChain: string; fromToken: string; toToken: string; amountIn: string; /** Expected amount arriving on destination (after fees + slippage floor) */ expectedAmountOut: string; minAmountOut: string; destinationAddress: string; estimatedDurationSec: number; } export interface AddLiquidityParams { /** Pool name (default: 'weth-usdc') */ pool?: string; /** Amount in USDC terms — SDK splits and swaps half automatically */ amount: string; /** Slippage tolerance in basis points (default: 300 = 3%) */ slippageBps?: number; } export interface AddLiquidityResult { txHash: string; amount: string; pool: string; } export interface RemoveLiquidityParams { pool?: string; slippageBps?: number; } export interface RemoveLiquidityResult { txHash: string; pool: string; amountWETH: string; amountUSDC: string; } export interface ClaimRewardsParams { pool?: string; } export interface ClaimRewardsResult { txHash: string; pool: string; } export interface LPPosition { pool: string; lpTokens: string; staked: boolean; usdValue: string; pendingRewards: string; apyEstimate: string; tvl?: string; } export interface SpeedMarketParams { /** Asset to bet on: ETH or BTC */ asset: string; /** Price direction: 'up' or 'down' */ direction: 'up' | 'down'; /** Bet amount in USDC (min $5, max $200) */ amount: string; /** Duration: '10m', '30m', '1h', '4h' (default: '10m') */ duration?: string; } export interface SpeedMarketResult { txHash: string; asset: string; direction: string; amount: string; strikeTime: number; duration: string; } export interface OpenPerpParams { /** Market: ETH, BTC, SOL, DOGE, etc. */ market: string; /** Long or short */ side: 'long' | 'short'; /** Position size in base asset (e.g. '0.1' = 0.1 ETH) */ size: string; /** USDC margin to deposit */ margin: string; /** Slippage tolerance in basis points (default: 100 = 1%) */ slippageBps?: number; } export interface OpenPerpResult { txHash: string; market: string; side: string; size: string; margin: string; } export interface ClosePerpParams { /** Market to close position in */ market: string; /** Synthetix perps account ID */ accountId: string; /** Slippage in basis points (default: 100) */ slippageBps?: number; } export interface ClosePerpResult { txHash: string; market: string; } export interface SynFuturesTradeParams { /** Instrument: LINK, PYTH, EMG, DEXV2, or contract address */ instrument: string; /** Long or short */ side: 'long' | 'short'; /** Trade size in USDC notional (e.g. '20' = $20 notional) */ notional: string; /** USDC margin to deposit (e.g. '10' for ~2x leverage) */ margin: string; /** Slippage in basis points (default: 300 = 3%) */ slippageBps?: number; } export interface SynFuturesTradeResult { txHash: string; instrument: string; side: string; notional: string; margin: string; size: string; priceUsd: string; } export interface SynFuturesCloseParams { /** Instrument to close position in */ instrument: string; /** Whether to also withdraw margin from Gate (default: true) */ withdrawMargin?: boolean; } export interface SynFuturesCloseResult { txHash: string; instrument: string; } export interface Call { /** Contract address to call */ to: string; /** ETH value in wei (use '0' for non-payable calls) */ value: string; /** ABI-encoded calldata */ data: string; } export declare class B402 { private config; private provider; private facilitatorUrl; /** Active chain ID (8453 = Base, 56 = BSC, 42161 = Arbitrum). */ readonly chainId: number; /** Resolved RPC URL (from config or chain default). */ readonly rpcUrl: string; /** Chain-specific contract addresses (Railgun relay, ERC-4337, paymaster). */ readonly contracts: ChainContracts; /** Railgun SDK network name for this chain (e.g. 'Base_Mainnet', 'Arbitrum'). */ readonly railgunNetworkName: string; /** Resolved backend API URL used for UTXO/merkle queries. */ readonly backendApiUrl: string; private incognitoKey; private incognitoWallet; private incognitoEOA; private wallet; private salt; private _initialized; constructor(config: B402Config); private submitUserOp; /** * Throw a clear error if the caller invokes a Base-only DeFi method from a * non-Base chain. Currently Morpho (lend/redeem), Aerodrome (LP/swap/rebalance), * 0x aggregator routing, and SynFutures are Base-only in this SDK. * Privacy primitives (shield/unshield/transact) are chain-aware and not gated here. */ private requireBase; /** Swap tokens via 0x aggregator. Requires zeroXApiKey. Base only. */ swap(params: SwapParams): Promise; /** Deposit tokens into a Morpho ERC-4626 vault. Base only. */ lend(params: LendParams): Promise; /** Withdraw from a Morpho vault. Omit shares to redeem all. Base only. */ redeem(params?: RedeemParams): Promise; /** Execute arbitrary calls through the smart wallet. Gasless via facilitator. */ transact(calls: Call[]): Promise<{ txHash: string; }>; /** Unshield tokens from Railgun privacy pool to smart wallet. Generates ZK proof client-side. * Pass amount: 'all' to drain all UTXOs for this token. */ unshield(params: UnshieldParams): Promise; /** Unshield a single UTXO fully (no change note). Used by unshield('all'). */ private _unshieldSingleUTXO; /** Get the incognito EOA address (deterministic, anonymous, no on-chain link to master key). * This address can sign EIP-3009 authorizations for x402 payments. */ getIncognitoAddress(): Promise; /** Get the incognito ethers.Wallet for x402 signing. * Has `address` and `signTypedData()` — exactly what x402 ClientEvmSigner needs. */ getIncognitoSigner(): Promise; /** Fund the incognito EOA from Railgun privacy pool via ZK proof. * Unshields tokens directly to the incognito EOA (NOT the smart wallet). * On-chain: Railgun Relay → Incognito EOA. No link to agent's real wallet. * The funded incognito EOA can then sign x402 EIP-3009 payments. */ fundIncognito(params: FundIncognitoParams): Promise; /** Initialize only the incognito wallet derivation (no network call needed for smart wallet address). */ private initIncognito; /** * Consolidate multiple shielded UTXOs into a single UTXO. * * When you shield tokens multiple times, each creates a separate UTXO. * Private operations use single-input ZK circuits, so they can only spend * one UTXO per proof. Consolidation merges all UTXOs into one large UTXO * so any private operation can access the full balance in a single proof. * * Flow: unshield all UTXOs → smart wallet → re-shield total as one UTXO. * The smart wallet is anonymous (derived from incognito key), so no identity leak. * * @param params - Token to consolidate (default: USDC) */ consolidate(params?: { token?: string; }): Promise; /** * Deterministically derive the b402 shield wallet address (CREATE2 smart wallet * owned by the incognito EOA, distinct from the incognito wallet itself). * * External callers (e.g. an ACP buyer) need this address as the `to` field * when signing an EIP-3009 TransferWithAuthorization that will later be * consumed by `shieldFromEOA({ from, auth })`. */ computeShieldWallet(): Promise<{ address: string; salt: string; }>; /** Shield tokens directly from the owner EOA into Railgun privacy pool. * Gasless — EOA signs EIP-2612 permit, smart wallet pulls tokens + shields via facilitator. * Useful for bootstrapping: fund EOA with USDC, shieldFromEOA, then operate privately. */ shieldFromEOA(params: ShieldParams): Promise; /** Shield tokens into Railgun privacy pool. Gasless — routes through smart wallet. */ shield(params: ShieldParams): Promise; /** Build shield calldata via Railgun SDK (heavy — starts engine, calls populateShield, stops engine). */ private buildShieldCalldata; /** Parse Shield events from TX receipt and cache locally for immediate balance availability. */ private cacheShieldFromReceipt; /** Poll for shield indexing. Backend indexes UserOp shields by smart wallet address. */ private waitForShieldIndexing; /** Check wallet balances and vault positions. */ status(): Promise; /** * Move capital to the highest-yield source across Morpho vaults AND Aerodrome LP. * Compares all yield sources and moves capital if the APY difference exceeds minApyDiff. */ rebalance(minApyDiff?: number): Promise; /** * Add liquidity to an Aerodrome pool from USDC on the smart wallet. * * SDK handles the split: swaps half USDC → WETH, then adds both as liquidity. * LP tokens are staked in the gauge to earn AERO emissions (~7.6% APY). * All calls execute in one gasless UserOp. */ addLiquidity(params: AddLiquidityParams): Promise; /** * Remove all liquidity from an Aerodrome pool. * Claims AERO rewards, unstakes from gauge, removes liquidity. * Returns WETH + USDC to the smart wallet. */ removeLiquidity(params?: RemoveLiquidityParams): Promise; /** Claim AERO rewards from gauge without removing liquidity. */ claimRewards(params?: ClaimRewardsParams): Promise; /** * Place a speed market bet (binary option) — predict UP or DOWN. * * Uses USDC from the smart wallet. Min $5, max $200. * Payout: ~2x minus fees. Auto-settled by Pyth oracle keepers. */ speedMarket(params: SpeedMarketParams): Promise; /** * Place a PRIVATE speed market bet — bet from the privacy pool. * * Flow: Pool USDC → unshield → approve + bet → shield remainder → Pool * On-chain: observer sees RelayAdapt placed a bet — no link to user. */ privateSpeedMarket(params: SpeedMarketParams): Promise; /** * Open a perpetual futures position via Synthetix V3. * * Creates account (if needed), wraps USDC → sUSDC, deposits margin, commits order. * Settlement happens automatically after ~2 blocks via Pyth keepers. */ openPerp(params: OpenPerpParams): Promise; /** * Close a perp position by committing an opposite-side order. */ closePerp(params: ClosePerpParams): Promise; /** * Open a PRIVATE perp position — fund margin from privacy pool. * * Flow: Pool USDC → unshield → wrap sUSDC → deposit margin → commit order → shield remainder * The perps account lives on the anonymous smart wallet. */ privateOpenPerp(params: OpenPerpParams): Promise; /** * Open a perp position on SynFutures V3. * * Deposits USDC margin into Gate, then trades on the instrument. * SynFutures has 65+ instruments with real volume on Base. * * @example * await b402.synfuturesTrade({ instrument: 'LINK', side: 'long', notional: '20', margin: '10' }) */ synfuturesTrade(params: SynFuturesTradeParams): Promise; /** * Close a SynFutures V3 position. * * Trades the opposite size to close, then optionally withdraws margin from Gate. */ synfuturesClose(params: SynFuturesCloseParams): Promise; /** * Open a PRIVATE SynFutures V3 perp position — fund margin from privacy pool. * * Flow: Pool USDC → unshield → approve + deposit Gate + trade → shield remainder * On-chain: observer sees RelayAdapt deposited to Gate — no link to user. */ privateSynfuturesTrade(params: SynFuturesTradeParams): Promise; /** Available SynFutures instruments */ static get synfuturesInstruments(): string[]; /** * Swap tokens privately from the privacy pool via RelayAdapt + Aerodrome. * * Flow: Pool USDC → unshield to RelayAdapt → Aerodrome swap → shield output → Pool * On-chain: observer sees "RelayAdapt called Aerodrome" — zero link to user. */ privateSwap(params: PrivateSwapParams): Promise; /** * Deposit tokens privately into a Morpho vault from the privacy pool. * * Flow: Pool USDC → unshield to RelayAdapt → approve + vault.deposit → shield shares → Pool * Share tokens (vault address as ERC20) are shielded back into the pool. */ privateLend(params: PrivateLendParams): Promise; /** * Redeem shares privately from a Morpho vault back to the privacy pool. * * Flow: Pool shares → unshield to RelayAdapt → vault.redeem → shield USDC → Pool * USDC is shielded back into the pool. */ privateRedeem(params?: PrivateRedeemParams): Promise; /** * Private cross-chain send — transfer, bridge, or bridge+swap in one atomic call. * Covers: same-token cross-chain transfer, cross-chain swap (bridge+swap), * and cross-chain payments. LI.FI picks the optimal route across ~30 bridges * and ~20 DEXes. * * Flow: * Source chain (atomic): * Pool USDC -> unshield to RelayAdapt -> approve LI.FI Diamond * -> LI.FI Diamond bridges+swaps * -> shields any remainder back to pool * Destination chain (follow-up): * Funds arrive at `destinationAddress` (derived EOA). * User/agent runs b402.shieldFromEOA on destination to complete privacy loop. * * Observer sees "RelayAdapt called LI.FI Diamond" on source; bridge fill on dest. * No link between the source shielded origin and the destination recipient. * * LI.FI picks the best tool (Across, Stargate, CCTP, Eco, NearIntents, etc.). * Charges a default 0.25% fixed fee. * * v1 limitation: source chain must match the SDK's current chain (8453 for now). * Cross-chain source selection will come in a follow-up. */ privateCrossChain(params: PrivateCrossChainParams): Promise; /** * Execute a private cross-contract call through RelayAdapt. * * Core pipeline: * 1. Derive Railgun keys * 2. Fetch UTXOs from privacy pool (smart wallet + EOA) * 3. Build shield requests for output tokens * 4. Compute adaptParams * 5. Generate ZK proof with adaptContract=RelayAdapt * 6. Build relay() transaction * 7. Submit as UserOp via facilitator * 8. Cache output shields from receipt */ private executeCrossContractCall; private getShieldedBalances; private init; private emit; /** Resolve a token symbol or address to {address, symbol, decimals} for the active chain. */ resolveToken(nameOrAddress: string): { address: string; symbol: string; decimals: number; }; static get vaults(): { name: string; fullName: string; address: string; curator: string; }[]; static get tokens(): { symbol: string; address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" | "0x4200000000000000000000000000000000000006" | "0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb" | "0x940181a94A35A4569E4529A3CDfB74e38FD98631" | "0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2"; decimals: 6 | 18; }[]; static get pools(): { name: string; fullName: any; poolAddress: any; gaugeAddress: any; }[]; static get perpMarkets(): { symbol: string; marketId: number; }[]; static get speedMarketAssets(): string[]; execute(params: Extract): Promise; } export type ExecuteParams = ({ action: 'privateSwap'; } & PrivateSwapParams) | ({ action: 'privateLend'; } & PrivateLendParams) | ({ action: 'privateRedeem'; } & PrivateRedeemParams) | ({ action: 'privateCrossChain'; } & PrivateCrossChainParams) | ({ action: 'shield'; } & ShieldParams) | ({ action: 'unshield'; } & UnshieldParams); export interface ExecuteResultMap { privateSwap: PrivateSwapResult; privateLend: PrivateLendResult; privateRedeem: PrivateRedeemResult; privateCrossChain: PrivateCrossChainResult; shield: ShieldResult; unshield: UnshieldResult; } export type ExecuteResult = ExecuteResultMap[keyof ExecuteResultMap]; export { BASE_TOKENS, BASE_CONTRACTS } from './types'; export { MORPHO_VAULTS } from './lend/morpho-vaults';