@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,6 +1,5 @@
1
1
  import {
2
2
  API_VERSION,
3
- Attributes,
4
3
  AuthenticatedApiClient,
5
4
  COINLIST_BASE_URL,
6
5
  HEADER_USER_AGENT,
@@ -13,6 +12,7 @@ import {
13
12
  VERIFY_IDENTITY_SOURCE_OF_FUNDS_PATH,
14
13
  VERIFY_IDENTITY_VERIFIED_PATH,
15
14
  WALLET_PATH,
15
+ createKycToken,
16
16
  createParticipation,
17
17
  fetchOfferDetails,
18
18
  fetchOfferRequirements,
@@ -21,17 +21,38 @@ import {
21
21
  fetchParticipation,
22
22
  fetchParticipations,
23
23
  fetchParticipationsPage,
24
- fetchRequirementStatuses
25
- } from "../chunk-5C4TEVM7.js";
24
+ fetchPii,
25
+ fetchRequirementStatuses,
26
+ submitDocument
27
+ } from "../chunk-MKCOK3DF.js";
26
28
  import {
27
29
  AuthorizationCode,
28
30
  CodeVerifier,
29
- generatePKCEParams
30
- } from "../chunk-UEJVCU2J.js";
31
+ ERC20_ABI,
32
+ SUPERSTATE_SWAP_ABI,
33
+ SWAP_POLL_INTERVAL_MS,
34
+ SwapQuote,
35
+ TOKEN_REGISTRY,
36
+ computePrice,
37
+ computeSlip,
38
+ decodeSwappedOutputAmount,
39
+ generatePKCEParams,
40
+ isStopped,
41
+ shortenAddress
42
+ } from "../chunk-I5YTJ5SL.js";
31
43
  import {
44
+ Attributes,
45
+ BlockchainAmount,
46
+ KycToken,
32
47
  NotAuthenticatedError,
33
- getUUIDv4
34
- } from "../chunk-7SB2GKEU.js";
48
+ OfferOptionAddressId,
49
+ SwapNamespaceImpl,
50
+ connectExternalWallet,
51
+ createWalletOwnershipChallenge,
52
+ getUUIDv4,
53
+ listOptionAddresses,
54
+ removeOptionAddress
55
+ } from "../chunk-Z2HAA2TI.js";
35
56
 
36
57
  // src/client/CoinListProvider.tsx
37
58
  import {
@@ -41,36 +62,6 @@ import {
41
62
  useState
42
63
  } from "react";
43
64
 
44
- // src/client/generated/sdk-styles.gen.ts
45
- 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)}}';
46
-
47
- // src/client/CoinListStyleScope.tsx
48
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
49
- function CoinListStyleScope({ children }) {
50
- return /* @__PURE__ */ jsxs(Fragment, { children: [
51
- /* @__PURE__ */ jsx("link", { rel: "preconnect", href: "https://fonts.googleapis.com" }),
52
- /* @__PURE__ */ jsx(
53
- "link",
54
- {
55
- rel: "preconnect",
56
- href: "https://fonts.gstatic.com",
57
- crossOrigin: "anonymous"
58
- }
59
- ),
60
- /* @__PURE__ */ jsx(
61
- "link",
62
- {
63
- rel: "stylesheet",
64
- href: "https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap"
65
- }
66
- ),
67
- /* @__PURE__ */ jsxs("div", { className: "clco-sdk-root", children: [
68
- /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: sdkStyles } }),
69
- children
70
- ] })
71
- ] });
72
- }
73
-
74
65
  // src/client/core/api/middleware/device-id.ts
75
66
  var DEVICE_ID_KEY = "coinlist.device_id";
76
67
  function getDeviceId() {
@@ -118,6 +109,286 @@ var ApiClient = class {
118
109
  }
119
110
  };
120
111
 
112
+ // src/client/core/blockchain/wallet-error.ts
113
+ import {
114
+ ContractFunctionRevertedError,
115
+ InsufficientFundsError,
116
+ UserRejectedRequestError,
117
+ WaitForTransactionReceiptTimeoutError
118
+ } from "viem";
119
+ function classifyWalletError(error, ctx) {
120
+ if (error instanceof UserRejectedRequestError) {
121
+ return { type: "user_rejected" };
122
+ }
123
+ if (error instanceof InsufficientFundsError) {
124
+ return { type: "insufficient_funds" };
125
+ }
126
+ if (error instanceof ContractFunctionRevertedError) {
127
+ return { type: "contract_reverted", reason: error.reason ?? error.message };
128
+ }
129
+ if (error instanceof WaitForTransactionReceiptTimeoutError && ctx?.hash) {
130
+ return { type: "timeout", hash: ctx.hash };
131
+ }
132
+ return { type: "unknown", cause: error };
133
+ }
134
+
135
+ // src/client/core/blockchain/swap-flows.ts
136
+ async function executeSwap(params) {
137
+ const {
138
+ swap,
139
+ wallet,
140
+ contractAddress,
141
+ chain,
142
+ inputTokenAddress,
143
+ quote,
144
+ slippageBps,
145
+ onProgress
146
+ } = params;
147
+ const emit = (phase) => onProgress?.(phase);
148
+ const inputAmount = BlockchainAmount.add(
149
+ quote.inputTokenAmount,
150
+ quote.fee
151
+ ).raw;
152
+ const minOut = computeSlip(quote.outputTokenAmount, slippageBps).raw;
153
+ emit("checking-status");
154
+ let status;
155
+ try {
156
+ status = await swap.getStatus({ contractAddress, chain });
157
+ } catch {
158
+ return { type: "error", error: { step: "status-check" } };
159
+ }
160
+ if (isStopped(status)) {
161
+ return { type: "error", error: { step: "swap-stopped" } };
162
+ }
163
+ emit("checking-allowance");
164
+ let allowance;
165
+ try {
166
+ allowance = await swap.getTokenAllowance({
167
+ tokenAddress: inputTokenAddress,
168
+ owner: wallet.address,
169
+ spender: contractAddress,
170
+ chain
171
+ });
172
+ } catch {
173
+ return { type: "error", error: { step: "allowance-check" } };
174
+ }
175
+ if (allowance.allowance < inputAmount) {
176
+ if (allowance.allowance > 0n) {
177
+ const reset = await submitApproval({
178
+ wallet,
179
+ tokenAddress: inputTokenAddress,
180
+ spender: contractAddress,
181
+ chain,
182
+ value: 0n,
183
+ pending: "resetting-allowance",
184
+ confirming: "confirming-allowance-reset",
185
+ emit
186
+ });
187
+ if (reset.type === "error") return { type: "error", error: reset.error };
188
+ }
189
+ const approve = await submitApproval({
190
+ wallet,
191
+ tokenAddress: inputTokenAddress,
192
+ spender: contractAddress,
193
+ chain,
194
+ value: inputAmount,
195
+ pending: "approving",
196
+ confirming: "confirming-approval",
197
+ emit
198
+ });
199
+ if (approve.type === "error")
200
+ return { type: "error", error: approve.error };
201
+ }
202
+ emit("swapping");
203
+ let swapTxHash;
204
+ try {
205
+ swapTxHash = await wallet.writeContract({
206
+ abi: SUPERSTATE_SWAP_ABI,
207
+ address: contractAddress,
208
+ functionName: "swap",
209
+ args: [inputTokenAddress, inputAmount, minOut],
210
+ chain
211
+ });
212
+ } catch (error) {
213
+ return {
214
+ type: "error",
215
+ error: { step: "swap", cause: classifyWalletError(error) }
216
+ };
217
+ }
218
+ emit("confirming-swap");
219
+ let receipt;
220
+ try {
221
+ receipt = await wallet.awaitTx(swapTxHash, chain);
222
+ } catch (error) {
223
+ return {
224
+ type: "error",
225
+ error: {
226
+ step: "swap",
227
+ cause: classifyWalletError(error, { hash: swapTxHash })
228
+ }
229
+ };
230
+ }
231
+ if (receipt.status !== "success") {
232
+ return { type: "error", error: { step: "swap-reverted" } };
233
+ }
234
+ const outputAmount = decodeSwappedOutputAmount(receipt, quote.outputTokenAmount.decimals) ?? quote.outputTokenAmount;
235
+ const finalQuote = { ...quote, outputTokenAmount: outputAmount };
236
+ return {
237
+ type: "success",
238
+ swapTxHash,
239
+ inputAmount: finalQuote.inputTokenAmount,
240
+ fee: finalQuote.fee,
241
+ outputAmount,
242
+ pricePerShare: computePrice(finalQuote),
243
+ recipientAddress: wallet.address
244
+ };
245
+ }
246
+ async function submitApproval(args) {
247
+ const {
248
+ wallet,
249
+ tokenAddress,
250
+ spender,
251
+ chain,
252
+ value,
253
+ pending,
254
+ confirming,
255
+ emit
256
+ } = args;
257
+ emit(pending);
258
+ let hash;
259
+ try {
260
+ hash = await wallet.writeContract({
261
+ abi: ERC20_ABI,
262
+ address: tokenAddress,
263
+ functionName: "approve",
264
+ args: [spender, value],
265
+ chain
266
+ });
267
+ } catch (error) {
268
+ return {
269
+ type: "error",
270
+ error: { step: "approval", cause: classifyWalletError(error) }
271
+ };
272
+ }
273
+ emit(confirming);
274
+ let receipt;
275
+ try {
276
+ receipt = await wallet.awaitTx(hash, chain);
277
+ } catch (error) {
278
+ return {
279
+ type: "error",
280
+ error: { step: "approval", cause: classifyWalletError(error, { hash }) }
281
+ };
282
+ }
283
+ if (receipt.status !== "success") {
284
+ return { type: "error", error: { step: "approval-reverted" } };
285
+ }
286
+ return { type: "ok" };
287
+ }
288
+ async function authorizeWallet(params) {
289
+ const { swap, wallet, offerId, contractAddress, chain, onProgress } = params;
290
+ const emit = (phase) => onProgress?.(phase);
291
+ const walletAddress = wallet.address;
292
+ emit("checking-authorization");
293
+ let auth;
294
+ try {
295
+ auth = await swap.getAuthorization({
296
+ walletAddress,
297
+ contractAddress,
298
+ chain
299
+ });
300
+ } catch {
301
+ return { type: "error", error: { step: "authorization-check" } };
302
+ }
303
+ if (auth.authorized) return { type: "success" };
304
+ emit("requesting-challenge");
305
+ let challenge;
306
+ try {
307
+ challenge = await swap.requestWalletOwnershipChallenge({
308
+ walletAddress,
309
+ chain,
310
+ challengeType: "plain"
311
+ });
312
+ } catch {
313
+ return { type: "error", error: { step: "challenge-request" } };
314
+ }
315
+ emit("signing-message");
316
+ let signature;
317
+ try {
318
+ signature = await wallet.signMessage(challenge.message);
319
+ } catch (error) {
320
+ return {
321
+ type: "error",
322
+ error: { step: "signing", cause: classifyWalletError(error) }
323
+ };
324
+ }
325
+ emit("submitting-signature");
326
+ let allow;
327
+ try {
328
+ allow = await swap.allowWallet({
329
+ offerId,
330
+ walletAddress,
331
+ chain,
332
+ signature
333
+ });
334
+ } catch {
335
+ return { type: "error", error: { step: "allow-wallet" } };
336
+ }
337
+ if (allow.action === "broadcast_transaction") {
338
+ emit("broadcasting-transaction");
339
+ let hash;
340
+ try {
341
+ hash = await wallet.broadcastRawTx({
342
+ to: allow.to,
343
+ data: allow.data,
344
+ chain
345
+ });
346
+ } catch (error) {
347
+ return {
348
+ type: "error",
349
+ error: { step: "broadcast", cause: classifyWalletError(error) }
350
+ };
351
+ }
352
+ emit("awaiting-confirmation");
353
+ try {
354
+ await wallet.awaitTx(hash, chain);
355
+ } catch (error) {
356
+ return {
357
+ type: "error",
358
+ error: {
359
+ step: "broadcast",
360
+ cause: classifyWalletError(error, { hash })
361
+ }
362
+ };
363
+ }
364
+ }
365
+ emit("verifying-authorization");
366
+ let reCheck;
367
+ try {
368
+ reCheck = await swap.getAuthorization({
369
+ walletAddress,
370
+ contractAddress,
371
+ chain
372
+ });
373
+ } catch {
374
+ return { type: "error", error: { step: "authorization-check" } };
375
+ }
376
+ if (!reCheck.authorized) {
377
+ return { type: "error", error: { step: "not-authorized" } };
378
+ }
379
+ return { type: "success" };
380
+ }
381
+
382
+ // src/client/core/client-swap-namespace.ts
383
+ var ClientSwapNamespaceImpl = class extends SwapNamespaceImpl {
384
+ executeSwap(params) {
385
+ return executeSwap({ ...params, swap: this });
386
+ }
387
+ authorizeWallet(params) {
388
+ return authorizeWallet({ ...params, swap: this });
389
+ }
390
+ };
391
+
121
392
  // src/client/core/coinlist-client.ts
122
393
  var OAUTH_STATE_KEY = "coinlist.oauth_state";
123
394
  var OAUTH_CODE_VERIFIER_KEY = "coinlist.oauth_code_verifier";
@@ -133,6 +404,10 @@ var CoinListClientImpl = class {
133
404
  },
134
405
  this.fetchAccessToken.bind(this)
135
406
  );
407
+ this.swap = new ClientSwapNamespaceImpl({
408
+ api: this.api,
409
+ ensureUserAuthenticated: async () => this.ensureAuthenticated()
410
+ });
136
411
  }
