Skip to content

FIDUCCI-Projects/rebeka_contracts

Repository files navigation

Rebeka RWA Contracts

Smart contracts and scripts for tokenizing real-world assets (land plots) on Arbitrum:

  • RWAPermissionedERC20: share token (1 token = 1 m², decimals = 0) with KYC/allowlist.
  • RevenueDistributor: USDC revenue distributor for share token holders.
  • AssetRegistry: on-chain registry of metadata and document references (URIs + hashes) per token.
  • RWATokenFactory: factory that, for each land plot, deploys a RWAPermissionedERC20 and its associated RevenueDistributor.

The project is built on Hardhat 3 + viem, with TypeScript tests using node:test and some additional Solidity tests.

Deployed addresses (Testnets)

Arbitrum Sepolia

Contract Address
RWATokenFactoryRouter 0x0ce62220867e7df484aca7768ac30be077346803
RWAPublicTokenFactory 0xbd6ac1b582a52d39cd22ecc9501a992b1edf11f0
RWAConfidentialTokenFactory 0xa0570079ebf260648801e3271535e48c33d18102
AssetRegistry 0x8ac75a491bea0e40ce230e3be632038f4324cd4d
Public Token (PAP1) 0x894cdA6feBf63aC3e4ae94e639D5D61eB9745d83
Confidential Token (CAP1) 0xA9b4F6A44d16796321f21522C1a70C7B4E97B94A
USDC (payout, testnet) 0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d

On-Chain Verification (Arbitrum Sepolia)

Logic verified using direct onReport calls via a temporary forwarder handshake.

  • Public Token Allowlist Proof: 0x9f4dafd74e63d422f3a3ddabddc6186e8d77248b97c5a65472f4c583d7f0004b
  • Confidential Mint Encrypted Proof (FHE): 0x8f94450c27ee99e49f3a9d790b5986996998befea90270b86722c1bb2f47a2d5

Ethereum Sepolia

Contract Address
RWATokenFactoryRouter 0xd3e41deae71e6c81f799ca746349b8d58e83b881
RWAPublicTokenFactory 0x4f87490b7879864324d4be083d6b217994015999
RWAConfidentialTokenFactory 0xa74236c1b78d17ba1639b705053a5f0bf4ffa5a5
AssetRegistry 0xdb113e53e45f4a4ee83b87c6e58d5fc86e0122d6
Public Token (PEP1) 0xb7c22c408bb1126FE5C4B35FE7e5EE6fc69C29Da
Confidential Token (CEP1) 0xc48e235465A9c04f051abf0dA6aD63Ea9B6651e5
USDC (payout, testnet) 0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238

Common

  • Admin / MASTERWALLET: 0xfBf9fcB06a4275DE4ba300bA0fAA8B19D048e1B2

Use Router for both public and confidential createToken and indexing. The Router is now dynamic and can link to the appropriate factories. See docs/DEPLOY.md for mainnet and env vars.


Contracts

RWAPermissionedERC20

  • File: contracts/RWAPermissionedERC20.sol
  • Access control:
    • DEFAULT_ADMIN_ROLE: general configuration.
    • ISSUER_ROLE: allowed to mint / burn.
    • KYC_ADMIN_ROLE: can allowUser / disallowUser.
    • PAUSER_ROLE: can pause / unpause transfers.
  • Transfer policy:
    • Only transfers between issuer and allowlisted investors are allowed.
    • mint and burn are not paused; only transfer is affected by pause.
  • Decimals:
    • decimals is configurable, but for RWA deploys it is set to 0 (1 token = 1 m²).

RevenueDistributor

  • File: contracts/RevenueDistributor.sol
  • Purpose: distribute a payout token (USDC on Arbitrum) to share token holders.
  • Features:
    • Pull model: issuer calls deposit(amount) and users claim with claim() / claimFor(user).
    • ACC_PRECISION = 1e27 to minimize rounding issues.
    • checkpoint(user) must be called by the backend whenever a user’s share token balance changes (mint/burn/transfer).
    • Only issuer and KYC’d (allowlisted) users can claim.
    • Reentrancy protection on deposit, claim, and claimFor.

AssetRegistry

  • File: contracts/AssetRegistry.sol
  • Access control:
    • REGISTRY_ADMIN_ROLE: only role allowed to update metadata and documents.
  • Structures:
    • MetadataRef { uri, contentHash, updatedAt, version }
    • DocumentRef { name, uri, contentHash, mimeType, gated, updatedAt, version }
  • Core functions:
    • setMetadata(token, uri, contentHash) — stores URI + hash for a token and increments a version counter.
    • upsertDocument(token, docId, name, uri, contentHash, mimeType, gated) — creates/updates a referenced document with versioning.
    • getDocument(token, docId) — returns the current version of a document.
  • Validations:
    • Constructor and write methods ensure address parameters are not address(0) (ZeroAddress, InvalidToken).

