Skip to content

Commit 33271ef

Browse files
committed
feat: add self-mint data to fasset-explorer apis
1 parent 7f24474 commit 33271ef

File tree

13 files changed

+112
-39
lines changed

13 files changed

+112
-39
lines changed

packages/fasset-indexer-api/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"start:prod": "node dist/src/main"
1313
},
1414
"dependencies": {
15+
"@mikro-orm/core": "6.3.6",
1516
"@nestjs/cache-manager": "^2.3.0",
1617
"@nestjs/common": "^10.0.0",
1718
"@nestjs/core": "^10.0.0",

packages/fasset-indexer-api/src/analytics/dashboard.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import type {
1313
TimeSeries, Timespan, FAssetTimeSeries, FAssetTimespan,
1414
TokenPortfolio, FAssetCollateralPoolScore,
1515
FAssetValueResult, FAssetAmountResult
16-
} from "./interface"
16+
} from "./types"
1717

1818

1919
const add = (x: bigint, y: bigint) => x + y

packages/fasset-indexer-api/src/analytics/explorer.ts

Lines changed: 66 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
11
import { ContractLookup, FAssetType } from "fasset-indexer-core"
22
import * as Entities from "fasset-indexer-core/entities"
3-
import * as ExplorerType from "./interface"
3+
import * as ExplorerType from "./types"
44
import * as SQL from "./utils/raw-sql"
5-
import type { EntityManager, ORM } from "fasset-indexer-core/orm"
6-
import { unixnow } from "src/shared/utils"
5+
import { PaymentReference } from "fasset-indexer-core/utils"
76
import { EVENTS } from "fasset-indexer-core/config"
7+
import { unixnow } from "../shared/utils"
8+
import type { EntityManager, ORM } from "fasset-indexer-core/orm"
9+
import type { FilterQuery } from "@mikro-orm/core"
810

9-
const TRANSACTION_TYPE_EVENTS = [
10-
EVENTS.ASSET_MANAGER.REDEMPTION_REQUESTED,
11-
EVENTS.ASSET_MANAGER.COLLATERAL_RESERVED,
12-
EVENTS.ASSET_MANAGER.TRANSFER_TO_CORE_VAULT_STARTED,
13-
EVENTS.ASSET_MANAGER.RETURN_FROM_CORE_VAULT_REQUESTED
14-
]
11+
const SELF_MINT_CONFIRMATION_OFFSET = 15 * 60
1512

