11import { FAssetType } from "fasset-indexer-core"
2+ import * as Entities from "fasset-indexer-core/entities"
23import { findOrCreateEntity , getVar , setVar , type EntityManager } from "fasset-indexer-core/orm"
3- import {
4- UnderlyingBlock , UnderlyingAddress , UnderlyingVoutReference , UnderlyingTransaction
5- } from "fasset-indexer-core/entities"
64import { PaymentReference } from "fasset-indexer-core/utils"
7- import { IXrpMemo , IXrpBlock , IXrpTransaction } from "../client/interface"
8- import { BLOCK_HEIGHT_OFFSET } from "../constants"
95import { logger } from "fasset-indexer-core/logger"
6+ import { IXrpMemo , IXrpBlock , IXrpTransaction } from "../client/interface"
107import type { XrpContext } from "../context"
118
129
13- export class XrpReferenceIndexer {
10+ export class XrpIndexer {
11+ private tracked = new Set < string > ( )
1412
1513 constructor (
1614 public readonly context : XrpContext ,
1715 public readonly firstUnhandledBlockDbKey : string ,
18- public readonly minBlockDbKey : string
19- ) { }
16+ public readonly minBlockDbKey : string ,
17+ public readonly initialTracked : string [ ]
18+ ) {
19+ for ( const address of initialTracked ) {
20+ this . tracked . add ( address )
21+ }
22+ }
2023
2124 async run ( startBlock ?: number ) : Promise < void > {
2225 return this . runHistoric ( startBlock )
2326 }
2427
28+ async updateTrackedAddresses ( ) : Promise < void > {
29+ const agents = await this . context . orm . em . fork ( ) . findAll (
30+ Entities . AgentVault , { populate : [ 'underlyingAddress' ] } )
31+ for ( const agent of agents ) {
32+ this . tracked . add ( agent . underlyingAddress . text )
33+ }
34+ }
35+
2536 async runHistoric ( startBlock ?: number , endBlock ?: number ) : Promise < void > {
2637 const firstUnhandledBlock = await this . firstUnhandledBlock ( startBlock )
2738 if ( startBlock === undefined || firstUnhandledBlock > startBlock ) {
@@ -31,6 +42,7 @@ export class XrpReferenceIndexer {
3142 if ( endBlock === undefined || endBlock > lastBlockToHandle ) {
3243 endBlock = lastBlockToHandle
3344 }
45+ await this . updateTrackedAddresses ( )
3446 for ( let i = startBlock ; i <= endBlock ; i += 1 ) {
3547 const block = await this . context . provider . block ( i )
3648 await this . processBlock ( block )
@@ -44,8 +56,14 @@ export class XrpReferenceIndexer {
4456 return ( block !== null ? Number ( block . value ! ) : startBlock ) ?? await this . minBlock ( )
4557 }
4658
59+ // note: this is so new agent vault creation events are indexed before
60+ // the xrp indexer skips the associated agent vault underlying addresses
61+ // opt: return await this.context.provider.blockHeight() - BLOCK_HEIGHT_OFFSET
4762 async lastBlockToHandle ( ) : Promise < number > {
48- return await this . context . provider . blockHeight ( ) - BLOCK_HEIGHT_OFFSET
63+ const blocks = await this . context . orm . em . fork ( ) . find (
64+ Entities . CurrentUnderlyingBlockUpdated , { } ,
65+ { limit : 1 , orderBy : { underlyingBlockNumber : 'desc' } } )
66+ return blocks [ 0 ] ?. underlyingBlockNumber ?? 0
4967 }
5068
5169 async minBlock ( ) : Promise < number > {
@@ -61,50 +79,74 @@ export class XrpReferenceIndexer {
6179
6280 protected async processBlock ( block : IXrpBlock ) : Promise < void > {
6381 await this . context . orm . em . transactional ( async em => {
64- let blockEnt = await em . findOne ( UnderlyingBlock , { hash : block . ledger_hash } )
65- if ( blockEnt != null ) return
82+ let blockEnt = await em . findOne ( Entities . UnderlyingBlock , { hash : block . ledger_hash } )
83+ if ( blockEnt == null ) {
6684 blockEnt = await this . storeXrpBlock ( em , block )
6785 for ( const tx of block . transactions ) {
68- await this . processTx ( em , tx , blockEnt )
86+ await this . processTransaction ( em , tx , blockEnt )
6987 }
70- } )
88+ } } )
7189 }
7290
73- protected async processTx (
91+ protected async processTransaction (
7492 em : EntityManager ,
7593 transaction : IXrpTransaction ,
76- block : UnderlyingBlock
94+ block : Entities . UnderlyingBlock
7795 ) : Promise < void > {
96+ let utransaction = null
97+ const { Account, Destination } = transaction
98+ if ( this . tracked . has ( Account ) || this . tracked . has ( Destination ! ) ) {
99+ utransaction = await this . storeTransaction ( em , transaction , block )
100+ }
78101 if ( transaction . Memos == null ) return
79102 for ( const memo of transaction . Memos ) {
80103 const reference = this . extractReference ( memo )
81104 if ( reference == null ) continue
82- if ( transaction . Account == null ) {
83- logger . error ( `reference but no account present at index ${ block . height } ` )
105+ if ( utransaction == null ) {
106+ utransaction = await this . storeTransaction ( em , transaction , block )
107+ }
108+ if ( utransaction . source == null ) {
109+ logger . warn ( `transaction ${ transaction . hash } has valid FAsset reference ${ reference } but no source` )
84110 continue
85111 }
86- const source = await findOrCreateEntity ( em , UnderlyingAddress , { text : transaction . Account } )
87- const target = transaction . Destination == null ? undefined :
88- await findOrCreateEntity ( em , UnderlyingAddress , { text : transaction . Destination } )
89- const utransaction = await findOrCreateEntity ( em , UnderlyingTransaction , {
90- hash : transaction . hash , block, value : BigInt ( transaction . Amount ! ) , source, target} )
91- await this . storeReference ( em , reference , utransaction , source , block )
112+ await this . storeReference ( em , reference , utransaction , utransaction . source , block )
92113 break
93114 }
94115 }
95116
96- private async storeXrpBlock ( em : EntityManager , xrpBlock : IXrpBlock ) : Promise < UnderlyingBlock > {
97- return em . create ( UnderlyingBlock , {
117+ protected async storeTransaction (
118+ em : EntityManager ,
119+ transaction : IXrpTransaction ,
120+ block : Entities . UnderlyingBlock
121+ ) : Promise < Entities . UnderlyingTransaction > {
122+ let source = undefined
123+ let target = undefined
124+ const { Account, Destination, Amount } = transaction
125+ if ( Account != null ) {
126+ source = await findOrCreateEntity ( em , Entities . UnderlyingAddress , { text : Account } )
127+ }
128+ if ( Destination != null ) {
129+ target = await findOrCreateEntity ( em , Entities . UnderlyingAddress , { text : Destination } )
130+ }
131+ return findOrCreateEntity ( em , Entities . UnderlyingTransaction , {
132+ hash : transaction . hash , block, value : BigInt ( Amount ?? 0 ) , source, target
133+ } )
134+ }
135+
136+ private async storeXrpBlock ( em : EntityManager , xrpBlock : IXrpBlock ) : Promise < Entities . UnderlyingBlock > {
137+ return em . create ( Entities . UnderlyingBlock , {
98138 hash : xrpBlock . ledger_hash , height : xrpBlock . ledger_index , timestamp : xrpBlock . close_time
99139 } )
100140 }
101141
102142 private async storeReference (
103- em : EntityManager , reference : string ,
104- transaction : UnderlyingTransaction ,
105- address : UnderlyingAddress , block : UnderlyingBlock
106- ) : Promise < UnderlyingVoutReference > {
107- return em . create ( UnderlyingVoutReference , {
143+ em : EntityManager ,
144+ reference : string ,
145+ transaction : Entities . UnderlyingTransaction ,
146+ address : Entities . UnderlyingAddress ,
147+ block : Entities . UnderlyingBlock
148+ ) : Promise < Entities . UnderlyingVoutReference > {
149+ return em . create ( Entities . UnderlyingVoutReference , {
108150 fasset : FAssetType . FXRP , reference, transaction, address, block
109151 } )
110152 }
0 commit comments