RWATokenFactory

  • File: contracts/RWATokenFactory.sol
  • Access control:
    • FACTORY_ADMIN_ROLE: allowed to create new assets (land plots).
  • Constructor:
    • RWATokenFactory(address factoryAdmin, IERC20 payoutToken_)
    • factoryAdmin is granted DEFAULT_ADMIN_ROLE and FACTORY_ADMIN_ROLE.
    • payoutToken_ must be the USDC on Arbitrum address.
  • Main function:
    • createToken(name, symbol, admin, issuer, kycAdmin, pauser):
      • Deploys RWAPermissionedERC20(name, symbol, 0, admin, issuer, kycAdmin, pauser).
      • Deploys RevenueDistributor(admin, issuer, pauser, payoutToken, token).
      • Emits TokenCreated(token, distributor, name, symbol).

Scripts

All scripts use Hardhat + viem and assume you’ve configured network environment variables (see below).

scripts/deploy.ts

  • Responsibility: initial deployment of the “infrastructure” contracts:
    • AssetRegistry
    • RWATokenFactory
  • Uses:
    • MULTISIG_ADDRESS as admin (or the ARBITRUM_PRIVATE_KEY account if not set).
    • USDC_ARBITRUM (or the default 0xaf88d065e77c8cC2239327C5EDb3A432268e5831).
  • Output:
    • AssetRegistry address.
    • RWATokenFactory address.

Example:

ARBITRUM_RPC_URL=... \
ARBITRUM_PRIVATE_KEY=0x... \
MULTISIG_ADDRESS=0xTuMultisig \
USDC_ARBITRUM=0xaf88d065e77c8cC2239327C5EDb3A432268e5831 \
npx hardhat run scripts/deploy.ts --network arbitrum

scripts/create-terreno.ts

  • Responsibility: create a new land asset (share token + distributor pair) using RWATokenFactory.
  • Variables:
    • RWA_FACTORY_ADDRESS (required): RWATokenFactory address.
    • MULTISIG_ADDRESS (optional): admin/issuer/kycAdmin/pauser; if not set, the deployer is used.
    • RWA_NAME / RWA_SYMBOL (optional): name and symbol of the new token.
  • Output:
    • Created RWAPermissionedERC20 address.
    • Associated RevenueDistributor address.

Example:

ARBITRUM_RPC_URL=... \
ARBITRUM_PRIVATE_KEY=0x... \
RWA_FACTORY_ADDRESS=0xFactory \
MULTISIG_ADDRESS=0xTuMultisig \
RWA_NAME="RWA Terreno 123" \
RWA_SYMBOL="RWA123" \
npx hardhat run scripts/create-terreno.ts --network arbitrum

scripts/register-asset.ts

  • Responsibility: register metadata and documents for a share token in AssetRegistry.
  • Variables:
    • ASSET_REGISTRY_ADDRESS (required): AssetRegistry address.
    • RWA_TOKEN_ADDRESS (required): share token to register.
    • METADATA_URI, METADATA_HASH (optional): main metadata.
    • DOC_ID (bytes32, optional). If set, upsertDocument is also called with:
      • DOC_NAME, DOC_URI, DOC_HASH, DOC_MIME, DOC_GATED.

Minimal example (metadata only):

ASSET_REGISTRY_ADDRESS=0xRegistry \
RWA_TOKEN_ADDRESS=0xToken \
METADATA_URI="ipfs://Qm.../metadata.json" \
METADATA_HASH=0x... \
ARBITRUM_RPC_URL=... \
ARBITRUM_PRIVATE_KEY=0x... \
npx hardhat run scripts/register-asset.ts --network arbitrum

scripts/revenue-actions.ts

  • Responsibility: actions on RevenueDistributor:
    • ACTION=deposit: deposit USDC as issuer.
    • ACTION=claim: claim revenue.
  • Common variables:
    • ACTION: "deposit" or "claim".
    • DISTRIBUTOR_ADDRESS: RevenueDistributor address.
  • For deposit:
    • PAYOUT_TOKEN_ADDRESS: USDC address.
    • DEPOSIT_AMOUNT: amount in smallest units (e.g. "1000000" = 1 USDC with 6 decimals).
  • For claim:
    • CLAIM_FOR (optional): if set and different from msg.sender, uses claimFor(user); otherwise uses claim().

Deposit example:

ACTION=deposit \
DISTRIBUTOR_ADDRESS=0xDistributor \
PAYOUT_TOKEN_ADDRESS=0xUSDC \
DEPOSIT_AMOUNT=1000000 \
ARBITRUM_RPC_URL=... \
ARBITRUM_PRIVATE_KEY=0xIssuerKey \
npx hardhat run scripts/revenue-actions.ts --network arbitrum

