Skip to main content

Install

npm install @b402/sdk

Quick Start

import { B402 } from '@b402/sdk'

const b402 = new B402({
  privateKey: process.env.PRIVATE_KEY,
})
One key. The b402 facilitator handles gas, wallet deployment, and UserOp submission.
Your privateKey derives a deterministic incognito wallet — cryptographically unlinkable to any other address. The facilitator sponsors gas via paymaster. You pay $0.

The Privacy Flow

Tokens enter the privacy pool, then exit untraceable to your smart wallet.
EOA → [shield] → Privacy Pool → [unshield] → Smart Wallet → [DeFi]
         ↑                           ↑                          ↑
    One-time setup           ZK proof breaks          Gasless via
    (needs gas)              the funding link          facilitator

Step 1: Shield — Enter the Privacy Pool

Move tokens from your EOA into the privacy pool. After this, nobody can trace where the tokens came from.
const shield = await b402.shield({ token: 'USDC', amount: '100' })
console.log(shield.txHash) // 0x...
// Tokens are now in the privacy pool — untraceable

Step 2: Unshield — Exit to Smart Wallet

Pull tokens from the privacy pool to your anonymous smart wallet. A ZK proof is generated client-side — proving you own the tokens without revealing the deposit.
const unshield = await b402.unshield({ token: 'USDC', amount: '50' })
console.log(unshield.txHash)  // 0x...
// USDC is now on your smart wallet, funding source hidden

Step 3: DeFi — Swap, Lend, Yield

Execute DeFi operations from the smart wallet. All gasless via facilitator.
// Swap USDC → WETH
const swap = await b402.swap({ from: 'USDC', to: 'WETH', amount: '10' })

// Earn yield anonymously in Morpho vault
await b402.lend({ token: 'USDC', amount: '100', vault: 'steakhouse' })

// Withdraw
const redeem = await b402.redeem({ vault: 'steakhouse' })

Step 4: Execute Anything

Run arbitrary calls through your smart wallet — any contract, any function.
const result = await b402.transact([
  { to: '0xTokenAddr', value: '0', data: '0xapproveCalldata...' },
  { to: '0xProtocol',  value: '0', data: '0xactionCalldata...' },
])
console.log(result.txHash)

Full API

shield(params) — Enter Privacy Pool

Deposit tokens from your EOA into the privacy pool. This is the onboarding step — it breaks the on-chain link between your real wallet and smart wallet.
const result = await b402.shield({ token: 'USDC', amount: '100' })
ParamTypeRequiredDescription
tokenstringYesToken symbol (USDC or USDT on Base)
amountstringYesAmount to shield
Returns: { txHash: string, indexed: boolean }
Shield sends a transaction from your master EOA — requires the EOA to hold tokens + ETH for gas. Indexing takes 1-3 minutes. The SDK polls automatically and returns once indexed.

unshield(params) — Exit Privacy Pool

Withdraw tokens from the privacy pool to your anonymous smart wallet. Generates a ZK proof client-side (Groth16) proving ownership without revealing the deposit.
const result = await b402.unshield({ token: 'USDC', amount: '50' })
ParamTypeRequiredDescription
tokenstringYesToken to unshield
amountstringYesAmount to unshield
Returns: { txHash: string, proofTimeSeconds: number }
ZK proof generation takes 5-15 seconds depending on hardware. The proof is generated entirely client-side — your private key never leaves your machine.

transact(calls) — Execute Arbitrary Calls

Send any batch of calls through your smart wallet via the facilitator. Gasless — paymaster sponsors gas.
import { ethers } from 'ethers'

const erc20 = new ethers.Interface(['function transfer(address to, uint256 amount)'])

const result = await b402.transact([
  {
    to: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // USDC
    value: '0',
    data: erc20.encodeFunctionData('transfer', ['0xRecipient', ethers.parseUnits('10', 6)]),
  },
])
console.log(result.txHash)
ParamTypeRequiredDescription
callsCall[]YesArray of { to, value, data }
Returns: { txHash: string } This is the low-level primitive. swap(), lend(), and redeem() are built on top of transact().

swap(params) — Private Token Swap

Swap tokens via 0x aggregator. Requires zeroXApiKey.
const b402 = new B402({
  privateKey: '0x...',
  zeroXApiKey: process.env.ZERO_X_API_KEY,
})

const result = await b402.swap({
  from: 'USDC',
  to: 'WETH',
  amount: '10',
  slippageBps: 100, // 1% default
})
ParamTypeRequiredDescription
fromstringYesSell token symbol
tostringYesBuy token symbol
amountstringYesHuman-readable amount
slippageBpsnumberNoSlippage in bps (default: 100 = 1%)
Returns: { txHash, amountIn, amountOut, tokenIn, tokenOut }

lend(params) — Private Lending

Deposit tokens into a Morpho ERC-4626 vault.
await b402.lend({ token: 'USDC', amount: '100', vault: 'steakhouse' })
ParamTypeRequiredDescription
tokenstringYesToken to deposit
amountstringYesHuman-readable amount
vaultstringNoVault name (default: steakhouse)
Returns: { txHash, amount, vault }

Available Vaults

