Skip to content

Commit 24a08f4

Browse files
committed
feat: add ripple address balance monitor
1 parent 06f78c2 commit 24a08f4

File tree

10 files changed

+99
-10
lines changed

10 files changed

+99
-10
lines changed

packages/fasset-indexer-core/src/orm/entities/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export { TokenBalance } from "./state/balance"
4040
export { AssetManagerSettings } from './state/settings'
4141
// underlying data
4242
export { UnderlyingBlock } from "./underlying/block"
43-
export { UnderlyingAddress } from "./underlying/address"
43+
export { UnderlyingAddress, UnderlyingBalance } from "./underlying/address"
4444
export { UnderlyingReference as UnderlyingVoutReference } from "./underlying/reference"
4545
export { UnderlyingTransaction } from "./underlying/transaction"
4646
// building event bound stuff

packages/fasset-indexer-core/src/orm/entities/underlying/address.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { Entity, Enum, PrimaryKey, Property } from "@mikro-orm/core"
1+
import { Entity, Enum, ManyToMany, ManyToOne, PrimaryKey, Property } from "@mikro-orm/core"
22
import { AddressType } from "../../interface"
3+
import { uint256 } from "../../custom/uint"
34

45

56
@Entity()
@@ -18,4 +19,19 @@ export class UnderlyingAddress {
1819
this.text = text
1920
this.type = type
2021
}
22+
}
23+
24+
@Entity()
25+
export class UnderlyingBalance {
26+
27+
@ManyToOne({ entity: () => UnderlyingAddress, primary: true })
28+
address: UnderlyingAddress
29+
30+
@Property({ type: new uint256() })
31+
balance: bigint
32+
33+
constructor(address: UnderlyingAddress, balance: bigint) {
34+
this.address = address
35+
this.balance = balance
36+
}
2137
}

packages/fasset-indexer-core/src/orm/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@ export { createOrm } from "./mikro-orm.config"
22
export { raw } from "@mikro-orm/core"
33
export { EntityManager, SelectQueryBuilder } from "@mikro-orm/knex"
44
export { ZeroAddress } from 'ethers' // for database lookup
5-
export { getVar, setVar, findOrCreateUnderlyingAddress, findOrCreateUnderlyingTransaction } from "./utils"
5+
export { getVar, setVar, findOrCreateUnderlyingAddress, findOrCreateUnderlyingTransaction, updateUnderlyingBalance } from "./utils"
66
export { OrmOptions, ORM, AddressType } from "./interface"

packages/fasset-indexer-core/src/orm/mikro-orm.config.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@ import { EvmAddress } from "./entities/evm/address"
44
import { EvmBlock } from "./entities/evm/block"
55
import { EvmTransaction } from "./entities/evm/transaction"
66
import { EvmLog } from "./entities/evm/log"
7-
import { AgentVaultCreated, AgentSettingChanged, SelfClose, VaultCollateralWithdrawalAnnounced, PoolTokenRedemptionAnnounced, UnderlyingWithdrawalAnnounced, UnderlyingWithdrawalConfirmed } from "./entities/events/agent"
7+
import {
8+
AgentVaultCreated, AgentSettingChanged, SelfClose,
9+
VaultCollateralWithdrawalAnnounced, PoolTokenRedemptionAnnounced,
10+
UnderlyingWithdrawalAnnounced, UnderlyingWithdrawalConfirmed
11+
} from "./entities/events/agent"
812
import {
913
CollateralReserved, MintingExecuted,
1014
MintingPaymentDefault, CollateralReservationDeleted,
@@ -50,7 +54,7 @@ import { AssetManagerSettings, CoreVaultManagerSettings } from "./entities/state
5054
import { FtsoPrice } from "./entities/state/price"
5155
import { TokenBalance } from "./entities/state/balance"
5256
import { UnderlyingBlock } from "./entities/underlying/block"
53-
import { UnderlyingAddress } from "./entities/underlying/address"
57+
import { UnderlyingAddress, UnderlyingBalance } from "./entities/underlying/address"
5458
import { UnderlyingReference } from "./entities/underlying/reference"
5559
import { updateSchema } from "./utils"
5660
import { MIN_DATABASE_POOL_CONNECTIONS, MAX_DATABASE_POOL_CONNECTIONS } from "../config/constants"
@@ -86,7 +90,7 @@ export const ORM_OPTIONS: Options<AbstractSqlDriver> = defineConfig({
8690
EscrowFinished, CoreVaultManagerCustodianAddressUpdated,
8791
AssetManagerSettings, CoreVaultManagerSettings,
8892
// underlying
89-
UnderlyingBlock, UnderlyingReference, UnderlyingAddress
93+
UnderlyingBlock, UnderlyingReference, UnderlyingAddress, UnderlyingBalance
9094
],
9195
pool: {
9296
min: MIN_DATABASE_POOL_CONNECTIONS,

packages/fasset-indexer-core/src/orm/utils.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Var } from "../orm/entities/state/var"
2-
import { UnderlyingAddress } from "../orm/entities/underlying/address"
2+
import { UnderlyingAddress, UnderlyingBalance } from "../orm/entities/underlying/address"
33
import type { EntityManager } from "@mikro-orm/core"
4-
import type { ORM, SchemaUpdate, AddressType } from "./interface"
4+
import { ORM, SchemaUpdate, AddressType } from "./interface"
55
import { UnderlyingBlock, UnderlyingTransaction } from "./entities";
66

77

@@ -59,3 +59,15 @@ export async function findOrCreateUnderlyingTransaction(
5959
}
6060
return underlyingTransaction
6161
}
62+
63+
export async function updateUnderlyingBalance(em: EntityManager, address: string, amount: bigint): Promise<UnderlyingBalance> {
64+
let balance = await em.findOne(UnderlyingBalance, { address: { text: address } })
65+
if (balance == null) {
66+
const _address = await findOrCreateUnderlyingAddress(em, address, AddressType.USER)
67+
balance = new UnderlyingBalance(_address, amount)
68+
} else {
69+
balance.balance = amount
70+
}
71+
em.persist(balance)
72+
return balance
73+
}

packages/fasset-indexer-xrp/src/client/interface.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,12 @@ export interface IXrpServerInfoResponse {
4646
}
4747
status: string
4848
}
49+
}
50+
51+
export interface IXrpAccountInfoResponse {
52+
result: {
53+
account_data: {
54+
Balance: string
55+
}
56+
}
4957
}

