9
9
SECS_PER_5_MINS ,
10
10
} from "@/config"
11
11
12
- import { Lightning , OnChain } from "@/app"
12
+ import { Lightning , OnChain , Prices } from "@/app"
13
13
14
14
import { toSeconds } from "@/domain/primitives"
15
15
@@ -32,6 +32,7 @@ import { activateLndHealthCheck } from "@/services/lnd/health"
32
32
import { ledgerAdmin , setupMongoConnection } from "@/services/mongodb"
33
33
34
34
import { timeoutWithCancel } from "@/utils"
35
+ import { displayAmountFromNumber , UsdDisplayCurrency } from "@/domain/fiat"
35
36
36
37
const TIMEOUT_WALLET_BALANCE = 30000
37
38
@@ -40,12 +41,35 @@ const logger = baseLogger.child({ module: "exporter" })
40
41
const prefix = "galoy"
41
42
42
43
const main = async ( ) => {
43
- const { getLiabilitiesBalance, getLndBalance, getBitcoindBalance, getOnChainBalance } =
44
- ledgerAdmin
44
+ const { getLndBalance, getBitcoindBalance, getOnChainBalance } = ledgerAdmin
45
+
46
+ createGauge ( {
47
+ name : "assets" ,
48
+ description : "how much money (BTC) is on books" ,
49
+ collect : async ( ) => {
50
+ const getDealerBalance = async ( getId : ( ) => Promise < WalletId > ) => {
51
+ const walletId = await getId ( )
52
+ return getWalletBalance ( walletId )
53
+ }
54
+
55
+ const btcAssets = await ledgerAdmin . getAssetsBalance ( )
56
+ const dealerBtcLiabilities = await getDealerBalance ( getDealerBtcWalletId )
57
+
58
+ // Dealer BTC liabilities must be deducted from assets because
59
+ // Stablesats deposits and withdrawals are processed directly through Bria.
60
+ return Math . abs ( btcAssets ) - dealerBtcLiabilities
61
+ } ,
62
+ } )
63
+
45
64
createGauge ( {
46
65
name : "liabilities" ,
47
- description : "how much money customers has" ,
48
- collect : getLiabilitiesBalance ,
66
+ description : "how much money (BTC) customers has" ,
67
+ collect : async ( ) => {
68
+ const liabilities = await getUserLiabilities ( )
69
+ if ( liabilities instanceof Error ) return 0
70
+
71
+ return liabilities
72
+ } ,
49
73
} )
50
74
51
75
createGauge ( {
@@ -109,6 +133,12 @@ const main = async () => {
109
133
} ,
110
134
} )
111
135
136
+ createGauge ( {
137
+ name : "realAssetsVsLiabilities" ,
138
+ description : "do we have enough Bitcoin to cover users' liabilities" ,
139
+ collect : getRealAssetsVersusLiabilities ,
140
+ } )
141
+
112
142
createGauge ( {
113
143
name : "assetsEqLiabilities" ,
114
144
description : "do we have a balanced book" ,
@@ -271,14 +301,31 @@ const createWalletGauge = ({
271
301
} )
272
302
}
273
303
304
+ const inProgressBalanceQueries = new Map < string , Promise < number > > ( )
305
+
274
306
const getWalletBalance = async ( walletId : WalletId ) : Promise < number > => {
275
- const walletBalance = await LedgerService ( ) . getWalletBalance ( walletId )
276
- if ( walletBalance instanceof Error ) {
277
- logger . warn ( { walletId, walletBalance } , "impossible to get balance" )
278
- return 0
307
+ const inProgressKey = `wallet-${ walletId } `
308
+
309
+ const inProgress = inProgressBalanceQueries . get ( inProgressKey )
310
+ if ( inProgress ) {
311
+ return inProgress
279
312
}
280
313
281
- return walletBalance
314
+ const balancePromise = ( async ( ) => {
315
+ try {
316
+ const walletBalance = await LedgerService ( ) . getWalletBalance ( walletId )
317
+ if ( walletBalance instanceof Error ) {
318
+ logger . warn ( { walletId, walletBalance } , "impossible to get balance" )
319
+ return 0
320
+ }
321
+ return walletBalance
322
+ } finally {
323
+ inProgressBalanceQueries . delete ( inProgressKey )
324
+ }
325
+ } ) ( )
326
+
327
+ inProgressBalanceQueries . set ( inProgressKey , balancePromise )
328
+ return balancePromise
282
329
}
283
330
284
331
const createColdStorageWalletGauge = ( ) => {
@@ -311,6 +358,77 @@ const getAssetsLiabilitiesDifference = async () => {
311
358
return assets + liabilities
312
359
}
313
360
361
+ const getUserLiabilities = async ( ) => {
362
+ const getDealerBalance = async ( getId : ( ) => Promise < WalletId > ) => {
363
+ const walletId = await getId ( )
364
+ return getWalletBalance ( walletId )
365
+ }
366
+
367
+ const btcLiabilities = await ledgerAdmin . getLiabilitiesBalance ( )
368
+ const dealerBtcLiabilities = await getDealerBalance ( getDealerBtcWalletId )
369
+
370
+ // Dealer BTC liabilities must be deducted from liabilities because
371
+ // Stablesats deposits and withdrawals are processed directly through Bria.
372
+ const customerBtcLiabilities = btcLiabilities - dealerBtcLiabilities
373
+
374
+ const dealerUsdLiabilities = await getDealerBalance ( getDealerUsdWalletId )
375
+ logger . info (
376
+ {
377
+ btcLiabilities,
378
+ dealerBtcLiabilities,
379
+ customerBtcLiabilities,
380
+ dealerUsdLiabilities,
381
+ } ,
382
+ "getUserLiabilities balances" ,
383
+ )
384
+ const dealerUsdLiabilitiesDisplay = displayAmountFromNumber ( {
385
+ amount : Math . abs ( dealerUsdLiabilities ) ,
386
+ currency : UsdDisplayCurrency ,
387
+ } )
388
+ if ( dealerUsdLiabilitiesDisplay instanceof Error ) return dealerUsdLiabilitiesDisplay
389
+
390
+ const dealerUsdLiabilitiesInSatsAmount = await Prices . estimateWalletsAmounts ( {
391
+ amount : Number ( dealerUsdLiabilitiesDisplay . displayInMajor ) ,
392
+ currency : UsdDisplayCurrency ,
393
+ } )
394
+ logger . info (
395
+ {
396
+ mayor : dealerUsdLiabilitiesDisplay . displayInMajor ,
397
+ currency : UsdDisplayCurrency ,
398
+ dealerUsdLiabilitiesInSatsAmount,
399
+ } ,
400
+ "getUserLiabilities usd balances" ,
401
+ )
402
+ if ( dealerUsdLiabilitiesInSatsAmount instanceof Error )
403
+ return dealerUsdLiabilitiesInSatsAmount
404
+
405
+ return (
406
+ customerBtcLiabilities + Number ( dealerUsdLiabilitiesInSatsAmount . btcSatAmount . amount )
407
+ )
408
+ }
409
+
410
+ const getRealAssetsVersusLiabilities = async ( ) => {
411
+ const [ liabilitiesBalance , lndBalance , coldStorage , hotBalance ] = await Promise . all ( [
412
+ getUserLiabilities ( ) ,
413
+ Lightning . getTotalBalance ( ) ,
414
+ OnChain . getColdBalance ( ) ,
415
+ OnChain . getHotBalance ( ) ,
416
+ ] )
417
+
418
+ const liabilities = liabilitiesBalance instanceof Error ? 0 : liabilitiesBalance
419
+ const lnd = lndBalance instanceof Error ? 0 : lndBalance
420
+ const briaHot = hotBalance instanceof Error ? 0 : Number ( hotBalance . amount )
421
+ const briaCold = coldStorage instanceof Error ? 0 : Number ( coldStorage . amount )
422
+
423
+ logger . info (
424
+ { liabilities, lnd, briaHot, briaCold } ,
425
+ "getRealAssetsVersusLiabilities balances" ,
426
+ )
427
+
428
+ // if it is a negative value then it must match with exchange stablesats balance
429
+ return lnd + briaCold + briaHot - liabilities
430
+ }
431
+
314
432
export const getBookingVersusRealWorldAssets = async ( ) => {
315
433
const [ lightning , bitcoin , onChain , lndBalance , coldStorage , hotBalance ] =
316
434
await Promise . all ( [
0 commit comments