From 8f054a88b959a8ea88c2b4ae7fdfd35d7239885f Mon Sep 17 00:00:00 2001 From: Corey Rice Date: Tue, 3 Sep 2024 10:34:30 -0400 Subject: [PATCH 1/2] feat: add weETHs invariant event indexing --- package.json | 4 +- subgraphs/etherfi-promo/config/index.ts | 19 ++- subgraphs/etherfi-promo/package.json | 4 +- subgraphs/etherfi-promo/schema.graphql | 30 ++-- .../etherfi-promo/src/constants/addresses.ts | 4 - .../src/constants/config-template | 4 - .../etherfi-promo/src/constants/index.ts | 4 - .../etherfi-promo/src/mappings/vToken.ts | 75 ++++------ .../etherfi-promo/src/operations/create.ts | 22 ++- subgraphs/etherfi-promo/src/operations/get.ts | 35 +++-- .../src/operations/getOrCreate.ts | 38 ++++++ .../etherfi-promo/src/operations/update.ts | 32 +++-- subgraphs/etherfi-promo/src/utilities/ids.ts | 4 + .../subgraph-client/.graphclientrc.yml | 2 +- .../etherfi-promo/subgraph-client/index.ts | 16 ++- .../queries/accountsQuery.graphql | 14 +- subgraphs/etherfi-promo/template.yaml | 37 ++++- .../etherfi-promo/tests/VToken/events.ts | 82 ----------- .../etherfi-promo/tests/VToken/index.test.ts | 128 +++++------------- subgraphs/etherfi-promo/tests/VToken/mocks.ts | 21 ++- subgraphs/etherfi-promo/tests/invariant.ts | 38 +++++- yarn.lock | 39 ++---- 22 files changed, 299 insertions(+), 353 deletions(-) delete mode 100644 subgraphs/etherfi-promo/src/constants/config-template create mode 100644 subgraphs/etherfi-promo/src/operations/getOrCreate.ts create mode 100644 subgraphs/etherfi-promo/src/utilities/ids.ts diff --git a/package.json b/package.json index 9535555b..6553dec7 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "devDependencies": { "@chainlink/contracts": "^0.5.1", "@graphprotocol/client-cli": "3.0.0", - "@graphprotocol/graph-cli": "^0.77.0", + "@graphprotocol/graph-cli": "^0.80.0", "@graphprotocol/graph-ts": "^0.35.1", "@layerzerolabs/solidity-examples": "^1.1.0", "@nomicfoundation/hardhat-chai-matchers": "^1.0.3", @@ -50,7 +50,7 @@ "@typescript-eslint/eslint-plugin": "^5.40.1", "@typescript-eslint/parser": "^5.40.1", "@venusprotocol/governance-contracts": "2.3.0-dev.4", - "@venusprotocol/isolated-pools": "3.5.0-dev.3", + "@venusprotocol/isolated-pools": "3.5.0-dev.10", "@venusprotocol/oracle": "2.2.0", "@venusprotocol/protocol-reserve": "2.3.0-dev.1", "@venusprotocol/solidity-utilities": "^2.0.3", diff --git a/subgraphs/etherfi-promo/config/index.ts b/subgraphs/etherfi-promo/config/index.ts index 8eb44f2a..57357a05 100644 --- a/subgraphs/etherfi-promo/config/index.ts +++ b/subgraphs/etherfi-promo/config/index.ts @@ -19,30 +19,29 @@ const main = () => { docker: { network: 'hardhat', vWeEthAddress: sepoliaILDeployments.addresses.VToken_vweETH_LiquidStakedETH, - weEthAddress: '0x3b8b6E96e57f0d1cD366AaCf4CcC68413aF308D0', - startBlock: '0', + vWeEthsAddress: sepoliaILDeployments.addresses.VToken_vweETHs_LiquidStakedETH, + vWeEthStartBlock: '0', + vWeEthsStartBlock: '0', }, sepolia: { network: 'sepolia', vWeEthAddress: sepoliaILDeployments.addresses.VToken_vweETH_LiquidStakedETH, - weEthAddress: '0x3b8b6E96e57f0d1cD366AaCf4CcC68413aF308D0', - startBlock: '5659827', + vWeEthsAddress: sepoliaILDeployments.addresses.VToken_vweETHs_LiquidStakedETH, + vWeEthStartBlock: '5659827', + vWeEthsStartBlock: '6536644', }, ethereum: { network: 'mainnet', vWeEthAddress: ethereumILDeployments.addresses.VToken_vweETH_LiquidStakedETH, - weEthAddress: '0xCd5fE23C85820F7B72D0926FC9b05b43E359b7ee', - startBlock: '19076099', + vWeEthsAddress: ethereumILDeployments.addresses.VToken_vweETHs_LiquidStakedETH, + vWeEthStartBlock: '19638180', + vWeEthsStartBlock: '20583508', }, }; const yamlTemplate = fs.readFileSync('template.yaml', 'utf8'); const yamlOutput = Mustache.render(yamlTemplate, config[network]); fs.writeFileSync('subgraph.yaml', yamlOutput); - - const configTemplate = fs.readFileSync('src/constants/config-template', 'utf8'); - const tsOutput = Mustache.render(configTemplate, config[network]); - fs.writeFileSync('src/constants/config.ts', tsOutput); }; main(); diff --git a/subgraphs/etherfi-promo/package.json b/subgraphs/etherfi-promo/package.json index acd40a94..24896ec5 100644 --- a/subgraphs/etherfi-promo/package.json +++ b/subgraphs/etherfi-promo/package.json @@ -26,10 +26,10 @@ "test:integration": "true" }, "dependencies": { - "@venusprotocol/isolated-pools": "3.3.0" + "@venusprotocol/isolated-pools": "3.5.0-dev.10" }, "devDependencies": { - "@graphprotocol/graph-cli": "^0.77.0", + "@graphprotocol/graph-cli": "^0.80.0", "ts-node": "^10.9.2", "viem": "^2.9.26" } diff --git a/subgraphs/etherfi-promo/schema.graphql b/subgraphs/etherfi-promo/schema.graphql index 6ea76ea0..0cc6a569 100644 --- a/subgraphs/etherfi-promo/schema.graphql +++ b/subgraphs/etherfi-promo/schema.graphql @@ -2,7 +2,7 @@ TVL """ type TVL @entity { - id: ID! + id: Bytes! tvl: BigInt! } @@ -10,44 +10,44 @@ type TVL @entity { Entity to iterate over suppliers """ type Supply @entity { - "SUPPLY" - id: ID! - suppliers: [SupplierAccount!]! @derivedFrom(field: "type") + "Token Address" + id: Bytes! + suppliers: [SupplierAccount!]! @derivedFrom(field: "token") } """ Entity to iterate over borrowers """ type Borrow @entity { - "BORROW" - id: ID! - borrowers: [BorrowerAccount!]! @derivedFrom(field: "type") + "Token Address" + id: Bytes! + borrowers: [BorrowerAccount!]! @derivedFrom(field: "token") } """ Supplier Account """ type SupplierAccount @entity { - "Account address" - id: ID! + "Account Address - Token Address" + id: Bytes! "Account address" address: Bytes! "Underlying balance" effective_balance: BigInt! - "SUPPLY" - type: Supply! + "Token Address" + token: Supply! } """ Borrower Account """ type BorrowerAccount @entity { - "Account address" - id: ID! + "Account Address - Token Address" + id: Bytes! "Account address" address: Bytes! "Underlying balance" effective_balance: BigInt! - "BORROW" - type: Borrow! + "Token Address" + token: Borrow! } diff --git a/subgraphs/etherfi-promo/src/constants/addresses.ts b/subgraphs/etherfi-promo/src/constants/addresses.ts index 4ba1cfef..9be493a3 100644 --- a/subgraphs/etherfi-promo/src/constants/addresses.ts +++ b/subgraphs/etherfi-promo/src/constants/addresses.ts @@ -1,7 +1,3 @@ import { Address } from '@graphprotocol/graph-ts'; -import { vWeEthAddress as vWeEthAddressString, weEthAddress as weEthAddressString } from './config'; - export const nullAddress = Address.fromString('0x0000000000000000000000000000000000000000'); -export const vWeEthAddress = Address.fromString(vWeEthAddressString); -export const weEthAddress = Address.fromString(weEthAddressString); diff --git a/subgraphs/etherfi-promo/src/constants/config-template b/subgraphs/etherfi-promo/src/constants/config-template deleted file mode 100644 index 8e22bb64..00000000 --- a/subgraphs/etherfi-promo/src/constants/config-template +++ /dev/null @@ -1,4 +0,0 @@ -// Use yarn prepare commands to generate config typescript file per env - -export const vWeEthAddress = '{{ vWeEthAddress }}'; -export const weEthAddress = '{{ weEthAddress }}'; diff --git a/subgraphs/etherfi-promo/src/constants/index.ts b/subgraphs/etherfi-promo/src/constants/index.ts index 232721a8..3afedd65 100644 --- a/subgraphs/etherfi-promo/src/constants/index.ts +++ b/subgraphs/etherfi-promo/src/constants/index.ts @@ -9,7 +9,3 @@ export const oneBigInt = BigInt.fromString('1'); export const mantissaFactor = 18; export const nullAddress = Address.fromString('0x0000000000000000000000000000000000000000'); - -export const SUPPLY = 'SUPPLY'; -export const BORROW = 'BORROW'; -export const TOTAL_VALUE_LOCKED = 'TOTAL_VALUE_LOCKED'; diff --git a/subgraphs/etherfi-promo/src/mappings/vToken.ts b/subgraphs/etherfi-promo/src/mappings/vToken.ts index 938e918c..8ebab350 100644 --- a/subgraphs/etherfi-promo/src/mappings/vToken.ts +++ b/subgraphs/etherfi-promo/src/mappings/vToken.ts @@ -1,51 +1,27 @@ import { Address } from '@graphprotocol/graph-ts'; -import { - AccrueInterest, - Borrow, - Mint, - Redeem, - RepayBorrow, - Transfer, -} from '../../generated/vWeETH/VToken'; +import { AccrueInterest, Borrow, Mint, Transfer } from '../../generated/vWeETH/VToken'; import { VToken as VTokenContract } from '../../generated/vWeETH/VToken'; import { nullAddress } from '../constants'; -import { vWeEthAddress } from '../constants/addresses'; -import { createBorrowerAccount, createSupplierAccount } from '../operations/create'; -import { getBorrow, getBorrowerAccount, getSupplierAccount, getSupply } from '../operations/get'; +import { getBorrow, getSupply } from '../operations/get'; +import { getOrCreateBorrowerAccount, getOrCreateSupplierAccount } from '../operations/getOrCreate'; import { updateBorrowerAccount, updateSupplierAccount, updateTvl } from '../operations/update'; import exponentToBigInt from '../utilities/exponentToBigInt'; export function handleMint(event: Mint): void { const minter = event.params.minter; - const supplierAccount = getSupplierAccount(minter); - if (supplierAccount) { - updateSupplierAccount(minter, supplierAccount.effective_balance.plus(event.params.mintAmount)); - } else { - createSupplierAccount(minter, event.params.mintAmount); - } -} - -export function handleRedeem(event: Redeem): void { - const redeemer = event.params.redeemer; - const supplierAccount = getSupplierAccount(redeemer)!; + const supplierAccount = getOrCreateSupplierAccount(minter, event.address); updateSupplierAccount( - redeemer, - supplierAccount.effective_balance.minus(event.params.redeemAmount), + minter, + event.address, + supplierAccount.effective_balance.plus(event.params.mintAmount), ); } export function handleBorrow(event: Borrow): void { const borrower = event.params.borrower; - const borrowerAccount = getBorrowerAccount(borrower); - if (!borrowerAccount) { - createBorrowerAccount(borrower, event.params.accountBorrows); - } -} - -export function handleRepayBorrow(event: RepayBorrow): void { - const borrower = event.params.borrower; - updateBorrowerAccount(borrower, event.params.accountBorrows); + getOrCreateBorrowerAccount(borrower, event.address); + updateBorrowerAccount(borrower, event.address, event.params.accountBorrows); } export function handleTransfer(event: Transfer): void { @@ -55,32 +31,37 @@ export function handleTransfer(event: Transfer): void { // If the to account is the vToken address we assume it was a redeem const toAccountAddress = event.params.to; - if (fromAccountAddress != nullAddress && fromAccountAddress != event.address) { + if ( + fromAccountAddress.notEqual(event.address) && + fromAccountAddress.notEqual(nullAddress) && + toAccountAddress.notEqual(event.address) + ) { const vTokenContract = VTokenContract.bind(event.address); const exchangeRateMantissa = vTokenContract.exchangeRateCurrent(); const amountUnderlying = exchangeRateMantissa .times(event.params.amount) .div(exponentToBigInt(18)); - const fromAccount = getSupplierAccount(fromAccountAddress)!; + const fromAccount = getOrCreateSupplierAccount(fromAccountAddress, event.address); updateSupplierAccount( fromAccountAddress, + event.address, fromAccount.effective_balance.minus(amountUnderlying), ); // To - const toAccount = getSupplierAccount(toAccountAddress); - if (toAccount) { - updateSupplierAccount(toAccountAddress, toAccount.effective_balance.plus(amountUnderlying)); - } else if (toAccountAddress != event.address) { - createSupplierAccount(toAccountAddress, amountUnderlying); - } + const toAccount = getOrCreateSupplierAccount(toAccountAddress, event.address); + updateSupplierAccount( + toAccountAddress, + event.address, + toAccount.effective_balance.plus(amountUnderlying), + ); } } // eslint-disable-next-line @typescript-eslint/no-unused-vars export function handleAccrueInterest(event: AccrueInterest): void { - const supply = getSupply(); + const supply = getSupply(event.address); supply.suppliers.load().forEach(supplier => { - const vTokenContract = VTokenContract.bind(vWeEthAddress); + const vTokenContract = VTokenContract.bind(Address.fromBytes(supplier.token)); const exchangeRateMantissa = vTokenContract.exchangeRateCurrent(); const vTokenBalance = vTokenContract.balanceOf(Address.fromBytes(supplier.address)); @@ -89,15 +70,15 @@ export function handleAccrueInterest(event: AccrueInterest): void { supplier.save(); }); - const borrow = getBorrow(); + const borrow = getBorrow(event.address); borrow.borrowers.load().forEach(borrower => { - const vTokenContract = VTokenContract.bind(vWeEthAddress); - const underlyingBorrowBalance = vTokenContract.borrowBalanceStored( + const vTokenContract = VTokenContract.bind(Address.fromBytes(borrower.token)); + const underlyingBorrowBalance = vTokenContract.borrowBalanceCurrent( Address.fromBytes(borrower.address), ); borrower.effective_balance = underlyingBorrowBalance; borrower.save(); }); - updateTvl(); + updateTvl(event); } diff --git a/subgraphs/etherfi-promo/src/operations/create.ts b/subgraphs/etherfi-promo/src/operations/create.ts index 9324c7b4..3cc4e9af 100644 --- a/subgraphs/etherfi-promo/src/operations/create.ts +++ b/subgraphs/etherfi-promo/src/operations/create.ts @@ -1,22 +1,30 @@ import { Address, BigInt } from '@graphprotocol/graph-ts'; import { BorrowerAccount, SupplierAccount } from '../../generated/schema'; -import { getBorrow, getSupply } from './get'; +import { getPositionId } from '../utilities/ids'; -export function createSupplierAccount(accountAddress: Address, amount: BigInt): SupplierAccount { - const account = new SupplierAccount(accountAddress.toHexString()); +export function createSupplierAccount( + accountAddress: Address, + tokenAddress: Address, + amount: BigInt, +): SupplierAccount { + const account = new SupplierAccount(getPositionId(accountAddress, tokenAddress)); account.address = accountAddress; account.effective_balance = amount; - account.type = getSupply().id; + account.token = tokenAddress; account.save(); return account; } -export function createBorrowerAccount(accountAddress: Address, amount: BigInt): BorrowerAccount { - const account = new BorrowerAccount(accountAddress.toHexString()); +export function createBorrowerAccount( + accountAddress: Address, + tokenAddress: Address, + amount: BigInt, +): BorrowerAccount { + const account = new BorrowerAccount(getPositionId(accountAddress, tokenAddress)); account.address = accountAddress; account.effective_balance = amount; - account.type = getBorrow().id; + account.token = tokenAddress; account.save(); return account; } diff --git a/subgraphs/etherfi-promo/src/operations/get.ts b/subgraphs/etherfi-promo/src/operations/get.ts index c9e93204..ad7d214c 100644 --- a/subgraphs/etherfi-promo/src/operations/get.ts +++ b/subgraphs/etherfi-promo/src/operations/get.ts @@ -1,12 +1,13 @@ import { Address } from '@graphprotocol/graph-ts'; import { Borrow, BorrowerAccount, SupplierAccount, Supply, TVL } from '../../generated/schema'; -import { BORROW, SUPPLY, TOTAL_VALUE_LOCKED, zeroBigInt32 } from '../constants'; +import { zeroBigInt32 } from '../constants'; +import { getPositionId } from '../utilities/ids'; -export const getTvl = (): TVL => { - let tvl = TVL.load(TOTAL_VALUE_LOCKED); +export const getTvl = (vTokenAddress: Address): TVL => { + let tvl = TVL.load(vTokenAddress); if (!tvl) { - tvl = new TVL(TOTAL_VALUE_LOCKED); + tvl = new TVL(vTokenAddress); tvl.tvl = zeroBigInt32; tvl.save(); } @@ -14,30 +15,36 @@ export const getTvl = (): TVL => { return tvl; }; -export const getSupply = (): Supply => { - let supply = Supply.load(SUPPLY); +export const getSupply = (tokenAddress: Address): Supply => { + let supply = Supply.load(tokenAddress); if (!supply) { - supply = new Supply(SUPPLY); + supply = new Supply(tokenAddress); } supply.save(); return supply; }; -export const getSupplierAccount = (accountAddress: Address): SupplierAccount | null => { - const supplierAccount = SupplierAccount.load(accountAddress.toHexString()); +export const getSupplierAccount = ( + accountAddress: Address, + tokenAddress: Address, +): SupplierAccount | null => { + const supplierAccount = SupplierAccount.load(getPositionId(accountAddress, tokenAddress)); return supplierAccount; }; -export const getBorrow = (): Borrow => { - let borrow = Borrow.load(BORROW); +export const getBorrow = (tokenAddress: Address): Borrow => { + let borrow = Borrow.load(tokenAddress); if (!borrow) { - borrow = new Borrow(BORROW); + borrow = new Borrow(tokenAddress); } borrow.save(); return borrow; }; -export const getBorrowerAccount = (accountAddress: Address): BorrowerAccount | null => { - const borrowerAccount = BorrowerAccount.load(accountAddress.toHexString()); +export const getBorrowerAccount = ( + accountAddress: Address, + tokenAddress: Address, +): BorrowerAccount | null => { + const borrowerAccount = BorrowerAccount.load(getPositionId(accountAddress, tokenAddress)); return borrowerAccount; }; diff --git a/subgraphs/etherfi-promo/src/operations/getOrCreate.ts b/subgraphs/etherfi-promo/src/operations/getOrCreate.ts new file mode 100644 index 00000000..56858653 --- /dev/null +++ b/subgraphs/etherfi-promo/src/operations/getOrCreate.ts @@ -0,0 +1,38 @@ +import { Address } from '@graphprotocol/graph-ts'; + +import { BorrowerAccount, SupplierAccount } from '../../generated/schema'; +import { zeroBigInt32 } from '../constants'; +import { getBorrow, getSupply } from '../operations/get'; +import { getPositionId } from '../utilities/ids'; + +export const getOrCreateSupplierAccount = ( + accountAddress: Address, + tokenAddress: Address, +): SupplierAccount => { + let supplierAccount = SupplierAccount.load(getPositionId(accountAddress, tokenAddress)); + if (!supplierAccount) { + const supply = getSupply(tokenAddress); + supplierAccount = new SupplierAccount(getPositionId(accountAddress, tokenAddress)); + supplierAccount.address = accountAddress; + supplierAccount.effective_balance = zeroBigInt32; + supplierAccount.token = supply.id; + supplierAccount.save(); + } + return supplierAccount; +}; + +export const getOrCreateBorrowerAccount = ( + accountAddress: Address, + tokenAddress: Address, +): BorrowerAccount => { + let borrowerAccount = BorrowerAccount.load(getPositionId(accountAddress, tokenAddress)); + if (!borrowerAccount) { + const borrow = getBorrow(tokenAddress); + borrowerAccount = new BorrowerAccount(getPositionId(accountAddress, tokenAddress)); + borrowerAccount.address = accountAddress; + borrowerAccount.effective_balance = zeroBigInt32; + borrowerAccount.token = borrow.id; + borrowerAccount.save(); + } + return borrowerAccount; +}; diff --git a/subgraphs/etherfi-promo/src/operations/update.ts b/subgraphs/etherfi-promo/src/operations/update.ts index b1de2277..ffdc4ab0 100644 --- a/subgraphs/etherfi-promo/src/operations/update.ts +++ b/subgraphs/etherfi-promo/src/operations/update.ts @@ -1,32 +1,40 @@ -import { Address, BigInt } from '@graphprotocol/graph-ts'; +import { Address, BigInt, ethereum } from '@graphprotocol/graph-ts'; import { BorrowerAccount, SupplierAccount, TVL } from '../../generated/schema'; import { ERC20 as ERC20Contract } from '../../generated/vWeETH/ERC20'; import { VToken as VTokenContract } from '../../generated/vWeETH/VToken'; -import { vWeEthAddress, weEthAddress } from '../constants/addresses'; import { getBorrowerAccount, getSupplierAccount, getTvl } from './get'; -export function updateSupplierAccount(accountAddress: Address, amount: BigInt): SupplierAccount { - const account = getSupplierAccount(accountAddress)!; +export function updateSupplierAccount( + accountAddress: Address, + tokenAddress: Address, + amount: BigInt, +): SupplierAccount { + const account = getSupplierAccount(accountAddress, tokenAddress)!; account.effective_balance = amount; account.save(); return account; } -export function updateBorrowerAccount(accountAddress: Address, amount: BigInt): BorrowerAccount { - const account = getBorrowerAccount(accountAddress)!; +export function updateBorrowerAccount( + accountAddress: Address, + tokenAddress: Address, + amount: BigInt, +): BorrowerAccount { + const account = getBorrowerAccount(accountAddress, tokenAddress)!; account.effective_balance = amount; account.save(); return account; } -export function updateTvl(): TVL { - const vTokenContract = VTokenContract.bind(vWeEthAddress); - const weEthContract = ERC20Contract.bind(weEthAddress); - const tvl = getTvl(); - const totalBorrows = vTokenContract.totalBorrows(); +export function updateTvl(event: ethereum.Event): TVL { + const vTokenContract = VTokenContract.bind(event.address); + const underlyingAddress = vTokenContract.underlying(); + const underlyingContract = ERC20Contract.bind(underlyingAddress); + const tvl = getTvl(event.address); + const totalBorrows = vTokenContract.totalBorrowsCurrent(); const totalReserves = vTokenContract.totalReserves(); - const vTokenContractBalance = weEthContract.balanceOf(vWeEthAddress); + const vTokenContractBalance = underlyingContract.balanceOf(event.address); tvl.tvl = vTokenContractBalance.plus(totalBorrows).minus(totalReserves); tvl.save(); return tvl; diff --git a/subgraphs/etherfi-promo/src/utilities/ids.ts b/subgraphs/etherfi-promo/src/utilities/ids.ts new file mode 100644 index 00000000..8d4f5f07 --- /dev/null +++ b/subgraphs/etherfi-promo/src/utilities/ids.ts @@ -0,0 +1,4 @@ +import { Address, Bytes } from '@graphprotocol/graph-ts'; + +export const getPositionId = (accountAddress: Address, tokenAddress: Address): Bytes => + accountAddress.concat(tokenAddress); diff --git a/subgraphs/etherfi-promo/subgraph-client/.graphclientrc.yml b/subgraphs/etherfi-promo/subgraph-client/.graphclientrc.yml index 63108654..ffabbc9c 100644 --- a/subgraphs/etherfi-promo/subgraph-client/.graphclientrc.yml +++ b/subgraphs/etherfi-promo/subgraph-client/.graphclientrc.yml @@ -2,7 +2,7 @@ sources: - name: venus-etherfi-promo-sepolia handler: graphql: - endpoint: https://api.studio.thegraph.com/query/51310/venus-etherfi-promo-sepolia/version/latest + endpoint: http://127.0.0.1:8000/subgraphs/name/venusprotocol/etherfi-promo documents: - '../**/*.graphql' diff --git a/subgraphs/etherfi-promo/subgraph-client/index.ts b/subgraphs/etherfi-promo/subgraph-client/index.ts index 8846ce59..a2fe29a9 100644 --- a/subgraphs/etherfi-promo/subgraph-client/index.ts +++ b/subgraphs/etherfi-promo/subgraph-client/index.ts @@ -1,7 +1,7 @@ import { DocumentNode } from 'graphql'; -import { Client as UrqlClient, createClient } from 'urql/core'; +import { OperationResult, Client as UrqlClient, createClient } from 'urql/core'; -import { AccountsDocument } from './.graphclient'; +import { AccountsDocument, AccountsQuery } from './.graphclient'; class SubgraphClient { urqlClient: UrqlClient; @@ -21,8 +21,16 @@ class SubgraphClient { return result; } - async getAccounts(blockNumber: number) { - const result = await this.query(AccountsDocument, { blockNumber }); + async getAccounts( + blockNumber: number, + token: string, + tokenId: string, + ): Promise> { + const result = await this.query(AccountsDocument, { + blockNumber, + token: token.toLowerCase(), + tokenId: tokenId.toLowerCase(), + }); return result; } } diff --git a/subgraphs/etherfi-promo/subgraph-client/queries/accountsQuery.graphql b/subgraphs/etherfi-promo/subgraph-client/queries/accountsQuery.graphql index 5e521f7a..35c37c52 100644 --- a/subgraphs/etherfi-promo/subgraph-client/queries/accountsQuery.graphql +++ b/subgraphs/etherfi-promo/subgraph-client/queries/accountsQuery.graphql @@ -1,15 +1,21 @@ -query Accounts($blockNumber: Int) { - supplierAccounts(block:{number: $blockNumber}) { +query Accounts($blockNumber: Int, $token: String, $tokenId: ID!) { + supplierAccounts(block:{number: $blockNumber}, where: {token: $token}) { id address effective_balance + token { + id + } } - borrowerAccounts(block:{number: $blockNumber}) { + borrowerAccounts(block:{number: $blockNumber}, where: {token: $token}) { id address effective_balance + token { + id + } } - tvl(block:{number: $blockNumber}, id: "TOTAL_VALUE_LOCKED") { + tvl(block:{number: $blockNumber}, id: $tokenId) { tvl } } diff --git a/subgraphs/etherfi-promo/template.yaml b/subgraphs/etherfi-promo/template.yaml index 2f5d802c..51d87e18 100644 --- a/subgraphs/etherfi-promo/template.yaml +++ b/subgraphs/etherfi-promo/template.yaml @@ -10,10 +10,39 @@ dataSources: source: address: "{{ vWeEthAddress }}" abi: VToken - startBlock: {{ startBlock }} + startBlock: {{ vWeEthStartBlock }} mapping: kind: ethereum/events - apiVersion: 0.0.5 + apiVersion: 0.0.9 + language: wasm/assemblyscript + file: ./src/mappings/vToken.ts + entities: + - SupplierAccount + - BorrowerAccount + abis: + - name: VToken + file: ../../node_modules/@venusprotocol/isolated-pools/artifacts/contracts/VToken.sol/VToken.json + - name: ERC20 + file: ../../node_modules/@venusprotocol/isolated-pools/artifacts/contracts/test/ERC20.sol/ERC20.json + eventHandlers: + - event: Mint(indexed address,uint256,uint256,uint256) + handler: handleMint + - event: Borrow(indexed address,uint256,uint256,uint256) + handler: handleBorrow + - event: Transfer(indexed address,indexed address,uint256) + handler: handleTransfer + - event: AccrueInterest(uint256,uint256,uint256,uint256) + handler: handleAccrueInterest + - kind: ethereum/contract + name: vWeETHs + network: {{ network }} + source: + address: "{{ vWeEthsAddress }}" + abi: VToken + startBlock: {{ vWeEthsStartBlock }} + mapping: + kind: ethereum/events + apiVersion: 0.0.9 language: wasm/assemblyscript file: ./src/mappings/vToken.ts entities: @@ -27,12 +56,8 @@ dataSources: eventHandlers: - event: Mint(indexed address,uint256,uint256,uint256) handler: handleMint - - event: Redeem(indexed address,uint256,uint256,uint256) - handler: handleRedeem - event: Borrow(indexed address,uint256,uint256,uint256) handler: handleBorrow - - event: RepayBorrow(indexed address,indexed address,uint256,uint256,uint256) - handler: handleRepayBorrow - event: Transfer(indexed address,indexed address,uint256) handler: handleTransfer - event: AccrueInterest(uint256,uint256,uint256,uint256) diff --git a/subgraphs/etherfi-promo/tests/VToken/events.ts b/subgraphs/etherfi-promo/tests/VToken/events.ts index c23c622c..62a89620 100644 --- a/subgraphs/etherfi-promo/tests/VToken/events.ts +++ b/subgraphs/etherfi-promo/tests/VToken/events.ts @@ -5,8 +5,6 @@ import { AccrueInterest as AccrueInterestEvent, Borrow as BorrowEvent, Mint as MintEvent, - Redeem as RedeemEvent, - RepayBorrow as RepayBorrowEvent, Transfer as TransferEvent, } from '../../generated/vWeETH/VToken'; @@ -45,44 +43,6 @@ export const createMintEvent = ( return event; }; -export const createRedeemEvent = ( - vTokenAddress: Address, - redeemerAddress: Address, - redeemAmount: BigInt, - redeemTokens: BigInt, - accountBalance: BigInt, -): RedeemEvent => { - const event = changetype(newMockEvent()); - event.address = vTokenAddress; - event.parameters = []; - - const redeemerParam = new ethereum.EventParam( - 'redeemer', - ethereum.Value.fromAddress(redeemerAddress), - ); - event.parameters.push(redeemerParam); - - const redeemAmountParam = new ethereum.EventParam( - 'redeemAmount', - ethereum.Value.fromUnsignedBigInt(redeemAmount), - ); - event.parameters.push(redeemAmountParam); - - const redeemTokensParam = new ethereum.EventParam( - 'redeemTokens', - ethereum.Value.fromUnsignedBigInt(redeemTokens), - ); - event.parameters.push(redeemTokensParam); - - const accountBalanceParam = new ethereum.EventParam( - 'accountBalance', - ethereum.Value.fromUnsignedBigInt(accountBalance), - ); - event.parameters.push(accountBalanceParam); - - return event; -}; - export const createBorrowEvent = ( vTokenAddress: Address, borrowerAddress: Address, @@ -121,48 +81,6 @@ export const createBorrowEvent = ( return event; }; -export const createRepayBorrowEvent = ( - vTokenAddress: Address, - payerAddress: Address, - borrowerAddress: Address, - repayAmount: BigInt, - accountBorrows: BigInt, - totalBorrows: BigInt, -): RepayBorrowEvent => { - const event = changetype(newMockEvent()); - event.address = vTokenAddress; - event.parameters = []; - - const payerParam = new ethereum.EventParam('payer', ethereum.Value.fromAddress(payerAddress)); - event.parameters.push(payerParam); - - const borrowerParam = new ethereum.EventParam( - 'borrower', - ethereum.Value.fromAddress(borrowerAddress), - ); - event.parameters.push(borrowerParam); - - const repayAmountParam = new ethereum.EventParam( - 'repayAmount', - ethereum.Value.fromUnsignedBigInt(repayAmount), - ); - event.parameters.push(repayAmountParam); - - const accountBorrowsParam = new ethereum.EventParam( - 'accountBorrows', - ethereum.Value.fromUnsignedBigInt(accountBorrows), - ); - event.parameters.push(accountBorrowsParam); - - const totalBorrowsParam = new ethereum.EventParam( - 'totalBorrows', - ethereum.Value.fromUnsignedBigInt(totalBorrows), - ); - event.parameters.push(totalBorrowsParam); - - return event; -}; - export const createAccrueInterestEvent = ( vTokenAddress: Address, cashPrior: BigInt, diff --git a/subgraphs/etherfi-promo/tests/VToken/index.test.ts b/subgraphs/etherfi-promo/tests/VToken/index.test.ts index 2365b26a..334d8685 100644 --- a/subgraphs/etherfi-promo/tests/VToken/index.test.ts +++ b/subgraphs/etherfi-promo/tests/VToken/index.test.ts @@ -9,22 +9,18 @@ import { } from 'matchstick-as/assembly/index'; import { zeroBigInt32 } from '../../src/constants'; -import { vWeEthAddress, weEthAddress } from '../../src/constants/addresses'; import { handleAccrueInterest, handleBorrow, handleMint, - handleRedeem, - handleRepayBorrow, handleTransfer, } from '../../src/mappings/vToken'; import exponentToBigInt from '../../src/utilities/exponentToBigInt'; +import { getPositionId } from '../../src/utilities/ids'; import { createAccrueInterestEvent, createBorrowEvent, createMintEvent, - createRedeemEvent, - createRepayBorrowEvent, createTransferEvent, } from './events'; import { createAccountVTokenBalanceOfMock, createBep20Mock, createVBep20Mock } from './mocks'; @@ -32,8 +28,8 @@ import { createAccountVTokenBalanceOfMock, createBep20Mock, createVBep20Mock } f const user1Address = Address.fromString('0x0000000000000000000000000000000000000101'); const user2Address = Address.fromString('0x0000000000000000000000000000000000000202'); const exchangeRateCurrent = BigInt.fromU64(2000000000000000000); -const vTokenAddress = vWeEthAddress; -const underlyingAddress = weEthAddress; +const vTokenAddress = Address.fromString('0xB3A201887396F57bad3fF50DFd02022fE1Fd1774'); +const underlyingAddress = Address.fromString('0x3b8b6E96e57f0d1cD366AaCf4CcC68413aF308D0'); const cleanup = (): void => { clearStore(); @@ -63,48 +59,18 @@ describe('VToken', () => { handleMint(mintEvent); - assert.fieldEquals('SupplierAccount', minter.toHexString(), 'address', minter.toHexString()); assert.fieldEquals( 'SupplierAccount', + getPositionId(minter, vTokenAddress).toHexString(), + 'address', minter.toHexString(), - 'effective_balance', - actualMintAmount.toString(), - ); - }); - - test('registers redeem event', () => { - /** Constants */ - const redeemer = user2Address; - const actualRedeemAmount = BigInt.fromString('5000000000000000000'); - const redeemTokens = BigInt.fromString('25000000000000000000'); - const accountBalance = zeroBigInt32; - /** Setup test */ - const redeemEvent = createRedeemEvent( - vTokenAddress, - redeemer, - actualRedeemAmount, - redeemTokens, - accountBalance, ); - const mintEvent = createMintEvent( - vTokenAddress, - redeemer, - actualRedeemAmount, - redeemTokens, - accountBalance, - ); - - handleMint(mintEvent); - - /** Fire Event */ - handleRedeem(redeemEvent); assert.fieldEquals( 'SupplierAccount', - redeemer.toHexString(), - 'address', - redeemer.toHexString(), + getPositionId(minter, vTokenAddress).toHexString(), + 'effective_balance', + actualMintAmount.toString(), ); - assert.fieldEquals('SupplierAccount', redeemer.toHexString(), 'effective_balance', '0'); }); test('registers borrow event', () => { @@ -128,58 +94,13 @@ describe('VToken', () => { assert.fieldEquals( 'BorrowerAccount', - borrower.toHexString(), - 'address', - borrower.toHexString(), - ); - assert.fieldEquals( - 'BorrowerAccount', - borrower.toHexString(), - 'effective_balance', - accountBorrows.toString(), - ); - }); - - test('registers repay borrow event', () => { - /** Constants */ - const borrower = user1Address; - const payer = user1Address; - const borrowAmount = BigInt.fromString('2000000000000000000'); - const accountBorrows = BigInt.fromString('4000000000000000000'); - const totalBorrows = BigInt.fromString('80000000000000000000'); - - /** Setup test */ - const borrowEvent = createBorrowEvent( - vTokenAddress, - borrower, - borrowAmount, - accountBorrows, - totalBorrows, - ); - - /** Fire Event */ - handleBorrow(borrowEvent); - const repayBorrowEvent = createRepayBorrowEvent( - vTokenAddress, - payer, - borrower, - borrowAmount, - accountBorrows, - totalBorrows, - ); - - /** Fire Event */ - handleRepayBorrow(repayBorrowEvent); - - assert.fieldEquals( - 'BorrowerAccount', - borrower.toHexString(), + getPositionId(borrower, vTokenAddress).toHexString(), 'address', borrower.toHexString(), ); assert.fieldEquals( 'BorrowerAccount', - borrower.toHexString(), + getPositionId(borrower, vTokenAddress).toHexString(), 'effective_balance', accountBorrows.toString(), ); @@ -223,6 +144,7 @@ describe('VToken', () => { createBep20Mock(underlyingAddress, vTokenAddress, cashPrior); createAccountVTokenBalanceOfMock( vTokenAddress, + underlyingAddress, user1Address, zeroBigInt32, accountBorrows, @@ -231,6 +153,7 @@ describe('VToken', () => { ); createAccountVTokenBalanceOfMock( vTokenAddress, + underlyingAddress, user2Address, zeroBigInt32, accountBorrows, @@ -254,21 +177,26 @@ describe('VToken', () => { assert.fieldEquals( 'SupplierAccount', - user1Address.toHexString(), + getPositionId(user1Address, vTokenAddress).toHexString(), 'address', user1Address.toHexString(), ); - assert.fieldEquals('SupplierAccount', user1Address.toHexString(), 'effective_balance', '0'); + assert.fieldEquals( + 'SupplierAccount', + getPositionId(user1Address, vTokenAddress).toHexString(), + 'effective_balance', + '0', + ); assert.fieldEquals( 'BorrowerAccount', - user2Address.toHexString(), + getPositionId(user2Address, vTokenAddress).toHexString(), 'address', user2Address.toHexString(), ); assert.fieldEquals( 'BorrowerAccount', - user2Address.toHexString(), + getPositionId(user2Address, vTokenAddress).toHexString(), 'effective_balance', accountBorrows.toString(), ); @@ -299,18 +227,28 @@ describe('VToken', () => { handleTransfer(transferEvent); const underlyingAmount = exchangeRateCurrent.times(amount).div(exponentToBigInt(18)); - assert.fieldEquals('SupplierAccount', from.toHexString(), 'address', from.toHexString()); assert.fieldEquals( 'SupplierAccount', + getPositionId(from, vTokenAddress).toHexString(), + 'address', from.toHexString(), + ); + assert.fieldEquals( + 'SupplierAccount', + getPositionId(from, vTokenAddress).toHexString(), 'effective_balance', actualMintAmount.minus(underlyingAmount).toString(), ); - assert.fieldEquals('SupplierAccount', to.toHexString(), 'address', to.toHexString()); assert.fieldEquals( 'SupplierAccount', + getPositionId(to, vTokenAddress).toHexString(), + 'address', to.toHexString(), + ); + assert.fieldEquals( + 'SupplierAccount', + getPositionId(to, vTokenAddress).toHexString(), 'effective_balance', underlyingAmount.toString(), ); diff --git a/subgraphs/etherfi-promo/tests/VToken/mocks.ts b/subgraphs/etherfi-promo/tests/VToken/mocks.ts index af702bec..5fe00d0a 100644 --- a/subgraphs/etherfi-promo/tests/VToken/mocks.ts +++ b/subgraphs/etherfi-promo/tests/VToken/mocks.ts @@ -25,9 +25,10 @@ export const createBep20Mock = ( export const createAccountVTokenBalanceOfMock = ( vTokenAddress: Address, + underlyingAddress: Address, accountAddress: Address, balance: BigInt, - borrowBalanceStored: BigInt, + borrowBalanceCurrent: BigInt, totalBorrows: BigInt, totalReserves: BigInt, ): void => { @@ -35,19 +36,25 @@ export const createAccountVTokenBalanceOfMock = ( .withArgs([ethereum.Value.fromAddress(accountAddress)]) .returns([ethereum.Value.fromSignedBigInt(balance)]); - createMockedFunction(vTokenAddress, 'totalBorrows', 'totalBorrows():(uint256)').returns([ - ethereum.Value.fromSignedBigInt(totalBorrows), - ]); + createMockedFunction( + vTokenAddress, + 'totalBorrowsCurrent', + 'totalBorrowsCurrent():(uint256)', + ).returns([ethereum.Value.fromSignedBigInt(totalBorrows)]); createMockedFunction(vTokenAddress, 'totalReserves', 'totalReserves():(uint256)').returns([ ethereum.Value.fromSignedBigInt(totalReserves), ]); + createMockedFunction(vTokenAddress, 'underlying', 'underlying():(address)').returns([ + ethereum.Value.fromAddress(underlyingAddress), + ]); + createMockedFunction( vTokenAddress, - 'borrowBalanceStored', - 'borrowBalanceStored(address):(uint256)', + 'borrowBalanceCurrent', + 'borrowBalanceCurrent(address):(uint256)', ) .withArgs([ethereum.Value.fromAddress(accountAddress)]) - .returns([ethereum.Value.fromUnsignedBigInt(borrowBalanceStored)]); + .returns([ethereum.Value.fromUnsignedBigInt(borrowBalanceCurrent)]); }; diff --git a/subgraphs/etherfi-promo/tests/invariant.ts b/subgraphs/etherfi-promo/tests/invariant.ts index d6f30d2a..1d98f0e6 100644 --- a/subgraphs/etherfi-promo/tests/invariant.ts +++ b/subgraphs/etherfi-promo/tests/invariant.ts @@ -2,18 +2,46 @@ import assert from 'assert'; import subgraphClient from '../subgraph-client'; -const main = async () => { - const { data } = await subgraphClient.getAccounts(19738555); +const weEths = '0xEF26C64bC06A8dE4CA5D31f119835f9A1d9433b9'; +const weEth = '0xb4933AF59868986316Ed37fa865C829Eba2df0C7'; + +const checkWeEth = async () => { + const { data } = await subgraphClient.getAccounts(20679412, weEth, weEth); + + const supplierBalanceSum = data!.supplierAccounts.reduce( + (acc: BigInt, curr: { effective_balance: string }) => { + return BigInt(acc.toString()) + BigInt(curr.effective_balance); + }, + BigInt(0), + ); - const supplierBalanceSum = data.supplierAccounts.reduce( + const inRange = (num: bigint) => num >= -10000000000n && num <= 10000000000n; + assert.ok( + inRange(BigInt(data!.tvl!.tvl) - (supplierBalanceSum as bigint)), + `TVL: ${data!.tvl!.tvl} supplierBalanceSum: ${supplierBalanceSum}`, + ); +}; + +const checkWeEths = async () => { + const { data } = await subgraphClient.getAccounts(20679412, weEths, weEths); + + const supplierBalanceSum = data!.supplierAccounts.reduce( (acc: BigInt, curr: { effective_balance: string }) => { return BigInt(acc.toString()) + BigInt(curr.effective_balance); }, BigInt(0), ); - const inRange = (num: bigint) => num >= -5000n && num <= 5000n; - assert.ok(inRange(BigInt(data.tvl.tvl) - supplierBalanceSum)); + const inRange = (num: bigint) => num >= -10000000000n && num <= 10000000000n; + assert.ok( + inRange(BigInt(data!.tvl!.tvl) - (supplierBalanceSum as bigint)), + `TVL: ${data!.tvl!.tvl} supplierBalanceSum: ${supplierBalanceSum}`, + ); +}; + +const main = async () => { + await checkWeEth(); + await checkWeEths(); }; export default main(); diff --git a/yarn.lock b/yarn.lock index 3ca5ba29..53ba6887 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1662,8 +1662,8 @@ __metadata: linkType: hard "@graphprotocol/graph-cli@npm:^0.80.0": - version: 0.80.1 - resolution: "@graphprotocol/graph-cli@npm:0.80.1" + version: 0.80.0 + resolution: "@graphprotocol/graph-cli@npm:0.80.0" dependencies: "@float-capital/float-subgraph-uncrashable": ^0.0.0-alpha.4 "@oclif/core": 2.8.6 @@ -1695,7 +1695,7 @@ __metadata: yaml: 1.10.2 bin: graph: bin/run - checksum: 2984d504a1bd94767c076455cf2a363b0e7e37bd1ba646ad180f2df51fbb053c3fe39255088145dbbfec78b750fd022090362114d66ab954c620299b8af8c597 + checksum: 072244e374f832fd0cae1dd301c3e64e2cf8a71be585b6a373dc5d207a3cca7cad0d104bacb3a161161490fba4636d47c7e1dd946abfd710d6587513942a2443 languageName: node linkType: hard @@ -4416,9 +4416,9 @@ __metadata: languageName: node linkType: hard -"@venusprotocol/isolated-pools@npm:3.3.0": - version: 3.3.0 - resolution: "@venusprotocol/isolated-pools@npm:3.3.0" +"@venusprotocol/isolated-pools@npm:3.5.0-dev.10": + version: 3.5.0-dev.10 + resolution: "@venusprotocol/isolated-pools@npm:3.5.0-dev.10" dependencies: "@nomiclabs/hardhat-ethers": ^2.2.3 "@openzeppelin/contracts": ^4.8.3 @@ -4429,24 +4429,7 @@ __metadata: ethers: ^5.7.0 hardhat-deploy: ^0.11.14 module-alias: ^2.2.2 - checksum: e6d92426500eaa6874fc57d532bd4dfbb57263810dbf1f863308f4c9faa1372839b003657c9a1945f074acaac55712caad41e0f920d7765e6c6e85712fb6eca1 - languageName: node - linkType: hard - -"@venusprotocol/isolated-pools@npm:3.5.0-dev.3": - version: 3.5.0-dev.3 - resolution: "@venusprotocol/isolated-pools@npm:3.5.0-dev.3" - dependencies: - "@nomiclabs/hardhat-ethers": ^2.2.3 - "@openzeppelin/contracts": ^4.8.3 - "@openzeppelin/contracts-upgradeable": ^4.8.3 - "@openzeppelin/hardhat-upgrades": ^1.21.0 - "@solidity-parser/parser": ^0.13.2 - "@venusprotocol/solidity-utilities": ^2.0.0 - ethers: ^5.7.0 - hardhat-deploy: ^0.11.14 - module-alias: ^2.2.2 - checksum: ed5bdb02fcf7bb2716601f47c41649834e944629bef288395d1410e7a954772324ab7409cdb16da2212518ec19cb70487ec829fc213e2083c5b01c07e9c28eec + checksum: 5cb5b050cdabb79227ad512f2f1a1ad103bb6e658b3dd8c8a96cc309dbf1d080dacd53f0cdf1dc2cccdee26913435d855740b0296b62c308eb7082e0f79cdc4f languageName: node linkType: hard @@ -7535,8 +7518,8 @@ __metadata: version: 0.0.0-use.local resolution: "etherfi-promo-subgraph@workspace:subgraphs/etherfi-promo" dependencies: - "@graphprotocol/graph-cli": ^0.77.0 - "@venusprotocol/isolated-pools": 3.3.0 + "@graphprotocol/graph-cli": ^0.80.0 + "@venusprotocol/isolated-pools": 3.5.0-dev.10 ts-node: ^10.9.2 viem: ^2.9.26 languageName: unknown @@ -13157,7 +13140,7 @@ __metadata: dependencies: "@chainlink/contracts": ^0.5.1 "@graphprotocol/client-cli": 3.0.0 - "@graphprotocol/graph-cli": ^0.77.0 + "@graphprotocol/graph-cli": ^0.80.0 "@graphprotocol/graph-ts": ^0.35.1 "@layerzerolabs/solidity-examples": ^1.1.0 "@nomicfoundation/hardhat-chai-matchers": ^1.0.3 @@ -13173,7 +13156,7 @@ __metadata: "@typescript-eslint/eslint-plugin": ^5.40.1 "@typescript-eslint/parser": ^5.40.1 "@venusprotocol/governance-contracts": 2.3.0-dev.4 - "@venusprotocol/isolated-pools": 3.5.0-dev.3 + "@venusprotocol/isolated-pools": 3.5.0-dev.10 "@venusprotocol/oracle": 2.2.0 "@venusprotocol/protocol-reserve": 2.3.0-dev.1 "@venusprotocol/solidity-utilities": ^2.0.3 From 29acca50dcf214c2d11361930b0a1d65b8a87e21 Mon Sep 17 00:00:00 2001 From: Corey Rice Date: Fri, 6 Sep 2024 13:40:19 -0300 Subject: [PATCH 2/2] refactor: save units as tokens --- subgraphs/etherfi-promo/package.json | 2 +- subgraphs/etherfi-promo/schema.graphql | 4 +-- .../etherfi-promo/src/mappings/vToken.ts | 26 ++++++++++++++----- .../src/operations/getOrCreate.ts | 6 ++--- .../etherfi-promo/src/operations/update.ts | 6 ++--- .../src/utilities/exponentToBigDecimal.ts | 11 ++++++++ .../etherfi-promo/tests/VToken/index.test.ts | 15 +++++++---- yarn.lock | 17 ++++++++++++ 8 files changed, 66 insertions(+), 21 deletions(-) create mode 100644 subgraphs/etherfi-promo/src/utilities/exponentToBigDecimal.ts diff --git a/subgraphs/etherfi-promo/package.json b/subgraphs/etherfi-promo/package.json index 24896ec5..e2de8011 100644 --- a/subgraphs/etherfi-promo/package.json +++ b/subgraphs/etherfi-promo/package.json @@ -1,6 +1,6 @@ { "name": "etherfi-promo-subgraph", - "version": "0.1.0", + "version": "0.1.1", "license": "MIT", "repository": { "url": "https://github.com/VenusProtocol/subgraphs", diff --git a/subgraphs/etherfi-promo/schema.graphql b/subgraphs/etherfi-promo/schema.graphql index 0cc6a569..873da0de 100644 --- a/subgraphs/etherfi-promo/schema.graphql +++ b/subgraphs/etherfi-promo/schema.graphql @@ -33,7 +33,7 @@ type SupplierAccount @entity { "Account address" address: Bytes! "Underlying balance" - effective_balance: BigInt! + effective_balance: BigDecimal! "Token Address" token: Supply! } @@ -47,7 +47,7 @@ type BorrowerAccount @entity { "Account address" address: Bytes! "Underlying balance" - effective_balance: BigInt! + effective_balance: BigDecimal! "Token Address" token: Borrow! } diff --git a/subgraphs/etherfi-promo/src/mappings/vToken.ts b/subgraphs/etherfi-promo/src/mappings/vToken.ts index 8ebab350..a7c55c42 100644 --- a/subgraphs/etherfi-promo/src/mappings/vToken.ts +++ b/subgraphs/etherfi-promo/src/mappings/vToken.ts @@ -6,6 +6,7 @@ import { nullAddress } from '../constants'; import { getBorrow, getSupply } from '../operations/get'; import { getOrCreateBorrowerAccount, getOrCreateSupplierAccount } from '../operations/getOrCreate'; import { updateBorrowerAccount, updateSupplierAccount, updateTvl } from '../operations/update'; +import exponentToBigDecimal from '../utilities/exponentToBigDecimal'; import exponentToBigInt from '../utilities/exponentToBigInt'; export function handleMint(event: Mint): void { @@ -14,14 +15,20 @@ export function handleMint(event: Mint): void { updateSupplierAccount( minter, event.address, - supplierAccount.effective_balance.plus(event.params.mintAmount), + supplierAccount.effective_balance.plus( + event.params.mintAmount.toBigDecimal().div(exponentToBigDecimal(18)), + ), ); } export function handleBorrow(event: Borrow): void { const borrower = event.params.borrower; getOrCreateBorrowerAccount(borrower, event.address); - updateBorrowerAccount(borrower, event.address, event.params.accountBorrows); + updateBorrowerAccount( + borrower, + event.address, + event.params.accountBorrows.toBigDecimal().div(exponentToBigDecimal(18)), + ); } export function handleTransfer(event: Transfer): void { @@ -45,19 +52,22 @@ export function handleTransfer(event: Transfer): void { updateSupplierAccount( fromAccountAddress, event.address, - fromAccount.effective_balance.minus(amountUnderlying), + fromAccount.effective_balance.minus( + amountUnderlying.toBigDecimal().div(exponentToBigDecimal(18)), + ), ); // To const toAccount = getOrCreateSupplierAccount(toAccountAddress, event.address); updateSupplierAccount( toAccountAddress, event.address, - toAccount.effective_balance.plus(amountUnderlying), + toAccount.effective_balance.plus( + amountUnderlying.toBigDecimal().div(exponentToBigDecimal(18)), + ), ); } } -// eslint-disable-next-line @typescript-eslint/no-unused-vars export function handleAccrueInterest(event: AccrueInterest): void { const supply = getSupply(event.address); supply.suppliers.load().forEach(supplier => { @@ -66,7 +76,7 @@ export function handleAccrueInterest(event: AccrueInterest): void { const exchangeRateMantissa = vTokenContract.exchangeRateCurrent(); const vTokenBalance = vTokenContract.balanceOf(Address.fromBytes(supplier.address)); const amountUnderlying = exchangeRateMantissa.times(vTokenBalance).div(exponentToBigInt(18)); - supplier.effective_balance = amountUnderlying; + supplier.effective_balance = amountUnderlying.toBigDecimal().div(exponentToBigDecimal(18)); supplier.save(); }); @@ -76,7 +86,9 @@ export function handleAccrueInterest(event: AccrueInterest): void { const underlyingBorrowBalance = vTokenContract.borrowBalanceCurrent( Address.fromBytes(borrower.address), ); - borrower.effective_balance = underlyingBorrowBalance; + borrower.effective_balance = underlyingBorrowBalance + .toBigDecimal() + .div(exponentToBigDecimal(18)); borrower.save(); }); diff --git a/subgraphs/etherfi-promo/src/operations/getOrCreate.ts b/subgraphs/etherfi-promo/src/operations/getOrCreate.ts index 56858653..e1d2801a 100644 --- a/subgraphs/etherfi-promo/src/operations/getOrCreate.ts +++ b/subgraphs/etherfi-promo/src/operations/getOrCreate.ts @@ -1,7 +1,7 @@ import { Address } from '@graphprotocol/graph-ts'; import { BorrowerAccount, SupplierAccount } from '../../generated/schema'; -import { zeroBigInt32 } from '../constants'; +import { zeroBigDecimal } from '../constants'; import { getBorrow, getSupply } from '../operations/get'; import { getPositionId } from '../utilities/ids'; @@ -14,7 +14,7 @@ export const getOrCreateSupplierAccount = ( const supply = getSupply(tokenAddress); supplierAccount = new SupplierAccount(getPositionId(accountAddress, tokenAddress)); supplierAccount.address = accountAddress; - supplierAccount.effective_balance = zeroBigInt32; + supplierAccount.effective_balance = zeroBigDecimal; supplierAccount.token = supply.id; supplierAccount.save(); } @@ -30,7 +30,7 @@ export const getOrCreateBorrowerAccount = ( const borrow = getBorrow(tokenAddress); borrowerAccount = new BorrowerAccount(getPositionId(accountAddress, tokenAddress)); borrowerAccount.address = accountAddress; - borrowerAccount.effective_balance = zeroBigInt32; + borrowerAccount.effective_balance = zeroBigDecimal; borrowerAccount.token = borrow.id; borrowerAccount.save(); } diff --git a/subgraphs/etherfi-promo/src/operations/update.ts b/subgraphs/etherfi-promo/src/operations/update.ts index ffdc4ab0..fa368d3a 100644 --- a/subgraphs/etherfi-promo/src/operations/update.ts +++ b/subgraphs/etherfi-promo/src/operations/update.ts @@ -1,4 +1,4 @@ -import { Address, BigInt, ethereum } from '@graphprotocol/graph-ts'; +import { Address, BigDecimal, ethereum } from '@graphprotocol/graph-ts'; import { BorrowerAccount, SupplierAccount, TVL } from '../../generated/schema'; import { ERC20 as ERC20Contract } from '../../generated/vWeETH/ERC20'; @@ -8,7 +8,7 @@ import { getBorrowerAccount, getSupplierAccount, getTvl } from './get'; export function updateSupplierAccount( accountAddress: Address, tokenAddress: Address, - amount: BigInt, + amount: BigDecimal, ): SupplierAccount { const account = getSupplierAccount(accountAddress, tokenAddress)!; account.effective_balance = amount; @@ -19,7 +19,7 @@ export function updateSupplierAccount( export function updateBorrowerAccount( accountAddress: Address, tokenAddress: Address, - amount: BigInt, + amount: BigDecimal, ): BorrowerAccount { const account = getBorrowerAccount(accountAddress, tokenAddress)!; account.effective_balance = amount; diff --git a/subgraphs/etherfi-promo/src/utilities/exponentToBigDecimal.ts b/subgraphs/etherfi-promo/src/utilities/exponentToBigDecimal.ts new file mode 100644 index 00000000..21c3556f --- /dev/null +++ b/subgraphs/etherfi-promo/src/utilities/exponentToBigDecimal.ts @@ -0,0 +1,11 @@ +import { BigDecimal } from '@graphprotocol/graph-ts'; + +function exponentToBigInt(decimals: i32): BigDecimal { + let bd = BigDecimal.fromString('1'); + for (let i = 0; i < decimals; i++) { + bd = bd.times(BigDecimal.fromString('10')); + } + return bd; +} + +export default exponentToBigInt; diff --git a/subgraphs/etherfi-promo/tests/VToken/index.test.ts b/subgraphs/etherfi-promo/tests/VToken/index.test.ts index 334d8685..d5c2b918 100644 --- a/subgraphs/etherfi-promo/tests/VToken/index.test.ts +++ b/subgraphs/etherfi-promo/tests/VToken/index.test.ts @@ -15,6 +15,7 @@ import { handleMint, handleTransfer, } from '../../src/mappings/vToken'; +import exponentToBigDecimal from '../../src/utilities/exponentToBigDecimal'; import exponentToBigInt from '../../src/utilities/exponentToBigInt'; import { getPositionId } from '../../src/utilities/ids'; import { @@ -69,7 +70,7 @@ describe('VToken', () => { 'SupplierAccount', getPositionId(minter, vTokenAddress).toHexString(), 'effective_balance', - actualMintAmount.toString(), + actualMintAmount.toBigDecimal().div(exponentToBigDecimal(18)).toString(), ); }); @@ -102,7 +103,7 @@ describe('VToken', () => { 'BorrowerAccount', getPositionId(borrower, vTokenAddress).toHexString(), 'effective_balance', - accountBorrows.toString(), + accountBorrows.toBigDecimal().div(exponentToBigDecimal(18)).toString(), ); }); @@ -198,7 +199,7 @@ describe('VToken', () => { 'BorrowerAccount', getPositionId(user2Address, vTokenAddress).toHexString(), 'effective_balance', - accountBorrows.toString(), + accountBorrows.toBigDecimal().div(exponentToBigDecimal(18)).toString(), ); }); @@ -237,7 +238,11 @@ describe('VToken', () => { 'SupplierAccount', getPositionId(from, vTokenAddress).toHexString(), 'effective_balance', - actualMintAmount.minus(underlyingAmount).toString(), + actualMintAmount + .minus(underlyingAmount) + .toBigDecimal() + .div(exponentToBigDecimal(18)) + .toString(), ); assert.fieldEquals( @@ -250,7 +255,7 @@ describe('VToken', () => { 'SupplierAccount', getPositionId(to, vTokenAddress).toHexString(), 'effective_balance', - underlyingAmount.toString(), + underlyingAmount.toBigDecimal().div(exponentToBigDecimal(18)).toString(), ); }); }); diff --git a/yarn.lock b/yarn.lock index 53ba6887..e9d6d062 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4416,6 +4416,23 @@ __metadata: languageName: node linkType: hard +"@venusprotocol/isolated-pools@npm:3.3.0": + version: 3.3.0 + resolution: "@venusprotocol/isolated-pools@npm:3.3.0" + dependencies: + "@nomiclabs/hardhat-ethers": ^2.2.3 + "@openzeppelin/contracts": ^4.8.3 + "@openzeppelin/contracts-upgradeable": ^4.8.3 + "@openzeppelin/hardhat-upgrades": ^1.21.0 + "@solidity-parser/parser": ^0.13.2 + "@venusprotocol/solidity-utilities": ^2.0.0 + ethers: ^5.7.0 + hardhat-deploy: ^0.11.14 + module-alias: ^2.2.2 + checksum: e6d92426500eaa6874fc57d532bd4dfbb57263810dbf1f863308f4c9faa1372839b003657c9a1945f074acaac55712caad41e0f920d7765e6c6e85712fb6eca1 + languageName: node + linkType: hard + "@venusprotocol/isolated-pools@npm:3.5.0-dev.10": version: 3.5.0-dev.10 resolution: "@venusprotocol/isolated-pools@npm:3.5.0-dev.10"