Skip to content

Smart Contracts Overview

Zk-RWA-Kit includes Solidity contracts for on-chain credential storage and compliance enforcement.

Contract Architecture

┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│  ZkOracle       │────▶│ IdentityRegistry│◀────│  RWAToken       │
│  (Relayer writes│     │ (Stores claims) │     │  (Checks claims)│
│   claims)       │     └─────────────────┘     └─────────────────┘
└─────────────────┘              ▲

                        ┌─────────────────┐
                        │  mYieldVault    │
                        │  (ERC-4626)     │
                        └─────────────────┘

Contracts

ContractPurpose
IdentityRegistryStores wallet claims with expiry times
ZkOracleReceives claims from relayer, writes to registry
RWATokenExample compliant ERC-20 token
mYieldVaultExample compliant ERC-4626 vault
ComplianceModuleReusable compliance checking logic

Key Concepts

Claims

A claim is a statement about a wallet:

solidity
struct Claim {
    bytes32 value;   // e.g., keccak256("true")
    uint256 expiry;  // Unix timestamp
}

Claims are stored per wallet, per claim type:

solidity
mapping(address => mapping(bytes32 => Claim)) public claims;

Claim Types

Claim types are bytes32 identifiers:

solidity
bytes32 constant ELIGIBLE = keccak256("ELIGIBLE");
bytes32 constant ACCREDITED = keccak256("ACCREDITED");
bytes32 constant NON_SANCTIONED = keccak256("NON_SANCTIONED");

Session Credentials

Unlike permanent allowlists, claims expire:

solidity
function isVerified(address wallet, bytes32 claimType) external view returns (bool) {
    Claim memory claim = claims[wallet][claimType];
    return claim.value != bytes32(0) && claim.expiry > block.timestamp;
}

Access Control

Contracts use OpenZeppelin's AccessControl:

RoleContractPurpose
DEFAULT_ADMIN_ROLEAllManage other roles
ORACLE_ROLEIdentityRegistryAdd/revoke claims
AGENT_ROLEZkOracleSubmit verified claims
MINTER_ROLERWATokenMint tokens

Deployment

Contracts are deployed to Mantle Sepolia. See Deployment for addresses and scripts.

Integration

To make your contract compliant:

solidity
import "./interfaces/IIdentityRegistry.sol";

contract MyCompliantContract {
    IIdentityRegistry public registry;
    bytes32 public constant ELIGIBLE = keccak256("ELIGIBLE");
    
    modifier onlyEligible(address user) {
        require(registry.isVerified(user, ELIGIBLE), "Not eligible");
        _;
    }
    
    function doSomething() external onlyEligible(msg.sender) {
        // Only eligible users can call this
    }
}

Next Steps

Built for the Mantle Global Hackathon 2025