1613
const ALL_TRANSACTION_TYPES = Object.values(ExplorerType.TransactionType)
1714
.filter(v => typeof v === "number")
@@ -132,7 +129,7 @@ export class ExplorerAnalytics {
132129

133130
async returnFromCoreVaultTransactionDetails(
134131
hash: string
135-
): Promise<ExplorerType.RetrunFromCoreVaultTransactionDetails> {
132+
): Promise<ExplorerType.ReturnFromCoreVaultTransactionDetails> {
136133
const em = this.orm.em.fork()
137134
const returnFromCoreVaultRequests = await em.find(Entities.ReturnFromCoreVaultRequested,
138135
{ evmLog: { transaction: { hash }} }, { populate: [
@@ -148,13 +145,31 @@ export class ExplorerAnalytics {
148145
return { flows }
149146
}
150147

148+
async selfMintTransactionDetails(
149+
hash: string
150+
): Promise<ExplorerType.SelfMintTransactionDetails> {
151+
const em = this.orm.em.fork()
152+
const selfMints = await em.find(Entities.SelfMint,
153+
{ evmLog: { transaction: { hash }} }, { populate: [
154+
'evmLog.block', 'evmLog.transaction.source',
155+
'agentVault.address', 'agentVault.underlyingAddress', 'agentVault.owner.manager'
156+
]}
157+
)
158+
const flows: ExplorerType.SelfMintEventDetails[] = []
159+
for (const selfMint of selfMints) {
160+
const details = await this.selfMintEventDetails(em, selfMint)
161+
flows.push(details)
162+
}
163+
return { flows }
164+
}
165+
151166
protected async mintingEventDetails(
152167
em: EntityManager, collateralReserved: Entities.CollateralReserved
153168
): Promise<ExplorerType.MintEventDetails> {
154169
const underlyingTransaction = await this.getUnderlyingTransaction(
155170
em, collateralReserved.fasset,
156171
collateralReserved.paymentReference,
157-
collateralReserved.paymentAddress.text
172+
{ transaction: { target: collateralReserved.paymentAddress }}
158173
)
159174
const resp: ExplorerType.MintEventDetails = {
160175
events: { original: collateralReserved }, underlyingTransaction
@@ -187,8 +202,10 @@ export class ExplorerAnalytics {
187202
const underlyingTransaction = await this.getUnderlyingTransaction(
188203
em, redemptionRequested.fasset,
189204
redemptionRequested.paymentReference,
190-
redemptionRequested.paymentAddress.text,
191-
redemptionRequested.agentVault.underlyingAddress.text
205+
{ transaction: {
206+
source: redemptionRequested.agentVault.underlyingAddress,
207+
target: redemptionRequested.paymentAddress
208+
}}
192209
)
193210
const resp: ExplorerType.RedeemEventDetails = {
194211
events: { original: redemptionRequested }, underlyingTransaction
@@ -237,8 +254,10 @@ export class ExplorerAnalytics {
237254
const underlyingTransaction = await this.getUnderlyingTransaction(
238255
em, transferToCoreVaultStarted.fasset,
239256
redemptionRequested.paymentReference,
240-
redemptionRequested.paymentAddress.text,
241-
transferToCoreVaultStarted.agentVault.underlyingAddress.text
257+
{ transaction: {
258+
source: transferToCoreVaultStarted.agentVault.underlyingAddress,
259+
target: redemptionRequested.paymentAddress
260+
}}
242261
)
243262
const resp: ExplorerType.TransferToCoreVaultEventDetails = {
244263
events: { original: transferToCoreVaultStarted }, underlyingTransaction
@@ -266,8 +285,10 @@ export class ExplorerAnalytics {
266285
const underlyingTransaction = await this.getUnderlyingTransaction(
267286
em, returnFromCoreVaultRequested.fasset,
268287
returnFromCoreVaultRequested.paymentReference,
269-
returnFromCoreVaultRequested.agentVault.underlyingAddress.text,
270-
coreVault
288+
{ transaction: {
289+
source: { text: coreVault },
290+
target: returnFromCoreVaultRequested.agentVault.underlyingAddress
291+
}}
271292
)
272293
const resp: ExplorerType.ReturnFromCoreVaultEventDetails = {
273294
events: { original: returnFromCoreVaultRequested }, underlyingTransaction
@@ -288,14 +309,20 @@ export class ExplorerAnalytics {
288309
return resp
289310
}
290311

291-
protected async getUnderlyingTransaction(
292-
em: EntityManager, fasset: FAssetType, reference: string, target: string, source?: string
293-
): Promise<Entities.UnderlyingVoutReference | null> {
294-
const obj = source == null ? {} : { source: { text: source } }
295-
return em.findOne(Entities.UnderlyingVoutReference,
296-
{ fasset, reference, transaction: { target: { text: target }, ...obj } },
297-
{ populate: [ 'transaction.block', 'transaction.source', 'transaction.target' ] }
312+
protected async selfMintEventDetails(
313+
em: EntityManager, selfMint: Entities.SelfMint
314+
): Promise<ExplorerType.SelfMintEventDetails> {
315+
const lastTs = selfMint.evmLog.block.timestamp
316+
const firstTs = lastTs - SELF_MINT_CONFIRMATION_OFFSET
317+
const underlyingTransaction = await this.getUnderlyingTransaction(
318+
em, selfMint.fasset,
319+
PaymentReference.selfMint(selfMint.agentVault.address.hex),
320+
{
321+
transaction: { value: selfMint.depositedUBA, target: selfMint.agentVault.underlyingAddress },
322+
block: { timestamp: { $gte: firstTs, $lte: lastTs } }
323+
}
298324
)
325+
return { events: { original: selfMint }, underlyingTransaction }
299326
}
300327

301328
protected async nativeTransactionClassification(em: EntityManager, hash: string): Promise<ExplorerType.GenericTransactionClassification> {
@@ -308,6 +335,7 @@ export class ExplorerAnalytics {
308335
|| log.name == EVENTS.ASSET_MANAGER.COLLATERAL_RESERVED
309336
|| log.name == EVENTS.ASSET_MANAGER.TRANSFER_TO_CORE_VAULT_STARTED
310337
|| log.name == EVENTS.ASSET_MANAGER.RETURN_FROM_CORE_VAULT_REQUESTED
338+
|| log.name == EVENTS.ASSET_MANAGER.SELF_MINT
311339
) {
312340
oglog = log
313341
// core vault transfers
@@ -375,6 +403,18 @@ export class ExplorerAnalytics {
375403
return resp.map(({ hash, name }) => ({ transactionHash: hash, eventName: name }))
376404
}
377405

406+
protected async getUnderlyingTransaction(
407+
em: EntityManager,
408+
fasset: FAssetType,
409+
reference: string,
410+
filters: FilterQuery<Entities.UnderlyingVoutReference> = {}
411+
): Promise<Entities.UnderlyingVoutReference | null> {
412+
return em.findOne(Entities.UnderlyingVoutReference,
413+
{ fasset, reference, ...filters as object },
414+
{ populate: [ 'transaction.block', 'transaction.source', 'transaction.target' ] }
415+
)
416+
}
417+
378418
protected eventNameToTransactionType(name: string): ExplorerType.TransactionType {
379419
switch (name) {
380420
case 'CollateralReserved':
@@ -385,6 +425,8 @@ export class ExplorerAnalytics {
385425
return ExplorerType.TransactionType.TransferToCV
386426
case 'ReturnFromCoreVaultRequested':
387427
return ExplorerType.TransactionType.ReturnFromCV
428+
case 'SelfMint':
429+
return ExplorerType.TransactionType.SelfMint
388430
default:
389431
throw new Error(`event name ${name} cannot be mapped to transaction type`)
390432
}

packages/fasset-indexer-api/src/analytics/fxrp-launch.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { FAssetType } from "fasset-indexer-core"
22
import { EntityManager, raw } from "fasset-indexer-core/orm"
33
import * as Entities from "fasset-indexer-core/entities"
44
import { DashboardAnalytics } from "./dashboard"
5-
import type { FAssetValueResult } from "./interface"
5+
import type { FAssetValueResult } from "./types"
66

77
export class FxrpLaunchAnalytics extends DashboardAnalytics {
88

packages/fasset-indexer-api/src/analytics/interface.ts renamed to packages/fasset-indexer-api/src/analytics/types.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ export enum TransactionType {
3939
Mint = 0,
4040
Redeem = 1,
4141
TransferToCV = 2,
42-
ReturnFromCV = 3
42+
ReturnFromCV = 3,
43+
SelfMint = 4
4344
}
4445

4546
export interface TransactionsInfo {
@@ -66,7 +67,8 @@ export type GenericTransactionClassification = {
6667
export type MintTransactionDetails = TransactionDetails<MintEventDetails, void>
6768
export type RedeemTransactionDetails = TransactionDetails<RedeemEventDetails, Entities.RedemptionRequestIncomplete[]>
6869
export type TransferToCoreVaultTransactionDetails = TransactionDetails<TransferToCoreVaultEventDetails, void>
69-
export type RetrunFromCoreVaultTransactionDetails = TransactionDetails<ReturnFromCoreVaultEventDetails, void>
70+
export type ReturnFromCoreVaultTransactionDetails = TransactionDetails<ReturnFromCoreVaultEventDetails, void>
71+
export type SelfMintTransactionDetails = TransactionDetails<SelfMintEventDetails, void>
7072

7173
export type MintEventDetails = EventDetails<
7274
Entities.CollateralReserved,
@@ -94,6 +96,8 @@ export type ReturnFromCoreVaultEventDetails = EventDetails<
9496
| Entities.ReturnFromCoreVaultCancelled
9597
>
9698

99+
export type SelfMintEventDetails = EventDetails<Entities.SelfMint, void>
100+
97101
interface TransactionDetails<T,U> {
98102
flows: T[]
99103
flags?: U

packages/fasset-indexer-api/src/analytics/utils/raw-sql.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { FAssetType } from "fasset-indexer-core"
2-
import { TransactionType } from "../interface"
2+
import { TransactionType } from "../types"
33

44

55
export const COLLATERAL_POOL_PORTFOLIO_SQL = `
@@ -105,7 +105,8 @@ const transactions = new Map([
105105
FULL JOIN transfer_to_core_vault_started tc ON rr.fasset = tc.fasset AND rr.request_id = tc.transfer_redemption_request_id
106106
WHERE tc.evm_log_id IS NULL`],
107107
[TransactionType.TransferToCV, `SELECT tc.evm_log_id, tc.agent_vault_address_id, tc.value_uba, NULL::integer as user_id FROM transfer_to_core_vault_started tc`],
108-
[TransactionType.ReturnFromCV, `SELECT rc.evm_log_id, rc.agent_vault_address_id, rc.value_uba, NULL::integer as user_id FROM return_from_core_vault_requested rc`]
108+
[TransactionType.ReturnFromCV, `SELECT rc.evm_log_id, rc.agent_vault_address_id, rc.value_uba, NULL::integer as user_id FROM return_from_core_vault_requested rc`],
109+
[TransactionType.SelfMint, `SELECT sm.evm_log_id, sm.agent_vault_address_id, sm.minted_uba as value_uba, NULL::integer as user_id FROM self_mint sm`]
109110
])
110111

111112
// psql specific query

packages/fasset-indexer-api/src/analytics/utils/weighted-average.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*/
66

77
import { MAX_BIPS } from "../../config/constants"
8-
import type { Timespan } from "../interface"
8+
import type { Timespan } from "../types"
99

1010
export function weightedAverage(timespan: Timespan<bigint>, T: number, d: number): bigint {
1111
const fun = (t: bigint) => weightFun(Number(t), T, d)

packages/fasset-indexer-api/src/controllers/dashboard.controller.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import type {
1616
AmountResult, TimeSeries, Timespan, TokenPortfolio,
1717
FAssetCollateralPoolScore, FAssetValueResult,
1818
FAssetAmountResult, FAssetTimespan
19-
} from '../analytics/interface'
19+
} from '../analytics/types'
2020

2121

2222
@ApiTags('Dashboard')

packages/fasset-indexer-api/src/controllers/explorer.controller.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@ import { apiResponse, ApiResponse } from '../shared/api-response'
66
import {
77
type MintTransactionDetails,
88
type RedeemTransactionDetails,
9-
type RetrunFromCoreVaultTransactionDetails,
9+
type ReturnFromCoreVaultTransactionDetails,
1010
type TransferToCoreVaultTransactionDetails,
1111
type TransactionsInfo,
1212
type GenericTransactionClassification,
13-
TransactionType
14-
} from '../analytics/interface'
13+
TransactionType,
14+
SelfMintTransactionDetails
15+
} from '../analytics/types'
1516

1617

1718
@ApiTags('FAsset Explorer')
@@ -41,7 +42,9 @@ export class ExplorerController {
4142
@Query('types') types?: string | string[]
4243
): Promise<ApiResponse<TransactionsInfo>> {
4344
if (types != null && typeof types == 'string') types = [types]
45+
console.log(types)
4446
const transactionTypes = types != null ? this.parseTransactionTypes(types as string[]) : undefined
47+
console.log(transactionTypes)
4548
return apiResponse(this.service.transactions(limit, offset, user, agent, start, end, asc, transactionTypes), 200)
4649
}
4750

@@ -86,10 +89,19 @@ export class ExplorerController {
8689
@ApiQuery({ name: 'hash', type: String })
8790
getReturnFromCoreVaultTransactionDetails(
8891
@Query('hash') hash: string,
89-
): Promise<ApiResponse<RetrunFromCoreVaultTransactionDetails>> {
92+
): Promise<ApiResponse<ReturnFromCoreVaultTransactionDetails>> {
9093
return apiResponse(this.service.returnFromCoreVaultTransactionDetails(hash), 200)
9194
}
9295

96+
@Get('transaction-details/self-mint')
97+
@ApiOperation({ summary: 'Progression details for the given self mint' })
98+
@ApiQuery({ name: 'hash', type: String })
99+
getSelfMintTransactionDetails(
100+
@Query('hash') hash: string
101+
): Promise<ApiResponse<SelfMintTransactionDetails>> {
102+
return apiResponse(this.service.selfMintTransactionDetails(hash), 200)
103+
}
104+
93105
private parseTransactionTypes(types: string[]): TransactionType[] {
94106
return types.map(t => TransactionType[t])
95107
}

packages/fasset-indexer-api/src/controllers/fxrp-launch.controller.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { ApiOperation, ApiParam, ApiTags } from "@nestjs/swagger"
33
import { Controller, Get, Param, UseInterceptors } from "@nestjs/common"
44
import { FxrpLaunchService } from "../services/fxrp-launch.service"
55
import { ApiResponse, apiResponse } from "../shared/api-response"
6-
import { FAssetValueResult } from "../analytics/interface"
6+
import { FAssetValueResult } from "../analytics/types"
77

88
@ApiTags('FXRP Launch')
99
@UseInterceptors(CacheInterceptor)

0 commit comments

Comments
 (0)