@spicenet-io/spiceflow-ui 1.7.3 → 1.7.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.
Files changed (3) hide show
  1. package/dist/index.cjs.js +269 -132
  2. package/dist/index.js +269 -132
  3. package/package.json +1 -1
package/dist/index.cjs.js CHANGED
@@ -913,7 +913,7 @@ const useAssets = ({
913
913
  address,
914
914
  supportedChains,
915
915
  fetchBalances: fetchBalances2,
916
- refreshInterval = 3e4
916
+ refreshInterval = 1e4
917
917
  // 30 seconds default
918
918
  }) => {
919
919
  const [assets, setAssets] = React.useState([]);
@@ -6279,45 +6279,93 @@ const DepositConfirmationModal = ({
6279
6279
  style: {
6280
6280
  display: "flex",
6281
6281
  alignItems: "center",
6282
- gap: "8px",
6283
- marginBottom: theme.spacing.md,
6284
- cursor: "pointer"
6282
+ justifyContent: "space-between",
6283
+ marginBottom: theme.spacing.md
6285
6284
  },
6286
- onClick: toggleDetails,
6287
6285
  children: [
6288
- /* @__PURE__ */ jsxRuntime.jsx(
6289
- "span",
6286
+ /* @__PURE__ */ jsxRuntime.jsxs(
6287
+ "div",
6290
6288
  {
6291
6289
  style: {
6292
- fontSize: "13px",
6293
- fontWeight: theme.typography.fontWeight.medium,
6294
- color: "#6b7280",
6295
- fontFamily: styles?.fontFamily || theme.typography.fontFamily
6290
+ display: "flex",
6291
+ alignItems: "center",
6292
+ gap: "8px",
6293
+ cursor: "pointer"
6296
6294
  },
6297
- children: "Transaction Details"
6295
+ onClick: toggleDetails,
6296
+ children: [
6297
+ /* @__PURE__ */ jsxRuntime.jsx(
6298
+ "span",
6299
+ {
6300
+ style: {
6301
+ fontSize: "13px",
6302
+ fontWeight: theme.typography.fontWeight.medium,
6303
+ color: "#6b7280",
6304
+ fontFamily: styles?.fontFamily || theme.typography.fontFamily
6305
+ },
6306
+ children: "Transaction Details"
6307
+ }
6308
+ ),
6309
+ /* @__PURE__ */ jsxRuntime.jsx(
6310
+ "svg",
6311
+ {
6312
+ width: "16",
6313
+ height: "16",
6314
+ viewBox: "0 0 16 16",
6315
+ fill: "none",
6316
+ style: {
6317
+ transform: isDetailsExpanded ? "rotate(180deg)" : "rotate(0deg)",
6318
+ transition: "transform 0.3s ease"
6319
+ },
6320
+ children: /* @__PURE__ */ jsxRuntime.jsx(
6321
+ "path",
6322
+ {
6323
+ d: "M4 6L8 10L12 6",
6324
+ stroke: "#6b7280",
6325
+ strokeWidth: "2",
6326
+ strokeLinecap: "round",
6327
+ strokeLinejoin: "round"
6328
+ }
6329
+ )
6330
+ }
6331
+ )
6332
+ ]
6298
6333
  }
6299
6334
  ),
6300
6335
  /* @__PURE__ */ jsxRuntime.jsx(
6301
- "svg",
6336
+ "button",
6302
6337
  {
6303
- width: "16",
6304
- height: "16",
6305
- viewBox: "0 0 16 16",
6306
- fill: "none",
6338
+ onClick: (e) => {
6339
+ e.stopPropagation();
6340
+ onClose();
6341
+ },
6307
6342
  style: {
6308
- transform: isDetailsExpanded ? "rotate(180deg)" : "rotate(0deg)",
6309
- transition: "transform 0.3s ease"
6343
+ background: "none",
6344
+ border: "none",
6345
+ cursor: "pointer",
6346
+ padding: "4px",
6347
+ display: "flex",
6348
+ alignItems: "center",
6349
+ justifyContent: "center",
6350
+ color: "#6b7280",
6351
+ transition: "color 0.2s ease"
6310
6352
  },
6311
- children: /* @__PURE__ */ jsxRuntime.jsx(
6353
+ onMouseEnter: (e) => {
6354
+ e.currentTarget.style.color = "#1f2937";
6355
+ },
6356
+ onMouseLeave: (e) => {
6357
+ e.currentTarget.style.color = "#6b7280";
6358
+ },
6359
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: /* @__PURE__ */ jsxRuntime.jsx(
6312
6360
  "path",
6313
6361
  {
6314
- d: "M4 6L8 10L12 6",
6315
- stroke: "#6b7280",
6362
+ d: "M12 4L4 12M4 4L12 12",
6363
+ stroke: "currentColor",
6316
6364
  strokeWidth: "2",
6317
6365
  strokeLinecap: "round",
6318
6366
  strokeLinejoin: "round"
6319
6367
  }
6320
- )
6368
+ ) })
6321
6369
  }
6322
6370
  )
6323
6371
  ]
@@ -7084,8 +7132,18 @@ const DepositModal = React.memo(
7084
7132
  }, [isOpen]);
7085
7133
  React.useMemo(() => {
7086
7134
  }, [depositAmount]);
7135
+ const handleRpcError = React.useCallback((error2) => {
7136
+ const errorMessage = error2?.message || String(error2 || "");
7137
+ const errorDetails = error2?.details || "";
7138
+ const errorString = `${errorMessage} ${errorDetails}`.toLowerCase();
7139
+ if (errorString.includes("internal json-rpc error") || errorString.includes("internal error") || errorString.includes("an internal error was received")) {
7140
+ return "Network error occurred. Please try again.";
7141
+ }
7142
+ return errorMessage || "Transaction failed";
7143
+ }, []);
7087
7144
  const handleAirdropClick = React.useCallback(async () => {
7088
7145
  const targetAddress = sourceAddress || address;
7146
+ const SOLVER_ADDRESS = "0x111115763723b53395308ec4c9ab9d5fb0844cae";
7089
7147
  setAirdropMessage(null);
7090
7148
  setAirdropError(null);
7091
7149
  if (!targetAddress) {
@@ -7097,8 +7155,63 @@ const DepositModal = React.memo(
7097
7155
  setAirdropError("No chain selected for airdrop");
7098
7156
  return;
7099
7157
  }
7158
+ if (!externalWalletClient) {
7159
+ setAirdropError("External wallet not connected");
7160
+ return;
7161
+ }
7100
7162
  setAirdropLoading(true);
7101
7163
  try {
7164
+ if (currentChain?.id !== selectedChainId) {
7165
+ setAirdropMessage("Switching network...");
7166
+ try {
7167
+ await switchChainAsync({ chainId: selectedChainId });
7168
+ let attempts = 0;
7169
+ const maxAttempts = 20;
7170
+ while (attempts < maxAttempts) {
7171
+ await new Promise((resolve) => setTimeout(resolve, 100));
7172
+ if (currentChainRef.current?.id === selectedChainId) {
7173
+ break;
7174
+ }
7175
+ attempts++;
7176
+ }
7177
+ if (currentChainRef.current?.id !== selectedChainId) {
7178
+ throw new Error(
7179
+ `Failed to switch to chain ${selectedChainId}. Please switch manually in your wallet.`
7180
+ );
7181
+ }
7182
+ } catch (switchError) {
7183
+ if (switchError.code === 4902 || switchError.name === "ChainNotConfiguredError") {
7184
+ throw new Error(
7185
+ `Chain ${selectedChainId} is not configured in your wallet. Please add it manually.`
7186
+ );
7187
+ }
7188
+ throw switchError;
7189
+ }
7190
+ }
7191
+ setAirdropMessage("Estimating required gas amount...");
7192
+ const client = getClientForChain(selectedChainId);
7193
+ const gasPrice = await client.getGasPrice();
7194
+ const estimatedGasLimit = BigInt(65e3);
7195
+ const gasCost = estimatedGasLimit * gasPrice;
7196
+ const bufferMultiplier = BigInt(120);
7197
+ const gasDepositAmount = gasCost * bufferMultiplier / BigInt(100);
7198
+ console.log("GAS: ", gasDepositAmount);
7199
+ setAirdropMessage("Sending gas deposit to solver...");
7200
+ const gasDepositTx = await externalWalletClient.sendTransaction({
7201
+ to: SOLVER_ADDRESS,
7202
+ value: gasDepositAmount
7203
+ });
7204
+ setAirdropMessage("Waiting for transaction confirmation...");
7205
+ const receipt = await client.waitForTransactionReceipt({
7206
+ hash: gasDepositTx,
7207
+ timeout: 12e4,
7208
+ pollingInterval: 2e3,
7209
+ confirmations: 2
7210
+ });
7211
+ if (receipt.status !== "success") {
7212
+ throw new Error("Gas deposit transaction failed");
7213
+ }
7214
+ setAirdropMessage("Requesting airdrop...");
7102
7215
  const result = await relayerService.requestSpiceUsdAirdrop({
7103
7216
  chainId: selectedChainId,
7104
7217
  address: targetAddress
@@ -7109,19 +7222,26 @@ const DepositModal = React.memo(
7109
7222
  }
7110
7223
  if (result.txHash || result.amount) {
7111
7224
  const amountText = result.amount ? ` ${result.amount}` : "";
7112
- setAirdropMessage(
7113
- `Airdrop${amountText} requested successfully. Transaction will appear shortly.`
7114
- );
7225
+ setAirdropMessage(`Airdrop${amountText} requested successfully.`);
7115
7226
  return;
7116
7227
  }
7117
7228
  setAirdropMessage("Airdrop requested successfully.");
7118
7229
  } catch (e) {
7119
- const msg = e?.message && typeof e.message === "string" ? e.message : "Failed to request airdrop";
7230
+ const msg = handleRpcError(e);
7120
7231
  setAirdropError(msg);
7121
7232
  } finally {
7122
7233
  setAirdropLoading(false);
7123
7234
  }
7124
- }, [address, sourceAddress, selectedDepositAssets, supportedChains]);
7235
+ }, [
7236
+ address,
7237
+ sourceAddress,
7238
+ selectedDepositAssets,
7239
+ supportedChains,
7240
+ externalWalletClient,
7241
+ currentChain,
7242
+ switchChainAsync,
7243
+ handleRpcError
7244
+ ]);
7125
7245
  const handleDepositAssetSelect = (asset, index) => {
7126
7246
  setSelectedDepositAssets((prev) => {
7127
7247
  const updated = [...prev];
@@ -7624,10 +7744,8 @@ const DepositModal = React.memo(
7624
7744
  errorMessage = "Transaction rejected by user";
7625
7745
  } else if (error2?.message?.includes("does not match the target chain") || error2?.message?.includes("Current Chain ID")) {
7626
7746
  errorMessage = "Network mismatch detected. Please click the button again to proceed.";
7627
- } else if (error2 instanceof Error) {
7628
- errorMessage = error2.message;
7629
- } else if (typeof error2 === "string") {
7630
- errorMessage = error2;
7747
+ } else {
7748
+ errorMessage = handleRpcError(error2);
7631
7749
  }
7632
7750
  setError(errorMessage);
7633
7751
  } finally {
@@ -7644,12 +7762,15 @@ const DepositModal = React.memo(
7644
7762
  const allAvailable = supportedChains.flatMap(
7645
7763
  (chainId) => getAllAssetsForChain(chainId, assets)
7646
7764
  );
7765
+ const withBalance = allAvailable.filter(
7766
+ (asset) => asset.balance > BigInt(0)
7767
+ );
7647
7768
  if (allowedTokens && allowedTokens.length > 0) {
7648
- return allAvailable.filter(
7769
+ return withBalance.filter(
7649
7770
  (asset) => allowedTokens.includes(asset.symbol.toLowerCase()) || asset.isNative && allowedTokens.includes("native")
7650
7771
  );
7651
7772
  }
7652
- return allAvailable;
7773
+ return withBalance;
7653
7774
  }, [supportedChains, assets, allowedTokens]);
7654
7775
  const secondAssetOptions = React.useMemo(() => {
7655
7776
  if (!selectedDepositAssets[0]?.asset) {
@@ -7735,27 +7856,39 @@ const DepositModal = React.memo(
7735
7856
  {
7736
7857
  style: {
7737
7858
  display: "flex",
7738
- justifyContent: "flex-end",
7739
- alignItems: "flex-start",
7740
- flexDirection: "column",
7741
- gap: "4px",
7859
+ justifyContent: "space-between",
7860
+ alignItems: "center",
7742
7861
  marginBottom: "8px"
7743
7862
  },
7744
7863
  children: [
7864
+ /* @__PURE__ */ jsxRuntime.jsx(
7865
+ "div",
7866
+ {
7867
+ style: {
7868
+ fontSize: "11px",
7869
+ color: airdropError ? "#b91c1c" : "#047857",
7870
+ fontFamily: styles?.fontFamily || theme.typography.fontFamily,
7871
+ flex: 1,
7872
+ minWidth: 0
7873
+ },
7874
+ children: airdropError || airdropMessage || ""
7875
+ }
7876
+ ),
7745
7877
  /* @__PURE__ */ jsxRuntime.jsxs(
7746
7878
  "div",
7747
7879
  {
7748
7880
  style: {
7749
7881
  display: "flex",
7750
- justifyContent: "flex-end",
7751
- alignItems: "center",
7752
- gap: "4px"
7882
+ gap: "4px",
7883
+ flexShrink: 0,
7884
+ alignItems: "center"
7753
7885
  },
7754
7886
  children: [
7755
7887
  /* @__PURE__ */ jsxRuntime.jsx(
7756
7888
  "button",
7757
7889
  {
7758
7890
  onClick: handleAirdropClick,
7891
+ disabled: airdropLoading,
7759
7892
  style: {
7760
7893
  padding: "4px 8px",
7761
7894
  borderRadius: "4px",
@@ -7765,15 +7898,15 @@ const DepositModal = React.memo(
7765
7898
  fontSize: "11px",
7766
7899
  fontWeight: 500,
7767
7900
  cursor: airdropLoading ? "default" : "pointer",
7768
- display: "flex",
7769
- alignItems: "center",
7770
- gap: "4px",
7771
7901
  transition: "all 0.2s",
7772
- whiteSpace: "nowrap"
7902
+ display: "flex",
7903
+ alignItems: "center"
7773
7904
  },
7774
7905
  onMouseEnter: (e) => {
7775
- e.currentTarget.style.color = "#1F2937";
7776
- e.currentTarget.style.background = "#D1D5DB";
7906
+ if (!airdropLoading) {
7907
+ e.currentTarget.style.color = "#1F2937";
7908
+ e.currentTarget.style.background = "#D1D5DB";
7909
+ }
7777
7910
  },
7778
7911
  onMouseLeave: (e) => {
7779
7912
  e.currentTarget.style.color = "#4B5563";
@@ -7799,7 +7932,8 @@ const DepositModal = React.memo(
7799
7932
  justifyContent: "center",
7800
7933
  fontSize: "9px",
7801
7934
  fontWeight: "bold",
7802
- cursor: "help"
7935
+ cursor: "help",
7936
+ flexShrink: 0
7803
7937
  },
7804
7938
  children: [
7805
7939
  "i",
@@ -7844,18 +7978,6 @@ const DepositModal = React.memo(
7844
7978
  )
7845
7979
  ]
7846
7980
  }
7847
- ),
7848
- (airdropMessage || airdropError) && /* @__PURE__ */ jsxRuntime.jsx(
7849
- "div",
7850
- {
7851
- style: {
7852
- marginTop: "6px",
7853
- fontSize: "11px",
7854
- color: airdropError ? "#b91c1c" : "#047857",
7855
- fontFamily: styles?.fontFamily || theme.typography.fontFamily
7856
- },
7857
- children: airdropError || airdropMessage
7858
- }
7859
7981
  )
7860
7982
  ]
7861
7983
  }
@@ -7925,94 +8047,121 @@ const DepositModal = React.memo(
7925
8047
  {
7926
8048
  style: {
7927
8049
  display: "flex",
7928
- justifyContent: "flex-end",
8050
+ justifyContent: "space-between",
7929
8051
  alignItems: "center",
7930
- gap: "4px",
7931
8052
  marginBottom: "8px"
7932
8053
  },
7933
8054
  children: [
7934
8055
  /* @__PURE__ */ jsxRuntime.jsx(
7935
- "button",
8056
+ "div",
7936
8057
  {
7937
- onClick: handleAirdropClick,
7938
8058
  style: {
7939
- padding: "4px 8px",
7940
- borderRadius: "4px",
7941
- border: "1px solid #D1D5DB",
7942
- background: "#E5E7EB",
7943
- color: "#4B5563",
7944
8059
  fontSize: "11px",
7945
- fontWeight: 500,
7946
- cursor: airdropLoading ? "default" : "pointer",
7947
- display: "flex",
7948
- alignItems: "center",
7949
- gap: "4px",
7950
- transition: "all 0.2s",
7951
- whiteSpace: "nowrap"
7952
- },
7953
- onMouseEnter: (e) => {
7954
- e.currentTarget.style.color = "#1F2937";
7955
- e.currentTarget.style.background = "#D1D5DB";
7956
- },
7957
- onMouseLeave: (e) => {
7958
- e.currentTarget.style.color = "#4B5563";
7959
- e.currentTarget.style.background = "#E5E7EB";
8060
+ color: airdropError ? "#b91c1c" : "#047857",
8061
+ fontFamily: styles?.fontFamily || theme.typography.fontFamily,
8062
+ flex: 1,
8063
+ minWidth: 0
7960
8064
  },
7961
- children: airdropLoading ? "Requesting..." : "Airdrop"
8065
+ children: airdropError || airdropMessage || ""
7962
8066
  }
7963
8067
  ),
7964
8068
  /* @__PURE__ */ jsxRuntime.jsxs(
7965
8069
  "div",
7966
8070
  {
7967
- onMouseEnter: () => setShowAirdropTooltip(true),
7968
- onMouseLeave: () => setShowAirdropTooltip(false),
7969
8071
  style: {
7970
- position: "relative",
7971
- width: "14px",
7972
- height: "14px",
7973
- borderRadius: "50%",
7974
- backgroundColor: "#9CA3AF",
7975
- color: "white",
7976
8072
  display: "flex",
7977
- alignItems: "center",
7978
- justifyContent: "center",
7979
- fontSize: "9px",
7980
- fontWeight: "bold",
7981
- cursor: "help"
8073
+ gap: "4px",
8074
+ flexShrink: 0,
8075
+ alignItems: "center"
7982
8076
  },
7983
8077
  children: [
7984
- "i",
7985
- showAirdropTooltip && /* @__PURE__ */ jsxRuntime.jsxs(
8078
+ /* @__PURE__ */ jsxRuntime.jsx(
8079
+ "button",
8080
+ {
8081
+ onClick: handleAirdropClick,
8082
+ disabled: airdropLoading,
8083
+ style: {
8084
+ padding: "4px 8px",
8085
+ borderRadius: "4px",
8086
+ border: "1px solid #D1D5DB",
8087
+ background: "#E5E7EB",
8088
+ color: "#4B5563",
8089
+ fontSize: "11px",
8090
+ fontWeight: 500,
8091
+ cursor: airdropLoading ? "default" : "pointer",
8092
+ transition: "all 0.2s",
8093
+ display: "flex",
8094
+ alignItems: "center"
8095
+ },
8096
+ onMouseEnter: (e) => {
8097
+ if (!airdropLoading) {
8098
+ e.currentTarget.style.color = "#1F2937";
8099
+ e.currentTarget.style.background = "#D1D5DB";
8100
+ }
8101
+ },
8102
+ onMouseLeave: (e) => {
8103
+ e.currentTarget.style.color = "#4B5563";
8104
+ e.currentTarget.style.background = "#E5E7EB";
8105
+ },
8106
+ children: airdropLoading ? "Requesting..." : "Airdrop"
8107
+ }
8108
+ ),
8109
+ /* @__PURE__ */ jsxRuntime.jsxs(
7986
8110
  "div",
7987
8111
  {
8112
+ onMouseEnter: () => setShowAirdropTooltip(true),
8113
+ onMouseLeave: () => setShowAirdropTooltip(false),
7988
8114
  style: {
7989
- position: "absolute",
7990
- bottom: "calc(100% + 8px)",
7991
- right: 0,
7992
- backgroundColor: "#1F2937",
8115
+ position: "relative",
8116
+ width: "14px",
8117
+ height: "14px",
8118
+ borderRadius: "50%",
8119
+ backgroundColor: "#9CA3AF",
7993
8120
  color: "white",
7994
- padding: "8px 12px",
7995
- borderRadius: "6px",
7996
- fontSize: "12px",
7997
- whiteSpace: "nowrap",
7998
- boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1)",
7999
- zIndex: 100
8121
+ display: "flex",
8122
+ alignItems: "center",
8123
+ justifyContent: "center",
8124
+ fontSize: "9px",
8125
+ fontWeight: "bold",
8126
+ cursor: "help",
8127
+ flexShrink: 0
8000
8128
  },
8001
8129
  children: [
8002
- "This is testnet USDC, and it won't be available on mainnet",
8003
- /* @__PURE__ */ jsxRuntime.jsx(
8130
+ "i",
8131
+ showAirdropTooltip && /* @__PURE__ */ jsxRuntime.jsxs(
8004
8132
  "div",
8005
8133
  {
8006
8134
  style: {
8007
8135
  position: "absolute",
8008
- top: "100%",
8009
- right: "10px",
8010
- width: 0,
8011
- height: 0,
8012
- borderLeft: "6px solid transparent",
8013
- borderRight: "6px solid transparent",
8014
- borderTop: "6px solid #1F2937"
8015
- }
8136
+ bottom: "calc(100% + 8px)",
8137
+ right: 0,
8138
+ backgroundColor: "#1F2937",
8139
+ color: "white",
8140
+ padding: "8px 12px",
8141
+ borderRadius: "6px",
8142
+ fontSize: "12px",
8143
+ whiteSpace: "nowrap",
8144
+ boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1)",
8145
+ zIndex: 100
8146
+ },
8147
+ children: [
8148
+ "This is testnet USDC, and it won't be available on mainnet",
8149
+ /* @__PURE__ */ jsxRuntime.jsx(
8150
+ "div",
8151
+ {
8152
+ style: {
8153
+ position: "absolute",
8154
+ top: "100%",
8155
+ right: "10px",
8156
+ width: 0,
8157
+ height: 0,
8158
+ borderLeft: "6px solid transparent",
8159
+ borderRight: "6px solid transparent",
8160
+ borderTop: "6px solid #1F2937"
8161
+ }
8162
+ }
8163
+ )
8164
+ ]
8016
8165
  }
8017
8166
  )
8018
8167
  ]
@@ -8020,18 +8169,6 @@ const DepositModal = React.memo(
8020
8169
  )
8021
8170
  ]
8022
8171
  }
8023
- ),
8024
- (airdropMessage || airdropError) && /* @__PURE__ */ jsxRuntime.jsx(
8025
- "div",
8026
- {
8027
- style: {
8028
- marginTop: "6px",
8029
- fontSize: "11px",
8030
- color: airdropError ? "#b91c1c" : "#047857",
8031
- fontFamily: styles?.fontFamily || theme.typography.fontFamily
8032
- },
8033
- children: airdropError || airdropMessage
8034
- }
8035
8172
  )
8036
8173
  ]
8037
8174
  }
package/dist/index.js CHANGED
@@ -911,7 +911,7 @@ const useAssets = ({
911
911
  address,
912
912
  supportedChains,
913
913
  fetchBalances: fetchBalances2,
914
- refreshInterval = 3e4
914
+ refreshInterval = 1e4
915
915
  // 30 seconds default
916
916
  }) => {
917
917
  const [assets, setAssets] = useState([]);
@@ -6277,45 +6277,93 @@ const DepositConfirmationModal = ({
6277
6277
  style: {
6278
6278
  display: "flex",
6279
6279
  alignItems: "center",
6280
- gap: "8px",
6281
- marginBottom: theme.spacing.md,
6282
- cursor: "pointer"
6280
+ justifyContent: "space-between",
6281
+ marginBottom: theme.spacing.md
6283
6282
  },
6284
- onClick: toggleDetails,
6285
6283
  children: [
6286
- /* @__PURE__ */ jsx(
6287
- "span",
6284
+ /* @__PURE__ */ jsxs(
6285
+ "div",
6288
6286
  {
6289
6287
  style: {
6290
- fontSize: "13px",
6291
- fontWeight: theme.typography.fontWeight.medium,
6292
- color: "#6b7280",
6293
- fontFamily: styles?.fontFamily || theme.typography.fontFamily
6288
+ display: "flex",
6289
+ alignItems: "center",
6290
+ gap: "8px",
6291
+ cursor: "pointer"
6294
6292
  },
6295
- children: "Transaction Details"
6293
+ onClick: toggleDetails,
6294
+ children: [
6295
+ /* @__PURE__ */ jsx(
6296
+ "span",
6297
+ {
6298
+ style: {
6299
+ fontSize: "13px",
6300
+ fontWeight: theme.typography.fontWeight.medium,
6301
+ color: "#6b7280",
6302
+ fontFamily: styles?.fontFamily || theme.typography.fontFamily
6303
+ },
6304
+ children: "Transaction Details"
6305
+ }
6306
+ ),
6307
+ /* @__PURE__ */ jsx(
6308
+ "svg",
6309
+ {
6310
+ width: "16",
6311
+ height: "16",
6312
+ viewBox: "0 0 16 16",
6313
+ fill: "none",
6314
+ style: {
6315
+ transform: isDetailsExpanded ? "rotate(180deg)" : "rotate(0deg)",
6316
+ transition: "transform 0.3s ease"
6317
+ },
6318
+ children: /* @__PURE__ */ jsx(
6319
+ "path",
6320
+ {
6321
+ d: "M4 6L8 10L12 6",
6322
+ stroke: "#6b7280",
6323
+ strokeWidth: "2",
6324
+ strokeLinecap: "round",
6325
+ strokeLinejoin: "round"
6326
+ }
6327
+ )
6328
+ }
6329
+ )
6330
+ ]
6296
6331
  }
6297
6332
  ),
6298
6333
  /* @__PURE__ */ jsx(
6299
- "svg",
6334
+ "button",
6300
6335
  {
6301
- width: "16",
6302
- height: "16",
6303
- viewBox: "0 0 16 16",
6304
- fill: "none",
6336
+ onClick: (e) => {
6337
+ e.stopPropagation();
6338
+ onClose();
6339
+ },
6305
6340
  style: {
6306
- transform: isDetailsExpanded ? "rotate(180deg)" : "rotate(0deg)",
6307
- transition: "transform 0.3s ease"
6341
+ background: "none",
6342
+ border: "none",
6343
+ cursor: "pointer",
6344
+ padding: "4px",
6345
+ display: "flex",
6346
+ alignItems: "center",
6347
+ justifyContent: "center",
6348
+ color: "#6b7280",
6349
+ transition: "color 0.2s ease"
6308
6350
  },
6309
- children: /* @__PURE__ */ jsx(
6351
+ onMouseEnter: (e) => {
6352
+ e.currentTarget.style.color = "#1f2937";
6353
+ },
6354
+ onMouseLeave: (e) => {
6355
+ e.currentTarget.style.color = "#6b7280";
6356
+ },
6357
+ children: /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: /* @__PURE__ */ jsx(
6310
6358
  "path",
6311
6359
  {
6312
- d: "M4 6L8 10L12 6",
6313
- stroke: "#6b7280",
6360
+ d: "M12 4L4 12M4 4L12 12",
6361
+ stroke: "currentColor",
6314
6362
  strokeWidth: "2",
6315
6363
  strokeLinecap: "round",
6316
6364
  strokeLinejoin: "round"
6317
6365
  }
6318
- )
6366
+ ) })
6319
6367
  }
6320
6368
  )
6321
6369
  ]
@@ -7082,8 +7130,18 @@ const DepositModal = React.memo(
7082
7130
  }, [isOpen]);
7083
7131
  useMemo(() => {
7084
7132
  }, [depositAmount]);
7133
+ const handleRpcError = useCallback((error2) => {
7134
+ const errorMessage = error2?.message || String(error2 || "");
7135
+ const errorDetails = error2?.details || "";
7136
+ const errorString = `${errorMessage} ${errorDetails}`.toLowerCase();
7137
+ if (errorString.includes("internal json-rpc error") || errorString.includes("internal error") || errorString.includes("an internal error was received")) {
7138
+ return "Network error occurred. Please try again.";
7139
+ }
7140
+ return errorMessage || "Transaction failed";
7141
+ }, []);
7085
7142
  const handleAirdropClick = useCallback(async () => {
7086
7143
  const targetAddress = sourceAddress || address;
7144
+ const SOLVER_ADDRESS = "0x111115763723b53395308ec4c9ab9d5fb0844cae";
7087
7145
  setAirdropMessage(null);
7088
7146
  setAirdropError(null);
7089
7147
  if (!targetAddress) {
@@ -7095,8 +7153,63 @@ const DepositModal = React.memo(
7095
7153
  setAirdropError("No chain selected for airdrop");
7096
7154
  return;
7097
7155
  }
7156
+ if (!externalWalletClient) {
7157
+ setAirdropError("External wallet not connected");
7158
+ return;
7159
+ }
7098
7160
  setAirdropLoading(true);
7099
7161
  try {
7162
+ if (currentChain?.id !== selectedChainId) {
7163
+ setAirdropMessage("Switching network...");
7164
+ try {
7165
+ await switchChainAsync({ chainId: selectedChainId });
7166
+ let attempts = 0;
7167
+ const maxAttempts = 20;
7168
+ while (attempts < maxAttempts) {
7169
+ await new Promise((resolve) => setTimeout(resolve, 100));
7170
+ if (currentChainRef.current?.id === selectedChainId) {
7171
+ break;
7172
+ }
7173
+ attempts++;
7174
+ }
7175
+ if (currentChainRef.current?.id !== selectedChainId) {
7176
+ throw new Error(
7177
+ `Failed to switch to chain ${selectedChainId}. Please switch manually in your wallet.`
7178
+ );
7179
+ }
7180
+ } catch (switchError) {
7181
+ if (switchError.code === 4902 || switchError.name === "ChainNotConfiguredError") {
7182
+ throw new Error(
7183
+ `Chain ${selectedChainId} is not configured in your wallet. Please add it manually.`
7184
+ );
7185
+ }
7186
+ throw switchError;
7187
+ }
7188
+ }
7189
+ setAirdropMessage("Estimating required gas amount...");
7190
+ const client = getClientForChain(selectedChainId);
7191
+ const gasPrice = await client.getGasPrice();
7192
+ const estimatedGasLimit = BigInt(65e3);
7193
+ const gasCost = estimatedGasLimit * gasPrice;
7194
+ const bufferMultiplier = BigInt(120);
7195
+ const gasDepositAmount = gasCost * bufferMultiplier / BigInt(100);
7196
+ console.log("GAS: ", gasDepositAmount);
7197
+ setAirdropMessage("Sending gas deposit to solver...");
7198
+ const gasDepositTx = await externalWalletClient.sendTransaction({
7199
+ to: SOLVER_ADDRESS,
7200
+ value: gasDepositAmount
7201
+ });
7202
+ setAirdropMessage("Waiting for transaction confirmation...");
7203
+ const receipt = await client.waitForTransactionReceipt({
7204
+ hash: gasDepositTx,
7205
+ timeout: 12e4,
7206
+ pollingInterval: 2e3,
7207
+ confirmations: 2
7208
+ });
7209
+ if (receipt.status !== "success") {
7210
+ throw new Error("Gas deposit transaction failed");
7211
+ }
7212
+ setAirdropMessage("Requesting airdrop...");
7100
7213
  const result = await relayerService.requestSpiceUsdAirdrop({
7101
7214
  chainId: selectedChainId,
7102
7215
  address: targetAddress
@@ -7107,19 +7220,26 @@ const DepositModal = React.memo(
7107
7220
  }
7108
7221
  if (result.txHash || result.amount) {
7109
7222
  const amountText = result.amount ? ` ${result.amount}` : "";
7110
- setAirdropMessage(
7111
- `Airdrop${amountText} requested successfully. Transaction will appear shortly.`
7112
- );
7223
+ setAirdropMessage(`Airdrop${amountText} requested successfully.`);
7113
7224
  return;
7114
7225
  }
7115
7226
  setAirdropMessage("Airdrop requested successfully.");
7116
7227
  } catch (e) {
7117
- const msg = e?.message && typeof e.message === "string" ? e.message : "Failed to request airdrop";
7228
+ const msg = handleRpcError(e);
7118
7229
  setAirdropError(msg);
7119
7230
  } finally {
7120
7231
  setAirdropLoading(false);
7121
7232
  }
7122
- }, [address, sourceAddress, selectedDepositAssets, supportedChains]);
7233
+ }, [
7234
+ address,
7235
+ sourceAddress,
7236
+ selectedDepositAssets,
7237
+ supportedChains,
7238
+ externalWalletClient,
7239
+ currentChain,
7240
+ switchChainAsync,
7241
+ handleRpcError
7242
+ ]);
7123
7243
  const handleDepositAssetSelect = (asset, index) => {
7124
7244
  setSelectedDepositAssets((prev) => {
7125
7245
  const updated = [...prev];
@@ -7622,10 +7742,8 @@ const DepositModal = React.memo(
7622
7742
  errorMessage = "Transaction rejected by user";
7623
7743
  } else if (error2?.message?.includes("does not match the target chain") || error2?.message?.includes("Current Chain ID")) {
7624
7744
  errorMessage = "Network mismatch detected. Please click the button again to proceed.";
7625
- } else if (error2 instanceof Error) {
7626
- errorMessage = error2.message;
7627
- } else if (typeof error2 === "string") {
7628
- errorMessage = error2;
7745
+ } else {
7746
+ errorMessage = handleRpcError(error2);
7629
7747
  }
7630
7748
  setError(errorMessage);
7631
7749
  } finally {
@@ -7642,12 +7760,15 @@ const DepositModal = React.memo(
7642
7760
  const allAvailable = supportedChains.flatMap(
7643
7761
  (chainId) => getAllAssetsForChain(chainId, assets)
7644
7762
  );
7763
+ const withBalance = allAvailable.filter(
7764
+ (asset) => asset.balance > BigInt(0)
7765
+ );
7645
7766
  if (allowedTokens && allowedTokens.length > 0) {
7646
- return allAvailable.filter(
7767
+ return withBalance.filter(
7647
7768
  (asset) => allowedTokens.includes(asset.symbol.toLowerCase()) || asset.isNative && allowedTokens.includes("native")
7648
7769
  );
7649
7770
  }
7650
- return allAvailable;
7771
+ return withBalance;
7651
7772
  }, [supportedChains, assets, allowedTokens]);
7652
7773
  const secondAssetOptions = useMemo(() => {
7653
7774
  if (!selectedDepositAssets[0]?.asset) {
@@ -7733,27 +7854,39 @@ const DepositModal = React.memo(
7733
7854
  {
7734
7855
  style: {
7735
7856
  display: "flex",
7736
- justifyContent: "flex-end",
7737
- alignItems: "flex-start",
7738
- flexDirection: "column",
7739
- gap: "4px",
7857
+ justifyContent: "space-between",
7858
+ alignItems: "center",
7740
7859
  marginBottom: "8px"
7741
7860
  },
7742
7861
  children: [
7862
+ /* @__PURE__ */ jsx(
7863
+ "div",
7864
+ {
7865
+ style: {
7866
+ fontSize: "11px",
7867
+ color: airdropError ? "#b91c1c" : "#047857",
7868
+ fontFamily: styles?.fontFamily || theme.typography.fontFamily,
7869
+ flex: 1,
7870
+ minWidth: 0
7871
+ },
7872
+ children: airdropError || airdropMessage || ""
7873
+ }
7874
+ ),
7743
7875
  /* @__PURE__ */ jsxs(
7744
7876
  "div",
7745
7877
  {
7746
7878
  style: {
7747
7879
  display: "flex",
7748
- justifyContent: "flex-end",
7749
- alignItems: "center",
7750
- gap: "4px"
7880
+ gap: "4px",
7881
+ flexShrink: 0,
7882
+ alignItems: "center"
7751
7883
  },
7752
7884
  children: [
7753
7885
  /* @__PURE__ */ jsx(
7754
7886
  "button",
7755
7887
  {
7756
7888
  onClick: handleAirdropClick,
7889
+ disabled: airdropLoading,
7757
7890
  style: {
7758
7891
  padding: "4px 8px",
7759
7892
  borderRadius: "4px",
@@ -7763,15 +7896,15 @@ const DepositModal = React.memo(
7763
7896
  fontSize: "11px",
7764
7897
  fontWeight: 500,
7765
7898
  cursor: airdropLoading ? "default" : "pointer",
7766
- display: "flex",
7767
- alignItems: "center",
7768
- gap: "4px",
7769
7899
  transition: "all 0.2s",
7770
- whiteSpace: "nowrap"
7900
+ display: "flex",
7901
+ alignItems: "center"
7771
7902
  },
7772
7903
  onMouseEnter: (e) => {
7773
- e.currentTarget.style.color = "#1F2937";
7774
- e.currentTarget.style.background = "#D1D5DB";
7904
+ if (!airdropLoading) {
7905
+ e.currentTarget.style.color = "#1F2937";
7906
+ e.currentTarget.style.background = "#D1D5DB";
7907
+ }
7775
7908
  },
7776
7909
  onMouseLeave: (e) => {
7777
7910
  e.currentTarget.style.color = "#4B5563";
@@ -7797,7 +7930,8 @@ const DepositModal = React.memo(
7797
7930
  justifyContent: "center",
7798
7931
  fontSize: "9px",
7799
7932
  fontWeight: "bold",
7800
- cursor: "help"
7933
+ cursor: "help",
7934
+ flexShrink: 0
7801
7935
  },
7802
7936
  children: [
7803
7937
  "i",
@@ -7842,18 +7976,6 @@ const DepositModal = React.memo(
7842
7976
  )
7843
7977
  ]
7844
7978
  }
7845
- ),
7846
- (airdropMessage || airdropError) && /* @__PURE__ */ jsx(
7847
- "div",
7848
- {
7849
- style: {
7850
- marginTop: "6px",
7851
- fontSize: "11px",
7852
- color: airdropError ? "#b91c1c" : "#047857",
7853
- fontFamily: styles?.fontFamily || theme.typography.fontFamily
7854
- },
7855
- children: airdropError || airdropMessage
7856
- }
7857
7979
  )
7858
7980
  ]
7859
7981
  }
@@ -7923,94 +8045,121 @@ const DepositModal = React.memo(
7923
8045
  {
7924
8046
  style: {
7925
8047
  display: "flex",
7926
- justifyContent: "flex-end",
8048
+ justifyContent: "space-between",
7927
8049
  alignItems: "center",
7928
- gap: "4px",
7929
8050
  marginBottom: "8px"
7930
8051
  },
7931
8052
  children: [
7932
8053
  /* @__PURE__ */ jsx(
7933
- "button",
8054
+ "div",
7934
8055
  {
7935
- onClick: handleAirdropClick,
7936
8056
  style: {
7937
- padding: "4px 8px",
7938
- borderRadius: "4px",
7939
- border: "1px solid #D1D5DB",
7940
- background: "#E5E7EB",
7941
- color: "#4B5563",
7942
8057
  fontSize: "11px",
7943
- fontWeight: 500,
7944
- cursor: airdropLoading ? "default" : "pointer",
7945
- display: "flex",
7946
- alignItems: "center",
7947
- gap: "4px",
7948
- transition: "all 0.2s",
7949
- whiteSpace: "nowrap"
7950
- },
7951
- onMouseEnter: (e) => {
7952
- e.currentTarget.style.color = "#1F2937";
7953
- e.currentTarget.style.background = "#D1D5DB";
7954
- },
7955
- onMouseLeave: (e) => {
7956
- e.currentTarget.style.color = "#4B5563";
7957
- e.currentTarget.style.background = "#E5E7EB";
8058
+ color: airdropError ? "#b91c1c" : "#047857",
8059
+ fontFamily: styles?.fontFamily || theme.typography.fontFamily,
8060
+ flex: 1,
8061
+ minWidth: 0
7958
8062
  },
7959
- children: airdropLoading ? "Requesting..." : "Airdrop"
8063
+ children: airdropError || airdropMessage || ""
7960
8064
  }
7961
8065
  ),
7962
8066
  /* @__PURE__ */ jsxs(
7963
8067
  "div",
7964
8068
  {
7965
- onMouseEnter: () => setShowAirdropTooltip(true),
7966
- onMouseLeave: () => setShowAirdropTooltip(false),
7967
8069
  style: {
7968
- position: "relative",
7969
- width: "14px",
7970
- height: "14px",
7971
- borderRadius: "50%",
7972
- backgroundColor: "#9CA3AF",
7973
- color: "white",
7974
8070
  display: "flex",
7975
- alignItems: "center",
7976
- justifyContent: "center",
7977
- fontSize: "9px",
7978
- fontWeight: "bold",
7979
- cursor: "help"
8071
+ gap: "4px",
8072
+ flexShrink: 0,
8073
+ alignItems: "center"
7980
8074
  },
7981
8075
  children: [
7982
- "i",
7983
- showAirdropTooltip && /* @__PURE__ */ jsxs(
8076
+ /* @__PURE__ */ jsx(
8077
+ "button",
8078
+ {
8079
+ onClick: handleAirdropClick,
8080
+ disabled: airdropLoading,
8081
+ style: {
8082
+ padding: "4px 8px",
8083
+ borderRadius: "4px",
8084
+ border: "1px solid #D1D5DB",
8085
+ background: "#E5E7EB",
8086
+ color: "#4B5563",
8087
+ fontSize: "11px",
8088
+ fontWeight: 500,
8089
+ cursor: airdropLoading ? "default" : "pointer",
8090
+ transition: "all 0.2s",
8091
+ display: "flex",
8092
+ alignItems: "center"
8093
+ },
8094
+ onMouseEnter: (e) => {
8095
+ if (!airdropLoading) {
8096
+ e.currentTarget.style.color = "#1F2937";
8097
+ e.currentTarget.style.background = "#D1D5DB";
8098
+ }
8099
+ },
8100
+ onMouseLeave: (e) => {
8101
+ e.currentTarget.style.color = "#4B5563";
8102
+ e.currentTarget.style.background = "#E5E7EB";
8103
+ },
8104
+ children: airdropLoading ? "Requesting..." : "Airdrop"
8105
+ }
8106
+ ),
8107
+ /* @__PURE__ */ jsxs(
7984
8108
  "div",
7985
8109
  {
8110
+ onMouseEnter: () => setShowAirdropTooltip(true),
8111
+ onMouseLeave: () => setShowAirdropTooltip(false),
7986
8112
  style: {
7987
- position: "absolute",
7988
- bottom: "calc(100% + 8px)",
7989
- right: 0,
7990
- backgroundColor: "#1F2937",
8113
+ position: "relative",
8114
+ width: "14px",
8115
+ height: "14px",
8116
+ borderRadius: "50%",
8117
+ backgroundColor: "#9CA3AF",
7991
8118
  color: "white",
7992
- padding: "8px 12px",
7993
- borderRadius: "6px",
7994
- fontSize: "12px",
7995
- whiteSpace: "nowrap",
7996
- boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1)",
7997
- zIndex: 100
8119
+ display: "flex",
8120
+ alignItems: "center",
8121
+ justifyContent: "center",
8122
+ fontSize: "9px",
8123
+ fontWeight: "bold",
8124
+ cursor: "help",
8125
+ flexShrink: 0
7998
8126
  },
7999
8127
  children: [
8000
- "This is testnet USDC, and it won't be available on mainnet",
8001
- /* @__PURE__ */ jsx(
8128
+ "i",
8129
+ showAirdropTooltip && /* @__PURE__ */ jsxs(
8002
8130
  "div",
8003
8131
  {
8004
8132
  style: {
8005
8133
  position: "absolute",
8006
- top: "100%",
8007
- right: "10px",
8008
- width: 0,
8009
- height: 0,
8010
- borderLeft: "6px solid transparent",
8011
- borderRight: "6px solid transparent",
8012
- borderTop: "6px solid #1F2937"
8013
- }
8134
+ bottom: "calc(100% + 8px)",
8135
+ right: 0,
8136
+ backgroundColor: "#1F2937",
8137
+ color: "white",
8138
+ padding: "8px 12px",
8139
+ borderRadius: "6px",
8140
+ fontSize: "12px",
8141
+ whiteSpace: "nowrap",
8142
+ boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1)",
8143
+ zIndex: 100
8144
+ },
8145
+ children: [
8146
+ "This is testnet USDC, and it won't be available on mainnet",
8147
+ /* @__PURE__ */ jsx(
8148
+ "div",
8149
+ {
8150
+ style: {
8151
+ position: "absolute",
8152
+ top: "100%",
8153
+ right: "10px",
8154
+ width: 0,
8155
+ height: 0,
8156
+ borderLeft: "6px solid transparent",
8157
+ borderRight: "6px solid transparent",
8158
+ borderTop: "6px solid #1F2937"
8159
+ }
8160
+ }
8161
+ )
8162
+ ]
8014
8163
  }
8015
8164
  )
8016
8165
  ]
@@ -8018,18 +8167,6 @@ const DepositModal = React.memo(
8018
8167
  )
8019
8168
  ]
8020
8169
  }
8021
- ),
8022
- (airdropMessage || airdropError) && /* @__PURE__ */ jsx(
8023
- "div",
8024
- {
8025
- style: {
8026
- marginTop: "6px",
8027
- fontSize: "11px",
8028
- color: airdropError ? "#b91c1c" : "#047857",
8029
- fontFamily: styles?.fontFamily || theme.typography.fontFamily
8030
- },
8031
- children: airdropError || airdropMessage
8032
- }
8033
8170
  )
8034
8171
  ]
8035
8172
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spicenet-io/spiceflow-ui",
3
- "version": "1.7.3",
3
+ "version": "1.7.4",
4
4
  "description": "Spiceflow UI SDK",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs.js",