├── ReadMe.md ├── Test.sol ├── backend ├── .gitignore ├── package-lock.json ├── package.json └── src │ ├── UniswapV2_V3.js │ ├── abi │ ├── arbitrage.json │ ├── erc20.json │ ├── flashloan.json │ ├── pancakeswapFactory.json │ ├── pancakeswapPair.json │ ├── pancakeswapRouter.json │ ├── sushiswapV2Factory.json │ ├── uniswapV2Pair.json │ └── uniswapV2Router.json │ ├── app.js │ ├── config.json │ ├── pancakeswap.js │ └── sushiswap.js ├── frontend └── index.js └── smartcontract ├── .gitignore ├── contracts ├── FlashloanArbitrage.sol └── NormalArbitrage.sol ├── hardhat.config.js ├── package-lock.json ├── package.json ├── scripts ├── deployFlashLoan.js └── deployNormal.js └── test └── FlashloanArbitrage.test.js /ReadMe.md: -------------------------------------------------------------------------------- 1 | # Test Arbitrage Bot 2 | -------------------------------------------------------------------------------- /Test.sol: -------------------------------------------------------------------------------- 1 | /** 2 | *Submitted for verification at BscScan.com on 2020-09-24 3 | */ 4 | 5 | // File: contracts/interfaces/IPancakePair.sol 6 | 7 | pragma solidity >=0.5.0; 8 | 9 | interface IPancakePair { 10 | event Approval(address indexed owner, address indexed spender, uint value); 11 | event Transfer(address indexed from, address indexed to, uint value); 12 | 13 | function name() external pure returns (string memory); 14 | function symbol() external pure returns (string memory); 15 | function decimals() external pure returns (uint8); 16 | function totalSupply() external view returns (uint); 17 | function balanceOf(address owner) external view returns (uint); 18 | function allowance(address owner, address spender) external view returns (uint); 19 | 20 | function approve(address spender, uint value) external returns (bool); 21 | function transfer(address to, uint value) external returns (bool); 22 | function transferFrom(address from, address to, uint value) external returns (bool); 23 | 24 | function DOMAIN_SEPARATOR() external view returns (bytes32); 25 | function PERMIT_TYPEHASH() external pure returns (bytes32); 26 | function nonces(address owner) external view returns (uint); 27 | 28 | function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; 29 | 30 | event Mint(address indexed sender, uint amount0, uint amount1); 31 | event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); 32 | event Swap( 33 | address indexed sender, 34 | uint amount0In, 35 | uint amount1In, 36 | uint amount0Out, 37 | uint amount1Out, 38 | address indexed to 39 | ); 40 | event Sync(uint112 reserve0, uint112 reserve1); 41 | 42 | function MINIMUM_LIQUIDITY() external pure returns (uint); 43 | function factory() external view returns (address); 44 | function token0() external view returns (address); 45 | function token1() external view returns (address); 46 | function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); 47 | function price0CumulativeLast() external view returns (uint); 48 | function price1CumulativeLast() external view returns (uint); 49 | function kLast() external view returns (uint); 50 | 51 | function mint(address to) external returns (uint liquidity); 52 | function burn(address to) external returns (uint amount0, uint amount1); 53 | function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external; 54 | function skim(address to) external; 55 | function sync() external; 56 | 57 | function initialize(address, address) external; 58 | } 59 | 60 | // File: contracts/interfaces/IPancakeERC20.sol 61 | 62 | pragma solidity >=0.5.0; 63 | 64 | interface IPancakeERC20 { 65 | event Approval(address indexed owner, address indexed spender, uint value); 66 | event Transfer(address indexed from, address indexed to, uint value); 67 | 68 | function name() external pure returns (string memory); 69 | function symbol() external pure returns (string memory); 70 | function decimals() external pure returns (uint8); 71 | function totalSupply() external view returns (uint); 72 | function balanceOf(address owner) external view returns (uint); 73 | function allowance(address owner, address spender) external view returns (uint); 74 | 75 | function approve(address spender, uint value) external returns (bool); 76 | function transfer(address to, uint value) external returns (bool); 77 | function transferFrom(address from, address to, uint value) external returns (bool); 78 | 79 | function DOMAIN_SEPARATOR() external view returns (bytes32); 80 | function PERMIT_TYPEHASH() external pure returns (bytes32); 81 | function nonces(address owner) external view returns (uint); 82 | 83 | function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; 84 | } 85 | 86 | // File: contracts/libraries/SafeMath.sol 87 | 88 | pragma solidity =0.5.16; 89 | 90 | // a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math) 91 | 92 | library SafeMath { 93 | function add(uint x, uint y) internal pure returns (uint z) { 94 | require((z = x + y) >= x, 'ds-math-add-overflow'); 95 | } 96 | 97 | function sub(uint x, uint y) internal pure returns (uint z) { 98 | require((z = x - y) <= x, 'ds-math-sub-underflow'); 99 | } 100 | 101 | function mul(uint x, uint y) internal pure returns (uint z) { 102 | require(y == 0 || (z = x * y) / y == x, 'ds-math-mul-overflow'); 103 | } 104 | } 105 | 106 | // File: contracts/PancakeERC20.sol 107 | 108 | pragma solidity =0.5.16; 109 | 110 | 111 | 112 | contract PancakeERC20 is IPancakeERC20 { 113 | using SafeMath for uint; 114 | 115 | string public constant name = 'Pancake LPs'; 116 | string public constant symbol = 'Cake-LP'; 117 | uint8 public constant decimals = 18; 118 | uint public totalSupply; 119 | mapping(address => uint) public balanceOf; 120 | mapping(address => mapping(address => uint)) public allowance; 121 | 122 | bytes32 public DOMAIN_SEPARATOR; 123 | // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); 124 | bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; 125 | mapping(address => uint) public nonces; 126 | 127 | event Approval(address indexed owner, address indexed spender, uint value); 128 | event Transfer(address indexed from, address indexed to, uint value); 129 | 130 | constructor() public { 131 | uint chainId; 132 | assembly { 133 | chainId := chainid 134 | } 135 | DOMAIN_SEPARATOR = keccak256( 136 | abi.encode( 137 | keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'), 138 | keccak256(bytes(name)), 139 | keccak256(bytes('1')), 140 | chainId, 141 | address(this) 142 | ) 143 | ); 144 | } 145 | 146 | function _mint(address to, uint value) internal { 147 | totalSupply = totalSupply.add(value); 148 | balanceOf[to] = balanceOf[to].add(value); 149 | emit Transfer(address(0), to, value); 150 | } 151 | 152 | function _burn(address from, uint value) internal { 153 | balanceOf[from] = balanceOf[from].sub(value); 154 | totalSupply = totalSupply.sub(value); 155 | emit Transfer(from, address(0), value); 156 | } 157 | 158 | function _approve(address owner, address spender, uint value) private { 159 | allowance[owner][spender] = value; 160 | emit Approval(owner, spender, value); 161 | } 162 | 163 | function _transfer(address from, address to, uint value) private { 164 | balanceOf[from] = balanceOf[from].sub(value); 165 | balanceOf[to] = balanceOf[to].add(value); 166 | emit Transfer(from, to, value); 167 | } 168 | 169 | function approve(address spender, uint value) external returns (bool) { 170 | _approve(msg.sender, spender, value); 171 | return true; 172 | } 173 | 174 | function transfer(address to, uint value) external returns (bool) { 175 | _transfer(msg.sender, to, value); 176 | return true; 177 | } 178 | 179 | function transferFrom(address from, address to, uint value) external returns (bool) { 180 | if (allowance[from][msg.sender] != uint(-1)) { 181 | allowance[from][msg.sender] = allowance[from][msg.sender].sub(value); 182 | } 183 | _transfer(from, to, value); 184 | return true; 185 | } 186 | 187 | function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external { 188 | require(deadline >= block.timestamp, 'Pancake: EXPIRED'); 189 | bytes32 digest = keccak256( 190 | abi.encodePacked( 191 | '\x19\x01', 192 | DOMAIN_SEPARATOR, 193 | keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline)) 194 | ) 195 | ); 196 | address recoveredAddress = ecrecover(digest, v, r, s); 197 | require(recoveredAddress != address(0) && recoveredAddress == owner, 'Pancake: INVALID_SIGNATURE'); 198 | _approve(owner, spender, value); 199 | } 200 | } 201 | 202 | // File: contracts/libraries/Math.sol 203 | 204 | pragma solidity =0.5.16; 205 | 206 | // a library for performing various math operations 207 | 208 | library Math { 209 | function min(uint x, uint y) internal pure returns (uint z) { 210 | z = x < y ? x : y; 211 | } 212 | 213 | // babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method) 214 | function sqrt(uint y) internal pure returns (uint z) { 215 | if (y > 3) { 216 | z = y; 217 | uint x = y / 2 + 1; 218 | while (x < z) { 219 | z = x; 220 | x = (y / x + x) / 2; 221 | } 222 | } else if (y != 0) { 223 | z = 1; 224 | } 225 | } 226 | } 227 | 228 | // File: contracts/libraries/UQ112x112.sol 229 | 230 | pragma solidity =0.5.16; 231 | 232 | // a library for handling binary fixed point numbers (https://en.wikipedia.org/wiki/Q_(number_format)) 233 | 234 | // range: [0, 2**112 - 1] 235 | // resolution: 1 / 2**112 236 | 237 | library UQ112x112 { 238 | uint224 constant Q112 = 2**112; 239 | 240 | // encode a uint112 as a UQ112x112 241 | function encode(uint112 y) internal pure returns (uint224 z) { 242 | z = uint224(y) * Q112; // never overflows 243 | } 244 | 245 | // divide a UQ112x112 by a uint112, returning a UQ112x112 246 | function uqdiv(uint224 x, uint112 y) internal pure returns (uint224 z) { 247 | z = x / uint224(y); 248 | } 249 | } 250 | 251 | // File: contracts/interfaces/IERC20.sol 252 | 253 | pragma solidity >=0.5.0; 254 | 255 | interface IERC20 { 256 | event Approval(address indexed owner, address indexed spender, uint value); 257 | event Transfer(address indexed from, address indexed to, uint value); 258 | 259 | function name() external view returns (string memory); 260 | function symbol() external view returns (string memory); 261 | function decimals() external view returns (uint8); 262 | function totalSupply() external view returns (uint); 263 | function balanceOf(address owner) external view returns (uint); 264 | function allowance(address owner, address spender) external view returns (uint); 265 | 266 | function approve(address spender, uint value) external returns (bool); 267 | function transfer(address to, uint value) external returns (bool); 268 | function transferFrom(address from, address to, uint value) external returns (bool); 269 | } 270 | 271 | // File: contracts/interfaces/IPancakeFactory.sol 272 | 273 | pragma solidity >=0.5.0; 274 | 275 | interface IPancakeFactory { 276 | event PairCreated(address indexed token0, address indexed token1, address pair, uint); 277 | 278 | function feeTo() external view returns (address); 279 | function feeToSetter() external view returns (address); 280 | 281 | function getPair(address tokenA, address tokenB) external view returns (address pair); 282 | function allPairs(uint) external view returns (address pair); 283 | function allPairsLength() external view returns (uint); 284 | 285 | function createPair(address tokenA, address tokenB) external returns (address pair); 286 | 287 | function setFeeTo(address) external; 288 | function setFeeToSetter(address) external; 289 | } 290 | 291 | // File: contracts/interfaces/IPancakeCallee.sol 292 | 293 | pragma solidity >=0.5.0; 294 | 295 | interface IPancakeCallee { 296 | function pancakeCall(address sender, uint amount0, uint amount1, bytes calldata data) external; 297 | } 298 | 299 | // File: contracts/PancakePair.sol 300 | 301 | pragma solidity =0.5.16; 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | contract PancakePair is IPancakePair, PancakeERC20 { 311 | using SafeMath for uint; 312 | using UQ112x112 for uint224; 313 | 314 | uint public constant MINIMUM_LIQUIDITY = 10**3; 315 | bytes4 private constant SELECTOR = bytes4(keccak256(bytes('transfer(address,uint256)'))); 316 | 317 | address public factory; 318 | address public token0; 319 | address public token1; 320 | 321 | uint112 private reserve0; // uses single storage slot, accessible via getReserves 322 | uint112 private reserve1; // uses single storage slot, accessible via getReserves 323 | uint32 private blockTimestampLast; // uses single storage slot, accessible via getReserves 324 | 325 | uint public price0CumulativeLast; 326 | uint public price1CumulativeLast; 327 | uint public kLast; // reserve0 * reserve1, as of immediately after the most recent liquidity event 328 | 329 | uint private unlocked = 1; 330 | modifier lock() { 331 | require(unlocked == 1, 'Pancake: LOCKED'); 332 | unlocked = 0; 333 | _; 334 | unlocked = 1; 335 | } 336 | 337 | function getReserves() public view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast) { 338 | _reserve0 = reserve0; 339 | _reserve1 = reserve1; 340 | _blockTimestampLast = blockTimestampLast; 341 | } 342 | 343 | function _safeTransfer(address token, address to, uint value) private { 344 | (bool success, bytes memory data) = token.call(abi.encodeWithSelector(SELECTOR, to, value)); 345 | require(success && (data.length == 0 || abi.decode(data, (bool))), 'Pancake: TRANSFER_FAILED'); 346 | } 347 | 348 | event Mint(address indexed sender, uint amount0, uint amount1); 349 | event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); 350 | event Swap( 351 | address indexed sender, 352 | uint amount0In, 353 | uint amount1In, 354 | uint amount0Out, 355 | uint amount1Out, 356 | address indexed to 357 | ); 358 | event Sync(uint112 reserve0, uint112 reserve1); 359 | 360 | constructor() public { 361 | factory = msg.sender; 362 | } 363 | 364 | // called once by the factory at time of deployment 365 | function initialize(address _token0, address _token1) external { 366 | require(msg.sender == factory, 'Pancake: FORBIDDEN'); // sufficient check 367 | token0 = _token0; 368 | token1 = _token1; 369 | } 370 | 371 | // update reserves and, on the first call per block, price accumulators 372 | function _update(uint balance0, uint balance1, uint112 _reserve0, uint112 _reserve1) private { 373 | require(balance0 <= uint112(-1) && balance1 <= uint112(-1), 'Pancake: OVERFLOW'); 374 | uint32 blockTimestamp = uint32(block.timestamp % 2**32); 375 | uint32 timeElapsed = blockTimestamp - blockTimestampLast; // overflow is desired 376 | if (timeElapsed > 0 && _reserve0 != 0 && _reserve1 != 0) { 377 | // * never overflows, and + overflow is desired 378 | price0CumulativeLast += uint(UQ112x112.encode(_reserve1).uqdiv(_reserve0)) * timeElapsed; 379 | price1CumulativeLast += uint(UQ112x112.encode(_reserve0).uqdiv(_reserve1)) * timeElapsed; 380 | } 381 | reserve0 = uint112(balance0); 382 | reserve1 = uint112(balance1); 383 | blockTimestampLast = blockTimestamp; 384 | emit Sync(reserve0, reserve1); 385 | } 386 | 387 | // if fee is on, mint liquidity equivalent to 1/6th of the growth in sqrt(k) 388 | function _mintFee(uint112 _reserve0, uint112 _reserve1) private returns (bool feeOn) { 389 | address feeTo = IPancakeFactory(factory).feeTo(); 390 | feeOn = feeTo != address(0); 391 | uint _kLast = kLast; // gas savings 392 | if (feeOn) { 393 | if (_kLast != 0) { 394 | uint rootK = Math.sqrt(uint(_reserve0).mul(_reserve1)); 395 | uint rootKLast = Math.sqrt(_kLast); 396 | if (rootK > rootKLast) { 397 | uint numerator = totalSupply.mul(rootK.sub(rootKLast)); 398 | uint denominator = rootK.mul(3).add(rootKLast); 399 | uint liquidity = numerator / denominator; 400 | if (liquidity > 0) _mint(feeTo, liquidity); 401 | } 402 | } 403 | } else if (_kLast != 0) { 404 | kLast = 0; 405 | } 406 | } 407 | 408 | // this low-level function should be called from a contract which performs important safety checks 409 | function mint(address to) external lock returns (uint liquidity) { 410 | (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings 411 | uint balance0 = IERC20(token0).balanceOf(address(this)); 412 | uint balance1 = IERC20(token1).balanceOf(address(this)); 413 | uint amount0 = balance0.sub(_reserve0); 414 | uint amount1 = balance1.sub(_reserve1); 415 | 416 | bool feeOn = _mintFee(_reserve0, _reserve1); 417 | uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee 418 | if (_totalSupply == 0) { 419 | liquidity = Math.sqrt(amount0.mul(amount1)).sub(MINIMUM_LIQUIDITY); 420 | _mint(address(0), MINIMUM_LIQUIDITY); // permanently lock the first MINIMUM_LIQUIDITY tokens 421 | } else { 422 | liquidity = Math.min(amount0.mul(_totalSupply) / _reserve0, amount1.mul(_totalSupply) / _reserve1); 423 | } 424 | require(liquidity > 0, 'Pancake: INSUFFICIENT_LIQUIDITY_MINTED'); 425 | _mint(to, liquidity); 426 | 427 | _update(balance0, balance1, _reserve0, _reserve1); 428 | if (feeOn) kLast = uint(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date 429 | emit Mint(msg.sender, amount0, amount1); 430 | } 431 | 432 | // this low-level function should be called from a contract which performs important safety checks 433 | function burn(address to) external lock returns (uint amount0, uint amount1) { 434 | (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings 435 | address _token0 = token0; // gas savings 436 | address _token1 = token1; // gas savings 437 | uint balance0 = IERC20(_token0).balanceOf(address(this)); 438 | uint balance1 = IERC20(_token1).balanceOf(address(this)); 439 | uint liquidity = balanceOf[address(this)]; 440 | 441 | bool feeOn = _mintFee(_reserve0, _reserve1); 442 | uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee 443 | amount0 = liquidity.mul(balance0) / _totalSupply; // using balances ensures pro-rata distribution 444 | amount1 = liquidity.mul(balance1) / _totalSupply; // using balances ensures pro-rata distribution 445 | require(amount0 > 0 && amount1 > 0, 'Pancake: INSUFFICIENT_LIQUIDITY_BURNED'); 446 | _burn(address(this), liquidity); 447 | _safeTransfer(_token0, to, amount0); 448 | _safeTransfer(_token1, to, amount1); 449 | balance0 = IERC20(_token0).balanceOf(address(this)); 450 | balance1 = IERC20(_token1).balanceOf(address(this)); 451 | 452 | _update(balance0, balance1, _reserve0, _reserve1); 453 | if (feeOn) kLast = uint(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date 454 | emit Burn(msg.sender, amount0, amount1, to); 455 | } 456 | 457 | // this low-level function should be called from a contract which performs important safety checks 458 | function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external lock { 459 | require(amount0Out > 0 || amount1Out > 0, 'Pancake: INSUFFICIENT_OUTPUT_AMOUNT'); 460 | (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings 461 | require(amount0Out < _reserve0 && amount1Out < _reserve1, 'Pancake: INSUFFICIENT_LIQUIDITY'); 462 | 463 | uint balance0; 464 | uint balance1; 465 | { // scope for _token{0,1}, avoids stack too deep errors 466 | address _token0 = token0; 467 | address _token1 = token1; 468 | require(to != _token0 && to != _token1, 'Pancake: INVALID_TO'); 469 | if (amount0Out > 0) _safeTransfer(_token0, to, amount0Out); // optimistically transfer tokens 470 | if (amount1Out > 0) _safeTransfer(_token1, to, amount1Out); // optimistically transfer tokens 471 | if (data.length > 0) IPancakeCallee(to).pancakeCall(msg.sender, amount0Out, amount1Out, data); 472 | balance0 = IERC20(_token0).balanceOf(address(this)); 473 | balance1 = IERC20(_token1).balanceOf(address(this)); 474 | } 475 | uint amount0In = balance0 > _reserve0 - amount0Out ? balance0 - (_reserve0 - amount0Out) : 0; 476 | uint amount1In = balance1 > _reserve1 - amount1Out ? balance1 - (_reserve1 - amount1Out) : 0; 477 | require(amount0In > 0 || amount1In > 0, 'Pancake: INSUFFICIENT_INPUT_AMOUNT'); 478 | { // scope for reserve{0,1}Adjusted, avoids stack too deep errors 479 | uint balance0Adjusted = balance0.mul(1000).sub(amount0In.mul(2)); 480 | uint balance1Adjusted = balance1.mul(1000).sub(amount1In.mul(2)); 481 | require(balance0Adjusted.mul(balance1Adjusted) >= uint(_reserve0).mul(_reserve1).mul(1000**2), 'Pancake: K'); 482 | } 483 | 484 | _update(balance0, balance1, _reserve0, _reserve1); 485 | emit Swap(msg.sender, amount0In, amount1In, amount0Out, amount1Out, to); 486 | } 487 | 488 | // force balances to match reserves 489 | function skim(address to) external lock { 490 | address _token0 = token0; // gas savings 491 | address _token1 = token1; // gas savings 492 | _safeTransfer(_token0, to, IERC20(_token0).balanceOf(address(this)).sub(reserve0)); 493 | _safeTransfer(_token1, to, IERC20(_token1).balanceOf(address(this)).sub(reserve1)); 494 | } 495 | 496 | // force reserves to match balances 497 | function sync() external lock { 498 | _update(IERC20(token0).balanceOf(address(this)), IERC20(token1).balanceOf(address(this)), reserve0, reserve1); 499 | } 500 | } -------------------------------------------------------------------------------- /backend/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env -------------------------------------------------------------------------------- /backend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "start": "node src/app.js" 4 | }, 5 | "dependencies": { 6 | "axios": "^1.4.0", 7 | "dotenv": "^16.0.3", 8 | "ethers": "^5.4.7", 9 | "web3": "^1.9.0" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /backend/src/UniswapV2_V3.js: -------------------------------------------------------------------------------- 1 | const Web3 = require("web3"); 2 | const dotenv = require("dotenv"); 3 | const tokenABI = require("./abi/erc20.json"); 4 | const flashyABI = require("./abi/flashloan.json"); 5 | const uniswapv2ABI = require("./abi/uniswapV2Router.json"); 6 | const ethers = require("ethers"); 7 | const axios = require("axios"); 8 | dotenv.config(); 9 | 10 | const ETHER_UNITS = { 11 | noether: "0", 12 | wei: "1", 13 | kwei: "1000", 14 | Kwei: "1000", 15 | babbage: "1000", 16 | femtoether: "1000", 17 | mwei: "1000000", 18 | Mwei: "1000000", 19 | lovelace: "1000000", 20 | picoether: "1000000", 21 | gwei: "1000000000", 22 | Gwei: "1000000000", 23 | shannon: "1000000000", 24 | nanoether: "1000000000", 25 | nano: "1000000000", 26 | szabo: "1000000000000", 27 | microether: "1000000000000", 28 | micro: "1000000000000", 29 | finney: "1000000000000000", 30 | milliether: "1000000000000000", 31 | milli: "1000000000000000", 32 | ether: "1000000000000000000", 33 | kether: "1000000000000000000000", 34 | grand: "1000000000000000000000", 35 | mether: "1000000000000000000000000", 36 | gether: "1000000000000000000000000000", 37 | tether: "1000000000000000000000000000000", 38 | }; 39 | 40 | const poolABIV3 = [ 41 | ` function slot0() external view returns 42 | (uint160 sqrtPriceX96, 43 | int24 tick, 44 | uint16 observationIndex, 45 | uint16 observationCardinality, 46 | uint16 observationCardinalityNext, 47 | uint8 feeProtocol, 48 | bool unlocked)`, 49 | ]; 50 | 51 | const factoryABIV3 = [ 52 | ` function getPool(address tokenA, address tokenB, uint24 fee) external view returns (address pool)`, 53 | ]; 54 | 55 | const PRIV_KEY = process.env.KKEEYY; 56 | const RPC_URL = process.env.GOERLI_RPC_URL; 57 | const FLASH_LOAN_ARBITRAGE_ADDRESS = process.env.FLASHY_CONTRACT_ADDRESS; 58 | const ERC20_TOKEN_ADDRESS = process.env.TOKEN_TO_LOAN; // USDC Smart Contract 59 | const LOAN_AMOUNT = process.env.TEKEN_AMOUNT_TO_LOAN; // 100 USDC 60 | const WETH_ADDRESS = process.env.WETH_ADDRESS; // WETH Smart Contract 61 | const ROUTER_ADDRESS_V2 = process.env.UNISWAP_V2_ROUTER_ADDRESS; // Uniswap V2 Router Smart Contract 62 | const FACTORY_ADDRESS_V3 = process.env.UNISWAP_V3_FACTORY_ADDRESS; // Uniswap V3 Factory Smart Contract 63 | //now we use USDC token address on gerli network, and loan amount is 100 USDC 64 | 65 | const web3 = new Web3(RPC_URL); 66 | const provider = new ethers.providers.JsonRpcProvider(RPC_URL); 67 | const myAccount = web3.eth.accounts.privateKeyToAccount(PRIV_KEY); 68 | const flashLoanArbitrageContract = new web3.eth.Contract(flashyABI, FLASH_LOAN_ARBITRAGE_ADDRESS); 69 | const erc20TokenContract = new web3.eth.Contract(tokenABI, ERC20_TOKEN_ADDRESS); 70 | const uniswapV2RouterContract = new web3.eth.Contract(uniswapv2ABI, ROUTER_ADDRESS_V2); 71 | const uniswapV3FactoryContract = new ethers.Contract(FACTORY_ADDRESS_V3, factoryABIV3, provider); 72 | let uniswapV3PoolContract; 73 | 74 | const getCurrentGasPrices = async () => { 75 | try { 76 | //this URL is for Ethereum mainnet and Ethereum testnets 77 | let GAS_STATION = `https://api.debank.com/chain/gas_price_dict_v2?chain=eth`; 78 | var response = await axios.get(GAS_STATION); 79 | var prices = { 80 | low: Math.floor(response.data.data.slow.price), 81 | medium: Math.floor(response.data.data.normal.price), 82 | high: Math.floor(response.data.data.fast.price), 83 | }; 84 | return prices; 85 | } catch (error) { 86 | //console.log(error); 87 | return { 88 | low: 25000000000, 89 | medium: 26000000000, 90 | high: 30000000000, 91 | }; 92 | } 93 | }; 94 | 95 | const getUniswapV2Price = async () => { 96 | let price = 0; 97 | try { 98 | // constructor(chainId: ChainId, address: string, decimals: number, symbol?: string, name?: string); 99 | const tokenDecimals = await erc20TokenContract.methods.decimals().call(); 100 | //console.log("Token Decimals: ", tokenDecimals); 101 | const ethUnitName = Object.keys(ETHER_UNITS).find((key) => Math.pow(10, tokenDecimals).toString() == ETHER_UNITS[key]); 102 | //console.log("ETH Unit: ", ethUnitName); 103 | let unitAmount = web3.utils.toWei("1", ethUnitName.toString()); 104 | //console.log("Unit Amount:", unitAmount); 105 | const amountsOut = await uniswapV2RouterContract.methods.getAmountsOut(unitAmount, [ERC20_TOKEN_ADDRESS, WETH_ADDRESS]).call(); 106 | //console.log("Amounts Out: ", amountsOut); 107 | const ethAmountOnWei = amountsOut[1]; 108 | const ethAmount = web3.utils.fromWei(ethAmountOnWei.toString(), "ether"); 109 | //console.log("ETH Amount: ", ethAmount); 110 | price = Number(ethAmount.toString()); 111 | } catch (error) { 112 | console.log(error); 113 | } 114 | return price; 115 | }; 116 | 117 | const getUniswapV3Price = async () => { 118 | let tokenPrice = 0; 119 | try { 120 | const slot0 = await uniswapV3PoolContract.slot0(); 121 | const sqrtPriceX96 = web3.utils.toBN(slot0?.sqrtPriceX96._hex.toString()); 122 | 123 | var priceX96, Q192; 124 | if (sqrtPriceX96.gt(web3.utils.toBN("0xffffffffffffffffffffffff")) === true) { 125 | let shiftedSqrtPriceX96 = sqrtPriceX96.div(web3.utils.toBN('18446744073709551616')); // 2^64 = 18446744073709551616 126 | priceX96 = shiftedSqrtPriceX96.mul(shiftedSqrtPriceX96); 127 | Q192 = web3.utils.toBN('18446744073709551616'); 128 | } 129 | else { 130 | priceX96 = sqrtPriceX96.mul(sqrtPriceX96); 131 | Q192 = web3.utils.toBN("0x100000000000000000000000000000000000000000000000000000"); 132 | } 133 | //console.log("priceX96 >>>> ", priceX96.toString()); 134 | //console.log("Q192 >>>> ", Q192.toString()); 135 | 136 | if (WETH_ADDRESS.toLowerCase() < ERC20_TOKEN_ADDRESS.toLowerCase()) 137 | tokenPrice = Q192.div(priceX96); 138 | else 139 | tokenPrice = priceX96.div(Q192); 140 | } catch (error) { 141 | console.log(error, "this is the error for getPrice"); 142 | } 143 | return 1 / Number(tokenPrice.toString()); 144 | }; 145 | 146 | const signAndSendTx = async (data, from, to) => { 147 | let currentGasPrice = await getCurrentGasPrices(); 148 | var nonce = await web3.eth.getTransactionCount(myAccount.address, "pending"); 149 | nonce = web3.utils.toHex(nonce); 150 | let encodedABI = data.encodeABI(); 151 | let gasEst = await data.estimateGas({ from: myAccount.address }); 152 | 153 | let tx = { 154 | from: from, 155 | to: to, 156 | gas: gasEst * 10, 157 | gasPrice: currentGasPrice.high, 158 | data: encodedABI, 159 | nonce, 160 | }; 161 | console.log("tx ===> ", tx); 162 | let signedTx = await myAccount.signTransaction(tx); 163 | await web3.eth.sendSignedTransaction(signedTx.rawTransaction) 164 | .on("transactionHash", function (hash) { 165 | console.log("ts hash = ", hash); 166 | }) 167 | .on("receipt", function (receipt) { 168 | console.log(""); 169 | console.log("---------------------- tx succeed ---------------------"); 170 | console.log(""); 171 | }) 172 | .on("error", function (error, receipt) { 173 | console.log(""); 174 | console.log("---------------------- tx failed ---------------------"); 175 | console.error(" error : ", error); 176 | }); 177 | }; 178 | 179 | const processArbitrage = async (premiumAmountOnWeiToLoan, amountOnWeiToLoan) => { 180 | try { 181 | let myBalance = await erc20TokenContract.methods.balanceOf(myAccount.address).call(); 182 | console.log("Wallet Balance: ", Number(myBalance)); 183 | console.log("Premium Amount to Loan: ", premiumAmountOnWeiToLoan); 184 | 185 | const priceOnv2 = await getUniswapV2Price(); 186 | console.log("Price(Uniswap V2): ", priceOnv2); 187 | 188 | const priceOnv3 = await getUniswapV3Price(); 189 | console.log("Price(Uniswap V3): ", priceOnv3); 190 | 191 | let dex_path = 7; 192 | if (priceOnv2 > priceOnv3) 193 | dex_path = 0; 194 | else if (priceOnv2 < priceOnv3) 195 | dex_path = 1; 196 | 197 | if (Number(myBalance) >= premiumAmountOnWeiToLoan) { 198 | //deposit premium to platform 199 | // let transferPremiums = tokenContract.methods.transfer( 200 | // PLATFORM_ADDRESS, 201 | // premiumAmountOnWeiToLoan 202 | // ); 203 | // await signAndSendTx( 204 | // transferPremiums, 205 | // bossWallet.address, 206 | // TOKEN_ADDRESS 207 | // ); 208 | //do flash loan 209 | console.log("Amount to Loan: ", amountOnWeiToLoan, ", Dex Path: ", dex_path); 210 | let doFlashy = flashLoanArbitrageContract.methods.fn_RequestFlashLoan(ERC20_TOKEN_ADDRESS, amountOnWeiToLoan, dex_path); 211 | await signAndSendTx(doFlashy, myAccount.address, FLASH_LOAN_ARBITRAGE_ADDRESS); 212 | } 213 | else { 214 | console.log("Token balance error."); 215 | const tokenSymbol = await erc20TokenContract.methods.symbol().call(); 216 | console.log(`You should deposit about ${Number(LOAN_AMOUNT) * 0.01} ${tokenSymbol} to platform smart contract before run flash loan.`); 217 | } 218 | } 219 | catch (error) { 220 | console.log("ERROR:"); 221 | console.log(error.message); 222 | } 223 | } 224 | 225 | const sleep = (ms) => new Promise(r => setTimeout(r, ms)); 226 | 227 | const main = async () => { 228 | const poolAddr = await uniswapV3FactoryContract.getPool(WETH_ADDRESS, ERC20_TOKEN_ADDRESS, 3000); 229 | uniswapV3PoolContract = new ethers.Contract(poolAddr, poolABIV3, provider); 230 | 231 | const tokenDecimals = await erc20TokenContract.methods.decimals().call(); 232 | const ethUnitName = Object.keys(ETHER_UNITS).find((key) => Math.pow(10, tokenDecimals).toString() == ETHER_UNITS[key]); 233 | let premiumAmountOnWeiToLoan = web3.utils.toWei((Number(LOAN_AMOUNT) * 0.01).toString(), ethUnitName.toString()); 234 | let amountOnWeiToLoan = web3.utils.toWei(LOAN_AMOUNT.toString(), ethUnitName.toString()); 235 | 236 | let transCount = 1; 237 | while (true) { 238 | await processArbitrage(Number(premiumAmountOnWeiToLoan), Number(amountOnWeiToLoan)); 239 | await sleep(1000); 240 | transCount--; 241 | if (transCount == 0) 242 | break; 243 | } 244 | }; 245 | 246 | /*const test = async () => { 247 | setInterval(async () => { 248 | let v2Price = await getUniswapV2Price(); 249 | let v3Price = await getUniswapV3Price(); 250 | console.log("==========================="); 251 | console.log("Uniswap V2 Price: ", v2Price); 252 | console.log("Uniswap V3 Price: ", v3Price); 253 | }, 1000); 254 | } 255 | test();*/ 256 | 257 | /*const printAllLiquidityList = () => { 258 | const url = "https://api.pancakeswap.info/api/v2/pairs"; 259 | 260 | fetch(url) 261 | .then(response => response.json()) 262 | .then(data => { 263 | console.log(data); 264 | for (let pair of data.data) { 265 | console.log(pair.pairName); 266 | console.log(pair.token0); 267 | console.log(pair.token1); 268 | console.log(pair.reserve0); 269 | console.log(pair.reserve1); 270 | console.log(pair.totalSupply); 271 | } 272 | }) 273 | .catch(error => console.error(error)); 274 | }*/ 275 | 276 | main(); 277 | -------------------------------------------------------------------------------- /backend/src/abi/arbitrage.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [], 4 | "stateMutability": "nonpayable", 5 | "type": "constructor" 6 | }, 7 | { 8 | "anonymous": false, 9 | "inputs": [ 10 | { 11 | "indexed": false, 12 | "internalType": "uint256", 13 | "name": "value", 14 | "type": "uint256" 15 | } 16 | ], 17 | "name": "Minner_fee", 18 | "type": "event" 19 | }, 20 | { 21 | "anonymous": false, 22 | "inputs": [ 23 | { 24 | "indexed": true, 25 | "internalType": "address", 26 | "name": "previousOwner", 27 | "type": "address" 28 | }, 29 | { 30 | "indexed": true, 31 | "internalType": "address", 32 | "name": "newOwner", 33 | "type": "address" 34 | } 35 | ], 36 | "name": "OwnershipTransferred", 37 | "type": "event" 38 | }, 39 | { 40 | "anonymous": false, 41 | "inputs": [ 42 | { 43 | "indexed": false, 44 | "internalType": "address", 45 | "name": "sender", 46 | "type": "address" 47 | }, 48 | { 49 | "indexed": false, 50 | "internalType": "uint256", 51 | "name": "value", 52 | "type": "uint256" 53 | } 54 | ], 55 | "name": "Received", 56 | "type": "event" 57 | }, 58 | { 59 | "anonymous": false, 60 | "inputs": [ 61 | { 62 | "indexed": false, 63 | "internalType": "address", 64 | "name": "to", 65 | "type": "address" 66 | }, 67 | { 68 | "indexed": false, 69 | "internalType": "uint256", 70 | "name": "value", 71 | "type": "uint256" 72 | } 73 | ], 74 | "name": "Withdraw", 75 | "type": "event" 76 | }, 77 | { 78 | "anonymous": false, 79 | "inputs": [ 80 | { 81 | "indexed": false, 82 | "internalType": "address", 83 | "name": "to", 84 | "type": "address" 85 | }, 86 | { 87 | "indexed": false, 88 | "internalType": "uint256", 89 | "name": "value", 90 | "type": "uint256" 91 | } 92 | ], 93 | "name": "Withdraw_token", 94 | "type": "event" 95 | }, 96 | { 97 | "stateMutability": "payable", 98 | "type": "fallback" 99 | }, 100 | { 101 | "inputs": [], 102 | "name": "owner", 103 | "outputs": [ 104 | { 105 | "internalType": "address", 106 | "name": "", 107 | "type": "address" 108 | } 109 | ], 110 | "stateMutability": "view", 111 | "type": "function" 112 | }, 113 | { 114 | "inputs": [], 115 | "name": "renounceOwnership", 116 | "outputs": [], 117 | "stateMutability": "nonpayable", 118 | "type": "function" 119 | }, 120 | { 121 | "inputs": [ 122 | { 123 | "internalType": "address", 124 | "name": "token", 125 | "type": "address" 126 | }, 127 | { 128 | "internalType": "uint256", 129 | "name": "amount", 130 | "type": "uint256" 131 | } 132 | ], 133 | "name": "swapTokenWithWethOnPancakeswap", 134 | "outputs": [], 135 | "stateMutability": "nonpayable", 136 | "type": "function" 137 | }, 138 | { 139 | "inputs": [ 140 | { 141 | "internalType": "address", 142 | "name": "token", 143 | "type": "address" 144 | }, 145 | { 146 | "internalType": "uint256", 147 | "name": "amount", 148 | "type": "uint256" 149 | } 150 | ], 151 | "name": "swapTokenWithWethOnSushiswap", 152 | "outputs": [], 153 | "stateMutability": "nonpayable", 154 | "type": "function" 155 | }, 156 | { 157 | "inputs": [ 158 | { 159 | "internalType": "address", 160 | "name": "tokenIn", 161 | "type": "address" 162 | }, 163 | { 164 | "internalType": "address", 165 | "name": "tokenOut", 166 | "type": "address" 167 | }, 168 | { 169 | "internalType": "uint256", 170 | "name": "amountIn", 171 | "type": "uint256" 172 | } 173 | ], 174 | "name": "swapTokensOnPancakeswap", 175 | "outputs": [], 176 | "stateMutability": "nonpayable", 177 | "type": "function" 178 | }, 179 | { 180 | "inputs": [ 181 | { 182 | "internalType": "address", 183 | "name": "tokenIn", 184 | "type": "address" 185 | }, 186 | { 187 | "internalType": "address", 188 | "name": "tokenOut", 189 | "type": "address" 190 | }, 191 | { 192 | "internalType": "uint256", 193 | "name": "amountIn", 194 | "type": "uint256" 195 | } 196 | ], 197 | "name": "swapTokensOnSushiswap", 198 | "outputs": [], 199 | "stateMutability": "nonpayable", 200 | "type": "function" 201 | }, 202 | { 203 | "inputs": [ 204 | { 205 | "internalType": "address", 206 | "name": "token0", 207 | "type": "address" 208 | }, 209 | { 210 | "internalType": "address", 211 | "name": "token1", 212 | "type": "address" 213 | }, 214 | { 215 | "internalType": "uint256", 216 | "name": "amount", 217 | "type": "uint256" 218 | }, 219 | { 220 | "internalType": "bool", 221 | "name": "firstPancake", 222 | "type": "bool" 223 | } 224 | ], 225 | "name": "trade", 226 | "outputs": [], 227 | "stateMutability": "nonpayable", 228 | "type": "function" 229 | }, 230 | { 231 | "inputs": [ 232 | { 233 | "internalType": "address", 234 | "name": "newOwner", 235 | "type": "address" 236 | } 237 | ], 238 | "name": "transferOwnership", 239 | "outputs": [], 240 | "stateMutability": "nonpayable", 241 | "type": "function" 242 | }, 243 | { 244 | "inputs": [ 245 | { 246 | "internalType": "uint256", 247 | "name": "_amount", 248 | "type": "uint256" 249 | } 250 | ], 251 | "name": "withdraw", 252 | "outputs": [ 253 | { 254 | "internalType": "bool", 255 | "name": "", 256 | "type": "bool" 257 | } 258 | ], 259 | "stateMutability": "nonpayable", 260 | "type": "function" 261 | }, 262 | { 263 | "inputs": [ 264 | { 265 | "internalType": "address", 266 | "name": "_token", 267 | "type": "address" 268 | } 269 | ], 270 | "name": "withdrawToken", 271 | "outputs": [ 272 | { 273 | "internalType": "bool", 274 | "name": "", 275 | "type": "bool" 276 | } 277 | ], 278 | "stateMutability": "nonpayable", 279 | "type": "function" 280 | }, 281 | { 282 | "inputs": [ 283 | { 284 | "internalType": "uint8", 285 | "name": "_percentage", 286 | "type": "uint8" 287 | } 288 | ], 289 | "name": "withdrawWeth", 290 | "outputs": [ 291 | { 292 | "internalType": "bool", 293 | "name": "", 294 | "type": "bool" 295 | } 296 | ], 297 | "stateMutability": "nonpayable", 298 | "type": "function" 299 | }, 300 | { 301 | "stateMutability": "payable", 302 | "type": "receive" 303 | } 304 | ] -------------------------------------------------------------------------------- /backend/src/abi/erc20.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 | "stateMutability": "nonpayable", 16 | "type": "constructor" 17 | }, 18 | { 19 | "anonymous": false, 20 | "inputs": [ 21 | { 22 | "indexed": true, 23 | "internalType": "address", 24 | "name": "owner", 25 | "type": "address" 26 | }, 27 | { 28 | "indexed": true, 29 | "internalType": "address", 30 | "name": "spender", 31 | "type": "address" 32 | }, 33 | { 34 | "indexed": false, 35 | "internalType": "uint256", 36 | "name": "value", 37 | "type": "uint256" 38 | } 39 | ], 40 | "name": "Approval", 41 | "type": "event" 42 | }, 43 | { 44 | "anonymous": false, 45 | "inputs": [ 46 | { 47 | "indexed": true, 48 | "internalType": "address", 49 | "name": "from", 50 | "type": "address" 51 | }, 52 | { 53 | "indexed": true, 54 | "internalType": "address", 55 | "name": "to", 56 | "type": "address" 57 | }, 58 | { 59 | "indexed": false, 60 | "internalType": "uint256", 61 | "name": "value", 62 | "type": "uint256" 63 | } 64 | ], 65 | "name": "Transfer", 66 | "type": "event" 67 | }, 68 | { 69 | "inputs": [ 70 | { 71 | "internalType": "address", 72 | "name": "owner", 73 | "type": "address" 74 | }, 75 | { 76 | "internalType": "address", 77 | "name": "spender", 78 | "type": "address" 79 | } 80 | ], 81 | "name": "allowance", 82 | "outputs": [ 83 | { 84 | "internalType": "uint256", 85 | "name": "", 86 | "type": "uint256" 87 | } 88 | ], 89 | "stateMutability": "view", 90 | "type": "function" 91 | }, 92 | { 93 | "inputs": [ 94 | { 95 | "internalType": "address", 96 | "name": "spender", 97 | "type": "address" 98 | }, 99 | { 100 | "internalType": "uint256", 101 | "name": "amount", 102 | "type": "uint256" 103 | } 104 | ], 105 | "name": "approve", 106 | "outputs": [ 107 | { 108 | "internalType": "bool", 109 | "name": "", 110 | "type": "bool" 111 | } 112 | ], 113 | "stateMutability": "nonpayable", 114 | "type": "function" 115 | }, 116 | { 117 | "inputs": [ 118 | { 119 | "internalType": "address", 120 | "name": "account", 121 | "type": "address" 122 | } 123 | ], 124 | "name": "balanceOf", 125 | "outputs": [ 126 | { 127 | "internalType": "uint256", 128 | "name": "", 129 | "type": "uint256" 130 | } 131 | ], 132 | "stateMutability": "view", 133 | "type": "function" 134 | }, 135 | { 136 | "inputs": [], 137 | "name": "decimals", 138 | "outputs": [ 139 | { 140 | "internalType": "uint8", 141 | "name": "", 142 | "type": "uint8" 143 | } 144 | ], 145 | "stateMutability": "view", 146 | "type": "function" 147 | }, 148 | { 149 | "inputs": [ 150 | { 151 | "internalType": "address", 152 | "name": "spender", 153 | "type": "address" 154 | }, 155 | { 156 | "internalType": "uint256", 157 | "name": "subtractedValue", 158 | "type": "uint256" 159 | } 160 | ], 161 | "name": "decreaseAllowance", 162 | "outputs": [ 163 | { 164 | "internalType": "bool", 165 | "name": "", 166 | "type": "bool" 167 | } 168 | ], 169 | "stateMutability": "nonpayable", 170 | "type": "function" 171 | }, 172 | { 173 | "inputs": [ 174 | { 175 | "internalType": "address", 176 | "name": "spender", 177 | "type": "address" 178 | }, 179 | { 180 | "internalType": "uint256", 181 | "name": "addedValue", 182 | "type": "uint256" 183 | } 184 | ], 185 | "name": "increaseAllowance", 186 | "outputs": [ 187 | { 188 | "internalType": "bool", 189 | "name": "", 190 | "type": "bool" 191 | } 192 | ], 193 | "stateMutability": "nonpayable", 194 | "type": "function" 195 | }, 196 | { 197 | "inputs": [], 198 | "name": "name", 199 | "outputs": [ 200 | { 201 | "internalType": "string", 202 | "name": "", 203 | "type": "string" 204 | } 205 | ], 206 | "stateMutability": "view", 207 | "type": "function" 208 | }, 209 | { 210 | "inputs": [], 211 | "name": "symbol", 212 | "outputs": [ 213 | { 214 | "internalType": "string", 215 | "name": "", 216 | "type": "string" 217 | } 218 | ], 219 | "stateMutability": "view", 220 | "type": "function" 221 | }, 222 | { 223 | "inputs": [], 224 | "name": "totalSupply", 225 | "outputs": [ 226 | { 227 | "internalType": "uint256", 228 | "name": "", 229 | "type": "uint256" 230 | } 231 | ], 232 | "stateMutability": "view", 233 | "type": "function" 234 | }, 235 | { 236 | "inputs": [ 237 | { 238 | "internalType": "address", 239 | "name": "to", 240 | "type": "address" 241 | }, 242 | { 243 | "internalType": "uint256", 244 | "name": "amount", 245 | "type": "uint256" 246 | } 247 | ], 248 | "name": "transfer", 249 | "outputs": [ 250 | { 251 | "internalType": "bool", 252 | "name": "", 253 | "type": "bool" 254 | } 255 | ], 256 | "stateMutability": "nonpayable", 257 | "type": "function" 258 | }, 259 | { 260 | "inputs": [ 261 | { 262 | "internalType": "address", 263 | "name": "from", 264 | "type": "address" 265 | }, 266 | { 267 | "internalType": "address", 268 | "name": "to", 269 | "type": "address" 270 | }, 271 | { 272 | "internalType": "uint256", 273 | "name": "amount", 274 | "type": "uint256" 275 | } 276 | ], 277 | "name": "transferFrom", 278 | "outputs": [ 279 | { 280 | "internalType": "bool", 281 | "name": "", 282 | "type": "bool" 283 | } 284 | ], 285 | "stateMutability": "nonpayable", 286 | "type": "function" 287 | } 288 | ] -------------------------------------------------------------------------------- /backend/src/abi/flashloan.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "address", 6 | "name": "_addressProvider", 7 | "type": "address" 8 | } 9 | ], 10 | "stateMutability": "nonpayable", 11 | "type": "constructor" 12 | }, 13 | { 14 | "anonymous": false, 15 | "inputs": [ 16 | { 17 | "indexed": false, 18 | "internalType": "uint256", 19 | "name": "value", 20 | "type": "uint256" 21 | } 22 | ], 23 | "name": "Minner_fee", 24 | "type": "event" 25 | }, 26 | { 27 | "anonymous": false, 28 | "inputs": [ 29 | { 30 | "indexed": true, 31 | "internalType": "address", 32 | "name": "previousOwner", 33 | "type": "address" 34 | }, 35 | { 36 | "indexed": true, 37 | "internalType": "address", 38 | "name": "newOwner", 39 | "type": "address" 40 | } 41 | ], 42 | "name": "OwnershipTransferred", 43 | "type": "event" 44 | }, 45 | { 46 | "anonymous": false, 47 | "inputs": [ 48 | { 49 | "indexed": false, 50 | "internalType": "address", 51 | "name": "sender", 52 | "type": "address" 53 | }, 54 | { 55 | "indexed": false, 56 | "internalType": "uint256", 57 | "name": "value", 58 | "type": "uint256" 59 | } 60 | ], 61 | "name": "Received", 62 | "type": "event" 63 | }, 64 | { 65 | "anonymous": false, 66 | "inputs": [ 67 | { 68 | "indexed": false, 69 | "internalType": "address", 70 | "name": "to", 71 | "type": "address" 72 | }, 73 | { 74 | "indexed": false, 75 | "internalType": "uint256", 76 | "name": "value", 77 | "type": "uint256" 78 | } 79 | ], 80 | "name": "Withdraw", 81 | "type": "event" 82 | }, 83 | { 84 | "anonymous": false, 85 | "inputs": [ 86 | { 87 | "indexed": false, 88 | "internalType": "address", 89 | "name": "to", 90 | "type": "address" 91 | }, 92 | { 93 | "indexed": false, 94 | "internalType": "uint256", 95 | "name": "value", 96 | "type": "uint256" 97 | } 98 | ], 99 | "name": "Withdraw_token", 100 | "type": "event" 101 | }, 102 | { 103 | "stateMutability": "payable", 104 | "type": "fallback" 105 | }, 106 | { 107 | "inputs": [], 108 | "name": "ADDRESSES_PROVIDER", 109 | "outputs": [ 110 | { 111 | "internalType": "contract IPoolAddressesProvider", 112 | "name": "", 113 | "type": "address" 114 | } 115 | ], 116 | "stateMutability": "view", 117 | "type": "function" 118 | }, 119 | { 120 | "inputs": [], 121 | "name": "POOL", 122 | "outputs": [ 123 | { 124 | "internalType": "contract IPool", 125 | "name": "", 126 | "type": "address" 127 | } 128 | ], 129 | "stateMutability": "view", 130 | "type": "function" 131 | }, 132 | { 133 | "inputs": [ 134 | { 135 | "internalType": "address", 136 | "name": "_asset01", 137 | "type": "address" 138 | }, 139 | { 140 | "internalType": "address", 141 | "name": "_asset02", 142 | "type": "address" 143 | }, 144 | { 145 | "internalType": "uint256", 146 | "name": "_amount", 147 | "type": "uint256" 148 | }, 149 | { 150 | "internalType": "uint8", 151 | "name": "_dex_path", 152 | "type": "uint8" 153 | }, 154 | { 155 | "internalType": "uint24", 156 | "name": "_fee", 157 | "type": "uint24" 158 | } 159 | ], 160 | "name": "arb_swap", 161 | "outputs": [], 162 | "stateMutability": "nonpayable", 163 | "type": "function" 164 | }, 165 | { 166 | "inputs": [], 167 | "name": "close", 168 | "outputs": [], 169 | "stateMutability": "payable", 170 | "type": "function" 171 | }, 172 | { 173 | "inputs": [ 174 | { 175 | "internalType": "address", 176 | "name": "asset", 177 | "type": "address" 178 | }, 179 | { 180 | "internalType": "uint256", 181 | "name": "amount", 182 | "type": "uint256" 183 | }, 184 | { 185 | "internalType": "uint256", 186 | "name": "premium", 187 | "type": "uint256" 188 | }, 189 | { 190 | "internalType": "address", 191 | "name": "initiator", 192 | "type": "address" 193 | }, 194 | { 195 | "internalType": "bytes", 196 | "name": "params", 197 | "type": "bytes" 198 | } 199 | ], 200 | "name": "executeOperation", 201 | "outputs": [ 202 | { 203 | "internalType": "bool", 204 | "name": "", 205 | "type": "bool" 206 | } 207 | ], 208 | "stateMutability": "nonpayable", 209 | "type": "function" 210 | }, 211 | { 212 | "inputs": [ 213 | { 214 | "internalType": "address", 215 | "name": "_token", 216 | "type": "address" 217 | }, 218 | { 219 | "internalType": "uint256", 220 | "name": "_amount", 221 | "type": "uint256" 222 | }, 223 | { 224 | "internalType": "uint8", 225 | "name": "dex_path", 226 | "type": "uint8" 227 | } 228 | ], 229 | "name": "fn_RequestFlashLoan", 230 | "outputs": [], 231 | "stateMutability": "nonpayable", 232 | "type": "function" 233 | }, 234 | { 235 | "inputs": [], 236 | "name": "owner", 237 | "outputs": [ 238 | { 239 | "internalType": "address", 240 | "name": "", 241 | "type": "address" 242 | } 243 | ], 244 | "stateMutability": "view", 245 | "type": "function" 246 | }, 247 | { 248 | "inputs": [], 249 | "name": "renounceOwnership", 250 | "outputs": [], 251 | "stateMutability": "nonpayable", 252 | "type": "function" 253 | }, 254 | { 255 | "inputs": [ 256 | { 257 | "internalType": "address", 258 | "name": "newOwner", 259 | "type": "address" 260 | } 261 | ], 262 | "name": "transferOwnership", 263 | "outputs": [], 264 | "stateMutability": "nonpayable", 265 | "type": "function" 266 | }, 267 | { 268 | "inputs": [], 269 | "name": "uni_router_v2", 270 | "outputs": [ 271 | { 272 | "internalType": "contract IUniswapV2Router02", 273 | "name": "", 274 | "type": "address" 275 | } 276 | ], 277 | "stateMutability": "view", 278 | "type": "function" 279 | }, 280 | { 281 | "inputs": [], 282 | "name": "uni_router_v3", 283 | "outputs": [ 284 | { 285 | "internalType": "contract ISwapRouter", 286 | "name": "", 287 | "type": "address" 288 | } 289 | ], 290 | "stateMutability": "view", 291 | "type": "function" 292 | }, 293 | { 294 | "inputs": [ 295 | { 296 | "internalType": "address", 297 | "name": "_tokenIn", 298 | "type": "address" 299 | }, 300 | { 301 | "internalType": "address", 302 | "name": "_tokenOut", 303 | "type": "address" 304 | }, 305 | { 306 | "internalType": "uint256", 307 | "name": "_amountIn", 308 | "type": "uint256" 309 | } 310 | ], 311 | "name": "uni_v2", 312 | "outputs": [], 313 | "stateMutability": "nonpayable", 314 | "type": "function" 315 | }, 316 | { 317 | "inputs": [ 318 | { 319 | "internalType": "address", 320 | "name": "_tokenIn", 321 | "type": "address" 322 | }, 323 | { 324 | "internalType": "address", 325 | "name": "_tokenOut", 326 | "type": "address" 327 | }, 328 | { 329 | "internalType": "uint256", 330 | "name": "_amountIn", 331 | "type": "uint256" 332 | }, 333 | { 334 | "internalType": "uint24", 335 | "name": "_fee", 336 | "type": "uint24" 337 | } 338 | ], 339 | "name": "uni_v3", 340 | "outputs": [], 341 | "stateMutability": "payable", 342 | "type": "function" 343 | }, 344 | { 345 | "inputs": [], 346 | "name": "weth", 347 | "outputs": [ 348 | { 349 | "internalType": "contract IWETH9", 350 | "name": "", 351 | "type": "address" 352 | } 353 | ], 354 | "stateMutability": "view", 355 | "type": "function" 356 | }, 357 | { 358 | "inputs": [ 359 | { 360 | "internalType": "uint256", 361 | "name": "_amount", 362 | "type": "uint256" 363 | } 364 | ], 365 | "name": "withdraw", 366 | "outputs": [ 367 | { 368 | "internalType": "bool", 369 | "name": "", 370 | "type": "bool" 371 | } 372 | ], 373 | "stateMutability": "nonpayable", 374 | "type": "function" 375 | }, 376 | { 377 | "inputs": [ 378 | { 379 | "internalType": "address", 380 | "name": "_token", 381 | "type": "address" 382 | }, 383 | { 384 | "internalType": "uint8", 385 | "name": "_percentage", 386 | "type": "uint8" 387 | }, 388 | { 389 | "internalType": "uint8", 390 | "name": "_dex", 391 | "type": "uint8" 392 | }, 393 | { 394 | "internalType": "uint24", 395 | "name": "_dexfee", 396 | "type": "uint24" 397 | } 398 | ], 399 | "name": "withdraw_filter", 400 | "outputs": [ 401 | { 402 | "internalType": "bool", 403 | "name": "", 404 | "type": "bool" 405 | } 406 | ], 407 | "stateMutability": "nonpayable", 408 | "type": "function" 409 | }, 410 | { 411 | "inputs": [ 412 | { 413 | "internalType": "address", 414 | "name": "_token", 415 | "type": "address" 416 | } 417 | ], 418 | "name": "withdraw_token", 419 | "outputs": [ 420 | { 421 | "internalType": "bool", 422 | "name": "", 423 | "type": "bool" 424 | } 425 | ], 426 | "stateMutability": "nonpayable", 427 | "type": "function" 428 | }, 429 | { 430 | "inputs": [ 431 | { 432 | "internalType": "uint8", 433 | "name": "_percentage", 434 | "type": "uint8" 435 | } 436 | ], 437 | "name": "withdraw_weth", 438 | "outputs": [ 439 | { 440 | "internalType": "bool", 441 | "name": "", 442 | "type": "bool" 443 | } 444 | ], 445 | "stateMutability": "nonpayable", 446 | "type": "function" 447 | }, 448 | { 449 | "stateMutability": "payable", 450 | "type": "receive" 451 | } 452 | ] -------------------------------------------------------------------------------- /backend/src/abi/pancakeswapFactory.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "address", 6 | "name": "_feeToSetter", 7 | "type": "address" 8 | } 9 | ], 10 | "payable": false, 11 | "stateMutability": "nonpayable", 12 | "type": "constructor" 13 | }, 14 | { 15 | "anonymous": false, 16 | "inputs": [ 17 | { 18 | "indexed": true, 19 | "internalType": "address", 20 | "name": "token0", 21 | "type": "address" 22 | }, 23 | { 24 | "indexed": true, 25 | "internalType": "address", 26 | "name": "token1", 27 | "type": "address" 28 | }, 29 | { 30 | "indexed": false, 31 | "internalType": "address", 32 | "name": "pair", 33 | "type": "address" 34 | }, 35 | { 36 | "indexed": false, 37 | "internalType": "uint256", 38 | "name": "", 39 | "type": "uint256" 40 | } 41 | ], 42 | "name": "PairCreated", 43 | "type": "event" 44 | }, 45 | { 46 | "constant": true, 47 | "inputs": [], 48 | "name": "INIT_CODE_PAIR_HASH", 49 | "outputs": [ 50 | { 51 | "internalType": "bytes32", 52 | "name": "", 53 | "type": "bytes32" 54 | } 55 | ], 56 | "payable": false, 57 | "stateMutability": "view", 58 | "type": "function" 59 | }, 60 | { 61 | "constant": true, 62 | "inputs": [ 63 | { 64 | "internalType": "uint256", 65 | "name": "", 66 | "type": "uint256" 67 | } 68 | ], 69 | "name": "allPairs", 70 | "outputs": [ 71 | { 72 | "internalType": "address", 73 | "name": "", 74 | "type": "address" 75 | } 76 | ], 77 | "payable": false, 78 | "stateMutability": "view", 79 | "type": "function" 80 | }, 81 | { 82 | "constant": true, 83 | "inputs": [], 84 | "name": "allPairsLength", 85 | "outputs": [ 86 | { 87 | "internalType": "uint256", 88 | "name": "", 89 | "type": "uint256" 90 | } 91 | ], 92 | "payable": false, 93 | "stateMutability": "view", 94 | "type": "function" 95 | }, 96 | { 97 | "constant": false, 98 | "inputs": [ 99 | { 100 | "internalType": "address", 101 | "name": "tokenA", 102 | "type": "address" 103 | }, 104 | { 105 | "internalType": "address", 106 | "name": "tokenB", 107 | "type": "address" 108 | } 109 | ], 110 | "name": "createPair", 111 | "outputs": [ 112 | { 113 | "internalType": "address", 114 | "name": "pair", 115 | "type": "address" 116 | } 117 | ], 118 | "payable": false, 119 | "stateMutability": "nonpayable", 120 | "type": "function" 121 | }, 122 | { 123 | "constant": true, 124 | "inputs": [], 125 | "name": "feeTo", 126 | "outputs": [ 127 | { 128 | "internalType": "address", 129 | "name": "", 130 | "type": "address" 131 | } 132 | ], 133 | "payable": false, 134 | "stateMutability": "view", 135 | "type": "function" 136 | }, 137 | { 138 | "constant": true, 139 | "inputs": [], 140 | "name": "feeToSetter", 141 | "outputs": [ 142 | { 143 | "internalType": "address", 144 | "name": "", 145 | "type": "address" 146 | } 147 | ], 148 | "payable": false, 149 | "stateMutability": "view", 150 | "type": "function" 151 | }, 152 | { 153 | "constant": true, 154 | "inputs": [ 155 | { 156 | "internalType": "address", 157 | "name": "", 158 | "type": "address" 159 | }, 160 | { 161 | "internalType": "address", 162 | "name": "", 163 | "type": "address" 164 | } 165 | ], 166 | "name": "getPair", 167 | "outputs": [ 168 | { 169 | "internalType": "address", 170 | "name": "", 171 | "type": "address" 172 | } 173 | ], 174 | "payable": false, 175 | "stateMutability": "view", 176 | "type": "function" 177 | }, 178 | { 179 | "constant": false, 180 | "inputs": [ 181 | { 182 | "internalType": "address", 183 | "name": "_feeTo", 184 | "type": "address" 185 | } 186 | ], 187 | "name": "setFeeTo", 188 | "outputs": [], 189 | "payable": false, 190 | "stateMutability": "nonpayable", 191 | "type": "function" 192 | }, 193 | { 194 | "constant": false, 195 | "inputs": [ 196 | { 197 | "internalType": "address", 198 | "name": "_feeToSetter", 199 | "type": "address" 200 | } 201 | ], 202 | "name": "setFeeToSetter", 203 | "outputs": [], 204 | "payable": false, 205 | "stateMutability": "nonpayable", 206 | "type": "function" 207 | } 208 | ] -------------------------------------------------------------------------------- /backend/src/abi/pancakeswapPair.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [], 4 | "payable": false, 5 | "stateMutability": "nonpayable", 6 | "type": "constructor" 7 | }, 8 | { 9 | "anonymous": false, 10 | "inputs": [ 11 | { 12 | "indexed": true, 13 | "internalType": "address", 14 | "name": "owner", 15 | "type": "address" 16 | }, 17 | { 18 | "indexed": true, 19 | "internalType": "address", 20 | "name": "spender", 21 | "type": "address" 22 | }, 23 | { 24 | "indexed": false, 25 | "internalType": "uint256", 26 | "name": "value", 27 | "type": "uint256" 28 | } 29 | ], 30 | "name": "Approval", 31 | "type": "event" 32 | }, 33 | { 34 | "anonymous": false, 35 | "inputs": [ 36 | { 37 | "indexed": true, 38 | "internalType": "address", 39 | "name": "sender", 40 | "type": "address" 41 | }, 42 | { 43 | "indexed": false, 44 | "internalType": "uint256", 45 | "name": "amount0", 46 | "type": "uint256" 47 | }, 48 | { 49 | "indexed": false, 50 | "internalType": "uint256", 51 | "name": "amount1", 52 | "type": "uint256" 53 | }, 54 | { 55 | "indexed": true, 56 | "internalType": "address", 57 | "name": "to", 58 | "type": "address" 59 | } 60 | ], 61 | "name": "Burn", 62 | "type": "event" 63 | }, 64 | { 65 | "anonymous": false, 66 | "inputs": [ 67 | { 68 | "indexed": true, 69 | "internalType": "address", 70 | "name": "sender", 71 | "type": "address" 72 | }, 73 | { 74 | "indexed": false, 75 | "internalType": "uint256", 76 | "name": "amount0", 77 | "type": "uint256" 78 | }, 79 | { 80 | "indexed": false, 81 | "internalType": "uint256", 82 | "name": "amount1", 83 | "type": "uint256" 84 | } 85 | ], 86 | "name": "Mint", 87 | "type": "event" 88 | }, 89 | { 90 | "anonymous": false, 91 | "inputs": [ 92 | { 93 | "indexed": true, 94 | "internalType": "address", 95 | "name": "sender", 96 | "type": "address" 97 | }, 98 | { 99 | "indexed": false, 100 | "internalType": "uint256", 101 | "name": "amount0In", 102 | "type": "uint256" 103 | }, 104 | { 105 | "indexed": false, 106 | "internalType": "uint256", 107 | "name": "amount1In", 108 | "type": "uint256" 109 | }, 110 | { 111 | "indexed": false, 112 | "internalType": "uint256", 113 | "name": "amount0Out", 114 | "type": "uint256" 115 | }, 116 | { 117 | "indexed": false, 118 | "internalType": "uint256", 119 | "name": "amount1Out", 120 | "type": "uint256" 121 | }, 122 | { 123 | "indexed": true, 124 | "internalType": "address", 125 | "name": "to", 126 | "type": "address" 127 | } 128 | ], 129 | "name": "Swap", 130 | "type": "event" 131 | }, 132 | { 133 | "anonymous": false, 134 | "inputs": [ 135 | { 136 | "indexed": false, 137 | "internalType": "uint112", 138 | "name": "reserve0", 139 | "type": "uint112" 140 | }, 141 | { 142 | "indexed": false, 143 | "internalType": "uint112", 144 | "name": "reserve1", 145 | "type": "uint112" 146 | } 147 | ], 148 | "name": "Sync", 149 | "type": "event" 150 | }, 151 | { 152 | "anonymous": false, 153 | "inputs": [ 154 | { 155 | "indexed": true, 156 | "internalType": "address", 157 | "name": "from", 158 | "type": "address" 159 | }, 160 | { 161 | "indexed": true, 162 | "internalType": "address", 163 | "name": "to", 164 | "type": "address" 165 | }, 166 | { 167 | "indexed": false, 168 | "internalType": "uint256", 169 | "name": "value", 170 | "type": "uint256" 171 | } 172 | ], 173 | "name": "Transfer", 174 | "type": "event" 175 | }, 176 | { 177 | "constant": true, 178 | "inputs": [], 179 | "name": "DOMAIN_SEPARATOR", 180 | "outputs": [ 181 | { 182 | "internalType": "bytes32", 183 | "name": "", 184 | "type": "bytes32" 185 | } 186 | ], 187 | "payable": false, 188 | "stateMutability": "view", 189 | "type": "function" 190 | }, 191 | { 192 | "constant": true, 193 | "inputs": [], 194 | "name": "MINIMUM_LIQUIDITY", 195 | "outputs": [ 196 | { 197 | "internalType": "uint256", 198 | "name": "", 199 | "type": "uint256" 200 | } 201 | ], 202 | "payable": false, 203 | "stateMutability": "view", 204 | "type": "function" 205 | }, 206 | { 207 | "constant": true, 208 | "inputs": [], 209 | "name": "PERMIT_TYPEHASH", 210 | "outputs": [ 211 | { 212 | "internalType": "bytes32", 213 | "name": "", 214 | "type": "bytes32" 215 | } 216 | ], 217 | "payable": false, 218 | "stateMutability": "view", 219 | "type": "function" 220 | }, 221 | { 222 | "constant": true, 223 | "inputs": [ 224 | { 225 | "internalType": "address", 226 | "name": "", 227 | "type": "address" 228 | }, 229 | { 230 | "internalType": "address", 231 | "name": "", 232 | "type": "address" 233 | } 234 | ], 235 | "name": "allowance", 236 | "outputs": [ 237 | { 238 | "internalType": "uint256", 239 | "name": "", 240 | "type": "uint256" 241 | } 242 | ], 243 | "payable": false, 244 | "stateMutability": "view", 245 | "type": "function" 246 | }, 247 | { 248 | "constant": false, 249 | "inputs": [ 250 | { 251 | "internalType": "address", 252 | "name": "spender", 253 | "type": "address" 254 | }, 255 | { 256 | "internalType": "uint256", 257 | "name": "value", 258 | "type": "uint256" 259 | } 260 | ], 261 | "name": "approve", 262 | "outputs": [ 263 | { 264 | "internalType": "bool", 265 | "name": "", 266 | "type": "bool" 267 | } 268 | ], 269 | "payable": false, 270 | "stateMutability": "nonpayable", 271 | "type": "function" 272 | }, 273 | { 274 | "constant": true, 275 | "inputs": [ 276 | { 277 | "internalType": "address", 278 | "name": "", 279 | "type": "address" 280 | } 281 | ], 282 | "name": "balanceOf", 283 | "outputs": [ 284 | { 285 | "internalType": "uint256", 286 | "name": "", 287 | "type": "uint256" 288 | } 289 | ], 290 | "payable": false, 291 | "stateMutability": "view", 292 | "type": "function" 293 | }, 294 | { 295 | "constant": false, 296 | "inputs": [ 297 | { 298 | "internalType": "address", 299 | "name": "to", 300 | "type": "address" 301 | } 302 | ], 303 | "name": "burn", 304 | "outputs": [ 305 | { 306 | "internalType": "uint256", 307 | "name": "amount0", 308 | "type": "uint256" 309 | }, 310 | { 311 | "internalType": "uint256", 312 | "name": "amount1", 313 | "type": "uint256" 314 | } 315 | ], 316 | "payable": false, 317 | "stateMutability": "nonpayable", 318 | "type": "function" 319 | }, 320 | { 321 | "constant": true, 322 | "inputs": [], 323 | "name": "decimals", 324 | "outputs": [ 325 | { 326 | "internalType": "uint8", 327 | "name": "", 328 | "type": "uint8" 329 | } 330 | ], 331 | "payable": false, 332 | "stateMutability": "view", 333 | "type": "function" 334 | }, 335 | { 336 | "constant": true, 337 | "inputs": [], 338 | "name": "factory", 339 | "outputs": [ 340 | { 341 | "internalType": "address", 342 | "name": "", 343 | "type": "address" 344 | } 345 | ], 346 | "payable": false, 347 | "stateMutability": "view", 348 | "type": "function" 349 | }, 350 | { 351 | "constant": true, 352 | "inputs": [], 353 | "name": "getReserves", 354 | "outputs": [ 355 | { 356 | "internalType": "uint112", 357 | "name": "_reserve0", 358 | "type": "uint112" 359 | }, 360 | { 361 | "internalType": "uint112", 362 | "name": "_reserve1", 363 | "type": "uint112" 364 | }, 365 | { 366 | "internalType": "uint32", 367 | "name": "_blockTimestampLast", 368 | "type": "uint32" 369 | } 370 | ], 371 | "payable": false, 372 | "stateMutability": "view", 373 | "type": "function" 374 | }, 375 | { 376 | "constant": false, 377 | "inputs": [ 378 | { 379 | "internalType": "address", 380 | "name": "_token0", 381 | "type": "address" 382 | }, 383 | { 384 | "internalType": "address", 385 | "name": "_token1", 386 | "type": "address" 387 | } 388 | ], 389 | "name": "initialize", 390 | "outputs": [], 391 | "payable": false, 392 | "stateMutability": "nonpayable", 393 | "type": "function" 394 | }, 395 | { 396 | "constant": true, 397 | "inputs": [], 398 | "name": "kLast", 399 | "outputs": [ 400 | { 401 | "internalType": "uint256", 402 | "name": "", 403 | "type": "uint256" 404 | } 405 | ], 406 | "payable": false, 407 | "stateMutability": "view", 408 | "type": "function" 409 | }, 410 | { 411 | "constant": false, 412 | "inputs": [ 413 | { 414 | "internalType": "address", 415 | "name": "to", 416 | "type": "address" 417 | } 418 | ], 419 | "name": "mint", 420 | "outputs": [ 421 | { 422 | "internalType": "uint256", 423 | "name": "liquidity", 424 | "type": "uint256" 425 | } 426 | ], 427 | "payable": false, 428 | "stateMutability": "nonpayable", 429 | "type": "function" 430 | }, 431 | { 432 | "constant": true, 433 | "inputs": [], 434 | "name": "name", 435 | "outputs": [ 436 | { 437 | "internalType": "string", 438 | "name": "", 439 | "type": "string" 440 | } 441 | ], 442 | "payable": false, 443 | "stateMutability": "view", 444 | "type": "function" 445 | }, 446 | { 447 | "constant": true, 448 | "inputs": [ 449 | { 450 | "internalType": "address", 451 | "name": "", 452 | "type": "address" 453 | } 454 | ], 455 | "name": "nonces", 456 | "outputs": [ 457 | { 458 | "internalType": "uint256", 459 | "name": "", 460 | "type": "uint256" 461 | } 462 | ], 463 | "payable": false, 464 | "stateMutability": "view", 465 | "type": "function" 466 | }, 467 | { 468 | "constant": false, 469 | "inputs": [ 470 | { 471 | "internalType": "address", 472 | "name": "owner", 473 | "type": "address" 474 | }, 475 | { 476 | "internalType": "address", 477 | "name": "spender", 478 | "type": "address" 479 | }, 480 | { 481 | "internalType": "uint256", 482 | "name": "value", 483 | "type": "uint256" 484 | }, 485 | { 486 | "internalType": "uint256", 487 | "name": "deadline", 488 | "type": "uint256" 489 | }, 490 | { 491 | "internalType": "uint8", 492 | "name": "v", 493 | "type": "uint8" 494 | }, 495 | { 496 | "internalType": "bytes32", 497 | "name": "r", 498 | "type": "bytes32" 499 | }, 500 | { 501 | "internalType": "bytes32", 502 | "name": "s", 503 | "type": "bytes32" 504 | } 505 | ], 506 | "name": "permit", 507 | "outputs": [], 508 | "payable": false, 509 | "stateMutability": "nonpayable", 510 | "type": "function" 511 | }, 512 | { 513 | "constant": true, 514 | "inputs": [], 515 | "name": "price0CumulativeLast", 516 | "outputs": [ 517 | { 518 | "internalType": "uint256", 519 | "name": "", 520 | "type": "uint256" 521 | } 522 | ], 523 | "payable": false, 524 | "stateMutability": "view", 525 | "type": "function" 526 | }, 527 | { 528 | "constant": true, 529 | "inputs": [], 530 | "name": "price1CumulativeLast", 531 | "outputs": [ 532 | { 533 | "internalType": "uint256", 534 | "name": "", 535 | "type": "uint256" 536 | } 537 | ], 538 | "payable": false, 539 | "stateMutability": "view", 540 | "type": "function" 541 | }, 542 | { 543 | "constant": false, 544 | "inputs": [ 545 | { 546 | "internalType": "address", 547 | "name": "to", 548 | "type": "address" 549 | } 550 | ], 551 | "name": "skim", 552 | "outputs": [], 553 | "payable": false, 554 | "stateMutability": "nonpayable", 555 | "type": "function" 556 | }, 557 | { 558 | "constant": false, 559 | "inputs": [ 560 | { 561 | "internalType": "uint256", 562 | "name": "amount0Out", 563 | "type": "uint256" 564 | }, 565 | { 566 | "internalType": "uint256", 567 | "name": "amount1Out", 568 | "type": "uint256" 569 | }, 570 | { 571 | "internalType": "address", 572 | "name": "to", 573 | "type": "address" 574 | }, 575 | { 576 | "internalType": "bytes", 577 | "name": "data", 578 | "type": "bytes" 579 | } 580 | ], 581 | "name": "swap", 582 | "outputs": [], 583 | "payable": false, 584 | "stateMutability": "nonpayable", 585 | "type": "function" 586 | }, 587 | { 588 | "constant": true, 589 | "inputs": [], 590 | "name": "symbol", 591 | "outputs": [ 592 | { 593 | "internalType": "string", 594 | "name": "", 595 | "type": "string" 596 | } 597 | ], 598 | "payable": false, 599 | "stateMutability": "view", 600 | "type": "function" 601 | }, 602 | { 603 | "constant": false, 604 | "inputs": [], 605 | "name": "sync", 606 | "outputs": [], 607 | "payable": false, 608 | "stateMutability": "nonpayable", 609 | "type": "function" 610 | }, 611 | { 612 | "constant": true, 613 | "inputs": [], 614 | "name": "token0", 615 | "outputs": [ 616 | { 617 | "internalType": "address", 618 | "name": "", 619 | "type": "address" 620 | } 621 | ], 622 | "payable": false, 623 | "stateMutability": "view", 624 | "type": "function" 625 | }, 626 | { 627 | "constant": true, 628 | "inputs": [], 629 | "name": "token1", 630 | "outputs": [ 631 | { 632 | "internalType": "address", 633 | "name": "", 634 | "type": "address" 635 | } 636 | ], 637 | "payable": false, 638 | "stateMutability": "view", 639 | "type": "function" 640 | }, 641 | { 642 | "constant": true, 643 | "inputs": [], 644 | "name": "totalSupply", 645 | "outputs": [ 646 | { 647 | "internalType": "uint256", 648 | "name": "", 649 | "type": "uint256" 650 | } 651 | ], 652 | "payable": false, 653 | "stateMutability": "view", 654 | "type": "function" 655 | }, 656 | { 657 | "constant": false, 658 | "inputs": [ 659 | { 660 | "internalType": "address", 661 | "name": "to", 662 | "type": "address" 663 | }, 664 | { 665 | "internalType": "uint256", 666 | "name": "value", 667 | "type": "uint256" 668 | } 669 | ], 670 | "name": "transfer", 671 | "outputs": [ 672 | { 673 | "internalType": "bool", 674 | "name": "", 675 | "type": "bool" 676 | } 677 | ], 678 | "payable": false, 679 | "stateMutability": "nonpayable", 680 | "type": "function" 681 | }, 682 | { 683 | "constant": false, 684 | "inputs": [ 685 | { 686 | "internalType": "address", 687 | "name": "from", 688 | "type": "address" 689 | }, 690 | { 691 | "internalType": "address", 692 | "name": "to", 693 | "type": "address" 694 | }, 695 | { 696 | "internalType": "uint256", 697 | "name": "value", 698 | "type": "uint256" 699 | } 700 | ], 701 | "name": "transferFrom", 702 | "outputs": [ 703 | { 704 | "internalType": "bool", 705 | "name": "", 706 | "type": "bool" 707 | } 708 | ], 709 | "payable": false, 710 | "stateMutability": "nonpayable", 711 | "type": "function" 712 | } 713 | ] -------------------------------------------------------------------------------- /backend/src/abi/sushiswapV2Factory.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "address", 6 | "name": "_feeToSetter", 7 | "type": "address" 8 | } 9 | ], 10 | "stateMutability": "nonpayable", 11 | "type": "constructor" 12 | }, 13 | { 14 | "anonymous": false, 15 | "inputs": [ 16 | { 17 | "indexed": true, 18 | "internalType": "address", 19 | "name": "token0", 20 | "type": "address" 21 | }, 22 | { 23 | "indexed": true, 24 | "internalType": "address", 25 | "name": "token1", 26 | "type": "address" 27 | }, 28 | { 29 | "indexed": false, 30 | "internalType": "address", 31 | "name": "pair", 32 | "type": "address" 33 | }, 34 | { 35 | "indexed": false, 36 | "internalType": "uint256", 37 | "name": "", 38 | "type": "uint256" 39 | } 40 | ], 41 | "name": "PairCreated", 42 | "type": "event" 43 | }, 44 | { 45 | "inputs": [ 46 | { 47 | "internalType": "uint256", 48 | "name": "", 49 | "type": "uint256" 50 | } 51 | ], 52 | "name": "allPairs", 53 | "outputs": [ 54 | { 55 | "internalType": "address", 56 | "name": "", 57 | "type": "address" 58 | } 59 | ], 60 | "stateMutability": "view", 61 | "type": "function" 62 | }, 63 | { 64 | "inputs": [], 65 | "name": "allPairsLength", 66 | "outputs": [ 67 | { 68 | "internalType": "uint256", 69 | "name": "", 70 | "type": "uint256" 71 | } 72 | ], 73 | "stateMutability": "view", 74 | "type": "function" 75 | }, 76 | { 77 | "inputs": [ 78 | { 79 | "internalType": "address", 80 | "name": "tokenA", 81 | "type": "address" 82 | }, 83 | { 84 | "internalType": "address", 85 | "name": "tokenB", 86 | "type": "address" 87 | } 88 | ], 89 | "name": "createPair", 90 | "outputs": [ 91 | { 92 | "internalType": "address", 93 | "name": "pair", 94 | "type": "address" 95 | } 96 | ], 97 | "stateMutability": "nonpayable", 98 | "type": "function" 99 | }, 100 | { 101 | "inputs": [], 102 | "name": "feeTo", 103 | "outputs": [ 104 | { 105 | "internalType": "address", 106 | "name": "", 107 | "type": "address" 108 | } 109 | ], 110 | "stateMutability": "view", 111 | "type": "function" 112 | }, 113 | { 114 | "inputs": [], 115 | "name": "feeToSetter", 116 | "outputs": [ 117 | { 118 | "internalType": "address", 119 | "name": "", 120 | "type": "address" 121 | } 122 | ], 123 | "stateMutability": "view", 124 | "type": "function" 125 | }, 126 | { 127 | "inputs": [ 128 | { 129 | "internalType": "address", 130 | "name": "", 131 | "type": "address" 132 | }, 133 | { 134 | "internalType": "address", 135 | "name": "", 136 | "type": "address" 137 | } 138 | ], 139 | "name": "getPair", 140 | "outputs": [ 141 | { 142 | "internalType": "address", 143 | "name": "", 144 | "type": "address" 145 | } 146 | ], 147 | "stateMutability": "view", 148 | "type": "function" 149 | }, 150 | { 151 | "inputs": [], 152 | "name": "migrator", 153 | "outputs": [ 154 | { 155 | "internalType": "address", 156 | "name": "", 157 | "type": "address" 158 | } 159 | ], 160 | "stateMutability": "view", 161 | "type": "function" 162 | }, 163 | { 164 | "inputs": [], 165 | "name": "pairCodeHash", 166 | "outputs": [ 167 | { 168 | "internalType": "bytes32", 169 | "name": "", 170 | "type": "bytes32" 171 | } 172 | ], 173 | "stateMutability": "pure", 174 | "type": "function" 175 | }, 176 | { 177 | "inputs": [ 178 | { 179 | "internalType": "address", 180 | "name": "_feeTo", 181 | "type": "address" 182 | } 183 | ], 184 | "name": "setFeeTo", 185 | "outputs": [], 186 | "stateMutability": "nonpayable", 187 | "type": "function" 188 | }, 189 | { 190 | "inputs": [ 191 | { 192 | "internalType": "address", 193 | "name": "_feeToSetter", 194 | "type": "address" 195 | } 196 | ], 197 | "name": "setFeeToSetter", 198 | "outputs": [], 199 | "stateMutability": "nonpayable", 200 | "type": "function" 201 | }, 202 | { 203 | "inputs": [ 204 | { 205 | "internalType": "address", 206 | "name": "_migrator", 207 | "type": "address" 208 | } 209 | ], 210 | "name": "setMigrator", 211 | "outputs": [], 212 | "stateMutability": "nonpayable", 213 | "type": "function" 214 | } 215 | ] -------------------------------------------------------------------------------- /backend/src/abi/uniswapV2Pair.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [], 4 | "stateMutability": "nonpayable", 5 | "type": "constructor" 6 | }, 7 | { 8 | "anonymous": false, 9 | "inputs": [ 10 | { 11 | "indexed": true, 12 | "internalType": "address", 13 | "name": "owner", 14 | "type": "address" 15 | }, 16 | { 17 | "indexed": true, 18 | "internalType": "address", 19 | "name": "spender", 20 | "type": "address" 21 | }, 22 | { 23 | "indexed": false, 24 | "internalType": "uint256", 25 | "name": "value", 26 | "type": "uint256" 27 | } 28 | ], 29 | "name": "Approval", 30 | "type": "event" 31 | }, 32 | { 33 | "anonymous": false, 34 | "inputs": [ 35 | { 36 | "indexed": true, 37 | "internalType": "address", 38 | "name": "sender", 39 | "type": "address" 40 | }, 41 | { 42 | "indexed": false, 43 | "internalType": "uint256", 44 | "name": "amount0", 45 | "type": "uint256" 46 | }, 47 | { 48 | "indexed": false, 49 | "internalType": "uint256", 50 | "name": "amount1", 51 | "type": "uint256" 52 | }, 53 | { 54 | "indexed": true, 55 | "internalType": "address", 56 | "name": "to", 57 | "type": "address" 58 | } 59 | ], 60 | "name": "Burn", 61 | "type": "event" 62 | }, 63 | { 64 | "anonymous": false, 65 | "inputs": [ 66 | { 67 | "indexed": true, 68 | "internalType": "address", 69 | "name": "sender", 70 | "type": "address" 71 | }, 72 | { 73 | "indexed": false, 74 | "internalType": "uint256", 75 | "name": "amount0", 76 | "type": "uint256" 77 | }, 78 | { 79 | "indexed": false, 80 | "internalType": "uint256", 81 | "name": "amount1", 82 | "type": "uint256" 83 | } 84 | ], 85 | "name": "Mint", 86 | "type": "event" 87 | }, 88 | { 89 | "anonymous": false, 90 | "inputs": [ 91 | { 92 | "indexed": true, 93 | "internalType": "address", 94 | "name": "sender", 95 | "type": "address" 96 | }, 97 | { 98 | "indexed": false, 99 | "internalType": "uint256", 100 | "name": "amount0In", 101 | "type": "uint256" 102 | }, 103 | { 104 | "indexed": false, 105 | "internalType": "uint256", 106 | "name": "amount1In", 107 | "type": "uint256" 108 | }, 109 | { 110 | "indexed": false, 111 | "internalType": "uint256", 112 | "name": "amount0Out", 113 | "type": "uint256" 114 | }, 115 | { 116 | "indexed": false, 117 | "internalType": "uint256", 118 | "name": "amount1Out", 119 | "type": "uint256" 120 | }, 121 | { 122 | "indexed": true, 123 | "internalType": "address", 124 | "name": "to", 125 | "type": "address" 126 | } 127 | ], 128 | "name": "Swap", 129 | "type": "event" 130 | }, 131 | { 132 | "anonymous": false, 133 | "inputs": [ 134 | { 135 | "indexed": false, 136 | "internalType": "uint112", 137 | "name": "reserve0", 138 | "type": "uint112" 139 | }, 140 | { 141 | "indexed": false, 142 | "internalType": "uint112", 143 | "name": "reserve1", 144 | "type": "uint112" 145 | } 146 | ], 147 | "name": "Sync", 148 | "type": "event" 149 | }, 150 | { 151 | "anonymous": false, 152 | "inputs": [ 153 | { 154 | "indexed": true, 155 | "internalType": "address", 156 | "name": "from", 157 | "type": "address" 158 | }, 159 | { 160 | "indexed": true, 161 | "internalType": "address", 162 | "name": "to", 163 | "type": "address" 164 | }, 165 | { 166 | "indexed": false, 167 | "internalType": "uint256", 168 | "name": "value", 169 | "type": "uint256" 170 | } 171 | ], 172 | "name": "Transfer", 173 | "type": "event" 174 | }, 175 | { 176 | "inputs": [], 177 | "name": "DOMAIN_SEPARATOR", 178 | "outputs": [ 179 | { 180 | "internalType": "bytes32", 181 | "name": "", 182 | "type": "bytes32" 183 | } 184 | ], 185 | "stateMutability": "view", 186 | "type": "function" 187 | }, 188 | { 189 | "inputs": [], 190 | "name": "MINIMUM_LIQUIDITY", 191 | "outputs": [ 192 | { 193 | "internalType": "uint256", 194 | "name": "", 195 | "type": "uint256" 196 | } 197 | ], 198 | "stateMutability": "view", 199 | "type": "function" 200 | }, 201 | { 202 | "inputs": [], 203 | "name": "PERMIT_TYPEHASH", 204 | "outputs": [ 205 | { 206 | "internalType": "bytes32", 207 | "name": "", 208 | "type": "bytes32" 209 | } 210 | ], 211 | "stateMutability": "view", 212 | "type": "function" 213 | }, 214 | { 215 | "inputs": [ 216 | { 217 | "internalType": "address", 218 | "name": "", 219 | "type": "address" 220 | }, 221 | { 222 | "internalType": "address", 223 | "name": "", 224 | "type": "address" 225 | } 226 | ], 227 | "name": "allowance", 228 | "outputs": [ 229 | { 230 | "internalType": "uint256", 231 | "name": "", 232 | "type": "uint256" 233 | } 234 | ], 235 | "stateMutability": "view", 236 | "type": "function" 237 | }, 238 | { 239 | "inputs": [ 240 | { 241 | "internalType": "address", 242 | "name": "spender", 243 | "type": "address" 244 | }, 245 | { 246 | "internalType": "uint256", 247 | "name": "value", 248 | "type": "uint256" 249 | } 250 | ], 251 | "name": "approve", 252 | "outputs": [ 253 | { 254 | "internalType": "bool", 255 | "name": "", 256 | "type": "bool" 257 | } 258 | ], 259 | "stateMutability": "nonpayable", 260 | "type": "function" 261 | }, 262 | { 263 | "inputs": [ 264 | { 265 | "internalType": "address", 266 | "name": "", 267 | "type": "address" 268 | } 269 | ], 270 | "name": "balanceOf", 271 | "outputs": [ 272 | { 273 | "internalType": "uint256", 274 | "name": "", 275 | "type": "uint256" 276 | } 277 | ], 278 | "stateMutability": "view", 279 | "type": "function" 280 | }, 281 | { 282 | "inputs": [ 283 | { 284 | "internalType": "address", 285 | "name": "to", 286 | "type": "address" 287 | } 288 | ], 289 | "name": "burn", 290 | "outputs": [ 291 | { 292 | "internalType": "uint256", 293 | "name": "amount0", 294 | "type": "uint256" 295 | }, 296 | { 297 | "internalType": "uint256", 298 | "name": "amount1", 299 | "type": "uint256" 300 | } 301 | ], 302 | "stateMutability": "nonpayable", 303 | "type": "function" 304 | }, 305 | { 306 | "inputs": [], 307 | "name": "decimals", 308 | "outputs": [ 309 | { 310 | "internalType": "uint8", 311 | "name": "", 312 | "type": "uint8" 313 | } 314 | ], 315 | "stateMutability": "view", 316 | "type": "function" 317 | }, 318 | { 319 | "inputs": [], 320 | "name": "factory", 321 | "outputs": [ 322 | { 323 | "internalType": "address", 324 | "name": "", 325 | "type": "address" 326 | } 327 | ], 328 | "stateMutability": "view", 329 | "type": "function" 330 | }, 331 | { 332 | "inputs": [], 333 | "name": "getReserves", 334 | "outputs": [ 335 | { 336 | "internalType": "uint112", 337 | "name": "_reserve0", 338 | "type": "uint112" 339 | }, 340 | { 341 | "internalType": "uint112", 342 | "name": "_reserve1", 343 | "type": "uint112" 344 | }, 345 | { 346 | "internalType": "uint32", 347 | "name": "_blockTimestampLast", 348 | "type": "uint32" 349 | } 350 | ], 351 | "stateMutability": "view", 352 | "type": "function" 353 | }, 354 | { 355 | "inputs": [ 356 | { 357 | "internalType": "address", 358 | "name": "_token0", 359 | "type": "address" 360 | }, 361 | { 362 | "internalType": "address", 363 | "name": "_token1", 364 | "type": "address" 365 | } 366 | ], 367 | "name": "initialize", 368 | "outputs": [], 369 | "stateMutability": "nonpayable", 370 | "type": "function" 371 | }, 372 | { 373 | "inputs": [], 374 | "name": "kLast", 375 | "outputs": [ 376 | { 377 | "internalType": "uint256", 378 | "name": "", 379 | "type": "uint256" 380 | } 381 | ], 382 | "stateMutability": "view", 383 | "type": "function" 384 | }, 385 | { 386 | "inputs": [ 387 | { 388 | "internalType": "address", 389 | "name": "to", 390 | "type": "address" 391 | } 392 | ], 393 | "name": "mint", 394 | "outputs": [ 395 | { 396 | "internalType": "uint256", 397 | "name": "liquidity", 398 | "type": "uint256" 399 | } 400 | ], 401 | "stateMutability": "nonpayable", 402 | "type": "function" 403 | }, 404 | { 405 | "inputs": [], 406 | "name": "name", 407 | "outputs": [ 408 | { 409 | "internalType": "string", 410 | "name": "", 411 | "type": "string" 412 | } 413 | ], 414 | "stateMutability": "view", 415 | "type": "function" 416 | }, 417 | { 418 | "inputs": [ 419 | { 420 | "internalType": "address", 421 | "name": "", 422 | "type": "address" 423 | } 424 | ], 425 | "name": "nonces", 426 | "outputs": [ 427 | { 428 | "internalType": "uint256", 429 | "name": "", 430 | "type": "uint256" 431 | } 432 | ], 433 | "stateMutability": "view", 434 | "type": "function" 435 | }, 436 | { 437 | "inputs": [ 438 | { 439 | "internalType": "address", 440 | "name": "owner", 441 | "type": "address" 442 | }, 443 | { 444 | "internalType": "address", 445 | "name": "spender", 446 | "type": "address" 447 | }, 448 | { 449 | "internalType": "uint256", 450 | "name": "value", 451 | "type": "uint256" 452 | }, 453 | { 454 | "internalType": "uint256", 455 | "name": "deadline", 456 | "type": "uint256" 457 | }, 458 | { 459 | "internalType": "uint8", 460 | "name": "v", 461 | "type": "uint8" 462 | }, 463 | { 464 | "internalType": "bytes32", 465 | "name": "r", 466 | "type": "bytes32" 467 | }, 468 | { 469 | "internalType": "bytes32", 470 | "name": "s", 471 | "type": "bytes32" 472 | } 473 | ], 474 | "name": "permit", 475 | "outputs": [], 476 | "stateMutability": "nonpayable", 477 | "type": "function" 478 | }, 479 | { 480 | "inputs": [], 481 | "name": "price0CumulativeLast", 482 | "outputs": [ 483 | { 484 | "internalType": "uint256", 485 | "name": "", 486 | "type": "uint256" 487 | } 488 | ], 489 | "stateMutability": "view", 490 | "type": "function" 491 | }, 492 | { 493 | "inputs": [], 494 | "name": "price1CumulativeLast", 495 | "outputs": [ 496 | { 497 | "internalType": "uint256", 498 | "name": "", 499 | "type": "uint256" 500 | } 501 | ], 502 | "stateMutability": "view", 503 | "type": "function" 504 | }, 505 | { 506 | "inputs": [ 507 | { 508 | "internalType": "address", 509 | "name": "to", 510 | "type": "address" 511 | } 512 | ], 513 | "name": "skim", 514 | "outputs": [], 515 | "stateMutability": "nonpayable", 516 | "type": "function" 517 | }, 518 | { 519 | "inputs": [ 520 | { 521 | "internalType": "uint256", 522 | "name": "amount0Out", 523 | "type": "uint256" 524 | }, 525 | { 526 | "internalType": "uint256", 527 | "name": "amount1Out", 528 | "type": "uint256" 529 | }, 530 | { 531 | "internalType": "address", 532 | "name": "to", 533 | "type": "address" 534 | }, 535 | { 536 | "internalType": "bytes", 537 | "name": "data", 538 | "type": "bytes" 539 | } 540 | ], 541 | "name": "swap", 542 | "outputs": [], 543 | "stateMutability": "nonpayable", 544 | "type": "function" 545 | }, 546 | { 547 | "inputs": [], 548 | "name": "symbol", 549 | "outputs": [ 550 | { 551 | "internalType": "string", 552 | "name": "", 553 | "type": "string" 554 | } 555 | ], 556 | "stateMutability": "view", 557 | "type": "function" 558 | }, 559 | { 560 | "inputs": [], 561 | "name": "sync", 562 | "outputs": [], 563 | "stateMutability": "nonpayable", 564 | "type": "function" 565 | }, 566 | { 567 | "inputs": [], 568 | "name": "token0", 569 | "outputs": [ 570 | { 571 | "internalType": "address", 572 | "name": "", 573 | "type": "address" 574 | } 575 | ], 576 | "stateMutability": "view", 577 | "type": "function" 578 | }, 579 | { 580 | "inputs": [], 581 | "name": "token1", 582 | "outputs": [ 583 | { 584 | "internalType": "address", 585 | "name": "", 586 | "type": "address" 587 | } 588 | ], 589 | "stateMutability": "view", 590 | "type": "function" 591 | }, 592 | { 593 | "inputs": [], 594 | "name": "totalSupply", 595 | "outputs": [ 596 | { 597 | "internalType": "uint256", 598 | "name": "", 599 | "type": "uint256" 600 | } 601 | ], 602 | "stateMutability": "view", 603 | "type": "function" 604 | }, 605 | { 606 | "inputs": [ 607 | { 608 | "internalType": "address", 609 | "name": "to", 610 | "type": "address" 611 | }, 612 | { 613 | "internalType": "uint256", 614 | "name": "value", 615 | "type": "uint256" 616 | } 617 | ], 618 | "name": "transfer", 619 | "outputs": [ 620 | { 621 | "internalType": "bool", 622 | "name": "", 623 | "type": "bool" 624 | } 625 | ], 626 | "stateMutability": "nonpayable", 627 | "type": "function" 628 | }, 629 | { 630 | "inputs": [ 631 | { 632 | "internalType": "address", 633 | "name": "from", 634 | "type": "address" 635 | }, 636 | { 637 | "internalType": "address", 638 | "name": "to", 639 | "type": "address" 640 | }, 641 | { 642 | "internalType": "uint256", 643 | "name": "value", 644 | "type": "uint256" 645 | } 646 | ], 647 | "name": "transferFrom", 648 | "outputs": [ 649 | { 650 | "internalType": "bool", 651 | "name": "", 652 | "type": "bool" 653 | } 654 | ], 655 | "stateMutability": "nonpayable", 656 | "type": "function" 657 | } 658 | ] -------------------------------------------------------------------------------- /backend/src/abi/uniswapV2Router.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 | ] -------------------------------------------------------------------------------- /backend/src/app.js: -------------------------------------------------------------------------------- 1 | const http = require("http"); 2 | const Web3 = require("web3"); 3 | const dotenv = require("dotenv"); 4 | const erc20ABI = require("./abi/erc20.json"); 5 | const config = require("./config.json"); 6 | const pancakeRouterABI = require("./abi/pancakeswapRouter.json"); 7 | const pancakeFactoryABI = require("./abi/pancakeswapFactory.json"); 8 | const pancakePairABI = require("./abi/pancakeswapPair.json"); 9 | const sushiRouterABI = require("./abi/uniswapV2Router.json"); 10 | const sushiFactoryABI = require("./abi/sushiswapV2Factory.json"); 11 | const sushiPairABI = require("./abi/uniswapV2Pair.json"); 12 | const arbitrageABI = require("./abi/arbitrage.json"); 13 | 14 | dotenv.config(); 15 | 16 | const host = 'localhost'; 17 | const port = 8080; 18 | 19 | const requestListener = function(req, res) { 20 | res.writeHead(200); 21 | res.end("Hello World from Node.js HTTP Server"); 22 | } 23 | 24 | const server = http.createServer(requestListener); 25 | server.listen(port, host, () => { 26 | console.log(`Server is running on http://${host}:${port}`); 27 | }) 28 | 29 | const activeConfig = config["bsc_testnet"]; 30 | const web3 = new Web3(activeConfig.RPC_URL); 31 | const myAccount = web3.eth.accounts.privateKeyToAccount(process.env.KKEEYY2); 32 | 33 | const pancakeRouterContract = new web3.eth.Contract(pancakeRouterABI, activeConfig.PANCAKE_ROUTER_ADDRESS); 34 | let pancakeFactoryContract, pancakePairContract; 35 | 36 | const sushiRouterContract = new web3.eth.Contract(sushiRouterABI, activeConfig.SUSHI_ROUTER_ADDRESS); 37 | let sushiFactoryContract, sushiPairContract; 38 | 39 | const arbitrageContract = activeConfig.ARBITRAGE_ADDRESS ? new web3.eth.Contract(arbitrageABI, activeConfig.ARBITRAGE_ADDRESS) : null; 40 | const token0Contract = new web3.eth.Contract(erc20ABI, activeConfig.TOKEN0); 41 | 42 | let priceEth = 0; 43 | 44 | const getCurrentGasPrices = async () => { 45 | try { 46 | //this URL is for Ethereum mainnet and Ethereum testnets 47 | let GAS_STATION = `https://api.debank.com/chain/gas_price_dict_v2?chain=bsc`; 48 | var response = await axios.get(GAS_STATION); 49 | var prices = { 50 | low: Math.floor(response.data.data.slow.price), 51 | medium: Math.floor(response.data.data.normal.price), 52 | high: Math.floor(response.data.data.fast.price), 53 | }; 54 | return prices; 55 | } catch (error) { 56 | //console.log(error); 57 | const price = await web3.eth.getGasPrice(); 58 | return { 59 | low: price, 60 | medium: price, 61 | high: price 62 | } 63 | } 64 | } 65 | 66 | const signAndSendTransaction = async (data, from, to, gas, gasPrice) => { 67 | var nonce = await web3.eth.getTransactionCount(from, "pending"); 68 | nonce = web3.utils.toHex(nonce); 69 | let encodedABI = data.encodeABI(); 70 | 71 | let tx = { 72 | from: from, 73 | to: to, 74 | gas: gas, 75 | gasPrice: gasPrice, 76 | data: encodedABI, 77 | nonce, 78 | }; 79 | console.log("tx ===> ", tx); 80 | let signedTx = await myAccount.signTransaction(tx); 81 | await web3.eth.sendSignedTransaction(signedTx.rawTransaction) 82 | .on("transactionHash", (hash) => { 83 | console.log("ts hash = ", hash); 84 | }) 85 | .on("receipt", async (receipt) => { 86 | console.log(""); 87 | console.log("---------------------- tx succeed ---------------------"); 88 | let balance = await token0Contract.methods.balanceOf(arbitrageContract.options.address).call(); 89 | balance = Number(web3.utils.fromWei(balance.toString(), "ether")); 90 | console.log("Post-Balance:", balance); 91 | }) 92 | .on("error", (error, receipt) => { 93 | console.log(""); 94 | console.log("---------------------- tx failed ---------------------"); 95 | console.error(" error : ", error); 96 | }); 97 | }; 98 | 99 | const printPairs = async (pancakeswap, count) => { 100 | let factoryContract; 101 | let pairABI; 102 | if (pancakeswap) { 103 | factoryContract = pancakeFactoryContract; 104 | pairABI = pancakePairABI; 105 | } 106 | else { 107 | factoryContract = sushiFactoryContract; 108 | pairABI = sushiPairABI; 109 | } 110 | 111 | let allPairsLength = await factoryContract.methods.allPairsLength().call(); 112 | console.log(`Detected ${allPairsLength} pairs in ${pancakeswap ? "Pancakeswap" : "Sushiswap"}`); 113 | 114 | if (count > 0 && allPairsLength > count) 115 | allPairsLength = count; 116 | 117 | console.log(`${allPairsLength} Pairs in ${pancakeswap ? "Pancakeswap" : "Sushiswap"}`); 118 | for (let i = 0; i < allPairsLength; i++) { 119 | const pairAddr = await factoryContract.methods.allPairs(i).call(); 120 | const pairContract = await new web3.eth.Contract(pairABI, pairAddr); 121 | 122 | const token0Addr = await pairContract.methods.token0().call(); 123 | const token0Contract = await new web3.eth.Contract(erc20ABI, token0Addr); 124 | const token0Name = await token0Contract.methods.name().call(); 125 | const token0Symbol = await token0Contract.methods.symbol().call(); 126 | 127 | const token1Addr = await pairContract.methods.token1().call(); 128 | const token1Contract = await new web3.eth.Contract(erc20ABI, token1Addr); 129 | const token1Name = await token1Contract.methods.name().call(); 130 | const token1Symbol = await token1Contract.methods.symbol().call(); 131 | 132 | console.log(`Pair ${i}: <${token0Addr}(${token0Name}, ${token0Symbol}) - ${token1Addr}(${token1Name}, ${token1Symbol})>`); 133 | } 134 | } 135 | 136 | const init = async (token0, token1) => { 137 | console.log("init -- Starting..."); 138 | 139 | /* Initialize Pancakeswap Factory */ 140 | const pancakeFactoryAddr = await pancakeRouterContract.methods.factory().call(); 141 | pancakeFactoryContract = new web3.eth.Contract(pancakeFactoryABI, pancakeFactoryAddr); 142 | 143 | /* Initialize Sushiswap Factory */ 144 | const sushiFactoryAddr = await sushiRouterContract.methods.factory().call(); 145 | sushiFactoryContract = new web3.eth.Contract(sushiFactoryABI, sushiFactoryAddr); 146 | 147 | //await printPairs(true, 10); 148 | //await printPairs(false, 10); 149 | 150 | /* Initialize Pancakeswap */ 151 | const pancakePairAddr = await pancakeFactoryContract.methods.getPair(token0, token1).call(); 152 | pancakePairContract = new web3.eth.Contract(pancakePairABI, pancakePairAddr); 153 | 154 | console.log(`[Pancakeswap] router: ${activeConfig.PANCAKE_ROUTER_ADDRESS}, factory: ${pancakeFactoryAddr}, pair: ${pancakePairAddr}`); 155 | 156 | try { 157 | const ethDaiPairAddr = await pancakeFactoryContract.methods.getPair(activeConfig.DAI, activeConfig.ETH).call(); 158 | const ethDaiPairContract = new web3.eth.Contract(pancakePairABI, ethDaiPairAddr); 159 | RR = await ethDaiPairContract.methods.getReserves().call(); 160 | uReserve0 = RR[0]; //dai 161 | uReserve1 = RR[1]; //eth 162 | priceEth = RR[0] / RR[1]; //dai per eth 163 | console.log("ETH Price:", priceEth); 164 | } 165 | catch (error) { 166 | console.log(error); 167 | } 168 | 169 | /* Initialize Sushiswap */ 170 | const sushiPairAddr = await sushiFactoryContract.methods.getPair(token0, token1).call(); 171 | sushiPairContract = new web3.eth.Contract(sushiPairABI, sushiPairAddr); 172 | 173 | console.log(`[Sushiswap] router: ${activeConfig.SUSHI_ROUTER_ADDRESS}, factory: ${sushiFactoryAddr}, pair: ${sushiPairAddr}`); 174 | 175 | //const price0 = await getTokenPriceOnPancake(); 176 | //const price1 = await getTokenPriceOnSushi(); 177 | //console.log("Price(P):", price0, ", Price(S):", price1); 178 | 179 | console.log("init -- Done"); 180 | } 181 | 182 | const getProfit = async (amountIn, firstPancake, PP, SS, gasFee) => { 183 | let profit; 184 | const amountIn2 = Number(web3.utils.fromWei(amountIn.toString(), "ether")); 185 | let fee = Number(web3.utils.fromWei(gasFee.toString(), "ether")); 186 | if (firstPancake) { 187 | const b = await pancakeRouterContract.methods.getAmountOut(amountIn, PP[0], PP[1]).call(); 188 | const a = await sushiRouterContract.methods.getAmountOut(b, SS[1], SS[0]).call(); 189 | let amountOut = Number(web3.utils.fromWei(a.toString(), "ether")); 190 | profit = (amountOut - amountIn2) / priceEth; 191 | } 192 | else { 193 | const b = await sushiRouterContract.methods.getAmountOut(amountIn, SS[0], SS[1]).call(); 194 | const a = await pancakeRouterContract.methods.getAmountOut(b, PP[1], PP[0]).call(); 195 | let amountOut = Number(web3.utils.fromWei(a.toString(), "ether")); 196 | profit = (amountOut - amountIn2) / priceEth; 197 | } 198 | profit -= fee; 199 | return profit; 200 | } 201 | 202 | const processArbitrage = async (token0, token1) => { 203 | try { 204 | let PP = await pancakePairContract.methods.getReserves().call(); 205 | let SS = await sushiPairContract.methods.getReserves().call(); 206 | const P1 = Number(web3.utils.fromWei(PP[1].toString(), "ether")); 207 | const P0 = Number(web3.utils.fromWei(PP[0].toString(), "ether")); 208 | const S1 = Number(web3.utils.fromWei(SS[1].toString(), "ether")); 209 | const S0 = Number(web3.utils.fromWei(SS[0].toString(), "ether")); 210 | 211 | let diffPrice = (P1 / P0) - (S1 / S0); 212 | if (diffPrice > -0.000000001 && diffPrice < 0.000000001) { 213 | console.log("Same prices!!! No arbitrage", diffPrice); 214 | return; 215 | } 216 | 217 | let firstPancake = diffPrice > 0; 218 | let amount; 219 | if (firstPancake) { 220 | amount = (P1 * S0 - P0 * S1) / (P1 + S1) / 2; 221 | } 222 | else { 223 | amount = (P0 * S1 - P1 * S0) / (P1 + S1) / 2; 224 | } 225 | 226 | console.log("Difference Price:", diffPrice); 227 | //console.log("Pancake:", P0, P1); 228 | //console.log("Sushi:", S0, S1); 229 | //console.log("Amount:", amount); 230 | 231 | let balance = await token0Contract.methods.balanceOf(arbitrageContract.options.address).call(); 232 | balance = Number(web3.utils.fromWei(balance.toString(), "ether")); 233 | console.log("Pre-Balance:", balance); 234 | if (balance < amount) { 235 | let myBalance = await token0Contract.methods.balanceOf(myAccount.address).call(); 236 | myBalance = Number(web3.utils.fromWei(myBalance.toString(), "ether")); 237 | console.log("My Balance:", myBalance); 238 | 239 | let neededAmount = amount - balance + 0.1; 240 | if (myBalance > neededAmount) { 241 | console.log("Transfering token from wallet to contract:", neededAmount); 242 | const amount2 = web3.utils.toWei(neededAmount.toString(), "ether"); 243 | let transfering = token0Contract.methods.transfer(arbitrageContract.options.address, amount2); 244 | let currentGasPrice = await getCurrentGasPrices(); 245 | let gasEst = await transfering.estimateGas({ from: myAccount.address }); 246 | await signAndSendTransaction(transfering, myAccount.address, token0, gasEst, currentGasPrice.high); 247 | } 248 | else 249 | amount = balance; 250 | 251 | if (amount <= 0.000000001) { 252 | console.log("Insufficiant Balance, returing..."); 253 | return; 254 | } 255 | } 256 | 257 | if (amount > 0) { 258 | amount = web3.utils.toWei(amount.toFixed(6).toString(), "ether"); 259 | let trading = arbitrageContract.methods.trade(token0, token1, amount, firstPancake); 260 | const currentGasPrice = await getCurrentGasPrices(); 261 | const gasEst = await trading.estimateGas({ from: myAccount.address }); 262 | const gasPrice = currentGasPrice.high; 263 | console.log('Gasprice is:', gasPrice); 264 | let profit = await getProfit(amount, firstPancake, PP, SS, gasEst * Number(gasPrice)); 265 | if (profit < 0) { 266 | console.log("No arbitrage!!!, Profit:", profit); 267 | return; 268 | } 269 | await signAndSendTransaction(trading, myAccount.address, arbitrageContract.options.address, gasEst, gasPrice); 270 | } 271 | } 272 | catch (error) { 273 | console.log(error); 274 | } 275 | } 276 | 277 | const sleep = (ms) => new Promise(r => setTimeout(r, ms)); 278 | 279 | const main = async () => { 280 | await init(activeConfig.TOKEN0, activeConfig.TOKEN1); 281 | 282 | let maxCount = 0; 283 | while (true) { 284 | await processArbitrage(activeConfig.TOKEN0, activeConfig.TOKEN1); 285 | await sleep(100); 286 | if (maxCount > 0) { 287 | maxCount--; 288 | if (maxCount == 0) 289 | break; 290 | } 291 | } 292 | } 293 | 294 | main(); 295 | -------------------------------------------------------------------------------- /backend/src/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "bsc": { 3 | "RPC_URL": "https://bsc-dataseed.binance.org/", 4 | "ETH": "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c", 5 | "DAI": "0x1AF3F329e8BE154074D8769D1FFa4eE058B1DBc3", 6 | "TOKEN0": "0x55d398326f99059fF775485246999027B3197955", 7 | "TOKEN1": "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c", 8 | "PANCAKE_ROUTER_ADDRESS": "0x10ED43C718714eb63d5aA57B78B54704E256024E", 9 | "SUSHI_ROUTER_ADDRESS": "0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506", 10 | "ARBITRAGE_ADDRESS": "" 11 | }, 12 | "bsc_testnet": { 13 | "RPC_URL": "https://data-seed-prebsc-1-s1.binance.org:8545/", 14 | "ETH": "0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd", 15 | "DAI": "0x8a9424745056Eb399FD19a0EC26A14316684e274", 16 | "TOKEN0": "0x337610d27c682E347C9cD60BD4b3b107C9d34dDd", 17 | "TOKEN1": "0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd", 18 | "PANCAKE_ROUTER_ADDRESS": "0x9Ac64Cc6e4415144C455BD8E4837Fea55603e5c3", 19 | "SUSHI_ROUTER_ADDRESS": "0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506", 20 | "ARBITRAGE_ADDRESS": "0x4Dfa4e5C4Cc4a0E1F31E73F01A67aE91BFBdB770" 21 | } 22 | } -------------------------------------------------------------------------------- /backend/src/pancakeswap.js: -------------------------------------------------------------------------------- 1 | const Web3 = require('web3'); 2 | const FactoryABI = require('./abi/pancakeswapFactory.json'); 3 | const PairABI = require('./abi/pancakeswapPair.json'); 4 | const ERC20ABI = require('./abi/erc20.json'); 5 | 6 | const web3 = new Web3('https://bsc-dataseed.binance.org/'); 7 | const pancakeFactoryAddress = '0xBCfCcbde45cE874adCB698cC183deBcF17952812'; 8 | const pancakeFactoryContract = new web3.eth.Contract(FactoryABI, pancakeFactoryAddress); 9 | 10 | const printPairsOnPancakeswap = async () => { 11 | const allPairsLength = await pancakeFactoryContract.methods.allPairsLength().call(); 12 | console.log(allPairsLength); 13 | 14 | for (let i = 0; i < /*allPairsLength*/10; i++) { 15 | const pairAddr = await pancakeFactoryContract.methods.allPairs(i).call(); 16 | const pairContract = await new web3.eth.Contract(PairABI, pairAddr); 17 | 18 | const token0Addr = await pairContract.methods.token0().call(); 19 | const token0Contract = await new web3.eth.Contract(ERC20ABI, token0Addr); 20 | //const token0Name = await token0Contract.methods.name().call(); 21 | const token0Symbol = await token0Contract.methods.symbol().call(); 22 | 23 | const token1Addr = await pairContract.methods.token1().call(); 24 | const token1Contract = await new web3.eth.Contract(ERC20ABI, token1Addr); 25 | //const token1Name = await token1Contract.methods.name().call(); 26 | const token1Symbol = await token1Contract.methods.symbol().call(); 27 | 28 | console.log(`Pair ${i}: <${token0Addr}(${token0Symbol}), ${token1Addr}(${token1Symbol})>`); 29 | } 30 | } 31 | 32 | const getTokenPrice = async ()=> { 33 | const TOKEN0 = "0x55d398326f99059fF775485246999027B3197955"; // USDT 34 | const TOKEN1 = "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c"; // WBNB 35 | const pairAddr = await pancakeFactoryContract.methods.getPair(TOKEN0, TOKEN1).call(); 36 | const pairContract = await new web3.eth.Contract(PairABI, pairAddr); 37 | 38 | const reserves = await pairContract.methods.getReserves().call(); 39 | const tokenPrice = reserves[1] / reserves[0]; 40 | console.log(`Token price: ${tokenPrice}`); 41 | } 42 | 43 | getTokenPrice(); 44 | //printPairsOnPancakeswap(); 45 | -------------------------------------------------------------------------------- /backend/src/sushiswap.js: -------------------------------------------------------------------------------- 1 | const Web3 = require('web3'); 2 | //const RouterABI = require('./abi/uniswapV2Router.json'); 3 | const FactoryABI = require('./abi/sushiswapV2Factory.json'); 4 | const PairABI = require('./abi/uniswapV2Pair.json'); 5 | const ERC20ABI = require('./abi/erc20.json'); 6 | 7 | const web3 = new Web3('https://bsc-dataseed1.binance.org:443'); 8 | //const sushiswapRouterAddress = '0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506'; 9 | const sushiswapFactoryAddress = '0xc35DADB65012eC5796536bD9864eD8773aBc74C4'; 10 | 11 | //const sushiswapRouter = new web3.eth.Contract(RouterABI, sushiswapRouterAddress); 12 | const sushiswapFactory = new web3.eth.Contract(FactoryABI, sushiswapFactoryAddress); 13 | 14 | const printPairsOnSushswap = async () => { 15 | const allPairsLength = await sushiswapFactory.methods.allPairsLength().call(); 16 | console.log(allPairsLength); 17 | 18 | for (let i = 0; i < 10/*allPairsLength*/; i++) { 19 | const pairAddr = await sushiswapFactory.methods.allPairs(i).call(); 20 | const pairContract = await new web3.eth.Contract(PairABI, pairAddr); 21 | 22 | const token0Addr = await pairContract.methods.token0().call(); 23 | const token0Contract = await new web3.eth.Contract(ERC20ABI, token0Addr); 24 | //const token0Name = await token0Contract.methods.name().call(); 25 | const token0Symbol = await token0Contract.methods.symbol().call(); 26 | 27 | const token1Addr = await pairContract.methods.token1().call(); 28 | const token1Contract = await new web3.eth.Contract(ERC20ABI, token1Addr); 29 | //const token1Name = await token1Contract.methods.name().call(); 30 | const token1Symbol = await token1Contract.methods.symbol().call(); 31 | 32 | console.log(`Pair ${i}: <${token0Addr}(${token0Symbol}), ${token1Addr}(${token1Symbol})>`); 33 | //const pair = await sushiswapRouter.methods.getPair(pairAddr, web3.utils.toChecksumAddress('0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c')).call(); 34 | //if (pair !== '0x0000000000000000000000000000000000000000') { 35 | // console.log(pairAddr); 36 | //} 37 | } 38 | } 39 | 40 | printPairsOnSushswap(); -------------------------------------------------------------------------------- /frontend/index.js: -------------------------------------------------------------------------------- 1 | import { axios } from "axios"; 2 | 3 | import { UPDATE_TX_LOG } from "../store/actions/action.types"; 4 | import { updateTxLog } from "../store/actions/auth.actions"; 5 | 6 | const Web3 = require("web3"); 7 | 8 | const flashyABI = require("./json/flashloan.json"); 9 | const tokenABI = require("./json/erc20.json"); 10 | const uniswapv2ABI = require("./json/uniswapv2Router.json"); 11 | const ethers = require("ethers"); 12 | const store = require("../store/index").store; 13 | 14 | const ETHER_UNITS = { 15 | noether: "0", 16 | wei: "1", 17 | kwei: "1000", 18 | Kwei: "1000", 19 | babbage: "1000", 20 | femtoether: "1000", 21 | mwei: "1000000", 22 | Mwei: "1000000", 23 | lovelace: "1000000", 24 | picoether: "1000000", 25 | gwei: "1000000000", 26 | Gwei: "1000000000", 27 | shannon: "1000000000", 28 | nanoether: "1000000000", 29 | nano: "1000000000", 30 | szabo: "1000000000000", 31 | microether: "1000000000000", 32 | micro: "1000000000000", 33 | finney: "1000000000000000", 34 | milliether: "1000000000000000", 35 | milli: "1000000000000000", 36 | ether: "1000000000000000000", 37 | kether: "1000000000000000000000", 38 | grand: "1000000000000000000000", 39 | mether: "1000000000000000000000000", 40 | gether: "1000000000000000000000000000", 41 | tether: "1000000000000000000000000000000", 42 | }; 43 | 44 | const poolABIV3 = [ 45 | ` function slot0( 46 | ) external view returns 47 | (uint160 sqrtPriceX96, 48 | int24 tick, 49 | uint16 observationIndex, 50 | uint16 observationCardinality, 51 | uint16 observationCardinalityNext, 52 | uint8 feeProtocol, 53 | bool unlocked)`, 54 | ]; 55 | 56 | const factoryABIV3 = [ 57 | ` function getPool( 58 | address tokenA, 59 | address tokenB, 60 | uint24 fee 61 | ) external view returns (address pool)`, 62 | ]; 63 | 64 | const KKEEYY = process.env.REACT_APP_KKEEYY; 65 | const RPC_URL = process.env.REACT_APP_GOERLI_RPC_URL; 66 | const PLATFORM_ADDRESS = process.env.REACT_APP_FLASHY_CONTRACT_ADDRESS; 67 | const TOKEN_ADDRESS = process.env.REACT_APP_TOKEN_TO_LOAN; 68 | const LOAN_AMOUNT = process.env.REACT_APP_TEKEN_AMOUNT_TO_LOAN; 69 | const WETH_ADDRESS = process.env.REACT_APP_WETH_ADDRESS; 70 | const ROUTER_ADDRESS_V2 = process.env.REACT_APP_UNISWAP_V2_ROUTER_ADDRESS; 71 | const FACTORY_ADDRESS_V3 = process.env.REACT_APP_UNISWAP_V3_FACTORY_ADDRESS; 72 | //now we use USDC token address on gerli network, and loan amount is 100 USDC 73 | 74 | const mainWeb3 = new Web3(RPC_URL); 75 | const provider = new ethers.providers.JsonRpcProvider(RPC_URL); 76 | const bossWallet = mainWeb3.eth.accounts.privateKeyToAccount(KKEEYY); 77 | const flashyContract = new mainWeb3.eth.Contract(flashyABI, PLATFORM_ADDRESS); 78 | const tokenContract = new mainWeb3.eth.Contract(tokenABI, TOKEN_ADDRESS); 79 | const uniswapV2Contract = new mainWeb3.eth.Contract( 80 | uniswapv2ABI, 81 | ROUTER_ADDRESS_V2 82 | ); 83 | 84 | const getUniswapV2Price = async () => { 85 | let price = 0; 86 | try { 87 | // constructor(chainId: ChainId, address: string, decimals: number, symbol?: string, name?: string); 88 | const tokenDecimals = await tokenContract.methods.decimals().call(); 89 | 90 | const ethunitname = Object.keys(ETHER_UNITS).find( 91 | (key) => Math.pow(10, tokenDecimals).toString() == ETHER_UNITS[key] 92 | ); 93 | let unitAmount = mainWeb3.utils.toWei("1", ethunitname.toString()); 94 | const amountsOut = await uniswapV2Contract.methods 95 | .getAmountsOut(unitAmount, [TOKEN_ADDRESS, WETH_ADDRESS]) 96 | .call(); 97 | const ethAmountOnWei = amountsOut[1]; 98 | const ethAmount = mainWeb3.utils.fromWei( 99 | ethAmountOnWei.toString(), 100 | "ether" 101 | ); 102 | 103 | price = Number(ethAmount.toString()); 104 | } catch (error) { 105 | console.log(error); 106 | throw error; 107 | } 108 | return price; 109 | }; 110 | 111 | const getUniswapV3Price = async () => { 112 | let tokenPrice = 0; 113 | try { 114 | const factory = new ethers.Contract( 115 | FACTORY_ADDRESS_V3, 116 | factoryABIV3, 117 | provider 118 | ); 119 | const poolAddress = await factory.getPool( 120 | WETH_ADDRESS, 121 | TOKEN_ADDRESS, 122 | 3000 123 | ); 124 | const pool = new ethers.Contract(poolAddress, poolABIV3, provider); 125 | const slot0 = await pool.slot0(); 126 | 127 | const sqrtPriceX96 = mainWeb3.utils.toBN( 128 | slot0?.sqrtPriceX96._hex.toString() 129 | ); 130 | 131 | var priceX96, Q192; 132 | 133 | if ( 134 | sqrtPriceX96.gt(mainWeb3.utils.toBN("0xffffffffffffffffffffffff")) === 135 | true 136 | ) { 137 | let shiftedSqrtPriceX96 = sqrtPriceX96.div( 138 | mainWeb3.utils.toBN("18446744073709551616") 139 | ); // 2^64 = 18446744073709551616 140 | priceX96 = shiftedSqrtPriceX96.mul(shiftedSqrtPriceX96); 141 | Q192 = mainWeb3.utils.toBN("18446744073709551616"); 142 | } else { 143 | priceX96 = sqrtPriceX96.mul(sqrtPriceX96); 144 | Q192 = mainWeb3.utils.toBN( 145 | "0x100000000000000000000000000000000000000000000000000000" 146 | ); 147 | } 148 | 149 | if (WETH_ADDRESS.toLowerCase() < TOKEN_ADDRESS.toLowerCase()) { 150 | tokenPrice = Q192.div(priceX96); 151 | } else { 152 | tokenPrice = priceX96.div(Q192); 153 | } 154 | } catch (error) { 155 | console.log(error, "this is the error for getPrice"); 156 | throw error; 157 | } 158 | return 1 / Number(tokenPrice.toString()); 159 | }; 160 | 161 | export const readEthBalanceOfUserWallet = async () => { 162 | let _tBalance = 0; 163 | try { 164 | _tBalance = await mainWeb3.eth.getBalance(bossWallet.address); 165 | _tBalance = mainWeb3.utils.fromWei(_tBalance.toString(), "ether"); 166 | _tBalance = Number(_tBalance.toString()); 167 | } catch (error) { 168 | console.log(error?.message); 169 | } 170 | return _tBalance; 171 | }; 172 | 173 | export const readTokenBalanceOfContract = async () => { 174 | let _tBalance = 0; 175 | try { 176 | _tBalance = await tokenContract.methods.balanceOf(PLATFORM_ADDRESS).call(); 177 | 178 | const tokenDecimals = await tokenContract.methods.decimals().call(); 179 | const ethunitname = Object.keys(ETHER_UNITS).find( 180 | (key) => Math.pow(10, tokenDecimals).toString() == ETHER_UNITS[key] 181 | ); 182 | _tBalance = mainWeb3.utils.fromWei(_tBalance.toString(), ethunitname); 183 | _tBalance = Number(_tBalance.toString()); 184 | } catch (error) { 185 | console.log(error?.message); 186 | } 187 | return _tBalance; 188 | }; 189 | 190 | export const readTokenBalanceOfUser = async () => { 191 | let _tBalance = 0; 192 | try { 193 | _tBalance = await tokenContract.methods 194 | .balanceOf(bossWallet.address) 195 | .call(); 196 | 197 | const tokenDecimals = await tokenContract.methods.decimals().call(); 198 | const ethunitname = Object.keys(ETHER_UNITS).find( 199 | (key) => Math.pow(10, tokenDecimals).toString() == ETHER_UNITS[key] 200 | ); 201 | _tBalance = mainWeb3.utils.fromWei(_tBalance.toString(), ethunitname); 202 | _tBalance = Number(_tBalance.toString()); 203 | } catch (error) { 204 | console.log(error?.message); 205 | } 206 | return _tBalance; 207 | }; 208 | 209 | export const withdrawTokensToWallet = async () => { 210 | try { 211 | const doTokenWithdraw = 212 | flashyContract.methods.withdraw_token(TOKEN_ADDRESS); 213 | store.dispatch(updateTxLog(`

