├── src ├── for ├── .prettierrc ├── package.json ├── utils.js ├── index.html ├── style.css └── js │ ├── index.js │ └── config.js ├── .gitignore ├── contracts ├── interfaces │ ├── V1 │ │ ├── IUniswapV1Factory.sol │ │ └── IUniswapV1Exchange.sol │ ├── IUniswapV2Callee.sol │ ├── V2 │ │ ├── IUniswapV2Callee.sol │ │ ├── IUniswapV2Factory.sol │ │ └── IUniswapV2Pair.sol │ ├── IWETH.sol │ ├── IUniswapV2Migrator.sol │ ├── IUniswapV2Library.sol │ ├── IUniswapV2Factory.sol │ ├── IERC20.sol │ ├── IUniswapV2ERC20.sol │ ├── IUniswapV2Pair.sol │ └── IUniswapV2Router01.sol ├── test │ ├── M0x.sol │ ├── MANA.sol │ ├── MDAI.sol │ ├── METH.sol │ ├── mBTC.sol │ ├── mUSDT.sol │ ├── ERC20.sol │ ├── CustomERC20.sol │ └── WETH9.sol ├── Migrations.sol ├── libraries │ ├── SafeMath.sol │ ├── Math.sol │ └── UQ112x112.sol ├── ForwarderReceiverBase.sol ├── UniswapV2Factory.sol ├── UniswapV2Migrator.sol ├── UniswapV2ERC20.sol ├── UniswapV2Library.sol ├── UniswapV2Pair.sol ├── EIP2585Forwader.sol └── UniswapV2Router01.sol ├── migrations ├── 1_initial_migration.js ├── 2_deploy_factory.js └── 3_deploy_contracts.js ├── package.json ├── README.md └── truffle-config.js /src/for: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build/contracts 3 | article 4 | -------------------------------------------------------------------------------- /src/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5", 3 | "tabWidth": 4, 4 | "semi": false, 5 | "singleQuote": true 6 | } -------------------------------------------------------------------------------- /contracts/interfaces/V1/IUniswapV1Factory.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 2 | 3 | interface IUniswapV1Factory { 4 | function getExchange(address) external view returns (address); 5 | } 6 | -------------------------------------------------------------------------------- /contracts/interfaces/IUniswapV2Callee.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 2 | 3 | interface IUniswapV2Callee { 4 | function uniswapV2Call(address sender, uint amount0, uint amount1, bytes calldata data) external; 5 | } 6 | -------------------------------------------------------------------------------- /contracts/interfaces/V2/IUniswapV2Callee.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 2 | 3 | interface IUniswapV2Callee { 4 | function uniswapV2Call(address sender, uint amount0, uint amount1, bytes calldata data) external; 5 | } 6 | -------------------------------------------------------------------------------- /contracts/interfaces/IWETH.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 2 | 3 | interface IWETH { 4 | function deposit() external payable; 5 | function transfer(address to, uint value) external returns (bool); 6 | function withdraw(uint) external; 7 | } 8 | -------------------------------------------------------------------------------- /migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | const Migrations = artifacts.require("Migrations"); 2 | 3 | module.exports = async function(deployer) { 4 | deployer.deploy(Migrations); 5 | let latestBlock = await web3.eth.getBlock("latest"); 6 | let now = latestBlock.timestamp; 7 | console.log(web3.utils.toHex(now+3600)); 8 | }; 9 | -------------------------------------------------------------------------------- /contracts/interfaces/IUniswapV2Migrator.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 2 | 3 | interface IUniswapV2Migrator { 4 | function factoryV1() external view returns (address); 5 | function router() external pure returns (address); 6 | 7 | function migrate(address token, uint amountTokenMin, uint amountETHMin, address to, uint deadline) external; 8 | } 9 | -------------------------------------------------------------------------------- /contracts/test/M0x.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 2 | 3 | import './CustomERC20.sol'; 4 | 5 | contract M0x is CustomERC20 { 6 | 7 | constructor(uint _initialSupply,uint _chainId) CustomERC20("m0x","m0x",_initialSupply,_chainId) public { 8 | 9 | } 10 | function mint(uint256 amount) public{ 11 | _mint(msg.sender, amount); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /contracts/test/MANA.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 2 | 3 | import './CustomERC20.sol'; 4 | 5 | contract MANA is CustomERC20 { 6 | 7 | constructor(uint _initialSupply,uint _chainId) CustomERC20("MANA","MANA",_initialSupply,_chainId) public { 8 | 9 | } 10 | function mint(uint256 amount) public{ 11 | _mint(msg.sender, amount); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /contracts/test/MDAI.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 2 | 3 | import './CustomERC20.sol'; 4 | 5 | contract MDAI is CustomERC20 { 6 | 7 | constructor(uint _initialSupply,uint _chainId) CustomERC20("mDAI","mDAI",_initialSupply,_chainId) public { 8 | 9 | } 10 | function mint(uint256 amount) public{ 11 | _mint(msg.sender, amount); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /contracts/test/METH.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 2 | 3 | import './CustomERC20.sol'; 4 | 5 | contract METH is CustomERC20 { 6 | 7 | constructor(uint _initialSupply,uint _chainId) CustomERC20("mETH","mETH",_initialSupply,_chainId) public { 8 | 9 | } 10 | function mint(uint256 amount) public{ 11 | _mint(msg.sender, amount); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /contracts/test/mBTC.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 2 | 3 | import './CustomERC20.sol'; 4 | 5 | contract MBTC is CustomERC20 { 6 | 7 | constructor(uint _initialSupply,uint _chainId) CustomERC20("mBTC","mBTC",_initialSupply,_chainId) public { 8 | 9 | } 10 | function mint(uint256 amount) public{ 11 | _mint(msg.sender, amount); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /contracts/test/mUSDT.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 2 | 3 | import './CustomERC20.sol'; 4 | 5 | contract MUSDT is CustomERC20 { 6 | 7 | constructor(uint _initialSupply,uint _chainId) CustomERC20("mUSDT","mUSDT",_initialSupply,_chainId) public { 8 | 9 | } 10 | function mint(uint256 amount) public{ 11 | _mint(msg.sender, amount); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.21 <0.7.0; 2 | 3 | contract Migrations { 4 | address public owner; 5 | uint public last_completed_migration; 6 | 7 | constructor() public { 8 | owner = msg.sender; 9 | } 10 | 11 | modifier restricted() { 12 | if (msg.sender == owner) _; 13 | } 14 | 15 | function setCompleted(uint completed) public restricted { 16 | last_completed_migration = completed; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "maticUniswapWithEIP2585", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "truffle-config.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "scripts": { 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | }, 12 | "keywords": [], 13 | "author": "", 14 | "license": "ISC", 15 | "devDependencies": { 16 | "@truffle/hdwallet-provider": "^1.0.34" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /contracts/interfaces/V1/IUniswapV1Exchange.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 2 | 3 | interface IUniswapV1Exchange { 4 | function balanceOf(address owner) external view returns (uint); 5 | function transferFrom(address from, address to, uint value) external returns (bool); 6 | function removeLiquidity(uint, uint, uint, uint) external returns (uint, uint); 7 | function tokenToEthSwapInput(uint, uint, uint) external returns (uint); 8 | function ethToTokenSwapInput(uint, uint) external payable returns (uint); 9 | } 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gasless-uniswap 2 | swap away without hodling ETH 3 | 4 | # Here is the frontend: https://gasless-uniswap.web.app/
5 | For more detailed explanation : https://medium.com/@shahyashs145/introducing-gasless-uniswap-dd056a2355de
6 | Demo video: https://www.youtube.com/watch?v=wu5mGoWAMuE 7 | 8 | Try it out on ropsten or matic testnetv3 (rpc: https://testnetv3.matic.network) 9 | 10 | # Run the front end locally 11 | 1. go to src directory 12 | 2. npm install 13 | 3. npm run dev 14 | 15 | # Deploy the contracts 16 | 1. npm install 17 | 2. truffle migrate --network [networkName] 18 | -------------------------------------------------------------------------------- /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/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/IUniswapV2Library.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 2 | 3 | interface IUniswapV2Library { 4 | function factory() external pure returns (address); 5 | 6 | function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB); 7 | function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut); 8 | function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn); 9 | function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts); 10 | function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts); 11 | } 12 | -------------------------------------------------------------------------------- /contracts/interfaces/IUniswapV2Factory.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 2 | 3 | interface IUniswapV2Factory { 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/V2/IUniswapV2Factory.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 2 | 3 | interface IUniswapV2Factory { 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 | -------------------------------------------------------------------------------- /src/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "htmlFrontend", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "PlaceHolder for a prettier Frontend", 6 | "dependencies": { 7 | "browserify": "^16.5.0", 8 | "eth-sig-util": "^2.5.3", 9 | "light-server": "^2.6.4", 10 | "web3": "^1.2.6" 11 | }, 12 | "devDependencies": { 13 | "@biconomy/mexa": "^1.5.7", 14 | "babel-preset-es2015": "^6.24.1", 15 | "babelify": "^10.0.0" 16 | }, 17 | "scripts": { 18 | "build:js": "browserify --standalone moduleTry ./js/index.js > bundle.js", 19 | "test": "echo \"Error: no test specified\" && exit 1", 20 | "dev": "light-server -s . -p 9090 -w \"./js/**/*.js, ./*.html # npm run build:js\"" 21 | }, 22 | "author": "yashnaman", 23 | "license": "ISC" 24 | } 25 | -------------------------------------------------------------------------------- /contracts/ForwarderReceiverBase.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 2 | 3 | 4 | contract ForwarderReceiverBase { 5 | /* immutable */ 6 | address _forwarder; // can be hardcoded once the Forwarder address is known 7 | 8 | constructor(address forwarder) public { 9 | _forwarder = forwarder; 10 | } 11 | 12 | function _getTxSigner() internal view returns (address payable signer) { 13 | if (msg.sender == _forwarder) { 14 | bytes memory data = msg.data; 15 | uint256 length = msg.data.length; 16 | assembly { 17 | signer := and( 18 | mload(sub(add(data, length), 0x00)), 19 | 0xffffffffffffffffffffffffffffffffffffffff 20 | ) 21 | } 22 | } else { 23 | signer = msg.sender; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /contracts/interfaces/IERC20.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 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 | -------------------------------------------------------------------------------- /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 | // multiply a UQ112x112 by a uint, returning a UQ112x112 in a uint container 22 | function uqmul(uint224 x, uint y) internal pure returns (uint z) { 23 | require(y == 0 || (z = uint(x) * y) / y == uint(x), "uqmul-overflow"); 24 | } 25 | 26 | // decode a UQ112x112 in a uint container into a uint 27 | function decode(uint y) internal pure returns (uint z) { 28 | z = y / uint(Q112); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /contracts/interfaces/IUniswapV2ERC20.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 2 | 3 | interface IUniswapV2ERC20 { 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 | -------------------------------------------------------------------------------- /migrations/2_deploy_factory.js: -------------------------------------------------------------------------------- 1 | const UniswapV2Factory = artifacts.require("UniswapV2Factory"); 2 | const EIP712Forwarder = artifacts.require("EIP712Forwarder"); 3 | 4 | module.exports = function(deployer, network, accounts) { 5 | deployer.then(async () => { 6 | 7 | async function getNetID() { 8 | return new Promise(function(resolve, reject) { 9 | web3.providers.HttpProvider.prototype.sendAsync = 10 | web3.providers.HttpProvider.prototype.send; 11 | 12 | web3.currentProvider.sendAsync( 13 | { 14 | jsonrpc: "2.0", 15 | method: "net_version", 16 | params: [], 17 | id: 0 18 | }, 19 | function(err, result) { 20 | if (err) { 21 | console.error(err.message); 22 | reject(err); 23 | } else { 24 | resolve(result.result); 25 | } 26 | } 27 | ); 28 | }); 29 | } 30 | setter = accounts[0]; 31 | //deploy the facotry 32 | let factoryContract = await deployer.deploy(UniswapV2Factory, setter); 33 | console.log(await web3.eth.net.getId()); 34 | 35 | 36 | 37 | let chainId = await getNetID(); 38 | console.log(chainId); 39 | let try1 = web3.utils.toHex(chainId); 40 | let EIP712ForwarderContract = await deployer.deploy(EIP712Forwarder,try1); 41 | }); 42 | }; 43 | -------------------------------------------------------------------------------- /contracts/UniswapV2Factory.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 2 | 3 | import './interfaces/IUniswapV2Factory.sol'; 4 | import './UniswapV2Pair.sol'; 5 | 6 | contract UniswapV2Factory is IUniswapV2Factory { 7 | address public feeTo; 8 | address public feeToSetter; 9 | 10 | mapping(address => mapping(address => address)) public getPair; 11 | address[] public allPairs; 12 | 13 | event PairCreated(address indexed token0, address indexed token1, address pair, uint); 14 | 15 | constructor(address _feeToSetter) public { 16 | feeToSetter = _feeToSetter; 17 | } 18 | 19 | function allPairsLength() external view returns (uint) { 20 | return allPairs.length; 21 | } 22 | 23 | function createPair(address tokenA, address tokenB) external returns (address pair) { 24 | require(tokenA != tokenB, 'UniswapV2: IDENTICAL_ADDRESSES'); 25 | (address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); 26 | require(token0 != address(0), 'UniswapV2: ZERO_ADDRESS'); 27 | require(getPair[token0][token1] == address(0), 'UniswapV2: PAIR_EXISTS'); // single check is sufficient 28 | bytes memory bytecode = type(UniswapV2Pair).creationCode; 29 | bytes32 salt = keccak256(abi.encodePacked(token0, token1)); 30 | assembly { 31 | pair := create2(0, add(bytecode, 32), mload(bytecode), salt) 32 | } 33 | IUniswapV2Pair(pair).initialize(token0, token1); 34 | getPair[token0][token1] = pair; 35 | getPair[token1][token0] = pair; // populate mapping in the reverse direction 36 | allPairs.push(pair); 37 | emit PairCreated(token0, token1, pair, allPairs.length); 38 | } 39 | 40 | function setFeeTo(address _feeTo) external { 41 | require(msg.sender == feeToSetter, 'UniswapV2: FORBIDDEN'); 42 | feeTo = _feeTo; 43 | } 44 | 45 | function setFeeToSetter(address _feeToSetter) external { 46 | require(msg.sender == feeToSetter, 'UniswapV2: FORBIDDEN'); 47 | feeToSetter = _feeToSetter; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /contracts/interfaces/IUniswapV2Pair.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 2 | 3 | interface IUniswapV2Pair { 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 | -------------------------------------------------------------------------------- /contracts/interfaces/V2/IUniswapV2Pair.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 2 | 3 | interface IUniswapV2Pair { 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 | -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | var x, i, j, selElmnt, a, b, c; 2 | /* Look for any elements with the class "custom-select": */ 3 | x = document.getElementsByClassName("custom-select"); 4 | for (i = 0; i < x.length; i++) { 5 | selElmnt = x[i].getElementsByTagName("select")[0]; 6 | /* For each element, create a new DIV that will act as the selected item: */ 7 | a = document.createElement("DIV"); 8 | a.setAttribute("class", "select-selected"); 9 | a.innerHTML = selElmnt.options[selElmnt.selectedIndex].innerHTML; 10 | x[i].appendChild(a); 11 | /* For each element, create a new DIV that will contain the option list: */ 12 | b = document.createElement("DIV"); 13 | b.setAttribute("class", "select-items select-hide"); 14 | for (j = 1; j < selElmnt.length; j++) { 15 | /* For each option in the original select element, 16 | create a new DIV that will act as an option item: */ 17 | c = document.createElement("DIV"); 18 | c.innerHTML = selElmnt.options[j].innerHTML; 19 | c.addEventListener("click", function(e) { 20 | /* When an item is clicked, update the original select box, 21 | and the selected item: */ 22 | var y, i, k, s, h; 23 | s = this.parentNode.parentNode.getElementsByTagName("select")[0]; 24 | h = this.parentNode.previousSibling; 25 | for (i = 0; i < s.length; i++) { 26 | if (s.options[i].innerHTML == this.innerHTML) { 27 | s.selectedIndex = i; 28 | h.innerHTML = this.innerHTML; 29 | y = this.parentNode.getElementsByClassName("same-as-selected"); 30 | for (k = 0; k < y.length; k++) { 31 | y[k].removeAttribute("class"); 32 | } 33 | this.setAttribute("class", "same-as-selected"); 34 | break; 35 | } 36 | } 37 | h.click(); 38 | }); 39 | b.appendChild(c); 40 | } 41 | x[i].appendChild(b); 42 | a.addEventListener("click", function(e) { 43 | /* When the select box is clicked, close any other select boxes, 44 | and open/close the current select box: */ 45 | e.stopPropagation(); 46 | closeAllSelect(this); 47 | this.nextSibling.classList.toggle("select-hide"); 48 | this.classList.toggle("select-arrow-active"); 49 | }); 50 | } 51 | 52 | function closeAllSelect(elmnt) { 53 | /* A function that will close all select boxes in the document, 54 | except the current select box: */ 55 | var x, y, i, arrNo = []; 56 | x = document.getElementsByClassName("select-items"); 57 | y = document.getElementsByClassName("select-selected"); 58 | for (i = 0; i < y.length; i++) { 59 | if (elmnt == y[i]) { 60 | arrNo.push(i) 61 | } else { 62 | y[i].classList.remove("select-arrow-active"); 63 | } 64 | } 65 | for (i = 0; i < x.length; i++) { 66 | if (arrNo.indexOf(i)) { 67 | x[i].classList.add("select-hide"); 68 | } 69 | } 70 | } 71 | 72 | /* If the user clicks anywhere outside the select box, 73 | then close all select boxes: */ 74 | document.addEventListener("click", closeAllSelect); -------------------------------------------------------------------------------- /contracts/UniswapV2Migrator.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 2 | 3 | import './interfaces/IUniswapV2Migrator.sol'; 4 | import './interfaces/V1/IUniswapV1Factory.sol'; 5 | import './interfaces/V1/IUniswapV1Exchange.sol'; 6 | import './interfaces/IUniswapV2Router01.sol'; 7 | 8 | contract UniswapV2Migrator is IUniswapV2Migrator { 9 | bytes4 private constant SELECTOR_APPROVE = bytes4(keccak256(bytes('approve(address,uint256)'))); 10 | bytes4 private constant SELECTOR_TRANSFER = bytes4(keccak256(bytes('transfer(address,uint256)'))); 11 | 12 | IUniswapV1Factory public factoryV1; 13 | // router address is identical across mainnet and testnets but differs between testing and deployed environments 14 | IUniswapV2Router01 public constant router = IUniswapV2Router01(0x84e924C5E04438D2c1Df1A981f7E7104952e6de1); 15 | 16 | function _safeApprove(address token, address to, uint value) private { 17 | (bool success, bytes memory data) = token.call(abi.encodeWithSelector(SELECTOR_APPROVE, to, value)); 18 | require(success && (data.length == 0 || abi.decode(data, (bool))), 'APPROVE_FAILED'); 19 | } 20 | 21 | function _safeTransfer(address token, address to, uint value) private { 22 | (bool success, bytes memory data) = token.call(abi.encodeWithSelector(SELECTOR_TRANSFER, to, value)); 23 | require(success && (data.length == 0 || abi.decode(data, (bool))), 'TRANSFER_FAILED'); 24 | } 25 | 26 | function _safeTransferETH(address to, uint value) private { 27 | (bool success,) = to.call.value(value)(new bytes(0)); 28 | require(success, 'ETH_TRANSFER_FAILED'); 29 | } 30 | 31 | constructor(address _factoryV1) public { 32 | factoryV1 = IUniswapV1Factory(_factoryV1); 33 | } 34 | 35 | // needs to accept ETH from any v1 exchange and the router. ideally this could be enforced, as in the router, 36 | // but it's not possible because it requires a call to the v1 factory, which takes too much gas 37 | function() external payable {} 38 | 39 | function migrate(address token, uint amountTokenMin, uint amountETHMin, address to, uint deadline) external { 40 | IUniswapV1Exchange exchangeV1 = IUniswapV1Exchange(factoryV1.getExchange(token)); 41 | uint liquidityV1 = exchangeV1.balanceOf(msg.sender); 42 | require(exchangeV1.transferFrom(msg.sender, address(this), liquidityV1), 'TRANSFER_FROM_FAILED'); 43 | (uint amountETHV1, uint amountTokenV1) = exchangeV1.removeLiquidity(liquidityV1, 1, 1, uint(-1)); 44 | _safeApprove(token, address(router), amountTokenV1); 45 | (uint amountTokenV2, uint amountETHV2,) = router.addLiquidityETH.value(amountETHV1)( 46 | token, 47 | amountTokenV1, 48 | amountTokenMin, 49 | amountETHMin, 50 | to, 51 | deadline 52 | ); 53 | if (amountTokenV1 > amountTokenV2) { 54 | _safeApprove(token, address(router), 0); // be a good blockchain citizen, reset allowance to 0 55 | _safeTransfer(token, msg.sender, amountTokenV1 - amountTokenV2); 56 | } else if (amountETHV1 > amountETHV2) { 57 | // addLiquidityETH guarantees that all of amountETHV1 or amountTokenV1 will be used, hence this else is safe 58 | _safeTransferETH(msg.sender, amountETHV1 - amountETHV2); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /contracts/test/ERC20.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 2 | 3 | import '../libraries/SafeMath.sol'; 4 | 5 | contract ERC20 { 6 | using SafeMath for uint; 7 | 8 | string public constant name = 'Test Token'; 9 | string public constant symbol = 'TT'; 10 | uint8 public constant decimals = 18; 11 | uint public totalSupply; 12 | mapping(address => uint) public balanceOf; 13 | mapping(address => mapping(address => uint)) public allowance; 14 | 15 | bytes32 public DOMAIN_SEPARATOR; 16 | // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); 17 | bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; 18 | mapping(address => uint) public nonces; 19 | 20 | event Approval(address indexed owner, address indexed spender, uint value); 21 | event Transfer(address indexed from, address indexed to, uint value); 22 | 23 | constructor(uint _totalSupply) public { 24 | uint chainId; 25 | assembly { 26 | chainId := chainid 27 | } 28 | DOMAIN_SEPARATOR = keccak256( 29 | abi.encode( 30 | keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'), 31 | keccak256(bytes(name)), 32 | keccak256(bytes('1')), 33 | chainId, 34 | address(this) 35 | ) 36 | ); 37 | _mint(msg.sender, _totalSupply); 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, '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, 'INVALID_SIGNATURE'); 92 | _approve(owner, spender, value); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /contracts/interfaces/IUniswapV2Router01.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 2 | 3 | interface IUniswapV2Router01 { 4 | function factory() external pure returns (address); 5 | 6 | function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB); 7 | function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut); 8 | function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn); 9 | function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts); 10 | function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts); 11 | 12 | function WETH() external view returns (address); 13 | 14 | function addLiquidity( 15 | address tokenA, 16 | address tokenB, 17 | uint amountADesired, 18 | uint amountBDesired, 19 | uint amountAMin, 20 | uint amountBMin, 21 | address to, 22 | uint deadline 23 | ) external returns (uint amountA, uint amountB, uint liquidity); 24 | function addLiquidityETH( 25 | address token, 26 | uint amountTokenDesired, 27 | uint amountTokenMin, 28 | uint amountETHMin, 29 | address to, 30 | uint deadline 31 | ) external payable returns (uint amountToken, uint amountETH, uint liquidity); 32 | function removeLiquidity( 33 | address tokenA, 34 | address tokenB, 35 | uint liquidity, 36 | uint amountAMin, 37 | uint amountBMin, 38 | address to, 39 | uint deadline 40 | ) external returns (uint amountA, uint amountB); 41 | function removeLiquidityETH( 42 | address token, 43 | uint liquidity, 44 | uint amountTokenMin, 45 | uint amountETHMin, 46 | address to, 47 | uint deadline 48 | ) external returns (uint amountToken, uint amountETH); 49 | function removeLiquidityWithPermit( 50 | address tokenA, 51 | address tokenB, 52 | uint liquidity, 53 | uint amountAMin, 54 | uint amountBMin, 55 | address to, 56 | uint deadline, 57 | bool approveMax, uint8 v, bytes32 r, bytes32 s 58 | ) external returns (uint amountA, uint amountB); 59 | function removeLiquidityETHWithPermit( 60 | address token, 61 | uint liquidity, 62 | uint amountTokenMin, 63 | uint amountETHMin, 64 | address to, 65 | uint deadline, 66 | bool approveMax, uint8 v, bytes32 r, bytes32 s 67 | ) external returns (uint amountToken, uint amountETH); 68 | function swapExactTokensForTokens( 69 | uint amountIn, 70 | uint amountOutMin, 71 | address[] calldata path, 72 | address to, 73 | uint deadline 74 | ) external returns (uint[] memory amounts); 75 | function swapTokensForExactTokens( 76 | uint amountOut, 77 | uint amountInMax, 78 | address[] calldata path, 79 | address to, 80 | uint deadline 81 | ) external returns (uint[] memory amounts); 82 | function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) 83 | external 84 | payable 85 | returns (uint[] memory amounts); 86 | function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline) 87 | external 88 | returns (uint[] memory amounts); 89 | function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) 90 | external 91 | returns (uint[] memory amounts); 92 | function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline) 93 | external 94 | payable 95 | returns (uint[] memory amounts); 96 | } 97 | -------------------------------------------------------------------------------- /contracts/test/CustomERC20.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 2 | 3 | import '../interfaces/IERC20.sol'; 4 | import '../libraries/SafeMath.sol'; 5 | 6 | contract CustomERC20 is IERC20 { 7 | using SafeMath for uint; 8 | 9 | string public name; 10 | string public symbol; 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(string memory _name,string memory _symbol,uint _totalSupply,uint _chainId) public { 25 | name = _name; 26 | symbol = _symbol; 27 | _mint(msg.sender, _totalSupply); 28 | 29 | uint chainId = _chainId; 30 | 31 | // assembly { 32 | // chainId := chainid 33 | // } 34 | DOMAIN_SEPARATOR = keccak256( 35 | abi.encode( 36 | keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'), 37 | keccak256(bytes(name)), 38 | keccak256(bytes('1')), 39 | chainId, 40 | address(this) 41 | ) 42 | ); 43 | 44 | } 45 | 46 | function _mint(address to, uint value) internal { 47 | totalSupply = totalSupply.add(value); 48 | balanceOf[to] = balanceOf[to].add(value); 49 | emit Transfer(address(0), to, value); 50 | } 51 | 52 | function _burn(address from, uint value) internal { 53 | balanceOf[from] = balanceOf[from].sub(value); 54 | totalSupply = totalSupply.sub(value); 55 | emit Transfer(from, address(0), value); 56 | } 57 | 58 | function _approve(address owner, address spender, uint value) private { 59 | allowance[owner][spender] = value; 60 | emit Approval(owner, spender, value); 61 | } 62 | 63 | function _transfer(address from, address to, uint value) private { 64 | balanceOf[from] = balanceOf[from].sub(value); 65 | balanceOf[to] = balanceOf[to].add(value); 66 | emit Transfer(from, to, value); 67 | } 68 | 69 | function approve(address spender, uint value) external returns (bool) { 70 | _approve(msg.sender, spender, value); 71 | return true; 72 | } 73 | 74 | function transfer(address to, uint value) external returns (bool) { 75 | _transfer(msg.sender, to, value); 76 | return true; 77 | } 78 | 79 | function transferFrom(address from, address to, uint value) external returns (bool) { 80 | if (allowance[from][msg.sender] != uint(-1)) { 81 | allowance[from][msg.sender] = allowance[from][msg.sender].sub(value); 82 | } 83 | _transfer(from, to, value); 84 | return true; 85 | } 86 | 87 | function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external { 88 | require(deadline >= block.timestamp, 'UniswapV2: EXPIRED'); 89 | bytes32 digest = keccak256( 90 | abi.encodePacked( 91 | '\x19\x01', 92 | DOMAIN_SEPARATOR, 93 | keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline)) 94 | ) 95 | ); 96 | address recoveredAddress = ecrecover(digest, v, r, s); 97 | require(recoveredAddress != address(0) && recoveredAddress == owner, 'UniswapV2: INVALID_SIGNATURE'); 98 | _approve(owner, spender, value); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /contracts/UniswapV2ERC20.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 2 | 3 | import "./interfaces/IUniswapV2ERC20.sol"; 4 | import "./libraries/SafeMath.sol"; 5 | 6 | 7 | contract UniswapV2ERC20 is IUniswapV2ERC20 { 8 | using SafeMath for uint256; 9 | 10 | string public constant name = "Uniswap V2"; 11 | string public constant symbol = "UNI-V2"; 12 | uint8 public constant decimals = 18; 13 | uint256 public totalSupply; 14 | mapping(address => uint256) public balanceOf; 15 | mapping(address => mapping(address => uint256)) public allowance; 16 | 17 | bytes32 public DOMAIN_SEPARATOR; 18 | // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); 19 | bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; 20 | mapping(address => uint256) public nonces; 21 | 22 | event Approval( 23 | address indexed owner, 24 | address indexed spender, 25 | uint256 value 26 | ); 27 | event Transfer(address indexed from, address indexed to, uint256 value); 28 | 29 | //0x46 not supported on matic? 30 | constructor() public { 31 | uint256 chainId = 15000; 32 | // assembly { 33 | // chainId := chainid 34 | // } 35 | DOMAIN_SEPARATOR = keccak256( 36 | abi.encode( 37 | keccak256( 38 | "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" 39 | ), 40 | keccak256(bytes(name)), 41 | keccak256(bytes("1")), 42 | chainId, 43 | address(this) 44 | ) 45 | ); 46 | } 47 | 48 | function _mint(address to, uint256 value) internal { 49 | totalSupply = totalSupply.add(value); 50 | balanceOf[to] = balanceOf[to].add(value); 51 | emit Transfer(address(0), to, value); 52 | } 53 | 54 | function _burn(address from, uint256 value) internal { 55 | balanceOf[from] = balanceOf[from].sub(value); 56 | totalSupply = totalSupply.sub(value); 57 | emit Transfer(from, address(0), value); 58 | } 59 | 60 | function _approve(address owner, address spender, uint256 value) private { 61 | allowance[owner][spender] = value; 62 | emit Approval(owner, spender, value); 63 | } 64 | 65 | function _transfer(address from, address to, uint256 value) private { 66 | balanceOf[from] = balanceOf[from].sub(value); 67 | balanceOf[to] = balanceOf[to].add(value); 68 | emit Transfer(from, to, value); 69 | } 70 | 71 | function approve(address spender, uint256 value) external returns (bool) { 72 | _approve(msg.sender, spender, value); 73 | return true; 74 | } 75 | 76 | function transfer(address to, uint256 value) external returns (bool) { 77 | _transfer(msg.sender, to, value); 78 | return true; 79 | } 80 | 81 | function transferFrom(address from, address to, uint256 value) 82 | external 83 | returns (bool) 84 | { 85 | if (allowance[from][msg.sender] != uint256(-1)) { 86 | allowance[from][msg.sender] = allowance[from][msg.sender].sub( 87 | value 88 | ); 89 | } 90 | _transfer(from, to, value); 91 | return true; 92 | } 93 | 94 | function permit( 95 | address owner, 96 | address spender, 97 | uint256 value, 98 | uint256 deadline, 99 | uint8 v, 100 | bytes32 r, 101 | bytes32 s 102 | ) external { 103 | require(deadline >= block.timestamp, "UniswapV2: EXPIRED"); 104 | bytes32 digest = keccak256( 105 | abi.encodePacked( 106 | "\x19\x01", 107 | DOMAIN_SEPARATOR, 108 | keccak256( 109 | abi.encode( 110 | PERMIT_TYPEHASH, 111 | owner, 112 | spender, 113 | value, 114 | nonces[owner]++, 115 | deadline 116 | ) 117 | ) 118 | ) 119 | ); 120 | address recoveredAddress = ecrecover(digest, v, r, s); 121 | require( 122 | recoveredAddress != address(0) && recoveredAddress == owner, 123 | "UniswapV2: INVALID_SIGNATURE" 124 | ); 125 | _approve(owner, spender, value); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /truffle-config.js: -------------------------------------------------------------------------------- 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 | * truffleframework.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 | // const infuraKey = "fj4jll3k....."; 23 | // 24 | const fs = require('fs'); 25 | const mnemonic = fs.readFileSync(".secret").toString().trim(); 26 | 27 | module.exports = { 28 | /** 29 | * Networks define how you connect to your ethereum client and let you set the 30 | * defaults web3 uses to send transactions. If you don't specify one truffle 31 | * will spin up a development blockchain for you on port 9545 when you 32 | * run `develop` or `test`. You can ask a truffle command to use a specific 33 | * network from the command line, e.g 34 | * 35 | * $ truffle test --network 36 | */ 37 | 38 | networks: { 39 | // Useful for testing. The `development` name is special - truffle uses it by default 40 | // if it's defined here and no other network is specified at the command line. 41 | // You should run a client (like ganache-cli, geth or parity) in a separate terminal 42 | // tab if you use this network and you must also set the `host`, `port` and `network_id` 43 | // options below to some value. 44 | // 45 | development: { 46 | host: "127.0.0.1", // Localhost (default: none) 47 | port: 8545, // Standard Ethereum port (default: none) 48 | network_id: "*", // Any network (default: none) 49 | }, 50 | matic: { 51 | provider: () => 52 | new HDWalletProvider(mnemonic, `https://testnetv3.matic.network`), 53 | network_id: 15001, 54 | gasPrice: "0x0", 55 | confirmations: 0, 56 | timeoutBlocks: 200, 57 | skipDryRun: true 58 | }, 59 | matic2: { 60 | provider: () => 61 | new HDWalletProvider(mnemonic, `https://testnet.matic.network`), 62 | network_id: 15001, 63 | gasPrice: "0x0", 64 | confirmations: 1, 65 | timeoutBlocks: 200, 66 | skipDryRun: true 67 | }, 68 | // Another network with more advanced options... 69 | // advanced: { 70 | // port: 8777, // Custom port 71 | // network_id: 1342, // Custom network 72 | // gas: 8500000, // Gas sent with each transaction (default: ~6700000) 73 | // gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei) 74 | // from:
, // Account to send txs from (default: accounts[0]) 75 | // websockets: true // Enable EventEmitter interface for web3 (default: false) 76 | // }, 77 | 78 | // Useful for deploying to a public network. 79 | // NB: It's important to wrap the provider as a function. 80 | ropsten: { 81 | provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/2a1a54c3aa374385ae4531da66fdf150`), 82 | network_id: 3, // Ropsten's id 83 | gas: 5500000, // Ropsten has a lower block limit than mainnet 84 | confirmations: 2, // # of confs to wait between deployments. (default: 0) 85 | timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50) 86 | skipDryRun: true // Skip dry run before migrations? (default: false for public nets ) 87 | }, 88 | 89 | // Useful for private networks 90 | // private: { 91 | // provider: () => new HDWalletProvider(mnemonic, `https://network.io`), 92 | // network_id: 2111, // This network is yours, in the cloud. 93 | // production: true // Treats this network as if it was a public net. (default: false) 94 | // } 95 | }, 96 | 97 | // Set default mocha options here, use special reporters etc. 98 | mocha: { 99 | // timeout: 100000 100 | }, 101 | 102 | // Configure your compilers 103 | compilers: { 104 | solc: { 105 | version: "0.5.16", // Fetch exact version from solc-bin (default: truffle's version) 106 | // docker: true, // Use "0.5.1" you've installed locally with docker (default: false) 107 | // settings: { // See the solidity docs for advice about optimization and evmVersion 108 | // optimizer: { 109 | // enabled: false, 110 | // runs: 200 111 | // }, 112 | // evmVersion: "byzantium" 113 | // } 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Gasless Uniswap 5 | 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 |

Gasless Uniswap

17 |         18 |
19 |
27 |
28 | 29 |
30 |

SWAP

31 |
32 |
33 | 44 | 45 | 46 |    47 | 48 | 49 | 50 |
51 |
52 | 53 | 54 |
55 | 68 |    69 | 70 |
71 |
72 | 73 |
74 | 75 |
76 |
77 | 78 | 81 | 82 | 83 | 84 |
85 |
86 | 87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |

ADD LIQUIDITY

95 |
96 |
97 | 108 | 109 | 110 |    111 | 112 | 115 | 116 | 117 |
118 |
119 | 120 | 121 |
122 | 134 | 135 |    136 | 137 | 140 |
141 |
142 | 143 |
144 | 145 |
146 |
147 | 148 | 149 |
150 |
151 | 152 |
153 |
154 |
155 | 156 | 157 | 158 | 159 |
160 | 161 |

Github

162 | https://github.com/yashnaman/gasless-uniswap 163 | 164 |

✌️

165 | 166 |
167 | 168 | 169 | -------------------------------------------------------------------------------- /contracts/UniswapV2Library.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 2 | 3 | import "./interfaces/IUniswapV2Library.sol"; 4 | import "./libraries/SafeMath.sol"; 5 | import "./interfaces/V2/IUniswapV2Factory.sol"; 6 | import "./interfaces/V2/IUniswapV2Pair.sol"; 7 | 8 | 9 | contract UniswapV2Library is IUniswapV2Library { 10 | using SafeMath for uint256; 11 | 12 | // factory address is identical across mainnet and testnets but differs between testing and deployed environments 13 | IUniswapV2Factory public factory; 14 | 15 | // returns sorted token addresses, used to handle return values from pairs sorted in this order 16 | function sortTokens(address tokenA, address tokenB) 17 | internal 18 | pure 19 | returns (address token0, address token1) 20 | { 21 | require(tokenA != tokenB, "UniswapV2Helper: IDENTICAL_ADDRESSES"); 22 | (token0, token1) = tokenA < tokenB 23 | ? (tokenA, tokenB) 24 | : (tokenB, tokenA); 25 | require(token0 != address(0), "UniswapV2Helper: ZERO_ADDRESS"); 26 | } 27 | 28 | // calculates the CREATE2 address for a pair without making any external calls 29 | //It seems that CREATE2 address does not work in Ganache? 30 | function pairFor(address tokenA, address tokenB) 31 | internal 32 | view 33 | returns (address pair) 34 | { 35 | (address token0, address token1) = sortTokens(tokenA, tokenB); 36 | 37 | // pair = address( 38 | // uint256( 39 | // keccak256( 40 | // abi.encodePacked( 41 | // hex"ff", 42 | // factory, 43 | // keccak256(abi.encodePacked(token0, token1)), 44 | // hex"0b77fb54a078d9399fa29cac94f5b35b9f11611b456ab507c7f46754712b642b" // init code hash 45 | // ) 46 | // ) 47 | // ) 48 | // ); 49 | pair = factory.getPair(token0, token1); 50 | } 51 | 52 | // fetches and sorts the reserves for a pair 53 | function getReserves(address tokenA, address tokenB) 54 | public 55 | view 56 | returns (uint256 reserveA, uint256 reserveB) 57 | { 58 | (address token0, ) = sortTokens(tokenA, tokenB); 59 | (uint256 reserve0, uint256 reserve1, ) = IUniswapV2Pair( 60 | pairFor(tokenA, tokenB) 61 | ) 62 | .getReserves(); 63 | (reserveA, reserveB) = tokenA == token0 64 | ? (reserve0, reserve1) 65 | : (reserve1, reserve0); 66 | } 67 | 68 | // given some amount of an asset and pair reserves, returns an equivalent amount of the other asset 69 | function quote(uint256 amountA, uint256 reserveA, uint256 reserveB) 70 | public 71 | pure 72 | returns (uint256 amountB) 73 | { 74 | require(amountA > 0, "UniswapV2Helper: INSUFFICIENT_AMOUNT"); 75 | require( 76 | reserveA > 0 && reserveB > 0, 77 | "UniswapV2Helper: INSUFFICIENT_LIQUIDITY" 78 | ); 79 | amountB = amountA.mul(reserveB) / reserveA; 80 | } 81 | 82 | // given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset 83 | function getAmountOut( 84 | uint256 amountIn, 85 | uint256 reserveIn, 86 | uint256 reserveOut 87 | ) public pure returns (uint256 amountOut) { 88 | require(amountIn > 0, "UniswapV2Helper: INSUFFICIENT_INPUT_AMOUNT"); 89 | require( 90 | reserveIn > 0 && reserveOut > 0, 91 | "UniswapV2Helper: INSUFFICIENT_LIQUIDITY" 92 | ); 93 | uint256 amountInWithFee = amountIn.mul(997); 94 | uint256 numerator = amountInWithFee.mul(reserveOut); 95 | uint256 denominator = reserveIn.mul(1000).add(amountInWithFee); 96 | amountOut = numerator / denominator; 97 | } 98 | 99 | // given an output amount of an asset and pair reserves, returns a required input amount of the other asset 100 | function getAmountIn( 101 | uint256 amountOut, 102 | uint256 reserveIn, 103 | uint256 reserveOut 104 | ) public pure returns (uint256 amountIn) { 105 | require(amountOut > 0, "UniswapV2Helper: INSUFFICIENT_OUTPUT_AMOUNT"); 106 | require( 107 | reserveIn > 0 && reserveOut > 0, 108 | "UniswapV2Helper: INSUFFICIENT_LIQUIDITY" 109 | ); 110 | uint256 numerator = reserveIn.mul(amountOut).mul(1000); 111 | uint256 denominator = reserveOut.sub(amountOut).mul(997); 112 | amountIn = (numerator / denominator).add(1); 113 | } 114 | 115 | // performs chained getAmountOut calculations on any number of pairs 116 | function getAmountsOut(uint256 amountIn, address[] memory path) 117 | public 118 | view 119 | returns (uint256[] memory amounts) 120 | { 121 | require(path.length >= 2, "UniswapV2Helper: INVALID_PATH"); 122 | amounts = new uint256[](path.length); 123 | amounts[0] = amountIn; 124 | for (uint256 i; i < path.length - 1; i++) { 125 | (uint256 reserveIn, uint256 reserveOut) = getReserves( 126 | path[i], 127 | path[i + 1] 128 | ); 129 | amounts[i + 1] = getAmountOut(amounts[i], reserveIn, reserveOut); 130 | } 131 | } 132 | 133 | // performs chained getAmountIn calculations on any number of pairs 134 | function getAmountsIn(uint256 amountOut, address[] memory path) 135 | public 136 | view 137 | returns (uint256[] memory amounts) 138 | { 139 | require(path.length >= 2, "UniswapV2Helper: INVALID_PATH"); 140 | amounts = new uint256[](path.length); 141 | amounts[amounts.length - 1] = amountOut; 142 | for (uint256 i = path.length - 1; i > 0; i--) { 143 | (uint256 reserveIn, uint256 reserveOut) = getReserves( 144 | path[i - 1], 145 | path[i] 146 | ); 147 | amounts[i - 1] = getAmountIn(amounts[i], reserveIn, reserveOut); 148 | } 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /migrations/3_deploy_contracts.js: -------------------------------------------------------------------------------- 1 | const UniswapV2Factory = artifacts.require("UniswapV2Factory"); 2 | const mDAI = artifacts.require("MDAI"); 3 | const mETH = artifacts.require("METH"); 4 | const m0x = artifacts.require("M0x"); 5 | const mBTC = artifacts.require("MBTC"); 6 | const MANA = artifacts.require("MANA"); 7 | const mUSDT = artifacts.require("MUSDT"); 8 | const UniswapV2Router01 = artifacts.require("UniswapV2Router01"); 9 | const EIP712Forwarder = artifacts.require("EIP712Forwarder"); 10 | // 11 | module.exports = function(deployer, network, accounts) { 12 | deployer.then(async () => { 13 | setter = accounts[0]; 14 | //get the deployed facotry 15 | let factoryContract = await UniswapV2Factory.deployed(); 16 | let EIP712ForwarderContract = await EIP712Forwarder.deployed(); 17 | async function getNetID() { 18 | return new Promise(function(resolve, reject) { 19 | web3.providers.HttpProvider.prototype.sendAsync = 20 | web3.providers.HttpProvider.prototype.send; 21 | 22 | web3.currentProvider.sendAsync( 23 | { 24 | jsonrpc: "2.0", 25 | method: "net_version", 26 | params: [], 27 | id: 0 28 | }, 29 | function(err, result) { 30 | if (err) { 31 | console.error(err.message); 32 | reject(err); 33 | } else { 34 | resolve(result.result); 35 | } 36 | } 37 | ); 38 | }); 39 | } 40 | function getAmountWithDecimals(_tokenAmount) { 41 | var decimals = web3.utils.toBN(18); 42 | var tokenAmount = web3.utils.toBN(_tokenAmount); 43 | var tokenAmountHex = tokenAmount.mul(web3.utils.toBN(10).pow(decimals)); 44 | 45 | return web3.utils.toHex(tokenAmountHex); 46 | } 47 | 48 | let chainId = await getNetID(); 49 | 50 | var initialSupply = getAmountWithDecimals(1000000); 51 | 52 | //deploy ERC20 contracts 53 | let mDAIContract = await deployer.deploy(mDAI, initialSupply, chainId); 54 | let mETHContract = await deployer.deploy(mETH, initialSupply, chainId); 55 | let m0XContract = await deployer.deploy(m0x, initialSupply, chainId); 56 | let MANAContract = await deployer.deploy(MANA, initialSupply, chainId); 57 | let mBTCContract = await deployer.deploy(mBTC, initialSupply, chainId); 58 | let mUSDTContract = await deployer.deploy(mUSDT, initialSupply, chainId); 59 | 60 | //deploy the router contracts 61 | let routerContract = await deployer.deploy( 62 | UniswapV2Router01, 63 | mETH.address, 64 | factoryContract.address, 65 | EIP712ForwarderContract.address 66 | // chainId 67 | ); 68 | 69 | var liquidityAmount = getAmountWithDecimals(10000); 70 | 71 | var erc20 = [ 72 | mDAIContract, 73 | mETHContract, 74 | m0XContract, 75 | MANAContract, 76 | mBTCContract, 77 | mUSDTContract 78 | ]; 79 | let latestBlock = await web3.eth.getBlock("latest"); 80 | let now = latestBlock.timestamp; 81 | console.log(now); 82 | 83 | let expiry = web3.utils.toHex(now + 3600); 84 | var addresses = { 85 | "mDAI": mDAIContract.address, 86 | "mETH": mETHContract.address, 87 | "m0x": m0XContract.address, 88 | "MANA": MANAContract.address, 89 | "mBTC":mBTC.address, 90 | "mUSDT":mUSDT.address, 91 | "factoryAddress": factoryContract.address, 92 | "routerAddress": routerContract.address, 93 | "EIP712forwarderAddress":EIP712ForwarderContract.address 94 | } 95 | console.log(addresses); 96 | for (i = 0; i < 6; i++) { 97 | for (j = i + 1; j < 6; j++) { 98 | await erc20[i].approve(routerContract.address, liquidityAmount); 99 | await erc20[j].approve(routerContract.address, liquidityAmount); 100 | await routerContract.addLiquidity( 101 | erc20[i].address, 102 | erc20[j].address, 103 | liquidityAmount, 104 | liquidityAmount, 105 | liquidityAmount, 106 | liquidityAmount, 107 | setter, 108 | expiry 109 | ); 110 | } 111 | } 112 | console.log("uidityDone"); 113 | 114 | console.log((await factoryContract.allPairsLength()).toString()); 115 | var swapAmount = getAmountWithDecimals(10); 116 | await MANAContract.approve(routerContract.address, swapAmount); 117 | var path = [MANAContract.address, mUSDTContract.address]; 118 | 119 | let amountOutMin = await routerContract.getAmountsOut(swapAmount, path); 120 | let a = await mUSDTContract.balanceOf(setter); 121 | console.log(a.toString()); 122 | await routerContract.swapExactTokensForTokens( 123 | swapAmount, 124 | web3.utils.toHex(amountOutMin[1]), 125 | path, 126 | setter, 127 | expiry 128 | ); 129 | a = await mUSDTContract.balanceOf(setter); 130 | console.log(a.toString()); 131 | addresses = { 132 | "mDAI": mDAIContract.address, 133 | "mETH": mETHContract.address, 134 | "m0x": m0XContract.address, 135 | "MANA": MANAContract.address, 136 | "mBTC":mBTC.address, 137 | "mUSDT":mUSDT.address, 138 | "factoryAddress": factoryContract.address, 139 | "routerAddress": routerContract.address, 140 | "EIP712forwarderAddress":EIP712ForwarderContract.address 141 | } 142 | let liquidityAmount1 = getAmountWithDecimals(100); 143 | let liquidityAmount2 = getAmountWithDecimals(200); 144 | await mUSDTContract.approve(routerContract.address, liquidityAmount1); 145 | await MANAContract.approve(routerContract.address, liquidityAmount2); 146 | let reserves = await routerContract.getReserves(mUSDTContract.address,MANAContract.address); 147 | console.log(reserves); 148 | let amountAmin = await routerContract.quote(liquidityAmount2,reserves[0],reserves[1]); 149 | let amountBmin = await routerContract.quote(liquidityAmount1,reserves[1],reserves[0]); 150 | console.log(amountAmin); 151 | 152 | routerContract.addLiquidity(mUSDTContract.address,MANAContract.address,liquidityAmount1,liquidityAmount2,amountAmin,amountBmin,setter,expiry); 153 | }); 154 | }; 155 | -------------------------------------------------------------------------------- /src/style.css: -------------------------------------------------------------------------------- 1 | 2 | .center { 3 | margin: auto; 4 | width: 60%; 5 | padding: 10px; 6 | border-style: double; 7 | } 8 | .center1 { 9 | margin: auto; 10 | width: 60%; 11 | padding: 10px; 12 | 13 | } 14 | 15 | input { 16 | padding: 9px; 17 | border: solid 1px #E5E5E5; 18 | outline: 0; 19 | font: normal 13px/100% Verdana, Tahoma, sans-serif; 20 | width: 175px; 21 | background: #FFFFFF url('bg_form.png') left top repeat-x; 22 | background: -webkit-gradient(linear, left top, left 25, from(#FFFFFF), color-stop(4%, #EEEEEE), to(#FFFFFF)); 23 | background: -moz-linear-gradient(top, #FFFFFF, #EEEEEE 1px, #FFFFFF 25px); 24 | box-shadow: rgba(0,0,0, 0.1) 0px 0px 8px; 25 | -moz-box-shadow: rgba(0,0,0, 0.1) 0px 0px 8px; 26 | -webkit-box-shadow: rgba(0,0,0, 0.1) 0px 0px 8px; 27 | } 28 | 29 | input:hover, textarea:hover, 30 | input:focus, textarea:focus { 31 | border-color: #C9C9C9; 32 | -webkit-box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 8px; 33 | } 34 | 35 | .form label { 36 | margin-left: 10px; 37 | color: #999999; 38 | } 39 | 40 | 41 | /* Normal white Button as seen on Google.com*/ 42 | button { 43 | color: #444444; 44 | background: #F3F3F3; 45 | border: 1px #DADADA solid; 46 | padding: 5px 10px; 47 | border-radius: 2px; 48 | font-weight: bold; 49 | font-size: 14pt; 50 | outline: none; 51 | } 52 | 53 | button:hover { 54 | border: 1px #C6C6C6 solid; 55 | box-shadow: 1px 1px 1px #EAEAEA; 56 | color: #333333; 57 | background: #F7F7F7; 58 | } 59 | 60 | button:active { 61 | box-shadow: inset 1px 1px 1px #DFDFDF; 62 | } 63 | 64 | 65 | .heading { 66 | position: relative; 67 | margin: 0 0 30px; 68 | padding-bottom: 30px; 69 | text-align: center; 70 | font-size: 30px; 71 | letter-spacing: 0.06em; 72 | } 73 | 74 | .heading:before { 75 | content: ""; 76 | display: block; 77 | position: absolute; 78 | left: 50%; 79 | transform:translateX(-50%); 80 | bottom: 0; 81 | width: 50px; 82 | height: 6px; 83 | border-left: 50px solid #f12735; 84 | background-color: #1598e3; 85 | } 86 | .heading:after { 87 | content: ""; 88 | display: block; 89 | position: absolute; 90 | right: 50%; 91 | bottom: 0; 92 | border-right: 3px solid #1598e3; 93 | border-bottom: 3px solid #1598e3; 94 | border-top: 3px solid transparent; 95 | border-left: 3px solid transparent; 96 | } 97 | /* UNIMPORTANT SETUP STYLES */ 98 | body { 99 | margin: 0; 100 | font-family: 'Montserrat', sans-serif; 101 | font-size: 18px; 102 | line-height: 32px; 103 | color: #101010; 104 | background: linear-gradient(to bottom, #ffffff, #dddddd); 105 | } 106 | 107 | .content { 108 | margin: 0 auto; 109 | padding: 30px; 110 | max-width: 760px; 111 | } 112 | 113 | p { 114 | margin: 0 0 20px; 115 | } 116 | 117 | 118 | /* HEADING STYLES */ 119 | h1 { 120 | position: relative; /* This is important */ 121 | margin: 1.5em 0 .9em; 122 | font-size: 28px; 123 | line-height: 1.2; 124 | font-weight: bold; 125 | text-align: center; 126 | overflow: hidden; /* This is important */ 127 | } 128 | 129 | /* Create two pseudo-elements */ 130 | h1:before, h1:after { 131 | position: absolute; 132 | top: 50%; 133 | content: ''; 134 | width: 50%; 135 | height: 2px; 136 | display: inline-block; 137 | background: #303030; 138 | } 139 | 140 | /* Adjust the "14px" value to change the text's left padding */ 141 | h1:before { 142 | margin-left: calc(-50% - 14px); 143 | } 144 | 145 | /* Adjust the "14px" value to change the text's right padding */ 146 | h1:after { 147 | margin-left: 14px; 148 | } 149 | 150 | /*[ Button ]*/ 151 | .container-login100-form-btn { 152 | width: 100%; 153 | display: -webkit-box; 154 | display: -webkit-flex; 155 | display: -moz-box; 156 | display: -ms-flexbox; 157 | display: flex; 158 | flex-wrap: wrap; 159 | justify-content: center; 160 | margin: auto; 161 | padding: 10px; 162 | width: 60%; 163 | } 164 | 165 | .login100-form-btn { 166 | font-family: Ubuntu-Bold; 167 | font-size: 18px; 168 | color: #fff; 169 | line-height: 1.2; 170 | text-transform: uppercase; 171 | 172 | display: -webkit-box; 173 | display: -webkit-flex; 174 | display: -moz-box; 175 | display: -ms-flexbox; 176 | display: flex; 177 | justify-content: center; 178 | align-items: center; 179 | padding: 0 20px; 180 | min-width: 160px; 181 | height: 42px; 182 | border-radius: 21px; 183 | 184 | background: #d41872; 185 | background: -webkit-linear-gradient(left, #a445b2, #d41872, #fa4299); 186 | background: -o-linear-gradient(left, #a445b2, #d41872, #fa4299); 187 | background: -moz-linear-gradient(left, #a445b2, #d41872, #fa4299); 188 | background: linear-gradient(left, #a445b2, #d41872, #fa4299); 189 | position: relative; 190 | z-index: 1; 191 | 192 | -webkit-transition: all 0.4s; 193 | -o-transition: all 0.4s; 194 | -moz-transition: all 0.4s; 195 | transition: all 0.4s; 196 | } 197 | 198 | .login100-form-btn::before { 199 | content: ""; 200 | display: block; 201 | position: absolute; 202 | z-index: -1; 203 | width: 100%; 204 | height: 100%; 205 | border-radius: 21px; 206 | background-color: #555555; 207 | top: 0; 208 | left: 0; 209 | opacity: 0; 210 | 211 | -webkit-transition: all 0.4s; 212 | -o-transition: all 0.4s; 213 | -moz-transition: all 0.4s; 214 | transition: all 0.4s; 215 | } 216 | 217 | .login100-form-btn:hover { 218 | background-color: transparent; 219 | } 220 | 221 | .login100-form-btn:hover:before { 222 | opacity: 1; 223 | } 224 | select { 225 | -webkit-appearance: button; 226 | -moz-appearance: button; 227 | -webkit-user-select: none; 228 | -moz-user-select: none; 229 | -webkit-padding-end: 20px; 230 | -moz-padding-end: 20px; 231 | -webkit-padding-start: 2px; 232 | -moz-padding-start: 2px; 233 | background-color:#dddddd; /* Fallback color if gradients are not supported */ 234 | background-image: url(../images/select-arrow.png), -webkit-linear-gradient(top, #E5E5E5, #F4F4F4); /* For Chrome and Safari */ 235 | background-image: url(../images/select-arrow.png), -moz-linear-gradient(top, #E5E5E5, #F4F4F4); /* For old Firefox (3.6 to 15) */ 236 | background-image: url(../images/select-arrow.png), -ms-linear-gradient(top, #E5E5E5, #F4F4F4); /* For pre-releases of Internet Explorer 10*/ 237 | background-image: url(../images/select-arrow.png), -o-linear-gradient(top, #E5E5E5, #F4F4F4); /* For old Opera (11.1 to 12.0) */ 238 | background-image: url(../images/select-arrow.png), linear-gradient(to bottom, #E5E5E5, #F4F4F4); /* Standard syntax; must be last */ 239 | background-position: center right; 240 | background-repeat: no-repeat; 241 | border: 1px solid #AAA; 242 | border-radius: 2px; 243 | box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.1); 244 | color: #555; 245 | font-size: inherit; 246 | margin: 0; 247 | overflow: hidden; 248 | padding-top: 2px; 249 | padding-bottom: 2px; 250 | text-overflow: ellipsis; 251 | white-space: nowrap; 252 | } 253 | .loader { 254 | border: 16px solid #f3f3f3; 255 | border-radius: 50%; 256 | border-top: 16px solid blue; 257 | border-right: 16px solid green; 258 | border-bottom: 16px solid red; 259 | border-left: 16px solid pink; 260 | width: 10px; 261 | height: 10px; 262 | -webkit-animation: spin 2s linear infinite; 263 | animation: spin 2s linear infinite; 264 | display: none; 265 | } 266 | 267 | @-webkit-keyframes spin { 268 | 0% { -webkit-transform: rotate(0deg); } 269 | 100% { -webkit-transform: rotate(360deg); } 270 | } 271 | 272 | @keyframes spin { 273 | 0% { transform: rotate(0deg); } 274 | 100% { transform: rotate(360deg); } 275 | } -------------------------------------------------------------------------------- /contracts/UniswapV2Pair.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 2 | 3 | import './interfaces/IUniswapV2Pair.sol'; 4 | import './UniswapV2ERC20.sol'; 5 | import './libraries/Math.sol'; 6 | import './libraries/UQ112x112.sol'; 7 | import './interfaces/IERC20.sol'; 8 | import './interfaces/IUniswapV2Factory.sol'; 9 | import './interfaces/IUniswapV2Callee.sol'; 10 | 11 | contract UniswapV2Pair is IUniswapV2Pair, UniswapV2ERC20 { 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, 'UniswapV2: 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))), 'UniswapV2: 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, 'UniswapV2: 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), 'UniswapV2: 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 = IUniswapV2Factory(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(5).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, 'UniswapV2: 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, 'UniswapV2: 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, 'UniswapV2: INSUFFICIENT_OUTPUT_AMOUNT'); 161 | (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings 162 | require(amount0Out < _reserve0 && amount1Out < _reserve1, 'UniswapV2: 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, 'UniswapV2: 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) IUniswapV2Callee(to).uniswapV2Call(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, 'UniswapV2: INSUFFICIENT_INPUT_AMOUNT'); 179 | { // scope for reserve{0,1}Adjusted, avoids stack too deep errors 180 | uint balance0Adjusted = balance0.mul(1000).sub(amount0In.mul(3)); 181 | uint balance1Adjusted = balance1.mul(1000).sub(amount1In.mul(3)); 182 | require(balance0Adjusted.mul(balance1Adjusted) >= uint(_reserve0).mul(_reserve1).mul(1000**2), 'UniswapV2: 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 | -------------------------------------------------------------------------------- /contracts/EIP2585Forwader.sol: -------------------------------------------------------------------------------- 1 | /* EIP-2585 Minimal Native Meta Transaction Forwarder 2 | * This standard defines a universal native meta transaction smart contract 3 | * that accept specially crafted Externally Owned Accounts (EOA) signed message 4 | * to forward to receiver contract via third parties. 5 | * 6 | * Written in 2020 by Ronan Sandford 7 | * 8 | * To the extent possible under law, the author(s) have dedicated all copyright 9 | * and related and neighboring rights to this software to the public domain 10 | * worldwide. This software is distributed without any warranty. 11 | * 12 | * You should have received a copy of the CC0 Public Domain Dedication along 13 | * with this software. If not, see 14 | * . 15 | * 16 | * .-''-. .-./`) .-------. .`````-. ,--------. .-''''-. ,--------. 17 | * .'_ _ \ \ .-.')\ _(`)_ \ / ,-. \ | _____| / _--. \ | _____| 18 | * / ( ` ) '/ `-' \| (_ o._)| (___/ | || ) |_( )_ ' | | ) 19 | * . (_ o _) | `-'`"`| (_,_) /_ _ _ _ .' / | '----. (_ o _). / | '----. 20 | * | (_,_)___| .---. | '-.-'( ' )--( ' ) _.-'_.-' |_.._ _ '. .'(_,_). `.|_.._ _ '. 21 | * ' \ .---. | | | | (_{;}_)(_{;}_)_/_ .' ( ' ) \|_( )_ \ | ( ' ) \ 22 | * \ `-' / | | | | (_,_)--(_,_)( ' )(__..--. _(_{;}_) |(_ o _) / |_(_{;}_) | 23 | * \ / | | / ) (_{;}_) || (_,_) / (_,_)..-' .'| (_,_) / 24 | * `'-..-' '---' `---' (_,_)-------' `...__..' `-....-' `...__..' 25 | * 26 | */ 27 | pragma solidity =0.5.16; 28 | pragma experimental ABIEncoderV2; 29 | 30 | 31 | interface ERC1271 { 32 | function isValidSignature(bytes calldata data, bytes calldata signature) 33 | external 34 | view 35 | returns (bytes4 magicValue); 36 | } 37 | 38 | 39 | interface ERC1654 { 40 | function isValidSignature(bytes32 hash, bytes calldata signature) 41 | external 42 | view 43 | returns (bytes4 magicValue); 44 | } 45 | 46 | 47 | interface ReplayProtection { 48 | function checkAndUpdateNonce(address signer, bytes calldata nonce) 49 | external 50 | returns (bool); 51 | } 52 | 53 | 54 | interface Forwarder { 55 | enum SignatureType {DIRECT, EIP1654, EIP1271} 56 | 57 | struct Message { 58 | address from; 59 | address to; 60 | uint256 chainId; 61 | address replayProtection; 62 | bytes nonce; 63 | bytes data; 64 | bytes32 innerMessageHash; 65 | } 66 | 67 | function forward( 68 | Message calldata message, 69 | SignatureType signatureType, 70 | bytes calldata signature 71 | ) external payable; 72 | } 73 | 74 | 75 | library SigUtil { 76 | function recover(bytes32 hash, bytes memory sig) 77 | internal 78 | pure 79 | returns (address recovered) 80 | { 81 | require(sig.length == 65, "SIGNATURE_INVALID_LENGTH"); 82 | 83 | bytes32 r; 84 | bytes32 s; 85 | uint8 v; 86 | assembly { 87 | r := mload(add(sig, 32)) 88 | s := mload(add(sig, 64)) 89 | v := byte(0, mload(add(sig, 96))) 90 | } 91 | 92 | // Version of signature should be 27 or 28, but 0 and 1 are also possible versions 93 | if (v < 27) { 94 | v += 27; 95 | } 96 | require(v == 27 || v == 28, "SIGNATURE_INVALID_V"); 97 | 98 | recovered = ecrecover(hash, v, r, s); 99 | require(recovered != address(0), "SIGNATURE_ZERO_ADDRESS"); 100 | } 101 | 102 | function eth_sign_prefix(bytes32 hash) 103 | internal 104 | pure 105 | returns (bytes memory) 106 | { 107 | return abi.encodePacked("\x19Ethereum Signed Message:\n32", hash); 108 | } 109 | } 110 | 111 | 112 | /// @notice Forwarder for Meta Transactions Using EIP712 Signing Standard, also implement default Replay Protection using 2 dimensional nonces 113 | contract EIP712Forwarder is Forwarder, ReplayProtection { 114 | // ///////////////////////////// FORWARDING EOA META TRANSACTION /////////////////////////////////// 115 | 116 | bytes4 internal constant ERC1271_MAGICVALUE = 0x20c13b0b; 117 | bytes4 internal constant ERC1654_MAGICVALUE = 0x1626ba7e; 118 | uint256 public chainId; 119 | 120 | constructor(uint256 _chainId) public { 121 | chainId = _chainId; 122 | } 123 | 124 | /// @notice forward call from EOA signed message 125 | /// @param message.from address from which the message come from (For EOA this is the same as signer) 126 | /// @param message.to target of the call 127 | /// @param message.replayProtection contract address that check and update nonce 128 | /// @param message.nonce nonce value 129 | /// @param message.data call data 130 | /// @param message.innerMessageHash extra data hashed that can be used as embedded message for implementing more complex scenario, with one sig 131 | /// @param signatureType signatureType either EOA, EIP1271 or EIP1654 132 | /// @param signature signature 133 | function forward( 134 | Message memory message, 135 | SignatureType signatureType, 136 | bytes memory signature 137 | ) public payable { 138 | // external with ABIEncoderV2 Struct is not supported in solidity < 0.6.4 139 | require(_isValidChainId(message.chainId), "INVALID_CHAIN_ID"); 140 | _checkSigner(message, signatureType, signature); 141 | // optimization to avoid call if using default nonce strategy 142 | // this contract implements a default nonce strategy and can be called directly 143 | if ( 144 | message.replayProtection == address(0) || 145 | message.replayProtection == address(this) 146 | ) { 147 | require( 148 | checkAndUpdateNonce(message.from, message.nonce), 149 | "NONCE_INVALID" 150 | ); 151 | } else { 152 | require( 153 | ReplayProtection(message.replayProtection).checkAndUpdateNonce( 154 | message.from, 155 | message.nonce 156 | ), 157 | "NONCE_INVALID" 158 | ); 159 | } 160 | 161 | _call(message.from, message.to, msg.value, message.data); 162 | } 163 | 164 | // /////////////////////////////////// BATCH CALL ///////////////////////////////////// 165 | 166 | struct Call { 167 | address to; 168 | bytes data; 169 | uint256 value; 170 | } 171 | 172 | /// @notice batcher function that can be called as part of a meta transaction (allowing to batch call atomically) 173 | /// @param calls list of call data and destination 174 | function batch(Call[] memory calls) public payable { 175 | // external with ABIEncoderV2 Struct is not supported in solidity < 0.6.4 176 | require(msg.sender == address(this), "FORWARDER_ONLY"); 177 | address signer; 178 | bytes memory data = msg.data; 179 | uint256 length = msg.data.length; 180 | assembly { 181 | signer := and( 182 | mload(sub(add(data, length), 0x00)), 183 | 0xffffffffffffffffffffffffffffffffffffffff 184 | ) 185 | } 186 | for (uint256 i = 0; i < calls.length; i++) { 187 | _call(signer, calls[i].to, calls[i].value, calls[i].data); 188 | } 189 | } 190 | 191 | // /////////////////////////////////// REPLAY PROTECTION ///////////////////////////////////// 192 | 193 | mapping(address => mapping(uint128 => uint128)) _batches; 194 | 195 | /// @notice implement a default nonce stategy 196 | /// @param signer address to check and update nonce for 197 | /// @param nonce value of nonce sent as part of the forward call 198 | function checkAndUpdateNonce(address signer, bytes memory nonce) 199 | public 200 | returns (bool) 201 | { 202 | // TODO? default nonce strategy could be different (maybe the most versatile : batchId + Nonce) 203 | uint256 value = abi.decode(nonce, (uint256)); 204 | uint128 batchId = uint128(value / 2**128); 205 | uint128 batchNonce = uint128(value % 2**128); 206 | 207 | uint128 currentNonce = _batches[signer][batchId]; 208 | if (batchNonce == currentNonce) { 209 | _batches[signer][batchId] = currentNonce + 1; 210 | return true; 211 | } 212 | return false; 213 | } 214 | 215 | function getNonce(address signer, uint128 batchId) 216 | external 217 | view 218 | returns (uint128) 219 | { 220 | return _batches[signer][batchId]; 221 | } 222 | 223 | // ///////////////////////////////// INTERNAL //////////////////////////////////////////// 224 | 225 | function _call(address from, address to, uint256 value, bytes memory data) 226 | internal 227 | { 228 | (bool success, ) = to.call.value(value)(abi.encodePacked(data, from)); 229 | if (!success) { 230 | assembly { 231 | let returnDataSize := returndatasize() 232 | returndatacopy(0, 0, returnDataSize) 233 | revert(0, returnDataSize) 234 | } 235 | } 236 | } 237 | 238 | function _checkSigner( 239 | Message memory message, 240 | SignatureType signatureType, 241 | bytes memory signature 242 | ) internal view returns (address) { 243 | bytes memory dataToHash = _encodeMessage(message); 244 | if (signatureType == SignatureType.EIP1271) { 245 | require( 246 | ERC1271(message.from).isValidSignature(dataToHash, signature) == 247 | ERC1271_MAGICVALUE, 248 | "SIGNATURE_1271_INVALID" 249 | ); 250 | } else if (signatureType == SignatureType.EIP1654) { 251 | require( 252 | ERC1654(message.from).isValidSignature( 253 | keccak256(dataToHash), 254 | signature 255 | ) == ERC1654_MAGICVALUE, 256 | "SIGNATURE_1654_INVALID" 257 | ); 258 | } else { 259 | address signer = SigUtil.recover(keccak256(dataToHash), signature); 260 | require(signer == message.from, "SIGNATURE_WRONG_SIGNER"); 261 | } 262 | } 263 | 264 | //matic does not support the opcode 0x46? 265 | function _isValidChainId(uint256 _chainId) internal view returns (bool) { 266 | // uint256 _chainId; 267 | // assembly { 268 | // _chainId := chainid() 269 | // } 270 | return chainId == _chainId; 271 | } 272 | 273 | bytes32 constant EIP712DOMAIN_TYPEHASH = keccak256( 274 | "EIP712Domain(string name,string version)" 275 | ); 276 | bytes32 constant DOMAIN_SEPARATOR = keccak256( 277 | abi.encode( 278 | EIP712DOMAIN_TYPEHASH, 279 | keccak256("Forwarder"), 280 | keccak256("1") 281 | ) 282 | ); 283 | 284 | bytes32 constant METATRANSACTION_TYPEHASH = keccak256( 285 | "MetaTransaction(address from,address to,uint256 value,uint256 chainId,address replayProtection,bytes nonce,bytes data,bytes32 innerMessageHash)" 286 | ); 287 | 288 | function _encodeMessage(Message memory message) 289 | internal 290 | view 291 | returns (bytes memory) 292 | { 293 | return 294 | abi.encodePacked( 295 | "\x19\x01", 296 | DOMAIN_SEPARATOR, 297 | keccak256( 298 | abi.encode( 299 | METATRANSACTION_TYPEHASH, 300 | message.from, 301 | message.to, 302 | msg.value, 303 | message.chainId, 304 | message.replayProtection, 305 | keccak256(message.nonce), 306 | keccak256(message.data), 307 | message.innerMessageHash 308 | ) 309 | ) 310 | ); 311 | } 312 | } 313 | -------------------------------------------------------------------------------- /contracts/UniswapV2Router01.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 2 | 3 | import "./interfaces/IUniswapV2Router01.sol"; 4 | import "./UniswapV2Library.sol"; 5 | import "./interfaces/IWETH.sol"; 6 | import "./ForwarderReceiverBase.sol"; 7 | 8 | 9 | contract UniswapV2Router01 is 10 | IUniswapV2Router01, 11 | UniswapV2Library, 12 | ForwarderReceiverBase 13 | { 14 | bytes4 private constant SELECTOR_TRANSFER = bytes4( 15 | keccak256(bytes("transfer(address,uint256)")) 16 | ); 17 | bytes4 private constant SELECTOR_TRANSFER_FROM = bytes4( 18 | keccak256(bytes("transferFrom(address,address,uint256)")) 19 | ); 20 | 21 | IWETH public WETH; 22 | 23 | // **** TRANSFER HELPERS **** 24 | function _safeTransfer(address token, address to, uint256 value) private { 25 | (bool success, bytes memory data) = token.call( 26 | abi.encodeWithSelector(SELECTOR_TRANSFER, to, value) 27 | ); 28 | require( 29 | success && (data.length == 0 || abi.decode(data, (bool))), 30 | "UniswapV2Router: TRANSFER_FAILED" 31 | ); 32 | } 33 | 34 | function _safeTransferFrom( 35 | address token, 36 | address from, 37 | address to, 38 | uint256 value 39 | ) private { 40 | (bool success, bytes memory data) = token.call( 41 | abi.encodeWithSelector(SELECTOR_TRANSFER_FROM, from, to, value) 42 | ); 43 | require( 44 | success && (data.length == 0 || abi.decode(data, (bool))), 45 | "UniswapV2Router: TRANSFER_FROM_FAILED" 46 | ); 47 | } 48 | 49 | function _safeTransferETH(address to, uint256 value) private { 50 | (bool success, ) = to.call.value(value)(new bytes(0)); 51 | require(success, "UniswapV2Router: ETH_TRANSFER_FAILED"); 52 | } 53 | 54 | modifier ensure(uint256 deadline) { 55 | require(deadline >= block.timestamp, "UniswapV2Router: EXPIRED"); 56 | _; 57 | } 58 | 59 | constructor(address _WETH, address _factory, address _forwarder) 60 | public 61 | ForwarderReceiverBase(_forwarder) 62 | { 63 | factory = IUniswapV2Factory(_factory); 64 | WETH = IWETH(_WETH); 65 | } 66 | 67 | function() external payable { 68 | assert(_getTxSigner() == address(WETH)); // only accept ETH via fallback from the WETH contract 69 | } 70 | 71 | // **** ADD LIQUIDITY **** 72 | function _addLiquidity( 73 | address tokenA, 74 | address tokenB, 75 | uint256 amountADesired, 76 | uint256 amountBDesired, 77 | uint256 amountAMin, 78 | uint256 amountBMin 79 | ) private returns (uint256 amountA, uint256 amountB) { 80 | // create the pair if it doesn't exist yet 81 | if (factory.getPair(tokenA, tokenB) == address(0)) { 82 | factory.createPair(tokenA, tokenB); 83 | } 84 | (uint256 reserveA, uint256 reserveB) = getReserves(tokenA, tokenB); 85 | if (reserveA == 0 && reserveB == 0) { 86 | (amountA, amountB) = (amountADesired, amountBDesired); 87 | } else { 88 | uint256 amountBOptimal = quote(amountADesired, reserveA, reserveB); 89 | if (amountBOptimal <= amountBDesired) { 90 | require( 91 | amountBOptimal >= amountBMin, 92 | "UniswapV2Router: INSUFFICIENT_B_AMOUNT" 93 | ); 94 | (amountA, amountB) = (amountADesired, amountBOptimal); 95 | } else { 96 | uint256 amountAOptimal = quote( 97 | amountBDesired, 98 | reserveB, 99 | reserveA 100 | ); 101 | assert(amountAOptimal <= amountADesired); 102 | require( 103 | amountAOptimal >= amountAMin, 104 | "UniswapV2Router: INSUFFICIENT_A_AMOUNT" 105 | ); 106 | (amountA, amountB) = (amountAOptimal, amountBDesired); 107 | } 108 | } 109 | } 110 | 111 | function addLiquidity( 112 | address tokenA, 113 | address tokenB, 114 | uint256 amountADesired, 115 | uint256 amountBDesired, 116 | uint256 amountAMin, 117 | uint256 amountBMin, 118 | address to, 119 | uint256 deadline 120 | ) 121 | external 122 | ensure(deadline) 123 | returns (uint256 amountA, uint256 amountB, uint256 liquidity) 124 | { 125 | (amountA, amountB) = _addLiquidity( 126 | tokenA, 127 | tokenB, 128 | amountADesired, 129 | amountBDesired, 130 | amountAMin, 131 | amountBMin 132 | ); 133 | address pair = pairFor(tokenA, tokenB); 134 | _safeTransferFrom(tokenA, _getTxSigner(), pair, amountA); 135 | _safeTransferFrom(tokenB, _getTxSigner(), pair, amountB); 136 | liquidity = IUniswapV2Pair(pair).mint(to); 137 | } 138 | 139 | function addLiquidityETH( 140 | address token, 141 | uint256 amountTokenDesired, 142 | uint256 amountTokenMin, 143 | uint256 amountETHMin, 144 | address to, 145 | uint256 deadline 146 | ) 147 | external 148 | payable 149 | ensure(deadline) 150 | returns (uint256 amountToken, uint256 amountETH, uint256 liquidity) 151 | { 152 | (amountToken, amountETH) = _addLiquidity( 153 | token, 154 | address(WETH), 155 | amountTokenDesired, 156 | msg.value, 157 | amountTokenMin, 158 | amountETHMin 159 | ); 160 | address pair = pairFor(token, address(WETH)); 161 | _safeTransferFrom(token, _getTxSigner(), pair, amountToken); 162 | WETH.deposit.value(amountETH)(); 163 | assert(WETH.transfer(pair, amountETH)); 164 | liquidity = IUniswapV2Pair(pair).mint(to); 165 | if (msg.value > amountETH) 166 | _safeTransferETH(_getTxSigner(), msg.value - amountETH); // refund dust eth, if any 167 | } 168 | 169 | // **** REMOVE LIQUIDITY **** 170 | function removeLiquidity( 171 | address tokenA, 172 | address tokenB, 173 | uint256 liquidity, 174 | uint256 amountAMin, 175 | uint256 amountBMin, 176 | address to, 177 | uint256 deadline 178 | ) public ensure(deadline) returns (uint256 amountA, uint256 amountB) { 179 | address pair = pairFor(tokenA, tokenB); 180 | IUniswapV2Pair(pair).transferFrom(_getTxSigner(), pair, liquidity); // send liquidity to pair 181 | (uint256 amount0, uint256 amount1) = IUniswapV2Pair(pair).burn(to); 182 | (address token0, ) = sortTokens(tokenA, tokenB); 183 | (amountA, amountB) = tokenA == token0 184 | ? (amount0, amount1) 185 | : (amount1, amount0); 186 | require( 187 | amountA >= amountAMin, 188 | "UniswapV2Router: INSUFFICIENT_A_AMOUNT" 189 | ); 190 | require( 191 | amountB >= amountBMin, 192 | "UniswapV2Router: INSUFFICIENT_B_AMOUNT" 193 | ); 194 | } 195 | 196 | function removeLiquidityETH( 197 | address token, 198 | uint256 liquidity, 199 | uint256 amountTokenMin, 200 | uint256 amountETHMin, 201 | address to, 202 | uint256 deadline 203 | ) public ensure(deadline) returns (uint256 amountToken, uint256 amountETH) { 204 | (amountToken, amountETH) = removeLiquidity( 205 | token, 206 | address(WETH), 207 | liquidity, 208 | amountTokenMin, 209 | amountETHMin, 210 | address(this), 211 | deadline 212 | ); 213 | _safeTransfer(token, to, amountToken); 214 | WETH.withdraw(amountETH); 215 | _safeTransferETH(to, amountETH); 216 | } 217 | 218 | function removeLiquidityWithPermit( 219 | address tokenA, 220 | address tokenB, 221 | uint256 liquidity, 222 | uint256 amountAMin, 223 | uint256 amountBMin, 224 | address to, 225 | uint256 deadline, 226 | bool approveMax, 227 | uint8 v, 228 | bytes32 r, 229 | bytes32 s 230 | ) external returns (uint256 amountA, uint256 amountB) { 231 | address pair = pairFor(tokenA, tokenB); 232 | uint256 value = approveMax ? uint256(-1) : liquidity; 233 | IUniswapV2Pair(pair).permit( 234 | _getTxSigner(), 235 | address(this), 236 | value, 237 | deadline, 238 | v, 239 | r, 240 | s 241 | ); 242 | (amountA, amountB) = removeLiquidity( 243 | tokenA, 244 | tokenB, 245 | liquidity, 246 | amountAMin, 247 | amountBMin, 248 | to, 249 | deadline 250 | ); 251 | } 252 | 253 | function removeLiquidityETHWithPermit( 254 | address token, 255 | uint256 liquidity, 256 | uint256 amountTokenMin, 257 | uint256 amountETHMin, 258 | address to, 259 | uint256 deadline, 260 | bool approveMax, 261 | uint8 v, 262 | bytes32 r, 263 | bytes32 s 264 | ) external returns (uint256 amountToken, uint256 amountETH) { 265 | address pair = pairFor(token, address(WETH)); 266 | uint256 value = approveMax ? uint256(-1) : liquidity; 267 | IUniswapV2Pair(pair).permit( 268 | _getTxSigner(), 269 | address(this), 270 | value, 271 | deadline, 272 | v, 273 | r, 274 | s 275 | ); 276 | (amountToken, amountETH) = removeLiquidityETH( 277 | token, 278 | liquidity, 279 | amountTokenMin, 280 | amountETHMin, 281 | to, 282 | deadline 283 | ); 284 | } 285 | 286 | // **** SWAP **** 287 | // requires the initial amount to have already been sent to the first pair 288 | function _swap(uint256[] memory amounts, address[] memory path, address _to) 289 | private 290 | { 291 | for (uint256 i; i < path.length - 1; i++) { 292 | (address input, address output) = (path[i], path[i + 1]); 293 | (address token0, ) = sortTokens(input, output); 294 | uint256 amountOut = amounts[i + 1]; 295 | (uint256 amount0Out, uint256 amount1Out) = input == token0 296 | ? (uint256(0), amountOut) 297 | : (amountOut, uint256(0)); 298 | address to = i < path.length - 2 299 | ? pairFor(output, path[i + 2]) 300 | : _to; 301 | IUniswapV2Pair(pairFor(input, output)).swap( 302 | amount0Out, 303 | amount1Out, 304 | to, 305 | new bytes(0) 306 | ); 307 | } 308 | } 309 | 310 | function swapExactTokensForTokens( 311 | uint256 amountIn, 312 | uint256 amountOutMin, 313 | address[] calldata path, 314 | address to, 315 | uint256 deadline 316 | ) external ensure(deadline) returns (uint256[] memory amounts) { 317 | amounts = getAmountsOut(amountIn, path); 318 | require( 319 | amounts[amounts.length - 1] >= amountOutMin, 320 | "UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT" 321 | ); 322 | _safeTransferFrom( 323 | path[0], 324 | _getTxSigner(), 325 | pairFor(path[0], path[1]), 326 | amounts[0] 327 | ); 328 | _swap(amounts, path, to); 329 | } 330 | 331 | function swapTokensForExactTokens( 332 | uint256 amountOut, 333 | uint256 amountInMax, 334 | address[] calldata path, 335 | address to, 336 | uint256 deadline 337 | ) external ensure(deadline) returns (uint256[] memory amounts) { 338 | amounts = getAmountsIn(amountOut, path); 339 | require( 340 | amounts[0] <= amountInMax, 341 | "UniswapV2Router: EXCESSIVE_INPUT_AMOUNT" 342 | ); 343 | _safeTransferFrom( 344 | path[0], 345 | _getTxSigner(), 346 | pairFor(path[0], path[1]), 347 | amounts[0] 348 | ); 349 | _swap(amounts, path, to); 350 | } 351 | 352 | function swapExactETHForTokens( 353 | uint256 amountOutMin, 354 | address[] calldata path, 355 | address to, 356 | uint256 deadline 357 | ) external payable ensure(deadline) returns (uint256[] memory amounts) { 358 | require(path[0] == address(WETH), "UniswapV2Router: INVALID_PATH"); 359 | amounts = getAmountsOut(msg.value, path); 360 | require( 361 | amounts[amounts.length - 1] >= amountOutMin, 362 | "UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT" 363 | ); 364 | WETH.deposit.value(amounts[0])(); 365 | assert(WETH.transfer(pairFor(path[0], path[1]), amounts[0])); 366 | _swap(amounts, path, to); 367 | } 368 | 369 | function swapTokensForExactETH( 370 | uint256 amountOut, 371 | uint256 amountInMax, 372 | address[] calldata path, 373 | address to, 374 | uint256 deadline 375 | ) external ensure(deadline) returns (uint256[] memory amounts) { 376 | require( 377 | path[path.length - 1] == address(WETH), 378 | "UniswapV2Router: INVALID_PATH" 379 | ); 380 | amounts = getAmountsIn(amountOut, path); 381 | require( 382 | amounts[0] <= amountInMax, 383 | "UniswapV2Router: EXCESSIVE_INPUT_AMOUNT" 384 | ); 385 | _safeTransferFrom( 386 | path[0], 387 | _getTxSigner(), 388 | pairFor(path[0], path[1]), 389 | amounts[0] 390 | ); 391 | _swap(amounts, path, address(this)); 392 | WETH.withdraw(amounts[amounts.length - 1]); 393 | _safeTransferETH(to, amounts[amounts.length - 1]); 394 | } 395 | 396 | function swapExactTokensForETH( 397 | uint256 amountIn, 398 | uint256 amountOutMin, 399 | address[] calldata path, 400 | address to, 401 | uint256 deadline 402 | ) external ensure(deadline) returns (uint256[] memory amounts) { 403 | require( 404 | path[path.length - 1] == address(WETH), 405 | "UniswapV2Router: INVALID_PATH" 406 | ); 407 | amounts = getAmountsOut(amountIn, path); 408 | require( 409 | amounts[amounts.length - 1] >= amountOutMin, 410 | "UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT" 411 | ); 412 | _safeTransferFrom( 413 | path[0], 414 | _getTxSigner(), 415 | pairFor(path[0], path[1]), 416 | amounts[0] 417 | ); 418 | _swap(amounts, path, address(this)); 419 | WETH.withdraw(amounts[amounts.length - 1]); 420 | _safeTransferETH(to, amounts[amounts.length - 1]); 421 | } 422 | 423 | function swapETHForExactTokens( 424 | uint256 amountOut, 425 | address[] calldata path, 426 | address to, 427 | uint256 deadline 428 | ) external payable ensure(deadline) returns (uint256[] memory amounts) { 429 | require(path[0] == address(WETH), "UniswapV2Router: INVALID_PATH"); 430 | amounts = getAmountsIn(amountOut, path); 431 | require( 432 | amounts[0] <= msg.value, 433 | "UniswapV2Router: EXCESSIVE_INPUT_AMOUNT" 434 | ); 435 | WETH.deposit.value(amounts[0])(); 436 | assert(WETH.transfer(pairFor(path[0], path[1]), amounts[0])); 437 | _swap(amounts, path, to); 438 | if (msg.value > amounts[0]) 439 | _safeTransferETH(_getTxSigner(), msg.value - amounts[0]); // refund dust eth, if any 440 | } 441 | } 442 | -------------------------------------------------------------------------------- /src/js/index.js: -------------------------------------------------------------------------------- 1 | var Web3 = require('web3') 2 | var Biconomy = require('@biconomy/mexa') 3 | const { config } = require('./config') 4 | let sigUtil = require('eth-sig-util') 5 | var web3 6 | var contract 7 | var erc20Contract 8 | var biconomy 9 | var netowrkName 10 | 11 | const domainType = [ 12 | { name: 'name', type: 'string' }, 13 | { name: 'version', type: 'string' }, 14 | { name: 'chainId', type: 'uint256' }, 15 | { name: 'verifyingContract', type: 'address' }, 16 | ] 17 | 18 | const permitType = [ 19 | { name: 'owner', type: 'address' }, 20 | { name: 'spender', type: 'address' }, 21 | { name: 'value', type: 'uint256' }, 22 | { name: 'nonce', type: 'uint256' }, 23 | { name: 'deadline', type: 'uint256' }, 24 | ] 25 | const domainTypeEIP2585 = [ 26 | { name: 'name', type: 'string' }, 27 | { name: 'version', type: 'string' }, 28 | ] 29 | const MetaTransactionType = [ 30 | { name: 'from', type: 'address' }, 31 | { name: 'to', type: 'address' }, 32 | { name: 'value', type: 'uint256' }, 33 | { name: 'chainId', type: 'uint256' }, 34 | { name: 'replayProtection', type: 'address' }, 35 | { name: 'nonce', type: 'bytes' }, 36 | { name: 'data', type: 'bytes' }, 37 | { name: 'innerMessageHash', type: 'bytes32' }, 38 | ] 39 | const domainData = { 40 | name: 'Forwarder', 41 | version: '1', 42 | } 43 | let domainDataERC20 = { 44 | version: '1', 45 | } 46 | const showFaucetLink = function () { 47 | if (netowrkName == 'ropsten') { 48 | mDAILink = 'https://oneclickdapp.com/cecilia-crash/' 49 | MANALink = 'https://oneclickdapp.com/velvet-papa/' 50 | } 51 | if (netowrkName == 'matic') { 52 | mDAILink = 'https://oneclickdapp.com/alias-type/' 53 | MANALink = 'https://oneclickdapp.com/street-mineral/' 54 | } 55 | var a = document.createElement('a') 56 | a.href = mDAILink 57 | a.title = 'faucet' 58 | a.target = '_blank' 59 | var link = document.createTextNode('mDAI faucet') 60 | a.appendChild(link) 61 | 62 | var x = document.createElement('LABEL') 63 | var t = document.createTextNode( 64 | ' :mint yourself 10000000000000000000 to be equal to 10 (Because of decimals): This action is not gasless' 65 | ) 66 | x.appendChild(t) 67 | var a1 = document.createElement('a') 68 | a1.href = MANALink 69 | a1.title = 'faucet' 70 | a1.target = '_blank' 71 | var link1 = document.createTextNode('MANA faucet') 72 | a1.appendChild(link1) 73 | document.body.prepend(x) 74 | var br = document.createElement('br') 75 | a1.appendChild(br) 76 | document.body.prepend(a) 77 | document.body.prepend(a1) 78 | } 79 | const forwarderEIP2585 = async function (_data) { 80 | var EIP712ForwarderContract = new web3.eth.Contract( 81 | config.contract.EIP712forwarderABI, 82 | config[netowrkName].EIP712forwarderAddress 83 | ) 84 | signer = ethereum.selectedAddress 85 | var from = signer 86 | var to = config[netowrkName].routerAddress 87 | var value = 0 88 | var chainId = await web3.eth.net.getId() 89 | var replayProtection = config[netowrkName].EIP712forwarderAddress 90 | console.log(chainId) 91 | var batchId = 0 92 | var batchNonce = await EIP712ForwarderContract.methods 93 | .getNonce(signer, batchId) 94 | .call() 95 | var value1 = batchId * Math.pow(2, 128) + batchNonce 96 | var valueBn = new web3.utils.BN(value1) 97 | var nonce = await web3.eth.abi.encodeParameter('uint256', valueBn) 98 | // var decoded = await web3.eth.abi.decodeParameter("uint256", nonce); 99 | // console.log(decoded); 100 | var data = _data 101 | var innerMessageHash = 102 | '0x0000000000000000000000000000000000000000000000000000000000000000' 103 | var forwardMessage = { 104 | from: from, 105 | to: to, 106 | value: 0, 107 | chainId, 108 | replayProtection: replayProtection, 109 | nonce: nonce, 110 | data, 111 | innerMessageHash: innerMessageHash, 112 | } 113 | var signatureData = { 114 | types: { 115 | EIP712Domain: domainTypeEIP2585, 116 | MetaTransaction: MetaTransactionType, 117 | }, 118 | domain: domainData, 119 | primaryType: 'MetaTransaction', 120 | message: forwardMessage, 121 | } 122 | console.log(signatureData) 123 | var sigString = JSON.stringify(signatureData) 124 | web3.providers.HttpProvider.prototype.sendAsync = 125 | web3.providers.HttpProvider.prototype.send 126 | 127 | web3.currentProvider.sendAsync( 128 | { 129 | method: 'eth_signTypedData_v4', 130 | params: [signer, sigString], 131 | from: signer, 132 | }, 133 | function (err, result) { 134 | if (err) { 135 | return console.error(err) 136 | } 137 | 138 | var signatureType = { 139 | SignatureType: 0, 140 | } 141 | console.log(forwardMessage) 142 | // var signatureType = 2; 143 | const signature = result.result 144 | console.log(signature) 145 | 146 | let tx = EIP712ForwarderContract.methods 147 | .forward(forwardMessage, 0, signature) 148 | .send({ from: signer }, (err, res) => { 149 | if (err) console.log(err) 150 | else console.log(res) 151 | }) 152 | 153 | tx.on('transactionHash', function (hash) { 154 | console.log(`Transaction hash is ${hash}`) 155 | var a = document.createElement('a') 156 | let tempString 157 | if (netowrkName == 'ropsten') { 158 | tempString = 'https://ropsten.etherscan.io/tx/' + hash 159 | } 160 | if (netowrkName == 'matic') { 161 | tempString = 162 | 'https://testnetv3-explorer.matic.network/tx/' + hash 163 | } 164 | a.href = tempString 165 | a.title = tempString 166 | var link = document.createTextNode(tempString) 167 | a.appendChild(link) 168 | // document.body.prepend(a) 169 | // var br = document.createElement('br') 170 | // a.appendChild(br) 171 | alert(a) 172 | }).once('confirmation', function (confirmationNumber, receipt) { 173 | console.log(receipt) 174 | }) 175 | } 176 | ) 177 | } 178 | 179 | const connectWallet = async function () { 180 | if (typeof window.ethereum !== 'undefined' && window.ethereum.isMetaMask) { 181 | // Ethereum user detected. You can now use the provider. 182 | const provider = window['ethereum'] 183 | let accounts = await provider.enable() 184 | document.getElementById('toWhom').value = accounts[0] 185 | document.getElementById('toWhom1').value = accounts[0] 186 | console.log(provider.networkVersion) 187 | var _chainId = provider.networkVersion 188 | 189 | //var chainId = parseInt(_chainId); 190 | domainDataERC20.chainId = _chainId 191 | console.log(_chainId) 192 | 193 | if (_chainId == 3) { 194 | netowrkName = 'ropsten' 195 | } 196 | if (_chainId == 15001) { 197 | netowrkName = 'matic' 198 | } 199 | showFaucetLink() 200 | web3 = new Web3(provider) 201 | if (netowrkName == 'ropsten') { 202 | biconomy = new Biconomy(window.ethereum, { 203 | apiKey: 'sdLlgS_TO.8a399db4-82ec-410c-897b-c77faab1ad1d', 204 | debug: 'true', 205 | }) 206 | web3 = new Web3(biconomy) 207 | biconomy 208 | .onEvent(biconomy.READY, async () => { 209 | console.log('hello') 210 | 211 | //await justTrying(); 212 | }) 213 | .onEvent(biconomy.ERROR, (error, message) => { 214 | console.log(error) 215 | }) 216 | } 217 | if (netowrkName == 'matic') { 218 | biconomy = new Biconomy(window.ethereum, { 219 | apiKey: 'Q34QBan9O.1fb12039-9bbe-45d2-a1f9-22cbb2636fe9', 220 | debug: 'true', 221 | }) 222 | web3 = new Web3(biconomy) 223 | biconomy 224 | .onEvent(biconomy.READY, async () => { 225 | console.log('hello') 226 | //await justTrying(); 227 | }) 228 | .onEvent(biconomy.ERROR, (error, message) => { 229 | console.log(error) 230 | }) 231 | } 232 | contract = new web3.eth.Contract( 233 | config.contract.routerABI, 234 | config[netowrkName].routerAddress 235 | ) 236 | 237 | //console.log(await contract.methods.getQuote().call()); 238 | } else { 239 | alert('Install meatamask first: https://metamask.io/ ') 240 | } 241 | } 242 | const getSignatureParameters = (signature) => { 243 | if (!web3.utils.isHexStrict(signature)) { 244 | throw new Error( 245 | 'Given value "'.concat(signature, '" is not a valid hex string.') 246 | ) 247 | } 248 | var r = signature.slice(0, 66) 249 | var s = '0x'.concat(signature.slice(66, 130)) 250 | var v = '0x'.concat(signature.slice(130, 132)) 251 | v = web3.utils.hexToNumber(v) 252 | if (![27, 28].includes(v)) v += 27 253 | return { 254 | r: r, 255 | s: s, 256 | v: v, 257 | } 258 | } 259 | const sendPermitTransaction = async ( 260 | owner, 261 | spender, 262 | value, 263 | deadline, 264 | v, 265 | r, 266 | s 267 | ) => { 268 | if (web3 && erc20Contract) { 269 | try { 270 | console.log('hi::::::::::') 271 | let gasLimit = await erc20Contract.methods 272 | .permit(owner, spender, value, deadline, v, r, s) 273 | .estimateGas({ from: owner }) 274 | let gasPrice = await web3.eth.getGasPrice() 275 | console.log(gasLimit) 276 | console.log(gasPrice) 277 | let tx = erc20Contract.methods 278 | .permit(owner, spender, value, deadline, v, r, s) 279 | .send({ 280 | from: owner, 281 | gasPrice: web3.utils.toHex(gasPrice), 282 | gasLimit: web3.utils.toHex(gasLimit), 283 | }) 284 | 285 | tx.on('transactionHash', function (hash) { 286 | console.log(`Transaction hash is ${hash}`) 287 | }).once('confirmation', function (confirmationNumber, receipt) { 288 | let elements = document.getElementsByClassName('loader') 289 | elements[0].style.display = 'none' 290 | console.log(receipt) 291 | alert('tokens unlocked') 292 | }) 293 | } catch (error) { 294 | console.log(error) 295 | } 296 | } 297 | } 298 | const getPermit = async function (token, _value) { 299 | let value = web3.utils.toWei(_value) 300 | erc20Contract = new web3.eth.Contract( 301 | config.contract.erc20ABI, 302 | config[netowrkName][token] 303 | ) 304 | console.log(config[netowrkName][token]) 305 | console.log(erc20Contract) 306 | let message = {} 307 | var userAddress = ethereum.selectedAddress 308 | var owner = userAddress 309 | var spender = config[netowrkName].routerAddress 310 | var now = await getNow() 311 | var deadline = now + 60 * 60 312 | var nonce = await erc20Contract.methods.nonces(userAddress).call() 313 | 314 | message.owner = userAddress 315 | message.spender = spender 316 | message.value = value 317 | message.nonce = parseInt(nonce) 318 | message.deadline = deadline 319 | 320 | domainDataERC20.name = token 321 | domainDataERC20.verifyingContract = config[netowrkName][token] 322 | 323 | const dataToSign = { 324 | types: { 325 | EIP712Domain: domainType, 326 | Permit: permitType, 327 | }, 328 | domain: domainDataERC20, 329 | primaryType: 'Permit', 330 | message: message, 331 | } 332 | const sigString = JSON.stringify(dataToSign) 333 | console.log(dataToSign) 334 | 335 | web3.currentProvider.send( 336 | { 337 | jsonrpc: '2.0', 338 | id: 999999999999, 339 | method: 'eth_signTypedData_v4', 340 | params: [userAddress, sigString], 341 | }, 342 | function (error, response) { 343 | console.log(response) 344 | let elements = document.getElementsByClassName('loader') 345 | elements[0].style.display = 'inline-block' 346 | let { r, s, v } = getSignatureParameters(response.result) 347 | sendPermitTransaction(owner, spender, value, deadline, v, r, s) 348 | } 349 | ) 350 | } 351 | const getNow = async function () { 352 | var latestBlock = await web3.eth.getBlock('latest') 353 | var now = latestBlock.timestamp 354 | return parseInt(now) 355 | } 356 | // function getAmountWithDecimals(_tokenAmount) { 357 | // var decimals = web3.utils.toBN(18) 358 | // var tokenAmount = web3.utils.toBN(_tokenAmount) 359 | // var tokenAmountHex = tokenAmount.mul(web3.utils.toBN(10).pow(decimals)) 360 | // return web3.utils.toHex(tokenAmountHex) 361 | // } 362 | 363 | const getAmountOut = async function ( 364 | inputAmount, 365 | inputTokenName, 366 | outputTokenName 367 | ) { 368 | if (web3 && contract) { 369 | let path = [ 370 | config[netowrkName][inputTokenName], 371 | config[netowrkName][outputTokenName], 372 | ] 373 | // let inputAmountDecimals = getAmountWithDecimals(inputAmount) 374 | // console.log(inputAmountDecimals) 375 | 376 | let amountsOut = await contract.methods 377 | .getAmountsOut(inputAmount, path) 378 | .call() 379 | let outputString = amountsOut[1].toString() 380 | return outputString 381 | } else { 382 | alert('coninputAmountnectWallet first') 383 | } 384 | } 385 | 386 | const swapExactTokensForTokens = async function ( 387 | amount, 388 | inputTokenName, 389 | outputTokenName, 390 | to 391 | ) { 392 | var now = await getNow() 393 | var deadline = now + 60 * 60 394 | let path = [ 395 | config[netowrkName][inputTokenName], 396 | config[netowrkName][outputTokenName], 397 | ] 398 | let amountsOutMin = await getAmountOut( 399 | amount, 400 | inputTokenName, 401 | outputTokenName 402 | ) 403 | let data = contract.methods 404 | .swapExactTokensForTokens( 405 | web3.utils.toWei(amount.toString(), 'ether'), 406 | amountsOutMin, 407 | path, 408 | to, 409 | deadline 410 | ) 411 | .encodeABI() 412 | // web3.eth.sendTransaction({from:from,to:config[netowrkName].routerAddress,data:data}); 413 | forwarderEIP2585(data) 414 | } 415 | const getBalanceERC20 = async function (ERC20address, wadAddress) { 416 | let tempERC20Contract = new web3.eth.Contract( 417 | config.contract.erc20ABI, 418 | ERC20address 419 | ) 420 | let balance = await tempERC20Contract.methods.balanceOf(wadAddress).call() 421 | // console.log(await ERC20Contract.methods.decimals().call()); 422 | console.log(balance) 423 | 424 | let balanceWithDecimals = web3.utils.fromWei(balance) 425 | return balanceWithDecimals 426 | } 427 | const getMax = async function (inputElementId, outputElementId) { 428 | let wadAddress = ethereum.selectedAddress 429 | console.log(wadAddress) 430 | let inputToken = document.getElementById(inputElementId) 431 | let inputTokenName = inputToken.options[inputToken.selectedIndex].value 432 | let inputTokenaddress = config[netowrkName][inputTokenName] 433 | console.log(inputTokenaddress) 434 | let balance = await getBalanceERC20(inputTokenaddress, wadAddress) 435 | document.getElementById(outputElementId).value = balance 436 | } 437 | const swap = async function () { 438 | let inputToken = document.getElementById('inputToken') 439 | let inputTokenName = inputToken.options[inputToken.selectedIndex].value 440 | let outputToken = document.getElementById('outputToken') 441 | let outputTokenName = outputToken.options[outputToken.selectedIndex].value 442 | let toWhom = document.getElementById('toWhom').value 443 | console.log(toWhom) 444 | 445 | let inputAmount = document.getElementById('input').value 446 | await swapExactTokensForTokens( 447 | inputAmount, 448 | inputTokenName, 449 | outputTokenName, 450 | toWhom 451 | ) 452 | } 453 | 454 | const unlockToken = async function (inputSelectElementId, inputValueElementId) { 455 | let inputToken = document.getElementById(inputSelectElementId) 456 | let inputTokenName = inputToken.options[inputToken.selectedIndex].value 457 | let inputAmount = document.getElementById(inputValueElementId).value 458 | await getPermit(inputTokenName, inputAmount) 459 | } 460 | 461 | const getExchangeRate = async function () { 462 | let inputToken = document.getElementById('inputToken') 463 | let inputTokenName = inputToken.options[inputToken.selectedIndex].value 464 | let outputToken = document.getElementById('outputToken') 465 | let outputTokenName = outputToken.options[outputToken.selectedIndex].value 466 | 467 | let inputAmount = document.getElementById('input').value 468 | console.log(inputTokenName) 469 | console.log(outputTokenName) 470 | console.log(inputAmount) 471 | let amountsInDecimals = web3.utils.toWei(inputAmount, 'ether') 472 | console.log(amountsInDecimals) 473 | 474 | let amountsOutDecimals = await getAmountOut( 475 | amountsInDecimals, 476 | inputTokenName, 477 | outputTokenName 478 | ) 479 | let amountOut = web3.utils.fromWei(amountsOutDecimals, 'ether') 480 | // console.log(amountOut); 481 | document.getElementById('output').value = amountOut 482 | 483 | // // let amountsOut = web3.utils.fromWei(amountsOutDecimals,"ether"); 484 | // console.log(amountsOutDecimals.toString()); 485 | } 486 | const addLiquidity = async function () { 487 | let inputToken1 = document.getElementById('inputToken1') 488 | let inputToken1Name = inputToken1.options[inputToken1.selectedIndex].value 489 | let inputToken2 = document.getElementById('inputToken2') 490 | let inputToken2Name = inputToken1.options[inputToken2.selectedIndex].value 491 | 492 | let inputAmount1 = document.getElementById('input1').value 493 | let inputAmount2 = document.getElementById('input2').value 494 | 495 | let toWhom = document.getElementById('toWhom1').value 496 | let now = await getNow() 497 | let expiry = now + 3600 498 | console.log(toWhom) 499 | 500 | let data = contract.methods 501 | .addLiquidity( 502 | config[netowrkName][inputToken1Name], 503 | config[netowrkName][inputToken2Name], 504 | web3.utils.toWei(inputAmount1.toString(), 'ether'), 505 | web3.utils.toWei(inputAmount2.toString(), 'ether'), 506 | 0, 507 | 0, 508 | toWhom, 509 | expiry 510 | ) 511 | .encodeABI() 512 | forwarderEIP2585(data) 513 | } 514 | 515 | // init(); 516 | 517 | var moduleTry = { 518 | connectWallet, 519 | getExchangeRate, 520 | swap, 521 | unlockToken, 522 | getMax, 523 | addLiquidity, 524 | } 525 | module.exports = moduleTry 526 | -------------------------------------------------------------------------------- /src/js/config.js: -------------------------------------------------------------------------------- 1 | let config = {}; 2 | 3 | config.ropsten= {//addresses 4 | mDAI: '0x99c3C3C6E280f6aF1F3D22a5DAC6802A2814bc31', 5 | mETH: '0x4BF793cc8b3488018CD6C182A6e179D130C99b92', 6 | m0x: '0x84B177Faa14e4474dd3b74E9Ba97dB2E8Fe8FF4d', 7 | MANA: '0x123fda699AFd052e3139E8Bc41B9fD4397489E5A', 8 | mBTC: '0xBBde5bf52eEBca84386523BCeAD0B47013F4673f', 9 | mUSDT: '0x9Cf8C345BF0a302c054df749968443F54fb4ea60', 10 | factoryAddress: '0x63f8e81F4e7628eC441Bdf508B309EdAE4022c71', 11 | routerAddress: '0x438697d6a5EB01f37B1599c82e9Dad56D9603658', 12 | EIP712forwarderAddress: '0x062ECA08aE7441528a298b9D81aa23b4B6cad4E5' 13 | }; 14 | config.matic={ //addresses 15 | mDAI: '0xa7E3c50e1050b59c31415537e021e3F9615Cd8FA', 16 |   mETH: '0x2B11Af8a49877cC9becbDF29019Ec15Ed751b720', 17 |   m0x: '0xf87a725e3DE96B2f927f93294AaDaD22A5b4756f', 18 |   MANA: '0x10024660B4260Df5B893eD47732346e11DA6537f', 19 |   mBTC: '0xb99c4fed57Bf60Fd95ab104F10be8d31068B08AE', 20 |   mUSDT: '0xcbF95FaF80F52456cc7022a92B76BB46718d83A2', 21 |   factoryAddress: '0xBa3e4831f6600BEeeA8C0F9F59754d9afc07F570', 22 |   routerAddress: '0x95c3F714C93b67Dff2B530E467f8b05bA477ab50', 23 |   EIP712forwarderAddress: '0xe6c89dB2aDDd90546e78bA008E0bCF07e2257171' } 24 | //add routerABI and ForwarderAbi 25 | config.contract = { 26 | erc20ABI: [ 27 | { 28 | inputs: [ 29 | { 30 | internalType: "uint256", 31 | name: "_initialSupply", 32 | type: "uint256" 33 | }, 34 | { 35 | internalType: "uint256", 36 | name: "_chainId", 37 | type: "uint256" 38 | } 39 | ], 40 | payable: false, 41 | stateMutability: "nonpayable", 42 | type: "constructor" 43 | }, 44 | { 45 | anonymous: false, 46 | inputs: [ 47 | { 48 | indexed: true, 49 | internalType: "address", 50 | name: "owner", 51 | type: "address" 52 | }, 53 | { 54 | indexed: true, 55 | internalType: "address", 56 | name: "spender", 57 | type: "address" 58 | }, 59 | { 60 | indexed: false, 61 | internalType: "uint256", 62 | name: "value", 63 | type: "uint256" 64 | } 65 | ], 66 | name: "Approval", 67 | type: "event" 68 | }, 69 | { 70 | anonymous: false, 71 | inputs: [ 72 | { 73 | indexed: true, 74 | internalType: "address", 75 | name: "from", 76 | type: "address" 77 | }, 78 | { 79 | indexed: true, 80 | internalType: "address", 81 | name: "to", 82 | type: "address" 83 | }, 84 | { 85 | indexed: false, 86 | internalType: "uint256", 87 | name: "value", 88 | type: "uint256" 89 | } 90 | ], 91 | name: "Transfer", 92 | type: "event" 93 | }, 94 | { 95 | constant: true, 96 | inputs: [], 97 | name: "DOMAIN_SEPARATOR", 98 | outputs: [ 99 | { 100 | internalType: "bytes32", 101 | name: "", 102 | type: "bytes32" 103 | } 104 | ], 105 | payable: false, 106 | stateMutability: "view", 107 | type: "function" 108 | }, 109 | { 110 | constant: true, 111 | inputs: [], 112 | name: "PERMIT_TYPEHASH", 113 | outputs: [ 114 | { 115 | internalType: "bytes32", 116 | name: "", 117 | type: "bytes32" 118 | } 119 | ], 120 | payable: false, 121 | stateMutability: "view", 122 | type: "function" 123 | }, 124 | { 125 | constant: true, 126 | inputs: [ 127 | { 128 | internalType: "address", 129 | name: "", 130 | type: "address" 131 | }, 132 | { 133 | internalType: "address", 134 | name: "", 135 | type: "address" 136 | } 137 | ], 138 | name: "allowance", 139 | outputs: [ 140 | { 141 | internalType: "uint256", 142 | name: "", 143 | type: "uint256" 144 | } 145 | ], 146 | payable: false, 147 | stateMutability: "view", 148 | type: "function" 149 | }, 150 | { 151 | constant: false, 152 | inputs: [ 153 | { 154 | internalType: "address", 155 | name: "spender", 156 | type: "address" 157 | }, 158 | { 159 | internalType: "uint256", 160 | name: "value", 161 | type: "uint256" 162 | } 163 | ], 164 | name: "approve", 165 | outputs: [ 166 | { 167 | internalType: "bool", 168 | name: "", 169 | type: "bool" 170 | } 171 | ], 172 | payable: false, 173 | stateMutability: "nonpayable", 174 | type: "function" 175 | }, 176 | { 177 | constant: true, 178 | inputs: [ 179 | { 180 | internalType: "address", 181 | name: "", 182 | type: "address" 183 | } 184 | ], 185 | name: "balanceOf", 186 | outputs: [ 187 | { 188 | internalType: "uint256", 189 | name: "", 190 | type: "uint256" 191 | } 192 | ], 193 | payable: false, 194 | stateMutability: "view", 195 | type: "function" 196 | }, 197 | { 198 | constant: true, 199 | inputs: [], 200 | name: "decimals", 201 | outputs: [ 202 | { 203 | internalType: "uint8", 204 | name: "", 205 | type: "uint8" 206 | } 207 | ], 208 | payable: false, 209 | stateMutability: "view", 210 | type: "function" 211 | }, 212 | { 213 | constant: true, 214 | inputs: [], 215 | name: "name", 216 | outputs: [ 217 | { 218 | internalType: "string", 219 | name: "", 220 | type: "string" 221 | } 222 | ], 223 | payable: false, 224 | stateMutability: "view", 225 | type: "function" 226 | }, 227 | { 228 | constant: true, 229 | inputs: [ 230 | { 231 | internalType: "address", 232 | name: "", 233 | type: "address" 234 | } 235 | ], 236 | name: "nonces", 237 | outputs: [ 238 | { 239 | internalType: "uint256", 240 | name: "", 241 | type: "uint256" 242 | } 243 | ], 244 | payable: false, 245 | stateMutability: "view", 246 | type: "function" 247 | }, 248 | { 249 | constant: false, 250 | inputs: [ 251 | { 252 | internalType: "address", 253 | name: "owner", 254 | type: "address" 255 | }, 256 | { 257 | internalType: "address", 258 | name: "spender", 259 | type: "address" 260 | }, 261 | { 262 | internalType: "uint256", 263 | name: "value", 264 | type: "uint256" 265 | }, 266 | { 267 | internalType: "uint256", 268 | name: "deadline", 269 | type: "uint256" 270 | }, 271 | { 272 | internalType: "uint8", 273 | name: "v", 274 | type: "uint8" 275 | }, 276 | { 277 | internalType: "bytes32", 278 | name: "r", 279 | type: "bytes32" 280 | }, 281 | { 282 | internalType: "bytes32", 283 | name: "s", 284 | type: "bytes32" 285 | } 286 | ], 287 | name: "permit", 288 | outputs: [], 289 | payable: false, 290 | stateMutability: "nonpayable", 291 | type: "function" 292 | }, 293 | { 294 | constant: true, 295 | inputs: [], 296 | name: "symbol", 297 | outputs: [ 298 | { 299 | internalType: "string", 300 | name: "", 301 | type: "string" 302 | } 303 | ], 304 | payable: false, 305 | stateMutability: "view", 306 | type: "function" 307 | }, 308 | { 309 | constant: true, 310 | inputs: [], 311 | name: "totalSupply", 312 | outputs: [ 313 | { 314 | internalType: "uint256", 315 | name: "", 316 | type: "uint256" 317 | } 318 | ], 319 | payable: false, 320 | stateMutability: "view", 321 | type: "function" 322 | }, 323 | { 324 | constant: false, 325 | inputs: [ 326 | { 327 | internalType: "address", 328 | name: "to", 329 | type: "address" 330 | }, 331 | { 332 | internalType: "uint256", 333 | name: "value", 334 | type: "uint256" 335 | } 336 | ], 337 | name: "transfer", 338 | outputs: [ 339 | { 340 | internalType: "bool", 341 | name: "", 342 | type: "bool" 343 | } 344 | ], 345 | payable: false, 346 | stateMutability: "nonpayable", 347 | type: "function" 348 | }, 349 | { 350 | constant: false, 351 | inputs: [ 352 | { 353 | internalType: "address", 354 | name: "from", 355 | type: "address" 356 | }, 357 | { 358 | internalType: "address", 359 | name: "to", 360 | type: "address" 361 | }, 362 | { 363 | internalType: "uint256", 364 | name: "value", 365 | type: "uint256" 366 | } 367 | ], 368 | name: "transferFrom", 369 | outputs: [ 370 | { 371 | internalType: "bool", 372 | name: "", 373 | type: "bool" 374 | } 375 | ], 376 | payable: false, 377 | stateMutability: "nonpayable", 378 | type: "function" 379 | }, 380 | { 381 | constant: false, 382 | inputs: [ 383 | { 384 | internalType: "uint256", 385 | name: "amount", 386 | type: "uint256" 387 | } 388 | ], 389 | name: "mint", 390 | outputs: [], 391 | payable: false, 392 | stateMutability: "nonpayable", 393 | type: "function" 394 | } 395 | ], 396 | EIP712forwarderABI:[ 397 | { 398 | "inputs": [ 399 | { 400 | "internalType": "uint256", 401 | "name": "_chainId", 402 | "type": "uint256" 403 | } 404 | ], 405 | "payable": false, 406 | "stateMutability": "nonpayable", 407 | "type": "constructor" 408 | }, 409 | { 410 | "constant": true, 411 | "inputs": [], 412 | "name": "chainId", 413 | "outputs": [ 414 | { 415 | "internalType": "uint256", 416 | "name": "", 417 | "type": "uint256" 418 | } 419 | ], 420 | "payable": false, 421 | "stateMutability": "view", 422 | "type": "function" 423 | }, 424 | { 425 | "constant": false, 426 | "inputs": [ 427 | { 428 | "components": [ 429 | { 430 | "internalType": "address", 431 | "name": "from", 432 | "type": "address" 433 | }, 434 | { 435 | "internalType": "address", 436 | "name": "to", 437 | "type": "address" 438 | }, 439 | { 440 | "internalType": "uint256", 441 | "name": "chainId", 442 | "type": "uint256" 443 | }, 444 | { 445 | "internalType": "address", 446 | "name": "replayProtection", 447 | "type": "address" 448 | }, 449 | { 450 | "internalType": "bytes", 451 | "name": "nonce", 452 | "type": "bytes" 453 | }, 454 | { 455 | "internalType": "bytes", 456 | "name": "data", 457 | "type": "bytes" 458 | }, 459 | { 460 | "internalType": "bytes32", 461 | "name": "innerMessageHash", 462 | "type": "bytes32" 463 | } 464 | ], 465 | "internalType": "struct Forwarder.Message", 466 | "name": "message", 467 | "type": "tuple" 468 | }, 469 | { 470 | "internalType": "enum Forwarder.SignatureType", 471 | "name": "signatureType", 472 | "type": "uint8" 473 | }, 474 | { 475 | "internalType": "bytes", 476 | "name": "signature", 477 | "type": "bytes" 478 | } 479 | ], 480 | "name": "forward", 481 | "outputs": [], 482 | "payable": true, 483 | "stateMutability": "payable", 484 | "type": "function" 485 | }, 486 | { 487 | "constant": false, 488 | "inputs": [ 489 | { 490 | "components": [ 491 | { 492 | "internalType": "address", 493 | "name": "to", 494 | "type": "address" 495 | }, 496 | { 497 | "internalType": "bytes", 498 | "name": "data", 499 | "type": "bytes" 500 | }, 501 | { 502 | "internalType": "uint256", 503 | "name": "value", 504 | "type": "uint256" 505 | } 506 | ], 507 | "internalType": "struct EIP712Forwarder.Call[]", 508 | "name": "calls", 509 | "type": "tuple[]" 510 | } 511 | ], 512 | "name": "batch", 513 | "outputs": [], 514 | "payable": true, 515 | "stateMutability": "payable", 516 | "type": "function" 517 | }, 518 | { 519 | "constant": false, 520 | "inputs": [ 521 | { 522 | "internalType": "address", 523 | "name": "signer", 524 | "type": "address" 525 | }, 526 | { 527 | "internalType": "bytes", 528 | "name": "nonce", 529 | "type": "bytes" 530 | } 531 | ], 532 | "name": "checkAndUpdateNonce", 533 | "outputs": [ 534 | { 535 | "internalType": "bool", 536 | "name": "", 537 | "type": "bool" 538 | } 539 | ], 540 | "payable": false, 541 | "stateMutability": "nonpayable", 542 | "type": "function" 543 | }, 544 | { 545 | "constant": true, 546 | "inputs": [ 547 | { 548 | "internalType": "address", 549 | "name": "signer", 550 | "type": "address" 551 | }, 552 | { 553 | "internalType": "uint128", 554 | "name": "batchId", 555 | "type": "uint128" 556 | } 557 | ], 558 | "name": "getNonce", 559 | "outputs": [ 560 | { 561 | "internalType": "uint128", 562 | "name": "", 563 | "type": "uint128" 564 | } 565 | ], 566 | "payable": false, 567 | "stateMutability": "view", 568 | "type": "function" 569 | } 570 | ], 571 | routerABI:[ 572 | { 573 | "inputs": [ 574 | { 575 | "internalType": "address", 576 | "name": "_WETH", 577 | "type": "address" 578 | }, 579 | { 580 | "internalType": "address", 581 | "name": "_factory", 582 | "type": "address" 583 | }, 584 | { 585 | "internalType": "address", 586 | "name": "_forwarder", 587 | "type": "address" 588 | } 589 | ], 590 | "payable": false, 591 | "stateMutability": "nonpayable", 592 | "type": "constructor" 593 | }, 594 | { 595 | "payable": true, 596 | "stateMutability": "payable", 597 | "type": "fallback" 598 | }, 599 | { 600 | "constant": true, 601 | "inputs": [], 602 | "name": "WETH", 603 | "outputs": [ 604 | { 605 | "internalType": "contract IWETH", 606 | "name": "", 607 | "type": "address" 608 | } 609 | ], 610 | "payable": false, 611 | "stateMutability": "view", 612 | "type": "function" 613 | }, 614 | { 615 | "constant": true, 616 | "inputs": [], 617 | "name": "factory", 618 | "outputs": [ 619 | { 620 | "internalType": "contract IUniswapV2Factory", 621 | "name": "", 622 | "type": "address" 623 | } 624 | ], 625 | "payable": false, 626 | "stateMutability": "view", 627 | "type": "function" 628 | }, 629 | { 630 | "constant": true, 631 | "inputs": [ 632 | { 633 | "internalType": "uint256", 634 | "name": "amountOut", 635 | "type": "uint256" 636 | }, 637 | { 638 | "internalType": "uint256", 639 | "name": "reserveIn", 640 | "type": "uint256" 641 | }, 642 | { 643 | "internalType": "uint256", 644 | "name": "reserveOut", 645 | "type": "uint256" 646 | } 647 | ], 648 | "name": "getAmountIn", 649 | "outputs": [ 650 | { 651 | "internalType": "uint256", 652 | "name": "amountIn", 653 | "type": "uint256" 654 | } 655 | ], 656 | "payable": false, 657 | "stateMutability": "pure", 658 | "type": "function" 659 | }, 660 | { 661 | "constant": true, 662 | "inputs": [ 663 | { 664 | "internalType": "uint256", 665 | "name": "amountIn", 666 | "type": "uint256" 667 | }, 668 | { 669 | "internalType": "uint256", 670 | "name": "reserveIn", 671 | "type": "uint256" 672 | }, 673 | { 674 | "internalType": "uint256", 675 | "name": "reserveOut", 676 | "type": "uint256" 677 | } 678 | ], 679 | "name": "getAmountOut", 680 | "outputs": [ 681 | { 682 | "internalType": "uint256", 683 | "name": "amountOut", 684 | "type": "uint256" 685 | } 686 | ], 687 | "payable": false, 688 | "stateMutability": "pure", 689 | "type": "function" 690 | }, 691 | { 692 | "constant": true, 693 | "inputs": [ 694 | { 695 | "internalType": "uint256", 696 | "name": "amountOut", 697 | "type": "uint256" 698 | }, 699 | { 700 | "internalType": "address[]", 701 | "name": "path", 702 | "type": "address[]" 703 | } 704 | ], 705 | "name": "getAmountsIn", 706 | "outputs": [ 707 | { 708 | "internalType": "uint256[]", 709 | "name": "amounts", 710 | "type": "uint256[]" 711 | } 712 | ], 713 | "payable": false, 714 | "stateMutability": "view", 715 | "type": "function" 716 | }, 717 | { 718 | "constant": true, 719 | "inputs": [ 720 | { 721 | "internalType": "uint256", 722 | "name": "amountIn", 723 | "type": "uint256" 724 | }, 725 | { 726 | "internalType": "address[]", 727 | "name": "path", 728 | "type": "address[]" 729 | } 730 | ], 731 | "name": "getAmountsOut", 732 | "outputs": [ 733 | { 734 | "internalType": "uint256[]", 735 | "name": "amounts", 736 | "type": "uint256[]" 737 | } 738 | ], 739 | "payable": false, 740 | "stateMutability": "view", 741 | "type": "function" 742 | }, 743 | { 744 | "constant": true, 745 | "inputs": [ 746 | { 747 | "internalType": "uint256", 748 | "name": "amountA", 749 | "type": "uint256" 750 | }, 751 | { 752 | "internalType": "uint256", 753 | "name": "reserveA", 754 | "type": "uint256" 755 | }, 756 | { 757 | "internalType": "uint256", 758 | "name": "reserveB", 759 | "type": "uint256" 760 | } 761 | ], 762 | "name": "quote", 763 | "outputs": [ 764 | { 765 | "internalType": "uint256", 766 | "name": "amountB", 767 | "type": "uint256" 768 | } 769 | ], 770 | "payable": false, 771 | "stateMutability": "pure", 772 | "type": "function" 773 | }, 774 | { 775 | "constant": false, 776 | "inputs": [ 777 | { 778 | "internalType": "address", 779 | "name": "tokenA", 780 | "type": "address" 781 | }, 782 | { 783 | "internalType": "address", 784 | "name": "tokenB", 785 | "type": "address" 786 | }, 787 | { 788 | "internalType": "uint256", 789 | "name": "amountADesired", 790 | "type": "uint256" 791 | }, 792 | { 793 | "internalType": "uint256", 794 | "name": "amountBDesired", 795 | "type": "uint256" 796 | }, 797 | { 798 | "internalType": "uint256", 799 | "name": "amountAMin", 800 | "type": "uint256" 801 | }, 802 | { 803 | "internalType": "uint256", 804 | "name": "amountBMin", 805 | "type": "uint256" 806 | }, 807 | { 808 | "internalType": "address", 809 | "name": "to", 810 | "type": "address" 811 | }, 812 | { 813 | "internalType": "uint256", 814 | "name": "deadline", 815 | "type": "uint256" 816 | } 817 | ], 818 | "name": "addLiquidity", 819 | "outputs": [ 820 | { 821 | "internalType": "uint256", 822 | "name": "amountA", 823 | "type": "uint256" 824 | }, 825 | { 826 | "internalType": "uint256", 827 | "name": "amountB", 828 | "type": "uint256" 829 | }, 830 | { 831 | "internalType": "uint256", 832 | "name": "liquidity", 833 | "type": "uint256" 834 | } 835 | ], 836 | "payable": false, 837 | "stateMutability": "nonpayable", 838 | "type": "function" 839 | }, 840 | { 841 | "constant": false, 842 | "inputs": [ 843 | { 844 | "internalType": "address", 845 | "name": "token", 846 | "type": "address" 847 | }, 848 | { 849 | "internalType": "uint256", 850 | "name": "amountTokenDesired", 851 | "type": "uint256" 852 | }, 853 | { 854 | "internalType": "uint256", 855 | "name": "amountTokenMin", 856 | "type": "uint256" 857 | }, 858 | { 859 | "internalType": "uint256", 860 | "name": "amountETHMin", 861 | "type": "uint256" 862 | }, 863 | { 864 | "internalType": "address", 865 | "name": "to", 866 | "type": "address" 867 | }, 868 | { 869 | "internalType": "uint256", 870 | "name": "deadline", 871 | "type": "uint256" 872 | } 873 | ], 874 | "name": "addLiquidityETH", 875 | "outputs": [ 876 | { 877 | "internalType": "uint256", 878 | "name": "amountToken", 879 | "type": "uint256" 880 | }, 881 | { 882 | "internalType": "uint256", 883 | "name": "amountETH", 884 | "type": "uint256" 885 | }, 886 | { 887 | "internalType": "uint256", 888 | "name": "liquidity", 889 | "type": "uint256" 890 | } 891 | ], 892 | "payable": true, 893 | "stateMutability": "payable", 894 | "type": "function" 895 | }, 896 | { 897 | "constant": false, 898 | "inputs": [ 899 | { 900 | "internalType": "address", 901 | "name": "tokenA", 902 | "type": "address" 903 | }, 904 | { 905 | "internalType": "address", 906 | "name": "tokenB", 907 | "type": "address" 908 | }, 909 | { 910 | "internalType": "uint256", 911 | "name": "liquidity", 912 | "type": "uint256" 913 | }, 914 | { 915 | "internalType": "uint256", 916 | "name": "amountAMin", 917 | "type": "uint256" 918 | }, 919 | { 920 | "internalType": "uint256", 921 | "name": "amountBMin", 922 | "type": "uint256" 923 | }, 924 | { 925 | "internalType": "address", 926 | "name": "to", 927 | "type": "address" 928 | }, 929 | { 930 | "internalType": "uint256", 931 | "name": "deadline", 932 | "type": "uint256" 933 | } 934 | ], 935 | "name": "removeLiquidity", 936 | "outputs": [ 937 | { 938 | "internalType": "uint256", 939 | "name": "amountA", 940 | "type": "uint256" 941 | }, 942 | { 943 | "internalType": "uint256", 944 | "name": "amountB", 945 | "type": "uint256" 946 | } 947 | ], 948 | "payable": false, 949 | "stateMutability": "nonpayable", 950 | "type": "function" 951 | }, 952 | { 953 | "constant": false, 954 | "inputs": [ 955 | { 956 | "internalType": "address", 957 | "name": "token", 958 | "type": "address" 959 | }, 960 | { 961 | "internalType": "uint256", 962 | "name": "liquidity", 963 | "type": "uint256" 964 | }, 965 | { 966 | "internalType": "uint256", 967 | "name": "amountTokenMin", 968 | "type": "uint256" 969 | }, 970 | { 971 | "internalType": "uint256", 972 | "name": "amountETHMin", 973 | "type": "uint256" 974 | }, 975 | { 976 | "internalType": "address", 977 | "name": "to", 978 | "type": "address" 979 | }, 980 | { 981 | "internalType": "uint256", 982 | "name": "deadline", 983 | "type": "uint256" 984 | } 985 | ], 986 | "name": "removeLiquidityETH", 987 | "outputs": [ 988 | { 989 | "internalType": "uint256", 990 | "name": "amountToken", 991 | "type": "uint256" 992 | }, 993 | { 994 | "internalType": "uint256", 995 | "name": "amountETH", 996 | "type": "uint256" 997 | } 998 | ], 999 | "payable": false, 1000 | "stateMutability": "nonpayable", 1001 | "type": "function" 1002 | }, 1003 | { 1004 | "constant": false, 1005 | "inputs": [ 1006 | { 1007 | "internalType": "address", 1008 | "name": "tokenA", 1009 | "type": "address" 1010 | }, 1011 | { 1012 | "internalType": "address", 1013 | "name": "tokenB", 1014 | "type": "address" 1015 | }, 1016 | { 1017 | "internalType": "uint256", 1018 | "name": "liquidity", 1019 | "type": "uint256" 1020 | }, 1021 | { 1022 | "internalType": "uint256", 1023 | "name": "amountAMin", 1024 | "type": "uint256" 1025 | }, 1026 | { 1027 | "internalType": "uint256", 1028 | "name": "amountBMin", 1029 | "type": "uint256" 1030 | }, 1031 | { 1032 | "internalType": "address", 1033 | "name": "to", 1034 | "type": "address" 1035 | }, 1036 | { 1037 | "internalType": "uint256", 1038 | "name": "deadline", 1039 | "type": "uint256" 1040 | }, 1041 | { 1042 | "internalType": "bool", 1043 | "name": "approveMax", 1044 | "type": "bool" 1045 | }, 1046 | { 1047 | "internalType": "uint8", 1048 | "name": "v", 1049 | "type": "uint8" 1050 | }, 1051 | { 1052 | "internalType": "bytes32", 1053 | "name": "r", 1054 | "type": "bytes32" 1055 | }, 1056 | { 1057 | "internalType": "bytes32", 1058 | "name": "s", 1059 | "type": "bytes32" 1060 | } 1061 | ], 1062 | "name": "removeLiquidityWithPermit", 1063 | "outputs": [ 1064 | { 1065 | "internalType": "uint256", 1066 | "name": "amountA", 1067 | "type": "uint256" 1068 | }, 1069 | { 1070 | "internalType": "uint256", 1071 | "name": "amountB", 1072 | "type": "uint256" 1073 | } 1074 | ], 1075 | "payable": false, 1076 | "stateMutability": "nonpayable", 1077 | "type": "function" 1078 | }, 1079 | { 1080 | "constant": false, 1081 | "inputs": [ 1082 | { 1083 | "internalType": "address", 1084 | "name": "token", 1085 | "type": "address" 1086 | }, 1087 | { 1088 | "internalType": "uint256", 1089 | "name": "liquidity", 1090 | "type": "uint256" 1091 | }, 1092 | { 1093 | "internalType": "uint256", 1094 | "name": "amountTokenMin", 1095 | "type": "uint256" 1096 | }, 1097 | { 1098 | "internalType": "uint256", 1099 | "name": "amountETHMin", 1100 | "type": "uint256" 1101 | }, 1102 | { 1103 | "internalType": "address", 1104 | "name": "to", 1105 | "type": "address" 1106 | }, 1107 | { 1108 | "internalType": "uint256", 1109 | "name": "deadline", 1110 | "type": "uint256" 1111 | }, 1112 | { 1113 | "internalType": "bool", 1114 | "name": "approveMax", 1115 | "type": "bool" 1116 | }, 1117 | { 1118 | "internalType": "uint8", 1119 | "name": "v", 1120 | "type": "uint8" 1121 | }, 1122 | { 1123 | "internalType": "bytes32", 1124 | "name": "r", 1125 | "type": "bytes32" 1126 | }, 1127 | { 1128 | "internalType": "bytes32", 1129 | "name": "s", 1130 | "type": "bytes32" 1131 | } 1132 | ], 1133 | "name": "removeLiquidityETHWithPermit", 1134 | "outputs": [ 1135 | { 1136 | "internalType": "uint256", 1137 | "name": "amountToken", 1138 | "type": "uint256" 1139 | }, 1140 | { 1141 | "internalType": "uint256", 1142 | "name": "amountETH", 1143 | "type": "uint256" 1144 | } 1145 | ], 1146 | "payable": false, 1147 | "stateMutability": "nonpayable", 1148 | "type": "function" 1149 | }, 1150 | { 1151 | "constant": false, 1152 | "inputs": [ 1153 | { 1154 | "internalType": "uint256", 1155 | "name": "amountIn", 1156 | "type": "uint256" 1157 | }, 1158 | { 1159 | "internalType": "uint256", 1160 | "name": "amountOutMin", 1161 | "type": "uint256" 1162 | }, 1163 | { 1164 | "internalType": "address[]", 1165 | "name": "path", 1166 | "type": "address[]" 1167 | }, 1168 | { 1169 | "internalType": "address", 1170 | "name": "to", 1171 | "type": "address" 1172 | }, 1173 | { 1174 | "internalType": "uint256", 1175 | "name": "deadline", 1176 | "type": "uint256" 1177 | } 1178 | ], 1179 | "name": "swapExactTokensForTokens", 1180 | "outputs": [ 1181 | { 1182 | "internalType": "uint256[]", 1183 | "name": "amounts", 1184 | "type": "uint256[]" 1185 | } 1186 | ], 1187 | "payable": false, 1188 | "stateMutability": "nonpayable", 1189 | "type": "function" 1190 | }, 1191 | { 1192 | "constant": false, 1193 | "inputs": [ 1194 | { 1195 | "internalType": "uint256", 1196 | "name": "amountOut", 1197 | "type": "uint256" 1198 | }, 1199 | { 1200 | "internalType": "uint256", 1201 | "name": "amountInMax", 1202 | "type": "uint256" 1203 | }, 1204 | { 1205 | "internalType": "address[]", 1206 | "name": "path", 1207 | "type": "address[]" 1208 | }, 1209 | { 1210 | "internalType": "address", 1211 | "name": "to", 1212 | "type": "address" 1213 | }, 1214 | { 1215 | "internalType": "uint256", 1216 | "name": "deadline", 1217 | "type": "uint256" 1218 | } 1219 | ], 1220 | "name": "swapTokensForExactTokens", 1221 | "outputs": [ 1222 | { 1223 | "internalType": "uint256[]", 1224 | "name": "amounts", 1225 | "type": "uint256[]" 1226 | } 1227 | ], 1228 | "payable": false, 1229 | "stateMutability": "nonpayable", 1230 | "type": "function" 1231 | }, 1232 | { 1233 | "constant": false, 1234 | "inputs": [ 1235 | { 1236 | "internalType": "uint256", 1237 | "name": "amountOutMin", 1238 | "type": "uint256" 1239 | }, 1240 | { 1241 | "internalType": "address[]", 1242 | "name": "path", 1243 | "type": "address[]" 1244 | }, 1245 | { 1246 | "internalType": "address", 1247 | "name": "to", 1248 | "type": "address" 1249 | }, 1250 | { 1251 | "internalType": "uint256", 1252 | "name": "deadline", 1253 | "type": "uint256" 1254 | } 1255 | ], 1256 | "name": "swapExactETHForTokens", 1257 | "outputs": [ 1258 | { 1259 | "internalType": "uint256[]", 1260 | "name": "amounts", 1261 | "type": "uint256[]" 1262 | } 1263 | ], 1264 | "payable": true, 1265 | "stateMutability": "payable", 1266 | "type": "function" 1267 | }, 1268 | { 1269 | "constant": false, 1270 | "inputs": [ 1271 | { 1272 | "internalType": "uint256", 1273 | "name": "amountOut", 1274 | "type": "uint256" 1275 | }, 1276 | { 1277 | "internalType": "uint256", 1278 | "name": "amountInMax", 1279 | "type": "uint256" 1280 | }, 1281 | { 1282 | "internalType": "address[]", 1283 | "name": "path", 1284 | "type": "address[]" 1285 | }, 1286 | { 1287 | "internalType": "address", 1288 | "name": "to", 1289 | "type": "address" 1290 | }, 1291 | { 1292 | "internalType": "uint256", 1293 | "name": "deadline", 1294 | "type": "uint256" 1295 | } 1296 | ], 1297 | "name": "swapTokensForExactETH", 1298 | "outputs": [ 1299 | { 1300 | "internalType": "uint256[]", 1301 | "name": "amounts", 1302 | "type": "uint256[]" 1303 | } 1304 | ], 1305 | "payable": false, 1306 | "stateMutability": "nonpayable", 1307 | "type": "function" 1308 | }, 1309 | { 1310 | "constant": false, 1311 | "inputs": [ 1312 | { 1313 | "internalType": "uint256", 1314 | "name": "amountIn", 1315 | "type": "uint256" 1316 | }, 1317 | { 1318 | "internalType": "uint256", 1319 | "name": "amountOutMin", 1320 | "type": "uint256" 1321 | }, 1322 | { 1323 | "internalType": "address[]", 1324 | "name": "path", 1325 | "type": "address[]" 1326 | }, 1327 | { 1328 | "internalType": "address", 1329 | "name": "to", 1330 | "type": "address" 1331 | }, 1332 | { 1333 | "internalType": "uint256", 1334 | "name": "deadline", 1335 | "type": "uint256" 1336 | } 1337 | ], 1338 | "name": "swapExactTokensForETH", 1339 | "outputs": [ 1340 | { 1341 | "internalType": "uint256[]", 1342 | "name": "amounts", 1343 | "type": "uint256[]" 1344 | } 1345 | ], 1346 | "payable": false, 1347 | "stateMutability": "nonpayable", 1348 | "type": "function" 1349 | }, 1350 | { 1351 | "constant": false, 1352 | "inputs": [ 1353 | { 1354 | "internalType": "uint256", 1355 | "name": "amountOut", 1356 | "type": "uint256" 1357 | }, 1358 | { 1359 | "internalType": "address[]", 1360 | "name": "path", 1361 | "type": "address[]" 1362 | }, 1363 | { 1364 | "internalType": "address", 1365 | "name": "to", 1366 | "type": "address" 1367 | }, 1368 | { 1369 | "internalType": "uint256", 1370 | "name": "deadline", 1371 | "type": "uint256" 1372 | } 1373 | ], 1374 | "name": "swapETHForExactTokens", 1375 | "outputs": [ 1376 | { 1377 | "internalType": "uint256[]", 1378 | "name": "amounts", 1379 | "type": "uint256[]" 1380 | } 1381 | ], 1382 | "payable": true, 1383 | "stateMutability": "payable", 1384 | "type": "function" 1385 | } 1386 | ] 1387 | }; 1388 | 1389 | module.exports = {config} 1390 | -------------------------------------------------------------------------------- /contracts/test/WETH9.sol: -------------------------------------------------------------------------------- 1 | /** 2 | *Submitted for verification at Etherscan.io on 2017-12-12 3 | */ 4 | 5 | // Copyright (C) 2015, 2016, 2017 Dapphub 6 | 7 | // This program is free software: you can redistribute it and/or modify 8 | // it under the terms of the GNU General Public License as published by 9 | // the Free Software Foundation, either version 3 of the License, or 10 | // (at your option) any later version. 11 | 12 | // This program is distributed in the hope that it will be useful, 13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | // GNU General Public License for more details. 16 | 17 | // You should have received a copy of the GNU General Public License 18 | // along with this program. If not, see . 19 | 20 | pragma solidity =0.5.16; 21 | 22 | contract WETH9 { 23 | string public name = "Wrapped Ether"; 24 | string public symbol = "WETH"; 25 | uint8 public decimals = 18; 26 | 27 | event Approval(address indexed src, address indexed guy, uint wad); 28 | event Transfer(address indexed src, address indexed dst, uint wad); 29 | event Deposit(address indexed dst, uint wad); 30 | event Withdrawal(address indexed src, uint wad); 31 | 32 | mapping (address => uint) public balanceOf; 33 | mapping (address => mapping (address => uint)) public allowance; 34 | 35 | // function() public payable { 36 | // deposit(); 37 | // } 38 | function deposit() public payable { 39 | balanceOf[msg.sender] += msg.value; 40 | emit Deposit(msg.sender, msg.value); 41 | } 42 | function withdraw(uint wad) public { 43 | require(balanceOf[msg.sender] >= wad, ""); 44 | balanceOf[msg.sender] -= wad; 45 | msg.sender.transfer(wad); 46 | emit Withdrawal(msg.sender, wad); 47 | } 48 | 49 | function totalSupply() public view returns (uint) { 50 | return address(this).balance; 51 | } 52 | 53 | function approve(address guy, uint wad) public returns (bool) { 54 | allowance[msg.sender][guy] = wad; 55 | emit Approval(msg.sender, guy, wad); 56 | return true; 57 | } 58 | 59 | function transfer(address dst, uint wad) public returns (bool) { 60 | return transferFrom(msg.sender, dst, wad); 61 | } 62 | 63 | function transferFrom(address src, address dst, uint wad) 64 | public 65 | returns (bool) 66 | { 67 | require(balanceOf[src] >= wad, ""); 68 | 69 | if (src != msg.sender && allowance[src][msg.sender] != uint(-1)) { 70 | require(allowance[src][msg.sender] >= wad, ""); 71 | allowance[src][msg.sender] -= wad; 72 | } 73 | 74 | balanceOf[src] -= wad; 75 | balanceOf[dst] += wad; 76 | 77 | emit Transfer(src, dst, wad); 78 | 79 | return true; 80 | } 81 | } 82 | 83 | 84 | /* 85 | GNU GENERAL PUBLIC LICENSE 86 | Version 3, 29 June 2007 87 | 88 | Copyright (C) 2007 Free Software Foundation, Inc. 89 | Everyone is permitted to copy and distribute verbatim copies 90 | of this license document, but changing it is not allowed. 91 | 92 | Preamble 93 | 94 | The GNU General Public License is a free, copyleft license for 95 | software and other kinds of works. 96 | 97 | The licenses for most software and other practical works are designed 98 | to take away your freedom to share and change the works. By contrast, 99 | the GNU General Public License is intended to guarantee your freedom to 100 | share and change all versions of a program--to make sure it remains free 101 | software for all its users. We, the Free Software Foundation, use the 102 | GNU General Public License for most of our software; it applies also to 103 | any other work released this way by its authors. You can apply it to 104 | your programs, too. 105 | 106 | When we speak of free software, we are referring to freedom, not 107 | price. Our General Public Licenses are designed to make sure that you 108 | have the freedom to distribute copies of free software (and charge for 109 | them if you wish), that you receive source code or can get it if you 110 | want it, that you can change the software or use pieces of it in new 111 | free programs, and that you know you can do these things. 112 | 113 | To protect your rights, we need to prevent others from denying you 114 | these rights or asking you to surrender the rights. Therefore, you have 115 | certain responsibilities if you distribute copies of the software, or if 116 | you modify it: responsibilities to respect the freedom of others. 117 | 118 | For example, if you distribute copies of such a program, whether 119 | gratis or for a fee, you must pass on to the recipients the same 120 | freedoms that you received. You must make sure that they, too, receive 121 | or can get the source code. And you must show them these terms so they 122 | know their rights. 123 | 124 | Developers that use the GNU GPL protect your rights with two steps: 125 | (1) assert copyright on the software, and (2) offer you this License 126 | giving you legal permission to copy, distribute and/or modify it. 127 | 128 | For the developers' and authors' protection, the GPL clearly explains 129 | that there is no warranty for this free software. For both users' and 130 | authors' sake, the GPL requires that modified versions be marked as 131 | changed, so that their problems will not be attributed erroneously to 132 | authors of previous versions. 133 | 134 | Some devices are designed to deny users access to install or run 135 | modified versions of the software inside them, although the manufacturer 136 | can do so. This is fundamentally incompatible with the aim of 137 | protecting users' freedom to change the software. The systematic 138 | pattern of such abuse occurs in the area of products for individuals to 139 | use, which is precisely where it is most unacceptable. Therefore, we 140 | have designed this version of the GPL to prohibit the practice for those 141 | products. If such problems arise substantially in other domains, we 142 | stand ready to extend this provision to those domains in future versions 143 | of the GPL, as needed to protect the freedom of users. 144 | 145 | Finally, every program is threatened constantly by software patents. 146 | States should not allow patents to restrict development and use of 147 | software on general-purpose computers, but in those that do, we wish to 148 | avoid the special danger that patents applied to a free program could 149 | make it effectively proprietary. To prevent this, the GPL assures that 150 | patents cannot be used to render the program non-free. 151 | 152 | The precise terms and conditions for copying, distribution and 153 | modification follow. 154 | 155 | TERMS AND CONDITIONS 156 | 157 | 0. Definitions. 158 | 159 | "This License" refers to version 3 of the GNU General Public License. 160 | 161 | "Copyright" also means copyright-like laws that apply to other kinds of 162 | works, such as semiconductor masks. 163 | 164 | "The Program" refers to any copyrightable work licensed under this 165 | License. Each licensee is addressed as "you". "Licensees" and 166 | "recipients" may be individuals or organizations. 167 | 168 | To "modify" a work means to copy from or adapt all or part of the work 169 | in a fashion requiring copyright permission, other than the making of an 170 | exact copy. The resulting work is called a "modified version" of the 171 | earlier work or a work "based on" the earlier work. 172 | 173 | A "covered work" means either the unmodified Program or a work based 174 | on the Program. 175 | 176 | To "propagate" a work means to do anything with it that, without 177 | permission, would make you directly or secondarily liable for 178 | infringement under applicable copyright law, except executing it on a 179 | computer or modifying a private copy. Propagation includes copying, 180 | distribution (with or without modification), making available to the 181 | public, and in some countries other activities as well. 182 | 183 | To "convey" a work means any kind of propagation that enables other 184 | parties to make or receive copies. Mere interaction with a user through 185 | a computer network, with no transfer of a copy, is not conveying. 186 | 187 | An interactive user interface displays "Appropriate Legal Notices" 188 | to the extent that it includes a convenient and prominently visible 189 | feature that (1) displays an appropriate copyright notice, and (2) 190 | tells the user that there is no warranty for the work (except to the 191 | extent that warranties are provided), that licensees may convey the 192 | work under this License, and how to view a copy of this License. If 193 | the interface presents a list of user commands or options, such as a 194 | menu, a prominent item in the list meets this criterion. 195 | 196 | 1. Source Code. 197 | 198 | The "source code" for a work means the preferred form of the work 199 | for making modifications to it. "Object code" means any non-source 200 | form of a work. 201 | 202 | A "Standard Interface" means an interface that either is an official 203 | standard defined by a recognized standards body, or, in the case of 204 | interfaces specified for a particular programming language, one that 205 | is widely used among developers working in that language. 206 | 207 | The "System Libraries" of an executable work include anything, other 208 | than the work as a whole, that (a) is included in the normal form of 209 | packaging a Major Component, but which is not part of that Major 210 | Component, and (b) serves only to enable use of the work with that 211 | Major Component, or to implement a Standard Interface for which an 212 | implementation is available to the public in source code form. A 213 | "Major Component", in this context, means a major essential component 214 | (kernel, window system, and so on) of the specific operating system 215 | (if any) on which the executable work runs, or a compiler used to 216 | produce the work, or an object code interpreter used to run it. 217 | 218 | The "Corresponding Source" for a work in object code form means all 219 | the source code needed to generate, install, and (for an executable 220 | work) run the object code and to modify the work, including scripts to 221 | control those activities. However, it does not include the work's 222 | System Libraries, or general-purpose tools or generally available free 223 | programs which are used unmodified in performing those activities but 224 | which are not part of the work. For example, Corresponding Source 225 | includes interface definition files associated with source files for 226 | the work, and the source code for shared libraries and dynamically 227 | linked subprograms that the work is specifically designed to require, 228 | such as by intimate data communication or control flow between those 229 | subprograms and other parts of the work. 230 | 231 | The Corresponding Source need not include anything that users 232 | can regenerate automatically from other parts of the Corresponding 233 | Source. 234 | 235 | The Corresponding Source for a work in source code form is that 236 | same work. 237 | 238 | 2. Basic Permissions. 239 | 240 | All rights granted under this License are granted for the term of 241 | copyright on the Program, and are irrevocable provided the stated 242 | conditions are met. This License explicitly affirms your unlimited 243 | permission to run the unmodified Program. The output from running a 244 | covered work is covered by this License only if the output, given its 245 | content, constitutes a covered work. This License acknowledges your 246 | rights of fair use or other equivalent, as provided by copyright law. 247 | 248 | You may make, run and propagate covered works that you do not 249 | convey, without conditions so long as your license otherwise remains 250 | in force. You may convey covered works to others for the sole purpose 251 | of having them make modifications exclusively for you, or provide you 252 | with facilities for running those works, provided that you comply with 253 | the terms of this License in conveying all material for which you do 254 | not control copyright. Those thus making or running the covered works 255 | for you must do so exclusively on your behalf, under your direction 256 | and control, on terms that prohibit them from making any copies of 257 | your copyrighted material outside their relationship with you. 258 | 259 | Conveying under any other circumstances is permitted solely under 260 | the conditions stated below. Sublicensing is not allowed; section 10 261 | makes it unnecessary. 262 | 263 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 264 | 265 | No covered work shall be deemed part of an effective technological 266 | measure under any applicable law fulfilling obligations under article 267 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 268 | similar laws prohibiting or restricting circumvention of such 269 | measures. 270 | 271 | When you convey a covered work, you waive any legal power to forbid 272 | circumvention of technological measures to the extent such circumvention 273 | is effected by exercising rights under this License with respect to 274 | the covered work, and you disclaim any intention to limit operation or 275 | modification of the work as a means of enforcing, against the work's 276 | users, your or third parties' legal rights to forbid circumvention of 277 | technological measures. 278 | 279 | 4. Conveying Verbatim Copies. 280 | 281 | You may convey verbatim copies of the Program's source code as you 282 | receive it, in any medium, provided that you conspicuously and 283 | appropriately publish on each copy an appropriate copyright notice; 284 | keep intact all notices stating that this License and any 285 | non-permissive terms added in accord with section 7 apply to the code; 286 | keep intact all notices of the absence of any warranty; and give all 287 | recipients a copy of this License along with the Program. 288 | 289 | You may charge any price or no price for each copy that you convey, 290 | and you may offer support or warranty protection for a fee. 291 | 292 | 5. Conveying Modified Source Versions. 293 | 294 | You may convey a work based on the Program, or the modifications to 295 | produce it from the Program, in the form of source code under the 296 | terms of section 4, provided that you also meet all of these conditions: 297 | 298 | a) The work must carry prominent notices stating that you modified 299 | it, and giving a relevant date. 300 | 301 | b) The work must carry prominent notices stating that it is 302 | released under this License and any conditions added under section 303 | 7. This requirement modifies the requirement in section 4 to 304 | "keep intact all notices". 305 | 306 | c) You must license the entire work, as a whole, under this 307 | License to anyone who comes into possession of a copy. This 308 | License will therefore apply, along with any applicable section 7 309 | additional terms, to the whole of the work, and all its parts, 310 | regardless of how they are packaged. This License gives no 311 | permission to license the work in any other way, but it does not 312 | invalidate such permission if you have separately received it. 313 | 314 | d) If the work has interactive user interfaces, each must display 315 | Appropriate Legal Notices; however, if the Program has interactive 316 | interfaces that do not display Appropriate Legal Notices, your 317 | work need not make them do so. 318 | 319 | A compilation of a covered work with other separate and independent 320 | works, which are not by their nature extensions of the covered work, 321 | and which are not combined with it such as to form a larger program, 322 | in or on a volume of a storage or distribution medium, is called an 323 | "aggregate" if the compilation and its resulting copyright are not 324 | used to limit the access or legal rights of the compilation's users 325 | beyond what the individual works permit. Inclusion of a covered work 326 | in an aggregate does not cause this License to apply to the other 327 | parts of the aggregate. 328 | 329 | 6. Conveying Non-Source Forms. 330 | 331 | You may convey a covered work in object code form under the terms 332 | of sections 4 and 5, provided that you also convey the 333 | machine-readable Corresponding Source under the terms of this License, 334 | in one of these ways: 335 | 336 | a) Convey the object code in, or embodied in, a physical product 337 | (including a physical distribution medium), accompanied by the 338 | Corresponding Source fixed on a durable physical medium 339 | customarily used for software interchange. 340 | 341 | b) Convey the object code in, or embodied in, a physical product 342 | (including a physical distribution medium), accompanied by a 343 | written offer, valid for at least three years and valid for as 344 | long as you offer spare parts or customer support for that product 345 | model, to give anyone who possesses the object code either (1) a 346 | copy of the Corresponding Source for all the software in the 347 | product that is covered by this License, on a durable physical 348 | medium customarily used for software interchange, for a price no 349 | more than your reasonable cost of physically performing this 350 | conveying of source, or (2) access to copy the 351 | Corresponding Source from a network server at no charge. 352 | 353 | c) Convey individual copies of the object code with a copy of the 354 | written offer to provide the Corresponding Source. This 355 | alternative is allowed only occasionally and noncommercially, and 356 | only if you received the object code with such an offer, in accord 357 | with subsection 6b. 358 | 359 | d) Convey the object code by offering access from a designated 360 | place (gratis or for a charge), and offer equivalent access to the 361 | Corresponding Source in the same way through the same place at no 362 | further charge. You need not require recipients to copy the 363 | Corresponding Source along with the object code. If the place to 364 | copy the object code is a network server, the Corresponding Source 365 | may be on a different server (operated by you or a third party) 366 | that supports equivalent copying facilities, provided you maintain 367 | clear directions next to the object code saying where to find the 368 | Corresponding Source. Regardless of what server hosts the 369 | Corresponding Source, you remain obligated to ensure that it is 370 | available for as long as needed to satisfy these requirements. 371 | 372 | e) Convey the object code using peer-to-peer transmission, provided 373 | you inform other peers where the object code and Corresponding 374 | Source of the work are being offered to the general public at no 375 | charge under subsection 6d. 376 | 377 | A separable portion of the object code, whose source code is excluded 378 | from the Corresponding Source as a System Library, need not be 379 | included in conveying the object code work. 380 | 381 | A "User Product" is either (1) a "consumer product", which means any 382 | tangible personal property which is normally used for personal, family, 383 | or household purposes, or (2) anything designed or sold for incorporation 384 | into a dwelling. In determining whether a product is a consumer product, 385 | doubtful cases shall be resolved in favor of coverage. For a particular 386 | product received by a particular user, "normally used" refers to a 387 | typical or common use of that class of product, regardless of the status 388 | of the particular user or of the way in which the particular user 389 | actually uses, or expects or is expected to use, the product. A product 390 | is a consumer product regardless of whether the product has substantial 391 | commercial, industrial or non-consumer uses, unless such uses represent 392 | the only significant mode of use of the product. 393 | 394 | "Installation Information" for a User Product means any methods, 395 | procedures, authorization keys, or other information required to install 396 | and execute modified versions of a covered work in that User Product from 397 | a modified version of its Corresponding Source. The information must 398 | suffice to ensure that the continued functioning of the modified object 399 | code is in no case prevented or interfered with solely because 400 | modification has been made. 401 | 402 | If you convey an object code work under this section in, or with, or 403 | specifically for use in, a User Product, and the conveying occurs as 404 | part of a transaction in which the right of possession and use of the 405 | User Product is transferred to the recipient in perpetuity or for a 406 | fixed term (regardless of how the transaction is characterized), the 407 | Corresponding Source conveyed under this section must be accompanied 408 | by the Installation Information. But this requirement does not apply 409 | if neither you nor any third party retains the ability to install 410 | modified object code on the User Product (for example, the work has 411 | been installed in ROM). 412 | 413 | The requirement to provide Installation Information does not include a 414 | requirement to continue to provide support service, warranty, or updates 415 | for a work that has been modified or installed by the recipient, or for 416 | the User Product in which it has been modified or installed. Access to a 417 | network may be denied when the modification itself materially and 418 | adversely affects the operation of the network or violates the rules and 419 | protocols for communication across the network. 420 | 421 | Corresponding Source conveyed, and Installation Information provided, 422 | in accord with this section must be in a format that is publicly 423 | documented (and with an implementation available to the public in 424 | source code form), and must require no special password or key for 425 | unpacking, reading or copying. 426 | 427 | 7. Additional Terms. 428 | 429 | "Additional permissions" are terms that supplement the terms of this 430 | License by making exceptions from one or more of its conditions. 431 | Additional permissions that are applicable to the entire Program shall 432 | be treated as though they were included in this License, to the extent 433 | that they are valid under applicable law. If additional permissions 434 | apply only to part of the Program, that part may be used separately 435 | under those permissions, but the entire Program remains governed by 436 | this License without regard to the additional permissions. 437 | 438 | When you convey a copy of a covered work, you may at your option 439 | remove any additional permissions from that copy, or from any part of 440 | it. (Additional permissions may be written to require their own 441 | removal in certain cases when you modify the work.) You may place 442 | additional permissions on material, added by you to a covered work, 443 | for which you have or can give appropriate copyright permission. 444 | 445 | Notwithstanding any other provision of this License, for material you 446 | add to a covered work, you may (if authorized by the copyright holders of 447 | that material) supplement the terms of this License with terms: 448 | 449 | a) Disclaiming warranty or limiting liability differently from the 450 | terms of sections 15 and 16 of this License; or 451 | 452 | b) Requiring preservation of specified reasonable legal notices or 453 | author attributions in that material or in the Appropriate Legal 454 | Notices displayed by works containing it; or 455 | 456 | c) Prohibiting misrepresentation of the origin of that material, or 457 | requiring that modified versions of such material be marked in 458 | reasonable ways as different from the original version; or 459 | 460 | d) Limiting the use for publicity purposes of names of licensors or 461 | authors of the material; or 462 | 463 | e) Declining to grant rights under trademark law for use of some 464 | trade names, trademarks, or service marks; or 465 | 466 | f) Requiring indemnification of licensors and authors of that 467 | material by anyone who conveys the material (or modified versions of 468 | it) with contractual assumptions of liability to the recipient, for 469 | any liability that these contractual assumptions directly impose on 470 | those licensors and authors. 471 | 472 | All other non-permissive additional terms are considered "further 473 | restrictions" within the meaning of section 10. If the Program as you 474 | received it, or any part of it, contains a notice stating that it is 475 | governed by this License along with a term that is a further 476 | restriction, you may remove that term. If a license document contains 477 | a further restriction but permits relicensing or conveying under this 478 | License, you may add to a covered work material governed by the terms 479 | of that license document, provided that the further restriction does 480 | not survive such relicensing or conveying. 481 | 482 | If you add terms to a covered work in accord with this section, you 483 | must place, in the relevant source files, a statement of the 484 | additional terms that apply to those files, or a notice indicating 485 | where to find the applicable terms. 486 | 487 | Additional terms, permissive or non-permissive, may be stated in the 488 | form of a separately written license, or stated as exceptions; 489 | the above requirements apply either way. 490 | 491 | 8. Termination. 492 | 493 | You may not propagate or modify a covered work except as expressly 494 | provided under this License. Any attempt otherwise to propagate or 495 | modify it is void, and will automatically terminate your rights under 496 | this License (including any patent licenses granted under the third 497 | paragraph of section 11). 498 | 499 | However, if you cease all violation of this License, then your 500 | license from a particular copyright holder is reinstated (a) 501 | provisionally, unless and until the copyright holder explicitly and 502 | finally terminates your license, and (b) permanently, if the copyright 503 | holder fails to notify you of the violation by some reasonable means 504 | prior to 60 days after the cessation. 505 | 506 | Moreover, your license from a particular copyright holder is 507 | reinstated permanently if the copyright holder notifies you of the 508 | violation by some reasonable means, this is the first time you have 509 | received notice of violation of this License (for any work) from that 510 | copyright holder, and you cure the violation prior to 30 days after 511 | your receipt of the notice. 512 | 513 | Termination of your rights under this section does not terminate the 514 | licenses of parties who have received copies or rights from you under 515 | this License. If your rights have been terminated and not permanently 516 | reinstated, you do not qualify to receive new licenses for the same 517 | material under section 10. 518 | 519 | 9. Acceptance Not Required for Having Copies. 520 | 521 | You are not required to accept this License in order to receive or 522 | run a copy of the Program. Ancillary propagation of a covered work 523 | occurring solely as a consequence of using peer-to-peer transmission 524 | to receive a copy likewise does not require acceptance. However, 525 | nothing other than this License grants you permission to propagate or 526 | modify any covered work. These actions infringe copyright if you do 527 | not accept this License. Therefore, by modifying or propagating a 528 | covered work, you indicate your acceptance of this License to do so. 529 | 530 | 10. Automatic Licensing of Downstream Recipients. 531 | 532 | Each time you convey a covered work, the recipient automatically 533 | receives a license from the original licensors, to run, modify and 534 | propagate that work, subject to this License. You are not responsible 535 | for enforcing compliance by third parties with this License. 536 | 537 | An "entity transaction" is a transaction transferring control of an 538 | organization, or substantially all assets of one, or subdividing an 539 | organization, or merging organizations. If propagation of a covered 540 | work results from an entity transaction, each party to that 541 | transaction who receives a copy of the work also receives whatever 542 | licenses to the work the party's predecessor in interest had or could 543 | give under the previous paragraph, plus a right to possession of the 544 | Corresponding Source of the work from the predecessor in interest, if 545 | the predecessor has it or can get it with reasonable efforts. 546 | 547 | You may not impose any further restrictions on the exercise of the 548 | rights granted or affirmed under this License. For example, you may 549 | not impose a license fee, royalty, or other charge for exercise of 550 | rights granted under this License, and you may not initiate litigation 551 | (including a cross-claim or counterclaim in a lawsuit) alleging that 552 | any patent claim is infringed by making, using, selling, offering for 553 | sale, or importing the Program or any portion of it. 554 | 555 | 11. Patents. 556 | 557 | A "contributor" is a copyright holder who authorizes use under this 558 | License of the Program or a work on which the Program is based. The 559 | work thus licensed is called the contributor's "contributor version". 560 | 561 | A contributor's "essential patent claims" are all patent claims 562 | owned or controlled by the contributor, whether already acquired or 563 | hereafter acquired, that would be infringed by some manner, permitted 564 | by this License, of making, using, or selling its contributor version, 565 | but do not include claims that would be infringed only as a 566 | consequence of further modification of the contributor version. For 567 | purposes of this definition, "control" includes the right to grant 568 | patent sublicenses in a manner consistent with the requirements of 569 | this License. 570 | 571 | Each contributor grants you a non-exclusive, worldwide, royalty-free 572 | patent license under the contributor's essential patent claims, to 573 | make, use, sell, offer for sale, import and otherwise run, modify and 574 | propagate the contents of its contributor version. 575 | 576 | In the following three paragraphs, a "patent license" is any express 577 | agreement or commitment, however denominated, not to enforce a patent 578 | (such as an express permission to practice a patent or covenant not to 579 | sue for patent infringement). To "grant" such a patent license to a 580 | party means to make such an agreement or commitment not to enforce a 581 | patent against the party. 582 | 583 | If you convey a covered work, knowingly relying on a patent license, 584 | and the Corresponding Source of the work is not available for anyone 585 | to copy, free of charge and under the terms of this License, through a 586 | publicly available network server or other readily accessible means, 587 | then you must either (1) cause the Corresponding Source to be so 588 | available, or (2) arrange to deprive yourself of the benefit of the 589 | patent license for this particular work, or (3) arrange, in a manner 590 | consistent with the requirements of this License, to extend the patent 591 | license to downstream recipients. "Knowingly relying" means you have 592 | actual knowledge that, but for the patent license, your conveying the 593 | covered work in a country, or your recipient's use of the covered work 594 | in a country, would infringe one or more identifiable patents in that 595 | country that you have reason to believe are valid. 596 | 597 | If, pursuant to or in connection with a single transaction or 598 | arrangement, you convey, or propagate by procuring conveyance of, a 599 | covered work, and grant a patent license to some of the parties 600 | receiving the covered work authorizing them to use, propagate, modify 601 | or convey a specific copy of the covered work, then the patent license 602 | you grant is automatically extended to all recipients of the covered 603 | work and works based on it. 604 | 605 | A patent license is "discriminatory" if it does not include within 606 | the scope of its coverage, prohibits the exercise of, or is 607 | conditioned on the non-exercise of one or more of the rights that are 608 | specifically granted under this License. You may not convey a covered 609 | work if you are a party to an arrangement with a third party that is 610 | in the business of distributing software, under which you make payment 611 | to the third party based on the extent of your activity of conveying 612 | the work, and under which the third party grants, to any of the 613 | parties who would receive the covered work from you, a discriminatory 614 | patent license (a) in connection with copies of the covered work 615 | conveyed by you (or copies made from those copies), or (b) primarily 616 | for and in connection with specific products or compilations that 617 | contain the covered work, unless you entered into that arrangement, 618 | or that patent license was granted, prior to 28 March 2007. 619 | 620 | Nothing in this License shall be construed as excluding or limiting 621 | any implied license or other defenses to infringement that may 622 | otherwise be available to you under applicable patent law. 623 | 624 | 12. No Surrender of Others' Freedom. 625 | 626 | If conditions are imposed on you (whether by court order, agreement or 627 | otherwise) that contradict the conditions of this License, they do not 628 | excuse you from the conditions of this License. If you cannot convey a 629 | covered work so as to satisfy simultaneously your obligations under this 630 | License and any other pertinent obligations, then as a consequence you may 631 | not convey it at all. For example, if you agree to terms that obligate you 632 | to collect a royalty for further conveying from those to whom you convey 633 | the Program, the only way you could satisfy both those terms and this 634 | License would be to refrain entirely from conveying the Program. 635 | 636 | 13. Use with the GNU Affero General Public License. 637 | 638 | Notwithstanding any other provision of this License, you have 639 | permission to link or combine any covered work with a work licensed 640 | under version 3 of the GNU Affero General Public License into a single 641 | combined work, and to convey the resulting work. The terms of this 642 | License will continue to apply to the part which is the covered work, 643 | but the special requirements of the GNU Affero General Public License, 644 | section 13, concerning interaction through a network will apply to the 645 | combination as such. 646 | 647 | 14. Revised Versions of this License. 648 | 649 | The Free Software Foundation may publish revised and/or new versions of 650 | the GNU General Public License from time to time. Such new versions will 651 | be similar in spirit to the present version, but may differ in detail to 652 | address new problems or concerns. 653 | 654 | Each version is given a distinguishing version number. If the 655 | Program specifies that a certain numbered version of the GNU General 656 | Public License "or any later version" applies to it, you have the 657 | option of following the terms and conditions either of that numbered 658 | version or of any later version published by the Free Software 659 | Foundation. If the Program does not specify a version number of the 660 | GNU General Public License, you may choose any version ever published 661 | by the Free Software Foundation. 662 | 663 | If the Program specifies that a proxy can decide which future 664 | versions of the GNU General Public License can be used, that proxy's 665 | public statement of acceptance of a version permanently authorizes you 666 | to choose that version for the Program. 667 | 668 | Later license versions may give you additional or different 669 | permissions. However, no additional obligations are imposed on any 670 | author or copyright holder as a result of your choosing to follow a 671 | later version. 672 | 673 | 15. Disclaimer of Warranty. 674 | 675 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 676 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 677 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 678 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 679 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 680 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 681 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 682 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 683 | 684 | 16. Limitation of Liability. 685 | 686 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 687 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 688 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 689 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 690 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 691 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 692 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 693 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 694 | SUCH DAMAGES. 695 | 696 | 17. Interpretation of Sections 15 and 16. 697 | 698 | If the disclaimer of warranty and limitation of liability provided 699 | above cannot be given local legal effect according to their terms, 700 | reviewing courts shall apply local law that most closely approximates 701 | an absolute waiver of all civil liability in connection with the 702 | Program, unless a warranty or assumption of liability accompanies a 703 | copy of the Program in return for a fee. 704 | 705 | END OF TERMS AND CONDITIONS 706 | 707 | How to Apply These Terms to Your New Programs 708 | 709 | If you develop a new program, and you want it to be of the greatest 710 | possible use to the public, the best way to achieve this is to make it 711 | free software which everyone can redistribute and change under these terms. 712 | 713 | To do so, attach the following notices to the program. It is safest 714 | to attach them to the start of each source file to most effectively 715 | state the exclusion of warranty; and each file should have at least 716 | the "copyright" line and a pointer to where the full notice is found. 717 | 718 | 719 | Copyright (C) 720 | 721 | This program is free software: you can redistribute it and/or modify 722 | it under the terms of the GNU General Public License as published by 723 | the Free Software Foundation, either version 3 of the License, or 724 | (at your option) any later version. 725 | 726 | This program is distributed in the hope that it will be useful, 727 | but WITHOUT ANY WARRANTY; without even the implied warranty of 728 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 729 | GNU General Public License for more details. 730 | 731 | You should have received a copy of the GNU General Public License 732 | along with this program. If not, see . 733 | 734 | Also add information on how to contact you by electronic and paper mail. 735 | 736 | If the program does terminal interaction, make it output a short 737 | notice like this when it starts in an interactive mode: 738 | 739 | Copyright (C) 740 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 741 | This is free software, and you are welcome to redistribute it 742 | under certain conditions; type `show c' for details. 743 | 744 | The hypothetical commands `show w' and `show c' should show the appropriate 745 | parts of the General Public License. Of course, your program's commands 746 | might be different; for a GUI interface, you would use an "about box". 747 | 748 | You should also get your employer (if you work as a programmer) or school, 749 | if any, to sign a "copyright disclaimer" for the program, if necessary. 750 | For more information on this, and how to apply and follow the GNU GPL, see 751 | . 752 | 753 | The GNU General Public License does not permit incorporating your program 754 | into proprietary programs. If your program is a subroutine library, you 755 | may consider it more useful to permit linking proprietary applications with 756 | the library. If this is what you want to do, use the GNU Lesser General 757 | Public License instead of this License. But first, please read 758 | . 759 | 760 | */ --------------------------------------------------------------------------------