Censor, Never Steal: Why the Service That Decides Is Never the Service That Signs

How FairWins runs a funded gas wallet on the open internet by splitting one server into two — a bouncer that decides, and an engine that pays

The button that spends someone else’s money

In part 1 of this series we covered the friendly half of gasless transactions: on FairWins, a user with no cryptocurrency for network fees can still act. They sign an instruction — “accept this wager,” “claim my winnings” — with their wallet, off to the side, for free. Someone else then pays the small network fee to actually submit it. That post ended on an uncomfortable word: someone.

Someone has to run a server. That server holds a funded wallet, accepts signed instructions from anyone on the internet, and turns them into paid transactions. Every bad outcome you can picture is on the table: the wallet’s key gets stolen; a bot floods the server until the gas budget is gone; a sanctioned wallet slips an action through; one deliberately expensive transaction burns a week’s budget in a single shot; or the whole thing falls over at 2 a.m. and people are stuck mid-wager.

FairWins had an extra constraint. The platform’s standing rule is no backend — just smart contracts, a static web app, and an indexer that reads the blockchain. This gas-paying server is the one deliberate exception, and being the exception raised the bar: if a server has to exist, its potential for damage has to be small enough to describe in a sentence.

The design that shipped does exactly that. One service decides whether a transaction should exist at all. A completely different service decides how it gets paid for and confirmed. Neither can do the other’s job. The goal, in the team’s own words: the hosted system can only ever censor, never steal.

The split: a bouncer in front, an engine behind

Picture two machines wired together.

The first is the bouncer. It faces the internet, receives each signed instruction, and runs it through a checklist before letting anything through. Is the system paused by its emergency switch? Is this a supported network and action? Who actually signed this — worked out mathematically from the signature itself, never taken on the sender’s word? Have we already processed this exact instruction (no double-submitting)? Does the signer pass a sanctions screen and stay under their rate limit? Would this blow the fee budget? Only an instruction that clears every gate gets packaged up and handed onward.

The second is the engine. It is a well-known open-source piece of infrastructure, run as-is, that does one unglamorous job well: take a fully-formed transaction, pay for it, and get it confirmed on the blockchain — managing the fiddly mechanics of ordering, pricing, retries, and switching to a backup connection if one fails. Crucially, the engine holds the gas wallet’s key. That key lives inside a hardware security module — a tamper-resistant vault that can use the key to sign but can never hand the key out.

Between the two machines is a deliberately tiny opening. The engine receives only a finished transaction: where it’s going, and how fast to push it. It never sees the original instruction, never learns who signed it, and holds no opinions. All the judgment lives in the bouncer; all the mechanics live in the engine.

That narrow seam buys three things. The engine is swappable — it’s off-the-shelf, so it could be replaced without touching a line of policy logic. The engine is auditable by its settings rather than its code — a plain configuration file pins a spending cap per network and, most importantly, a list of the only addresses it is ever allowed to pay. Even if hijacked, it could only ever pay into FairWins’ own contracts. And the policy is testable without touching a real blockchain, because it’s cleanly separated from the machinery.

Status flows back honestly: the engine tells the bouncer when a transaction is genuinely confirmed on-chain, and only then does the app report it as done. The system never guesses or reports success early.

Fail closed where money moves

The most telling item on the checklist is the sanctions screen. The smart contracts already screen everyone — so why screen again? Because the gas wallet pays the network fee before the contract ever gets a chance to reject the transaction, and “we paid to submit a sanctioned wallet’s transaction” is a sentence nobody wants to write. So the bouncer re-checks the true signer against the same on-chain screen.

The rule when that screen can’t give a clear answer is strict: if it says no, reject; if it’s unreachable, also reject — never “assume it’s fine and pay anyway.” This is the instinct across the whole checklist: when money is about to move, refuse rather than guess.

What a total compromise actually buys an attacker

Because of the split, the worst case fits in a small table:

PartHoldsCan doCannot do
Bouncertwo shared passwordsaccept or refuse instructions, screen, rate-limitsign anything, move funds, fake a signer
Enginethe ability to use the gas keypay for transactions to approved addresses onlyexceed the spending cap, pay anyone else, touch user funds
Hardware vaultthe actual gas keyproduce signaturesever reveal the key
Gas walleta small balance for feespay network feesanything else — it has no special authority

Take over the entire hosted system and here is your whole prize: the small gas balance, plus the power to refuse service for a while. No user funds are reachable — the stakes sit in escrow contracts that independently verify every signature themselves. No administrative power is reachable — the keys that could change the contracts live offline, on physically separate storage, in an entirely different security tier. The blockchain re-checks and re-screens everything regardless of what the server claims. That’s what “censor, never steal” means as an engineering property rather than a slogan.

One checklist, two gasless systems

FairWins actually runs two flavors of gasless transactions, and this is where the split pays off twice.

The first is the one above: signed instructions submitted on a user’s behalf. The second serves the platform’s passkey wallets — accounts you unlock with Face ID or a fingerprint (the same WebAuthn standard your phone already uses for passwordless sign-in). For these, FairWins can sponsor the network fee directly, so the user pays nothing.

Rather than build a second server, the same bouncer simply grew a second door. Sponsoring a fee reuses the same emergency switch, the same sanctions screen, and the same rate limits — plus two extra ceilings that cap what any single sponsored action can cost, so one deliberately expensive request can’t drain the sponsorship fund. One perimeter, one audit trail, one emergency switch, covering two economically different systems. The same checklist has since taken on the platform’s other outside connections too — the collectibles marketplace and the prediction-market trading feature. This bouncer turned out to be the platform’s one reusable piece of backend.

Optional by construction: the never-stranded rule

All of this would still be a liability if people needed it. They don’t. A firm rule holds throughout: every action that can go through the gas-paying server must also complete perfectly well without it, landing exactly the same result on the blockchain — the user just pays their own small network fee.

The app enforces this automatically. Before asking you to sign, it quietly checks whether the server is healthy. If that check fails, the emergency switch is on, the network looks down, or anything goes wrong mid-flow, the app silently routes the very same action through your own wallet as an ordinary paid transaction. Same destination, same result; the only difference is who covered the fee. The sponsored-passkey path behaves the same way — any problem, and the confirmation screen honestly says the user is paying.

Because the worst case is merely “users pay their own fee,” the emergency switch is cheap to pull — which means operators will actually pull it when they should.

Design decisions

Build the judgment, buy the machinery. Transaction ordering, fee pricing, and connection failover are solved problems with sharp edges; a mature open-source engine handles them well. The judgment layer — which contracts, which actions, whose signatures, what limits — encodes FairWins-specific calls no off-the-shelf tool could know. The split puts custom code exactly where the custom decisions are.

Fail closed on money, fail soft on availability. Screening and address-pinning fail closed — the bouncer would rather refuse than guess. Availability fails soft — every refusal degrades to self-pay. The asymmetry is the whole point: the only thing this infrastructure is ever allowed to break is its own usefulness.

Further reading

Compliance as Code: On-Chain Screening, KYC/AML Programs, and the Travel Rule

What a contract-level sanctions gate can and cannot do — and where it fits inside a real compliance program

SeriesFinance Professional Series
TrackCompliance, Disclosure & Governance
LevelAdvanced
AudienceCompliance officers, BSA/AML program leads, fintech risk and product managers, general counsel
Tagssanctions, KYC-AML, travel-rule, screening, controls
Reading time~9 minutes

Informational, not advice. This briefing is educational. It is not legal, regulatory, or compliance advice, and it does not describe a regulated money-services program. Sanctions and AML obligations vary by jurisdiction and are evolving; consult qualified counsel for your own facts.

The control that lived in the wrong place

Imagine reviewing a peer-to-peer platform’s compliance posture. On paper it screens users: when a customer connects, the interface checks their wallet address against the sanctions list and refuses to proceed if there’s a hit. The Terms of Service describe this as a control. The screen even renders a tidy “blocked” state. As a compliance reviewer, you ask the question that decides whether this is a control or a decoration: what happens if a sanctioned party never loads your interface?

On a public blockchain, the settlement logic is directly reachable. Anyone with a script can call the contracts without ever touching the website. A screen-only check is a suggestion, not an enforcement point. And US sanctions exposure is effectively strict liability — intent and interface design don’t rescue you if prohibited property was accepted. So the compliance-relevant question is never “does the app screen?” It is “where does enforcement actually bind, and can it be routed around?”

