Skip to content

Commit

Permalink
feat: track investments and redemptions in onchain cash asset (#188)
Browse files Browse the repository at this point in the history
* chore: rename .env.example

* chore: update schema

* feat: track investments/redemptions in onchain cash asset
Fixes #163
  • Loading branch information
filo87 authored Jun 4, 2024
1 parent 6b12c82 commit aef3249
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 12 deletions.
4 changes: 2 additions & 2 deletions .envrc → .envrc.example
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export COMPOSE_PROFILES=subql-eth
export COMPOSE_PROFILES=subql-cfg
export DB_USER=postgres
export DB_PASS=postgres
export DB_DATABASE=postgres
Expand All @@ -7,4 +7,4 @@ export DB_PORT=5432
export SUBQL_DB_USER=$DB_USER
export SUBQL_DB_PASS=$DB_PASS
export CHAIN_ID="centrifuge"
export ONFINALITY_API_KEY=#ENTER HERE
export ONFINALITY_API_KEY=# TOKEN HERE
7 changes: 6 additions & 1 deletion schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,8 @@ type Epoch @entity {
sumRepaidAmount: BigInt!
sumInvestedAmount: BigInt!
sumRedeemedAmount: BigInt!

sumPoolFeesPaidAmount: BigInt

epochStates: [EpochState] @derivedFrom(field: "epoch")

Expand Down Expand Up @@ -282,6 +284,9 @@ enum AssetTransactionType {
REPAID
CLOSED
CASH_TRANSFER
DEPOSIT_FROM_INVESTMENTS
WITHDRAWAL_FOR_REDEMPTIONS
WITHDRAWAL_FOR_FEES
}

type AssetTransaction @entity {
Expand All @@ -290,7 +295,7 @@ type AssetTransaction @entity {
pool: Pool! @index
hash: String!

account: Account! @index
account: Account @index
epochNumber: Int!
epoch: Epoch! @index
asset: Asset!
Expand Down
6 changes: 6 additions & 0 deletions src/mappings/handlers/poolFeesHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
import { PoolFeeData, PoolFeeService } from '../services/poolFeeService'
import { PoolService } from '../services/poolService'
import { PoolFeeTransactionService } from '../services/poolFeeTransactionService'
import { EpochService } from '../services/epochService'

export const handleFeeProposed = errorHandler(_handleFeeProposed)
async function _handleFeeProposed(event: SubstrateEvent<PoolFeesProposedEvent>): Promise<void> {
Expand Down Expand Up @@ -190,6 +191,11 @@ async function _handleFeePaid(event: SubstrateEvent<PoolFeesPaidEvent>): Promise
await pool.increasePaidFees(poolFeeData.amount)
await pool.save()

const epoch = await EpochService.getById(pool.id, pool.currentEpoch)
if (!poolFee) throw new Error(`Current epoch for pool ${pool.id} not found`)
await epoch.increasePaidFees(poolFeeData.amount)
await epoch.save()

const poolFeeTransaction = PoolFeeTransactionService.pay(poolFeeData)
await poolFeeTransaction.save()
}
43 changes: 38 additions & 5 deletions src/mappings/handlers/poolsHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import { InvestorTransactionService } from '../services/investorTransactionServi
import { CurrencyService, currencyFormatters } from '../services/currencyService'
import { TrancheBalanceService } from '../services/trancheBalanceService'
import { BlockchainService, LOCAL_CHAIN_ID } from '../services/blockchainService'
import { AssetService } from '../services/assetService'
import { AssetService, ONCHAIN_CASH_ASSET_ID } from '../services/assetService'
import { AssetTransactionData, AssetTransactionService } from '../services/assetTransactionService'

export const handlePoolCreated = errorHandler(_handlePoolCreated)
async function _handlePoolCreated(event: SubstrateEvent<PoolCreatedEvent>): Promise<void> {
Expand Down Expand Up @@ -112,9 +113,7 @@ async function _handlePoolUpdated(event: SubstrateEvent<PoolUpdatedEvent>): Prom
export const handleMetadataSet = errorHandler(_handleMetadataSet)
async function _handleMetadataSet(event: SubstrateEvent<PoolMetadataSetEvent>) {
const [poolId, metadata] = event.event.data
logger.info(
`Pool metadata set for pool ${poolId.toString(10)}`
)
logger.info(`Pool metadata set for pool ${poolId.toString(10)}`)
const pool = await PoolService.getById(poolId.toString())
if (!pool) throw missingPool
await pool.updateMetadata(metadata.toUtf8())
Expand Down Expand Up @@ -159,7 +158,7 @@ async function _handleEpochExecuted(event: SubstrateEvent<EpochClosedExecutedEve
)

const pool = await PoolService.getById(poolId.toString())
if (pool === undefined) throw missingPool
if (!pool) throw missingPool

const epoch = await EpochService.getById(poolId.toString(), epochId.toNumber())

Expand Down Expand Up @@ -251,4 +250,38 @@ async function _handleEpochExecuted(event: SubstrateEvent<EpochClosedExecutedEve
}
}
await nextEpoch.saveWithStates()

// Track investments and redemptions for onchain cash
const onChainCashAsset = await AssetService.getById(pool.id, ONCHAIN_CASH_ASSET_ID)
if (!onChainCashAsset) throw new Error(`OnChain Asset not found for ${pool.id}`)
const txData: Omit<AssetTransactionData, 'amount'> = {
poolId: pool.id,
epochNumber: epoch.index,
hash: event.extrinsic.extrinsic.hash.toString(),
timestamp: event.block.timestamp,
assetId: ONCHAIN_CASH_ASSET_ID,
}
const assetTransactionSaves: Array<Promise<void>> = []
if (epoch.sumInvestedAmount > BigInt(0)) {
const deposit = AssetTransactionService.depositFromInvestments({ ...txData, amount: epoch.sumInvestedAmount })
assetTransactionSaves.push(deposit.save())
}

if (epoch.sumRedeemedAmount > BigInt(0)) {
const withdrawalRedemptions = await AssetTransactionService.withdrawalForRedemptions({
...txData,
amount: epoch.sumRedeemedAmount,
})
assetTransactionSaves.push(withdrawalRedemptions.save())
}

if (epoch.sumPoolFeesPaidAmount > BigInt(0)) {
const withdrawalFees = await AssetTransactionService.withdrawalForFees({
...txData,
amount: epoch.sumPoolFeesPaidAmount,
})
assetTransactionSaves.push(withdrawalFees.save())
}

await Promise.all(assetTransactionSaves)
}
34 changes: 30 additions & 4 deletions src/mappings/services/assetTransactionService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { AssetTransaction, AssetTransactionType } from '../../types'
export interface AssetTransactionData {
readonly poolId: string
readonly epochNumber: number
readonly address: string
readonly hash: string
readonly address?: string
readonly amount?: bigint
readonly principalAmount?: bigint
readonly interestAmount?: bigint
Expand All @@ -24,13 +24,12 @@ export class AssetTransactionService extends AssetTransaction {
data.timestamp,
data.poolId,
data.hash,
data.address,
data.epochNumber,
`${data.poolId}-${data.epochNumber.toString(10)}`,
`${data.poolId}-${data.assetId}`,
type
)

tx.accountId = data.address ?? null
tx.amount = data.amount ?? null
tx.principalAmount = data.principalAmount ?? null
tx.interestAmount = data.interestAmount ?? null
Expand Down Expand Up @@ -81,9 +80,36 @@ export class AssetTransactionService extends AssetTransaction {
static cashTransfer(data: AssetTransactionData) {
logger.info(
`Asset transaction of type cash transfer for address ${data.address} in pool ${data.poolId} ` +
`for loan ${data.assetId} amount: ${data.amount}`
`for asset ${data.assetId} amount: ${data.amount}`
)
const tx = this.init(data, AssetTransactionType.CASH_TRANSFER)
return tx
}

static depositFromInvestments(data: AssetTransactionData) {
logger.info(
`Asset transaction of type deposit from investments for address ${data.address} in pool ${data.poolId} ` +
`for asset ${data.assetId} amount: ${data.amount}`
)
const tx = this.init(data, AssetTransactionType.DEPOSIT_FROM_INVESTMENTS)
return tx
}

static withdrawalForRedemptions(data: AssetTransactionData) {
logger.info(
`Asset transaction of type withdrawal for redemptions for address ${data.address} in pool ${data.poolId} ` +
`for asset ${data.assetId} amount: ${data.amount}`
)
const tx = this.init(data, AssetTransactionType.WITHDRAWAL_FOR_REDEMPTIONS)
return tx
}

static withdrawalForFees(data: AssetTransactionData) {
logger.info(
`Asset transaction of type withdrawal for fees for address ${data.address} in pool ${data.poolId} ` +
`for asset ${data.assetId} amount: ${data.amount}`
)
const tx = this.init(data, AssetTransactionType.WITHDRAWAL_FOR_FEES)
return tx
}
}
8 changes: 8 additions & 0 deletions src/mappings/services/epochService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ export class EpochService extends Epoch {
BigInt(0)
)

epoch.sumPoolFeesPaidAmount = BigInt(0)

epoch.states = trancheIds.map(
(trancheId) =>
new EpochState(`${poolId}-${epochNr}-${trancheId}`, epoch.id, trancheId, BigInt(0), BigInt(0), BigInt(0))
Expand Down Expand Up @@ -147,4 +149,10 @@ export class EpochService extends Epoch {
logger.info(`Increasing repayments for epoch ${this.id} of ${amount}`)
this.sumRepaidAmount += amount
}

public increasePaidFees(paidAmount: bigint) {
logger.info(`Increasing paid fees for epoch ${this.id} by ${paidAmount.toString(10)}`)
this.sumPoolFeesPaidAmount += paidAmount
return this
}
}

0 comments on commit aef3249

Please sign in to comment.