Docs / Smart Contracts

Smart Contracts

All contracts are deployed and verified on Arbitrum Sepolia (chainId 421614). Source in contracts/. ABIs in artifacts/. Frontend ABIs in app/lib/contracts.ts.

// Architecture

Wallet
  β”‚
  β”œβ”€ @iexec-nox/handle β†’ { handle, handleProof }   ← Intel TDX TEE
  β”‚
  β”œβ”€ usdt.approve(PropertyToken, amount)
  └─ PropertyToken.purchaseTokens(handle, proof, amount)
         β”‚  Nox.fromExternal(handle, proof) β†’ euint256 (encrypted balance)
         β”‚  Nox.allowThis + Nox.allow(amount, wallet)
         β”‚
         β”œβ”€ PropertyRegistry.registerHolder(propertyId, wallet)
         β”‚        β”‚
         β”‚        β”œβ”€ RentDistributor.distributeRent() β†’ USDT per holder (equal share)
         β”‚        β”‚
         β”‚        └─ TierNFT.mint() ← Gold/Platinum require isHolder() gate
         β”‚
         β”œβ”€ SecondaryMarket
         β”‚        β”‚  grantOperator β†’ createListing(tokenContract, id, amount, price)
         β”‚        β”‚  usdt.approve(SecondaryMarket) β†’ executeBuy(listingId)
         β”‚        β”‚  confidentialTransferFrom (encrypted) via ERC-7984
         β”‚        β”‚
         β”‚        └─ CESTToken.stake() β†’ getTier() β†’ fee discount (0.5% β†’ 0%)
         β”‚
         β”œβ”€ ConfidentialGovernance
         β”‚        β”‚  registry.isHolder() β†’ onlyHolder gate
         β”‚        └─ createProposal / castVote / finalizeProposal
         β”‚
         └─ TierNFT (Soulbound)
                  β”‚  CESTToken.getTier() β†’ badge tier eligibility
                  β”‚  CEST burned β†’ treasury (fee-discount reserve)
                  β”‚  recordPoints(wallet, handle, proof) β†’ euint256 encrypted points
                  └─ airdropMultiplierBps / feeDiscount

iExec Nox Integration β€” All Contracts

ContractNox ImportsWhat It Does
PropertyToken.solERC7984, Nox, euint256, externalEuint256purchaseTokens() β€” Nox.fromExternal(handle, proof) β†’ euint256 encrypted balance. confidentialTransfer / confidentialTransferFrom for private moves.
TierNFT.solNox, euint256, externalEuint256recordPoints() β€” Nox.fromExternal(handle, proof) + Nox.add() accumulates encrypted points per wallet. Only holder can decrypt via Nox JS SDK. PropertyRegistry.isHolder() gates Gold/Platinum mint.
CESTToken.solNox, euint256, externalEuint256encryptMyStake() β€” after staking CEST, holder encrypts their stake amount as euint256. Nox.fromExternal(handle, proof). Confidential layer on top of public stake record.
SecondaryMarket.solvia ERC7984 interfaceexecuteBuy() calls PropertyToken.operatorTransfer() which uses confidentialTransferFrom β€” encrypted amount moves without revealing quantity on-chain.
RentDistributor.solvia PropertyToken interfacedistributeRent() calls operatorTransfer for each holder β€” USDT amounts auditable on-chain, but per-investor token positions remain encrypted.
ConfidentialGovernance.solvia PropertyRegistryonlyHolder modifier uses registry.isHolder() β€” membership gated by ERC-7984 Nox token holding. 1-address-1-vote preserves balance privacy.

iApp Live Test Evidence

Verified on iExec

The iExec Nox iApp was live-tested on April 30, 2026 against the Arbitrum Sepolia PropertyToken contracts. All 5 latest tasks completed successfully β€” 100% success rate on the latest test run. All deals used the same Intel TDX enclave, confirming the full TEE encryption pipeline is operational end-to-end.

