@interchain-kit/react 0.3.31 → 0.3.34

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.
@@ -2,24 +2,26 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { ConnectedContent, ConnectedHeader, ConnectingContent, ConnectingHeader, ErrorContent, ErrorHeader, NotExistContent, NotExistHeader, QRCodeContent, QRCodeHeader, RejectContent, RejectHeader, WalletListContent, WalletListHeader, } from "./views";
3
3
  import { useMemo, useState } from "react";
4
4
  import { WalletState } from "@interchain-kit/core";
5
- import { ConnectModal, } from "@interchain-ui/react";
5
+ import { ConnectModal, ThemeProvider, } from "@interchain-ui/react";
6
6
  import { useWalletManager } from "../hooks";
7
7
  import { transferToWalletUISchema } from "../utils";
8
- export const InterchainWalletModal = () => {
8
+ export const InterchainWalletModal = ({
9
+ // ==== Custom modal styles
10
+ modalContainerClassName, modalContentClassName, modalChildrenClassName, modalContentStyles, modalThemeProviderProps, }) => {
9
11
  const [shouldShowList, setShouldShowList] = useState(false);
10
12
  const { modalIsOpen: isOpen, walletConnectQRCodeUri, wallets: statefulWallets, getChainWalletState, currentWalletName, currentChainName, openModal: open, closeModal: close, chains, setCurrentWalletName, getDownloadLink, getEnv, } = useWalletManager();
11
- const [selectedWallet, setSelectedWallet] = useState(null);
13
+ const [walletToConnect, setWalletToConnect] = useState(null);
12
14
  const walletsForUI = statefulWallets.map((w) => transferToWalletUISchema(w));
13
15
  const chainNameToConnect = currentChainName || chains[0].chainName;
14
16
  const chainToConnect = chains.find((chain) => chain.chainName === chainNameToConnect);
15
17
  const currentWallet = statefulWallets.find((w) => w.info.name === currentWalletName);
16
- const walletToShow = selectedWallet || currentWallet;
17
- const { account, errorMessage } = getChainWalletState(selectedWallet?.info?.name || currentWalletName, currentChainName) || {};
18
+ const walletToShow = walletToConnect || currentWallet;
19
+ const { account, errorMessage } = getChainWalletState(walletToConnect?.info?.name || currentWalletName, currentChainName) || {};
18
20
  const disconnect = () => {
19
21
  walletToShow.disconnect(chainToConnect.chainId);
20
22
  };
21
23
  const onSelectWallet = (wallet) => {
22
- setSelectedWallet(wallet);
24
+ setWalletToConnect(wallet);
23
25
  setShouldShowList(false);
24
26
  return wallet.connect(chainToConnect.chainId);
25
27
  };
@@ -31,9 +33,9 @@ export const InterchainWalletModal = () => {
31
33
  const onReconnect = () => {
32
34
  currentWallet.connect(chainToConnect.chainId);
33
35
  };
34
- return (_jsx(WalletModal, { shouldShowList: shouldShowList, username: account?.username, address: account?.address, disconnect: disconnect, isOpen: isOpen, open: open, close: handleCloseModal, wallets: walletsForUI, walletConnectQRCodeUri: walletConnectQRCodeUri, currentWallet: walletToShow, isConnecting: walletToShow?.walletState === WalletState.Connecting, isConnected: walletToShow?.walletState === WalletState.Connected, isRejected: walletToShow?.walletState === WalletState.Rejected, isDisconnected: walletToShow?.walletState === WalletState.Disconnected, isNotExist: walletToShow?.walletState === WalletState.NotExist, errorMessage: errorMessage, onSelectWallet: (w) => onSelectWallet(w), onBack: () => setShouldShowList(true), onReconnect: () => onSelectWallet(walletToShow), getDownloadLink: () => getDownloadLink(walletToShow?.info.name), getEnv: getEnv }));
36
+ return (_jsx(ThemeProvider, { ...modalThemeProviderProps, children: _jsx(WalletModalElement, { shouldShowList: shouldShowList, username: account?.username, address: account?.address, disconnect: disconnect, isOpen: isOpen, open: open, close: handleCloseModal, wallets: walletsForUI, walletConnectQRCodeUri: walletConnectQRCodeUri, currentWallet: walletToShow, isConnecting: walletToShow?.walletState === WalletState.Connecting, isConnected: walletToShow?.walletState === WalletState.Connected, isRejected: walletToShow?.walletState === WalletState.Rejected, isDisconnected: walletToShow?.walletState === WalletState.Disconnected, isNotExist: walletToShow?.walletState === WalletState.NotExist, errorMessage: errorMessage, onSelectWallet: (w) => onSelectWallet(w), onBack: () => setShouldShowList(true), onReconnect: () => onSelectWallet(walletToShow), getDownloadLink: () => getDownloadLink(walletToShow?.info.name), getEnv: getEnv, modalContainerClassName: modalContainerClassName, modalContentClassName: modalContentClassName, modalChildrenClassName: modalChildrenClassName, modalContentStyles: modalContentStyles, modalThemeProviderProps: modalThemeProviderProps }) }));
35
37
  };
36
- export const WalletModal = ({ shouldShowList, isOpen, walletConnectQRCodeUri, wallets, username, address, currentWallet, isConnecting, isConnected, isRejected, isDisconnected, isNotExist, errorMessage, open, close, disconnect, onSelectWallet, onBack, onReconnect, getDownloadLink, getEnv, }) => {
38
+ export const WalletModalElement = ({ shouldShowList, isOpen, walletConnectQRCodeUri, wallets, username, address, currentWallet, isConnecting, isConnected, isRejected, isDisconnected, isNotExist, errorMessage, open, close, disconnect, onSelectWallet, onBack, onReconnect, getDownloadLink, getEnv, modalThemeProviderProps, modalContainerClassName, modalContentClassName, modalChildrenClassName, modalContentStyles, }) => {
37
39
  const { header, content } = useMemo(() => {
38
40
  if (shouldShowList ||
39
41
  (isDisconnected && currentWallet.errorMessage === "")) {
@@ -94,12 +96,11 @@ export const WalletModal = ({ shouldShowList, isOpen, walletConnectQRCodeUri, wa
94
96
  wallets,
95
97
  isOpen,
96
98
  ]);
97
- return (_jsx(ConnectModal, { isOpen: isOpen, header: header, onOpen: open, onClose: close, children: content }));
99
+ return (_jsx(ConnectModal, { isOpen: isOpen, header: header, onOpen: open, onClose: close, modalContainerClassName: modalContainerClassName, modalContentClassName: modalContentClassName, modalChildrenClassName: modalChildrenClassName, modalContentStyles: modalContentStyles, children: content }));
98
100
  };
99
101
  export const ModalRenderer = ({ walletModal: ProvidedWalletModal, }) => {
100
102
  if (!ProvidedWalletModal) {
101
- throw new Error(`InterchainWalletProvider: walletModal is required. Please provide a wallet modal component. or use InterchainkitWalletModal/n
102
- Example: <ChainProvider chains={chains} assetLists={assetLists} wallets={wallets} walletModal={InterchainKitWalletModal} />`);
103
+ return null;
103
104
  }
104
105
  const { modalIsOpen, openModal, closeModal, wallets, currentWalletName } = useWalletManager();
105
106
  return (_jsx(ProvidedWalletModal, { wallets: wallets, isOpen: modalIsOpen, open: openModal, close: closeModal, currentWallet: wallets.find((w) => w.info.name === currentWalletName) }));
package/esm/provider.js CHANGED
@@ -13,7 +13,7 @@ export const ChainProvider = ({ chains, assetLists, wallets, signerOptions, endp
13
13
  // walletManager.init();
14
14
  store.current.getState().init();
15
15
  }, []);
16
- return (_jsxs(InterchainWalletContext.Provider, { value: store.current, children: [children, _jsx(ModalRenderer, { walletModal: ProviderWalletModal })] }));
16
+ return (_jsxs(InterchainWalletContext.Provider, { value: store.current, children: [children, ProviderWalletModal && (_jsx(ModalRenderer, { walletModal: ProviderWalletModal }))] }));
17
17
  };
18
18
  export const useInterchainWalletContext = () => {
19
19
  const context = useContext(InterchainWalletContext);
@@ -1,105 +1,129 @@
1
- import { BaseWallet, WalletState, WCWallet } from "@interchain-kit/core";
1
+ import { BaseWallet, clientNotExistError, CosmosWallet, EthereumWallet, MultiChainWallet, WalletState, WCWallet } from "@interchain-kit/core";
2
2
  export class StatefulWallet extends BaseWallet {
3
3
  originalWallet;
4
4
  walletName;
5
- walletState;
6
- walletSet;
7
- walletGet;
8
- set;
9
5
  get;
10
- constructor(wallet, walletSet, walletGet, set, get) {
6
+ constructor(wallet, get) {
11
7
  super(wallet.info);
12
8
  this.originalWallet = wallet;
13
9
  this.walletName = wallet.info.name;
14
- this.walletState = WalletState.Disconnected;
15
- this.errorMessage = "";
16
- this.walletSet = walletSet;
17
- this.walletGet = walletGet;
18
- this.set = set;
19
10
  this.get = get;
20
11
  }
21
- getChainToConnect(chainId) {
22
- const { currentChainName, chains } = this.get();
23
- const lastChainName = currentChainName;
24
- const lastChain = chains.find((chain) => chain.chainName === lastChainName);
25
- return chainId ? this.originalWallet.getChainById(chainId) : lastChain;
12
+ get store() {
13
+ return this.get();
14
+ }
15
+ get walletState() {
16
+ // 獲取此錢包在所有鏈上的狀態
17
+ const states = (this.store.chainWalletState || [])
18
+ .filter(cws => cws.walletName === this.walletName)
19
+ .map(cws => cws.walletState);
20
+ // If any chain is in the connected state, return connected
21
+ if (states.includes(WalletState.Connected)) {
22
+ return WalletState.Connected;
23
+ }
24
+ // 如果有任何一個鏈正在連接中,則返回連接中
25
+ if (states.includes(WalletState.Connecting)) {
26
+ return WalletState.Connecting;
27
+ }
28
+ // 如果所有鏈都是不存在狀態,則返回不存在
29
+ if (states.length > 0 && states.every(state => state === WalletState.NotExist)) {
30
+ return WalletState.NotExist;
31
+ }
32
+ // 如果有任何一個鏈是被拒絕狀態,則返回被拒絕
33
+ if (states.includes(WalletState.Rejected)) {
34
+ return WalletState.Rejected;
35
+ }
36
+ // 預設返回未連接
37
+ return WalletState.Disconnected;
38
+ }
39
+ get errorMessage() {
40
+ // 獲取此錢包在所有鏈上的錯誤訊息
41
+ const errors = (this.store.chainWalletState || [])
42
+ .filter(cws => cws.walletName === this.walletName)
43
+ .map(cws => cws.errorMessage)
44
+ .filter(error => error && error.trim() !== '');
45
+ // 返回第一個非空錯誤訊息,如果沒有則返回空字串
46
+ return errors.length > 0 ? errors[0] : '';
26
47
  }
27
48
  async init() {
28
- return this.originalWallet.init();
49
+ try {
50
+ await this.originalWallet.init();
51
+ this.store.chains.forEach(chain => {
52
+ const lastChainWalletState = this.store.getChainWalletState(this.walletName, chain.chainName)?.walletState;
53
+ if (lastChainWalletState === WalletState.NotExist) {
54
+ this.store.updateChainWalletState(this.walletName, chain.chainName, {
55
+ walletState: WalletState.Disconnected,
56
+ errorMessage: ''
57
+ });
58
+ }
59
+ });
60
+ }
61
+ catch (error) {
62
+ if (error === clientNotExistError) {
63
+ this.store.chains.forEach(chain => {
64
+ this.store.updateChainWalletState(this.walletName, chain.chainName, {
65
+ walletState: WalletState.NotExist,
66
+ errorMessage: clientNotExistError.message
67
+ });
68
+ });
69
+ }
70
+ }
29
71
  }
30
72
  async connect(chainId) {
31
- const { get, set, walletName, walletGet, walletSet, originalWallet } = this;
32
- const chainToConnect = this.getChainToConnect(chainId);
33
- const state = get().getChainWalletState(walletName, chainToConnect.chainName)?.walletState;
73
+ const { store, walletName, originalWallet } = this;
74
+ const chainToConnect = this.getChainById(chainId);
75
+ const state = store.getChainWalletState(walletName, chainToConnect.chainName)?.walletState;
34
76
  if (state === WalletState.NotExist) {
35
77
  return;
36
78
  }
37
79
  if (walletName === 'WalletConnect' && state === WalletState.Connected) {
38
80
  return;
39
81
  }
40
- set(draft => {
41
- draft.currentChainName = chainToConnect.chainName;
42
- draft.currentWalletName = walletName;
43
- draft.walletConnectQRCodeUri = '';
44
- });
45
- walletSet(draft => {
46
- draft.walletState = WalletState.Connecting;
47
- draft.errorMessage = '';
48
- });
49
- get().updateChainWalletState(walletName, chainToConnect.chainName, { walletState: WalletState.Connecting, errorMessage: '' });
82
+ store.setCurrentChainName(chainToConnect.chainName);
83
+ store.setCurrentWalletName(walletName);
84
+ store.setWalletConnectQRCodeUri('');
85
+ store.updateChainWalletState(walletName, chainToConnect.chainName, { walletState: WalletState.Connecting, errorMessage: '' });
50
86
  try {
51
87
  if (originalWallet instanceof WCWallet) {
52
88
  originalWallet.setOnPairingUriCreatedCallback((uri) => {
53
- set(draft => {
54
- draft.walletConnectQRCodeUri = uri;
55
- });
89
+ store.setWalletConnectQRCodeUri(uri);
56
90
  });
57
91
  }
58
92
  await originalWallet.connect(chainToConnect.chainId);
59
- get().updateChainWalletState(walletName, chainToConnect.chainName, { walletState: WalletState.Connected });
60
- walletSet(draft => {
61
- draft.walletState = WalletState.Connected;
62
- });
63
- await walletGet().getAccount(chainToConnect.chainId);
93
+ store.updateChainWalletState(walletName, chainToConnect.chainName, { walletState: WalletState.Connected });
94
+ await this.getAccount(chainToConnect.chainId);
64
95
  }
65
96
  catch (error) {
66
- if (error.message === 'Request rejected') {
67
- get().updateChainWalletState(walletName, chainToConnect.chainName, { walletState: WalletState.Rejected, errorMessage: error.message });
68
- walletSet(draft => {
69
- draft.walletState = WalletState.Rejected;
70
- draft.errorMessage = error.message;
71
- });
97
+ if (error.message.includes('rejected')) {
98
+ store.updateChainWalletState(walletName, chainToConnect.chainName, { walletState: WalletState.Rejected, errorMessage: error.message });
72
99
  return;
73
100
  }
74
- get().updateChainWalletState(walletName, chainToConnect.chainName, { walletState: WalletState.Disconnected, errorMessage: error.message });
75
- walletSet(draft => {
76
- draft.walletState = WalletState.Disconnected;
77
- draft.errorMessage = error.message;
78
- });
101
+ else {
102
+ store.updateChainWalletState(walletName, chainToConnect.chainName, { walletState: WalletState.Disconnected, errorMessage: error.message });
103
+ }
79
104
  }
80
105
  }
81
106
  async disconnect(chainId) {
82
- const { get, walletName, walletSet, originalWallet } = this;
83
- const chainToConnect = this.getChainToConnect(chainId);
107
+ const { store, walletName, originalWallet } = this;
108
+ const chainToConnect = this.getChainById(chainId);
84
109
  try {
85
- if (this.walletGet().walletState === WalletState.Connected) {
110
+ if (this.walletState === WalletState.Connected) {
86
111
  await originalWallet.disconnect(chainToConnect.chainId);
87
112
  }
88
- get().updateChainWalletState(walletName, chainToConnect.chainName, { walletState: WalletState.Disconnected, account: null });
89
- walletSet(draft => {
90
- draft.walletState = WalletState.Disconnected;
91
- draft.errorMessage = "";
92
- });
113
+ store.updateChainWalletState(walletName, chainToConnect.chainName, { walletState: WalletState.Disconnected, account: null });
93
114
  }
94
115
  catch (error) {
95
116
  }
96
117
  }
97
118
  async getAccount(chainId) {
98
- const chainToConnect = this.getChainToConnect(chainId);
99
- const { get, walletName, originalWallet } = this;
119
+ const chainToConnect = this.getChainById(chainId);
120
+ const { store, walletName, originalWallet } = this;
100
121
  try {
101
122
  const account = await originalWallet.getAccount(chainToConnect.chainId);
102
- get().updateChainWalletState(walletName, chainToConnect.chainName, { account });
123
+ store.updateChainWalletState(walletName, chainToConnect.chainName, { account });
124
+ if (this.originalWallet instanceof WCWallet) {
125
+ this.originalWallet.setAccountToRestore(account);
126
+ }
103
127
  return account;
104
128
  }
105
129
  catch (error) {
@@ -118,4 +142,24 @@ export class StatefulWallet extends BaseWallet {
118
142
  getChainById(chainId) {
119
143
  return this.originalWallet.getChainById(chainId);
120
144
  }
145
+ getWalletOfType(WalletClass) {
146
+ if (this.originalWallet instanceof WalletClass) {
147
+ return this.originalWallet;
148
+ }
149
+ if (this.originalWallet instanceof MultiChainWallet) {
150
+ if (WalletClass === CosmosWallet) {
151
+ const cosmosWallet = this.originalWallet.getWalletByChainType('cosmos');
152
+ if (cosmosWallet) {
153
+ return cosmosWallet;
154
+ }
155
+ }
156
+ if (WalletClass === EthereumWallet) {
157
+ const ethereumWallet = this.originalWallet.getWalletByChainType('eip155');
158
+ if (ethereumWallet) {
159
+ return ethereumWallet;
160
+ }
161
+ }
162
+ }
163
+ return undefined;
164
+ }
121
165
  }
@@ -1,11 +1,9 @@
1
- import { SigningClient } from '@interchainjs/cosmos/signing-client';
2
- import { clientNotExistError, WalletState } from "@interchain-kit/core";
1
+ import { WalletState } from "@interchain-kit/core";
3
2
  import { createStore } from "zustand";
4
3
  import { immer } from "zustand/middleware/immer";
5
4
  import { persist, createJSONStorage } from 'zustand/middleware';
6
- import { dedupeAsync } from '../utils';
5
+ import { dedupeAsync, restoreAccountFromLocalStorage } from '../utils';
7
6
  import { StatefulWallet } from './stateful-wallet';
8
- import { AminoGenericOfflineSigner, DirectGenericOfflineSigner } from '@interchainjs/cosmos/types/wallet';
9
7
  const immerSyncUp = (newWalletManager) => {
10
8
  return (draft) => {
11
9
  draft.chains = newWalletManager.chains;
@@ -25,12 +23,7 @@ export const createInterchainStore = (walletManager) => {
25
23
  currentChainName: '',
26
24
  chains: [...walletManager.chains],
27
25
  assetLists: [...walletManager.assetLists],
28
- wallets: walletManager.wallets.map(wallet => {
29
- const walletSet = (fn) => {
30
- set((draft) => fn(draft.wallets.find(w => w.info.name === wallet.info.name)));
31
- };
32
- return new StatefulWallet(wallet, walletSet, () => get().wallets.find(w => w.info.name === wallet.info.name), set, get);
33
- }),
26
+ wallets: walletManager.wallets.map(wallet => new StatefulWallet(wallet, get)),
34
27
  signerOptions: walletManager.signerOptions,
35
28
  endpointOptions: walletManager.endpointOptions,
36
29
  preferredSignTypeMap: { ...walletManager.preferredSignTypeMap },
@@ -56,28 +49,6 @@ export const createInterchainStore = (walletManager) => {
56
49
  draft.chainWalletState[targetIndex] = { ...draft.chainWalletState[targetIndex], ...data };
57
50
  });
58
51
  },
59
- createStatefulWallet: () => {
60
- const wallets = walletManager.wallets.map(wallet => {
61
- const walletSet = (fn) => {
62
- set((draft) => fn(draft.wallets.find(w => w.info.name === wallet.info.name)));
63
- };
64
- return new StatefulWallet(wallet, walletSet, () => get().wallets.find(w => w.info.name === wallet.info.name), set, get);
65
- });
66
- set(draft => {
67
- draft.wallets = wallets;
68
- });
69
- const defaultWalletStates = get().chainWalletState.reduce((acc, cws) => {
70
- if (acc[cws.walletName] && cws.walletState === WalletState.Connected) {
71
- return acc;
72
- }
73
- return { ...acc, [cws.walletName]: cws.walletState };
74
- }, {});
75
- set(draft => {
76
- draft.wallets.forEach(wallet => {
77
- wallet.walletState = defaultWalletStates[wallet.info.name];
78
- });
79
- });
80
- },
81
52
  init: async () => {
82
53
  const oldChainWalletStatesMap = new Map(get().chainWalletState.map(cws => [cws.walletName + cws.chainName, cws]));
83
54
  // get().createStatefulWallet()
@@ -104,42 +75,8 @@ export const createInterchainStore = (walletManager) => {
104
75
  });
105
76
  });
106
77
  });
107
- const NotExistWallets = [];
108
- const ExistWallets = [];
109
- await Promise.all(get().wallets.map(async (wallet) => {
110
- try {
111
- await wallet.init();
112
- ExistWallets.push(wallet.info.name);
113
- }
114
- catch (error) {
115
- if (error === clientNotExistError) {
116
- NotExistWallets.push(wallet.info.name);
117
- }
118
- }
119
- }));
78
+ await Promise.all(get().wallets.map(async (wallet) => wallet.init()));
120
79
  set(draft => {
121
- draft.chainWalletState = draft.chainWalletState.map(cws => {
122
- if (NotExistWallets.includes(cws.walletName)) {
123
- return { ...cws, walletState: WalletState.NotExist };
124
- }
125
- return cws;
126
- });
127
- draft.chainWalletState = draft.chainWalletState.map(cws => {
128
- if (ExistWallets.includes(cws.walletName)) {
129
- const newState = cws.walletState === WalletState.NotExist ? WalletState.Disconnected : cws.walletState;
130
- return { ...cws, walletState: newState };
131
- }
132
- return cws;
133
- });
134
- draft.chainWalletState.forEach(cws => {
135
- const lastExistWallet = draft.wallets.find(w => w.info.name === cws.walletName);
136
- if (cws.walletState === WalletState.Connected && lastExistWallet.walletState !== WalletState.Connected) {
137
- lastExistWallet.walletState = WalletState.Connected;
138
- }
139
- if (cws.walletState === WalletState.NotExist) {
140
- lastExistWallet.walletState = WalletState.NotExist;
141
- }
142
- });
143
80
  draft.isReady = true;
144
81
  });
145
82
  },
@@ -149,6 +86,9 @@ export const createInterchainStore = (walletManager) => {
149
86
  setCurrentWalletName: (walletName) => {
150
87
  set(draft => { draft.currentWalletName = walletName; });
151
88
  },
89
+ setWalletConnectQRCodeUri: (uri) => {
90
+ set(draft => { draft.walletConnectQRCodeUri = uri; });
91
+ },
152
92
  getDraftChainWalletState: (state, walletName, chainName) => {
153
93
  const targetIndex = state.chainWalletState.findIndex(cws => cws.walletName === walletName && cws.chainName === chainName);
154
94
  return state.chainWalletState[targetIndex];
@@ -237,10 +177,6 @@ export const createInterchainStore = (walletManager) => {
237
177
  }
238
178
  const existedAccount = get().chainWalletState.find(cws => cws.walletName === walletName && cws.chainName === chainName)?.account;
239
179
  if (existedAccount) {
240
- if (typeof existedAccount.pubkey === 'object') {
241
- // return from localstorage need to restructure to uinit8Array
242
- return { ...existedAccount, pubkey: Uint8Array.from({ ...existedAccount.pubkey, length: Object.keys(existedAccount.pubkey).length }) };
243
- }
244
180
  return existedAccount;
245
181
  }
246
182
  return wallet.getAccount(chain.chainId);
@@ -267,29 +203,7 @@ export const createInterchainStore = (walletManager) => {
267
203
  return walletManager.getDownloadLink(walletName);
268
204
  },
269
205
  async getOfflineSigner(walletName, chainName) {
270
- const chain = get().chains.find(c => c.chainName === chainName);
271
- const wallet = get().getStatefulWalletByName(walletName);
272
- const walletToUse = wallet.originalWallet;
273
- console.log(await get().getAccount(walletName, chainName));
274
- const preferSignType = get().getPreferSignType(chainName);
275
- let offlineSigner;
276
- if (preferSignType === 'amino') {
277
- offlineSigner = new AminoGenericOfflineSigner({
278
- getAccounts: async () => [await get().getAccount(walletName, chainName)],
279
- signAmino(signerAddress, signDoc) {
280
- return walletToUse.signAmino(chain.chainId, signerAddress, signDoc, walletToUse.defaultSignOptions);
281
- },
282
- });
283
- }
284
- else if (preferSignType === 'direct') {
285
- offlineSigner = new DirectGenericOfflineSigner({
286
- getAccounts: async () => [await get().getAccount(walletName, chainName)],
287
- signDirect(signerAddress, signDoc) {
288
- return walletToUse.signDirect(chain.chainId, signerAddress, signDoc, walletToUse.defaultSignOptions);
289
- }
290
- });
291
- }
292
- return offlineSigner;
206
+ return walletManager.getOfflineSigner(walletName, chainName);
293
207
  },
294
208
  getPreferSignType(chainName) {
295
209
  const result = walletManager.getPreferSignType(chainName);
@@ -308,11 +222,7 @@ export const createInterchainStore = (walletManager) => {
308
222
  return get().wallets.find(w => w.info.name === walletName);
309
223
  },
310
224
  async getSigningClient(walletName, chainName) {
311
- const chainWalletState = get().getChainWalletState(walletName, chainName);
312
- const signerOptions = await get().getSignerOptions(chainName);
313
- const offlineSigner = await get().getOfflineSigner(walletName, chainName);
314
- const signingClient = await SigningClient.connectWithSigner(chainWalletState.rpcEndpoint, offlineSigner, signerOptions);
315
- return signingClient;
225
+ return walletManager.getSigningClient(walletName, chainName);
316
226
  },
317
227
  getEnv() {
318
228
  return walletManager.getEnv();
@@ -339,6 +249,12 @@ export const createInterchainStore = (walletManager) => {
339
249
  }
340
250
  else {
341
251
  // console.log('interchain-kit store hydration finished')
252
+ state.chainWalletState = state.chainWalletState.map(cws => {
253
+ return {
254
+ ...cws,
255
+ account: cws.account ? restoreAccountFromLocalStorage(cws.account) : null
256
+ };
257
+ });
342
258
  }
343
259
  };
344
260
  },
@@ -1,2 +1,3 @@
1
1
  export * from './wallet';
2
2
  export * from './dedupeAsync';
3
+ export * from './restoreAccount';
@@ -0,0 +1,8 @@
1
+ export const restoreAccountFromLocalStorage = (walletAccount) => {
2
+ const pubkey = walletAccount.pubkey;
3
+ if (typeof pubkey === 'object') {
4
+ // return from localstorage need to restructure to uinit8Array
5
+ return { ...walletAccount, pubkey: Uint8Array.from({ ...pubkey, length: Object.keys(pubkey).length }) };
6
+ }
7
+ return walletAccount;
8
+ };
package/modal/modal.d.ts CHANGED
@@ -1,8 +1,23 @@
1
1
  import { ReactElement } from "react";
2
2
  import { DownloadInfo } from "@interchain-kit/core";
3
- import { Wallet as InterchainUIWalletType } from "@interchain-ui/react";
3
+ import { Wallet as InterchainUIWalletType, ThemeProviderProps } from "@interchain-ui/react";
4
4
  import { StatefulWallet } from "../store/stateful-wallet";
5
+ export type WalletModalProps = {
6
+ isOpen: boolean;
7
+ wallets: StatefulWallet[];
8
+ currentWallet?: StatefulWallet;
9
+ open: () => void;
10
+ close: () => void;
11
+ };
5
12
  export type InterchainWalletModalProps = {
13
+ modalContainerClassName?: string;
14
+ modalContentClassName?: string;
15
+ modalChildrenClassName?: string;
16
+ modalContentStyles?: React.CSSProperties;
17
+ modalThemeProviderProps?: ThemeProviderProps;
18
+ };
19
+ export declare const InterchainWalletModal: ({ modalContainerClassName, modalContentClassName, modalChildrenClassName, modalContentStyles, modalThemeProviderProps, }: InterchainWalletModalProps) => import("react/jsx-runtime").JSX.Element;
20
+ export type WalletModalElementProps = {
6
21
  shouldShowList: boolean;
7
22
  isOpen: boolean;
8
23
  walletConnectQRCodeUri: string | null;
@@ -28,16 +43,13 @@ export type InterchainWalletModalProps = {
28
43
  device?: string;
29
44
  os?: string;
30
45
  };
46
+ modalThemeProviderProps?: ThemeProviderProps;
47
+ modalContainerClassName?: string;
48
+ modalContentClassName?: string;
49
+ modalChildrenClassName?: string;
50
+ modalContentStyles?: React.CSSProperties;
31
51
  };
32
- export type WalletModalProps = {
33
- isOpen: boolean;
34
- wallets: StatefulWallet[];
35
- currentWallet?: StatefulWallet;
36
- open: () => void;
37
- close: () => void;
38
- };
39
- export declare const InterchainWalletModal: () => import("react/jsx-runtime").JSX.Element;
40
- export declare const WalletModal: ({ shouldShowList, isOpen, walletConnectQRCodeUri, wallets, username, address, currentWallet, isConnecting, isConnected, isRejected, isDisconnected, isNotExist, errorMessage, open, close, disconnect, onSelectWallet, onBack, onReconnect, getDownloadLink, getEnv, }: InterchainWalletModalProps) => import("react/jsx-runtime").JSX.Element;
52
+ export declare const WalletModalElement: ({ shouldShowList, isOpen, walletConnectQRCodeUri, wallets, username, address, currentWallet, isConnecting, isConnected, isRejected, isDisconnected, isNotExist, errorMessage, open, close, disconnect, onSelectWallet, onBack, onReconnect, getDownloadLink, getEnv, modalThemeProviderProps, modalContainerClassName, modalContentClassName, modalChildrenClassName, modalContentStyles, }: WalletModalElementProps) => import("react/jsx-runtime").JSX.Element;
41
53
  export declare const ModalRenderer: ({ walletModal: ProvidedWalletModal, }: {
42
54
  walletModal: (props: WalletModalProps) => ReactElement;
43
55
  }) => import("react/jsx-runtime").JSX.Element;
package/modal/modal.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ModalRenderer = exports.WalletModal = exports.InterchainWalletModal = void 0;
3
+ exports.ModalRenderer = exports.WalletModalElement = exports.InterchainWalletModal = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const views_1 = require("./views");
6
6
  const react_1 = require("react");
@@ -8,21 +8,23 @@ const core_1 = require("@interchain-kit/core");
8
8
  const react_2 = require("@interchain-ui/react");
9
9
  const hooks_1 = require("../hooks");
10
10
  const utils_1 = require("../utils");
11
- const InterchainWalletModal = () => {
11
+ const InterchainWalletModal = ({
12
+ // ==== Custom modal styles
13
+ modalContainerClassName, modalContentClassName, modalChildrenClassName, modalContentStyles, modalThemeProviderProps, }) => {
12
14
  const [shouldShowList, setShouldShowList] = (0, react_1.useState)(false);
13
15
  const { modalIsOpen: isOpen, walletConnectQRCodeUri, wallets: statefulWallets, getChainWalletState, currentWalletName, currentChainName, openModal: open, closeModal: close, chains, setCurrentWalletName, getDownloadLink, getEnv, } = (0, hooks_1.useWalletManager)();
14
- const [selectedWallet, setSelectedWallet] = (0, react_1.useState)(null);
16
+ const [walletToConnect, setWalletToConnect] = (0, react_1.useState)(null);
15
17
  const walletsForUI = statefulWallets.map((w) => (0, utils_1.transferToWalletUISchema)(w));
16
18
  const chainNameToConnect = currentChainName || chains[0].chainName;
17
19
  const chainToConnect = chains.find((chain) => chain.chainName === chainNameToConnect);
18
20
  const currentWallet = statefulWallets.find((w) => w.info.name === currentWalletName);
19
- const walletToShow = selectedWallet || currentWallet;
20
- const { account, errorMessage } = getChainWalletState(selectedWallet?.info?.name || currentWalletName, currentChainName) || {};
21
+ const walletToShow = walletToConnect || currentWallet;
22
+ const { account, errorMessage } = getChainWalletState(walletToConnect?.info?.name || currentWalletName, currentChainName) || {};
21
23
  const disconnect = () => {
22
24
  walletToShow.disconnect(chainToConnect.chainId);
23
25
  };
24
26
  const onSelectWallet = (wallet) => {
25
- setSelectedWallet(wallet);
27
+ setWalletToConnect(wallet);
26
28
  setShouldShowList(false);
27
29
  return wallet.connect(chainToConnect.chainId);
28
30
  };
@@ -34,10 +36,10 @@ const InterchainWalletModal = () => {
34
36
  const onReconnect = () => {
35
37
  currentWallet.connect(chainToConnect.chainId);
36
38
  };
37
- return ((0, jsx_runtime_1.jsx)(exports.WalletModal, { shouldShowList: shouldShowList, username: account?.username, address: account?.address, disconnect: disconnect, isOpen: isOpen, open: open, close: handleCloseModal, wallets: walletsForUI, walletConnectQRCodeUri: walletConnectQRCodeUri, currentWallet: walletToShow, isConnecting: walletToShow?.walletState === core_1.WalletState.Connecting, isConnected: walletToShow?.walletState === core_1.WalletState.Connected, isRejected: walletToShow?.walletState === core_1.WalletState.Rejected, isDisconnected: walletToShow?.walletState === core_1.WalletState.Disconnected, isNotExist: walletToShow?.walletState === core_1.WalletState.NotExist, errorMessage: errorMessage, onSelectWallet: (w) => onSelectWallet(w), onBack: () => setShouldShowList(true), onReconnect: () => onSelectWallet(walletToShow), getDownloadLink: () => getDownloadLink(walletToShow?.info.name), getEnv: getEnv }));
39
+ return ((0, jsx_runtime_1.jsx)(react_2.ThemeProvider, { ...modalThemeProviderProps, children: (0, jsx_runtime_1.jsx)(exports.WalletModalElement, { shouldShowList: shouldShowList, username: account?.username, address: account?.address, disconnect: disconnect, isOpen: isOpen, open: open, close: handleCloseModal, wallets: walletsForUI, walletConnectQRCodeUri: walletConnectQRCodeUri, currentWallet: walletToShow, isConnecting: walletToShow?.walletState === core_1.WalletState.Connecting, isConnected: walletToShow?.walletState === core_1.WalletState.Connected, isRejected: walletToShow?.walletState === core_1.WalletState.Rejected, isDisconnected: walletToShow?.walletState === core_1.WalletState.Disconnected, isNotExist: walletToShow?.walletState === core_1.WalletState.NotExist, errorMessage: errorMessage, onSelectWallet: (w) => onSelectWallet(w), onBack: () => setShouldShowList(true), onReconnect: () => onSelectWallet(walletToShow), getDownloadLink: () => getDownloadLink(walletToShow?.info.name), getEnv: getEnv, modalContainerClassName: modalContainerClassName, modalContentClassName: modalContentClassName, modalChildrenClassName: modalChildrenClassName, modalContentStyles: modalContentStyles, modalThemeProviderProps: modalThemeProviderProps }) }));
38
40
  };
39
41
  exports.InterchainWalletModal = InterchainWalletModal;
40
- const WalletModal = ({ shouldShowList, isOpen, walletConnectQRCodeUri, wallets, username, address, currentWallet, isConnecting, isConnected, isRejected, isDisconnected, isNotExist, errorMessage, open, close, disconnect, onSelectWallet, onBack, onReconnect, getDownloadLink, getEnv, }) => {
42
+ const WalletModalElement = ({ shouldShowList, isOpen, walletConnectQRCodeUri, wallets, username, address, currentWallet, isConnecting, isConnected, isRejected, isDisconnected, isNotExist, errorMessage, open, close, disconnect, onSelectWallet, onBack, onReconnect, getDownloadLink, getEnv, modalThemeProviderProps, modalContainerClassName, modalContentClassName, modalChildrenClassName, modalContentStyles, }) => {
41
43
  const { header, content } = (0, react_1.useMemo)(() => {
42
44
  if (shouldShowList ||
43
45
  (isDisconnected && currentWallet.errorMessage === "")) {
@@ -98,13 +100,12 @@ const WalletModal = ({ shouldShowList, isOpen, walletConnectQRCodeUri, wallets,
98
100
  wallets,
99
101
  isOpen,
100
102
  ]);
101
- return ((0, jsx_runtime_1.jsx)(react_2.ConnectModal, { isOpen: isOpen, header: header, onOpen: open, onClose: close, children: content }));
103
+ return ((0, jsx_runtime_1.jsx)(react_2.ConnectModal, { isOpen: isOpen, header: header, onOpen: open, onClose: close, modalContainerClassName: modalContainerClassName, modalContentClassName: modalContentClassName, modalChildrenClassName: modalChildrenClassName, modalContentStyles: modalContentStyles, children: content }));
102
104
  };
103
- exports.WalletModal = WalletModal;
105
+ exports.WalletModalElement = WalletModalElement;
104
106
  const ModalRenderer = ({ walletModal: ProvidedWalletModal, }) => {
105
107
  if (!ProvidedWalletModal) {
106
- throw new Error(`InterchainWalletProvider: walletModal is required. Please provide a wallet modal component. or use InterchainkitWalletModal/n
107
- Example: <ChainProvider chains={chains} assetLists={assetLists} wallets={wallets} walletModal={InterchainKitWalletModal} />`);
108
+ return null;
108
109
  }
109
110
  const { modalIsOpen, openModal, closeModal, wallets, currentWalletName } = (0, hooks_1.useWalletManager)();
110
111
  return ((0, jsx_runtime_1.jsx)(ProvidedWalletModal, { wallets: wallets, isOpen: modalIsOpen, open: openModal, close: closeModal, currentWallet: wallets.find((w) => w.info.name === currentWalletName) }));
@@ -1,11 +1,12 @@
1
- import { BaseWallet, DownloadInfo } from "@interchain-kit/core";
1
+ import { DownloadInfo } from "@interchain-kit/core";
2
+ import { StatefulWallet } from "../../store/stateful-wallet";
2
3
  export declare const NotExistHeader: ({ wallet, close, onBack, }: {
3
- wallet: BaseWallet;
4
+ wallet: StatefulWallet;
4
5
  close: () => void;
5
6
  onBack: () => void;
6
7
  }) => import("react/jsx-runtime").JSX.Element;
7
8
  export declare const NotExistContent: ({ wallet, getDownloadLink, getEnv, }: {
8
- wallet: BaseWallet;
9
+ wallet: StatefulWallet;
9
10
  getDownloadLink: (walletName: string) => DownloadInfo;
10
11
  getEnv: () => {
11
12
  browser?: string;
@@ -1,10 +1,10 @@
1
- import { BaseWallet } from "@interchain-kit/core";
1
+ import { StatefulWallet } from "../../store/stateful-wallet";
2
2
  export declare const RejectHeader: ({ wallet, close, onBack, }: {
3
- wallet: BaseWallet;
3
+ wallet: StatefulWallet;
4
4
  close: () => void;
5
5
  onBack: () => void;
6
6
  }) => import("react/jsx-runtime").JSX.Element;
7
7
  export declare const RejectContent: ({ wallet, onReconnect, }: {
8
- wallet: BaseWallet;
8
+ wallet: StatefulWallet;
9
9
  onReconnect: () => void;
10
10
  }) => import("react/jsx-runtime").JSX.Element;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@interchain-kit/react",
3
- "version": "0.3.31",
3
+ "version": "0.3.34",
4
4
  "author": "Hyperweb <developers@hyperweb.io>",
5
5
  "description": "interchain-kit wallet connector react package",
6
6
  "main": "index.js",
@@ -34,7 +34,7 @@
34
34
  "keywords": [],
35
35
  "dependencies": {
36
36
  "@chain-registry/v2-types": "^0.53.40",
37
- "@interchain-kit/core": "^0.3.31",
37
+ "@interchain-kit/core": "0.3.34",
38
38
  "@interchain-ui/react": "1.26.1",
39
39
  "@interchainjs/cosmos": "1.11.11",
40
40
  "@interchainjs/cosmos-types": "1.11.11",
@@ -64,5 +64,5 @@
64
64
  "react": "^19.0.0",
65
65
  "react-dom": "^19.0.0"
66
66
  },
67
- "gitHead": "ec8719da721263a2b3f1474aa106ce0da2425bf6"
67
+ "gitHead": "f20fdd36dee935e0abe8e7cddc0de505d987ec50"
68
68
  }
package/provider.d.ts CHANGED
@@ -12,7 +12,7 @@ type InterchainWalletProviderProps = {
12
12
  signerOptions?: SignerOptions;
13
13
  endpointOptions?: EndpointOptions;
14
14
  children: React.ReactNode;
15
- walletModal: (props: WalletModalProps) => ReactElement;
15
+ walletModal?: (props: WalletModalProps) => ReactElement;
16
16
  };
17
17
  export declare const ChainProvider: ({ chains, assetLists, wallets, signerOptions, endpointOptions, children, walletModal: ProviderWalletModal, }: InterchainWalletProviderProps) => import("react/jsx-runtime").JSX.Element;
18
18
  export declare const useInterchainWalletContext: () => InterchainWalletContextType;
package/provider.js CHANGED
@@ -16,7 +16,7 @@ const ChainProvider = ({ chains, assetLists, wallets, signerOptions, endpointOpt
16
16
  // walletManager.init();
17
17
  store.current.getState().init();
18
18
  }, []);
19
- return ((0, jsx_runtime_1.jsxs)(InterchainWalletContext.Provider, { value: store.current, children: [children, (0, jsx_runtime_1.jsx)(modal_1.ModalRenderer, { walletModal: ProviderWalletModal })] }));
19
+ return ((0, jsx_runtime_1.jsxs)(InterchainWalletContext.Provider, { value: store.current, children: [children, ProviderWalletModal && ((0, jsx_runtime_1.jsx)(modal_1.ModalRenderer, { walletModal: ProviderWalletModal }))] }));
20
20
  };
21
21
  exports.ChainProvider = ChainProvider;
22
22
  const useInterchainWalletContext = () => {
@@ -4,13 +4,11 @@ import { Chain } from "@chain-registry/v2-types";
4
4
  export declare class StatefulWallet extends BaseWallet {
5
5
  originalWallet: BaseWallet;
6
6
  walletName: string;
7
- walletState: WalletState;
8
- walletSet: (arg: (draft: StatefulWallet) => void) => void;
9
- walletGet: () => StatefulWallet;
10
- set: (arg: (draft: InterchainStore) => void) => void;
11
7
  get: () => InterchainStore;
12
- constructor(wallet: BaseWallet, walletSet: (arg: (draft: StatefulWallet) => void) => void, walletGet: () => StatefulWallet, set: (arg: (draft: InterchainStore) => void) => void, get: () => InterchainStore);
13
- getChainToConnect(chainId?: Chain["chainId"]): Chain;
8
+ constructor(wallet: BaseWallet, get: () => InterchainStore);
9
+ get store(): InterchainStore;
10
+ get walletState(): WalletState;
11
+ get errorMessage(): string;
14
12
  init(): Promise<void>;
15
13
  connect(chainId: Chain["chainId"]): Promise<void>;
16
14
  disconnect(chainId: Chain["chainId"]): Promise<void>;
@@ -19,4 +17,5 @@ export declare class StatefulWallet extends BaseWallet {
19
17
  addSuggestChain(chainId: Chain["chainId"]): Promise<void>;
20
18
  getProvider(chainId?: Chain["chainId"]): Promise<any>;
21
19
  getChainById(chainId: Chain["chainId"]): Chain;
20
+ getWalletOfType<T>(WalletClass: new (...args: any[]) => T): T | undefined;
22
21
  }
@@ -5,104 +5,128 @@ const core_1 = require("@interchain-kit/core");
5
5
  class StatefulWallet extends core_1.BaseWallet {
6
6
  originalWallet;
7
7
  walletName;
8
- walletState;
9
- walletSet;
10
- walletGet;
11
- set;
12
8
  get;
13
- constructor(wallet, walletSet, walletGet, set, get) {
9
+ constructor(wallet, get) {
14
10
  super(wallet.info);
15
11
  this.originalWallet = wallet;
16
12
  this.walletName = wallet.info.name;
17
- this.walletState = core_1.WalletState.Disconnected;
18
- this.errorMessage = "";
19
- this.walletSet = walletSet;
20
- this.walletGet = walletGet;
21
- this.set = set;
22
13
  this.get = get;
23
14
  }
24
- getChainToConnect(chainId) {
25
- const { currentChainName, chains } = this.get();
26
- const lastChainName = currentChainName;
27
- const lastChain = chains.find((chain) => chain.chainName === lastChainName);
28
- return chainId ? this.originalWallet.getChainById(chainId) : lastChain;
15
+ get store() {
16
+ return this.get();
17
+ }
18
+ get walletState() {
19
+ // 獲取此錢包在所有鏈上的狀態
20
+ const states = (this.store.chainWalletState || [])
21
+ .filter(cws => cws.walletName === this.walletName)
22
+ .map(cws => cws.walletState);
23
+ // If any chain is in the connected state, return connected
24
+ if (states.includes(core_1.WalletState.Connected)) {
25
+ return core_1.WalletState.Connected;
26
+ }
27
+ // 如果有任何一個鏈正在連接中,則返回連接中
28
+ if (states.includes(core_1.WalletState.Connecting)) {
29
+ return core_1.WalletState.Connecting;
30
+ }
31
+ // 如果所有鏈都是不存在狀態,則返回不存在
32
+ if (states.length > 0 && states.every(state => state === core_1.WalletState.NotExist)) {
33
+ return core_1.WalletState.NotExist;
34
+ }
35
+ // 如果有任何一個鏈是被拒絕狀態,則返回被拒絕
36
+ if (states.includes(core_1.WalletState.Rejected)) {
37
+ return core_1.WalletState.Rejected;
38
+ }
39
+ // 預設返回未連接
40
+ return core_1.WalletState.Disconnected;
41
+ }
42
+ get errorMessage() {
43
+ // 獲取此錢包在所有鏈上的錯誤訊息
44
+ const errors = (this.store.chainWalletState || [])
45
+ .filter(cws => cws.walletName === this.walletName)
46
+ .map(cws => cws.errorMessage)
47
+ .filter(error => error && error.trim() !== '');
48
+ // 返回第一個非空錯誤訊息,如果沒有則返回空字串
49
+ return errors.length > 0 ? errors[0] : '';
29
50
  }
30
51
  async init() {
31
- return this.originalWallet.init();
52
+ try {
53
+ await this.originalWallet.init();
54
+ this.store.chains.forEach(chain => {
55
+ const lastChainWalletState = this.store.getChainWalletState(this.walletName, chain.chainName)?.walletState;
56
+ if (lastChainWalletState === core_1.WalletState.NotExist) {
57
+ this.store.updateChainWalletState(this.walletName, chain.chainName, {
58
+ walletState: core_1.WalletState.Disconnected,
59
+ errorMessage: ''
60
+ });
61
+ }
62
+ });
63
+ }
64
+ catch (error) {
65
+ if (error === core_1.clientNotExistError) {
66
+ this.store.chains.forEach(chain => {
67
+ this.store.updateChainWalletState(this.walletName, chain.chainName, {
68
+ walletState: core_1.WalletState.NotExist,
69
+ errorMessage: core_1.clientNotExistError.message
70
+ });
71
+ });
72
+ }
73
+ }
32
74
  }
33
75
  async connect(chainId) {
34
- const { get, set, walletName, walletGet, walletSet, originalWallet } = this;
35
- const chainToConnect = this.getChainToConnect(chainId);
36
- const state = get().getChainWalletState(walletName, chainToConnect.chainName)?.walletState;
76
+ const { store, walletName, originalWallet } = this;
77
+ const chainToConnect = this.getChainById(chainId);
78
+ const state = store.getChainWalletState(walletName, chainToConnect.chainName)?.walletState;
37
79
  if (state === core_1.WalletState.NotExist) {
38
80
  return;
39
81
  }
40
82
  if (walletName === 'WalletConnect' && state === core_1.WalletState.Connected) {
41
83
  return;
42
84
  }
43
- set(draft => {
44
- draft.currentChainName = chainToConnect.chainName;
45
- draft.currentWalletName = walletName;
46
- draft.walletConnectQRCodeUri = '';
47
- });
48
- walletSet(draft => {
49
- draft.walletState = core_1.WalletState.Connecting;
50
- draft.errorMessage = '';
51
- });
52
- get().updateChainWalletState(walletName, chainToConnect.chainName, { walletState: core_1.WalletState.Connecting, errorMessage: '' });
85
+ store.setCurrentChainName(chainToConnect.chainName);
86
+ store.setCurrentWalletName(walletName);
87
+ store.setWalletConnectQRCodeUri('');
88
+ store.updateChainWalletState(walletName, chainToConnect.chainName, { walletState: core_1.WalletState.Connecting, errorMessage: '' });
53
89
  try {
54
90
  if (originalWallet instanceof core_1.WCWallet) {
55
91
  originalWallet.setOnPairingUriCreatedCallback((uri) => {
56
- set(draft => {
57
- draft.walletConnectQRCodeUri = uri;
58
- });
92
+ store.setWalletConnectQRCodeUri(uri);
59
93
  });
60
94
  }
61
95
  await originalWallet.connect(chainToConnect.chainId);
62
- get().updateChainWalletState(walletName, chainToConnect.chainName, { walletState: core_1.WalletState.Connected });
63
- walletSet(draft => {
64
- draft.walletState = core_1.WalletState.Connected;
65
- });
66
- await walletGet().getAccount(chainToConnect.chainId);
96
+ store.updateChainWalletState(walletName, chainToConnect.chainName, { walletState: core_1.WalletState.Connected });
97
+ await this.getAccount(chainToConnect.chainId);
67
98
  }
68
99
  catch (error) {
69
- if (error.message === 'Request rejected') {
70
- get().updateChainWalletState(walletName, chainToConnect.chainName, { walletState: core_1.WalletState.Rejected, errorMessage: error.message });
71
- walletSet(draft => {
72
- draft.walletState = core_1.WalletState.Rejected;
73
- draft.errorMessage = error.message;
74
- });
100
+ if (error.message.includes('rejected')) {
101
+ store.updateChainWalletState(walletName, chainToConnect.chainName, { walletState: core_1.WalletState.Rejected, errorMessage: error.message });
75
102
  return;
76
103
  }
77
- get().updateChainWalletState(walletName, chainToConnect.chainName, { walletState: core_1.WalletState.Disconnected, errorMessage: error.message });
78
- walletSet(draft => {
79
- draft.walletState = core_1.WalletState.Disconnected;
80
- draft.errorMessage = error.message;
81
- });
104
+ else {
105
+ store.updateChainWalletState(walletName, chainToConnect.chainName, { walletState: core_1.WalletState.Disconnected, errorMessage: error.message });
106
+ }
82
107
  }
83
108
  }
84
109
  async disconnect(chainId) {
85
- const { get, walletName, walletSet, originalWallet } = this;
86
- const chainToConnect = this.getChainToConnect(chainId);
110
+ const { store, walletName, originalWallet } = this;
111
+ const chainToConnect = this.getChainById(chainId);
87
112
  try {
88
- if (this.walletGet().walletState === core_1.WalletState.Connected) {
113
+ if (this.walletState === core_1.WalletState.Connected) {
89
114
  await originalWallet.disconnect(chainToConnect.chainId);
90
115
  }
91
- get().updateChainWalletState(walletName, chainToConnect.chainName, { walletState: core_1.WalletState.Disconnected, account: null });
92
- walletSet(draft => {
93
- draft.walletState = core_1.WalletState.Disconnected;
94
- draft.errorMessage = "";
95
- });
116
+ store.updateChainWalletState(walletName, chainToConnect.chainName, { walletState: core_1.WalletState.Disconnected, account: null });
96
117
  }
97
118
  catch (error) {
98
119
  }
99
120
  }
100
121
  async getAccount(chainId) {
101
- const chainToConnect = this.getChainToConnect(chainId);
102
- const { get, walletName, originalWallet } = this;
122
+ const chainToConnect = this.getChainById(chainId);
123
+ const { store, walletName, originalWallet } = this;
103
124
  try {
104
125
  const account = await originalWallet.getAccount(chainToConnect.chainId);
105
- get().updateChainWalletState(walletName, chainToConnect.chainName, { account });
126
+ store.updateChainWalletState(walletName, chainToConnect.chainName, { account });
127
+ if (this.originalWallet instanceof core_1.WCWallet) {
128
+ this.originalWallet.setAccountToRestore(account);
129
+ }
106
130
  return account;
107
131
  }
108
132
  catch (error) {
@@ -121,5 +145,25 @@ class StatefulWallet extends core_1.BaseWallet {
121
145
  getChainById(chainId) {
122
146
  return this.originalWallet.getChainById(chainId);
123
147
  }
148
+ getWalletOfType(WalletClass) {
149
+ if (this.originalWallet instanceof WalletClass) {
150
+ return this.originalWallet;
151
+ }
152
+ if (this.originalWallet instanceof core_1.MultiChainWallet) {
153
+ if (WalletClass === core_1.CosmosWallet) {
154
+ const cosmosWallet = this.originalWallet.getWalletByChainType('cosmos');
155
+ if (cosmosWallet) {
156
+ return cosmosWallet;
157
+ }
158
+ }
159
+ if (WalletClass === core_1.EthereumWallet) {
160
+ const ethereumWallet = this.originalWallet.getWalletByChainType('eip155');
161
+ if (ethereumWallet) {
162
+ return ethereumWallet;
163
+ }
164
+ }
165
+ }
166
+ return undefined;
167
+ }
124
168
  }
125
169
  exports.StatefulWallet = StatefulWallet;
package/store/store.d.ts CHANGED
@@ -25,8 +25,8 @@ export interface InterchainStore extends WalletManager {
25
25
  getDraftChainWalletState: (state: InterchainStore, walletName: string, chainName: string) => ChainWalletState;
26
26
  getChainWalletState: (walletName: string, chainName: string) => ChainWalletState | undefined;
27
27
  updateChainWalletState: (walletName: string, chainName: string, data: Partial<ChainWalletState>) => void;
28
- createStatefulWallet: () => void;
29
28
  getStatefulWalletByName: (walletName: string) => StatefulWallet | undefined;
29
+ setWalletConnectQRCodeUri: (uri: string) => void;
30
30
  }
31
31
  export type InterchainStoreData = {
32
32
  chains: Chain[];
package/store/store.js CHANGED
@@ -1,14 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createInterchainStore = void 0;
4
- const signing_client_1 = require("@interchainjs/cosmos/signing-client");
5
4
  const core_1 = require("@interchain-kit/core");
6
5
  const zustand_1 = require("zustand");
7
6
  const immer_1 = require("zustand/middleware/immer");
8
7
  const middleware_1 = require("zustand/middleware");
9
8
  const utils_1 = require("../utils");
10
9
  const stateful_wallet_1 = require("./stateful-wallet");
11
- const wallet_1 = require("@interchainjs/cosmos/types/wallet");
12
10
  const immerSyncUp = (newWalletManager) => {
13
11
  return (draft) => {
14
12
  draft.chains = newWalletManager.chains;
@@ -28,12 +26,7 @@ const createInterchainStore = (walletManager) => {
28
26
  currentChainName: '',
29
27
  chains: [...walletManager.chains],
30
28
  assetLists: [...walletManager.assetLists],
31
- wallets: walletManager.wallets.map(wallet => {
32
- const walletSet = (fn) => {
33
- set((draft) => fn(draft.wallets.find(w => w.info.name === wallet.info.name)));
34
- };
35
- return new stateful_wallet_1.StatefulWallet(wallet, walletSet, () => get().wallets.find(w => w.info.name === wallet.info.name), set, get);
36
- }),
29
+ wallets: walletManager.wallets.map(wallet => new stateful_wallet_1.StatefulWallet(wallet, get)),
37
30
  signerOptions: walletManager.signerOptions,
38
31
  endpointOptions: walletManager.endpointOptions,
39
32
  preferredSignTypeMap: { ...walletManager.preferredSignTypeMap },
@@ -59,28 +52,6 @@ const createInterchainStore = (walletManager) => {
59
52
  draft.chainWalletState[targetIndex] = { ...draft.chainWalletState[targetIndex], ...data };
60
53
  });
61
54
  },
62
- createStatefulWallet: () => {
63
- const wallets = walletManager.wallets.map(wallet => {
64
- const walletSet = (fn) => {
65
- set((draft) => fn(draft.wallets.find(w => w.info.name === wallet.info.name)));
66
- };
67
- return new stateful_wallet_1.StatefulWallet(wallet, walletSet, () => get().wallets.find(w => w.info.name === wallet.info.name), set, get);
68
- });
69
- set(draft => {
70
- draft.wallets = wallets;
71
- });
72
- const defaultWalletStates = get().chainWalletState.reduce((acc, cws) => {
73
- if (acc[cws.walletName] && cws.walletState === core_1.WalletState.Connected) {
74
- return acc;
75
- }
76
- return { ...acc, [cws.walletName]: cws.walletState };
77
- }, {});
78
- set(draft => {
79
- draft.wallets.forEach(wallet => {
80
- wallet.walletState = defaultWalletStates[wallet.info.name];
81
- });
82
- });
83
- },
84
55
  init: async () => {
85
56
  const oldChainWalletStatesMap = new Map(get().chainWalletState.map(cws => [cws.walletName + cws.chainName, cws]));
86
57
  // get().createStatefulWallet()
@@ -107,42 +78,8 @@ const createInterchainStore = (walletManager) => {
107
78
  });
108
79
  });
109
80
  });
110
- const NotExistWallets = [];
111
- const ExistWallets = [];
112
- await Promise.all(get().wallets.map(async (wallet) => {
113
- try {
114
- await wallet.init();
115
- ExistWallets.push(wallet.info.name);
116
- }
117
- catch (error) {
118
- if (error === core_1.clientNotExistError) {
119
- NotExistWallets.push(wallet.info.name);
120
- }
121
- }
122
- }));
81
+ await Promise.all(get().wallets.map(async (wallet) => wallet.init()));
123
82
  set(draft => {
124
- draft.chainWalletState = draft.chainWalletState.map(cws => {
125
- if (NotExistWallets.includes(cws.walletName)) {
126
- return { ...cws, walletState: core_1.WalletState.NotExist };
127
- }
128
- return cws;
129
- });
130
- draft.chainWalletState = draft.chainWalletState.map(cws => {
131
- if (ExistWallets.includes(cws.walletName)) {
132
- const newState = cws.walletState === core_1.WalletState.NotExist ? core_1.WalletState.Disconnected : cws.walletState;
133
- return { ...cws, walletState: newState };
134
- }
135
- return cws;
136
- });
137
- draft.chainWalletState.forEach(cws => {
138
- const lastExistWallet = draft.wallets.find(w => w.info.name === cws.walletName);
139
- if (cws.walletState === core_1.WalletState.Connected && lastExistWallet.walletState !== core_1.WalletState.Connected) {
140
- lastExistWallet.walletState = core_1.WalletState.Connected;
141
- }
142
- if (cws.walletState === core_1.WalletState.NotExist) {
143
- lastExistWallet.walletState = core_1.WalletState.NotExist;
144
- }
145
- });
146
83
  draft.isReady = true;
147
84
  });
148
85
  },
@@ -152,6 +89,9 @@ const createInterchainStore = (walletManager) => {
152
89
  setCurrentWalletName: (walletName) => {
153
90
  set(draft => { draft.currentWalletName = walletName; });
154
91
  },
92
+ setWalletConnectQRCodeUri: (uri) => {
93
+ set(draft => { draft.walletConnectQRCodeUri = uri; });
94
+ },
155
95
  getDraftChainWalletState: (state, walletName, chainName) => {
156
96
  const targetIndex = state.chainWalletState.findIndex(cws => cws.walletName === walletName && cws.chainName === chainName);
157
97
  return state.chainWalletState[targetIndex];
@@ -240,10 +180,6 @@ const createInterchainStore = (walletManager) => {
240
180
  }
241
181
  const existedAccount = get().chainWalletState.find(cws => cws.walletName === walletName && cws.chainName === chainName)?.account;
242
182
  if (existedAccount) {
243
- if (typeof existedAccount.pubkey === 'object') {
244
- // return from localstorage need to restructure to uinit8Array
245
- return { ...existedAccount, pubkey: Uint8Array.from({ ...existedAccount.pubkey, length: Object.keys(existedAccount.pubkey).length }) };
246
- }
247
183
  return existedAccount;
248
184
  }
249
185
  return wallet.getAccount(chain.chainId);
@@ -270,29 +206,7 @@ const createInterchainStore = (walletManager) => {
270
206
  return walletManager.getDownloadLink(walletName);
271
207
  },
272
208
  async getOfflineSigner(walletName, chainName) {
273
- const chain = get().chains.find(c => c.chainName === chainName);
274
- const wallet = get().getStatefulWalletByName(walletName);
275
- const walletToUse = wallet.originalWallet;
276
- console.log(await get().getAccount(walletName, chainName));
277
- const preferSignType = get().getPreferSignType(chainName);
278
- let offlineSigner;
279
- if (preferSignType === 'amino') {
280
- offlineSigner = new wallet_1.AminoGenericOfflineSigner({
281
- getAccounts: async () => [await get().getAccount(walletName, chainName)],
282
- signAmino(signerAddress, signDoc) {
283
- return walletToUse.signAmino(chain.chainId, signerAddress, signDoc, walletToUse.defaultSignOptions);
284
- },
285
- });
286
- }
287
- else if (preferSignType === 'direct') {
288
- offlineSigner = new wallet_1.DirectGenericOfflineSigner({
289
- getAccounts: async () => [await get().getAccount(walletName, chainName)],
290
- signDirect(signerAddress, signDoc) {
291
- return walletToUse.signDirect(chain.chainId, signerAddress, signDoc, walletToUse.defaultSignOptions);
292
- }
293
- });
294
- }
295
- return offlineSigner;
209
+ return walletManager.getOfflineSigner(walletName, chainName);
296
210
  },
297
211
  getPreferSignType(chainName) {
298
212
  const result = walletManager.getPreferSignType(chainName);
@@ -311,11 +225,7 @@ const createInterchainStore = (walletManager) => {
311
225
  return get().wallets.find(w => w.info.name === walletName);
312
226
  },
313
227
  async getSigningClient(walletName, chainName) {
314
- const chainWalletState = get().getChainWalletState(walletName, chainName);
315
- const signerOptions = await get().getSignerOptions(chainName);
316
- const offlineSigner = await get().getOfflineSigner(walletName, chainName);
317
- const signingClient = await signing_client_1.SigningClient.connectWithSigner(chainWalletState.rpcEndpoint, offlineSigner, signerOptions);
318
- return signingClient;
228
+ return walletManager.getSigningClient(walletName, chainName);
319
229
  },
320
230
  getEnv() {
321
231
  return walletManager.getEnv();
@@ -342,6 +252,12 @@ const createInterchainStore = (walletManager) => {
342
252
  }
343
253
  else {
344
254
  // console.log('interchain-kit store hydration finished')
255
+ state.chainWalletState = state.chainWalletState.map(cws => {
256
+ return {
257
+ ...cws,
258
+ account: cws.account ? (0, utils_1.restoreAccountFromLocalStorage)(cws.account) : null
259
+ };
260
+ });
345
261
  }
346
262
  };
347
263
  },
package/utils/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export * from './wallet';
2
2
  export * from './dedupeAsync';
3
+ export * from './restoreAccount';
package/utils/index.js CHANGED
@@ -16,3 +16,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./wallet"), exports);
18
18
  __exportStar(require("./dedupeAsync"), exports);
19
+ __exportStar(require("./restoreAccount"), exports);
@@ -0,0 +1,2 @@
1
+ import { WalletAccount } from "@interchain-kit/core";
2
+ export declare const restoreAccountFromLocalStorage: (walletAccount: WalletAccount) => WalletAccount;
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.restoreAccountFromLocalStorage = void 0;
4
+ const restoreAccountFromLocalStorage = (walletAccount) => {
5
+ const pubkey = walletAccount.pubkey;
6
+ if (typeof pubkey === 'object') {
7
+ // return from localstorage need to restructure to uinit8Array
8
+ return { ...walletAccount, pubkey: Uint8Array.from({ ...pubkey, length: Object.keys(pubkey).length }) };
9
+ }
10
+ return walletAccount;
11
+ };
12
+ exports.restoreAccountFromLocalStorage = restoreAccountFromLocalStorage;
package/utils/wallet.d.ts CHANGED
@@ -14,7 +14,6 @@ export declare const transferToWalletUISchema: (w: BaseWallet) => {
14
14
  originalWallet: {
15
15
  session: import("@walletconnect/types").SessionTypes.Struct;
16
16
  info: import("@interchain-kit/core").Wallet;
17
- errorMessage: string;
18
17
  events: import("events")<import("@interchain-kit/core").WalletEvents>;
19
18
  chainMap: Map<import("@chain-registry/v2-types").Chain["chainId"], import("@chain-registry/v2-types").Chain>;
20
19
  assetLists: import("@chain-registry/v2-types").AssetList[];
@@ -1,38 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { createContext, useContext, useEffect, useRef, useState } from "react";
3
- import { WalletState } from "@interchain-kit/core";
4
- import { useChainWallet, useWalletManager } from "../hooks";
5
- import { transferToWalletUISchema } from "../utils";
6
- import { InterchainWalletModal } from "./modal";
7
- const WalletModalContext = createContext(null);
8
- export const WalletModalProvider = ({ children, }) => {
9
- const [modalIsOpen, setModalIsOpen] = useState(false);
10
- const open = () => setModalIsOpen(true);
11
- const close = () => setModalIsOpen(false);
12
- const { chains, wallets, setCurrentWalletName, currentChainName, currentWalletName, walletConnectQRCodeUri, getDownloadLink, getEnv, connect, getAccount, } = useWalletManager();
13
- const { wallet, status, disconnect, username, address, message } = useChainWallet(currentChainName || chains[0].chainName, currentWalletName);
14
- const [shouldShowList, setShouldShowList] = useState(!(currentChainName && currentWalletName));
15
- const walletsForUI = wallets.map(transferToWalletUISchema);
16
- const handleCloseModal = () => {
17
- close();
18
- setShouldShowList(false);
19
- };
20
- const currentChainNameRef = useRef("");
21
- useEffect(() => {
22
- currentChainNameRef.current = currentChainName;
23
- }, [currentChainName]);
24
- const handleConnectWallet = async (walletName) => {
25
- const chainToConnect = currentChainNameRef.current || chains[0].chainName;
26
- setShouldShowList(false);
27
- setCurrentWalletName(walletName);
28
- await connect(walletName, chainToConnect);
29
- };
30
- return (_jsxs(WalletModalContext.Provider, { value: { modalIsOpen, open, close }, children: [children, _jsx(InterchainWalletModal, { shouldShowList: shouldShowList, username: username, address: address, disconnect: disconnect, isOpen: modalIsOpen, open: open, close: handleCloseModal, wallets: walletsForUI, walletConnectQRCodeUri: walletConnectQRCodeUri, currentWallet: wallet, isConnecting: status === WalletState.Connecting, isConnected: status === WalletState.Connected, isRejected: status === WalletState.Rejected, isDisconnected: status === WalletState.Disconnected, isNotExist: status === WalletState.NotExist, errorMessage: message, onSelectWallet: (w) => handleConnectWallet(w.info.name), onBack: () => setShouldShowList(true), onReconnect: () => handleConnectWallet(currentWalletName), getDownloadLink: () => getDownloadLink(wallet?.info.name), getEnv: getEnv })] }));
31
- };
32
- export const useWalletModal = () => {
33
- const context = useContext(WalletModalContext);
34
- if (!context) {
35
- throw new Error("useWalletModal must be used within a WalletModalProvider");
36
- }
37
- return context;
38
- };
@@ -1,10 +0,0 @@
1
- type WalletModalContextType = {
2
- modalIsOpen: boolean;
3
- open: () => void;
4
- close: () => void;
5
- };
6
- export declare const WalletModalProvider: ({ children, }: {
7
- children: React.ReactNode;
8
- }) => import("react/jsx-runtime").JSX.Element;
9
- export declare const useWalletModal: () => WalletModalContextType;
10
- export {};
package/modal/provider.js DELETED
@@ -1,43 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useWalletModal = exports.WalletModalProvider = void 0;
4
- const jsx_runtime_1 = require("react/jsx-runtime");
5
- const react_1 = require("react");
6
- const core_1 = require("@interchain-kit/core");
7
- const hooks_1 = require("../hooks");
8
- const utils_1 = require("../utils");
9
- const modal_1 = require("./modal");
10
- const WalletModalContext = (0, react_1.createContext)(null);
11
- const WalletModalProvider = ({ children, }) => {
12
- const [modalIsOpen, setModalIsOpen] = (0, react_1.useState)(false);
13
- const open = () => setModalIsOpen(true);
14
- const close = () => setModalIsOpen(false);
15
- const { chains, wallets, setCurrentWalletName, currentChainName, currentWalletName, walletConnectQRCodeUri, getDownloadLink, getEnv, connect, getAccount, } = (0, hooks_1.useWalletManager)();
16
- const { wallet, status, disconnect, username, address, message } = (0, hooks_1.useChainWallet)(currentChainName || chains[0].chainName, currentWalletName);
17
- const [shouldShowList, setShouldShowList] = (0, react_1.useState)(!(currentChainName && currentWalletName));
18
- const walletsForUI = wallets.map(utils_1.transferToWalletUISchema);
19
- const handleCloseModal = () => {
20
- close();
21
- setShouldShowList(false);
22
- };
23
- const currentChainNameRef = (0, react_1.useRef)("");
24
- (0, react_1.useEffect)(() => {
25
- currentChainNameRef.current = currentChainName;
26
- }, [currentChainName]);
27
- const handleConnectWallet = async (walletName) => {
28
- const chainToConnect = currentChainNameRef.current || chains[0].chainName;
29
- setShouldShowList(false);
30
- setCurrentWalletName(walletName);
31
- await connect(walletName, chainToConnect);
32
- };
33
- return ((0, jsx_runtime_1.jsxs)(WalletModalContext.Provider, { value: { modalIsOpen, open, close }, children: [children, (0, jsx_runtime_1.jsx)(modal_1.InterchainWalletModal, { shouldShowList: shouldShowList, username: username, address: address, disconnect: disconnect, isOpen: modalIsOpen, open: open, close: handleCloseModal, wallets: walletsForUI, walletConnectQRCodeUri: walletConnectQRCodeUri, currentWallet: wallet, isConnecting: status === core_1.WalletState.Connecting, isConnected: status === core_1.WalletState.Connected, isRejected: status === core_1.WalletState.Rejected, isDisconnected: status === core_1.WalletState.Disconnected, isNotExist: status === core_1.WalletState.NotExist, errorMessage: message, onSelectWallet: (w) => handleConnectWallet(w.info.name), onBack: () => setShouldShowList(true), onReconnect: () => handleConnectWallet(currentWalletName), getDownloadLink: () => getDownloadLink(wallet?.info.name), getEnv: getEnv })] }));
34
- };
35
- exports.WalletModalProvider = WalletModalProvider;
36
- const useWalletModal = () => {
37
- const context = (0, react_1.useContext)(WalletModalContext);
38
- if (!context) {
39
- throw new Error("useWalletModal must be used within a WalletModalProvider");
40
- }
41
- return context;
42
- };
43
- exports.useWalletModal = useWalletModal;