├── .env.example ├── .gitignore ├── .husky └── commit-msg ├── ABIs ├── abi.json ├── erc20.js ├── index.js └── swapABI.json ├── Config └── constants.js ├── Functions ├── buyToken.js ├── calculateGasPrice.js ├── index.js ├── router.js └── sellToken.js ├── Lists ├── blacklist.json ├── index.js └── whitelist.json ├── README.md ├── TODO ├── bot.js ├── changelog.md ├── folderstruct.tree ├── package-lock.json └── package.json /.env.example: -------------------------------------------------------------------------------- 1 | ################################################################ 2 | # Configure your Bot settings below 3 | ################################################################ 4 | 5 | # Port that server is running on, typically localhost:3000 6 | PORT=3888 7 | 8 | # BSC Wss Node Url, using https://getblock.io/ replace with your link 9 | WSS=wss://bsc.getblock.io//mainnet/ 10 | 11 | # BSC Wss Node Url, using https://quicknode.com/ replace with your link 12 | #WSS=wss://late-necessary-mansion.bsc.discover.quiknode.pro// 13 | 14 | # Private Key from Metamask Test 15 | PRIVATE_KEY=12345678abcdefg 16 | 17 | # BNB Contract Address 18 | BNB_CONTRACT=0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c 19 | 20 | # Pancake Router Contract Address 21 | PAN_ROUTER_ADDRESS=0x10ED43C718714eb63d5aA57B78B54704E256024E 22 | 23 | # Budget for how to buy when bot executes the transaction 24 | BUDGET=0.01 25 | 26 | # Value for filtering transactions with higher value thatn this number 27 | # for example we will be only showing transaction that are higher than 30 bnb 28 | MINVALUE=2 29 | 30 | # Slippage for buying tokens using sandwhich, set to 1 for 1% 31 | SLIPPAGE=11 32 | 33 | # Gas percent increate to sandwhich buys and sells 34 | GAS_PERCENT=10 35 | 36 | ################################################ 37 | # GITHub Settings 38 | ################################################ 39 | 40 | # Github Username 41 | GITHUB_USERNAME= 42 | 43 | # Github Repo 44 | GITHUB_REPO= 45 | 46 | # Github Token 47 | GITHUB_TOKEN= -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .env 4 | bump.json 5 | legacy-files/ 6 | commit-script/ 7 | Flows/ 8 | error_logs/log.txt 9 | error_logs/commit_error.log 10 | temp.json 11 | .DS_Store 12 | design/ 13 | contracts/ 14 | # Xcode 15 | # 16 | files/images/ 17 | build/ 18 | build/intermediates/ 19 | *.pbxuser 20 | !default.pbxuser 21 | *.mode1v3 22 | !default.mode1v3 23 | *.mode2v3 24 | !default.mode2v3 25 | *.perspectivev3 26 | !default.perspectivev3 27 | xcuserdata 28 | *.xccheckout 29 | *.moved-aside 30 | DerivedData 31 | *.hmap 32 | *.ipa 33 | *.xcuserstate 34 | 35 | # Android/IntelliJ 36 | # 37 | build/ 38 | .idea 39 | .gradle 40 | *.iml 41 | 42 | # node.js 43 | # 44 | node_modules/ 45 | npm-debug.log 46 | yarn-error.log 47 | yarn.lock 48 | # BUCK 49 | buck-out/ 50 | \.buckd/ 51 | *.keystore 52 | !debug.keystore 53 | 54 | # fastlane 55 | # 56 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 57 | # screenshots whenever they are needed. 58 | # For more information about the recommended setup visit: 59 | # https://docs.fastlane.tools/best-practices/source-control/ 60 | 61 | */fastlane/report.xml 62 | */fastlane/Preview.html 63 | */fastlane/screenshots 64 | 65 | # Bundle artifact 66 | *.jsbundle 67 | 68 | # CocoaPods 69 | /ios/Pods/ 70 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npx --no-install commitlint --edit $1 5 | -------------------------------------------------------------------------------- /ABIs/abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "address", 6 | "name": "_factory", 7 | "type": "address" 8 | }, 9 | { 10 | "internalType": "address", 11 | "name": "_WETH", 12 | "type": "address" 13 | } 14 | ], 15 | "stateMutability": "nonpayable", 16 | "type": "constructor" 17 | }, 18 | { 19 | "inputs": [], 20 | "name": "WETH", 21 | "outputs": [ 22 | { 23 | "internalType": "address", 24 | "name": "", 25 | "type": "address" 26 | } 27 | ], 28 | "stateMutability": "view", 29 | "type": "function" 30 | }, 31 | { 32 | "inputs": [ 33 | { 34 | "internalType": "address", 35 | "name": "tokenA", 36 | "type": "address" 37 | }, 38 | { 39 | "internalType": "address", 40 | "name": "tokenB", 41 | "type": "address" 42 | }, 43 | { 44 | "internalType": "uint256", 45 | "name": "amountADesired", 46 | "type": "uint256" 47 | }, 48 | { 49 | "internalType": "uint256", 50 | "name": "amountBDesired", 51 | "type": "uint256" 52 | }, 53 | { 54 | "internalType": "uint256", 55 | "name": "amountAMin", 56 | "type": "uint256" 57 | }, 58 | { 59 | "internalType": "uint256", 60 | "name": "amountBMin", 61 | "type": "uint256" 62 | }, 63 | { 64 | "internalType": "address", 65 | "name": "to", 66 | "type": "address" 67 | }, 68 | { 69 | "internalType": "uint256", 70 | "name": "deadline", 71 | "type": "uint256" 72 | } 73 | ], 74 | "name": "addLiquidity", 75 | "outputs": [ 76 | { 77 | "internalType": "uint256", 78 | "name": "amountA", 79 | "type": "uint256" 80 | }, 81 | { 82 | "internalType": "uint256", 83 | "name": "amountB", 84 | "type": "uint256" 85 | }, 86 | { 87 | "internalType": "uint256", 88 | "name": "liquidity", 89 | "type": "uint256" 90 | } 91 | ], 92 | "stateMutability": "nonpayable", 93 | "type": "function" 94 | }, 95 | { 96 | "inputs": [ 97 | { 98 | "internalType": "address", 99 | "name": "token", 100 | "type": "address" 101 | }, 102 | { 103 | "internalType": "uint256", 104 | "name": "amountTokenDesired", 105 | "type": "uint256" 106 | }, 107 | { 108 | "internalType": "uint256", 109 | "name": "amountTokenMin", 110 | "type": "uint256" 111 | }, 112 | { 113 | "internalType": "uint256", 114 | "name": "amountETHMin", 115 | "type": "uint256" 116 | }, 117 | { 118 | "internalType": "address", 119 | "name": "to", 120 | "type": "address" 121 | }, 122 | { 123 | "internalType": "uint256", 124 | "name": "deadline", 125 | "type": "uint256" 126 | } 127 | ], 128 | "name": "addLiquidityETH", 129 | "outputs": [ 130 | { 131 | "internalType": "uint256", 132 | "name": "amountToken", 133 | "type": "uint256" 134 | }, 135 | { 136 | "internalType": "uint256", 137 | "name": "amountETH", 138 | "type": "uint256" 139 | }, 140 | { 141 | "internalType": "uint256", 142 | "name": "liquidity", 143 | "type": "uint256" 144 | } 145 | ], 146 | "stateMutability": "payable", 147 | "type": "function" 148 | }, 149 | { 150 | "inputs": [], 151 | "name": "factory", 152 | "outputs": [ 153 | { 154 | "internalType": "address", 155 | "name": "", 156 | "type": "address" 157 | } 158 | ], 159 | "stateMutability": "view", 160 | "type": "function" 161 | }, 162 | { 163 | "inputs": [ 164 | { 165 | "internalType": "uint256", 166 | "name": "amountOut", 167 | "type": "uint256" 168 | }, 169 | { 170 | "internalType": "uint256", 171 | "name": "reserveIn", 172 | "type": "uint256" 173 | }, 174 | { 175 | "internalType": "uint256", 176 | "name": "reserveOut", 177 | "type": "uint256" 178 | } 179 | ], 180 | "name": "getAmountIn", 181 | "outputs": [ 182 | { 183 | "internalType": "uint256", 184 | "name": "amountIn", 185 | "type": "uint256" 186 | } 187 | ], 188 | "stateMutability": "pure", 189 | "type": "function" 190 | }, 191 | { 192 | "inputs": [ 193 | { 194 | "internalType": "uint256", 195 | "name": "amountIn", 196 | "type": "uint256" 197 | }, 198 | { 199 | "internalType": "uint256", 200 | "name": "reserveIn", 201 | "type": "uint256" 202 | }, 203 | { 204 | "internalType": "uint256", 205 | "name": "reserveOut", 206 | "type": "uint256" 207 | } 208 | ], 209 | "name": "getAmountOut", 210 | "outputs": [ 211 | { 212 | "internalType": "uint256", 213 | "name": "amountOut", 214 | "type": "uint256" 215 | } 216 | ], 217 | "stateMutability": "pure", 218 | "type": "function" 219 | }, 220 | { 221 | "inputs": [ 222 | { 223 | "internalType": "uint256", 224 | "name": "amountOut", 225 | "type": "uint256" 226 | }, 227 | { 228 | "internalType": "address[]", 229 | "name": "path", 230 | "type": "address[]" 231 | } 232 | ], 233 | "name": "getAmountsIn", 234 | "outputs": [ 235 | { 236 | "internalType": "uint256[]", 237 | "name": "amounts", 238 | "type": "uint256[]" 239 | } 240 | ], 241 | "stateMutability": "view", 242 | "type": "function" 243 | }, 244 | { 245 | "inputs": [ 246 | { 247 | "internalType": "uint256", 248 | "name": "amountIn", 249 | "type": "uint256" 250 | }, 251 | { 252 | "internalType": "address[]", 253 | "name": "path", 254 | "type": "address[]" 255 | } 256 | ], 257 | "name": "getAmountsOut", 258 | "outputs": [ 259 | { 260 | "internalType": "uint256[]", 261 | "name": "amounts", 262 | "type": "uint256[]" 263 | } 264 | ], 265 | "stateMutability": "view", 266 | "type": "function" 267 | }, 268 | { 269 | "inputs": [ 270 | { 271 | "internalType": "uint256", 272 | "name": "amountA", 273 | "type": "uint256" 274 | }, 275 | { 276 | "internalType": "uint256", 277 | "name": "reserveA", 278 | "type": "uint256" 279 | }, 280 | { 281 | "internalType": "uint256", 282 | "name": "reserveB", 283 | "type": "uint256" 284 | } 285 | ], 286 | "name": "quote", 287 | "outputs": [ 288 | { 289 | "internalType": "uint256", 290 | "name": "amountB", 291 | "type": "uint256" 292 | } 293 | ], 294 | "stateMutability": "pure", 295 | "type": "function" 296 | }, 297 | { 298 | "inputs": [ 299 | { 300 | "internalType": "address", 301 | "name": "tokenA", 302 | "type": "address" 303 | }, 304 | { 305 | "internalType": "address", 306 | "name": "tokenB", 307 | "type": "address" 308 | }, 309 | { 310 | "internalType": "uint256", 311 | "name": "liquidity", 312 | "type": "uint256" 313 | }, 314 | { 315 | "internalType": "uint256", 316 | "name": "amountAMin", 317 | "type": "uint256" 318 | }, 319 | { 320 | "internalType": "uint256", 321 | "name": "amountBMin", 322 | "type": "uint256" 323 | }, 324 | { 325 | "internalType": "address", 326 | "name": "to", 327 | "type": "address" 328 | }, 329 | { 330 | "internalType": "uint256", 331 | "name": "deadline", 332 | "type": "uint256" 333 | } 334 | ], 335 | "name": "removeLiquidity", 336 | "outputs": [ 337 | { 338 | "internalType": "uint256", 339 | "name": "amountA", 340 | "type": "uint256" 341 | }, 342 | { 343 | "internalType": "uint256", 344 | "name": "amountB", 345 | "type": "uint256" 346 | } 347 | ], 348 | "stateMutability": "nonpayable", 349 | "type": "function" 350 | }, 351 | { 352 | "inputs": [ 353 | { 354 | "internalType": "address", 355 | "name": "token", 356 | "type": "address" 357 | }, 358 | { 359 | "internalType": "uint256", 360 | "name": "liquidity", 361 | "type": "uint256" 362 | }, 363 | { 364 | "internalType": "uint256", 365 | "name": "amountTokenMin", 366 | "type": "uint256" 367 | }, 368 | { 369 | "internalType": "uint256", 370 | "name": "amountETHMin", 371 | "type": "uint256" 372 | }, 373 | { 374 | "internalType": "address", 375 | "name": "to", 376 | "type": "address" 377 | }, 378 | { 379 | "internalType": "uint256", 380 | "name": "deadline", 381 | "type": "uint256" 382 | } 383 | ], 384 | "name": "removeLiquidityETH", 385 | "outputs": [ 386 | { 387 | "internalType": "uint256", 388 | "name": "amountToken", 389 | "type": "uint256" 390 | }, 391 | { 392 | "internalType": "uint256", 393 | "name": "amountETH", 394 | "type": "uint256" 395 | } 396 | ], 397 | "stateMutability": "nonpayable", 398 | "type": "function" 399 | }, 400 | { 401 | "inputs": [ 402 | { 403 | "internalType": "address", 404 | "name": "token", 405 | "type": "address" 406 | }, 407 | { 408 | "internalType": "uint256", 409 | "name": "liquidity", 410 | "type": "uint256" 411 | }, 412 | { 413 | "internalType": "uint256", 414 | "name": "amountTokenMin", 415 | "type": "uint256" 416 | }, 417 | { 418 | "internalType": "uint256", 419 | "name": "amountETHMin", 420 | "type": "uint256" 421 | }, 422 | { 423 | "internalType": "address", 424 | "name": "to", 425 | "type": "address" 426 | }, 427 | { 428 | "internalType": "uint256", 429 | "name": "deadline", 430 | "type": "uint256" 431 | } 432 | ], 433 | "name": "removeLiquidityETHSupportingFeeOnTransferTokens", 434 | "outputs": [ 435 | { 436 | "internalType": "uint256", 437 | "name": "amountETH", 438 | "type": "uint256" 439 | } 440 | ], 441 | "stateMutability": "nonpayable", 442 | "type": "function" 443 | }, 444 | { 445 | "inputs": [ 446 | { 447 | "internalType": "address", 448 | "name": "token", 449 | "type": "address" 450 | }, 451 | { 452 | "internalType": "uint256", 453 | "name": "liquidity", 454 | "type": "uint256" 455 | }, 456 | { 457 | "internalType": "uint256", 458 | "name": "amountTokenMin", 459 | "type": "uint256" 460 | }, 461 | { 462 | "internalType": "uint256", 463 | "name": "amountETHMin", 464 | "type": "uint256" 465 | }, 466 | { 467 | "internalType": "address", 468 | "name": "to", 469 | "type": "address" 470 | }, 471 | { 472 | "internalType": "uint256", 473 | "name": "deadline", 474 | "type": "uint256" 475 | }, 476 | { 477 | "internalType": "bool", 478 | "name": "approveMax", 479 | "type": "bool" 480 | }, 481 | { 482 | "internalType": "uint8", 483 | "name": "v", 484 | "type": "uint8" 485 | }, 486 | { 487 | "internalType": "bytes32", 488 | "name": "r", 489 | "type": "bytes32" 490 | }, 491 | { 492 | "internalType": "bytes32", 493 | "name": "s", 494 | "type": "bytes32" 495 | } 496 | ], 497 | "name": "removeLiquidityETHWithPermit", 498 | "outputs": [ 499 | { 500 | "internalType": "uint256", 501 | "name": "amountToken", 502 | "type": "uint256" 503 | }, 504 | { 505 | "internalType": "uint256", 506 | "name": "amountETH", 507 | "type": "uint256" 508 | } 509 | ], 510 | "stateMutability": "nonpayable", 511 | "type": "function" 512 | }, 513 | { 514 | "inputs": [ 515 | { 516 | "internalType": "address", 517 | "name": "token", 518 | "type": "address" 519 | }, 520 | { 521 | "internalType": "uint256", 522 | "name": "liquidity", 523 | "type": "uint256" 524 | }, 525 | { 526 | "internalType": "uint256", 527 | "name": "amountTokenMin", 528 | "type": "uint256" 529 | }, 530 | { 531 | "internalType": "uint256", 532 | "name": "amountETHMin", 533 | "type": "uint256" 534 | }, 535 | { 536 | "internalType": "address", 537 | "name": "to", 538 | "type": "address" 539 | }, 540 | { 541 | "internalType": "uint256", 542 | "name": "deadline", 543 | "type": "uint256" 544 | }, 545 | { 546 | "internalType": "bool", 547 | "name": "approveMax", 548 | "type": "bool" 549 | }, 550 | { 551 | "internalType": "uint8", 552 | "name": "v", 553 | "type": "uint8" 554 | }, 555 | { 556 | "internalType": "bytes32", 557 | "name": "r", 558 | "type": "bytes32" 559 | }, 560 | { 561 | "internalType": "bytes32", 562 | "name": "s", 563 | "type": "bytes32" 564 | } 565 | ], 566 | "name": "removeLiquidityETHWithPermitSupportingFeeOnTransferTokens", 567 | "outputs": [ 568 | { 569 | "internalType": "uint256", 570 | "name": "amountETH", 571 | "type": "uint256" 572 | } 573 | ], 574 | "stateMutability": "nonpayable", 575 | "type": "function" 576 | }, 577 | { 578 | "inputs": [ 579 | { 580 | "internalType": "address", 581 | "name": "tokenA", 582 | "type": "address" 583 | }, 584 | { 585 | "internalType": "address", 586 | "name": "tokenB", 587 | "type": "address" 588 | }, 589 | { 590 | "internalType": "uint256", 591 | "name": "liquidity", 592 | "type": "uint256" 593 | }, 594 | { 595 | "internalType": "uint256", 596 | "name": "amountAMin", 597 | "type": "uint256" 598 | }, 599 | { 600 | "internalType": "uint256", 601 | "name": "amountBMin", 602 | "type": "uint256" 603 | }, 604 | { 605 | "internalType": "address", 606 | "name": "to", 607 | "type": "address" 608 | }, 609 | { 610 | "internalType": "uint256", 611 | "name": "deadline", 612 | "type": "uint256" 613 | }, 614 | { 615 | "internalType": "bool", 616 | "name": "approveMax", 617 | "type": "bool" 618 | }, 619 | { 620 | "internalType": "uint8", 621 | "name": "v", 622 | "type": "uint8" 623 | }, 624 | { 625 | "internalType": "bytes32", 626 | "name": "r", 627 | "type": "bytes32" 628 | }, 629 | { 630 | "internalType": "bytes32", 631 | "name": "s", 632 | "type": "bytes32" 633 | } 634 | ], 635 | "name": "removeLiquidityWithPermit", 636 | "outputs": [ 637 | { 638 | "internalType": "uint256", 639 | "name": "amountA", 640 | "type": "uint256" 641 | }, 642 | { 643 | "internalType": "uint256", 644 | "name": "amountB", 645 | "type": "uint256" 646 | } 647 | ], 648 | "stateMutability": "nonpayable", 649 | "type": "function" 650 | }, 651 | { 652 | "inputs": [ 653 | { 654 | "internalType": "uint256", 655 | "name": "amountOut", 656 | "type": "uint256" 657 | }, 658 | { 659 | "internalType": "address[]", 660 | "name": "path", 661 | "type": "address[]" 662 | }, 663 | { 664 | "internalType": "address", 665 | "name": "to", 666 | "type": "address" 667 | }, 668 | { 669 | "internalType": "uint256", 670 | "name": "deadline", 671 | "type": "uint256" 672 | } 673 | ], 674 | "name": "swapETHForExactTokens", 675 | "outputs": [ 676 | { 677 | "internalType": "uint256[]", 678 | "name": "amounts", 679 | "type": "uint256[]" 680 | } 681 | ], 682 | "stateMutability": "payable", 683 | "type": "function" 684 | }, 685 | { 686 | "inputs": [ 687 | { 688 | "internalType": "uint256", 689 | "name": "amountOutMin", 690 | "type": "uint256" 691 | }, 692 | { 693 | "internalType": "address[]", 694 | "name": "path", 695 | "type": "address[]" 696 | }, 697 | { 698 | "internalType": "address", 699 | "name": "to", 700 | "type": "address" 701 | }, 702 | { 703 | "internalType": "uint256", 704 | "name": "deadline", 705 | "type": "uint256" 706 | } 707 | ], 708 | "name": "swapExactETHForTokens", 709 | "outputs": [ 710 | { 711 | "internalType": "uint256[]", 712 | "name": "amounts", 713 | "type": "uint256[]" 714 | } 715 | ], 716 | "stateMutability": "payable", 717 | "type": "function" 718 | }, 719 | { 720 | "inputs": [ 721 | { 722 | "internalType": "uint256", 723 | "name": "amountOutMin", 724 | "type": "uint256" 725 | }, 726 | { 727 | "internalType": "address[]", 728 | "name": "path", 729 | "type": "address[]" 730 | }, 731 | { 732 | "internalType": "address", 733 | "name": "to", 734 | "type": "address" 735 | }, 736 | { 737 | "internalType": "uint256", 738 | "name": "deadline", 739 | "type": "uint256" 740 | } 741 | ], 742 | "name": "swapExactETHForTokensSupportingFeeOnTransferTokens", 743 | "outputs": [], 744 | "stateMutability": "payable", 745 | "type": "function" 746 | }, 747 | { 748 | "inputs": [ 749 | { 750 | "internalType": "uint256", 751 | "name": "amountIn", 752 | "type": "uint256" 753 | }, 754 | { 755 | "internalType": "uint256", 756 | "name": "amountOutMin", 757 | "type": "uint256" 758 | }, 759 | { 760 | "internalType": "address[]", 761 | "name": "path", 762 | "type": "address[]" 763 | }, 764 | { 765 | "internalType": "address", 766 | "name": "to", 767 | "type": "address" 768 | }, 769 | { 770 | "internalType": "uint256", 771 | "name": "deadline", 772 | "type": "uint256" 773 | } 774 | ], 775 | "name": "swapExactTokensForETH", 776 | "outputs": [ 777 | { 778 | "internalType": "uint256[]", 779 | "name": "amounts", 780 | "type": "uint256[]" 781 | } 782 | ], 783 | "stateMutability": "nonpayable", 784 | "type": "function" 785 | }, 786 | { 787 | "inputs": [ 788 | { 789 | "internalType": "uint256", 790 | "name": "amountIn", 791 | "type": "uint256" 792 | }, 793 | { 794 | "internalType": "uint256", 795 | "name": "amountOutMin", 796 | "type": "uint256" 797 | }, 798 | { 799 | "internalType": "address[]", 800 | "name": "path", 801 | "type": "address[]" 802 | }, 803 | { 804 | "internalType": "address", 805 | "name": "to", 806 | "type": "address" 807 | }, 808 | { 809 | "internalType": "uint256", 810 | "name": "deadline", 811 | "type": "uint256" 812 | } 813 | ], 814 | "name": "swapExactTokensForETHSupportingFeeOnTransferTokens", 815 | "outputs": [], 816 | "stateMutability": "nonpayable", 817 | "type": "function" 818 | }, 819 | { 820 | "inputs": [ 821 | { 822 | "internalType": "uint256", 823 | "name": "amountIn", 824 | "type": "uint256" 825 | }, 826 | { 827 | "internalType": "uint256", 828 | "name": "amountOutMin", 829 | "type": "uint256" 830 | }, 831 | { 832 | "internalType": "address[]", 833 | "name": "path", 834 | "type": "address[]" 835 | }, 836 | { 837 | "internalType": "address", 838 | "name": "to", 839 | "type": "address" 840 | }, 841 | { 842 | "internalType": "uint256", 843 | "name": "deadline", 844 | "type": "uint256" 845 | } 846 | ], 847 | "name": "swapExactTokensForTokens", 848 | "outputs": [ 849 | { 850 | "internalType": "uint256[]", 851 | "name": "amounts", 852 | "type": "uint256[]" 853 | } 854 | ], 855 | "stateMutability": "nonpayable", 856 | "type": "function" 857 | }, 858 | { 859 | "inputs": [ 860 | { 861 | "internalType": "uint256", 862 | "name": "amountIn", 863 | "type": "uint256" 864 | }, 865 | { 866 | "internalType": "uint256", 867 | "name": "amountOutMin", 868 | "type": "uint256" 869 | }, 870 | { 871 | "internalType": "address[]", 872 | "name": "path", 873 | "type": "address[]" 874 | }, 875 | { 876 | "internalType": "address", 877 | "name": "to", 878 | "type": "address" 879 | }, 880 | { 881 | "internalType": "uint256", 882 | "name": "deadline", 883 | "type": "uint256" 884 | } 885 | ], 886 | "name": "swapExactTokensForTokensSupportingFeeOnTransferTokens", 887 | "outputs": [], 888 | "stateMutability": "nonpayable", 889 | "type": "function" 890 | }, 891 | { 892 | "inputs": [ 893 | { 894 | "internalType": "uint256", 895 | "name": "amountOut", 896 | "type": "uint256" 897 | }, 898 | { 899 | "internalType": "uint256", 900 | "name": "amountInMax", 901 | "type": "uint256" 902 | }, 903 | { 904 | "internalType": "address[]", 905 | "name": "path", 906 | "type": "address[]" 907 | }, 908 | { 909 | "internalType": "address", 910 | "name": "to", 911 | "type": "address" 912 | }, 913 | { 914 | "internalType": "uint256", 915 | "name": "deadline", 916 | "type": "uint256" 917 | } 918 | ], 919 | "name": "swapTokensForExactETH", 920 | "outputs": [ 921 | { 922 | "internalType": "uint256[]", 923 | "name": "amounts", 924 | "type": "uint256[]" 925 | } 926 | ], 927 | "stateMutability": "nonpayable", 928 | "type": "function" 929 | }, 930 | { 931 | "inputs": [ 932 | { 933 | "internalType": "uint256", 934 | "name": "amountOut", 935 | "type": "uint256" 936 | }, 937 | { 938 | "internalType": "uint256", 939 | "name": "amountInMax", 940 | "type": "uint256" 941 | }, 942 | { 943 | "internalType": "address[]", 944 | "name": "path", 945 | "type": "address[]" 946 | }, 947 | { 948 | "internalType": "address", 949 | "name": "to", 950 | "type": "address" 951 | }, 952 | { 953 | "internalType": "uint256", 954 | "name": "deadline", 955 | "type": "uint256" 956 | } 957 | ], 958 | "name": "swapTokensForExactTokens", 959 | "outputs": [ 960 | { 961 | "internalType": "uint256[]", 962 | "name": "amounts", 963 | "type": "uint256[]" 964 | } 965 | ], 966 | "stateMutability": "nonpayable", 967 | "type": "function" 968 | }, 969 | { 970 | "stateMutability": "payable", 971 | "type": "receive" 972 | } 973 | ] -------------------------------------------------------------------------------- /ABIs/erc20.js: -------------------------------------------------------------------------------- 1 | import { Contract } from 'ethers'; // Assuming you have ethers in this file 2 | 3 | function erc20(account, tokenAddress) { 4 | return new Contract( 5 | tokenAddress, 6 | [ 7 | { 8 | constant: true, 9 | inputs: [{ name: "_owner", type: "address" }], 10 | name: "balanceOf", 11 | outputs: [{ name: "balance", type: "uint256" }], 12 | payable: false, 13 | type: "function", 14 | }, 15 | { 16 | inputs: [], 17 | name: "decimals", 18 | outputs: [{ internalType: "uint256", name: "", type: "uint256" }], 19 | stateMutability: "view", 20 | type: "function", 21 | }, 22 | { 23 | inputs: [], 24 | name: "symbol", 25 | outputs: [{ internalType: "string", name: "", type: "string" }], 26 | stateMutability: "view", 27 | type: "function", 28 | }, 29 | { 30 | constant: false, 31 | inputs: [ 32 | { name: "_spender", type: "address" }, 33 | { name: "_value", type: "uint256" }, 34 | ], 35 | name: "approve", 36 | outputs: [{ name: "", type: "bool" }], 37 | payable: false, 38 | stateMutability: "nonpayable", 39 | type: "function", 40 | }, 41 | { 42 | constant: true, 43 | inputs: [ 44 | { name: "_owner", type: "address" }, 45 | { name: "_spender", type: "address" } 46 | ], 47 | name: "allowance", 48 | outputs: [{ name: "remaining", type: "uint256" }], 49 | type: "function", 50 | }, 51 | 52 | ], 53 | account 54 | ); 55 | } 56 | 57 | export default erc20; 58 | -------------------------------------------------------------------------------- /ABIs/index.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import path from 'path'; 3 | import { fileURLToPath } from 'url'; 4 | 5 | const __filename = fileURLToPath(import.meta.url); 6 | const __dirname = path.dirname(__filename); 7 | 8 | const abi = JSON.parse(fs.readFileSync(path.join(__dirname, 'abi.json'), 'utf-8')); 9 | const swapAbi = JSON.parse(fs.readFileSync(path.join(__dirname, 'swapAbi.json'), 'utf-8')); 10 | import erc20 from './erc20.js'; 11 | 12 | export { abi, swapAbi, erc20}; -------------------------------------------------------------------------------- /ABIs/swapABI.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "string", 6 | "name": "_name", 7 | "type": "string" 8 | }, 9 | { 10 | "internalType": "string", 11 | "name": "_symbol", 12 | "type": "string" 13 | }, 14 | { 15 | "internalType": "uint256", 16 | "name": "_decimals", 17 | "type": "uint256" 18 | }, 19 | { 20 | "internalType": "uint256", 21 | "name": "_supply", 22 | "type": "uint256" 23 | }, 24 | { 25 | "internalType": "uint256", 26 | "name": "_txFee", 27 | "type": "uint256" 28 | }, 29 | { 30 | "internalType": "uint256", 31 | "name": "_burnFee", 32 | "type": "uint256" 33 | }, 34 | { 35 | "internalType": "uint256", 36 | "name": "_charityFee", 37 | "type": "uint256" 38 | }, 39 | { 40 | "internalType": "address", 41 | "name": "_FeeAddress", 42 | "type": "address" 43 | }, 44 | { 45 | "internalType": "address", 46 | "name": "tokenOwner", 47 | "type": "address" 48 | } 49 | ], 50 | "stateMutability": "nonpayable", 51 | "type": "constructor" 52 | }, 53 | { 54 | "anonymous": false, 55 | "inputs": [ 56 | { 57 | "indexed": true, 58 | "internalType": "address", 59 | "name": "owner", 60 | "type": "address" 61 | }, 62 | { 63 | "indexed": true, 64 | "internalType": "address", 65 | "name": "spender", 66 | "type": "address" 67 | }, 68 | { 69 | "indexed": false, 70 | "internalType": "uint256", 71 | "name": "value", 72 | "type": "uint256" 73 | } 74 | ], 75 | "name": "Approval", 76 | "type": "event" 77 | }, 78 | { 79 | "anonymous": false, 80 | "inputs": [ 81 | { 82 | "indexed": true, 83 | "internalType": "address", 84 | "name": "previousOwner", 85 | "type": "address" 86 | }, 87 | { 88 | "indexed": true, 89 | "internalType": "address", 90 | "name": "newOwner", 91 | "type": "address" 92 | } 93 | ], 94 | "name": "OwnershipTransferred", 95 | "type": "event" 96 | }, 97 | { 98 | "anonymous": false, 99 | "inputs": [ 100 | { 101 | "indexed": true, 102 | "internalType": "address", 103 | "name": "from", 104 | "type": "address" 105 | }, 106 | { 107 | "indexed": true, 108 | "internalType": "address", 109 | "name": "to", 110 | "type": "address" 111 | }, 112 | { 113 | "indexed": false, 114 | "internalType": "uint256", 115 | "name": "value", 116 | "type": "uint256" 117 | } 118 | ], 119 | "name": "Transfer", 120 | "type": "event" 121 | }, 122 | { 123 | "inputs": [], 124 | "name": "FeeAddress", 125 | "outputs": [ 126 | { 127 | "internalType": "address", 128 | "name": "", 129 | "type": "address" 130 | } 131 | ], 132 | "stateMutability": "view", 133 | "type": "function" 134 | }, 135 | { 136 | "inputs": [], 137 | "name": "_BURN_FEE", 138 | "outputs": [ 139 | { 140 | "internalType": "uint256", 141 | "name": "", 142 | "type": "uint256" 143 | } 144 | ], 145 | "stateMutability": "view", 146 | "type": "function" 147 | }, 148 | { 149 | "inputs": [], 150 | "name": "_CHARITY_FEE", 151 | "outputs": [ 152 | { 153 | "internalType": "uint256", 154 | "name": "", 155 | "type": "uint256" 156 | } 157 | ], 158 | "stateMutability": "view", 159 | "type": "function" 160 | }, 161 | { 162 | "inputs": [], 163 | "name": "_TAX_FEE", 164 | "outputs": [ 165 | { 166 | "internalType": "uint256", 167 | "name": "", 168 | "type": "uint256" 169 | } 170 | ], 171 | "stateMutability": "view", 172 | "type": "function" 173 | }, 174 | { 175 | "inputs": [], 176 | "name": "_owner", 177 | "outputs": [ 178 | { 179 | "internalType": "address", 180 | "name": "", 181 | "type": "address" 182 | } 183 | ], 184 | "stateMutability": "view", 185 | "type": "function" 186 | }, 187 | { 188 | "inputs": [ 189 | { 190 | "internalType": "address", 191 | "name": "owner", 192 | "type": "address" 193 | }, 194 | { 195 | "internalType": "address", 196 | "name": "spender", 197 | "type": "address" 198 | } 199 | ], 200 | "name": "allowance", 201 | "outputs": [ 202 | { 203 | "internalType": "uint256", 204 | "name": "", 205 | "type": "uint256" 206 | } 207 | ], 208 | "stateMutability": "view", 209 | "type": "function" 210 | }, 211 | { 212 | "inputs": [ 213 | { 214 | "internalType": "address", 215 | "name": "spender", 216 | "type": "address" 217 | }, 218 | { 219 | "internalType": "uint256", 220 | "name": "amount", 221 | "type": "uint256" 222 | } 223 | ], 224 | "name": "approve", 225 | "outputs": [ 226 | { 227 | "internalType": "bool", 228 | "name": "", 229 | "type": "bool" 230 | } 231 | ], 232 | "stateMutability": "nonpayable", 233 | "type": "function" 234 | }, 235 | { 236 | "inputs": [ 237 | { 238 | "internalType": "address", 239 | "name": "account", 240 | "type": "address" 241 | } 242 | ], 243 | "name": "balanceOf", 244 | "outputs": [ 245 | { 246 | "internalType": "uint256", 247 | "name": "", 248 | "type": "uint256" 249 | } 250 | ], 251 | "stateMutability": "view", 252 | "type": "function" 253 | }, 254 | { 255 | "inputs": [ 256 | { 257 | "internalType": "uint256", 258 | "name": "_value", 259 | "type": "uint256" 260 | } 261 | ], 262 | "name": "burn", 263 | "outputs": [], 264 | "stateMutability": "nonpayable", 265 | "type": "function" 266 | }, 267 | { 268 | "inputs": [], 269 | "name": "decimals", 270 | "outputs": [ 271 | { 272 | "internalType": "uint256", 273 | "name": "", 274 | "type": "uint256" 275 | } 276 | ], 277 | "stateMutability": "view", 278 | "type": "function" 279 | }, 280 | { 281 | "inputs": [ 282 | { 283 | "internalType": "address", 284 | "name": "spender", 285 | "type": "address" 286 | }, 287 | { 288 | "internalType": "uint256", 289 | "name": "subtractedValue", 290 | "type": "uint256" 291 | } 292 | ], 293 | "name": "decreaseAllowance", 294 | "outputs": [ 295 | { 296 | "internalType": "bool", 297 | "name": "", 298 | "type": "bool" 299 | } 300 | ], 301 | "stateMutability": "nonpayable", 302 | "type": "function" 303 | }, 304 | { 305 | "inputs": [ 306 | { 307 | "internalType": "uint256", 308 | "name": "tAmount", 309 | "type": "uint256" 310 | } 311 | ], 312 | "name": "deliver", 313 | "outputs": [], 314 | "stateMutability": "nonpayable", 315 | "type": "function" 316 | }, 317 | { 318 | "inputs": [ 319 | { 320 | "internalType": "address", 321 | "name": "account", 322 | "type": "address" 323 | } 324 | ], 325 | "name": "excludeAccount", 326 | "outputs": [], 327 | "stateMutability": "nonpayable", 328 | "type": "function" 329 | }, 330 | { 331 | "inputs": [ 332 | { 333 | "internalType": "address", 334 | "name": "account", 335 | "type": "address" 336 | } 337 | ], 338 | "name": "includeAccount", 339 | "outputs": [], 340 | "stateMutability": "nonpayable", 341 | "type": "function" 342 | }, 343 | { 344 | "inputs": [ 345 | { 346 | "internalType": "address", 347 | "name": "spender", 348 | "type": "address" 349 | }, 350 | { 351 | "internalType": "uint256", 352 | "name": "addedValue", 353 | "type": "uint256" 354 | } 355 | ], 356 | "name": "increaseAllowance", 357 | "outputs": [ 358 | { 359 | "internalType": "bool", 360 | "name": "", 361 | "type": "bool" 362 | } 363 | ], 364 | "stateMutability": "nonpayable", 365 | "type": "function" 366 | }, 367 | { 368 | "inputs": [ 369 | { 370 | "internalType": "address", 371 | "name": "account", 372 | "type": "address" 373 | } 374 | ], 375 | "name": "isCharity", 376 | "outputs": [ 377 | { 378 | "internalType": "bool", 379 | "name": "", 380 | "type": "bool" 381 | } 382 | ], 383 | "stateMutability": "view", 384 | "type": "function" 385 | }, 386 | { 387 | "inputs": [ 388 | { 389 | "internalType": "address", 390 | "name": "account", 391 | "type": "address" 392 | } 393 | ], 394 | "name": "isExcluded", 395 | "outputs": [ 396 | { 397 | "internalType": "bool", 398 | "name": "", 399 | "type": "bool" 400 | } 401 | ], 402 | "stateMutability": "view", 403 | "type": "function" 404 | }, 405 | { 406 | "inputs": [ 407 | { 408 | "internalType": "address", 409 | "name": "account", 410 | "type": "address" 411 | }, 412 | { 413 | "internalType": "uint256", 414 | "name": "amount", 415 | "type": "uint256" 416 | } 417 | ], 418 | "name": "mint", 419 | "outputs": [], 420 | "stateMutability": "nonpayable", 421 | "type": "function" 422 | }, 423 | { 424 | "inputs": [], 425 | "name": "name", 426 | "outputs": [ 427 | { 428 | "internalType": "string", 429 | "name": "", 430 | "type": "string" 431 | } 432 | ], 433 | "stateMutability": "view", 434 | "type": "function" 435 | }, 436 | { 437 | "inputs": [], 438 | "name": "owner", 439 | "outputs": [ 440 | { 441 | "internalType": "address", 442 | "name": "", 443 | "type": "address" 444 | } 445 | ], 446 | "stateMutability": "view", 447 | "type": "function" 448 | }, 449 | { 450 | "inputs": [ 451 | { 452 | "internalType": "uint256", 453 | "name": "tAmount", 454 | "type": "uint256" 455 | }, 456 | { 457 | "internalType": "bool", 458 | "name": "deductTransferFee", 459 | "type": "bool" 460 | } 461 | ], 462 | "name": "reflectionFromToken", 463 | "outputs": [ 464 | { 465 | "internalType": "uint256", 466 | "name": "", 467 | "type": "uint256" 468 | } 469 | ], 470 | "stateMutability": "view", 471 | "type": "function" 472 | }, 473 | { 474 | "inputs": [], 475 | "name": "renounceOwnership", 476 | "outputs": [], 477 | "stateMutability": "nonpayable", 478 | "type": "function" 479 | }, 480 | { 481 | "inputs": [ 482 | { 483 | "internalType": "address", 484 | "name": "account", 485 | "type": "address" 486 | } 487 | ], 488 | "name": "setAsCharityAccount", 489 | "outputs": [], 490 | "stateMutability": "nonpayable", 491 | "type": "function" 492 | }, 493 | { 494 | "inputs": [], 495 | "name": "symbol", 496 | "outputs": [ 497 | { 498 | "internalType": "string", 499 | "name": "", 500 | "type": "string" 501 | } 502 | ], 503 | "stateMutability": "view", 504 | "type": "function" 505 | }, 506 | { 507 | "inputs": [ 508 | { 509 | "internalType": "uint256", 510 | "name": "rAmount", 511 | "type": "uint256" 512 | } 513 | ], 514 | "name": "tokenFromReflection", 515 | "outputs": [ 516 | { 517 | "internalType": "uint256", 518 | "name": "", 519 | "type": "uint256" 520 | } 521 | ], 522 | "stateMutability": "view", 523 | "type": "function" 524 | }, 525 | { 526 | "inputs": [], 527 | "name": "totalBurn", 528 | "outputs": [ 529 | { 530 | "internalType": "uint256", 531 | "name": "", 532 | "type": "uint256" 533 | } 534 | ], 535 | "stateMutability": "view", 536 | "type": "function" 537 | }, 538 | { 539 | "inputs": [], 540 | "name": "totalCharity", 541 | "outputs": [ 542 | { 543 | "internalType": "uint256", 544 | "name": "", 545 | "type": "uint256" 546 | } 547 | ], 548 | "stateMutability": "view", 549 | "type": "function" 550 | }, 551 | { 552 | "inputs": [], 553 | "name": "totalFees", 554 | "outputs": [ 555 | { 556 | "internalType": "uint256", 557 | "name": "", 558 | "type": "uint256" 559 | } 560 | ], 561 | "stateMutability": "view", 562 | "type": "function" 563 | }, 564 | { 565 | "inputs": [], 566 | "name": "totalSupply", 567 | "outputs": [ 568 | { 569 | "internalType": "uint256", 570 | "name": "", 571 | "type": "uint256" 572 | } 573 | ], 574 | "stateMutability": "view", 575 | "type": "function" 576 | }, 577 | { 578 | "inputs": [ 579 | { 580 | "internalType": "address", 581 | "name": "recipient", 582 | "type": "address" 583 | }, 584 | { 585 | "internalType": "uint256", 586 | "name": "amount", 587 | "type": "uint256" 588 | } 589 | ], 590 | "name": "transfer", 591 | "outputs": [ 592 | { 593 | "internalType": "bool", 594 | "name": "", 595 | "type": "bool" 596 | } 597 | ], 598 | "stateMutability": "nonpayable", 599 | "type": "function" 600 | }, 601 | { 602 | "inputs": [ 603 | { 604 | "internalType": "address", 605 | "name": "sender", 606 | "type": "address" 607 | }, 608 | { 609 | "internalType": "address", 610 | "name": "recipient", 611 | "type": "address" 612 | }, 613 | { 614 | "internalType": "uint256", 615 | "name": "amount", 616 | "type": "uint256" 617 | } 618 | ], 619 | "name": "transferFrom", 620 | "outputs": [ 621 | { 622 | "internalType": "bool", 623 | "name": "", 624 | "type": "bool" 625 | } 626 | ], 627 | "stateMutability": "nonpayable", 628 | "type": "function" 629 | }, 630 | { 631 | "inputs": [ 632 | { 633 | "internalType": "address", 634 | "name": "newOwner", 635 | "type": "address" 636 | } 637 | ], 638 | "name": "transferOwnership", 639 | "outputs": [], 640 | "stateMutability": "nonpayable", 641 | "type": "function" 642 | }, 643 | { 644 | "inputs": [ 645 | { 646 | "internalType": "uint256", 647 | "name": "_txFee", 648 | "type": "uint256" 649 | }, 650 | { 651 | "internalType": "uint256", 652 | "name": "_burnFee", 653 | "type": "uint256" 654 | }, 655 | { 656 | "internalType": "uint256", 657 | "name": "_charityFee", 658 | "type": "uint256" 659 | } 660 | ], 661 | "name": "updateFee", 662 | "outputs": [], 663 | "stateMutability": "nonpayable", 664 | "type": "function" 665 | } 666 | ] -------------------------------------------------------------------------------- /Config/constants.js: -------------------------------------------------------------------------------- 1 | import dotenv from 'dotenv'; 2 | dotenv.config(); 3 | 4 | import Web3 from "web3"; 5 | import { providers, Wallet } from "ethers"; 6 | import chalk from 'chalk'; 7 | import Winston from "winston"; 8 | import fs from 'fs'; 9 | import express from "express"; 10 | const app = express(); 11 | import http from "http"; 12 | import ethers from 'ethers'; 13 | 14 | // List imports 15 | import { blacklist, whitelist } from '../Lists/index.js'; 16 | 17 | // ABI imports 18 | import { abi, erc20, swapAbi } from '../ABIs/index.js'; 19 | 20 | // Function imports 21 | import { calculate_gas_price, buyToken, sellToken, router } from '../Functions/index.js'; 22 | 23 | 24 | // Global ENV variables 25 | const PORT = process.env.PORT || 3888; 26 | let wss = process.env.WSS; 27 | const secretKey = process.env.PRIVATE_KEY; 28 | const minValue = process.env.MINVALUE || 2; 29 | const BNBCONTRACT = process.env.BNB_CONTRACT || "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c"; 30 | const PANROUTERADDRESS = process.env.PAN_ROUTER_ADDRESS; 31 | const Budget = process.env.BUDGET || 0.01; 32 | const Slippage = process.env.SLIPPAGE || 0; 33 | const gas_percent = process.env.GAS_PERCENT || 10; 34 | const web3 = new Web3(wss); 35 | 36 | // Global variables for provider and wallet 37 | const provider = new providers.WebSocketProvider(wss); 38 | const wallet = new Wallet(secretKey, provider); 39 | 40 | export default { 41 | abi, 42 | app, 43 | BNBCONTRACT, 44 | blacklist, 45 | Budget, 46 | buyToken, 47 | calculate_gas_price, 48 | chalk, 49 | erc20, 50 | ethers, 51 | express, 52 | fs, 53 | gas_percent, 54 | http, 55 | minValue, 56 | PANROUTERADDRESS, 57 | PORT, 58 | router, 59 | sellToken, 60 | Slippage, 61 | swapAbi, 62 | wallet, 63 | web3, 64 | Web3, 65 | whitelist, 66 | Winston, 67 | wss 68 | } 69 | -------------------------------------------------------------------------------- /Functions/buyToken.js: -------------------------------------------------------------------------------- 1 | import constants from '../Config/constants.js'; 2 | 3 | const buyToken = async (account, tokenContract, gasLimit, gasPrice) => { 4 | //buyAmount how much are we going to pay for example 0.1 BNB 5 | const buyAmount = constants.Budget; 6 | 7 | //Slippage refers to the difference between the expected price of a trade and the price at which the trade is executed 8 | const slippage = constants.Slippage; 9 | 10 | //amountOutMin how many token we are going to receive 11 | let amountOutMin = 0; 12 | const amountIn = constants.ethers.utils.parseUnits(buyAmount.toString(), "ether"); 13 | if (parseInt(slippage) !== 0) { 14 | const amounts = await constants.router(account).getAmountsOut(amountIn, [ 15 | constants.BNBCONTRACT, 16 | tokenContract, 17 | ]); 18 | amountOutMin = amounts[1].sub(amounts[1].div(100).mul(`${slippage}`)); 19 | } 20 | try { 21 | const tx = await constants.router( 22 | account 23 | ).swapExactETHForTokensSupportingFeeOnTransferTokens( 24 | amountOutMin, 25 | [constants.BNBCONTRACT, tokenContract], 26 | account.address, 27 | Date.now() + 1000 * 60 * 10, 28 | { 29 | value: amountIn, 30 | gasLimit: gasLimit, 31 | gasPrice: gasPrice, 32 | } 33 | ); 34 | const receipt = await tx.wait(); 35 | if (receipt && receipt.blockNumber && receipt.status === 1) { 36 | // 0 - failed, 1 - success 37 | const message = `INFO - Transaction https://bscscan.com/tx/${receipt.transactionHash} mined, status success ${constants.chalk.green('✅')}`; 38 | console.log(constants.chalk.green(message)); 39 | constants.fs.appendFileSync('./error_logs/log.txt', `${new Date().toLocaleString()} - ${message}\n`); 40 | } else if (receipt && receipt.blockNumber && receipt.status === 0) { 41 | const message = `ERROR - Transaction https://bscscan.com/tx/${receipt.transactionHash} mined, status failed ${constants.chalk.red('❌')}`; 42 | console.log(constants.chalk.red(message)); 43 | constants.fs.appendFileSync('./error_logs/log.txt', `${new Date().toLocaleString()} - ${message}\n`); 44 | } else { 45 | const message = `WARNING - Transaction https://bscscan.com/tx/${receipt.transactionHash} not mined ${constants.chalk.yellow('⚠️')}`; 46 | console.log(constants.chalk.yellow(message)); 47 | constants.fs.appendFileSync('./error_logs/log.txt', `${new Date().toLocaleString()} - ${message}\n`); 48 | } 49 | } catch (error) { 50 | let errorMessage = error.message; 51 | const errorReasonIndex = errorMessage.indexOf("(reason="); 52 | 53 | // Extract error reason if it exists 54 | if (errorReasonIndex !== -1) { 55 | errorMessage = errorMessage.substring(errorReasonIndex + 9, errorMessage.indexOf(",")); 56 | errorMessage = `Error reason: ${errorMessage}`; 57 | } 58 | 59 | const message = `ERROR - Error while buying token: ${errorMessage} ${constants.chalk.red('❌')}`; 60 | console.error(constants.chalk.red(message)); 61 | constants.fs.appendFileSync('./error_logs/log.txt', `${new Date().toLocaleString()} - ${message}\n`); 62 | } 63 | 64 | } 65 | 66 | export default buyToken; -------------------------------------------------------------------------------- /Functions/calculateGasPrice.js: -------------------------------------------------------------------------------- 1 | import constants from '../Config/constants.js'; 2 | 3 | function calculate_gas_price(action, amount) { 4 | amount = constants.ethers.BigNumber.from(amount.toString()); 5 | let gasPercent = constants.gas_percent; 6 | if (action === "buy") { 7 | const gasLimit = amount.add(constants.ethers.BigNumber.from("1000000000")); 8 | const percent = gasLimit.div(gasPercent); 9 | return gasLimit.add(percent); 10 | } else { 11 | const gasLimit = amount.sub(constants.ethers.BigNumber.from("1000000000")); 12 | const percent = gasLimit.div(gasPercent); 13 | return gasLimit.add(percent); 14 | } 15 | } 16 | 17 | export default calculate_gas_price; -------------------------------------------------------------------------------- /Functions/index.js: -------------------------------------------------------------------------------- 1 | import calculate_gas_price from './calculateGasPrice.js'; 2 | import buyToken from './buyToken.js'; 3 | import sellToken from './sellToken.js'; 4 | import router from './router.js'; 5 | 6 | export { calculate_gas_price, buyToken, sellToken, router }; 7 | -------------------------------------------------------------------------------- /Functions/router.js: -------------------------------------------------------------------------------- 1 | import constants from '../Config/constants.js'; 2 | 3 | const router = (account, PANROUTERADDRESS) => { 4 | return new constants.ethers.Contract( 5 | constants.PANROUTERADDRESS, 6 | [ 7 | "function getAmountsOut(uint amountIn, address[] memory path) public view returns (uint[] memory amounts)", 8 | "function swapExactTokensForTokens(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts)", 9 | "function swapExactTokensForTokensSupportingFeeOnTransferTokens(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external", 10 | "function swapExactETHForTokensSupportingFeeOnTransferTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) external payable", 11 | "function swapExactTokensForETH (uint amountOutMin, address[] calldata path, address to, uint deadline) external", 12 | ], 13 | account 14 | ); 15 | } 16 | 17 | export default router; 18 | -------------------------------------------------------------------------------- /Functions/sellToken.js: -------------------------------------------------------------------------------- 1 | import constants from '../Config/constants.js'; 2 | 3 | // Helper function to delay execution 4 | const delay = ms => new Promise(res => setTimeout(res, ms)); 5 | 6 | const sellToken = async (account, tokenContract, gasLimit, gasPrice, value = 99) => { 7 | let attempts = 10; // max attempts 8 | let slippage = constants.Slippage; // starting slippage 9 | 10 | while (attempts > 0) { 11 | try { 12 | const contract = new constants.ethers.Contract(constants.PANROUTERADDRESS, constants.abi, account); 13 | const accountAddress = account.address; 14 | const tokenBalance = await constants.erc20(account, tokenContract).balanceOf( 15 | accountAddress 16 | ); 17 | let amountOutMin = 0; 18 | const amountIn = tokenBalance.mul(value).div(100); 19 | 20 | const sellTokenContract = new constants.ethers.Contract( 21 | tokenContract, 22 | constants.swapAbi, 23 | account 24 | ); 25 | const allowance = await sellTokenContract.allowance(account.address, constants.PANROUTERADDRESS); 26 | 27 | // If allowance is less than double the amount we want to sell, approve double the spending 28 | if (allowance.lt(amountIn.mul(2))) { 29 | const approve = await sellTokenContract.approve(constants.PANROUTERADDRESS, amountIn.mul(2)); 30 | const receipt_approve = await approve.wait(); 31 | if ( 32 | receipt_approve && 33 | receipt_approve.blockNumber && 34 | receipt_approve.status === 1 35 | ) { 36 | const message = `INFO - Approved https://bscscan.com/tx/${receipt_approve.transactionHash} ${constants.chalk.green('✅')}`; 37 | console.log(constants.chalk.green(message)); 38 | constants.fs.appendFileSync('./error_logs/log.txt', `${new Date().toLocaleString()} - ${message}\n`); 39 | } 40 | } 41 | 42 | const amounts = await constants.router(account).getAmountsOut(amountIn, [ 43 | tokenContract, 44 | constants.BNBCONTRACT 45 | ]); 46 | 47 | // increment slippage by 2% for each attempt 48 | slippage += 2; 49 | 50 | if (parseInt(slippage) !== 0) { 51 | amountOutMin = amounts[1].sub(amounts[1].mul(slippage.toString()).div(100)); 52 | } else { 53 | amountOutMin = amounts[1]; 54 | } 55 | 56 | const swap_txn = await contract.swapExactTokensForETHSupportingFeeOnTransferTokens( 57 | amountIn, 58 | amountOutMin, 59 | [tokenContract, constants.BNBCONTRACT], 60 | accountAddress, 61 | Date.now() + 1000 * 60 * 10, 62 | { 63 | gasLimit: gasLimit, 64 | gasPrice: gasPrice, 65 | } 66 | ); 67 | const receipt = await swap_txn.wait(); 68 | if (receipt && receipt.blockNumber && receipt.status === 1) { 69 | // 0 - failed, 1 - success 70 | const message = `INFO - Transaction https://bscscan.com/tx/${receipt.transactionHash} mined, status success ${constants.chalk.green('✅')}`; 71 | console.log(constants.chalk.green(message)); 72 | constants.fs.appendFileSync('./error_logs/log.txt', `${new Date().toLocaleString()} - ${message}\n`); 73 | // if the sell transaction is successful, break the loop 74 | break; 75 | } else if (receipt && receipt.blockNumber && receipt.status === 0) { 76 | const message = `ERROR - Transaction https://bscscan.com/tx/${receipt.transactionHash} mined, status failed ${constants.chalk.red('❌')}`; 77 | console.log(constants.chalk.red(message)); 78 | constants.fs.appendFileSync('./error_logs/log.txt', `${new Date().toLocaleString()} - ${message}\n`); 79 | } else { 80 | const message = `WARNING - Transaction https://bscscan.com/tx/${receipt.transactionHash} not mined ${constants.chalk.yellow('⚠️')}`; 81 | console.log(constants.chalk.yellow(message)); 82 | constants.fs.appendFileSync('./error_logs/log.txt', `${new Date().toLocaleString()} - ${message}\n`); 83 | } 84 | // decrement the value by 10 each time 85 | value -= 10; 86 | attempts--; 87 | 88 | // delay execution for 5 second (5000 milliseconds) between each sell attempt 89 | await delay(5000); 90 | } catch (error) { 91 | let errorMessage = error.message; 92 | const errorReasonIndex = errorMessage.indexOf("(reason="); 93 | 94 | // Extract error reason if it exists 95 | if (errorReasonIndex !== -1) { 96 | errorMessage = errorMessage.substring(errorReasonIndex + 9, errorMessage.indexOf(",")); 97 | errorMessage = `Error reason: ${errorMessage}`; 98 | } 99 | 100 | const message = `ERROR - Error while selling token: ${errorMessage} ${constants.chalk.red('❌')}`; 101 | console.error(constants.chalk.red(message)); 102 | constants.fs.appendFileSync('./error_logs/log.txt', `${new Date().toLocaleString()} - ${message}\n`); 103 | attempts--; 104 | 105 | // delay execution for 1 second (1000 milliseconds) between each sell attempt 106 | await delay(1000); 107 | } 108 | 109 | } // closing brace for while loop 110 | // If all attempts have been made and the token couldn't be sold, add to blacklist 111 | if (attempts === 0) { 112 | constants.blacklist.push(tokenContract); 113 | constants.fs.writeFile('./Lists/blacklist.json', JSON.stringify(constants.blacklist), (err) => { 114 | if (err) { 115 | const message = `ERROR - Error while updating blacklist: ${err} ${constants.chalk.red('❌')}`; 116 | console.error(constants.chalk.red(message)); 117 | constants.fs.appendFileSync('./error_logs/log.txt', `${new Date().toLocaleString()} - ${message}\n`); 118 | } else { 119 | const message = `INFO - Token ${tokenContract} added to blacklist after unsuccessful sell attempts ${constants.chalk.green('✅')}`; 120 | console.log(constants.chalk.green(message)); 121 | constants.fs.appendFileSync('./error_logs/log.txt', `${new Date().toLocaleString()} - ${message}\n`); 122 | } 123 | }); 124 | } 125 | } 126 | 127 | export default sellToken; 128 | -------------------------------------------------------------------------------- /Lists/blacklist.json: -------------------------------------------------------------------------------- 1 | ["0x171130a203df66c50B2Ec2BC0E385dF4F5F6eC20","0x556a527E17732735cf7baBf582a7cF001Fc309C2","0xC41Cd7cE260704b1Fb2AA630ec2d959C529A36BA","0xa18F57919851387Affc4482bF77c2A0609F4DE67","0x55d398326f99059fF775485246999027B3197955","0xB10EDe74D38b15751BACe7CdA02dd6d684126c30","0xda74cD3D68A3E54D955162110Ea40c04Bf7e17E6","0xC4Fd0a6328f39F1db9E9A0DFc32534C78E19Bf6f","0xb5002A946c0150A0EF30eEB034b099928490E67C","0x877839Cc5312743aAEc1F1DDa0c195d89Cd755D5","0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56","0x0E09FaBB73Bd3Ade0a17ECC321fD13a19e81cE82","0x608756c184A0723077B0c10F97f4D054c9eE1C0F","0x1E84BFB6dc6cf352572344B772DF549c04Fda869","0x1e3eC969F9D8fb8FcF01267a56eA2D603B914991","0x082744dD08Dc96929e476d7C65a29B6Bfd6b0755","0x5053C014eB017757e343ff4fc8741195aF76B40c","0xC708Fa57A4e9c821443f6251a4FF11DC446b6741","0x0baB3607beEDC157EccDFECbCAD8Dc038d72f8c5","0x55d398326f99059fF775485246999027B3197955","0x1e84bfb6dc6cf352572344b772df549c04fda869","0xFEC99f71DD6e58Be0711A251eaA44ce1c5B64c01","0x556a527E17732735cf7baBf582a7cF001Fc309C2","0x1E84BFB6dc6cf352572344B772DF549c04Fda869","0x78b617aFA309aF36Fc8606728026C8fd1FC78BBC","0x47974d4117280bb6f6b60182323177f6a1df61b2","0x494c83CaED27aeb836d7fd1482D080e1D35DD0f3","0xedbd18b82215e7e39b7080ad967669b00ff1b8b4","0xf8b8C14CDCCeD823CACCe592c82f526aEB197a30","0x8A3AE5f13Aff94A3E72F45951d2f191Befbc006c","0x253c0460cC962F48e2ff4Be8D9F790B47CE4d756","0x1b9DEc855E98d1c01426a3eD615dd25d2947290E","0x8A3AE5f13Aff94A3E72F45951d2f191Befbc006c","0xd692500383Eb72e271426E732Cdb5668948058d5","0xE5bA47fD94CB645ba4119222e34fB33F59C7CD90","0x7cF551258d6871b72EE1bD1624588a6245bF48c4","0x1dcDC54cFd22E0FF5586A505c827D55A6D8ceB1d","0xC496108Ed523AF656bb0F3E1Cb63E3daaCB987F4","0xF0C26f3c132FF29FfCd236DB51E18b935137E76c","0x0451BCC93E8bbAfd6849A7cFa747c484658094AD","0x9D655C9eD8D2291f0df80051b2D4d403Ef930acC","0xbC606aFE23c6c77Ab4a19138167053a6bd0C83c3","0x47Fd014706081068448b89Fc6bAca2730977216a","0x237ace23Ab2C36a004AA5e4fB134fe5c1cedF06c","0x13C2C08ebBf9589e47F4F62cC21fFfcD89F69e5B","0x845d551fAE4Be2dD871Eb978beb509fD74261231","0x5fa26252c23e43De50D3368f624e47Fa8808488E","0xbF2F3084B0050A318bA04b9569dB34f84832183D","0x49AD9aC79a9C730b55f2Ee2DA92f2Bc38234fc36","0xdb93cefbc621Fa18bEe2B3fcdFC34860351a1532","0xc9Bb93672E4C10A9BcCCC570D1F1407db2bac1Ac","0xb5640A587dCDc5964A1A441455A41d6Fbb071719","0x7704d0EaD6F74E625d7371b079D8b2475bc852d4","0x98f20E497D2579FF3adb8F37d09f1F5fbFAb42Cb","0x02887cD6615BD7A005b5cB72f27EBbAd70884406","0x8E0c77B827963Cacf18ac170e95f67973d93ed1c","0x69C2fcAe7e30b429166BD616A322e32BeC036bCf","0xCaCbE4A581A7A0e5f4740f981E26299FE4712369","0x9A2478C4036548864d96a97Fbf93f6a3341fedac","0xe01B835630d63DF7Dd09E36B4aae694816e19bdb","0xC8Ea428c377611687502AaAc960712A9A40922C5","0x3C19f025de3Ab7530C38C327A73aDA4eF0a0Ba28","0xaD593871779Ba17B51EBE4eA9905517a57bd2B30","0x3a36dc12eFaa14a3F692B94f97450594459661b6","0xC825E3eb47D82877988BF6669E49FDcb6F1A269F","0x1334d68c198d72aec449E39025F2e61Dac374c3e","0x16384cB0AA7755e091D00EE17BaB7238CA112DAa","0xE6Ff512626702E0D0A59a9CFe78a8e44f5928AaB","0x35ABDE04D3Bf887247EDA7F34dD59cA093E8648F"] -------------------------------------------------------------------------------- /Lists/index.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import path from 'path'; 3 | import { fileURLToPath } from 'url'; 4 | 5 | const __filename = fileURLToPath(import.meta.url); 6 | const __dirname = path.dirname(__filename); 7 | 8 | const blacklist = JSON.parse(fs.readFileSync(path.join(__dirname, 'blacklist.json'), 'utf-8')); 9 | const whitelist = JSON.parse(fs.readFileSync(path.join(__dirname, 'whitelist.json'), 'utf-8')); 10 | 11 | export { blacklist, whitelist}; -------------------------------------------------------------------------------- /Lists/whitelist.json: -------------------------------------------------------------------------------- 1 | [ 2 | "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c", 3 | "0x2170ed0880ac9a755fd29b2688956bd959f933f8", 4 | "0xC41Cd7cE260704b1Fb2AA630ec2d959C529A36BA", 5 | "0x24086EAb82DBDaa4771d0A5D66B0D810458b0E86", 6 | "0xFe19a6Be4dd2BD108b5C87f5125275b14275Ef14", 7 | "0x947FE50c2aE24d5FF56f0e4E7C9043eb6ee1ABe7", 8 | "0x922722E9Ef614EC9A3E94b78496e92AbFBb5A624" 9 | ] 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🚀 Ultimate FrontRunning Bot 2 | 3 | ============================ 4 | 5 | This bot is designed to listen for transactions on PancakeSwap and automatically perform token buying and selling based on predefined conditions. The bot listens to the mempool for any pending transactions and acts upon them. It uses the Ethers.js library to interact with the EVM Blockchain. 6 | 7 | ## 🎯 Features 8 | 9 | ----------- 10 | 11 | - 💹 Real-time transaction monitoring on PancakeSwap. 12 | - ✅ Whitelisting and blacklisting of tokens. 13 | - 💰 Automated token buying and selling. 14 | - 🔀 Dynamic slippage adjustment for sell orders. 15 | - ⛔ Auto-blacklisting of unsellable tokens. 16 | - 🛠️ Error and exception handling. 17 | - 🔄 Auto-reconnection on WebSocket connection loss. 18 | - 📝 Logging of transaction data and errors for review and debugging. 19 | 20 | ## 👀 What is FrontRunning? 21 | 22 | ----------- 23 | 24 | FrontRunning is a practice in which a bot makes a transaction based on prior knowledge of pending transactions in the mempool which are waiting to be mined. In essence, the bot 'jumps' the queue by paying a higher gas fee to get its transaction mined first. 25 | 26 | ## 📂 Project Structure 27 | 28 | ----------- 29 | 30 | - root 31 | - bot.js 32 | - .env 33 | - package.json 34 | - node_modules/ 35 | - ABIs/ 36 | - swapABI.json 37 | - abi.json 38 | - erc20.js 39 | - Lists/ 40 | - blacklist.json 41 | - whitelist.json 42 | - config/ 43 | - constants.js 44 | - functions/ 45 | - calculateGasPrice.js 46 | - router.js 47 | - buyToken.js 48 | - sellToken.js 49 | - error_logs/ 50 | - log.txt 51 | 52 | 53 | ## 🛠️ How to Run the Bot 54 | 55 | ----------- 56 | 57 | 1. Clone this repository to your local machine. 58 | 2. Install Node.js and NPM on your machine. 59 | 3. Run `npm install` in the root directory of the bot to install all the required dependencies. 60 | 4. Create a `.env` file in the root directory of the bot and configure it based on the provided `.env.example` file. You will need to provide your own environment variables. 61 | 5. Obtain a WSS node URL. I used GetBlock.io for my bot running (they provide 40,000 requests/day for free.) You can Sign up with this referral link: [GetBlock](https://account.getblock.io/sign-in?ref=MDFkYzRhOWYtZjVmMC01MGQxLTkyY2ItNThkMWJjZWQxMjY0) or you can use [QuickNode](https://www.quicknode.com?tap_a=67226-09396e&tap_s=3858549-ab57d2&utm_source=affiliate&utm_campaign=generic&utm_content=affiliate_landing_page&utm_medium=generic). 62 | 63 | 64 | 65 | 6. Run `npm start` to start the bot. 66 | 67 | ## 📝 .env Configuration 68 | 69 | ----------- 70 | 71 | Here's an example of what your `.env` file should look like, make sure you replace the `PRIVATE_KEY` and `WSS` node url: 72 | 73 | ``` 74 | env 75 | PORT=3888 76 | WSS=wss://bsc.getblock.io//mainnet/ 77 | PRIVATE_KEY= 78 | BNB_CONTRACT=0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c 79 | PAN_ROUTER_ADDRESS=0x10ED43C718714eb63d5aA57B78B54704E256024E 80 | BUDGET=0.01 81 | MINVALUE=2 82 | SLIPPAGE=11 83 | GAS_PERCENT=10 84 | ``` 85 | 86 | ## ⚠️ Disclaimer 87 | 88 | ----------- 89 | 90 | Please note that this bot is provided as-is, and I am not responsible for any losses you may incur while using it. The bot is not foolproof and does not directly detect scam or honeypot tokens. While it does include functionality for a blacklist and whitelist, these measures are not guaranteed to be 100% effective. Please use this bot responsibly and at your own risk. 91 | 92 | ## 💖 Donations 93 | 94 | ----------- 95 | 96 | If you find this bot useful and would like to support its development, you can send donations to the following address: 97 | 98 | `0xE4d3D0DD2693D978442fd75Dd7176A7551aE282e` 99 | 100 | Donations can be made in any of the following cryptocurrencies: ETH, BNB, MATIC, CRO, etc. Any amount is appreciated and will go a long way in helping support the further development of this bot. Thank you in advance for your generosity! 101 | 102 | ## 📚 Key Components 103 | 104 | ----------------- 105 | 106 | - `bot.js`: The main entry point to the application. It connects to the Ethereum network, listens for transactions, checks token lists, and triggers buying and selling actions. 107 | - `buyToken.js`: Handles the purchasing of tokens on PancakeSwap. 108 | - `sellToken.js`: Manages the selling of tokens on PancakeSwap. If a token cannot be sold after several attempts, it gets automatically added to the blacklist. 109 | - `calculateGasPrice.js`: Calculates the gas price for buying and selling tokens based on the current gas price and the gas percentage set in the .env file. 110 | - `whitelist.json`: Contains a list of tokens that the bot will buy and sell. Currently this is populated manually, but I am working on a way to automate this process. 111 | - `blacklist.json`: Contains a list of tokens that the bot will ignore, this works with the whitelist. If a token is in the whitelist and blacklist, the whitelist takes precedence. If a token is in the blacklist, the bot will ignore it. Auto-blacklisting is also implemented for tokens that cannot be sold after several attempts. 112 | 113 | ## 📦 Costants Configuration 114 | 115 | ----------------- 116 | 117 | - `constants.js`: Contains all the constants used in the application. These include pulling in the .env variables like the contract addresses, gas price, slippage, and other values. 118 | - `router.js`: Handles the routing through the PancakeSwap Router functions. 119 | - `erc20.js`: Contains the ERC20 ABI for interacting with ERC20 tokens. 120 | - `swapABI.json`: Contains the ABI for interacting with the PancakeSwap Router. 121 | - `abi.json`: Contains the ABI for interacting with the PancakeSwap Factory. 122 | 123 | ## 🔄 Operation 124 | 125 | ------------ 126 | 127 | The bot operates by: 128 | 129 | 1. Listening for pending transactions from the PancakeSwap Factory. 130 | 2. Checking if a transaction's value is higher than a set minimum. 131 | 3. Retrieving the token address from the transaction data. 132 | 4. Checking if the token is in the whitelist or blacklist. If it's in the whitelist, the bot proceeds with the transaction. If it's in the blacklist, the bot ignores the transaction. 133 | 5. If the token passes the checks, the bot calculates the gas price for buying and selling, buys the token, and then sells it. 134 | 6. If a token cannot be sold after several attempts, the bot increases the slippage for each try. If all attempts fail, the token is added to the blacklist. 135 | 136 | ## 🔧 Versioning 137 | 138 | ------- 139 | We are using for versioning in this program follows the principles of Semantic Versioning (SemVer). Semantic Versioning is a versioning scheme that consists of three numbers separated by dots: MAJOR.MINOR.PATCH. 140 | 141 | 1. 📦 MAJOR version is incremented when you make incompatible API changes. This means that there are breaking changes that could impact existing functionality and require modifications in the code that uses your program. 142 | 143 | 2. ⚡️ MINOR version is incremented when you add functionality in a backwards-compatible manner. This means that you introduce new features or enhancements that do not break existing functionality. 144 | 145 | 3. 🐛 PATCH version is incremented when you make backwards-compatible bug fixes. This means that you address issues or bugs in the program without introducing any new features or breaking changes. 146 | 147 | Following this versioning methodology helps provide clarity about the nature of changes in each release and allows users to understand the impact of upgrading to a new version. It also helps ensure compatibility and enables users to make informed decisions when incorporating new versions into their projects. 148 | 149 | ### 📌 Using Bump 150 | 151 | ------- 152 | 153 | - Using the package bump to handle versioning and releases 154 | 155 | - Install bump globally using npm: 156 | ```npm install -g @fabiospampinato/bump``` 157 | 158 | - Run bump to see the available commands: 159 | ```bump --help``` 160 | 161 | 162 | ## 📝 TODO 163 | 164 | ------ 165 | 166 | - Portfolio Tracking 📊: Develop a feature to track the bot's token portfolio, showing Profit and Loss. Implement a database for this functionality. 167 | - Database Schema 🗄️: Develop a schema for a database to manage the bot's portfolio and other necessary aspects to track. 168 | - Improved Error Handling 🐞: Enhance the bot's error handling and console logging for easier debugging and more comprehensive error coverage. 169 | - Deployment Strategy 🚀: Create a strategy for deploying the bot remotely, setting the stage for frontend development. 170 | - Frontend Web App 💻: Develop a frontend web application that can be used to manage the bot remotely via a desktop browser or mobile device. 171 | - Backend API 📡: Develop a backend API to support the frontend web app, allowing users to manage the bot remotely. 172 | - Telegram Integration 📱: Integrate the bot with Telegram to allow users to manage the bot remotely via the Telegram app. 173 | - Discord Integration 🎮: Integrate the bot with Discord to allow users to manage the bot remotely via the Discord app. 174 | - Twitter Integration 🐦: Integrate the bot with Twitter to allow users to manage the bot remotely via the Twitter app. 175 | - Multi-chain Functionality ⛓️: Expand the bot's capability to manage multiple EVM-based networks, moving beyond BSC to other chains like Ethereum, Polygon, etc. 176 | - Performance Optimization ⚡: Monitor the bot's performance and identify areas for optimization to ensure it runs efficiently under different network conditions. 177 | - Security Improvements 🔒: Constantly review and improve the bot's security, ensuring that sensitive information like account details remains secure. 178 | - User Customization 🛠️: Allow users to customize bot settings, such as the minimum transaction value or the list of whitelisted/blacklisted tokens. 179 | - Fix Token Approval issue 🐞: Fix the issue where the bot is approving same token contract over and over. 180 | 181 | Remember to keep your Ethereum account and network details secure, as they are sensitive data. Trading involves risks and automated trading can result in a loss of funds, so use this bot responsibly. 🤖 182 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | - Fix issue with approving same token over and over 2 | - Fix error logging to be more clear and separate out different log types 3 | - Portfolio Tracking 📊: Develop a feature to track the bot's token portfolio, showing Profit and Loss. Implement a database for this functionality. 4 | - Database Schema 🗄️: Develop a schema for a database to manage the bot's portfolio and other necessary aspects to track. 5 | - Improved Error Handling 🐞: Enhance the bot's error handling and console logging for easier debugging and more comprehensive error coverage. 6 | - Deployment Strategy 🚀: Create a strategy for deploying the bot remotely, setting the stage for frontend development. 7 | - Frontend Web App 💻: Develop a frontend web application that can be used to manage the bot remotely via a desktop browser or mobile device. 8 | - Multi-chain Functionality ⛓️: Expand the bot's capability to manage multiple EVM-based networks, moving beyond BSC to other chains like Ethereum, Polygon, etc. 9 | - Performance Optimization ⚡: Monitor the bot's performance and identify areas for optimization to ensure it runs efficiently under different network conditions. 10 | - Security Improvements 🔒: Constantly review and improve the bot's security, ensuring that sensitive information like account details remains secure. 11 | - User Customization 🛠️: Allow users to customize bot settings, such as the minimum transaction value or the list of whitelisted/blacklisted tokens. 12 | -------------------------------------------------------------------------------- /bot.js: -------------------------------------------------------------------------------- 1 | import dotenv from 'dotenv'; 2 | dotenv.config(); 3 | // Importing libraries 4 | import constants from './Config/constants.js'; 5 | 6 | // Catch unhandled promise rejections 7 | process.on("unhandledRejection", (reason, p) => { 8 | console.error('Unhandled Rejection at:', p, 'reason:', reason); 9 | }); 10 | 11 | var init = async function () { 12 | try { 13 | var customWsProvider = new constants.ethers.providers.WebSocketProvider(constants.wss); 14 | const account = constants.wallet.connect(customWsProvider); 15 | const iface = new constants.ethers.utils.Interface([ 16 | "function swapExactETHForTokens(uint256 amountOutMin, address[] path, address to, uint256 deadline)", 17 | "function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)", 18 | "function swapExactETHForTokensSupportingFeeOnTransferTokens(uint amountOutMin,address[] calldata path,address to,uint deadline)", 19 | ]); 20 | 21 | customWsProvider.on("pending", async (tx) => { 22 | try { 23 | const transaction = await customWsProvider.getTransaction(tx); 24 | 25 | if (transaction && transaction.to === "0x10ED43C718714eb63d5aA57B78B54704E256024E") { 26 | const value = constants.web3.utils.fromWei(transaction.value.toString()); 27 | 28 | // Skip the transaction if the value is below MINVALUE 29 | if (value <= constants.minValue) { 30 | return; 31 | } 32 | 33 | const gasPrice = constants.web3.utils.fromWei(transaction.gasPrice.toString()); 34 | const gasLimit = constants.web3.utils.fromWei(transaction.gasLimit.toString()); 35 | 36 | // for example we will be only showing transaction that are higher than 30 bnb 37 | if (value > constants.minValue) { 38 | console.log("value : ", value); 39 | console.log("gasPrice : ", gasPrice); 40 | console.log("gasLimit : ", gasLimit); 41 | //we can print the sender of that transaction 42 | console.log("from", transaction.from); 43 | 44 | let result = []; 45 | //we will use try and catch to handle the error and decode the data of the function used to swap the token 46 | try { 47 | result = iface.decodeFunctionData( 48 | "swapExactETHForTokens", 49 | transaction.data 50 | ); 51 | } catch (error) { 52 | try { 53 | result = iface.decodeFunctionData( 54 | "swapExactETHForTokensSupportingFeeOnTransferTokens", 55 | transaction.data 56 | ); 57 | } catch (error) { 58 | try { 59 | result = iface.decodeFunctionData( 60 | "swapETHForExactTokens", 61 | transaction.data 62 | ); 63 | } catch (error) { 64 | console.log("final err : ", transaction); 65 | } 66 | } 67 | } 68 | 69 | if (result.length > 0) { 70 | let tokenAddress = ""; 71 | if (result[1].length > 0) { 72 | tokenAddress = result[1][1]; 73 | console.log("tokenAddress", tokenAddress); 74 | 75 | // Check if the token address is in the whitelist 76 | if (constants.whitelist.includes(tokenAddress)) { 77 | console.log(`Token Address: ${tokenAddress} is in the whitelist, so we will proceed with this transaction.`); 78 | } else { 79 | // If it's not in the whitelist, then check if it's in the blacklist 80 | if (constants.blacklist.includes(tokenAddress)) { 81 | console.log(`Token Address: ${tokenAddress} is in the blacklist, so we will ignore this transaction.`); 82 | return; 83 | } 84 | } 85 | 86 | // Calculate the gas price for buying and selling 87 | const buyGasPrice = constants.calculate_gas_price( 88 | "buy", 89 | transaction.gasPrice 90 | ); 91 | const sellGasPrice = constants.calculate_gas_price( 92 | "sell", 93 | transaction.gasPrice 94 | ); 95 | 96 | console.log("going to buy"); 97 | await constants.buyToken( 98 | account, 99 | tokenAddress, 100 | transaction.gasLimit, 101 | buyGasPrice 102 | ); 103 | 104 | 105 | // after calculating the gas price we buy the token 106 | console.log("going to sell the token"); 107 | await constants.sellToken( 108 | account, 109 | tokenAddress, 110 | transaction.gasLimit, 111 | sellGasPrice 112 | ); 113 | } 114 | } 115 | } 116 | } 117 | } catch (err) { 118 | console.error(`Error processing transaction for tx: ${tx}`); 119 | console.error(err); 120 | } 121 | }); 122 | 123 | customWsProvider._websocket.on("error", async (ep) => { 124 | console.log(`Unable to connect to ${ep.subdomain} retrying in 3s...`); 125 | setTimeout(init, 3000); 126 | }); 127 | 128 | customWsProvider._websocket.on("close", async (code) => { 129 | console.log(`Connection lost with code ${code}! Attempting reconnect in 3s...`); 130 | customWsProvider._websocket.terminate(); 131 | setTimeout(init, 3000); 132 | }); 133 | } catch (err) { 134 | console.error('An error occurred:', err); 135 | } 136 | }; 137 | 138 | init(); 139 | //now we create the express server 140 | const server = constants.http.createServer(constants.app); 141 | // we launch the server 142 | server.listen(constants.PORT, () => { 143 | console.log(`Listening on port ${constants.PORT}`); 144 | }); 145 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | ## [0.0.3] - 2023-06-09 2 | ### Added 3 | - try-catch blocks around async operations to handle potential promise rejections. 4 | - process-level event listener for unhandled promise rejections to catch any that might still occur. 5 | - Check whether a transaction was successfully retrieved before attempting to process it. 6 | - Only process transactions higher than MINVALUE. Transaction not found for tx: message will only be logged for those 7 | - Adding comments for better code clarity. 8 | ## [0.0.2] - 2023-05-16 9 | ### Added 10 | - Approval function in the erc20.js file for the approval of the token 11 | - Update sellToken.js file to include the approval function and double allowance if less then sell amount 12 | ### Changed 13 | ### Deprecated 14 | ### Removed 15 | ### Fixed 16 | ### Security 17 | ## [0.0.1] - 2023-05-16 18 | - Initial Commit for bot 19 | - updates to TODO 20 | - fix(content) updated env.example file contents 21 | - Bumped version to 0.0.1 22 | - update Approval function double allowance if less than 0 23 | 24 | [keep a changelog]: https://keepachangelog.com/en/1.0.0/ 25 | [semantic versioning]: https://semver.org/spec/v2.0.0.html 26 | 27 | [unreleased]: https://github.com/Author/Repository/compare/v0.0.2...HEAD 28 | [0.0.2]: https://github.com/Author/Repository/compare/v0.0.1...v0.0.2 29 | [0.0.1]: https://github.com/Author/Repository/releases/tag/v0.0.1 -------------------------------------------------------------------------------- /folderstruct.tree: -------------------------------------------------------------------------------- 1 | ├── .env 2 | ├── .env.example 3 | ├── .gitignore 4 | ├── ABIs 5 | │ ├── abi.json 6 | │ ├── erc20.js 7 | │ ├── index.js 8 | │ └── swapABI.json 9 | ├── bot.js 10 | ├── Config 11 | │ └── constants.js 12 | ├── error_logs 13 | │ └── log.txt 14 | ├── Functions 15 | │ ├── buyToken.js 16 | │ ├── calculateGasPrice.js 17 | │ ├── index.js 18 | │ ├── router.js 19 | │ └── sellToken.js 20 | ├── Lists 21 | │ ├── blacklist.json 22 | │ ├── index.js 23 | │ └── whitelist.json 24 | ├── package-lock.json 25 | ├── package.json 26 | ├── .gitignore 27 | ├── changelog.md 28 | ├── bump.json 29 | ├── TODO 30 | └── README.md -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ultimate-frontrunning-bot", 3 | "version": "0.0.1", 4 | "description": "Automated trading bot for PancakeSwap based on predefined conditions", 5 | "main": "bot.js", 6 | "type": "module", 7 | "scripts": { 8 | "start": "node bot.js", 9 | "test": "echo \"Error: no test specified\" && exit 1", 10 | "prepare": "husky install", 11 | "release": "semantic-release", 12 | "prebump": "npm run prepublishOnly", 13 | "prerelease": "npm run prepublishOnly", 14 | "postrelease": "npm publish" 15 | }, 16 | "release": { 17 | "branches": [ 18 | "main" 19 | ], 20 | "plugins": [ 21 | "@semantic-release/commit-analyzer", 22 | "@semantic-release/release-notes-generator", 23 | "@semantic-release/npm", 24 | "@semantic-release/changelog", 25 | [ 26 | "@semantic-release/git", 27 | { 28 | "assets": [ 29 | "CHANGELOG.md", 30 | "package.json" 31 | ], 32 | "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}" 33 | } 34 | ] 35 | ] 36 | }, 37 | "author": "KryptoBasedDev", 38 | "license": "MIT", 39 | "dependencies": { 40 | "@structure-codes/cli": "^0.0.6", 41 | "chalk": "^5.2.0", 42 | "chokidar": "^3.5.3", 43 | "dotenv": "^10.0.0", 44 | "ethers": "^5.5.3", 45 | "express": "^4.17.1", 46 | "json": "^11.0.0", 47 | "semantic-release": "^21.0.2", 48 | "web3": "^1.6.1", 49 | "winston": "^3.8.2" 50 | }, 51 | "devDependencies": { 52 | "@semantic-release/changelog": "^5.0.1", 53 | "@semantic-release/commit-analyzer": "^9.0.1", 54 | "@semantic-release/npm": "^9.0.1", 55 | "@semantic-release/release-notes-generator": "^11.0.2", 56 | "@commitlint/cli": "^17.6.3", 57 | "@commitlint/config-conventional": "^17.6.3", 58 | "husky": "^8.0.3" 59 | } 60 | } 61 | --------------------------------------------------------------------------------