Skip to content

Latest commit

 

History

History
372 lines (250 loc) · 9.88 KB

File metadata and controls

372 lines (250 loc) · 9.88 KB

Escrow Logic Unit Tests Documentation

Overview

This document describes the comprehensive unit test suite for escrow logic in the Stellar payroll system. The tests cover two main escrow implementations:

  1. Vesting Escrow Contract - Time-based token vesting with cliff periods and clawback
  2. Cross-Asset Payment Contract - Payment escrow for SEP-31 cross-border transactions

Test Files

  • contracts/vesting_escrow/src/test_escrow_logic.rs - Vesting escrow tests
  • contracts/cross_asset_payment/src/test_escrow.rs - Payment escrow tests

Vesting Escrow Tests

Test Categories

1. Escrow Fund Locking Tests

Tests that verify funds are properly locked in the escrow contract.

Tests:

  • test_escrow_locks_funds_on_initialization - Verifies tokens transfer from funder to contract
  • test_escrow_holds_funds_during_cliff_period - Ensures funds remain locked before cliff
  • test_escrow_prevents_unauthorized_withdrawal - Security test for unauthorized access
  • test_escrow_multiple_schedules_independent - Tests isolation between multiple escrows

Key Assertions:

  • Funder balance decreases by escrow amount
  • Contract balance equals escrow amount
  • Beneficiary balance remains zero during lock period
  • Multiple escrows don't interfere with each other

2. Vesting Calculation Tests

Tests the linear vesting formula and time-based calculations.

Tests:

  • test_linear_vesting_calculation - Validates vesting at various time points (0%, 10%, 25%, 50%, 75%, 100%)
  • test_vesting_with_cliff_calculation - Tests cliff period behavior
  • test_claimable_amount_calculation - Verifies claimable = vested - claimed
  • test_vesting_precision_no_rounding_errors - Tests with prime numbers to catch precision issues

Formula Tested:

vested = total_amount * (time_elapsed / duration_seconds)

Edge Cases:

  • Before cliff: vested = 0
  • After duration: vested = total_amount (capped)
  • During vesting: linear interpolation

3. Partial Release Tests

Tests incremental token releases as vesting progresses.

Tests:

  • test_partial_claim_releases_correct_amount - Multiple claims at different percentages
  • test_multiple_small_claims - Frequent small claims (every 10%)
  • test_claim_after_full_vesting_releases_all - Full release after vesting complete

Scenarios:

  • Claim at 25%, then 75% - verify correct deltas
  • 10 consecutive 10% claims - verify accumulation
  • Single claim after 100% vesting - verify full release

4. Clawback Mechanism Tests

Tests early termination and unvested token recovery.

Tests:

  • test_clawback_returns_unvested_to_admin - Admin receives unvested portion
  • test_clawback_before_cliff_returns_all - 100% return before any vesting
  • test_clawback_after_partial_claim - Clawback with existing claims
  • test_clawback_deactivates_future_vesting - Prevents further vesting
  • test_clawback_twice_panics - Security: prevent double clawback

Clawback Logic:

unvested = total_amount - vested_at_clawback_time
// Admin receives: unvested
// Beneficiary can still claim: vested - already_claimed

5. Token Balance Invariant Tests

Tests that ensure no tokens are created or destroyed.

Tests:

  • test_total_supply_conservation - Total tokens remain constant
  • test_escrow_balance_equals_unclaimed_vested - Contract balance = total - claimed
  • test_no_token_loss_after_clawback_and_full_claim - All tokens accounted for

Invariants:

initial_supply = funder + contract + beneficiary + admin (constant)
contract_balance = total_amount - claimed_amount

6. Edge Cases and Security Tests

Tests boundary conditions and attack vectors.

Tests:

  • test_zero_amount_escrow_panics - Reject zero amount
  • test_negative_amount_escrow_panics - Reject negative amount
  • test_very_large_escrow_amount - Handle i128::MAX / 2
  • test_very_long_vesting_duration - 10-year vesting period
  • test_claim_with_no_vested_amount_is_noop - Graceful handling of early claims
  • test_concurrent_escrows_same_beneficiary - Multiple escrows for same user

Cross-Asset Payment Escrow Tests

Test Categories

1. Escrow Fund Locking Tests

Tests payment fund locking during processing.

Tests:

  • test_payment_escrow_locks_funds - Funds transfer to contract on initiation
  • test_multiple_payments_accumulate_in_escrow - Multiple payments sum correctly
  • test_escrow_holds_funds_until_completion - Funds locked until status change

2. Payment Completion and Release Tests

Tests successful payment processing and fund release.

Tests:

  • test_complete_payment_releases_funds - Funds transfer to recipient
  • test_multiple_payments_released_independently - Independent payment processing

Flow:

initiate_payment() -> funds locked in contract
complete_payment() -> funds released to recipient

3. Payment Failure and Refund Tests

Tests refund mechanisms for failed payments.

Tests:

  • test_fail_payment_refunds_sender - Full refund on failure
  • test_partial_refund_scenario - Mixed success/failure handling

Flow:

initiate_payment() -> funds locked in contract
fail_payment() -> funds refunded to sender

4. Security and Authorization Tests

Tests replay protection and authorization.

Tests:

  • test_duplicate_payment_same_ledger_panics - Prevent replay attacks
  • test_payments_allowed_different_ledgers - Allow legitimate retries

Security Mechanism:

// Tracks last ledger per sender to prevent duplicates
LastPaymentLedger(Address) -> u32

5. Edge Cases and Invariant Tests

Tests system invariants and boundary conditions.

Tests:

  • test_escrow_balance_invariant - Contract balance matches pending payments
  • test_large_payment_amount - Handle large amounts (500M)
  • test_payment_count_accuracy - Counter increments correctly
  • test_zero_balance_after_all_payments_processed - Clean state after processing

Invariant:

contract_balance = sum(pending_payment_amounts)

Running the Tests

Run All Escrow Tests

# Vesting escrow tests
cd contracts/vesting_escrow
cargo test test_escrow_logic

# Cross-asset payment escrow tests
cd contracts/cross_asset_payment
cargo test test_escrow

# Run all contract tests
cargo test --all

Run Specific Test

# Run single test
cargo test test_escrow_locks_funds_on_initialization

# Run test category
cargo test test_escrow_locks -- --nocapture

# Run with output
cargo test -- --nocapture --test-threads=1

Run with Coverage

# Install tarpaulin
cargo install cargo-tarpaulin

# Generate coverage report
cargo tarpaulin --out Html --output-dir coverage

Test Patterns and Best Practices

1. Setup Pattern

Each test uses a setup function that:

  • Creates a fresh test environment
  • Generates test addresses
  • Registers contracts
  • Mints initial tokens
  • Returns all necessary clients
let (e, funder, beneficiary, admin, token, token_client, _, client, contract_addr) = setup_escrow();

2. Ledger Manipulation

Tests control time and sequence:

e.ledger().set_timestamp(start + 500);  // Advance time
e.ledger().set_sequence_number(10);     // Set ledger sequence

3. Balance Assertions

Always verify all relevant balances:

assert_eq!(token_client.balance(&sender), expected_sender);
assert_eq!(token_client.balance(&contract), expected_contract);
assert_eq!(token_client.balance(&recipient), expected_recipient);

4. Panic Testing

Use #[should_panic] for expected failures:

#[test]
#[should_panic(expected = "Already initialized")]
fn test_double_init_panics() {
    // Test code that should panic
}

Test Coverage

Vesting Escrow Coverage

  • Initialization: 100% (all paths tested)
  • Vesting Calculation: 100% (all time ranges)
  • Claim Logic: 100% (all scenarios)
  • Clawback Logic: 100% (all scenarios)
  • Edge Cases: 95% (most boundary conditions)

Cross-Asset Payment Coverage

  • Payment Initiation: 100%
  • Payment Completion: 100%
  • Payment Failure: 100%
  • Replay Protection: 100%
  • Edge Cases: 90%

Known Limitations

  1. Time Precision: Tests use second-level precision; sub-second vesting not tested
  2. Gas Costs: Tests don't verify gas optimization
  3. Concurrent Access: Limited testing of high-concurrency scenarios
  4. Network Conditions: Tests run in isolated environment, not on actual network

Future Test Enhancements

  1. Property-Based Testing: Use quickcheck/proptest for fuzzing
  2. Integration Tests: Test contract interactions with real Stellar network
  3. Performance Tests: Benchmark gas costs and execution time
  4. Stress Tests: Test with thousands of concurrent escrows
  5. Upgrade Tests: Test contract upgrade scenarios

Debugging Failed Tests

Common Issues

  1. Balance Mismatch

    • Check initial token minting
    • Verify all transfers are accounted for
    • Check for integer overflow
  2. Timing Issues

    • Ensure ledger timestamp is set correctly
    • Verify cliff and duration calculations
    • Check for off-by-one errors
  3. Panic Messages

    • Read panic message carefully
    • Check authorization requirements
    • Verify ledger sequence uniqueness

Debug Commands

# Run with backtrace
RUST_BACKTRACE=1 cargo test test_name

# Run with logging
RUST_LOG=debug cargo test test_name

# Run single test with output
cargo test test_name -- --nocapture --test-threads=1

Contributing

When adding new escrow tests:

  1. Follow existing naming conventions
  2. Add tests to appropriate category
  3. Include descriptive comments
  4. Test both success and failure paths
  5. Verify all balance invariants
  6. Update this documentation

References