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 interfaceOwnable
- OpenZeppelin access control for owner functions
Dependencies
SafeERC20
- Safe token transfer operationsErrors
- 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 weifeeCollector_
: 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 addressesvalues
: 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 addressesvalues
: 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 addressesvalues
: 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 addressesvalues
: 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 distributionfeeType
: AlwaysITypes.FeeType.Gas
totalAmount
: Total ETH distributed to recipientstotalFee
: 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 distributiontoken
: Token contract addressfeeType
: AlwaysITypes.FeeType.Gas
totalAmount
: Total tokens distributed to recipientstotalFee
: 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
- DisperseFactory Documentation - Factory contract
- DisperseTokenFee Documentation - Token-based fee contract
- User Guide - Complete usage guide