@coinlist-co/react 0.12.1-rc.a230abc → 0.12.1-rc.c2b6ba5

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.
Files changed (33) hide show
  1. package/dist/{chunk-GFLU5OMP.js → chunk-6CQHDASY.js} +643 -643
  2. package/dist/chunk-6CQHDASY.js.map +1 -0
  3. package/dist/{chunk-HLL7IBIS.js → chunk-F6WGUKZC.js} +9 -9
  4. package/dist/chunk-F6WGUKZC.js.map +1 -0
  5. package/dist/{chunk-RPE7XIBV.js → chunk-ZFBEI3BW.js} +126 -126
  6. package/dist/chunk-ZFBEI3BW.js.map +1 -0
  7. package/dist/client/index.cjs +2032 -2030
  8. package/dist/client/index.cjs.map +1 -1
  9. package/dist/client/index.d.cts +149 -149
  10. package/dist/client/index.d.ts +149 -149
  11. package/dist/client/index.js +481 -481
  12. package/dist/client/index.js.map +1 -1
  13. package/dist/{collections-CAfs2Eww.d.cts → collections-DOm9VKVm.d.cts} +1 -1
  14. package/dist/{collections-DZZFrizd.d.ts → collections-aCv-Wr2a.d.ts} +1 -1
  15. package/dist/{config-D19ktBr0.d.cts → config-DIaFzrMW.d.cts} +13 -13
  16. package/dist/{config-D19ktBr0.d.ts → config-DIaFzrMW.d.ts} +13 -13
  17. package/dist/server/index.cjs +232 -232
  18. package/dist/server/index.cjs.map +1 -1
  19. package/dist/server/index.d.cts +4 -4
  20. package/dist/server/index.d.ts +4 -4
  21. package/dist/server/index.js +3 -3
  22. package/dist/server/index.js.map +1 -1
  23. package/dist/{shared → universal}/index.cjs +850 -848
  24. package/dist/universal/index.cjs.map +1 -0
  25. package/dist/{shared → universal}/index.d.cts +557 -557
  26. package/dist/{shared → universal}/index.d.ts +557 -557
  27. package/dist/{shared → universal}/index.js +2 -2
  28. package/package.json +6 -5
  29. package/dist/chunk-GFLU5OMP.js.map +0 -1
  30. package/dist/chunk-HLL7IBIS.js.map +0 -1
  31. package/dist/chunk-RPE7XIBV.js.map +0 -1
  32. package/dist/shared/index.cjs.map +0 -1
  33. /package/dist/{shared → universal}/index.js.map +0 -0
@@ -171,7 +171,7 @@ module.exports = __toCommonJS(client_exports);
171
171
  // src/client/CoinListProvider.tsx
172
172
  var import_react3 = require("react");
173
173
 
