@coinlist-co/react 0.6.0 → 0.9.0

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