From 1f67f7c2001a010331b16b5706919090c3581409 Mon Sep 17 00:00:00 2001 From: Corey Rice Date: Fri, 13 Dec 2024 13:00:46 -0300 Subject: [PATCH] refactor: create token entity --- subgraphs/isolated-pools/schema.graphql | 31 +++++++---- .../isolated-pools/src/operations/create.ts | 37 +++++++------- .../src/operations/getOrCreate.ts | 24 +++++++++ .../isolated-pools/src/operations/update.ts | 11 ++-- .../src/operations/updateOrCreate.ts | 2 +- .../utilities/getExchangeRateBigDecimal.ts | 2 +- subgraphs/isolated-pools/src/utilities/ids.ts | 2 + .../queries/accountPositions.graphql | 12 +++-- .../queries/marketActionsQuery.graphql | 4 +- .../queries/marketByIdQuery.graphql | 10 ++-- .../queries/marketsQuery.graphql | 10 ++-- .../queries/rewardDistributors.graphql | 4 +- .../isolated-pools/tests/Pool/index.test.ts | 2 +- .../tests/RewardsDistributor/index.test.ts | 3 +- .../isolated-pools/tests/VToken/mocks.ts | 31 +++++++---- .../isolated-pools/tests/integration/pool.ts | 2 +- .../tests/scripts/checkMarkets.ts | 8 +-- subgraphs/venus/schema.graphql | 27 ++++++---- subgraphs/venus/src/mappings/vToken.ts | 5 +- subgraphs/venus/src/operations/getOrCreate.ts | 51 +++++++++++++------ .../operations/updateMarketExchangeRate.ts | 2 +- subgraphs/venus/src/utilities/ids.ts | 2 + .../queries/marketByIdQuery.graphql | 10 ++-- .../queries/marketsQuery.graphql | 10 ++-- subgraphs/venus/tests/Comptroller.test.ts | 9 ++-- subgraphs/venus/tests/scripts/checkMarkets.ts | 8 +-- 26 files changed, 213 insertions(+), 106 deletions(-) diff --git a/subgraphs/isolated-pools/schema.graphql b/subgraphs/isolated-pools/schema.graphql index 905d6409..de22180c 100644 --- a/subgraphs/isolated-pools/schema.graphql +++ b/subgraphs/isolated-pools/schema.graphql @@ -36,6 +36,23 @@ type Pool @entity { } """ +ERC20 Token +""" +type Token @entity(immutable: true) { + "Address of the asset" + id: Bytes! + "Address of the asset" + address: Bytes! + "Name of the asset" + name: String! + "Symbol of the asset" + symbol: String! + "Decimals of the asset" + decimals: Int! +} + +""" +MarketAction is an action that can be taken on a market enum MarketPauseGuardianAction { Mint = "Mint", Borrow = "Borrow", @@ -45,7 +62,7 @@ type MarketAction @entity { "Concatentation of address and action" id: Bytes! "vToken Address affected" - vToken: Bytes! + market: Market! "Action (Borrow, Mint)" action: String! "True if paused, otherwise False if active" @@ -83,12 +100,8 @@ type Market @entity { supplyRateMantissa: BigInt! "VToken symbol" symbol: String! - "Underlying token address" - underlyingAddress: Bytes! - "Underlying token name" - underlyingName: String! - "Underlying token symbol" - underlyingSymbol: String! + "Underlying Token" + underlyingToken: Token! "Max token borrow amount allowed" borrowCapMantissa: BigInt! "Total borrowed underlying token" @@ -106,8 +119,6 @@ type Market @entity { lastUnderlyingPriceCents: BigInt! "Block price was last updated" lastUnderlyingPriceBlockNumber: BigInt! - "Underlying token decimal length" - underlyingDecimals: Int! "vToken decimal length" vTokenDecimals: Int! @@ -247,7 +258,7 @@ type RewardsDistributor @entity { "Address of the pool" pool: Pool! "Address of the reward token" - rewardTokenAddress: Bytes! + rewardToken: Token! "Distribution rate for suppliers" marketRewards: [MarketReward!]! @derivedFrom(field:"rewardsDistributor") "Depending on the Chain, the rewards distributor is time based or block based" diff --git a/subgraphs/isolated-pools/src/operations/create.ts b/subgraphs/isolated-pools/src/operations/create.ts index d14af97f..b35473ea 100644 --- a/subgraphs/isolated-pools/src/operations/create.ts +++ b/subgraphs/isolated-pools/src/operations/create.ts @@ -1,4 +1,4 @@ -import { Address, BigInt } from '@graphprotocol/graph-ts'; +import { Address, BigInt, Bytes } from '@graphprotocol/graph-ts'; import { Comptroller as ComptrollerContract } from '../../generated/PoolRegistry/Comptroller'; import { PoolRegistry as PoolRegistryContract } from '../../generated/PoolRegistry/PoolRegistry'; @@ -23,7 +23,6 @@ import { } from '../../generated/schema'; import { Comptroller } from '../../generated/templates/Pool/Comptroller'; import { RewardsDistributor as RewardDistributorContract } from '../../generated/templates/RewardsDistributor/RewardsDistributor'; -import { BEP20 as BEP20Contract } from '../../generated/templates/VToken/BEP20'; import { VToken as VTokenContract } from '../../generated/templates/VToken/VToken'; import { BORROW, LIQUIDATE, MINT, REDEEM, REPAY, TRANSFER, zeroBigInt32 } from '../constants'; import { @@ -37,7 +36,7 @@ import { vWETHLiquidStakedETHAddress, vWETHCoreAddress, } from '../constants/addresses'; -import { getOrCreateMarketReward } from './getOrCreate'; +import { getOrCreateMarketReward, getOrCreateToken } from './getOrCreate'; import { getTokenPriceInCents, valueOrNotAvailableIntIfReverted } from '../utilities'; import { getAccountId, @@ -107,7 +106,7 @@ export function createMarket( const vTokenContract = VTokenContract.bind(vTokenAddress); const poolComptroller = Comptroller.bind(comptroller); const underlyingAddress = vTokenContract.underlying(); - const underlyingContract = BEP20Contract.bind(Address.fromBytes(underlyingAddress)); + const market = new Market(vTokenAddress); market.address = vTokenAddress; @@ -118,14 +117,14 @@ export function createMarket( market.interestRateModelAddress = vTokenContract.interestRateModel(); market.symbol = vTokenContract.symbol(); market.vTokenDecimals = vTokenContract.decimals(); + const underlyingToken = getOrCreateToken(underlyingAddress); + market.underlyingToken = underlyingToken.id; - market.underlyingAddress = underlyingAddress; - market.underlyingName = underlyingContract.name(); - market.underlyingSymbol = underlyingContract.symbol(); - const underlyingDecimals = underlyingContract.decimals(); - market.underlyingDecimals = underlyingDecimals; - - const underlyingValue = getTokenPriceInCents(comptroller, vTokenAddress, underlyingDecimals); + const underlyingValue = getTokenPriceInCents( + comptroller, + vTokenAddress, + underlyingToken.decimals, + ); market.lastUnderlyingPriceCents = underlyingValue; market.lastUnderlyingPriceBlockNumber = blockNumber; market.accessControlManagerAddress = vTokenContract.accessControlManager(); @@ -178,15 +177,17 @@ export function createMarket( } if (vTokenAddress.equals(vankrBNBLiquidStakedBNBAddress)) { - market.underlyingAddress = Address.fromHexString('0x5269b7558D3d5E113010Ef1cFF0901c367849CC9'); + market.underlyingToken = getOrCreateToken( + Address.fromBytes(Bytes.fromHexString('0x5269b7558D3d5E113010Ef1cFF0901c367849CC9')), + ).id; market.symbol = 'vankrBNB_LiquidStakedBNB'; - market.underlyingName = 'Ankr Staked BNB '; } if (vTokenAddress.equals(vankrBNBDeFiAddress)) { - market.underlyingAddress = Address.fromHexString('0x5269b7558D3d5E113010Ef1cFF0901c367849CC9'); + market.underlyingToken = getOrCreateToken( + Address.fromBytes(Bytes.fromHexString('0x5269b7558D3d5E113010Ef1cFF0901c367849CC9')), + ).id; market.symbol = 'vankrBNB_DeFi'; - market.underlyingName = 'Ankr Staked BNB '; } if (vTokenAddress.equals(vSnBNBAddress)) { @@ -195,7 +196,9 @@ export function createMarket( } if (vTokenAddress.equals(vWETHLiquidStakedETHAddress) || vTokenAddress.equals(vWETHCoreAddress)) { - market.underlyingAddress = Address.fromHexString('0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9'); + market.underlyingToken = getOrCreateToken( + Address.fromBytes(Bytes.fromHexString('0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9')), + ).id; } market.save(); @@ -311,7 +314,7 @@ export function createRewardDistributor( const rewardsDistributor = new RewardsDistributor(id); rewardsDistributor.address = rewardsDistributorAddress; rewardsDistributor.pool = comptrollerAddress; - rewardsDistributor.rewardTokenAddress = rewardToken; + rewardsDistributor.rewardToken = getOrCreateToken(rewardToken).id; rewardsDistributor.isTimeBased = valueOrFalseIfReverted( rewardDistributorContract.try_isTimeBased(), ); diff --git a/subgraphs/isolated-pools/src/operations/getOrCreate.ts b/subgraphs/isolated-pools/src/operations/getOrCreate.ts index 6cb9ff4c..6522216b 100644 --- a/subgraphs/isolated-pools/src/operations/getOrCreate.ts +++ b/subgraphs/isolated-pools/src/operations/getOrCreate.ts @@ -1,6 +1,7 @@ import { Address, BigInt } from '@graphprotocol/graph-ts'; import { VToken as VTokenContract } from '../../generated/PoolRegistry/VToken'; +import { BEP20 } from '../../generated/PoolRegistry/BEP20'; import { Account, AccountPool, @@ -9,6 +10,7 @@ import { Pool, MarketReward, RewardsDistributor, + Token, } from '../../generated/schema'; import { zeroBigInt32 } from '../constants'; import { @@ -17,6 +19,7 @@ import { getPoolId, getMarketRewardId, getRewardsDistributorId, + getTokenId, } from '../utilities/ids'; import { createAccount, @@ -140,3 +143,24 @@ export const getOrCreateRewardDistributor = ( return rewardsDistributor as RewardsDistributor; }; + +/** + * Creates and Token object with symbol and address + * + * @param asset Address of the token + * @returns Token + */ +export function getOrCreateToken(asset: Address): Token { + let tokenEntity = Token.load(getTokenId(asset)); + + if (!tokenEntity) { + const erc20 = BEP20.bind(asset); + tokenEntity = new Token(getTokenId(asset)); + tokenEntity.address = asset; + tokenEntity.name = erc20.name(); + tokenEntity.symbol = erc20.symbol(); + tokenEntity.decimals = erc20.decimals(); + tokenEntity.save(); + } + return tokenEntity; +} diff --git a/subgraphs/isolated-pools/src/operations/update.ts b/subgraphs/isolated-pools/src/operations/update.ts index cfd6b10e..962e329e 100644 --- a/subgraphs/isolated-pools/src/operations/update.ts +++ b/subgraphs/isolated-pools/src/operations/update.ts @@ -6,7 +6,12 @@ import { VToken } from '../../generated/templates/VToken/VToken'; import { valueOrNotAvailableIntIfReverted } from '../utilities'; import { getTokenPriceInCents } from '../utilities'; import { getMarket } from './get'; -import { getOrCreateAccount, getOrCreateMarketPosition, getOrCreatePool } from './getOrCreate'; +import { + getOrCreateAccount, + getOrCreateMarketPosition, + getOrCreatePool, + getOrCreateToken, +} from './getOrCreate'; import { oneBigInt, zeroBigInt32 } from '../constants'; export const updateMarketPositionAccrualBlockNumber = ( @@ -98,11 +103,11 @@ export const updateMarket = (vTokenAddress: Address, blockNumber: BigInt): Marke return market as Market; } const marketContract = VToken.bind(vTokenAddress); - + const underlyingToken = getOrCreateToken(Address.fromBytes(market.underlyingToken)); const tokenPriceCents = getTokenPriceInCents( Address.fromBytes(market.pool), vTokenAddress, - market.underlyingDecimals, + underlyingToken.decimals, ); market.lastUnderlyingPriceCents = tokenPriceCents; market.lastUnderlyingPriceBlockNumber = blockNumber; diff --git a/subgraphs/isolated-pools/src/operations/updateOrCreate.ts b/subgraphs/isolated-pools/src/operations/updateOrCreate.ts index a91bfd4a..56d55edd 100644 --- a/subgraphs/isolated-pools/src/operations/updateOrCreate.ts +++ b/subgraphs/isolated-pools/src/operations/updateOrCreate.ts @@ -39,7 +39,7 @@ export const updateOrCreateMarketAction = ( ): MarketAction => { const id = getMarketActionId(vTokenAddress, action); const marketAction = new MarketAction(id); - marketAction.vToken = vTokenAddress; + marketAction.market = vTokenAddress; marketAction.action = Actions[action]; marketAction.pauseState = pauseState; marketAction.save(); diff --git a/subgraphs/isolated-pools/src/utilities/getExchangeRateBigDecimal.ts b/subgraphs/isolated-pools/src/utilities/getExchangeRateBigDecimal.ts index 3cb8f57d..3c9030ae 100644 --- a/subgraphs/isolated-pools/src/utilities/getExchangeRateBigDecimal.ts +++ b/subgraphs/isolated-pools/src/utilities/getExchangeRateBigDecimal.ts @@ -14,7 +14,7 @@ const getExchangeRateBigDecimal = ( - If you call the vUSDC contract on bscscan it comes back (2.0 * 10^14) - The real value is ~0.02. So vDAI is off by 10^28, and vUSDC 10^16 How to calculate for tokens with different decimals - - Must div by tokenDecimals, 10^market.underlyingDecimals + - Must div by tokenDecimals, 10^market.underlyingToken.decimals - Must multiply by vtokenDecimals, 10^8 - Must div by mantissa, 10^18 */ diff --git a/subgraphs/isolated-pools/src/utilities/ids.ts b/subgraphs/isolated-pools/src/utilities/ids.ts index 6ede4507..6f30a464 100644 --- a/subgraphs/isolated-pools/src/utilities/ids.ts +++ b/subgraphs/isolated-pools/src/utilities/ids.ts @@ -28,3 +28,5 @@ export const getMarketRewardId = ( export const getAccountPoolId = (accountAddress: Address, poolAddress: Address): Bytes => accountAddress.concat(poolAddress); + +export const getTokenId = (tokenAddress: Address): Bytes => tokenAddress; diff --git a/subgraphs/isolated-pools/subgraph-client/queries/accountPositions.graphql b/subgraphs/isolated-pools/subgraph-client/queries/accountPositions.graphql index d8269cdf..2f58c114 100644 --- a/subgraphs/isolated-pools/subgraph-client/queries/accountPositions.graphql +++ b/subgraphs/isolated-pools/subgraph-client/queries/accountPositions.graphql @@ -17,9 +17,11 @@ query AccountPositions($id: ID!) { id liquidationThresholdMantissa exchangeRateMantissa - underlyingAddress + underlyingToken { + address + decimals + } vTokenDecimals - underlyingDecimals } } borrows: tokens(where: { storedBorrowBalanceMantissa_gt: 0 }) { @@ -28,9 +30,11 @@ query AccountPositions($id: ID!) { borrowIndex market { id - underlyingAddress + underlyingToken { + address + decimals + } vTokenDecimals - underlyingDecimals } } } diff --git a/subgraphs/isolated-pools/subgraph-client/queries/marketActionsQuery.graphql b/subgraphs/isolated-pools/subgraph-client/queries/marketActionsQuery.graphql index cfd901c7..fced784d 100644 --- a/subgraphs/isolated-pools/subgraph-client/queries/marketActionsQuery.graphql +++ b/subgraphs/isolated-pools/subgraph-client/queries/marketActionsQuery.graphql @@ -1,7 +1,9 @@ query MarketActions { marketActions { id - vToken + market { + address + } action pauseState } diff --git a/subgraphs/isolated-pools/subgraph-client/queries/marketByIdQuery.graphql b/subgraphs/isolated-pools/subgraph-client/queries/marketByIdQuery.graphql index 98139d1a..87f6f786 100644 --- a/subgraphs/isolated-pools/subgraph-client/queries/marketByIdQuery.graphql +++ b/subgraphs/isolated-pools/subgraph-client/queries/marketByIdQuery.graphql @@ -16,17 +16,19 @@ query MarketById($id: ID!) { reservesMantissa supplyRateMantissa symbol - underlyingAddress - underlyingName + underlyingToken { + address + name + symbol + decimals + } lastUnderlyingPriceCents lastUnderlyingPriceBlockNumber - underlyingSymbol borrowCapMantissa supplyCapMantissa accrualBlockNumber borrowIndex reserveFactorMantissa - underlyingDecimals supplierCount borrowerCount totalBorrowsMantissa diff --git a/subgraphs/isolated-pools/subgraph-client/queries/marketsQuery.graphql b/subgraphs/isolated-pools/subgraph-client/queries/marketsQuery.graphql index e6939a54..2ddcc486 100644 --- a/subgraphs/isolated-pools/subgraph-client/queries/marketsQuery.graphql +++ b/subgraphs/isolated-pools/subgraph-client/queries/marketsQuery.graphql @@ -15,9 +15,12 @@ query Markets { reservesMantissa supplyRateMantissa symbol - underlyingAddress - underlyingName - underlyingSymbol + underlyingToken { + address + name + symbol + decimals + } vTokenDecimals borrowCapMantissa accrualBlockNumber @@ -26,7 +29,6 @@ query Markets { reserveFactorMantissa lastUnderlyingPriceCents lastUnderlyingPriceBlockNumber - underlyingDecimals supplyCapMantissa accessControlManagerAddress supplierCount diff --git a/subgraphs/isolated-pools/subgraph-client/queries/rewardDistributors.graphql b/subgraphs/isolated-pools/subgraph-client/queries/rewardDistributors.graphql index dc385126..4ef13fcd 100644 --- a/subgraphs/isolated-pools/subgraph-client/queries/rewardDistributors.graphql +++ b/subgraphs/isolated-pools/subgraph-client/queries/rewardDistributors.graphql @@ -2,7 +2,9 @@ query RewardsDistributors { rewardsDistributors { id address - rewardTokenAddress + rewardToken { + address + } isTimeBased marketRewards { id diff --git a/subgraphs/isolated-pools/tests/Pool/index.test.ts b/subgraphs/isolated-pools/tests/Pool/index.test.ts index 89e2f8a9..0d402171 100644 --- a/subgraphs/isolated-pools/tests/Pool/index.test.ts +++ b/subgraphs/isolated-pools/tests/Pool/index.test.ts @@ -321,7 +321,7 @@ describe('Pool Events', () => { const id = getMarketActionId(vTokenAddress, action).toHexString(); assert.fieldEquals('MarketAction', id, 'id', id); - assert.fieldEquals('MarketAction', id, 'vToken', vTokenAddress.toHexString()); + assert.fieldEquals('MarketAction', id, 'market', vTokenAddress.toHexString()); assert.fieldEquals('MarketAction', id, 'action', 'MINT'); assert.fieldEquals('MarketAction', id, 'pauseState', pauseState.toString()); }); diff --git a/subgraphs/isolated-pools/tests/RewardsDistributor/index.test.ts b/subgraphs/isolated-pools/tests/RewardsDistributor/index.test.ts index 3e5dfa6e..a8c52575 100644 --- a/subgraphs/isolated-pools/tests/RewardsDistributor/index.test.ts +++ b/subgraphs/isolated-pools/tests/RewardsDistributor/index.test.ts @@ -18,7 +18,7 @@ import { } from '../../src/mappings/rewardsDistributor'; import { getMarketRewardId } from '../../src/utilities/ids'; import { createNewRewardsDistributor } from '../Pool/events'; -import { createVBep20AndUnderlyingMock } from '../VToken/mocks'; +import { createVBep20AndUnderlyingMock, createBep20Mock } from '../VToken/mocks'; import { createRewardTokenBorrowSpeedUpdatedEvent, createRewardTokenSupplySpeedUpdatedEvent, @@ -48,6 +48,7 @@ beforeAll(() => { beforeEach(() => { createRewardsDistributorMock(rewardsDistributorAddress, tokenAddress); + createBep20Mock(tokenAddress, 'B0B Coin', 'B0B', BigInt.fromI32(18)); const newRewardsDistributorEvent = createNewRewardsDistributor( comptrollerAddress, rewardsDistributorAddress, diff --git a/subgraphs/isolated-pools/tests/VToken/mocks.ts b/subgraphs/isolated-pools/tests/VToken/mocks.ts index e81b362e..654b35f6 100644 --- a/subgraphs/isolated-pools/tests/VToken/mocks.ts +++ b/subgraphs/isolated-pools/tests/VToken/mocks.ts @@ -78,6 +78,25 @@ export const createPoolRegistryMock = (pools: Array): void => { }); }; +export const createBep20Mock = ( + contractAddress: Address, + name: string, + symbol: string, + decimals: BigInt, +): void => { + createMockedFunction(contractAddress, 'decimals', 'decimals():(uint8)').returns([ + ethereum.Value.fromUnsignedBigInt(decimals), + ]); + + createMockedFunction(contractAddress, 'name', 'name():(string)').returns([ + ethereum.Value.fromString(name), + ]); + + createMockedFunction(contractAddress, 'symbol', 'symbol():(string)').returns([ + ethereum.Value.fromString(symbol), + ]); +}; + export const createVBep20AndUnderlyingMock = ( contractAddress: Address, underlyingAddress: Address, @@ -130,17 +149,7 @@ export const createVBep20AndUnderlyingMock = ( ).returns([ethereum.Value.fromAddress(accessControlManagerAddress)]); // Underlying - createMockedFunction(underlyingAddress, 'decimals', 'decimals():(uint8)').returns([ - ethereum.Value.fromUnsignedBigInt(decimals), - ]); - - createMockedFunction(underlyingAddress, 'name', 'name():(string)').returns([ - ethereum.Value.fromString(name), - ]); - - createMockedFunction(underlyingAddress, 'symbol', 'symbol():(string)').returns([ - ethereum.Value.fromString(symbol), - ]); + createBep20Mock(underlyingAddress, name, symbol, decimals); createMockedFunction( mockPriceOracleAddress, diff --git a/subgraphs/isolated-pools/tests/integration/pool.ts b/subgraphs/isolated-pools/tests/integration/pool.ts index 8261579c..6a86322a 100644 --- a/subgraphs/isolated-pools/tests/integration/pool.ts +++ b/subgraphs/isolated-pools/tests/integration/pool.ts @@ -131,7 +131,7 @@ describe('Pools', function () { expect(marketActions.length).to.be.equal(1); marketActions.forEach(ma => { - expect(ma.vToken).to.be.equal(markets[1].id); + expect(ma.market).to.be.equal(markets[1].id); expect(ma.action).to.be.equal('REDEEM'); expect(ma.pauseState).to.be.equal(true); }); diff --git a/subgraphs/isolated-pools/tests/scripts/checkMarkets.ts b/subgraphs/isolated-pools/tests/scripts/checkMarkets.ts index 3287e24b..9c0ef7bc 100644 --- a/subgraphs/isolated-pools/tests/scripts/checkMarkets.ts +++ b/subgraphs/isolated-pools/tests/scripts/checkMarkets.ts @@ -140,10 +140,10 @@ const checkMarkets = async ( assertEqual(market, symbol, 'symbol'); assertEqual(market, decimals, 'vTokenDecimals'); - assertEqual(market, underlyingAddress, 'underlyingAddress', getAddress); - assertEqual(market, underlyingName, 'underlyingName'); - assertEqual(market, underlyingSymbol, 'underlyingSymbol'); - assertEqual(market, underlyingDecimals, 'underlyingDecimals'); + assertEqual(market.underlyingToken, underlyingAddress, 'address', getAddress); + assertEqual(market.underlyingToken, underlyingName, 'name'); + assertEqual(market.underlyingToken, underlyingSymbol, 'symbol'); + assertEqual(market.underlyingToken, underlyingDecimals, 'decimals'); assertEqual(market, marketStorage.isListed, 'isListed'); assertEqual(market, marketStorage.collateralFactorMantissa, 'collateralFactorMantissa'); assertEqual(market, marketStorage.liquidationThresholdMantissa, 'liquidationThresholdMantissa'); diff --git a/subgraphs/venus/schema.graphql b/subgraphs/venus/schema.graphql index fd46e44d..f8002a22 100644 --- a/subgraphs/venus/schema.graphql +++ b/subgraphs/venus/schema.graphql @@ -16,6 +16,22 @@ type Comptroller @entity { maxAssets: BigInt! } +""" +ERC20 Token +""" +type Token @entity(immutable: true) { + "Address of the asset" + id: Bytes! + "Address of the asset" + address: Bytes! + "Name of the asset" + name: String! + "Symbol of the asset" + symbol: String + "Decimals of the asset" + decimals: Int! +} + """ Market stores all high level variables for a vToken market """ @@ -50,14 +66,8 @@ type Market @entity { totalBorrowsMantissa: BigInt! "Total vToken supplied" totalSupplyVTokenMantissa: BigInt! - "Underlying token address" - underlyingAddress: Bytes! - "Underlying token name" - underlyingName: String! - "Underlying token symbol" - underlyingSymbol: String! - "Underlying token decimal length" - underlyingDecimals: Int! + "Underlying Token" + underlyingToken: Token! "XVS Supply Distribution Block" xvsSupplyStateBlock: BigInt! "XVS Supply Distribution Index" @@ -71,7 +81,6 @@ type Market @entity { "The rate at which XVS is distributed to the corresponding borrow market (per block)" xvsBorrowSpeed: BigInt! - # Fields that are not in Venus api "Block the market is updated to" accrualBlockNumber: BigInt! "The history of the markets borrow index return (Think S&P 500)" diff --git a/subgraphs/venus/src/mappings/vToken.ts b/subgraphs/venus/src/mappings/vToken.ts index 160bd7c9..fa974477 100644 --- a/subgraphs/venus/src/mappings/vToken.ts +++ b/subgraphs/venus/src/mappings/vToken.ts @@ -1,5 +1,6 @@ /* eslint-disable prefer-const */ // to satisfy AS compiler +import { Address } from '@graphprotocol/graph-ts'; import { AccrueInterest, Borrow, @@ -31,6 +32,7 @@ import { getOrCreateAccount, getOrCreateMarketPosition, getOrCreateMarket, + getOrCreateToken, } from '../operations/getOrCreate'; import { updateMarketPositionSupply, updateMarketPositionBorrow } from '../operations/update'; import { updateMarketCashMantissa } from '../operations/updateMarketCashMantissa'; @@ -280,7 +282,8 @@ export function handleAccrueInterest(event: AccrueInterest): void { market.borrowIndex = event.params.borrowIndex; market.totalBorrowsMantissa = event.params.totalBorrows; updateMarketCashMantissa(market, vTokenContract); - market.lastUnderlyingPriceCents = getUnderlyingPrice(marketAddress, market.underlyingDecimals); + const underlyingToken = getOrCreateToken(Address.fromBytes(market.underlyingToken)); + market.lastUnderlyingPriceCents = getUnderlyingPrice(marketAddress, underlyingToken.decimals); market.lastUnderlyingPriceBlockNumber = event.block.number; updateMarketRates(market, vTokenContract); diff --git a/subgraphs/venus/src/operations/getOrCreate.ts b/subgraphs/venus/src/operations/getOrCreate.ts index cecf6fea..b8a3ce50 100644 --- a/subgraphs/venus/src/operations/getOrCreate.ts +++ b/subgraphs/venus/src/operations/getOrCreate.ts @@ -1,6 +1,6 @@ import { Address, BigInt, Bytes, ethereum } from '@graphprotocol/graph-ts'; -import { Account, MarketPosition, Market } from '../../generated/schema'; +import { Account, MarketPosition, Market, Token } from '../../generated/schema'; import { VToken as VTokenTemplate, VTokenUpdatedEvents as VTokenUpdatedEventsTemplate, @@ -20,7 +20,7 @@ import { valueOrNotAvailableAddressIfReverted, valueOrNotAvailableIntIfReverted, } from '../utilities'; -import { getMarketPositionId } from '../utilities/ids'; +import { getMarketPositionId, getTokenId } from '../utilities/ids'; import { getMarket } from './get'; import { updateMarketCashMantissa } from './updateMarketCashMantissa'; import { updateMarketRates } from './updateMarketRates'; @@ -54,16 +54,15 @@ export function getOrCreateMarket(marketAddress: Address, event: ethereum.Event) // It is vBNB, which has a slightly different interface if (market.symbol == 'vBNB') { - market.underlyingAddress = nativeAddress; - market.underlyingDecimals = 18; - market.underlyingName = 'BNB'; - market.underlyingSymbol = 'BNB'; + const tokenEntity = new Token(getTokenId(nativeAddress)); + tokenEntity.address = nativeAddress; + tokenEntity.name = 'BNB'; + tokenEntity.symbol = 'BNB'; + tokenEntity.decimals = 18; + tokenEntity.save(); + market.underlyingToken = tokenEntity.id; } else { - market.underlyingAddress = vTokenContract.underlying(); - const underlyingContract = BEP20.bind(Address.fromBytes(market.underlyingAddress)); - market.underlyingDecimals = underlyingContract.decimals(); - market.underlyingName = underlyingContract.name(); - market.underlyingSymbol = underlyingContract.symbol(); + market.underlyingToken = getOrCreateToken(vTokenContract.underlying()).id; } market.interestRateModelAddress = valueOrNotAvailableAddressIfReverted( @@ -74,7 +73,8 @@ export function getOrCreateMarket(marketAddress: Address, event: ethereum.Event) vTokenContract.try_reserveFactorMantissa(), 'vBEP20 try_reserveFactorMantissa()', ); - market.lastUnderlyingPriceCents = getUnderlyingPrice(marketAddress, market.underlyingDecimals); + const underlyingToken = getOrCreateToken(Address.fromBytes(market.underlyingToken)); + market.lastUnderlyingPriceCents = getUnderlyingPrice(marketAddress, underlyingToken.decimals); market.lastUnderlyingPriceBlockNumber = event.block.number; market.accrualBlockNumber = vTokenContract.accrualBlockNumber(); @@ -94,9 +94,9 @@ export function getOrCreateMarket(marketAddress: Address, event: ethereum.Event) market.reservesMantissa = zeroBigInt32; if (marketAddress.equals(vwbETHAddress)) { - market.underlyingAddress = Address.fromHexString( - '0x9c37E59Ba22c4320547F00D4f1857AF1abd1Dd6f', - ); + market.underlyingToken = getOrCreateToken( + Address.fromBytes(Bytes.fromHexString('0x9c37E59Ba22c4320547F00D4f1857AF1abd1Dd6f')), + ).id; } if (marketAddress.equals(vTRXAddressAddress)) { @@ -168,3 +168,24 @@ export function getOrCreateMarketPosition( } return { entity: marketPosition, created }; } + +/** + * Creates and Token object with symbol and address + * + * @param asset Address of the token + * @returns Token + */ +export function getOrCreateToken(asset: Address): Token { + let tokenEntity = Token.load(getTokenId(asset)); + + if (!tokenEntity) { + const erc20 = BEP20.bind(asset); + tokenEntity = new Token(getTokenId(asset)); + tokenEntity.address = asset; + tokenEntity.name = erc20.name(); + tokenEntity.symbol = erc20.symbol(); + tokenEntity.decimals = erc20.decimals(); + tokenEntity.save(); + } + return tokenEntity; +} diff --git a/subgraphs/venus/src/operations/updateMarketExchangeRate.ts b/subgraphs/venus/src/operations/updateMarketExchangeRate.ts index bb4ce0e2..bf56bb11 100644 --- a/subgraphs/venus/src/operations/updateMarketExchangeRate.ts +++ b/subgraphs/venus/src/operations/updateMarketExchangeRate.ts @@ -8,7 +8,7 @@ import { valueOrNotAvailableIntIfReverted } from '../utilities'; - If you call the vUSDC contract on bscscan it comes back (2.0 * 10^14) - The real value is ~0.02. So vDAI is off by 10^28, and vUSDC 10^16 How to calculate for tokens with different decimals - - Must div by tokenDecimals, 10^market.underlyingDecimals + - Must div by tokenDecimals, 10^market.underlyingToken.decimals - Must multiply by vtokenDecimals, 10^8 - Must div by mantissa, 10^18 */ diff --git a/subgraphs/venus/src/utilities/ids.ts b/subgraphs/venus/src/utilities/ids.ts index 35916ed2..babf364e 100644 --- a/subgraphs/venus/src/utilities/ids.ts +++ b/subgraphs/venus/src/utilities/ids.ts @@ -16,3 +16,5 @@ export const getMarketActionId = (vTokenAddress: Address, action: i32): Bytes => vTokenAddress.concatI32(action); export const getMarketId = (vTokenAddress: Address): Bytes => vTokenAddress; + +export const getTokenId = (tokenAddress: Address): Bytes => tokenAddress; diff --git a/subgraphs/venus/subgraph-client/queries/marketByIdQuery.graphql b/subgraphs/venus/subgraph-client/queries/marketByIdQuery.graphql index e1eb46ce..7bfb64dc 100644 --- a/subgraphs/venus/subgraph-client/queries/marketByIdQuery.graphql +++ b/subgraphs/venus/subgraph-client/queries/marketByIdQuery.graphql @@ -11,16 +11,18 @@ query MarketById($id: ID!) { reservesMantissa supplyRateMantissa symbol - underlyingAddress - underlyingName + underlyingToken { + name + symbol + address + decimals + } lastUnderlyingPriceCents lastUnderlyingPriceBlockNumber - underlyingSymbol accrualBlockNumber borrowIndex totalSupplyVTokenMantissa totalBorrowsMantissa - underlyingDecimals supplierCount borrowerCount xvsSupplyStateBlock diff --git a/subgraphs/venus/subgraph-client/queries/marketsQuery.graphql b/subgraphs/venus/subgraph-client/queries/marketsQuery.graphql index 48b59fdb..9a9a1a55 100644 --- a/subgraphs/venus/subgraph-client/queries/marketsQuery.graphql +++ b/subgraphs/venus/subgraph-client/queries/marketsQuery.graphql @@ -4,10 +4,12 @@ query Markets { name symbol vTokenDecimals - underlyingAddress - underlyingName - underlyingSymbol - underlyingDecimals + underlyingToken { + name + symbol + address + decimals + } isListed borrowRateMantissa cashMantissa diff --git a/subgraphs/venus/tests/Comptroller.test.ts b/subgraphs/venus/tests/Comptroller.test.ts index 1f448177..d1532b4d 100644 --- a/subgraphs/venus/tests/Comptroller.test.ts +++ b/subgraphs/venus/tests/Comptroller.test.ts @@ -76,10 +76,7 @@ describe('handleMarketListing', () => { }; assertMarketDocument('id', vBnbAddress.toHex()); assertMarketDocument('isListed', 'true'); - assertMarketDocument('underlyingAddress', nativeAddress.toHex()); - assertMarketDocument('underlyingDecimals', '18'); - assertMarketDocument('underlyingName', 'BNB'); - assertMarketDocument('underlyingSymbol', 'BNB'); + assertMarketDocument('underlyingToken', nativeAddress.toHex()); assertMarketDocument('lastUnderlyingPriceCents', '0'); assertMarketDocument('lastUnderlyingPriceBlockNumber', '1'); assertMarketDocument('borrowRateMantissa', '12678493'); @@ -100,6 +97,10 @@ describe('handleMarketListing', () => { assertMarketDocument('xvsSupplyStateIndex', '1000000000000000000000000000000000000'); assertMarketDocument('xvsBorrowStateBlock', '1'); assertMarketDocument('xvsSupplyStateBlock', '1'); + + assert.fieldEquals('Token', nativeAddress.toHex(), 'decimals', '18'); + assert.fieldEquals('Token', nativeAddress.toHex(), 'name', 'BNB'); + assert.fieldEquals('Token', nativeAddress.toHex(), 'symbol', 'BNB'); }); test('unlist vBNB market correctly', () => { diff --git a/subgraphs/venus/tests/scripts/checkMarkets.ts b/subgraphs/venus/tests/scripts/checkMarkets.ts index 9393572d..ab0290c1 100644 --- a/subgraphs/venus/tests/scripts/checkMarkets.ts +++ b/subgraphs/venus/tests/scripts/checkMarkets.ts @@ -155,10 +155,10 @@ const checkMarkets = async ( assertEqual(market, name, 'name'); assertEqual(market, symbol, 'symbol'); assertEqual(market, decimals, 'vTokenDecimals'); - assertEqual(market, underlyingAddress, 'underlyingAddress', getAddress); - assertEqual(market, underlyingName, 'underlyingName'); - assertEqual(market, underlyingSymbol, 'underlyingSymbol'); - assertEqual(market, underlyingDecimals, 'underlyingDecimals'); + assertEqual(market.underlyingToken, underlyingAddress, 'address', getAddress); + assertEqual(market.underlyingToken, underlyingName, 'name'); + assertEqual(market.underlyingToken, underlyingSymbol, 'symbol'); + assertEqual(market.underlyingToken, underlyingDecimals, 'decimals'); assertEqual(market, marketStorage.isListed, 'isListed'); assertEqual(market, marketStorage.collateralFactorMantissa, 'collateralFactorMantissa');