Torii Wallet contracts#
One vault contract per mandate, created by a factory. Base Sepolia (chain 84532) only. Testnet: cleared for testnet by audit R2; a mainnet list is open.
Addresses#
| Item | Address |
|---|---|
| ToriiMandateFactory | 0x39e8a6dba45983c779C8A249fca40f2026a2f873 |
| ToriiMandate implementation | 0xB63F6Aba4d4147dCF364f0E8B145630b123dd7f8 |
| USDC (Base Sepolia) | 0x036CbD53842c5426634e7929541eC2318f3dCF7e |
| First rehearsal vault (stopped, withdrawn) | 0x128Ba6B938789EB5F0bf1Ec3bcc8D8f957B0CB8E |
Hosted rehearsal vault, mandate m_irifvvp7rr (stopped, withdrawn) | 0x06b6da180D35b27997cC2f57731d66beee86fa39 |
The factory address is read from TW_MANDATE_FACTORY_ADDRESS on the API host. While it is unset, no vault exists and no money moves. This table is filled from deployments/base-sepolia.json. The rehearsal vault was created, funded with 1 USDC, paused, resumed, stopped and emptied on 2026-10-13 (64 of 64 checks, transactions in the testnet runbook section 7); it is a record, not a live vault. The same day a second vault was made through the production API (10 USDC deposited, paused, stopped and withdrawn, vault balance 0; transactions in the testnet runbook section 7b); it is also a record.
Roles#
| Role | Who | Can | Cannot |
|---|---|---|---|
owner | The person | create (own mandates only), deposit, stop (also revokes the agent), withdrawAll when allowed, revokeAgent, setAgent, setFeeRecipient (draft only), removeTarget, unwind and rescueToken after close | Add targets; change caps, floor or fee after creation |
agent | A session signer | execute inside the caps while live; unwind after close on still-allowed targets (USDC may not go down; an agent unwind must raise it) | Stop, withdraw, mark, settle, touch USDC or the mandate as a target |
keeper | The house; read live from the factory; rotated in two steps | markWorth, stop, settle (fee at most bps times on-chain profit) | Withdraw, execute, change limits |
| factory admin | The house | Grant and revoke roles | Touch any existing mandate or funds |
| pauser | The house, a separate key | setPaused (blocks new mandates only) | Anything else |
| keeper admin | The house, a separate key | proposeKeeper, cancelKeeper | Make a keeper live before keeperDelay (at least 1 day) |
Parameters, fixed at creation#
perTxCap, dailyCap (rolling 24 hours, 24 hourly buckets), stopFloor (absolute USDC units), endsAt, allowedTargets[] (at most 16, never USDC or the mandate itself), agentFeeBps (at most 2000). USDC amounts are 6-decimal base units. The factory requires a 6-decimal USDC.
What the contract enforces#
- Per-transaction cap, measured as the vault's USDC drop across the call, not parsed from calldata.
- Rolling daily cap in hourly steps. At worst about twice the cap can leave inside one 24-hour stretch.
- Allowed targets.
execute(target, data, approveAmount)approves exactlyapproveAmountfor one call and resets it to 0 in the same transaction. - The end time.
- The stop line: when the keeper marks worth below
stopFloor, trading stops and the owner maywithdrawAll. A floor stop or keeper stop keeps the agent so it canunwind; an ownerstop()also revokes the agent. - One settlement, only after
endsAtor a stop. The agent fee is clamped to on-chain profit (balance - (deposited - withdrawn)). - Owner-only withdraw. Withdraw opens after a stop, after settlement, or one day after
endsAt. - Agent revoke and
setAgent. - Deposits are counted by balance change, and only through
deposit(). A plain transfer to the vault is not a deposit.
What the contract does not do#
| The chain enforces | The API only records or derives |
|---|---|
| Caps, targets, end time, stop on a floor mark, one settle, owner-only withdraw, agent revoke | Purpose text, payout wording, worth between marks, realized gain computation (the keeper passes it to settle), the four-state balance view, progress, anything about non-USDC assets |
The daily cap limits how much can leave the vault, not what is lost at a venue the owner allowed. A target that holds value is a counterparty risk the owner accepted.
Trust assumptions (v1)#
The keeper is trusted for worth marks and settlement. On testnet one key holds every role; mainnet must split them. The keeper delay is immutable and at least one day.
Audits#
| Round | Result |
|---|---|
| R1 | 2 High, 4 Medium found; fixed in the R1 fix pass (unwind, settle clamp, atomic execute, owner-only create, two-step keeper) |
| R2 | Cleared for Base Sepolia; the Medium (owner stop did not stop the agent) and the Low (keeper delay of zero) were fixed |
Sources (internal, not served here): ops/TORII_MANDATE_CONTRACTS.md, ops/TORII_TESTNET_DEPLOY.md, ops/TORII_AUDIT_R1.md, ops/TORII_AUDIT_R2.md.
Parked#
The Torii dollar (tUSD) reserve and token were parked on 2026-10-11. They are not part of the product and are not deployed.