@coinlist-co/react 0.11.1-rc.8cfcd2a → 0.11.1-rc.e102bdb

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) {
@@ -222,7 +228,9 @@ async function fetchAllPages(fetchPage, baseParams) {
222
228
  // src/shared/types/blockchain/core.ts
223
229
  var ETHEREUM_CHAINS = {
224
230
  ethereum_mainnet: true,
225
- ethereum_sepolia: true
231
+ ethereum_sepolia: true,
232
+ base_mainnet: true,
233
+ base_sepolia: true
226
234
  };
227
235
  var EthereumChain = (value) => {
228
236
  if (!Object.keys(ETHEREUM_CHAINS).includes(value)) {
@@ -277,9 +285,25 @@ var BlockchainAmount = Object.assign(
277
285
  (value) => value,
278
286
  {
279
287
  add: (a, b) => combineAmounts(a, b, (x, y) => x + y),
280
- sub: (a, b) => combineAmounts(a, b, (x, y) => x - y)
288
+ sub: (a, b) => combineAmounts(a, b, (x, y) => x - y),
289
+ mul: multiplyAmounts,
290
+ div: divideAmounts
281
291
  }
282
292
  );
293
+ function multiplyAmounts(a, b) {
294
+ const product = a.raw * b.raw;
295
+ return BlockchainAmount({
296
+ raw: product / 10n ** BigInt(b.decimals),
297
+ decimals: a.decimals
298
+ });
299
+ }
300
+ function divideAmounts(a, b) {
301
+ if (b.raw === 0n) {
302
+ throw new MathError("Cannot divide a BlockchainAmount by zero");
303
+ }
304
+ const scaled = a.raw * 10n ** BigInt(b.decimals);
305
+ return BlockchainAmount({ raw: scaled / b.raw, decimals: a.decimals });
306
+ }
283
307
  function combineAmounts(a, b, op) {
284
308
  if (a.decimals !== b.decimals) {
285
309
  throw new InvariantError(
@@ -308,7 +332,9 @@ var AssetIconUrl = (value) => value;
308
332
  // src/shared/core/blockchain/chain.ts
309
333
  var CHAIN_IDS = {
310
334
  ethereum_mainnet: 1,
311
- ethereum_sepolia: 11155111
335
+ ethereum_sepolia: 11155111,
336
+ base_mainnet: 8453,
337
+ base_sepolia: 84532
312
338
  };
313
339
  function getChainId(chain) {
314
340
  return CHAIN_IDS[chain];
@@ -327,6 +353,10 @@ function getNetworkName(chain) {
327
353
  return "Ethereum";
328
354
  case "ethereum_sepolia":
329
355
  return "Ethereum Sepolia";
356
+ case "base_mainnet":
357
+ return "Base";
358
+ case "base_sepolia":
359
+ return "Base Sepolia";
330
360
  default: {
331
361
  const _exhaustive = chain;
332
362
  return _exhaustive;
@@ -342,6 +372,10 @@ function explorerBaseUrl(chain) {
342
372
  return "https://etherscan.io";
343
373
  case "ethereum_sepolia":
344
374
  return "https://sepolia.etherscan.io";
375
+ case "base_mainnet":
376
+ return "https://basescan.org";
377
+ case "base_sepolia":
378
+ return "https://sepolia-explorer.base.org";
345
379
  default: {
346
380
  const _exhaustive = chain;
347
381
  return _exhaustive;
@@ -517,6 +551,9 @@ function classifyLogCause(error) {
517
551
  if (error instanceof InvariantError) {
518
552
  return { type: "invariant", message: error.message };
519
553
  }
554
+ if (error instanceof MathError) {
555
+ return { type: "math", message: error.message };
556
+ }
520
557
  if (error instanceof NotAuthenticatedError) {
521
558
  return { type: "not-authenticated" };
522
559
  }
@@ -1196,47 +1233,122 @@ var OndoQuote = {
1196
1233
  };
1197
1234
  }
1198
1235
  };
1199
- var OndoSwapTransaction = {
1236
+ var OndoBuyTransaction = {
1200
1237
  fromDto: (dto) => {
1201
- const inputDecimals = AssetDecimals(dto.pay_input_decimals);
1238
+ const spendDecimals = AssetDecimals(dto.spend_input_decimals);
1202
1239
  const outputDecimals = AssetDecimals(dto.receive_output_decimals);
1203
1240
  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
- }),
1241
+ ...parseSwapCore(dto, spendDecimals),
1242
+ side: "buy",
1214
1243
  fee: blockchainAmountFromRawOrThrow({
1215
1244
  label: "fee",
1216
1245
  raw: dto.fee,
1217
- decimals: inputDecimals
1246
+ decimals: spendDecimals
1218
1247
  }),
1219
1248
  notionalValue: blockchainAmountFromRawOrThrow({
1220
1249
  label: "notional_value",
1221
1250
  raw: dto.notional_value,
1222
- decimals: inputDecimals
1251
+ decimals: spendDecimals
1223
1252
  }),
1224
- receiveOutputAmount: parseReceiveOutputAmount(
1225
- dto.receive_output_amount,
1226
- outputDecimals
1227
- )
1253
+ receiveOutputAmount: parsePositiveAmount({
1254
+ label: "receive_output_amount",
1255
+ raw: dto.receive_output_amount,
1256
+ decimals: outputDecimals,
1257
+ // A transaction that yields nothing is not one to sign - the user
1258
+ // would pay the deposit and receive no asset - and frontline refuses
1259
+ // to emit one. A zero here is a changed encoding, not a small order.
1260
+ // Rejecting it at the boundary is also what lets `computeOndoBuyPrice`
1261
+ // divide by it without a fallible result: the failure surfaces as the
1262
+ // data hook's ERROR state rather than as a division during render.
1263
+ reason: "a buy that yields nothing is not fillable"
1264
+ })
1228
1265
  };
1229
1266
  }
1230
1267
  };
1231
- function parseReceiveOutputAmount(raw, decimals) {
1232
- const amount = blockchainAmountFromRawOrThrow({
1233
- label: "receive_output_amount",
1268
+ var OndoSellTransaction = {
1269
+ fromDto: (dto) => {
1270
+ const spendDecimals = AssetDecimals(dto.spend_input_decimals);
1271
+ const outputDecimals = AssetDecimals(dto.receive_output_decimals);
1272
+ const expectedQuantity = parsePositiveAmount({
1273
+ label: "expected_quantity",
1274
+ raw: dto.expected_quantity,
1275
+ decimals: outputDecimals,
1276
+ reason: "a sale that yields nothing is not fillable"
1277
+ });
1278
+ return {
1279
+ ...parseSwapCore(dto, spendDecimals),
1280
+ side: "sell",
1281
+ expected: {
1282
+ quantity: expectedQuantity,
1283
+ fee: blockchainAmountFromRawOrThrow({
1284
+ label: "expected_fee",
1285
+ raw: dto.expected_fee,
1286
+ decimals: outputDecimals
1287
+ })
1288
+ },
1289
+ minimum: {
1290
+ quantity: parseMinimumQuantity(
1291
+ dto.minimum_quantity,
1292
+ outputDecimals,
1293
+ expectedQuantity
1294
+ ),
1295
+ fee: blockchainAmountFromRawOrThrow({
1296
+ label: "minimum_fee",
1297
+ raw: dto.minimum_fee,
1298
+ decimals: outputDecimals
1299
+ })
1300
+ }
1301
+ };
1302
+ }
1303
+ };
1304
+ function parseSwapCore(dto, spendDecimals) {
1305
+ return {
1306
+ tx: {
1307
+ to: EvmContractAddress(dto.to),
1308
+ data: HexEncodedTransactionData(dto.data)
1309
+ },
1310
+ expiresAt: parseExpiresAt(dto.expires_at),
1311
+ spendInputAmount: parsePositiveAmount({
1312
+ label: "spend_input_amount",
1313
+ raw: dto.spend_input_amount,
1314
+ decimals: spendDecimals,
1315
+ // A transaction that takes nothing from the wallet is not one to sign:
1316
+ // it would settle one leg of a trade and skip the other. Frontline
1317
+ // refuses an `amount` of zero whichever way the trade runs, so this is a
1318
+ // changed encoding rather than a small order.
1319
+ //
1320
+ // Guarded on both sides rather than on the sale alone, because which
1321
+ // amount becomes the divisor in the price flips with the direction: a
1322
+ // guard placed by that would be a rule about the arithmetic rather than
1323
+ // about the trade.
1324
+ reason: "a swap that spends nothing is not fillable"
1325
+ })
1326
+ };
1327
+ }
1328
+ function parseMinimumQuantity(raw, decimals, expectedQuantity) {
1329
+ const amount = parsePositiveAmount({
1330
+ label: "minimum_quantity",
1234
1331
  raw,
1235
- decimals
1332
+ decimals,
1333
+ reason: "a floor of zero guarantees nothing"
1236
1334
  });
1335
+ if (amount.raw > expectedQuantity.raw) {
1336
+ throw new ValidationError(
1337
+ `minimum_quantity: must not exceed expected_quantity ("${raw}" > "${expectedQuantity.raw}")`
1338
+ );
1339
+ }
1340
+ return amount;
1341
+ }
1342
+ function parsePositiveAmount({
1343
+ label,
1344
+ raw,
1345
+ decimals,
1346
+ reason
1347
+ }) {
1348
+ const amount = blockchainAmountFromRawOrThrow({ label, raw, decimals });
1237
1349
  if (amount.raw <= 0n) {
1238
1350
  throw new ValidationError(
1239
- `receive_output_amount: must be greater than zero ("${raw}")`
1351
+ `${label}: must be greater than zero ("${raw}") - ${reason}`
1240
1352
  );
1241
1353
  }
1242
1354
  return amount;
@@ -1273,27 +1385,57 @@ async function getOndoQuote(api, params) {
1273
1385
  });
1274
1386
  return OndoQuote.fromDto(dto);
1275
1387
  }
1276
- async function buildOndoSwapTransaction(api, params) {
1388
+ async function buildOndoBuy(api, params) {
1277
1389
  const dto = await api.send({
1278
1390
  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
- },
1391
+ url: "/v1/ondo/swap/buy",
1392
+ body: swapBody(params),
1286
1393
  attributes: Attributes.protected()
1287
1394
  });
1288
- assertFundingScaleAgrees(dto, params);
1289
- return OndoSwapTransaction.fromDto(dto);
1395
+ assertSpendScaleAgrees({
1396
+ published: dto.spend_input_decimals,
1397
+ sized: params.amount,
1398
+ trade: "purchase"
1399
+ });
1400
+ return OndoBuyTransaction.fromDto(dto);
1290
1401
  }
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
- }
1402
+ async function buildOndoSell(api, params) {
1403
+ const dto = await api.send({
1404
+ method: "POST",
1405
+ url: "/v1/ondo/swap/sell",
1406
+ body: swapBody(params),
1407
+ attributes: Attributes.protected()
1408
+ });
1409
+ assertSpendScaleAgrees({
1410
+ published: dto.spend_input_decimals,
1411
+ sized: params.amount,
1412
+ trade: "sale",
1413
+ // The two answers come from two chains, so on a testnet they can disagree
1414
+ // for a reason that is neither the caller's nor a corrupt response. Say so,
1415
+ // or a QA run reads as a puzzle rather than a diagnosis.
1416
+ 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"
1417
+ });
1418
+ return OndoSellTransaction.fromDto(dto);
1419
+ }
1420
+ function swapBody(params) {
1421
+ return {
1422
+ symbol: params.symbol,
1423
+ chain: params.chain,
1424
+ wallet_address: params.walletAddress,
1425
+ amount: params.amount.raw.toString()
1426
+ };
1427
+ }
1428
+ function assertSpendScaleAgrees({
1429
+ published,
1430
+ sized,
1431
+ trade,
1432
+ note
1433
+ }) {
1434
+ if (published === sized.decimals) return;
1435
+ const because = note === void 0 ? "" : ` - ${note}`;
1436
+ throw new ValidationError(
1437
+ `spend_input_decimals: the ${trade} was priced in ${published} decimals but the order was sized in ${sized.decimals}${because}`
1438
+ );
1297
1439
  }
1298
1440
  function sizeParam(params) {
1299
1441
  const tokenAmount = "tokenAmount" in params ? params.tokenAmount : void 0;
@@ -1332,10 +1474,16 @@ var OndoNamespaceImpl = class {
1332
1474
  return getOndoQuote(this.ctx.api, params);
1333
1475
  });
1334
1476
  }
1335
- async buildSwapTransaction(params) {
1336
- return this.log.wrap("buildSwapTransaction", params, async () => {
1477
+ async buildBuyTransaction(params) {
1478
+ return this.log.wrap("buildBuyTransaction", params, async () => {
1479
+ await this.ctx.ensureUserAuthenticated();
1480
+ return buildOndoBuy(this.ctx.api, params);
1481
+ });
1482
+ }
1483
+ async buildSellTransaction(params) {
1484
+ return this.log.wrap("buildSellTransaction", params, async () => {
1337
1485
  await this.ctx.ensureUserAuthenticated();
1338
- return buildOndoSwapTransaction(this.ctx.api, params);
1486
+ return buildOndoSell(this.ctx.api, params);
1339
1487
  });
1340
1488
  }
1341
1489
  };
@@ -1579,27 +1727,47 @@ var TokenMetadata = {
1579
1727
  logoDark: dto.logo_dark === void 0 ? null : TokenLogo.fromDto(dto.logo_dark, baseUrl)
1580
1728
  };
1581
1729
  },
1730
+ /**
1731
+ * Maps the complete registry snapshot to every token it lists across the
1732
+ * chains this SDK models, skipping native coins and chains outside
1733
+ * {@link EthereumChain} (e.g. Solana) rather than failing on them — the
1734
+ * registry may serve chains ahead of the SDK's type surface.
1735
+ */
1736
+ fromRegistryDto: (dto, baseUrl) => {
1737
+ assertSupportedSchemaVersion(dto.schema_version);
1738
+ return dto.chains.flatMap((chainDto) => {
1739
+ let chain;
1740
+ try {
1741
+ chain = EthereumChain(chainDto.chain);
1742
+ } catch {
1743
+ return [];
1744
+ }
1745
+ return tokensOfChain(chain, chainDto.assets, baseUrl);
1746
+ });
1747
+ },
1582
1748
  /**
1583
1749
  * Maps a chain snapshot to the tokens it lists, skipping the chain's native
1584
1750
  * coin (`kind: 'COIN'`, no contract address).
1585
1751
  */
1586
1752
  fromChainAssetsDto: (dto, baseUrl) => {
1587
1753
  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
- }));
1754
+ return tokensOfChain(EthereumChain(dto.chain), dto.assets, baseUrl);
1601
1755
  }
1602
1756
  };
1757
+ function tokensOfChain(chain, assets, baseUrl) {
1758
+ return assets.filter((asset) => asset.kind === "TOKEN" && asset.address !== void 0).map((asset) => ({
1759
+ identifier: {
1760
+ chain,
1761
+ // The filter above cannot narrow `address` for the type checker.
1762
+ address: EvmContractAddress(asset.address)
1763
+ },
1764
+ name: asset.name,
1765
+ symbol: AssetSymbol(asset.symbol),
1766
+ decimals: AssetDecimals(asset.decimals),
1767
+ logo: TokenLogo.fromDto(asset.logo, baseUrl),
1768
+ logoDark: asset.logo_dark === void 0 ? null : TokenLogo.fromDto(asset.logo_dark, baseUrl)
1769
+ }));
1770
+ }
1603
1771
  function assertSupportedSchemaVersion(version) {
1604
1772
  if (version !== 1) {
1605
1773
  throw new ValidationError(
@@ -1840,6 +2008,29 @@ async function fetchTokensMetadata(client, chain) {
1840
2008
  }
1841
2009
  return TokenMetadata.fromChainAssetsDto(response.body, client.config.baseUrl);
1842
2010
  }
2011
+ async function fetchAllTokensMetadata(client) {
2012
+ let response;
2013
+ try {
2014
+ response = await client.send({
2015
+ method: "GET",
2016
+ url: `/assets.json`
2017
+ });
2018
+ } catch (error) {
2019
+ if (isRegistryHtmlFallback(error)) {
2020
+ throw new ValidationError(
2021
+ "Token registry returned non-JSON for the complete snapshot"
2022
+ );
2023
+ }
2024
+ throw error;
2025
+ }
2026
+ assertOk(response);
2027
+ if (response.body === null) {
2028
+ throw new ValidationError(
2029
+ "Token registry returned an empty complete snapshot"
2030
+ );
2031
+ }
2032
+ return TokenMetadata.fromRegistryDto(response.body, client.config.baseUrl);
2033
+ }
1843
2034
  function isRegistryHtmlFallback(error) {
1844
2035
  return error instanceof HttpError && error.response.status >= 200 && error.response.status < 300;
1845
2036
  }
@@ -1878,7 +2069,7 @@ var TokensNamespaceImpl = class {
1878
2069
  return this.log.wrap(
1879
2070
  "list",
1880
2071
  chain,
1881
- () => fetchTokensMetadata(this.api, chain)
2072
+ () => chain === void 0 ? fetchAllTokensMetadata(this.api) : fetchTokensMetadata(this.api, chain)
1882
2073
  );
1883
2074
  }
1884
2075
  };
@@ -2092,6 +2283,7 @@ export {
2092
2283
  NotAuthenticatedError,
2093
2284
  ValidationError,
2094
2285
  InvariantError,
2286
+ MathError,
2095
2287
  describeErrorUnredacted,
2096
2288
  internalLogger,
2097
2289
  HttpClient,
@@ -2172,7 +2364,8 @@ export {
2172
2364
  Ticker,
2173
2365
  OndoTradingStatus,
2174
2366
  OndoQuote,
2175
- OndoSwapTransaction,
2367
+ OndoBuyTransaction,
2368
+ OndoSellTransaction,
2176
2369
  OndoNamespaceImpl,
2177
2370
  SuperstateSwapNamespaceImpl,
2178
2371
  fetchOffers,
@@ -2203,4 +2396,4 @@ export {
2203
2396
  OAuthRefreshToken,
2204
2397
  OAuthSession
2205
2398
  };
2206
- //# sourceMappingURL=chunk-ZVB6KWZ2.js.map
2399
+ //# sourceMappingURL=chunk-7CTH4KPU.js.map