@sundaeswap/wallet-lite 0.0.25 → 0.0.26

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/dist/cjs/classes/WalletObserver.class.js +11 -0
  2. package/dist/cjs/classes/WalletObserver.class.js.map +1 -1
  3. package/dist/cjs/react-components/WalletObserverProvider/WalletObserverProvider.js +13 -20
  4. package/dist/cjs/react-components/WalletObserverProvider/WalletObserverProvider.js.map +1 -1
  5. package/dist/cjs/react-components/WalletObserverProvider/hooks/effects/useProviderEventListeners.js +6 -8
  6. package/dist/cjs/react-components/WalletObserverProvider/hooks/effects/useProviderEventListeners.js.map +1 -1
  7. package/dist/cjs/react-components/WalletObserverProvider/hooks/useWalletObserverState.js +106 -71
  8. package/dist/cjs/react-components/WalletObserverProvider/hooks/useWalletObserverState.js.map +1 -1
  9. package/dist/cjs/react-components/contexts/observer/types.js.map +1 -1
  10. package/dist/cjs/react-components/hooks/useWalletHandles.js +67 -52
  11. package/dist/cjs/react-components/hooks/useWalletHandles.js.map +1 -1
  12. package/dist/cjs/react-components/hooks/useWalletObserver.js +6 -3
  13. package/dist/cjs/react-components/hooks/useWalletObserver.js.map +1 -1
  14. package/dist/esm/classes/WalletObserver.class.js +9 -0
  15. package/dist/esm/classes/WalletObserver.class.js.map +1 -1
  16. package/dist/esm/react-components/WalletObserverProvider/WalletObserverProvider.js +7 -11
  17. package/dist/esm/react-components/WalletObserverProvider/WalletObserverProvider.js.map +1 -1
  18. package/dist/esm/react-components/WalletObserverProvider/hooks/effects/useProviderEventListeners.js +6 -8
  19. package/dist/esm/react-components/WalletObserverProvider/hooks/effects/useProviderEventListeners.js.map +1 -1
  20. package/dist/esm/react-components/WalletObserverProvider/hooks/useWalletObserverState.js +57 -40
  21. package/dist/esm/react-components/WalletObserverProvider/hooks/useWalletObserverState.js.map +1 -1
  22. package/dist/esm/react-components/contexts/observer/types.js.map +1 -1
  23. package/dist/esm/react-components/hooks/useWalletHandles.js +31 -24
  24. package/dist/esm/react-components/hooks/useWalletHandles.js.map +1 -1
  25. package/dist/esm/react-components/hooks/useWalletObserver.js +6 -3
  26. package/dist/esm/react-components/hooks/useWalletObserver.js.map +1 -1
  27. package/dist/types/classes/WalletObserver.class.d.ts +6 -0
  28. package/dist/types/classes/WalletObserver.class.d.ts.map +1 -1
  29. package/dist/types/react-components/WalletObserverProvider/WalletObserverProvider.d.ts.map +1 -1
  30. package/dist/types/react-components/WalletObserverProvider/hooks/effects/useProviderEventListeners.d.ts +2 -1
  31. package/dist/types/react-components/WalletObserverProvider/hooks/effects/useProviderEventListeners.d.ts.map +1 -1
  32. package/dist/types/react-components/WalletObserverProvider/hooks/useWalletObserverState.d.ts +4 -0
  33. package/dist/types/react-components/WalletObserverProvider/hooks/useWalletObserverState.d.ts.map +1 -1
  34. package/dist/types/react-components/contexts/observer/types.d.ts +3 -0
  35. package/dist/types/react-components/contexts/observer/types.d.ts.map +1 -1
  36. package/dist/types/react-components/hooks/useWalletHandles.d.ts.map +1 -1
  37. package/dist/types/react-components/hooks/useWalletObserver.d.ts.map +1 -1
  38. package/dist/types/tsconfig.build.tsbuildinfo +1 -1
  39. package/package.json +1 -1
  40. package/src/classes/WalletObserver.class.ts +9 -0
  41. package/src/react-components/WalletObserverProvider/WalletObserverProvider.tsx +6 -9
  42. package/src/react-components/WalletObserverProvider/hooks/effects/useProviderEventListeners.ts +7 -13
  43. package/src/react-components/WalletObserverProvider/hooks/useWalletObserverState.ts +90 -67
  44. package/src/react-components/contexts/observer/types.ts +3 -0
  45. package/src/react-components/hooks/useWalletHandles.ts +69 -62
  46. package/src/react-components/hooks/useWalletObserver.ts +7 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sundaeswap/wallet-lite",
