The following error appears
Error: cannot estimate gas; transaction may fail or may require manual gas limit (error={"reason":"processing response error","code":"SERVER_ERROR","body":"{"jsonrpc":"2.0","id":45,"error":{"code":-32000,"message":"execution reverted"}}","error":{"code":-32000},"requestBody":"{"method":"eth_estimateGas","params":[{"from":"0x4209c9ea64fb4fa437eb950b3839a43c99d96c06","to":"0x5eeaa2dcb23056f4e8654a349e57ebe5e76b5e6e","data":"0xa9059cbb0000000000000000000000006232a23425f132c4fbe49dd1bdb9e872403a1cc90000000000000000000000000000000000000000000054b40b1f852bda000000"}],"id":45,"jsonrpc":"2.0"}","requestMethod":"POST","url":"https://mainnet.infura.io/v3/7ff28c44784b4d3d97e169bc155675eb"}, method="estimateGas", transaction={"from":"0x4209C9eA64fb4fA437eb950B3839a43C99d96c06","to":"0x5EeAA2DCb23056F4E8654a349E57eBE5e76b5e6e","data":"0xa9059cbb0000000000000000000000006232a23425f132c4fbe49dd1bdb9e872403a1cc90000000000000000000000000000000000000000000054b40b1f852bda000000","accessList":null}, code=UNPREDICTABLE_GAS_LIMIT, version=providers/5.4.3)
import {
FlashbotsBundleProvider, FlashbotsBundleRawTransaction,
FlashbotsBundleResolution,
FlashbotsBundleTransaction
} from "@flashbots/ethers-provider-bundle";
import { BigNumber, providers, Wallet } from "ethers";
import { Base } from "./engine/Base";
import {TransferERC20} from "./engine/TransferERC20";
import { checkSimulation, gasPriceToGwei, printTransactions } from "./utils";
import { Approval721 } from "./engine/Approval721";
require('log-timestamp');
const BLOCKS_IN_FUTURE = 2;
const GWEI = BigNumber.from(10).pow(9);
const PRIORITY_GAS_PRICE = GWEI.mul(31)
const PRIVATE_KEY_EXECUTOR = process.env.PRIVATE_KEY_EXECUTOR
const PRIVATE_KEY_SPONSOR = process.env.PRIVATE_KEY_SPONSOR
const FLASHBOTS_RELAY_SIGNING_KEY = process.env.FLASHBOTS_RELAY_SIGNING_KEY
const RECIPIENT = process.env.RECIPIENT
if (PRIVATE_KEY_EXECUTOR === "") {
console.warn("Must provide PRIVATE_KEY_EXECUTOR environment variable, corresponding to Ethereum EOA with assets to be transferred")
process.exit(1)
}
if (PRIVATE_KEY_SPONSOR === "") {
console.warn("Must provide PRIVATE_KEY_SPONSOR environment variable, corresponding to an Ethereum EOA with ETH to pay miner")
process.exit(1)
}
if (FLASHBOTS_RELAY_SIGNING_KEY === "") {
console.warn("Must provide FLASHBOTS_RELAY_SIGNING_KEY environment variable. Please see https://github.com/flashbots/pm/blob/main/guides/flashbots-alpha.md")
process.exit(1)
}
if (RECIPIENT === "") {
console.warn("Must provide RECIPIENT environment variable, an address which will receive assets")
process.exit(1)
}
async function main() {
const walletRelay = new Wallet(FLASHBOTS_RELAY_SIGNING_KEY)
// ======= UNCOMMENT FOR GOERLI ==========
// const provider = new providers.InfuraProvider(5, process.env.INFURA_API_KEY || '');
// const flashbotsProvider = await FlashbotsBundleProvider.create(provider, walletRelay, 'https://relay-goerli.epheph.com/');
// ======= UNCOMMENT FOR GOERLI ==========
// ======= UNCOMMENT FOR MAINNET ==========
const ETHEREUM_RPC_URL = process.env.ETHEREUM_RPC_URL || "https://mainnet.infura.io/v3/7ff28c44784b4d3d97e169bc155675eb"
const provider = new providers.StaticJsonRpcProvider(ETHEREUM_RPC_URL);
const flashbotsProvider = await FlashbotsBundleProvider.create(provider, walletRelay);
// ======= UNCOMMENT FOR MAINNET ==========
const walletExecutor = new Wallet(PRIVATE_KEY_EXECUTOR);
const walletSponsor = new Wallet(PRIVATE_KEY_SPONSOR);
const block = await provider.getBlock("latest")
// ======= UNCOMMENT FOR ERC20 TRANSFER ==========
const tokenAddress = "0x5EeAA2DCb23056F4E8654a349E57eBE5e76b5e6e";
const engine: Base = new TransferERC20(provider, walletExecutor.address, RECIPIENT, tokenAddress);
// ======= UNCOMMENT FOR ERC20 TRANSFER ==========
// ======= UNCOMMENT FOR 721 Approval ==========
//const HASHMASKS_ADDRESS = "0x082903f4e94c5e10a2b116a4284940a36afaed63";
//const engine: Base = new Approval721(RECIPIENT, [HASHMASKS_ADDRESS]);
// ======= UNCOMMENT FOR 721 Approval ==========
const sponsoredTransactions = await engine.getSponsoredTransactions();
const gasEstimates = await Promise.all(sponsoredTransactions.map(tx =>
provider.estimateGas({
...tx,
from: tx.from === undefined ? walletExecutor.address : tx.from
}))
)
const gasEstimateTotal = gasEstimates.reduce((acc, cur) => acc.add(cur), BigNumber.from(0))
const gasPrice = PRIORITY_GAS_PRICE.add(block.baseFeePerGas || 0);
const bundleTransactions: Array<FlashbotsBundleTransaction | FlashbotsBundleRawTransaction> = [
{
transaction: {
to: walletExecutor.address,
gasPrice: gasPrice,
value: gasEstimateTotal.mul(gasPrice),
gasLimit: 100000,
},
signer: walletSponsor
},
...sponsoredTransactions.map((transaction, txNumber) => {
return {
transaction: {
...transaction,
gasPrice: gasPrice,
gasLimit: gasEstimates[txNumber],
},
signer: walletExecutor,
}
})
]
const signedBundle = await flashbotsProvider.signBundle(bundleTransactions)
await printTransactions(bundleTransactions, signedBundle);
const simulatedGasPrice = await checkSimulation(flashbotsProvider, signedBundle);
console.log(await engine.description())
console.log(`Executor Account: ${walletExecutor.address}`)
console.log(`Sponsor Account: ${walletSponsor.address}`)
console.log(`Simulated Gas Price: ${gasPriceToGwei(simulatedGasPrice)} gwei`)
console.log(`Gas Price: ${gasPriceToGwei(gasPrice)} gwei`)
console.log(`Gas Used: ${gasEstimateTotal.toString()}`)
provider.on('block', async (blockNumber) => {
const simulatedGasPrice = await checkSimulation(flashbotsProvider, signedBundle);
const targetBlockNumber = blockNumber + BLOCKS_IN_FUTURE;
console.log(`Current Block Number: ${blockNumber}, Target Block Number:${targetBlockNumber}, gasPrice: ${gasPriceToGwei(simulatedGasPrice)} gwei`)
const bundleResponse = await flashbotsProvider.sendBundle(bundleTransactions, targetBlockNumber);
if ('error' in bundleResponse) {
throw new Error(bundleResponse.error.message)
}
const bundleResolution = await bundleResponse.wait()
if (bundleResolution === FlashbotsBundleResolution.BundleIncluded) {
console.log(`Congrats, included in ${targetBlockNumber}`)
process.exit(0)
} else if (bundleResolution === FlashbotsBundleResolution.BlockPassedWithoutInclusion) {
console.log(`Not included in ${targetBlockNumber}`)
} else if (bundleResolution === FlashbotsBundleResolution.AccountNonceTooHigh) {
console.log("Nonce too high, bailing")
process.exit(1)
}
})
}
main()