From 50f2640d550734283381395780725ee990afa806 Mon Sep 17 00:00:00 2001 From: Dmitri Tsumak Date: Thu, 11 Jul 2024 20:42:11 +0300 Subject: [PATCH] Fix rate calculation, update addresses (#71) * Fix rate calculation, update addresses * Update packages * Fix not found vault during harvest --- package-lock.json | 136 +++++----- package.json | 27 +- scripts/createConstants.js | 5 + scripts/deploy.js | 2 +- src/abis/BlocklistVault.json | 102 +++++++- src/abis/Erc20Vault.json | 102 +++++++- src/abis/GenesisVault.json | 102 +++++++- src/abis/GnoVault.json | 17 +- src/abis/Multicall.json | 440 +++++++++++++++++++++++++++++++++ src/abis/PriceFeed.json | 15 -- src/abis/PrivateVault.json | 102 +++++++- src/abis/RestakeVault.json | 13 + src/abis/Vault.json | 102 +++++++- src/config/chiado.json | 52 ++-- src/config/gnosis.json | 70 ++++++ src/config/holesky.json | 44 ++-- src/config/mainnet.json | 32 ++- src/entities/apySnapshots.ts | 77 ++---- src/entities/network.ts | 13 - src/entities/v2pool.ts | 5 +- src/entities/vaults.ts | 6 +- src/helpers/utils.ts | 146 +++++++++++ src/mappings/blocklistVault.ts | 2 +- src/mappings/gnoVault.ts | 24 +- src/mappings/keeper.ts | 135 +++++----- src/mappings/mevEscrow.ts | 16 +- src/mappings/v2pool.ts | 94 +------ src/mappings/vault.ts | 76 +++--- src/schema.graphql | 33 ++- src/subgraph.template.yaml | 8 +- 30 files changed, 1524 insertions(+), 474 deletions(-) create mode 100644 src/abis/Multicall.json delete mode 100644 src/abis/PriceFeed.json create mode 100644 src/config/gnosis.json create mode 100644 src/helpers/utils.ts diff --git a/package-lock.json b/package-lock.json index 6b0ec0c..6a289f4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,28 +1,28 @@ { "name": "v3-subgraph", - "version": "1.2.0", + "version": "2.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "v3-subgraph", - "version": "1.2.0", + "version": "2.0.0", "license": "AGPL-3.0-only", "devDependencies": { - "@graphprotocol/graph-cli": "0.73.0", + "@graphprotocol/graph-cli": "0.78.0", "@graphprotocol/graph-ts": "0.35.1", - "@types/node": "20.14.2", - "@typescript-eslint/eslint-plugin": "7.13.0", - "@typescript-eslint/parser": "7.13.0", + "@types/node": "20.14.10", + "@typescript-eslint/eslint-plugin": "7.16.0", + "@typescript-eslint/parser": "7.16.0", "dotenv": "16.4.5", "eslint": "8.57.0", "eslint-config-prettier": "9.1.0", "husky": "9.0.11", - "lint-staged": "15.2.6", + "lint-staged": "15.2.7", "matchstick-as": "0.6.0", "mustache": "4.2.0", "prettier": "3.3.2", - "typescript": "5.4.5" + "typescript": "5.5.3" }, "engines": { "node": "18" @@ -678,9 +678,9 @@ } }, "node_modules/@graphprotocol/graph-cli": { - "version": "0.73.0", - "resolved": "https://registry.npmjs.org/@graphprotocol/graph-cli/-/graph-cli-0.73.0.tgz", - "integrity": "sha512-g+EapDRvxhRjMccnUJE8gBRGDIF6mXqtv8g0tzzixVClw/BezBni8QXtXMHs4Gg0G2UnerJJLp5ZQgZqtHWnmg==", + "version": "0.78.0", + "resolved": "https://registry.npmjs.org/@graphprotocol/graph-cli/-/graph-cli-0.78.0.tgz", + "integrity": "sha512-Zw/6k7YYjVoHFgy1BbqpllPUSjzk1ubkIBbYp7HlD//mPUnUhWQLgId92yENw1DqbWOx1R+LhXjeKkwbJgjUxA==", "dev": true, "dependencies": { "@float-capital/float-subgraph-uncrashable": "^0.0.0-alpha.4", @@ -1395,9 +1395,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.14.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.2.tgz", - "integrity": "sha512-xyu6WAMVwv6AKFLB+e/7ySZVr/0zLCzOa7rSpq6jNwpqOrUbcACDWC+53d4n2QHOnDou0fbIsg8wZu/sxrnI4Q==", + "version": "20.14.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.10.tgz", + "integrity": "sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==", "dev": true, "dependencies": { "undici-types": "~5.26.4" @@ -1443,16 +1443,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.13.0.tgz", - "integrity": "sha512-FX1X6AF0w8MdVFLSdqwqN/me2hyhuQg4ykN6ZpVhh1ij/80pTvDKclX1sZB9iqex8SjQfVhwMKs3JtnnMLzG9w==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.16.0.tgz", + "integrity": "sha512-py1miT6iQpJcs1BiJjm54AMzeuMPBSPuKPlnT8HlfudbcS5rYeX5jajpLf3mrdRh9dA/Ec2FVUY0ifeVNDIhZw==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.13.0", - "@typescript-eslint/type-utils": "7.13.0", - "@typescript-eslint/utils": "7.13.0", - "@typescript-eslint/visitor-keys": "7.13.0", + "@typescript-eslint/scope-manager": "7.16.0", + "@typescript-eslint/type-utils": "7.16.0", + "@typescript-eslint/utils": "7.16.0", + "@typescript-eslint/visitor-keys": "7.16.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -1476,13 +1476,13 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.13.0.tgz", - "integrity": "sha512-xMEtMzxq9eRkZy48XuxlBFzpVMDurUAfDu5Rz16GouAtXm0TaAoTFzqWUFPPuQYXI/CDaH/Bgx/fk/84t/Bc9A==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.16.0.tgz", + "integrity": "sha512-j0fuUswUjDHfqV/UdW6mLtOQQseORqfdmoBNDFOqs9rvNVR2e+cmu6zJu/Ku4SDuqiJko6YnhwcL8x45r8Oqxg==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.13.0", - "@typescript-eslint/utils": "7.13.0", + "@typescript-eslint/typescript-estree": "7.16.0", + "@typescript-eslint/utils": "7.16.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -1503,15 +1503,15 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.13.0.tgz", - "integrity": "sha512-jceD8RgdKORVnB4Y6BqasfIkFhl4pajB1wVxrF4akxD2QPM8GNYjgGwEzYS+437ewlqqrg7Dw+6dhdpjMpeBFQ==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.16.0.tgz", + "integrity": "sha512-PqP4kP3hb4r7Jav+NiRCntlVzhxBNWq6ZQ+zQwII1y/G/1gdIPeYDCKr2+dH6049yJQsWZiHU6RlwvIFBXXGNA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.13.0", - "@typescript-eslint/types": "7.13.0", - "@typescript-eslint/typescript-estree": "7.13.0" + "@typescript-eslint/scope-manager": "7.16.0", + "@typescript-eslint/types": "7.16.0", + "@typescript-eslint/typescript-estree": "7.16.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -1525,15 +1525,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.13.0.tgz", - "integrity": "sha512-EjMfl69KOS9awXXe83iRN7oIEXy9yYdqWfqdrFAYAAr6syP8eLEFI7ZE4939antx2mNgPRW/o1ybm2SFYkbTVA==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.16.0.tgz", + "integrity": "sha512-ar9E+k7CU8rWi2e5ErzQiC93KKEFAXA2Kky0scAlPcxYblLt8+XZuHUZwlyfXILyQa95P6lQg+eZgh/dDs3+Vw==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.13.0", - "@typescript-eslint/types": "7.13.0", - "@typescript-eslint/typescript-estree": "7.13.0", - "@typescript-eslint/visitor-keys": "7.13.0", + "@typescript-eslint/scope-manager": "7.16.0", + "@typescript-eslint/types": "7.16.0", + "@typescript-eslint/typescript-estree": "7.16.0", + "@typescript-eslint/visitor-keys": "7.16.0", "debug": "^4.3.4" }, "engines": { @@ -1553,13 +1553,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.13.0.tgz", - "integrity": "sha512-ZrMCe1R6a01T94ilV13egvcnvVJ1pxShkE0+NDjDzH4nvG1wXpwsVI5bZCvE7AEDH1mXEx5tJSVR68bLgG7Dng==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.16.0.tgz", + "integrity": "sha512-8gVv3kW6n01Q6TrI1cmTZ9YMFi3ucDT7i7aI5lEikk2ebk1AEjrwX8MDTdaX5D7fPXMBLvnsaa0IFTAu+jcfOw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.13.0", - "@typescript-eslint/visitor-keys": "7.13.0" + "@typescript-eslint/types": "7.16.0", + "@typescript-eslint/visitor-keys": "7.16.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -1570,9 +1570,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.0.tgz", - "integrity": "sha512-QWuwm9wcGMAuTsxP+qz6LBBd3Uq8I5Nv8xb0mk54jmNoCyDspnMvVsOxI6IsMmway5d1S9Su2+sCKv1st2l6eA==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.16.0.tgz", + "integrity": "sha512-fecuH15Y+TzlUutvUl9Cc2XJxqdLr7+93SQIbcZfd4XRGGKoxyljK27b+kxKamjRkU7FYC6RrbSCg0ALcZn/xw==", "dev": true, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -1583,13 +1583,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.0.tgz", - "integrity": "sha512-cAvBvUoobaoIcoqox1YatXOnSl3gx92rCZoMRPzMNisDiM12siGilSM4+dJAekuuHTibI2hVC2fYK79iSFvWjw==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.16.0.tgz", + "integrity": "sha512-a5NTvk51ZndFuOLCh5OaJBELYc2O3Zqxfl3Js78VFE1zE46J2AaVuW+rEbVkQznjkmlzWsUI15BG5tQMixzZLw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.13.0", - "@typescript-eslint/visitor-keys": "7.13.0", + "@typescript-eslint/types": "7.16.0", + "@typescript-eslint/visitor-keys": "7.16.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1623,12 +1623,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.0.tgz", - "integrity": "sha512-nxn+dozQx+MK61nn/JP+M4eCkHDSxSLDpgE3WcQo0+fkjEolnaB5jswvIKC4K56By8MMgIho7f1PVxERHEo8rw==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.16.0.tgz", + "integrity": "sha512-rMo01uPy9C7XxG7AFsxa8zLnWXTF8N3PYclekWSrurvhwiw1eW88mrKiAYe6s53AUY57nTRz8dJsuuXdkAhzCg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.13.0", + "@typescript-eslint/types": "7.16.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -1690,9 +1690,9 @@ } }, "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -4918,9 +4918,9 @@ "dev": true }, "node_modules/lint-staged": { - "version": "15.2.6", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.6.tgz", - "integrity": "sha512-M/3PdijFXT/A5lnbSK3EQNLbIIrkE00JZaD39r7t4kfFOqT1Ly9LgSZSMMtvQ3p2/C8Nyj/ou0vkNHmEwqoB8g==", + "version": "15.2.7", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.7.tgz", + "integrity": "sha512-+FdVbbCZ+yoh7E/RosSdqKJyUM2OEjTciH0TFNkawKgvFp1zbGlEC39RADg+xKBG1R4mhoH2j85myBQZ5wR+lw==", "dev": true, "dependencies": { "chalk": "~5.3.0", @@ -5666,9 +5666,9 @@ "dev": true }, "node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" @@ -7341,9 +7341,9 @@ "dev": true }, "node_modules/typescript": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", - "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", + "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", "dev": true, "bin": { "tsc": "bin/tsc", diff --git a/package.json b/package.json index d0a85ed..5e4469d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "v3-subgraph", - "version": "1.2.0", + "version": "2.0.0", "description": "Subgraph for the StakeWise Protocol", "repository": "https://github.com/stakewise/v3-subgraph", "license": "AGPL-3.0-only", @@ -42,23 +42,34 @@ "build:chiado": "npm run prepare:chiado && npm run generate-wasm:chiado", "test:chiado": "npm run prepare:chiado && npm run generate-tests-yaml:chiado && graph test", "deploy-hosted:chiado": "npm run prepare:chiado && npm run deploy network:chiado node:hosted", - "deploy-local:chiado": "npm run prepare:chiado && npm run deploy network:chiado node:local" + "deploy-local:chiado": "npm run prepare:chiado && npm run deploy network:chiado node:local", + "---GNOSIS---": "", + "generate-const:gnosis": "node ./scripts/createConstants.js gnosis", + "generate-yaml:gnosis": "mustache src/config/gnosis.json src/subgraph.template.yaml > src/subgraph-gnosis.yaml", + "generate-tests-yaml:gnosis": "mustache src/config/gnosis.json matchstick.template.yaml > matchstick.yaml", + "generate-types:gnosis": "graph codegen src/subgraph-gnosis.yaml", + "generate-wasm:gnosis": "graph build src/subgraph-gnosis.yaml -o build/gnosis", + "prepare:gnosis": "npm run generate-const:gnosis && npm run generate-yaml:gnosis && npm run generate-types:gnosis", + "build:gnosis": "npm run prepare:gnosis && npm run generate-wasm:gnosis", + "test:gnosis": "npm run prepare:gnosis && npm run generate-tests-yaml:gnosis && graph test", + "deploy-hosted:gnosis": "npm run prepare:gnosis && npm run deploy network:gnosis node:hosted", + "deploy-local:gnosis": "npm run prepare:gnosis && npm run deploy network:gnosis node:local" }, "devDependencies": { - "@graphprotocol/graph-cli": "0.73.0", + "@graphprotocol/graph-cli": "0.78.0", "@graphprotocol/graph-ts": "0.35.1", - "@types/node": "20.14.2", - "@typescript-eslint/eslint-plugin": "7.13.0", - "@typescript-eslint/parser": "7.13.0", + "@types/node": "20.14.10", + "@typescript-eslint/eslint-plugin": "7.16.0", + "@typescript-eslint/parser": "7.16.0", "dotenv": "16.4.5", "eslint": "8.57.0", "eslint-config-prettier": "9.1.0", "husky": "9.0.11", - "lint-staged": "15.2.6", + "lint-staged": "15.2.7", "matchstick-as": "0.6.0", "mustache": "4.2.0", "prettier": "3.3.2", - "typescript": "5.4.5" + "typescript": "5.5.3" }, "engines": { "node": "18" diff --git a/scripts/createConstants.js b/scripts/createConstants.js index 8e52dbb..6147914 100644 --- a/scripts/createConstants.js +++ b/scripts/createConstants.js @@ -4,6 +4,7 @@ const path = require('path') const isMainnet = process.argv.includes('mainnet') const isHolesky = process.argv.includes('holesky') const isChiado = process.argv.includes('chiado') +const isGnosis = process.argv.includes('gnosis') let configName = null @@ -19,6 +20,10 @@ if (isChiado) { configName = 'chiado' } +if (isGnosis) { + configName = 'gnosis' +} + if (!configName) { throw new Error('Network is not supported') } diff --git a/scripts/deploy.js b/scripts/deploy.js index 6a6f4ed..95ecacb 100644 --- a/scripts/deploy.js +++ b/scripts/deploy.js @@ -43,7 +43,7 @@ const validateEnv = () => { const validateArgs = () => { const { network, node } = args - const allowedNetworks = ['holesky', 'mainnet', 'chiado'] + const allowedNetworks = ['holesky', 'mainnet', 'chiado', 'gnosis'] const allowedNodes = ['hosted', 'local'] if (!network) { diff --git a/src/abis/BlocklistVault.json b/src/abis/BlocklistVault.json index f2a9765..f0c6673 100644 --- a/src/abis/BlocklistVault.json +++ b/src/abis/BlocklistVault.json @@ -161,6 +161,19 @@ "name": "ExitedAssetsClaimed", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "penalty", + "type": "uint256" + } + ], + "name": "ExitingAssetsPenalized", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -558,9 +571,9 @@ { "inputs": [ { - "internalType": "uint256", + "internalType": "uint128", "name": "osTokenShares", - "type": "uint256" + "type": "uint128" } ], "name": "burnOsToken", @@ -716,6 +729,35 @@ "stateMutability": "payable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "internalType": "uint256", + "name": "osTokenShares", + "type": "uint256" + }, + { + "internalType": "address", + "name": "referrer", + "type": "address" + } + ], + "name": "depositAndMintOsToken", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [ { @@ -1242,6 +1284,62 @@ "stateMutability": "payable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "internalType": "uint256", + "name": "osTokenShares", + "type": "uint256" + }, + { + "internalType": "address", + "name": "referrer", + "type": "address" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "rewardsRoot", + "type": "bytes32" + }, + { + "internalType": "int160", + "name": "reward", + "type": "int160" + }, + { + "internalType": "uint160", + "name": "unlockedMevReward", + "type": "uint160" + }, + { + "internalType": "bytes32[]", + "name": "proof", + "type": "bytes32[]" + } + ], + "internalType": "struct IKeeperRewards.HarvestParams", + "name": "harvestParams", + "type": "tuple" + } + ], + "name": "updateStateAndDepositAndMintOsToken", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [], "name": "validatorsManager", diff --git a/src/abis/Erc20Vault.json b/src/abis/Erc20Vault.json index 9041e09..089a462 100644 --- a/src/abis/Erc20Vault.json +++ b/src/abis/Erc20Vault.json @@ -142,6 +142,19 @@ "name": "ExitedAssetsClaimed", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "penalty", + "type": "uint256" + } + ], + "name": "ExitingAssetsPenalized", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -612,9 +625,9 @@ { "inputs": [ { - "internalType": "uint256", + "internalType": "uint128", "name": "osTokenShares", - "type": "uint256" + "type": "uint128" } ], "name": "burnOsToken", @@ -783,6 +796,35 @@ "stateMutability": "payable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "internalType": "uint256", + "name": "osTokenShares", + "type": "uint256" + }, + { + "internalType": "address", + "name": "referrer", + "type": "address" + } + ], + "name": "depositAndMintOsToken", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [ { @@ -1432,6 +1474,62 @@ "stateMutability": "payable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "internalType": "uint256", + "name": "osTokenShares", + "type": "uint256" + }, + { + "internalType": "address", + "name": "referrer", + "type": "address" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "rewardsRoot", + "type": "bytes32" + }, + { + "internalType": "int160", + "name": "reward", + "type": "int160" + }, + { + "internalType": "uint160", + "name": "unlockedMevReward", + "type": "uint160" + }, + { + "internalType": "bytes32[]", + "name": "proof", + "type": "bytes32[]" + } + ], + "internalType": "struct IKeeperRewards.HarvestParams", + "name": "harvestParams", + "type": "tuple" + } + ], + "name": "updateStateAndDepositAndMintOsToken", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [], "name": "validatorsManager", diff --git a/src/abis/GenesisVault.json b/src/abis/GenesisVault.json index e12e5c0..de81c51 100644 --- a/src/abis/GenesisVault.json +++ b/src/abis/GenesisVault.json @@ -117,6 +117,19 @@ "name": "ExitedAssetsClaimed", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "penalty", + "type": "uint256" + } + ], + "name": "ExitingAssetsPenalized", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -545,9 +558,9 @@ { "inputs": [ { - "internalType": "uint256", + "internalType": "uint128", "name": "osTokenShares", - "type": "uint256" + "type": "uint128" } ], "name": "burnOsToken", @@ -703,6 +716,35 @@ "stateMutability": "payable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "internalType": "uint256", + "name": "osTokenShares", + "type": "uint256" + }, + { + "internalType": "address", + "name": "referrer", + "type": "address" + } + ], + "name": "depositAndMintOsToken", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [ { @@ -1222,6 +1264,62 @@ "stateMutability": "payable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "internalType": "uint256", + "name": "osTokenShares", + "type": "uint256" + }, + { + "internalType": "address", + "name": "referrer", + "type": "address" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "rewardsRoot", + "type": "bytes32" + }, + { + "internalType": "int160", + "name": "reward", + "type": "int160" + }, + { + "internalType": "uint160", + "name": "unlockedMevReward", + "type": "uint160" + }, + { + "internalType": "bytes32[]", + "name": "proof", + "type": "bytes32[]" + } + ], + "internalType": "struct IKeeperRewards.HarvestParams", + "name": "harvestParams", + "type": "tuple" + } + ], + "name": "updateStateAndDepositAndMintOsToken", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [], "name": "validatorsManager", diff --git a/src/abis/GnoVault.json b/src/abis/GnoVault.json index b003725..2f76b6a 100644 --- a/src/abis/GnoVault.json +++ b/src/abis/GnoVault.json @@ -117,6 +117,19 @@ "name": "ExitedAssetsClaimed", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "penalty", + "type": "uint256" + } + ], + "name": "ExitingAssetsPenalized", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -501,9 +514,9 @@ { "inputs": [ { - "internalType": "uint256", + "internalType": "uint128", "name": "osTokenShares", - "type": "uint256" + "type": "uint128" } ], "name": "burnOsToken", diff --git a/src/abis/Multicall.json b/src/abis/Multicall.json new file mode 100644 index 0000000..d9c5855 --- /dev/null +++ b/src/abis/Multicall.json @@ -0,0 +1,440 @@ +[ + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "bytes", + "name": "callData", + "type": "bytes" + } + ], + "internalType": "struct Multicall3.Call[]", + "name": "calls", + "type": "tuple[]" + } + ], + "name": "aggregate", + "outputs": [ + { + "internalType": "uint256", + "name": "blockNumber", + "type": "uint256" + }, + { + "internalType": "bytes[]", + "name": "returnData", + "type": "bytes[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "bool", + "name": "allowFailure", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "callData", + "type": "bytes" + } + ], + "internalType": "struct Multicall3.Call3[]", + "name": "calls", + "type": "tuple[]" + } + ], + "name": "aggregate3", + "outputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "returnData", + "type": "bytes" + } + ], + "internalType": "struct Multicall3.Result[]", + "name": "returnData", + "type": "tuple[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "bool", + "name": "allowFailure", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "callData", + "type": "bytes" + } + ], + "internalType": "struct Multicall3.Call3Value[]", + "name": "calls", + "type": "tuple[]" + } + ], + "name": "aggregate3Value", + "outputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "returnData", + "type": "bytes" + } + ], + "internalType": "struct Multicall3.Result[]", + "name": "returnData", + "type": "tuple[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "bytes", + "name": "callData", + "type": "bytes" + } + ], + "internalType": "struct Multicall3.Call[]", + "name": "calls", + "type": "tuple[]" + } + ], + "name": "blockAndAggregate", + "outputs": [ + { + "internalType": "uint256", + "name": "blockNumber", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "blockHash", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "returnData", + "type": "bytes" + } + ], + "internalType": "struct Multicall3.Result[]", + "name": "returnData", + "type": "tuple[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "getBasefee", + "outputs": [ + { + "internalType": "uint256", + "name": "basefee", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "blockNumber", + "type": "uint256" + } + ], + "name": "getBlockHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "blockHash", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getBlockNumber", + "outputs": [ + { + "internalType": "uint256", + "name": "blockNumber", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getChainId", + "outputs": [ + { + "internalType": "uint256", + "name": "chainid", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCurrentBlockCoinbase", + "outputs": [ + { + "internalType": "address", + "name": "coinbase", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCurrentBlockDifficulty", + "outputs": [ + { + "internalType": "uint256", + "name": "difficulty", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCurrentBlockGasLimit", + "outputs": [ + { + "internalType": "uint256", + "name": "gaslimit", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCurrentBlockTimestamp", + "outputs": [ + { + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "addr", + "type": "address" + } + ], + "name": "getEthBalance", + "outputs": [ + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getLastBlockHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "blockHash", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "requireSuccess", + "type": "bool" + }, + { + "components": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "bytes", + "name": "callData", + "type": "bytes" + } + ], + "internalType": "struct Multicall3.Call[]", + "name": "calls", + "type": "tuple[]" + } + ], + "name": "tryAggregate", + "outputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "returnData", + "type": "bytes" + } + ], + "internalType": "struct Multicall3.Result[]", + "name": "returnData", + "type": "tuple[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "requireSuccess", + "type": "bool" + }, + { + "components": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "bytes", + "name": "callData", + "type": "bytes" + } + ], + "internalType": "struct Multicall3.Call[]", + "name": "calls", + "type": "tuple[]" + } + ], + "name": "tryBlockAndAggregate", + "outputs": [ + { + "internalType": "uint256", + "name": "blockNumber", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "blockHash", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "returnData", + "type": "bytes" + } + ], + "internalType": "struct Multicall3.Result[]", + "name": "returnData", + "type": "tuple[]" + } + ], + "stateMutability": "payable", + "type": "function" + } +] \ No newline at end of file diff --git a/src/abis/PriceFeed.json b/src/abis/PriceFeed.json deleted file mode 100644 index ffafaf1..0000000 --- a/src/abis/PriceFeed.json +++ /dev/null @@ -1,15 +0,0 @@ -[ - { - "inputs": [], - "name": "latestAnswer", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - } -] \ No newline at end of file diff --git a/src/abis/PrivateVault.json b/src/abis/PrivateVault.json index fb638d3..7b1a7ff 100644 --- a/src/abis/PrivateVault.json +++ b/src/abis/PrivateVault.json @@ -117,6 +117,19 @@ "name": "ExitedAssetsClaimed", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "penalty", + "type": "uint256" + } + ], + "name": "ExitingAssetsPenalized", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -526,9 +539,9 @@ { "inputs": [ { - "internalType": "uint256", + "internalType": "uint128", "name": "osTokenShares", - "type": "uint256" + "type": "uint128" } ], "name": "burnOsToken", @@ -684,6 +697,35 @@ "stateMutability": "payable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "internalType": "uint256", + "name": "osTokenShares", + "type": "uint256" + }, + { + "internalType": "address", + "name": "referrer", + "type": "address" + } + ], + "name": "depositAndMintOsToken", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [ { @@ -1192,6 +1234,62 @@ "stateMutability": "payable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "internalType": "uint256", + "name": "osTokenShares", + "type": "uint256" + }, + { + "internalType": "address", + "name": "referrer", + "type": "address" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "rewardsRoot", + "type": "bytes32" + }, + { + "internalType": "int160", + "name": "reward", + "type": "int160" + }, + { + "internalType": "uint160", + "name": "unlockedMevReward", + "type": "uint160" + }, + { + "internalType": "bytes32[]", + "name": "proof", + "type": "bytes32[]" + } + ], + "internalType": "struct IKeeperRewards.HarvestParams", + "name": "harvestParams", + "type": "tuple" + } + ], + "name": "updateStateAndDepositAndMintOsToken", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [ { diff --git a/src/abis/RestakeVault.json b/src/abis/RestakeVault.json index afe547c..7524ff0 100644 --- a/src/abis/RestakeVault.json +++ b/src/abis/RestakeVault.json @@ -136,6 +136,19 @@ "name": "ExitedAssetsClaimed", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "penalty", + "type": "uint256" + } + ], + "name": "ExitingAssetsPenalized", + "type": "event" + }, { "anonymous": false, "inputs": [ diff --git a/src/abis/Vault.json b/src/abis/Vault.json index b42398f..eb6324f 100644 --- a/src/abis/Vault.json +++ b/src/abis/Vault.json @@ -130,6 +130,19 @@ "name": "ExitedAssetsClaimed", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "penalty", + "type": "uint256" + } + ], + "name": "ExitingAssetsPenalized", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -495,9 +508,9 @@ { "inputs": [ { - "internalType": "uint256", + "internalType": "uint128", "name": "osTokenShares", - "type": "uint256" + "type": "uint128" } ], "name": "burnOsToken", @@ -653,6 +666,35 @@ "stateMutability": "payable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "internalType": "uint256", + "name": "osTokenShares", + "type": "uint256" + }, + { + "internalType": "address", + "name": "referrer", + "type": "address" + } + ], + "name": "depositAndMintOsToken", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [ { @@ -1148,6 +1190,62 @@ "stateMutability": "payable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "internalType": "uint256", + "name": "osTokenShares", + "type": "uint256" + }, + { + "internalType": "address", + "name": "referrer", + "type": "address" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "rewardsRoot", + "type": "bytes32" + }, + { + "internalType": "int160", + "name": "reward", + "type": "int160" + }, + { + "internalType": "uint160", + "name": "unlockedMevReward", + "type": "uint160" + }, + { + "internalType": "bytes32[]", + "name": "proof", + "type": "bytes32[]" + } + ], + "internalType": "struct IKeeperRewards.HarvestParams", + "name": "harvestParams", + "type": "tuple" + } + ], + "name": "updateStateAndDepositAndMintOsToken", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [], "name": "validatorsManager", diff --git a/src/config/chiado.json b/src/config/chiado.json index ca98f84..9ab3314 100644 --- a/src/config/chiado.json +++ b/src/config/chiado.json @@ -1,20 +1,18 @@ { - "network": "mainnet", + "network": "chiado", "wad": "1000000000000000000", "zeroAddress": "0x0000000000000000000000000000000000000000", - "daiUsdPriceFeed": "0x390C320Ae2B001C7CB31A690e2500b55313aC986", - "gnoUsdPriceFeed": "0xcC5E385EdB2fEaB9C9A6DE97b572f1d811312ae7", "v2PoolFeePercent": "1500", "vaultFactoryV1": "0x0000000000000000000000000000000000000000", - "vaultFactoryV2": "0x3092C23185bCEFB440B0Bc8bFA1E340E40b3A410", + "vaultFactoryV2": "0x7fEFdC8375E84Adb0bE5e4Ba5E238c021F1858fE", "privVaultFactoryV1": "0x0000000000000000000000000000000000000000", - "privVaultFactoryV2": "0xEBAF5bEbFb199D7c08fE82347C6D37914d07de70", + "privVaultFactoryV2": "0xA67D62F8D26Fe034426B512A6621D4e8fc8B2aB3", "erc20VaultFactoryV1": "0x0000000000000000000000000000000000000000", - "erc20VaultFactoryV2": "0x951D3BAB6BebB42BEabf807df808b58a5c4FC55D", + "erc20VaultFactoryV2": "0x7eA0D7dB6cf2402eB2B1A56bfBf6c2C88e6c8284", "privErc20VaultFactoryV1": "0x0000000000000000000000000000000000000000", - "privErc20VaultFactoryV2": "0x81feD710De1aC9D3D860F6C9aB4f150B1dfF621d", - "blocklistVaultFactoryV2": "0x6e16fc22013e07B8C8e6d4b30280F44d42A60a97", - "blocklistErc20VaultFactoryV2": "0xdd9e0dBFb218fb17f0A2f96E77224e00dF095bf2", + "privErc20VaultFactoryV2": "0x588102eB5E387956b8067F4948BcA34893E89597", + "blocklistVaultFactoryV2": "0x2bC7968461c51525433b9DcE504a543b26a2f31B", + "blocklistErc20VaultFactoryV2": "0x35482A11E21157E0C706d1A562483902421dB341", "restakeVaultFactoryV2": "0x0000000000000000000000000000000000000000", "restakePrivVaultFactoryV2": "0x0000000000000000000000000000000000000000", "restakeBlocklistVaultFactoryV2": "0x0000000000000000000000000000000000000000", @@ -27,46 +25,46 @@ "foxVault2": "0x0000000000000000000000000000000000000000", "vestingEscrowFactory": { "address": "0x0000000000000000000000000000000000000000", - "startBlock": "9652014" + "startBlock": "10627588" }, "keeper": { - "address": "0x13Af1266d8664aF3da4c711E7C86725D4779EA72", - "startBlock": "10258082" + "address": "0x5f31eD13eBF81B67a9f9498F3d1D2Da553058988", + "startBlock": "10627588" }, "osToken": { - "address": "0x11Bd460C704b74Dc84Fce0C45d7dDA49EffCA59f", - "startBlock": "10258076" + "address": "0x0b4F6bFB694790051E0203Db83edbB5888099556", + "startBlock": "10627582" }, "swiseToken": { "address": "0x0000000000000000000000000000000000000000", - "startBlock": "10258082" + "startBlock": "10627582" }, "osTokenVaultController": { - "address": "0x28637130e692F821843eBAbeB8708dAB3F82cFa5", - "startBlock": "10258071" + "address": "0x5518052f2d898f062ee59964004A560F24E2eE7d", + "startBlock": "10627576" }, "genesisVault": { - "address": "0x0386467c4DfFA2A9Cf8b12dD9b62950065aa7e96", - "startBlock": "10258217" + "address": "0xF82f6E46d0d0a9536b9CA4bc480372EeaFcd9E6c", + "startBlock": "10627708" }, "depositDataRegistry": { - "address": "0xf9eB9EAd3d71516bF5206F702B8BD0c183045474", - "startBlock": "10258106" + "address": "0xFAce8504462AEb9BB6ae7Ecb206BD7B1EdF7956D", + "startBlock": "10627614" }, "v2RewardToken": { - "address": "0x0d6736e4ee767B1Bdfc1daeEfB74150643a50C15", - "startBlock": "10257788" + "address": "0x14c74b1C7eCa8362D4ABcCd71051Ce174d61a3D4", + "startBlock": "10626852" }, "v2StakedToken": { - "address": "0x61A58F486c9E23D3ACB88792c50ddcdde7cda656", - "startBlock": "10257854" + "address": "0xee2493a42861a0a49f88525c44aab8126d04b761", + "startBlock": "10626869" }, "eigenDelegationManager": { "address": "0x0000000000000000000000000000000000000000", - "startBlock": "10257854" + "startBlock": "10626869" }, "eigenPodManager": { "address": "0x0000000000000000000000000000000000000000", - "startBlock": "10257854" + "startBlock": "10626869" } } diff --git a/src/config/gnosis.json b/src/config/gnosis.json new file mode 100644 index 0000000..633a398 --- /dev/null +++ b/src/config/gnosis.json @@ -0,0 +1,70 @@ +{ + "network": "gnosis", + "wad": "1000000000000000000", + "zeroAddress": "0x0000000000000000000000000000000000000000", + "v2PoolFeePercent": "1500", + "vaultFactoryV1": "0x0000000000000000000000000000000000000000", + "vaultFactoryV2": "0xC2ecc7620416bd65bfab7010B0db955a0e49579a", + "privVaultFactoryV1": "0x0000000000000000000000000000000000000000", + "privVaultFactoryV2": "0x574952EC88b2fC271d0C0dB130794c86Ea42139A", + "erc20VaultFactoryV1": "0x0000000000000000000000000000000000000000", + "erc20VaultFactoryV2": "0xF6BBBc05536Ab198d4b7Ab74a93f8e2d4cAd5354", + "privErc20VaultFactoryV1": "0x0000000000000000000000000000000000000000", + "privErc20VaultFactoryV2": "0x48319f97E5Da1233c21c48b80097c0FB7a20Ff86", + "blocklistVaultFactoryV2": "0x78FbfBd1DD38892476Ac469325df36604A27F5B7", + "blocklistErc20VaultFactoryV2": "0x99E4300326867FE3f97864a74e500d19654c19e9", + "restakeVaultFactoryV2": "0x0000000000000000000000000000000000000000", + "restakePrivVaultFactoryV2": "0x0000000000000000000000000000000000000000", + "restakeBlocklistVaultFactoryV2": "0x0000000000000000000000000000000000000000", + "restakeErc20VaultFactoryV2": "0x0000000000000000000000000000000000000000", + "restakePrivErc20VaultFactoryV2": "0x0000000000000000000000000000000000000000", + "restakeBlocklistErc20VaultFactoryV2": "0x0000000000000000000000000000000000000000", + "rewardSplitterFactoryV1": "0x0000000000000000000000000000000000000000", + "rewardSplitterFactoryV2": "0x4c6306BA1821D88803e27A115433520F2d6276Fb", + "foxVault1": "0x0000000000000000000000000000000000000000", + "foxVault2": "0x0000000000000000000000000000000000000000", + "vestingEscrowFactory": { + "address": "0x0000000000000000000000000000000000000000", + "startBlock": "10627588" + }, + "keeper": { + "address": "0xcAC0e3E35d3BA271cd2aaBE688ac9DB1898C26aa", + "startBlock": "34778552" + }, + "osToken": { + "address": "0xF490c80aAE5f2616d3e3BDa2483E30C4CB21d1A0", + "startBlock": "34778547" + }, + "swiseToken": { + "address": "0xfdA94F056346d2320d4B5E468D6Ad099b2277746", + "startBlock": "20299140" + }, + "osTokenVaultController": { + "address": "0x60B2053d7f2a0bBa70fe6CDd88FB47b579B9179a", + "startBlock": "34778543" + }, + "genesisVault": { + "address": "0x4b4406Ed8659D03423490D8b62a1639206dA0A7a", + "startBlock": "34778680" + }, + "depositDataRegistry": { + "address": "0x58e16621B5c0786D6667D2d54E28A20940269E16", + "startBlock": "34778574" + }, + "v2RewardToken": { + "address": "0x6aC78efae880282396a335CA2F79863A1e6831D4", + "startBlock": "21275821" + }, + "v2StakedToken": { + "address": "0xA4eF9Da5BA71Cc0D2e5E877a910A37eC43420445", + "startBlock": "21275849" + }, + "eigenDelegationManager": { + "address": "0x0000000000000000000000000000000000000000", + "startBlock": "10626869" + }, + "eigenPodManager": { + "address": "0x0000000000000000000000000000000000000000", + "startBlock": "10626869" + } +} diff --git a/src/config/holesky.json b/src/config/holesky.json index 4bf37c2..0be05ba 100644 --- a/src/config/holesky.json +++ b/src/config/holesky.json @@ -2,27 +2,25 @@ "network": "holesky", "wad": "1000000000000000000", "zeroAddress": "0x0000000000000000000000000000000000000000", - "daiUsdPriceFeed": "0x0000000000000000000000000000000000000000", - "gnoUsdPriceFeed": "0x0000000000000000000000000000000000000000", "v2PoolFeePercent": "1000", "vaultFactoryV1": "0x1428BB71261f01BbC03ce4eC7cEEA674f94b5F18", "privVaultFactoryV1": "0x9741f8e49fFa322714511b5D17bD052698eAFA43", "erc20VaultFactoryV1": "0x4C1140F4A5E3DD459De642A46bd1df6FBe287e1B", "privErc20VaultFactoryV1": "0x930A2D0ADEbF4E69Bb929F6456C3D4bcabf52796", - "vaultFactoryV2": "0xd68ef965D4E32b99Fd2D014Fc35304f3C273277E", - "privVaultFactoryV2": "0x09fD091483d64b3b9d5474F374ddFE6039F79aAd", - "blocklistVaultFactoryV2": "0x473a94aBe8f173cac48A6213f61335E21B913875", - "erc20VaultFactoryV2": "0x10C5066FB5DA1C0D7eb189DE4dfA26d23e8e4aDa", - "privErc20VaultFactoryV2": "0x5da7d1De2e84047De2A7988a7E01B494d54284e7", - "blocklistErc20VaultFactoryV2": "0x3A945FD94A1d810B5e1c4536747F0de358d32854", + "vaultFactoryV2": "0xA1424Bd00e6940A58B1232ad4160A77dD0AC3099", + "privVaultFactoryV2": "0x8023518b2192FB5384DAdc596765B3dD1cdFe471", + "blocklistVaultFactoryV2": "0x82FE8C78CaE0013471179e76224ef89941bAaa75", + "erc20VaultFactoryV2": "0xc6e7d05B3F6e73E3A86C6deAE0Da1fce993cF833", + "privErc20VaultFactoryV2": "0x481f28C0D733614aF87897E43d0D52C451799592", + "blocklistErc20VaultFactoryV2": "0x82FE8C78CaE0013471179e76224ef89941bAaa75", "rewardSplitterFactoryV1": "0x6c56AC64457B8AeA1Bb8d1f5eA2d1E397C9c7a13", - "rewardSplitterFactoryV2": "0x7Fcb1857011BAF51003018e9299deE9012de0967", - "restakeVaultFactoryV2": "0x390C320Ae2B001C7CB31A690e2500b55313aC986", - "restakePrivVaultFactoryV2": "0x2a7FBFAaa33CFDB9E0EB3eb3F6aB01eA985354F2", - "restakeBlocklistVaultFactoryV2": "0x9e345cFa4A00aA2714264E9072800B89787aa826", - "restakeErc20VaultFactoryV2": "0x67E134aa61ee3903665a8045EC32886bfdf0B2B5", - "restakePrivErc20VaultFactoryV2": "0x860c75A594966f78fbd7c07D1748219CE9c42c39", - "restakeBlocklistErc20VaultFactoryV2": "0xd14013F989825037196089A498E8b7D3763B8695", + "rewardSplitterFactoryV2": "0x2Ed24638b3aB48cF0076f19199c78A62bfEb5889", + "restakeVaultFactoryV2": "0x3F6E93ca5c426907aA8C66f4202d5fEd4e86804a", + "restakePrivVaultFactoryV2": "0x38a6C11417bBf584bDC2C18a1E83bCD7e906BB19", + "restakeBlocklistVaultFactoryV2": "0x3a30416A16B992ff65722e7D659668DB36d678b5", + "restakeErc20VaultFactoryV2": "0xdB79701D6a4d6476Bfe2d59Afb0d675F97A6f67D", + "restakePrivErc20VaultFactoryV2": "0x470e61817bE4d064aCd9422aB6BfC23D5101F84E", + "restakeBlocklistErc20VaultFactoryV2": "0xcCE89aB06221c533190E0001F6ad1BAD58888DC2", "foxVault1": "0x3c4ae629bf823475192124E02b9879D3C1fd4538", "foxVault2": "0x37Bf0883c27365CffCd0C4202918df930989891f", "vestingEscrowFactory": { @@ -46,20 +44,20 @@ "startBlock": "215371" }, "genesisVault": { - "address": "0xf42cEAFa21Beb670573f32C31485E84233AFDB6b", - "startBlock": "215444" + "address": "0x0bD7de255880d0e4DBD8cA6081a129FD56Ecb661", + "startBlock": "1869831" }, "depositDataRegistry": { - "address": "0xf25f9A254F38aF10Dc352bF8F446Dc09a820ca76", - "startBlock": "1711347" + "address": "0xAC0F906E433d58FA868F936E8A43230473652885", + "startBlock": "1871189" }, "v2RewardToken": { - "address": "0xd57c19f20168406d162852515030e00e49bB7781", - "startBlock": "1104929" + "address": "0x14c74b1C7eCa8362D4ABcCd71051Ce174d61a3D4", + "startBlock": "1869701" }, "v2StakedToken": { - "address": "0xFb534BB912Eb83b7b629329195b8DF798Ea325b2", - "startBlock": "1104931" + "address": "0xb948180A455ad82f5D1b2946F2972F6Cc15293a5", + "startBlock": "1869726" }, "eigenDelegationManager": { "address": "0xA44151489861Fe9e3055d95adC98FbD462B948e7", diff --git a/src/config/mainnet.json b/src/config/mainnet.json index 6afcaa3..809c9f8 100644 --- a/src/config/mainnet.json +++ b/src/config/mainnet.json @@ -2,27 +2,25 @@ "network": "mainnet", "wad": "1000000000000000000", "zeroAddress": "0x0000000000000000000000000000000000000000", - "daiUsdPriceFeed": "0x0000000000000000000000000000000000000000", - "gnoUsdPriceFeed": "0x0000000000000000000000000000000000000000", "v2PoolFeePercent": "1000", "vaultFactoryV1": "0xDada5a8E3703B1e3EA2bAe5Ab704627eb2659fCC", - "vaultFactoryV2": "0x0000000000000000000000000000000000000000", + "vaultFactoryV2": "0xfaa05900019f6E465086bcE16Bb3F06992715D53", "privVaultFactoryV1": "0x170618936cd96B1eD8112eC3D3778374B38DFe5e", - "privVaultFactoryV2": "0x0000000000000000000000000000000000000000", + "privVaultFactoryV2": "0xb7832C9e93e54661354C8B88F3Ce7c0915f4C896", "erc20VaultFactoryV1": "0x6DDc10eEeEBbBcF00E784bA44Fe4B038af26cB53", - "erc20VaultFactoryV2": "0x0000000000000000000000000000000000000000", + "erc20VaultFactoryV2": "0x7a4F9912a812d932da57d73Cb5E5784B2c1cBA4A", "privErc20VaultFactoryV1": "0xe84183EfFbcc76D022Cccc31b95EAa332bB5Bb11", - "privErc20VaultFactoryV2": "0x0000000000000000000000000000000000000000", - "blocklistVaultFactoryV2": "0x0000000000000000000000000000000000000000", - "blocklistErc20VaultFactoryV2": "0x0000000000000000000000000000000000000000", - "restakeVaultFactoryV2": "0x0000000000000000000000000000000000000000", - "restakePrivVaultFactoryV2": "0x0000000000000000000000000000000000000000", - "restakeBlocklistVaultFactoryV2": "0x0000000000000000000000000000000000000000", - "restakeErc20VaultFactoryV2": "0x0000000000000000000000000000000000000000", - "restakePrivErc20VaultFactoryV2": "0x0000000000000000000000000000000000000000", - "restakeBlocklistErc20VaultFactoryV2": "0x0000000000000000000000000000000000000000", + "privErc20VaultFactoryV2": "0x58FDD303ab66722130C01533e7A1177f2b3a2949", + "blocklistVaultFactoryV2": "0x4E3D8197c2cb9bCd29e3DCeAE3670d3d5e774017", + "blocklistErc20VaultFactoryV2": "0x1bE3Ad178d85CE1b6a7fCF5baEFe68F26541b07C", + "restakeVaultFactoryV2": "0x32634dEc69D4523D2f980Be92494dC03bD4C9fce", + "restakePrivVaultFactoryV2": "0x807305c086A99cbDBff07cB4256cE556d9d6F0af", + "restakeBlocklistVaultFactoryV2": "0xF63666399aA1af203BfC9171147EDcB21A6Bf3A2", + "restakeErc20VaultFactoryV2": "0x44ECC30Bcc64b832A2cB5d1ff44260B1fCC565e1", + "restakePrivErc20VaultFactoryV2": "0x026dF36Ec050E7f473cbfc30aA42946D3Ed11b2c", + "restakeBlocklistErc20VaultFactoryV2": "0x6a2835087C6809902a2f39b86fe64Ef5daCc31e1", "rewardSplitterFactoryV1": "0x90a9428b8c58cA80B28aAF46B936D42e87797449", - "rewardSplitterFactoryV2": "0x0000000000000000000000000000000000000000", + "rewardSplitterFactoryV2": "0x256aF27ce81282A0491A5361172c1Db08f6cC5F8", "foxVault1": "0x4FEF9D741011476750A243aC70b9789a63dd47Df", "foxVault2": "0x0000000000000000000000000000000000000000", "vestingEscrowFactory": { @@ -50,8 +48,8 @@ "startBlock": "18470145" }, "depositDataRegistry": { - "address": "0x0000000000000000000000000000000000000000", - "startBlock": "18470145" + "address": "0x75AB6DdCe07556639333d3Df1eaa684F5735223e", + "startBlock": "20236211" }, "v2RewardToken": { "address": "0x20BC832ca081b91433ff6c17f85701B6e92486c5", diff --git a/src/entities/apySnapshots.ts b/src/entities/apySnapshots.ts index c3e0273..a11b5b5 100644 --- a/src/entities/apySnapshots.ts +++ b/src/entities/apySnapshots.ts @@ -6,31 +6,6 @@ const snapshotsPerWeek = 14 const secondsInYear = '31536000' const maxPercent = '100' -export function getRewardPerAsset( - reward: BigInt, - totalAssets: BigInt, - feePercent: i32, - totalDuration: BigInt, -): BigDecimal { - if (totalAssets.le(BigInt.zero()) || totalDuration.le(BigInt.zero())) { - return BigDecimal.zero() - } - - // Constants - const maxPercentDecimal = BigDecimal.fromString('10000') - const feePercentDecimal = BigDecimal.fromString(feePercent.toString()) - const rewardDecimal = BigDecimal.fromString(reward.toString()) - .times(maxPercentDecimal.minus(feePercentDecimal)) - .div(maxPercentDecimal) - - const totalAssetsDecimal = BigDecimal.fromString(totalAssets.toString()) - return rewardDecimal - .times(BigDecimal.fromString(secondsInYear)) - .times(BigDecimal.fromString(maxPercent)) - .div(totalAssetsDecimal) - .div(BigDecimal.fromString(totalDuration.toString())) -} - function _calculateMedian(values: Array): BigDecimal { if (values.length === 0) { return BigDecimal.fromString('0') @@ -46,8 +21,7 @@ function _calculateMedian(values: Array): BigDecimal { } else { // For even number of elements, calculate the average of the two middle elements const lowerMidIndex = mid - 1 - const upperMidIndex = mid - return sortedValues[lowerMidIndex as i32].plus(sortedValues[upperMidIndex as i32]).div(BigDecimal.fromString('2')) + return sortedValues[lowerMidIndex as i32].plus(sortedValues[mid as i32]).div(BigDecimal.fromString('2')) } } @@ -74,26 +48,22 @@ export function updateVaultApy( vault: Vault, fromTimestamp: BigInt | null, toTimestamp: BigInt, - periodConsensusReward: BigInt, - periodExecutionReward: BigInt, + rateChange: BigInt, ): void { if (fromTimestamp === null) { // it's the first update, skip return } const totalDuration = toTimestamp.minus(fromTimestamp) - const currentExecApy = getRewardPerAsset( - periodExecutionReward, - vault.principalAssets, - vault.feePercent, - totalDuration, - ) - const currentConsensusApy = getRewardPerAsset( - periodConsensusReward, - vault.principalAssets, - vault.feePercent, - totalDuration, - ) + const currentApy = BigDecimal.fromString(rateChange.toString()) + .times(BigDecimal.fromString(secondsInYear)) + .times(BigDecimal.fromString(maxPercent)) + .div(BigDecimal.fromString(WAD)) + .div(BigDecimal.fromString(totalDuration.toString())) + + // TODO: remove after deprecation period + const currentExecApy = currentApy.div(BigDecimal.fromString('2')) + const currentConsensusApy = currentApy.minus(currentExecApy) // calculate weekly apy let executionApys: Array = [currentExecApy] @@ -114,9 +84,6 @@ export function updateVaultApy( vaultApySnapshot.apy = currentExecApy.plus(currentConsensusApy) vaultApySnapshot.executionApy = currentExecApy vaultApySnapshot.consensusApy = currentConsensusApy - vaultApySnapshot.periodExecutionReward = periodExecutionReward - vaultApySnapshot.periodConsensusReward = periodConsensusReward - vaultApySnapshot.principalAssets = vault.principalAssets vaultApySnapshot.fromEpochTimestamp = fromTimestamp vaultApySnapshot.toEpochTimestamp = toTimestamp vaultApySnapshot.vault = vault.id @@ -136,21 +103,22 @@ export function updatePoolApy( pool: V2Pool, fromTimestamp: BigInt | null, toTimestamp: BigInt, - periodConsensusReward: BigInt, - periodExecutionReward: BigInt, + rateChange: BigInt, ): void { if (fromTimestamp === null) { // it's the first update, skip return } const totalDuration = toTimestamp.minus(fromTimestamp) - const currentExecApy = getRewardPerAsset(periodExecutionReward, pool.principalAssets, pool.feePercent, totalDuration) - const currentConsensusApy = getRewardPerAsset( - periodConsensusReward, - pool.principalAssets, - pool.feePercent, - totalDuration, - ) + const currentApy = BigDecimal.fromString(rateChange.toString()) + .times(BigDecimal.fromString(secondsInYear)) + .times(BigDecimal.fromString(maxPercent)) + .div(BigDecimal.fromString(WAD)) + .div(BigDecimal.fromString(totalDuration.toString())) + + // TODO: remove after deprecation period + const currentExecApy = currentApy.div(BigDecimal.fromString('2')) + const currentConsensusApy = currentApy.minus(currentExecApy) // calculate weekly apy let execApys: Array = [currentExecApy] @@ -171,9 +139,6 @@ export function updatePoolApy( poolApySnapshot.apy = currentExecApy.plus(currentConsensusApy) poolApySnapshot.executionApy = currentExecApy poolApySnapshot.consensusApy = currentConsensusApy - poolApySnapshot.periodExecutionReward = periodExecutionReward - poolApySnapshot.periodConsensusReward = periodConsensusReward - poolApySnapshot.principalAssets = pool.principalAssets poolApySnapshot.fromEpochTimestamp = fromTimestamp poolApySnapshot.toEpochTimestamp = toTimestamp poolApySnapshot.save() diff --git a/src/entities/network.ts b/src/entities/network.ts index 6fed662..9190542 100644 --- a/src/entities/network.ts +++ b/src/entities/network.ts @@ -1,7 +1,4 @@ import { Network } from '../../generated/schema' -import { PriceFeed } from '../../generated/Keeper/PriceFeed' -import { Address, BigInt } from '@graphprotocol/graph-ts' -import { DAI_USD_PRICE_FEED, GNO_USD_PRICE_FEED, WAD, ZERO_ADDRESS } from '../helpers/constants' export function createOrLoadNetwork(): Network { const id = '0' @@ -16,13 +13,3 @@ export function createOrLoadNetwork(): Network { return network } - -export function getConversionRate(): BigInt { - if (GNO_USD_PRICE_FEED == ZERO_ADDRESS) { - return BigInt.fromString(WAD) - } - - const daiUsdRate = PriceFeed.bind(Address.fromString(DAI_USD_PRICE_FEED)).latestAnswer() - const gnoUsdRate = PriceFeed.bind(Address.fromString(GNO_USD_PRICE_FEED)).latestAnswer() - return daiUsdRate.times(BigInt.fromString(WAD)).div(gnoUsdRate) -} diff --git a/src/entities/v2pool.ts b/src/entities/v2pool.ts index 3ffdb45..0eb904f 100644 --- a/src/entities/v2pool.ts +++ b/src/entities/v2pool.ts @@ -1,7 +1,6 @@ import { BigDecimal, BigInt } from '@graphprotocol/graph-ts' - import { V2Pool } from '../../generated/schema' -import { V2_POOL_FEE_PERCENT } from '../helpers/constants' +import { V2_POOL_FEE_PERCENT, WAD } from '../helpers/constants' const poolId = '1' @@ -13,7 +12,9 @@ export function createOrLoadV2Pool(): V2Pool { pool.totalAssets = BigInt.zero() pool.rewardAssets = BigInt.zero() pool.principalAssets = BigInt.zero() + pool.penaltyAssets = BigInt.zero() pool.feePercent = I32.parseInt(V2_POOL_FEE_PERCENT) + pool.rate = BigInt.fromString(WAD) pool.migrated = false pool.apySnapshotsCount = BigInt.zero() pool.apy = BigDecimal.zero() diff --git a/src/entities/vaults.ts b/src/entities/vaults.ts index 30b8bac..727f1d8 100644 --- a/src/entities/vaults.ts +++ b/src/entities/vaults.ts @@ -11,6 +11,7 @@ import { VaultCreated } from '../../generated/templates/VaultFactory/VaultFactor import { OsTokenPosition, Vault, VaultsStat } from '../../generated/schema' import { createOrLoadNetwork } from './network' import { createTransaction } from './transaction' +import { WAD } from '../helpers/constants' const vaultsStatId = '1' @@ -49,6 +50,7 @@ export function createVault( vault.feeRecipient = admin vault.keysManager = admin // Deprecated vault.depositDataManager = admin + vault.canHarvest = false vault.consensusReward = BigInt.zero() vault.lockedExecutionReward = BigInt.zero() vault.unlockedExecutionReward = BigInt.zero() @@ -58,11 +60,13 @@ export function createVault( vault.score = BigDecimal.zero() vault.totalAssets = BigInt.zero() vault.principalAssets = BigInt.zero() + vault.rate = BigInt.fromString(WAD) + vault.exitingAssets = BigInt.zero() vault.isPrivate = isPrivate vault.isBlocklist = isBlocklist vault.isRestake = isRestake vault.isErc20 = isErc20 - vault.isOsTokenEnabled = true + vault.isOsTokenEnabled = !isRestake vault.addressString = vaultAddressHex vault.createdAt = block.timestamp vault.apySnapshotsCount = BigInt.zero() diff --git a/src/helpers/utils.ts b/src/helpers/utils.ts new file mode 100644 index 0000000..d3eea04 --- /dev/null +++ b/src/helpers/utils.ts @@ -0,0 +1,146 @@ +import { Address, Bytes, BigInt, ethereum, log } from '@graphprotocol/graph-ts' +import { GENESIS_VAULT, NETWORK, V2_REWARD_TOKEN, V2_STAKED_TOKEN, WAD } from './constants' +import { Vault } from '../../generated/schema' +import { Vault as VaultContract } from '../../generated/Keeper/Vault' +import { Multicall as MulticallContract, TryAggregateCallReturnDataStruct } from '../../generated/Keeper/Multicall' + +export function isGnosisNetwork(): boolean { + return NETWORK == 'chiado' || NETWORK == 'gnosis' +} + +const multicallContractAddr = Address.fromString('0xcA11bde05977b3631167028862bE2a173976CA11') +const updateStateSelector = '0x1a7ff553' +const totalAssetsSelector = '0x01e1d114' +const totalSharesSelector = '0x3a98ef39' +const convertToAssetsSelector = '0x07a2d13a' +const swapXdaiToGnoSelector = '0xb0d11302' +const poolRewardAssetsSelector = '0x18160ddd' +const poolPrincipalAssetsSelector = '0x18160ddd' +const poolPenaltyAssetsSelector = '0xe6af61c8' + +export function getVaultTotalAssets(vault: Vault): BigInt { + const vaultAddr = Address.fromString(vault.id) + const vaultContract = VaultContract.bind(vaultAddr) + return vaultContract.totalAssets() +} + +export function getVaultStateUpdate( + vault: Vault, + rewardsRoot: Bytes, + reward: BigInt, + unlockedMevReward: BigInt, + proof: Array, +): Array { + const isGnosis = isGnosisNetwork() + const vaultAddr = Address.fromString(vault.id) + const updateStateCall = getUpdateStateCall(rewardsRoot, reward, unlockedMevReward, proof) + const convertToAssetsCall = getConvertToAssetsCall(BigInt.fromString(WAD)) + const totalAssetsCall = Bytes.fromHexString(totalAssetsSelector) + const totalSharesCall = Bytes.fromHexString(totalSharesSelector) + const swapXdaiToGnoCall = Bytes.fromHexString(swapXdaiToGnoSelector) + + const multicallContract = MulticallContract.bind(multicallContractAddr) + let calls: Array = [getAggregateCall(vaultAddr, updateStateCall)] + if (isGnosis) { + calls.push(getAggregateCall(vaultAddr, swapXdaiToGnoCall)) + } + calls.push(getAggregateCall(vaultAddr, convertToAssetsCall)) + calls.push(getAggregateCall(vaultAddr, totalAssetsCall)) + calls.push(getAggregateCall(vaultAddr, totalSharesCall)) + + const result = multicallContract.call('tryAggregate', 'tryAggregate(bool,(address,bytes)[]):((bool,bytes)[])', [ + ethereum.Value.fromBoolean(false), + ethereum.Value.fromArray(calls), + ]) + const resultValue = result[0].toTupleArray() + if (!resultValue[0].success) { + log.error('[Vault] getVaultStateUpdate failed for vault={} updateStateCall={}', [ + vault.id, + updateStateCall.toHexString(), + ]) + assert(false, 'executeVaultUpdateState failed') + } + + let newRate: BigInt, totalAssets: BigInt, totalShares: BigInt + if (isGnosis) { + newRate = ethereum.decode('uint256', resultValue[2].returnData)!.toBigInt() + totalAssets = ethereum.decode('uint256', resultValue[3].returnData)!.toBigInt() + totalShares = ethereum.decode('uint256', resultValue[4].returnData)!.toBigInt() + } else { + newRate = ethereum.decode('uint256', resultValue[1].returnData)!.toBigInt() + totalAssets = ethereum.decode('uint256', resultValue[2].returnData)!.toBigInt() + totalShares = ethereum.decode('uint256', resultValue[3].returnData)!.toBigInt() + } + return [newRate, totalAssets, totalShares] +} + +export function getPoolStateUpdate( + rewardsRoot: Bytes, + reward: BigInt, + unlockedMevReward: BigInt, + proof: Array, +): Array { + const isGnosis = isGnosisNetwork() + const rewardAssetsCall = Bytes.fromHexString(poolRewardAssetsSelector) + const principalAssetsCall = Bytes.fromHexString(poolPrincipalAssetsSelector) + const penaltyAssetsCall = Bytes.fromHexString(poolPenaltyAssetsSelector) + const updateStateCall = getUpdateStateCall(rewardsRoot, reward, unlockedMevReward, proof) + const swapXdaiToGnoCall = Bytes.fromHexString(swapXdaiToGnoSelector) + + const multicallContract = MulticallContract.bind(multicallContractAddr) + let calls: Array = [getAggregateCall(GENESIS_VAULT, updateStateCall)] + if (isGnosis) { + calls.push(getAggregateCall(GENESIS_VAULT, swapXdaiToGnoCall)) + } + calls.push(getAggregateCall(V2_REWARD_TOKEN, rewardAssetsCall)) + calls.push(getAggregateCall(V2_REWARD_TOKEN, penaltyAssetsCall)) + calls.push(getAggregateCall(V2_STAKED_TOKEN, principalAssetsCall)) + + const result = multicallContract.call('tryAggregate', 'tryAggregate(bool,(address,bytes)[]):((bool,bytes)[])', [ + ethereum.Value.fromBoolean(false), + ethereum.Value.fromArray(calls), + ]) + const resultValue = result[0].toTupleArray() + if (!resultValue[0].success) { + log.error('[Vault] getPoolStateUpdate failed updateStateCall={}', [updateStateCall.toHexString()]) + assert(false, 'getPoolLatestRate failed') + } + + let rewardAssets: BigInt, principalAssets: BigInt, penaltyAssets: BigInt + if (isGnosis) { + rewardAssets = ethereum.decode('uint256', resultValue[2].returnData)!.toBigInt() + penaltyAssets = ethereum.decode('uint256', resultValue[3].returnData)!.toBigInt() + principalAssets = ethereum.decode('uint256', resultValue[4].returnData)!.toBigInt() + } else { + rewardAssets = ethereum.decode('uint256', resultValue[1].returnData)!.toBigInt() + penaltyAssets = ethereum.decode('uint256', resultValue[2].returnData)!.toBigInt() + principalAssets = ethereum.decode('uint256', resultValue[3].returnData)!.toBigInt() + } + const newRate = BigInt.fromString(WAD) + .times(rewardAssets.plus(principalAssets).minus(penaltyAssets)) + .div(principalAssets) + + return [newRate, rewardAssets, principalAssets, penaltyAssets] +} + +function getUpdateStateCall(rewardsRoot: Bytes, reward: BigInt, unlockedMevReward: BigInt, proof: Array): Bytes { + const updateStateArray: Array = [ + ethereum.Value.fromFixedBytes(rewardsRoot), + ethereum.Value.fromSignedBigInt(reward), + ethereum.Value.fromUnsignedBigInt(unlockedMevReward), + ethereum.Value.fromFixedBytesArray(proof), + ] + // Encode the tuple + const encodedUpdateStateArgs = ethereum.encode(ethereum.Value.fromTuple(changetype(updateStateArray))) + return Bytes.fromHexString(updateStateSelector).concat(encodedUpdateStateArgs as Bytes) +} + +function getConvertToAssetsCall(shares: BigInt): Bytes { + const encodedConvertToAssetsArgs = ethereum.encode(ethereum.Value.fromUnsignedBigInt(shares)) + return Bytes.fromHexString(convertToAssetsSelector).concat(encodedConvertToAssetsArgs as Bytes) +} + +function getAggregateCall(target: Address, data: Bytes): ethereum.Value { + const struct: Array = [ethereum.Value.fromAddress(target), ethereum.Value.fromBytes(data)] + return ethereum.Value.fromTuple(changetype(struct)) +} diff --git a/src/mappings/blocklistVault.ts b/src/mappings/blocklistVault.ts index 0284945..0ed1c33 100644 --- a/src/mappings/blocklistVault.ts +++ b/src/mappings/blocklistVault.ts @@ -51,7 +51,7 @@ export function handleBlocklistManagerUpdated(event: BlocklistManagerUpdated): v createTransaction(event.transaction.hash.toHex()) - log.info('[PrivateVault] BlocklistManagerUpdated vault={} blocklistManager={}', [ + log.info('[BlocklistVault] BlocklistManagerUpdated vault={} blocklistManager={}', [ vaultAddress, blocklistManager.toHex(), ]) diff --git a/src/mappings/gnoVault.ts b/src/mappings/gnoVault.ts index e0afe53..bc49c6b 100644 --- a/src/mappings/gnoVault.ts +++ b/src/mappings/gnoVault.ts @@ -2,31 +2,25 @@ import { BigInt, log } from '@graphprotocol/graph-ts' import { Vault } from '../../generated/schema' import { XdaiSwapped } from '../../generated/templates/GnoVault/GnoVault' -import { createOrLoadVaultsStat } from '../entities/vaults' // Event emitted when xDAI is swapped to GNO export function handleXdaiSwapped(event: XdaiSwapped): void { const params = event.params const vaultAddress = event.address - const assets = params.assets + let gnoAssets = params.assets + const xdaiAssets = params.amount const vault = Vault.load(vaultAddress.toHex()) as Vault - vault.totalAssets = vault.totalAssets.plus(assets) - vault.principalAssets = vault.principalAssets.plus(assets) - if (vault.unconvertedExecutionReward.le(params.amount)) { - vault.unconvertedExecutionReward = BigInt.zero() - } else { - vault.unconvertedExecutionReward = vault.unconvertedExecutionReward.minus(params.amount) - } - vault.save() + vault.unconvertedExecutionReward = vault.unconvertedExecutionReward.le(xdaiAssets) + ? BigInt.zero() + : vault.unconvertedExecutionReward.minus(xdaiAssets) - const vaultsStat = createOrLoadVaultsStat() - vaultsStat.totalAssets = vaultsStat.totalAssets.plus(assets) - vaultsStat.save() + vault.principalAssets = vault.principalAssets.plus(gnoAssets) + vault.save() log.info('[GnoVault] XdaiSwapped vault={} xdai={} gno={}', [ vaultAddress.toHexString(), - params.amount.toString(), - assets.toString(), + xdaiAssets.toString(), + gnoAssets.toString(), ]) } diff --git a/src/mappings/keeper.ts b/src/mappings/keeper.ts index f73ce68..d4379e5 100644 --- a/src/mappings/keeper.ts +++ b/src/mappings/keeper.ts @@ -17,8 +17,7 @@ import { RewardSplitterFactory as RewardSplitterFactoryTemplate, VaultFactory as VaultFactoryTemplate, } from '../../generated/templates' -import { updateVaultApy } from '../entities/apySnapshots' -import { createOrLoadV2Pool } from '../entities/v2pool' +import { updatePoolApy, updateVaultApy } from '../entities/apySnapshots' import { BLOCKLIST_ERC20_VAULT_FACTORY_V2, BLOCKLIST_VAULT_FACTORY_V2, @@ -26,7 +25,6 @@ import { ERC20_VAULT_FACTORY_V2, FOX_VAULT1, FOX_VAULT2, - GNO_USD_PRICE_FEED, PRIV_ERC20_VAULT_FACTORY_V1, PRIV_ERC20_VAULT_FACTORY_V2, PRIV_VAULT_FACTORY_V1, @@ -41,10 +39,11 @@ import { RESTAKE_ERC20_VAULT_FACTORY_V2, RESTAKE_PRIV_ERC20_VAULT_FACTORY_V2, RESTAKE_BLOCKLIST_ERC20_VAULT_FACTORY_V2, - WAD, ZERO_ADDRESS, } from '../helpers/constants' -import { getConversionRate } from '../entities/network' +import { getPoolStateUpdate, getVaultStateUpdate, getVaultTotalAssets, isGnosisNetwork } from '../helpers/utils' +import { createOrLoadVaultsStat } from '../entities/vaults' +import { createOrLoadV2Pool } from '../entities/v2pool' const IS_PRIVATE_KEY = 'isPrivate' const IS_ERC20_KEY = 'isErc20' @@ -189,7 +188,9 @@ export function updateRewards( rewardsIpfsHash: string, ): void { const vaultRewards = value.toObject().mustGet('vaults').toArray() - const executionRewardRate = getConversionRate() + const vaultsStat = createOrLoadVaultsStat() + const isGnosis = isGnosisNetwork() + const v2Pool = createOrLoadV2Pool() for (let i = 0; i < vaultRewards.length; i++) { // load vault object const vaultReward = vaultRewards[i].toObject() @@ -205,70 +206,46 @@ export function updateRewards( vault.mevEscrow === null ? vaultReward.mustGet('locked_mev_reward').toBigInt() : BigInt.zero() const unlockedMevReward = vaultReward.mustGet('unlocked_mev_reward').toBigInt() const consensusReward = vaultReward.mustGet('consensus_reward').toBigInt() - const executionReward = unlockedMevReward.plus(lockedMevReward) - const proof = vaultReward.mustGet('proof').toArray() - - // calculate period rewards - let periodConsensusReward: BigInt, periodExecutionReward: BigInt - if (vault.isGenesis) { - // period reward is calculated during harvest - periodConsensusReward = BigInt.zero() - periodExecutionReward = BigInt.zero() - } else if (vault.proofReward === null) { - // the first rewards update, no delta - periodConsensusReward = consensusReward - periodExecutionReward = executionReward - } else { - // calculate delta from previous update - periodConsensusReward = consensusReward.minus(vault.consensusReward) - periodExecutionReward = executionReward.minus(vault.lockedExecutionReward.plus(vault.unlockedExecutionReward)) - } - - // calculate smoothing pool penalty - let slashedMevReward = vault.slashedMevReward - if (vault.lockedExecutionReward.gt(lockedMevReward) && vault.unlockedExecutionReward.ge(unlockedMevReward)) { - slashedMevReward = slashedMevReward.plus(vault.lockedExecutionReward.minus(lockedMevReward)) - } + const proof = vaultReward + .mustGet('proof') + .toArray() + .map((p: JSONValue): Bytes => Bytes.fromHexString(p.toString()) as Bytes) // calculate proof values for state update let proofReward: BigInt let proofUnlockedMevReward: BigInt if (vault.mevEscrow !== null) { - // vault has own mev escrow, proof reward is consensus reward, nothing can be slashed + // vault has own mev escrow, proof reward is consensus reward, nothing can be locked proofReward = consensusReward - slashedMevReward = BigInt.zero() proofUnlockedMevReward = BigInt.zero() + } else if (isGnosis) { + // for gnosis network, execution rewards are received in DAI and must be converted to GNO + proofReward = consensusReward + proofUnlockedMevReward = unlockedMevReward } else { // vault uses shared mev escrow, proof reward is consensus reward + total mev reward - if (GNO_USD_PRICE_FEED == ZERO_ADDRESS) { - proofReward = consensusReward.plus(lockedMevReward).plus(unlockedMevReward) - } else { - // for gnosis network, execution rewards are received in DAI and converted later by the operator - proofReward = consensusReward - } + proofReward = consensusReward.plus(lockedMevReward).plus(unlockedMevReward) proofUnlockedMevReward = unlockedMevReward } - if (!vault.isGenesis) { - // genesis vault apy is updated during harvest - updateVaultApy( - vault, - vault.rewardsTimestamp, - updateTimestamp, - periodConsensusReward, - periodExecutionReward.times(executionRewardRate).div(BigInt.fromString(WAD)), - ) - } + // fetch new principal and total assets + const stateUpdate = getVaultStateUpdate(vault, rewardsRoot, proofReward, proofUnlockedMevReward, proof) + const newRate = stateUpdate[0] + const newTotalAssets = stateUpdate[1] + const newTotalShares = stateUpdate[2] - // update vault state - if (executionRewardRate.equals(BigInt.fromString(WAD))) { - vault.totalAssets = vault.totalAssets.plus(periodConsensusReward).plus(periodExecutionReward) - } else { - // for gnosis network, execution rewards must be converted for GNO before adding them to the total assets - vault.totalAssets = vault.totalAssets.plus(periodConsensusReward) - const unlockedExecutionRewardDelta = unlockedMevReward.minus(vault.unlockedExecutionReward) - vault.unconvertedExecutionReward = vault.unconvertedExecutionReward.plus(unlockedExecutionRewardDelta) + // calculate smoothing pool penalty + let slashedMevReward = vault.slashedMevReward + if (vault.lockedExecutionReward.gt(lockedMevReward) && vault.unlockedExecutionReward.ge(unlockedMevReward)) { + slashedMevReward = slashedMevReward.plus(vault.lockedExecutionReward.minus(lockedMevReward)) } + + updateVaultApy(vault, vault.rewardsTimestamp, updateTimestamp, newRate.minus(vault.rate)) + + vaultsStat.totalAssets = vaultsStat.totalAssets.minus(vault.totalAssets).plus(newTotalAssets) + vault.totalAssets = newTotalAssets + vault.totalShares = newTotalShares + vault.rate = newRate vault.rewardsRoot = rewardsRoot vault.proofReward = proofReward vault.proofUnlockedMevReward = proofUnlockedMevReward @@ -276,11 +253,30 @@ export function updateRewards( vault.lockedExecutionReward = lockedMevReward vault.unlockedExecutionReward = unlockedMevReward vault.slashedMevReward = slashedMevReward - vault.proof = proof.map((proofValue: JSONValue) => proofValue.toString()) + vault.proof = proof.map((proofValue: Bytes) => proofValue.toHexString()) vault.rewardsTimestamp = updateTimestamp vault.rewardsIpfsHash = rewardsIpfsHash + vault.canHarvest = true vault.save() + + // update v2 pool data + if (vault.isGenesis && v2Pool.migrated) { + const stateUpdate = getPoolStateUpdate(rewardsRoot, proofReward, proofUnlockedMevReward, proof) + const newRate = stateUpdate[0] + const newRewardAssets = stateUpdate[1] + const newPrincipalAssets = stateUpdate[2] + const newPenaltyAssets = stateUpdate[3] + updatePoolApy(v2Pool, v2Pool.rewardsTimestamp, updateTimestamp, newRate.minus(v2Pool.rate)) + v2Pool.rate = newRate + v2Pool.principalAssets = newPrincipalAssets + v2Pool.rewardAssets = newRewardAssets + v2Pool.penaltyAssets = newPenaltyAssets + v2Pool.totalAssets = newRewardAssets.plus(newPrincipalAssets).minus(newPenaltyAssets) + v2Pool.rewardsTimestamp = updateTimestamp + v2Pool.save() + } } + vaultsStat.save() } export function handleRewardsUpdated(event: RewardsUpdated): void { @@ -299,24 +295,25 @@ export function handleRewardsUpdated(event: RewardsUpdated): void { // Event emitted on Keeper assets harvest export function handleHarvested(event: Harvested): void { - let totalAssetsDelta = event.params.totalAssetsDelta const vaultAddress = event.params.vault.toHex() + const totalAssetsDelta = event.params.totalAssetsDelta - const vault = Vault.load(vaultAddress) as Vault - if (!vault.isGenesis) { - vault.principalAssets = vault.principalAssets.plus(totalAssetsDelta) - if (vault.totalAssets.lt(vault.principalAssets)) { - vault.totalAssets = vault.principalAssets - } - vault.save() - } else { + const vault = Vault.load(vaultAddress) + if (vault == null) { + log.error('[Keeper] Harvested vault={} not found', [vaultAddress]) + return + } + vault.canHarvest = (vault.rewardsRoot as Bytes).notEqual(event.params.rewardsRoot) + if (vault.isGenesis) { const v2Pool = createOrLoadV2Pool() if (!v2Pool.migrated) { - totalAssetsDelta = totalAssetsDelta.minus(v2Pool.rewardAssets) v2Pool.migrated = true + v2Pool.save() } - v2Pool.vaultHarvestDelta = totalAssetsDelta - v2Pool.save() + vault.principalAssets = getVaultTotalAssets(vault) + } else { + vault.principalAssets = vault.principalAssets.plus(totalAssetsDelta) } + vault.save() log.info('[Keeper] Harvested vault={} totalAssetsDelta={}', [vaultAddress, totalAssetsDelta.toString()]) } diff --git a/src/mappings/mevEscrow.ts b/src/mappings/mevEscrow.ts index 05e5755..466d458 100644 --- a/src/mappings/mevEscrow.ts +++ b/src/mappings/mevEscrow.ts @@ -2,26 +2,18 @@ import { log, dataSource } from '@graphprotocol/graph-ts' import { Vault } from '../../generated/schema' import { Harvested } from '../../generated/templates/OwnMevEscrow/OwnMevEscrow' -import { GNO_USD_PRICE_FEED, ZERO_ADDRESS } from '../helpers/constants' -import { createOrLoadVaultsStat } from '../entities/vaults' +import { isGnosisNetwork } from '../helpers/utils' // Event emitted on OwnMevEscrow harvesting rewards export function handleHarvested(event: Harvested): void { - if (GNO_USD_PRICE_FEED !== ZERO_ADDRESS) { - // ignore for gnosis networks - return - } + // ignore for gnosis networks + if (isGnosisNetwork()) return + const totalAssetsDelta = event.params.assets const context = dataSource.context() const vaultId = context.getString('vault') const vault = Vault.load(vaultId) as Vault vault.principalAssets = vault.principalAssets.plus(totalAssetsDelta) - if (vault.totalAssets.lt(vault.principalAssets)) { - const vaultsStat = createOrLoadVaultsStat() - vaultsStat.totalAssets = vaultsStat.totalAssets.plus(vault.principalAssets).minus(vault.totalAssets) - vaultsStat.save() - vault.totalAssets = vault.principalAssets - } vault.save() log.info('[OwnMevEscrow] Harvested vault={} totalAssetsDelta={}', [vaultId, totalAssetsDelta.toString()]) } diff --git a/src/mappings/v2pool.ts b/src/mappings/v2pool.ts index b322014..4207b27 100644 --- a/src/mappings/v2pool.ts +++ b/src/mappings/v2pool.ts @@ -6,16 +6,14 @@ import { Transfer as RewardTokenTransfer, } from '../../generated/V2RewardToken/V2RewardToken' import { Transfer as StakedTokenTransfer } from '../../generated/V2StakedToken/V2StakedToken' -import { Vault } from '../../generated/schema' import { createOrLoadV2Pool } from '../entities/v2pool' -import { updatePoolApy, updateVaultApy } from '../entities/apySnapshots' -import { GENESIS_VAULT, WAD } from '../helpers/constants' -import { getConversionRate } from '../entities/network' +import { WAD } from '../helpers/constants' export function handleRewardsUpdatedV0(event: RewardsUpdatedV0): void { let pool = createOrLoadV2Pool() pool.rewardAssets = event.params.totalRewards pool.totalAssets = pool.principalAssets.plus(pool.rewardAssets) + pool.rate = BigInt.fromString(WAD).times(pool.totalAssets).div(pool.principalAssets) pool.save() log.info('[V2 Pool] RewardsUpdated V0 totalRewards={}', [pool.rewardAssets.toString()]) @@ -25,96 +23,21 @@ export function handleRewardsUpdatedV1(event: RewardsUpdatedV1): void { let pool = createOrLoadV2Pool() pool.rewardAssets = event.params.totalRewards pool.totalAssets = pool.principalAssets.plus(pool.rewardAssets) + pool.rate = BigInt.fromString(WAD).times(pool.totalAssets).div(pool.principalAssets) pool.save() log.info('[V2 Pool] RewardsUpdated V1 totalRewards={}', [pool.rewardAssets.toString()]) } export function handleRewardsUpdatedV2(event: RewardsUpdatedV2): void { - let pool = createOrLoadV2Pool() + const pool = createOrLoadV2Pool() if (!pool.migrated) { - // pool hasn't been migrated yet, update V2 rewards pool.rewardAssets = event.params.totalRewards pool.totalAssets = pool.principalAssets.plus(pool.rewardAssets) + pool.rate = BigInt.fromString(WAD).times(pool.totalAssets).div(pool.principalAssets) pool.save() - log.info('[V2 Pool] RewardsUpdated V2 rewardAssets={}', [pool.rewardAssets.toString()]) - return - } - - // calculate period pool and vault rewards - const vault = Vault.load(GENESIS_VAULT.toHex()) as Vault - if (pool.rewardsTimestamp !== null && (vault.rewardsTimestamp as BigInt).equals(pool.rewardsTimestamp as BigInt)) { - // rewards haven't been updated - log.info('[V2 Pool] RewardsUpdated V2 skipped, rewardsTimestamp={}', [(pool.rewardsTimestamp as BigInt).toString()]) - return - } - const totalPrincipal = vault.principalAssets.plus(pool.totalAssets) - const totalPeriodReward = pool.vaultHarvestDelta as BigInt - let poolPeriodReward: BigInt - if (totalPeriodReward.lt(BigInt.zero())) { - poolPeriodReward = totalPeriodReward.times(pool.totalAssets).div(totalPrincipal) - } else { - poolPeriodReward = event.params.periodRewards } - const vaultPeriodReward = totalPeriodReward.minus(poolPeriodReward) - - // skip updating apy if it's the first rewards update - if (pool.rewardsTimestamp === null) { - pool.rewardsTimestamp = vault.rewardsTimestamp - pool.rewardAssets = event.params.totalRewards - pool.totalAssets = pool.principalAssets.plus(pool.rewardAssets) - pool.executionReward = vault.unlockedExecutionReward.plus(vault.lockedExecutionReward) - pool.consensusReward = vault.consensusReward - pool.save() - - vault.totalAssets = vault.totalAssets.plus(vaultPeriodReward) - vault.principalAssets = vault.principalAssets.plus(vaultPeriodReward) - vault.save() - return - } - - const periodConsensusReward = vault.consensusReward.minus(pool.consensusReward as BigInt) - const periodExecutionReward = vault.unlockedExecutionReward - .plus(vault.lockedExecutionReward) - .minus(pool.executionReward as BigInt) - - // update genesis vault - const executionRewardRate = getConversionRate() - updateVaultApy( - vault, - pool.rewardsTimestamp, - vault.rewardsTimestamp as BigInt, - periodConsensusReward.times(vault.principalAssets).div(totalPrincipal), - periodExecutionReward - .times(vault.principalAssets) - .times(executionRewardRate) - .div(totalPrincipal) - .div(BigInt.fromString(WAD)), - ) - vault.totalAssets = vault.totalAssets.plus(vaultPeriodReward) - vault.principalAssets = vault.principalAssets.plus(vaultPeriodReward) - vault.save() - - // update pool - updatePoolApy( - pool, - pool.rewardsTimestamp, - vault.rewardsTimestamp as BigInt, - periodConsensusReward.times(pool.totalAssets).div(totalPrincipal), - periodExecutionReward - .times(pool.totalAssets) - .times(executionRewardRate) - .div(totalPrincipal) - .div(BigInt.fromString(WAD)), - ) - pool.rewardsTimestamp = vault.rewardsTimestamp - pool.rewardAssets = event.params.totalRewards - pool.totalAssets = pool.principalAssets.plus(pool.rewardAssets) - pool.executionReward = vault.unlockedExecutionReward.plus(vault.lockedExecutionReward) - pool.consensusReward = vault.consensusReward - pool.vaultHarvestDelta = BigInt.zero() - pool.save() - log.info('[V2 Pool] RewardsUpdated V2 totalRewards={}', [pool.rewardAssets.toString()]) + log.info('[V2 Pool] RewardsUpdated V2 rewardAssets={}', [pool.rewardAssets.toString()]) } export function handleRewardTokenTransfer(event: RewardTokenTransfer): void { @@ -127,7 +50,7 @@ export function handleRewardTokenTransfer(event: RewardTokenTransfer): void { let pool = createOrLoadV2Pool() let value = event.params.value pool.rewardAssets = pool.rewardAssets.minus(value) - pool.totalAssets = pool.principalAssets.plus(pool.rewardAssets) + pool.totalAssets = pool.totalAssets.minus(value) pool.save() log.info('[V2 Pool] StakedToken burn amount={}', [value.toString()]) @@ -145,13 +68,14 @@ export function handleStakedTokenTransfer(event: StakedTokenTransfer): void { let value = event.params.value if (isMint) { pool.principalAssets = pool.principalAssets.plus(value) + pool.totalAssets = pool.totalAssets.plus(value) log.info('[V2 Pool] StakedToken mint amount={}', [value.toString()]) } if (isBurn) { pool.principalAssets = pool.principalAssets.minus(value) + pool.totalAssets = pool.totalAssets.minus(value) log.info('[V2 Pool] StakedToken burn amount={}', [value.toString()]) } - pool.totalAssets = pool.principalAssets.plus(pool.rewardAssets) pool.save() } diff --git a/src/mappings/vault.ts b/src/mappings/vault.ts index c5018e7..e4cf6d5 100644 --- a/src/mappings/vault.ts +++ b/src/mappings/vault.ts @@ -24,6 +24,7 @@ import { Redeemed, ValidatorsRootUpdated, ValidatorsManagerUpdated, + ExitingAssetsPenalized, } from '../../generated/templates/Vault/Vault' import { GenesisVaultCreated, Migrated } from '../../generated/GenesisVault/GenesisVault' import { EthFoxVaultCreated } from '../../generated/templates/FoxVault/FoxVault' @@ -34,7 +35,7 @@ import { createAllocatorAction, createOrLoadAllocator } from '../entities/alloca import { createOrLoadNetwork } from '../entities/network' import { createOrLoadOsTokenPosition, createOrLoadVaultsStat } from '../entities/vaults' import { createOrLoadOsToken } from '../entities/osToken' -import { DEPOSIT_DATA_REGISTRY } from '../helpers/constants' +import { DEPOSIT_DATA_REGISTRY, WAD } from '../helpers/constants' // Event emitted on assets transfer from allocator to vault export function handleDeposited(event: Deposited): void { @@ -285,14 +286,22 @@ export function handleV2ExitQueueEntered(event: V2ExitQueueEntered): void { const assets = params.assets const vaultAddress = event.address.toHex() - // Update vault queued shares + // Update vault shares and assets const vault = Vault.load(vaultAddress) as Vault - if (!vault.isErc20) { - // if it's ERC-20 vault shares are updated in Transfer event handler - const allocator = createOrLoadAllocator(owner, event.address) - allocator.shares = allocator.shares.minus(shares) - allocator.save() - } + vault.totalShares = vault.totalShares.minus(shares) + vault.totalAssets = vault.totalAssets.minus(assets) + vault.principalAssets = vault.principalAssets.minus(assets) + vault.exitingAssets = vault.exitingAssets.plus(assets) + vault.save() + + const vaultsStat = createOrLoadVaultsStat() + vaultsStat.totalAssets = vaultsStat.totalAssets.minus(assets) + vaultsStat.save() + + // Update allocator shares + const allocator = createOrLoadAllocator(owner, event.address) + allocator.shares = allocator.shares.minus(shares) + allocator.save() const timestamp = event.block.timestamp @@ -331,8 +340,6 @@ export function handleExitedAssetsClaimed(event: ExitedAssetsClaimed): void { const newPositionTicket = params.newPositionTicket const claimedAssets = params.withdrawnAssets const vaultAddress = event.address.toHex() - const vault = Vault.load(vaultAddress) as Vault - vault.save() createAllocatorAction(event, event.address, 'ExitedAssetsClaimed', receiver, claimedAssets, null) @@ -342,15 +349,23 @@ export function handleExitedAssetsClaimed(event: ExitedAssetsClaimed): void { const prevExitRequest = ExitRequest.load(prevExitRequestId) as ExitRequest const isExitQueueRequestResolved = newPositionTicket.equals(BigInt.zero()) + const isV2ExitRequest = prevExitRequest.totalShares.equals(BigInt.zero()) + + if (isV2ExitRequest) { + // Update vault shares and assets + const vault = Vault.load(vaultAddress) as Vault + vault.exitingAssets = vault.exitingAssets.minus(claimedAssets) + vault.save() + } if (!isExitQueueRequestResolved) { const nextExitQueueRequestId = `${vaultAddress}-${newPositionTicket}` let withdrawnShares: BigInt = BigInt.zero() let withdrawnAssets: BigInt = BigInt.zero() - if (prevExitRequest.totalShares.gt(BigInt.zero())) { - withdrawnShares = newPositionTicket.minus(prevPositionTicket) - } else { + if (isV2ExitRequest) { withdrawnAssets = claimedAssets + } else { + withdrawnShares = newPositionTicket.minus(prevPositionTicket) } const nextExitRequest = new ExitRequest(nextExitQueueRequestId) @@ -379,21 +394,11 @@ export function handleCheckpointCreated(event: CheckpointCreated): void { const vaultAddress = event.address.toHex() const vault = Vault.load(vaultAddress) as Vault - vault.totalShares = vault.totalShares.minus(burnedShares) - vault.totalAssets = vault.totalAssets.minus(exitedAssets) vault.principalAssets = vault.principalAssets.minus(exitedAssets) vault.save() - const vaultsStat = createOrLoadVaultsStat() - vaultsStat.totalAssets = vaultsStat.totalAssets.minus(exitedAssets) - vaultsStat.save() - - // queued shares are burned - const allocator = createOrLoadAllocator(event.address, event.address) - allocator.shares = allocator.shares.minus(burnedShares) - allocator.save() - - log.info('[Vault] CheckpointCreated burnedShares={} exitedAssets={}', [ + log.info('[Vault] CheckpointCreated vault={} burnedShares={} exitedAssets={}', [ + vaultAddress, burnedShares.toString(), exitedAssets.toString(), ]) @@ -407,10 +412,6 @@ export function handleFeeSharesMinted(event: FeeSharesMinted): void { const assets = params.assets const shares = params.shares - const vault = Vault.load(vaultAddress.toHex()) as Vault - vault.totalShares = vault.totalShares.plus(shares) - vault.save() - const allocator = createOrLoadAllocator(receiver, vaultAddress) allocator.shares = allocator.shares.plus(shares) allocator.save() @@ -423,6 +424,17 @@ export function handleFeeSharesMinted(event: FeeSharesMinted): void { ]) } +export function handleExitingAssetsPenalized(event: ExitingAssetsPenalized): void { + const vaultAddress = event.address + const penaltyAssets = event.params.penalty + + const vault = Vault.load(vaultAddress.toHex()) as Vault + vault.exitingAssets = vault.exitingAssets.minus(penaltyAssets) + vault.save() + + log.info('[Vault] ExitingAssetsPenalized vault={} penaltyAssets={}', [vaultAddress.toHex(), penaltyAssets.toString()]) +} + export function handleOsTokenMinted(event: OsTokenMinted): void { const holder = event.params.caller const shares = event.params.shares @@ -552,11 +564,14 @@ export function handleGenesisVaultCreated(event: GenesisVaultCreated): void { vault.lockedExecutionReward = BigInt.zero() vault.unlockedExecutionReward = BigInt.zero() vault.unconvertedExecutionReward = BigInt.zero() + vault.canHarvest = false vault.slashedMevReward = BigInt.zero() vault.totalShares = BigInt.zero() vault.score = BigDecimal.zero() + vault.rate = BigInt.fromString(WAD) vault.totalAssets = BigInt.zero() vault.principalAssets = BigInt.zero() + vault.exitingAssets = BigInt.zero() vault.isPrivate = false vault.isBlocklist = false vault.isErc20 = false @@ -619,11 +634,14 @@ export function handleFoxVaultCreated(event: EthFoxVaultCreated): void { vault.lockedExecutionReward = BigInt.zero() vault.unlockedExecutionReward = BigInt.zero() vault.unconvertedExecutionReward = BigInt.zero() + vault.canHarvest = false vault.slashedMevReward = BigInt.zero() vault.totalShares = BigInt.zero() vault.score = BigDecimal.zero() + vault.rate = BigInt.fromString(WAD) vault.totalAssets = BigInt.zero() vault.principalAssets = BigInt.zero() + vault.exitingAssets = BigInt.zero() vault.isPrivate = false vault.isBlocklist = true vault.isErc20 = false diff --git a/src/schema.graphql b/src/schema.graphql index b7b3baf..38dbf44 100644 --- a/src/schema.graphql +++ b/src/schema.graphql @@ -212,6 +212,9 @@ type Vault @entity { "The vault slashed MEV reward in the smoothing pool" slashedMevReward: BigInt! + "Defines whether the vault can harvest new rewards" + canHarvest: Boolean! + "The vault allocators' actions" allocatorActions: [AllocatorAction!]! @derivedFrom(field: "vault") @@ -236,6 +239,12 @@ type Vault @entity { "The number of assets used for rewardPerAsset calculation" principalAssets: BigInt! + "The current exchange rate for 10^18 amount" + rate: BigInt! + + "The total number of assets that are exiting (in V2 vaults)" + exitingAssets: BigInt! + "Indicates whether the Vault is private" isPrivate: Boolean! @@ -363,15 +372,6 @@ type VaultApySnapshot @entity { "The vault execution APY for the period" executionApy: BigDecimal! - "The period consensus reward" - periodConsensusReward: BigInt! - - "The period execution reward" - periodExecutionReward: BigInt! - - "The total assets in the vault that share the period reward" - principalAssets: BigInt! - "The period start epoch timestamp" fromEpochTimestamp: BigInt! @@ -519,21 +519,21 @@ type V2Pool @entity { "Total assets staked" principalAssets: BigInt! + "Total penalty accrued" + penaltyAssets: BigInt! + "The staking fee percent charged by the pool" feePercent: Int! - "The vault and pool execution reward" - executionReward: BigInt - - "The vault and pool consensus reward" - consensusReward: BigInt - "Whether V2 Pool has migrated to V3" migrated: Boolean! "The total number of APY snapshots" apySnapshotsCount: BigInt! + "The current exchange rate for 10^18 staked token" + rate: BigInt! + "The pool average weekly total APY" apy: BigDecimal! @@ -548,9 +548,6 @@ type V2Pool @entity { "Last rewards update timestamp" rewardsTimestamp: BigInt - - "The last genesis vault harvest delta" - vaultHarvestDelta: BigInt } """ diff --git a/src/subgraph.template.yaml b/src/subgraph.template.yaml index 33cec1d..bf53616 100644 --- a/src/subgraph.template.yaml +++ b/src/subgraph.template.yaml @@ -68,8 +68,10 @@ dataSources: abis: - name: Keeper file: ./abis/Keeper.json - - name: PriceFeed - file: ./abis/PriceFeed.json + - name: Vault + file: ./abis/Vault.json + - name: Multicall + file: ./abis/Multicall.json eventHandlers: - event: RewardsUpdated(indexed address,indexed bytes32,uint256,uint64,uint64,string) handler: handleRewardsUpdated @@ -351,6 +353,8 @@ templates: handler: handleValidatorsManagerUpdated - event: CheckpointCreated(uint256,uint256) handler: handleCheckpointCreated + - event: ExitingAssetsPenalized(uint256) + handler: handleExitingAssetsPenalized - event: FeeSharesMinted(address,uint256,uint256) handler: handleFeeSharesMinted - event: OsTokenMinted(indexed address,address,uint256,uint256,address)