Claim example (for the investor themselves):

ACTION=claim \
DISTRIBUTOR_ADDRESS=0xDistributor \
ARBITRUM_RPC_URL=... \
ARBITRUM_PRIVATE_KEY=0xInvestorKey \
npx hardhat run scripts/revenue-actions.ts --network arbitrum

scripts/deploy-confidential.ts

  • Responsibility: deploy RWAConfidentialTokenFactory and optionally create the first confidential token (FHE). Uses CoFHE; supports Arbitrum Sepolia.
  • Variables: MASTERWALLET (admin/issuer/kycAdmin/pauser of the token), USDC payout address for the distributor (optional; script has defaults for Arbitrum Sepolia).
  • Output: factory address and, if created, the first RWAConfidentialERC20 address (use the latter as RWA_CONFIDENTIAL_TOKEN_ADDRESS for minting).

Example:

npx hardhat run scripts/deploy-confidential.ts --network arbitrumSepolia

scripts/mint-confidential.ts (FHE / confidential)

  • Responsibility: whitelist and mint tokens for a user on RWAConfidentialERC20. Uses mintEncrypted (amount encrypted via cofhejs in a CJS helper); balances and mint amount stay private on-chain.
  • Variables:
    • RWA_CONFIDENTIAL_TOKEN_ADDRESS (required): address of the RWAConfidentialERC20 contract (e.g. the token created by deploy-confidential.ts).
    • USER_TO_ALLOW_AND_MINT (required): address to whitelist and mint to.
    • MINT_AMOUNT (optional): amount to mint (default 100).
    • ALLOW_ONLY (optional): set to 1 to only whitelist, no mint.
  • Network: use the network where the confidential token is deployed (e.g. arbitrumSepolia).
  • Signer: must have KYC_ADMIN_ROLE (for allowUser) and ISSUER_ROLE (for mintEncrypted). Same env as the network (e.g. ARBITRUM_SEPOLIA_RPC_URL, ARBITRUM_SEPOLIA_PRIVATE_KEY).

Example:

export RWA_CONFIDENTIAL_TOKEN_ADDRESS=0xe3A879a1e56FC801CaCf128eD1ddbadEc43e272a
export USER_TO_ALLOW_AND_MINT=0x...
npx hardhat run scripts/mint-confidential.ts --network arbitrumSepolia

scripts/grant-role.ts

  • Responsibility: grant or revoke AccessControl roles on a contract after deploy. See docs/DEPLOY.md for usage.

Network & environment configuration

Networks are defined in hardhat.config.ts. For Arbitrum:

  • Environment variables:
    • ARBITRUM_RPC_URL — Arbitrum One RPC endpoint.
    • ARBITRUM_PRIVATE_KEY — key of the account that will sign transactions (multisig delegate or operational EOA).
  • Other useful values:
    • MULTISIG_ADDRESS — if you want to separate deployer and logical admin.
    • USDC_ARBITRUM — USDC contract address (defaults to Circle native USDC on Arbitrum).

Quick export example:

export ARBITRUM_RPC_URL="https://arb-mainnet.g.alchemy.com/v2/..."
export ARBITRUM_PRIVATE_KEY="0x..."
export MULTISIG_ADDRESS="0x..."
export USDC_ARBITRUM="0xaf88d065e77c8cC2239327C5EDb3A432268e5831"

Tests

TypeScript tests (node:test + viem)

Main tests live in test/:

  • RWAPermissionedERC20.ts
  • RevenueDistributor.ts
  • AssetRegistry.ts
  • RWATokenFactory.ts

Run them with:

npx hardhat test

(In this project we don’t split “solidity” vs “nodejs” suites; everything runs with the command above.)

Solidity tests (Foundry)

Some contracts also have Solidity tests (*.t.sol) intended for Foundry.

Example (if you have Foundry installed):

forge test

Typical production flow

  1. Infrastructure deploy (once)

    • Run scripts/deploy.ts to deploy AssetRegistry and RWATokenFactory.
  2. Create a land asset (new RWA token)

    • Run scripts/create-terreno.ts with RWA_FACTORY_ADDRESS and optionally RWA_NAME / RWA_SYMBOL.
    • Store the share token and RevenueDistributor addresses.
  3. Register land metadata & documents

    • Run scripts/register-asset.ts with ASSET_REGISTRY_ADDRESS and RWA_TOKEN_ADDRESS.
  4. Daily revenue operations

    • Issuer/ops: use scripts/revenue-actions.ts with ACTION=deposit to deposit revenue into the distributor.
    • Investors / backend / relayers: use scripts/revenue-actions.ts with ACTION=claim (and optionally CLAIM_FOR) to claim.

This flow matches what is described in docs/ARCHITECTURE_AND_TASKS.md and the user stories in docs/context/user_stories.md.

About

Smart contracts for tokenize land

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors