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

Sanctions Screening as a Shared Building Block: One Guard, Every Money Path

Why FairWins moved compliance out of the frontend and into a single, fail-closed on-chain gate — and how the same small piece of code protects wagers, pools, memberships, and token issuance

The check that wasn’t there

Picture the code review. Your team ships wallet screening for a peer-to-peer wager platform: when a user connects, the website checks their address against a sanctions list, and if the address is listed, the interface refuses to proceed. The compliance box is ticked. The demo looks great.

A week later, someone on the security review asks the obvious question: what happens if a sanctioned address never opens your website? The contracts live on a public blockchain. Anyone with a script can call them directly, bypassing your site entirely. Your screening layer — the one your Terms of Service describe as a control — turns out to be a polite suggestion.

This is the trap that catches most “compliance-aware” crypto apps. Sanctions exposure under US law is strict liability: it doesn’t matter that you intended to block the address, or that your interface would have blocked it. If your contract accepted money from a listed address, the violation happened. A check that lives only in the website is not a control; it’s theater with good intentions.

FairWins’ answer is to treat sanctions screening the way a careful team treats any core safety check: as a shared building block baked into the contracts themselves. One small, shared piece of code — call it the sanctions guard — is consulted by every entry point on the platform where money moves. The website still checks first, for fast feedback and to avoid wasting anyone’s gas, but the layer that actually enforces is the one nobody can route around.

The guard itself

The guard is deliberately tiny: about a hundred lines, holds no funds, and can’t be upgraded. It combines two lists into a single yes-or-no verdict:

  1. A public sanctions oracle maintained by Chainalysis — an on-chain service that answers, for any address, whether it appears on the US Treasury’s sanctions list.
  2. A discretionary block-list the operator maintains — a simple list for addresses tied to illicit finance beyond the official set, editable only by the holder of the narrow compliance permission described in part 1 of this series.

Consumers get two ways to ask the guard a question. One returns a plain yes-or-no, for callers that want to branch on it — that’s what the website’s advisory check uses. The other simply stops the transaction cold if the address is blocked, which is the form the contracts use, because refusing to let a transaction complete is the cheapest and safest way to make sure a forbidden action never happens.

The block-list editing has one nice property worth calling out: every change records who made it, which address was affected, in which direction, and a human-readable reason — all written permanently to the blockchain. So the block-list’s entire history is a built-in audit trail. There’s no separate off-chain compliance database to subpoena or lose; the on-chain event log is the record. And the keys that can edit those lists follow the platform’s air-gapped, offline signing process, so no change happens casually.

Fail-closed, for real

The interesting engineering is in how the guard talks to the outside sanctions oracle. The naive version — just call the oracle and wrap it in a try/catch — has a sharp edge. If the oracle address is misconfigured, pointing at nothing or at the wrong network, that kind of failure isn’t reliably caught, and the system can silently start treating everyone as clean.

So the guard makes the query in a careful, low-level way that gives it full control over every possible failure: the oracle reverts, runs out of gas, returns nothing, or returns garbage. Anything short of a clean, well-formed “yes” or “no” is treated as the oracle gave no usable answer — and in that case the guard blocks every address. The rule is stated plainly in the platform’s requirements: if the screening source is unavailable, refuse the action rather than allow it unscreened. This is what “fail-closed” means — when in doubt, deny.

There’s exactly one deliberate exception, and it’s a configuration, not a failure. Setting the oracle to “none” means block-list-only enforcement — the intended posture for networks where Chainalysis simply doesn’t operate. Test networks get a stand-in; production gets the real oracle address injected at deployment, never hardcoded. The distinction is precise: a configured but broken oracle blocks everyone, while an intentionally unset oracle blocks only the block-list. Confusing those two states is exactly how fail-closed systems quietly turn fail-open.

One guard, four subsystems

What makes this a reusable building block rather than a one-off feature is that the same guard protects four independent parts of the platform in the same way:

Wagers. Every escrow entry point screens first. Creating a wager screens the creator. Accepting one screens both sides — the person accepting and the original creator — because acceptance is the moment the second stake enters escrow, and the creator might have been added to a sanctions list since they first posted the wager. Screen at every entry, every time.

Memberships. Buying, upgrading, extending, or redeeming a voucher into a membership all screen the person before any USDC moves. Even the admin-only path that grants a membership directly screens the recipient — the guard can’t be bypassed even by operators, so a permission-holder can’t accidentally hand access to a listed address.

Wager pools. Group pools screen creators and joiners through the same guard, with one extra safeguard worth stealing: on production networks the pool factory refuses to run at all if screening is supposed to be on but no guard is configured. The “unset means off” convenience that’s fine on a laptop becomes an impossible, boot-blocking state in production.

Token issuance and naming. Issuing a token screens the issuer and passes the same guard into every token it creates. The naming registry checks the guard before letting anyone claim a name.

Each of these holds its own pointer to the guard, so the guard can be swapped out without touching any of them — and a single block-list update propagates instantly to all four. One list, one place to edit it, one event stream, four enforcement points.

What is deliberately not screened

Here’s the design decision most teams get backwards: the exit paths — claiming a refund, claiming a payout, sweeping up expired wagers — are not screened.

The reasoning matters. If an address is added to the block-list after their stake is already sitting in escrow, screening the exit would permanently trap their funds inside your contract. That turns a screening control into an asset freeze — a much heavier and legally distinct act than simply refusing new business, and one that effectively makes your escrow contract a custodian of blocked property. FairWins draws the line cleanly: a listed address can take no new action that moves value in, but can always recover what’s already theirs. The guard gates entry, never exit.

Trade-offs

A little gas on every entry. Each screened action pays for an extra cross-contract call, plus a second one into the oracle when it’s set. That’s real overhead on the busy path. The team judged it worth it, because the alternative — screening only once, at membership time — leaves a gap: an address listed mid-membership could keep wagering until renewal. Re-screening at every entry closes it.

Trusting an outside oracle. The Chainalysis oracle is a centralized, permissioned data source, and FairWins takes its answers as ground truth. The safeguards are structural rather than trustless: the guard only ever reads from it, it can be swapped out if it’s ever compromised or retired, and the discretionary block-list keeps working even with the oracle unset. This is an honest trade — no decentralized sanctions feed exists, and pretending otherwise helps no one.

Fail-closed can mean downtime. If the oracle ever broke for everyone, every screened entry point would halt until an operator re-pointed or unset it. That’s the accepted cost of failing closed: a brief outage is recoverable; a strict-liability violation is not.

Defense in depth, not defense in one place. The on-chain guard is one layer of several: an edge network geo-gate that blocks restricted regions before a request even reaches the app, the website’s fast advisory check, versioned legal documents, and on-chain records of user consent. The guard is the layer that holds when every other layer is skipped — because on a public blockchain, one of them always can be.

Further reading