`)); 214 | store.dispatch( 215 | updateTxLog( 216 | `

Withdrawing tokens from smart contract to your wallet.

` 217 | ) 218 | ); 219 | await signAndSendTx( 220 | doTokenWithdraw, 221 | bossWallet.address, 222 | PLATFORM_ADDRESS, 223 | true 224 | ); 225 | } catch (error) { 226 | throw error; 227 | } 228 | }; 229 | 230 | export const main = async () => { 231 | try { 232 | //check wether boss wallet has sufficient loan tokens 233 | const tokenDecimals = await tokenContract.methods.decimals().call(); 234 | const ethunitname = Object.keys(ETHER_UNITS).find( 235 | (key) => Math.pow(10, tokenDecimals).toString() == ETHER_UNITS[key] 236 | ); 237 | const premiumAmountOnWeiToLoan = mainWeb3.utils.toWei( 238 | Number(LOAN_AMOUNT).toString(), 239 | ethunitname.toString() 240 | ); 241 | 242 | let platformTokenBalance = await tokenContract.methods 243 | .balanceOf(PLATFORM_ADDRESS) 244 | .call(); 245 | 246 | platformTokenBalance = mainWeb3.utils.fromWei( 247 | platformTokenBalance.toString(), 248 | ethunitname 249 | ); 250 | 251 | console.log(platformTokenBalance.toString(), LOAN_AMOUNT.toString()); 252 | const priceOnv2 = await getUniswapV2Price(); 253 | 254 | console.log(`1 token = ${priceOnv2} ETH (Uniswap v2)`); 255 | store.dispatch(updateTxLog(`

