@moneolabs/wallet

An account per agent,
with keys it never sees.

Agents leak. They paste their context into logs, into tools, into other models. So the wallet is built on the assumption that anything the agent can read is already public: it holds a handle, and the signature happens somewhere it cannot reach.

import { createWallet, localSigner, memoryRail } from "@moneolabs/wallet";
 
const wallet = await createWallet({
agent: "research-agent-01",
signer: localSigner(),
rail: memoryRail(),
asset: "USDG",
guard,
funding: "500 USDG",
});
 
// The agent receives a handle. There is no key to leak.
// → wallet.id "wlt_3m9Qz…"
// → wallet.address "0x4a91…c7d2"
No API key and no account. The signer and the rail are objects you supply, so the whole thing runs in your process.
Custody

Pick how much of the key you want to hold.

tee-signerDefault

Keys are generated and used inside an attested enclave. Moneo can sign on the agent's behalf but cannot export the key, and attestation is verifiable from your side.

mpc-2-of-3Shared

Three shares: one held by you, one by Moneo, one in cold backup. Two must cooperate to sign, so neither party can move funds alone.

byo-kmsSelf-custody

Point the SDK at your own KMS or HSM. Moneo builds and simulates the transaction, your infrastructure produces the signature.

Surface

Eight calls do the work.

createWallet()Issue an account bound to one agent identity
wallet.balance()What the rail holds for this wallet
wallet.available()Balance minus anything the guard has reserved
wallet.preflight()Ask whether a payment would pass, without making it
wallet.pay()Pay an address, an invoice, or an x402 endpoint
wallet.fund()Move budget in, when the rail can credit
wallet.sweep()Return idle balance above a floor you set
wallet.history()Signed, attributable record of every movement
Wallet ledger
Agent
research-01
Custody
tee-signer
Network
robinhood-mainnet
Balance
$486.32
24h spent
$119.68
Key exposure
none
Spend Guard · built in

Policy runs between intent and signature.

The guard ships inside the wallet and runs before every signature. A refusal is a structured value with a reason, never a fee, and every verdict lands in the decision ledger with the policy version that decided.

Caps

A ceiling per transaction, per counterparty, per asset class. The smallest useful policy is one line and stops the worst outcome.

Budgets

Rolling windows rather than calendar months. A stuck retry loop burns the budget, then stops, instead of the balance.

Allowlists

Counterparties by address, domain, x402 endpoint, or merchant ID. Deny by default is the sane setting when the caller is a language model.

Velocity

Rate limits on money, not requests. Ten payments a minute to the same address is a bug signature, whatever the amounts look like.

Escalation

Above a threshold, the action pauses and a human approves it in Slack, email, or your own webhook. The agent gets a pending handle, not a failure.

Simulation

Replay a proposed policy against last month's ledger before shipping it. See what would have been blocked, and what it would have cost you.

Decision ledger

research-01pay · x402 market data$0.04Allowunder micro-payment floor
research-01pay · x402 market data$0.04Allow142 calls today · $5.68 of $50 cap
ops-03trade · USDG → $TSLAx$1,500.00Allowtwap 30m · slippage 0.11% · venue verified
ops-03transfer · 0x9f3c…a71b$8,200.00Blockexceeds $2,000 rolling 24h budget · nothing signed
growth-02subscribe · vendor invoice$99.00Holdnew counterparty · awaiting human approval
ops-03trade · USDG → $AAPLx$240.00Blockcounterparty not on allowlist · unverified contract
Execution · built in

Execution with the exit attached.

Tokenized equities on Robinhood Chain, quoted across verified venues, with every fill routed through the same guard as a payment.

Slippage bound

Every order carries a maximum. Exceeded means rejected, never silently filled worse.

Order types

Market, limit, TWAP, and bracket — entry with the take-profit and stop attached at submission, so an unattended run has an exit.

Position caps

Concentration limits per symbol and per agent, enforced at submission time.

Guarded settlement

Notional passes the spend guard before signing, exactly like a payment does.

The alternative

Why not just hand it the exchange API?

Because the API assumes the caller is you. An agent trading unattended needs a layer that assumes the opposite: that the caller leaks, loops, and never sleeps.

The key

Raw exchange API · An API key with full account access sits in the model's context, one pasted log away from public.

Behind Moneo · The model holds a handle. The key lives in a TEE or an MPC quorum it cannot read from.

A bad loop

Raw exchange API · A stuck retry loop trades until the balance is gone or you wake up.

Behind Moneo · The loop burns its rolling budget, then every attempt comes back blocked, with a reason.

Position size

Raw exchange API · Whatever the account can afford is what the agent can concentrate into one symbol.

Behind Moneo · Per-symbol and per-agent caps are enforced at submission, before any order exists.

A bad fill

Raw exchange API · Thin liquidity fills you anyway, and you find out from the statement.

Behind Moneo · Every order carries a slippage bound. Exceeded means rejected, never filled worse.

The exit

Raw exchange API · Stop logic is code you write, hosted somewhere that has to stay awake.

Behind Moneo · Brackets attach the take-profit and the stop at submission. The exit ships with the entry.

The record

Raw exchange API · A list of fills. What the agent tried and was refused is nowhere.

Behind Moneo · Every attempt, verdict and reason included, attributable to one agent and one policy version.

How it works

Four steps from an agent that asks to an agent that pays.

Nothing here is a migration. Each step is a call you add next to the code you already have.

01

Write the policy

Declare what this agent may do with money: caps per transaction, a rolling budget, who it can pay, what it can trade, and the threshold where a human has to say yes.

02

Issue the wallet

One call creates a funded account for a named agent, with the policy already attached. Custody is a TEE signer, an MPC quorum, or your own KMS. Nothing about the key material crosses into the model's context.

03

Hand it the tools

Expose the SDK to your agent over MCP or plain function calling. It sees pay, swap, quote, balance, and gets a structured refusal when policy says no.

04

Read the ledger

Every attempt is recorded with its verdict and reason, attributable to one agent, one run, one policy version. Reconciliation stops being archaeology.

Roughly twenty lines to a funded agent.

Start on the sandbox ledger with test funds. Flip one flag when you want it real.

Read the docs