The platform is structured around three core layers: the smart contract layer (on-chain), the compliance layer (hybrid), and the application layer (off-chain).
The smart contract layer consists of ERC-20 tokens for fungible asset fractions and ERC-721 tokens for unique asset representations. All token contracts extend a compliance module that checks transfer eligibility against an on-chain whitelist before allowing any transfer.
The compliance layer bridges on-chain and off-chain worlds. When a user completes KYC verification, the platform updates the on-chain whitelist via a privileged admin transaction. Transfer restrictions are enforced at the protocol level — even if a user interacts with the contract directly, compliance rules apply.
Key Decisions
- On-chain compliance enforcement — Transfer restrictions live in the smart contract, not just the application. This is a regulatory requirement for security token offerings.
- ERC-20 for fungible fractions, ERC-721 for unique assets — Different asset types require different token standards. The platform supports both with a unified trading interface.
- Separation of KYC data from blockchain — Personally identifiable information never touches the blockchain. Only verification status is recorded on-chain.
- Order book model over AMM — Institutional traders expect order book mechanics with limit orders, not automated market maker pools.
KYC Pipeline
Multi-step verification: identity documents with liveness detection, real-time sanctions screening (OFAC, EU, UN), accreditation verification per jurisdiction, and ongoing monitoring with automatic wallet suspension on match. KYC data encrypted at rest with AES-256, stored exclusively off-chain.
// Compliant RWA Token with transfer restrictions
contract RWAToken is ERC20, Ownable {
mapping(address => bool) private _whitelist;
function _update(
address from,
address to,
uint256 amount
) internal override {
if (from != address(0) && to != address(0)) {
if (!_whitelist[from] || !_whitelist[to]) {
revert TransferNotCompliant(from, to);
}
}
super._update(from, to, amount);
}
}