@2bad/walt 2.1.0 → 2.1.1

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.
package/build/client.d.ts CHANGED
@@ -28,9 +28,9 @@ export type Portfolio = {
28
28
  /** Spot balances above zero, largest fiat value first. */
29
29
  entries: PortfolioEntry[];
30
30
  entriesTotal: number;
31
- /** The API's own total, which includes staked funds. */
31
+ /** `entriesTotal + staked`. */
32
32
  total: number;
33
- /** `total - entriesTotal`, itemised by `earnCampaigns()`. */
33
+ /** What the API total counts beyond spot balances, itemised by `earnCampaigns()`. */
34
34
  staked: number;
35
35
  fiatCurrency: string;
36
36
  };
@@ -150,7 +150,7 @@ export declare class WaltClient {
150
150
  /**
151
151
  * OHLCV candles for several tickers in one request.
152
152
  *
153
- * @param requests - One per series wanted.
153
+ * @param requests - One per series wanted, 20 at most.
154
154
  */
155
155
  candles(requests: CandleRequest[]): Promise<CandleSeries[]>;
156
156
  coinDetails(currency: string, fiatCurrency: FiatCurrency): Promise<CoinDetails>;
@@ -171,6 +171,9 @@ export declare class WaltClient {
171
171
  * @param request - The exchange, in the shape the API takes it.
172
172
  */
173
173
  createExchange(request: ExchangeRequest): Promise<Exchange>;
174
- /** Non-zero spot balances against the API total, which also counts staked funds. */
174
+ /**
175
+ * Non-zero spot balances and the total, which also counts staked funds.
176
+ * A USD account is priced at the latest candle close, any other at the rates `accounts()` reports.
177
+ */
175
178
  portfolio(): Promise<Portfolio>;
176
179
  }
package/build/client.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { Transport, WaltAuthError } from "./transport.js";
2
2
  // source/client.ts
3
3
  const BASE_URL = "https://walletbot.me";
4
+ const CANDLE_BATCH_SIZE = 20;
4
5
  const calendarDate = (date) => [
5
6
  date.getUTCFullYear(),
6
7
  date.getUTCMonth() + 1,
@@ -271,7 +272,7 @@ var WaltClient = class {
271
272
  /**
272
273
  * OHLCV candles for several tickers in one request.
273
274
  *
274
- * @param requests - One per series wanted.
275
+ * @param requests - One per series wanted, 20 at most.
275
276
  */
276
277
  async candles(requests) {
277
278
  const { responses } = await this.transport.post("/kandelabr/public-api/v1/candles/batch", { requests });
@@ -317,12 +318,15 @@ var WaltClient = class {
317
318
  createExchange(request) {
318
319
  return this.transport.post("/api/v1/exchange/create_exchange/", request, 0);
319
320
  }
320
- /** Non-zero spot balances against the API total, which also counts staked funds. */
321
+ /**
322
+ * Non-zero spot balances and the total, which also counts staked funds.
323
+ * A USD account is priced at the latest candle close, any other at the rates `accounts()` reports.
324
+ */
321
325
  async portfolio() {
322
326
  const data = await this.accounts();
323
327
  if (!Array.isArray(data.accounts)) throw new Error("accounts response carries no accounts array");
324
- const total = decimal(data.available_balance_total_fiat_amount);
325
- if (total === null) throw new Error(`accounts total is not a number: ${String(data.available_balance_total_fiat_amount)}`);
328
+ const accountsTotal = decimal(data.available_balance_total_fiat_amount);
329
+ if (accountsTotal === null) throw new Error(`accounts total is not a number: ${String(data.available_balance_total_fiat_amount)}`);
326
330
  const entries = [];
327
331
  for (const account of data.accounts) {
328
332
  const balance = decimal(account.available_balance);
@@ -336,12 +340,28 @@ var WaltClient = class {
336
340
  fiatValue
337
341
  });
338
342
  }
343
+ const staked = accountsTotal - entries.reduce((sum, entry) => sum + entry.fiatValue, 0);
344
+ if (data.available_balance_total_fiat_currency === "USD") {
345
+ const requests = entries.map((entry) => ({
346
+ ticker: `${entry.currency}/USD/SPOT`,
347
+ resolution: "1m",
348
+ limit: 1
349
+ }));
350
+ const batches = Array.from({ length: Math.ceil(requests.length / CANDLE_BATCH_SIZE) }, (_, index) => requests.slice(index * CANDLE_BATCH_SIZE, (index + 1) * CANDLE_BATCH_SIZE));
351
+ const series = (await Promise.all(batches.map((batch) => this.candles(batch)))).flat();
352
+ const closes = new Map(series.map((item) => [item.ticker, decimal(item.candles.at(-1)?.c)]));
353
+ for (const entry of entries) {
354
+ const close = closes.get(`${entry.currency}/USD/SPOT`) ?? null;
355
+ if (close === null) throw new Error(`${entry.currency} has no candle price`);
356
+ entry.fiatValue = Number(entry.amount) * close;
357
+ }
358
+ }
339
359
  const entriesTotal = entries.reduce((sum, entry) => sum + entry.fiatValue, 0);
340
360
  return {
341
361
  entries: entries.sort((a, b) => b.fiatValue - a.fiatValue),
342
362
  entriesTotal,
343
- total,
344
- staked: total - entriesTotal,
363
+ total: entriesTotal + staked,
364
+ staked,
345
365
  fiatCurrency: data.available_balance_total_fiat_currency
346
366
  };
347
367
  }
package/build/refresh.js CHANGED
@@ -91,7 +91,8 @@ var RefreshTokenSource = class {
91
91
  return this.store(data, state.deviceSerial);
92
92
  }
93
93
  async post(path, body) {
94
- const response = await this.fetchImpl(`${this.authUrl}${path}`, {
94
+ const { fetchImpl } = this;
95
+ const response = await fetchImpl(`${this.authUrl}${path}`, {
95
96
  method: "POST",
96
97
  headers: {
97
98
  ...BROWSER_HEADERS,
@@ -136,9 +136,10 @@ var Transport = class {
136
136
  headers["content-type"] = "application/json";
137
137
  headers["origin"] = this.baseUrl;
138
138
  }
139
+ const { fetchImpl } = this;
139
140
  let response;
140
141
  try {
141
- response = await this.fetchImpl(`${this.baseUrl}${path}`, {
142
+ response = await fetchImpl(`${this.baseUrl}${path}`, {
142
143
  method,
143
144
  headers,
144
145
  body: method === "POST" ? JSON.stringify(body) : null
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@2bad/walt",
3
- "version": "2.1.0",
3
+ "version": "2.1.1",
4
4
  "description": "Client for the Walt (ex. Wallet) API in Telegram to track a crypto portfolio and exchange between assets",
5
5
  "keywords": [
6
6
  "telegram",