Skip to main content

v0.16.x → v0.17.0

v0.17.0 shows arrival estimates while a deposit is in flight. Nothing in the prop, proxy, or callback surface changes; the only contract worth checking is when PROCESS_TIMEOUT fires.

PROCESS_TIMEOUT moves earlier

The advisory onError callback still fires at most once per deposit, with the same code and message, and still means the deposit is slow rather than failed. It now fires at the escalated threshold served for that deposit — five to ten minutes in practice, rather than a fixed ten minutes. With no served estimate it keeps the previous fixed threshold. If your app starts a support timer or a warning banner from this code, re-check the copy against the earlier trigger.

Unaffected

Hosts see no new props, proxy routes, or configuration — the estimate rides the existing POST /quotes/preview and GET /deposits routes. The withdraw modal’s pending screen is served no estimate and is unchanged, including its fixed PROCESS_TIMEOUT threshold. A deposit with no served estimate behaves exactly as it did in v0.16.x. See arrival estimates.

v0.15.x → v0.16.0

v0.16.0 removes the standalone claim modal. It is breaking, and the version number does not say so: under 0.x semver there is no major to spend, so a breaking change is a minor bump.

Use recovery from history instead

Pass signRecovery to DepositModal or WithdrawModal, and a failed row offers a Recover action. A deposit history never lists is reachable through the panel’s transaction-hash lookup. See history and recovery — nothing about that flow changes in this release. One capability leaves the package: the standalone lookup matched a transaction hash against any account, while history’s fallback is scoped to the account the modal is mounted for. Cross-account support cases go through the dashboard workflow.

Unaffected

The whole ClaimAnalytics* family stays, still importable from ., ./deposit and ./withdraw — recovery from history reports in it. So do SignRecovery, SignRecoveryPayload, RecoveryErrorCode, and createRefundHandler from @rhinestone/deposit-modal/server, which never depended on the modal.

The hosted page is not version-pinned

A host adopts the removed import on its own schedule, but the native embed is served by us. Claim mode disappears for every native host when the page deploys. Asking for it returns the page’s existing unsupported-mode error frame naming the mode.

v0.14.x → v0.15.0

v0.15.0 adds account-scoped history recovery to the deposit and withdraw modals. Existing integrations remain compatible: if you omit signRecovery, history is read-only and the fallback transaction-hash lookup is absent.

Enable recovery when the account can sign

Pass the existing SignRecovery callback to enable row recovery and account-scoped transaction-hash fallback. Deposit history always uses the configured recipient. Withdraw history follows the valid withdrawal destination, so provide the callback only if your app can sign for destinations users choose.
Omitting the prop needs no migration work. History remains visible and read-only; it does not show fallback lookup or a recovery status promise. The existing GET /deposits and POST /deposits/recover proxy routes serve the new flow. See history and recovery.

Use the destination verifier chain

SignRecoveryPayload.chainId existed before v0.15.0, but the standalone runtime previously supplied the source/refund chain. It now supplies the deposit destination chain, where the recipient’s EOA, ERC-1271, or ERC-6492 verifier lives. EOA signing is unaffected. A smart-account integration that selects account deployment data, owners, or an RPC by chain must select them with the supplied destination chainId. Do not derive the signing chain from the refund transaction.

Widen callbacks and exhaustive switches

History-originated recovery sends claim analytics through the host modal callback:
Make the equivalent change for WithdrawAnalyticsEvent. Inferred callback parameters update automatically. No claim lifecycle variants are added to deposit or withdraw onLifecycle. Exhaustive analytics switches must also handle the five *_modal_history_* variants documented in history analytics. Claim switches must accept entry_source values history_row and history_fallback, the optional cross-session correlation fields, and history_back in ClaimAnalyticsCloseSource. v0.15.0 publicly exports SignRecovery, SignRecoveryPayload, RecoveryErrorCode, HistoryStatus, HistoryAnalyticsBadge, HistoryClaimEntrySource, ClaimAnalyticsEntrySource, and ClaimAnalyticsCorrelation from the relevant root and modal entry points. The deposit and withdraw entry points also expose the existing claim analytics types required by their widened callbacks. There is no separate HistoryAnalyticsEvent; history variants are members of DepositAnalyticsEvent and WithdrawAnalyticsEvent.

v0.13.x → v0.14.0

v0.14.0 replaces the analytics contracts for all three modals and adds a session envelope. No flow, prop, or UI behavior changes, but annotated callback types and switches over old event names need updates.

Update callback and union handling

onEvent also delivers ingest failures. Widen explicitly annotated callbacks:
Do the same for WithdrawAnalyticsEvent and ClaimAnalyticsEvent. An inferred parameter needs no annotation change. This widening handles the diagnostic type only; it does not migrate switches over removed event names. ModalAnalyticsEvent now has four members: the three modal funnel unions plus AnalyticsIngestFailureEvent. Add an analytics_ingest_failure branch to exhaustive modal-wide switches.

