flowbatcher
Version:
Save gas by batching multiple ETH and ERC-20 transactions into a single operation, optimizing efficiency and reducing costs.
87 lines (80 loc) • 3.46 kB
JavaScript
const { ethers } = require("ethers")
const { getEthPriceInUsd } = require("./lib/price.lib")
const generalUseUtil = require("./utils/general.use.utils")
const validatorsUtil = require("./utils/validators.utils")
const errorUtil = require("./utils/error.utils")
const globalKeysEnum = require("./enums/global.keys.enum")
/**
* Estimates the gas fees for executing a batch transfer of ERC-20 tokens or native Ethereum (ETH).
* This function calculates the estimated gas based on the number of recipients, the amounts to be transferred, and whether the transfer is for native ETH or ERC-20 tokens.
*
* @async
* @param {string[]} recipients - An array of recipient addresses for the batch transfer.
* @param {number[]} amounts - An array of amounts to transfer to each recipient.
* @param {string} tokenAddress - The ERC-20 token address. Use `ethers.ZeroAddress` for native ETH transfers.
* @param {boolean} [isNative=false] - A flag indicating whether the transfer is native Ethereum (ETH) (default is false for ERC-20 tokens).
*
* @throws {Error} - Throws an error if the recipients or amounts are empty, or if there is an issue estimating gas fees.
*
* @returns {Promise<Object>} - A promise that resolves with an object containing:
* - `estimatedGas`: The estimated gas for the batch transfer (in units).
* - `gasPrice`: The current gas price in **gwei**.
* - `estimatedCostInEth`: The estimated cost in **ETH**.
* - `estimatedCostInUsd`: The estimated cost in **USD** (using the current ETH to USD exchange rate).
*/
async function estimateGasFees(
recipients,
amounts,
tokenAddress,
isNative = false,
) {
try {
if (validatorsUtil.isEmpty(recipients) || validatorsUtil.isEmpty(amounts)) {
errorUtil.throwError(
`Invalid recipients or amounts: ${recipients}, ${amounts}`,
)
}
const tokenContract = generalUseUtil.getGlobalKey(
globalKeysEnum.ERC20_CONTRACT,
)
const decimals = isNative ? 18 : await tokenContract.decimals()
const parsedAmounts = amounts.map((a) =>
ethers.parseUnits(a.toString(), decimals),
)
const totalAmount = parsedAmounts.reduce(
(a, b) => a + b,
ethers.parseUnits("0", decimals),
)
const batchTransferContract = generalUseUtil.getGlobalKey(
globalKeysEnum.BATCH_TRANSFER_CONTRACT,
)
const provider = generalUseUtil.getGlobalKey(globalKeysEnum.PROVIDER)
const signer = generalUseUtil.getGlobalKey(globalKeysEnum.SIGNER)
const txData =
await batchTransferContract.batchTransfer.populateTransaction(
recipients,
parsedAmounts,
tokenAddress,
isNative ? { value: totalAmount } : {},
)
const estimatedGas = await provider.estimateGas({
...txData,
from: signer.address,
value: isNative ? totalAmount : 0,
})
const gasPrice = await provider.getFeeData()
const estimatedCost = estimatedGas * gasPrice.gasPrice
const ethToUsd = await getEthPriceInUsd()
const estimatedgasInEth = parseFloat(ethers.formatEther(estimatedCost))
const estimatedCostInUsd = estimatedgasInEth * ethToUsd
return {
estimatedGas: estimatedGas.toString(),
gasPrice: ethers.formatUnits(gasPrice.gasPrice, "gwei"),
estimatedCostInEth: estimatedgasInEth,
estimatedCostInUsd: estimatedCostInUsd,
}
} catch {
throw new Error("Error estimating gas fees")
}
}
module.exports = { estimateGasFees: estimateGasFees }