Latest Tasks

5 / 5

100% β€” latest run

Total Deals

8+

all at 0.1 RLC

Deal Price

0.1 RLC

Test Date

30 Apr 2026

iApp (TEE Enclave)

0xB11bC7288eE239F6536829E410d22Eb514C5E282 β†—

jancok075/iexec:0.0.1-tdx-1f1d5e8f915a

Tag: tee,tdx β€” Intel TDX hardware enclave

Requester Wallet

0x834De729cb9dF77451DBc6bf7FD05F475B011Ac7 β†—

Workerpool

0x2956f0...3123f

Latest Requested Tasks β€” April 30, 2026

Task IDStatusDeadline
0x7c10bc…de3a1COMPLETED04/30/2026 01:33 PM
0xca537d…1fcc3COMPLETED04/30/2026 01:26 PM
0xee7f34…80365COMPLETED04/30/2026 01:25 PM
0x423c62…8a4d9COMPLETED04/30/2026 11:26 AM
0x6091cf…5df0dCOMPLETED04/30/2026 09:42 AM

Showing page 1 of 3 β€” all 5 latest tasks COMPLETED. Full history at iExec Explorer β†—

Latest Requested Deals β€” iApp 0xb11bc7…5e282

Deal IDTimeSuccessPrice
0xe8990c…76b951h ago100%0.1 RLC
0x3d6a21…2d00b1h ago100%0.1 RLC
0xaa4fd6…3c3b71h ago100%0.1 RLC
0x8e424d…9119c3h ago100%0.1 RLC
0x31da2e…173585h ago100%0.1 RLC

Showing page 1 of 3 β€” all latest deals at 100% success. Workerpool: 0x2956f0…3123f Β· No dataset.

IPFS Document Registry

10 / 10 Pinned
Pinned via Pinata Β· Arbitrum Sepolia

All legal documents are pinned to IPFS via Pinata and accessible via ipfs.io and gateway.pinata.cloud gateways. CIDs are immutable β€” content is guaranteed identical across all gateways.

PEARL-DXB-001β€” The Pearl Residences

SPV Structure Document

QmaVooqBwZjjkCQAvfodgtpGvfmifqQQgyPkj45m3AXMfu

Property Valuation Report

Qmep6ua83jnqGEYgFvEzFt7xuXntP7mCDhSGy9VqH4m92w

Rental Agreement

QmcNvbSwHecj9sxHZvz9GaJwCZcWnCLbALCes653kBY7KZ
SHIBUYA-TYO-001β€” Shibuya Terrace

SPV Structure Document

QmdCLkDwBq9KcGBmDB1NGsGxEtJd5KqgsW2vAMhR1qaXqT

Property Valuation Report

QmQoKfhdfUfuWwTKcpZ3eeiMSqsasntftSSbkMzA32h1sU
MARINA-SGP-001β€” Marina Heights

SPV Structure Document

QmPzTpiTzYcQNJ12eGRjvYtXVj6vHtcHK2UtJZpfD3wtAJ
CANARY-LON-001β€” Canary Wharf Executive

SPV Structure Document

QmZf53DUoSH5wGJKeLPrLq4SFbaKj2nncWNa5TnJ9rjAVu

Property Valuation Report

QmQTNv8wSxmtAhnUZwb2jtVHKWVhW9x8u1nmdZ2d5pzuek

Lease Agreement

QmaMgjXMqUvTbwMLicL2TcAbhR6mxHuz4JEeoXoA3MYnfF
AZURE-BCN-001β€” Azure Barcelona Suite

SPV Structure Document

QmUe6PK91ZHbPGtwE6tqyp1K2AX2NYboLvzBy9usd99oxq
ERC-7984

PropertyToken.sol

0x853D51fB…21a641 β†—

One instance per property, deployed via CREATE2 from PropertyRegistry. The core confidential token β€” balances stored as euint256, encrypted by Intel TDX TEE. No observer can read holdings.