Read funnel position from step

The v0.14.0 contracts remove last_step. Read step on every position-bearing event. Abandonment always has a non-null step. Close has the latest step, or step: null only when the session closes before entering the funnel. UI outcomes use the latest logical step and do not prove backend fulfillment.

Update reason routing

Friction means progress is blocked without a failed attempted operation. It carries step and reason, but no retryable. Failure means an attempted operation failed or the flow reached a terminal condition. It carries step, reason, and retryable. A retry is a subsequent explicit attempt after the reported reason. Bounded friction, failure, and retry reasons begin with an exported AnalyticsReasonFamily: account_setup, amount, exchange, lookup, migration, modal, processor, provider, quote, recipient, recovery, refund, regional_methods, registration, route, signature, submission, swapped, transfer, or wallet. Match the declared list longest-prefix first. Do not split at the first underscore. Abandonment, close-source, and ingest-diagnostic vocabularies are separate. Already-routable reason values are unchanged.

Replace deposit events

All eight v0.13.x events are removed. v0.14.0 uses a method-aware taxonomy with step and top-level funding_method. See the current deposit analytics contract. Balances, amounts, token labels, country, and shortcut CTA details leave the event stream with no replacement. Method selection and handoff now use method-aware identifier bags: Transfer handoff identities describe the source the user pays from, not the session target. source_chain is CAIP-2 (eip155:<id>, the Solana mainnet namespace, or hypercore:spot). source_token is the on-chain identity: lowercase for EVM and HyperCore hex values, case-sensitive for Solana mints, with native SOL represented by the system-program mint rather than native. The handoff uses a deposit_address correlator. Non-transfer handoffs use transaction_hash, deposit_id, or swapped_external_customer_id; those four correlator types can also appear on deposit_modal_correlator_observed. Do not treat the source displayed while the transfer picker is loading as the selected source. The handoff waits for the picker to settle and never publishes that temporary default. A session whose source never resolves emits step events but no transfer handoff; a later selection of a distinct source can emit another handoff. When rebuilding same-route deposit funnels, preserve the processing-step order. A transfer emits deposit_modal_step_open at transfer_tracking before deposit_modal_ui_outcome reports outcome: "completed" at that step. A wallet deposit does the same at wallet_processing. These completed outcomes are widget observations, not proof of backend or on-chain fulfillment. See the current deposit analytics contract.

Replace withdraw events

Both v0.13.x amount-screen events are removed. See the current withdraw events. Balances, amount, and token and chain labels leave the stream. withdraw_modal_handoff adds transaction_hash, managed_account, and same_route as the join identities and route classification. same_route is unknown before submit, pinned on handoff, and repeated on later events. Same-route withdrawals create no backend bridge row, so their UI outcome is only a client observation.

Replace claim events

All five v0.13.x events are replaced. See the current claim events. The handoff contains deposit_id, transaction_hash: string | null, and refund_transaction_hash. The first is the authoritative join key; transaction_hash is the deposit’s source transaction, and refund_transaction_hash is the submitted refund transaction. The searched hash, typed refund destination, deposit amount, chain, and HTTP status are not sent.

Read the session envelope

Every funnel event now carries session_id, modal, widget_version, timestamp, and modal-specific session_properties. Deposit events additionally carry top-level funding_method, which is null before method selection. The snapshot is taken when the modal opens and stays fixed for that session.
  • Deposit properties include enabled funding methods, wallet integration, fiat-method provenance, asset-migration providers and initial provider, gasless-wallet configuration, presentation, effective overlay-close configuration, prefill flags, and optional target dimensions.
  • Withdraw properties include presentation, effective overlay-close configuration, prefill flags, and optional target dimensions. The target is the destination on which the form opened, including its source fallback; flags record whether your app supplied it.
  • Claim properties include presentation, effective overlay-close configuration, and transaction-hash and refund-destination prefill flags.
target_chain is CAIP-2 and target_token is the on-chain identity. EVM and HyperCore hex values are lowercased; Solana mint case is preserved; native is allowed. Invalid target fields are omitted independently. Changing target props while the modal is open changes the flow but not this snapshot.

Forward POST /analytics/ingest-token

The browser mints a short-lived attribution token on your proxy. Events go directly to Rhinestone and never traverse your proxy. deposit-widget-proxy forwards this route already; for a custom proxy, add it to the allowlist and return Cache-Control: no-store. Skipping the route leaves sessions unattributed but does not stop collection or any modal flow. See the analytics token route.

Allow the ingest origin in connect-src

If your app sets an explicit content security policy, add https://v1.orchestrator.rhinestone.dev to connect-src. The directive must also include your proxy origin and any configured rpcUrls; see content security policy. A block surfaces only as analytics_ingest_failure with reason: "network". Apps without an explicit policy need no change.