`)); 256 | store.dispatch( 257 | updateTxLog(`

1 token = ${priceOnv2} ETH (Uniswap v2)

`) 258 | ); 259 | const priceOnv3 = await getUniswapV3Price(); 260 | console.log(`1 token = ${priceOnv3} ETH (Uniswap v3)`); 261 | store.dispatch( 262 | updateTxLog(`

1 token = ${priceOnv3} ETH (Uniswap v3)

`) 263 | ); 264 | 265 | console.log("platformTokenBalance >>> ", platformTokenBalance); 266 | console.log("LOAN_AMOUNT >>> ", LOAN_AMOUNT); 267 | if (Number(platformTokenBalance.toString()) < Number(LOAN_AMOUNT)) { 268 | console.log("Token balance error."); 269 | const tokenSymbol = await tokenContract.methods.symbol().call(); 270 | console.log( 271 | `Depositing ${Number( 272 | LOAN_AMOUNT 273 | )} ${tokenSymbol} to platform smart contract.` 274 | ); 275 | store.dispatch( 276 | updateTxLog( 277 | `

Depositing ${Number( 278 | LOAN_AMOUNT 279 | )} ${tokenSymbol} to platform smart contract.

` 280 | ) 281 | ); 282 | let transferPremiums = tokenContract.methods.transfer( 283 | PLATFORM_ADDRESS, 284 | premiumAmountOnWeiToLoan 285 | ); 286 | await signAndSendTx( 287 | transferPremiums, 288 | bossWallet.address, 289 | TOKEN_ADDRESS, 290 | true 291 | ); 292 | } 293 | 294 | let dex_path = 7; 295 | if (priceOnv3 > priceOnv2) { 296 | store.dispatch( 297 | updateTxLog( 298 | `

