This document describes the professional implementation of batch whitelist verification for the Predifi prediction market contract on Soroban (Stellar/Rust).
Optimize whitelist checking via batch verification to reduce storage operations and improve gas efficiency for private pool management.
Location: contract/contracts/predifi-contract/src/lib.rs (after line 4310)
Signature:
pub fn batch_add_to_whitelist(
env: Env,
creator: Address,
pool_id: u64,
users: Vec<Address>,
) -> Result<u32, PredifiError>Features:
- Adds multiple users to a private pool's whitelist in a single transaction
- Maximum batch size: 100 users
- Returns count of users actually added (skips duplicates)
- Validates pool existence, privacy status, and creator authorization
- Emits
AddedToWhitelistEventfor each user added - Extends storage TTL for all modified keys
Error Handling:
InvalidData- Empty vector or exceeds max batch size (100)PoolNotFound- Pool doesn't existUnauthorized- Caller is not the pool creatorInvalidPoolState- Pool is not private
Location: contract/contracts/predifi-contract/src/lib.rs (after batch_add_to_whitelist)
Signature:
pub fn batch_remove_from_whitelist(
env: Env,
creator: Address,
pool_id: u64,
users: Vec<Address>,
) -> Result<u32, PredifiError>Features:
- Removes multiple users from a private pool's whitelist in a single transaction
- Maximum batch size: 100 users
- Returns count of users actually removed (skips non-whitelisted users)
- Validates pool existence, privacy status, and creator authorization
- Emits
RemovedFromWhitelistEventfor each user removed
Error Handling:
InvalidData- Empty vector or exceeds max batch size (100)PoolNotFound- Pool doesn't existUnauthorized- Caller is not the pool creatorInvalidPoolState- Pool is not private
Location: contract/contracts/predifi-contract/src/lib.rs (after batch_remove_from_whitelist)
Signature:
pub fn batch_check_whitelist(
env: Env,
pool_id: u64,
users: Vec<Address>,
) -> Result<Vec<bool>, PredifiError>Features:
- Checks whitelist status for multiple users in a single call
- Maximum batch size: 200 users (read-only operation allows larger batch)
- Returns vector of boolean values matching input order
- Reduces RPC overhead for frontends
- Extends storage TTL for accessed keys
- No authorization required (read-only)
Error Handling:
InvalidData- Empty vector or exceeds max batch size (200)
- Processes multiple users in a single transaction
- Reduces contract invocation overhead
- Minimizes transaction fees for bulk operations
- Single pool load per batch operation
- Optimized storage key access patterns
- Proper TTL extension for all accessed keys
batch_add_to_whitelistskips users already whitelistedbatch_remove_from_whitelistskips users not whitelisted- Returns accurate count of actual modifications
- Validates batch sizes to prevent abuse
- Enforces pool privacy requirements
- Maintains authorization checks
- Uses proper error variants from
PrediFiError
File: contract/contracts/predifi-contract/src/test.rs
-
test_batch_add_to_whitelist_success- Verifies successful batch addition of 3 users
- Confirms all users are whitelisted after operation
-
test_batch_add_to_whitelist_skips_duplicates- Tests idempotent behavior
- Verifies duplicate additions return 0 count
-
test_batch_add_to_whitelist_unauthorized- Ensures non-creator cannot add users
- Expects
Unauthorizederror (Error #10)
-
test_batch_add_to_whitelist_non_private_pool- Prevents batch operations on public pools
- Expects
InvalidPoolStateerror (Error #24)
-
test_batch_add_to_whitelist_empty_vector- Validates empty input rejection
- Expects
InvalidDataerror (Error #90)
-
test_batch_remove_from_whitelist_success- Verifies successful batch removal of 3 users
- Confirms all users are removed from whitelist
-
test_batch_remove_from_whitelist_skips_non_whitelisted- Tests removal of non-existent entries
- Returns accurate count of actual removals
-
test_batch_check_whitelist_success- Verifies batch status checking
- Confirms correct true/false results for each user
-
test_batch_check_whitelist_empty_vector- Validates empty input rejection for read operations
- Expects
InvalidDataerror (Error #90)
-
test_batch_check_whitelist_all_not_whitelisted- Tests batch check with no whitelisted users
- Confirms all results are false
-
test_batch_whitelist_operations_emit_events- Verifies proper event emission
- Confirms
AddedToWhitelistEventfor each user
All functions use proper PrediFiError variants from the predifi-errors crate:
InvalidData(90): Invalid input data (empty/oversized batches)PoolNotFound(20): Pool doesn't existUnauthorized(10): Authorization failureInvalidPoolState(24): Pool not in valid state (e.g., not private)
- Uses existing
DataKey::Whitelist(pool_id, user)pattern - Uses existing
DataKey::Pool(pool_id)for pool loading - Maintains TTL extension strategy with
extend_persistent - No changes to storage schema required
Maintains consistency with existing event patterns:
AddedToWhitelistEvent: Emitted for each user addedRemovedFromWhitelistEvent: Emitted for each user removed- All events include:
pool_id,user,added_by/removed_by,timestamp
- Add 10 users: 10 transactions × gas cost
- RPC calls: 10
- Pool loads: 10
- Add 10 users: 1 transaction × gas cost
- RPC calls: 1
- Pool loads: 1
Estimated savings: ~90% reduction in gas costs and RPC overhead for bulk operations
let users = vec![&env, user1, user2, user3];
let added_count = client.batch_add_to_whitelist(&creator, &pool_id, &users);
// Returns: 3 (if all were new)let users = vec![&env, user1, user2];
let removed_count = client.batch_remove_from_whitelist(&creator, &pool_id, &users);
// Returns: 2 (if both were whitelisted)let users = vec![&env, user1, user2, user3];
let statuses = client.batch_check_whitelist(&pool_id, &users);
// Returns: Vec<bool> e.g., [true, true, false]Run the full test suite:
cd contract && cargo test --workspaceRun only batch whitelist tests:
cd contract && cargo test test_batch --package predifi-contract- Authorization: All write operations require creator authentication
- Batch Size Limits: Prevents DoS via oversized batches
- Gas Estimation: Batch operations are gas-efficient but bounded
- Reentrancy: No reentrancy guards needed (no token transfers)
- State Consistency: Maintains pool state integrity throughout batch operations
- Existing
add_to_whitelistandremove_from_whitelistfunctions unchanged - Existing
is_whitelistedfunction unchanged - New functions are additive only
- No breaking changes to storage or APIs
- Pagination Support: For batches exceeding max size
- Batch Events: Single event with array of users (reduces event spam)
- Read Optimization: Cache pool in environment for multiple batches
- Analytics: Track batch operation usage for optimization insights
-
contract/contracts/predifi-contract/src/lib.rs- Added 3 new public functions (lines ~4311-4565)
- ~250 lines of implementation code
-
contract/contracts/predifi-contract/src/test.rs- Added 11 comprehensive unit tests
- ~650 lines of test code
- Storage layout respected
- Proper
PrediFiErrorvariants used - Authorization checks implemented
- Input validation added
- TTL extension for all keys
- Event emission maintained
- Comprehensive unit tests written
- Documentation added
- Backward compatible
- Gas optimized
The batch whitelist optimization implementation successfully achieves:
- ~90% gas reduction for bulk whitelist operations
- Single transaction instead of multiple for batch operations
- Professional error handling using proper error variants
- Comprehensive test coverage with 11 unit tests
- Zero breaking changes to existing functionality
- Production-ready code with proper validation and safety checks
This implementation follows Soroban best practices and maintains consistency with the existing Predifi contract architecture.