Skip to content

Commit 9ec23c4

Browse files
authored
fix: investment positions (#259)
* fix: investment positions * chore: upgrade dependencies * fix: update getByFields arguments
1 parent f3373af commit 9ec23c4

File tree

13 files changed

+492
-298
lines changed

13 files changed

+492
-298
lines changed

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@
3636
"@polkadot/api": "^12",
3737
"@polkadot/typegen": "^12",
3838
"@subql/cli": "^5.2.6",
39-
"@subql/common-substrate": "latest",
39+
"@subql/common-substrate": "^4.3.2",
4040
"@subql/node-ethereum": "^5.1.3",
41-
"@subql/testing": "latest",
42-
"@subql/types": "latest",
41+
"@subql/testing": "^2.2.2",
42+
"@subql/types": "^3.11.3",
4343
"@types/jest": "^29.1.2",
4444
"@types/node-fetch": "^2.6.11",
4545
"@typescript-eslint/eslint-plugin": "^6.15.0",

schema.graphql

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -676,5 +676,4 @@ type PoolFeeTransaction @entity {
676676
epoch: Epoch!
677677

678678
amount: BigInt
679-
680679
}

src/mappings/handlers/blockHandlers.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,9 @@ async function _handleBlock(block: SubstrateBlock): Promise<void> {
7979
await tranche.save()
8080

8181
// Compute TrancheBalances Unrealized Profit
82-
const trancheBalances = (await TrancheBalanceService.getByTrancheId(tranche.id)) as TrancheBalanceService[]
82+
const trancheBalances = (await TrancheBalanceService.getByTrancheId(tranche.id, {
83+
limit: 100,
84+
})) as TrancheBalanceService[]
8385
for (const trancheBalance of trancheBalances) {
8486
const unrealizedProfit = await InvestorPositionService.computeUnrealizedProfitAtPrice(
8587
trancheBalance.accountId,

src/mappings/handlers/ethHandlers.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ async function updateLoans(
182182
navFeed: string
183183
) {
184184
logger.info(`Updating loans for pool ${poolId}`)
185-
let existingLoans = await AssetService.getByPoolId(poolId)
185+
let existingLoans = await AssetService.getByPoolId(poolId, { limit: 100 })
186186
const existingLoanIds = existingLoans?.map((loan) => parseInt(loan.id.split('-')[1]))
187187
const newLoans = await getNewLoans(existingLoanIds as number[], shelf)
188188
logger.info(`Found ${newLoans.length} new loans for pool ${poolId}`)
@@ -276,7 +276,8 @@ async function updateLoans(
276276
}
277277

278278
// update all loans
279-
existingLoans = (await AssetService.getByPoolId(poolId))?.filter((loan) => loan.status !== AssetStatus.CLOSED) || []
279+
existingLoans =
280+
(await AssetService.getByPoolId(poolId, { limit: 100 }))?.filter((loan) => loan.status !== AssetStatus.CLOSED) || []
280281
logger.info(`Updating ${existingLoans?.length} existing loans for pool ${poolId}`)
281282
const loanDetailsCalls: PoolMulticall[] = []
282283
existingLoans.forEach((loan) => {

src/mappings/handlers/evmHandlers.ts

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import type { Provider } from '@ethersproject/providers'
1313
import { TrancheBalanceService } from '../services/trancheBalanceService'
1414
import { escrows, userEscrows } from '../../config'
1515
import { InvestorPositionService } from '../services/investorPositionService'
16+
import { getPeriodStart } from '../../helpers/timekeeperService'
1617

1718
const _ethApi = api as unknown as Provider
1819
//const networkPromise = typeof ethApi.getNetwork === 'function' ? ethApi.getNetwork() : null
@@ -62,6 +63,7 @@ async function _handleEvmTransfer(event: TransferLog): Promise<void> {
6263
const [fromEvmAddress, toEvmAddress, amount] = event.args
6364
logger.info(`Transfer ${fromEvmAddress}-${toEvmAddress} of ${amount.toString()} at block: ${event.blockNumber}`)
6465

66+
const timestamp = new Date(Number(event.block.timestamp) * 1000)
6567
const evmTokenAddress = event.address
6668
const chainId = await getNodeEvmChainId() //(await networkPromise).chainId.toString(10)
6769
const evmBlockchain = await BlockchainService.getOrInit(chainId)
@@ -74,12 +76,16 @@ async function _handleEvmTransfer(event: TransferLog): Promise<void> {
7476
const isFromEscrow = fromEvmAddress === escrowAddress
7577
const _isFromUserEscrow = fromEvmAddress === userEscrowAddress
7678

79+
const trancheId = evmToken.trancheId.split('-')[1]
80+
const tranche = await TrancheService.getById(evmToken.poolId, trancheId)
81+
7782
const orderData: Omit<InvestorTransactionData, 'address'> = {
7883
poolId: evmToken.poolId,
79-
trancheId: evmToken.trancheId.split('-')[1],
84+
trancheId: trancheId,
8085
hash: event.transactionHash,
81-
timestamp: new Date(Number(event.block.timestamp) * 1000),
86+
timestamp: timestamp,
8287
amount: amount.toBigInt(),
88+
price: tranche.snapshot?.tokenPrice,
8389
}
8490

8591
const isLpTokenMigrationDay =
@@ -128,27 +134,40 @@ async function _handleEvmTransfer(event: TransferLog): Promise<void> {
128134

129135
// Handle Transfer In and Out
130136
if (isFromUserAddress && isToUserAddress) {
131-
const txIn = InvestorTransactionService.transferIn({ ...orderData, address: toAccount.id })
132-
if (!isLpTokenMigrationDay)
133-
await InvestorPositionService.buy(
134-
txIn.accountId,
135-
txIn.trancheId,
136-
txIn.hash,
137-
txIn.timestamp,
138-
txIn.tokenAmount,
139-
txIn.tokenPrice
140-
)
141-
await txIn.save()
137+
await tranche.loadSnapshot(getPeriodStart(timestamp))
138+
const price = tranche.tokenPrice
142139

143-
const txOut = InvestorTransactionService.transferOut({ ...orderData, address: fromAccount.id })
140+
const txIn = InvestorTransactionService.transferIn({ ...orderData, address: toAccount.id, price })
141+
await txIn.save()
142+
if (!isLpTokenMigrationDay)
143+
try {
144+
await InvestorPositionService.buy(
145+
txIn.accountId,
146+
txIn.trancheId,
147+
txIn.hash,
148+
txIn.timestamp,
149+
txIn.tokenAmount,
150+
txIn.tokenPrice
151+
)
152+
} catch (error) {
153+
logger.error(`Unable to save buy investor position: ${error}`)
154+
// TODO: Fallback use PoolManager Contract to read price
155+
}
156+
157+
const txOut = InvestorTransactionService.transferOut({ ...orderData, address: fromAccount.id, price })
144158
if (!isLpTokenMigrationDay) {
145-
const profit = await InvestorPositionService.sellFifo(
146-
txOut.accountId,
147-
txOut.trancheId,
148-
txOut.tokenAmount,
149-
txOut.tokenPrice
150-
)
151-
await txOut.setRealizedProfitFifo(profit)
159+
try {
160+
const profit = await InvestorPositionService.sellFifo(
161+
txOut.accountId,
162+
txOut.trancheId,
163+
txOut.tokenAmount,
164+
txOut.tokenPrice
165+
)
166+
await txOut.setRealizedProfitFifo(profit)
167+
} catch (error) {
168+
logger.error(`Unable to save sell investor position: ${error}`)
169+
// TODO: Fallback use PoolManager Contract to read price
170+
}
152171
}
153172
await txOut.save()
154173
}

src/mappings/services/assetCashflowService.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export class AssetCashflowService extends AssetCashflow {
3030

3131
static async clearAssetCashflows(assetId: string) {
3232
logger.info(`Clearing AssetCashflows for asset: ${assetId}`)
33-
const cashflows = await this.getByAssetId(assetId)
33+
const cashflows = await this.getByAssetId(assetId, { limit: 100 })
3434
const deletes = cashflows.map((cf) => this.remove(cf.id))
3535
return Promise.all(deletes)
3636
}

src/mappings/services/assetPositionService.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export class AssetPositionService extends AssetPosition {
2727
`sellingQuantity: ${sellingQuantity.toString(10)} sellingPrice: ${sellingPrice.toString(10)}`
2828
)
2929
if (sellingQuantity <= BigInt(0)) return BigInt(0)
30-
const positions = await this.getByAssetId(assetId)
30+
const positions = await this.getByAssetId(assetId, { limit: 100 })
3131
positions.sort((a, b) => b.timestamp.valueOf() - a.timestamp.valueOf())
3232

3333
const sellPositions: [assetPosition: AssetPosition, sellQuantity: bigint][] = []
@@ -67,7 +67,7 @@ export class AssetPositionService extends AssetPosition {
6767
static async computeUnrealizedProfitAtPrice(assetId: string, sellingPrice: bigint) {
6868
if (!sellingPrice || sellingPrice <= BigInt(0)) return BigInt(0)
6969
logger.info(`Computing unrealizedProfit at price ${sellingPrice} for asset ${assetId}`)
70-
const sellingPositions = await this.getByAssetId(assetId)
70+
const sellingPositions = await this.getByAssetId(assetId, { limit: 100 })
7171
const sellingQuantity = sellingPositions.reduce<bigint>(
7272
(result, position) => result + position.holdingQuantity,
7373
BigInt(0)

src/mappings/services/assetService.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ export class AssetService extends Asset {
8989
await AssetService.getByFields([
9090
['collateralNftClassId', '=', collectionId],
9191
['collateralNftItemId', '=', itemId],
92-
])
92+
], { limit: 100 })
9393
).pop() as AssetService
9494
return asset
9595
}
@@ -263,7 +263,7 @@ export class AssetService extends Asset {
263263
const snapshots = await AssetSnapshot.getByFields([
264264
['assetId', '=', this.id],
265265
['periodId', '=', periodStart.toISOString()],
266-
])
266+
], { limit: 100 })
267267
if (snapshots.length !== 1) {
268268
logger.warn(`Unable to load snapshot for asset ${this.id} for period ${periodStart.toISOString()}`)
269269
return

src/mappings/services/epochService.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export class EpochService extends Epoch {
4545
static async getById(poolId: string, epochNr: number) {
4646
const epoch = (await this.get(`${poolId}-${epochNr.toString()}`)) as EpochService
4747
if (!epoch) return undefined
48-
const epochStates = await EpochState.getByEpochId(`${poolId}-${epochNr.toString(10)}`)
48+
const epochStates = await EpochState.getByEpochId(`${poolId}-${epochNr.toString(10)}`, { limit: 100 })
4949
epoch.states = epochStates
5050
return epoch
5151
}

src/mappings/services/investorPositionService.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import assert from 'assert'
55

66
export class InvestorPositionService extends InvestorPosition {
77
static init(accountId: string, trancheId: string, hash: string, timestamp: Date, quantity: bigint, price: bigint) {
8-
const [ poolId ] = trancheId.split('-')
8+
const [poolId] = trancheId.split('-')
99
assert(quantity, 'Missing quantity')
1010
assert(price, 'Missing price')
1111
assert(hash, 'Missing hash')
@@ -27,12 +27,20 @@ export class InvestorPositionService extends InvestorPosition {
2727
}
2828

2929
static async sellFifo(accountId: string, trancheId: string, sellingQuantity: bigint, sellingPrice: bigint) {
30+
assert(sellingPrice, 'Missing price')
31+
assert(sellingQuantity, 'Missing quantity')
3032
logger.info(
3133
`Selling positions for ${trancheId} ` +
3234
`sellingQuantity: ${sellingQuantity.toString(10)} sellingPrice: ${sellingPrice.toString(10)}`
3335
)
3436
if (sellingQuantity <= BigInt(0)) return BigInt(0)
35-
const positions = await this.getByFields([['accountId', '=', accountId], ['trancheId', '=', trancheId]])
37+
const positions = await this.getByFields(
38+
[
39+
['accountId', '=', accountId],
40+
['trancheId', '=', trancheId],
41+
],
42+
{ limit: 100 }
43+
)
3644
positions.sort((a, b) => b.timestamp.valueOf() - a.timestamp.valueOf())
3745

3846
const sellPositions: [InvestorPosition: InvestorPosition, sellQuantity: bigint][] = []
@@ -72,7 +80,13 @@ export class InvestorPositionService extends InvestorPosition {
7280
static async computeUnrealizedProfitAtPrice(accountId: string, trancheId: string, sellingPrice: bigint) {
7381
if (!sellingPrice || sellingPrice <= BigInt(0)) return BigInt(0)
7482
logger.info(`Computing unrealizedProfit at price ${sellingPrice} for tranche ${trancheId}`)
75-
const sellingPositions = await this.getByFields([['accountId', '=', accountId], ['trancheId', '=', trancheId]])
83+
const sellingPositions = await this.getByFields(
84+
[
85+
['accountId', '=', accountId],
86+
['trancheId', '=', trancheId],
87+
],
88+
{ limit: 100 }
89+
)
7690
const sellingQuantity = sellingPositions.reduce<bigint>(
7791
(result, position) => result + position.holdingQuantity,
7892
BigInt(0)

0 commit comments

Comments
 (0)