OverviewArchitectureContractsComplianceYieldSecurityBack to App
LIVE ON BASE MAINNET

Institutional RWA
compliance at the token layer.

On-chain KYC, atomic sanction enforcement, automated Merkle yield settlement, and a Chainlink-powered circuit breaker — encoded into the token itself. No off-chain gates. No manual approvals. No workarounds.

ArchitectureContractsComplianceSecurity
SCROLL
Why this exists

Standard ERC-20 is the wrong primitive for regulated assets.

Permissionless token transfers are a feature of DeFi. For tokenized Real-World Assets — US Treasury Bills, real estate, corporate bonds — they are a compliance catastrophe. A US T-Bill cannot legally be held by an Iranian national. A corporate bond cannot legally be sold to an unaccredited investor in a restricted jurisdiction. These rules exist in securities law regardless of what the blockchain does.

Most tokenization projects solve this with an off-chain approval layer: a centralized server that checks transfers before they go through. The blockchain records the outcome but not the rule. The compliance is invisible, revocable, and not cryptographically verifiable by anyone reading the chain.

Nexus RWA encodes the compliance rulebook into the token itself. Every mint, burn, and peer-to-peer transfer is evaluated against KYC status, OFAC sanction lists, jurisdictional restrictions, and supply caps in a single atomic transaction. The rule is the contract.

The protocol is live on Base Mainnet with six deployed and verified contracts. It supports four asset classes — T-Bills, real estate, corporate bonds, and commodities — each with its own jurisdiction ruleset, supply cap, and maturity date. The Genesis Token (nUSTB) is a tokenized US Treasury Bill already operating on the system.

System Design

Three layers. Separation taken seriously.

Every contract in Nexus RWA has exactly one job. Identity does not know about assets. Assets do not execute compliance. Compliance does not hold any funds.

SYSTEM LAYERS — TOP TO BOTTOM
INVESTOR / DAPPWagmi · Viem · RainbowKit · Base Mainnet
COMPLIANCE ENGINEBlacklist check · Sanction check · Whitelist check · Jurisdiction rules
IDENTITY REGISTRYKYC tier · Country code · Accreditation · Expiry
ASSET REGISTRYSupply cap · Maturity date · Per-asset whitelist · Jurisdiction rule
RWA TOKENERC-20 + _update() hook · Forced transfer · Mint / Burn · Pause
Deployed on Base Mainnet

Six contracts. One coherent system.

01

IdentityRegistry

ERC-3643 · KYC Hub
0x18026c0BF58c978caDc8Df7f31b1cbC2f6A94c5A
View on BaseScan
02

AssetRegistry

Supply Ledger
0x88bb8025dc10Cc642d2F0D10F4335EcDBdC9A594
View on BaseScan
03

ComplianceEngine

Transfer Gatekeeper
0x00c0E82e0C81c4Df096aAd98f2aA5A399b34131c
View on BaseScan
04

NAVOracle

Chainlink · 15% Breaker
0xE4BeA2a081BA5d7137618840aFD012883014cbdD
View on BaseScan
05

YieldDistributor

Merkle · Automated Epochs
0x8cbdAC28819d95b8425a0BdFD37610075F021996
View on BaseScan
06

Genesis Token (nUSTB)

ERC-20 · Compliance-gated
0xFDFda5Ca91bDC022EC85C9F2bE5d29A33f874EDE
View on BaseScan
How transfers work

Every transfer runs four gates in sequence.

One gate fails, the whole transaction reverts. No partial state. No error recovery. No second chances.

01
GATE 01

Global blacklist and sanction check

Both sender and receiver are checked against the global investor blacklist in ComplianceEngine and against the OFAC hardcoded jurisdiction constants in JurisdictionLib. Any match reverts with `BlockedInvestor` or `SanctionedJurisdiction`.

02
GATE 02

Per-asset whitelist verification

Each asset maintains its own whitelist in the AssetRegistry. Both parties must appear in the specific whitelist for the asset being transferred. General KYC clearance is not sufficient — per-asset clearance is required for every individual security.

03
GATE 03

Jurisdiction and accreditation enforcement

