Skip to content

Instantly share code, notes, and snippets.

@claytantor
Last active April 2, 2025 20:28
Show Gist options
  • Select an option

  • Save claytantor/0c53047054478d93ba8b339f8cfb4dde to your computer and use it in GitHub Desktop.

Select an option

Save claytantor/0c53047054478d93ba8b339f8cfb4dde to your computer and use it in GitHub Desktop.
Simulated Builder Tx on Titan
/**
RPC_ENDPOINT_ETHERS = "https://mainnet.infura.io/v3/<secret>"
BUILDER_RPC = "https://rpc.titanbuilder.xyz"
ETH_NETWORK = "mainnet"
*/
const ethers = require('ethers');
const {
FlashbotsBundleProvider,
} = require("@flashbots/ethers-provider-bundle");
const dotenv = require("dotenv");
let TX_ACTION = process.argv.length == 4 ? process.argv[3] : 'simulate';
if (process.argv.length < 3) {
console.error("Please provide the environment file path as an argument.");
process.exit(1);
} else {
dotenv.config({ path: process.argv[2] });
}
// dotenv.config({ path: './config/.env.fbbundle.mainnet' });
const {
ETH_NETWORK,
FROM_ADDRESS_PRIVATE_KEY,
TO_ADDRESS,
BUILDER_RPC,
SIMULATION_RPC,
RPC_ENDPOINT_ETHERS,
PRIORITY_FEE_GWEI
} = process.env;
async function main() {
console.log("ethers version:", ethers.version);
console.log("ETH_NETWORK:", ETH_NETWORK);
console.log("RPC_ENDPOINT_ETHERS:", RPC_ENDPOINT_ETHERS);
console.log("BUILDER_RPC:", BUILDER_RPC);
console.log("SIMULATION_RPC:", SIMULATION_RPC);
console.log("TX_ACTION:", TX_ACTION);
const provider = new ethers.JsonRpcProvider(RPC_ENDPOINT_ETHERS);
const latestBlockNumber = await provider.getBlockNumber();
console.log("Latest Block number:", latestBlockNumber);
console.log(`getting block ${latestBlockNumber}...`);
const block = await provider.getBlock(latestBlockNumber);
console.log(block);
if (block.baseFeePerGas == null) {
console.error('This chain is not EIP-1559 enabled')
return false;
}
let chainId = (await provider.getNetwork()).chainId;
console.log("chainId:", chainId);
const wallet = new ethers.Wallet(
FROM_ADDRESS_PRIVATE_KEY,
provider
);
// Flashbots provider requires passing in a standard provider and an auth signer
const builderProvider = await FlashbotsBundleProvider.create(
provider,
wallet,
BUILDER_RPC,
ETH_NETWORK
);
// Flashbots provider requires passing in a standard provider and an auth signer
const simlationProvider = await FlashbotsBundleProvider.create(
provider,
wallet,
SIMULATION_RPC,
ETH_NETWORK
);
const maxBaseFeeInFutureBlock = FlashbotsBundleProvider.getMaxBaseFeeInFutureBlock(block.baseFeePerGas, 1)
// convert the priority fee from gwei to wei
const priorityFee = ethers.parseUnits(PRIORITY_FEE_GWEI, "gwei");
const valueToSend = ethers.parseEther("0.001");
let tx = {
to: TO_ADDRESS,
value: valueToSend,
maxFeePerGas: priorityFee + maxBaseFeeInFutureBlock,
maxPriorityFeePerGas: priorityFee,
gasLimit: 21000,
type: 2,
chainId: chainId,
};
if (TX_ACTION === "simulate") {
console.log("simulating...")
const targetBlock = latestBlockNumber + 1;
const signedBundleSimlation = await simlationProvider.signBundle([
{
signer: wallet,
transaction: tx,
},
]);
const simulation = await simlationProvider.simulate(signedBundleSimlation, targetBlock)
console.log(simulation);
if ("error" in simulation) {
console.error("Simulation Error:", simulation.error);
process.exitCode = 3;
} else {
console.log("Simulation Success:", simulation);
const signedBundleBundler = await builderProvider.signBundle([
{
signer: wallet,
transaction: tx,
},
]);
// Submitting the bundle if simulation succeeds
const response = await builderProvider.sendRawBundle(
signedBundleBundler,
block.number + 1
);
if (response.error) {
console.error("Failed to send bundle:", response.error);
process.exitCode = 2;
} else {
console.log(JSON.stringify(response, null, 2));
}
}
console.log("simulation completed bundle...")
} else if (TX_ACTION === "send") {
console.log("sending...")
const targetBlock = latestBlockNumber + 1;
const signedBundle = await builderProvider.signBundle([
{
signer: wallet,
transaction: tx,
},
]);
const txResponse = await builderProvider.sendRawBundle(signedBundle, targetBlock);
console.log("txResponse:", txResponse);
if ('error' in txResponse) {
console.warn(`Send Error: ${txResponse.error.message}`)
return false;
}
console.log("sent bundle successfully...")
} else {
console.error("Invalid action. Use 'simulate' or 'send'.");
process.exit(1);
}
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment