diff --git a/.sample.local.env b/.sample.local.env deleted file mode 100644 index a1249b5..0000000 --- a/.sample.local.env +++ /dev/null @@ -1,8 +0,0 @@ -SUBGRAPH_ENDPOINT = https://api.thegraph.com/subgraphs/name/rrridges-crypto/yearn-vault-roi-dev -WEB3_ENDPOINT = https://mainnet.infura.io/v3/4f8bf400ab354820998e6dfdea0a1b78 -ARCHIVENODE_ENDPOINT = https://api.archivenode.io/93mwpmy684fb0dc3c0q93mwpmwlssf6a -ETHERSCAN_API_KEY = GEQXZDY67RZ4QHNU1A57QVPNDV3RP1RYH4 - -AWS_ACCESS_KEY_ID = dummy -AWS_SECRET_ACCESS_KEY = dummy -SERVERLESS_STAGE = local \ No newline at end of file diff --git a/abi/strategyMinABI.json b/abi/strategyMinABI.json index b1fe9dd..f5fe779 100644 --- a/abi/strategyMinABI.json +++ b/abi/strategyMinABI.json @@ -16,5 +16,23 @@ "payable": false, "stateMutability": "view", "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "balanceOf", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getName", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "payable": false, + "stateMutability": "pure", + "type": "function" } ] diff --git a/docker-compose.yml b/docker-compose.yml index 0620b0d..66d077c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -15,6 +15,7 @@ services: ports: - "3000:3000" volumes: - - "./config:/opt/app/config:ro" - - "./services:/opt/app/services:ro" - - "./utils:/opt/app/utils:ro" + - "./config:/opt/app/config:rw" + - "./services:/opt/app/services:rw" + - "./utils:/opt/app/utils:rw" + - "./abi:/opt/app/abi:rw" diff --git a/package-lock.json b/package-lock.json index 143a9c7..80239a6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -747,6 +747,11 @@ "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==" }, + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==" + }, "ansi-regex": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", @@ -893,6 +898,14 @@ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.1.tgz", "integrity": "sha512-zg7Hz2k5lI8kb7U32998pRRFin7zJlkfezGJjUc2heaD4Pw2wObakCDVzkKztTm/Ln7eiVvYsjqak0Ed4LkMDA==" }, + "axios": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.0.tgz", + "integrity": "sha512-fmkJBknJKoZwem3/IKSSLpkdNXZeBu5Q7GA/aRsr2btgrptmSCxi2oFjZHqGdK9DoTil9PIHlPIZw2EcRJXRvw==", + "requires": { + "follow-redirects": "^1.10.0" + } + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -1191,6 +1204,11 @@ "supports-color": "^7.1.0" } }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" + }, "check-error": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", @@ -1324,6 +1342,79 @@ "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", "dev": true }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "requires": { + "restore-cursor": "^2.0.0" + } + }, + "cli-spinners": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.5.0.tgz", + "integrity": "sha512-PC+AmIuK04E6aeSs/pUccSujsTzBhu4HzC2dL+CfJB/Jcc2qTRbEwZQDfIUpt2Xl8BodYBEq8w4fc0kU2I9DjQ==" + }, + "cli-table": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.4.tgz", + "integrity": "sha512-1vinpnX/ZERcmE443i3SZTmU5DF0rPO9DrL4I2iVAllhxzCM9SzPlHnz19fsZB78htkKZvYBvj6SZ6vXnaxmTA==", + "requires": { + "chalk": "^2.4.1", + "string-width": "^4.2.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "cli-width": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", + "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==" + }, "cliui": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", @@ -1346,6 +1437,11 @@ } } }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=" + }, "clone-response": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", @@ -1377,6 +1473,11 @@ "delayed-stream": "~1.0.0" } }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -1602,6 +1703,14 @@ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, + "defaults": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "requires": { + "clone": "^1.0.2" + } + }, "defer-to-connect": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", @@ -2377,6 +2486,24 @@ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", @@ -2398,6 +2525,14 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, "file-entry-cache": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", @@ -2465,6 +2600,11 @@ "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", "dev": true }, + "follow-redirects": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz", + "integrity": "sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==" + }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -2490,6 +2630,11 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" }, + "fs-exists-sync": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz", + "integrity": "sha1-mC1ok6+RjnLQjeyehnP/K1qNat0=" + }, "fs-extra": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", @@ -2883,6 +3028,96 @@ "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "dev": true }, + "inquirer": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", + "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", + "requires": { + "ansi-escapes": "^3.2.0", + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^2.0.0", + "lodash": "^4.17.12", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rxjs": "^6.4.0", + "string-width": "^2.1.0", + "strip-ansi": "^5.1.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, "ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -2927,6 +3162,11 @@ "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==" }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" + }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -3327,6 +3567,77 @@ "immediate": "~3.0.5" } }, + "lint": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/lint/-/lint-0.7.0.tgz", + "integrity": "sha512-bmsncKKwZEQxCoL35eer2Aw7E24iGl8M9cY50gK1ptoQYlPhuSPH8KgQKM8d41wYwUUnHyE8wHIxJjlAexhssA==", + "requires": { + "chalk": "^2.4.1", + "cli-table": "^0.3.1", + "commander": "^2.17.1", + "inquirer": "^6.1.0", + "js-yaml": ">=3.13.1", + "loadash": "^1.0.0", + "moment": "^2.22.2", + "ora": "^3.0.0", + "prettier": "^1.15.3", + "replace-in-file": "^3.4.2", + "request": "^2.87.0", + "simple-git": "^1.96.0", + "write-yaml": "^1.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "prettier": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", + "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, "load-json-file": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", @@ -3339,6 +3650,11 @@ "strip-bom": "^3.0.0" } }, + "loadash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/loadash/-/loadash-1.0.0.tgz", + "integrity": "sha512-xlX5HBsXB3KG0FJbJJG/3kYWCfsCyCSus3T+uHVu6QL6YxAdggmm3QeyLgn54N2yi5/UE6xxL5ZWJAAiHzHYEg==" + }, "locate-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", @@ -3801,6 +4117,11 @@ } } }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=" + }, "nano-json-stream-parser": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz", @@ -4058,6 +4379,70 @@ "word-wrap": "^1.2.3" } }, + "ora": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-3.4.0.tgz", + "integrity": "sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg==", + "requires": { + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-spinners": "^2.0.0", + "log-symbols": "^2.2.0", + "strip-ansi": "^5.2.0", + "wcwidth": "^1.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + }, "p-cancelable": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", @@ -4635,6 +5020,62 @@ "rc": "^1.2.8" } }, + "replace-in-file": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/replace-in-file/-/replace-in-file-3.4.4.tgz", + "integrity": "sha512-ehq0dFsxSpfPiPLBU5kli38Ud8bZL0CQKG8WQVbvhmyilXaMJ8y4LtDZs/K3MD8C0+rHbsfW8c9r2bUEy0B/6Q==", + "requires": { + "chalk": "^2.4.2", + "glob": "^7.1.3", + "yargs": "^13.2.2" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, "request": { "version": "2.88.2", "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", @@ -4703,6 +5144,30 @@ "lowercase-keys": "^1.0.0" } }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + }, + "dependencies": { + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==" + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "requires": { + "mimic-fn": "^1.0.0" + } + } + } + }, "retry": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", @@ -4734,6 +5199,19 @@ "bn.js": "^4.11.1" } }, + "run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==" + }, + "rxjs": { + "version": "6.6.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz", + "integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==", + "requires": { + "tslib": "^1.9.0" + } + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -5107,8 +5585,7 @@ "signal-exit": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", - "dev": true + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" }, "simple-concat": { "version": "1.0.1", @@ -5125,6 +5602,29 @@ "simple-concat": "^1.0.0" } }, + "simple-git": { + "version": "1.132.0", + "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-1.132.0.tgz", + "integrity": "sha512-xauHm1YqCTom1sC9eOjfq3/9RKiUA9iPnxBbrY2DdL8l4ADMu0jjM5l5lphQP5YWNqAL2aXC/OeuQ76vHtW5fg==", + "requires": { + "debug": "^4.0.1" + }, + "dependencies": { + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, "slice-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", @@ -5264,7 +5764,6 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", - "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -5274,26 +5773,22 @@ "ansi-regex": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" }, "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" }, "strip-ansi": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, "requires": { "ansi-regex": "^5.0.0" } @@ -5500,11 +5995,24 @@ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, "timed-out": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=" }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "requires": { + "os-tmpdir": "~1.0.2" + } + }, "to-readable-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", @@ -5536,6 +6044,11 @@ "strip-bom": "^3.0.0" } }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -5753,6 +6266,14 @@ "extsprintf": "^1.2.0" } }, + "wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "requires": { + "defaults": "^1.0.3" + } + }, "web3": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/web3/-/web3-1.3.0.tgz", @@ -6196,6 +6717,35 @@ "typedarray-to-buffer": "^3.1.5" } }, + "write-yaml": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/write-yaml/-/write-yaml-1.0.0.tgz", + "integrity": "sha1-MUWWEZ0NuRJHy8g1vOADO24LoJ4=", + "requires": { + "extend-shallow": "^2.0.1", + "js-yaml": "^3.8.3", + "write": "^0.3.3" + }, + "dependencies": { + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "requires": { + "minimist": "^1.2.5" + } + }, + "write": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/write/-/write-0.3.3.tgz", + "integrity": "sha1-Cc3FohVWB+4nn0XjjZGuKftqUXg=", + "requires": { + "fs-exists-sync": "^0.1.0", + "mkdirp": "^0.5.1" + } + } + } + }, "ws": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", diff --git a/package.json b/package.json index 1d8d10d..5eea9bd 100644 --- a/package.json +++ b/package.json @@ -28,10 +28,12 @@ }, "dependencies": { "aws-sdk": "^2.790.0", + "axios": "^0.21.0", "bignumber": "^1.1.0", "bignumber.js": "^9.0.1", "delay": "^4.4.0", "dotenv": "^8.2.0", + "lint": "^0.7.0", "lodash": "^4.17.20", "moment": "^2.28.0", "node-fetch": "^2.6.1", diff --git a/serverless.yml b/serverless.yml index c7b3de9..79d766e 100644 --- a/serverless.yml +++ b/serverless.yml @@ -143,7 +143,30 @@ functions: path: /vaults/apy/save method: get - # /user + vaults-holdings: + handler: services/vaults/holdings/handler.handler + role: arn:aws:iam::698083237070:role/service-role/fetchTokenIds-role-o9i24lq2 + timeout: 30 + events: + - http: + path: /vaults/holdings + method: get + cors: true + documentation: + summary: Gets holdings for all V1 Vaults, Earn products, YFI staked in governance and veCRV. + tags: + - Vaults + description: > + Vault holdings is calculated based on strategy + vault holdings per vault. + + vaults-holdings-save: + handler: services/vaults/holdings/save/handler.handler + role: arn:aws:iam::698083237070:role/service-role/fetchTokenIds-role-o9i24lq2 + events: + - http: + path: /vaults/holdings/save + method: get + # /user user-vaults: handler: services/user/vaults/handler.handler role: arn:aws:iam::698083237070:role/service-role/fetchTokenIds-role-o9i24lq2 diff --git a/services/vaults/apy/save/handler.js b/services/vaults/apy/save/handler.js index 6fe3ea6..5929928 100644 --- a/services/vaults/apy/save/handler.js +++ b/services/vaults/apy/save/handler.js @@ -276,7 +276,7 @@ const readVault = async (vault) => { return data; }; -module.exports.handler = async () => { +const handler = async () => { console.log('Fetching historical blocks'); currentBlockNbr = await infuraWeb3.eth.getBlockNumber(); await delay(delayTime); @@ -305,3 +305,5 @@ module.exports.handler = async () => { }; return response; }; + +module.exports = {getVirtualPrice, handler}; \ No newline at end of file diff --git a/services/vaults/holdings/handler.js b/services/vaults/holdings/handler.js new file mode 100644 index 0000000..43d6f0f --- /dev/null +++ b/services/vaults/holdings/handler.js @@ -0,0 +1,36 @@ +'use strict'; + +const dynamodb = require('../../../utils/dynamoDb'); +// const _ = require('lodash'); + +const db = dynamodb.doc; + +const getVaultsHoldings = async () => { + const params = { + TableName: 'holdings', + }; + const entries = await db.scan(params).promise(); + const holdings = entries.Items; + +/* const injectVaultAddress = (vault) => { + vault.vaultAddress = vault.address; + return vault; + }; + const vaultAddress = _.map(apy, injectVaultAddress); */ + return holdings; +}; + +exports.getVaultsHoldings = getVaultsHoldings; + +exports.handler = async () => { + const holdings = await this.getVaultsHoldings(); + const response = { + statusCode: 200, + headers: { + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Credentials': true, + }, + body: JSON.stringify(holdings), + }; + return response; +}; diff --git a/services/vaults/holdings/save/config.js b/services/vaults/holdings/save/config.js new file mode 100644 index 0000000..26e5035 --- /dev/null +++ b/services/vaults/holdings/save/config.js @@ -0,0 +1,16 @@ +'use strict'; + +const vaultContractABI = require('../../../../abi/vaultV1'); +const vaultContractV2ABI = require('../../../../abi/vaultV2'); +const vaultContractV3ABI = require('../../../../abi/vaultV3'); +const vaultContractV4ABI = require('../../../../abi/vaultV4'); +const vaultContractV5ABI = require('../../../../abi/vaultV5'); + +module.exports = { + delayTime: 1000, + vaultContractABI, + vaultContractV2ABI, + vaultContractV3ABI, + vaultContractV4ABI, + vaultContractV5ABI, +}; diff --git a/services/vaults/holdings/save/getHoldings.js b/services/vaults/holdings/save/getHoldings.js new file mode 100644 index 0000000..e9bd33d --- /dev/null +++ b/services/vaults/holdings/save/getHoldings.js @@ -0,0 +1,128 @@ +'use strict'; + +const Web3 = require('web3'); + +const web3 = new Web3(process.env.WEB3_ENDPOINT); +const yRegistryAddress = '0x3ee41c098f9666ed2ea246f4d2558010e59d63a0'; +const yRegistryAbi = require('../../../../abi/yRegistry.json'); +const strategyMinABI = require('../../../../abi/strategyMinABI.json'); +const _ = require('lodash'); +const getVirtualPrice = require('../../apy/save/handler'); + +const infuraUrl = process.env.WEB3_ENDPOINT; +const infuraWeb3 = new Web3(infuraUrl); +const delay = require('delay'); +const { delayTime } = require('./config'); + +const pools = [ + { + symbol: 'yCRV', + address: '0x45F783CCE6B7FF23B2ab2D70e416cdb7D6055f51', + }, + { + symbol: 'crvBUSD', + address: '0x79a8C46DeA5aDa233ABaFFD40F3A0A2B1e5A4F27', + }, + { + symbol: 'crvBTC', + address: '0x7fC77b5c7614E1533320Ea6DDc2Eb61fa00A9714', + }, +]; + +const poolMinABI = [ + { + name: 'totalSupply', + outputs: [ + { + type: 'uint256', + name: 'out', + }, + ], + inputs: [], + constant: true, + payable: false, + type: 'function', + gas: 1181, + }, +]; + +const vaultStrategyMap = {}; + +const getVaultsStrategy = async vault => { + // Populate vault->strategy mapping if first time here to reuse of future calls. + if (_.isEmpty(vaultStrategyMap)) { + const registryContract = new web3.eth.Contract( + yRegistryAbi, + yRegistryAddress, + ); + + const vaultAddresses = await registryContract.methods.getVaults().call(); + const vaultsInfo = await registryContract.methods.getVaultsInfo().call(); + + vaultAddresses.forEach((address, index) => { + vaultStrategyMap[address] = vaultsInfo.strategyArray[index]; + }); + } + + return vaultStrategyMap[vault.vaultContractAddress]; +}; + +const getPoolTotalSupply = async poolAddress => { + const poolContract = new web3.eth.Contract(poolMinABI, poolAddress); + const _totalSupply = (await poolContract.methods.totalSupply().call()) / 1e18; + return _totalSupply; +}; + +const getHoldings = async vault => { + let poolBalance; let holdings; + const { symbol, erc20address } = vault; + const strategyAddress = await getVaultsStrategy(vault); + const strategyContract = new web3.eth.Contract( + strategyMinABI, + strategyAddress, + ); + const vaultContract = new web3.eth.Contract( + vault.vaultContractABI, + vault.vaultContractAddress, + ); + const vaultHoldings = + (await vaultContract.methods.balance().call()) / + Math.pow(10, vault.decimals); + const strategyHoldings = + (await strategyContract.methods.balanceOf().call()) / + Math.pow( + 10, + vault.strategyDecimals ? vault.strategyDecimals : vault.decimals, + ); + const pool = _.find(pools, { symbol }); + + if (pool) { + const currentBlockNbr = await infuraWeb3.eth.getBlockNumber(); + await delay(delayTime); + const poolAddress = pool.address; + const virtualPriceCurrent = + (await getVirtualPrice.getVirtualPrice(poolAddress, currentBlockNbr)) / + 1e18; + const poolTotalSupply = await getPoolTotalSupply(erc20address); + + poolBalance = poolTotalSupply * virtualPriceCurrent; + holdings = { + strategyAddress, + vaultHoldings, + strategyHoldings, + tokenSymbol: symbol, + tokenAddress: erc20address, + poolBalanceUSD: poolBalance, + }; + } else { + holdings = { + strategyAddress, + vaultHoldings, + strategyHoldings, + }; + } + + return holdings; +}; + +module.exports = { getHoldings, getPoolTotalSupply }; diff --git a/services/vaults/holdings/save/handler.js b/services/vaults/holdings/save/handler.js new file mode 100644 index 0000000..866ebe5 --- /dev/null +++ b/services/vaults/holdings/save/handler.js @@ -0,0 +1,161 @@ +/* + +Holdings calculated here are for Vaults, Strategies and the Earn yTokens +This is part of the TVL calculation defined here: https://hackmd.io/@dudesahn/BkxKfTzqw + + */ + +'use strict'; + +require('dotenv').config(); +const dynamodb = require('../../../../utils/dynamoDb'); +const delay = require('delay'); +const vaults = require('./vaults'); +const { delayTime } = require('./config'); +const axios = require('axios'); +const { getHoldings, getPoolTotalSupply } = require('./getHoldings'); + +const db = dynamodb.doc; +const Web3 = require('web3'); + +const web3 = new Web3(process.env.WEB3_ENDPOINT); + +const saveVault = async data => { + const params = { + TableName: 'holdings', + Item: data, + }; + await db + .put(params) + .promise() + .catch(err => console.log('err', err)); + console.log(`Saved ${data.name}`); +}; + +const readVault = async vault => { + const { + name, + symbol, + vaultContractABI: abi, + vaultContractAddress: address, + // eslint-disable-next-line camelcase + price_id, + } = vault; + console.log(`Reading vault ${vault.name}`); + if (!abi || !address) { + console.log(`Vault ABI not found: ${name}`); + return null; + } + try { + const holdings = await getHoldings(vault); + const priceFeed = await axios.get( + `https://api.coingecko.com/api/v3/coins/${ vault.price_id}`, + ); + console.log('Vault: ', name); + const data = { + address, + name, + symbol, + price_id, + price_usd: priceFeed.data.market_data.current_price.usd, + timestamp: Date.now(), + holdings, + }; + await saveVault(data); + + return data; + } catch (e) { + console.log('error', e); + return e; + } +}; + +// getting the veCRV locked in yearn used to vote on Curve +const readveCRV = async () => { + const veCRVMinABI = [ + { + name: 'balanceOf', + outputs: [ + { + type: 'uint256', + name: '', + }, + ], + inputs: [ + { + type: 'address', + name: 'addr', + }, + ], + stateMutability: 'view', + type: 'function', + }, + ]; + const poolContract = new web3.eth.Contract( + veCRVMinABI, + '0x5f3b5dfeb7b28cdbd7faba78963ee202a494e2a2', + ); + const voterAddress = '0xF147b8125d2ef93FB6965Db97D6746952a133934'; + const veCRVLocked = + (await poolContract.methods.balanceOf(voterAddress).call()) / 1e18; + const priceFeed = await axios.get( + 'https://api.coingecko.com/api/v3/coins/curve-dao-token', + ); + const veCRVContract = { + address: '0x5f3b5dfeb7b28cdbd7faba78963ee202a494e2a2', + name: 'veCRV', + symbol: 'veCRV', + price_id: 'curve-dao-token', + price_usd: priceFeed.data.market_data.current_price.usd, + timestamp: Date.now(), + veCRVLocked, + }; + await saveVault(veCRVContract); + return veCRVContract; +}; + +// getting YFI staked in GOV for the holdings endpoint +const readStaking = async () => { + const staked = await getPoolTotalSupply( + '0xBa37B002AbaFDd8E89a1995dA52740bbC013D992', + ); + const priceFeed = await axios.get( + 'https://api.coingecko.com/api/v3/coins/yearn-finance', + ); + const stakingContract = { + address: '0xBa37B002AbaFDd8E89a1995dA52740bbC013D992', + name: 'staked YFI', + symbol: 'YFI', + price_id: 'yearn-finance', + price_usd: priceFeed.data.market_data.current_price.usd, + timestamp: Date.now(), + stakedYFI: staked, + }; + await saveVault(stakingContract); + return stakingContract; +}; + +module.exports.handler = async () => { + const vaultsWithHoldings = []; + for (const vault of vaults) { + const vaultWithHoldings = await readVault(vault); + if (vaultWithHoldings !== null) { + vaultsWithHoldings.push(vaultWithHoldings); + } + await delay(delayTime); + } + + const staked = await readStaking(); + const veCRVLocked = await readveCRV(); + vaultsWithHoldings.push(staked); + vaultsWithHoldings.push(veCRVLocked); + const response = { + statusCode: 200, + headers: { + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Credentials': true, + }, + body: JSON.stringify(vaultsWithHoldings), + }; + return response; +}; diff --git a/services/vaults/holdings/save/vaults.js b/services/vaults/holdings/save/vaults.js new file mode 100644 index 0000000..dfdd06b --- /dev/null +++ b/services/vaults/holdings/save/vaults.js @@ -0,0 +1,315 @@ +'use strict'; + +const config = require('./config.js'); + + +module.exports = [ + { + id: 'CRV', + name: 'curve.fi/y LP', + symbol: 'yCRV', + description: 'yDAI/yUSDC/yUSDT/yTUSD', + vaultSymbol: 'yUSD', + erc20address: '0xdf5e0e81dff6faf3a7e52ba697820c5e32d806a8', + vaultContractAddress: '0x5dbcF33D8c2E976c6b560249878e6F1491Bca25c', + vaultContractABI: config.vaultContractABI, + balance: 0, + vaultBalance: 0, + decimals: 18, + deposit: true, + depositAll: false, + withdraw: true, + withdrawAll: false, + lastMeasurement: 10559448, + measurement: 1e18, + price_id: 'curve-fi-ydai-yusdc-yusdt-ytusd', + }, + { + id: 'vcDAI+cUSDC', + name: 'yearn Curve.fi cDAI/cUSDC', + symbol: 'yvcDAI+cUSDC', + description: 'vcDAI+cUSDC Vault', + vaultSymbol: 'vcDAI+cUSDC', + erc20address: '0x845838DF265Dcd2c412A1Dc9e959c7d08537f8a2', + vaultContractAddress: '0x629c759D1E83eFbF63d84eb3868B564d9521C129', + vaultContractABI: config.vaultContractABI, + balance: 0, + vaultBalance: 0, + decimals: 18, + deposit: true, + depositAll: false, + withdraw: true, + withdrawAll: false, + lastMeasurement: 10559448, + measurement: 1e18, + price_id: 'lp-ccurve', + }, + { + id: 'crvBUSD', + name: 'curve.fi/busd LP', + symbol: 'crvBUSD', + description: 'yDAI/yUSDC/yUSDT/yBUSD', + vaultSymbol: 'ycrvBUSD', + erc20address: '0x3B3Ac5386837Dc563660FB6a0937DFAa5924333B', + vaultContractAddress: '0x2994529C0652D127b7842094103715ec5299bBed', + vaultContractABI: config.vaultContractV3ABI, + balance: 0, + vaultBalance: 0, + decimals: 18, + deposit: true, + depositAll: true, + withdraw: true, + withdrawAll: true, + depositDisabled: false, + lastMeasurement: 10709740, + measurement: 1e18, + price_id: 'lp-bcurve', + }, + { + id: 'crvBTC', + name: 'curve.fi/sbtc LP', + symbol: 'crvBTC', + description: 'renBTC/wBTC/sBTC', + vaultSymbol: 'ycrvBTC', + erc20address: '0x075b1bb99792c9E1041bA13afEf80C91a1e70fB3', + vaultContractAddress: '0x7Ff566E1d69DEfF32a7b244aE7276b9f90e9D0f6', + vaultContractABI: config.vaultContractV3ABI, + balance: 0, + vaultBalance: 0, + decimals: 18, + deposit: true, + depositAll: true, + withdraw: true, + withdrawAll: true, + lastMeasurement: 10734341, + measurement: 1e18, + price_id: 'lp-sbtc-curve', + }, + { + id: '3Crv', + name: 'curve.fi/3pool LP', + symbol: '3Crv', + description: 'yDAI/yUSDC/yUSDT', + vaultSymbol: 'y3Crv', + erc20address: '0x6c3f90f043a72fa612cbac8115ee7e52bde6e490', + vaultContractAddress: '0x9cA85572E6A3EbF24dEDd195623F188735A5179f', + vaultContractABI: config.vaultContractV5ABI, + balance: 0, + vaultBalance: 0, + decimals: 18, + deposit: true, + depositAll: true, + withdraw: true, + withdrawAll: true, + lastMeasurement: 11039340, + measurement: 1e18, + depositDisabled: false, + price_id: 'curve-fi-ydai-yusdc-yusdt-ytusd', // TODO: Update this when Coingecko adds token + }, + { + id: 'GUSD', + name: 'GUSD', + symbol: 'GUSD', + description: 'GUSD', + vaultSymbol: 'yGUSD', + erc20address: '0xec0d8D3ED5477106c6D4ea27D90a60e594693C90', + vaultContractAddress: '0xec0d8D3ED5477106c6D4ea27D90a60e594693C90', + vaultContractABI: config.vaultContractV5ABI, + balance: 0, + vaultBalance: 0, + decimals: 2, + deposit: true, + depositAll: true, + withdraw: true, + withdrawAll: true, + lastMeasurement: 11039340, + measurement: 1e18, + depositDisabled: false, + price_id: 'gemini-dollar', + }, + { + id: 'ETH', + name: 'ETH', + symbol: 'ETH', + description: 'Ether', + vaultSymbol: 'yETH', + erc20address: 'Ethereum', + vaultContractAddress: '0xe1237aA7f535b0CC33Fd973D66cBf830354D16c7', + vaultContractABI: config.vaultContractV4ABI, + balance: 0, + vaultBalance: 0, + decimals: 18, + deposit: true, + depositAll: false, + withdraw: true, + withdrawAll: true, + lastMeasurement: 10774489, + measurement: 1e18, + depositDisabled: true, + price_id: 'ethereum', + }, + { + id: 'WETH', + name: 'WETH', + symbol: 'WETH', + description: 'Wrappeth Ether', + vaultSymbol: 'yWETH', + erc20address: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', + vaultContractAddress: '0xe1237aA7f535b0CC33Fd973D66cBf830354D16c7', + vaultContractABI: config.vaultContractV4ABI, + balance: 0, + vaultBalance: 0, + decimals: 18, + deposit: true, + depositAll: true, + withdraw: true, + withdrawAll: true, + lastMeasurement: 10774489, + measurement: 1e18, + depositDisabled: true, + price_id: 'ethereum', + }, + { + id: 'YFI', + name: 'yearn.finance', + symbol: 'YFI', + description: 'yearn.finance', + vaultSymbol: 'yYFI', + erc20address: '0x0bc529c00c6401aef6d220be8c6ea1667f6ad93e', + vaultContractAddress: '0xBA2E7Fed597fd0E3e70f5130BcDbbFE06bB94fe1', + vaultContractABI: config.vaultContractV2ABI, + balance: 0, + vaultBalance: 0, + decimals: 18, + deposit: true, + depositAll: true, + withdraw: true, + withdrawAll: true, + lastMeasurement: 10695309, + measurement: 1e18, + price_id: 'yearn-finance', + }, + { + id: 'DAI', + name: 'DAI', + symbol: 'DAI', + description: 'DAI Stablecoin', + vaultSymbol: 'yDAI', + erc20address: '0x6b175474e89094c44da98b954eedeac495271d0f', + vaultContractAddress: '0xACd43E627e64355f1861cEC6d3a6688B31a6F952', + vaultContractABI: config.vaultContractV2ABI, + balance: 0, + vaultBalance: 0, + decimals: 18, + deposit: true, + depositAll: true, + withdraw: true, + withdrawAll: true, + lastMeasurement: 10650116, + measurement: 1e18, + price_id: 'dai', + }, + { + id: 'TUSD', + name: 'TUSD', + symbol: 'TUSD', + description: 'TrueUSD', + vaultSymbol: 'yTUSD', + erc20address: '0x0000000000085d4780B73119b644AE5ecd22b376', + vaultContractAddress: '0x37d19d1c4E1fa9DC47bD1eA12f742a0887eDa74a', + vaultContractABI: config.vaultContractV2ABI, + balance: 0, + vaultBalance: 0, + decimals: 18, + deposit: true, + depositAll: true, + withdraw: true, + withdrawAll: true, + lastMeasurement: 10603368, + measurement: 1e18, + price_id: 'true-usd', + }, + { + id: 'USDC', + name: 'USD Coin', + symbol: 'USDC', + description: 'USD Coin', + vaultSymbol: 'yUSDC', + erc20address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + vaultContractAddress: '0x597aD1e0c13Bfe8025993D9e79C69E1c0233522e', + vaultContractABI: config.vaultContractABI, + balance: 0, + vaultBalance: 0, + decimals: 6, + deposit: true, + depositAll: false, + withdraw: true, + withdrawAll: false, + lastMeasurement: 10532708, + measurement: 1e18, + price_id: 'usd-coin', + }, + { + id: 'USDT', + name: 'USDT', + symbol: 'USDT', + description: 'Tether USD', + vaultSymbol: 'yUSDT', + erc20address: '0xdAC17F958D2ee523a2206206994597C13D831ec7', + vaultContractAddress: '0x2f08119C6f07c006695E079AAFc638b8789FAf18', + vaultContractABI: config.vaultContractV2ABI, + balance: 0, + vaultBalance: 0, + decimals: 6, + deposit: true, + depositAll: true, + withdraw: true, + withdrawAll: true, + lastMeasurement: 10651402, + measurement: 1e18, + price_id: 'tether', + }, + { + id: 'aLINK', + name: 'aLINK', + symbol: 'aLINK', + description: 'Aave Interest bearing LINK', + vaultSymbol: 'yaLINK', + erc20address: '0xA64BD6C70Cb9051F6A9ba1F163Fdc07E0DfB5F84', + vaultContractAddress: '0x29E240CFD7946BA20895a7a02eDb25C210f9f324', + vaultContractABI: config.vaultContractV2ABI, + balance: 0, + vaultBalance: 0, + decimals: 18, + strategyDecimals: 6, + deposit: true, + depositAll: true, + withdraw: true, + withdrawAll: true, + lastMeasurement: 10599617, + measurement: 1e18, + price_id: 'aave-link', + }, + { + id: 'LINK', + name: 'ChainLink', + symbol: 'LINK', + description: 'ChainLink', + vaultSymbol: 'yLINK', + erc20address: '0x514910771af9ca656af840dff83e8264ecf986ca', + vaultContractAddress: '0x881b06da56BB5675c54E4Ed311c21E54C5025298', + vaultContractABI: config.vaultContractV2ABI, + balance: 0, + vaultBalance: 0, + decimals: 18, + strategyDecimals: 6, + deposit: true, + depositAll: true, + withdraw: true, + withdrawAll: true, + depositDisabled: true, + lastMeasurement: 10604016, + measurement: 1e18, + price_id: 'chainlink', + }, +]; diff --git a/services/vaults/save/handler.js b/services/vaults/save/handler.js index 9ae2a30..37d77a6 100644 --- a/services/vaults/save/handler.js +++ b/services/vaults/save/handler.js @@ -1,6 +1,6 @@ 'use strict'; -const db = dynamodb.doc; + require('dotenv').config(); const _ = require('lodash'); const dynamodb = require('../../../utils/dynamoDb'); @@ -9,6 +9,7 @@ const Web3 = require('web3'); const yRegistryAbi = require('../../../abi/yRegistry.json'); const delay = require('delay'); +const db = dynamodb.doc; const web3 = new Web3(process.env.WEB3_ENDPOINT); const etherscanApiKey = process.env.ETHERSCAN_API_KEY; const yRegistryAddress = '0x3ee41c098f9666ed2ea246f4d2558010e59d63a0'; @@ -142,6 +143,7 @@ module.exports.handler = async () => { delegated: vaultInfo.isDelegatedArray[idx], timestamp: Date.now(), }; + console.log(vault); await saveVault(vault); return vault; }; @@ -165,3 +167,4 @@ module.exports.handler = async () => { }; return response; }; + diff --git a/sls-resources/resource.local.yml b/sls-resources/resource.local.yml index c426499..595b2f2 100644 --- a/sls-resources/resource.local.yml +++ b/sls-resources/resource.local.yml @@ -34,4 +34,16 @@ Resources: KeyType: HASH AttributeDefinitions: - AttributeName: name - AttributeType: S \ No newline at end of file + AttributeType: S + DynamoDBTable4: + Type: AWS::DynamoDB::Table + DeletionPolicy: Retain + Properties: + TableName: holdings + BillingMode: PAY_PER_REQUEST + KeySchema: + - AttributeName: address + KeyType: HASH + AttributeDefinitions: + - AttributeName: address + AttributeType: S diff --git a/utils/dynamoDb.js b/utils/dynamoDb.js index db183bb..4a54870 100644 --- a/utils/dynamoDb.js +++ b/utils/dynamoDb.js @@ -25,6 +25,7 @@ 'use strict'; const AWS = require('aws-sdk'); +require('dotenv').config(); const options = { apiVersion: '2012-08-10',