The problem

So you want to tokenize a fund and trade it on Uniswap.

Say you’re a bank. Clients want a tokenized money-market fund they can actually trade. Compliance needs today’s rules to keep working on-chain. Usually you’re told to pick one.

Every holder is KYC'd
Checked at every trade, not just at onboarding.
Jurisdictions can be switched off
Block Japan, and Japan stops trading. Immediately.
Transfer-agent powers stay
Freeze, pause, force-transfer, recover.
And it's a real market
Genuine Uniswap liquidity, in the open.

We built it. Two prompts for the contracts. ~200 lines of policy. 13 tests that try to break it. Every number below is a live read from the chain, not a screenshot.

The architecture, live

pick a scenario — the pulse traces the real call flow
1/7
THE OPENZEPPELIN LAYERCOLOUR = WHOSE TECHNOLOGYOpenZeppelinTokeny · T-REXUniswap v4this dashboardInvestorbrowser session — no walletTHIS DASHBOARDKYC claim issuersigns the passport's stampsTOKENY · T-REXOn-chain passportONCHAINID + signed claimsTOKENY · T-REXCustody accountsegregated, CREATE2 · OZ ContractsOPENZEPPELINCompliance hookon BaseHook · uniswap-hooks libOPENZEPPELINCompliance bridgeAllowlistChecker — your rule, ~200 linesOPENZEPPELINIdentity registrywho is a verified holderTOKENY · T-REXPermissioned routerthe only door to the poolUNISWAP V4Pool · PoolManagerlive market, public ledgerUNISWAP V4APMMF tokenERC-3643 security tokenTOKENY · T-REXCompliance consoleissuer & agent controlsTHIS DASHBOARD
1/7

The investor places an order. The custodian signs from the segregated custody account — the client never holds a key.

1

One prompt → the security token

OpenZeppelin

One sentence in. A complete permissioned token out.

›Prompt

Generate a permissioned RWA token called APACMoneyMarket, symbol APMM. Transfers have to be restricted to an allowlist. I need to freeze an individual holder's balance, mint, burn, and pause the whole asset. Use role-based access control rather than a single owner, include ERC-2612 permit, and pre-mint 1,000,000 to the deployer. MIT licence, security contact security@openzeppelin.com.

Verified · compiles untouched
Verbatim generator output, on audited OpenZeppelin Contracts.
// SPDX-License-Identifier: MIT
// Compatible with OpenZeppelin Contracts ^5.7.0 and Community Contracts commit b0ddd27
pragma solidity ^0.8.27;

import {ERC20Freezable} from "@openzeppelin/community-contracts/token/ERC20/extensions/ERC20Freezable.sol";
import {ERC20Restricted} from "@openzeppelin/community-contracts/token/ERC20/extensions/ERC20Restricted.sol";
Expand if someone asks.
2

One prompt → the market's gatekeeper

OpenZeppelin

The hook is the contract the pool asks before every trade — and which can refuse. Generated on OpenZeppelin's audited BaseHook.

›Prompt

Scaffold a Uniswap v4 hook called CompliantSwapHook on top of BaseHook. It has to gate pool initialisation, gate liquidity adds, gate swaps, and observe swaps after they settle — so beforeInitialize, beforeAddLiquidity, beforeSwap and afterSwap, and nothing else.

Verified · why generate it
In v4, a hook’s address must encode its permissions. Get it wrong and compliance silently never runs. A generator’s job, not a human’s.
3

The one part you must own: the rule

OpenZeppelin

No generator writes your policy. ~200 lines, reading the issuer's ERC-3643 registry — the standard behind ~$28bn of tokenized assets.

// The whole decision, cheapest gate first — asked before every trade.

if (_isPaused(tokenAddress))                       return NONE;  // issuer paused the asset
if (_isFrozen(tokenAddress, account))              return NONE;  // agent froze this wallet
if (!_isVerified(policy.identityRegistry, account)) return NONE; // passport not verified
if (policy.enforceCountry && !_countryAllowed[token][country])
                                                   return NONE;  // venue blocked the jurisdiction

granted = SWAP_ALLOWED;
if (_holdsClaim(account, policy.liquidityClaimTopic))
contracts/ERC3643AllowlistChecker.sol — the venue asks; the issuer's registry answers.
Verified · that rule answering live, right now
CLIENT-A · Sakura (JP, professional)swapLPKYC + professional claim
CLIENT-C · Harbour (HK, retail)swapLPKYC only — no professional claim
CLIENT-D · Prospect (KYC pending)swapLPNo identity registered

One function, three answers — all from the issuer’s attestations.

4

Prove it refuses

OpenZeppelin

A control nobody tried to break is a claim. These tests attack every gate.

13/13 passingcaptured from forge test --json, not transcribed
  • ✓An unverified wallet can't reach the asset by any route.
  • ✓KYC-only investors can trade — but can't provide liquidity.
  • ✓Freeze one client; the others keep trading.

Now watch it trade

Same deployment, live. Press Present demo there — a trade settles, a wallet freezes, the pool refuses on its own.

Open the live console →