3
- "version": "0.0.25",
3
+ "version": "0.0.26",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/index.js",
@@ -210,6 +210,15 @@ export class WalletObserver<
210
210
  return this._performingSync;
211
211
  }
212
212
 
213
+ /**
214
+ * Helper method to check if the instance has an active connection.
215
+ *
216
+ * @returns {boolean}
217
+ */
218
+ hasActiveConnection(): boolean {
219
+ return Boolean(this._activeWallet && this.api);
220
+ }
221
+
213
222
  /**
214
223
  * Synchronizes the API with the wallet. This is useful if the account has changed,
215
224
  * but the underlying intent has not.
@@ -22,19 +22,17 @@ const WalletObserverProvider: FC<
22
22
  PropsWithChildren<IWalletObserverProviderProps>
23
23
  > = ({ children, options }) => {
24
24
  const observerRef = useProviderWalletObserverRef(options?.observerOptions);
25
- const { syncWallet, ...reactiveState } = useWalletObserverState(
26
- observerRef.current
27
- );
25
+ const state = useWalletObserverState(observerRef.current);
28
26
 
29
- useProviderEventListeners(observerRef.current, syncWallet);
27
+ useProviderEventListeners(observerRef.current, state);
30
28
  useProviderRefreshInterval(
31
29
  observerRef.current,
32
- syncWallet,
30
+ state.syncWallet,
33
31
  options?.refreshInterval
34
32
  );
35
33
 
36
34
  const derivedState = useDerivedState(observerRef.current, {
37
- usedAddresses: reactiveState.usedAddresses,
35
+ usedAddresses: state.usedAddresses,
38
36
  });
39
37
 
40
38
  // Memoize the context value
@@ -43,13 +41,12 @@ const WalletObserverProvider: FC<
43
41
  observerRef: observerRef,
44
42
  refreshInterval: options?.refreshInterval || 30000,
45
43
  state: {
46
- ...reactiveState,
44
+ ...state,
47
45
  ...derivedState,
48
46
  observer: observerRef.current,
49
- syncWallet,
50
47
  },
51
48
  }),
52
- [options, syncWallet, reactiveState, derivedState]
49
+ [options, state, derivedState]
53
50
  );
54
51
 
55
52
  return (
@@ -3,6 +3,7 @@ import { useEffect } from "react";
3
3
  import { EWalletObserverEvents } from "../../../../@types/events.js";
4
4
  import { WalletObserver } from "../../../../classes/WalletObserver.class.js";
5
5
  import { TWalletProviderHooks } from "../../../contexts/observer/index.js";
6
+ import { useWalletObserverState } from "../useWalletObserverState.js";
6
7
 
7
8
  /**
8
9
  * Internal use only. This is run in every WalletObserverProvider
@@ -15,7 +16,7 @@ import { TWalletProviderHooks } from "../../../contexts/observer/index.js";
15
16
  */
