@reown/appkit 1.8.15-viem-upgrade.0 → 1.8.15-wc-linking-reset-headless.0
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.
- package/dist/esm/exports/auth-provider.js +2 -0
- package/dist/esm/exports/auth-provider.js.map +1 -0
- package/dist/esm/exports/constants.js +2 -0
- package/dist/esm/exports/constants.js.map +1 -0
- package/dist/esm/exports/core.js +11 -0
- package/dist/esm/exports/core.js.map +1 -0
- package/dist/esm/exports/index.js +14 -0
- package/dist/esm/exports/index.js.map +1 -0
- package/dist/esm/exports/library/react.js +2 -0
- package/dist/esm/exports/library/react.js.map +1 -0
- package/dist/esm/exports/library/vue.js +2 -0
- package/dist/esm/exports/library/vue.js.map +1 -0
- package/dist/esm/exports/networks.js +2 -0
- package/dist/esm/exports/networks.js.map +1 -0
- package/dist/esm/exports/react-core.js +39 -0
- package/dist/esm/exports/react-core.js.map +1 -0
- package/dist/esm/exports/react.js +50 -0
- package/dist/esm/exports/react.js.map +1 -0
- package/dist/esm/exports/testing.js +15 -0
- package/dist/esm/exports/testing.js.map +1 -0
- package/dist/esm/exports/utils.js +2 -0
- package/dist/esm/exports/utils.js.map +1 -0
- package/dist/esm/exports/vue-core.js +45 -0
- package/dist/esm/exports/vue-core.js.map +1 -0
- package/dist/esm/exports/vue.js +53 -0
- package/dist/esm/exports/vue.js.map +1 -0
- package/dist/esm/package.json +171 -0
- package/dist/esm/src/auth-provider/W3MFrameProviderSingleton.js +26 -0
- package/dist/esm/src/auth-provider/W3MFrameProviderSingleton.js.map +1 -0
- package/dist/esm/src/auth-provider/index.js +2 -0
- package/dist/esm/src/auth-provider/index.js.map +1 -0
- package/dist/esm/src/client/appkit-base-client.js +1893 -0
- package/dist/esm/src/client/appkit-base-client.js.map +1 -0
- package/dist/esm/src/client/appkit-core.js +44 -0
- package/dist/esm/src/client/appkit-core.js.map +1 -0
- package/dist/esm/src/client/appkit.js +540 -0
- package/dist/esm/src/client/appkit.js.map +1 -0
- package/dist/esm/src/library/react/components.js +24 -0
- package/dist/esm/src/library/react/components.js.map +1 -0
- package/dist/esm/src/library/react/index.js +110 -0
- package/dist/esm/src/library/react/index.js.map +1 -0
- package/dist/esm/src/library/react/providers.js +17 -0
- package/dist/esm/src/library/react/providers.js.map +1 -0
- package/dist/esm/src/library/vue/index.js +117 -0
- package/dist/esm/src/library/vue/index.js.map +1 -0
- package/dist/esm/src/networks/bitcoin.js +46 -0
- package/dist/esm/src/networks/bitcoin.js.map +1 -0
- package/dist/esm/src/networks/index.js +9 -0
- package/dist/esm/src/networks/index.js.map +1 -0
- package/dist/esm/src/networks/solana/index.js +4 -0
- package/dist/esm/src/networks/solana/index.js.map +1 -0
- package/dist/esm/src/networks/solana/solana.js +16 -0
- package/dist/esm/src/networks/solana/solana.js.map +1 -0
- package/dist/esm/src/networks/solana/solanaDevnet.js +16 -0
- package/dist/esm/src/networks/solana/solanaDevnet.js.map +1 -0
- package/dist/esm/src/networks/solana/solanaTestnet.js +15 -0
- package/dist/esm/src/networks/solana/solanaTestnet.js.map +1 -0
- package/dist/esm/src/networks/ton/index.js +3 -0
- package/dist/esm/src/networks/ton/index.js.map +1 -0
- package/dist/esm/src/networks/ton/ton.js +15 -0
- package/dist/esm/src/networks/ton/ton.js.map +1 -0
- package/dist/esm/src/networks/ton/tonTestnet.js +15 -0
- package/dist/esm/src/networks/ton/tonTestnet.js.map +1 -0
- package/dist/esm/src/networks/utils.js +9 -0
- package/dist/esm/src/networks/utils.js.map +1 -0
- package/dist/esm/src/universal-adapter/client.js +203 -0
- package/dist/esm/src/universal-adapter/client.js.map +1 -0
- package/dist/esm/src/universal-adapter/index.js +2 -0
- package/dist/esm/src/universal-adapter/index.js.map +1 -0
- package/dist/esm/src/utils/BalanceUtil.js +28 -0
- package/dist/esm/src/utils/BalanceUtil.js.map +1 -0
- package/dist/esm/src/utils/ConfigUtil.js +273 -0
- package/dist/esm/src/utils/ConfigUtil.js.map +1 -0
- package/dist/esm/src/utils/ConstantsUtil.js +6 -0
- package/dist/esm/src/utils/ConstantsUtil.js.map +1 -0
- package/dist/esm/src/utils/TypesUtil.js +2 -0
- package/dist/esm/src/utils/TypesUtil.js.map +1 -0
- package/dist/esm/src/utils/index.js +3 -0
- package/dist/esm/src/utils/index.js.map +1 -0
- package/dist/esm/tsconfig.build.tsbuildinfo +1 -0
- package/dist/types/exports/auth-provider.d.ts +1 -0
- package/dist/types/exports/constants.d.ts +1 -0
- package/dist/types/exports/core.d.ts +8 -0
- package/dist/types/exports/index.d.ts +10 -0
- package/dist/types/exports/library/react.d.ts +1 -0
- package/dist/types/exports/library/vue.d.ts +1 -0
- package/dist/types/exports/networks.d.ts +1 -0
- package/dist/types/exports/react-core.d.ts +16 -0
- package/dist/types/exports/react.d.ts +30 -0
- package/dist/types/exports/testing.d.ts +7 -0
- package/dist/types/exports/utils.d.ts +1 -0
- package/dist/types/exports/vue-core.d.ts +15 -0
- package/dist/types/exports/vue.d.ts +23 -0
- package/dist/types/src/auth-provider/W3MFrameProviderSingleton.d.ts +17 -0
- package/dist/types/src/auth-provider/index.d.ts +1 -0
- package/dist/types/src/client/appkit-base-client.d.ts +322 -0
- package/dist/types/src/client/appkit-core.d.ts +27 -0
- package/dist/types/src/client/appkit.d.ts +28 -0
- package/dist/types/src/library/react/components.d.ts +5 -0
- package/dist/types/src/library/react/index.d.ts +78 -0
- package/dist/types/src/library/react/providers.d.ts +7 -0
- package/dist/types/src/library/vue/index.d.ts +86 -0
- package/dist/types/src/networks/bitcoin.d.ts +150 -0
- package/dist/types/src/networks/index.d.ts +7 -0
- package/dist/types/src/networks/solana/index.d.ts +3 -0
- package/dist/types/src/networks/solana/solana.d.ts +46 -0
- package/dist/types/src/networks/solana/solanaDevnet.d.ts +46 -0
- package/dist/types/src/networks/solana/solanaTestnet.d.ts +45 -0
- package/dist/types/src/networks/ton/index.d.ts +2 -0
- package/dist/types/src/networks/ton/ton.d.ts +45 -0
- package/dist/types/src/networks/ton/tonTestnet.d.ts +45 -0
- package/dist/types/src/networks/utils.d.ts +3 -0
- package/dist/types/src/universal-adapter/client.d.ts +41 -0
- package/dist/types/src/universal-adapter/index.d.ts +1 -0
- package/dist/types/src/utils/BalanceUtil.d.ts +14 -0
- package/dist/types/src/utils/ConfigUtil.d.ts +29 -0
- package/dist/types/src/utils/ConstantsUtil.d.ts +5 -0
- package/dist/types/src/utils/TypesUtil.d.ts +98 -0
- package/dist/types/src/utils/index.d.ts +2 -0
- package/package.json +11 -11
|
@@ -0,0 +1,1893 @@
|
|
|
1
|
+
import UniversalProvider from '@walletconnect/universal-provider';
|
|
2
|
+
import { ConstantsUtil, NetworkUtil, ParseUtil } from '@reown/appkit-common';
|
|
3
|
+
import { AdapterController, AlertController, ApiController, AssetUtil, BlockchainApiController, ChainController, ConnectionController, ConnectionControllerUtil, ConnectorController, ConnectorUtil, ConstantsUtil as CoreConstantsUtil, CoreHelperUtil, EnsController, EventsController, ModalController, OnRampController, OptionsController, ProviderController, PublicStateController, RouterController, SIWXUtil, SendController, SnackController, StorageUtil, ThemeController, WalletUtil, WcHelpersUtil, getPreferredAccountType } from '@reown/appkit-controllers';
|
|
4
|
+
import { setColorTheme, setThemeVariables } from '@reown/appkit-ui';
|
|
5
|
+
import { CaipNetworksUtil, ErrorUtil, HelpersUtil, LoggerUtil, TokenUtil, ConstantsUtil as UtilConstantsUtil } from '@reown/appkit-utils';
|
|
6
|
+
import { UniversalAdapter } from '../universal-adapter/client.js';
|
|
7
|
+
import { ConfigUtil } from '../utils/ConfigUtil.js';
|
|
8
|
+
export class AppKitBaseClient {
|
|
9
|
+
constructor(options) {
|
|
10
|
+
this.chainNamespaces = [];
|
|
11
|
+
this.features = {};
|
|
12
|
+
this.remoteFeatures = {};
|
|
13
|
+
this.reportedAlertErrors = {};
|
|
14
|
+
// -- Public Internal ---------------------------------------------------
|
|
15
|
+
this.getCaipNetwork = (chainNamespace, id) => {
|
|
16
|
+
if (chainNamespace) {
|
|
17
|
+
const caipNetworkWithId = ChainController.getCaipNetworks(chainNamespace)?.find(c => c.id === id);
|
|
18
|
+
if (caipNetworkWithId) {
|
|
19
|
+
return caipNetworkWithId;
|
|
20
|
+
}
|
|
21
|
+
const namespaceCaipNetwork = ChainController.getNetworkData(chainNamespace)?.caipNetwork;
|
|
22
|
+
if (namespaceCaipNetwork) {
|
|
23
|
+
return namespaceCaipNetwork;
|
|
24
|
+
}
|
|
25
|
+
const requestedCaipNetworks = ChainController.getRequestedCaipNetworks(chainNamespace);
|
|
26
|
+
return requestedCaipNetworks.filter(c => c.chainNamespace === chainNamespace)?.[0];
|
|
27
|
+
}
|
|
28
|
+
return ChainController.state.activeCaipNetwork || this.defaultCaipNetwork;
|
|
29
|
+
};
|
|
30
|
+
this.getCaipNetworkId = () => {
|
|
31
|
+
const network = this.getCaipNetwork();
|
|
32
|
+
if (network) {
|
|
33
|
+
return network.id;
|
|
34
|
+
}
|
|
35
|
+
return undefined;
|
|
36
|
+
};
|
|
37
|
+
this.getCaipNetworks = (namespace) => ChainController.getCaipNetworks(namespace);
|
|
38
|
+
this.getActiveChainNamespace = () => ChainController.state.activeChain;
|
|
39
|
+
this.setRequestedCaipNetworks = (requestedCaipNetworks, chain) => {
|
|
40
|
+
ChainController.setRequestedCaipNetworks(requestedCaipNetworks, chain);
|
|
41
|
+
};
|
|
42
|
+
this.getApprovedCaipNetworkIds = () => ChainController.getAllApprovedCaipNetworkIds();
|
|
43
|
+
this.getCaipAddress = (chainNamespace) => {
|
|
44
|
+
if (ChainController.state.activeChain === chainNamespace || !chainNamespace) {
|
|
45
|
+
return ChainController.state.activeCaipAddress;
|
|
46
|
+
}
|
|
47
|
+
return ChainController.state.chains.get(chainNamespace)?.accountState?.caipAddress;
|
|
48
|
+
};
|
|
49
|
+
this.setClientId = clientId => {
|
|
50
|
+
BlockchainApiController.setClientId(clientId);
|
|
51
|
+
};
|
|
52
|
+
this.getProvider = (namespace) => ProviderController.getProvider(namespace);
|
|
53
|
+
this.getProviderType = (namespace) => ProviderController.getProviderId(namespace);
|
|
54
|
+
this.getPreferredAccountType = (namespace) => getPreferredAccountType(namespace);
|
|
55
|
+
this.setCaipAddress = (caipAddress, chain, shouldRefresh = false) => {
|
|
56
|
+
ChainController.setAccountProp('caipAddress', caipAddress, chain, shouldRefresh);
|
|
57
|
+
ChainController.setAccountProp('address', CoreHelperUtil.getPlainAddress(caipAddress), chain, shouldRefresh);
|
|
58
|
+
};
|
|
59
|
+
this.setBalance = (balance, balanceSymbol, chain) => {
|
|
60
|
+
ChainController.setAccountProp('balance', balance, chain);
|
|
61
|
+
ChainController.setAccountProp('balanceSymbol', balanceSymbol, chain);
|
|
62
|
+
};
|
|
63
|
+
this.setProfileName = (profileName, chain) => {
|
|
64
|
+
ChainController.setAccountProp('profileName', profileName, chain);
|
|
65
|
+
};
|
|
66
|
+
this.setProfileImage = (profileImage, chain) => {
|
|
67
|
+
ChainController.setAccountProp('profileImage', profileImage, chain);
|
|
68
|
+
};
|
|
69
|
+
this.setUser = (user, chain) => {
|
|
70
|
+
ChainController.setAccountProp('user', user, chain);
|
|
71
|
+
};
|
|
72
|
+
this.resetAccount = (chain) => {
|
|
73
|
+
ChainController.resetAccount(chain);
|
|
74
|
+
};
|
|
75
|
+
this.setCaipNetwork = caipNetwork => {
|
|
76
|
+
ChainController.setActiveCaipNetwork(caipNetwork);
|
|
77
|
+
};
|
|
78
|
+
this.setCaipNetworkOfNamespace = (caipNetwork, chainNamespace) => {
|
|
79
|
+
ChainController.setChainNetworkData(chainNamespace, { caipNetwork });
|
|
80
|
+
};
|
|
81
|
+
this.setStatus = (status, chain) => {
|
|
82
|
+
ChainController.setAccountProp('status', status, chain);
|
|
83
|
+
// If at least one namespace is connected, set the connection status
|
|
84
|
+
if (ConnectorController.isConnected()) {
|
|
85
|
+
StorageUtil.setConnectionStatus('connected');
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
StorageUtil.setConnectionStatus('disconnected');
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
this.getAddressByChainNamespace = (chainNamespace) => ChainController.getAccountData(chainNamespace)?.address;
|
|
92
|
+
this.setConnectors = connectors => {
|
|
93
|
+
const allConnectors = [...ConnectorController.state.allConnectors, ...connectors];
|
|
94
|
+
ConnectorController.setConnectors(allConnectors);
|
|
95
|
+
};
|
|
96
|
+
this.setConnections = (connections, chainNamespace) => {
|
|
97
|
+
StorageUtil.setConnections(connections, chainNamespace);
|
|
98
|
+
ConnectionController.setConnections(connections, chainNamespace);
|
|
99
|
+
};
|
|
100
|
+
this.fetchIdentity = request => BlockchainApiController.fetchIdentity(request);
|
|
101
|
+
this.getReownName = address => EnsController.getNamesForAddress(address);
|
|
102
|
+
this.getConnectors = () => ConnectorController.getConnectors();
|
|
103
|
+
this.getConnectorImage = connector => AssetUtil.getConnectorImage(connector);
|
|
104
|
+
this.getConnections = (namespace) => {
|
|
105
|
+
if (!this.remoteFeatures.multiWallet) {
|
|
106
|
+
AlertController.open(ConstantsUtil.REMOTE_FEATURES_ALERTS.MULTI_WALLET_NOT_ENABLED.DEFAULT, 'info');
|
|
107
|
+
return [];
|
|
108
|
+
}
|
|
109
|
+
return ConnectionControllerUtil.getConnectionsData(namespace).connections;
|
|
110
|
+
};
|
|
111
|
+
this.getRecentConnections = (namespace) => {
|
|
112
|
+
if (!this.remoteFeatures.multiWallet) {
|
|
113
|
+
AlertController.open(ConstantsUtil.REMOTE_FEATURES_ALERTS.MULTI_WALLET_NOT_ENABLED.DEFAULT, 'info');
|
|
114
|
+
return [];
|
|
115
|
+
}
|
|
116
|
+
return ConnectionControllerUtil.getConnectionsData(namespace).recentConnections;
|
|
117
|
+
};
|
|
118
|
+
this.switchConnection = async (params) => {
|
|
119
|
+
if (!this.remoteFeatures.multiWallet) {
|
|
120
|
+
AlertController.open(ConstantsUtil.REMOTE_FEATURES_ALERTS.MULTI_WALLET_NOT_ENABLED.DEFAULT, 'info');
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
await ConnectionController.switchConnection(params);
|
|
124
|
+
};
|
|
125
|
+
this.deleteConnection = params => {
|
|
126
|
+
if (!this.remoteFeatures.multiWallet) {
|
|
127
|
+
AlertController.open(ConstantsUtil.REMOTE_FEATURES_ALERTS.MULTI_WALLET_NOT_ENABLED.DEFAULT, 'info');
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
StorageUtil.deleteAddressFromConnection(params);
|
|
131
|
+
ConnectionController.syncStorageConnections();
|
|
132
|
+
};
|
|
133
|
+
this.setConnectedWalletInfo = (connectedWalletInfo, chain) => {
|
|
134
|
+
const type = ProviderController.getProviderId(chain);
|
|
135
|
+
const walletInfo = connectedWalletInfo ? { ...connectedWalletInfo, type } : undefined;
|
|
136
|
+
ChainController.setAccountProp('connectedWalletInfo', walletInfo, chain);
|
|
137
|
+
};
|
|
138
|
+
this.getIsConnectedState = () => Boolean(ChainController.state.activeCaipAddress);
|
|
139
|
+
this.addAddressLabel = (address, label, chain) => {
|
|
140
|
+
const addressLabels = ChainController.getAccountData(chain)?.addressLabels || {};
|
|
141
|
+
ChainController.setAccountProp('addressLabels', { ...addressLabels, [address]: label }, chain);
|
|
142
|
+
};
|
|
143
|
+
this.removeAddressLabel = (address, chain) => {
|
|
144
|
+
const addressLabels = ChainController.getAccountData(chain)?.addressLabels || {};
|
|
145
|
+
ChainController.setAccountProp('addressLabels', { ...addressLabels, [address]: undefined }, chain);
|
|
146
|
+
};
|
|
147
|
+
this.getAddress = (chainNamespace) => {
|
|
148
|
+
const namespace = chainNamespace || ChainController.state.activeChain;
|
|
149
|
+
return ChainController.getAccountData(namespace)?.address;
|
|
150
|
+
};
|
|
151
|
+
this.resetNetwork = (namespace) => {
|
|
152
|
+
ChainController.resetNetwork(namespace);
|
|
153
|
+
};
|
|
154
|
+
this.addConnector = connector => {
|
|
155
|
+
ConnectorController.addConnector(connector);
|
|
156
|
+
};
|
|
157
|
+
this.resetWcConnection = () => {
|
|
158
|
+
ConnectionController.resetWcConnection();
|
|
159
|
+
};
|
|
160
|
+
this.setAddressExplorerUrl = (addressExplorerUrl, chain) => {
|
|
161
|
+
ChainController.setAccountProp('addressExplorerUrl', addressExplorerUrl, chain);
|
|
162
|
+
};
|
|
163
|
+
this.setSmartAccountDeployed = (isDeployed, chain) => {
|
|
164
|
+
ChainController.setAccountProp('smartAccountDeployed', isDeployed, chain);
|
|
165
|
+
};
|
|
166
|
+
this.setPreferredAccountType = (preferredAccountType, chain) => {
|
|
167
|
+
ChainController.setAccountProp('preferredAccountType', preferredAccountType, chain);
|
|
168
|
+
};
|
|
169
|
+
this.setEIP6963Enabled = enabled => {
|
|
170
|
+
OptionsController.setEIP6963Enabled(enabled);
|
|
171
|
+
};
|
|
172
|
+
this.handleUnsafeRPCRequest = () => {
|
|
173
|
+
if (this.isOpen()) {
|
|
174
|
+
// If we are on the modal but there is no transaction stack, close the modal
|
|
175
|
+
if (this.isTransactionStackEmpty()) {
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
// Check if we need to replace or redirect
|
|
179
|
+
this.redirect('ApproveTransaction');
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
// If called from outside the modal, open ApproveTransaction
|
|
183
|
+
this.open({ view: 'ApproveTransaction' });
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
this.options = options;
|
|
187
|
+
this.version = options.sdkVersion;
|
|
188
|
+
this.caipNetworks = this.extendCaipNetworks(options);
|
|
189
|
+
this.chainNamespaces = this.getChainNamespacesSet(options.adapters, this.caipNetworks);
|
|
190
|
+
this.defaultCaipNetwork = this.extendDefaultCaipNetwork(options);
|
|
191
|
+
this.chainAdapters = this.createAdapters(options.adapters);
|
|
192
|
+
this.readyPromise = this.initialize(options);
|
|
193
|
+
}
|
|
194
|
+
getChainNamespacesSet(adapters, caipNetworks) {
|
|
195
|
+
const adapterNamespaces = adapters
|
|
196
|
+
?.map(adapter => adapter.namespace)
|
|
197
|
+
.filter((namespace) => Boolean(namespace));
|
|
198
|
+
if (adapterNamespaces?.length) {
|
|
199
|
+
return [...new Set(adapterNamespaces)];
|
|
200
|
+
}
|
|
201
|
+
const networkNamespaces = caipNetworks?.map(network => network.chainNamespace);
|
|
202
|
+
return [...new Set(networkNamespaces)];
|
|
203
|
+
}
|
|
204
|
+
async initialize(options) {
|
|
205
|
+
this.initializeProjectSettings(options);
|
|
206
|
+
this.initControllers(options);
|
|
207
|
+
await this.initChainAdapters();
|
|
208
|
+
this.sendInitializeEvent(options);
|
|
209
|
+
if (options.features?.headless && !ConnectorUtil.hasInjectedConnectors()) {
|
|
210
|
+
ApiController.prefetch({
|
|
211
|
+
fetchNetworkImages: false,
|
|
212
|
+
fetchConnectorImages: false,
|
|
213
|
+
fetchWalletRanks: false,
|
|
214
|
+
fetchRecommendedWallets: true
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
if (OptionsController.state.enableReconnect) {
|
|
218
|
+
await this.syncExistingConnection();
|
|
219
|
+
await this.syncAdapterConnections();
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
await this.unSyncExistingConnection();
|
|
223
|
+
}
|
|
224
|
+
if (!options.basic && !options.manualWCControl) {
|
|
225
|
+
this.remoteFeatures = await ConfigUtil.fetchRemoteFeatures(options);
|
|
226
|
+
}
|
|
227
|
+
await ApiController.fetchUsage();
|
|
228
|
+
OptionsController.setRemoteFeatures(this.remoteFeatures);
|
|
229
|
+
if (this.remoteFeatures.onramp) {
|
|
230
|
+
OnRampController.setOnrampProviders(this.remoteFeatures.onramp);
|
|
231
|
+
}
|
|
232
|
+
// Check allowed origins only if email or social features are enabled
|
|
233
|
+
if (OptionsController.state.remoteFeatures?.email ||
|
|
234
|
+
(Array.isArray(OptionsController.state.remoteFeatures?.socials) &&
|
|
235
|
+
OptionsController.state.remoteFeatures?.socials.length > 0)) {
|
|
236
|
+
await this.checkAllowedOrigins();
|
|
237
|
+
}
|
|
238
|
+
if (OptionsController.state.features?.reownAuthentication ||
|
|
239
|
+
OptionsController.state.remoteFeatures?.reownAuthentication) {
|
|
240
|
+
const { ReownAuthentication } = await import('@reown/appkit-controllers/features');
|
|
241
|
+
const currentSIWX = OptionsController.state.siwx;
|
|
242
|
+
if (!(currentSIWX instanceof ReownAuthentication)) {
|
|
243
|
+
if (currentSIWX) {
|
|
244
|
+
console.warn('ReownAuthentication option is enabled, SIWX configuration will be overridden.');
|
|
245
|
+
}
|
|
246
|
+
OptionsController.setSIWX(new ReownAuthentication());
|
|
247
|
+
}
|
|
248
|
+
// If siwx is already configured for ReownAuthentication we keep the current instance
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
async openSend(args) {
|
|
252
|
+
const namespaceToUse = args.namespace || ChainController.state.activeChain;
|
|
253
|
+
const caipAddress = this.getCaipAddress(namespaceToUse);
|
|
254
|
+
const chainId = this.getCaipNetwork(namespaceToUse)?.id;
|
|
255
|
+
if (!caipAddress) {
|
|
256
|
+
throw new Error('openSend: caipAddress not found');
|
|
257
|
+
}
|
|
258
|
+
if (chainId?.toString() !== args.chainId.toString()) {
|
|
259
|
+
const caipNetwork = ChainController.getCaipNetworkById(args.chainId, namespaceToUse);
|
|
260
|
+
if (!caipNetwork) {
|
|
261
|
+
throw new Error(`openSend: caipNetwork with chainId ${args.chainId} not found`);
|
|
262
|
+
}
|
|
263
|
+
await this.switchNetwork(caipNetwork, { throwOnFailure: true });
|
|
264
|
+
}
|
|
265
|
+
try {
|
|
266
|
+
const symbol = TokenUtil.getTokenSymbolByAddress(args.assetAddress);
|
|
267
|
+
if (symbol) {
|
|
268
|
+
await ApiController.fetchTokenImages([symbol]);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
catch {
|
|
272
|
+
/* Ignore */
|
|
273
|
+
}
|
|
274
|
+
await ModalController.open({
|
|
275
|
+
view: 'WalletSend',
|
|
276
|
+
data: { send: args }
|
|
277
|
+
});
|
|
278
|
+
return new Promise((resolve, reject) => {
|
|
279
|
+
const unsubscribe = SendController.subscribeKey('hash', hash => {
|
|
280
|
+
if (hash) {
|
|
281
|
+
cleanup();
|
|
282
|
+
resolve({ hash });
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
const unsubscribeModal = ModalController.subscribe(modal => {
|
|
286
|
+
if (!modal.open) {
|
|
287
|
+
cleanup();
|
|
288
|
+
reject(new Error('Modal closed'));
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
const cleanup = this.createCleanupHandler([unsubscribe, unsubscribeModal]);
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
toModalOptions() {
|
|
295
|
+
function isSwap(options) {
|
|
296
|
+
return options?.view === 'Swap';
|
|
297
|
+
}
|
|
298
|
+
function isSend(options) {
|
|
299
|
+
return options?.view === 'WalletSend';
|
|
300
|
+
}
|
|
301
|
+
return {
|
|
302
|
+
isSwap,
|
|
303
|
+
isSend
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
async checkAllowedOrigins() {
|
|
307
|
+
try {
|
|
308
|
+
const allowedOrigins = await ApiController.fetchAllowedOrigins();
|
|
309
|
+
if (!CoreHelperUtil.isClient()) {
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
const currentOrigin = window.location.origin;
|
|
313
|
+
const isOriginAllowed = WcHelpersUtil.isOriginAllowed(currentOrigin, allowedOrigins, ConstantsUtil.DEFAULT_ALLOWED_ANCESTORS);
|
|
314
|
+
if (!isOriginAllowed) {
|
|
315
|
+
AlertController.open(ErrorUtil.ALERT_ERRORS.ORIGIN_NOT_ALLOWED, 'error');
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
catch (error) {
|
|
319
|
+
if (!(error instanceof Error)) {
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
switch (error.message) {
|
|
323
|
+
case 'RATE_LIMITED':
|
|
324
|
+
AlertController.open(ErrorUtil.ALERT_ERRORS.RATE_LIMITED_APP_CONFIGURATION, 'error');
|
|
325
|
+
break;
|
|
326
|
+
case 'SERVER_ERROR': {
|
|
327
|
+
const originalError = error.cause instanceof Error ? error.cause : error;
|
|
328
|
+
AlertController.open({
|
|
329
|
+
displayMessage: ErrorUtil.ALERT_ERRORS.SERVER_ERROR_APP_CONFIGURATION.displayMessage,
|
|
330
|
+
debugMessage: ErrorUtil.ALERT_ERRORS.SERVER_ERROR_APP_CONFIGURATION.debugMessage(originalError.message)
|
|
331
|
+
}, 'error');
|
|
332
|
+
break;
|
|
333
|
+
}
|
|
334
|
+
default:
|
|
335
|
+
break;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
createCleanupHandler(unsubscribeFunctions) {
|
|
340
|
+
return () => {
|
|
341
|
+
unsubscribeFunctions.forEach(unsubscribe => {
|
|
342
|
+
try {
|
|
343
|
+
unsubscribe();
|
|
344
|
+
}
|
|
345
|
+
catch {
|
|
346
|
+
// Ignore cleanup errors
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
sendInitializeEvent(options) {
|
|
352
|
+
const { ...optionsCopy } = options;
|
|
353
|
+
delete optionsCopy.adapters;
|
|
354
|
+
delete optionsCopy.universalProvider;
|
|
355
|
+
EventsController.sendEvent({
|
|
356
|
+
type: 'track',
|
|
357
|
+
event: 'INITIALIZE',
|
|
358
|
+
properties: {
|
|
359
|
+
...optionsCopy,
|
|
360
|
+
networks: options.networks.map(n => n.id),
|
|
361
|
+
siweConfig: {
|
|
362
|
+
options: options.siweConfig?.options || {}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
// -- Controllers initialization ---------------------------------------------------
|
|
368
|
+
initControllers(options) {
|
|
369
|
+
this.initializeOptionsController(options);
|
|
370
|
+
this.initializeChainController(options);
|
|
371
|
+
this.initializeThemeController(options);
|
|
372
|
+
this.initializeConnectionController(options);
|
|
373
|
+
this.initializeConnectorController();
|
|
374
|
+
}
|
|
375
|
+
initAdapterController() {
|
|
376
|
+
AdapterController.initialize(this.chainAdapters);
|
|
377
|
+
}
|
|
378
|
+
initializeThemeController(options) {
|
|
379
|
+
if (options.themeMode) {
|
|
380
|
+
ThemeController.setThemeMode(options.themeMode);
|
|
381
|
+
}
|
|
382
|
+
if (options.themeVariables) {
|
|
383
|
+
ThemeController.setThemeVariables(options.themeVariables);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
initializeChainController(options) {
|
|
387
|
+
if (!this.connectionControllerClient) {
|
|
388
|
+
throw new Error('ConnectionControllerClient must be set');
|
|
389
|
+
}
|
|
390
|
+
ChainController.initialize(options.adapters ?? [], this.caipNetworks, {
|
|
391
|
+
connectionControllerClient: this.connectionControllerClient
|
|
392
|
+
});
|
|
393
|
+
const network = this.getDefaultNetwork();
|
|
394
|
+
if (network) {
|
|
395
|
+
ChainController.setActiveCaipNetwork(network);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
initializeConnectionController(options) {
|
|
399
|
+
ConnectionController.initialize(options.adapters ?? []);
|
|
400
|
+
ConnectionController.setWcBasic(options.basic ?? false);
|
|
401
|
+
}
|
|
402
|
+
initializeConnectorController() {
|
|
403
|
+
ConnectorController.initialize(this.chainNamespaces);
|
|
404
|
+
}
|
|
405
|
+
initializeProjectSettings(options) {
|
|
406
|
+
OptionsController.setProjectId(options.projectId);
|
|
407
|
+
OptionsController.setSdkVersion(options.sdkVersion);
|
|
408
|
+
}
|
|
409
|
+
initializeOptionsController(options) {
|
|
410
|
+
OptionsController.setDebug(options.debug !== false);
|
|
411
|
+
// On by default
|
|
412
|
+
OptionsController.setEnableWalletGuide(options.enableWalletGuide !== false);
|
|
413
|
+
OptionsController.setEnableWallets(options.enableWallets !== false);
|
|
414
|
+
OptionsController.setEIP6963Enabled(options.enableEIP6963 !== false);
|
|
415
|
+
OptionsController.setEnableNetworkSwitch(options.enableNetworkSwitch !== false);
|
|
416
|
+
OptionsController.setEnableReconnect(options.enableReconnect !== false);
|
|
417
|
+
OptionsController.setEnableMobileFullScreen(options.enableMobileFullScreen === true);
|
|
418
|
+
OptionsController.setCoinbasePreference(options.coinbasePreference);
|
|
419
|
+
OptionsController.setEnableAuthLogger(options.enableAuthLogger !== false);
|
|
420
|
+
OptionsController.setCustomRpcUrls(options.customRpcUrls);
|
|
421
|
+
OptionsController.setEnableEmbedded(options.enableEmbedded);
|
|
422
|
+
OptionsController.setAllWallets(options.allWallets);
|
|
423
|
+
OptionsController.setIncludeWalletIds(options.includeWalletIds);
|
|
424
|
+
OptionsController.setExcludeWalletIds(options.excludeWalletIds);
|
|
425
|
+
OptionsController.setFeaturedWalletIds(options.featuredWalletIds);
|
|
426
|
+
OptionsController.setTokens(options.tokens);
|
|
427
|
+
OptionsController.setTermsConditionsUrl(options.termsConditionsUrl);
|
|
428
|
+
OptionsController.setPrivacyPolicyUrl(options.privacyPolicyUrl);
|
|
429
|
+
OptionsController.setCustomWallets(options.customWallets);
|
|
430
|
+
OptionsController.setFeatures(options.features);
|
|
431
|
+
OptionsController.setAllowUnsupportedChain(options.allowUnsupportedChain);
|
|
432
|
+
OptionsController.setUniversalProviderConfigOverride(options.universalProviderConfigOverride);
|
|
433
|
+
OptionsController.setPreferUniversalLinks(options.experimental_preferUniversalLinks);
|
|
434
|
+
// Save option in controller
|
|
435
|
+
OptionsController.setDefaultAccountTypes(options.defaultAccountTypes);
|
|
436
|
+
const defaultMetaData = this.getDefaultMetaData();
|
|
437
|
+
if (!options.metadata && defaultMetaData) {
|
|
438
|
+
options.metadata = defaultMetaData;
|
|
439
|
+
}
|
|
440
|
+
OptionsController.setMetadata(options.metadata);
|
|
441
|
+
OptionsController.setDisableAppend(options.disableAppend);
|
|
442
|
+
OptionsController.setEnableEmbedded(options.enableEmbedded);
|
|
443
|
+
OptionsController.setSIWX(options.siwx);
|
|
444
|
+
this.features = OptionsController.state.features ?? {};
|
|
445
|
+
if (!options.projectId) {
|
|
446
|
+
AlertController.open(ErrorUtil.ALERT_ERRORS.PROJECT_ID_NOT_CONFIGURED, 'error');
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
449
|
+
const evmAdapter = options.adapters?.find(adapter => adapter.namespace === ConstantsUtil.CHAIN.EVM);
|
|
450
|
+
// Set the SIWE client for EVM chains
|
|
451
|
+
if (evmAdapter) {
|
|
452
|
+
if (options.siweConfig) {
|
|
453
|
+
if (options.siwx) {
|
|
454
|
+
throw new Error('Cannot set both `siweConfig` and `siwx` options');
|
|
455
|
+
}
|
|
456
|
+
OptionsController.setSIWX(options.siweConfig.mapToSIWX());
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
getDefaultMetaData() {
|
|
461
|
+
if (CoreHelperUtil.isClient()) {
|
|
462
|
+
return {
|
|
463
|
+
name: document.getElementsByTagName('title')?.[0]?.textContent || '',
|
|
464
|
+
description: document.querySelector('meta[property="og:description"]')?.content || '',
|
|
465
|
+
url: window.location.origin,
|
|
466
|
+
icons: [document.querySelector('link[rel~="icon"]')?.href || '']
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
return null;
|
|
470
|
+
}
|
|
471
|
+
// -- Network Initialization ---------------------------------------------------
|
|
472
|
+
setUnsupportedNetwork(chainId) {
|
|
473
|
+
const namespace = this.getActiveChainNamespace();
|
|
474
|
+
if (namespace) {
|
|
475
|
+
const unsupportedNetwork = CaipNetworksUtil.getUnsupportedNetwork(`${namespace}:${chainId}`);
|
|
476
|
+
ChainController.setActiveCaipNetwork(unsupportedNetwork);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
getDefaultNetwork() {
|
|
480
|
+
return CaipNetworksUtil.getCaipNetworkFromStorage(this.defaultCaipNetwork);
|
|
481
|
+
}
|
|
482
|
+
extendCaipNetwork(network, options) {
|
|
483
|
+
const extendedNetwork = CaipNetworksUtil.extendCaipNetwork(network, {
|
|
484
|
+
customNetworkImageUrls: options.chainImages,
|
|
485
|
+
projectId: options.projectId
|
|
486
|
+
});
|
|
487
|
+
return extendedNetwork;
|
|
488
|
+
}
|
|
489
|
+
extendCaipNetworks(options) {
|
|
490
|
+
const extendedNetworks = CaipNetworksUtil.extendCaipNetworks(options.networks, {
|
|
491
|
+
customNetworkImageUrls: options.chainImages,
|
|
492
|
+
customRpcUrls: options.customRpcUrls,
|
|
493
|
+
projectId: options.projectId
|
|
494
|
+
});
|
|
495
|
+
return extendedNetworks;
|
|
496
|
+
}
|
|
497
|
+
extendDefaultCaipNetwork(options) {
|
|
498
|
+
const defaultNetwork = options.networks.find(n => n.id === options.defaultNetwork?.id);
|
|
499
|
+
const extendedNetwork = defaultNetwork
|
|
500
|
+
? CaipNetworksUtil.extendCaipNetwork(defaultNetwork, {
|
|
501
|
+
customNetworkImageUrls: options.chainImages,
|
|
502
|
+
customRpcUrls: options.customRpcUrls,
|
|
503
|
+
projectId: options.projectId
|
|
504
|
+
})
|
|
505
|
+
: undefined;
|
|
506
|
+
return extendedNetwork;
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* Disconnects a connector with the given namespace and id. If the connector id is not provided, disconnects the adapter (namespace).
|
|
510
|
+
* @param namespace ChainNamespace
|
|
511
|
+
* @param id string
|
|
512
|
+
* @returns
|
|
513
|
+
*/
|
|
514
|
+
async disconnectConnector(namespace, id) {
|
|
515
|
+
try {
|
|
516
|
+
this.setLoading(true, namespace);
|
|
517
|
+
let disconnectResult = {
|
|
518
|
+
connections: []
|
|
519
|
+
};
|
|
520
|
+
const adapter = this.getAdapter(namespace);
|
|
521
|
+
const caipAddress = ChainController.state.chains.get(namespace)?.accountState?.caipAddress;
|
|
522
|
+
/**
|
|
523
|
+
* When the page loaded, the controller doesn't have address yet.
|
|
524
|
+
* To disconnect, we are checking enableReconnect flag to disconnect the namespace.
|
|
525
|
+
*/
|
|
526
|
+
if ((caipAddress || !OptionsController.state.enableReconnect) && adapter?.disconnect) {
|
|
527
|
+
disconnectResult = await adapter.disconnect({ id });
|
|
528
|
+
}
|
|
529
|
+
this.setLoading(false, namespace);
|
|
530
|
+
return disconnectResult;
|
|
531
|
+
}
|
|
532
|
+
catch (error) {
|
|
533
|
+
this.setLoading(false, namespace);
|
|
534
|
+
throw new Error(`Failed to disconnect chains: ${error.message}`);
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
// -- Client Initialization ---------------------------------------------------
|
|
538
|
+
createClients() {
|
|
539
|
+
this.connectionControllerClient = {
|
|
540
|
+
connectWalletConnect: async () => {
|
|
541
|
+
const activeChain = ChainController.state.activeChain;
|
|
542
|
+
const adapter = this.getAdapter(activeChain);
|
|
543
|
+
const chainId = this.getCaipNetwork(activeChain)?.id;
|
|
544
|
+
const connections = ConnectionController.getConnections(activeChain);
|
|
545
|
+
const isMultiWallet = this.remoteFeatures.multiWallet;
|
|
546
|
+
const hasConnections = connections.length > 0;
|
|
547
|
+
if (!adapter) {
|
|
548
|
+
throw new Error('Adapter not found');
|
|
549
|
+
}
|
|
550
|
+
const result = await adapter.connectWalletConnect(chainId);
|
|
551
|
+
const shouldClose = !hasConnections || !isMultiWallet;
|
|
552
|
+
if (shouldClose) {
|
|
553
|
+
this.close();
|
|
554
|
+
}
|
|
555
|
+
this.setClientId(result?.clientId || null);
|
|
556
|
+
StorageUtil.setConnectedNamespaces([...ChainController.state.chains.keys()]);
|
|
557
|
+
await this.syncWalletConnectAccount();
|
|
558
|
+
await SIWXUtil.initializeIfEnabled();
|
|
559
|
+
},
|
|
560
|
+
connectExternal: async (params) => {
|
|
561
|
+
const connectResult = await this.onConnectExternal(params);
|
|
562
|
+
await this.connectInactiveNamespaces(params, connectResult);
|
|
563
|
+
return connectResult ? { address: connectResult.address } : undefined;
|
|
564
|
+
},
|
|
565
|
+
reconnectExternal: async ({ id, info, type, provider }) => {
|
|
566
|
+
const namespace = ChainController.state.activeChain;
|
|
567
|
+
const adapter = this.getAdapter(namespace);
|
|
568
|
+
if (!namespace) {
|
|
569
|
+
throw new Error('reconnectExternal: namespace not found');
|
|
570
|
+
}
|
|
571
|
+
if (!adapter) {
|
|
572
|
+
throw new Error('reconnectExternal: adapter not found');
|
|
573
|
+
}
|
|
574
|
+
if (adapter?.reconnect) {
|
|
575
|
+
await adapter?.reconnect({ id, info, type, provider, chainId: this.getCaipNetwork()?.id });
|
|
576
|
+
StorageUtil.addConnectedNamespace(namespace);
|
|
577
|
+
this.syncConnectedWalletInfo(namespace);
|
|
578
|
+
}
|
|
579
|
+
},
|
|
580
|
+
disconnectConnector: async (params) => {
|
|
581
|
+
await this.disconnectConnector(params.namespace, params.id);
|
|
582
|
+
},
|
|
583
|
+
disconnect: async (params) => {
|
|
584
|
+
const { id: connectorIdParam, chainNamespace, initialDisconnect } = params || {};
|
|
585
|
+
const namespace = chainNamespace || ChainController.state.activeChain;
|
|
586
|
+
const namespaceConnectorId = ConnectorController.getConnectorId(namespace);
|
|
587
|
+
const isAuth = connectorIdParam === ConstantsUtil.CONNECTOR_ID.AUTH ||
|
|
588
|
+
namespaceConnectorId === ConstantsUtil.CONNECTOR_ID.AUTH;
|
|
589
|
+
const isWalletConnect = connectorIdParam === ConstantsUtil.CONNECTOR_ID.WALLET_CONNECT ||
|
|
590
|
+
namespaceConnectorId === ConstantsUtil.CONNECTOR_ID.WALLET_CONNECT;
|
|
591
|
+
try {
|
|
592
|
+
const namespaces = Array.from(ChainController.state.chains.keys());
|
|
593
|
+
let namespacesToDisconnect = chainNamespace ? [chainNamespace] : namespaces;
|
|
594
|
+
/*
|
|
595
|
+
* If the connector is WalletConnect or Auth, disconnect all namespaces
|
|
596
|
+
* since they share a single connector instance across all adapters
|
|
597
|
+
*/
|
|
598
|
+
if (isWalletConnect || isAuth) {
|
|
599
|
+
namespacesToDisconnect = namespaces;
|
|
600
|
+
}
|
|
601
|
+
const disconnectPromises = namespacesToDisconnect.map(async (ns) => {
|
|
602
|
+
const currentConnectorId = ConnectorController.getConnectorId(ns);
|
|
603
|
+
const connectorIdToDisconnect = connectorIdParam || currentConnectorId;
|
|
604
|
+
const disconnectData = await this.disconnectConnector(ns, connectorIdToDisconnect);
|
|
605
|
+
if (disconnectData) {
|
|
606
|
+
if (isAuth) {
|
|
607
|
+
StorageUtil.deleteConnectedSocialProvider();
|
|
608
|
+
}
|
|
609
|
+
disconnectData.connections.forEach(connection => {
|
|
610
|
+
StorageUtil.addDisconnectedConnectorId(connection.connectorId, ns);
|
|
611
|
+
});
|
|
612
|
+
}
|
|
613
|
+
if (initialDisconnect) {
|
|
614
|
+
this.onDisconnectNamespace({ chainNamespace: ns, closeModal: false });
|
|
615
|
+
}
|
|
616
|
+
});
|
|
617
|
+
const disconnectResults = await Promise.allSettled(disconnectPromises);
|
|
618
|
+
SendController.resetSend();
|
|
619
|
+
ConnectionController.resetWcConnection();
|
|
620
|
+
if (SIWXUtil.getSIWX()?.signOutOnDisconnect) {
|
|
621
|
+
await SIWXUtil.clearSessions();
|
|
622
|
+
}
|
|
623
|
+
ConnectorController.setFilterByNamespace(undefined);
|
|
624
|
+
ConnectionController.syncStorageConnections();
|
|
625
|
+
const failures = disconnectResults.filter((result) => result.status === 'rejected');
|
|
626
|
+
if (failures.length > 0) {
|
|
627
|
+
throw new Error(failures.map(f => f.reason.message).join(', '));
|
|
628
|
+
}
|
|
629
|
+
EventsController.sendEvent({
|
|
630
|
+
type: 'track',
|
|
631
|
+
event: 'DISCONNECT_SUCCESS',
|
|
632
|
+
properties: {
|
|
633
|
+
namespace: chainNamespace || 'all'
|
|
634
|
+
}
|
|
635
|
+
});
|
|
636
|
+
}
|
|
637
|
+
catch (error) {
|
|
638
|
+
throw new Error(`Failed to disconnect chains: ${error.message}`);
|
|
639
|
+
}
|
|
640
|
+
},
|
|
641
|
+
checkInstalled: (ids) => {
|
|
642
|
+
if (!ids) {
|
|
643
|
+
return Boolean(window.ethereum);
|
|
644
|
+
}
|
|
645
|
+
return ids.some(id => Boolean(window.ethereum?.[String(id)]));
|
|
646
|
+
},
|
|
647
|
+
signMessage: async (message) => {
|
|
648
|
+
const namespace = ChainController.state.activeChain;
|
|
649
|
+
const adapter = this.getAdapter(ChainController.state.activeChain);
|
|
650
|
+
if (!namespace) {
|
|
651
|
+
throw new Error('signMessage: namespace not found');
|
|
652
|
+
}
|
|
653
|
+
if (!adapter) {
|
|
654
|
+
throw new Error('signMessage: adapter not found');
|
|
655
|
+
}
|
|
656
|
+
const address = this.getAddress(namespace);
|
|
657
|
+
if (!address) {
|
|
658
|
+
throw new Error('signMessage: address not found');
|
|
659
|
+
}
|
|
660
|
+
const result = await adapter?.signMessage({
|
|
661
|
+
message,
|
|
662
|
+
address,
|
|
663
|
+
provider: ProviderController.getProvider(namespace)
|
|
664
|
+
});
|
|
665
|
+
return result?.signature || '';
|
|
666
|
+
},
|
|
667
|
+
sendTransaction: async (args) => {
|
|
668
|
+
const namespace = args.chainNamespace;
|
|
669
|
+
if (!namespace) {
|
|
670
|
+
throw new Error('sendTransaction: namespace not found');
|
|
671
|
+
}
|
|
672
|
+
if (CoreConstantsUtil.SEND_SUPPORTED_NAMESPACES.includes(namespace)) {
|
|
673
|
+
const adapter = this.getAdapter(namespace);
|
|
674
|
+
if (!adapter) {
|
|
675
|
+
throw new Error('sendTransaction: adapter not found');
|
|
676
|
+
}
|
|
677
|
+
const provider = ProviderController.getProvider(namespace);
|
|
678
|
+
const result = await adapter?.sendTransaction({
|
|
679
|
+
...args,
|
|
680
|
+
caipNetwork: this.getCaipNetwork(),
|
|
681
|
+
provider
|
|
682
|
+
});
|
|
683
|
+
return result?.hash || '';
|
|
684
|
+
}
|
|
685
|
+
return '';
|
|
686
|
+
},
|
|
687
|
+
estimateGas: async (args) => {
|
|
688
|
+
const namespace = args.chainNamespace;
|
|
689
|
+
if (namespace === ConstantsUtil.CHAIN.EVM) {
|
|
690
|
+
const adapter = this.getAdapter(namespace);
|
|
691
|
+
if (!adapter) {
|
|
692
|
+
throw new Error('estimateGas: adapter is required but got undefined');
|
|
693
|
+
}
|
|
694
|
+
const provider = ProviderController.getProvider(namespace);
|
|
695
|
+
const caipNetwork = this.getCaipNetwork();
|
|
696
|
+
if (!caipNetwork) {
|
|
697
|
+
throw new Error('estimateGas: caipNetwork is required but got undefined');
|
|
698
|
+
}
|
|
699
|
+
const result = await adapter?.estimateGas({ ...args, provider, caipNetwork });
|
|
700
|
+
return result?.gas || 0n;
|
|
701
|
+
}
|
|
702
|
+
return 0n;
|
|
703
|
+
},
|
|
704
|
+
getEnsAvatar: async () => {
|
|
705
|
+
const namespace = ChainController.state.activeChain;
|
|
706
|
+
if (!namespace) {
|
|
707
|
+
throw new Error('getEnsAvatar: namespace is required but got undefined');
|
|
708
|
+
}
|
|
709
|
+
const address = this.getAddress(namespace);
|
|
710
|
+
if (!address) {
|
|
711
|
+
throw new Error('getEnsAvatar: address not found');
|
|
712
|
+
}
|
|
713
|
+
await this.syncIdentity({
|
|
714
|
+
address,
|
|
715
|
+
chainId: Number(this.getCaipNetwork()?.id),
|
|
716
|
+
chainNamespace: namespace
|
|
717
|
+
});
|
|
718
|
+
const accountData = ChainController.getAccountData();
|
|
719
|
+
return accountData?.profileImage || false;
|
|
720
|
+
},
|
|
721
|
+
getEnsAddress: async (name) => await WcHelpersUtil.resolveReownName(name),
|
|
722
|
+
writeContract: async (args) => {
|
|
723
|
+
const namespace = ChainController.state.activeChain;
|
|
724
|
+
const adapter = this.getAdapter(namespace);
|
|
725
|
+
if (!namespace) {
|
|
726
|
+
throw new Error('writeContract: namespace is required but got undefined');
|
|
727
|
+
}
|
|
728
|
+
if (!adapter) {
|
|
729
|
+
throw new Error('writeContract: adapter is required but got undefined');
|
|
730
|
+
}
|
|
731
|
+
const caipNetwork = this.getCaipNetwork();
|
|
732
|
+
const caipAddress = this.getCaipAddress();
|
|
733
|
+
const provider = ProviderController.getProvider(namespace);
|
|
734
|
+
if (!caipNetwork || !caipAddress) {
|
|
735
|
+
throw new Error('writeContract: caipNetwork or caipAddress is required but got undefined');
|
|
736
|
+
}
|
|
737
|
+
const result = await adapter?.writeContract({ ...args, caipNetwork, provider, caipAddress });
|
|
738
|
+
return result?.hash;
|
|
739
|
+
},
|
|
740
|
+
parseUnits: (value, decimals) => {
|
|
741
|
+
const adapter = this.getAdapter(ChainController.state.activeChain);
|
|
742
|
+
if (!adapter) {
|
|
743
|
+
throw new Error('parseUnits: adapter is required but got undefined');
|
|
744
|
+
}
|
|
745
|
+
return adapter?.parseUnits({ value, decimals }) ?? 0n;
|
|
746
|
+
},
|
|
747
|
+
formatUnits: (value, decimals) => {
|
|
748
|
+
const adapter = this.getAdapter(ChainController.state.activeChain);
|
|
749
|
+
if (!adapter) {
|
|
750
|
+
throw new Error('formatUnits: adapter is required but got undefined');
|
|
751
|
+
}
|
|
752
|
+
return adapter?.formatUnits({ value, decimals }) ?? '0';
|
|
753
|
+
},
|
|
754
|
+
getCapabilities: async (params) => {
|
|
755
|
+
const adapter = this.getAdapter(ChainController.state.activeChain);
|
|
756
|
+
if (!adapter) {
|
|
757
|
+
throw new Error('getCapabilities: adapter is required but got undefined');
|
|
758
|
+
}
|
|
759
|
+
return await adapter?.getCapabilities(params);
|
|
760
|
+
},
|
|
761
|
+
grantPermissions: async (params) => {
|
|
762
|
+
const adapter = this.getAdapter(ChainController.state.activeChain);
|
|
763
|
+
if (!adapter) {
|
|
764
|
+
throw new Error('grantPermissions: adapter is required but got undefined');
|
|
765
|
+
}
|
|
766
|
+
return await adapter?.grantPermissions(params);
|
|
767
|
+
},
|
|
768
|
+
revokePermissions: async (params) => {
|
|
769
|
+
const adapter = this.getAdapter(ChainController.state.activeChain);
|
|
770
|
+
if (!adapter) {
|
|
771
|
+
throw new Error('revokePermissions: adapter is required but got undefined');
|
|
772
|
+
}
|
|
773
|
+
if (adapter?.revokePermissions) {
|
|
774
|
+
return await adapter.revokePermissions(params);
|
|
775
|
+
}
|
|
776
|
+
return '0x';
|
|
777
|
+
},
|
|
778
|
+
walletGetAssets: async (params) => {
|
|
779
|
+
const adapter = this.getAdapter(ChainController.state.activeChain);
|
|
780
|
+
if (!adapter) {
|
|
781
|
+
throw new Error('walletGetAssets: adapter is required but got undefined');
|
|
782
|
+
}
|
|
783
|
+
return (await adapter?.walletGetAssets(params)) ?? {};
|
|
784
|
+
},
|
|
785
|
+
updateBalance: (namespace) => {
|
|
786
|
+
const address = this.getAddress(namespace);
|
|
787
|
+
const caipNetwork = this.getCaipNetwork(namespace);
|
|
788
|
+
if (!caipNetwork || !address) {
|
|
789
|
+
return;
|
|
790
|
+
}
|
|
791
|
+
this.updateNativeBalance(address, caipNetwork?.id, namespace);
|
|
792
|
+
}
|
|
793
|
+
};
|
|
794
|
+
ConnectionController.setClient(this.connectionControllerClient);
|
|
795
|
+
}
|
|
796
|
+
async onConnectExternal(params) {
|
|
797
|
+
const activeChain = ChainController.state.activeChain;
|
|
798
|
+
const namespace = params.chain || activeChain;
|
|
799
|
+
const adapter = this.getAdapter(namespace);
|
|
800
|
+
let shouldUpdateNetwork = true;
|
|
801
|
+
if (params.type === UtilConstantsUtil.CONNECTOR_TYPE_AUTH) {
|
|
802
|
+
const authNamespaces = ConstantsUtil.AUTH_CONNECTOR_SUPPORTED_CHAINS;
|
|
803
|
+
const hasConnectedAuthNamespace = authNamespaces.some(namespace => ConnectorController.getConnectorId(namespace) === ConstantsUtil.CONNECTOR_ID.AUTH);
|
|
804
|
+
if (hasConnectedAuthNamespace && params.chain !== activeChain) {
|
|
805
|
+
shouldUpdateNetwork = false;
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
if (params.chain && params.chain !== activeChain && !params.caipNetwork) {
|
|
809
|
+
const toConnectNetwork = this.getCaipNetworks().find(network => network.chainNamespace === params.chain);
|
|
810
|
+
if (toConnectNetwork && shouldUpdateNetwork) {
|
|
811
|
+
this.setCaipNetwork(toConnectNetwork);
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
if (!namespace) {
|
|
815
|
+
throw new Error('connectExternal: namespace not found');
|
|
816
|
+
}
|
|
817
|
+
if (!adapter) {
|
|
818
|
+
throw new Error('connectExternal: adapter not found');
|
|
819
|
+
}
|
|
820
|
+
const fallbackCaipNetwork = this.getCaipNetwork(namespace);
|
|
821
|
+
const caipNetworkToUse = params.caipNetwork || fallbackCaipNetwork;
|
|
822
|
+
const res = await adapter.connect({
|
|
823
|
+
id: params.id,
|
|
824
|
+
address: params.address,
|
|
825
|
+
info: params.info,
|
|
826
|
+
type: params.type,
|
|
827
|
+
provider: params.provider,
|
|
828
|
+
socialUri: params.socialUri,
|
|
829
|
+
chainId: params.caipNetwork?.id || fallbackCaipNetwork?.id,
|
|
830
|
+
rpcUrl: params.caipNetwork?.rpcUrls?.default?.http?.[0] ||
|
|
831
|
+
fallbackCaipNetwork?.rpcUrls?.default?.http?.[0]
|
|
832
|
+
});
|
|
833
|
+
if (!res) {
|
|
834
|
+
return undefined;
|
|
835
|
+
}
|
|
836
|
+
StorageUtil.addConnectedNamespace(namespace);
|
|
837
|
+
this.syncProvider({ ...res, chainNamespace: namespace });
|
|
838
|
+
this.setStatus('connected', namespace);
|
|
839
|
+
this.syncConnectedWalletInfo(namespace);
|
|
840
|
+
StorageUtil.removeDisconnectedConnectorId(params.id, namespace);
|
|
841
|
+
return { address: res.address, connectedCaipNetwork: caipNetworkToUse };
|
|
842
|
+
}
|
|
843
|
+
async connectInactiveNamespaces(params, connectResult) {
|
|
844
|
+
const isConnectingToAuth = params.type === UtilConstantsUtil.CONNECTOR_TYPE_AUTH;
|
|
845
|
+
const otherAuthNamespaces = HelpersUtil.getOtherAuthNamespaces(connectResult?.connectedCaipNetwork?.chainNamespace);
|
|
846
|
+
const activeCaipNetwork = ChainController.state.activeCaipNetwork;
|
|
847
|
+
const activeAdapter = this.getAdapter(activeCaipNetwork?.chainNamespace);
|
|
848
|
+
if (isConnectingToAuth) {
|
|
849
|
+
await Promise.all(otherAuthNamespaces.map(async (ns) => {
|
|
850
|
+
try {
|
|
851
|
+
const provider = ProviderController.getProvider(ns);
|
|
852
|
+
const caipNetworkToUse = this.getCaipNetwork(ns);
|
|
853
|
+
const adapter = this.getAdapter(ns);
|
|
854
|
+
const res = await adapter?.connect({
|
|
855
|
+
...params,
|
|
856
|
+
provider,
|
|
857
|
+
socialUri: undefined,
|
|
858
|
+
chainId: caipNetworkToUse?.id,
|
|
859
|
+
rpcUrl: caipNetworkToUse?.rpcUrls?.default?.http?.[0]
|
|
860
|
+
});
|
|
861
|
+
if (res) {
|
|
862
|
+
StorageUtil.addConnectedNamespace(ns);
|
|
863
|
+
StorageUtil.removeDisconnectedConnectorId(params.id, ns);
|
|
864
|
+
this.setStatus('connected', ns);
|
|
865
|
+
this.syncConnectedWalletInfo(ns);
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
catch (error) {
|
|
869
|
+
AlertController.warn(ErrorUtil.ALERT_WARNINGS.INACTIVE_NAMESPACE_NOT_CONNECTED.displayMessage, ErrorUtil.ALERT_WARNINGS.INACTIVE_NAMESPACE_NOT_CONNECTED.debugMessage(ns, error instanceof Error ? error.message : undefined), ErrorUtil.ALERT_WARNINGS.INACTIVE_NAMESPACE_NOT_CONNECTED.code);
|
|
870
|
+
}
|
|
871
|
+
}));
|
|
872
|
+
// Make the secure site back to current network after reconnecting the other namespaces
|
|
873
|
+
if (activeCaipNetwork) {
|
|
874
|
+
await activeAdapter?.switchNetwork({
|
|
875
|
+
caipNetwork: activeCaipNetwork
|
|
876
|
+
});
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
getApprovedCaipNetworksData() {
|
|
881
|
+
const providerType = ProviderController.getProviderId(ChainController.state.activeChain);
|
|
882
|
+
if (providerType === UtilConstantsUtil.CONNECTOR_TYPE_WALLET_CONNECT) {
|
|
883
|
+
const namespaces = this.universalProvider?.session?.namespaces;
|
|
884
|
+
return {
|
|
885
|
+
/*
|
|
886
|
+
* MetaMask Wallet only returns 1 namespace in the session object. This makes it imposible
|
|
887
|
+
* to switch to other networks. Setting supportsAllNetworks to true for MetaMask Wallet
|
|
888
|
+
* will make it possible to switch to other networks.
|
|
889
|
+
*/
|
|
890
|
+
supportsAllNetworks: this.universalProvider?.session?.peer?.metadata.name === 'MetaMask Wallet',
|
|
891
|
+
approvedCaipNetworkIds: this.getChainsFromNamespaces(namespaces)
|
|
892
|
+
};
|
|
893
|
+
}
|
|
894
|
+
return { supportsAllNetworks: true, approvedCaipNetworkIds: [] };
|
|
895
|
+
}
|
|
896
|
+
async switchCaipNetwork(caipNetwork) {
|
|
897
|
+
const networkNamespace = caipNetwork.chainNamespace;
|
|
898
|
+
const namespaceAddress = this.getAddressByChainNamespace(caipNetwork.chainNamespace);
|
|
899
|
+
if (namespaceAddress) {
|
|
900
|
+
const providerType = ProviderController.getProviderId(networkNamespace);
|
|
901
|
+
if (caipNetwork.chainNamespace === ChainController.state.activeChain) {
|
|
902
|
+
const adapter = this.getAdapter(networkNamespace);
|
|
903
|
+
await adapter?.switchNetwork({ caipNetwork });
|
|
904
|
+
}
|
|
905
|
+
else {
|
|
906
|
+
this.setCaipNetwork(caipNetwork);
|
|
907
|
+
if (providerType === UtilConstantsUtil.CONNECTOR_TYPE_WALLET_CONNECT) {
|
|
908
|
+
this.syncWalletConnectAccount();
|
|
909
|
+
}
|
|
910
|
+
else {
|
|
911
|
+
const address = this.getAddressByChainNamespace(networkNamespace);
|
|
912
|
+
if (address) {
|
|
913
|
+
this.syncAccount({
|
|
914
|
+
address,
|
|
915
|
+
chainId: caipNetwork.id,
|
|
916
|
+
chainNamespace: networkNamespace
|
|
917
|
+
});
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
else {
|
|
923
|
+
this.setCaipNetwork(caipNetwork);
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
getChainsFromNamespaces(namespaces = {}) {
|
|
927
|
+
return Object.values(namespaces).flatMap((namespace) => {
|
|
928
|
+
const chains = (namespace.chains || []);
|
|
929
|
+
const accountsChains = namespace.accounts.map(account => {
|
|
930
|
+
const { chainId, chainNamespace } = ParseUtil.parseCaipAddress(account);
|
|
931
|
+
return `${chainNamespace}:${chainId}`;
|
|
932
|
+
});
|
|
933
|
+
return Array.from(new Set([...chains, ...accountsChains]));
|
|
934
|
+
});
|
|
935
|
+
}
|
|
936
|
+
// -- Adapter Initialization ---------------------------------------------------
|
|
937
|
+
createAdapters(blueprints) {
|
|
938
|
+
this.createClients();
|
|
939
|
+
return this.chainNamespaces.reduce((adapters, namespace) => {
|
|
940
|
+
const blueprint = blueprints?.find(b => b.namespace === namespace);
|
|
941
|
+
if (blueprint) {
|
|
942
|
+
blueprint.construct({
|
|
943
|
+
namespace,
|
|
944
|
+
projectId: this.options?.projectId,
|
|
945
|
+
networks: this.caipNetworks?.filter(({ chainNamespace }) => chainNamespace === namespace)
|
|
946
|
+
});
|
|
947
|
+
adapters[namespace] = blueprint;
|
|
948
|
+
}
|
|
949
|
+
else {
|
|
950
|
+
adapters[namespace] = new UniversalAdapter({
|
|
951
|
+
namespace,
|
|
952
|
+
networks: this.getCaipNetworks()
|
|
953
|
+
});
|
|
954
|
+
}
|
|
955
|
+
return adapters;
|
|
956
|
+
// eslint-disable-next-line @typescript-eslint/prefer-reduce-type-parameter
|
|
957
|
+
}, {});
|
|
958
|
+
}
|
|
959
|
+
async initChainAdapter(namespace) {
|
|
960
|
+
this.onConnectors(namespace);
|
|
961
|
+
this.listenAdapter(namespace);
|
|
962
|
+
const adapter = this.getAdapter(namespace);
|
|
963
|
+
if (!adapter) {
|
|
964
|
+
throw new Error('adapter not found');
|
|
965
|
+
}
|
|
966
|
+
await adapter.syncConnectors();
|
|
967
|
+
await this.createUniversalProviderForAdapter(namespace);
|
|
968
|
+
}
|
|
969
|
+
async initChainAdapters() {
|
|
970
|
+
await Promise.all(this.chainNamespaces.map(async (namespace) => {
|
|
971
|
+
await this.initChainAdapter(namespace);
|
|
972
|
+
}));
|
|
973
|
+
this.initAdapterController();
|
|
974
|
+
}
|
|
975
|
+
onConnectors(chainNamespace) {
|
|
976
|
+
const adapter = this.getAdapter(chainNamespace);
|
|
977
|
+
adapter?.on('connectors', this.setConnectors.bind(this));
|
|
978
|
+
}
|
|
979
|
+
listenAdapter(chainNamespace) {
|
|
980
|
+
const adapter = this.getAdapter(chainNamespace);
|
|
981
|
+
if (!adapter) {
|
|
982
|
+
return;
|
|
983
|
+
}
|
|
984
|
+
const connectionStatus = StorageUtil.getConnectionStatus();
|
|
985
|
+
if (OptionsController.state.enableReconnect === false) {
|
|
986
|
+
this.setStatus('disconnected', chainNamespace);
|
|
987
|
+
}
|
|
988
|
+
else if (connectionStatus === 'connected') {
|
|
989
|
+
this.setStatus('connecting', chainNamespace);
|
|
990
|
+
}
|
|
991
|
+
else if (connectionStatus === 'disconnected') {
|
|
992
|
+
/*
|
|
993
|
+
* Address cache is kept after disconnecting from the wallet
|
|
994
|
+
* but should be cleared if appkit is launched in disconnected state
|
|
995
|
+
*/
|
|
996
|
+
StorageUtil.clearAddressCache();
|
|
997
|
+
this.setStatus(connectionStatus, chainNamespace);
|
|
998
|
+
}
|
|
999
|
+
else {
|
|
1000
|
+
this.setStatus(connectionStatus, chainNamespace);
|
|
1001
|
+
}
|
|
1002
|
+
adapter.on('switchNetwork', ({ address, chainId }) => {
|
|
1003
|
+
const caipNetwork = this.getCaipNetworks().find(n => n.id.toString() === chainId.toString() ||
|
|
1004
|
+
n.caipNetworkId.toString() === chainId.toString());
|
|
1005
|
+
const isSameNamespace = ChainController.state.activeChain === chainNamespace;
|
|
1006
|
+
const accountAddress = ChainController.state.chains.get(chainNamespace)?.accountState?.address;
|
|
1007
|
+
if (caipNetwork) {
|
|
1008
|
+
const account = isSameNamespace && address ? address : accountAddress;
|
|
1009
|
+
if (account) {
|
|
1010
|
+
this.syncAccount({ address: account, chainId: caipNetwork.id, chainNamespace });
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
else {
|
|
1014
|
+
this.setUnsupportedNetwork(chainId);
|
|
1015
|
+
}
|
|
1016
|
+
});
|
|
1017
|
+
adapter.on('disconnect', () => {
|
|
1018
|
+
const isMultiWallet = this.remoteFeatures.multiWallet;
|
|
1019
|
+
const allConnections = Array.from(ConnectionController.state.connections.values()).flat();
|
|
1020
|
+
this.onDisconnectNamespace({
|
|
1021
|
+
chainNamespace,
|
|
1022
|
+
closeModal: !isMultiWallet || allConnections.length === 0
|
|
1023
|
+
});
|
|
1024
|
+
});
|
|
1025
|
+
adapter.on('connections', connections => {
|
|
1026
|
+
this.setConnections(connections, chainNamespace);
|
|
1027
|
+
});
|
|
1028
|
+
adapter.on('pendingTransactions', () => {
|
|
1029
|
+
const address = this.getAddress(chainNamespace);
|
|
1030
|
+
const activeCaipNetwork = ChainController.state.activeCaipNetwork;
|
|
1031
|
+
if (!address || !activeCaipNetwork?.id) {
|
|
1032
|
+
return;
|
|
1033
|
+
}
|
|
1034
|
+
this.updateNativeBalance(address, activeCaipNetwork.id, activeCaipNetwork.chainNamespace);
|
|
1035
|
+
});
|
|
1036
|
+
adapter.on('accountChanged', ({ address, chainId, connector }) => {
|
|
1037
|
+
this.handlePreviousConnectorConnection(connector);
|
|
1038
|
+
const isActiveChain = ChainController.state.activeChain === chainNamespace;
|
|
1039
|
+
if (connector?.provider) {
|
|
1040
|
+
this.syncProvider({
|
|
1041
|
+
id: connector.id,
|
|
1042
|
+
type: connector.type,
|
|
1043
|
+
provider: connector?.provider,
|
|
1044
|
+
chainNamespace
|
|
1045
|
+
});
|
|
1046
|
+
this.syncConnectedWalletInfo(chainNamespace);
|
|
1047
|
+
}
|
|
1048
|
+
const namespaceNetworkId = ChainController.getNetworkData(chainNamespace)?.caipNetwork?.id;
|
|
1049
|
+
const syncAccountChainId = chainId || namespaceNetworkId;
|
|
1050
|
+
if (isActiveChain && syncAccountChainId) {
|
|
1051
|
+
this.syncAccount({
|
|
1052
|
+
address,
|
|
1053
|
+
chainId: syncAccountChainId,
|
|
1054
|
+
chainNamespace
|
|
1055
|
+
});
|
|
1056
|
+
}
|
|
1057
|
+
else if (!isActiveChain && syncAccountChainId) {
|
|
1058
|
+
this.syncAccountInfo(address, syncAccountChainId, chainNamespace);
|
|
1059
|
+
this.syncBalance({ address, chainId: syncAccountChainId, chainNamespace });
|
|
1060
|
+
}
|
|
1061
|
+
else {
|
|
1062
|
+
this.syncAccountInfo(address, chainId, chainNamespace);
|
|
1063
|
+
}
|
|
1064
|
+
StorageUtil.addConnectedNamespace(chainNamespace);
|
|
1065
|
+
});
|
|
1066
|
+
}
|
|
1067
|
+
/**
|
|
1068
|
+
* Checks the incoming connector and handles the previous connection in the connector's namespace, and if necessary (i.e multi-wallet is disabled) disconnects the previous connector
|
|
1069
|
+
* @param connector
|
|
1070
|
+
*/
|
|
1071
|
+
async handlePreviousConnectorConnection(connector) {
|
|
1072
|
+
const namespace = connector?.chain;
|
|
1073
|
+
const newConnectorId = connector?.id;
|
|
1074
|
+
const currentConnectorId = ConnectorController.getConnectorId(namespace);
|
|
1075
|
+
const isMultiWalletEnabled = OptionsController.state.remoteFeatures?.multiWallet;
|
|
1076
|
+
const hasNewConnectorConnected = currentConnectorId !== newConnectorId;
|
|
1077
|
+
const shouldDisconnectPreviousConnector = namespace &&
|
|
1078
|
+
newConnectorId &&
|
|
1079
|
+
currentConnectorId &&
|
|
1080
|
+
hasNewConnectorConnected &&
|
|
1081
|
+
!isMultiWalletEnabled;
|
|
1082
|
+
try {
|
|
1083
|
+
if (shouldDisconnectPreviousConnector) {
|
|
1084
|
+
await ConnectionController.disconnect({ id: currentConnectorId, namespace });
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
catch (error) {
|
|
1088
|
+
console.warn('Error disconnecting previous connector', error);
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
async createUniversalProviderForAdapter(chainNamespace) {
|
|
1092
|
+
await this.getUniversalProvider();
|
|
1093
|
+
if (this.universalProvider) {
|
|
1094
|
+
await this.chainAdapters?.[chainNamespace]?.setUniversalProvider?.(this.universalProvider);
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
// -- Connection Sync ---------------------------------------------------
|
|
1098
|
+
async syncExistingConnection() {
|
|
1099
|
+
await Promise.allSettled(this.chainNamespaces.map(namespace => this.syncNamespaceConnection(namespace)));
|
|
1100
|
+
}
|
|
1101
|
+
async unSyncExistingConnection() {
|
|
1102
|
+
try {
|
|
1103
|
+
await Promise.allSettled(this.chainNamespaces.map(namespace => ConnectionController.disconnect({ namespace, initialDisconnect: true })));
|
|
1104
|
+
}
|
|
1105
|
+
catch (error) {
|
|
1106
|
+
// eslint-disable-next-line no-console
|
|
1107
|
+
console.error('Error disconnecting existing connections:', error);
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
async reconnectWalletConnect() {
|
|
1111
|
+
await this.syncWalletConnectAccount();
|
|
1112
|
+
const address = this.getAddress();
|
|
1113
|
+
if (!this.getCaipAddress()) {
|
|
1114
|
+
StorageUtil.deleteRecentWallet();
|
|
1115
|
+
}
|
|
1116
|
+
const recentWallet = StorageUtil.getRecentWallet();
|
|
1117
|
+
EventsController.sendEvent({
|
|
1118
|
+
type: 'track',
|
|
1119
|
+
event: 'CONNECT_SUCCESS',
|
|
1120
|
+
address,
|
|
1121
|
+
properties: {
|
|
1122
|
+
method: CoreHelperUtil.isMobile() ? 'mobile' : 'qrcode',
|
|
1123
|
+
name: recentWallet?.name || 'Unknown',
|
|
1124
|
+
reconnect: true,
|
|
1125
|
+
view: RouterController.state.view,
|
|
1126
|
+
walletRank: recentWallet?.order
|
|
1127
|
+
}
|
|
1128
|
+
});
|
|
1129
|
+
}
|
|
1130
|
+
async syncNamespaceConnection(namespace) {
|
|
1131
|
+
try {
|
|
1132
|
+
if (namespace === ConstantsUtil.CHAIN.EVM && CoreHelperUtil.isSafeApp()) {
|
|
1133
|
+
ConnectorController.setConnectorId(ConstantsUtil.CONNECTOR_ID.SAFE, namespace);
|
|
1134
|
+
}
|
|
1135
|
+
const connectorId = ConnectorController.getConnectorId(namespace);
|
|
1136
|
+
this.setStatus('connecting', namespace);
|
|
1137
|
+
switch (connectorId) {
|
|
1138
|
+
case ConstantsUtil.CONNECTOR_ID.WALLET_CONNECT:
|
|
1139
|
+
await this.reconnectWalletConnect();
|
|
1140
|
+
break;
|
|
1141
|
+
case ConstantsUtil.CONNECTOR_ID.AUTH:
|
|
1142
|
+
// Handled during initialization of adapters' auth provider
|
|
1143
|
+
break;
|
|
1144
|
+
default:
|
|
1145
|
+
await this.syncAdapterConnection(namespace);
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
catch (err) {
|
|
1149
|
+
console.warn("AppKit couldn't sync existing connection", err);
|
|
1150
|
+
this.setStatus('disconnected', namespace);
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
onDisconnectNamespace(options) {
|
|
1154
|
+
const { chainNamespace, closeModal } = options || {};
|
|
1155
|
+
ChainController.resetAccount(chainNamespace);
|
|
1156
|
+
ChainController.resetNetwork(chainNamespace);
|
|
1157
|
+
StorageUtil.removeConnectedNamespace(chainNamespace);
|
|
1158
|
+
const namespaces = Array.from(ChainController.state.chains.keys());
|
|
1159
|
+
const namespacesToDisconnect = chainNamespace ? [chainNamespace] : namespaces;
|
|
1160
|
+
namespacesToDisconnect.forEach(ns => StorageUtil.addDisconnectedConnectorId(ConnectorController.getConnectorId(ns) || '', ns));
|
|
1161
|
+
ConnectorController.removeConnectorId(chainNamespace);
|
|
1162
|
+
ProviderController.resetChain(chainNamespace);
|
|
1163
|
+
this.setUser(null, chainNamespace);
|
|
1164
|
+
this.setStatus('disconnected', chainNamespace);
|
|
1165
|
+
this.setConnectedWalletInfo(null, chainNamespace);
|
|
1166
|
+
if (closeModal !== false) {
|
|
1167
|
+
ModalController.close();
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
async syncAdapterConnections() {
|
|
1171
|
+
await Promise.allSettled(this.chainNamespaces.map(namespace => {
|
|
1172
|
+
const adapter = this.getAdapter(namespace);
|
|
1173
|
+
const caipAddress = this.getCaipAddress(namespace);
|
|
1174
|
+
const caipNetwork = this.getCaipNetwork(namespace);
|
|
1175
|
+
return adapter?.syncConnections({
|
|
1176
|
+
connectToFirstConnector: !caipAddress,
|
|
1177
|
+
caipNetwork
|
|
1178
|
+
});
|
|
1179
|
+
}));
|
|
1180
|
+
}
|
|
1181
|
+
async syncAdapterConnection(namespace) {
|
|
1182
|
+
const adapter = this.getAdapter(namespace);
|
|
1183
|
+
const caipNetwork = this.getCaipNetwork(namespace);
|
|
1184
|
+
const connectorId = ConnectorController.getConnectorId(namespace);
|
|
1185
|
+
const connectors = ConnectorController.getConnectors(namespace);
|
|
1186
|
+
const connector = connectors.find(c => c.id === connectorId);
|
|
1187
|
+
try {
|
|
1188
|
+
if (!adapter || !connector) {
|
|
1189
|
+
throw new Error(`Adapter or connector not found for namespace ${namespace}`);
|
|
1190
|
+
}
|
|
1191
|
+
if (!caipNetwork?.id) {
|
|
1192
|
+
throw new Error('CaipNetwork not found');
|
|
1193
|
+
}
|
|
1194
|
+
const connection = await adapter?.syncConnection({
|
|
1195
|
+
namespace,
|
|
1196
|
+
id: connector.id,
|
|
1197
|
+
chainId: caipNetwork.id,
|
|
1198
|
+
rpcUrl: caipNetwork?.rpcUrls?.default?.http?.[0]
|
|
1199
|
+
});
|
|
1200
|
+
if (connection) {
|
|
1201
|
+
this.syncProvider({ ...connection, chainNamespace: namespace });
|
|
1202
|
+
await this.syncAccount({ ...connection, chainNamespace: namespace });
|
|
1203
|
+
this.setStatus('connected', namespace);
|
|
1204
|
+
EventsController.sendEvent({
|
|
1205
|
+
type: 'track',
|
|
1206
|
+
event: 'CONNECT_SUCCESS',
|
|
1207
|
+
address: connection.address,
|
|
1208
|
+
properties: {
|
|
1209
|
+
method: 'browser',
|
|
1210
|
+
name: connector.info?.name || connector.name || 'Unknown',
|
|
1211
|
+
reconnect: true,
|
|
1212
|
+
view: RouterController.state.view,
|
|
1213
|
+
walletRank: connector?.explorerWallet?.order
|
|
1214
|
+
}
|
|
1215
|
+
});
|
|
1216
|
+
}
|
|
1217
|
+
else {
|
|
1218
|
+
this.setStatus('disconnected', namespace);
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
catch (e) {
|
|
1222
|
+
this.onDisconnectNamespace({ chainNamespace: namespace, closeModal: false });
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
async syncWalletConnectAccount() {
|
|
1226
|
+
const sessionNamespaces = Object.keys(this.universalProvider?.session?.namespaces || {});
|
|
1227
|
+
const syncTasks = this.chainNamespaces.map(async (chainNamespace) => {
|
|
1228
|
+
const adapter = this.getAdapter(chainNamespace);
|
|
1229
|
+
if (!adapter) {
|
|
1230
|
+
return;
|
|
1231
|
+
}
|
|
1232
|
+
const namespaceAccounts = this.universalProvider?.session?.namespaces?.[chainNamespace]?.accounts || [];
|
|
1233
|
+
// We try and find the address for this network in the session object.
|
|
1234
|
+
const activeChainId = ChainController.state.activeCaipNetwork?.id;
|
|
1235
|
+
const sessionAddress = namespaceAccounts.find(account => {
|
|
1236
|
+
const { chainId } = ParseUtil.parseCaipAddress(account);
|
|
1237
|
+
return chainId === activeChainId?.toString();
|
|
1238
|
+
}) || namespaceAccounts[0];
|
|
1239
|
+
if (sessionAddress) {
|
|
1240
|
+
const caipAddress = ParseUtil.validateCaipAddress(sessionAddress);
|
|
1241
|
+
const { chainId, address } = ParseUtil.parseCaipAddress(caipAddress);
|
|
1242
|
+
ProviderController.setProviderId(chainNamespace, UtilConstantsUtil.CONNECTOR_TYPE_WALLET_CONNECT);
|
|
1243
|
+
if (this.caipNetworks &&
|
|
1244
|
+
ChainController.state.activeCaipNetwork &&
|
|
1245
|
+
adapter.namespace !== ConstantsUtil.CHAIN.EVM) {
|
|
1246
|
+
const provider = adapter.getWalletConnectProvider({
|
|
1247
|
+
caipNetworks: this.getCaipNetworks(),
|
|
1248
|
+
provider: this.universalProvider,
|
|
1249
|
+
activeCaipNetwork: ChainController.state.activeCaipNetwork
|
|
1250
|
+
});
|
|
1251
|
+
ProviderController.setProvider(chainNamespace, provider);
|
|
1252
|
+
}
|
|
1253
|
+
else {
|
|
1254
|
+
ProviderController.setProvider(chainNamespace, this.universalProvider);
|
|
1255
|
+
}
|
|
1256
|
+
ConnectorController.setConnectorId(ConstantsUtil.CONNECTOR_ID.WALLET_CONNECT, chainNamespace);
|
|
1257
|
+
StorageUtil.addConnectedNamespace(chainNamespace);
|
|
1258
|
+
await this.syncAccount({
|
|
1259
|
+
address,
|
|
1260
|
+
chainId,
|
|
1261
|
+
chainNamespace
|
|
1262
|
+
});
|
|
1263
|
+
}
|
|
1264
|
+
else if (sessionNamespaces.includes(chainNamespace)) {
|
|
1265
|
+
this.setStatus('disconnected', chainNamespace);
|
|
1266
|
+
}
|
|
1267
|
+
const data = this.getApprovedCaipNetworksData();
|
|
1268
|
+
this.syncConnectedWalletInfo(chainNamespace);
|
|
1269
|
+
ChainController.setApprovedCaipNetworksData(chainNamespace, {
|
|
1270
|
+
approvedCaipNetworkIds: data.approvedCaipNetworkIds,
|
|
1271
|
+
supportsAllNetworks: data.supportsAllNetworks
|
|
1272
|
+
});
|
|
1273
|
+
});
|
|
1274
|
+
await Promise.all(syncTasks);
|
|
1275
|
+
}
|
|
1276
|
+
syncProvider({ type, provider, id, chainNamespace }) {
|
|
1277
|
+
ProviderController.setProviderId(chainNamespace, type);
|
|
1278
|
+
ProviderController.setProvider(chainNamespace, provider);
|
|
1279
|
+
ConnectorController.setConnectorId(id, chainNamespace);
|
|
1280
|
+
}
|
|
1281
|
+
async syncAccount(params) {
|
|
1282
|
+
const isActiveNamespace = params.chainNamespace === ChainController.state.activeChain;
|
|
1283
|
+
const networkOfChain = ChainController.getCaipNetworkByNamespace(params.chainNamespace, params.chainId);
|
|
1284
|
+
const { address, chainId, chainNamespace } = params;
|
|
1285
|
+
const { chainId: activeChainId } = StorageUtil.getActiveNetworkProps();
|
|
1286
|
+
const chainIdToUse = networkOfChain?.id || activeChainId;
|
|
1287
|
+
const isUnsupportedNetwork = ChainController.state.activeCaipNetwork?.name === ConstantsUtil.UNSUPPORTED_NETWORK_NAME;
|
|
1288
|
+
const shouldSupportAllNetworks = ChainController.getNetworkProp('supportsAllNetworks', chainNamespace);
|
|
1289
|
+
this.setStatus('connected', chainNamespace);
|
|
1290
|
+
if (isUnsupportedNetwork && !shouldSupportAllNetworks) {
|
|
1291
|
+
return;
|
|
1292
|
+
}
|
|
1293
|
+
if (chainIdToUse) {
|
|
1294
|
+
let caipNetwork = this.getCaipNetworks().find(n => n.id.toString() === chainIdToUse.toString());
|
|
1295
|
+
let fallbackCaipNetwork = this.getCaipNetworks().find(n => n.chainNamespace === chainNamespace);
|
|
1296
|
+
// If doesn't support all networks, we need to use approved networks
|
|
1297
|
+
if (!shouldSupportAllNetworks && !caipNetwork && !fallbackCaipNetwork) {
|
|
1298
|
+
// Connection can be requested for a chain that is not supported by the wallet so we need to use approved networks here
|
|
1299
|
+
const caipNetworkIds = this.getApprovedCaipNetworkIds() || [];
|
|
1300
|
+
const caipNetworkId = caipNetworkIds.find(id => ParseUtil.parseCaipNetworkId(id)?.chainId === chainIdToUse.toString());
|
|
1301
|
+
const fallBackCaipNetworkId = caipNetworkIds.find(id => ParseUtil.parseCaipNetworkId(id)?.chainNamespace === chainNamespace);
|
|
1302
|
+
caipNetwork = this.getCaipNetworks().find(n => n.caipNetworkId === caipNetworkId);
|
|
1303
|
+
fallbackCaipNetwork = this.getCaipNetworks().find(n => n.caipNetworkId === fallBackCaipNetworkId ||
|
|
1304
|
+
// This is a workaround used in Solana network to support deprecated caipNetworkId
|
|
1305
|
+
('deprecatedCaipNetworkId' in n && n.deprecatedCaipNetworkId === fallBackCaipNetworkId));
|
|
1306
|
+
}
|
|
1307
|
+
const network = caipNetwork || fallbackCaipNetwork;
|
|
1308
|
+
if (network?.chainNamespace === ChainController.state.activeChain) {
|
|
1309
|
+
// If the network is unsupported and the user doesn't allow unsupported chains, we show the unsupported chain UI
|
|
1310
|
+
if (OptionsController.state.enableNetworkSwitch &&
|
|
1311
|
+
!OptionsController.state.allowUnsupportedChain &&
|
|
1312
|
+
ChainController.state.activeCaipNetwork?.name === ConstantsUtil.UNSUPPORTED_NETWORK_NAME) {
|
|
1313
|
+
ChainController.showUnsupportedChainUI();
|
|
1314
|
+
}
|
|
1315
|
+
else {
|
|
1316
|
+
this.setCaipNetwork(network);
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
else if (!isActiveNamespace) {
|
|
1320
|
+
if (networkOfChain) {
|
|
1321
|
+
this.setCaipNetworkOfNamespace(networkOfChain, chainNamespace);
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
this.syncConnectedWalletInfo(chainNamespace);
|
|
1325
|
+
const currentAddress = this.getAddress(chainNamespace);
|
|
1326
|
+
if (!HelpersUtil.isLowerCaseMatch(address, currentAddress)) {
|
|
1327
|
+
this.syncAccountInfo(address, network?.id, chainNamespace);
|
|
1328
|
+
}
|
|
1329
|
+
if (isActiveNamespace) {
|
|
1330
|
+
await this.syncBalance({ address, chainId: network?.id, chainNamespace });
|
|
1331
|
+
}
|
|
1332
|
+
else {
|
|
1333
|
+
await this.syncBalance({ address, chainId: networkOfChain?.id, chainNamespace });
|
|
1334
|
+
}
|
|
1335
|
+
this.syncIdentity({
|
|
1336
|
+
address,
|
|
1337
|
+
chainId,
|
|
1338
|
+
chainNamespace
|
|
1339
|
+
});
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
async syncAccountInfo(address, chainId, chainNamespace) {
|
|
1343
|
+
const caipAddress = this.getCaipAddress(chainNamespace);
|
|
1344
|
+
const newChainId = chainId || caipAddress?.split(':')[1];
|
|
1345
|
+
if (!newChainId) {
|
|
1346
|
+
return;
|
|
1347
|
+
}
|
|
1348
|
+
const newCaipAddress = `${chainNamespace}:${newChainId}:${address}`;
|
|
1349
|
+
this.setCaipAddress(newCaipAddress, chainNamespace, true);
|
|
1350
|
+
await this.syncIdentity({
|
|
1351
|
+
address,
|
|
1352
|
+
chainId: newChainId,
|
|
1353
|
+
chainNamespace
|
|
1354
|
+
});
|
|
1355
|
+
}
|
|
1356
|
+
async syncReownName(address, chainNamespace) {
|
|
1357
|
+
try {
|
|
1358
|
+
const registeredWcNames = await this.getReownName(address);
|
|
1359
|
+
if (registeredWcNames[0]) {
|
|
1360
|
+
const wcName = registeredWcNames[0];
|
|
1361
|
+
this.setProfileName(wcName.name, chainNamespace);
|
|
1362
|
+
}
|
|
1363
|
+
else {
|
|
1364
|
+
this.setProfileName(null, chainNamespace);
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
catch {
|
|
1368
|
+
this.setProfileName(null, chainNamespace);
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
syncConnectedWalletInfo(chainNamespace) {
|
|
1372
|
+
const connectorId = ConnectorController.getConnectorId(chainNamespace);
|
|
1373
|
+
const providerType = ProviderController.getProviderId(chainNamespace);
|
|
1374
|
+
if (providerType === UtilConstantsUtil.CONNECTOR_TYPE_ANNOUNCED ||
|
|
1375
|
+
providerType === UtilConstantsUtil.CONNECTOR_TYPE_INJECTED) {
|
|
1376
|
+
if (connectorId) {
|
|
1377
|
+
const connectors = this.getConnectors();
|
|
1378
|
+
const connector = connectors.find(c => {
|
|
1379
|
+
const isConnectorId = c.id === connectorId;
|
|
1380
|
+
const isRdns = c.info?.rdns === connectorId;
|
|
1381
|
+
const hasMultiChainConnector = c.connectors?.some(_c => _c.id === connectorId || _c.info?.rdns === connectorId);
|
|
1382
|
+
return isConnectorId || isRdns || Boolean(hasMultiChainConnector);
|
|
1383
|
+
});
|
|
1384
|
+
if (connector) {
|
|
1385
|
+
const { info, name, imageUrl } = connector;
|
|
1386
|
+
const icon = imageUrl || this.getConnectorImage(connector);
|
|
1387
|
+
this.setConnectedWalletInfo({ name, icon, ...info }, chainNamespace);
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
else if (providerType === UtilConstantsUtil.CONNECTOR_TYPE_WALLET_CONNECT) {
|
|
1392
|
+
const provider = ProviderController.getProvider(chainNamespace);
|
|
1393
|
+
if (provider?.session) {
|
|
1394
|
+
this.setConnectedWalletInfo({
|
|
1395
|
+
...provider.session.peer.metadata,
|
|
1396
|
+
name: provider.session.peer.metadata.name,
|
|
1397
|
+
icon: provider.session.peer.metadata.icons?.[0]
|
|
1398
|
+
}, chainNamespace);
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
else if (connectorId) {
|
|
1402
|
+
if (connectorId === ConstantsUtil.CONNECTOR_ID.COINBASE_SDK ||
|
|
1403
|
+
connectorId === ConstantsUtil.CONNECTOR_ID.COINBASE) {
|
|
1404
|
+
const connector = this.getConnectors().find(c => c.id === connectorId);
|
|
1405
|
+
const name = connector?.name || 'Coinbase Wallet';
|
|
1406
|
+
const icon = connector?.imageUrl || this.getConnectorImage(connector);
|
|
1407
|
+
const info = connector?.info;
|
|
1408
|
+
this.setConnectedWalletInfo({
|
|
1409
|
+
...info,
|
|
1410
|
+
name,
|
|
1411
|
+
icon
|
|
1412
|
+
}, chainNamespace);
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
async syncBalance(params) {
|
|
1417
|
+
const caipNetwork = NetworkUtil.getNetworksByNamespace(this.getCaipNetworks(), params.chainNamespace).find(n => n.id.toString() === params.chainId?.toString());
|
|
1418
|
+
if (!caipNetwork || !params.chainId) {
|
|
1419
|
+
return;
|
|
1420
|
+
}
|
|
1421
|
+
await this.updateNativeBalance(params.address, params.chainId, params.chainNamespace);
|
|
1422
|
+
}
|
|
1423
|
+
async ready() {
|
|
1424
|
+
await this.readyPromise;
|
|
1425
|
+
}
|
|
1426
|
+
async updateNativeBalance(address, chainId, namespace) {
|
|
1427
|
+
const adapter = this.getAdapter(namespace);
|
|
1428
|
+
const caipNetwork = ChainController.getCaipNetworkByNamespace(namespace, chainId);
|
|
1429
|
+
if (adapter) {
|
|
1430
|
+
const balance = await adapter.getBalance({
|
|
1431
|
+
address,
|
|
1432
|
+
chainId,
|
|
1433
|
+
caipNetwork,
|
|
1434
|
+
tokens: this.options.tokens
|
|
1435
|
+
});
|
|
1436
|
+
this.setBalance(balance.balance, balance.symbol, namespace);
|
|
1437
|
+
return balance;
|
|
1438
|
+
}
|
|
1439
|
+
return undefined;
|
|
1440
|
+
}
|
|
1441
|
+
// -- Universal Provider ---------------------------------------------------
|
|
1442
|
+
async initializeUniversalAdapter() {
|
|
1443
|
+
const logger = LoggerUtil.createLogger((error, ...args) => {
|
|
1444
|
+
if (error) {
|
|
1445
|
+
this.handleAlertError(error);
|
|
1446
|
+
}
|
|
1447
|
+
// eslint-disable-next-line no-console
|
|
1448
|
+
console.error(...args);
|
|
1449
|
+
});
|
|
1450
|
+
const universalProviderOptions = {
|
|
1451
|
+
projectId: this.options?.projectId,
|
|
1452
|
+
metadata: {
|
|
1453
|
+
name: this.options?.metadata ? this.options?.metadata.name : '',
|
|
1454
|
+
description: this.options?.metadata ? this.options?.metadata.description : '',
|
|
1455
|
+
url: this.options?.metadata ? this.options?.metadata.url : '',
|
|
1456
|
+
icons: this.options?.metadata ? this.options?.metadata.icons : ['']
|
|
1457
|
+
},
|
|
1458
|
+
logger
|
|
1459
|
+
};
|
|
1460
|
+
OptionsController.setManualWCControl(Boolean(this.options?.manualWCControl));
|
|
1461
|
+
this.universalProvider =
|
|
1462
|
+
this.options.universalProvider ?? (await UniversalProvider.init(universalProviderOptions));
|
|
1463
|
+
const originalDisconnect = this.universalProvider.disconnect.bind(this.universalProvider);
|
|
1464
|
+
this.universalProvider.disconnect = async () => {
|
|
1465
|
+
try {
|
|
1466
|
+
return await originalDisconnect();
|
|
1467
|
+
}
|
|
1468
|
+
catch (error) {
|
|
1469
|
+
if (error instanceof Error) {
|
|
1470
|
+
const isAlreadyDisconnected = error.message.includes('Missing or invalid. Record was recently deleted');
|
|
1471
|
+
if (isAlreadyDisconnected) {
|
|
1472
|
+
return undefined;
|
|
1473
|
+
}
|
|
1474
|
+
}
|
|
1475
|
+
throw error;
|
|
1476
|
+
}
|
|
1477
|
+
};
|
|
1478
|
+
if (OptionsController.state.enableReconnect === false && this.universalProvider.session) {
|
|
1479
|
+
await this.universalProvider.disconnect();
|
|
1480
|
+
}
|
|
1481
|
+
this.listenWalletConnect();
|
|
1482
|
+
}
|
|
1483
|
+
listenWalletConnect() {
|
|
1484
|
+
if (this.universalProvider) {
|
|
1485
|
+
this.chainNamespaces.forEach(namespace => {
|
|
1486
|
+
WcHelpersUtil.listenWcProvider({
|
|
1487
|
+
universalProvider: this.universalProvider,
|
|
1488
|
+
namespace,
|
|
1489
|
+
onDisplayUri: uri => {
|
|
1490
|
+
ConnectionController.setUri(uri);
|
|
1491
|
+
},
|
|
1492
|
+
onConnect: accounts => {
|
|
1493
|
+
const { address } = CoreHelperUtil.getAccount(accounts[0]);
|
|
1494
|
+
ConnectionController.finalizeWcConnection(address);
|
|
1495
|
+
},
|
|
1496
|
+
onDisconnect: () => {
|
|
1497
|
+
if (ChainController.state.noAdapters) {
|
|
1498
|
+
this.resetAccount(namespace);
|
|
1499
|
+
}
|
|
1500
|
+
ConnectionController.resetWcConnection();
|
|
1501
|
+
},
|
|
1502
|
+
onChainChanged: chainId => {
|
|
1503
|
+
const activeNamespace = ChainController.state.activeChain;
|
|
1504
|
+
const isCurrentConnectorWalletConnect = activeNamespace &&
|
|
1505
|
+
ConnectorController.state.activeConnectorIds[activeNamespace] ===
|
|
1506
|
+
ConstantsUtil.CONNECTOR_ID.WALLET_CONNECT;
|
|
1507
|
+
if (activeNamespace === namespace &&
|
|
1508
|
+
(ChainController.state.noAdapters || isCurrentConnectorWalletConnect)) {
|
|
1509
|
+
const caipNetwork = this.getCaipNetworks().find(n => n.id.toString() === chainId.toString() ||
|
|
1510
|
+
n.caipNetworkId.toString() === chainId.toString());
|
|
1511
|
+
const currentCaipNetwork = this.getCaipNetwork();
|
|
1512
|
+
if (!caipNetwork) {
|
|
1513
|
+
this.setUnsupportedNetwork(chainId);
|
|
1514
|
+
return;
|
|
1515
|
+
}
|
|
1516
|
+
if (currentCaipNetwork?.id.toString() !== caipNetwork?.id.toString() &&
|
|
1517
|
+
currentCaipNetwork?.chainNamespace === caipNetwork?.chainNamespace) {
|
|
1518
|
+
this.setCaipNetwork(caipNetwork);
|
|
1519
|
+
}
|
|
1520
|
+
}
|
|
1521
|
+
},
|
|
1522
|
+
onAccountsChanged: accounts => {
|
|
1523
|
+
const activeNamespace = ChainController.state.activeChain;
|
|
1524
|
+
const isCurrentConnectorWalletConnect = activeNamespace &&
|
|
1525
|
+
ConnectorController.state.activeConnectorIds[activeNamespace] ===
|
|
1526
|
+
ConstantsUtil.CONNECTOR_ID.WALLET_CONNECT;
|
|
1527
|
+
if (activeNamespace === namespace &&
|
|
1528
|
+
(ChainController.state.noAdapters || isCurrentConnectorWalletConnect)) {
|
|
1529
|
+
const account = accounts?.[0];
|
|
1530
|
+
if (account) {
|
|
1531
|
+
this.syncAccount({
|
|
1532
|
+
address: account.address,
|
|
1533
|
+
chainId: account.chainId,
|
|
1534
|
+
chainNamespace: account.chainNamespace
|
|
1535
|
+
});
|
|
1536
|
+
}
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
});
|
|
1540
|
+
});
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1543
|
+
createUniversalProvider() {
|
|
1544
|
+
if (!this.universalProviderInitPromise &&
|
|
1545
|
+
CoreHelperUtil.isClient() &&
|
|
1546
|
+
this.options?.projectId) {
|
|
1547
|
+
this.universalProviderInitPromise = this.initializeUniversalAdapter();
|
|
1548
|
+
}
|
|
1549
|
+
return this.universalProviderInitPromise;
|
|
1550
|
+
}
|
|
1551
|
+
async getUniversalProvider() {
|
|
1552
|
+
if (!this.universalProvider) {
|
|
1553
|
+
try {
|
|
1554
|
+
await this.createUniversalProvider();
|
|
1555
|
+
}
|
|
1556
|
+
catch (err) {
|
|
1557
|
+
EventsController.sendEvent({
|
|
1558
|
+
type: 'error',
|
|
1559
|
+
event: 'INTERNAL_SDK_ERROR',
|
|
1560
|
+
properties: {
|
|
1561
|
+
errorType: 'UniversalProviderInitError',
|
|
1562
|
+
errorMessage: err instanceof Error ? err.message : 'Unknown',
|
|
1563
|
+
uncaught: false
|
|
1564
|
+
}
|
|
1565
|
+
});
|
|
1566
|
+
// eslint-disable-next-line no-console
|
|
1567
|
+
console.error('AppKit:getUniversalProvider - Cannot create provider', err);
|
|
1568
|
+
}
|
|
1569
|
+
}
|
|
1570
|
+
return this.universalProvider;
|
|
1571
|
+
}
|
|
1572
|
+
getDisabledCaipNetworks() {
|
|
1573
|
+
const approvedCaipNetworkIds = ChainController.getAllApprovedCaipNetworkIds();
|
|
1574
|
+
const requestedCaipNetworks = ChainController.getAllRequestedCaipNetworks();
|
|
1575
|
+
const sortedNetworks = CoreHelperUtil.sortRequestedNetworks(approvedCaipNetworkIds, requestedCaipNetworks);
|
|
1576
|
+
return sortedNetworks.filter(network => ChainController.isCaipNetworkDisabled(network));
|
|
1577
|
+
}
|
|
1578
|
+
// - Utils -------------------------------------------------------------------
|
|
1579
|
+
handleAlertError(error) {
|
|
1580
|
+
const matchedUniversalProviderError = Object.entries(ErrorUtil.UniversalProviderErrors).find(([, { message }]) => error.message.includes(message));
|
|
1581
|
+
const [errorKey, errorValue] = matchedUniversalProviderError ?? [];
|
|
1582
|
+
const { message, alertErrorKey } = errorValue ?? {};
|
|
1583
|
+
if (errorKey && message && !this.reportedAlertErrors[errorKey]) {
|
|
1584
|
+
const alertError = ErrorUtil.ALERT_ERRORS[alertErrorKey];
|
|
1585
|
+
if (alertError) {
|
|
1586
|
+
AlertController.open(alertError, 'error');
|
|
1587
|
+
this.reportedAlertErrors[errorKey] = true;
|
|
1588
|
+
}
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1591
|
+
getAdapter(namespace) {
|
|
1592
|
+
if (!namespace) {
|
|
1593
|
+
return undefined;
|
|
1594
|
+
}
|
|
1595
|
+
return this.chainAdapters?.[namespace];
|
|
1596
|
+
}
|
|
1597
|
+
createAdapter(blueprint) {
|
|
1598
|
+
if (!blueprint) {
|
|
1599
|
+
return;
|
|
1600
|
+
}
|
|
1601
|
+
const namespace = blueprint.namespace;
|
|
1602
|
+
if (!namespace) {
|
|
1603
|
+
return;
|
|
1604
|
+
}
|
|
1605
|
+
this.createClients();
|
|
1606
|
+
const adapterBlueprint = blueprint;
|
|
1607
|
+
adapterBlueprint.namespace = namespace;
|
|
1608
|
+
adapterBlueprint.construct({
|
|
1609
|
+
namespace,
|
|
1610
|
+
projectId: this.options?.projectId,
|
|
1611
|
+
networks: this.caipNetworks?.filter(({ chainNamespace }) => chainNamespace === namespace)
|
|
1612
|
+
});
|
|
1613
|
+
if (!this.chainNamespaces.includes(namespace)) {
|
|
1614
|
+
this.chainNamespaces.push(namespace);
|
|
1615
|
+
}
|
|
1616
|
+
if (this.chainAdapters) {
|
|
1617
|
+
this.chainAdapters[namespace] = adapterBlueprint;
|
|
1618
|
+
}
|
|
1619
|
+
}
|
|
1620
|
+
// -- Public -------------------------------------------------------------------
|
|
1621
|
+
async open(options) {
|
|
1622
|
+
await this.injectModalUi();
|
|
1623
|
+
if (options?.uri) {
|
|
1624
|
+
ConnectionController.setUri(options.uri);
|
|
1625
|
+
}
|
|
1626
|
+
const { isSwap, isSend } = this.toModalOptions();
|
|
1627
|
+
if (isSwap(options)) {
|
|
1628
|
+
return ModalController.open({
|
|
1629
|
+
...options,
|
|
1630
|
+
data: { swap: options.arguments }
|
|
1631
|
+
});
|
|
1632
|
+
}
|
|
1633
|
+
else if (isSend(options)) {
|
|
1634
|
+
if (options.arguments) {
|
|
1635
|
+
return this.openSend(options.arguments);
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
return ModalController.open(options);
|
|
1639
|
+
}
|
|
1640
|
+
async close() {
|
|
1641
|
+
await this.injectModalUi();
|
|
1642
|
+
ModalController.close();
|
|
1643
|
+
}
|
|
1644
|
+
setLoading(loading, namespace) {
|
|
1645
|
+
ModalController.setLoading(loading, namespace);
|
|
1646
|
+
}
|
|
1647
|
+
async disconnect(chainNamespace) {
|
|
1648
|
+
await ConnectionController.disconnect({ namespace: chainNamespace });
|
|
1649
|
+
}
|
|
1650
|
+
getSIWX() {
|
|
1651
|
+
return OptionsController.state.siwx;
|
|
1652
|
+
}
|
|
1653
|
+
// -- review these -------------------------------------------------------------------
|
|
1654
|
+
getError() {
|
|
1655
|
+
return '';
|
|
1656
|
+
}
|
|
1657
|
+
getChainId() {
|
|
1658
|
+
return ChainController.state.activeCaipNetwork?.id;
|
|
1659
|
+
}
|
|
1660
|
+
async switchNetwork(appKitNetwork, { throwOnFailure = false } = {}) {
|
|
1661
|
+
const network = this.getCaipNetworks().find(n => n.id === appKitNetwork.id);
|
|
1662
|
+
if (!network) {
|
|
1663
|
+
AlertController.open(ErrorUtil.ALERT_ERRORS.SWITCH_NETWORK_NOT_FOUND, 'error');
|
|
1664
|
+
return;
|
|
1665
|
+
}
|
|
1666
|
+
await ChainController.switchActiveNetwork(network, { throwOnFailure });
|
|
1667
|
+
}
|
|
1668
|
+
getWalletProvider() {
|
|
1669
|
+
return ChainController.state.activeChain
|
|
1670
|
+
? ProviderController.state.providers[ChainController.state.activeChain]
|
|
1671
|
+
: null;
|
|
1672
|
+
}
|
|
1673
|
+
getWalletProviderType() {
|
|
1674
|
+
return ProviderController.getProviderId(ChainController.state.activeChain);
|
|
1675
|
+
}
|
|
1676
|
+
subscribeProviders(callback) {
|
|
1677
|
+
return ProviderController.subscribeProviders(callback);
|
|
1678
|
+
}
|
|
1679
|
+
getThemeMode() {
|
|
1680
|
+
return ThemeController.state.themeMode;
|
|
1681
|
+
}
|
|
1682
|
+
getThemeVariables() {
|
|
1683
|
+
return ThemeController.state.themeVariables;
|
|
1684
|
+
}
|
|
1685
|
+
setThemeMode(themeMode) {
|
|
1686
|
+
ThemeController.setThemeMode(themeMode);
|
|
1687
|
+
setColorTheme(ThemeController.state.themeMode);
|
|
1688
|
+
}
|
|
1689
|
+
setTermsConditionsUrl(termsConditionsUrl) {
|
|
1690
|
+
OptionsController.setTermsConditionsUrl(termsConditionsUrl);
|
|
1691
|
+
}
|
|
1692
|
+
setPrivacyPolicyUrl(privacyPolicyUrl) {
|
|
1693
|
+
OptionsController.setPrivacyPolicyUrl(privacyPolicyUrl);
|
|
1694
|
+
}
|
|
1695
|
+
setThemeVariables(themeVariables) {
|
|
1696
|
+
ThemeController.setThemeVariables(themeVariables);
|
|
1697
|
+
setThemeVariables(ThemeController.state.themeVariables);
|
|
1698
|
+
}
|
|
1699
|
+
subscribeTheme(callback) {
|
|
1700
|
+
return ThemeController.subscribe(callback);
|
|
1701
|
+
}
|
|
1702
|
+
subscribeConnections(callback) {
|
|
1703
|
+
if (!this.remoteFeatures.multiWallet) {
|
|
1704
|
+
AlertController.open(ConstantsUtil.REMOTE_FEATURES_ALERTS.MULTI_WALLET_NOT_ENABLED.DEFAULT, 'info');
|
|
1705
|
+
return () => undefined;
|
|
1706
|
+
}
|
|
1707
|
+
return ConnectionController.subscribe(callback);
|
|
1708
|
+
}
|
|
1709
|
+
getWalletInfo(namespace) {
|
|
1710
|
+
if (namespace) {
|
|
1711
|
+
return ChainController.state.chains.get(namespace)?.accountState?.connectedWalletInfo;
|
|
1712
|
+
}
|
|
1713
|
+
const accountData = ChainController.getAccountData();
|
|
1714
|
+
return accountData?.connectedWalletInfo;
|
|
1715
|
+
}
|
|
1716
|
+
getAccount(_namespace) {
|
|
1717
|
+
const namespace = _namespace || ChainController.state.activeChain;
|
|
1718
|
+
const authConnector = ConnectorController.getAuthConnector(namespace);
|
|
1719
|
+
const accountState = ChainController.getAccountData(namespace);
|
|
1720
|
+
const activeConnectorId = StorageUtil.getConnectedConnectorId(ChainController.state.activeChain);
|
|
1721
|
+
const connections = ConnectionController.getConnections(namespace);
|
|
1722
|
+
if (!namespace) {
|
|
1723
|
+
throw new Error('AppKit:getAccount - namespace is required');
|
|
1724
|
+
}
|
|
1725
|
+
const allAccounts = connections.flatMap(connection => connection.accounts.map(({ address, type, publicKey }) => CoreHelperUtil.createAccount(namespace, address, (type || 'eoa'), publicKey)));
|
|
1726
|
+
if (!accountState) {
|
|
1727
|
+
return undefined;
|
|
1728
|
+
}
|
|
1729
|
+
return {
|
|
1730
|
+
allAccounts,
|
|
1731
|
+
caipAddress: accountState.caipAddress,
|
|
1732
|
+
address: CoreHelperUtil.getPlainAddress(accountState.caipAddress),
|
|
1733
|
+
isConnected: Boolean(accountState.caipAddress),
|
|
1734
|
+
status: accountState.status,
|
|
1735
|
+
embeddedWalletInfo: authConnector && activeConnectorId === ConstantsUtil.CONNECTOR_ID.AUTH
|
|
1736
|
+
? {
|
|
1737
|
+
user: accountState.user
|
|
1738
|
+
? {
|
|
1739
|
+
...accountState.user,
|
|
1740
|
+
/*
|
|
1741
|
+
* Getting the username from the chain controller works well for social logins,
|
|
1742
|
+
* but Farcaster uses a different connection flow and doesn't emit the username via events.
|
|
1743
|
+
* Since the username is stored in local storage before the chain controller updates,
|
|
1744
|
+
* it's safe to use the local storage value here.
|
|
1745
|
+
*/
|
|
1746
|
+
username: StorageUtil.getConnectedSocialUsername()
|
|
1747
|
+
}
|
|
1748
|
+
: undefined,
|
|
1749
|
+
authProvider: accountState.socialProvider || 'email',
|
|
1750
|
+
accountType: getPreferredAccountType(namespace),
|
|
1751
|
+
isSmartAccountDeployed: Boolean(accountState.smartAccountDeployed)
|
|
1752
|
+
}
|
|
1753
|
+
: undefined
|
|
1754
|
+
};
|
|
1755
|
+
}
|
|
1756
|
+
subscribeAccount(callback, namespace) {
|
|
1757
|
+
const updateVal = () => {
|
|
1758
|
+
const account = this.getAccount(namespace);
|
|
1759
|
+
if (!account) {
|
|
1760
|
+
return;
|
|
1761
|
+
}
|
|
1762
|
+
callback(account);
|
|
1763
|
+
};
|
|
1764
|
+
if (namespace) {
|
|
1765
|
+
ChainController.subscribeChainProp('accountState', updateVal, namespace);
|
|
1766
|
+
}
|
|
1767
|
+
else {
|
|
1768
|
+
ChainController.subscribe(updateVal);
|
|
1769
|
+
}
|
|
1770
|
+
ConnectorController.subscribe(updateVal);
|
|
1771
|
+
}
|
|
1772
|
+
subscribeNetwork(callback) {
|
|
1773
|
+
return ChainController.subscribe(({ activeCaipNetwork }) => {
|
|
1774
|
+
callback({
|
|
1775
|
+
caipNetwork: activeCaipNetwork,
|
|
1776
|
+
chainId: activeCaipNetwork?.id,
|
|
1777
|
+
caipNetworkId: activeCaipNetwork?.caipNetworkId
|
|
1778
|
+
});
|
|
1779
|
+
});
|
|
1780
|
+
}
|
|
1781
|
+
subscribeWalletInfo(callback, namespace) {
|
|
1782
|
+
if (namespace) {
|
|
1783
|
+
return ChainController.subscribeChainProp('accountState', accountState => callback(accountState?.connectedWalletInfo), namespace);
|
|
1784
|
+
}
|
|
1785
|
+
return ChainController.subscribeChainProp('accountState', accountState => callback(accountState?.connectedWalletInfo));
|
|
1786
|
+
}
|
|
1787
|
+
subscribeShouldUpdateToAddress(callback) {
|
|
1788
|
+
ChainController.subscribeChainProp('accountState', accountState => callback(accountState?.shouldUpdateToAddress));
|
|
1789
|
+
}
|
|
1790
|
+
subscribeCaipNetworkChange(callback) {
|
|
1791
|
+
ChainController.subscribeKey('activeCaipNetwork', callback);
|
|
1792
|
+
}
|
|
1793
|
+
getState() {
|
|
1794
|
+
return PublicStateController.state;
|
|
1795
|
+
}
|
|
1796
|
+
getRemoteFeatures() {
|
|
1797
|
+
return OptionsController.state.remoteFeatures;
|
|
1798
|
+
}
|
|
1799
|
+
subscribeState(callback) {
|
|
1800
|
+
return PublicStateController.subscribe(callback);
|
|
1801
|
+
}
|
|
1802
|
+
subscribeRemoteFeatures(callback) {
|
|
1803
|
+
return OptionsController.subscribeKey('remoteFeatures', callback);
|
|
1804
|
+
}
|
|
1805
|
+
showErrorMessage(message) {
|
|
1806
|
+
SnackController.showError(message);
|
|
1807
|
+
}
|
|
1808
|
+
showSuccessMessage(message) {
|
|
1809
|
+
SnackController.showSuccess(message);
|
|
1810
|
+
}
|
|
1811
|
+
getEvent() {
|
|
1812
|
+
return { ...EventsController.state };
|
|
1813
|
+
}
|
|
1814
|
+
subscribeEvents(callback) {
|
|
1815
|
+
return EventsController.subscribe(callback);
|
|
1816
|
+
}
|
|
1817
|
+
replace(route) {
|
|
1818
|
+
RouterController.replace(route);
|
|
1819
|
+
}
|
|
1820
|
+
redirect(route) {
|
|
1821
|
+
RouterController.push(route);
|
|
1822
|
+
}
|
|
1823
|
+
popTransactionStack(status) {
|
|
1824
|
+
RouterController.popTransactionStack(status);
|
|
1825
|
+
}
|
|
1826
|
+
isOpen() {
|
|
1827
|
+
return ModalController.state.open;
|
|
1828
|
+
}
|
|
1829
|
+
isTransactionStackEmpty() {
|
|
1830
|
+
return RouterController.state.transactionStack.length === 0;
|
|
1831
|
+
}
|
|
1832
|
+
static getInstance() {
|
|
1833
|
+
return this.instance;
|
|
1834
|
+
}
|
|
1835
|
+
updateFeatures(newFeatures) {
|
|
1836
|
+
OptionsController.setFeatures(newFeatures);
|
|
1837
|
+
}
|
|
1838
|
+
updateRemoteFeatures(newRemoteFeatures) {
|
|
1839
|
+
OptionsController.setRemoteFeatures(newRemoteFeatures);
|
|
1840
|
+
}
|
|
1841
|
+
updateOptions(newOptions) {
|
|
1842
|
+
const currentOptions = OptionsController.state || {};
|
|
1843
|
+
const updatedOptions = { ...currentOptions, ...newOptions };
|
|
1844
|
+
OptionsController.setOptions(updatedOptions);
|
|
1845
|
+
}
|
|
1846
|
+
setConnectMethodsOrder(connectMethodsOrder) {
|
|
1847
|
+
OptionsController.setConnectMethodsOrder(connectMethodsOrder);
|
|
1848
|
+
}
|
|
1849
|
+
setWalletFeaturesOrder(walletFeaturesOrder) {
|
|
1850
|
+
OptionsController.setWalletFeaturesOrder(walletFeaturesOrder);
|
|
1851
|
+
}
|
|
1852
|
+
setCollapseWallets(collapseWallets) {
|
|
1853
|
+
OptionsController.setCollapseWallets(collapseWallets);
|
|
1854
|
+
}
|
|
1855
|
+
setSocialsOrder(socialsOrder) {
|
|
1856
|
+
OptionsController.setSocialsOrder(socialsOrder);
|
|
1857
|
+
}
|
|
1858
|
+
getConnectMethodsOrder() {
|
|
1859
|
+
return WalletUtil.getConnectOrderMethod(OptionsController.state.features, ConnectorController.getConnectors());
|
|
1860
|
+
}
|
|
1861
|
+
/**
|
|
1862
|
+
* Adds a network to an existing adapter in AppKit.
|
|
1863
|
+
* @param namespace - The chain namespace to add the network to (e.g. 'eip155', 'solana')
|
|
1864
|
+
* @param network - The network configuration to add
|
|
1865
|
+
* @throws Error if adapter for namespace doesn't exist
|
|
1866
|
+
*/
|
|
1867
|
+
addNetwork(namespace, network) {
|
|
1868
|
+
if (this.chainAdapters && !this.chainAdapters[namespace]) {
|
|
1869
|
+
throw new Error(`Adapter for namespace ${namespace} doesn't exist`);
|
|
1870
|
+
}
|
|
1871
|
+
const extendedNetwork = this.extendCaipNetwork(network, this.options);
|
|
1872
|
+
if (!this.getCaipNetworks().find(n => n.id === extendedNetwork.id)) {
|
|
1873
|
+
ChainController.addNetwork(extendedNetwork);
|
|
1874
|
+
}
|
|
1875
|
+
}
|
|
1876
|
+
/**
|
|
1877
|
+
* Removes a network from an existing adapter in AppKit.
|
|
1878
|
+
* @param namespace - The chain namespace the network belongs to
|
|
1879
|
+
* @param networkId - The network ID to remove
|
|
1880
|
+
* @throws Error if adapter for namespace doesn't exist or if removing last network
|
|
1881
|
+
*/
|
|
1882
|
+
removeNetwork(namespace, networkId) {
|
|
1883
|
+
if (this.chainAdapters && !this.chainAdapters[namespace]) {
|
|
1884
|
+
throw new Error(`Adapter for namespace ${namespace} doesn't exist`);
|
|
1885
|
+
}
|
|
1886
|
+
const networkToRemove = this.getCaipNetworks().find(n => n.id === networkId);
|
|
1887
|
+
if (!networkToRemove) {
|
|
1888
|
+
return;
|
|
1889
|
+
}
|
|
1890
|
+
ChainController.removeNetwork(namespace, networkId);
|
|
1891
|
+
}
|
|
1892
|
+
}
|
|
1893
|
+
//# sourceMappingURL=appkit-base-client.js.map
|