@spicenet-io/spiceflow-ui 1.8.4 → 1.8.6

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,12 @@
1
+ import React from "react";
2
+ import { IntentStatus } from "../../types/status";
3
+ import { Theme } from "../../types/theme";
4
+ interface DepositStatusPanelProps {
5
+ intentStatus: IntentStatus;
6
+ onClose: () => void;
7
+ onRetry?: () => void;
8
+ onNewDeposit?: () => void;
9
+ theme?: Theme;
10
+ }
11
+ export declare const DepositStatusPanel: React.FC<DepositStatusPanelProps>;
12
+ export {};
@@ -3,11 +3,11 @@ import { Asset } from "../../types/assets";
3
3
  export interface SpiceBalanceApiResponse {
4
4
  success: boolean;
5
5
  data?: {
6
- tokens: {
7
- [chainId: string]: {
8
- [tokenAddress: string]: string;
9
- };
10
- };
6
+ tokens: Array<{
7
+ chainId: number;
8
+ tokenAddress: string;
9
+ amount: string;
10
+ }>;
11
11
  };
12
12
  }
13
13
  export interface UseSpiceAssetsConfig {
@@ -3,11 +3,11 @@ import { BalanceData } from "../../types/balance";
3
3
  export interface SpiceBalanceApiResponse {
4
4
  success: boolean;
5
5
  data?: {
6
- tokens: {
7
- [chainId: string]: {
8
- [tokenAddress: string]: string;
9
- };
10
- };
6
+ tokens: Array<{
7
+ chainId: number;
8
+ tokenAddress: string;
9
+ amount: string;
10
+ }>;
11
11
  };
12
12
  }
13
13
  export interface UseSpiceBalanceConfig {
package/dist/index.cjs.js CHANGED
@@ -3988,61 +3988,55 @@ const useSpiceAssets = ({
3988
3988
  throw new Error(`Failed to fetch balance: ${response.status}`);
3989
3989
  }
3990
3990
  const result = await response.json();
3991
- if (result.success && result.data?.tokens) {
3992
- const tokens = result.data.tokens;
3991
+ if (result.success && result.data?.tokens && Array.isArray(result.data.tokens)) {
3993
3992
  const parsedAssets = [];
3994
- Object.keys(tokens).forEach((chainIdStr) => {
3995
- const chainId = parseInt(chainIdStr);
3993
+ result.data.tokens.forEach((token) => {
3994
+ const chainId = token.chainId;
3995
+ const tokenAddress = token.tokenAddress;
3996
+ const rawBalanceStr = token.amount;
3996
3997
  if (supportedChains && !supportedChains.includes(chainId)) {
3997
3998
  return;
3998
3999
  }
3999
- const chainTokens = tokens[chainIdStr];
4000
- const chainConfig = getChainConfig(chainId);
4001
- if (chainTokens && typeof chainTokens === "object") {
4002
- Object.keys(chainTokens).forEach((tokenAddress) => {
4003
- const rawBalanceStr = chainTokens[tokenAddress];
4004
- const rawBalance = BigInt(rawBalanceStr || "0");
4005
- if (rawBalance > BigInt(0)) {
4006
- const isNative = tokenAddress.toLowerCase() === "0x0" || tokenAddress.toLowerCase() === "0x0000000000000000000000000000000000000000" || tokenAddress.toLowerCase() === "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";
4007
- let decimals = 18;
4008
- let symbol = "TOKEN";
4009
- let name = tokenAddress.slice(0, 6) + "..." + tokenAddress.slice(-4);
4010
- let logoURI;
4011
- if (isNative) {
4012
- decimals = chainConfig?.nativeCurrency?.decimals || 18;
4013
- symbol = chainConfig?.nativeCurrency?.symbol || "ETH";
4014
- name = chainConfig?.nativeCurrency?.name || "Native Token";
4015
- } else {
4016
- const tokenConfig = chainConfig?.supportedTokens?.find(
4017
- (t) => t.address.toLowerCase() === tokenAddress.toLowerCase()
4018
- );
4019
- if (tokenConfig) {
4020
- decimals = tokenConfig.decimals;
4021
- symbol = tokenConfig.symbol;
4022
- name = tokenConfig.name;
4023
- logoURI = tokenConfig.logoURI;
4024
- }
4025
- }
4026
- const balanceFormatted = parseFloat(
4027
- (Number(rawBalance) / Math.pow(10, decimals)).toFixed(6)
4028
- );
4029
- if (balanceFormatted > 0) {
4030
- parsedAssets.push({
4031
- address: isNative ? "0x0000000000000000000000000000000000000000" : tokenAddress,
4032
- symbol,
4033
- name,
4034
- decimals,
4035
- chainId,
4036
- balance: rawBalance,
4037
- balanceFormatted,
4038
- balanceUsd: 0,
4039
- // API doesn't provide USD value
4040
- isNative,
4041
- logoURI
4042
- });
4043
- }
4000
+ const rawBalance = BigInt(rawBalanceStr || "0");
4001
+ if (rawBalance > BigInt(0)) {
4002
+ const chainConfig = getChainConfig(chainId);
4003
+ const isNative = tokenAddress.toLowerCase() === "0x0" || tokenAddress.toLowerCase() === "0x0000000000000000000000000000000000000000" || tokenAddress.toLowerCase() === "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";
4004
+ let decimals = 18;
4005
+ let symbol = "TOKEN";
4006
+ let name = tokenAddress.slice(0, 6) + "..." + tokenAddress.slice(-4);
4007
+ let logoURI;
4008
+ if (isNative) {
4009
+ decimals = chainConfig?.nativeCurrency?.decimals || 18;
4010
+ symbol = chainConfig?.nativeCurrency?.symbol || "ETH";
4011
+ name = chainConfig?.nativeCurrency?.name || "Native Token";
4012
+ } else {
4013
+ const tokenConfig = chainConfig?.supportedTokens?.find(
4014
+ (t) => t.address.toLowerCase() === tokenAddress.toLowerCase()
4015
+ );
4016
+ if (tokenConfig) {
4017
+ decimals = tokenConfig.decimals;
4018
+ symbol = tokenConfig.symbol;
4019
+ name = tokenConfig.name;
4020
+ logoURI = tokenConfig.logoURI;
4044
4021
  }
4045
- });
4022
+ }
4023
+ const balanceFormatted = parseFloat(
4024
+ (Number(rawBalance) / Math.pow(10, decimals)).toFixed(6)
4025
+ );
4026
+ if (balanceFormatted > 0) {
4027
+ parsedAssets.push({
4028
+ address: isNative ? "0x0000000000000000000000000000000000000000" : tokenAddress,
4029
+ symbol,
4030
+ name,
4031
+ decimals,
4032
+ chainId,
4033
+ balance: rawBalance,
4034
+ balanceFormatted,
4035
+ balanceUsd: 0,
4036
+ isNative,
4037
+ logoURI
4038
+ });
4039
+ }
4046
4040
  }
4047
4041
  });
4048
4042
  setAssets(parsedAssets);
@@ -4089,6 +4083,211 @@ const useSpiceAssets = ({
4089
4083
  };
4090
4084
  };
4091
4085
 
4086
+ const DepositStatusPanel = ({
4087
+ intentStatus,
4088
+ onClose,
4089
+ onRetry,
4090
+ onNewDeposit,
4091
+ theme: providedTheme
4092
+ }) => {
4093
+ const theme = providedTheme || Button.createTheme("dark");
4094
+ const containerStyles = {
4095
+ width: "100%",
4096
+ maxWidth: "28rem",
4097
+ margin: "0 auto",
4098
+ backgroundColor: theme.colors.background,
4099
+ border: `1px solid ${theme.colors.border}`,
4100
+ borderRadius: theme.borderRadius.lg,
4101
+ padding: theme.spacing.lg,
4102
+ color: theme.colors.text
4103
+ };
4104
+ const headerStyles = {
4105
+ textAlign: "center",
4106
+ marginBottom: theme.spacing.lg
4107
+ };
4108
+ const iconContainerStyles = {
4109
+ width: "5rem",
4110
+ height: "5rem",
4111
+ margin: "0 auto",
4112
+ backgroundColor: theme.colors.surface,
4113
+ borderRadius: "50%",
4114
+ display: "flex",
4115
+ alignItems: "center",
4116
+ justifyContent: "center",
4117
+ border: `2px solid ${theme.colors.border}`,
4118
+ marginBottom: theme.spacing.md
4119
+ };
4120
+ const titleStyles = {
4121
+ fontSize: theme.typography.fontSize.lg,
4122
+ fontWeight: theme.typography.fontWeight.semibold,
4123
+ color: theme.colors.text,
4124
+ marginBottom: theme.spacing.sm
4125
+ };
4126
+ const descriptionStyles = {
4127
+ fontSize: theme.typography.fontSize.sm,
4128
+ color: theme.colors.textMuted
4129
+ };
4130
+ const buttonContainerStyles = {
4131
+ display: "flex",
4132
+ flexDirection: "column",
4133
+ gap: theme.spacing.sm,
4134
+ marginTop: theme.spacing.lg
4135
+ };
4136
+ const getStatusContent = () => {
4137
+ switch (intentStatus.overallStatus) {
4138
+ case "success":
4139
+ return {
4140
+ icon: /* @__PURE__ */ jsxRuntime.jsx(
4141
+ "svg",
4142
+ {
4143
+ width: "32",
4144
+ height: "32",
4145
+ fill: "none",
4146
+ stroke: theme.colors.success,
4147
+ viewBox: "0 0 24 24",
4148
+ children: /* @__PURE__ */ jsxRuntime.jsx(
4149
+ "path",
4150
+ {
4151
+ strokeLinecap: "round",
4152
+ strokeLinejoin: "round",
4153
+ strokeWidth: 2,
4154
+ d: "M5 13l4 4L19 7"
4155
+ }
4156
+ )
4157
+ }
4158
+ ),
4159
+ title: "Deposit Completed!",
4160
+ description: "Your tokens have been successfully deposited.",
4161
+ borderColor: theme.colors.success
4162
+ };
4163
+ case "failed":
4164
+ return {
4165
+ icon: /* @__PURE__ */ jsxRuntime.jsx(
4166
+ "svg",
4167
+ {
4168
+ width: "32",
4169
+ height: "32",
4170
+ fill: "none",
4171
+ stroke: theme.colors.error,
4172
+ viewBox: "0 0 24 24",
4173
+ children: /* @__PURE__ */ jsxRuntime.jsx(
4174
+ "path",
4175
+ {
4176
+ strokeLinecap: "round",
4177
+ strokeLinejoin: "round",
4178
+ strokeWidth: 2,
4179
+ d: "M6 18L18 6M6 6l12 12"
4180
+ }
4181
+ )
4182
+ }
4183
+ ),
4184
+ title: "Deposit Failed",
4185
+ description: "Something went wrong. Please try again.",
4186
+ borderColor: theme.colors.error
4187
+ };
4188
+ default:
4189
+ return {
4190
+ icon: /* @__PURE__ */ jsxRuntime.jsx(
4191
+ "div",
4192
+ {
4193
+ style: {
4194
+ width: "2rem",
4195
+ height: "2rem",
4196
+ border: `3px solid ${theme.colors.primary}`,
4197
+ borderTop: "3px solid transparent",
4198
+ borderRadius: "50%",
4199
+ animation: "spin 1s linear infinite"
4200
+ }
4201
+ }
4202
+ ),
4203
+ title: "Processing Deposit",
4204
+ description: "Please wait while your deposit is being processed...",
4205
+ borderColor: theme.colors.primary
4206
+ };
4207
+ }
4208
+ };
4209
+ const statusContent = getStatusContent();
4210
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: containerStyles, children: [
4211
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: `
4212
+ @keyframes spin {
4213
+ 0% { transform: rotate(0deg); }
4214
+ 100% { transform: rotate(360deg); }
4215
+ }
4216
+ ` }),
4217
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: headerStyles, children: [
4218
+ /* @__PURE__ */ jsxRuntime.jsx(
4219
+ "div",
4220
+ {
4221
+ style: {
4222
+ ...iconContainerStyles,
4223
+ borderColor: statusContent.borderColor
4224
+ },
4225
+ children: statusContent.icon
4226
+ }
4227
+ ),
4228
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { style: titleStyles, children: statusContent.title }),
4229
+ /* @__PURE__ */ jsxRuntime.jsx("p", { style: descriptionStyles, children: statusContent.description })
4230
+ ] }),
4231
+ intentStatus.overallStatus === "processing" && /* @__PURE__ */ jsxRuntime.jsxs(
4232
+ "div",
4233
+ {
4234
+ style: {
4235
+ backgroundColor: theme.colors.surface,
4236
+ borderRadius: theme.borderRadius.md,
4237
+ padding: theme.spacing.md,
4238
+ marginBottom: theme.spacing.md
4239
+ },
4240
+ children: [
4241
+ /* @__PURE__ */ jsxRuntime.jsx(
4242
+ "div",
4243
+ {
4244
+ style: {
4245
+ height: "4px",
4246
+ backgroundColor: `${theme.colors.primary}30`,
4247
+ borderRadius: "2px",
4248
+ overflow: "hidden"
4249
+ },
4250
+ children: /* @__PURE__ */ jsxRuntime.jsx(
4251
+ "div",
4252
+ {
4253
+ style: {
4254
+ width: "30%",
4255
+ height: "100%",
4256
+ backgroundColor: theme.colors.primary,
4257
+ borderRadius: "2px",
4258
+ animation: "progress 1.5s ease-in-out infinite"
4259
+ }
4260
+ }
4261
+ )
4262
+ }
4263
+ ),
4264
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: `
4265
+ @keyframes progress {
4266
+ 0% { transform: translateX(-100%); width: 30%; }
4267
+ 50% { width: 60%; }
4268
+ 100% { transform: translateX(400%); width: 30%; }
4269
+ }
4270
+ ` })
4271
+ ]
4272
+ }
4273
+ ),
4274
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: buttonContainerStyles, children: [
4275
+ intentStatus.overallStatus === "success" && onNewDeposit && /* @__PURE__ */ jsxRuntime.jsx(
4276
+ Button.Button,
4277
+ {
4278
+ variant: "success",
4279
+ fullWidth: true,
4280
+ onClick: onNewDeposit,
4281
+ theme,
4282
+ children: "New Deposit"
4283
+ }
4284
+ ),
4285
+ intentStatus.overallStatus === "failed" && onRetry && /* @__PURE__ */ jsxRuntime.jsx(Button.Button, { variant: "error", fullWidth: true, onClick: onRetry, theme, children: "Try Again" }),
4286
+ intentStatus.overallStatus === "processing" && /* @__PURE__ */ jsxRuntime.jsx(Button.Button, { variant: "ghost", fullWidth: true, onClick: onClose, theme, children: "Cancel" })
4287
+ ] })
4288
+ ] });
4289
+ };
4290
+
4092
4291
  const DepositWidget = ({
4093
4292
  depositBatches,
4094
4293
  tokenAddress,
@@ -4192,62 +4391,7 @@ const DepositWidget = ({
4192
4391
  setIsExecuting(true);
4193
4392
  setError(null);
4194
4393
  try {
4195
- const depositClient = getClientForChain(
4196
- selectedDepositAsset.asset.chainId
4197
- );
4198
- const depositRecentBlock = await depositClient.getBlockNumber();
4199
- let depositAssetBatch;
4200
- if (selectedDepositAsset.asset.isNative) {
4201
- depositAssetBatch = {
4202
- chainId: selectedDepositAsset.asset.chainId,
4203
- recentBlock: depositRecentBlock,
4204
- calls: [
4205
- {
4206
- to: "0xeee2b52e7CFe6e2168341a34cEB783b68FEdf1A2",
4207
- value: viem.parseEther(selectedDepositAsset.amount),
4208
- data: "0x"
4209
- }
4210
- ]
4211
- };
4212
- } else {
4213
- depositAssetBatch = {
4214
- chainId: selectedDepositAsset.asset.chainId,
4215
- recentBlock: depositRecentBlock,
4216
- calls: [
4217
- {
4218
- to: selectedDepositAsset.asset.address,
4219
- value: BigInt(0),
4220
- data: viem.encodeFunctionData({
4221
- abi: viem.erc20Abi,
4222
- functionName: "approve",
4223
- args: [
4224
- "0xeee2b52e7CFe6e2168341a34cEB783b68FEdf1A2",
4225
- viem.parseUnits(
4226
- selectedDepositAsset.amount,
4227
- selectedDepositAsset.asset.decimals
4228
- )
4229
- ]
4230
- })
4231
- },
4232
- {
4233
- to: selectedDepositAsset.asset.address,
4234
- value: BigInt(0),
4235
- data: viem.encodeFunctionData({
4236
- abi: viem.erc20Abi,
4237
- functionName: "transfer",
4238
- args: [
4239
- "0xeee2b52e7CFe6e2168341a34cEB783b68FEdf1A2",
4240
- viem.parseUnits(
4241
- selectedDepositAsset.amount,
4242
- selectedDepositAsset.asset.decimals
4243
- )
4244
- ]
4245
- })
4246
- }
4247
- ]
4248
- };
4249
- }
4250
- const allChainBatches = [depositAssetBatch, ...depositBatches];
4394
+ const allChainBatches = [...depositBatches];
4251
4395
  const uniqueChainIds = [
4252
4396
  ...new Set(allChainBatches.map((batch) => batch.chainId))
4253
4397
  ];
@@ -4294,6 +4438,19 @@ const DepositWidget = ({
4294
4438
  };
4295
4439
  const result = await relayerService.submitTransaction(submitRequest);
4296
4440
  if (result) {
4441
+ const withdrawalAmount = viem.parseUnits(
4442
+ selectedDepositAsset.amount,
4443
+ selectedDepositAsset.asset.decimals
4444
+ );
4445
+ await relayerService.submitSpiceDeposit({
4446
+ user: address,
4447
+ txHash: result.hash,
4448
+ sender: address,
4449
+ tokenAddress: selectedDepositAsset.asset.address,
4450
+ chainId: selectedDepositAsset.asset.chainId,
4451
+ amount: withdrawalAmount.toString(),
4452
+ isDeposit: false
4453
+ });
4297
4454
  const getChainName = (chainId) => {
4298
4455
  return `Chain ${chainId}`;
4299
4456
  };
@@ -4336,7 +4493,7 @@ const DepositWidget = ({
4336
4493
  };
4337
4494
  if (intentStatus) {
4338
4495
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className, children: /* @__PURE__ */ jsxRuntime.jsx(
4339
- StatusDisplay,
4496
+ DepositStatusPanel,
4340
4497
  {
4341
4498
  intentStatus,
4342
4499
  onClose: clearStatus,
@@ -4344,13 +4501,11 @@ const DepositWidget = ({
4344
4501
  clearStatus();
4345
4502
  handleDeposit();
4346
4503
  },
4347
- txType: "deposit",
4348
- onNewTx: () => {
4504
+ onNewDeposit: () => {
4349
4505
  clearStatus();
4350
4506
  setSelectedDepositAsset(null);
4351
4507
  refreshSpiceAssets();
4352
4508
  },
4353
- explorerUrlBuilder: (chainId, txHash) => getExplorerUrl(chainId, txHash),
4354
4509
  theme
4355
4510
  }
4356
4511
  ) });
@@ -9049,51 +9204,45 @@ const useSpiceBalance = ({
9049
9204
  throw new Error(`Failed to fetch balance: ${response.status}`);
9050
9205
  }
9051
9206
  const result = await response.json();
9052
- if (result.success && result.data && result.data.tokens) {
9053
- const tokens = result.data.tokens;
9207
+ if (result.success && result.data?.tokens && Array.isArray(result.data.tokens)) {
9054
9208
  const freeCollateralItems = [];
9055
9209
  let totalBalance = 0;
9056
- Object.keys(tokens).forEach((chainIdStr) => {
9057
- const chainId = parseInt(chainIdStr);
9058
- const chainTokens = tokens[chainIdStr];
9059
- if (chainTokens && typeof chainTokens === "object") {
9060
- Object.keys(chainTokens).forEach((tokenAddress) => {
9061
- const balanceStr = chainTokens[tokenAddress];
9062
- const rawBalance = parseFloat(balanceStr || "0");
9063
- if (rawBalance > 0) {
9064
- const chainConfig = getChainConfig(chainId);
9065
- const isNative = tokenAddress.toLowerCase() === "0x0" || tokenAddress.toLowerCase() === "0x0000000000000000000000000000000000000000" || tokenAddress.toLowerCase() === "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";
9066
- let decimals = 18;
9067
- let tokenSymbol = "TOKEN";
9068
- let tokenName = tokenAddress.slice(0, 6) + "..." + tokenAddress.slice(-4);
9069
- if (isNative) {
9070
- decimals = chainConfig?.nativeCurrency?.decimals || 18;
9071
- tokenSymbol = chainConfig?.nativeCurrency?.symbol || "ETH";
9072
- tokenName = chainConfig?.nativeCurrency?.name || "Native Token";
9073
- } else {
9074
- const tokenConfig = chainConfig?.supportedTokens?.find(
9075
- (t) => t.address.toLowerCase() === tokenAddress.toLowerCase()
9076
- );
9077
- if (tokenConfig) {
9078
- decimals = tokenConfig.decimals;
9079
- tokenSymbol = tokenConfig.symbol;
9080
- tokenName = tokenConfig.name;
9081
- }
9082
- }
9083
- const balance = rawBalance / Math.pow(10, decimals);
9084
- if (balance > 0) {
9085
- freeCollateralItems.push({
9086
- id: `${tokenSymbol.toLowerCase()}-${chainId}`,
9087
- name: tokenSymbol,
9088
- balance,
9089
- subtitle: tokenName,
9090
- iconColor: "#2775CA",
9091
- networks: [chainId]
9092
- });
9093
- totalBalance += balance;
9094
- }
9210
+ result.data.tokens.forEach((token) => {
9211
+ const chainId = token.chainId;
9212
+ const tokenAddress = token.tokenAddress;
9213
+ const rawBalance = parseFloat(token.amount || "0");
9214
+ if (rawBalance > 0) {
9215
+ const chainConfig = getChainConfig(chainId);
9216
+ const isNative = tokenAddress.toLowerCase() === "0x0" || tokenAddress.toLowerCase() === "0x0000000000000000000000000000000000000000" || tokenAddress.toLowerCase() === "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";
9217
+ let decimals = 18;
9218
+ let tokenSymbol = "TOKEN";
9219
+ let tokenName = tokenAddress.slice(0, 6) + "..." + tokenAddress.slice(-4);
9220
+ if (isNative) {
9221
+ decimals = chainConfig?.nativeCurrency?.decimals || 18;
9222
+ tokenSymbol = chainConfig?.nativeCurrency?.symbol || "ETH";
9223
+ tokenName = chainConfig?.nativeCurrency?.name || "Native Token";
9224
+ } else {
9225
+ const tokenConfig = chainConfig?.supportedTokens?.find(
9226
+ (t) => t.address.toLowerCase() === tokenAddress.toLowerCase()
9227
+ );
9228
+ if (tokenConfig) {
9229
+ decimals = tokenConfig.decimals;
9230
+ tokenSymbol = tokenConfig.symbol;
9231
+ tokenName = tokenConfig.name;
9095
9232
  }
9096
- });
9233
+ }
9234
+ const balance = rawBalance / Math.pow(10, decimals);
9235
+ if (balance > 0) {
9236
+ freeCollateralItems.push({
9237
+ id: `${tokenSymbol.toLowerCase()}-${chainId}`,
9238
+ name: tokenSymbol,
9239
+ balance,
9240
+ subtitle: tokenName,
9241
+ iconColor: "#2775CA",
9242
+ networks: [chainId]
9243
+ });
9244
+ totalBalance += balance;
9245
+ }
9097
9246
  }
9098
9247
  });
9099
9248
  if (totalBalance > 0 && freeCollateralItems.length > 0) {
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { defineChain, createPublicClient, http, isAddress, getAddress, parseEther, encodeFunctionData, parseUnits, erc20Abi } from 'viem';
2
+ import { defineChain, createPublicClient, http, isAddress, getAddress, parseEther, parseUnits, encodeFunctionData } from 'viem';
3
3
  import { basecampTestnet, citreaTestnet, baseSepolia, arbitrumSepolia, sepolia } from 'viem/chains';
4
4
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
5
5
  import React, { useState, useRef, useEffect, useCallback, createContext, useContext, useTransition, useMemo, forwardRef, createElement } from 'react';
@@ -3986,61 +3986,55 @@ const useSpiceAssets = ({
3986
3986
  throw new Error(`Failed to fetch balance: ${response.status}`);
3987
3987
  }
3988
3988
  const result = await response.json();
3989
- if (result.success && result.data?.tokens) {
3990
- const tokens = result.data.tokens;
3989
+ if (result.success && result.data?.tokens && Array.isArray(result.data.tokens)) {
3991
3990
  const parsedAssets = [];
3992
- Object.keys(tokens).forEach((chainIdStr) => {
3993
- const chainId = parseInt(chainIdStr);
3991
+ result.data.tokens.forEach((token) => {
3992
+ const chainId = token.chainId;
3993
+ const tokenAddress = token.tokenAddress;
3994
+ const rawBalanceStr = token.amount;
3994
3995
  if (supportedChains && !supportedChains.includes(chainId)) {
3995
3996
  return;
3996
3997
  }
3997
- const chainTokens = tokens[chainIdStr];
3998
- const chainConfig = getChainConfig(chainId);
3999
- if (chainTokens && typeof chainTokens === "object") {
4000
- Object.keys(chainTokens).forEach((tokenAddress) => {
4001
- const rawBalanceStr = chainTokens[tokenAddress];
4002
- const rawBalance = BigInt(rawBalanceStr || "0");
4003
- if (rawBalance > BigInt(0)) {
4004
- const isNative = tokenAddress.toLowerCase() === "0x0" || tokenAddress.toLowerCase() === "0x0000000000000000000000000000000000000000" || tokenAddress.toLowerCase() === "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";
4005
- let decimals = 18;
4006
- let symbol = "TOKEN";
4007
- let name = tokenAddress.slice(0, 6) + "..." + tokenAddress.slice(-4);
4008
- let logoURI;
4009
- if (isNative) {
4010
- decimals = chainConfig?.nativeCurrency?.decimals || 18;
4011
- symbol = chainConfig?.nativeCurrency?.symbol || "ETH";
4012
- name = chainConfig?.nativeCurrency?.name || "Native Token";
4013
- } else {
4014
- const tokenConfig = chainConfig?.supportedTokens?.find(
4015
- (t) => t.address.toLowerCase() === tokenAddress.toLowerCase()
4016
- );
4017
- if (tokenConfig) {
4018
- decimals = tokenConfig.decimals;
4019
- symbol = tokenConfig.symbol;
4020
- name = tokenConfig.name;
4021
- logoURI = tokenConfig.logoURI;
4022
- }
4023
- }
4024
- const balanceFormatted = parseFloat(
4025
- (Number(rawBalance) / Math.pow(10, decimals)).toFixed(6)
4026
- );
4027
- if (balanceFormatted > 0) {
4028
- parsedAssets.push({
4029
- address: isNative ? "0x0000000000000000000000000000000000000000" : tokenAddress,
4030
- symbol,
4031
- name,
4032
- decimals,
4033
- chainId,
4034
- balance: rawBalance,
4035
- balanceFormatted,
4036
- balanceUsd: 0,
4037
- // API doesn't provide USD value
4038
- isNative,
4039
- logoURI
4040
- });
4041
- }
3998
+ const rawBalance = BigInt(rawBalanceStr || "0");
3999
+ if (rawBalance > BigInt(0)) {
4000
+ const chainConfig = getChainConfig(chainId);
4001
+ const isNative = tokenAddress.toLowerCase() === "0x0" || tokenAddress.toLowerCase() === "0x0000000000000000000000000000000000000000" || tokenAddress.toLowerCase() === "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";
4002
+ let decimals = 18;
4003
+ let symbol = "TOKEN";
4004
+ let name = tokenAddress.slice(0, 6) + "..." + tokenAddress.slice(-4);
4005
+ let logoURI;
4006
+ if (isNative) {
4007
+ decimals = chainConfig?.nativeCurrency?.decimals || 18;
4008
+ symbol = chainConfig?.nativeCurrency?.symbol || "ETH";
4009
+ name = chainConfig?.nativeCurrency?.name || "Native Token";
4010
+ } else {
4011
+ const tokenConfig = chainConfig?.supportedTokens?.find(
4012
+ (t) => t.address.toLowerCase() === tokenAddress.toLowerCase()
4013
+ );
4014
+ if (tokenConfig) {
4015
+ decimals = tokenConfig.decimals;
4016
+ symbol = tokenConfig.symbol;
4017
+ name = tokenConfig.name;
4018
+ logoURI = tokenConfig.logoURI;
4042
4019
  }
4043
- });
4020
+ }
4021
+ const balanceFormatted = parseFloat(
4022
+ (Number(rawBalance) / Math.pow(10, decimals)).toFixed(6)
4023
+ );
4024
+ if (balanceFormatted > 0) {
4025
+ parsedAssets.push({
4026
+ address: isNative ? "0x0000000000000000000000000000000000000000" : tokenAddress,
4027
+ symbol,
4028
+ name,
4029
+ decimals,
4030
+ chainId,
4031
+ balance: rawBalance,
4032
+ balanceFormatted,
4033
+ balanceUsd: 0,
4034
+ isNative,
4035
+ logoURI
4036
+ });
4037
+ }
4044
4038
  }
4045
4039
  });
4046
4040
  setAssets(parsedAssets);
@@ -4087,6 +4081,211 @@ const useSpiceAssets = ({
4087
4081
  };
4088
4082
  };
4089
4083
 
4084
+ const DepositStatusPanel = ({
4085
+ intentStatus,
4086
+ onClose,
4087
+ onRetry,
4088
+ onNewDeposit,
4089
+ theme: providedTheme
4090
+ }) => {
4091
+ const theme = providedTheme || createTheme("dark");
4092
+ const containerStyles = {
4093
+ width: "100%",
4094
+ maxWidth: "28rem",
4095
+ margin: "0 auto",
4096
+ backgroundColor: theme.colors.background,
4097
+ border: `1px solid ${theme.colors.border}`,
4098
+ borderRadius: theme.borderRadius.lg,
4099
+ padding: theme.spacing.lg,
4100
+ color: theme.colors.text
4101
+ };
4102
+ const headerStyles = {
4103
+ textAlign: "center",
4104
+ marginBottom: theme.spacing.lg
4105
+ };
4106
+ const iconContainerStyles = {
4107
+ width: "5rem",
4108
+ height: "5rem",
4109
+ margin: "0 auto",
4110
+ backgroundColor: theme.colors.surface,
4111
+ borderRadius: "50%",
4112
+ display: "flex",
4113
+ alignItems: "center",
4114
+ justifyContent: "center",
4115
+ border: `2px solid ${theme.colors.border}`,
4116
+ marginBottom: theme.spacing.md
4117
+ };
4118
+ const titleStyles = {
4119
+ fontSize: theme.typography.fontSize.lg,
4120
+ fontWeight: theme.typography.fontWeight.semibold,
4121
+ color: theme.colors.text,
4122
+ marginBottom: theme.spacing.sm
4123
+ };
4124
+ const descriptionStyles = {
4125
+ fontSize: theme.typography.fontSize.sm,
4126
+ color: theme.colors.textMuted
4127
+ };
4128
+ const buttonContainerStyles = {
4129
+ display: "flex",
4130
+ flexDirection: "column",
4131
+ gap: theme.spacing.sm,
4132
+ marginTop: theme.spacing.lg
4133
+ };
4134
+ const getStatusContent = () => {
4135
+ switch (intentStatus.overallStatus) {
4136
+ case "success":
4137
+ return {
4138
+ icon: /* @__PURE__ */ jsx(
4139
+ "svg",
4140
+ {
4141
+ width: "32",
4142
+ height: "32",
4143
+ fill: "none",
4144
+ stroke: theme.colors.success,
4145
+ viewBox: "0 0 24 24",
4146
+ children: /* @__PURE__ */ jsx(
4147
+ "path",
4148
+ {
4149
+ strokeLinecap: "round",
4150
+ strokeLinejoin: "round",
4151
+ strokeWidth: 2,
4152
+ d: "M5 13l4 4L19 7"
4153
+ }
4154
+ )
4155
+ }
4156
+ ),
4157
+ title: "Deposit Completed!",
4158
+ description: "Your tokens have been successfully deposited.",
4159
+ borderColor: theme.colors.success
4160
+ };
4161
+ case "failed":
4162
+ return {
4163
+ icon: /* @__PURE__ */ jsx(
4164
+ "svg",
4165
+ {
4166
+ width: "32",
4167
+ height: "32",
4168
+ fill: "none",
4169
+ stroke: theme.colors.error,
4170
+ viewBox: "0 0 24 24",
4171
+ children: /* @__PURE__ */ jsx(
4172
+ "path",
4173
+ {
4174
+ strokeLinecap: "round",
4175
+ strokeLinejoin: "round",
4176
+ strokeWidth: 2,
4177
+ d: "M6 18L18 6M6 6l12 12"
4178
+ }
4179
+ )
4180
+ }
4181
+ ),
4182
+ title: "Deposit Failed",
4183
+ description: "Something went wrong. Please try again.",
4184
+ borderColor: theme.colors.error
4185
+ };
4186
+ default:
4187
+ return {
4188
+ icon: /* @__PURE__ */ jsx(
4189
+ "div",
4190
+ {
4191
+ style: {
4192
+ width: "2rem",
4193
+ height: "2rem",
4194
+ border: `3px solid ${theme.colors.primary}`,
4195
+ borderTop: "3px solid transparent",
4196
+ borderRadius: "50%",
4197
+ animation: "spin 1s linear infinite"
4198
+ }
4199
+ }
4200
+ ),
4201
+ title: "Processing Deposit",
4202
+ description: "Please wait while your deposit is being processed...",
4203
+ borderColor: theme.colors.primary
4204
+ };
4205
+ }
4206
+ };
4207
+ const statusContent = getStatusContent();
4208
+ return /* @__PURE__ */ jsxs("div", { style: containerStyles, children: [
4209
+ /* @__PURE__ */ jsx("style", { children: `
4210
+ @keyframes spin {
4211
+ 0% { transform: rotate(0deg); }
4212
+ 100% { transform: rotate(360deg); }
4213
+ }
4214
+ ` }),
4215
+ /* @__PURE__ */ jsxs("div", { style: headerStyles, children: [
4216
+ /* @__PURE__ */ jsx(
4217
+ "div",
4218
+ {
4219
+ style: {
4220
+ ...iconContainerStyles,
4221
+ borderColor: statusContent.borderColor
4222
+ },
4223
+ children: statusContent.icon
4224
+ }
4225
+ ),
4226
+ /* @__PURE__ */ jsx("h3", { style: titleStyles, children: statusContent.title }),
4227
+ /* @__PURE__ */ jsx("p", { style: descriptionStyles, children: statusContent.description })
4228
+ ] }),
4229
+ intentStatus.overallStatus === "processing" && /* @__PURE__ */ jsxs(
4230
+ "div",
4231
+ {
4232
+ style: {
4233
+ backgroundColor: theme.colors.surface,
4234
+ borderRadius: theme.borderRadius.md,
4235
+ padding: theme.spacing.md,
4236
+ marginBottom: theme.spacing.md
4237
+ },
4238
+ children: [
4239
+ /* @__PURE__ */ jsx(
4240
+ "div",
4241
+ {
4242
+ style: {
4243
+ height: "4px",
4244
+ backgroundColor: `${theme.colors.primary}30`,
4245
+ borderRadius: "2px",
4246
+ overflow: "hidden"
4247
+ },
4248
+ children: /* @__PURE__ */ jsx(
4249
+ "div",
4250
+ {
4251
+ style: {
4252
+ width: "30%",
4253
+ height: "100%",
4254
+ backgroundColor: theme.colors.primary,
4255
+ borderRadius: "2px",
4256
+ animation: "progress 1.5s ease-in-out infinite"
4257
+ }
4258
+ }
4259
+ )
4260
+ }
4261
+ ),
4262
+ /* @__PURE__ */ jsx("style", { children: `
4263
+ @keyframes progress {
4264
+ 0% { transform: translateX(-100%); width: 30%; }
4265
+ 50% { width: 60%; }
4266
+ 100% { transform: translateX(400%); width: 30%; }
4267
+ }
4268
+ ` })
4269
+ ]
4270
+ }
4271
+ ),
4272
+ /* @__PURE__ */ jsxs("div", { style: buttonContainerStyles, children: [
4273
+ intentStatus.overallStatus === "success" && onNewDeposit && /* @__PURE__ */ jsx(
4274
+ Button,
4275
+ {
4276
+ variant: "success",
4277
+ fullWidth: true,
4278
+ onClick: onNewDeposit,
4279
+ theme,
4280
+ children: "New Deposit"
4281
+ }
4282
+ ),
4283
+ intentStatus.overallStatus === "failed" && onRetry && /* @__PURE__ */ jsx(Button, { variant: "error", fullWidth: true, onClick: onRetry, theme, children: "Try Again" }),
4284
+ intentStatus.overallStatus === "processing" && /* @__PURE__ */ jsx(Button, { variant: "ghost", fullWidth: true, onClick: onClose, theme, children: "Cancel" })
4285
+ ] })
4286
+ ] });
4287
+ };
4288
+
4090
4289
  const DepositWidget = ({
4091
4290
  depositBatches,
4092
4291
  tokenAddress,
@@ -4190,62 +4389,7 @@ const DepositWidget = ({
4190
4389
  setIsExecuting(true);
4191
4390
  setError(null);
4192
4391
  try {
4193
- const depositClient = getClientForChain(
4194
- selectedDepositAsset.asset.chainId
4195
- );
4196
- const depositRecentBlock = await depositClient.getBlockNumber();
4197
- let depositAssetBatch;
4198
- if (selectedDepositAsset.asset.isNative) {
4199
- depositAssetBatch = {
4200
- chainId: selectedDepositAsset.asset.chainId,
4201
- recentBlock: depositRecentBlock,
4202
- calls: [
4203
- {
4204
- to: "0xeee2b52e7CFe6e2168341a34cEB783b68FEdf1A2",
4205
- value: parseEther(selectedDepositAsset.amount),
4206
- data: "0x"
4207
- }
4208
- ]
4209
- };
4210
- } else {
4211
- depositAssetBatch = {
4212
- chainId: selectedDepositAsset.asset.chainId,
4213
- recentBlock: depositRecentBlock,
4214
- calls: [
4215
- {
4216
- to: selectedDepositAsset.asset.address,
4217
- value: BigInt(0),
4218
- data: encodeFunctionData({
4219
- abi: erc20Abi,
4220
- functionName: "approve",
4221
- args: [
4222
- "0xeee2b52e7CFe6e2168341a34cEB783b68FEdf1A2",
4223
- parseUnits(
4224
- selectedDepositAsset.amount,
4225
- selectedDepositAsset.asset.decimals
4226
- )
4227
- ]
4228
- })
4229
- },
4230
- {
4231
- to: selectedDepositAsset.asset.address,
4232
- value: BigInt(0),
4233
- data: encodeFunctionData({
4234
- abi: erc20Abi,
4235
- functionName: "transfer",
4236
- args: [
4237
- "0xeee2b52e7CFe6e2168341a34cEB783b68FEdf1A2",
4238
- parseUnits(
4239
- selectedDepositAsset.amount,
4240
- selectedDepositAsset.asset.decimals
4241
- )
4242
- ]
4243
- })
4244
- }
4245
- ]
4246
- };
4247
- }
4248
- const allChainBatches = [depositAssetBatch, ...depositBatches];
4392
+ const allChainBatches = [...depositBatches];
4249
4393
  const uniqueChainIds = [
4250
4394
  ...new Set(allChainBatches.map((batch) => batch.chainId))
4251
4395
  ];
@@ -4292,6 +4436,19 @@ const DepositWidget = ({
4292
4436
  };
4293
4437
  const result = await relayerService.submitTransaction(submitRequest);
4294
4438
  if (result) {
4439
+ const withdrawalAmount = parseUnits(
4440
+ selectedDepositAsset.amount,
4441
+ selectedDepositAsset.asset.decimals
4442
+ );
4443
+ await relayerService.submitSpiceDeposit({
4444
+ user: address,
4445
+ txHash: result.hash,
4446
+ sender: address,
4447
+ tokenAddress: selectedDepositAsset.asset.address,
4448
+ chainId: selectedDepositAsset.asset.chainId,
4449
+ amount: withdrawalAmount.toString(),
4450
+ isDeposit: false
4451
+ });
4295
4452
  const getChainName = (chainId) => {
4296
4453
  return `Chain ${chainId}`;
4297
4454
  };
@@ -4334,7 +4491,7 @@ const DepositWidget = ({
4334
4491
  };
4335
4492
  if (intentStatus) {
4336
4493
  return /* @__PURE__ */ jsx("div", { className, children: /* @__PURE__ */ jsx(
4337
- StatusDisplay,
4494
+ DepositStatusPanel,
4338
4495
  {
4339
4496
  intentStatus,
4340
4497
  onClose: clearStatus,
@@ -4342,13 +4499,11 @@ const DepositWidget = ({
4342
4499
  clearStatus();
4343
4500
  handleDeposit();
4344
4501
  },
4345
- txType: "deposit",
4346
- onNewTx: () => {
4502
+ onNewDeposit: () => {
4347
4503
  clearStatus();
4348
4504
  setSelectedDepositAsset(null);
4349
4505
  refreshSpiceAssets();
4350
4506
  },
4351
- explorerUrlBuilder: (chainId, txHash) => getExplorerUrl(chainId, txHash),
4352
4507
  theme
4353
4508
  }
4354
4509
  ) });
@@ -9047,51 +9202,45 @@ const useSpiceBalance = ({
9047
9202
  throw new Error(`Failed to fetch balance: ${response.status}`);
9048
9203
  }
9049
9204
  const result = await response.json();
9050
- if (result.success && result.data && result.data.tokens) {
9051
- const tokens = result.data.tokens;
9205
+ if (result.success && result.data?.tokens && Array.isArray(result.data.tokens)) {
9052
9206
  const freeCollateralItems = [];
9053
9207
  let totalBalance = 0;
9054
- Object.keys(tokens).forEach((chainIdStr) => {
9055
- const chainId = parseInt(chainIdStr);
9056
- const chainTokens = tokens[chainIdStr];
9057
- if (chainTokens && typeof chainTokens === "object") {
9058
- Object.keys(chainTokens).forEach((tokenAddress) => {
9059
- const balanceStr = chainTokens[tokenAddress];
9060
- const rawBalance = parseFloat(balanceStr || "0");
9061
- if (rawBalance > 0) {
9062
- const chainConfig = getChainConfig(chainId);
9063
- const isNative = tokenAddress.toLowerCase() === "0x0" || tokenAddress.toLowerCase() === "0x0000000000000000000000000000000000000000" || tokenAddress.toLowerCase() === "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";
9064
- let decimals = 18;
9065
- let tokenSymbol = "TOKEN";
9066
- let tokenName = tokenAddress.slice(0, 6) + "..." + tokenAddress.slice(-4);
9067
- if (isNative) {
9068
- decimals = chainConfig?.nativeCurrency?.decimals || 18;
9069
- tokenSymbol = chainConfig?.nativeCurrency?.symbol || "ETH";
9070
- tokenName = chainConfig?.nativeCurrency?.name || "Native Token";
9071
- } else {
9072
- const tokenConfig = chainConfig?.supportedTokens?.find(
9073
- (t) => t.address.toLowerCase() === tokenAddress.toLowerCase()
9074
- );
9075
- if (tokenConfig) {
9076
- decimals = tokenConfig.decimals;
9077
- tokenSymbol = tokenConfig.symbol;
9078
- tokenName = tokenConfig.name;
9079
- }
9080
- }
9081
- const balance = rawBalance / Math.pow(10, decimals);
9082
- if (balance > 0) {
9083
- freeCollateralItems.push({
9084
- id: `${tokenSymbol.toLowerCase()}-${chainId}`,
9085
- name: tokenSymbol,
9086
- balance,
9087
- subtitle: tokenName,
9088
- iconColor: "#2775CA",
9089
- networks: [chainId]
9090
- });
9091
- totalBalance += balance;
9092
- }
9208
+ result.data.tokens.forEach((token) => {
9209
+ const chainId = token.chainId;
9210
+ const tokenAddress = token.tokenAddress;
9211
+ const rawBalance = parseFloat(token.amount || "0");
9212
+ if (rawBalance > 0) {
9213
+ const chainConfig = getChainConfig(chainId);
9214
+ const isNative = tokenAddress.toLowerCase() === "0x0" || tokenAddress.toLowerCase() === "0x0000000000000000000000000000000000000000" || tokenAddress.toLowerCase() === "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";
9215
+ let decimals = 18;
9216
+ let tokenSymbol = "TOKEN";
9217
+ let tokenName = tokenAddress.slice(0, 6) + "..." + tokenAddress.slice(-4);
9218
+ if (isNative) {
9219
+ decimals = chainConfig?.nativeCurrency?.decimals || 18;
9220
+ tokenSymbol = chainConfig?.nativeCurrency?.symbol || "ETH";
9221
+ tokenName = chainConfig?.nativeCurrency?.name || "Native Token";
9222
+ } else {
9223
+ const tokenConfig = chainConfig?.supportedTokens?.find(
9224
+ (t) => t.address.toLowerCase() === tokenAddress.toLowerCase()
9225
+ );
9226
+ if (tokenConfig) {
9227
+ decimals = tokenConfig.decimals;
9228
+ tokenSymbol = tokenConfig.symbol;
9229
+ tokenName = tokenConfig.name;
9093
9230
  }
9094
- });
9231
+ }
9232
+ const balance = rawBalance / Math.pow(10, decimals);
9233
+ if (balance > 0) {
9234
+ freeCollateralItems.push({
9235
+ id: `${tokenSymbol.toLowerCase()}-${chainId}`,
9236
+ name: tokenSymbol,
9237
+ balance,
9238
+ subtitle: tokenName,
9239
+ iconColor: "#2775CA",
9240
+ networks: [chainId]
9241
+ });
9242
+ totalBalance += balance;
9243
+ }
9095
9244
  }
9096
9245
  });
9097
9246
  if (totalBalance > 0 && freeCollateralItems.length > 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spicenet-io/spiceflow-ui",
3
- "version": "1.8.4",
3
+ "version": "1.8.6",
4
4
  "description": "Spiceflow UI SDK",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs.js",