@xoxno/sdk-js 1.0.230 → 1.0.231

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,10 +2,9 @@
2
2
  * Decoders for the Stellar lending `#[contractevent]`s (controller, pool, and
3
3
  * the price-aggregator's `config:asset_oracle`).
4
4
  *
5
- * Decodes core protocol topics plus pool `strategy:fee` and live controller
6
- * config topics used by the indexer. Intentional omissions still return
7
- * `null`: `config:spoke_asset` / `config:remove_spoke_asset` / `config:hub` /
8
- * `strategy:blend_migration` (handled by az-functions own decoders).
5
+ * Decodes every topic the controller, pool, price aggregator, governance and
6
+ * DeFindex strategy contracts emit, plus legacy keys for historical ledgers.
7
+ * Unknown topics (for example access-control events) return `null`.
9
8
  *
10
9
  * The public API takes base64-XDR strings (`decodeStellarLendingEvent(topicsB64,
11
10
  * dataB64)`) and parses them with this SDK's bundled `@stellar/stellar-sdk`, so
@@ -37,8 +36,7 @@ export declare const toBase64Xdr: (scv: {
37
36
  }) => string;
38
37
  /** Build the `"<domain>:<action>"` dispatch key from the event topic ScVals. */
39
38
  export declare const stellarLendingDispatchKey: (topicsB64: readonly string[]) => string;
40
- /** Topic keys this SDK can decode. See the module header for the intentional
41
- * omissions. */
39
+ /** Topic keys this SDK can decode. */
42
40
  export declare const STELLAR_LENDING_TOPICS: readonly string[];
43
41
  /**
44
42
  * Decode a Stellar lending controller event from its base64-XDR topics and
@@ -1,8 +1,9 @@
1
1
  /** Typed Stellar lending reads. Configure the API deployment with XOXNOClient.apiUrl.
2
2
  * These cached HTTP reads do not simulate transactions or authorize spending.
3
3
  */
4
- import type { OurRequestInit, XOXNOClient } from '../../utils/api.js';
4
+ import { type OurRequestInit, type XOXNOClient } from '../../utils/api.js';
5
5
  import type * as Api from './lending-api-types.js';
6
+ import type { UserTokenInventoryResponseDto } from '@xoxno/types';
6
7
  import type { StellarLendingMarketSide, StellarLendingHoldersSide, StellarMarketGraphQuery, StellarReservesParams, StellarActivityQuery, StellarActivityPageQuery, StellarGovernanceQuery, StellarPositionsQuery, StellarRevenueQuery, StellarFeeRevenueQuery, StellarParticipantsQuery, StellarLiquidationsQuery, StellarLiquidationsLeaderboardQuery, StellarVolumeQuery, StellarDistributionQuery, StellarRateSpreadQuery } from './lending-read-types.js';
7
8
  /** Load assets, hubs, spokes, reserves and keyed reserve details in one response.
8
9
  * @category Stellar lending reads
@@ -56,7 +57,18 @@ export declare const getStellarUserPositions: (client: XOXNOClient, owner: strin
56
57
  * @category Stellar lending reads
57
58
  */
58
59
  export declare const getStellarAccountPositions: (client: XOXNOClient, accountId: string, init?: OurRequestInit) => Promise<Api.AccountPositionsDto>;
59
- /** Read exact token base-unit holdings for a G or C wallet. Holdings may exceed spendable funds. Requires the API release exposing this route; older deployments return 404.
60
+ /** Read a G or C wallet's token holdings from `/user/{owner}/token-inventory`:
61
+ * Horizon balances (native XLM and classic assets, keyed by their SAC id) plus
62
+ * indexed Soroban tokens, cached for about 10 seconds. Each token's
63
+ * `identifier` is its contract id and `balance` is base units as a decimal
64
+ * string. Tokens without a balance or trustline are absent.
65
+ * @category Stellar lending reads
66
+ */
67
+ export declare const getStellarWalletTokens: (client: XOXNOClient, owner: string, init?: OurRequestInit) => Promise<UserTokenInventoryResponseDto>;
68
+ /** Read exact token base-unit holdings of one asset for a G or C wallet, from
69
+ * {@link getStellarWalletTokens}. An asset the wallet does not hold returns
70
+ * `amount: '0'`, with decimals read from the lending asset. Holdings may exceed
71
+ * spendable funds (reserves, liabilities).
60
72
  * @category Stellar lending reads
61
73
  */
62
74
  export declare const getStellarWalletBalance: (client: XOXNOClient, owner: string, asset: string, init?: OurRequestInit) => Promise<Api.StellarWalletBalanceDto>;
@@ -218,6 +230,8 @@ export declare const stellarLendingRead: (client: XOXNOClient) => {
218
230
  userPositions: (owner: string, init?: OurRequestInit) => Promise<Api.AccountPositionsDto>;
219
231
  /** {@inheritDoc getStellarAccountPositions} */
220
232
  accountPositions: (accountId: string, init?: OurRequestInit) => Promise<Api.AccountPositionsDto>;
233
+ /** {@inheritDoc getStellarWalletTokens} */
234
+ walletTokens: (owner: string, init?: OurRequestInit) => Promise<UserTokenInventoryResponseDto>;
221
235
  /** {@inheritDoc getStellarWalletBalance} */
222
236
  walletBalance: (owner: string, asset: string, init?: OurRequestInit) => Promise<Api.StellarWalletBalanceDto>;
223
237
  /** {@inheritDoc getStellarAssetPage} */
@@ -2,10 +2,9 @@
2
2
  * Decoders for the Stellar lending `#[contractevent]`s (controller, pool, and
3
3
  * the price-aggregator's `config:asset_oracle`).
4
4
  *
5
- * Decodes core protocol topics plus pool `strategy:fee` and live controller
6
- * config topics used by the indexer. Intentional omissions still return
7
- * `null`: `config:spoke_asset` / `config:remove_spoke_asset` / `config:hub` /
8
- * `strategy:blend_migration` (handled by az-functions own decoders).
5
+ * Decodes every topic the controller, pool, price aggregator, governance and
6
+ * DeFindex strategy contracts emit, plus legacy keys for historical ledgers.
7
+ * Unknown topics (for example access-control events) return `null`.
9
8
  *
10
9
  * The public API takes base64-XDR strings (`decodeStellarLendingEvent(topicsB64,
11
10
  * dataB64)`) and parses them with this SDK's bundled `@stellar/stellar-sdk`, so
@@ -196,12 +195,11 @@ const REGISTRY = {
196
195
  marketAddress: str(d.market_address)
197
196
  }
198
197
  }),
199
- // `hub_id` is required to tell same-token markets apart; the upstream DTO
200
- // does not declare it yet, hence the cast.
198
+ // `hub_id` tells same-token markets apart; absent on pre-hub ledgers.
201
199
  'market:params_update': (d)=>({
202
200
  topic: 'market:params_update',
203
201
  data: {
204
- hubId: num(d.hub_id),
202
+ hubId: d.hub_id === undefined ? undefined : num(d.hub_id),
205
203
  asset: str(d.asset),
206
204
  maxBorrowRateRay: dec(d.max_borrow_rate),
207
205
  baseBorrowRateRay: dec(d.base_borrow_rate),
@@ -307,13 +305,14 @@ const REGISTRY = {
307
305
  totalCollateralUsdWad: dec(d.total_collateral_usd_wad)
308
306
  }
309
307
  }),
310
- // The event carries `{ token, amount, account_id }` only. The upstream DTO
311
- // still declares `usdValueWad`; it is left absent rather than fabricated.
308
+ // Current contracts emit `{ token, amount, account_id }`; `usd_value_wad`
309
+ // exists only on older ledgers and is never fabricated.
312
310
  'strategy:initial_payment': (d)=>({
313
311
  topic: 'strategy:initial_payment',
314
312
  data: {
315
313
  token: str(d.token),
316
314
  amount: dec(d.amount),
315
+ usdValueWad: d.usd_value_wad === undefined ? undefined : dec(d.usd_value_wad),
317
316
  accountId: dec(d.account_id)
318
317
  }
319
318
  }),
@@ -402,10 +401,112 @@ const REGISTRY = {
402
401
  liquidationBonusFactorBps: num(s.liquidation_bonus_factor_bps)
403
402
  }
404
403
  };
405
- }
404
+ },
405
+ 'position:flash_position': (d)=>({
406
+ topic: 'position:flash_position',
407
+ data: {
408
+ accountId: dec(d.account_id),
409
+ hubId: num(d.hub_id),
410
+ asset: str(d.asset),
411
+ receiver: str(d.receiver),
412
+ caller: str(d.caller),
413
+ amount: dec(d.amount),
414
+ amountReceived: dec(d.amount_received),
415
+ fee: dec(d.fee)
416
+ }
417
+ }),
418
+ 'revenue:claim': (d)=>({
419
+ topic: 'revenue:claim',
420
+ data: {
421
+ hubId: num(d.hub_id),
422
+ asset: str(d.asset),
423
+ caller: str(d.caller),
424
+ accumulator: str(d.accumulator),
425
+ amount: dec(d.amount)
426
+ }
427
+ }),
428
+ 'account:delegate': (d)=>({
429
+ topic: 'account:delegate',
430
+ data: {
431
+ accountId: dec(d.account_id),
432
+ owner: str(d.owner),
433
+ delegate: str(d.delegate),
434
+ granted: Boolean(d.granted)
435
+ }
436
+ }),
437
+ 'config:hub': (d)=>({
438
+ topic: 'config:hub',
439
+ data: {
440
+ hubId: num(d.hub_id)
441
+ }
442
+ }),
443
+ 'config:spoke_asset': (d)=>{
444
+ const c = d.config;
445
+ return {
446
+ topic: 'config:spoke_asset',
447
+ data: {
448
+ spokeId: num(d.spoke_id),
449
+ hubId: num(d.hub_id),
450
+ asset: str(d.asset),
451
+ config: {
452
+ isCollateralizable: Boolean(c.is_collateralizable),
453
+ isBorrowable: Boolean(c.is_borrowable),
454
+ paused: Boolean(c.paused),
455
+ frozen: Boolean(c.frozen),
456
+ noSeize: Boolean(c.no_seize),
457
+ loanToValueBps: num(c.loan_to_value),
458
+ liquidationThresholdBps: num(c.liquidation_threshold),
459
+ liquidationBonusBps: num(c.liquidation_bonus),
460
+ liquidationFeesBps: num(c.liquidation_fees),
461
+ supplyCap: dec(c.supply_cap),
462
+ borrowCap: dec(c.borrow_cap)
463
+ }
464
+ }
465
+ };
466
+ },
467
+ 'config:remove_spoke_asset': (d)=>({
468
+ topic: 'config:remove_spoke_asset',
469
+ data: {
470
+ spokeId: num(d.spoke_id),
471
+ hubId: num(d.hub_id),
472
+ asset: str(d.asset)
473
+ }
474
+ }),
475
+ 'strategy:blend_migration': (d)=>({
476
+ topic: 'strategy:blend_migration',
477
+ data: {
478
+ accountId: dec(d.account_id),
479
+ blendPool: str(d.blend_pool),
480
+ collateralCount: num(d.collateral_count),
481
+ supplyCount: num(d.supply_count),
482
+ debtCount: num(d.debt_count)
483
+ }
484
+ }),
485
+ // Emitted by the DeFindex strategy adapter, not the controller.
486
+ 'strategy:harvest': (d)=>({
487
+ topic: 'strategy:harvest',
488
+ data: {
489
+ from: str(d.from),
490
+ amount: dec(d.amount),
491
+ pricePerShare: dec(d.price_per_share)
492
+ }
493
+ }),
494
+ 'governance:deploy_controller': (d)=>({
495
+ topic: 'governance:deploy_controller',
496
+ data: {
497
+ controller: str(d.controller),
498
+ wasmHash: hex(d.wasm_hash)
499
+ }
500
+ }),
501
+ 'governance:deploy_price_aggregator': (d)=>({
502
+ topic: 'governance:deploy_price_aggregator',
503
+ data: {
504
+ priceAggregator: str(d.price_aggregator),
505
+ wasmHash: hex(d.wasm_hash)
506
+ }
507
+ })
406
508
  };
