Skip to content

Latest commit

 

History

History
123 lines (91 loc) · 3.42 KB

File metadata and controls

123 lines (91 loc) · 3.42 KB

Withdrawal Function - Quick Summary

What Was Implemented

A secure withdraw() function in the Soroban smart contract that allows designated winners to withdraw collected pools for specific cycles.

Key Features

1. Cycle-to-Recipient Mapping ✅

  • Uses RotationOrder storage (shuffled member list)
  • Enforces strict rotation: only designated member can withdraw for their cycle
  • Validates cycle index against rotation order

2. Cycle Maturity Check ✅

  • New helper: get_cycle_deadline(env, cycle)
  • Calculates deadline: initial_deadline + (cycles_elapsed * frequency_days * 86400)
  • Rejects withdrawals before cycle deadline

3. Pool Funding Verification ✅

  • New helper: is_cycle_fully_funded(env, cycle, required_amount)
  • Checks all members contributed: total_contributed >= (cycle * contribution_amount)
  • Ensures pool has sufficient funds

4. Reentrancy Protection ✅

  • Follows Checks-Effects-Interactions pattern
  • Updates state BEFORE token transfer
  • New storage: CycleWithdrawals - tracks withdrawals per cycle
  • Prevents double-withdrawal attacks

Code Changes

File: contracts/ajo-circle/src/lib.rs

  1. Added DataKey:

    CycleWithdrawals, // Map<cycle, Map<member, bool>>
  2. New Functions:

    • withdraw(env, member, cycle) - Main withdrawal function
    • get_cycle_deadline(env, cycle) - Calculate cycle deadline
    • is_cycle_fully_funded(env, cycle, amount) - Verify funding
  3. Updated Function:

    • claim_payout() - Now wraps withdraw() for backward compatibility
  4. Added Tests (8 new tests):

    • Happy path withdrawal
    • Double-withdrawal prevention
    • Rotation enforcement
    • Rotation requirement
    • Cycle validation
    • Panic protection
    • Member standing check
    • Backward compatibility

Security Measures

  • ✅ Authorization via member.require_auth()
  • ✅ Panic state blocking
  • ✅ Cycle range validation (1 to max_rounds)
  • ✅ Member standing verification
  • ✅ Rotation order enforcement
  • ✅ Double-withdrawal prevention
  • ✅ State updates before transfers (reentrancy protection)
  • ✅ Time-based maturity checks
  • ✅ Pool funding verification

Usage

// Withdraw for cycle 1
let payout = contract.withdraw(&member_address, &1_u32)?;

// Legacy function still works
let payout = contract.claim_payout(&member_address)?;

Testing

cd contracts/ajo-circle
cargo test test_withdraw  # Run withdrawal tests
cargo test                # Run all tests

Files Modified

  1. contracts/ajo-circle/src/lib.rs - Main implementation
  2. WITHDRAWAL_IMPLEMENTATION.md - Detailed documentation
  3. WITHDRAWAL_SUMMARY.md - This file

Next Steps

To deploy and use:

  1. Build the contract:

    cd contracts/ajo-circle
    cargo build --target wasm32-unknown-unknown --release
  2. Deploy to Stellar testnet using Soroban CLI

  3. Update frontend to call withdraw() function

  4. Test thoroughly on testnet before mainnet deployment

Error Codes

  • CirclePanicked - Emergency state active
  • InvalidInput - Invalid cycle or not mature
  • Disqualified - Member inactive
  • InsufficientFunds - Pool not fully funded
  • Unauthorized - Wrong member for cycle
  • AlreadyPaid - Already withdrawn
  • NotFound - Data missing

Backward Compatibility

✅ Existing claim_payout() calls continue to work ✅ All security improvements apply to legacy calls ✅ No breaking changes to existing integrations