Inherits

ERC7984 (iExec Nox)OwnablePausableReentrancyGuard

Key Functions

purchaseTokens(bytes32 handle, bytes handleProof, uint256 clearAmount)public

Pay USDT, receive encrypted tokens. handle + handleProof generated by @iexec-nox/handle SDK.

grantOperator(address operator, uint256 expiry)holder

Delegate transfer rights to SecondaryMarket for listings. Expiry in unix timestamp.

pricePerToken() β†’ uint256view

Token price in USDT 6 decimals. All 5 deployed = 1_000_000 ($1.00).

propertyId() β†’ uint256view

ID assigned by PropertyRegistry (1–5 for current properties).

Notes

  • Β·Transfers never revert on insufficient balance (ERC-7984 spec β€” prevents balance inference via gas)
  • Β·Events do not emit token amounts β€” privacy by design
  • Β·Salt for CREATE2 = bytes32(propertyId) β†’ deterministic addresses
Factory

PropertyRegistry.sol

0xCdBCA38E…C00d5e β†—

Central registry and CREATE2 factory. Admin lists properties, which deploys a new PropertyToken. Tracks all holders per property for RentDistributor. Currently 5 active properties.

Inherits

OwnablePausableReentrancyGuard

Key Functions

listProperty(string name, string location, string ipfsDocHash, uint256 totalSupply, uint256 pricePerToken, uint256 monthlyRent) β†’ (uint256 propertyId, address tokenContract)onlyOwner

Deploys PropertyToken via CREATE2, registers property. pricePerToken in USDT 6 decimals.

registerHolder(uint256 propertyId, address holder)approved

Called by PropertyToken on purchase and by approved markets. Prevents duplicate entries.

setApprovedMarket(address market, bool approved)onlyOwner

Whitelist SecondaryMarket to register buyers as holders post-trade.

getPropertyHolders(uint256 propertyId) β†’ address[]view

Returns all registered holder addresses. Used by RentDistributor.

properties(uint256) β†’ Propertyview

Returns full property struct: id, name, location, supply, price, rent, status, tokenContract.

propertyCount() β†’ uint256view

Total properties listed. Currently 5.

Notes

  • Β·owner() = 0x834De729cb9dF77451DBc6bf7FD05F475B011Ac7 (treasury/deployer)
  • Β·paused() = false (all contracts operational)
P2P Marketplace

SecondaryMarket.sol

0x77836405…424cfa β†—

Fixed-price P2P listing marketplace for property token trading. Sellers post a listing at a fixed price; buyers execute against it. Token amounts moved via confidentialTransferFrom (encrypted). CEST stakers get fee discounts.

Inherits

ReentrancyGuardPausable

Key Functions

createListing(address tokenContract, uint256 propertyId, uint256 tokenAmount, uint256 pricePerToken) β†’ uint256 listingIdpublic

Requires grantOperator first. pricePerToken in USDT 6 decimals (e.g. $1.025 = 1_025_000). Returns listingId.

executeBuy(uint256 listingId)public

Buyer must approve USDT first. Triggers confidentialTransferFrom (encrypted). Deducts 0.5% fee (reduced by CEST tier).

cancelListing(uint256 listingId)seller

Seller can cancel an active listing at any time.

listings(uint256) β†’ Listingview

Returns: listingId, seller, tokenContract, propertyId, tokenAmount, pricePerToken, listedAt, active.

Notes

  • Β·Fee: 0.5% base, reduced by CEST staking tier (0% for PLATINUM)
  • Β·Seller must call propertyToken.grantOperator(secondaryMarket, expiry) before listing
  • Β·Buyer must call usdt.approve(secondaryMarket, totalCost) before executeBuy
Income

RentDistributor.sol

0x80E0e5f6…f72609 β†—