This is the lens for understanding programmatic compliance: pushing a specific, narrow control — sanctions and blocklist screening — down to the layer where value actually moves, so it cannot be bypassed. It is powerful and genuinely useful. It is also frequently oversold. The honest version distinguishes carefully between what address screening does and what a full KYC/AML program does, because they are not substitutes.

The traditional model

In a regulated financial institution, sanctions screening is one component of a broader Bank Secrecy Act / anti-money-laundering (BSA/AML) program. That program rests on several pillars: a written program with board-level ownership; Customer Identification and Customer Due Diligence (CIP/CDD) — you verify who the customer is; ongoing transaction monitoring; sanctions screening of parties and transactions against lists such as OFAC’s Specially Designated Nationals; suspicious-activity reporting; recordkeeping; and independent testing. Screening is the gate; identity verification, monitoring, and reporting are the rest of the house.

Layered on top for value transfers is the FATF travel rule (FATF Recommendation 16). It requires that originator and beneficiary information — names, account identifiers, and often address or identifier details — travel with a qualifying transfer between the institutions on each end. It exists so that the sending and receiving institutions can each screen the counterparty and reconstruct a payment’s parties after the fact. Crucially, the travel rule is an obligation on regulated intermediaries (banks, and, in the crypto context, “virtual asset service providers”). It presumes there is an intermediary who takes custody and holds identity data to pass along.

What changes on-chain

A contract-level screening control collapses the gate into the settlement path itself. Instead of a website consulting a list and asking the system to stop, the settlement logic consults a shared screening component on every entry point where money moves in — and simply refuses to complete a transaction from a listed address. Because the check lives with the money, skipping the interface skips nothing.

Three properties are worth a compliance reader’s attention.

Fail-closed by design. A well-built on-chain gate treats an unavailable or malformed answer from its screening source the same as a hit: it blocks. If the sanctions data source can’t give a clean, well-formed “yes” or “no,” the safe posture is to deny rather than wave everyone through. This is the on-chain analogue of a control that defaults to “hold” when the screening system is down — the opposite of the fail-open behavior that quietly creates exposure.

A built-in, immutable audit trail. The screening source combines a public on-chain sanctions oracle (a service that answers, for any address, whether it appears on the US Treasury list) with a discretionary operator blocklist for addresses tied to illicit finance beyond the official set. Every blocklist change — who made it, which address, in which direction, and a human-readable reason — is written permanently to the chain. There is no separate compliance database to reconcile or lose; the event log is the record. For anyone who has assembled evidence for an exam or a lookback, an immutable, timestamped change history is a real operational advantage.

Gate entry, never exit. A deliberate and defensible line: entry paths (putting value in, creating or accepting a position) are screened; exit paths (claiming a refund or a payout already owed) are not. If an address is listed after its stake is already in escrow, screening the exit would trap those funds — converting a screening control into a de facto asset freeze, a heavier and legally distinct act that would make the contract a custodian of blocked property. Refusing new business is not the same as freezing existing property, and conflating the two is a common design error.

Where it genuinely differs — address screening is not identity KYC

Here is the distinction a compliance professional must hold firmly, because marketing language routinely blurs it.

Address screening answers “is this address on a list?” It does not answer “who is this person?” A contract gate checks a wallet against sanctions and blocklists. It performs no identity verification, no beneficial-ownership analysis, no CDD, no sanctions screening of a name behind the address, and no ongoing behavioral monitoring. A newly created wallet with no listing history passes trivially — it is clean as an address while being completely unknown as a person. Address screening is necessary but nowhere near sufficient for a program that must actually know its customer.

This also reframes the travel rule honestly. The travel rule is about intermediaries exchanging identity data about the parties to a transfer. A non-custodial, peer-to-peer settlement layer where users hold their own keys and the platform never takes custody sits differently from a custodial VASP in most current frameworks — but “differently” is not “exempt,” classification is jurisdiction-specific and unsettled, and regulators are actively extending travel-rule expectations into crypto. The correct posture is not to claim the rule doesn’t apply; it is to recognize that a screening gate does not satisfy the travel rule, because the gate transmits no originator/beneficiary identity information at all. These are different controls addressing different obligations.

