@coinlist-co/react 0.12.1-rc.df659d8 → 0.12.1-rc.f2804ef

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.
@@ -77,11 +77,12 @@ __export(universal_exports, {
77
77
  OAuthRefreshToken: () => OAuthRefreshToken,
78
78
  OAuthSession: () => OAuthSession,
79
79
  ONDO_POLL_INTERVAL_MS: () => ONDO_POLL_INTERVAL_MS,
80
- ONDO_QUOTE_EXPIRY_THRESHOLD_MS: () => ONDO_QUOTE_EXPIRY_THRESHOLD_MS,
80
+ ONDO_QUOTE_MAX_TTL_MS: () => ONDO_QUOTE_MAX_TTL_MS,
81
81
  ONDO_SETTLEMENT_ASSET: () => ONDO_SETTLEMENT_ASSET,
82
82
  ONDO_SUPPORTED_INPUT_ASSETS: () => ONDO_SUPPORTED_INPUT_ASSETS,
83
83
  Offer: () => Offer,
84
84
  OfferDetail: () => OfferDetail,
85
+ OfferEditorial: () => OfferEditorial,
85
86
  OfferId: () => OfferId,
86
87
  OfferOption: () => OfferOption,
87
88
  OfferOptionAddress: () => OfferOptionAddress,
@@ -135,6 +136,7 @@ __export(universal_exports, {
135
136
  TokenLogo: () => TokenLogo,
136
137
  TokenLogoUrl: () => TokenLogoUrl,
137
138
  TokenMetadata: () => TokenMetadata,
139
+ TokenRegistrySnapshot: () => TokenRegistrySnapshot,
138
140
  TokensNamespaceImpl: () => TokensNamespaceImpl,
139
141
  TxExplorerUrl: () => TxExplorerUrl,
140
142
  USDC: () => USDC,
@@ -170,7 +172,10 @@ __export(universal_exports, {
170
172
  getChainId: () => getChainId,
171
173
  getNetworkName: () => getNetworkName,
172
174
  isChain: () => isChain,
175
+ isOfferType: () => isOfferType,
173
176
  isSwapAvailable: () => isSwapAvailable,
177
+ offerDisplayTokens: () => offerDisplayTokens,
178
+ ondoQuoteOfferDeadline: () => ondoQuoteOfferDeadline,
174
179
  parseBlockchainAmount: () => parseBlockchainAmount,
175
180
  parseUint256: () => parseUint256,
176
181
  shortenAddress: () => shortenAddress,
@@ -428,8 +433,15 @@ async function generatePKCEParams(config) {
428
433
  // src/universal/types/pagination.ts
429
434
  var Cursor = (value) => value;
430
435
  var PaginatedResponse = {
431
- fromDto: (dto, itemMapper) => ({
432
- data: dto.data.map(itemMapper),
436
+ fromDto: (dto, itemMapper) => PaginatedResponse.fromDtoPage(dto, (items) => items.map(itemMapper)),
437
+ /**
438
+ * For a mapper that decides the page as a whole - one that drops items it
439
+ * cannot map, such as `Offer.listFromDto` - rather than item by item. The
440
+ * cursors are the wire's either way: dropping an item changes what the
441
+ * page holds, not where the next page starts.
442
+ */
443
+ fromDtoPage: (dto, pageMapper) => ({
444
+ data: pageMapper(dto.data),
433
445
  startingAfter: dto.starting_after ? Cursor(dto.starting_after) : null,
434
446
  startingBefore: dto.starting_before ? Cursor(dto.starting_before) : null
435
447
  })
@@ -494,6 +506,40 @@ var MathError = class extends Error {
494
506
  }
495
507
  };
496
508
 
509
+ // src/universal/core/shared/utils/wire.ts
510
+ function unknownTypeError(dto, model) {
511
+ const type = dto.type;
512
+ throw new ValidationError(
513
+ `${model}.type: unknown type ${JSON.stringify(type)}`
514
+ );
515
+ }
516
+ function requiredString(value, field) {
517
+ const text = notBlankStringOrNull(value);
518
+ if (text === null) {
519
+ throw new ValidationError(
520
+ `${field}: expected a non-blank string, got ${typeof value === "string" ? "a blank string" : String(value)}`
521
+ );
522
+ }
523
+ return text;
524
+ }
525
+ function requiredDate(value, field) {
526
+ const date = typeof value === "string" ? new Date(value) : null;
527
+ if (date === null || Number.isNaN(date.getTime())) {
528
+ throw new ValidationError(
529
+ `${field}: expected a date, got ${JSON.stringify(value)}`
530
+ );
531
+ }
532
+ return date;
533
+ }
534
+ function requiredArray(value, field) {
535
+ if (!Array.isArray(value)) {
536
+ throw new ValidationError(
537
+ `${field}: expected an array, got ${typeof value}`
538
+ );
539
+ }
540
+ return value;
541
+ }
542
+
497
543
  // src/universal/types/blockchain/core.ts
498
544
  var ETHEREUM_CHAINS = {
499
545
  ethereum_mainnet: true,
@@ -594,25 +640,69 @@ var Bps = (value) => value;
594
640
  // src/universal/types/offer.ts
595
641
  var OfferId = (value) => value;
596
642
  var OfferSlug = (value) => value;
643
+ var OFFER_TYPES = {
644
+ "coinlist::token_sale": true,
645
+ "superstate::swap": true,
646
+ "ondo::swap": true
647
+ };
648
+ var isOfferType = (value) => Object.keys(OFFER_TYPES).includes(value);
649
+ var OfferEditorial = {
650
+ /**
651
+ * `model` prefixes the field in the error (`'Offer'`, `'OfferDetail'`), so
652
+ * the same three checks name the payload that failed them.
653
+ */
654
+ fromDto: (dto, model) => ({
655
+ tagline: requiredString(dto.tagline, `${model}.tagline`),
656
+ bannerUrl: requiredString(dto.banner_url, `${model}.banner_url`),
657
+ startsAt: requiredDate(dto.starts_at, `${model}.starts_at`)
658
+ })
659
+ };
597
660
  var Offer = {
598
661
  fromDto: (dto) => {
599
- if (!Array.isArray(dto.tokens)) {
600
- throw new ValidationError(
601
- `Offer.tokens: expected an array, got ${typeof dto.tokens}`
602
- );
603
- }
604
- return {
662
+ const tokens = requiredArray(dto.tokens, "Offer.tokens");
663
+ const base2 = {
605
664
  id: OfferId(dto.id),
606
665
  slug: OfferSlug(dto.slug),
607
- type: dto.type,
608
- tagline: dto.tagline,
609
- bannerUrl: dto.banner_url,
610
- logoUrl: dto.logo_url,
611
- startsAt: new Date(dto.starts_at),
612
666
  endsAt: dto.ends_at ? new Date(dto.ends_at) : null,
613
- tokens: OfferToken.listFromDto(dto.tokens)
667
+ tokens: OfferToken.listFromDto(tokens)
614
668
  };
615
- }
669
+ switch (dto.type) {
670
+ case "coinlist::token_sale":
671
+ return {
672
+ ...base2,
673
+ ...OfferEditorial.fromDto(dto, "Offer"),
674
+ type: dto.type,
675
+ logoUrl: requiredString(dto.logo_url, "Offer.logo_url")
676
+ };
677
+ case "superstate::swap":
678
+ return {
679
+ ...base2,
680
+ ...OfferEditorial.fromDto(dto, "Offer"),
681
+ type: dto.type,
682
+ logoUrl: notBlankStringOrNull(dto.logo_url)
683
+ };
684
+ // `tagline`, `banner_url` and `starts_at` arrive as `null` and are left
685
+ // on the wire: copying them would hand every consumer a `startsAt` that
686
+ // is 1970 for one variant and a date for the others.
687
+ case "ondo::swap":
688
+ return {
689
+ ...base2,
690
+ type: dto.type,
691
+ logoUrl: notBlankStringOrNull(dto.logo_url)
692
+ };
693
+ default:
694
+ return unknownTypeError(dto, "Offer");
695
+ }
696
+ },
697
+ /**
698
+ * Maps a page of offers, dropping every offer whose `type` this SDK does not
699
+ * name. The same reasoning as {@link OfferToken.listFromDto}: a plain `.map`
700
+ * would throw out of `fromDto` and, through `PaginatedResponse.fromDto`,
701
+ * reject the whole page, so one offer of an unknown type would blank the
702
+ * grid for every offer beside it. A single offer fetched by id still
703
+ * throws, because there is nothing beside it to keep.
704
+ */
705
+ listFromDto: (dtos) => dtos.filter((dto) => isOfferType(dto.type)).map(Offer.fromDto)
616
706
  };
617
707
  var OfferToken = {
618
708
  fromDto: (dto) => ({
@@ -649,76 +739,69 @@ var OfferSwapContract = {
649
739
  };
650
740
  var OfferDetail = {
651
741
  fromDto: (dto) => {
652
- if (!Array.isArray(dto.funding_assets)) {
653
- throw new ValidationError(
654
- `OfferDetail.funding_assets: expected an array, got ${typeof dto.funding_assets}`
655
- );
656
- }
657
- if (!Array.isArray(dto.options)) {
658
- throw new ValidationError(
659
- `OfferDetail.options: expected an array, got ${typeof dto.options}`
660
- );
661
- }
662
- if (!Array.isArray(dto.terms)) {
663
- throw new ValidationError(
664
- `OfferDetail.terms: expected an array, got ${typeof dto.terms}`
665
- );
666
- }
667
- if (!Array.isArray(dto.links)) {
668
- throw new ValidationError(
669
- `OfferDetail.links: expected an array, got ${typeof dto.links}`
670
- );
671
- }
672
- if (!Array.isArray(dto.faqs)) {
673
- throw new ValidationError(
674
- `OfferDetail.faqs: expected an array, got ${typeof dto.faqs}`
675
- );
676
- }
677
- if (!Array.isArray(dto.milestones)) {
678
- throw new ValidationError(
679
- `OfferDetail.milestones: expected an array, got ${typeof dto.milestones}`
680
- );
681
- }
682
- if (!Array.isArray(dto.tokens)) {
683
- throw new ValidationError(
684
- `OfferDetail.tokens: expected an array, got ${typeof dto.tokens}`
685
- );
686
- }
687
- const swapContracts = dto.swap_contracts === void 0 ? [] : dto.swap_contracts;
688
- if (!Array.isArray(swapContracts)) {
689
- throw new ValidationError(
690
- `OfferDetail.swap_contracts: expected an array, got ${typeof swapContracts}`
691
- );
692
- }
742
+ const fundingAssets = requiredArray(
743
+ dto.funding_assets,
744
+ "OfferDetail.funding_assets"
745
+ );
746
+ const options = requiredArray(dto.options, "OfferDetail.options");
747
+ const terms = requiredArray(dto.terms, "OfferDetail.terms");
748
+ const links = requiredArray(dto.links, "OfferDetail.links");
749
+ const faqs = requiredArray(dto.faqs, "OfferDetail.faqs");
750
+ const milestones = requiredArray(dto.milestones, "OfferDetail.milestones");
751
+ const tokens = requiredArray(dto.tokens, "OfferDetail.tokens");
693
752
  const isin = notBlankStringOrNull(dto.isin);
694
753
  const ticker = notBlankStringOrNull(dto.ticker);
695
- return {
754
+ const base2 = {
696
755
  id: OfferId(dto.id),
697
756
  slug: OfferSlug(dto.slug),
698
- type: dto.type,
699
757
  name: dto.name,
700
758
  asset: Asset.fromDto(dto.asset),
701
- fundingAssets: dto.funding_assets.map(Asset.fromDto),
702
- tokens: OfferToken.listFromDto(dto.tokens),
703
- swapContracts: swapContracts.map(OfferSwapContract.fromDto),
759
+ fundingAssets: fundingAssets.map(Asset.fromDto),
760
+ tokens: OfferToken.listFromDto(tokens),
704
761
  about: notBlankStringOrNull(dto.about),
705
- tagline: dto.tagline,
706
- bannerUrl: dto.banner_url,
707
- logoUrl: dto.logo_url,
708
762
  category: dto.category,
709
763
  issuer: notBlankStringOrNull(dto.issuer),
710
764
  isin: isin === null ? null : Isin(isin),
711
765
  ticker: ticker === null ? null : Ticker(ticker),
712
766
  instrumentType: notBlankStringOrNull(dto.instrument_type),
713
767
  listingVenue: notBlankStringOrNull(dto.listing_venue),
714
- startsAt: new Date(dto.starts_at),
715
768
  endsAt: dto.ends_at ? new Date(dto.ends_at) : null,
716
- faqs: dto.faqs.map(FaqItem.fromDto),
717
- links: dto.links.map(Link.fromDto),
718
- milestones: dto.milestones.map(Milestone.fromDto),
719
- options: dto.options.map(OfferOption.fromDto),
720
- terms: dto.terms.map(TermItem.fromDto)
769
+ faqs: faqs.map(FaqItem.fromDto),
770
+ links: links.map(Link.fromDto),
771
+ milestones: milestones.map(Milestone.fromDto),
772
+ options: options.map(OfferOption.fromDto),
773
+ terms: terms.map(TermItem.fromDto)
721
774
  };
775
+ switch (dto.type) {
776
+ case "coinlist::token_sale":
777
+ return {
778
+ ...base2,
779
+ ...OfferEditorial.fromDto(dto, "OfferDetail"),
780
+ type: dto.type,
781
+ logoUrl: requiredString(dto.logo_url, "OfferDetail.logo_url")
782
+ };
783
+ case "superstate::swap":
784
+ return {
785
+ ...base2,
786
+ ...OfferEditorial.fromDto(dto, "OfferDetail"),
787
+ type: dto.type,
788
+ logoUrl: notBlankStringOrNull(dto.logo_url)
789
+ };
790
+ // `tagline`, `banner_url` and `starts_at` arrive as `null` and are left
791
+ // on the wire, as in `Offer.fromDto`.
792
+ case "ondo::swap":
793
+ return {
794
+ ...base2,
795
+ type: dto.type,
796
+ logoUrl: notBlankStringOrNull(dto.logo_url),
797
+ swapContracts: requiredArray(
798
+ dto.swap_contracts,
799
+ "OfferDetail.swap_contracts"
800
+ ).map(OfferSwapContract.fromDto)
801
+ };
802
+ default:
803
+ return unknownTypeError(dto, "OfferDetail");
804
+ }
722
805
  }
723
806
  };
724
807
  var OfferOption = {
@@ -1111,7 +1194,7 @@ var TOKEN_REGISTRY = {
1111
1194
 
1112
1195
  // src/universal/core/checkout/ondo/constants.ts
1113
1196
  var ONDO_POLL_INTERVAL_MS = 15e3;
1114
- var ONDO_QUOTE_EXPIRY_THRESHOLD_MS = 5e3;
1197
+ var ONDO_QUOTE_MAX_TTL_MS = 15e3;
1115
1198
  var DEFAULT_ONDO_AMOUNT_TO_COMPUTE_PRICE = DecimalString("1000");
1116
1199
  var ONDO_SETTLEMENT_ASSET = USDC_SYMBOL;
1117
1200
  var DEFAULT_ONDO_SELL_TOKENS_TO_COMPUTE_PRICE = 1;
@@ -1134,6 +1217,9 @@ function computeOndoSellPrice(transaction) {
1134
1217
  shares: spendInputAmount
1135
1218
  });
1136
1219
  }
1220
+ function ondoQuoteOfferDeadline(expiresAt, nowMs = Date.now()) {
1221
+ return new Date(Math.min(expiresAt.getTime(), nowMs + ONDO_QUOTE_MAX_TTL_MS));
1222
+ }
1137
1223
  function grossProceeds(expected) {
1138
1224
  const raw = expected.quantity.raw + expected.fee.raw;
1139
1225
  if (raw > MAX_UINT_256) {
@@ -2930,7 +3016,7 @@ async function fetchOffersPage(api, params, clientCreds) {
2930
3016
  Attributes.clientCredentials(clientCreds)
2931
3017
  )
2932
3018
  });
2933
- return PaginatedResponse.fromDto(pageDto, Offer.fromDto);
3019
+ return PaginatedResponse.fromDtoPage(pageDto, Offer.listFromDto);
2934
3020
  }
2935
3021
  async function fetchOfferDetails(api, id, clientCreds) {
2936
3022
  const dto = await api.send({
@@ -3192,6 +3278,52 @@ var Erc20NamespaceImpl = class {
3192
3278
  }
3193
3279
  };
3194
3280
 
3281
+ // src/universal/core/tokens/token-registry-snapshot.ts
3282
+ var TokenRegistrySnapshot = {
3283
+ /** Indexes a `tokens.list()` result. `[]` is a valid, empty snapshot. */
3284
+ fromTokens: (tokens) => ({
3285
+ tokens,
3286
+ byKey: new Map(
3287
+ tokens.map((token) => [registryKey(token.identifier), token])
3288
+ )
3289
+ }),
3290
+ /**
3291
+ * The registry's entry for one token, or `null` when it lists none. The
3292
+ * registry is curated, so `null` is an ordinary answer rather than an
3293
+ * error, and callers fall back to their own display defaults.
3294
+ */
3295
+ get: (snapshot, token) => snapshot.byKey.get(registryKey(token)) ?? null,
3296
+ /**
3297
+ * The registry's entry for the token an offer is *about*, or `null` when
3298
+ * it lists none of them.
3299
+ *
3300
+ * Resolution follows {@link offerDisplayTokens}: the token a sale
3301
+ * distributes or a swap hands over, never the funding token the user pays
3302
+ * with. An offer deployed on several chains carries one such token per
3303
+ * chain, and the first the registry knows wins - they are the same asset,
3304
+ * so any listed one answers for the offer.
3305
+ */
3306
+ forOffer: (snapshot, offer) => {
3307
+ for (const token of offerDisplayTokens(offer)) {
3308
+ const metadata = TokenRegistrySnapshot.get(snapshot, token);
3309
+ if (metadata !== null) {
3310
+ return metadata;
3311
+ }
3312
+ }
3313
+ return null;
3314
+ }
3315
+ };
3316
+ function offerDisplayTokens(offer) {
3317
+ const swaps = offer.tokens.filter((token) => token.role === "swap");
3318
+ const distributions = offer.tokens.filter(
3319
+ (token) => token.role === "distribution"
3320
+ );
3321
+ return [...swaps, ...distributions];
3322
+ }
3323
+ function registryKey(token) {
3324
+ return `${token.chain}:${token.address.toLowerCase()}`;
3325
+ }
3326
+
3195
3327
  // src/universal/api/nabu/tokens.ts
3196
3328
  var import_viem5 = require("viem");
3197
3329
 
@@ -3785,11 +3917,12 @@ var User = {
3785
3917
  OAuthRefreshToken,
3786
3918
  OAuthSession,
3787
3919
  ONDO_POLL_INTERVAL_MS,
3788
- ONDO_QUOTE_EXPIRY_THRESHOLD_MS,
3920
+ ONDO_QUOTE_MAX_TTL_MS,
3789
3921
  ONDO_SETTLEMENT_ASSET,
3790
3922
  ONDO_SUPPORTED_INPUT_ASSETS,
3791
3923
  Offer,
3792
3924
  OfferDetail,
3925
+ OfferEditorial,
3793
3926
  OfferId,
3794
3927
  OfferOption,
3795
3928
  OfferOptionAddress,
@@ -3843,6 +3976,7 @@ var User = {
3843
3976
  TokenLogo,
3844
3977
  TokenLogoUrl,
3845
3978
  TokenMetadata,
3979
+ TokenRegistrySnapshot,
3846
3980
  TokensNamespaceImpl,
3847
3981
  TxExplorerUrl,
3848
3982
  USDC,
@@ -3878,7 +4012,10 @@ var User = {
3878
4012
  getChainId,
3879
4013
  getNetworkName,
3880
4014
  isChain,
4015
+ isOfferType,
3881
4016
  isSwapAvailable,
4017
+ offerDisplayTokens,
4018
+ ondoQuoteOfferDeadline,
3882
4019
  parseBlockchainAmount,
3883
4020
  parseUint256,
3884
4021
  shortenAddress,