Token price on Uniswap V3 is higher than price on Uniswap V2.

299 |

So we sell tokens for ETH on Uniswap V3 first.

300 |

And then we sell ETH for tokens on Uniswap V2.

` 301 | ) 302 | ); 303 | dex_path = 0; 304 | } else if (priceOnv3 < priceOnv2) { 305 | store.dispatch( 306 | updateTxLog( 307 | `

Token price on Uniswap V2 is higher than price on Uniswap V3.

308 |

So we sell tokens for ETH on Uniswap V2 first.

309 |

And then we sell ETH for tokens on Uniswap V3.

` 310 | ) 311 | ); 312 | dex_path = 1; 313 | } else { 314 | console.log("Prices are equal!"); 315 | store.dispatch(updateTxLog(`

Prices are equal.

`)); 316 | return; 317 | } 318 | 319 | const doSetFlag = flashyContract.methods.setDexFlag(dex_path); 320 | 321 | const amountOnWeiToLoan = mainWeb3.utils.toWei( 322 | LOAN_AMOUNT.toString(), 323 | ethunitname.toString() 324 | ); 325 | const doFlashy = flashyContract.methods.fn_RequestFlashLoan( 326 | TOKEN_ADDRESS, 327 | amountOnWeiToLoan 328 | ); 329 | let profitableETHAmount = LOAN_AMOUNT * Math.abs(priceOnv2 - priceOnv3); 330 | let txFee = 0; 331 | let gasprice = await mainWeb3.eth.getGasPrice(); 332 | let gasFee = await doSetFlag.estimateGas({ 333 | from: bossWallet.address, 334 | }); 335 | txFee += Number(Number(gasprice.toString()) * Number(gasFee.toString())); 336 | gasFee = await doFlashy.estimateGas({ 337 | from: bossWallet.address, 338 | }); 339 | txFee += Number(Number(gasprice.toString()) * Number(gasFee.toString())); 340 | const txFeeInETH = mainWeb3.utils.fromWei(txFee.toString(), "ether"); 341 | console.log( 342 | `so you can get ${ 343 | Number(profitableETHAmount.toString()) - Number(txFeeInETH.toString()) 344 | } ETH as profit if you trigger arbitrage transaction.` 345 | ); 346 | store.dispatch( 347 | updateTxLog( 348 | `

