Misthos

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

RoleWhoCan
OwnerYour walletDeposit, withdraw (even while paused), set limits, pause, approve rounds, cancel rounds, replace the agent or guardian, transfer ownership.
AgentThe Misthos agent's Circle walletRegister payout wallets, propose rounds, execute rounds. Nothing else.
GuardianOptional, set by youPause the vault and cancel rounds. Can't move funds.

Limits

Set when you create the program, changeable at any time from Settings (one transaction).

LimitEnforced as
Max per payoutNo single payout in a round may exceed it. Over it, proposeRound reverts with PayoutTooLarge.
Max per roundThe round's total may not exceed it (RoundTooLarge).
Max per rolling 24hPaid in the last 24 hours plus this round may not exceed it (DailyCapExceeded), checked again at execution.
Approval thresholdRounds 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 cooldownA 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.

ContractAddress
MisthosVaultFactory0x19afd6fCeb49A333B3b3b455A26e6ee43db8849b
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.