Skip to main content

CurrencyTransferLib

Overview

CurrencyTransferLib is a utility library that provides safe and efficient functions for transferring ERC20 tokens and native ETH. It includes comprehensive error handling, gas optimization, and supports both standard token transfers and native currency operations.

Contract Specification

library CurrencyTransferLib

Library Type: Utility library for safe token transfers Usage: Used internally by staking contracts for all token operations

Constants

address public constant NATIVE_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;

This constant represents native ETH transfers using a special address identifier.

Core Functions

Token Transfer Functions

transferCurrency

function transferCurrency(address currency, address to, uint256 amount) internal

Safely transfers tokens or native ETH to a specified address.

Parameters:

  • currency: Token contract address (or NATIVE_TOKEN for ETH)
  • to: Recipient address
  • amount: Amount to transfer

Behavior:

  • If currency == NATIVE_TOKEN: Transfers native ETH
  • Otherwise: Transfers ERC20 tokens using safe transfer

Error Handling:

  • Reverts with TransferFailed if transfer fails
  • Includes recipient address and amount in error for debugging

transferCurrencyWithWrapper

function transferCurrencyWithWrapper(address currency, address to, uint256 amount, address wrapperToken) internal

Transfers tokens with wrapper token support for protocols that need WETH handling.

Parameters:

  • currency: Token contract address
  • to: Recipient address
  • amount: Amount to transfer
  • wrapperToken: Wrapper token address (e.g., WETH)

Behavior:

  • If currency == NATIVE_TOKEN: Uses wrapper token for transfer
  • Otherwise: Standard ERC20 transfer

Transfer Verification Functions

safeTransferFrom

function safeTransferFrom(address token, address from, address to, uint256 amount) internal

Safely transfers tokens from one address to another with balance verification.

Parameters:

  • token: ERC20 token contract address
  • from: Source address
  • to: Recipient address
  • amount: Amount to transfer

Safety Features:

  • Verifies balance before transfer
  • Checks balance after transfer
  • Handles tokens with non-standard return values
  • Comprehensive error reporting

Process:

  1. Records recipient's balance before transfer
  2. Executes transferFrom call
  3. Verifies balance increase matches expected amount
  4. Reverts if balance verification fails

safeTransfer

function safeTransfer(address token, address to, uint256 amount) internal

Safely transfers tokens from current contract to specified address.

Parameters:

  • token: ERC20 token contract address
  • to: Recipient address
  • amount: Amount to transfer

Safety Features:

  • Balance verification before and after transfer
  • Handles non-standard ERC20 implementations
  • Detailed error reporting

Native ETH Transfer Functions

safeTransferNativeToken

function safeTransferNativeToken(address to, uint256 value) internal

Safely transfers native ETH to specified address.

Parameters:

  • to: Recipient address
  • value: Amount of ETH to transfer in wei

Safety Features:

  • Uses low-level call for gas efficiency
  • Checks call success
  • Reverts with descriptive error if transfer fails

safeTransferNativeTokenWithWrapper

function safeTransferNativeTokenWithWrapper(address to, uint256 value, address wrapperToken) internal

Transfers native ETH using wrapper token (WETH) for protocols requiring wrapped ETH.

Parameters:

  • to: Recipient address
  • value: Amount to transfer
  • wrapperToken: Wrapper token address

Process:

  1. Uses IWETH interface to interact with wrapper
  2. Withdraws ETH from wrapper contract
  3. Transfers unwrapped ETH to recipient

Internal Helper Functions

Low-Level Transfer Operations

_callOptionalReturn

function _callOptionalReturn(address token, bytes memory data) private returns (bool)

Executes low-level call to token contract and handles return value variations.

Parameters:

  • token: Token contract address
  • data: Encoded function call data

Returns:

  • Boolean indicating success of the operation

Handling:

  • Supports tokens that return bool values
  • Supports tokens with no return value
  • Validates return data length and value

_checkReturnValue

function _checkReturnValue(bool success, bytes memory returndata) private pure returns (bool)

Validates return data from token contract calls.

Parameters:

  • success: Whether the low-level call succeeded
  • returndata: Return data from the call

Returns:

  • Boolean indicating if the operation was successful

Validation Logic:

  • If no return data: considers success if call succeeded
  • If return data exists: validates it represents true

Error Handling

Custom Errors

error TransferFailed(address to, uint256 amount);
error InsufficientBalance(address token, address account, uint256 required, uint256 available);
error TransferReturnValueInvalid(address token);
error NativeTokenTransferFailed(address to, uint256 amount);

Error Conditions

TransferFailed:

  • Triggered when token transfer operation fails
  • Includes recipient address and amount for debugging

InsufficientBalance:

  • Triggered when account has insufficient token balance
  • Provides detailed balance information

TransferReturnValueInvalid:

  • Triggered when token returns invalid data
  • Indicates non-compliant ERC20 implementation

