Skip to content

Commit 3549783

Browse files
committed
feat: add transaction type filter to the fasset explorer and include total pagination count in the same (now postgres specific) sql query
1 parent d03b159 commit 3549783

File tree

3 files changed

+43
-73
lines changed

3 files changed

+43
-73
lines changed

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

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ const VALID_EVENTS = [
1313
EVENTS.ASSET_MANAGER.RETURN_FROM_CORE_VAULT_REQUESTED
1414
]
1515

16+
const ALL_TRANSACTION_TYPES = Object.values(ExplorerType.TransactionType)
17+
.filter(v => typeof v === "number")
18+
1619
export class ExplorerAnalytics {
1720
protected lookup: ContractLookup
1821
private coreVaultCache = new Map<FAssetType, string>()
@@ -29,15 +32,16 @@ export class ExplorerAnalytics {
2932
limit: number, offset: number,
3033
user?: string, agent?: string,
3134
start?: number, end?: number,
32-
asc: boolean = false
35+
asc: boolean = false,
36+
types: ExplorerType.TransactionType[] = ALL_TRANSACTION_TYPES
3337
): Promise<ExplorerType.TransactionsInfo> {
3438
const em = this.orm.em.fork()
3539
const isuser = user != null
3640
const isagent = agent != null
3741
;[start, end] = this.standardizeInterval(start, end)
3842
const window = start != null || end != null
3943
const transactions = await em.getConnection('read').execute(
40-
SQL.EXPLORER_TRANSACTIONS(isuser, isagent, asc, window),
44+
SQL.EXPLORER_TRANSACTIONS(isuser, isagent, asc, window, types),
4145
(isuser || isagent)
4246
? (window ? [user ?? agent, start, end, limit, offset] : [user ?? agent, limit, offset])
4347
: (window ? [start, end, limit, offset] : [limit, offset])
@@ -51,10 +55,7 @@ export class ExplorerAnalytics {
5155
timestamp, origin: source, hash, value: BigInt(value_uba)
5256
})
5357
}
54-
const count = (info.length < limit)
55-
? offset + info.length
56-
: await this.getExplorerTransactionCount(em, user, agent)
57-
return { transactions: info, count }
58+
return { transactions: info, count: transactions[0]?.count ?? 0 }
5859
}
5960

