@coinlist-co/react 0.5.1 → 0.9.0

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 (40) hide show
  1. package/dist/{chunk-5E3P7AMH.js → chunk-AAER5LOL.js} +3 -1
  2. package/dist/chunk-AAER5LOL.js.map +1 -0
  3. package/dist/chunk-I5YTJ5SL.js +644 -0
  4. package/dist/chunk-I5YTJ5SL.js.map +1 -0
  5. package/dist/{chunk-N3WBC2VS.js → chunk-MKCOK3DF.js} +68 -57
  6. package/dist/chunk-MKCOK3DF.js.map +1 -0
  7. package/dist/chunk-Z2HAA2TI.js +768 -0
  8. package/dist/chunk-Z2HAA2TI.js.map +1 -0
  9. package/dist/client/index.cjs +3360 -556
  10. package/dist/client/index.cjs.map +1 -1
  11. package/dist/client/index.d.cts +921 -18
  12. package/dist/client/index.d.ts +921 -18
  13. package/dist/client/index.js +2275 -392
  14. package/dist/client/index.js.map +1 -1
  15. package/dist/collections-B84Vw55t.d.cts +28 -0
  16. package/dist/collections-BQbFJS3g.d.ts +28 -0
  17. package/dist/requirement-C2w45Q11.d.cts +969 -0
  18. package/dist/requirement-C2w45Q11.d.ts +969 -0
  19. package/dist/server/index.cjs +521 -37
  20. package/dist/server/index.cjs.map +1 -1
  21. package/dist/server/index.d.cts +116 -9
  22. package/dist/server/index.d.ts +116 -9
  23. package/dist/server/index.js +95 -28
  24. package/dist/server/index.js.map +1 -1
  25. package/dist/shared/index.cjs +1264 -42
  26. package/dist/shared/index.cjs.map +1 -1
  27. package/dist/shared/index.d.cts +644 -3
  28. package/dist/shared/index.d.ts +644 -3
  29. package/dist/shared/index.js +220 -5
  30. package/dist/shared/index.js.map +1 -1
  31. package/package.json +33 -30
  32. package/dist/chunk-5E3P7AMH.js.map +0 -1
  33. package/dist/chunk-CRACFEJ4.js +0 -17
  34. package/dist/chunk-CRACFEJ4.js.map +0 -1
  35. package/dist/chunk-N3WBC2VS.js.map +0 -1
  36. package/dist/chunk-V6WO67RO.js +0 -311
  37. package/dist/chunk-V6WO67RO.js.map +0 -1
  38. package/dist/client/styles.css +0 -2
  39. package/dist/requirement-BEO42QOr.d.cts +0 -387
  40. package/dist/requirement-BEO42QOr.d.ts +0 -387
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,16 +17,31 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // src/client/index.ts
21
31
  var client_exports = {};
22
32
  __export(client_exports, {
23
33
  ChecklistStatus: () => ChecklistStatus,
34
+ ClientSwapNamespaceImpl: () => ClientSwapNamespaceImpl,
24
35
  CoinListClientInitializationError: () => CoinListClientInitializationError,
25
36
  CoinListContext: () => CoinListContext,
37
+ CoinListContextProvider: () => CoinListContextProvider,
26
38
  CoinListProvider: () => CoinListProvider,
27
39
  CoinListSignInCard: () => CoinListSignInCard,
40
+ CoinListStyleScope: () => CoinListStyleScope,
41
+ ConnectWalletModal: () => ConnectWalletModal,
42
+ ConnectedWalletList: () => ConnectedWalletList,
43
+ IdentityVerification: () => IdentityVerification,
44
+ KycToken: () => KycToken,
28
45
  OAUTH_CODE_VERIFIER_KEY: () => OAUTH_CODE_VERIFIER_KEY,
29
46
  OAUTH_STATE_KEY: () => OAUTH_STATE_KEY,
30
47
  OfferCard: () => OfferCard,
@@ -35,16 +52,27 @@ __export(client_exports, {
35
52
  RequirementStatus: () => RequirementStatus,
36
53
  RequirementVariant: () => RequirementVariant,
37
54
  RequirementsChecklist: () => RequirementsChecklist,
55
+ TaxDocumentModal: () => TaxDocumentModal,
56
+ authorizeWallet: () => authorizeWallet,
57
+ classifyWalletError: () => classifyWalletError,
58
+ connectExternalWalletFlow: () => connectExternalWalletFlow,
38
59
  createCoinListClient: () => createCoinListClient,
60
+ executeSwap: () => executeSwap,
39
61
  useCoinList: () => useCoinList,
40
62
  useCompleteOAuth: () => useCompleteOAuth,
63
+ useConnectWallet: () => useConnectWallet,
64
+ useKycToken: () => useKycToken,
41
65
  useOfferDetails: () => useOfferDetails,
42
66
  useOffers: () => useOffers,
67
+ useOptionAddresses: () => useOptionAddresses,
43
68
  useParticipations: () => useParticipations,
44
- useRequirements: () => useRequirements
69
+ useRequirements: () => useRequirements,
70
+ useSwapOutputToken: () => useSwapOutputToken,
71
+ useSwapQuote: () => useSwapQuote,
72
+ useSwapTokenBalances: () => useSwapTokenBalances,
73
+ useTaxDocument: () => useTaxDocument
45
74
  });
46
75
  module.exports = __toCommonJS(client_exports);
47
- var import_styles = require("./styles.css");
48
76
 
49
77
  // src/client/CoinListProvider.tsx
50
78
  var import_react = require("react");
@@ -144,6 +172,9 @@ var userAgent = () => ({ userAgent: true });
144
172
  var idempotencyKey = () => ({
145
173
  idempotencyKey: true
146
174
  });
175
+ var clientCredentials = (credentials) => ({
176
+ clientCredentials: credentials
177
+ });
147
178
  var retryAttempt = (attempt) => ({
148
179
  retryAttempt: attempt
149
180
  });
@@ -155,6 +186,7 @@ var needUserAgent = (attrs) => attrs?.userAgent === true;
155
186
  var isIdempotent = (attrs) => attrs?.idempotencyKey === true;
156
187
  var getRetryAttempt = (attrs) => attrs?.retryAttempt ?? 0;
157
188
  var wasRenewAttempted = (attrs) => attrs?.renewAttempted === true;
189
+ var getClientCredentials = (attrs) => attrs?.clientCredentials;
158
190
  var Attributes = {
159
191
  empty,
160
192
  concat,
@@ -168,7 +200,9 @@ var Attributes = {
168
200
  retryAttempt,
169
201
  getRetryAttempt,
170
202
  renewAttempted,
171
- wasRenewAttempted
203
+ wasRenewAttempted,
204
+ clientCredentials,
205
+ getClientCredentials
172
206
  };
173
207
 
174
208
  // src/client/core/api/middleware/user-agent.ts
@@ -368,7 +402,13 @@ function attachSessionMiddleware(fetchAccessToken) {
368
402
  if (!Attributes.isProtected(request.attributes)) {
369
403
  return request;
370
404
  }
371
- const accessToken = await fetchAccessToken(false);
405
+ let accessToken = await fetchAccessToken(false);
406
+ if (!accessToken) {
407
+ const clientCreds = Attributes.getClientCredentials(request.attributes);
408
+ if (clientCreds) {
409
+ accessToken = clientCreds;
410
+ }
411
+ }
372
412
  if (accessToken === null) {
373
413
  return request;
374
414
  }
@@ -497,88 +537,869 @@ var ApiClient = class {
497
537
  }
498
538
  };
499
539
 
500
- // src/shared/api/pagination.ts
501
- var Cursor = (value) => value;
502
- async function fetchAllPages(fetchPage, baseParams) {
503
- const items = [];
504
- let cursor = null;
505
- do {
506
- const params = {
507
- ...baseParams ?? {},
508
- after: cursor ?? void 0
509
- };
510
- const page = await fetchPage(params);
511
- items.push(...page.data);
512
- cursor = page.startingAfter;
513
- } while (cursor);
514
- return items;
540
+ // src/client/core/blockchain/wallet-error.ts
541
+ var import_viem = require("viem");
542
+ function classifyWalletError(error, ctx) {
543
+ if (error instanceof import_viem.UserRejectedRequestError) {
544
+ return { type: "user_rejected" };
545
+ }
546
+ if (error instanceof import_viem.InsufficientFundsError) {
547
+ return { type: "insufficient_funds" };
548
+ }
549
+ if (error instanceof import_viem.ContractFunctionRevertedError) {
550
+ return { type: "contract_reverted", reason: error.reason ?? error.message };
551
+ }
552
+ if (error instanceof import_viem.WaitForTransactionReceiptTimeoutError && ctx?.hash) {
553
+ return { type: "timeout", hash: ctx.hash };
554
+ }
555
+ return { type: "unknown", cause: error };
515
556
  }
516
- var PaginatedResponse = {
517
- fromDto: (dto, itemMapper) => ({
518
- data: dto.data.map(itemMapper),
519
- startingAfter: dto.starting_after ? Cursor(dto.starting_after) : null,
520
- startingBefore: dto.starting_before ? Cursor(dto.starting_before) : null
521
- })
557
+
558
+ // src/shared/core/blockchain/abis/erc20.ts
559
+ var ERC20_ABI = [
560
+ {
561
+ type: "function",
562
+ name: "allowance",
563
+ inputs: [
564
+ { name: "owner", type: "address" },
565
+ { name: "spender", type: "address" }
566
+ ],
567
+ outputs: [{ name: "", type: "uint256" }],
568
+ stateMutability: "view"
569
+ },
570
+ {
571
+ type: "function",
572
+ name: "approve",
573
+ inputs: [
574
+ { name: "spender", type: "address" },
575
+ { name: "amount", type: "uint256" }
576
+ ],
577
+ outputs: [{ name: "", type: "bool" }],
578
+ stateMutability: "nonpayable"
579
+ },
580
+ {
581
+ type: "function",
582
+ name: "balanceOf",
583
+ inputs: [{ name: "account", type: "address" }],
584
+ outputs: [{ name: "", type: "uint256" }],
585
+ stateMutability: "view"
586
+ },
587
+ {
588
+ type: "function",
589
+ name: "decimals",
590
+ inputs: [],
591
+ outputs: [{ name: "", type: "uint8" }],
592
+ stateMutability: "view"
593
+ },
594
+ {
595
+ type: "function",
596
+ name: "name",
597
+ inputs: [],
598
+ outputs: [{ name: "", type: "string" }],
599
+ stateMutability: "view"
600
+ },
601
+ {
602
+ type: "function",
603
+ name: "symbol",
604
+ inputs: [],
605
+ outputs: [{ name: "", type: "string" }],
606
+ stateMutability: "view"
607
+ },
608
+ {
609
+ type: "function",
610
+ name: "totalSupply",
611
+ inputs: [],
612
+ outputs: [{ name: "", type: "uint256" }],
613
+ stateMutability: "view"
614
+ },
615
+ {
616
+ type: "function",
617
+ name: "transfer",
618
+ inputs: [
619
+ { name: "recipient", type: "address" },
620
+ { name: "amount", type: "uint256" }
621
+ ],
622
+ outputs: [{ name: "", type: "bool" }],
623
+ stateMutability: "nonpayable"
624
+ },
625
+ {
626
+ type: "function",
627
+ name: "transferFrom",
628
+ inputs: [
629
+ { name: "sender", type: "address" },
630
+ { name: "recipient", type: "address" },
631
+ { name: "amount", type: "uint256" }
632
+ ],
633
+ outputs: [{ name: "", type: "bool" }],
634
+ stateMutability: "nonpayable"
635
+ },
636
+ {
637
+ type: "event",
638
+ name: "Approval",
639
+ inputs: [
640
+ { name: "owner", type: "address", indexed: true },
641
+ { name: "spender", type: "address", indexed: true },
642
+ { name: "value", type: "uint256", indexed: false }
643
+ ],
644
+ anonymous: false
645
+ },
646
+ {
647
+ type: "event",
648
+ name: "Transfer",
649
+ inputs: [
650
+ { name: "from", type: "address", indexed: true },
651
+ { name: "to", type: "address", indexed: true },
652
+ { name: "value", type: "uint256", indexed: false }
653
+ ],
654
+ anonymous: false
655
+ }
656
+ ];
657
+
658
+ // src/shared/core/blockchain/abis/superstate-swap.ts
659
+ var SUPERSTATE_SWAP_ABI = [
660
+ {
661
+ type: "function",
662
+ name: "authorized",
663
+ inputs: [{ name: "user", type: "address", internalType: "address" }],
664
+ outputs: [{ name: "", type: "bool", internalType: "bool" }],
665
+ stateMutability: "view"
666
+ },
667
+ {
668
+ type: "function",
669
+ name: "stopped",
670
+ inputs: [],
671
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
672
+ stateMutability: "view"
673
+ },
674
+ {
675
+ type: "function",
676
+ name: "SWAP_LEVEL",
677
+ inputs: [],
678
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
679
+ stateMutability: "view"
680
+ },
681
+ {
682
+ type: "function",
683
+ name: "preview",
684
+ inputs: [
685
+ { name: "token", type: "address", internalType: "address" },
686
+ { name: "amount", type: "uint256", internalType: "uint256" }
687
+ ],
688
+ outputs: [
689
+ {
690
+ name: "",
691
+ type: "tuple",
692
+ internalType: "struct Preview",
693
+ components: [
694
+ { name: "input", type: "uint256", internalType: "uint256" },
695
+ { name: "fee", type: "uint256", internalType: "uint256" },
696
+ { name: "output", type: "uint256", internalType: "uint256" }
697
+ ]
698
+ }
699
+ ],
700
+ stateMutability: "view"
701
+ },
702
+ {
703
+ type: "function",
704
+ name: "swap",
705
+ inputs: [
706
+ { name: "token", type: "address", internalType: "address" },
707
+ { name: "amount", type: "uint256", internalType: "uint256" },
708
+ { name: "slip", type: "uint256", internalType: "uint256" }
709
+ ],
710
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
711
+ stateMutability: "nonpayable"
712
+ },
713
+ {
714
+ type: "function",
715
+ name: "tokenBalance",
716
+ inputs: [{ name: "token", type: "address", internalType: "address" }],
717
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
718
+ stateMutability: "view"
719
+ },
720
+ {
721
+ type: "function",
722
+ name: "outputToken",
723
+ inputs: [],
724
+ outputs: [{ name: "", type: "address", internalType: "address" }],
725
+ stateMutability: "view"
726
+ },
727
+ {
728
+ type: "function",
729
+ name: "outputTokenBalance",
730
+ inputs: [],
731
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
732
+ stateMutability: "view"
733
+ },
734
+ {
735
+ type: "function",
736
+ name: "totals",
737
+ inputs: [{ name: "token", type: "address", internalType: "address" }],
738
+ outputs: [
739
+ {
740
+ name: "",
741
+ type: "tuple",
742
+ internalType: "struct SwapTotal",
743
+ components: [
744
+ { name: "inputSum", type: "uint256", internalType: "uint256" },
745
+ { name: "feeSum", type: "uint256", internalType: "uint256" },
746
+ { name: "outputSum", type: "uint256", internalType: "uint256" },
747
+ { name: "count", type: "uint256", internalType: "uint256" }
748
+ ]
749
+ }
750
+ ],
751
+ stateMutability: "view"
752
+ },
753
+ {
754
+ type: "function",
755
+ name: "totals",
756
+ inputs: [
757
+ { name: "user", type: "address", internalType: "address" },
758
+ { name: "token", type: "address", internalType: "address" }
759
+ ],
760
+ outputs: [
761
+ {
762
+ name: "",
763
+ type: "tuple",
764
+ internalType: "struct SwapTotal",
765
+ components: [
766
+ { name: "inputSum", type: "uint256", internalType: "uint256" },
767
+ { name: "feeSum", type: "uint256", internalType: "uint256" },
768
+ { name: "outputSum", type: "uint256", internalType: "uint256" },
769
+ { name: "count", type: "uint256", internalType: "uint256" }
770
+ ]
771
+ }
772
+ ],
773
+ stateMutability: "view"
774
+ },
775
+ {
776
+ type: "function",
777
+ name: "transfer",
778
+ inputs: [
779
+ { name: "to", type: "address", internalType: "address" },
780
+ { name: "amount", type: "uint256", internalType: "uint256" }
781
+ ],
782
+ outputs: [{ name: "", type: "bool", internalType: "bool" }],
783
+ stateMutability: "nonpayable"
784
+ },
785
+ {
786
+ type: "function",
787
+ name: "transfer",
788
+ inputs: [
789
+ { name: "to", type: "address", internalType: "address" },
790
+ { name: "token", type: "address", internalType: "address" },
791
+ { name: "amount", type: "uint256", internalType: "uint256" }
792
+ ],
793
+ outputs: [{ name: "", type: "bool", internalType: "bool" }],
794
+ stateMutability: "nonpayable"
795
+ },
796
+ {
797
+ type: "function",
798
+ name: "setBps",
799
+ inputs: [{ name: "points", type: "uint256", internalType: "uint256" }],
800
+ outputs: [{ name: "", type: "bool", internalType: "bool" }],
801
+ stateMutability: "nonpayable"
802
+ },
803
+ {
804
+ type: "event",
805
+ name: "Swapped",
806
+ inputs: [
807
+ { name: "user", type: "address", indexed: true, internalType: "address" },
808
+ {
809
+ name: "inputToken",
810
+ type: "address",
811
+ indexed: true,
812
+ internalType: "address"
813
+ },
814
+ {
815
+ name: "outputToken",
816
+ type: "address",
817
+ indexed: true,
818
+ internalType: "address"
819
+ },
820
+ {
821
+ name: "inputAmount",
822
+ type: "uint256",
823
+ indexed: false,
824
+ internalType: "uint256"
825
+ },
826
+ {
827
+ name: "outputAmount",
828
+ type: "uint256",
829
+ indexed: false,
830
+ internalType: "uint256"
831
+ }
832
+ ],
833
+ anonymous: false
834
+ },
835
+ {
836
+ type: "event",
837
+ name: "Transferred",
838
+ inputs: [
839
+ { name: "to", type: "address", indexed: true, internalType: "address" },
840
+ {
841
+ name: "token",
842
+ type: "address",
843
+ indexed: true,
844
+ internalType: "address"
845
+ },
846
+ {
847
+ name: "amount",
848
+ type: "uint256",
849
+ indexed: false,
850
+ internalType: "uint256"
851
+ }
852
+ ],
853
+ anonymous: false
854
+ },
855
+ {
856
+ type: "error",
857
+ name: "InvalidAddress",
858
+ inputs: []
859
+ },
860
+ {
861
+ type: "error",
862
+ name: "InsufficientAmount",
863
+ inputs: []
864
+ },
865
+ {
866
+ type: "error",
867
+ name: "InvalidAmount",
868
+ inputs: []
869
+ },
870
+ {
871
+ type: "error",
872
+ name: "SwapFailed",
873
+ inputs: [
874
+ { name: "user", type: "address", internalType: "address" },
875
+ { name: "token", type: "address", internalType: "address" }
876
+ ]
877
+ }
878
+ ];
879
+
880
+ // src/shared/types/blockchain/core.ts
881
+ var EvmWalletAddress = (value) => value;
882
+ var EvmContractAddress = (value) => value;
883
+ var HexEncodedTransactionData = (value) => value;
884
+ var AssetDecimals = (value) => value;
885
+ var MAX_UINT_256 = 2n ** 256n - 1n;
886
+ var assertUint256 = (value) => {
887
+ if (value < 0n || value > MAX_UINT_256) {
888
+ throw new Error(`Value out of uint256 bounds: ${value}`);
889
+ }
890
+ return value;
522
891
  };
523
- var PaginationParams = {
524
- toQueryParams: (params) => {
525
- const queryParams = {};
526
- if (params.after) {
527
- queryParams.starting_after = params.after;
892
+ var BlockchainAmount = Object.assign(
893
+ (value) => value,
894
+ {
895
+ add: (a, b) => combineAmounts(a, b, (x, y) => x + y),
896
+ sub: (a, b) => combineAmounts(a, b, (x, y) => x - y)
897
+ }
898
+ );
899
+ function combineAmounts(a, b, op) {
900
+ if (a.decimals !== b.decimals) {
901
+ throw new Error(
902
+ `Cannot combine BlockchainAmounts with different decimals: ${a.decimals} vs ${b.decimals}`
903
+ );
904
+ }
905
+ const raw = op(a.raw, b.raw);
906
+ if (raw < 0n || raw > MAX_UINT_256) {
907
+ throw new Error(`BlockchainAmount out of uint256 bounds: ${raw}`);
908
+ }
909
+ return BlockchainAmount({ raw, decimals: a.decimals });
910
+ }
911
+ var AssetSymbol = (value) => value;
912
+ var StablecoinSymbol = (value) => value;
913
+ var Bps = (value) => value;
914
+
915
+ // src/shared/core/blockchain/bps.ts
916
+ var BPS_DENOM = Bps(10000n);
917
+ function applyBps(amount, bps) {
918
+ return assertUint256(amount * bps / BPS_DENOM);
919
+ }
920
+
921
+ // src/shared/core/blockchain/swap/math.ts
922
+ function computePrice({
923
+ inputTokenAmount,
924
+ outputTokenAmount
925
+ }) {
926
+ if (outputTokenAmount.raw === 0n) return null;
927
+ const scale = 10n ** BigInt(outputTokenAmount.decimals);
928
+ const raw = assertUint256(
929
+ inputTokenAmount.raw * scale / outputTokenAmount.raw
930
+ );
931
+ return BlockchainAmount({ raw, decimals: inputTokenAmount.decimals });
932
+ }
933
+ function computeSlip(amount, slippage) {
934
+ const retained = Bps(assertUint256(BPS_DENOM - slippage));
935
+ const slipRaw = applyBps(amount.raw, retained);
936
+ return BlockchainAmount({ raw: slipRaw, decimals: amount.decimals });
937
+ }
938
+
939
+ // src/shared/core/blockchain/swap/status.ts
940
+ function isStopped(status) {
941
+ return (status.stopped & status.swapLevel) !== 0n;
942
+ }
943
+
944
+ // src/shared/core/blockchain/swap/swapped-event.ts
945
+ var import_viem2 = require("viem");
946
+ function decodeSwappedOutputAmount(receipt, outputDecimals) {
947
+ try {
948
+ const [swapped] = (0, import_viem2.parseEventLogs)({
949
+ abi: SUPERSTATE_SWAP_ABI,
950
+ eventName: "Swapped",
951
+ logs: receipt.logs
952
+ });
953
+ if (!swapped) return null;
954
+ const raw = swapped.args.outputAmount;
955
+ if (raw < 0n || raw > MAX_UINT_256) return null;
956
+ return BlockchainAmount({ raw, decimals: outputDecimals });
957
+ } catch {
958
+ return null;
959
+ }
960
+ }
961
+
962
+ // src/client/core/blockchain/swap-flows.ts
963
+ async function executeSwap(params) {
964
+ const {
965
+ swap,
966
+ wallet,
967
+ contractAddress,
968
+ chain,
969
+ inputTokenAddress,
970
+ quote,
971
+ slippageBps,
972
+ onProgress
973
+ } = params;
974
+ const emit = (phase) => onProgress?.(phase);
975
+ const inputAmount = BlockchainAmount.add(
976
+ quote.inputTokenAmount,
977
+ quote.fee
978
+ ).raw;
979
+ const minOut = computeSlip(quote.outputTokenAmount, slippageBps).raw;
980
+ emit("checking-status");
981
+ let status;
982
+ try {
983
+ status = await swap.getStatus({ contractAddress, chain });
984
+ } catch {
985
+ return { type: "error", error: { step: "status-check" } };
986
+ }
987
+ if (isStopped(status)) {
988
+ return { type: "error", error: { step: "swap-stopped" } };
989
+ }
990
+ emit("checking-allowance");
991
+ let allowance;
992
+ try {
993
+ allowance = await swap.getTokenAllowance({
994
+ tokenAddress: inputTokenAddress,
995
+ owner: wallet.address,
996
+ spender: contractAddress,
997
+ chain
998
+ });
999
+ } catch {
1000
+ return { type: "error", error: { step: "allowance-check" } };
1001
+ }
1002
+ if (allowance.allowance < inputAmount) {
1003
+ if (allowance.allowance > 0n) {
1004
+ const reset = await submitApproval({
1005
+ wallet,
1006
+ tokenAddress: inputTokenAddress,
1007
+ spender: contractAddress,
1008
+ chain,
1009
+ value: 0n,
1010
+ pending: "resetting-allowance",
1011
+ confirming: "confirming-allowance-reset",
1012
+ emit
1013
+ });
1014
+ if (reset.type === "error") return { type: "error", error: reset.error };
528
1015
  }
529
- if (params.before) {
530
- queryParams.starting_before = params.before;
1016
+ const approve = await submitApproval({
1017
+ wallet,
1018
+ tokenAddress: inputTokenAddress,
1019
+ spender: contractAddress,
1020
+ chain,
1021
+ value: inputAmount,
1022
+ pending: "approving",
1023
+ confirming: "confirming-approval",
1024
+ emit
1025
+ });
1026
+ if (approve.type === "error")
1027
+ return { type: "error", error: approve.error };
1028
+ }
1029
+ emit("swapping");
1030
+ let swapTxHash;
1031
+ try {
1032
+ swapTxHash = await wallet.writeContract({
1033
+ abi: SUPERSTATE_SWAP_ABI,
1034
+ address: contractAddress,
1035
+ functionName: "swap",
1036
+ args: [inputTokenAddress, inputAmount, minOut],
1037
+ chain
1038
+ });
1039
+ } catch (error) {
1040
+ return {
1041
+ type: "error",
1042
+ error: { step: "swap", cause: classifyWalletError(error) }
1043
+ };
1044
+ }
1045
+ emit("confirming-swap");
1046
+ let receipt;
1047
+ try {
1048
+ receipt = await wallet.awaitTx(swapTxHash, chain);
1049
+ } catch (error) {
1050
+ return {
1051
+ type: "error",
1052
+ error: {
1053
+ step: "swap",
1054
+ cause: classifyWalletError(error, { hash: swapTxHash })
1055
+ }
1056
+ };
1057
+ }
1058
+ if (receipt.status !== "success") {
1059
+ return { type: "error", error: { step: "swap-reverted" } };
1060
+ }
1061
+ const outputAmount = decodeSwappedOutputAmount(receipt, quote.outputTokenAmount.decimals) ?? quote.outputTokenAmount;
1062
+ const finalQuote = { ...quote, outputTokenAmount: outputAmount };
1063
+ return {
1064
+ type: "success",
1065
+ swapTxHash,
1066
+ inputAmount: finalQuote.inputTokenAmount,
1067
+ fee: finalQuote.fee,
1068
+ outputAmount,
1069
+ pricePerShare: computePrice(finalQuote),
1070
+ recipientAddress: wallet.address
1071
+ };
1072
+ }
1073
+ async function submitApproval(args) {
1074
+ const {
1075
+ wallet,
1076
+ tokenAddress,
1077
+ spender,
1078
+ chain,
1079
+ value,
1080
+ pending,
1081
+ confirming,
1082
+ emit
1083
+ } = args;
1084
+ emit(pending);
1085
+ let hash;
1086
+ try {
1087
+ hash = await wallet.writeContract({
1088
+ abi: ERC20_ABI,
1089
+ address: tokenAddress,
1090
+ functionName: "approve",
1091
+ args: [spender, value],
1092
+ chain
1093
+ });
1094
+ } catch (error) {
1095
+ return {
1096
+ type: "error",
1097
+ error: { step: "approval", cause: classifyWalletError(error) }
1098
+ };
1099
+ }
1100
+ emit(confirming);
1101
+ let receipt;
1102
+ try {
1103
+ receipt = await wallet.awaitTx(hash, chain);
1104
+ } catch (error) {
1105
+ return {
1106
+ type: "error",
1107
+ error: { step: "approval", cause: classifyWalletError(error, { hash }) }
1108
+ };
1109
+ }
1110
+ if (receipt.status !== "success") {
1111
+ return { type: "error", error: { step: "approval-reverted" } };
1112
+ }
1113
+ return { type: "ok" };
1114
+ }
1115
+ async function authorizeWallet(params) {
1116
+ const { swap, wallet, offerId, contractAddress, chain, onProgress } = params;
1117
+ const emit = (phase) => onProgress?.(phase);
1118
+ const walletAddress = wallet.address;
1119
+ emit("checking-authorization");
1120
+ let auth;
1121
+ try {
1122
+ auth = await swap.getAuthorization({
1123
+ walletAddress,
1124
+ contractAddress,
1125
+ chain
1126
+ });
1127
+ } catch {
1128
+ return { type: "error", error: { step: "authorization-check" } };
1129
+ }
1130
+ if (auth.authorized) return { type: "success" };
1131
+ emit("requesting-challenge");
1132
+ let challenge;
1133
+ try {
1134
+ challenge = await swap.requestWalletOwnershipChallenge({
1135
+ walletAddress,
1136
+ chain,
1137
+ challengeType: "plain"
1138
+ });
1139
+ } catch {
1140
+ return { type: "error", error: { step: "challenge-request" } };
1141
+ }
1142
+ emit("signing-message");
1143
+ let signature;
1144
+ try {
1145
+ signature = await wallet.signMessage(challenge.message);
1146
+ } catch (error) {
1147
+ return {
1148
+ type: "error",
1149
+ error: { step: "signing", cause: classifyWalletError(error) }
1150
+ };
1151
+ }
1152
+ emit("submitting-signature");
1153
+ let allow;
1154
+ try {
1155
+ allow = await swap.allowWallet({
1156
+ offerId,
1157
+ walletAddress,
1158
+ chain,
1159
+ signature
1160
+ });
1161
+ } catch {
1162
+ return { type: "error", error: { step: "allow-wallet" } };
1163
+ }
1164
+ if (allow.action === "broadcast_transaction") {
1165
+ emit("broadcasting-transaction");
1166
+ let hash;
1167
+ try {
1168
+ hash = await wallet.broadcastRawTx({
1169
+ to: allow.to,
1170
+ data: allow.data,
1171
+ chain
1172
+ });
1173
+ } catch (error) {
1174
+ return {
1175
+ type: "error",
1176
+ error: { step: "broadcast", cause: classifyWalletError(error) }
1177
+ };
531
1178
  }
532
- if (params.limit) {
533
- queryParams.limit = params.limit;
1179
+ emit("awaiting-confirmation");
1180
+ try {
1181
+ await wallet.awaitTx(hash, chain);
1182
+ } catch (error) {
1183
+ return {
1184
+ type: "error",
1185
+ error: {
1186
+ step: "broadcast",
1187
+ cause: classifyWalletError(error, { hash })
1188
+ }
1189
+ };
534
1190
  }
535
- return queryParams;
536
1191
  }
537
- };
1192
+ emit("verifying-authorization");
1193
+ let reCheck;
1194
+ try {
1195
+ reCheck = await swap.getAuthorization({
1196
+ walletAddress,
1197
+ contractAddress,
1198
+ chain
1199
+ });
1200
+ } catch {
1201
+ return { type: "error", error: { step: "authorization-check" } };
1202
+ }
1203
+ if (!reCheck.authorized) {
1204
+ return { type: "error", error: { step: "not-authorized" } };
1205
+ }
1206
+ return { type: "success" };
1207
+ }
538
1208
 
539
- // src/shared/types/offer.ts
540
- var OfferId = (value) => value;
541
- var OfferSlug = (value) => value;
542
- var Offer = {
1209
+ // src/shared/types/swap.ts
1210
+ var SwapAuthorization = {
543
1211
  fromDto: (dto) => ({
544
- id: OfferId(dto.id),
545
- slug: OfferSlug(dto.slug),
546
- tagline: notBlankStringOrNull(dto.tagline),
547
- bannerUrl: notBlankStringOrNull(dto.banner_url),
548
- logoUrl: notBlankStringOrNull(dto.logo_url),
549
- startsAt: new Date(dto.starts_at),
550
- endsAt: new Date(dto.ends_at)
1212
+ authorized: dto.authorized
551
1213
  })
552
1214
  };
553
-
554
- // src/shared/types/asset.ts
555
- var AssetId = (value) => value;
556
- var AssetCode = (value) => value;
557
- var Asset = {
1215
+ var SwapPreview = {
558
1216
  fromDto: (dto) => ({
559
- id: AssetId(dto.id),
560
- code: AssetCode(dto.code),
561
- name: dto.name,
562
- fractionalDigits: dto.fractional_digits
1217
+ inputAmount: assertUint256(BigInt(dto.pay_input_amount)),
1218
+ fee: assertUint256(BigInt(dto.fee)),
1219
+ outputAmount: assertUint256(BigInt(dto.receive_output_amount))
563
1220
  })
564
1221
  };
565
-
566
- // src/shared/types/offer-detail.ts
567
- var OfferOptionId = (value) => value;
568
- var OfferOptionSlug = (value) => value;
569
- var OfferDetail = {
1222
+ var SwapStatus = {
1223
+ fromDto: (dto) => ({
1224
+ stopped: assertUint256(BigInt(dto.stopped)),
1225
+ swapLevel: assertUint256(BigInt(dto.swap_level))
1226
+ })
1227
+ };
1228
+ var TokenAllowance = {
1229
+ fromDto: (dto) => ({
1230
+ allowance: assertUint256(BigInt(dto.allowance))
1231
+ })
1232
+ };
1233
+ var TokenBalance = {
1234
+ fromDto: (dto) => ({
1235
+ balance: assertUint256(BigInt(dto.balance))
1236
+ })
1237
+ };
1238
+ var AllowWalletResponse = {
570
1239
  fromDto: (dto) => {
571
- if (!Array.isArray(dto.funding_assets)) {
572
- throw new Error(`funding_assets must be an array`);
573
- }
574
- if (!Array.isArray(dto.options)) {
575
- throw new Error(`options must be an array`);
576
- }
577
- if (!Array.isArray(dto.terms)) {
578
- throw new Error(`terms must be an array`);
579
- }
580
- if (!Array.isArray(dto.links)) {
581
- throw new Error(`links must be an array`);
1240
+ switch (dto.action) {
1241
+ case "broadcast_transaction":
1242
+ return {
1243
+ action: "broadcast_transaction",
1244
+ to: EvmContractAddress(dto.to),
1245
+ data: HexEncodedTransactionData(dto.data)
1246
+ };
1247
+ case "none":
1248
+ return {
1249
+ action: "none",
1250
+ alreadyAllowed: dto.already_allowed
1251
+ };
1252
+ default: {
1253
+ const _exhaustive = dto;
1254
+ return _exhaustive;
1255
+ }
1256
+ }
1257
+ }
1258
+ };
1259
+
1260
+ // src/shared/api/frontline/swap.ts
1261
+ async function getSwapAuthorization(api, params) {
1262
+ const dto = await api.send({
1263
+ method: "GET",
1264
+ url: "/v1/wallet/authorized",
1265
+ queryParams: {
1266
+ chain: params.chain,
1267
+ contract_address: params.contractAddress,
1268
+ wallet_address: params.walletAddress
1269
+ },
1270
+ attributes: Attributes.protected()
1271
+ });
1272
+ return SwapAuthorization.fromDto(dto);
1273
+ }
1274
+ async function getSwapOutputToken(api, params) {
1275
+ const dto = await api.send({
1276
+ method: "GET",
1277
+ url: "/v1/swap/output-token",
1278
+ queryParams: {
1279
+ chain: params.chain,
1280
+ contract_address: params.contractAddress
1281
+ },
1282
+ attributes: Attributes.protected()
1283
+ });
1284
+ return toErc20Asset(dto);
1285
+ }
1286
+ async function getSwapPreview(api, params) {
1287
+ const dto = await api.send({
1288
+ method: "GET",
1289
+ url: "/v1/swap/preview",
1290
+ queryParams: {
1291
+ chain: params.chain,
1292
+ contract_address: params.contractAddress,
1293
+ input_token: params.inputToken,
1294
+ amount: params.amount.toString()
1295
+ },
1296
+ attributes: Attributes.protected()
1297
+ });
1298
+ return SwapPreview.fromDto(dto);
1299
+ }
1300
+ async function getSwapStatus(api, params) {
1301
+ const dto = await api.send({
1302
+ method: "GET",
1303
+ url: "/v1/swap/status",
1304
+ queryParams: {
1305
+ chain: params.chain,
1306
+ contract_address: params.contractAddress
1307
+ },
1308
+ attributes: Attributes.protected()
1309
+ });
1310
+ return SwapStatus.fromDto(dto);
1311
+ }
1312
+ async function getTokenAllowance(api, params) {
1313
+ const dto = await api.send({
1314
+ method: "GET",
1315
+ url: "/v1/token/allowance",
1316
+ queryParams: {
1317
+ chain: params.chain,
1318
+ token_address: params.tokenAddress,
1319
+ owner: params.owner,
1320
+ spender: params.spender
1321
+ },
1322
+ attributes: Attributes.protected()
1323
+ });
1324
+ return TokenAllowance.fromDto(dto);
1325
+ }
1326
+ async function getTokenBalance(api, params) {
1327
+ const dto = await api.send({
1328
+ method: "GET",
1329
+ url: "/v1/token/balance",
1330
+ queryParams: {
1331
+ chain: params.chain,
1332
+ token_address: params.tokenAddress,
1333
+ owner: params.owner
1334
+ },
1335
+ attributes: Attributes.protected()
1336
+ });
1337
+ return TokenBalance.fromDto(dto);
1338
+ }
1339
+ async function allowWallet(api, params) {
1340
+ const dto = await api.send({
1341
+ method: "POST",
1342
+ url: `/v1/offers/${encodeURIComponent(params.offerId)}/allow-wallet`,
1343
+ body: {
1344
+ wallet_address: params.walletAddress,
1345
+ chain: params.chain,
1346
+ signature: params.signature
1347
+ },
1348
+ attributes: Attributes.protected()
1349
+ });
1350
+ return AllowWalletResponse.fromDto(dto);
1351
+ }
1352
+ function toErc20Asset(dto) {
1353
+ return {
1354
+ name: dto.name,
1355
+ symbol: AssetSymbol(dto.symbol),
1356
+ decimals: AssetDecimals(dto.decimals)
1357
+ };
1358
+ }
1359
+
1360
+ // src/shared/types/asset.ts
1361
+ var AssetId = (value) => value;
1362
+ var AssetCode = (value) => value;
1363
+ var Asset = {
1364
+ fromDto: (dto) => ({
1365
+ id: AssetId(dto.id),
1366
+ code: AssetCode(dto.code),
1367
+ name: dto.name,
1368
+ fractionalDigits: dto.fractional_digits
1369
+ })
1370
+ };
1371
+
1372
+ // src/shared/types/offer.ts
1373
+ var OfferId = (value) => value;
1374
+ var OfferSlug = (value) => value;
1375
+ var Offer = {
1376
+ fromDto: (dto) => ({
1377
+ id: OfferId(dto.id),
1378
+ slug: OfferSlug(dto.slug),
1379
+ tagline: notBlankStringOrNull(dto.tagline),
1380
+ bannerUrl: notBlankStringOrNull(dto.banner_url),
1381
+ logoUrl: notBlankStringOrNull(dto.logo_url),
1382
+ startsAt: new Date(dto.starts_at),
1383
+ endsAt: new Date(dto.ends_at)
1384
+ })
1385
+ };
1386
+
1387
+ // src/shared/types/offer-detail.ts
1388
+ var OfferOptionId = (value) => value;
1389
+ var OfferOptionSlug = (value) => value;
1390
+ var OfferDetail = {
1391
+ fromDto: (dto) => {
1392
+ if (!Array.isArray(dto.funding_assets)) {
1393
+ throw new Error(`funding_assets must be an array`);
1394
+ }
1395
+ if (!Array.isArray(dto.options)) {
1396
+ throw new Error(`options must be an array`);
1397
+ }
1398
+ if (!Array.isArray(dto.terms)) {
1399
+ throw new Error(`terms must be an array`);
1400
+ }
1401
+ if (!Array.isArray(dto.links)) {
1402
+ throw new Error(`links must be an array`);
582
1403
  }
583
1404
  if (!Array.isArray(dto.faqs)) {
584
1405
  throw new Error(`faqs must be an array`);
@@ -645,25 +1466,257 @@ var Milestone = {
645
1466
  })
646
1467
  };
647
1468
 
1469
+ // src/shared/types/offer-option-address.ts
1470
+ var OfferOptionAddressId = (value) => value;
1471
+ var OfferOptionAddress = {
1472
+ /** Maps the API DTO into the SDK offer-option-address domain model. */
1473
+ fromDto: (dto) => ({
1474
+ id: OfferOptionAddressId(dto.id),
1475
+ offerOptionId: OfferOptionId(dto.offer_option_id),
1476
+ address: EvmWalletAddress(dto.address),
1477
+ protocol: dto.protocol,
1478
+ createdAt: new Date(dto.created_at)
1479
+ })
1480
+ };
1481
+ var ConnectExternalWalletParams = {
1482
+ /** Maps connect-wallet params into the API DTO payload. */
1483
+ toDto: (params) => ({
1484
+ offer_option_id: params.offerOptionId,
1485
+ wallet_address: params.walletAddress,
1486
+ chain: params.chain,
1487
+ signature: params.signature
1488
+ })
1489
+ };
1490
+
1491
+ // src/shared/types/wallet-ownership-challenge.ts
1492
+ var WalletOwnershipChallenge = {
1493
+ /** Maps the API DTO into the SDK wallet-ownership-challenge domain model. */
1494
+ fromDto: (dto) => ({
1495
+ message: dto.message,
1496
+ expiresAt: new Date(dto.expires_at)
1497
+ })
1498
+ };
1499
+ var CreateWalletOwnershipChallengeParams = {
1500
+ /**
1501
+ * Maps challenge-request params into the API DTO payload. The discriminated
1502
+ * union guarantees SIWE fields are present exactly when `challengeType` is
1503
+ * `siwe`, so the mapping narrows on the discriminant.
1504
+ */
1505
+ toDto: (params) => {
1506
+ switch (params.challengeType) {
1507
+ case "plain":
1508
+ return {
1509
+ wallet_address: params.walletAddress,
1510
+ chain: params.chain,
1511
+ challenge_type: "plain"
1512
+ };
1513
+ case "siwe":
1514
+ return {
1515
+ wallet_address: params.walletAddress,
1516
+ chain: params.chain,
1517
+ challenge_type: "siwe",
1518
+ domain: params.domain,
1519
+ uri: params.uri,
1520
+ statement: params.statement
1521
+ };
1522
+ default: {
1523
+ const _exhaustive = params;
1524
+ return _exhaustive;
1525
+ }
1526
+ }
1527
+ }
1528
+ };
1529
+
1530
+ // src/shared/api/frontline/wallet-connect.ts
1531
+ async function createWalletOwnershipChallenge(api, params) {
1532
+ const dto = await api.send({
1533
+ method: "POST",
1534
+ url: "/v1/wallet-ownership",
1535
+ body: CreateWalletOwnershipChallengeParams.toDto(params),
1536
+ attributes: Attributes.protected()
1537
+ });
1538
+ return WalletOwnershipChallenge.fromDto(dto);
1539
+ }
1540
+ async function connectExternalWallet(api, offerId, params) {
1541
+ const dto = await api.send({
1542
+ method: "POST",
1543
+ url: `/v1/offers/${offerId}/addresses`,
1544
+ body: ConnectExternalWalletParams.toDto(params),
1545
+ attributes: Attributes.protected()
1546
+ });
1547
+ return OfferOptionAddress.fromDto(dto);
1548
+ }
1549
+ async function listOptionAddresses(api, offerId, offerOptionId) {
1550
+ const { data } = await api.send({
1551
+ method: "GET",
1552
+ url: `/v1/offers/${offerId}/addresses`,
1553
+ queryParams: { offer_option_id: offerOptionId },
1554
+ attributes: Attributes.protected()
1555
+ });
1556
+ return data.map(OfferOptionAddress.fromDto);
1557
+ }
1558
+ async function removeOptionAddress(api, offerId, addressId) {
1559
+ const dto = await api.send({
1560
+ method: "DELETE",
1561
+ url: `/v1/offers/${offerId}/addresses/${addressId}`,
1562
+ attributes: Attributes.protected()
1563
+ });
1564
+ return OfferOptionAddress.fromDto(dto);
1565
+ }
1566
+
1567
+ // src/shared/core/swap-namespace.ts
1568
+ var SwapNamespaceImpl = class {
1569
+ constructor(ctx) {
1570
+ this.ctx = ctx;
1571
+ }
1572
+ async getAuthorization(params) {
1573
+ await this.ctx.ensureUserAuthenticated();
1574
+ return getSwapAuthorization(this.ctx.api, params);
1575
+ }
1576
+ async getPreview(params) {
1577
+ await this.ctx.ensureUserAuthenticated();
1578
+ return getSwapPreview(this.ctx.api, params);
1579
+ }
1580
+ async getStatus(params) {
1581
+ await this.ctx.ensureUserAuthenticated();
1582
+ return getSwapStatus(this.ctx.api, params);
1583
+ }
1584
+ async getTokenAllowance(params) {
1585
+ await this.ctx.ensureUserAuthenticated();
1586
+ return getTokenAllowance(this.ctx.api, params);
1587
+ }
1588
+ async getTokenBalance(params) {
1589
+ await this.ctx.ensureUserAuthenticated();
1590
+ return getTokenBalance(this.ctx.api, params);
1591
+ }
1592
+ async getOutputToken(params) {
1593
+ await this.ctx.ensureUserAuthenticated();
1594
+ return getSwapOutputToken(this.ctx.api, params);
1595
+ }
1596
+ async requestWalletOwnershipChallenge(params) {
1597
+ await this.ctx.ensureUserAuthenticated();
1598
+ return createWalletOwnershipChallenge(this.ctx.api, params);
1599
+ }
1600
+ async allowWallet(params) {
1601
+ await this.ctx.ensureUserAuthenticated();
1602
+ return allowWallet(this.ctx.api, params);
1603
+ }
1604
+ };
1605
+
1606
+ // src/client/core/client-swap-namespace.ts
1607
+ var ClientSwapNamespaceImpl = class extends SwapNamespaceImpl {
1608
+ executeSwap(params) {
1609
+ return executeSwap({ ...params, swap: this });
1610
+ }
1611
+ authorizeWallet(params) {
1612
+ return authorizeWallet({ ...params, swap: this });
1613
+ }
1614
+ };
1615
+
1616
+ // src/shared/types/document-submission.ts
1617
+ var DocumentSubmission = {
1618
+ fromDto: (dto) => ({
1619
+ status: dto.status,
1620
+ formType: dto.form_type
1621
+ })
1622
+ };
1623
+
1624
+ // src/shared/api/frontline/documents.ts
1625
+ async function submitDocument(api, documentType, fields) {
1626
+ const dto = await api.send({
1627
+ method: "POST",
1628
+ url: `/v1/documents/${documentType}/submission`,
1629
+ body: fields,
1630
+ attributes: Attributes.protected()
1631
+ });
1632
+ return DocumentSubmission.fromDto(dto);
1633
+ }
1634
+
1635
+ // src/shared/types/kyc.ts
1636
+ var KycToken = {
1637
+ fromDto: (dto) => ({
1638
+ token: dto.token
1639
+ })
1640
+ };
1641
+
1642
+ // src/shared/api/frontline/kyc.ts
1643
+ async function createKycToken(api, levelName, reset) {
1644
+ const dto = await api.send({
1645
+ method: "POST",
1646
+ url: "/v1/kyc-token",
1647
+ body: {
1648
+ ...levelName === void 0 ? {} : { level_name: levelName },
1649
+ ...reset === void 0 ? {} : { reset }
1650
+ },
1651
+ attributes: Attributes.protected()
1652
+ });
1653
+ return KycToken.fromDto(dto);
1654
+ }
1655
+
1656
+ // src/shared/api/pagination.ts
1657
+ var Cursor = (value) => value;
1658
+ async function fetchAllPages(fetchPage, baseParams) {
1659
+ const items = [];
1660
+ let cursor = null;
1661
+ do {
1662
+ const params = {
1663
+ ...baseParams ?? {},
1664
+ after: cursor ?? void 0
1665
+ };
1666
+ const page = await fetchPage(params);
1667
+ items.push(...page.data);
1668
+ cursor = page.startingAfter;
1669
+ } while (cursor);
1670
+ return items;
1671
+ }
1672
+ var PaginatedResponse = {
1673
+ fromDto: (dto, itemMapper) => ({
1674
+ data: dto.data.map(itemMapper),
1675
+ startingAfter: dto.starting_after ? Cursor(dto.starting_after) : null,
1676
+ startingBefore: dto.starting_before ? Cursor(dto.starting_before) : null
1677
+ })
1678
+ };
1679
+ var PaginationParams = {
1680
+ toQueryParams: (params) => {
1681
+ const queryParams = {};
1682
+ if (params.after) {
1683
+ queryParams.starting_after = params.after;
1684
+ }
1685
+ if (params.before) {
1686
+ queryParams.starting_before = params.before;
1687
+ }
1688
+ if (params.limit) {
1689
+ queryParams.limit = params.limit;
1690
+ }
1691
+ return queryParams;
1692
+ }
1693
+ };
1694
+
648
1695
  // src/shared/api/frontline/offers.ts
649
- async function fetchOffers(api) {
650
- return fetchAllPages((params) => fetchOffersPage(api, params));
1696
+ async function fetchOffers(api, clientCreds) {
1697
+ return fetchAllPages((params) => fetchOffersPage(api, params, clientCreds));
651
1698
  }
652
- async function fetchOffersPage(api, params) {
1699
+ async function fetchOffersPage(api, params, clientCreds) {
653
1700
  const queryParams = PaginationParams.toQueryParams(params);
654
1701
  const pageDto = await api.send({
655
1702
  method: "GET",
656
1703
  url: "/v1/offers",
657
1704
  queryParams,
658
- attributes: Attributes.protected()
1705
+ attributes: Attributes.concat(
1706
+ Attributes.protected(),
1707
+ Attributes.clientCredentials(clientCreds)
1708
+ )
659
1709
  });
660
1710
  return PaginatedResponse.fromDto(pageDto, Offer.fromDto);
661
1711
  }
662
- async function fetchOfferDetails(api, id) {
1712
+ async function fetchOfferDetails(api, id, clientCreds) {
663
1713
  const dto = await api.send({
664
1714
  method: "GET",
665
1715
  url: `/v1/offers/${id}`,
666
- attributes: Attributes.protected()
1716
+ attributes: Attributes.concat(
1717
+ Attributes.protected(),
1718
+ Attributes.clientCredentials(clientCreds)
1719
+ )
667
1720
  });
668
1721
  return OfferDetail.fromDto(dto);
669
1722
  }
@@ -749,6 +1802,44 @@ async function createParticipation(api, params) {
749
1802
  return Participation.fromDto(dto);
750
1803
  }
751
1804
 
1805
+ // src/shared/types/pii.ts
1806
+ var Iso2CountryCode = (value) => value;
1807
+ var PiiJurisdiction = {
1808
+ fromDto: (dto) => ({
1809
+ iso2: Iso2CountryCode(dto.iso_2),
1810
+ name: dto.name
1811
+ })
1812
+ };
1813
+ var PiiAddress = {
1814
+ fromDto: (dto) => ({
1815
+ street: dto.street,
1816
+ city: dto.city,
1817
+ state: dto.state,
1818
+ postalCode: dto.postal_code,
1819
+ country: dto.country
1820
+ })
1821
+ };
1822
+ var Pii = {
1823
+ fromDto: (dto) => ({
1824
+ kind: dto.kind,
1825
+ fullLegalName: dto.full_legal_name,
1826
+ dateOfBirth: dto.date_of_birth,
1827
+ jurisdiction: dto.jurisdiction ? PiiJurisdiction.fromDto(dto.jurisdiction) : null,
1828
+ taxId: dto.tax_id,
1829
+ permanentAddress: PiiAddress.fromDto(dto.permanent_address)
1830
+ })
1831
+ };
1832
+
1833
+ // src/shared/api/frontline/pii.ts
1834
+ async function fetchPii(api) {
1835
+ const dto = await api.send({
1836
+ method: "GET",
1837
+ url: "/v1/pii",
1838
+ attributes: Attributes.protected()
1839
+ });
1840
+ return Pii.fromDto(dto);
1841
+ }
1842
+
752
1843
  // src/shared/types/requirement.ts
753
1844
  var RequirementId = (value) => value;
754
1845
  var Requirement = {
@@ -759,18 +1850,26 @@ var Requirement = {
759
1850
  })
760
1851
  };
761
1852
  var RequirementStatusInfo = {
762
- fromStatusesDto: (dto) => Object.entries(dto.statuses).map(([id, status]) => ({
763
- id: RequirementId(id),
764
- status
765
- }))
1853
+ fromStatusesDto: (dto) => Object.entries(dto.statuses).map(
1854
+ ([id, value]) => typeof value === "string" ? { id: RequirementId(id), status: value, action: null } : {
1855
+ id: RequirementId(id),
1856
+ status: value.status,
1857
+ action: value.action ?? null,
1858
+ kycLevel: value.kyc_level,
1859
+ kycReset: value.kyc_reset
1860
+ }
1861
+ )
766
1862
  };
767
1863
 
768
1864
  // src/shared/api/frontline/requirements.ts
769
- async function fetchOfferRequirements(api, offerId) {
1865
+ async function fetchOfferRequirements(api, offerId, clientCreds) {
770
1866
  const response = await api.send({
771
1867
  method: "GET",
772
1868
  url: `/v1/offers/${offerId}/requirements`,
773
- attributes: Attributes.protected()
1869
+ attributes: Attributes.concat(
1870
+ Attributes.protected(),
1871
+ Attributes.clientCredentials(clientCreds)
1872
+ )
774
1873
  });
775
1874
  return Object.fromEntries(
776
1875
  Object.entries(response.options).map(([optionId, list]) => [
@@ -788,6 +1887,29 @@ async function fetchRequirementStatuses(api, offerId) {
788
1887
  return RequirementStatusInfo.fromStatusesDto(response);
789
1888
  }
790
1889
 
1890
+ // src/shared/types/oauth.ts
1891
+ var AuthorizationCode = (value) => value;
1892
+ var CodeVerifier = (value) => value;
1893
+ var CodeChallenge = (value) => value;
1894
+ var PKCEState = (value) => value;
1895
+
1896
+ // src/shared/pkce.ts
1897
+ async function generatePKCEParams(config) {
1898
+ const state = generateSecureRandomBase64Url(32);
1899
+ const codeVerifier = generateSecureRandomBase64Url(32);
1900
+ const codeChallengeRaw = await sha256(codeVerifier);
1901
+ const codeChallenge = arrayBufferToBase64Url(codeChallengeRaw, false);
1902
+ return {
1903
+ clientId: config.clientId,
1904
+ responseType: "code",
1905
+ redirectUri: config.redirectUri,
1906
+ codeChallenge: CodeChallenge(codeChallenge),
1907
+ codeChallengeMethod: "S256",
1908
+ state: PKCEState(state),
1909
+ codeVerifier: CodeVerifier(codeVerifier)
1910
+ };
1911
+ }
1912
+
791
1913
  // src/shared/types/errors.ts
792
1914
  var NotAuthenticatedError = class extends Error {
793
1915
  constructor(message = "The user is not authenticated. Go through the OAuth flow first!") {
@@ -796,10 +1918,6 @@ var NotAuthenticatedError = class extends Error {
796
1918
  }
797
1919
  };
798
1920
 
799
- // src/shared/types/oauth.ts
800
- var AuthorizationCode = (value) => value;
801
- var CodeVerifier = (value) => value;
802
-
803
1921
  // src/client/core/coinlist-client.ts
804
1922
  var OAUTH_STATE_KEY = "coinlist.oauth_state";
805
1923
  var OAUTH_CODE_VERIFIER_KEY = "coinlist.oauth_code_verifier";
@@ -815,6 +1933,10 @@ var CoinListClientImpl = class {
815
1933
  },
816
1934
  this.fetchAccessToken.bind(this)
817
1935
  );
1936
+ this.swap = new ClientSwapNamespaceImpl({
1937
+ api: this.api,
1938
+ ensureUserAuthenticated: async () => this.ensureAuthenticated()
1939
+ });
818
1940
  }
819
1941
  async init() {
820
1942
  await this.fetchAccessToken(true);
@@ -838,19 +1960,16 @@ var CoinListClientImpl = class {
838
1960
  return this._accessToken !== null ? "logged-in" : "logged-out";
839
1961
  }
840
1962
  async startOAuth() {
841
- const state = generateSecureRandomBase64Url(32);
842
- const codeVerifier = generateSecureRandomBase64Url(32);
843
- const codeChallengeRaw = await sha256(codeVerifier);
844
- const codeChallenge = arrayBufferToBase64Url(codeChallengeRaw, false);
845
- sessionStorage.setItem(OAUTH_STATE_KEY, state);
846
- sessionStorage.setItem(OAUTH_CODE_VERIFIER_KEY, codeVerifier);
1963
+ const pkceParams = await generatePKCEParams(this._config);
1964
+ sessionStorage.setItem(OAUTH_STATE_KEY, pkceParams.state);
1965
+ sessionStorage.setItem(OAUTH_CODE_VERIFIER_KEY, pkceParams.codeVerifier);
847
1966
  const params = new URLSearchParams({
848
- client_id: this._config.clientId,
849
- response_type: "code",
850
- redirect_uri: this._config.redirectUri,
851
- code_challenge: codeChallenge,
852
- code_challenge_method: "S256",
853
- state
1967
+ client_id: pkceParams.clientId,
1968
+ response_type: pkceParams.responseType,
1969
+ redirect_uri: pkceParams.redirectUri,
1970
+ code_challenge: pkceParams.codeChallenge,
1971
+ code_challenge_method: pkceParams.codeChallengeMethod,
1972
+ state: pkceParams.state
854
1973
  });
855
1974
  const baseUrl = this._config.coinlistBaseUrl ?? COINLIST_BASE_URL;
856
1975
  const url = `${baseUrl}${OAUTH_PAGE_PATH}?${params.toString()}`;
@@ -889,15 +2008,15 @@ var CoinListClientImpl = class {
889
2008
  }
890
2009
  async fetchOffers() {
891
2010
  this.ensureAuthenticated();
892
- return fetchOffers(this.api);
2011
+ return fetchOffers(this.api, void 0);
893
2012
  }
894
2013
  async fetchOffersPage(params) {
895
2014
  this.ensureAuthenticated();
896
- return fetchOffersPage(this.api, params);
2015
+ return fetchOffersPage(this.api, params, void 0);
897
2016
  }
898
2017
  async fetchOfferDetails(id) {
899
2018
  this.ensureAuthenticated();
900
- return fetchOfferDetails(this.api, id);
2019
+ return fetchOfferDetails(this.api, id, void 0);
901
2020
  }
902
2021
  async fetchParticipations(offerId) {
903
2022
  this.ensureAuthenticated();
@@ -915,16 +2034,48 @@ var CoinListClientImpl = class {
915
2034
  this.ensureAuthenticated();
916
2035
  return createParticipation(this.api, params);
917
2036
  }
2037
+ async createWalletOwnershipChallenge(params) {
2038
+ this.ensureAuthenticated();
2039
+ return createWalletOwnershipChallenge(this.api, params);
2040
+ }
2041
+ async connectExternalWallet(offerId, params) {
2042
+ this.ensureAuthenticated();
2043
+ return connectExternalWallet(this.api, offerId, params);
2044
+ }
2045
+ async listOptionAddresses(offerId, offerOptionId) {
2046
+ this.ensureAuthenticated();
2047
+ return listOptionAddresses(
2048
+ this.api,
2049
+ offerId,
2050
+ offerOptionId
2051
+ );
2052
+ }
2053
+ async removeOptionAddress(offerId, addressId) {
2054
+ this.ensureAuthenticated();
2055
+ return removeOptionAddress(this.api, offerId, addressId);
2056
+ }
918
2057
  async fetchOfferRequirements(offerId) {
919
2058
  this.ensureAuthenticated();
920
- return fetchOfferRequirements(this.api, offerId);
2059
+ return fetchOfferRequirements(this.api, offerId, void 0);
921
2060
  }
922
2061
  async fetchRequirementStatuses(offerId) {
923
2062
  this.ensureAuthenticated();
924
2063
  return fetchRequirementStatuses(this.api, offerId);
925
2064
  }
926
- handleRequirement(requirement) {
927
- const baseUrl = this._config.coinlistBaseUrl ?? COINLIST_BASE_URL;
2065
+ async fetchPii() {
2066
+ this.ensureAuthenticated();
2067
+ return fetchPii(this.api);
2068
+ }
2069
+ async submitDocument(documentType, fields) {
2070
+ this.ensureAuthenticated();
2071
+ return submitDocument(this.api, documentType, fields);
2072
+ }
2073
+ async createKycToken(levelName, reset) {
2074
+ this.ensureAuthenticated();
2075
+ return createKycToken(this.api, levelName, reset);
2076
+ }
2077
+ handleRequirement(requirement) {
2078
+ const baseUrl = this._config.coinlistBaseUrl ?? COINLIST_BASE_URL;
928
2079
  let path;
929
2080
  switch (requirement.type) {
930
2081
  case "kyc_approved":
@@ -949,6 +2100,9 @@ var CoinListClientImpl = class {
949
2100
  case "jurisdiction":
950
2101
  path = null;
951
2102
  break;
2103
+ case "document":
2104
+ path = null;
2105
+ break;
952
2106
  default: {
953
2107
  const _exhaustive = requirement.type;
954
2108
  return;
@@ -976,7 +2130,10 @@ function createCoinListClient(config) {
976
2130
  // src/client/CoinListProvider.tsx
977
2131
  var import_jsx_runtime = require("react/jsx-runtime");
978
2132
  var CoinListContext = (0, import_react.createContext)(null);
979
- function CoinListProvider({ config, children }) {
2133
+ function CoinListContextProvider({
2134
+ config,
2135
+ children
2136
+ }) {
980
2137
  const [isReady, setIsReady] = (0, import_react.useState)(false);
981
2138
  const coinlist = (0, import_react.useMemo)(() => createCoinListClient(config), [config]);
982
2139
  (0, import_react.useEffect)(() => {
@@ -1001,23 +2158,69 @@ function CoinListProvider({ config, children }) {
1001
2158
  const value = (0, import_react.useMemo)(() => ({ coinlist, isReady }), [coinlist, isReady]);
1002
2159
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CoinListContext.Provider, { value, children });
1003
2160
  }
2161
+ var CoinListProvider = CoinListContextProvider;
2162
+
2163
+ // src/client/CoinListStyleScope.tsx
2164
+ var import_react2 = require("react");
2165
+
2166
+ // src/client/generated/sdk-styles.gen.ts
2167
+ var sdkStyles = '/*! tailwindcss v4.2.1 | MIT License | https://tailwindcss.com */\n@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-space-y-reverse:0;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-duration:initial;--tw-ease:initial;--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0}}}@layer theme{:root,:host{--clcosdk-font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--clcosdk-color-red-400:oklch(70.4% .191 22.216);--clcosdk-color-red-500:oklch(63.7% .237 25.331);--clcosdk-color-amber-500:oklch(76.9% .188 70.08);--clcosdk-color-gray-400:oklch(70.7% .022 261.325);--clcosdk-color-gray-500:oklch(55.1% .027 264.364);--clcosdk-color-black:#000;--clcosdk-spacing:.25rem;--clcosdk-container-md:28rem;--clcosdk-text-xs:.75rem;--clcosdk-text-xs--line-height:calc(1 / .75);--clcosdk-text-sm:.875rem;--clcosdk-text-sm--line-height:calc(1.25 / .875);--clcosdk-text-base:1rem;--clcosdk-text-base--line-height:calc(1.5 / 1);--clcosdk-font-weight-normal:400;--clcosdk-font-weight-medium:500;--clcosdk-font-weight-semibold:600;--clcosdk-radius-md:.375rem;--clcosdk-radius-lg:.5rem;--clcosdk-radius-2xl:1rem;--clcosdk-ease-in-out:cubic-bezier(.4, 0, .2, 1);--clcosdk-animate-spin:spin 1s linear infinite;--clcosdk-animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--clcosdk-color-brand-primary:var(--color-brand-primary)}}@layer base{.clco-sdk-root{--color-brand-primary:#171717;--color-brand-primary-hover:#000;--color-brand-primary-active:#262626;--color-accent:#2b3a67;--color-accent-hover:#243057;--color-accent-active:#1d2647;--color-accent-focus:#c7d2fe;--color-accent-subtle:#eef1f8;--color-text-primary:#171717;--color-text-secondary:#8c8c8c;--color-text-disabled:#d1d1d1;--color-text-inverse:#fff;--color-background:#fff;--color-surface:#fafafa;--color-section:#f3f3f3;--color-border:#e5e5e5;--color-divider:#ececec;--color-overlay:#00000080;--color-positive:#15803d;--color-positive-subtle:#dcfce7;--color-negative:#dc2626;--color-negative-subtle:#fee2e2;--color-success:#2c8c5e;--color-success-subtle:#e6f4ec;--color-success-border:#cfe9db;--color-warning:#e08a1a;--color-warning-subtle:#fff7ed;--color-warning-border:#fdead7;--color-error:#b42318;--color-error-subtle:#feeceb;--color-error-border:#fbd5d2}@media (prefers-color-scheme:dark){.clco-sdk-root:not(:where(.light,.light *)){--color-brand-primary:#f4f4f5;--color-brand-primary-hover:#fff;--color-brand-primary-active:#e4e4e7;--color-accent:#6f82c9;--color-accent-hover:#8799e4;--color-accent-active:#5b6fcf;--color-accent-focus:#6f82c959;--color-accent-subtle:#6f82c91f;--color-text-primary:#f4f4f5;--color-text-secondary:#a1a1aa;--color-text-disabled:#71717a;--color-text-inverse:#171717;--color-background:#0f1115;--color-surface:#161a20;--color-section:#20242c;--color-border:#2a2e35;--color-divider:#323741;--color-overlay:#000000b3;--color-positive:#22c55e;--color-positive-subtle:#22c55e1f;--color-negative:#ef4444;--color-negative-subtle:#ef44441f;--color-success:#34d399;--color-success-subtle:#34d3991f;--color-success-border:#34d39940;--color-warning:#f59e0b;--color-warning-subtle:#f59e0b1f;--color-warning-border:#f59e0b40;--color-error:#f87171;--color-error-subtle:#f871711f;--color-error-border:#f8717140}}:where(.dark,.dark *) .clco-sdk-root{--color-brand-primary:#f4f4f5;--color-brand-primary-hover:#fff;--color-brand-primary-active:#e4e4e7;--color-accent:#6f82c9;--color-accent-hover:#8799e4;--color-accent-active:#5b6fcf;--color-accent-focus:#6f82c959;--color-accent-subtle:#6f82c91f;--color-text-primary:#f4f4f5;--color-text-secondary:#a1a1aa;--color-text-disabled:#71717a;--color-text-inverse:#171717;--color-background:#0f1115;--color-surface:#161a20;--color-section:#20242c;--color-border:#2a2e35;--color-divider:#323741;--color-overlay:#000000b3;--color-positive:#22c55e;--color-positive-subtle:#22c55e1f;--color-negative:#ef4444;--color-negative-subtle:#ef44441f;--color-success:#34d399;--color-success-subtle:#34d3991f;--color-success-border:#34d39940;--color-warning:#f59e0b;--color-warning-subtle:#f59e0b1f;--color-warning-border:#f59e0b40;--color-error:#f87171;--color-error-subtle:#f871711f;--color-error-border:#f8717140}.clco-sdk-root{color:var(--color-text-primary);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-family:Inter,sans-serif}.clco-sdk-root *,.clco-sdk-root :before,.clco-sdk-root :after{box-sizing:border-box}.clco-sdk-root button{appearance:none;cursor:pointer;font:inherit;color:inherit;background:0 0;border:none;padding:0}.clco-sdk-root a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}.clco-sdk-root ul,.clco-sdk-root ol{margin:0;padding:0;list-style:none}.clco-sdk-root img,.clco-sdk-root svg{max-width:100%;display:block}}@layer components;@layer utilities{.clcosdk\\:absolute{position:absolute}.clcosdk\\:fixed{position:fixed}.clcosdk\\:relative{position:relative}.clcosdk\\:inset-0{inset:calc(var(--clcosdk-spacing) * 0)}.clcosdk\\:top-4{top:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\:right-4{right:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\:z-50{z-index:50}.clcosdk\\:mt-4{margin-top:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\:mb-6{margin-bottom:calc(var(--clcosdk-spacing) * 6)}.clcosdk\\:flex{display:flex}.clcosdk\\:grid{display:grid}.clcosdk\\:inline-flex{display:inline-flex}.clcosdk\\:h-3{height:calc(var(--clcosdk-spacing) * 3)}.clcosdk\\:h-4{height:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\:h-5{height:calc(var(--clcosdk-spacing) * 5)}.clcosdk\\:h-6{height:calc(var(--clcosdk-spacing) * 6)}.clcosdk\\:h-9{height:calc(var(--clcosdk-spacing) * 9)}.clcosdk\\:h-11{height:calc(var(--clcosdk-spacing) * 11)}.clcosdk\\:h-12{height:calc(var(--clcosdk-spacing) * 12)}.clcosdk\\:h-14{height:calc(var(--clcosdk-spacing) * 14)}.clcosdk\\:h-28{height:calc(var(--clcosdk-spacing) * 28)}.clcosdk\\:h-52{height:calc(var(--clcosdk-spacing) * 52)}.clcosdk\\:h-\\[18px\\]{height:18px}.clcosdk\\:h-auto{height:auto}.clcosdk\\:h-full{height:100%}.clcosdk\\:max-h-\\[92vh\\]{max-height:92vh}.clcosdk\\:min-h-0{min-height:calc(var(--clcosdk-spacing) * 0)}.clcosdk\\:min-h-9{min-height:calc(var(--clcosdk-spacing) * 9)}.clcosdk\\:min-h-40{min-height:calc(var(--clcosdk-spacing) * 40)}.clcosdk\\:min-h-\\[2\\.4rem\\]{min-height:2.4rem}.clcosdk\\:w-4{width:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\:w-5{width:calc(var(--clcosdk-spacing) * 5)}.clcosdk\\:w-6{width:calc(var(--clcosdk-spacing) * 6)}.clcosdk\\:w-12{width:calc(var(--clcosdk-spacing) * 12)}.clcosdk\\:w-16{width:calc(var(--clcosdk-spacing) * 16)}.clcosdk\\:w-28{width:calc(var(--clcosdk-spacing) * 28)}.clcosdk\\:w-48{width:calc(var(--clcosdk-spacing) * 48)}.clcosdk\\:w-80{width:calc(var(--clcosdk-spacing) * 80)}.clcosdk\\:w-96{width:calc(var(--clcosdk-spacing) * 96)}.clcosdk\\:w-\\[16px\\]{width:16px}.clcosdk\\:w-\\[448px\\]{width:448px}.clcosdk\\:w-auto{width:auto}.clcosdk\\:w-full{width:100%}.clcosdk\\:max-w-\\[22rem\\]{max-width:22rem}.clcosdk\\:max-w-\\[28rem\\]{max-width:28rem}.clcosdk\\:max-w-\\[30rem\\]{max-width:30rem}.clcosdk\\:max-w-\\[760px\\]{max-width:760px}.clcosdk\\:max-w-\\[1200px\\]{max-width:1200px}.clcosdk\\:max-w-md{max-width:var(--clcosdk-container-md)}.clcosdk\\:shrink-0{flex-shrink:0}.clcosdk\\:rotate-90{rotate:90deg}.clcosdk\\:animate-pulse{animation:var(--clcosdk-animate-pulse)}.clcosdk\\:animate-spin{animation:var(--clcosdk-animate-spin)}.clcosdk\\:cursor-pointer{cursor:pointer}.clcosdk\\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.clcosdk\\:grid-rows-\\[0fr\\]{grid-template-rows:0fr}.clcosdk\\:grid-rows-\\[1fr\\]{grid-template-rows:1fr}.clcosdk\\:flex-col{flex-direction:column}.clcosdk\\:flex-wrap{flex-wrap:wrap}.clcosdk\\:items-center{align-items:center}.clcosdk\\:items-start{align-items:flex-start}.clcosdk\\:justify-between{justify-content:space-between}.clcosdk\\:justify-center{justify-content:center}.clcosdk\\:gap-1{gap:calc(var(--clcosdk-spacing) * 1)}.clcosdk\\:gap-2{gap:calc(var(--clcosdk-spacing) * 2)}.clcosdk\\:gap-3{gap:calc(var(--clcosdk-spacing) * 3)}.clcosdk\\:gap-4{gap:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\:gap-5{gap:calc(var(--clcosdk-spacing) * 5)}.clcosdk\\:gap-6{gap:calc(var(--clcosdk-spacing) * 6)}.clcosdk\\:gap-8{gap:calc(var(--clcosdk-spacing) * 8)}.clcosdk\\:gap-\\[5px\\]{gap:5px}:where(.clcosdk\\:space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--clcosdk-spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--clcosdk-spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.clcosdk\\:space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--clcosdk-spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--clcosdk-spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}:where(.clcosdk\\:divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px * var(--tw-divide-y-reverse));border-bottom-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)))}:where(.clcosdk\\:divide-border>:not(:last-child)){border-color:var(--color-border)}:where(.clcosdk\\:divide-divider>:not(:last-child)){border-color:var(--color-divider)}.clcosdk\\:self-start{align-self:flex-start}.clcosdk\\:overflow-hidden{overflow:hidden}.clcosdk\\:overflow-y-auto{overflow-y:auto}.clcosdk\\:rounded{border-radius:.25rem}.clcosdk\\:rounded-2xl{border-radius:var(--clcosdk-radius-2xl)}.clcosdk\\:rounded-btn{border-radius:12px}.clcosdk\\:rounded-card{border-radius:24px}.clcosdk\\:rounded-full{border-radius:3.40282e38px}.clcosdk\\:rounded-lg{border-radius:var(--clcosdk-radius-lg)}.clcosdk\\:rounded-md{border-radius:var(--clcosdk-radius-md)}.clcosdk\\:border{border-style:var(--tw-border-style);border-width:1px}.clcosdk\\:border-2{border-style:var(--tw-border-style);border-width:2px}.clcosdk\\:border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.clcosdk\\:border-dashed{--tw-border-style:dashed;border-style:dashed}.clcosdk\\:border-accent\\/50{border-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.clcosdk\\:border-accent\\/50{border-color:color-mix(in oklab, var(--color-accent) 50%, transparent)}}.clcosdk\\:border-accent\\/60{border-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.clcosdk\\:border-accent\\/60{border-color:color-mix(in oklab, var(--color-accent) 60%, transparent)}}.clcosdk\\:border-amber-500{border-color:var(--clcosdk-color-amber-500)}.clcosdk\\:border-border,.clcosdk\\:border-border\\/60{border-color:var(--color-border)}@supports (color:color-mix(in lab, red, red)){.clcosdk\\:border-border\\/60{border-color:color-mix(in oklab, var(--color-border) 60%, transparent)}}.clcosdk\\:border-current{border-color:currentColor}.clcosdk\\:border-divider{border-color:var(--color-divider)}.clcosdk\\:border-error-border{border-color:var(--color-error-border)}.clcosdk\\:border-success-border{border-color:var(--color-success-border)}.clcosdk\\:border-warning-border{border-color:var(--color-warning-border)}.clcosdk\\:border-t-transparent{border-top-color:#0000}.clcosdk\\:bg-accent\\/10{background-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.clcosdk\\:bg-accent\\/10{background-color:color-mix(in oklab, var(--color-accent) 10%, transparent)}}.clcosdk\\:bg-background{background-color:var(--color-background)}.clcosdk\\:bg-black\\/50{background-color:var(--clcosdk-color-black)}@supports (color:color-mix(in lab, red, red)){.clcosdk\\:bg-black\\/50{background-color:color-mix(in oklab, var(--clcosdk-color-black) 50%, transparent)}}.clcosdk\\:bg-brand-primary{background-color:var(--color-brand-primary)}.clcosdk\\:bg-error-subtle{background-color:var(--color-error-subtle)}.clcosdk\\:bg-overlay{background-color:var(--color-overlay)}.clcosdk\\:bg-section{background-color:var(--color-section)}.clcosdk\\:bg-success-subtle{background-color:var(--color-success-subtle)}.clcosdk\\:bg-surface{background-color:var(--color-surface)}.clcosdk\\:bg-transparent{background-color:#0000}.clcosdk\\:bg-warning-subtle{background-color:var(--color-warning-subtle)}.clcosdk\\:bg-gradient-to-b{--tw-gradient-position:to bottom in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.clcosdk\\:bg-gradient-to-br{--tw-gradient-position:to bottom right in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.clcosdk\\:from-surface{--tw-gradient-from:var(--color-surface);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.clcosdk\\:from-transparent{--tw-gradient-from:transparent;--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.clcosdk\\:via-section{--tw-gradient-via:var(--color-section);--tw-gradient-via-stops:var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-via-stops)}.clcosdk\\:via-transparent{--tw-gradient-via:transparent;--tw-gradient-via-stops:var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-via-stops)}.clcosdk\\:to-background{--tw-gradient-to:var(--color-background);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.clcosdk\\:to-overlay\\/35{--tw-gradient-to:var(--color-overlay)}@supports (color:color-mix(in lab, red, red)){.clcosdk\\:to-overlay\\/35{--tw-gradient-to:color-mix(in oklab, var(--color-overlay) 35%, transparent)}}.clcosdk\\:to-overlay\\/35{--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.clcosdk\\:object-cover{object-fit:cover}.clcosdk\\:p-0{padding:calc(var(--clcosdk-spacing) * 0)}.clcosdk\\:p-1\\.5{padding:calc(var(--clcosdk-spacing) * 1.5)}.clcosdk\\:p-3{padding:calc(var(--clcosdk-spacing) * 3)}.clcosdk\\:p-4{padding:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\:p-6{padding:calc(var(--clcosdk-spacing) * 6)}.clcosdk\\:p-8{padding:calc(var(--clcosdk-spacing) * 8)}.clcosdk\\:px-2{padding-inline:calc(var(--clcosdk-spacing) * 2)}.clcosdk\\:px-3{padding-inline:calc(var(--clcosdk-spacing) * 3)}.clcosdk\\:px-4{padding-inline:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\:px-5{padding-inline:calc(var(--clcosdk-spacing) * 5)}.clcosdk\\:px-6{padding-inline:calc(var(--clcosdk-spacing) * 6)}.clcosdk\\:py-2{padding-block:calc(var(--clcosdk-spacing) * 2)}.clcosdk\\:pt-4{padding-top:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\:pt-14{padding-top:calc(var(--clcosdk-spacing) * 14)}.clcosdk\\:pb-4{padding-bottom:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\:text-center{text-align:center}.clcosdk\\:text-left{text-align:left}.clcosdk\\:font-mono{font-family:var(--clcosdk-font-mono)}.clcosdk\\:text-base{font-size:var(--clcosdk-text-base);line-height:var(--tw-leading,var(--clcosdk-text-base--line-height))}.clcosdk\\:text-sm{font-size:var(--clcosdk-text-sm);line-height:var(--tw-leading,var(--clcosdk-text-sm--line-height))}.clcosdk\\:text-xs{font-size:var(--clcosdk-text-xs);line-height:var(--tw-leading,var(--clcosdk-text-xs--line-height))}.clcosdk\\:text-\\[11px\\]{font-size:11px}.clcosdk\\:text-\\[12px\\]{font-size:12px}.clcosdk\\:text-\\[14px\\]{font-size:14px}.clcosdk\\:text-\\[16px\\]{font-size:16px}.clcosdk\\:text-\\[18px\\]{font-size:18px}.clcosdk\\:text-\\[22px\\]{font-size:22px}.clcosdk\\:text-\\[28px\\]{font-size:28px}.clcosdk\\:text-\\[36px\\]{font-size:36px}.clcosdk\\:text-\\[48px\\]{font-size:48px}.clcosdk\\:text-\\[64px\\]{font-size:64px}.clcosdk\\:leading-\\[110\\%\\]{--tw-leading:110%;line-height:110%}.clcosdk\\:leading-\\[120\\%\\]{--tw-leading:120%;line-height:120%}.clcosdk\\:leading-\\[125\\%\\]{--tw-leading:125%;line-height:125%}.clcosdk\\:leading-\\[130\\%\\]{--tw-leading:130%;line-height:130%}.clcosdk\\:leading-\\[135\\%\\]{--tw-leading:135%;line-height:135%}.clcosdk\\:leading-\\[140\\%\\]{--tw-leading:140%;line-height:140%}.clcosdk\\:leading-\\[150\\%\\]{--tw-leading:150%;line-height:150%}.clcosdk\\:font-medium{--tw-font-weight:var(--clcosdk-font-weight-medium);font-weight:var(--clcosdk-font-weight-medium)}.clcosdk\\:font-normal{--tw-font-weight:var(--clcosdk-font-weight-normal);font-weight:var(--clcosdk-font-weight-normal)}.clcosdk\\:font-semibold{--tw-font-weight:var(--clcosdk-font-weight-semibold);font-weight:var(--clcosdk-font-weight-semibold)}.clcosdk\\:tracking-\\[0\\.12px\\]{--tw-tracking:.12px;letter-spacing:.12px}.clcosdk\\:tracking-\\[0\\.28px\\]{--tw-tracking:.28px;letter-spacing:.28px}.clcosdk\\:whitespace-nowrap{white-space:nowrap}.clcosdk\\:text-error{color:var(--color-error)}.clcosdk\\:text-success{color:var(--color-success)}.clcosdk\\:text-text-inverse{color:var(--color-text-inverse)}.clcosdk\\:text-text-primary{color:var(--color-text-primary)}.clcosdk\\:text-text-secondary{color:var(--color-text-secondary)}.clcosdk\\:text-warning{color:var(--color-warning)}.clcosdk\\:capitalize{text-transform:capitalize}.clcosdk\\:underline{text-decoration-line:underline}.clcosdk\\:underline-offset-2{text-underline-offset:2px}.clcosdk\\:underline-offset-4{text-underline-offset:4px}.clcosdk\\:opacity-60{opacity:.6}.clcosdk\\:shadow-\\[0_0_0_3px_rgba\\(59\\,130\\,246\\,0\\.2\\)\\]{--tw-shadow:0 0 0 3px var(--tw-shadow-color,#3b82f633);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.clcosdk\\:shadow-\\[0_0_0_3px_rgba\\(59\\,130\\,246\\,0\\.18\\)\\]{--tw-shadow:0 0 0 3px var(--tw-shadow-color,#3b82f62e);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.clcosdk\\:shadow-\\[0_0_0_3px_rgba\\(59\\,130\\,246\\,0\\.25\\)\\]{--tw-shadow:0 0 0 3px var(--tw-shadow-color,#3b82f640);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.clcosdk\\:shadow-\\[0_10px_24px_rgba\\(0\\,0\\,0\\,0\\.18\\)\\]{--tw-shadow:0 10px 24px var(--tw-shadow-color,#0000002e);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.clcosdk\\:shadow-\\[0_10px_24px_rgba\\(0\\,0\\,0\\,0\\.25\\)\\]{--tw-shadow:0 10px 24px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.clcosdk\\:shadow-card{--tw-shadow:0px 4px 6px -2px var(--tw-shadow-color,#0000000d), 0px 12px 24px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.clcosdk\\:transition-\\[grid-template-rows\\]{transition-property:grid-template-rows;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.clcosdk\\:transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.clcosdk\\:transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.clcosdk\\:transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.clcosdk\\:duration-200{--tw-duration:.2s;transition-duration:.2s}.clcosdk\\:duration-300{--tw-duration:.3s;transition-duration:.3s}.clcosdk\\:ease-in-out{--tw-ease:var(--clcosdk-ease-in-out);transition-timing-function:var(--clcosdk-ease-in-out)}@media (hover:hover){.clcosdk\\:hover\\:-translate-y-0\\.5:hover{--tw-translate-y:calc(var(--clcosdk-spacing) * -.5);translate:var(--tw-translate-x) var(--tw-translate-y)}.clcosdk\\:hover\\:border-divider:hover{border-color:var(--color-divider)}.clcosdk\\:hover\\:bg-\\[\\#fcdcd8\\]:hover{background-color:#fcdcd8}.clcosdk\\:hover\\:bg-border:hover{background-color:var(--color-border)}.clcosdk\\:hover\\:bg-brand-primary:hover{background-color:var(--color-brand-primary)}.clcosdk\\:hover\\:bg-brand-primary-hover:hover{background-color:var(--color-brand-primary-hover)}.clcosdk\\:hover\\:bg-section:hover{background-color:var(--color-section)}.clcosdk\\:hover\\:bg-surface:hover{background-color:var(--color-surface)}.clcosdk\\:hover\\:text-\\[\\#8b1a13\\]:hover{color:#8b1a13}.clcosdk\\:hover\\:text-text-primary:hover{color:var(--color-text-primary)}.clcosdk\\:hover\\:underline:hover{text-decoration-line:underline}.clcosdk\\:hover\\:shadow-\\[0px_14px_32px_-10px_rgba\\(0\\,0\\,0\\,0\\.35\\)\\]:hover{--tw-shadow:0px 14px 32px -10px var(--tw-shadow-color,#00000059);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}}.clcosdk\\:focus-visible\\:ring-2:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.clcosdk\\:focus-visible\\:ring-accent-focus:focus-visible{--tw-ring-color:var(--color-accent-focus)}.clcosdk\\:focus-visible\\:ring-gray-400:focus-visible{--tw-ring-color:var(--clcosdk-color-gray-400)}.clcosdk\\:focus-visible\\:ring-gray-500:focus-visible{--tw-ring-color:var(--clcosdk-color-gray-500)}.clcosdk\\:focus-visible\\:ring-red-400:focus-visible{--tw-ring-color:var(--clcosdk-color-red-400)}.clcosdk\\:focus-visible\\:ring-red-500:focus-visible{--tw-ring-color:var(--clcosdk-color-red-500)}.clcosdk\\:focus-visible\\:ring-offset-2:focus-visible{--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.clcosdk\\:focus-visible\\:outline-none:focus-visible{--tw-outline-style:none;outline-style:none}.clcosdk\\:active\\:bg-\\[\\#d9d9d9\\]:active{background-color:#d9d9d9}.clcosdk\\:active\\:bg-\\[\\#f9c9c4\\]:active{background-color:#f9c9c4}.clcosdk\\:active\\:bg-border:active{background-color:var(--color-border)}.clcosdk\\:active\\:bg-brand-primary-active:active{background-color:var(--color-brand-primary-active)}.clcosdk\\:active\\:text-\\[\\#6d1510\\]:active{color:#6d1510}.clcosdk\\:disabled\\:pointer-events-none:disabled{pointer-events:none}.clcosdk\\:disabled\\:opacity-40:disabled{opacity:.4}@media (prefers-color-scheme:dark){@media (hover:hover){.clcosdk\\:dark\\:hover\\:bg-\\[rgba\\(248\\,113\\,113\\,0\\.20\\)\\]:not(:where(.light,.light *)):hover{background-color:#f8717133}}}@media (hover:hover){.clcosdk\\:dark\\:hover\\:bg-\\[rgba\\(248\\,113\\,113\\,0\\.20\\)\\]:where(.dark,.dark *):hover{background-color:#f8717133}}@media (prefers-color-scheme:dark){@media (hover:hover){.clcosdk\\:dark\\:hover\\:text-\\[\\#fca5a5\\]:not(:where(.light,.light *)):hover{color:#fca5a5}}}@media (hover:hover){.clcosdk\\:dark\\:hover\\:text-\\[\\#fca5a5\\]:where(.dark,.dark *):hover{color:#fca5a5}}@media (prefers-color-scheme:dark){.clcosdk\\:dark\\:active\\:bg-\\[rgba\\(248\\,113\\,113\\,0\\.30\\)\\]:not(:where(.light,.light *)):active{background-color:#f871714d}}.clcosdk\\:dark\\:active\\:bg-\\[rgba\\(248\\,113\\,113\\,0\\.30\\)\\]:where(.dark,.dark *):active{background-color:#f871714d}@media (prefers-color-scheme:dark){.clcosdk\\:dark\\:active\\:bg-divider:not(:where(.light,.light *)):active{background-color:var(--color-divider)}}.clcosdk\\:dark\\:active\\:bg-divider:where(.dark,.dark *):active{background-color:var(--color-divider)}@media (prefers-color-scheme:dark){.clcosdk\\:dark\\:active\\:text-\\[\\#f87171\\]:not(:where(.light,.light *)):active{color:#f87171}}.clcosdk\\:dark\\:active\\:text-\\[\\#f87171\\]:where(.dark,.dark *):active{color:#f87171}.clcosdk\\:\\[\\&_circle\\]\\:fill-error-subtle circle{fill:var(--color-error-subtle)}.clcosdk\\:\\[\\&_circle\\]\\:fill-success-subtle circle{fill:var(--color-success-subtle)}.clcosdk\\:\\[\\&_circle\\]\\:fill-warning-subtle circle{fill:var(--color-warning-subtle)}}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-gradient-position{syntax:"*";inherits:false}@property --tw-gradient-from{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-via{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-to{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-stops{syntax:"*";inherits:false}@property --tw-gradient-via-stops{syntax:"*";inherits:false}@property --tw-gradient-from-position{syntax:"<length-percentage>";inherits:false;initial-value:0%}@property --tw-gradient-via-position{syntax:"<length-percentage>";inherits:false;initial-value:50%}@property --tw-gradient-to-position{syntax:"<length-percentage>";inherits:false;initial-value:100%}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@keyframes spin{to{transform:rotate(360deg)}}@keyframes pulse{50%{opacity:.5}}';
2168
+
2169
+ // src/client/CoinListStyleScope.tsx
2170
+ var import_jsx_runtime2 = require("react/jsx-runtime");
2171
+ var ScopeContext = (0, import_react2.createContext)(false);
2172
+ function CoinListStyleScope({ children }) {
2173
+ const alreadyScoped = (0, import_react2.useContext)(ScopeContext);
2174
+ if (alreadyScoped) {
2175
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children });
2176
+ }
2177
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
2178
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("link", { rel: "preconnect", href: "https://fonts.googleapis.com" }),
2179
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2180
+ "link",
2181
+ {
2182
+ rel: "preconnect",
2183
+ href: "https://fonts.gstatic.com",
2184
+ crossOrigin: "anonymous"
2185
+ }
2186
+ ),
2187
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2188
+ "link",
2189
+ {
2190
+ rel: "stylesheet",
2191
+ href: "https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap"
2192
+ }
2193
+ ),
2194
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "clco-sdk-root", style: { display: "contents" }, children: [
2195
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2196
+ "style",
2197
+ {
2198
+ href: "clco-sdk-styles",
2199
+ precedence: "default",
2200
+ dangerouslySetInnerHTML: { __html: sdkStyles }
2201
+ }
2202
+ ),
2203
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ScopeContext.Provider, { value: true, children })
2204
+ ] })
2205
+ ] });
2206
+ }
1004
2207
 
1005
2208
  // src/client/components/design-system/AlertBanner.tsx
1006
2209
  var import_lucide_react = require("lucide-react");
1007
2210
 
1008
2211
  // src/client/components/design-system/tokens/typography.ts
1009
2212
  var typeClasses = {
1010
- hero: "text-[64px] leading-[110%] font-semibold",
1011
- display: "text-[48px] leading-[110%] font-semibold",
1012
- h1: "text-[36px] leading-[120%] font-semibold",
1013
- h2: "text-[28px] leading-[125%] font-semibold",
1014
- h3: "text-[22px] leading-[130%] font-semibold",
1015
- h4: "text-[18px] leading-[135%] font-medium",
1016
- body: "text-[16px] leading-[150%] font-normal",
1017
- subhead: "text-[14px] leading-[150%] font-normal",
1018
- caption: "text-[12px] leading-[140%] font-normal",
1019
- label: "text-[14px] leading-[140%] font-medium",
1020
- data: "text-[14px] leading-[140%] font-normal"
2213
+ hero: "clcosdk:text-[64px] clcosdk:leading-[110%] clcosdk:font-semibold",
2214
+ display: "clcosdk:text-[48px] clcosdk:leading-[110%] clcosdk:font-semibold",
2215
+ h1: "clcosdk:text-[36px] clcosdk:leading-[120%] clcosdk:font-semibold",
2216
+ h2: "clcosdk:text-[28px] clcosdk:leading-[125%] clcosdk:font-semibold",
2217
+ h3: "clcosdk:text-[22px] clcosdk:leading-[130%] clcosdk:font-semibold",
2218
+ h4: "clcosdk:text-[18px] clcosdk:leading-[135%] clcosdk:font-medium",
2219
+ body: "clcosdk:text-[16px] clcosdk:leading-[150%] clcosdk:font-normal",
2220
+ subhead: "clcosdk:text-[14px] clcosdk:leading-[150%] clcosdk:font-normal",
2221
+ caption: "clcosdk:text-[12px] clcosdk:leading-[140%] clcosdk:font-normal",
2222
+ label: "clcosdk:text-[14px] clcosdk:leading-[140%] clcosdk:font-medium",
2223
+ data: "clcosdk:text-[14px] clcosdk:leading-[140%] clcosdk:font-normal"
1021
2224
  };
1022
2225
 
1023
2226
  // src/client/components/design-system/utils.ts
@@ -1027,26 +2230,26 @@ function cn(...inputs) {
1027
2230
  }
1028
2231
 
1029
2232
  // src/client/components/design-system/AlertBanner.tsx
1030
- var import_jsx_runtime2 = require("react/jsx-runtime");
2233
+ var import_jsx_runtime3 = require("react/jsx-runtime");
1031
2234
  var variantConfig = {
1032
2235
  info: {
1033
- container: "bg-surface border-border",
1034
- text: "text-text-secondary",
2236
+ container: "clcosdk:bg-surface clcosdk:border-border",
2237
+ text: "clcosdk:text-text-secondary",
1035
2238
  Icon: import_lucide_react.Info
1036
2239
  },
1037
2240
  success: {
1038
- container: "bg-success-subtle border-success-border",
1039
- text: "text-success",
2241
+ container: "clcosdk:bg-success-subtle clcosdk:border-success-border",
2242
+ text: "clcosdk:text-success",
1040
2243
  Icon: import_lucide_react.CircleCheck
1041
2244
  },
1042
2245
  warning: {
1043
- container: "bg-warning-subtle border-warning-border",
1044
- text: "text-warning",
2246
+ container: "clcosdk:bg-warning-subtle clcosdk:border-warning-border",
2247
+ text: "clcosdk:text-warning",
1045
2248
  Icon: import_lucide_react.Info
1046
2249
  },
1047
2250
  error: {
1048
- container: "bg-error-subtle border-error-border",
1049
- text: "text-error",
2251
+ container: "clcosdk:bg-error-subtle clcosdk:border-error-border",
2252
+ text: "clcosdk:text-error",
1050
2253
  Icon: import_lucide_react.Info
1051
2254
  }
1052
2255
  };
@@ -1057,18 +2260,24 @@ function AlertBanner({
1057
2260
  className
1058
2261
  }) {
1059
2262
  const { container, text, Icon } = variantConfig[variant];
1060
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
2263
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1061
2264
  "div",
1062
2265
  {
1063
2266
  className: cn(
1064
- "flex items-center rounded-btn border p-3",
1065
- icon && "gap-2",
2267
+ "clcosdk:flex clcosdk:items-center clcosdk:rounded-btn clcosdk:border clcosdk:p-3",
2268
+ icon && "clcosdk:gap-2",
1066
2269
  container,
1067
2270
  className
1068
2271
  ),
1069
2272
  children: [
1070
- icon && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Icon, { className: cn("h-4 w-4 shrink-0", text), "aria-hidden": "true" }),
1071
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: cn(typeClasses.subhead, text), children: content })
2273
+ icon && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2274
+ Icon,
2275
+ {
2276
+ className: cn("clcosdk:h-4 clcosdk:w-4 clcosdk:shrink-0", text),
2277
+ "aria-hidden": "true"
2278
+ }
2279
+ ),
2280
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: cn(typeClasses.subhead, text), children: content })
1072
2281
  ]
1073
2282
  }
1074
2283
  );
@@ -1076,31 +2285,31 @@ function AlertBanner({
1076
2285
 
1077
2286
  // src/client/components/design-system/CloseButton.tsx
1078
2287
  var import_lucide_react2 = require("lucide-react");
1079
- var import_jsx_runtime3 = require("react/jsx-runtime");
2288
+ var import_jsx_runtime4 = require("react/jsx-runtime");
1080
2289
  function CloseButton({
1081
2290
  onClick,
1082
2291
  "aria-label": ariaLabel = "Close",
1083
2292
  className
1084
2293
  }) {
1085
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2294
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1086
2295
  "button",
1087
2296
  {
1088
2297
  type: "button",
1089
2298
  onClick,
1090
2299
  "aria-label": ariaLabel,
1091
2300
  className: cn(
1092
- "cursor-pointer rounded-full p-1.5 text-text-secondary transition-colors hover:bg-surface hover:text-text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-gray-400 focus-visible:ring-offset-2",
2301
+ "clcosdk:cursor-pointer clcosdk:rounded-full clcosdk:p-1.5 clcosdk:text-text-secondary clcosdk:transition-colors clcosdk:hover:bg-surface clcosdk:hover:text-text-primary clcosdk:focus-visible:outline-none clcosdk:focus-visible:ring-2 clcosdk:focus-visible:ring-gray-400 clcosdk:focus-visible:ring-offset-2",
1093
2302
  className
1094
2303
  ),
1095
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react2.X, { className: "h-5 w-5" })
2304
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react2.X, { className: "clcosdk:h-5 clcosdk:w-5" })
1096
2305
  }
1097
2306
  );
1098
2307
  }
1099
2308
 
1100
2309
  // src/client/components/design-system/logos/CoinListWordmark.tsx
1101
- var import_jsx_runtime4 = require("react/jsx-runtime");
2310
+ var import_jsx_runtime5 = require("react/jsx-runtime");
1102
2311
  function CoinListWordmark(props) {
1103
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
2312
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1104
2313
  "svg",
1105
2314
  {
1106
2315
  width: "638",
@@ -1111,35 +2320,35 @@ function CoinListWordmark(props) {
1111
2320
  "aria-hidden": "true",
1112
2321
  ...props,
1113
2322
  children: [
1114
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2323
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1115
2324
  "path",
1116
2325
  {
1117
2326
  d: "M68.7724 123.966C74.8226 124.172 80.7696 123.519 86.5104 121.799C97.4076 118.531 106.551 112.58 113.942 103.947C113.942 103.947 113.942 103.947 113.908 103.912C111.879 102.193 109.851 100.507 107.857 98.8218L105.829 97.1363C105.451 96.8268 105.107 96.5172 104.729 96.2076C103.939 95.5197 103.148 94.8662 102.323 94.2126C95.3107 98.8562 87.6104 101.539 79.1196 101.883C74.8569 102.055 70.6287 101.642 66.5036 100.507C59.5252 98.6154 53.2688 95.1757 48.2499 89.7755C39.1059 79.938 35.8745 68.1743 38.2465 55.0348C39.7246 46.9172 43.4373 40.0723 49.1093 34.5C47.9061 34.7408 46.703 35.016 45.5342 35.3943C36.5277 38.2148 29.6181 43.6839 24.6336 51.6639C20.6803 58.0273 18.5834 64.9411 18.3428 72.4739C18.2053 76.7047 18.4803 80.7979 19.4428 84.7879C22.5023 97.2395 29.3087 107.043 39.6903 114.335H39.7934V114.403C40.1372 114.644 40.4809 114.919 40.8247 115.16C49.2812 120.801 58.5971 123.691 68.7724 124.035V123.966Z",
1118
2327
  fill: "currentColor"
1119
2328
  }
1120
2329
  ),
1121
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2330
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1122
2331
  "path",
1123
2332
  {
1124
2333
  d: "M72.2101 89.052C68.1881 90.8406 64.0286 91.8725 59.6973 92.2165C64.9912 95.209 70.8007 96.688 77.1259 96.8256C79.1885 96.86 81.251 96.6536 83.4167 96.3097C88.745 95.4841 93.6951 93.5579 98.3015 90.7374C93.9358 87.057 89.6044 83.4109 85.2386 79.7305C81.526 83.6861 77.1946 86.8506 72.2101 89.052Z",
1125
2334
  fill: "currentColor"
1126
2335
  }
1127
2336
  ),
1128
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2337
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1129
2338
  "path",
1130
2339
  {
1131
2340
  d: "M66.9848 0.241609C66.4348 0.276006 65.8848 0.344799 65.3691 0.413592C70.663 1.4111 75.7851 3.13093 80.6321 5.71068C90.0511 10.7326 97.3732 17.9215 102.289 27.4494L104.936 25.1448C107.652 22.7714 110.368 20.3981 113.084 18.0247C106.655 11.1797 99.092 6.15784 90.223 3.06214C84.3103 0.998336 78.2601 -0.0335643 72.0381 0.000832319C70.388 0.000832319 68.7036 0.138419 66.9848 0.241609Z",
1132
2341
  fill: "currentColor"
1133
2342
  }
1134
2343
  ),
1135
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2344
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1136
2345
  "path",
1137
2346
  {
1138
2347
  d: "M25.4242 107.871C17.4833 97.9988 13.1519 86.7167 13.2207 73.818C13.2207 67.317 14.5614 61.0568 17.1396 55.1062C20.9553 46.2662 26.9711 39.1805 35.4276 34.2962C43.3685 29.687 51.9968 27.8984 61.1752 29.2743C70.5943 30.7189 78.3976 35.2249 84.6541 42.2762C84.6541 42.2762 84.8603 42.5514 84.9634 42.6546C85.8916 41.8291 86.8541 41.0035 87.7823 40.178L88.9167 39.1805C89.8792 38.355 90.8417 37.4951 91.8043 36.6696C94.0043 34.7434 96.17 32.8515 98.3357 30.9253C94.1075 22.223 87.7479 15.55 79.3258 10.8377C69.3911 5.26541 58.7002 3.54557 47.3904 5.02463C41.7528 5.78136 36.3557 7.50119 31.1993 10.0465C13.702 18.7145 1.08597 36.532 0.0546833 58.4771C-0.117196 62.0887 0.123436 65.7348 0.673452 69.3464C2.04849 78.3239 5.34859 86.4759 10.6425 93.8368C14.7676 99.5123 19.6834 104.19 25.3898 107.871H25.4242Z",
1139
2348
  fill: "currentColor"
1140
2349
  }
1141
2350
  ),
1142
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2351
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1143
2352
  "path",
1144
2353
  {
1145
2354
  fillRule: "evenodd",
@@ -1154,18 +2363,18 @@ function CoinListWordmark(props) {
1154
2363
  }
1155
2364
 
1156
2365
  // src/client/components/design-system/PoweredByCoinList.tsx
1157
- var import_jsx_runtime5 = require("react/jsx-runtime");
2366
+ var import_jsx_runtime6 = require("react/jsx-runtime");
1158
2367
  function PoweredByCoinList({ className }) {
1159
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
2368
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1160
2369
  "div",
1161
2370
  {
1162
2371
  className: cn(
1163
- "flex items-center justify-center gap-[5px] text-text-secondary",
2372
+ "clcosdk:flex clcosdk:items-center clcosdk:justify-center clcosdk:gap-[5px] clcosdk:text-text-secondary",
1164
2373
  className
1165
2374
  ),
1166
2375
  children: [
1167
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: cn(typeClasses.caption, "tracking-[0.12px]"), children: "Powered by" }),
1168
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CoinListWordmark, { className: "h-3 w-auto" })
2376
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: cn(typeClasses.caption, "clcosdk:tracking-[0.12px]"), children: "Powered by" }),
2377
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CoinListWordmark, { className: "clcosdk:h-3 clcosdk:w-auto" })
1169
2378
  ]
1170
2379
  }
1171
2380
  );
@@ -1173,49 +2382,49 @@ function PoweredByCoinList({ className }) {
1173
2382
 
1174
2383
  // src/client/components/design-system/ClButton.tsx
1175
2384
  var import_class_variance_authority = require("class-variance-authority");
1176
- var import_react2 = require("react");
1177
- var import_jsx_runtime6 = require("react/jsx-runtime");
2385
+ var import_react3 = require("react");
2386
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1178
2387
  var buttonVariants = (0, import_class_variance_authority.cva)(
1179
- "inline-flex items-center justify-center gap-3 whitespace-nowrap transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-40 cursor-pointer",
2388
+ "clcosdk:inline-flex clcosdk:items-center clcosdk:justify-center clcosdk:gap-3 clcosdk:whitespace-nowrap clcosdk:transition-colors clcosdk:focus-visible:outline-none clcosdk:focus-visible:ring-2 clcosdk:focus-visible:ring-offset-2 clcosdk:disabled:pointer-events-none clcosdk:disabled:opacity-40 clcosdk:cursor-pointer",
1180
2389
  {
1181
2390
  variants: {
1182
2391
  variant: {
1183
2392
  // Primary — tokens auto-switch: dark bg (#171717) → light bg (#f4f4f5) in dark mode
1184
- primary: "bg-brand-primary text-text-inverse font-semibold hover:bg-brand-primary-hover active:bg-brand-primary-active focus-visible:ring-gray-500",
2393
+ primary: "clcosdk:bg-brand-primary clcosdk:text-text-inverse clcosdk:font-semibold clcosdk:hover:bg-brand-primary-hover clcosdk:active:bg-brand-primary-active clcosdk:focus-visible:ring-gray-500",
1185
2394
  // Secondary — bg-section, border-border, text-text-primary all auto-switch
1186
2395
  // hover maps to border token value; active has no token so uses dark: override
1187
- secondary: "bg-section border border-border text-text-primary font-medium hover:bg-border active:bg-[#d9d9d9] dark:active:bg-divider focus-visible:ring-gray-400",
2396
+ secondary: "clcosdk:bg-section clcosdk:border clcosdk:border-border clcosdk:text-text-primary clcosdk:font-medium clcosdk:hover:bg-border clcosdk:active:bg-[#d9d9d9] clcosdk:dark:active:bg-divider clcosdk:focus-visible:ring-gray-400",
1188
2397
  // Destructive — error tokens auto-switch to translucent dark equivalents
1189
2398
  // hover/active have no tokens so use dark: overrides
1190
- destructive: "bg-error-subtle border border-error-border text-error font-semibold hover:bg-[#fcdcd8] active:bg-[#f9c9c4] dark:hover:bg-[rgba(248,113,113,0.20)] dark:active:bg-[rgba(248,113,113,0.30)] focus-visible:ring-red-400",
2399
+ destructive: "clcosdk:bg-error-subtle clcosdk:border clcosdk:border-error-border clcosdk:text-error clcosdk:font-semibold clcosdk:hover:bg-[#fcdcd8] clcosdk:active:bg-[#f9c9c4] clcosdk:dark:hover:bg-[rgba(248,113,113,0.20)] clcosdk:dark:active:bg-[rgba(248,113,113,0.30)] clcosdk:focus-visible:ring-red-400",
1191
2400
  // Ghost — transparent base; hover/active use section/border tokens (auto-switch)
1192
- ghost: "bg-transparent text-text-primary font-medium hover:bg-section active:bg-border focus-visible:ring-gray-400",
2401
+ ghost: "clcosdk:bg-transparent clcosdk:text-text-primary clcosdk:font-medium clcosdk:hover:bg-section clcosdk:active:bg-border clcosdk:focus-visible:ring-gray-400",
1193
2402
  // Link — text-text-primary auto-switches light/dark
1194
- link: "h-auto p-0 text-text-primary font-medium underline-offset-4 hover:underline focus-visible:ring-gray-500",
2403
+ link: "clcosdk:h-auto clcosdk:p-0 clcosdk:text-text-primary clcosdk:font-medium clcosdk:underline-offset-4 clcosdk:hover:underline clcosdk:focus-visible:ring-gray-500",
1195
2404
  // Destructive link — text-error auto-switches (#b42318 → #f87171 in dark)
1196
- destructiveLink: "h-auto p-0 text-error font-medium hover:text-[#8b1a13] active:text-[#6d1510] dark:hover:text-[#fca5a5] dark:active:text-[#f87171] focus-visible:ring-red-500"
2405
+ destructiveLink: "clcosdk:h-auto clcosdk:p-0 clcosdk:text-error clcosdk:font-medium clcosdk:hover:text-[#8b1a13] clcosdk:active:text-[#6d1510] clcosdk:dark:hover:text-[#fca5a5] clcosdk:dark:active:text-[#f87171] clcosdk:focus-visible:ring-red-500"
1197
2406
  },
1198
2407
  size: {
1199
- sm: "h-9 px-4 text-sm tracking-[0.28px]",
1200
- default: "h-11 px-5 text-sm tracking-[0.28px]",
1201
- lg: "h-14 px-6 text-base",
1202
- icon: "h-12 w-12"
2408
+ sm: "clcosdk:h-9 clcosdk:px-4 clcosdk:text-sm clcosdk:tracking-[0.28px]",
2409
+ default: "clcosdk:h-11 clcosdk:px-5 clcosdk:text-sm clcosdk:tracking-[0.28px]",
2410
+ lg: "clcosdk:h-14 clcosdk:px-6 clcosdk:text-base",
2411
+ icon: "clcosdk:h-12 clcosdk:w-12"
1203
2412
  },
1204
2413
  radius: {
1205
- pill: "rounded-full",
2414
+ pill: "clcosdk:rounded-full",
1206
2415
  // compound variants below handle size-specific radii
1207
2416
  rounded: ""
1208
2417
  },
1209
2418
  fullWidth: {
1210
- true: "w-full",
2419
+ true: "clcosdk:w-full",
1211
2420
  false: ""
1212
2421
  }
1213
2422
  },
1214
2423
  compoundVariants: [
1215
- { size: "sm", radius: "rounded", className: "rounded-lg" },
1216
- { size: "default", radius: "rounded", className: "rounded-2xl" },
1217
- { size: "lg", radius: "rounded", className: "rounded-2xl" },
1218
- { size: "icon", radius: "rounded", className: "rounded-md" }
2424
+ { size: "sm", radius: "rounded", className: "clcosdk:rounded-lg" },
2425
+ { size: "default", radius: "rounded", className: "clcosdk:rounded-2xl" },
2426
+ { size: "lg", radius: "rounded", className: "clcosdk:rounded-2xl" },
2427
+ { size: "icon", radius: "rounded", className: "clcosdk:rounded-md" }
1219
2428
  ],
1220
2429
  defaultVariants: {
1221
2430
  variant: "primary",
@@ -1225,7 +2434,7 @@ var buttonVariants = (0, import_class_variance_authority.cva)(
1225
2434
  }
1226
2435
  }
1227
2436
  );
1228
- var ClButton = (0, import_react2.forwardRef)(
2437
+ var ClButton = (0, import_react3.forwardRef)(
1229
2438
  ({
1230
2439
  className,
1231
2440
  variant,
@@ -1241,7 +2450,7 @@ var ClButton = (0, import_react2.forwardRef)(
1241
2450
  ...props
1242
2451
  }, ref) => {
1243
2452
  const isDisabled = disabled || isLoading;
1244
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2453
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1245
2454
  "button",
1246
2455
  {
1247
2456
  className: cn(
@@ -1252,16 +2461,16 @@ var ClButton = (0, import_react2.forwardRef)(
1252
2461
  disabled: isDisabled,
1253
2462
  ...props,
1254
2463
  children: [
1255
- isLoading && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2464
+ isLoading && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1256
2465
  "span",
1257
2466
  {
1258
- className: "h-4 w-4 shrink-0 animate-spin rounded-full border-2 border-current border-t-transparent opacity-60",
2467
+ className: "clcosdk:h-4 clcosdk:w-4 clcosdk:shrink-0 clcosdk:animate-spin clcosdk:rounded-full clcosdk:border-2 clcosdk:border-current clcosdk:border-t-transparent clcosdk:opacity-60",
1259
2468
  "aria-hidden": "true"
1260
2469
  }
1261
2470
  ),
1262
- startIcon && !isLoading && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "shrink-0", children: startIcon }),
1263
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: cn(isLoading && "opacity-60"), children: isLoading && loadingText ? loadingText : children }),
1264
- endIcon && !isLoading && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "shrink-0", children: endIcon })
2471
+ startIcon && !isLoading && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "clcosdk:shrink-0", children: startIcon }),
2472
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: cn(isLoading && "clcosdk:opacity-60"), children: isLoading && loadingText ? loadingText : children }),
2473
+ endIcon && !isLoading && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "clcosdk:shrink-0", children: endIcon })
1265
2474
  ]
1266
2475
  }
1267
2476
  );
@@ -1270,9 +2479,9 @@ var ClButton = (0, import_react2.forwardRef)(
1270
2479
  ClButton.displayName = "ClButton";
1271
2480
 
1272
2481
  // src/client/components/design-system/logos/CoinListLogomark.tsx
1273
- var import_jsx_runtime7 = require("react/jsx-runtime");
2482
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1274
2483
  function CoinListLogomark(props) {
1275
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
2484
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1276
2485
  "svg",
1277
2486
  {
1278
2487
  width: "115",
@@ -1283,28 +2492,28 @@ function CoinListLogomark(props) {
1283
2492
  "aria-hidden": "true",
1284
2493
  ...props,
1285
2494
  children: [
1286
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2495
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1287
2496
  "path",
1288
2497
  {
1289
2498
  d: "M69.7519 123.966C75.8021 124.172 81.7491 123.519 87.4899 121.799C98.3871 118.531 107.531 112.58 114.922 103.947C114.922 103.947 114.922 103.947 114.888 103.912C112.859 102.193 110.831 100.507 108.837 98.8218L106.809 97.1363C106.431 96.8268 106.087 96.5172 105.709 96.2076C104.919 95.5197 104.128 94.8662 103.303 94.2126C96.2902 98.8562 88.5899 101.539 80.0991 101.883C75.8364 102.055 71.6082 101.642 67.4831 100.507C60.5047 98.6154 54.2483 95.1757 49.2294 89.7755C40.0854 79.938 36.854 68.1743 39.226 55.0348C40.7041 46.9172 44.4168 40.0723 50.0888 34.5C48.8856 34.7408 47.6825 35.016 46.5137 35.3943C37.5072 38.2148 30.5976 43.6839 25.6131 51.6639C21.6598 58.0273 19.5629 64.9411 19.3223 72.4739C19.1848 76.7047 19.4598 80.7979 20.4223 84.7879C23.4818 97.2395 30.2882 107.043 40.6698 114.335H40.7729V114.403C41.1167 114.644 41.4604 114.919 41.8042 115.16C50.2607 120.801 59.5766 123.691 69.7519 124.035V123.966Z",
1290
2499
  fill: "currentColor"
1291
2500
  }
1292
2501
  ),
1293
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2502
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1294
2503
  "path",
1295
2504
  {
1296
2505
  d: "M73.1896 89.052C69.1676 90.8406 65.0081 91.8725 60.6768 92.2165C65.9707 95.209 71.7802 96.688 78.1054 96.8256C80.168 96.86 82.2305 96.6536 84.3962 96.3097C89.7245 95.4841 94.6746 93.5579 99.281 90.7374C94.9153 87.057 90.5839 83.4109 86.2181 79.7305C82.5055 83.6861 78.1741 86.8506 73.1896 89.052Z",
1297
2506
  fill: "currentColor"
1298
2507
  }
1299
2508
  ),
1300
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2509
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1301
2510
  "path",
1302
2511
  {
1303
2512
  d: "M67.9643 0.241609C67.4143 0.276006 66.8643 0.344799 66.3486 0.413592C71.6425 1.4111 76.7646 3.13093 81.6116 5.71068C91.0306 10.7326 98.3527 17.9215 103.268 27.4494L105.915 25.1448C108.631 22.7714 111.347 20.3981 114.063 18.0247C107.634 11.1797 100.072 6.15784 91.2025 3.06214C85.2898 0.998336 79.2396 -0.0335643 73.0176 0.000832322C71.3675 0.000832322 69.6831 0.138419 67.9643 0.241609Z",
1304
2513
  fill: "currentColor"
1305
2514
  }
1306
2515
  ),
1307
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2516
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1308
2517
  "path",
1309
2518
  {
1310
2519
  d: "M26.4037 107.871C18.4628 97.9988 14.1314 86.7167 14.2002 73.818C14.2002 67.317 15.5409 61.0568 18.1191 55.1062C21.9348 46.2662 27.9506 39.1805 36.4071 34.2962C44.348 29.687 52.9763 27.8984 62.1547 29.2743C71.5738 30.7189 79.3771 35.2249 85.6336 42.2762C85.6336 42.2762 85.8398 42.5514 85.9429 42.6546C86.8711 41.8291 87.8336 41.0035 88.7618 40.178L89.8962 39.1805C90.8587 38.355 91.8212 37.4951 92.7838 36.6696C94.9838 34.7434 97.1495 32.8515 99.3152 30.9253C95.087 22.223 88.7274 15.55 80.3053 10.8377C70.3706 5.26541 59.6797 3.54557 48.37 5.02463C42.7323 5.78136 37.3352 7.50119 32.1788 10.0465C14.6815 18.7145 2.06546 36.532 1.03418 58.4771C0.862296 62.0887 1.10293 65.7348 1.65294 69.3464C3.02798 78.3239 6.32808 86.4759 11.622 93.8368C15.7471 99.5123 20.6629 104.19 26.3693 107.871H26.4037Z",
@@ -1317,7 +2526,7 @@ function CoinListLogomark(props) {
1317
2526
  }
1318
2527
 
1319
2528
  // src/client/components/oauth/CoinListSignInButton.tsx
1320
- var import_jsx_runtime8 = require("react/jsx-runtime");
2529
+ var import_jsx_runtime9 = require("react/jsx-runtime");
1321
2530
  function CoinListSignInButton({
1322
2531
  onClick,
1323
2532
  disabled = false,
@@ -1325,7 +2534,7 @@ function CoinListSignInButton({
1325
2534
  isLoading = false,
1326
2535
  className
1327
2536
  }) {
1328
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2537
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1329
2538
  ClButton,
1330
2539
  {
1331
2540
  variant: "primary",
@@ -1335,7 +2544,7 @@ function CoinListSignInButton({
1335
2544
  disabled,
1336
2545
  isLoading,
1337
2546
  loadingText: "Signing in...",
1338
- startIcon: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CoinListLogomark, { className: "h-[18px] w-[16px] shrink-0" }),
2547
+ startIcon: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(CoinListLogomark, { className: "clcosdk:h-[18px] clcosdk:w-[16px] clcosdk:shrink-0" }),
1339
2548
  className,
1340
2549
  children: "Continue with CoinList"
1341
2550
  }
@@ -1343,9 +2552,9 @@ function CoinListSignInButton({
1343
2552
  }
1344
2553
 
1345
2554
  // src/client/hooks/useCoinList.ts
1346
- var import_react3 = require("react");
2555
+ var import_react4 = require("react");
1347
2556
  function useCoinList() {
1348
- const context = (0, import_react3.useContext)(CoinListContext);
2557
+ const context = (0, import_react4.useContext)(CoinListContext);
1349
2558
  if (context === null) {
1350
2559
  throw new CoinListClientInitializationError();
1351
2560
  }
@@ -1362,7 +2571,7 @@ var CoinListClientInitializationError = class extends Error {
1362
2571
  };
1363
2572
 
1364
2573
  // src/client/components/oauth/CoinListSignInCard.tsx
1365
- var import_jsx_runtime9 = require("react/jsx-runtime");
2574
+ var import_jsx_runtime10 = require("react/jsx-runtime");
1366
2575
  function CoinListSignInCard({
1367
2576
  state = "idle",
1368
2577
  onSignIn,
@@ -1373,37 +2582,50 @@ function CoinListSignInCard({
1373
2582
  const handleSignIn = onSignIn ?? (() => {
1374
2583
  void coinlist.startOAuth();
1375
2584
  });
1376
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2585
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(CoinListStyleScope, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1377
2586
  "div",
1378
2587
  {
1379
2588
  className: cn(
1380
- "relative flex w-full max-w-md flex-col rounded-card border border-border bg-background p-6 shadow-card",
2589
+ "clcosdk:relative clcosdk:flex clcosdk:w-full clcosdk:max-w-md clcosdk:flex-col clcosdk:rounded-card clcosdk:border clcosdk:border-border clcosdk:bg-background clcosdk:p-6 clcosdk:shadow-card",
1381
2590
  className
1382
2591
  ),
1383
2592
  children: [
1384
- onClose && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(CloseButton, { onClick: onClose, className: "absolute right-4 top-4" }),
1385
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col gap-2", children: [
1386
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h3", { className: cn(typeClasses.h3, "text-text-primary"), children: "Sign in to participate" }),
1387
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: cn(typeClasses.body, "text-text-secondary"), children: "A CoinList account is required to participate in this sale." })
2593
+ onClose && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2594
+ CloseButton,
2595
+ {
2596
+ onClick: onClose,
2597
+ className: "clcosdk:absolute clcosdk:right-4 clcosdk:top-4"
2598
+ }
2599
+ ),
2600
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-2", children: [
2601
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h3", { className: cn(typeClasses.h3, "clcosdk:text-text-primary"), children: "Sign in to participate" }),
2602
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: cn(typeClasses.body, "clcosdk:text-text-secondary"), children: "A CoinList account is required to participate in this sale." })
1388
2603
  ] }),
1389
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(CoinListSignInButton, { onClick: handleSignIn, fullWidth: true, className: "mt-4" }),
1390
- state === "error" && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2604
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2605
+ CoinListSignInButton,
2606
+ {
2607
+ onClick: handleSignIn,
2608
+ fullWidth: true,
2609
+ className: "clcosdk:mt-4"
2610
+ }
2611
+ ),
2612
+ state === "error" && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1391
2613
  AlertBanner,
1392
2614
  {
1393
2615
  variant: "error",
1394
2616
  icon: true,
1395
2617
  content: "Error signing in. Please try again.",
1396
- className: "mt-4"
2618
+ className: "clcosdk:mt-4"
1397
2619
  }
1398
2620
  ),
1399
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(PoweredByCoinList, { className: "mt-4" })
2621
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PoweredByCoinList, { className: "clcosdk:mt-4" })
1400
2622
  ]
1401
2623
  }
1402
- );
2624
+ ) });
1403
2625
  }
1404
2626
 
1405
2627
  // src/client/components/offers/OfferCard.tsx
1406
- var import_jsx_runtime10 = require("react/jsx-runtime");
2628
+ var import_jsx_runtime11 = require("react/jsx-runtime");
1407
2629
  var monthYearFormatter = new Intl.DateTimeFormat("en-US", {
1408
2630
  month: "short",
1409
2631
  year: "numeric"
@@ -1424,46 +2646,67 @@ function OfferCard({
1424
2646
  containerClassName
1425
2647
  }) {
1426
2648
  const cardLabel = "Open offer details";
1427
- const cardContent = /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
1428
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "relative mb-6 h-52 w-full overflow-hidden rounded-2xl border border-border/60 bg-section", children: [
1429
- offer.bannerUrl ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2649
+ const cardContent = /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
2650
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "clcosdk:relative clcosdk:mb-6 clcosdk:h-52 clcosdk:w-full clcosdk:overflow-hidden clcosdk:rounded-2xl clcosdk:border clcosdk:border-border/60 clcosdk:bg-section", children: [
2651
+ offer.bannerUrl ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1430
2652
  "img",
1431
2653
  {
1432
2654
  src: offer.bannerUrl,
1433
2655
  alt: "Offer banner",
1434
- className: "h-full w-full object-cover"
2656
+ className: "clcosdk:h-full clcosdk:w-full clcosdk:object-cover"
1435
2657
  }
1436
- ) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "h-full w-full bg-gradient-to-br from-surface via-section to-background" }),
1437
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "absolute inset-0 bg-gradient-to-b from-transparent via-transparent to-overlay/35" }),
1438
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "absolute inset-0 flex items-center justify-center p-6", children: offer.logoUrl ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2658
+ ) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "clcosdk:h-full clcosdk:w-full clcosdk:bg-gradient-to-br clcosdk:from-surface clcosdk:via-section clcosdk:to-background" }),
2659
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "clcosdk:absolute clcosdk:inset-0 clcosdk:bg-gradient-to-b clcosdk:from-transparent clcosdk:via-transparent clcosdk:to-overlay/35" }),
2660
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "clcosdk:absolute clcosdk:inset-0 clcosdk:flex clcosdk:items-center clcosdk:justify-center clcosdk:p-6", children: offer.logoUrl ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1439
2661
  "img",
