For Safe accounts · agents · autonomous commerce
Safe decides whether your agent may spend. Recourse decides on what terms.
A Safe with a Roles policy tells an agent which contracts and amounts it may touch. It says nothing about what happens when the agent pays for work that doesn't arrive, or arrives wrong. Recourse adds that layer: every dollar the agent commits goes into an escrow transaction against hashed terms, a dispute is decided by an independent venue in minutes, and the contract executes the ruling — proportionally, with an appeal. Nothing in it requires trusting the counterparty, the other vendor's model, or Recourse with the money.
What the Safe community gets
RecourseEscrowModule installs on any Safe running the Safe7579 adapter. The Safe names the agent key and sets the commercial policy; the agent can commit funds only into Recourse transactions within it.
RecourseEscrow holds the money. Release, refund, matched settlement, timeouts, or a venue-signed ruling. OpenZeppelin primitives only; no fees on chain; anyone can execute a signed ruling.
Determinations under the Standard Rules v1.0 with full reasoning, proportional outcomes, an appeal to a human panel, and case fees priced for small transactions — paid by the agent with the request over x402, no account needed.
Two ways in
1 · A Safe with the Safe7579 adapter — install the module
Safe becomes an ERC-7579 account through the Safe7579 adapter (a Safe module plus fallback handler by Rhinestone). Once the Safe is 7579-enabled, installing Recourse is one installModule from the Safe — executed like any other Safe transaction, by the owners' threshold — with the policy as init data:
// from the Safe (owners sign; Safe{Wallet} tx builder, the Safe SDK, or permissionless.js)
bytes memory policy = abi.encode(
agentKey, // the key your agent holds
[USDC], // tokens it may commit
1_000e6, // per transaction
5_000e6, 1 days, // per period
1 hours // never an inspection window shorter than this
);
safe.installModule(2 /* executor */, RECOURSE_MODULE, policy);
// the agent, later — the Safe is the payer of record
uint256 id = module.commit(safe, seller, USDC, 500e6, keccak256(terms), "ipfs://terms", deadline, 2 hours);
module.dispute(safe, id, ref); // or release / proposeSettlement
Revoke the agent with uninstallModule; tighten the caps with setPolicy. The module only ever calls executeFromExecutor on the Safe and only ever targets the token approval and the escrow. It is not Safe-exclusive: the same module runs on Kernel, Nexus, and any other ERC-7579 account, which is why it is built to the standard rather than as a Safe-only module.
2 · A plain Safe with Zodiac Roles — point the agent at the escrow
No adapter, no module: the Safe itself is the payer. Give the agent a Zodiac Roles policy scoped to USDC.approve(escrow, ≤cap) and RecourseEscrow.open / release / dispute / proposeSettlement with parameter conditions (payee allow-list, amount ≤ cap, acceptWindow ≥ minimum). Roles enforces which calls; the escrow contract enforces what happens next. This works today on any Safe with Zodiac installed, and the commercial protection is identical: the funds sit in the transaction contract, and a dispute is decided by the venue and executed by the contract.
Roles and the Recourse module are complementary, not competing: Roles is the authority layer, Recourse is the terms-and-enforcement layer. Teams already on Roles can start with path 2 and move to the module when they adopt Safe7579.
How a dispute actually runs
- Commit. The agent opens a transaction: funds leave the Safe into the escrow against
keccak256(terms), with a delivery deadline and an inspection window. - Deliver. The counterparty marks delivery on chain. If the agent neither releases nor disputes within the window, the counterparty is paid by timeout — agents can't stall.
- Dispute. The agent (or the counterparty) freezes the transaction and files the record with Recourse over the Verdict API: wallet signature as identity and consent, case fee paid with the request. No signup.
- Determination. The venue rules under the Standard Rules — a split, with reasoning — and signs it (EIP-712) with the settlement key the escrow trusts. Escalated cases carry no signature until the bench finalises.
- Execution. Anyone submits the signature; the escrow pays the split. If you set an appeal window, the ruling's
notBeforeholds execution on chain until it closes, and an appeal ruling (round 2) supersedes it.
Where it stands
| Piece | Status |
|---|---|
| RecourseEscrow + RecourseEscrowModule | built; 30 Foundry tests covering every path, forged rulings, appeal rounds, policy caps, fuzzed conservation of funds; not yet externally audited |
| Live demo | running on the Tempo Moderato testnet against a reference ERC-7579 account, every transaction on the public explorer; a Safe7579 run is next |
| Networks | Deployed on Tempo Moderato (addresses on the protocol page); Base Sepolia and Base deploy scripts ready |
| Rules and venue | live — the same Rules and engine every human contract naming Recourse already uses; published decisions |
Why not a jury escrow?
Token-juror escrows exist and are respected, but they were built for humans: open a case, wait for incentivised jurors, receive a binary ruling. Agent commerce needs structured terms hashed into the transaction, evidence filed over an API, a reasoned proportional determination in minutes, and fees that make sense at fifty dollars. That is what the Recourse Protocol is, and a Safe is the natural place for the principal's side of it to live.
Run the demoProtocol docsTalk to us about a Safe integration