174
- // src/shared/core/utils/crypto.ts
174
+ // src/universal/core/shared/utils/crypto.ts
175
175
  async function sha256(data) {
176
176
  const bytes = typeof data === "string" ? new TextEncoder().encode(data) : data;
177
177
  const buffer = bytes.buffer.slice(
@@ -232,7 +232,7 @@ function getDeviceId() {
232
232
  return deviceId;
233
233
  }
234
234
 
235
- // src/shared/api/frontline/config.ts
235
+ // src/universal/api/frontline/config.ts
236
236
  var PUBLIC_API_BASE_URL = "https://api.coinlist.co";
237
237
  var HEADER_API_VERSION = "X-API-Version";
238
238
  var HEADER_USER_AGENT = "User-Agent";
@@ -245,7 +245,7 @@ var VERIFY_IDENTITY_PATH = "/verify-identity";
245
245
  var VERIFY_IDENTITY_ACCREDITATION_PATH = "/verify-identity/accreditation_full";
246
246
  var WALLET_PATH = "/wallet";
247
247
 
248
- // src/shared/api/http-attributes.ts
248
+ // src/universal/api/http-attributes.ts
249
249
  var empty = {};
250
250
  var concat = (left, right) => ({
251
251
  ...left,
@@ -324,7 +324,7 @@ function generateUserAgent() {
324
324
  return `${appInfo} (${deviceInfo}; ${devicePlatform}; ${deviceAppId}; ${finalDeviceId})`;
325
325
  }
326
326
 
327
- // src/shared/api/http.ts
327
+ // src/universal/api/http.ts
328
328
  var HttpError = class extends Error {
329
329
  constructor(response) {
330
330
  super(`Request failed with ${response.status} status`);
@@ -448,7 +448,7 @@ var Request = {
448
448
  concatAttributes
449
449
  };
450
450
 
451
- // src/shared/types/errors.ts
451
+ // src/universal/types/errors.ts
452
452
  var NotImplementedError = class extends Error {
453
453
  constructor(message = "Not implemented yet") {
454
454
  super(message);
@@ -480,7 +480,7 @@ var MathError = class extends Error {
480
480
  }
481
481
  };
482
482
 
483
- // src/shared/core/observability/log-cause.ts
483
+ // src/universal/core/shared/observability/log-cause.ts
484
484
  function classifyLogCause(error) {
485
485
  if (error instanceof HttpError) {
486
486
  return httpCause(error);
@@ -546,7 +546,7 @@ function apiErrorEventId(error) {
546
546
  return typeof eventId === "string" ? eventId : null;
547
547
  }
548
548
 
549
- // src/shared/core/observability/internal-logger.ts
549
+ // src/universal/core/shared/observability/internal-logger.ts
550
550
  function internalLogger(logger, scope) {
551
551
  return logger ? scopedLogger(logger, scope, {}) : noopInternalLogger;
552
552
  }
@@ -629,7 +629,7 @@ var noopInternalLogger = {
629
629
  wrap: (_op, _params, run) => run()
630
630
  };
631
631
 
632
- // src/shared/api/http-client.ts
632
+ // src/universal/api/http-client.ts
633
633
  var HttpClient = class {
634
634
  constructor(config, middleware = {}, logger = null, options = {}) {
635
635
  this.config = config;
@@ -785,7 +785,7 @@ function describeRequestUnredacted(request) {
785
785
  };
786
786
  }
787
787
 
788
- // src/shared/api/middleware/attach-session-middleware.ts
788
+ // src/universal/api/middleware/attach-session-middleware.ts
789
789
  function attachSessionMiddleware(fetchAccessToken) {
790
790
  return async (request) => {
791
791
  if (!Attributes.isProtected(request.attributes)) {
@@ -811,7 +811,7 @@ function attachSessionMiddleware(fetchAccessToken) {
811
811
  };
812
812
  }
813
813
 
814
- // src/shared/api/middleware/idempotency-key.ts
814
+ // src/universal/api/middleware/idempotency-key.ts
815
815
  var idempotencyKeyMiddleware = async (request) => {
816
816
  if (!Attributes.isIdempotent(request.attributes)) {
817
817
  return request;
@@ -829,7 +829,7 @@ var idempotencyKeyMiddleware = async (request) => {
829
829
  };
830
830
  };
831
831
 
832
- // src/shared/api/middleware/request-retry.ts
832
+ // src/universal/api/middleware/request-retry.ts
833
833
  var MAX_ATTEMPTS = 3;
834
834
  var INITIAL_DELAY_MS = 300;
835
835
  var MAX_DELAY_MS = 2e3;
@@ -864,7 +864,7 @@ function defaultDelay(ms) {
864
864
  }
865
865
  var requestRetryMiddleware = createRequestRetryMiddleware();
866
866
 
867
- // src/shared/api/middleware/session-renewal.ts
867
+ // src/universal/api/middleware/session-renewal.ts
868
868
  function renewSessionMiddleware(fetchAccessToken) {
869
869
  return async ({ request, response, retry }) => {
870
870
  if (response.status !== 401) {
@@ -889,7 +889,7 @@ function renewSessionMiddleware(fetchAccessToken) {
889
889
  };
890
890
  }
891
891
 
892
- // src/shared/api/authenticated-api-client.ts
892
+ // src/universal/api/authenticated-api-client.ts
893
893
  var AuthenticatedApiClient = class {
894
894
  constructor(config, fetchAccessToken, additionalBeforeRequest = [], logger = null) {
895
895
  this.httpClient = new HttpClient(
@@ -933,13 +933,13 @@ var ApiClient = class {
933
933
  }
934
934
  };
935
935
 
936
- // src/shared/types/oauth.ts
936
+ // src/universal/types/oauth.ts
937
937
  var AuthorizationCode = (value) => value;
938
938
  var CodeVerifier = (value) => value;
939
939
  var CodeChallenge = (value) => value;
940
940
  var PKCEState = (value) => value;
941
941
 
942
- // src/shared/core/auth/pkce.ts
942
+ // src/universal/core/auth/pkce.ts
943
943
  async function generatePKCEParams(config) {
944
944
  const state = generateSecureRandomBase64Url(32);
945
945
  const codeVerifier = generateSecureRandomBase64Url(32);
@@ -1044,7 +1044,7 @@ var ClientAuthNamespaceImpl = class {
1044
1044
  }
1045
1045
  };
1046
1046
 
1047
- // src/client/core/blockchain/wallet-error.ts
1047
+ // src/client/core/shared/blockchain/wallet-error.ts
1048
1048
  var import_viem = require("viem");
1049
1049
  function classifyWalletError(error, ctx) {
1050
1050
  if (causeOf(error, import_viem.UserRejectedRequestError)) {
@@ -1073,7 +1073,7 @@ function revertReason(error) {
1073
1073
  return error.reason ?? error.data?.errorName ?? error.signature ?? null;
1074
1074
  }
1075
1075
 
1076
- // src/shared/core/blockchain/erc20/abi.ts
1076
+ // src/universal/core/shared/blockchain/erc20/abi.ts
1077
1077
  var ERC20_ABI = [
1078
1078
  {
1079
1079
  type: "function",
@@ -1173,7 +1173,7 @@ var ERC20_ABI = [
1173
1173
  }
1174
1174
  ];
1175
1175
 
1176
- // src/client/core/blockchain/erc20/approval.ts
1176
+ // src/client/core/shared/blockchain/erc20/approval.ts
1177
1177
  async function ensureErc20Allowance({
1178
1178
  erc20,
1179
1179
  chain,
@@ -1271,7 +1271,7 @@ async function submitErc20Approval(args) {
1271
1271
  return { type: "ok", txHash: hash };
1272
1272
  }
1273
1273
 
1274
- // src/shared/api/pagination.ts
1274
+ // src/universal/api/pagination.ts
1275
1275
  async function fetchAllPages(fetchPage, baseParams) {
1276
1276
  const items = [];
1277
1277
  let cursor = null;
@@ -1287,7 +1287,44 @@ async function fetchAllPages(fetchPage, baseParams) {
1287
1287
  return items;
1288
1288
  }
1289
1289
 
1290
- // src/shared/types/blockchain/core.ts
1290
+ // src/universal/types/pagination.ts
1291
+ var Cursor = (value) => value;
1292
+ var PaginatedResponse = {
1293
+ fromDto: (dto, itemMapper) => ({
1294
+ data: dto.data.map(itemMapper),
1295
+ startingAfter: dto.starting_after ? Cursor(dto.starting_after) : null,
1296
+ startingBefore: dto.starting_before ? Cursor(dto.starting_before) : null
1297
+ })
1298
+ };
1299
+ var PaginationParams = {
1300
+ toQueryParams: (params) => {
1301
+ const queryParams = {};
1302
+ if (params.after) {
1303
+ queryParams.starting_after = params.after;
1304
+ }
1305
+ if (params.before) {
1306
+ queryParams.starting_before = params.before;
1307
+ }
1308
+ if (params.limit) {
1309
+ queryParams.limit = params.limit;
1310
+ }
1311
+ return queryParams;
1312
+ }
1313
+ };
1314
+
1315
+ // src/universal/types/asset.ts
1316
+ var AssetId = (value) => value;
1317
+ var AssetCode = (value) => value;
1318
+ var Asset = {
1319
+ fromDto: (dto) => ({
1320
+ id: AssetId(dto.id),
1321
+ code: AssetCode(dto.code),
1322
+ name: dto.name,
1323
+ fractionalDigits: dto.fractional_digits
1324
+ })
1325
+ };
1326
+
1327
+ // src/universal/types/blockchain/core.ts
1291
1328
  var ETHEREUM_CHAINS = {
1292
1329
  ethereum_mainnet: true,
1293
1330
  ethereum_sepolia: true,
@@ -1377,392 +1414,277 @@ var AssetSymbol = (value) => value;
1377
1414
  var StablecoinSymbol = (value) => value;
1378
1415
  var Bps = (value) => value;
1379
1416
 
1380
- // src/shared/core/blockchain/bps.ts
1381
- var BPS_DENOM = Bps(10000n);
1382
- function applyBps(amount, bps) {
1383
- return assertUint256(amount * bps / BPS_DENOM);
1384
- }
1385
-
1386
- // src/shared/types/blockchain/ui.ts
1387
- var FormattedAmountUi = (value) => value;
1388
- var FormattedPercentUi = (value) => value;
1389
- var TxExplorerUrl = (value) => value;
1390
- var ShortenedWalletAddress = (value) => value;
1391
- var FormattedAmountAssetUi = (value) => value;
1392
- var AssetIconUrl = (value) => value;
1417
+ // src/universal/types/offer.ts
1418
+ var OfferId = (value) => value;
1419
+ var OfferSlug = (value) => value;
1420
+ var Offer = {
1421
+ fromDto: (dto) => {
1422
+ if (!Array.isArray(dto.tokens)) {
1423
+ throw new ValidationError(
1424
+ `Offer.tokens: expected an array, got ${typeof dto.tokens}`
1425
+ );
1426
+ }
1427
+ return {
1428
+ id: OfferId(dto.id),
1429
+ slug: OfferSlug(dto.slug),
1430
+ type: dto.type,
1431
+ tagline: dto.tagline,
1432
+ bannerUrl: dto.banner_url,
1433
+ logoUrl: dto.logo_url,
1434
+ startsAt: new Date(dto.starts_at),
1435
+ endsAt: dto.ends_at ? new Date(dto.ends_at) : null,
1436
+ tokens: OfferToken.listFromDto(dto.tokens)
1437
+ };
1438
+ }
1439
+ };
1440
+ var OfferToken = {
1441
+ fromDto: (dto) => ({
1442
+ role: dto.role,
1443
+ chain: Chain(dto.chain),
1444
+ address: EvmContractAddress(dto.address)
1445
+ }),
1446
+ /**
1447
+ * Maps an offer's token list, dropping every token on a chain this SDK does
1448
+ * not name. Frontline's chain registry runs ahead of {@link Chain}, and a
1449
+ * plain `.map` would throw out of `Offer.fromDto` and, through
1450
+ * `PaginatedResponse.fromDto`, reject the whole offers page - which is how
1451
+ * one Base token blanked production's offers list. Dropping costs that
1452
+ * token's metadata alone: `coinlist.tokens.get` takes an `EthereumChain`,
1453
+ * so nobody could have looked it up anyway.
1454
+ *
1455
+ * Same shape as `TokenMetadata.fromRegistryDto`.
1456
+ */
1457
+ listFromDto: (dtos) => dtos.filter((dto) => isChain(dto.chain)).map(OfferToken.fromDto)
1458
+ };
1393
1459
 
1394
- // src/shared/core/blockchain/chain.ts
1395
- var CHAIN_IDS = {
1396
- ethereum_mainnet: 1,
1397
- ethereum_sepolia: 11155111,
1398
- base_mainnet: 8453,
1399
- base_sepolia: 84532
1460
+ // src/universal/types/offer-detail.ts
1461
+ var OfferOptionId = (value) => value;
1462
+ var OfferOptionSlug = (value) => value;
1463
+ var OfferSwapContract = {
1464
+ fromDto: (dto) => ({
1465
+ chain: Chain(dto.chain),
1466
+ address: EvmContractAddress(dto.address)
1467
+ })
1400
1468
  };
1401
- function chainFromId(chainId) {
1402
- const chains = Object.keys(CHAIN_IDS);
1403
- const chain = chains.find((c) => String(CHAIN_IDS[c]) === chainId);
1404
- if (!chain) {
1405
- throw new ValidationError(`Unsupported EIP-155 chain id: "${chainId}"`);
1406
- }
1407
- return chain;
1408
- }
1409
- function getNetworkName(chain) {
1410
- switch (chain) {
1411
- case "ethereum_mainnet":
1412
- return "Ethereum";
1413
- case "ethereum_sepolia":
1414
- return "Ethereum Sepolia";
1415
- case "base_mainnet":
1416
- return "Base";
1417
- case "base_sepolia":
1418
- return "Base Sepolia";
1419
- default: {
1420
- const _exhaustive = chain;
1421
- return _exhaustive;
1469
+ var OfferDetail = {
1470
+ fromDto: (dto) => {
1471
+ if (!Array.isArray(dto.funding_assets)) {
1472
+ throw new ValidationError(
1473
+ `OfferDetail.funding_assets: expected an array, got ${typeof dto.funding_assets}`
1474
+ );
1422
1475
  }
1423
- }
1424
- }
1425
- function txExplorerUrl(chain, txHash) {
1426
- return TxExplorerUrl(`${explorerBaseUrl(chain)}/tx/${txHash}`);
1427
- }
1428
- function explorerBaseUrl(chain) {
1429
- switch (chain) {
1430
- case "ethereum_mainnet":
1431
- return "https://etherscan.io";
1432
- case "ethereum_sepolia":
1433
- return "https://sepolia.etherscan.io";
1434
- case "base_mainnet":
1435
- return "https://basescan.org";
1436
- case "base_sepolia":
1437
- return "https://sepolia-explorer.base.org";
1438
- default: {
1439
- const _exhaustive = chain;
1440
- return _exhaustive;
1476
+ if (!Array.isArray(dto.options)) {
1477
+ throw new ValidationError(
1478
+ `OfferDetail.options: expected an array, got ${typeof dto.options}`
1479
+ );
1480
+ }
1481
+ if (!Array.isArray(dto.terms)) {
1482
+ throw new ValidationError(
1483
+ `OfferDetail.terms: expected an array, got ${typeof dto.terms}`
1484
+ );
1485
+ }
1486
+ if (!Array.isArray(dto.links)) {
1487
+ throw new ValidationError(
1488
+ `OfferDetail.links: expected an array, got ${typeof dto.links}`
1489
+ );
1490
+ }
1491
+ if (!Array.isArray(dto.faqs)) {
1492
+ throw new ValidationError(
1493
+ `OfferDetail.faqs: expected an array, got ${typeof dto.faqs}`
1494
+ );
1495
+ }
1496
+ if (!Array.isArray(dto.milestones)) {
1497
+ throw new ValidationError(
1498
+ `OfferDetail.milestones: expected an array, got ${typeof dto.milestones}`
1499
+ );
1500
+ }
1501
+ if (!Array.isArray(dto.tokens)) {
1502
+ throw new ValidationError(
1503
+ `OfferDetail.tokens: expected an array, got ${typeof dto.tokens}`
1504
+ );
1505
+ }
1506
+ const swapContracts = dto.swap_contracts === void 0 ? [] : dto.swap_contracts;
1507
+ if (!Array.isArray(swapContracts)) {
1508
+ throw new ValidationError(
1509
+ `OfferDetail.swap_contracts: expected an array, got ${typeof swapContracts}`
1510
+ );
1441
1511
  }
1512
+ return {
1513
+ id: OfferId(dto.id),
1514
+ slug: OfferSlug(dto.slug),
1515
+ type: dto.type,
1516
+ name: dto.name,
1517
+ asset: Asset.fromDto(dto.asset),
1518
+ fundingAssets: dto.funding_assets.map(Asset.fromDto),
1519
+ tokens: OfferToken.listFromDto(dto.tokens),
1520
+ swapContracts: swapContracts.map(OfferSwapContract.fromDto),
1521
+ about: notBlankStringOrNull(dto.about),
1522
+ tagline: dto.tagline,
1523
+ bannerUrl: dto.banner_url,
1524
+ logoUrl: dto.logo_url,
1525
+ category: dto.category,
1526
+ startsAt: new Date(dto.starts_at),
1527
+ endsAt: dto.ends_at ? new Date(dto.ends_at) : null,
1528
+ faqs: dto.faqs.map(FaqItem.fromDto),
1529
+ links: dto.links.map(Link.fromDto),
1530
+ milestones: dto.milestones.map(Milestone.fromDto),
1531
+ options: dto.options.map(OfferOption.fromDto),
1532
+ terms: dto.terms.map(TermItem.fromDto)
1533
+ };
1442
1534
  }
1443
- }
1444
-
1445
- // src/shared/types/providers/superstate/swap.ts
1446
- var SwapAuthorization = {
1535
+ };
1536
+ var OfferOption = {
1447
1537
  fromDto: (dto) => ({
1448
- authorized: dto.authorized
1538
+ id: OfferOptionId(dto.id),
1539
+ slug: OfferOptionSlug(dto.slug),
1540
+ bidIncrement: dto.bid_increment,
1541
+ floorPriceUsd: dto.floor_price_usd,
1542
+ minimumPurchaseUsd: dto.minimum_purchase_usd,
1543
+ priceUsd: dto.price_usd,
1544
+ saleAgreementUrl: notBlankStringOrNull(dto.sale_agreement_url),
1545
+ totalTokenSupply: dto.total_token_supply
1449
1546
  })
1450
1547
  };
1451
- var SwapPreview = {
1548
+ var FaqItem = {
1452
1549
  fromDto: (dto) => ({
1453
- inputAmount: parseUint256(
1454
- BigInt(dto.pay_input_amount),
1455
- "SwapPreview.pay_input_amount"
1456
- ),
1457
- fee: parseUint256(BigInt(dto.fee), "SwapPreview.fee"),
1458
- outputAmount: parseUint256(
1459
- BigInt(dto.receive_output_amount),
1460
- "SwapPreview.receive_output_amount"
1461
- )
1550
+ question: notBlankStringOrNull(dto.question),
1551
+ answer: notBlankStringOrNull(dto.answer)
1462
1552
  })
1463
1553
  };
1464
- var SwapStatus = {
1554
+ var Link = {
1465
1555
  fromDto: (dto) => ({
1466
- stopped: parseUint256(BigInt(dto.stopped), "SwapStatus.stopped"),
1467
- swapLevel: parseUint256(BigInt(dto.swap_level), "SwapStatus.swap_level")
1556
+ label: notBlankStringOrNull(dto.label),
1557
+ url: notBlankStringOrNull(dto.url)
1468
1558
  })
1469
1559
  };
1470
- var TokenAllowance = {
1560
+ var TermItem = {
1471
1561
  fromDto: (dto) => ({
1472
- allowance: parseUint256(BigInt(dto.allowance), "TokenAllowance.allowance")
1562
+ key: notBlankStringOrNull(dto.key),
1563
+ value: notBlankStringOrNull(dto.value)
1473
1564
  })
1474
1565
  };
1475
- var TokenBalance = {
1566
+ var Milestone = {
1476
1567
  fromDto: (dto) => ({
1477
- balance: parseUint256(BigInt(dto.balance), "TokenBalance.balance")
1568
+ name: notBlankStringOrNull(dto.name),
1569
+ schedule: notBlankStringOrNull(dto.schedule),
1570
+ status: dto.status
1478
1571
  })
1479
1572
  };
1480
- var AllowWalletResponse = {
1481
- fromDto: (dto) => {
1482
- switch (dto.action) {
1483
- case "broadcast_transaction":
1484
- return {
1485
- action: "broadcast_transaction",
1486
- to: EvmContractAddress(dto.to),
1487
- data: HexEncodedTransactionData(dto.data)
1488
- };
1489
- case "none":
1490
- return {
1491
- action: "none",
1492
- alreadyAllowed: dto.already_allowed
1493
- };
1494
- default: {
1495
- const _exhaustive = dto;
1496
- return _exhaustive;
1497
- }
1573
+
1574
+ // src/universal/types/providers/coin-list/token-sale.ts
1575
+ var ParticipationId = (value) => value;
1576
+ var Blockchain = (value) => value;
1577
+ var WalletAddress = (value) => value;
1578
+ var ParticipationsPaginationParams = {
1579
+ toQueryParams: (params) => {
1580
+ const queryParams = PaginationParams.toQueryParams(params);
1581
+ if (params.offerId) {
1582
+ queryParams["filters[0][field]"] = "offer_id";
1583
+ queryParams["filters[0][op]"] = "==";
1584
+ queryParams["filters[0][value]"] = params.offerId;
1498
1585
  }
1586
+ return queryParams;
1587
+ }
1588
+ };
1589
+ var Participation = {
1590
+ /** Maps API DTO shape into the SDK participation domain model. */
1591
+ fromDto: (dto) => {
1592
+ const walletAddress = notBlankStringOrNull(dto.wallet_address);
1593
+ return {
1594
+ id: ParticipationId(dto.id),
1595
+ offerId: OfferId(dto.offer_id),
1596
+ offerOptionId: OfferOptionId(dto.offer_option_id),
1597
+ status: dto.status,
1598
+ amount: dto.amount,
1599
+ displayAmount: dto.amount_string,
1600
+ asset: Asset.fromDto(dto.asset),
1601
+ chain: Blockchain(dto.chain),
1602
+ insertedAt: dto.inserted_at ? new Date(dto.inserted_at) : null,
1603
+ updatedAt: dto.updated_at ? new Date(dto.updated_at) : null,
1604
+ walletAddress: walletAddress ? WalletAddress(walletAddress) : null
1605
+ };
1499
1606
  }
1500
1607
  };
1608
+ var CreateParticipationParams = {
1609
+ /** Maps participation creation params into API DTO payload. */
1610
+ toDto: (params) => ({
1611
+ offer_id: params.offerId,
1612
+ offer_option_id: params.offerOptionId,
1613
+ chain: params.chain,
1614
+ wallet_address: params.walletAddress,
1615
+ amount: params.amount,
1616
+ asset_id: params.assetId,
1617
+ approval_transaction_hash: params.approvalTransactionHash
1618
+ })
1619
+ };
1501
1620
 
1502
- // src/shared/api/frontline/providers/superstate/swap.ts
1503
- async function getSwapAuthorization(api, params) {
1504
- const dto = await api.send({
1505
- method: "GET",
1506
- url: "/v1/wallet/authorized",
1507
- queryParams: {
1508
- chain: params.chain,
1509
- contract_address: params.contractAddress,
1510
- wallet_address: params.walletAddress
1511
- },
1512
- attributes: Attributes.protected()
1513
- });
1514
- return SwapAuthorization.fromDto(dto);
1515
- }
1516
- async function getSwapOutputToken(api, params) {
1517
- const dto = await api.send({
1518
- method: "GET",
1519
- url: "/v1/swap/output-token",
1520
- queryParams: {
1521
- chain: params.chain,
1522
- contract_address: params.contractAddress
1523
- },
1524
- attributes: Attributes.protected()
1525
- });
1526
- return toErc20Asset(dto);
1527
- }
1528
- async function getSwapPreview(api, params) {
1529
- const dto = await api.send({
1530
- method: "GET",
1531
- url: "/v1/swap/preview",
1532
- queryParams: {
1533
- chain: params.chain,
1534
- contract_address: params.contractAddress,
1535
- input_token: params.inputToken,
1536
- amount: params.amount.toString()
1537
- },
1538
- attributes: Attributes.protected()
1539
- });
1540
- return SwapPreview.fromDto(dto);
1541
- }
1542
- async function getSwapStatus(api, params) {
1543
- const dto = await api.send({
1544
- method: "GET",
1545
- url: "/v1/swap/status",
1546
- queryParams: {
1547
- chain: params.chain,
1548
- contract_address: params.contractAddress
1549
- },
1550
- attributes: Attributes.protected()
1551
- });
1552
- return SwapStatus.fromDto(dto);
1621
+ // src/universal/api/frontline/providers/coin-list/token-sale.ts
1622
+ async function fetchParticipations(api, offerId) {
1623
+ return fetchAllPages(
1624
+ (params) => fetchParticipationsPage(api, params),
1625
+ { offerId }
1626
+ );
1553
1627
  }
1554
- async function getTokenAllowance(api, params) {
1555
- const dto = await api.send({
1628
+ async function fetchParticipationsPage(api, params) {
1629
+ const pageDto = await api.send({
1556
1630
  method: "GET",
1557
- url: "/v1/token/allowance",
1558
- queryParams: {
1559
- chain: params.chain,
1560
- token_address: params.tokenAddress,
1561
- owner: params.owner,
1562
- spender: params.spender
1563
- },
1631
+ url: "/v1/participations",
1632
+ queryParams: ParticipationsPaginationParams.toQueryParams(params),
1564
1633
  attributes: Attributes.protected()
1565
1634
  });
1566
- return TokenAllowance.fromDto(dto);
1635
+ return PaginatedResponse.fromDto(pageDto, Participation.fromDto);
1567
1636
  }
1568
- async function getTokenBalance(api, params) {
1637
+ async function fetchParticipation(api, id) {
1569
1638
  const dto = await api.send({
1570
1639
  method: "GET",
1571
- url: "/v1/token/balance",
1572
- queryParams: {
1573
- chain: params.chain,
1574
- token_address: params.tokenAddress,
1575
- owner: params.owner
1576
- },
1640
+ url: `/v1/participations/${id}`,
1577
1641
  attributes: Attributes.protected()
1578
1642
  });
1579
- return TokenBalance.fromDto(dto);
1643
+ return Participation.fromDto(dto);
1580
1644
  }
1581
- async function allowWallet(api, params) {
1645
+ async function createParticipation(api, params) {
1582
1646
  const dto = await api.send({
1583
1647
  method: "POST",
1584
- url: `/v1/offers/${encodeURIComponent(params.offerId)}/allow-wallet`,
1585
- body: {
1586
- wallet_address: params.walletAddress,
1587
- chain: params.chain,
1588
- signature: params.signature
1589
- },
1648
+ url: "/v1/participations",
1649
+ body: CreateParticipationParams.toDto(params),
1590
1650
  attributes: Attributes.protected()
1591
1651
  });
1592
- return AllowWalletResponse.fromDto(dto);
1593
- }
1594
- function toErc20Asset(dto) {
1595
- return {
1596
- name: dto.name,
1597
- symbol: AssetSymbol(dto.symbol),
1598
- decimals: AssetDecimals(dto.decimals)
1599
- };
1652
+ return Participation.fromDto(dto);
1600
1653
  }
1601
1654
 
1602
- // src/shared/core/blockchain/erc20/erc20-namespace.ts
1603
- var Erc20NamespaceImpl = class {
1655
+ // src/universal/core/checkout/coin-list/token-sale-namespace.ts
1656
+ var CoinListTokenSaleNamespaceImpl = class {
1604
1657
  constructor(ctx) {
1605
1658
  this.ctx = ctx;
1606
- this.log = internalLogger(ctx.logger, "ERC20");
1659
+ this.log = internalLogger(ctx.logger, "TOKEN_SALE");
1607
1660
  }
1608
- async getAllowance(params) {
1609
- return this.log.wrap("getAllowance", params, async () => {
1661
+ async list(offerId) {
1662
+ return this.log.wrap("list", offerId, async () => {
1610
1663
  await this.ctx.ensureUserAuthenticated();
1611
- return getTokenAllowance(this.ctx.api, params);
1664
+ return fetchParticipations(this.ctx.api, offerId);
1612
1665
  });
1613
1666
  }
1614
- async getBalance(params) {
1615
- return this.log.wrap("getBalance", params, async () => {
1667
+ async listPage(params) {
1668
+ return this.log.wrap("listPage", params, async () => {
1616
1669
  await this.ctx.ensureUserAuthenticated();
1617
- return getTokenBalance(this.ctx.api, params);
1670
+ return fetchParticipationsPage(this.ctx.api, params);
1618
1671
  });
1619
1672
  }
1620
- };
1621
-
1622
- // src/shared/core/blockchain/formatters.ts
1623
- var import_viem2 = require("viem");
1624
- function shortenAddress(address) {
1625
- const short = address.length > 10 ? `${address.slice(0, 6)}\u2026${address.slice(-4)}` : address;
1626
- return ShortenedWalletAddress(short);
1627
- }
1628
- function formatAmount(amount, locale, options) {
1629
- const decimal = formatRawAmount(amount);
1630
- let [integerPart, fractionPart = ""] = decimal.split(".");
1631
- const maxFractionDigits = options?.maxFractionDigits;
1632
- const minFractionDigits = maxFractionDigits !== void 0 ? Math.min(maxFractionDigits, amount.decimals) : Math.min(2, amount.decimals);
1633
- if (maxFractionDigits !== void 0 && fractionPart.length > maxFractionDigits) {
1634
- ({ integerPart, fractionPart } = roundFractionHalfUp(
1635
- integerPart,
1636
- fractionPart,
1637
- maxFractionDigits
1638
- ));
1639
- }
1640
- const fraction = minFractionDigits === 0 ? "" : fractionPart.padEnd(minFractionDigits, "0");
1641
- const integerFormatted = BigInt(integerPart).toLocaleString(locale);
1642
- if (minFractionDigits === 0 && fraction === "") {
1643
- return FormattedAmountUi(integerFormatted);
1644
- }
1645
- const decimalSeparator = new Intl.NumberFormat(locale).formatToParts(1.1).find((p) => p.type === "decimal")?.value ?? ".";
1646
- return FormattedAmountUi(`${integerFormatted}${decimalSeparator}${fraction}`);
1647
- }
1648
- function roundFractionHalfUp(integerPart, fractionPart, maxFractionDigits) {
1649
- if (fractionPart.length <= maxFractionDigits) {
1650
- return { integerPart, fractionPart };
1651
- }
1652
- if (maxFractionDigits === 0) {
1653
- const roundUp = fractionPart[0] >= "5";
1654
- const integer = BigInt(integerPart) + (roundUp ? 1n : 0n);
1655
- return { integerPart: integer.toString(), fractionPart: "" };
1656
- }
1657
- const trimmed = fractionPart.slice(0, maxFractionDigits);
1658
- if (fractionPart[maxFractionDigits] < "5") {
1659
- return { integerPart, fractionPart: trimmed };
1660
- }
1661
- const digits = trimmed.split("").map((digit) => Number.parseInt(digit, 10));
1662
- let carry = 1;
1663
- for (let i = digits.length - 1; i >= 0 && carry > 0; i -= 1) {
1664
- const sum = digits[i] + carry;
1665
- if (sum === 10) {
1666
- digits[i] = 0;
1667
- carry = 1;
1668
- } else {
1669
- digits[i] = sum;
1670
- carry = 0;
1671
- }
1673
+ async get(id) {
1674
+ return this.log.wrap("get", id, async () => {
1675
+ await this.ctx.ensureUserAuthenticated();
1676
+ return fetchParticipation(this.ctx.api, id);
1677
+ });
1672
1678
  }
1673
- return {
1674
- integerPart: carry > 0 ? (BigInt(integerPart) + 1n).toString() : integerPart,
1675
- fractionPart: digits.join("")
1676
- };
1677
- }
1678
- function formatRawAmount(amount) {
1679
- return (0, import_viem2.formatUnits)(amount.raw, amount.decimals);
1680
- }
1681
- function formatBpsAsPercent(bps, locale) {
1682
- const whole = bps / 100n;
1683
- const fraction = bps % 100n;
1684
- const wholeFormatted = whole.toLocaleString(locale);
1685
- const decimalSeparator = new Intl.NumberFormat(locale).formatToParts(1.1).find((p) => p.type === "decimal")?.value ?? ".";
1686
- if (fraction === 0n) {
1687
- return FormattedPercentUi(`${wholeFormatted}%`);
1679
+ async createParticipation(params) {
1680
+ return this.log.wrap("createParticipation", params, async () => {
1681
+ await this.ctx.ensureUserAuthenticated();
1682
+ return createParticipation(this.ctx.api, params);
1683
+ });
1688
1684
  }
1689
- const fractionFormatted = fraction.toString().padStart(2, "0").replace(/0+$/, "");
1690
- return FormattedPercentUi(
1691
- `${wholeFormatted}${decimalSeparator}${fractionFormatted}%`
1692
- );
1693
- }
1694
- function usdAmount(amount) {
1695
- return FormattedAmountAssetUi(`$${amount}`);
1696
- }
1697
- function assetAmount(amount, symbol) {
1698
- return FormattedAmountAssetUi(`${amount} ${symbol}`);
1699
- }
1700
- var NA_AMOUNT_ASSET_UI = FormattedAmountAssetUi("-");
1701
- var USD_FRACTION_DIGITS = AssetDecimals(2);
1702
- function formattedUsdPrice(amount, locale) {
1703
- if (!amount) return NA_AMOUNT_ASSET_UI;
1704
- return usdAmount(
1705
- formatAmount(amount, locale, { maxFractionDigits: USD_FRACTION_DIGITS })
1706
- );
1707
- }
1708
-
1709
- // src/shared/core/blockchain/math.ts
1710
- var import_viem3 = require("viem");
1711
- function blockchainAmountFromRawOrThrow({
1712
- label,
1713
- raw,
1714
- decimals
1715
- }) {
1716
- const trimmed = raw.trim();
1717
- if (trimmed === "") {
1718
- throw new ValidationError(`${label}: not a uint256 integer ("${raw}")`);
1719
- }
1720
- let value;
1721
- try {
1722
- value = BigInt(trimmed);
1723
- } catch {
1724
- throw new ValidationError(`${label}: not a uint256 integer ("${raw}")`);
1725
- }
1726
- try {
1727
- return BlockchainAmount({ raw: assertUint256(value), decimals });
1728
- } catch {
1729
- throw new ValidationError(`${label}: out of uint256 bounds (${value})`);
1730
- }
1731
- }
1732
- function parseBlockchainAmount(amount, decimals) {
1733
- const trimmed = amount.trim();
1734
- if (trimmed === "") return { valid: false, reason: { type: "empty" } };
1735
- if (trimmed.startsWith("-")) {
1736
- return { valid: false, reason: { type: "negative" } };
1737
- }
1738
- if (/[eE]/.test(trimmed)) {
1739
- return { valid: false, reason: { type: "invalid-format" } };
1740
- }
1741
- if (!/^\d+(\.\d+)?$/.test(trimmed)) {
1742
- return { valid: false, reason: { type: "invalid-format" } };
1743
- }
1744
- const [, fraction = ""] = trimmed.split(".");
1745
- if (fraction.length > decimals) {
1746
- return {
1747
- valid: false,
1748
- reason: { type: "too-many-decimals", maxDecimals: decimals }
1749
- };
1750
- }
1751
- try {
1752
- const raw = (0, import_viem3.parseUnits)(trimmed, decimals);
1753
- if (raw > MAX_UINT_256) {
1754
- return { valid: false, reason: { type: "overflow" } };
1755
- }
1756
- return {
1757
- valid: true,
1758
- amount: BlockchainAmount({ raw, decimals })
1759
- };
1760
- } catch {
1761
- return { valid: false, reason: { type: "invalid-format" } };
1762
- }
1763
- }
1685
+ };
1764
1686
 
1765
- // src/shared/core/blockchain/token-registry.ts
1687
+ // src/universal/core/shared/blockchain/token-registry.ts
1766
1688
  var USDC_SYMBOL = StablecoinSymbol("USDC");
1767
1689
  var USDC = {
1768
1690
  name: "USD Coin",
@@ -1825,378 +1747,275 @@ var TOKEN_REGISTRY = {
1825
1747
  usdtAddress: (chain) => USDT_ADDRESSES[chain]
1826
1748
  };
1827
1749
 
1828
- // src/shared/types/pagination.ts
1829
- var Cursor = (value) => value;
1830
- var PaginatedResponse = {
1831
- fromDto: (dto, itemMapper) => ({
1832
- data: dto.data.map(itemMapper),
1833
- startingAfter: dto.starting_after ? Cursor(dto.starting_after) : null,
1834
- startingBefore: dto.starting_before ? Cursor(dto.starting_before) : null
1835
- })
1836
- };
1837
- var PaginationParams = {
1838
- toQueryParams: (params) => {
1839
- const queryParams = {};
1840
- if (params.after) {
1841
- queryParams.starting_after = params.after;
1842
- }
1843
- if (params.before) {
1844
- queryParams.starting_before = params.before;
1845
- }
1846
- if (params.limit) {
1847
- queryParams.limit = params.limit;
1848
- }
1849
- return queryParams;
1750
+ // src/universal/core/checkout/ondo/constants.ts
1751
+ var ONDO_POLL_INTERVAL_MS = 15e3;
1752
+ var ONDO_QUOTE_EXPIRY_THRESHOLD_MS = 5e3;
1753
+ var DEFAULT_ONDO_AMOUNT_TO_COMPUTE_PRICE = DecimalString("1000");
1754
+ var ONDO_SETTLEMENT_ASSET = USDC_SYMBOL;
1755
+ var DEFAULT_ONDO_SELL_TOKENS_TO_COMPUTE_PRICE = 1;
1756
+ var ONDO_SUPPORTED_INPUT_ASSETS = [
1757
+ USDC_SYMBOL
1758
+ ];
1759
+
1760
+ // src/universal/core/checkout/ondo/math.ts
1761
+ function computeOndoBuyPrice(transaction) {
1762
+ const { notionalValue, receiveOutputAmount } = transaction;
1763
+ return pricePerShare({
1764
+ usd: notionalValue,
1765
+ shares: receiveOutputAmount
1766
+ });
1767
+ }
1768
+ function computeOndoSellPrice(transaction) {
1769
+ const { expected, spendInputAmount } = transaction;
1770
+ return pricePerShare({
1771
+ usd: grossProceeds(expected),
1772
+ shares: spendInputAmount
1773
+ });
1774
+ }
1775
+ function grossProceeds(expected) {
1776
+ const raw = expected.quantity.raw + expected.fee.raw;
1777
+ if (raw > MAX_UINT_256) {
1778
+ throw new MathError(`Ondo sell proceeds: out of uint256 bounds (${raw})`);
1850
1779
  }
1851
- };
1780
+ return BlockchainAmount.add(expected.quantity, expected.fee);
1781
+ }
1782
+ function pricePerShare({
1783
+ usd,
1784
+ shares
1785
+ }) {
1786
+ const price = BlockchainAmount.div(usd, shares);
1787
+ return BlockchainAmount({
1788
+ raw: assertPriceFits(price.raw),
1789
+ decimals: price.decimals
1790
+ });
1791
+ }
1792
+ function assertPriceFits(raw) {
1793
+ try {
1794
+ return assertUint256(raw);
1795
+ } catch {
1796
+ throw new MathError(`Ondo price: out of uint256 bounds (${raw})`);
1797
+ }
1798
+ }
1852
1799
 
1853
- // src/shared/types/asset.ts
1854
- var AssetId = (value) => value;
1855
- var AssetCode = (value) => value;
1856
- var Asset = {
1857
- fromDto: (dto) => ({
1858
- id: AssetId(dto.id),
1859
- code: AssetCode(dto.code),
1860
- name: dto.name,
1861
- fractionalDigits: dto.fractional_digits
1862
- })
1863
- };
1800
+ // src/universal/core/shared/blockchain/formatters.ts
1801
+ var import_viem2 = require("viem");
1864
1802
 
1865
- // src/shared/types/offer.ts
1866
- var OfferId = (value) => value;
1867
- var OfferSlug = (value) => value;
1868
- var Offer = {
1869
- fromDto: (dto) => {
1870
- if (!Array.isArray(dto.tokens)) {
1871
- throw new ValidationError(
1872
- `Offer.tokens: expected an array, got ${typeof dto.tokens}`
1873
- );
1803
+ // src/universal/types/blockchain/ui.ts
1804
+ var FormattedAmountUi = (value) => value;
1805
+ var FormattedPercentUi = (value) => value;
1806
+ var TxExplorerUrl = (value) => value;
1807
+ var ShortenedWalletAddress = (value) => value;
1808
+ var FormattedAmountAssetUi = (value) => value;
1809
+ var AssetIconUrl = (value) => value;
1810
+
1811
+ // src/universal/core/shared/blockchain/formatters.ts
1812
+ function shortenAddress(address) {
1813
+ const short = address.length > 10 ? `${address.slice(0, 6)}\u2026${address.slice(-4)}` : address;
1814
+ return ShortenedWalletAddress(short);
1815
+ }
1816
+ function formatAmount(amount, locale, options) {
1817
+ const decimal = formatRawAmount(amount);
1818
+ let [integerPart, fractionPart = ""] = decimal.split(".");
1819
+ const maxFractionDigits = options?.maxFractionDigits;
1820
+ const minFractionDigits = maxFractionDigits !== void 0 ? Math.min(maxFractionDigits, amount.decimals) : Math.min(2, amount.decimals);
1821
+ if (maxFractionDigits !== void 0 && fractionPart.length > maxFractionDigits) {
1822
+ ({ integerPart, fractionPart } = roundFractionHalfUp(
1823
+ integerPart,
1824
+ fractionPart,
1825
+ maxFractionDigits
1826
+ ));
1827
+ }
1828
+ const fraction = minFractionDigits === 0 ? "" : fractionPart.padEnd(minFractionDigits, "0");
1829
+ const integerFormatted = BigInt(integerPart).toLocaleString(locale);
1830
+ if (minFractionDigits === 0 && fraction === "") {
1831
+ return FormattedAmountUi(integerFormatted);
1832
+ }
1833
+ const decimalSeparator = new Intl.NumberFormat(locale).formatToParts(1.1).find((p) => p.type === "decimal")?.value ?? ".";
1834
+ return FormattedAmountUi(`${integerFormatted}${decimalSeparator}${fraction}`);
1835
+ }
1836
+ function roundFractionHalfUp(integerPart, fractionPart, maxFractionDigits) {
1837
+ if (fractionPart.length <= maxFractionDigits) {
1838
+ return { integerPart, fractionPart };
1839
+ }
1840
+ if (maxFractionDigits === 0) {
1841
+ const roundUp = fractionPart[0] >= "5";
1842
+ const integer = BigInt(integerPart) + (roundUp ? 1n : 0n);
1843
+ return { integerPart: integer.toString(), fractionPart: "" };
1844
+ }
1845
+ const trimmed = fractionPart.slice(0, maxFractionDigits);
1846
+ if (fractionPart[maxFractionDigits] < "5") {
1847
+ return { integerPart, fractionPart: trimmed };
1848
+ }
1849
+ const digits = trimmed.split("").map((digit) => Number.parseInt(digit, 10));
1850
+ let carry = 1;
1851
+ for (let i = digits.length - 1; i >= 0 && carry > 0; i -= 1) {
1852
+ const sum = digits[i] + carry;
1853
+ if (sum === 10) {
1854
+ digits[i] = 0;
1855
+ carry = 1;
1856
+ } else {
1857
+ digits[i] = sum;
1858
+ carry = 0;
1874
1859
  }
1875
- return {
1876
- id: OfferId(dto.id),
1877
- slug: OfferSlug(dto.slug),
1878
- type: dto.type,
1879
- tagline: dto.tagline,
1880
- bannerUrl: dto.banner_url,
1881
- logoUrl: dto.logo_url,
1882
- startsAt: new Date(dto.starts_at),
1883
- endsAt: dto.ends_at ? new Date(dto.ends_at) : null,
1884
- tokens: OfferToken.listFromDto(dto.tokens)
1885
- };
1886
1860
  }
1861
+ return {
1862
+ integerPart: carry > 0 ? (BigInt(integerPart) + 1n).toString() : integerPart,
1863
+ fractionPart: digits.join("")
1864
+ };
1865
+ }
1866
+ function formatRawAmount(amount) {
1867
+ return (0, import_viem2.formatUnits)(amount.raw, amount.decimals);
1868
+ }
1869
+ function formatBpsAsPercent(bps, locale) {
1870
+ const whole = bps / 100n;
1871
+ const fraction = bps % 100n;
1872
+ const wholeFormatted = whole.toLocaleString(locale);
1873
+ const decimalSeparator = new Intl.NumberFormat(locale).formatToParts(1.1).find((p) => p.type === "decimal")?.value ?? ".";
1874
+ if (fraction === 0n) {
1875
+ return FormattedPercentUi(`${wholeFormatted}%`);
1876
+ }
1877
+ const fractionFormatted = fraction.toString().padStart(2, "0").replace(/0+$/, "");
1878
+ return FormattedPercentUi(
1879
+ `${wholeFormatted}${decimalSeparator}${fractionFormatted}%`
1880
+ );
1881
+ }
1882
+ function usdAmount(amount) {
1883
+ return FormattedAmountAssetUi(`$${amount}`);
1884
+ }
1885
+ function assetAmount(amount, symbol) {
1886
+ return FormattedAmountAssetUi(`${amount} ${symbol}`);
1887
+ }
1888
+ var NA_AMOUNT_ASSET_UI = FormattedAmountAssetUi("-");
1889
+ var USD_FRACTION_DIGITS = AssetDecimals(2);
1890
+ function formattedUsdPrice(amount, locale) {
1891
+ if (!amount) return NA_AMOUNT_ASSET_UI;
1892
+ return usdAmount(
1893
+ formatAmount(amount, locale, { maxFractionDigits: USD_FRACTION_DIGITS })
1894
+ );
1895
+ }
1896
+
1897
+ // src/universal/core/shared/blockchain/chain.ts
1898
+ var CHAIN_IDS = {
1899
+ ethereum_mainnet: 1,
1900
+ ethereum_sepolia: 11155111,
1901
+ base_mainnet: 8453,
1902
+ base_sepolia: 84532
1887
1903
  };
1888
- var OfferToken = {
1889
- fromDto: (dto) => ({
1890
- role: dto.role,
1891
- chain: Chain(dto.chain),
1892
- address: EvmContractAddress(dto.address)
1893
- }),
1894
- /**
1895
- * Maps an offer's token list, dropping every token on a chain this SDK does
1896
- * not name. Frontline's chain registry runs ahead of {@link Chain}, and a
1897
- * plain `.map` would throw out of `Offer.fromDto` and, through
1898
- * `PaginatedResponse.fromDto`, reject the whole offers page - which is how
1899
- * one Base token blanked production's offers list. Dropping costs that
1900
- * token's metadata alone: `coinlist.tokens.get` takes an `EthereumChain`,
1901
- * so nobody could have looked it up anyway.
1902
- *
1903
- * Same shape as `TokenMetadata.fromRegistryDto`.
1904
- */
1905
- listFromDto: (dtos) => dtos.filter((dto) => isChain(dto.chain)).map(OfferToken.fromDto)
1906
- };
1907
-
1908
- // src/shared/types/offer-detail.ts
1909
- var OfferOptionId = (value) => value;
1910
- var OfferOptionSlug = (value) => value;
1911
- var OfferSwapContract = {
1912
- fromDto: (dto) => ({
1913
- chain: Chain(dto.chain),
1914
- address: EvmContractAddress(dto.address)
1915
- })
1916
- };
1917
- var OfferDetail = {
1918
- fromDto: (dto) => {
1919
- if (!Array.isArray(dto.funding_assets)) {
1920
- throw new ValidationError(
1921
- `OfferDetail.funding_assets: expected an array, got ${typeof dto.funding_assets}`
1922
- );
1923
- }
1924
- if (!Array.isArray(dto.options)) {
1925
- throw new ValidationError(
1926
- `OfferDetail.options: expected an array, got ${typeof dto.options}`
1927
- );
1928
- }
1929
- if (!Array.isArray(dto.terms)) {
1930
- throw new ValidationError(
1931
- `OfferDetail.terms: expected an array, got ${typeof dto.terms}`
1932
- );
1933
- }
1934
- if (!Array.isArray(dto.links)) {
1935
- throw new ValidationError(
1936
- `OfferDetail.links: expected an array, got ${typeof dto.links}`
1937
- );
1938
- }
1939
- if (!Array.isArray(dto.faqs)) {
1940
- throw new ValidationError(
1941
- `OfferDetail.faqs: expected an array, got ${typeof dto.faqs}`
1942
- );
1943
- }
1944
- if (!Array.isArray(dto.milestones)) {
1945
- throw new ValidationError(
1946
- `OfferDetail.milestones: expected an array, got ${typeof dto.milestones}`
1947
- );
1948
- }
1949
- if (!Array.isArray(dto.tokens)) {
1950
- throw new ValidationError(
1951
- `OfferDetail.tokens: expected an array, got ${typeof dto.tokens}`
1952
- );
1904
+ function chainFromId(chainId) {
1905
+ const chains = Object.keys(CHAIN_IDS);
1906
+ const chain = chains.find((c) => String(CHAIN_IDS[c]) === chainId);
1907
+ if (!chain) {
1908
+ throw new ValidationError(`Unsupported EIP-155 chain id: "${chainId}"`);
1909
+ }
1910
+ return chain;
1911
+ }
1912
+ function getNetworkName(chain) {
1913
+ switch (chain) {
1914
+ case "ethereum_mainnet":
1915
+ return "Ethereum";
1916
+ case "ethereum_sepolia":
1917
+ return "Ethereum Sepolia";
1918
+ case "base_mainnet":
1919
+ return "Base";
1920
+ case "base_sepolia":
1921
+ return "Base Sepolia";
1922
+ default: {
1923
+ const _exhaustive = chain;
1924
+ return _exhaustive;
1953
1925
  }
1954
- const swapContracts = dto.swap_contracts === void 0 ? [] : dto.swap_contracts;
1955
- if (!Array.isArray(swapContracts)) {
1956
- throw new ValidationError(
1957
- `OfferDetail.swap_contracts: expected an array, got ${typeof swapContracts}`
1958
- );
1926
+ }
1927
+ }
1928
+ function txExplorerUrl(chain, txHash) {
1929
+ return TxExplorerUrl(`${explorerBaseUrl(chain)}/tx/${txHash}`);
1930
+ }
1931
+ function explorerBaseUrl(chain) {
1932
+ switch (chain) {
1933
+ case "ethereum_mainnet":
1934
+ return "https://etherscan.io";
1935
+ case "ethereum_sepolia":
1936
+ return "https://sepolia.etherscan.io";
1937
+ case "base_mainnet":
1938
+ return "https://basescan.org";
1939
+ case "base_sepolia":
1940
+ return "https://sepolia-explorer.base.org";
1941
+ default: {
1942
+ const _exhaustive = chain;
1943
+ return _exhaustive;
1959
1944
  }
1945
+ }
1946
+ }
1947
+
1948
+ // src/universal/core/shared/blockchain/math.ts
1949
+ var import_viem3 = require("viem");
1950
+ function blockchainAmountFromRawOrThrow({
1951
+ label,
1952
+ raw,
1953
+ decimals
1954
+ }) {
1955
+ const trimmed = raw.trim();
1956
+ if (trimmed === "") {
1957
+ throw new ValidationError(`${label}: not a uint256 integer ("${raw}")`);
1958
+ }
1959
+ let value;
1960
+ try {
1961
+ value = BigInt(trimmed);
1962
+ } catch {
1963
+ throw new ValidationError(`${label}: not a uint256 integer ("${raw}")`);
1964
+ }
1965
+ try {
1966
+ return BlockchainAmount({ raw: assertUint256(value), decimals });
1967
+ } catch {
1968
+ throw new ValidationError(`${label}: out of uint256 bounds (${value})`);
1969
+ }
1970
+ }
1971
+ function parseBlockchainAmount(amount, decimals) {
1972
+ const trimmed = amount.trim();
1973
+ if (trimmed === "") return { valid: false, reason: { type: "empty" } };
1974
+ if (trimmed.startsWith("-")) {
1975
+ return { valid: false, reason: { type: "negative" } };
1976
+ }
1977
+ if (/[eE]/.test(trimmed)) {
1978
+ return { valid: false, reason: { type: "invalid-format" } };
1979
+ }
1980
+ if (!/^\d+(\.\d+)?$/.test(trimmed)) {
1981
+ return { valid: false, reason: { type: "invalid-format" } };
1982
+ }
1983
+ const [, fraction = ""] = trimmed.split(".");
1984
+ if (fraction.length > decimals) {
1960
1985
  return {
1961
- id: OfferId(dto.id),
1962
- slug: OfferSlug(dto.slug),
1963
- type: dto.type,
1964
- name: dto.name,
1965
- asset: Asset.fromDto(dto.asset),
1966
- fundingAssets: dto.funding_assets.map(Asset.fromDto),
1967
- tokens: OfferToken.listFromDto(dto.tokens),
1968
- swapContracts: swapContracts.map(OfferSwapContract.fromDto),
1969
- about: notBlankStringOrNull(dto.about),
1970
- tagline: dto.tagline,
1971
- bannerUrl: dto.banner_url,
1972
- logoUrl: dto.logo_url,
1973
- category: dto.category,
1974
- startsAt: new Date(dto.starts_at),
1975
- endsAt: dto.ends_at ? new Date(dto.ends_at) : null,
1976
- faqs: dto.faqs.map(FaqItem.fromDto),
1977
- links: dto.links.map(Link.fromDto),
1978
- milestones: dto.milestones.map(Milestone.fromDto),
1979
- options: dto.options.map(OfferOption.fromDto),
1980
- terms: dto.terms.map(TermItem.fromDto)
1986
+ valid: false,
1987
+ reason: { type: "too-many-decimals", maxDecimals: decimals }
1981
1988
  };
1982
1989
  }
1983
- };
1984
- var OfferOption = {
1985
- fromDto: (dto) => ({
1986
- id: OfferOptionId(dto.id),
1987
- slug: OfferOptionSlug(dto.slug),
1988
- bidIncrement: dto.bid_increment,
1989
- floorPriceUsd: dto.floor_price_usd,
1990
- minimumPurchaseUsd: dto.minimum_purchase_usd,
1991
- priceUsd: dto.price_usd,
1992
- saleAgreementUrl: notBlankStringOrNull(dto.sale_agreement_url),
1993
- totalTokenSupply: dto.total_token_supply
1994
- })
1995
- };
1996
- var FaqItem = {
1997
- fromDto: (dto) => ({
1998
- question: notBlankStringOrNull(dto.question),
1999
- answer: notBlankStringOrNull(dto.answer)
2000
- })
2001
- };
2002
- var Link = {
2003
- fromDto: (dto) => ({
2004
- label: notBlankStringOrNull(dto.label),
2005
- url: notBlankStringOrNull(dto.url)
2006
- })
2007
- };
2008
- var TermItem = {
2009
- fromDto: (dto) => ({
2010
- key: notBlankStringOrNull(dto.key),
2011
- value: notBlankStringOrNull(dto.value)
2012
- })
2013
- };
2014
- var Milestone = {
2015
- fromDto: (dto) => ({
2016
- name: notBlankStringOrNull(dto.name),
2017
- schedule: notBlankStringOrNull(dto.schedule),
2018
- status: dto.status
2019
- })
2020
- };
2021
-
2022
- // src/shared/types/providers/coin-list/token-sale.ts
2023
- var ParticipationId = (value) => value;
2024
- var Blockchain = (value) => value;
2025
- var WalletAddress = (value) => value;
2026
- var ParticipationsPaginationParams = {
2027
- toQueryParams: (params) => {
2028
- const queryParams = PaginationParams.toQueryParams(params);
2029
- if (params.offerId) {
2030
- queryParams["filters[0][field]"] = "offer_id";
2031
- queryParams["filters[0][op]"] = "==";
2032
- queryParams["filters[0][value]"] = params.offerId;
1990
+ try {
1991
+ const raw = (0, import_viem3.parseUnits)(trimmed, decimals);
1992
+ if (raw > MAX_UINT_256) {
1993
+ return { valid: false, reason: { type: "overflow" } };
2033
1994
  }
2034
- return queryParams;
1995
+ return {
1996
+ valid: true,
1997
+ amount: BlockchainAmount({ raw, decimals })
1998
+ };
1999
+ } catch {
2000
+ return { valid: false, reason: { type: "invalid-format" } };
2035
2001
  }
2036
- };
2037
- var Participation = {
2038
- /** Maps API DTO shape into the SDK participation domain model. */
2002
+ }
2003
+
2004
+ // src/universal/types/trading.ts
2005
+ var Ticker = (value) => value;
2006
+
2007
+ // src/universal/types/providers/ondo/ondo.ts
2008
+ var OndoTradingStatus = {
2039
2009
  fromDto: (dto) => {
2040
- const walletAddress = notBlankStringOrNull(dto.wallet_address);
2010
+ if (!dto.tradable) return { type: "not-tradable", side: dto.side };
2041
2011
  return {
2042
- id: ParticipationId(dto.id),
2043
- offerId: OfferId(dto.offer_id),
2044
- offerOptionId: OfferOptionId(dto.offer_option_id),
2045
- status: dto.status,
2046
- amount: dto.amount,
2047
- displayAmount: dto.amount_string,
2048
- asset: Asset.fromDto(dto.asset),
2049
- chain: Blockchain(dto.chain),
2050
- insertedAt: dto.inserted_at ? new Date(dto.inserted_at) : null,
2051
- updatedAt: dto.updated_at ? new Date(dto.updated_at) : null,
2052
- walletAddress: walletAddress ? WalletAddress(walletAddress) : null
2053
- };
2054
- }
2055
- };
2056
- var CreateParticipationParams = {
2057
- /** Maps participation creation params into API DTO payload. */
2058
- toDto: (params) => ({
2059
- offer_id: params.offerId,
2060
- offer_option_id: params.offerOptionId,
2061
- chain: params.chain,
2062
- wallet_address: params.walletAddress,
2063
- amount: params.amount,
2064
- asset_id: params.assetId,
2065
- approval_transaction_hash: params.approvalTransactionHash
2066
- })
2067
- };
2068
-
2069
- // src/shared/api/frontline/providers/coin-list/token-sale.ts
2070
- async function fetchParticipations(api, offerId) {
2071
- return fetchAllPages(
2072
- (params) => fetchParticipationsPage(api, params),
2073
- { offerId }
2074
- );
2075
- }
2076
- async function fetchParticipationsPage(api, params) {
2077
- const pageDto = await api.send({
2078
- method: "GET",
2079
- url: "/v1/participations",
2080
- queryParams: ParticipationsPaginationParams.toQueryParams(params),
2081
- attributes: Attributes.protected()
2082
- });
2083
- return PaginatedResponse.fromDto(pageDto, Participation.fromDto);
2084
- }
2085
- async function fetchParticipation(api, id) {
2086
- const dto = await api.send({
2087
- method: "GET",
2088
- url: `/v1/participations/${id}`,
2089
- attributes: Attributes.protected()
2090
- });
2091
- return Participation.fromDto(dto);
2092
- }
2093
- async function createParticipation(api, params) {
2094
- const dto = await api.send({
2095
- method: "POST",
2096
- url: "/v1/participations",
2097
- body: CreateParticipationParams.toDto(params),
2098
- attributes: Attributes.protected()
2099
- });
2100
- return Participation.fromDto(dto);
2101
- }
2102
-
2103
- // src/shared/core/checkout/coin-list/token-sale-namespace.ts
2104
- var CoinListTokenSaleNamespaceImpl = class {
2105
- constructor(ctx) {
2106
- this.ctx = ctx;
2107
- this.log = internalLogger(ctx.logger, "TOKEN_SALE");
2108
- }
2109
- async list(offerId) {
2110
- return this.log.wrap("list", offerId, async () => {
2111
- await this.ctx.ensureUserAuthenticated();
2112
- return fetchParticipations(this.ctx.api, offerId);
2113
- });
2114
- }
2115
- async listPage(params) {
2116
- return this.log.wrap("listPage", params, async () => {
2117
- await this.ctx.ensureUserAuthenticated();
2118
- return fetchParticipationsPage(this.ctx.api, params);
2119
- });
2120
- }
2121
- async get(id) {
2122
- return this.log.wrap("get", id, async () => {
2123
- await this.ctx.ensureUserAuthenticated();
2124
- return fetchParticipation(this.ctx.api, id);
2125
- });
2126
- }
2127
- async createParticipation(params) {
2128
- return this.log.wrap("createParticipation", params, async () => {
2129
- await this.ctx.ensureUserAuthenticated();
2130
- return createParticipation(this.ctx.api, params);
2131
- });
2132
- }
2133
- };
2134
-
2135
- // src/shared/core/checkout/ondo/constants.ts
2136
- var ONDO_POLL_INTERVAL_MS = 15e3;
2137
- var ONDO_QUOTE_EXPIRY_THRESHOLD_MS = 5e3;
2138
- var DEFAULT_ONDO_AMOUNT_TO_COMPUTE_PRICE = DecimalString("1000");
2139
- var ONDO_SETTLEMENT_ASSET = USDC_SYMBOL;
2140
- var DEFAULT_ONDO_SELL_TOKENS_TO_COMPUTE_PRICE = 1;
2141
- var ONDO_SUPPORTED_INPUT_ASSETS = [
2142
- USDC_SYMBOL
2143
- ];
2144
-
2145
- // src/shared/core/checkout/ondo/math.ts
2146
- function computeOndoBuyPrice(transaction) {
2147
- const { notionalValue, receiveOutputAmount } = transaction;
2148
- return pricePerShare({
2149
- usd: notionalValue,
2150
- shares: receiveOutputAmount
2151
- });
2152
- }
2153
- function computeOndoSellPrice(transaction) {
2154
- const { expected, spendInputAmount } = transaction;
2155
- return pricePerShare({
2156
- usd: grossProceeds(expected),
2157
- shares: spendInputAmount
2158
- });
2159
- }
2160
- function grossProceeds(expected) {
2161
- const raw = expected.quantity.raw + expected.fee.raw;
2162
- if (raw > MAX_UINT_256) {
2163
- throw new MathError(`Ondo sell proceeds: out of uint256 bounds (${raw})`);
2164
- }
2165
- return BlockchainAmount.add(expected.quantity, expected.fee);
2166
- }
2167
- function pricePerShare({
2168
- usd,
2169
- shares
2170
- }) {
2171
- const price = BlockchainAmount.div(usd, shares);
2172
- return BlockchainAmount({
2173
- raw: assertPriceFits(price.raw),
2174
- decimals: price.decimals
2175
- });
2176
- }
2177
- function assertPriceFits(raw) {
2178
- try {
2179
- return assertUint256(raw);
2180
- } catch {
2181
- throw new MathError(`Ondo price: out of uint256 bounds (${raw})`);
2182
- }
2183
- }
2184
-
2185
- // src/shared/types/trading.ts
2186
- var Ticker = (value) => value;
2187
-
2188
- // src/shared/types/providers/ondo/ondo.ts
2189
- var OndoTradingStatus = {
2190
- fromDto: (dto) => {
2191
- if (!dto.tradable) return { type: "not-tradable", side: dto.side };
2192
- return {
2193
- type: "tradable",
2194
- side: dto.side,
2195
- grossMaxTokens: decimalOrNull(dto.gross_max_tokens),
2196
- grossMaxNotionalValue: decimalOrNull(dto.gross_max_notional_value),
2197
- grossMaxActiveNotionalValue: decimalOrNull(
2198
- dto.gross_max_active_notional_value
2199
- )
2012
+ type: "tradable",
2013
+ side: dto.side,
2014
+ grossMaxTokens: decimalOrNull(dto.gross_max_tokens),
2015
+ grossMaxNotionalValue: decimalOrNull(dto.gross_max_notional_value),
2016
+ grossMaxActiveNotionalValue: decimalOrNull(
2017
+ dto.gross_max_active_notional_value
2018
+ )
2200
2019
  };
2201
2020
  }
2202
2021
  };
@@ -2351,7 +2170,7 @@ function parseExpiresAt(value) {
2351
2170
  return date;
2352
2171
  }
2353
2172
 
2354
- // src/shared/api/frontline/providers/ondo/ondo.ts
2173
+ // src/universal/api/frontline/providers/ondo/ondo.ts
2355
2174
  async function getOndoTradingStatus(api, params) {
2356
2175
  const dto = await api.send({
2357
2176
  method: "GET",
@@ -2446,7 +2265,7 @@ function sizeParam(params) {
2446
2265
  return { notional_value: notionalValue };
2447
2266
  }
2448
2267
 
2449
- // src/shared/core/checkout/ondo/ondo-namespace.ts
2268
+ // src/universal/core/checkout/ondo/ondo-namespace.ts
2450
2269
  var OndoNamespaceImpl = class {
2451
2270
  constructor(ctx) {
2452
2271
  this.ctx = ctx;
@@ -2478,7 +2297,7 @@ var OndoNamespaceImpl = class {
2478
2297
  }
2479
2298
  };
2480
2299
 
2481
- // src/shared/core/checkout/superstate/blockchain/abi.ts
2300
+ // src/universal/core/checkout/superstate/blockchain/abi.ts
2482
2301
  var SUPERSTATE_SWAP_ABI = [
2483
2302
  {
2484
2303
  type: "function",
@@ -2700,7 +2519,13 @@ var SUPERSTATE_SWAP_ABI = [
2700
2519
  }
2701
2520
  ];
2702
2521
 
2703
- // src/shared/core/checkout/superstate/blockchain/math.ts
2522
+ // src/universal/core/shared/blockchain/bps.ts
2523
+ var BPS_DENOM = Bps(10000n);
2524
+ function applyBps(amount, bps) {
2525
+ return assertUint256(amount * bps / BPS_DENOM);
2526
+ }
2527
+
2528
+ // src/universal/core/checkout/superstate/blockchain/math.ts
2704
2529
  function computePrice({
2705
2530
  inputTokenAmount,
2706
2531
  outputTokenAmount
@@ -2718,7 +2543,7 @@ function computeSlip(amount, slippage) {
2718
2543
  return BlockchainAmount({ raw: slipRaw, decimals: amount.decimals });
2719
2544
  }
2720
2545
 
2721
- // src/shared/core/checkout/superstate/blockchain/quote.ts
2546
+ // src/universal/core/checkout/superstate/blockchain/quote.ts
2722
2547
  var SwapQuote = {
2723
2548
  /**
2724
2549
  * Assembles a {@link SwapQuote} from a raw contract {@link SwapPreview}. The
@@ -2738,12 +2563,12 @@ var SwapQuote = {
2738
2563
  })
2739
2564
  };
2740
2565
 
2741
- // src/shared/core/checkout/superstate/blockchain/status.ts
2566
+ // src/universal/core/checkout/superstate/blockchain/status.ts
2742
2567
  function isStopped(status) {
2743
2568
  return (status.stopped & status.swapLevel) !== 0n;
2744
2569
  }
2745
2570
 
2746
- // src/shared/core/checkout/superstate/blockchain/swapped-event.ts
2571
+ // src/universal/core/checkout/superstate/blockchain/swapped-event.ts
2747
2572
  var import_viem4 = require("viem");
2748
2573
  function decodeSwappedOutputAmount(receipt, outputDecimals) {
2749
2574
  try {
@@ -2761,7 +2586,7 @@ function decodeSwappedOutputAmount(receipt, outputDecimals) {
2761
2586
  }
2762
2587
  }
2763
2588
 
2764
- // src/shared/core/checkout/superstate/constants.ts
2589
+ // src/universal/core/checkout/superstate/constants.ts
2765
2590
  var SUPERSTATE_ISSUER_NAME = "Superstate";
2766
2591
  var SUPERSTATE_SUPPORTED_INPUT_ASSETS = [USDC_SYMBOL];
2767
2592
  var SWAP_POLL_INTERVAL_MS = 15e3;
@@ -2778,68 +2603,225 @@ function superstateSwapContractAddress(chain) {
2778
2603
  return SUPERSTATE_SWAP_CONTRACT_ADDRESSES[chain] ?? null;
2779
2604
  }
2780
2605
 
2781
- // src/shared/core/checkout/superstate/formatters.ts
2606
+ // src/universal/core/checkout/superstate/formatters.ts
2782
2607
  function formattedPricePerShare(quote, locale) {
2783
2608
  if (!quote) return NA_AMOUNT_ASSET_UI;
2784
2609
  return formattedUsdPrice(computePrice(quote), locale);
2785
2610
  }
2786
2611
 
2787
- // src/shared/core/checkout/superstate/swap-namespace.ts
2788
- var SuperstateSwapNamespaceImpl = class {
2789
- constructor(ctx) {
2790
- this.ctx = ctx;
2791
- this.log = internalLogger(ctx.logger, "SUPERSTATE");
2792
- }
2793
- async getAuthorization(params) {
2794
- return this.log.wrap("getAuthorization", params, async () => {
2795
- await this.ctx.ensureUserAuthenticated();
2796
- return getSwapAuthorization(this.ctx.api, params);
2797
- });
2798
- }
2799
- async getPreview(params) {
2800
- return this.log.wrap("getPreview", params, async () => {
2801
- await this.ctx.ensureUserAuthenticated();
2802
- return getSwapPreview(this.ctx.api, params);
2803
- });
2804
- }
2805
- async getStatus(params) {
2806
- return this.log.wrap("getStatus", params, async () => {
2807
- await this.ctx.ensureUserAuthenticated();
2808
- return getSwapStatus(this.ctx.api, params);
2809
- });
2810
- }
2811
- async getOutputToken(params) {
2812
- return this.log.wrap("getOutputToken", params, async () => {
2813
- await this.ctx.ensureUserAuthenticated();
2814
- return getSwapOutputToken(this.ctx.api, params);
2815
- });
2816
- }
2817
- async allowWallet(params) {
2818
- return this.log.wrap("allowWallet", params, async () => {
2819
- await this.ctx.ensureUserAuthenticated();
2820
- return allowWallet(this.ctx.api, params);
2821
- });
2612
+ // src/universal/types/providers/superstate/swap.ts
2613
+ var SwapAuthorization = {
2614
+ fromDto: (dto) => ({
2615
+ authorized: dto.authorized
2616
+ })
2617
+ };
2618
+ var SwapPreview = {
2619
+ fromDto: (dto) => ({
2620
+ inputAmount: parseUint256(
2621
+ BigInt(dto.pay_input_amount),
2622
+ "SwapPreview.pay_input_amount"
2623
+ ),
2624
+ fee: parseUint256(BigInt(dto.fee), "SwapPreview.fee"),
2625
+ outputAmount: parseUint256(
2626
+ BigInt(dto.receive_output_amount),
2627
+ "SwapPreview.receive_output_amount"
2628
+ )
2629
+ })
2630
+ };
2631
+ var SwapStatus = {
2632
+ fromDto: (dto) => ({
2633
+ stopped: parseUint256(BigInt(dto.stopped), "SwapStatus.stopped"),
2634
+ swapLevel: parseUint256(BigInt(dto.swap_level), "SwapStatus.swap_level")
2635
+ })
2636
+ };
2637
+ var TokenAllowance = {
2638
+ fromDto: (dto) => ({
2639
+ allowance: parseUint256(BigInt(dto.allowance), "TokenAllowance.allowance")
2640
+ })
2641
+ };
2642
+ var TokenBalance = {
2643
+ fromDto: (dto) => ({
2644
+ balance: parseUint256(BigInt(dto.balance), "TokenBalance.balance")
2645
+ })
2646
+ };
2647
+ var AllowWalletResponse = {
2648
+ fromDto: (dto) => {
2649
+ switch (dto.action) {
2650
+ case "broadcast_transaction":
2651
+ return {
2652
+ action: "broadcast_transaction",
2653
+ to: EvmContractAddress(dto.to),
2654
+ data: HexEncodedTransactionData(dto.data)
2655
+ };
2656
+ case "none":
2657
+ return {
2658
+ action: "none",
2659
+ alreadyAllowed: dto.already_allowed
2660
+ };
2661
+ default: {
2662
+ const _exhaustive = dto;
2663
+ return _exhaustive;
2664
+ }
2665
+ }
2822
2666
  }
2823
2667
  };
2824
2668
 
2825
- // src/shared/api/frontline/offers.ts
2826
- async function fetchOffers(api, clientCreds) {
2827
- return fetchAllPages((params) => fetchOffersPage(api, params, clientCreds));
2828
- }
2829
- async function fetchOffersPage(api, params, clientCreds) {
2830
- const queryParams = PaginationParams.toQueryParams(params);
2831
- const pageDto = await api.send({
2669
+ // src/universal/api/frontline/providers/superstate/swap.ts
2670
+ async function getSwapAuthorization(api, params) {
2671
+ const dto = await api.send({
2832
2672
  method: "GET",
2833
- url: "/v1/offers",
2834
- queryParams,
2835
- attributes: Attributes.concat(
2836
- Attributes.protected(),
2837
- Attributes.clientCredentials(clientCreds)
2838
- )
2673
+ url: "/v1/wallet/authorized",
2674
+ queryParams: {
2675
+ chain: params.chain,
2676
+ contract_address: params.contractAddress,
2677
+ wallet_address: params.walletAddress
2678
+ },
2679
+ attributes: Attributes.protected()
2839
2680
  });
2840
- return PaginatedResponse.fromDto(pageDto, Offer.fromDto);
2681
+ return SwapAuthorization.fromDto(dto);
2841
2682
  }
2842
- async function fetchOfferDetails(api, id, clientCreds) {
2683
+ async function getSwapOutputToken(api, params) {
2684
+ const dto = await api.send({
2685
+ method: "GET",
2686
+ url: "/v1/swap/output-token",
2687
+ queryParams: {
2688
+ chain: params.chain,
2689
+ contract_address: params.contractAddress
2690
+ },
2691
+ attributes: Attributes.protected()
2692
+ });
2693
+ return toErc20Asset(dto);
2694
+ }
2695
+ async function getSwapPreview(api, params) {
2696
+ const dto = await api.send({
2697
+ method: "GET",
2698
+ url: "/v1/swap/preview",
2699
+ queryParams: {
2700
+ chain: params.chain,
2701
+ contract_address: params.contractAddress,
2702
+ input_token: params.inputToken,
2703
+ amount: params.amount.toString()
2704
+ },
2705
+ attributes: Attributes.protected()
2706
+ });
2707
+ return SwapPreview.fromDto(dto);
2708
+ }
2709
+ async function getSwapStatus(api, params) {
2710
+ const dto = await api.send({
2711
+ method: "GET",
2712
+ url: "/v1/swap/status",
2713
+ queryParams: {
2714
+ chain: params.chain,
2715
+ contract_address: params.contractAddress
2716
+ },
2717
+ attributes: Attributes.protected()
2718
+ });
2719
+ return SwapStatus.fromDto(dto);
2720
+ }
2721
+ async function getTokenAllowance(api, params) {
2722
+ const dto = await api.send({
2723
+ method: "GET",
2724
+ url: "/v1/token/allowance",
2725
+ queryParams: {
2726
+ chain: params.chain,
2727
+ token_address: params.tokenAddress,
2728
+ owner: params.owner,
2729
+ spender: params.spender
2730
+ },
2731
+ attributes: Attributes.protected()
2732
+ });
2733
+ return TokenAllowance.fromDto(dto);
2734
+ }
2735
+ async function getTokenBalance(api, params) {
2736
+ const dto = await api.send({
2737
+ method: "GET",
2738
+ url: "/v1/token/balance",
2739
+ queryParams: {
2740
+ chain: params.chain,
2741
+ token_address: params.tokenAddress,
2742
+ owner: params.owner
2743
+ },
2744
+ attributes: Attributes.protected()
2745
+ });
2746
+ return TokenBalance.fromDto(dto);
2747
+ }
2748
+ async function allowWallet(api, params) {
2749
+ const dto = await api.send({
2750
+ method: "POST",
2751
+ url: `/v1/offers/${encodeURIComponent(params.offerId)}/allow-wallet`,
2752
+ body: {
2753
+ wallet_address: params.walletAddress,
2754
+ chain: params.chain,
2755
+ signature: params.signature
2756
+ },
2757
+ attributes: Attributes.protected()
2758
+ });
2759
+ return AllowWalletResponse.fromDto(dto);
2760
+ }
2761
+ function toErc20Asset(dto) {
2762
+ return {
2763
+ name: dto.name,
2764
+ symbol: AssetSymbol(dto.symbol),
2765
+ decimals: AssetDecimals(dto.decimals)
2766
+ };
2767
+ }
2768
+
2769
+ // src/universal/core/checkout/superstate/swap-namespace.ts
2770
+ var SuperstateSwapNamespaceImpl = class {
2771
+ constructor(ctx) {
2772
+ this.ctx = ctx;
2773
+ this.log = internalLogger(ctx.logger, "SUPERSTATE");
2774
+ }
2775
+ async getAuthorization(params) {
2776
+ return this.log.wrap("getAuthorization", params, async () => {
2777
+ await this.ctx.ensureUserAuthenticated();
2778
+ return getSwapAuthorization(this.ctx.api, params);
2779
+ });
2780
+ }
2781
+ async getPreview(params) {
2782
+ return this.log.wrap("getPreview", params, async () => {
2783
+ await this.ctx.ensureUserAuthenticated();
2784
+ return getSwapPreview(this.ctx.api, params);
2785
+ });
2786
+ }
2787
+ async getStatus(params) {
2788
+ return this.log.wrap("getStatus", params, async () => {
2789
+ await this.ctx.ensureUserAuthenticated();
2790
+ return getSwapStatus(this.ctx.api, params);
2791
+ });
2792
+ }
2793
+ async getOutputToken(params) {
2794
+ return this.log.wrap("getOutputToken", params, async () => {
2795
+ await this.ctx.ensureUserAuthenticated();
2796
+ return getSwapOutputToken(this.ctx.api, params);
2797
+ });
2798
+ }
2799
+ async allowWallet(params) {
2800
+ return this.log.wrap("allowWallet", params, async () => {
2801
+ await this.ctx.ensureUserAuthenticated();
2802
+ return allowWallet(this.ctx.api, params);
2803
+ });
2804
+ }
2805
+ };
2806
+
2807
+ // src/universal/api/frontline/offers.ts
2808
+ async function fetchOffers(api, clientCreds) {
2809
+ return fetchAllPages((params) => fetchOffersPage(api, params, clientCreds));
2810
+ }
2811
+ async function fetchOffersPage(api, params, clientCreds) {
2812
+ const queryParams = PaginationParams.toQueryParams(params);
2813
+ const pageDto = await api.send({
2814
+ method: "GET",
2815
+ url: "/v1/offers",
2816
+ queryParams,
2817
+ attributes: Attributes.concat(
2818
+ Attributes.protected(),
2819
+ Attributes.clientCredentials(clientCreds)
2820
+ )
2821
+ });
2822
+ return PaginatedResponse.fromDto(pageDto, Offer.fromDto);
2823
+ }
2824
+ async function fetchOfferDetails(api, id, clientCreds) {
2843
2825
  const dto = await api.send({
2844
2826
  method: "GET",
2845
2827
  url: `/v1/offers/${id}`,
@@ -2851,7 +2833,7 @@ async function fetchOfferDetails(api, id, clientCreds) {
2851
2833
  return OfferDetail.fromDto(dto);
2852
2834
  }
2853
2835
 
2854
- // src/shared/core/offers/offers-namespace.ts
2836
+ // src/universal/core/offers/offers-namespace.ts
2855
2837
  var OffersNamespaceImpl = class {
2856
2838
  constructor(ctx) {
2857
2839
  this.ctx = ctx;
@@ -2877,12 +2859,12 @@ var OffersNamespaceImpl = class {
2877
2859
  }
2878
2860
  };
2879
2861
 
2880
- // src/shared/core/offers/swap-contracts.ts
2862
+ // src/universal/core/offers/swap-contracts.ts
2881
2863
  function swapSpender(swapContracts, chain) {
2882
2864
  return swapContracts.find((contract) => contract.chain === chain)?.address ?? null;
2883
2865
  }
2884
2866
 
2885
- // src/shared/types/document-submission.ts
2867
+ // src/universal/types/document-submission.ts
2886
2868
  var DocumentSubmission = {
2887
2869
  fromDto: (dto) => ({
2888
2870
  status: dto.status,
@@ -2890,7 +2872,7 @@ var DocumentSubmission = {
2890
2872
  })
2891
2873
  };
2892
2874
 
2893
- // src/shared/api/frontline/documents.ts
2875
+ // src/universal/api/frontline/documents.ts
2894
2876
  async function submitDocument(api, documentType, fields) {
2895
2877
  const dto = await api.send({
2896
2878
  method: "POST",
@@ -2901,14 +2883,14 @@ async function submitDocument(api, documentType, fields) {
2901
2883
  return DocumentSubmission.fromDto(dto);
2902
2884
  }
2903
2885
 
2904
- // src/shared/types/kyc.ts
2886
+ // src/universal/types/kyc.ts
2905
2887
  var KycToken = {
2906
2888
  fromDto: (dto) => ({
2907
2889
  token: dto.token
2908
2890
  })
2909
2891
  };
2910
2892
 
2911
- // src/shared/api/frontline/kyc.ts
2893
+ // src/universal/api/frontline/kyc.ts
2912
2894
  async function createKycToken(api, levelName, reset) {
2913
2895
  const dto = await api.send({
2914
2896
  method: "POST",
@@ -2922,7 +2904,7 @@ async function createKycToken(api, levelName, reset) {
2922
2904
  return KycToken.fromDto(dto);
2923
2905
  }
2924
2906
 
2925
- // src/shared/types/pii.ts
2907
+ // src/universal/types/pii.ts
2926
2908
  var Iso2CountryCode = (value) => value;
2927
2909
  var PiiJurisdiction = {
2928
2910
  fromDto: (dto) => ({
@@ -2950,7 +2932,7 @@ var Pii = {
2950
2932
  })
2951
2933
  };
2952
2934
 
2953
- // src/shared/api/frontline/pii.ts
2935
+ // src/universal/api/frontline/pii.ts
2954
2936
  async function fetchPii(api) {
2955
2937
  const dto = await api.send({
2956
2938
  method: "GET",
@@ -2960,7 +2942,7 @@ async function fetchPii(api) {
2960
2942
  return Pii.fromDto(dto);
2961
2943
  }
2962
2944
 
2963
- // src/shared/types/requirement.ts
2945
+ // src/universal/types/requirement.ts
2964
2946
  var RequirementId = (value) => value;
2965
2947
  var Requirement = {
2966
2948
  fromDto: (dto) => ({
@@ -2981,7 +2963,7 @@ var RequirementStatusInfo = {
2981
2963
  )
2982
2964
  };
2983
2965
 
2984
- // src/shared/api/frontline/requirements.ts
2966
+ // src/universal/api/frontline/requirements.ts
2985
2967
  async function fetchOfferRequirements(api, offerId, clientCreds) {
2986
2968
  const response = await api.send({
2987
2969
  method: "GET",
@@ -3007,7 +2989,7 @@ async function fetchRequirementStatuses(api, offerId) {
3007
2989
  return RequirementStatusInfo.fromStatusesDto(response);
3008
2990
  }
3009
2991
 
3010
- // src/shared/core/requirements/requirements-namespace.ts
2992
+ // src/universal/core/requirements/requirements-namespace.ts
3011
2993
  var RequirementsNamespaceImpl = class {
3012
2994
  constructor(ctx) {
3013
2995
  this.ctx = ctx;
@@ -3057,10 +3039,30 @@ var RequirementsNamespaceImpl = class {
3057
3039
  }
3058
3040
  };
3059
3041
 
3060
- // src/shared/api/nabu/tokens.ts
3042
+ // src/universal/core/shared/blockchain/erc20/erc20-namespace.ts
3043
+ var Erc20NamespaceImpl = class {
3044
+ constructor(ctx) {
3045
+ this.ctx = ctx;
3046
+ this.log = internalLogger(ctx.logger, "ERC20");
3047
+ }
3048
+ async getAllowance(params) {
3049
+ return this.log.wrap("getAllowance", params, async () => {
3050
+ await this.ctx.ensureUserAuthenticated();
3051
+ return getTokenAllowance(this.ctx.api, params);
3052
+ });
3053
+ }
3054
+ async getBalance(params) {
3055
+ return this.log.wrap("getBalance", params, async () => {
3056
+ await this.ctx.ensureUserAuthenticated();
3057
+ return getTokenBalance(this.ctx.api, params);
3058
+ });
3059
+ }
3060
+ };
3061
+
3062
+ // src/universal/api/nabu/tokens.ts
3061
3063
  var import_viem5 = require("viem");
3062
3064
 
3063
- // src/shared/types/token-metadata.ts
3065
+ // src/universal/types/token-metadata.ts
3064
3066
  var TokenLogoUrl = (value) => value;
3065
3067
  var TokenLogo = {
3066
3068
  /** `baseUrl` is the registry origin; registry URLs are root-relative. */
@@ -3143,7 +3145,7 @@ var resolveLogoUrl = (url, baseUrl) => TokenLogoUrl(
3143
3145
  url.startsWith("http") ? url : `${baseUrl.replace(/\/$/, "")}${url}`
3144
3146
  );
3145
3147
 
3146
- // src/shared/api/nabu/tokens.ts
3148
+ // src/universal/api/nabu/tokens.ts
3147
3149
  function createNabuApiClient(baseUrl, logger = null) {
3148
3150
  return new HttpClient({ baseUrl }, {}, logger);
3149
3151
  }
@@ -3234,10 +3236,10 @@ function checksummed(address) {
3234
3236
  }
3235
3237
  }
3236
3238
 
3237
- // src/shared/core/tokens/tokens-namespace.ts
3239
+ // src/universal/core/tokens/tokens-namespace.ts
3238
3240
  var TokensNamespaceImpl = class {
3239
3241
  /**
3240
- * Takes the registry origin rather than a `SharedNamespaceContext`: the
3242
+ * Takes the registry origin rather than a `UniversalNamespaceContext`: the
3241
3243
  * registry is unauthenticated and on its own host, so the frontline sender
3242
3244
  * and the auth check would both be dead weight here.
3243
3245
  */
@@ -3261,7 +3263,7 @@ var TokensNamespaceImpl = class {
3261
3263
  }
3262
3264
  };
3263
3265
 
3264
- // src/shared/types/offer-option-address.ts
3266
+ // src/universal/types/offer-option-address.ts
3265
3267
  var OfferOptionAddressId = (value) => value;
3266
3268
  var OfferOptionAddress = {
3267
3269
  /** Maps the API DTO into the SDK offer-option-address domain model. */
@@ -3283,7 +3285,7 @@ var ConnectExternalWalletParams = {
3283
3285
  })
3284
3286
  };
3285
3287
 
3286
- // src/shared/types/wallet-ownership-challenge.ts
3288
+ // src/universal/types/wallet-ownership-challenge.ts
3287
3289
  var WalletOwnershipChallenge = {
3288
3290
  /** Maps the API DTO into the SDK wallet-ownership-challenge domain model. */
3289
3291
  fromDto: (dto) => ({
@@ -3322,7 +3324,7 @@ var CreateWalletOwnershipChallengeParams = {
3322
3324
  }
3323
3325
  };
3324
3326
 
3325
- // src/shared/api/frontline/wallet-connect.ts
3327
+ // src/universal/api/frontline/wallet-connect.ts
3326
3328
  async function createWalletOwnershipChallenge(api, params) {
3327
3329
  const dto = await api.send({
3328
3330
  method: "POST",
@@ -3359,7 +3361,7 @@ async function removeOptionAddress(api, offerId, addressId) {
3359
3361
  return OfferOptionAddress.fromDto(dto);
3360
3362
  }
3361
3363
 
3362
- // src/shared/core/wallets/wallets-namespace.ts
3364
+ // src/universal/core/wallets/wallets-namespace.ts
3363
3365
  var WalletsNamespaceImpl = class {
3364
3366
  constructor(ctx) {
3365
3367
  this.ctx = ctx;
@@ -3402,7 +3404,7 @@ var WalletsNamespaceImpl = class {
3402
3404
  }
3403
3405
  };
3404
3406
 
3405
- // src/shared/types/blockchain/wallet-error.ts
3407
+ // src/universal/types/blockchain/wallet-error.ts
3406
3408
  var RedactedWalletError = {
3407
3409
  fromWalletError: (error) => error.type === "unknown" ? { type: "unknown" } : error
3408
3410
  };
@@ -3486,7 +3488,7 @@ async function executeTokenSale(params) {
3486
3488
  return { type: "success", participation, approvalTxHash };
3487
3489
  }
3488
3490
 
3489
- // src/client/core/observability/flow-logging.ts
3491
+ // src/client/core/shared/observability/flow-logging.ts
3490
3492
  async function withFlowLogging(log, flow, fields, onProgress, run) {
3491
3493
  const flowLog = log.child({ flow });
3492
3494
  flowLog.info(() => ({ msg: "flow started", fields }));
@@ -3936,7 +3938,7 @@ var ClientSuperstateSwapNamespaceImpl = class extends SuperstateSwapNamespaceImp
3936
3938
  }
3937
3939
  };
3938
3940
 
3939
- // src/client/core/utils/open-in-new-tab.ts
3941
+ // src/client/core/shared/utils/open-in-new-tab.ts
3940
3942
  function openInNewTab(url) {
3941
3943
  window.open(url, "_blank", "noopener,noreferrer");
3942
3944
  }
@@ -3994,7 +3996,7 @@ var ClientSupportNamespaceImpl = class {
3994
3996
  }
3995
3997
  };
3996
3998
 
3997
- // src/shared/api/nabu/config.ts
3999
+ // src/universal/api/nabu/config.ts
3998
4000
  var NABU_BASE_URL = "https://asset.coinlist.co";
3999
4001
 
4000
4002
  // src/client/core/coinlist-client.ts
@@ -12071,1205 +12073,823 @@ function CheckoutContainer({
12071
12073
  enabled: enabled && isOndo && side === "sell",
12072
12074
  onOrderConfirmed: config["ondo::swap"].onOrderConfirmed
12073
12075
  });
12074
- const superstate = useSuperstateSwapCheckoutViewModel({
12075
- offer,
12076
- chain,
12077
- wallets,
12078
- enabled: enabled && offer.type === "superstate::swap",
12079
- onOrderConfirmed: config["superstate::swap"].onOrderConfirmed
12080
- });
12081
- return renderOffer(offer.type, {
12082
- ondo: () => renderOndoSide(side, {
12083
- buy: () => /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
12084
- OndoBuyCheckoutView,
12085
- {
12086
- state: ondoBuy.state,
12087
- onEvent: ondoBuy.onEvent,
12088
- className
12089
- }
12090
- ),
12091
- sell: () => /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
12092
- OndoSellCheckoutView,
12093
- {
12094
- state: ondoSell.state,
12095
- onEvent: ondoSell.onEvent,
12096
- className
12097
- }
12098
- )
12099
- }),
12100
- superstate: () => /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
12101
- SuperstateSwapCheckoutView,
12102
- {
12103
- state: superstate.state,
12104
- onEvent: superstate.onEvent,
12105
- className
12106
- }
12107
- ),
12108
- tokenSale: () => config["coinlist::token_sale"].render(offer)
12109
- });
12110
- }
12111
- function renderOffer(type, branches) {
12112
- switch (type) {
12113
- case "ondo::swap":
12114
- return branches.ondo();
12115
- case "superstate::swap":
12116
- return branches.superstate();
12117
- case "coinlist::token_sale":
12118
- return branches.tokenSale();
12119
- default: {
12120
- const exhaustive = type;
12121
- return exhaustive;
12122
- }
12123
- }
12124
- }
12125
- function renderOndoSide(side, branches) {
12126
- switch (side) {
12127
- case "buy":
12128
- return branches.buy();
12129
- case "sell":
12130
- return branches.sell();
12131
- default: {
12132
- const exhaustive = side;
12133
- return exhaustive;
12134
- }
12135
- }
12136
- }
12137
-
12138
- // src/client/components/checkout/ondo/buy/OndoBuyCheckoutContainer.tsx
12139
- var import_jsx_runtime48 = require("react/jsx-runtime");
12140
- function OndoBuyCheckoutContainer({
12141
- offer,
12142
- ondoSymbol,
12143
- chain,
12144
- wallets,
12145
- enabled,
12146
- onOrderConfirmed,
12147
- className
12148
- }) {
12149
- const { state, onEvent } = useOndoBuyCheckoutViewModel({
12150
- offer,
12151
- ondoSymbol,
12152
- chain,
12153
- wallets,
12154
- enabled,
12155
- onOrderConfirmed
12156
- });
12157
- return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
12158
- OndoBuyCheckoutView,
12159
- {
12160
- state,
12161
- onEvent,
12162
- className
12163
- }
12164
- );
12165
- }
12166
-
12167
- // src/client/components/checkout/ondo/sell/OndoSellCheckoutContainer.tsx
12168
- var import_jsx_runtime49 = require("react/jsx-runtime");
12169
- function OndoSellCheckoutContainer({
12170
- offer,
12171
- ondoSymbol,
12172
- chain,
12173
- wallets,
12174
- enabled,
12175
- onOrderConfirmed,
12176
- className
12177
- }) {
12178
- const { state, onEvent } = useOndoSellCheckoutViewModel({
12179
- offer,
12180
- ondoSymbol,
12181
- chain,
12182
- wallets,
12183
- enabled,
12184
- onOrderConfirmed
12185
- });
12186
- return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
12187
- OndoSellCheckoutView,
12188
- {
12189
- state,
12190
- onEvent,
12191
- className
12192
- }
12193
- );
12194
- }
12195
-
12196
- // src/client/components/checkout/superstate/swap/SuperstateSwapCheckoutContainer.tsx
12197
- var import_jsx_runtime50 = require("react/jsx-runtime");
12198
- function SuperstateSwapCheckoutContainer({
12199
- offer,
12200
- chain,
12201
- wallets,
12202
- enabled,
12203
- onOrderConfirmed,
12204
- className
12205
- }) {
12206
- const { state, onEvent } = useSuperstateSwapCheckoutViewModel({
12207
- offer,
12208
- chain,
12209
- wallets,
12210
- enabled,
12211
- onOrderConfirmed
12212
- });
12213
- return /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
12214
- SuperstateSwapCheckoutView,
12215
- {
12216
- state,
12217
- onEvent,
12218
- className
12219
- }
12220
- );
12221
- }
12222
-
12223
- // src/client/components/offers/shared/offer-card-keyboard.ts
12224
- function onOfferCardKeyDown(event, onClick) {
12225
- if (event.key !== "Enter" && event.key !== " ") return;
12226
- event.preventDefault();
12227
- onClick();
12228
- }
12229
-
12230
- // src/client/components/offers/shared/OfferAssetCard.tsx
12231
- var import_jsx_runtime51 = require("react/jsx-runtime");
12232
- function OfferAssetCard({
12233
- offer,
12234
- onClick,
12235
- className,
12236
- containerClassName
12237
- }) {
12238
- const interactive = onClick !== void 0;
12239
- const card = /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
12240
- "article",
12241
- {
12242
- className: cn(
12243
- "clcosdk:relative clcosdk:flex clcosdk:w-full clcosdk:items-center clcosdk:rounded-[20px] clcosdk:border clcosdk:border-border clcosdk:bg-background clcosdk:p-3 clcosdk:shadow-[0px_1px_1px_0px_rgba(10,10,10,0.04),0px_8px_12px_0px_rgba(10,10,10,0.08)]",
12244
- "clcosdk:md:rounded-card clcosdk:md:p-4",
12245
- interactive && "clcosdk:cursor-pointer clcosdk:transition-transform clcosdk:duration-300 clcosdk:ease-out clcosdk:hover:scale-[1.02] clcosdk:focus-visible:ring-2 clcosdk:focus-visible:ring-gray-400 clcosdk:focus-visible:ring-offset-2 clcosdk:focus-visible:outline-none clcosdk:max-md:hover:scale-100",
12246
- className
12247
- ),
12248
- "aria-label": interactive ? cardActionLabel(offer) : void 0,
12249
- role: interactive ? "button" : void 0,
12250
- tabIndex: interactive ? 0 : void 0,
12251
- onClick,
12252
- onKeyDown: interactive ? (event) => onOfferCardKeyDown(event, onClick) : void 0,
12253
- children: /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: "clcosdk:flex clcosdk:min-w-0 clcosdk:flex-1 clcosdk:items-center clcosdk:gap-2.5 clcosdk:pr-3 clcosdk:md:gap-3 clcosdk:md:pr-4", children: [
12254
- offer.logoUrl ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("div", { className: "clcosdk:h-10 clcosdk:w-10 clcosdk:shrink-0 clcosdk:overflow-hidden clcosdk:rounded-full clcosdk:md:h-12 clcosdk:md:w-12", children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
12255
- "img",
12256
- {
12257
- src: offer.logoUrl,
12258
- alt: "",
12259
- width: 48,
12260
- height: 48,
12261
- className: "clcosdk:size-full clcosdk:object-cover",
12262
- style: { maxWidth: "none", width: "100%", height: "100%" }
12263
- }
12264
- ) }) : null,
12265
- /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: "clcosdk:flex clcosdk:min-w-0 clcosdk:flex-1 clcosdk:flex-col clcosdk:items-start clcosdk:justify-center", children: [
12266
- offer.name ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
12267
- "h2",
12268
- {
12269
- className: cn(
12270
- "clcosdk:w-full clcosdk:truncate clcosdk:text-[16px] clcosdk:leading-[140%] clcosdk:font-medium clcosdk:text-text-primary clcosdk:md:text-[18px]"
12271
- ),
12272
- children: offer.name
12273
- }
12274
- ) : null,
12275
- offer.symbol ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("p", { className: "clcosdk:w-full clcosdk:truncate clcosdk:text-[13px] clcosdk:leading-[150%] clcosdk:font-normal clcosdk:text-text-secondary clcosdk:md:text-[14px]", children: offer.symbol }) : null
12276
- ] })
12277
- ] })
12278
- }
12279
- );
12280
- const wrapped = containerClassName ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("div", { className: containerClassName, children: card }) : card;
12281
- return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(CoinListStyleScope, { children: wrapped });
12282
- }
12283
- function cardActionLabel(offer) {
12284
- const parts = [offer.name, offer.symbol].filter(Boolean);
12285
- return parts.length > 0 ? parts.join(", ") : "View offer";
12286
- }
12287
-
12288
- // src/client/components/offers/grid/OffersAssetGrid.tsx
12289
- var import_jsx_runtime52 = require("react/jsx-runtime");
12290
- var DEFAULT_MAX_COLUMNS = 3;
12291
- function OffersAssetGrid({
12292
- offers,
12293
- onOfferClick,
12294
- maxColumns,
12295
- className,
12296
- containerClassName
12297
- }) {
12298
- const cols = Math.min(
12299
- DEFAULT_MAX_COLUMNS,
12300
- Math.max(1, maxColumns ?? DEFAULT_MAX_COLUMNS)
12301
- );
12302
- const maxGridWidth = `calc(${cols} * 20rem + ${Math.max(cols - 1, 0)} * 1.5rem)`;
12303
- const interactive = onOfferClick !== void 0;
12304
- return /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(CoinListStyleScope, { children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
12305
- "div",
12306
- {
12307
- className: cn(
12308
- "clcosdk:flex clcosdk:w-full clcosdk:justify-center",
12309
- containerClassName
12310
- ),
12311
- children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
12312
- "div",
12313
- {
12314
- className: cn(
12315
- "clcosdk:grid clcosdk:w-full clcosdk:grid-cols-1 clcosdk:gap-4 clcosdk:md:gap-6",
12316
- cols >= 2 && "clcosdk:sm:grid-cols-2",
12317
- cols >= 3 && "clcosdk:md:grid-cols-3",
12318
- className
12319
- ),
12320
- style: { maxWidth: maxGridWidth },
12321
- children: offers.map((offer) => /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
12322
- OfferAssetCard,
12323
- {
12324
- offer,
12325
- onClick: interactive ? () => onOfferClick(offer.id) : void 0
12326
- },
12327
- offer.id
12328
- ))
12329
- }
12330
- )
12331
- }
12332
- ) });
12333
- }
12334
-
12335
- // src/client/components/offers/shared/OfferSaleCard.tsx
12336
- var import_lucide_react13 = require("lucide-react");
12337
-
12338
- // src/client/components/offers/shared/sale-card-status.ts
12339
- function saleCardStatus({
12340
- endsAt,
12341
- secondsUntilStart,
12342
- secondsLeft
12343
- }) {
12344
- if (secondsUntilStart !== null && secondsUntilStart > 0) {
12345
- return {
12346
- phase: "upcoming",
12347
- label: formatSaleCardCountdown(secondsUntilStart)
12348
- };
12349
- }
12350
- if (endsAt === null) {
12351
- return { phase: "live", label: "Live" };
12352
- }
12353
- if (secondsLeft === null || secondsLeft <= 0) {
12354
- return { phase: "ended", label: "Ended" };
12355
- }
12356
- return {
12357
- phase: "live",
12358
- label: formatSaleCardCountdown(secondsLeft)
12359
- };
12360
- }
12361
-
12362
- // src/client/components/offers/shared/OfferSaleCard.tsx
12363
- var import_jsx_runtime53 = require("react/jsx-runtime");
12364
- function OfferSaleCard({
12365
- offer,
12366
- onClick,
12367
- className,
12368
- containerClassName
12369
- }) {
12370
- const secondsUntilStart = useCountdown({ until: offer.startsAt });
12371
- const secondsLeft = useCountdown({ until: offer.endsAt });
12372
- const status = saleCardStatus({
12373
- endsAt: offer.endsAt,
12374
- secondsUntilStart,
12375
- secondsLeft
12376
- });
12377
- const interactive = onClick !== void 0;
12378
- const card = /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
12379
- "article",
12380
- {
12381
- className: cn(
12382
- "clcosdk:relative clcosdk:flex clcosdk:h-full clcosdk:w-full clcosdk:flex-col clcosdk:gap-4 clcosdk:overflow-hidden clcosdk:rounded-[28px] clcosdk:border-2 clcosdk:border-sale-card-border clcosdk:bg-[image:var(--sale-card-surface)] clcosdk:p-5 clcosdk:shadow-[0px_4px_12px_0px_rgba(0,0,0,0.08),0px_12px_28px_0px_rgba(0,0,0,0.13)]",
12383
- "clcosdk:md:gap-6 clcosdk:md:rounded-[40px] clcosdk:md:p-8",
12384
- interactive && "clcosdk:group clcosdk:cursor-pointer clcosdk:transition-transform clcosdk:duration-300 clcosdk:ease-out clcosdk:hover:scale-[1.02] clcosdk:focus-visible:ring-2 clcosdk:focus-visible:ring-sale-card-focus-ring clcosdk:focus-visible:ring-offset-2 clcosdk:focus-visible:outline-none clcosdk:max-md:hover:scale-100",
12385
- className
12386
- ),
12387
- "aria-label": interactive ? cardActionLabel2(offer, status.phase) : void 0,
12388
- role: interactive ? "button" : void 0,
12389
- tabIndex: interactive ? 0 : void 0,
12390
- onClick,
12391
- onKeyDown: interactive ? (event) => onOfferCardKeyDown(event, onClick) : void 0,
12392
- children: [
12393
- offer.logoUrl ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
12394
- "div",
12395
- {
12396
- "aria-hidden": "true",
12397
- className: "clcosdk:pointer-events-none clcosdk:absolute clcosdk:top-1/2 clcosdk:right-[-14%] clcosdk:z-0 clcosdk:size-[15rem] clcosdk:-translate-y-1/2 clcosdk:md:right-[-10%] clcosdk:md:size-[20rem]",
12398
- style: { mixBlendMode: "overlay" },
12399
- children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
12400
- "img",
12401
- {
12402
- src: offer.logoUrl,
12403
- alt: "",
12404
- className: "clcosdk:size-full clcosdk:rounded-full clcosdk:object-cover",
12405
- style: { maxWidth: "none", width: "100%", height: "100%" }
12406
- }
12407
- )
12408
- }
12409
- ) : null,
12410
- /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "clcosdk:relative clcosdk:z-10 clcosdk:flex clcosdk:flex-col clcosdk:gap-2 clcosdk:md:gap-3", children: [
12411
- /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "clcosdk:flex clcosdk:min-w-0 clcosdk:items-center clcosdk:gap-2.5 clcosdk:md:gap-3", children: [
12412
- offer.logoUrl ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("div", { className: "clcosdk:h-8 clcosdk:w-8 clcosdk:shrink-0 clcosdk:overflow-hidden clcosdk:rounded-full clcosdk:md:h-9 clcosdk:md:w-9", children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
12413
- "img",
12414
- {
12415
- src: offer.logoUrl,
12416
- alt: "",
12417
- width: 36,
12418
- height: 36,
12419
- className: "clcosdk:size-full clcosdk:object-cover",
12420
- style: { maxWidth: "none", width: "100%", height: "100%" }
12421
- }
12422
- ) }) : null,
12423
- offer.name ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
12424
- "h2",
12425
- {
12426
- className: cn(
12427
- "clcosdk:min-w-0 clcosdk:truncate clcosdk:text-[22px] clcosdk:leading-[130%] clcosdk:font-medium clcosdk:text-sale-card-text clcosdk:md:text-[28px] clcosdk:md:leading-[120%]"
12428
- ),
12429
- children: offer.name
12430
- }
12431
- ) : null
12432
- ] }),
12433
- offer.tagline ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
12434
- "p",
12435
- {
12436
- className: cn(
12437
- typeClasses.bodySm,
12438
- "clcosdk:text-sale-card-text-muted clcosdk:md:text-[16px] clcosdk:md:leading-[160%]"
12439
- ),
12440
- children: offer.tagline
12441
- }
12442
- ) : null
12443
- ] }),
12444
- /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "clcosdk:relative clcosdk:z-10 clcosdk:mt-auto clcosdk:flex clcosdk:h-11 clcosdk:w-full clcosdk:min-w-0 clcosdk:items-center clcosdk:justify-between clcosdk:gap-2 clcosdk:rounded-full clcosdk:border clcosdk:border-sale-card-chrome-border clcosdk:bg-sale-card-chrome-bg clcosdk:py-1.5 clcosdk:pr-1.5 clcosdk:pl-3 clcosdk:md:h-[54px] clcosdk:md:gap-3 clcosdk:md:py-2 clcosdk:md:pr-2 clcosdk:md:pl-4", children: [
12445
- /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "clcosdk:flex clcosdk:min-w-0 clcosdk:items-center clcosdk:gap-2 clcosdk:md:gap-3", children: [
12446
- status.phase === "live" ? /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
12447
- "span",
12448
- {
12449
- className: "clcosdk:relative clcosdk:inline-flex clcosdk:size-2 clcosdk:shrink-0",
12450
- "aria-hidden": "true",
12451
- children: [
12452
- /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "clcosdk-status-dot-ping clcosdk:absolute clcosdk:inset-0 clcosdk:rounded-full clcosdk:bg-positive" }),
12453
- /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "clcosdk:relative clcosdk:inline-flex clcosdk:size-full clcosdk:rounded-full clcosdk:bg-positive" })
12454
- ]
12455
- }
12456
- ) : null,
12457
- /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
12458
- "p",
12459
- {
12460
- className: cn(
12461
- typeClasses.data,
12462
- "clcosdk:min-w-0 clcosdk:truncate clcosdk:text-sale-card-text"
12463
- ),
12464
- children: status.label
12465
- }
12466
- )
12467
- ] }),
12468
- /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
12469
- "span",
12470
- {
12471
- className: cn(
12472
- "clcosdk:inline-flex clcosdk:h-full clcosdk:shrink-0 clcosdk:items-center clcosdk:gap-1.5 clcosdk:rounded-full clcosdk:border clcosdk:border-sale-card-chrome-border clcosdk:bg-sale-card-chrome-bg clcosdk:px-3 clcosdk:text-sm clcosdk:font-semibold clcosdk:text-sale-card-text-strong clcosdk:md:px-6 clcosdk:md:text-base",
12473
- interactive && "clcosdk:transition-[background-color,border-color] clcosdk:duration-500 clcosdk:ease-out clcosdk:group-hover:border-sale-card-chrome-emphasis-border clcosdk:group-hover:bg-sale-card-chrome-emphasis-bg clcosdk:group-focus-visible:border-sale-card-chrome-emphasis-border clcosdk:group-focus-visible:bg-sale-card-chrome-emphasis-bg"
12474
- ),
12475
- "aria-hidden": "true",
12476
- children: [
12477
- "View",
12478
- /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "clcosdk:max-md:hidden", children: " offer" }),
12479
- /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react13.ArrowRight, { className: "clcosdk:size-4", "aria-hidden": true })
12480
- ]
12481
- }
12482
- )
12483
- ] })
12484
- ]
12485
- }
12486
- );
12487
- const wrapped = containerClassName ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("div", { className: containerClassName, children: card }) : card;
12488
- return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(CoinListStyleScope, { children: wrapped });
12489
- }
12490
- var SALE_PHASE_LABEL = {
12491
- upcoming: "Upcoming",
12492
- live: "Live",
12493
- ended: "Ended"
12494
- };
12495
- function cardActionLabel2(offer, phase) {
12496
- const title2 = offer.name || offer.tagline;
12497
- return [title2, SALE_PHASE_LABEL[phase], "View offer"].filter(Boolean).join(". ");
12498
- }
12499
-
12500
- // src/client/components/offers/grid/OffersGridView.tsx
12501
- var import_jsx_runtime54 = require("react/jsx-runtime");
12502
- var DEFAULT_MAX_COLUMNS2 = 2;
12503
- function OffersGridView(props) {
12504
- return /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(CoinListStyleScope, { children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(OffersGridViewBody, { ...props }) });
12505
- }
12506
- function OffersGridViewBody({
12507
- state,
12508
- onEvent,
12509
- maxColumns,
12510
- className,
12511
- containerClassName,
12512
- loading,
12513
- error,
12514
- emptyState
12515
- }) {
12516
- switch (state.type) {
12517
- case "loading":
12518
- return loading ?? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(LoadingState, {});
12519
- case "error":
12520
- return error ?? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(ErrorState, { message: state.message });
12521
- case "empty":
12522
- return emptyState ?? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(EmptyState, {});
12523
- case "content":
12524
- return /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
12525
- OffersGridContent,
12526
- {
12527
- offers: state.offers,
12528
- interactive: state.interactive,
12529
- onEvent,
12530
- maxColumns,
12531
- className,
12532
- containerClassName
12533
- }
12534
- );
12535
- default: {
12536
- const exhaustive = state;
12537
- return exhaustive;
12538
- }
12539
- }
12540
- }
12541
- function OffersGridContent({
12542
- offers,
12543
- interactive,
12544
- onEvent,
12545
- maxColumns,
12546
- className,
12547
- containerClassName
12548
- }) {
12549
- const cols = Math.min(
12550
- DEFAULT_MAX_COLUMNS2,
12551
- Math.max(1, maxColumns ?? DEFAULT_MAX_COLUMNS2)
12552
- );
12553
- const maxGridWidth = `calc(${cols} * 28rem + ${Math.max(cols - 1, 0)} * 1.5rem)`;
12554
- return /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
12555
- "div",
12556
- {
12557
- className: cn(
12558
- "clcosdk:flex clcosdk:w-full clcosdk:justify-center",
12559
- containerClassName
12076
+ const superstate = useSuperstateSwapCheckoutViewModel({
12077
+ offer,
12078
+ chain,
12079
+ wallets,
12080
+ enabled: enabled && offer.type === "superstate::swap",
12081
+ onOrderConfirmed: config["superstate::swap"].onOrderConfirmed
12082
+ });
12083
+ return renderOffer(offer.type, {
12084
+ ondo: () => renderOndoSide(side, {
12085
+ buy: () => /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
12086
+ OndoBuyCheckoutView,
12087
+ {
12088
+ state: ondoBuy.state,
12089
+ onEvent: ondoBuy.onEvent,
12090
+ className
12091
+ }
12560
12092
  ),
12561
- children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
12562
- "div",
12093
+ sell: () => /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
12094
+ OndoSellCheckoutView,
12563
12095
  {
12564
- className: cn(
12565
- "clcosdk:grid clcosdk:w-full clcosdk:grid-cols-1 clcosdk:gap-4 clcosdk:md:gap-6",
12566
- cols >= 2 && "clcosdk:md:grid-cols-2",
12567
- className
12568
- ),
12569
- style: { maxWidth: maxGridWidth },
12570
- children: offers.map((offer) => /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
12571
- OfferSaleCard,
12572
- {
12573
- offer,
12574
- onClick: interactive ? () => onEvent({ type: "ON_OFFER_CLICK", offerId: offer.id }) : void 0
12575
- },
12576
- offer.id
12577
- ))
12096
+ state: ondoSell.state,
12097
+ onEvent: ondoSell.onEvent,
12098
+ className
12578
12099
  }
12579
12100
  )
12580
- }
12581
- );
12101
+ }),
12102
+ superstate: () => /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
12103
+ SuperstateSwapCheckoutView,
12104
+ {
12105
+ state: superstate.state,
12106
+ onEvent: superstate.onEvent,
12107
+ className
12108
+ }
12109
+ ),
12110
+ tokenSale: () => config["coinlist::token_sale"].render(offer)
12111
+ });
12582
12112
  }
12583
- function LoadingState() {
12584
- return /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
12585
- "output",
12586
- {
12587
- "aria-live": "polite",
12588
- className: "clcosdk:flex clcosdk:min-h-40 clcosdk:items-center clcosdk:justify-center clcosdk:rounded-2xl clcosdk:border clcosdk:border-border clcosdk:bg-background clcosdk:p-6",
12589
- children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("p", { className: cn(typeClasses.body, "clcosdk:text-text-secondary"), children: "Loading offers..." })
12113
+ function renderOffer(type, branches) {
12114
+ switch (type) {
12115
+ case "ondo::swap":
12116
+ return branches.ondo();
12117
+ case "superstate::swap":
12118
+ return branches.superstate();
12119
+ case "coinlist::token_sale":
12120
+ return branches.tokenSale();
12121
+ default: {
12122
+ const exhaustive = type;
12123
+ return exhaustive;
12590
12124
  }
12591
- );
12125
+ }
12592
12126
  }
12593
- function ErrorState({ message }) {
12594
- return /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
12595
- AlertBanner,
12596
- {
12597
- variant: "error",
12598
- icon: true,
12599
- content: message,
12600
- className: "clcosdk:w-full clcosdk:max-w-[28rem]"
12127
+ function renderOndoSide(side, branches) {
12128
+ switch (side) {
12129
+ case "buy":
12130
+ return branches.buy();
12131
+ case "sell":
12132
+ return branches.sell();
12133
+ default: {
12134
+ const exhaustive = side;
12135
+ return exhaustive;
12601
12136
  }
12602
- );
12137
+ }
12603
12138
  }
12604
- function EmptyState() {
12605
- return /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(
12606
- "output",
12139
+
12140
+ // src/client/components/checkout/ondo/buy/OndoBuyCheckoutContainer.tsx
12141
+ var import_jsx_runtime48 = require("react/jsx-runtime");
12142
+ function OndoBuyCheckoutContainer({
12143
+ offer,
12144
+ ondoSymbol,
12145
+ chain,
12146
+ wallets,
12147
+ enabled,
12148
+ onOrderConfirmed,
12149
+ className
12150
+ }) {
12151
+ const { state, onEvent } = useOndoBuyCheckoutViewModel({
12152
+ offer,
12153
+ ondoSymbol,
12154
+ chain,
12155
+ wallets,
12156
+ enabled,
12157
+ onOrderConfirmed
12158
+ });
12159
+ return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
12160
+ OndoBuyCheckoutView,
12607
12161
  {
12608
- "aria-live": "polite",
12609
- className: "clcosdk:flex clcosdk:min-h-40 clcosdk:flex-col clcosdk:items-center clcosdk:justify-center clcosdk:gap-2 clcosdk:rounded-2xl clcosdk:border clcosdk:border-border clcosdk:bg-background clcosdk:p-6 clcosdk:text-center",
12610
- children: [
12611
- /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
12612
- "p",
12613
- {
12614
- className: cn(
12615
- typeClasses.body,
12616
- "clcosdk:font-medium clcosdk:text-text-primary"
12617
- ),
12618
- children: "No offers available"
12619
- }
12620
- ),
12621
- /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("p", { className: cn(typeClasses.subhead, "clcosdk:text-text-secondary"), children: "Check back soon for upcoming opportunities." })
12622
- ]
12162
+ state,
12163
+ onEvent,
12164
+ className
12623
12165
  }
12624
12166
  );
12625
12167
  }
12626
12168
 
12627
- // src/client/hooks/offers/grid/useOffersGridViewModel.ts
12628
- var import_react37 = require("react");
12629
-
12630
- // src/client/hooks/offers/data/useOffers.ts
12631
- var import_react36 = require("react");
12632
- var LOADING_STATE3 = { type: "LOADING" };
12633
- function useOffers(options = {}) {
12634
- const { coinlist, isReady } = useCoinList();
12635
- const log = useLogger("useOffers");
12636
- const { data: serverOffers } = options;
12637
- const [offersState, setOffersState] = (0, import_react36.useState)(
12638
- serverOffers !== void 0 ? { type: "CONTENT", offers: serverOffers } : LOADING_STATE3
12639
- );
12640
- (0, import_react36.useEffect)(() => {
12641
- let isCancelled = false;
12642
- if (!isReady) {
12643
- if (serverOffers === void 0) {
12644
- setOffersState(LOADING_STATE3);
12645
- }
12646
- return () => {
12647
- isCancelled = true;
12648
- };
12649
- }
12650
- if (serverOffers !== void 0) {
12651
- return () => {
12652
- isCancelled = true;
12653
- };
12654
- }
12655
- setOffersState(LOADING_STATE3);
12656
- coinlist.offers.list().then((offers) => {
12657
- if (!isCancelled) {
12658
- log.debug(() => ({
12659
- msg: "settled",
12660
- fields: { state: "CONTENT", count: offers.length }
12661
- }));
12662
- setOffersState({ type: "CONTENT", offers });
12663
- }
12664
- }).catch((error) => {
12665
- if (!isCancelled) {
12666
- const reason = error instanceof NotAuthenticatedError ? "not-authenticated" : "generic-error";
12667
- log.failure(
12668
- () => ({ msg: "settled", fields: { state: "ERROR", reason } }),
12669
- error
12670
- );
12671
- setOffersState({ type: "ERROR", reason });
12672
- }
12673
- });
12674
- return () => {
12675
- isCancelled = true;
12676
- };
12677
- }, [coinlist, isReady, serverOffers, log]);
12678
- return { offersState };
12679
- }
12680
-
12681
- // src/client/hooks/offers/shared/offer-sale-card.types.ts
12682
- var OfferSaleCardUi = {
12683
- fromOffer: (offer) => ({
12684
- id: offer.id,
12685
- tagline: offer.tagline,
12686
- logoUrl: offer.logoUrl,
12687
- startsAt: offer.startsAt,
12688
- endsAt: offer.endsAt
12689
- }),
12690
- fromDetail: (detail) => ({
12691
- id: detail.id,
12692
- name: detail.name,
12693
- tagline: detail.tagline,
12694
- logoUrl: detail.logoUrl,
12695
- startsAt: detail.startsAt,
12696
- endsAt: detail.endsAt
12697
- })
12698
- };
12699
-
12700
- // src/client/hooks/offers/grid/useOffersGridViewModel.ts
12701
- var NOT_AUTHENTICATED_MESSAGE = "Sign in to view available offers.";
12702
- var GENERIC_ERROR_MESSAGE = "Unable to load offers right now. Please try again.";
12703
- function useOffersGridViewModel(options = {}) {
12704
- const { data, onOfferClick } = options;
12705
- const { offersState } = useOffers({ data });
12706
- const state = (0, import_react37.useMemo)(
12707
- () => toUiState(offersState, onOfferClick !== void 0),
12708
- [offersState, onOfferClick]
12709
- );
12710
- const onEvent = (0, import_react37.useCallback)(
12711
- (event) => {
12712
- switch (event.type) {
12713
- case "ON_OFFER_CLICK": {
12714
- if (offersState.type !== "CONTENT" || !onOfferClick) {
12715
- return;
12716
- }
12717
- const offer = offersState.offers.find((o) => o.id === event.offerId);
12718
- if (offer) {
12719
- onOfferClick(offer);
12720
- }
12721
- return;
12722
- }
12723
- default: {
12724
- const exhaustive = event.type;
12725
- return exhaustive;
12726
- }
12727
- }
12728
- },
12729
- [offersState, onOfferClick]
12169
+ // src/client/components/checkout/ondo/sell/OndoSellCheckoutContainer.tsx
12170
+ var import_jsx_runtime49 = require("react/jsx-runtime");
12171
+ function OndoSellCheckoutContainer({
12172
+ offer,
12173
+ ondoSymbol,
12174
+ chain,
12175
+ wallets,
12176
+ enabled,
12177
+ onOrderConfirmed,
12178
+ className
12179
+ }) {
12180
+ const { state, onEvent } = useOndoSellCheckoutViewModel({
12181
+ offer,
12182
+ ondoSymbol,
12183
+ chain,
12184
+ wallets,
12185
+ enabled,
12186
+ onOrderConfirmed
12187
+ });
12188
+ return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
12189
+ OndoSellCheckoutView,
12190
+ {
12191
+ state,
12192
+ onEvent,
12193
+ className
12194
+ }
12730
12195
  );
12731
- return { state, onEvent };
12732
12196
  }
12733
- function toUiState(offersState, interactive) {
12734
- switch (offersState.type) {
12735
- case "LOADING":
12736
- return { type: "loading" };
12737
- case "ERROR":
12738
- return {
12739
- type: "error",
12740
- message: offersState.reason === "not-authenticated" ? NOT_AUTHENTICATED_MESSAGE : GENERIC_ERROR_MESSAGE
12741
- };
12742
- case "CONTENT": {
12743
- if (offersState.offers.length === 0) {
12744
- return { type: "empty" };
12745
- }
12746
- return {
12747
- type: "content",
12748
- offers: offersState.offers.map(OfferSaleCardUi.fromOffer),
12749
- interactive
12750
- };
12751
- }
12752
- default: {
12753
- const exhaustive = offersState;
12754
- return exhaustive;
12197
+
12198
+ // src/client/components/checkout/superstate/swap/SuperstateSwapCheckoutContainer.tsx
12199
+ var import_jsx_runtime50 = require("react/jsx-runtime");
12200
+ function SuperstateSwapCheckoutContainer({
12201
+ offer,
12202
+ chain,
12203
+ wallets,
12204
+ enabled,
12205
+ onOrderConfirmed,
12206
+ className
12207
+ }) {
12208
+ const { state, onEvent } = useSuperstateSwapCheckoutViewModel({
12209
+ offer,
12210
+ chain,
12211
+ wallets,
12212
+ enabled,
12213
+ onOrderConfirmed
12214
+ });
12215
+ return /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
12216
+ SuperstateSwapCheckoutView,
12217
+ {
12218
+ state,
12219
+ onEvent,
12220
+ className
12755
12221
  }
12756
- }
12222
+ );
12757
12223
  }
12758
12224
 
12759
- // src/client/components/offers/grid/OffersGridContainer.tsx
12760
- var import_jsx_runtime55 = require("react/jsx-runtime");
12761
- function OffersGridContainer({
12762
- data,
12763
- onOfferClick,
12764
- ...viewProps
12765
- } = {}) {
12766
- const { state, onEvent } = useOffersGridViewModel({ data, onOfferClick });
12767
- return /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(OffersGridView, { state, onEvent, ...viewProps });
12225
+ // src/client/components/offers/shared/offer-card-keyboard.ts
12226
+ function onOfferCardKeyDown(event, onClick) {
12227
+ if (event.key !== "Enter" && event.key !== " ") return;
12228
+ event.preventDefault();
12229
+ onClick();
12768
12230
  }
12769
12231
 
12770
- // src/client/components/requirements/checklist/ConnectedWalletList.tsx
12771
- var import_react38 = require("react");
12772
- var import_jsx_runtime56 = require("react/jsx-runtime");
12773
- function ConnectedWalletRow({
12774
- wallet,
12775
- onRemove
12232
+ // src/client/components/offers/shared/OfferAssetCard.tsx
12233
+ var import_jsx_runtime51 = require("react/jsx-runtime");
12234
+ function OfferAssetCard({
12235
+ offer,
12236
+ onClick,
12237
+ className,
12238
+ containerClassName
12776
12239
  }) {
12777
- const [state, setState] = (0, import_react38.useState)("idle");
12778
- const remove = async () => {
12779
- if (!onRemove) return;
12780
- setState("removing");
12781
- try {
12782
- await onRemove(wallet.id);
12783
- setState("idle");
12784
- } catch {
12785
- setState("error");
12786
- }
12787
- };
12788
- return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "clcosdk:flex clcosdk:min-h-9 clcosdk:flex-wrap clcosdk:items-center clcosdk:justify-between clcosdk:gap-2", children: [
12789
- /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
12790
- "span",
12791
- {
12792
- title: wallet.address,
12793
- className: cn(
12794
- typeClasses.body,
12795
- "clcosdk:font-mono clcosdk:text-text-primary"
12796
- ),
12797
- children: wallet.shortAddress
12798
- }
12799
- ),
12800
- onRemove != null && (state === "confirming" ? /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "clcosdk:flex clcosdk:items-center clcosdk:gap-2", children: [
12801
- /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
12802
- "span",
12803
- {
12804
- className: cn(typeClasses.subhead, "clcosdk:text-text-secondary"),
12805
- children: "Remove?"
12806
- }
12240
+ const interactive = onClick !== void 0;
12241
+ const card = /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
12242
+ "article",
12243
+ {
12244
+ className: cn(
12245
+ "clcosdk:relative clcosdk:flex clcosdk:w-full clcosdk:items-center clcosdk:rounded-[20px] clcosdk:border clcosdk:border-border clcosdk:bg-background clcosdk:p-3 clcosdk:shadow-[0px_1px_1px_0px_rgba(10,10,10,0.04),0px_8px_12px_0px_rgba(10,10,10,0.08)]",
12246
+ "clcosdk:md:rounded-card clcosdk:md:p-4",
12247
+ interactive && "clcosdk:cursor-pointer clcosdk:transition-transform clcosdk:duration-300 clcosdk:ease-out clcosdk:hover:scale-[1.02] clcosdk:focus-visible:ring-2 clcosdk:focus-visible:ring-gray-400 clcosdk:focus-visible:ring-offset-2 clcosdk:focus-visible:outline-none clcosdk:max-md:hover:scale-100",
12248
+ className
12807
12249
  ),
12808
- /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(ClButton, { size: "sm", variant: "destructive", onClick: remove, children: "Remove" }),
12809
- /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
12810
- ClButton,
12811
- {
12812
- size: "sm",
12813
- variant: "ghost",
12814
- onClick: () => setState("idle"),
12815
- children: "Cancel"
12816
- }
12817
- )
12818
- ] }) : state === "error" ? /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "clcosdk:flex clcosdk:items-center clcosdk:gap-2", children: [
12819
- /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: cn(typeClasses.subhead, "clcosdk:text-error"), children: "Couldn't remove." }),
12820
- /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
12821
- ClButton,
12822
- {
12823
- size: "sm",
12824
- variant: "destructiveLink",
12825
- onClick: () => setState("confirming"),
12826
- children: "Try again"
12827
- }
12828
- )
12829
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
12830
- ClButton,
12831
- {
12832
- size: "sm",
12833
- variant: "destructiveLink",
12834
- disabled: state === "removing",
12835
- onClick: () => setState("confirming"),
12836
- children: state === "removing" ? "Removing\u2026" : "Remove"
12837
- }
12838
- ))
12839
- ] });
12250
+ "aria-label": interactive ? cardActionLabel(offer) : void 0,
12251
+ role: interactive ? "button" : void 0,
12252
+ tabIndex: interactive ? 0 : void 0,
12253
+ onClick,
12254
+ onKeyDown: interactive ? (event) => onOfferCardKeyDown(event, onClick) : void 0,
12255
+ children: /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: "clcosdk:flex clcosdk:min-w-0 clcosdk:flex-1 clcosdk:items-center clcosdk:gap-2.5 clcosdk:pr-3 clcosdk:md:gap-3 clcosdk:md:pr-4", children: [
12256
+ offer.logoUrl ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("div", { className: "clcosdk:h-10 clcosdk:w-10 clcosdk:shrink-0 clcosdk:overflow-hidden clcosdk:rounded-full clcosdk:md:h-12 clcosdk:md:w-12", children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
12257
+ "img",
12258
+ {
12259
+ src: offer.logoUrl,
12260
+ alt: "",
12261
+ width: 48,
12262
+ height: 48,
12263
+ className: "clcosdk:size-full clcosdk:object-cover",
12264
+ style: { maxWidth: "none", width: "100%", height: "100%" }
12265
+ }
12266
+ ) }) : null,
12267
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: "clcosdk:flex clcosdk:min-w-0 clcosdk:flex-1 clcosdk:flex-col clcosdk:items-start clcosdk:justify-center", children: [
12268
+ offer.name ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
12269
+ "h2",
12270
+ {
12271
+ className: cn(
12272
+ "clcosdk:w-full clcosdk:truncate clcosdk:text-[16px] clcosdk:leading-[140%] clcosdk:font-medium clcosdk:text-text-primary clcosdk:md:text-[18px]"
12273
+ ),
12274
+ children: offer.name
12275
+ }
12276
+ ) : null,
12277
+ offer.symbol ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("p", { className: "clcosdk:w-full clcosdk:truncate clcosdk:text-[13px] clcosdk:leading-[150%] clcosdk:font-normal clcosdk:text-text-secondary clcosdk:md:text-[14px]", children: offer.symbol }) : null
12278
+ ] })
12279
+ ] })
12280
+ }
12281
+ );
12282
+ const wrapped = containerClassName ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("div", { className: containerClassName, children: card }) : card;
12283
+ return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(CoinListStyleScope, { children: wrapped });
12840
12284
  }
12841
- function ConnectedWalletList(props) {
12842
- return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(CoinListStyleScope, { children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(ConnectedWalletListBody, { ...props }) });
12285
+ function cardActionLabel(offer) {
12286
+ const parts = [offer.name, offer.symbol].filter(Boolean);
12287
+ return parts.length > 0 ? parts.join(", ") : "View offer";
12843
12288
  }
12844
- function ConnectedWalletListBody({
12845
- wallets,
12846
- onRemove,
12847
- onAdd,
12848
- addLabel = "Add wallet",
12849
- status = "ready",
12850
- className
12289
+
12290
+ // src/client/components/offers/grid/OffersAssetGrid.tsx
12291
+ var import_jsx_runtime52 = require("react/jsx-runtime");
12292
+ var DEFAULT_MAX_COLUMNS = 3;
12293
+ function OffersAssetGrid({
12294
+ offers,
12295
+ onOfferClick,
12296
+ maxColumns,
12297
+ className,
12298
+ containerClassName
12851
12299
  }) {
12852
- return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(
12300
+ const cols = Math.min(
12301
+ DEFAULT_MAX_COLUMNS,
12302
+ Math.max(1, maxColumns ?? DEFAULT_MAX_COLUMNS)
12303
+ );
12304
+ const maxGridWidth = `calc(${cols} * 20rem + ${Math.max(cols - 1, 0)} * 1.5rem)`;
12305
+ const interactive = onOfferClick !== void 0;
12306
+ return /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(CoinListStyleScope, { children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
12853
12307
  "div",
12854
12308
  {
12855
- className: cn("clcosdk:flex clcosdk:flex-col clcosdk:gap-2", className),
12856
- children: [
12857
- status === "loading" ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(AlertBanner, { variant: "info", content: "Loading your connected wallets\u2026" }) : status === "error" ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
12858
- AlertBanner,
12859
- {
12860
- variant: "error",
12861
- content: "Couldn't load your connected wallets."
12862
- }
12863
- ) : wallets.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(AlertBanner, { variant: "info", content: "No wallets connected yet." }) : /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:divide-y clcosdk:divide-divider", children: wallets.map((wallet) => /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
12864
- ConnectedWalletRow,
12865
- {
12866
- wallet,
12867
- onRemove
12868
- },
12869
- wallet.id
12870
- )) }),
12871
- onAdd != null && status !== "loading" && /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
12872
- ClButton,
12873
- {
12874
- size: "sm",
12875
- variant: "secondary",
12876
- onClick: onAdd,
12877
- className: "clcosdk:self-start",
12878
- children: addLabel
12879
- }
12880
- )
12881
- ]
12309
+ className: cn(
12310
+ "clcosdk:flex clcosdk:w-full clcosdk:justify-center",
12311
+ containerClassName
12312
+ ),
12313
+ children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
12314
+ "div",
12315
+ {
12316
+ className: cn(
12317
+ "clcosdk:grid clcosdk:w-full clcosdk:grid-cols-1 clcosdk:gap-4 clcosdk:md:gap-6",
12318
+ cols >= 2 && "clcosdk:sm:grid-cols-2",
12319
+ cols >= 3 && "clcosdk:md:grid-cols-3",
12320
+ className
12321
+ ),
12322
+ style: { maxWidth: maxGridWidth },
12323
+ children: offers.map((offer) => /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
12324
+ OfferAssetCard,
12325
+ {
12326
+ offer,
12327
+ onClick: interactive ? () => onOfferClick(offer.id) : void 0
12328
+ },
12329
+ offer.id
12330
+ ))
12331
+ }
12332
+ )
12882
12333
  }
12883
- );
12334
+ ) });
12884
12335
  }
12885
12336
 
12886
- // src/client/components/requirements/checklist/RequirementItem.tsx
12887
- var import_lucide_react15 = require("lucide-react");
12337
+ // src/client/components/offers/shared/OfferSaleCard.tsx
12338
+ var import_lucide_react13 = require("lucide-react");
12888
12339
 
12889
- // src/client/components/design-system/StepStatusIcon.tsx
12890
- var import_lucide_react14 = require("lucide-react");
12891
- var import_jsx_runtime57 = require("react/jsx-runtime");
12892
- var statusConfig = {
12893
- required: {
12894
- Icon: import_lucide_react14.Info,
12895
- colorClass: "clcosdk:text-warning",
12896
- fillClass: "clcosdk:[&_circle]:fill-warning-subtle"
12897
- },
12898
- pending: {
12899
- Icon: import_lucide_react14.Info,
12900
- colorClass: "clcosdk:text-warning",
12901
- fillClass: "clcosdk:[&_circle]:fill-warning-subtle"
12902
- },
12903
- completed: {
12904
- Icon: import_lucide_react14.CircleCheck,
12905
- colorClass: "clcosdk:text-success",
12906
- fillClass: "clcosdk:[&_circle]:fill-success-subtle"
12907
- },
12908
- rejected: {
12909
- Icon: import_lucide_react14.CircleX,
12910
- colorClass: "clcosdk:text-error",
12911
- fillClass: "clcosdk:[&_circle]:fill-error-subtle"
12340
+ // src/client/components/offers/shared/sale-card-status.ts
12341
+ function saleCardStatus({
12342
+ endsAt,
12343
+ secondsUntilStart,
12344
+ secondsLeft
12345
+ }) {
12346
+ if (secondsUntilStart !== null && secondsUntilStart > 0) {
12347
+ return {
12348
+ phase: "upcoming",
12349
+ label: formatSaleCardCountdown(secondsUntilStart)
12350
+ };
12912
12351
  }
12913
- };
12914
- function StepStatusIcon({ status, className }) {
12915
- const { Icon, colorClass, fillClass } = statusConfig[status];
12916
- return /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
12917
- Icon,
12352
+ if (endsAt === null) {
12353
+ return { phase: "live", label: "Live" };
12354
+ }
12355
+ if (secondsLeft === null || secondsLeft <= 0) {
12356
+ return { phase: "ended", label: "Ended" };
12357
+ }
12358
+ return {
12359
+ phase: "live",
12360
+ label: formatSaleCardCountdown(secondsLeft)
12361
+ };
12362
+ }
12363
+
12364
+ // src/client/components/offers/shared/OfferSaleCard.tsx
12365
+ var import_jsx_runtime53 = require("react/jsx-runtime");
12366
+ function OfferSaleCard({
12367
+ offer,
12368
+ onClick,
12369
+ className,
12370
+ containerClassName
12371
+ }) {
12372
+ const secondsUntilStart = useCountdown({ until: offer.startsAt });
12373
+ const secondsLeft = useCountdown({ until: offer.endsAt });
12374
+ const status = saleCardStatus({
12375
+ endsAt: offer.endsAt,
12376
+ secondsUntilStart,
12377
+ secondsLeft
12378
+ });
12379
+ const interactive = onClick !== void 0;
12380
+ const card = /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
12381
+ "article",
12918
12382
  {
12919
12383
  className: cn(
12920
- "clcosdk:h-6 clcosdk:w-6 clcosdk:shrink-0",
12921
- colorClass,
12922
- fillClass,
12384
+ "clcosdk:relative clcosdk:flex clcosdk:h-full clcosdk:w-full clcosdk:flex-col clcosdk:gap-4 clcosdk:overflow-hidden clcosdk:rounded-[28px] clcosdk:border-2 clcosdk:border-sale-card-border clcosdk:bg-[image:var(--sale-card-surface)] clcosdk:p-5 clcosdk:shadow-[0px_4px_12px_0px_rgba(0,0,0,0.08),0px_12px_28px_0px_rgba(0,0,0,0.13)]",
12385
+ "clcosdk:md:gap-6 clcosdk:md:rounded-[40px] clcosdk:md:p-8",
12386
+ interactive && "clcosdk:group clcosdk:cursor-pointer clcosdk:transition-transform clcosdk:duration-300 clcosdk:ease-out clcosdk:hover:scale-[1.02] clcosdk:focus-visible:ring-2 clcosdk:focus-visible:ring-sale-card-focus-ring clcosdk:focus-visible:ring-offset-2 clcosdk:focus-visible:outline-none clcosdk:max-md:hover:scale-100",
12923
12387
  className
12924
12388
  ),
12925
- "aria-hidden": "true"
12389
+ "aria-label": interactive ? cardActionLabel2(offer, status.phase) : void 0,
12390
+ role: interactive ? "button" : void 0,
12391
+ tabIndex: interactive ? 0 : void 0,
12392
+ onClick,
12393
+ onKeyDown: interactive ? (event) => onOfferCardKeyDown(event, onClick) : void 0,
12394
+ children: [
12395
+ offer.logoUrl ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
12396
+ "div",
12397
+ {
12398
+ "aria-hidden": "true",
12399
+ className: "clcosdk:pointer-events-none clcosdk:absolute clcosdk:top-1/2 clcosdk:right-[-14%] clcosdk:z-0 clcosdk:size-[15rem] clcosdk:-translate-y-1/2 clcosdk:md:right-[-10%] clcosdk:md:size-[20rem]",
12400
+ style: { mixBlendMode: "overlay" },
12401
+ children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
12402
+ "img",
12403
+ {
12404
+ src: offer.logoUrl,
12405
+ alt: "",
12406
+ className: "clcosdk:size-full clcosdk:rounded-full clcosdk:object-cover",
12407
+ style: { maxWidth: "none", width: "100%", height: "100%" }
12408
+ }
12409
+ )
12410
+ }
12411
+ ) : null,
12412
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "clcosdk:relative clcosdk:z-10 clcosdk:flex clcosdk:flex-col clcosdk:gap-2 clcosdk:md:gap-3", children: [
12413
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "clcosdk:flex clcosdk:min-w-0 clcosdk:items-center clcosdk:gap-2.5 clcosdk:md:gap-3", children: [
12414
+ offer.logoUrl ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("div", { className: "clcosdk:h-8 clcosdk:w-8 clcosdk:shrink-0 clcosdk:overflow-hidden clcosdk:rounded-full clcosdk:md:h-9 clcosdk:md:w-9", children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
12415
+ "img",
12416
+ {
12417
+ src: offer.logoUrl,
12418
+ alt: "",
12419
+ width: 36,
12420
+ height: 36,
12421
+ className: "clcosdk:size-full clcosdk:object-cover",
12422
+ style: { maxWidth: "none", width: "100%", height: "100%" }
12423
+ }
12424
+ ) }) : null,
12425
+ offer.name ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
12426
+ "h2",
12427
+ {
12428
+ className: cn(
12429
+ "clcosdk:min-w-0 clcosdk:truncate clcosdk:text-[22px] clcosdk:leading-[130%] clcosdk:font-medium clcosdk:text-sale-card-text clcosdk:md:text-[28px] clcosdk:md:leading-[120%]"
12430
+ ),
12431
+ children: offer.name
12432
+ }
12433
+ ) : null
12434
+ ] }),
12435
+ offer.tagline ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
12436
+ "p",
12437
+ {
12438
+ className: cn(
12439
+ typeClasses.bodySm,
12440
+ "clcosdk:text-sale-card-text-muted clcosdk:md:text-[16px] clcosdk:md:leading-[160%]"
12441
+ ),
12442
+ children: offer.tagline
12443
+ }
12444
+ ) : null
12445
+ ] }),
12446
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "clcosdk:relative clcosdk:z-10 clcosdk:mt-auto clcosdk:flex clcosdk:h-11 clcosdk:w-full clcosdk:min-w-0 clcosdk:items-center clcosdk:justify-between clcosdk:gap-2 clcosdk:rounded-full clcosdk:border clcosdk:border-sale-card-chrome-border clcosdk:bg-sale-card-chrome-bg clcosdk:py-1.5 clcosdk:pr-1.5 clcosdk:pl-3 clcosdk:md:h-[54px] clcosdk:md:gap-3 clcosdk:md:py-2 clcosdk:md:pr-2 clcosdk:md:pl-4", children: [
12447
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "clcosdk:flex clcosdk:min-w-0 clcosdk:items-center clcosdk:gap-2 clcosdk:md:gap-3", children: [
12448
+ status.phase === "live" ? /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
12449
+ "span",
12450
+ {
12451
+ className: "clcosdk:relative clcosdk:inline-flex clcosdk:size-2 clcosdk:shrink-0",
12452
+ "aria-hidden": "true",
12453
+ children: [
12454
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "clcosdk-status-dot-ping clcosdk:absolute clcosdk:inset-0 clcosdk:rounded-full clcosdk:bg-positive" }),
12455
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "clcosdk:relative clcosdk:inline-flex clcosdk:size-full clcosdk:rounded-full clcosdk:bg-positive" })
12456
+ ]
12457
+ }
12458
+ ) : null,
12459
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
12460
+ "p",
12461
+ {
12462
+ className: cn(
12463
+ typeClasses.data,
12464
+ "clcosdk:min-w-0 clcosdk:truncate clcosdk:text-sale-card-text"
12465
+ ),
12466
+ children: status.label
12467
+ }
12468
+ )
12469
+ ] }),
12470
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
12471
+ "span",
12472
+ {
12473
+ className: cn(
12474
+ "clcosdk:inline-flex clcosdk:h-full clcosdk:shrink-0 clcosdk:items-center clcosdk:gap-1.5 clcosdk:rounded-full clcosdk:border clcosdk:border-sale-card-chrome-border clcosdk:bg-sale-card-chrome-bg clcosdk:px-3 clcosdk:text-sm clcosdk:font-semibold clcosdk:text-sale-card-text-strong clcosdk:md:px-6 clcosdk:md:text-base",
12475
+ interactive && "clcosdk:transition-[background-color,border-color] clcosdk:duration-500 clcosdk:ease-out clcosdk:group-hover:border-sale-card-chrome-emphasis-border clcosdk:group-hover:bg-sale-card-chrome-emphasis-bg clcosdk:group-focus-visible:border-sale-card-chrome-emphasis-border clcosdk:group-focus-visible:bg-sale-card-chrome-emphasis-bg"
12476
+ ),
12477
+ "aria-hidden": "true",
12478
+ children: [
12479
+ "View",
12480
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "clcosdk:max-md:hidden", children: " offer" }),
12481
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react13.ArrowRight, { className: "clcosdk:size-4", "aria-hidden": true })
12482
+ ]
12483
+ }
12484
+ )
12485
+ ] })
12486
+ ]
12926
12487
  }