Receives monthly USDT from the property operator and distributes 90% to all registered holders. Platform takes 5%, maintenance reserve 5%. Equal-share model (not pro-rata) because ERC-7984 balances cannot be read on-chain.

Inherits

ReentrancyGuardPausableOwnable

Key Functions

depositRent(uint256 propertyId, uint256 amount)onlyOwner

Deposit USDT rent for a property. Accumulates in pendingRent[propertyId].

distributeRent(uint256 propertyId)onlyOwner

Distribute accumulated pendingRent β€” splits: 5% platform + 5% maintenance + 90% equally to all holders.

getDistributionHistory(uint256 propertyId) β†’ RentDistribution[]view

Returns past distributions for a property.

getPendingRent(uint256 propertyId) β†’ uint256view

Returns accumulated undistributed rent for a property.

Notes

  • Β·Equal share per holder β€” not pro-rata by token balance
  • Β·Pro-rata distribution planned for Phase 2 using iExec Nox compute over encrypted balances
  • Β·All distribution totals are on-chain auditable; per-investor amounts are private
ERC20Votes + Nox

CESTToken.sol

0xC6c08db8…78190D β†—

Utility and future-governance token. 1 Billion total supply. Staking unlocks: (1) SecondaryMarket fee discounts (0.5% β†’ 0% at PLATINUM), (2) TierNFT badge eligibility (determines mint tier). Now includes iExec Nox integration: after staking, holders can call encryptMyStake() to store their staked amount as an encrypted euint256 handle via Nox.fromExternal() β€” adding a confidential layer on top of the on-chain stake record. Price: $0.04 β†’ $40M market cap.

Inherits

ERC20 (OZ)ERC20Votes (OZ)ERC20Permit (OZ)Ownable (OZ)Nox SDK (iExec)

Key Functions

stake(uint256 amount, uint256 lockDays)public

Time-lock CEST for tier benefits. Min 30 days, max 365 days. Adds to existing staked amount. Tier automatically recalculates.

unstake(uint256 amount)holder

Withdraw a specific staked CEST amount after lock period expires. Tier recalculates automatically.

encryptMyStake(externalEuint256 handle, bytes handleProof)holder

iExec Nox: store your staked amount as encrypted euint256. Call after stake(). Uses Nox.fromExternal(handle, handleProof) β€” same TEE-verified pattern as PropertyToken. Only you can decrypt your stake amount off-chain via Nox JS SDK.

encryptedStake(address holder) β†’ euint256view

Returns the Nox-encrypted stake handle. Only readable (decryptable) by the holder via Nox.allow().

getTier(address account) β†’ StakingTierview

Returns NONE/BRONZE/SILVER/GOLD/PLATINUM based on staked balance. Read by TierNFT.getTier() for badge eligibility.

getFeeDiscount(address account) β†’ uint256view

Returns discount in BPS (0–10000). PLATINUM = 10000 (100% free). Used by SecondaryMarket.executeBuy().

Notes

  • Β·ERC20Votes = delegation only (future DAO) β€” ConfidentialGovernance uses PropertyToken holder status, not CEST
  • Β·TierNFT reads CESTToken.getTier() to determine which badge tier a wallet qualifies for
  • Β·Faucet drips 2,400 CEST (~$96) per address per 24h on testnet
  • Β·Total supply: 1,000,000,000 Β· Airdrop pool: 250,000,000 (25%)
Governance

ConfidentialGovernance.sol

0x32AC3549…021a14 β†—

Property-level governance gated by PropertyToken (ERC-7984) holder status β€” NOT by CEST token. Each verified holder gets exactly 1 vote regardless of their encrypted token balance, preventing whale dominance while preserving full privacy. Holder status checked via registry.isHolder().

Inherits

Ownable

Key Functions

createProposal(uint256 propertyId, ProposalType proposalType, string description) β†’ uint256 proposalIdonlyHolder

Create a governance proposal for a property. ProposalType: RentAdjustment | Maintenance | PropertyStatus | Other.