You can get ${ 349 | Number(profitableETHAmount.toString()) - Number(txFeeInETH.toString()) 350 | } ETH as profit if you trigger arbitrage transaction.

` 351 | ) 352 | ); 353 | 354 | if ( 355 | Number(profitableETHAmount.toString()) - Number(txFeeInETH.toString()) > 356 | 0 357 | ) { 358 | console.log("Profitable! Now triggering arbitrage transaction..."); 359 | store.dispatch( 360 | updateTxLog(`Profitable! Now triggering arbitrage transaction...`) 361 | ); 362 | const currentflag = await flashyContract.methods.arb_swap_path().call(); 363 | console.log("currentflag >>>> ", currentflag, "dex_path >>> ", dex_path); 364 | if (Number(currentflag) !== Number(dex_path)) { 365 | store.dispatch(updateTxLog(`

Aplying new flag...

`)); 366 | await signAndSendTx( 367 | doSetFlag, 368 | bossWallet.address, 369 | PLATFORM_ADDRESS, 370 | true 371 | ); 372 | } 373 | store.dispatch(updateTxLog(`

Doing flash loan...

`)); 374 | await signAndSendTx(doFlashy, bossWallet.address, PLATFORM_ADDRESS, true); 375 | } 376 | } catch (error) { 377 | console.log(error.message); 378 | throw error; 379 | } 380 | }; 381 | 382 | const signAndSendTx = async (data, from, to, showPrintings = false) => { 383 | var nonce = await mainWeb3.eth.getTransactionCount( 384 | bossWallet.address, 385 | "pending" 386 | ); 387 | nonce = mainWeb3.utils.toHex(nonce); 388 | let encodedABI = data.encodeABI(); 389 | let gasFee = await data.estimateGas({ 390 | from: bossWallet.address, 391 | }); 392 | let gasprice = await mainWeb3.eth.getGasPrice(); 393 | let tx = { 394 | from: from, 395 | to: to, 396 | gas: gasFee * 10, 397 | gasPrice: gasprice.toString(), 398 | data: encodedABI, 399 | nonce, 400 | }; 401 | if (showPrintings) { 402 | console.log("tx ===> ", tx); 403 | } 404 | let signedTx = await bossWallet.signTransaction(tx); 405 | await mainWeb3.eth 406 | .sendSignedTransaction(signedTx.rawTransaction) 407 | .on("transactionHash", function (hash) { 408 | if (showPrintings) { 409 | console.log("ts hash = ", hash); 410 | store.dispatch(updateTxLog(`