VaultNameAPY
steakhouseSteakhouse USDC4-6%
moonwellMoonwell Flagship USDC3-5%
gauntletGauntlet USDC Prime4-6%
steakhouse-hySteakhouse High Yield USDC6-8%

redeem(params) — Withdraw from Vault

const result = await b402.redeem({ vault: 'steakhouse' })
console.log(result.assetsReceived) // '100.23' USDC
ParamTypeRequiredDescription
vaultstringNoVault name (default: steakhouse)
sharesstringNoShares to redeem (default: all)
Returns: { txHash, assetsReceived, vault }

rebalance(minApyDiff?) — Auto-Rebalance

Move capital to the highest-yield vault.
const result = await b402.rebalance(0.5) // min 0.5% APY diff
Returns: { action: 'rebalanced' | 'no-change', currentVault, bestVault, txHash }

status() — Check Wallet

const status = await b402.status()
Returns:
{
  ownerEOA: '0x0001Dc...',       // Incognito EOA (derived, unlinkable)
  smartWallet: '0x6CdF29...',    // Smart wallet address
  deployed: true,
  chain: 'base',
  balances: [{ token: 'USDC', balance: '50.0' }],
  positions: [{ vault: 'steakhouse', assets: '100.5 USDC', apyEstimate: '4-6%' }],
}

How It Works

Wallet Derivation

privateKey
  → sign("b402 Incognito EOA Derivation")
  → keccak256(signature)
  → incognitoPrivateKey
  → Wallet(incognitoPrivateKey)
  → incognitoEOA (deterministic, unlinkable)

incognitoEOA
  → salt = keccak256("b402-incognito-" + eoa.toLowerCase())
  → NexusFactory.computeAccountAddress(initData, salt)
  → smartWallet (CREATE2, deployed on first use)

Execution Flow (Facilitator)

SDK builds calls[] → POST /verify → facilitator builds UserOp + paymaster sig
  → SDK signs userOpHash with incognito wallet
  → POST /settle → facilitator submits to bundler → relayer pays gas

ZK Proof Flow (Shield / Unshield)

Shield:    EOA → approve → populateShield() → send tx → wait for indexing
Unshield:  deriveKeys → fetchUTXOs → buildProofInputs → generateProof → buildUnshieldTx
Proofs are Groth16 (snarkjs), generated entirely client-side. Your private key never leaves your machine.

What’s Visible vs Hidden

Visible On-ChainHidden
Smart wallet addressWho owns it
DeFi action + amountFunding source (privacy pool)
Block numberOperator’s real EOA
Paymaster sponsorshipLink between shield and unshield

Constructor

new B402(config: B402Config)
ParamTypeRequiredDescription
privateKeystringYesOperator private key. Derives anonymous smart wallet.
zeroXApiKeystringNo0x API key. Required for swap().
rpcUrlstringNoBase RPC URL. Default: https://mainnet.base.org
facilitatorUrlstringNob402 facilitator URL. Default: production.
onProgressfunctionNoProgress callback for step updates.

Progress Tracking

const b402 = new B402({
  privateKey: '0x...',
  onProgress: (event) => {
    if (event.type === 'step') console.log(`[${event.step}/${event.totalSteps}] ${event.title}`)
    else if (event.type === 'done') console.log(`Done: ${event.message}`)
    else if (event.type === 'info') console.log(`${event.title}: ${event.message}`)
  },
})

Static Helpers

B402.vaults  // [{ name, fullName, address, curator }]
B402.tokens  // [{ symbol, address, decimals }]

Constants

import { BASE_TOKENS, BASE_CONTRACTS } from '@b402/sdk'

BASE_TOKENS.USDC.address       // '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913'
BASE_CONTRACTS.RAILGUN_RELAY   // '0x26111e2379E5fC0A7Cd8728fe52c7b84CA4fbE85'

Network

Base Mainnet (chain ID 8453). All operations use real tokens.
ContractAddress
Railgun Relay0x26111e2379E5fC0A7Cd8728fe52c7b84CA4fbE85
EntryPoint v0.70x0000000071727De22E5E9d8BAf0edAc6f37da032
Nexus Factory0x0000006648ED9B2B842552BE63Af870bC74af837
Facilitatorhttps://facilitatorv3.b402.ai

Fees

Gas for all DeFi operations is sponsored by the facilitator. The standard b402 protocol fees apply to payments — see Fee Structure for details.
FeeAmount
Gas (DeFi ops)$0.00 (facilitator-sponsored)
ShieldETH gas on EOA (one-time onboarding)
SwapDEX fee (varies by pair)
Lend / Redeem0%
Privacy pool unshield$0.00 (included in protocol fee)

Error Handling

try {
  await b402.swap({ from: 'USDC', to: 'WETH', amount: '10' })
} catch (err) {
  console.error('Failed:', err.message)
}
ErrorFix
zeroXApiKey required for swapsPass zeroXApiKey in constructor
Unknown token: XShield: USDC. Swaps: any token supported by the DEX (e.g. USDC, WETH, DAI)
Unknown vault: XUse: steakhouse, moonwell, gauntlet, steakhouse-hy
No shares in XNo position — deposit first with lend()
Insufficient balanceShield more tokens or check EOA balance
Facilitator verify failedCheck facilitator health, try again