@coinlist-co/react 0.11.1-rc.22d81d4 → 0.11.1-rc.578d93b

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.
@@ -202,6 +202,12 @@ var InvariantError = class extends Error {
202
202
  this.name = "InvariantError";
203
203
  }
204
204
  };
205
+ var MathError = class extends Error {
206
+ constructor(message) {
207
+ super(message);
208
+ this.name = "MathError";
209
+ }
210
+ };
205
211
 
206
212
  // src/shared/api/pagination.ts
207
213
  async function fetchAllPages(fetchPage, baseParams) {
@@ -277,9 +283,25 @@ var BlockchainAmount = Object.assign(
277
283
  (value) => value,
278
284
  {
279
285
  add: (a, b) => combineAmounts(a, b, (x, y) => x + y),
280
- sub: (a, b) => combineAmounts(a, b, (x, y) => x - y)
286
+ sub: (a, b) => combineAmounts(a, b, (x, y) => x - y),
287
+ mul: multiplyAmounts,
288
+ div: divideAmounts
281
289
  }
282
290
  );
291
+ function multiplyAmounts(a, b) {
292
+ const product = a.raw * b.raw;
293
+ return BlockchainAmount({
294
+ raw: product / 10n ** BigInt(b.decimals),
295
+ decimals: a.decimals
296
+ });
297
+ }
298
+ function divideAmounts(a, b) {
299
+ if (b.raw === 0n) {
300
+ throw new MathError("Cannot divide a BlockchainAmount by zero");
301
+ }
302
+ const scaled = a.raw * 10n ** BigInt(b.decimals);
303
+ return BlockchainAmount({ raw: scaled / b.raw, decimals: a.decimals });
304
+ }
283
305
  function combineAmounts(a, b, op) {
284
306
  if (a.decimals !== b.decimals) {
285
307
  throw new InvariantError(
@@ -517,6 +539,9 @@ function classifyLogCause(error) {
517
539
  if (error instanceof InvariantError) {
518
540
  return { type: "invariant", message: error.message };
519
541
  }
542
+ if (error instanceof MathError) {
543
+ return { type: "math", message: error.message };
544
+ }
520
545
  if (error instanceof NotAuthenticatedError) {
521
546
  return { type: "not-authenticated" };
522
547
  }
@@ -1196,47 +1221,122 @@ var OndoQuote = {
1196
1221
  };
1197
1222
  }
1198
1223
  };
1199
- var OndoSwapTransaction = {
1224
+ var OndoBuyTransaction = {
1200
1225
  fromDto: (dto) => {
1201
- const inputDecimals = AssetDecimals(dto.pay_input_decimals);
1226
+ const spendDecimals = AssetDecimals(dto.spend_input_decimals);
1202
1227
  const outputDecimals = AssetDecimals(dto.receive_output_decimals);
1203
1228
  return {
1204
- tx: {
1205
- to: EvmContractAddress(dto.to),
1206
- data: HexEncodedTransactionData(dto.data)
1207
- },
1208
- expiresAt: parseExpiresAt(dto.expires_at),
1209
- payInputAmount: blockchainAmountFromRawOrThrow({
1210
- label: "pay_input_amount",
1211
- raw: dto.pay_input_amount,
1212
- decimals: inputDecimals
1213
- }),
1229
+ ...parseSwapCore(dto, spendDecimals),
1230
+ side: "buy",
1214
1231
  fee: blockchainAmountFromRawOrThrow({
1215
1232
  label: "fee",
1216
1233
  raw: dto.fee,
1217
- decimals: inputDecimals
1234
+ decimals: spendDecimals
1218
1235
  }),
1219
1236
  notionalValue: blockchainAmountFromRawOrThrow({
1220
1237
  label: "notional_value",
1221
1238
  raw: dto.notional_value,
1222
- decimals: inputDecimals
1239
+ decimals: spendDecimals
1223
1240
  }),
1224
- receiveOutputAmount: parseReceiveOutputAmount(
1225
- dto.receive_output_amount,
1226
- outputDecimals
1227
- )
1241
+ receiveOutputAmount: parsePositiveAmount({
1242
+ label: "receive_output_amount",
1243
+ raw: dto.receive_output_amount,
1244
+ decimals: outputDecimals,
1245
+ // A transaction that yields nothing is not one to sign - the user
1246
+ // would pay the deposit and receive no asset - and frontline refuses
1247
+ // to emit one. A zero here is a changed encoding, not a small order.
1248
+ // Rejecting it at the boundary is also what lets `computeOndoBuyPrice`
1249
+ // divide by it without a fallible result: the failure surfaces as the
1250
+ // data hook's ERROR state rather than as a division during render.
1251
+ reason: "a buy that yields nothing is not fillable"
1252
+ })
1228
1253
  };
1229
1254
  }
1230
1255
  };
1231
- function parseReceiveOutputAmount(raw, decimals) {
1232
- const amount = blockchainAmountFromRawOrThrow({
1233
- label: "receive_output_amount",
1256
+ var OndoSellTransaction = {
1257
+ fromDto: (dto) => {
1258
+ const spendDecimals = AssetDecimals(dto.spend_input_decimals);
1259
+ const outputDecimals = AssetDecimals(dto.receive_output_decimals);
1260
+ const expectedQuantity = parsePositiveAmount({
1261
+ label: "expected_quantity",
1262
+ raw: dto.expected_quantity,
1263
+ decimals: outputDecimals,
1264
+ reason: "a sale that yields nothing is not fillable"
1265
+ });
1266
+ return {
1267
+ ...parseSwapCore(dto, spendDecimals),
1268
+ side: "sell",
1269
+ expected: {
1270
+ quantity: expectedQuantity,
1271
+ fee: blockchainAmountFromRawOrThrow({
1272
+ label: "expected_fee",
1273
+ raw: dto.expected_fee,
1274
+ decimals: outputDecimals
1275
+ })
1276
+ },
1277
+ minimum: {
1278
+ quantity: parseMinimumQuantity(
1279
+ dto.minimum_quantity,
1280
+ outputDecimals,
1281
+ expectedQuantity
1282
+ ),
1283
+ fee: blockchainAmountFromRawOrThrow({
1284
+ label: "minimum_fee",
1285
+ raw: dto.minimum_fee,
1286
+ decimals: outputDecimals
1287
+ })
1288
+ }
1289
+ };
1290
+ }
1291
+ };
1292
+ function parseSwapCore(dto, spendDecimals) {
1293
+ return {
1294
+ tx: {
1295
+ to: EvmContractAddress(dto.to),
1296
+ data: HexEncodedTransactionData(dto.data)
1297
+ },
1298
+ expiresAt: parseExpiresAt(dto.expires_at),
1299
+ spendInputAmount: parsePositiveAmount({
1300
+ label: "spend_input_amount",
1301
+ raw: dto.spend_input_amount,
1302
+ decimals: spendDecimals,
1303
+ // A transaction that takes nothing from the wallet is not one to sign:
1304
+ // it would settle one leg of a trade and skip the other. Frontline
1305
+ // refuses an `amount` of zero whichever way the trade runs, so this is a
1306
+ // changed encoding rather than a small order.
1307
+ //
1308
+ // Guarded on both sides rather than on the sale alone, because which
1309
+ // amount becomes the divisor in the price flips with the direction: a
1310
+ // guard placed by that would be a rule about the arithmetic rather than
1311
+ // about the trade.
1312
+ reason: "a swap that spends nothing is not fillable"
1313
+ })
1314
+ };
1315
+ }
1316
+ function parseMinimumQuantity(raw, decimals, expectedQuantity) {
1317
+ const amount = parsePositiveAmount({
1318
+ label: "minimum_quantity",
1234
1319
  raw,
1235
- decimals
1320
+ decimals,
1321
+ reason: "a floor of zero guarantees nothing"
1236
1322
  });
1323
+ if (amount.raw > expectedQuantity.raw) {
1324
+ throw new ValidationError(
1325
+ `minimum_quantity: must not exceed expected_quantity ("${raw}" > "${expectedQuantity.raw}")`
1326
+ );
1327
+ }
1328
+ return amount;
1329
+ }
1330
+ function parsePositiveAmount({
1331
+ label,
1332
+ raw,
1333
+ decimals,
1334
+ reason
1335
+ }) {
1336
+ const amount = blockchainAmountFromRawOrThrow({ label, raw, decimals });
1237
1337
  if (amount.raw <= 0n) {
1238
1338
  throw new ValidationError(
1239
- `receive_output_amount: must be greater than zero ("${raw}")`
1339
+ `${label}: must be greater than zero ("${raw}") - ${reason}`
1240
1340
  );
1241
1341
  }
1242
1342
  return amount;
@@ -1273,27 +1373,57 @@ async function getOndoQuote(api, params) {
1273
1373
  });
1274
1374
  return OndoQuote.fromDto(dto);
1275
1375
  }
1276
- async function buildOndoSwapTransaction(api, params) {
1376
+ async function buildOndoBuy(api, params) {
1277
1377
  const dto = await api.send({
1278
1378
  method: "POST",
1279
- url: "/v1/ondo/swap/transaction",
1280
- body: {
1281
- symbol: params.symbol,
1282
- chain: params.chain,
1283
- wallet_address: params.walletAddress,
1284
- amount: params.amount.raw.toString()
1285
- },
1379
+ url: "/v1/ondo/swap/buy",
1380
+ body: swapBody(params),
1286
1381
  attributes: Attributes.protected()
1287
1382
  });
1288
- assertFundingScaleAgrees(dto, params);
1289
- return OndoSwapTransaction.fromDto(dto);
1383
+ assertSpendScaleAgrees({
1384
+ published: dto.spend_input_decimals,
1385
+ sized: params.amount,
1386
+ trade: "purchase"
1387
+ });
1388
+ return OndoBuyTransaction.fromDto(dto);
1290
1389
  }
1291
- function assertFundingScaleAgrees(dto, params) {
1292
- if (dto.pay_input_decimals !== params.amount.decimals) {
1293
- throw new ValidationError(
1294
- `pay_input_decimals: the swap was priced in ${dto.pay_input_decimals} decimals but the order was sized in ${params.amount.decimals}`
1295
- );
1296
- }
1390
+ async function buildOndoSell(api, params) {
1391
+ const dto = await api.send({
1392
+ method: "POST",
1393
+ url: "/v1/ondo/swap/sell",
1394
+ body: swapBody(params),
1395
+ attributes: Attributes.protected()
1396
+ });
1397
+ assertSpendScaleAgrees({
1398
+ published: dto.spend_input_decimals,
1399
+ sized: params.amount,
1400
+ trade: "sale",
1401
+ // The two answers come from two chains, so on a testnet they can disagree
1402
+ // for a reason that is neither the caller's nor a corrupt response. Say so,
1403
+ // or a QA run reads as a puzzle rather than a diagnosis.
1404
+ note: "the quote resolves the asset on Ethereum mainnet while the swap executes on the chain requested, so these disagree until frontline serves a chain-scoped quote"
1405
+ });
1406
+ return OndoSellTransaction.fromDto(dto);
1407
+ }
1408
+ function swapBody(params) {
1409
+ return {
1410
+ symbol: params.symbol,
1411
+ chain: params.chain,
1412
+ wallet_address: params.walletAddress,
1413
+ amount: params.amount.raw.toString()
1414
+ };
1415
+ }
1416
+ function assertSpendScaleAgrees({
1417
+ published,
1418
+ sized,
1419
+ trade,
1420
+ note
1421
+ }) {
1422
+ if (published === sized.decimals) return;
1423
+ const because = note === void 0 ? "" : ` - ${note}`;
1424
+ throw new ValidationError(
1425
+ `spend_input_decimals: the ${trade} was priced in ${published} decimals but the order was sized in ${sized.decimals}${because}`
1426
+ );
1297
1427
  }
1298
1428
  function sizeParam(params) {
1299
1429
  const tokenAmount = "tokenAmount" in params ? params.tokenAmount : void 0;
@@ -1332,10 +1462,16 @@ var OndoNamespaceImpl = class {
1332
1462
  return getOndoQuote(this.ctx.api, params);
1333
1463
  });
1334
1464
  }
1335
- async buildSwapTransaction(params) {
1336
- return this.log.wrap("buildSwapTransaction", params, async () => {
1465
+ async buildBuyTransaction(params) {
1466
+ return this.log.wrap("buildBuyTransaction", params, async () => {
1467
+ await this.ctx.ensureUserAuthenticated();
1468
+ return buildOndoBuy(this.ctx.api, params);
1469
+ });
1470
+ }
1471
+ async buildSellTransaction(params) {
1472
+ return this.log.wrap("buildSellTransaction", params, async () => {
1337
1473
  await this.ctx.ensureUserAuthenticated();
1338
- return buildOndoSwapTransaction(this.ctx.api, params);
1474
+ return buildOndoSell(this.ctx.api, params);
1339
1475
  });
1340
1476
  }
1341
1477
  };
@@ -1579,27 +1715,47 @@ var TokenMetadata = {
1579
1715
  logoDark: dto.logo_dark === void 0 ? null : TokenLogo.fromDto(dto.logo_dark, baseUrl)
1580
1716
  };
1581
1717
  },
1718
+ /**
1719
+ * Maps the complete registry snapshot to every token it lists across the
1720
+ * chains this SDK models, skipping native coins and chains outside
1721
+ * {@link EthereumChain} (e.g. Solana) rather than failing on them — the
1722
+ * registry may serve chains ahead of the SDK's type surface.
1723
+ */
1724
+ fromRegistryDto: (dto, baseUrl) => {
1725
+ assertSupportedSchemaVersion(dto.schema_version);
1726
+ return dto.chains.flatMap((chainDto) => {
1727
+ let chain;
1728
+ try {
1729
+ chain = EthereumChain(chainDto.chain);
1730
+ } catch {
1731
+ return [];
1732
+ }
1733
+ return tokensOfChain(chain, chainDto.assets, baseUrl);
1734
+ });
1735
+ },
1582
1736
  /**
1583
1737
  * Maps a chain snapshot to the tokens it lists, skipping the chain's native
1584
1738
  * coin (`kind: 'COIN'`, no contract address).
1585
1739
  */
1586
1740
  fromChainAssetsDto: (dto, baseUrl) => {
1587
1741
  assertSupportedSchemaVersion(dto.schema_version);
1588
- const chain = EthereumChain(dto.chain);
1589
- return dto.assets.filter((asset) => asset.kind === "TOKEN" && asset.address !== void 0).map((asset) => ({
1590
- identifier: {
1591
- chain,
1592
- // The filter above cannot narrow `address` for the type checker.
1593
- address: EvmContractAddress(asset.address)
1594
- },
1595
- name: asset.name,
1596
- symbol: AssetSymbol(asset.symbol),
1597
- decimals: AssetDecimals(asset.decimals),
1598
- logo: TokenLogo.fromDto(asset.logo, baseUrl),
1599
- logoDark: asset.logo_dark === void 0 ? null : TokenLogo.fromDto(asset.logo_dark, baseUrl)
1600
- }));
1742
+ return tokensOfChain(EthereumChain(dto.chain), dto.assets, baseUrl);
1601
1743
  }
1602
1744
  };
1745
+ function tokensOfChain(chain, assets, baseUrl) {
1746
+ return assets.filter((asset) => asset.kind === "TOKEN" && asset.address !== void 0).map((asset) => ({
1747
+ identifier: {
1748
+ chain,
1749
+ // The filter above cannot narrow `address` for the type checker.
1750
+ address: EvmContractAddress(asset.address)
1751
+ },
1752
+ name: asset.name,
1753
+ symbol: AssetSymbol(asset.symbol),
1754
+ decimals: AssetDecimals(asset.decimals),
1755
+ logo: TokenLogo.fromDto(asset.logo, baseUrl),
1756
+ logoDark: asset.logo_dark === void 0 ? null : TokenLogo.fromDto(asset.logo_dark, baseUrl)
1757
+ }));
1758
+ }
1603
1759
  function assertSupportedSchemaVersion(version) {
1604
1760
  if (version !== 1) {
1605
1761
  throw new ValidationError(
@@ -1840,6 +1996,29 @@ async function fetchTokensMetadata(client, chain) {
1840
1996
  }
1841
1997
  return TokenMetadata.fromChainAssetsDto(response.body, client.config.baseUrl);
1842
1998
  }
1999
+ async function fetchAllTokensMetadata(client) {
2000
+ let response;
2001
+ try {
2002
+ response = await client.send({
2003
+ method: "GET",
2004
+ url: `/assets.json`
2005
+ });
2006
+ } catch (error) {
2007
+ if (isRegistryHtmlFallback(error)) {
2008
+ throw new ValidationError(
2009
+ "Token registry returned non-JSON for the complete snapshot"
2010
+ );
2011
+ }
2012
+ throw error;
2013
+ }
2014
+ assertOk(response);
2015
+ if (response.body === null) {
2016
+ throw new ValidationError(
2017
+ "Token registry returned an empty complete snapshot"
2018
+ );
2019
+ }
2020
+ return TokenMetadata.fromRegistryDto(response.body, client.config.baseUrl);
2021
+ }
1843
2022
  function isRegistryHtmlFallback(error) {
1844
2023
  return error instanceof HttpError && error.response.status >= 200 && error.response.status < 300;
1845
2024
  }
@@ -1878,7 +2057,7 @@ var TokensNamespaceImpl = class {
1878
2057
  return this.log.wrap(
1879
2058
  "list",
1880
2059
  chain,
1881
- () => fetchTokensMetadata(this.api, chain)
2060
+ () => chain === void 0 ? fetchAllTokensMetadata(this.api) : fetchTokensMetadata(this.api, chain)
1882
2061
  );
1883
2062
  }
1884
2063
  };
@@ -2092,6 +2271,7 @@ export {
2092
2271
  NotAuthenticatedError,
2093
2272
  ValidationError,
2094
2273
  InvariantError,
2274
+ MathError,
2095
2275
  describeErrorUnredacted,
2096
2276
  internalLogger,
2097
2277
  HttpClient,
@@ -2172,7 +2352,8 @@ export {
2172
2352
  Ticker,
2173
2353
  OndoTradingStatus,
2174
2354
  OndoQuote,
2175
- OndoSwapTransaction,
2355
+ OndoBuyTransaction,
2356
+ OndoSellTransaction,
2176
2357
  OndoNamespaceImpl,
2177
2358
  SuperstateSwapNamespaceImpl,
2178
2359
  fetchOffers,
@@ -2203,4 +2384,4 @@ export {
2203
2384
  OAuthRefreshToken,
2204
2385
  OAuthSession
2205
2386
  };
2206
- //# sourceMappingURL=chunk-ZVB6KWZ2.js.map
2387
+ //# sourceMappingURL=chunk-HYC4JARU.js.map