1440
2662
  {
1441
2663
  src: offer.logoUrl,
1442
2664
  alt: "Offer logo",
1443
- className: "h-28 w-28 rounded-full border border-border bg-surface object-cover shadow-[0_10px_24px_rgba(0,0,0,0.25)]"
2665
+ className: "clcosdk:h-28 clcosdk:w-28 clcosdk:rounded-full clcosdk:border clcosdk:border-border clcosdk:bg-surface clcosdk:object-cover clcosdk:shadow-[0_10px_24px_rgba(0,0,0,0.25)]"
1444
2666
  }
1445
- ) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "h-28 w-28 rounded-full border border-border bg-surface shadow-[0_10px_24px_rgba(0,0,0,0.18)]" }) })
2667
+ ) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "clcosdk:h-28 clcosdk:w-28 clcosdk:rounded-full clcosdk:border clcosdk:border-border clcosdk:bg-surface clcosdk:shadow-[0_10px_24px_rgba(0,0,0,0.18)]" }) })
1446
2668
  ] }),
1447
- offer.tagline && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: cn(typeClasses.h3, "min-h-[2.4rem] text-text-primary"), children: offer.tagline }),
1448
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "mt-4 grid grid-cols-2 gap-5 border-t border-divider pt-4", children: [
1449
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col gap-1", children: [
1450
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: cn(typeClasses.subhead, "text-text-secondary"), children: "Starts" }),
1451
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: cn(typeClasses.label, "text-text-primary"), children: offer.formattedStartsAt })
2669
+ offer.tagline && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2670
+ "p",
2671
+ {
2672
+ className: cn(
2673
+ typeClasses.h3,
2674
+ "clcosdk:min-h-[2.4rem] clcosdk:text-text-primary"
2675
+ ),
2676
+ children: offer.tagline
2677
+ }
2678
+ ),
2679
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "clcosdk:mt-4 clcosdk:grid clcosdk:grid-cols-2 clcosdk:gap-5 clcosdk:border-t clcosdk:border-divider clcosdk:pt-4", children: [
2680
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-1", children: [
2681
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2682
+ "span",
2683
+ {
2684
+ className: cn(typeClasses.subhead, "clcosdk:text-text-secondary"),
2685
+ children: "Starts"
2686
+ }
2687
+ ),
2688
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: cn(typeClasses.label, "clcosdk:text-text-primary"), children: offer.formattedStartsAt })
1452
2689
  ] }),
1453
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col gap-1", children: [
1454
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: cn(typeClasses.subhead, "text-text-secondary"), children: "Ends" }),
1455
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: cn(typeClasses.label, "text-text-primary"), children: offer.formattedEndsAt })
2690
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-1", children: [
2691
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2692
+ "span",
2693
+ {
2694
+ className: cn(typeClasses.subhead, "clcosdk:text-text-secondary"),
2695
+ children: "Ends"
2696
+ }
2697
+ ),
2698
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: cn(typeClasses.label, "clcosdk:text-text-primary"), children: offer.formattedEndsAt })
1456
2699
  ] })
1457
2700
  ] })
1458
2701
  ] });
1459
2702
  const baseClasses = cn(
1460
- "relative flex w-full max-w-[28rem] flex-col rounded-card border border-border bg-background p-6 text-left shadow-card transition-all duration-200",
2703
+ "clcosdk:relative clcosdk:flex clcosdk:w-full clcosdk:max-w-[28rem] clcosdk:flex-col clcosdk:rounded-card clcosdk:border clcosdk:border-border clcosdk:bg-background clcosdk:p-6 clcosdk:text-left clcosdk:shadow-card clcosdk:transition-all clcosdk:duration-200",
1461
2704
  className,
1462
- onClick && "cursor-pointer hover:-translate-y-0.5 hover:border-divider hover:shadow-[0px_14px_32px_-10px_rgba(0,0,0,0.35)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent-focus focus-visible:ring-offset-2"
2705
+ onClick && "clcosdk:cursor-pointer clcosdk:hover:-translate-y-0.5 clcosdk:hover:border-divider clcosdk:hover:shadow-[0px_14px_32px_-10px_rgba(0,0,0,0.35)] clcosdk:focus-visible:outline-none clcosdk:focus-visible:ring-2 clcosdk:focus-visible:ring-accent-focus clcosdk:focus-visible:ring-offset-2"
1463
2706
  );
1464
2707
  let cardNode;
1465
2708
  if (onClick) {
1466
- cardNode = /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2709
+ cardNode = /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1467
2710
  "button",
1468
2711
  {
1469
2712
  type: "button",
@@ -1474,24 +2717,22 @@ function OfferCard({
1474
2717
  }
1475
2718
  );
1476
2719
  } else {
1477
- cardNode = /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: baseClasses, children: cardContent });
1478
- }
1479
- if (!containerClassName) {
1480
- return cardNode;
2720
+ cardNode = /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: baseClasses, children: cardContent });
1481
2721
  }
1482
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: containerClassName, children: cardNode });
2722
+ const card = containerClassName ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: containerClassName, children: cardNode }) : cardNode;
2723
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(CoinListStyleScope, { children: card });
1483
2724
  }
1484
2725
 
1485
2726
  // src/client/hooks/useOffers.ts
1486
- var import_react4 = require("react");
2727
+ var import_react5 = require("react");
1487
2728
  var LOADING_STATE = { type: "LOADING" };
1488
2729
  function useOffers(options = {}) {
1489
2730
  const { coinlist, isReady } = useCoinList();
1490
2731
  const { data: serverOffers } = options;
1491
- const [offersState, setOffersState] = (0, import_react4.useState)(
2732
+ const [offersState, setOffersState] = (0, import_react5.useState)(
1492
2733
  serverOffers !== void 0 ? { type: "CONTENT", offers: serverOffers } : LOADING_STATE
1493
2734
  );
1494
- (0, import_react4.useEffect)(() => {
2735
+ (0, import_react5.useEffect)(() => {
1495
2736
  let isCancelled = false;
1496
2737
  if (!isReady) {
1497
2738
  if (serverOffers === void 0) {
@@ -1525,9 +2766,9 @@ function useOffers(options = {}) {
1525
2766
  }
1526
2767
 
1527
2768
  // src/client/components/offers/OffersGrid.tsx
1528
- var import_jsx_runtime11 = require("react/jsx-runtime");
2769
+ var import_jsx_runtime12 = require("react/jsx-runtime");
1529
2770
  var DEFAULT_MAX_COLUMNS = 3;
1530
- function OffersGrid({
2771
+ function OffersGridBody({
1531
2772
  data,
1532
2773
  maxColumns,
1533
2774
  className,
@@ -1543,12 +2784,12 @@ function OffersGrid({
1543
2784
  if (loading) {
1544
2785
  return loading;
1545
2786
  }
1546
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2787
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1547
2788
  "output",
1548
2789
  {
1549
2790
  "aria-live": "polite",
1550
- className: "flex min-h-40 items-center justify-center rounded-2xl border border-border bg-background p-6",
1551
- children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: cn(typeClasses.body, "text-text-secondary"), children: "Loading offers..." })
2791
+ 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",
2792
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: cn(typeClasses.body, "clcosdk:text-text-secondary"), children: "Loading offers..." })
1552
2793
  }
1553
2794
  );
1554
2795
  }
@@ -1557,13 +2798,13 @@ function OffersGrid({
1557
2798
  return error;
1558
2799
  }
1559
2800
  const errorMessage = offersState.reason === "not-authenticated" ? "Sign in to view available offers." : "Unable to load offers right now. Please try again.";
1560
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2801
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1561
2802
  AlertBanner,
1562
2803
  {
1563
2804
  variant: "error",
1564
2805
  icon: true,
1565
2806
  content: errorMessage,
1566
- className: "w-full max-w-[28rem]"
2807
+ className: "clcosdk:w-full clcosdk:max-w-[28rem]"
1567
2808
  }
1568
2809
  );
1569
2810
  }
@@ -1571,290 +2812,1410 @@ function OffersGrid({
1571
2812
  if (emptyState) {
1572
2813
  return emptyState;
1573
2814
  }
1574
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
2815
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
1575
2816
  "output",
1576
2817
  {
1577
2818
  "aria-live": "polite",
1578
- className: "flex min-h-40 flex-col items-center justify-center rounded-2xl border border-border bg-background p-6 text-center",
2819
+ className: "clcosdk:flex clcosdk:min-h-40 clcosdk:flex-col clcosdk:items-center clcosdk:justify-center clcosdk:rounded-2xl clcosdk:border clcosdk:border-border clcosdk:bg-background clcosdk:p-6 clcosdk:text-center",
1579
2820
  children: [
1580
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: cn(typeClasses.body, "font-medium text-text-primary"), children: "No offers available" }),
1581
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: cn(typeClasses.subhead, "text-text-secondary"), children: "Check back soon for upcoming opportunities." })
2821
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2822
+ "p",
2823
+ {
2824
+ className: cn(
2825
+ typeClasses.body,
2826
+ "clcosdk:font-medium clcosdk:text-text-primary"
2827
+ ),
2828
+ children: "No offers available"
2829
+ }
2830
+ ),
2831
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: cn(typeClasses.subhead, "clcosdk:text-text-secondary"), children: "Check back soon for upcoming opportunities." })
1582
2832
  ]
1583
2833
  }
1584
2834
  );
1585
2835
  }
1586
2836
  const maxGridWidth = `calc(${cols} * 28rem + ${Math.max(cols - 1, 0)} * 1.5rem)`;
1587
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: cn("flex w-full justify-center", containerClassName), children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2837
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1588
2838
  "div",
1589
2839
  {
1590
- className: cn("grid w-full gap-6", className),
1591
- style: {
1592
- gridTemplateColumns: "repeat(auto-fit, minmax(min(100%, 20rem), 1fr))",
1593
- maxWidth: maxGridWidth
1594
- },
1595
- children: offersState.offers.map((offer) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1596
- OfferCard,
2840
+ className: cn(
2841
+ "clcosdk:flex clcosdk:w-full clcosdk:justify-center",
2842
+ containerClassName
2843
+ ),
2844
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2845
+ "div",
1597
2846
  {
1598
- offer: OfferCardUi.fromDomain(offer),
1599
- onClick: onOfferClick ? () => onOfferClick(offer) : void 0
1600
- },
1601
- offer.id
1602
- ))
1603
- }
1604
- ) });
1605
- }
1606
-
1607
- // src/client/components/requirements/RequirementItem.tsx
1608
- var import_lucide_react4 = require("lucide-react");
1609
-
1610
- // src/client/components/design-system/StepStatusIcon.tsx
1611
- var import_lucide_react3 = require("lucide-react");
1612
- var import_jsx_runtime12 = require("react/jsx-runtime");
1613
- var statusConfig = {
1614
- required: {
1615
- Icon: import_lucide_react3.Info,
1616
- colorClass: "text-warning",
1617
- fillClass: "[&_circle]:fill-warning-subtle"
1618
- },
1619
- pending: {
1620
- Icon: import_lucide_react3.Info,
1621
- colorClass: "text-warning",
1622
- fillClass: "[&_circle]:fill-warning-subtle"
1623
- },
1624
- completed: {
1625
- Icon: import_lucide_react3.CircleCheck,
1626
- colorClass: "text-success",
1627
- fillClass: "[&_circle]:fill-success-subtle"
1628
- },
1629
- rejected: {
1630
- Icon: import_lucide_react3.CircleX,
1631
- colorClass: "text-error",
1632
- fillClass: "[&_circle]:fill-error-subtle"
1633
- }
1634
- };
1635
- function StepStatusIcon({ status, className }) {
1636
- const { Icon, colorClass, fillClass } = statusConfig[status];
1637
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1638
- Icon,
1639
- {
1640
- className: cn("h-6 w-6 shrink-0", colorClass, fillClass, className),
1641
- "aria-hidden": "true"
2847
+ className: cn("clcosdk:grid clcosdk:w-full clcosdk:gap-6", className),
2848
+ style: {
2849
+ gridTemplateColumns: "repeat(auto-fit, minmax(min(100%, 20rem), 1fr))",
2850
+ maxWidth: maxGridWidth
2851
+ },
2852
+ children: offersState.offers.map((offer) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2853
+ OfferCard,
2854
+ {
2855
+ offer: OfferCardUi.fromDomain(offer),
2856
+ onClick: onOfferClick ? () => onOfferClick(offer) : void 0
2857
+ },
2858
+ offer.id
2859
+ ))
2860
+ }
2861
+ )
1642
2862
  }
1643
2863
  );
1644
2864
  }
2865
+ function OffersGrid(props = {}) {
2866
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(CoinListStyleScope, { children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(OffersGridBody, { ...props }) });
2867
+ }
1645
2868
 
1646
- // src/client/components/requirements/RequirementItem.tsx
2869
+ // src/client/components/requirements/ConnectedWalletList.tsx
2870
+ var import_react6 = require("react");
1647
2871
  var import_jsx_runtime13 = require("react/jsx-runtime");
1648
- var RequirementVariant = {
1649
- fromType(type) {
1650
- switch (type) {
1651
- case "external_wallet":
1652
- case "whitelisted_wallet":
1653
- return "wallet";
1654
- default:
1655
- return "verification";
1656
- }
1657
- }
1658
- };
1659
- var RequirementStatus = {
1660
- fromStatusValue(status) {
1661
- switch (status) {
1662
- case "not_started":
1663
- case "action_needed":
1664
- return "required";
1665
- case "in_progress":
1666
- return "pending";
1667
- case "completed":
1668
- return "completed";
1669
- case "rejected":
1670
- return "rejected";
1671
- }
1672
- }
1673
- };
1674
- var ChecklistStatus = {
1675
- derive(statuses) {
1676
- if (statuses.some((s) => s.status === "rejected")) return "ineligible";
1677
- if (statuses.every((s) => s.status === "completed")) return "eligible";
1678
- return "inProgress";
1679
- }
1680
- };
1681
- var RequirementItemUi = {
1682
- fromDomain(req, statusInfo, label, description, walletAddress) {
1683
- return {
1684
- variant: RequirementVariant.fromType(req.type),
1685
- status: statusInfo ? RequirementStatus.fromStatusValue(statusInfo.status) : "required",
1686
- label,
1687
- description,
1688
- walletAddress
1689
- };
1690
- }
1691
- };
1692
- function VerificationActionZone({
1693
- status,
1694
- onAction,
1695
- onContactSupport
2872
+ function ConnectedWalletRow({
2873
+ wallet,
2874
+ onRemove
1696
2875
  }) {
1697
- switch (status) {
1698
- case "required":
1699
- if (onAction === null) return null;
1700
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ClButton, { size: "sm", onClick: onAction, children: "Continue" });
1701
- case "pending":
1702
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1703
- AlertBanner,
1704
- {
1705
- variant: "warning",
1706
- content: "Under review. We'll notify you when complete."
1707
- }
1708
- );
1709
- case "completed":
1710
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(AlertBanner, { variant: "success", content: "Identity verified." });
1711
- case "rejected":
1712
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1713
- AlertBanner,
2876
+ const [state, setState] = (0, import_react6.useState)("idle");
2877
+ const remove = async () => {
2878
+ if (!onRemove) return;
2879
+ setState("removing");
2880
+ try {
2881
+ await onRemove(wallet.id);
2882
+ setState("idle");
2883
+ } catch {
2884
+ setState("error");
2885
+ }
2886
+ };
2887
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "clcosdk:flex clcosdk:min-h-9 clcosdk:flex-wrap clcosdk:items-center clcosdk:justify-between clcosdk:gap-2", children: [
2888
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2889
+ "span",
2890
+ {
2891
+ title: wallet.address,
2892
+ className: cn(
2893
+ typeClasses.body,
2894
+ "clcosdk:font-mono clcosdk:text-text-primary"
2895
+ ),
2896
+ children: wallet.shortAddress
2897
+ }
2898
+ ),
2899
+ onRemove != null && (state === "confirming" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "clcosdk:flex clcosdk:items-center clcosdk:gap-2", children: [
2900
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2901
+ "span",
1714
2902
  {
1715
- variant: "error",
1716
- content: onContactSupport === null ? "Verification rejected." : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
1717
- "Verification rejected.",
1718
- " ",
1719
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1720
- "button",
1721
- {
1722
- type: "button",
1723
- onClick: onContactSupport,
1724
- className: "underline",
1725
- children: "Contact support"
1726
- }
1727
- ),
1728
- "."
1729
- ] })
2903
+ className: cn(typeClasses.subhead, "clcosdk:text-text-secondary"),
2904
+ children: "Remove?"
1730
2905
  }
1731
- );
1732
- }
1733
- }
1734
- function WalletActionZone({
1735
- status,
1736
- walletAddress,
1737
- onAction
1738
- }) {
1739
- if (status === "completed") {
1740
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
1741
- onAction !== null && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ClButton, { size: "sm", variant: "secondary", onClick: onAction, children: "Change wallet" }),
2906
+ ),
2907
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ClButton, { size: "sm", variant: "destructive", onClick: remove, children: "Remove" }),
1742
2908
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1743
- AlertBanner,
2909
+ ClButton,
1744
2910
  {
1745
- variant: "success",
1746
- content: walletAddress ?? "Connected: 0xBa4b...9f2c"
2911
+ size: "sm",
2912
+ variant: "ghost",
2913
+ onClick: () => setState("idle"),
2914
+ children: "Cancel"
1747
2915
  }
1748
2916
  )
1749
- ] });
1750
- }
1751
- if (status === "rejected") {
1752
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
1753
- onAction !== null && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ClButton, { size: "sm", onClick: onAction, children: "Connect wallet" }),
2917
+ ] }) : state === "error" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "clcosdk:flex clcosdk:items-center clcosdk:gap-2", children: [
2918
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: cn(typeClasses.subhead, "clcosdk:text-error"), children: "Couldn't remove." }),
1754
2919
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1755
- AlertBanner,
2920
+ ClButton,
1756
2921
  {
1757
- variant: "error",
1758
- content: "This wallet is not eligible for this sale."
2922
+ size: "sm",
2923
+ variant: "destructiveLink",
2924
+ onClick: () => setState("confirming"),
2925
+ children: "Try again"
1759
2926
  }
1760
2927
  )
1761
- ] });
1762
- }
1763
- if (onAction === null) return null;
1764
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ClButton, { size: "sm", onClick: onAction, children: "Connect wallet" });
1765
- }
1766
- function RequirementItem({
1767
- ui,
1768
- expanded = false,
1769
- onToggle,
1770
- className,
1771
- onAction,
1772
- onContactSupport
1773
- }) {
1774
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: cn("flex w-full flex-col", className), children: [
1775
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1776
- "button",
2928
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2929
+ ClButton,
1777
2930
  {
1778
- type: "button",
1779
- onClick: onToggle,
1780
- "aria-expanded": expanded,
1781
- className: "flex h-14 w-full cursor-pointer items-center justify-between rounded-2xl px-2 transition-colors hover:bg-surface",
1782
- children: [
1783
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-3", children: [
1784
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(StepStatusIcon, { status: ui.status }),
1785
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1786
- "span",
1787
- {
1788
- className: cn(
1789
- typeClasses.body,
1790
- "whitespace-nowrap font-medium text-text-primary"
1791
- ),
1792
- children: ui.label
1793
- }
1794
- )
1795
- ] }),
1796
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1797
- import_lucide_react4.ChevronRight,
1798
- {
1799
- className: cn(
1800
- "h-6 w-6 shrink-0 text-text-secondary transition-transform duration-300",
1801
- expanded && "rotate-90"
1802
- ),
1803
- "aria-hidden": "true"
1804
- }
1805
- )
1806
- ]
2931
+ size: "sm",
2932
+ variant: "destructiveLink",
2933
+ disabled: state === "removing",
2934
+ onClick: () => setState("confirming"),
2935
+ children: state === "removing" ? "Removing\u2026" : "Remove"
1807
2936
  }
1808
- ),
1809
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1810
- "div",
1811
- {
1812
- className: cn(
1813
- "grid transition-[grid-template-rows] duration-300 ease-in-out",
1814
- expanded ? "grid-rows-[1fr]" : "grid-rows-[0fr]"
2937
+ ))
2938
+ ] });
2939
+ }
2940
+ function ConnectedWalletList({
2941
+ wallets,
2942
+ onRemove,
2943
+ onAdd,
2944
+ addLabel = "Add wallet",
2945
+ status = "ready",
2946
+ className
2947
+ }) {
2948
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
2949
+ "div",
2950
+ {
2951
+ className: cn("clcosdk:flex clcosdk:flex-col clcosdk:gap-2", className),
2952
+ children: [
2953
+ status === "loading" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(AlertBanner, { variant: "info", content: "Loading your connected wallets\u2026" }) : status === "error" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2954
+ AlertBanner,
2955
+ {
2956
+ variant: "error",
2957
+ content: "Couldn't load your connected wallets."
2958
+ }
2959
+ ) : wallets.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(AlertBanner, { variant: "info", content: "No wallets connected yet." }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:divide-y clcosdk:divide-divider", children: wallets.map((wallet) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2960
+ ConnectedWalletRow,
2961
+ {
2962
+ wallet,
2963
+ onRemove
2964
+ },
2965
+ wallet.id
2966
+ )) }),
2967
+ onAdd != null && status !== "loading" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2968
+ ClButton,
2969
+ {
2970
+ size: "sm",
2971
+ variant: "secondary",
2972
+ onClick: onAdd,
2973
+ className: "clcosdk:self-start",
2974
+ children: addLabel
2975
+ }
2976
+ )
2977
+ ]
2978
+ }
2979
+ );
2980
+ }
2981
+
2982
+ // src/client/components/requirements/ConnectWalletModal.tsx
2983
+ var import_react8 = require("react");
2984
+
2985
+ // src/client/hooks/useConnectWallet.ts
2986
+ var import_react7 = require("react");
2987
+
2988
+ // src/client/core/connect-external-wallet.ts
2989
+ var DEFAULT_STATEMENT = "Sign this message to prove you own this wallet. This does not cost gas or move funds.";
2990
+ var TERMINAL_CODES = /* @__PURE__ */ new Set([
2991
+ "not_authenticated",
2992
+ "wallet_not_whitelisted",
2993
+ "max_wallets_reached"
2994
+ ]);
2995
+ var API_ERROR_CODES = /* @__PURE__ */ new Set([
2996
+ "wallet_not_whitelisted",
2997
+ "max_wallets_reached"
2998
+ ]);
2999
+ function flowError(code) {
3000
+ return { code, retryable: !TERMINAL_CODES.has(code) };
3001
+ }
3002
+ function siweContext() {
3003
+ if (typeof window === "undefined") return { domain: "", uri: "" };
3004
+ return { domain: window.location.host, uri: window.location.origin };
3005
+ }
3006
+ function apiErrorCode(error) {
3007
+ if (typeof error !== "object" || error === null) return void 0;
3008
+ const body = error.response?.body;
3009
+ return typeof body?.code === "string" ? body.code : void 0;
3010
+ }
3011
+ function classifyApiError(error) {
3012
+ if (error instanceof NotAuthenticatedError) {
3013
+ return flowError("not_authenticated");
3014
+ }
3015
+ const code = apiErrorCode(error);
3016
+ if (code !== void 0 && API_ERROR_CODES.has(code)) {
3017
+ return flowError(code);
3018
+ }
3019
+ return flowError("unknown");
3020
+ }
3021
+ function challengeParams(wallet, challengeType, statement) {
3022
+ switch (challengeType) {
3023
+ case "siwe":
3024
+ return {
3025
+ walletAddress: wallet.address,
3026
+ chain: wallet.chain,
3027
+ challengeType: "siwe",
3028
+ ...siweContext(),
3029
+ statement: statement ?? DEFAULT_STATEMENT
3030
+ };
3031
+ case "plain":
3032
+ return {
3033
+ walletAddress: wallet.address,
3034
+ chain: wallet.chain,
3035
+ challengeType: "plain"
3036
+ };
3037
+ default: {
3038
+ const _exhaustive = challengeType;
3039
+ return _exhaustive;
3040
+ }
3041
+ }
3042
+ }
3043
+ async function connectExternalWalletFlow(params) {
3044
+ const {
3045
+ coinlist,
3046
+ wallet,
3047
+ offerId,
3048
+ offerOptionId,
3049
+ challengeType,
3050
+ statement,
3051
+ isCancelled,
3052
+ onProgress
3053
+ } = params;
3054
+ const emit = (phase) => onProgress?.(phase);
3055
+ const cancelled = () => isCancelled?.() ?? false;
3056
+ emit("requesting-challenge");
3057
+ let challenge;
3058
+ try {
3059
+ challenge = await coinlist.createWalletOwnershipChallenge(
3060
+ challengeParams(wallet, challengeType ?? "siwe", statement)
3061
+ );
3062
+ } catch (error) {
3063
+ return { type: "error", error: classifyApiError(error) };
3064
+ }
3065
+ if (cancelled()) return { type: "cancelled" };
3066
+ emit("signing-message");
3067
+ let signature;
3068
+ try {
3069
+ signature = await wallet.signMessage(challenge.message);
3070
+ } catch (error) {
3071
+ if (classifyWalletError(error).type === "user_rejected") {
3072
+ return { type: "error", error: flowError("user_rejected") };
3073
+ }
3074
+ return { type: "error", error: flowError("unknown") };
3075
+ }
3076
+ if (cancelled()) return { type: "cancelled" };
3077
+ emit("submitting-signature");
3078
+ try {
3079
+ const binding = await coinlist.connectExternalWallet(offerId, {
3080
+ offerOptionId,
3081
+ walletAddress: wallet.address,
3082
+ chain: wallet.chain,
3083
+ signature
3084
+ });
3085
+ return { type: "success", binding };
3086
+ } catch (error) {
3087
+ return { type: "error", error: classifyApiError(error) };
3088
+ }
3089
+ }
3090
+
3091
+ // src/client/hooks/useConnectWallet.ts
3092
+ var IDLE_SIGN = { type: "idle", error: null };
3093
+ var ERROR_COPY = {
3094
+ not_authenticated: "Sign in to connect your wallet.",
3095
+ user_rejected: "Signature request declined. Approve it in your wallet to continue.",
3096
+ wallet_not_whitelisted: "This wallet is not approved for this offer.",
3097
+ max_wallets_reached: "You've reached the maximum number of wallets for this option.",
3098
+ unknown: "Unable to connect your wallet. Please try again."
3099
+ };
3100
+ function displayError(error) {
3101
+ return {
3102
+ code: error.code,
3103
+ message: ERROR_COPY[error.code],
3104
+ retryable: error.retryable
3105
+ };
3106
+ }
3107
+ function useConnectWallet({
3108
+ isOpen,
3109
+ offerId,
3110
+ offerOptionId,
3111
+ wallet,
3112
+ challengeType,
3113
+ statement
3114
+ }) {
3115
+ const { coinlist } = useCoinList();
3116
+ const [state, setState] = (0, import_react7.useState)(
3117
+ () => wallet ? { type: "READY", address: wallet.address, sign: IDLE_SIGN } : { type: "NEEDS_WALLET" }
3118
+ );
3119
+ const attempt = (0, import_react7.useRef)(0);
3120
+ (0, import_react7.useEffect)(() => {
3121
+ attempt.current += 1;
3122
+ if (!isOpen) return;
3123
+ setState(
3124
+ wallet ? { type: "READY", address: wallet.address, sign: IDLE_SIGN } : { type: "NEEDS_WALLET" }
3125
+ );
3126
+ }, [isOpen, wallet?.address]);
3127
+ (0, import_react7.useEffect)(
3128
+ () => () => {
3129
+ attempt.current += 1;
3130
+ },
3131
+ []
3132
+ );
3133
+ const onSign = (0, import_react7.useCallback)(() => {
3134
+ if (!wallet || state.type !== "READY") return;
3135
+ attempt.current += 1;
3136
+ const gen = attempt.current;
3137
+ setState({
3138
+ type: "READY",
3139
+ address: wallet.address,
3140
+ sign: { type: "signing" }
3141
+ });
3142
+ connectExternalWalletFlow({
3143
+ coinlist,
3144
+ wallet,
3145
+ offerId,
3146
+ offerOptionId,
3147
+ challengeType,
3148
+ statement,
3149
+ // Cancels the flow before signing / binding if this attempt is superseded.
3150
+ isCancelled: () => attempt.current !== gen
3151
+ }).then((result) => {
3152
+ if (attempt.current !== gen) return;
3153
+ if (result.type === "success") {
3154
+ setState({ type: "CONNECTED", binding: result.binding });
3155
+ } else if (result.type === "error") {
3156
+ setState({
3157
+ type: "READY",
3158
+ address: wallet.address,
3159
+ sign: { type: "idle", error: displayError(result.error) }
3160
+ });
3161
+ }
3162
+ });
3163
+ }, [
3164
+ wallet,
3165
+ state,
3166
+ coinlist,
3167
+ offerId,
3168
+ offerOptionId,
3169
+ challengeType,
3170
+ statement
3171
+ ]);
3172
+ return { state, onSign };
3173
+ }
3174
+
3175
+ // src/shared/core/blockchain/formatters.ts
3176
+ var import_viem3 = require("viem");
3177
+
3178
+ // src/shared/types/blockchain/ui.ts
3179
+ var ShortenedWalletAddress = (value) => value;
3180
+ var FormattedAmountAssetUi = (value) => value;
3181
+
3182
+ // src/shared/core/blockchain/formatters.ts
3183
+ function shortenAddress(address) {
3184
+ const short = address.length > 10 ? `${address.slice(0, 6)}\u2026${address.slice(-4)}` : address;
3185
+ return ShortenedWalletAddress(short);
3186
+ }
3187
+ var NA_AMOUNT_ASSET_UI = FormattedAmountAssetUi("-");
3188
+ var USD_FRACTION_DIGITS = AssetDecimals(2);
3189
+
3190
+ // src/client/components/requirements/ConnectWalletModal.tsx
3191
+ var import_jsx_runtime14 = require("react/jsx-runtime");
3192
+ function ConnectWalletModal({
3193
+ isOpen,
3194
+ onClose,
3195
+ offerId,
3196
+ optionId,
3197
+ wallet,
3198
+ onConnected,
3199
+ onRequestConnect,
3200
+ challengeType,
3201
+ statement,
3202
+ className
3203
+ }) {
3204
+ const { state, onSign } = useConnectWallet({
3205
+ isOpen,
3206
+ offerId,
3207
+ offerOptionId: optionId,
3208
+ wallet,
3209
+ challengeType,
3210
+ statement
3211
+ });
3212
+ const titleId = (0, import_react8.useId)();
3213
+ (0, import_react8.useEffect)(() => {
3214
+ if (state.type === "CONNECTED") {
3215
+ onConnected?.(state.binding);
3216
+ onClose();
3217
+ }
3218
+ }, [state]);
3219
+ if (!isOpen || state.type === "CONNECTED") return null;
3220
+ return /* @__PURE__ */ (0, import_jsx_runtime14.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_runtime14.jsxs)(
3221
+ "div",
3222
+ {
3223
+ role: "dialog",
3224
+ "aria-modal": "true",
3225
+ "aria-labelledby": titleId,
3226
+ className: cn(
3227
+ "clcosdk:flex clcosdk:w-full clcosdk:max-w-md clcosdk:flex-col clcosdk:gap-6 clcosdk:rounded-2xl clcosdk:bg-background clcosdk:p-6",
3228
+ className
3229
+ ),
3230
+ children: [
3231
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "clcosdk:flex clcosdk:items-start clcosdk:justify-between clcosdk:gap-4", children: [
3232
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3233
+ "h3",
3234
+ {
3235
+ id: titleId,
3236
+ className: cn(typeClasses.h3, "clcosdk:text-text-primary"),
3237
+ children: "Connect your wallet"
3238
+ }
3239
+ ),
3240
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(CloseButton, { onClick: onClose })
3241
+ ] }),
3242
+ state.type === "NEEDS_WALLET" && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(NeedsWalletScreen, { onRequestConnect }),
3243
+ state.type === "READY" && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3244
+ ReadyScreen,
3245
+ {
3246
+ address: state.address,
3247
+ sign: state.sign,
3248
+ onSign,
3249
+ onRequestConnect
3250
+ }
3251
+ )
3252
+ ]
3253
+ }
3254
+ ) });
3255
+ }
3256
+ function NeedsWalletScreen({
3257
+ onRequestConnect
3258
+ }) {
3259
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-6", children: [
3260
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: cn(typeClasses.body, "clcosdk:text-text-secondary"), children: "Connect an external wallet to prove ownership and bind it to this offer." }),
3261
+ onRequestConnect && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ClButton, { fullWidth: true, onClick: onRequestConnect, children: "Connect wallet" })
3262
+ ] });
3263
+ }
3264
+ function ReadyScreen({
3265
+ address,
3266
+ sign,
3267
+ onSign,
3268
+ onRequestConnect
3269
+ }) {
3270
+ const hasTerminalError = sign.type === "idle" && sign.error !== null && !sign.error.retryable;
3271
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-6", children: [
3272
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: cn(typeClasses.body, "clcosdk:text-text-secondary"), children: "Sign a message with your connected wallet to prove you own it. This does not cost gas or move any funds." }),
3273
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-1 clcosdk:border-t clcosdk:border-divider clcosdk:pt-4", children: [
3274
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: cn(typeClasses.label, "clcosdk:text-text-secondary"), children: "Wallet address" }),
3275
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: cn(typeClasses.body, "clcosdk:text-text-primary"), children: shortenAddress(address) })
3276
+ ] }),
3277
+ sign.type === "idle" && sign.error && // Live region: the error is inserted async after a failed attempt, so
3278
+ // screen readers need it announced rather than silently rendered.
3279
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { role: "alert", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(AlertBanner, { variant: "error", icon: true, content: sign.error.message }) }),
3280
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3281
+ ClButton,
3282
+ {
3283
+ fullWidth: true,
3284
+ onClick: onSign,
3285
+ isLoading: sign.type === "signing",
3286
+ loadingText: "Waiting for signature...",
3287
+ disabled: hasTerminalError,
3288
+ children: "Sign & connect"
3289
+ }
3290
+ ),
3291
+ onRequestConnect && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3292
+ ClButton,
3293
+ {
3294
+ fullWidth: true,
3295
+ variant: "secondary",
3296
+ onClick: onRequestConnect,
3297
+ disabled: sign.type === "signing",
3298
+ children: "Use a different wallet"
3299
+ }
3300
+ )
3301
+ ] });
3302
+ }
3303
+
3304
+ // src/client/components/requirements/IdentityVerification.tsx
3305
+ var import_websdk_react = __toESM(require("@sumsub/websdk-react"), 1);
3306
+ var import_react10 = require("react");
3307
+
3308
+ // src/client/hooks/useKycToken.ts
3309
+ var import_react9 = require("react");
3310
+ var IDLE_STATE = { type: "IDLE" };
3311
+ var LOADING_STATE2 = { type: "LOADING" };
3312
+ function useKycToken(levelName, reset) {
3313
+ const { coinlist } = useCoinList();
3314
+ const [kycTokenState, setKycTokenState] = (0, import_react9.useState)(IDLE_STATE);
3315
+ const resetPendingRef = (0, import_react9.useRef)(reset === true);
3316
+ const tokenIssuedRef = (0, import_react9.useRef)(false);
3317
+ (0, import_react9.useEffect)(() => {
3318
+ if (!tokenIssuedRef.current) {
3319
+ resetPendingRef.current = reset === true;
3320
+ }
3321
+ }, [reset]);
3322
+ const fetchToken = (0, import_react9.useCallback)(async () => {
3323
+ setKycTokenState(LOADING_STATE2);
3324
+ try {
3325
+ const kycToken = await coinlist.createKycToken(
3326
+ levelName,
3327
+ resetPendingRef.current
3328
+ );
3329
+ resetPendingRef.current = false;
3330
+ tokenIssuedRef.current = true;
3331
+ setKycTokenState({ type: "CONTENT", token: kycToken.token });
3332
+ return kycToken.token;
3333
+ } catch (error) {
3334
+ const reason = error instanceof NotAuthenticatedError ? "not-authenticated" : "generic-error";
3335
+ setKycTokenState({ type: "ERROR", reason });
3336
+ throw error;
3337
+ }
3338
+ }, [coinlist, levelName]);
3339
+ return { kycTokenState, fetchToken };
3340
+ }
3341
+
3342
+ // src/client/components/requirements/IdentityVerification.tsx
3343
+ var import_jsx_runtime15 = require("react/jsx-runtime");
3344
+ function IdentityVerification({
3345
+ levelName,
3346
+ reset,
3347
+ locale,
3348
+ onSubmitted,
3349
+ onError,
3350
+ className
3351
+ }) {
3352
+ const { kycTokenState, fetchToken } = useKycToken(levelName, reset);
3353
+ const fetchedRef = (0, import_react10.useRef)(false);
3354
+ (0, import_react10.useEffect)(() => {
3355
+ if (fetchedRef.current) return;
3356
+ fetchedRef.current = true;
3357
+ fetchToken().catch(() => {
3358
+ });
3359
+ }, [fetchToken]);
3360
+ const handleMessage = (type, payload) => {
3361
+ switch (type) {
3362
+ case "idCheck.onApplicantSubmitted":
3363
+ onSubmitted?.();
3364
+ break;
3365
+ case "idCheck.onError": {
3366
+ const message = payload?.message ?? "Verification error";
3367
+ onError?.(new Error(message));
3368
+ break;
3369
+ }
3370
+ default:
3371
+ break;
3372
+ }
3373
+ };
3374
+ const handleError = (error) => {
3375
+ onError?.(error instanceof Error ? error : new Error("Verification error"));
3376
+ };
3377
+ if (kycTokenState.type === "IDLE" || kycTokenState.type === "LOADING") {
3378
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3379
+ "output",
3380
+ {
3381
+ "aria-live": "polite",
3382
+ className: cn(
3383
+ "clcosdk:flex clcosdk:min-h-40 clcosdk:items-center clcosdk:justify-center",
3384
+ className
3385
+ ),
3386
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: cn(typeClasses.body, "clcosdk:text-text-secondary"), children: "Loading identity verification..." })
3387
+ }
3388
+ );
3389
+ }
3390
+ if (kycTokenState.type === "ERROR") {
3391
+ const errorMessage = kycTokenState.reason === "not-authenticated" ? "Sign in to verify your identity." : "Unable to start identity verification right now. Please try again.";
3392
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
3393
+ "div",
3394
+ {
3395
+ className: cn("clcosdk:flex clcosdk:flex-col clcosdk:gap-4", className),
3396
+ children: [
3397
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(AlertBanner, { variant: "error", icon: true, content: errorMessage }),
3398
+ kycTokenState.reason !== "not-authenticated" && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3399
+ ClButton,
3400
+ {
3401
+ size: "sm",
3402
+ onClick: () => {
3403
+ fetchToken().catch(() => {
3404
+ });
3405
+ },
3406
+ children: "Try again"
3407
+ }
3408
+ )
3409
+ ]
3410
+ }
3411
+ );
3412
+ }
3413
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: cn("clcosdk:w-full", className), children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3414
+ import_websdk_react.default,
3415
+ {
3416
+ accessToken: kycTokenState.token,
3417
+ expirationHandler: fetchToken,
3418
+ config: locale === void 0 ? {} : { lang: locale },
3419
+ options: { addViewportTag: false, adaptIframeHeight: true },
3420
+ onMessage: handleMessage,
3421
+ onError: handleError
3422
+ }
3423
+ ) });
3424
+ }
3425
+
3426
+ // src/client/components/requirements/RequirementItem.tsx
3427
+ var import_lucide_react4 = require("lucide-react");
3428
+
3429
+ // src/client/components/design-system/StepStatusIcon.tsx
3430
+ var import_lucide_react3 = require("lucide-react");
3431
+ var import_jsx_runtime16 = require("react/jsx-runtime");
3432
+ var statusConfig = {
3433
+ required: {
3434
+ Icon: import_lucide_react3.Info,
3435
+ colorClass: "clcosdk:text-warning",
3436
+ fillClass: "clcosdk:[&_circle]:fill-warning-subtle"
3437
+ },
3438
+ pending: {
3439
+ Icon: import_lucide_react3.Info,
3440
+ colorClass: "clcosdk:text-warning",
3441
+ fillClass: "clcosdk:[&_circle]:fill-warning-subtle"
3442
+ },
3443
+ completed: {
3444
+ Icon: import_lucide_react3.CircleCheck,
3445
+ colorClass: "clcosdk:text-success",
3446
+ fillClass: "clcosdk:[&_circle]:fill-success-subtle"
3447
+ },
3448
+ rejected: {
3449
+ Icon: import_lucide_react3.CircleX,
3450
+ colorClass: "clcosdk:text-error",
3451
+ fillClass: "clcosdk:[&_circle]:fill-error-subtle"
3452
+ }
3453
+ };
3454
+ function StepStatusIcon({ status, className }) {
3455
+ const { Icon, colorClass, fillClass } = statusConfig[status];
3456
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3457
+ Icon,
3458
+ {
3459
+ className: cn(
3460
+ "clcosdk:h-6 clcosdk:w-6 clcosdk:shrink-0",
3461
+ colorClass,
3462
+ fillClass,
3463
+ className
3464
+ ),
3465
+ "aria-hidden": "true"
3466
+ }
3467
+ );
3468
+ }
3469
+
3470
+ // src/client/components/requirements/RequirementItem.tsx
3471
+ var import_jsx_runtime17 = require("react/jsx-runtime");
3472
+ var RequirementVariant = {
3473
+ fromType(type) {
3474
+ switch (type) {
3475
+ case "external_wallet":
3476
+ case "whitelisted_wallet":
3477
+ return "wallet";
3478
+ default:
3479
+ return "verification";
3480
+ }
3481
+ }
3482
+ };
3483
+ var RequirementStatus = {
3484
+ fromStatusValue(status) {
3485
+ switch (status) {
3486
+ case "not_started":
3487
+ case "action_needed":
3488
+ return "required";
3489
+ case "in_progress":
3490
+ return "pending";
3491
+ case "completed":
3492
+ return "completed";
3493
+ case "rejected":
3494
+ return "rejected";
3495
+ }
3496
+ }
3497
+ };
3498
+ var ChecklistStatus = {
3499
+ derive(statuses) {
3500
+ if (statuses.some((s) => s.status === "rejected")) return "ineligible";
3501
+ if (statuses.every((s) => s.status === "completed")) return "eligible";
3502
+ return "inProgress";
3503
+ }
3504
+ };
3505
+ var RequirementItemUi = {
3506
+ fromDomain(req, statusInfo, label, description, addresses = []) {
3507
+ return {
3508
+ variant: RequirementVariant.fromType(req.type),
3509
+ status: statusInfo ? RequirementStatus.fromStatusValue(statusInfo.status) : "required",
3510
+ label,
3511
+ description,
3512
+ multiWallet: req.type === "whitelisted_wallet",
3513
+ connectedWallets: addresses.map((address) => ({
3514
+ id: address.id,
3515
+ address: address.address,
3516
+ shortAddress: shortenAddress(address.address)
3517
+ }))
3518
+ };
3519
+ }
3520
+ };
3521
+ function VerificationActionZone({
3522
+ status,
3523
+ onAction,
3524
+ onContactSupport
3525
+ }) {
3526
+ switch (status) {
3527
+ case "required":
3528
+ if (onAction === null) return null;
3529
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ClButton, { size: "sm", onClick: onAction, children: "Continue" });
3530
+ case "pending":
3531
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3532
+ AlertBanner,
3533
+ {
3534
+ variant: "warning",
3535
+ content: "Under review. We'll notify you when complete."
3536
+ }
3537
+ );
3538
+ case "completed":
3539
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(AlertBanner, { variant: "success", content: "Identity verified." });
3540
+ case "rejected":
3541
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3542
+ AlertBanner,
3543
+ {
3544
+ variant: "error",
3545
+ content: onContactSupport === null ? "Verification rejected." : /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
3546
+ "Verification rejected.",
3547
+ " ",
3548
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3549
+ "button",
3550
+ {
3551
+ type: "button",
3552
+ onClick: onContactSupport,
3553
+ className: "clcosdk:underline",
3554
+ children: "Contact support"
3555
+ }
3556
+ ),
3557
+ "."
3558
+ ] })
3559
+ }
3560
+ );
3561
+ }
3562
+ }
3563
+ function WalletActionZone({
3564
+ status,
3565
+ multiWallet,
3566
+ connectedWallets,
3567
+ walletsStatus,
3568
+ onAction,
3569
+ onRemoveWallet
3570
+ }) {
3571
+ if (multiWallet) {
3572
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
3573
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3574
+ ConnectedWalletList,
3575
+ {
3576
+ wallets: connectedWallets,
3577
+ onRemove: onRemoveWallet,
3578
+ onAdd: onAction ?? void 0,
3579
+ status: walletsStatus
3580
+ }
3581
+ ),
3582
+ status === "rejected" && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3583
+ AlertBanner,
3584
+ {
3585
+ variant: "error",
3586
+ content: "One of these wallets is not eligible for this sale."
3587
+ }
3588
+ )
3589
+ ] });
3590
+ }
3591
+ if (status === "completed") {
3592
+ const connected = connectedWallets[0];
3593
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
3594
+ onAction !== null && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ClButton, { size: "sm", variant: "secondary", onClick: onAction, children: "Change wallet" }),
3595
+ walletsStatus === "loading" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3596
+ AlertBanner,
3597
+ {
3598
+ variant: "info",
3599
+ content: "Loading your connected wallet\u2026"
3600
+ }
3601
+ ) : walletsStatus === "error" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3602
+ AlertBanner,
3603
+ {
3604
+ variant: "error",
3605
+ content: "Couldn't load your connected wallet."
3606
+ }
3607
+ ) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3608
+ AlertBanner,
3609
+ {
3610
+ variant: "success",
3611
+ content: connected ? connected.shortAddress : "Wallet connected."
3612
+ }
3613
+ )
3614
+ ] });
3615
+ }
3616
+ if (status === "rejected") {
3617
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
3618
+ onAction !== null && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ClButton, { size: "sm", onClick: onAction, children: "Connect wallet" }),
3619
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3620
+ AlertBanner,
3621
+ {
3622
+ variant: "error",
3623
+ content: "This wallet is not eligible for this sale."
3624
+ }
3625
+ )
3626
+ ] });
3627
+ }
3628
+ if (onAction === null) return null;
3629
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ClButton, { size: "sm", onClick: onAction, children: "Connect wallet" });
3630
+ }
3631
+ function RequirementItem({
3632
+ ui,
3633
+ expanded = false,
3634
+ onToggle,
3635
+ className,
3636
+ onAction,
3637
+ onRemoveWallet,
3638
+ walletsStatus,
3639
+ onContactSupport
3640
+ }) {
3641
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(CoinListStyleScope, { children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
3642
+ "div",
3643
+ {
3644
+ className: cn(
3645
+ "clcosdk:flex clcosdk:w-full clcosdk:flex-col",
3646
+ className
3647
+ ),
3648
+ children: [
3649
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
3650
+ "button",
3651
+ {
3652
+ type: "button",
3653
+ onClick: onToggle,
3654
+ "aria-expanded": expanded,
3655
+ 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",
3656
+ children: [
3657
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "clcosdk:flex clcosdk:items-center clcosdk:gap-3", children: [
3658
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(StepStatusIcon, { status: ui.status }),
3659
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3660
+ "span",
3661
+ {
3662
+ className: cn(
3663
+ typeClasses.body,
3664
+ "clcosdk:whitespace-nowrap clcosdk:font-medium clcosdk:text-text-primary"
3665
+ ),
3666
+ children: ui.label
3667
+ }
3668
+ )
3669
+ ] }),
3670
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3671
+ import_lucide_react4.ChevronRight,
3672
+ {
3673
+ className: cn(
3674
+ "clcosdk:h-6 clcosdk:w-6 clcosdk:shrink-0 clcosdk:text-text-secondary clcosdk:transition-transform clcosdk:duration-300",
3675
+ expanded && "clcosdk:rotate-90"
3676
+ ),
3677
+ "aria-hidden": "true"
3678
+ }
3679
+ )
3680
+ ]
3681
+ }
3682
+ ),
3683
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3684
+ "div",
3685
+ {
3686
+ className: cn(
3687
+ "clcosdk:grid clcosdk:transition-[grid-template-rows] clcosdk:duration-300 clcosdk:ease-in-out",
3688
+ expanded ? "clcosdk:grid-rows-[1fr]" : "clcosdk:grid-rows-[0fr]"
3689
+ ),
3690
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "clcosdk:min-h-0 clcosdk:overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-4 clcosdk:px-2 clcosdk:pb-4", children: [
3691
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3692
+ "p",
3693
+ {
3694
+ className: cn(
3695
+ typeClasses.subhead,
3696
+ "clcosdk:text-text-secondary"
3697
+ ),
3698
+ children: ui.description
3699
+ }
3700
+ ),
3701
+ ui.variant === "verification" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3702
+ VerificationActionZone,
3703
+ {
3704
+ status: ui.status,
3705
+ onAction,
3706
+ onContactSupport
3707
+ }
3708
+ ) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3709
+ WalletActionZone,
3710
+ {
3711
+ status: ui.status,
3712
+ multiWallet: ui.multiWallet,
3713
+ connectedWallets: ui.connectedWallets,
3714
+ walletsStatus,
3715
+ onAction,
3716
+ onRemoveWallet
3717
+ }
3718
+ )
3719
+ ] }) })
3720
+ }
3721
+ )
3722
+ ]
3723
+ }
3724
+ ) });
3725
+ }
3726
+
3727
+ // src/client/components/requirements/RequirementsChecklist.tsx
3728
+ var import_react15 = require("react");
3729
+
3730
+ // src/client/components/requirements/TaxDocumentModal.tsx
3731
+ var import_react12 = require("react");
3732
+
3733
+ // src/client/hooks/useTaxDocument.ts
3734
+ var import_react11 = require("react");
3735
+ var IDLE_SIGN2 = { type: "idle", error: null };
3736
+ var LOADING_STATE3 = { type: "LOADING" };
3737
+ var SIGN_FAILED_MESSAGE = "Unable to sign document. Please try again.";
3738
+ var DOB_INVALID_MESSAGE = "Enter your date of birth as MM/DD/YYYY.";
3739
+ var FIELD_KEYS = {
3740
+ fullLegalName: "Full Name",
3741
+ dob: "DOB",
3742
+ countryOfCitizenship: "Country Of Citizenship",
3743
+ taxId: "Foreign Tax Number",
3744
+ permanentAddress: "Permanent Address"
3745
+ };
3746
+ function formatUsDate(date) {
3747
+ const month = String(date.getMonth() + 1).padStart(2, "0");
3748
+ const day = String(date.getDate()).padStart(2, "0");
3749
+ const year = String(date.getFullYear()).padStart(4, "0");
3750
+ return `${month}/${day}/${year}`;
3751
+ }
3752
+ function formatIsoDateOnly(isoDate) {
3753
+ const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(isoDate);
3754
+ if (!match) return "";
3755
+ const [, year, month, day] = match;
3756
+ return `${month}/${day}/${year}`;
3757
+ }
3758
+ function isValidUsDate(value) {
3759
+ const match = /^(\d{2})\/(\d{2})\/(\d{4})$/.exec(value);
3760
+ if (!match) return false;
3761
+ const [, mm, dd, yyyy] = match;
3762
+ const month = Number(mm);
3763
+ const day = Number(dd);
3764
+ const year = Number(yyyy);
3765
+ const date = new Date(year, month - 1, day);
3766
+ return date.getFullYear() === year && date.getMonth() === month - 1 && date.getDate() === day;
3767
+ }
3768
+ function mapPiiToFields(pii) {
3769
+ const { street, city, state, postalCode } = pii.permanentAddress;
3770
+ const cityLine = [postalCode, city].filter(Boolean).join(" ");
3771
+ const permanentAddress = [street, cityLine, state].filter(Boolean).join(", ");
3772
+ return {
3773
+ fullLegalName: pii.fullLegalName ?? "",
3774
+ // Date-only ISO from the backend, shown as MM/DD/YYYY. Blank until the
3775
+ // backend has a date of birth (the field is editable in the meantime).
3776
+ dob: formatIsoDateOnly(pii.dateOfBirth ?? ""),
3777
+ countryOfCitizenship: pii.jurisdiction?.name ?? "",
3778
+ taxId: pii.taxId ?? "",
3779
+ permanentAddress
3780
+ };
3781
+ }
3782
+ function addressPartsFromPii(pii) {
3783
+ return {
3784
+ city: pii.permanentAddress.city ?? "",
3785
+ country: pii.permanentAddress.country ?? ""
3786
+ };
3787
+ }
3788
+ function hasAnyFieldValue(fields) {
3789
+ return Object.values(fields).some((value) => value.trim() !== "");
3790
+ }
3791
+ function toSubmissionFields(fields, addressParts) {
3792
+ return {
3793
+ [FIELD_KEYS.fullLegalName]: fields.fullLegalName,
3794
+ [FIELD_KEYS.dob]: fields.dob,
3795
+ [FIELD_KEYS.countryOfCitizenship]: fields.countryOfCitizenship,
3796
+ [FIELD_KEYS.taxId]: fields.taxId,
3797
+ [FIELD_KEYS.permanentAddress]: fields.permanentAddress,
3798
+ City: addressParts.city,
3799
+ Country: addressParts.country,
3800
+ Signature: fields.fullLegalName,
3801
+ Date: formatUsDate(/* @__PURE__ */ new Date())
3802
+ };
3803
+ }
3804
+ function useTaxDocument({
3805
+ isOpen
3806
+ }) {
3807
+ const { coinlist, isReady } = useCoinList();
3808
+ const [state, setState] = (0, import_react11.useState)(LOADING_STATE3);
3809
+ (0, import_react11.useEffect)(() => {
3810
+ let isCancelled = false;
3811
+ if (!isOpen) {
3812
+ return () => {
3813
+ isCancelled = true;
3814
+ };
3815
+ }
3816
+ if (!isReady) {
3817
+ setState(LOADING_STATE3);
3818
+ return () => {
3819
+ isCancelled = true;
3820
+ };
3821
+ }
3822
+ setState(LOADING_STATE3);
3823
+ coinlist.fetchPii().then((pii) => {
3824
+ if (isCancelled) return;
3825
+ if (pii.kind === "company") {
3826
+ setState({ type: "SIGN_ONLY", sign: IDLE_SIGN2 });
3827
+ return;
3828
+ }
3829
+ const fields = mapPiiToFields(pii);
3830
+ setState({
3831
+ type: "REVIEW",
3832
+ fields,
3833
+ addressParts: addressPartsFromPii(pii),
3834
+ piiUnavailable: !hasAnyFieldValue(fields),
3835
+ sign: IDLE_SIGN2
3836
+ });
3837
+ }).catch((error) => {
3838
+ if (isCancelled) return;
3839
+ setState({
3840
+ type: "ERROR",
3841
+ reason: error instanceof NotAuthenticatedError ? "not-authenticated" : "generic-error"
3842
+ });
3843
+ });
3844
+ return () => {
3845
+ isCancelled = true;
3846
+ };
3847
+ }, [coinlist, isReady, isOpen]);
3848
+ const onEditField = (0, import_react11.useCallback)(
3849
+ (field, value) => {
3850
+ setState(
3851
+ (prev) => prev.type === "EDITING" ? { ...prev, fields: { ...prev.fields, [field]: value } } : prev
3852
+ );
3853
+ },
3854
+ []
3855
+ );
3856
+ const onStartEdit = (0, import_react11.useCallback)(() => {
3857
+ setState(
3858
+ (prev) => prev.type === "REVIEW" ? {
3859
+ type: "EDITING",
3860
+ fields: prev.fields,
3861
+ original: prev.fields,
3862
+ addressParts: prev.addressParts,
3863
+ piiUnavailable: prev.piiUnavailable
3864
+ } : prev
3865
+ );
3866
+ }, []);
3867
+ const onSaveEdit = (0, import_react11.useCallback)(() => {
3868
+ setState(
3869
+ (prev) => prev.type === "EDITING" ? {
3870
+ type: "REVIEW",
3871
+ fields: prev.fields,
3872
+ addressParts: prev.addressParts,
3873
+ piiUnavailable: prev.piiUnavailable,
3874
+ sign: IDLE_SIGN2
3875
+ } : prev
3876
+ );
3877
+ }, []);
3878
+ const onCancelEdit = (0, import_react11.useCallback)(() => {
3879
+ setState(
3880
+ (prev) => prev.type === "EDITING" ? {
3881
+ type: "REVIEW",
3882
+ fields: prev.original,
3883
+ addressParts: prev.addressParts,
3884
+ piiUnavailable: prev.piiUnavailable,
3885
+ sign: IDLE_SIGN2
3886
+ } : prev
3887
+ );
3888
+ }, []);
3889
+ const onSign = (0, import_react11.useCallback)(() => {
3890
+ if (state.type !== "REVIEW" && state.type !== "SIGN_ONLY") return;
3891
+ if (state.type === "REVIEW" && state.fields.dob.trim() !== "" && !isValidUsDate(state.fields.dob)) {
3892
+ setState({
3893
+ ...state,
3894
+ sign: { type: "idle", error: DOB_INVALID_MESSAGE }
3895
+ });
3896
+ return;
3897
+ }
3898
+ setState({ ...state, sign: { type: "signing" } });
3899
+ coinlist.submitDocument(
3900
+ "tax_certification",
3901
+ state.type === "REVIEW" ? toSubmissionFields(state.fields, state.addressParts) : {}
3902
+ ).then((submission) => {
3903
+ setState({ type: "SUBMITTED", submission });
3904
+ }).catch(() => {
3905
+ setState(
3906
+ (prev) => prev.type === "REVIEW" || prev.type === "SIGN_ONLY" ? { ...prev, sign: { type: "idle", error: SIGN_FAILED_MESSAGE } } : prev
3907
+ );
3908
+ });
3909
+ }, [state, coinlist]);
3910
+ return { state, onEditField, onStartEdit, onSaveEdit, onCancelEdit, onSign };
3911
+ }
3912
+
3913
+ // src/client/components/requirements/TaxDocumentModal.tsx
3914
+ var import_jsx_runtime18 = require("react/jsx-runtime");
3915
+ var FIELD_ROWS = [
3916
+ { field: "fullLegalName", label: "Full legal name" },
3917
+ { field: "dob", label: "Date of birth", placeholder: "MM/DD/YYYY" },
3918
+ { field: "countryOfCitizenship", label: "Country of citizenship" },
3919
+ { field: "taxId", label: "Tax ID" },
3920
+ { field: "permanentAddress", label: "Permanent address" }
3921
+ ];
3922
+ function TaxDocumentModal({
3923
+ isOpen,
3924
+ onClose,
3925
+ onSubmitted,
3926
+ className
3927
+ }) {
3928
+ const { state, onEditField, onStartEdit, onSaveEdit, onCancelEdit, onSign } = useTaxDocument({ isOpen });
3929
+ (0, import_react12.useEffect)(() => {
3930
+ if (state.type === "SUBMITTED") {
3931
+ onSubmitted?.(state.submission);
3932
+ onClose();
3933
+ }
3934
+ }, [state]);
3935
+ if (!isOpen || state.type === "SUBMITTED") return null;
3936
+ return /* @__PURE__ */ (0, import_jsx_runtime18.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_runtime18.jsxs)(
3937
+ "div",
3938
+ {
3939
+ className: cn(
3940
+ "clcosdk:flex clcosdk:w-full clcosdk:max-w-md clcosdk:flex-col clcosdk:gap-6 clcosdk:rounded-2xl clcosdk:bg-background clcosdk:p-6",
3941
+ className
3942
+ ),
3943
+ children: [
3944
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "clcosdk:flex clcosdk:items-start clcosdk:justify-between clcosdk:gap-4", children: [
3945
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(TaxDocumentModalHeading, { state }),
3946
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(CloseButton, { onClick: onClose })
3947
+ ] }),
3948
+ state.type === "LOADING" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(LoadingScreen, {}),
3949
+ state.type === "ERROR" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ErrorScreen, { reason: state.reason }),
3950
+ state.type === "REVIEW" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
3951
+ ReviewScreen,
3952
+ {
3953
+ fields: state.fields,
3954
+ piiUnavailable: state.piiUnavailable,
3955
+ sign: state.sign,
3956
+ onStartEdit,
3957
+ onSign
3958
+ }
3959
+ ),
3960
+ state.type === "EDITING" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
3961
+ EditScreen,
3962
+ {
3963
+ fields: state.fields,
3964
+ onEditField,
3965
+ onSaveEdit,
3966
+ onCancelEdit
3967
+ }
1815
3968
  ),
