@spicenet-io/spiceflow-ui 1.2.6 → 1.3.0-1

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.
@@ -0,0 +1,3 @@
1
+ import React from "react";
2
+ import { DepositWidgetProps } from "../../types/deposit";
3
+ export declare const DepositWidget: React.FC<DepositWidgetProps>;
@@ -0,0 +1,2 @@
1
+ export { DepositWidget } from "./DepositWidget";
2
+ export type { DepositWidgetProps } from "../../types/deposit";
@@ -6,3 +6,4 @@ export * from "./DebugWidget";
6
6
  export * from "./SpiceBalance";
7
7
  export * from "./ui";
8
8
  export * from "./LpModal";
9
+ export * from "./DepositWidget";
package/dist/index.cjs.js CHANGED
@@ -3669,6 +3669,441 @@ const DebugWidget = (props) => {
3669
3669
  return /* @__PURE__ */ jsxRuntime.jsx(DebugWidgetErrorBoundary, { fallback: fallbackComponent, children: /* @__PURE__ */ jsxRuntime.jsx(DebugWidgetInternal, { ...props }) });
3670
3670
  };
3671
3671
 
3672
+ const DepositWidget = ({
3673
+ depositBatches,
3674
+ tokenAddress = "0x0",
3675
+ supportedChains,
3676
+ theme: themeMode = "light",
3677
+ styles,
3678
+ className = "",
3679
+ depositInputHook,
3680
+ onDepositSuccess,
3681
+ onDepositError
3682
+ }) => {
3683
+ const baseTheme = Button.createTheme(themeMode);
3684
+ const theme = {
3685
+ ...baseTheme,
3686
+ typography: {
3687
+ ...baseTheme.typography,
3688
+ fontFamily: styles?.fontFamily || baseTheme.typography.fontFamily
3689
+ },
3690
+ colors: {
3691
+ ...baseTheme.colors,
3692
+ primary: styles?.primaryColor || baseTheme.colors.primary,
3693
+ primaryHover: styles?.primaryColor ? `${styles.primaryColor}dd` : baseTheme.colors.primaryHover
3694
+ }
3695
+ };
3696
+ const wallet = useWallet();
3697
+ const {
3698
+ isReady: ready,
3699
+ isAuthenticated: authenticated,
3700
+ isConnected,
3701
+ address,
3702
+ provider,
3703
+ actions
3704
+ } = wallet;
3705
+ const spiceFlowContext = React.useContext(SpiceFlowProviderContext);
3706
+ const [selectedDepositAsset, setSelectedDepositAsset] = React.useState(null);
3707
+ const [isPending, startTransition] = React.useTransition();
3708
+ const {
3709
+ assets,
3710
+ loading: loadingAssets,
3711
+ error: assetsError,
3712
+ refreshAssets
3713
+ } = useAssets({
3714
+ address,
3715
+ supportedChains,
3716
+ fetchBalances
3717
+ });
3718
+ const [isExecuting, setIsExecuting] = React.useState(false);
3719
+ const [error, setError] = React.useState(null);
3720
+ const { intentStatus, startStatusPolling, clearStatus } = useStatus({
3721
+ checkStepStatus: (intentId, stepId) => relayerService.checkStepStatus(intentId, stepId)
3722
+ });
3723
+ React.useEffect(() => {
3724
+ if (depositInputHook && depositInputHook.depositAmount !== selectedDepositAsset?.amount) {
3725
+ if (selectedDepositAsset) {
3726
+ setSelectedDepositAsset({
3727
+ ...selectedDepositAsset,
3728
+ amount: depositInputHook.depositAmount
3729
+ });
3730
+ }
3731
+ }
3732
+ }, [depositInputHook?.depositAmount, selectedDepositAsset]);
3733
+ const clearError = React.useCallback(() => {
3734
+ setError(null);
3735
+ }, []);
3736
+ const handleDepositAssetSelect = (asset) => {
3737
+ setSelectedDepositAsset({
3738
+ asset,
3739
+ amount: selectedDepositAsset?.amount || ""
3740
+ });
3741
+ clearError();
3742
+ };
3743
+ const handleDepositAmountChange = React.useCallback(
3744
+ (amount) => {
3745
+ if (selectedDepositAsset) {
3746
+ startTransition(() => {
3747
+ setSelectedDepositAsset({
3748
+ ...selectedDepositAsset,
3749
+ amount
3750
+ });
3751
+ clearError();
3752
+ });
3753
+ if (depositInputHook) {
3754
+ depositInputHook.setDepositAmount(amount);
3755
+ }
3756
+ }
3757
+ },
3758
+ [selectedDepositAsset, depositInputHook, clearError]
3759
+ );
3760
+ const handleDeposit = async () => {
3761
+ if (!selectedDepositAsset || !address || depositBatches.length === 0)
3762
+ return;
3763
+ if (!ready || !authenticated) {
3764
+ setError(
3765
+ `Please authenticate with ${provider || "wallet provider"} to continue`
3766
+ );
3767
+ return;
3768
+ }
3769
+ setIsExecuting(true);
3770
+ setError(null);
3771
+ try {
3772
+ const depositClient = getClientForChain(
3773
+ selectedDepositAsset.asset.chainId
3774
+ );
3775
+ const depositRecentBlock = await depositClient.getBlockNumber();
3776
+ const depositAssetBatch = {
3777
+ chainId: selectedDepositAsset.asset.chainId,
3778
+ recentBlock: depositRecentBlock,
3779
+ calls: [
3780
+ {
3781
+ to: "0xeee2b52e7CFe6e2168341a34cEB783b68FEdf1A2",
3782
+ // Escrow contract address
3783
+ value: viem.parseEther(selectedDepositAsset.amount),
3784
+ data: "0x"
3785
+ }
3786
+ ]
3787
+ };
3788
+ const allChainBatches = [depositAssetBatch, ...depositBatches];
3789
+ const uniqueChainIds = [
3790
+ ...new Set(allChainBatches.map((batch) => batch.chainId))
3791
+ ];
3792
+ const authorizations = [];
3793
+ for (const chainId of uniqueChainIds) {
3794
+ const client = getClientForChain(chainId);
3795
+ const delegateContract = getDelegateContractAddress(chainId);
3796
+ const nonce = await spiceflowCoreTest.getAccountNonce(
3797
+ address,
3798
+ client
3799
+ );
3800
+ const auth = await actions.signAuthorization({
3801
+ contractAddress: delegateContract,
3802
+ chainId,
3803
+ nonce: Number(nonce)
3804
+ });
3805
+ authorizations.push(auth);
3806
+ console.log("auth for chain", chainId, auth);
3807
+ }
3808
+ const hashedChainBatches = spiceflowCoreTest.hashChainBatches(allChainBatches);
3809
+ const digest = spiceflowCoreTest.getAuthorizationHash(hashedChainBatches);
3810
+ const intentSignature = await actions.signMessage(digest);
3811
+ if (!intentSignature)
3812
+ throw new Error("Failed to sign intent authorization");
3813
+ const submitRequest = {
3814
+ tokenAddress,
3815
+ tokenAmount: viem.parseEther(selectedDepositAsset.amount),
3816
+ address,
3817
+ authorization: authorizations,
3818
+ intentAuthorization: {
3819
+ signature: intentSignature.signature,
3820
+ chainBatches: hashedChainBatches
3821
+ }
3822
+ };
3823
+ const result = await relayerService.submitTransaction(submitRequest);
3824
+ if (result) {
3825
+ const getChainName = (chainId) => {
3826
+ return `Chain ${chainId}`;
3827
+ };
3828
+ const initialSteps = createInitialSteps(allChainBatches, getChainName);
3829
+ startStatusPolling(result.intentId, initialSteps);
3830
+ onDepositSuccess?.(result.intentId);
3831
+ refreshAssets();
3832
+ }
3833
+ } catch (error2) {
3834
+ const errorMessage = error2 instanceof Error ? error2.message : "Deposit failed";
3835
+ setError(errorMessage);
3836
+ onDepositError?.(errorMessage);
3837
+ } finally {
3838
+ setIsExecuting(false);
3839
+ }
3840
+ };
3841
+ const depositAssets = supportedChains.flatMap(
3842
+ (chainId) => getAllAssetsForChain(chainId, assets)
3843
+ );
3844
+ const canDeposit = selectedDepositAsset && selectedDepositAsset.amount && parseFloat(selectedDepositAsset.amount) > 0 && parseFloat(selectedDepositAsset.amount) <= selectedDepositAsset.asset.balanceFormatted && isConnected && !isExecuting && depositBatches.length > 0;
3845
+ const displayError = assetsError || error;
3846
+ const containerStyles = {
3847
+ backgroundColor: styles?.container?.backgroundColor || styles?.primaryBackground || theme.colors.background,
3848
+ border: `1px solid ${styles?.container?.borderColor || theme.colors.border}`,
3849
+ borderRadius: styles?.container?.borderRadius || theme.borderRadius.lg,
3850
+ padding: styles?.container?.padding || theme.spacing.md,
3851
+ width: styles?.container?.width || "100%",
3852
+ maxWidth: "28rem",
3853
+ margin: "0 auto",
3854
+ color: theme.colors.text,
3855
+ fontFamily: theme.typography.fontFamily,
3856
+ boxShadow: styles?.container?.boxShadow || (theme.mode === "light" ? "0 4px 6px -1px rgb(0 0 0 / 0.1)" : "0 4px 6px -1px rgb(0 0 0 / 0.3)")
3857
+ };
3858
+ if (intentStatus) {
3859
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className, children: /* @__PURE__ */ jsxRuntime.jsx(
3860
+ StatusDisplay,
3861
+ {
3862
+ intentStatus,
3863
+ onClose: clearStatus,
3864
+ onRetry: () => {
3865
+ clearStatus();
3866
+ handleDeposit();
3867
+ },
3868
+ onNewSwap: () => {
3869
+ clearStatus();
3870
+ setSelectedDepositAsset(null);
3871
+ refreshAssets();
3872
+ },
3873
+ explorerUrlBuilder: (chainId, txHash) => getExplorerUrl(chainId, txHash),
3874
+ theme
3875
+ }
3876
+ ) });
3877
+ }
3878
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: containerStyles, className, children: [
3879
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { marginBottom: theme.spacing.sm }, children: /* @__PURE__ */ jsxRuntime.jsxs(
3880
+ "div",
3881
+ {
3882
+ style: {
3883
+ padding: styles?.statusDisplay?.padding || "8px",
3884
+ backgroundColor: styles?.statusDisplay?.backgroundColor || styles?.tertiaryBackground || (theme.mode === "light" ? "#f9fafb" : theme.colors.surface),
3885
+ border: `1px solid ${styles?.statusDisplay?.borderColor || (theme.mode === "light" ? "#e5e7eb" : theme.colors.border)}`,
3886
+ borderRadius: styles?.statusDisplay?.borderRadius || theme.borderRadius.md
3887
+ },
3888
+ children: [
3889
+ /* @__PURE__ */ jsxRuntime.jsxs(
3890
+ "div",
3891
+ {
3892
+ style: {
3893
+ display: "flex",
3894
+ alignItems: "center",
3895
+ justifyContent: "space-between"
3896
+ },
3897
+ children: [
3898
+ /* @__PURE__ */ jsxRuntime.jsxs(
3899
+ "span",
3900
+ {
3901
+ style: {
3902
+ fontSize: styles?.statusDisplay?.text?.fontSize || theme.typography.fontSize.xs,
3903
+ fontWeight: styles?.statusDisplay?.text?.fontWeight || theme.typography.fontWeight.medium,
3904
+ color: styles?.statusDisplay?.text?.color || theme.colors.text,
3905
+ fontFamily: styles?.statusDisplay?.text?.fontFamily || theme.typography.fontFamily
3906
+ },
3907
+ children: [
3908
+ spiceFlowContext?.provider === "privy" ? "Privy" : spiceFlowContext?.provider === "dynamic" ? "Dynamic" : "Wallet",
3909
+ " ",
3910
+ "Status"
3911
+ ]
3912
+ }
3913
+ ),
3914
+ /* @__PURE__ */ jsxRuntime.jsx(
3915
+ "span",
3916
+ {
3917
+ style: {
3918
+ fontSize: styles?.statusDisplay?.text?.fontSize || theme.typography.fontSize.xs,
3919
+ padding: `2px ${theme.spacing.xs}`,
3920
+ borderRadius: theme.borderRadius.sm,
3921
+ border: `1px solid ${isConnected ? styles?.statusDisplay?.successColor || theme.colors.success : styles?.statusDisplay?.warningColor || theme.colors.warning}`,
3922
+ backgroundColor: isConnected ? theme.mode === "light" ? "#dcfce7" : `${styles?.statusDisplay?.successColor || theme.colors.success}20` : theme.mode === "light" ? "#fef3c7" : `${styles?.statusDisplay?.warningColor || theme.colors.warning}20`,
3923
+ color: isConnected ? styles?.statusDisplay?.successColor || theme.colors.success : styles?.statusDisplay?.warningColor || theme.colors.warning,
3924
+ fontFamily: styles?.statusDisplay?.text?.fontFamily || theme.typography.fontFamily
3925
+ },
3926
+ children: isConnected ? "Connected" : "Disconnected"
3927
+ }
3928
+ )
3929
+ ]
3930
+ }
3931
+ ),
3932
+ isConnected && address && /* @__PURE__ */ jsxRuntime.jsxs(
3933
+ "div",
3934
+ {
3935
+ className: "ibm-plex-mono",
3936
+ style: {
3937
+ marginTop: "6px",
3938
+ backgroundColor: styles?.addressDisplay?.backgroundColor || (theme.mode === "light" ? "#f3f4f6" : theme.colors.secondary),
3939
+ border: `1px solid ${styles?.addressDisplay?.borderColor || (theme.mode === "light" ? "#d1d5db" : theme.colors.borderHover)}`,
3940
+ borderRadius: styles?.addressDisplay?.borderRadius || theme.borderRadius.sm,
3941
+ padding: styles?.addressDisplay?.padding || `${theme.spacing.xs} ${theme.spacing.sm}`,
3942
+ fontSize: styles?.addressDisplay?.fontSize || theme.typography.fontSize.xs,
3943
+ fontFamily: styles?.addressDisplay?.fontFamily || (styles?.fontFamily ? `${styles.fontFamily}, IBM Plex Mono` : "IBM Plex Mono"),
3944
+ color: styles?.addressDisplay?.color || theme.colors.text,
3945
+ display: "flex",
3946
+ alignItems: "center",
3947
+ gap: theme.spacing.sm
3948
+ },
3949
+ children: [
3950
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { flex: 1 }, children: [
3951
+ address.slice(0, 6),
3952
+ "...",
3953
+ address.slice(-4)
3954
+ ] }),
3955
+ /* @__PURE__ */ jsxRuntime.jsx(
3956
+ "button",
3957
+ {
3958
+ style: {
3959
+ fontSize: styles?.addressDisplay?.copyButton?.fontSize || theme.typography.fontSize.xs,
3960
+ padding: styles?.addressDisplay?.copyButton?.padding || `${theme.spacing.xs} ${theme.spacing.sm}`,
3961
+ backgroundColor: styles?.addressDisplay?.copyButton?.backgroundColor || (theme.mode === "light" ? "#e5e7eb" : theme.colors.surfaceHover),
3962
+ border: `1px solid ${styles?.addressDisplay?.copyButton?.borderColor || (theme.mode === "light" ? "#d1d5db" : theme.colors.border)}`,
3963
+ borderRadius: styles?.addressDisplay?.copyButton?.borderRadius || theme.borderRadius.sm,
3964
+ color: styles?.addressDisplay?.copyButton?.color || theme.colors.text,
3965
+ fontFamily: styles?.addressDisplay?.copyButton?.fontFamily || theme.typography.fontFamily,
3966
+ cursor: "pointer",
3967
+ transition: `background-color ${theme.animation.normal}`
3968
+ },
3969
+ onClick: () => copyToClipboard(address),
3970
+ title: "Copy address",
3971
+ children: "Copy"
3972
+ }
3973
+ )
3974
+ ]
3975
+ }
3976
+ ),
3977
+ !ready && /* @__PURE__ */ jsxRuntime.jsxs(
3978
+ "div",
3979
+ {
3980
+ style: {
3981
+ marginTop: "6px",
3982
+ fontSize: theme.typography.fontSize.xs,
3983
+ color: theme.colors.textSecondary,
3984
+ fontFamily: theme.typography.fontFamily
3985
+ },
3986
+ children: [
3987
+ "Loading",
3988
+ " ",
3989
+ spiceFlowContext?.provider === "privy" ? "Privy" : spiceFlowContext?.provider === "dynamic" ? "Dynamic" : "Wallet",
3990
+ "..."
3991
+ ]
3992
+ }
3993
+ )
3994
+ ]
3995
+ }
3996
+ ) }),
3997
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { marginBottom: theme.spacing.sm }, children: /* @__PURE__ */ jsxRuntime.jsx(
3998
+ AssetSelector,
3999
+ {
4000
+ assets: depositAssets,
4001
+ selectedAsset: selectedDepositAsset || void 0,
4002
+ onAssetSelect: handleDepositAssetSelect,
4003
+ onAmountChange: handleDepositAmountChange,
4004
+ loading: loadingAssets,
4005
+ label: "Deposit",
4006
+ showBalance: true,
4007
+ showMaxButton: true,
4008
+ theme,
4009
+ styles
4010
+ }
4011
+ ) }),
4012
+ depositBatches.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { marginBottom: theme.spacing.sm }, children: /* @__PURE__ */ jsxRuntime.jsxs(
4013
+ "div",
4014
+ {
4015
+ style: {
4016
+ backgroundColor: styles?.infoCard?.backgroundColor || styles?.tertiaryBackground || (theme.mode === "light" ? "#f9fafb" : theme.colors.surface),
4017
+ border: `1px solid ${styles?.infoCard?.borderColor || (theme.mode === "light" ? "#e5e7eb" : theme.colors.border)}`,
4018
+ borderRadius: styles?.infoCard?.borderRadius || theme.borderRadius.md,
4019
+ padding: styles?.infoCard?.padding || theme.spacing.sm
4020
+ },
4021
+ children: [
4022
+ /* @__PURE__ */ jsxRuntime.jsx(
4023
+ "div",
4024
+ {
4025
+ style: {
4026
+ fontSize: styles?.infoCard?.title?.fontSize || theme.typography.fontSize.xs,
4027
+ fontWeight: styles?.infoCard?.title?.fontWeight || theme.typography.fontWeight.medium,
4028
+ color: styles?.infoCard?.title?.color || theme.colors.text,
4029
+ fontFamily: styles?.infoCard?.title?.fontFamily || theme.typography.fontFamily,
4030
+ marginBottom: "4px"
4031
+ },
4032
+ children: "Deposit Batches Ready"
4033
+ }
4034
+ ),
4035
+ /* @__PURE__ */ jsxRuntime.jsxs(
4036
+ "div",
4037
+ {
4038
+ style: {
4039
+ fontSize: styles?.infoCard?.description?.fontSize || theme.typography.fontSize.xs,
4040
+ color: styles?.infoCard?.description?.color || theme.colors.textSecondary,
4041
+ fontFamily: styles?.infoCard?.description?.fontFamily || theme.typography.fontFamily
4042
+ },
4043
+ children: [
4044
+ depositBatches.length,
4045
+ " deposit batch",
4046
+ depositBatches.length > 1 ? "es" : "",
4047
+ " across chains:",
4048
+ " ",
4049
+ [...new Set(depositBatches.map((b) => b.chainId))].join(", ")
4050
+ ]
4051
+ }
4052
+ )
4053
+ ]
4054
+ }
4055
+ ) }),
4056
+ displayError && /* @__PURE__ */ jsxRuntime.jsx(
4057
+ "div",
4058
+ {
4059
+ style: {
4060
+ backgroundColor: styles?.errorMessage?.backgroundColor || (theme.mode === "light" ? "#fef2f2" : `${styles?.statusDisplay?.errorColor || theme.colors.error}20`),
4061
+ border: `1px solid ${styles?.errorMessage?.borderColor || (theme.mode === "light" ? "#fecaca" : styles?.statusDisplay?.errorColor || theme.colors.error)}`,
4062
+ borderRadius: styles?.errorMessage?.borderRadius || theme.borderRadius.md,
4063
+ padding: styles?.errorMessage?.padding || theme.spacing.md,
4064
+ marginBottom: theme.spacing.sm
4065
+ },
4066
+ children: /* @__PURE__ */ jsxRuntime.jsx(
4067
+ "p",
4068
+ {
4069
+ style: {
4070
+ color: styles?.errorMessage?.color || styles?.statusDisplay?.errorColor || theme.colors.error,
4071
+ fontSize: styles?.errorMessage?.fontSize || theme.typography.fontSize.sm,
4072
+ fontWeight: styles?.errorMessage?.fontWeight,
4073
+ fontFamily: styles?.errorMessage?.fontFamily || theme.typography.fontFamily,
4074
+ margin: 0
4075
+ },
4076
+ children: displayError
4077
+ }
4078
+ )
4079
+ }
4080
+ ),
4081
+ /* @__PURE__ */ jsxRuntime.jsx(
4082
+ "div",
4083
+ {
4084
+ style: {
4085
+ display: "flex",
4086
+ flexDirection: "column",
4087
+ gap: theme.spacing.sm
4088
+ },
4089
+ children: /* @__PURE__ */ jsxRuntime.jsx(
4090
+ Button.Button,
4091
+ {
4092
+ variant: "primary",
4093
+ fullWidth: true,
4094
+ onClick: handleDeposit,
4095
+ loading: isExecuting,
4096
+ disabled: !canDeposit || !isConnected,
4097
+ theme,
4098
+ styles,
4099
+ children: !ready ? "Loading..." : !authenticated ? "Authentication Required" : !isConnected ? "Wallet Not Connected" : isExecuting ? "Executing Deposit..." : !selectedDepositAsset ? "Select Token" : !selectedDepositAsset.amount ? "Enter Amount" : parseFloat(selectedDepositAsset.amount) > selectedDepositAsset.asset.balanceFormatted ? "Insufficient Balance" : depositBatches.length === 0 ? "No Deposit Batches" : "Execute Deposit"
4100
+ }
4101
+ )
4102
+ }
4103
+ )
4104
+ ] });
4105
+ };
4106
+
3672
4107
  /**
3673
4108
  * @license lucide-react v0.383.0 - ISC
3674
4109
  *
@@ -9397,6 +9832,7 @@ const useToInputUpdate = () => {
9397
9832
  exports.ConnectWalletModal = ConnectWalletModal;
9398
9833
  exports.DebugWidget = DebugWidget;
9399
9834
  exports.DepositModal = DepositModal;
9835
+ exports.DepositWidget = DepositWidget;
9400
9836
  exports.LpModal = LpModal;
9401
9837
  exports.ProviderLogin = ProviderLogin;
9402
9838
  exports.SelectChainModal = SelectChainModal;
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import "./globals.css";
2
2
  export { SwapWidget } from "./components/SwapWidget";
3
3
  export { DebugWidget } from "./components/DebugWidget";
4
+ export { DepositWidget } from "./components/DepositWidget";
4
5
  export { SpiceDeposit, SelectChainModal, ConnectWalletModal, DepositModal, } from "./components/SpiceDeposit";
5
6
  export { SpiceBalance } from "./components/SpiceBalance";
6
7
  export { LpModal } from "./components/LpModal";
@@ -9,6 +10,7 @@ export type { SpiceFlowProviderProps } from "./providers";
9
10
  export { ProviderLogin } from "./components/ProviderLogins";
10
11
  export type { ProviderLoginProps } from "./components/ProviderLogins";
11
12
  export type { SwapWidgetProps, SwapConfig } from "./types/swap";
13
+ export type { DepositWidgetProps } from "./types/deposit";
12
14
  export type { RelayerSubmitRequest, RelayerSubmitResponse, } from "./types/relayer";
13
15
  export type { DebugWidgetProps } from "./components/DebugWidget";
14
16
  export type { SpiceDepositProps } from "./components/SpiceDeposit/SpiceDeposit";
package/dist/index.js CHANGED
@@ -3667,6 +3667,441 @@ const DebugWidget = (props) => {
3667
3667
  return /* @__PURE__ */ jsx(DebugWidgetErrorBoundary, { fallback: fallbackComponent, children: /* @__PURE__ */ jsx(DebugWidgetInternal, { ...props }) });
3668
3668
  };
3669
3669
 
3670
+ const DepositWidget = ({
3671
+ depositBatches,
3672
+ tokenAddress = "0x0",
3673
+ supportedChains,
3674
+ theme: themeMode = "light",
3675
+ styles,
3676
+ className = "",
3677
+ depositInputHook,
3678
+ onDepositSuccess,
3679
+ onDepositError
3680
+ }) => {
3681
+ const baseTheme = createTheme(themeMode);
3682
+ const theme = {
3683
+ ...baseTheme,
3684
+ typography: {
3685
+ ...baseTheme.typography,
3686
+ fontFamily: styles?.fontFamily || baseTheme.typography.fontFamily
3687
+ },
3688
+ colors: {
3689
+ ...baseTheme.colors,
3690
+ primary: styles?.primaryColor || baseTheme.colors.primary,
3691
+ primaryHover: styles?.primaryColor ? `${styles.primaryColor}dd` : baseTheme.colors.primaryHover
3692
+ }
3693
+ };
3694
+ const wallet = useWallet();
3695
+ const {
3696
+ isReady: ready,
3697
+ isAuthenticated: authenticated,
3698
+ isConnected,
3699
+ address,
3700
+ provider,
3701
+ actions
3702
+ } = wallet;
3703
+ const spiceFlowContext = useContext(SpiceFlowProviderContext);
3704
+ const [selectedDepositAsset, setSelectedDepositAsset] = useState(null);
3705
+ const [isPending, startTransition] = useTransition();
3706
+ const {
3707
+ assets,
3708
+ loading: loadingAssets,
3709
+ error: assetsError,
3710
+ refreshAssets
3711
+ } = useAssets({
3712
+ address,
3713
+ supportedChains,
3714
+ fetchBalances
3715
+ });
3716
+ const [isExecuting, setIsExecuting] = useState(false);
3717
+ const [error, setError] = useState(null);
3718
+ const { intentStatus, startStatusPolling, clearStatus } = useStatus({
3719
+ checkStepStatus: (intentId, stepId) => relayerService.checkStepStatus(intentId, stepId)
3720
+ });
3721
+ useEffect(() => {
3722
+ if (depositInputHook && depositInputHook.depositAmount !== selectedDepositAsset?.amount) {
3723
+ if (selectedDepositAsset) {
3724
+ setSelectedDepositAsset({
3725
+ ...selectedDepositAsset,
3726
+ amount: depositInputHook.depositAmount
3727
+ });
3728
+ }
3729
+ }
3730
+ }, [depositInputHook?.depositAmount, selectedDepositAsset]);
3731
+ const clearError = useCallback(() => {
3732
+ setError(null);
3733
+ }, []);
3734
+ const handleDepositAssetSelect = (asset) => {
3735
+ setSelectedDepositAsset({
3736
+ asset,
3737
+ amount: selectedDepositAsset?.amount || ""
3738
+ });
3739
+ clearError();
3740
+ };
3741
+ const handleDepositAmountChange = useCallback(
3742
+ (amount) => {
3743
+ if (selectedDepositAsset) {
3744
+ startTransition(() => {
3745
+ setSelectedDepositAsset({
3746
+ ...selectedDepositAsset,
3747
+ amount
3748
+ });
3749
+ clearError();
3750
+ });
3751
+ if (depositInputHook) {
3752
+ depositInputHook.setDepositAmount(amount);
3753
+ }
3754
+ }
3755
+ },
3756
+ [selectedDepositAsset, depositInputHook, clearError]
3757
+ );
3758
+ const handleDeposit = async () => {
3759
+ if (!selectedDepositAsset || !address || depositBatches.length === 0)
3760
+ return;
3761
+ if (!ready || !authenticated) {
3762
+ setError(
3763
+ `Please authenticate with ${provider || "wallet provider"} to continue`
3764
+ );
3765
+ return;
3766
+ }
3767
+ setIsExecuting(true);
3768
+ setError(null);
3769
+ try {
3770
+ const depositClient = getClientForChain(
3771
+ selectedDepositAsset.asset.chainId
3772
+ );
3773
+ const depositRecentBlock = await depositClient.getBlockNumber();
3774
+ const depositAssetBatch = {
3775
+ chainId: selectedDepositAsset.asset.chainId,
3776
+ recentBlock: depositRecentBlock,
3777
+ calls: [
3778
+ {
3779
+ to: "0xeee2b52e7CFe6e2168341a34cEB783b68FEdf1A2",
3780
+ // Escrow contract address
3781
+ value: parseEther(selectedDepositAsset.amount),
3782
+ data: "0x"
3783
+ }
3784
+ ]
3785
+ };
3786
+ const allChainBatches = [depositAssetBatch, ...depositBatches];
3787
+ const uniqueChainIds = [
3788
+ ...new Set(allChainBatches.map((batch) => batch.chainId))
3789
+ ];
3790
+ const authorizations = [];
3791
+ for (const chainId of uniqueChainIds) {
3792
+ const client = getClientForChain(chainId);
3793
+ const delegateContract = getDelegateContractAddress(chainId);
3794
+ const nonce = await getAccountNonce(
3795
+ address,
3796
+ client
3797
+ );
3798
+ const auth = await actions.signAuthorization({
3799
+ contractAddress: delegateContract,
3800
+ chainId,
3801
+ nonce: Number(nonce)
3802
+ });
3803
+ authorizations.push(auth);
3804
+ console.log("auth for chain", chainId, auth);
3805
+ }
3806
+ const hashedChainBatches = hashChainBatches(allChainBatches);
3807
+ const digest = getAuthorizationHash(hashedChainBatches);
3808
+ const intentSignature = await actions.signMessage(digest);
3809
+ if (!intentSignature)
3810
+ throw new Error("Failed to sign intent authorization");
3811
+ const submitRequest = {
3812
+ tokenAddress,
3813
+ tokenAmount: parseEther(selectedDepositAsset.amount),
3814
+ address,
3815
+ authorization: authorizations,
3816
+ intentAuthorization: {
3817
+ signature: intentSignature.signature,
3818
+ chainBatches: hashedChainBatches
3819
+ }
3820
+ };
3821
+ const result = await relayerService.submitTransaction(submitRequest);
3822
+ if (result) {
3823
+ const getChainName = (chainId) => {
3824
+ return `Chain ${chainId}`;
3825
+ };
3826
+ const initialSteps = createInitialSteps(allChainBatches, getChainName);
3827
+ startStatusPolling(result.intentId, initialSteps);
3828
+ onDepositSuccess?.(result.intentId);
3829
+ refreshAssets();
3830
+ }
3831
+ } catch (error2) {
3832
+ const errorMessage = error2 instanceof Error ? error2.message : "Deposit failed";
3833
+ setError(errorMessage);
3834
+ onDepositError?.(errorMessage);
3835
+ } finally {
3836
+ setIsExecuting(false);
3837
+ }
3838
+ };
3839
+ const depositAssets = supportedChains.flatMap(
3840
+ (chainId) => getAllAssetsForChain(chainId, assets)
3841
+ );
3842
+ const canDeposit = selectedDepositAsset && selectedDepositAsset.amount && parseFloat(selectedDepositAsset.amount) > 0 && parseFloat(selectedDepositAsset.amount) <= selectedDepositAsset.asset.balanceFormatted && isConnected && !isExecuting && depositBatches.length > 0;
3843
+ const displayError = assetsError || error;
3844
+ const containerStyles = {
3845
+ backgroundColor: styles?.container?.backgroundColor || styles?.primaryBackground || theme.colors.background,
3846
+ border: `1px solid ${styles?.container?.borderColor || theme.colors.border}`,
3847
+ borderRadius: styles?.container?.borderRadius || theme.borderRadius.lg,
3848
+ padding: styles?.container?.padding || theme.spacing.md,
3849
+ width: styles?.container?.width || "100%",
3850
+ maxWidth: "28rem",
3851
+ margin: "0 auto",
3852
+ color: theme.colors.text,
3853
+ fontFamily: theme.typography.fontFamily,
3854
+ boxShadow: styles?.container?.boxShadow || (theme.mode === "light" ? "0 4px 6px -1px rgb(0 0 0 / 0.1)" : "0 4px 6px -1px rgb(0 0 0 / 0.3)")
3855
+ };
3856
+ if (intentStatus) {
3857
+ return /* @__PURE__ */ jsx("div", { className, children: /* @__PURE__ */ jsx(
3858
+ StatusDisplay,
3859
+ {
3860
+ intentStatus,
3861
+ onClose: clearStatus,
3862
+ onRetry: () => {
3863
+ clearStatus();
3864
+ handleDeposit();
3865
+ },
3866
+ onNewSwap: () => {
3867
+ clearStatus();
3868
+ setSelectedDepositAsset(null);
3869
+ refreshAssets();
3870
+ },
3871
+ explorerUrlBuilder: (chainId, txHash) => getExplorerUrl(chainId, txHash),
3872
+ theme
3873
+ }
3874
+ ) });
3875
+ }
3876
+ return /* @__PURE__ */ jsxs("div", { style: containerStyles, className, children: [
3877
+ /* @__PURE__ */ jsx("div", { style: { marginBottom: theme.spacing.sm }, children: /* @__PURE__ */ jsxs(
3878
+ "div",
3879
+ {
3880
+ style: {
3881
+ padding: styles?.statusDisplay?.padding || "8px",
3882
+ backgroundColor: styles?.statusDisplay?.backgroundColor || styles?.tertiaryBackground || (theme.mode === "light" ? "#f9fafb" : theme.colors.surface),
3883
+ border: `1px solid ${styles?.statusDisplay?.borderColor || (theme.mode === "light" ? "#e5e7eb" : theme.colors.border)}`,
3884
+ borderRadius: styles?.statusDisplay?.borderRadius || theme.borderRadius.md
3885
+ },
3886
+ children: [
3887
+ /* @__PURE__ */ jsxs(
3888
+ "div",
3889
+ {
3890
+ style: {
3891
+ display: "flex",
3892
+ alignItems: "center",
3893
+ justifyContent: "space-between"
3894
+ },
3895
+ children: [
3896
+ /* @__PURE__ */ jsxs(
3897
+ "span",
3898
+ {
3899
+ style: {
3900
+ fontSize: styles?.statusDisplay?.text?.fontSize || theme.typography.fontSize.xs,
3901
+ fontWeight: styles?.statusDisplay?.text?.fontWeight || theme.typography.fontWeight.medium,
3902
+ color: styles?.statusDisplay?.text?.color || theme.colors.text,
3903
+ fontFamily: styles?.statusDisplay?.text?.fontFamily || theme.typography.fontFamily
3904
+ },
3905
+ children: [
3906
+ spiceFlowContext?.provider === "privy" ? "Privy" : spiceFlowContext?.provider === "dynamic" ? "Dynamic" : "Wallet",
3907
+ " ",
3908
+ "Status"
3909
+ ]
3910
+ }
3911
+ ),
3912
+ /* @__PURE__ */ jsx(
3913
+ "span",
3914
+ {
3915
+ style: {
3916
+ fontSize: styles?.statusDisplay?.text?.fontSize || theme.typography.fontSize.xs,
3917
+ padding: `2px ${theme.spacing.xs}`,
3918
+ borderRadius: theme.borderRadius.sm,
3919
+ border: `1px solid ${isConnected ? styles?.statusDisplay?.successColor || theme.colors.success : styles?.statusDisplay?.warningColor || theme.colors.warning}`,
3920
+ backgroundColor: isConnected ? theme.mode === "light" ? "#dcfce7" : `${styles?.statusDisplay?.successColor || theme.colors.success}20` : theme.mode === "light" ? "#fef3c7" : `${styles?.statusDisplay?.warningColor || theme.colors.warning}20`,
3921
+ color: isConnected ? styles?.statusDisplay?.successColor || theme.colors.success : styles?.statusDisplay?.warningColor || theme.colors.warning,
3922
+ fontFamily: styles?.statusDisplay?.text?.fontFamily || theme.typography.fontFamily
3923
+ },
3924
+ children: isConnected ? "Connected" : "Disconnected"
3925
+ }
3926
+ )
3927
+ ]
3928
+ }
3929
+ ),
3930
+ isConnected && address && /* @__PURE__ */ jsxs(
3931
+ "div",
3932
+ {
3933
+ className: "ibm-plex-mono",
3934
+ style: {
3935
+ marginTop: "6px",
3936
+ backgroundColor: styles?.addressDisplay?.backgroundColor || (theme.mode === "light" ? "#f3f4f6" : theme.colors.secondary),
3937
+ border: `1px solid ${styles?.addressDisplay?.borderColor || (theme.mode === "light" ? "#d1d5db" : theme.colors.borderHover)}`,
3938
+ borderRadius: styles?.addressDisplay?.borderRadius || theme.borderRadius.sm,
3939
+ padding: styles?.addressDisplay?.padding || `${theme.spacing.xs} ${theme.spacing.sm}`,
3940
+ fontSize: styles?.addressDisplay?.fontSize || theme.typography.fontSize.xs,
3941
+ fontFamily: styles?.addressDisplay?.fontFamily || (styles?.fontFamily ? `${styles.fontFamily}, IBM Plex Mono` : "IBM Plex Mono"),
3942
+ color: styles?.addressDisplay?.color || theme.colors.text,
3943
+ display: "flex",
3944
+ alignItems: "center",
3945
+ gap: theme.spacing.sm
3946
+ },
3947
+ children: [
3948
+ /* @__PURE__ */ jsxs("span", { style: { flex: 1 }, children: [
3949
+ address.slice(0, 6),
3950
+ "...",
3951
+ address.slice(-4)
3952
+ ] }),
3953
+ /* @__PURE__ */ jsx(
3954
+ "button",
3955
+ {
3956
+ style: {
3957
+ fontSize: styles?.addressDisplay?.copyButton?.fontSize || theme.typography.fontSize.xs,
3958
+ padding: styles?.addressDisplay?.copyButton?.padding || `${theme.spacing.xs} ${theme.spacing.sm}`,
3959
+ backgroundColor: styles?.addressDisplay?.copyButton?.backgroundColor || (theme.mode === "light" ? "#e5e7eb" : theme.colors.surfaceHover),
3960
+ border: `1px solid ${styles?.addressDisplay?.copyButton?.borderColor || (theme.mode === "light" ? "#d1d5db" : theme.colors.border)}`,
3961
+ borderRadius: styles?.addressDisplay?.copyButton?.borderRadius || theme.borderRadius.sm,
3962
+ color: styles?.addressDisplay?.copyButton?.color || theme.colors.text,
3963
+ fontFamily: styles?.addressDisplay?.copyButton?.fontFamily || theme.typography.fontFamily,
3964
+ cursor: "pointer",
3965
+ transition: `background-color ${theme.animation.normal}`
3966
+ },
3967
+ onClick: () => copyToClipboard(address),
3968
+ title: "Copy address",
3969
+ children: "Copy"
3970
+ }
3971
+ )
3972
+ ]
3973
+ }
3974
+ ),
3975
+ !ready && /* @__PURE__ */ jsxs(
3976
+ "div",
3977
+ {
3978
+ style: {
3979
+ marginTop: "6px",
3980
+ fontSize: theme.typography.fontSize.xs,
3981
+ color: theme.colors.textSecondary,
3982
+ fontFamily: theme.typography.fontFamily
3983
+ },
3984
+ children: [
3985
+ "Loading",
3986
+ " ",
3987
+ spiceFlowContext?.provider === "privy" ? "Privy" : spiceFlowContext?.provider === "dynamic" ? "Dynamic" : "Wallet",
3988
+ "..."
3989
+ ]
3990
+ }
3991
+ )
3992
+ ]
3993
+ }
3994
+ ) }),
3995
+ /* @__PURE__ */ jsx("div", { style: { marginBottom: theme.spacing.sm }, children: /* @__PURE__ */ jsx(
3996
+ AssetSelector,
3997
+ {
3998
+ assets: depositAssets,
3999
+ selectedAsset: selectedDepositAsset || void 0,
4000
+ onAssetSelect: handleDepositAssetSelect,
4001
+ onAmountChange: handleDepositAmountChange,
4002
+ loading: loadingAssets,
4003
+ label: "Deposit",
4004
+ showBalance: true,
4005
+ showMaxButton: true,
4006
+ theme,
4007
+ styles
4008
+ }
4009
+ ) }),
4010
+ depositBatches.length > 0 && /* @__PURE__ */ jsx("div", { style: { marginBottom: theme.spacing.sm }, children: /* @__PURE__ */ jsxs(
4011
+ "div",
4012
+ {
4013
+ style: {
4014
+ backgroundColor: styles?.infoCard?.backgroundColor || styles?.tertiaryBackground || (theme.mode === "light" ? "#f9fafb" : theme.colors.surface),
4015
+ border: `1px solid ${styles?.infoCard?.borderColor || (theme.mode === "light" ? "#e5e7eb" : theme.colors.border)}`,
4016
+ borderRadius: styles?.infoCard?.borderRadius || theme.borderRadius.md,
4017
+ padding: styles?.infoCard?.padding || theme.spacing.sm
4018
+ },
4019
+ children: [
4020
+ /* @__PURE__ */ jsx(
4021
+ "div",
4022
+ {
4023
+ style: {
4024
+ fontSize: styles?.infoCard?.title?.fontSize || theme.typography.fontSize.xs,
4025
+ fontWeight: styles?.infoCard?.title?.fontWeight || theme.typography.fontWeight.medium,
4026
+ color: styles?.infoCard?.title?.color || theme.colors.text,
4027
+ fontFamily: styles?.infoCard?.title?.fontFamily || theme.typography.fontFamily,
4028
+ marginBottom: "4px"
4029
+ },
4030
+ children: "Deposit Batches Ready"
4031
+ }
4032
+ ),
4033
+ /* @__PURE__ */ jsxs(
4034
+ "div",
4035
+ {
4036
+ style: {
4037
+ fontSize: styles?.infoCard?.description?.fontSize || theme.typography.fontSize.xs,
4038
+ color: styles?.infoCard?.description?.color || theme.colors.textSecondary,
4039
+ fontFamily: styles?.infoCard?.description?.fontFamily || theme.typography.fontFamily
4040
+ },
4041
+ children: [
4042
+ depositBatches.length,
4043
+ " deposit batch",
4044
+ depositBatches.length > 1 ? "es" : "",
4045
+ " across chains:",
4046
+ " ",
4047
+ [...new Set(depositBatches.map((b) => b.chainId))].join(", ")
4048
+ ]
4049
+ }
4050
+ )
4051
+ ]
4052
+ }
4053
+ ) }),
4054
+ displayError && /* @__PURE__ */ jsx(
4055
+ "div",
4056
+ {
4057
+ style: {
4058
+ backgroundColor: styles?.errorMessage?.backgroundColor || (theme.mode === "light" ? "#fef2f2" : `${styles?.statusDisplay?.errorColor || theme.colors.error}20`),
4059
+ border: `1px solid ${styles?.errorMessage?.borderColor || (theme.mode === "light" ? "#fecaca" : styles?.statusDisplay?.errorColor || theme.colors.error)}`,
4060
+ borderRadius: styles?.errorMessage?.borderRadius || theme.borderRadius.md,
4061
+ padding: styles?.errorMessage?.padding || theme.spacing.md,
4062
+ marginBottom: theme.spacing.sm
4063
+ },
4064
+ children: /* @__PURE__ */ jsx(
4065
+ "p",
4066
+ {
4067
+ style: {
4068
+ color: styles?.errorMessage?.color || styles?.statusDisplay?.errorColor || theme.colors.error,
4069
+ fontSize: styles?.errorMessage?.fontSize || theme.typography.fontSize.sm,
4070
+ fontWeight: styles?.errorMessage?.fontWeight,
4071
+ fontFamily: styles?.errorMessage?.fontFamily || theme.typography.fontFamily,
4072
+ margin: 0
4073
+ },
4074
+ children: displayError
4075
+ }
4076
+ )
4077
+ }
4078
+ ),
4079
+ /* @__PURE__ */ jsx(
4080
+ "div",
4081
+ {
4082
+ style: {
4083
+ display: "flex",
4084
+ flexDirection: "column",
4085
+ gap: theme.spacing.sm
4086
+ },
4087
+ children: /* @__PURE__ */ jsx(
4088
+ Button,
4089
+ {
4090
+ variant: "primary",
4091
+ fullWidth: true,
4092
+ onClick: handleDeposit,
4093
+ loading: isExecuting,
4094
+ disabled: !canDeposit || !isConnected,
4095
+ theme,
4096
+ styles,
4097
+ children: !ready ? "Loading..." : !authenticated ? "Authentication Required" : !isConnected ? "Wallet Not Connected" : isExecuting ? "Executing Deposit..." : !selectedDepositAsset ? "Select Token" : !selectedDepositAsset.amount ? "Enter Amount" : parseFloat(selectedDepositAsset.amount) > selectedDepositAsset.asset.balanceFormatted ? "Insufficient Balance" : depositBatches.length === 0 ? "No Deposit Batches" : "Execute Deposit"
4098
+ }
4099
+ )
4100
+ }
4101
+ )
4102
+ ] });
4103
+ };
4104
+
3670
4105
  /**
3671
4106
  * @license lucide-react v0.383.0 - ISC
3672
4107
  *
@@ -9392,4 +9827,4 @@ const useToInputUpdate = () => {
9392
9827
  };
9393
9828
  };
9394
9829
 
9395
- export { ConnectWalletModal, DebugWidget, DepositModal, LpModal, ProviderLogin, SelectChainModal, SpiceBalance, SpiceDeposit, SpiceFlowProvider, SpiceFlowProviderContext, SwapWidget, fetchBalances, useAssets, useFromInput, useStatus, useToInputUpdate, useWallet };
9830
+ export { ConnectWalletModal, DebugWidget, DepositModal, DepositWidget, LpModal, ProviderLogin, SelectChainModal, SpiceBalance, SpiceDeposit, SpiceFlowProvider, SpiceFlowProviderContext, SwapWidget, fetchBalances, useAssets, useFromInput, useStatus, useToInputUpdate, useWallet };
@@ -1,5 +1,5 @@
1
1
  import { Asset } from "./assets";
2
- import { CustomStyles } from "./theme";
2
+ import { CustomStyles, ThemeMode } from "./theme";
3
3
  import { UseDepositInputReturn } from "../hooks/useDepositInput";
4
4
  import { Address } from "viem";
5
5
  import { ChainBatch } from ".";
@@ -17,6 +17,17 @@ export interface SpiceDepositResponse {
17
17
  message: string;
18
18
  };
19
19
  }
20
+ export interface DepositWidgetProps {
21
+ depositBatches: ChainBatch[];
22
+ tokenAddress?: Address;
23
+ supportedChains: number[];
24
+ theme?: ThemeMode;
25
+ styles?: CustomStyles;
26
+ className?: string;
27
+ depositInputHook?: UseDepositInputReturn;
28
+ onDepositSuccess?: (intentId: string) => void;
29
+ onDepositError?: (error: string) => void;
30
+ }
20
31
  export interface DepositModalProps {
21
32
  isOpen: boolean;
22
33
  onClose: () => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spicenet-io/spiceflow-ui",
3
- "version": "1.2.6",
3
+ "version": "1.3.0-1",
4
4
  "description": "Spiceflow UI SDK",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs.js",