@stridge/kit 0.1.0-alpha.2 → 0.1.0-alpha.21

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 (132) hide show
  1. package/README.md +17 -3
  2. package/dist/KitProvider.d.ts +13 -0
  3. package/dist/KitProvider.js +1 -1
  4. package/dist/_internal/withdraw/driver/index.d.ts +2 -2
  5. package/dist/drivers/stridge/createStridgeDepositDriver.js +1 -1
  6. package/dist/drivers/stridge/createStridgeWithdrawDriver.d.ts +10 -12
  7. package/dist/drivers/stridge/createStridgeWithdrawDriver.js +1 -1
  8. package/dist/drivers/stridge/internal/metadata.js +1 -1
  9. package/dist/drivers/stridge/types.d.ts +7 -4
  10. package/dist/drivers/stridge-mock/createStridgeMockWithdrawDriver.d.ts +2 -2
  11. package/dist/drivers/stridge-mock/createStridgeMockWithdrawDriver.js +1 -1
  12. package/dist/drivers/stridge-mock/fixtures.d.ts +1 -1
  13. package/dist/drivers/stridge-mock/fixtures.js +1 -1
  14. package/dist/flows/deposit/dialog/DepositDialog.js +1 -1
  15. package/dist/flows/deposit/orchestrator/controller.js +1 -1
  16. package/dist/flows/deposit/widgets/deposit/Deposit.js +1 -1
  17. package/dist/flows/deposit/widgets/deposit-status-banner/DepositStatusBanner.js +1 -1
  18. package/dist/flows/deposit/widgets/deposit-status-banner/compound/DepositStatusBanner.js +1 -1
  19. package/dist/flows/deposit/widgets/transfer-crypto/compound/components/Address.js +1 -1
  20. package/dist/flows/deposit/widgets/transfer-crypto/compound/components/Disclosure.d.ts +2 -1
  21. package/dist/flows/deposit/widgets/transfer-crypto/compound/components/Disclosure.js +1 -1
  22. package/dist/flows/deposit/widgets/transfer-crypto/compound/components/QrCode.js +1 -1
  23. package/dist/flows/shared/transformers/pickRelevantSettlement.js +1 -1
  24. package/dist/flows/withdraw/bindings/WithdrawBindings.d.ts +92 -0
  25. package/dist/flows/withdraw/bindings/WithdrawBindings.js +1 -0
  26. package/dist/flows/withdraw/bindings/index.d.ts +1 -0
  27. package/dist/flows/withdraw/bindings/index.js +1 -0
  28. package/dist/flows/withdraw/dialog/WithdrawDialog.d.ts +57 -11
  29. package/dist/flows/withdraw/dialog/WithdrawDialog.js +1 -1
  30. package/dist/flows/withdraw/driver/payloads.d.ts +10 -1
  31. package/dist/flows/withdraw/driver/transformers/supportedAssetsToReceiveOptionsPayload.js +1 -1
  32. package/dist/flows/withdraw/driver/types.d.ts +53 -11
  33. package/dist/flows/withdraw/orchestrator/controller.js +1 -1
  34. package/dist/flows/withdraw/orchestrator/reducer.js +1 -1
  35. package/dist/flows/withdraw/orchestrator/types.d.ts +106 -31
  36. package/dist/flows/withdraw/widgets/withdraw-form/WithdrawForm.js +1 -1
  37. package/dist/flows/withdraw/widgets/withdraw-form/compound/WithdrawForm.js +1 -1
  38. package/dist/flows/withdraw/widgets/withdraw-form/compound/components/RecipientField.d.ts +7 -5
  39. package/dist/flows/withdraw/widgets/withdraw-form/compound/components/RecipientField.js +1 -1
  40. package/dist/flows/withdraw/widgets/withdraw-form/compound/types.d.ts +15 -5
  41. package/dist/flows/withdraw/widgets/withdraw-form/validation.js +1 -1
  42. package/dist/i18n/index.d.ts +5 -4
  43. package/dist/i18n/index.js +1 -1
  44. package/dist/i18n/locales/ar.js +1 -1
  45. package/dist/i18n/locales/es.js +1 -1
  46. package/dist/i18n/locales/source-keys.d.ts +12 -0
  47. package/dist/i18n/locales/source-keys.js +0 -0
  48. package/dist/icons/index.d.ts +2 -1
  49. package/dist/icons/index.js +1 -1
  50. package/dist/index.d.ts +7 -4
  51. package/dist/index.js +1 -1
  52. package/dist/package.js +1 -0
  53. package/dist/scope/KitPortalScope.js +1 -1
  54. package/dist/scope/KitScope.d.ts +18 -1
  55. package/dist/scope/KitScope.js +1 -1
  56. package/dist/scope/context.d.ts +17 -1
  57. package/dist/scope/index.d.ts +1 -1
  58. package/dist/shared/attribution/Attribution.js +1 -0
  59. package/dist/shared/attribution/Attribution.slots.js +1 -0
  60. package/dist/shared/attribution/Attribution.styles.js +1 -0
  61. package/dist/shared/attribution/index.js +1 -0
  62. package/dist/shared/chains/index.d.ts +48 -1
  63. package/dist/shared/chains/index.js +1 -1
  64. package/dist/shared/constants/brand-intercom.js +1 -0
  65. package/dist/shared/cuer/Cuer.js +1 -0
  66. package/dist/shared/cuer/QrCode.js +1 -0
  67. package/dist/shared/cuer/index.js +1 -0
  68. package/dist/shared/dialog/Frame.js +1 -1
  69. package/dist/shared/dialog/StepTransition.js +1 -1
  70. package/dist/shared/driver/types.d.ts +4 -3
  71. package/dist/shared/format/shortenAddress.d.ts +2 -2
  72. package/dist/shared/format/types.d.ts +2 -2
  73. package/dist/shared/i18n/KitI18nProvider.d.ts +11 -8
  74. package/dist/shared/i18n/KitI18nProvider.js +1 -1
  75. package/dist/shared/i18n/createKitI18n.d.ts +79 -16
  76. package/dist/shared/i18n/createKitI18n.js +1 -1
  77. package/dist/shared/i18n/useLingui.d.ts +11 -3
  78. package/dist/shared/icons/LogoIcon.d.ts +13 -0
  79. package/dist/shared/icons/LogoIcon.js +1 -0
  80. package/dist/shared/orchestrator/useSettlementWatcher.js +1 -1
  81. package/dist/shared/primitives/TxHashValue/TxHashValue.js +1 -1
  82. package/dist/shared/support/SupportButton.d.ts +1 -0
  83. package/dist/shared/support/SupportButton.js +1 -0
  84. package/dist/shared/support/SupportConfigContext.d.ts +1 -0
  85. package/dist/shared/support/SupportConfigContext.js +1 -0
  86. package/dist/shared/support/SupportLink.d.ts +1 -0
  87. package/dist/shared/support/SupportLink.js +1 -0
  88. package/dist/shared/support/SupportSpinner.d.ts +1 -0
  89. package/dist/shared/support/SupportSpinner.js +1 -0
  90. package/dist/shared/support/index.d.ts +2 -0
  91. package/dist/shared/support/index.js +1 -0
  92. package/dist/shared/support/intercom-loader.d.ts +17 -0
  93. package/dist/shared/support/intercom-loader.js +1 -0
  94. package/dist/shared/support/resolveSupport.d.ts +1 -0
  95. package/dist/shared/support/resolveSupport.js +1 -0
  96. package/dist/shared/support/types.d.ts +43 -0
  97. package/dist/shared/support/useIntercomMerchantContext.d.ts +27 -0
  98. package/dist/shared/support/useIntercomMerchantContext.js +1 -0
  99. package/dist/shared/support/useIntercomShutdownOnUnmount.js +1 -0
  100. package/dist/shared/support/useMerchantContext.d.ts +1 -0
  101. package/dist/shared/support/useMerchantContext.js +1 -0
  102. package/dist/shared/support/useSupportTrigger.js +1 -0
  103. package/dist/shared/ui/Card/Card.styles.js +1 -1
  104. package/dist/shared/ui/Details/Details.d.ts +10 -2
  105. package/dist/shared/ui/Details/Details.styles.js +1 -1
  106. package/dist/shared/ui/Dialog/Dialog.js +1 -1
  107. package/dist/shared/ui/Dialog/Dialog.styles.js +1 -1
  108. package/dist/shared/ui/ExternalLink/ExternalLink.js +1 -1
  109. package/dist/shared/ui/Select/Select.js +1 -1
  110. package/dist/shared/ui/WalletRow/WalletRow.d.ts +1 -1
  111. package/dist/shared/ui/WalletRow/WalletRow.js +1 -1
  112. package/dist/shared/widgets/confirm-transfer/compound/components/Disclaimer.js +1 -1
  113. package/dist/shared/widgets/confirm-transfer/compound/types.d.ts +1 -1
  114. package/dist/shared/widgets/error-state/compound/components/AssetValue.js +1 -1
  115. package/dist/shared/widgets/error-state/compound/components/HelpInfo.js +1 -1
  116. package/dist/shared/widgets/error-state/compound/components/StatusValue.js +1 -1
  117. package/dist/shared/widgets/processing-state/compound/components/Rows.js +1 -1
  118. package/dist/shared/widgets/success-state/compound/components/Actions.js +1 -1
  119. package/dist/shared/widgets/success-state/compound/components/AssetValue.js +1 -1
  120. package/dist/shared/widgets/success-state/compound/components/RouteValue.js +1 -1
  121. package/dist/shared/widgets/success-state/compound/components/StatusPill.js +1 -1
  122. package/dist/stridge/StridgeProvider.d.ts +88 -4
  123. package/dist/stridge/StridgeProvider.js +1 -1
  124. package/dist/stridge/optionalWagmi.js +1 -0
  125. package/dist/stridge/stubs.js +1 -1
  126. package/dist/styles/index.css +58 -12
  127. package/dist/types.d.ts +3 -2
  128. package/dist/ui/index.js +1 -1
  129. package/dist/withdraw/dialog/index.d.ts +3 -1
  130. package/package.json +10 -11
  131. package/dist/kit/package.js +0 -1
  132. /package/dist/{utils/src/use-copy-to-clipboard.js → shared/utils/useCopyToClipboard.js} +0 -0