v0.11.x → v0.12.0

Two changes: one proxy-side, one a single line to delete.

Forward GET /chains

The modal has read the chain set from /chains since v0.11.0, but it still carried a compiled-in table it fell back to. That table is gone. A proxy that does not forward the route no longer degrades to a built-in chain list — it leaves every picker empty, and the deposit flow reports that supported chains are unavailable. deposit-widget-proxy has forwarded it since 2026-08-11, so redeploying the packaged proxy is enough. A hand-written proxy needs the route added to its allowlist — see required routes. This is not a CORS change: it is a GET using headers the modal already sends, so it cannot break a preflight.
The upside of the removal is that the chain set is now whatever the backend serves, in both directions — a chain we add appears without a modal release, and one we withdraw stops being offered instead of lingering until you upgrade.

Delete uiConfig.showHistoryButton

Deposit history is now always available, so the flag has nothing left to switch. Delete the line; the button renders regardless, from the screen where the user picks a deposit method.
If your proxy does not forward GET /deposits, this is the release where that becomes visible: the panel is now reachable and shows the failure, where before the button could be switched off and the gap stayed hidden.

v0.8.x → v0.9.0

v0.9.0 moves both modals onto service-managed accounts, hands the withdrawal transfer to your app, and renames or removes props that no longer described what they did. The account and withdraw changes need code; the prop renames are mechanical.

Deploy your proxy first

Four of these changes are proxy-side and take effect the moment the new modal loads in a browser. None of them degrades — the request 404s, or the browser blocks it at preflight. See required routes for the full table. /setup-account and /register are no longer called and can be dropped once no older modal version is in use.
Bare Hono cors() is safe for the version header — with no allowHeaders it reflects whatever the preflight asks for. An explicit allow-list is what breaks, and it breaks on upgrade rather than on first deploy.
Both modals — the signerAddress and sessionChainIds props are gone, along with the DEFAULT_SIGNER_ADDRESS, EnableSessionDetails, and AccountInitData exports. Registration now goes through POST /register-managed, which a self-hosted proxy must forward before you ship — see required routes. There is no session key and no signature prompt during setup. <WithdrawModal> no longer moves funds. It previously built and submitted a Safe execTransaction, which only worked for apps whose funds sat in a Safe. It now asks your app to perform one transfer:
Send to to exactly, and return the on-chain transaction hash — not a userOp hash. See executing the transfer for both rules and a Safe-backed example, including how to keep gas sponsored. Also on <WithdrawModal>: onRequestConnect is removed (the modal needs no wallet, so there is no connect step — it opens on the withdraw form), the SafeTransactionRequest export is replaced by WithdrawTransferRequest, and the "submitted" lifecycle event renames safeAddress to accountAddress. POST /safe/withdraw still exists — the modal simply stopped calling it.

Renamed and removed props

Renames, plus the removal of config the server already owns. Nothing here changes what the modal can do.
dappAddress is removed with no replacement. The modal reads the address off walletClient.account, which nothing previously validated it against — so the modal could read balances for one address while the user was connected as another. allowedRoutes and the RouteConfig type are removed from both modals. They filtered the pickers client-side with nothing enforcing it, so a list that drifted from your deposit whitelist offered the user a source the processor then rejected. Set the whitelist via POST /setup; to offer a restricted subset, use an API key whose whitelist matches. enableSolana is removed for the same reason — Solana sources follow the deposit whitelist. uiConfig.checkLiquidity is removed. It cost an orchestrator round trip per continue to compute a warning the review screen never rendered. The cap is still checked and shown on the QR / transfer screen. rhinestoneApiKey is removed from both modals. It was never read — the key belongs on your backend proxy, which attaches it upstream. Delete it; nothing consumed it. FiatPaymentMethodOption is no longer exported. It described a row descriptor that fiatMethods no longer takes. backendUrl is now required on all three modals, and the DEFAULT_BACKEND_URL export is gone. The old default pointed at a Rhinestone-internal service running on our API key, so any integration that omitted the prop was silently routing its users’ deposits through it.
If you already set backendUrl, nothing changes. If you didn’t, you were on our key and need a proxy before upgrading. TypeScript flags the omission; each modal also logs a console.error when the value is missing, empty or whitespace, since backendUrl={process.env.X ?? ""} typechecks fine. fiatOnrampMethods becomes fiatMethods, a boolean map keyed by Swapped payment_group instead of a list of row descriptors:
The old prop made you supply each row’s label, sublabel and icon, which meant pasting our copy and freezing a claim like "Instant - $10,000 limit" into your bundle.
fiatOnrampMethods={[]} used to fall through to offering every payment method. An empty or all-false fiatMethods now offers none. If you computed the list dynamically and could produce an empty one, check which you wanted.