12927
12488
  );
12489
+ const wrapped = containerClassName ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("div", { className: containerClassName, children: card }) : card;
12490
+ return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(CoinListStyleScope, { children: wrapped });
12491
+ }
12492
+ var SALE_PHASE_LABEL = {
12493
+ upcoming: "Upcoming",
12494
+ live: "Live",
12495
+ ended: "Ended"
12496
+ };
12497
+ function cardActionLabel2(offer, phase) {
12498
+ const title2 = offer.name || offer.tagline;
12499
+ return [title2, SALE_PHASE_LABEL[phase], "View offer"].filter(Boolean).join(". ");
12928
12500
  }
12929
12501
 
12930
- // src/client/components/requirements/checklist/RequirementItem.tsx
12931
- var import_jsx_runtime58 = require("react/jsx-runtime");
12932
- function VerificationActionZone({
12933
- status,
12934
- onAction,
12935
- onContactSupport
12936
- }) {
12937
- switch (status) {
12938
- case "required":
12939
- if (onAction === null) return null;
12940
- return /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(ClButton, { size: "sm", onClick: onAction, children: "Continue" });
12941
- case "pending":
12942
- return /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
12943
- AlertBanner,
12944
- {
12945
- variant: "warning",
12946
- content: "Under review. We'll notify you when complete."
12947
- }
12948
- );
12949
- case "completed":
12950
- return /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(AlertBanner, { variant: "success", content: "Identity verified." });
12951
- case "rejected":
12952
- return /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
12953
- AlertBanner,
12954
- {
12955
- variant: "error",
12956
- content: onContactSupport === null ? "Verification rejected." : /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(import_jsx_runtime58.Fragment, { children: [
12957
- "Verification rejected.",
12958
- " ",
12959
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
12960
- "button",
12961
- {
12962
- type: "button",
12963
- onClick: onContactSupport,
12964
- className: "clcosdk:underline",
12965
- children: "Contact support"
12966
- }
12967
- ),
12968
- "."
12969
- ] })
12970
- }
12971
- );
12972
- }
12502
+ // src/client/components/offers/grid/OffersGridView.tsx
12503
+ var import_jsx_runtime54 = require("react/jsx-runtime");
12504
+ var DEFAULT_MAX_COLUMNS2 = 2;
12505
+ function OffersGridView(props) {
12506
+ return /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(CoinListStyleScope, { children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(OffersGridViewBody, { ...props }) });
12973
12507
  }