16
17
  export const useProviderEventListeners = (
17
18
  observer: WalletObserver,
18
- syncWallet: () => Promise<void>,
19
+ state: ReturnType<typeof useWalletObserverState>,
19
20
  hooks?: TWalletProviderHooks
20
21
  ) => {
21
22
  /**
@@ -80,26 +81,19 @@ export const useProviderEventListeners = (
80
81
  * Ensure the wallet syncs on connect and disconnect.
81
82
  */
82
83
  useEffect(() => {
83
- window.addEventListener("focus", syncWallet);
84
+ window.addEventListener("focus", state.syncWallet);
84
85
 
85
86
  observer.addEventListener(
86
87
  EWalletObserverEvents.CONNECT_WALLET_END,
87
- syncWallet
88
+ state.syncWallet
88
89
  );
89
90
 
90
- observer.addEventListener(EWalletObserverEvents.DISCONNECT, syncWallet);
91
-
92
91
  return () => {
93
- window.addEventListener("focus", syncWallet);
92
+ window.addEventListener("focus", state.syncWallet);
94
93
  observer.removeEventListener(
95
94
  EWalletObserverEvents.CONNECT_WALLET_END,
96
- syncWallet
97
- );
98
-
99
- observer.removeEventListener(
100
- EWalletObserverEvents.DISCONNECT,
101
- syncWallet
95
+ state.syncWallet
102
96
  );
103
97
  };
104
- }, [observer, syncWallet]);
98
+ }, [observer, state.syncWallet]);
105
99
  };
@@ -1,7 +1,6 @@
1
1
  import type { TransactionUnspentOutput } from "@cardano-sdk/core/dist/cjs/Serialization/index.js";
2
2
  import { AssetAmount } from "@sundaeswap/asset";
3
3
  import { useCallback, useState } from "react";
4
- import { unstable_batchedUpdates } from "react-dom";
5
4
 