407
- /** Topic keys this SDK can decode. See the module header for the intentional
408
- * omissions. */ export const STELLAR_LENDING_TOPICS = Object.freeze(Object.keys(REGISTRY));
509
+ /** Topic keys this SDK can decode. */ export const STELLAR_LENDING_TOPICS = Object.freeze(Object.keys(REGISTRY));
409
510
  /**
410
511
  * Decode a Stellar lending controller event from its base64-XDR topics and
411
512
  * data (exactly as Soroban RPC `getEvents` delivers them). Returns `null` for a
@@ -1,6 +1,7 @@
1
1
  /** Typed Stellar lending reads. Configure the API deployment with XOXNOClient.apiUrl.
2
2
  * These cached HTTP reads do not simulate transactions or authorize spending.
3
- */ const BASE = '/stellar-lending';
3
+ */ import { Chain } from "../../utils/api.js";
4
+ const BASE = '/stellar-lending';
4
5
  const enc = encodeURIComponent;
5
6
  /** Load assets, hubs, spokes, reserves and keyed reserve details in one response.
6
7
  * @category Stellar lending reads
@@ -46,9 +47,43 @@ const enc = encodeURIComponent;
46
47
  /** Read a single lending account, identified by its decimal ID; balances use RAY token quantities.
47
48
  * @category Stellar lending reads
48
49
  */ export const getStellarAccountPositions = (client, accountId, init)=>client.fetchWithTimeout(`${BASE}/accounts/${enc(accountId)}/positions`, init);