12974
- function WalletActionZone({
12975
- status,
12976
- multiWallet,
12977
- connectedWallets,
12978
- walletsStatus,
12979
- onAction,
12980
- onRemoveWallet
12508
+ function OffersGridViewBody({
12509
+ state,
12510
+ onEvent,
12511
+ maxColumns,
12512
+ className,
12513
+ containerClassName,
12514
+ loading,
12515
+ error,
12516
+ emptyState
12981
12517
  }) {
12982
- if (multiWallet) {
12983
- return /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(import_jsx_runtime58.Fragment, { children: [
12984
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
12985
- ConnectedWalletList,
12986
- {
12987
- wallets: connectedWallets,
12988
- onRemove: onRemoveWallet,
12989
- onAdd: onAction ?? void 0,
12990
- status: walletsStatus
12991
- }
12992
- ),
12993
- status === "rejected" && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
12994
- AlertBanner,
12995
- {
12996
- variant: "error",
12997
- content: "One of these wallets is not eligible for this sale."
12998
- }
12999
- )
13000
- ] });
13001
- }
13002
- if (status === "completed") {
13003
- const connected = connectedWallets[0];
13004
- return /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(import_jsx_runtime58.Fragment, { children: [
13005
- onAction !== null && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(ClButton, { size: "sm", variant: "secondary", onClick: onAction, children: "Change wallet" }),
13006
- walletsStatus === "loading" ? /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
13007
- AlertBanner,
13008
- {
13009
- variant: "info",
13010
- content: "Loading your connected wallet\u2026"
13011
- }
13012
- ) : walletsStatus === "error" ? /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
13013
- AlertBanner,
13014
- {
13015
- variant: "error",
13016
- content: "Couldn't load your connected wallet."
13017
- }
13018
- ) : /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
13019
- AlertBanner,
13020
- {
13021
- variant: "success",
13022
- content: connected ? connected.shortAddress : "Wallet connected."
13023
- }
13024
- )
13025
- ] });
13026
- }
13027
- if (status === "rejected") {
13028
- return /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(import_jsx_runtime58.Fragment, { children: [
13029
- onAction !== null && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(ClButton, { size: "sm", onClick: onAction, children: "Connect wallet" }),
13030
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
13031
- AlertBanner,
12518
+ switch (state.type) {
12519
+ case "loading":
12520
+ return loading ?? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(LoadingState, {});
12521
+ case "error":
12522
+ return error ?? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(ErrorState, { message: state.message });
12523
+ case "empty":
12524
+ return emptyState ?? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(EmptyState, {});
12525
+ case "content":
12526
+ return /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
12527
+ OffersGridContent,
13032
12528
  {
13033
- variant: "error",
13034
- content: "This wallet is not eligible for this sale."
12529
+ offers: state.offers,
12530
+ interactive: state.interactive,
12531
+ onEvent,
12532
+ maxColumns,
12533
+ className,
12534
+ containerClassName
13035
12535
  }
13036
- )
13037
- ] });
12536
+ );
12537
+ default: {
12538
+ const exhaustive = state;
12539
+ return exhaustive;
12540
+ }
13038
12541
  }
