forked from paco0x/amm-arbitrageur
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.ts
93 lines (82 loc) · 2.76 KB
/
index.ts
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
import { ethers } from 'hardhat';
import { BigNumber } from 'ethers';
import pool from '@ricokahler/pool';
import AsyncLock from 'async-lock';
import { FlashBot } from '../typechain/FlashBot';
import { Network, tryLoadPairs, getTokens } from './tokens';
import { getBnbPrice } from './basetoken-price';
import log from './log';
import config from './config';
function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
async function calcNetProfit(profitWei: BigNumber, address: string, baseTokens: Tokens): Promise<number> {
let price = 1;
if (baseTokens.wbnb.address == address) {
price = await getBnbPrice();
}
let profit = parseFloat(ethers.utils.formatEther(profitWei));
profit = profit * price;
const gasCost = price * parseFloat(ethers.utils.formatEther(config.gasPrice)) * (config.gasLimit as number);
return profit - gasCost;
}
function arbitrageFunc(flashBot: FlashBot, baseTokens: Tokens) {
const lock = new AsyncLock({ timeout: 2000, maxPending: 20 });
return async function arbitrage(pair: ArbitragePair) {
const [pair0, pair1] = pair.pairs;
let res: [BigNumber, string] & {
profit: BigNumber;
baseToken: string;
};
try {
res = await flashBot.getProfit(pair0, pair1);
log.debug(`Profit on ${pair.symbols}: ${ethers.utils.formatEther(res.profit)}`);
} catch (err) {
log.debug(err);
return;
}
if (res.profit.gt(BigNumber.from('0'))) {
const netProfit = await calcNetProfit(res.profit, res.baseToken, baseTokens);
if (netProfit < config.minimumProfit) {
return;
}
log.info(`Calling flash arbitrage, net profit: ${netProfit}`);
try {
// lock to prevent tx nonce overlap
await lock.acquire('flash-bot', async () => {
const response = await flashBot.flashArbitrage(pair0, pair1, {
gasPrice: config.gasPrice,
gasLimit: config.gasLimit,
});
const receipt = await response.wait(1);
log.info(`Tx: ${receipt.transactionHash}`);
});
} catch (err) {
if (err.message === 'Too much pending tasks' || err.message === 'async-lock timed out') {
return;
}
log.error(err);
}
}
};
}
async function main() {
const pairs = await tryLoadPairs(Network.BSC);
const flashBot = (await ethers.getContractAt('FlashBot', config.contractAddr)) as FlashBot;
const [baseTokens] = getTokens(Network.BSC);
log.info('Start arbitraging');
while (true) {
await pool({
collection: pairs,
task: arbitrageFunc(flashBot, baseTokens),
// maxConcurrency: config.concurrency,
});
await sleep(1000);
}
}
main()
.then(() => process.exit(0))
.catch((err) => {
log.error(err);
process.exit(1);
});