6
5
  import {
7
6
  TAssetAmountMap,
@@ -38,92 +37,112 @@ export const useWalletObserverState = (observer: WalletObserver) => {
38
37
  const [collateral, setCollateral] = useState<TransactionUnspentOutput[]>();
39
38
  const [ready, setReady] = useState(false);
40
39
  const [isCip45, setIsCip45] = useState(false);
40
+ const [switching, setSwitching] = useState(false);
41
+
42
+ const disconnect = useCallback(() => {
43
+ // Reset observer state.
44
+ observer.disconnect();
45
+
46
+ // Reset state.
47
+ setAdaBalance(new AssetAmount(0n));
48
+ setBalance(new WalletBalanceMap(observer));
49
+ setHandleMetadata(new WalletAssetMap());
50
+ setUsedAddresses([]);
51
+ setUnusedAddresses([]);
52
+ setActiveWallet(undefined);
53
+ setNetwork(undefined);
54
+ setUtxos(undefined);
55
+ setCollateral(undefined);
56
+ setReady(false);
57
+ setIsCip45(false);
58
+ }, [observer]);
59
+
60
+ const connectWallet = useCallback(
61
+ async (wallet: TSupportedWalletExtensions) => {
62
+ if (
63
+ observer.hasActiveConnection() &&
64
+ wallet !== observer.getActiveWallet()
65
+ ) {
66
+ setSwitching(true);
67
+ }
68
+
69
+ await observer.connectWallet(wallet);
70
+ setSwitching(false);
71
+ },
72
+ [observer, setSwitching]
73
+ );
41
74
 
42
75
  const syncWallet = useCallback(async () => {
43
- if (observer.isSyncing()) {
76
+ if (observer.isSyncing() || !observer.hasActiveConnection()) {
44
77
  return;
45
78
  }
46
79
 
47
80
  const newWallet = observer.getActiveWallet();
48
-
49
81
  if (!newWallet) {
50
- unstable_batchedUpdates(() => {
51
- setAdaBalance(new AssetAmount(0n));
52
- setBalance(new WalletBalanceMap(observer));
53
- setUsedAddresses([]);
54
- setUnusedAddresses([]);
55
- setActiveWallet(undefined);
56
- setNetwork(undefined);
57
- setUtxos(undefined);
58
- setCollateral(undefined);
59
- });
82
+ disconnect();
60
83
  return;
61
84
  }
62
85
 
63
86
  const freshData = await observer.sync();
64
87
 
65
- unstable_batchedUpdates(() => {
66
- setActiveWallet((prevWallet) =>
67
- newWallet === prevWallet ? prevWallet : newWallet
68
- );
69
-
70
- const newAdaBalance = freshData.balanceMap.get(
71
- WalletObserver.ADA_ASSET_ID
72
- );
73
- if (newAdaBalance) {
74
- setAdaBalance((prevBalance) =>
75
- prevBalance.amount === newAdaBalance.amount
76
- ? prevBalance
77
- : newAdaBalance
78
- );
79
- }
88
+ setActiveWallet((prevWallet) =>
89
+ newWallet === prevWallet ? prevWallet : newWallet
90
+ );
80
91
 
81
- setBalance((prevBalance) =>
82
- areAssetMapsEqual(prevBalance, freshData.balanceMap)
92
+ const newAdaBalance = freshData.balanceMap.get(WalletObserver.ADA_ASSET_ID);
93
+ if (newAdaBalance) {
94
+ setAdaBalance((prevBalance) =>
95
+ prevBalance.amount === newAdaBalance.amount
83
96
  ? prevBalance
84
- : freshData.balanceMap
85
- );
86
-
87
- setUsedAddresses((prevValue) =>
88
- JSON.stringify(prevValue) === JSON.stringify(freshData.usedAddresses)
89
- ? prevValue
90
- : freshData.usedAddresses
97
+ : newAdaBalance
91
98
  );
99
+ }
92
100
 
93
- setUnusedAddresses((prevValue) =>
94
- JSON.stringify(prevValue) === JSON.stringify(freshData.unusedAddresses)
95
- ? prevValue
96
- : freshData.unusedAddresses
97
- );
98
-
99
- setNetwork((prevValue) =>
100
- prevValue === freshData.network ? prevValue : freshData.network
101
- );
102
-
103
- setUtxos((prevValue) => {
104
- const prevValueRep = prevValue?.map((v) => v.toCbor());
105
- const newValueRep = freshData.utxos?.map((v) => v.toCbor());
106
- if (prevValueRep !== newValueRep) {
107
- return freshData.utxos;
108
- }
109
-
110
- return prevValue;
111
- });
101
+ setBalance((prevBalance) =>
102
+ areAssetMapsEqual(prevBalance, freshData.balanceMap)
103
+ ? prevBalance
104
+ : freshData.balanceMap
105
+ );
106
+
107
+ setUsedAddresses((prevValue) =>
108
+ JSON.stringify(prevValue) === JSON.stringify(freshData.usedAddresses)
109
+ ? prevValue
110
+ : freshData.usedAddresses
111
+ );
112
+
113
+ setUnusedAddresses((prevValue) =>
114
+ JSON.stringify(prevValue) === JSON.stringify(freshData.unusedAddresses)
115
+ ? prevValue
116
+ : freshData.unusedAddresses
117
+ );
118
+
119
+ setNetwork((prevValue) =>
120
+ prevValue === freshData.network ? prevValue : freshData.network
121
+ );
122
+
123
+ setUtxos((prevValue) => {
124
+ const prevValueRep = prevValue?.map((v) => v.toCbor());
125
+ const newValueRep = freshData.utxos?.map((v) => v.toCbor());
126
+ if (prevValueRep !== newValueRep) {
127
+ return freshData.utxos;
128
+ }
112
129
 
113
- setCollateral((prevValue) => {
114
- const prevValueRep = prevValue?.map((v) => v.toCbor());
115
- const newValueRep = freshData.utxos?.map((v) => v.toCbor());
116
- if (prevValueRep !== newValueRep) {
117
- return freshData.utxos;
118
- }
130
+ return prevValue;
131
+ });
119
132
 
120
- return prevValue;
121
- });
133
+ setCollateral((prevValue) => {
134
+ const prevValueRep = prevValue?.map((v) => v.toCbor());
135
+ const newValueRep = freshData.utxos?.map((v) => v.toCbor());
136
+ if (prevValueRep !== newValueRep) {
137
+ return freshData.utxos;
138
+ }
122
139
 
123
- setReady(true);
124
- setIsCip45(newWallet.includes("p2p"));
140
+ return prevValue;
125
141
  });
126
- }, [observer]);
142
+
143
+ setReady(true);
144
+ setIsCip45(newWallet.includes("p2p"));
145
+ }, [observer, disconnect]);
127
146
 
128
147
  return {
129
148
  activeWallet,
@@ -147,6 +166,10 @@ export const useWalletObserverState = (observer: WalletObserver) => {
147
166
  collateral,
148
167
  setCollateral,
149
168
  syncWallet,
169
+ disconnect,
170
+ connectWallet,
171
+ switching,
172
+ setSwitching,
150
173
  ready,
151
174
  setReady,
152
175
  };
@@ -75,7 +75,10 @@ export interface IWalletObserverState<
75
75
  setUnusedAddresses: Dispatch<SetStateAction<string[]>>;
76
76
  usedAddresses: string[];
77
77
  setUsedAddresses: Dispatch<SetStateAction<string[]>>;
78
+ switching: boolean;
78
79
  syncWallet: () => Promise<void>;
80
+ disconnect: () => void;
81
+ connectWallet: (wallet: TSupportedWalletExtensions) => Promise<void>;
79
82
  };
80
83
  }
81
84
 
@@ -33,45 +33,53 @@ export const useWalletHandles = <
33
33
  }
34
34
 
35
35
  try {
36
- const HandleClient = await import("@koralabs/adahandle-sdk");
37
- const context =
38
- state.network === 1
39
- ? HandleClient.HandleClientContext.MAINNET
40
- : HandleClient.HandleClientContext.PREVIEW;
41
-
42
- // @ts-ignore Type isn't exported from default.
43
- const sdk = new HandleClient({
44
- context,
45
- provider: new HandleClient.KoraLabsProvider(context),
46
- });
47
-
48
- // Restore once SDK updated
49
- const walletHandlesWithDataArray = [...walletHandles.entries()];
50
- const walletHandleDataArray: IHandle[] = await sdk
51
- .provider()
52
- .getAllDataBatch(
53
- walletHandlesWithDataArray.map(([key]) => ({
54
- value: key.split(".")[1],
55
- }))
56
- );
57
-
58
- walletHandlesWithDataArray.forEach(([key, asset]) => {
59
- const matchingData = walletHandleDataArray.find(
60
- ({ hex }) => hex === key.split(".")[1]
61
- ) as IHandle;
62
-
63
- walletHandles.set(
64
- normalizeAssetIdWithDot(key),
65
- asset
66
- .withMetadata({
67
- ...matchingData,
68
- ...asset.metadata,
69
- assetId: normalizeAssetIdWithDot(asset.metadata.assetId),
70
- decimals: 0,
71
- })
72
- .withAmount(1n)
73
- );
74
- });
36
+ await import("@koralabs/adahandle-sdk").then(
37
+ async ({
38
+ default: HandleClient,
39
+ HandleClientContext,
40
+ KoraLabsProvider,
41
+ }) => {
42
+ setLoadingHandles(true);
43
+ const context =
44
+ state.network === 1
45
+ ? HandleClientContext.MAINNET
46
+ : HandleClientContext.PREVIEW;
47
+
48
+ // @ts-ignore Type isn't exported from default.
49
+ const sdk = new HandleClient({
50
+ context,
51
+ provider: new KoraLabsProvider(context),
52
+ });
53
+
54
+ // Restore once SDK updated
55
+ const walletHandlesWithDataArray = [...walletHandles.entries()];
56
+ const walletHandleDataArray: IHandle[] = await sdk
57
+ .provider()
58
+ .getAllDataBatch(
59
+ walletHandlesWithDataArray.map(([key]) => ({
60
+ value: key.split(".")[1],
61
+ }))
62
+ );
63
+
64
+ walletHandlesWithDataArray.forEach(([key, asset]) => {
65
+ const matchingData = walletHandleDataArray.find(
66
+ ({ hex }) => hex === key.split(".")[1]
67
+ ) as IHandle;
68
+
69
+ walletHandles.set(
70
+ normalizeAssetIdWithDot(key),
71
+ asset
72
+ .withMetadata({
73
+ ...matchingData,
74
+ ...asset.metadata,
75
+ assetId: normalizeAssetIdWithDot(asset.metadata.assetId),
76
+ decimals: 0,
77
+ })
78
+ .withAmount(1n)
79
+ );
80
+ });
81
+ }
82
+ );
75
83
 
76
84
  return walletHandles;
77
85
  } catch (e) {
@@ -79,35 +87,34 @@ export const useWalletHandles = <
79
87
  return walletHandles;
80
88
  }
81
89
  // We only want to update the callback if the Handle keys change.
82
- }, [state.balance, setLoadingHandles]);
90
+ }, [state.balance]);
83
91
 
84
92
  useEffect(() => {
85
- syncHandles()
86
- .then((newHandles) => {
87
- setHandles((prevHandles) => {
88
- let handleMetadataChanged = false;
89
-
90
- if (newHandles.size !== prevHandles?.size) {
91
- handleMetadataChanged = true;
92
- } else {
93
- for (const [key, val] of newHandles) {
94
- if (
95
- !prevHandles.has(key) ||
96
- prevHandles.get(key)?.amount !== val?.amount
97
- ) {
98
- handleMetadataChanged = true;
99
- }
93
+ syncHandles().then((newHandles) => {
94
+ setHandles((prevHandles) => {
95
+ let handleMetadataChanged = false;
96
+
97
+ if (newHandles.size !== prevHandles?.size) {
98
+ handleMetadataChanged = true;
99
+ } else {
100
+ for (const [key, val] of newHandles) {
101
+ if (
102
+ !prevHandles.has(key) ||
103
+ prevHandles.get(key)?.amount !== val?.amount
104
+ ) {
105
+ handleMetadataChanged = true;
100
106
  }
101
107
  }
108
+ }
102
109
 
103
- if (!handleMetadataChanged) {
104
- return prevHandles;
105
- }
110
+ if (!handleMetadataChanged) {
111
+ return prevHandles;
112
+ }
106
113
 
107
- return newHandles;
108
- });
109
- })
110
- .then(() => setLoadingHandles((prevValue) => !prevValue));
114
+ return newHandles;
115
+ });
116
+ setLoadingHandles(() => false);
117
+ });
111
118
  }, [memoizedHandleDep, syncHandles, setHandles, setLoadingHandles]);
112
119
 
113
120
  const data = useMemo(
@@ -29,9 +29,12 @@ export const useWalletObserver = <
29
29
  utxos: state.utxos,
30
30
  collateral: state.collateral,
31
31
  observer: state.observer,
32
- syncWallet: state.syncWallet,
33
32
  unusedAddresses: state.unusedAddresses,
34
33
  usedAddresses: state.usedAddresses,
34
+ syncWallet: state.syncWallet,
35
+ disconnect: state.disconnect,
36
+ connectWallet: state.connectWallet,
37
+ switching: state.switching,
35
38
  };
36
39
 
37
40
  return result;
@@ -44,12 +47,15 @@ export const useWalletObserver = <
44
47
  state.network,
45
48
  state.observer,
46
49
  state.syncWallet,
50
+ state.disconnect,
51
+ state.connectWallet,
47
52
  state.unusedAddresses,
48
53
  state.usedAddresses,
49
54
  state.utxos,
50
55
  state.collateral,
51
56
  state.ready,
52
57
  state.isCip45,
58
+ state.switching,
53
59
  ]);
54
60
 
55
61
  return memoizedState;