-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathbot-example.js
178 lines (149 loc) · 5.54 KB
/
bot-example.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
// This is a basic Example of a Seeker Bot
// For Educational Purpose: Only a Specific contract is targeted, remember Ethereum is
// a dark forest and alot of these predators wander there with alot more ability
// than this little fellow
// 1. Setup ethers, required variables, contracts and start function
const { Wallet, ethers } = require("ethers");
const {
FlashbotsBundleProvider,
FlashbotsBundleResolution,
} = require("@flashbots/ethers-provider-bundle");
// 1. Setup Providers and Wallets
// Setup user modifiable variables
const flashbotsUrl = "https://relay-goerli.flashbots.net";
const httpProviderUrl =
"http-endpoint";
const wsProviderUrl =
"wss-endpoint";
// Copy Pvt key from Metamask and paste here
const privateKey =
"";
//* Setup Contract to Watch
// ? Normally the bot will scan every Transaction & Contract but due to limited resources we know our target
const targetContractAddress = "0x94a4BFb8D582279Fd79feF4686b8062a6a1b5cee";
// Chain Goerli
const chainId = 5;
// Initialize Providers
const provider = new ethers.providers.JsonRpcProvider(httpProviderUrl);
const wsProvider = new ethers.providers.WebSocketProvider(wsProviderUrl);
// Setup Signer Wallet for Bot
const signingWallet = new ethers.Wallet(privateKey, provider);
// 2. Process the Transaction to see if we should frontrun it
const processTransaction = async (txHash, flashbotsProvider) => {
let tx = null
// * 3. Check if someone called our targeted Smart Contract
try {
tx = await provider.getTransaction(txHash);
// console.log(transaction)
if (tx.to.toLowerCase() == targetContractAddress.toLowerCase()) {
console.log("Someone intetracted with our target contract");
console.log(tx);
}
else {
return false
}
} catch (err) {
return false;
}
// 4. Get fee costs for simplicity we'll add the user's gas fee
// 6. Get fee costs for simplicity we'll add the user's gas fee
const bribeToMiners = ethers.utils.parseUnits("150", "gwei");
const maxGasFee = transaction.maxFeePerGas
? transaction.maxFeePerGas.add(bribeToMiners)
: bribeToMiners;
const priorityFee = transaction.maxPriorityFeePerGas
? transaction.maxPriorityFeePerGas.add(bribeToMiners)
: bribeToMiners;
const totalGasFee = maxGasFee.add(priorityFee);
console.log("Copying Sender's Transaction")
// Construct the transaction parameters for copying
const copiedTransaction = {
to: tx.to,
value: tx.value,
data: tx.data,
gasPrice: totalGasFee,
gasLimit: 300000, // Set the gas price including bribe
nonce: await provider.getTransactionCount(signingWallet.address, "latest"), // Get the next nonce
chainId: tx.chainId,
};
// * Build your transaction
let firstTransaction = {
signer: signingWallet,
transaction: copiedTransaction
};
firstTransaction.transaction = {
...firstTransaction.transaction,
chainId,
};
console.log("Creating Tx Array")
const transactionsArray = [firstTransaction];
console.log("signing Transaction")
const signedTransactions = await flashbotsProvider.signBundle(
transactionsArray
);
console.log("Getting Block Number")
const blockNumber = await provider.getBlockNumber();
// Simulate and send transactions
console.log("Simulating...");
const simulation = await flashbotsProvider.simulate(
signedTransactions,
blockNumber + 1
);
if (simulation.firstRevert) {
return console.log("Simulation error", simulation.firstRevert);
} else {
console.log("Simulation success", simulation);
}
// Send transactions with flashbots
let bundleSubmission;
flashbotsProvider
.sendRawBundle(signedTransactions, blockNumber + 1)
.then((_bundleSubmission) => {
bundleSubmission = _bundleSubmission;
console.log("Bundle submitted", bundleSubmission.bundleHash);
return bundleSubmission.wait();
})
.then(async (waitResponse) => {
console.log("Wait response", FlashbotsBundleResolution[waitResponse]);
if (waitResponse == FlashbotsBundleResolution.BundleIncluded) {
console.log("-------------------------------------------");
console.log("-------------------------------------------");
console.log("----------- Bundle Included ---------------");
console.log("-------------------------------------------");
console.log("-------------------------------------------");
} else if (
waitResponse == FlashbotsBundleResolution.AccountNonceTooHigh
) {
console.log("The transaction has been confirmed already");
} else {
console.log("Bundle hash", bundleSubmission.bundleHash);
try {
console.log({
bundleStats: await flashbotsProvider.getBundleStats(
bundleSubmission.bundleHash,
blockNumber + 1
),
userStats: await flashbotsProvider.getUserStats(),
});
} catch (e) {
return false;
}
}
});
};
// 3. Start Listening for pending transactions
const start = async () => {
console.log("Listening on transaction for the chain id", chainId);
console.log("Creating FLashboat Provider")
const flashbotsProvider = await FlashbotsBundleProvider.create(
provider,
signingWallet,
flashbotsUrl
);
// Listen to all transactions in the mempool
// ? With a status = Pending
wsProvider.on("pending", (tx) => {
processTransaction(tx, flashbotsProvider);
});
};
start();