├── .babelrc
├── .gitignore
├── migrations
├── 1_initial_migration.js
└── 2_deploy_contracts.js
├── package-lock.json
├── package.json
├── public
├── favicon.ico
├── index.html
└── manifest.json
├── scripts
└── issue-token.js
├── src
├── abis
│ ├── DaiToken.json
│ ├── DappToken.json
│ ├── Migrations.json
│ └── TokenFarm.json
├── components
│ ├── App.css
│ ├── App.js
│ ├── Main.js
│ └── Navbar.js
├── contracts
│ ├── DaiToken.sol
│ ├── DappToken.sol
│ ├── Migrations.sol
│ └── TokenFarm.sol
├── dai.png
├── eth-logo.png
├── farmer.png
├── index.js
├── logo.png
├── serviceWorker.js
└── token-logo.png
├── test
└── TokenFarm.test.js
└── truffle-config.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015", "stage-2", "stage-3"]
3 | }
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env
17 | .env.local
18 | .env.development.local
19 | .env.test.local
20 | .env.production.local
21 |
22 | npm-debug.log*
23 | yarn-debug.log*
24 | yarn-error.log*
25 |
--------------------------------------------------------------------------------
/migrations/1_initial_migration.js:
--------------------------------------------------------------------------------
1 | const Migrations = artifacts.require("Migrations");
2 |
3 | module.exports = function(deployer) {
4 | deployer.deploy(Migrations);
5 | };
6 |
--------------------------------------------------------------------------------
/migrations/2_deploy_contracts.js:
--------------------------------------------------------------------------------
1 | const DappToken = artifacts.require('DappToken')
2 | const DaiToken = artifacts.require('DaiToken')
3 | const TokenFarm = artifacts.require('TokenFarm')
4 |
5 | module.exports = async function(deployer, network, accounts) {
6 | // Deploy Mock DAI Token
7 | await deployer.deploy(DaiToken)
8 | const daiToken = await DaiToken.deployed()
9 |
10 | // Deploy Dapp Token
11 | await deployer.deploy(DappToken)
12 | const dappToken = await DappToken.deployed()
13 |
14 | // Deploy TokenFarm
15 | await deployer.deploy(TokenFarm, dappToken.address, daiToken.address)
16 | const tokenFarm = await TokenFarm.deployed()
17 |
18 | // Transfer all tokens to TokenFarm (1 million)
19 | await dappToken.transfer(tokenFarm.address, '1000000000000000000000000')
20 |
21 | // Transfer 100 Mock DAI tokens to investor
22 | await daiToken.transfer(accounts[1], '100000000000000000000')
23 | }
24 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "defi-tutorial",
3 | "version": "0.1.0",
4 | "description": "DeFi Token Staking App",
5 | "author": "gregory@dappuniversity.com",
6 | "dependencies": {
7 | "babel-polyfill": "6.26.0",
8 | "babel-preset-env": "1.7.0",
9 | "babel-preset-es2015": "6.24.1",
10 | "babel-preset-stage-2": "6.24.1",
11 | "babel-preset-stage-3": "6.24.1",
12 | "babel-register": "6.26.0",
13 | "bootstrap": "4.3.1",
14 | "chai": "4.2.0",
15 | "chai-as-promised": "7.1.1",
16 | "chai-bignumber": "3.0.0",
17 | "identicon.js": "^2.3.3",
18 | "react": "16.8.4",
19 | "react-bootstrap": "1.0.0-beta.5",
20 | "react-dom": "16.8.4",
21 | "react-scripts": "2.1.3",
22 | "truffle": "5.1.39",
23 | "web3": "1.2.11"
24 | },
25 | "scripts": {
26 | "start": "react-scripts start",
27 | "build": "react-scripts build",
28 | "test": "react-scripts test",
29 | "eject": "react-scripts eject"
30 | },
31 | "eslintConfig": {
32 | "extends": "react-app"
33 | },
34 | "browserslist": [
35 | ">0.2%",
36 | "not dead",
37 | "not ie <= 11",
38 | "not op_mini all"
39 | ]
40 | }
41 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dappuniversity/defi_tutorial/7d86e7f1c4f737ad39dd97b4c01915f8603b5588/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
10 |
11 |
15 |
16 |
25 | Dapp Token Farm
26 |
27 |
28 |
29 |
30 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "Starter Kit",
3 | "name": "Dapp Token Farm",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/scripts/issue-token.js:
--------------------------------------------------------------------------------
1 | const TokenFarm = artifacts.require('TokenFarm')
2 |
3 | module.exports = async function(callback) {
4 | let tokenFarm = await TokenFarm.deployed()
5 | await tokenFarm.issueTokens()
6 | // Code goes here...
7 | console.log("Tokens issued!")
8 | callback()
9 | }
10 |
--------------------------------------------------------------------------------
/src/abis/Migrations.json:
--------------------------------------------------------------------------------
1 | {
2 | "contractName": "Migrations",
3 | "abi": [
4 | {
5 | "inputs": [],
6 | "payable": false,
7 | "stateMutability": "nonpayable",
8 | "type": "constructor"
9 | },
10 | {
11 | "constant": true,
12 | "inputs": [],
13 | "name": "last_completed_migration",
14 | "outputs": [
15 | {
16 | "internalType": "uint256",
17 | "name": "",
18 | "type": "uint256"
19 | }
20 | ],
21 | "payable": false,
22 | "stateMutability": "view",
23 | "type": "function"
24 | },
25 | {
26 | "constant": true,
27 | "inputs": [],
28 | "name": "owner",
29 | "outputs": [
30 | {
31 | "internalType": "address",
32 | "name": "",
33 | "type": "address"
34 | }
35 | ],
36 | "payable": false,
37 | "stateMutability": "view",
38 | "type": "function"
39 | },
40 | {
41 | "constant": false,
42 | "inputs": [
43 | {
44 | "internalType": "uint256",
45 | "name": "completed",
46 | "type": "uint256"
47 | }
48 | ],
49 | "name": "setCompleted",
50 | "outputs": [],
51 | "payable": false,
52 | "stateMutability": "nonpayable",
53 | "type": "function"
54 | },
55 | {
56 | "constant": false,
57 | "inputs": [
58 | {
59 | "internalType": "address",
60 | "name": "new_address",
61 | "type": "address"
62 | }
63 | ],
64 | "name": "upgrade",
65 | "outputs": [],
66 | "payable": false,
67 | "stateMutability": "nonpayable",
68 | "type": "function"
69 | }
70 | ],
71 | "metadata": "{\"compiler\":{\"version\":\"0.5.16+commit.9c3226ce\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"constant\":true,\"inputs\":[],\"name\":\"last_completed_migration\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"completed\",\"type\":\"uint256\"}],\"name\":\"setCompleted\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"new_address\",\"type\":\"address\"}],\"name\":\"upgrade\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"methods\":{}},\"userdoc\":{\"methods\":{}}},\"settings\":{\"compilationTarget\":{\"/Users/gregory/code/defi_tutorial/src/contracts/Migrations.sol\":\"Migrations\"},\"evmVersion\":\"petersburg\",\"libraries\":{},\"optimizer\":{\"enabled\":false,\"runs\":200},\"remappings\":[]},\"sources\":{\"/Users/gregory/code/defi_tutorial/src/contracts/Migrations.sol\":{\"keccak256\":\"0xfdb731592344e2a2890faf03baec7b4bee7057ffba18ba6dbb6eec8db85f8f4c\",\"urls\":[\"bzz-raw://f9b488bbb84816dd04c1b155e943319758db16ee943943648fb264bccecc9879\",\"dweb:/ipfs/QmbW34mYrj3uLteyHf3S46pnp9bnwovtCXHbdBHfzMkSZx\"]}},\"version\":1}",
72 | "bytecode": "0x608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506102b7806100606000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c80630900f01014610051578063445df0ac146100955780638da5cb5b146100b3578063fdacd576146100fd575b600080fd5b6100936004803603602081101561006757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061012b565b005b61009d6101f7565b6040518082815260200191505060405180910390f35b6100bb6101fd565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6101296004803603602081101561011357600080fd5b8101908080359060200190929190505050610222565b005b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614156101f45760008190508073ffffffffffffffffffffffffffffffffffffffff1663fdacd5766001546040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156101da57600080fd5b505af11580156101ee573d6000803e3d6000fd5b50505050505b50565b60015481565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561027f57806001819055505b5056fea265627a7a72315820c46be0c3c07eaa3e907f1557f7161dae5b9d38ef67f4c3f2adc1a2df7489fe4664736f6c63430005100032",
73 | "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061004c5760003560e01c80630900f01014610051578063445df0ac146100955780638da5cb5b146100b3578063fdacd576146100fd575b600080fd5b6100936004803603602081101561006757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061012b565b005b61009d6101f7565b6040518082815260200191505060405180910390f35b6100bb6101fd565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6101296004803603602081101561011357600080fd5b8101908080359060200190929190505050610222565b005b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614156101f45760008190508073ffffffffffffffffffffffffffffffffffffffff1663fdacd5766001546040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156101da57600080fd5b505af11580156101ee573d6000803e3d6000fd5b50505050505b50565b60015481565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561027f57806001819055505b5056fea265627a7a72315820c46be0c3c07eaa3e907f1557f7161dae5b9d38ef67f4c3f2adc1a2df7489fe4664736f6c63430005100032",
74 | "sourceMap": "34:480:2:-;;;123:50;8:9:-1;5:2;;;30:1;27;20:12;5:2;123:50:2;158:10;150:5;;:18;;;;;;;;;;;;;;;;;;34:480;;;;;;",
75 | "deployedSourceMap": "34:480:2:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;34:480:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;347:165;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;347:165:2;;;;;;;;;;;;;;;;;;;:::i;:::-;;82:36;;;:::i;:::-;;;;;;;;;;;;;;;;;;;58:20;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;240:103;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;240:103:2;;;;;;;;;;;;;;;;;:::i;:::-;;347:165;223:5;;;;;;;;;;;209:19;;:10;:19;;;205:26;;;409:19;442:11;409:45;;460:8;:21;;;482:24;;460:47;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;460:47:2;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;460:47:2;;;;230:1;205:26;347:165;:::o;82:36::-;;;;:::o;58:20::-;;;;;;;;;;;;;:::o;240:103::-;223:5;;;;;;;;;;;209:19;;:10;:19;;;205:26;;;329:9;302:24;:36;;;;205:26;240:103;:::o",
76 | "source": "pragma solidity >=0.4.21 <0.6.0;\n\ncontract Migrations {\n address public owner;\n uint public last_completed_migration;\n\n constructor() public {\n owner = msg.sender;\n }\n\n modifier restricted() {\n if (msg.sender == owner) _;\n }\n\n function setCompleted(uint completed) public restricted {\n last_completed_migration = completed;\n }\n\n function upgrade(address new_address) public restricted {\n Migrations upgraded = Migrations(new_address);\n upgraded.setCompleted(last_completed_migration);\n }\n}\n",
77 | "sourcePath": "/Users/gregory/code/defi_tutorial/src/contracts/Migrations.sol",
78 | "ast": {
79 | "absolutePath": "/Users/gregory/code/defi_tutorial/src/contracts/Migrations.sol",
80 | "exportedSymbols": {
81 | "Migrations": [
82 | 418
83 | ]
84 | },
85 | "id": 419,
86 | "nodeType": "SourceUnit",
87 | "nodes": [
88 | {
89 | "id": 363,
90 | "literals": [
91 | "solidity",
92 | ">=",
93 | "0.4",
94 | ".21",
95 | "<",
96 | "0.6",
97 | ".0"
98 | ],
99 | "nodeType": "PragmaDirective",
100 | "src": "0:32:2"
101 | },
102 | {
103 | "baseContracts": [],
104 | "contractDependencies": [],
105 | "contractKind": "contract",
106 | "documentation": null,
107 | "fullyImplemented": true,
108 | "id": 418,
109 | "linearizedBaseContracts": [
110 | 418
111 | ],
112 | "name": "Migrations",
113 | "nodeType": "ContractDefinition",
114 | "nodes": [
115 | {
116 | "constant": false,
117 | "id": 365,
118 | "name": "owner",
119 | "nodeType": "VariableDeclaration",
120 | "scope": 418,
121 | "src": "58:20:2",
122 | "stateVariable": true,
123 | "storageLocation": "default",
124 | "typeDescriptions": {
125 | "typeIdentifier": "t_address",
126 | "typeString": "address"
127 | },
128 | "typeName": {
129 | "id": 364,
130 | "name": "address",
131 | "nodeType": "ElementaryTypeName",
132 | "src": "58:7:2",
133 | "stateMutability": "nonpayable",
134 | "typeDescriptions": {
135 | "typeIdentifier": "t_address",
136 | "typeString": "address"
137 | }
138 | },
139 | "value": null,
140 | "visibility": "public"
141 | },
142 | {
143 | "constant": false,
144 | "id": 367,
145 | "name": "last_completed_migration",
146 | "nodeType": "VariableDeclaration",
147 | "scope": 418,
148 | "src": "82:36:2",
149 | "stateVariable": true,
150 | "storageLocation": "default",
151 | "typeDescriptions": {
152 | "typeIdentifier": "t_uint256",
153 | "typeString": "uint256"
154 | },
155 | "typeName": {
156 | "id": 366,
157 | "name": "uint",
158 | "nodeType": "ElementaryTypeName",
159 | "src": "82:4:2",
160 | "typeDescriptions": {
161 | "typeIdentifier": "t_uint256",
162 | "typeString": "uint256"
163 | }
164 | },
165 | "value": null,
166 | "visibility": "public"
167 | },
168 | {
169 | "body": {
170 | "id": 375,
171 | "nodeType": "Block",
172 | "src": "144:29:2",
173 | "statements": [
174 | {
175 | "expression": {
176 | "argumentTypes": null,
177 | "id": 373,
178 | "isConstant": false,
179 | "isLValue": false,
180 | "isPure": false,
181 | "lValueRequested": false,
182 | "leftHandSide": {
183 | "argumentTypes": null,
184 | "id": 370,
185 | "name": "owner",
186 | "nodeType": "Identifier",
187 | "overloadedDeclarations": [],
188 | "referencedDeclaration": 365,
189 | "src": "150:5:2",
190 | "typeDescriptions": {
191 | "typeIdentifier": "t_address",
192 | "typeString": "address"
193 | }
194 | },
195 | "nodeType": "Assignment",
196 | "operator": "=",
197 | "rightHandSide": {
198 | "argumentTypes": null,
199 | "expression": {
200 | "argumentTypes": null,
201 | "id": 371,
202 | "name": "msg",
203 | "nodeType": "Identifier",
204 | "overloadedDeclarations": [],
205 | "referencedDeclaration": 439,
206 | "src": "158:3:2",
207 | "typeDescriptions": {
208 | "typeIdentifier": "t_magic_message",
209 | "typeString": "msg"
210 | }
211 | },
212 | "id": 372,
213 | "isConstant": false,
214 | "isLValue": false,
215 | "isPure": false,
216 | "lValueRequested": false,
217 | "memberName": "sender",
218 | "nodeType": "MemberAccess",
219 | "referencedDeclaration": null,
220 | "src": "158:10:2",
221 | "typeDescriptions": {
222 | "typeIdentifier": "t_address_payable",
223 | "typeString": "address payable"
224 | }
225 | },
226 | "src": "150:18:2",
227 | "typeDescriptions": {
228 | "typeIdentifier": "t_address",
229 | "typeString": "address"
230 | }
231 | },
232 | "id": 374,
233 | "nodeType": "ExpressionStatement",
234 | "src": "150:18:2"
235 | }
236 | ]
237 | },
238 | "documentation": null,
239 | "id": 376,
240 | "implemented": true,
241 | "kind": "constructor",
242 | "modifiers": [],
243 | "name": "",
244 | "nodeType": "FunctionDefinition",
245 | "parameters": {
246 | "id": 368,
247 | "nodeType": "ParameterList",
248 | "parameters": [],
249 | "src": "134:2:2"
250 | },
251 | "returnParameters": {
252 | "id": 369,
253 | "nodeType": "ParameterList",
254 | "parameters": [],
255 | "src": "144:0:2"
256 | },
257 | "scope": 418,
258 | "src": "123:50:2",
259 | "stateMutability": "nonpayable",
260 | "superFunction": null,
261 | "visibility": "public"
262 | },
263 | {
264 | "body": {
265 | "id": 384,
266 | "nodeType": "Block",
267 | "src": "199:37:2",
268 | "statements": [
269 | {
270 | "condition": {
271 | "argumentTypes": null,
272 | "commonType": {
273 | "typeIdentifier": "t_address",
274 | "typeString": "address"
275 | },
276 | "id": 381,
277 | "isConstant": false,
278 | "isLValue": false,
279 | "isPure": false,
280 | "lValueRequested": false,
281 | "leftExpression": {
282 | "argumentTypes": null,
283 | "expression": {
284 | "argumentTypes": null,
285 | "id": 378,
286 | "name": "msg",
287 | "nodeType": "Identifier",
288 | "overloadedDeclarations": [],
289 | "referencedDeclaration": 439,
290 | "src": "209:3:2",
291 | "typeDescriptions": {
292 | "typeIdentifier": "t_magic_message",
293 | "typeString": "msg"
294 | }
295 | },
296 | "id": 379,
297 | "isConstant": false,
298 | "isLValue": false,
299 | "isPure": false,
300 | "lValueRequested": false,
301 | "memberName": "sender",
302 | "nodeType": "MemberAccess",
303 | "referencedDeclaration": null,
304 | "src": "209:10:2",
305 | "typeDescriptions": {
306 | "typeIdentifier": "t_address_payable",
307 | "typeString": "address payable"
308 | }
309 | },
310 | "nodeType": "BinaryOperation",
311 | "operator": "==",
312 | "rightExpression": {
313 | "argumentTypes": null,
314 | "id": 380,
315 | "name": "owner",
316 | "nodeType": "Identifier",
317 | "overloadedDeclarations": [],
318 | "referencedDeclaration": 365,
319 | "src": "223:5:2",
320 | "typeDescriptions": {
321 | "typeIdentifier": "t_address",
322 | "typeString": "address"
323 | }
324 | },
325 | "src": "209:19:2",
326 | "typeDescriptions": {
327 | "typeIdentifier": "t_bool",
328 | "typeString": "bool"
329 | }
330 | },
331 | "falseBody": null,
332 | "id": 383,
333 | "nodeType": "IfStatement",
334 | "src": "205:26:2",
335 | "trueBody": {
336 | "id": 382,
337 | "nodeType": "PlaceholderStatement",
338 | "src": "230:1:2"
339 | }
340 | }
341 | ]
342 | },
343 | "documentation": null,
344 | "id": 385,
345 | "name": "restricted",
346 | "nodeType": "ModifierDefinition",
347 | "parameters": {
348 | "id": 377,
349 | "nodeType": "ParameterList",
350 | "parameters": [],
351 | "src": "196:2:2"
352 | },
353 | "src": "177:59:2",
354 | "visibility": "internal"
355 | },
356 | {
357 | "body": {
358 | "id": 396,
359 | "nodeType": "Block",
360 | "src": "296:47:2",
361 | "statements": [
362 | {
363 | "expression": {
364 | "argumentTypes": null,
365 | "id": 394,
366 | "isConstant": false,
367 | "isLValue": false,
368 | "isPure": false,
369 | "lValueRequested": false,
370 | "leftHandSide": {
371 | "argumentTypes": null,
372 | "id": 392,
373 | "name": "last_completed_migration",
374 | "nodeType": "Identifier",
375 | "overloadedDeclarations": [],
376 | "referencedDeclaration": 367,
377 | "src": "302:24:2",
378 | "typeDescriptions": {
379 | "typeIdentifier": "t_uint256",
380 | "typeString": "uint256"
381 | }
382 | },
383 | "nodeType": "Assignment",
384 | "operator": "=",
385 | "rightHandSide": {
386 | "argumentTypes": null,
387 | "id": 393,
388 | "name": "completed",
389 | "nodeType": "Identifier",
390 | "overloadedDeclarations": [],
391 | "referencedDeclaration": 387,
392 | "src": "329:9:2",
393 | "typeDescriptions": {
394 | "typeIdentifier": "t_uint256",
395 | "typeString": "uint256"
396 | }
397 | },
398 | "src": "302:36:2",
399 | "typeDescriptions": {
400 | "typeIdentifier": "t_uint256",
401 | "typeString": "uint256"
402 | }
403 | },
404 | "id": 395,
405 | "nodeType": "ExpressionStatement",
406 | "src": "302:36:2"
407 | }
408 | ]
409 | },
410 | "documentation": null,
411 | "id": 397,
412 | "implemented": true,
413 | "kind": "function",
414 | "modifiers": [
415 | {
416 | "arguments": null,
417 | "id": 390,
418 | "modifierName": {
419 | "argumentTypes": null,
420 | "id": 389,
421 | "name": "restricted",
422 | "nodeType": "Identifier",
423 | "overloadedDeclarations": [],
424 | "referencedDeclaration": 385,
425 | "src": "285:10:2",
426 | "typeDescriptions": {
427 | "typeIdentifier": "t_modifier$__$",
428 | "typeString": "modifier ()"
429 | }
430 | },
431 | "nodeType": "ModifierInvocation",
432 | "src": "285:10:2"
433 | }
434 | ],
435 | "name": "setCompleted",
436 | "nodeType": "FunctionDefinition",
437 | "parameters": {
438 | "id": 388,
439 | "nodeType": "ParameterList",
440 | "parameters": [
441 | {
442 | "constant": false,
443 | "id": 387,
444 | "name": "completed",
445 | "nodeType": "VariableDeclaration",
446 | "scope": 397,
447 | "src": "262:14:2",
448 | "stateVariable": false,
449 | "storageLocation": "default",
450 | "typeDescriptions": {
451 | "typeIdentifier": "t_uint256",
452 | "typeString": "uint256"
453 | },
454 | "typeName": {
455 | "id": 386,
456 | "name": "uint",
457 | "nodeType": "ElementaryTypeName",
458 | "src": "262:4:2",
459 | "typeDescriptions": {
460 | "typeIdentifier": "t_uint256",
461 | "typeString": "uint256"
462 | }
463 | },
464 | "value": null,
465 | "visibility": "internal"
466 | }
467 | ],
468 | "src": "261:16:2"
469 | },
470 | "returnParameters": {
471 | "id": 391,
472 | "nodeType": "ParameterList",
473 | "parameters": [],
474 | "src": "296:0:2"
475 | },
476 | "scope": 418,
477 | "src": "240:103:2",
478 | "stateMutability": "nonpayable",
479 | "superFunction": null,
480 | "visibility": "public"
481 | },
482 | {
483 | "body": {
484 | "id": 416,
485 | "nodeType": "Block",
486 | "src": "403:109:2",
487 | "statements": [
488 | {
489 | "assignments": [
490 | 405
491 | ],
492 | "declarations": [
493 | {
494 | "constant": false,
495 | "id": 405,
496 | "name": "upgraded",
497 | "nodeType": "VariableDeclaration",
498 | "scope": 416,
499 | "src": "409:19:2",
500 | "stateVariable": false,
501 | "storageLocation": "default",
502 | "typeDescriptions": {
503 | "typeIdentifier": "t_contract$_Migrations_$418",
504 | "typeString": "contract Migrations"
505 | },
506 | "typeName": {
507 | "contractScope": null,
508 | "id": 404,
509 | "name": "Migrations",
510 | "nodeType": "UserDefinedTypeName",
511 | "referencedDeclaration": 418,
512 | "src": "409:10:2",
513 | "typeDescriptions": {
514 | "typeIdentifier": "t_contract$_Migrations_$418",
515 | "typeString": "contract Migrations"
516 | }
517 | },
518 | "value": null,
519 | "visibility": "internal"
520 | }
521 | ],
522 | "id": 409,
523 | "initialValue": {
524 | "argumentTypes": null,
525 | "arguments": [
526 | {
527 | "argumentTypes": null,
528 | "id": 407,
529 | "name": "new_address",
530 | "nodeType": "Identifier",
531 | "overloadedDeclarations": [],
532 | "referencedDeclaration": 399,
533 | "src": "442:11:2",
534 | "typeDescriptions": {
535 | "typeIdentifier": "t_address",
536 | "typeString": "address"
537 | }
538 | }
539 | ],
540 | "expression": {
541 | "argumentTypes": [
542 | {
543 | "typeIdentifier": "t_address",
544 | "typeString": "address"
545 | }
546 | ],
547 | "id": 406,
548 | "name": "Migrations",
549 | "nodeType": "Identifier",
550 | "overloadedDeclarations": [],
551 | "referencedDeclaration": 418,
552 | "src": "431:10:2",
553 | "typeDescriptions": {
554 | "typeIdentifier": "t_type$_t_contract$_Migrations_$418_$",
555 | "typeString": "type(contract Migrations)"
556 | }
557 | },
558 | "id": 408,
559 | "isConstant": false,
560 | "isLValue": false,
561 | "isPure": false,
562 | "kind": "typeConversion",
563 | "lValueRequested": false,
564 | "names": [],
565 | "nodeType": "FunctionCall",
566 | "src": "431:23:2",
567 | "typeDescriptions": {
568 | "typeIdentifier": "t_contract$_Migrations_$418",
569 | "typeString": "contract Migrations"
570 | }
571 | },
572 | "nodeType": "VariableDeclarationStatement",
573 | "src": "409:45:2"
574 | },
575 | {
576 | "expression": {
577 | "argumentTypes": null,
578 | "arguments": [
579 | {
580 | "argumentTypes": null,
581 | "id": 413,
582 | "name": "last_completed_migration",
583 | "nodeType": "Identifier",
584 | "overloadedDeclarations": [],
585 | "referencedDeclaration": 367,
586 | "src": "482:24:2",
587 | "typeDescriptions": {
588 | "typeIdentifier": "t_uint256",
589 | "typeString": "uint256"
590 | }
591 | }
592 | ],
593 | "expression": {
594 | "argumentTypes": [
595 | {
596 | "typeIdentifier": "t_uint256",
597 | "typeString": "uint256"
598 | }
599 | ],
600 | "expression": {
601 | "argumentTypes": null,
602 | "id": 410,
603 | "name": "upgraded",
604 | "nodeType": "Identifier",
605 | "overloadedDeclarations": [],
606 | "referencedDeclaration": 405,
607 | "src": "460:8:2",
608 | "typeDescriptions": {
609 | "typeIdentifier": "t_contract$_Migrations_$418",
610 | "typeString": "contract Migrations"
611 | }
612 | },
613 | "id": 412,
614 | "isConstant": false,
615 | "isLValue": false,
616 | "isPure": false,
617 | "lValueRequested": false,
618 | "memberName": "setCompleted",
619 | "nodeType": "MemberAccess",
620 | "referencedDeclaration": 397,
621 | "src": "460:21:2",
622 | "typeDescriptions": {
623 | "typeIdentifier": "t_function_external_nonpayable$_t_uint256_$returns$__$",
624 | "typeString": "function (uint256) external"
625 | }
626 | },
627 | "id": 414,
628 | "isConstant": false,
629 | "isLValue": false,
630 | "isPure": false,
631 | "kind": "functionCall",
632 | "lValueRequested": false,
633 | "names": [],
634 | "nodeType": "FunctionCall",
635 | "src": "460:47:2",
636 | "typeDescriptions": {
637 | "typeIdentifier": "t_tuple$__$",
638 | "typeString": "tuple()"
639 | }
640 | },
641 | "id": 415,
642 | "nodeType": "ExpressionStatement",
643 | "src": "460:47:2"
644 | }
645 | ]
646 | },
647 | "documentation": null,
648 | "id": 417,
649 | "implemented": true,
650 | "kind": "function",
651 | "modifiers": [
652 | {
653 | "arguments": null,
654 | "id": 402,
655 | "modifierName": {
656 | "argumentTypes": null,
657 | "id": 401,
658 | "name": "restricted",
659 | "nodeType": "Identifier",
660 | "overloadedDeclarations": [],
661 | "referencedDeclaration": 385,
662 | "src": "392:10:2",
663 | "typeDescriptions": {
664 | "typeIdentifier": "t_modifier$__$",
665 | "typeString": "modifier ()"
666 | }
667 | },
668 | "nodeType": "ModifierInvocation",
669 | "src": "392:10:2"
670 | }
671 | ],
672 | "name": "upgrade",
673 | "nodeType": "FunctionDefinition",
674 | "parameters": {
675 | "id": 400,
676 | "nodeType": "ParameterList",
677 | "parameters": [
678 | {
679 | "constant": false,
680 | "id": 399,
681 | "name": "new_address",
682 | "nodeType": "VariableDeclaration",
683 | "scope": 417,
684 | "src": "364:19:2",
685 | "stateVariable": false,
686 | "storageLocation": "default",
687 | "typeDescriptions": {
688 | "typeIdentifier": "t_address",
689 | "typeString": "address"
690 | },
691 | "typeName": {
692 | "id": 398,
693 | "name": "address",
694 | "nodeType": "ElementaryTypeName",
695 | "src": "364:7:2",
696 | "stateMutability": "nonpayable",
697 | "typeDescriptions": {
698 | "typeIdentifier": "t_address",
699 | "typeString": "address"
700 | }
701 | },
702 | "value": null,
703 | "visibility": "internal"
704 | }
705 | ],
706 | "src": "363:21:2"
707 | },
708 | "returnParameters": {
709 | "id": 403,
710 | "nodeType": "ParameterList",
711 | "parameters": [],
712 | "src": "403:0:2"
713 | },
714 | "scope": 418,
715 | "src": "347:165:2",
716 | "stateMutability": "nonpayable",
717 | "superFunction": null,
718 | "visibility": "public"
719 | }
720 | ],
721 | "scope": 419,
722 | "src": "34:480:2"
723 | }
724 | ],
725 | "src": "0:515:2"
726 | },
727 | "legacyAST": {
728 | "absolutePath": "/Users/gregory/code/defi_tutorial/src/contracts/Migrations.sol",
729 | "exportedSymbols": {
730 | "Migrations": [
731 | 418
732 | ]
733 | },
734 | "id": 419,
735 | "nodeType": "SourceUnit",
736 | "nodes": [
737 | {
738 | "id": 363,
739 | "literals": [
740 | "solidity",
741 | ">=",
742 | "0.4",
743 | ".21",
744 | "<",
745 | "0.6",
746 | ".0"
747 | ],
748 | "nodeType": "PragmaDirective",
749 | "src": "0:32:2"
750 | },
751 | {
752 | "baseContracts": [],
753 | "contractDependencies": [],
754 | "contractKind": "contract",
755 | "documentation": null,
756 | "fullyImplemented": true,
757 | "id": 418,
758 | "linearizedBaseContracts": [
759 | 418
760 | ],
761 | "name": "Migrations",
762 | "nodeType": "ContractDefinition",
763 | "nodes": [
764 | {
765 | "constant": false,
766 | "id": 365,
767 | "name": "owner",
768 | "nodeType": "VariableDeclaration",
769 | "scope": 418,
770 | "src": "58:20:2",
771 | "stateVariable": true,
772 | "storageLocation": "default",
773 | "typeDescriptions": {
774 | "typeIdentifier": "t_address",
775 | "typeString": "address"
776 | },
777 | "typeName": {
778 | "id": 364,
779 | "name": "address",
780 | "nodeType": "ElementaryTypeName",
781 | "src": "58:7:2",
782 | "stateMutability": "nonpayable",
783 | "typeDescriptions": {
784 | "typeIdentifier": "t_address",
785 | "typeString": "address"
786 | }
787 | },
788 | "value": null,
789 | "visibility": "public"
790 | },
791 | {
792 | "constant": false,
793 | "id": 367,
794 | "name": "last_completed_migration",
795 | "nodeType": "VariableDeclaration",
796 | "scope": 418,
797 | "src": "82:36:2",
798 | "stateVariable": true,
799 | "storageLocation": "default",
800 | "typeDescriptions": {
801 | "typeIdentifier": "t_uint256",
802 | "typeString": "uint256"
803 | },
804 | "typeName": {
805 | "id": 366,
806 | "name": "uint",
807 | "nodeType": "ElementaryTypeName",
808 | "src": "82:4:2",
809 | "typeDescriptions": {
810 | "typeIdentifier": "t_uint256",
811 | "typeString": "uint256"
812 | }
813 | },
814 | "value": null,
815 | "visibility": "public"
816 | },
817 | {
818 | "body": {
819 | "id": 375,
820 | "nodeType": "Block",
821 | "src": "144:29:2",
822 | "statements": [
823 | {
824 | "expression": {
825 | "argumentTypes": null,
826 | "id": 373,
827 | "isConstant": false,
828 | "isLValue": false,
829 | "isPure": false,
830 | "lValueRequested": false,
831 | "leftHandSide": {
832 | "argumentTypes": null,
833 | "id": 370,
834 | "name": "owner",
835 | "nodeType": "Identifier",
836 | "overloadedDeclarations": [],
837 | "referencedDeclaration": 365,
838 | "src": "150:5:2",
839 | "typeDescriptions": {
840 | "typeIdentifier": "t_address",
841 | "typeString": "address"
842 | }
843 | },
844 | "nodeType": "Assignment",
845 | "operator": "=",
846 | "rightHandSide": {
847 | "argumentTypes": null,
848 | "expression": {
849 | "argumentTypes": null,
850 | "id": 371,
851 | "name": "msg",
852 | "nodeType": "Identifier",
853 | "overloadedDeclarations": [],
854 | "referencedDeclaration": 439,
855 | "src": "158:3:2",
856 | "typeDescriptions": {
857 | "typeIdentifier": "t_magic_message",
858 | "typeString": "msg"
859 | }
860 | },
861 | "id": 372,
862 | "isConstant": false,
863 | "isLValue": false,
864 | "isPure": false,
865 | "lValueRequested": false,
866 | "memberName": "sender",
867 | "nodeType": "MemberAccess",
868 | "referencedDeclaration": null,
869 | "src": "158:10:2",
870 | "typeDescriptions": {
871 | "typeIdentifier": "t_address_payable",
872 | "typeString": "address payable"
873 | }
874 | },
875 | "src": "150:18:2",
876 | "typeDescriptions": {
877 | "typeIdentifier": "t_address",
878 | "typeString": "address"
879 | }
880 | },
881 | "id": 374,
882 | "nodeType": "ExpressionStatement",
883 | "src": "150:18:2"
884 | }
885 | ]
886 | },
887 | "documentation": null,
888 | "id": 376,
889 | "implemented": true,
890 | "kind": "constructor",
891 | "modifiers": [],
892 | "name": "",
893 | "nodeType": "FunctionDefinition",
894 | "parameters": {
895 | "id": 368,
896 | "nodeType": "ParameterList",
897 | "parameters": [],
898 | "src": "134:2:2"
899 | },
900 | "returnParameters": {
901 | "id": 369,
902 | "nodeType": "ParameterList",
903 | "parameters": [],
904 | "src": "144:0:2"
905 | },
906 | "scope": 418,
907 | "src": "123:50:2",
908 | "stateMutability": "nonpayable",
909 | "superFunction": null,
910 | "visibility": "public"
911 | },
912 | {
913 | "body": {
914 | "id": 384,
915 | "nodeType": "Block",
916 | "src": "199:37:2",
917 | "statements": [
918 | {
919 | "condition": {
920 | "argumentTypes": null,
921 | "commonType": {
922 | "typeIdentifier": "t_address",
923 | "typeString": "address"
924 | },
925 | "id": 381,
926 | "isConstant": false,
927 | "isLValue": false,
928 | "isPure": false,
929 | "lValueRequested": false,
930 | "leftExpression": {
931 | "argumentTypes": null,
932 | "expression": {
933 | "argumentTypes": null,
934 | "id": 378,
935 | "name": "msg",
936 | "nodeType": "Identifier",
937 | "overloadedDeclarations": [],
938 | "referencedDeclaration": 439,
939 | "src": "209:3:2",
940 | "typeDescriptions": {
941 | "typeIdentifier": "t_magic_message",
942 | "typeString": "msg"
943 | }
944 | },
945 | "id": 379,
946 | "isConstant": false,
947 | "isLValue": false,
948 | "isPure": false,
949 | "lValueRequested": false,
950 | "memberName": "sender",
951 | "nodeType": "MemberAccess",
952 | "referencedDeclaration": null,
953 | "src": "209:10:2",
954 | "typeDescriptions": {
955 | "typeIdentifier": "t_address_payable",
956 | "typeString": "address payable"
957 | }
958 | },
959 | "nodeType": "BinaryOperation",
960 | "operator": "==",
961 | "rightExpression": {
962 | "argumentTypes": null,
963 | "id": 380,
964 | "name": "owner",
965 | "nodeType": "Identifier",
966 | "overloadedDeclarations": [],
967 | "referencedDeclaration": 365,
968 | "src": "223:5:2",
969 | "typeDescriptions": {
970 | "typeIdentifier": "t_address",
971 | "typeString": "address"
972 | }
973 | },
974 | "src": "209:19:2",
975 | "typeDescriptions": {
976 | "typeIdentifier": "t_bool",
977 | "typeString": "bool"
978 | }
979 | },
980 | "falseBody": null,
981 | "id": 383,
982 | "nodeType": "IfStatement",
983 | "src": "205:26:2",
984 | "trueBody": {
985 | "id": 382,
986 | "nodeType": "PlaceholderStatement",
987 | "src": "230:1:2"
988 | }
989 | }
990 | ]
991 | },
992 | "documentation": null,
993 | "id": 385,
994 | "name": "restricted",
995 | "nodeType": "ModifierDefinition",
996 | "parameters": {
997 | "id": 377,
998 | "nodeType": "ParameterList",
999 | "parameters": [],
1000 | "src": "196:2:2"
1001 | },
1002 | "src": "177:59:2",
1003 | "visibility": "internal"
1004 | },
1005 | {
1006 | "body": {
1007 | "id": 396,
1008 | "nodeType": "Block",
1009 | "src": "296:47:2",
1010 | "statements": [
1011 | {
1012 | "expression": {
1013 | "argumentTypes": null,
1014 | "id": 394,
1015 | "isConstant": false,
1016 | "isLValue": false,
1017 | "isPure": false,
1018 | "lValueRequested": false,
1019 | "leftHandSide": {
1020 | "argumentTypes": null,
1021 | "id": 392,
1022 | "name": "last_completed_migration",
1023 | "nodeType": "Identifier",
1024 | "overloadedDeclarations": [],
1025 | "referencedDeclaration": 367,
1026 | "src": "302:24:2",
1027 | "typeDescriptions": {
1028 | "typeIdentifier": "t_uint256",
1029 | "typeString": "uint256"
1030 | }
1031 | },
1032 | "nodeType": "Assignment",
1033 | "operator": "=",
1034 | "rightHandSide": {
1035 | "argumentTypes": null,
1036 | "id": 393,
1037 | "name": "completed",
1038 | "nodeType": "Identifier",
1039 | "overloadedDeclarations": [],
1040 | "referencedDeclaration": 387,
1041 | "src": "329:9:2",
1042 | "typeDescriptions": {
1043 | "typeIdentifier": "t_uint256",
1044 | "typeString": "uint256"
1045 | }
1046 | },
1047 | "src": "302:36:2",
1048 | "typeDescriptions": {
1049 | "typeIdentifier": "t_uint256",
1050 | "typeString": "uint256"
1051 | }
1052 | },
1053 | "id": 395,
1054 | "nodeType": "ExpressionStatement",
1055 | "src": "302:36:2"
1056 | }
1057 | ]
1058 | },
1059 | "documentation": null,
1060 | "id": 397,
1061 | "implemented": true,
1062 | "kind": "function",
1063 | "modifiers": [
1064 | {
1065 | "arguments": null,
1066 | "id": 390,
1067 | "modifierName": {
1068 | "argumentTypes": null,
1069 | "id": 389,
1070 | "name": "restricted",
1071 | "nodeType": "Identifier",
1072 | "overloadedDeclarations": [],
1073 | "referencedDeclaration": 385,
1074 | "src": "285:10:2",
1075 | "typeDescriptions": {
1076 | "typeIdentifier": "t_modifier$__$",
1077 | "typeString": "modifier ()"
1078 | }
1079 | },
1080 | "nodeType": "ModifierInvocation",
1081 | "src": "285:10:2"
1082 | }
1083 | ],
1084 | "name": "setCompleted",
1085 | "nodeType": "FunctionDefinition",
1086 | "parameters": {
1087 | "id": 388,
1088 | "nodeType": "ParameterList",
1089 | "parameters": [
1090 | {
1091 | "constant": false,
1092 | "id": 387,
1093 | "name": "completed",
1094 | "nodeType": "VariableDeclaration",
1095 | "scope": 397,
1096 | "src": "262:14:2",
1097 | "stateVariable": false,
1098 | "storageLocation": "default",
1099 | "typeDescriptions": {
1100 | "typeIdentifier": "t_uint256",
1101 | "typeString": "uint256"
1102 | },
1103 | "typeName": {
1104 | "id": 386,
1105 | "name": "uint",
1106 | "nodeType": "ElementaryTypeName",
1107 | "src": "262:4:2",
1108 | "typeDescriptions": {
1109 | "typeIdentifier": "t_uint256",
1110 | "typeString": "uint256"
1111 | }
1112 | },
1113 | "value": null,
1114 | "visibility": "internal"
1115 | }
1116 | ],
1117 | "src": "261:16:2"
1118 | },
1119 | "returnParameters": {
1120 | "id": 391,
1121 | "nodeType": "ParameterList",
1122 | "parameters": [],
1123 | "src": "296:0:2"
1124 | },
1125 | "scope": 418,
1126 | "src": "240:103:2",
1127 | "stateMutability": "nonpayable",
1128 | "superFunction": null,
1129 | "visibility": "public"
1130 | },
1131 | {
1132 | "body": {
1133 | "id": 416,
1134 | "nodeType": "Block",
1135 | "src": "403:109:2",
1136 | "statements": [
1137 | {
1138 | "assignments": [
1139 | 405
1140 | ],
1141 | "declarations": [
1142 | {
1143 | "constant": false,
1144 | "id": 405,
1145 | "name": "upgraded",
1146 | "nodeType": "VariableDeclaration",
1147 | "scope": 416,
1148 | "src": "409:19:2",
1149 | "stateVariable": false,
1150 | "storageLocation": "default",
1151 | "typeDescriptions": {
1152 | "typeIdentifier": "t_contract$_Migrations_$418",
1153 | "typeString": "contract Migrations"
1154 | },
1155 | "typeName": {
1156 | "contractScope": null,
1157 | "id": 404,
1158 | "name": "Migrations",
1159 | "nodeType": "UserDefinedTypeName",
1160 | "referencedDeclaration": 418,
1161 | "src": "409:10:2",
1162 | "typeDescriptions": {
1163 | "typeIdentifier": "t_contract$_Migrations_$418",
1164 | "typeString": "contract Migrations"
1165 | }
1166 | },
1167 | "value": null,
1168 | "visibility": "internal"
1169 | }
1170 | ],
1171 | "id": 409,
1172 | "initialValue": {
1173 | "argumentTypes": null,
1174 | "arguments": [
1175 | {
1176 | "argumentTypes": null,
1177 | "id": 407,
1178 | "name": "new_address",
1179 | "nodeType": "Identifier",
1180 | "overloadedDeclarations": [],
1181 | "referencedDeclaration": 399,
1182 | "src": "442:11:2",
1183 | "typeDescriptions": {
1184 | "typeIdentifier": "t_address",
1185 | "typeString": "address"
1186 | }
1187 | }
1188 | ],
1189 | "expression": {
1190 | "argumentTypes": [
1191 | {
1192 | "typeIdentifier": "t_address",
1193 | "typeString": "address"
1194 | }
1195 | ],
1196 | "id": 406,
1197 | "name": "Migrations",
1198 | "nodeType": "Identifier",
1199 | "overloadedDeclarations": [],
1200 | "referencedDeclaration": 418,
1201 | "src": "431:10:2",
1202 | "typeDescriptions": {
1203 | "typeIdentifier": "t_type$_t_contract$_Migrations_$418_$",
1204 | "typeString": "type(contract Migrations)"
1205 | }
1206 | },
1207 | "id": 408,
1208 | "isConstant": false,
1209 | "isLValue": false,
1210 | "isPure": false,
1211 | "kind": "typeConversion",
1212 | "lValueRequested": false,
1213 | "names": [],
1214 | "nodeType": "FunctionCall",
1215 | "src": "431:23:2",
1216 | "typeDescriptions": {
1217 | "typeIdentifier": "t_contract$_Migrations_$418",
1218 | "typeString": "contract Migrations"
1219 | }
1220 | },
1221 | "nodeType": "VariableDeclarationStatement",
1222 | "src": "409:45:2"
1223 | },
1224 | {
1225 | "expression": {
1226 | "argumentTypes": null,
1227 | "arguments": [
1228 | {
1229 | "argumentTypes": null,
1230 | "id": 413,
1231 | "name": "last_completed_migration",
1232 | "nodeType": "Identifier",
1233 | "overloadedDeclarations": [],
1234 | "referencedDeclaration": 367,
1235 | "src": "482:24:2",
1236 | "typeDescriptions": {
1237 | "typeIdentifier": "t_uint256",
1238 | "typeString": "uint256"
1239 | }
1240 | }
1241 | ],
1242 | "expression": {
1243 | "argumentTypes": [
1244 | {
1245 | "typeIdentifier": "t_uint256",
1246 | "typeString": "uint256"
1247 | }
1248 | ],
1249 | "expression": {
1250 | "argumentTypes": null,
1251 | "id": 410,
1252 | "name": "upgraded",
1253 | "nodeType": "Identifier",
1254 | "overloadedDeclarations": [],
1255 | "referencedDeclaration": 405,
1256 | "src": "460:8:2",
1257 | "typeDescriptions": {
1258 | "typeIdentifier": "t_contract$_Migrations_$418",
1259 | "typeString": "contract Migrations"
1260 | }
1261 | },
1262 | "id": 412,
1263 | "isConstant": false,
1264 | "isLValue": false,
1265 | "isPure": false,
1266 | "lValueRequested": false,
1267 | "memberName": "setCompleted",
1268 | "nodeType": "MemberAccess",
1269 | "referencedDeclaration": 397,
1270 | "src": "460:21:2",
1271 | "typeDescriptions": {
1272 | "typeIdentifier": "t_function_external_nonpayable$_t_uint256_$returns$__$",
1273 | "typeString": "function (uint256) external"
1274 | }
1275 | },
1276 | "id": 414,
1277 | "isConstant": false,
1278 | "isLValue": false,
1279 | "isPure": false,
1280 | "kind": "functionCall",
1281 | "lValueRequested": false,
1282 | "names": [],
1283 | "nodeType": "FunctionCall",
1284 | "src": "460:47:2",
1285 | "typeDescriptions": {
1286 | "typeIdentifier": "t_tuple$__$",
1287 | "typeString": "tuple()"
1288 | }
1289 | },
1290 | "id": 415,
1291 | "nodeType": "ExpressionStatement",
1292 | "src": "460:47:2"
1293 | }
1294 | ]
1295 | },
1296 | "documentation": null,
1297 | "id": 417,
1298 | "implemented": true,
1299 | "kind": "function",
1300 | "modifiers": [
1301 | {
1302 | "arguments": null,
1303 | "id": 402,
1304 | "modifierName": {
1305 | "argumentTypes": null,
1306 | "id": 401,
1307 | "name": "restricted",
1308 | "nodeType": "Identifier",
1309 | "overloadedDeclarations": [],
1310 | "referencedDeclaration": 385,
1311 | "src": "392:10:2",
1312 | "typeDescriptions": {
1313 | "typeIdentifier": "t_modifier$__$",
1314 | "typeString": "modifier ()"
1315 | }
1316 | },
1317 | "nodeType": "ModifierInvocation",
1318 | "src": "392:10:2"
1319 | }
1320 | ],
1321 | "name": "upgrade",
1322 | "nodeType": "FunctionDefinition",
1323 | "parameters": {
1324 | "id": 400,
1325 | "nodeType": "ParameterList",
1326 | "parameters": [
1327 | {
1328 | "constant": false,
1329 | "id": 399,
1330 | "name": "new_address",
1331 | "nodeType": "VariableDeclaration",
1332 | "scope": 417,
1333 | "src": "364:19:2",
1334 | "stateVariable": false,
1335 | "storageLocation": "default",
1336 | "typeDescriptions": {
1337 | "typeIdentifier": "t_address",
1338 | "typeString": "address"
1339 | },
1340 | "typeName": {
1341 | "id": 398,
1342 | "name": "address",
1343 | "nodeType": "ElementaryTypeName",
1344 | "src": "364:7:2",
1345 | "stateMutability": "nonpayable",
1346 | "typeDescriptions": {
1347 | "typeIdentifier": "t_address",
1348 | "typeString": "address"
1349 | }
1350 | },
1351 | "value": null,
1352 | "visibility": "internal"
1353 | }
1354 | ],
1355 | "src": "363:21:2"
1356 | },
1357 | "returnParameters": {
1358 | "id": 403,
1359 | "nodeType": "ParameterList",
1360 | "parameters": [],
1361 | "src": "403:0:2"
1362 | },
1363 | "scope": 418,
1364 | "src": "347:165:2",
1365 | "stateMutability": "nonpayable",
1366 | "superFunction": null,
1367 | "visibility": "public"
1368 | }
1369 | ],
1370 | "scope": 419,
1371 | "src": "34:480:2"
1372 | }
1373 | ],
1374 | "src": "0:515:2"
1375 | },
1376 | "compiler": {
1377 | "name": "solc",
1378 | "version": "0.5.16+commit.9c3226ce.Emscripten.clang"
1379 | },
1380 | "networks": {
1381 | "5777": {
1382 | "events": {},
1383 | "links": {},
1384 | "address": "0x237f74501d59e9d8E2D9725c187eCf69de89C2E4",
1385 | "transactionHash": "0xf4d4c484b28c131288e1e97c20e82a7cc83a941fce84a77424f27092362b29c8"
1386 | }
1387 | },
1388 | "schemaVersion": "3.2.3",
1389 | "updatedAt": "2020-08-18T20:08:17.487Z",
1390 | "networkType": "ethereum",
1391 | "devdoc": {
1392 | "methods": {}
1393 | },
1394 | "userdoc": {
1395 | "methods": {}
1396 | }
1397 | }
--------------------------------------------------------------------------------
/src/components/App.css:
--------------------------------------------------------------------------------
1 | /* Styles go here */
2 |
--------------------------------------------------------------------------------
/src/components/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import Web3 from 'web3'
3 | import DaiToken from '../abis/DaiToken.json'
4 | import DappToken from '../abis/DappToken.json'
5 | import TokenFarm from '../abis/TokenFarm.json'
6 | import Navbar from './Navbar'
7 | import Main from './Main'
8 | import './App.css'
9 |
10 | class App extends Component {
11 |
12 | async componentWillMount() {
13 | await this.loadWeb3()
14 | await this.loadBlockchainData()
15 | }
16 |
17 | async loadBlockchainData() {
18 | const web3 = window.web3
19 |
20 | const accounts = await web3.eth.getAccounts()
21 | this.setState({ account: accounts[0] })
22 |
23 | const networkId = await web3.eth.net.getId()
24 |
25 | // Load DaiToken
26 | const daiTokenData = DaiToken.networks[networkId]
27 | if(daiTokenData) {
28 | const daiToken = new web3.eth.Contract(DaiToken.abi, daiTokenData.address)
29 | this.setState({ daiToken })
30 | let daiTokenBalance = await daiToken.methods.balanceOf(this.state.account).call()
31 | this.setState({ daiTokenBalance: daiTokenBalance.toString() })
32 | } else {
33 | window.alert('DaiToken contract not deployed to detected network.')
34 | }
35 |
36 | // Load DappToken
37 | const dappTokenData = DappToken.networks[networkId]
38 | if(dappTokenData) {
39 | const dappToken = new web3.eth.Contract(DappToken.abi, dappTokenData.address)
40 | this.setState({ dappToken })
41 | let dappTokenBalance = await dappToken.methods.balanceOf(this.state.account).call()
42 | this.setState({ dappTokenBalance: dappTokenBalance.toString() })
43 | } else {
44 | window.alert('DappToken contract not deployed to detected network.')
45 | }
46 |
47 | // Load TokenFarm
48 | const tokenFarmData = TokenFarm.networks[networkId]
49 | if(tokenFarmData) {
50 | const tokenFarm = new web3.eth.Contract(TokenFarm.abi, tokenFarmData.address)
51 | this.setState({ tokenFarm })
52 | let stakingBalance = await tokenFarm.methods.stakingBalance(this.state.account).call()
53 | this.setState({ stakingBalance: stakingBalance.toString() })
54 | } else {
55 | window.alert('TokenFarm contract not deployed to detected network.')
56 | }
57 |
58 | this.setState({ loading: false })
59 | }
60 |
61 | async loadWeb3() {
62 | if (window.ethereum) {
63 | window.web3 = new Web3(window.ethereum)
64 | await window.ethereum.enable()
65 | }
66 | else if (window.web3) {
67 | window.web3 = new Web3(window.web3.currentProvider)
68 | }
69 | else {
70 | window.alert('Non-Ethereum browser detected. You should consider trying MetaMask!')
71 | }
72 | }
73 |
74 | stakeTokens = (amount) => {
75 | this.setState({ loading: true })
76 | this.state.daiToken.methods.approve(this.state.tokenFarm._address, amount).send({ from: this.state.account }).on('transactionHash', (hash) => {
77 | this.state.tokenFarm.methods.stakeTokens(amount).send({ from: this.state.account }).on('transactionHash', (hash) => {
78 | this.setState({ loading: false })
79 | })
80 | })
81 | }
82 |
83 | unstakeTokens = (amount) => {
84 | this.setState({ loading: true })
85 | this.state.tokenFarm.methods.unstakeTokens().send({ from: this.state.account }).on('transactionHash', (hash) => {
86 | this.setState({ loading: false })
87 | })
88 | }
89 |
90 | constructor(props) {
91 | super(props)
92 | this.state = {
93 | account: '0x0',
94 | daiToken: {},
95 | dappToken: {},
96 | tokenFarm: {},
97 | daiTokenBalance: '0',
98 | dappTokenBalance: '0',
99 | stakingBalance: '0',
100 | loading: true
101 | }
102 | }
103 |
104 | render() {
105 | let content
106 | if(this.state.loading) {
107 | content = Loading...
108 | } else {
109 | content =
116 | }
117 |
118 | return (
119 |
120 |
121 |
122 |
123 |
124 |
125 |
130 |
131 |
132 | {content}
133 |
134 |
135 |
136 |
137 |
138 |
139 | );
140 | }
141 | }
142 |
143 | export default App;
144 |
--------------------------------------------------------------------------------
/src/components/Main.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import dai from '../dai.png'
3 |
4 | class Main extends Component {
5 |
6 | render() {
7 | return (
8 |
9 |
10 |
11 |
12 |
13 | Staking Balance |
14 | Reward Balance |
15 |
16 |
17 |
18 |
19 | {window.web3.utils.fromWei(this.props.stakingBalance, 'Ether')} mDAI |
20 | {window.web3.utils.fromWei(this.props.dappTokenBalance, 'Ether')} DAPP |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
58 |
67 |
68 |
69 |
70 |
71 | );
72 | }
73 | }
74 |
75 | export default Main;
76 |
--------------------------------------------------------------------------------
/src/components/Navbar.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import farmer from '../farmer.png'
3 |
4 | class Navbar extends Component {
5 |
6 | render() {
7 | return (
8 |
27 | );
28 | }
29 | }
30 |
31 | export default Navbar;
32 |
--------------------------------------------------------------------------------
/src/contracts/DaiToken.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.0;
2 |
3 | contract DaiToken {
4 | string public name = "Mock DAI Token";
5 | string public symbol = "mDAI";
6 | uint256 public totalSupply = 1000000000000000000000000; // 1 million tokens
7 | uint8 public decimals = 18;
8 |
9 | event Transfer(
10 | address indexed _from,
11 | address indexed _to,
12 | uint256 _value
13 | );
14 |
15 | event Approval(
16 | address indexed _owner,
17 | address indexed _spender,
18 | uint256 _value
19 | );
20 |
21 | mapping(address => uint256) public balanceOf;
22 | mapping(address => mapping(address => uint256)) public allowance;
23 |
24 | constructor() public {
25 | balanceOf[msg.sender] = totalSupply;
26 | }
27 |
28 | function transfer(address _to, uint256 _value) public returns (bool success) {
29 | require(balanceOf[msg.sender] >= _value);
30 | balanceOf[msg.sender] -= _value;
31 | balanceOf[_to] += _value;
32 | emit Transfer(msg.sender, _to, _value);
33 | return true;
34 | }
35 |
36 | function approve(address _spender, uint256 _value) public returns (bool success) {
37 | allowance[msg.sender][_spender] = _value;
38 | emit Approval(msg.sender, _spender, _value);
39 | return true;
40 | }
41 |
42 | function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
43 | require(_value <= balanceOf[_from]);
44 | require(_value <= allowance[_from][msg.sender]);
45 | balanceOf[_from] -= _value;
46 | balanceOf[_to] += _value;
47 | allowance[_from][msg.sender] -= _value;
48 | emit Transfer(_from, _to, _value);
49 | return true;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/contracts/DappToken.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.0;
2 |
3 | contract DappToken {
4 | string public name = "DApp Token";
5 | string public symbol = "DAPP";
6 | uint256 public totalSupply = 1000000000000000000000000; // 1 million tokens
7 | uint8 public decimals = 18;
8 |
9 | event Transfer(
10 | address indexed _from,
11 | address indexed _to,
12 | uint256 _value
13 | );
14 |
15 | event Approval(
16 | address indexed _owner,
17 | address indexed _spender,
18 | uint256 _value
19 | );
20 |
21 | mapping(address => uint256) public balanceOf;
22 | mapping(address => mapping(address => uint256)) public allowance;
23 |
24 | constructor() public {
25 | balanceOf[msg.sender] = totalSupply;
26 | }
27 |
28 | function transfer(address _to, uint256 _value) public returns (bool success) {
29 | require(balanceOf[msg.sender] >= _value);
30 | balanceOf[msg.sender] -= _value;
31 | balanceOf[_to] += _value;
32 | emit Transfer(msg.sender, _to, _value);
33 | return true;
34 | }
35 |
36 | function approve(address _spender, uint256 _value) public returns (bool success) {
37 | allowance[msg.sender][_spender] = _value;
38 | emit Approval(msg.sender, _spender, _value);
39 | return true;
40 | }
41 |
42 | function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
43 | require(_value <= balanceOf[_from]);
44 | require(_value <= allowance[_from][msg.sender]);
45 | balanceOf[_from] -= _value;
46 | balanceOf[_to] += _value;
47 | allowance[_from][msg.sender] -= _value;
48 | emit Transfer(_from, _to, _value);
49 | return true;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/contracts/Migrations.sol:
--------------------------------------------------------------------------------
1 | pragma solidity >=0.4.21 <0.6.0;
2 |
3 | contract Migrations {
4 | address public owner;
5 | uint public last_completed_migration;
6 |
7 | constructor() public {
8 | owner = msg.sender;
9 | }
10 |
11 | modifier restricted() {
12 | if (msg.sender == owner) _;
13 | }
14 |
15 | function setCompleted(uint completed) public restricted {
16 | last_completed_migration = completed;
17 | }
18 |
19 | function upgrade(address new_address) public restricted {
20 | Migrations upgraded = Migrations(new_address);
21 | upgraded.setCompleted(last_completed_migration);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/contracts/TokenFarm.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.0;
2 |
3 | import "./DappToken.sol";
4 | import "./DaiToken.sol";
5 |
6 | contract TokenFarm {
7 | string public name = "Dapp Token Farm";
8 | address public owner;
9 | DappToken public dappToken;
10 | DaiToken public daiToken;
11 |
12 | address[] public stakers;
13 | mapping(address => uint) public stakingBalance;
14 | mapping(address => bool) public hasStaked;
15 | mapping(address => bool) public isStaking;
16 |
17 | constructor(DappToken _dappToken, DaiToken _daiToken) public {
18 | dappToken = _dappToken;
19 | daiToken = _daiToken;
20 | owner = msg.sender;
21 | }
22 |
23 | function stakeTokens(uint _amount) public {
24 | // Require amount greater than 0
25 | require(_amount > 0, "amount cannot be 0");
26 |
27 | // Trasnfer Mock Dai tokens to this contract for staking
28 | daiToken.transferFrom(msg.sender, address(this), _amount);
29 |
30 | // Update staking balance
31 | stakingBalance[msg.sender] = stakingBalance[msg.sender] + _amount;
32 |
33 | // Add user to stakers array *only* if they haven't staked already
34 | if(!hasStaked[msg.sender]) {
35 | stakers.push(msg.sender);
36 | }
37 |
38 | // Update staking status
39 | isStaking[msg.sender] = true;
40 | hasStaked[msg.sender] = true;
41 | }
42 |
43 | // Unstaking Tokens (Withdraw)
44 | function unstakeTokens() public {
45 | // Fetch staking balance
46 | uint balance = stakingBalance[msg.sender];
47 |
48 | // Require amount greater than 0
49 | require(balance > 0, "staking balance cannot be 0");
50 |
51 | // Transfer Mock Dai tokens to this contract for staking
52 | daiToken.transfer(msg.sender, balance);
53 |
54 | // Reset staking balance
55 | stakingBalance[msg.sender] = 0;
56 |
57 | // Update staking status
58 | isStaking[msg.sender] = false;
59 | }
60 |
61 | // Issuing Tokens
62 | function issueTokens() public {
63 | // Only owner can call this function
64 | require(msg.sender == owner, "caller must be the owner");
65 |
66 | // Issue tokens to all stakers
67 | for (uint i=0; i 0) {
71 | dappToken.transfer(recipient, balance);
72 | }
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/dai.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dappuniversity/defi_tutorial/7d86e7f1c4f737ad39dd97b4c01915f8603b5588/src/dai.png
--------------------------------------------------------------------------------
/src/eth-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dappuniversity/defi_tutorial/7d86e7f1c4f737ad39dd97b4c01915f8603b5588/src/eth-logo.png
--------------------------------------------------------------------------------
/src/farmer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dappuniversity/defi_tutorial/7d86e7f1c4f737ad39dd97b4c01915f8603b5588/src/farmer.png
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import 'bootstrap/dist/css/bootstrap.css'
4 | import App from './components/App';
5 | import * as serviceWorker from './serviceWorker';
6 |
7 | ReactDOM.render(, document.getElementById('root'));
8 |
9 | // If you want your app to work offline and load faster, you can change
10 | // unregister() to register() below. Note this comes with some pitfalls.
11 | // Learn more about service workers: https://bit.ly/CRA-PWA
12 | serviceWorker.unregister();
13 |
--------------------------------------------------------------------------------
/src/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dappuniversity/defi_tutorial/7d86e7f1c4f737ad39dd97b4c01915f8603b5588/src/logo.png
--------------------------------------------------------------------------------
/src/serviceWorker.js:
--------------------------------------------------------------------------------
1 | // This optional code is used to register a service worker.
2 | // register() is not called by default.
3 |
4 | // This lets the app load faster on subsequent visits in production, and gives
5 | // it offline capabilities. However, it also means that developers (and users)
6 | // will only see deployed updates on subsequent visits to a page, after all the
7 | // existing tabs open on the page have been closed, since previously cached
8 | // resources are updated in the background.
9 |
10 | // To learn more about the benefits of this model and instructions on how to
11 | // opt-in, read https://bit.ly/CRA-PWA
12 |
13 | const isLocalhost = Boolean(
14 | window.location.hostname === 'localhost' ||
15 | // [::1] is the IPv6 localhost address.
16 | window.location.hostname === '[::1]' ||
17 | // 127.0.0.1/8 is considered localhost for IPv4.
18 | window.location.hostname.match(
19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
20 | )
21 | );
22 |
23 | export function register(config) {
24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
25 | // The URL constructor is available in all browsers that support SW.
26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
27 | if (publicUrl.origin !== window.location.origin) {
28 | // Our service worker won't work if PUBLIC_URL is on a different origin
29 | // from what our page is served on. This might happen if a CDN is used to
30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374
31 | return;
32 | }
33 |
34 | window.addEventListener('load', () => {
35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
36 |
37 | if (isLocalhost) {
38 | // This is running on localhost. Let's check if a service worker still exists or not.
39 | checkValidServiceWorker(swUrl, config);
40 |
41 | // Add some additional logging to localhost, pointing developers to the
42 | // service worker/PWA documentation.
43 | navigator.serviceWorker.ready.then(() => {
44 | console.log(
45 | 'This web app is being served cache-first by a service ' +
46 | 'worker. To learn more, visit https://bit.ly/CRA-PWA'
47 | );
48 | });
49 | } else {
50 | // Is not localhost. Just register service worker
51 | registerValidSW(swUrl, config);
52 | }
53 | });
54 | }
55 | }
56 |
57 | function registerValidSW(swUrl, config) {
58 | navigator.serviceWorker
59 | .register(swUrl)
60 | .then(registration => {
61 | registration.onupdatefound = () => {
62 | const installingWorker = registration.installing;
63 | if (installingWorker == null) {
64 | return;
65 | }
66 | installingWorker.onstatechange = () => {
67 | if (installingWorker.state === 'installed') {
68 | if (navigator.serviceWorker.controller) {
69 | // At this point, the updated precached content has been fetched,
70 | // but the previous service worker will still serve the older
71 | // content until all client tabs are closed.
72 | console.log(
73 | 'New content is available and will be used when all ' +
74 | 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
75 | );
76 |
77 | // Execute callback
78 | if (config && config.onUpdate) {
79 | config.onUpdate(registration);
80 | }
81 | } else {
82 | // At this point, everything has been precached.
83 | // It's the perfect time to display a
84 | // "Content is cached for offline use." message.
85 | console.log('Content is cached for offline use.');
86 |
87 | // Execute callback
88 | if (config && config.onSuccess) {
89 | config.onSuccess(registration);
90 | }
91 | }
92 | }
93 | };
94 | };
95 | })
96 | .catch(error => {
97 | console.error('Error during service worker registration:', error);
98 | });
99 | }
100 |
101 | function checkValidServiceWorker(swUrl, config) {
102 | // Check if the service worker can be found. If it can't reload the page.
103 | fetch(swUrl)
104 | .then(response => {
105 | // Ensure service worker exists, and that we really are getting a JS file.
106 | const contentType = response.headers.get('content-type');
107 | if (
108 | response.status === 404 ||
109 | (contentType != null && contentType.indexOf('javascript') === -1)
110 | ) {
111 | // No service worker found. Probably a different app. Reload the page.
112 | navigator.serviceWorker.ready.then(registration => {
113 | registration.unregister().then(() => {
114 | window.location.reload();
115 | });
116 | });
117 | } else {
118 | // Service worker found. Proceed as normal.
119 | registerValidSW(swUrl, config);
120 | }
121 | })
122 | .catch(() => {
123 | console.log(
124 | 'No internet connection found. App is running in offline mode.'
125 | );
126 | });
127 | }
128 |
129 | export function unregister() {
130 | if ('serviceWorker' in navigator) {
131 | navigator.serviceWorker.ready.then(registration => {
132 | registration.unregister();
133 | });
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/src/token-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dappuniversity/defi_tutorial/7d86e7f1c4f737ad39dd97b4c01915f8603b5588/src/token-logo.png
--------------------------------------------------------------------------------
/test/TokenFarm.test.js:
--------------------------------------------------------------------------------
1 | const DaiToken = artifacts.require('DaiToken')
2 | const DappToken = artifacts.require('DappToken')
3 | const TokenFarm = artifacts.require('TokenFarm')
4 |
5 | require('chai')
6 | .use(require('chai-as-promised'))
7 | .should()
8 |
9 | function tokens(n) {
10 | return web3.utils.toWei(n, 'ether');
11 | }
12 |
13 | contract('TokenFarm', ([owner, investor]) => {
14 | let daiToken, dappToken, tokenFarm
15 |
16 | before(async () => {
17 | // Load Contracts
18 | daiToken = await DaiToken.new()
19 | dappToken = await DappToken.new()
20 | tokenFarm = await TokenFarm.new(dappToken.address, daiToken.address)
21 |
22 | // Transfer all Dapp tokens to farm (1 million)
23 | await dappToken.transfer(tokenFarm.address, tokens('1000000'))
24 |
25 | // Send tokens to investor
26 | await daiToken.transfer(investor, tokens('100'), { from: owner })
27 | })
28 |
29 | describe('Mock DAI deployment', async () => {
30 | it('has a name', async () => {
31 | const name = await daiToken.name()
32 | assert.equal(name, 'Mock DAI Token')
33 | })
34 | })
35 |
36 | describe('Dapp Token deployment', async () => {
37 | it('has a name', async () => {
38 | const name = await dappToken.name()
39 | assert.equal(name, 'DApp Token')
40 | })
41 | })
42 |
43 | describe('Token Farm deployment', async () => {
44 | it('has a name', async () => {
45 | const name = await tokenFarm.name()
46 | assert.equal(name, 'Dapp Token Farm')
47 | })
48 |
49 | it('contract has tokens', async () => {
50 | let balance = await dappToken.balanceOf(tokenFarm.address)
51 | assert.equal(balance.toString(), tokens('1000000'))
52 | })
53 | })
54 |
55 | describe('Farming tokens', async () => {
56 |
57 | it('rewards investors for staking mDai tokens', async () => {
58 | let result
59 |
60 | // Check investor balance before staking
61 | result = await daiToken.balanceOf(investor)
62 | assert.equal(result.toString(), tokens('100'), 'investor Mock DAI wallet balance correct before staking')
63 |
64 | // Stake Mock DAI Tokens
65 | await daiToken.approve(tokenFarm.address, tokens('100'), { from: investor })
66 | await tokenFarm.stakeTokens(tokens('100'), { from: investor })
67 |
68 | // Check staking result
69 | result = await daiToken.balanceOf(investor)
70 | assert.equal(result.toString(), tokens('0'), 'investor Mock DAI wallet balance correct after staking')
71 |
72 | result = await daiToken.balanceOf(tokenFarm.address)
73 | assert.equal(result.toString(), tokens('100'), 'Token Farm Mock DAI balance correct after staking')
74 |
75 | result = await tokenFarm.stakingBalance(investor)
76 | assert.equal(result.toString(), tokens('100'), 'investor staking balance correct after staking')
77 |
78 | result = await tokenFarm.isStaking(investor)
79 | assert.equal(result.toString(), 'true', 'investor staking status correct after staking')
80 |
81 | // Issue Tokens
82 | await tokenFarm.issueTokens({ from: owner })
83 |
84 | // Check balances after issuance
85 | result = await dappToken.balanceOf(investor)
86 | assert.equal(result.toString(), tokens('100'), 'investor DApp Token wallet balance correct affter issuance')
87 |
88 | // Ensure that only onwer can issue tokens
89 | await tokenFarm.issueTokens({ from: investor }).should.be.rejected;
90 |
91 | // Unstake tokens
92 | await tokenFarm.unstakeTokens({ from: investor })
93 |
94 | // Check results after unstaking
95 | result = await daiToken.balanceOf(investor)
96 | assert.equal(result.toString(), tokens('100'), 'investor Mock DAI wallet balance correct after staking')
97 |
98 | result = await daiToken.balanceOf(tokenFarm.address)
99 | assert.equal(result.toString(), tokens('0'), 'Token Farm Mock DAI balance correct after staking')
100 |
101 | result = await tokenFarm.stakingBalance(investor)
102 | assert.equal(result.toString(), tokens('0'), 'investor staking balance correct after staking')
103 |
104 | result = await tokenFarm.isStaking(investor)
105 | assert.equal(result.toString(), 'false', 'investor staking status correct after staking')
106 | })
107 | })
108 |
109 | })
110 |
--------------------------------------------------------------------------------
/truffle-config.js:
--------------------------------------------------------------------------------
1 | require('babel-register');
2 | require('babel-polyfill');
3 |
4 | module.exports = {
5 | networks: {
6 | development: {
7 | host: "127.0.0.1",
8 | port: 7545,
9 | network_id: "*" // Match any network id
10 | },
11 | },
12 | contracts_directory: './src/contracts/',
13 | contracts_build_directory: './src/abis/',
14 | compilers: {
15 | solc: {
16 | optimizer: {
17 | enabled: true,
18 | runs: 200
19 | },
20 | evmVersion: "petersburg"
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------