137
412
  async init() {
138
413
  await this.fetchAccessToken(true);
@@ -204,15 +479,15 @@ var CoinListClientImpl = class {
204
479
  }
205
480
  async fetchOffers() {
206
481
  this.ensureAuthenticated();
207
- return fetchOffers(this.api);
482
+ return fetchOffers(this.api, void 0);
208
483
  }
209
484
  async fetchOffersPage(params) {
210
485
  this.ensureAuthenticated();
211
- return fetchOffersPage(this.api, params);
486
+ return fetchOffersPage(this.api, params, void 0);
212
487
  }
213
488
  async fetchOfferDetails(id) {
214
489
  this.ensureAuthenticated();
215
- return fetchOfferDetails(this.api, id);
490
+ return fetchOfferDetails(this.api, id, void 0);
216
491
  }
217
492
  async fetchParticipations(offerId) {
218
493
  this.ensureAuthenticated();
@@ -230,14 +505,46 @@ var CoinListClientImpl = class {
230
505
  this.ensureAuthenticated();
231
506
  return createParticipation(this.api, params);
232
507
  }
508
+ async createWalletOwnershipChallenge(params) {
509
+ this.ensureAuthenticated();
510
+ return createWalletOwnershipChallenge(this.api, params);
511
+ }
512
+ async connectExternalWallet(offerId, params) {
513
+ this.ensureAuthenticated();
514
+ return connectExternalWallet(this.api, offerId, params);
515
+ }
516
+ async listOptionAddresses(offerId, offerOptionId) {
517
+ this.ensureAuthenticated();
518
+ return listOptionAddresses(
519
+ this.api,
520
+ offerId,
521
+ offerOptionId
522
+ );
523
+ }
524
+ async removeOptionAddress(offerId, addressId) {
525
+ this.ensureAuthenticated();
526
+ return removeOptionAddress(this.api, offerId, addressId);
527
+ }
233
528
  async fetchOfferRequirements(offerId) {
234
529
  this.ensureAuthenticated();
235
- return fetchOfferRequirements(this.api, offerId);
530
+ return fetchOfferRequirements(this.api, offerId, void 0);
236
531
  }
237
532
  async fetchRequirementStatuses(offerId) {
238
533
  this.ensureAuthenticated();
239
534
  return fetchRequirementStatuses(this.api, offerId);
240
535
  }
536
+ async fetchPii() {
537
+ this.ensureAuthenticated();
538
+ return fetchPii(this.api);
539
+ }
540
+ async submitDocument(documentType, fields) {
541
+ this.ensureAuthenticated();
542
+ return submitDocument(this.api, documentType, fields);
543
+ }
544
+ async createKycToken(levelName, reset) {
545
+ this.ensureAuthenticated();
546
+ return createKycToken(this.api, levelName, reset);
547
+ }
241
548
  handleRequirement(requirement) {
242
549
  const baseUrl = this._config.coinlistBaseUrl ?? COINLIST_BASE_URL;
243
550
  let path;
@@ -264,6 +571,9 @@ var CoinListClientImpl = class {
264
571
  case "jurisdiction":
265
572
  path = null;
266
573
  break;
574
+ case "document":
575
+ path = null;
576
+ break;
267
577
  default: {
268
578
  const _exhaustive = requirement.type;
269
579
  return;
@@ -289,7 +599,7 @@ function createCoinListClient(config) {
289
599
  }
290
600
 
291
601
  // src/client/CoinListProvider.tsx
292
- import { jsx as jsx2 } from "react/jsx-runtime";
602
+ import { jsx } from "react/jsx-runtime";
293
603
  var CoinListContext = createContext(null);
294
604
  function CoinListContextProvider({
295
605
  config,
@@ -317,10 +627,53 @@ function CoinListContextProvider({
317
627
  };
318
628
  }, [coinlist]);
319
629
  const value = useMemo(() => ({ coinlist, isReady }), [coinlist, isReady]);
320
- return /* @__PURE__ */ jsx2(CoinListContext.Provider, { value, children });
630
+ return /* @__PURE__ */ jsx(CoinListContext.Provider, { value, children });
321
631
  }
322
- function CoinListProvider({ config, children }) {
323
- return /* @__PURE__ */ jsx2(CoinListContextProvider, { config, children: /* @__PURE__ */ jsx2(CoinListStyleScope, { children }) });
632
+ var CoinListProvider = CoinListContextProvider;
633
+
634
+ // src/client/CoinListStyleScope.tsx
635
+ import { createContext as createContext2, useContext } from "react";
636
+
637
+ // src/client/generated/sdk-styles.gen.ts
638
+ 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}}';
639
+
640
+ // src/client/CoinListStyleScope.tsx
641
+ import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
642
+ var ScopeContext = createContext2(false);
643
+ function CoinListStyleScope({ children }) {
644
+ const alreadyScoped = useContext(ScopeContext);
645
+ if (alreadyScoped) {
646
+ return /* @__PURE__ */ jsx2(Fragment, { children });
647
+ }
648
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
649
+ /* @__PURE__ */ jsx2("link", { rel: "preconnect", href: "https://fonts.googleapis.com" }),
650
+ /* @__PURE__ */ jsx2(
651
+ "link",
652
+ {
653
+ rel: "preconnect",
654
+ href: "https://fonts.gstatic.com",
655
+ crossOrigin: "anonymous"
656
+ }
657
+ ),
658
+ /* @__PURE__ */ jsx2(
659
+ "link",
660
+ {
661
+ rel: "stylesheet",
662
+ href: "https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap"
663
+ }
664
+ ),
665
+ /* @__PURE__ */ jsxs("div", { className: "clco-sdk-root", style: { display: "contents" }, children: [
666
+ /* @__PURE__ */ jsx2(
667
+ "style",
668
+ {
669
+ href: "clco-sdk-styles",
670
+ precedence: "default",
671
+ dangerouslySetInnerHTML: { __html: sdkStyles }
672
+ }
673
+ ),
674
+ /* @__PURE__ */ jsx2(ScopeContext.Provider, { value: true, children })
675
+ ] })
676
+ ] });
324
677
  }
325
678
 
326
679
  // src/client/components/design-system/AlertBanner.tsx
@@ -670,9 +1023,9 @@ function CoinListSignInButton({
670
1023
  }
671
1024
 
672
1025
  // src/client/hooks/useCoinList.ts
673
- import { useContext } from "react";
1026
+ import { useContext as useContext2 } from "react";
674
1027
  function useCoinList() {
675
- const context = useContext(CoinListContext);
1028
+ const context = useContext2(CoinListContext);
676
1029
  if (context === null) {
677
1030
  throw new CoinListClientInitializationError();
678
1031
  }
@@ -700,7 +1053,7 @@ function CoinListSignInCard({
700
1053
  const handleSignIn = onSignIn ?? (() => {
701
1054
  void coinlist.startOAuth();
702
1055
  });
703
- return /* @__PURE__ */ jsxs7(
1056
+ return /* @__PURE__ */ jsx10(CoinListStyleScope, { children: /* @__PURE__ */ jsxs7(
704
1057
  "div",
705
1058
  {
706
1059
  className: cn(
@@ -739,7 +1092,7 @@ function CoinListSignInCard({
739
1092
  /* @__PURE__ */ jsx10(PoweredByCoinList, { className: "clcosdk:mt-4" })
740
1093
  ]
741
1094
  }
742
- );
1095
+ ) });
743
1096
  }
744
1097
 
745
1098
  // src/client/components/offers/OfferCard.tsx
@@ -837,10 +1190,8 @@ function OfferCard({
837
1190
  } else {
838
1191
  cardNode = /* @__PURE__ */ jsx11("div", { className: baseClasses, children: cardContent });
839
1192
  }
840
- if (!containerClassName) {
841
- return cardNode;
842
- }
843
- return /* @__PURE__ */ jsx11("div", { className: containerClassName, children: cardNode });
1193
+ const card = containerClassName ? /* @__PURE__ */ jsx11("div", { className: containerClassName, children: cardNode }) : cardNode;
1194
+ return /* @__PURE__ */ jsx11(CoinListStyleScope, { children: card });
844
1195
  }
845
1196
 
846
1197
  // src/client/hooks/useOffers.ts
@@ -888,7 +1239,7 @@ function useOffers(options = {}) {
888
1239
  // src/client/components/offers/OffersGrid.tsx
889
1240
  import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
890
1241
  var DEFAULT_MAX_COLUMNS = 3;
891
- function OffersGrid({
1242
+ function OffersGridBody({
892
1243
  data,
893
1244
  maxColumns,
894
1245
  className,
@@ -982,94 +1333,644 @@ function OffersGrid({
982
1333
  }
983
1334
  );
984
1335
  }
1336
+ function OffersGrid(props = {}) {
1337
+ return /* @__PURE__ */ jsx12(CoinListStyleScope, { children: /* @__PURE__ */ jsx12(OffersGridBody, { ...props }) });
1338
+ }
985
1339
 
986
- // src/client/components/requirements/RequirementItem.tsx
987
- import { ChevronRight } from "lucide-react";
988
-
989
- // src/client/components/design-system/StepStatusIcon.tsx
990
- import { CircleCheck as CircleCheck2, CircleX, Info as Info2 } from "lucide-react";
991
- import { jsx as jsx13 } from "react/jsx-runtime";
992
- var statusConfig = {
993
- required: {
994
- Icon: Info2,
995
- colorClass: "clcosdk:text-warning",
996
- fillClass: "clcosdk:[&_circle]:fill-warning-subtle"
997
- },
998
- pending: {
999
- Icon: Info2,
1000
- colorClass: "clcosdk:text-warning",
1001
- fillClass: "clcosdk:[&_circle]:fill-warning-subtle"
1002
- },
1003
- completed: {
1004
- Icon: CircleCheck2,
1005
- colorClass: "clcosdk:text-success",
1006
- fillClass: "clcosdk:[&_circle]:fill-success-subtle"
1007
- },
1008
- rejected: {
1009
- Icon: CircleX,
1010
- colorClass: "clcosdk:text-error",
1011
- fillClass: "clcosdk:[&_circle]:fill-error-subtle"
1012
- }
1013
- };
1014
- function StepStatusIcon({ status, className }) {
1015
- const { Icon, colorClass, fillClass } = statusConfig[status];
1016
- return /* @__PURE__ */ jsx13(
1017
- Icon,
1018
- {
1019
- className: cn(
1020
- "clcosdk:h-6 clcosdk:w-6 clcosdk:shrink-0",
1021
- colorClass,
1022
- fillClass,
1023
- className
1340
+ // src/client/components/requirements/ConnectedWalletList.tsx
1341
+ import { useState as useState3 } from "react";
1342
+ import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
1343
+ function ConnectedWalletRow({
1344
+ wallet,
1345
+ onRemove
1346
+ }) {
1347
+ const [state, setState] = useState3("idle");
1348
+ const remove = async () => {
1349
+ if (!onRemove) return;
1350
+ setState("removing");
1351
+ try {
1352
+ await onRemove(wallet.id);
1353
+ setState("idle");
1354
+ } catch {
1355
+ setState("error");
1356
+ }
1357
+ };
1358
+ return /* @__PURE__ */ jsxs10("div", { className: "clcosdk:flex clcosdk:min-h-9 clcosdk:flex-wrap clcosdk:items-center clcosdk:justify-between clcosdk:gap-2", children: [
1359
+ /* @__PURE__ */ jsx13(
1360
+ "span",
1361
+ {
1362
+ title: wallet.address,
1363
+ className: cn(
1364
+ typeClasses.body,
1365
+ "clcosdk:font-mono clcosdk:text-text-primary"
1366
+ ),
1367
+ children: wallet.shortAddress
1368
+ }
1369
+ ),
1370
+ onRemove != null && (state === "confirming" ? /* @__PURE__ */ jsxs10("div", { className: "clcosdk:flex clcosdk:items-center clcosdk:gap-2", children: [
1371
+ /* @__PURE__ */ jsx13(
1372
+ "span",
1373
+ {
1374
+ className: cn(typeClasses.subhead, "clcosdk:text-text-secondary"),
1375
+ children: "Remove?"
1376
+ }
1024
1377
  ),
1025
- "aria-hidden": "true"
1378
+ /* @__PURE__ */ jsx13(ClButton, { size: "sm", variant: "destructive", onClick: remove, children: "Remove" }),
1379
+ /* @__PURE__ */ jsx13(
1380
+ ClButton,
1381
+ {
1382
+ size: "sm",
1383
+ variant: "ghost",
1384
+ onClick: () => setState("idle"),
1385
+ children: "Cancel"
1386
+ }
1387
+ )
1388
+ ] }) : state === "error" ? /* @__PURE__ */ jsxs10("div", { className: "clcosdk:flex clcosdk:items-center clcosdk:gap-2", children: [
1389
+ /* @__PURE__ */ jsx13("span", { className: cn(typeClasses.subhead, "clcosdk:text-error"), children: "Couldn't remove." }),
1390
+ /* @__PURE__ */ jsx13(
1391
+ ClButton,
1392
+ {
1393
+ size: "sm",
1394
+ variant: "destructiveLink",
1395
+ onClick: () => setState("confirming"),
1396
+ children: "Try again"
1397
+ }
1398
+ )
1399
+ ] }) : /* @__PURE__ */ jsx13(
1400
+ ClButton,
1401
+ {
1402
+ size: "sm",
1403
+ variant: "destructiveLink",
1404
+ disabled: state === "removing",
1405
+ onClick: () => setState("confirming"),
1406
+ children: state === "removing" ? "Removing\u2026" : "Remove"
1407
+ }
1408
+ ))
1409
+ ] });
1410
+ }
1411
+ function ConnectedWalletList({
1412
+ wallets,
1413
+ onRemove,
1414
+ onAdd,
1415
+ addLabel = "Add wallet",
1416
+ status = "ready",
1417
+ className
1418
+ }) {
1419
+ return /* @__PURE__ */ jsxs10(
1420
+ "div",
1421
+ {
1422
+ className: cn("clcosdk:flex clcosdk:flex-col clcosdk:gap-2", className),
1423
+ children: [
1424
+ status === "loading" ? /* @__PURE__ */ jsx13(AlertBanner, { variant: "info", content: "Loading your connected wallets\u2026" }) : status === "error" ? /* @__PURE__ */ jsx13(
1425
+ AlertBanner,
1426
+ {
1427
+ variant: "error",
1428
+ content: "Couldn't load your connected wallets."
1429
+ }
1430
+ ) : wallets.length === 0 ? /* @__PURE__ */ jsx13(AlertBanner, { variant: "info", content: "No wallets connected yet." }) : /* @__PURE__ */ jsx13("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:divide-y clcosdk:divide-divider", children: wallets.map((wallet) => /* @__PURE__ */ jsx13(
1431
+ ConnectedWalletRow,
1432
+ {
1433
+ wallet,
1434
+ onRemove
1435
+ },
1436
+ wallet.id
1437
+ )) }),
1438
+ onAdd != null && status !== "loading" && /* @__PURE__ */ jsx13(
1439
+ ClButton,
1440
+ {
1441
+ size: "sm",
1442
+ variant: "secondary",
1443
+ onClick: onAdd,
1444
+ className: "clcosdk:self-start",
1445
+ children: addLabel
1446
+ }
1447
+ )
1448
+ ]
1026
1449
  }
1027
1450
  );
1028
1451
  }
1029
1452
 
1030
- // src/client/components/requirements/RequirementItem.tsx
1031
- import { Fragment as Fragment3, jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
1032
- var RequirementVariant = {
1033
- fromType(type) {
1034
- switch (type) {
1035
- case "external_wallet":
1036
- case "whitelisted_wallet":
1037
- return "wallet";
1038
- default:
1039
- return "verification";
1453
+ // src/client/components/requirements/ConnectWalletModal.tsx
1454
+ import { useEffect as useEffect4, useId } from "react";
1455
+
1456
+ // src/client/hooks/useConnectWallet.ts
1457
+ import { useCallback, useEffect as useEffect3, useRef, useState as useState4 } from "react";
1458
+
1459
+ // src/client/core/connect-external-wallet.ts
1460
+ var DEFAULT_STATEMENT = "Sign this message to prove you own this wallet. This does not cost gas or move funds.";
1461
+ var TERMINAL_CODES = /* @__PURE__ */ new Set([
1462
+ "not_authenticated",
1463
+ "wallet_not_whitelisted",
1464
+ "max_wallets_reached"
1465
+ ]);
1466
+ var API_ERROR_CODES = /* @__PURE__ */ new Set([
1467
+ "wallet_not_whitelisted",
1468
+ "max_wallets_reached"
1469
+ ]);
1470
+ function flowError(code) {
1471
+ return { code, retryable: !TERMINAL_CODES.has(code) };
1472
+ }
1473
+ function siweContext() {
1474
+ if (typeof window === "undefined") return { domain: "", uri: "" };
1475
+ return { domain: window.location.host, uri: window.location.origin };
1476
+ }
1477
+ function apiErrorCode(error) {
1478
+ if (typeof error !== "object" || error === null) return void 0;
1479
+ const body = error.response?.body;
1480
+ return typeof body?.code === "string" ? body.code : void 0;
1481
+ }
1482
+ function classifyApiError(error) {
1483
+ if (error instanceof NotAuthenticatedError) {
1484
+ return flowError("not_authenticated");
1485
+ }
1486
+ const code = apiErrorCode(error);
1487
+ if (code !== void 0 && API_ERROR_CODES.has(code)) {
1488
+ return flowError(code);
1489
+ }
1490
+ return flowError("unknown");
1491
+ }
1492
+ function challengeParams(wallet, challengeType, statement) {
1493
+ switch (challengeType) {
1494
+ case "siwe":
1495
+ return {
1496
+ walletAddress: wallet.address,
1497
+ chain: wallet.chain,
1498
+ challengeType: "siwe",
1499
+ ...siweContext(),
1500
+ statement: statement ?? DEFAULT_STATEMENT
1501
+ };
1502
+ case "plain":
1503
+ return {
1504
+ walletAddress: wallet.address,
1505
+ chain: wallet.chain,
1506
+ challengeType: "plain"
1507
+ };
1508
+ default: {
1509
+ const _exhaustive = challengeType;
1510
+ return _exhaustive;
1040
1511
  }
1041
1512
  }
1042
- };
1043
- var RequirementStatus = {
1044
- fromStatusValue(status) {
1045
- switch (status) {
1046
- case "not_started":
1047
- case "action_needed":
1048
- return "required";
1049
- case "in_progress":
1050
- return "pending";
1051
- case "completed":
1052
- return "completed";
1053
- case "rejected":
1054
- return "rejected";
1513
+ }
1514
+ async function connectExternalWalletFlow(params) {
1515
+ const {
1516
+ coinlist,
1517
+ wallet,
1518
+ offerId,
1519
+ offerOptionId,
1520
+ challengeType,
1521
+ statement,
1522
+ isCancelled,
1523
+ onProgress
1524
+ } = params;
1525
+ const emit = (phase) => onProgress?.(phase);
1526
+ const cancelled = () => isCancelled?.() ?? false;
1527
+ emit("requesting-challenge");
1528
+ let challenge;
1529
+ try {
1530
+ challenge = await coinlist.createWalletOwnershipChallenge(
1531
+ challengeParams(wallet, challengeType ?? "siwe", statement)
1532
+ );
1533
+ } catch (error) {
1534
+ return { type: "error", error: classifyApiError(error) };
1535
+ }
1536
+ if (cancelled()) return { type: "cancelled" };
1537
+ emit("signing-message");
1538
+ let signature;
1539
+ try {
1540
+ signature = await wallet.signMessage(challenge.message);
1541
+ } catch (error) {
1542
+ if (classifyWalletError(error).type === "user_rejected") {
1543
+ return { type: "error", error: flowError("user_rejected") };
1055
1544
  }
1545
+ return { type: "error", error: flowError("unknown") };
1056
1546
  }
1057
- };
1058
- var ChecklistStatus = {
1059
- derive(statuses) {
1060
- if (statuses.some((s) => s.status === "rejected")) return "ineligible";
1061
- if (statuses.every((s) => s.status === "completed")) return "eligible";
1062
- return "inProgress";
1547
+ if (cancelled()) return { type: "cancelled" };
1548
+ emit("submitting-signature");
1549
+ try {
1550
+ const binding = await coinlist.connectExternalWallet(offerId, {
1551
+ offerOptionId,
1552
+ walletAddress: wallet.address,
1553
+ chain: wallet.chain,
1554
+ signature
1555
+ });
1556
+ return { type: "success", binding };
1557
+ } catch (error) {
1558
+ return { type: "error", error: classifyApiError(error) };
1063
1559
  }
1560
+ }
1561
+
1562
+ // src/client/hooks/useConnectWallet.ts
1563
+ var IDLE_SIGN = { type: "idle", error: null };
1564
+ var ERROR_COPY = {
1565
+ not_authenticated: "Sign in to connect your wallet.",
1566
+ user_rejected: "Signature request declined. Approve it in your wallet to continue.",
1567
+ wallet_not_whitelisted: "This wallet is not approved for this offer.",
1568
+ max_wallets_reached: "You've reached the maximum number of wallets for this option.",
1569
+ unknown: "Unable to connect your wallet. Please try again."
1064
1570
  };
1065
- var RequirementItemUi = {
1066
- fromDomain(req, statusInfo, label, description, walletAddress) {
1067
- return {
1571
+ function displayError(error) {
1572
+ return {
1573
+ code: error.code,
1574
+ message: ERROR_COPY[error.code],
1575
+ retryable: error.retryable
1576
+ };
1577
+ }
1578
+ function useConnectWallet({
1579
+ isOpen,
1580
+ offerId,
1581
+ offerOptionId,
1582
+ wallet,
1583
+ challengeType,
1584
+ statement
1585
+ }) {
1586
+ const { coinlist } = useCoinList();
1587
+ const [state, setState] = useState4(
1588
+ () => wallet ? { type: "READY", address: wallet.address, sign: IDLE_SIGN } : { type: "NEEDS_WALLET" }
1589
+ );
1590
+ const attempt = useRef(0);
1591
+ useEffect3(() => {
1592
+ attempt.current += 1;
1593
+ if (!isOpen) return;
1594
+ setState(
1595
+ wallet ? { type: "READY", address: wallet.address, sign: IDLE_SIGN } : { type: "NEEDS_WALLET" }
1596
+ );
1597
+ }, [isOpen, wallet?.address]);
1598
+ useEffect3(
1599
+ () => () => {
1600
+ attempt.current += 1;
1601
+ },
1602
+ []
1603
+ );
1604
+ const onSign = useCallback(() => {
1605
+ if (!wallet || state.type !== "READY") return;
1606
+ attempt.current += 1;
1607
+ const gen = attempt.current;
1608
+ setState({
1609
+ type: "READY",
1610
+ address: wallet.address,
1611
+ sign: { type: "signing" }
1612
+ });
1613
+ connectExternalWalletFlow({
1614
+ coinlist,
1615
+ wallet,
1616
+ offerId,
1617
+ offerOptionId,
1618
+ challengeType,
1619
+ statement,
1620
+ // Cancels the flow before signing / binding if this attempt is superseded.
1621
+ isCancelled: () => attempt.current !== gen
1622
+ }).then((result) => {
1623
+ if (attempt.current !== gen) return;
1624
+ if (result.type === "success") {
1625
+ setState({ type: "CONNECTED", binding: result.binding });
1626
+ } else if (result.type === "error") {
1627
+ setState({
1628
+ type: "READY",
1629
+ address: wallet.address,
1630
+ sign: { type: "idle", error: displayError(result.error) }
1631
+ });
1632
+ }
1633
+ });
1634
+ }, [
1635
+ wallet,
1636
+ state,
1637
+ coinlist,
1638
+ offerId,
1639
+ offerOptionId,
1640
+ challengeType,
1641
+ statement
1642
+ ]);
1643
+ return { state, onSign };
1644
+ }
1645
+
1646
+ // src/client/components/requirements/ConnectWalletModal.tsx
1647
+ import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
1648
+ function ConnectWalletModal({
1649
+ isOpen,
1650
+ onClose,
1651
+ offerId,
1652
+ optionId,
1653
+ wallet,
1654
+ onConnected,
1655
+ onRequestConnect,
1656
+ challengeType,
1657
+ statement,
1658
+ className
1659
+ }) {
1660
+ const { state, onSign } = useConnectWallet({
1661
+ isOpen,
1662
+ offerId,
1663
+ offerOptionId: optionId,
1664
+ wallet,
1665
+ challengeType,
1666
+ statement
1667
+ });
1668
+ const titleId = useId();
1669
+ useEffect4(() => {
1670
+ if (state.type === "CONNECTED") {
1671
+ onConnected?.(state.binding);
1672
+ onClose();
1673
+ }
1674
+ }, [state]);
1675
+ if (!isOpen || state.type === "CONNECTED") return null;
1676
+ return /* @__PURE__ */ jsx14("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__ */ jsxs11(
1677
+ "div",
1678
+ {
1679
+ role: "dialog",
1680
+ "aria-modal": "true",
1681
+ "aria-labelledby": titleId,
1682
+ className: cn(
1683
+ "clcosdk:flex clcosdk:w-full clcosdk:max-w-md clcosdk:flex-col clcosdk:gap-6 clcosdk:rounded-2xl clcosdk:bg-background clcosdk:p-6",
1684
+ className
1685
+ ),
1686
+ children: [
1687
+ /* @__PURE__ */ jsxs11("div", { className: "clcosdk:flex clcosdk:items-start clcosdk:justify-between clcosdk:gap-4", children: [
1688
+ /* @__PURE__ */ jsx14(
1689
+ "h3",
1690
+ {
1691
+ id: titleId,
1692
+ className: cn(typeClasses.h3, "clcosdk:text-text-primary"),
1693
+ children: "Connect your wallet"
1694
+ }
1695
+ ),
1696
+ /* @__PURE__ */ jsx14(CloseButton, { onClick: onClose })
1697
+ ] }),
1698
+ state.type === "NEEDS_WALLET" && /* @__PURE__ */ jsx14(NeedsWalletScreen, { onRequestConnect }),
1699
+ state.type === "READY" && /* @__PURE__ */ jsx14(
1700
+ ReadyScreen,
1701
+ {
1702
+ address: state.address,
1703
+ sign: state.sign,
1704
+ onSign,
1705
+ onRequestConnect
1706
+ }
1707
+ )
1708
+ ]
1709
+ }
1710
+ ) });
1711
+ }
1712
+ function NeedsWalletScreen({
1713
+ onRequestConnect
1714
+ }) {
1715
+ return /* @__PURE__ */ jsxs11("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-6", children: [
1716
+ /* @__PURE__ */ jsx14("p", { className: cn(typeClasses.body, "clcosdk:text-text-secondary"), children: "Connect an external wallet to prove ownership and bind it to this offer." }),
1717
+ onRequestConnect && /* @__PURE__ */ jsx14(ClButton, { fullWidth: true, onClick: onRequestConnect, children: "Connect wallet" })
1718
+ ] });
1719
+ }
1720
+ function ReadyScreen({
1721
+ address,
1722
+ sign,
1723
+ onSign,
1724
+ onRequestConnect
1725
+ }) {
1726
+ const hasTerminalError = sign.type === "idle" && sign.error !== null && !sign.error.retryable;
1727
+ return /* @__PURE__ */ jsxs11("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-6", children: [
1728
+ /* @__PURE__ */ jsx14("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." }),
1729
+ /* @__PURE__ */ jsxs11("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-1 clcosdk:border-t clcosdk:border-divider clcosdk:pt-4", children: [
1730
+ /* @__PURE__ */ jsx14("span", { className: cn(typeClasses.label, "clcosdk:text-text-secondary"), children: "Wallet address" }),
1731
+ /* @__PURE__ */ jsx14("span", { className: cn(typeClasses.body, "clcosdk:text-text-primary"), children: shortenAddress(address) })
1732
+ ] }),
1733
+ sign.type === "idle" && sign.error && // Live region: the error is inserted async after a failed attempt, so
1734
+ // screen readers need it announced rather than silently rendered.
1735
+ /* @__PURE__ */ jsx14("div", { role: "alert", children: /* @__PURE__ */ jsx14(AlertBanner, { variant: "error", icon: true, content: sign.error.message }) }),
1736
+ /* @__PURE__ */ jsx14(
1737
+ ClButton,
1738
+ {
1739
+ fullWidth: true,
1740
+ onClick: onSign,
1741
+ isLoading: sign.type === "signing",
1742
+ loadingText: "Waiting for signature...",
1743
+ disabled: hasTerminalError,
1744
+ children: "Sign & connect"
1745
+ }
1746
+ ),
1747
+ onRequestConnect && /* @__PURE__ */ jsx14(
1748
+ ClButton,
1749
+ {
1750
+ fullWidth: true,
1751
+ variant: "secondary",
1752
+ onClick: onRequestConnect,
1753
+ disabled: sign.type === "signing",
1754
+ children: "Use a different wallet"
1755
+ }
1756
+ )
1757
+ ] });
1758
+ }
1759
+
1760
+ // src/client/components/requirements/IdentityVerification.tsx
1761
+ import SumsubWebSdk from "@sumsub/websdk-react";
1762
+ import { useEffect as useEffect6, useRef as useRef3 } from "react";
1763
+
1764
+ // src/client/hooks/useKycToken.ts
1765
+ import { useCallback as useCallback2, useEffect as useEffect5, useRef as useRef2, useState as useState5 } from "react";
1766
+ var IDLE_STATE = { type: "IDLE" };
1767
+ var LOADING_STATE2 = { type: "LOADING" };
1768
+ function useKycToken(levelName, reset) {
1769
+ const { coinlist } = useCoinList();
1770
+ const [kycTokenState, setKycTokenState] = useState5(IDLE_STATE);
1771
+ const resetPendingRef = useRef2(reset === true);
1772
+ const tokenIssuedRef = useRef2(false);
1773
+ useEffect5(() => {
1774
+ if (!tokenIssuedRef.current) {
1775
+ resetPendingRef.current = reset === true;
1776
+ }
1777
+ }, [reset]);
1778
+ const fetchToken = useCallback2(async () => {
1779
+ setKycTokenState(LOADING_STATE2);
1780
+ try {
1781
+ const kycToken = await coinlist.createKycToken(
1782
+ levelName,
1783
+ resetPendingRef.current
1784
+ );
1785
+ resetPendingRef.current = false;
1786
+ tokenIssuedRef.current = true;
1787
+ setKycTokenState({ type: "CONTENT", token: kycToken.token });
1788
+ return kycToken.token;
1789
+ } catch (error) {
1790
+ const reason = error instanceof NotAuthenticatedError ? "not-authenticated" : "generic-error";
1791
+ setKycTokenState({ type: "ERROR", reason });
1792
+ throw error;
1793
+ }
1794
+ }, [coinlist, levelName]);
1795
+ return { kycTokenState, fetchToken };
1796
+ }
1797
+
1798
+ // src/client/components/requirements/IdentityVerification.tsx
1799
+ import { jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
1800
+ function IdentityVerification({
1801
+ levelName,
1802
+ reset,
1803
+ locale,
1804
+ onSubmitted,
1805
+ onError,
1806
+ className
1807
+ }) {
1808
+ const { kycTokenState, fetchToken } = useKycToken(levelName, reset);
1809
+ const fetchedRef = useRef3(false);
1810
+ useEffect6(() => {
1811
+ if (fetchedRef.current) return;
1812
+ fetchedRef.current = true;
1813
+ fetchToken().catch(() => {
1814
+ });
1815
+ }, [fetchToken]);
1816
+ const handleMessage = (type, payload) => {
1817
+ switch (type) {
1818
+ case "idCheck.onApplicantSubmitted":
1819
+ onSubmitted?.();
1820
+ break;
1821
+ case "idCheck.onError": {
1822
+ const message = payload?.message ?? "Verification error";
1823
+ onError?.(new Error(message));
1824
+ break;
1825
+ }
1826
+ default:
1827
+ break;
1828
+ }
1829
+ };
1830
+ const handleError = (error) => {
1831
+ onError?.(error instanceof Error ? error : new Error("Verification error"));
1832
+ };
1833
+ if (kycTokenState.type === "IDLE" || kycTokenState.type === "LOADING") {
1834
+ return /* @__PURE__ */ jsx15(
1835
+ "output",
1836
+ {
1837
+ "aria-live": "polite",
1838
+ className: cn(
1839
+ "clcosdk:flex clcosdk:min-h-40 clcosdk:items-center clcosdk:justify-center",
1840
+ className
1841
+ ),
1842
+ children: /* @__PURE__ */ jsx15("p", { className: cn(typeClasses.body, "clcosdk:text-text-secondary"), children: "Loading identity verification..." })
1843
+ }
1844
+ );
1845
+ }
1846
+ if (kycTokenState.type === "ERROR") {
1847
+ const errorMessage = kycTokenState.reason === "not-authenticated" ? "Sign in to verify your identity." : "Unable to start identity verification right now. Please try again.";
1848
+ return /* @__PURE__ */ jsxs12(
1849
+ "div",
1850
+ {
1851
+ className: cn("clcosdk:flex clcosdk:flex-col clcosdk:gap-4", className),
1852
+ children: [
1853
+ /* @__PURE__ */ jsx15(AlertBanner, { variant: "error", icon: true, content: errorMessage }),
1854
+ kycTokenState.reason !== "not-authenticated" && /* @__PURE__ */ jsx15(
1855
+ ClButton,
1856
+ {
1857
+ size: "sm",
1858
+ onClick: () => {
1859
+ fetchToken().catch(() => {
1860
+ });
1861
+ },
1862
+ children: "Try again"
1863
+ }
1864
+ )
1865
+ ]
1866
+ }
1867
+ );
1868
+ }
1869
+ return /* @__PURE__ */ jsx15("div", { className: cn("clcosdk:w-full", className), children: /* @__PURE__ */ jsx15(
1870
+ SumsubWebSdk,
1871
+ {
1872
+ accessToken: kycTokenState.token,
1873
+ expirationHandler: fetchToken,
1874
+ config: locale === void 0 ? {} : { lang: locale },
1875
+ options: { addViewportTag: false, adaptIframeHeight: true },
1876
+ onMessage: handleMessage,
1877
+ onError: handleError
1878
+ }
1879
+ ) });
1880
+ }
1881
+
1882
+ // src/client/components/requirements/RequirementItem.tsx
1883
+ import { ChevronRight } from "lucide-react";
1884
+
1885
+ // src/client/components/design-system/StepStatusIcon.tsx
1886
+ import { CircleCheck as CircleCheck2, CircleX, Info as Info2 } from "lucide-react";
1887
+ import { jsx as jsx16 } from "react/jsx-runtime";
1888
+ var statusConfig = {
1889
+ required: {
1890
+ Icon: Info2,
1891
+ colorClass: "clcosdk:text-warning",
1892
+ fillClass: "clcosdk:[&_circle]:fill-warning-subtle"
1893
+ },
1894
+ pending: {
1895
+ Icon: Info2,
1896
+ colorClass: "clcosdk:text-warning",
1897
+ fillClass: "clcosdk:[&_circle]:fill-warning-subtle"
1898
+ },
1899
+ completed: {
1900
+ Icon: CircleCheck2,
1901
+ colorClass: "clcosdk:text-success",
1902
+ fillClass: "clcosdk:[&_circle]:fill-success-subtle"
1903
+ },
1904
+ rejected: {
1905
+ Icon: CircleX,
1906
+ colorClass: "clcosdk:text-error",
1907
+ fillClass: "clcosdk:[&_circle]:fill-error-subtle"
1908
+ }
1909
+ };
1910
+ function StepStatusIcon({ status, className }) {
1911
+ const { Icon, colorClass, fillClass } = statusConfig[status];
1912
+ return /* @__PURE__ */ jsx16(
1913
+ Icon,
1914
+ {
1915
+ className: cn(
1916
+ "clcosdk:h-6 clcosdk:w-6 clcosdk:shrink-0",
1917
+ colorClass,
1918
+ fillClass,
1919
+ className
1920
+ ),
1921
+ "aria-hidden": "true"
1922
+ }
1923
+ );
1924
+ }
1925
+
1926
+ // src/client/components/requirements/RequirementItem.tsx
1927
+ import { Fragment as Fragment3, jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
1928
+ var RequirementVariant = {
1929
+ fromType(type) {
1930
+ switch (type) {
1931
+ case "external_wallet":
1932
+ case "whitelisted_wallet":
1933
+ return "wallet";
1934
+ default:
1935
+ return "verification";
1936
+ }
1937
+ }
1938
+ };
1939
+ var RequirementStatus = {
1940
+ fromStatusValue(status) {
1941
+ switch (status) {
1942
+ case "not_started":
1943
+ case "action_needed":
1944
+ return "required";
1945
+ case "in_progress":
1946
+ return "pending";
1947
+ case "completed":
1948
+ return "completed";
1949
+ case "rejected":
1950
+ return "rejected";
1951
+ }
1952
+ }
1953
+ };
1954
+ var ChecklistStatus = {
1955
+ derive(statuses) {
1956
+ if (statuses.some((s) => s.status === "rejected")) return "ineligible";
1957
+ if (statuses.every((s) => s.status === "completed")) return "eligible";
1958
+ return "inProgress";
1959
+ }
1960
+ };
1961
+ var RequirementItemUi = {
1962
+ fromDomain(req, statusInfo, label, description, addresses = []) {
1963
+ return {
1068
1964
  variant: RequirementVariant.fromType(req.type),
1069
1965
  status: statusInfo ? RequirementStatus.fromStatusValue(statusInfo.status) : "required",
1070
1966
  label,
1071
1967
  description,
1072
- walletAddress
1968
+ multiWallet: req.type === "whitelisted_wallet",
1969
+ connectedWallets: addresses.map((address) => ({
1970
+ id: address.id,
1971
+ address: address.address,
1972
+ shortAddress: shortenAddress(address.address)
1973
+ }))
1073
1974
  };
1074
1975
  }
1075
1976
  };
@@ -1081,9 +1982,9 @@ function VerificationActionZone({
1081
1982
  switch (status) {
1082
1983
  case "required":
1083
1984
  if (onAction === null) return null;
1084
- return /* @__PURE__ */ jsx14(ClButton, { size: "sm", onClick: onAction, children: "Continue" });
1985
+ return /* @__PURE__ */ jsx17(ClButton, { size: "sm", onClick: onAction, children: "Continue" });
1085
1986
  case "pending":
1086
- return /* @__PURE__ */ jsx14(
1987
+ return /* @__PURE__ */ jsx17(
1087
1988
  AlertBanner,
1088
1989
  {
1089
1990
  variant: "warning",
@@ -1091,16 +1992,16 @@ function VerificationActionZone({
1091
1992
  }
1092
1993
  );
1093
1994
  case "completed":
1094
- return /* @__PURE__ */ jsx14(AlertBanner, { variant: "success", content: "Identity verified." });
1995
+ return /* @__PURE__ */ jsx17(AlertBanner, { variant: "success", content: "Identity verified." });
1095
1996
  case "rejected":
1096
- return /* @__PURE__ */ jsx14(
1997
+ return /* @__PURE__ */ jsx17(
1097
1998
  AlertBanner,
1098
1999
  {
1099
2000
  variant: "error",
1100
- content: onContactSupport === null ? "Verification rejected." : /* @__PURE__ */ jsxs10(Fragment3, { children: [
2001
+ content: onContactSupport === null ? "Verification rejected." : /* @__PURE__ */ jsxs13(Fragment3, { children: [
1101
2002
  "Verification rejected.",
1102
2003
  " ",
1103
- /* @__PURE__ */ jsx14(
2004
+ /* @__PURE__ */ jsx17(
1104
2005
  "button",
1105
2006
  {
1106
2007
  type: "button",
@@ -1117,25 +2018,61 @@ function VerificationActionZone({
1117
2018
  }
1118
2019
  function WalletActionZone({
1119
2020
  status,
1120
- walletAddress,
1121
- onAction
2021
+ multiWallet,
2022
+ connectedWallets,
2023
+ walletsStatus,
2024
+ onAction,
2025
+ onRemoveWallet
1122
2026
  }) {
2027
+ if (multiWallet) {
2028
+ return /* @__PURE__ */ jsxs13(Fragment3, { children: [
2029
+ /* @__PURE__ */ jsx17(
2030
+ ConnectedWalletList,
2031
+ {
2032
+ wallets: connectedWallets,
2033
+ onRemove: onRemoveWallet,
2034
+ onAdd: onAction ?? void 0,
2035
+ status: walletsStatus
2036
+ }
2037
+ ),
2038
+ status === "rejected" && /* @__PURE__ */ jsx17(
2039
+ AlertBanner,
2040
+ {
2041
+ variant: "error",
2042
+ content: "One of these wallets is not eligible for this sale."
2043
+ }
2044
+ )
2045
+ ] });
2046
+ }
1123
2047
  if (status === "completed") {
1124
- return /* @__PURE__ */ jsxs10(Fragment3, { children: [
1125
- onAction !== null && /* @__PURE__ */ jsx14(ClButton, { size: "sm", variant: "secondary", onClick: onAction, children: "Change wallet" }),
1126
- /* @__PURE__ */ jsx14(
2048
+ const connected = connectedWallets[0];
2049
+ return /* @__PURE__ */ jsxs13(Fragment3, { children: [
2050
+ onAction !== null && /* @__PURE__ */ jsx17(ClButton, { size: "sm", variant: "secondary", onClick: onAction, children: "Change wallet" }),
2051
+ walletsStatus === "loading" ? /* @__PURE__ */ jsx17(
2052
+ AlertBanner,
2053
+ {
2054
+ variant: "info",
2055
+ content: "Loading your connected wallet\u2026"
2056
+ }
2057
+ ) : walletsStatus === "error" ? /* @__PURE__ */ jsx17(
2058
+ AlertBanner,
2059
+ {
2060
+ variant: "error",
2061
+ content: "Couldn't load your connected wallet."
2062
+ }
2063
+ ) : /* @__PURE__ */ jsx17(
1127
2064
  AlertBanner,
1128
2065
  {
1129
2066
  variant: "success",
1130
- content: walletAddress ?? "Connected: 0xBa4b...9f2c"
2067
+ content: connected ? connected.shortAddress : "Wallet connected."
1131
2068
  }
1132
2069
  )
1133
2070
  ] });
1134
2071
  }
1135
2072
  if (status === "rejected") {
1136
- return /* @__PURE__ */ jsxs10(Fragment3, { children: [
1137
- onAction !== null && /* @__PURE__ */ jsx14(ClButton, { size: "sm", onClick: onAction, children: "Connect wallet" }),
1138
- /* @__PURE__ */ jsx14(
2073
+ return /* @__PURE__ */ jsxs13(Fragment3, { children: [
2074
+ onAction !== null && /* @__PURE__ */ jsx17(ClButton, { size: "sm", onClick: onAction, children: "Connect wallet" }),
2075
+ /* @__PURE__ */ jsx17(
1139
2076
  AlertBanner,
1140
2077
  {
1141
2078
  variant: "error",
@@ -1145,7 +2082,7 @@ function WalletActionZone({
1145
2082
  ] });
1146
2083
  }
1147
2084
  if (onAction === null) return null;
1148
- return /* @__PURE__ */ jsx14(ClButton, { size: "sm", onClick: onAction, children: "Connect wallet" });
2085
+ return /* @__PURE__ */ jsx17(ClButton, { size: "sm", onClick: onAction, children: "Connect wallet" });
1149
2086
  }
1150
2087
  function RequirementItem({
1151
2088
  ui,
@@ -1153,14 +2090,19 @@ function RequirementItem({
1153
2090
  onToggle,
1154
2091
  className,
1155
2092
  onAction,
2093
+ onRemoveWallet,
2094
+ walletsStatus,
1156
2095
  onContactSupport
1157
2096
  }) {
1158
- return /* @__PURE__ */ jsxs10(
2097
+ return /* @__PURE__ */ jsx17(CoinListStyleScope, { children: /* @__PURE__ */ jsxs13(
1159
2098
  "div",
1160
2099
  {
1161
- className: cn("clcosdk:flex clcosdk:w-full clcosdk:flex-col", className),
2100
+ className: cn(
2101
+ "clcosdk:flex clcosdk:w-full clcosdk:flex-col",
2102
+ className
2103
+ ),
1162
2104
  children: [
1163
- /* @__PURE__ */ jsxs10(
2105
+ /* @__PURE__ */ jsxs13(
1164
2106
  "button",
1165
2107
  {
1166
2108
  type: "button",
@@ -1168,9 +2110,9 @@ function RequirementItem({
1168
2110
  "aria-expanded": expanded,
1169
2111
  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",
1170
2112
  children: [
1171
- /* @__PURE__ */ jsxs10("div", { className: "clcosdk:flex clcosdk:items-center clcosdk:gap-3", children: [
1172
- /* @__PURE__ */ jsx14(StepStatusIcon, { status: ui.status }),
1173
- /* @__PURE__ */ jsx14(
2113
+ /* @__PURE__ */ jsxs13("div", { className: "clcosdk:flex clcosdk:items-center clcosdk:gap-3", children: [
2114
+ /* @__PURE__ */ jsx17(StepStatusIcon, { status: ui.status }),
2115
+ /* @__PURE__ */ jsx17(
1174
2116
  "span",
1175
2117
  {
1176
2118
  className: cn(
@@ -1181,7 +2123,7 @@ function RequirementItem({
1181
2123
  }
1182
2124
  )
1183
2125
  ] }),
1184
- /* @__PURE__ */ jsx14(
2126
+ /* @__PURE__ */ jsx17(
1185
2127
  ChevronRight,
1186
2128
  {
1187
2129
  className: cn(
@@ -1194,34 +2136,40 @@ function RequirementItem({
1194
2136
  ]
1195
2137
  }
1196
2138
  ),
1197
- /* @__PURE__ */ jsx14(
2139
+ /* @__PURE__ */ jsx17(
1198
2140
  "div",
1199
2141
  {
1200
2142
  className: cn(
1201
2143
  "clcosdk:grid clcosdk:transition-[grid-template-rows] clcosdk:duration-300 clcosdk:ease-in-out",
1202
2144
  expanded ? "clcosdk:grid-rows-[1fr]" : "clcosdk:grid-rows-[0fr]"
1203
2145
  ),
1204
- children: /* @__PURE__ */ jsx14("div", { className: "clcosdk:min-h-0 clcosdk:overflow-hidden", children: /* @__PURE__ */ jsxs10("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-4 clcosdk:px-2 clcosdk:pb-4", children: [
1205
- /* @__PURE__ */ jsx14(
2146
+ children: /* @__PURE__ */ jsx17("div", { className: "clcosdk:min-h-0 clcosdk:overflow-hidden", children: /* @__PURE__ */ jsxs13("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-4 clcosdk:px-2 clcosdk:pb-4", children: [
2147
+ /* @__PURE__ */ jsx17(
1206
2148
  "p",
1207
2149
  {
1208
- className: cn(typeClasses.subhead, "clcosdk:text-text-secondary"),
2150
+ className: cn(
2151
+ typeClasses.subhead,
2152
+ "clcosdk:text-text-secondary"
2153
+ ),
1209
2154
  children: ui.description
1210
2155
  }
1211
2156
  ),
1212
- ui.variant === "verification" ? /* @__PURE__ */ jsx14(
2157
+ ui.variant === "verification" ? /* @__PURE__ */ jsx17(
1213
2158
  VerificationActionZone,
1214
2159
  {
1215
2160
  status: ui.status,
1216
2161
  onAction,
1217
2162
  onContactSupport
1218
2163
  }
1219
- ) : /* @__PURE__ */ jsx14(
2164
+ ) : /* @__PURE__ */ jsx17(
1220
2165
  WalletActionZone,
1221
2166
  {
1222
2167
  status: ui.status,
1223
- walletAddress: ui.walletAddress,
1224
- onAction
2168
+ multiWallet: ui.multiWallet,
2169
+ connectedWallets: ui.connectedWallets,
2170
+ walletsStatus,
2171
+ onAction,
2172
+ onRemoveWallet
1225
2173
  }
1226
2174
  )
1227
2175
  ] }) })
@@ -1229,28 +2177,501 @@ function RequirementItem({
1229
2177
  )
1230
2178
  ]
1231
2179
  }
1232
- );
2180
+ ) });
1233
2181
  }
1234
2182
 
1235
2183
  // src/client/components/requirements/RequirementsChecklist.tsx
1236
- import { useState as useState4 } from "react";
2184
+ import { useEffect as useEffect11, useRef as useRef4, useState as useState9 } from "react";
2185
+
2186
+ // src/client/components/requirements/TaxDocumentModal.tsx
2187
+ import { useEffect as useEffect8 } from "react";
2188
+
2189
+ // src/client/hooks/useTaxDocument.ts
2190
+ import { useCallback as useCallback3, useEffect as useEffect7, useState as useState6 } from "react";
2191
+ var IDLE_SIGN2 = { type: "idle", error: null };
2192
+ var LOADING_STATE3 = { type: "LOADING" };
2193
+ var SIGN_FAILED_MESSAGE = "Unable to sign document. Please try again.";
2194
+ var DOB_INVALID_MESSAGE = "Enter your date of birth as MM/DD/YYYY.";
2195
+ var FIELD_KEYS = {
2196
+ fullLegalName: "Full Name",
2197
+ dob: "DOB",
2198
+ countryOfCitizenship: "Country Of Citizenship",
2199
+ taxId: "Foreign Tax Number",
2200
+ permanentAddress: "Permanent Address"
2201
+ };
2202
+ function formatUsDate(date) {
2203
+ const month = String(date.getMonth() + 1).padStart(2, "0");
2204
+ const day = String(date.getDate()).padStart(2, "0");
2205
+ const year = String(date.getFullYear()).padStart(4, "0");
2206
+ return `${month}/${day}/${year}`;
2207
+ }
2208
+ function formatIsoDateOnly(isoDate) {
2209
+ const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(isoDate);
2210
+ if (!match) return "";
2211
+ const [, year, month, day] = match;
2212
+ return `${month}/${day}/${year}`;
2213
+ }
2214
+ function isValidUsDate(value) {
2215
+ const match = /^(\d{2})\/(\d{2})\/(\d{4})$/.exec(value);
2216
+ if (!match) return false;
2217
+ const [, mm, dd, yyyy] = match;
2218
+ const month = Number(mm);
2219
+ const day = Number(dd);
2220
+ const year = Number(yyyy);
2221
+ const date = new Date(year, month - 1, day);
2222
+ return date.getFullYear() === year && date.getMonth() === month - 1 && date.getDate() === day;
2223
+ }
2224
+ function mapPiiToFields(pii) {
2225
+ const { street, city, state, postalCode } = pii.permanentAddress;
2226
+ const cityLine = [postalCode, city].filter(Boolean).join(" ");
2227
+ const permanentAddress = [street, cityLine, state].filter(Boolean).join(", ");
2228
+ return {
2229
+ fullLegalName: pii.fullLegalName ?? "",
2230
+ // Date-only ISO from the backend, shown as MM/DD/YYYY. Blank until the
2231
+ // backend has a date of birth (the field is editable in the meantime).
2232
+ dob: formatIsoDateOnly(pii.dateOfBirth ?? ""),
2233
+ countryOfCitizenship: pii.jurisdiction?.name ?? "",
2234
+ taxId: pii.taxId ?? "",
2235
+ permanentAddress
2236
+ };
2237
+ }
2238
+ function addressPartsFromPii(pii) {
2239
+ return {
2240
+ city: pii.permanentAddress.city ?? "",
2241
+ country: pii.permanentAddress.country ?? ""
2242
+ };
2243
+ }
2244
+ function hasAnyFieldValue(fields) {
2245
+ return Object.values(fields).some((value) => value.trim() !== "");
2246
+ }
2247
+ function toSubmissionFields(fields, addressParts) {
2248
+ return {
2249
+ [FIELD_KEYS.fullLegalName]: fields.fullLegalName,
2250
+ [FIELD_KEYS.dob]: fields.dob,
2251
+ [FIELD_KEYS.countryOfCitizenship]: fields.countryOfCitizenship,
2252
+ [FIELD_KEYS.taxId]: fields.taxId,
2253
+ [FIELD_KEYS.permanentAddress]: fields.permanentAddress,
2254
+ City: addressParts.city,
2255
+ Country: addressParts.country,
2256
+ Signature: fields.fullLegalName,
2257
+ Date: formatUsDate(/* @__PURE__ */ new Date())
2258
+ };
2259
+ }
2260
+ function useTaxDocument({
2261
+ isOpen
2262
+ }) {
2263
+ const { coinlist, isReady } = useCoinList();
2264
+ const [state, setState] = useState6(LOADING_STATE3);
2265
+ useEffect7(() => {
2266
+ let isCancelled = false;
2267
+ if (!isOpen) {
2268
+ return () => {
2269
+ isCancelled = true;
2270
+ };
2271
+ }
2272
+ if (!isReady) {
2273
+ setState(LOADING_STATE3);
2274
+ return () => {
2275
+ isCancelled = true;
2276
+ };
2277
+ }
2278
+ setState(LOADING_STATE3);
2279
+ coinlist.fetchPii().then((pii) => {
2280
+ if (isCancelled) return;
2281
+ if (pii.kind === "company") {
2282
+ setState({ type: "SIGN_ONLY", sign: IDLE_SIGN2 });
2283
+ return;
2284
+ }
2285
+ const fields = mapPiiToFields(pii);
2286
+ setState({
2287
+ type: "REVIEW",
2288
+ fields,
2289
+ addressParts: addressPartsFromPii(pii),
2290
+ piiUnavailable: !hasAnyFieldValue(fields),
2291
+ sign: IDLE_SIGN2
2292
+ });
2293
+ }).catch((error) => {
2294
+ if (isCancelled) return;
2295
+ setState({
2296
+ type: "ERROR",
2297
+ reason: error instanceof NotAuthenticatedError ? "not-authenticated" : "generic-error"
2298
+ });
2299
+ });
2300
+ return () => {
2301
+ isCancelled = true;
2302
+ };
2303
+ }, [coinlist, isReady, isOpen]);
2304
+ const onEditField = useCallback3(
2305
+ (field, value) => {
2306
+ setState(
2307
+ (prev) => prev.type === "EDITING" ? { ...prev, fields: { ...prev.fields, [field]: value } } : prev
2308
+ );
2309
+ },
2310
+ []
2311
+ );
2312
+ const onStartEdit = useCallback3(() => {
2313
+ setState(
2314
+ (prev) => prev.type === "REVIEW" ? {
2315
+ type: "EDITING",
2316
+ fields: prev.fields,
2317
+ original: prev.fields,
2318
+ addressParts: prev.addressParts,
2319
+ piiUnavailable: prev.piiUnavailable
2320
+ } : prev
2321
+ );
2322
+ }, []);
2323
+ const onSaveEdit = useCallback3(() => {
2324
+ setState(
2325
+ (prev) => prev.type === "EDITING" ? {
2326
+ type: "REVIEW",
2327
+ fields: prev.fields,
2328
+ addressParts: prev.addressParts,
2329
+ piiUnavailable: prev.piiUnavailable,
2330
+ sign: IDLE_SIGN2
2331
+ } : prev
2332
+ );
2333
+ }, []);
2334
+ const onCancelEdit = useCallback3(() => {
2335
+ setState(
2336
+ (prev) => prev.type === "EDITING" ? {
2337
+ type: "REVIEW",
2338
+ fields: prev.original,
2339
+ addressParts: prev.addressParts,
2340
+ piiUnavailable: prev.piiUnavailable,
2341
+ sign: IDLE_SIGN2
2342
+ } : prev
2343
+ );
2344
+ }, []);
2345
+ const onSign = useCallback3(() => {
2346
+ if (state.type !== "REVIEW" && state.type !== "SIGN_ONLY") return;
2347
+ if (state.type === "REVIEW" && state.fields.dob.trim() !== "" && !isValidUsDate(state.fields.dob)) {
2348
+ setState({
2349
+ ...state,
2350
+ sign: { type: "idle", error: DOB_INVALID_MESSAGE }
2351
+ });
2352
+ return;
2353
+ }
2354
+ setState({ ...state, sign: { type: "signing" } });
2355
+ coinlist.submitDocument(
2356
+ "tax_certification",
2357
+ state.type === "REVIEW" ? toSubmissionFields(state.fields, state.addressParts) : {}
2358
+ ).then((submission) => {
2359
+ setState({ type: "SUBMITTED", submission });
2360
+ }).catch(() => {
2361
+ setState(
2362
+ (prev) => prev.type === "REVIEW" || prev.type === "SIGN_ONLY" ? { ...prev, sign: { type: "idle", error: SIGN_FAILED_MESSAGE } } : prev
2363
+ );
2364
+ });
2365
+ }, [state, coinlist]);
2366
+ return { state, onEditField, onStartEdit, onSaveEdit, onCancelEdit, onSign };
2367
+ }
2368
+
2369
+ // src/client/components/requirements/TaxDocumentModal.tsx
2370
+ import { jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
2371
+ var FIELD_ROWS = [
2372
+ { field: "fullLegalName", label: "Full legal name" },
2373
+ { field: "dob", label: "Date of birth", placeholder: "MM/DD/YYYY" },
2374
+ { field: "countryOfCitizenship", label: "Country of citizenship" },
2375
+ { field: "taxId", label: "Tax ID" },
2376
+ { field: "permanentAddress", label: "Permanent address" }
2377
+ ];
2378
+ function TaxDocumentModal({
2379
+ isOpen,
2380
+ onClose,
2381
+ onSubmitted,
2382
+ className
2383
+ }) {
2384
+ const { state, onEditField, onStartEdit, onSaveEdit, onCancelEdit, onSign } = useTaxDocument({ isOpen });
2385
+ useEffect8(() => {
2386
+ if (state.type === "SUBMITTED") {
2387
+ onSubmitted?.(state.submission);
2388
+ onClose();
2389
+ }
2390
+ }, [state]);
2391
+ if (!isOpen || state.type === "SUBMITTED") return null;
2392
+ return /* @__PURE__ */ jsx18("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__ */ jsxs14(
2393
+ "div",
2394
+ {
2395
+ className: cn(
2396
+ "clcosdk:flex clcosdk:w-full clcosdk:max-w-md clcosdk:flex-col clcosdk:gap-6 clcosdk:rounded-2xl clcosdk:bg-background clcosdk:p-6",
2397
+ className
2398
+ ),
2399
+ children: [
2400
+ /* @__PURE__ */ jsxs14("div", { className: "clcosdk:flex clcosdk:items-start clcosdk:justify-between clcosdk:gap-4", children: [
2401
+ /* @__PURE__ */ jsx18(TaxDocumentModalHeading, { state }),
2402
+ /* @__PURE__ */ jsx18(CloseButton, { onClick: onClose })
2403
+ ] }),
2404
+ state.type === "LOADING" && /* @__PURE__ */ jsx18(LoadingScreen, {}),
2405
+ state.type === "ERROR" && /* @__PURE__ */ jsx18(ErrorScreen, { reason: state.reason }),
2406
+ state.type === "REVIEW" && /* @__PURE__ */ jsx18(
2407
+ ReviewScreen,
2408
+ {
2409
+ fields: state.fields,
2410
+ piiUnavailable: state.piiUnavailable,
2411
+ sign: state.sign,
2412
+ onStartEdit,
2413
+ onSign
2414
+ }
2415
+ ),
2416
+ state.type === "EDITING" && /* @__PURE__ */ jsx18(
2417
+ EditScreen,
2418
+ {
2419
+ fields: state.fields,
2420
+ onEditField,
2421
+ onSaveEdit,
2422
+ onCancelEdit
2423
+ }
2424
+ ),
2425
+ state.type === "SIGN_ONLY" && /* @__PURE__ */ jsx18(SignOnlyScreen, { sign: state.sign, onSign })
2426
+ ]
2427
+ }
2428
+ ) });
2429
+ }
2430
+ function TaxDocumentModalHeading({
2431
+ state
2432
+ }) {
2433
+ 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";
2434
+ return /* @__PURE__ */ jsx18("h3", { className: cn(typeClasses.h3, "clcosdk:text-text-primary"), children: title });
2435
+ }
2436
+ function LoadingScreen() {
2437
+ return /* @__PURE__ */ jsx18(
2438
+ "output",
2439
+ {
2440
+ "aria-live": "polite",
2441
+ className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-4",
2442
+ children: FIELD_ROWS.map(({ field }) => /* @__PURE__ */ jsxs14(
2443
+ "div",
2444
+ {
2445
+ className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-1",
2446
+ children: [
2447
+ /* @__PURE__ */ jsx18("div", { className: "clcosdk:h-3 clcosdk:w-28 clcosdk:animate-pulse clcosdk:rounded clcosdk:bg-surface" }),
2448
+ /* @__PURE__ */ jsx18("div", { className: "clcosdk:h-5 clcosdk:w-48 clcosdk:animate-pulse clcosdk:rounded clcosdk:bg-surface" })
2449
+ ]
2450
+ },
2451
+ field
2452
+ ))
2453
+ }
2454
+ );
2455
+ }
2456
+ function ErrorScreen({
2457
+ reason
2458
+ }) {
2459
+ return /* @__PURE__ */ jsx18(
2460
+ AlertBanner,
2461
+ {
2462
+ variant: "error",
2463
+ icon: true,
2464
+ content: reason === "not-authenticated" ? "Sign in to complete your tax document." : "Unable to load your tax information right now. Please try again."
2465
+ }
2466
+ );
2467
+ }
2468
+ function ReviewScreen({
2469
+ fields,
2470
+ piiUnavailable,
2471
+ sign,
2472
+ onStartEdit,
2473
+ onSign
2474
+ }) {
2475
+ return /* @__PURE__ */ jsxs14("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-6", children: [
2476
+ /* @__PURE__ */ jsx18("p", { className: cn(typeClasses.body, "clcosdk:text-text-secondary"), children: "Review your information below. If anything looks incorrect, edit before signing." }),
2477
+ piiUnavailable && /* @__PURE__ */ jsx18(
2478
+ AlertBanner,
2479
+ {
2480
+ variant: "info",
2481
+ icon: true,
2482
+ content: "We don't have this information on file yet \u2014 please fill it in below."
2483
+ }
2484
+ ),
2485
+ /* @__PURE__ */ jsx18("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__ */ jsxs14(
2486
+ "div",
2487
+ {
2488
+ className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-1",
2489
+ children: [
2490
+ /* @__PURE__ */ jsx18(
2491
+ "span",
2492
+ {
2493
+ className: cn(typeClasses.label, "clcosdk:text-text-secondary"),
2494
+ children: label
2495
+ }
2496
+ ),
2497
+ /* @__PURE__ */ jsx18("span", { className: cn(typeClasses.body, "clcosdk:text-text-primary"), children: fields[field] || "\u2014" })
2498
+ ]
2499
+ },
2500
+ field
2501
+ )) }),
2502
+ /* @__PURE__ */ jsx18("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." }),
2503
+ sign.type === "idle" && sign.error && /* @__PURE__ */ jsx18(AlertBanner, { variant: "error", icon: true, content: sign.error }),
2504
+ /* @__PURE__ */ jsxs14("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-2", children: [
2505
+ /* @__PURE__ */ jsx18(
2506
+ ClButton,
2507
+ {
2508
+ fullWidth: true,
2509
+ onClick: onSign,
2510
+ isLoading: sign.type === "signing",
2511
+ loadingText: "Signing...",
2512
+ children: "Sign W-8BEN"
2513
+ }
2514
+ ),
2515
+ /* @__PURE__ */ jsx18(
2516
+ ClButton,
2517
+ {
2518
+ fullWidth: true,
2519
+ variant: "secondary",
2520
+ onClick: onStartEdit,
2521
+ disabled: sign.type === "signing",
2522
+ children: "Edit information"
2523
+ }
2524
+ )
2525
+ ] })
2526
+ ] });
2527
+ }
2528
+ function EditScreen({
2529
+ fields,
2530
+ onEditField,
2531
+ onSaveEdit,
2532
+ onCancelEdit
2533
+ }) {
2534
+ return /* @__PURE__ */ jsxs14("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-6", children: [
2535
+ /* @__PURE__ */ jsx18("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__ */ jsxs14(
2536
+ "label",
2537
+ {
2538
+ className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-1",
2539
+ children: [
2540
+ /* @__PURE__ */ jsx18(
2541
+ "span",
2542
+ {
2543
+ className: cn(typeClasses.label, "clcosdk:text-text-secondary"),
2544
+ children: label
2545
+ }
2546
+ ),
2547
+ /* @__PURE__ */ jsx18(
2548
+ "input",
2549
+ {
2550
+ type: "text",
2551
+ value: fields[field],
2552
+ placeholder,
2553
+ onChange: (e) => onEditField(field, e.target.value),
2554
+ className: cn(
2555
+ typeClasses.body,
2556
+ "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"
2557
+ )
2558
+ }
2559
+ )
2560
+ ]
2561
+ },
2562
+ field
2563
+ )) }),
2564
+ /* @__PURE__ */ jsxs14("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-2", children: [
2565
+ /* @__PURE__ */ jsx18(ClButton, { fullWidth: true, onClick: onSaveEdit, children: "Save & review" }),
2566
+ /* @__PURE__ */ jsx18(ClButton, { fullWidth: true, variant: "secondary", onClick: onCancelEdit, children: "Cancel" })
2567
+ ] })
2568
+ ] });
2569
+ }
2570
+ function SignOnlyScreen({
2571
+ sign,
2572
+ onSign
2573
+ }) {
2574
+ return /* @__PURE__ */ jsxs14("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-6", children: [
2575
+ /* @__PURE__ */ jsx18("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." }),
2576
+ sign.type === "idle" && sign.error && /* @__PURE__ */ jsx18(AlertBanner, { variant: "error", icon: true, content: sign.error }),
2577
+ /* @__PURE__ */ jsx18(
2578
+ ClButton,
2579
+ {
2580
+ fullWidth: true,
2581
+ onClick: onSign,
2582
+ isLoading: sign.type === "signing",
2583
+ loadingText: "Signing...",
2584
+ children: "Sign W-8BEN-E"
2585
+ }
2586
+ )
2587
+ ] });
2588
+ }
2589
+
2590
+ // src/client/hooks/useOptionAddresses.ts
2591
+ import { useCallback as useCallback4, useEffect as useEffect9, useState as useState7 } from "react";
2592
+ var LOADING_STATE4 = { type: "LOADING" };
2593
+ var EMPTY_STATE = {
2594
+ type: "CONTENT",
2595
+ addresses: []
2596
+ };
2597
+ function useOptionAddresses(offerId, offerOptionId, options = {}) {
2598
+ const { coinlist, isReady } = useCoinList();
2599
+ const { data, enabled = true } = options;
2600
+ const [addressesState, setAddressesState] = useState7(
2601
+ data !== void 0 ? { type: "CONTENT", addresses: data } : LOADING_STATE4
2602
+ );
2603
+ const [fetchKey, setFetchKey] = useState7(0);
2604
+ const refetch = useCallback4(() => setFetchKey((k) => k + 1), []);
2605
+ const disconnect = useCallback4(
2606
+ async (addressId) => {
2607
+ await coinlist.removeOptionAddress(offerId, addressId);
2608
+ refetch();
2609
+ },
2610
+ [coinlist, offerId, refetch]
2611
+ );
2612
+ useEffect9(() => {
2613
+ let isCancelled = false;
2614
+ if (!enabled) {
2615
+ setAddressesState(
2616
+ data !== void 0 ? { type: "CONTENT", addresses: data } : EMPTY_STATE
2617
+ );
2618
+ return () => {
2619
+ isCancelled = true;
2620
+ };
2621
+ }
2622
+ if (!isReady) {
2623
+ if (data === void 0) {
2624
+ setAddressesState(LOADING_STATE4);
2625
+ }
2626
+ return () => {
2627
+ isCancelled = true;
2628
+ };
2629
+ }
2630
+ if (data !== void 0 && fetchKey === 0) {
2631
+ return () => {
2632
+ isCancelled = true;
2633
+ };
2634
+ }
2635
+ if (coinlist.getAuthState() === "logged-out") {
2636
+ setAddressesState({ type: "ERROR", reason: "not-authenticated" });
2637
+ return () => {
2638
+ isCancelled = true;
2639
+ };
2640
+ }
2641
+ setAddressesState(LOADING_STATE4);
2642
+ coinlist.listOptionAddresses(offerId, offerOptionId).then((addresses) => {
2643
+ if (!isCancelled) {
2644
+ setAddressesState({ type: "CONTENT", addresses });
2645
+ }
2646
+ }).catch((error) => {
2647
+ if (!isCancelled) {
2648
+ const reason = error instanceof NotAuthenticatedError ? "not-authenticated" : "generic-error";
2649
+ setAddressesState({ type: "ERROR", reason });
2650
+ }
2651
+ });
2652
+ return () => {
2653
+ isCancelled = true;
2654
+ };
2655
+ }, [coinlist, isReady, enabled, offerId, offerOptionId, fetchKey]);
2656
+ return { addressesState, refetch, disconnect };
2657
+ }
1237
2658
 
1238
2659
  // src/client/hooks/useRequirements.ts
1239
- import { useCallback, useEffect as useEffect3, useState as useState3 } from "react";
1240
- var LOADING_STATE2 = { type: "LOADING" };
2660
+ import { useCallback as useCallback5, useEffect as useEffect10, useState as useState8 } from "react";
2661
+ var LOADING_STATE5 = { type: "LOADING" };
1241
2662
  function useRequirements(offerId, options = {}) {
1242
2663
  const { coinlist, isReady } = useCoinList();
1243
2664
  const { data } = options;
1244
- const [requirementsState, setRequirementsState] = useState3(
1245
- data !== void 0 ? { type: "CONTENT", ...data } : LOADING_STATE2
2665
+ const [requirementsState, setRequirementsState] = useState8(
2666
+ data !== void 0 ? { type: "CONTENT", ...data } : LOADING_STATE5
1246
2667
  );
1247
- const [fetchKey, setFetchKey] = useState3(0);
1248
- const refetch = useCallback(() => setFetchKey((k) => k + 1), []);
1249
- useEffect3(() => {
2668
+ const [fetchKey, setFetchKey] = useState8(0);
2669
+ const refetch = useCallback5(() => setFetchKey((k) => k + 1), []);
2670
+ useEffect10(() => {
1250
2671
  let isCancelled = false;
1251
2672
  if (!isReady) {
1252
2673
  if (data === void 0) {
1253
- setRequirementsState(LOADING_STATE2);
2674
+ setRequirementsState(LOADING_STATE5);
1254
2675
  }
1255
2676
  return () => {
1256
2677
  isCancelled = true;
@@ -1261,7 +2682,13 @@ function useRequirements(offerId, options = {}) {
1261
2682
  isCancelled = true;
1262
2683
  };
1263
2684
  }
1264
- setRequirementsState(LOADING_STATE2);
2685
+ if (coinlist.getAuthState() === "logged-out") {
2686
+ setRequirementsState({ type: "ERROR", reason: "not-authenticated" });
2687
+ return () => {
2688
+ isCancelled = true;
2689
+ };
2690
+ }
2691
+ setRequirementsState(LOADING_STATE5);
1265
2692
  Promise.all([
1266
2693
  coinlist.fetchOfferRequirements(offerId),
1267
2694
  coinlist.fetchRequirementStatuses(offerId)
@@ -1287,7 +2714,8 @@ function useRequirements(offerId, options = {}) {
1287
2714
  }
1288
2715
 
1289
2716
  // src/client/components/requirements/RequirementsChecklist.tsx
1290
- import { jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
2717
+ import { jsx as jsx19, jsxs as jsxs15 } from "react/jsx-runtime";
2718
+ var isWalletRequirement = (requirement) => RequirementVariant.fromType(requirement.type) === "wallet";
1291
2719
  var DEFAULT_LABELS = {
1292
2720
  kyc_approved: "KYC Verification",
1293
2721
  identity_verified: "Identity Verification",
@@ -1296,7 +2724,8 @@ var DEFAULT_LABELS = {
1296
2724
  external_wallet: "External Wallet",
1297
2725
  whitelisted_wallet: "Whitelisted Wallet",
1298
2726
  jurisdiction: "Jurisdiction Check",
1299
- accreditation: "Accreditation"
2727
+ accreditation: "Accreditation",
2728
+ document: "Document"
1300
2729
  };
1301
2730
  var DEFAULT_DESCRIPTIONS = {
1302
2731
  kyc_approved: "Complete Know Your Customer verification.",
@@ -1306,9 +2735,39 @@ var DEFAULT_DESCRIPTIONS = {
1306
2735
  external_wallet: "Connect an external wallet.",
1307
2736
  whitelisted_wallet: "Connect a whitelisted wallet.",
1308
2737
  jurisdiction: "Confirm your jurisdiction eligibility.",
1309
- accreditation: "Verify your accreditation status."
2738
+ accreditation: "Verify your accreditation status.",
2739
+ document: "Confirm your Tax Documents."
1310
2740
  };
1311
- function RequirementsChecklist({
2741
+ var VERIFICATION_POLL_INTERVAL_MS = 5e3;
2742
+ var VERIFICATION_POLL_TIMEOUT_MS = 12e4;
2743
+ function sleep(ms) {
2744
+ return new Promise((resolve) => setTimeout(resolve, ms));
2745
+ }
2746
+ function VerificationOverlay({
2747
+ onClose,
2748
+ children
2749
+ }) {
2750
+ return /* @__PURE__ */ jsx19(
2751
+ "div",
2752
+ {
2753
+ role: "dialog",
2754
+ "aria-modal": "true",
2755
+ "aria-label": "Identity verification",
2756
+ className: "clcosdk:fixed clcosdk:inset-0 clcosdk:z-50 clcosdk:flex clcosdk:items-center clcosdk:justify-center clcosdk:bg-overlay clcosdk:p-4",
2757
+ children: /* @__PURE__ */ jsxs15("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: [
2758
+ /* @__PURE__ */ jsx19(
2759
+ CloseButton,
2760
+ {
2761
+ onClick: onClose,
2762
+ className: "clcosdk:absolute clcosdk:top-4 clcosdk:right-4"
2763
+ }
2764
+ ),
2765
+ children
2766
+ ] })
2767
+ }
2768
+ );
2769
+ }
2770
+ function RequirementsChecklistBody({
1312
2771
  offerId,
1313
2772
  optionId,
1314
2773
  title,
@@ -1316,38 +2775,106 @@ function RequirementsChecklist({
1316
2775
  onContinue,
1317
2776
  onRequirementActionOverride,
1318
2777
  onContactSupportOverride,
2778
+ wallet,
2779
+ onRequestConnect,
1319
2780
  getLabel,
1320
2781
  getDescription,
1321
2782
  loading,
2783
+ unauthenticatedState,
1322
2784
  error,
1323
2785
  className,
1324
- data
2786
+ data,
2787
+ identityVerificationOptions
1325
2788
  }) {
1326
2789
  const { coinlist } = useCoinList();
1327
- const { requirementsState } = useRequirements(offerId, { data });
1328
- const [expandedIndex, setExpandedIndex] = useState4(null);
1329
- const onRequirementAction = onRequirementActionOverride !== void 0 ? onRequirementActionOverride : (requirement) => coinlist.handleRequirement(requirement);
2790
+ const { requirementsState, refetch } = useRequirements(offerId, { data });
2791
+ const [expandedIndex, setExpandedIndex] = useState9(null);
2792
+ const [taxDocumentOpen, setTaxDocumentOpen] = useState9(false);
2793
+ const [walletConnectOpen, setConnectWalletOpen] = useState9(false);
2794
+ const [verifyingRequirementId, setVerifyingRequirementId] = useState9(null);
2795
+ const isMountedRef = useRef4(true);
2796
+ useEffect11(() => {
2797
+ isMountedRef.current = true;
2798
+ return () => {
2799
+ isMountedRef.current = false;
2800
+ };
2801
+ }, []);
2802
+ const [hasWalletRequirement, setHasWalletRequirement] = useState9(false);
2803
+ useEffect11(() => {
2804
+ if (requirementsState.type === "CONTENT") {
2805
+ setHasWalletRequirement(
2806
+ (requirementsState.requirements[optionId] ?? []).some(
2807
+ isWalletRequirement
2808
+ )
2809
+ );
2810
+ }
2811
+ }, [requirementsState, optionId]);
2812
+ const {
2813
+ addressesState,
2814
+ refetch: refetchAddresses,
2815
+ disconnect
2816
+ } = useOptionAddresses(offerId, optionId, {
2817
+ enabled: hasWalletRequirement
2818
+ });
2819
+ const optionAddresses = addressesState.type === "CONTENT" ? addressesState.addresses : [];
2820
+ const walletsStatus = addressesState.type === "ERROR" ? "error" : addressesState.type === "LOADING" ? "loading" : "ready";
2821
+ const onRemoveWallet = async (id) => {
2822
+ await disconnect(OfferOptionAddressId(id));
2823
+ refetch();
2824
+ };
2825
+ const onRequirementAction = onRequirementActionOverride !== void 0 ? onRequirementActionOverride : (requirement) => {
2826
+ if (requirement.type === "document") {
2827
+ setTaxDocumentOpen(true);
2828
+ return;
2829
+ }
2830
+ if ((requirement.type === "external_wallet" || requirement.type === "whitelisted_wallet") && wallet !== void 0 && (wallet !== null || onRequestConnect !== void 0)) {
2831
+ setConnectWalletOpen(true);
2832
+ return;
2833
+ }
2834
+ coinlist.handleRequirement(requirement);
2835
+ };
1330
2836
  const onContactSupport = onContactSupportOverride !== void 0 ? onContactSupportOverride : () => coinlist.contactSupport();
2837
+ const awaitVerificationResult = (requirementId, statusBeforeSubmit) => {
2838
+ void (async () => {
2839
+ const deadline = Date.now() + VERIFICATION_POLL_TIMEOUT_MS;
2840
+ while (Date.now() < deadline) {
2841
+ await sleep(VERIFICATION_POLL_INTERVAL_MS);
2842
+ if (!isMountedRef.current) return;
2843
+ try {
2844
+ const statuses2 = await coinlist.fetchRequirementStatuses(offerId);
2845
+ const current = statuses2.find((s) => s.id === requirementId)?.status;
2846
+ if (current !== void 0 && current !== statusBeforeSubmit) break;
2847
+ } catch (_) {
2848
+ }
2849
+ }
2850
+ if (isMountedRef.current) {
2851
+ setVerifyingRequirementId(null);
2852
+ refetch();
2853
+ }
2854
+ })();
2855
+ };
1331
2856
  if (requirementsState.type === "LOADING") {
1332
2857
  if (loading) return loading;
1333
- return /* @__PURE__ */ jsx15(
2858
+ return /* @__PURE__ */ jsx19(
1334
2859
  "output",
1335
2860
  {
1336
2861
  "aria-live": "polite",
1337
2862
  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",
1338
- children: /* @__PURE__ */ jsx15("p", { className: cn(typeClasses.body, "clcosdk:text-text-secondary"), children: "Loading requirements..." })
2863
+ children: /* @__PURE__ */ jsx19("p", { className: cn(typeClasses.body, "clcosdk:text-text-secondary"), children: "Loading requirements..." })
1339
2864
  }
1340
2865
  );
1341
2866
  }
1342
2867
  if (requirementsState.type === "ERROR") {
2868
+ if (requirementsState.reason === "not-authenticated") {
2869
+ return unauthenticatedState !== void 0 ? unauthenticatedState : /* @__PURE__ */ jsx19(CoinListSignInCard, {});
2870
+ }
1343
2871
  if (error) return error;
1344
- const errorMessage = requirementsState.reason === "not-authenticated" ? "Sign in to view requirements." : "Unable to load requirements right now. Please try again.";
1345
- return /* @__PURE__ */ jsx15(
2872
+ return /* @__PURE__ */ jsx19(
1346
2873
  AlertBanner,
1347
2874
  {
1348
2875
  variant: "error",
1349
2876
  icon: true,
1350
- content: errorMessage,
2877
+ content: "Unable to load requirements right now. Please try again.",
1351
2878
  className: "clcosdk:w-full clcosdk:max-w-[28rem]"
1352
2879
  }
1353
2880
  );
@@ -1358,7 +2885,7 @@ function RequirementsChecklist({
1358
2885
  const optionStatuses = statuses.filter((s) => requirementIds.has(s.id));
1359
2886
  const statusByRequirementId = new Map(optionStatuses.map((s) => [s.id, s]));
1360
2887
  const checklistStatus = ChecklistStatus.derive(optionStatuses);
1361
- return /* @__PURE__ */ jsxs11(
2888
+ return /* @__PURE__ */ jsxs15(
1362
2889
  "div",
1363
2890
  {
1364
2891
  className: cn(
@@ -1366,17 +2893,20 @@ function RequirementsChecklist({
1366
2893
  className
1367
2894
  ),
1368
2895
  children: [
1369
- /* @__PURE__ */ jsxs11("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-2", children: [
1370
- /* @__PURE__ */ jsx15("h3", { className: cn(typeClasses.h3, "clcosdk:text-text-primary"), children: title }),
1371
- /* @__PURE__ */ jsx15("p", { className: cn(typeClasses.body, "clcosdk:text-text-secondary"), children: description })
2896
+ /* @__PURE__ */ jsxs15("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-2", children: [
2897
+ /* @__PURE__ */ jsx19("h3", { className: cn(typeClasses.h3, "clcosdk:text-text-primary"), children: title }),
2898
+ /* @__PURE__ */ jsx19("p", { className: cn(typeClasses.body, "clcosdk:text-text-secondary"), children: description })
1372
2899
  ] }),
1373
- /* @__PURE__ */ jsx15("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:divide-y clcosdk:divide-divider", children: requirements.map((req, index) => {
2900
+ /* @__PURE__ */ jsx19("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:divide-y clcosdk:divide-divider", children: requirements.map((req, index) => {
1374
2901
  const statusInfo = statusByRequirementId.get(req.id);
1375
2902
  const label = getLabel ? getLabel(req) : DEFAULT_LABELS[req.type];
1376
2903
  const itemDescription = (getDescription ? getDescription(req) : null) ?? DEFAULT_DESCRIPTIONS[req.type];
2904
+ const inlineVerification = statusInfo?.kycLevel !== void 0 && onRequirementActionOverride === void 0;
1377
2905
  let onActionBound;
1378
2906
  if (onRequirementAction === null) {
1379
2907
  onActionBound = null;
2908
+ } else if (inlineVerification) {
2909
+ onActionBound = () => setVerifyingRequirementId(req.id);
1380
2910
  } else if (onRequirementAction) {
1381
2911
  onActionBound = () => onRequirementAction(req);
1382
2912
  }
@@ -1386,24 +2916,28 @@ function RequirementsChecklist({
1386
2916
  } else if (onContactSupport) {
1387
2917
  onContactSupportBound = () => onContactSupport(req);
1388
2918
  }
1389
- return /* @__PURE__ */ jsx15(
2919
+ const walletRequirement = isWalletRequirement(req);
2920
+ return /* @__PURE__ */ jsx19(
1390
2921
  RequirementItem,
1391
2922
  {
1392
2923
  ui: RequirementItemUi.fromDomain(
1393
2924
  req,
1394
2925
  statusInfo,
1395
2926
  label,
1396
- itemDescription
2927
+ itemDescription,
2928
+ walletRequirement ? optionAddresses : []
1397
2929
  ),
1398
2930
  expanded: expandedIndex === index,
1399
2931
  onToggle: () => setExpandedIndex((prev) => prev === index ? null : index),
1400
2932
  onAction: onActionBound,
2933
+ onRemoveWallet: walletRequirement ? onRemoveWallet : void 0,
2934
+ walletsStatus: walletRequirement ? walletsStatus : void 0,
1401
2935
  onContactSupport: onContactSupportBound
1402
2936
  },
1403
2937
  req.id
1404
2938
  );
1405
2939
  }) }),
1406
- checklistStatus === "ineligible" && /* @__PURE__ */ jsx15(
2940
+ checklistStatus === "ineligible" && /* @__PURE__ */ jsx19(
1407
2941
  AlertBanner,
1408
2942
  {
1409
2943
  variant: "error",
@@ -1411,7 +2945,7 @@ function RequirementsChecklist({
1411
2945
  content: "You are not eligible to participate."
1412
2946
  }
1413
2947
  ),
1414
- onContinue && /* @__PURE__ */ jsx15(
2948
+ onContinue && /* @__PURE__ */ jsx19(
1415
2949
  ClButton,
1416
2950
  {
1417
2951
  fullWidth: true,
@@ -1419,24 +2953,242 @@ function RequirementsChecklist({
1419
2953
  onClick: onContinue,
1420
2954
  children: "Continue"
1421
2955
  }
2956
+ ),
2957
+ /* @__PURE__ */ jsx19(
2958
+ TaxDocumentModal,
2959
+ {
2960
+ isOpen: taxDocumentOpen,
2961
+ onClose: () => setTaxDocumentOpen(false),
2962
+ onSubmitted: () => refetch()
2963
+ }
2964
+ ),
2965
+ verifyingRequirementId !== null && /* @__PURE__ */ jsx19(VerificationOverlay, { onClose: () => setVerifyingRequirementId(null), children: /* @__PURE__ */ jsx19(
2966
+ IdentityVerification,
2967
+ {
2968
+ levelName: identityVerificationOptions?.levelName ?? statusByRequirementId.get(verifyingRequirementId)?.kycLevel,
2969
+ reset: statusByRequirementId.get(verifyingRequirementId)?.kycReset ?? false,
2970
+ locale: identityVerificationOptions?.locale,
2971
+ onSubmitted: () => awaitVerificationResult(
2972
+ verifyingRequirementId,
2973
+ statusByRequirementId.get(verifyingRequirementId)?.status ?? "not_started"
2974
+ )
2975
+ }
2976
+ ) }),
2977
+ /* @__PURE__ */ jsx19(
2978
+ ConnectWalletModal,
2979
+ {
2980
+ isOpen: walletConnectOpen,
2981
+ onClose: () => setConnectWalletOpen(false),
2982
+ offerId,
2983
+ optionId,
2984
+ wallet: wallet ?? null,
2985
+ onRequestConnect,
2986
+ onConnected: () => {
2987
+ refetch();
2988
+ refetchAddresses();
2989
+ }
2990
+ }
1422
2991
  )
1423
2992
  ]
1424
2993
  }
1425
2994
  );
1426
2995
  }
2996
+ function RequirementsChecklist(props) {
2997
+ return /* @__PURE__ */ jsx19(CoinListStyleScope, { children: /* @__PURE__ */ jsx19(RequirementsChecklistBody, { ...props }) });
2998
+ }
2999
+
3000
+ // src/client/hooks/swap/useSwapOutputToken.ts
3001
+ import { useEffect as useEffect12, useRef as useRef5, useState as useState10 } from "react";
3002
+ var LOADING_STATE6 = { type: "LOADING" };
3003
+ function useSwapOutputToken(options) {
3004
+ const { contractAddress, chain, enabled } = options;
3005
+ const { coinlist, isReady } = useCoinList();
3006
+ const [outputTokenState, setOutputTokenState] = useState10(LOADING_STATE6);
3007
+ const fetchIdRef = useRef5(0);
3008
+ useEffect12(() => {
3009
+ if (!enabled || !isReady) return;
3010
+ const currentFetchId = ++fetchIdRef.current;
3011
+ const load = async () => {
3012
+ try {
3013
+ const outputToken = await coinlist.swap.getOutputToken({
3014
+ contractAddress,
3015
+ chain
3016
+ });
3017
+ if (currentFetchId !== fetchIdRef.current) return;
3018
+ setOutputTokenState({ type: "CONTENT", outputToken });
3019
+ } catch {
3020
+ if (currentFetchId !== fetchIdRef.current) return;
3021
+ setOutputTokenState({ type: "ERROR" });
3022
+ }
3023
+ };
3024
+ load();
3025
+ return () => {
3026
+ ++fetchIdRef.current;
3027
+ };
3028
+ }, [coinlist, isReady, contractAddress, chain, enabled]);
3029
+ return { outputTokenState };
3030
+ }
3031
+
3032
+ // src/client/hooks/swap/useSwapQuote.ts
3033
+ import { useEffect as useEffect13, useRef as useRef6, useState as useState11 } from "react";
3034
+ function useSwapQuote(options) {
3035
+ const {
3036
+ contractAddress,
3037
+ chain,
3038
+ inputAmount,
3039
+ inputTokenAddress,
3040
+ outputTokenDecimals,
3041
+ pollIntervalMs = SWAP_POLL_INTERVAL_MS,
3042
+ enabled
3043
+ } = options;
3044
+ const { coinlist, isReady } = useCoinList();
3045
+ const [quote, setQuote] = useState11(null);
3046
+ const [isLoading, setIsLoading] = useState11(true);
3047
+ const [isRefreshing, setIsRefreshing] = useState11(false);
3048
+ const isFetchingRef = useRef6(false);
3049
+ const hasQuoteRef = useRef6(false);
3050
+ const fetchIdRef = useRef6(0);
3051
+ useEffect13(() => {
3052
+ if (!isReady) return;
3053
+ if (!enabled) {
3054
+ setIsLoading(false);
3055
+ return;
3056
+ }
3057
+ const currentFetchId = ++fetchIdRef.current;
3058
+ isFetchingRef.current = false;
3059
+ const loadQuote = async () => {
3060
+ if (outputTokenDecimals === null) return;
3061
+ if (isFetchingRef.current) return;
3062
+ isFetchingRef.current = true;
3063
+ if (hasQuoteRef.current) {
3064
+ setIsRefreshing(true);
3065
+ }
3066
+ try {
3067
+ const preview = await coinlist.swap.getPreview({
3068
+ contractAddress,
3069
+ chain,
3070
+ inputToken: inputTokenAddress,
3071
+ amount: inputAmount.raw
3072
+ });
3073
+ if (currentFetchId !== fetchIdRef.current) return;
3074
+ setQuote(
3075
+ SwapQuote.fromPreview(
3076
+ preview,
3077
+ inputAmount.decimals,
3078
+ outputTokenDecimals
3079
+ )
3080
+ );
3081
+ if (!hasQuoteRef.current) {
3082
+ hasQuoteRef.current = true;
3083
+ setIsLoading(false);
3084
+ }
3085
+ } catch {
3086
+ } finally {
3087
+ if (currentFetchId === fetchIdRef.current) {
3088
+ isFetchingRef.current = false;
3089
+ setIsRefreshing(false);
3090
+ }
3091
+ }
3092
+ };
3093
+ loadQuote();
3094
+ const interval = setInterval(loadQuote, pollIntervalMs);
3095
+ return () => {
3096
+ clearInterval(interval);
3097
+ ++fetchIdRef.current;
3098
+ setIsRefreshing(false);
3099
+ };
3100
+ }, [
3101
+ coinlist,
3102
+ isReady,
3103
+ contractAddress,
3104
+ chain,
3105
+ inputAmount.raw,
3106
+ inputAmount.decimals,
3107
+ inputTokenAddress,
3108
+ outputTokenDecimals,
3109
+ pollIntervalMs,
3110
+ enabled
3111
+ ]);
3112
+ return { quote, isLoading, isRefreshing };
3113
+ }
3114
+
3115
+ // src/client/hooks/swap/useSwapTokenBalances.ts
3116
+ import { useEffect as useEffect14, useRef as useRef7, useState as useState12 } from "react";
3117
+ function useSwapTokenBalances(options) {
3118
+ const {
3119
+ address,
3120
+ chain,
3121
+ assets,
3122
+ pollIntervalMs = SWAP_POLL_INTERVAL_MS,
3123
+ enabled
3124
+ } = options;
3125
+ const { coinlist, isReady } = useCoinList();
3126
+ const [balances, setBalances] = useState12(/* @__PURE__ */ new Map());
3127
+ const [isLoading, setIsLoading] = useState12(true);
3128
+ const fetchIdRef = useRef7(0);
3129
+ const isFetchingRef = useRef7(false);
3130
+ const assetsKey = assets.join(",");
3131
+ useEffect14(() => {
3132
+ if (!isReady) return;
3133
+ if (!enabled) {
3134
+ setIsLoading(false);
3135
+ return;
3136
+ }
3137
+ const symbols = assetsKey.split(",");
3138
+ const currentFetchId = ++fetchIdRef.current;
3139
+ isFetchingRef.current = false;
3140
+ let isFirstFetch = true;
3141
+ async function fetchBalances() {
3142
+ if (isFetchingRef.current) return;
3143
+ isFetchingRef.current = true;
3144
+ if (isFirstFetch) {
3145
+ setIsLoading(true);
3146
+ }
3147
+ const results = await Promise.allSettled(
3148
+ symbols.map(
3149
+ (symbol) => coinlist.swap.getTokenBalance({
3150
+ tokenAddress: TOKEN_REGISTRY.contractAddress(symbol, chain),
3151
+ owner: address,
3152
+ chain
3153
+ })
3154
+ )
3155
+ );
3156
+ if (currentFetchId !== fetchIdRef.current) return;
3157
+ isFetchingRef.current = false;
3158
+ const next = /* @__PURE__ */ new Map();
3159
+ symbols.forEach((symbol, i) => {
3160
+ const result = results[i];
3161
+ next.set(
3162
+ symbol,
3163
+ result.status === "fulfilled" ? result.value.balance : null
3164
+ );
3165
+ });
3166
+ setBalances(next);
3167
+ setIsLoading(false);
3168
+ isFirstFetch = false;
3169
+ }
3170
+ fetchBalances();
3171
+ const interval = setInterval(fetchBalances, pollIntervalMs);
3172
+ return () => {
3173
+ clearInterval(interval);
3174
+ ++fetchIdRef.current;
3175
+ };
3176
+ }, [coinlist, isReady, address, chain, assetsKey, pollIntervalMs, enabled]);
3177
+ return { balances, isLoading };
3178
+ }
1427
3179
 
1428
3180
  // src/client/hooks/useCompleteOAuth.ts
1429
- import { useEffect as useEffect4, useRef } from "react";
3181
+ import { useEffect as useEffect15, useRef as useRef8 } from "react";
1430
3182
  function useCompleteOAuth(options) {
1431
3183
  const { coinlist } = useCoinList();
1432
- const postOAuthCompleteRef = useRef(options.postOAuthComplete);
1433
- const onFailureRef = useRef(options.onFailure);
1434
- const onSuccessRef = useRef(options.onSuccess);
3184
+ const postOAuthCompleteRef = useRef8(options.postOAuthComplete);
3185
+ const onFailureRef = useRef8(options.onFailure);
3186
+ const onSuccessRef = useRef8(options.onSuccess);
1435
3187
  postOAuthCompleteRef.current = options.postOAuthComplete;
1436
3188
  onFailureRef.current = options.onFailure;
1437
3189
  onSuccessRef.current = options.onSuccess;
1438
- const hasStartedExchangeRef = useRef(false);
1439
- useEffect4(() => {
3190
+ const hasStartedExchangeRef = useRef8(false);
3191
+ useEffect15(() => {
1440
3192
  if (typeof window === "undefined") return;
1441
3193
  const params = new URLSearchParams(window.location.search);
1442
3194
  if (!params.has("code") && !params.has("error")) return;
@@ -1480,19 +3232,19 @@ function useCompleteOAuth(options) {
1480
3232
  }
1481
3233
 
1482
3234
  // src/client/hooks/useOfferDetails.ts
1483
- import { useEffect as useEffect5, useState as useState5 } from "react";
1484
- var LOADING_STATE3 = { type: "LOADING" };
3235
+ import { useEffect as useEffect16, useState as useState13 } from "react";
3236
+ var LOADING_STATE7 = { type: "LOADING" };
1485
3237
  function useOfferDetails(offerId, options = {}) {
1486
3238
  const { coinlist, isReady } = useCoinList();
1487
3239
  const { data } = options;
1488
- const [offerDetailsState, setOfferDetailsState] = useState5(
1489
- data !== void 0 ? { type: "CONTENT", offerDetail: data } : LOADING_STATE3
3240
+ const [offerDetailsState, setOfferDetailsState] = useState13(
3241
+ data !== void 0 ? { type: "CONTENT", offerDetail: data } : LOADING_STATE7
1490
3242
  );
1491
- useEffect5(() => {
3243
+ useEffect16(() => {
1492
3244
  let isCancelled = false;
1493
3245
  if (!isReady) {
1494
3246
  if (data === void 0) {
1495
- setOfferDetailsState(LOADING_STATE3);
3247
+ setOfferDetailsState(LOADING_STATE7);
1496
3248
  }
1497
3249
  return () => {
1498
3250
  isCancelled = true;
@@ -1503,7 +3255,7 @@ function useOfferDetails(offerId, options = {}) {
1503
3255
  isCancelled = true;
1504
3256
  };
1505
3257
  }
1506
- setOfferDetailsState(LOADING_STATE3);
3258
+ setOfferDetailsState(LOADING_STATE7);
1507
3259
  coinlist.fetchOfferDetails(offerId).then((offerDetail) => {
1508
3260
  if (!isCancelled) {
1509
3261
  setOfferDetailsState({ type: "CONTENT", offerDetail });
@@ -1522,19 +3274,19 @@ function useOfferDetails(offerId, options = {}) {
1522
3274
  }
1523
3275
 
1524
3276
  // src/client/hooks/useParticipations.ts
1525
- import { useEffect as useEffect6, useState as useState6 } from "react";
1526
- var LOADING_STATE4 = { type: "LOADING" };
3277
+ import { useEffect as useEffect17, useState as useState14 } from "react";
3278
+ var LOADING_STATE8 = { type: "LOADING" };
1527
3279
  function useParticipations(offerId, options = {}) {
1528
3280
  const { coinlist, isReady } = useCoinList();
1529
3281
  const { data } = options;
1530
- const [participationsState, setParticipationsState] = useState6(
1531
- data !== void 0 ? { type: "CONTENT", participations: data } : LOADING_STATE4
3282
+ const [participationsState, setParticipationsState] = useState14(
3283
+ data !== void 0 ? { type: "CONTENT", participations: data } : LOADING_STATE8
1532
3284
  );
1533
- useEffect6(() => {
3285
+ useEffect17(() => {
1534
3286
  let isCancelled = false;
1535
3287
  if (!isReady) {
1536
3288
  if (data === void 0) {
1537
- setParticipationsState(LOADING_STATE4);
3289
+ setParticipationsState(LOADING_STATE8);
1538
3290
  }
1539
3291
  return () => {
1540
3292
  isCancelled = true;
@@ -1545,7 +3297,7 @@ function useParticipations(offerId, options = {}) {
1545
3297
  isCancelled = true;
1546
3298
  };
1547
3299
  }
1548
- setParticipationsState(LOADING_STATE4);
3300
+ setParticipationsState(LOADING_STATE8);
1549
3301
  coinlist.fetchParticipations(offerId).then((participations) => {
1550
3302
  if (!isCancelled) {
1551
3303
  setParticipationsState({ type: "CONTENT", participations });
@@ -1564,12 +3316,17 @@ function useParticipations(offerId, options = {}) {
1564
3316
  }
1565
3317
  export {
1566
3318
  ChecklistStatus,
3319
+ ClientSwapNamespaceImpl,
1567
3320
  CoinListClientInitializationError,
1568
3321
  CoinListContext,
1569
3322
  CoinListContextProvider,
1570
3323
  CoinListProvider,
1571
3324
  CoinListSignInCard,
1572
3325
  CoinListStyleScope,
3326
+ ConnectWalletModal,
3327
+ ConnectedWalletList,
3328
+ IdentityVerification,
3329
+ KycToken,
1573
3330
  OAUTH_CODE_VERIFIER_KEY,
1574
3331
  OAUTH_STATE_KEY,
1575
3332
  OfferCard,
@@ -1580,12 +3337,24 @@ export {
1580
3337
  RequirementStatus,
1581
3338
  RequirementVariant,
1582
3339
  RequirementsChecklist,
3340
+ TaxDocumentModal,
3341
+ authorizeWallet,
3342
+ classifyWalletError,
3343
+ connectExternalWalletFlow,
1583
3344
  createCoinListClient,
3345
+ executeSwap,
1584
3346
  useCoinList,
1585
3347
  useCompleteOAuth,
3348
+ useConnectWallet,
3349
+ useKycToken,
1586
3350
  useOfferDetails,
1587
3351
  useOffers,
3352
+ useOptionAddresses,
1588
3353
  useParticipations,
1589
- useRequirements
3354
+ useRequirements,
3355
+ useSwapOutputToken,
3356
+ useSwapQuote,
3357
+ useSwapTokenBalances,
3358
+ useTaxDocument
1590
3359
  };
1591
3360
  //# sourceMappingURL=index.js.map