6061
async transactionClassification(
@@ -302,19 +303,6 @@ export class ExplorerAnalytics {
302303
return resp
303304
}
304305

305-
async getExplorerTransactionCount(em: EntityManager, user?: string, agent?: string): Promise<number> {
306-
let query = null
307-
if (user != null) {
308-
query = SQL.EXPLORER_TRANSACTION_USER_COUNT
309-
} else if (agent != null) {
310-
query = SQL.EXPLORER_TRANSACTION_AGENT_COUNT
311-
} else {
312-
query = SQL.EXPLORER_TRANSACTION_COUNT
313-
}
314-
const resp = await em.getConnection('read').execute(query, [user ?? agent])
315-
return Number(resp[0]?.cnt)
316-
}
317-
318306
protected async getUnderlyingTransaction(
319307
em: EntityManager, fasset: FAssetType, reference: string, target: string, source?: string
320308
): Promise<Entities.UnderlyingVoutReference | null> {

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

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

34

45
export const COLLATERAL_POOL_PORTFOLIO_SQL = `
@@ -98,18 +99,22 @@ GROUP BY t.fasset
9899
ORDER BY t.fasset
99100
`
100101

101-
export const EXPLORER_TRANSACTIONS = (user: boolean, agent: boolean, asc: boolean, window: boolean) => `
102-
SELECT et.hash, el.name, eb.timestamp, eaa.hex as agent_vault, am.name as agent_name, eau.hex as user, eao.hex as source, t.value_uba FROM (
103-
SELECT cr.evm_log_id, cr.agent_vault_address_id, cr.value_uba, cr.minter_id as user_id FROM collateral_reserved cr
104-
UNION ALL
105-
SELECT rr.evm_log_id, rr.agent_vault_address_id, rr.value_uba, rr.redeemer_id as user_id FROM redemption_requested rr
106-
FULL JOIN transfer_to_core_vault_started tc ON rr.fasset = tc.fasset AND rr.request_id = tc.transfer_redemption_request_id
107-
WHERE tc.evm_log_id IS NULL
108-
UNION ALL
109-
SELECT tc.evm_log_id, tc.agent_vault_address_id, tc.value_uba, NULL as user_id FROM transfer_to_core_vault_started tc
110-
UNION ALL
111-
SELECT rc.evm_log_id, rc.agent_vault_address_id, rc.value_uba, NULL as user_id FROM return_from_core_vault_requested rc
112-
) t
102+
const transactions = new Map([
103+
[TransactionType.Mint, `SELECT cr.evm_log_id, cr.agent_vault_address_id, cr.value_uba, cr.minter_id as user_id FROM collateral_reserved cr`],
104+
[TransactionType.Redeem, `SELECT rr.evm_log_id, rr.agent_vault_address_id, rr.value_uba, rr.redeemer_id as user_id FROM redemption_requested rr
105+
FULL JOIN transfer_to_core_vault_started tc ON rr.fasset = tc.fasset AND rr.request_id = tc.transfer_redemption_request_id
106+
WHERE tc.evm_log_id IS NULL`],
107+
[TransactionType.TransferToCV, `SELECT tc.evm_log_id, tc.agent_vault_address_id, tc.value_uba, NULL 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 as user_id FROM return_from_core_vault_requested rc`]
109+
])
110+
111+
// psql specific query
112+
export const EXPLORER_TRANSACTIONS = (user: boolean, agent: boolean, asc: boolean, window: boolean, methods: TransactionType[]) => `
113+
SELECT
114+
et.hash, el.name, eb.timestamp, eaa.hex as agent_vault,
115+
am.name as agent_name, eau.hex as user, eao.hex as source,
116+
t.value_uba, COUNT(*) OVER() as count
117+
FROM (${Array.from(transactions.entries()).filter(([k, _]) => methods.includes(k)).map(([_,v]) => v).join(' UNION ALL ')}) t
113118
FULL JOIN evm_address eau ON eau.id = t.user_id
114119
JOIN evm_log el ON el.id = t.evm_log_id
115120
JOIN evm_block eb ON eb.index = el.block_index
@@ -126,41 +131,10 @@ ORDER BY el.block_index ${asc ? 'ASC' : 'DESC'}
126131
LIMIT ? OFFSET ?
127132
`
128133

129-
// postgresql-specific query
130-
export const EXPLORER_TRANSACTION_COUNT = `
131-
SELECT SUM(reltuples::bigint) AS cnt FROM pg_class
132-
WHERE relkind = 'r' AND relname IN (
133-
'collateral_reserved', 'redemption_requested', 'return_from_core_vault_requested'
134-
);
135-
`
136-
137-
export const EXPLORER_TRANSACTION_USER_COUNT = `
138-
SELECT COUNT(evm_log_id) as cnt FROM (
139-
SELECT cr.evm_log_id, cr.minter_id as user_id FROM collateral_reserved cr
140-
UNION ALL
141-
SELECT rr.evm_log_id, rr.redeemer_id as user_id FROM redemption_requested rr
142-
FULL JOIN transfer_to_core_vault_started tc ON rr.fasset = tc.fasset AND rr.request_id = tc.transfer_redemption_request_id
143-
WHERE tc.evm_log_id IS NULL
144-
) t
145-
JOIN evm_address ea ON t.user_id = ea.id
146-
WHERE ea.hex = ?
147-
`
148-
149-
export const EXPLORER_TRANSACTION_AGENT_COUNT = `
150-
SELECT COUNT(evm_log_id) AS cnt FROM (
151-
SELECT cr.evm_log_id, cr.agent_vault_address_id FROM collateral_reserved cr
152-
UNION ALL
153-
SELECT rr.evm_log_id, rr.agent_vault_address_id FROM redemption_requested rr
154-
UNION ALL
155-
SELECT rc.evm_log_id, rc.agent_vault_address_id FROM return_from_core_vault_requested rc
156-
) t
157-
JOIN evm_address eaa ON eaa.id = t.agent_vault_address_id
158-
WHERE eaa.hex = ?
159-
`
160-
161134
export type ExplorerTransactionsOrmResult = {
162135
name: string, timestamp: number, source: string, user: string,
163-
hash: string, agent_vault: string, agent_name: string, value_uba: string
136+
hash: string, agent_vault: string, agent_name: string, value_uba: string,
137+
count: number
164138
}
165139

166140
export const EVENT_FROM_UNDERLYING_HASH = `

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

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@ import { CacheInterceptor } from '@nestjs/cache-manager'
33
import { ApiOperation, ApiQuery, ApiTags } from '@nestjs/swagger'
44
import { ExplorerService } from '../services/explorer.service'
55
import { apiResponse, ApiResponse } from '../shared/api-response'
6-
import type {
7-
MintTransactionDetails,
8-
RedeemTransactionDetails,
9-
RetrunFromCoreVaultTransactionDetails,
10-
TransferToCoreVaultTransactionDetails,
11-
TransactionsInfo,
12-
GenericTransactionClassification
6+
import {
7+
type MintTransactionDetails,
8+
type RedeemTransactionDetails,
9+
type RetrunFromCoreVaultTransactionDetails,
10+
type TransferToCoreVaultTransactionDetails,
11+
type TransactionsInfo,
12+
type GenericTransactionClassification,
13+
TransactionType
1314
} from '../analytics/interface'
1415

1516

@@ -28,16 +29,20 @@ export class ExplorerController {
2829
@ApiQuery({ name: 'start', type: Number, required: false })
2930
@ApiQuery({ name: 'end', type: Number, required: false })
3031
@ApiQuery({ name: 'asc', type: Boolean, required: false })
32+
@ApiQuery({ name: 'types', type: String, isArray: true, required: false })
3133
getTransactions(
3234
@Query('limit', ParseIntPipe) limit: number,
3335
@Query('offset', ParseIntPipe) offset: number,
3436
@Query('user') user?: string,
3537
@Query('agent') agent?: string,
3638
@Query('asc') asc?: boolean,
3739
@Query('start', new ParseIntPipe({ optional: true })) start?: number,
38-
@Query('end', new ParseIntPipe({ optional: true })) end?: number
40+
@Query('end', new ParseIntPipe({ optional: true })) end?: number,
41+
@Query('types') types?: string | string[]
3942
): Promise<ApiResponse<TransactionsInfo>> {
40-
return apiResponse(this.service.transactions(limit, offset, user, agent, start, end, asc), 200)
43+
if (types != null && typeof types == 'string') types = [types]
44+
const transactionTypes = types != null ? this.parseTransactionTypes(types as string[]) : null
45+
return apiResponse(this.service.transactions(limit, offset, user, agent, start, end, asc, transactionTypes), 200)
4146
}
4247

4348
@Get('transaction-classification')
@@ -85,4 +90,7 @@ export class ExplorerController {
8590
return apiResponse(this.service.returnFromCoreVaultTransactionDetails(hash), 200)
8691
}
8792

93+
private parseTransactionTypes(types: string[]): TransactionType[] {
94+
return types.map(t => TransactionType[t])
95+
}
8896
}

0 commit comments

Comments
 (0)