@rhinestone/deposit-modal 0.1.19 → 0.1.20

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.
package/README.md CHANGED
@@ -124,6 +124,28 @@ import "@rhinestone/deposit-modal/styles.css";
124
124
  />
125
125
  ```
126
126
 
127
+ ### Withdrawal flow
128
+
129
+ Prerequisites:
130
+ - A 1/1 Safe (single owner) with ERC20 token balance on a supported source chain
131
+ - The connected wallet must be the sole owner of the Safe
132
+
133
+ End-to-end steps:
134
+ 1. User connects wallet (must be the Safe owner)
135
+ 2. Modal creates a Rhinestone smart account and signs session authorization
136
+ 3. Modal registers the smart account with the backend (`/register`)
137
+ 4. User enters withdrawal amount
138
+ 5. User signs an EIP-712 `execTransaction` authorizing the ERC20 transfer from the Safe to the smart account
139
+ 6. Modal calls `/process/:address` to trigger the bridge intent
140
+ 7. Modal polls `/status/:address` for webhook events until the bridge completes on the destination chain
141
+
142
+ To test with the demo configurator:
143
+ 1. Switch flow to "Withdraw"
144
+ 2. Enter the Safe address
145
+ 3. Select the source chain/token matching the Safe's holdings
146
+ 4. Select the destination chain/token
147
+ 5. The connected wallet (Privy embedded or Reown) must be the Safe's sole owner
148
+
127
149
  ### Additional Props (beyond shared DepositModal props)
128
150
 
129
151
  | Prop | Type | Required | Description |
@@ -156,7 +178,7 @@ Also supports `onReady`, `onConnected`, and `onError` (same as DepositModal).
156
178
 
157
179
  **Branding**: `logoUrl`, `title`
158
180
 
159
- **UI Config**: `showLogo`, `showStepper`, `showBackButton`, `balanceTitle`, `maxDepositUsd`
181
+ **UI Config**: `showLogo`, `showStepper`, `showBackButton`, `balanceTitle`, `maxDepositUsd`, `minDepositUsd`
160
182
 
161
183
  ## Utility Exports
162
184
 
package/dist/index.cjs CHANGED
@@ -1937,6 +1937,12 @@ function AmountStep({
1937
1937
  );
1938
1938
  return;
1939
1939
  }
1940
+ if (uiConfig?.minDepositUsd && usdValue < uiConfig.minDepositUsd) {
1941
+ setError(
1942
+ `Minimum deposit is ${currencyFormatter.format(uiConfig.minDepositUsd)}`
1943
+ );
1944
+ return;
1945
+ }
1940
1946
  if (tokenPriceUsd === null || tokenPriceUsd === 0) {
1941
1947
  setError("Unable to determine token price");
1942
1948
  return;
@@ -2525,8 +2531,8 @@ function getEventTxHash(event) {
2525
2531
  return asString(event.data?.transactionHash);
2526
2532
  }
2527
2533
  if (event.type === "bridge-started" || event.type === "bridge-complete") {
2528
- const source = isRecord(event.data?.source) ? event.data.source : void 0;
2529
- return asString(source?.transactionHash);
2534
+ const deposit = isRecord(event.data?.deposit) ? event.data.deposit : void 0;
2535
+ return asString(deposit?.transactionHash);
2530
2536
  }
2531
2537
  if (event.type === "bridge-failed" || event.type === "error") {
2532
2538
  const deposit = isRecord(event.data?.deposit) ? event.data.deposit : void 0;
@@ -2575,6 +2581,7 @@ function ProcessingStep({
2575
2581
  waitForFinalTx,
2576
2582
  service,
2577
2583
  flowLabel = "deposit",
2584
+ debug,
2578
2585
  onClose,
2579
2586
  onNewDeposit,
2580
2587
  onDepositComplete,
@@ -2585,7 +2592,6 @@ function ProcessingStep({
2585
2592
  const [elapsedSeconds, setElapsedSeconds] = (0, import_react6.useState)(0);
2586
2593
  const startTimeRef = (0, import_react6.useRef)(Date.now());
2587
2594
  const intervalRef = (0, import_react6.useRef)(null);
2588
- const sameChainAndToken = targetChain === sourceChain && targetToken.toLowerCase() === sourceToken.toLowerCase();
2589
2595
  (0, import_react6.useEffect)(() => {
2590
2596
  startTimeRef.current = Date.now();
2591
2597
  intervalRef.current = setInterval(() => {
@@ -2618,6 +2624,15 @@ function ProcessingStep({
2618
2624
  const lastEvent2 = data.lastEvent;
2619
2625
  const eventMatchesTx = isEventForTx(lastEvent2, txHash);
2620
2626
  const eventForCurrentTx = eventMatchesTx ? lastEvent2 : void 0;
2627
+ if (debug && lastEvent2) {
2628
+ const eventData = lastEvent2.data;
2629
+ console.log("[deposit-modal] status poll", {
2630
+ type: lastEvent2.type,
2631
+ matchesTx: eventMatchesTx,
2632
+ intentId: eventData?.intentId,
2633
+ data: eventData
2634
+ });
2635
+ }
2621
2636
  if (!isMounted) return;
2622
2637
  if (eventForCurrentTx?.type === "bridge-complete") {
2623
2638
  setState({ type: "complete", lastEvent: eventForCurrentTx });
@@ -2630,11 +2645,6 @@ function ProcessingStep({
2630
2645
  onDepositComplete?.(txHash);
2631
2646
  return;
2632
2647
  }
2633
- if (eventForCurrentTx?.type === "deposit-received" && sameChainAndToken) {
2634
- setState({ type: "complete", lastEvent: eventForCurrentTx });
2635
- onDepositComplete?.(txHash);
2636
- return;
2637
- }
2638
2648
  if (eventForCurrentTx?.type === "bridge-failed") {
2639
2649
  const formatted = formatBridgeFailedMessage(eventForCurrentTx);
2640
2650
  setState({
@@ -2683,7 +2693,6 @@ function ProcessingStep({
2683
2693
  smartAccount,
2684
2694
  txHash,
2685
2695
  service,
2686
- sameChainAndToken,
2687
2696
  waitForFinalTx,
2688
2697
  onDepositComplete,
2689
2698
  onDepositFailed
@@ -3572,7 +3581,8 @@ function DepositFlow({
3572
3581
  onDepositSubmitted,
3573
3582
  onDepositComplete,
3574
3583
  onDepositFailed,
3575
- onError
3584
+ onError,
3585
+ debug
3576
3586
  }) {
3577
3587
  const [step, setStep] = (0, import_react9.useState)({ type: "setup" });
3578
3588
  const [flowMode, setFlowMode] = (0, import_react9.useState)(null);
@@ -3912,7 +3922,8 @@ function DepositFlow({
3912
3922
  onNewDeposit: handleNewDeposit,
3913
3923
  onDepositComplete: handleDepositComplete,
3914
3924
  onDepositFailed: handleDepositFailed,
3915
- onError: handleError
3925
+ onError: handleError,
3926
+ debug
3916
3927
  }
3917
3928
  )
3918
3929
  ] });
@@ -4238,7 +4249,8 @@ function DepositModalInner({
4238
4249
  onDepositSubmitted,
4239
4250
  onDepositComplete,
4240
4251
  onDepositFailed,
4241
- onError
4252
+ onError,
4253
+ debug
4242
4254
  }) {
4243
4255
  const modalRef = (0, import_react13.useRef)(null);
4244
4256
  const [currentStepIndex, setCurrentStepIndex] = (0, import_react13.useState)(0);
@@ -4406,7 +4418,8 @@ function DepositModalInner({
4406
4418
  onDepositSubmitted,
4407
4419
  onDepositComplete,
4408
4420
  onDepositFailed,
4409
- onError
4421
+ onError,
4422
+ debug
4410
4423
  }
4411
4424
  )
4412
4425
  ] })
@@ -5207,7 +5220,8 @@ function WithdrawFlow({
5207
5220
  onWithdrawSubmitted,
5208
5221
  onWithdrawComplete,
5209
5222
  onWithdrawFailed,
5210
- onError
5223
+ onError,
5224
+ debug
5211
5225
  }) {
5212
5226
  const [step, setStep] = (0, import_react15.useState)({ type: "form" });
5213
5227
  const [isSubmitting, setIsSubmitting] = (0, import_react15.useState)(false);
@@ -5596,7 +5610,8 @@ function WithdrawFlow({
5596
5610
  onNewDeposit: () => setStep({ type: "form" }),
5597
5611
  onDepositComplete: handleWithdrawComplete,
5598
5612
  onDepositFailed: handleWithdrawFailed,
5599
- onError: handleError
5613
+ onError: handleError,
5614
+ debug
5600
5615
  }
5601
5616
  )
5602
5617
  ] });
@@ -5697,7 +5712,8 @@ function WithdrawModalInner({
5697
5712
  onWithdrawSubmitted,
5698
5713
  onWithdrawComplete,
5699
5714
  onWithdrawFailed,
5700
- onError
5715
+ onError,
5716
+ debug
5701
5717
  }) {
5702
5718
  const modalRef = (0, import_react17.useRef)(null);
5703
5719
  const [currentStepIndex, setCurrentStepIndex] = (0, import_react17.useState)(0);
@@ -5863,7 +5879,8 @@ function WithdrawModalInner({
5863
5879
  onWithdrawSubmitted,
5864
5880
  onWithdrawComplete,
5865
5881
  onWithdrawFailed,
5866
- onError
5882
+ onError,
5883
+ debug
5867
5884
  }
5868
5885
  )
5869
5886
  ] })
package/dist/index.d.cts CHANGED
@@ -19,6 +19,7 @@ interface DepositModalUIConfig {
19
19
  showBackButton?: boolean;
20
20
  balanceTitle?: string;
21
21
  maxDepositUsd?: number;
22
+ minDepositUsd?: number;
22
23
  }
23
24
  interface DepositModalBranding {
24
25
  logoUrl?: string;
@@ -91,6 +92,7 @@ interface DepositModalProps {
91
92
  onDepositComplete?: (data: DepositCompleteEventData) => void;
92
93
  onDepositFailed?: (data: DepositFailedEventData) => void;
93
94
  onError?: (data: ErrorEventData) => void;
95
+ debug?: boolean;
94
96
  }
95
97
  interface WithdrawSignParams {
96
98
  safeAddress: Address;
@@ -136,6 +138,7 @@ interface WithdrawModalProps {
136
138
  onWithdrawComplete?: (data: WithdrawCompleteEventData) => void;
137
139
  onWithdrawFailed?: (data: WithdrawFailedEventData) => void;
138
140
  onError?: (data: ErrorEventData) => void;
141
+ debug?: boolean;
139
142
  }
140
143
  interface AssetOption {
141
144
  id: string;
package/dist/index.d.ts CHANGED
@@ -19,6 +19,7 @@ interface DepositModalUIConfig {
19
19
  showBackButton?: boolean;
20
20
  balanceTitle?: string;
21
21
  maxDepositUsd?: number;
22
+ minDepositUsd?: number;
22
23
  }
23
24
  interface DepositModalBranding {
24
25
  logoUrl?: string;
@@ -91,6 +92,7 @@ interface DepositModalProps {
91
92
  onDepositComplete?: (data: DepositCompleteEventData) => void;
92
93
  onDepositFailed?: (data: DepositFailedEventData) => void;
93
94
  onError?: (data: ErrorEventData) => void;
95
+ debug?: boolean;
94
96
  }
95
97
  interface WithdrawSignParams {
96
98
  safeAddress: Address;
@@ -136,6 +138,7 @@ interface WithdrawModalProps {
136
138
  onWithdrawComplete?: (data: WithdrawCompleteEventData) => void;
137
139
  onWithdrawFailed?: (data: WithdrawFailedEventData) => void;
138
140
  onError?: (data: ErrorEventData) => void;
141
+ debug?: boolean;
139
142
  }
140
143
  interface AssetOption {
141
144
  id: string;
package/dist/index.mjs CHANGED
@@ -1925,6 +1925,12 @@ function AmountStep({
1925
1925
  );
1926
1926
  return;
1927
1927
  }
1928
+ if (uiConfig?.minDepositUsd && usdValue < uiConfig.minDepositUsd) {
1929
+ setError(
1930
+ `Minimum deposit is ${currencyFormatter.format(uiConfig.minDepositUsd)}`
1931
+ );
1932
+ return;
1933
+ }
1928
1934
  if (tokenPriceUsd === null || tokenPriceUsd === 0) {
1929
1935
  setError("Unable to determine token price");
1930
1936
  return;
@@ -2509,8 +2515,8 @@ function getEventTxHash(event) {
2509
2515
  return asString(event.data?.transactionHash);
2510
2516
  }
2511
2517
  if (event.type === "bridge-started" || event.type === "bridge-complete") {
2512
- const source = isRecord(event.data?.source) ? event.data.source : void 0;
2513
- return asString(source?.transactionHash);
2518
+ const deposit = isRecord(event.data?.deposit) ? event.data.deposit : void 0;
2519
+ return asString(deposit?.transactionHash);
2514
2520
  }
2515
2521
  if (event.type === "bridge-failed" || event.type === "error") {
2516
2522
  const deposit = isRecord(event.data?.deposit) ? event.data.deposit : void 0;
@@ -2562,6 +2568,7 @@ function ProcessingStep({
2562
2568
  waitForFinalTx,
2563
2569
  service,
2564
2570
  flowLabel = "deposit",
2571
+ debug,
2565
2572
  onClose,
2566
2573
  onNewDeposit,
2567
2574
  onDepositComplete,
@@ -2572,7 +2579,6 @@ function ProcessingStep({
2572
2579
  const [elapsedSeconds, setElapsedSeconds] = useState5(0);
2573
2580
  const startTimeRef = useRef4(Date.now());
2574
2581
  const intervalRef = useRef4(null);
2575
- const sameChainAndToken = targetChain === sourceChain && targetToken.toLowerCase() === sourceToken.toLowerCase();
2576
2582
  useEffect5(() => {
2577
2583
  startTimeRef.current = Date.now();
2578
2584
  intervalRef.current = setInterval(() => {
@@ -2605,6 +2611,15 @@ function ProcessingStep({
2605
2611
  const lastEvent2 = data.lastEvent;
2606
2612
  const eventMatchesTx = isEventForTx(lastEvent2, txHash);
2607
2613
  const eventForCurrentTx = eventMatchesTx ? lastEvent2 : void 0;
2614
+ if (debug && lastEvent2) {
2615
+ const eventData = lastEvent2.data;
2616
+ console.log("[deposit-modal] status poll", {
2617
+ type: lastEvent2.type,
2618
+ matchesTx: eventMatchesTx,
2619
+ intentId: eventData?.intentId,
2620
+ data: eventData
2621
+ });
2622
+ }
2608
2623
  if (!isMounted) return;
2609
2624
  if (eventForCurrentTx?.type === "bridge-complete") {
2610
2625
  setState({ type: "complete", lastEvent: eventForCurrentTx });
@@ -2617,11 +2632,6 @@ function ProcessingStep({
2617
2632
  onDepositComplete?.(txHash);
2618
2633
  return;
2619
2634
  }
2620
- if (eventForCurrentTx?.type === "deposit-received" && sameChainAndToken) {
2621
- setState({ type: "complete", lastEvent: eventForCurrentTx });
2622
- onDepositComplete?.(txHash);
2623
- return;
2624
- }
2625
2635
  if (eventForCurrentTx?.type === "bridge-failed") {
2626
2636
  const formatted = formatBridgeFailedMessage(eventForCurrentTx);
2627
2637
  setState({
@@ -2670,7 +2680,6 @@ function ProcessingStep({
2670
2680
  smartAccount,
2671
2681
  txHash,
2672
2682
  service,
2673
- sameChainAndToken,
2674
2683
  waitForFinalTx,
2675
2684
  onDepositComplete,
2676
2685
  onDepositFailed
@@ -3557,7 +3566,8 @@ function DepositFlow({
3557
3566
  onDepositSubmitted,
3558
3567
  onDepositComplete,
3559
3568
  onDepositFailed,
3560
- onError
3569
+ onError,
3570
+ debug
3561
3571
  }) {
3562
3572
  const [step, setStep] = useState7({ type: "setup" });
3563
3573
  const [flowMode, setFlowMode] = useState7(null);
@@ -3897,7 +3907,8 @@ function DepositFlow({
3897
3907
  onNewDeposit: handleNewDeposit,
3898
3908
  onDepositComplete: handleDepositComplete,
3899
3909
  onDepositFailed: handleDepositFailed,
3900
- onError: handleError
3910
+ onError: handleError,
3911
+ debug
3901
3912
  }
3902
3913
  )
3903
3914
  ] });
@@ -4236,7 +4247,8 @@ function DepositModalInner({
4236
4247
  onDepositSubmitted,
4237
4248
  onDepositComplete,
4238
4249
  onDepositFailed,
4239
- onError
4250
+ onError,
4251
+ debug
4240
4252
  }) {
4241
4253
  const modalRef = useRef7(null);
4242
4254
  const [currentStepIndex, setCurrentStepIndex] = useState9(0);
@@ -4404,7 +4416,8 @@ function DepositModalInner({
4404
4416
  onDepositSubmitted,
4405
4417
  onDepositComplete,
4406
4418
  onDepositFailed,
4407
- onError
4419
+ onError,
4420
+ debug
4408
4421
  }
4409
4422
  )
4410
4423
  ] })
@@ -5214,7 +5227,8 @@ function WithdrawFlow({
5214
5227
  onWithdrawSubmitted,
5215
5228
  onWithdrawComplete,
5216
5229
  onWithdrawFailed,
5217
- onError
5230
+ onError,
5231
+ debug
5218
5232
  }) {
5219
5233
  const [step, setStep] = useState11({ type: "form" });
5220
5234
  const [isSubmitting, setIsSubmitting] = useState11(false);
@@ -5603,7 +5617,8 @@ function WithdrawFlow({
5603
5617
  onNewDeposit: () => setStep({ type: "form" }),
5604
5618
  onDepositComplete: handleWithdrawComplete,
5605
5619
  onDepositFailed: handleWithdrawFailed,
5606
- onError: handleError
5620
+ onError: handleError,
5621
+ debug
5607
5622
  }
5608
5623
  )
5609
5624
  ] });
@@ -5708,7 +5723,8 @@ function WithdrawModalInner({
5708
5723
  onWithdrawSubmitted,
5709
5724
  onWithdrawComplete,
5710
5725
  onWithdrawFailed,
5711
- onError
5726
+ onError,
5727
+ debug
5712
5728
  }) {
5713
5729
  const modalRef = useRef9(null);
5714
5730
  const [currentStepIndex, setCurrentStepIndex] = useState12(0);
@@ -5874,7 +5890,8 @@ function WithdrawModalInner({
5874
5890
  onWithdrawSubmitted,
5875
5891
  onWithdrawComplete,
5876
5892
  onWithdrawFailed,
5877
- onError
5893
+ onError,
5894
+ debug
5878
5895
  }
5879
5896
  )
5880
5897
  ] })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rhinestone/deposit-modal",
3
- "version": "0.1.19",
3
+ "version": "0.1.20",
4
4
  "description": "React modal component for Rhinestone cross-chain deposits",
5
5
  "author": "Rhinestone <dev@rhinestone.wtf>",
6
6
  "bugs": {