Skip to main content

DisperseGasFee Documentation

Overview

The DisperseGasFee contract enables efficient batch distribution of ETH and ERC20 tokens to multiple recipients with a fixed gas-based fee structure. This contract charges a predetermined fee per recipient in native currency (ETH), making it ideal for scenarios where fee predictability is important.

✨ Key Features:

  • Fixed Fee Structure: Predictable fee per recipient in ETH
  • Dual Distribution: Support for both ETH and ERC20 token distribution
  • Fee Options: Pay fees on top or deduct from recipient amounts
  • Automatic Refunds: Excess ETH automatically returned to sender
  • Access Control: Owner and fee collector role separation

Contract Details

License: BUSL-1.1 Solidity Version: 0.8.28 Fee Type: ITypes.FeeType.Gas

Inheritance

  • IDisperseGasFee - Standard gas fee disperse interface
  • Ownable - OpenZeppelin access control for owner functions

Dependencies

  • SafeERC20 - Safe token transfer operations
  • Errors - Centralized error handling library

Architecture

Constants

ITypes.FeeType public constant FEE_TYPE = ITypes.FeeType.Gas;
uint256 public immutable FEE;
uint256 public immutable DEPLOYMENT_BLOCK_NUMBER;

State Variables

address public feeCollector;

Constructor

constructor(
uint256 gasFee_,
address feeCollector_,
address creator_
)

Parameters:

  • gasFee_: Fee per recipient in wei
  • feeCollector_: Address that will collect fees (cannot be zero)
  • creator_: Contract owner address

Requirements:

  • feeCollector_ cannot be zero address

Fee Structure

The contract uses a fixed fee per recipient model:

  • Fee Amount: Set at deployment time (immutable)
  • Fee Currency: Native currency (ETH)
  • Fee Collection: Immediate collection during distribution

Core Functions

ETH Distribution

disperseEther(address[], uint256[])

Distributes ETH to multiple recipients with fees paid on top.

function disperseEther(
address[] calldata recipients,
uint256[] calldata values
) external payable

Parameters:

  • recipients: Array of recipient addresses
  • values: Array of ETH amounts to send (in wei)

Payment Required: sum(values) + (recipients.length * FEE)

Requirements:

  • Arrays cannot be empty
  • Arrays must have equal length
  • Sufficient ETH must be provided
  • No zero addresses in recipients

Events Emitted: EtherDispersed

Refunds: Excess ETH automatically returned to sender

disperseEtherDeductedFee(address[], uint256[])

Distributes ETH with fees deducted from recipient amounts.

function disperseEtherDeductedFee(
address[] calldata recipients,
uint256[] calldata values
) external payable

Parameters:

  • recipients: Array of recipient addresses
  • values: Array of gross ETH amounts (before fee deduction)

Payment Required: sum(values)

Requirements:

  • Arrays cannot be empty
  • Arrays must have equal length
  • Each value must be greater than FEE
  • No zero addresses in recipients
  • No zero values allowed

Recipients Receive: values[i] - FEE

Events Emitted: EtherDispersed

⚠️ Important:

  • Each recipient's value must be greater than the fee amount
  • Zero addresses are not allowed as recipients
  • Zero values are not allowed

Token Distribution

disperseToken(IERC20, address[], uint256[])

Distributes ERC20 tokens with gas fees paid separately.

function disperseToken(
IERC20 token,
address[] calldata recipients,
uint256[] calldata values
) external payable

Parameters:

  • token: ERC20 token contract address (cannot be zero)
  • recipients: Array of recipient addresses
  • values: Array of token amounts to distribute

Payment Required: recipients.length * FEE (in ETH)

Token Approval Required: sum(values) tokens

Requirements:

  • Token address cannot be zero
  • Arrays cannot be empty
  • Arrays must have equal length
  • Exact fee amount must be provided in ETH
  • Sufficient token approval required

Events Emitted: TokenDispersed

disperseTokenSimple(IERC20, address[], uint256[])

Distributes ERC20 tokens with direct transfers from sender.

function disperseTokenSimple(
IERC20 token,
address[] calldata recipients,
uint256[] calldata values
) external payable

Parameters:

  • token: ERC20 token contract address (cannot be zero)
  • recipients: Array of recipient addresses
  • values: Array of token amounts to distribute

Payment Required: recipients.length * FEE (in ETH)

Token Approval Required: Individual approvals or unlimited approval

Use Case: When avoiding bulk transfer and transferring directly from sender

Events Emitted: TokenDispersed

Fee Management

Fee Collection

withdrawGasFee(address, uint256)

Withdraws collected gas fees.

function withdrawGasFee(address recipient, uint256 amount)
external onlyFeeCollector

Parameters:

  • recipient: Address to receive the withdrawn fees (cannot be zero)
  • amount: Amount to withdraw in wei (0 = withdraw all)

Access: Fee collector only

Requirements:

  • Recipient cannot be zero address
  • Contract must have sufficient balance
  • Amount cannot exceed available balance

Events Emitted: GasFeeWithdrawn

transferFeeCollectorRole(address)

Transfers fee collector role to new address.

function transferFeeCollectorRole(address newFeeCollector)
external onlyFeeCollector

Parameters:

  • newFeeCollector: New fee collector address (cannot be zero)

Access: Fee collector only

Requirements:

  • New fee collector cannot be zero address

Events Emitted: FeeCollectorUpdated

Recovery Functions

withdrawERC20(address)

Withdraws stuck ERC20 tokens from the contract.

function withdrawERC20(address tokenAddr) external onlyOwner

Parameters:

  • tokenAddr: Token contract address to withdraw (cannot be zero)

Access: Owner only

Requirements:

  • Token address cannot be zero
  • Contract must have token balance

Use Case: Recovery of tokens sent to contract by mistake

Events Emitted: ERC20Withdrawn

Events

Distribution Events

EtherDispersed

event EtherDispersed(
address indexed sender,
ITypes.FeeType feeType,
uint256 totalAmount,
uint256 totalFee
);

Emitted when ETH is distributed to recipients.

Parameters:

  • sender: Address that initiated the distribution
  • feeType: Always ITypes.FeeType.Gas
  • totalAmount: Total ETH distributed to recipients
  • totalFee: Total fees collected

TokenDispersed

event TokenDispersed(
address indexed sender,
address indexed token,
ITypes.FeeType feeType,
uint256 totalAmount,
uint256 totalFee
);

Emitted when tokens are distributed to recipients.

Parameters:

  • sender: Address that initiated the distribution
  • token: Token contract address
  • feeType: Always ITypes.FeeType.Gas
  • totalAmount: Total tokens distributed to recipients
  • totalFee: Total fees collected in ETH (converted for display)

Management Events

GasFeeWithdrawn

event GasFeeWithdrawn(address indexed recipient, uint256 withdrawAmount);

ERC20Withdrawn

event ERC20Withdrawn(address indexed token, uint256 amount);

FeeCollectorUpdated

event FeeCollectorUpdated(
address indexed oldFeeCollector,
address indexed newFeeCollector
);

Error Handling

Common Errors

TransferFailed()

Description: Transfer operation failed Common Causes:

  • Recipient contract doesn't accept ETH
  • Insufficient gas for transfer
  • Target contract reverted

InvalidAddress()

Description: Zero address provided Common Causes:

  • Zero address in recipient list
  • Zero address for fee collector
  • Zero address for token contract

InsufficientAmount()

Description: Not enough funds provided Common Causes:

  • ETH amount less than distribution + fees
  • Token approval insufficient

InsufficientFee()

Description: Fee amount too low Common Causes:

  • Gas fee payment doesn't match required amount
  • Partial fee payment

InvalidArrayLength()

Description: Empty array provided Common Causes:

  • Empty recipients array
  • Empty values array

ArrayLengthMismatch()

Description: Array lengths don't match Common Causes:

  • Recipients and values arrays different sizes

ZeroBalance()

Description: No balance available Common Causes:

  • No fees to withdraw
  • No tokens to recover

OnlyFeeCollector()

Description: Only fee collector can execute Common Causes:

  • Non-fee collector trying to withdraw fees
  • Non-fee collector trying to transfer role

Security Considerations

🔒 Security Features:

  • Reentrancy Protection: Uses safe external calls
  • Input Validation: Comprehensive checks on all inputs
  • Access Control: Owner and fee collector roles
  • Immutable Fees: Fee amount cannot be changed after deployment
  • Automatic Refunds: Excess ETH returned to sender

Troubleshooting

Transaction Failures

"Transaction ran out of gas"

  • Cause: Batch size too large
  • Solution: Reduce batch size or increase gas limit

"Insufficient funds"

  • Cause: Not enough ETH for distribution + fees
  • Solution: Calculate total requirement: sum(values) + (count * fee)

"Transfer failed"

  • Cause: Recipient contract doesn't accept ETH
  • Solution: Check recipient contracts have payable receive/fallback functions

Token Distribution Issues

"ERC20: transfer amount exceeds allowance"

  • Cause: Insufficient token approval
  • Solution: Approve sufficient tokens before distribution

"ERC20: transfer from the zero address"

  • Cause: Token address validation failed
  • Solution: Use valid, non-zero token contract address

Next Steps