Risk & controls

  • Oracle/data-source risk. The on-chain sanctions oracle is a centralized, permissioned feed taken as ground truth. Mitigations are structural, not trustless: the gate only reads from it, the source can be replaced if compromised or retired, and the operator blocklist keeps working even if the oracle is unset. No decentralized sanctions feed exists; pretending otherwise helps no one.
  • List-coverage risk. Sanctions lists change; on-chain oracles update on their own cadence; addresses are added faster than any list captures. Screening reduces exposure to known listed addresses. It does nothing about a sanctioned party operating through a fresh, unlisted wallet — the residual risk that only real identity diligence addresses.
  • Availability vs. exposure. Fail-closed means a screening-source outage can halt entry across the platform until an operator restores or reconfigures it. That downtime is the accepted cost: a recoverable outage beats a strict-liability violation.
  • Program completeness. The largest risk is treating the gate as the whole program. Address screening is one layer among many a serious operation still needs — jurisdictional geo-controls, versioned legal terms with recorded consent, and, where the activity and jurisdiction require it, actual identity verification and monitoring. Defense in depth, not defense in one place.

How FairWins approaches this

FairWins treats sanctions screening as a shared, fail-closed building block enforced inside the contracts rather than in the interface. A single screening component — the public sanctions oracle plus an operator-maintained, fully audit-logged blocklist — is consulted at every entry point where value moves: creating and accepting wagers (both sides are re-screened at acceptance), buying or extending memberships, joining pools, and issuing tokens. The interface still checks first for fast feedback, but the enforcement layer is the one no one can route around. Exit paths are intentionally never gated, so a mid-position listing can’t strand funds. FairWins is explicit that this is address screening, not identity KYC, and that participants remain fully subject to applicable law — the gate is a genuine control, not a complete compliance program.

Informational, not advice. Nothing here is a determination that any particular activity is or isn’t subject to the travel rule, VASP registration, or any AML obligation. Those are facts-and-jurisdiction questions for qualified counsel.

Related deep-dive

For the engineering details, see Sanctions Screening as a Shared Building Block.

Further reading

  • FATF Recommendations and the travel rule (Recommendation 16): https://www.fatf-gafi.org/en/publications/Fatfrecommendations/Fatf-recommendations.html
  • FATF guidance on virtual assets and VASPs: https://www.fatf-gafi.org/en/publications/Fatfrecommendations/Guidance-rba-virtual-assets-2021.html
  • US Treasury OFAC sanctions programs and the SDN List: https://ofac.treasury.gov/sanctions-list-service
  • FFIEC BSA/AML Examination Manual (program pillars, CDD, sanctions): https://bsaaml.ffiec.gov/manual
  • Investopedia, “Know Your Client (KYC)”: https://www.investopedia.com/terms/k/knowyourclient.asp

One Signature, Zero Gas: How Gasless Payments Actually Work

How FairWins turned every action into a signed “intent” — you sign what you want, and someone else pays the fee to submit it

The Stranded User

A user wins a wager on FairWins. Fifty USDC sits in escrow with their address recorded as the winner. All they have to do is claim it. One problem: their wallet holds exactly zero of Polygon’s native coin — the token every transaction needs to pay its network fee, its “gas.” They funded their wallet with USDC from an exchange, never touched the native token, and have no intention of learning what a gas station is. Their money is on-chain, provably theirs, and completely out of reach.

The old flow was worse than one stuck action. Just creating a wager took two transactions: a step to authorize the platform to move your stablecoin, then the step that actually creates the wager. Accepting one meant the same dance. Every step needed native gas, and the failure mode was plain: a user who holds only the stablecoin can’t act at all.

The cruelest version is lopsided — a user who scraped together enough gas to place a bet but can’t afford the gas to claim their winnings. Money in, no money out. Any gasless design that fixes deposits but not withdrawals has built a lobster trap.

The fix is to make the entire platform run on signed intents. Instead of sending a transaction and paying the fee, the user signs a message — for free, no gas — describing exactly what they want to do. Anyone can then carry that signed message onto the blockchain and pay the fee to submit it. Crucially, the on-chain effect is always credited to the person who signed it, never to whoever submitted it. One signature replaces the whole authorize-then-act dance, and a helper service — a “relayer” — pays the fee.

What an Intent Actually Is

An intent is a structured, human-readable message the user signs with their wallet, built on EIP-712 — a widely used standard for signable data a wallet can display in plain terms, so you see the actual stake, deadline, and counterparty, not a wall of hex. Every action on the platform has its own intent: create a wager, accept one, claim a payout, declare a draw, buy a membership tier, and so on.

Each intent locks down three things:

  1. Who is acting — a named field that must match whoever actually signed. You can’t sign on someone else’s behalf.
  2. Every detail of the action — stake amounts, deadlines, which wager. Nothing is left blank for the submitter to fill in later.
  3. A replay guard and an expiry — a random one-time code so the same intent can’t be reused, plus a window so a stale intent eventually expires.

Signatures are checked under a fingerprint unique to each contract and each network, so a signed intent is valid on exactly one contract on exactly one blockchain — a one-time code used up on one contract can never be replayed on another. The check also accepts signatures from smart-contract wallets, so FairWins’ passkey wallets can sign intents too. A failed intent never uses up its one-time code; a successful one can never run twice.

Paying With a Signature, Not a Gas Balance

Signing an action is the easy half. The hard half is money-in actions. The intent says “stake 50 USDC” — but the platform still has to pull 50 USDC out of the wallet, which normally needs a separate, gas-paying authorization first.

This is what EIP-3009 is for — a feature built into Circle’s USDC that lets a holder authorize a specific payment purely by signing. The user signs an authorization naming who gets paid, how much, and a validity window; the receiving contract presents that signature to the USDC token, and the transfer happens. No standing “allowance” ever exists, and no separate transaction is needed.

So a money-in intent carries two signatures: the FairWins intent (“accept wager 41”) and the USDC payment authorization (“pay 50 USDC”). Which raises the attack that shapes the whole design: what stops the submitter from mixing and matching? Could they staple your payment authorization to a different action, or pair your accept-intent with a payment meant for something else?

They can’t, because the two signatures are cryptographically stapled together. The intent you sign references the exact payment it’s meant to travel with, and the contract refuses to proceed unless the payment matches — same amount, same one-time code — the one you committed to. The USDC token adds the final lock: the payment can only land in the contract that’s asking. The net result: a submitter can refuse to carry your intent, but can never substitute, redirect, or resize the payment.

Two Twins, Identical Rules

Every gasless action is a twin of an ordinary one. Accepting a wager the normal way and accepting it via a signed intent run the exact same checks against the person acting — sanctions screening, membership gating, ownership, account freezes. The only difference is how the acting identity is established: from the sender on the direct path, from the recovered signature on the intent path. The submitter’s own standing is never consulted, and because both twins run the same underlying action, they can’t quietly drift apart.

Keeping Three Codebases in Perfect Sync

Here’s the lesson most write-ups skip. The exact shape of each intent has to be defined in three separate places: the smart contract that verifies it, the app that helps the user sign it, and the relayer service that handles it.

These three definitions must be byte-identical — not just similar in spirit. The signing standard fingerprints the entire structure, so a single reordered field, or a field’s type written slightly differently, produces a completely different fingerprint and a signature that verifies to a random, wrong address. The failure is silent when you build it and total when a real user tries: every signature rejected, every time.

The discipline FairWins landed on treats the deployed contract as authoritative, and every other copy documents exactly where it matches. New intents ship in all three places at once, with cross-references so no one edits one and forgets the others. It’s unglamorous bookkeeping, and it’s the entire difference between a working gasless system and a flood of mysterious support tickets.

Never Stranded

The final rule is architectural humility: the relayer is optional, and the design has to survive without it. Every gasless flow keeps a pay-your-own-gas fallback — the original path is never removed. The app enforces this at the wiring level: a screen literally can’t ship a gasless-only dead end, because the code refuses to build one. If the relayer is switched off, overloaded, rate-limiting, or timing out, the app quietly falls back to the user paying their own gas, and the on-chain result is identical.