13039
- if (onAction === null) return null;
13040
- return /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(ClButton, { size: "sm", onClick: onAction, children: "Connect wallet" });
13041
12542
  }
13042
- function RequirementItem({
13043
- ui,
13044
- expanded = false,
13045
- onToggle,
12543
+ function OffersGridContent({
12544
+ offers,
12545
+ interactive,
12546
+ onEvent,
12547
+ maxColumns,
13046
12548
  className,
13047
- onAction,
13048
- onRemoveWallet,
13049
- walletsStatus,
13050
- onContactSupport
12549
+ containerClassName
13051
12550
  }) {
13052
- return /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(CoinListStyleScope, { children: /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(
12551
+ const cols = Math.min(
12552
+ DEFAULT_MAX_COLUMNS2,
12553
+ Math.max(1, maxColumns ?? DEFAULT_MAX_COLUMNS2)
12554
+ );
12555
+ const maxGridWidth = `calc(${cols} * 28rem + ${Math.max(cols - 1, 0)} * 1.5rem)`;
12556
+ return /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
13053
12557
  "div",
13054
12558
  {
13055
12559
  className: cn(
13056
- "clcosdk:flex clcosdk:w-full clcosdk:flex-col",
13057
- className
12560
+ "clcosdk:flex clcosdk:w-full clcosdk:justify-center",
12561
+ containerClassName
13058
12562
  ),
12563
+ children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
12564
+ "div",
12565
+ {
12566
+ className: cn(
12567
+ "clcosdk:grid clcosdk:w-full clcosdk:grid-cols-1 clcosdk:gap-4 clcosdk:md:gap-6",
12568
+ cols >= 2 && "clcosdk:md:grid-cols-2",
12569
+ className
12570
+ ),
12571
+ style: { maxWidth: maxGridWidth },
12572
+ children: offers.map((offer) => /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
12573
+ OfferSaleCard,
12574
+ {
12575
+ offer,
12576
+ onClick: interactive ? () => onEvent({ type: "ON_OFFER_CLICK", offerId: offer.id }) : void 0
12577
+ },
12578
+ offer.id
12579
+ ))
12580
+ }
12581
+ )
12582
+ }
12583
+ );
12584
+ }
12585
+ function LoadingState() {
12586
+ return /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
12587
+ "output",
12588
+ {
12589
+ "aria-live": "polite",
12590
+ className: "clcosdk:flex clcosdk:min-h-40 clcosdk:items-center clcosdk:justify-center clcosdk:rounded-2xl clcosdk:border clcosdk:border-border clcosdk:bg-background clcosdk:p-6",
12591
+ children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("p", { className: cn(typeClasses.body, "clcosdk:text-text-secondary"), children: "Loading offers..." })
12592
+ }
12593
+ );
12594
+ }
12595
+ function ErrorState({ message }) {
12596
+ return /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
12597
+ AlertBanner,
12598
+ {
12599
+ variant: "error",
12600
+ icon: true,
12601
+ content: message,
12602
+ className: "clcosdk:w-full clcosdk:max-w-[28rem]"
12603
+ }
12604
+ );
12605
+ }
12606
+ function EmptyState() {
12607
+ return /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(
12608
+ "output",
12609
+ {
12610
+ "aria-live": "polite",
12611
+ className: "clcosdk:flex clcosdk:min-h-40 clcosdk:flex-col clcosdk:items-center clcosdk:justify-center clcosdk:gap-2 clcosdk:rounded-2xl clcosdk:border clcosdk:border-border clcosdk:bg-background clcosdk:p-6 clcosdk:text-center",
13059
12612
  children: [
13060
- /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(
13061
- "button",
13062
- {
13063
- type: "button",
13064
- onClick: onToggle,
13065
- "aria-expanded": expanded,
13066
- className: "clcosdk:flex clcosdk:h-14 clcosdk:w-full clcosdk:cursor-pointer clcosdk:items-center clcosdk:justify-between clcosdk:rounded-2xl clcosdk:px-2 clcosdk:transition-colors clcosdk:hover:bg-surface",
13067
- children: [
13068
- /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "clcosdk:flex clcosdk:items-center clcosdk:gap-3", children: [
13069
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(StepStatusIcon, { status: ui.status }),
13070
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
13071
- "span",
13072
- {
13073
- className: cn(
13074
- typeClasses.body,
13075
- "clcosdk:whitespace-nowrap clcosdk:font-medium clcosdk:text-text-primary"
13076
- ),
13077
- children: ui.label
13078
- }
13079
- )
13080
- ] }),
13081
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
13082
- import_lucide_react15.ChevronRight,
13083
- {
13084
- className: cn(
13085
- "clcosdk:h-6 clcosdk:w-6 clcosdk:shrink-0 clcosdk:text-text-secondary clcosdk:transition-transform clcosdk:duration-300",
13086
- expanded && "clcosdk:rotate-90"
13087
- ),
13088
- "aria-hidden": "true"
13089
- }
13090
- )
13091
- ]
13092
- }
13093
- ),
13094
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
13095
- "div",
12613
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
12614
+ "p",
13096
12615
  {
13097
12616
  className: cn(
13098
- "clcosdk:grid clcosdk:transition-[grid-template-rows] clcosdk:duration-300 clcosdk:ease-in-out",
13099
- expanded ? "clcosdk:grid-rows-[1fr]" : "clcosdk:grid-rows-[0fr]"
12617
+ typeClasses.body,
12618
+ "clcosdk:font-medium clcosdk:text-text-primary"
13100
12619
  ),
13101
- children: /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("div", { className: "clcosdk:min-h-0 clcosdk:overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-4 clcosdk:px-2 clcosdk:pb-4", children: [
13102
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
13103
- "p",
13104
- {
13105
- className: cn(
13106
- typeClasses.subhead,
13107
- "clcosdk:text-text-secondary"
13108
- ),
13109
- children: ui.description
13110
- }
13111
- ),
13112
- ui.variant === "verification" ? /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
13113
- VerificationActionZone,
13114
- {
13115
- status: ui.status,
13116
- onAction,
13117
- onContactSupport
13118
- }
13119
- ) : /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
13120
- WalletActionZone,
13121
- {
13122
- status: ui.status,
13123
- multiWallet: ui.multiWallet,
13124
- connectedWallets: ui.connectedWallets,
13125
- walletsStatus,
13126
- onAction,
13127
- onRemoveWallet
13128
- }
13129
- )
13130
- ] }) })
12620
+ children: "No offers available"
13131
12621
  }
