From 063f3330d8a000ee1f4c6b327fb84cf587bb8a54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Pr=C3=A9vost?= <998369+prevostc@users.noreply.github.com> Date: Sat, 3 Aug 2024 13:45:07 +0200 Subject: [PATCH] Fix balances held in boosts --- .gitignore | 4 +- abis/beefy/BeefyLaunchPool.json | 640 ++++++++++++++++++++++++++++++++ src/vault-config-asm.ts | 13 +- src/vault-interaction.ts | 16 +- subgraph.template.yaml | 2 + 5 files changed, 672 insertions(+), 3 deletions(-) create mode 100644 abis/beefy/BeefyLaunchPool.json diff --git a/.gitignore b/.gitignore index 9cc8901..0106f2e 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,6 @@ src/config.ts random.json src/random.ts -tests/.latest.json \ No newline at end of file +tests/.latest.json +*.log +.DS_Store \ No newline at end of file diff --git a/abis/beefy/BeefyLaunchPool.json b/abis/beefy/BeefyLaunchPool.json new file mode 100644 index 0000000..86f55a0 --- /dev/null +++ b/abis/beefy/BeefyLaunchPool.json @@ -0,0 +1,640 @@ +[ + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "earned", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "notifyAlreadySent", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "rewards", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "duration", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "amount", + "type": "uint256" + } + ], + "name": "withdraw", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_notifier", + "type": "address" + }, + { + "name": "_enable", + "type": "bool" + } + ], + "name": "setNotifier", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "getReward", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "manager", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "closePreStake", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "notifiers", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_amount", + "type": "uint256" + } + ], + "name": "notifyAmount", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "treasury", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_fee", + "type": "uint256" + } + ], + "name": "setTreasuryFee", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "rewardRate", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "lastTimeRewardApplicable", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "userRewardPerTokenPaid", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "owner", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "isOwner", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "openPreStake", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "amount", + "type": "uint256" + } + ], + "name": "stake", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "rewardBalance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "isPreStake", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_duration", + "type": "uint256" + } + ], + "name": "setRewardDuration", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "lastUpdateTime", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "treasuryFee", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "stakedToken", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "rewardPerToken", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_token", + "type": "address" + } + ], + "name": "inCaseTokensGetStuck", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "rewardPerTokenStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "exit", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "periodFinish", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_treasury", + "type": "address" + } + ], + "name": "setTreasury", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_token", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_amount", + "type": "uint256" + } + ], + "name": "inCaseTokensGetStuck", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "rewardToken", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "name": "_stakedToken", + "type": "address" + }, + { + "name": "_rewardToken", + "type": "address" + }, + { + "name": "_duration", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "reward", + "type": "uint256" + } + ], + "name": "RewardAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "user", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Staked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "user", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Withdrawn", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "user", + "type": "address" + }, + { + "indexed": false, + "name": "reward", + "type": "uint256" + } + ], + "name": "RewardPaid", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + } +] \ No newline at end of file diff --git a/src/vault-config-asm.ts b/src/vault-config-asm.ts index 56328ec..2945d9f 100644 --- a/src/vault-config-asm.ts +++ b/src/vault-config-asm.ts @@ -1,4 +1,4 @@ -import { Address, DataSourceContext, log, dataSource } from "@graphprotocol/graph-ts" +import { Address, DataSourceContext, log, dataSource, Bytes } from "@graphprotocol/graph-ts" import { NETWORK_NAME } from "./config" import { VaultConfig, _getChainVaults } from "./vault-config" import { RANDOM } from "./random" @@ -32,6 +32,17 @@ export function getChainVaults(): Array { return vaults } +export function getVaultConfigByAddress(address: Bytes): VaultConfigAsm | null { + const vaults = getChainVaults() + for (let i = 0; i < vaults.length; i++) { + if (vaults[i].address.equals(address)) { + return vaults[i] + } + } + + return null +} + export function isBoostAddress(address: Address): boolean { const vaults = getChainVaults() for (let i = 0; i < vaults.length; i++) { diff --git a/src/vault-interaction.ts b/src/vault-interaction.ts index 204c6cc..ed8ff7c 100644 --- a/src/vault-interaction.ts +++ b/src/vault-interaction.ts @@ -1,10 +1,11 @@ import { Address, log, ethereum, BigInt, Bytes } from "@graphprotocol/graph-ts" import { Transfer as TransferEvent, IERC20 as IERC20Contract } from "../generated/templates/BeefyVaultV7/IERC20" +import { BeefyLaunchPool as BeefyBoostContract } from "../generated/templates/BeefyVaultV7/BeefyLaunchPool" import { getBeefyStrategy, getBeefyVault, isVaultInitialized } from "./entity/vault" import { ZERO_BD, ZERO_BI, tokenAmountToDecimal } from "./utils/decimal" import { getTokenAndInitIfNeeded } from "./entity/token" import { SHARE_TOKEN_MINT_ADDRESS, BURN_ADDRESS } from "./config" -import { getChainVaults, isBoostAddress, isRewardPoolAddress } from "./vault-config-asm" +import { getChainVaults, isBoostAddress, isRewardPoolAddress, getVaultConfigByAddress } from "./vault-config-asm" import { getInvestor } from "./entity/investor" import { getInvestorPosition } from "./entity/position" import { BeefyVault, Investor } from "../generated/schema" @@ -121,9 +122,22 @@ function updateInvestorVaultData(vault: BeefyVault, investor: Investor): Investo for (let i = 0; i < rewardPools.length; i++) { const rewardPool = rewardPools[i] const rewardPoolContract = IERC20Contract.bind(Address.fromBytes(rewardPool.id)) + // This is assuming RP token are equivalent to vault token rawSharesBalance = rawSharesBalance.plus(rewardPoolContract.balanceOf(investorAddress)) } + const vaultConfig = getVaultConfigByAddress(vault.id) + if (vaultConfig) { + const boosts = vaultConfig.boostAddresses + for (let i = 0; i < boosts.length; i++) { + const boostAddress = boosts[i] + const boostContract = BeefyBoostContract.bind(boostAddress) + rawSharesBalance = rawSharesBalance.plus(boostContract.balanceOf(investorAddress)) + } + } else { + log.error("updateInvestorVaultData: vault config not found {}", [vault.id.toHexString()]) + } + // get the new investor deposit value const sharesToken = getTokenAndInitIfNeeded(vault.sharesToken) const investorShareTokenBalance = tokenAmountToDecimal(rawSharesBalance, sharesToken.decimals) diff --git a/subgraph.template.yaml b/subgraph.template.yaml index e6d02f1..32c33d1 100644 --- a/subgraph.template.yaml +++ b/subgraph.template.yaml @@ -36,6 +36,8 @@ dataSources: file: ./abis/beefy/BeefyVaultV7.json - name: BeefyRewardPool file: ./abis/beefy/BeefyRewardPool.json + - name: BeefyLaunchPool + file: ./abis/beefy/BeefyLaunchPool.json - name: BeefyIStrategyV7 file: ./abis/beefy/BeefyIStrategyV7.json - name: Multicall3