packages/fasset-indexer-xrp/src/client/xrp-client.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { XrpConfigLoader } from "../config/config"
2-
import { IXrpBlock, IXrpBlockQueryResponse, IXrpLedgerCurrentResponse, IXrpServerInfoResponse } from "./interface"
2+
import { IXrpAccountInfoResponse, IXrpBlock, IXrpBlockQueryResponse, IXrpLedgerCurrentResponse, IXrpServerInfoResponse } from "./interface"
33

44
export class XrpClient {
55

@@ -25,6 +25,15 @@ export class XrpClient {
2525
return current_block
2626
}
2727

28+
async balanceOf(account: string): Promise<bigint> {
29+
const resp = await this.getAccountInfo(account)
30+
return BigInt(resp.result.account_data.Balance)
31+
}
32+
33+
private async getAccountInfo(account: string): Promise<IXrpAccountInfoResponse> {
34+
return this.request('account_info', [{ account, ledger_index: 'validated' }])
35+
}
36+
2837
private async getLedgerCurrent(): Promise<IXrpLedgerCurrentResponse> {
2938
return this.request('ledger_current', [])
3039
}

packages/fasset-indexer-xrp/src/config/config.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,9 @@ export class XrpConfigLoader extends ConfigLoader {
1717
get xrpNodeIsAmendmentBlocked(): boolean {
1818
return process.env.XRP_RPC_AMENDMENT_BLOCKED === "true"
1919
}
20+
21+
get xrpMonitoredAddresses(): string[] {
22+
const addresses = process.env.XRP_MONITORED_ADDRESSES
23+
return (addresses != null) ? addresses.split(',') : []
24+
}
2025
}

packages/fasset-indexer-xrp/src/run/run-indexer.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@ import { IndexerRunner } from "fasset-indexer-core"
22
import { XrpIndexer } from "../indexer/indexer"
33
import { XrpConfigLoader } from "../config/config"
44
import { XrpContext } from "../context"
5+
import { monitor } from "./run-monitor"
56

67

78
async function runIndexer() {
89
const config = new XrpConfigLoader()
910
const context = await XrpContext.create(config)
1011
const indexer = new XrpIndexer(context)
1112
const runner = new IndexerRunner(indexer, 'xrp')
12-
await runner.run(config.xrpMinBlockNumber)
13+
await Promise.all([monitor(config, context), runner.run(config.xrpMinBlockNumber)])
1314
}
1415

1516
runIndexer()
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { sleep } from "fasset-indexer-core/utils"
2+
import { logger } from "fasset-indexer-core/logger"
3+
import { updateUnderlyingBalance } from "fasset-indexer-core/orm"
4+
import { XrpConfigLoader } from "../config/config"
5+
import { XrpContext } from "../context"
6+
7+
const SLEEP_CYCLE_MS = 60_000
8+
9+
export async function monitor(config: XrpConfigLoader, context: XrpContext) {
10+
while (true) {
11+
await updateBalances(config.xrpMonitoredAddresses, context)
12+
await sleep(SLEEP_CYCLE_MS)
13+
}
14+
}
15+
16+
async function updateBalances(addresses: string[], context: XrpContext) {
17+
for (const address of addresses) {
18+
const balance = await fetchBalanceOf(address, context)
19+
if (balance == null) continue
20+
await context.orm.em.transactional(async em => {
21+
await updateUnderlyingBalance(em, address, balance)
22+
})
23+
logger.info(`successfully updated ripple balance for ${address}`)
24+
}
25+
}
26+
27+
async function fetchBalanceOf(address: string, context: XrpContext): Promise<bigint | null> {
28+
try {
29+
return await context.provider.balanceOf(address)
30+
} catch (err: any) {
31+
logger.error(`could not fetch ripple balance for ${address} due to: ${err}`)
32+
return null
33+
}
34+
}

0 commit comments

Comments
 (0)