49
- /** Read exact token base-unit holdings for a G or C wallet. Holdings may exceed spendable funds. Requires the API release exposing this route; older deployments return 404.
50
- * @category Stellar lending reads
51
- */ export const getStellarWalletBalance = (client, owner, asset, init)=>client.fetchWithTimeout(`${BASE}/users/${enc(owner)}/assets/${enc(asset)}/balance`, init);
50
+ /** Read a G or C wallet's token holdings from `/user/{owner}/token-inventory`:
51
+ * Horizon balances (native XLM and classic assets, keyed by their SAC id) plus
52
+ * indexed Soroban tokens, cached for about 10 seconds. Each token's
53
+ * `identifier` is its contract id and `balance` is base units as a decimal
54
+ * string. Tokens without a balance or trustline are absent.
55
+ * @category Stellar lending reads
56
+ */ export const getStellarWalletTokens = (client, owner, init)=>client.fetchWithTimeout(`/user/${enc(owner)}/token-inventory`, init);
57
+ /** Read exact token base-unit holdings of one asset for a G or C wallet, from
58
+ * {@link getStellarWalletTokens}. An asset the wallet does not hold returns
59
+ * `amount: '0'`, with decimals read from the lending asset. Holdings may exceed
60
+ * spendable funds (reserves, liabilities).
61
+ * @category Stellar lending reads
62
+ */ export const getStellarWalletBalance = async (client, owner, asset, init)=>{
63
+ const inventory = await getStellarWalletTokens(client, owner, init);
64
+ const network = client.chain === Chain.MAINNET ? 'mainnet' : 'testnet';
65
+ const token = (inventory?.tokens ?? []).find((t)=>t.identifier === asset);
66
+ if (token) {
67
+ return {
68
+ owner,
69
+ network: token.stellarNetwork ?? network,
70
+ asset,
71
+ amount: String(token.balance),
72
+ decimals: token.decimals
73
+ };
74
+ }
75
+ const { decimals } = await getStellarAsset(client, asset, init);
76
+ if (typeof decimals !== 'number') {
77
+ throw new Error(`Stellar lending: no decimals for ${asset}; it is not a lending asset`);
78
+ }
79
+ return {
80
+ owner,
81
+ network,
82
+ asset,
83
+ amount: '0',
84
+ decimals
85
+ };
86
+ };
52
87
  /** Load overview, deposit/borrow markets and chart series for an asset page.
53
88
  * @category Stellar lending reads
54
89
  */ export const getStellarAssetPage = (client, asset, query, init)=>client.fetchWithTimeout(`${BASE}/assets/${enc(asset)}/page`, {
@@ -307,6 +342,7 @@ const enc = encodeURIComponent;
307
342
  /** {@inheritDoc getStellarSpoke} */ spoke: (spokeId, init)=>getStellarSpoke(client, spokeId, init),
308
343
  /** {@inheritDoc getStellarUserPositions} */ userPositions: (owner, init)=>getStellarUserPositions(client, owner, init),
309
344
  /** {@inheritDoc getStellarAccountPositions} */ accountPositions: (accountId, init)=>getStellarAccountPositions(client, accountId, init),
345
+ /** {@inheritDoc getStellarWalletTokens} */ walletTokens: (owner, init)=>getStellarWalletTokens(client, owner, init),
310
346
  /** {@inheritDoc getStellarWalletBalance} */ walletBalance: (owner, asset, init)=>getStellarWalletBalance(client, owner, asset, init),
311
347
  /** {@inheritDoc getStellarAssetPage} */ assetPage: (asset, query, init)=>getStellarAssetPage(client, asset, query, init),
312
348
  /** {@inheritDoc getStellarAssetMarkets} */ assetMarkets: (asset, side, init)=>getStellarAssetMarkets(client, asset, side, init),