Optional where it was mandatory

<WithdrawModal>’s targetChain and targetToken are now optional. They only ever seeded the form — the user can pick any supported destination — so omitting them opens on a same-chain, same-token withdrawal. @reown/appkit and @reown/appkit-adapter-wagmi are now optional peer dependencies. An app that passes its own walletClient never opens AppKit and no longer needs it installed. See install.

New

  • enableWallet?: boolean (default true) on <DepositModal> — turn off to present a flow with no wallet even when a walletClient or reownAppId is supplied.
  • <ClaimModal> and the ./claim subpath — a standalone transaction-hash lookup that returned a failed or rejected deposit’s funds. Removed in v0.16.0; use history and recovery instead.

Behavior changes worth checking

  • connected no longer fires for flows with no wallet (QR, fiat, exchange). It previously reported the declared address as though a wallet had connected. If you used it as a “flow started” signal, switch to onReady.
  • A QR-only integration no longer auto-locks to the wallet. The connect step’s auto-skip never accounted for enableQrTransfer or asset migrations, so it could skip past the only funding option you had enabled.
  • Logos load from Rhinestone’s asset CDN. Apps with an explicit img-src CSP must allow https://s3.rhinestone.dev — a blocked image fails silently. See content security policy.
  • HYPERCORE_RECIPIENT_NOT_EOA is no longer emitted. HyperCore deposits now accept a smart-account recipient, and the pre-screen that blocked one is gone. If you branch on that onError code, the branch is dead.
  • A chain your deposit whitelist allows nothing on is no longer offered in the QR flow’s chain picker, instead of appearing with built-in tokens the deposit would then be rejected for. Chains the shortlist says nothing about keep their existing set.
  • Fiat payment methods are personalized by region unless you pass fiatMethods. See regional payment methods.
  • The deposit review shows a single “Fees” row. The per-category breakdown and its tooltips are gone; uiConfig.feeSponsored and uiConfig.feeTooltip still apply on the processing and result screens.

Removed prop warnings

Both modals log a console.error naming the replacement when passed any prop removed in this release. TypeScript already catches these; the runtime warning is for plain JavaScript hosts, spread props, and loosely typed call sites, where several of the removals fail silently rather than visibly.

v0.1.x / v0.2.x → v0.3.0

v0.3.0 collapses each modal’s per-event callbacks into a single onLifecycle callback, renames the analytics event types, removes the /reown and /safe subpath entry points, and drops connectButtonLabel. <DepositModal> and <WithdrawModal> share the same callback shape, but their lifecycle payloads are not identical — see Asymmetries below.

Callback collapse — onLifecycle

Both modals replace their individual callbacks with one onLifecycle that receives a discriminated event. Switch on event.type; the payload fields keep the same names as before.
DepositModal
See status tracking for the full event payloads.

Asymmetries

The two unions look alike but differ — don’t assume one helper typechecks against both.
sourceChain: "unknown" is deposit-only. A webhook-detected deposit can arrive without chain or token info, in which case deposit events carry sourceChain: "unknown" and sourceToken: undefined. Handle this branch in your deposit onLifecycle switch — the wrong branch picks the wrong explorer URL. Withdraw flows always know the source chain.

Analytics type rename

The onEvent prop name is unchanged on both modals, but its parameter type was renamed. The payload shape is unchanged.

Removed

  • connectButtonLabel — gone from both modals. The connect-step copy is controlled internally; delete any consumer-side label, there is no replacement.
  • /reown and /safe subpath imports — they re-exported nothing that isn’t already on the root entry point.
    The ./deposit, ./withdraw, ./constants, and ./styles.css subpaths remain for tree-shaking.

Additive — no action required

New in v0.3.0; existing code keeps working:
  • appBalanceUsd?: number on <DepositModal> — renders a “Balance after deposit” row (appBalanceUsd + amount) instead of fetching a portfolio balance.
  • dappImports?: DappImportsConfig on <DepositModal> — pull balances from third-party apps. See migrating assets.
  • defaultAmount: "max" — defaults the input to the user’s full source-token balance.
  • Solana destinationstargetChain: Chain | number | "solana", targetToken: Address | string, recipient: Address | string.
  • New root exportsDepositLifecycleEvent, WithdrawLifecycleEvent, DappImportsConfig, OutputTokenRule, plus the renamed analytics types.

Unchanged

onError, onReady, onRequestConnect, the onEvent prop name, dappWalletClient / dappPublicClient / reownAppId, <WithdrawModal>’s onSignTransaction, and the @rhinestone/deposit-modal/styles.css export all keep their names and signatures.
Scoped to v0.3.0. Several of these changed again in v0.9.0 — see the v0.8.x → v0.9.0 section at the top of this page.