Skip to content

Latest commit

 

History

History
177 lines (136 loc) · 6.01 KB

File metadata and controls

177 lines (136 loc) · 6.01 KB

Batch Remittance Creation Implementation

Overview

This document describes the implementation of batch remittance creation for SwiftRemit, which allows high-volume senders to create multiple remittances in a single atomic transaction, reducing ledger fees.

Changes Made

1. Type Definition (src/types.rs)

Added BatchCreateEntry struct to represent individual entries in a batch:

#[contracttype]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct BatchCreateEntry {
    /// Address of the agent who will receive the payout
    pub agent: Address,
    /// Amount to send (in USDC)
    pub amount: i128,
    /// Optional expiry timestamp (seconds since epoch) for settlement
    pub expiry: Option<u64>,
}

2. Batch Creation Function (src/lib.rs)

Added batch_create_remittances function with the following features:

Key Features:

  • Atomic Operation: All entries are validated before any state changes occur
  • Single Token Transfer: Total amount is transferred in one transaction
  • Batch Size Limit: Maximum 100 entries per batch (MAX_BATCH_SIZE)
  • Comprehensive Validation: Each entry is validated individually
  • Daily Limit Enforcement: Each entry checks daily send limits

Function Signature:

pub fn batch_create_remittances(
    env: Env,
    sender: Address,
    entries: Vec<BatchCreateEntry>,
) -> Result<Vec<u64>, ContractError>

Implementation Details:

  1. Batch Size Validation: Checks that batch is not empty and doesn't exceed MAX_BATCH_SIZE (100)

  2. Pre-validation Phase:

    • Validates all entries before any state changes
    • Checks agent registration for each entry
    • Validates amounts are positive
    • Ensures sender is not blacklisted
    • Enforces daily send limits for each entry
    • Accumulates total amount with overflow protection
  3. Token Transfer:

    • Transfers total amount in a single token transfer
    • Reduces ledger fees compared to individual transfers
  4. Remittance Creation:

    • Creates all remittances with sequential IDs
    • Calculates fees for each entry individually
    • Sets up payout commitments
    • Initializes transfer states
    • Indexes remittances under sender for queries
  5. Counter Update: Updates remittance counter once at the end

3. Unit Tests (src/test_batch_create.rs)

Created comprehensive test suite covering:

  1. Success Case: Multiple entries with different agents and amounts
  2. Partial Failure: Atomic rollback when one entry fails validation
  3. Oversized Batch: Rejection of batches exceeding 100 entries
  4. Empty Batch: Rejection of empty batch
  5. Invalid Amount: Rejection when any entry has zero/negative amount
  6. Maximum Size: Successful creation of exactly 100 entries
  7. Different Amounts: Verification of fee calculation for varying amounts

4. README Update

Checked off "Batch remittance processing" in the roadmap section.

Acceptance Criteria Met

Batch size limited to MAX_BATCH_SIZE (100)

  • Implemented validation in batch_create_remittances function
  • Returns ContractError::InvalidBatchSize if batch is empty or exceeds 100

Atomic: all succeed or all fail

  • All entries are validated before any state changes
  • If any validation fails, no remittances are created
  • Token transfer only occurs after all validations pass

Single token transfer for the total amount

  • Total amount is accumulated during validation
  • Single token_client.transfer() call with total amount
  • Reduces ledger fees compared to N individual transfers

Unit tests cover: success, partial failure, oversized batch

  • test_batch_create_success: Multiple entries succeed
  • test_batch_create_partial_failure: Atomic rollback on validation failure
  • test_batch_create_oversized: Rejection of >100 entries
  • Additional tests for edge cases

README roadmap item checked off

  • Updated README.md to mark batch remittance processing as complete

Error Handling

The function returns appropriate errors for various failure scenarios:

  • ContractError::InvalidBatchSize: Batch is empty or exceeds 100 entries
  • ContractError::InvalidAmount: Any entry has zero or negative amount
  • ContractError::AgentNotRegistered: Any agent is not registered
  • ContractError::UserBlacklisted: Sender is blacklisted
  • ContractError::DailySendLimitExceeded: Total amount exceeds daily limit
  • ContractError::Overflow: Arithmetic overflow in amount calculation
  • ContractError::MigrationInProgress: Contract migration is in progress

Usage Example

// Create batch entries
let mut entries = Vec::new(&env);
entries.push_back(BatchCreateEntry {
    agent: agent1,
    amount: 100_000_000, // 100 USDC
    expiry: None,
});
entries.push_back(BatchCreateEntry {
    agent: agent2,
    amount: 200_000_000, // 200 USDC
    expiry: Some(env.ledger().timestamp() + 3600),
});

// Execute batch creation
let remittance_ids = batch_create_remittances(
    env.clone(),
    sender.clone(),
    entries
)?;

// Returns vector of created remittance IDs
assert_eq!(remittance_ids.len(), 2);

Benefits

  1. Cost Reduction: Single token transfer instead of N transfers reduces ledger fees
  2. Atomicity: All-or-nothing execution ensures data consistency
  3. Efficiency: Batch processing is more efficient than individual calls
  4. Validation: Comprehensive pre-validation prevents partial state changes
  5. Scalability: Supports up to 100 entries per batch

Testing

The implementation includes 7 comprehensive unit tests covering:

  • Success scenarios with multiple entries
  • Atomic rollback on validation failures
  • Batch size limits (empty, oversized, maximum)
  • Invalid amounts
  • Different fee calculations

All tests follow the existing test patterns in the codebase and use the Soroban testing framework.

Future Enhancements

Potential improvements for future iterations:

  • Support for corridor-specific fees in batch entries
  • Idempotency key support for batch operations
  • Batch settlement confirmation
  • Batch cancellation
  • Performance optimizations for large batches