@rhinestone/deposit-modal 0.1.3 → 0.1.4
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/dist/index.cjs +197 -66
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.mjs +213 -79
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1955,6 +1955,7 @@ var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
|
1955
1955
|
var INITIAL_POLL_INTERVAL = 3e3;
|
|
1956
1956
|
var MAX_POLL_INTERVAL = 3e4;
|
|
1957
1957
|
var BACKOFF_MULTIPLIER = 1.5;
|
|
1958
|
+
var PROCESS_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
1958
1959
|
function ProcessingStep({
|
|
1959
1960
|
publicClient,
|
|
1960
1961
|
smartAccount,
|
|
@@ -2010,6 +2011,13 @@ function ProcessingStep({
|
|
|
2010
2011
|
}
|
|
2011
2012
|
try {
|
|
2012
2013
|
await publicClient.waitForTransactionReceipt({ hash: txHash });
|
|
2014
|
+
} catch (error) {
|
|
2015
|
+
const message = error instanceof Error ? error.message : "Transaction not confirmed";
|
|
2016
|
+
setState({ type: "error", message });
|
|
2017
|
+
onError?.(message, "PROCESS_ERROR");
|
|
2018
|
+
return;
|
|
2019
|
+
}
|
|
2020
|
+
try {
|
|
2013
2021
|
const result = await service.processDeposit(smartAccount, {
|
|
2014
2022
|
chainId: sourceChain,
|
|
2015
2023
|
token: sourceToken,
|
|
@@ -2017,22 +2025,24 @@ function ProcessingStep({
|
|
|
2017
2025
|
txHash,
|
|
2018
2026
|
sender
|
|
2019
2027
|
});
|
|
2020
|
-
if (result.
|
|
2028
|
+
if (result.message.includes("Funds are already on the target chain")) {
|
|
2021
2029
|
if (sameChainAndToken) {
|
|
2022
2030
|
setState({ type: "complete" });
|
|
2023
2031
|
onDepositComplete?.(txHash);
|
|
2024
|
-
|
|
2025
|
-
const message = `Processor returned same-chain response. Re-register the account for target chain ${targetChain}.`;
|
|
2026
|
-
setState({ type: "error", message });
|
|
2027
|
-
onError?.(message, "TARGET_CHAIN_MISMATCH");
|
|
2032
|
+
return;
|
|
2028
2033
|
}
|
|
2034
|
+
setState({ type: "processing" });
|
|
2035
|
+
return;
|
|
2036
|
+
}
|
|
2037
|
+
if (result.status === 202) {
|
|
2038
|
+
setState({ type: "processing" });
|
|
2029
2039
|
return;
|
|
2030
2040
|
}
|
|
2031
2041
|
setState({ type: "processing" });
|
|
2032
2042
|
} catch (error) {
|
|
2033
2043
|
const message = error instanceof Error ? error.message : "Process failed";
|
|
2034
|
-
setState({ type: "
|
|
2035
|
-
onError?.(message, "
|
|
2044
|
+
setState({ type: "processing", warning: message });
|
|
2045
|
+
onError?.(message, "PROCESS_FALLBACK");
|
|
2036
2046
|
}
|
|
2037
2047
|
}
|
|
2038
2048
|
triggerProcess();
|
|
@@ -2051,7 +2061,8 @@ function ProcessingStep({
|
|
|
2051
2061
|
onError
|
|
2052
2062
|
]);
|
|
2053
2063
|
const pollIntervalRef = (0, import_react6.useRef)(INITIAL_POLL_INTERVAL);
|
|
2054
|
-
const
|
|
2064
|
+
const pollTimeoutRef = (0, import_react6.useRef)(null);
|
|
2065
|
+
const processTimeoutRef = (0, import_react6.useRef)(null);
|
|
2055
2066
|
(0, import_react6.useEffect)(() => {
|
|
2056
2067
|
if (state.type !== "processing") {
|
|
2057
2068
|
pollIntervalRef.current = INITIAL_POLL_INTERVAL;
|
|
@@ -2099,7 +2110,7 @@ function ProcessingStep({
|
|
|
2099
2110
|
}
|
|
2100
2111
|
function scheduleNextPoll() {
|
|
2101
2112
|
if (!isMounted) return;
|
|
2102
|
-
|
|
2113
|
+
pollTimeoutRef.current = setTimeout(() => {
|
|
2103
2114
|
pollIntervalRef.current = Math.min(
|
|
2104
2115
|
pollIntervalRef.current * BACKOFF_MULTIPLIER,
|
|
2105
2116
|
MAX_POLL_INTERVAL
|
|
@@ -2110,8 +2121,8 @@ function ProcessingStep({
|
|
|
2110
2121
|
pollStatus();
|
|
2111
2122
|
return () => {
|
|
2112
2123
|
isMounted = false;
|
|
2113
|
-
if (
|
|
2114
|
-
clearTimeout(
|
|
2124
|
+
if (pollTimeoutRef.current) {
|
|
2125
|
+
clearTimeout(pollTimeoutRef.current);
|
|
2115
2126
|
}
|
|
2116
2127
|
};
|
|
2117
2128
|
}, [
|
|
@@ -2124,6 +2135,26 @@ function ProcessingStep({
|
|
|
2124
2135
|
onDepositComplete,
|
|
2125
2136
|
onDepositFailed
|
|
2126
2137
|
]);
|
|
2138
|
+
(0, import_react6.useEffect)(() => {
|
|
2139
|
+
if (state.type !== "processing") {
|
|
2140
|
+
if (processTimeoutRef.current) {
|
|
2141
|
+
clearTimeout(processTimeoutRef.current);
|
|
2142
|
+
processTimeoutRef.current = null;
|
|
2143
|
+
}
|
|
2144
|
+
return;
|
|
2145
|
+
}
|
|
2146
|
+
processTimeoutRef.current = setTimeout(() => {
|
|
2147
|
+
const message = "We couldn't confirm your transfer. Please contact support if funds do not arrive.";
|
|
2148
|
+
setState({ type: "error", message });
|
|
2149
|
+
onError?.(message, "PROCESS_TIMEOUT");
|
|
2150
|
+
}, PROCESS_TIMEOUT_MS);
|
|
2151
|
+
return () => {
|
|
2152
|
+
if (processTimeoutRef.current) {
|
|
2153
|
+
clearTimeout(processTimeoutRef.current);
|
|
2154
|
+
processTimeoutRef.current = null;
|
|
2155
|
+
}
|
|
2156
|
+
};
|
|
2157
|
+
}, [state.type, onError]);
|
|
2127
2158
|
const isError = state.type === "error" || state.type === "failed";
|
|
2128
2159
|
const isComplete = state.type === "complete";
|
|
2129
2160
|
const isProcessing = state.type === "triggering" || state.type === "processing";
|
|
@@ -2376,6 +2407,27 @@ function ProcessingStep({
|
|
|
2376
2407
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rs-step-body rs-space-y-3", children: [
|
|
2377
2408
|
isProcessing && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
2378
2409
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "rs-progress-bar", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "rs-progress-bar-fill rs-progress-bar-fill--indeterminate" }) }),
|
|
2410
|
+
state.type === "processing" && state.warning && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rs-alert rs-alert--warning", children: [
|
|
2411
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2412
|
+
"svg",
|
|
2413
|
+
{
|
|
2414
|
+
className: "rs-alert-icon",
|
|
2415
|
+
viewBox: "0 0 24 24",
|
|
2416
|
+
fill: "none",
|
|
2417
|
+
stroke: "currentColor",
|
|
2418
|
+
strokeWidth: "2",
|
|
2419
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2420
|
+
"path",
|
|
2421
|
+
{
|
|
2422
|
+
strokeLinecap: "round",
|
|
2423
|
+
strokeLinejoin: "round",
|
|
2424
|
+
d: "M12 9v3.75m9-.75a9 9 0 11-18 0 9 9 0 0118 0zm-9 3.75h.008v.008H12v-.008z"
|
|
2425
|
+
}
|
|
2426
|
+
)
|
|
2427
|
+
}
|
|
2428
|
+
),
|
|
2429
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "rs-alert-text", children: "We couldn't reach the processor. We'll keep checking for a webhook update." })
|
|
2430
|
+
] }),
|
|
2379
2431
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rs-alert rs-alert--info", children: [
|
|
2380
2432
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2381
2433
|
"svg",
|
|
@@ -2513,6 +2565,7 @@ function DepositFlow({
|
|
|
2513
2565
|
amount: defaultAmount,
|
|
2514
2566
|
recipient,
|
|
2515
2567
|
signerAddress = DEFAULT_SIGNER_ADDRESS,
|
|
2568
|
+
forceRegister = true,
|
|
2516
2569
|
waitForFinalTx = true,
|
|
2517
2570
|
onRequestConnect,
|
|
2518
2571
|
connectButtonLabel,
|
|
@@ -2529,6 +2582,16 @@ function DepositFlow({
|
|
|
2529
2582
|
const [step, setStep] = (0, import_react7.useState)({ type: "setup" });
|
|
2530
2583
|
const [totalBalanceUsd, setTotalBalanceUsd] = (0, import_react7.useState)(0);
|
|
2531
2584
|
const targetChainObj = (0, import_react7.useMemo)(() => CHAIN_BY_ID[targetChain], [targetChain]);
|
|
2585
|
+
const lastTargetRef = (0, import_react7.useRef)(null);
|
|
2586
|
+
(0, import_react7.useEffect)(() => {
|
|
2587
|
+
const prev = lastTargetRef.current;
|
|
2588
|
+
if (prev && (prev.chain !== targetChain || prev.token.toLowerCase() !== targetToken.toLowerCase())) {
|
|
2589
|
+
if (step.type !== "processing") {
|
|
2590
|
+
setStep({ type: "setup" });
|
|
2591
|
+
}
|
|
2592
|
+
}
|
|
2593
|
+
lastTargetRef.current = { chain: targetChain, token: targetToken };
|
|
2594
|
+
}, [targetChain, targetToken, step.type]);
|
|
2532
2595
|
const handleBackFromAmount = (0, import_react7.useCallback)(() => {
|
|
2533
2596
|
setStep((prev) => {
|
|
2534
2597
|
if (prev.type !== "amount") return prev;
|
|
@@ -2658,6 +2721,7 @@ function DepositFlow({
|
|
|
2658
2721
|
targetToken,
|
|
2659
2722
|
signerAddress,
|
|
2660
2723
|
recipient,
|
|
2724
|
+
forceRegister,
|
|
2661
2725
|
service,
|
|
2662
2726
|
onSetupComplete: handleSetupComplete,
|
|
2663
2727
|
onConnected: handleConnected,
|
|
@@ -2795,6 +2859,7 @@ function DepositModal({
|
|
|
2795
2859
|
recipient,
|
|
2796
2860
|
backendUrl = DEFAULT_BACKEND_URL,
|
|
2797
2861
|
signerAddress = DEFAULT_SIGNER_ADDRESS,
|
|
2862
|
+
forceRegister = true,
|
|
2798
2863
|
waitForFinalTx = true,
|
|
2799
2864
|
onRequestConnect,
|
|
2800
2865
|
connectButtonLabel,
|
|
@@ -2960,6 +3025,7 @@ function DepositModal({
|
|
|
2960
3025
|
amount: defaultAmount,
|
|
2961
3026
|
recipient,
|
|
2962
3027
|
signerAddress,
|
|
3028
|
+
forceRegister,
|
|
2963
3029
|
waitForFinalTx,
|
|
2964
3030
|
onRequestConnect,
|
|
2965
3031
|
connectButtonLabel,
|
|
@@ -3494,13 +3560,6 @@ var import_sdk3 = require("@rhinestone/sdk");
|
|
|
3494
3560
|
// src/core/safe.ts
|
|
3495
3561
|
var import_viem8 = require("viem");
|
|
3496
3562
|
var SAFE_ABI = [
|
|
3497
|
-
{
|
|
3498
|
-
type: "function",
|
|
3499
|
-
name: "nonce",
|
|
3500
|
-
stateMutability: "view",
|
|
3501
|
-
inputs: [],
|
|
3502
|
-
outputs: [{ name: "", type: "uint256" }]
|
|
3503
|
-
},
|
|
3504
3563
|
{
|
|
3505
3564
|
type: "function",
|
|
3506
3565
|
name: "isOwner",
|
|
@@ -3545,20 +3604,88 @@ var SAFE_ABI = [
|
|
|
3545
3604
|
anonymous: false
|
|
3546
3605
|
}
|
|
3547
3606
|
];
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
}
|
|
3607
|
+
async function executeSafeEthTransfer(params) {
|
|
3608
|
+
const {
|
|
3609
|
+
walletClient,
|
|
3610
|
+
publicClient,
|
|
3611
|
+
safeAddress,
|
|
3612
|
+
recipient,
|
|
3613
|
+
amount,
|
|
3614
|
+
chainId
|
|
3615
|
+
} = params;
|
|
3616
|
+
const account = walletClient.account;
|
|
3617
|
+
const chain = walletClient.chain;
|
|
3618
|
+
if (!account || !chain) {
|
|
3619
|
+
throw new Error("Wallet not connected");
|
|
3620
|
+
}
|
|
3621
|
+
if (chain.id !== chainId) {
|
|
3622
|
+
throw new Error(`Switch to ${getChainName(chainId)} to sign`);
|
|
3623
|
+
}
|
|
3624
|
+
const isOwner = await publicClient.readContract({
|
|
3625
|
+
address: safeAddress,
|
|
3626
|
+
abi: SAFE_ABI,
|
|
3627
|
+
functionName: "isOwner",
|
|
3628
|
+
args: [account.address]
|
|
3629
|
+
});
|
|
3630
|
+
if (!isOwner) {
|
|
3631
|
+
throw new Error("Connected wallet is not a Safe owner");
|
|
3632
|
+
}
|
|
3633
|
+
const safeTx = {
|
|
3634
|
+
to: recipient,
|
|
3635
|
+
value: amount,
|
|
3636
|
+
data: "0x",
|
|
3637
|
+
operation: 0,
|
|
3638
|
+
safeTxGas: 0n,
|
|
3639
|
+
baseGas: 0n,
|
|
3640
|
+
gasPrice: 0n,
|
|
3641
|
+
gasToken: import_viem8.zeroAddress,
|
|
3642
|
+
refundReceiver: import_viem8.zeroAddress
|
|
3643
|
+
};
|
|
3644
|
+
const signature = (0, import_viem8.concat)([
|
|
3645
|
+
(0, import_viem8.pad)(account.address, { size: 32 }),
|
|
3646
|
+
(0, import_viem8.pad)((0, import_viem8.toHex)(0), { size: 32 }),
|
|
3647
|
+
(0, import_viem8.toHex)(1, { size: 1 })
|
|
3648
|
+
]);
|
|
3649
|
+
const txHash = await walletClient.writeContract({
|
|
3650
|
+
account,
|
|
3651
|
+
chain,
|
|
3652
|
+
address: safeAddress,
|
|
3653
|
+
abi: SAFE_ABI,
|
|
3654
|
+
functionName: "execTransaction",
|
|
3655
|
+
args: [
|
|
3656
|
+
safeTx.to,
|
|
3657
|
+
safeTx.value,
|
|
3658
|
+
safeTx.data,
|
|
3659
|
+
safeTx.operation,
|
|
3660
|
+
safeTx.safeTxGas,
|
|
3661
|
+
safeTx.baseGas,
|
|
3662
|
+
safeTx.gasPrice,
|
|
3663
|
+
safeTx.gasToken,
|
|
3664
|
+
safeTx.refundReceiver,
|
|
3665
|
+
signature
|
|
3666
|
+
]
|
|
3667
|
+
});
|
|
3668
|
+
const receipt = await publicClient.waitForTransactionReceipt({
|
|
3669
|
+
hash: txHash
|
|
3670
|
+
});
|
|
3671
|
+
const safeLogs = receipt.logs.filter(
|
|
3672
|
+
(log) => log.address.toLowerCase() === safeAddress.toLowerCase()
|
|
3673
|
+
);
|
|
3674
|
+
const parsed = (0, import_viem8.parseEventLogs)({
|
|
3675
|
+
abi: SAFE_ABI,
|
|
3676
|
+
logs: safeLogs,
|
|
3677
|
+
strict: false
|
|
3678
|
+
});
|
|
3679
|
+
const failed = parsed.find((log) => log.eventName === "ExecutionFailure");
|
|
3680
|
+
if (failed) {
|
|
3681
|
+
throw new Error("Safe transaction failed");
|
|
3682
|
+
}
|
|
3683
|
+
const succeeded = parsed.find((log) => log.eventName === "ExecutionSuccess");
|
|
3684
|
+
if (!succeeded) {
|
|
3685
|
+
throw new Error("Safe transaction status unavailable");
|
|
3686
|
+
}
|
|
3687
|
+
return { txHash };
|
|
3688
|
+
}
|
|
3562
3689
|
async function executeSafeErc20Transfer(params) {
|
|
3563
3690
|
const {
|
|
3564
3691
|
walletClient,
|
|
@@ -3577,19 +3704,12 @@ async function executeSafeErc20Transfer(params) {
|
|
|
3577
3704
|
if (chain.id !== chainId) {
|
|
3578
3705
|
throw new Error(`Switch to ${getChainName(chainId)} to sign`);
|
|
3579
3706
|
}
|
|
3580
|
-
const
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
}),
|
|
3587
|
-
publicClient.readContract({
|
|
3588
|
-
address: safeAddress,
|
|
3589
|
-
abi: SAFE_ABI,
|
|
3590
|
-
functionName: "nonce"
|
|
3591
|
-
})
|
|
3592
|
-
]);
|
|
3707
|
+
const isOwner = await publicClient.readContract({
|
|
3708
|
+
address: safeAddress,
|
|
3709
|
+
abi: SAFE_ABI,
|
|
3710
|
+
functionName: "isOwner",
|
|
3711
|
+
args: [account.address]
|
|
3712
|
+
});
|
|
3593
3713
|
if (!isOwner) {
|
|
3594
3714
|
throw new Error("Connected wallet is not a Safe owner");
|
|
3595
3715
|
}
|
|
@@ -3607,19 +3727,13 @@ async function executeSafeErc20Transfer(params) {
|
|
|
3607
3727
|
baseGas: 0n,
|
|
3608
3728
|
gasPrice: 0n,
|
|
3609
3729
|
gasToken: import_viem8.zeroAddress,
|
|
3610
|
-
refundReceiver: import_viem8.zeroAddress
|
|
3611
|
-
nonce
|
|
3730
|
+
refundReceiver: import_viem8.zeroAddress
|
|
3612
3731
|
};
|
|
3613
|
-
const signature =
|
|
3614
|
-
account,
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
},
|
|
3619
|
-
types: SAFE_TX_TYPES,
|
|
3620
|
-
primaryType: "SafeTx",
|
|
3621
|
-
message: safeTx
|
|
3622
|
-
});
|
|
3732
|
+
const signature = (0, import_viem8.concat)([
|
|
3733
|
+
(0, import_viem8.pad)(account.address, { size: 32 }),
|
|
3734
|
+
(0, import_viem8.pad)((0, import_viem8.toHex)(0), { size: 32 }),
|
|
3735
|
+
(0, import_viem8.toHex)(1, { size: 1 })
|
|
3736
|
+
]);
|
|
3623
3737
|
const txHash = await walletClient.writeContract({
|
|
3624
3738
|
account,
|
|
3625
3739
|
chain,
|
|
@@ -3713,6 +3827,7 @@ function WithdrawFlow({
|
|
|
3713
3827
|
decimals
|
|
3714
3828
|
};
|
|
3715
3829
|
}, [sourceChain, sourceToken]);
|
|
3830
|
+
const isSourceNative = sourceToken.toLowerCase() === NATIVE_TOKEN_ADDRESS.toLowerCase();
|
|
3716
3831
|
const stepIndex = step.type === "form" ? 0 : 1;
|
|
3717
3832
|
const currentBackHandler = void 0;
|
|
3718
3833
|
(0, import_react10.useEffect)(() => {
|
|
@@ -3789,7 +3904,14 @@ function WithdrawFlow({
|
|
|
3789
3904
|
});
|
|
3790
3905
|
handleConnected(address, smartAccount);
|
|
3791
3906
|
const amountUnits = (0, import_viem9.parseUnits)(amountValue, asset.decimals);
|
|
3792
|
-
const result = await
|
|
3907
|
+
const result = isSourceNative ? await executeSafeEthTransfer({
|
|
3908
|
+
walletClient,
|
|
3909
|
+
publicClient,
|
|
3910
|
+
safeAddress,
|
|
3911
|
+
recipient: smartAccount,
|
|
3912
|
+
amount: amountUnits,
|
|
3913
|
+
chainId: sourceChain
|
|
3914
|
+
}) : await executeSafeErc20Transfer({
|
|
3793
3915
|
walletClient,
|
|
3794
3916
|
publicClient,
|
|
3795
3917
|
safeAddress,
|
|
@@ -3836,6 +3958,7 @@ function WithdrawFlow({
|
|
|
3836
3958
|
sourceToken,
|
|
3837
3959
|
sourceChain,
|
|
3838
3960
|
onWithdrawSubmitted,
|
|
3961
|
+
isSourceNative,
|
|
3839
3962
|
handleError
|
|
3840
3963
|
]
|
|
3841
3964
|
);
|
|
@@ -3852,15 +3975,23 @@ function WithdrawFlow({
|
|
|
3852
3975
|
[onWithdrawFailed]
|
|
3853
3976
|
);
|
|
3854
3977
|
const targetChainOptions = (0, import_react10.useMemo)(() => {
|
|
3978
|
+
if (isSourceNative) return SOURCE_CHAINS;
|
|
3855
3979
|
return SOURCE_CHAINS.filter((chain) => Boolean(getUsdcAddress(chain.id)));
|
|
3856
|
-
}, []);
|
|
3857
|
-
const handleTargetChainChange = (0, import_react10.useCallback)(
|
|
3858
|
-
|
|
3859
|
-
|
|
3860
|
-
|
|
3861
|
-
|
|
3862
|
-
|
|
3863
|
-
|
|
3980
|
+
}, [isSourceNative]);
|
|
3981
|
+
const handleTargetChainChange = (0, import_react10.useCallback)(
|
|
3982
|
+
(chainId) => {
|
|
3983
|
+
setTargetChain(chainId);
|
|
3984
|
+
if (isSourceNative) {
|
|
3985
|
+
setTargetToken(NATIVE_TOKEN_ADDRESS);
|
|
3986
|
+
return;
|
|
3987
|
+
}
|
|
3988
|
+
const nextToken = getUsdcAddress(chainId);
|
|
3989
|
+
if (nextToken) {
|
|
3990
|
+
setTargetToken(nextToken);
|
|
3991
|
+
}
|
|
3992
|
+
},
|
|
3993
|
+
[isSourceNative]
|
|
3994
|
+
);
|
|
3864
3995
|
const handleTargetTokenChange = (0, import_react10.useCallback)((token) => {
|
|
3865
3996
|
setTargetToken(token);
|
|
3866
3997
|
}, []);
|
package/dist/index.d.cts
CHANGED
|
@@ -77,6 +77,7 @@ interface DepositModalProps {
|
|
|
77
77
|
recipient?: Address;
|
|
78
78
|
backendUrl?: string;
|
|
79
79
|
signerAddress?: Address;
|
|
80
|
+
forceRegister?: boolean;
|
|
80
81
|
waitForFinalTx?: boolean;
|
|
81
82
|
onRequestConnect?: () => void;
|
|
82
83
|
connectButtonLabel?: string;
|
|
@@ -135,7 +136,7 @@ interface AssetOption {
|
|
|
135
136
|
balanceUsd?: number;
|
|
136
137
|
}
|
|
137
138
|
|
|
138
|
-
declare function DepositModal({ walletClient, publicClient, address, targetChain: targetChainProp, targetToken, isOpen, onClose, inline, switchChain, sourceChain: sourceChainProp, sourceToken, defaultAmount, recipient, backendUrl, signerAddress, waitForFinalTx, onRequestConnect, connectButtonLabel, theme, branding, uiConfig, className, onReady, onConnected, onDepositSubmitted, onDepositComplete, onDepositFailed, onError, }: DepositModalProps): react_jsx_runtime.JSX.Element;
|
|
139
|
+
declare function DepositModal({ walletClient, publicClient, address, targetChain: targetChainProp, targetToken, isOpen, onClose, inline, switchChain, sourceChain: sourceChainProp, sourceToken, defaultAmount, recipient, backendUrl, signerAddress, forceRegister, waitForFinalTx, onRequestConnect, connectButtonLabel, theme, branding, uiConfig, className, onReady, onConnected, onDepositSubmitted, onDepositComplete, onDepositFailed, onError, }: DepositModalProps): react_jsx_runtime.JSX.Element;
|
|
139
140
|
declare namespace DepositModal {
|
|
140
141
|
var displayName: string;
|
|
141
142
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -77,6 +77,7 @@ interface DepositModalProps {
|
|
|
77
77
|
recipient?: Address;
|
|
78
78
|
backendUrl?: string;
|
|
79
79
|
signerAddress?: Address;
|
|
80
|
+
forceRegister?: boolean;
|
|
80
81
|
waitForFinalTx?: boolean;
|
|
81
82
|
onRequestConnect?: () => void;
|
|
82
83
|
connectButtonLabel?: string;
|
|
@@ -135,7 +136,7 @@ interface AssetOption {
|
|
|
135
136
|
balanceUsd?: number;
|
|
136
137
|
}
|
|
137
138
|
|
|
138
|
-
declare function DepositModal({ walletClient, publicClient, address, targetChain: targetChainProp, targetToken, isOpen, onClose, inline, switchChain, sourceChain: sourceChainProp, sourceToken, defaultAmount, recipient, backendUrl, signerAddress, waitForFinalTx, onRequestConnect, connectButtonLabel, theme, branding, uiConfig, className, onReady, onConnected, onDepositSubmitted, onDepositComplete, onDepositFailed, onError, }: DepositModalProps): react_jsx_runtime.JSX.Element;
|
|
139
|
+
declare function DepositModal({ walletClient, publicClient, address, targetChain: targetChainProp, targetToken, isOpen, onClose, inline, switchChain, sourceChain: sourceChainProp, sourceToken, defaultAmount, recipient, backendUrl, signerAddress, forceRegister, waitForFinalTx, onRequestConnect, connectButtonLabel, theme, branding, uiConfig, className, onReady, onConnected, onDepositSubmitted, onDepositComplete, onDepositFailed, onError, }: DepositModalProps): react_jsx_runtime.JSX.Element;
|
|
139
140
|
declare namespace DepositModal {
|
|
140
141
|
var displayName: string;
|
|
141
142
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/DepositModal.tsx
|
|
2
|
-
import { useMemo as useMemo5, useEffect as useEffect7, useRef as
|
|
2
|
+
import { useMemo as useMemo5, useEffect as useEffect7, useRef as useRef6, useState as useState7, useCallback as useCallback4 } from "react";
|
|
3
3
|
|
|
4
4
|
// src/components/ui/Modal.tsx
|
|
5
5
|
import {
|
|
@@ -132,7 +132,7 @@ function Modal({
|
|
|
132
132
|
Modal.displayName = "Modal";
|
|
133
133
|
|
|
134
134
|
// src/DepositFlow.tsx
|
|
135
|
-
import { useState as useState6, useCallback as useCallback3, useMemo as useMemo4, useEffect as useEffect6 } from "react";
|
|
135
|
+
import { useState as useState6, useCallback as useCallback3, useMemo as useMemo4, useEffect as useEffect6, useRef as useRef5 } from "react";
|
|
136
136
|
|
|
137
137
|
// src/components/ui/Spinner.tsx
|
|
138
138
|
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
@@ -1915,6 +1915,7 @@ import { Fragment as Fragment2, jsx as jsx10, jsxs as jsxs9 } from "react/jsx-ru
|
|
|
1915
1915
|
var INITIAL_POLL_INTERVAL = 3e3;
|
|
1916
1916
|
var MAX_POLL_INTERVAL = 3e4;
|
|
1917
1917
|
var BACKOFF_MULTIPLIER = 1.5;
|
|
1918
|
+
var PROCESS_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
1918
1919
|
function ProcessingStep({
|
|
1919
1920
|
publicClient,
|
|
1920
1921
|
smartAccount,
|
|
@@ -1970,6 +1971,13 @@ function ProcessingStep({
|
|
|
1970
1971
|
}
|
|
1971
1972
|
try {
|
|
1972
1973
|
await publicClient.waitForTransactionReceipt({ hash: txHash });
|
|
1974
|
+
} catch (error) {
|
|
1975
|
+
const message = error instanceof Error ? error.message : "Transaction not confirmed";
|
|
1976
|
+
setState({ type: "error", message });
|
|
1977
|
+
onError?.(message, "PROCESS_ERROR");
|
|
1978
|
+
return;
|
|
1979
|
+
}
|
|
1980
|
+
try {
|
|
1973
1981
|
const result = await service.processDeposit(smartAccount, {
|
|
1974
1982
|
chainId: sourceChain,
|
|
1975
1983
|
token: sourceToken,
|
|
@@ -1977,22 +1985,24 @@ function ProcessingStep({
|
|
|
1977
1985
|
txHash,
|
|
1978
1986
|
sender
|
|
1979
1987
|
});
|
|
1980
|
-
if (result.
|
|
1988
|
+
if (result.message.includes("Funds are already on the target chain")) {
|
|
1981
1989
|
if (sameChainAndToken) {
|
|
1982
1990
|
setState({ type: "complete" });
|
|
1983
1991
|
onDepositComplete?.(txHash);
|
|
1984
|
-
|
|
1985
|
-
const message = `Processor returned same-chain response. Re-register the account for target chain ${targetChain}.`;
|
|
1986
|
-
setState({ type: "error", message });
|
|
1987
|
-
onError?.(message, "TARGET_CHAIN_MISMATCH");
|
|
1992
|
+
return;
|
|
1988
1993
|
}
|
|
1994
|
+
setState({ type: "processing" });
|
|
1995
|
+
return;
|
|
1996
|
+
}
|
|
1997
|
+
if (result.status === 202) {
|
|
1998
|
+
setState({ type: "processing" });
|
|
1989
1999
|
return;
|
|
1990
2000
|
}
|
|
1991
2001
|
setState({ type: "processing" });
|
|
1992
2002
|
} catch (error) {
|
|
1993
2003
|
const message = error instanceof Error ? error.message : "Process failed";
|
|
1994
|
-
setState({ type: "
|
|
1995
|
-
onError?.(message, "
|
|
2004
|
+
setState({ type: "processing", warning: message });
|
|
2005
|
+
onError?.(message, "PROCESS_FALLBACK");
|
|
1996
2006
|
}
|
|
1997
2007
|
}
|
|
1998
2008
|
triggerProcess();
|
|
@@ -2011,7 +2021,8 @@ function ProcessingStep({
|
|
|
2011
2021
|
onError
|
|
2012
2022
|
]);
|
|
2013
2023
|
const pollIntervalRef = useRef4(INITIAL_POLL_INTERVAL);
|
|
2014
|
-
const
|
|
2024
|
+
const pollTimeoutRef = useRef4(null);
|
|
2025
|
+
const processTimeoutRef = useRef4(null);
|
|
2015
2026
|
useEffect5(() => {
|
|
2016
2027
|
if (state.type !== "processing") {
|
|
2017
2028
|
pollIntervalRef.current = INITIAL_POLL_INTERVAL;
|
|
@@ -2059,7 +2070,7 @@ function ProcessingStep({
|
|
|
2059
2070
|
}
|
|
2060
2071
|
function scheduleNextPoll() {
|
|
2061
2072
|
if (!isMounted) return;
|
|
2062
|
-
|
|
2073
|
+
pollTimeoutRef.current = setTimeout(() => {
|
|
2063
2074
|
pollIntervalRef.current = Math.min(
|
|
2064
2075
|
pollIntervalRef.current * BACKOFF_MULTIPLIER,
|
|
2065
2076
|
MAX_POLL_INTERVAL
|
|
@@ -2070,8 +2081,8 @@ function ProcessingStep({
|
|
|
2070
2081
|
pollStatus();
|
|
2071
2082
|
return () => {
|
|
2072
2083
|
isMounted = false;
|
|
2073
|
-
if (
|
|
2074
|
-
clearTimeout(
|
|
2084
|
+
if (pollTimeoutRef.current) {
|
|
2085
|
+
clearTimeout(pollTimeoutRef.current);
|
|
2075
2086
|
}
|
|
2076
2087
|
};
|
|
2077
2088
|
}, [
|
|
@@ -2084,6 +2095,26 @@ function ProcessingStep({
|
|
|
2084
2095
|
onDepositComplete,
|
|
2085
2096
|
onDepositFailed
|
|
2086
2097
|
]);
|
|
2098
|
+
useEffect5(() => {
|
|
2099
|
+
if (state.type !== "processing") {
|
|
2100
|
+
if (processTimeoutRef.current) {
|
|
2101
|
+
clearTimeout(processTimeoutRef.current);
|
|
2102
|
+
processTimeoutRef.current = null;
|
|
2103
|
+
}
|
|
2104
|
+
return;
|
|
2105
|
+
}
|
|
2106
|
+
processTimeoutRef.current = setTimeout(() => {
|
|
2107
|
+
const message = "We couldn't confirm your transfer. Please contact support if funds do not arrive.";
|
|
2108
|
+
setState({ type: "error", message });
|
|
2109
|
+
onError?.(message, "PROCESS_TIMEOUT");
|
|
2110
|
+
}, PROCESS_TIMEOUT_MS);
|
|
2111
|
+
return () => {
|
|
2112
|
+
if (processTimeoutRef.current) {
|
|
2113
|
+
clearTimeout(processTimeoutRef.current);
|
|
2114
|
+
processTimeoutRef.current = null;
|
|
2115
|
+
}
|
|
2116
|
+
};
|
|
2117
|
+
}, [state.type, onError]);
|
|
2087
2118
|
const isError = state.type === "error" || state.type === "failed";
|
|
2088
2119
|
const isComplete = state.type === "complete";
|
|
2089
2120
|
const isProcessing = state.type === "triggering" || state.type === "processing";
|
|
@@ -2336,6 +2367,27 @@ function ProcessingStep({
|
|
|
2336
2367
|
/* @__PURE__ */ jsxs9("div", { className: "rs-step-body rs-space-y-3", children: [
|
|
2337
2368
|
isProcessing && /* @__PURE__ */ jsxs9(Fragment2, { children: [
|
|
2338
2369
|
/* @__PURE__ */ jsx10("div", { className: "rs-progress-bar", children: /* @__PURE__ */ jsx10("div", { className: "rs-progress-bar-fill rs-progress-bar-fill--indeterminate" }) }),
|
|
2370
|
+
state.type === "processing" && state.warning && /* @__PURE__ */ jsxs9("div", { className: "rs-alert rs-alert--warning", children: [
|
|
2371
|
+
/* @__PURE__ */ jsx10(
|
|
2372
|
+
"svg",
|
|
2373
|
+
{
|
|
2374
|
+
className: "rs-alert-icon",
|
|
2375
|
+
viewBox: "0 0 24 24",
|
|
2376
|
+
fill: "none",
|
|
2377
|
+
stroke: "currentColor",
|
|
2378
|
+
strokeWidth: "2",
|
|
2379
|
+
children: /* @__PURE__ */ jsx10(
|
|
2380
|
+
"path",
|
|
2381
|
+
{
|
|
2382
|
+
strokeLinecap: "round",
|
|
2383
|
+
strokeLinejoin: "round",
|
|
2384
|
+
d: "M12 9v3.75m9-.75a9 9 0 11-18 0 9 9 0 0118 0zm-9 3.75h.008v.008H12v-.008z"
|
|
2385
|
+
}
|
|
2386
|
+
)
|
|
2387
|
+
}
|
|
2388
|
+
),
|
|
2389
|
+
/* @__PURE__ */ jsx10("p", { className: "rs-alert-text", children: "We couldn't reach the processor. We'll keep checking for a webhook update." })
|
|
2390
|
+
] }),
|
|
2339
2391
|
/* @__PURE__ */ jsxs9("div", { className: "rs-alert rs-alert--info", children: [
|
|
2340
2392
|
/* @__PURE__ */ jsx10(
|
|
2341
2393
|
"svg",
|
|
@@ -2473,6 +2525,7 @@ function DepositFlow({
|
|
|
2473
2525
|
amount: defaultAmount,
|
|
2474
2526
|
recipient,
|
|
2475
2527
|
signerAddress = DEFAULT_SIGNER_ADDRESS,
|
|
2528
|
+
forceRegister = true,
|
|
2476
2529
|
waitForFinalTx = true,
|
|
2477
2530
|
onRequestConnect,
|
|
2478
2531
|
connectButtonLabel,
|
|
@@ -2489,6 +2542,16 @@ function DepositFlow({
|
|
|
2489
2542
|
const [step, setStep] = useState6({ type: "setup" });
|
|
2490
2543
|
const [totalBalanceUsd, setTotalBalanceUsd] = useState6(0);
|
|
2491
2544
|
const targetChainObj = useMemo4(() => CHAIN_BY_ID[targetChain], [targetChain]);
|
|
2545
|
+
const lastTargetRef = useRef5(null);
|
|
2546
|
+
useEffect6(() => {
|
|
2547
|
+
const prev = lastTargetRef.current;
|
|
2548
|
+
if (prev && (prev.chain !== targetChain || prev.token.toLowerCase() !== targetToken.toLowerCase())) {
|
|
2549
|
+
if (step.type !== "processing") {
|
|
2550
|
+
setStep({ type: "setup" });
|
|
2551
|
+
}
|
|
2552
|
+
}
|
|
2553
|
+
lastTargetRef.current = { chain: targetChain, token: targetToken };
|
|
2554
|
+
}, [targetChain, targetToken, step.type]);
|
|
2492
2555
|
const handleBackFromAmount = useCallback3(() => {
|
|
2493
2556
|
setStep((prev) => {
|
|
2494
2557
|
if (prev.type !== "amount") return prev;
|
|
@@ -2618,6 +2681,7 @@ function DepositFlow({
|
|
|
2618
2681
|
targetToken,
|
|
2619
2682
|
signerAddress,
|
|
2620
2683
|
recipient,
|
|
2684
|
+
forceRegister,
|
|
2621
2685
|
service,
|
|
2622
2686
|
onSetupComplete: handleSetupComplete,
|
|
2623
2687
|
onConnected: handleConnected,
|
|
@@ -2755,6 +2819,7 @@ function DepositModal({
|
|
|
2755
2819
|
recipient,
|
|
2756
2820
|
backendUrl = DEFAULT_BACKEND_URL,
|
|
2757
2821
|
signerAddress = DEFAULT_SIGNER_ADDRESS,
|
|
2822
|
+
forceRegister = true,
|
|
2758
2823
|
waitForFinalTx = true,
|
|
2759
2824
|
onRequestConnect,
|
|
2760
2825
|
connectButtonLabel,
|
|
@@ -2769,10 +2834,10 @@ function DepositModal({
|
|
|
2769
2834
|
onDepositFailed,
|
|
2770
2835
|
onError
|
|
2771
2836
|
}) {
|
|
2772
|
-
const modalRef =
|
|
2837
|
+
const modalRef = useRef6(null);
|
|
2773
2838
|
const [currentStepIndex, setCurrentStepIndex] = useState7(0);
|
|
2774
2839
|
const [totalBalanceUsd, setTotalBalanceUsd] = useState7(null);
|
|
2775
|
-
const backHandlerRef =
|
|
2840
|
+
const backHandlerRef = useRef6(void 0);
|
|
2776
2841
|
const targetChain = getChainId(targetChainProp);
|
|
2777
2842
|
const sourceChain = sourceChainProp ? getChainId(sourceChainProp) : void 0;
|
|
2778
2843
|
const service = useMemo5(() => createDepositService(backendUrl), [backendUrl]);
|
|
@@ -2781,7 +2846,7 @@ function DepositModal({
|
|
|
2781
2846
|
applyTheme(modalRef.current, theme);
|
|
2782
2847
|
}
|
|
2783
2848
|
}, [isOpen, theme]);
|
|
2784
|
-
const hasCalledReady =
|
|
2849
|
+
const hasCalledReady = useRef6(false);
|
|
2785
2850
|
useEffect7(() => {
|
|
2786
2851
|
if (isOpen && !hasCalledReady.current) {
|
|
2787
2852
|
hasCalledReady.current = true;
|
|
@@ -2920,6 +2985,7 @@ function DepositModal({
|
|
|
2920
2985
|
amount: defaultAmount,
|
|
2921
2986
|
recipient,
|
|
2922
2987
|
signerAddress,
|
|
2988
|
+
forceRegister,
|
|
2923
2989
|
waitForFinalTx,
|
|
2924
2990
|
onRequestConnect,
|
|
2925
2991
|
connectButtonLabel,
|
|
@@ -2941,13 +3007,13 @@ function DepositModal({
|
|
|
2941
3007
|
DepositModal.displayName = "DepositModal";
|
|
2942
3008
|
|
|
2943
3009
|
// src/WithdrawModal.tsx
|
|
2944
|
-
import { useCallback as useCallback7, useEffect as useEffect10, useMemo as useMemo8, useRef as
|
|
3010
|
+
import { useCallback as useCallback7, useEffect as useEffect10, useMemo as useMemo8, useRef as useRef8, useState as useState10 } from "react";
|
|
2945
3011
|
|
|
2946
3012
|
// src/WithdrawFlow.tsx
|
|
2947
3013
|
import { useCallback as useCallback6, useEffect as useEffect9, useMemo as useMemo7, useState as useState9 } from "react";
|
|
2948
3014
|
|
|
2949
3015
|
// src/components/steps/WithdrawFormStep.tsx
|
|
2950
|
-
import { useCallback as useCallback5, useEffect as useEffect8, useMemo as useMemo6, useRef as
|
|
3016
|
+
import { useCallback as useCallback5, useEffect as useEffect8, useMemo as useMemo6, useRef as useRef7, useState as useState8 } from "react";
|
|
2951
3017
|
import { erc20Abi as erc20Abi3, formatUnits as formatUnits5, parseUnits as parseUnits3 } from "viem";
|
|
2952
3018
|
import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
2953
3019
|
function useClickOutside(ref, onClose) {
|
|
@@ -2989,9 +3055,9 @@ function WithdrawFormStep({
|
|
|
2989
3055
|
const [showChainDropdown, setShowChainDropdown] = useState8(false);
|
|
2990
3056
|
const [showTokenDropdown, setShowTokenDropdown] = useState8(false);
|
|
2991
3057
|
const [isSubmitting, setIsSubmitting] = useState8(false);
|
|
2992
|
-
const hasAttemptedSwitch =
|
|
2993
|
-
const chainDropdownRef =
|
|
2994
|
-
const tokenDropdownRef =
|
|
3058
|
+
const hasAttemptedSwitch = useRef7(false);
|
|
3059
|
+
const chainDropdownRef = useRef7(null);
|
|
3060
|
+
const tokenDropdownRef = useRef7(null);
|
|
2995
3061
|
const publicClientChainId = publicClient.chain?.id;
|
|
2996
3062
|
useClickOutside(chainDropdownRef, () => setShowChainDropdown(false));
|
|
2997
3063
|
useClickOutside(tokenDropdownRef, () => setShowTokenDropdown(false));
|
|
@@ -3453,19 +3519,15 @@ import { walletClientToAccount as walletClientToAccount2 } from "@rhinestone/sdk
|
|
|
3453
3519
|
|
|
3454
3520
|
// src/core/safe.ts
|
|
3455
3521
|
import {
|
|
3522
|
+
concat,
|
|
3456
3523
|
encodeFunctionData,
|
|
3457
3524
|
erc20Abi as erc20Abi4,
|
|
3525
|
+
pad,
|
|
3458
3526
|
parseEventLogs,
|
|
3527
|
+
toHex,
|
|
3459
3528
|
zeroAddress as zeroAddress2
|
|
3460
3529
|
} from "viem";
|
|
3461
3530
|
var SAFE_ABI = [
|
|
3462
|
-
{
|
|
3463
|
-
type: "function",
|
|
3464
|
-
name: "nonce",
|
|
3465
|
-
stateMutability: "view",
|
|
3466
|
-
inputs: [],
|
|
3467
|
-
outputs: [{ name: "", type: "uint256" }]
|
|
3468
|
-
},
|
|
3469
3531
|
{
|
|
3470
3532
|
type: "function",
|
|
3471
3533
|
name: "isOwner",
|
|
@@ -3510,20 +3572,88 @@ var SAFE_ABI = [
|
|
|
3510
3572
|
anonymous: false
|
|
3511
3573
|
}
|
|
3512
3574
|
];
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
}
|
|
3575
|
+
async function executeSafeEthTransfer(params) {
|
|
3576
|
+
const {
|
|
3577
|
+
walletClient,
|
|
3578
|
+
publicClient,
|
|
3579
|
+
safeAddress,
|
|
3580
|
+
recipient,
|
|
3581
|
+
amount,
|
|
3582
|
+
chainId
|
|
3583
|
+
} = params;
|
|
3584
|
+
const account = walletClient.account;
|
|
3585
|
+
const chain = walletClient.chain;
|
|
3586
|
+
if (!account || !chain) {
|
|
3587
|
+
throw new Error("Wallet not connected");
|
|
3588
|
+
}
|
|
3589
|
+
if (chain.id !== chainId) {
|
|
3590
|
+
throw new Error(`Switch to ${getChainName(chainId)} to sign`);
|
|
3591
|
+
}
|
|
3592
|
+
const isOwner = await publicClient.readContract({
|
|
3593
|
+
address: safeAddress,
|
|
3594
|
+
abi: SAFE_ABI,
|
|
3595
|
+
functionName: "isOwner",
|
|
3596
|
+
args: [account.address]
|
|
3597
|
+
});
|
|
3598
|
+
if (!isOwner) {
|
|
3599
|
+
throw new Error("Connected wallet is not a Safe owner");
|
|
3600
|
+
}
|
|
3601
|
+
const safeTx = {
|
|
3602
|
+
to: recipient,
|
|
3603
|
+
value: amount,
|
|
3604
|
+
data: "0x",
|
|
3605
|
+
operation: 0,
|
|
3606
|
+
safeTxGas: 0n,
|
|
3607
|
+
baseGas: 0n,
|
|
3608
|
+
gasPrice: 0n,
|
|
3609
|
+
gasToken: zeroAddress2,
|
|
3610
|
+
refundReceiver: zeroAddress2
|
|
3611
|
+
};
|
|
3612
|
+
const signature = concat([
|
|
3613
|
+
pad(account.address, { size: 32 }),
|
|
3614
|
+
pad(toHex(0), { size: 32 }),
|
|
3615
|
+
toHex(1, { size: 1 })
|
|
3616
|
+
]);
|
|
3617
|
+
const txHash = await walletClient.writeContract({
|
|
3618
|
+
account,
|
|
3619
|
+
chain,
|
|
3620
|
+
address: safeAddress,
|
|
3621
|
+
abi: SAFE_ABI,
|
|
3622
|
+
functionName: "execTransaction",
|
|
3623
|
+
args: [
|
|
3624
|
+
safeTx.to,
|
|
3625
|
+
safeTx.value,
|
|
3626
|
+
safeTx.data,
|
|
3627
|
+
safeTx.operation,
|
|
3628
|
+
safeTx.safeTxGas,
|
|
3629
|
+
safeTx.baseGas,
|
|
3630
|
+
safeTx.gasPrice,
|
|
3631
|
+
safeTx.gasToken,
|
|
3632
|
+
safeTx.refundReceiver,
|
|
3633
|
+
signature
|
|
3634
|
+
]
|
|
3635
|
+
});
|
|
3636
|
+
const receipt = await publicClient.waitForTransactionReceipt({
|
|
3637
|
+
hash: txHash
|
|
3638
|
+
});
|
|
3639
|
+
const safeLogs = receipt.logs.filter(
|
|
3640
|
+
(log) => log.address.toLowerCase() === safeAddress.toLowerCase()
|
|
3641
|
+
);
|
|
3642
|
+
const parsed = parseEventLogs({
|
|
3643
|
+
abi: SAFE_ABI,
|
|
3644
|
+
logs: safeLogs,
|
|
3645
|
+
strict: false
|
|
3646
|
+
});
|
|
3647
|
+
const failed = parsed.find((log) => log.eventName === "ExecutionFailure");
|
|
3648
|
+
if (failed) {
|
|
3649
|
+
throw new Error("Safe transaction failed");
|
|
3650
|
+
}
|
|
3651
|
+
const succeeded = parsed.find((log) => log.eventName === "ExecutionSuccess");
|
|
3652
|
+
if (!succeeded) {
|
|
3653
|
+
throw new Error("Safe transaction status unavailable");
|
|
3654
|
+
}
|
|
3655
|
+
return { txHash };
|
|
3656
|
+
}
|
|
3527
3657
|
async function executeSafeErc20Transfer(params) {
|
|
3528
3658
|
const {
|
|
3529
3659
|
walletClient,
|
|
@@ -3542,19 +3672,12 @@ async function executeSafeErc20Transfer(params) {
|
|
|
3542
3672
|
if (chain.id !== chainId) {
|
|
3543
3673
|
throw new Error(`Switch to ${getChainName(chainId)} to sign`);
|
|
3544
3674
|
}
|
|
3545
|
-
const
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
}),
|
|
3552
|
-
publicClient.readContract({
|
|
3553
|
-
address: safeAddress,
|
|
3554
|
-
abi: SAFE_ABI,
|
|
3555
|
-
functionName: "nonce"
|
|
3556
|
-
})
|
|
3557
|
-
]);
|
|
3675
|
+
const isOwner = await publicClient.readContract({
|
|
3676
|
+
address: safeAddress,
|
|
3677
|
+
abi: SAFE_ABI,
|
|
3678
|
+
functionName: "isOwner",
|
|
3679
|
+
args: [account.address]
|
|
3680
|
+
});
|
|
3558
3681
|
if (!isOwner) {
|
|
3559
3682
|
throw new Error("Connected wallet is not a Safe owner");
|
|
3560
3683
|
}
|
|
@@ -3572,19 +3695,13 @@ async function executeSafeErc20Transfer(params) {
|
|
|
3572
3695
|
baseGas: 0n,
|
|
3573
3696
|
gasPrice: 0n,
|
|
3574
3697
|
gasToken: zeroAddress2,
|
|
3575
|
-
refundReceiver: zeroAddress2
|
|
3576
|
-
nonce
|
|
3698
|
+
refundReceiver: zeroAddress2
|
|
3577
3699
|
};
|
|
3578
|
-
const signature =
|
|
3579
|
-
account,
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
},
|
|
3584
|
-
types: SAFE_TX_TYPES,
|
|
3585
|
-
primaryType: "SafeTx",
|
|
3586
|
-
message: safeTx
|
|
3587
|
-
});
|
|
3700
|
+
const signature = concat([
|
|
3701
|
+
pad(account.address, { size: 32 }),
|
|
3702
|
+
pad(toHex(0), { size: 32 }),
|
|
3703
|
+
toHex(1, { size: 1 })
|
|
3704
|
+
]);
|
|
3588
3705
|
const txHash = await walletClient.writeContract({
|
|
3589
3706
|
account,
|
|
3590
3707
|
chain,
|
|
@@ -3678,6 +3795,7 @@ function WithdrawFlow({
|
|
|
3678
3795
|
decimals
|
|
3679
3796
|
};
|
|
3680
3797
|
}, [sourceChain, sourceToken]);
|
|
3798
|
+
const isSourceNative = sourceToken.toLowerCase() === NATIVE_TOKEN_ADDRESS.toLowerCase();
|
|
3681
3799
|
const stepIndex = step.type === "form" ? 0 : 1;
|
|
3682
3800
|
const currentBackHandler = void 0;
|
|
3683
3801
|
useEffect9(() => {
|
|
@@ -3754,7 +3872,14 @@ function WithdrawFlow({
|
|
|
3754
3872
|
});
|
|
3755
3873
|
handleConnected(address, smartAccount);
|
|
3756
3874
|
const amountUnits = parseUnits4(amountValue, asset.decimals);
|
|
3757
|
-
const result = await
|
|
3875
|
+
const result = isSourceNative ? await executeSafeEthTransfer({
|
|
3876
|
+
walletClient,
|
|
3877
|
+
publicClient,
|
|
3878
|
+
safeAddress,
|
|
3879
|
+
recipient: smartAccount,
|
|
3880
|
+
amount: amountUnits,
|
|
3881
|
+
chainId: sourceChain
|
|
3882
|
+
}) : await executeSafeErc20Transfer({
|
|
3758
3883
|
walletClient,
|
|
3759
3884
|
publicClient,
|
|
3760
3885
|
safeAddress,
|
|
@@ -3801,6 +3926,7 @@ function WithdrawFlow({
|
|
|
3801
3926
|
sourceToken,
|
|
3802
3927
|
sourceChain,
|
|
3803
3928
|
onWithdrawSubmitted,
|
|
3929
|
+
isSourceNative,
|
|
3804
3930
|
handleError
|
|
3805
3931
|
]
|
|
3806
3932
|
);
|
|
@@ -3817,15 +3943,23 @@ function WithdrawFlow({
|
|
|
3817
3943
|
[onWithdrawFailed]
|
|
3818
3944
|
);
|
|
3819
3945
|
const targetChainOptions = useMemo7(() => {
|
|
3946
|
+
if (isSourceNative) return SOURCE_CHAINS;
|
|
3820
3947
|
return SOURCE_CHAINS.filter((chain) => Boolean(getUsdcAddress(chain.id)));
|
|
3821
|
-
}, []);
|
|
3822
|
-
const handleTargetChainChange = useCallback6(
|
|
3823
|
-
|
|
3824
|
-
|
|
3825
|
-
|
|
3826
|
-
|
|
3827
|
-
|
|
3828
|
-
|
|
3948
|
+
}, [isSourceNative]);
|
|
3949
|
+
const handleTargetChainChange = useCallback6(
|
|
3950
|
+
(chainId) => {
|
|
3951
|
+
setTargetChain(chainId);
|
|
3952
|
+
if (isSourceNative) {
|
|
3953
|
+
setTargetToken(NATIVE_TOKEN_ADDRESS);
|
|
3954
|
+
return;
|
|
3955
|
+
}
|
|
3956
|
+
const nextToken = getUsdcAddress(chainId);
|
|
3957
|
+
if (nextToken) {
|
|
3958
|
+
setTargetToken(nextToken);
|
|
3959
|
+
}
|
|
3960
|
+
},
|
|
3961
|
+
[isSourceNative]
|
|
3962
|
+
);
|
|
3829
3963
|
const handleTargetTokenChange = useCallback6((token) => {
|
|
3830
3964
|
setTargetToken(token);
|
|
3831
3965
|
}, []);
|
|
@@ -3918,10 +4052,10 @@ function WithdrawModal({
|
|
|
3918
4052
|
onWithdrawFailed,
|
|
3919
4053
|
onError
|
|
3920
4054
|
}) {
|
|
3921
|
-
const modalRef =
|
|
4055
|
+
const modalRef = useRef8(null);
|
|
3922
4056
|
const [currentStepIndex, setCurrentStepIndex] = useState10(0);
|
|
3923
4057
|
const [totalBalanceUsd, setTotalBalanceUsd] = useState10(null);
|
|
3924
|
-
const backHandlerRef =
|
|
4058
|
+
const backHandlerRef = useRef8(void 0);
|
|
3925
4059
|
const targetChain = getChainId(targetChainProp);
|
|
3926
4060
|
const sourceChain = getChainId(sourceChainProp);
|
|
3927
4061
|
const service = useMemo8(() => createDepositService(backendUrl), [backendUrl]);
|
|
@@ -3930,7 +4064,7 @@ function WithdrawModal({
|
|
|
3930
4064
|
applyTheme(modalRef.current, theme);
|
|
3931
4065
|
}
|
|
3932
4066
|
}, [isOpen, theme]);
|
|
3933
|
-
const hasCalledReady =
|
|
4067
|
+
const hasCalledReady = useRef8(false);
|
|
3934
4068
|
useEffect10(() => {
|
|
3935
4069
|
if (isOpen && !hasCalledReady.current) {
|
|
3936
4070
|
hasCalledReady.current = true;
|