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 |
90 |
92 |
93 |
94 |
ADD LIQUIDITY
95 |
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 | */
--------------------------------------------------------------------------------