Custody & control
Custody is the heart of Olbos. The claim — "the engine cannot steal your funds" — is not a promise, a policy, or a ToS clause. It is a property the Solana runtime enforces, that anyone can verify by reading the on-chain role. This doc explains exactly how.
The building block: a Swig smart account
Olbos uses Swig (by Anagram), a smart-wallet program with a role-based authority model. A Swig account holds a set of roles; each role has an authority (a public key) and a set of actions it's permitted. Crucially:
- Role 0 is root and immutable. The Swig program forbids removing or updating
role 0 (on-chain errors
PermissionDeniedCannotRemoveRootAuthority/...CannotUpdateRootAuthority). Whoever is root stays root. - Actions can be scoped precisely: a role can be permitted only to compose instructions for a specific program, only to spend a specific token up to a recurring limit, and so on.
- Assets in a v2 Swig live at a separate wallet PDA (
getSwigWalletAddress), which signs CPIs — not at the Swig account itself.
One Swig per strategy
Every strategy gets its own Swig account. This delivers two things at once:
- Custody — the owner controls the funds.
- Isolation — no commingling. Two agents funding two strategies have two separate Swig wallets; positions can never cross.
The role layout
| Role | Authority | Actions |
|---|---|---|
| 0 (root) | the owner (the funding agent's wallet) | all — full control, immutable |
| scoped | the Olbos engine | venue programs + USDC cap + receipt mints (see below) |
The engine's role is granted exactly:
programLimit(venue programs) → may ONLY compose instructions for
approved venues (Kamino, Marginfi)
tokenRecurringLimit(USDC, cap/24h) → may move ≤ the policy's daily cap of
USDC per ~24h window
tokenRecurringLimit(receipt mints) → may spend kTokens/shares to unwind
positionsAnd — by deliberate omission — the role does not include the SPL token program in its scope. The engine therefore has no ability to transfer tokens to an arbitrary address. It can deposit into venues and unwind from them; it cannot send funds out to anyone, the owner included.
The daily cap comes from the policy (custodyDailyCapUsdc: $10k / $100k / $1M for
conservative / balanced / aggressive). It is enforced on-chain by the Swig
program — even a fully compromised engine cannot exceed it.
Two-phase creation: why the owner must sign
Granting the engine a role is delegation, and delegation cryptographically requires the root's consent. You cannot bootstrap the engine as root and have it renounce later — role 0 is immutable, so it can never be removed. The owner must be root from the very first instruction. Hence two phases:
init— the engine creates the Swig with the owner as root. The engine pays the account's rent (so the owner never needs SOL — agents hold USDC, not gas), but holds no role at all. (custody.createdis not yet emitted; a strategy that could hold funds without its final role layout must never be announced.)activate— the engine builds a transaction granting itself the scoped role, pre-signs it as fee payer, and hands it to the owner to sign. The owner's single signature is the delegation. In x402 mode the SDK signs this automatically with the same keypair that paid — sodeployStrategyfeels like one call. Only when the owner's signature lands and the on-chain role layout is verified does the engine emitcustody.created.
The result: there is no window in which the engine outranks the owner. The owner is root from birth; the engine is a tenant the owner invited in.
Funding is gated on
custody.created. Capital can only ever arrive into the final, owner-rooted layout. A fund call against a strategy whose activation hasn't landed returns409 custody pending.
How the engine acts: sign-wrapping
When the strategy runtime needs to deposit or withdraw, it builds the venue
instructions and asks custody to wrap them: the engine's scoped role signs
them through the Swig's sign instruction. The Swig program then checks, at
execution time, that every wrapped instruction is within the role's scope — and
rejects the whole transaction if not. The runtime re-fetches the role on every
wrap, because the owner can change or revoke it at any moment.
Withdrawals: the owner signs the exit
Because the engine has no transfer power, getting USDC out of the Swig requires the owner's root authority. The withdrawal flow:
- The engine unwinds positions back to liquid USDC inside the Swig (this it can do — it's within venue scope).
- The engine builds a transfer from the Swig wallet to the owner's USDC account, signs it under the owner's root role, and fee-pays it.
- The owner's key signs the transfer (the SDK does this invisibly when the payer is the owner). The funds land in the owner's wallet.
The engine builds and pays; only the owner's signature moves value out. Agents pay, owners sign, owners withdraw.
Break-glass: two ways to stop the engine
Kill switch (fast, reversible)
A wallet-signed message (olbos:kill:<strategyId>:<ts>, valid ±300s) halts all
activity for a strategy. The engine refuses every action until an unkill (also
signed) clears it. The dashboard's hold-to-seal torc ring is exactly this. Kill
state lives in the event log, so even a restarted engine stays halted.
On-chain revoke (terminal, API-independent)
The strongest control: the owner removes the engine's role from the Swig on-chain. After this, the engine's scoped role no longer exists — it cannot touch the strategy's funds at all, and only the owner's root key can move them.
The critical property: this does not depend on Olbos. The owner can revoke
with any Swig tooling, directly against the Swig program, even if the Olbos API is
down, compromised, or gone forever. Olbos offers to build and fee-pay the revoke
as a convenience (revokeCustody in the SDK, revoke_engine_custody in owner MCP
sessions), but the owner never needs Olbos to exercise it. That independence is
the real promise of the architecture.
Owner authentication
Break-glass is gated by wallet signature, never a shared secret. The owner recorded at deploy is a public key; kill/unkill/revoke require an ed25519 signature from that key. (On the localnet dev rail a shared token is accepted for the demo dashboard; on the x402 rail the signature is the only door.) See Security — owner auth.
What "you hold your keys" really means here
Post-custody, you never hand Olbos a private key, and you never hand Olbos unilateral control of funds:
- Keys never leave your machine. The SDK signs locally.
- Funds sit in a Swig where you are root and the engine holds a revocable, capped, transfer-less role.
- Exit is always available: revoke on-chain and walk away with everything, with or without Olbos's cooperation.
This is verified, not asserted — see the rug test.
Next: Security model · Payments.