13132
- )
12622
+ ),
12623
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("p", { className: cn(typeClasses.subhead, "clcosdk:text-text-secondary"), children: "Check back soon for upcoming opportunities." })
13133
12624
  ]
13134
12625
  }
13135
- ) });
12626
+ );
12627
+ }
12628
+
12629
+ // src/client/hooks/offers/grid/useOffersGridViewModel.ts
12630
+ var import_react37 = require("react");
12631
+
12632
+ // src/client/hooks/offers/data/useOffers.ts
12633
+ var import_react36 = require("react");
12634
+ var LOADING_STATE3 = { type: "LOADING" };
12635
+ function useOffers(options = {}) {
12636
+ const { coinlist, isReady } = useCoinList();
12637
+ const log = useLogger("useOffers");
12638
+ const { data: serverOffers } = options;
12639
+ const [offersState, setOffersState] = (0, import_react36.useState)(
12640
+ serverOffers !== void 0 ? { type: "CONTENT", offers: serverOffers } : LOADING_STATE3
12641
+ );
12642
+ (0, import_react36.useEffect)(() => {
12643
+ let isCancelled = false;
12644
+ if (!isReady) {
12645
+ if (serverOffers === void 0) {
12646
+ setOffersState(LOADING_STATE3);
12647
+ }
12648
+ return () => {
12649
+ isCancelled = true;
12650
+ };
12651
+ }
12652
+ if (serverOffers !== void 0) {
12653
+ return () => {
12654
+ isCancelled = true;
12655
+ };
12656
+ }
12657
+ setOffersState(LOADING_STATE3);
12658
+ coinlist.offers.list().then((offers) => {
12659
+ if (!isCancelled) {
12660
+ log.debug(() => ({
12661
+ msg: "settled",
12662
+ fields: { state: "CONTENT", count: offers.length }
12663
+ }));
12664
+ setOffersState({ type: "CONTENT", offers });
12665
+ }
12666
+ }).catch((error) => {
12667
+ if (!isCancelled) {
12668
+ const reason = error instanceof NotAuthenticatedError ? "not-authenticated" : "generic-error";
12669
+ log.failure(
12670
+ () => ({ msg: "settled", fields: { state: "ERROR", reason } }),
12671
+ error
12672
+ );
12673
+ setOffersState({ type: "ERROR", reason });
12674
+ }
12675
+ });
12676
+ return () => {
12677
+ isCancelled = true;
12678
+ };
12679
+ }, [coinlist, isReady, serverOffers, log]);
12680
+ return { offersState };
13136
12681
  }