The fallback also covers networks where the signature-based payment simply doesn’t exist — one test network’s stablecoin lacks it entirely, so the app detects the gap before opening the signing prompt and uses the normal path. And status is honest end to end: the interface never shows “confirmed” before a transaction is actually mined. Signed, pending, confirmed, expired, and failed are all distinct, truthful states.

Design Decisions

Random one-time codes, not a counter. Each intent’s replay guard is a random value, usable in any order. A counter would force a user’s actions into strict sequence and let one stuck intent block everything behind it; random codes let someone sign three intents and have them land in any order. Cancellation is precise — a user can kill one specific unsubmitted intent, and even that can be gasless.

Sign everything, trust nothing. Every detail the action uses is inside the signed message. The alternative — signing a compact code that stands for details delivered separately — is fewer bytes but shows the user nothing legible to approve. Human-readable signed data means the wallet displays the real stake, deadline, and counterparty.

Fee recovery is bounded and segregated. An optional second payment authorization lets the platform recover its gas cost in USDC, but it’s capped on-chain, settles in the same transaction as the action, and pays into a segregated account — never the relayer’s own wallet. A compromised relayer gains no power to skim fees.

Censorship is the accepted residual risk. A relayer can decline to submit an intent; it cannot forge, alter, or replay one. And because the pay-your-own-gas path always exists, refusal degrades to mere inconvenience. That trade — accept the possibility of censorship, eliminate any custody of user funds — is the entire design in one sentence.


Note: FairWins wagers are peer-to-peer agreements based on publicly available information and legitimate forecasting. Gasless submission changes who pays the transaction fee, not who is accountable: every intent is credited to its signer, who remains fully subject to applicable law and the platform’s compliance screening.

Further reading

Enough Signatures Is Not Enough: Adding Real Rules to a Shared Vault

How a small guard contract turns “enough people approved” into “enough people approved, and it obeys the rules” — with no admin key and no way to lock a vault out of its own money

The transaction that had every signature it needed

A three-owner treasury runs a two-of-three multisig: any two owners must approve before money moves. One Tuesday a proposal appears in the queue — send 180,000 USDC to an address nobody recognizes. Owner one approves it from a phone between meetings; the amount looks like the quarterly market-maker payment, and the description says exactly that. Owner two approves an hour later for the same reason. Two approvals: threshold met. The transaction executes. The address belonged to whoever phished owner one and quietly queued the proposal.

Nothing in the multisig failed. That’s the uncomfortable part. A multisig has exactly one control — enough owners agree — and once that bar is cleared, it will send any amount, to any destination, at any time. Everything else teams rely on is procedure: “we review destinations carefully,” “we never approve on mobile,” “big transfers get a phone call first.” Procedures are rules that live in people’s heads, and people approve things between meetings.

Part 1 covered FairWins’ shared vaults: a group holds a multisig with a propose-and-approve queue. This post adds the missing layer — a policy engine that constrains what an already-approved transaction may do, after the threshold is met but before the money moves. The phished proposal above dies at that final step against a per-transaction limit or a recipient allowlist, no matter how many signatures it collected.

The interesting question is where such rules can live so they’re actually binding. Checks inside the app are only advisory — anyone can talk to the multisig directly. A rules service on a company server is just another party you have to trust. The place that actually works is a transaction guard: a contract the multisig itself consults, on-chain, before every execution.

Where the guard sits

A modern Safe multisig can register a guard contract with a veto over every transaction. Just before executing an approved transaction, the Safe hands the guard the full details; if the guard objects, the transaction never runs.

FairWins’ guard is a single shared contract per network: one immutable contract holds the rule settings and running totals for every vault that has opted in, filed under each vault’s address. Because the multisig itself is the one asking, the guard always knows which vault’s rules to apply — no setup handshake needed.

Two properties define the trust model. First, the guard is restriction-only: it can block a transaction but never start, approve, or execute one, and it holds no money. Second, a vault is the only authority over its own rules: changing a vault’s policy is itself a transaction that must clear that vault’s normal approval threshold. There is no owner, no admin role, and the guard is deliberately not upgradeable — an upgrade key over it would be a master backdoor over every vault’s enforcement.

The rules

Version 1 ships the classic treasury controls, each independently switchable per vault:

  • Per-transaction limit — per asset; no single outgoing transaction may exceed it.
  • Daily limit — per asset, over a rolling 24-hour window.
  • Recipient allowlist — outgoing money may only go to pre-approved addresses.
  • Cooldown — a minimum wait between money-moving transactions.

A transaction “counts” against these limits when it moves value — sending the native coin, or one of the standard token operations the guard recognizes: transfer, transfer-on-behalf-of, and approve. Counting approve matters: approving a spender is a spending grant, and ignoring it would leave an obvious loophole where the vault grants an unlimited allowance and the spender quietly drains it later.

The allowlist has a subtlety worth copying. For token movements it checks the beneficiary — whoever ultimately receives or can pull the tokens — not just the token contract being called. For everything else it checks the direct target, so even a transaction the guard can’t fully interpret still can’t reach an un-approved contract. A locked-down vault genuinely stays locked down.

Closing the escape hatches first

Limits are worthless if a transaction can step outside the accounting entirely. So while any rule is active, the guard flatly rejects two dangerous shapes:

  • Code that runs inside the vault’s own context. One transaction type lets external code execute with the vault’s full authority — it could move funds without tripping any rule, or even rewrite the guard’s own settings. Refused outright. (The cost is that a certain batching trick isn’t available on rule-governed vaults; since these flows are single-action anyway, nothing is lost.)
  • Gas-refund transactions. The multisig can be told to reimburse the submitter’s gas out of vault funds — an outflow the limits wouldn’t otherwise see. Refused too.

Both rejections come back as clear, named errors, so the app can explain exactly why something was blocked instead of guessing at a cryptic failure.

You can always loosen the rules

The classic failure mode of on-chain rules is locking yourself in: owners set a cooldown of a year, or turn on an allowlist whose only address is now defunct, and the vault is bricked. The fix is a simple, deliberate carve-out. Two kinds of transaction skip all the spending rules entirely: managing the vault itself (owners, threshold, the guard), and changing the vault’s own policy. Both still require the vault’s normal approval threshold — so the only thing exempt is the collective ability to change the rules.

The result: a too-strict policy can always be loosened by the same group consent that set it, and no vault can ever be locked out by its own rules. This isn’t just asserted — it’s tested against a real multisig deployment, not a stand-in mock.

What you see is what gets enforced

Owners should learn a transaction breaks policy before they spend approvals on it. The guard offers a read-only preview that runs the exact same rule check the real enforcement uses, and the app runs every proposal through it first — so what the interface warns you about can never drift from what the chain enforces. Enforcement itself is careful about ordering: the guard reads and evaluates first, then records the updated totals, and never calls out to another contract, so there’s no room for the reentrancy trickery that plagues contracts that move money.

Rules from the very first transaction

A guard attached after creation leaves a window where early transactions are unpoliced. So FairWins can wire the guard in during vault creation itself: the guard address and starting rules are part of the setup, baked into the vault’s predicted address, and if any part of that setup fails the whole creation is aborted — a half-configured vault can never come into existence. For an existing vault, attachment is ordered so there’s never a moment where the guard is half-on.

Design decisions and accepted limits

Immutable, not upgradeable — on purpose. Elsewhere FairWins leans on upgradeable contracts, but the guard has no upgrade path by design: whoever could swap it out could disable every vault’s enforcement. Improvements ship as a brand-new guard that each vault chooses to adopt through its own approval — consent per vault, never a decision imposed by a single deploy key.

Fixed daily window, not perfectly rolling. A truly continuous rolling window would require storing unbounded transaction history on-chain. The simpler fixed-reset window can, in a worst case straddling a reset, allow up to twice the limit — a small, bounded weakening that’s disclosed in the interface rather than hidden.

Uninterpreted transactions pass the spending limits. The guard values native transfers and the standard token operations; something exotic like a DEX swap passes the spending limits unmeasured. It still faces the allowlist on its target — so a vault that needs a hard lockdown turns on the allowlist and gets one.

Conservative accounting. Totals are recorded before the transaction executes. If the inner action later fails quietly, the spend still counts. Overcounting can only ever restrict, never over-permit — the safe direction to err.

The through-line: every rule that exists is enforced exactly, every gap that exists is named, bounded, and disclosed, and no key anywhere can quietly waive either.

Further reading