diff --git a/subgraphs/venus/schema.graphql b/subgraphs/venus/schema.graphql index 4f94809a..5da5e903 100644 --- a/subgraphs/venus/schema.graphql +++ b/subgraphs/venus/schema.graphql @@ -2,104 +2,147 @@ The Comptroller type has protocol level variables stored """ type Comptroller @entity { - "ID is set to comptroller address" - id: Bytes! - "Comptroller Address" - address: Bytes! - "Address of price oracle the comptroller uses" - priceOracle: Bytes! - "Factor used to determine repayAmount for liquidating" - closeFactorMantissa: BigInt! - "The percent bonus liquidators get for liquidating" - liquidationIncentive: BigInt! + "ID is set to comptroller address" + id: Bytes! + "Comptroller Address" + address: Bytes! + "Address of price oracle the comptroller uses" + priceOracle: Bytes! + "Factor used to determine repayAmount for liquidating" + closeFactorMantissa: BigInt! + "The percent bonus liquidators get for liquidating" + liquidationIncentive: 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! + "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 """ type Market @entity { - "VToken address" - id: Bytes! - "Vtoken Address" - address: Bytes! - "vToken decimal length" - vTokenDecimals: Int! - "Name of the vToken" - name: String! - "VToken symbol" - symbol: String! - "Flag indicating if the market 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! - "Borrows in the market" - totalBorrowsMantissa: BigInt! - "Total vToken supplied" - totalSupplyVTokenMantissa: BigInt! - "Underlying Token" - underlyingToken: Token! - "XVS Supply Distribution Block" - xvsSupplyStateBlock: BigInt! - "XVS Supply Distribution Index" - xvsSupplyStateIndex: BigInt! - "XVS Reward Distribution Block" - xvsBorrowStateBlock: BigInt! - "XVS Reward Distribution Index" - xvsBorrowStateIndex: BigInt! - "The rate at which XVS is distributed to the corresponding supply market (per block)" - xvsSupplySpeed: BigInt! - "The rate at which XVS is distributed to the corresponding borrow market (per block)" - xvsBorrowSpeed: BigInt! + "VToken address" + id: Bytes! + "Vtoken Address" + address: Bytes! + "vToken decimal length" + vTokenDecimals: Int! + "Name of the vToken" + name: String! + "VToken symbol" + symbol: String! + "Flag indicating if the market 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! + "Borrows in the market" + totalBorrowsMantissa: BigInt! + "Total vToken supplied" + totalSupplyVTokenMantissa: BigInt! + "Underlying Token" + underlyingToken: Token! + "XVS Supply Distribution Block" + xvsSupplyStateBlock: BigInt! + "XVS Supply Distribution Index" + xvsSupplyStateIndex: BigInt! + "XVS Reward Distribution Block" + xvsBorrowStateBlock: BigInt! + "XVS Reward Distribution Index" + xvsBorrowStateIndex: BigInt! + "The rate at which XVS is distributed to the corresponding supply market (per block)" + xvsSupplySpeed: BigInt! + "The rate at which XVS is distributed to the corresponding borrow market (per block)" + xvsBorrowSpeed: 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! - "Last recorded Underlying token price in USD cents" - lastUnderlyingPriceCents: BigInt! - "Block price was last updated" - lastUnderlyingPriceBlockNumber: BigInt! - "Total XVS Distributed for this market" - totalXvsDistributedMantissa: 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! + "Last recorded Underlying token price in USD cents" + lastUnderlyingPriceCents: BigInt! + "Block price was last updated" + lastUnderlyingPriceBlockNumber: BigInt! + "Total XVS Distributed for this market" + totalXvsDistributedMantissa: BigInt! - "Number of accounts currently supplying to this market" - supplierCount: BigInt! + "Number of accounts currently supplying to this market" + supplierCount: BigInt! - "Number of accounts currently borrowing from this market" - borrowerCount: BigInt! + "Number of accounts currently borrowing from this market" + borrowerCount: 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") } """ @@ -107,54 +150,90 @@ Account is an BNB address, with a list of all vToken markets the account has participated in, along with liquidation information. """ type Account @entity { - "Account address" - id: Bytes! - "Account address" - address: Bytes! - "Array of VTokens user is in" - tokens: [MarketPosition!]! @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! + "Account address" + id: Bytes! + "Account address" + address: Bytes! + "Array of VTokens user is in" + tokens: [MarketPosition!]! @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! } """ MarketPosition is a single account within a single vToken market """ type MarketPosition @entity { - "Concatenation of VToken address and user address" - id: Bytes! - "Relation to market" - market: Market! - "Relation to user" - account: Account! - "Block the position is updated to" - accrualBlockNumber: BigInt! - "Borrow Index this position last accrued interest" - borrowIndex: BigInt! - "True if user is entered, false if they are exited" - enteredMarket: Boolean! - "VToken balance of the user" - vTokenBalanceMantissa: BigInt! - "Total amount of underlying redeemed" - totalUnderlyingRedeemedMantissa: BigInt! - "Total amount underlying repaid" - totalUnderlyingRepaidMantissa: BigInt! - "Stored borrow balance stored in contract (exclusive of interest since accrualBlockNumber)" - storedBorrowBalanceMantissa: BigInt! + "Concatenation of VToken address and user address" + id: Bytes! + "Relation to market" + market: Market! + "Relation to user" + account: Account! + "Block the position is updated to" + accrualBlockNumber: BigInt! + "Borrow Index this position last accrued interest" + borrowIndex: BigInt! + "True if user is entered, false if they are exited" + enteredMarket: Boolean! + "VToken balance of the user" + vTokenBalanceMantissa: BigInt! + "Total amount of underlying redeemed" + totalUnderlyingRedeemedMantissa: BigInt! + "Total amount underlying repaid" + totalUnderlyingRepaidMantissa: BigInt! + "Stored borrow balance stored in contract (exclusive of interest since accrualBlockNumber)" + storedBorrowBalanceMantissa: 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! } enum EventType { - MINT - MINT_BEHALF - REDEEM - BORROW - TRANSFER - LIQUIDATE - REPAY + MINT + MINT_BEHALF + REDEEM + BORROW + TRANSFER + LIQUIDATE + REPAY } """ @@ -162,18 +241,18 @@ An interface for a transfer of any vToken. TransferEvent, MintEvent, RedeemEvent, and LiquidationEvent all use this interface """ type Transaction @entity { - "Transaction hash concatenated with log index" - id: Bytes! - "enum of event type" - type: EventType! - "The account that sent the tokens, usually 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 tokens, usually vToken" + from: Bytes! + "count of vTokens transferred" + amountMantissa: BigInt! + "Account that received tokens" + to: Bytes! + "Block number" + blockNumber: Int! + "Block time" + blockTime: Int! } diff --git a/subgraphs/venus/src/mappings/vToken.ts b/subgraphs/venus/src/mappings/vToken.ts index fa974477..965c21a1 100644 --- a/subgraphs/venus/src/mappings/vToken.ts +++ b/subgraphs/venus/src/mappings/vToken.ts @@ -283,11 +283,13 @@ export function handleAccrueInterest(event: AccrueInterest): void { market.totalBorrowsMantissa = event.params.totalBorrows; updateMarketCashMantissa(market, vTokenContract); const underlyingToken = getOrCreateToken(Address.fromBytes(market.underlyingToken)); - market.lastUnderlyingPriceCents = getUnderlyingPrice(marketAddress, underlyingToken.decimals); + const underlyingPriceCents = getUnderlyingPrice(marketAddress, underlyingToken.decimals); + market.lastUnderlyingPriceCents = underlyingPriceCents; market.lastUnderlyingPriceBlockNumber = event.block.number; - - updateMarketRates(market, vTokenContract); market.reservesMantissa = vTokenContract.totalReserves(); + + updateMarketRates(market, vTokenContract, underlyingPriceCents, event.block.number); + market.save(); } @@ -370,9 +372,12 @@ export function handleRedeemV1(event: RedeemV1): void { export function handleReservesAdded(event: ReservesAdded): void { const marketAddress = event.address; const market = getOrCreateMarket(event.address, event); - const vTokenContract = VToken.bind(marketAddress); market.reservesMantissa = event.params.newTotalReserves; - updateMarketRates(market, vTokenContract); + + const vTokenContract = VToken.bind(marketAddress); + const underlyingToken = getOrCreateToken(Address.fromBytes(market.underlyingToken)); + const underlyingPriceCents = getUnderlyingPrice(marketAddress, underlyingToken.decimals); + updateMarketRates(market, vTokenContract, underlyingPriceCents, event.block.number); market.save(); } @@ -383,7 +388,10 @@ export function handleReservesReduced(event: ReservesReduced): void { const vTokenContract = VToken.bind(marketAddress); market.reservesMantissa = event.params.newTotalReserves; - updateMarketRates(market, vTokenContract); + + const underlyingToken = getOrCreateToken(Address.fromBytes(market.underlyingToken)); + const underlyingPriceCents = getUnderlyingPrice(marketAddress, underlyingToken.decimals); + updateMarketRates(market, vTokenContract, underlyingPriceCents, event.block.number); market.save(); } diff --git a/subgraphs/venus/src/operations/create.ts b/subgraphs/venus/src/operations/create.ts index a1907845..12be05a3 100644 --- a/subgraphs/venus/src/operations/create.ts +++ b/subgraphs/venus/src/operations/create.ts @@ -1,4 +1,10 @@ -import { Transaction } from '../../generated/schema'; +import { Address, BigInt } from '@graphprotocol/graph-ts'; +import { + MarketBorrowPositionData, + MarketRatesData, + MarketSupplyPositionData, + Transaction, +} from '../../generated/schema'; import { BORROW, LIQUIDATE, MINT, MINT_BEHALF, REDEEM, REPAY, TRANSFER } from '../constants'; import { getTransactionId } from '../utilities/ids'; @@ -90,3 +96,49 @@ export function createTransferEvent(event: E): void { transaction.blockTime = event.block.timestamp.toI32(); transaction.save(); } + +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/venus/src/operations/getOrCreate.ts b/subgraphs/venus/src/operations/getOrCreate.ts index 2d4eef79..5b49e5e2 100644 --- a/subgraphs/venus/src/operations/getOrCreate.ts +++ b/subgraphs/venus/src/operations/getOrCreate.ts @@ -74,7 +74,8 @@ export function getOrCreateMarket(marketAddress: Address, event: ethereum.Event) 'vBEP20 try_reserveFactorMantissa()', ); const underlyingToken = getOrCreateToken(Address.fromBytes(market.underlyingToken)); - market.lastUnderlyingPriceCents = getUnderlyingPrice(marketAddress, underlyingToken.decimals); + const underlyingPriceCents = getUnderlyingPrice(marketAddress, underlyingToken.decimals); + market.lastUnderlyingPriceCents = underlyingPriceCents; market.lastUnderlyingPriceBlockNumber = event.block.number; market.accrualBlockNumber = vTokenContract.accrualBlockNumber(); @@ -83,7 +84,7 @@ export function getOrCreateMarket(marketAddress: Address, event: ethereum.Event) market.supplierCount = zeroBigInt32; market.borrowerCount = zeroBigInt32; - updateMarketRates(market, vTokenContract); + updateMarketRates(market, vTokenContract, underlyingPriceCents, event.block.number); updateMarketCashMantissa(market, vTokenContract); market.totalSupplyVTokenMantissa = zeroBigInt32; market.borrowIndex = valueOrNotAvailableIntIfReverted( diff --git a/subgraphs/venus/src/operations/update.ts b/subgraphs/venus/src/operations/update.ts index d8460fec..12765b3d 100644 --- a/subgraphs/venus/src/operations/update.ts +++ b/subgraphs/venus/src/operations/update.ts @@ -6,6 +6,7 @@ import { valueOrNotAvailableIntIfReverted } from '../utilities'; import { getMarket } from './get'; import { getOrCreateAccount, getOrCreateMarketPosition } from './getOrCreate'; import { oneBigInt, zeroBigInt32 } from '../constants'; +import { createMarketBorrowPositionData, createMarketSupplyPositionData } from './create'; export const updateMarketPositionAccrualBlockNumber = ( accountAddress: Address, @@ -35,6 +36,13 @@ export const updateMarketPositionSupply = ( marketPosition.vTokenBalanceMantissa = accountSupplyBalanceMantissa; marketPosition.save(); + createMarketSupplyPositionData( + marketAddress, + accountAddress, + blockNumber, + accountSupplyBalanceMantissa, + ); + if ( _vTokenBalanceMantissa.equals(zeroBigInt32) && accountSupplyBalanceMantissa.notEqual(zeroBigInt32) @@ -71,6 +79,8 @@ export const updateMarketPositionBorrow = ( ); marketPosition.save(); + createMarketBorrowPositionData(marketAddress, accountAddress, blockNumber, accountBorrows); + if (_storedBorrowBalanceMantissa.equals(zeroBigInt32) && accountBorrows.notEqual(zeroBigInt32)) { market.borrowerCount = market.borrowerCount.plus(oneBigInt); } else if ( diff --git a/subgraphs/venus/src/operations/updateMarketBorrowRate.ts b/subgraphs/venus/src/operations/updateMarketBorrowRate.ts index 843abc92..691f8111 100644 --- a/subgraphs/venus/src/operations/updateMarketBorrowRate.ts +++ b/subgraphs/venus/src/operations/updateMarketBorrowRate.ts @@ -1,10 +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 updateMarketBorrowRate(market: Market, vTokenContract: VToken): void { +export function updateMarketBorrowRate(market: Market, vTokenContract: VToken): BigInt { market.borrowRateMantissa = valueOrNotAvailableIntIfReverted( vTokenContract.try_borrowRatePerBlock(), 'vBEP20 try_borrowRatePerBlock()', ); + return market.borrowRateMantissa; } diff --git a/subgraphs/venus/src/operations/updateMarketExchangeRate.ts b/subgraphs/venus/src/operations/updateMarketExchangeRate.ts index bf56bb11..966c5d64 100644 --- a/subgraphs/venus/src/operations/updateMarketExchangeRate.ts +++ b/subgraphs/venus/src/operations/updateMarketExchangeRate.ts @@ -1,3 +1,4 @@ +import { BigInt } from '@graphprotocol/graph-ts'; import { Market } from '../../generated/schema'; import { VToken } from '../../generated/templates/VToken/VToken'; import { valueOrNotAvailableIntIfReverted } from '../utilities'; @@ -12,9 +13,10 @@ import { valueOrNotAvailableIntIfReverted } from '../utilities'; - Must multiply by vtokenDecimals, 10^8 - Must div by mantissa, 10^18 */ -export function updateMarketExchangeRate(market: Market, vTokenContract: VToken): void { +export function updateMarketExchangeRate(market: Market, vTokenContract: VToken): BigInt { market.exchangeRateMantissa = valueOrNotAvailableIntIfReverted( vTokenContract.try_exchangeRateStored(), 'vBEP20 try_exchangeRateStored()', ); + return market.exchangeRateMantissa; } diff --git a/subgraphs/venus/src/operations/updateMarketRates.ts b/subgraphs/venus/src/operations/updateMarketRates.ts index 013dfa65..669867d3 100644 --- a/subgraphs/venus/src/operations/updateMarketRates.ts +++ b/subgraphs/venus/src/operations/updateMarketRates.ts @@ -1,13 +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): void { - updateMarketBorrowRate(market, vTokenContract); - updateMarketSupplyRate(market, vTokenContract); - updateMarketExchangeRate(market, vTokenContract); +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/venus/src/operations/updateMarketSupplyRate.ts b/subgraphs/venus/src/operations/updateMarketSupplyRate.ts index d6d7a8dc..73336a6b 100644 --- a/subgraphs/venus/src/operations/updateMarketSupplyRate.ts +++ b/subgraphs/venus/src/operations/updateMarketSupplyRate.ts @@ -1,12 +1,15 @@ +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): void { +export function updateMarketSupplyRate(market: Market, vTokenContract: VToken): BigInt { // This fails on only the first call to cZRX. It is unclear why, but otherwise it works. // So we handle it like this. market.supplyRateMantissa = valueOrNotAvailableIntIfReverted( vTokenContract.try_supplyRatePerBlock(), 'vBEP20 try_supplyRatePerBlock()', ); + + return market.supplyRateMantissa; }