13137
12682
 
13138
- // src/client/components/requirements/checklist/RequirementsChecklistView.tsx
13139
- var import_jsx_runtime59 = require("react/jsx-runtime");
13140
- function RequirementsChecklistView(props) {
13141
- return /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(CoinListStyleScope, { children: /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(RequirementsChecklistViewBody, { ...props }) });
13142
- }
13143
- function RequirementsChecklistViewBody({
13144
- state,
13145
- onEvent,
13146
- loading,
13147
- error,
13148
- unauthenticatedState,
13149
- className
13150
- }) {
13151
- switch (state.type) {
13152
- case "loading":
13153
- return loading ?? /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(LoadingState2, {});
13154
- case "not-authenticated":
13155
- return unauthenticatedState ?? null;
13156
- case "error":
13157
- return error ?? /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
13158
- AlertBanner,
13159
- {
13160
- variant: "error",
13161
- icon: true,
13162
- content: "Unable to load requirements right now. Please try again.",
13163
- className: "clcosdk:w-full clcosdk:max-w-[28rem]"
12683
+ // src/client/hooks/offers/shared/offer-sale-card.types.ts
12684
+ var OfferSaleCardUi = {
12685
+ fromOffer: (offer) => ({
12686
+ id: offer.id,
12687
+ tagline: offer.tagline,
12688
+ logoUrl: offer.logoUrl,
12689
+ startsAt: offer.startsAt,
12690
+ endsAt: offer.endsAt
12691
+ }),
12692
+ fromDetail: (detail) => ({
12693
+ id: detail.id,
12694
+ name: detail.name,
12695
+ tagline: detail.tagline,
12696
+ logoUrl: detail.logoUrl,
12697
+ startsAt: detail.startsAt,
12698
+ endsAt: detail.endsAt
12699
+ })
12700
+ };
12701
+
12702
+ // src/client/hooks/offers/grid/useOffersGridViewModel.ts
12703
+ var NOT_AUTHENTICATED_MESSAGE = "Sign in to view available offers.";
12704
+ var GENERIC_ERROR_MESSAGE = "Unable to load offers right now. Please try again.";
12705
+ function useOffersGridViewModel(options = {}) {
12706
+ const { data, onOfferClick } = options;
12707
+ const { offersState } = useOffers({ data });
12708
+ const state = (0, import_react37.useMemo)(
12709
+ () => toUiState(offersState, onOfferClick !== void 0),
12710
+ [offersState, onOfferClick]
12711
+ );
12712
+ const onEvent = (0, import_react37.useCallback)(
12713
+ (event) => {
12714
+ switch (event.type) {
12715
+ case "ON_OFFER_CLICK": {
12716
+ if (offersState.type !== "CONTENT" || !onOfferClick) {
12717
+ return;
12718
+ }
12719
+ const offer = offersState.offers.find((o) => o.id === event.offerId);
12720
+ if (offer) {
12721
+ onOfferClick(offer);
12722
+ }
12723
+ return;
13164
12724
  }
13165
- );
13166
- case "content":
13167
- return /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)(
13168
- "div",
13169
- {
13170
- className: cn(
13171
- "clcosdk:flex clcosdk:w-full clcosdk:flex-col clcosdk:gap-4",
13172
- className
13173
- ),
13174
- children: [
13175
- /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-2", children: [
13176
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("h3", { className: cn(typeClasses.h3, "clcosdk:text-text-primary"), children: state.title }),
13177
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("p", { className: cn(typeClasses.body, "clcosdk:text-text-secondary"), children: state.description })
13178
- ] }),
13179
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:divide-y clcosdk:divide-divider", children: state.items.map((row) => /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
13180
- RequirementItem,
13181
- {
13182
- ui: row.item,
13183
- expanded: row.expanded,
13184
- onToggle: () => onEvent({ type: "ON_TOGGLE_ITEM", requirementId: row.id }),
13185
- onAction: row.actionEnabled ? () => onEvent({
13186
- type: "ON_REQUIREMENT_ACTION",
13187
- requirementId: row.id
13188
- }) : null,
13189
- onRemoveWallet: row.wallets ? (id) => state.removeWallet(id) : void 0,
13190
- walletsStatus: row.wallets?.status,
13191
- onContactSupport: row.contactSupportEnabled ? () => onEvent({
13192
- type: "ON_CONTACT_SUPPORT",
13193
- requirementId: row.id
13194
- }) : null
13195
- },
13196
- row.id
13197
- )) }),
13198
- state.ineligible && /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
13199
- AlertBanner,
13200
- {
13201
- variant: "error",
13202
- icon: true,
13203
- content: "You are not eligible to participate."
13204
- }
13205
- ),
13206
- state.continueAction && /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
13207
- ClButton,
13208
- {
13209
- fullWidth: true,
13210
- disabled: !state.continueAction.enabled,
13211
- onClick: () => onEvent({ type: "ON_CONTINUE" }),
13212
- children: "Continue"
13213
- }
13214
- )
13215
- ]
12725
+ default: {
12726
+ const exhaustive = event.type;
12727
+ return exhaustive;
13216
12728
  }
13217
- );
12729
+ }
12730
+ },
12731
+ [offersState, onOfferClick]
12732
+ );
12733
+ return { state, onEvent };
12734
+ }
12735
+ function toUiState(offersState, interactive) {
12736
+ switch (offersState.type) {
12737
+ case "LOADING":
12738
+ return { type: "loading" };
12739
+ case "ERROR":
12740
+ return {
12741
+ type: "error",
12742
+ message: offersState.reason === "not-authenticated" ? NOT_AUTHENTICATED_MESSAGE : GENERIC_ERROR_MESSAGE
12743
+ };
12744
+ case "CONTENT": {
12745
+ if (offersState.offers.length === 0) {
12746
+ return { type: "empty" };
12747
+ }
12748
+ return {
12749
+ type: "content",
12750
+ offers: offersState.offers.map(OfferSaleCardUi.fromOffer),
12751
+ interactive
12752
+ };
12753
+ }
13218
12754
  default: {
13219
- const exhaustive = state;
12755
+ const exhaustive = offersState;
13220
12756
  return exhaustive;
13221
12757
  }
13222
12758
  }
13223
12759
  }
13224
- function LoadingState2() {
13225
- return /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
13226
- "output",
13227
- {
13228
- "aria-live": "polite",
13229
- className: "clcosdk:flex clcosdk:min-h-40 clcosdk:items-center clcosdk:justify-center clcosdk:rounded-2xl clcosdk:border clcosdk:border-border clcosdk:bg-background clcosdk:p-6",
13230
- children: /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("p", { className: cn(typeClasses.body, "clcosdk:text-text-secondary"), children: "Loading requirements..." })
13231
- }
13232
- );
12760
+
12761
+ // src/client/components/offers/grid/OffersGridContainer.tsx
12762
+ var import_jsx_runtime55 = require("react/jsx-runtime");
12763
+ function OffersGridContainer({
12764
+ data,
12765
+ onOfferClick,
12766
+ ...viewProps
12767
+ } = {}) {
12768
+ const { state, onEvent } = useOffersGridViewModel({ data, onOfferClick });
12769
+ return /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(OffersGridView, { state, onEvent, ...viewProps });
13233
12770
  }
13234
12771
 
13235
- // src/client/components/requirements/checklist/VerificationOverlay.tsx
13236
- var import_jsx_runtime60 = require("react/jsx-runtime");
13237
- function VerificationOverlay({
13238
- onClose,
13239
- children
12772
+ // src/client/components/requirements/ConnectedWalletList.tsx
12773
+ var import_react38 = require("react");
12774
+ var import_jsx_runtime56 = require("react/jsx-runtime");
12775
+ function ConnectedWalletRow({
12776
+ wallet,
12777
+ onRemove
13240
12778
  }) {
13241
- return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(CoinListStyleScope, { children: /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(VerificationOverlayBody, { onClose, children }) });
12779
+ const [state, setState] = (0, import_react38.useState)("idle");
12780
+ const remove = async () => {
12781
+ if (!onRemove) return;
12782
+ setState("removing");
12783
+ try {
12784
+ await onRemove(wallet.id);
12785
+ setState("idle");
12786
+ } catch {
12787
+ setState("error");
12788
+ }
12789
+ };
12790
+ return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "clcosdk:flex clcosdk:min-h-9 clcosdk:flex-wrap clcosdk:items-center clcosdk:justify-between clcosdk:gap-2", children: [
12791
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
12792
+ "span",
12793
+ {
12794
+ title: wallet.address,
12795
+ className: cn(
12796
+ typeClasses.body,
12797
+ "clcosdk:font-mono clcosdk:text-text-primary"
12798
+ ),
12799
+ children: wallet.shortAddress
12800
+ }
12801
+ ),
12802
+ onRemove != null && (state === "confirming" ? /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "clcosdk:flex clcosdk:items-center clcosdk:gap-2", children: [
12803
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
12804
+ "span",
12805
+ {
12806
+ className: cn(typeClasses.subhead, "clcosdk:text-text-secondary"),
12807
+ children: "Remove?"
12808
+ }
12809
+ ),
12810
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(ClButton, { size: "sm", variant: "destructive", onClick: remove, children: "Remove" }),
12811
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
12812
+ ClButton,
12813
+ {
12814
+ size: "sm",
12815
+ variant: "ghost",
12816
+ onClick: () => setState("idle"),
12817
+ children: "Cancel"
12818
+ }
12819
+ )
12820
+ ] }) : state === "error" ? /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "clcosdk:flex clcosdk:items-center clcosdk:gap-2", children: [
12821
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: cn(typeClasses.subhead, "clcosdk:text-error"), children: "Couldn't remove." }),
12822
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
12823
+ ClButton,
12824
+ {
12825
+ size: "sm",
12826
+ variant: "destructiveLink",
12827
+ onClick: () => setState("confirming"),
12828
+ children: "Try again"
12829
+ }
12830
+ )
12831
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
12832
+ ClButton,
12833
+ {
12834
+ size: "sm",
12835
+ variant: "destructiveLink",
12836
+ disabled: state === "removing",
12837
+ onClick: () => setState("confirming"),
12838
+ children: state === "removing" ? "Removing\u2026" : "Remove"
12839
+ }
12840
+ ))
12841
+ ] });
13242
12842
  }
13243
- function VerificationOverlayBody({
13244
- onClose,
13245
- children
12843
+ function ConnectedWalletList(props) {
12844
+ return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(CoinListStyleScope, { children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(ConnectedWalletListBody, { ...props }) });
12845
+ }
12846
+ function ConnectedWalletListBody({
12847
+ wallets,
12848
+ onRemove,
12849
+ onAdd,
12850
+ addLabel = "Add wallet",
12851
+ status = "ready",
12852
+ className
13246
12853
  }) {
13247
- return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
12854
+ return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(
13248
12855
  "div",
13249
12856
  {
13250
- role: "dialog",
13251
- "aria-modal": "true",
13252
- "aria-label": "Identity verification",
13253
- className: "clcosdk:fixed clcosdk:inset-0 clcosdk:z-50 clcosdk:flex clcosdk:items-center clcosdk:justify-center clcosdk:bg-overlay clcosdk:p-4",
13254
- children: /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "clcosdk:relative clcosdk:flex clcosdk:max-h-[92vh] clcosdk:w-full clcosdk:max-w-[760px] clcosdk:flex-col clcosdk:overflow-y-auto clcosdk:rounded-2xl clcosdk:bg-background clcosdk:p-6 clcosdk:pt-14", children: [
13255
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
13256
- CloseButton,
12857
+ className: cn("clcosdk:flex clcosdk:flex-col clcosdk:gap-2", className),
12858
+ children: [
12859
+ status === "loading" ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(AlertBanner, { variant: "info", content: "Loading your connected wallets\u2026" }) : status === "error" ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
12860
+ AlertBanner,
13257
12861
  {
13258
- onClick: onClose,
13259
- className: "clcosdk:absolute clcosdk:top-4 clcosdk:right-4"
12862
+ variant: "error",
12863
+ content: "Couldn't load your connected wallets."
13260
12864
  }
13261
- ),
13262
- children
13263
- ] })
12865
+ ) : wallets.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(AlertBanner, { variant: "info", content: "No wallets connected yet." }) : /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:divide-y clcosdk:divide-divider", children: wallets.map((wallet) => /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
12866
+ ConnectedWalletRow,
12867
+ {
12868
+ wallet,
12869
+ onRemove
12870
+ },
12871
+ wallet.id
12872
+ )) }),
12873
+ onAdd != null && status !== "loading" && /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
12874
+ ClButton,
12875
+ {
12876
+ size: "sm",
12877
+ variant: "secondary",
12878
+ onClick: onAdd,
12879
+ className: "clcosdk:self-start",
12880
+ children: addLabel
12881
+ }
12882
+ )
12883
+ ]
13264
12884
  }
13265
12885
  );
13266
12886
  }
13267
12887
 
13268
12888
  // src/client/components/requirements/identity-verification/IdentityVerificationView.tsx
13269
12889
  var import_websdk_react = __toESM(require("@sumsub/websdk-react"), 1);
13270
- var import_jsx_runtime61 = require("react/jsx-runtime");
12890
+ var import_jsx_runtime57 = require("react/jsx-runtime");
13271
12891
  function IdentityVerificationView(props) {
13272
- return /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(CoinListStyleScope, { children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(IdentityVerificationViewBody, { ...props }) });
12892
+ return /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(CoinListStyleScope, { children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(IdentityVerificationViewBody, { ...props }) });
13273
12893
  }
13274
12894
  function IdentityVerificationViewBody({
13275
12895
  state,
@@ -13278,7 +12898,7 @@ function IdentityVerificationViewBody({
13278
12898
  }) {
13279
12899
  switch (state.type) {
13280
12900
  case "loading":
13281
- return /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
12901
+ return /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
13282
12902
  "output",
13283
12903
  {
13284
12904
  "aria-live": "polite",
@@ -13286,11 +12906,11 @@ function IdentityVerificationViewBody({
13286
12906
  "clcosdk:flex clcosdk:min-h-40 clcosdk:items-center clcosdk:justify-center",
13287
12907
  className
13288
12908
  ),
13289
- children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("p", { className: cn(typeClasses.body, "clcosdk:text-text-secondary"), children: "Loading identity verification..." })
12909
+ children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("p", { className: cn(typeClasses.body, "clcosdk:text-text-secondary"), children: "Loading identity verification..." })
13290
12910
  }
13291
12911
  );
13292
12912
  case "error":
13293
- return /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)(
12913
+ return /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(
13294
12914
  "div",
13295
12915
  {
13296
12916
  className: cn(
@@ -13298,13 +12918,13 @@ function IdentityVerificationViewBody({
13298
12918
  className
13299
12919
  ),
13300
12920
  children: [
13301
- /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(AlertBanner, { variant: "error", icon: true, content: state.message }),
13302
- state.retryable && /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(ClButton, { size: "sm", onClick: () => onEvent({ type: "ON_RETRY" }), children: "Try again" })
12921
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(AlertBanner, { variant: "error", icon: true, content: state.message }),
12922
+ state.retryable && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(ClButton, { size: "sm", onClick: () => onEvent({ type: "ON_RETRY" }), children: "Try again" })
13303
12923
  ]
13304
12924
  }
13305
12925
  );
13306
12926
  case "ready":
13307
- return /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { className: cn("clcosdk:w-full", className), children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
12927
+ return /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("div", { className: cn("clcosdk:w-full", className), children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
13308
12928
  import_websdk_react.default,
13309
12929
  {
13310
12930
  accessToken: state.accessToken,
@@ -13454,35 +13074,384 @@ function useIdentityVerificationViewModel(options = {}) {
13454
13074
  return { state, onEvent };
13455
13075
  }
13456
13076
 
13457
- // src/client/components/requirements/identity-verification/IdentityVerificationContainer.tsx
13458
- var import_jsx_runtime62 = require("react/jsx-runtime");
13459
- function IdentityVerificationContainer({
13460
- levelName,
13461
- reset,
13462
- locale,
13463
- onSubmitted,
13464
- onError,
13077
+ // src/client/components/requirements/identity-verification/IdentityVerificationContainer.tsx
13078
+ var import_jsx_runtime58 = require("react/jsx-runtime");
13079
+ function IdentityVerificationContainer({
13080
+ levelName,
13081
+ reset,
13082
+ locale,
13083
+ onSubmitted,
13084
+ onError,
13085
+ className
13086
+ }) {
13087
+ const { state, onEvent } = useIdentityVerificationViewModel({
13088
+ levelName,
13089
+ reset,
13090
+ locale,
13091
+ onSubmitted,
13092
+ onError
13093
+ });
13094
+ return /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
13095
+ IdentityVerificationView,
13096
+ {
13097
+ state,
13098
+ onEvent,
13099
+ className
13100
+ }
13101
+ );
13102
+ }
13103
+
13104
+ // src/client/components/requirements/RequirementItem.tsx
13105
+ var import_lucide_react15 = require("lucide-react");
13106
+
13107
+ // src/client/components/design-system/StepStatusIcon.tsx
13108
+ var import_lucide_react14 = require("lucide-react");
13109
+ var import_jsx_runtime59 = require("react/jsx-runtime");
13110
+ var statusConfig = {
13111
+ required: {
13112
+ Icon: import_lucide_react14.Info,
13113
+ colorClass: "clcosdk:text-warning",
13114
+ fillClass: "clcosdk:[&_circle]:fill-warning-subtle"
13115
+ },
13116
+ pending: {
13117
+ Icon: import_lucide_react14.Info,
13118
+ colorClass: "clcosdk:text-warning",
13119
+ fillClass: "clcosdk:[&_circle]:fill-warning-subtle"
13120
+ },
13121
+ completed: {
13122
+ Icon: import_lucide_react14.CircleCheck,
13123
+ colorClass: "clcosdk:text-success",
13124
+ fillClass: "clcosdk:[&_circle]:fill-success-subtle"
13125
+ },
13126
+ rejected: {
13127
+ Icon: import_lucide_react14.CircleX,
13128
+ colorClass: "clcosdk:text-error",
13129
+ fillClass: "clcosdk:[&_circle]:fill-error-subtle"
13130
+ }
13131
+ };
13132
+ function StepStatusIcon({ status, className }) {
13133
+ const { Icon, colorClass, fillClass } = statusConfig[status];
13134
+ return /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
13135
+ Icon,
13136
+ {
13137
+ className: cn(
13138
+ "clcosdk:h-6 clcosdk:w-6 clcosdk:shrink-0",
13139
+ colorClass,
13140
+ fillClass,
13141
+ className
13142
+ ),
13143
+ "aria-hidden": "true"
13144
+ }
13145
+ );
13146
+ }
13147
+
13148
+ // src/client/components/requirements/RequirementItem.tsx
13149
+ var import_jsx_runtime60 = require("react/jsx-runtime");
13150
+ function VerificationActionZone({
13151
+ status,
13152
+ onAction,
13153
+ onContactSupport
13154
+ }) {
13155
+ switch (status) {
13156
+ case "required":
13157
+ if (onAction === null) return null;
13158
+ return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(ClButton, { size: "sm", onClick: onAction, children: "Continue" });
13159
+ case "pending":
13160
+ return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
13161
+ AlertBanner,
13162
+ {
13163
+ variant: "warning",
13164
+ content: "Under review. We'll notify you when complete."
13165
+ }
13166
+ );
13167
+ case "completed":
13168
+ return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(AlertBanner, { variant: "success", content: "Identity verified." });
13169
+ case "rejected":
13170
+ return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
13171
+ AlertBanner,
13172
+ {
13173
+ variant: "error",
13174
+ content: onContactSupport === null ? "Verification rejected." : /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)(import_jsx_runtime60.Fragment, { children: [
13175
+ "Verification rejected.",
13176
+ " ",
13177
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
13178
+ "button",
13179
+ {
13180
+ type: "button",
13181
+ onClick: onContactSupport,
13182
+ className: "clcosdk:underline",
13183
+ children: "Contact support"
13184
+ }
13185
+ ),
13186
+ "."
13187
+ ] })
13188
+ }
13189
+ );
13190
+ }
13191
+ }
13192
+ function WalletActionZone({
13193
+ status,
13194
+ multiWallet,
13195
+ connectedWallets,
13196
+ walletsStatus,
13197
+ onAction,
13198
+ onRemoveWallet
13199
+ }) {
13200
+ if (multiWallet) {
13201
+ return /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)(import_jsx_runtime60.Fragment, { children: [
13202
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
13203
+ ConnectedWalletList,
13204
+ {
13205
+ wallets: connectedWallets,
13206
+ onRemove: onRemoveWallet,
13207
+ onAdd: onAction ?? void 0,
13208
+ status: walletsStatus
13209
+ }
13210
+ ),
13211
+ status === "rejected" && /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
13212
+ AlertBanner,
13213
+ {
13214
+ variant: "error",
13215
+ content: "One of these wallets is not eligible for this sale."
13216
+ }
13217
+ )
13218
+ ] });
13219
+ }
13220
+ if (status === "completed") {
13221
+ const connected = connectedWallets[0];
13222
+ return /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)(import_jsx_runtime60.Fragment, { children: [
13223
+ onAction !== null && /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(ClButton, { size: "sm", variant: "secondary", onClick: onAction, children: "Change wallet" }),
13224
+ walletsStatus === "loading" ? /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
13225
+ AlertBanner,
13226
+ {
13227
+ variant: "info",
13228
+ content: "Loading your connected wallet\u2026"
13229
+ }
13230
+ ) : walletsStatus === "error" ? /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
13231
+ AlertBanner,
13232
+ {
13233
+ variant: "error",
13234
+ content: "Couldn't load your connected wallet."
13235
+ }
13236
+ ) : /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
13237
+ AlertBanner,
13238
+ {
13239
+ variant: "success",
13240
+ content: connected ? connected.shortAddress : "Wallet connected."
13241
+ }
13242
+ )
13243
+ ] });
13244
+ }
13245
+ if (status === "rejected") {
13246
+ return /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)(import_jsx_runtime60.Fragment, { children: [
13247
+ onAction !== null && /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(ClButton, { size: "sm", onClick: onAction, children: "Connect wallet" }),
13248
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
13249
+ AlertBanner,
13250
+ {
13251
+ variant: "error",
13252
+ content: "This wallet is not eligible for this sale."
13253
+ }
13254
+ )
13255
+ ] });
13256
+ }
13257
+ if (onAction === null) return null;
13258
+ return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(ClButton, { size: "sm", onClick: onAction, children: "Connect wallet" });
13259
+ }
13260
+ function RequirementItem({
13261
+ ui,
13262
+ expanded = false,
13263
+ onToggle,
13264
+ className,
13265
+ onAction,
13266
+ onRemoveWallet,
13267
+ walletsStatus,
13268
+ onContactSupport
13269
+ }) {
13270
+ return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(CoinListStyleScope, { children: /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)(
13271
+ "div",
13272
+ {
13273
+ className: cn(
13274
+ "clcosdk:flex clcosdk:w-full clcosdk:flex-col",
13275
+ className
13276
+ ),
13277
+ children: [
13278
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)(
13279
+ "button",
13280
+ {
13281
+ type: "button",
13282
+ onClick: onToggle,
13283
+ "aria-expanded": expanded,
13284
+ className: "clcosdk:flex clcosdk:h-14 clcosdk:w-full clcosdk:cursor-pointer clcosdk:items-center clcosdk:justify-between clcosdk:rounded-2xl clcosdk:px-2 clcosdk:transition-colors clcosdk:hover:bg-surface",
13285
+ children: [
13286
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "clcosdk:flex clcosdk:items-center clcosdk:gap-3", children: [
13287
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(StepStatusIcon, { status: ui.status }),
13288
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
13289
+ "span",
13290
+ {
13291
+ className: cn(
13292
+ typeClasses.body,
13293
+ "clcosdk:whitespace-nowrap clcosdk:font-medium clcosdk:text-text-primary"
13294
+ ),
13295
+ children: ui.label
13296
+ }
13297
+ )
13298
+ ] }),
13299
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
13300
+ import_lucide_react15.ChevronRight,
13301
+ {
13302
+ className: cn(
13303
+ "clcosdk:h-6 clcosdk:w-6 clcosdk:shrink-0 clcosdk:text-text-secondary clcosdk:transition-transform clcosdk:duration-300",
13304
+ expanded && "clcosdk:rotate-90"
13305
+ ),
13306
+ "aria-hidden": "true"
13307
+ }
13308
+ )
13309
+ ]
13310
+ }
13311
+ ),
13312
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
13313
+ "div",
13314
+ {
13315
+ className: cn(
13316
+ "clcosdk:grid clcosdk:transition-[grid-template-rows] clcosdk:duration-300 clcosdk:ease-in-out",
13317
+ expanded ? "clcosdk:grid-rows-[1fr]" : "clcosdk:grid-rows-[0fr]"
13318
+ ),
13319
+ children: /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("div", { className: "clcosdk:min-h-0 clcosdk:overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-4 clcosdk:px-2 clcosdk:pb-4", children: [
13320
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
13321
+ "p",
13322
+ {
13323
+ className: cn(
13324
+ typeClasses.subhead,
13325
+ "clcosdk:text-text-secondary"
13326
+ ),
13327
+ children: ui.description
13328
+ }
13329
+ ),
13330
+ ui.variant === "verification" ? /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
13331
+ VerificationActionZone,
13332
+ {
13333
+ status: ui.status,
13334
+ onAction,
13335
+ onContactSupport
13336
+ }
13337
+ ) : /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
13338
+ WalletActionZone,
13339
+ {
13340
+ status: ui.status,
13341
+ multiWallet: ui.multiWallet,
13342
+ connectedWallets: ui.connectedWallets,
13343
+ walletsStatus,
13344
+ onAction,
13345
+ onRemoveWallet
13346
+ }
13347
+ )
13348
+ ] }) })
13349
+ }
13350
+ )
13351
+ ]
13352
+ }
13353
+ ) });
13354
+ }
13355
+
13356
+ // src/client/components/requirements/RequirementsChecklistView.tsx
13357
+ var import_jsx_runtime61 = require("react/jsx-runtime");
13358
+ function RequirementsChecklistView(props) {
13359
+ return /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(CoinListStyleScope, { children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(RequirementsChecklistViewBody, { ...props }) });
13360
+ }
13361
+ function RequirementsChecklistViewBody({
13362
+ state,
13363
+ onEvent,
13364
+ loading,
13365
+ error,
13366
+ unauthenticatedState,
13465
13367
  className
13466
13368
  }) {
13467
- const { state, onEvent } = useIdentityVerificationViewModel({
13468
- levelName,
13469
- reset,
13470
- locale,
13471
- onSubmitted,
13472
- onError
13473
- });
13474
- return /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
13475
- IdentityVerificationView,
13369
+ switch (state.type) {
13370
+ case "loading":
13371
+ return loading ?? /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(LoadingState2, {});
13372
+ case "not-authenticated":
13373
+ return unauthenticatedState ?? null;
13374
+ case "error":
13375
+ return error ?? /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
13376
+ AlertBanner,
13377
+ {
13378
+ variant: "error",
13379
+ icon: true,
13380
+ content: "Unable to load requirements right now. Please try again.",
13381
+ className: "clcosdk:w-full clcosdk:max-w-[28rem]"
13382
+ }
13383
+ );
13384
+ case "content":
13385
+ return /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)(
13386
+ "div",
13387
+ {
13388
+ className: cn(
13389
+ "clcosdk:flex clcosdk:w-full clcosdk:flex-col clcosdk:gap-4",
13390
+ className
13391
+ ),
13392
+ children: [
13393
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-2", children: [
13394
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("h3", { className: cn(typeClasses.h3, "clcosdk:text-text-primary"), children: state.title }),
13395
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("p", { className: cn(typeClasses.body, "clcosdk:text-text-secondary"), children: state.description })
13396
+ ] }),
13397
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:divide-y clcosdk:divide-divider", children: state.items.map((row) => /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
13398
+ RequirementItem,
13399
+ {
13400
+ ui: row.item,
13401
+ expanded: row.expanded,
13402
+ onToggle: () => onEvent({ type: "ON_TOGGLE_ITEM", requirementId: row.id }),
13403
+ onAction: row.actionEnabled ? () => onEvent({
13404
+ type: "ON_REQUIREMENT_ACTION",
13405
+ requirementId: row.id
13406
+ }) : null,
13407
+ onRemoveWallet: row.wallets ? (id) => state.removeWallet(id) : void 0,
13408
+ walletsStatus: row.wallets?.status,
13409
+ onContactSupport: row.contactSupportEnabled ? () => onEvent({
13410
+ type: "ON_CONTACT_SUPPORT",
13411
+ requirementId: row.id
13412
+ }) : null
13413
+ },
13414
+ row.id
13415
+ )) }),
13416
+ state.ineligible && /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
13417
+ AlertBanner,
13418
+ {
13419
+ variant: "error",
13420
+ icon: true,
13421
+ content: "You are not eligible to participate."
13422
+ }
13423
+ ),
13424
+ state.continueAction && /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
13425
+ ClButton,
13426
+ {
13427
+ fullWidth: true,
13428
+ disabled: !state.continueAction.enabled,
13429
+ onClick: () => onEvent({ type: "ON_CONTINUE" }),
13430
+ children: "Continue"
13431
+ }
13432
+ )
13433
+ ]
13434
+ }
13435
+ );
13436
+ default: {
13437
+ const exhaustive = state;
13438
+ return exhaustive;
13439
+ }
13440
+ }
13441
+ }
13442
+ function LoadingState2() {
13443
+ return /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
13444
+ "output",
13476
13445
  {
13477
- state,
13478
- onEvent,
13479
- className
13446
+ "aria-live": "polite",
13447
+ className: "clcosdk:flex clcosdk:min-h-40 clcosdk:items-center clcosdk:justify-center clcosdk:rounded-2xl clcosdk:border clcosdk:border-border clcosdk:bg-background clcosdk:p-6",
13448
+ children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("p", { className: cn(typeClasses.body, "clcosdk:text-text-secondary"), children: "Loading requirements..." })
13480
13449
  }
13481
13450
  );
