Skip to main content

Self-Custodial Model

Circuit never takes custody of user funds. Private keys live in a secure enclave (KMS) completely separate from agent code. Agents can only request transactions - signing happens outside the agent sandbox. Agent code never sees private keys, users can export their wallet at any time, and all transactions are visible onchain.

Wallet VM Families

Agents declare their required wallet VM family in circuit.toml:
  • "evm" - EVM-compatible networks (Ethereum, Polygon, Arbitrum, Base, Hyperliquid, etc.)
  • "svm" - SVM-compatible networks (currently Solana)
An agent can only run on wallets matching its walletVmFamily.

Starting Asset

Every agent defines a startingAsset in circuit.toml - the token a user must hold to start a session:
  • network - The chain where the asset lives (Network Identifiers)
  • address - Token contract address. For native tokens: "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" (EVM) or "11111111111111111111111111111111" (Solana)
  • minimumAmount - Minimum balance required in raw units (wei, lamports, etc.). Hyperliquid hypercore:perp + USDC uses 8 decimal places in Circuit (not EVM USDC’s 6); see Hyperliquid.

How Allocation Works

When a user starts a session:
  1. The user chooses an exact starting-asset quantity (minimumAmount is the agent’s recommended minimum)
  2. Circuit requires that quantity to exist in recorded wallet money after other unreleased session allocations, then appends the session allocation in the start transaction
  3. Each claimed invocation builds agent.allocation from that session’s allocation and recorded transaction/venue events
Hyperliquid agents allocate the same way: you allocate a portion of the wallet’s Hyperliquid USDC collateral to the session, and multiple Hyperliquid agents can share one wallet - each draws from the unallocated remainder. Because a shared wallet nets positions at the account level, agents on the same wallet share liquidation risk, so size and monitor positions accordingly.

Positions

The invocation allocation contains:
  • allocation.balances - fungible inventory the session holds outright: cash, spot tokens, staking, Polymarket pUSD cash, and Kraken’s synthetic available cash plus base-asset inventory.
  • allocation.positions - open market exposures: Hyperliquid perps (signed sizes) and Polymarket outcome-token positions (enriched with polymarketMetadata). Tell them apart by whether polymarketMetadata is present.
Important: the field is one immutable invocation-start snapshot. Track effects locally when a later step in the same invocation depends on an earlier action; the next invocation receives committed top-ups and observed transaction/venue events. Do not mirror balances across invocations. Hyperliquid note: This session’s deployable perp cash at invocation start is the agent.allocation.balances entry carrying hyperliquidMetadata.collateral, and its open perps are in agent.allocation.positions (with leverage / liquidation price / margin used under hyperliquidMetadata). The cash amount includes locked margin and excludes unrealized PnL; session collateral = cash + Σ positions’ unrealizedPnlUsd, and free margin ≈ session collateral − Σ marginUsed. Size from the allocation - never a whole-wallet read, which on a shared wallet would overspend the other sessions sharing it. See Hyperliquid. Kraken note: Match a base-inventory balance by tokenAddress and size sells from its exact krakenMetadata.availableBaseVolume. The same fungible base inventory backs either supported quote pair. The credential-wide balance includes other sessions and is never ownership authority. No matching allocation entry means zero inventory for that base. See Kraken.

Units

  • Onchain transaction, swap, and allocation amounts are strings in smallest units (wei/token base units for EVM, lamports for Solana). Keep them as strings to preserve precision.
  • Never size an amount through float math (parseFloat, Math.round(usd * 1e6), Number(amountRaw) / 10 ** decimals). Use the SDK’s exact converter pair — decimalToBaseUnits(decimal, decimals) / baseUnitsToDecimal(raw, decimals) (decimal_to_base_units / base_units_to_decimal in Python) — and bigint/int arithmetic on raw units. Spend-all is the allocation entry’s amountRaw, verbatim.
  • The engine rejects an agent swap or transfer whose amount exceeds the session’s attributed inventory for that asset, so sizing from anything other than agent.allocation fails at admission.
  • Hyperliquid order sizes and prices are formatted numbers; its allocation fields remain raw string amounts.
  • Kraken amounts are decimal strings in venue units. Polymarket orders use unit-explicit numbers: spendUsd for buys and shares for sells.

See Also