Package Exports
- flowbatcher
- flowbatcher/index.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (flowbatcher) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
flowBatcher SDK
Overview
This SDK simplifies the process of transferring ERC-20 tokens and native Ethereum (ETH) to multiple recipients in a single transaction. By bundling transactions, it helps save on gas fees and improves transaction efficiency.
Getting Started
👉 click: npmjs/flowbatcher
To use the Ethereum Batch Transfer SDK, follow these steps:
Installation
npm i flowbatcher Set up Environment Variables:
Create a .env file in the root of the project with your Ethereum node URL and wallet private key:
ETH_NODE_URL=https://your-ethereum-node-url
WALLET_PRIVATE_KEY=your-private-keyProblem Statement
Transferring tokens or native Ethereum (ETH) to multiple addresses is often inefficient and costly, especially when multiple transactions incur separate gas fees. This SDK optimizes the process by allowing batch transfers of tokens and ETH in a single operation, making it more cost-effective and convenient.

System Flow
- User Inputs: The user provides recipient addresses and amounts of ERC-20 tokens or ETH.
- Gas Estimation: The SDK estimates the gas fees required for the batch transfer and notifies the user of the estimated cost in both ETH and USD.
- User Confirmation: The user is prompted for confirmation to proceed with the batch transfer.
- Token Approval: For ERC-20 tokens, the SDK calls the
approvemethod to allow the contract to transfer tokens on behalf of the user. - Batch Transfer Execution: The SDK sends the batch transfer of ERC-20 tokens or ETH to all recipients in one transaction.
Features
- Batch Transfer of ERC-20 Tokens: Send ERC-20 tokens to multiple recipients with one transaction.
- Batch Transfer of Native Ethereum (ETH): Transfer ETH to multiple addresses with a single transaction.
- Gas Estimation: Calculate the gas required for the batch transfer.
- User Interaction: Confirm the transfer before executing to ensure control over large transactions.
- Cross-platform Support: Works with both ERC-20 tokens and native Ethereum (ETH).
Security Enhancements
Reentrancy Guard
- Implemented
ReentrancyGuardfrom OpenZeppelin to prevent reentrancy attacks, especially for native Ether transfers. - The
nonReentrantmodifier ensures the batch transfer function cannot be called recursively, protecting against vulnerabilities.
ETH Transfer Validation
- The contract verifies that the total Ether sent (
msg.value) matches the expected sum of amounts. - If the user sends more or less ETH than required, the transaction is reverted to prevent errors or fund loss.
Efficiency Enhancements
Optimized Token Transfer
- Instead of using
transferFrom(which requires prior approval), the contract usestransferwhen the contract itself is the sender, reducing gas costs. IERC20(token).transferFrom(msg.sender, recipients[i], amounts[i]);was changed totoken.transferFrom(msg.sender, recipients[i], amounts[i]);.
Helper Function (sumAmounts)
- A helper function,
sumAmounts, efficiently calculates the total ETH amount in the batch transfer. - Avoids redundant computations in the main function, reducing gas consumption.
Gas Optimization
- By precomputing the sum of amounts in the
sumAmountshelper function, unnecessary operations in the main loop are avoided, enhancing efficiency.
Functionality
batchTransferERC20(recipients, amounts)
Transfers ERC-20 tokens to multiple recipients in a single transaction.
Parameters:
recipients: Array of recipient addresses.amounts: Array of amounts to send to each recipient.
Response:
- Success: Returns the transaction hash and logs completion.
- Error: Throws an error if invalid recipients or amounts are provided.
Example:
const recipients = ["0xRecipient1", "0xRecipient2"]
const amounts = [10, 5]
await sdk.batchTransferERC20(recipients, amounts)Response Sample
{
date: '4/4/2025, 2:53:07 AM',
message: '🚨 GAS FEE ESTIMATE FOR Eth BATCH TRANSFER: \n' +
' - Estimated Gas: 71857 \n' +
' - Gas Price (gwei): 0.01444276\n' +
' - Estimated Cost (ETH): 0.00000103781340532\n' +
' - Estimated Cost (USD): 0.001869465177673182',
data: {}
}
Proceed with Eth Batch Transfer? (yes/no):batchTransferNative(recipients, amounts)
Transfers native ETH to multiple recipients in one batch transaction.
Parameters:
recipients: Array of recipient addresses.amounts: Array of amounts of ETH to send to each recipient.
Response:
- Success: Returns the transaction hash and logs completion.
- Error: Throws an error if the recipient list or amounts are invalid.
Example:
const recipients = ["0xRecipient1", "0xRecipient2"]
const amounts = [0.1, 0.2]
await sdk.batchTransferNative(recipients, amounts)estimateGasFees(recipients, amounts, tokenAddress, isNative)
Estimates the gas fees for the batch transfer of ERC-20 tokens or native ETH.
Parameters:
recipients: Array of recipient addresses.amounts: Array of amounts to transfer.tokenAddress: The ERC-20 token address (useethers.ZeroAddressfor ETH).isNative: Boolean to specify if the transfer is native ETH.
Response:
- Success: Returns the estimated gas, gas price, and cost in both ETH and USD.
- Error: Throws an error if gas estimation fails.
Response Sample
{
date: '4/4/2025, 2:53:07 AM',
message: '🚨 GAS FEE ESTIMATE FOR ERC-20 BATCH TRANSFER: \n' +
' - Estimated Gas: 71857 \n' +
' - Gas Price (gwei): 0.01444276\n' +
' - Estimated Cost (ETH): 0.00000103781340532\n' +
' - Estimated Cost (USD): 0.001869465177673182',
data: {}
}
Proceed with ERC-20 Batch Transfer? (yes/no):Example Usage
require("dotenv").config({ path: "./.env" })
const { createProviderAndSigner } = require("./src/lib/ethers.lib.src")
const SDK = require("./src/sdk")
const config = require("./src/config")
const validatorsUtil = require("./src/utils/validators.utils")
const { provider, signer } = createProviderAndSigner(
process.env.ETH_NODE_URL,
process.env.WALLET_PRIVATE_KEY,
)
const sdk = new SDK(provider, signer, config)
;(async () => {
try {
const recipients = [
"0x93297d48A40446dc84a388BB94F3A1247CB74870",
"0x50da5C365a08169A9101C1969492540dA937071F",
]
const amounts = [1, 2]
await sdk.batchTransferERC20(recipients, amounts)
} catch (error) {
throw error
}
})()Function Responses
batchTransferERC20(recipients, amounts)
Success:
{
"txHash": "0xFakeTxHash",
"message": "✅ ERC-20 Batch Transfer completed!"
}Error:
{
"error": "Invalid recipients or amounts"
}Coding Practices
- Modular Code Structure: The SDK follows a modular architecture for easy debugging and scalability.
- Code Linting: Uses
eslintwith strict rules (--max-warnings=0) to enforce clean code. - Prettier Formatting: Ensures consistent code styling using
prettier . --write. - Error Handling: Implements proper error handling with
try-catchblocks to prevent unexpected failures. - Unit Testing: 100 % test coverage using Mocha and Chai for each modules like sdk , library, utils
Coding Standards & Dependencies
- Coding Standards:
- Uses modern JavaScript (ES6+).
- Consistent naming conventions (
camelCasefor variables). - Modular functions for improved maintainability.
Key Dependencies: -
ethers: Used for blockchain interactions. -axios: HTTP client for API calls. -eslint,prettier: Code quality tools. -mocha,chai,sinon: Testing libraries. -dotenv: Manages environment variables.
Smart Contract Used
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.10;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
contract BatchTransfer is ReentrancyGuard {
event ERC20Transfer(address indexed token, address indexed from, address indexed to, uint256 amount);
event NativeTransfer(address indexed from, address indexed to, uint256 amount);
error ArraysLengthMismatch(uint256 recipientsLength, uint256 amountsLength);
/**
* @notice Batch transfer of ERC-20 tokens or native Ether to multiple recipients.
* @param recipients List of recipient addresses.
* @param amounts List of amounts to be transferred.
* @param tokenAddress Address of the ERC-20 token. Use address(0) for native Ether transfers.
*/
function batchTransfer(
address[] calldata recipients,
uint256[] calldata amounts,
address tokenAddress
) external payable nonReentrant {
if (recipients.length != amounts.length) {
revert ArraysLengthMismatch(recipients.length, amounts.length);
}
if (tokenAddress == address(0)) {
uint256 totalAmount = msg.value;
uint256 totalRecipients = recipients.length;
if (totalAmount != sumAmounts(amounts)) {
revert ArraysLengthMismatch(recipients.length, amounts.length);
}
for (uint256 i = 0; i < totalRecipients; i++) {
payable(recipients[i]).transfer(amounts[i]);
emit NativeTransfer(msg.sender, recipients[i], amounts[i]);
}
} else {
IERC20 token = IERC20(tokenAddress);
for (uint256 i = 0; i < recipients.length; i++) {
token.transferFrom(msg.sender, recipients[i], amounts[i]);
emit ERC20Transfer(tokenAddress, msg.sender, recipients[i], amounts[i]);
}
}
}
function sumAmounts(uint256[] calldata amounts) private pure returns (uint256 total) {
for (uint256 i = 0; i < amounts.length; i++) {
total += amounts[i];
}
}
}