@xswap-link/sdk 0.10.6 → 0.10.7

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 (46) hide show
  1. package/.github/workflows/main.yml +1 -1
  2. package/CHANGELOG.md +7 -0
  3. package/dist/index.d.mts +39 -8
  4. package/dist/index.d.ts +39 -8
  5. package/dist/index.global.js +827 -440
  6. package/dist/index.js +9 -9
  7. package/dist/index.mjs +9 -9
  8. package/package.json +12 -1
  9. package/src/components/AllWalletsConfig/index.tsx +40 -0
  10. package/src/components/Swap/HistoryView/index.tsx +28 -5
  11. package/src/components/Swap/SwapView/ConfirmationView/TxOverview/index.tsx +73 -47
  12. package/src/components/Swap/SwapView/SwapButton/index.tsx +45 -10
  13. package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/index.tsx +123 -4
  14. package/src/components/Swap/SwapView/SwapPanel/WalletPanel/index.tsx +71 -0
  15. package/src/components/Swap/SwapView/SwapPanel/index.tsx +4 -0
  16. package/src/components/Swap/SwapView/WalletPicker/index.tsx +63 -28
  17. package/src/components/Swap/index.tsx +2 -2
  18. package/src/components/TxConfigForm/index.tsx +9 -34
  19. package/src/components/TxDataCard/TxDataCardUI/index.tsx +16 -10
  20. package/src/components/TxDataCard/index.tsx +1 -0
  21. package/src/components/index.ts +1 -0
  22. package/src/config/wagmiConfig.ts +1 -6
  23. package/src/constants/index.ts +14 -0
  24. package/src/context/HistoryProvider.tsx +121 -25
  25. package/src/context/SwapProvider.tsx +104 -48
  26. package/src/context/TransactionProvider.tsx +60 -1
  27. package/src/context/TxUIWrapper.tsx +187 -71
  28. package/src/context/WalletProvider.tsx +108 -0
  29. package/src/contracts/addresses.ts +4 -0
  30. package/src/contracts/idl/jupiter.ts +2879 -0
  31. package/src/models/Ecosystem.ts +1 -0
  32. package/src/models/Route.ts +14 -3
  33. package/src/models/SolanaTransaction.ts +38 -0
  34. package/src/models/SolanaWeb3Network.ts +5 -0
  35. package/src/models/TxUIWrapper.ts +8 -4
  36. package/src/models/index.ts +1 -0
  37. package/src/models/payloads/GetBalancesPayload.ts +2 -1
  38. package/src/models/payloads/GetSolanaRoutePayload.ts +8 -0
  39. package/src/models/payloads/index.ts +1 -0
  40. package/src/services/api.ts +21 -3
  41. package/src/services/solana/jupiter/extract-swap-data.ts +183 -0
  42. package/src/services/solana/jupiter/get-events.ts +37 -0
  43. package/src/services/solana/jupiter/instruction-parser.ts +217 -0
  44. package/src/services/solana/jupiter/utils.ts +37 -0
  45. package/src/utils/strings.ts +16 -0
  46. package/test/context/SwapProvider.test.tsx +6 -9
@@ -1,6 +1,8 @@
1
1
  import { CloseIcon, WalletConnectIcon } from "@src/assets/icons";
2
- import { FC, useCallback, useMemo } from "react";
2
+ import { FC, useCallback } from "react";
3
3
  import { Connector, useConnect } from "wagmi";
4
+ import { useWallet as useSolanaWallet } from "@solana/wallet-adapter-react";
5
+ import { Ecosystem } from "@src/models";
4
6
 
