Skip to content

[Security] Implement Token Whitelist, Standard Detection, and Safe Transfer Verification #23

Description

@KarenZita01

Description

The asset.rs module handles token types (Stellar Asset Contract tokens) but does not implement a proper token whitelist, blacklist, or sanitization for the tokens accepted by the protocol. Any token address can be used in register_meter, lock_guarantor_deposit, initialize_gas_buffer, and other functions. This exposes the protocol to potential attacks using malicious or non-standard tokens (rebasing tokens, fee-on-transfer tokens, ERC-777-style hooks, pausable tokens, tokens that revert on zero-value transfers).

Token sanitization gaps:

  • No token whitelist enforced for critical operations (gas buffer, insurance pool, streaming)
  • No balance checks before/after transfers to detect fee-on-transfer tokens
  • No maximum approval limits for token interactions
  • No detection of non-standard token behavior (rebasing, pausing)
  • No handling for tokens with >18 or <6 decimals
  • No token metadata validation (name, symbol, decimals)

Technical Context & Impact

  • Affected Components/Files: contracts/utility_contracts/src/asset.rs, contracts/utility_contracts/src/lib.rs (all token transfer calls), contracts/utility_contracts/src/stream.rs
  • Impact: Security, Protocol Solvency, User Protection

Step-by-Step Implementation Guide

  1. Implement token whitelist: DataKey::ApprovedTokens as a Vec<Address>; require_approved_token(&env, &token_address) guard on all token deposit/transfer functions
  2. Add balance change verification: After every token_client.transfer, verify balance_after == balance_before + expected_amount (vs balance_after >= balance_before + expected_amount for fee-on-transfer)
  3. Add admin token management: approve_token(token_address), revoke_token(token_address), get_approved_tokens(page, page_size)
  4. Detect non-standard tokens: validate_token(token_address) -> TokenStandard { Standard, Rebasing, FeeOnTransfer, Blacklisted } using on-chain heuristics
  5. Handle decimals: Store DataKey::TokenDecimals(token) and normalize all amounts to 7-decimal fixed point internally
  6. Add max transfer guard: transfer(amount) should cap at min(amount, user_balance) to prevent partial fill issues
  7. Write token compatibility tests: Test with mock rebasing token, fee-on-transfer token, and reverting token contracts

Verification & Testing Steps

  1. Test with standard token: deposit -> verify -> withdraw -> verify amounts match
  2. Test with fee-on-transfer mock token (charges 1% on transfer): deposit -> verify balance reflects fee -> withdrawal should use actual balance
  3. Test with unapproved token: attempt deposit -> should be rejected
  4. Test decimals: register token with 6 decimals, 8 decimals, 18 decimals -> verify internal normalization works
  5. Run full test suite: cargo test --package utility_contracts
  6. Deploy to testnet and test with real Stellar tokens (USDC, XLM)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions