@coinlist-co/react 0.6.0 → 0.10.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 (39) hide show
  1. package/dist/{chunk-5C4TEVM7.js → chunk-7BJ2HAG7.js} +62 -92
  2. package/dist/chunk-7BJ2HAG7.js.map +1 -0
  3. package/dist/{chunk-5E3P7AMH.js → chunk-AAER5LOL.js} +3 -1
  4. package/dist/chunk-AAER5LOL.js.map +1 -0
  5. package/dist/chunk-GSSAB4K5.js +644 -0
  6. package/dist/chunk-GSSAB4K5.js.map +1 -0
  7. package/dist/chunk-TUZKKFNW.js +836 -0
  8. package/dist/chunk-TUZKKFNW.js.map +1 -0
  9. package/dist/client/index.cjs +3203 -412
  10. package/dist/client/index.cjs.map +1 -1
  11. package/dist/client/index.d.cts +996 -41
  12. package/dist/client/index.d.ts +996 -41
  13. package/dist/client/index.js +2069 -208
  14. package/dist/client/index.js.map +1 -1
  15. package/dist/collections-CJ24dOda.d.cts +28 -0
  16. package/dist/collections-ZYLKp8JB.d.ts +28 -0
  17. package/dist/requirement-CDi5NJI8.d.cts +1036 -0
  18. package/dist/requirement-CDi5NJI8.d.ts +1036 -0
  19. package/dist/server/index.cjs +588 -85
  20. package/dist/server/index.cjs.map +1 -1
  21. package/dist/server/index.d.cts +117 -17
  22. package/dist/server/index.d.ts +117 -17
  23. package/dist/server/index.js +92 -40
  24. package/dist/server/index.js.map +1 -1
  25. package/dist/shared/index.cjs +1334 -91
  26. package/dist/shared/index.cjs.map +1 -1
  27. package/dist/shared/index.d.cts +624 -3
  28. package/dist/shared/index.d.ts +624 -3
  29. package/dist/shared/index.js +220 -5
  30. package/dist/shared/index.js.map +1 -1
  31. package/package.json +7 -3
  32. package/dist/chunk-5C4TEVM7.js.map +0 -1
  33. package/dist/chunk-5E3P7AMH.js.map +0 -1
  34. package/dist/chunk-7SB2GKEU.js +0 -311
  35. package/dist/chunk-7SB2GKEU.js.map +0 -1
  36. package/dist/chunk-UEJVCU2J.js +0 -43
  37. package/dist/chunk-UEJVCU2J.js.map +0 -1
  38. package/dist/requirement-Dk6nYN1c.d.cts +0 -389
  39. package/dist/requirement-Dk6nYN1c.d.ts +0 -389
@@ -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,18 +17,32 @@ 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,
35
+ ClientTokenSaleNamespaceImpl: () => ClientTokenSaleNamespaceImpl,
24
36
  CoinListClientInitializationError: () => CoinListClientInitializationError,
25
37
  CoinListContext: () => CoinListContext,
26
38
  CoinListContextProvider: () => CoinListContextProvider,
27
39
  CoinListProvider: () => CoinListProvider,
28
40
  CoinListSignInCard: () => CoinListSignInCard,
29
41
  CoinListStyleScope: () => CoinListStyleScope,
42
+ ConnectWalletModal: () => ConnectWalletModal,
43
+ ConnectedWalletList: () => ConnectedWalletList,
44
+ IdentityVerification: () => IdentityVerification,
45
+ KycToken: () => KycToken,
30
46
  OAUTH_CODE_VERIFIER_KEY: () => OAUTH_CODE_VERIFIER_KEY,
31
47
  OAUTH_STATE_KEY: () => OAUTH_STATE_KEY,
32
48
  OfferCard: () => OfferCard,
@@ -37,49 +53,32 @@ __export(client_exports, {
37
53
  RequirementStatus: () => RequirementStatus,
38
54
  RequirementVariant: () => RequirementVariant,
39
55
  RequirementsChecklist: () => RequirementsChecklist,
56
+ TaxDocumentModal: () => TaxDocumentModal,
57
+ authorizeWallet: () => authorizeWallet,
58
+ classifyWalletError: () => classifyWalletError,
59
+ connectExternalWalletFlow: () => connectExternalWalletFlow,
40
60
  createCoinListClient: () => createCoinListClient,
61
+ executeSwap: () => executeSwap,
62
+ executeTokenSale: () => executeTokenSale,
41
63
  useCoinList: () => useCoinList,
42
64
  useCompleteOAuth: () => useCompleteOAuth,
65
+ useConnectWallet: () => useConnectWallet,
66
+ useKycToken: () => useKycToken,
43
67
  useOfferDetails: () => useOfferDetails,
44
68
  useOffers: () => useOffers,
69
+ useOptionAddresses: () => useOptionAddresses,
45
70
  useParticipations: () => useParticipations,
46
- useRequirements: () => useRequirements
71
+ useRequirements: () => useRequirements,
72
+ useSwapOutputToken: () => useSwapOutputToken,
73
+ useSwapQuote: () => useSwapQuote,
74
+ useSwapTokenBalances: () => useSwapTokenBalances,
75
+ useTaxDocument: () => useTaxDocument
47
76
  });
48
77
  module.exports = __toCommonJS(client_exports);
49
78
 
50
79
  // src/client/CoinListProvider.tsx
51
80
  var import_react = require("react");
52
81
 
53
- // src/client/generated/sdk-styles.gen.ts
54
- 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-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-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-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\\: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\\: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\\:min-h-0{min-height:calc(var(--clcosdk-spacing) * 0)}.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-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-\\[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-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\\:overflow-hidden{overflow:hidden}.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-brand-primary{background-color:var(--color-brand-primary)}.clcosdk\\:bg-error-subtle{background-color:var(--color-error-subtle)}.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-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-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\\:pt-4{padding-top:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\:pb-4{padding-bottom:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\:text-center{text-align:center}.clcosdk\\:text-left{text-align:left}.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)}}';
55
-
56
- // src/client/CoinListStyleScope.tsx
57
- var import_jsx_runtime = require("react/jsx-runtime");
58
- function CoinListStyleScope({ children }) {
59
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
60
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("link", { rel: "preconnect", href: "https://fonts.googleapis.com" }),
61
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
62
- "link",
63
- {
64
- rel: "preconnect",
65
- href: "https://fonts.gstatic.com",
66
- crossOrigin: "anonymous"
67
- }
68
- ),
69
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
70
- "link",
71
- {
72
- rel: "stylesheet",
73
- href: "https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap"
74
- }
75
- ),
76
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "clco-sdk-root", children: [
77
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { dangerouslySetInnerHTML: { __html: sdkStyles } }),
78
- children
79
- ] })
80
- ] });
81
- }
82
-
83
82
  // src/shared/utils.ts
84
83
  async function sha256(data) {
85
84
  const bytes = typeof data === "string" ? new TextEncoder().encode(data) : data;
@@ -175,6 +174,9 @@ var userAgent = () => ({ userAgent: true });
175
174
  var idempotencyKey = () => ({
176
175
  idempotencyKey: true
177
176
  });
177
+ var clientCredentials = (credentials) => ({
178
+ clientCredentials: credentials
179
+ });
178
180
  var retryAttempt = (attempt) => ({
179
181
  retryAttempt: attempt
180
182
  });
@@ -186,6 +188,7 @@ var needUserAgent = (attrs) => attrs?.userAgent === true;
186
188
  var isIdempotent = (attrs) => attrs?.idempotencyKey === true;
187
189
  var getRetryAttempt = (attrs) => attrs?.retryAttempt ?? 0;
188
190
  var wasRenewAttempted = (attrs) => attrs?.renewAttempted === true;
191
+ var getClientCredentials = (attrs) => attrs?.clientCredentials;
189
192
  var Attributes = {
190
193
  empty,
191
194
  concat,
@@ -199,7 +202,9 @@ var Attributes = {
199
202
  retryAttempt,
200
203
  getRetryAttempt,
201
204
  renewAttempted,
202
- wasRenewAttempted
205
+ wasRenewAttempted,
206
+ clientCredentials,
207
+ getClientCredentials
203
208
  };
204
209
 
205
210
  // src/client/core/api/middleware/user-agent.ts
@@ -399,7 +404,13 @@ function attachSessionMiddleware(fetchAccessToken) {
399
404
  if (!Attributes.isProtected(request.attributes)) {
400
405
  return request;
401
406
  }
402
- const accessToken = await fetchAccessToken(false);
407
+ let accessToken = await fetchAccessToken(false);
408
+ if (!accessToken) {
409
+ const clientCreds = Attributes.getClientCredentials(request.attributes);
410
+ if (clientCreds) {
411
+ accessToken = clientCreds;
412
+ }
413
+ }
403
414
  if (accessToken === null) {
404
415
  return request;
405
416
  }
@@ -528,81 +539,866 @@ var ApiClient = class {
528
539
  }
529
540
  };
530
541
 
531
- // src/shared/api/pagination.ts
532
- var Cursor = (value) => value;
533
- async function fetchAllPages(fetchPage, baseParams) {
534
- const items = [];
535
- let cursor = null;
536
- do {
537
- const params = {
538
- ...baseParams ?? {},
539
- after: cursor ?? void 0
542
+ // src/client/core/blockchain/wallet-error.ts
543
+ var import_viem = require("viem");
544
+ function classifyWalletError(error, ctx) {
545
+ if (error instanceof import_viem.UserRejectedRequestError) {
546
+ return { type: "user_rejected" };
547
+ }
548
+ if (error instanceof import_viem.InsufficientFundsError) {
549
+ return { type: "insufficient_funds" };
550
+ }
551
+ if (error instanceof import_viem.ContractFunctionRevertedError) {
552
+ return { type: "contract_reverted", reason: error.reason ?? error.message };
553
+ }
554
+ if (error instanceof import_viem.WaitForTransactionReceiptTimeoutError && ctx?.hash) {
555
+ return { type: "timeout", hash: ctx.hash };
556
+ }
557
+ return { type: "unknown", cause: error };
558
+ }
559
+
560
+ // src/shared/core/blockchain/abis/erc20.ts
561
+ var ERC20_ABI = [
562
+ {
563
+ type: "function",
564
+ name: "allowance",
565
+ inputs: [
566
+ { name: "owner", type: "address" },
567
+ { name: "spender", type: "address" }
568
+ ],
569
+ outputs: [{ name: "", type: "uint256" }],
570
+ stateMutability: "view"
571
+ },
572
+ {
573
+ type: "function",
574
+ name: "approve",
575
+ inputs: [
576
+ { name: "spender", type: "address" },
577
+ { name: "amount", type: "uint256" }
578
+ ],
579
+ outputs: [{ name: "", type: "bool" }],
580
+ stateMutability: "nonpayable"
581
+ },
582
+ {
583
+ type: "function",
584
+ name: "balanceOf",
585
+ inputs: [{ name: "account", type: "address" }],
586
+ outputs: [{ name: "", type: "uint256" }],
587
+ stateMutability: "view"
588
+ },
589
+ {
590
+ type: "function",
591
+ name: "decimals",
592
+ inputs: [],
593
+ outputs: [{ name: "", type: "uint8" }],
594
+ stateMutability: "view"
595
+ },
596
+ {
597
+ type: "function",
598
+ name: "name",
599
+ inputs: [],
600
+ outputs: [{ name: "", type: "string" }],
601
+ stateMutability: "view"
602
+ },
603
+ {
604
+ type: "function",
605
+ name: "symbol",
606
+ inputs: [],
607
+ outputs: [{ name: "", type: "string" }],
608
+ stateMutability: "view"
609
+ },
610
+ {
611
+ type: "function",
612
+ name: "totalSupply",
613
+ inputs: [],
614
+ outputs: [{ name: "", type: "uint256" }],
615
+ stateMutability: "view"
616
+ },
617
+ {
618
+ type: "function",
619
+ name: "transfer",
620
+ inputs: [
621
+ { name: "recipient", type: "address" },
622
+ { name: "amount", type: "uint256" }
623
+ ],
624
+ outputs: [{ name: "", type: "bool" }],
625
+ stateMutability: "nonpayable"
626
+ },
627
+ {
628
+ type: "function",
629
+ name: "transferFrom",
630
+ inputs: [
631
+ { name: "sender", type: "address" },
632
+ { name: "recipient", type: "address" },
633
+ { name: "amount", type: "uint256" }
634
+ ],
635
+ outputs: [{ name: "", type: "bool" }],
636
+ stateMutability: "nonpayable"
637
+ },
638
+ {
639
+ type: "event",
640
+ name: "Approval",
641
+ inputs: [
642
+ { name: "owner", type: "address", indexed: true },
643
+ { name: "spender", type: "address", indexed: true },
644
+ { name: "value", type: "uint256", indexed: false }
645
+ ],
646
+ anonymous: false
647
+ },
648
+ {
649
+ type: "event",
650
+ name: "Transfer",
651
+ inputs: [
652
+ { name: "from", type: "address", indexed: true },
653
+ { name: "to", type: "address", indexed: true },
654
+ { name: "value", type: "uint256", indexed: false }
655
+ ],
656
+ anonymous: false
657
+ }
658
+ ];
659
+
660
+ // src/client/core/blockchain/erc20-approval.ts
661
+ async function submitErc20Approval(args) {
662
+ const {
663
+ wallet,
664
+ tokenAddress,
665
+ spender,
666
+ chain,
667
+ value,
668
+ pending,
669
+ confirming,
670
+ emit
671
+ } = args;
672
+ emit(pending);
673
+ let hash;
674
+ try {
675
+ hash = await wallet.writeContract({
676
+ abi: ERC20_ABI,
677
+ address: tokenAddress,
678
+ functionName: "approve",
679
+ args: [spender, value],
680
+ chain
681
+ });
682
+ } catch (error) {
683
+ return {
684
+ type: "error",
685
+ error: { step: "approval", cause: classifyWalletError(error) }
540
686
  };
541
- const page = await fetchPage(params);
542
- items.push(...page.data);
543
- cursor = page.startingAfter;
544
- } while (cursor);
545
- return items;
687
+ }
688
+ emit(confirming);
689
+ let receipt;
690
+ try {
691
+ receipt = await wallet.awaitTx(hash, chain);
692
+ } catch (error) {
693
+ return {
694
+ type: "error",
695
+ error: { step: "approval", cause: classifyWalletError(error, { hash }) }
696
+ };
697
+ }
698
+ if (receipt.status !== "success") {
699
+ return { type: "error", error: { step: "approval-reverted" } };
700
+ }
701
+ return { type: "ok", txHash: hash };
546
702
  }
547
- var PaginatedResponse = {
548
- fromDto: (dto, itemMapper) => ({
549
- data: dto.data.map(itemMapper),
550
- startingAfter: dto.starting_after ? Cursor(dto.starting_after) : null,
551
- startingBefore: dto.starting_before ? Cursor(dto.starting_before) : null
552
- })
703
+
704
+ // src/shared/core/blockchain/abis/superstate-swap.ts
705
+ var SUPERSTATE_SWAP_ABI = [
706
+ {
707
+ type: "function",
708
+ name: "authorized",
709
+ inputs: [{ name: "user", type: "address", internalType: "address" }],
710
+ outputs: [{ name: "", type: "bool", internalType: "bool" }],
711
+ stateMutability: "view"
712
+ },
713
+ {
714
+ type: "function",
715
+ name: "stopped",
716
+ inputs: [],
717
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
718
+ stateMutability: "view"
719
+ },
720
+ {
721
+ type: "function",
722
+ name: "SWAP_LEVEL",
723
+ inputs: [],
724
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
725
+ stateMutability: "view"
726
+ },
727
+ {
728
+ type: "function",
729
+ name: "preview",
730
+ inputs: [
731
+ { name: "token", type: "address", internalType: "address" },
732
+ { name: "amount", type: "uint256", internalType: "uint256" }
733
+ ],
734
+ outputs: [
735
+ {
736
+ name: "",
737
+ type: "tuple",
738
+ internalType: "struct Preview",
739
+ components: [
740
+ { name: "input", type: "uint256", internalType: "uint256" },
741
+ { name: "fee", type: "uint256", internalType: "uint256" },
742
+ { name: "output", type: "uint256", internalType: "uint256" }
743
+ ]
744
+ }
745
+ ],
746
+ stateMutability: "view"
747
+ },
748
+ {
749
+ type: "function",
750
+ name: "swap",
751
+ inputs: [
752
+ { name: "token", type: "address", internalType: "address" },
753
+ { name: "amount", type: "uint256", internalType: "uint256" },
754
+ { name: "slip", type: "uint256", internalType: "uint256" }
755
+ ],
756
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
757
+ stateMutability: "nonpayable"
758
+ },
759
+ {
760
+ type: "function",
761
+ name: "tokenBalance",
762
+ inputs: [{ name: "token", type: "address", internalType: "address" }],
763
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
764
+ stateMutability: "view"
765
+ },
766
+ {
767
+ type: "function",
768
+ name: "outputToken",
769
+ inputs: [],
770
+ outputs: [{ name: "", type: "address", internalType: "address" }],
771
+ stateMutability: "view"
772
+ },
773
+ {
774
+ type: "function",
775
+ name: "outputTokenBalance",
776
+ inputs: [],
777
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
778
+ stateMutability: "view"
779
+ },
780
+ {
781
+ type: "function",
782
+ name: "totals",
783
+ inputs: [{ name: "token", type: "address", internalType: "address" }],
784
+ outputs: [
785
+ {
786
+ name: "",
787
+ type: "tuple",
788
+ internalType: "struct SwapTotal",
789
+ components: [
790
+ { name: "inputSum", type: "uint256", internalType: "uint256" },
791
+ { name: "feeSum", type: "uint256", internalType: "uint256" },
792
+ { name: "outputSum", type: "uint256", internalType: "uint256" },
793
+ { name: "count", type: "uint256", internalType: "uint256" }
794
+ ]
795
+ }
796
+ ],
797
+ stateMutability: "view"
798
+ },
799
+ {
800
+ type: "function",
801
+ name: "totals",
802
+ inputs: [
803
+ { name: "user", type: "address", internalType: "address" },
804
+ { name: "token", type: "address", internalType: "address" }
805
+ ],
806
+ outputs: [
807
+ {
808
+ name: "",
809
+ type: "tuple",
810
+ internalType: "struct SwapTotal",
811
+ components: [
812
+ { name: "inputSum", type: "uint256", internalType: "uint256" },
813
+ { name: "feeSum", type: "uint256", internalType: "uint256" },
814
+ { name: "outputSum", type: "uint256", internalType: "uint256" },
815
+ { name: "count", type: "uint256", internalType: "uint256" }
816
+ ]
817
+ }
818
+ ],
819
+ stateMutability: "view"
820
+ },
821
+ {
822
+ type: "function",
823
+ name: "transfer",
824
+ inputs: [
825
+ { name: "to", type: "address", internalType: "address" },
826
+ { name: "amount", type: "uint256", internalType: "uint256" }
827
+ ],
828
+ outputs: [{ name: "", type: "bool", internalType: "bool" }],
829
+ stateMutability: "nonpayable"
830
+ },
831
+ {
832
+ type: "function",
833
+ name: "transfer",
834
+ inputs: [
835
+ { name: "to", type: "address", internalType: "address" },
836
+ { name: "token", type: "address", internalType: "address" },
837
+ { name: "amount", type: "uint256", internalType: "uint256" }
838
+ ],
839
+ outputs: [{ name: "", type: "bool", internalType: "bool" }],
840
+ stateMutability: "nonpayable"
841
+ },
842
+ {
843
+ type: "function",
844
+ name: "setBps",
845
+ inputs: [{ name: "points", type: "uint256", internalType: "uint256" }],
846
+ outputs: [{ name: "", type: "bool", internalType: "bool" }],
847
+ stateMutability: "nonpayable"
848
+ },
849
+ {
850
+ type: "event",
851
+ name: "Swapped",
852
+ inputs: [
853
+ { name: "user", type: "address", indexed: true, internalType: "address" },
854
+ {
855
+ name: "inputToken",
856
+ type: "address",
857
+ indexed: true,
858
+ internalType: "address"
859
+ },
860
+ {
861
+ name: "outputToken",
862
+ type: "address",
863
+ indexed: true,
864
+ internalType: "address"
865
+ },
866
+ {
867
+ name: "inputAmount",
868
+ type: "uint256",
869
+ indexed: false,
870
+ internalType: "uint256"
871
+ },
872
+ {
873
+ name: "outputAmount",
874
+ type: "uint256",
875
+ indexed: false,
876
+ internalType: "uint256"
877
+ }
878
+ ],
879
+ anonymous: false
880
+ },
881
+ {
882
+ type: "event",
883
+ name: "Transferred",
884
+ inputs: [
885
+ { name: "to", type: "address", indexed: true, internalType: "address" },
886
+ {
887
+ name: "token",
888
+ type: "address",
889
+ indexed: true,
890
+ internalType: "address"
891
+ },
892
+ {
893
+ name: "amount",
894
+ type: "uint256",
895
+ indexed: false,
896
+ internalType: "uint256"
897
+ }
898
+ ],
899
+ anonymous: false
900
+ },
901
+ {
902
+ type: "error",
903
+ name: "InvalidAddress",
904
+ inputs: []
905
+ },
906
+ {
907
+ type: "error",
908
+ name: "InsufficientAmount",
909
+ inputs: []
910
+ },
911
+ {
912
+ type: "error",
913
+ name: "InvalidAmount",
914
+ inputs: []
915
+ },
916
+ {
917
+ type: "error",
918
+ name: "SwapFailed",
919
+ inputs: [
920
+ { name: "user", type: "address", internalType: "address" },
921
+ { name: "token", type: "address", internalType: "address" }
922
+ ]
923
+ }
924
+ ];
925
+
926
+ // src/shared/types/blockchain/core.ts
927
+ var EvmWalletAddress = (value) => value;
928
+ var EvmContractAddress = (value) => value;
929
+ var HexEncodedTransactionData = (value) => value;
930
+ var AssetDecimals = (value) => value;
931
+ var MAX_UINT_256 = 2n ** 256n - 1n;
932
+ var assertUint256 = (value) => {
933
+ if (value < 0n || value > MAX_UINT_256) {
934
+ throw new Error(`Value out of uint256 bounds: ${value}`);
935
+ }
936
+ return value;
553
937
  };
554
- var PaginationParams = {
555
- toQueryParams: (params) => {
556
- const queryParams = {};
557
- if (params.after) {
558
- queryParams.starting_after = params.after;
938
+ var BlockchainAmount = Object.assign(
939
+ (value) => value,
940
+ {
941
+ add: (a, b) => combineAmounts(a, b, (x, y) => x + y),
942
+ sub: (a, b) => combineAmounts(a, b, (x, y) => x - y)
943
+ }
944
+ );
945
+ function combineAmounts(a, b, op) {
946
+ if (a.decimals !== b.decimals) {
947
+ throw new Error(
948
+ `Cannot combine BlockchainAmounts with different decimals: ${a.decimals} vs ${b.decimals}`
949
+ );
950
+ }
951
+ const raw = op(a.raw, b.raw);
952
+ if (raw < 0n || raw > MAX_UINT_256) {
953
+ throw new Error(`BlockchainAmount out of uint256 bounds: ${raw}`);
954
+ }
955
+ return BlockchainAmount({ raw, decimals: a.decimals });
956
+ }
957
+ var AssetSymbol = (value) => value;
958
+ var StablecoinSymbol = (value) => value;
959
+ var Bps = (value) => value;
960
+
961
+ // src/shared/core/blockchain/bps.ts
962
+ var BPS_DENOM = Bps(10000n);
963
+ function applyBps(amount, bps) {
964
+ return assertUint256(amount * bps / BPS_DENOM);
965
+ }
966
+
967
+ // src/shared/core/blockchain/swap/math.ts
968
+ function computePrice({
969
+ inputTokenAmount,
970
+ outputTokenAmount
971
+ }) {
972
+ if (outputTokenAmount.raw === 0n) return null;
973
+ const scale = 10n ** BigInt(outputTokenAmount.decimals);
974
+ const raw = assertUint256(
975
+ inputTokenAmount.raw * scale / outputTokenAmount.raw
976
+ );
977
+ return BlockchainAmount({ raw, decimals: inputTokenAmount.decimals });
978
+ }
979
+ function computeSlip(amount, slippage) {
980
+ const retained = Bps(assertUint256(BPS_DENOM - slippage));
981
+ const slipRaw = applyBps(amount.raw, retained);
982
+ return BlockchainAmount({ raw: slipRaw, decimals: amount.decimals });
983
+ }
984
+
985
+ // src/shared/core/blockchain/swap/status.ts
986
+ function isStopped(status) {
987
+ return (status.stopped & status.swapLevel) !== 0n;
988
+ }
989
+
990
+ // src/shared/core/blockchain/swap/swapped-event.ts
991
+ var import_viem2 = require("viem");
992
+ function decodeSwappedOutputAmount(receipt, outputDecimals) {
993
+ try {
994
+ const [swapped] = (0, import_viem2.parseEventLogs)({
995
+ abi: SUPERSTATE_SWAP_ABI,
996
+ eventName: "Swapped",
997
+ logs: receipt.logs
998
+ });
999
+ if (!swapped) return null;
1000
+ const raw = swapped.args.outputAmount;
1001
+ if (raw < 0n || raw > MAX_UINT_256) return null;
1002
+ return BlockchainAmount({ raw, decimals: outputDecimals });
1003
+ } catch {
1004
+ return null;
1005
+ }
1006
+ }
1007
+
1008
+ // src/client/core/blockchain/swap-flows.ts
1009
+ async function executeSwap(params) {
1010
+ const {
1011
+ swap,
1012
+ erc20,
1013
+ wallet,
1014
+ contractAddress,
1015
+ chain,
1016
+ inputTokenAddress,
1017
+ quote,
1018
+ slippageBps,
1019
+ onProgress
1020
+ } = params;
1021
+ const emit = (phase) => onProgress?.(phase);
1022
+ const inputAmount = BlockchainAmount.add(
1023
+ quote.inputTokenAmount,
1024
+ quote.fee
1025
+ ).raw;
1026
+ const minOut = computeSlip(quote.outputTokenAmount, slippageBps).raw;
1027
+ emit("checking-status");
1028
+ let status;
1029
+ try {
1030
+ status = await swap.getStatus({ contractAddress, chain });
1031
+ } catch {
1032
+ return { type: "error", error: { step: "status-check" } };
1033
+ }
1034
+ if (isStopped(status)) {
1035
+ return { type: "error", error: { step: "swap-stopped" } };
1036
+ }
1037
+ emit("checking-allowance");
1038
+ let allowance;
1039
+ try {
1040
+ allowance = await erc20.getTokenAllowance({
1041
+ tokenAddress: inputTokenAddress,
1042
+ owner: wallet.address,
1043
+ spender: contractAddress,
1044
+ chain
1045
+ });
1046
+ } catch {
1047
+ return { type: "error", error: { step: "allowance-check" } };
1048
+ }
1049
+ if (allowance.allowance < inputAmount) {
1050
+ if (allowance.allowance > 0n) {
1051
+ const reset = await submitErc20Approval({
1052
+ wallet,
1053
+ tokenAddress: inputTokenAddress,
1054
+ spender: contractAddress,
1055
+ chain,
1056
+ value: 0n,
1057
+ pending: "resetting-allowance",
1058
+ confirming: "confirming-allowance-reset",
1059
+ emit
1060
+ });
1061
+ if (reset.type === "error") return { type: "error", error: reset.error };
559
1062
  }
560
- if (params.before) {
561
- queryParams.starting_before = params.before;
1063
+ const approve = await submitErc20Approval({
1064
+ wallet,
1065
+ tokenAddress: inputTokenAddress,
1066
+ spender: contractAddress,
1067
+ chain,
1068
+ value: inputAmount,
1069
+ pending: "approving",
1070
+ confirming: "confirming-approval",
1071
+ emit
1072
+ });
1073
+ if (approve.type === "error")
1074
+ return { type: "error", error: approve.error };
1075
+ }
1076
+ emit("swapping");
1077
+ let swapTxHash;
1078
+ try {
1079
+ swapTxHash = await wallet.writeContract({
1080
+ abi: SUPERSTATE_SWAP_ABI,
1081
+ address: contractAddress,
1082
+ functionName: "swap",
1083
+ args: [inputTokenAddress, inputAmount, minOut],
1084
+ chain
1085
+ });
1086
+ } catch (error) {
1087
+ return {
1088
+ type: "error",
1089
+ error: { step: "swap", cause: classifyWalletError(error) }
1090
+ };
1091
+ }
1092
+ emit("confirming-swap");
1093
+ let receipt;
1094
+ try {
1095
+ receipt = await wallet.awaitTx(swapTxHash, chain);
1096
+ } catch (error) {
1097
+ return {
1098
+ type: "error",
1099
+ error: {
1100
+ step: "swap",
1101
+ cause: classifyWalletError(error, { hash: swapTxHash })
1102
+ }
1103
+ };
1104
+ }
1105
+ if (receipt.status !== "success") {
1106
+ return { type: "error", error: { step: "swap-reverted" } };
1107
+ }
1108
+ const outputAmount = decodeSwappedOutputAmount(receipt, quote.outputTokenAmount.decimals) ?? quote.outputTokenAmount;
1109
+ const finalQuote = { ...quote, outputTokenAmount: outputAmount };
1110
+ return {
1111
+ type: "success",
1112
+ swapTxHash,
1113
+ inputAmount: finalQuote.inputTokenAmount,
1114
+ fee: finalQuote.fee,
1115
+ outputAmount,
1116
+ pricePerShare: computePrice(finalQuote),
1117
+ recipientAddress: wallet.address
1118
+ };
1119
+ }
1120
+ async function authorizeWallet(params) {
1121
+ const { swap, wallet, offerId, contractAddress, chain, onProgress } = params;
1122
+ const emit = (phase) => onProgress?.(phase);
1123
+ const walletAddress = wallet.address;
1124
+ emit("checking-authorization");
1125
+ let auth;
1126
+ try {
1127
+ auth = await swap.getAuthorization({
1128
+ walletAddress,
1129
+ contractAddress,
1130
+ chain
1131
+ });
1132
+ } catch {
1133
+ return { type: "error", error: { step: "authorization-check" } };
1134
+ }
1135
+ if (auth.authorized) return { type: "success" };
1136
+ emit("requesting-challenge");
1137
+ let challenge;
1138
+ try {
1139
+ challenge = await swap.requestWalletOwnershipChallenge({
1140
+ walletAddress,
1141
+ chain,
1142
+ challengeType: "plain"
1143
+ });
1144
+ } catch {
1145
+ return { type: "error", error: { step: "challenge-request" } };
1146
+ }
1147
+ emit("signing-message");
1148
+ let signature;
1149
+ try {
1150
+ signature = await wallet.signMessage(challenge.message);
1151
+ } catch (error) {
1152
+ return {
1153
+ type: "error",
1154
+ error: { step: "signing", cause: classifyWalletError(error) }
1155
+ };
1156
+ }
1157
+ emit("submitting-signature");
1158
+ let allow;
1159
+ try {
1160
+ allow = await swap.allowWallet({
1161
+ offerId,
1162
+ walletAddress,
1163
+ chain,
1164
+ signature
1165
+ });
1166
+ } catch {
1167
+ return { type: "error", error: { step: "allow-wallet" } };
1168
+ }
1169
+ if (allow.action === "broadcast_transaction") {
1170
+ emit("broadcasting-transaction");
1171
+ let hash;
1172
+ try {
1173
+ hash = await wallet.broadcastRawTx({
1174
+ to: allow.to,
1175
+ data: allow.data,
1176
+ chain
1177
+ });
1178
+ } catch (error) {
1179
+ return {
1180
+ type: "error",
1181
+ error: { step: "broadcast", cause: classifyWalletError(error) }
1182
+ };
562
1183
  }
563
- if (params.limit) {
564
- queryParams.limit = params.limit;
1184
+ emit("awaiting-confirmation");
1185
+ try {
1186
+ await wallet.awaitTx(hash, chain);
1187
+ } catch (error) {
1188
+ return {
1189
+ type: "error",
1190
+ error: {
1191
+ step: "broadcast",
1192
+ cause: classifyWalletError(error, { hash })
1193
+ }
1194
+ };
565
1195
  }
566
- return queryParams;
567
1196
  }
568
- };
1197
+ emit("verifying-authorization");
1198
+ let reCheck;
1199
+ try {
1200
+ reCheck = await swap.getAuthorization({
1201
+ walletAddress,
1202
+ contractAddress,
1203
+ chain
1204
+ });
1205
+ } catch {
1206
+ return { type: "error", error: { step: "authorization-check" } };
1207
+ }
1208
+ if (!reCheck.authorized) {
1209
+ return { type: "error", error: { step: "not-authorized" } };
1210
+ }
1211
+ return { type: "success" };
1212
+ }
569
1213
 
570
- // src/shared/types/offer.ts
571
- var OfferId = (value) => value;
572
- var OfferSlug = (value) => value;
573
- var Offer = {
1214
+ // src/shared/types/swap.ts
1215
+ var SwapAuthorization = {
574
1216
  fromDto: (dto) => ({
575
- id: OfferId(dto.id),
576
- slug: OfferSlug(dto.slug),
577
- tagline: notBlankStringOrNull(dto.tagline),
578
- bannerUrl: notBlankStringOrNull(dto.banner_url),
579
- logoUrl: notBlankStringOrNull(dto.logo_url),
580
- startsAt: new Date(dto.starts_at),
581
- endsAt: new Date(dto.ends_at)
1217
+ authorized: dto.authorized
582
1218
  })
583
1219
  };
584
-
585
- // src/shared/types/asset.ts
586
- var AssetId = (value) => value;
587
- var AssetCode = (value) => value;
588
- var Asset = {
1220
+ var SwapPreview = {
589
1221
  fromDto: (dto) => ({
590
- id: AssetId(dto.id),
591
- code: AssetCode(dto.code),
592
- name: dto.name,
593
- fractionalDigits: dto.fractional_digits
1222
+ inputAmount: assertUint256(BigInt(dto.pay_input_amount)),
1223
+ fee: assertUint256(BigInt(dto.fee)),
1224
+ outputAmount: assertUint256(BigInt(dto.receive_output_amount))
594
1225
  })
595
1226
  };
596
-
597
- // src/shared/types/offer-detail.ts
598
- var OfferOptionId = (value) => value;
599
- var OfferOptionSlug = (value) => value;
600
- var OfferDetail = {
601
- fromDto: (dto) => {
602
- if (!Array.isArray(dto.funding_assets)) {
603
- throw new Error(`funding_assets must be an array`);
604
- }
605
- if (!Array.isArray(dto.options)) {
1227
+ var SwapStatus = {
1228
+ fromDto: (dto) => ({
1229
+ stopped: assertUint256(BigInt(dto.stopped)),
1230
+ swapLevel: assertUint256(BigInt(dto.swap_level))
1231
+ })
1232
+ };
1233
+ var TokenAllowance = {
1234
+ fromDto: (dto) => ({
1235
+ allowance: assertUint256(BigInt(dto.allowance))
1236
+ })
1237
+ };
1238
+ var TokenBalance = {
1239
+ fromDto: (dto) => ({
1240
+ balance: assertUint256(BigInt(dto.balance))
1241
+ })
1242
+ };
1243
+ var AllowWalletResponse = {
1244
+ fromDto: (dto) => {
1245
+ switch (dto.action) {
1246
+ case "broadcast_transaction":
1247
+ return {
1248
+ action: "broadcast_transaction",
1249
+ to: EvmContractAddress(dto.to),
1250
+ data: HexEncodedTransactionData(dto.data)
1251
+ };
1252
+ case "none":
1253
+ return {
1254
+ action: "none",
1255
+ alreadyAllowed: dto.already_allowed
1256
+ };
1257
+ default: {
1258
+ const _exhaustive = dto;
1259
+ return _exhaustive;
1260
+ }
1261
+ }
1262
+ }
1263
+ };
1264
+
1265
+ // src/shared/api/frontline/swap.ts
1266
+ async function getSwapAuthorization(api, params) {
1267
+ const dto = await api.send({
1268
+ method: "GET",
1269
+ url: "/v1/wallet/authorized",
1270
+ queryParams: {
1271
+ chain: params.chain,
1272
+ contract_address: params.contractAddress,
1273
+ wallet_address: params.walletAddress
1274
+ },
1275
+ attributes: Attributes.protected()
1276
+ });
1277
+ return SwapAuthorization.fromDto(dto);
1278
+ }
1279
+ async function getSwapOutputToken(api, params) {
1280
+ const dto = await api.send({
1281
+ method: "GET",
1282
+ url: "/v1/swap/output-token",
1283
+ queryParams: {
1284
+ chain: params.chain,
1285
+ contract_address: params.contractAddress
1286
+ },
1287
+ attributes: Attributes.protected()
1288
+ });
1289
+ return toErc20Asset(dto);
1290
+ }
1291
+ async function getSwapPreview(api, params) {
1292
+ const dto = await api.send({
1293
+ method: "GET",
1294
+ url: "/v1/swap/preview",
1295
+ queryParams: {
1296
+ chain: params.chain,
1297
+ contract_address: params.contractAddress,
1298
+ input_token: params.inputToken,
1299
+ amount: params.amount.toString()
1300
+ },
1301
+ attributes: Attributes.protected()
1302
+ });
1303
+ return SwapPreview.fromDto(dto);
1304
+ }
1305
+ async function getSwapStatus(api, params) {
1306
+ const dto = await api.send({
1307
+ method: "GET",
1308
+ url: "/v1/swap/status",
1309
+ queryParams: {
1310
+ chain: params.chain,
1311
+ contract_address: params.contractAddress
1312
+ },
1313
+ attributes: Attributes.protected()
1314
+ });
1315
+ return SwapStatus.fromDto(dto);
1316
+ }
1317
+ async function getTokenAllowance(api, params) {
1318
+ const dto = await api.send({
1319
+ method: "GET",
1320
+ url: "/v1/token/allowance",
1321
+ queryParams: {
1322
+ chain: params.chain,
1323
+ token_address: params.tokenAddress,
1324
+ owner: params.owner,
1325
+ spender: params.spender
1326
+ },
1327
+ attributes: Attributes.protected()
1328
+ });
1329
+ return TokenAllowance.fromDto(dto);
1330
+ }
1331
+ async function getTokenBalance(api, params) {
1332
+ const dto = await api.send({
1333
+ method: "GET",
1334
+ url: "/v1/token/balance",
1335
+ queryParams: {
1336
+ chain: params.chain,
1337
+ token_address: params.tokenAddress,
1338
+ owner: params.owner
1339
+ },
1340
+ attributes: Attributes.protected()
1341
+ });
1342
+ return TokenBalance.fromDto(dto);
1343
+ }
1344
+ async function allowWallet(api, params) {
1345
+ const dto = await api.send({
1346
+ method: "POST",
1347
+ url: `/v1/offers/${encodeURIComponent(params.offerId)}/allow-wallet`,
1348
+ body: {
1349
+ wallet_address: params.walletAddress,
1350
+ chain: params.chain,
1351
+ signature: params.signature
1352
+ },
1353
+ attributes: Attributes.protected()
1354
+ });
1355
+ return AllowWalletResponse.fromDto(dto);
1356
+ }
1357
+ function toErc20Asset(dto) {
1358
+ return {
1359
+ name: dto.name,
1360
+ symbol: AssetSymbol(dto.symbol),
1361
+ decimals: AssetDecimals(dto.decimals)
1362
+ };
1363
+ }
1364
+
1365
+ // src/shared/types/asset.ts
1366
+ var AssetId = (value) => value;
1367
+ var AssetCode = (value) => value;
1368
+ var Asset = {
1369
+ fromDto: (dto) => ({
1370
+ id: AssetId(dto.id),
1371
+ code: AssetCode(dto.code),
1372
+ name: dto.name,
1373
+ fractionalDigits: dto.fractional_digits
1374
+ })
1375
+ };
1376
+
1377
+ // src/shared/types/offer.ts
1378
+ var OfferId = (value) => value;
1379
+ var OfferSlug = (value) => value;
1380
+ var Offer = {
1381
+ fromDto: (dto) => ({
1382
+ id: OfferId(dto.id),
1383
+ slug: OfferSlug(dto.slug),
1384
+ type: dto.type,
1385
+ tagline: dto.tagline,
1386
+ bannerUrl: dto.banner_url,
1387
+ logoUrl: dto.logo_url,
1388
+ startsAt: new Date(dto.starts_at),
1389
+ endsAt: dto.ends_at ? new Date(dto.ends_at) : null
1390
+ })
1391
+ };
1392
+
1393
+ // src/shared/types/offer-detail.ts
1394
+ var OfferOptionId = (value) => value;
1395
+ var OfferOptionSlug = (value) => value;
1396
+ var OfferDetail = {
1397
+ fromDto: (dto) => {
1398
+ if (!Array.isArray(dto.funding_assets)) {
1399
+ throw new Error(`funding_assets must be an array`);
1400
+ }
1401
+ if (!Array.isArray(dto.options)) {
606
1402
  throw new Error(`options must be an array`);
607
1403
  }
608
1404
  if (!Array.isArray(dto.terms)) {
@@ -620,16 +1416,17 @@ var OfferDetail = {
620
1416
  return {
621
1417
  id: OfferId(dto.id),
622
1418
  slug: OfferSlug(dto.slug),
1419
+ type: dto.type,
623
1420
  name: dto.name,
624
1421
  asset: Asset.fromDto(dto.asset),
625
1422
  fundingAssets: dto.funding_assets.map(Asset.fromDto),
626
1423
  about: notBlankStringOrNull(dto.about),
627
- tagline: notBlankStringOrNull(dto.tagline),
628
- bannerUrl: notBlankStringOrNull(dto.banner_url),
629
- logoUrl: notBlankStringOrNull(dto.logo_url),
630
- category: notBlankStringOrNull(dto.category),
1424
+ tagline: dto.tagline,
1425
+ bannerUrl: dto.banner_url,
1426
+ logoUrl: dto.logo_url,
1427
+ category: dto.category,
631
1428
  startsAt: new Date(dto.starts_at),
632
- endsAt: new Date(dto.ends_at),
1429
+ endsAt: dto.ends_at ? new Date(dto.ends_at) : null,
633
1430
  faqs: dto.faqs.map(FaqItem.fromDto),
634
1431
  links: dto.links.map(Link.fromDto),
635
1432
  milestones: dto.milestones.map(Milestone.fromDto),
@@ -676,28 +1473,187 @@ var Milestone = {
676
1473
  })
677
1474
  };
678
1475
 
679
- // src/shared/api/frontline/offers.ts
680
- async function fetchOffers(api) {
681
- return fetchAllPages((params) => fetchOffersPage(api, params));
1476
+ // src/shared/types/offer-option-address.ts
1477
+ var OfferOptionAddressId = (value) => value;
1478
+ var OfferOptionAddress = {
1479
+ /** Maps the API DTO into the SDK offer-option-address domain model. */
1480
+ fromDto: (dto) => ({
1481
+ id: OfferOptionAddressId(dto.id),
1482
+ offerOptionId: OfferOptionId(dto.offer_option_id),
1483
+ address: EvmWalletAddress(dto.address),
1484
+ protocol: dto.protocol,
1485
+ createdAt: new Date(dto.created_at)
1486
+ })
1487
+ };
1488
+ var ConnectExternalWalletParams = {
1489
+ /** Maps connect-wallet params into the API DTO payload. */
1490
+ toDto: (params) => ({
1491
+ offer_option_id: params.offerOptionId,
1492
+ wallet_address: params.walletAddress,
1493
+ chain: params.chain,
1494
+ signature: params.signature
1495
+ })
1496
+ };
1497
+
1498
+ // src/shared/types/wallet-ownership-challenge.ts
1499
+ var WalletOwnershipChallenge = {
1500
+ /** Maps the API DTO into the SDK wallet-ownership-challenge domain model. */
1501
+ fromDto: (dto) => ({
1502
+ message: dto.message,
1503
+ expiresAt: new Date(dto.expires_at)
1504
+ })
1505
+ };
1506
+ var CreateWalletOwnershipChallengeParams = {
1507
+ /**
1508
+ * Maps challenge-request params into the API DTO payload. The discriminated
1509
+ * union guarantees SIWE fields are present exactly when `challengeType` is
1510
+ * `siwe`, so the mapping narrows on the discriminant.
1511
+ */
1512
+ toDto: (params) => {
1513
+ switch (params.challengeType) {
1514
+ case "plain":
1515
+ return {
1516
+ wallet_address: params.walletAddress,
1517
+ chain: params.chain,
1518
+ challenge_type: "plain"
1519
+ };
1520
+ case "siwe":
1521
+ return {
1522
+ wallet_address: params.walletAddress,
1523
+ chain: params.chain,
1524
+ challenge_type: "siwe",
1525
+ domain: params.domain,
1526
+ uri: params.uri,
1527
+ statement: params.statement
1528
+ };
1529
+ default: {
1530
+ const _exhaustive = params;
1531
+ return _exhaustive;
1532
+ }
1533
+ }
1534
+ }
1535
+ };
1536
+
1537
+ // src/shared/api/frontline/wallet-connect.ts
1538
+ async function createWalletOwnershipChallenge(api, params) {
1539
+ const dto = await api.send({
1540
+ method: "POST",
1541
+ url: "/v1/wallet-ownership",
1542
+ body: CreateWalletOwnershipChallengeParams.toDto(params),
1543
+ attributes: Attributes.protected()
1544
+ });
1545
+ return WalletOwnershipChallenge.fromDto(dto);
682
1546
  }
683
- async function fetchOffersPage(api, params) {
684
- const queryParams = PaginationParams.toQueryParams(params);
685
- const pageDto = await api.send({
1547
+ async function connectExternalWallet(api, offerId, params) {
1548
+ const dto = await api.send({
1549
+ method: "POST",
1550
+ url: `/v1/offers/${offerId}/addresses`,
1551
+ body: ConnectExternalWalletParams.toDto(params),
1552
+ attributes: Attributes.protected()
1553
+ });
1554
+ return OfferOptionAddress.fromDto(dto);
1555
+ }
1556
+ async function listOptionAddresses(api, offerId, offerOptionId) {
1557
+ const { data } = await api.send({
686
1558
  method: "GET",
687
- url: "/v1/offers",
688
- queryParams,
1559
+ url: `/v1/offers/${offerId}/addresses`,
1560
+ queryParams: { offer_option_id: offerOptionId },
689
1561
  attributes: Attributes.protected()
690
1562
  });
691
- return PaginatedResponse.fromDto(pageDto, Offer.fromDto);
1563
+ return data.map(OfferOptionAddress.fromDto);
692
1564
  }
693
- async function fetchOfferDetails(api, id) {
1565
+ async function removeOptionAddress(api, offerId, addressId) {
694
1566
  const dto = await api.send({
695
- method: "GET",
696
- url: `/v1/offers/${id}`,
1567
+ method: "DELETE",
1568
+ url: `/v1/offers/${offerId}/addresses/${addressId}`,
697
1569
  attributes: Attributes.protected()
698
1570
  });
699
- return OfferDetail.fromDto(dto);
1571
+ return OfferOptionAddress.fromDto(dto);
1572
+ }
1573
+
1574
+ // src/shared/core/swap-namespace.ts
1575
+ var SwapNamespaceImpl = class {
1576
+ constructor(ctx) {
1577
+ this.ctx = ctx;
1578
+ }
1579
+ async getAuthorization(params) {
1580
+ await this.ctx.ensureUserAuthenticated();
1581
+ return getSwapAuthorization(this.ctx.api, params);
1582
+ }
1583
+ async getPreview(params) {
1584
+ await this.ctx.ensureUserAuthenticated();
1585
+ return getSwapPreview(this.ctx.api, params);
1586
+ }
1587
+ async getStatus(params) {
1588
+ await this.ctx.ensureUserAuthenticated();
1589
+ return getSwapStatus(this.ctx.api, params);
1590
+ }
1591
+ async getOutputToken(params) {
1592
+ await this.ctx.ensureUserAuthenticated();
1593
+ return getSwapOutputToken(this.ctx.api, params);
1594
+ }
1595
+ async requestWalletOwnershipChallenge(params) {
1596
+ await this.ctx.ensureUserAuthenticated();
1597
+ return createWalletOwnershipChallenge(this.ctx.api, params);
1598
+ }
1599
+ async allowWallet(params) {
1600
+ await this.ctx.ensureUserAuthenticated();
1601
+ return allowWallet(this.ctx.api, params);
1602
+ }
1603
+ };
1604
+
1605
+ // src/client/core/client-swap-namespace.ts
1606
+ var ClientSwapNamespaceImpl = class extends SwapNamespaceImpl {
1607
+ constructor(ctx, erc20) {
1608
+ super(ctx);
1609
+ this.erc20 = erc20;
1610
+ }
1611
+ executeSwap(params) {
1612
+ return executeSwap({ ...params, swap: this, erc20: this.erc20 });
1613
+ }
1614
+ authorizeWallet(params) {
1615
+ return authorizeWallet({ ...params, swap: this });
1616
+ }
1617
+ };
1618
+
1619
+ // src/shared/api/pagination.ts
1620
+ var Cursor = (value) => value;
1621
+ async function fetchAllPages(fetchPage, baseParams) {
1622
+ const items = [];
1623
+ let cursor = null;
1624
+ do {
1625
+ const params = {
1626
+ ...baseParams ?? {},
1627
+ after: cursor ?? void 0
1628
+ };
1629
+ const page = await fetchPage(params);
1630
+ items.push(...page.data);
1631
+ cursor = page.startingAfter;
1632
+ } while (cursor);
1633
+ return items;
700
1634
  }
1635
+ var PaginatedResponse = {
1636
+ fromDto: (dto, itemMapper) => ({
1637
+ data: dto.data.map(itemMapper),
1638
+ startingAfter: dto.starting_after ? Cursor(dto.starting_after) : null,
1639
+ startingBefore: dto.starting_before ? Cursor(dto.starting_before) : null
1640
+ })
1641
+ };
1642
+ var PaginationParams = {
1643
+ toQueryParams: (params) => {
1644
+ const queryParams = {};
1645
+ if (params.after) {
1646
+ queryParams.starting_after = params.after;
1647
+ }
1648
+ if (params.before) {
1649
+ queryParams.starting_before = params.before;
1650
+ }
1651
+ if (params.limit) {
1652
+ queryParams.limit = params.limit;
1653
+ }
1654
+ return queryParams;
1655
+ }
1656
+ };
701
1657
 
702
1658
  // src/shared/types/participation.ts
703
1659
  var ParticipationId = (value) => value;
@@ -746,6 +1702,85 @@ var CreateParticipationParams = {
746
1702
  })
747
1703
  };
748
1704
 
1705
+ // src/client/core/blockchain/token-sale-flow.ts
1706
+ async function executeTokenSale(params) {
1707
+ const {
1708
+ erc20,
1709
+ tokenSale,
1710
+ wallet,
1711
+ offerId,
1712
+ offerOptionId,
1713
+ assetId,
1714
+ paymentTokenAddress,
1715
+ fundingContractAddress,
1716
+ chain,
1717
+ amount,
1718
+ onProgress
1719
+ } = params;
1720
+ const emit = (phase) => onProgress?.(phase);
1721
+ emit("checking-allowance");
1722
+ let currentAllowance;
1723
+ try {
1724
+ const allowance = await erc20.getTokenAllowance({
1725
+ tokenAddress: paymentTokenAddress,
1726
+ owner: wallet.address,
1727
+ spender: fundingContractAddress,
1728
+ chain
1729
+ });
1730
+ currentAllowance = allowance.allowance;
1731
+ } catch {
1732
+ return { type: "error", error: { step: "allowance-check" } };
1733
+ }
1734
+ if (currentAllowance > 0n) {
1735
+ const reset = await submitErc20Approval({
1736
+ wallet,
1737
+ tokenAddress: paymentTokenAddress,
1738
+ spender: fundingContractAddress,
1739
+ chain,
1740
+ value: 0n,
1741
+ pending: "resetting-allowance",
1742
+ confirming: "confirming-allowance-reset",
1743
+ emit
1744
+ });
1745
+ if (reset.type === "error") {
1746
+ return {
1747
+ type: "error",
1748
+ error: reset.error.step === "approval-reverted" ? { step: "allowance-reset-reverted" } : { step: "allowance-reset", cause: reset.error.cause }
1749
+ };
1750
+ }
1751
+ }
1752
+ const approve = await submitErc20Approval({
1753
+ wallet,
1754
+ tokenAddress: paymentTokenAddress,
1755
+ spender: fundingContractAddress,
1756
+ chain,
1757
+ value: amount.raw,
1758
+ pending: "approving",
1759
+ confirming: "confirming-approval",
1760
+ emit
1761
+ });
1762
+ if (approve.type === "error") {
1763
+ return { type: "error", error: approve.error };
1764
+ }
1765
+ const approvalTxHash = approve.txHash;
1766
+ emit("recording-participation");
1767
+ let participation;
1768
+ try {
1769
+ participation = await tokenSale.createParticipation({
1770
+ offerId,
1771
+ offerOptionId,
1772
+ chain: Blockchain(chain),
1773
+ walletAddress: WalletAddress(wallet.address),
1774
+ amount: amount.raw.toString(),
1775
+ assetId,
1776
+ approvalTransactionHash: approvalTxHash
1777
+ });
1778
+ } catch {
1779
+ return { type: "error", error: { step: "participation", approvalTxHash } };
1780
+ }
1781
+ return { type: "success", participation, approvalTxHash };
1782
+ }
1783
+
749
1784
  // src/shared/api/frontline/participations.ts
750
1785
  async function fetchParticipations(api, offerId) {
751
1786
  return fetchAllPages(
@@ -780,53 +1815,217 @@ async function createParticipation(api, params) {
780
1815
  return Participation.fromDto(dto);
781
1816
  }
782
1817
 
783
- // src/shared/types/requirement.ts
784
- var RequirementId = (value) => value;
785
- var Requirement = {
1818
+ // src/shared/core/token-sale-namespace.ts
1819
+ var TokenSaleNamespaceImpl = class {
1820
+ constructor(ctx) {
1821
+ this.ctx = ctx;
1822
+ }
1823
+ async fetchParticipations(offerId) {
1824
+ await this.ctx.ensureUserAuthenticated();
1825
+ return fetchParticipations(this.ctx.api, offerId);
1826
+ }
1827
+ async fetchParticipationsPage(params) {
1828
+ await this.ctx.ensureUserAuthenticated();
1829
+ return fetchParticipationsPage(this.ctx.api, params);
1830
+ }
1831
+ async fetchParticipation(id) {
1832
+ await this.ctx.ensureUserAuthenticated();
1833
+ return fetchParticipation(this.ctx.api, id);
1834
+ }
1835
+ async createParticipation(params) {
1836
+ await this.ctx.ensureUserAuthenticated();
1837
+ return createParticipation(this.ctx.api, params);
1838
+ }
1839
+ };
1840
+
1841
+ // src/client/core/client-token-sale-namespace.ts
1842
+ var ClientTokenSaleNamespaceImpl = class extends TokenSaleNamespaceImpl {
1843
+ constructor(ctx, erc20) {
1844
+ super(ctx);
1845
+ this.erc20 = erc20;
1846
+ }
1847
+ executeTokenSale(params) {
1848
+ return executeTokenSale({ ...params, erc20: this.erc20, tokenSale: this });
1849
+ }
1850
+ };
1851
+
1852
+ // src/shared/types/document-submission.ts
1853
+ var DocumentSubmission = {
786
1854
  fromDto: (dto) => ({
787
- id: RequirementId(dto.id),
788
- type: dto.type,
789
- details: dto.details
1855
+ status: dto.status,
1856
+ formType: dto.form_type
790
1857
  })
791
1858
  };
792
- var RequirementStatusInfo = {
793
- fromStatusesDto: (dto) => Object.entries(dto.statuses).map(([id, status]) => ({
794
- id: RequirementId(id),
795
- status
796
- }))
797
- };
798
1859
 
799
- // src/shared/api/frontline/requirements.ts
800
- async function fetchOfferRequirements(api, offerId) {
801
- const response = await api.send({
802
- method: "GET",
803
- url: `/v1/offers/${offerId}/requirements`,
1860
+ // src/shared/api/frontline/documents.ts
1861
+ async function submitDocument(api, documentType, fields) {
1862
+ const dto = await api.send({
1863
+ method: "POST",
1864
+ url: `/v1/documents/${documentType}/submission`,
1865
+ body: fields,
804
1866
  attributes: Attributes.protected()
805
1867
  });
806
- return Object.fromEntries(
807
- Object.entries(response.options).map(([optionId, list]) => [
808
- optionId,
809
- list.data.map(Requirement.fromDto)
810
- ])
811
- );
1868
+ return DocumentSubmission.fromDto(dto);
812
1869
  }
813
- async function fetchRequirementStatuses(api, offerId) {
814
- const response = await api.send({
815
- method: "GET",
816
- url: `/v1/offers/${offerId}/requirements/statuses`,
1870
+
1871
+ // src/shared/types/kyc.ts
1872
+ var KycToken = {
1873
+ fromDto: (dto) => ({
1874
+ token: dto.token
1875
+ })
1876
+ };
1877
+
1878
+ // src/shared/api/frontline/kyc.ts
1879
+ async function createKycToken(api, levelName, reset) {
1880
+ const dto = await api.send({
1881
+ method: "POST",
1882
+ url: "/v1/kyc-token",
1883
+ body: {
1884
+ ...levelName === void 0 ? {} : { level_name: levelName },
1885
+ ...reset === void 0 ? {} : { reset }
1886
+ },
817
1887
  attributes: Attributes.protected()
818
1888
  });
819
- return RequirementStatusInfo.fromStatusesDto(response);
1889
+ return KycToken.fromDto(dto);
820
1890
  }
821
1891
 
822
- // src/shared/types/oauth.ts
823
- var AuthorizationCode = (value) => value;
824
- var CodeVerifier = (value) => value;
825
- var CodeChallenge = (value) => value;
826
- var PKCEState = (value) => value;
827
-
828
- // src/shared/pkce.ts
829
- async function generatePKCEParams(config) {
1892
+ // src/shared/api/frontline/offers.ts
1893
+ async function fetchOffers(api, clientCreds) {
1894
+ return fetchAllPages((params) => fetchOffersPage(api, params, clientCreds));
1895
+ }
1896
+ async function fetchOffersPage(api, params, clientCreds) {
1897
+ const queryParams = PaginationParams.toQueryParams(params);
1898
+ const pageDto = await api.send({
1899
+ method: "GET",
1900
+ url: "/v1/offers",
1901
+ queryParams,
1902
+ attributes: Attributes.concat(
1903
+ Attributes.protected(),
1904
+ Attributes.clientCredentials(clientCreds)
1905
+ )
1906
+ });
1907
+ return PaginatedResponse.fromDto(pageDto, Offer.fromDto);
1908
+ }
1909
+ async function fetchOfferDetails(api, id, clientCreds) {
1910
+ const dto = await api.send({
1911
+ method: "GET",
1912
+ url: `/v1/offers/${id}`,
1913
+ attributes: Attributes.concat(
1914
+ Attributes.protected(),
1915
+ Attributes.clientCredentials(clientCreds)
1916
+ )
1917
+ });
1918
+ return OfferDetail.fromDto(dto);
1919
+ }
1920
+
1921
+ // src/shared/types/pii.ts
1922
+ var Iso2CountryCode = (value) => value;
1923
+ var PiiJurisdiction = {
1924
+ fromDto: (dto) => ({
1925
+ iso2: Iso2CountryCode(dto.iso_2),
1926
+ name: dto.name
1927
+ })
1928
+ };
1929
+ var PiiAddress = {
1930
+ fromDto: (dto) => ({
1931
+ street: dto.street,
1932
+ city: dto.city,
1933
+ state: dto.state,
1934
+ postalCode: dto.postal_code,
1935
+ country: dto.country
1936
+ })
1937
+ };
1938
+ var Pii = {
1939
+ fromDto: (dto) => ({
1940
+ kind: dto.kind,
1941
+ fullLegalName: dto.full_legal_name,
1942
+ dateOfBirth: dto.date_of_birth,
1943
+ jurisdiction: dto.jurisdiction ? PiiJurisdiction.fromDto(dto.jurisdiction) : null,
1944
+ taxId: dto.tax_id,
1945
+ permanentAddress: PiiAddress.fromDto(dto.permanent_address)
1946
+ })
1947
+ };
1948
+
1949
+ // src/shared/api/frontline/pii.ts
1950
+ async function fetchPii(api) {
1951
+ const dto = await api.send({
1952
+ method: "GET",
1953
+ url: "/v1/pii",
1954
+ attributes: Attributes.protected()
1955
+ });
1956
+ return Pii.fromDto(dto);
1957
+ }
1958
+
1959
+ // src/shared/types/requirement.ts
1960
+ var RequirementId = (value) => value;
1961
+ var Requirement = {
1962
+ fromDto: (dto) => ({
1963
+ id: RequirementId(dto.id),
1964
+ type: dto.type,
1965
+ details: dto.details
1966
+ })
1967
+ };
1968
+ var RequirementStatusInfo = {
1969
+ fromStatusesDto: (dto) => Object.entries(dto.statuses).map(
1970
+ ([id, value]) => typeof value === "string" ? { id: RequirementId(id), status: value, action: null } : {
1971
+ id: RequirementId(id),
1972
+ status: value.status,
1973
+ action: value.action ?? null,
1974
+ kycLevel: value.kyc_level,
1975
+ kycReset: value.kyc_reset
1976
+ }
1977
+ )
1978
+ };
1979
+
1980
+ // src/shared/api/frontline/requirements.ts
1981
+ async function fetchOfferRequirements(api, offerId, clientCreds) {
1982
+ const response = await api.send({
1983
+ method: "GET",
1984
+ url: `/v1/offers/${offerId}/requirements`,
1985
+ attributes: Attributes.concat(
1986
+ Attributes.protected(),
1987
+ Attributes.clientCredentials(clientCreds)
1988
+ )
1989
+ });
1990
+ return Object.fromEntries(
1991
+ Object.entries(response.options).map(([optionId, list]) => [
1992
+ optionId,
1993
+ list.data.map(Requirement.fromDto)
1994
+ ])
1995
+ );
1996
+ }
1997
+ async function fetchRequirementStatuses(api, offerId) {
1998
+ const response = await api.send({
1999
+ method: "GET",
2000
+ url: `/v1/offers/${offerId}/requirements/statuses`,
2001
+ attributes: Attributes.protected()
2002
+ });
2003
+ return RequirementStatusInfo.fromStatusesDto(response);
2004
+ }
2005
+
2006
+ // src/shared/core/erc20-namespace.ts
2007
+ var Erc20NamespaceImpl = class {
2008
+ constructor(ctx) {
2009
+ this.ctx = ctx;
2010
+ }
2011
+ async getTokenAllowance(params) {
2012
+ await this.ctx.ensureUserAuthenticated();
2013
+ return getTokenAllowance(this.ctx.api, params);
2014
+ }
2015
+ async getTokenBalance(params) {
2016
+ await this.ctx.ensureUserAuthenticated();
2017
+ return getTokenBalance(this.ctx.api, params);
2018
+ }
2019
+ };
2020
+
2021
+ // src/shared/types/oauth.ts
2022
+ var AuthorizationCode = (value) => value;
2023
+ var CodeVerifier = (value) => value;
2024
+ var CodeChallenge = (value) => value;
2025
+ var PKCEState = (value) => value;
2026
+
2027
+ // src/shared/pkce.ts
2028
+ async function generatePKCEParams(config) {
830
2029
  const state = generateSecureRandomBase64Url(32);
831
2030
  const codeVerifier = generateSecureRandomBase64Url(32);
832
2031
  const codeChallengeRaw = await sha256(codeVerifier);
@@ -865,6 +2064,13 @@ var CoinListClientImpl = class {
865
2064
  },
866
2065
  this.fetchAccessToken.bind(this)
867
2066
  );
2067
+ const ctx = {
2068
+ api: this.api,
2069
+ ensureUserAuthenticated: async () => this.ensureAuthenticated()
2070
+ };
2071
+ this.erc20 = new Erc20NamespaceImpl(ctx);
2072
+ this.tokenSale = new ClientTokenSaleNamespaceImpl(ctx, this.erc20);
2073
+ this.swap = new ClientSwapNamespaceImpl(ctx, this.erc20);
868
2074
  }
869
2075
  async init() {
870
2076
  await this.fetchAccessToken(true);
@@ -936,40 +2142,56 @@ var CoinListClientImpl = class {
936
2142
  }
937
2143
  async fetchOffers() {
938
2144
  this.ensureAuthenticated();
939
- return fetchOffers(this.api);
2145
+ return fetchOffers(this.api, void 0);
940
2146
  }
941
2147
  async fetchOffersPage(params) {
942
2148
  this.ensureAuthenticated();
943
- return fetchOffersPage(this.api, params);
2149
+ return fetchOffersPage(this.api, params, void 0);
944
2150
  }
945
2151
  async fetchOfferDetails(id) {
946
2152
  this.ensureAuthenticated();
947
- return fetchOfferDetails(this.api, id);
2153
+ return fetchOfferDetails(this.api, id, void 0);
948
2154
  }
949
- async fetchParticipations(offerId) {
2155
+ async createWalletOwnershipChallenge(params) {
950
2156
  this.ensureAuthenticated();
951
- return fetchParticipations(this.api, offerId);
2157
+ return createWalletOwnershipChallenge(this.api, params);
952
2158
  }
953
- async fetchParticipationsPage(params) {
2159
+ async connectExternalWallet(offerId, params) {
954
2160
  this.ensureAuthenticated();
955
- return fetchParticipationsPage(this.api, params);
2161
+ return connectExternalWallet(this.api, offerId, params);
956
2162
  }
957
- async fetchParticipation(id) {
2163
+ async listOptionAddresses(offerId, offerOptionId) {
958
2164
  this.ensureAuthenticated();
959
- return fetchParticipation(this.api, id);
2165
+ return listOptionAddresses(
2166
+ this.api,
2167
+ offerId,
2168
+ offerOptionId
2169
+ );
960
2170
  }
961
- async createParticipation(params) {
2171
+ async removeOptionAddress(offerId, addressId) {
962
2172
  this.ensureAuthenticated();
963
- return createParticipation(this.api, params);
2173
+ return removeOptionAddress(this.api, offerId, addressId);
964
2174
  }
965
2175
  async fetchOfferRequirements(offerId) {
966
2176
  this.ensureAuthenticated();
967
- return fetchOfferRequirements(this.api, offerId);
2177
+ return fetchOfferRequirements(this.api, offerId, void 0);
968
2178
  }
969
2179
  async fetchRequirementStatuses(offerId) {
970
2180
  this.ensureAuthenticated();
971
2181
  return fetchRequirementStatuses(this.api, offerId);
972
2182
  }
2183
+ async fetchPii() {
2184
+ this.ensureAuthenticated();
2185
+ return fetchPii(this.api);
2186
+ }
2187
+ async submitDocument(documentType, fields) {
2188
+ this.ensureAuthenticated();
2189
+ return submitDocument(this.api, documentType, fields);
2190
+ }
2191
+ async createKycToken(levelName, reset) {
2192
+ this.ensureAuthenticated();
2193
+ return createKycToken(this.api, levelName, reset);
2194
+ }
973
2195
  handleRequirement(requirement) {
974
2196
  const baseUrl = this._config.coinlistBaseUrl ?? COINLIST_BASE_URL;
975
2197
  let path;
@@ -996,6 +2218,9 @@ var CoinListClientImpl = class {
996
2218
  case "jurisdiction":
997
2219
  path = null;
998
2220
  break;
2221
+ case "document":
2222
+ path = null;
2223
+ break;
999
2224
  default: {
1000
2225
  const _exhaustive = requirement.type;
1001
2226
  return;
@@ -1021,7 +2246,7 @@ function createCoinListClient(config) {
1021
2246
  }
1022
2247
 
1023
2248
  // src/client/CoinListProvider.tsx
1024
- var import_jsx_runtime2 = require("react/jsx-runtime");
2249
+ var import_jsx_runtime = require("react/jsx-runtime");
1025
2250
  var CoinListContext = (0, import_react.createContext)(null);
1026
2251
  function CoinListContextProvider({
1027
2252
  config,
@@ -1049,10 +2274,53 @@ function CoinListContextProvider({
1049
2274
  };
1050
2275
  }, [coinlist]);
1051
2276
  const value = (0, import_react.useMemo)(() => ({ coinlist, isReady }), [coinlist, isReady]);
1052
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(CoinListContext.Provider, { value, children });
2277
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CoinListContext.Provider, { value, children });
1053
2278
  }
1054
- function CoinListProvider({ config, children }) {
1055
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(CoinListContextProvider, { config, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(CoinListStyleScope, { children }) });
2279
+ var CoinListProvider = CoinListContextProvider;
2280
+
2281
+ // src/client/CoinListStyleScope.tsx
2282
+ var import_react2 = require("react");
2283
+
2284
+ // src/client/generated/sdk-styles.gen.ts
2285
+ 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}}';
2286
+
2287
+ // src/client/CoinListStyleScope.tsx
2288
+ var import_jsx_runtime2 = require("react/jsx-runtime");
2289
+ var ScopeContext = (0, import_react2.createContext)(false);
2290
+ function CoinListStyleScope({ children }) {
2291
+ const alreadyScoped = (0, import_react2.useContext)(ScopeContext);
2292
+ if (alreadyScoped) {
2293
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children });
2294
+ }
2295
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
2296
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("link", { rel: "preconnect", href: "https://fonts.googleapis.com" }),
2297
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2298
+ "link",
2299
+ {
2300
+ rel: "preconnect",
2301
+ href: "https://fonts.gstatic.com",
2302
+ crossOrigin: "anonymous"
2303
+ }
2304
+ ),
2305
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2306
+ "link",
2307
+ {
2308
+ rel: "stylesheet",
2309
+ href: "https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap"
2310
+ }
2311
+ ),
2312
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "clco-sdk-root", style: { display: "contents" }, children: [
2313
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2314
+ "style",
2315
+ {
2316
+ href: "clco-sdk-styles",
2317
+ precedence: "default",
2318
+ dangerouslySetInnerHTML: { __html: sdkStyles }
2319
+ }
2320
+ ),
2321
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ScopeContext.Provider, { value: true, children })
2322
+ ] })
2323
+ ] });
1056
2324
  }
1057
2325
 
1058
2326
  // src/client/components/design-system/AlertBanner.tsx
@@ -1232,7 +2500,7 @@ function PoweredByCoinList({ className }) {
1232
2500
 
1233
2501
  // src/client/components/design-system/ClButton.tsx
1234
2502
  var import_class_variance_authority = require("class-variance-authority");
1235
- var import_react2 = require("react");
2503
+ var import_react3 = require("react");
1236
2504
  var import_jsx_runtime7 = require("react/jsx-runtime");
1237
2505
  var buttonVariants = (0, import_class_variance_authority.cva)(
1238
2506
  "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",
@@ -1284,7 +2552,7 @@ var buttonVariants = (0, import_class_variance_authority.cva)(
1284
2552
  }
1285
2553
  }
1286
2554
  );
1287
- var ClButton = (0, import_react2.forwardRef)(
2555
+ var ClButton = (0, import_react3.forwardRef)(
1288
2556
  ({
1289
2557
  className,
1290
2558
  variant,
@@ -1402,9 +2670,9 @@ function CoinListSignInButton({
1402
2670
  }
1403
2671
 
1404
2672
  // src/client/hooks/useCoinList.ts
1405
- var import_react3 = require("react");
2673
+ var import_react4 = require("react");
1406
2674
  function useCoinList() {
1407
- const context = (0, import_react3.useContext)(CoinListContext);
2675
+ const context = (0, import_react4.useContext)(CoinListContext);
1408
2676
  if (context === null) {
1409
2677
  throw new CoinListClientInitializationError();
1410
2678
  }
@@ -1432,7 +2700,7 @@ function CoinListSignInCard({
1432
2700
  const handleSignIn = onSignIn ?? (() => {
1433
2701
  void coinlist.startOAuth();
1434
2702
  });
1435
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2703
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(CoinListStyleScope, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1436
2704
  "div",
1437
2705
  {
1438
2706
  className: cn(
@@ -1471,7 +2739,7 @@ function CoinListSignInCard({
1471
2739
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PoweredByCoinList, { className: "clcosdk:mt-4" })
1472
2740
  ]
1473
2741
  }
1474
- );
2742
+ ) });
1475
2743
  }
1476
2744
 
1477
2745
  // src/client/components/offers/OfferCard.tsx
@@ -1486,7 +2754,7 @@ var OfferCardUi = {
1486
2754
  bannerUrl: offer.bannerUrl,
1487
2755
  logoUrl: offer.logoUrl,
1488
2756
  formattedStartsAt: monthYearFormatter.format(offer.startsAt),
1489
- formattedEndsAt: monthYearFormatter.format(offer.endsAt)
2757
+ formattedEndsAt: offer.endsAt ? monthYearFormatter.format(offer.endsAt) : null
1490
2758
  })
1491
2759
  };
1492
2760
  function OfferCard({
@@ -1537,7 +2805,7 @@ function OfferCard({
1537
2805
  ),
1538
2806
  /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: cn(typeClasses.label, "clcosdk:text-text-primary"), children: offer.formattedStartsAt })
1539
2807
  ] }),
1540
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-1", children: [
2808
+ offer.formattedEndsAt && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-1", children: [
1541
2809
  /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1542
2810
  "span",
1543
2811
  {
@@ -1545,7 +2813,13 @@ function OfferCard({
1545
2813
  children: "Ends"
1546
2814
  }
1547
2815
  ),
1548
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: cn(typeClasses.label, "clcosdk:text-text-primary"), children: offer.formattedEndsAt })
2816
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2817
+ "span",
2818
+ {
2819
+ className: cn(typeClasses.label, "clcosdk:text-text-primary"),
2820
+ children: offer.formattedEndsAt
2821
+ }
2822
+ )
1549
2823
  ] })
1550
2824
  ] })
1551
2825
  ] });
@@ -1565,154 +2839,712 @@ function OfferCard({
1565
2839
  onClick,
1566
2840
  children: cardContent
1567
2841
  }
1568
- );
1569
- } else {
1570
- cardNode = /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: baseClasses, children: cardContent });
1571
- }
1572
- if (!containerClassName) {
1573
- return cardNode;
1574
- }
1575
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: containerClassName, children: cardNode });
2842
+ );
2843
+ } else {
2844
+ cardNode = /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: baseClasses, children: cardContent });
2845
+ }
2846
+ const card = containerClassName ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: containerClassName, children: cardNode }) : cardNode;
2847
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(CoinListStyleScope, { children: card });
2848
+ }
2849
+
2850
+ // src/client/hooks/useOffers.ts
2851
+ var import_react5 = require("react");
2852
+ var LOADING_STATE = { type: "LOADING" };
2853
+ function useOffers(options = {}) {
2854
+ const { coinlist, isReady } = useCoinList();
2855
+ const { data: serverOffers } = options;
2856
+ const [offersState, setOffersState] = (0, import_react5.useState)(
2857
+ serverOffers !== void 0 ? { type: "CONTENT", offers: serverOffers } : LOADING_STATE
2858
+ );
2859
+ (0, import_react5.useEffect)(() => {
2860
+ let isCancelled = false;
2861
+ if (!isReady) {
2862
+ if (serverOffers === void 0) {
2863
+ setOffersState(LOADING_STATE);
2864
+ }
2865
+ return () => {
2866
+ isCancelled = true;
2867
+ };
2868
+ }
2869
+ if (serverOffers !== void 0) {
2870
+ return () => {
2871
+ isCancelled = true;
2872
+ };
2873
+ }
2874
+ setOffersState(LOADING_STATE);
2875
+ coinlist.fetchOffers().then((offers) => {
2876
+ if (!isCancelled) {
2877
+ setOffersState({ type: "CONTENT", offers });
2878
+ }
2879
+ }).catch((error) => {
2880
+ if (!isCancelled) {
2881
+ const reason = error instanceof NotAuthenticatedError ? "not-authenticated" : "generic-error";
2882
+ setOffersState({ type: "ERROR", reason });
2883
+ }
2884
+ });
2885
+ return () => {
2886
+ isCancelled = true;
2887
+ };
2888
+ }, [coinlist, isReady, serverOffers]);
2889
+ return { offersState };
2890
+ }
2891
+
2892
+ // src/client/components/offers/OffersGrid.tsx
2893
+ var import_jsx_runtime12 = require("react/jsx-runtime");
2894
+ var DEFAULT_MAX_COLUMNS = 3;
2895
+ function OffersGridBody({
2896
+ data,
2897
+ maxColumns,
2898
+ className,
2899
+ containerClassName,
2900
+ loading,
2901
+ error,
2902
+ emptyState,
2903
+ onOfferClick
2904
+ } = {}) {
2905
+ const { offersState } = useOffers({ data });
2906
+ const cols = Math.max(1, maxColumns ?? DEFAULT_MAX_COLUMNS);
2907
+ if (offersState.type === "LOADING") {
2908
+ if (loading) {
2909
+ return loading;
2910
+ }
2911
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2912
+ "output",
2913
+ {
2914
+ "aria-live": "polite",
2915
+ 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",
2916
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: cn(typeClasses.body, "clcosdk:text-text-secondary"), children: "Loading offers..." })
2917
+ }
2918
+ );
2919
+ }
2920
+ if (offersState.type === "ERROR") {
2921
+ if (error) {
2922
+ return error;
2923
+ }
2924
+ const errorMessage = offersState.reason === "not-authenticated" ? "Sign in to view available offers." : "Unable to load offers right now. Please try again.";
2925
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2926
+ AlertBanner,
2927
+ {
2928
+ variant: "error",
2929
+ icon: true,
2930
+ content: errorMessage,
2931
+ className: "clcosdk:w-full clcosdk:max-w-[28rem]"
2932
+ }
2933
+ );
2934
+ }
2935
+ if (offersState.offers.length === 0) {
2936
+ if (emptyState) {
2937
+ return emptyState;
2938
+ }
2939
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
2940
+ "output",
2941
+ {
2942
+ "aria-live": "polite",
2943
+ 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",
2944
+ children: [
2945
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2946
+ "p",
2947
+ {
2948
+ className: cn(
2949
+ typeClasses.body,
2950
+ "clcosdk:font-medium clcosdk:text-text-primary"
2951
+ ),
2952
+ children: "No offers available"
2953
+ }
2954
+ ),
2955
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: cn(typeClasses.subhead, "clcosdk:text-text-secondary"), children: "Check back soon for upcoming opportunities." })
2956
+ ]
2957
+ }
2958
+ );
2959
+ }
2960
+ const maxGridWidth = `calc(${cols} * 28rem + ${Math.max(cols - 1, 0)} * 1.5rem)`;
2961
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2962
+ "div",
2963
+ {
2964
+ className: cn(
2965
+ "clcosdk:flex clcosdk:w-full clcosdk:justify-center",
2966
+ containerClassName
2967
+ ),
2968
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2969
+ "div",
2970
+ {
2971
+ className: cn("clcosdk:grid clcosdk:w-full clcosdk:gap-6", className),
2972
+ style: {
2973
+ gridTemplateColumns: "repeat(auto-fit, minmax(min(100%, 20rem), 1fr))",
2974
+ maxWidth: maxGridWidth
2975
+ },
2976
+ children: offersState.offers.map((offer) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2977
+ OfferCard,
2978
+ {
2979
+ offer: OfferCardUi.fromDomain(offer),
2980
+ onClick: onOfferClick ? () => onOfferClick(offer) : void 0
2981
+ },
2982
+ offer.id
2983
+ ))
2984
+ }
2985
+ )
2986
+ }
2987
+ );
2988
+ }
2989
+ function OffersGrid(props = {}) {
2990
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(CoinListStyleScope, { children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(OffersGridBody, { ...props }) });
2991
+ }
2992
+
2993
+ // src/client/components/requirements/ConnectedWalletList.tsx
2994
+ var import_react6 = require("react");
2995
+ var import_jsx_runtime13 = require("react/jsx-runtime");
2996
+ function ConnectedWalletRow({
2997
+ wallet,
2998
+ onRemove
2999
+ }) {
3000
+ const [state, setState] = (0, import_react6.useState)("idle");
3001
+ const remove = async () => {
3002
+ if (!onRemove) return;
3003
+ setState("removing");
3004
+ try {
3005
+ await onRemove(wallet.id);
3006
+ setState("idle");
3007
+ } catch {
3008
+ setState("error");
3009
+ }
3010
+ };
3011
+ 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: [
3012
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3013
+ "span",
3014
+ {
3015
+ title: wallet.address,
3016
+ className: cn(
3017
+ typeClasses.body,
3018
+ "clcosdk:font-mono clcosdk:text-text-primary"
3019
+ ),
3020
+ children: wallet.shortAddress
3021
+ }
3022
+ ),
3023
+ onRemove != null && (state === "confirming" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "clcosdk:flex clcosdk:items-center clcosdk:gap-2", children: [
3024
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3025
+ "span",
3026
+ {
3027
+ className: cn(typeClasses.subhead, "clcosdk:text-text-secondary"),
3028
+ children: "Remove?"
3029
+ }
3030
+ ),
3031
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ClButton, { size: "sm", variant: "destructive", onClick: remove, children: "Remove" }),
3032
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3033
+ ClButton,
3034
+ {
3035
+ size: "sm",
3036
+ variant: "ghost",
3037
+ onClick: () => setState("idle"),
3038
+ children: "Cancel"
3039
+ }
3040
+ )
3041
+ ] }) : state === "error" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "clcosdk:flex clcosdk:items-center clcosdk:gap-2", children: [
3042
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: cn(typeClasses.subhead, "clcosdk:text-error"), children: "Couldn't remove." }),
3043
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3044
+ ClButton,
3045
+ {
3046
+ size: "sm",
3047
+ variant: "destructiveLink",
3048
+ onClick: () => setState("confirming"),
3049
+ children: "Try again"
3050
+ }
3051
+ )
3052
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3053
+ ClButton,
3054
+ {
3055
+ size: "sm",
3056
+ variant: "destructiveLink",
3057
+ disabled: state === "removing",
3058
+ onClick: () => setState("confirming"),
3059
+ children: state === "removing" ? "Removing\u2026" : "Remove"
3060
+ }
3061
+ ))
3062
+ ] });
3063
+ }
3064
+ function ConnectedWalletList({
3065
+ wallets,
3066
+ onRemove,
3067
+ onAdd,
3068
+ addLabel = "Add wallet",
3069
+ status = "ready",
3070
+ className
3071
+ }) {
3072
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3073
+ "div",
3074
+ {
3075
+ className: cn("clcosdk:flex clcosdk:flex-col clcosdk:gap-2", className),
3076
+ children: [
3077
+ 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)(
3078
+ AlertBanner,
3079
+ {
3080
+ variant: "error",
3081
+ content: "Couldn't load your connected wallets."
3082
+ }
3083
+ ) : 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)(
3084
+ ConnectedWalletRow,
3085
+ {
3086
+ wallet,
3087
+ onRemove
3088
+ },
3089
+ wallet.id
3090
+ )) }),
3091
+ onAdd != null && status !== "loading" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3092
+ ClButton,
3093
+ {
3094
+ size: "sm",
3095
+ variant: "secondary",
3096
+ onClick: onAdd,
3097
+ className: "clcosdk:self-start",
3098
+ children: addLabel
3099
+ }
3100
+ )
3101
+ ]
3102
+ }
3103
+ );
3104
+ }
3105
+
3106
+ // src/client/components/requirements/ConnectWalletModal.tsx
3107
+ var import_react8 = require("react");
3108
+
3109
+ // src/client/hooks/useConnectWallet.ts
3110
+ var import_react7 = require("react");
3111
+
3112
+ // src/client/core/connect-external-wallet.ts
3113
+ var DEFAULT_STATEMENT = "Sign this message to prove you own this wallet. This does not cost gas or move funds.";
3114
+ var TERMINAL_CODES = /* @__PURE__ */ new Set([
3115
+ "not_authenticated",
3116
+ "wallet_not_whitelisted",
3117
+ "max_wallets_reached"
3118
+ ]);
3119
+ var API_ERROR_CODES = /* @__PURE__ */ new Set([
3120
+ "wallet_not_whitelisted",
3121
+ "max_wallets_reached"
3122
+ ]);
3123
+ function flowError(code) {
3124
+ return { code, retryable: !TERMINAL_CODES.has(code) };
3125
+ }
3126
+ function siweContext() {
3127
+ if (typeof window === "undefined") return { domain: "", uri: "" };
3128
+ return { domain: window.location.host, uri: window.location.origin };
3129
+ }
3130
+ function apiErrorCode(error) {
3131
+ if (typeof error !== "object" || error === null) return void 0;
3132
+ const body = error.response?.body;
3133
+ return typeof body?.code === "string" ? body.code : void 0;
3134
+ }
3135
+ function classifyApiError(error) {
3136
+ if (error instanceof NotAuthenticatedError) {
3137
+ return flowError("not_authenticated");
3138
+ }
3139
+ const code = apiErrorCode(error);
3140
+ if (code !== void 0 && API_ERROR_CODES.has(code)) {
3141
+ return flowError(code);
3142
+ }
3143
+ return flowError("unknown");
3144
+ }
3145
+ function challengeParams(wallet, challengeType, statement) {
3146
+ switch (challengeType) {
3147
+ case "siwe":
3148
+ return {
3149
+ walletAddress: wallet.address,
3150
+ chain: wallet.chain,
3151
+ challengeType: "siwe",
3152
+ ...siweContext(),
3153
+ statement: statement ?? DEFAULT_STATEMENT
3154
+ };
3155
+ case "plain":
3156
+ return {
3157
+ walletAddress: wallet.address,
3158
+ chain: wallet.chain,
3159
+ challengeType: "plain"
3160
+ };
3161
+ default: {
3162
+ const _exhaustive = challengeType;
3163
+ return _exhaustive;
3164
+ }
3165
+ }
3166
+ }
3167
+ async function connectExternalWalletFlow(params) {
3168
+ const {
3169
+ coinlist,
3170
+ wallet,
3171
+ offerId,
3172
+ offerOptionId,
3173
+ challengeType,
3174
+ statement,
3175
+ isCancelled,
3176
+ onProgress
3177
+ } = params;
3178
+ const emit = (phase) => onProgress?.(phase);
3179
+ const cancelled = () => isCancelled?.() ?? false;
3180
+ emit("requesting-challenge");
3181
+ let challenge;
3182
+ try {
3183
+ challenge = await coinlist.createWalletOwnershipChallenge(
3184
+ challengeParams(wallet, challengeType ?? "siwe", statement)
3185
+ );
3186
+ } catch (error) {
3187
+ return { type: "error", error: classifyApiError(error) };
3188
+ }
3189
+ if (cancelled()) return { type: "cancelled" };
3190
+ emit("signing-message");
3191
+ let signature;
3192
+ try {
3193
+ signature = await wallet.signMessage(challenge.message);
3194
+ } catch (error) {
3195
+ if (classifyWalletError(error).type === "user_rejected") {
3196
+ return { type: "error", error: flowError("user_rejected") };
3197
+ }
3198
+ return { type: "error", error: flowError("unknown") };
3199
+ }
3200
+ if (cancelled()) return { type: "cancelled" };
3201
+ emit("submitting-signature");
3202
+ try {
3203
+ const binding = await coinlist.connectExternalWallet(offerId, {
3204
+ offerOptionId,
3205
+ walletAddress: wallet.address,
3206
+ chain: wallet.chain,
3207
+ signature
3208
+ });
3209
+ return { type: "success", binding };
3210
+ } catch (error) {
3211
+ return { type: "error", error: classifyApiError(error) };
3212
+ }
3213
+ }
3214
+
3215
+ // src/client/hooks/useConnectWallet.ts
3216
+ var IDLE_SIGN = { type: "idle", error: null };
3217
+ var ERROR_COPY = {
3218
+ not_authenticated: "Sign in to connect your wallet.",
3219
+ user_rejected: "Signature request declined. Approve it in your wallet to continue.",
3220
+ wallet_not_whitelisted: "This wallet is not approved for this offer.",
3221
+ max_wallets_reached: "You've reached the maximum number of wallets for this option.",
3222
+ unknown: "Unable to connect your wallet. Please try again."
3223
+ };
3224
+ function displayError(error) {
3225
+ return {
3226
+ code: error.code,
3227
+ message: ERROR_COPY[error.code],
3228
+ retryable: error.retryable
3229
+ };
3230
+ }
3231
+ function useConnectWallet({
3232
+ isOpen,
3233
+ offerId,
3234
+ offerOptionId,
3235
+ wallet,
3236
+ challengeType,
3237
+ statement
3238
+ }) {
3239
+ const { coinlist } = useCoinList();
3240
+ const [state, setState] = (0, import_react7.useState)(
3241
+ () => wallet ? { type: "READY", address: wallet.address, sign: IDLE_SIGN } : { type: "NEEDS_WALLET" }
3242
+ );
3243
+ const attempt = (0, import_react7.useRef)(0);
3244
+ (0, import_react7.useEffect)(() => {
3245
+ attempt.current += 1;
3246
+ if (!isOpen) return;
3247
+ setState(
3248
+ wallet ? { type: "READY", address: wallet.address, sign: IDLE_SIGN } : { type: "NEEDS_WALLET" }
3249
+ );
3250
+ }, [isOpen, wallet?.address]);
3251
+ (0, import_react7.useEffect)(
3252
+ () => () => {
3253
+ attempt.current += 1;
3254
+ },
3255
+ []
3256
+ );
3257
+ const onSign = (0, import_react7.useCallback)(() => {
3258
+ if (!wallet || state.type !== "READY") return;
3259
+ attempt.current += 1;
3260
+ const gen = attempt.current;
3261
+ setState({
3262
+ type: "READY",
3263
+ address: wallet.address,
3264
+ sign: { type: "signing" }
3265
+ });
3266
+ connectExternalWalletFlow({
3267
+ coinlist,
3268
+ wallet,
3269
+ offerId,
3270
+ offerOptionId,
3271
+ challengeType,
3272
+ statement,
3273
+ // Cancels the flow before signing / binding if this attempt is superseded.
3274
+ isCancelled: () => attempt.current !== gen
3275
+ }).then((result) => {
3276
+ if (attempt.current !== gen) return;
3277
+ if (result.type === "success") {
3278
+ setState({ type: "CONNECTED", binding: result.binding });
3279
+ } else if (result.type === "error") {
3280
+ setState({
3281
+ type: "READY",
3282
+ address: wallet.address,
3283
+ sign: { type: "idle", error: displayError(result.error) }
3284
+ });
3285
+ }
3286
+ });
3287
+ }, [
3288
+ wallet,
3289
+ state,
3290
+ coinlist,
3291
+ offerId,
3292
+ offerOptionId,
3293
+ challengeType,
3294
+ statement
3295
+ ]);
3296
+ return { state, onSign };
3297
+ }
3298
+
3299
+ // src/shared/core/blockchain/formatters.ts
3300
+ var import_viem3 = require("viem");
3301
+
3302
+ // src/shared/types/blockchain/ui.ts
3303
+ var ShortenedWalletAddress = (value) => value;
3304
+ var FormattedAmountAssetUi = (value) => value;
3305
+
3306
+ // src/shared/core/blockchain/formatters.ts
3307
+ function shortenAddress(address) {
3308
+ const short = address.length > 10 ? `${address.slice(0, 6)}\u2026${address.slice(-4)}` : address;
3309
+ return ShortenedWalletAddress(short);
3310
+ }
3311
+ var NA_AMOUNT_ASSET_UI = FormattedAmountAssetUi("-");
3312
+ var USD_FRACTION_DIGITS = AssetDecimals(2);
3313
+
3314
+ // src/client/components/requirements/ConnectWalletModal.tsx
3315
+ var import_jsx_runtime14 = require("react/jsx-runtime");
3316
+ function ConnectWalletModal({
3317
+ isOpen,
3318
+ onClose,
3319
+ offerId,
3320
+ optionId,
3321
+ wallet,
3322
+ onConnected,
3323
+ onRequestConnect,
3324
+ challengeType,
3325
+ statement,
3326
+ className
3327
+ }) {
3328
+ const { state, onSign } = useConnectWallet({
3329
+ isOpen,
3330
+ offerId,
3331
+ offerOptionId: optionId,
3332
+ wallet,
3333
+ challengeType,
3334
+ statement
3335
+ });
3336
+ const titleId = (0, import_react8.useId)();
3337
+ (0, import_react8.useEffect)(() => {
3338
+ if (state.type === "CONNECTED") {
3339
+ onConnected?.(state.binding);
3340
+ onClose();
3341
+ }
3342
+ }, [state]);
3343
+ if (!isOpen || state.type === "CONNECTED") return null;
3344
+ 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)(
3345
+ "div",
3346
+ {
3347
+ role: "dialog",
3348
+ "aria-modal": "true",
3349
+ "aria-labelledby": titleId,
3350
+ className: cn(
3351
+ "clcosdk:flex clcosdk:w-full clcosdk:max-w-md clcosdk:flex-col clcosdk:gap-6 clcosdk:rounded-2xl clcosdk:bg-background clcosdk:p-6",
3352
+ className
3353
+ ),
3354
+ children: [
3355
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "clcosdk:flex clcosdk:items-start clcosdk:justify-between clcosdk:gap-4", children: [
3356
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3357
+ "h3",
3358
+ {
3359
+ id: titleId,
3360
+ className: cn(typeClasses.h3, "clcosdk:text-text-primary"),
3361
+ children: "Connect your wallet"
3362
+ }
3363
+ ),
3364
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(CloseButton, { onClick: onClose })
3365
+ ] }),
3366
+ state.type === "NEEDS_WALLET" && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(NeedsWalletScreen, { onRequestConnect }),
3367
+ state.type === "READY" && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3368
+ ReadyScreen,
3369
+ {
3370
+ address: state.address,
3371
+ sign: state.sign,
3372
+ onSign,
3373
+ onRequestConnect
3374
+ }
3375
+ )
3376
+ ]
3377
+ }
3378
+ ) });
3379
+ }
3380
+ function NeedsWalletScreen({
3381
+ onRequestConnect
3382
+ }) {
3383
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-6", children: [
3384
+ /* @__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." }),
3385
+ onRequestConnect && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ClButton, { fullWidth: true, onClick: onRequestConnect, children: "Connect wallet" })
3386
+ ] });
3387
+ }
3388
+ function ReadyScreen({
3389
+ address,
3390
+ sign,
3391
+ onSign,
3392
+ onRequestConnect
3393
+ }) {
3394
+ const hasTerminalError = sign.type === "idle" && sign.error !== null && !sign.error.retryable;
3395
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-6", children: [
3396
+ /* @__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." }),
3397
+ /* @__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: [
3398
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: cn(typeClasses.label, "clcosdk:text-text-secondary"), children: "Wallet address" }),
3399
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: cn(typeClasses.body, "clcosdk:text-text-primary"), children: shortenAddress(address) })
3400
+ ] }),
3401
+ sign.type === "idle" && sign.error && // Live region: the error is inserted async after a failed attempt, so
3402
+ // screen readers need it announced rather than silently rendered.
3403
+ /* @__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 }) }),
3404
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3405
+ ClButton,
3406
+ {
3407
+ fullWidth: true,
3408
+ onClick: onSign,
3409
+ isLoading: sign.type === "signing",
3410
+ loadingText: "Waiting for signature...",
3411
+ disabled: hasTerminalError,
3412
+ children: "Sign & connect"
3413
+ }
3414
+ ),
3415
+ onRequestConnect && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3416
+ ClButton,
3417
+ {
3418
+ fullWidth: true,
3419
+ variant: "secondary",
3420
+ onClick: onRequestConnect,
3421
+ disabled: sign.type === "signing",
3422
+ children: "Use a different wallet"
3423
+ }
3424
+ )
3425
+ ] });
1576
3426
  }
1577
3427
 
1578
- // src/client/hooks/useOffers.ts
1579
- var import_react4 = require("react");
1580
- var LOADING_STATE = { type: "LOADING" };
1581
- function useOffers(options = {}) {
1582
- const { coinlist, isReady } = useCoinList();
1583
- const { data: serverOffers } = options;
1584
- const [offersState, setOffersState] = (0, import_react4.useState)(
1585
- serverOffers !== void 0 ? { type: "CONTENT", offers: serverOffers } : LOADING_STATE
1586
- );
1587
- (0, import_react4.useEffect)(() => {
1588
- let isCancelled = false;
1589
- if (!isReady) {
1590
- if (serverOffers === void 0) {
1591
- setOffersState(LOADING_STATE);
1592
- }
1593
- return () => {
1594
- isCancelled = true;
1595
- };
3428
+ // src/client/components/requirements/IdentityVerification.tsx
3429
+ var import_websdk_react = __toESM(require("@sumsub/websdk-react"), 1);
3430
+ var import_react10 = require("react");
3431
+
3432
+ // src/client/hooks/useKycToken.ts
3433
+ var import_react9 = require("react");
3434
+ var IDLE_STATE = { type: "IDLE" };
3435
+ var LOADING_STATE2 = { type: "LOADING" };
3436
+ function useKycToken(levelName, reset) {
3437
+ const { coinlist } = useCoinList();
3438
+ const [kycTokenState, setKycTokenState] = (0, import_react9.useState)(IDLE_STATE);
3439
+ const resetPendingRef = (0, import_react9.useRef)(reset === true);
3440
+ const tokenIssuedRef = (0, import_react9.useRef)(false);
3441
+ (0, import_react9.useEffect)(() => {
3442
+ if (!tokenIssuedRef.current) {
3443
+ resetPendingRef.current = reset === true;
1596
3444
  }
1597
- if (serverOffers !== void 0) {
1598
- return () => {
1599
- isCancelled = true;
1600
- };
3445
+ }, [reset]);
3446
+ const fetchToken = (0, import_react9.useCallback)(async () => {
3447
+ setKycTokenState(LOADING_STATE2);
3448
+ try {
3449
+ const kycToken = await coinlist.createKycToken(
3450
+ levelName,
3451
+ resetPendingRef.current
3452
+ );
3453
+ resetPendingRef.current = false;
3454
+ tokenIssuedRef.current = true;
3455
+ setKycTokenState({ type: "CONTENT", token: kycToken.token });
3456
+ return kycToken.token;
3457
+ } catch (error) {
3458
+ const reason = error instanceof NotAuthenticatedError ? "not-authenticated" : "generic-error";
3459
+ setKycTokenState({ type: "ERROR", reason });
3460
+ throw error;
1601
3461
  }
1602
- setOffersState(LOADING_STATE);
1603
- coinlist.fetchOffers().then((offers) => {
1604
- if (!isCancelled) {
1605
- setOffersState({ type: "CONTENT", offers });
1606
- }
1607
- }).catch((error) => {
1608
- if (!isCancelled) {
1609
- const reason = error instanceof NotAuthenticatedError ? "not-authenticated" : "generic-error";
1610
- setOffersState({ type: "ERROR", reason });
1611
- }
1612
- });
1613
- return () => {
1614
- isCancelled = true;
1615
- };
1616
- }, [coinlist, isReady, serverOffers]);
1617
- return { offersState };
3462
+ }, [coinlist, levelName]);
3463
+ return { kycTokenState, fetchToken };
1618
3464
  }
1619
3465
 
1620
- // src/client/components/offers/OffersGrid.tsx
1621
- var import_jsx_runtime12 = require("react/jsx-runtime");
1622
- var DEFAULT_MAX_COLUMNS = 3;
1623
- function OffersGrid({
1624
- data,
1625
- maxColumns,
1626
- className,
1627
- containerClassName,
1628
- loading,
1629
- error,
1630
- emptyState,
1631
- onOfferClick
1632
- } = {}) {
1633
- const { offersState } = useOffers({ data });
1634
- const cols = Math.max(1, maxColumns ?? DEFAULT_MAX_COLUMNS);
1635
- if (offersState.type === "LOADING") {
1636
- if (loading) {
1637
- return loading;
3466
+ // src/client/components/requirements/IdentityVerification.tsx
3467
+ var import_jsx_runtime15 = require("react/jsx-runtime");
3468
+ function IdentityVerification({
3469
+ levelName,
3470
+ reset,
3471
+ locale,
3472
+ onSubmitted,
3473
+ onError,
3474
+ className
3475
+ }) {
3476
+ const { kycTokenState, fetchToken } = useKycToken(levelName, reset);
3477
+ const fetchedRef = (0, import_react10.useRef)(false);
3478
+ (0, import_react10.useEffect)(() => {
3479
+ if (fetchedRef.current) return;
3480
+ fetchedRef.current = true;
3481
+ fetchToken().catch(() => {
3482
+ });
3483
+ }, [fetchToken]);
3484
+ const handleMessage = (type, payload) => {
3485
+ switch (type) {
3486
+ case "idCheck.onApplicantSubmitted":
3487
+ onSubmitted?.();
3488
+ break;
3489
+ case "idCheck.onError": {
3490
+ const message = payload?.message ?? "Verification error";
3491
+ onError?.(new Error(message));
3492
+ break;
3493
+ }
3494
+ default:
3495
+ break;
1638
3496
  }
1639
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3497
+ };
3498
+ const handleError = (error) => {
3499
+ onError?.(error instanceof Error ? error : new Error("Verification error"));
3500
+ };
3501
+ if (kycTokenState.type === "IDLE" || kycTokenState.type === "LOADING") {
3502
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1640
3503
  "output",
1641
3504
  {
1642
3505
  "aria-live": "polite",
1643
- 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",
1644
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: cn(typeClasses.body, "clcosdk:text-text-secondary"), children: "Loading offers..." })
1645
- }
1646
- );
1647
- }
1648
- if (offersState.type === "ERROR") {
1649
- if (error) {
1650
- return error;
1651
- }
1652
- const errorMessage = offersState.reason === "not-authenticated" ? "Sign in to view available offers." : "Unable to load offers right now. Please try again.";
1653
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1654
- AlertBanner,
1655
- {
1656
- variant: "error",
1657
- icon: true,
1658
- content: errorMessage,
1659
- className: "clcosdk:w-full clcosdk:max-w-[28rem]"
3506
+ className: cn(
3507
+ "clcosdk:flex clcosdk:min-h-40 clcosdk:items-center clcosdk:justify-center",
3508
+ className
3509
+ ),
3510
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: cn(typeClasses.body, "clcosdk:text-text-secondary"), children: "Loading identity verification..." })
1660
3511
  }
1661
3512
  );
1662
3513
  }
1663
- if (offersState.offers.length === 0) {
1664
- if (emptyState) {
1665
- return emptyState;
1666
- }
1667
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
1668
- "output",
3514
+ if (kycTokenState.type === "ERROR") {
3515
+ const errorMessage = kycTokenState.reason === "not-authenticated" ? "Sign in to verify your identity." : "Unable to start identity verification right now. Please try again.";
3516
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
3517
+ "div",
1669
3518
  {
1670
- "aria-live": "polite",
1671
- 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",
3519
+ className: cn("clcosdk:flex clcosdk:flex-col clcosdk:gap-4", className),
1672
3520
  children: [
1673
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1674
- "p",
3521
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(AlertBanner, { variant: "error", icon: true, content: errorMessage }),
3522
+ kycTokenState.reason !== "not-authenticated" && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3523
+ ClButton,
1675
3524
  {
1676
- className: cn(
1677
- typeClasses.body,
1678
- "clcosdk:font-medium clcosdk:text-text-primary"
1679
- ),
1680
- children: "No offers available"
3525
+ size: "sm",
3526
+ onClick: () => {
3527
+ fetchToken().catch(() => {
3528
+ });
3529
+ },
3530
+ children: "Try again"
1681
3531
  }
1682
- ),
1683
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: cn(typeClasses.subhead, "clcosdk:text-text-secondary"), children: "Check back soon for upcoming opportunities." })
3532
+ )
1684
3533
  ]
1685
3534
  }
1686
3535
  );
1687
3536
  }
1688
- const maxGridWidth = `calc(${cols} * 28rem + ${Math.max(cols - 1, 0)} * 1.5rem)`;
1689
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1690
- "div",
3537
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: cn("clcosdk:w-full", className), children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3538
+ import_websdk_react.default,
1691
3539
  {
1692
- className: cn(
1693
- "clcosdk:flex clcosdk:w-full clcosdk:justify-center",
1694
- containerClassName
1695
- ),
1696
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1697
- "div",
1698
- {
1699
- className: cn("clcosdk:grid clcosdk:w-full clcosdk:gap-6", className),
1700
- style: {
1701
- gridTemplateColumns: "repeat(auto-fit, minmax(min(100%, 20rem), 1fr))",
1702
- maxWidth: maxGridWidth
1703
- },
1704
- children: offersState.offers.map((offer) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1705
- OfferCard,
1706
- {
1707
- offer: OfferCardUi.fromDomain(offer),
1708
- onClick: onOfferClick ? () => onOfferClick(offer) : void 0
1709
- },
1710
- offer.id
1711
- ))
1712
- }
1713
- )
3540
+ accessToken: kycTokenState.token,
3541
+ expirationHandler: fetchToken,
3542
+ config: locale === void 0 ? {} : { lang: locale },
3543
+ options: { addViewportTag: false, adaptIframeHeight: true },
3544
+ onMessage: handleMessage,
3545
+ onError: handleError
1714
3546
  }
1715
- );
3547
+ ) });
1716
3548
  }
1717
3549
 
1718
3550
  // src/client/components/requirements/RequirementItem.tsx
@@ -1720,7 +3552,7 @@ var import_lucide_react4 = require("lucide-react");
1720
3552
 
1721
3553
  // src/client/components/design-system/StepStatusIcon.tsx
1722
3554
  var import_lucide_react3 = require("lucide-react");
1723
- var import_jsx_runtime13 = require("react/jsx-runtime");
3555
+ var import_jsx_runtime16 = require("react/jsx-runtime");
1724
3556
  var statusConfig = {
1725
3557
  required: {
1726
3558
  Icon: import_lucide_react3.Info,
@@ -1745,7 +3577,7 @@ var statusConfig = {
1745
3577
  };
1746
3578
  function StepStatusIcon({ status, className }) {
1747
3579
  const { Icon, colorClass, fillClass } = statusConfig[status];
1748
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3580
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1749
3581
  Icon,
1750
3582
  {
1751
3583
  className: cn(
@@ -1760,7 +3592,7 @@ function StepStatusIcon({ status, className }) {
1760
3592
  }
1761
3593
 
1762
3594
  // src/client/components/requirements/RequirementItem.tsx
1763
- var import_jsx_runtime14 = require("react/jsx-runtime");
3595
+ var import_jsx_runtime17 = require("react/jsx-runtime");
1764
3596
  var RequirementVariant = {
1765
3597
  fromType(type) {
1766
3598
  switch (type) {
@@ -1795,13 +3627,18 @@ var ChecklistStatus = {
1795
3627
  }
1796
3628
  };
1797
3629
  var RequirementItemUi = {
1798
- fromDomain(req, statusInfo, label, description, walletAddress) {
3630
+ fromDomain(req, statusInfo, label, description, addresses = []) {
1799
3631
  return {
1800
3632
  variant: RequirementVariant.fromType(req.type),
1801
3633
  status: statusInfo ? RequirementStatus.fromStatusValue(statusInfo.status) : "required",
1802
3634
  label,
1803
3635
  description,
1804
- walletAddress
3636
+ multiWallet: req.type === "whitelisted_wallet",
3637
+ connectedWallets: addresses.map((address) => ({
3638
+ id: address.id,
3639
+ address: address.address,
3640
+ shortAddress: shortenAddress(address.address)
3641
+ }))
1805
3642
  };
1806
3643
  }
1807
3644
  };
@@ -1813,9 +3650,9 @@ function VerificationActionZone({
1813
3650
  switch (status) {
1814
3651
  case "required":
1815
3652
  if (onAction === null) return null;
1816
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ClButton, { size: "sm", onClick: onAction, children: "Continue" });
3653
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ClButton, { size: "sm", onClick: onAction, children: "Continue" });
1817
3654
  case "pending":
1818
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3655
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1819
3656
  AlertBanner,
1820
3657
  {
1821
3658
  variant: "warning",
@@ -1823,16 +3660,16 @@ function VerificationActionZone({
1823
3660
  }
1824
3661
  );
1825
3662
  case "completed":
1826
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(AlertBanner, { variant: "success", content: "Identity verified." });
3663
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(AlertBanner, { variant: "success", content: "Identity verified." });
1827
3664
  case "rejected":
1828
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3665
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1829
3666
  AlertBanner,
1830
3667
  {
1831
3668
  variant: "error",
1832
- content: onContactSupport === null ? "Verification rejected." : /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
3669
+ content: onContactSupport === null ? "Verification rejected." : /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
1833
3670
  "Verification rejected.",
1834
3671
  " ",
1835
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3672
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1836
3673
  "button",
1837
3674
  {
1838
3675
  type: "button",
@@ -1849,25 +3686,61 @@ function VerificationActionZone({
1849
3686
  }
1850
3687
  function WalletActionZone({
1851
3688
  status,
1852
- walletAddress,
1853
- onAction
3689
+ multiWallet,
3690
+ connectedWallets,
3691
+ walletsStatus,
3692
+ onAction,
3693
+ onRemoveWallet
1854
3694
  }) {
3695
+ if (multiWallet) {
3696
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
3697
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3698
+ ConnectedWalletList,
3699
+ {
3700
+ wallets: connectedWallets,
3701
+ onRemove: onRemoveWallet,
3702
+ onAdd: onAction ?? void 0,
3703
+ status: walletsStatus
3704
+ }
3705
+ ),
3706
+ status === "rejected" && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3707
+ AlertBanner,
3708
+ {
3709
+ variant: "error",
3710
+ content: "One of these wallets is not eligible for this sale."
3711
+ }
3712
+ )
3713
+ ] });
3714
+ }
1855
3715
  if (status === "completed") {
1856
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
1857
- onAction !== null && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ClButton, { size: "sm", variant: "secondary", onClick: onAction, children: "Change wallet" }),
1858
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3716
+ const connected = connectedWallets[0];
3717
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
3718
+ onAction !== null && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ClButton, { size: "sm", variant: "secondary", onClick: onAction, children: "Change wallet" }),
3719
+ walletsStatus === "loading" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3720
+ AlertBanner,
3721
+ {
3722
+ variant: "info",
3723
+ content: "Loading your connected wallet\u2026"
3724
+ }
3725
+ ) : walletsStatus === "error" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3726
+ AlertBanner,
3727
+ {
3728
+ variant: "error",
3729
+ content: "Couldn't load your connected wallet."
3730
+ }
3731
+ ) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1859
3732
  AlertBanner,
1860
3733
  {
1861
3734
  variant: "success",
1862
- content: walletAddress ?? "Connected: 0xBa4b...9f2c"
3735
+ content: connected ? connected.shortAddress : "Wallet connected."
1863
3736
  }
1864
3737
  )
1865
3738
  ] });
1866
3739
  }
1867
3740
  if (status === "rejected") {
1868
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
1869
- onAction !== null && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ClButton, { size: "sm", onClick: onAction, children: "Connect wallet" }),
1870
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3741
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
3742
+ onAction !== null && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ClButton, { size: "sm", onClick: onAction, children: "Connect wallet" }),
3743
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1871
3744
  AlertBanner,
1872
3745
  {
1873
3746
  variant: "error",
@@ -1877,7 +3750,7 @@ function WalletActionZone({
1877
3750
  ] });
1878
3751
  }
1879
3752
  if (onAction === null) return null;
1880
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ClButton, { size: "sm", onClick: onAction, children: "Connect wallet" });
3753
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ClButton, { size: "sm", onClick: onAction, children: "Connect wallet" });
1881
3754
  }
1882
3755
  function RequirementItem({
1883
3756
  ui,
@@ -1885,14 +3758,19 @@ function RequirementItem({
1885
3758
  onToggle,
1886
3759
  className,
1887
3760
  onAction,
3761
+ onRemoveWallet,
3762
+ walletsStatus,
1888
3763
  onContactSupport
1889
3764
  }) {
1890
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
3765
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(CoinListStyleScope, { children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
1891
3766
  "div",
1892
3767
  {
1893
- className: cn("clcosdk:flex clcosdk:w-full clcosdk:flex-col", className),
3768
+ className: cn(
3769
+ "clcosdk:flex clcosdk:w-full clcosdk:flex-col",
3770
+ className
3771
+ ),
1894
3772
  children: [
1895
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
3773
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
1896
3774
  "button",
1897
3775
  {
1898
3776
  type: "button",
@@ -1900,9 +3778,9 @@ function RequirementItem({
1900
3778
  "aria-expanded": expanded,
1901
3779
  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",
1902
3780
  children: [
1903
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "clcosdk:flex clcosdk:items-center clcosdk:gap-3", children: [
1904
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(StepStatusIcon, { status: ui.status }),
1905
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3781
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "clcosdk:flex clcosdk:items-center clcosdk:gap-3", children: [
3782
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(StepStatusIcon, { status: ui.status }),
3783
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1906
3784
  "span",
1907
3785
  {
1908
3786
  className: cn(
@@ -1913,7 +3791,7 @@ function RequirementItem({
1913
3791
  }
1914
3792
  )
1915
3793
  ] }),
1916
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3794
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1917
3795
  import_lucide_react4.ChevronRight,
1918
3796
  {
1919
3797
  className: cn(
@@ -1926,63 +3804,542 @@ function RequirementItem({
1926
3804
  ]
1927
3805
  }
1928
3806
  ),
1929
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1930
- "div",
3807
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3808
+ "div",
3809
+ {
3810
+ className: cn(
3811
+ "clcosdk:grid clcosdk:transition-[grid-template-rows] clcosdk:duration-300 clcosdk:ease-in-out",
3812
+ expanded ? "clcosdk:grid-rows-[1fr]" : "clcosdk:grid-rows-[0fr]"
3813
+ ),
3814
+ 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: [
3815
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3816
+ "p",
3817
+ {
3818
+ className: cn(
3819
+ typeClasses.subhead,
3820
+ "clcosdk:text-text-secondary"
3821
+ ),
3822
+ children: ui.description
3823
+ }
3824
+ ),
3825
+ ui.variant === "verification" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3826
+ VerificationActionZone,
3827
+ {
3828
+ status: ui.status,
3829
+ onAction,
3830
+ onContactSupport
3831
+ }
3832
+ ) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3833
+ WalletActionZone,
3834
+ {
3835
+ status: ui.status,
3836
+ multiWallet: ui.multiWallet,
3837
+ connectedWallets: ui.connectedWallets,
3838
+ walletsStatus,
3839
+ onAction,
3840
+ onRemoveWallet
3841
+ }
3842
+ )
3843
+ ] }) })
3844
+ }
3845
+ )
3846
+ ]
3847
+ }
3848
+ ) });
3849
+ }
3850
+
3851
+ // src/client/components/requirements/RequirementsChecklist.tsx
3852
+ var import_react15 = require("react");
3853
+
3854
+ // src/client/components/requirements/TaxDocumentModal.tsx
3855
+ var import_react12 = require("react");
3856
+
3857
+ // src/client/hooks/useTaxDocument.ts
3858
+ var import_react11 = require("react");
3859
+ var IDLE_SIGN2 = { type: "idle", error: null };
3860
+ var LOADING_STATE3 = { type: "LOADING" };
3861
+ var SIGN_FAILED_MESSAGE = "Unable to sign document. Please try again.";
3862
+ var DOB_INVALID_MESSAGE = "Enter your date of birth as MM/DD/YYYY.";
3863
+ var FIELD_KEYS = {
3864
+ fullLegalName: "Full Name",
3865
+ dob: "DOB",
3866
+ countryOfCitizenship: "Country Of Citizenship",
3867
+ taxId: "Foreign Tax Number",
3868
+ permanentAddress: "Permanent Address"
3869
+ };
3870
+ function formatUsDate(date) {
3871
+ const month = String(date.getMonth() + 1).padStart(2, "0");
3872
+ const day = String(date.getDate()).padStart(2, "0");
3873
+ const year = String(date.getFullYear()).padStart(4, "0");
3874
+ return `${month}/${day}/${year}`;
3875
+ }
3876
+ function formatIsoDateOnly(isoDate) {
3877
+ const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(isoDate);
3878
+ if (!match) return "";
3879
+ const [, year, month, day] = match;
3880
+ return `${month}/${day}/${year}`;
3881
+ }
3882
+ function isValidUsDate(value) {
3883
+ const match = /^(\d{2})\/(\d{2})\/(\d{4})$/.exec(value);
3884
+ if (!match) return false;
3885
+ const [, mm, dd, yyyy] = match;
3886
+ const month = Number(mm);
3887
+ const day = Number(dd);
3888
+ const year = Number(yyyy);
3889
+ const date = new Date(year, month - 1, day);
3890
+ return date.getFullYear() === year && date.getMonth() === month - 1 && date.getDate() === day;
3891
+ }
3892
+ function mapPiiToFields(pii) {
3893
+ const { street, city, state, postalCode } = pii.permanentAddress;
3894
+ const cityLine = [postalCode, city].filter(Boolean).join(" ");
3895
+ const permanentAddress = [street, cityLine, state].filter(Boolean).join(", ");
3896
+ return {
3897
+ fullLegalName: pii.fullLegalName ?? "",
3898
+ // Date-only ISO from the backend, shown as MM/DD/YYYY. Blank until the
3899
+ // backend has a date of birth (the field is editable in the meantime).
3900
+ dob: formatIsoDateOnly(pii.dateOfBirth ?? ""),
3901
+ countryOfCitizenship: pii.jurisdiction?.name ?? "",
3902
+ taxId: pii.taxId ?? "",
3903
+ permanentAddress
3904
+ };
3905
+ }
3906
+ function addressPartsFromPii(pii) {
3907
+ return {
3908
+ city: pii.permanentAddress.city ?? "",
3909
+ country: pii.permanentAddress.country ?? ""
3910
+ };
3911
+ }
3912
+ function hasAnyFieldValue(fields) {
3913
+ return Object.values(fields).some((value) => value.trim() !== "");
3914
+ }
3915
+ function toSubmissionFields(fields, addressParts) {
3916
+ return {
3917
+ [FIELD_KEYS.fullLegalName]: fields.fullLegalName,
3918
+ [FIELD_KEYS.dob]: fields.dob,
3919
+ [FIELD_KEYS.countryOfCitizenship]: fields.countryOfCitizenship,
3920
+ [FIELD_KEYS.taxId]: fields.taxId,
3921
+ [FIELD_KEYS.permanentAddress]: fields.permanentAddress,
3922
+ City: addressParts.city,
3923
+ Country: addressParts.country,
3924
+ Signature: fields.fullLegalName,
3925
+ Date: formatUsDate(/* @__PURE__ */ new Date())
3926
+ };
3927
+ }
3928
+ function useTaxDocument({
3929
+ isOpen
3930
+ }) {
3931
+ const { coinlist, isReady } = useCoinList();
3932
+ const [state, setState] = (0, import_react11.useState)(LOADING_STATE3);
3933
+ (0, import_react11.useEffect)(() => {
3934
+ let isCancelled = false;
3935
+ if (!isOpen) {
3936
+ return () => {
3937
+ isCancelled = true;
3938
+ };
3939
+ }
3940
+ if (!isReady) {
3941
+ setState(LOADING_STATE3);
3942
+ return () => {
3943
+ isCancelled = true;
3944
+ };
3945
+ }
3946
+ setState(LOADING_STATE3);
3947
+ coinlist.fetchPii().then((pii) => {
3948
+ if (isCancelled) return;
3949
+ if (pii.kind === "company") {
3950
+ setState({ type: "SIGN_ONLY", sign: IDLE_SIGN2 });
3951
+ return;
3952
+ }
3953
+ const fields = mapPiiToFields(pii);
3954
+ setState({
3955
+ type: "REVIEW",
3956
+ fields,
3957
+ addressParts: addressPartsFromPii(pii),
3958
+ piiUnavailable: !hasAnyFieldValue(fields),
3959
+ sign: IDLE_SIGN2
3960
+ });
3961
+ }).catch((error) => {
3962
+ if (isCancelled) return;
3963
+ setState({
3964
+ type: "ERROR",
3965
+ reason: error instanceof NotAuthenticatedError ? "not-authenticated" : "generic-error"
3966
+ });
3967
+ });
3968
+ return () => {
3969
+ isCancelled = true;
3970
+ };
3971
+ }, [coinlist, isReady, isOpen]);
3972
+ const onEditField = (0, import_react11.useCallback)(
3973
+ (field, value) => {
3974
+ setState(
3975
+ (prev) => prev.type === "EDITING" ? { ...prev, fields: { ...prev.fields, [field]: value } } : prev
3976
+ );
3977
+ },
3978
+ []
3979
+ );
3980
+ const onStartEdit = (0, import_react11.useCallback)(() => {
3981
+ setState(
3982
+ (prev) => prev.type === "REVIEW" ? {
3983
+ type: "EDITING",
3984
+ fields: prev.fields,
3985
+ original: prev.fields,
3986
+ addressParts: prev.addressParts,
3987
+ piiUnavailable: prev.piiUnavailable
3988
+ } : prev
3989
+ );
3990
+ }, []);
3991
+ const onSaveEdit = (0, import_react11.useCallback)(() => {
3992
+ setState(
3993
+ (prev) => prev.type === "EDITING" ? {
3994
+ type: "REVIEW",
3995
+ fields: prev.fields,
3996
+ addressParts: prev.addressParts,
3997
+ piiUnavailable: prev.piiUnavailable,
3998
+ sign: IDLE_SIGN2
3999
+ } : prev
4000
+ );
4001
+ }, []);
4002
+ const onCancelEdit = (0, import_react11.useCallback)(() => {
4003
+ setState(
4004
+ (prev) => prev.type === "EDITING" ? {
4005
+ type: "REVIEW",
4006
+ fields: prev.original,
4007
+ addressParts: prev.addressParts,
4008
+ piiUnavailable: prev.piiUnavailable,
4009
+ sign: IDLE_SIGN2
4010
+ } : prev
4011
+ );
4012
+ }, []);
4013
+ const onSign = (0, import_react11.useCallback)(() => {
4014
+ if (state.type !== "REVIEW" && state.type !== "SIGN_ONLY") return;
4015
+ if (state.type === "REVIEW" && state.fields.dob.trim() !== "" && !isValidUsDate(state.fields.dob)) {
4016
+ setState({
4017
+ ...state,
4018
+ sign: { type: "idle", error: DOB_INVALID_MESSAGE }
4019
+ });
4020
+ return;
4021
+ }
4022
+ setState({ ...state, sign: { type: "signing" } });
4023
+ coinlist.submitDocument(
4024
+ "tax_certification",
4025
+ state.type === "REVIEW" ? toSubmissionFields(state.fields, state.addressParts) : {}
4026
+ ).then((submission) => {
4027
+ setState({ type: "SUBMITTED", submission });
4028
+ }).catch(() => {
4029
+ setState(
4030
+ (prev) => prev.type === "REVIEW" || prev.type === "SIGN_ONLY" ? { ...prev, sign: { type: "idle", error: SIGN_FAILED_MESSAGE } } : prev
4031
+ );
4032
+ });
4033
+ }, [state, coinlist]);
4034
+ return { state, onEditField, onStartEdit, onSaveEdit, onCancelEdit, onSign };
4035
+ }
4036
+
4037
+ // src/client/components/requirements/TaxDocumentModal.tsx
4038
+ var import_jsx_runtime18 = require("react/jsx-runtime");
4039
+ var FIELD_ROWS = [
4040
+ { field: "fullLegalName", label: "Full legal name" },
4041
+ { field: "dob", label: "Date of birth", placeholder: "MM/DD/YYYY" },
4042
+ { field: "countryOfCitizenship", label: "Country of citizenship" },
4043
+ { field: "taxId", label: "Tax ID" },
4044
+ { field: "permanentAddress", label: "Permanent address" }
4045
+ ];
4046
+ function TaxDocumentModal({
4047
+ isOpen,
4048
+ onClose,
4049
+ onSubmitted,
4050
+ className
4051
+ }) {
4052
+ const { state, onEditField, onStartEdit, onSaveEdit, onCancelEdit, onSign } = useTaxDocument({ isOpen });
4053
+ (0, import_react12.useEffect)(() => {
4054
+ if (state.type === "SUBMITTED") {
4055
+ onSubmitted?.(state.submission);
4056
+ onClose();
4057
+ }
4058
+ }, [state]);
4059
+ if (!isOpen || state.type === "SUBMITTED") return null;
4060
+ 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)(
4061
+ "div",
4062
+ {
4063
+ className: cn(
4064
+ "clcosdk:flex clcosdk:w-full clcosdk:max-w-md clcosdk:flex-col clcosdk:gap-6 clcosdk:rounded-2xl clcosdk:bg-background clcosdk:p-6",
4065
+ className
4066
+ ),
4067
+ children: [
4068
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "clcosdk:flex clcosdk:items-start clcosdk:justify-between clcosdk:gap-4", children: [
4069
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(TaxDocumentModalHeading, { state }),
4070
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(CloseButton, { onClick: onClose })
4071
+ ] }),
4072
+ state.type === "LOADING" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(LoadingScreen, {}),
4073
+ state.type === "ERROR" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ErrorScreen, { reason: state.reason }),
4074
+ state.type === "REVIEW" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4075
+ ReviewScreen,
4076
+ {
4077
+ fields: state.fields,
4078
+ piiUnavailable: state.piiUnavailable,
4079
+ sign: state.sign,
4080
+ onStartEdit,
4081
+ onSign
4082
+ }
4083
+ ),
4084
+ state.type === "EDITING" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4085
+ EditScreen,
1931
4086
  {
1932
- className: cn(
1933
- "clcosdk:grid clcosdk:transition-[grid-template-rows] clcosdk:duration-300 clcosdk:ease-in-out",
1934
- expanded ? "clcosdk:grid-rows-[1fr]" : "clcosdk:grid-rows-[0fr]"
1935
- ),
1936
- children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "clcosdk:min-h-0 clcosdk:overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-4 clcosdk:px-2 clcosdk:pb-4", children: [
1937
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1938
- "p",
1939
- {
1940
- className: cn(typeClasses.subhead, "clcosdk:text-text-secondary"),
1941
- children: ui.description
1942
- }
1943
- ),
1944
- ui.variant === "verification" ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1945
- VerificationActionZone,
1946
- {
1947
- status: ui.status,
1948
- onAction,
1949
- onContactSupport
1950
- }
1951
- ) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1952
- WalletActionZone,
1953
- {
1954
- status: ui.status,
1955
- walletAddress: ui.walletAddress,
1956
- onAction
1957
- }
1958
- )
1959
- ] }) })
4087
+ fields: state.fields,
4088
+ onEditField,
4089
+ onSaveEdit,
4090
+ onCancelEdit
1960
4091
  }
1961
- )
4092
+ ),
4093
+ state.type === "SIGN_ONLY" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SignOnlyScreen, { sign: state.sign, onSign })
1962
4094
  ]
1963
4095
  }
4096
+ ) });
4097
+ }
4098
+ function TaxDocumentModalHeading({
4099
+ state
4100
+ }) {
4101
+ 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";
4102
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("h3", { className: cn(typeClasses.h3, "clcosdk:text-text-primary"), children: title });
4103
+ }
4104
+ function LoadingScreen() {
4105
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4106
+ "output",
4107
+ {
4108
+ "aria-live": "polite",
4109
+ className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-4",
4110
+ children: FIELD_ROWS.map(({ field }) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
4111
+ "div",
4112
+ {
4113
+ className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-1",
4114
+ children: [
4115
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "clcosdk:h-3 clcosdk:w-28 clcosdk:animate-pulse clcosdk:rounded clcosdk:bg-surface" }),
4116
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "clcosdk:h-5 clcosdk:w-48 clcosdk:animate-pulse clcosdk:rounded clcosdk:bg-surface" })
4117
+ ]
4118
+ },
4119
+ field
4120
+ ))
4121
+ }
4122
+ );
4123
+ }
4124
+ function ErrorScreen({
4125
+ reason
4126
+ }) {
4127
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4128
+ AlertBanner,
4129
+ {
4130
+ variant: "error",
4131
+ icon: true,
4132
+ content: reason === "not-authenticated" ? "Sign in to complete your tax document." : "Unable to load your tax information right now. Please try again."
4133
+ }
1964
4134
  );
1965
4135
  }
4136
+ function ReviewScreen({
4137
+ fields,
4138
+ piiUnavailable,
4139
+ sign,
4140
+ onStartEdit,
4141
+ onSign
4142
+ }) {
4143
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-6", children: [
4144
+ /* @__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." }),
4145
+ piiUnavailable && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4146
+ AlertBanner,
4147
+ {
4148
+ variant: "info",
4149
+ icon: true,
4150
+ content: "We don't have this information on file yet \u2014 please fill it in below."
4151
+ }
4152
+ ),
4153
+ /* @__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)(
4154
+ "div",
4155
+ {
4156
+ className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-1",
4157
+ children: [
4158
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4159
+ "span",
4160
+ {
4161
+ className: cn(typeClasses.label, "clcosdk:text-text-secondary"),
4162
+ children: label
4163
+ }
4164
+ ),
4165
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: cn(typeClasses.body, "clcosdk:text-text-primary"), children: fields[field] || "\u2014" })
4166
+ ]
4167
+ },
4168
+ field
4169
+ )) }),
4170
+ /* @__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." }),
4171
+ sign.type === "idle" && sign.error && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(AlertBanner, { variant: "error", icon: true, content: sign.error }),
4172
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-2", children: [
4173
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4174
+ ClButton,
4175
+ {
4176
+ fullWidth: true,
4177
+ onClick: onSign,
4178
+ isLoading: sign.type === "signing",
4179
+ loadingText: "Signing...",
4180
+ children: "Sign W-8BEN"
4181
+ }
4182
+ ),
4183
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4184
+ ClButton,
4185
+ {
4186
+ fullWidth: true,
4187
+ variant: "secondary",
4188
+ onClick: onStartEdit,
4189
+ disabled: sign.type === "signing",
4190
+ children: "Edit information"
4191
+ }
4192
+ )
4193
+ ] })
4194
+ ] });
4195
+ }
4196
+ function EditScreen({
4197
+ fields,
4198
+ onEditField,
4199
+ onSaveEdit,
4200
+ onCancelEdit
4201
+ }) {
4202
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-6", children: [
4203
+ /* @__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)(
4204
+ "label",
4205
+ {
4206
+ className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-1",
4207
+ children: [
4208
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4209
+ "span",
4210
+ {
4211
+ className: cn(typeClasses.label, "clcosdk:text-text-secondary"),
4212
+ children: label
4213
+ }
4214
+ ),
4215
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4216
+ "input",
4217
+ {
4218
+ type: "text",
4219
+ value: fields[field],
4220
+ placeholder,
4221
+ onChange: (e) => onEditField(field, e.target.value),
4222
+ className: cn(
4223
+ typeClasses.body,
4224
+ "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"
4225
+ )
4226
+ }
4227
+ )
4228
+ ]
4229
+ },
4230
+ field
4231
+ )) }),
4232
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-2", children: [
4233
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ClButton, { fullWidth: true, onClick: onSaveEdit, children: "Save & review" }),
4234
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ClButton, { fullWidth: true, variant: "secondary", onClick: onCancelEdit, children: "Cancel" })
4235
+ ] })
4236
+ ] });
4237
+ }
4238
+ function SignOnlyScreen({
4239
+ sign,
4240
+ onSign
4241
+ }) {
4242
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-6", children: [
4243
+ /* @__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." }),
4244
+ sign.type === "idle" && sign.error && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(AlertBanner, { variant: "error", icon: true, content: sign.error }),
4245
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4246
+ ClButton,
4247
+ {
4248
+ fullWidth: true,
4249
+ onClick: onSign,
4250
+ isLoading: sign.type === "signing",
4251
+ loadingText: "Signing...",
4252
+ children: "Sign W-8BEN-E"
4253
+ }
4254
+ )
4255
+ ] });
4256
+ }
1966
4257
 
1967
- // src/client/components/requirements/RequirementsChecklist.tsx
1968
- var import_react6 = require("react");
4258
+ // src/client/hooks/useOptionAddresses.ts
4259
+ var import_react13 = require("react");
4260
+ var LOADING_STATE4 = { type: "LOADING" };
4261
+ var EMPTY_STATE = {
4262
+ type: "CONTENT",
4263
+ addresses: []
4264
+ };
4265
+ function useOptionAddresses(offerId, offerOptionId, options = {}) {
4266
+ const { coinlist, isReady } = useCoinList();
4267
+ const { data, enabled = true } = options;
4268
+ const [addressesState, setAddressesState] = (0, import_react13.useState)(
4269
+ data !== void 0 ? { type: "CONTENT", addresses: data } : LOADING_STATE4
4270
+ );
4271
+ const [fetchKey, setFetchKey] = (0, import_react13.useState)(0);
4272
+ const refetch = (0, import_react13.useCallback)(() => setFetchKey((k) => k + 1), []);
4273
+ const disconnect = (0, import_react13.useCallback)(
4274
+ async (addressId) => {
4275
+ await coinlist.removeOptionAddress(offerId, addressId);
4276
+ refetch();
4277
+ },
4278
+ [coinlist, offerId, refetch]
4279
+ );
4280
+ (0, import_react13.useEffect)(() => {
4281
+ let isCancelled = false;
4282
+ if (!enabled) {
4283
+ setAddressesState(
4284
+ data !== void 0 ? { type: "CONTENT", addresses: data } : EMPTY_STATE
4285
+ );
4286
+ return () => {
4287
+ isCancelled = true;
4288
+ };
4289
+ }
4290
+ if (!isReady) {
4291
+ if (data === void 0) {
4292
+ setAddressesState(LOADING_STATE4);
4293
+ }
4294
+ return () => {
4295
+ isCancelled = true;
4296
+ };
4297
+ }
4298
+ if (data !== void 0 && fetchKey === 0) {
4299
+ return () => {
4300
+ isCancelled = true;
4301
+ };
4302
+ }
4303
+ if (coinlist.getAuthState() === "logged-out") {
4304
+ setAddressesState({ type: "ERROR", reason: "not-authenticated" });
4305
+ return () => {
4306
+ isCancelled = true;
4307
+ };
4308
+ }
4309
+ setAddressesState(LOADING_STATE4);
4310
+ coinlist.listOptionAddresses(offerId, offerOptionId).then((addresses) => {
4311
+ if (!isCancelled) {
4312
+ setAddressesState({ type: "CONTENT", addresses });
4313
+ }
4314
+ }).catch((error) => {
4315
+ if (!isCancelled) {
4316
+ const reason = error instanceof NotAuthenticatedError ? "not-authenticated" : "generic-error";
4317
+ setAddressesState({ type: "ERROR", reason });
4318
+ }
4319
+ });
4320
+ return () => {
4321
+ isCancelled = true;
4322
+ };
4323
+ }, [coinlist, isReady, enabled, offerId, offerOptionId, fetchKey]);
4324
+ return { addressesState, refetch, disconnect };
4325
+ }
1969
4326
 
1970
4327
  // src/client/hooks/useRequirements.ts
1971
- var import_react5 = require("react");
1972
- var LOADING_STATE2 = { type: "LOADING" };
4328
+ var import_react14 = require("react");
4329
+ var LOADING_STATE5 = { type: "LOADING" };
1973
4330
  function useRequirements(offerId, options = {}) {
1974
4331
  const { coinlist, isReady } = useCoinList();
1975
4332
  const { data } = options;
1976
- const [requirementsState, setRequirementsState] = (0, import_react5.useState)(
1977
- data !== void 0 ? { type: "CONTENT", ...data } : LOADING_STATE2
4333
+ const [requirementsState, setRequirementsState] = (0, import_react14.useState)(
4334
+ data !== void 0 ? { type: "CONTENT", ...data } : LOADING_STATE5
1978
4335
  );
1979
- const [fetchKey, setFetchKey] = (0, import_react5.useState)(0);
1980
- const refetch = (0, import_react5.useCallback)(() => setFetchKey((k) => k + 1), []);
1981
- (0, import_react5.useEffect)(() => {
4336
+ const [fetchKey, setFetchKey] = (0, import_react14.useState)(0);
4337
+ const refetch = (0, import_react14.useCallback)(() => setFetchKey((k) => k + 1), []);
4338
+ (0, import_react14.useEffect)(() => {
1982
4339
  let isCancelled = false;
1983
4340
  if (!isReady) {
1984
4341
  if (data === void 0) {
1985
- setRequirementsState(LOADING_STATE2);
4342
+ setRequirementsState(LOADING_STATE5);
1986
4343
  }
1987
4344
  return () => {
1988
4345
  isCancelled = true;
@@ -1993,7 +4350,13 @@ function useRequirements(offerId, options = {}) {
1993
4350
  isCancelled = true;
1994
4351
  };
1995
4352
  }
1996
- setRequirementsState(LOADING_STATE2);
4353
+ if (coinlist.getAuthState() === "logged-out") {
4354
+ setRequirementsState({ type: "ERROR", reason: "not-authenticated" });
4355
+ return () => {
4356
+ isCancelled = true;
4357
+ };
4358
+ }
4359
+ setRequirementsState(LOADING_STATE5);
1997
4360
  Promise.all([
1998
4361
  coinlist.fetchOfferRequirements(offerId),
1999
4362
  coinlist.fetchRequirementStatuses(offerId)
@@ -2019,7 +4382,8 @@ function useRequirements(offerId, options = {}) {
2019
4382
  }
2020
4383
 
2021
4384
  // src/client/components/requirements/RequirementsChecklist.tsx
2022
- var import_jsx_runtime15 = require("react/jsx-runtime");
4385
+ var import_jsx_runtime19 = require("react/jsx-runtime");
4386
+ var isWalletRequirement = (requirement) => RequirementVariant.fromType(requirement.type) === "wallet";
2023
4387
  var DEFAULT_LABELS = {
2024
4388
  kyc_approved: "KYC Verification",
2025
4389
  identity_verified: "Identity Verification",
@@ -2028,7 +4392,8 @@ var DEFAULT_LABELS = {
2028
4392
  external_wallet: "External Wallet",
2029
4393
  whitelisted_wallet: "Whitelisted Wallet",
2030
4394
  jurisdiction: "Jurisdiction Check",
2031
- accreditation: "Accreditation"
4395
+ accreditation: "Accreditation",
4396
+ document: "Document"
2032
4397
  };
2033
4398
  var DEFAULT_DESCRIPTIONS = {
2034
4399
  kyc_approved: "Complete Know Your Customer verification.",
@@ -2038,9 +4403,39 @@ var DEFAULT_DESCRIPTIONS = {
2038
4403
  external_wallet: "Connect an external wallet.",
2039
4404
  whitelisted_wallet: "Connect a whitelisted wallet.",
2040
4405
  jurisdiction: "Confirm your jurisdiction eligibility.",
2041
- accreditation: "Verify your accreditation status."
4406
+ accreditation: "Verify your accreditation status.",
4407
+ document: "Confirm your Tax Documents."
2042
4408
  };
2043
- function RequirementsChecklist({
4409
+ var VERIFICATION_POLL_INTERVAL_MS = 5e3;
4410
+ var VERIFICATION_POLL_TIMEOUT_MS = 12e4;
4411
+ function sleep(ms) {
4412
+ return new Promise((resolve) => setTimeout(resolve, ms));
4413
+ }
4414
+ function VerificationOverlay({
4415
+ onClose,
4416
+ children
4417
+ }) {
4418
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4419
+ "div",
4420
+ {
4421
+ role: "dialog",
4422
+ "aria-modal": "true",
4423
+ "aria-label": "Identity verification",
4424
+ className: "clcosdk:fixed clcosdk:inset-0 clcosdk:z-50 clcosdk:flex clcosdk:items-center clcosdk:justify-center clcosdk:bg-overlay clcosdk:p-4",
4425
+ 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: [
4426
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4427
+ CloseButton,
4428
+ {
4429
+ onClick: onClose,
4430
+ className: "clcosdk:absolute clcosdk:top-4 clcosdk:right-4"
4431
+ }
4432
+ ),
4433
+ children
4434
+ ] })
4435
+ }
4436
+ );
4437
+ }
4438
+ function RequirementsChecklistBody({
2044
4439
  offerId,
2045
4440
  optionId,
2046
4441
  title,
@@ -2048,38 +4443,106 @@ function RequirementsChecklist({
2048
4443
  onContinue,
2049
4444
  onRequirementActionOverride,
2050
4445
  onContactSupportOverride,
4446
+ wallet,
4447
+ onRequestConnect,
2051
4448
  getLabel,
2052
4449
  getDescription,
2053
4450
  loading,
4451
+ unauthenticatedState,
2054
4452
  error,
2055
4453
  className,
2056
- data
4454
+ data,
4455
+ identityVerificationOptions
2057
4456
  }) {
2058
4457
  const { coinlist } = useCoinList();
2059
- const { requirementsState } = useRequirements(offerId, { data });
2060
- const [expandedIndex, setExpandedIndex] = (0, import_react6.useState)(null);
2061
- const onRequirementAction = onRequirementActionOverride !== void 0 ? onRequirementActionOverride : (requirement) => coinlist.handleRequirement(requirement);
4458
+ const { requirementsState, refetch } = useRequirements(offerId, { data });
4459
+ const [expandedIndex, setExpandedIndex] = (0, import_react15.useState)(null);
4460
+ const [taxDocumentOpen, setTaxDocumentOpen] = (0, import_react15.useState)(false);
4461
+ const [walletConnectOpen, setConnectWalletOpen] = (0, import_react15.useState)(false);
4462
+ const [verifyingRequirementId, setVerifyingRequirementId] = (0, import_react15.useState)(null);
4463
+ const isMountedRef = (0, import_react15.useRef)(true);
4464
+ (0, import_react15.useEffect)(() => {
4465
+ isMountedRef.current = true;
4466
+ return () => {
4467
+ isMountedRef.current = false;
4468
+ };
4469
+ }, []);
4470
+ const [hasWalletRequirement, setHasWalletRequirement] = (0, import_react15.useState)(false);
4471
+ (0, import_react15.useEffect)(() => {
4472
+ if (requirementsState.type === "CONTENT") {
4473
+ setHasWalletRequirement(
4474
+ (requirementsState.requirements[optionId] ?? []).some(
4475
+ isWalletRequirement
4476
+ )
4477
+ );
4478
+ }
4479
+ }, [requirementsState, optionId]);
4480
+ const {
4481
+ addressesState,
4482
+ refetch: refetchAddresses,
4483
+ disconnect
4484
+ } = useOptionAddresses(offerId, optionId, {
4485
+ enabled: hasWalletRequirement
4486
+ });
4487
+ const optionAddresses = addressesState.type === "CONTENT" ? addressesState.addresses : [];
4488
+ const walletsStatus = addressesState.type === "ERROR" ? "error" : addressesState.type === "LOADING" ? "loading" : "ready";
4489
+ const onRemoveWallet = async (id) => {
4490
+ await disconnect(OfferOptionAddressId(id));
4491
+ refetch();
4492
+ };
4493
+ const onRequirementAction = onRequirementActionOverride !== void 0 ? onRequirementActionOverride : (requirement) => {
4494
+ if (requirement.type === "document") {
4495
+ setTaxDocumentOpen(true);
4496
+ return;
4497
+ }
4498
+ if ((requirement.type === "external_wallet" || requirement.type === "whitelisted_wallet") && wallet !== void 0 && (wallet !== null || onRequestConnect !== void 0)) {
4499
+ setConnectWalletOpen(true);
4500
+ return;
4501
+ }
4502
+ coinlist.handleRequirement(requirement);
4503
+ };
2062
4504
  const onContactSupport = onContactSupportOverride !== void 0 ? onContactSupportOverride : () => coinlist.contactSupport();
4505
+ const awaitVerificationResult = (requirementId, statusBeforeSubmit) => {
4506
+ void (async () => {
4507
+ const deadline = Date.now() + VERIFICATION_POLL_TIMEOUT_MS;
4508
+ while (Date.now() < deadline) {
4509
+ await sleep(VERIFICATION_POLL_INTERVAL_MS);
4510
+ if (!isMountedRef.current) return;
4511
+ try {
4512
+ const statuses2 = await coinlist.fetchRequirementStatuses(offerId);
4513
+ const current = statuses2.find((s) => s.id === requirementId)?.status;
4514
+ if (current !== void 0 && current !== statusBeforeSubmit) break;
4515
+ } catch (_) {
4516
+ }
4517
+ }
4518
+ if (isMountedRef.current) {
4519
+ setVerifyingRequirementId(null);
4520
+ refetch();
4521
+ }
4522
+ })();
4523
+ };
2063
4524
  if (requirementsState.type === "LOADING") {
2064
4525
  if (loading) return loading;
2065
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
4526
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2066
4527
  "output",
2067
4528
  {
2068
4529
  "aria-live": "polite",
2069
4530
  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",
2070
- children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: cn(typeClasses.body, "clcosdk:text-text-secondary"), children: "Loading requirements..." })
4531
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: cn(typeClasses.body, "clcosdk:text-text-secondary"), children: "Loading requirements..." })
2071
4532
  }
2072
4533
  );
2073
4534
  }
2074
4535
  if (requirementsState.type === "ERROR") {
4536
+ if (requirementsState.reason === "not-authenticated") {
4537
+ return unauthenticatedState !== void 0 ? unauthenticatedState : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(CoinListSignInCard, {});
4538
+ }
2075
4539
  if (error) return error;
2076
- const errorMessage = requirementsState.reason === "not-authenticated" ? "Sign in to view requirements." : "Unable to load requirements right now. Please try again.";
2077
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
4540
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2078
4541
  AlertBanner,
2079
4542
  {
2080
4543
  variant: "error",
2081
4544
  icon: true,
2082
- content: errorMessage,
4545
+ content: "Unable to load requirements right now. Please try again.",
2083
4546
  className: "clcosdk:w-full clcosdk:max-w-[28rem]"
2084
4547
  }
2085
4548
  );
@@ -2090,7 +4553,7 @@ function RequirementsChecklist({
2090
4553
  const optionStatuses = statuses.filter((s) => requirementIds.has(s.id));
2091
4554
  const statusByRequirementId = new Map(optionStatuses.map((s) => [s.id, s]));
2092
4555
  const checklistStatus = ChecklistStatus.derive(optionStatuses);
2093
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
4556
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
2094
4557
  "div",
2095
4558
  {
2096
4559
  className: cn(
@@ -2098,17 +4561,20 @@ function RequirementsChecklist({
2098
4561
  className
2099
4562
  ),
2100
4563
  children: [
2101
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-2", children: [
2102
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("h3", { className: cn(typeClasses.h3, "clcosdk:text-text-primary"), children: title }),
2103
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: cn(typeClasses.body, "clcosdk:text-text-secondary"), children: description })
4564
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-2", children: [
4565
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h3", { className: cn(typeClasses.h3, "clcosdk:text-text-primary"), children: title }),
4566
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: cn(typeClasses.body, "clcosdk:text-text-secondary"), children: description })
2104
4567
  ] }),
2105
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:divide-y clcosdk:divide-divider", children: requirements.map((req, index) => {
4568
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:divide-y clcosdk:divide-divider", children: requirements.map((req, index) => {
2106
4569
  const statusInfo = statusByRequirementId.get(req.id);
2107
4570
  const label = getLabel ? getLabel(req) : DEFAULT_LABELS[req.type];
2108
4571
  const itemDescription = (getDescription ? getDescription(req) : null) ?? DEFAULT_DESCRIPTIONS[req.type];
4572
+ const inlineVerification = statusInfo?.kycLevel !== void 0 && onRequirementActionOverride === void 0;
2109
4573
  let onActionBound;
2110
4574
  if (onRequirementAction === null) {
2111
4575
  onActionBound = null;
4576
+ } else if (inlineVerification) {
4577
+ onActionBound = () => setVerifyingRequirementId(req.id);
2112
4578
  } else if (onRequirementAction) {
2113
4579
  onActionBound = () => onRequirementAction(req);
2114
4580
  }
@@ -2118,24 +4584,28 @@ function RequirementsChecklist({
2118
4584
  } else if (onContactSupport) {
2119
4585
  onContactSupportBound = () => onContactSupport(req);
2120
4586
  }
2121
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
4587
+ const walletRequirement = isWalletRequirement(req);
4588
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2122
4589
  RequirementItem,
2123
4590
  {
2124
4591
  ui: RequirementItemUi.fromDomain(
2125
4592
  req,
2126
4593
  statusInfo,
2127
4594
  label,
2128
- itemDescription
4595
+ itemDescription,
4596
+ walletRequirement ? optionAddresses : []
2129
4597
  ),
2130
4598
  expanded: expandedIndex === index,
2131
4599
  onToggle: () => setExpandedIndex((prev) => prev === index ? null : index),
2132
4600
  onAction: onActionBound,
4601
+ onRemoveWallet: walletRequirement ? onRemoveWallet : void 0,
4602
+ walletsStatus: walletRequirement ? walletsStatus : void 0,
2133
4603
  onContactSupport: onContactSupportBound
2134
4604
  },
2135
4605
  req.id
2136
4606
  );
2137
4607
  }) }),
2138
- checklistStatus === "ineligible" && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
4608
+ checklistStatus === "ineligible" && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2139
4609
  AlertBanner,
2140
4610
  {
2141
4611
  variant: "error",
@@ -2143,7 +4613,7 @@ function RequirementsChecklist({
2143
4613
  content: "You are not eligible to participate."
2144
4614
  }
2145
4615
  ),
2146
- onContinue && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
4616
+ onContinue && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2147
4617
  ClButton,
2148
4618
  {
2149
4619
  fullWidth: true,
@@ -2151,24 +4621,326 @@ function RequirementsChecklist({
2151
4621
  onClick: onContinue,
2152
4622
  children: "Continue"
2153
4623
  }
4624
+ ),
4625
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4626
+ TaxDocumentModal,
4627
+ {
4628
+ isOpen: taxDocumentOpen,
4629
+ onClose: () => setTaxDocumentOpen(false),
4630
+ onSubmitted: () => refetch()
4631
+ }
4632
+ ),
4633
+ verifyingRequirementId !== null && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(VerificationOverlay, { onClose: () => setVerifyingRequirementId(null), children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4634
+ IdentityVerification,
4635
+ {
4636
+ levelName: identityVerificationOptions?.levelName ?? statusByRequirementId.get(verifyingRequirementId)?.kycLevel,
4637
+ reset: statusByRequirementId.get(verifyingRequirementId)?.kycReset ?? false,
4638
+ locale: identityVerificationOptions?.locale,
4639
+ onSubmitted: () => awaitVerificationResult(
4640
+ verifyingRequirementId,
4641
+ statusByRequirementId.get(verifyingRequirementId)?.status ?? "not_started"
4642
+ )
4643
+ }
4644
+ ) }),
4645
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4646
+ ConnectWalletModal,
4647
+ {
4648
+ isOpen: walletConnectOpen,
4649
+ onClose: () => setConnectWalletOpen(false),
4650
+ offerId,
4651
+ optionId,
4652
+ wallet: wallet ?? null,
4653
+ onRequestConnect,
4654
+ onConnected: () => {
4655
+ refetch();
4656
+ refetchAddresses();
4657
+ }
4658
+ }
2154
4659
  )
2155
4660
  ]
2156
4661
  }
2157
4662
  );
2158
4663
  }
4664
+ function RequirementsChecklist(props) {
4665
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(CoinListStyleScope, { children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(RequirementsChecklistBody, { ...props }) });
4666
+ }
4667
+
4668
+ // src/client/hooks/swap/useSwapOutputToken.ts
4669
+ var import_react16 = require("react");
4670
+ var LOADING_STATE6 = { type: "LOADING" };
4671
+ function useSwapOutputToken(options) {
4672
+ const { contractAddress, chain, enabled } = options;
4673
+ const { coinlist, isReady } = useCoinList();
4674
+ const [outputTokenState, setOutputTokenState] = (0, import_react16.useState)(LOADING_STATE6);
4675
+ const fetchIdRef = (0, import_react16.useRef)(0);
4676
+ (0, import_react16.useEffect)(() => {
4677
+ if (!enabled || !isReady) return;
4678
+ const currentFetchId = ++fetchIdRef.current;
4679
+ const load = async () => {
4680
+ try {
4681
+ const outputToken = await coinlist.swap.getOutputToken({
4682
+ contractAddress,
4683
+ chain
4684
+ });
4685
+ if (currentFetchId !== fetchIdRef.current) return;
4686
+ setOutputTokenState({ type: "CONTENT", outputToken });
4687
+ } catch {
4688
+ if (currentFetchId !== fetchIdRef.current) return;
4689
+ setOutputTokenState({ type: "ERROR" });
4690
+ }
4691
+ };
4692
+ load();
4693
+ return () => {
4694
+ ++fetchIdRef.current;
4695
+ };
4696
+ }, [coinlist, isReady, contractAddress, chain, enabled]);
4697
+ return { outputTokenState };
4698
+ }
4699
+
4700
+ // src/client/hooks/swap/useSwapQuote.ts
4701
+ var import_react17 = require("react");
4702
+
4703
+ // src/shared/core/blockchain/swap/constants.ts
4704
+ var SWAP_POLL_INTERVAL_MS = 15e3;
4705
+ var SLIPPAGE_OPTIONS_BPS = [25n, 50n, 100n, 200n, 500n].map(
4706
+ (n) => Bps(n)
4707
+ );
4708
+ var DEFAULT_SLIPPAGE_BPS = Bps(50n);
4709
+ var SUPERSTATE_SWAP_CONTRACT_ADDRESS_SEPOLIA = EvmContractAddress("0x84f8e9a6C9Cc12fe911259372EfCa5582C4ae557");
4710
+
4711
+ // src/shared/core/blockchain/swap/quote.ts
4712
+ var SwapQuote = {
4713
+ /**
4714
+ * Assembles a {@link SwapQuote} from a raw contract {@link SwapPreview}. The
4715
+ * input and fee are denominated in the input token; the output in the output
4716
+ * token.
4717
+ */
4718
+ fromPreview: (preview, inputDecimals, outputDecimals) => ({
4719
+ inputTokenAmount: BlockchainAmount({
4720
+ raw: preview.inputAmount,
4721
+ decimals: inputDecimals
4722
+ }),
4723
+ fee: BlockchainAmount({ raw: preview.fee, decimals: inputDecimals }),
4724
+ outputTokenAmount: BlockchainAmount({
4725
+ raw: preview.outputAmount,
4726
+ decimals: outputDecimals
4727
+ })
4728
+ })
4729
+ };
4730
+
4731
+ // src/client/hooks/swap/useSwapQuote.ts
4732
+ function useSwapQuote(options) {
4733
+ const {
4734
+ contractAddress,
4735
+ chain,
4736
+ inputAmount,
4737
+ inputTokenAddress,
4738
+ outputTokenDecimals,
4739
+ pollIntervalMs = SWAP_POLL_INTERVAL_MS,
4740
+ enabled
4741
+ } = options;
4742
+ const { coinlist, isReady } = useCoinList();
4743
+ const [quote, setQuote] = (0, import_react17.useState)(null);
4744
+ const [isLoading, setIsLoading] = (0, import_react17.useState)(true);
4745
+ const [isRefreshing, setIsRefreshing] = (0, import_react17.useState)(false);
4746
+ const isFetchingRef = (0, import_react17.useRef)(false);
4747
+ const hasQuoteRef = (0, import_react17.useRef)(false);
4748
+ const fetchIdRef = (0, import_react17.useRef)(0);
4749
+ (0, import_react17.useEffect)(() => {
4750
+ if (!isReady) return;
4751
+ if (!enabled) {
4752
+ setIsLoading(false);
4753
+ return;
4754
+ }
4755
+ const currentFetchId = ++fetchIdRef.current;
4756
+ isFetchingRef.current = false;
4757
+ const loadQuote = async () => {
4758
+ if (outputTokenDecimals === null) return;
4759
+ if (isFetchingRef.current) return;
4760
+ isFetchingRef.current = true;
4761
+ if (hasQuoteRef.current) {
4762
+ setIsRefreshing(true);
4763
+ }
4764
+ try {
4765
+ const preview = await coinlist.swap.getPreview({
4766
+ contractAddress,
4767
+ chain,
4768
+ inputToken: inputTokenAddress,
4769
+ amount: inputAmount.raw
4770
+ });
4771
+ if (currentFetchId !== fetchIdRef.current) return;
4772
+ setQuote(
4773
+ SwapQuote.fromPreview(
4774
+ preview,
4775
+ inputAmount.decimals,
4776
+ outputTokenDecimals
4777
+ )
4778
+ );
4779
+ if (!hasQuoteRef.current) {
4780
+ hasQuoteRef.current = true;
4781
+ setIsLoading(false);
4782
+ }
4783
+ } catch {
4784
+ } finally {
4785
+ if (currentFetchId === fetchIdRef.current) {
4786
+ isFetchingRef.current = false;
4787
+ setIsRefreshing(false);
4788
+ }
4789
+ }
4790
+ };
4791
+ loadQuote();
4792
+ const interval = setInterval(loadQuote, pollIntervalMs);
4793
+ return () => {
4794
+ clearInterval(interval);
4795
+ ++fetchIdRef.current;
4796
+ setIsRefreshing(false);
4797
+ };
4798
+ }, [
4799
+ coinlist,
4800
+ isReady,
4801
+ contractAddress,
4802
+ chain,
4803
+ inputAmount.raw,
4804
+ inputAmount.decimals,
4805
+ inputTokenAddress,
4806
+ outputTokenDecimals,
4807
+ pollIntervalMs,
4808
+ enabled
4809
+ ]);
4810
+ return { quote, isLoading, isRefreshing };
4811
+ }
4812
+
4813
+ // src/client/hooks/swap/useSwapTokenBalances.ts
4814
+ var import_react18 = require("react");
4815
+
4816
+ // src/shared/core/blockchain/token-registry.ts
4817
+ var USDC_SYMBOL = StablecoinSymbol("USDC");
4818
+ var USDC = {
4819
+ name: "USD Coin",
4820
+ symbol: USDC_SYMBOL,
4821
+ decimals: AssetDecimals(6)
4822
+ };
4823
+ var USDT_SYMBOL = StablecoinSymbol("USDT");
4824
+ var USDT = {
4825
+ name: "Tether USD",
4826
+ symbol: USDT_SYMBOL,
4827
+ decimals: AssetDecimals(6)
4828
+ };
4829
+ var USDC_ADDRESSES = {
4830
+ ethereum_mainnet: EvmContractAddress(
4831
+ "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
4832
+ ),
4833
+ ethereum_sepolia: EvmContractAddress(
4834
+ "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238"
4835
+ )
4836
+ };
4837
+ var USDT_ADDRESSES = {
4838
+ ethereum_mainnet: EvmContractAddress(
4839
+ "0xdac17f958d2ee523a2206206994597c13d831ec7"
4840
+ ),
4841
+ ethereum_sepolia: EvmContractAddress(
4842
+ "0x7169D38820dfd117C3FA1f22a697dBA58d90BA06"
4843
+ )
4844
+ };
4845
+ var TOKEN_REGISTRY = {
4846
+ erc20: (symbol) => {
4847
+ switch (symbol) {
4848
+ case "USDC":
4849
+ return USDC;
4850
+ case "USDT":
4851
+ return USDT;
4852
+ default:
4853
+ throw new Error(`Unknown asset symbol: ${symbol}`);
4854
+ }
4855
+ },
4856
+ contractAddress: (symbol, chain) => {
4857
+ switch (symbol) {
4858
+ case "USDC":
4859
+ return USDC_ADDRESSES[chain];
4860
+ case "USDT":
4861
+ return USDT_ADDRESSES[chain];
4862
+ default:
4863
+ throw new Error(`Unknown asset symbol: ${symbol}`);
4864
+ }
4865
+ }
4866
+ };
4867
+
4868
+ // src/client/hooks/swap/useSwapTokenBalances.ts
4869
+ function useSwapTokenBalances(options) {
4870
+ const {
4871
+ address,
4872
+ chain,
4873
+ assets,
4874
+ pollIntervalMs = SWAP_POLL_INTERVAL_MS,
4875
+ enabled
4876
+ } = options;
4877
+ const { coinlist, isReady } = useCoinList();
4878
+ const [balances, setBalances] = (0, import_react18.useState)(/* @__PURE__ */ new Map());
4879
+ const [isLoading, setIsLoading] = (0, import_react18.useState)(true);
4880
+ const fetchIdRef = (0, import_react18.useRef)(0);
4881
+ const isFetchingRef = (0, import_react18.useRef)(false);
4882
+ const assetsKey = assets.join(",");
4883
+ (0, import_react18.useEffect)(() => {
4884
+ if (!isReady) return;
4885
+ if (!enabled) {
4886
+ setIsLoading(false);
4887
+ return;
4888
+ }
4889
+ const symbols = assetsKey.split(",");
4890
+ const currentFetchId = ++fetchIdRef.current;
4891
+ isFetchingRef.current = false;
4892
+ let isFirstFetch = true;
4893
+ async function fetchBalances() {
4894
+ if (isFetchingRef.current) return;
4895
+ isFetchingRef.current = true;
4896
+ if (isFirstFetch) {
4897
+ setIsLoading(true);
4898
+ }
4899
+ const results = await Promise.allSettled(
4900
+ symbols.map(
4901
+ (symbol) => coinlist.erc20.getTokenBalance({
4902
+ tokenAddress: TOKEN_REGISTRY.contractAddress(symbol, chain),
4903
+ owner: address,
4904
+ chain
4905
+ })
4906
+ )
4907
+ );
4908
+ if (currentFetchId !== fetchIdRef.current) return;
4909
+ isFetchingRef.current = false;
4910
+ const next = /* @__PURE__ */ new Map();
4911
+ symbols.forEach((symbol, i) => {
4912
+ const result = results[i];
4913
+ next.set(
4914
+ symbol,
4915
+ result.status === "fulfilled" ? result.value.balance : null
4916
+ );
4917
+ });
4918
+ setBalances(next);
4919
+ setIsLoading(false);
4920
+ isFirstFetch = false;
4921
+ }
4922
+ fetchBalances();
4923
+ const interval = setInterval(fetchBalances, pollIntervalMs);
4924
+ return () => {
4925
+ clearInterval(interval);
4926
+ ++fetchIdRef.current;
4927
+ };
4928
+ }, [coinlist, isReady, address, chain, assetsKey, pollIntervalMs, enabled]);
4929
+ return { balances, isLoading };
4930
+ }
2159
4931
 
