Guardrails and the vault
What the contract enforces, whatever the agent decides.
Each program has its own MisthosVault, a small contract that holds the program's USDC. The agent decides who earned
what. The vault decides what can actually be paid.
Roles
| Role | Who | Can |
|---|---|---|
| Owner | Your wallet | Deposit, withdraw (even while paused), set limits, pause, approve rounds, cancel rounds, replace the agent or guardian, transfer ownership. |
| Agent | The Misthos agent's Circle wallet | Register payout wallets, propose rounds, execute rounds. Nothing else. |
| Guardian | Optional, set by you | Pause the vault and cancel rounds. Can't move funds. |
Limits
Set when you create the program, changeable at any time from Settings (one transaction).
| Limit | Enforced as |
|---|---|
| Max per payout | No single payout in a round may exceed it. Over it, proposeRound reverts with PayoutTooLarge. |
| Max per round | The round's total may not exceed it (RoundTooLarge). |
| Max per rolling 24h | Paid in the last 24 hours plus this round may not exceed it (DailyCapExceeded), checked again at execution. |
| Approval threshold | Rounds with a larger total wait for the owner's approveRound (ApprovalRequired). The vault checks it per round; the agent also waits for you once its auto-paid rounds in the last 24 h pass it. |
| Payee cooldown | A newly registered or changed payout wallet can't be paid until the cooldown ends (PayeeInCooldown). |
The vault accepts up to 200 payouts per round; the agent puts at most 50 in one, so each transaction stays well under Arc's 30M block gas limit, and carries the rest to the next round. Execution re-checks every payout against the limits and payout wallets as they are at that moment, so lowering a limit or pausing takes effect even for a round that was already proposed.
If the agent were compromised, the most it could pay out is maxPerDay per day until you pause the vault. The
approval threshold is checked per round on-chain, so a rogue agent could split payouts into rounds just under it.
Set maxPerDay to what you're prepared to lose in a day.
Exactly once
Every payout has a fixed id, keccak256(abi.encode(programId, roundId, contributorId)). The vault records it when
paid and never resets it (AlreadyPaid, DuplicatePayout). The agent's transactions also carry deterministic Circle
idempotency keys, so a retried job gets the original transaction back instead of sending a second one. Before the
worker ever marks a round failed it reads the round on-chain: if it was executed, it's recorded as paid; if it's
still proposed, it's cancelled on-chain first. Items are released for another round only when the vault confirms
they weren't paid.
If one payee can't be paid (their wallet changed after planning, or the token refuses the transfer), the worker cancels the round on-chain and re-plans it without them, so everyone else is paid; the dropped item carries over. A contributor's wallet change waits while one of their payouts is in a round.
Only one worker run may process a round at a time (a lease in the database, renewed before every transaction), so two workers, for example the old and new one during a deploy, can't act on the same round. If the vault holds less than the round pays, the round shows Vault needs funds, keeps your approval, and pays as soon as you deposit.
Tested
The contracts have unit tests for every function and revert path, fuzz tests of every cap (1,024 runs each), and invariant tests: paid plus withdrawn never exceeds deposited, a payout id is paid at most once, and only the owner or agent can move funds.
Deployed contracts
Arc testnet (chain id 5042002). Both contracts are verified on the explorer.
| Contract | Address |
|---|---|
| MisthosVaultFactory | 0x19afd6fCeb49A333B3b3b455A26e6ee43db8849b |
| MisthosVault (implementation) | 0xbB016FeB193c9F1151e77444a2145c5dfAA965D7 |
| Agent wallet (Circle smart-contract wallet) | 0x74a60caa5e6c14a33be4ebf1507a209ac61b78a1 |
| USDC (Arc testnet) | 0x3600000000000000000000000000000000000000 |
Program vaults are minimal clones of the implementation, created by the factory at a deterministic address per owner and program.