diff --git a/subgraphs/isolated-pools/schema.graphql b/subgraphs/isolated-pools/schema.graphql index e25759e7..268fe982 100644 --- a/subgraphs/isolated-pools/schema.graphql +++ b/subgraphs/isolated-pools/schema.graphql @@ -2,53 +2,53 @@ The Pool entity """ type Pool @entity { - "Pool Address as id" - id: Bytes! - "Pool Comptroller address" - address: Bytes! - "Name of the pool" - name: String! - "Creator of the pool" - creator: Bytes! - "Block where the market was created" - blockPosted: BigInt! - "Timestamp of market creation" - timestampPosted: BigInt! - "Category that the pool belongs too" - category: String! - "Url for pool logo" - logoUrl: String! - "Description of the pool" - description: String! - "Address of price oracle the comptroller uses" - priceOracleAddress: Bytes! - "Factor used to determine repayAmount for liquidating" - closeFactorMantissa: BigInt! - "The percent bonus liquidators get for liquidating" - liquidationIncentiveMantissa: BigInt! - "Min Liquidatable Amount allowed" - minLiquidatableCollateralMantissa: BigInt! - "Markets associated to this pool" - markets: [Market!]! @derivedFrom(field: "pool") + "Pool Address as id" + id: Bytes! + "Pool Comptroller address" + address: Bytes! + "Name of the pool" + name: String! + "Creator of the pool" + creator: Bytes! + "Block where the market was created" + blockPosted: BigInt! + "Timestamp of market creation" + timestampPosted: BigInt! + "Category that the pool belongs too" + category: String! + "Url for pool logo" + logoUrl: String! + "Description of the pool" + description: String! + "Address of price oracle the comptroller uses" + priceOracleAddress: Bytes! + "Factor used to determine repayAmount for liquidating" + closeFactorMantissa: BigInt! + "The percent bonus liquidators get for liquidating" + liquidationIncentiveMantissa: BigInt! + "Min Liquidatable Amount allowed" + minLiquidatableCollateralMantissa: BigInt! + "Markets associated to this pool" + markets: [Market!]! @derivedFrom(field: "pool") - "Reward distributors distributing rewards for markets in this pool" - rewardsDistributors: [RewardsDistributor!]! @derivedFrom(field: "pool") + "Reward distributors distributing rewards for markets in this pool" + rewardsDistributors: [RewardsDistributor!]! @derivedFrom(field: "pool") } """ ERC20 Token """ type Token @entity { - "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! + "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! } """ @@ -59,86 +59,129 @@ enum MarketPauseGuardianAction { } """ type MarketAction @entity { - "Concatentation of address and action" - id: Bytes! - "Market affected" - market: Market! - "Action (Borrow, Mint)" - action: String! - "True if paused, otherwise False if active" - pauseState: Boolean! + "Concatentation of address and action" + id: Bytes! + "Market affected" + market: Market! + "Action (Borrow, Mint)" + action: String! + "True if paused, otherwise False if active" + pauseState: Boolean! } """ Market stores all high level variables for a vToken market """ type Market @entity { - "VToken address" - id: Bytes! - "VToken address" - address: Bytes! - "Pool the market belongs to" - pool: Pool! + "VToken address" + id: Bytes! + "VToken address" + address: Bytes! + "Pool the market belongs to" + pool: Pool! - "Name of the vToken" - name: String! - "Flag for if the token is listed" - isListed: Boolean! - "Borrow rate per block" - borrowRateMantissa: BigInt! - "The vToken contract balance of BEP20 or BNB" - cashMantissa: BigInt! - "Collateral factor determining how much one can borrow" - collateralFactorMantissa: BigInt! - "Exchange rate of tokens / vTokens" - exchangeRateMantissa: BigInt! - "Address of the interest rate model" - interestRateModelAddress: Bytes! - "Reserves stored in the contract" - reservesMantissa: BigInt! - "Supply rate per block" - supplyRateMantissa: BigInt! - "VToken symbol" - symbol: String! - "Underlying Token" - underlyingToken: Token! - "Max token borrow amount allowed" - borrowCapMantissa: BigInt! - "Total borrowed underlying token" - totalBorrowsMantissa: BigInt! - "Total vToken supplied" - totalSupplyVTokenMantissa: BigInt! + "Name of the vToken" + name: String! + "Flag for if the token is listed" + isListed: Boolean! + "Borrow rate per block" + borrowRateMantissa: BigInt! + "The vToken contract balance of BEP20 or BNB" + cashMantissa: BigInt! + "Collateral factor determining how much one can borrow" + collateralFactorMantissa: BigInt! + "Exchange rate of tokens / vTokens" + exchangeRateMantissa: BigInt! + "Address of the interest rate model" + interestRateModelAddress: Bytes! + "Reserves stored in the contract" + reservesMantissa: BigInt! + "Supply rate per block" + supplyRateMantissa: BigInt! + "VToken symbol" + symbol: String! + "Underlying Token" + underlyingToken: Token! + "Max token borrow amount allowed" + borrowCapMantissa: BigInt! + "Total borrowed underlying token" + totalBorrowsMantissa: BigInt! + "Total vToken supplied" + totalSupplyVTokenMantissa: BigInt! - "Block the market is updated to" - accrualBlockNumber: BigInt! - "The history of the markets borrow index return (Think S&P 500)" - borrowIndex: BigInt! - "The factor determining interest that goes to reserves" - reserveFactorMantissa: BigInt! - "Underlying token price in USD cents (updated based on the last received event)" - lastUnderlyingPriceCents: BigInt! - "Block price was last updated" - lastUnderlyingPriceBlockNumber: BigInt! - "vToken decimal length" - vTokenDecimals: Int! + "Block the market is updated to" + accrualBlockNumber: BigInt! + "The history of the markets borrow index return (Think S&P 500)" + borrowIndex: BigInt! + "The factor determining interest that goes to reserves" + reserveFactorMantissa: BigInt! + "Underlying token price in USD cents (updated based on the last received event)" + lastUnderlyingPriceCents: BigInt! + "Block price was last updated" + lastUnderlyingPriceBlockNumber: BigInt! + "vToken decimal length" + vTokenDecimals: Int! - "Supply cap set for market" - supplyCapMantissa: BigInt! - "The amount of bad debt in the market" - badDebtMantissa: BigInt! - "Contract address for the Access Control Manager" - accessControlManagerAddress: Bytes! + "Supply cap set for market" + supplyCapMantissa: BigInt! + "The amount of bad debt in the market" + badDebtMantissa: BigInt! + "Contract address for the Access Control Manager" + accessControlManagerAddress: Bytes! - "Number of accounts currently supplying to this market" - supplierCount: BigInt! - "Number of accounts currently borrowing from this market" - borrowerCount: BigInt! + "Number of accounts currently supplying to this market" + supplierCount: BigInt! + "Number of accounts currently borrowing from this market" + borrowerCount: BigInt! - "Multiplier representing the collateralization after which the borrow is eligible for liquidation" - liquidationThresholdMantissa: BigInt! + "Multiplier representing the collateralization after which the borrow is eligible for liquidation" + liquidationThresholdMantissa: BigInt! - "Accounts who participate in this market" - accounts: [MarketPosition!]! @derivedFrom(field:"market") + "Accounts who participate in this market" + accounts: [MarketPosition!]! @derivedFrom(field: "market") +} + +""" +MarketRatesData records the state of a given market rates in a block number/timestamp +""" +type MarketRatesData @entity(timeseries: true) { + "Incremental ID" + id: Int8! + "Timestamp in microseconds" + timestamp: Timestamp! + "Corresponding block number" + blockNumber: BigInt! + "Corresponding market" + market: Market! + "vToken exchange rate in the given block number/timestamp" + exchangeRateMantissa: BigInt! + "Supply rate in the given block number/timestamp" + supplyRateMantissa: BigInt! + "Borrow rate in the given block number/timestamp" + borrowRateMantissa: BigInt! + "Underlying token price in cents" + underlyingPriceCents: BigInt! +} + +""" +MarketRatesDaily is an aggregation for the MarketRatesData time series +Useful to calculate daily averages for the market rates +""" +type MarketRatesDaily @aggregation(intervals: ["day"], source: "MarketRatesData") { + "Incremental ID" + id: Int8! + "Timestamp in microseconds" + timestamp: Timestamp! + "Corresponding market" + market: Market! + "Count of data points the given interval" + count: Int8! @aggregate(fn: "count", cumulative: true) + "Sum of the supply rates in the given interval" + supplyRateMantissaSum: BigInt! @aggregate(fn: "sum", arg: "supplyRateMantissa") + "Sum of the borrow rates in the given interval" + borrowRateMantissaSum: BigInt! @aggregate(fn: "sum", arg: "borrowRateMantissa") + "Sum of the exchange rates in the given interval" + exchangeRateMantissaSum: BigInt! @aggregate(fn: "sum", arg: "exchangeRateMantissa") } """ @@ -146,29 +189,29 @@ Account is an BNB address, with a list of all vToken markets the account has participated in, along with liquidation information. """ type Account @entity { - "User address" - id: Bytes! - "User address" - address: Bytes! - "Pools the user is participating on" - pools: [AccountPool!]! @derivedFrom(field: "account") - "Count user has been liquidated" - countLiquidated: Int! - "Count user has liquidated others" - countLiquidator: Int! - "True if user has ever borrowed" - hasBorrowed: Boolean! + "User address" + id: Bytes! + "User address" + address: Bytes! + "Pools the user is participating on" + pools: [AccountPool!]! @derivedFrom(field: "account") + "Count user has been liquidated" + countLiquidated: Int! + "Count user has liquidated others" + countLiquidator: Int! + "True if user has ever borrowed" + hasBorrowed: Boolean! } """ Through entity for aggregating positions by pool and account """ type AccountPool @entity(immutable: true) { - "Joined Account address and Pool address" - id: Bytes! - pool: Pool! - account: Account! - tokens: [MarketPosition!]! @derivedFrom(field:"accountPool") + "Joined Account address and Pool address" + id: Bytes! + pool: Pool! + account: Account! + tokens: [MarketPosition!]! @derivedFrom(field: "accountPool") } """ @@ -176,119 +219,155 @@ MarketPosition is a single account within a single vToken market, with data such as interest earned or paid """ type MarketPosition @entity { - "Concatenation of VToken address and user address" - id: Bytes! - "Pool of the market" - accountPool: AccountPool! - "Relation to market" - market: Market! - "Relation to user" - account: Account! - "Bad debt data for the account in the market" - badDebt: [MarketPositionBadDebt!]! @derivedFrom(field:"account") - "Block number this asset was updated at in the contract" - accrualBlockNumber: BigInt! - "Borrow Index this position last accrued interest" - borrowIndex: BigInt! - "vToken balance representing underlying supplied to the market, underlying balance can be calculated with the exchange rate" - vTokenBalanceMantissa: BigInt! - "Stored borrow balance stored in contract (exclusive of interest since accrualBlockNumber)" - storedBorrowBalanceMantissa: BigInt! - "True if user is entered, false if they are exited" - enteredMarket: Boolean! - "Total amount of underlying redeemed" - totalUnderlyingRedeemedMantissa: BigInt! - "Total amount underlying repaid" - totalUnderlyingRepaidMantissa: BigInt! + "Concatenation of VToken address and user address" + id: Bytes! + "Pool of the market" + accountPool: AccountPool! + "Relation to market" + market: Market! + "Relation to user" + account: Account! + "Bad debt data for the account in the market" + badDebt: [MarketPositionBadDebt!]! @derivedFrom(field: "account") + "Block number this asset was updated at in the contract" + accrualBlockNumber: BigInt! + "Borrow Index this position last accrued interest" + borrowIndex: BigInt! + "vToken balance representing underlying supplied to the market, underlying balance can be calculated with the exchange rate" + vTokenBalanceMantissa: BigInt! + "Stored borrow balance stored in contract (exclusive of interest since accrualBlockNumber)" + storedBorrowBalanceMantissa: BigInt! + "True if user is entered, false if they are exited" + enteredMarket: Boolean! + "Total amount of underlying redeemed" + totalUnderlyingRedeemedMantissa: BigInt! + "Total amount underlying repaid" + totalUnderlyingRepaidMantissa: BigInt! +} + +""" +MarketSupplyPositionData records the state of an account's supply position in a block number/timestamp +""" +type MarketSupplyPositionData @entity(timeseries: true) { + "Incremental ID" + id: Int8! + "Timestamp in microseconds" + timestamp: Timestamp! + "Corresponding block number" + blockNumber: BigInt! + "Supplier account" + account: Account! + "Supplied market" + market: Market! + "vToken balance at the given block number/timestamp" + vTokenBalanceMantissa: BigInt! +} + +""" +MarketBorrowPositionData records the state of an account's borrow position in a block number/timestamp +""" +type MarketBorrowPositionData @entity(timeseries: true) { + "Incremental ID" + id: Int8! + "Timestamp in microseconds" + timestamp: Timestamp! + "Corresponding block number" + blockNumber: BigInt! + "Borrower account" + account: Account! + "Borrowed from this market" + market: Market! + "Borrowed underlying balance at the given block number/timestamp" + borrowBalanceMantissa: BigInt! } """ Auxiliary entity for MarketPosition indicating when a certain amount of bad debt was healed """ type MarketPositionBadDebt @entity { - "Concatenation of borrower and vToken Address" - id: Bytes! - "Market that was healed" - account: MarketPosition! - "Amount that was healed" - amountMantissa: BigInt! - "Timestamp" - timestamp: BigInt! - "Block Number" - block: BigInt! + "Concatenation of borrower and vToken Address" + id: Bytes! + "Market that was healed" + account: MarketPosition! + "Amount that was healed" + amountMantissa: BigInt! + "Timestamp" + timestamp: BigInt! + "Block Number" + block: BigInt! } enum EventType { - MINT - REDEEM - BORROW - TRANSFER - LIQUIDATE - REPAY + MINT + REDEEM + BORROW + TRANSFER + LIQUIDATE + REPAY } """ Entity recording transactions for interacting with markets """ type Transaction @entity(immutable: true) { - "Transaction hash concatenated with log index" - id: Bytes! - "enum of event type" - type: EventType! - "The account that sent the transaction, for example sender of vToken" - from: Bytes! - "count of vTokens transferred" - amountMantissa: BigInt! - "Account that received tokens" - to: Bytes! - "Block number" - blockNumber: Int! - "Block time" - blockTime: Int! + "Transaction hash concatenated with log index" + id: Bytes! + "enum of event type" + type: EventType! + "The account that sent the transaction, for example sender of vToken" + from: Bytes! + "count of vTokens transferred" + amountMantissa: BigInt! + "Account that received tokens" + to: Bytes! + "Block number" + blockNumber: Int! + "Block time" + blockTime: Int! } """ An interface for rewards distributor that distribute rewards to isolated pools """ type RewardsDistributor @entity { - "Address of the rewards distributor" - id: Bytes! - "Address of the rewards distributor" - address: Bytes! - "Address of the pool" - pool: Pool! - "Address of the reward token" - rewardToken: Token! - "Distribution rate for suppliers" - marketRewards: [MarketReward!]! @derivedFrom(field:"rewardsDistributor") - "Depending on the Chain, the rewards distributor is time based or block based" - isTimeBased: Boolean! + "Address of the rewards distributor" + id: Bytes! + "Address of the rewards distributor" + address: Bytes! + "Address of the pool" + pool: Pool! + "Address of the reward token" + rewardToken: Token! + "Distribution rate for suppliers" + marketRewards: [MarketReward!]! @derivedFrom(field: "rewardsDistributor") + "Depending on the Chain, the rewards distributor is time based or block based" + isTimeBased: Boolean! } """ A interface for rewards distributor that distribute rewards to isolated pools """ type MarketReward @entity { - "ID created from the reward distributor and market this speed applies to" - id: Bytes! - "Address of rewards distributor" - rewardsDistributor: RewardsDistributor! - "Address of the market this speed applies to" - market: Market! - "Distribution rate for borrowers" - borrowSpeedPerBlockMantissa: BigInt! - "Distribution rate for suppliers" - supplySpeedPerBlockMantissa: BigInt! - "Index of the last supply state update" - supplyStateIndex: BigInt! - "Timestamp or block number of the last supply state update" - supplyStateBlockNumberOrTimestamp: BigInt! - "Index of the last borrow state update" - borrowStateIndex: BigInt! - "Timestamp or block number of the last borrow state update" - borrowStateBlockNumberOrTimestamp: BigInt! - "Supply last rewarding block or timestamp" - supplyLastRewardingBlockTimestamp: BigInt! - "Borrow last rewarding block or timestamp" - borrowLastRewardingBlockTimestamp: BigInt! + "ID created from the reward distributor and market this speed applies to" + id: Bytes! + "Address of rewards distributor" + rewardsDistributor: RewardsDistributor! + "Address of the market this speed applies to" + market: Market! + "Distribution rate for borrowers" + borrowSpeedPerBlockMantissa: BigInt! + "Distribution rate for suppliers" + supplySpeedPerBlockMantissa: BigInt! + "Index of the last supply state update" + supplyStateIndex: BigInt! + "Timestamp or block number of the last supply state update" + supplyStateBlockNumberOrTimestamp: BigInt! + "Index of the last borrow state update" + borrowStateIndex: BigInt! + "Timestamp or block number of the last borrow state update" + borrowStateBlockNumberOrTimestamp: BigInt! + "Supply last rewarding block or timestamp" + supplyLastRewardingBlockTimestamp: BigInt! + "Borrow last rewarding block or timestamp" + borrowLastRewardingBlockTimestamp: BigInt! } diff --git a/subgraphs/isolated-pools/src/mappings/vToken.ts b/subgraphs/isolated-pools/src/mappings/vToken.ts index 38911c95..1cf0d635 100644 --- a/subgraphs/isolated-pools/src/mappings/vToken.ts +++ b/subgraphs/isolated-pools/src/mappings/vToken.ts @@ -17,6 +17,7 @@ import { ReservesAdded, SpreadReservesReduced, Transfer, + VToken, } from '../../generated/PoolRegistry/VToken'; import { VToken as VTokenContract } from '../../generated/PoolRegistry/VToken'; import { nullAddress } from '../constants/addresses'; @@ -31,12 +32,14 @@ import { createTransferTransaction, } from '../operations/create'; import { getMarket } from '../operations/get'; -import { getOrCreateAccount } from '../operations/getOrCreate'; +import { getOrCreateAccount, getOrCreateToken } from '../operations/getOrCreate'; import { updateMarketPositionBorrow, updateMarketPositionSupply, updateMarket, } from '../operations/update'; +import { updateMarketRates } from '../operations/updateMarketRates'; +import getTokenPriceInCents from '../utilities/getTokenPriceInCents'; /* Account supplies assets into market and receives vTokens in exchange * @@ -329,6 +332,16 @@ export function handleReservesAdded(event: ReservesAdded): void { const market = getMarket(vTokenAddress); if (market) { market.reservesMantissa = event.params.newTotalReserves; + + const marketContract = VToken.bind(vTokenAddress); + const underlyingToken = getOrCreateToken(Address.fromBytes(market.underlyingToken)); + const underlyingPriceCents = getTokenPriceInCents( + Address.fromBytes(market.pool), + vTokenAddress, + underlyingToken.decimals, + ); + updateMarketRates(market, marketContract, underlyingPriceCents, event.block.number); + market.save(); } } @@ -338,6 +351,16 @@ export function handleSpreadReservesReduced(event: SpreadReservesReduced): void const market = getMarket(vTokenAddress); if (market) { market.reservesMantissa = event.params.newTotalReserves; + + const marketContract = VToken.bind(vTokenAddress); + const underlyingToken = getOrCreateToken(Address.fromBytes(market.underlyingToken)); + const underlyingPriceCents = getTokenPriceInCents( + Address.fromBytes(market.pool), + vTokenAddress, + underlyingToken.decimals, + ); + updateMarketRates(market, marketContract, underlyingPriceCents, event.block.number); + market.save(); } } diff --git a/subgraphs/isolated-pools/src/operations/create.ts b/subgraphs/isolated-pools/src/operations/create.ts index 7be7beab..5651753b 100644 --- a/subgraphs/isolated-pools/src/operations/create.ts +++ b/subgraphs/isolated-pools/src/operations/create.ts @@ -23,6 +23,9 @@ import { Pool, RewardsDistributor, Transaction, + MarketRatesData, + MarketSupplyPositionData, + MarketBorrowPositionData, } from '../../generated/schema'; import { Comptroller } from '../../generated/templates/Pool/Comptroller'; import { RewardsDistributor as RewardDistributorContract } from '../../generated/templates/RewardsDistributor/RewardsDistributor'; @@ -341,3 +344,49 @@ export function createRewardDistributor( } return rewardsDistributor; } + +export function createMarketRatesData( + marketAddress: Address, + blockNumber: BigInt, + exchangeRateMantissa: BigInt, + supplyRateMantissa: BigInt, + borrowRateMantissa: BigInt, + underlyingPriceCents: BigInt, +): void { + const marketRatesEntity = new MarketRatesData('auto'); + marketRatesEntity.market = marketAddress; + marketRatesEntity.exchangeRateMantissa = exchangeRateMantissa; + marketRatesEntity.supplyRateMantissa = supplyRateMantissa; + marketRatesEntity.borrowRateMantissa = borrowRateMantissa; + marketRatesEntity.blockNumber = blockNumber; + marketRatesEntity.underlyingPriceCents = underlyingPriceCents; + marketRatesEntity.save(); +} + +export function createMarketSupplyPositionData( + marketAddress: Address, + accountAddress: Address, + blockNumber: BigInt, + vTokenBalanceMantissa: BigInt, +): void { + const marketSupplyPositionEntity = new MarketSupplyPositionData('auto'); + marketSupplyPositionEntity.market = marketAddress; + marketSupplyPositionEntity.account = accountAddress; + marketSupplyPositionEntity.blockNumber = blockNumber; + marketSupplyPositionEntity.vTokenBalanceMantissa = vTokenBalanceMantissa; + marketSupplyPositionEntity.save(); +} + +export function createMarketBorrowPositionData( + marketAddress: Address, + accountAddress: Address, + blockNumber: BigInt, + borrowBalanceMantissa: BigInt, +): void { + const marketBorrowPositionEntity = new MarketBorrowPositionData('auto'); + marketBorrowPositionEntity.market = marketAddress; + marketBorrowPositionEntity.account = accountAddress; + marketBorrowPositionEntity.blockNumber = blockNumber; + marketBorrowPositionEntity.borrowBalanceMantissa = borrowBalanceMantissa; + marketBorrowPositionEntity.save(); +} diff --git a/subgraphs/isolated-pools/src/operations/update.ts b/subgraphs/isolated-pools/src/operations/update.ts index 0cc8ba76..25ace362 100644 --- a/subgraphs/isolated-pools/src/operations/update.ts +++ b/subgraphs/isolated-pools/src/operations/update.ts @@ -13,6 +13,8 @@ import { getOrCreateToken, } from './getOrCreate'; import { oneBigInt, zeroBigInt32 } from '../constants'; +import { updateMarketRates } from './updateMarketRates'; +import { createMarketSupplyPositionData } from './create'; export const updateMarketPositionAccrualBlockNumber = ( accountAddress: Address, @@ -49,11 +51,19 @@ export const updateMarketPositionSupply = ( Address.fromBytes(market.pool), blockNumber, ); + if (marketPosition) { const _vTokenBalanceMantissa = marketPosition.vTokenBalanceMantissa; marketPosition.vTokenBalanceMantissa = accountSupplyBalanceMantissa; marketPosition.save(); + createMarketSupplyPositionData( + marketAddress, + accountAddress, + blockNumber, + accountSupplyBalanceMantissa, + ); + if ( _vTokenBalanceMantissa.equals(zeroBigInt32) && accountSupplyBalanceMantissa.notEqual(zeroBigInt32) @@ -86,6 +96,7 @@ export const updateMarketPositionBorrow = ( Address.fromBytes(market.pool), blockNumber, ); + if (marketPosition) { const _storedBorrowBalanceMantissa = marketPosition.storedBorrowBalanceMantissa; marketPosition.storedBorrowBalanceMantissa = accountBorrows; @@ -93,6 +104,8 @@ export const updateMarketPositionBorrow = ( marketPosition.borrowIndex = vTokenContract.borrowIndex(); marketPosition.save(); + updateMarketPositionBorrow(accountAddress, marketAddress, blockNumber, accountBorrows); + if ( _storedBorrowBalanceMantissa.equals(zeroBigInt32) && accountBorrows.notEqual(zeroBigInt32) @@ -134,23 +147,12 @@ export const updateMarket = (vTokenAddress: Address, blockNumber: BigInt): Marke marketContract.try_accrualBlockNumber(), ); - const exchangeRateMantissa = valueOrNotAvailableIntIfReverted( - marketContract.try_exchangeRateStored(), - ); - market.exchangeRateMantissa = exchangeRateMantissa; - market.reservesMantissa = valueOrNotAvailableIntIfReverted(marketContract.try_totalReserves()); const cashBigInt = valueOrNotAvailableIntIfReverted(marketContract.try_getCash()); market.cashMantissa = cashBigInt; - // calling supplyRatePerBlock & borrowRatePerBlock can fail due to external reasons, so we fall back to 0 in case of an error - market.borrowRateMantissa = valueOrNotAvailableIntIfReverted( - marketContract.try_borrowRatePerBlock(), - ); - market.supplyRateMantissa = valueOrNotAvailableIntIfReverted( - marketContract.try_supplyRatePerBlock(), - ); + updateMarketRates(market, marketContract, tokenPriceCents, blockNumber); market.save(); return market; diff --git a/subgraphs/isolated-pools/src/operations/updateMarketBorrowRate.ts b/subgraphs/isolated-pools/src/operations/updateMarketBorrowRate.ts new file mode 100644 index 00000000..dea8d00e --- /dev/null +++ b/subgraphs/isolated-pools/src/operations/updateMarketBorrowRate.ts @@ -0,0 +1,11 @@ +import { BigInt } from '@graphprotocol/graph-ts'; +import { Market } from '../../generated/schema'; +import { VToken } from '../../generated/templates/VToken/VToken'; +import { valueOrNotAvailableIntIfReverted } from '../utilities'; + +export function updateMarketBorrowRate(market: Market, vTokenContract: VToken): BigInt { + market.borrowRateMantissa = valueOrNotAvailableIntIfReverted( + vTokenContract.try_borrowRatePerBlock(), + ); + return market.borrowRateMantissa; +} diff --git a/subgraphs/isolated-pools/src/operations/updateMarketExchangeRate.ts b/subgraphs/isolated-pools/src/operations/updateMarketExchangeRate.ts new file mode 100644 index 00000000..38f61e99 --- /dev/null +++ b/subgraphs/isolated-pools/src/operations/updateMarketExchangeRate.ts @@ -0,0 +1,11 @@ +import { BigInt } from '@graphprotocol/graph-ts'; +import { Market } from '../../generated/schema'; +import { VToken } from '../../generated/templates/VToken/VToken'; +import { valueOrNotAvailableIntIfReverted } from '../utilities'; + +export function updateMarketExchangeRate(market: Market, vTokenContract: VToken): BigInt { + market.exchangeRateMantissa = valueOrNotAvailableIntIfReverted( + vTokenContract.try_exchangeRateStored(), + ); + return market.exchangeRateMantissa; +} diff --git a/subgraphs/isolated-pools/src/operations/updateMarketRates.ts b/subgraphs/isolated-pools/src/operations/updateMarketRates.ts new file mode 100644 index 00000000..669867d3 --- /dev/null +++ b/subgraphs/isolated-pools/src/operations/updateMarketRates.ts @@ -0,0 +1,29 @@ +import { Address, BigInt } from '@graphprotocol/graph-ts'; +import { Market } from '../../generated/schema'; +import { VToken } from '../../generated/templates/VToken/VToken'; +import { createMarketRatesData } from './create'; +import { updateMarketBorrowRate } from './updateMarketBorrowRate'; +import { updateMarketExchangeRate } from './updateMarketExchangeRate'; +import { updateMarketSupplyRate } from './updateMarketSupplyRate'; + +// if an event updated the market reserves, it means we need to update the market rates that depend on it: +// borrow rate, supply rate and the exchange rate +export function updateMarketRates( + market: Market, + vTokenContract: VToken, + underlyingPriceCents: BigInt, + blockNumber: BigInt, +): void { + const borrowRate = updateMarketBorrowRate(market, vTokenContract); + const supplyRate = updateMarketSupplyRate(market, vTokenContract); + const exchangeRate = updateMarketExchangeRate(market, vTokenContract); + + createMarketRatesData( + Address.fromBytes(market.address), + blockNumber, + exchangeRate, + supplyRate, + borrowRate, + underlyingPriceCents, + ); +} diff --git a/subgraphs/isolated-pools/src/operations/updateMarketSupplyRate.ts b/subgraphs/isolated-pools/src/operations/updateMarketSupplyRate.ts new file mode 100644 index 00000000..88d31857 --- /dev/null +++ b/subgraphs/isolated-pools/src/operations/updateMarketSupplyRate.ts @@ -0,0 +1,12 @@ +import { BigInt } from '@graphprotocol/graph-ts'; +import { Market } from '../../generated/schema'; +import { VToken } from '../../generated/templates/VToken/VToken'; +import { valueOrNotAvailableIntIfReverted } from '../utilities'; + +export function updateMarketSupplyRate(market: Market, vTokenContract: VToken): BigInt { + market.supplyRateMantissa = valueOrNotAvailableIntIfReverted( + vTokenContract.try_supplyRatePerBlock(), + ); + + return market.supplyRateMantissa; +}