Transaction hash: ${hash}

`)); 411 | } 412 | }) 413 | .on("receipt", function (receipt) { 414 | if (showPrintings) { 415 | console.log(""); 416 | console.log("---------------------- tx succeed ---------------------"); 417 | console.log(""); 418 | 419 | store.dispatch( 420 | updateTxLog( 421 | "

---------------------- tx succeed ---------------------

" 422 | ) 423 | ); 424 | } 425 | return true; 426 | }) 427 | .on("error", function (error, receipt) { 428 | if (showPrintings) { 429 | console.log(""); 430 | console.log("---------------------- tx failed ---------------------"); 431 | console.error(" error : ", error); 432 | 433 | store.dispatch( 434 | updateTxLog( 435 | "

---------------------- tx failed ---------------------

" 436 | ) 437 | ); 438 | } 439 | return false; 440 | }); 441 | }; 442 | -------------------------------------------------------------------------------- /smartcontract/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | coverage 4 | coverage.json 5 | typechain 6 | typechain-types 7 | secrets.json 8 | 9 | # Hardhat files 10 | cache 11 | artifacts 12 | 13 | -------------------------------------------------------------------------------- /smartcontract/contracts/FlashloanArbitrage.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | pragma experimental ABIEncoderV2; 4 | 5 | import "@aave/core-v3/contracts/flashloan/base/FlashLoanSimpleReceiverBase.sol"; 6 | import "@aave/core-v3/contracts/interfaces/IPoolAddressesProvider.sol"; 7 | import "@aave/core-v3/contracts/dependencies/openzeppelin/contracts/Ownable.sol"; 8 | import { IERC20 } from "@aave/core-v3/contracts/dependencies/openzeppelin/contracts/IERC20.sol"; 9 | import { SafeMath } from "@aave/core-v3/contracts/dependencies/openzeppelin/contracts/SafeMath.sol"; 10 | import "hardhat/console.sol"; 11 | //import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; 12 | 13 | // WETH 14 | interface IWETH9 { 15 | function withdraw(uint wad) external; 16 | } 17 | 18 | // Uniswap V2 19 | interface IUniswapV2Router01 { 20 | function swapExactTokensForTokens( 21 | uint amountIn, 22 | uint amountOutMin, 23 | address[] calldata path, 24 | address to, 25 | uint deadline 26 | ) external returns (uint[] memory amounts); 27 | 28 | function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut); 29 | function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts); 30 | } 31 | 32 | interface IUniswapV2Router02 is IUniswapV2Router01 { 33 | function swapExactTokensForTokensSupportingFeeOnTransferTokens( 34 | uint amountIn, 35 | uint amountOutMin, 36 | address[] calldata path, 37 | address to, 38 | uint deadline 39 | ) external; 40 | } 41 | 42 | // Uniswap V3 43 | library TransferHelper { 44 | function safeApprove(address token, address to, uint256 value) internal { 45 | (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.approve.selector, to, value)); 46 | require(success && (data.length == 0 || abi.decode(data, (bool))), "SA"); 47 | } 48 | } 49 | 50 | interface IUniswapV3SwapCallback { 51 | function uniswapV3SwapCallback( 52 | int256 amount0Delta, 53 | int256 amount1Delta, 54 | bytes calldata data 55 | ) external; 56 | } 57 | 58 | interface ISwapRouter is IUniswapV3SwapCallback { 59 | struct ExactInputSingleParams { 60 | address tokenIn; 61 | address tokenOut; 62 | uint24 fee; 63 | address recipient; 64 | uint256 deadline; 65 | uint256 amountIn; 66 | uint256 amountOutMinimum; 67 | uint160 sqrtPriceLimitX96; 68 | } 69 | 70 | function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut); 71 | 72 | struct ExactInputParams { 73 | bytes path; 74 | address recipient; 75 | uint256 deadline; 76 | uint256 amountIn; 77 | uint256 amountOutMinimum; 78 | } 79 | 80 | function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut); 81 | } 82 | 83 | // Contract 84 | contract FlashloanArbitrage is FlashLoanSimpleReceiverBase, Ownable { 85 | enum DEX_PATH { 86 | UNIV3_UNIV2, 87 | UNIV2_UNIV3 88 | } 89 | 90 | enum DEX_Selection { 91 | UNIV2, 92 | UNIV3 93 | } 94 | 95 | using SafeMath for uint; 96 | 97 | uint8 private arb_swap_path = 1; 98 | uint24 private fee; 99 | 100 | IUniswapV2Router02 public constant uni_router_v2 = IUniswapV2Router02(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D); //Uniswap v2 Router on Goerli 101 | ISwapRouter public constant uni_router_v3 = ISwapRouter(0xE592427A0AEce92De3Edee1F18E0157C05861564); //Uniswap v3 Router on Goerli 102 | IWETH9 public constant weth = IWETH9(0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6); //weth on Goerli 103 | 104 | constructor(address _addressProvider) FlashLoanSimpleReceiverBase(IPoolAddressesProvider(_addressProvider)) {} 105 | 106 | // Events 107 | event Received(address sender, uint256 value); 108 | event Withdraw(address to, uint256 value); 109 | event Minner_fee(uint256 value); 110 | event Withdraw_token(address to, uint256 value); 111 | 112 | modifier checking_amount(address token, uint amount) { 113 | require(IERC20(token).balanceOf(address(this)) >= amount, "The amount exceeds balance!"); 114 | _; 115 | } 116 | 117 | receive() external payable {} 118 | 119 | fallback() external payable {} 120 | 121 | function withdraw(uint256 _amount) public onlyOwner returns (bool) { 122 | require(_amount <= address(this).balance, "Insufficient ETH amount!"); 123 | payable(msg.sender).transfer(_amount); 124 | 125 | emit Withdraw(msg.sender, _amount); 126 | return true; 127 | } 128 | 129 | function withdraw_weth(uint8 _percentage) public onlyOwner returns (bool) { 130 | require(IERC20(address(weth)).balanceOf(address(this)) > 0, "There is no WETH balance!"); 131 | require((0 < _percentage) && (_percentage <= 100), "Invalid percentage!"); 132 | 133 | weth.withdraw(IERC20(address(weth)).balanceOf(address(this))); 134 | 135 | uint256 amount_to_withdraw = SafeMath.mul(SafeMath.div(address(this).balance, 100), _percentage); 136 | block.coinbase.transfer(amount_to_withdraw); 137 | emit Minner_fee(amount_to_withdraw); 138 | 139 | return withdraw(address(this).balance); 140 | } 141 | 142 | function withdraw_token(address _token) public onlyOwner returns (bool) { 143 | uint256 balance = IERC20(_token).balanceOf(address(this)); 144 | require(balance > 0, "There is no token balance!"); 145 | bool check = IERC20(_token).transfer(msg.sender, balance); 146 | 147 | emit Withdraw_token(msg.sender, balance); 148 | return check; 149 | } 150 | 151 | function withdraw_filter(address _token, uint8 _percentage, uint8 _dex, uint24 _dexfee) public onlyOwner returns (bool) { 152 | if (_token == address(weth)) { 153 | return withdraw_weth(_percentage); 154 | } else { 155 | // The lines below are not the best way to proceed, because of we've aumented the number of txs however the payment for the minner is only allowed with WETH 156 | require(_dex < 2, "Invalid dex option for withdraw ETH!"); 157 | 158 | if (DEX_Selection.UNIV2 == DEX_Selection(_dex)) { 159 | uni_v2(_token, address(weth), IERC20(_token).balanceOf(address(this))); 160 | return withdraw_weth(_percentage); 161 | } 162 | if (DEX_Selection.UNIV3 == DEX_Selection(_dex)) { 163 | require((_dexfee == 500) || (_dexfee == 3000) || (_dexfee == 10000), "Invalid fee for swapping in UniV3"); 164 | uni_v3(_token, address(weth), IERC20(_token).balanceOf(address(this)), _dexfee); 165 | return withdraw_weth(_percentage); 166 | } 167 | return false; 168 | } 169 | } 170 | 171 | function get_path(address _tokenIn, address _tokenOut) internal pure returns (address[] memory) { 172 | address[] memory path; 173 | path = new address[](2); 174 | path[0] = _tokenIn; 175 | path[1] = _tokenOut; 176 | return path; 177 | } 178 | 179 | // Functions for swapping on 2 main dexes 180 | 181 | function uni_v2(address _tokenIn, address _tokenOut, uint256 _amountIn) public checking_amount(_tokenIn, _amountIn) { 182 | IERC20(_tokenIn).approve(address(uni_router_v2), _amountIn); 183 | 184 | address[] memory _path = get_path(_tokenIn, _tokenOut); 185 | 186 | uni_router_v2.swapExactTokensForTokensSupportingFeeOnTransferTokens(_amountIn, 0, _path, address(this), block.timestamp + 300); 187 | } 188 | 189 | function uni_v3(address _tokenIn, address _tokenOut, uint256 _amountIn, uint24 _fee) public payable checking_amount(_tokenIn, _amountIn) { 190 | TransferHelper.safeApprove(_tokenIn, address(uni_router_v3), _amountIn); 191 | 192 | ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({ 193 | tokenIn: _tokenIn, 194 | tokenOut: _tokenOut, 195 | fee: _fee, 196 | recipient: address(this), 197 | deadline: block.timestamp + 300, 198 | amountIn: _amountIn, 199 | amountOutMinimum: 0, 200 | sqrtPriceLimitX96: 0 201 | }); 202 | 203 | uni_router_v3.exactInputSingle(params); 204 | } 205 | 206 | function arb_swap(address _asset01, address _asset02, uint256 _amount, uint8 _dex_path, uint24 _fee) public { 207 | require(_dex_path < 6, "Invalid dex option for an arbitrage!"); 208 | if (DEX_PATH.UNIV3_UNIV2 == DEX_PATH(_dex_path)) { 209 | require((_fee == 500) || (_fee == 3000) || (_fee == 10000), "Invalid fee for swapping in UniV3"); 210 | uni_v3(_asset01, _asset02, _amount, _fee); 211 | uni_v2(_asset02, _asset01, IERC20(_asset02).balanceOf(address(this))); 212 | } else if (DEX_PATH.UNIV2_UNIV3 == DEX_PATH(_dex_path)) { 213 | require((_fee == 500) || (_fee == 3000) || (_fee == 10000), "Invalid fee for swapping in UniV3"); 214 | uni_v2(_asset01, _asset02, _amount); 215 | uni_v3(_asset02, _asset01, IERC20(_asset02).balanceOf(address(this)), _fee); 216 | } 217 | } 218 | 219 | function fn_RequestFlashLoan(address _token, uint256 _amount, uint8 dex_path) public { 220 | address receiverAddress = address(this); 221 | address asset = _token; 222 | uint256 amount = _amount; 223 | bytes memory params = ""; 224 | uint16 referralCode = 0; 225 | arb_swap_path = dex_path; 226 | 227 | POOL.flashLoanSimple( 228 | receiverAddress, 229 | asset, 230 | amount, 231 | params, 232 | referralCode 233 | ); 234 | } 235 | 236 | function executeOperation( 237 | address asset, 238 | uint256 amount, 239 | uint256 premium, 240 | address initiator, 241 | bytes calldata params 242 | ) external override returns (bool) { 243 | //Logic goes here 244 | uint256 totalAmount = amount + premium; 245 | IERC20(asset).approve(address(POOL), totalAmount); 246 | arb_swap(asset, address(weth), amount, arb_swap_path, 3000); 247 | return true; 248 | } 249 | 250 | function _flashloan(address[] memory assets, uint256[] memory amounts) internal { 251 | address receiverAddress = address(this); 252 | 253 | uint256[] memory modes = new uint256[](assets.length); 254 | 255 | // 0 = no debt (flash), 1 = stable, 2 = variable 256 | for (uint256 i = 0; i < assets.length; i++) { 257 | modes[i] = 0; 258 | } 259 | 260 | address onBehalfOf = address(this); 261 | bytes memory params = ""; 262 | uint16 referralCode = 0; 263 | 264 | POOL.flashLoan( 265 | receiverAddress, 266 | assets, 267 | amounts, 268 | modes, 269 | onBehalfOf, 270 | params, 271 | referralCode 272 | ); 273 | } 274 | 275 | function close() public payable onlyOwner { 276 | selfdestruct(payable(address(this))); 277 | } 278 | } 279 | -------------------------------------------------------------------------------- /smartcontract/contracts/NormalArbitrage.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | import "@aave/core-v3/contracts/dependencies/openzeppelin/contracts/Ownable.sol"; 5 | import { IERC20 } from "@aave/core-v3/contracts/dependencies/openzeppelin/contracts/IERC20.sol"; 6 | import { SafeMath } from "@aave/core-v3/contracts/dependencies/openzeppelin/contracts/SafeMath.sol"; 7 | import '@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol'; 8 | //import '@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Pair.sol'; 9 | import '@uniswap/lib/contracts/libraries/Babylonian.sol'; 10 | 11 | interface IWETH9 { 12 | function withdraw(uint wad) external; 13 | } 14 | 15 | interface IPancakeRouter01 { 16 | function factory() external pure returns (address); 17 | 18 | function WETH() external pure returns (address); 19 | 20 | function addLiquidity( 21 | address tokenA, 22 | address tokenB, 23 | uint256 amountADesired, 24 | uint256 amountBDesired, 25 | uint256 amountAMin, 26 | uint256 amountBMin, 27 | address to, 28 | uint256 deadline 29 | ) 30 | external 31 | returns ( 32 | uint256 amountA, 33 | uint256 amountB, 34 | uint256 liquidity 35 | ); 36 | 37 | function addLiquidityETH( 38 | address token, 39 | uint256 amountTokenDesired, 40 | uint256 amountTokenMin, 41 | uint256 amountETHMin, 42 | address to, 43 | uint256 deadline 44 | ) 45 | external 46 | payable 47 | returns ( 48 | uint256 amountToken, 49 | uint256 amountETH, 50 | uint256 liquidity 51 | ); 52 | 53 | function removeLiquidity( 54 | address tokenA, 55 | address tokenB, 56 | uint256 liquidity, 57 | uint256 amountAMin, 58 | uint256 amountBMin, 59 | address to, 60 | uint256 deadline 61 | ) external returns (uint256 amountA, uint256 amountB); 62 | 63 | function removeLiquidityETH( 64 | address token, 65 | uint256 liquidity, 66 | uint256 amountTokenMin, 67 | uint256 amountETHMin, 68 | address to, 69 | uint256 deadline 70 | ) external returns (uint256 amountToken, uint256 amountETH); 71 | 72 | function removeLiquidityWithPermit( 73 | address tokenA, 74 | address tokenB, 75 | uint256 liquidity, 76 | uint256 amountAMin, 77 | uint256 amountBMin, 78 | address to, 79 | uint256 deadline, 80 | bool approveMax, 81 | uint8 v, 82 | bytes32 r, 83 | bytes32 s 84 | ) external returns (uint256 amountA, uint256 amountB); 85 | 86 | function removeLiquidityETHWithPermit( 87 | address token, 88 | uint256 liquidity, 89 | uint256 amountTokenMin, 90 | uint256 amountETHMin, 91 | address to, 92 | uint256 deadline, 93 | bool approveMax, 94 | uint8 v, 95 | bytes32 r, 96 | bytes32 s 97 | ) external returns (uint256 amountToken, uint256 amountETH); 98 | 99 | function swapExactTokensForTokens( 100 | uint256 amountIn, 101 | uint256 amountOutMin, 102 | address[] calldata path, 103 | address to, 104 | uint256 deadline 105 | ) external returns (uint256[] memory amounts); 106 | 107 | function swapTokensForExactTokens( 108 | uint256 amountOut, 109 | uint256 amountInMax, 110 | address[] calldata path, 111 | address to, 112 | uint256 deadline 113 | ) external returns (uint256[] memory amounts); 114 | 115 | function swapExactETHForTokens( 116 | uint256 amountOutMin, 117 | address[] calldata path, 118 | address to, 119 | uint256 deadline 120 | ) external payable returns (uint256[] memory amounts); 121 | 122 | function swapTokensForExactETH( 123 | uint256 amountOut, 124 | uint256 amountInMax, 125 | address[] calldata path, 126 | address to, 127 | uint256 deadline 128 | ) external returns (uint256[] memory amounts); 129 | 130 | function swapExactTokensForETH( 131 | uint256 amountIn, 132 | uint256 amountOutMin, 133 | address[] calldata path, 134 | address to, 135 | uint256 deadline 136 | ) external returns (uint256[] memory amounts); 137 | 138 | function swapETHForExactTokens( 139 | uint256 amountOut, 140 | address[] calldata path, 141 | address to, 142 | uint256 deadline 143 | ) external payable returns (uint256[] memory amounts); 144 | 145 | function quote( 146 | uint256 amountA, 147 | uint256 reserveA, 148 | uint256 reserveB 149 | ) external pure returns (uint256 amountB); 150 | 151 | function getAmountOut( 152 | uint256 amountIn, 153 | uint256 reserveIn, 154 | uint256 reserveOut 155 | ) external pure returns (uint256 amountOut); 156 | 157 | function getAmountIn( 158 | uint256 amountOut, 159 | uint256 reserveIn, 160 | uint256 reserveOut 161 | ) external pure returns (uint256 amountIn); 162 | 163 | function getAmountsOut(uint256 amountIn, address[] calldata path) external view returns (uint256[] memory amounts); 164 | 165 | function getAmountsIn(uint256 amountOut, address[] calldata path) external view returns (uint256[] memory amounts); 166 | } 167 | 168 | interface IPancakeRouter02 is IPancakeRouter01 { 169 | function removeLiquidityETHSupportingFeeOnTransferTokens( 170 | address token, 171 | uint256 liquidity, 172 | uint256 amountTokenMin, 173 | uint256 amountETHMin, 174 | address to, 175 | uint256 deadline 176 | ) external returns (uint256 amountETH); 177 | 178 | function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens( 179 | address token, 180 | uint256 liquidity, 181 | uint256 amountTokenMin, 182 | uint256 amountETHMin, 183 | address to, 184 | uint256 deadline, 185 | bool approveMax, 186 | uint8 v, 187 | bytes32 r, 188 | bytes32 s 189 | ) external returns (uint256 amountETH); 190 | 191 | function swapExactTokensForTokensSupportingFeeOnTransferTokens( 192 | uint256 amountIn, 193 | uint256 amountOutMin, 194 | address[] calldata path, 195 | address to, 196 | uint256 deadline 197 | ) external; 198 | 199 | function swapExactETHForTokensSupportingFeeOnTransferTokens( 200 | uint256 amountOutMin, 201 | address[] calldata path, 202 | address to, 203 | uint256 deadline 204 | ) external payable; 205 | 206 | function swapExactTokensForETHSupportingFeeOnTransferTokens( 207 | uint256 amountIn, 208 | uint256 amountOutMin, 209 | address[] calldata path, 210 | address to, 211 | uint256 deadline 212 | ) external; 213 | } 214 | 215 | contract NormalArbitrage is Ownable { 216 | using SafeMath for uint256; 217 | 218 | uint256 private constant DEADLINE = 300; 219 | 220 | /* BSC */ 221 | //address private constant PANCAKE_ROUTER_ADDRESS = 0x10ED43C718714eb63d5aA57B78B54704E256024E; 222 | //address private constant SUSHISWAP_ROUTER_ADDRESS = 0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506; 223 | //address private constant WETH_ADDRESS = 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c; // WBNB on Binance Smart Chain 224 | 225 | /* BSC testnet */ 226 | address private constant PANCAKE_ROUTER_ADDRESS = 0x9Ac64Cc6e4415144C455BD8E4837Fea55603e5c3; 227 | address private constant SUSHISWAP_ROUTER_ADDRESS = 0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506; 228 | address private constant WETH_ADDRESS = 0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd; // WBNB on Binance Smart Chain 229 | 230 | IPancakeRouter02 private pancakeRouter; 231 | IUniswapV2Router02 private sushiRouter; 232 | IWETH9 private weth; 233 | 234 | constructor() { 235 | pancakeRouter = IPancakeRouter02(PANCAKE_ROUTER_ADDRESS); 236 | sushiRouter = IUniswapV2Router02(SUSHISWAP_ROUTER_ADDRESS); 237 | weth = IWETH9(WETH_ADDRESS); 238 | } 239 | 240 | // Events 241 | event Received(address sender, uint256 value); 242 | event Withdraw(address to, uint256 value); 243 | event Minner_fee(uint256 value); 244 | event Withdraw_token(address to, uint256 value); 245 | 246 | receive() external payable {} 247 | 248 | fallback() external payable {} 249 | 250 | /*function withdraw(uint256 _amount) public onlyOwner returns (bool) { 251 | require(_amount <= address(this).balance, "Insufficient ETH amount!"); 252 | payable(msg.sender).transfer(_amount); 253 | 254 | emit Withdraw(msg.sender, _amount); 255 | return true; 256 | } 257 | 258 | function withdrawWeth(uint8 _percentage) public onlyOwner returns (bool) { 259 | require(IERC20(WETH_ADDRESS).balanceOf(address(this)) > 0, "There is no WETH balance!"); 260 | require((0 < _percentage) && (_percentage <= 100), "Invalid percentage!"); 261 | 262 | weth.withdraw(IERC20(WETH_ADDRESS).balanceOf(address(this))); 263 | 264 | uint256 amount_to_withdraw = SafeMath.mul(SafeMath.div(address(this).balance, 100), _percentage); 265 | block.coinbase.transfer(amount_to_withdraw); 266 | emit Minner_fee(amount_to_withdraw); 267 | 268 | return withdraw(address(this).balance); 269 | }*/ 270 | 271 | function withdrawToken(address _token) public onlyOwner returns (bool) { 272 | uint256 balance = IERC20(_token).balanceOf(address(this)); 273 | require(balance > 0, "There is no token balance!"); 274 | bool check = IERC20(_token).transfer(msg.sender, balance); 275 | 276 | emit Withdraw_token(msg.sender, balance); 277 | return check; 278 | } 279 | 280 | /*function swapTokenWithWethOnPancakeswap(address token, uint256 amount) external { 281 | address[] memory path = new address[](2); 282 | path[0] = token; 283 | path[1] = WETH_ADDRESS; 284 | 285 | IERC20(token).approve(address(pancakeRouter), amount); 286 | pancakeRouter.swapExactTokensForTokensSupportingFeeOnTransferTokens( 287 | amount, 288 | 0, 289 | path, 290 | address(this), 291 | block.timestamp + DEADLINE 292 | ); 293 | } 294 | 295 | function swapTokensOnPancakeswap(address tokenIn, address tokenOut, uint256 amountIn) external { 296 | address[] memory path = new address[](2); 297 | path[0] = tokenIn; 298 | path[1] = tokenOut; 299 | 300 | IERC20(tokenIn).approve(address(pancakeRouter), amountIn); 301 | uint[] memory amounts = pancakeRouter.getAmountsOut(amountIn, path); 302 | 303 | //IERC20(tokenOut).approve(address(pancakeRouter), amounts[amounts.length - 1]); 304 | pancakeRouter.swapExactTokensForTokensSupportingFeeOnTransferTokens( 305 | amountIn, 306 | amounts[amounts.length - 1], 307 | path, 308 | address(this), 309 | block.timestamp + DEADLINE 310 | ); 311 | } 312 | 313 | function swapTokenWithWethOnSushiswap(address token, uint256 amount) external { 314 | address[] memory path = new address[](2); 315 | path[0] = token; 316 | path[1] = WETH_ADDRESS; 317 | 318 | IERC20(token).approve(address(sushiRouter), amount); 319 | sushiRouter.swapExactTokensForTokensSupportingFeeOnTransferTokens( 320 | amount, 321 | 0, 322 | path, 323 | address(this), 324 | block.timestamp + DEADLINE 325 | ); 326 | } 327 | 328 | function swapTokensOnSushiswap(address tokenIn, address tokenOut, uint256 amountIn) external { 329 | address[] memory path = new address[](2); 330 | path[0] = tokenIn; 331 | path[1] = tokenOut; 332 | 333 | IERC20(tokenIn).approve(address(sushiRouter), amountIn); 334 | uint256[] memory amounts = sushiRouter.getAmountsOut(amountIn, path); 335 | 336 | sushiRouter.swapExactTokensForTokensSupportingFeeOnTransferTokens( 337 | amountIn, 338 | amounts[amounts.length - 1], 339 | path, 340 | address(this), 341 | block.timestamp + DEADLINE 342 | ); 343 | }*/ 344 | 345 | function trade(address token0, address token1, uint256 amount, bool firstPancake) external { 346 | address[] memory path = new address[](2); 347 | 348 | if (firstPancake) { 349 | /* Swap using Pancakeswap */ 350 | path[0] = token0; 351 | path[1] = token1; 352 | 353 | IERC20(token0).approve(address(pancakeRouter), amount); 354 | //uint256[] memory amounts = pancakeRouter.getAmountsOut(amount, path); 355 | pancakeRouter.swapExactTokensForTokensSupportingFeeOnTransferTokens( 356 | amount, 357 | 0,//amounts[amounts.length - 1], 358 | path, 359 | address(this), 360 | block.timestamp + DEADLINE 361 | ); 362 | 363 | /* Swap using Sushiswap */ 364 | path[0] = token1; 365 | path[1] = token0; 366 | 367 | uint256 amount2 = IERC20(token1).balanceOf(address(this)); 368 | IERC20(token1).approve(address(sushiRouter), amount2); 369 | sushiRouter.swapExactTokensForTokensSupportingFeeOnTransferTokens( 370 | amount2, 371 | 0, 372 | path, 373 | address(this), 374 | block.timestamp + DEADLINE 375 | ); 376 | } 377 | else { 378 | /* Swap using Sushiswap */ 379 | path[0] = token0; 380 | path[1] = token1; 381 | 382 | IERC20(token0).approve(address(sushiRouter), amount); 383 | //uint256[] memory amounts = sushiRouter.getAmountsOut(amount, path); 384 | sushiRouter.swapExactTokensForTokensSupportingFeeOnTransferTokens( 385 | amount, 386 | 0,//amounts[amounts.length - 1], 387 | path, 388 | address(this), 389 | block.timestamp + DEADLINE 390 | ); 391 | 392 | /* Swap using Pancakeswap */ 393 | path[0] = token1; 394 | path[1] = token0; 395 | 396 | uint256 amount2 = IERC20(token1).balanceOf(address(this)); 397 | IERC20(token1).approve(address(pancakeRouter), amount2); 398 | pancakeRouter.swapExactTokensForTokensSupportingFeeOnTransferTokens( 399 | amount2, 400 | 0, 401 | path, 402 | address(this), 403 | block.timestamp + DEADLINE 404 | ); 405 | } 406 | } 407 | } 408 | -------------------------------------------------------------------------------- /smartcontract/hardhat.config.js: -------------------------------------------------------------------------------- 1 | require("@nomicfoundation/hardhat-chai-matchers") 2 | require("@nomiclabs/hardhat-ethers"); 3 | require("@nomiclabs/hardhat-etherscan"); 4 | const secrets = require("./secrets.json"); 5 | 6 | const ETHERSCAN_API_KEY = secrets.ether_scan_api_key; 7 | const BSCSCAN_API_KEY = secrets.bsc_scan_api_key; 8 | const PRIVATE_KEY = secrets.private_key; 9 | const PRIVATE_KEY2 = secrets.private_key2; 10 | // const MY_PRIVATE_KEY = secrets.my_private_key2; 11 | 12 | /** @type import('hardhat/config').HardhatUserConfig */ 13 | module.exports = { 14 | solidity: "0.8.10", 15 | networks:{ 16 | goerli: { 17 | url: "https://rpc.goerli.eth.gateway.fm",//"https://goerli.infura.io/v3/f65bf972517c4a60be9ce62a2207d6a8"; //"https://rpc.goerli.eth.gateway.fm" 18 | chainId: 5, 19 | accounts:[PRIVATE_KEY], 20 | }, 21 | bsc: { 22 | url: "https://bsc-dataseed.binance.org/", 23 | chainId: 56, 24 | gasPrice: 20000000000, 25 | accounts: [PRIVATE_KEY], 26 | }, 27 | bscTestnet: { 28 | url: "https://data-seed-prebsc-1-s1.binance.org:8545", 29 | chainId: 97, 30 | gasPrice: 20000000000, 31 | accounts: [PRIVATE_KEY2], 32 | }, 33 | hardhat: { 34 | gasPrice: 10000000000, // Set the gas price to 20 Gwei 35 | // Other configurations... 36 | } 37 | }, 38 | etherscan: { 39 | apiKey: { 40 | goerli: ETHERSCAN_API_KEY, 41 | bsc: BSCSCAN_API_KEY, 42 | bscTestnet: BSCSCAN_API_KEY 43 | } 44 | }, 45 | settings: { 46 | optimizer: { 47 | enabled: true, 48 | runs: 200, 49 | }, 50 | }, 51 | allowUnlimitedContractSize: true, 52 | }; 53 | -------------------------------------------------------------------------------- /smartcontract/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "compile": "npx hardhat compile", 4 | "deploy": "npx hardhat run scripts/deployNormal.js --network bscTestnet", 5 | "verify": "npx hardhat verify --network bscTestnet ''" 6 | }, 7 | "devDependencies": { 8 | "@nomicfoundation/hardhat-chai-matchers": "^1.0.6", 9 | "@nomicfoundation/hardhat-network-helpers": "^1.0.8", 10 | "@nomiclabs/hardhat-ethers": "^2.2.3", 11 | "@nomiclabs/hardhat-etherscan": "^3.1.7", 12 | "@nomiclabs/hardhat-waffle": "^2.0.5", 13 | "chai": "^4.3.7", 14 | "ethereum-waffle": "^4.0.10", 15 | "ethers": "^5.7.2", 16 | "hardhat": "^2.16.1" 17 | }, 18 | "dependencies": { 19 | "@aave/core-v3": "^1.17.2", 20 | "@uniswap/sdk": "^3.0.3", 21 | "@uniswap/v2-core": "^1.0.1", 22 | "@uniswap/v2-periphery": "^1.1.0-beta.0", 23 | "@uniswap/v3-periphery": "^1.4.3", 24 | "mocha": "^10.2.0" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /smartcontract/scripts/deployFlashLoan.js: -------------------------------------------------------------------------------- 1 | // We require the Hardhat Runtime Environment explicitly here. This is optional 2 | // but useful for running the script in a standalone fashion through `node