├── .gitignore ├── setup-env.js ├── babel.config.cjs ├── extensions ├── time.js ├── bignumber.js ├── enum.js └── collections.js ├── .gitmodules ├── addresses ├── benswap-mainnet.json ├── mistswap-mainnet.json └── index.js ├── jest.config.cjs ├── migrations └── 1_initial_migration.js ├── entity ├── balance.js ├── withdrawal.js └── order.js ├── contracts ├── interfaces │ ├── IPancakeCallee.sol │ ├── IPancakeFactory.sol │ ├── IERC20.sol │ ├── IPancakeERC20.sol │ └── IPancakePair.sol ├── test │ └── ERC20.sol ├── Migration.sol ├── libraries │ ├── SafeMath.sol │ ├── UQ112x112.sol │ └── Math.sol ├── PancakeFactory.sol ├── PancakeERC20.sol ├── PancakePair.sol ├── BenSwapFactory.sol └── BenSwapRouter.sol ├── classes-mapper.js ├── .env.template ├── io ├── db.js ├── http.js └── websocket.js ├── abis ├── index.js ├── BenSwapFactory.json ├── Erc20.json ├── IUniswapV2Pair.json ├── PancakePair.json ├── MistSwapRouter.json └── BenSwapRouter.json ├── package.json ├── README.md ├── dex ├── base.js ├── benswap.js └── mistswap.js ├── truffle-config.cjs └── dexduels.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | build/ 3 | .vscode/ 4 | .env -------------------------------------------------------------------------------- /setup-env.js: -------------------------------------------------------------------------------- 1 | import dotenv from "dotenv"; 2 | dotenv.config(); -------------------------------------------------------------------------------- /babel.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { presets: ["@babel/preset-env"] }; 2 | -------------------------------------------------------------------------------- /extensions/time.js: -------------------------------------------------------------------------------- 1 | function delay(ms) { 2 | return new Promise((cb) => setTimeout(cb, ms)); 3 | } 4 | 5 | export { delay }; 6 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "benswapbch-assets"] 2 | path = benswapbch-assets 3 | url = git@github.com:BenTokenFinance/benswapbch-assets.git 4 | -------------------------------------------------------------------------------- /addresses/benswap-mainnet.json: -------------------------------------------------------------------------------- 1 | { 2 | "factory": "0x8d973bAD782c1FFfd8FcC9d7579542BA7Dd0998D", 3 | "router": "0xa194133ED572D86fe27796F2feADBAFc062cB9E0" 4 | } 5 | -------------------------------------------------------------------------------- /addresses/mistswap-mainnet.json: -------------------------------------------------------------------------------- 1 | { 2 | "factory": "0x6008247F53395E7be698249770aa1D2bfE265Ca0", 3 | "router": "0x5d0bF8d8c8b054080E2131D8b260a5c6959411B8" 4 | } -------------------------------------------------------------------------------- /jest.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: "ts-jest", 3 | transform: { 4 | "^.+\\.(ts|tsx)?$": "ts-jest", 5 | "^.+\\.(js|jsx)$": "babel-jest", 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | const Migrations = artifacts.require("Migrations"); 2 | 3 | module.exports = function (deployer) { 4 | deployer.deploy(Migrations); 5 | }; 6 | -------------------------------------------------------------------------------- /entity/balance.js: -------------------------------------------------------------------------------- 1 | import { Data } from "dataclass"; 2 | 3 | class Balance extends Data { 4 | currency; 5 | total; 6 | available; 7 | } 8 | 9 | export { Balance }; 10 | -------------------------------------------------------------------------------- /contracts/interfaces/IPancakeCallee.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.5.0; 2 | 3 | interface IPancakeCallee { 4 | function pancakeCall(address sender, uint amount0, uint amount1, bytes calldata data) external; 5 | } 6 | -------------------------------------------------------------------------------- /extensions/bignumber.js: -------------------------------------------------------------------------------- 1 | import BigNumber from "bignumber.js"; 2 | 3 | const ZERO = new BigNumber("0"); 4 | const ONE = new BigNumber("1"); 5 | const TWO = new BigNumber("2"); 6 | 7 | export { ZERO, BigNumber, ONE}; 8 | -------------------------------------------------------------------------------- /addresses/index.js: -------------------------------------------------------------------------------- 1 | import { createRequire } from "module"; 2 | const require = createRequire(import.meta.url); 3 | export const mainnet = { 4 | benswap: require("./benswap-mainnet.json"), 5 | mistswap: require("./mistswap-mainnet.json"), 6 | }; 7 | -------------------------------------------------------------------------------- /contracts/test/ERC20.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 2 | 3 | import '../PancakeERC20.sol'; 4 | 5 | contract ERC20 is PancakeERC20 { 6 | constructor(uint _totalSupply) public { 7 | _mint(msg.sender, _totalSupply); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /classes-mapper.js: -------------------------------------------------------------------------------- 1 | import Benswap from "./dex/benswap.js"; 2 | import Mistswap from "./dex/mistswap.js"; 3 | 4 | const classesMapper = { 5 | Mistswap: Mistswap, 6 | Benswap: Benswap, 7 | }; 8 | 9 | export { classesMapper, Mistswap, Benswap }; 10 | -------------------------------------------------------------------------------- /extensions/enum.js: -------------------------------------------------------------------------------- 1 | class Enum { 2 | constructor(...keys) { 3 | keys.forEach((key, i) => { 4 | this[key] = key; 5 | }); 6 | Object.freeze(this); 7 | } 8 | 9 | *[Symbol.iterator]() { 10 | for (let key of Object.keys(this)) yield key; 11 | } 12 | } 13 | 14 | export { Enum }; 15 | -------------------------------------------------------------------------------- /.env.template: -------------------------------------------------------------------------------- 1 | SMART_BCH_WSS=wss://smartbch-wss.greyh.at 2 | SMART_BCH_HTTPS=https://global.uat.cash 3 | QUOTE_SYMBOLS=EBEN,FLEX 4 | BASE_SYMBOL=WBCH 5 | BASE_QTY=1 6 | INTERVAL=5000 7 | TRIGGER_PROFIT_IN_USD=4 8 | HTTP_PROXY=http://127.0.0.1:7890 9 | ROUTE_BASES=WBCH,flexUSD 10 | DEXDUELS_DEXES=Benswap,Mistswap 11 | WALLET_ADDRESS= 12 | WALLET_PRIVATE_KEY= -------------------------------------------------------------------------------- /io/db.js: -------------------------------------------------------------------------------- 1 | import { MongoClient } from "mongodb"; 2 | 3 | const DEFAULT_DB_URL = "mongodb://localhost:27017"; 4 | 5 | async function installDB(dbName, url = DEFAULT_DB_URL) { 6 | const client = new MongoClient(url); 7 | await client.connect(); 8 | console.log("Connected successfully to mongodb"); 9 | return client.db(dbName); 10 | } 11 | 12 | export default installDB; 13 | -------------------------------------------------------------------------------- /extensions/collections.js: -------------------------------------------------------------------------------- 1 | function chunk(lst, size) { 2 | let chunks = []; 3 | for (let i = 0; i < lst.length; i += size) 4 | chunks.push(lst.slice(i, i + size)); 5 | return chunks; 6 | } 7 | 8 | function genCombinations(lst) { 9 | return lst.flatMap((base, i) => 10 | lst.slice(i + 1).map((other) => [base, other]) 11 | ); 12 | } 13 | 14 | export { chunk, genCombinations }; 15 | -------------------------------------------------------------------------------- /contracts/Migration.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.4.25 <0.7.0; 3 | 4 | contract Migrations { 5 | address public owner; 6 | uint public last_completed_migration; 7 | 8 | modifier restricted() { 9 | if (msg.sender == owner) _; 10 | } 11 | 12 | constructor() public { 13 | owner = msg.sender; 14 | } 15 | 16 | function setCompleted(uint completed) public restricted { 17 | last_completed_migration = completed; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /abis/index.js: -------------------------------------------------------------------------------- 1 | import { createRequire } from "module"; 2 | const require = createRequire(import.meta.url); 3 | const mistswapRouter = require("./MistSwapRouter.json"); 4 | const benswapRouter = require("./BenSwapRouter.json"); 5 | const benswapFactory = require("./BenSwapFactory.json"); 6 | const uniswapV2Pair = require("./IUniswapV2Pair.json"); 7 | const pancakePair = require("./PancakePair.json"); 8 | const erc20 = require("./Erc20.json") 9 | export default { mistswapRouter, benswapRouter, benswapFactory, uniswapV2Pair, pancakePair, erc20 }; 10 | -------------------------------------------------------------------------------- /contracts/libraries/SafeMath.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 2 | 3 | // a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math) 4 | 5 | library SafeMath { 6 | function add(uint x, uint y) internal pure returns (uint z) { 7 | require((z = x + y) >= x, 'ds-math-add-overflow'); 8 | } 9 | 10 | function sub(uint x, uint y) internal pure returns (uint z) { 11 | require((z = x - y) <= x, 'ds-math-sub-underflow'); 12 | } 13 | 14 | function mul(uint x, uint y) internal pure returns (uint z) { 15 | require(y == 0 || (z = x * y) / y == x, 'ds-math-mul-overflow'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /contracts/libraries/UQ112x112.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 2 | 3 | // a library for handling binary fixed point numbers (https://en.wikipedia.org/wiki/Q_(number_format)) 4 | 5 | // range: [0, 2**112 - 1] 6 | // resolution: 1 / 2**112 7 | 8 | library UQ112x112 { 9 | uint224 constant Q112 = 2**112; 10 | 11 | // encode a uint112 as a UQ112x112 12 | function encode(uint112 y) internal pure returns (uint224 z) { 13 | z = uint224(y) * Q112; // never overflows 14 | } 15 | 16 | // divide a UQ112x112 by a uint112, returning a UQ112x112 17 | function uqdiv(uint224 x, uint112 y) internal pure returns (uint224 z) { 18 | z = x / uint224(y); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /contracts/libraries/Math.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 2 | 3 | // a library for performing various math operations 4 | 5 | library Math { 6 | function min(uint x, uint y) internal pure returns (uint z) { 7 | z = x < y ? x : y; 8 | } 9 | 10 | // babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method) 11 | function sqrt(uint y) internal pure returns (uint z) { 12 | if (y > 3) { 13 | z = y; 14 | uint x = y / 2 + 1; 15 | while (x < z) { 16 | z = x; 17 | x = (y / x + x) / 2; 18 | } 19 | } else if (y != 0) { 20 | z = 1; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /contracts/interfaces/IPancakeFactory.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.5.0; 2 | 3 | interface IPancakeFactory { 4 | event PairCreated(address indexed token0, address indexed token1, address pair, uint); 5 | 6 | function feeTo() external view returns (address); 7 | function feeToSetter() external view returns (address); 8 | 9 | function getPair(address tokenA, address tokenB) external view returns (address pair); 10 | function allPairs(uint) external view returns (address pair); 11 | function allPairsLength() external view returns (uint); 12 | 13 | function createPair(address tokenA, address tokenB) external returns (address pair); 14 | 15 | function setFeeTo(address) external; 16 | function setFeeToSetter(address) external; 17 | } 18 | -------------------------------------------------------------------------------- /contracts/interfaces/IERC20.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.5.0; 2 | 3 | interface IERC20 { 4 | event Approval(address indexed owner, address indexed spender, uint value); 5 | event Transfer(address indexed from, address indexed to, uint value); 6 | 7 | function name() external view returns (string memory); 8 | function symbol() external view returns (string memory); 9 | function decimals() external view returns (uint8); 10 | function totalSupply() external view returns (uint); 11 | function balanceOf(address owner) external view returns (uint); 12 | function allowance(address owner, address spender) external view returns (uint); 13 | 14 | function approve(address spender, uint value) external returns (bool); 15 | function transfer(address to, uint value) external returns (bool); 16 | function transferFrom(address from, address to, uint value) external returns (bool); 17 | } 18 | -------------------------------------------------------------------------------- /entity/withdrawal.js: -------------------------------------------------------------------------------- 1 | import { Data } from "dataclass"; 2 | import { Enum } from "../extensions/enum.js"; 3 | 4 | const withdrawalStatus = new Enum( 5 | "Pending", 6 | "Cancelled", 7 | "Failed", 8 | "Completed" 9 | ); 10 | 11 | class Withdrawal extends Data { 12 | id; 13 | exName; 14 | currency; 15 | address; 16 | status; 17 | chain; 18 | amount; 19 | fee; 20 | ts; 21 | } 22 | 23 | function withdrawalStatusOf(word) { 24 | switch (word) { 25 | case "audit": 26 | case "pass": 27 | case "processing": 28 | case "confirming": 29 | return withdrawalStatus.Pending; 30 | case "not_pass": 31 | case "cancel": 32 | return withdrawalStatus.Cancelled; 33 | case "fail": 34 | return withdrawalStatus.Failed; 35 | case "finish": 36 | return withdrawalStatus.Completed; 37 | } 38 | } 39 | 40 | export { Withdrawal, withdrawalStatusOf, withdrawalStatus }; 41 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "benswap-arbitrage", 3 | "type": "module", 4 | "version": "1.0.0", 5 | "description": "", 6 | "main": "index.js", 7 | "directories": { 8 | "test": "test" 9 | }, 10 | "scripts": { 11 | "test": "jest --detectOpenHandles", 12 | "start": "node index.js" 13 | }, 14 | "author": "", 15 | "license": "ISC", 16 | "dependencies": { 17 | "@babel/core": "^7.16.10", 18 | "@babel/preset-env": "^7.16.10", 19 | "@ethersproject/abi": "^5.5.0", 20 | "@mistswapdex/sdk": "^0.0.12", 21 | "@pancakeswap-libs/sdk-v2": "https://github.com/BenTokenFinance/benswapbch-sdk/tarball/master", 22 | "axios": "^0.26.0", 23 | "babel-jest": "^27.4.6", 24 | "collections": "^5.1.13", 25 | "crc": "^4.1.0", 26 | "dataclass": "^2.0.0", 27 | "dotenv": "^11.0.0", 28 | "fastpriorityqueue": "^0.7.1", 29 | "https-proxy-agent": "^5.0.0", 30 | "lodash": "^4.17.21", 31 | "lodash.combinations": "^18.10.0", 32 | "mongodb": "^4.3.1", 33 | "rxjs": "^7.5.2", 34 | "ts-jest": "^27.1.3", 35 | "uuid": "^8.3.2", 36 | "web3": "^1.6.1", 37 | "web3-eth": "^1.6.1", 38 | "ws": "^8.4.2" 39 | }, 40 | "devDependencies": { 41 | "jest": "^27.4.7" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /contracts/interfaces/IPancakeERC20.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.5.0; 2 | 3 | interface IPancakeERC20 { 4 | event Approval(address indexed owner, address indexed spender, uint value); 5 | event Transfer(address indexed from, address indexed to, uint value); 6 | 7 | function name() external pure returns (string memory); 8 | function symbol() external pure returns (string memory); 9 | function decimals() external pure returns (uint8); 10 | function totalSupply() external view returns (uint); 11 | function balanceOf(address owner) external view returns (uint); 12 | function allowance(address owner, address spender) external view returns (uint); 13 | 14 | function approve(address spender, uint value) external returns (bool); 15 | function transfer(address to, uint value) external returns (bool); 16 | function transferFrom(address from, address to, uint value) external returns (bool); 17 | 18 | function DOMAIN_SEPARATOR() external view returns (bytes32); 19 | function PERMIT_TYPEHASH() external pure returns (bytes32); 20 | function nonces(address owner) external view returns (uint); 21 | 22 | function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; 23 | } 24 | -------------------------------------------------------------------------------- /io/http.js: -------------------------------------------------------------------------------- 1 | import "../setup-env.js"; 2 | import axios from "axios"; 3 | 4 | const httpProxy = process.env.HTTP_PROXY; 5 | const proxyOn = httpProxy !== undefined; 6 | const DEFAULT_REQUEST_CONFIG = { 7 | timeout: 10000, 8 | headers: { 9 | "User-Agent": 10 | "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36", 11 | post: { 12 | "Content-Type": "application/json", 13 | }, 14 | }, 15 | }; 16 | if (proxyOn) { 17 | const [scheme, host, port] = httpProxy.match( 18 | /(https?|(\d+(\.|(?=:)|$)){4}|(?<=:)\d+$)/g 19 | ); 20 | DEFAULT_REQUEST_CONFIG.proxy = { host: host, port: port }; 21 | } 22 | 23 | const client = axios.create(DEFAULT_REQUEST_CONFIG); 24 | async function request(method, url, data, headers) { 25 | client.interceptors.request.use((config) => { 26 | for (const [k, v] of Object.entries(headers)) { 27 | config.headers[k] = v; 28 | } 29 | return config; 30 | }); 31 | const requestConf = { 32 | method: method.toLowerCase(), 33 | url: url, 34 | }; 35 | switch (requestConf.method) { 36 | case "get": 37 | case "delete": 38 | requestConf.params = data; 39 | break; 40 | case "post": 41 | requestConf.data = data; 42 | break; 43 | } 44 | return await client.request(requestConf); 45 | } 46 | 47 | export default request; 48 | -------------------------------------------------------------------------------- /entity/order.js: -------------------------------------------------------------------------------- 1 | import { Data } from "dataclass"; 2 | import { Enum } from "../extensions/enum.js"; 3 | 4 | const side = new Enum("Buy", "Sell"); 5 | const type = new Enum("Limit", "Market"); 6 | const action = new Enum("Arb", "Hedge"); 7 | const status = new Enum("New", "Cancelled", "PartiallyFilled", "Filled"); 8 | const tif = new Enum("GTC", "IOC", "FOK"); 9 | 10 | function sideOf(word) { 11 | switch (word) { 12 | case "Buy": 13 | case "buy": 14 | case "BUY": 15 | case "bid": 16 | return side.Buy; 17 | case "Sell": 18 | case "sell": 19 | case "SELL": 20 | case "ask": 21 | return side.Sell; 22 | } 23 | } 24 | 25 | function typeOf(word) { 26 | switch (word) { 27 | case "limit": 28 | case "LIMIT": 29 | return type.Limit; 30 | case "market": 31 | case "MARKET": 32 | return type.Market; 33 | } 34 | } 35 | 36 | function statusOf(word) { 37 | switch (word) { 38 | case "not_deal": 39 | return status.New; 40 | case "part_deal": 41 | return status.PartiallyFilled; 42 | case "cancel": 43 | return status.Cancelled; 44 | case "done": 45 | return status.Filled; 46 | } 47 | } 48 | 49 | class Order extends Data { 50 | id; 51 | clID; 52 | exName; 53 | symbol; 54 | px; 55 | avgPx; 56 | qty; 57 | side; 58 | type; 59 | status; 60 | cumQty; 61 | value; 62 | tif; 63 | ts; 64 | action; 65 | } 66 | export { 67 | side, 68 | sideOf, 69 | type, 70 | typeOf, 71 | status, 72 | statusOf, 73 | tif, 74 | action, 75 | Order, 76 | }; 77 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | Arbitrage program demo using the web3.js library to implement interaction with DEXs running on the SmartBCH chain, such as `Benswap`, `Mistswap`, etc. It can also run on other EVM-compatible sidechains with a few modifications. 4 | 5 | ## Notice 6 | 7 | This demo was created solely to share the arbitrage model. Please be cautious when running it in a production environment. There are still some issues that need to be resolved, such as the consensus problem. 8 | 9 | ## Strategy Summary 10 | 11 | Based on `DEXDUELS_DEXES`, the program generates pairs of DEXs to attempt arbitrage. It works with different pairs of input and output tokens, generated by `BASE_SYMBOL` and `QUOTE_SYMBOLS`. Each pair of DEXs will attempt profitable swaps using the token pairs. 12 | 13 | ## Usage 14 | 15 | - Install [MongoDB](https://docs.mongodb.com/manual/installation/). 16 | - Fill in the properties in the `.env.template` file as shown below, then rename it to `.env`: 17 | 18 | ``` 19 | SMART_BCH_WSS=wss://smartbch-wss.greyh.at 20 | SMART_BCH_HTTPS=https://global.uat.cash 21 | QUOTE_SYMBOLS=EBEN,FLEX // Quotes for the arbitrage 22 | BASE_SYMBOL=WBCH // Base token for the arbitrage 23 | BASE_QTY=1 // Amount of base token for the arbitrage 24 | INTERVAL=5000 // Interval to check for opportunities 25 | TRIGGER_PROFIT_IN_USD=4 // Profit required to trigger the arbitrage 26 | HTTP_PROXY= // Set proxy if your machine is configured with one 27 | DEXDUELS_DEXES=Benswap,Mistswap // Names of DEXs that will participate in the arbitrage 28 | WALLET_ADDRESS= 29 | WALLET_PRIVATE_KEY= 30 | ``` 31 | 32 | - Run the program with `node dexduels.js`.- Run with `node dexduels.js` 33 | -------------------------------------------------------------------------------- /contracts/PancakeFactory.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 2 | 3 | import './interfaces/IPancakeFactory.sol'; 4 | import './PancakePair.sol'; 5 | 6 | contract BenSwapFactory is IPancakeFactory { 7 | bytes32 public constant INIT_CODE_PAIR_HASH = keccak256(abi.encodePacked(type(PancakePair).creationCode)); 8 | 9 | address public feeTo; 10 | address public feeToSetter; 11 | 12 | mapping(address => mapping(address => address)) public getPair; 13 | address[] public allPairs; 14 | 15 | event PairCreated(address indexed token0, address indexed token1, address pair, uint); 16 | 17 | constructor(address _feeToSetter) public { 18 | feeToSetter = _feeToSetter; 19 | } 20 | 21 | function allPairsLength() external view returns (uint) { 22 | return allPairs.length; 23 | } 24 | 25 | function createPair(address tokenA, address tokenB) external returns (address pair) { 26 | require(tokenA != tokenB, 'BenSwap: IDENTICAL_ADDRESSES'); 27 | (address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); 28 | require(token0 != address(0), 'BenSwap: ZERO_ADDRESS'); 29 | require(getPair[token0][token1] == address(0), 'BenSwap: PAIR_EXISTS'); // single check is sufficient 30 | bytes memory bytecode = type(PancakePair).creationCode; 31 | bytes32 salt = keccak256(abi.encodePacked(token0, token1)); 32 | assembly { 33 | pair := create2(0, add(bytecode, 32), mload(bytecode), salt) 34 | } 35 | IPancakePair(pair).initialize(token0, token1); 36 | getPair[token0][token1] = pair; 37 | getPair[token1][token0] = pair; // populate mapping in the reverse direction 38 | allPairs.push(pair); 39 | emit PairCreated(token0, token1, pair, allPairs.length); 40 | } 41 | 42 | function setFeeTo(address _feeTo) external { 43 | require(msg.sender == feeToSetter, 'BenSwap: FORBIDDEN'); 44 | feeTo = _feeTo; 45 | } 46 | 47 | function setFeeToSetter(address _feeToSetter) external { 48 | require(msg.sender == feeToSetter, 'BenSwap: FORBIDDEN'); 49 | feeToSetter = _feeToSetter; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /contracts/interfaces/IPancakePair.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.5.0; 2 | 3 | interface IPancakePair { 4 | event Approval(address indexed owner, address indexed spender, uint value); 5 | event Transfer(address indexed from, address indexed to, uint value); 6 | 7 | function name() external pure returns (string memory); 8 | function symbol() external pure returns (string memory); 9 | function decimals() external pure returns (uint8); 10 | function totalSupply() external view returns (uint); 11 | function balanceOf(address owner) external view returns (uint); 12 | function allowance(address owner, address spender) external view returns (uint); 13 | 14 | function approve(address spender, uint value) external returns (bool); 15 | function transfer(address to, uint value) external returns (bool); 16 | function transferFrom(address from, address to, uint value) external returns (bool); 17 | 18 | function DOMAIN_SEPARATOR() external view returns (bytes32); 19 | function PERMIT_TYPEHASH() external pure returns (bytes32); 20 | function nonces(address owner) external view returns (uint); 21 | 22 | function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; 23 | 24 | event Mint(address indexed sender, uint amount0, uint amount1); 25 | event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); 26 | event Swap( 27 | address indexed sender, 28 | uint amount0In, 29 | uint amount1In, 30 | uint amount0Out, 31 | uint amount1Out, 32 | address indexed to 33 | ); 34 | event Sync(uint112 reserve0, uint112 reserve1); 35 | 36 | function MINIMUM_LIQUIDITY() external pure returns (uint); 37 | function factory() external view returns (address); 38 | function token0() external view returns (address); 39 | function token1() external view returns (address); 40 | function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); 41 | function price0CumulativeLast() external view returns (uint); 42 | function price1CumulativeLast() external view returns (uint); 43 | function kLast() external view returns (uint); 44 | 45 | function mint(address to) external returns (uint liquidity); 46 | function burn(address to) external returns (uint amount0, uint amount1); 47 | function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external; 48 | function skim(address to) external; 49 | function sync() external; 50 | 51 | function initialize(address, address) external; 52 | } 53 | -------------------------------------------------------------------------------- /io/websocket.js: -------------------------------------------------------------------------------- 1 | import "../setup-env.js" 2 | import WebSocket from "ws"; 3 | import url from "url"; 4 | import HttpsProxyAgent from "https-proxy-agent"; 5 | 6 | const timestamp = () => 7 | new Date().toISOString().replace("T", " ").substr(0, 19); 8 | const proxy = process.env.HTTP_PROXY; 9 | const options = url.parse(proxy); 10 | const agent = new HttpsProxyAgent(options); 11 | 12 | function WebSocketClient(url) { 13 | const minBackoff = 250; 14 | const maxBackoff = 8000; 15 | let client; 16 | let timeout; 17 | let backoff = minBackoff; 18 | 19 | const reconnect = () => { 20 | backoff = backoff >= maxBackoff ? minBackoff : backoff * 2; 21 | setTimeout(() => init(), backoff); 22 | }; 23 | 24 | const init = () => { 25 | console.info(timestamp(), "WebSocketClient :: connecting"); 26 | if (client !== undefined) { 27 | client.removeAllListeners(); 28 | } 29 | client = new WebSocket(url, { agent: agent }); 30 | const heartbeat = () => { 31 | if (timeout !== undefined) { 32 | clearTimeout(timeout); 33 | timeout = undefined; 34 | } 35 | timeout = setTimeout(() => client.terminate(), 35000); 36 | }; 37 | client.on("ping", () => { 38 | console.log(timestamp(), "WebSocketClient :: pinged"); 39 | heartbeat(); 40 | }); 41 | client.on("open", (e) => { 42 | if (typeof this.onOpen === "function") { 43 | this.onOpen(); 44 | } else { 45 | console.log(timestamp(), "WebSocketClient :: opened"); 46 | console.log(e); 47 | } 48 | heartbeat(); 49 | }); 50 | client.on("message", (e) => { 51 | if (typeof this.onMessage === "function") { 52 | this.onMessage(e); 53 | } else { 54 | console.log(timestamp(), "WebSocketClient :: messaged"); 55 | } 56 | heartbeat(); 57 | }); 58 | client.on("close", (code, _) => { 59 | switch (code) { 60 | case 1000: 61 | console.log("WebSocket: closed"); 62 | if (typeof this.onClose === "function") { 63 | this.onClose(); 64 | } 65 | break; 66 | case 1006: 67 | console.log("WebSocket: closed abnormally"); 68 | reconnect(); 69 | break; 70 | default: 71 | console.log("WebSocket: closed unknown"); 72 | reconnect(); 73 | break; 74 | } 75 | }); 76 | client.on("error", (e) => { 77 | if (e.code === "ECONREFUSED") { 78 | reconnect(); 79 | } else if (typeof this.onError === "function") { 80 | this.onError(e); 81 | } else { 82 | console.error(timestamp(), "WebSocketClient :: errored"); 83 | console.error(e); 84 | } 85 | }); 86 | this.send = client.send.bind(client); 87 | this.close = client.close.bind(client); 88 | }; 89 | init(); 90 | } 91 | 92 | export default WebSocketClient; 93 | -------------------------------------------------------------------------------- /dex/base.js: -------------------------------------------------------------------------------- 1 | import "../setup-env.js"; 2 | import Web3 from "web3"; 3 | import abis from "../abis/index.js"; 4 | import { createRequire } from "module"; 5 | import { Balance } from "../entity/balance.js"; 6 | import { mainnet } from "../addresses/index.js"; 7 | import { BigNumber } from "../extensions/bignumber.js"; 8 | import { Percent, JSBI } from "@pancakeswap-libs/sdk-v2"; 9 | 10 | const web3 = new Web3( 11 | new Web3.providers.HttpProvider(process.env.SMART_BCH_HTTPS) 12 | ); 13 | const require = createRequire(import.meta.url); 14 | const tokens = Object.fromEntries( 15 | require("../benswapbch-assets/tokens.json").map((e) => [e.symbol, e]) 16 | ); 17 | 18 | const { address: wallet } = web3.eth.accounts.wallet.add( 19 | process.env.WALLET_PRIVATE_KEY 20 | ); 21 | const publicAddress = process.env.WALLET_ADDRESS; 22 | const gasPrice = 1050000000; 23 | const gasCost = 180000; 24 | 25 | function newContract(abi, address) { 26 | return new web3.eth.Contract(abi, address); 27 | } 28 | 29 | async function transfer(receiver, currency, amount) { 30 | const contract = newContract(abis.erc20, tokens[currency].address); 31 | const amountInWei = Web3.utils.toWei(amount.toString(), "ether"); 32 | const data = contract.methods.transfer(receiver, amountInWei).encodeABI(); 33 | const tx = { 34 | to: receiver, 35 | from: wallet, 36 | data: data, 37 | value: amountInWei, 38 | }; 39 | tx.gas = await web3.eth.estimateGas(tx); 40 | tx.gasPrice = gasPrice; 41 | return await web3.eth.sendTransaction(tx); 42 | } 43 | 44 | async function getBalance(currency) { 45 | let balance; 46 | if (currency === "BCH") { 47 | balance = await web3.eth.getBalance(publicAddress); 48 | } else { 49 | const contract = newContract(abis.erc20, tokens[currency].address); 50 | balance = await contract.methods.balanceOf(publicAddress).call(); 51 | } 52 | balance = new BigNumber(web3.utils.fromWei(balance.toString(), "ether")); 53 | return Balance.create({ 54 | currency: currency, 55 | total: balance, 56 | available: balance, 57 | }); 58 | } 59 | 60 | class Dex { 61 | ZERO_PERCENT = new Percent("0"); 62 | ONE_HUNDRED_PERCENT = new Percent("1"); 63 | TRADES_OPTIONS = { maxHops: 3, maxmaxNumResults: 1 }; 64 | BETTER_TRADE_LESS_HOPS_THRESHOLD = new Percent( 65 | JSBI.BigInt(50), 66 | JSBI.BigInt(10000) 67 | ); 68 | DEFAULT_SWAP_OPTIONS = { 69 | ttl: 50, 70 | recipient: publicAddress, 71 | allowedSlippage: new Percent("1", "1000"), 72 | }; 73 | 74 | constructor() {} 75 | 76 | async getBalances() {} 77 | 78 | async getQuotes([symIn, symOut], baseAmount) {} 79 | 80 | _currencyCombinations(sym0, sym1, basesToCheckTradesAgainst) { 81 | const bases = basesToCheckTradesAgainst; 82 | const basePairs = bases.flatMap((base, _) => 83 | bases.map((otherBase) => [base, otherBase]) 84 | ); 85 | return [ 86 | [sym0, sym1], 87 | ...bases.map((base) => [sym0, base]), 88 | ...bases.map((base) => [sym1, base]), 89 | ...basePairs, 90 | ].filter(([symA, symB]) => tokens[symA].address !== tokens[symB].address); 91 | } 92 | } 93 | 94 | export { 95 | web3, 96 | tokens, 97 | abis, 98 | mainnet, 99 | Dex, 100 | wallet, 101 | gasCost, 102 | gasPrice, 103 | newContract, 104 | transfer, 105 | getBalance, 106 | }; 107 | -------------------------------------------------------------------------------- /contracts/PancakeERC20.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 2 | 3 | import './interfaces/IPancakeERC20.sol'; 4 | import './libraries/SafeMath.sol'; 5 | 6 | contract PancakeERC20 is IPancakeERC20 { 7 | using SafeMath for uint; 8 | 9 | string public constant name = 'BenSwap LPs'; 10 | string public constant symbol = 'BenSwap-LP'; 11 | uint8 public constant decimals = 18; 12 | uint public totalSupply; 13 | mapping(address => uint) public balanceOf; 14 | mapping(address => mapping(address => uint)) public allowance; 15 | 16 | bytes32 public DOMAIN_SEPARATOR; 17 | // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); 18 | bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; 19 | mapping(address => uint) public nonces; 20 | 21 | event Approval(address indexed owner, address indexed spender, uint value); 22 | event Transfer(address indexed from, address indexed to, uint value); 23 | 24 | constructor() public { 25 | uint chainId; 26 | assembly { 27 | chainId := chainid 28 | } 29 | DOMAIN_SEPARATOR = keccak256( 30 | abi.encode( 31 | keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'), 32 | keccak256(bytes(name)), 33 | keccak256(bytes('1')), 34 | chainId, 35 | address(this) 36 | ) 37 | ); 38 | } 39 | 40 | function _mint(address to, uint value) internal { 41 | totalSupply = totalSupply.add(value); 42 | balanceOf[to] = balanceOf[to].add(value); 43 | emit Transfer(address(0), to, value); 44 | } 45 | 46 | function _burn(address from, uint value) internal { 47 | balanceOf[from] = balanceOf[from].sub(value); 48 | totalSupply = totalSupply.sub(value); 49 | emit Transfer(from, address(0), value); 50 | } 51 | 52 | function _approve(address owner, address spender, uint value) private { 53 | allowance[owner][spender] = value; 54 | emit Approval(owner, spender, value); 55 | } 56 | 57 | function _transfer(address from, address to, uint value) private { 58 | balanceOf[from] = balanceOf[from].sub(value); 59 | balanceOf[to] = balanceOf[to].add(value); 60 | emit Transfer(from, to, value); 61 | } 62 | 63 | function approve(address spender, uint value) external returns (bool) { 64 | _approve(msg.sender, spender, value); 65 | return true; 66 | } 67 | 68 | function transfer(address to, uint value) external returns (bool) { 69 | _transfer(msg.sender, to, value); 70 | return true; 71 | } 72 | 73 | function transferFrom(address from, address to, uint value) external returns (bool) { 74 | if (allowance[from][msg.sender] != uint(-1)) { 75 | allowance[from][msg.sender] = allowance[from][msg.sender].sub(value); 76 | } 77 | _transfer(from, to, value); 78 | return true; 79 | } 80 | 81 | function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external { 82 | require(deadline >= block.timestamp, 'BenSwap: EXPIRED'); 83 | bytes32 digest = keccak256( 84 | abi.encodePacked( 85 | '\x19\x01', 86 | DOMAIN_SEPARATOR, 87 | keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline)) 88 | ) 89 | ); 90 | address recoveredAddress = ecrecover(digest, v, r, s); 91 | require(recoveredAddress != address(0) && recoveredAddress == owner, 'BenSwap: INVALID_SIGNATURE'); 92 | _approve(owner, spender, value); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /abis/BenSwapFactory.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 | ] 209 | -------------------------------------------------------------------------------- /truffle-config.cjs: -------------------------------------------------------------------------------- 1 | /** 2 | * Use this file to configure your truffle project. It's seeded with some 3 | * common settings for different networks and features like migrations, 4 | * compilation and testing. Uncomment the ones you need or modify 5 | * them to suit your project as necessary. 6 | * 7 | * More information about configuration can be found at: 8 | * 9 | * trufflesuite.com/docs/advanced/configuration 10 | * 11 | * To deploy via Infura you'll need a wallet provider (like @truffle/hdwallet-provider) 12 | * to sign your transactions before they're sent to a remote public node. Infura accounts 13 | * are available for free at: infura.io/register. 14 | * 15 | * You'll also need a mnemonic - the twelve word phrase the wallet uses to generate 16 | * public/private key pairs. If you're publishing your code to GitHub make sure you load this 17 | * phrase from a file you've .gitignored so it doesn't accidentally become public. 18 | * 19 | */ 20 | 21 | // const HDWalletProvider = require('@truffle/hdwallet-provider'); 22 | // 23 | // const fs = require('fs'); 24 | // const mnemonic = fs.readFileSync(".secret").toString().trim(); 25 | 26 | module.exports = { 27 | /** 28 | * Networks define how you connect to your ethereum client and let you set the 29 | * defaults web3 uses to send transactions. If you don't specify one truffle 30 | * will spin up a development blockchain for you on port 9545 when you 31 | * run `develop` or `test`. You can ask a truffle command to use a specific 32 | * network from the command line, e.g 33 | * 34 | * $ truffle test --network 35 | */ 36 | 37 | networks: { 38 | // Useful for testing. The `development` name is special - truffle uses it by default 39 | // if it's defined here and no other network is specified at the command line. 40 | // You should run a client (like ganache-cli, geth or parity) in a separate terminal 41 | // tab if you use this network and you must also set the `host`, `port` and `network_id` 42 | // options below to some value. 43 | // 44 | // development: { 45 | // host: "127.0.0.1", // Localhost (default: none) 46 | // port: 8545, // Standard Ethereum port (default: none) 47 | // network_id: "*", // Any network (default: none) 48 | // }, 49 | // Another network with more advanced options... 50 | // advanced: { 51 | // port: 8777, // Custom port 52 | // network_id: 1342, // Custom network 53 | // gas: 8500000, // Gas sent with each transaction (default: ~6700000) 54 | // gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei) 55 | // from:
, // Account to send txs from (default: accounts[0]) 56 | // websocket: true // Enable EventEmitter interface for web3 (default: false) 57 | // }, 58 | // Useful for deploying to a public network. 59 | // NB: It's important to wrap the provider as a function. 60 | // ropsten: { 61 | // provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`), 62 | // network_id: 3, // Ropsten's id 63 | // gas: 5500000, // Ropsten has a lower block limit than mainnet 64 | // confirmations: 2, // # of confs to wait between deployments. (default: 0) 65 | // timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50) 66 | // skipDryRun: true // Skip dry run before migrations? (default: false for public nets ) 67 | // }, 68 | // Useful for private networks 69 | // private: { 70 | // provider: () => new HDWalletProvider(mnemonic, `https://network.io`), 71 | // network_id: 2111, // This network is yours, in the cloud. 72 | // production: true // Treats this network as if it was a public net. (default: false) 73 | // } 74 | }, 75 | 76 | // Set default mocha options here, use special reporters etc. 77 | mocha: { 78 | // timeout: 100000 79 | }, 80 | 81 | // Configure your compilers 82 | compilers: { 83 | solc: { 84 | version: "0.5.16", // Fetch exact version from solc-bin (default: truffle's version) 85 | // docker: true, // Use "0.5.1" you've installed locally with docker (default: false) 86 | // settings: { // See the solidity docs for advice about optimization and evmVersion 87 | // optimizer: { 88 | // enabled: false, 89 | // runs: 200 90 | // }, 91 | // evmVersion: "byzantium" 92 | // } 93 | } 94 | }, 95 | 96 | // Truffle DB is currently disabled by default; to enable it, change enabled: 97 | // false to enabled: true. The default storage location can also be 98 | // overridden by specifying the adapter settings, as shown in the commented code below. 99 | // 100 | // NOTE: It is not possible to migrate your contracts to truffle DB and you should 101 | // make a backup of your artifacts to a safe location before enabling this feature. 102 | // 103 | // After you backed up your artifacts you can utilize db by running migrate as follows: 104 | // $ truffle migrate --reset --compile-all 105 | // 106 | // db: { 107 | // enabled: false, 108 | // host: "127.0.0.1", 109 | // adapter: { 110 | // name: "sqlite", 111 | // settings: { 112 | // directory: ".db" 113 | // } 114 | // } 115 | // } 116 | }; 117 | -------------------------------------------------------------------------------- /abis/Erc20.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "constant": true, 4 | "inputs": [], 5 | "name": "name", 6 | "outputs": [ 7 | { 8 | "name": "", 9 | "type": "string" 10 | } 11 | ], 12 | "payable": false, 13 | "stateMutability": "view", 14 | "type": "function" 15 | }, 16 | { 17 | "constant": false, 18 | "inputs": [ 19 | { 20 | "name": "_spender", 21 | "type": "address" 22 | }, 23 | { 24 | "name": "_value", 25 | "type": "uint256" 26 | } 27 | ], 28 | "name": "approve", 29 | "outputs": [ 30 | { 31 | "name": "", 32 | "type": "bool" 33 | } 34 | ], 35 | "payable": false, 36 | "stateMutability": "nonpayable", 37 | "type": "function" 38 | }, 39 | { 40 | "constant": true, 41 | "inputs": [], 42 | "name": "totalSupply", 43 | "outputs": [ 44 | { 45 | "name": "", 46 | "type": "uint256" 47 | } 48 | ], 49 | "payable": false, 50 | "stateMutability": "view", 51 | "type": "function" 52 | }, 53 | { 54 | "constant": false, 55 | "inputs": [ 56 | { 57 | "name": "_from", 58 | "type": "address" 59 | }, 60 | { 61 | "name": "_to", 62 | "type": "address" 63 | }, 64 | { 65 | "name": "_value", 66 | "type": "uint256" 67 | } 68 | ], 69 | "name": "transferFrom", 70 | "outputs": [ 71 | { 72 | "name": "", 73 | "type": "bool" 74 | } 75 | ], 76 | "payable": false, 77 | "stateMutability": "nonpayable", 78 | "type": "function" 79 | }, 80 | { 81 | "constant": true, 82 | "inputs": [], 83 | "name": "decimals", 84 | "outputs": [ 85 | { 86 | "name": "", 87 | "type": "uint8" 88 | } 89 | ], 90 | "payable": false, 91 | "stateMutability": "view", 92 | "type": "function" 93 | }, 94 | { 95 | "constant": true, 96 | "inputs": [ 97 | { 98 | "name": "_owner", 99 | "type": "address" 100 | } 101 | ], 102 | "name": "balanceOf", 103 | "outputs": [ 104 | { 105 | "name": "balance", 106 | "type": "uint256" 107 | } 108 | ], 109 | "payable": false, 110 | "stateMutability": "view", 111 | "type": "function" 112 | }, 113 | { 114 | "constant": true, 115 | "inputs": [], 116 | "name": "symbol", 117 | "outputs": [ 118 | { 119 | "name": "", 120 | "type": "string" 121 | } 122 | ], 123 | "payable": false, 124 | "stateMutability": "view", 125 | "type": "function" 126 | }, 127 | { 128 | "constant": false, 129 | "inputs": [ 130 | { 131 | "name": "_to", 132 | "type": "address" 133 | }, 134 | { 135 | "name": "_value", 136 | "type": "uint256" 137 | } 138 | ], 139 | "name": "transfer", 140 | "outputs": [ 141 | { 142 | "name": "", 143 | "type": "bool" 144 | } 145 | ], 146 | "payable": false, 147 | "stateMutability": "nonpayable", 148 | "type": "function" 149 | }, 150 | { 151 | "constant": true, 152 | "inputs": [ 153 | { 154 | "name": "_owner", 155 | "type": "address" 156 | }, 157 | { 158 | "name": "_spender", 159 | "type": "address" 160 | } 161 | ], 162 | "name": "allowance", 163 | "outputs": [ 164 | { 165 | "name": "", 166 | "type": "uint256" 167 | } 168 | ], 169 | "payable": false, 170 | "stateMutability": "view", 171 | "type": "function" 172 | }, 173 | { 174 | "payable": true, 175 | "stateMutability": "payable", 176 | "type": "fallback" 177 | }, 178 | { 179 | "anonymous": false, 180 | "inputs": [ 181 | { 182 | "indexed": true, 183 | "name": "owner", 184 | "type": "address" 185 | }, 186 | { 187 | "indexed": true, 188 | "name": "spender", 189 | "type": "address" 190 | }, 191 | { 192 | "indexed": false, 193 | "name": "value", 194 | "type": "uint256" 195 | } 196 | ], 197 | "name": "Approval", 198 | "type": "event" 199 | }, 200 | { 201 | "anonymous": false, 202 | "inputs": [ 203 | { 204 | "indexed": true, 205 | "name": "from", 206 | "type": "address" 207 | }, 208 | { 209 | "indexed": true, 210 | "name": "to", 211 | "type": "address" 212 | }, 213 | { 214 | "indexed": false, 215 | "name": "value", 216 | "type": "uint256" 217 | } 218 | ], 219 | "name": "Transfer", 220 | "type": "event" 221 | } 222 | ] -------------------------------------------------------------------------------- /dexduels.js: -------------------------------------------------------------------------------- 1 | import _ from "lodash"; 2 | import "./setup-env.js"; 3 | import "lodash.combinations"; 4 | import installDB from "./io/db.js"; 5 | import { v1 as uuidv1 } from "uuid"; 6 | import { status, action } from "./entity/order.js"; 7 | import { classesMapper } from "./classes-mapper.js"; 8 | import { BigNumber, ONE } from "./extensions/bignumber.js"; 9 | import { delay } from "./extensions/time.js"; 10 | 11 | const { 12 | QUOTE_SYMBOLS, 13 | BASE_SYMBOL, 14 | DEXDUELS_DEXES, 15 | INTERVAL, 16 | BASE_QTY, 17 | TRIGGER_PROFIT_IN_USD, 18 | } = process.env; 19 | 20 | const stableCoin = "flexUSD"; 21 | const baseQty = new BigNumber(BASE_QTY); 22 | const triggerProfitInUSD = new BigNumber(TRIGGER_PROFIT_IN_USD); 23 | 24 | const db = await installDB("dexduels"); 25 | const orders = db.collection("orders"); 26 | 27 | const pairs = QUOTE_SYMBOLS.split(",").map((sym) => [BASE_SYMBOL, sym]); 28 | const dexes = _.fromPairs( 29 | DEXDUELS_DEXES.split(",").map((name) => [name, new classesMapper[name]()]) 30 | ); 31 | 32 | console.info( 33 | `Attempts to find arbitrage opportunities with below pairs:\n ${pairs}` 34 | ); 35 | 36 | const start = async () => { 37 | await checkAndComplete(); 38 | const duels = _.combinations(Object.values(dexes), 2); 39 | while (true) { 40 | await dueling(duels); 41 | await delay(INTERVAL); 42 | } 43 | }; 44 | 45 | /** 46 | * Query out the pending hedge orders and to complete 47 | */ 48 | async function checkAndComplete() { 49 | const pendingHedgeOrders = await orders 50 | .find({ status: status.New, action: action.Hedge }) 51 | .sort({ ts: 1 }) 52 | .toArray(); 53 | for (const order of pendingHedgeOrders) { 54 | order.dex = dexes[order.exName]; 55 | order.tx = await swap(order); 56 | await save(order); 57 | } 58 | } 59 | 60 | async function dueling(duels) { 61 | const opps = await checkOpportunities(duels); 62 | // only carry out the most profitable opportunity in every duels 63 | if (opps.length > 0) { 64 | const bestOpp = opps.reduce((prev, curr) => { 65 | if (curr.estimateProfit.gt(prev.estimateProfit)) { 66 | return curr; 67 | } else { 68 | return prev; 69 | } 70 | }, opps[0]); 71 | const [placedArb, placedHedge] = await excute(bestOpp); 72 | if (placedArb) save(placedArb); 73 | if (placedHedge) save(placedHedge); 74 | } 75 | } 76 | 77 | async function excute(opp) { 78 | const [arbOrder, hedgeOrder] = opp.orders; 79 | await save(arbOrder); 80 | arbOrder.tx = await swap(arbOrder); 81 | if (arbOrder.tx.status) { 82 | await save(hedgeOrder); 83 | // It will be better to check change of balance before hedge instead of use delay 84 | await delay(5000); 85 | hedgeOrder.tx = await swap(hedgeOrder); 86 | return [arbOrder, hedgeOrder]; 87 | } 88 | return [arbOrder, undefined]; 89 | } 90 | 91 | async function save(order) { 92 | const updatedStatus = 93 | order.tx === undefined 94 | ? status.New 95 | : order.tx.status 96 | ? status.Filled 97 | : status.Cancelled; 98 | order.exName = order.dex.constructor.name; 99 | order.status = updatedStatus; 100 | order.ts = Date.now(); 101 | if (order.status === status.New) { 102 | const row = _.pick(order, [ 103 | "id", 104 | "symIn", 105 | "symOut", 106 | "amountIn", 107 | "action", 108 | "hedgeTo", 109 | "exName", 110 | "status", 111 | "ts", 112 | "tx", 113 | ]); 114 | await orders.insertOne(row); 115 | } else { 116 | await orders.updateOne( 117 | { id: order.id }, 118 | { $set: { status: order.status, tx: order.tx } } 119 | ); 120 | } 121 | } 122 | 123 | async function checkOpportunities(duels) { 124 | const opps = []; 125 | for (const [dexA, dexB] of duels) { 126 | for (const pair of pairs) { 127 | const [base, quote] = pair; 128 | const [quotePx] = await dexA.getQuotes([quote, stableCoin], ONE); 129 | const [bidA, askA] = await dexA.getQuotes(pair, baseQty); 130 | const [bidB, askB] = await dexB.getQuotes(pair, baseQty); 131 | 132 | // Swap Base to Quote in Dex A and then swap Quote to Base in Dex B 133 | const profitA2B = bidA.minus(askB).multipliedBy(quotePx); 134 | if (profitA2B.gt(triggerProfitInUSD)) { 135 | const arbID = uuidv1(); 136 | const hedgeID = uuidv1(); 137 | opps.push({ 138 | estimateProfit: profitA2B, 139 | orders: [ 140 | { 141 | id: arbID, 142 | dex: dexA, 143 | symIn: base, 144 | symOut: quote, 145 | amountIn: baseQty, 146 | action: action.Arb, 147 | }, 148 | { 149 | id: hedgeID, 150 | hedgeTo: arbID, 151 | dex: dexB, 152 | symIn: quote, 153 | symOut: base, 154 | amountOut: baseQty, 155 | action: action.Hedge, 156 | }, 157 | ], 158 | }); 159 | } 160 | // Swap Base to Quote in Dex B and then swap Quote to Base in Dex A 161 | const profitB2A = bidB.minus(askA).multipliedBy(quotePx); 162 | if (profitB2A.gt(triggerProfitInUSD)) { 163 | const arbID = uuidv1(); 164 | const hedgeID = uuidv1(); 165 | opps.push({ 166 | estimateProfit: profitB2A, 167 | orders: [ 168 | { 169 | id: arbID, 170 | dex: dexA, 171 | symIn: quote, 172 | symOut: base, 173 | amountOut: baseQty, 174 | action: action.Arb, 175 | }, 176 | { 177 | id: hedgeID, 178 | hedgeTo: arbID, 179 | dex: dexB, 180 | symIn: base, 181 | symOut: quote, 182 | amountIn: baseQty, 183 | action: action.Hedge, 184 | }, 185 | ], 186 | }); 187 | } 188 | } 189 | } 190 | return opps; 191 | } 192 | 193 | async function swap({ dex, symIn, symOut, amountIn, amountOut }) { 194 | return await dex.swap(symIn, symOut, amountIn, amountOut); 195 | } 196 | 197 | start(); 198 | -------------------------------------------------------------------------------- /dex/benswap.js: -------------------------------------------------------------------------------- 1 | import _ from "lodash"; 2 | import Web3 from "web3"; 3 | import "../setup-env.js"; 4 | import BigNumber from "bignumber.js"; 5 | import { 6 | Dex, 7 | mainnet, 8 | abis, 9 | tokens, 10 | wallet, 11 | web3, 12 | gasPrice, 13 | newContract, 14 | } from "./base.js"; 15 | import { 16 | Pair, 17 | Router, 18 | TokenAmount, 19 | Trade, 20 | Token, 21 | ChainId, 22 | CurrencyAmount, 23 | currencyEquals, 24 | } from "@pancakeswap-libs/sdk-v2"; 25 | 26 | class Benswap extends Dex { 27 | routerContract = newContract(abis.benswapRouter, mainnet.benswap.router); 28 | 29 | async getQuotes([symIn, symOut], baseAmount) { 30 | const tokenIn = this._asToken(symIn); 31 | const tokenOut = this._asToken(symOut); 32 | const bid = await this._getOutputAmount( 33 | tokenIn, 34 | tokenOut, 35 | baseAmount, 36 | true 37 | ); 38 | const ask = await this._getOutputAmount( 39 | tokenOut, 40 | tokenIn, 41 | baseAmount, 42 | false 43 | ); 44 | return [new BigNumber(bid), new BigNumber(ask)]; 45 | } 46 | 47 | async _getOutputAmount(tokenIn, tokenOut, amount, isExactIn = true) { 48 | const trade = await this._trade(tokenIn, tokenOut, amount, isExactIn); 49 | return (isExactIn ? trade.outputAmount : trade.inputAmount).toSignificant( 50 | 6 51 | ); 52 | } 53 | 54 | async swap(symIn, symOut, amountIn, amountOut) { 55 | const isExactIn = amountIn !== undefined && amountOut === undefined; 56 | const tokenIn = this._asToken(symIn); 57 | const tokenOut = this._asToken(symOut); 58 | const trade = await this._trade( 59 | tokenIn, 60 | tokenOut, 61 | amountIn || amountOut, 62 | isExactIn 63 | ); 64 | const { methodName, args, value } = Router.swapCallParameters( 65 | trade, 66 | this.DEFAULT_SWAP_OPTIONS 67 | ); 68 | const data = this.routerContract.methods[methodName](...args).encodeABI(); 69 | const tx = { 70 | from: wallet, 71 | to: this.routerContract.options.address, 72 | data: data, 73 | value: value, 74 | }; 75 | tx.gas = await web3.eth.estimateGas(tx); 76 | tx.gasPrice = gasPrice; 77 | return await web3.eth.sendTransaction(tx); 78 | } 79 | 80 | async _trade( 81 | tokenIn, 82 | tokenOut, 83 | amount, 84 | isExactIn, 85 | { maxHops } = this.TRADES_OPTIONS 86 | ) { 87 | const allowedPairs = await this._pairs(tokenIn, tokenOut); 88 | const amountInWei = Web3.utils.toWei(amount.toString(), "ether"); 89 | 90 | const currencyInAmount = this._isEther(tokenIn) 91 | ? CurrencyAmount.ether(amountInWei) 92 | : new TokenAmount(tokenIn, amountInWei); 93 | const currencyOutAmount = this._isEther(tokenOut) 94 | ? CurrencyAmount.ether(amountInWei) 95 | : new TokenAmount(tokenOut, amountInWei); 96 | 97 | if (maxHops === 1) { 98 | return this._bestTrades( 99 | allowedPairs, 100 | tokenIn, 101 | tokenOut, 102 | isExactIn ? currencyInAmount : currencyOutAmount, 103 | isExactIn, 104 | { 105 | maxHops: 1, 106 | maxNumResults: 1, 107 | } 108 | )[0]; 109 | } 110 | // search through trades with varying hops, find best trade out of them 111 | let bestTradeSoFar; 112 | for (let i = 1; i <= maxHops; i++) { 113 | const currentTrade = this._bestTrades( 114 | allowedPairs, 115 | tokenIn, 116 | tokenOut, 117 | isExactIn ? currencyInAmount : currencyOutAmount, 118 | isExactIn, 119 | { 120 | maxHops: i, 121 | maxNumResults: 1, 122 | } 123 | )[0]; 124 | if ( 125 | // if current trade is best yet, save it 126 | this._isTradeBetter( 127 | bestTradeSoFar, 128 | currentTrade, 129 | this.BETTER_TRADE_LESS_HOPS_THRESHOLD 130 | ) 131 | ) { 132 | bestTradeSoFar = currentTrade; 133 | } 134 | } 135 | return bestTradeSoFar; 136 | } 137 | 138 | _bestTrades( 139 | allowedPairs, 140 | tokenIn, 141 | tokenOut, 142 | parsedAmount, 143 | isExactIn, 144 | options 145 | ) { 146 | return isExactIn 147 | ? Trade.bestTradeExactIn(allowedPairs, parsedAmount, tokenOut, options) 148 | : Trade.bestTradeExactOut(allowedPairs, tokenIn, parsedAmount, options); 149 | } 150 | 151 | _isTradeBetter(tradeA, tradeB, minimumDelta = this.ZERO_PERCENT) { 152 | if (tradeA && !tradeB) return false; 153 | if (tradeB && !tradeA) return true; 154 | if (!tradeA || !tradeB) return undefined; 155 | 156 | if ( 157 | tradeA.tradeType !== tradeB.tradeType || 158 | !currencyEquals( 159 | tradeA.inputAmount.currency, 160 | tradeB.inputAmount.currency 161 | ) || 162 | !currencyEquals( 163 | tradeB.outputAmount.currency, 164 | tradeB.outputAmount.currency 165 | ) 166 | ) { 167 | throw new Error("Comparing incomparable trades"); 168 | } 169 | 170 | if (minimumDelta.equalTo(this.ZERO_PERCENT)) { 171 | return tradeA.executionPrice.lessThan(tradeB.executionPrice); 172 | } else { 173 | return tradeA.executionPrice.raw 174 | .multiply(minimumDelta.add(this.ONE_HUNDRED_PERCENT)) 175 | .lessThan(tradeB.executionPrice); 176 | } 177 | } 178 | 179 | async _pairs(token0, token1) { 180 | const currencyCombinations = this._currencyCombinations( 181 | token0.symbol, 182 | token1.symbol 183 | ); 184 | return ( 185 | await Promise.all( 186 | currencyCombinations.map(async ([token0, token1]) => { 187 | return await this._pairOf(token0, token1); 188 | }) 189 | ) 190 | ).filter((pair) => pair !== undefined); 191 | } 192 | 193 | async _pairOf(token0, token1) { 194 | const pairAddress = this._getPairAddress(token0, token1); 195 | const pairContract = newContract(abis.pancakePair, pairAddress); 196 | const reserves = await pairContract.methods.getReserves().call(); 197 | const [t0, t1] = token0.sortsBefore(token1) 198 | ? [token0, token1] 199 | : [token1, token0]; 200 | const token0Amount = new TokenAmount(t0, reserves[0]); 201 | const token1Amount = new TokenAmount(t1, reserves[1]); 202 | return new Pair(token0Amount, token1Amount); 203 | } 204 | 205 | _getPairAddress(tokenA, tokenB) { 206 | return Pair.getAddress(tokenA, tokenB); 207 | } 208 | 209 | _asToken(symbol) { 210 | const json = tokens[symbol]; 211 | return new Token( 212 | ChainId.MAINNET, 213 | json.address, 214 | json.decimals, 215 | json.symbol, 216 | json.name 217 | ); 218 | } 219 | 220 | _currencyCombinations( 221 | sym0, 222 | sym1, 223 | basesToCheckTradesAgainst = ["WBCH", "flexUSD"] 224 | ) { 225 | return super 226 | ._currencyCombinations(sym0, sym1, basesToCheckTradesAgainst) 227 | .map(([tokenJson0, tokenJson1]) => [ 228 | this._asToken(tokenJson0), 229 | this._asToken(tokenJson1), 230 | ]) 231 | .filter(([token0, token1]) => !token0.equals(token1)); 232 | } 233 | 234 | _isEther(token) { 235 | return token.symbol === "WBCH"; 236 | } 237 | } 238 | 239 | export default Benswap; 240 | -------------------------------------------------------------------------------- /dex/mistswap.js: -------------------------------------------------------------------------------- 1 | import BigNumber from "bignumber.js"; 2 | import { parseUnits } from "@ethersproject/units"; 3 | import { 4 | mainnet, 5 | abis, 6 | Dex, 7 | tokens, 8 | wallet, 9 | gasPrice, 10 | web3, 11 | newContract, 12 | } from "./base.js"; 13 | import { 14 | computePairAddress, 15 | Pair, 16 | CurrencyAmount, 17 | Trade, 18 | JSBI, 19 | Token, 20 | ChainId, 21 | Router, 22 | SmartBCH, 23 | } from "@mistswapdex/sdk"; 24 | 25 | class Mistswap extends Dex { 26 | SMARTBCH = SmartBCH.onChain(ChainId.SMARTBCH); 27 | routerContract = newContract(abis.mistswapRouter, mainnet.mistswap.router); 28 | 29 | async getQuotes([symIn, symOut], baseAmount) { 30 | const tokenIn = this._asToken(symIn); 31 | const tokenOut = this._asToken(symOut); 32 | const bid = await this._getOutputAmount( 33 | tokenIn, 34 | tokenOut, 35 | baseAmount, 36 | true 37 | ); 38 | 39 | const ask = await this._getOutputAmount( 40 | tokenOut, 41 | tokenIn, 42 | baseAmount, 43 | false 44 | ); 45 | return [new BigNumber(bid), new BigNumber(ask)]; 46 | } 47 | 48 | async _getOutputAmount(tokenIn, tokenOut, amount, isExactIn = true) { 49 | const trade = await this._trade(tokenIn, tokenOut, amount, isExactIn); 50 | return (isExactIn ? trade.outputAmount : trade.inputAmount).toSignificant( 51 | 6 52 | ); 53 | } 54 | 55 | async swap(symIn, symOut, amountIn, amountOut) { 56 | const isExactIn = amountIn !== undefined && amountOut === undefined; 57 | const tokenIn = this._asToken(symIn); 58 | const tokenOut = this._asToken(symOut); 59 | const trade = await this._trade( 60 | tokenIn, 61 | tokenOut, 62 | amountIn || amountOut, 63 | isExactIn 64 | ); 65 | const { methodName, args, value } = Router.swapCallParameters( 66 | trade, 67 | this.DEFAULT_SWAP_OPTIONS 68 | ); 69 | const data = this.routerContract.methods[methodName](...args).encodeABI(); 70 | const tx = { 71 | from: wallet, 72 | to: this.routerContract.options.address, 73 | data: data, 74 | value: value, 75 | }; 76 | tx.gas = await web3.eth.estimateGas(tx); 77 | tx.gasPrice = gasPrice; 78 | return await web3.eth.sendTransaction(tx); 79 | } 80 | 81 | async _trade( 82 | tokenIn, 83 | tokenOut, 84 | amount, 85 | isExactIn, 86 | { maxHops } = this.TRADES_OPTIONS 87 | ) { 88 | const allowedPairs = await this._pairs(tokenIn, tokenOut); 89 | 90 | tokenIn = this._isEther(tokenIn) ? this.SMARTBCH : tokenIn; 91 | tokenOut = this._isEther(tokenOut) ? this.SMARTBCH : tokenOut; 92 | 93 | const parsedAmount = this._parseAmount( 94 | amount.toString(), 95 | isExactIn ? tokenIn : tokenOut 96 | ); 97 | 98 | if (maxHops === 1) { 99 | return this._bestTrades( 100 | allowedPairs, 101 | tokenIn, 102 | tokenOut, 103 | parsedAmount, 104 | isExactIn, 105 | { 106 | maxHops: 1, 107 | maxNumResults: 1, 108 | } 109 | )[0]; 110 | } 111 | // search through trades with varying hops, find best trade out of them 112 | let bestTradeSoFar; 113 | for (let i = 1; i <= maxHops; i++) { 114 | const currentTrade = this._bestTrades( 115 | allowedPairs, 116 | tokenIn, 117 | tokenOut, 118 | parsedAmount, 119 | isExactIn, 120 | { 121 | maxHops: i, 122 | maxNumResults: 1, 123 | } 124 | )[0]; 125 | if ( 126 | this._isTradeBetter( 127 | bestTradeSoFar, 128 | currentTrade, 129 | this.BETTER_TRADE_LESS_HOPS_THRESHOLD 130 | ) 131 | ) { 132 | bestTradeSoFar = currentTrade; 133 | } 134 | } 135 | return bestTradeSoFar; 136 | } 137 | 138 | _isTradeBetter(tradeA, tradeB, minimumDelta = this.ZERO_PERCENT) { 139 | if (tradeA && !tradeB) return false; 140 | if (tradeB && !tradeA) return true; 141 | if (!tradeA || !tradeB) return undefined; 142 | 143 | if ( 144 | tradeA.tradeType !== tradeB.tradeType || 145 | !tradeA.inputAmount.currency.equals(tradeB.inputAmount.currency) || 146 | !tradeB.outputAmount.currency.equals(tradeB.outputAmount.currency) 147 | ) { 148 | throw new Error("Comparing incomparable trades"); 149 | } 150 | 151 | if (minimumDelta.equalTo(this.ZERO_PERCENT)) { 152 | return tradeA.executionPrice.lessThan(tradeB.executionPrice); 153 | } else { 154 | return tradeA.executionPrice.asFraction 155 | .multiply(minimumDelta.add(this.ONE_HUNDRED_PERCENT)) 156 | .lessThan(tradeB.executionPrice); 157 | } 158 | } 159 | 160 | _bestTrades( 161 | allowedPairs, 162 | tokenIn, 163 | tokenOut, 164 | parsedAmount, 165 | isExactIn, 166 | options 167 | ) { 168 | return isExactIn 169 | ? Trade.bestTradeExactIn(allowedPairs, parsedAmount, tokenOut, options) 170 | : Trade.bestTradeExactOut(allowedPairs, tokenIn, parsedAmount, options); 171 | } 172 | 173 | async _pairs(token0, token1) { 174 | return ( 175 | await Promise.all( 176 | this._currencyCombinations(token0.symbol, token1.symbol).map( 177 | async ([token0, token1]) => { 178 | return await this._pairOf(token0, token1); 179 | } 180 | ) 181 | ) 182 | ).filter((pair) => pair !== undefined); 183 | } 184 | 185 | async _pairOf(token0, token1) { 186 | const pairAddress = this._getPairAddress(token0, token1); 187 | const contract = newContract(abis.uniswapV2Pair, pairAddress); 188 | [token0, token1] = token0.sortsBefore(token1) 189 | ? [token0, token1] 190 | : [token1, token0]; 191 | 192 | return contract.methods 193 | .getReserves() 194 | .call() 195 | .then((reserves) => { 196 | return new Pair( 197 | CurrencyAmount.fromRawAmount(token0, reserves.reserve0.toString()), 198 | CurrencyAmount.fromRawAmount(token1, reserves.reserve1.toString()) 199 | ); 200 | }) 201 | .catch(() => { 202 | return undefined; 203 | }); 204 | } 205 | 206 | _getPairAddress(tokenA, tokenB) { 207 | return computePairAddress({ 208 | factoryAddress: mainnet.mistswap.factory, 209 | tokenA, 210 | tokenB, 211 | }); 212 | } 213 | 214 | _parseAmount(amount, tokenIn) { 215 | const parsedAmount = parseUnits(amount, tokenIn.decimals).toString(); 216 | return CurrencyAmount.fromRawAmount(tokenIn, JSBI.BigInt(parsedAmount)); 217 | } 218 | 219 | _asToken(symbol) { 220 | const json = tokens[symbol]; 221 | return new Token( 222 | ChainId.SMARTBCH, 223 | json.address, 224 | json.decimals, 225 | json.symbol, 226 | json.name 227 | ); 228 | } 229 | 230 | _isEther(token) { 231 | return token.symbol === "WBCH"; 232 | } 233 | 234 | _currencyCombinations( 235 | sym0, 236 | sym1, 237 | basesToCheckTradesAgainst = ["WBCH", "flexUSD"] 238 | ) { 239 | return super 240 | ._currencyCombinations(sym0, sym1, basesToCheckTradesAgainst) 241 | .map(([tokenJson0, tokenJson1]) => [ 242 | this._asToken(tokenJson0), 243 | this._asToken(tokenJson1), 244 | ]) 245 | .filter(([token0, token1]) => !token0.equals(token1)); 246 | } 247 | } 248 | 249 | export default Mistswap; 250 | -------------------------------------------------------------------------------- /contracts/PancakePair.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 2 | 3 | import './interfaces/IPancakePair.sol'; 4 | import './PancakeERC20.sol'; 5 | import './libraries/Math.sol'; 6 | import './libraries/UQ112x112.sol'; 7 | import './interfaces/IERC20.sol'; 8 | import './interfaces/IPancakeFactory.sol'; 9 | import './interfaces/IPancakeCallee.sol'; 10 | 11 | contract PancakePair is IPancakePair, PancakeERC20 { 12 | using SafeMath for uint; 13 | using UQ112x112 for uint224; 14 | 15 | uint public constant MINIMUM_LIQUIDITY = 10**3; 16 | bytes4 private constant SELECTOR = bytes4(keccak256(bytes('transfer(address,uint256)'))); 17 | 18 | address public factory; 19 | address public token0; 20 | address public token1; 21 | 22 | uint112 private reserve0; // uses single storage slot, accessible via getReserves 23 | uint112 private reserve1; // uses single storage slot, accessible via getReserves 24 | uint32 private blockTimestampLast; // uses single storage slot, accessible via getReserves 25 | 26 | uint public price0CumulativeLast; 27 | uint public price1CumulativeLast; 28 | uint public kLast; // reserve0 * reserve1, as of immediately after the most recent liquidity event 29 | 30 | uint private unlocked = 1; 31 | modifier lock() { 32 | require(unlocked == 1, 'BenSwap: LOCKED'); 33 | unlocked = 0; 34 | _; 35 | unlocked = 1; 36 | } 37 | 38 | function getReserves() public view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast) { 39 | _reserve0 = reserve0; 40 | _reserve1 = reserve1; 41 | _blockTimestampLast = blockTimestampLast; 42 | } 43 | 44 | function _safeTransfer(address token, address to, uint value) private { 45 | (bool success, bytes memory data) = token.call(abi.encodeWithSelector(SELECTOR, to, value)); 46 | require(success && (data.length == 0 || abi.decode(data, (bool))), 'BenSwap: TRANSFER_FAILED'); 47 | } 48 | 49 | event Mint(address indexed sender, uint amount0, uint amount1); 50 | event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); 51 | event Swap( 52 | address indexed sender, 53 | uint amount0In, 54 | uint amount1In, 55 | uint amount0Out, 56 | uint amount1Out, 57 | address indexed to 58 | ); 59 | event Sync(uint112 reserve0, uint112 reserve1); 60 | 61 | constructor() public { 62 | factory = msg.sender; 63 | } 64 | 65 | // called once by the factory at time of deployment 66 | function initialize(address _token0, address _token1) external { 67 | require(msg.sender == factory, 'BenSwap: FORBIDDEN'); // sufficient check 68 | token0 = _token0; 69 | token1 = _token1; 70 | } 71 | 72 | // update reserves and, on the first call per block, price accumulators 73 | function _update(uint balance0, uint balance1, uint112 _reserve0, uint112 _reserve1) private { 74 | require(balance0 <= uint112(-1) && balance1 <= uint112(-1), 'BenSwap: OVERFLOW'); 75 | uint32 blockTimestamp = uint32(block.timestamp % 2**32); 76 | uint32 timeElapsed = blockTimestamp - blockTimestampLast; // overflow is desired 77 | if (timeElapsed > 0 && _reserve0 != 0 && _reserve1 != 0) { 78 | // * never overflows, and + overflow is desired 79 | price0CumulativeLast += uint(UQ112x112.encode(_reserve1).uqdiv(_reserve0)) * timeElapsed; 80 | price1CumulativeLast += uint(UQ112x112.encode(_reserve0).uqdiv(_reserve1)) * timeElapsed; 81 | } 82 | reserve0 = uint112(balance0); 83 | reserve1 = uint112(balance1); 84 | blockTimestampLast = blockTimestamp; 85 | emit Sync(reserve0, reserve1); 86 | } 87 | 88 | // if fee is on, mint liquidity equivalent to 1/6th of the growth in sqrt(k) 89 | function _mintFee(uint112 _reserve0, uint112 _reserve1) private returns (bool feeOn) { 90 | address feeTo = IPancakeFactory(factory).feeTo(); 91 | feeOn = feeTo != address(0); 92 | uint _kLast = kLast; // gas savings 93 | if (feeOn) { 94 | if (_kLast != 0) { 95 | uint rootK = Math.sqrt(uint(_reserve0).mul(_reserve1)); 96 | uint rootKLast = Math.sqrt(_kLast); 97 | if (rootK > rootKLast) { 98 | uint numerator = totalSupply.mul(rootK.sub(rootKLast)); 99 | uint denominator = rootK.mul(3).add(rootKLast); 100 | uint liquidity = numerator / denominator; 101 | if (liquidity > 0) _mint(feeTo, liquidity); 102 | } 103 | } 104 | } else if (_kLast != 0) { 105 | kLast = 0; 106 | } 107 | } 108 | 109 | // this low-level function should be called from a contract which performs important safety checks 110 | function mint(address to) external lock returns (uint liquidity) { 111 | (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings 112 | uint balance0 = IERC20(token0).balanceOf(address(this)); 113 | uint balance1 = IERC20(token1).balanceOf(address(this)); 114 | uint amount0 = balance0.sub(_reserve0); 115 | uint amount1 = balance1.sub(_reserve1); 116 | 117 | bool feeOn = _mintFee(_reserve0, _reserve1); 118 | uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee 119 | if (_totalSupply == 0) { 120 | liquidity = Math.sqrt(amount0.mul(amount1)).sub(MINIMUM_LIQUIDITY); 121 | _mint(address(0), MINIMUM_LIQUIDITY); // permanently lock the first MINIMUM_LIQUIDITY tokens 122 | } else { 123 | liquidity = Math.min(amount0.mul(_totalSupply) / _reserve0, amount1.mul(_totalSupply) / _reserve1); 124 | } 125 | require(liquidity > 0, 'BenSwap: INSUFFICIENT_LIQUIDITY_MINTED'); 126 | _mint(to, liquidity); 127 | 128 | _update(balance0, balance1, _reserve0, _reserve1); 129 | if (feeOn) kLast = uint(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date 130 | emit Mint(msg.sender, amount0, amount1); 131 | } 132 | 133 | // this low-level function should be called from a contract which performs important safety checks 134 | function burn(address to) external lock returns (uint amount0, uint amount1) { 135 | (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings 136 | address _token0 = token0; // gas savings 137 | address _token1 = token1; // gas savings 138 | uint balance0 = IERC20(_token0).balanceOf(address(this)); 139 | uint balance1 = IERC20(_token1).balanceOf(address(this)); 140 | uint liquidity = balanceOf[address(this)]; 141 | 142 | bool feeOn = _mintFee(_reserve0, _reserve1); 143 | uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee 144 | amount0 = liquidity.mul(balance0) / _totalSupply; // using balances ensures pro-rata distribution 145 | amount1 = liquidity.mul(balance1) / _totalSupply; // using balances ensures pro-rata distribution 146 | require(amount0 > 0 && amount1 > 0, 'BenSwap: INSUFFICIENT_LIQUIDITY_BURNED'); 147 | _burn(address(this), liquidity); 148 | _safeTransfer(_token0, to, amount0); 149 | _safeTransfer(_token1, to, amount1); 150 | balance0 = IERC20(_token0).balanceOf(address(this)); 151 | balance1 = IERC20(_token1).balanceOf(address(this)); 152 | 153 | _update(balance0, balance1, _reserve0, _reserve1); 154 | if (feeOn) kLast = uint(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date 155 | emit Burn(msg.sender, amount0, amount1, to); 156 | } 157 | 158 | // this low-level function should be called from a contract which performs important safety checks 159 | function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external lock { 160 | require(amount0Out > 0 || amount1Out > 0, 'BenSwap: INSUFFICIENT_OUTPUT_AMOUNT'); 161 | (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings 162 | require(amount0Out < _reserve0 && amount1Out < _reserve1, 'BenSwap: INSUFFICIENT_LIQUIDITY'); 163 | 164 | uint balance0; 165 | uint balance1; 166 | { // scope for _token{0,1}, avoids stack too deep errors 167 | address _token0 = token0; 168 | address _token1 = token1; 169 | require(to != _token0 && to != _token1, 'BenSwap: INVALID_TO'); 170 | if (amount0Out > 0) _safeTransfer(_token0, to, amount0Out); // optimistically transfer tokens 171 | if (amount1Out > 0) _safeTransfer(_token1, to, amount1Out); // optimistically transfer tokens 172 | if (data.length > 0) IPancakeCallee(to).pancakeCall(msg.sender, amount0Out, amount1Out, data); 173 | balance0 = IERC20(_token0).balanceOf(address(this)); 174 | balance1 = IERC20(_token1).balanceOf(address(this)); 175 | } 176 | uint amount0In = balance0 > _reserve0 - amount0Out ? balance0 - (_reserve0 - amount0Out) : 0; 177 | uint amount1In = balance1 > _reserve1 - amount1Out ? balance1 - (_reserve1 - amount1Out) : 0; 178 | require(amount0In > 0 || amount1In > 0, 'BenSwap: INSUFFICIENT_INPUT_AMOUNT'); 179 | { // scope for reserve{0,1}Adjusted, avoids stack too deep errors 180 | uint balance0Adjusted = balance0.mul(1000).sub(amount0In.mul(2)); 181 | uint balance1Adjusted = balance1.mul(1000).sub(amount1In.mul(2)); 182 | require(balance0Adjusted.mul(balance1Adjusted) >= uint(_reserve0).mul(_reserve1).mul(1000**2), 'BenSwap: K'); 183 | } 184 | 185 | _update(balance0, balance1, _reserve0, _reserve1); 186 | emit Swap(msg.sender, amount0In, amount1In, amount0Out, amount1Out, to); 187 | } 188 | 189 | // force balances to match reserves 190 | function skim(address to) external lock { 191 | address _token0 = token0; // gas savings 192 | address _token1 = token1; // gas savings 193 | _safeTransfer(_token0, to, IERC20(_token0).balanceOf(address(this)).sub(reserve0)); 194 | _safeTransfer(_token1, to, IERC20(_token1).balanceOf(address(this)).sub(reserve1)); 195 | } 196 | 197 | // force reserves to match balances 198 | function sync() external lock { 199 | _update(IERC20(token0).balanceOf(address(this)), IERC20(token1).balanceOf(address(this)), reserve0, reserve1); 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /abis/IUniswapV2Pair.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "anonymous": false, 4 | "inputs": [ 5 | { 6 | "indexed": true, 7 | "internalType": "address", 8 | "name": "owner", 9 | "type": "address" 10 | }, 11 | { 12 | "indexed": true, 13 | "internalType": "address", 14 | "name": "spender", 15 | "type": "address" 16 | }, 17 | { 18 | "indexed": false, 19 | "internalType": "uint256", 20 | "name": "value", 21 | "type": "uint256" 22 | } 23 | ], 24 | "name": "Approval", 25 | "type": "event" 26 | }, 27 | { 28 | "anonymous": false, 29 | "inputs": [ 30 | { 31 | "indexed": true, 32 | "internalType": "address", 33 | "name": "sender", 34 | "type": "address" 35 | }, 36 | { 37 | "indexed": false, 38 | "internalType": "uint256", 39 | "name": "amount0", 40 | "type": "uint256" 41 | }, 42 | { 43 | "indexed": false, 44 | "internalType": "uint256", 45 | "name": "amount1", 46 | "type": "uint256" 47 | }, 48 | { 49 | "indexed": true, 50 | "internalType": "address", 51 | "name": "to", 52 | "type": "address" 53 | } 54 | ], 55 | "name": "Burn", 56 | "type": "event" 57 | }, 58 | { 59 | "anonymous": false, 60 | "inputs": [ 61 | { 62 | "indexed": true, 63 | "internalType": "address", 64 | "name": "sender", 65 | "type": "address" 66 | }, 67 | { 68 | "indexed": false, 69 | "internalType": "uint256", 70 | "name": "amount0", 71 | "type": "uint256" 72 | }, 73 | { 74 | "indexed": false, 75 | "internalType": "uint256", 76 | "name": "amount1", 77 | "type": "uint256" 78 | } 79 | ], 80 | "name": "Mint", 81 | "type": "event" 82 | }, 83 | { 84 | "anonymous": false, 85 | "inputs": [ 86 | { 87 | "indexed": true, 88 | "internalType": "address", 89 | "name": "sender", 90 | "type": "address" 91 | }, 92 | { 93 | "indexed": false, 94 | "internalType": "uint256", 95 | "name": "amount0In", 96 | "type": "uint256" 97 | }, 98 | { 99 | "indexed": false, 100 | "internalType": "uint256", 101 | "name": "amount1In", 102 | "type": "uint256" 103 | }, 104 | { 105 | "indexed": false, 106 | "internalType": "uint256", 107 | "name": "amount0Out", 108 | "type": "uint256" 109 | }, 110 | { 111 | "indexed": false, 112 | "internalType": "uint256", 113 | "name": "amount1Out", 114 | "type": "uint256" 115 | }, 116 | { 117 | "indexed": true, 118 | "internalType": "address", 119 | "name": "to", 120 | "type": "address" 121 | } 122 | ], 123 | "name": "Swap", 124 | "type": "event" 125 | }, 126 | { 127 | "anonymous": false, 128 | "inputs": [ 129 | { 130 | "indexed": false, 131 | "internalType": "uint112", 132 | "name": "reserve0", 133 | "type": "uint112" 134 | }, 135 | { 136 | "indexed": false, 137 | "internalType": "uint112", 138 | "name": "reserve1", 139 | "type": "uint112" 140 | } 141 | ], 142 | "name": "Sync", 143 | "type": "event" 144 | }, 145 | { 146 | "anonymous": false, 147 | "inputs": [ 148 | { 149 | "indexed": true, 150 | "internalType": "address", 151 | "name": "from", 152 | "type": "address" 153 | }, 154 | { 155 | "indexed": true, 156 | "internalType": "address", 157 | "name": "to", 158 | "type": "address" 159 | }, 160 | { 161 | "indexed": false, 162 | "internalType": "uint256", 163 | "name": "value", 164 | "type": "uint256" 165 | } 166 | ], 167 | "name": "Transfer", 168 | "type": "event" 169 | }, 170 | { 171 | "inputs": [], 172 | "name": "DOMAIN_SEPARATOR", 173 | "outputs": [ 174 | { 175 | "internalType": "bytes32", 176 | "name": "", 177 | "type": "bytes32" 178 | } 179 | ], 180 | "stateMutability": "view", 181 | "type": "function" 182 | }, 183 | { 184 | "inputs": [], 185 | "name": "MINIMUM_LIQUIDITY", 186 | "outputs": [ 187 | { 188 | "internalType": "uint256", 189 | "name": "", 190 | "type": "uint256" 191 | } 192 | ], 193 | "stateMutability": "pure", 194 | "type": "function" 195 | }, 196 | { 197 | "inputs": [], 198 | "name": "PERMIT_TYPEHASH", 199 | "outputs": [ 200 | { 201 | "internalType": "bytes32", 202 | "name": "", 203 | "type": "bytes32" 204 | } 205 | ], 206 | "stateMutability": "pure", 207 | "type": "function" 208 | }, 209 | { 210 | "inputs": [ 211 | { 212 | "internalType": "address", 213 | "name": "owner", 214 | "type": "address" 215 | }, 216 | { 217 | "internalType": "address", 218 | "name": "spender", 219 | "type": "address" 220 | } 221 | ], 222 | "name": "allowance", 223 | "outputs": [ 224 | { 225 | "internalType": "uint256", 226 | "name": "", 227 | "type": "uint256" 228 | } 229 | ], 230 | "stateMutability": "view", 231 | "type": "function" 232 | }, 233 | { 234 | "inputs": [ 235 | { 236 | "internalType": "address", 237 | "name": "spender", 238 | "type": "address" 239 | }, 240 | { 241 | "internalType": "uint256", 242 | "name": "value", 243 | "type": "uint256" 244 | } 245 | ], 246 | "name": "approve", 247 | "outputs": [ 248 | { 249 | "internalType": "bool", 250 | "name": "", 251 | "type": "bool" 252 | } 253 | ], 254 | "stateMutability": "nonpayable", 255 | "type": "function" 256 | }, 257 | { 258 | "inputs": [ 259 | { 260 | "internalType": "address", 261 | "name": "owner", 262 | "type": "address" 263 | } 264 | ], 265 | "name": "balanceOf", 266 | "outputs": [ 267 | { 268 | "internalType": "uint256", 269 | "name": "", 270 | "type": "uint256" 271 | } 272 | ], 273 | "stateMutability": "view", 274 | "type": "function" 275 | }, 276 | { 277 | "inputs": [ 278 | { 279 | "internalType": "address", 280 | "name": "to", 281 | "type": "address" 282 | } 283 | ], 284 | "name": "burn", 285 | "outputs": [ 286 | { 287 | "internalType": "uint256", 288 | "name": "amount0", 289 | "type": "uint256" 290 | }, 291 | { 292 | "internalType": "uint256", 293 | "name": "amount1", 294 | "type": "uint256" 295 | } 296 | ], 297 | "stateMutability": "nonpayable", 298 | "type": "function" 299 | }, 300 | { 301 | "inputs": [], 302 | "name": "decimals", 303 | "outputs": [ 304 | { 305 | "internalType": "uint8", 306 | "name": "", 307 | "type": "uint8" 308 | } 309 | ], 310 | "stateMutability": "pure", 311 | "type": "function" 312 | }, 313 | { 314 | "inputs": [], 315 | "name": "factory", 316 | "outputs": [ 317 | { 318 | "internalType": "address", 319 | "name": "", 320 | "type": "address" 321 | } 322 | ], 323 | "stateMutability": "view", 324 | "type": "function" 325 | }, 326 | { 327 | "inputs": [], 328 | "name": "getReserves", 329 | "outputs": [ 330 | { 331 | "internalType": "uint112", 332 | "name": "reserve0", 333 | "type": "uint112" 334 | }, 335 | { 336 | "internalType": "uint112", 337 | "name": "reserve1", 338 | "type": "uint112" 339 | }, 340 | { 341 | "internalType": "uint32", 342 | "name": "blockTimestampLast", 343 | "type": "uint32" 344 | } 345 | ], 346 | "stateMutability": "view", 347 | "type": "function" 348 | }, 349 | { 350 | "inputs": [ 351 | { 352 | "internalType": "address", 353 | "name": "", 354 | "type": "address" 355 | }, 356 | { 357 | "internalType": "address", 358 | "name": "", 359 | "type": "address" 360 | } 361 | ], 362 | "name": "initialize", 363 | "outputs": [], 364 | "stateMutability": "nonpayable", 365 | "type": "function" 366 | }, 367 | { 368 | "inputs": [], 369 | "name": "kLast", 370 | "outputs": [ 371 | { 372 | "internalType": "uint256", 373 | "name": "", 374 | "type": "uint256" 375 | } 376 | ], 377 | "stateMutability": "view", 378 | "type": "function" 379 | }, 380 | { 381 | "inputs": [ 382 | { 383 | "internalType": "address", 384 | "name": "to", 385 | "type": "address" 386 | } 387 | ], 388 | "name": "mint", 389 | "outputs": [ 390 | { 391 | "internalType": "uint256", 392 | "name": "liquidity", 393 | "type": "uint256" 394 | } 395 | ], 396 | "stateMutability": "nonpayable", 397 | "type": "function" 398 | }, 399 | { 400 | "inputs": [], 401 | "name": "name", 402 | "outputs": [ 403 | { 404 | "internalType": "string", 405 | "name": "", 406 | "type": "string" 407 | } 408 | ], 409 | "stateMutability": "pure", 410 | "type": "function" 411 | }, 412 | { 413 | "inputs": [ 414 | { 415 | "internalType": "address", 416 | "name": "owner", 417 | "type": "address" 418 | } 419 | ], 420 | "name": "nonces", 421 | "outputs": [ 422 | { 423 | "internalType": "uint256", 424 | "name": "", 425 | "type": "uint256" 426 | } 427 | ], 428 | "stateMutability": "view", 429 | "type": "function" 430 | }, 431 | { 432 | "inputs": [ 433 | { 434 | "internalType": "address", 435 | "name": "owner", 436 | "type": "address" 437 | }, 438 | { 439 | "internalType": "address", 440 | "name": "spender", 441 | "type": "address" 442 | }, 443 | { 444 | "internalType": "uint256", 445 | "name": "value", 446 | "type": "uint256" 447 | }, 448 | { 449 | "internalType": "uint256", 450 | "name": "deadline", 451 | "type": "uint256" 452 | }, 453 | { 454 | "internalType": "uint8", 455 | "name": "v", 456 | "type": "uint8" 457 | }, 458 | { 459 | "internalType": "bytes32", 460 | "name": "r", 461 | "type": "bytes32" 462 | }, 463 | { 464 | "internalType": "bytes32", 465 | "name": "s", 466 | "type": "bytes32" 467 | } 468 | ], 469 | "name": "permit", 470 | "outputs": [], 471 | "stateMutability": "nonpayable", 472 | "type": "function" 473 | }, 474 | { 475 | "inputs": [], 476 | "name": "price0CumulativeLast", 477 | "outputs": [ 478 | { 479 | "internalType": "uint256", 480 | "name": "", 481 | "type": "uint256" 482 | } 483 | ], 484 | "stateMutability": "view", 485 | "type": "function" 486 | }, 487 | { 488 | "inputs": [], 489 | "name": "price1CumulativeLast", 490 | "outputs": [ 491 | { 492 | "internalType": "uint256", 493 | "name": "", 494 | "type": "uint256" 495 | } 496 | ], 497 | "stateMutability": "view", 498 | "type": "function" 499 | }, 500 | { 501 | "inputs": [ 502 | { 503 | "internalType": "address", 504 | "name": "to", 505 | "type": "address" 506 | } 507 | ], 508 | "name": "skim", 509 | "outputs": [], 510 | "stateMutability": "nonpayable", 511 | "type": "function" 512 | }, 513 | { 514 | "inputs": [ 515 | { 516 | "internalType": "uint256", 517 | "name": "amount0Out", 518 | "type": "uint256" 519 | }, 520 | { 521 | "internalType": "uint256", 522 | "name": "amount1Out", 523 | "type": "uint256" 524 | }, 525 | { 526 | "internalType": "address", 527 | "name": "to", 528 | "type": "address" 529 | }, 530 | { 531 | "internalType": "bytes", 532 | "name": "data", 533 | "type": "bytes" 534 | } 535 | ], 536 | "name": "swap", 537 | "outputs": [], 538 | "stateMutability": "nonpayable", 539 | "type": "function" 540 | }, 541 | { 542 | "inputs": [], 543 | "name": "symbol", 544 | "outputs": [ 545 | { 546 | "internalType": "string", 547 | "name": "", 548 | "type": "string" 549 | } 550 | ], 551 | "stateMutability": "pure", 552 | "type": "function" 553 | }, 554 | { 555 | "inputs": [], 556 | "name": "sync", 557 | "outputs": [], 558 | "stateMutability": "nonpayable", 559 | "type": "function" 560 | }, 561 | { 562 | "inputs": [], 563 | "name": "token0", 564 | "outputs": [ 565 | { 566 | "internalType": "address", 567 | "name": "", 568 | "type": "address" 569 | } 570 | ], 571 | "stateMutability": "view", 572 | "type": "function" 573 | }, 574 | { 575 | "inputs": [], 576 | "name": "token1", 577 | "outputs": [ 578 | { 579 | "internalType": "address", 580 | "name": "", 581 | "type": "address" 582 | } 583 | ], 584 | "stateMutability": "view", 585 | "type": "function" 586 | }, 587 | { 588 | "inputs": [], 589 | "name": "totalSupply", 590 | "outputs": [ 591 | { 592 | "internalType": "uint256", 593 | "name": "", 594 | "type": "uint256" 595 | } 596 | ], 597 | "stateMutability": "view", 598 | "type": "function" 599 | }, 600 | { 601 | "inputs": [ 602 | { 603 | "internalType": "address", 604 | "name": "to", 605 | "type": "address" 606 | }, 607 | { 608 | "internalType": "uint256", 609 | "name": "value", 610 | "type": "uint256" 611 | } 612 | ], 613 | "name": "transfer", 614 | "outputs": [ 615 | { 616 | "internalType": "bool", 617 | "name": "", 618 | "type": "bool" 619 | } 620 | ], 621 | "stateMutability": "nonpayable", 622 | "type": "function" 623 | }, 624 | { 625 | "inputs": [ 626 | { 627 | "internalType": "address", 628 | "name": "from", 629 | "type": "address" 630 | }, 631 | { 632 | "internalType": "address", 633 | "name": "to", 634 | "type": "address" 635 | }, 636 | { 637 | "internalType": "uint256", 638 | "name": "value", 639 | "type": "uint256" 640 | } 641 | ], 642 | "name": "transferFrom", 643 | "outputs": [ 644 | { 645 | "internalType": "bool", 646 | "name": "", 647 | "type": "bool" 648 | } 649 | ], 650 | "stateMutability": "nonpayable", 651 | "type": "function" 652 | } 653 | ] 654 | -------------------------------------------------------------------------------- /abis/PancakePair.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": true, 296 | "inputs": [], 297 | "name": "decimals", 298 | "outputs": [ 299 | { 300 | "internalType": "uint8", 301 | "name": "", 302 | "type": "uint8" 303 | } 304 | ], 305 | "payable": false, 306 | "stateMutability": "view", 307 | "type": "function" 308 | }, 309 | { 310 | "constant": true, 311 | "inputs": [], 312 | "name": "factory", 313 | "outputs": [ 314 | { 315 | "internalType": "address", 316 | "name": "", 317 | "type": "address" 318 | } 319 | ], 320 | "payable": false, 321 | "stateMutability": "view", 322 | "type": "function" 323 | }, 324 | { 325 | "constant": true, 326 | "inputs": [], 327 | "name": "kLast", 328 | "outputs": [ 329 | { 330 | "internalType": "uint256", 331 | "name": "", 332 | "type": "uint256" 333 | } 334 | ], 335 | "payable": false, 336 | "stateMutability": "view", 337 | "type": "function" 338 | }, 339 | { 340 | "constant": true, 341 | "inputs": [], 342 | "name": "name", 343 | "outputs": [ 344 | { 345 | "internalType": "string", 346 | "name": "", 347 | "type": "string" 348 | } 349 | ], 350 | "payable": false, 351 | "stateMutability": "view", 352 | "type": "function" 353 | }, 354 | { 355 | "constant": true, 356 | "inputs": [ 357 | { 358 | "internalType": "address", 359 | "name": "", 360 | "type": "address" 361 | } 362 | ], 363 | "name": "nonces", 364 | "outputs": [ 365 | { 366 | "internalType": "uint256", 367 | "name": "", 368 | "type": "uint256" 369 | } 370 | ], 371 | "payable": false, 372 | "stateMutability": "view", 373 | "type": "function" 374 | }, 375 | { 376 | "constant": false, 377 | "inputs": [ 378 | { 379 | "internalType": "address", 380 | "name": "owner", 381 | "type": "address" 382 | }, 383 | { 384 | "internalType": "address", 385 | "name": "spender", 386 | "type": "address" 387 | }, 388 | { 389 | "internalType": "uint256", 390 | "name": "value", 391 | "type": "uint256" 392 | }, 393 | { 394 | "internalType": "uint256", 395 | "name": "deadline", 396 | "type": "uint256" 397 | }, 398 | { 399 | "internalType": "uint8", 400 | "name": "v", 401 | "type": "uint8" 402 | }, 403 | { 404 | "internalType": "bytes32", 405 | "name": "r", 406 | "type": "bytes32" 407 | }, 408 | { 409 | "internalType": "bytes32", 410 | "name": "s", 411 | "type": "bytes32" 412 | } 413 | ], 414 | "name": "permit", 415 | "outputs": [], 416 | "payable": false, 417 | "stateMutability": "nonpayable", 418 | "type": "function" 419 | }, 420 | { 421 | "constant": true, 422 | "inputs": [], 423 | "name": "price0CumulativeLast", 424 | "outputs": [ 425 | { 426 | "internalType": "uint256", 427 | "name": "", 428 | "type": "uint256" 429 | } 430 | ], 431 | "payable": false, 432 | "stateMutability": "view", 433 | "type": "function" 434 | }, 435 | { 436 | "constant": true, 437 | "inputs": [], 438 | "name": "price1CumulativeLast", 439 | "outputs": [ 440 | { 441 | "internalType": "uint256", 442 | "name": "", 443 | "type": "uint256" 444 | } 445 | ], 446 | "payable": false, 447 | "stateMutability": "view", 448 | "type": "function" 449 | }, 450 | { 451 | "constant": true, 452 | "inputs": [], 453 | "name": "symbol", 454 | "outputs": [ 455 | { 456 | "internalType": "string", 457 | "name": "", 458 | "type": "string" 459 | } 460 | ], 461 | "payable": false, 462 | "stateMutability": "view", 463 | "type": "function" 464 | }, 465 | { 466 | "constant": true, 467 | "inputs": [], 468 | "name": "token0", 469 | "outputs": [ 470 | { 471 | "internalType": "address", 472 | "name": "", 473 | "type": "address" 474 | } 475 | ], 476 | "payable": false, 477 | "stateMutability": "view", 478 | "type": "function" 479 | }, 480 | { 481 | "constant": true, 482 | "inputs": [], 483 | "name": "token1", 484 | "outputs": [ 485 | { 486 | "internalType": "address", 487 | "name": "", 488 | "type": "address" 489 | } 490 | ], 491 | "payable": false, 492 | "stateMutability": "view", 493 | "type": "function" 494 | }, 495 | { 496 | "constant": true, 497 | "inputs": [], 498 | "name": "totalSupply", 499 | "outputs": [ 500 | { 501 | "internalType": "uint256", 502 | "name": "", 503 | "type": "uint256" 504 | } 505 | ], 506 | "payable": false, 507 | "stateMutability": "view", 508 | "type": "function" 509 | }, 510 | { 511 | "constant": false, 512 | "inputs": [ 513 | { 514 | "internalType": "address", 515 | "name": "to", 516 | "type": "address" 517 | }, 518 | { 519 | "internalType": "uint256", 520 | "name": "value", 521 | "type": "uint256" 522 | } 523 | ], 524 | "name": "transfer", 525 | "outputs": [ 526 | { 527 | "internalType": "bool", 528 | "name": "", 529 | "type": "bool" 530 | } 531 | ], 532 | "payable": false, 533 | "stateMutability": "nonpayable", 534 | "type": "function" 535 | }, 536 | { 537 | "constant": false, 538 | "inputs": [ 539 | { 540 | "internalType": "address", 541 | "name": "from", 542 | "type": "address" 543 | }, 544 | { 545 | "internalType": "address", 546 | "name": "to", 547 | "type": "address" 548 | }, 549 | { 550 | "internalType": "uint256", 551 | "name": "value", 552 | "type": "uint256" 553 | } 554 | ], 555 | "name": "transferFrom", 556 | "outputs": [ 557 | { 558 | "internalType": "bool", 559 | "name": "", 560 | "type": "bool" 561 | } 562 | ], 563 | "payable": false, 564 | "stateMutability": "nonpayable", 565 | "type": "function" 566 | }, 567 | { 568 | "constant": true, 569 | "inputs": [], 570 | "name": "getReserves", 571 | "outputs": [ 572 | { 573 | "internalType": "uint112", 574 | "name": "_reserve0", 575 | "type": "uint112" 576 | }, 577 | { 578 | "internalType": "uint112", 579 | "name": "_reserve1", 580 | "type": "uint112" 581 | }, 582 | { 583 | "internalType": "uint32", 584 | "name": "_blockTimestampLast", 585 | "type": "uint32" 586 | } 587 | ], 588 | "payable": false, 589 | "stateMutability": "view", 590 | "type": "function" 591 | }, 592 | { 593 | "constant": false, 594 | "inputs": [ 595 | { 596 | "internalType": "address", 597 | "name": "_token0", 598 | "type": "address" 599 | }, 600 | { 601 | "internalType": "address", 602 | "name": "_token1", 603 | "type": "address" 604 | } 605 | ], 606 | "name": "initialize", 607 | "outputs": [], 608 | "payable": false, 609 | "stateMutability": "nonpayable", 610 | "type": "function" 611 | }, 612 | { 613 | "constant": false, 614 | "inputs": [ 615 | { 616 | "internalType": "address", 617 | "name": "to", 618 | "type": "address" 619 | } 620 | ], 621 | "name": "mint", 622 | "outputs": [ 623 | { 624 | "internalType": "uint256", 625 | "name": "liquidity", 626 | "type": "uint256" 627 | } 628 | ], 629 | "payable": false, 630 | "stateMutability": "nonpayable", 631 | "type": "function" 632 | }, 633 | { 634 | "constant": false, 635 | "inputs": [ 636 | { 637 | "internalType": "address", 638 | "name": "to", 639 | "type": "address" 640 | } 641 | ], 642 | "name": "burn", 643 | "outputs": [ 644 | { 645 | "internalType": "uint256", 646 | "name": "amount0", 647 | "type": "uint256" 648 | }, 649 | { 650 | "internalType": "uint256", 651 | "name": "amount1", 652 | "type": "uint256" 653 | } 654 | ], 655 | "payable": false, 656 | "stateMutability": "nonpayable", 657 | "type": "function" 658 | }, 659 | { 660 | "constant": false, 661 | "inputs": [ 662 | { 663 | "internalType": "uint256", 664 | "name": "amount0Out", 665 | "type": "uint256" 666 | }, 667 | { 668 | "internalType": "uint256", 669 | "name": "amount1Out", 670 | "type": "uint256" 671 | }, 672 | { 673 | "internalType": "address", 674 | "name": "to", 675 | "type": "address" 676 | }, 677 | { 678 | "internalType": "bytes", 679 | "name": "data", 680 | "type": "bytes" 681 | } 682 | ], 683 | "name": "swap", 684 | "outputs": [], 685 | "payable": false, 686 | "stateMutability": "nonpayable", 687 | "type": "function" 688 | }, 689 | { 690 | "constant": false, 691 | "inputs": [ 692 | { 693 | "internalType": "address", 694 | "name": "to", 695 | "type": "address" 696 | } 697 | ], 698 | "name": "skim", 699 | "outputs": [], 700 | "payable": false, 701 | "stateMutability": "nonpayable", 702 | "type": "function" 703 | }, 704 | { 705 | "constant": false, 706 | "inputs": [], 707 | "name": "sync", 708 | "outputs": [], 709 | "payable": false, 710 | "stateMutability": "nonpayable", 711 | "type": "function" 712 | } 713 | ] 714 | -------------------------------------------------------------------------------- /abis/MistSwapRouter.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { "internalType": "address", "name": "_factory", "type": "address" }, 5 | { "internalType": "address", "name": "_WETH", "type": "address" } 6 | ], 7 | "stateMutability": "nonpayable", 8 | "type": "constructor" 9 | }, 10 | { 11 | "inputs": [], 12 | "name": "WETH", 13 | "outputs": [{ "internalType": "address", "name": "", "type": "address" }], 14 | "stateMutability": "view", 15 | "type": "function" 16 | }, 17 | { 18 | "inputs": [ 19 | { "internalType": "address", "name": "tokenA", "type": "address" }, 20 | { "internalType": "address", "name": "tokenB", "type": "address" }, 21 | { 22 | "internalType": "uint256", 23 | "name": "amountADesired", 24 | "type": "uint256" 25 | }, 26 | { 27 | "internalType": "uint256", 28 | "name": "amountBDesired", 29 | "type": "uint256" 30 | }, 31 | { "internalType": "uint256", "name": "amountAMin", "type": "uint256" }, 32 | { "internalType": "uint256", "name": "amountBMin", "type": "uint256" }, 33 | { "internalType": "address", "name": "to", "type": "address" }, 34 | { "internalType": "uint256", "name": "deadline", "type": "uint256" } 35 | ], 36 | "name": "addLiquidity", 37 | "outputs": [ 38 | { "internalType": "uint256", "name": "amountA", "type": "uint256" }, 39 | { "internalType": "uint256", "name": "amountB", "type": "uint256" }, 40 | { "internalType": "uint256", "name": "liquidity", "type": "uint256" } 41 | ], 42 | "stateMutability": "nonpayable", 43 | "type": "function" 44 | }, 45 | { 46 | "inputs": [ 47 | { "internalType": "address", "name": "token", "type": "address" }, 48 | { 49 | "internalType": "uint256", 50 | "name": "amountTokenDesired", 51 | "type": "uint256" 52 | }, 53 | { 54 | "internalType": "uint256", 55 | "name": "amountTokenMin", 56 | "type": "uint256" 57 | }, 58 | { "internalType": "uint256", "name": "amountETHMin", "type": "uint256" }, 59 | { "internalType": "address", "name": "to", "type": "address" }, 60 | { "internalType": "uint256", "name": "deadline", "type": "uint256" } 61 | ], 62 | "name": "addLiquidityETH", 63 | "outputs": [ 64 | { "internalType": "uint256", "name": "amountToken", "type": "uint256" }, 65 | { "internalType": "uint256", "name": "amountETH", "type": "uint256" }, 66 | { "internalType": "uint256", "name": "liquidity", "type": "uint256" } 67 | ], 68 | "stateMutability": "payable", 69 | "type": "function" 70 | }, 71 | { 72 | "inputs": [], 73 | "name": "factory", 74 | "outputs": [{ "internalType": "address", "name": "", "type": "address" }], 75 | "stateMutability": "view", 76 | "type": "function" 77 | }, 78 | { 79 | "inputs": [ 80 | { "internalType": "uint256", "name": "amountOut", "type": "uint256" }, 81 | { "internalType": "uint256", "name": "reserveIn", "type": "uint256" }, 82 | { "internalType": "uint256", "name": "reserveOut", "type": "uint256" } 83 | ], 84 | "name": "getAmountIn", 85 | "outputs": [ 86 | { "internalType": "uint256", "name": "amountIn", "type": "uint256" } 87 | ], 88 | "stateMutability": "pure", 89 | "type": "function" 90 | }, 91 | { 92 | "inputs": [ 93 | { "internalType": "uint256", "name": "amountIn", "type": "uint256" }, 94 | { "internalType": "uint256", "name": "reserveIn", "type": "uint256" }, 95 | { "internalType": "uint256", "name": "reserveOut", "type": "uint256" } 96 | ], 97 | "name": "getAmountOut", 98 | "outputs": [ 99 | { "internalType": "uint256", "name": "amountOut", "type": "uint256" } 100 | ], 101 | "stateMutability": "pure", 102 | "type": "function" 103 | }, 104 | { 105 | "inputs": [ 106 | { "internalType": "uint256", "name": "amountOut", "type": "uint256" }, 107 | { "internalType": "address[]", "name": "path", "type": "address[]" } 108 | ], 109 | "name": "getAmountsIn", 110 | "outputs": [ 111 | { "internalType": "uint256[]", "name": "amounts", "type": "uint256[]" } 112 | ], 113 | "stateMutability": "view", 114 | "type": "function" 115 | }, 116 | { 117 | "inputs": [ 118 | { "internalType": "uint256", "name": "amountIn", "type": "uint256" }, 119 | { "internalType": "address[]", "name": "path", "type": "address[]" } 120 | ], 121 | "name": "getAmountsOut", 122 | "outputs": [ 123 | { "internalType": "uint256[]", "name": "amounts", "type": "uint256[]" } 124 | ], 125 | "stateMutability": "view", 126 | "type": "function" 127 | }, 128 | { 129 | "inputs": [ 130 | { "internalType": "uint256", "name": "amountA", "type": "uint256" }, 131 | { "internalType": "uint256", "name": "reserveA", "type": "uint256" }, 132 | { "internalType": "uint256", "name": "reserveB", "type": "uint256" } 133 | ], 134 | "name": "quote", 135 | "outputs": [ 136 | { "internalType": "uint256", "name": "amountB", "type": "uint256" } 137 | ], 138 | "stateMutability": "pure", 139 | "type": "function" 140 | }, 141 | { 142 | "inputs": [ 143 | { "internalType": "address", "name": "tokenA", "type": "address" }, 144 | { "internalType": "address", "name": "tokenB", "type": "address" }, 145 | { "internalType": "uint256", "name": "liquidity", "type": "uint256" }, 146 | { "internalType": "uint256", "name": "amountAMin", "type": "uint256" }, 147 | { "internalType": "uint256", "name": "amountBMin", "type": "uint256" }, 148 | { "internalType": "address", "name": "to", "type": "address" }, 149 | { "internalType": "uint256", "name": "deadline", "type": "uint256" } 150 | ], 151 | "name": "removeLiquidity", 152 | "outputs": [ 153 | { "internalType": "uint256", "name": "amountA", "type": "uint256" }, 154 | { "internalType": "uint256", "name": "amountB", "type": "uint256" } 155 | ], 156 | "stateMutability": "nonpayable", 157 | "type": "function" 158 | }, 159 | { 160 | "inputs": [ 161 | { "internalType": "address", "name": "token", "type": "address" }, 162 | { "internalType": "uint256", "name": "liquidity", "type": "uint256" }, 163 | { 164 | "internalType": "uint256", 165 | "name": "amountTokenMin", 166 | "type": "uint256" 167 | }, 168 | { "internalType": "uint256", "name": "amountETHMin", "type": "uint256" }, 169 | { "internalType": "address", "name": "to", "type": "address" }, 170 | { "internalType": "uint256", "name": "deadline", "type": "uint256" } 171 | ], 172 | "name": "removeLiquidityETH", 173 | "outputs": [ 174 | { "internalType": "uint256", "name": "amountToken", "type": "uint256" }, 175 | { "internalType": "uint256", "name": "amountETH", "type": "uint256" } 176 | ], 177 | "stateMutability": "nonpayable", 178 | "type": "function" 179 | }, 180 | { 181 | "inputs": [ 182 | { "internalType": "address", "name": "token", "type": "address" }, 183 | { "internalType": "uint256", "name": "liquidity", "type": "uint256" }, 184 | { 185 | "internalType": "uint256", 186 | "name": "amountTokenMin", 187 | "type": "uint256" 188 | }, 189 | { "internalType": "uint256", "name": "amountETHMin", "type": "uint256" }, 190 | { "internalType": "address", "name": "to", "type": "address" }, 191 | { "internalType": "uint256", "name": "deadline", "type": "uint256" } 192 | ], 193 | "name": "removeLiquidityETHSupportingFeeOnTransferTokens", 194 | "outputs": [ 195 | { "internalType": "uint256", "name": "amountETH", "type": "uint256" } 196 | ], 197 | "stateMutability": "nonpayable", 198 | "type": "function" 199 | }, 200 | { 201 | "inputs": [ 202 | { "internalType": "address", "name": "token", "type": "address" }, 203 | { "internalType": "uint256", "name": "liquidity", "type": "uint256" }, 204 | { 205 | "internalType": "uint256", 206 | "name": "amountTokenMin", 207 | "type": "uint256" 208 | }, 209 | { "internalType": "uint256", "name": "amountETHMin", "type": "uint256" }, 210 | { "internalType": "address", "name": "to", "type": "address" }, 211 | { "internalType": "uint256", "name": "deadline", "type": "uint256" }, 212 | { "internalType": "bool", "name": "approveMax", "type": "bool" }, 213 | { "internalType": "uint8", "name": "v", "type": "uint8" }, 214 | { "internalType": "bytes32", "name": "r", "type": "bytes32" }, 215 | { "internalType": "bytes32", "name": "s", "type": "bytes32" } 216 | ], 217 | "name": "removeLiquidityETHWithPermit", 218 | "outputs": [ 219 | { "internalType": "uint256", "name": "amountToken", "type": "uint256" }, 220 | { "internalType": "uint256", "name": "amountETH", "type": "uint256" } 221 | ], 222 | "stateMutability": "nonpayable", 223 | "type": "function" 224 | }, 225 | { 226 | "inputs": [ 227 | { "internalType": "address", "name": "token", "type": "address" }, 228 | { "internalType": "uint256", "name": "liquidity", "type": "uint256" }, 229 | { 230 | "internalType": "uint256", 231 | "name": "amountTokenMin", 232 | "type": "uint256" 233 | }, 234 | { "internalType": "uint256", "name": "amountETHMin", "type": "uint256" }, 235 | { "internalType": "address", "name": "to", "type": "address" }, 236 | { "internalType": "uint256", "name": "deadline", "type": "uint256" }, 237 | { "internalType": "bool", "name": "approveMax", "type": "bool" }, 238 | { "internalType": "uint8", "name": "v", "type": "uint8" }, 239 | { "internalType": "bytes32", "name": "r", "type": "bytes32" }, 240 | { "internalType": "bytes32", "name": "s", "type": "bytes32" } 241 | ], 242 | "name": "removeLiquidityETHWithPermitSupportingFeeOnTransferTokens", 243 | "outputs": [ 244 | { "internalType": "uint256", "name": "amountETH", "type": "uint256" } 245 | ], 246 | "stateMutability": "nonpayable", 247 | "type": "function" 248 | }, 249 | { 250 | "inputs": [ 251 | { "internalType": "address", "name": "tokenA", "type": "address" }, 252 | { "internalType": "address", "name": "tokenB", "type": "address" }, 253 | { "internalType": "uint256", "name": "liquidity", "type": "uint256" }, 254 | { "internalType": "uint256", "name": "amountAMin", "type": "uint256" }, 255 | { "internalType": "uint256", "name": "amountBMin", "type": "uint256" }, 256 | { "internalType": "address", "name": "to", "type": "address" }, 257 | { "internalType": "uint256", "name": "deadline", "type": "uint256" }, 258 | { "internalType": "bool", "name": "approveMax", "type": "bool" }, 259 | { "internalType": "uint8", "name": "v", "type": "uint8" }, 260 | { "internalType": "bytes32", "name": "r", "type": "bytes32" }, 261 | { "internalType": "bytes32", "name": "s", "type": "bytes32" } 262 | ], 263 | "name": "removeLiquidityWithPermit", 264 | "outputs": [ 265 | { "internalType": "uint256", "name": "amountA", "type": "uint256" }, 266 | { "internalType": "uint256", "name": "amountB", "type": "uint256" } 267 | ], 268 | "stateMutability": "nonpayable", 269 | "type": "function" 270 | }, 271 | { 272 | "inputs": [ 273 | { "internalType": "uint256", "name": "amountOut", "type": "uint256" }, 274 | { "internalType": "address[]", "name": "path", "type": "address[]" }, 275 | { "internalType": "address", "name": "to", "type": "address" }, 276 | { "internalType": "uint256", "name": "deadline", "type": "uint256" } 277 | ], 278 | "name": "swapETHForExactTokens", 279 | "outputs": [ 280 | { "internalType": "uint256[]", "name": "amounts", "type": "uint256[]" } 281 | ], 282 | "stateMutability": "payable", 283 | "type": "function" 284 | }, 285 | { 286 | "inputs": [ 287 | { "internalType": "uint256", "name": "amountOutMin", "type": "uint256" }, 288 | { "internalType": "address[]", "name": "path", "type": "address[]" }, 289 | { "internalType": "address", "name": "to", "type": "address" }, 290 | { "internalType": "uint256", "name": "deadline", "type": "uint256" } 291 | ], 292 | "name": "swapExactETHForTokens", 293 | "outputs": [ 294 | { "internalType": "uint256[]", "name": "amounts", "type": "uint256[]" } 295 | ], 296 | "stateMutability": "payable", 297 | "type": "function" 298 | }, 299 | { 300 | "inputs": [ 301 | { "internalType": "uint256", "name": "amountOutMin", "type": "uint256" }, 302 | { "internalType": "address[]", "name": "path", "type": "address[]" }, 303 | { "internalType": "address", "name": "to", "type": "address" }, 304 | { "internalType": "uint256", "name": "deadline", "type": "uint256" } 305 | ], 306 | "name": "swapExactETHForTokensSupportingFeeOnTransferTokens", 307 | "outputs": [], 308 | "stateMutability": "payable", 309 | "type": "function" 310 | }, 311 | { 312 | "inputs": [ 313 | { "internalType": "uint256", "name": "amountIn", "type": "uint256" }, 314 | { "internalType": "uint256", "name": "amountOutMin", "type": "uint256" }, 315 | { "internalType": "address[]", "name": "path", "type": "address[]" }, 316 | { "internalType": "address", "name": "to", "type": "address" }, 317 | { "internalType": "uint256", "name": "deadline", "type": "uint256" } 318 | ], 319 | "name": "swapExactTokensForETH", 320 | "outputs": [ 321 | { "internalType": "uint256[]", "name": "amounts", "type": "uint256[]" } 322 | ], 323 | "stateMutability": "nonpayable", 324 | "type": "function" 325 | }, 326 | { 327 | "inputs": [ 328 | { "internalType": "uint256", "name": "amountIn", "type": "uint256" }, 329 | { "internalType": "uint256", "name": "amountOutMin", "type": "uint256" }, 330 | { "internalType": "address[]", "name": "path", "type": "address[]" }, 331 | { "internalType": "address", "name": "to", "type": "address" }, 332 | { "internalType": "uint256", "name": "deadline", "type": "uint256" } 333 | ], 334 | "name": "swapExactTokensForETHSupportingFeeOnTransferTokens", 335 | "outputs": [], 336 | "stateMutability": "nonpayable", 337 | "type": "function" 338 | }, 339 | { 340 | "inputs": [ 341 | { "internalType": "uint256", "name": "amountIn", "type": "uint256" }, 342 | { "internalType": "uint256", "name": "amountOutMin", "type": "uint256" }, 343 | { "internalType": "address[]", "name": "path", "type": "address[]" }, 344 | { "internalType": "address", "name": "to", "type": "address" }, 345 | { "internalType": "uint256", "name": "deadline", "type": "uint256" } 346 | ], 347 | "name": "swapExactTokensForTokens", 348 | "outputs": [ 349 | { "internalType": "uint256[]", "name": "amounts", "type": "uint256[]" } 350 | ], 351 | "stateMutability": "nonpayable", 352 | "type": "function" 353 | }, 354 | { 355 | "inputs": [ 356 | { "internalType": "uint256", "name": "amountIn", "type": "uint256" }, 357 | { "internalType": "uint256", "name": "amountOutMin", "type": "uint256" }, 358 | { "internalType": "address[]", "name": "path", "type": "address[]" }, 359 | { "internalType": "address", "name": "to", "type": "address" }, 360 | { "internalType": "uint256", "name": "deadline", "type": "uint256" } 361 | ], 362 | "name": "swapExactTokensForTokensSupportingFeeOnTransferTokens", 363 | "outputs": [], 364 | "stateMutability": "nonpayable", 365 | "type": "function" 366 | }, 367 | { 368 | "inputs": [ 369 | { "internalType": "uint256", "name": "amountOut", "type": "uint256" }, 370 | { "internalType": "uint256", "name": "amountInMax", "type": "uint256" }, 371 | { "internalType": "address[]", "name": "path", "type": "address[]" }, 372 | { "internalType": "address", "name": "to", "type": "address" }, 373 | { "internalType": "uint256", "name": "deadline", "type": "uint256" } 374 | ], 375 | "name": "swapTokensForExactETH", 376 | "outputs": [ 377 | { "internalType": "uint256[]", "name": "amounts", "type": "uint256[]" } 378 | ], 379 | "stateMutability": "nonpayable", 380 | "type": "function" 381 | }, 382 | { 383 | "inputs": [ 384 | { "internalType": "uint256", "name": "amountOut", "type": "uint256" }, 385 | { "internalType": "uint256", "name": "amountInMax", "type": "uint256" }, 386 | { "internalType": "address[]", "name": "path", "type": "address[]" }, 387 | { "internalType": "address", "name": "to", "type": "address" }, 388 | { "internalType": "uint256", "name": "deadline", "type": "uint256" } 389 | ], 390 | "name": "swapTokensForExactTokens", 391 | "outputs": [ 392 | { "internalType": "uint256[]", "name": "amounts", "type": "uint256[]" } 393 | ], 394 | "stateMutability": "nonpayable", 395 | "type": "function" 396 | }, 397 | { "stateMutability": "payable", "type": "receive" } 398 | ] 399 | -------------------------------------------------------------------------------- /abis/BenSwapRouter.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 | ] 974 | -------------------------------------------------------------------------------- /contracts/BenSwapFactory.sol: -------------------------------------------------------------------------------- 1 | // File: https://github.com/BenTokenFinance/benswap-core/blob/master/contracts/interfaces/IPancakeCallee.sol 2 | 3 | pragma solidity >=0.5.0; 4 | 5 | interface IPancakeCallee { 6 | function pancakeCall(address sender, uint amount0, uint amount1, bytes calldata data) external; 7 | } 8 | 9 | // File: https://github.com/BenTokenFinance/benswap-core/blob/master/contracts/interfaces/IERC20.sol 10 | 11 | pragma solidity >=0.5.0; 12 | 13 | interface IERC20 { 14 | event Approval(address indexed owner, address indexed spender, uint value); 15 | event Transfer(address indexed from, address indexed to, uint value); 16 | 17 | function name() external view returns (string memory); 18 | function symbol() external view returns (string memory); 19 | function decimals() external view returns (uint8); 20 | function totalSupply() external view returns (uint); 21 | function balanceOf(address owner) external view returns (uint); 22 | function allowance(address owner, address spender) external view returns (uint); 23 | 24 | function approve(address spender, uint value) external returns (bool); 25 | function transfer(address to, uint value) external returns (bool); 26 | function transferFrom(address from, address to, uint value) external returns (bool); 27 | } 28 | 29 | // File: https://github.com/BenTokenFinance/benswap-core/blob/master/contracts/libraries/UQ112x112.sol 30 | 31 | pragma solidity =0.5.16; 32 | 33 | // a library for handling binary fixed point numbers (https://en.wikipedia.org/wiki/Q_(number_format)) 34 | 35 | // range: [0, 2**112 - 1] 36 | // resolution: 1 / 2**112 37 | 38 | library UQ112x112 { 39 | uint224 constant Q112 = 2**112; 40 | 41 | // encode a uint112 as a UQ112x112 42 | function encode(uint112 y) internal pure returns (uint224 z) { 43 | z = uint224(y) * Q112; // never overflows 44 | } 45 | 46 | // divide a UQ112x112 by a uint112, returning a UQ112x112 47 | function uqdiv(uint224 x, uint112 y) internal pure returns (uint224 z) { 48 | z = x / uint224(y); 49 | } 50 | } 51 | 52 | // File: https://github.com/BenTokenFinance/benswap-core/blob/master/contracts/libraries/Math.sol 53 | 54 | pragma solidity =0.5.16; 55 | 56 | // a library for performing various math operations 57 | 58 | library Math { 59 | function min(uint x, uint y) internal pure returns (uint z) { 60 | z = x < y ? x : y; 61 | } 62 | 63 | // babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method) 64 | function sqrt(uint y) internal pure returns (uint z) { 65 | if (y > 3) { 66 | z = y; 67 | uint x = y / 2 + 1; 68 | while (x < z) { 69 | z = x; 70 | x = (y / x + x) / 2; 71 | } 72 | } else if (y != 0) { 73 | z = 1; 74 | } 75 | } 76 | } 77 | 78 | // File: https://github.com/BenTokenFinance/benswap-core/blob/master/contracts/libraries/SafeMath.sol 79 | 80 | pragma solidity =0.5.16; 81 | 82 | // a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math) 83 | 84 | library SafeMath { 85 | function add(uint x, uint y) internal pure returns (uint z) { 86 | require((z = x + y) >= x, 'ds-math-add-overflow'); 87 | } 88 | 89 | function sub(uint x, uint y) internal pure returns (uint z) { 90 | require((z = x - y) <= x, 'ds-math-sub-underflow'); 91 | } 92 | 93 | function mul(uint x, uint y) internal pure returns (uint z) { 94 | require(y == 0 || (z = x * y) / y == x, 'ds-math-mul-overflow'); 95 | } 96 | } 97 | 98 | // File: https://github.com/BenTokenFinance/benswap-core/blob/master/contracts/interfaces/IPancakeERC20.sol 99 | 100 | pragma solidity >=0.5.0; 101 | 102 | interface IPancakeERC20 { 103 | event Approval(address indexed owner, address indexed spender, uint value); 104 | event Transfer(address indexed from, address indexed to, uint value); 105 | 106 | function name() external pure returns (string memory); 107 | function symbol() external pure returns (string memory); 108 | function decimals() external pure returns (uint8); 109 | function totalSupply() external view returns (uint); 110 | function balanceOf(address owner) external view returns (uint); 111 | function allowance(address owner, address spender) external view returns (uint); 112 | 113 | function approve(address spender, uint value) external returns (bool); 114 | function transfer(address to, uint value) external returns (bool); 115 | function transferFrom(address from, address to, uint value) external returns (bool); 116 | 117 | function DOMAIN_SEPARATOR() external view returns (bytes32); 118 | function PERMIT_TYPEHASH() external pure returns (bytes32); 119 | function nonces(address owner) external view returns (uint); 120 | 121 | function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; 122 | } 123 | 124 | // File: https://github.com/BenTokenFinance/benswap-core/blob/master/contracts/PancakeERC20.sol 125 | 126 | pragma solidity =0.5.16; 127 | 128 | 129 | 130 | contract PancakeERC20 is IPancakeERC20 { 131 | using SafeMath for uint; 132 | 133 | string public constant name = 'BenSwap LPs'; 134 | string public constant symbol = 'BenSwap-LP'; 135 | uint8 public constant decimals = 18; 136 | uint public totalSupply; 137 | mapping(address => uint) public balanceOf; 138 | mapping(address => mapping(address => uint)) public allowance; 139 | 140 | bytes32 public DOMAIN_SEPARATOR; 141 | // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); 142 | bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; 143 | mapping(address => uint) public nonces; 144 | 145 | event Approval(address indexed owner, address indexed spender, uint value); 146 | event Transfer(address indexed from, address indexed to, uint value); 147 | 148 | constructor() public { 149 | uint chainId; 150 | assembly { 151 | chainId := chainid 152 | } 153 | DOMAIN_SEPARATOR = keccak256( 154 | abi.encode( 155 | keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'), 156 | keccak256(bytes(name)), 157 | keccak256(bytes('1')), 158 | chainId, 159 | address(this) 160 | ) 161 | ); 162 | } 163 | 164 | function _mint(address to, uint value) internal { 165 | totalSupply = totalSupply.add(value); 166 | balanceOf[to] = balanceOf[to].add(value); 167 | emit Transfer(address(0), to, value); 168 | } 169 | 170 | function _burn(address from, uint value) internal { 171 | balanceOf[from] = balanceOf[from].sub(value); 172 | totalSupply = totalSupply.sub(value); 173 | emit Transfer(from, address(0), value); 174 | } 175 | 176 | function _approve(address owner, address spender, uint value) private { 177 | allowance[owner][spender] = value; 178 | emit Approval(owner, spender, value); 179 | } 180 | 181 | function _transfer(address from, address to, uint value) private { 182 | balanceOf[from] = balanceOf[from].sub(value); 183 | balanceOf[to] = balanceOf[to].add(value); 184 | emit Transfer(from, to, value); 185 | } 186 | 187 | function approve(address spender, uint value) external returns (bool) { 188 | _approve(msg.sender, spender, value); 189 | return true; 190 | } 191 | 192 | function transfer(address to, uint value) external returns (bool) { 193 | _transfer(msg.sender, to, value); 194 | return true; 195 | } 196 | 197 | function transferFrom(address from, address to, uint value) external returns (bool) { 198 | if (allowance[from][msg.sender] != uint(-1)) { 199 | allowance[from][msg.sender] = allowance[from][msg.sender].sub(value); 200 | } 201 | _transfer(from, to, value); 202 | return true; 203 | } 204 | 205 | function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external { 206 | require(deadline >= block.timestamp, 'BenSwap: EXPIRED'); 207 | bytes32 digest = keccak256( 208 | abi.encodePacked( 209 | '\x19\x01', 210 | DOMAIN_SEPARATOR, 211 | keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline)) 212 | ) 213 | ); 214 | address recoveredAddress = ecrecover(digest, v, r, s); 215 | require(recoveredAddress != address(0) && recoveredAddress == owner, 'BenSwap: INVALID_SIGNATURE'); 216 | _approve(owner, spender, value); 217 | } 218 | } 219 | 220 | // File: https://github.com/BenTokenFinance/benswap-core/blob/master/contracts/interfaces/IPancakePair.sol 221 | 222 | pragma solidity >=0.5.0; 223 | 224 | interface IPancakePair { 225 | event Approval(address indexed owner, address indexed spender, uint value); 226 | event Transfer(address indexed from, address indexed to, uint value); 227 | 228 | function name() external pure returns (string memory); 229 | function symbol() external pure returns (string memory); 230 | function decimals() external pure returns (uint8); 231 | function totalSupply() external view returns (uint); 232 | function balanceOf(address owner) external view returns (uint); 233 | function allowance(address owner, address spender) external view returns (uint); 234 | 235 | function approve(address spender, uint value) external returns (bool); 236 | function transfer(address to, uint value) external returns (bool); 237 | function transferFrom(address from, address to, uint value) external returns (bool); 238 | 239 | function DOMAIN_SEPARATOR() external view returns (bytes32); 240 | function PERMIT_TYPEHASH() external pure returns (bytes32); 241 | function nonces(address owner) external view returns (uint); 242 | 243 | function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; 244 | 245 | event Mint(address indexed sender, uint amount0, uint amount1); 246 | event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); 247 | event Swap( 248 | address indexed sender, 249 | uint amount0In, 250 | uint amount1In, 251 | uint amount0Out, 252 | uint amount1Out, 253 | address indexed to 254 | ); 255 | event Sync(uint112 reserve0, uint112 reserve1); 256 | 257 | function MINIMUM_LIQUIDITY() external pure returns (uint); 258 | function factory() external view returns (address); 259 | function token0() external view returns (address); 260 | function token1() external view returns (address); 261 | function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); 262 | function price0CumulativeLast() external view returns (uint); 263 | function price1CumulativeLast() external view returns (uint); 264 | function kLast() external view returns (uint); 265 | 266 | function mint(address to) external returns (uint liquidity); 267 | function burn(address to) external returns (uint amount0, uint amount1); 268 | function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external; 269 | function skim(address to) external; 270 | function sync() external; 271 | 272 | function initialize(address, address) external; 273 | } 274 | 275 | // File: https://github.com/BenTokenFinance/benswap-core/blob/master/contracts/PancakePair.sol 276 | 277 | pragma solidity =0.5.16; 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | contract PancakePair is IPancakePair, PancakeERC20 { 287 | using SafeMath for uint; 288 | using UQ112x112 for uint224; 289 | 290 | uint public constant MINIMUM_LIQUIDITY = 10**3; 291 | bytes4 private constant SELECTOR = bytes4(keccak256(bytes('transfer(address,uint256)'))); 292 | 293 | address public factory; 294 | address public token0; 295 | address public token1; 296 | 297 | uint112 private reserve0; // uses single storage slot, accessible via getReserves 298 | uint112 private reserve1; // uses single storage slot, accessible via getReserves 299 | uint32 private blockTimestampLast; // uses single storage slot, accessible via getReserves 300 | 301 | uint public price0CumulativeLast; 302 | uint public price1CumulativeLast; 303 | uint public kLast; // reserve0 * reserve1, as of immediately after the most recent liquidity event 304 | 305 | uint private unlocked = 1; 306 | modifier lock() { 307 | require(unlocked == 1, 'BenSwap: LOCKED'); 308 | unlocked = 0; 309 | _; 310 | unlocked = 1; 311 | } 312 | 313 | function getReserves() public view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast) { 314 | _reserve0 = reserve0; 315 | _reserve1 = reserve1; 316 | _blockTimestampLast = blockTimestampLast; 317 | } 318 | 319 | function _safeTransfer(address token, address to, uint value) private { 320 | (bool success, bytes memory data) = token.call(abi.encodeWithSelector(SELECTOR, to, value)); 321 | require(success && (data.length == 0 || abi.decode(data, (bool))), 'BenSwap: TRANSFER_FAILED'); 322 | } 323 | 324 | event Mint(address indexed sender, uint amount0, uint amount1); 325 | event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); 326 | event Swap( 327 | address indexed sender, 328 | uint amount0In, 329 | uint amount1In, 330 | uint amount0Out, 331 | uint amount1Out, 332 | address indexed to 333 | ); 334 | event Sync(uint112 reserve0, uint112 reserve1); 335 | 336 | constructor() public { 337 | factory = msg.sender; 338 | } 339 | 340 | // called once by the factory at time of deployment 341 | function initialize(address _token0, address _token1) external { 342 | require(msg.sender == factory, 'BenSwap: FORBIDDEN'); // sufficient check 343 | token0 = _token0; 344 | token1 = _token1; 345 | } 346 | 347 | // update reserves and, on the first call per block, price accumulators 348 | function _update(uint balance0, uint balance1, uint112 _reserve0, uint112 _reserve1) private { 349 | require(balance0 <= uint112(-1) && balance1 <= uint112(-1), 'BenSwap: OVERFLOW'); 350 | uint32 blockTimestamp = uint32(block.timestamp % 2**32); 351 | uint32 timeElapsed = blockTimestamp - blockTimestampLast; // overflow is desired 352 | if (timeElapsed > 0 && _reserve0 != 0 && _reserve1 != 0) { 353 | // * never overflows, and + overflow is desired 354 | price0CumulativeLast += uint(UQ112x112.encode(_reserve1).uqdiv(_reserve0)) * timeElapsed; 355 | price1CumulativeLast += uint(UQ112x112.encode(_reserve0).uqdiv(_reserve1)) * timeElapsed; 356 | } 357 | reserve0 = uint112(balance0); 358 | reserve1 = uint112(balance1); 359 | blockTimestampLast = blockTimestamp; 360 | emit Sync(reserve0, reserve1); 361 | } 362 | 363 | // if fee is on, mint liquidity equivalent to 1/6th of the growth in sqrt(k) 364 | function _mintFee(uint112 _reserve0, uint112 _reserve1) private returns (bool feeOn) { 365 | address feeTo = IPancakeFactory(factory).feeTo(); 366 | feeOn = feeTo != address(0); 367 | uint _kLast = kLast; // gas savings 368 | if (feeOn) { 369 | if (_kLast != 0) { 370 | uint rootK = Math.sqrt(uint(_reserve0).mul(_reserve1)); 371 | uint rootKLast = Math.sqrt(_kLast); 372 | if (rootK > rootKLast) { 373 | uint numerator = totalSupply.mul(rootK.sub(rootKLast)); 374 | uint denominator = rootK.mul(3).add(rootKLast); 375 | uint liquidity = numerator / denominator; 376 | if (liquidity > 0) _mint(feeTo, liquidity); 377 | } 378 | } 379 | } else if (_kLast != 0) { 380 | kLast = 0; 381 | } 382 | } 383 | 384 | // this low-level function should be called from a contract which performs important safety checks 385 | function mint(address to) external lock returns (uint liquidity) { 386 | (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings 387 | uint balance0 = IERC20(token0).balanceOf(address(this)); 388 | uint balance1 = IERC20(token1).balanceOf(address(this)); 389 | uint amount0 = balance0.sub(_reserve0); 390 | uint amount1 = balance1.sub(_reserve1); 391 | 392 | bool feeOn = _mintFee(_reserve0, _reserve1); 393 | uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee 394 | if (_totalSupply == 0) { 395 | liquidity = Math.sqrt(amount0.mul(amount1)).sub(MINIMUM_LIQUIDITY); 396 | _mint(address(0), MINIMUM_LIQUIDITY); // permanently lock the first MINIMUM_LIQUIDITY tokens 397 | } else { 398 | liquidity = Math.min(amount0.mul(_totalSupply) / _reserve0, amount1.mul(_totalSupply) / _reserve1); 399 | } 400 | require(liquidity > 0, 'BenSwap: INSUFFICIENT_LIQUIDITY_MINTED'); 401 | _mint(to, liquidity); 402 | 403 | _update(balance0, balance1, _reserve0, _reserve1); 404 | if (feeOn) kLast = uint(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date 405 | emit Mint(msg.sender, amount0, amount1); 406 | } 407 | 408 | // this low-level function should be called from a contract which performs important safety checks 409 | function burn(address to) external lock returns (uint amount0, uint amount1) { 410 | (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings 411 | address _token0 = token0; // gas savings 412 | address _token1 = token1; // gas savings 413 | uint balance0 = IERC20(_token0).balanceOf(address(this)); 414 | uint balance1 = IERC20(_token1).balanceOf(address(this)); 415 | uint liquidity = balanceOf[address(this)]; 416 | 417 | bool feeOn = _mintFee(_reserve0, _reserve1); 418 | uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee 419 | amount0 = liquidity.mul(balance0) / _totalSupply; // using balances ensures pro-rata distribution 420 | amount1 = liquidity.mul(balance1) / _totalSupply; // using balances ensures pro-rata distribution 421 | require(amount0 > 0 && amount1 > 0, 'BenSwap: INSUFFICIENT_LIQUIDITY_BURNED'); 422 | _burn(address(this), liquidity); 423 | _safeTransfer(_token0, to, amount0); 424 | _safeTransfer(_token1, to, amount1); 425 | balance0 = IERC20(_token0).balanceOf(address(this)); 426 | balance1 = IERC20(_token1).balanceOf(address(this)); 427 | 428 | _update(balance0, balance1, _reserve0, _reserve1); 429 | if (feeOn) kLast = uint(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date 430 | emit Burn(msg.sender, amount0, amount1, to); 431 | } 432 | 433 | // this low-level function should be called from a contract which performs important safety checks 434 | function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external lock { 435 | require(amount0Out > 0 || amount1Out > 0, 'BenSwap: INSUFFICIENT_OUTPUT_AMOUNT'); 436 | (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings 437 | require(amount0Out < _reserve0 && amount1Out < _reserve1, 'BenSwap: INSUFFICIENT_LIQUIDITY'); 438 | 439 | uint balance0; 440 | uint balance1; 441 | { // scope for _token{0,1}, avoids stack too deep errors 442 | address _token0 = token0; 443 | address _token1 = token1; 444 | require(to != _token0 && to != _token1, 'BenSwap: INVALID_TO'); 445 | if (amount0Out > 0) _safeTransfer(_token0, to, amount0Out); // optimistically transfer tokens 446 | if (amount1Out > 0) _safeTransfer(_token1, to, amount1Out); // optimistically transfer tokens 447 | if (data.length > 0) IPancakeCallee(to).pancakeCall(msg.sender, amount0Out, amount1Out, data); 448 | balance0 = IERC20(_token0).balanceOf(address(this)); 449 | balance1 = IERC20(_token1).balanceOf(address(this)); 450 | } 451 | uint amount0In = balance0 > _reserve0 - amount0Out ? balance0 - (_reserve0 - amount0Out) : 0; 452 | uint amount1In = balance1 > _reserve1 - amount1Out ? balance1 - (_reserve1 - amount1Out) : 0; 453 | require(amount0In > 0 || amount1In > 0, 'BenSwap: INSUFFICIENT_INPUT_AMOUNT'); 454 | { // scope for reserve{0,1}Adjusted, avoids stack too deep errors 455 | uint balance0Adjusted = balance0.mul(1000).sub(amount0In.mul(2)); 456 | uint balance1Adjusted = balance1.mul(1000).sub(amount1In.mul(2)); 457 | require(balance0Adjusted.mul(balance1Adjusted) >= uint(_reserve0).mul(_reserve1).mul(1000**2), 'BenSwap: K'); 458 | } 459 | 460 | _update(balance0, balance1, _reserve0, _reserve1); 461 | emit Swap(msg.sender, amount0In, amount1In, amount0Out, amount1Out, to); 462 | } 463 | 464 | // force balances to match reserves 465 | function skim(address to) external lock { 466 | address _token0 = token0; // gas savings 467 | address _token1 = token1; // gas savings 468 | _safeTransfer(_token0, to, IERC20(_token0).balanceOf(address(this)).sub(reserve0)); 469 | _safeTransfer(_token1, to, IERC20(_token1).balanceOf(address(this)).sub(reserve1)); 470 | } 471 | 472 | // force reserves to match balances 473 | function sync() external lock { 474 | _update(IERC20(token0).balanceOf(address(this)), IERC20(token1).balanceOf(address(this)), reserve0, reserve1); 475 | } 476 | } 477 | 478 | // File: https://github.com/BenTokenFinance/benswap-core/blob/master/contracts/interfaces/IPancakeFactory.sol 479 | 480 | pragma solidity >=0.5.0; 481 | 482 | interface IPancakeFactory { 483 | event PairCreated(address indexed token0, address indexed token1, address pair, uint); 484 | 485 | function feeTo() external view returns (address); 486 | function feeToSetter() external view returns (address); 487 | 488 | function getPair(address tokenA, address tokenB) external view returns (address pair); 489 | function allPairs(uint) external view returns (address pair); 490 | function allPairsLength() external view returns (uint); 491 | 492 | function createPair(address tokenA, address tokenB) external returns (address pair); 493 | 494 | function setFeeTo(address) external; 495 | function setFeeToSetter(address) external; 496 | } 497 | 498 | // File: github/BenTokenFinance/benswap-core/contracts/PancakeFactory.sol 499 | 500 | pragma solidity =0.5.16; 501 | 502 | //import './interfaces/IPancakeFactory.sol'; 503 | //import './PancakePair.sol'; 504 | 505 | 506 | 507 | contract BenSwapFactory is IPancakeFactory { 508 | bytes32 public constant INIT_CODE_PAIR_HASH = keccak256(abi.encodePacked(type(PancakePair).creationCode)); 509 | 510 | address public feeTo; 511 | address public feeToSetter; 512 | 513 | mapping(address => mapping(address => address)) public getPair; 514 | address[] public allPairs; 515 | 516 | event PairCreated(address indexed token0, address indexed token1, address pair, uint); 517 | 518 | constructor(address _feeToSetter) public { 519 | feeToSetter = _feeToSetter; 520 | } 521 | 522 | function allPairsLength() external view returns (uint) { 523 | return allPairs.length; 524 | } 525 | 526 | function createPair(address tokenA, address tokenB) external returns (address pair) { 527 | require(tokenA != tokenB, 'BenSwap: IDENTICAL_ADDRESSES'); 528 | (address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); 529 | require(token0 != address(0), 'BenSwap: ZERO_ADDRESS'); 530 | require(getPair[token0][token1] == address(0), 'BenSwap: PAIR_EXISTS'); // single check is sufficient 531 | bytes memory bytecode = type(PancakePair).creationCode; 532 | bytes32 salt = keccak256(abi.encodePacked(token0, token1)); 533 | assembly { 534 | pair := create2(0, add(bytecode, 32), mload(bytecode), salt) 535 | } 536 | IPancakePair(pair).initialize(token0, token1); 537 | getPair[token0][token1] = pair; 538 | getPair[token1][token0] = pair; // populate mapping in the reverse direction 539 | allPairs.push(pair); 540 | emit PairCreated(token0, token1, pair, allPairs.length); 541 | } 542 | 543 | function setFeeTo(address _feeTo) external { 544 | require(msg.sender == feeToSetter, 'BenSwap: FORBIDDEN'); 545 | feeTo = _feeTo; 546 | } 547 | 548 | function setFeeToSetter(address _feeToSetter) external { 549 | require(msg.sender == feeToSetter, 'BenSwap: FORBIDDEN'); 550 | feeToSetter = _feeToSetter; 551 | } 552 | } 553 | -------------------------------------------------------------------------------- /contracts/BenSwapRouter.sol: -------------------------------------------------------------------------------- 1 | // File: @uniswap\lib\contracts\libraries\TransferHelper.sol 2 | 3 | pragma solidity >=0.6.0; 4 | 5 | // helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false 6 | library TransferHelper { 7 | function safeApprove(address token, address to, uint value) internal { 8 | // bytes4(keccak256(bytes('approve(address,uint256)'))); 9 | (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value)); 10 | require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: APPROVE_FAILED'); 11 | } 12 | 13 | function safeTransfer(address token, address to, uint value) internal { 14 | // bytes4(keccak256(bytes('transfer(address,uint256)'))); 15 | (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value)); 16 | require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FAILED'); 17 | } 18 | 19 | function safeTransferFrom(address token, address from, address to, uint value) internal { 20 | // bytes4(keccak256(bytes('transferFrom(address,address,uint256)'))); 21 | (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value)); 22 | require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FROM_FAILED'); 23 | } 24 | 25 | function safeTransferETH(address to, uint value) internal { 26 | (bool success,) = to.call{value:value}(new bytes(0)); 27 | require(success, 'TransferHelper: ETH_TRANSFER_FAILED'); 28 | } 29 | } 30 | 31 | // File: contracts\interfaces\IPancakeRouter01.sol 32 | 33 | pragma solidity >=0.6.2; 34 | 35 | interface IPancakeRouter01 { 36 | function factory() external pure returns (address); 37 | function WETH() external pure returns (address); 38 | 39 | function addLiquidity( 40 | address tokenA, 41 | address tokenB, 42 | uint amountADesired, 43 | uint amountBDesired, 44 | uint amountAMin, 45 | uint amountBMin, 46 | address to, 47 | uint deadline 48 | ) external returns (uint amountA, uint amountB, uint liquidity); 49 | function addLiquidityETH( 50 | address token, 51 | uint amountTokenDesired, 52 | uint amountTokenMin, 53 | uint amountETHMin, 54 | address to, 55 | uint deadline 56 | ) external payable returns (uint amountToken, uint amountETH, uint liquidity); 57 | function removeLiquidity( 58 | address tokenA, 59 | address tokenB, 60 | uint liquidity, 61 | uint amountAMin, 62 | uint amountBMin, 63 | address to, 64 | uint deadline 65 | ) external returns (uint amountA, uint amountB); 66 | function removeLiquidityETH( 67 | address token, 68 | uint liquidity, 69 | uint amountTokenMin, 70 | uint amountETHMin, 71 | address to, 72 | uint deadline 73 | ) external returns (uint amountToken, uint amountETH); 74 | function removeLiquidityWithPermit( 75 | address tokenA, 76 | address tokenB, 77 | uint liquidity, 78 | uint amountAMin, 79 | uint amountBMin, 80 | address to, 81 | uint deadline, 82 | bool approveMax, uint8 v, bytes32 r, bytes32 s 83 | ) external returns (uint amountA, uint amountB); 84 | function removeLiquidityETHWithPermit( 85 | address token, 86 | uint liquidity, 87 | uint amountTokenMin, 88 | uint amountETHMin, 89 | address to, 90 | uint deadline, 91 | bool approveMax, uint8 v, bytes32 r, bytes32 s 92 | ) external returns (uint amountToken, uint amountETH); 93 | function swapExactTokensForTokens( 94 | uint amountIn, 95 | uint amountOutMin, 96 | address[] calldata path, 97 | address to, 98 | uint deadline 99 | ) external returns (uint[] memory amounts); 100 | function swapTokensForExactTokens( 101 | uint amountOut, 102 | uint amountInMax, 103 | address[] calldata path, 104 | address to, 105 | uint deadline 106 | ) external returns (uint[] memory amounts); 107 | function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) 108 | external 109 | payable 110 | returns (uint[] memory amounts); 111 | function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline) 112 | external 113 | returns (uint[] memory amounts); 114 | function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) 115 | external 116 | returns (uint[] memory amounts); 117 | function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline) 118 | external 119 | payable 120 | returns (uint[] memory amounts); 121 | 122 | function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB); 123 | function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut); 124 | function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn); 125 | function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts); 126 | function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts); 127 | } 128 | 129 | // File: contracts\interfaces\IPancakeRouter02.sol 130 | 131 | pragma solidity >=0.6.2; 132 | 133 | interface IPancakeRouter02 is IPancakeRouter01 { 134 | function removeLiquidityETHSupportingFeeOnTransferTokens( 135 | address token, 136 | uint liquidity, 137 | uint amountTokenMin, 138 | uint amountETHMin, 139 | address to, 140 | uint deadline 141 | ) external returns (uint amountETH); 142 | function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens( 143 | address token, 144 | uint liquidity, 145 | uint amountTokenMin, 146 | uint amountETHMin, 147 | address to, 148 | uint deadline, 149 | bool approveMax, uint8 v, bytes32 r, bytes32 s 150 | ) external returns (uint amountETH); 151 | 152 | function swapExactTokensForTokensSupportingFeeOnTransferTokens( 153 | uint amountIn, 154 | uint amountOutMin, 155 | address[] calldata path, 156 | address to, 157 | uint deadline 158 | ) external; 159 | function swapExactETHForTokensSupportingFeeOnTransferTokens( 160 | uint amountOutMin, 161 | address[] calldata path, 162 | address to, 163 | uint deadline 164 | ) external payable; 165 | function swapExactTokensForETHSupportingFeeOnTransferTokens( 166 | uint amountIn, 167 | uint amountOutMin, 168 | address[] calldata path, 169 | address to, 170 | uint deadline 171 | ) external; 172 | } 173 | 174 | // File: contracts\interfaces\IPancakeFactory.sol 175 | 176 | pragma solidity >=0.5.0; 177 | 178 | interface IPancakeFactory { 179 | event PairCreated(address indexed token0, address indexed token1, address pair, uint); 180 | 181 | function feeTo() external view returns (address); 182 | function feeToSetter() external view returns (address); 183 | 184 | function getPair(address tokenA, address tokenB) external view returns (address pair); 185 | function allPairs(uint) external view returns (address pair); 186 | function allPairsLength() external view returns (uint); 187 | 188 | function createPair(address tokenA, address tokenB) external returns (address pair); 189 | 190 | function setFeeTo(address) external; 191 | function setFeeToSetter(address) external; 192 | 193 | function INIT_CODE_PAIR_HASH() external view returns (bytes32); 194 | } 195 | 196 | // File: contracts\libraries\SafeMath.sol 197 | 198 | pragma solidity =0.6.6; 199 | 200 | // a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math) 201 | 202 | library SafeMath { 203 | function add(uint x, uint y) internal pure returns (uint z) { 204 | require((z = x + y) >= x, 'ds-math-add-overflow'); 205 | } 206 | 207 | function sub(uint x, uint y) internal pure returns (uint z) { 208 | require((z = x - y) <= x, 'ds-math-sub-underflow'); 209 | } 210 | 211 | function mul(uint x, uint y) internal pure returns (uint z) { 212 | require(y == 0 || (z = x * y) / y == x, 'ds-math-mul-overflow'); 213 | } 214 | } 215 | 216 | // File: contracts\interfaces\IPancakePair.sol 217 | 218 | pragma solidity >=0.5.0; 219 | 220 | interface IPancakePair { 221 | event Approval(address indexed owner, address indexed spender, uint value); 222 | event Transfer(address indexed from, address indexed to, uint value); 223 | 224 | function name() external pure returns (string memory); 225 | function symbol() external pure returns (string memory); 226 | function decimals() external pure returns (uint8); 227 | function totalSupply() external view returns (uint); 228 | function balanceOf(address owner) external view returns (uint); 229 | function allowance(address owner, address spender) external view returns (uint); 230 | 231 | function approve(address spender, uint value) external returns (bool); 232 | function transfer(address to, uint value) external returns (bool); 233 | function transferFrom(address from, address to, uint value) external returns (bool); 234 | 235 | function DOMAIN_SEPARATOR() external view returns (bytes32); 236 | function PERMIT_TYPEHASH() external pure returns (bytes32); 237 | function nonces(address owner) external view returns (uint); 238 | 239 | function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; 240 | 241 | event Mint(address indexed sender, uint amount0, uint amount1); 242 | event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); 243 | event Swap( 244 | address indexed sender, 245 | uint amount0In, 246 | uint amount1In, 247 | uint amount0Out, 248 | uint amount1Out, 249 | address indexed to 250 | ); 251 | event Sync(uint112 reserve0, uint112 reserve1); 252 | 253 | function MINIMUM_LIQUIDITY() external pure returns (uint); 254 | function factory() external view returns (address); 255 | function token0() external view returns (address); 256 | function token1() external view returns (address); 257 | function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); 258 | function price0CumulativeLast() external view returns (uint); 259 | function price1CumulativeLast() external view returns (uint); 260 | function kLast() external view returns (uint); 261 | 262 | function mint(address to) external returns (uint liquidity); 263 | function burn(address to) external returns (uint amount0, uint amount1); 264 | function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external; 265 | function skim(address to) external; 266 | function sync() external; 267 | 268 | function initialize(address, address) external; 269 | } 270 | 271 | // File: contracts\libraries\PancakeLibrary.sol 272 | 273 | pragma solidity >=0.5.0; 274 | 275 | 276 | 277 | library PancakeLibrary { 278 | using SafeMath for uint; 279 | 280 | // returns sorted token addresses, used to handle return values from pairs sorted in this order 281 | function sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) { 282 | require(tokenA != tokenB, 'PancakeLibrary: IDENTICAL_ADDRESSES'); 283 | (token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); 284 | require(token0 != address(0), 'PancakeLibrary: ZERO_ADDRESS'); 285 | } 286 | 287 | // calculates the CREATE2 address for a pair without making any external calls 288 | function pairFor(address factory, address tokenA, address tokenB) internal pure returns (address pair) { 289 | (address token0, address token1) = sortTokens(tokenA, tokenB); 290 | pair = address(uint(keccak256(abi.encodePacked( 291 | hex'ff', 292 | factory, 293 | keccak256(abi.encodePacked(token0, token1)), 294 | hex'2962dc095594ddede1fd758ba8debc77f2f285a00cdb2fadc35c807f0d804b41' // init code hash 295 | )))); 296 | } 297 | 298 | // fetches and sorts the reserves for a pair 299 | function getReserves(address factory, address tokenA, address tokenB) internal view returns (uint reserveA, uint reserveB) { 300 | (address token0,) = sortTokens(tokenA, tokenB); 301 | pairFor(factory, tokenA, tokenB); 302 | (uint reserve0, uint reserve1,) = IPancakePair(pairFor(factory, tokenA, tokenB)).getReserves(); 303 | (reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0); 304 | } 305 | 306 | // given some amount of an asset and pair reserves, returns an equivalent amount of the other asset 307 | function quote(uint amountA, uint reserveA, uint reserveB) internal pure returns (uint amountB) { 308 | require(amountA > 0, 'PancakeLibrary: INSUFFICIENT_AMOUNT'); 309 | require(reserveA > 0 && reserveB > 0, 'PancakeLibrary: INSUFFICIENT_LIQUIDITY'); 310 | amountB = amountA.mul(reserveB) / reserveA; 311 | } 312 | 313 | // given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset 314 | function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) internal pure returns (uint amountOut) { 315 | require(amountIn > 0, 'PancakeLibrary: INSUFFICIENT_INPUT_AMOUNT'); 316 | require(reserveIn > 0 && reserveOut > 0, 'PancakeLibrary: INSUFFICIENT_LIQUIDITY'); 317 | uint amountInWithFee = amountIn.mul(9975); 318 | uint numerator = amountInWithFee.mul(reserveOut); 319 | uint denominator = reserveIn.mul(10000).add(amountInWithFee); 320 | amountOut = numerator / denominator; 321 | } 322 | 323 | // given an output amount of an asset and pair reserves, returns a required input amount of the other asset 324 | function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) internal pure returns (uint amountIn) { 325 | require(amountOut > 0, 'PancakeLibrary: INSUFFICIENT_OUTPUT_AMOUNT'); 326 | require(reserveIn > 0 && reserveOut > 0, 'PancakeLibrary: INSUFFICIENT_LIQUIDITY'); 327 | uint numerator = reserveIn.mul(amountOut).mul(10000); 328 | uint denominator = reserveOut.sub(amountOut).mul(9975); 329 | amountIn = (numerator / denominator).add(1); 330 | } 331 | 332 | // performs chained getAmountOut calculations on any number of pairs 333 | function getAmountsOut(address factory, uint amountIn, address[] memory path) internal view returns (uint[] memory amounts) { 334 | require(path.length >= 2, 'PancakeLibrary: INVALID_PATH'); 335 | amounts = new uint[](path.length); 336 | amounts[0] = amountIn; 337 | for (uint i; i < path.length - 1; i++) { 338 | (uint reserveIn, uint reserveOut) = getReserves(factory, path[i], path[i + 1]); 339 | amounts[i + 1] = getAmountOut(amounts[i], reserveIn, reserveOut); 340 | } 341 | } 342 | 343 | // performs chained getAmountIn calculations on any number of pairs 344 | function getAmountsIn(address factory, uint amountOut, address[] memory path) internal view returns (uint[] memory amounts) { 345 | require(path.length >= 2, 'PancakeLibrary: INVALID_PATH'); 346 | amounts = new uint[](path.length); 347 | amounts[amounts.length - 1] = amountOut; 348 | for (uint i = path.length - 1; i > 0; i--) { 349 | (uint reserveIn, uint reserveOut) = getReserves(factory, path[i - 1], path[i]); 350 | amounts[i - 1] = getAmountIn(amounts[i], reserveIn, reserveOut); 351 | } 352 | } 353 | } 354 | 355 | // File: contracts\interfaces\IERC20.sol 356 | 357 | pragma solidity >=0.5.0; 358 | 359 | interface IERC20 { 360 | event Approval(address indexed owner, address indexed spender, uint value); 361 | event Transfer(address indexed from, address indexed to, uint value); 362 | 363 | function name() external view returns (string memory); 364 | function symbol() external view returns (string memory); 365 | function decimals() external view returns (uint8); 366 | function totalSupply() external view returns (uint); 367 | function balanceOf(address owner) external view returns (uint); 368 | function allowance(address owner, address spender) external view returns (uint); 369 | 370 | function approve(address spender, uint value) external returns (bool); 371 | function transfer(address to, uint value) external returns (bool); 372 | function transferFrom(address from, address to, uint value) external returns (bool); 373 | } 374 | 375 | // File: contracts\interfaces\IWETH.sol 376 | 377 | pragma solidity >=0.5.0; 378 | 379 | interface IWETH { 380 | function deposit() external payable; 381 | function transfer(address to, uint value) external returns (bool); 382 | function withdraw(uint) external; 383 | } 384 | 385 | // File: contracts\PancakeRouter.sol 386 | 387 | pragma solidity =0.6.6; 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | contract BenSwapRouter is IPancakeRouter02 { 396 | using SafeMath for uint; 397 | 398 | address public immutable override factory; 399 | address public immutable override WETH; 400 | 401 | modifier ensure(uint deadline) { 402 | require(deadline >= block.timestamp, 'BenSwapRouter: EXPIRED'); 403 | _; 404 | } 405 | 406 | constructor(address _factory, address _WETH) public { 407 | factory = _factory; 408 | WETH = _WETH; 409 | } 410 | 411 | receive() external payable { 412 | assert(msg.sender == WETH); // only accept ETH via fallback from the WETH contract 413 | } 414 | 415 | // **** ADD LIQUIDITY **** 416 | function _addLiquidity( 417 | address tokenA, 418 | address tokenB, 419 | uint amountADesired, 420 | uint amountBDesired, 421 | uint amountAMin, 422 | uint amountBMin 423 | ) internal virtual returns (uint amountA, uint amountB) { 424 | // create the pair if it doesn't exist yet 425 | if (IPancakeFactory(factory).getPair(tokenA, tokenB) == address(0)) { 426 | IPancakeFactory(factory).createPair(tokenA, tokenB); 427 | } 428 | (uint reserveA, uint reserveB) = PancakeLibrary.getReserves(factory, tokenA, tokenB); 429 | if (reserveA == 0 && reserveB == 0) { 430 | (amountA, amountB) = (amountADesired, amountBDesired); 431 | } else { 432 | uint amountBOptimal = PancakeLibrary.quote(amountADesired, reserveA, reserveB); 433 | if (amountBOptimal <= amountBDesired) { 434 | require(amountBOptimal >= amountBMin, 'BenSwapRouter: INSUFFICIENT_B_AMOUNT'); 435 | (amountA, amountB) = (amountADesired, amountBOptimal); 436 | } else { 437 | uint amountAOptimal = PancakeLibrary.quote(amountBDesired, reserveB, reserveA); 438 | assert(amountAOptimal <= amountADesired); 439 | require(amountAOptimal >= amountAMin, 'BenSwapRouter: INSUFFICIENT_A_AMOUNT'); 440 | (amountA, amountB) = (amountAOptimal, amountBDesired); 441 | } 442 | } 443 | } 444 | function addLiquidity( 445 | address tokenA, 446 | address tokenB, 447 | uint amountADesired, 448 | uint amountBDesired, 449 | uint amountAMin, 450 | uint amountBMin, 451 | address to, 452 | uint deadline 453 | ) external virtual override ensure(deadline) returns (uint amountA, uint amountB, uint liquidity) { 454 | (amountA, amountB) = _addLiquidity(tokenA, tokenB, amountADesired, amountBDesired, amountAMin, amountBMin); 455 | address pair = PancakeLibrary.pairFor(factory, tokenA, tokenB); 456 | TransferHelper.safeTransferFrom(tokenA, msg.sender, pair, amountA); 457 | TransferHelper.safeTransferFrom(tokenB, msg.sender, pair, amountB); 458 | liquidity = IPancakePair(pair).mint(to); 459 | } 460 | function addLiquidityETH( 461 | address token, 462 | uint amountTokenDesired, 463 | uint amountTokenMin, 464 | uint amountETHMin, 465 | address to, 466 | uint deadline 467 | ) external virtual override payable ensure(deadline) returns (uint amountToken, uint amountETH, uint liquidity) { 468 | (amountToken, amountETH) = _addLiquidity( 469 | token, 470 | WETH, 471 | amountTokenDesired, 472 | msg.value, 473 | amountTokenMin, 474 | amountETHMin 475 | ); 476 | address pair = PancakeLibrary.pairFor(factory, token, WETH); 477 | TransferHelper.safeTransferFrom(token, msg.sender, pair, amountToken); 478 | IWETH(WETH).deposit{value: amountETH}(); 479 | assert(IWETH(WETH).transfer(pair, amountETH)); 480 | liquidity = IPancakePair(pair).mint(to); 481 | // refund dust eth, if any 482 | if (msg.value > amountETH) TransferHelper.safeTransferETH(msg.sender, msg.value - amountETH); 483 | } 484 | 485 | // **** REMOVE LIQUIDITY **** 486 | function removeLiquidity( 487 | address tokenA, 488 | address tokenB, 489 | uint liquidity, 490 | uint amountAMin, 491 | uint amountBMin, 492 | address to, 493 | uint deadline 494 | ) public virtual override ensure(deadline) returns (uint amountA, uint amountB) { 495 | address pair = PancakeLibrary.pairFor(factory, tokenA, tokenB); 496 | IPancakePair(pair).transferFrom(msg.sender, pair, liquidity); // send liquidity to pair 497 | (uint amount0, uint amount1) = IPancakePair(pair).burn(to); 498 | (address token0,) = PancakeLibrary.sortTokens(tokenA, tokenB); 499 | (amountA, amountB) = tokenA == token0 ? (amount0, amount1) : (amount1, amount0); 500 | require(amountA >= amountAMin, 'BenSwapRouter: INSUFFICIENT_A_AMOUNT'); 501 | require(amountB >= amountBMin, 'BenSwapRouter: INSUFFICIENT_B_AMOUNT'); 502 | } 503 | function removeLiquidityETH( 504 | address token, 505 | uint liquidity, 506 | uint amountTokenMin, 507 | uint amountETHMin, 508 | address to, 509 | uint deadline 510 | ) public virtual override ensure(deadline) returns (uint amountToken, uint amountETH) { 511 | (amountToken, amountETH) = removeLiquidity( 512 | token, 513 | WETH, 514 | liquidity, 515 | amountTokenMin, 516 | amountETHMin, 517 | address(this), 518 | deadline 519 | ); 520 | TransferHelper.safeTransfer(token, to, amountToken); 521 | IWETH(WETH).withdraw(amountETH); 522 | TransferHelper.safeTransferETH(to, amountETH); 523 | } 524 | function removeLiquidityWithPermit( 525 | address tokenA, 526 | address tokenB, 527 | uint liquidity, 528 | uint amountAMin, 529 | uint amountBMin, 530 | address to, 531 | uint deadline, 532 | bool approveMax, uint8 v, bytes32 r, bytes32 s 533 | ) external virtual override returns (uint amountA, uint amountB) { 534 | address pair = PancakeLibrary.pairFor(factory, tokenA, tokenB); 535 | uint value = approveMax ? uint(-1) : liquidity; 536 | IPancakePair(pair).permit(msg.sender, address(this), value, deadline, v, r, s); 537 | (amountA, amountB) = removeLiquidity(tokenA, tokenB, liquidity, amountAMin, amountBMin, to, deadline); 538 | } 539 | function removeLiquidityETHWithPermit( 540 | address token, 541 | uint liquidity, 542 | uint amountTokenMin, 543 | uint amountETHMin, 544 | address to, 545 | uint deadline, 546 | bool approveMax, uint8 v, bytes32 r, bytes32 s 547 | ) external virtual override returns (uint amountToken, uint amountETH) { 548 | address pair = PancakeLibrary.pairFor(factory, token, WETH); 549 | uint value = approveMax ? uint(-1) : liquidity; 550 | IPancakePair(pair).permit(msg.sender, address(this), value, deadline, v, r, s); 551 | (amountToken, amountETH) = removeLiquidityETH(token, liquidity, amountTokenMin, amountETHMin, to, deadline); 552 | } 553 | 554 | // **** REMOVE LIQUIDITY (supporting fee-on-transfer tokens) **** 555 | function removeLiquidityETHSupportingFeeOnTransferTokens( 556 | address token, 557 | uint liquidity, 558 | uint amountTokenMin, 559 | uint amountETHMin, 560 | address to, 561 | uint deadline 562 | ) public virtual override ensure(deadline) returns (uint amountETH) { 563 | (, amountETH) = removeLiquidity( 564 | token, 565 | WETH, 566 | liquidity, 567 | amountTokenMin, 568 | amountETHMin, 569 | address(this), 570 | deadline 571 | ); 572 | TransferHelper.safeTransfer(token, to, IERC20(token).balanceOf(address(this))); 573 | IWETH(WETH).withdraw(amountETH); 574 | TransferHelper.safeTransferETH(to, amountETH); 575 | } 576 | function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens( 577 | address token, 578 | uint liquidity, 579 | uint amountTokenMin, 580 | uint amountETHMin, 581 | address to, 582 | uint deadline, 583 | bool approveMax, uint8 v, bytes32 r, bytes32 s 584 | ) external virtual override returns (uint amountETH) { 585 | address pair = PancakeLibrary.pairFor(factory, token, WETH); 586 | uint value = approveMax ? uint(-1) : liquidity; 587 | IPancakePair(pair).permit(msg.sender, address(this), value, deadline, v, r, s); 588 | amountETH = removeLiquidityETHSupportingFeeOnTransferTokens( 589 | token, liquidity, amountTokenMin, amountETHMin, to, deadline 590 | ); 591 | } 592 | 593 | // **** SWAP **** 594 | // requires the initial amount to have already been sent to the first pair 595 | function _swap(uint[] memory amounts, address[] memory path, address _to) internal virtual { 596 | for (uint i; i < path.length - 1; i++) { 597 | (address input, address output) = (path[i], path[i + 1]); 598 | (address token0,) = PancakeLibrary.sortTokens(input, output); 599 | uint amountOut = amounts[i + 1]; 600 | (uint amount0Out, uint amount1Out) = input == token0 ? (uint(0), amountOut) : (amountOut, uint(0)); 601 | address to = i < path.length - 2 ? PancakeLibrary.pairFor(factory, output, path[i + 2]) : _to; 602 | IPancakePair(PancakeLibrary.pairFor(factory, input, output)).swap( 603 | amount0Out, amount1Out, to, new bytes(0) 604 | ); 605 | } 606 | } 607 | function swapExactTokensForTokens( 608 | uint amountIn, 609 | uint amountOutMin, 610 | address[] calldata path, 611 | address to, 612 | uint deadline 613 | ) external virtual override ensure(deadline) returns (uint[] memory amounts) { 614 | amounts = PancakeLibrary.getAmountsOut(factory, amountIn, path); 615 | require(amounts[amounts.length - 1] >= amountOutMin, 'BenSwapRouter: INSUFFICIENT_OUTPUT_AMOUNT'); 616 | TransferHelper.safeTransferFrom( 617 | path[0], msg.sender, PancakeLibrary.pairFor(factory, path[0], path[1]), amounts[0] 618 | ); 619 | _swap(amounts, path, to); 620 | } 621 | function swapTokensForExactTokens( 622 | uint amountOut, 623 | uint amountInMax, 624 | address[] calldata path, 625 | address to, 626 | uint deadline 627 | ) external virtual override ensure(deadline) returns (uint[] memory amounts) { 628 | amounts = PancakeLibrary.getAmountsIn(factory, amountOut, path); 629 | require(amounts[0] <= amountInMax, 'BenSwapRouter: EXCESSIVE_INPUT_AMOUNT'); 630 | TransferHelper.safeTransferFrom( 631 | path[0], msg.sender, PancakeLibrary.pairFor(factory, path[0], path[1]), amounts[0] 632 | ); 633 | _swap(amounts, path, to); 634 | } 635 | function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) 636 | external 637 | virtual 638 | override 639 | payable 640 | ensure(deadline) 641 | returns (uint[] memory amounts) 642 | { 643 | require(path[0] == WETH, 'BenSwapRouter: INVALID_PATH'); 644 | amounts = PancakeLibrary.getAmountsOut(factory, msg.value, path); 645 | require(amounts[amounts.length - 1] >= amountOutMin, 'BenSwapRouter: INSUFFICIENT_OUTPUT_AMOUNT'); 646 | IWETH(WETH).deposit{value: amounts[0]}(); 647 | assert(IWETH(WETH).transfer(PancakeLibrary.pairFor(factory, path[0], path[1]), amounts[0])); 648 | _swap(amounts, path, to); 649 | } 650 | function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline) 651 | external 652 | virtual 653 | override 654 | ensure(deadline) 655 | returns (uint[] memory amounts) 656 | { 657 | require(path[path.length - 1] == WETH, 'BenSwapRouter: INVALID_PATH'); 658 | amounts = PancakeLibrary.getAmountsIn(factory, amountOut, path); 659 | require(amounts[0] <= amountInMax, 'BenSwapRouter: EXCESSIVE_INPUT_AMOUNT'); 660 | TransferHelper.safeTransferFrom( 661 | path[0], msg.sender, PancakeLibrary.pairFor(factory, path[0], path[1]), amounts[0] 662 | ); 663 | _swap(amounts, path, address(this)); 664 | IWETH(WETH).withdraw(amounts[amounts.length - 1]); 665 | TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]); 666 | } 667 | function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) 668 | external 669 | virtual 670 | override 671 | ensure(deadline) 672 | returns (uint[] memory amounts) 673 | { 674 | require(path[path.length - 1] == WETH, 'BenSwapRouter: INVALID_PATH'); 675 | amounts = PancakeLibrary.getAmountsOut(factory, amountIn, path); 676 | require(amounts[amounts.length - 1] >= amountOutMin, 'BenSwapRouter: INSUFFICIENT_OUTPUT_AMOUNT'); 677 | TransferHelper.safeTransferFrom( 678 | path[0], msg.sender, PancakeLibrary.pairFor(factory, path[0], path[1]), amounts[0] 679 | ); 680 | _swap(amounts, path, address(this)); 681 | IWETH(WETH).withdraw(amounts[amounts.length - 1]); 682 | TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]); 683 | } 684 | function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline) 685 | external 686 | virtual 687 | override 688 | payable 689 | ensure(deadline) 690 | returns (uint[] memory amounts) 691 | { 692 | require(path[0] == WETH, 'BenSwapRouter: INVALID_PATH'); 693 | amounts = PancakeLibrary.getAmountsIn(factory, amountOut, path); 694 | require(amounts[0] <= msg.value, 'BenSwapRouter: EXCESSIVE_INPUT_AMOUNT'); 695 | IWETH(WETH).deposit{value: amounts[0]}(); 696 | assert(IWETH(WETH).transfer(PancakeLibrary.pairFor(factory, path[0], path[1]), amounts[0])); 697 | _swap(amounts, path, to); 698 | // refund dust eth, if any 699 | if (msg.value > amounts[0]) TransferHelper.safeTransferETH(msg.sender, msg.value - amounts[0]); 700 | } 701 | 702 | // **** SWAP (supporting fee-on-transfer tokens) **** 703 | // requires the initial amount to have already been sent to the first pair 704 | function _swapSupportingFeeOnTransferTokens(address[] memory path, address _to) internal virtual { 705 | for (uint i; i < path.length - 1; i++) { 706 | (address input, address output) = (path[i], path[i + 1]); 707 | (address token0,) = PancakeLibrary.sortTokens(input, output); 708 | IPancakePair pair = IPancakePair(PancakeLibrary.pairFor(factory, input, output)); 709 | uint amountInput; 710 | uint amountOutput; 711 | { // scope to avoid stack too deep errors 712 | (uint reserve0, uint reserve1,) = pair.getReserves(); 713 | (uint reserveInput, uint reserveOutput) = input == token0 ? (reserve0, reserve1) : (reserve1, reserve0); 714 | amountInput = IERC20(input).balanceOf(address(pair)).sub(reserveInput); 715 | amountOutput = PancakeLibrary.getAmountOut(amountInput, reserveInput, reserveOutput); 716 | } 717 | (uint amount0Out, uint amount1Out) = input == token0 ? (uint(0), amountOutput) : (amountOutput, uint(0)); 718 | address to = i < path.length - 2 ? PancakeLibrary.pairFor(factory, output, path[i + 2]) : _to; 719 | pair.swap(amount0Out, amount1Out, to, new bytes(0)); 720 | } 721 | } 722 | function swapExactTokensForTokensSupportingFeeOnTransferTokens( 723 | uint amountIn, 724 | uint amountOutMin, 725 | address[] calldata path, 726 | address to, 727 | uint deadline 728 | ) external virtual override ensure(deadline) { 729 | TransferHelper.safeTransferFrom( 730 | path[0], msg.sender, PancakeLibrary.pairFor(factory, path[0], path[1]), amountIn 731 | ); 732 | uint balanceBefore = IERC20(path[path.length - 1]).balanceOf(to); 733 | _swapSupportingFeeOnTransferTokens(path, to); 734 | require( 735 | IERC20(path[path.length - 1]).balanceOf(to).sub(balanceBefore) >= amountOutMin, 736 | 'BenSwapRouter: INSUFFICIENT_OUTPUT_AMOUNT' 737 | ); 738 | } 739 | function swapExactETHForTokensSupportingFeeOnTransferTokens( 740 | uint amountOutMin, 741 | address[] calldata path, 742 | address to, 743 | uint deadline 744 | ) 745 | external 746 | virtual 747 | override 748 | payable 749 | ensure(deadline) 750 | { 751 | require(path[0] == WETH, 'BenSwapRouter: INVALID_PATH'); 752 | uint amountIn = msg.value; 753 | IWETH(WETH).deposit{value: amountIn}(); 754 | assert(IWETH(WETH).transfer(PancakeLibrary.pairFor(factory, path[0], path[1]), amountIn)); 755 | uint balanceBefore = IERC20(path[path.length - 1]).balanceOf(to); 756 | _swapSupportingFeeOnTransferTokens(path, to); 757 | require( 758 | IERC20(path[path.length - 1]).balanceOf(to).sub(balanceBefore) >= amountOutMin, 759 | 'BenSwapRouter: INSUFFICIENT_OUTPUT_AMOUNT' 760 | ); 761 | } 762 | function swapExactTokensForETHSupportingFeeOnTransferTokens( 763 | uint amountIn, 764 | uint amountOutMin, 765 | address[] calldata path, 766 | address to, 767 | uint deadline 768 | ) 769 | external 770 | virtual 771 | override 772 | ensure(deadline) 773 | { 774 | require(path[path.length - 1] == WETH, 'BenSwapRouter: INVALID_PATH'); 775 | TransferHelper.safeTransferFrom( 776 | path[0], msg.sender, PancakeLibrary.pairFor(factory, path[0], path[1]), amountIn 777 | ); 778 | _swapSupportingFeeOnTransferTokens(path, address(this)); 779 | uint amountOut = IERC20(WETH).balanceOf(address(this)); 780 | require(amountOut >= amountOutMin, 'BenSwapRouter: INSUFFICIENT_OUTPUT_AMOUNT'); 781 | IWETH(WETH).withdraw(amountOut); 782 | TransferHelper.safeTransferETH(to, amountOut); 783 | } 784 | 785 | // **** LIBRARY FUNCTIONS **** 786 | function quote(uint amountA, uint reserveA, uint reserveB) public pure virtual override returns (uint amountB) { 787 | return PancakeLibrary.quote(amountA, reserveA, reserveB); 788 | } 789 | 790 | function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) 791 | public 792 | pure 793 | virtual 794 | override 795 | returns (uint amountOut) 796 | { 797 | return PancakeLibrary.getAmountOut(amountIn, reserveIn, reserveOut); 798 | } 799 | 800 | function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) 801 | public 802 | pure 803 | virtual 804 | override 805 | returns (uint amountIn) 806 | { 807 | return PancakeLibrary.getAmountIn(amountOut, reserveIn, reserveOut); 808 | } 809 | 810 | function getAmountsOut(uint amountIn, address[] memory path) 811 | public 812 | view 813 | virtual 814 | override 815 | returns (uint[] memory amounts) 816 | { 817 | return PancakeLibrary.getAmountsOut(factory, amountIn, path); 818 | } 819 | 820 | function getAmountsIn(uint amountOut, address[] memory path) 821 | public 822 | view 823 | virtual 824 | override 825 | returns (uint[] memory amounts) 826 | { 827 | return PancakeLibrary.getAmountsIn(factory, amountOut, path); 828 | } 829 | } 830 | --------------------------------------------------------------------------------