1816
- children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "min-h-0 overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col gap-4 px-2 pb-4", children: [
1817
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: cn(typeClasses.subhead, "text-text-secondary"), children: ui.description }),
1818
- ui.variant === "verification" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1819
- VerificationActionZone,
3969
+ state.type === "SIGN_ONLY" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SignOnlyScreen, { sign: state.sign, onSign })
3970
+ ]
3971
+ }
3972
+ ) });
3973
+ }
3974
+ function TaxDocumentModalHeading({
3975
+ state
3976
+ }) {
3977
+ const title = state.type === "EDITING" ? "Edit your W-8BEN" : state.type === "REVIEW" ? "Confirm your W-8BEN" : state.type === "SIGN_ONLY" ? "Confirm your W-8BEN-E" : "Tax document";
3978
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("h3", { className: cn(typeClasses.h3, "clcosdk:text-text-primary"), children: title });
3979
+ }
3980
+ function LoadingScreen() {
3981
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
3982
+ "output",
3983
+ {
3984
+ "aria-live": "polite",
3985
+ className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-4",
3986
+ children: FIELD_ROWS.map(({ field }) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
3987
+ "div",
3988
+ {
3989
+ className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-1",
3990
+ children: [
3991
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "clcosdk:h-3 clcosdk:w-28 clcosdk:animate-pulse clcosdk:rounded clcosdk:bg-surface" }),
3992
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "clcosdk:h-5 clcosdk:w-48 clcosdk:animate-pulse clcosdk:rounded clcosdk:bg-surface" })
3993
+ ]
3994
+ },
3995
+ field
3996
+ ))
3997
+ }
3998
+ );
3999
+ }
4000
+ function ErrorScreen({
4001
+ reason
4002
+ }) {
4003
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4004
+ AlertBanner,
4005
+ {
4006
+ variant: "error",
4007
+ icon: true,
4008
+ content: reason === "not-authenticated" ? "Sign in to complete your tax document." : "Unable to load your tax information right now. Please try again."
4009
+ }
4010
+ );
4011
+ }
4012
+ function ReviewScreen({
4013
+ fields,
4014
+ piiUnavailable,
4015
+ sign,
4016
+ onStartEdit,
4017
+ onSign
4018
+ }) {
4019
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-6", children: [
4020
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: cn(typeClasses.body, "clcosdk:text-text-secondary"), children: "Review your information below. If anything looks incorrect, edit before signing." }),
4021
+ piiUnavailable && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4022
+ AlertBanner,
4023
+ {
4024
+ variant: "info",
4025
+ icon: true,
4026
+ content: "We don't have this information on file yet \u2014 please fill it in below."
4027
+ }
4028
+ ),
4029
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-4 clcosdk:border-t clcosdk:border-divider clcosdk:pt-4", children: FIELD_ROWS.map(({ field, label }) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
4030
+ "div",
4031
+ {
4032
+ className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-1",
4033
+ children: [
4034
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4035
+ "span",
1820
4036
  {
1821
- status: ui.status,
1822
- onAction,
1823
- onContactSupport
4037
+ className: cn(typeClasses.label, "clcosdk:text-text-secondary"),
4038
+ children: label
1824
4039
  }
1825
- ) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1826
- WalletActionZone,
4040
+ ),
4041
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: cn(typeClasses.body, "clcosdk:text-text-primary"), children: fields[field] || "\u2014" })
4042
+ ]
4043
+ },
4044
+ field
4045
+ )) }),
4046
+ /* @__PURE__ */ (0, import_jsx_runtime18.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." }),
4047
+ sign.type === "idle" && sign.error && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(AlertBanner, { variant: "error", icon: true, content: sign.error }),
4048
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-2", children: [
4049
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4050
+ ClButton,
4051
+ {
4052
+ fullWidth: true,
4053
+ onClick: onSign,
4054
+ isLoading: sign.type === "signing",
4055
+ loadingText: "Signing...",
4056
+ children: "Sign W-8BEN"
4057
+ }
4058
+ ),
4059
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4060
+ ClButton,
4061
+ {
4062
+ fullWidth: true,
4063
+ variant: "secondary",
4064
+ onClick: onStartEdit,
4065
+ disabled: sign.type === "signing",
4066
+ children: "Edit information"
4067
+ }
4068
+ )
4069
+ ] })
4070
+ ] });
4071
+ }
4072
+ function EditScreen({
4073
+ fields,
4074
+ onEditField,
4075
+ onSaveEdit,
4076
+ onCancelEdit
4077
+ }) {
4078
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-6", children: [
4079
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-4 clcosdk:border-t clcosdk:border-divider clcosdk:pt-4", children: FIELD_ROWS.map(({ field, label, placeholder }) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
4080
+ "label",
4081
+ {
4082
+ className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-1",
4083
+ children: [
4084
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4085
+ "span",
1827
4086
  {
1828
- status: ui.status,
1829
- walletAddress: ui.walletAddress,
1830
- onAction
4087
+ className: cn(typeClasses.label, "clcosdk:text-text-secondary"),
4088
+ children: label
4089
+ }
4090
+ ),
4091
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4092
+ "input",
4093
+ {
4094
+ type: "text",
4095
+ value: fields[field],
4096
+ placeholder,
4097
+ onChange: (e) => onEditField(field, e.target.value),
4098
+ className: cn(
4099
+ typeClasses.body,
4100
+ "clcosdk:rounded-lg clcosdk:border clcosdk:border-border clcosdk:bg-background clcosdk:px-3 clcosdk:py-2 clcosdk:text-text-primary clcosdk:focus-visible:outline-none clcosdk:focus-visible:ring-2 clcosdk:focus-visible:ring-gray-400"
4101
+ )
1831
4102
  }
1832
4103
  )
1833
- ] }) })
4104
+ ]
4105
+ },
4106
+ field
4107
+ )) }),
4108
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-2", children: [
4109
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ClButton, { fullWidth: true, onClick: onSaveEdit, children: "Save & review" }),
4110
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ClButton, { fullWidth: true, variant: "secondary", onClick: onCancelEdit, children: "Cancel" })
4111
+ ] })
4112
+ ] });
4113
+ }
4114
+ function SignOnlyScreen({
4115
+ sign,
4116
+ onSign
4117
+ }) {
4118
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-6", children: [
4119
+ /* @__PURE__ */ (0, import_jsx_runtime18.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." }),
4120
+ sign.type === "idle" && sign.error && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(AlertBanner, { variant: "error", icon: true, content: sign.error }),
4121
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4122
+ ClButton,
4123
+ {
4124
+ fullWidth: true,
4125
+ onClick: onSign,
4126
+ isLoading: sign.type === "signing",
4127
+ loadingText: "Signing...",
4128
+ children: "Sign W-8BEN-E"
1834
4129
  }
1835
4130
  )
1836
4131
  ] });
1837
4132
  }
1838
4133
 
1839
- // src/client/components/requirements/RequirementsChecklist.tsx
1840
- var import_react6 = require("react");
4134
+ // src/client/hooks/useOptionAddresses.ts
4135
+ var import_react13 = require("react");
4136
+ var LOADING_STATE4 = { type: "LOADING" };
4137
+ var EMPTY_STATE = {
4138
+ type: "CONTENT",
4139
+ addresses: []
4140
+ };
4141
+ function useOptionAddresses(offerId, offerOptionId, options = {}) {
4142
+ const { coinlist, isReady } = useCoinList();
4143
+ const { data, enabled = true } = options;
4144
+ const [addressesState, setAddressesState] = (0, import_react13.useState)(
4145
+ data !== void 0 ? { type: "CONTENT", addresses: data } : LOADING_STATE4
4146
+ );
4147
+ const [fetchKey, setFetchKey] = (0, import_react13.useState)(0);
4148
+ const refetch = (0, import_react13.useCallback)(() => setFetchKey((k) => k + 1), []);
4149
+ const disconnect = (0, import_react13.useCallback)(
4150
+ async (addressId) => {
4151
+ await coinlist.removeOptionAddress(offerId, addressId);
4152
+ refetch();
4153
+ },
4154
+ [coinlist, offerId, refetch]
4155
+ );
4156
+ (0, import_react13.useEffect)(() => {
4157
+ let isCancelled = false;
4158
+ if (!enabled) {
4159
+ setAddressesState(
4160
+ data !== void 0 ? { type: "CONTENT", addresses: data } : EMPTY_STATE
4161
+ );
4162
+ return () => {
4163
+ isCancelled = true;
4164
+ };
4165
+ }
4166
+ if (!isReady) {
4167
+ if (data === void 0) {
4168
+ setAddressesState(LOADING_STATE4);
4169
+ }
4170
+ return () => {
4171
+ isCancelled = true;
4172
+ };
4173
+ }
4174
+ if (data !== void 0 && fetchKey === 0) {
4175
+ return () => {
4176
+ isCancelled = true;
4177
+ };
4178
+ }
4179
+ if (coinlist.getAuthState() === "logged-out") {
4180
+ setAddressesState({ type: "ERROR", reason: "not-authenticated" });
4181
+ return () => {
4182
+ isCancelled = true;
4183
+ };
4184
+ }
4185
+ setAddressesState(LOADING_STATE4);
4186
+ coinlist.listOptionAddresses(offerId, offerOptionId).then((addresses) => {
4187
+ if (!isCancelled) {
4188
+ setAddressesState({ type: "CONTENT", addresses });
4189
+ }
4190
+ }).catch((error) => {
4191
+ if (!isCancelled) {
4192
+ const reason = error instanceof NotAuthenticatedError ? "not-authenticated" : "generic-error";
4193
+ setAddressesState({ type: "ERROR", reason });
4194
+ }
4195
+ });
4196
+ return () => {
4197
+ isCancelled = true;
4198
+ };
4199
+ }, [coinlist, isReady, enabled, offerId, offerOptionId, fetchKey]);
4200
+ return { addressesState, refetch, disconnect };
4201
+ }
1841
4202
 
1842
4203
  // src/client/hooks/useRequirements.ts
