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 on-chain.

Wallet Types

Agents declare their required wallet type in circuit.toml:
  • "ethereum" — EVM-compatible chains (Ethereum, Polygon, Arbitrum, Base, etc.)
  • "solana" — Solana
An agent can only run on wallets matching its walletType.

Starting Asset

Every agent defines a startingAsset in circuit.toml — the token a user must hold to start a session:
[startingAsset]
network = "ethereum:137"
address = "0x2791bca1f2de4661ed88a30c99a7a9449aa84174"  # USDC on Polygon
minimumAmount = "1000000"  # 1 USDC (6 decimals)
  • 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.)

How Allocation Works

When a user starts a session:
  1. Circuit verifies the user holds at least minimumAmount of the starting asset
  2. The specified amount is allocated to the agent session
  3. The agent receives these allocations as agent.currentPositions
Hyperliquid exception: For Hyperliquid agents, the entire wallet balance is available to the agent (not just an allocated portion). This is because Circuit restricts one Hyperliquid agent per wallet to safely manage margin requirements.

Positions

MethodWhen to Use
agent.currentPositionsSnapshot at execution start. Fast, no API call. Use for initial decision-making.
getCurrentPositions() / get_current_positions()Live balances. Makes an API call. Use after transactions to verify updated state.
Important: After executing transactions, currentPositions will be stale. Call getCurrentPositions() if you need updated balances within the same run cycle. Hyperliquid note: Use agent.platforms.hyperliquid.balances() and agent.platforms.hyperliquid.positions() instead of currentPositions for Hyperliquid agents. See Hyperliquid.

Pending Transactions

The getCurrentPositions() response includes a hasPendingTxs flag. When true, balances may not reflect recent transactions due to indexing delay (varies by chain). For time-sensitive logic, track position changes in Memory instead of polling.

Units

  • All amounts are strings in smallest units (wei for EVM, lamports for Solana)
  • Keep amounts as strings to preserve precision for large values
  • Hyperliquid exception: Amounts are formatted values (e.g., "1.5" for $1.50 USDC), not raw units

See Also