2160
4932
  // src/client/hooks/useCompleteOAuth.ts
2161
- var import_react7 = require("react");
4933
+ var import_react19 = require("react");
2162
4934
  function useCompleteOAuth(options) {
2163
4935
  const { coinlist } = useCoinList();
2164
- const postOAuthCompleteRef = (0, import_react7.useRef)(options.postOAuthComplete);
2165
- const onFailureRef = (0, import_react7.useRef)(options.onFailure);
2166
- const onSuccessRef = (0, import_react7.useRef)(options.onSuccess);
4936
+ const postOAuthCompleteRef = (0, import_react19.useRef)(options.postOAuthComplete);
4937
+ const onFailureRef = (0, import_react19.useRef)(options.onFailure);
4938
+ const onSuccessRef = (0, import_react19.useRef)(options.onSuccess);
2167
4939
  postOAuthCompleteRef.current = options.postOAuthComplete;
2168
4940
  onFailureRef.current = options.onFailure;
2169
4941
  onSuccessRef.current = options.onSuccess;
2170
- const hasStartedExchangeRef = (0, import_react7.useRef)(false);
2171
- (0, import_react7.useEffect)(() => {
4942
+ const hasStartedExchangeRef = (0, import_react19.useRef)(false);
4943
+ (0, import_react19.useEffect)(() => {
2172
4944
  if (typeof window === "undefined") return;
2173
4945
  const params = new URLSearchParams(window.location.search);
2174
4946
  if (!params.has("code") && !params.has("error")) return;
@@ -2212,19 +4984,19 @@ function useCompleteOAuth(options) {
2212
4984
  }
2213
4985
 
2214
4986
  // src/client/hooks/useOfferDetails.ts
2215
- var import_react8 = require("react");
2216
- var LOADING_STATE3 = { type: "LOADING" };
4987
+ var import_react20 = require("react");
4988
+ var LOADING_STATE7 = { type: "LOADING" };
2217
4989
  function useOfferDetails(offerId, options = {}) {
2218
4990
  const { coinlist, isReady } = useCoinList();
2219
4991
  const { data } = options;
2220
- const [offerDetailsState, setOfferDetailsState] = (0, import_react8.useState)(
2221
- data !== void 0 ? { type: "CONTENT", offerDetail: data } : LOADING_STATE3
4992
+ const [offerDetailsState, setOfferDetailsState] = (0, import_react20.useState)(
4993
+ data !== void 0 ? { type: "CONTENT", offerDetail: data } : LOADING_STATE7
2222
4994
  );
2223
- (0, import_react8.useEffect)(() => {
4995
+ (0, import_react20.useEffect)(() => {
2224
4996
  let isCancelled = false;
2225
4997
  if (!isReady) {
2226
4998
  if (data === void 0) {
2227
- setOfferDetailsState(LOADING_STATE3);
4999
+ setOfferDetailsState(LOADING_STATE7);
2228
5000
  }
2229
5001
  return () => {
2230
5002
  isCancelled = true;
@@ -2235,7 +5007,7 @@ function useOfferDetails(offerId, options = {}) {
2235
5007
  isCancelled = true;
2236
5008
  };
2237
5009
  }
2238
- setOfferDetailsState(LOADING_STATE3);
5010
+ setOfferDetailsState(LOADING_STATE7);
2239
5011
  coinlist.fetchOfferDetails(offerId).then((offerDetail) => {
2240
5012
  if (!isCancelled) {
2241
5013
  setOfferDetailsState({ type: "CONTENT", offerDetail });
@@ -2254,19 +5026,19 @@ function useOfferDetails(offerId, options = {}) {
2254
5026
  }
2255
5027
 
2256
5028
  // src/client/hooks/useParticipations.ts
2257
- var import_react9 = require("react");
2258
- var LOADING_STATE4 = { type: "LOADING" };
5029
+ var import_react21 = require("react");
5030
+ var LOADING_STATE8 = { type: "LOADING" };
2259
5031
  function useParticipations(offerId, options = {}) {
2260
5032
  const { coinlist, isReady } = useCoinList();
2261
5033
  const { data } = options;
2262
- const [participationsState, setParticipationsState] = (0, import_react9.useState)(
2263
- data !== void 0 ? { type: "CONTENT", participations: data } : LOADING_STATE4
5034
+ const [participationsState, setParticipationsState] = (0, import_react21.useState)(
5035
+ data !== void 0 ? { type: "CONTENT", participations: data } : LOADING_STATE8
2264
5036
  );
2265
- (0, import_react9.useEffect)(() => {
5037
+ (0, import_react21.useEffect)(() => {
2266
5038
  let isCancelled = false;
2267
5039
  if (!isReady) {
2268
5040
  if (data === void 0) {
2269
- setParticipationsState(LOADING_STATE4);
5041
+ setParticipationsState(LOADING_STATE8);
2270
5042
  }
2271
5043
  return () => {
2272
5044
  isCancelled = true;
@@ -2277,8 +5049,8 @@ function useParticipations(offerId, options = {}) {
2277
5049
  isCancelled = true;
2278
5050
  };
2279
5051
  }
2280
- setParticipationsState(LOADING_STATE4);
2281
- coinlist.fetchParticipations(offerId).then((participations) => {
5052
+ setParticipationsState(LOADING_STATE8);
5053
+ coinlist.tokenSale.fetchParticipations(offerId).then((participations) => {
2282
5054
  if (!isCancelled) {
2283
5055
  setParticipationsState({ type: "CONTENT", participations });
2284
5056
  }
@@ -2297,12 +5069,18 @@ function useParticipations(offerId, options = {}) {
2297
5069
  // Annotate the CommonJS export names for ESM import in node:
2298
5070
  0 && (module.exports = {
2299
5071
  ChecklistStatus,
5072
+ ClientSwapNamespaceImpl,
5073
+ ClientTokenSaleNamespaceImpl,
2300
5074
  CoinListClientInitializationError,
2301
5075
  CoinListContext,
2302
5076
  CoinListContextProvider,
2303
5077
  CoinListProvider,
2304
5078
  CoinListSignInCard,
2305
5079
  CoinListStyleScope,
5080
+ ConnectWalletModal,
5081
+ ConnectedWalletList,
5082
+ IdentityVerification,
5083
+ KycToken,
2306
5084
  OAUTH_CODE_VERIFIER_KEY,
2307
5085
  OAUTH_STATE_KEY,
2308
5086
  OfferCard,
@@ -2313,12 +5091,25 @@ function useParticipations(offerId, options = {}) {
2313
5091
  RequirementStatus,
2314
5092
  RequirementVariant,
2315
5093
  RequirementsChecklist,
5094
+ TaxDocumentModal,
5095
+ authorizeWallet,
5096
+ classifyWalletError,
5097
+ connectExternalWalletFlow,
2316
5098
  createCoinListClient,
5099
+ executeSwap,
5100
+ executeTokenSale,
2317
5101
  useCoinList,
2318
5102
  useCompleteOAuth,
5103
+ useConnectWallet,
5104
+ useKycToken,
2319
5105
  useOfferDetails,
2320
5106
  useOffers,
5107
+ useOptionAddresses,
2321
5108
  useParticipations,
2322
- useRequirements
5109
+ useRequirements,
5110
+ useSwapOutputToken,
5111
+ useSwapQuote,
5112
+ useSwapTokenBalances,
5113
+ useTaxDocument
2323
5114
  });
2324
5115
  //# sourceMappingURL=index.cjs.map