13482
13451
  }
13483
13452
 
13484
13453
  // src/client/components/requirements/tax-document/TaxDocumentModalView.tsx
13485
- var import_jsx_runtime63 = require("react/jsx-runtime");
13454
+ var import_jsx_runtime62 = require("react/jsx-runtime");
13486
13455
  function TaxDocumentModalView({
13487
13456
  state,
13488
13457
  onEvent,
@@ -13491,7 +13460,7 @@ function TaxDocumentModalView({
13491
13460
  if (state.type === "hidden") {
13492
13461
  return null;
13493
13462
  }
13494
- return /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(CoinListStyleScope, { children: /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("div", { className: "clcosdk:fixed clcosdk:inset-0 clcosdk:z-50 clcosdk:flex clcosdk:items-center clcosdk:justify-center clcosdk:bg-black/50 clcosdk:p-4", children: /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(
13463
+ return /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(CoinListStyleScope, { children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("div", { className: "clcosdk:fixed clcosdk:inset-0 clcosdk:z-50 clcosdk:flex clcosdk:items-center clcosdk:justify-center clcosdk:bg-black/50 clcosdk:p-4", children: /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)(
13495
13464
  "div",
13496
13465
  {
13497
13466
  className: cn(
@@ -13499,11 +13468,11 @@ function TaxDocumentModalView({
13499
13468
  className
13500
13469
  ),
13501
13470
  children: [
13502
- /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: "clcosdk:flex clcosdk:items-start clcosdk:justify-between clcosdk:gap-4", children: [
13503
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("h3", { className: cn(typeClasses.h3, "clcosdk:text-text-primary"), children: state.title }),
13504
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(CloseButton, { onClick: () => onEvent({ type: "ON_CLOSE" }) })
13471
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: "clcosdk:flex clcosdk:items-start clcosdk:justify-between clcosdk:gap-4", children: [
13472
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("h3", { className: cn(typeClasses.h3, "clcosdk:text-text-primary"), children: state.title }),
13473
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(CloseButton, { onClick: () => onEvent({ type: "ON_CLOSE" }) })
13505
13474
  ] }),
13506
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(Screen, { screen: state.screen, onEvent })
13475
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(Screen, { screen: state.screen, onEvent })
13507
13476
  ]
13508
13477
  }
13509
13478
  ) }) });
@@ -13514,11 +13483,11 @@ function Screen({
13514
13483
  }) {
13515
13484
  switch (screen.type) {
13516
13485
  case "loading":
13517
- return /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(LoadingScreen, {});
13486
+ return /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(LoadingScreen, {});
13518
13487
  case "error":
13519
- return /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(AlertBanner, { variant: "error", icon: true, content: screen.message });
13488
+ return /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(AlertBanner, { variant: "error", icon: true, content: screen.message });
13520
13489
  case "review":
13521
- return /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
13490
+ return /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
13522
13491
  ReviewScreen,
13523
13492
  {
13524
13493
  fields: screen.fields,
@@ -13529,9 +13498,9 @@ function Screen({
13529
13498
  }
13530
13499
  );
13531
13500
  case "editing":
13532
- return /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(EditScreen, { fields: screen.fields, onEvent });
13501
+ return /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(EditScreen, { fields: screen.fields, onEvent });
13533
13502
  case "sign-only":
13534
- return /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
13503
+ return /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
13535
13504
  SignOnlyScreen,
13536
13505
  {
13537
13506
  signing: screen.signing,
@@ -13546,14 +13515,14 @@ function Screen({
13546
13515
  }
13547
13516
  }
13548
13517
  function LoadingScreen() {
13549
- return /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
13518
+ return /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
13550
13519
  "output",
13551
13520
  {
13552
13521
  "aria-live": "polite",
13553
13522
  className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-4",
13554
- children: [0, 1, 2, 3, 4].map((row) => /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-1", children: [
13555
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("div", { className: "clcosdk:h-3 clcosdk:w-28 clcosdk:animate-pulse clcosdk:rounded clcosdk:bg-surface" }),
13556
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("div", { className: "clcosdk:h-5 clcosdk:w-48 clcosdk:animate-pulse clcosdk:rounded clcosdk:bg-surface" })
13523
+ children: [0, 1, 2, 3, 4].map((row) => /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-1", children: [
13524
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("div", { className: "clcosdk:h-3 clcosdk:w-28 clcosdk:animate-pulse clcosdk:rounded clcosdk:bg-surface" }),
13525
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("div", { className: "clcosdk:h-5 clcosdk:w-48 clcosdk:animate-pulse clcosdk:rounded clcosdk:bg-surface" })
13557
13526
  ] }, row))
13558
13527
  }
13559
13528
  );
@@ -13565,9 +13534,9 @@ function ReviewScreen({
13565
13534
  signError,
13566
13535
  onEvent
13567
13536
  }) {
13568
- return /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-6", children: [
13569
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("p", { className: cn(typeClasses.body, "clcosdk:text-text-secondary"), children: "Review your information below. If anything looks incorrect, edit before signing." }),
13570
- piiUnavailable && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
13537
+ return /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-6", children: [
13538
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("p", { className: cn(typeClasses.body, "clcosdk:text-text-secondary"), children: "Review your information below. If anything looks incorrect, edit before signing." }),
13539
+ piiUnavailable && /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
13571
13540
  AlertBanner,
13572
13541
  {
13573
13542
  variant: "info",
@@ -13575,27 +13544,27 @@ function ReviewScreen({
13575
13544
  content: "We don't have this information on file yet \u2014 please fill it in below."
13576
13545
  }
13577
13546
  ),
13578
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-4 clcosdk:border-t clcosdk:border-divider clcosdk:pt-4", children: fields.map(({ field, label, displayValue }) => /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(
13547
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-4 clcosdk:border-t clcosdk:border-divider clcosdk:pt-4", children: fields.map(({ field, label, displayValue }) => /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)(
13579
13548
  "div",
13580
13549
  {
13581
13550
  className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-1",
13582
13551
  children: [
13583
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
13552
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
13584
13553
  "span",
13585
13554
  {
13586
13555
  className: cn(typeClasses.label, "clcosdk:text-text-secondary"),
13587
13556
  children: label
13588
13557
  }
13589
13558
  ),
13590
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("span", { className: cn(typeClasses.body, "clcosdk:text-text-primary"), children: displayValue })
13559
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("span", { className: cn(typeClasses.body, "clcosdk:text-text-primary"), children: displayValue })
13591
13560
  ]
13592
13561
  },
13593
13562
  field
13594
13563
  )) }),
13595
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("p", { className: cn(typeClasses.caption, "clcosdk:text-text-secondary"), children: "By signing, you certify that the information above is accurate and that you are the beneficial owner of the income this form relates to. This document cannot be edited once signed." }),
13596
- signError && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(AlertBanner, { variant: "error", icon: true, content: signError }),
13597
- /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-2", children: [
13598
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
13564
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("p", { className: cn(typeClasses.caption, "clcosdk:text-text-secondary"), children: "By signing, you certify that the information above is accurate and that you are the beneficial owner of the income this form relates to. This document cannot be edited once signed." }),
13565
+ signError && /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(AlertBanner, { variant: "error", icon: true, content: signError }),
13566
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-2", children: [
13567
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
13599
13568
  ClButton,
13600
13569
  {
13601
13570
  fullWidth: true,
@@ -13605,7 +13574,7 @@ function ReviewScreen({
13605
13574
  children: "Sign W-8BEN"
13606
13575
  }
13607
13576
  ),
13608
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
13577
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
13609
13578
  ClButton,
13610
13579
  {
13611
13580
  fullWidth: true,
@@ -13622,20 +13591,20 @@ function EditScreen({
13622
13591
  fields,
13623
13592
  onEvent
13624
13593
  }) {
13625
- return /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-6", children: [
13626
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-4 clcosdk:border-t clcosdk:border-divider clcosdk:pt-4", children: fields.map(({ field, label, placeholder, value }) => /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(
13594
+ return /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-6", children: [
13595
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-4 clcosdk:border-t clcosdk:border-divider clcosdk:pt-4", children: fields.map(({ field, label, placeholder, value }) => /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)(
13627
13596
  "label",
13628
13597
  {
13629
13598
  className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-1",
13630
13599
  children: [
13631
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
13600
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
13632
13601
  "span",
13633
13602
  {
13634
13603
  className: cn(typeClasses.label, "clcosdk:text-text-secondary"),
13635
13604
  children: label
13636
13605
  }
13637
13606
  ),
13638
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
13607
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
13639
13608
  "input",
13640
13609
  {
13641
13610
  type: "text",
@@ -13656,9 +13625,9 @@ function EditScreen({
13656
13625
  },
13657
13626
  field
13658
13627
  )) }),
13659
- /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-2", children: [
13660
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(ClButton, { fullWidth: true, onClick: () => onEvent({ type: "ON_SAVE_EDIT" }), children: "Save & review" }),
13661
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
13628
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-2", children: [
13629
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(ClButton, { fullWidth: true, onClick: () => onEvent({ type: "ON_SAVE_EDIT" }), children: "Save & review" }),
13630
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
13662
13631
  ClButton,
13663
13632
  {
13664
13633
  fullWidth: true,
@@ -13675,10 +13644,10 @@ function SignOnlyScreen({
13675
13644
  signError,
13676
13645
  onEvent
13677
13646
  }) {
13678
- return /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-6", children: [
13679
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("p", { className: cn(typeClasses.body, "clcosdk:text-text-secondary"), children: "As an entity investor, you must complete a W-8BEN-E to confirm your foreign tax status and claim applicable treaty benefits. You'll receive an email to complete the signing." }),
13680
- signError && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(AlertBanner, { variant: "error", icon: true, content: signError }),
13681
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
13647
+ return /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-6", children: [
13648
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("p", { className: cn(typeClasses.body, "clcosdk:text-text-secondary"), children: "As an entity investor, you must complete a W-8BEN-E to confirm your foreign tax status and claim applicable treaty benefits. You'll receive an email to complete the signing." }),
13649
+ signError && /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(AlertBanner, { variant: "error", icon: true, content: signError }),
13650
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
13682
13651
  ClButton,
13683
13652
  {
13684
13653
  fullWidth: true,
@@ -13990,7 +13959,7 @@ function toFieldsUi(fields) {
13990
13959
  }
13991
13960
 
13992
13961
  // src/client/components/requirements/tax-document/TaxDocumentModalContainer.tsx
13993
- var import_jsx_runtime64 = require("react/jsx-runtime");
13962
+ var import_jsx_runtime63 = require("react/jsx-runtime");
13994
13963
  function TaxDocumentModalContainer({
13995
13964
  isOpen,
13996
13965
  onClose,
@@ -14002,7 +13971,7 @@ function TaxDocumentModalContainer({
14002
13971
  onClose,
14003
13972
  onSubmitted
14004
13973
  });
14005
- return /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
13974
+ return /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
14006
13975
  TaxDocumentModalView,
14007
13976
  {
14008
13977
  state,
@@ -14012,6 +13981,39 @@ function TaxDocumentModalContainer({
14012
13981
  );
14013
13982
  }
14014
13983
 
13984
+ // src/client/components/requirements/VerificationOverlay.tsx
13985
+ var import_jsx_runtime64 = require("react/jsx-runtime");
13986
+ function VerificationOverlay({
13987
+ onClose,
13988
+ children
13989
+ }) {
13990
+ return /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(CoinListStyleScope, { children: /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(VerificationOverlayBody, { onClose, children }) });
13991
+ }
13992
+ function VerificationOverlayBody({
13993
+ onClose,
13994
+ children
13995
+ }) {
13996
+ return /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
13997
+ "div",
13998
+ {
13999
+ role: "dialog",
14000
+ "aria-modal": "true",
14001
+ "aria-label": "Identity verification",
14002
+ className: "clcosdk:fixed clcosdk:inset-0 clcosdk:z-50 clcosdk:flex clcosdk:items-center clcosdk:justify-center clcosdk:bg-overlay clcosdk:p-4",
14003
+ children: /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("div", { className: "clcosdk:relative clcosdk:flex clcosdk:max-h-[92vh] clcosdk:w-full clcosdk:max-w-[760px] clcosdk:flex-col clcosdk:overflow-y-auto clcosdk:rounded-2xl clcosdk:bg-background clcosdk:p-6 clcosdk:pt-14", children: [
14004
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
14005
+ CloseButton,
14006
+ {
14007
+ onClick: onClose,
14008
+ className: "clcosdk:absolute clcosdk:top-4 clcosdk:right-4"
14009
+ }
14010
+ ),
14011
+ children
14012
+ ] })
14013
+ }
14014
+ );
14015
+ }
14016
+
14015
14017
  // src/client/components/requirements/wallet/ConnectWalletModalView.tsx
14016
14018
  var import_react43 = require("react");
14017
14019
  var import_jsx_runtime65 = require("react/jsx-runtime");
@@ -14407,60 +14409,9 @@ function ConnectWalletModalContainer({
14407
14409
  );
14408
14410
  }
14409
14411
 
14410
- // src/client/hooks/requirements/checklist/useRequirementsChecklistViewModel.ts
14412
+ // src/client/hooks/requirements/useRequirementsChecklistViewModel.ts
14411
14413
  var import_react48 = require("react");
14412
14414
 
14413
- // src/client/hooks/requirements/checklist/useRequirementsChecklistViewModel.types.ts
14414
- var RequirementItemUi = {
14415
- fromDomain(req, statusInfo, label, description2, addresses = []) {
14416
- return {
14417
- variant: RequirementVariant.fromType(req.type),
14418
- status: statusInfo ? RequirementStatus.fromStatusValue(statusInfo.status) : "required",
14419
- label,
14420
- description: description2,
14421
- multiWallet: req.type === "whitelisted_wallet",
14422
- connectedWallets: addresses.map((address) => ({
14423
- id: address.id,
14424
- address: address.address,
14425
- shortAddress: shortenAddress(address.address)
14426
- }))
14427
- };
14428
- }
14429
- };
14430
- var RequirementVariant = {
14431
- fromType(type) {
14432
- switch (type) {
14433
- case "external_wallet":
14434
- case "whitelisted_wallet":
14435
- return "wallet";
14436
- default:
14437
- return "verification";
14438
- }
14439
- }
14440
- };
14441
- var RequirementStatus = {
14442
- fromStatusValue(status) {
14443
- switch (status) {
14444
- case "not_started":
14445
- case "action_needed":
14446
- return "required";
14447
- case "in_progress":
14448
- return "pending";
14449
- case "completed":
14450
- return "completed";
14451
- case "rejected":
14452
- return "rejected";
14453
- }
14454
- }
14455
- };
14456
- var ChecklistStatus = {
14457
- derive(statuses) {
14458
- if (statuses.some((s) => s.status === "rejected")) return "ineligible";
14459
- if (statuses.every((s) => s.status === "completed")) return "eligible";
14460
- return "inProgress";
14461
- }
14462
- };
14463
-
14464
14415
  // src/client/hooks/requirements/data/useOptionAddresses.ts
14465
14416
  var import_react46 = require("react");
14466
14417
  var LOADING_STATE6 = { type: "LOADING" };
@@ -14609,7 +14560,58 @@ function useRequirements(offerId, options = {}) {
14609
14560
  return { requirementsState, refetch };
14610
14561
  }
14611
14562
 
14612
- // src/client/hooks/requirements/checklist/useRequirementsChecklistViewModel.ts
14563
+ // src/client/hooks/requirements/useRequirementsChecklistViewModel.types.ts
14564
+ var RequirementItemUi = {
14565
+ fromDomain(req, statusInfo, label, description2, addresses = []) {
14566
+ return {
14567
+ variant: RequirementVariant.fromType(req.type),
14568
+ status: statusInfo ? RequirementStatus.fromStatusValue(statusInfo.status) : "required",
14569
+ label,
14570
+ description: description2,
14571
+ multiWallet: req.type === "whitelisted_wallet",
14572
+ connectedWallets: addresses.map((address) => ({
14573
+ id: address.id,
14574
+ address: address.address,
14575
+ shortAddress: shortenAddress(address.address)
14576
+ }))
14577
+ };
14578
+ }
14579
+ };
14580
+ var RequirementVariant = {
14581
+ fromType(type) {
14582
+ switch (type) {
14583
+ case "external_wallet":
14584
+ case "whitelisted_wallet":
14585
+ return "wallet";
14586
+ default:
14587
+ return "verification";
14588
+ }
14589
+ }
14590
+ };
14591
+ var RequirementStatus = {
14592
+ fromStatusValue(status) {
14593
+ switch (status) {
14594
+ case "not_started":
14595
+ case "action_needed":
14596
+ return "required";
14597
+ case "in_progress":
14598
+ return "pending";
14599
+ case "completed":
14600
+ return "completed";
14601
+ case "rejected":
14602
+ return "rejected";
14603
+ }
14604
+ }
14605
+ };
14606
+ var ChecklistStatus = {
14607
+ derive(statuses) {
14608
+ if (statuses.some((s) => s.status === "rejected")) return "ineligible";
14609
+ if (statuses.every((s) => s.status === "completed")) return "eligible";
14610
+ return "inProgress";
14611
+ }
14612
+ };
14613
+
14614
+ // src/client/hooks/requirements/useRequirementsChecklistViewModel.ts
14613
14615
  var DEFAULT_LABELS = {
14614
14616
  kyc_approved: "KYC Verification",
14615
14617
  external_wallet: "External Wallet",
@@ -14924,7 +14926,7 @@ function toVerificationUi(verifyingRequirementId, statusById, identityVerificati
14924
14926
  };
14925
14927
  }
14926
14928
 
14927
- // src/client/components/requirements/checklist/RequirementsChecklistContainer.tsx
14929
+ // src/client/components/requirements/RequirementsChecklistContainer.tsx
14928
14930
  var import_jsx_runtime67 = require("react/jsx-runtime");
14929
14931
  function RequirementsChecklistContainer({
14930
14932
  loading,
@@ -14990,10 +14992,10 @@ function RequirementsChecklistContainer({
14990
14992
  ] });
14991
14993
  }
14992
14994
 
14993
- // src/client/core/observability/pino-client-logger.ts
14995
+ // src/client/core/shared/observability/pino-client-logger.ts
14994
14996
  var import_pino = require("pino");
14995
14997
 
14996
- // src/shared/core/observability/pino-logger.ts
14998
+ // src/universal/core/shared/observability/pino-logger.ts
14997
14999
  function toPinoRecord(event) {
14998
15000
  try {
14999
15001
  const record = {};
@@ -15119,7 +15121,7 @@ function reportRenderFailure(sink, error) {
15119
15121
  }
15120
15122
  }
15121
15123
 
15122
- // src/client/core/observability/pino-client-logger.ts
15124
+ // src/client/core/shared/observability/pino-client-logger.ts
15123
15125
  function pinoClientLogger(options) {
15124
15126
  return loggerOverPino(
15125
15127
  // `name` as a child binding rather than pino's `name` option: the option