Smart Contracts

Overview

Money Race is powered by Sui Move smart contracts deployed as the money_race_v2 module. All core protocol logic—room management, periodic deposits, and proportional reward distribution—is handled on-chain with 100% gasless transactions for users.

Key Characteristics:

  • 🔐 Non-custodial — Users control funds via PlayerPosition NFTs

  • 🆓 Gasless — Backend sponsors all gas fees (users pay zero SUI)

  • 📊 Proportional — Rewards based on consistency, NO penalties

  • 🏦 Vault-based — Separate principal and reward balances


Contract Architecture

Contract Architecture

Design Pattern: Object-centric architecture where Room and Vault are shared objects, while PlayerPosition is an owned NFT giving users exclusive control over their participation.


Core Structs

1. AdminCap

Admin capability object for privileged operations:

Used for:

  • Starting rooms (start_room())

  • Finalizing rooms (finalize_room())


2. Room

The savings room object (shared):

Status Lifecycle:

Period Calculation:

Examples:


3. Vault

Holds all deposited funds (shared):

Balance Flow (Testnet Simulation):

Mainnet (Future):


4. PlayerPosition

User's participation NFT (owned by player):

Key Fields:

  • deposited_count — Used to calculate proportional share (deposited_count / total_weight)

  • last_period — Prevents double-depositing in same period

  • claimed — Ensures one-time claim only


Constants

Room Status

Strategy IDs

Yield Rates (Testnet Simulation)

Note: Basis points (bps) where 100 bps = 1%. Testnet simulates yield by moving principal to reward pool. Mainnet will integrate real DeFi protocols.


Entry Functions

create_room()

Create a new savings room:

Creates:

  • Room object (shared)

  • Vault object (shared)

Emits: RoomCreated event

Example:


start_room()

Admin starts the room (moves from OPEN to ACTIVE):

Requirements:

  • Caller must have AdminCap

  • Room status must be OPEN


join_room()

Join room and make first deposit (period 0):

Requirements:

  • Room status must be ACTIVE

  • Current period must be 0 (first period)

  • Coin amount must equal room.deposit_amount

Effects:

  • Deposit added to vault.principal

  • PlayerPosition NFT created and transferred to user

  • room.total_weight increases by 1

  • accrue_yield() called to simulate yield

Emits: PlayerJoined event


deposit()

Make periodic deposit (periods 1+):

Requirements:

  • Room status must be ACTIVE

  • Current period < total_periods

  • Current period > player.last_period (prevents double deposit)

  • Coin amount must equal room.deposit_amount

Effects:

  • Deposit added to vault.principal

  • player.deposited_count increases by 1

  • player.last_period updated to current period

  • room.total_weight increases by 1

  • accrue_yield() called to simulate yield

Emits: DepositMade event


finalize_room()

Admin finalizes room (moves from ACTIVE to FINISHED):

Requirements:

  • Caller must have AdminCap

  • Room status must be ACTIVE

  • room.total_weight > 0 (at least one deposit made)

Effects:

  • Final accrue_yield() called

  • Room status set to FINISHED


claim_all()

Claim proportional principal + reward:

Requirements:

  • Room status must be FINISHED

  • player.claimed must be false (one-time claim)

Proportional Distribution Formula:

Effects:

  • Two Coin transfers to player.owner:

    • principal_coin (proportional principal)

    • reward_coin (proportional yield)

  • player.claimed set to true

  • room.total_weight decreased by player.deposited_count

Emits: RewardsClaimed event

Example:


Internal Functions

current_period()

Calculate which period the room is currently in:


accrue_yield()

Simulate external yield (testnet only):

Testnet Simulation: Yield is simulated by moving principal to reward pool, creating a zero-sum environment for demo purposes.

Mainnet: This function will integrate with real Sui DeFi protocols (Scallop, Navi, Cetus, Turbos, Kriya, Aftermath) to generate genuine external yield, keeping principal 100% intact.


Events

RoomCreated

PlayerJoined

DepositMade

YieldAccrued

RewardsClaimed


Security Features

Object Ownership Model

  • PlayerPosition is owned by user (non-custodial)

  • Room and Vault are shared objects (transparent state)

Access Control

  • AdminCap required for privileged operations

  • PlayerPosition ownership verified on-chain

Balance Safety

  • Proper Balance<USDC> handling with balance::split() and balance::join()

  • No direct coin manipulation

Double-Deposit Prevention

  • player.last_period prevents depositing twice in same period

One-Time Claim

  • player.claimed boolean ensures single claim only

Time-Based Logic

  • Clock object used for accurate period calculation

  • No reliance on block timestamps

Safe Math

  • All arithmetic uses u64 with proper overflow checks

  • Proportional distribution using integer division


Gasless Transactions

Money Race is 100% gasless for users.

How it works:

  1. User signs transaction with their wallet/zkLogin

  2. Backend adds sponsor signature using Gas Station pattern

  3. Backend pays gas in SUI

  4. User only needs USDC, zero SUI required

Sponsored Operations:

  • create_room() → Gasless ✅

  • join_room() → Gasless ✅

  • deposit() → Gasless ✅

  • claim_all() → Gasless ✅

Backend Implementation:


Testnet vs Mainnet

Aspect
Testnet (Current)
Mainnet (Coming)

Yield Source

Simulated (moves principal to reward)

Real (external DeFi protocols)

Principal

Reduced by yield simulation

100% intact

Protocols

None (simulation only)

Scallop, Navi, Cetus, Turbos, Kriya, Aftermath

APY

Fixed (4%/8%/15%)

Variable (market rates)

accrue_yield()

Cuts from principal

Adds from DeFi protocols


Example Flow

Complete User Journey:


Contract Deployment

Package ID (Testnet):

Module Name:

View on Sui Explorer: https://suiexplorer.com/object/0x0e5bb307c15081e2159f2a3a4d4aa509bd0ed1cda6338accf4189e734c5f122c?network=testnetarrow-up-right


Next: Deployments →

Last updated