JurisdictionLib checks whether the asset allows all jurisdictions or only specific ones. If restricted, the pair of country codes must be compatible with the issuer jurisdiction. Accreditation level is enforced on the receiver — not the sender.

04
GATE 04

Asset lifecycle and KYC expiry

The AssetRegistry confirms the asset is ACTIVE and has not matured. The IdentityRegistry confirms neither wallet's KYC has expired. All of this happens inside the `_update()` override — the same hook OpenZeppelin calls for every balance movement.

IdentityRegistry

Five verification tiers. One registry.

Identity is registered once and shared across every asset on the protocol. Upgrading a wallet from KYC to ACCREDITED immediately unlocks every asset that requires that clearance.

NONE

Unregistered. No protocol access whatsoever.

BASIC

Standard KYC — name, email, government ID.

KYC

Advanced KYC — proof of address, biometrics.

ACCREDITED

Verified high-net-worth individual status.

INSTITUTIONAL

Corporate and institutional entity clearance.

Tier upgrades are unidirectional — the contract enforces that a wallet can only move to a higher tier, never downgrade. This prevents a compliance officer from accidentally removing access from an investor who qualifies for institutional clearance.

Each identity record includes a `kycExpiry` timestamp. Once that timestamp passes, the wallet is treated as non-compliant even if it is active and whitelisted. The `renewKYC()` function refreshes this expiry — no re-registration required.

AssetRegistry

Four asset classes. One ledger.

T-Bill

US Treasury Bills tokenized as permissioned ERC-20s. Supply caps and maturity dates enforced in storage.

Real Estate

Commercial and residential property fractionalised with jurisdiction-specific transfer rules.

Corporate Bond

Fixed-income instruments with Chainlink-priced NAV and automated coupon epochs.

Commodity

Physical commodity exposure with circuit breakers preventing NAV manipulation.

YieldDistributor

Yield that scales to any number of holders.

Paying yield to ten thousand holders in a single loop transaction would exceed the block gas limit and never land. YieldDistributor.sol approaches the problem differently. The full distribution list — every investor and their exact allocation — is computed off-chain and committed to a 32-byte Merkle root stored on-chain. The protocol holds the cryptographic fingerprint; the proof lives with the user.

When an investor wants to claim, they submit their allocation amount alongside a Merkle proof generated by the frontend. The contract verifies the proof against the stored root — a constant-gas operation that does not depend on protocol size. Whether the distributor has ten holders or a hundred thousand, the gas cost to claim is identical.

Epoch cycles are advanced automatically by Chainlink Automation. When the scheduled interval passes, the Chainlink node calls `performUpkeep()` which opens the next epoch. No operator, no cron job, no multisig.

Double-spending is prevented by writing `s_hasClaimed[epochId][investor] = true` before the token transfer. Any reentrant claim attempt finds the flag set and reverts with `AlreadyClaimed`. Batch claiming across up to 50 epochs is supported in a single transaction, with all state updates processed before any external transfer call.

NAVOracle

The circuit breaker is autonomous.

NAVOracle integrates with Chainlink Data Feeds to provide real-time Net Asset Value for each registered asset. Every price read is validated for round completeness — the `answeredInRound` must equal the `roundId` — and staleness. Any price older than one hour reverts with `StalePriceFeed`.

The circuit breaker adds a second layer of protection against oracle manipulation and flash crashes. The oracle stores a price snapshot every 24 hours. If any subsequent read comes in more than 15% below that snapshot — within the same 24-hour window — the breaker trips and all NAV reads for that asset revert. Nothing downstream can act on a crashed price.

Resetting the breaker requires a manual call from the guardian address. This friction is intentional. Automated systems that depend on NAV — lending protocols, yield calculators, margin engines — should not silently resume after a 15% drop. A human needs to review what happened first.

Design Decisions

Why it was built this way.

01

Compliance is the token, not a wrapper around it

Standard ERC-20 tokens are permissionless. Nexus RWA inverts this. The transfer hook `_update()` is overridden at the lowest possible level — inside OpenZeppelin's ERC-20 base — and calls the ComplianceEngine before a single balance bit moves. There is no way to bypass this gate from outside the contract. Not from a wallet, not from another contract, not from the owner.

02

Identity decoupled from the asset

The IdentityRegistry is a standalone contract that knows nothing about which assets exist. The AssetRegistry knows about assets but defers all KYC decisions to the identity layer. The ComplianceEngine reads from both and makes the final call. This means a wallet's KYC status improves once — globally — and every asset it holds benefits immediately without a single re-whitelist transaction.

03

Sanction enforcement is pure Solidity, no oracle

OFAC-sanctioned jurisdictions — Iran, North Korea, Russia, Syria, Cuba, Venezuela — are hardcoded as constants in JurisdictionLib.sol. Country code 364 will always revert. There is no off-chain feed that could be delayed, stale, or manipulated. The six blocked nations are a permanent, gas-free check that runs on every transfer.

04

Legal clawback without upgradeability

Court-ordered seizures, wallet recovery after key compromise, and confiscation of hacker proceeds are handled by `executeForcedTransfer()` in the ComplianceEngine. It bypasses the whitelist entirely by calling `ERC20._update()` directly — the same internal function, but invoked by the compliance role rather than the transfer hook. No proxy upgrade, no contract migration, no operational downtime.

05

The 15% circuit breaker is autonomous

The NAVOracle stores a snapshot of each asset's price every 24 hours. If the next Chainlink round returns a value more than 15% below that snapshot, the circuit breaker trips and all NAV reads for that asset revert. Nothing can read a crashed price. Resumption requires manual guardian intervention — a deliberate friction that prevents automated systems from acting on manipulated data.

06

Yield scales to any number of holders

A naive yield distribution loop over ten thousand holders would hit the block gas limit and never land. YieldDistributor.sol sidesteps this entirely. Off-chain, a Merkle tree is built from the full distribution allocation. Only the 32-byte root is stored on-chain. Each investor proves their own inclusion with a Merkle proof — a constant-gas operation regardless of protocol size. Chainlink Automation advances epochs on schedule with zero operator calls.

Testing and Auditing

219 tests. 5,000 randomised sequences. Zero critical findings.

Every state-changing function follows the Checks-Effects-Interactions pattern without exception. All validation happens first. All storage writes happen second. All external calls happen last. Reentrancy guards are applied at the function level on every path that moves tokens or updates accounting state.

Beyond unit tests, the protocol's core invariants are verified through stateful invariant fuzzing — 5,000 randomised call sequences exercising every possible ordering of mint, transfer, burn, whitelist, and blacklist operations. If any sequence can breach a supply cap, give tokens to a blocked investor, or allow a double yield claim, the fuzzer will find it.

Core invariants verified by the fuzzer

Non-whitelisted balance is always zero
Minting reverts if `isWhitelisted` returns false. Transfer hook reverts on both sides. Proven via 5,000+ randomised state sequences in stateful invariant fuzzing.
Supply cap is never breached
`recordMint()` checks against `totalSupplyCap` before updating `mintedSupply`. The invariant test runs millions of mint permutations to confirm.
Yield cannot be claimed twice per epoch
`s_hasClaimed[epochId][investor]` is written before the token transfer. Any reentrant claim attempt sees the flag set and reverts with `AlreadyClaimed`.
Sanctioned jurisdictions never receive tokens
`JurisdictionLib.enforceSanctionCheck()` is called on both whitelist registration and every live transfer. Two-layered: entry prevention and transfer prevention.
Matured assets cannot be minted
`isAssetActive()` checks `maturityDate` against `block.timestamp`. Passed maturity reverts with `AssetMatured` before any supply is recorded.
Forced transfer always emits an on-chain proof
`ForcedTransferExecuted` is emitted before the external token call, ensuring an immutable audit trail regardless of downstream call success.
DISCLAIMER

The protocol implements production-grade security patterns, CEI across all contracts, and has been statically analysed with Slither at zero critical or high severity. It has not undergone a formal external audit. Do not deploy against real capital without engaging a professional smart contract auditing firm.

BASE MAINNET · CHAIN ID 8453

Deploy on compliant rails.

Nexus RWA is live and operational. Connect a wallet to interact with the protocol, or read every contract on GitHub.

Open AppSource Code