Skip to content

Commit

Permalink
Update NAV calculations (#179)
Browse files Browse the repository at this point in the history
* feat: update NAV calculations

* fix: update schema

* fix: duplication in schema

* fix: cash asset value name

* fix: explicit big ints

* fix: init values

* fix: remove faulty casts
  • Loading branch information
hieronx authored May 31, 2024
1 parent ba03d80 commit 90d22c3
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 41 deletions.
24 changes: 13 additions & 11 deletions schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,15 @@ type Pool @entity {
lastEpochClosed: Int
lastEpochExecuted: Int

#States
portfolioValuation: BigInt
# NAV == totalReserve + offchainCashValue + portfolioValuation - sumPoolFeesPendingAmount
netAssetValue: BigInt # previously: portfolioValuation
totalReserve: BigInt
offchainCashValue: BigInt # previously: cashAssetValue
portfolioValuation: BigInt

availableReserve: BigInt
maxReserve: BigInt
sumDebt: BigInt
value: BigInt
cashAssetValue: BigInt


# Aggregated transaction data over the last period
sumBorrowedAmountByPeriod: BigInt
sumRepaidAmountByPeriod: BigInt
Expand All @@ -52,6 +52,7 @@ type Pool @entity {
sumNumberOfAssetsByPeriod: BigInt

sumNumberOfActiveAssets: BigInt
sumDebt: BigInt
sumDebtOverdue: BigInt
sumDebtWrittenOffByPeriod: BigInt
deltaPortfolioValuationByPeriod: BigInt
Expand Down Expand Up @@ -87,14 +88,14 @@ type PoolSnapshot @entity {
periodStart: Date! @index

#States
portfolioValuation: BigInt
netAssetValue: BigInt # previously: portfolioValuation
totalReserve: BigInt
offchainCashValue: BigInt # previously: cashAssetValue
portfolioValuation: BigInt

availableReserve: BigInt
maxReserve: BigInt
sumDebt: BigInt
value: BigInt
cashAssetValue: BigInt


# Aggregated transaction data over the last period
sumBorrowedAmountByPeriod: BigInt
sumRepaidAmountByPeriod: BigInt
Expand All @@ -107,6 +108,7 @@ type PoolSnapshot @entity {
sumNumberOfAssetsByPeriod: BigInt

sumNumberOfActiveAssets: BigInt
sumDebt: BigInt
sumDebtOverdue: BigInt
sumDebtWrittenOffByPeriod: BigInt
deltaPortfolioValuationByPeriod: BigInt
Expand Down
7 changes: 3 additions & 4 deletions src/mappings/handlers/blockHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@ async function _handleBlock(block: SubstrateBlock): Promise<void> {
const pools = await PoolService.getCfgActivePools()
for (const pool of pools) {
await pool.updateState()
await pool.updatePortfolioValuation()
await pool.computePoolValue()
await pool.updateNAV()
await pool.resetDebtOverdue()

// Update tranche states
Expand All @@ -62,14 +61,14 @@ async function _handleBlock(block: SubstrateBlock): Promise<void> {
}
// Asset operations
const activeLoanData = await pool.getPortfolio()
pool.resetCashAssetValue()
pool.resetOffchainCashValue()
for (const loanId in activeLoanData) {
const asset = await AssetService.getById(pool.id, loanId)
await asset.updateActiveAssetData(activeLoanData[loanId])
await pool.increaseInterestAccrued(asset.interestAccruedByPeriod)
await asset.save()
if (asset.actualMaturityDate < block.timestamp) pool.increaseDebtOverdue(asset.outstandingDebt)
if (asset.isOffchainCash()) pool.increaseCashAssetValue(asset.presentValue)
if (asset.isOffchainCash()) pool.increaseOffchainCashValue(asset.presentValue)
}
await pool.updateNumberOfActiveAssets(BigInt(Object.keys(activeLoanData).length))

Expand Down
10 changes: 5 additions & 5 deletions src/mappings/handlers/ethHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,11 @@ async function _handleEthBlock(block: EthereumBlock): Promise<void> {
const poolUpdateCalls: PoolMulticall[] = []
for (const tinlakePool of tinlakePools) {
if (block.number >= tinlakePool.startBlock) {
const pool = await PoolService.getOrSeed(tinlakePool.id, false, blockchain.id)
const pool = await PoolService.getOrSeed(tinlakePool.id, false, blockchain.id)

// initialize new pool
if (!pool.isActive) {
pool.name = tinlakePool.shortName
pool.totalReserve = BigInt(0)
pool.portfolioValuation = BigInt(0)
pool.isActive = true
pool.currencyId = currency.id
await pool.save()
Expand Down Expand Up @@ -100,6 +98,7 @@ async function _handleEthBlock(block: EthereumBlock): Promise<void> {
callResult.result
)[0]
pool.portfolioValuation = currentNAV.toBigInt()
pool.netAssetValue = (pool.portfolioValuation || BigInt(0)) + (pool.totalReserve || BigInt(0))
await pool.save()
logger.info(`Updating pool ${tinlakePool?.id} with portfolioValuation: ${pool.portfolioValuation}`)
}
Expand All @@ -109,12 +108,13 @@ async function _handleEthBlock(block: EthereumBlock): Promise<void> {
callResult.result
)[0]
pool.totalReserve = totalBalance.toBigInt()
pool.netAssetValue = (pool.portfolioValuation || BigInt(0)) + (pool.totalReserve || BigInt(0))
await pool.save()
logger.info(`Updating pool ${tinlakePool?.id} with totalReserve: ${pool.totalReserve}`)
}

// Update loans (only index if fully synced)
if (latestNavFeed && date.toDateString() === (new Date()).toDateString()) {
if (latestNavFeed && date.toDateString() === new Date().toDateString()) {
await updateLoans(
tinlakePool?.id as string,
date,
Expand All @@ -127,7 +127,7 @@ async function _handleEthBlock(block: EthereumBlock): Promise<void> {
}

// Take snapshots
await evmStateSnapshotter<Pool,PoolSnapshot>(Pool, PoolSnapshot, block, 'isActive', true, 'poolId')
await evmStateSnapshotter<Pool, PoolSnapshot>(Pool, PoolSnapshot, block, 'isActive', true, 'poolId')
//await evmStateSnapshotter<Asset,AssetSnapshot>('Asset', 'AssetSnapshot', block, 'isActive', true, 'assetId')

//Update tracking of period and continue
Expand Down
2 changes: 1 addition & 1 deletion src/mappings/services/poolService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ describe('Given a new pool, when initialised', () => {

describe('Given an existing pool,', () => {
test.skip('when the nav is updated, then the value is fetched and set correctly', async () => {
await pool.updatePortfolioValuation()
await pool.updateNAV()
expect(api.query.loans.portfolioValuation).toHaveBeenCalled()
expect(pool.portfolioValuation).toBe(BigInt(100000000000000))
})
Expand Down
46 changes: 26 additions & 20 deletions src/mappings/services/poolService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,15 @@ export class PoolService extends Pool {

this.currentEpoch = 1

this.portfolioValuation = BigInt(0)
this.netAssetValue = BigInt(0)
this.totalReserve = BigInt(0)
this.offchainCashValue = BigInt(0)
this.portfolioValuation = BigInt(0)

this.availableReserve = BigInt(0)
this.maxReserve = maxReserve

this.sumDebt = BigInt(0)
this.value = BigInt(0)
this.cashAssetValue = BigInt(0)

this.sumNumberOfActiveAssets = BigInt(0)
this.sumDebtOverdue = BigInt(0)
Expand Down Expand Up @@ -161,40 +162,50 @@ export class PoolService extends Pool {
return this
}

public updatePortfolioValuation() {
public updateNAV() {
const specVersion = api.runtimeVersion.specVersion.toNumber()
const specName = api.runtimeVersion.specName.toString()
switch (specName) {
case 'centrifuge-devel':
return specVersion < 1038 ? this.updatePortfolioValuationQuery() : this.updatePortfolioValuationCall()
return specVersion < 1038 ? this.updateNAVQuery() : this.updateNAVCall()
default:
return specVersion < 1025 ? this.updatePortfolioValuationQuery() : this.updatePortfolioValuationCall()
return specVersion < 1025 ? this.updateNAVQuery() : this.updateNAVCall()
}
}

private async updatePortfolioValuationQuery() {
private async updateNAVQuery() {
logger.info(`Updating portfolio valuation for pool: ${this.id} (state)`)
const navResponse = await api.query.loans.portfolioValuation<NavDetails>(this.id)
const newPortfolioValuation = navResponse.value.toBigInt()

this.deltaPortfolioValuationByPeriod = newPortfolioValuation - this.portfolioValuation
this.portfolioValuation = newPortfolioValuation

// The query was only used before either offchain cash assets or fees were introduced,
// so NAV == portfolioValuation + totalReserve
this.netAssetValue = newPortfolioValuation + this.totalReserve

logger.info(
`portfolio valuation: ${this.portfolioValuation.toString(10)} delta: ${this.deltaPortfolioValuationByPeriod}`
)
return this
}

private async updatePortfolioValuationCall() {
private async updateNAVCall() {
logger.info(`Updating portfolio valuation for pool: ${this.id} (runtime)`)
const apiCall = api.call as ExtendedCall
const navResponse = await apiCall.poolsApi.nav(this.id)
if (navResponse.isEmpty) {
logger.warn('Empty pv response')
return
}
const newPortfolioValuation = navResponse.unwrap().total.toBigInt()
const newNAV = navResponse.unwrap().total.toBigInt()
const newPortfolioValuation = navResponse.unwrap().navAum.toBigInt() - this.offchainCashValue

this.deltaPortfolioValuationByPeriod = newPortfolioValuation - this.portfolioValuation
this.portfolioValuation = newPortfolioValuation
this.netAssetValue = newNAV

logger.info(
`portfolio valuation: ${this.portfolioValuation.toString(10)} delta: ${this.deltaPortfolioValuationByPeriod}`
)
Expand Down Expand Up @@ -252,11 +263,6 @@ export class PoolService extends Pool {
this.lastEpochExecuted = epochId
}

public computePoolValue() {
this.value = this.portfolioValuation + this.totalReserve
logger.info(`Updating pool.value: ${this.value}`)
}

public resetDebtOverdue() {
logger.info('Resetting sumDebtOverdue')
this.sumDebtOverdue = BigInt(0)
Expand Down Expand Up @@ -383,14 +389,14 @@ export class PoolService extends Pool {
return this
}

public resetCashAssetValue() {
logger.info(`Resetting cashAssetValue for pool ${this.id}`)
this.cashAssetValue = BigInt(0)
public resetOffchainCashValue() {
logger.info(`Resetting offchainCashValue for pool ${this.id}`)
this.offchainCashValue = BigInt(0)
}

public increaseCashAssetValue(amount: bigint) {
logger.info(`Increasing cashAssetValue for pool ${this.id} by ${amount.toString(10)}`)
this.cashAssetValue += amount
public increaseOffchainCashValue(amount: bigint) {
logger.info(`Increasing offchainCashValue for pool ${this.id} by ${amount.toString(10)}`)
this.offchainCashValue += amount
}

public updateSumPoolFeesPendingAmount(pendingAmount: bigint) {
Expand Down

0 comments on commit 90d22c3

Please sign in to comment.