@@ -5,7 +5,8 @@ import * as _$react_jsx_runtime0 from "react/jsx-runtime";
5
5
  /**
6
6
  * Disclosure part — collapsible footer surfacing the rough processing-time
7
7
  * hint as the trigger and the "Have questions?" help row inside the panel.
8
- * The help row always renders and links to {@link BRAND_LINKS.support}.
8
+ * The help row always renders and opens the Stridge messenger via
9
+ * {@link SupportLink}.
9
10
  */
10
11
  declare function TransferCryptoDisclosure({
11
12
  defaultOpen,
@@ -1 +1 @@
1
- "use client";import{useLingui as e}from"../../../../../../shared/i18n/useLingui.js";import"../../../../../../i18n/index.js";import{ChevronDownIcon as t}from"../../../../../../shared/icons/ChevronDownIcon.js";import{CircleHelpIcon as n}from"../../../../../../shared/icons/CircleHelpIcon.js";import{ClockIcon as r}from"../../../../../../shared/icons/ClockIcon.js";import"../../../../../../icons/index.js";import{Card as i}from"../../../../../../shared/ui/Card/Card.js";import{Collapsible as a}from"../../../../../../shared/ui/Collapsible/Collapsible.js";import"../../../../../../shared/ui/Collapsible/index.js";import{ExternalLink as o}from"../../../../../../shared/ui/ExternalLink/ExternalLink.js";import"../../../../../../shared/ui/ExternalLink/index.js";import{text as s}from"../../../../../../shared/ui/Text/Text.js";import"../../../../../../ui/index.js";import{BRAND_LINKS as c}from"../../../../../../shared/constants/brand-links.js";import{TRANSFER_CRYPTO_SLOTS as l}from"../TransferCrypto.slots.js";import{styles as u}from"../TransferCrypto.styles.js";import{jsx as d,jsxs as f}from"react/jsx-runtime";import*as p from"@stylexjs/stylex";function m({defaultOpen:m=!1,open:h,onOpenChange:g,processingTime:_}){let{_:v}=e(),y=_??v({id:`KuqCAK`,message:`~ 2 min`});return f(a,{"data-stridge-slot":l.disclosure,defaultOpen:m,open:h,onOpenChange:g,render:d(i,{variant:`subdued`}),...p.props(u.disclosure),children:[f(a.Trigger,{render:d(`div`,{}),nativeButton:!1,...p.props(u.disclosureHeader),children:[d(r,{"aria-hidden":!0,...p.props(u.disclosureRowIcon)}),d(`div`,{...p.props(u.disclosureRowTextWithInfo),children:d(s.span,{size:`meta`,fontWeight:`medium`,leading:`tight`,children:v({id:`7evBec`,message:`Processing time: {resolvedProcessingTime}`,values:{resolvedProcessingTime:y}})})}),d(t,{"aria-hidden":!0,...p.props(u.disclosureChevron,u.disclosureHeaderChevron)})]}),d(a.Panel,{children:d(`div`,{...p.props(u.disclosurePanelInner),children:f(`div`,{...p.props(u.disclosureRow),children:[d(n,{"aria-hidden":!0,...p.props(u.disclosureRowIcon)}),f(`div`,{children:[d(s.span,{size:`meta`,fontWeight:`medium`,leading:`tight`,...p.props(u.helpQuestion),children:v({id:`QU2cIs`,message:`Have questions?`})}),d(o,{href:c.support,...p.props(u.helpLink),children:d(s.span,{size:`meta`,fontWeight:`medium`,leading:`tight`,color:`inherit`,children:v({id:`AWtGgd`,message:`Get help`})})})]})]})})})]})}export{m as TransferCryptoDisclosure};
1
+ "use client";import{useLingui as e}from"../../../../../../shared/i18n/useLingui.js";import"../../../../../../i18n/index.js";import{ChevronDownIcon as t}from"../../../../../../shared/icons/ChevronDownIcon.js";import{CircleHelpIcon as n}from"../../../../../../shared/icons/CircleHelpIcon.js";import{ClockIcon as r}from"../../../../../../shared/icons/ClockIcon.js";import"../../../../../../icons/index.js";import{SupportLink as i}from"../../../../../../shared/support/SupportLink.js";import"../../../../../../shared/support/index.js";import{Card as a}from"../../../../../../shared/ui/Card/Card.js";import{Collapsible as o}from"../../../../../../shared/ui/Collapsible/Collapsible.js";import"../../../../../../shared/ui/Collapsible/index.js";import{text as s}from"../../../../../../shared/ui/Text/Text.js";import"../../../../../../ui/index.js";import{TRANSFER_CRYPTO_SLOTS as c}from"../TransferCrypto.slots.js";import{styles as l}from"../TransferCrypto.styles.js";import{jsx as u,jsxs as d}from"react/jsx-runtime";import*as f from"@stylexjs/stylex";function p({defaultOpen:p=!1,open:m,onOpenChange:h,processingTime:g}){let{_}=e(),v=g??_({id:`KuqCAK`,message:`~ 2 min`});return d(o,{"data-stridge-slot":c.disclosure,defaultOpen:p,open:m,onOpenChange:h,render:u(a,{variant:`subdued`}),...f.props(l.disclosure),children:[d(o.Trigger,{render:u(`div`,{}),nativeButton:!1,...f.props(l.disclosureHeader),children:[u(r,{"aria-hidden":!0,...f.props(l.disclosureRowIcon)}),u(`div`,{...f.props(l.disclosureRowTextWithInfo),children:u(s.span,{size:`meta`,fontWeight:`medium`,leading:`tight`,children:_({id:`7evBec`,message:`Processing time: {resolvedProcessingTime}`,values:{resolvedProcessingTime:v}})})}),u(t,{"aria-hidden":!0,...f.props(l.disclosureChevron,l.disclosureHeaderChevron)})]}),u(o.Panel,{children:u(`div`,{...f.props(l.disclosurePanelInner),children:d(`div`,{...f.props(l.disclosureRow),children:[u(n,{"aria-hidden":!0,...f.props(l.disclosureRowIcon)}),d(`div`,{children:[u(s.span,{size:`meta`,fontWeight:`medium`,leading:`tight`,...f.props(l.helpQuestion),children:_({id:`QU2cIs`,message:`Have questions?`})}),u(i,{...f.props(l.helpLink),children:u(s.span,{size:`meta`,fontWeight:`medium`,leading:`tight`,color:`inherit`,children:_({id:`AWtGgd`,message:`Get help`})})})]})]})})})]})}export{p as TransferCryptoDisclosure};
@@ -1 +1 @@
1
- "use client";import{resolveChainLogoChain as e}from"../../../../../../shared/utils/logos/resolveLogoSrc.js";import"../../../../../../shared/utils/logos/index.js";import{useTransferCryptoContext as t}from"../context.js";import{TRANSFER_CRYPTO_SLOTS as n}from"../TransferCrypto.slots.js";import{styles as r}from"../TransferCrypto.styles.js";import{useEffect as i,useState as a}from"react";import{jsx as o}from"react/jsx-runtime";import*as s from"@stylexjs/stylex";import{Cuer as c}from"cuer";function l(){let l=t(`TransferCrypto.QrCode`),u=e({...l.chain.chainId===void 0?{}:{chainId:l.chain.chainId},...l.chain.logoUrl===void 0?{}:{chainLogoUrl:l.chain.logoUrl}}),[d,f]=a(0);i(()=>{f(0)},[u.join(`|`)]);let p=u[d];return o(`div`,{"data-stridge-slot":n.qr,...s.props(r.qrFrame),children:o(c,{value:l.depositAddress,size:160,arena:p?o(`img`,{src:p,alt:l.chain.symbol,"data-stridge-slot":n.qrArena,onError:()=>{d<u.length-1&&f(d+1)},style:{width:`100%`,height:`100%`,objectFit:`contain`,display:`block`,borderRadius:`var(--stridge-kit-radius-lg)`}},p):null,...s.props(r.qrSvg)})})}export{l as TransferCryptoQrCode};
1
+ "use client";import{resolveChainLogoChain as e}from"../../../../../../shared/utils/logos/resolveLogoSrc.js";import"../../../../../../shared/utils/logos/index.js";import{useTransferCryptoContext as t}from"../context.js";import{TRANSFER_CRYPTO_SLOTS as n}from"../TransferCrypto.slots.js";import{styles as r}from"../TransferCrypto.styles.js";import{Cuer as i}from"../../../../../../shared/cuer/Cuer.js";import"../../../../../../shared/cuer/index.js";import{useEffect as a,useState as o}from"react";import{jsx as s}from"react/jsx-runtime";import*as c from"@stylexjs/stylex";function l(){let l=t(`TransferCrypto.QrCode`),u=e({...l.chain.chainId===void 0?{}:{chainId:l.chain.chainId},...l.chain.logoUrl===void 0?{}:{chainLogoUrl:l.chain.logoUrl}}),[d,f]=o(0);a(()=>{f(0)},[u.join(`|`)]);let p=u[d];return s(`div`,{"data-stridge-slot":n.qr,...c.props(r.qrFrame),children:s(i,{value:l.depositAddress,size:160,arena:p?s(`img`,{src:p,alt:l.chain.symbol,"data-stridge-slot":n.qrArena,onError:()=>{d<u.length-1&&f(d+1)},style:{width:`100%`,height:`100%`,objectFit:`contain`,display:`block`,borderRadius:`var(--stridge-kit-radius-lg)`}},p):null,...c.props(r.qrSvg)})})}export{l as TransferCryptoQrCode};
@@ -1 +1 @@
1
- function e(e,t={}){let n=e.settlements??[],r=t.txHash?.toLowerCase(),i=t.sinceIso??``,a=n.filter(e=>r?e.from?.tx_id?.toLowerCase()===r:(e.created_at??``)>=i);if(a.length!==0)return[...a].sort((e,t)=>(t.updated_at??``).localeCompare(e.updated_at??``))[0]}export{e as pickRelevantSettlement};
1
+ function e(e,t={}){let n=e.settlements??[],r=t.txHash?.toLowerCase();if(r){let e=n.filter(e=>e.from?.tx_id?.toLowerCase()===r);return e.length===0?void 0:[...e].sort((e,t)=>(t.updated_at??``).localeCompare(e.updated_at??``))[0]}let i=t.bestMatch;if(i){let t=i.destination.recipientAddress.toLowerCase(),r=i.destination.tokenSymbol.toLowerCase(),a=new Date(i.submittedAt).toISOString(),o=i.sourceAmountBaseUnits,s=n.filter(n=>{let s=n.created_at??``;if(s&&s<a)return!1;let c=e.destination;return!(Number(c.eip155_id)!==i.destination.chainId||(c.asset_symbol??``).toLowerCase()!==r||(c.address??``).toLowerCase()!==t||o!==void 0&&n.from?.raw_amount!==o)});return s.length===0?void 0:[...s].sort((e,t)=>(t.updated_at??``).localeCompare(e.updated_at??``))[0]}let a=t.sinceIso??``,o=n.filter(e=>(e.created_at??``)>=a);if(o.length!==0)return[...o].sort((e,t)=>(t.updated_at??``).localeCompare(e.updated_at??``))[0]}export{e as pickRelevantSettlement};
@@ -0,0 +1,92 @@
1
+ import { WithdrawSubmitCallback } from "../orchestrator/types.js";
2
+ import { ReactNode } from "react";
3
+ //#region src/flows/withdraw/bindings/WithdrawBindings.d.ts
4
+ /**
5
+ * Withdrawable balance the host surfaces to the withdraw form. Two accepted forms:
6
+ *
7
+ * - `number` — bare amount in display units (kit infers symbol from the provider-level
8
+ * `asset.symbol`; USD value is derived for known stablecoins or hidden otherwise).
9
+ * - `{ amount, amountUsd? }` — explicit amount plus optional pre-computed USD value.
10
+ *
11
+ * `undefined` represents the loading state — the kit renders a skeleton / em-dashes instead
12
+ * of a value.
13
+ */
14
+ type WithdrawBalanceInput = number | {
15
+ amount: number;
16
+ amountUsd?: number;
17
+ };
18
+ /**
19
+ * Trusted-recipient prefill chip surfaced next to the recipient address input. The kit no
20
+ * longer auto-derives a chip from `wagmi.address` — that misled users on embedded-wallet
21
+ * integrations, where `wagmi.address` is the integration's generated wallet rather than the
22
+ * user's primary self-custodial wallet. Hosts that have a verified, user-trusted address (a
23
+ * saved wallet on the user's profile, a KYC-bound payout destination, a whitelisted withdrawal
24
+ * address) pass it via {@link useWithdrawBindings} (or the `<WithdrawDialog>` prop of the same
25
+ * name); the chip's `aria-label` reads off `label` so the affordance is unambiguous about which
26
+ * address the user is filling with.
27
+ */
28
+ interface WithdrawSuggestedRecipient {
29
+ /** Address that fills the recipient input when the chip is clicked. */
30
+ address: string;
31
+ /**
32
+ * Short human label for the chip — used as the accessible name (`aria-label`) so screen
33
+ * readers and click targets describe the saved address concretely (e.g. `"Saved wallet"`,
34
+ * `"Your verified address"`). When omitted, the chip falls back to a generic kit-default.
35
+ */
36
+ label?: string;
37
+ /**
38
+ * Receive-side chain id this address belongs to (EIP-155 numeric). When set, the chip is
39
+ * surfaced only while the form's selected receive chain matches — prevents the user from
40
+ * one-click-filling an Ethereum address while routing to BSC, etc. When omitted, the chip
41
+ * is surfaced unconditionally and address-chain compatibility is the integrator's concern.
42
+ */
43
+ chainId?: number;
44
+ }
45
+ /**
46
+ * Render-time inputs the host supplies to the withdraw flow. Whoever renders the withdraw UI —
47
+ * the kit's `<WithdrawDialog>` or a fully custom headless surface — publishes these via
48
+ * {@link useWithdrawBindings}. Form widgets read the display values reactively; the orchestrator's
49
+ * submit action reads `onSubmit` at submit time to fire the host's callback.
50
+ */
51
+ interface WithdrawBindings {
52
+ /** Host-supplied source-side balance the form renders. */
53
+ balance?: WithdrawBalanceInput;
54
+ /**
55
+ * Host-supplied submit handler. Fired when the user submits the form (after the kit has
56
+ * prepared a fresh UDA target). The host calls the supplied actions to advance the FSM at
57
+ * the points its backend reaches the matching state.
58
+ */
59
+ onSubmit?: WithdrawSubmitCallback;
60
+ /**
61
+ * Trusted recipient address surfaced as a prefill chip on the recipient field. See
62
+ * {@link WithdrawSuggestedRecipient}.
63
+ */
64
+ suggestedRecipient?: WithdrawSuggestedRecipient;
65
+ }
66
+ /**
67
+ * Publish the host's render-time withdraw inputs (`balance`, `onSubmit`, `suggestedRecipient`)
68
+ * into the kit's withdraw scope. Call it once from whatever component renders the withdraw UI:
69
+ *
70
+ * - The kit's `<WithdrawDialog>` calls it internally with its render-time props.
71
+ * - A **headless** host that renders fully custom withdraw UI from `useWithdraw()` /
72
+ * `useWithdrawState()` / `useWithdrawSnapshot()` calls it directly — it's the supported way
73
+ * to wire `onSubmit` (and the optional display inputs) without mounting the dialog.
74
+ *
75
+ * Writes synchronously to the bridge ref during render so the controller's submit action always
76
+ * reads the latest `onSubmit`; a deferred `setState` updates the reactive state read by display
77
+ * widgets. Clears the bridge on unmount.
78
+ *
79
+ * @example Headless usage
80
+ * ```tsx
81
+ * useWithdrawBindings({
82
+ * balance: walletBalance,
83
+ * onSubmit: async (input, actions) => {
84
+ * const txHash = await backend.broadcastWithdrawal(input.depositTarget);
85
+ * actions.beginProcessing({ hash: txHash });
86
+ * },
87
+ * });
88
+ * ```
89
+ */
90
+ declare function useWithdrawBindings(bindings: WithdrawBindings): void;
91
+ //#endregion
92
+ export { WithdrawBalanceInput, WithdrawBindings, WithdrawSuggestedRecipient, useWithdrawBindings };
@@ -0,0 +1 @@
1
+ "use client";import{createContext as e,use as t,useEffect as n,useMemo as r,useRef as i,useState as a}from"react";import{jsx as o}from"react/jsx-runtime";const s=e(null);s.displayName=`WithdrawBindingsContext`;function c({children:e}){let[t,n]=a({}),c=i({});return o(s,{value:r(()=>({bindings:t,setBindings:n,ref:c}),[t]),children:e})}function l(){return t(s)?.bindings??{}}function u(){let e=t(s),n=i({});return e?.ref??n}function d(e){let r=t(s),a=e.balance,o=e.onSubmit,c=e.suggestedRecipient;r&&(r.ref.current={...a===void 0?{}:{balance:a},...o?{onSubmit:o}:{},...c?{suggestedRecipient:c}:{}});let l=i(r?.setBindings);l.current=r?.setBindings;let u=i(r?.ref);u.current=r?.ref,n(()=>{let e=l.current;if(e)return e({...a===void 0?{}:{balance:a},...o?{onSubmit:o}:{},...c?{suggestedRecipient:c}:{}}),()=>{let e=l.current,t=u.current;t&&(t.current={}),e&&e({})}},[a,o,c])}export{c as WithdrawBindingsProvider,d as useWithdrawBindings,u as useWithdrawBindingsRef,l as useWithdrawBindingsValue};
@@ -0,0 +1 @@
1
+ import { WithdrawBalanceInput, WithdrawBindings, WithdrawSuggestedRecipient, useWithdrawBindings } from "./WithdrawBindings.js";
@@ -0,0 +1 @@
1
+ import"./WithdrawBindings.js";
@@ -1,8 +1,9 @@
1
1
  import { TxRef } from "../../../shared/driver/types.js";
2
2
  import { WithdrawalQuotePayload, WithdrawalSettlementFailurePayload, WithdrawalSettlementPendingPayload, WithdrawalSettlementSuccessPayload } from "../driver/payloads.js";
3
- import { SubmitWithdrawalInput } from "../driver/types.js";
3
+ import { PrepareWithdrawalInput } from "../driver/types.js";
4
4
  import { FailureInfo } from "../../../shared/orchestrator/types.js";
5
- import { WithdrawStateName } from "../orchestrator/types.js";
5
+ import { WithdrawStateName, WithdrawSubmitCallback } from "../orchestrator/types.js";
6
+ import { WithdrawBalanceInput, WithdrawSuggestedRecipient } from "../bindings/WithdrawBindings.js";
6
7
  import { WithdrawFormEventCallbacks } from "./WithdrawDialogEventsContext.js";
7
8
  import { ErrorInfo } from "react";
8
9
  import * as _$react_jsx_runtime0 from "react/jsx-runtime";
@@ -25,7 +26,10 @@ declare function WithdrawDialog({
25
26
  onOpened,
26
27
  onClosed,
27
28
  onStepChanged,
28
- events
29
+ events,
30
+ balance,
31
+ onSubmit,
32
+ suggestedRecipient
29
33
  }?: WithdrawDialog.Props): _$react_jsx_runtime0.JSX.Element;
30
34
  declare namespace WithdrawDialog {
31
35
  interface Props {
@@ -56,21 +60,56 @@ declare namespace WithdrawDialog {
56
60
  * valid for the named event.
57
61
  */
58
62
  events?: Events;
63
+ /**
64
+ * Withdrawable balance to display in the form. Two forms:
65
+ *
66
+ * - `number` — bare amount in display units (kit infers symbol from the provider's
67
+ * `asset.symbol`; USD value is short-circuited to $1 for known stablecoins or
68
+ * hidden otherwise).
69
+ * - `{ amount, amountUsd? }` — explicit amount plus an optional pre-computed USD
70
+ * value.
71
+ *
72
+ * Pass `undefined` (or omit) while loading; the form renders a skeleton until a value
73
+ * arrives.
74
+ */
75
+ balance?: WithdrawBalanceInput;
76
+ /**
77
+ * Submit handler — fires once the kit has prepared a fresh UDA target for the
78
+ * withdrawal. The host's backend (treasury wallet, custodial signer, whatever fits their
79
+ * stack) is responsible for broadcasting a transfer of the brand currency to that UDA;
80
+ * the kit hands a `WithdrawSubmitActions` handle the host calls to advance the FSM at
81
+ * the point its backend reaches the matching state. Required when the dialog is used —
82
+ * a missing callback lands the user on the error screen instead of an infinite spinner.
83
+ */
84
+ onSubmit?: WithdrawSubmitCallback;
85
+ /**
86
+ * Trusted recipient address surfaced as a one-click prefill chip next to the recipient
87
+ * input. The kit no longer auto-derives this from `wagmi.address` (it misled users on
88
+ * embedded-wallet integrations where wagmi exposes a generated wallet, not the user's
89
+ * primary self-custodial wallet). Pass an explicit address you trust the user wants to
90
+ * fill with — a saved profile wallet, a KYC-bound payout destination, a whitelisted
91
+ * payout. When omitted, no chip renders.
92
+ */
93
+ suggestedRecipient?: WithdrawSuggestedRecipient;
59
94
  }
60
95
  /**
61
96
  * Operational lifecycle hooks. Splits cleanly into:
62
97
  *
63
98
  * - **Form-level inputs** (`onRecipientChanged` / `onAmountChanged` / `onReceiveTokenChanged`
64
99
  * / `onReceiveChainChanged`) — fire on every change of the form's local state.
65
- * - **User actions** (`onWithdrawalConfirmed`) — fire when the user submits the form.
100
+ * - **User actions** (`onWithdrawalConfirmed`) — fires when the user submits the form, just
101
+ * before the kit hands control to the host's `<WithdrawDialog onSubmit>` callback.
66
102
  * - **Quote lifecycle** — track the form's quote entity through `loading → ready / error`.
67
- * - **Submit lifecycle** — track the wagmi-driven broadcast through wagmi → receipt → terminal
68
- * verdict.
103
+ * - **Submit lifecycle** — track the host-driven progression. The host calls
104
+ * `actions.beginProcessing(tx?)` from inside `onSubmit` to move the orchestrator into
105
+ * `inProgress`; `onWithdrawalSubmitted` fires once a tx hash is surfaced (either via
106
+ * `beginProcessing({ hash })` or a later `setTxHash`). `onSubmissionFailed` fires when
107
+ * the host calls `actions.fail(failure)` or `onSubmit` throws.
69
108
  * - **Settlement entity** — track the gateway's settlement payload through pending / succeeded /
70
109
  * failed.
71
110
  */
72
111
  interface Events extends WithdrawFormEventCallbacks {
73
- /** User submitted the form (the SUBMIT action wallet prompt is about to fire). */
112
+ /** User submitted the form fires just before the host's `onSubmit` callback runs. */
74
113
  onWithdrawalConfirmed?: () => void;
75
114
  /** Quote entity reached `ready` with the formatted payload. */
76
115
  onQuoteResolved?: (quote: WithdrawalQuotePayload) => void;
@@ -79,14 +118,21 @@ declare namespace WithdrawDialog {
79
118
  reason: string;
80
119
  code?: string;
81
120
  }) => void;
82
- /** Wagmi broadcast completed and the orchestrator transitioned into `inProgress`. */
121
+ /**
122
+ * Orchestrator transitioned into `inProgress` with a tx hash supplied by the host —
123
+ * either passed to `actions.beginProcessing({ hash })` or surfaced later via
124
+ * `actions.setTxHash`.
125
+ */
83
126
  onWithdrawalSubmitted?: (event: {
84
- input: SubmitWithdrawalInput;
127
+ input: PrepareWithdrawalInput;
85
128
  tx: TxRef;
86
129
  }) => void;
87
- /** User declined the wallet signature prompt; orchestrator transitioned into `error`. */
130
+ /**
131
+ * Host signaled a user-rejection-shaped failure from `onSubmit` (typically the user
132
+ * backed out of a wallet prompt); the orchestrator routed back to `form{notice}`.
133
+ */
88
134
  onSignatureDeclined?: () => void;
89
- /** Submission failed for a non-rejection reason (network, bad input, etc). */
135
+ /** Host signaled a non-rejection submission failure (backend rejection, network, ). */
90
136
  onSubmissionFailed?: (failure: FailureInfo) => void;
91
137
  /** The driver's `settlement` entity emitted a progressive pending update. */
92
138
  onProcessingProgress?: (update: WithdrawalSettlementPendingPayload) => void;
@@ -1 +1 @@
1
- "use client";import{useDialogLifecycle as e}from"../../../shared/orchestrator/useDialogLifecycle.js";import"../../../shared/orchestrator/index.js";import{useWithdrawSnapshot as t}from"../driver/context.js";import{useWithdrawEffectiveState as n,useWithdrawState as r}from"../orchestrator/controller.js";import{useWithdraw as i}from"../orchestrator/useWithdraw.js";import"../orchestrator/index.js";import{Dialog as a}from"../../../shared/ui/Dialog/Dialog.js";import"../../../shared/ui/Dialog/index.js";import{StepTransition as o}from"../../../shared/dialog/StepTransition.js";import{GatewayKitBoundary as s}from"../../../shared/error-handling/components/GatewayKitBoundary.js";import"../../../shared/error-handling/index.js";import{WithdrawError as c}from"../widgets/withdraw-error/WithdrawError.js";import{WithdrawDialogEventsProvider as l}from"./WithdrawDialogEventsContext.js";import{WithdrawForm as u}from"../widgets/withdraw-form/WithdrawForm.js";import{WithdrawInProgress as d}from"../widgets/withdraw-in-progress/WithdrawInProgress.js";import{WithdrawSuccess as f}from"../widgets/withdraw-success/WithdrawSuccess.js";import"../../../_internal/withdraw/widgets/index.js";import{useRef as p}from"react";import{jsx as m,jsxs as h}from"react/jsx-runtime";function g({container:e,onError:p,onOpened:g,onClosed:v,onStepChanged:y,events:b}={}){let x=r(),S=n(),{close:C}=i(),w=t(),T=x.name!==`closed`;_(x,w.settlement,w.quote,{onOpened:g,onClosed:v,onStepChanged:y,events:b});let E=S.name===`submitting`?`form`:S.name;return m(a,{open:T,onOpenChange:e=>e?void 0:C(),children:m(a.Content,{container:e,children:m(s,{onError:p,onReset:C,children:m(l,{events:b??{},children:h(o,{stateKey:E,children:[S.name===`form`||S.name===`submitting`?m(u,{}):null,S.name===`inProgress`?m(d,{}):null,S.name===`success`?m(f,{}):null,S.name===`error`?m(c,{}):null]})})})})})}function _(t,n,r,i){let a=p(i);a.current=i,e({state:t,settlement:n,quote:r,fireFsm:(e,t)=>v(e,t,a.current),fireSettlement:(e,t)=>y(t,a.current),fireQuote:(e,t)=>{if(t.status===e)return;let n=a.current.events;t.status===`ready`&&n?.onQuoteResolved?.(t.payload),t.status===`error`&&n?.onQuoteFailed?.({reason:t.error.message||`Quote failed.`,...t.error.name?{code:t.error.name}:{}})}})}function v(e,t,n){let{onOpened:r,onClosed:i,onStepChanged:a,events:o}=n,s=e.name===`form`&&!!e.ctx?.notice;if(t.name===`form`&&t.ctx?.notice&&!s&&o?.onSignatureDeclined?.(),e.name!==t.name&&(e.name===`closed`&&t.name!==`closed`&&r?.(),e.name!==`closed`&&t.name===`closed`&&i?.(e.name),a?.({from:e.name,to:t.name}),e.name===`form`&&t.name===`submitting`&&o?.onWithdrawalConfirmed?.(),e.name===`submitting`&&t.name===`inProgress`&&o?.onWithdrawalSubmitted?.({input:t.ctx.input,tx:t.ctx.tx}),t.name===`error`)){let e=t.ctx.failure;e!==void 0&&t.ctx.tx===void 0&&e&&(o?.onSubmissionFailed?.(e),o?.onFailed?.(e))}}function y(e,t){if(e.status!==`ready`&&e.status!==`stale`)return;let n=e.payload,r=t.events;if(r){if(n.kind===`pending`){r.onProcessingProgress?.(n);return}if(n.kind===`succeeded`){r.onSucceeded?.(n);return}n.kind===`failed`&&r.onFailed?.(n)}}export{g as WithdrawDialog};
1
+ "use client";import{useDialogLifecycle as e}from"../../../shared/orchestrator/useDialogLifecycle.js";import"../../../shared/orchestrator/index.js";import{useWithdrawBindings as t}from"../bindings/WithdrawBindings.js";import"../bindings/index.js";import{useWithdrawSnapshot as n}from"../driver/context.js";import{useWithdrawEffectiveState as r,useWithdrawState as i}from"../orchestrator/controller.js";import{useWithdraw as a}from"../orchestrator/useWithdraw.js";import"../orchestrator/index.js";import{useIntercomShutdownOnUnmount as o}from"../../../shared/support/useIntercomShutdownOnUnmount.js";import"../../../shared/support/index.js";import{Dialog as s}from"../../../shared/ui/Dialog/Dialog.js";import"../../../shared/ui/Dialog/index.js";import{StepTransition as c}from"../../../shared/dialog/StepTransition.js";import{GatewayKitBoundary as l}from"../../../shared/error-handling/components/GatewayKitBoundary.js";import"../../../shared/error-handling/index.js";import{WithdrawError as u}from"../widgets/withdraw-error/WithdrawError.js";import{WithdrawDialogEventsProvider as d}from"./WithdrawDialogEventsContext.js";import{WithdrawForm as f}from"../widgets/withdraw-form/WithdrawForm.js";import{WithdrawInProgress as p}from"../widgets/withdraw-in-progress/WithdrawInProgress.js";import{WithdrawSuccess as m}from"../widgets/withdraw-success/WithdrawSuccess.js";import"../../../_internal/withdraw/widgets/index.js";import{useRef as h}from"react";import{jsx as g,jsxs as _}from"react/jsx-runtime";function v({container:e,onError:h,onOpened:v,onClosed:b,onStepChanged:x,events:S,balance:C,onSubmit:w,suggestedRecipient:T}={}){let E=i(),D=r(),{close:O}=a(),k=n(),A=E.name!==`closed`;y(E,k.settlement,k.quote,{onOpened:v,onClosed:b,onStepChanged:x,events:S}),o(),t({...C===void 0?{}:{balance:C},...w?{onSubmit:w}:{},...T?{suggestedRecipient:T}:{}});let j=D.name===`submitting`?`form`:D.name;return g(s,{open:A,onOpenChange:e=>e?void 0:O(),children:g(s.Content,{container:e,children:g(l,{onError:h,onReset:O,children:g(d,{events:S??{},children:_(c,{stateKey:j,children:[D.name===`form`||D.name===`submitting`?g(f,{}):null,D.name===`inProgress`?g(p,{}):null,D.name===`success`?g(m,{}):null,D.name===`error`?g(u,{}):null]})})})})})}function y(t,n,r,i){let a=h(i);a.current=i,e({state:t,settlement:n,quote:r,fireFsm:(e,t)=>b(e,t,a.current),fireSettlement:(e,t)=>x(t,a.current),fireQuote:(e,t)=>{if(t.status===e)return;let n=a.current.events;t.status===`ready`&&n?.onQuoteResolved?.(t.payload),t.status===`error`&&n?.onQuoteFailed?.({reason:t.error.message||`Quote failed.`,...t.error.name?{code:t.error.name}:{}})}})}function b(e,t,n){let{onOpened:r,onClosed:i,onStepChanged:a,events:o}=n,s=e.name===`form`&&!!e.ctx?.notice;if(t.name===`form`&&t.ctx?.notice&&!s&&o?.onSignatureDeclined?.(),e.name!==t.name&&(e.name===`closed`&&t.name!==`closed`&&r?.(),e.name!==`closed`&&t.name===`closed`&&i?.(e.name),a?.({from:e.name,to:t.name}),e.name===`form`&&t.name===`submitting`&&o?.onWithdrawalConfirmed?.(),e.name===`submitting`&&t.name===`inProgress`&&t.ctx.tx&&o?.onWithdrawalSubmitted?.({input:t.ctx.input,tx:t.ctx.tx}),t.name===`error`)){let e=t.ctx.failure;e!==void 0&&t.ctx.tx===void 0&&e&&(o?.onSubmissionFailed?.(e),o?.onFailed?.(e))}}function x(e,t){if(e.status!==`ready`&&e.status!==`stale`)return;let n=e.payload,r=t.events;if(r){if(n.kind===`pending`){r.onProcessingProgress?.(n);return}if(n.kind===`succeeded`){r.onSucceeded?.(n);return}n.kind===`failed`&&r.onFailed?.(n)}}export{v as WithdrawDialog};
@@ -1,5 +1,7 @@
1
1
  import { SettlementFailureKind } from "../../../shared/driver/types.js";
2
2
  import { FormattedField } from "../../../shared/format/types.js";
3
+ import { ChainType } from "../../../shared/chains/index.js";
4
+
3
5
  //#region src/flows/withdraw/driver/payloads.d.ts
4
6
  /**
5
7
  * Per-asset balance available to withdraw — the brand-managed source the cash-out flow draws
@@ -191,8 +193,15 @@ interface ReceiveChainPayload {
191
193
  networkId: string;
192
194
  /** Human-readable network name (e.g. `"Polygon"`). */
193
195
  networkName: string;
194
- /** EIP-155 chain id (numeric). */
196
+ /** EIP-155 chain id (numeric). Only meaningful when `chainType === "evm"`. */
195
197
  eip155Id: number;
198
+ /**
199
+ * Chain family this network belongs to — driver-populated from the gateway's `chain_type`
200
+ * tag. The withdraw form drives recipient-address validation off this so a non-EVM receive
201
+ * chain accepts its own address shape instead of the EVM `0x…` form. Drivers that can't
202
+ * determine the family tag it `"unknown"`, which keeps the address gate permissive.
203
+ */
204
+ chainType: ChainType;
196
205
  /** Resolved chain icon URL — derived from the chain's native_currency.logo. */
197
206
  chainLogoUrl?: string;
198
207
  /**
@@ -1 +1 @@
1
- import{formatNetworkName as e}from"../../../../shared/format/formatNetworkName.js";function t(t,n={}){let r=n.excludedChainIds,i=[];for(let n of t.assets){if(r?.has(n.eip155_id))continue;let t=n.native_currency,a=new Set,o=(e,t)=>`${e.toUpperCase()}@${t.toLowerCase()}`,s=[];if(t?.symbol){let e={symbol:t.symbol,name:t.name??t.symbol,address:``,decimals:typeof t.decimals==`number`?t.decimals:18,isNative:!0,...t.logo?{assetLogoUrl:t.logo}:{}};s.push(e),a.add(o(e.symbol,e.address))}let c=t?.symbol?.toUpperCase();for(let e of n.assets){if(!e.symbol||!e.address||c&&e.symbol.toUpperCase()===c)continue;let t=o(e.symbol,e.address);a.has(t)||(a.add(t),s.push({symbol:e.symbol,name:e.name??e.symbol,address:e.address,decimals:e.decimals,isNative:!1,...e.logo?{assetLogoUrl:e.logo}:{}}))}s.length!==0&&i.push({networkId:n.network_id,networkName:e(n.network_name),eip155Id:n.eip155_id,...t?.logo?{chainLogoUrl:t.logo}:{},tokens:s})}return i.sort((e,t)=>e.eip155Id-t.eip155Id),i}export{t as supportedAssetsToReceiveOptionsPayload};
1
+ import{toChainType as e}from"../../../../shared/chains/index.js";import{formatNetworkName as t}from"../../../../shared/format/formatNetworkName.js";function n(n,r={}){let i=r.excludedChainIds,a=[];for(let r of n.assets){if(i?.has(r.eip155_id))continue;let n=r.native_currency,o=new Set,s=(e,t)=>`${e.toUpperCase()}@${t.toLowerCase()}`,c=[];if(n?.symbol){let e={symbol:n.symbol,name:n.name??n.symbol,address:``,decimals:typeof n.decimals==`number`?n.decimals:18,isNative:!0,...n.logo?{assetLogoUrl:n.logo}:{}};c.push(e),o.add(s(e.symbol,e.address))}let l=n?.symbol?.toUpperCase();for(let e of r.assets){if(!e.symbol||!e.address||l&&e.symbol.toUpperCase()===l)continue;let t=s(e.symbol,e.address);o.has(t)||(o.add(t),c.push({symbol:e.symbol,name:e.name??e.symbol,address:e.address,decimals:e.decimals,isNative:!1,...e.logo?{assetLogoUrl:e.logo}:{}}))}c.length!==0&&a.push({networkId:r.network_id,networkName:t(r.network_name),eip155Id:r.eip155_id,chainType:e(r.chain_type),...n?.logo?{chainLogoUrl:n.logo}:{},tokens:c})}return a.sort((e,t)=>e.eip155Id-t.eip155Id),a}export{n as supportedAssetsToReceiveOptionsPayload};
@@ -57,17 +57,57 @@ interface RequestWithdrawalQuoteInput {
57
57
  recipientAddress: string;
58
58
  }
59
59
  /**
60
- * Input to {@link WithdrawDriver.submitWithdrawal}. Identical to {@link RequestWithdrawalQuoteInput}
61
- * — the live driver re-uses the most recent quote for submit, so the same identifying fields
62
- * scope both calls.
60
+ * Input to {@link WithdrawDriver.prepareWithdrawal}. Identical to {@link RequestWithdrawalQuoteInput}
61
+ * — the live driver re-uses the most recent quote shape for the gateway/start call, so the same
62
+ * identifying fields scope both calls.
63
63
  */
64
- type SubmitWithdrawalInput = RequestWithdrawalQuoteInput;
64
+ type PrepareWithdrawalInput = RequestWithdrawalQuoteInput;
65
65
  /**
66
- * Input to {@link WithdrawDriver.watchSettlement}. Carries the broadcast tx ref so the watcher
67
- * can scope its poll to the in-flight withdraw.
66
+ * Result of {@link WithdrawDriver.prepareWithdrawal}. Carries everything the host's `onSubmit`
67
+ * callback needs to broadcast a transfer to the Stridge UDA on the brand-currency chain — the
68
+ * UDA address, the chain, the token, the amount — plus the Stridge correlation fields the host
69
+ * may want to mirror into their own backend logs.
70
+ */
71
+ interface WithdrawPreparation {
72
+ /**
73
+ * Where the host should send brand-currency funds. The kit has already provisioned a UDA
74
+ * (via `gateway/start`); the host's job is to broadcast a single on-chain transfer of
75
+ * `amount` of `tokenSymbol` from their treasury / custodial wallet to `address` on `chainId`.
76
+ * Stridge takes over from there to bridge into the user's chosen recipient/chain/token.
77
+ */
78
+ depositTarget: {
79
+ /** UDA deposit address on the brand-currency chain. */address: string; /** EIP-155 chain id of the brand-currency network. */
80
+ chainId: number; /** Brand-currency token symbol (e.g. `"USDC"`). */
81
+ tokenSymbol: string; /** ERC-20 contract address of the brand currency. Empty string for native gas tokens. */
82
+ tokenAddress: string; /** On-chain decimal precision (e.g. `6` for USDC on Ethereum, `18` for ETH). */
83
+ tokenDecimals: number; /** `true` when the brand currency is the chain's native gas token. */
84
+ isNative: boolean; /** Exact amount to transfer, in display units (kit-managed decimals already factored in). */
85
+ amount: number;
86
+ };
87
+ /**
88
+ * Stridge correlation slot the host can pass through to their own backend / logs. `owner`
89
+ * is the same value the kit threaded into `gateway/start.owner` for this UDA.
90
+ */
91
+ correlation: {
92
+ owner: string;
93
+ };
94
+ }
95
+ /**
96
+ * Input to {@link WithdrawDriver.watchSettlement}. `tx` is optional — when the host has
97
+ * surfaced a broadcast tx hash via the orchestrator's `setTxHash` action, the watcher anchors
98
+ * to it for precise matching. When omitted, the watcher falls back to a best-match heuristic
99
+ * (destination tuple + amount tolerance + submit-time window) so the kit can find the relevant
100
+ * settlement even if the host never surfaces a tx hash.
68
101
  */
69
102
  interface WatchWithdrawalSettlementInput {
70
- tx: TxRef;
103
+ tx?: TxRef;
104
+ /**
105
+ * Form snapshot at submit time. The driver uses this in best-match mode to filter
106
+ * `gateway/{owner}` to settlements whose destination matches the user's selection.
107
+ */
108
+ form: RequestWithdrawalQuoteInput;
109
+ /** Unix-ms timestamp the host called `beginProcessing` — the start of the matching window. */
110
+ submittedAt: number;
71
111
  }
72
112
  /**
73
113
  * Input to {@link WithdrawDriver.watchWithdrawableBalances}. Optional listener — the form's
@@ -113,10 +153,12 @@ interface WithdrawDriver {
113
153
  */
114
154
  requestQuote(input: RequestWithdrawalQuoteInput, signal: AbortSignal): Promise<void>;
115
155
  /**
116
- * Submits the confirmed withdrawal. Resolves with the broadcast tx ref. The settlement
117
- * watcher takes over from there to populate the `settlement` entity.
156
+ * Provisions a fresh UDA for this withdrawal (via `gateway/start`) and returns the deposit
157
+ * target + Stridge correlation slot for the host's `onSubmit` callback to act on. The kit
158
+ * never signs the withdraw transfer itself — the host's backend (treasury wallet, custodial
159
+ * signer, hot-wallet service) does. See {@link WithdrawPreparation}.
118
160
  */
119
- submitWithdrawal(input: SubmitWithdrawalInput, signal: AbortSignal): Promise<TxRef>;
161
+ prepareWithdrawal(input: PrepareWithdrawalInput, signal: AbortSignal): Promise<WithdrawPreparation>;
120
162
  /**
121
163
  * Watches the settlement entity through its lifecycle (pending → succeeded / failed). The
122
164
  * listener fires on every transition with the new envelope; the FSM consumes these via the
@@ -130,4 +172,4 @@ interface WithdrawDriver {
130
172
  watchWithdrawableBalances?(input: WatchWithdrawableBalancesInput, listener: (entity: WithdrawSnapshot["withdrawableBalances"]) => void, signal: AbortSignal): void;
131
173
  }
132
174
  //#endregion
133
- export { RequestWithdrawalQuoteInput, SubmitWithdrawalInput, WatchWithdrawableBalancesInput, WatchWithdrawalSettlementInput, WithdrawDriver, WithdrawSnapshot };
175
+ export { PrepareWithdrawalInput, RequestWithdrawalQuoteInput, WatchWithdrawableBalancesInput, WatchWithdrawalSettlementInput, WithdrawDriver, WithdrawPreparation, WithdrawSnapshot };
@@ -1 +1 @@
1
- "use client";import{useLingui as e}from"../../../shared/i18n/useLingui.js";import"../../../i18n/index.js";import{toFailure as t}from"../../../shared/orchestrator/toFailure.js";import{useDriverSettlementListener as n}from"../../../shared/orchestrator/useDriverSettlementListener.js";import{useEffectiveState as r}from"../../../shared/orchestrator/useEffectiveState.js";import{useSettlementWatcher as i}from"../../../shared/orchestrator/useSettlementWatcher.js";import"../../../shared/orchestrator/index.js";import{useWithdrawDriverInstance as a}from"../driver/context.js";import{initialState as o,reducer as s}from"./reducer.js";import{createContext as c,use as l,useCallback as u,useMemo as d,useReducer as f,useRef as p}from"react";import{jsx as m}from"react/jsx-runtime";const h={id:`ldK3jJ`,message:`Failed to submit withdrawal.`},g={id:`kUFhUv`,message:`Withdrawal failed.`},_=c(null);_.displayName=`WithdrawControllerContext`;function v(){let e=l(_);if(!e)throw Error(`useWithdraw / WithdrawControllerProvider must be used inside <KitProvider withdraw={…} />. Mount KitProvider once at the host's app root with a withdraw driver.`);return e}function y(){return v().state}function b(){return v().effectiveState}function x(){return v().actions}function S({children:e}){let t=a(),[n,c]=f(s,o),l=w(n,c,t);i(t,n.name===`inProgress`?n.ctx.tx:void 0),T(n,c,t);let u=r(n),p=C(c,l);return m(_,{value:d(()=>({state:n,effectiveState:u,dispatch:c,controller:p,actions:l}),[n,u,p,l]),children:e})}function C(e,t){let n=u(()=>{e({type:`OPEN`})},[e]),r=u(()=>{e({type:`CLOSE`})},[e]);return d(()=>({open:n,close:r,actions:t}),[n,r,t])}function w(n,r,i){let a=p(n);a.current=n;let o=p(i);o.current=i;let s=p(r);s.current=r;let{i18n:c}=e(),l=p(c);l.current=c;let f=u(e=>{let n=o.current;s.current({type:`SUBMIT`,input:e});let r=new AbortController,i={sourceAssetSymbol:e.sourceAssetSymbol,sourceChainId:e.sourceChainId,amount:e.amount,receiveTokenSymbol:e.receiveTokenSymbol,receiveChainId:e.receiveChainId,recipientAddress:e.recipientAddress};n.submitWithdrawal(i,r.signal).then(e=>{r.signal.aborted||s.current({type:`SUBMIT_CONFIRMED`,tx:e})}).catch(n=>{r.signal.aborted||s.current({type:`SUBMIT_FAILED`,failure:t(n,l.current._(h)),input:e})})},[]),m=u(()=>{s.current({type:`CLOSE`})},[]),g=u(()=>{s.current({type:`RESET`})},[]),_=u(()=>{s.current({type:`CLEAR_NOTICE`})},[]);return d(()=>({submit:f,close:m,reset:g,clearNotice:_}),[f,m,g,_])}function T(t,r,i){let a=p(t);a.current=t;let{i18n:o}=e(),s=p(o);s.current=o,n(i,(e,t)=>{if(a.current.name===`inProgress`){if(e===`succeeded`){r({type:`SETTLEMENT_SUCCEEDED`});return}if(e===`failed`){let e=t.settlement,n=e.status===`ready`||e.status===`stale`?e.payload:null,i=n&&n.kind===`failed`?{reason:s.current._(g),code:n.failureKind}:void 0;r({type:`SETTLEMENT_FAILED`,...i?{failure:i}:{}})}}})}export{S as WithdrawControllerProvider,v as useControllerContext,x as useWithdrawActions,b as useWithdrawEffectiveState,y as useWithdrawState};
1
+ "use client";import{useLingui as e}from"../../../shared/i18n/useLingui.js";import"../../../i18n/index.js";import{toFailure as t}from"../../../shared/orchestrator/toFailure.js";import{useDriverSettlementListener as n}from"../../../shared/orchestrator/useDriverSettlementListener.js";import{useEffectiveState as r}from"../../../shared/orchestrator/useEffectiveState.js";import{useSettlementWatcher as i}from"../../../shared/orchestrator/useSettlementWatcher.js";import"../../../shared/orchestrator/index.js";import{useWithdrawBindingsRef as a}from"../bindings/WithdrawBindings.js";import"../bindings/index.js";import{useWithdrawDriverInstance as o}from"../driver/context.js";import{initialState as s,reducer as c}from"./reducer.js";import{createContext as l,use as u,useCallback as d,useMemo as f,useReducer as p,useRef as m}from"react";import{jsx as h}from"react/jsx-runtime";const g={id:`ldK3jJ`,message:`Failed to submit withdrawal.`},_={id:`kUFhUv`,message:`Withdrawal failed.`},v=l(null);v.displayName=`WithdrawControllerContext`;function y(){let e=u(v);if(!e)throw Error(`useWithdraw / WithdrawControllerProvider must be used inside <KitProvider withdraw={…} />. Mount KitProvider once at the host's app root with a withdraw driver.`);return e}function b(){return y().state}function x(){return y().effectiveState}function S(){return y().actions}function C({children:e}){let t=o(),[n,a]=p(c,s),l=T(n,a,t),u=n.name===`inProgress`?{form:n.ctx.input,submittedAt:n.ctx.submittedAt,...n.ctx.tx?{tx:n.ctx.tx}:{}}:void 0;i(t,u,u?`${u.submittedAt}|${u.tx?.hash??``}`:void 0),E(n,a,t);let d=r(n),m=w(a,l);return h(v,{value:f(()=>({state:n,effectiveState:d,dispatch:a,controller:m,actions:l}),[n,d,m,l]),children:e})}function w(e,t){let n=d(()=>{e({type:`OPEN`})},[e]),r=d(()=>{e({type:`CLOSE`})},[e]);return f(()=>({open:n,close:r,actions:t}),[n,r,t])}function T(n,r,i){let o=m(n);o.current=n;let s=m(i);s.current=i;let c=m(r);c.current=r;let{i18n:l}=e(),u=m(l);u.current=l;let p=a(),h=d(e=>{let n=s.current;c.current({type:`SUBMIT`,input:e});let r=new AbortController,i={sourceAssetSymbol:e.sourceAssetSymbol,sourceChainId:e.sourceChainId,amount:e.amount,receiveTokenSymbol:e.receiveTokenSymbol,receiveChainId:e.receiveChainId,recipientAddress:e.recipientAddress},a={beginProcessing(e){c.current({type:`BEGIN_PROCESSING`,submittedAt:Date.now(),...e?{tx:e}:{}})},setTxHash(e){c.current({type:`SET_TX_HASH`,tx:e,submittedAt:Date.now()})},fail(e){c.current({type:`MARK_FAILED`,...e?{failure:e}:{}})},succeed(){c.current({type:`MARK_SUCCEEDED`})}};n.prepareWithdrawal(i,r.signal).then(i=>{if(r.signal.aborted)return;let o=p.current.onSubmit;if(!o){c.current({type:`SUBMIT_FAILED`,failure:t(Error(`WithdrawDialog onSubmit is missing.`),u.current._(g)),input:e});return}let s=n.getSnapshot().quote,l=s.status===`ready`||s.status===`stale`?s.payload:void 0;try{let n=o({form:e,depositTarget:i.depositTarget,correlation:i.correlation,...l?{quote:l}:{}},a,r.signal);n&&typeof n.catch==`function`&&n.catch(n=>{r.signal.aborted||c.current({type:`SUBMIT_FAILED`,failure:t(n,u.current._(g)),input:e})})}catch(n){if(r.signal.aborted)return;c.current({type:`SUBMIT_FAILED`,failure:t(n,u.current._(g)),input:e})}}).catch(n=>{r.signal.aborted||c.current({type:`SUBMIT_FAILED`,failure:t(n,u.current._(g)),input:e})})},[]),_=d(()=>{c.current({type:`CLOSE`})},[]),v=d(()=>{c.current({type:`RESET`})},[]),y=d(()=>{c.current({type:`CLEAR_NOTICE`})},[]);return f(()=>({submit:h,close:_,reset:v,clearNotice:y}),[h,_,v,y])}function E(t,r,i){let a=m(t);a.current=t;let{i18n:o}=e(),s=m(o);s.current=o,n(i,(e,t)=>{if(a.current.name===`inProgress`){if(e===`succeeded`){r({type:`SETTLEMENT_SUCCEEDED`});return}if(e===`failed`){let e=t.settlement,n=e.status===`ready`||e.status===`stale`?e.payload:null,i=n&&n.kind===`failed`?{reason:s.current._(_),code:n.failureKind}:void 0;r({type:`SETTLEMENT_FAILED`,...i?{failure:i}:{}})}}})}export{C as WithdrawControllerProvider,y as useControllerContext,S as useWithdrawActions,x as useWithdrawEffectiveState,b as useWithdrawState};
@@ -1 +1 @@
1
- import{isUserRejectionFailure as e}from"../../../shared/orchestrator/userRejection.js";import"../../../shared/orchestrator/index.js";const t={name:`closed`};function n(e,t){switch(e.name){case`closed`:return r(t);case`form`:return i(e,t);case`submitting`:return a(e,t);case`inProgress`:return o(e,t);case`success`:return s(e,t);case`error`:return c(e,t);default:return l(e)}}function r(e){return e.type===`OPEN`?{name:`form`}:{name:`closed`}}function i(e,t){switch(t.type){case`SUBMIT`:return{name:`submitting`,ctx:{input:t.input}};case`CLEAR_NOTICE`:return e.ctx?.notice?{name:`form`}:e;case`CLOSE`:return{name:`closed`};default:return e}}function a(t,n){switch(n.type){case`SUBMIT_CONFIRMED`:return{name:`inProgress`,ctx:{input:t.ctx.input,tx:n.tx}};case`SUBMIT_FAILED`:return e(n.failure)?{name:`form`,ctx:{notice:n.failure.reason}}:{name:`error`,ctx:{input:n.input,failure:n.failure}};case`CLOSE`:return{name:`closed`};default:return t}}function o(e,t){switch(t.type){case`SETTLEMENT_SUCCEEDED`:return{name:`success`,ctx:{input:e.ctx.input,tx:e.ctx.tx}};case`SETTLEMENT_FAILED`:return{name:`error`,ctx:{input:e.ctx.input,tx:e.ctx.tx,...t.failure?{failure:t.failure}:{}}};case`CLOSE`:return{name:`closed`};default:return e}}function s(e,t){switch(t.type){case`RESET`:return{name:`form`};case`CLOSE`:return{name:`closed`};default:return e}}function c(e,t){switch(t.type){case`RESET`:return{name:`form`};case`CLOSE`:return{name:`closed`};default:return e}}function l(e){throw Error(`Unhandled withdraw state: ${JSON.stringify(e)}`)}export{t as initialState,n as reducer};
1
+ import{isUserRejectionFailure as e}from"../../../shared/orchestrator/userRejection.js";import"../../../shared/orchestrator/index.js";const t={name:`closed`};function n(e,t){switch(e.name){case`closed`:return r(t);case`form`:return i(e,t);case`submitting`:return a(e,t);case`inProgress`:return o(e,t);case`success`:return s(e,t);case`error`:return c(e,t);default:return l(e)}}function r(e){return e.type===`OPEN`?{name:`form`}:{name:`closed`}}function i(e,t){switch(t.type){case`SUBMIT`:return{name:`submitting`,ctx:{input:t.input}};case`CLEAR_NOTICE`:return e.ctx?.notice?{name:`form`}:e;case`CLOSE`:return{name:`closed`};default:return e}}function a(t,n){switch(n.type){case`BEGIN_PROCESSING`:return{name:`inProgress`,ctx:{input:t.ctx.input,submittedAt:n.submittedAt,...n.tx?{tx:n.tx}:{}}};case`SET_TX_HASH`:return{name:`inProgress`,ctx:{input:t.ctx.input,submittedAt:n.submittedAt,tx:n.tx}};case`MARK_SUCCEEDED`:return{name:`success`,ctx:{input:t.ctx.input}};case`MARK_FAILED`:return{name:`error`,ctx:{input:t.ctx.input,...n.failure?{failure:n.failure}:{}}};case`SUBMIT_FAILED`:return e(n.failure)?{name:`form`,ctx:{notice:n.failure.reason}}:{name:`error`,ctx:{input:n.input,failure:n.failure}};case`CLOSE`:return{name:`closed`};default:return t}}function o(e,t){switch(t.type){case`SET_TX_HASH`:return{name:`inProgress`,ctx:{...e.ctx,tx:t.tx}};case`BEGIN_PROCESSING`:return{name:`inProgress`,ctx:{input:e.ctx.input,submittedAt:e.ctx.submittedAt,...e.ctx.tx?{tx:e.ctx.tx}:t.tx?{tx:t.tx}:{}}};case`MARK_SUCCEEDED`:return{name:`success`,ctx:{input:e.ctx.input,...e.ctx.tx?{tx:e.ctx.tx}:{}}};case`MARK_FAILED`:return{name:`error`,ctx:{input:e.ctx.input,...e.ctx.tx?{tx:e.ctx.tx}:{},...t.failure?{failure:t.failure}:{}}};case`SETTLEMENT_SUCCEEDED`:return{name:`success`,ctx:{input:e.ctx.input,...e.ctx.tx?{tx:e.ctx.tx}:{}}};case`SETTLEMENT_FAILED`:return{name:`error`,ctx:{input:e.ctx.input,...e.ctx.tx?{tx:e.ctx.tx}:{},...t.failure?{failure:t.failure}:{}}};case`CLOSE`:return{name:`closed`};default:return e}}function s(e,t){switch(t.type){case`RESET`:return{name:`form`};case`CLOSE`:return{name:`closed`};default:return e}}function c(e,t){switch(t.type){case`RESET`:return{name:`form`};case`CLOSE`:return{name:`closed`};default:return e}}function l(e){throw Error(`Unhandled withdraw state: ${JSON.stringify(e)}`)}export{t as initialState,n as reducer};