NativeTokenTransferFailed:

  • Triggered when ETH transfer fails
  • Includes recipient and amount information

Token Compatibility

Standard ERC20 Tokens

Supports tokens that follow ERC20 standard:

  • Return true on successful transfers
  • Revert on failed transfers
  • Standard transfer() and transferFrom() functions

Non-Standard Tokens

Handles tokens with variations:

  • Tokens that don't return values (e.g., USDT)
  • Tokens that return false instead of reverting
  • Tokens with different return data formats

Balance Verification

Additional safety through balance checks:

  • Compares balances before and after transfers
  • Ensures expected amount was actually transferred
  • Protects against tokens with transfer fees or rebasing mechanisms

Gas Optimization

Efficient ETH Transfers

  • Uses low-level call for ETH transfers
  • Avoids unnecessary operations
  • Minimizes gas overhead

Batch Operations

  • Optimized for use in loops
  • Efficient error handling
  • Minimal storage operations

Call Pattern Optimization

  • Single external call per operation
  • Efficient return data handling
  • Optimized assembly for balance checks

Integration Patterns

Staking Contract Usage

contract StakingContract {
using CurrencyTransferLib for address;

function stake(uint256 amount) external {
// Transfer tokens from user to contract
CurrencyTransferLib.safeTransferFrom(
stakingToken,
msg.sender,
address(this),
amount
);
}

function withdraw(uint256 amount) external {
// Transfer tokens from contract to user
CurrencyTransferLib.safeTransfer(
stakingToken,
msg.sender,
amount
);
}
}

Fee Collection

function collectFee(address token, uint256 feeAmount) internal {
if (token == CurrencyTransferLib.NATIVE_TOKEN) {
CurrencyTransferLib.safeTransferNativeToken(
feeCollector,
feeAmount
);
} else {
CurrencyTransferLib.safeTransfer(
token,
feeCollector,
feeAmount
);
}
}

Multi-Token Support

function transferMultipleTokens(
address[] calldata tokens,
address[] calldata recipients,
uint256[] calldata amounts
) external {
for (uint256 i = 0; i < tokens.length; i++) {
CurrencyTransferLib.transferCurrency(
tokens[i],
recipients[i],
amounts[i]
);
}
}

Security Features

Reentrancy Protection

  • Uses _callOptionalReturn to minimize external call risks
  • Designed for use with ReentrancyGuard
  • Safe for use in complex contract interactions

Balance Validation

  • Pre and post-transfer balance checks
  • Protection against fee-on-transfer tokens
  • Verification of actual transferred amounts

Return Value Handling

  • Comprehensive handling of different return patterns
  • Protection against malicious token contracts
  • Graceful handling of non-compliant tokens

Address Validation

  • Zero address checks where appropriate
  • Validation of contract addresses
  • Protection against invalid transfer destinations

Wrapper Token Support

WETH Integration

The library provides special handling for WETH (Wrapped ETH):

interface IWETH {
function withdraw(uint256 amount) external;
function deposit() external payable;
}

Wrapper Usage Patterns

Deposit ETH to WETH:

  • Contract receives ETH
  • Wraps to WETH for protocol compatibility
  • Transfers WETH to recipient

Withdraw WETH to ETH:

  • Contract holds WETH
  • Unwraps to native ETH
  • Transfers ETH to recipient

Best Practices

Function Selection

Use safeTransfer when:

  • Transferring from contract to external address
  • Known token balances
  • Simple transfer operations

Use safeTransferFrom when:

  • Transferring from external address to contract
  • User-initiated transfers
  • Allowance-based transfers

Use transferCurrency when:

  • Supporting both ETH and ERC20 tokens
  • Generic transfer operations
  • Multi-token protocols

Error Handling

  • Always handle transfer failures gracefully
  • Provide meaningful error messages
  • Include relevant addresses and amounts in errors

Gas Efficiency

  • Batch transfers when possible
  • Minimize external calls
  • Use appropriate transfer function for context

Dependencies

External Interfaces

interface IERC20 {
function transfer(address to, uint256 amount) external returns (bool);
function transferFrom(address from, address to, uint256 amount) external returns (bool);
function balanceOf(address account) external view returns (uint256);
}

interface IWETH {
function withdraw(uint256 amount) external;
function deposit() external payable;
}

Assembly Usage

Limited assembly usage for:

  • Return data length checks
  • Low-level call result validation
  • Gas-efficient balance comparisons

Testing Considerations

Token Variations

Test with tokens that:

  • Return different values (true, false, no return)
  • Have transfer fees
  • Use different decimal places
  • Implement non-standard behaviors

Edge Cases

  • Zero amount transfers
  • Transfers to zero address
  • Insufficient balance scenarios
  • Gas limit edge cases

Integration Testing

  • Test with actual token contracts
  • Verify behavior with different wallets
  • Test wrapper token interactions
  • Validate error reporting