├── .env
├── .gitattributes
├── .gitignore
├── LICENSE
├── README.md
├── brownie-config.yaml
├── build
└── interfaces
│ ├── IERC20.json
│ ├── IQuoter.json
│ ├── ISwapRouter.json
│ ├── IUniswapV2Router01.json
│ └── IUniswapV2Router02.json
├── front-end
├── README.md
├── package-lock.json
├── package.json
├── public
│ ├── favicon.ico
│ ├── index.html
│ ├── logo192.png
│ ├── logo512.png
│ ├── manifest.json
│ └── robots.txt
├── src
│ ├── App.css
│ ├── App.js
│ ├── App.test.js
│ ├── artifacts
│ │ └── interfaces
│ │ │ ├── IERC20.json
│ │ │ ├── IQuoter.json
│ │ │ ├── ISwapRouter.json
│ │ │ ├── IUniswapV2Router01.json
│ │ │ └── IUniswapV2Router02.json
│ ├── assets
│ │ ├── css
│ │ │ └── styles.css
│ │ └── images
│ │ │ ├── aave.png
│ │ │ ├── bnb.png
│ │ │ ├── crv.png
│ │ │ ├── dai.png
│ │ │ ├── etherLogo.png
│ │ │ ├── link.png
│ │ │ ├── matic.png
│ │ │ ├── uni.jpg
│ │ │ ├── usdc.png
│ │ │ └── usdt.png
│ ├── components
│ │ ├── Account.js
│ │ ├── Exchanges.js
│ │ ├── Main.js
│ │ ├── NavBar.js
│ │ ├── NavbarElements.js
│ │ └── Swap.js
│ ├── dapp-logo.png
│ ├── features
│ │ └── blockchain.js
│ ├── index.css
│ ├── index.js
│ ├── reportWebVitals.js
│ ├── setupTests.js
│ └── utils
│ │ ├── helpers.js
│ │ └── networksMap.json
└── yarn.lock
├── interfaces
├── IERC20.sol
├── IQouter.sol
├── ISwapRouter.sol
└── IUniswapV2Router02.sol
└── scripts
├── get_prices.py
├── get_weth.py
├── helper_scripts.py
└── update_front_end.py
/.env:
--------------------------------------------------------------------------------
1 | PRIVATE_KEY=<< YOUR PRIVATE KEY >>
2 | WEB3_INFURA_PROJECT_ID=<< YOUR INFURA PROJECT ID >>
3 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.sol linguist-language=Solidity
2 | *.vy linguist-language=Python
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | __pycache__
2 | .env
3 | .history
4 | .hypothesis/
5 | build/
6 | reports/
7 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Aymen
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ## Dex-aggregator
5 |
6 | With the ever growing DEFI world and the appearance of multiple decentralized exchanges on the different blockchains, the WEB3 ecosystem needs a way to compare the pros & cons of swapping on each DEX.
7 |
8 | This excatly what Paraswap & 1inch protocol are trying to do, they aggregate the prices of tokens from multiple exchanges in each Blockchain (for example: uniswap, sushiswap, shibaswap in the Ethereum Mainnet), then they compare those prices and the swapping fee and offer to their user the best exchange rate possible.
9 |
10 | In this Dapp, i built a simplified version of Paraswap it works on 4 blockchains: Ethereum, Polygon, Binance Smart Chain and the kovan testnet.For the moment it supports some well known tokens (ETH, Matic, Dai, USDC,...).
11 |
12 |
13 |
14 |
15 |
16 | ### Built With
17 |
18 | * [Solidity](https://docs.soliditylang.org/)
19 | * [Brownie](https://eth-brownie.readthedocs.io)
20 | * [React.js](https://reactjs.org/)
21 | * [ethers.js](https://docs.ethers.io/v5/)
22 | * [web3modal](https://github.com/Web3Modal/web3modal)
23 | * [material ui](https://mui.com/getting-started/installation/)
24 |
25 |
26 |
27 | ## Getting Started
28 |
29 | ### Prerequisites
30 |
31 | Please install or have installed the following:
32 | * [nodejs and npm](https://nodejs.org/en/download/)
33 | * [python](https://www.python.org/downloads/)
34 | * [MetaMask](https://chrome.google.com/webstore/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn) Chrome extension installed in your browser
35 |
36 | ### Installation
37 |
38 | 1. Installing Brownie: Brownie is a python framework for smart contracts development,testing and deployments. It's quit like [HardHat](https://hardhat.org) but it uses python for writing test and deployements scripts instead of javascript.
39 | Here is a simple way to install brownie.
40 | ```
41 | pip install --user pipx
42 | pipx ensurepath
43 | # restart your terminal
44 | pipx install eth-brownie
45 | ```
46 | Or if you can't get pipx to work, via pip (it's recommended to use pipx)
47 | ```sh
48 | pip install eth-brownie
49 | ```
50 | Install [ganache-cli](https://www.npmjs.com/package/ganache-cli):
51 | ```sh
52 | npm install -g ganache-cli
53 | ```
54 | 2. Clone the repo:
55 | ```sh
56 | git clone https://github.com/kaymen99/Dex-aggregator.git
57 | cd Dex-aggregator
58 | ```
59 |
60 | 3. Set your environment variables
61 | To be able to deploy to real testnets you need to add your PRIVATE_KEY (You can find your PRIVATE_KEY from your ethereum wallet like metamask) and the infura project Id (just create an infura account it's free) to the .env file:
62 | ```
63 | PRIVATE_KEY=
64 | WEB3_INFURA_PROJECT_ID=<< YOUR INFURA PROJECT ID >>
65 | ```
66 | You can choose to use ethereum testnets like rinkeby, Kovan or any other evm compatible testnet.
67 | You'll also need some eth in the testnet. You can get it into your wallet by using a public faucet.
68 |
69 |
70 | (back to top )
71 |
72 |
73 |
74 | ## How to Use
75 | After going throught the installation part you can start the app by running:
76 | ```sh
77 | cd front-end
78 | yarn
79 | yarn start
80 | ```
81 | The front-end is built using the following libraries:
82 |
83 | Ethers.js: used as interface between the UI and the deployed smart contract
84 | Web3modal: for conecting to Metamask
85 | @reduxjs/toolkit & redux-persist: for managing the app states (account, balance, blockchain)
86 | Material UI: used for react components and styles
87 |
88 | There are 2 main components:
89 |
90 | Swap component: It finds the best price possible for the user tokens from the supported exchanges and allow user to approve & excute the swap transaction
91 | Exchanges component: For getting the token prices on the different exchanges
92 |
93 |
94 | (back to top )
95 |
96 |
97 |
98 | ## Contact
99 |
100 | If you have any question or problem running this project just contact me: aymenMir1001@gmail.com
101 |
102 | (back to top )
103 |
104 |
105 |
106 | ## License
107 |
108 | Distributed under the MIT License. See `LICENSE.txt` for more information.
109 |
110 | (back to top )
111 |
112 |
113 |
--------------------------------------------------------------------------------
/brownie-config.yaml:
--------------------------------------------------------------------------------
1 | dotenv: .env
2 |
3 | wallets:
4 | from_key: ${PRIVATE_KEY}
5 |
6 | dependencies:
7 | - OpenZeppelin/openzeppelin-contracts@3.4.0
8 | - Uniswap/v3-core@1.0.0
9 |
10 | compiler:
11 | solc:
12 | remappings:
13 | - "@openzeppelin=OpenZeppelin/openzeppelin-contracts@3.4.0"
14 | - "@uniswap=Uniswap/v3-core@1.0.0"
15 |
16 | networks:
17 | mainnet-fork:
18 | uniswap-router: "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D"
19 | uniswapV3-router: "0xE592427A0AEce92De3Edee1F18E0157C05861564"
20 | uniswapV3-qouter: "0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6"
21 | sushiswap-router: "0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F"
22 | shibaswap-router: "0x03f7724180AA6b939894B5Ca4314783B0b36b329"
23 | weth-token: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
24 | dai-token: "0x6b175474e89094c44da98b954eedeac495271d0f"
25 | kovan:
26 | uniswap-router: "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D"
27 | uniswapV3-router: "0xE592427A0AEce92De3Edee1F18E0157C05861564"
28 | uniswapV3-qouter: "0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6"
29 | sushiswap-router: "0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F"
30 | weth-token: "0xd0a1e359811322d97991e03f863a0c30c2cf029c"
31 | dai-token: "0xFf795577d9AC8bD7D90Ee22b6C1703490b6512FD"
32 |
33 | polygone-mainnet-dev:
34 | uniswapV3-router: "0xE592427A0AEce92De3Edee1F18E0157C05861564"
35 | uniswapV3-qouter: "0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6"
36 | quickswap-router: "0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff"
37 | sushiswap-router: "0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506"
38 | jetswap-router: "0x5C6EC38fb0e2609672BDf628B1fD605A523E5923"
39 | weth-token: "0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619"
40 | dai-token: "0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063"
41 |
--------------------------------------------------------------------------------
/build/interfaces/IERC20.json:
--------------------------------------------------------------------------------
1 | {
2 | "abi": [
3 | {
4 | "anonymous": false,
5 | "inputs": [
6 | {
7 | "indexed": true,
8 | "internalType": "address",
9 | "name": "owner",
10 | "type": "address"
11 | },
12 | {
13 | "indexed": true,
14 | "internalType": "address",
15 | "name": "spender",
16 | "type": "address"
17 | },
18 | {
19 | "indexed": false,
20 | "internalType": "uint256",
21 | "name": "value",
22 | "type": "uint256"
23 | }
24 | ],
25 | "name": "Approval",
26 | "type": "event"
27 | },
28 | {
29 | "anonymous": false,
30 | "inputs": [
31 | {
32 | "indexed": true,
33 | "internalType": "address",
34 | "name": "from",
35 | "type": "address"
36 | },
37 | {
38 | "indexed": true,
39 | "internalType": "address",
40 | "name": "to",
41 | "type": "address"
42 | },
43 | {
44 | "indexed": false,
45 | "internalType": "uint256",
46 | "name": "value",
47 | "type": "uint256"
48 | }
49 | ],
50 | "name": "Transfer",
51 | "type": "event"
52 | },
53 | {
54 | "inputs": [
55 | {
56 | "internalType": "address",
57 | "name": "owner",
58 | "type": "address"
59 | },
60 | {
61 | "internalType": "address",
62 | "name": "spender",
63 | "type": "address"
64 | }
65 | ],
66 | "name": "allowance",
67 | "outputs": [
68 | {
69 | "internalType": "uint256",
70 | "name": "",
71 | "type": "uint256"
72 | }
73 | ],
74 | "stateMutability": "view",
75 | "type": "function"
76 | },
77 | {
78 | "inputs": [
79 | {
80 | "internalType": "address",
81 | "name": "spender",
82 | "type": "address"
83 | },
84 | {
85 | "internalType": "uint256",
86 | "name": "amount",
87 | "type": "uint256"
88 | }
89 | ],
90 | "name": "approve",
91 | "outputs": [
92 | {
93 | "internalType": "bool",
94 | "name": "",
95 | "type": "bool"
96 | }
97 | ],
98 | "stateMutability": "nonpayable",
99 | "type": "function"
100 | },
101 | {
102 | "inputs": [
103 | {
104 | "internalType": "address",
105 | "name": "account",
106 | "type": "address"
107 | }
108 | ],
109 | "name": "balanceOf",
110 | "outputs": [
111 | {
112 | "internalType": "uint256",
113 | "name": "",
114 | "type": "uint256"
115 | }
116 | ],
117 | "stateMutability": "view",
118 | "type": "function"
119 | },
120 | {
121 | "inputs": [],
122 | "name": "totalSupply",
123 | "outputs": [
124 | {
125 | "internalType": "uint256",
126 | "name": "",
127 | "type": "uint256"
128 | }
129 | ],
130 | "stateMutability": "view",
131 | "type": "function"
132 | },
133 | {
134 | "inputs": [
135 | {
136 | "internalType": "address",
137 | "name": "recipient",
138 | "type": "address"
139 | },
140 | {
141 | "internalType": "uint256",
142 | "name": "amount",
143 | "type": "uint256"
144 | }
145 | ],
146 | "name": "transfer",
147 | "outputs": [
148 | {
149 | "internalType": "bool",
150 | "name": "",
151 | "type": "bool"
152 | }
153 | ],
154 | "stateMutability": "nonpayable",
155 | "type": "function"
156 | },
157 | {
158 | "inputs": [
159 | {
160 | "internalType": "address",
161 | "name": "sender",
162 | "type": "address"
163 | },
164 | {
165 | "internalType": "address",
166 | "name": "recipient",
167 | "type": "address"
168 | },
169 | {
170 | "internalType": "uint256",
171 | "name": "amount",
172 | "type": "uint256"
173 | }
174 | ],
175 | "name": "transferFrom",
176 | "outputs": [
177 | {
178 | "internalType": "bool",
179 | "name": "",
180 | "type": "bool"
181 | }
182 | ],
183 | "stateMutability": "nonpayable",
184 | "type": "function"
185 | }
186 | ],
187 | "ast": {
188 | "absolutePath": "interfaces/IERC20.sol",
189 | "exportedSymbols": {
190 | "IERC20": [
191 | 77
192 | ]
193 | },
194 | "id": 78,
195 | "license": "MIT",
196 | "nodeType": "SourceUnit",
197 | "nodes": [
198 | {
199 | "id": 1,
200 | "literals": [
201 | "solidity",
202 | ">=",
203 | "0.6",
204 | ".0",
205 | "<",
206 | "0.8",
207 | ".0"
208 | ],
209 | "nodeType": "PragmaDirective",
210 | "src": "33:31:1"
211 | },
212 | {
213 | "abstract": false,
214 | "baseContracts": [],
215 | "contractDependencies": [],
216 | "contractKind": "interface",
217 | "documentation": {
218 | "id": 2,
219 | "nodeType": "StructuredDocumentation",
220 | "src": "66:70:1",
221 | "text": " @dev Interface of the ERC20 standard as defined in the EIP."
222 | },
223 | "fullyImplemented": false,
224 | "id": 77,
225 | "linearizedBaseContracts": [
226 | 77
227 | ],
228 | "name": "IERC20",
229 | "nodeType": "ContractDefinition",
230 | "nodes": [
231 | {
232 | "documentation": {
233 | "id": 3,
234 | "nodeType": "StructuredDocumentation",
235 | "src": "160:66:1",
236 | "text": " @dev Returns the amount of tokens in existence."
237 | },
238 | "functionSelector": "18160ddd",
239 | "id": 8,
240 | "implemented": false,
241 | "kind": "function",
242 | "modifiers": [],
243 | "name": "totalSupply",
244 | "nodeType": "FunctionDefinition",
245 | "parameters": {
246 | "id": 4,
247 | "nodeType": "ParameterList",
248 | "parameters": [],
249 | "src": "251:2:1"
250 | },
251 | "returnParameters": {
252 | "id": 7,
253 | "nodeType": "ParameterList",
254 | "parameters": [
255 | {
256 | "constant": false,
257 | "id": 6,
258 | "mutability": "mutable",
259 | "name": "",
260 | "nodeType": "VariableDeclaration",
261 | "scope": 8,
262 | "src": "277:7:1",
263 | "stateVariable": false,
264 | "storageLocation": "default",
265 | "typeDescriptions": {
266 | "typeIdentifier": "t_uint256",
267 | "typeString": "uint256"
268 | },
269 | "typeName": {
270 | "id": 5,
271 | "name": "uint256",
272 | "nodeType": "ElementaryTypeName",
273 | "src": "277:7:1",
274 | "typeDescriptions": {
275 | "typeIdentifier": "t_uint256",
276 | "typeString": "uint256"
277 | }
278 | },
279 | "visibility": "internal"
280 | }
281 | ],
282 | "src": "276:9:1"
283 | },
284 | "scope": 77,
285 | "src": "231:55:1",
286 | "stateMutability": "view",
287 | "virtual": false,
288 | "visibility": "external"
289 | },
290 | {
291 | "documentation": {
292 | "id": 9,
293 | "nodeType": "StructuredDocumentation",
294 | "src": "292:72:1",
295 | "text": " @dev Returns the amount of tokens owned by `account`."
296 | },
297 | "functionSelector": "70a08231",
298 | "id": 16,
299 | "implemented": false,
300 | "kind": "function",
301 | "modifiers": [],
302 | "name": "balanceOf",
303 | "nodeType": "FunctionDefinition",
304 | "parameters": {
305 | "id": 12,
306 | "nodeType": "ParameterList",
307 | "parameters": [
308 | {
309 | "constant": false,
310 | "id": 11,
311 | "mutability": "mutable",
312 | "name": "account",
313 | "nodeType": "VariableDeclaration",
314 | "scope": 16,
315 | "src": "388:15:1",
316 | "stateVariable": false,
317 | "storageLocation": "default",
318 | "typeDescriptions": {
319 | "typeIdentifier": "t_address",
320 | "typeString": "address"
321 | },
322 | "typeName": {
323 | "id": 10,
324 | "name": "address",
325 | "nodeType": "ElementaryTypeName",
326 | "src": "388:7:1",
327 | "stateMutability": "nonpayable",
328 | "typeDescriptions": {
329 | "typeIdentifier": "t_address",
330 | "typeString": "address"
331 | }
332 | },
333 | "visibility": "internal"
334 | }
335 | ],
336 | "src": "387:17:1"
337 | },
338 | "returnParameters": {
339 | "id": 15,
340 | "nodeType": "ParameterList",
341 | "parameters": [
342 | {
343 | "constant": false,
344 | "id": 14,
345 | "mutability": "mutable",
346 | "name": "",
347 | "nodeType": "VariableDeclaration",
348 | "scope": 16,
349 | "src": "428:7:1",
350 | "stateVariable": false,
351 | "storageLocation": "default",
352 | "typeDescriptions": {
353 | "typeIdentifier": "t_uint256",
354 | "typeString": "uint256"
355 | },
356 | "typeName": {
357 | "id": 13,
358 | "name": "uint256",
359 | "nodeType": "ElementaryTypeName",
360 | "src": "428:7:1",
361 | "typeDescriptions": {
362 | "typeIdentifier": "t_uint256",
363 | "typeString": "uint256"
364 | }
365 | },
366 | "visibility": "internal"
367 | }
368 | ],
369 | "src": "427:9:1"
370 | },
371 | "scope": 77,
372 | "src": "369:68:1",
373 | "stateMutability": "view",
374 | "virtual": false,
375 | "visibility": "external"
376 | },
377 | {
378 | "documentation": {
379 | "id": 17,
380 | "nodeType": "StructuredDocumentation",
381 | "src": "443:209:1",
382 | "text": " @dev Moves `amount` tokens from the caller's account to `recipient`.\n Returns a boolean value indicating whether the operation succeeded.\n Emits a {Transfer} event."
383 | },
384 | "functionSelector": "a9059cbb",
385 | "id": 26,
386 | "implemented": false,
387 | "kind": "function",
388 | "modifiers": [],
389 | "name": "transfer",
390 | "nodeType": "FunctionDefinition",
391 | "parameters": {
392 | "id": 22,
393 | "nodeType": "ParameterList",
394 | "parameters": [
395 | {
396 | "constant": false,
397 | "id": 19,
398 | "mutability": "mutable",
399 | "name": "recipient",
400 | "nodeType": "VariableDeclaration",
401 | "scope": 26,
402 | "src": "675:17:1",
403 | "stateVariable": false,
404 | "storageLocation": "default",
405 | "typeDescriptions": {
406 | "typeIdentifier": "t_address",
407 | "typeString": "address"
408 | },
409 | "typeName": {
410 | "id": 18,
411 | "name": "address",
412 | "nodeType": "ElementaryTypeName",
413 | "src": "675:7:1",
414 | "stateMutability": "nonpayable",
415 | "typeDescriptions": {
416 | "typeIdentifier": "t_address",
417 | "typeString": "address"
418 | }
419 | },
420 | "visibility": "internal"
421 | },
422 | {
423 | "constant": false,
424 | "id": 21,
425 | "mutability": "mutable",
426 | "name": "amount",
427 | "nodeType": "VariableDeclaration",
428 | "scope": 26,
429 | "src": "694:14:1",
430 | "stateVariable": false,
431 | "storageLocation": "default",
432 | "typeDescriptions": {
433 | "typeIdentifier": "t_uint256",
434 | "typeString": "uint256"
435 | },
436 | "typeName": {
437 | "id": 20,
438 | "name": "uint256",
439 | "nodeType": "ElementaryTypeName",
440 | "src": "694:7:1",
441 | "typeDescriptions": {
442 | "typeIdentifier": "t_uint256",
443 | "typeString": "uint256"
444 | }
445 | },
446 | "visibility": "internal"
447 | }
448 | ],
449 | "src": "674:35:1"
450 | },
451 | "returnParameters": {
452 | "id": 25,
453 | "nodeType": "ParameterList",
454 | "parameters": [
455 | {
456 | "constant": false,
457 | "id": 24,
458 | "mutability": "mutable",
459 | "name": "",
460 | "nodeType": "VariableDeclaration",
461 | "scope": 26,
462 | "src": "744:4:1",
463 | "stateVariable": false,
464 | "storageLocation": "default",
465 | "typeDescriptions": {
466 | "typeIdentifier": "t_bool",
467 | "typeString": "bool"
468 | },
469 | "typeName": {
470 | "id": 23,
471 | "name": "bool",
472 | "nodeType": "ElementaryTypeName",
473 | "src": "744:4:1",
474 | "typeDescriptions": {
475 | "typeIdentifier": "t_bool",
476 | "typeString": "bool"
477 | }
478 | },
479 | "visibility": "internal"
480 | }
481 | ],
482 | "src": "743:6:1"
483 | },
484 | "scope": 77,
485 | "src": "657:93:1",
486 | "stateMutability": "nonpayable",
487 | "virtual": false,
488 | "visibility": "external"
489 | },
490 | {
491 | "documentation": {
492 | "id": 27,
493 | "nodeType": "StructuredDocumentation",
494 | "src": "756:264:1",
495 | "text": " @dev Returns the remaining number of tokens that `spender` will be\n allowed to spend on behalf of `owner` through {transferFrom}. This is\n zero by default.\n This value changes when {approve} or {transferFrom} are called."
496 | },
497 | "functionSelector": "dd62ed3e",
498 | "id": 36,
499 | "implemented": false,
500 | "kind": "function",
501 | "modifiers": [],
502 | "name": "allowance",
503 | "nodeType": "FunctionDefinition",
504 | "parameters": {
505 | "id": 32,
506 | "nodeType": "ParameterList",
507 | "parameters": [
508 | {
509 | "constant": false,
510 | "id": 29,
511 | "mutability": "mutable",
512 | "name": "owner",
513 | "nodeType": "VariableDeclaration",
514 | "scope": 36,
515 | "src": "1044:13:1",
516 | "stateVariable": false,
517 | "storageLocation": "default",
518 | "typeDescriptions": {
519 | "typeIdentifier": "t_address",
520 | "typeString": "address"
521 | },
522 | "typeName": {
523 | "id": 28,
524 | "name": "address",
525 | "nodeType": "ElementaryTypeName",
526 | "src": "1044:7:1",
527 | "stateMutability": "nonpayable",
528 | "typeDescriptions": {
529 | "typeIdentifier": "t_address",
530 | "typeString": "address"
531 | }
532 | },
533 | "visibility": "internal"
534 | },
535 | {
536 | "constant": false,
537 | "id": 31,
538 | "mutability": "mutable",
539 | "name": "spender",
540 | "nodeType": "VariableDeclaration",
541 | "scope": 36,
542 | "src": "1059:15:1",
543 | "stateVariable": false,
544 | "storageLocation": "default",
545 | "typeDescriptions": {
546 | "typeIdentifier": "t_address",
547 | "typeString": "address"
548 | },
549 | "typeName": {
550 | "id": 30,
551 | "name": "address",
552 | "nodeType": "ElementaryTypeName",
553 | "src": "1059:7:1",
554 | "stateMutability": "nonpayable",
555 | "typeDescriptions": {
556 | "typeIdentifier": "t_address",
557 | "typeString": "address"
558 | }
559 | },
560 | "visibility": "internal"
561 | }
562 | ],
563 | "src": "1043:32:1"
564 | },
565 | "returnParameters": {
566 | "id": 35,
567 | "nodeType": "ParameterList",
568 | "parameters": [
569 | {
570 | "constant": false,
571 | "id": 34,
572 | "mutability": "mutable",
573 | "name": "",
574 | "nodeType": "VariableDeclaration",
575 | "scope": 36,
576 | "src": "1123:7:1",
577 | "stateVariable": false,
578 | "storageLocation": "default",
579 | "typeDescriptions": {
580 | "typeIdentifier": "t_uint256",
581 | "typeString": "uint256"
582 | },
583 | "typeName": {
584 | "id": 33,
585 | "name": "uint256",
586 | "nodeType": "ElementaryTypeName",
587 | "src": "1123:7:1",
588 | "typeDescriptions": {
589 | "typeIdentifier": "t_uint256",
590 | "typeString": "uint256"
591 | }
592 | },
593 | "visibility": "internal"
594 | }
595 | ],
596 | "src": "1122:9:1"
597 | },
598 | "scope": 77,
599 | "src": "1025:107:1",
600 | "stateMutability": "view",
601 | "virtual": false,
602 | "visibility": "external"
603 | },
604 | {
605 | "documentation": {
606 | "id": 37,
607 | "nodeType": "StructuredDocumentation",
608 | "src": "1138:642:1",
609 | "text": " @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n Returns a boolean value indicating whether the operation succeeded.\n IMPORTANT: Beware that changing an allowance with this method brings the risk\n that someone may use both the old and the new allowance by unfortunate\n transaction ordering. One possible solution to mitigate this race\n condition is to first reduce the spender's allowance to 0 and set the\n desired value afterwards:\n https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n Emits an {Approval} event."
610 | },
611 | "functionSelector": "095ea7b3",
612 | "id": 46,
613 | "implemented": false,
614 | "kind": "function",
615 | "modifiers": [],
616 | "name": "approve",
617 | "nodeType": "FunctionDefinition",
618 | "parameters": {
619 | "id": 42,
620 | "nodeType": "ParameterList",
621 | "parameters": [
622 | {
623 | "constant": false,
624 | "id": 39,
625 | "mutability": "mutable",
626 | "name": "spender",
627 | "nodeType": "VariableDeclaration",
628 | "scope": 46,
629 | "src": "1802:15:1",
630 | "stateVariable": false,
631 | "storageLocation": "default",
632 | "typeDescriptions": {
633 | "typeIdentifier": "t_address",
634 | "typeString": "address"
635 | },
636 | "typeName": {
637 | "id": 38,
638 | "name": "address",
639 | "nodeType": "ElementaryTypeName",
640 | "src": "1802:7:1",
641 | "stateMutability": "nonpayable",
642 | "typeDescriptions": {
643 | "typeIdentifier": "t_address",
644 | "typeString": "address"
645 | }
646 | },
647 | "visibility": "internal"
648 | },
649 | {
650 | "constant": false,
651 | "id": 41,
652 | "mutability": "mutable",
653 | "name": "amount",
654 | "nodeType": "VariableDeclaration",
655 | "scope": 46,
656 | "src": "1819:14:1",
657 | "stateVariable": false,
658 | "storageLocation": "default",
659 | "typeDescriptions": {
660 | "typeIdentifier": "t_uint256",
661 | "typeString": "uint256"
662 | },
663 | "typeName": {
664 | "id": 40,
665 | "name": "uint256",
666 | "nodeType": "ElementaryTypeName",
667 | "src": "1819:7:1",
668 | "typeDescriptions": {
669 | "typeIdentifier": "t_uint256",
670 | "typeString": "uint256"
671 | }
672 | },
673 | "visibility": "internal"
674 | }
675 | ],
676 | "src": "1801:33:1"
677 | },
678 | "returnParameters": {
679 | "id": 45,
680 | "nodeType": "ParameterList",
681 | "parameters": [
682 | {
683 | "constant": false,
684 | "id": 44,
685 | "mutability": "mutable",
686 | "name": "",
687 | "nodeType": "VariableDeclaration",
688 | "scope": 46,
689 | "src": "1853:4:1",
690 | "stateVariable": false,
691 | "storageLocation": "default",
692 | "typeDescriptions": {
693 | "typeIdentifier": "t_bool",
694 | "typeString": "bool"
695 | },
696 | "typeName": {
697 | "id": 43,
698 | "name": "bool",
699 | "nodeType": "ElementaryTypeName",
700 | "src": "1853:4:1",
701 | "typeDescriptions": {
702 | "typeIdentifier": "t_bool",
703 | "typeString": "bool"
704 | }
705 | },
706 | "visibility": "internal"
707 | }
708 | ],
709 | "src": "1852:6:1"
710 | },
711 | "scope": 77,
712 | "src": "1785:74:1",
713 | "stateMutability": "nonpayable",
714 | "virtual": false,
715 | "visibility": "external"
716 | },
717 | {
718 | "documentation": {
719 | "id": 47,
720 | "nodeType": "StructuredDocumentation",
721 | "src": "1865:296:1",
722 | "text": " @dev Moves `amount` tokens from `sender` to `recipient` using the\n allowance mechanism. `amount` is then deducted from the caller's\n allowance.\n Returns a boolean value indicating whether the operation succeeded.\n Emits a {Transfer} event."
723 | },
724 | "functionSelector": "23b872dd",
725 | "id": 58,
726 | "implemented": false,
727 | "kind": "function",
728 | "modifiers": [],
729 | "name": "transferFrom",
730 | "nodeType": "FunctionDefinition",
731 | "parameters": {
732 | "id": 54,
733 | "nodeType": "ParameterList",
734 | "parameters": [
735 | {
736 | "constant": false,
737 | "id": 49,
738 | "mutability": "mutable",
739 | "name": "sender",
740 | "nodeType": "VariableDeclaration",
741 | "scope": 58,
742 | "src": "2197:14:1",
743 | "stateVariable": false,
744 | "storageLocation": "default",
745 | "typeDescriptions": {
746 | "typeIdentifier": "t_address",
747 | "typeString": "address"
748 | },
749 | "typeName": {
750 | "id": 48,
751 | "name": "address",
752 | "nodeType": "ElementaryTypeName",
753 | "src": "2197:7:1",
754 | "stateMutability": "nonpayable",
755 | "typeDescriptions": {
756 | "typeIdentifier": "t_address",
757 | "typeString": "address"
758 | }
759 | },
760 | "visibility": "internal"
761 | },
762 | {
763 | "constant": false,
764 | "id": 51,
765 | "mutability": "mutable",
766 | "name": "recipient",
767 | "nodeType": "VariableDeclaration",
768 | "scope": 58,
769 | "src": "2221:17:1",
770 | "stateVariable": false,
771 | "storageLocation": "default",
772 | "typeDescriptions": {
773 | "typeIdentifier": "t_address",
774 | "typeString": "address"
775 | },
776 | "typeName": {
777 | "id": 50,
778 | "name": "address",
779 | "nodeType": "ElementaryTypeName",
780 | "src": "2221:7:1",
781 | "stateMutability": "nonpayable",
782 | "typeDescriptions": {
783 | "typeIdentifier": "t_address",
784 | "typeString": "address"
785 | }
786 | },
787 | "visibility": "internal"
788 | },
789 | {
790 | "constant": false,
791 | "id": 53,
792 | "mutability": "mutable",
793 | "name": "amount",
794 | "nodeType": "VariableDeclaration",
795 | "scope": 58,
796 | "src": "2248:14:1",
797 | "stateVariable": false,
798 | "storageLocation": "default",
799 | "typeDescriptions": {
800 | "typeIdentifier": "t_uint256",
801 | "typeString": "uint256"
802 | },
803 | "typeName": {
804 | "id": 52,
805 | "name": "uint256",
806 | "nodeType": "ElementaryTypeName",
807 | "src": "2248:7:1",
808 | "typeDescriptions": {
809 | "typeIdentifier": "t_uint256",
810 | "typeString": "uint256"
811 | }
812 | },
813 | "visibility": "internal"
814 | }
815 | ],
816 | "src": "2187:81:1"
817 | },
818 | "returnParameters": {
819 | "id": 57,
820 | "nodeType": "ParameterList",
821 | "parameters": [
822 | {
823 | "constant": false,
824 | "id": 56,
825 | "mutability": "mutable",
826 | "name": "",
827 | "nodeType": "VariableDeclaration",
828 | "scope": 58,
829 | "src": "2287:4:1",
830 | "stateVariable": false,
831 | "storageLocation": "default",
832 | "typeDescriptions": {
833 | "typeIdentifier": "t_bool",
834 | "typeString": "bool"
835 | },
836 | "typeName": {
837 | "id": 55,
838 | "name": "bool",
839 | "nodeType": "ElementaryTypeName",
840 | "src": "2287:4:1",
841 | "typeDescriptions": {
842 | "typeIdentifier": "t_bool",
843 | "typeString": "bool"
844 | }
845 | },
846 | "visibility": "internal"
847 | }
848 | ],
849 | "src": "2286:6:1"
850 | },
851 | "scope": 77,
852 | "src": "2166:127:1",
853 | "stateMutability": "nonpayable",
854 | "virtual": false,
855 | "visibility": "external"
856 | },
857 | {
858 | "anonymous": false,
859 | "documentation": {
860 | "id": 59,
861 | "nodeType": "StructuredDocumentation",
862 | "src": "2299:158:1",
863 | "text": " @dev Emitted when `value` tokens are moved from one account (`from`) to\n another (`to`).\n Note that `value` may be zero."
864 | },
865 | "id": 67,
866 | "name": "Transfer",
867 | "nodeType": "EventDefinition",
868 | "parameters": {
869 | "id": 66,
870 | "nodeType": "ParameterList",
871 | "parameters": [
872 | {
873 | "constant": false,
874 | "id": 61,
875 | "indexed": true,
876 | "mutability": "mutable",
877 | "name": "from",
878 | "nodeType": "VariableDeclaration",
879 | "scope": 67,
880 | "src": "2477:20:1",
881 | "stateVariable": false,
882 | "storageLocation": "default",
883 | "typeDescriptions": {
884 | "typeIdentifier": "t_address",
885 | "typeString": "address"
886 | },
887 | "typeName": {
888 | "id": 60,
889 | "name": "address",
890 | "nodeType": "ElementaryTypeName",
891 | "src": "2477:7:1",
892 | "stateMutability": "nonpayable",
893 | "typeDescriptions": {
894 | "typeIdentifier": "t_address",
895 | "typeString": "address"
896 | }
897 | },
898 | "visibility": "internal"
899 | },
900 | {
901 | "constant": false,
902 | "id": 63,
903 | "indexed": true,
904 | "mutability": "mutable",
905 | "name": "to",
906 | "nodeType": "VariableDeclaration",
907 | "scope": 67,
908 | "src": "2499:18:1",
909 | "stateVariable": false,
910 | "storageLocation": "default",
911 | "typeDescriptions": {
912 | "typeIdentifier": "t_address",
913 | "typeString": "address"
914 | },
915 | "typeName": {
916 | "id": 62,
917 | "name": "address",
918 | "nodeType": "ElementaryTypeName",
919 | "src": "2499:7:1",
920 | "stateMutability": "nonpayable",
921 | "typeDescriptions": {
922 | "typeIdentifier": "t_address",
923 | "typeString": "address"
924 | }
925 | },
926 | "visibility": "internal"
927 | },
928 | {
929 | "constant": false,
930 | "id": 65,
931 | "indexed": false,
932 | "mutability": "mutable",
933 | "name": "value",
934 | "nodeType": "VariableDeclaration",
935 | "scope": 67,
936 | "src": "2519:13:1",
937 | "stateVariable": false,
938 | "storageLocation": "default",
939 | "typeDescriptions": {
940 | "typeIdentifier": "t_uint256",
941 | "typeString": "uint256"
942 | },
943 | "typeName": {
944 | "id": 64,
945 | "name": "uint256",
946 | "nodeType": "ElementaryTypeName",
947 | "src": "2519:7:1",
948 | "typeDescriptions": {
949 | "typeIdentifier": "t_uint256",
950 | "typeString": "uint256"
951 | }
952 | },
953 | "visibility": "internal"
954 | }
955 | ],
956 | "src": "2476:57:1"
957 | },
958 | "src": "2462:72:1"
959 | },
960 | {
961 | "anonymous": false,
962 | "documentation": {
963 | "id": 68,
964 | "nodeType": "StructuredDocumentation",
965 | "src": "2540:148:1",
966 | "text": " @dev Emitted when the allowance of a `spender` for an `owner` is set by\n a call to {approve}. `value` is the new allowance."
967 | },
968 | "id": 76,
969 | "name": "Approval",
970 | "nodeType": "EventDefinition",
971 | "parameters": {
972 | "id": 75,
973 | "nodeType": "ParameterList",
974 | "parameters": [
975 | {
976 | "constant": false,
977 | "id": 70,
978 | "indexed": true,
979 | "mutability": "mutable",
980 | "name": "owner",
981 | "nodeType": "VariableDeclaration",
982 | "scope": 76,
983 | "src": "2717:21:1",
984 | "stateVariable": false,
985 | "storageLocation": "default",
986 | "typeDescriptions": {
987 | "typeIdentifier": "t_address",
988 | "typeString": "address"
989 | },
990 | "typeName": {
991 | "id": 69,
992 | "name": "address",
993 | "nodeType": "ElementaryTypeName",
994 | "src": "2717:7:1",
995 | "stateMutability": "nonpayable",
996 | "typeDescriptions": {
997 | "typeIdentifier": "t_address",
998 | "typeString": "address"
999 | }
1000 | },
1001 | "visibility": "internal"
1002 | },
1003 | {
1004 | "constant": false,
1005 | "id": 72,
1006 | "indexed": true,
1007 | "mutability": "mutable",
1008 | "name": "spender",
1009 | "nodeType": "VariableDeclaration",
1010 | "scope": 76,
1011 | "src": "2748:23:1",
1012 | "stateVariable": false,
1013 | "storageLocation": "default",
1014 | "typeDescriptions": {
1015 | "typeIdentifier": "t_address",
1016 | "typeString": "address"
1017 | },
1018 | "typeName": {
1019 | "id": 71,
1020 | "name": "address",
1021 | "nodeType": "ElementaryTypeName",
1022 | "src": "2748:7:1",
1023 | "stateMutability": "nonpayable",
1024 | "typeDescriptions": {
1025 | "typeIdentifier": "t_address",
1026 | "typeString": "address"
1027 | }
1028 | },
1029 | "visibility": "internal"
1030 | },
1031 | {
1032 | "constant": false,
1033 | "id": 74,
1034 | "indexed": false,
1035 | "mutability": "mutable",
1036 | "name": "value",
1037 | "nodeType": "VariableDeclaration",
1038 | "scope": 76,
1039 | "src": "2781:13:1",
1040 | "stateVariable": false,
1041 | "storageLocation": "default",
1042 | "typeDescriptions": {
1043 | "typeIdentifier": "t_uint256",
1044 | "typeString": "uint256"
1045 | },
1046 | "typeName": {
1047 | "id": 73,
1048 | "name": "uint256",
1049 | "nodeType": "ElementaryTypeName",
1050 | "src": "2781:7:1",
1051 | "typeDescriptions": {
1052 | "typeIdentifier": "t_uint256",
1053 | "typeString": "uint256"
1054 | }
1055 | },
1056 | "visibility": "internal"
1057 | }
1058 | ],
1059 | "src": "2707:93:1"
1060 | },
1061 | "src": "2693:108:1"
1062 | }
1063 | ],
1064 | "scope": 78,
1065 | "src": "137:2666:1"
1066 | }
1067 | ],
1068 | "src": "33:2771:1"
1069 | },
1070 | "contractName": "IERC20",
1071 | "dependencies": [],
1072 | "offset": [
1073 | 137,
1074 | 2803
1075 | ],
1076 | "sha1": "6b2cffe7b0ed20aefdb3bb642379dddeb6506a5f",
1077 | "source": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.6.0 <0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address recipient, uint256 amount)\n external\n returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender)\n external\n view\n returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(\n address indexed owner,\n address indexed spender,\n uint256 value\n );\n}\n",
1078 | "type": "interface"
1079 | }
--------------------------------------------------------------------------------
/build/interfaces/IQuoter.json:
--------------------------------------------------------------------------------
1 | {
2 | "abi": [
3 | {
4 | "inputs": [
5 | {
6 | "internalType": "bytes",
7 | "name": "path",
8 | "type": "bytes"
9 | },
10 | {
11 | "internalType": "uint256",
12 | "name": "amountIn",
13 | "type": "uint256"
14 | }
15 | ],
16 | "name": "quoteExactInput",
17 | "outputs": [
18 | {
19 | "internalType": "uint256",
20 | "name": "amountOut",
21 | "type": "uint256"
22 | }
23 | ],
24 | "stateMutability": "nonpayable",
25 | "type": "function"
26 | },
27 | {
28 | "inputs": [
29 | {
30 | "internalType": "address",
31 | "name": "tokenIn",
32 | "type": "address"
33 | },
34 | {
35 | "internalType": "address",
36 | "name": "tokenOut",
37 | "type": "address"
38 | },
39 | {
40 | "internalType": "uint24",
41 | "name": "fee",
42 | "type": "uint24"
43 | },
44 | {
45 | "internalType": "uint256",
46 | "name": "amountIn",
47 | "type": "uint256"
48 | },
49 | {
50 | "internalType": "uint160",
51 | "name": "sqrtPriceLimitX96",
52 | "type": "uint160"
53 | }
54 | ],
55 | "name": "quoteExactInputSingle",
56 | "outputs": [
57 | {
58 | "internalType": "uint256",
59 | "name": "amountOut",
60 | "type": "uint256"
61 | }
62 | ],
63 | "stateMutability": "nonpayable",
64 | "type": "function"
65 | },
66 | {
67 | "inputs": [
68 | {
69 | "internalType": "bytes",
70 | "name": "path",
71 | "type": "bytes"
72 | },
73 | {
74 | "internalType": "uint256",
75 | "name": "amountOut",
76 | "type": "uint256"
77 | }
78 | ],
79 | "name": "quoteExactOutput",
80 | "outputs": [
81 | {
82 | "internalType": "uint256",
83 | "name": "amountIn",
84 | "type": "uint256"
85 | }
86 | ],
87 | "stateMutability": "nonpayable",
88 | "type": "function"
89 | },
90 | {
91 | "inputs": [
92 | {
93 | "internalType": "address",
94 | "name": "tokenIn",
95 | "type": "address"
96 | },
97 | {
98 | "internalType": "address",
99 | "name": "tokenOut",
100 | "type": "address"
101 | },
102 | {
103 | "internalType": "uint24",
104 | "name": "fee",
105 | "type": "uint24"
106 | },
107 | {
108 | "internalType": "uint256",
109 | "name": "amountOut",
110 | "type": "uint256"
111 | },
112 | {
113 | "internalType": "uint160",
114 | "name": "sqrtPriceLimitX96",
115 | "type": "uint160"
116 | }
117 | ],
118 | "name": "quoteExactOutputSingle",
119 | "outputs": [
120 | {
121 | "internalType": "uint256",
122 | "name": "amountIn",
123 | "type": "uint256"
124 | }
125 | ],
126 | "stateMutability": "nonpayable",
127 | "type": "function"
128 | }
129 | ],
130 | "ast": {
131 | "absolutePath": "interfaces/IQouter.sol",
132 | "exportedSymbols": {
133 | "IQuoter": [
134 | 56
135 | ]
136 | },
137 | "id": 57,
138 | "license": "GPL-2.0-or-later",
139 | "nodeType": "SourceUnit",
140 | "nodes": [
141 | {
142 | "id": 1,
143 | "literals": [
144 | "solidity",
145 | ">=",
146 | "0.7",
147 | ".5"
148 | ],
149 | "nodeType": "PragmaDirective",
150 | "src": "45:24:1"
151 | },
152 | {
153 | "id": 2,
154 | "literals": [
155 | "abicoder",
156 | "v2"
157 | ],
158 | "nodeType": "PragmaDirective",
159 | "src": "70:19:1"
160 | },
161 | {
162 | "abstract": false,
163 | "baseContracts": [],
164 | "canonicalName": "IQuoter",
165 | "contractDependencies": [],
166 | "contractKind": "interface",
167 | "documentation": {
168 | "id": 3,
169 | "nodeType": "StructuredDocumentation",
170 | "src": "91:320:1",
171 | "text": "@title Quoter Interface\n @notice Supports quoting the calculated amounts from exact input or exact output swaps\n @dev These functions are not marked view because they rely on calling non-view functions and reverting\n to compute the result. They are also not gas efficient and should not be called on-chain."
172 | },
173 | "fullyImplemented": false,
174 | "id": 56,
175 | "linearizedBaseContracts": [
176 | 56
177 | ],
178 | "name": "IQuoter",
179 | "nameLocation": "421:7:1",
180 | "nodeType": "ContractDefinition",
181 | "nodes": [
182 | {
183 | "documentation": {
184 | "id": 4,
185 | "nodeType": "StructuredDocumentation",
186 | "src": "435:319:1",
187 | "text": "@notice Returns the amount out received for a given exact input swap without executing the swap\n @param path The path of the swap, i.e. each token pair and the pool fee\n @param amountIn The amount of the first token to swap\n @return amountOut The amount of the last token that would be received"
188 | },
189 | "functionSelector": "cdca1753",
190 | "id": 13,
191 | "implemented": false,
192 | "kind": "function",
193 | "modifiers": [],
194 | "name": "quoteExactInput",
195 | "nameLocation": "768:15:1",
196 | "nodeType": "FunctionDefinition",
197 | "parameters": {
198 | "id": 9,
199 | "nodeType": "ParameterList",
200 | "parameters": [
201 | {
202 | "constant": false,
203 | "id": 6,
204 | "mutability": "mutable",
205 | "name": "path",
206 | "nameLocation": "797:4:1",
207 | "nodeType": "VariableDeclaration",
208 | "scope": 13,
209 | "src": "784:17:1",
210 | "stateVariable": false,
211 | "storageLocation": "memory",
212 | "typeDescriptions": {
213 | "typeIdentifier": "t_bytes_memory_ptr",
214 | "typeString": "bytes"
215 | },
216 | "typeName": {
217 | "id": 5,
218 | "name": "bytes",
219 | "nodeType": "ElementaryTypeName",
220 | "src": "784:5:1",
221 | "typeDescriptions": {
222 | "typeIdentifier": "t_bytes_storage_ptr",
223 | "typeString": "bytes"
224 | }
225 | },
226 | "visibility": "internal"
227 | },
228 | {
229 | "constant": false,
230 | "id": 8,
231 | "mutability": "mutable",
232 | "name": "amountIn",
233 | "nameLocation": "811:8:1",
234 | "nodeType": "VariableDeclaration",
235 | "scope": 13,
236 | "src": "803:16:1",
237 | "stateVariable": false,
238 | "storageLocation": "default",
239 | "typeDescriptions": {
240 | "typeIdentifier": "t_uint256",
241 | "typeString": "uint256"
242 | },
243 | "typeName": {
244 | "id": 7,
245 | "name": "uint256",
246 | "nodeType": "ElementaryTypeName",
247 | "src": "803:7:1",
248 | "typeDescriptions": {
249 | "typeIdentifier": "t_uint256",
250 | "typeString": "uint256"
251 | }
252 | },
253 | "visibility": "internal"
254 | }
255 | ],
256 | "src": "783:37:1"
257 | },
258 | "returnParameters": {
259 | "id": 12,
260 | "nodeType": "ParameterList",
261 | "parameters": [
262 | {
263 | "constant": false,
264 | "id": 11,
265 | "mutability": "mutable",
266 | "name": "amountOut",
267 | "nameLocation": "863:9:1",
268 | "nodeType": "VariableDeclaration",
269 | "scope": 13,
270 | "src": "855:17:1",
271 | "stateVariable": false,
272 | "storageLocation": "default",
273 | "typeDescriptions": {
274 | "typeIdentifier": "t_uint256",
275 | "typeString": "uint256"
276 | },
277 | "typeName": {
278 | "id": 10,
279 | "name": "uint256",
280 | "nodeType": "ElementaryTypeName",
281 | "src": "855:7:1",
282 | "typeDescriptions": {
283 | "typeIdentifier": "t_uint256",
284 | "typeString": "uint256"
285 | }
286 | },
287 | "visibility": "internal"
288 | }
289 | ],
290 | "src": "854:19:1"
291 | },
292 | "scope": 56,
293 | "src": "759:115:1",
294 | "stateMutability": "nonpayable",
295 | "virtual": false,
296 | "visibility": "external"
297 | },
298 | {
299 | "documentation": {
300 | "id": 14,
301 | "nodeType": "StructuredDocumentation",
302 | "src": "880:491:1",
303 | "text": "@notice Returns the amount out received for a given exact input but for a swap of a single pool\n @param tokenIn The token being swapped in\n @param tokenOut The token being swapped out\n @param fee The fee of the token pool to consider for the pair\n @param amountIn The desired input amount\n @param sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap\n @return amountOut The amount of `tokenOut` that would be received"
304 | },
305 | "functionSelector": "f7729d43",
306 | "id": 29,
307 | "implemented": false,
308 | "kind": "function",
309 | "modifiers": [],
310 | "name": "quoteExactInputSingle",
311 | "nameLocation": "1385:21:1",
312 | "nodeType": "FunctionDefinition",
313 | "parameters": {
314 | "id": 25,
315 | "nodeType": "ParameterList",
316 | "parameters": [
317 | {
318 | "constant": false,
319 | "id": 16,
320 | "mutability": "mutable",
321 | "name": "tokenIn",
322 | "nameLocation": "1424:7:1",
323 | "nodeType": "VariableDeclaration",
324 | "scope": 29,
325 | "src": "1416:15:1",
326 | "stateVariable": false,
327 | "storageLocation": "default",
328 | "typeDescriptions": {
329 | "typeIdentifier": "t_address",
330 | "typeString": "address"
331 | },
332 | "typeName": {
333 | "id": 15,
334 | "name": "address",
335 | "nodeType": "ElementaryTypeName",
336 | "src": "1416:7:1",
337 | "stateMutability": "nonpayable",
338 | "typeDescriptions": {
339 | "typeIdentifier": "t_address",
340 | "typeString": "address"
341 | }
342 | },
343 | "visibility": "internal"
344 | },
345 | {
346 | "constant": false,
347 | "id": 18,
348 | "mutability": "mutable",
349 | "name": "tokenOut",
350 | "nameLocation": "1449:8:1",
351 | "nodeType": "VariableDeclaration",
352 | "scope": 29,
353 | "src": "1441:16:1",
354 | "stateVariable": false,
355 | "storageLocation": "default",
356 | "typeDescriptions": {
357 | "typeIdentifier": "t_address",
358 | "typeString": "address"
359 | },
360 | "typeName": {
361 | "id": 17,
362 | "name": "address",
363 | "nodeType": "ElementaryTypeName",
364 | "src": "1441:7:1",
365 | "stateMutability": "nonpayable",
366 | "typeDescriptions": {
367 | "typeIdentifier": "t_address",
368 | "typeString": "address"
369 | }
370 | },
371 | "visibility": "internal"
372 | },
373 | {
374 | "constant": false,
375 | "id": 20,
376 | "mutability": "mutable",
377 | "name": "fee",
378 | "nameLocation": "1474:3:1",
379 | "nodeType": "VariableDeclaration",
380 | "scope": 29,
381 | "src": "1467:10:1",
382 | "stateVariable": false,
383 | "storageLocation": "default",
384 | "typeDescriptions": {
385 | "typeIdentifier": "t_uint24",
386 | "typeString": "uint24"
387 | },
388 | "typeName": {
389 | "id": 19,
390 | "name": "uint24",
391 | "nodeType": "ElementaryTypeName",
392 | "src": "1467:6:1",
393 | "typeDescriptions": {
394 | "typeIdentifier": "t_uint24",
395 | "typeString": "uint24"
396 | }
397 | },
398 | "visibility": "internal"
399 | },
400 | {
401 | "constant": false,
402 | "id": 22,
403 | "mutability": "mutable",
404 | "name": "amountIn",
405 | "nameLocation": "1495:8:1",
406 | "nodeType": "VariableDeclaration",
407 | "scope": 29,
408 | "src": "1487:16:1",
409 | "stateVariable": false,
410 | "storageLocation": "default",
411 | "typeDescriptions": {
412 | "typeIdentifier": "t_uint256",
413 | "typeString": "uint256"
414 | },
415 | "typeName": {
416 | "id": 21,
417 | "name": "uint256",
418 | "nodeType": "ElementaryTypeName",
419 | "src": "1487:7:1",
420 | "typeDescriptions": {
421 | "typeIdentifier": "t_uint256",
422 | "typeString": "uint256"
423 | }
424 | },
425 | "visibility": "internal"
426 | },
427 | {
428 | "constant": false,
429 | "id": 24,
430 | "mutability": "mutable",
431 | "name": "sqrtPriceLimitX96",
432 | "nameLocation": "1521:17:1",
433 | "nodeType": "VariableDeclaration",
434 | "scope": 29,
435 | "src": "1513:25:1",
436 | "stateVariable": false,
437 | "storageLocation": "default",
438 | "typeDescriptions": {
439 | "typeIdentifier": "t_uint160",
440 | "typeString": "uint160"
441 | },
442 | "typeName": {
443 | "id": 23,
444 | "name": "uint160",
445 | "nodeType": "ElementaryTypeName",
446 | "src": "1513:7:1",
447 | "typeDescriptions": {
448 | "typeIdentifier": "t_uint160",
449 | "typeString": "uint160"
450 | }
451 | },
452 | "visibility": "internal"
453 | }
454 | ],
455 | "src": "1406:138:1"
456 | },
457 | "returnParameters": {
458 | "id": 28,
459 | "nodeType": "ParameterList",
460 | "parameters": [
461 | {
462 | "constant": false,
463 | "id": 27,
464 | "mutability": "mutable",
465 | "name": "amountOut",
466 | "nameLocation": "1571:9:1",
467 | "nodeType": "VariableDeclaration",
468 | "scope": 29,
469 | "src": "1563:17:1",
470 | "stateVariable": false,
471 | "storageLocation": "default",
472 | "typeDescriptions": {
473 | "typeIdentifier": "t_uint256",
474 | "typeString": "uint256"
475 | },
476 | "typeName": {
477 | "id": 26,
478 | "name": "uint256",
479 | "nodeType": "ElementaryTypeName",
480 | "src": "1563:7:1",
481 | "typeDescriptions": {
482 | "typeIdentifier": "t_uint256",
483 | "typeString": "uint256"
484 | }
485 | },
486 | "visibility": "internal"
487 | }
488 | ],
489 | "src": "1562:19:1"
490 | },
491 | "scope": 56,
492 | "src": "1376:206:1",
493 | "stateMutability": "nonpayable",
494 | "virtual": false,
495 | "visibility": "external"
496 | },
497 | {
498 | "documentation": {
499 | "id": 30,
500 | "nodeType": "StructuredDocumentation",
501 | "src": "1588:355:1",
502 | "text": "@notice Returns the amount in required for a given exact output swap without executing the swap\n @param path The path of the swap, i.e. each token pair and the pool fee. Path must be provided in reverse order\n @param amountOut The amount of the last token to receive\n @return amountIn The amount of first token required to be paid"
503 | },
504 | "functionSelector": "2f80bb1d",
505 | "id": 39,
506 | "implemented": false,
507 | "kind": "function",
508 | "modifiers": [],
509 | "name": "quoteExactOutput",
510 | "nameLocation": "1957:16:1",
511 | "nodeType": "FunctionDefinition",
512 | "parameters": {
513 | "id": 35,
514 | "nodeType": "ParameterList",
515 | "parameters": [
516 | {
517 | "constant": false,
518 | "id": 32,
519 | "mutability": "mutable",
520 | "name": "path",
521 | "nameLocation": "1987:4:1",
522 | "nodeType": "VariableDeclaration",
523 | "scope": 39,
524 | "src": "1974:17:1",
525 | "stateVariable": false,
526 | "storageLocation": "memory",
527 | "typeDescriptions": {
528 | "typeIdentifier": "t_bytes_memory_ptr",
529 | "typeString": "bytes"
530 | },
531 | "typeName": {
532 | "id": 31,
533 | "name": "bytes",
534 | "nodeType": "ElementaryTypeName",
535 | "src": "1974:5:1",
536 | "typeDescriptions": {
537 | "typeIdentifier": "t_bytes_storage_ptr",
538 | "typeString": "bytes"
539 | }
540 | },
541 | "visibility": "internal"
542 | },
543 | {
544 | "constant": false,
545 | "id": 34,
546 | "mutability": "mutable",
547 | "name": "amountOut",
548 | "nameLocation": "2001:9:1",
549 | "nodeType": "VariableDeclaration",
550 | "scope": 39,
551 | "src": "1993:17:1",
552 | "stateVariable": false,
553 | "storageLocation": "default",
554 | "typeDescriptions": {
555 | "typeIdentifier": "t_uint256",
556 | "typeString": "uint256"
557 | },
558 | "typeName": {
559 | "id": 33,
560 | "name": "uint256",
561 | "nodeType": "ElementaryTypeName",
562 | "src": "1993:7:1",
563 | "typeDescriptions": {
564 | "typeIdentifier": "t_uint256",
565 | "typeString": "uint256"
566 | }
567 | },
568 | "visibility": "internal"
569 | }
570 | ],
571 | "src": "1973:38:1"
572 | },
573 | "returnParameters": {
574 | "id": 38,
575 | "nodeType": "ParameterList",
576 | "parameters": [
577 | {
578 | "constant": false,
579 | "id": 37,
580 | "mutability": "mutable",
581 | "name": "amountIn",
582 | "nameLocation": "2054:8:1",
583 | "nodeType": "VariableDeclaration",
584 | "scope": 39,
585 | "src": "2046:16:1",
586 | "stateVariable": false,
587 | "storageLocation": "default",
588 | "typeDescriptions": {
589 | "typeIdentifier": "t_uint256",
590 | "typeString": "uint256"
591 | },
592 | "typeName": {
593 | "id": 36,
594 | "name": "uint256",
595 | "nodeType": "ElementaryTypeName",
596 | "src": "2046:7:1",
597 | "typeDescriptions": {
598 | "typeIdentifier": "t_uint256",
599 | "typeString": "uint256"
600 | }
601 | },
602 | "visibility": "internal"
603 | }
604 | ],
605 | "src": "2045:18:1"
606 | },
607 | "scope": 56,
608 | "src": "1948:116:1",
609 | "stateMutability": "nonpayable",
610 | "virtual": false,
611 | "visibility": "external"
612 | },
613 | {
614 | "documentation": {
615 | "id": 40,
616 | "nodeType": "StructuredDocumentation",
617 | "src": "2070:538:1",
618 | "text": "@notice Returns the amount in required to receive the given exact output amount but for a swap of a single pool\n @param tokenIn The token being swapped in\n @param tokenOut The token being swapped out\n @param fee The fee of the token pool to consider for the pair\n @param amountOut The desired output amount\n @param sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap\n @return amountIn The amount required as the input for the swap in order to receive `amountOut`"
619 | },
620 | "functionSelector": "30d07f21",
621 | "id": 55,
622 | "implemented": false,
623 | "kind": "function",
624 | "modifiers": [],
625 | "name": "quoteExactOutputSingle",
626 | "nameLocation": "2622:22:1",
627 | "nodeType": "FunctionDefinition",
628 | "parameters": {
629 | "id": 51,
630 | "nodeType": "ParameterList",
631 | "parameters": [
632 | {
633 | "constant": false,
634 | "id": 42,
635 | "mutability": "mutable",
636 | "name": "tokenIn",
637 | "nameLocation": "2662:7:1",
638 | "nodeType": "VariableDeclaration",
639 | "scope": 55,
640 | "src": "2654:15:1",
641 | "stateVariable": false,
642 | "storageLocation": "default",
643 | "typeDescriptions": {
644 | "typeIdentifier": "t_address",
645 | "typeString": "address"
646 | },
647 | "typeName": {
648 | "id": 41,
649 | "name": "address",
650 | "nodeType": "ElementaryTypeName",
651 | "src": "2654:7:1",
652 | "stateMutability": "nonpayable",
653 | "typeDescriptions": {
654 | "typeIdentifier": "t_address",
655 | "typeString": "address"
656 | }
657 | },
658 | "visibility": "internal"
659 | },
660 | {
661 | "constant": false,
662 | "id": 44,
663 | "mutability": "mutable",
664 | "name": "tokenOut",
665 | "nameLocation": "2687:8:1",
666 | "nodeType": "VariableDeclaration",
667 | "scope": 55,
668 | "src": "2679:16:1",
669 | "stateVariable": false,
670 | "storageLocation": "default",
671 | "typeDescriptions": {
672 | "typeIdentifier": "t_address",
673 | "typeString": "address"
674 | },
675 | "typeName": {
676 | "id": 43,
677 | "name": "address",
678 | "nodeType": "ElementaryTypeName",
679 | "src": "2679:7:1",
680 | "stateMutability": "nonpayable",
681 | "typeDescriptions": {
682 | "typeIdentifier": "t_address",
683 | "typeString": "address"
684 | }
685 | },
686 | "visibility": "internal"
687 | },
688 | {
689 | "constant": false,
690 | "id": 46,
691 | "mutability": "mutable",
692 | "name": "fee",
693 | "nameLocation": "2712:3:1",
694 | "nodeType": "VariableDeclaration",
695 | "scope": 55,
696 | "src": "2705:10:1",
697 | "stateVariable": false,
698 | "storageLocation": "default",
699 | "typeDescriptions": {
700 | "typeIdentifier": "t_uint24",
701 | "typeString": "uint24"
702 | },
703 | "typeName": {
704 | "id": 45,
705 | "name": "uint24",
706 | "nodeType": "ElementaryTypeName",
707 | "src": "2705:6:1",
708 | "typeDescriptions": {
709 | "typeIdentifier": "t_uint24",
710 | "typeString": "uint24"
711 | }
712 | },
713 | "visibility": "internal"
714 | },
715 | {
716 | "constant": false,
717 | "id": 48,
718 | "mutability": "mutable",
719 | "name": "amountOut",
720 | "nameLocation": "2733:9:1",
721 | "nodeType": "VariableDeclaration",
722 | "scope": 55,
723 | "src": "2725:17:1",
724 | "stateVariable": false,
725 | "storageLocation": "default",
726 | "typeDescriptions": {
727 | "typeIdentifier": "t_uint256",
728 | "typeString": "uint256"
729 | },
730 | "typeName": {
731 | "id": 47,
732 | "name": "uint256",
733 | "nodeType": "ElementaryTypeName",
734 | "src": "2725:7:1",
735 | "typeDescriptions": {
736 | "typeIdentifier": "t_uint256",
737 | "typeString": "uint256"
738 | }
739 | },
740 | "visibility": "internal"
741 | },
742 | {
743 | "constant": false,
744 | "id": 50,
745 | "mutability": "mutable",
746 | "name": "sqrtPriceLimitX96",
747 | "nameLocation": "2760:17:1",
748 | "nodeType": "VariableDeclaration",
749 | "scope": 55,
750 | "src": "2752:25:1",
751 | "stateVariable": false,
752 | "storageLocation": "default",
753 | "typeDescriptions": {
754 | "typeIdentifier": "t_uint160",
755 | "typeString": "uint160"
756 | },
757 | "typeName": {
758 | "id": 49,
759 | "name": "uint160",
760 | "nodeType": "ElementaryTypeName",
761 | "src": "2752:7:1",
762 | "typeDescriptions": {
763 | "typeIdentifier": "t_uint160",
764 | "typeString": "uint160"
765 | }
766 | },
767 | "visibility": "internal"
768 | }
769 | ],
770 | "src": "2644:139:1"
771 | },
772 | "returnParameters": {
773 | "id": 54,
774 | "nodeType": "ParameterList",
775 | "parameters": [
776 | {
777 | "constant": false,
778 | "id": 53,
779 | "mutability": "mutable",
780 | "name": "amountIn",
781 | "nameLocation": "2810:8:1",
782 | "nodeType": "VariableDeclaration",
783 | "scope": 55,
784 | "src": "2802:16:1",
785 | "stateVariable": false,
786 | "storageLocation": "default",
787 | "typeDescriptions": {
788 | "typeIdentifier": "t_uint256",
789 | "typeString": "uint256"
790 | },
791 | "typeName": {
792 | "id": 52,
793 | "name": "uint256",
794 | "nodeType": "ElementaryTypeName",
795 | "src": "2802:7:1",
796 | "typeDescriptions": {
797 | "typeIdentifier": "t_uint256",
798 | "typeString": "uint256"
799 | }
800 | },
801 | "visibility": "internal"
802 | }
803 | ],
804 | "src": "2801:18:1"
805 | },
806 | "scope": 56,
807 | "src": "2613:207:1",
808 | "stateMutability": "nonpayable",
809 | "virtual": false,
810 | "visibility": "external"
811 | }
812 | ],
813 | "scope": 57,
814 | "src": "411:2411:1",
815 | "usedErrors": []
816 | }
817 | ],
818 | "src": "45:2778:1"
819 | },
820 | "contractName": "IQuoter",
821 | "dependencies": [],
822 | "offset": [
823 | 411,
824 | 2822
825 | ],
826 | "sha1": "ceb9e5faaa7a24c3d862871705d3893b833b0f25",
827 | "source": "// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity >=0.7.5;\npragma abicoder v2;\n\n/// @title Quoter Interface\n/// @notice Supports quoting the calculated amounts from exact input or exact output swaps\n/// @dev These functions are not marked view because they rely on calling non-view functions and reverting\n/// to compute the result. They are also not gas efficient and should not be called on-chain.\ninterface IQuoter {\n /// @notice Returns the amount out received for a given exact input swap without executing the swap\n /// @param path The path of the swap, i.e. each token pair and the pool fee\n /// @param amountIn The amount of the first token to swap\n /// @return amountOut The amount of the last token that would be received\n function quoteExactInput(bytes memory path, uint256 amountIn)\n external\n returns (uint256 amountOut);\n\n /// @notice Returns the amount out received for a given exact input but for a swap of a single pool\n /// @param tokenIn The token being swapped in\n /// @param tokenOut The token being swapped out\n /// @param fee The fee of the token pool to consider for the pair\n /// @param amountIn The desired input amount\n /// @param sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap\n /// @return amountOut The amount of `tokenOut` that would be received\n function quoteExactInputSingle(\n address tokenIn,\n address tokenOut,\n uint24 fee,\n uint256 amountIn,\n uint160 sqrtPriceLimitX96\n ) external returns (uint256 amountOut);\n\n /// @notice Returns the amount in required for a given exact output swap without executing the swap\n /// @param path The path of the swap, i.e. each token pair and the pool fee. Path must be provided in reverse order\n /// @param amountOut The amount of the last token to receive\n /// @return amountIn The amount of first token required to be paid\n function quoteExactOutput(bytes memory path, uint256 amountOut)\n external\n returns (uint256 amountIn);\n\n /// @notice Returns the amount in required to receive the given exact output amount but for a swap of a single pool\n /// @param tokenIn The token being swapped in\n /// @param tokenOut The token being swapped out\n /// @param fee The fee of the token pool to consider for the pair\n /// @param amountOut The desired output amount\n /// @param sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap\n /// @return amountIn The amount required as the input for the swap in order to receive `amountOut`\n function quoteExactOutputSingle(\n address tokenIn,\n address tokenOut,\n uint24 fee,\n uint256 amountOut,\n uint160 sqrtPriceLimitX96\n ) external returns (uint256 amountIn);\n}\n",
828 | "type": "interface"
829 | }
--------------------------------------------------------------------------------
/front-end/README.md:
--------------------------------------------------------------------------------
1 | # Getting Started with Create React App
2 |
3 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
4 |
5 | ## Available Scripts
6 |
7 | In the project directory, you can run:
8 |
9 | ### `npm start`
10 |
11 | Runs the app in the development mode.\
12 | Open [http://localhost:3000](http://localhost:3000) to view it in your browser.
13 |
14 | The page will reload when you make changes.\
15 | You may also see any lint errors in the console.
16 |
17 | ### `npm test`
18 |
19 | Launches the test runner in the interactive watch mode.\
20 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
21 |
22 | ### `npm run build`
23 |
24 | Builds the app for production to the `build` folder.\
25 | It correctly bundles React in production mode and optimizes the build for the best performance.
26 |
27 | The build is minified and the filenames include the hashes.\
28 | Your app is ready to be deployed!
29 |
30 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
31 |
32 | ### `npm run eject`
33 |
34 | **Note: this is a one-way operation. Once you `eject`, you can't go back!**
35 |
36 | If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
37 |
38 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own.
39 |
40 | You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it.
41 |
42 | ## Learn More
43 |
44 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
45 |
46 | To learn React, check out the [React documentation](https://reactjs.org/).
47 |
48 | ### Code Splitting
49 |
50 | This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting)
51 |
52 | ### Analyzing the Bundle Size
53 |
54 | This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size)
55 |
56 | ### Making a Progressive Web App
57 |
58 | This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app)
59 |
60 | ### Advanced Configuration
61 |
62 | This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration)
63 |
64 | ### Deployment
65 |
66 | This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment)
67 |
68 | ### `npm run build` fails to minify
69 |
70 | This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)
71 |
--------------------------------------------------------------------------------
/front-end/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "front-end",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@emotion/react": "^11.9.0",
7 | "@emotion/styled": "^11.8.1",
8 | "@mui/material": "^5.6.0",
9 | "@reduxjs/toolkit": "^1.8.1",
10 | "@testing-library/jest-dom": "^5.16.4",
11 | "@testing-library/react": "^12.1.4",
12 | "@testing-library/user-event": "^13.5.0",
13 | "bootstrap": "^5.1.3",
14 | "ethers": "^5.6.2",
15 | "framer-motion": "^6.2.9",
16 | "moment": "^2.29.3",
17 | "react": "^18.0.0",
18 | "react-bootstrap": "^2.2.3",
19 | "react-dom": "^18.0.0",
20 | "react-redux": "^7.2.8",
21 | "react-scripts": "5.0.0",
22 | "redux": "^4.1.2",
23 | "redux-persist": "^6.0.0",
24 | "styled-components": "^5.3.5",
25 | "web-vitals": "^2.1.4",
26 | "web3modal": "^1.9.6"
27 | },
28 | "scripts": {
29 | "start": "react-scripts start",
30 | "build": "react-scripts build",
31 | "test": "react-scripts test",
32 | "eject": "react-scripts eject"
33 | },
34 | "eslintConfig": {
35 | "extends": [
36 | "react-app",
37 | "react-app/jest"
38 | ]
39 | },
40 | "browserslist": {
41 | "production": [
42 | ">0.2%",
43 | "not dead",
44 | "not op_mini all"
45 | ],
46 | "development": [
47 | "last 1 chrome version",
48 | "last 1 firefox version",
49 | "last 1 safari version"
50 | ]
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/front-end/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kaymen99/Dex-aggregator/f9f1478ec780196f5b4248535bccbf05b513fcc3/front-end/public/favicon.ico
--------------------------------------------------------------------------------
/front-end/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | React App
28 |
29 |
30 | You need to enable JavaScript to run this app.
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/front-end/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kaymen99/Dex-aggregator/f9f1478ec780196f5b4248535bccbf05b513fcc3/front-end/public/logo192.png
--------------------------------------------------------------------------------
/front-end/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kaymen99/Dex-aggregator/f9f1478ec780196f5b4248535bccbf05b513fcc3/front-end/public/logo512.png
--------------------------------------------------------------------------------
/front-end/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/front-end/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/front-end/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | height: 40vmin;
7 | pointer-events: none;
8 | }
9 |
10 | /*
11 | body {
12 | background: rgb(30, 30, 30) !important;
13 | }
14 | */
15 |
16 |
17 | @media (prefers-reduced-motion: no-preference) {
18 | .App-logo {
19 | animation: App-logo-spin infinite 20s linear;
20 | }
21 | }
22 |
23 | .App-header {
24 | background-color: #282c34;
25 | min-height: 100vh;
26 | display: flex;
27 | flex-direction: column;
28 | align-items: center;
29 | justify-content: center;
30 | font-size: calc(10px + 2vmin);
31 | color: white;
32 | }
33 |
34 | .App-link {
35 | color: #61dafb;
36 | }
37 |
38 | @keyframes App-logo-spin {
39 | from {
40 | transform: rotate(0deg);
41 | }
42 |
43 | to {
44 | transform: rotate(360deg);
45 | }
46 | }
--------------------------------------------------------------------------------
/front-end/src/App.js:
--------------------------------------------------------------------------------
1 | import './App.css';
2 | import Main from "./components/Main";
3 | import Swap from './components/Swap';
4 |
5 | function App() {
6 |
7 | return (
8 |
9 |
10 |
11 |
12 |
Multi-Chain Dex Aggregator
13 |
14 |
15 |
16 | );
17 | }
18 |
19 | export default App;
20 |
21 |
--------------------------------------------------------------------------------
/front-end/src/App.test.js:
--------------------------------------------------------------------------------
1 | import { render, screen } from '@testing-library/react';
2 | import App from './App';
3 |
4 | test('renders learn react link', () => {
5 | render( );
6 | const linkElement = screen.getByText(/learn react/i);
7 | expect(linkElement).toBeInTheDocument();
8 | });
9 |
--------------------------------------------------------------------------------
/front-end/src/artifacts/interfaces/IQuoter.json:
--------------------------------------------------------------------------------
1 | {
2 | "abi": [
3 | {
4 | "inputs": [
5 | {
6 | "internalType": "bytes",
7 | "name": "path",
8 | "type": "bytes"
9 | },
10 | {
11 | "internalType": "uint256",
12 | "name": "amountIn",
13 | "type": "uint256"
14 | }
15 | ],
16 | "name": "quoteExactInput",
17 | "outputs": [
18 | {
19 | "internalType": "uint256",
20 | "name": "amountOut",
21 | "type": "uint256"
22 | }
23 | ],
24 | "stateMutability": "nonpayable",
25 | "type": "function"
26 | },
27 | {
28 | "inputs": [
29 | {
30 | "internalType": "address",
31 | "name": "tokenIn",
32 | "type": "address"
33 | },
34 | {
35 | "internalType": "address",
36 | "name": "tokenOut",
37 | "type": "address"
38 | },
39 | {
40 | "internalType": "uint24",
41 | "name": "fee",
42 | "type": "uint24"
43 | },
44 | {
45 | "internalType": "uint256",
46 | "name": "amountIn",
47 | "type": "uint256"
48 | },
49 | {
50 | "internalType": "uint160",
51 | "name": "sqrtPriceLimitX96",
52 | "type": "uint160"
53 | }
54 | ],
55 | "name": "quoteExactInputSingle",
56 | "outputs": [
57 | {
58 | "internalType": "uint256",
59 | "name": "amountOut",
60 | "type": "uint256"
61 | }
62 | ],
63 | "stateMutability": "nonpayable",
64 | "type": "function"
65 | },
66 | {
67 | "inputs": [
68 | {
69 | "internalType": "bytes",
70 | "name": "path",
71 | "type": "bytes"
72 | },
73 | {
74 | "internalType": "uint256",
75 | "name": "amountOut",
76 | "type": "uint256"
77 | }
78 | ],
79 | "name": "quoteExactOutput",
80 | "outputs": [
81 | {
82 | "internalType": "uint256",
83 | "name": "amountIn",
84 | "type": "uint256"
85 | }
86 | ],
87 | "stateMutability": "nonpayable",
88 | "type": "function"
89 | },
90 | {
91 | "inputs": [
92 | {
93 | "internalType": "address",
94 | "name": "tokenIn",
95 | "type": "address"
96 | },
97 | {
98 | "internalType": "address",
99 | "name": "tokenOut",
100 | "type": "address"
101 | },
102 | {
103 | "internalType": "uint24",
104 | "name": "fee",
105 | "type": "uint24"
106 | },
107 | {
108 | "internalType": "uint256",
109 | "name": "amountOut",
110 | "type": "uint256"
111 | },
112 | {
113 | "internalType": "uint160",
114 | "name": "sqrtPriceLimitX96",
115 | "type": "uint160"
116 | }
117 | ],
118 | "name": "quoteExactOutputSingle",
119 | "outputs": [
120 | {
121 | "internalType": "uint256",
122 | "name": "amountIn",
123 | "type": "uint256"
124 | }
125 | ],
126 | "stateMutability": "nonpayable",
127 | "type": "function"
128 | }
129 | ],
130 | "ast": {
131 | "absolutePath": "interfaces/IQouter.sol",
132 | "exportedSymbols": {
133 | "IQuoter": [
134 | 56
135 | ]
136 | },
137 | "id": 57,
138 | "license": "GPL-2.0-or-later",
139 | "nodeType": "SourceUnit",
140 | "nodes": [
141 | {
142 | "id": 1,
143 | "literals": [
144 | "solidity",
145 | ">=",
146 | "0.7",
147 | ".5"
148 | ],
149 | "nodeType": "PragmaDirective",
150 | "src": "45:24:1"
151 | },
152 | {
153 | "id": 2,
154 | "literals": [
155 | "abicoder",
156 | "v2"
157 | ],
158 | "nodeType": "PragmaDirective",
159 | "src": "70:19:1"
160 | },
161 | {
162 | "abstract": false,
163 | "baseContracts": [],
164 | "canonicalName": "IQuoter",
165 | "contractDependencies": [],
166 | "contractKind": "interface",
167 | "documentation": {
168 | "id": 3,
169 | "nodeType": "StructuredDocumentation",
170 | "src": "91:320:1",
171 | "text": "@title Quoter Interface\n @notice Supports quoting the calculated amounts from exact input or exact output swaps\n @dev These functions are not marked view because they rely on calling non-view functions and reverting\n to compute the result. They are also not gas efficient and should not be called on-chain."
172 | },
173 | "fullyImplemented": false,
174 | "id": 56,
175 | "linearizedBaseContracts": [
176 | 56
177 | ],
178 | "name": "IQuoter",
179 | "nameLocation": "421:7:1",
180 | "nodeType": "ContractDefinition",
181 | "nodes": [
182 | {
183 | "documentation": {
184 | "id": 4,
185 | "nodeType": "StructuredDocumentation",
186 | "src": "435:319:1",
187 | "text": "@notice Returns the amount out received for a given exact input swap without executing the swap\n @param path The path of the swap, i.e. each token pair and the pool fee\n @param amountIn The amount of the first token to swap\n @return amountOut The amount of the last token that would be received"
188 | },
189 | "functionSelector": "cdca1753",
190 | "id": 13,
191 | "implemented": false,
192 | "kind": "function",
193 | "modifiers": [],
194 | "name": "quoteExactInput",
195 | "nameLocation": "768:15:1",
196 | "nodeType": "FunctionDefinition",
197 | "parameters": {
198 | "id": 9,
199 | "nodeType": "ParameterList",
200 | "parameters": [
201 | {
202 | "constant": false,
203 | "id": 6,
204 | "mutability": "mutable",
205 | "name": "path",
206 | "nameLocation": "797:4:1",
207 | "nodeType": "VariableDeclaration",
208 | "scope": 13,
209 | "src": "784:17:1",
210 | "stateVariable": false,
211 | "storageLocation": "memory",
212 | "typeDescriptions": {
213 | "typeIdentifier": "t_bytes_memory_ptr",
214 | "typeString": "bytes"
215 | },
216 | "typeName": {
217 | "id": 5,
218 | "name": "bytes",
219 | "nodeType": "ElementaryTypeName",
220 | "src": "784:5:1",
221 | "typeDescriptions": {
222 | "typeIdentifier": "t_bytes_storage_ptr",
223 | "typeString": "bytes"
224 | }
225 | },
226 | "visibility": "internal"
227 | },
228 | {
229 | "constant": false,
230 | "id": 8,
231 | "mutability": "mutable",
232 | "name": "amountIn",
233 | "nameLocation": "811:8:1",
234 | "nodeType": "VariableDeclaration",
235 | "scope": 13,
236 | "src": "803:16:1",
237 | "stateVariable": false,
238 | "storageLocation": "default",
239 | "typeDescriptions": {
240 | "typeIdentifier": "t_uint256",
241 | "typeString": "uint256"
242 | },
243 | "typeName": {
244 | "id": 7,
245 | "name": "uint256",
246 | "nodeType": "ElementaryTypeName",
247 | "src": "803:7:1",
248 | "typeDescriptions": {
249 | "typeIdentifier": "t_uint256",
250 | "typeString": "uint256"
251 | }
252 | },
253 | "visibility": "internal"
254 | }
255 | ],
256 | "src": "783:37:1"
257 | },
258 | "returnParameters": {
259 | "id": 12,
260 | "nodeType": "ParameterList",
261 | "parameters": [
262 | {
263 | "constant": false,
264 | "id": 11,
265 | "mutability": "mutable",
266 | "name": "amountOut",
267 | "nameLocation": "863:9:1",
268 | "nodeType": "VariableDeclaration",
269 | "scope": 13,
270 | "src": "855:17:1",
271 | "stateVariable": false,
272 | "storageLocation": "default",
273 | "typeDescriptions": {
274 | "typeIdentifier": "t_uint256",
275 | "typeString": "uint256"
276 | },
277 | "typeName": {
278 | "id": 10,
279 | "name": "uint256",
280 | "nodeType": "ElementaryTypeName",
281 | "src": "855:7:1",
282 | "typeDescriptions": {
283 | "typeIdentifier": "t_uint256",
284 | "typeString": "uint256"
285 | }
286 | },
287 | "visibility": "internal"
288 | }
289 | ],
290 | "src": "854:19:1"
291 | },
292 | "scope": 56,
293 | "src": "759:115:1",
294 | "stateMutability": "nonpayable",
295 | "virtual": false,
296 | "visibility": "external"
297 | },
298 | {
299 | "documentation": {
300 | "id": 14,
301 | "nodeType": "StructuredDocumentation",
302 | "src": "880:491:1",
303 | "text": "@notice Returns the amount out received for a given exact input but for a swap of a single pool\n @param tokenIn The token being swapped in\n @param tokenOut The token being swapped out\n @param fee The fee of the token pool to consider for the pair\n @param amountIn The desired input amount\n @param sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap\n @return amountOut The amount of `tokenOut` that would be received"
304 | },
305 | "functionSelector": "f7729d43",
306 | "id": 29,
307 | "implemented": false,
308 | "kind": "function",
309 | "modifiers": [],
310 | "name": "quoteExactInputSingle",
311 | "nameLocation": "1385:21:1",
312 | "nodeType": "FunctionDefinition",
313 | "parameters": {
314 | "id": 25,
315 | "nodeType": "ParameterList",
316 | "parameters": [
317 | {
318 | "constant": false,
319 | "id": 16,
320 | "mutability": "mutable",
321 | "name": "tokenIn",
322 | "nameLocation": "1424:7:1",
323 | "nodeType": "VariableDeclaration",
324 | "scope": 29,
325 | "src": "1416:15:1",
326 | "stateVariable": false,
327 | "storageLocation": "default",
328 | "typeDescriptions": {
329 | "typeIdentifier": "t_address",
330 | "typeString": "address"
331 | },
332 | "typeName": {
333 | "id": 15,
334 | "name": "address",
335 | "nodeType": "ElementaryTypeName",
336 | "src": "1416:7:1",
337 | "stateMutability": "nonpayable",
338 | "typeDescriptions": {
339 | "typeIdentifier": "t_address",
340 | "typeString": "address"
341 | }
342 | },
343 | "visibility": "internal"
344 | },
345 | {
346 | "constant": false,
347 | "id": 18,
348 | "mutability": "mutable",
349 | "name": "tokenOut",
350 | "nameLocation": "1449:8:1",
351 | "nodeType": "VariableDeclaration",
352 | "scope": 29,
353 | "src": "1441:16:1",
354 | "stateVariable": false,
355 | "storageLocation": "default",
356 | "typeDescriptions": {
357 | "typeIdentifier": "t_address",
358 | "typeString": "address"
359 | },
360 | "typeName": {
361 | "id": 17,
362 | "name": "address",
363 | "nodeType": "ElementaryTypeName",
364 | "src": "1441:7:1",
365 | "stateMutability": "nonpayable",
366 | "typeDescriptions": {
367 | "typeIdentifier": "t_address",
368 | "typeString": "address"
369 | }
370 | },
371 | "visibility": "internal"
372 | },
373 | {
374 | "constant": false,
375 | "id": 20,
376 | "mutability": "mutable",
377 | "name": "fee",
378 | "nameLocation": "1474:3:1",
379 | "nodeType": "VariableDeclaration",
380 | "scope": 29,
381 | "src": "1467:10:1",
382 | "stateVariable": false,
383 | "storageLocation": "default",
384 | "typeDescriptions": {
385 | "typeIdentifier": "t_uint24",
386 | "typeString": "uint24"
387 | },
388 | "typeName": {
389 | "id": 19,
390 | "name": "uint24",
391 | "nodeType": "ElementaryTypeName",
392 | "src": "1467:6:1",
393 | "typeDescriptions": {
394 | "typeIdentifier": "t_uint24",
395 | "typeString": "uint24"
396 | }
397 | },
398 | "visibility": "internal"
399 | },
400 | {
401 | "constant": false,
402 | "id": 22,
403 | "mutability": "mutable",
404 | "name": "amountIn",
405 | "nameLocation": "1495:8:1",
406 | "nodeType": "VariableDeclaration",
407 | "scope": 29,
408 | "src": "1487:16:1",
409 | "stateVariable": false,
410 | "storageLocation": "default",
411 | "typeDescriptions": {
412 | "typeIdentifier": "t_uint256",
413 | "typeString": "uint256"
414 | },
415 | "typeName": {
416 | "id": 21,
417 | "name": "uint256",
418 | "nodeType": "ElementaryTypeName",
419 | "src": "1487:7:1",
420 | "typeDescriptions": {
421 | "typeIdentifier": "t_uint256",
422 | "typeString": "uint256"
423 | }
424 | },
425 | "visibility": "internal"
426 | },
427 | {
428 | "constant": false,
429 | "id": 24,
430 | "mutability": "mutable",
431 | "name": "sqrtPriceLimitX96",
432 | "nameLocation": "1521:17:1",
433 | "nodeType": "VariableDeclaration",
434 | "scope": 29,
435 | "src": "1513:25:1",
436 | "stateVariable": false,
437 | "storageLocation": "default",
438 | "typeDescriptions": {
439 | "typeIdentifier": "t_uint160",
440 | "typeString": "uint160"
441 | },
442 | "typeName": {
443 | "id": 23,
444 | "name": "uint160",
445 | "nodeType": "ElementaryTypeName",
446 | "src": "1513:7:1",
447 | "typeDescriptions": {
448 | "typeIdentifier": "t_uint160",
449 | "typeString": "uint160"
450 | }
451 | },
452 | "visibility": "internal"
453 | }
454 | ],
455 | "src": "1406:138:1"
456 | },
457 | "returnParameters": {
458 | "id": 28,
459 | "nodeType": "ParameterList",
460 | "parameters": [
461 | {
462 | "constant": false,
463 | "id": 27,
464 | "mutability": "mutable",
465 | "name": "amountOut",
466 | "nameLocation": "1571:9:1",
467 | "nodeType": "VariableDeclaration",
468 | "scope": 29,
469 | "src": "1563:17:1",
470 | "stateVariable": false,
471 | "storageLocation": "default",
472 | "typeDescriptions": {
473 | "typeIdentifier": "t_uint256",
474 | "typeString": "uint256"
475 | },
476 | "typeName": {
477 | "id": 26,
478 | "name": "uint256",
479 | "nodeType": "ElementaryTypeName",
480 | "src": "1563:7:1",
481 | "typeDescriptions": {
482 | "typeIdentifier": "t_uint256",
483 | "typeString": "uint256"
484 | }
485 | },
486 | "visibility": "internal"
487 | }
488 | ],
489 | "src": "1562:19:1"
490 | },
491 | "scope": 56,
492 | "src": "1376:206:1",
493 | "stateMutability": "nonpayable",
494 | "virtual": false,
495 | "visibility": "external"
496 | },
497 | {
498 | "documentation": {
499 | "id": 30,
500 | "nodeType": "StructuredDocumentation",
501 | "src": "1588:355:1",
502 | "text": "@notice Returns the amount in required for a given exact output swap without executing the swap\n @param path The path of the swap, i.e. each token pair and the pool fee. Path must be provided in reverse order\n @param amountOut The amount of the last token to receive\n @return amountIn The amount of first token required to be paid"
503 | },
504 | "functionSelector": "2f80bb1d",
505 | "id": 39,
506 | "implemented": false,
507 | "kind": "function",
508 | "modifiers": [],
509 | "name": "quoteExactOutput",
510 | "nameLocation": "1957:16:1",
511 | "nodeType": "FunctionDefinition",
512 | "parameters": {
513 | "id": 35,
514 | "nodeType": "ParameterList",
515 | "parameters": [
516 | {
517 | "constant": false,
518 | "id": 32,
519 | "mutability": "mutable",
520 | "name": "path",
521 | "nameLocation": "1987:4:1",
522 | "nodeType": "VariableDeclaration",
523 | "scope": 39,
524 | "src": "1974:17:1",
525 | "stateVariable": false,
526 | "storageLocation": "memory",
527 | "typeDescriptions": {
528 | "typeIdentifier": "t_bytes_memory_ptr",
529 | "typeString": "bytes"
530 | },
531 | "typeName": {
532 | "id": 31,
533 | "name": "bytes",
534 | "nodeType": "ElementaryTypeName",
535 | "src": "1974:5:1",
536 | "typeDescriptions": {
537 | "typeIdentifier": "t_bytes_storage_ptr",
538 | "typeString": "bytes"
539 | }
540 | },
541 | "visibility": "internal"
542 | },
543 | {
544 | "constant": false,
545 | "id": 34,
546 | "mutability": "mutable",
547 | "name": "amountOut",
548 | "nameLocation": "2001:9:1",
549 | "nodeType": "VariableDeclaration",
550 | "scope": 39,
551 | "src": "1993:17:1",
552 | "stateVariable": false,
553 | "storageLocation": "default",
554 | "typeDescriptions": {
555 | "typeIdentifier": "t_uint256",
556 | "typeString": "uint256"
557 | },
558 | "typeName": {
559 | "id": 33,
560 | "name": "uint256",
561 | "nodeType": "ElementaryTypeName",
562 | "src": "1993:7:1",
563 | "typeDescriptions": {
564 | "typeIdentifier": "t_uint256",
565 | "typeString": "uint256"
566 | }
567 | },
568 | "visibility": "internal"
569 | }
570 | ],
571 | "src": "1973:38:1"
572 | },
573 | "returnParameters": {
574 | "id": 38,
575 | "nodeType": "ParameterList",
576 | "parameters": [
577 | {
578 | "constant": false,
579 | "id": 37,
580 | "mutability": "mutable",
581 | "name": "amountIn",
582 | "nameLocation": "2054:8:1",
583 | "nodeType": "VariableDeclaration",
584 | "scope": 39,
585 | "src": "2046:16:1",
586 | "stateVariable": false,
587 | "storageLocation": "default",
588 | "typeDescriptions": {
589 | "typeIdentifier": "t_uint256",
590 | "typeString": "uint256"
591 | },
592 | "typeName": {
593 | "id": 36,
594 | "name": "uint256",
595 | "nodeType": "ElementaryTypeName",
596 | "src": "2046:7:1",
597 | "typeDescriptions": {
598 | "typeIdentifier": "t_uint256",
599 | "typeString": "uint256"
600 | }
601 | },
602 | "visibility": "internal"
603 | }
604 | ],
605 | "src": "2045:18:1"
606 | },
607 | "scope": 56,
608 | "src": "1948:116:1",
609 | "stateMutability": "nonpayable",
610 | "virtual": false,
611 | "visibility": "external"
612 | },
613 | {
614 | "documentation": {
615 | "id": 40,
616 | "nodeType": "StructuredDocumentation",
617 | "src": "2070:538:1",
618 | "text": "@notice Returns the amount in required to receive the given exact output amount but for a swap of a single pool\n @param tokenIn The token being swapped in\n @param tokenOut The token being swapped out\n @param fee The fee of the token pool to consider for the pair\n @param amountOut The desired output amount\n @param sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap\n @return amountIn The amount required as the input for the swap in order to receive `amountOut`"
619 | },
620 | "functionSelector": "30d07f21",
621 | "id": 55,
622 | "implemented": false,
623 | "kind": "function",
624 | "modifiers": [],
625 | "name": "quoteExactOutputSingle",
626 | "nameLocation": "2622:22:1",
627 | "nodeType": "FunctionDefinition",
628 | "parameters": {
629 | "id": 51,
630 | "nodeType": "ParameterList",
631 | "parameters": [
632 | {
633 | "constant": false,
634 | "id": 42,
635 | "mutability": "mutable",
636 | "name": "tokenIn",
637 | "nameLocation": "2662:7:1",
638 | "nodeType": "VariableDeclaration",
639 | "scope": 55,
640 | "src": "2654:15:1",
641 | "stateVariable": false,
642 | "storageLocation": "default",
643 | "typeDescriptions": {
644 | "typeIdentifier": "t_address",
645 | "typeString": "address"
646 | },
647 | "typeName": {
648 | "id": 41,
649 | "name": "address",
650 | "nodeType": "ElementaryTypeName",
651 | "src": "2654:7:1",
652 | "stateMutability": "nonpayable",
653 | "typeDescriptions": {
654 | "typeIdentifier": "t_address",
655 | "typeString": "address"
656 | }
657 | },
658 | "visibility": "internal"
659 | },
660 | {
661 | "constant": false,
662 | "id": 44,
663 | "mutability": "mutable",
664 | "name": "tokenOut",
665 | "nameLocation": "2687:8:1",
666 | "nodeType": "VariableDeclaration",
667 | "scope": 55,
668 | "src": "2679:16:1",
669 | "stateVariable": false,
670 | "storageLocation": "default",
671 | "typeDescriptions": {
672 | "typeIdentifier": "t_address",
673 | "typeString": "address"
674 | },
675 | "typeName": {
676 | "id": 43,
677 | "name": "address",
678 | "nodeType": "ElementaryTypeName",
679 | "src": "2679:7:1",
680 | "stateMutability": "nonpayable",
681 | "typeDescriptions": {
682 | "typeIdentifier": "t_address",
683 | "typeString": "address"
684 | }
685 | },
686 | "visibility": "internal"
687 | },
688 | {
689 | "constant": false,
690 | "id": 46,
691 | "mutability": "mutable",
692 | "name": "fee",
693 | "nameLocation": "2712:3:1",
694 | "nodeType": "VariableDeclaration",
695 | "scope": 55,
696 | "src": "2705:10:1",
697 | "stateVariable": false,
698 | "storageLocation": "default",
699 | "typeDescriptions": {
700 | "typeIdentifier": "t_uint24",
701 | "typeString": "uint24"
702 | },
703 | "typeName": {
704 | "id": 45,
705 | "name": "uint24",
706 | "nodeType": "ElementaryTypeName",
707 | "src": "2705:6:1",
708 | "typeDescriptions": {
709 | "typeIdentifier": "t_uint24",
710 | "typeString": "uint24"
711 | }
712 | },
713 | "visibility": "internal"
714 | },
715 | {
716 | "constant": false,
717 | "id": 48,
718 | "mutability": "mutable",
719 | "name": "amountOut",
720 | "nameLocation": "2733:9:1",
721 | "nodeType": "VariableDeclaration",
722 | "scope": 55,
723 | "src": "2725:17:1",
724 | "stateVariable": false,
725 | "storageLocation": "default",
726 | "typeDescriptions": {
727 | "typeIdentifier": "t_uint256",
728 | "typeString": "uint256"
729 | },
730 | "typeName": {
731 | "id": 47,
732 | "name": "uint256",
733 | "nodeType": "ElementaryTypeName",
734 | "src": "2725:7:1",
735 | "typeDescriptions": {
736 | "typeIdentifier": "t_uint256",
737 | "typeString": "uint256"
738 | }
739 | },
740 | "visibility": "internal"
741 | },
742 | {
743 | "constant": false,
744 | "id": 50,
745 | "mutability": "mutable",
746 | "name": "sqrtPriceLimitX96",
747 | "nameLocation": "2760:17:1",
748 | "nodeType": "VariableDeclaration",
749 | "scope": 55,
750 | "src": "2752:25:1",
751 | "stateVariable": false,
752 | "storageLocation": "default",
753 | "typeDescriptions": {
754 | "typeIdentifier": "t_uint160",
755 | "typeString": "uint160"
756 | },
757 | "typeName": {
758 | "id": 49,
759 | "name": "uint160",
760 | "nodeType": "ElementaryTypeName",
761 | "src": "2752:7:1",
762 | "typeDescriptions": {
763 | "typeIdentifier": "t_uint160",
764 | "typeString": "uint160"
765 | }
766 | },
767 | "visibility": "internal"
768 | }
769 | ],
770 | "src": "2644:139:1"
771 | },
772 | "returnParameters": {
773 | "id": 54,
774 | "nodeType": "ParameterList",
775 | "parameters": [
776 | {
777 | "constant": false,
778 | "id": 53,
779 | "mutability": "mutable",
780 | "name": "amountIn",
781 | "nameLocation": "2810:8:1",
782 | "nodeType": "VariableDeclaration",
783 | "scope": 55,
784 | "src": "2802:16:1",
785 | "stateVariable": false,
786 | "storageLocation": "default",
787 | "typeDescriptions": {
788 | "typeIdentifier": "t_uint256",
789 | "typeString": "uint256"
790 | },
791 | "typeName": {
792 | "id": 52,
793 | "name": "uint256",
794 | "nodeType": "ElementaryTypeName",
795 | "src": "2802:7:1",
796 | "typeDescriptions": {
797 | "typeIdentifier": "t_uint256",
798 | "typeString": "uint256"
799 | }
800 | },
801 | "visibility": "internal"
802 | }
803 | ],
804 | "src": "2801:18:1"
805 | },
806 | "scope": 56,
807 | "src": "2613:207:1",
808 | "stateMutability": "nonpayable",
809 | "virtual": false,
810 | "visibility": "external"
811 | }
812 | ],
813 | "scope": 57,
814 | "src": "411:2411:1",
815 | "usedErrors": []
816 | }
817 | ],
818 | "src": "45:2778:1"
819 | },
820 | "contractName": "IQuoter",
821 | "dependencies": [],
822 | "offset": [
823 | 411,
824 | 2822
825 | ],
826 | "sha1": "ceb9e5faaa7a24c3d862871705d3893b833b0f25",
827 | "source": "// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity >=0.7.5;\npragma abicoder v2;\n\n/// @title Quoter Interface\n/// @notice Supports quoting the calculated amounts from exact input or exact output swaps\n/// @dev These functions are not marked view because they rely on calling non-view functions and reverting\n/// to compute the result. They are also not gas efficient and should not be called on-chain.\ninterface IQuoter {\n /// @notice Returns the amount out received for a given exact input swap without executing the swap\n /// @param path The path of the swap, i.e. each token pair and the pool fee\n /// @param amountIn The amount of the first token to swap\n /// @return amountOut The amount of the last token that would be received\n function quoteExactInput(bytes memory path, uint256 amountIn)\n external\n returns (uint256 amountOut);\n\n /// @notice Returns the amount out received for a given exact input but for a swap of a single pool\n /// @param tokenIn The token being swapped in\n /// @param tokenOut The token being swapped out\n /// @param fee The fee of the token pool to consider for the pair\n /// @param amountIn The desired input amount\n /// @param sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap\n /// @return amountOut The amount of `tokenOut` that would be received\n function quoteExactInputSingle(\n address tokenIn,\n address tokenOut,\n uint24 fee,\n uint256 amountIn,\n uint160 sqrtPriceLimitX96\n ) external returns (uint256 amountOut);\n\n /// @notice Returns the amount in required for a given exact output swap without executing the swap\n /// @param path The path of the swap, i.e. each token pair and the pool fee. Path must be provided in reverse order\n /// @param amountOut The amount of the last token to receive\n /// @return amountIn The amount of first token required to be paid\n function quoteExactOutput(bytes memory path, uint256 amountOut)\n external\n returns (uint256 amountIn);\n\n /// @notice Returns the amount in required to receive the given exact output amount but for a swap of a single pool\n /// @param tokenIn The token being swapped in\n /// @param tokenOut The token being swapped out\n /// @param fee The fee of the token pool to consider for the pair\n /// @param amountOut The desired output amount\n /// @param sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap\n /// @return amountIn The amount required as the input for the swap in order to receive `amountOut`\n function quoteExactOutputSingle(\n address tokenIn,\n address tokenOut,\n uint24 fee,\n uint256 amountOut,\n uint160 sqrtPriceLimitX96\n ) external returns (uint256 amountIn);\n}\n",
828 | "type": "interface"
829 | }
--------------------------------------------------------------------------------
/front-end/src/assets/css/styles.css:
--------------------------------------------------------------------------------
1 | /* header */
2 |
3 | .header {
4 | width: 100%;
5 | position: relative;
6 | padding-bottom: 2rem;
7 | }
8 |
9 | .header-container {
10 | width: 80%;
11 | min-height: 65vh;
12 | margin: 0 auto;
13 | display: flex;
14 | justify-content: center;
15 | align-items: center;
16 | }
17 |
18 | .header-box {
19 | width: 50%;
20 | height: 100%;
21 | display: flex;
22 | flex-direction: column;
23 | justify-content: center;
24 | align-items: center;
25 | }
26 |
27 | #window {
28 | width: 500px;
29 | margin-top: 50px;
30 | background-color: rgb(81, 76, 76);
31 | color: #fff;
32 | padding: 15px;
33 | border-radius: 20px;
34 | box-shadow: 0 0 5px black;
35 | }
36 |
37 | .swapbox_select {
38 | width: 70%;
39 | float: left;
40 | }
41 |
42 | .swapbox {
43 | overflow: auto;
44 | margin: 20px 0;
45 | padding: 20px;
46 | background-color: #2f2f2f;
47 | border-radius: 20px;
48 | border: 1px solid #565656;
49 | }
50 |
51 | .token_select {
52 | padding: 5px 0;
53 | width: 30%;
54 | }
55 |
56 | .token_select:hover {
57 | background-color: #464646;
58 | cursor: pointer;
59 | }
60 |
61 | .token_row {
62 | padding: 5px 10px;
63 | }
64 |
65 | .token_img {
66 | height: 30px;
67 | }
68 |
69 | .token_text {
70 | padding: 10px;
71 | }
72 |
73 | .token_row:hover {
74 | background-color: #e4e4e4;
75 | cursor: pointer;
76 | }
77 |
78 | .gas_estimate_label {
79 | padding-bottom: 10px;
80 | }
81 |
82 | .modal-body {
83 | overflow: scroll;
84 | }
85 |
86 | @media (max-width: 64em) {
87 | .header-container {
88 | flex-direction: column;
89 | width: 100%;
90 | }
91 |
92 | #window {
93 | width: 400px;
94 | margin-bottom: 35px;
95 | }
96 | }
97 |
98 | @media (max-width: 32em) {
99 | .header-container {
100 | flex-direction: column;
101 | width: 100%;
102 | }
103 |
104 | .header-box {
105 | width: 100%;
106 | }
107 |
108 | #window {
109 | width: 350px;
110 | margin-bottom: 35px;
111 | }
112 |
113 | .token_img {
114 | height: 25px;
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/front-end/src/assets/images/aave.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kaymen99/Dex-aggregator/f9f1478ec780196f5b4248535bccbf05b513fcc3/front-end/src/assets/images/aave.png
--------------------------------------------------------------------------------
/front-end/src/assets/images/bnb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kaymen99/Dex-aggregator/f9f1478ec780196f5b4248535bccbf05b513fcc3/front-end/src/assets/images/bnb.png
--------------------------------------------------------------------------------
/front-end/src/assets/images/crv.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kaymen99/Dex-aggregator/f9f1478ec780196f5b4248535bccbf05b513fcc3/front-end/src/assets/images/crv.png
--------------------------------------------------------------------------------
/front-end/src/assets/images/dai.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kaymen99/Dex-aggregator/f9f1478ec780196f5b4248535bccbf05b513fcc3/front-end/src/assets/images/dai.png
--------------------------------------------------------------------------------
/front-end/src/assets/images/etherLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kaymen99/Dex-aggregator/f9f1478ec780196f5b4248535bccbf05b513fcc3/front-end/src/assets/images/etherLogo.png
--------------------------------------------------------------------------------
/front-end/src/assets/images/link.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kaymen99/Dex-aggregator/f9f1478ec780196f5b4248535bccbf05b513fcc3/front-end/src/assets/images/link.png
--------------------------------------------------------------------------------
/front-end/src/assets/images/matic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kaymen99/Dex-aggregator/f9f1478ec780196f5b4248535bccbf05b513fcc3/front-end/src/assets/images/matic.png
--------------------------------------------------------------------------------
/front-end/src/assets/images/uni.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kaymen99/Dex-aggregator/f9f1478ec780196f5b4248535bccbf05b513fcc3/front-end/src/assets/images/uni.jpg
--------------------------------------------------------------------------------
/front-end/src/assets/images/usdc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kaymen99/Dex-aggregator/f9f1478ec780196f5b4248535bccbf05b513fcc3/front-end/src/assets/images/usdc.png
--------------------------------------------------------------------------------
/front-end/src/assets/images/usdt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kaymen99/Dex-aggregator/f9f1478ec780196f5b4248535bccbf05b513fcc3/front-end/src/assets/images/usdt.png
--------------------------------------------------------------------------------
/front-end/src/components/Account.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react'
2 | import { useDispatch, useSelector } from "react-redux"
3 | import { updateAccountData, disconnect } from "../features/blockchain"
4 | import { ethers, utils } from "ethers"
5 | import { Modal } from "react-bootstrap"
6 | import { Button } from "@mui/material"
7 | import Web3Modal from "web3modal"
8 | import networks from "../utils/networksMap.json";
9 |
10 |
11 | const eth = window.ethereum
12 | let web3Modal = new Web3Modal()
13 |
14 | function Account() {
15 | const dispatch = useDispatch()
16 | const data = useSelector((state) => state.blockchain.value)
17 |
18 | const [injectedProvider, setInjectedProvider] = useState();
19 | const [show, setShow] = useState(false);
20 |
21 | const handleClose = () => setShow(false);
22 | const handleShow = () => setShow(true);
23 |
24 | async function fetchAccountData() {
25 | if (typeof window.ethereum !== 'undefined') {
26 | const connection = await web3Modal.connect()
27 | const provider = new ethers.providers.Web3Provider(connection)
28 |
29 | setInjectedProvider(provider);
30 |
31 | const signer = provider.getSigner()
32 | const chainId = await provider.getNetwork()
33 | const account = await signer.getAddress()
34 | const balance = await signer.getBalance()
35 |
36 | dispatch(updateAccountData(
37 | {
38 | account: account,
39 | balance: utils.formatUnits(balance),
40 | network: networks[String(chainId.chainId)]
41 | }
42 | ))
43 | }
44 | else {
45 | console.log("Please install metamask")
46 | window.alert("Please Install Metamask")
47 | }
48 | }
49 |
50 | async function Disconnect() {
51 | web3Modal.clearCachedProvider();
52 | if (injectedProvider && injectedProvider.provider && typeof injectedProvider.provider.disconnect == "function") {
53 | await injectedProvider.provider.disconnect();
54 | setInjectedProvider(null)
55 | }
56 | dispatch(disconnect())
57 | setShow(false)
58 | }
59 |
60 | useEffect(() => {
61 | if (eth) {
62 | eth.on('chainChanged', (chainId) => {
63 | fetchAccountData()
64 | })
65 | eth.on('accountsChanged', (accounts) => {
66 | fetchAccountData()
67 | })
68 | }
69 | }, [])
70 |
71 | const isConnected = data.account !== ""
72 |
73 | return (
74 |
75 |
76 | {isConnected ? (
77 | <>
78 |
83 | {data.account &&
84 | `${data.account.slice(0, 6)}...${data.account.slice(
85 | data.account.length - 6,
86 | data.account.length
87 | )}`}
88 |
89 |
90 |
91 | User
92 |
93 |
94 | Account: {data.account}
95 | Balance: {data.balance && parseFloat(data.balance).toFixed(4)} ETH
96 | Network: {data.network}
97 |
98 |
99 |
100 | Disconnect
101 |
102 |
103 |
104 | >
105 | ) : (
106 |
112 | Connect Wallet
113 |
114 | )}
115 |
116 | )
117 | }
118 |
119 | export default Account;
120 |
121 |
122 |
123 |
124 |
125 |
--------------------------------------------------------------------------------
/front-end/src/components/Exchanges.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react'
2 | import { ethers, utils } from 'ethers';
3 | import { Table } from "@mui/material"
4 | import { useSelector } from "react-redux";
5 | import { tokens, exchanges } from "../utils/helpers";
6 |
7 | function Exchanges(props) {
8 |
9 | const data = useSelector((state) => state.blockchain.value)
10 | const [amounts, setAmounts] = useState([])
11 |
12 | const currentNet = data.network !== "" ? data.network : "Ethereum Mainnet"
13 |
14 | async function getPrices() {
15 | if (window.ethereum !== undefined) {
16 | const provider = new ethers.providers.Web3Provider(window.ethereum, "any");
17 |
18 | const _tokenIn = tokens[currentNet][props.token0]["address"]
19 | const _tokenOut = tokens[currentNet][props.token1]["address"]
20 | let path = [_tokenIn, _tokenOut]
21 |
22 | const decimals = tokens[currentNet][props.token1]["decimals"]
23 |
24 | let amountIn = utils.parseEther("1", "ether")
25 |
26 | const items = await Promise.all(
27 | exchanges[currentNet].map(async (e) => {
28 | if (e.name !== "Uniswap V3") {
29 | const router = new ethers.Contract(e.address, e.router.abi, provider)
30 | try {
31 | const amount = await router.getAmountsOut(amountIn, path)
32 |
33 | let item = {
34 | exchange: e.name,
35 | price: amount[1] / 10 ** decimals
36 | }
37 | return item
38 | } catch (err) {
39 | let item = {
40 | exchange: e.name,
41 | price: 0
42 | }
43 | return item
44 | }
45 | } else {
46 | const quoter = new ethers.Contract(e.address, e.quoter.abi, provider)
47 | try {
48 | const amount = await quoter.callStatic.quoteExactInputSingle(
49 | _tokenIn,
50 | _tokenOut,
51 | 3000,
52 | amountIn,
53 | 0
54 | )
55 |
56 | let item = {
57 | exchange: e.name,
58 | price: amount / 10 ** decimals
59 | }
60 | return item
61 | } catch (err) {
62 | let item = {
63 | exchange: e.name,
64 | price: 0
65 | }
66 | return item
67 | }
68 | }
69 | }))
70 | setAmounts(items)
71 | }
72 | }
73 |
74 | /*
75 | setInterval(() => {
76 | getPrices()
77 | }, 30000);
78 | */
79 |
80 | useEffect(() => {
81 | if (window.ethereum != undefined && data.network !== "") {
82 | getPrices()
83 | }
84 |
85 | }, [props.token0, props.token1, data.network])
86 |
87 | return (
88 | <>
89 |
90 |
91 |
92 | Exchange
93 | Price
94 |
95 |
96 |
97 | {amounts.map((a, index) => {
98 | return (
99 |
100 |
101 | {a.exchange}
102 |
103 |
104 | {a.price !== 0 ? parseFloat(a.price).toFixed(8) : "/"}
105 |
106 |
107 | )
108 | })}
109 |
110 |
111 | >
112 | )
113 | }
114 |
115 | export default Exchanges;
116 |
--------------------------------------------------------------------------------
/front-end/src/components/Main.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useSelector } from "react-redux"
3 | import NavBar from "./NavBar"
4 | import { NoteNav, Note } from "./NavbarElements"
5 |
6 | function Main() {
7 | const data = useSelector((state) => state.blockchain.value)
8 |
9 | const isConnected = data.account !== ""
10 |
11 | return (
12 | <>
13 |
14 |
15 |
16 | {isConnected ? (
17 |
18 | Note: You are currently connected to the {data.network} network
19 |
20 | ) : (
21 | Please connect your wallet
22 | )}
23 |
24 |
25 |
26 | >
27 | )
28 | }
29 |
30 | export default Main
--------------------------------------------------------------------------------
/front-end/src/components/NavBar.js:
--------------------------------------------------------------------------------
1 | import { Navbar, Container, Nav } from "react-bootstrap"
2 | import 'bootstrap/dist/css/bootstrap.css';
3 | import Account from "./Account"
4 | import logo from '../dapp-logo.png';
5 |
6 | function NavBar() {
7 |
8 | return (
9 | <>
10 |
11 |
12 |
13 | DeXAggregator
14 |
15 |
16 |
17 |
18 | >
19 | );
20 | }
21 |
22 | export default NavBar;
23 |
--------------------------------------------------------------------------------
/front-end/src/components/NavbarElements.js:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components';
2 |
3 | export const NoteNav = styled.nav`
4 | background: black;
5 | height: 30px;
6 | width: 450px;
7 | text-align: center;
8 | display: block;
9 | margin: 0px auto;
10 | margin-bottom: 80px;
11 |
12 | @media (max-width: 32em) {
13 | width: 250px;
14 | height: 50px;
15 | }
16 | }
17 | `;
18 |
19 | export const NavBar = styled.nav`
20 | text-align: center;
21 | display: flex;
22 | margin-left: 10%;
23 |
24 | `;
25 |
26 | export const Note = styled.div`
27 | color: white;
28 | align-text: center;
29 | font-size: 14px;
30 |
31 | `;
32 |
33 |
34 |
--------------------------------------------------------------------------------
/front-end/src/components/Swap.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react'
2 | import { useSelector } from "react-redux"
3 | import { Modal } from "react-bootstrap"
4 | import { Button, CircularProgress } from "@mui/material";
5 | import { ethers, utils } from 'ethers';
6 | import qs from 'qs'
7 |
8 | import "../assets/css/styles.css";
9 | import { tokens, exchanges, exchangesMap } from "../utils/helpers";
10 | import IRouter from "../artifacts/interfaces/IUniswapV2Router02.json";
11 | import ISwapRouter from "../artifacts/interfaces/ISwapRouter.json";
12 | import ERC20 from "../artifacts/interfaces/IERC20.json";
13 | import Exchanges from './Exchanges';
14 |
15 | function Swap() {
16 | const data = useSelector((state) => state.blockchain.value)
17 | const [amountIn, setAmountIn] = useState(0);
18 | const [amountOut, setAmountOut] = useState(0);
19 | const [tokenInBalance, setTokenInBalance] = useState(null);
20 | const [gasPrice, setGasPrice] = useState(null);
21 | const [bestExchange, setBestExchange] = useState(null);
22 | const [isSwapping, setIsSwapping] = useState(false);
23 |
24 | const [tradeSide, setTradeSide] = useState("");
25 | const [trade, setTrade] = useState({
26 | fromToken: "0",
27 | toToken: "1"
28 | });
29 |
30 | const [show, setShow] = useState(false);
31 |
32 | const handleClose = () => setShow(false);
33 | const handleShow = (side) => {
34 | setTradeSide(side)
35 | setShow(true);
36 | }
37 |
38 |
39 | async function getPriceOut(_amountIn) {
40 | if (window.ethereum !== undefined) {
41 | const provider = new ethers.providers.Web3Provider(window.ethereum, "any");
42 | setAmountIn(Number(_amountIn))
43 | if (Number(_amountIn) !== 0) {
44 | const decimals = tokens[currentNet][trade.toToken]["decimals"]
45 | const _tokenIn = tokens[currentNet][trade.fromToken]["address"]
46 | const _tokenOut = tokens[currentNet][trade.toToken]["address"]
47 | let path = [_tokenIn, _tokenOut]
48 |
49 | let amount_in = utils.parseEther(_amountIn.toString(), "ether")
50 | const prices = await Promise.all(
51 | exchanges[currentNet].map(async (e) => {
52 | if (e.name !== "Uniswap V3") {
53 | const router = new ethers.Contract(e.address, e.router.abi, provider)
54 | try {
55 | const amount = await router.getAmountsOut(amount_in, path)
56 | return Number(amount[1])
57 | } catch (err) {
58 | return 0
59 | }
60 | } else {
61 | const quoter = new ethers.Contract(e.address, e.quoter.abi, provider)
62 | try {
63 | const amount = await quoter.callStatic.quoteExactInputSingle(
64 | _tokenIn,
65 | _tokenOut,
66 | 3000,
67 | amount_in,
68 | 0
69 | )
70 | return Number(amount)
71 | } catch (err) {
72 | return 0
73 | }
74 | }
75 | }))
76 |
77 | const maxPrice = Math.max.apply(null, prices)
78 | const maxPriceIndex = prices.indexOf(maxPrice)
79 |
80 | setAmountOut(Number(maxPrice) / 10 ** decimals)
81 | getGasPrice(_tokenIn, _tokenOut, Number(_amountIn) * 10 ** decimals)
82 | setBestExchange(exchangesMap[currentNet][maxPriceIndex])
83 | } else {
84 | setAmountOut("0")
85 | }
86 | }
87 | }
88 |
89 | async function getPriceIn(_amountOut) {
90 | if (window.ethereum !== undefined) {
91 | const provider = new ethers.providers.Web3Provider(window.ethereum, "any");
92 | setAmountOut(Number(_amountOut))
93 | if (Number(_amountOut) !== 0) {
94 | const decimals = tokens[currentNet][trade.toToken]["decimals"]
95 | const _tokenIn = tokens[currentNet][trade.fromToken]["address"]
96 | const _tokenOut = tokens[currentNet][trade.toToken]["address"]
97 | let path = [_tokenIn, _tokenOut]
98 |
99 | let amount_out = utils.parseEther(_amountOut.toString(), "ether")
100 | const prices = await Promise.all(
101 | exchanges[currentNet].map(async (e) => {
102 | const router = new ethers.Contract(e.address, e.router.abi, provider)
103 | try {
104 | const amount = await router.getAmountsIn(amount_out, path)
105 | return Number(amount[0])
106 | } catch (err) {
107 | return 10 ** 60
108 | }
109 | }))
110 |
111 | const minPrice = Math.min.apply(null, prices)
112 | const minPriceIndex = prices.indexOf(minPrice)
113 |
114 | setAmountIn(Number(minPrice) / 10 ** decimals)
115 | getGasPrice(_tokenOut, _tokenIn, Number(_amountOut) * 10 ** decimals)
116 | setBestExchange(exchangesMap[currentNet][minPriceIndex])
117 | } else {
118 | setAmountIn("0")
119 | }
120 | }
121 | }
122 |
123 | async function swap() {
124 | if (window.ethereum !== undefined) {
125 | const provider = new ethers.providers.Web3Provider(window.ethereum, "any");
126 | try {
127 | setIsSwapping(true)
128 | const _tokenIn = tokens[currentNet][trade.fromToken]["address"]
129 | const _tokenOut = tokens[currentNet][trade.toToken]["address"]
130 | let path = [_tokenIn, _tokenOut]
131 |
132 | const _amountOutMin = Number(amountOut) * 0.95
133 |
134 | const amountOutMin = utils.parseEther(_amountOutMin.toString(), "ether")
135 |
136 | const signer = provider.getSigner()
137 |
138 | const erc20Contract = new ethers.Contract(_tokenIn, ERC20.abi, signer);
139 |
140 | const amount_in = utils.parseEther(amountIn.toString(), "ether")
141 |
142 | const approve_tx = await erc20Contract.approve(bestExchange["address"], amount_in)
143 |
144 | await approve_tx.wait()
145 |
146 | let timestamp = Math.floor(new Date().getTime() / 1000.0) + 15
147 |
148 | let router;
149 | if (bestExchange["name"] !== "Uniswap V3") {
150 | router = new ethers.Contract(bestExchange["address"], IRouter.abi, signer)
151 | try {
152 | const swap_tx = await router.swapExactTokensForTokens(
153 | amount_in,
154 | amountOutMin,
155 | path,
156 | data.account,
157 | timestamp
158 | );
159 | await swap_tx.wait()
160 |
161 | setIsSwapping(false)
162 | setAmountIn(null)
163 | setAmountIn(null)
164 | } catch (err) {
165 | setIsSwapping(false)
166 | window.alert("An error has occured")
167 | }
168 | } else {
169 | router = new ethers.Contract(bestExchange["address"], ISwapRouter.abi, signer)
170 | try {
171 | const params = {
172 | tokenIn: path[0],
173 | tokenOut: path[1],
174 | fee: 3000,
175 | recipient: data.account,
176 | deadline: timestamp,
177 | amountIn: amount_in,
178 | amountOutMinimum: amountOutMin,
179 | sqrtPriceLimitX96: 0
180 | }
181 | const swap_tx = await router.exactInputSingle(params);
182 | await swap_tx.wait()
183 |
184 | setIsSwapping(false)
185 | setAmountIn(null)
186 | setAmountIn(null)
187 | } catch (err) {
188 | setIsSwapping(false)
189 | window.alert("An error has occured")
190 | }
191 | }
192 | } catch (err) {
193 | setIsSwapping(false)
194 | window.alert("An error has occured")
195 | }
196 | }
197 | }
198 |
199 | async function getGasPrice(tokenIn, tokenOut, amount) {
200 | if (window.ethereum !== undefined) {
201 | const provider = new ethers.providers.Web3Provider(window.ethereum, "any");
202 | const params = {
203 | sellToken: tokenIn,
204 | buyToken: tokenOut,
205 | sellAmount: amount,
206 | }
207 | // Fetch the swap price.
208 | const response = await fetch(
209 | `https://api.0x.org/swap/v1/price?${qs.stringify(params)}`
210 | );
211 | const swapPriceJSON = await response.json();
212 | const _gasPrice = await provider.getGasPrice()
213 | setGasPrice(swapPriceJSON.estimatedGas)
214 | }
215 | }
216 |
217 | async function getErc20Balance() {
218 | if (window.ethereum !== undefined) {
219 | const provider = new ethers.providers.Web3Provider(window.ethereum, "any");
220 | const signer = provider.getSigner()
221 |
222 | const decimals = tokens[currentNet][trade.fromToken]["decimals"]
223 | const _tokenIn = tokens[currentNet][trade.fromToken]["address"]
224 |
225 | const erc20Contract = new ethers.Contract(_tokenIn, ERC20.abi, signer);
226 | const balance = (await erc20Contract.balanceOf(data.account)).toString();
227 |
228 | setTokenInBalance(Number(balance) / 10 ** decimals)
229 | }
230 | }
231 |
232 | async function selectToken(tokenIndex) {
233 | handleClose()
234 | if (tradeSide == "from") {
235 | setTrade({ ...trade, fromToken: tokenIndex })
236 | } else {
237 | setTrade({ ...trade, toToken: tokenIndex })
238 | }
239 | }
240 | const currentNet = data.network !== "" ? data.network : "Ethereum Mainnet"
241 |
242 | useEffect(() => {
243 | if (window.ethereum != undefined && data.network !== "") {
244 | getErc20Balance()
245 | }
246 | }, [trade.fromToken, data.network])
247 |
248 | return (
249 | data.network !== "" ? (
250 |
251 |
252 |
312 |
313 |
314 | SELECT A TOKEN
315 |
316 |
317 | {tokens["Ethereum Mainnet"].map((token, index) => {
318 | return (
319 | { selectToken(index) }} >
320 |
321 |
{token.name}
322 |
323 | )
324 | })}
325 |
326 |
327 |
328 | Close
329 |
330 |
331 |
332 |
333 |
Exchanges
334 |
335 |
336 |
337 |
338 | ) : null
339 | )
340 | }
341 |
342 | export default Swap;
343 |
--------------------------------------------------------------------------------
/front-end/src/dapp-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kaymen99/Dex-aggregator/f9f1478ec780196f5b4248535bccbf05b513fcc3/front-end/src/dapp-logo.png
--------------------------------------------------------------------------------
/front-end/src/features/blockchain.js:
--------------------------------------------------------------------------------
1 | import { createSlice } from '@reduxjs/toolkit';
2 |
3 | const initialData = { account: "", balance: 0, network: "" }
4 | export const blockchainSlice = createSlice({
5 | name: "blockchain",
6 | initialState: { value: initialData },
7 | reducers: {
8 | updateAccountData: (state, action) => {
9 | state.value = action.payload
10 | },
11 | disconnect: (state) => {
12 | state.value = initialData
13 | }
14 | },
15 | }
16 | )
17 |
18 | export default blockchainSlice.reducer;
19 |
20 | export const { updateAccountData, disconnect } = blockchainSlice.actions;
21 |
--------------------------------------------------------------------------------
/front-end/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
5 | sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
12 | monospace;
13 | }
--------------------------------------------------------------------------------
/front-end/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import './index.css';
4 | import { combineReducers } from 'redux'
5 | import reportWebVitals from './reportWebVitals';
6 | import { configureStore } from "@reduxjs/toolkit";
7 | import { Provider } from "react-redux";
8 | import blockchainReducer from "./features/blockchain"
9 | import {
10 | persistStore,
11 | persistReducer,
12 | FLUSH,
13 | REHYDRATE,
14 | PAUSE,
15 | PERSIST,
16 | PURGE,
17 | REGISTER,
18 | } from 'redux-persist'
19 | import storage from 'redux-persist/lib/storage'
20 | import { PersistGate } from 'redux-persist/integration/react';
21 | import App from './App';
22 |
23 |
24 | const persistConfig = {
25 | key: 'root',
26 | version: 1,
27 | storage,
28 | }
29 |
30 | const rootReducer = combineReducers({
31 | blockchain: blockchainReducer
32 | })
33 |
34 |
35 | const persistedReducer = persistReducer(persistConfig, rootReducer)
36 |
37 | const store = configureStore({
38 | reducer: persistedReducer,
39 | middleware: (getDefaultMiddleware) =>
40 | getDefaultMiddleware({
41 | serializableCheck: {
42 | ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
43 | },
44 | }),
45 | })
46 |
47 | let persistor = persistStore(store)
48 |
49 | ReactDOM.render(
50 |
51 |
52 |
53 |
54 |
55 |
56 | ,
57 | document.getElementById('root')
58 | );
59 |
60 | // If you want to start measuring performance in your app, pass a function
61 | // to log results (for example: reportWebVitals(console.log))
62 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
63 | reportWebVitals();
64 |
65 |
--------------------------------------------------------------------------------
/front-end/src/reportWebVitals.js:
--------------------------------------------------------------------------------
1 | const reportWebVitals = onPerfEntry => {
2 | if (onPerfEntry && onPerfEntry instanceof Function) {
3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
4 | getCLS(onPerfEntry);
5 | getFID(onPerfEntry);
6 | getFCP(onPerfEntry);
7 | getLCP(onPerfEntry);
8 | getTTFB(onPerfEntry);
9 | });
10 | }
11 | };
12 |
13 | export default reportWebVitals;
14 |
--------------------------------------------------------------------------------
/front-end/src/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom';
6 |
--------------------------------------------------------------------------------
/front-end/src/utils/helpers.js:
--------------------------------------------------------------------------------
1 | import IRouter from "./../artifacts/interfaces/IUniswapV2Router02.json";
2 | import ISwapRouter from "./../artifacts/interfaces/ISwapRouter.json";
3 | import IQouter from "./../artifacts/interfaces/IQuoter.json";
4 |
5 | import eth from "./../assets/images/etherLogo.png";
6 | import bnb from "./../assets/images/bnb.png";
7 | import matic from "./../assets/images/matic.png";
8 | import dai from "./../assets/images/dai.png";
9 | import crv from "./../assets/images/crv.png";
10 | import usdc from "./../assets/images/usdc.png";
11 | import aave from "./../assets/images/aave.png"
12 | import link from "./../assets/images/link.png"
13 | import usdt from "./../assets/images/usdt.png";
14 | import uni from "./../assets/images/uni.jpg"
15 |
16 | export const tokens = {
17 | "Ethereum Mainnet": [
18 | {
19 | "image": eth,
20 | "name": "ETH",
21 | "address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
22 | "decimals": 18
23 | },
24 | {
25 | "image": dai,
26 | "name": "DAI",
27 | "address": "0x6b175474e89094c44da98b954eedeac495271d0f",
28 | "decimals": 18
29 | },
30 | {
31 | "image": usdc,
32 | "name": "USDC",
33 | "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
34 | "decimals": 6
35 | },
36 | {
37 | "image": usdt,
38 | "name": "USDT",
39 | "address": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
40 | "decimals": 6
41 | },
42 | {
43 | "image": matic,
44 | "name": "MATIC",
45 | "address": "0x7D1AfA7B718fb893dB30A3aBc0Cfc608AaCfeBB0",
46 | "decimals": 18
47 | },
48 | {
49 | "image": crv,
50 | "name": "CRV",
51 | "address": "0xD533a949740bb3306d119CC777fa900bA034cd52",
52 | "decimals": 18
53 | },
54 | {
55 | "image": link,
56 | "name": "LINK",
57 | "address": "0x514910771AF9Ca656af840dff83E8264EcF986CA",
58 | "decimals": 18
59 | },
60 | {
61 | "image": uni,
62 | "name": "UNI",
63 | "address": "0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984",
64 | "decimals": 18
65 | }
66 | ],
67 | "Goerli": [
68 | {
69 | "image": eth,
70 | "name": "ETH",
71 | "address": "0xd0A1E359811322d97991E03f863a0C30C2cF029C",
72 | "decimals": 18
73 | },
74 | {
75 | "image": dai,
76 | "name": "DAI",
77 | "address": "0x4F96Fe3b7A6Cf9725f59d353F723c1bDb64CA6Aa",
78 | "decimals": 18
79 | },
80 | {
81 | "image": usdc,
82 | "name": "USDC",
83 | "address": "0xdCFaB8057d08634279f8201b55d311c2a67897D2",
84 | "decimals": 2
85 | },
86 | {
87 | "image": usdt,
88 | "name": "USDT",
89 | "address": "0xf3e0d7bF58c5d455D31ef1c2d5375904dF525105",
90 | "decimals": 6
91 | },
92 | {
93 | "image": crv,
94 | "name": "CRV",
95 | "address": "0xB8EEb94cFf33EfACf0c6def6967FD8852DcECDdB",
96 | "decimals": 18
97 | },
98 | {
99 | "image": matic,
100 | "name": "MATIC",
101 | "address": "0x7D1AfA7B718fb893dB30A3aBc0Cfc608AaCfeBB0",
102 | "decimals": 18
103 | },
104 | {
105 | "image": link,
106 | "name": "LINK",
107 | "address": "0xa36085F69e2889c224210F603D836748e7dC0088",
108 | "decimals": 18
109 | },
110 | {
111 | "image": uni,
112 | "name": "UNI",
113 | "address": "0x9b6Ff80Ff8348852d5281de45E66B7ED36E7B8a9",
114 | "decimals": 18
115 | },
116 | ],
117 | "Polygon Mainnet": [
118 | {
119 | "image": matic,
120 | "name": "MATIC",
121 | "address": "0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270",
122 | "decimals": 18
123 | },
124 | {
125 | "image": eth,
126 | "name": "ETH",
127 | "address": "0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619",
128 | "decimals": 18
129 | },
130 | {
131 | "image": dai,
132 | "name": "DAI",
133 | "address": "0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063",
134 | "decimals": 18
135 | },
136 | {
137 | "image": usdc,
138 | "name": "USDC",
139 | "address": "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174",
140 | "decimals": 6
141 | },
142 | {
143 | "image": usdt,
144 | "name": "USDT",
145 | "address": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
146 | "decimals": 6
147 | },
148 | {
149 | "image": aave,
150 | "name": "AAVE",
151 | "address": "0xD6DF932A45C0f255f85145f286eA0b292B21C90B",
152 | "decimals": 18
153 | },
154 | {
155 | "image": link,
156 | "name": "LINK",
157 | "address": "0x53E0bca35eC356BD5ddDFebbD1Fc0fD03FaBad39",
158 | "decimals": 18
159 | }
160 | ],
161 | "BSC": [
162 | {
163 | "image": eth,
164 | "name": "ETH",
165 | "address": "0x2170Ed0880ac9A755fd29B2688956BD959F933F8",
166 | "decimals": 18
167 | },
168 | {
169 | "image": bnb,
170 | "name": "BNB",
171 | "address": "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c",
172 | "decimals": 18
173 | },
174 | {
175 | "image": dai,
176 | "name": "DAI",
177 | "address": "0x1AF3F329e8BE154074D8769D1FFa4eE058B1DBc3",
178 | "decimals": 18
179 | },
180 | {
181 | "image": usdc,
182 | "name": "USDC",
183 | "address": "0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d",
184 | "decimals": 6
185 | },
186 | {
187 | "image": usdt,
188 | "name": "USDT",
189 | "address": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
190 | "decimals": 6
191 | },
192 | {
193 | "image": link,
194 | "name": "LINK",
195 | "address": "0xF8A0BF9cF54Bb92F17374d9e9A321E6a111a51bD",
196 | "decimals": 18
197 | }
198 | ],
199 | }
200 |
201 | export const exchanges = {
202 | "Ethereum Mainnet": [
203 | {
204 | "name": "Uniswap",
205 | "address": "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D",
206 | "router": IRouter
207 | },
208 | {
209 | "name": "Uniswap V3",
210 | "address": "0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6",
211 | "router": ISwapRouter,
212 | "quoter": IQouter
213 | },
214 | {
215 | "name": "Sushiswap",
216 | "address": "0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F",
217 | "router": IRouter
218 | },
219 | {
220 | "name": "Shibaswap",
221 | "address": "0x03f7724180AA6b939894B5Ca4314783B0b36b329",
222 | "router": IRouter
223 | }
224 | ],
225 | "Goerli": [
226 | {
227 | "name": "Uniswap",
228 | "address": "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D",
229 | "router": IRouter
230 | },
231 | {
232 | "name": "Uniswap V3",
233 | "address": "0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6",
234 | "router": ISwapRouter,
235 | "quoter": IQouter
236 | },
237 | {
238 | "name": "Sushiswap",
239 | "address": "0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F",
240 | "router": IRouter
241 | },
242 | {
243 | "name": "Shibaswap",
244 | "address": "0x03f7724180AA6b939894B5Ca4314783B0b36b329",
245 | "router": IRouter
246 | }
247 | ],
248 | "Polygon Mainnet": [
249 | {
250 | "name": "Sushiswap",
251 | "address": "0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506",
252 | "router": IRouter
253 | },
254 | {
255 | "name": "Uniswap V3",
256 | "address": "0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6",
257 | "router": ISwapRouter,
258 | "quoter": IQouter
259 | },
260 | {
261 | "name": "Quickswap",
262 | "address": "0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff",
263 | "router": IRouter
264 | },
265 | {
266 | "name": "Jetswap",
267 | "address": "0x5C6EC38fb0e2609672BDf628B1fD605A523E5923",
268 | "router": IRouter
269 | },
270 | {
271 | "name": "Apeswap",
272 | "address": "0xC0788A3aD43d79aa53B09c2EaCc313A787d1d607",
273 | "router": IRouter
274 | }
275 |
276 | ],
277 | "BSC": [
278 | {
279 | "name": "Sushiswap",
280 | "address": "0x947950BcC74888a40Ffa2593C5798F11Fc9124C4",
281 | "router": IRouter
282 | },
283 | {
284 | "name": "Apeswap",
285 | "address": "0xcF0feBd3f17CEf5b47b0cD257aCf6025c5BFf3b7",
286 | "router": IRouter
287 | },
288 | {
289 | "name": "Jetswap",
290 | "address": "0x5C6EC38fb0e2609672BDf628B1fD605A523E5923",
291 | "router": IRouter
292 | },
293 | {
294 | "name": "Pancakeswap",
295 | "address": "0x10ED43C718714eb63d5aA57B78B54704E256024E",
296 | "router": IRouter
297 | }
298 | ]
299 | }
300 |
301 | export const exchangesMap = {
302 | "Ethereum Mainnet": {
303 | 0: {
304 | "name": "UNISWAP",
305 | "address": "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D"
306 | },
307 | 1: {
308 | "name": "Uniswap V3",
309 | "address": "0xE592427A0AEce92De3Edee1F18E0157C05861564",
310 | },
311 | 2: {
312 | "name": "SUSHISWAP",
313 | "address": "0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F"
314 | },
315 | 3: {
316 | "name": "SHIBASWAP",
317 | "address": "0x03f7724180AA6b939894B5Ca4314783B0b36b329"
318 | }
319 | },
320 | "Goerli": {
321 | 0: {
322 | "name": "UNISWAP",
323 | "address": "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D"
324 | },
325 | 1: {
326 | "name": "Uniswap V3",
327 | "address": "0xE592427A0AEce92De3Edee1F18E0157C05861564",
328 | },
329 | 2: {
330 | "name": "SUSHISWAP",
331 | "address": "0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F"
332 | },
333 | 3: {
334 | "name": "SHIBASWAP",
335 | "address": "0x03f7724180AA6b939894B5Ca4314783B0b36b329"
336 | }
337 | },
338 | "Polygon Mainnet": {
339 | 0: {
340 | "name": "SUSHISWAP",
341 | "address": "0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506"
342 | },
343 | 1: {
344 | "name": "Uniswap V3",
345 | "address": "0xE592427A0AEce92De3Edee1F18E0157C05861564",
346 | },
347 | 2: {
348 | "name": "QUICKSWAP",
349 | "address": "0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff"
350 | },
351 | 3: {
352 | "name": "JETSWAP",
353 | "address": "0x5C6EC38fb0e2609672BDf628B1fD605A523E5923"
354 | },
355 | 4: {
356 | "name": "APESWAP",
357 | "address": "0xC0788A3aD43d79aa53B09c2EaCc313A787d1d607"
358 | }
359 | },
360 | "BSC": {
361 | 0: {
362 | "name": "SUSHISWAP",
363 | "address": "0x947950BcC74888a40Ffa2593C5798F11Fc9124C4"
364 | },
365 | 1: {
366 | "name": "PANCAKESWAP",
367 | "address": "0x10ED43C718714eb63d5aA57B78B54704E256024E"
368 | },
369 | 2: {
370 | "name": "JETSWAP",
371 | "address": "0x5C6EC38fb0e2609672BDf628B1fD605A523E5923"
372 | },
373 | 3: {
374 | "name": "APESWAP",
375 | "address": "0xcF0feBd3f17CEf5b47b0cD257aCf6025c5BFf3b7"
376 | }
377 | },
378 | }
379 |
--------------------------------------------------------------------------------
/front-end/src/utils/networksMap.json:
--------------------------------------------------------------------------------
1 | {
2 | "1": "Ethereum Mainnet",
3 | "5": "Goerli",
4 | "1337": "ganache",
5 | "80001": "Polygon Testnet",
6 | "137": "Polygon Mainnet",
7 | "56": "BSC"
8 | }
9 |
--------------------------------------------------------------------------------
/interfaces/IERC20.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 |
3 | pragma solidity >=0.6.0 <0.8.0;
4 |
5 | /**
6 | * @dev Interface of the ERC20 standard as defined in the EIP.
7 | */
8 | interface IERC20 {
9 | /**
10 | * @dev Returns the amount of tokens in existence.
11 | */
12 | function totalSupply() external view returns (uint256);
13 |
14 | /**
15 | * @dev Returns the amount of tokens owned by `account`.
16 | */
17 | function balanceOf(address account) external view returns (uint256);
18 |
19 | /**
20 | * @dev Moves `amount` tokens from the caller's account to `recipient`.
21 | *
22 | * Returns a boolean value indicating whether the operation succeeded.
23 | *
24 | * Emits a {Transfer} event.
25 | */
26 | function transfer(address recipient, uint256 amount)
27 | external
28 | returns (bool);
29 |
30 | /**
31 | * @dev Returns the remaining number of tokens that `spender` will be
32 | * allowed to spend on behalf of `owner` through {transferFrom}. This is
33 | * zero by default.
34 | *
35 | * This value changes when {approve} or {transferFrom} are called.
36 | */
37 | function allowance(address owner, address spender)
38 | external
39 | view
40 | returns (uint256);
41 |
42 | /**
43 | * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
44 | *
45 | * Returns a boolean value indicating whether the operation succeeded.
46 | *
47 | * IMPORTANT: Beware that changing an allowance with this method brings the risk
48 | * that someone may use both the old and the new allowance by unfortunate
49 | * transaction ordering. One possible solution to mitigate this race
50 | * condition is to first reduce the spender's allowance to 0 and set the
51 | * desired value afterwards:
52 | * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
53 | *
54 | * Emits an {Approval} event.
55 | */
56 | function approve(address spender, uint256 amount) external returns (bool);
57 |
58 | /**
59 | * @dev Moves `amount` tokens from `sender` to `recipient` using the
60 | * allowance mechanism. `amount` is then deducted from the caller's
61 | * allowance.
62 | *
63 | * Returns a boolean value indicating whether the operation succeeded.
64 | *
65 | * Emits a {Transfer} event.
66 | */
67 | function transferFrom(
68 | address sender,
69 | address recipient,
70 | uint256 amount
71 | ) external returns (bool);
72 |
73 | /**
74 | * @dev Emitted when `value` tokens are moved from one account (`from`) to
75 | * another (`to`).
76 | *
77 | * Note that `value` may be zero.
78 | */
79 | event Transfer(address indexed from, address indexed to, uint256 value);
80 |
81 | /**
82 | * @dev Emitted when the allowance of a `spender` for an `owner` is set by
83 | * a call to {approve}. `value` is the new allowance.
84 | */
85 | event Approval(
86 | address indexed owner,
87 | address indexed spender,
88 | uint256 value
89 | );
90 | }
91 |
--------------------------------------------------------------------------------
/interfaces/IQouter.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: GPL-2.0-or-later
2 | pragma solidity >=0.7.5;
3 | pragma abicoder v2;
4 |
5 | /// @title Quoter Interface
6 | /// @notice Supports quoting the calculated amounts from exact input or exact output swaps
7 | /// @dev These functions are not marked view because they rely on calling non-view functions and reverting
8 | /// to compute the result. They are also not gas efficient and should not be called on-chain.
9 | interface IQuoter {
10 | /// @notice Returns the amount out received for a given exact input swap without executing the swap
11 | /// @param path The path of the swap, i.e. each token pair and the pool fee
12 | /// @param amountIn The amount of the first token to swap
13 | /// @return amountOut The amount of the last token that would be received
14 | function quoteExactInput(bytes memory path, uint256 amountIn)
15 | external
16 | returns (uint256 amountOut);
17 |
18 | /// @notice Returns the amount out received for a given exact input but for a swap of a single pool
19 | /// @param tokenIn The token being swapped in
20 | /// @param tokenOut The token being swapped out
21 | /// @param fee The fee of the token pool to consider for the pair
22 | /// @param amountIn The desired input amount
23 | /// @param sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap
24 | /// @return amountOut The amount of `tokenOut` that would be received
25 | function quoteExactInputSingle(
26 | address tokenIn,
27 | address tokenOut,
28 | uint24 fee,
29 | uint256 amountIn,
30 | uint160 sqrtPriceLimitX96
31 | ) external returns (uint256 amountOut);
32 |
33 | /// @notice Returns the amount in required for a given exact output swap without executing the swap
34 | /// @param path The path of the swap, i.e. each token pair and the pool fee. Path must be provided in reverse order
35 | /// @param amountOut The amount of the last token to receive
36 | /// @return amountIn The amount of first token required to be paid
37 | function quoteExactOutput(bytes memory path, uint256 amountOut)
38 | external
39 | returns (uint256 amountIn);
40 |
41 | /// @notice Returns the amount in required to receive the given exact output amount but for a swap of a single pool
42 | /// @param tokenIn The token being swapped in
43 | /// @param tokenOut The token being swapped out
44 | /// @param fee The fee of the token pool to consider for the pair
45 | /// @param amountOut The desired output amount
46 | /// @param sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap
47 | /// @return amountIn The amount required as the input for the swap in order to receive `amountOut`
48 | function quoteExactOutputSingle(
49 | address tokenIn,
50 | address tokenOut,
51 | uint24 fee,
52 | uint256 amountOut,
53 | uint160 sqrtPriceLimitX96
54 | ) external returns (uint256 amountIn);
55 | }
56 |
--------------------------------------------------------------------------------
/interfaces/ISwapRouter.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: GPL-2.0-or-later
2 | pragma solidity >=0.7.5;
3 | pragma abicoder v2;
4 |
5 | import "@uniswap/contracts/interfaces/callback/IUniswapV3SwapCallback.sol";
6 |
7 | /// @title Router token swapping functionality
8 | /// @notice Functions for swapping tokens via Uniswap V3
9 | interface ISwapRouter is IUniswapV3SwapCallback {
10 | struct ExactInputSingleParams {
11 | address tokenIn;
12 | address tokenOut;
13 | uint24 fee;
14 | address recipient;
15 | uint256 deadline;
16 | uint256 amountIn;
17 | uint256 amountOutMinimum;
18 | uint160 sqrtPriceLimitX96;
19 | }
20 |
21 | /// @notice Swaps `amountIn` of one token for as much as possible of another token
22 | /// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata
23 | /// @return amountOut The amount of the received token
24 | function exactInputSingle(ExactInputSingleParams calldata params)
25 | external
26 | payable
27 | returns (uint256 amountOut);
28 |
29 | struct ExactInputParams {
30 | bytes path;
31 | address recipient;
32 | uint256 deadline;
33 | uint256 amountIn;
34 | uint256 amountOutMinimum;
35 | }
36 |
37 | /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path
38 | /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata
39 | /// @return amountOut The amount of the received token
40 | function exactInput(ExactInputParams calldata params)
41 | external
42 | payable
43 | returns (uint256 amountOut);
44 |
45 | struct ExactOutputSingleParams {
46 | address tokenIn;
47 | address tokenOut;
48 | uint24 fee;
49 | address recipient;
50 | uint256 deadline;
51 | uint256 amountOut;
52 | uint256 amountInMaximum;
53 | uint160 sqrtPriceLimitX96;
54 | }
55 |
56 | /// @notice Swaps as little as possible of one token for `amountOut` of another token
57 | /// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata
58 | /// @return amountIn The amount of the input token
59 | function exactOutputSingle(ExactOutputSingleParams calldata params)
60 | external
61 | payable
62 | returns (uint256 amountIn);
63 |
64 | struct ExactOutputParams {
65 | bytes path;
66 | address recipient;
67 | uint256 deadline;
68 | uint256 amountOut;
69 | uint256 amountInMaximum;
70 | }
71 |
72 | /// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed)
73 | /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata
74 | /// @return amountIn The amount of the input token
75 | function exactOutput(ExactOutputParams calldata params)
76 | external
77 | payable
78 | returns (uint256 amountIn);
79 | }
80 |
--------------------------------------------------------------------------------
/interfaces/IUniswapV2Router02.sol:
--------------------------------------------------------------------------------
1 | pragma solidity >=0.6.2;
2 |
3 | interface IUniswapV2Router01 {
4 | function factory() external pure returns (address);
5 |
6 | function WETH() external pure returns (address);
7 |
8 | function addLiquidity(
9 | address tokenA,
10 | address tokenB,
11 | uint256 amountADesired,
12 | uint256 amountBDesired,
13 | uint256 amountAMin,
14 | uint256 amountBMin,
15 | address to,
16 | uint256 deadline
17 | )
18 | external
19 | returns (
20 | uint256 amountA,
21 | uint256 amountB,
22 | uint256 liquidity
23 | );
24 |
25 | function addLiquidityETH(
26 | address token,
27 | uint256 amountTokenDesired,
28 | uint256 amountTokenMin,
29 | uint256 amountETHMin,
30 | address to,
31 | uint256 deadline
32 | )
33 | external
34 | payable
35 | returns (
36 | uint256 amountToken,
37 | uint256 amountETH,
38 | uint256 liquidity
39 | );
40 |
41 | function removeLiquidity(
42 | address tokenA,
43 | address tokenB,
44 | uint256 liquidity,
45 | uint256 amountAMin,
46 | uint256 amountBMin,
47 | address to,
48 | uint256 deadline
49 | ) external returns (uint256 amountA, uint256 amountB);
50 |
51 | function removeLiquidityETH(
52 | address token,
53 | uint256 liquidity,
54 | uint256 amountTokenMin,
55 | uint256 amountETHMin,
56 | address to,
57 | uint256 deadline
58 | ) external returns (uint256 amountToken, uint256 amountETH);
59 |
60 | function removeLiquidityWithPermit(
61 | address tokenA,
62 | address tokenB,
63 | uint256 liquidity,
64 | uint256 amountAMin,
65 | uint256 amountBMin,
66 | address to,
67 | uint256 deadline,
68 | bool approveMax,
69 | uint8 v,
70 | bytes32 r,
71 | bytes32 s
72 | ) external returns (uint256 amountA, uint256 amountB);
73 |
74 | function removeLiquidityETHWithPermit(
75 | address token,
76 | uint256 liquidity,
77 | uint256 amountTokenMin,
78 | uint256 amountETHMin,
79 | address to,
80 | uint256 deadline,
81 | bool approveMax,
82 | uint8 v,
83 | bytes32 r,
84 | bytes32 s
85 | ) external returns (uint256 amountToken, uint256 amountETH);
86 |
87 | function swapExactTokensForTokens(
88 | uint256 amountIn,
89 | uint256 amountOutMin,
90 | address[] calldata path,
91 | address to,
92 | uint256 deadline
93 | ) external returns (uint256[] memory amounts);
94 |
95 | function swapTokensForExactTokens(
96 | uint256 amountOut,
97 | uint256 amountInMax,
98 | address[] calldata path,
99 | address to,
100 | uint256 deadline
101 | ) external returns (uint256[] memory amounts);
102 |
103 | function swapExactETHForTokens(
104 | uint256 amountOutMin,
105 | address[] calldata path,
106 | address to,
107 | uint256 deadline
108 | ) external payable returns (uint256[] memory amounts);
109 |
110 | function swapTokensForExactETH(
111 | uint256 amountOut,
112 | uint256 amountInMax,
113 | address[] calldata path,
114 | address to,
115 | uint256 deadline
116 | ) external returns (uint256[] memory amounts);
117 |
118 | function swapExactTokensForETH(
119 | uint256 amountIn,
120 | uint256 amountOutMin,
121 | address[] calldata path,
122 | address to,
123 | uint256 deadline
124 | ) external returns (uint256[] memory amounts);
125 |
126 | function swapETHForExactTokens(
127 | uint256 amountOut,
128 | address[] calldata path,
129 | address to,
130 | uint256 deadline
131 | ) external payable returns (uint256[] memory amounts);
132 |
133 | function quote(
134 | uint256 amountA,
135 | uint256 reserveA,
136 | uint256 reserveB
137 | ) external pure returns (uint256 amountB);
138 |
139 | function getAmountOut(
140 | uint256 amountIn,
141 | uint256 reserveIn,
142 | uint256 reserveOut
143 | ) external pure returns (uint256 amountOut);
144 |
145 | function getAmountIn(
146 | uint256 amountOut,
147 | uint256 reserveIn,
148 | uint256 reserveOut
149 | ) external pure returns (uint256 amountIn);
150 |
151 | function getAmountsOut(uint256 amountIn, address[] calldata path)
152 | external
153 | view
154 | returns (uint256[] memory amounts);
155 |
156 | function getAmountsIn(uint256 amountOut, address[] calldata path)
157 | external
158 | view
159 | returns (uint256[] memory amounts);
160 | }
161 |
162 | interface IUniswapV2Router02 is IUniswapV2Router01 {
163 | function removeLiquidityETHSupportingFeeOnTransferTokens(
164 | address token,
165 | uint256 liquidity,
166 | uint256 amountTokenMin,
167 | uint256 amountETHMin,
168 | address to,
169 | uint256 deadline
170 | ) external returns (uint256 amountETH);
171 |
172 | function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
173 | address token,
174 | uint256 liquidity,
175 | uint256 amountTokenMin,
176 | uint256 amountETHMin,
177 | address to,
178 | uint256 deadline,
179 | bool approveMax,
180 | uint8 v,
181 | bytes32 r,
182 | bytes32 s
183 | ) external returns (uint256 amountETH);
184 |
185 | function swapExactTokensForTokensSupportingFeeOnTransferTokens(
186 | uint256 amountIn,
187 | uint256 amountOutMin,
188 | address[] calldata path,
189 | address to,
190 | uint256 deadline
191 | ) external;
192 |
193 | function swapExactETHForTokensSupportingFeeOnTransferTokens(
194 | uint256 amountOutMin,
195 | address[] calldata path,
196 | address to,
197 | uint256 deadline
198 | ) external payable;
199 |
200 | function swapExactTokensForETHSupportingFeeOnTransferTokens(
201 | uint256 amountIn,
202 | uint256 amountOutMin,
203 | address[] calldata path,
204 | address to,
205 | uint256 deadline
206 | ) external;
207 | }
208 |
--------------------------------------------------------------------------------
/scripts/get_prices.py:
--------------------------------------------------------------------------------
1 | from brownie import config, network, interface
2 | from scripts.helper_scripts import get_account, toWei, fromWei, approve_erc20, FORKED_BLOCHCHAINS
3 | from scripts.get_weth import get_weth
4 | import brownie, requests
5 |
6 |
7 |
8 | weth_token = config["networks"][network.show_active()]["weth-token"]
9 | dai_token = config["networks"][network.show_active()]["dai-token"]
10 |
11 |
12 | uni_router_address = config["networks"][network.show_active()]["uniswap-router"]
13 | shiba_router_address = config["networks"][network.show_active()]["shibaswap-router"]
14 | sushi_router_address = config["networks"][network.show_active()]["sushiswap-rou
15 |
16 |
17 | def main():
18 | amount = toWei(1)
19 |
20 | uniswap_router = interface.IUniswapV2Router02(uni_router_address)
21 | sushiswap_router = interface.IUniswapV2Router02(sushi_router_address)
22 | shibaswap_router = interface.IUniswapV2Router02(shiba_router_address)
23 |
24 | path = [weth_token, usdt_token]
25 |
26 | amount_uniswap= uniswap_router.getAmountsOut(amount, path)[1]
27 | amount_sushiswap = sushiswap_router.getAmountsOut(amount, path)[1]
28 | amount_shibaswap = shibaswap_router.getAmountsOut(amount, path)[1]
29 |
30 | print("amount in uniswap: " , float(amount_uniswap) / 10**18)
31 | print("amount in sushiswap: " , float(amount_sushiswap)/ 10**18)
32 | print("amount in shibaswap: " , float(amount_shibaswap)/ 10**18)
33 |
34 |
35 |
--------------------------------------------------------------------------------
/scripts/get_weth.py:
--------------------------------------------------------------------------------
1 | from brownie import network, interface, config
2 | from scripts.helper_scripts import fromWei, get_account, toWei
3 |
4 |
5 |
6 | def get_weth(account, amount):
7 | weth_address = config["networks"][network.show_active()]["weth-token"]
8 |
9 | weth = interface.IWeth(weth_address)
10 |
11 | deposit_tx = weth.deposit({"from": account, "value": toWei(amount)})
12 | deposit_tx.wait(1)
13 |
14 | print(f"You recieved {amount} weth")
15 |
16 | def main():
17 | account = get_account()
18 | amount = toWei(10)
19 | get_weth(account, amount)
--------------------------------------------------------------------------------
/scripts/helper_scripts.py:
--------------------------------------------------------------------------------
1 | from brownie import config, network, accounts, Contract, interface
2 | from web3 import Web3
3 |
4 |
5 | LOCAL_BLOCKCHAINS = ["ganache-local", "development"]
6 |
7 | FORKED_BLOCHCHAINS = ["mainnet-fork", "mainnet-fork-dev"]
8 |
9 | ZERO_ADDRESS = "0x0000000000000000000000000000000000000000"
10 |
11 | def get_account(index=None):
12 | if network.show_active() in LOCAL_BLOCKCHAINS or network.show_active() in FORKED_BLOCHCHAINS:
13 | if index is not None:
14 | return accounts[index]
15 | else:
16 | return accounts[0]
17 | else:
18 | return accounts.add(config["wallets"]["from_key"])
19 |
20 | def toWei(amount):
21 | return Web3.toWei(amount, "ether")
22 |
23 | def fromWei(amount):
24 | return Web3.fromWei(amount, "ether")
25 |
26 |
27 | def get_contract(_contract, contract_address):
28 | contract = Contract.from_abi(_contract._name, contract_address, _contract.abi)
29 |
30 | def approve_erc20(erc20_address, spender, amount, account):
31 | erc20 = interface.IERC20(erc20_address)
32 | approve_tx = erc20.approve(spender, amount, {"from": account})
33 | approve_tx.wait(1)
34 |
35 | print("----- Erc20 approved -----")
--------------------------------------------------------------------------------
/scripts/update_front_end.py:
--------------------------------------------------------------------------------
1 | import json, yaml, os, shutil
2 |
3 | # functions to copy smart contract data to the front end
4 |
5 | def copy_build_folder():
6 | copy2frontend("./build", "./front-end/src/artifacts")
7 | with open("brownie-config.yaml", "r") as brownie_config:
8 | config_dict = yaml.load(brownie_config, Loader=yaml.FullLoader)
9 | with open("./front-end/src/utils/brownie-config.json", 'w') as brownie_config_json:
10 | json.dump(config_dict, brownie_config_json)
11 |
12 | print("front end updated !!!")
13 |
14 | def copy2frontend(src, des):
15 | if os.path.exists(des):
16 | shutil.rmtree(des)
17 | shutil.copytree(src, des)
18 |
19 |
20 | def main():
21 | copy_build_folder()
--------------------------------------------------------------------------------