castVote(uint256 proposalId, VoteOption option)holder

1 address = 1 vote. VoteOption: For | Against | Abstain. Balance-blind β€” no whale advantage visible on-chain.

finalizeProposal(uint256 proposalId)public

Finalize a proposal after voting deadline. Checks quorum and majority. Any address can call.

getProposal(uint256 proposalId) β†’ Proposalview

Returns full proposal struct including vote counts and execution status.

getProposalsByProperty(uint256 propertyId) β†’ Proposal[]view

Returns all proposals for a property.

Notes

  • Β·Access control: registry.isHolder(propertyId, msg.sender) β€” no balance exposed
  • Β·1 address = 1 vote (balance-blind for privacy)
  • Β·Proposals: rent adjustments, maintenance, property status changes
Soulbound NFT

TierNFT.sol

0xda3072dd…5FFFfc β†—

Soulbound (non-transferable) ERC-721 tier badge. Minted by staking CEST via CESTToken.stake() and paying a CEST burn cost to the treasury (fee-discount reserve pool). Four tiers: Bronze / Silver / Gold / Platinum. Gold and Platinum additionally require the caller to hold a Nox ERC-7984 PropertyToken β€” proved via PropertyRegistry.isHolder(). On-chain testnet interaction points are stored as encrypted euint256 using Nox.fromExternal() + Nox.add() β€” the same TEE-verified pattern as PropertyToken.purchaseTokens(). No observer can read your point balance.

Inherits

ERC721 (OZ)Ownable (OZ)ReentrancyGuard (OZ)Nox SDK (iExec)

Key Functions

mint()public

Mint your tier badge. Requires: (1) CESTToken.stake(amount, days) to reach a tier, (2) CEST.approve(TierNFT, mintCost). CEST cost is sent to treasury. Gold/Platinum also require PropertyRegistry.isHolder() (Nox gate).

upgrade()holder

Upgrade existing badge to a higher tier by paying only the cost delta. Example: Bronzeβ†’Gold = 8,000βˆ’500 = 7,500 CEST. Requires CESTToken.getTier() to have increased.

recordPoints(address holder, externalEuint256 handle, bytes handleProof)onlyOwner

Record encrypted testnet interaction points. Uses Nox.fromExternal(handle, handleProof) β€” same pattern as PropertyToken. Points are accumulated as euint256: never readable on-chain. Only holder can decrypt via Nox JS SDK.

getTier(address holder) β†’ Tierview

Returns live eligible tier based on CESTToken.getTier() (staked amount). None/Bronze/Silver/Gold/Platinum.

airdropMultiplierBps(address holder) β†’ uint16view

Returns airdrop multiplier in BPS (100=1Γ—, 110=1.1Γ—, 125=1.25Γ—, 150=1.5Γ—, 200=2Γ—) based on minted badge tier.

feeDiscount(address holder) β†’ uint8view

Returns fee discount percentage (0/5/10/15/20) based on minted badge tier.

encryptedPoints(address holder) β†’ euint256view

Returns the Nox-encrypted points handle. Requires Nox.allow() access β€” only holder can decrypt off-chain.

hasBadge(address holder) β†’ boolview

Returns true if the wallet has minted a badge.

badgeTier(address holder) β†’ Tierview

Returns the tier of the minted badge (may differ from live getTier if balance dropped).

Notes

  • Β·Soulbound: _update() reverts on wallet-to-wallet transfer (ERC-721 override)
  • Β·Mint costs burned to treasury: Bronze 500 Β· Silver 2K Β· Gold 8K Β· Platinum 25K CEST
  • Β·upgrade() costs delta only: e.g. Silverβ†’Platinum = 25,000βˆ’2,000 = 23,000 CEST
  • Β·Point amounts omitted from PointsRecorded event β€” confidentiality by design
  • Β·Gold/Platinum require PropertyRegistry.isHolder() β€” must have purchased via Nox TEE first