5
7
  const ConnectorIcon: FC<{ connector: Connector; className?: string }> = ({
6
8
  connector,
@@ -26,30 +28,41 @@ const ConnectorIcon: FC<{ connector: Connector; className?: string }> = ({
26
28
  }
27
29
  };
28
30
 
29
- export const WalletPicker: FC<{ className?: string; onClose: () => void }> = ({
30
- className,
31
- onClose,
32
- }) => {
31
+ export const WalletPicker: FC<{
32
+ ecosystem: Ecosystem;
33
+ className?: string;
34
+ onClose: () => void;
35
+ }> = ({ ecosystem, className, onClose }) => {
33
36
  const { connectors, connectAsync } = useConnect();
37
+ const { wallets, select, connect } = useSolanaWallet();
34
38
 
35
- const allowedConnectors = useMemo(() => {
36
- return connectors.filter((connector) => {
37
- const isInjected = connector.type === "injected";
38
- const isInjectedGeneric = connector.name === "Injected";
39
- const isWalletConnect = connector.type === "walletConnect";
40
-
41
- return isWalletConnect || (isInjected && !isInjectedGeneric);
42
- });
43
- }, [connectors]);
44
-
45
- const handleWalletClick = useCallback(
39
+ const handleEvmWalletClick = useCallback(
46
40
  async (connector: Connector) => {
47
- await connectAsync({ connector });
48
- onClose();
41
+ try {
42
+ await connectAsync({ connector });
43
+ } catch (error) {
44
+ console.error("Failed to connect EVM wallet:", error);
45
+ } finally {
46
+ onClose();
47
+ }
49
48
  },
50
49
  [connectAsync, onClose],
51
50
  );
52
51
 
52
+ const handleConnectSolana = useCallback(
53
+ async (walletName) => {
54
+ try {
55
+ select(walletName);
56
+ await connect();
57
+ } catch (error) {
58
+ console.error("Failed to connect Solana wallet:", error);
59
+ } finally {
60
+ onClose();
61
+ }
62
+ },
63
+ [connect, select, onClose],
64
+ );
65
+
53
66
  return (
54
67
  <div className={`flex flex-col h-full ${className || ""}`}>
55
68
  <div className="flex justify-between">
@@ -63,16 +76,38 @@ export const WalletPicker: FC<{ className?: string; onClose: () => void }> = ({
63
76
  </div>
64
77
  <div className="horizontal-separator" />
65
78
  <div className="h-full pt-4">
66
- {allowedConnectors.map((connector) => (
67
- <button
68
- key={connector.id}
69
- onClick={() => handleWalletClick(connector)}
70
- className="flex items-center w-full gap-3 mt-2 mb-2 cursor-pointer p-4 border border-solid border-white border-opacity-0 hover:selected-wallet-item"
71
- >
72
- <ConnectorIcon connector={connector} />
73
- <div className="text-t_text_primary">{connector.name}</div>
74
- </button>
75
- ))}
79
+ {ecosystem === Ecosystem.EVM && (
80
+ <>
81
+ {connectors.map((connector) => (
82
+ <button
83
+ key={connector.id}
84
+ onClick={() => handleEvmWalletClick(connector)}
85
+ className="flex items-center w-full gap-3 mt-2 mb-2 cursor-pointer p-4 border border-solid border-white border-opacity-0 hover:selected-wallet-item"
86
+ >
87
+ <ConnectorIcon connector={connector} />
88
+ <div className="text-t_text_primary">{connector.name}</div>
89
+ </button>
90
+ ))}
91
+ </>
92
+ )}
93
+ {ecosystem === Ecosystem.SOLANA && (
94
+ <>
95
+ {wallets.map((wallet) => (
96
+ <button
97
+ key={wallet.adapter.name}
98
+ onClick={() => handleConnectSolana(wallet.adapter.name)}
99
+ className="flex items-center w-full gap-3 mt-2 mb-2 cursor-pointer p-4 border border-solid border-white border-opacity-0 hover:selected-wallet-item"
100
+ >
101
+ <img
102
+ src={wallet.adapter.icon}
103
+ alt={wallet.adapter.name}
104
+ className={`w-[34px] h-[34px] rounded-md ${className || ""}`}
105
+ />
106
+ <div className="text-t_text_primary">{wallet.adapter.name}</div>
107
+ </button>
108
+ ))}
109
+ </>
110
+ )}
76
111
  </div>
77
112
  </div>
78
113
  );
@@ -1,13 +1,13 @@
1
1
  import { useSwapContext } from "@src/context";
2
- import { Route } from "@src/models";
3
2
  import { useMemo } from "react";
4
3
  import { Header } from "./Header";
5
4
  import { HistoryView } from "./HistoryView";
6
5
  import { SettingsView } from "./SettingsView";
7
6
  import { SwapView } from "./SwapView";
7
+ import { UnifiedRoute } from "@src/models";
8
8
 
9
9
  type Props = {
10
- onSubmit: (route: Route) => void;
10
+ onSubmit: (route: UnifiedRoute) => void;
11
11
  onClose: () => void;
12
12
  };
13
13
  export const Swap = ({ onClose }: Props) => {
@@ -7,13 +7,13 @@ import {
7
7
  TxUIWrapper,
8
8
  useHistory,
9
9
  } from "@src/context";
10
- import { Chain, ModalIntegrationPayload, Route } from "@src/models";
11
- import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
10
+ import { Chain, ModalIntegrationPayload, UnifiedRoute } from "@src/models";
12
11
  import { FC, MouseEvent, useEffect, useMemo } from "react";
13
12
  import { ErrorBoundary } from "react-error-boundary";
14
- import { useReconnect, WagmiProvider } from "wagmi";
15
13
  import { changeHostVariableColor } from "../../../localTheme";
16
14
  import { setApiUrl } from "@src/services/api";
15
+ import { WalletProvider } from "@src/context/WalletProvider";
16
+ import { AllWalletsConfig } from "../AllWalletsConfig";
17
17
 
18
18
  export type TxConfigFormPayload = Omit<
19
19
  ModalIntegrationPayload,
@@ -33,7 +33,7 @@ export type TxConfigFormPayload = Omit<
33
33
  type TxConfigFormProps = TxConfigFormPayload &
34
34
  (
35
35
  | {
36
- onSubmit: (route: Route) => void;
36
+ onSubmit: (route: UnifiedRoute) => void;
37
37
  onClose: () => void;
38
38
  overlay: true;
39
39
  }
@@ -44,29 +44,6 @@ type TxConfigFormProps = TxConfigFormPayload &
44
44
  }
45
45
  );
46
46
 
47
- const queryClient = new QueryClient();
48
-
49
- const WagmiReload: FC = () => {
50
- const { reconnect } = useReconnect();
51
-
52
- useEffect(() => {
53
- let count = 0;
54
- const interval = setInterval(() => {
55
- reconnect();
56
- count++;
57
- if (count >= 5) {
58
- clearInterval(interval);
59
- }
60
- }, 1000);
61
-
62
- return () => {
63
- clearInterval(interval);
64
- };
65
- }, [reconnect]);
66
-
67
- return <></>;
68
- };
69
-
70
47
  const normalizeTxConfigFormProps = (props: TxConfigFormProps) => {
71
48
  return {
72
49
  ...props,
@@ -165,9 +142,8 @@ export const TxConfigForm = (props: TxConfigFormProps) => {
165
142
  <div>Something went wrong, please contact XSwap.</div>
166
143
  )}
167
144
  >
168
- <WagmiProvider config={wagmiConfig}>
169
- <QueryClientProvider client={queryClient}>
170
- <WagmiReload />
145
+ <AllWalletsConfig wagmiConfig={wagmiConfig}>
146
+ <WalletProvider>
171
147
  <HistoryProvider>
172
148
  <PendingTransactionsEmitter
173
149
  onPendingTransactionsChange={onPendingTransactionsChange}
@@ -198,7 +174,6 @@ export const TxConfigForm = (props: TxConfigFormProps) => {
198
174
  highlightedDstTokens,
199
175
  }}
200
176
  supportedChains={supportedChains}
201
- wagmiConfig={wagmiConfig}
202
177
  overlay={overlay}
203
178
  >
204
179
  <TransactionProvider>
@@ -223,8 +198,8 @@ export const TxConfigForm = (props: TxConfigFormProps) => {
223
198
  </TransactionProvider>
224
199
  </SwapProvider>
225
200
  </HistoryProvider>
226
- </QueryClientProvider>
227
- </WagmiProvider>
201
+ </WalletProvider>
202
+ </AllWalletsConfig>
228
203
  </ErrorBoundary>
229
204
  );
230
205
  };
@@ -248,7 +223,7 @@ export const openTxConfigForm = async ({
248
223
  srcTokenLocked,
249
224
  srcChainLocked,
250
225
  override,
251
- }: TxConfigFormPayload): Promise<Route> => {
226
+ }: TxConfigFormPayload): Promise<UnifiedRoute> => {
252
227
  try {
253
228
  if (xpayRoot === null) {
254
229
  throw new Error("XPay was incorrectly initialized");
@@ -32,16 +32,22 @@ export const TxDataCardUI = ({
32
32
 
33
33
  const date = getDate(transaction.timestamp);
34
34
 
35
- const transferredAmount = weiToHumanReadable({
36
- amount: transaction.amountWei,
37
- decimals: srcToken?.decimals || 18,
38
- precisionFractionalPlaces: 4,
39
- });
40
- const receivedAmount = weiToHumanReadable({
41
- amount: transaction?.tokenOutAmount || "0",
42
- decimals: dstToken?.decimals || 18,
43
- precisionFractionalPlaces: 4,
44
- });
35
+ const transferredAmount =
36
+ transaction.sourceChainId === "mainnet-beta"
37
+ ? transaction.amountWei
38
+ : weiToHumanReadable({
39
+ amount: transaction.amountWei,
40
+ decimals: srcToken?.decimals || 18,
41
+ precisionFractionalPlaces: 4,
42
+ });
43
+ const receivedAmount =
44
+ transaction.sourceChainId === "mainnet-beta"
45
+ ? (transaction.tokenOutAmount as string)
46
+ : weiToHumanReadable({
47
+ amount: transaction?.tokenOutAmount || "0",
48
+ decimals: dstToken?.decimals || 18,
49
+ precisionFractionalPlaces: 4,
50
+ });
45
51
 
46
52
  const srcChain = supportedChains.find(
47
53
  (chain) => chain.chainId === transaction.sourceChainId,
@@ -19,6 +19,7 @@ export const TxDataCard = ({ transaction }: Props) => {
19
19
  transaction.targetChainId,
20
20
  )
21
21
  : undefined;
22
+
22
23
  return (
23
24
  <TxDataCardUI
24
25
  transaction={transaction}
@@ -1,4 +1,5 @@
1
1
  export * from "./Alert";
2
+ export * from "./AllWalletsConfig";
2
3
  export * from "./Button";
3
4
  export * from "./MessageBar";
4
5
  export * from "./MessageBar/SnackMessage";
@@ -4,7 +4,7 @@ import { Transport } from "viem";
4
4
  import * as WagmiChains from "viem/chains";
5
5
  import { mainnet } from "viem/chains";
6
6
  import { Config, createConfig, createStorage, http } from "@wagmi/core";
7
- import { injected, walletConnect, coinbaseWallet } from "@wagmi/connectors";
7
+ import { walletConnect } from "@wagmi/connectors";
8
8
 
9
9
  const storage = createStorage({
10
10
  key: "xpay.wagmi.store",
@@ -18,11 +18,6 @@ export const getWagmiConfig = (supportedChains: Chain[]): Config => {
18
18
  chains,
19
19
  transports,
20
20
  connectors: [
21
- injected(),
22
- coinbaseWallet({
23
- appLogoUrl: "https://xswap.link/favicon.ico",
24
- appName: "XSwap",
25
- }),
26
21
  walletConnect({
27
22
  projectId: "c392898b45ac587a280b5eb33e92aeb0",
28
23
  showQrModal: true,
@@ -1,6 +1,20 @@
1
+ import { PublicKey } from "@solana/web3.js";
1
2
  import { Ecosystem } from "@src/models";
2
3
  import { constants } from "ethers";
3
4
 
5
+ export const SOLANA_NATIVE_TOKEN_ADDRESS = new PublicKey(
6
+ "So11111111111111111111111111111111111111112",
7
+ );
8
+ export const SOLANA_TOKEN_PROGRAM_ID = new PublicKey(
9
+ "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
10
+ );
11
+ export const METADATA_PROGRAM_ID =
12
+ "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s";
13
+ export const SOLANA_MAINNET_RPC_URL =
14
+ "https://orbital-thrilling-water.solana-mainnet.quiknode.pro/6b4a6d73d2cbe0590ce45bad3b375b183acef83f/";
15
+ export const JUPITER_V6_PROGRAM_ID = new PublicKey(
16
+ "JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4",
17
+ );
4
18
  export const DEFAULT_ECOSYSTEM = Ecosystem.EVM;
5
19
  export const NUMBER_INPUT_REGEX = /^[0-9]*[.,]?[0-9]*$/;
6
20
  export const SLIPPAGE_PRESETS: number[] = [0.5, 1.5, 3.0];
@@ -1,13 +1,19 @@
1
+ import { Connection, PublicKey } from "@solana/web3.js";
1
2
  import { CloseIcon } from "@src/assets/icons";
2
3
  import { Button, SnackMessage } from "@src/components";
3
4
  import {
4
5
  CCIP_EXPLORER,
5
6
  FALLBACK_CROSSCHAIN_ESTIMATION_TIME,
7
+ SOLANA_MAINNET_RPC_URL,
6
8
  crosschainEstimationTimes,
7
9
  } from "@src/constants";
10
+ import { useWallet } from "@src/context/WalletProvider";
8
11
  import { useDebounce } from "@src/hooks";
9
12
  import { Transaction, TransactionStatus } from "@src/models";
13
+ import { TransactionWithMeta } from "@src/models/SolanaTransaction";
10
14
  import { getHistory } from "@src/services";
15
+ import { extractSolanaSwapData } from "@src/services/solana/jupiter/extract-swap-data";
16
+ import { isJupiterTransaction } from "@src/services/solana/jupiter/utils";
11
17
  import { isServer } from "@src/utils";
12
18
  import BigNumberJS from "bignumber.js";
13
19
  import { useSnackbar } from "notistack";
@@ -21,7 +27,6 @@ import {
21
27
  useMemo,
22
28
  useState,
23
29
  } from "react";
24
- import { useAccount } from "wagmi";
25
30
 
26
31
  export interface HistoryState {
27
32
  history: Transaction[];
@@ -34,6 +39,8 @@ export interface HistoryState {
34
39
  userAddress: string,
35
40
  ) => void;
36
41
  historyLoadedOnce: boolean;
42
+ solanaHistory: Transaction[];
43
+ solanaHistoryLoadedOnce: boolean;
37
44
  }
38
45
 
39
46
  const HistoryContext: Context<HistoryState> = createContext<HistoryState>(
@@ -63,11 +70,48 @@ const setLocalHistory = (data: LocalHistory) => {
63
70
  }
64
71
  };
65
72
 
73
+ async function processSolanaTransactions(
74
+ transactions: (TransactionWithMeta | null)[],
75
+ ): Promise<Transaction[]> {
76
+ const results: Transaction[] = [];
77
+
78
+ for (let i = 0; i < transactions.length; i++) {
79
+ try {
80
+ const tx = transactions[i];
81
+ if (!tx) continue;
82
+
83
+ const signature = tx.transaction.signatures[0];
84
+
85
+ if (!signature) continue;
86
+
87
+ const connection = new Connection(SOLANA_MAINNET_RPC_URL, "confirmed");
88
+
89
+ const swapDetails = await extractSolanaSwapData(
90
+ signature,
91
+ connection,
92
+ tx,
93
+ );
94
+
95
+ if (swapDetails) {
96
+ results.push(swapDetails);
97
+ }
98
+ } catch (error) {
99
+ console.error(`Error processing transaction:`, error);
100
+ }
101
+ }
102
+
103
+ return results;
104
+ }
105
+
66
106
  export const HistoryProvider = ({ children }: HistoryProviderProps) => {
67
- const { address } = useAccount();
107
+ const { evm, solana } = useWallet();
108
+ const { address: address } = evm;
109
+ const { address: solanaAddress } = solana;
68
110
 
111
+ const [solanaHistory, setSolanaHistory] = useState<Transaction[]>([]);
69
112
  const [history, setHistory] = useState<Transaction[]>([]);
70
113
  const [historyLoadedOnce, setHistoryLoadedOnce] = useState(false);
114
+ const [solanaHistoryLoadedOnce, setSolanaHistoryLoadedOnce] = useState(false);
71
115
 
72
116
  const { enqueueSnackbar, closeSnackbar } = useSnackbar();
73
117
  const { debounce: getHistoryDebounce } = useDebounce({
@@ -82,16 +126,70 @@ export const HistoryProvider = ({ children }: HistoryProviderProps) => {
82
126
  }
83
127
  }, []);
84
128
 
129
+ const fetchLastSignatures = async (senderAddress: string, limit = 50) => {
130
+ const connection = new Connection(SOLANA_MAINNET_RPC_URL, "confirmed");
131
+ const userPubkey = new PublicKey(senderAddress);
132
+
133
+ try {
134
+ const signatures = await connection.getSignaturesForAddress(userPubkey, {
135
+ limit,
136
+ });
137
+
138
+ const transactions = await connection.getParsedTransactions(
139
+ signatures.map((s) => s.signature),
140
+ {
141
+ maxSupportedTransactionVersion: 0,
142
+ },
143
+ );
144
+
145
+ const jupiterTransactions = transactions
146
+ .filter((val) => !!val)
147
+ .filter((tx) => isJupiterTransaction(tx));
148
+
149
+ const swapDetails = await processSolanaTransactions(
150
+ jupiterTransactions as TransactionWithMeta[],
151
+ );
152
+ return swapDetails;
153
+ } catch (error) {
154
+ console.error("Error fetching transactions:", error);
155
+ return [];
156
+ }
157
+ };
158
+
159
+ const fetchSolanaHistory = async () => {
160
+ if (!solanaAddress) {
161
+ setSolanaHistoryLoadedOnce(true);
162
+ return;
163
+ }
164
+
165
+ try {
166
+ const lastSignatures = await fetchLastSignatures(solanaAddress);
167
+ setSolanaHistory(lastSignatures);
168
+ } finally {
169
+ setSolanaHistoryLoadedOnce(true);
170
+ }
171
+ };
172
+
173
+ useEffect(() => {
174
+ if (solanaAddress) {
175
+ fetchSolanaHistory();
176
+ } else {
177
+ setSolanaHistory([]);
178
+ setSolanaHistoryLoadedOnce(true);
179
+ }
180
+ // eslint-disable-next-line react-hooks/exhaustive-deps
181
+ }, [solanaAddress]);
182
+
85
183
  const fetchHistory = useCallback(async () => {
86
184
  try {
87
185
  if (!address) {
88
186
  return;
89
187
  }
90
188
 
189
+ const fetchedTransactions: Transaction[] = [];
91
190
  const fetchedHistory = await getHistory({
92
191
  walletAddress: address,
93
192
  });
94
- const fetchedTransactions: Transaction[] = [];
95
193
 
96
194
  for (const entry of fetchedHistory.history) {
97
195
  if (!entry.source) {
@@ -158,15 +256,16 @@ export const HistoryProvider = ({ children }: HistoryProviderProps) => {
158
256
  for (const [walletAddress, transactions] of Object.entries(
159
257
  localHistory,
160
258
  )) {
161
- if (
162
- walletAddress.toLowerCase().toLowerCase() !== address.toLowerCase()
163
- ) {
259
+ if (walletAddress.toLowerCase() !== address.toLowerCase()) {
164
260
  continue;
165
261
  }
166
262
  const newLocalHistoryForWallet: Transaction[] = [];
167
263
 
168
264
  for (const transaction of transactions) {
169
- if (!txHashToTxFromAPI[transaction.hash]) {
265
+ const txHash = transaction.hash;
266
+ const apiTransaction = txHashToTxFromAPI[txHash];
267
+
268
+ if (!apiTransaction) {
170
269
  // localStorage has fresher data.
171
270
  fetchedTransactions.push(transaction);
172
271
  newLocalHistoryForWallet.push(transaction);
@@ -174,20 +273,17 @@ export const HistoryProvider = ({ children }: HistoryProviderProps) => {
174
273
  }
175
274
 
176
275
  if (
177
- txHashToTxFromAPI[transaction.hash] &&
276
+ apiTransaction &&
178
277
  transaction.status === "DONE" &&
179
- txHashToTxFromAPI[transaction.hash]?.status === "IN_PROGRESS"
278
+ apiTransaction?.status === "IN_PROGRESS"
180
279
  ) {
181
280
  // If we know on the frontend that the tx is done we should update backend result
182
- // @ts-ignore
183
- txHashToTxFromAPI[transaction.hash].status = "DONE";
281
+ apiTransaction.status = "DONE";
184
282
  }
185
283
 
186
284
  if (
187
- // @ts-ignore
188
- txHashToTxFromAPI[transaction.hash].status === "DONE" ||
189
- // @ts-ignore
190
- txHashToTxFromAPI[transaction.hash].status === "REVERTED"
285
+ apiTransaction.status === "DONE" ||
286
+ apiTransaction.status === "REVERTED"
191
287
  ) {
192
288
  // API has the same or newer data.
193
289
  continue;
@@ -212,7 +308,7 @@ export const HistoryProvider = ({ children }: HistoryProviderProps) => {
212
308
  } finally {
213
309
  setHistoryLoadedOnce(true);
214
310
  }
215
- }, [address, getHistory, enqueueSnackbar]);
311
+ }, [address, enqueueSnackbar]);
216
312
 
217
313
  useEffect(() => {
218
314
  if (!historyLoadedOnce) {
@@ -222,13 +318,7 @@ export const HistoryProvider = ({ children }: HistoryProviderProps) => {
222
318
  getHistoryDebounce(fetchHistory);
223
319
  }, 60000);
224
320
  return () => clearInterval(timer);
225
- }, [
226
- address,
227
- fetchHistory,
228
- getHistory,
229
- getHistoryDebounce,
230
- historyLoadedOnce,
231
- ]);
321
+ }, [address, fetchHistory, getHistoryDebounce, historyLoadedOnce]);
232
322
 
233
323
  const addTransactionToLocalHistory = useCallback(
234
324
  (transaction: Transaction, userAddress: string) => {
@@ -281,7 +371,7 @@ export const HistoryProvider = ({ children }: HistoryProviderProps) => {
281
371
  { persist: false, key: messageId },
282
372
  );
283
373
  },
284
- [enqueueSnackbar],
374
+ [closeSnackbar, enqueueSnackbar],
285
375
  );
286
376
 
287
377
  const updateTransactionInLocalHistory = useCallback(
@@ -319,8 +409,10 @@ export const HistoryProvider = ({ children }: HistoryProviderProps) => {
319
409
 
320
410
  useEffect(() => {
321
411
  setHistoryLoadedOnce(false);
412
+ setSolanaHistoryLoadedOnce(false);
322
413
  setHistory([]);
323
- }, [address]);
414
+ setSolanaHistory([]);
415
+ }, [address, solanaAddress]);
324
416
 
325
417
  const state = useMemo<HistoryState>(
326
418
  () => ({
@@ -328,12 +420,16 @@ export const HistoryProvider = ({ children }: HistoryProviderProps) => {
328
420
  addTransactionToLocalHistory,
329
421
  updateTransactionInLocalHistory,
330
422
  historyLoadedOnce,
423
+ solanaHistory,
424
+ solanaHistoryLoadedOnce,
331
425
  }),
332
426
  [
333
427
  history,
334
428
  addTransactionToLocalHistory,
335
429
  updateTransactionInLocalHistory,
336
430
  historyLoadedOnce,
431
+ solanaHistory,
432
+ solanaHistoryLoadedOnce,
337
433
  ],
338
434
  );
339
435