1843
- var import_react5 = require("react");
1844
- var LOADING_STATE2 = { type: "LOADING" };
4204
+ var import_react14 = require("react");
4205
+ var LOADING_STATE5 = { type: "LOADING" };
1845
4206
  function useRequirements(offerId, options = {}) {
1846
4207
  const { coinlist, isReady } = useCoinList();
1847
4208
  const { data } = options;
1848
- const [requirementsState, setRequirementsState] = (0, import_react5.useState)(
1849
- data !== void 0 ? { type: "CONTENT", ...data } : LOADING_STATE2
4209
+ const [requirementsState, setRequirementsState] = (0, import_react14.useState)(
4210
+ data !== void 0 ? { type: "CONTENT", ...data } : LOADING_STATE5
1850
4211
  );
1851
- const [fetchKey, setFetchKey] = (0, import_react5.useState)(0);
1852
- const refetch = (0, import_react5.useCallback)(() => setFetchKey((k) => k + 1), []);
1853
- (0, import_react5.useEffect)(() => {
4212
+ const [fetchKey, setFetchKey] = (0, import_react14.useState)(0);
4213
+ const refetch = (0, import_react14.useCallback)(() => setFetchKey((k) => k + 1), []);
4214
+ (0, import_react14.useEffect)(() => {
1854
4215
  let isCancelled = false;
1855
4216
  if (!isReady) {
1856
4217
  if (data === void 0) {
1857
- setRequirementsState(LOADING_STATE2);
4218
+ setRequirementsState(LOADING_STATE5);
1858
4219
  }
1859
4220
  return () => {
1860
4221
  isCancelled = true;
@@ -1865,7 +4226,13 @@ function useRequirements(offerId, options = {}) {
1865
4226
  isCancelled = true;
1866
4227
  };
1867
4228
  }
1868
- setRequirementsState(LOADING_STATE2);
4229
+ if (coinlist.getAuthState() === "logged-out") {
4230
+ setRequirementsState({ type: "ERROR", reason: "not-authenticated" });
4231
+ return () => {
4232
+ isCancelled = true;
4233
+ };
4234
+ }
4235
+ setRequirementsState(LOADING_STATE5);
1869
4236
  Promise.all([
1870
4237
  coinlist.fetchOfferRequirements(offerId),
1871
4238
  coinlist.fetchRequirementStatuses(offerId)
@@ -1891,7 +4258,8 @@ function useRequirements(offerId, options = {}) {
1891
4258
  }
1892
4259
 
1893
4260
  // src/client/components/requirements/RequirementsChecklist.tsx
1894
- var import_jsx_runtime14 = require("react/jsx-runtime");
4261
+ var import_jsx_runtime19 = require("react/jsx-runtime");
4262
+ var isWalletRequirement = (requirement) => RequirementVariant.fromType(requirement.type) === "wallet";
1895
4263
  var DEFAULT_LABELS = {
1896
4264
  kyc_approved: "KYC Verification",
1897
4265
  identity_verified: "Identity Verification",
@@ -1900,7 +4268,8 @@ var DEFAULT_LABELS = {
1900
4268
  external_wallet: "External Wallet",
1901
4269
  whitelisted_wallet: "Whitelisted Wallet",
1902
4270
  jurisdiction: "Jurisdiction Check",
1903
- accreditation: "Accreditation"
4271
+ accreditation: "Accreditation",
4272
+ document: "Document"
1904
4273
  };
1905
4274
  var DEFAULT_DESCRIPTIONS = {
1906
4275
  kyc_approved: "Complete Know Your Customer verification.",
@@ -1910,9 +4279,39 @@ var DEFAULT_DESCRIPTIONS = {
1910
4279
  external_wallet: "Connect an external wallet.",
1911
4280
  whitelisted_wallet: "Connect a whitelisted wallet.",
1912
4281
  jurisdiction: "Confirm your jurisdiction eligibility.",
1913
- accreditation: "Verify your accreditation status."
4282
+ accreditation: "Verify your accreditation status.",
4283
+ document: "Confirm your Tax Documents."
1914
4284
  };
1915
- function RequirementsChecklist({
4285
+ var VERIFICATION_POLL_INTERVAL_MS = 5e3;
4286
+ var VERIFICATION_POLL_TIMEOUT_MS = 12e4;
4287
+ function sleep(ms) {
4288
+ return new Promise((resolve) => setTimeout(resolve, ms));
4289
+ }
4290
+ function VerificationOverlay({
4291
+ onClose,
4292
+ children
4293
+ }) {
4294
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4295
+ "div",
4296
+ {
4297
+ role: "dialog",
4298
+ "aria-modal": "true",
4299
+ "aria-label": "Identity verification",
4300
+ className: "clcosdk:fixed clcosdk:inset-0 clcosdk:z-50 clcosdk:flex clcosdk:items-center clcosdk:justify-center clcosdk:bg-overlay clcosdk:p-4",
4301
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.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: [
4302
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4303
+ CloseButton,
4304
+ {
4305
+ onClick: onClose,
4306
+ className: "clcosdk:absolute clcosdk:top-4 clcosdk:right-4"
4307
+ }
4308
+ ),
4309
+ children
4310
+ ] })
4311
+ }
4312
+ );
4313
+ }
4314
+ function RequirementsChecklistBody({
1916
4315
  offerId,
1917
4316
  optionId,
1918
4317
  title,
@@ -1920,39 +4319,107 @@ function RequirementsChecklist({
1920
4319
  onContinue,
1921
4320
  onRequirementActionOverride,
1922
4321
  onContactSupportOverride,
4322
+ wallet,
4323
+ onRequestConnect,
1923
4324
  getLabel,
1924
4325
  getDescription,
1925
4326
  loading,
4327
+ unauthenticatedState,
1926
4328
  error,
1927
4329
  className,
1928
- data
4330
+ data,
4331
+ identityVerificationOptions
1929
4332
  }) {
1930
4333
  const { coinlist } = useCoinList();
1931
- const { requirementsState } = useRequirements(offerId, { data });
1932
- const [expandedIndex, setExpandedIndex] = (0, import_react6.useState)(null);
1933
- const onRequirementAction = onRequirementActionOverride !== void 0 ? onRequirementActionOverride : (requirement) => coinlist.handleRequirement(requirement);
4334
+ const { requirementsState, refetch } = useRequirements(offerId, { data });
4335
+ const [expandedIndex, setExpandedIndex] = (0, import_react15.useState)(null);
4336
+ const [taxDocumentOpen, setTaxDocumentOpen] = (0, import_react15.useState)(false);
4337
+ const [walletConnectOpen, setConnectWalletOpen] = (0, import_react15.useState)(false);
4338
+ const [verifyingRequirementId, setVerifyingRequirementId] = (0, import_react15.useState)(null);
4339
+ const isMountedRef = (0, import_react15.useRef)(true);
4340
+ (0, import_react15.useEffect)(() => {
4341
+ isMountedRef.current = true;
4342
+ return () => {
4343
+ isMountedRef.current = false;
4344
+ };
4345
+ }, []);
4346
+ const [hasWalletRequirement, setHasWalletRequirement] = (0, import_react15.useState)(false);
4347
+ (0, import_react15.useEffect)(() => {
4348
+ if (requirementsState.type === "CONTENT") {
4349
+ setHasWalletRequirement(
4350
+ (requirementsState.requirements[optionId] ?? []).some(
4351
+ isWalletRequirement
4352
+ )
4353
+ );
4354
+ }
4355
+ }, [requirementsState, optionId]);
4356
+ const {
4357
+ addressesState,
4358
+ refetch: refetchAddresses,
4359
+ disconnect
4360
+ } = useOptionAddresses(offerId, optionId, {
4361
+ enabled: hasWalletRequirement
4362
+ });
4363
+ const optionAddresses = addressesState.type === "CONTENT" ? addressesState.addresses : [];
4364
+ const walletsStatus = addressesState.type === "ERROR" ? "error" : addressesState.type === "LOADING" ? "loading" : "ready";
4365
+ const onRemoveWallet = async (id) => {
4366
+ await disconnect(OfferOptionAddressId(id));
4367
+ refetch();
4368
+ };
4369
+ const onRequirementAction = onRequirementActionOverride !== void 0 ? onRequirementActionOverride : (requirement) => {
4370
+ if (requirement.type === "document") {
4371
+ setTaxDocumentOpen(true);
4372
+ return;
4373
+ }
4374
+ if ((requirement.type === "external_wallet" || requirement.type === "whitelisted_wallet") && wallet !== void 0 && (wallet !== null || onRequestConnect !== void 0)) {
4375
+ setConnectWalletOpen(true);
4376
+ return;
4377
+ }
4378
+ coinlist.handleRequirement(requirement);
4379
+ };
1934
4380
  const onContactSupport = onContactSupportOverride !== void 0 ? onContactSupportOverride : () => coinlist.contactSupport();
4381
+ const awaitVerificationResult = (requirementId, statusBeforeSubmit) => {
4382
+ void (async () => {
4383
+ const deadline = Date.now() + VERIFICATION_POLL_TIMEOUT_MS;
4384
+ while (Date.now() < deadline) {
4385
+ await sleep(VERIFICATION_POLL_INTERVAL_MS);
4386
+ if (!isMountedRef.current) return;
4387
+ try {
4388
+ const statuses2 = await coinlist.fetchRequirementStatuses(offerId);
4389
+ const current = statuses2.find((s) => s.id === requirementId)?.status;
4390
+ if (current !== void 0 && current !== statusBeforeSubmit) break;
4391
+ } catch (_) {
4392
+ }
4393
+ }
4394
+ if (isMountedRef.current) {
4395
+ setVerifyingRequirementId(null);
4396
+ refetch();
4397
+ }
4398
+ })();
4399
+ };
1935
4400
  if (requirementsState.type === "LOADING") {
1936
4401
  if (loading) return loading;
1937
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
4402
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1938
4403
  "output",
1939
4404
  {
1940
4405
  "aria-live": "polite",
1941
- className: "flex min-h-40 items-center justify-center rounded-2xl border border-border bg-background p-6",
1942
- children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: cn(typeClasses.body, "text-text-secondary"), children: "Loading requirements..." })
4406
+ 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",
4407
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: cn(typeClasses.body, "clcosdk:text-text-secondary"), children: "Loading requirements..." })
1943
4408
  }
1944
4409
  );
1945
4410
  }
1946
4411
  if (requirementsState.type === "ERROR") {
4412
+ if (requirementsState.reason === "not-authenticated") {
4413
+ return unauthenticatedState !== void 0 ? unauthenticatedState : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(CoinListSignInCard, {});
4414
+ }
1947
4415
  if (error) return error;
1948
- const errorMessage = requirementsState.reason === "not-authenticated" ? "Sign in to view requirements." : "Unable to load requirements right now. Please try again.";
1949
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
4416
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1950
4417
  AlertBanner,
1951
4418
  {
1952
4419
  variant: "error",
1953
4420
  icon: true,
1954
- content: errorMessage,
1955
- className: "w-full max-w-[28rem]"
4421
+ content: "Unable to load requirements right now. Please try again.",
4422
+ className: "clcosdk:w-full clcosdk:max-w-[28rem]"
1956
4423
  }
1957
4424
  );
1958
4425
  }
@@ -1962,76 +4429,394 @@ function RequirementsChecklist({
1962
4429
  const optionStatuses = statuses.filter((s) => requirementIds.has(s.id));
1963
4430
  const statusByRequirementId = new Map(optionStatuses.map((s) => [s.id, s]));
1964
4431
  const checklistStatus = ChecklistStatus.derive(optionStatuses);
1965
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: cn("flex w-full flex-col gap-4", className), children: [
1966
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-col gap-2", children: [
1967
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("h3", { className: cn(typeClasses.h3, "text-text-primary"), children: title }),
1968
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: cn(typeClasses.body, "text-text-secondary"), children: description })
1969
- ] }),
1970
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "flex flex-col divide-y divide-divider", children: requirements.map((req, index) => {
1971
- const statusInfo = statusByRequirementId.get(req.id);
1972
- const label = getLabel ? getLabel(req) : DEFAULT_LABELS[req.type];
1973
- const itemDescription = (getDescription ? getDescription(req) : null) ?? DEFAULT_DESCRIPTIONS[req.type];
1974
- let onActionBound;
1975
- if (onRequirementAction === null) {
1976
- onActionBound = null;
1977
- } else if (onRequirementAction) {
1978
- onActionBound = () => onRequirementAction(req);
4432
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
4433
+ "div",
4434
+ {
4435
+ className: cn(
4436
+ "clcosdk:flex clcosdk:w-full clcosdk:flex-col clcosdk:gap-4",
4437
+ className
4438
+ ),
4439
+ children: [
4440
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-2", children: [
4441
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h3", { className: cn(typeClasses.h3, "clcosdk:text-text-primary"), children: title }),
4442
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: cn(typeClasses.body, "clcosdk:text-text-secondary"), children: description })
4443
+ ] }),
4444
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:divide-y clcosdk:divide-divider", children: requirements.map((req, index) => {
4445
+ const statusInfo = statusByRequirementId.get(req.id);
4446
+ const label = getLabel ? getLabel(req) : DEFAULT_LABELS[req.type];
4447
+ const itemDescription = (getDescription ? getDescription(req) : null) ?? DEFAULT_DESCRIPTIONS[req.type];
4448
+ const inlineVerification = statusInfo?.kycLevel !== void 0 && onRequirementActionOverride === void 0;
4449
+ let onActionBound;
4450
+ if (onRequirementAction === null) {
4451
+ onActionBound = null;
4452
+ } else if (inlineVerification) {
4453
+ onActionBound = () => setVerifyingRequirementId(req.id);
4454
+ } else if (onRequirementAction) {
4455
+ onActionBound = () => onRequirementAction(req);
4456
+ }
4457
+ let onContactSupportBound;
4458
+ if (onContactSupport === null) {
4459
+ onContactSupportBound = null;
4460
+ } else if (onContactSupport) {
4461
+ onContactSupportBound = () => onContactSupport(req);
4462
+ }
4463
+ const walletRequirement = isWalletRequirement(req);
4464
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4465
+ RequirementItem,
4466
+ {
4467
+ ui: RequirementItemUi.fromDomain(
4468
+ req,
4469
+ statusInfo,
4470
+ label,
4471
+ itemDescription,
4472
+ walletRequirement ? optionAddresses : []
4473
+ ),
4474
+ expanded: expandedIndex === index,
4475
+ onToggle: () => setExpandedIndex((prev) => prev === index ? null : index),
4476
+ onAction: onActionBound,
4477
+ onRemoveWallet: walletRequirement ? onRemoveWallet : void 0,
4478
+ walletsStatus: walletRequirement ? walletsStatus : void 0,
4479
+ onContactSupport: onContactSupportBound
4480
+ },
4481
+ req.id
4482
+ );
4483
+ }) }),
4484
+ checklistStatus === "ineligible" && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4485
+ AlertBanner,
4486
+ {
4487
+ variant: "error",
4488
+ icon: true,
4489
+ content: "You are not eligible to participate."
4490
+ }
4491
+ ),
4492
+ onContinue && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4493
+ ClButton,
4494
+ {
4495
+ fullWidth: true,
4496
+ disabled: checklistStatus !== "eligible",
4497
+ onClick: onContinue,
4498
+ children: "Continue"
4499
+ }
4500
+ ),
4501
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4502
+ TaxDocumentModal,
4503
+ {
4504
+ isOpen: taxDocumentOpen,
4505
+ onClose: () => setTaxDocumentOpen(false),
4506
+ onSubmitted: () => refetch()
4507
+ }
4508
+ ),
4509
+ verifyingRequirementId !== null && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(VerificationOverlay, { onClose: () => setVerifyingRequirementId(null), children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4510
+ IdentityVerification,
4511
+ {
4512
+ levelName: identityVerificationOptions?.levelName ?? statusByRequirementId.get(verifyingRequirementId)?.kycLevel,
4513
+ reset: statusByRequirementId.get(verifyingRequirementId)?.kycReset ?? false,
4514
+ locale: identityVerificationOptions?.locale,
4515
+ onSubmitted: () => awaitVerificationResult(
4516
+ verifyingRequirementId,
4517
+ statusByRequirementId.get(verifyingRequirementId)?.status ?? "not_started"
4518
+ )
4519
+ }
4520
+ ) }),
4521
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4522
+ ConnectWalletModal,
4523
+ {
4524
+ isOpen: walletConnectOpen,
4525
+ onClose: () => setConnectWalletOpen(false),
4526
+ offerId,
4527
+ optionId,
4528
+ wallet: wallet ?? null,
4529
+ onRequestConnect,
4530
+ onConnected: () => {
4531
+ refetch();
4532
+ refetchAddresses();
4533
+ }
4534
+ }
4535
+ )
4536
+ ]
4537
+ }
4538
+ );
4539
+ }
4540
+ function RequirementsChecklist(props) {
4541
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(CoinListStyleScope, { children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(RequirementsChecklistBody, { ...props }) });
4542
+ }
4543
+
4544
+ // src/client/hooks/swap/useSwapOutputToken.ts
4545
+ var import_react16 = require("react");
4546
+ var LOADING_STATE6 = { type: "LOADING" };
4547
+ function useSwapOutputToken(options) {
4548
+ const { contractAddress, chain, enabled } = options;
4549
+ const { coinlist, isReady } = useCoinList();
4550
+ const [outputTokenState, setOutputTokenState] = (0, import_react16.useState)(LOADING_STATE6);
4551
+ const fetchIdRef = (0, import_react16.useRef)(0);
4552
+ (0, import_react16.useEffect)(() => {
4553
+ if (!enabled || !isReady) return;
4554
+ const currentFetchId = ++fetchIdRef.current;
4555
+ const load = async () => {
4556
+ try {
4557
+ const outputToken = await coinlist.swap.getOutputToken({
4558
+ contractAddress,
4559
+ chain
4560
+ });
4561
+ if (currentFetchId !== fetchIdRef.current) return;
4562
+ setOutputTokenState({ type: "CONTENT", outputToken });
4563
+ } catch {
4564
+ if (currentFetchId !== fetchIdRef.current) return;
4565
+ setOutputTokenState({ type: "ERROR" });
1979
4566
  }
1980
- let onContactSupportBound;
1981
- if (onContactSupport === null) {
1982
- onContactSupportBound = null;
1983
- } else if (onContactSupport) {
1984
- onContactSupportBound = () => onContactSupport(req);
4567
+ };
4568
+ load();
4569
+ return () => {
4570
+ ++fetchIdRef.current;
4571
+ };
4572
+ }, [coinlist, isReady, contractAddress, chain, enabled]);
4573
+ return { outputTokenState };
4574
+ }
4575
+
4576
+ // src/client/hooks/swap/useSwapQuote.ts
4577
+ var import_react17 = require("react");
4578
+
4579
+ // src/shared/core/blockchain/swap/constants.ts
4580
+ var SWAP_POLL_INTERVAL_MS = 15e3;
4581
+ var SLIPPAGE_OPTIONS_BPS = [25n, 50n, 100n, 200n, 500n].map(
4582
+ (n) => Bps(n)
4583
+ );
4584
+ var DEFAULT_SLIPPAGE_BPS = Bps(50n);
4585
+ var SUPERSTATE_SWAP_CONTRACT_ADDRESS_SEPOLIA = EvmContractAddress("0x84f8e9a6C9Cc12fe911259372EfCa5582C4ae557");
4586
+
4587
+ // src/shared/core/blockchain/swap/quote.ts
4588
+ var SwapQuote = {
4589
+ /**
4590
+ * Assembles a {@link SwapQuote} from a raw contract {@link SwapPreview}. The
4591
+ * input and fee are denominated in the input token; the output in the output
4592
+ * token.
4593
+ */
4594
+ fromPreview: (preview, inputDecimals, outputDecimals) => ({
4595
+ inputTokenAmount: BlockchainAmount({
4596
+ raw: preview.inputAmount,
4597
+ decimals: inputDecimals
4598
+ }),
4599
+ fee: BlockchainAmount({ raw: preview.fee, decimals: inputDecimals }),
4600
+ outputTokenAmount: BlockchainAmount({
4601
+ raw: preview.outputAmount,
4602
+ decimals: outputDecimals
4603
+ })
4604
+ })
4605
+ };
4606
+
4607
+ // src/client/hooks/swap/useSwapQuote.ts
4608
+ function useSwapQuote(options) {
4609
+ const {
4610
+ contractAddress,
4611
+ chain,
4612
+ inputAmount,
4613
+ inputTokenAddress,
4614
+ outputTokenDecimals,
4615
+ pollIntervalMs = SWAP_POLL_INTERVAL_MS,
4616
+ enabled
4617
+ } = options;
4618
+ const { coinlist, isReady } = useCoinList();
4619
+ const [quote, setQuote] = (0, import_react17.useState)(null);
4620
+ const [isLoading, setIsLoading] = (0, import_react17.useState)(true);
4621
+ const [isRefreshing, setIsRefreshing] = (0, import_react17.useState)(false);
4622
+ const isFetchingRef = (0, import_react17.useRef)(false);
4623
+ const hasQuoteRef = (0, import_react17.useRef)(false);
4624
+ const fetchIdRef = (0, import_react17.useRef)(0);
4625
+ (0, import_react17.useEffect)(() => {
4626
+ if (!isReady) return;
4627
+ if (!enabled) {
4628
+ setIsLoading(false);
4629
+ return;
4630
+ }
4631
+ const currentFetchId = ++fetchIdRef.current;
4632
+ isFetchingRef.current = false;
4633
+ const loadQuote = async () => {
4634
+ if (outputTokenDecimals === null) return;
4635
+ if (isFetchingRef.current) return;
4636
+ isFetchingRef.current = true;
4637
+ if (hasQuoteRef.current) {
4638
+ setIsRefreshing(true);
1985
4639
  }
1986
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1987
- RequirementItem,
1988
- {
1989
- ui: RequirementItemUi.fromDomain(
1990
- req,
1991
- statusInfo,
1992
- label,
1993
- itemDescription
1994
- ),
1995
- expanded: expandedIndex === index,
1996
- onToggle: () => setExpandedIndex((prev) => prev === index ? null : index),
1997
- onAction: onActionBound,
1998
- onContactSupport: onContactSupportBound
1999
- },
2000
- req.id
2001
- );
2002
- }) }),
2003
- checklistStatus === "ineligible" && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2004
- AlertBanner,
2005
- {
2006
- variant: "error",
2007
- icon: true,
2008
- content: "You are not eligible to participate."
4640
+ try {
4641
+ const preview = await coinlist.swap.getPreview({
4642
+ contractAddress,
4643
+ chain,
4644
+ inputToken: inputTokenAddress,
4645
+ amount: inputAmount.raw
4646
+ });
4647
+ if (currentFetchId !== fetchIdRef.current) return;
4648
+ setQuote(
4649
+ SwapQuote.fromPreview(
4650
+ preview,
4651
+ inputAmount.decimals,
4652
+ outputTokenDecimals
4653
+ )
4654
+ );
4655
+ if (!hasQuoteRef.current) {
4656
+ hasQuoteRef.current = true;
4657
+ setIsLoading(false);
4658
+ }
4659
+ } catch {
4660
+ } finally {
4661
+ if (currentFetchId === fetchIdRef.current) {
4662
+ isFetchingRef.current = false;
4663
+ setIsRefreshing(false);
4664
+ }
2009
4665
  }
2010
- ),
2011
- onContinue && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2012
- ClButton,
2013
- {
2014
- fullWidth: true,
2015
- disabled: checklistStatus !== "eligible",
2016
- onClick: onContinue,
2017
- children: "Continue"
4666
+ };
4667
+ loadQuote();
4668
+ const interval = setInterval(loadQuote, pollIntervalMs);
4669
+ return () => {
4670
+ clearInterval(interval);
4671
+ ++fetchIdRef.current;
4672
+ setIsRefreshing(false);
4673
+ };
4674
+ }, [
4675
+ coinlist,
4676
+ isReady,
4677
+ contractAddress,
4678
+ chain,
4679
+ inputAmount.raw,
4680
+ inputAmount.decimals,
4681
+ inputTokenAddress,
4682
+ outputTokenDecimals,
4683
+ pollIntervalMs,
4684
+ enabled
4685
+ ]);
4686
+ return { quote, isLoading, isRefreshing };
4687
+ }
4688
+
4689
+ // src/client/hooks/swap/useSwapTokenBalances.ts
4690
+ var import_react18 = require("react");
4691
+
4692
+ // src/shared/core/blockchain/token-registry.ts
4693
+ var USDC_SYMBOL = StablecoinSymbol("USDC");
4694
+ var USDC = {
4695
+ name: "USD Coin",
4696
+ symbol: USDC_SYMBOL,
4697
+ decimals: AssetDecimals(6)
4698
+ };
4699
+ var USDT_SYMBOL = StablecoinSymbol("USDT");
4700
+ var USDT = {
4701
+ name: "Tether USD",
4702
+ symbol: USDT_SYMBOL,
4703
+ decimals: AssetDecimals(6)
4704
+ };
4705
+ var USDC_ADDRESSES = {
4706
+ ethereum_mainnet: EvmContractAddress(
4707
+ "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
4708
+ ),
4709
+ ethereum_sepolia: EvmContractAddress(
4710
+ "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238"
4711
+ )
4712
+ };
4713
+ var USDT_ADDRESSES = {
4714
+ ethereum_mainnet: EvmContractAddress(
4715
+ "0xdac17f958d2ee523a2206206994597c13d831ec7"
4716
+ ),
4717
+ ethereum_sepolia: EvmContractAddress(
4718
+ "0x7169D38820dfd117C3FA1f22a697dBA58d90BA06"
4719
+ )
4720
+ };
4721
+ var TOKEN_REGISTRY = {
4722
+ erc20: (symbol) => {
4723
+ switch (symbol) {
4724
+ case "USDC":
4725
+ return USDC;
4726
+ case "USDT":
4727
+ return USDT;
4728
+ default:
4729
+ throw new Error(`Unknown asset symbol: ${symbol}`);
4730
+ }
4731
+ },
4732
+ contractAddress: (symbol, chain) => {
4733
+ switch (symbol) {
4734
+ case "USDC":
4735
+ return USDC_ADDRESSES[chain];
4736
+ case "USDT":
4737
+ return USDT_ADDRESSES[chain];
4738
+ default:
4739
+ throw new Error(`Unknown asset symbol: ${symbol}`);
4740
+ }
4741
+ }
4742
+ };
4743
+
4744
+ // src/client/hooks/swap/useSwapTokenBalances.ts
4745
+ function useSwapTokenBalances(options) {
4746
+ const {
4747
+ address,
4748
+ chain,
4749
+ assets,
4750
+ pollIntervalMs = SWAP_POLL_INTERVAL_MS,
4751
+ enabled
4752
+ } = options;
4753
+ const { coinlist, isReady } = useCoinList();
4754
+ const [balances, setBalances] = (0, import_react18.useState)(/* @__PURE__ */ new Map());
4755
+ const [isLoading, setIsLoading] = (0, import_react18.useState)(true);
4756
+ const fetchIdRef = (0, import_react18.useRef)(0);
4757
+ const isFetchingRef = (0, import_react18.useRef)(false);
4758
+ const assetsKey = assets.join(",");
4759
+ (0, import_react18.useEffect)(() => {
4760
+ if (!isReady) return;
4761
+ if (!enabled) {
4762
+ setIsLoading(false);
4763
+ return;
4764
+ }
4765
+ const symbols = assetsKey.split(",");
4766
+ const currentFetchId = ++fetchIdRef.current;
4767
+ isFetchingRef.current = false;
4768
+ let isFirstFetch = true;
4769
+ async function fetchBalances() {
4770
+ if (isFetchingRef.current) return;
4771
+ isFetchingRef.current = true;
4772
+ if (isFirstFetch) {
4773
+ setIsLoading(true);
2018
4774
  }
2019
- )
2020
- ] });
4775
+ const results = await Promise.allSettled(
4776
+ symbols.map(
4777
+ (symbol) => coinlist.swap.getTokenBalance({
4778
+ tokenAddress: TOKEN_REGISTRY.contractAddress(symbol, chain),
4779
+ owner: address,
4780
+ chain
4781
+ })
4782
+ )
4783
+ );
4784
+ if (currentFetchId !== fetchIdRef.current) return;
4785
+ isFetchingRef.current = false;
4786
+ const next = /* @__PURE__ */ new Map();
4787
+ symbols.forEach((symbol, i) => {
4788
+ const result = results[i];
4789
+ next.set(
4790
+ symbol,
4791
+ result.status === "fulfilled" ? result.value.balance : null
4792
+ );
4793
+ });
4794
+ setBalances(next);
4795
+ setIsLoading(false);
4796
+ isFirstFetch = false;
4797
+ }
4798
+ fetchBalances();
4799
+ const interval = setInterval(fetchBalances, pollIntervalMs);
4800
+ return () => {
4801
+ clearInterval(interval);
4802
+ ++fetchIdRef.current;
4803
+ };
4804
+ }, [coinlist, isReady, address, chain, assetsKey, pollIntervalMs, enabled]);
4805
+ return { balances, isLoading };
2021
4806
  }
2022
4807
 
2023
4808
  // src/client/hooks/useCompleteOAuth.ts
2024
- var import_react7 = require("react");
4809
+ var import_react19 = require("react");
2025
4810
  function useCompleteOAuth(options) {
2026
4811
  const { coinlist } = useCoinList();
2027
- const postOAuthCompleteRef = (0, import_react7.useRef)(options.postOAuthComplete);
2028
- const onFailureRef = (0, import_react7.useRef)(options.onFailure);
2029
- const onSuccessRef = (0, import_react7.useRef)(options.onSuccess);
4812
+ const postOAuthCompleteRef = (0, import_react19.useRef)(options.postOAuthComplete);
4813
+ const onFailureRef = (0, import_react19.useRef)(options.onFailure);
4814
+ const onSuccessRef = (0, import_react19.useRef)(options.onSuccess);
2030
4815
  postOAuthCompleteRef.current = options.postOAuthComplete;
2031
4816
  onFailureRef.current = options.onFailure;
2032
4817
  onSuccessRef.current = options.onSuccess;
2033
- const hasStartedExchangeRef = (0, import_react7.useRef)(false);
2034
- (0, import_react7.useEffect)(() => {
4818
+ const hasStartedExchangeRef = (0, import_react19.useRef)(false);
4819
+ (0, import_react19.useEffect)(() => {
2035
4820
  if (typeof window === "undefined") return;
2036
4821
  const params = new URLSearchParams(window.location.search);
2037
4822
  if (!params.has("code") && !params.has("error")) return;
@@ -2075,19 +4860,19 @@ function useCompleteOAuth(options) {
2075
4860
  }
2076
4861
 
2077
4862
  // src/client/hooks/useOfferDetails.ts
2078
- var import_react8 = require("react");
2079
- var LOADING_STATE3 = { type: "LOADING" };
4863
+ var import_react20 = require("react");
4864
+ var LOADING_STATE7 = { type: "LOADING" };
2080
4865
  function useOfferDetails(offerId, options = {}) {
2081
4866
  const { coinlist, isReady } = useCoinList();
2082
4867
  const { data } = options;
2083
- const [offerDetailsState, setOfferDetailsState] = (0, import_react8.useState)(
2084
- data !== void 0 ? { type: "CONTENT", offerDetail: data } : LOADING_STATE3
4868
+ const [offerDetailsState, setOfferDetailsState] = (0, import_react20.useState)(
4869
+ data !== void 0 ? { type: "CONTENT", offerDetail: data } : LOADING_STATE7
2085
4870
  );
2086
- (0, import_react8.useEffect)(() => {
4871
+ (0, import_react20.useEffect)(() => {
2087
4872
  let isCancelled = false;
2088
4873
  if (!isReady) {
2089
4874
  if (data === void 0) {
2090
- setOfferDetailsState(LOADING_STATE3);
4875
+ setOfferDetailsState(LOADING_STATE7);
2091
4876
  }
2092
4877
  return () => {
2093
4878
  isCancelled = true;
@@ -2098,7 +4883,7 @@ function useOfferDetails(offerId, options = {}) {
2098
4883
  isCancelled = true;
2099
4884
  };
2100
4885
  }
2101
- setOfferDetailsState(LOADING_STATE3);
4886
+ setOfferDetailsState(LOADING_STATE7);
2102
4887
  coinlist.fetchOfferDetails(offerId).then((offerDetail) => {
2103
4888
  if (!isCancelled) {
2104
4889
  setOfferDetailsState({ type: "CONTENT", offerDetail });
@@ -2117,19 +4902,19 @@ function useOfferDetails(offerId, options = {}) {
2117
4902
  }
2118
4903
 
2119
4904
  // src/client/hooks/useParticipations.ts
2120
- var import_react9 = require("react");
2121
- var LOADING_STATE4 = { type: "LOADING" };
4905
+ var import_react21 = require("react");
4906
+ var LOADING_STATE8 = { type: "LOADING" };
2122
4907
  function useParticipations(offerId, options = {}) {
2123
4908
  const { coinlist, isReady } = useCoinList();
2124
4909
  const { data } = options;
2125
- const [participationsState, setParticipationsState] = (0, import_react9.useState)(
2126
- data !== void 0 ? { type: "CONTENT", participations: data } : LOADING_STATE4
4910
+ const [participationsState, setParticipationsState] = (0, import_react21.useState)(
4911
+ data !== void 0 ? { type: "CONTENT", participations: data } : LOADING_STATE8
2127
4912
  );
2128
- (0, import_react9.useEffect)(() => {
4913
+ (0, import_react21.useEffect)(() => {
2129
4914
  let isCancelled = false;
2130
4915
  if (!isReady) {
2131
4916
  if (data === void 0) {
2132
- setParticipationsState(LOADING_STATE4);
4917
+ setParticipationsState(LOADING_STATE8);
2133
4918
  }
2134
4919
  return () => {
2135
4920
  isCancelled = true;
@@ -2140,7 +4925,7 @@ function useParticipations(offerId, options = {}) {
2140
4925
  isCancelled = true;
2141
4926
  };
2142
4927
  }
2143
- setParticipationsState(LOADING_STATE4);
4928
+ setParticipationsState(LOADING_STATE8);
2144
4929
  coinlist.fetchParticipations(offerId).then((participations) => {
2145
4930
  if (!isCancelled) {
2146
4931
  setParticipationsState({ type: "CONTENT", participations });
@@ -2160,10 +4945,17 @@ function useParticipations(offerId, options = {}) {
2160
4945
  // Annotate the CommonJS export names for ESM import in node:
2161
4946
  0 && (module.exports = {
2162
4947
  ChecklistStatus,
4948
+ ClientSwapNamespaceImpl,
2163
4949
  CoinListClientInitializationError,
2164
4950
  CoinListContext,
4951
+ CoinListContextProvider,
2165
4952
  CoinListProvider,
2166
4953
  CoinListSignInCard,
4954
+ CoinListStyleScope,
4955
+ ConnectWalletModal,
4956
+ ConnectedWalletList,
4957
+ IdentityVerification,
4958
+ KycToken,
2167
4959
  OAUTH_CODE_VERIFIER_KEY,
2168
4960
  OAUTH_STATE_KEY,
2169
4961
  OfferCard,
@@ -2174,12 +4966,24 @@ function useParticipations(offerId, options = {}) {
2174
4966
  RequirementStatus,
2175
4967
  RequirementVariant,
2176
4968
  RequirementsChecklist,
4969
+ TaxDocumentModal,
4970
+ authorizeWallet,
4971
+ classifyWalletError,
4972
+ connectExternalWalletFlow,
2177
4973
  createCoinListClient,
4974
+ executeSwap,
2178
4975
  useCoinList,
2179
4976
  useCompleteOAuth,
4977
+ useConnectWallet,
4978
+ useKycToken,
2180
4979
  useOfferDetails,
2181
4980
  useOffers,
4981
+ useOptionAddresses,
2182
4982
  useParticipations,
2183
- useRequirements
4983
+ useRequirements,
4984
+ useSwapOutputToken,
4985
+ useSwapQuote,
4986
+ useSwapTokenBalances,
4987
+ useTaxDocument
2184
4988
  });
2185
4989
  //# sourceMappingURL=index.cjs.map