@mictonode/widget 0.3.22 → 0.3.23
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/README.md +2 -2
- package/dist/{ConstantsUtil-df193f67.js → ConstantsUtil-f9dc60b6.js} +3 -3
- package/dist/{ConstantsUtil-1b0c0436.js → ConstantsUtil-fb0ff2e5.js} +1 -1
- package/dist/{ExchangeController-953f14bc.js → ExchangeController-173fd1dc.js} +2 -2
- package/dist/{HelpersUtil-3810bb58.js → HelpersUtil-4891ff5f.js} +4 -4
- package/dist/{ReownAuthentication-7c5b6e79.js → ReownAuthentication-bba89dc5.js} +2 -2
- package/dist/{SwapController-e1a7b5f8.js → SwapController-e8b097ca.js} +3 -3
- package/dist/{abis-61cccfbf.js → abis-96fed285.js} +1 -1
- package/dist/{assertCurrentChain-0c3d6c93.js → assertCurrentChain-b60aa59f.js} +1 -1
- package/dist/{ccip-80fe88fb.js → ccip-8f82ae2a.js} +6 -6
- package/dist/{data-capture-7edeb077.js → data-capture-7009ffa0.js} +8 -8
- package/dist/{email-40537ec5.js → email-d6e2da58.js} +12 -12
- package/dist/{embedded-wallet-f71f6169.js → embedded-wallet-48284179.js} +14 -14
- package/dist/{encodeFunctionData-91e7c0f6.js → encodeFunctionData-b24a0b2b.js} +2 -2
- package/dist/{fallback-1ab5a270.js → fallback-ae0315d4.js} +2 -2
- package/dist/features-82db0d52.js +8 -0
- package/dist/{hashTypedData-1e059dc4.js → hashTypedData-c13ba550.js} +2 -2
- package/dist/{http-d9e0a50a.js → http-90ef23f3.js} +2 -2
- package/dist/{index-d3f36c31.js → index-0ac134af.js} +34 -34
- package/dist/{index-2cd6a2b2.js → index-19f302c4.js} +3 -3
- package/dist/{index-78c5b9e2.js → index-22727038.js} +3 -3
- package/dist/{index-144edd3f.js → index-270ff8a2.js} +11 -11
- package/dist/{index-abb0ff46.js → index-29eb95bd.js} +3 -3
- package/dist/{index-9cc1116b.js → index-2a90711e.js} +2 -2
- package/dist/{index-289a865f.js → index-2de6c5bf.js} +4 -4
- package/dist/{index-fbced89b.js → index-3de7fa96.js} +3 -3
- package/dist/{index-26b53c8a.js → index-42a8a5ec.js} +15 -15
- package/dist/{index-58ec291c.js → index-4bd03aed.js} +7 -7
- package/dist/{index-85bc86d7.js → index-52edc95a.js} +2 -2
- package/dist/{index-04dd1ab3.js → index-577d2709.js} +4 -4
- package/dist/{index-4a4ee1e7.js → index-582e4199.js} +7 -7
- package/dist/{index-72706598.js → index-617b2147.js} +6 -6
- package/dist/{index-0b6166c5.js → index-6a0902fc.js} +2 -2
- package/dist/{index-a37d4c03.js → index-6d51f24f.js} +2 -2
- package/dist/{index-759b09b0.js → index-80954332.js} +3 -3
- package/dist/{index-0e2c49ad.js → index-95777860.js} +7 -7
- package/dist/{index-d9effd37.js → index-96729706.js} +13 -13
- package/dist/{index-39f31546.js → index-997bc756.js} +2 -2
- package/dist/{index-cb4d3345.js → index-a41841e6.js} +3 -3
- package/dist/{index-c10f5e72.js → index-adaa2ea4.js} +3 -3
- package/dist/{index-97b58f89.js → index-b37b670f.js} +11 -11
- package/dist/{index-0763de43.js → index-b8e2c282.js} +3 -3
- package/dist/{index-1f02e7d0.js → index-bb5e4071.js} +1 -1
- package/dist/{index-3678e7d8.js → index-bf40b971.js} +2 -2
- package/dist/{index-a4f054e9.js → index-cb69565e.js} +2 -2
- package/dist/{index-197dfd69.js → index-cbb6096a.js} +3 -3
- package/dist/{index-119c358f.js → index-ce6854ef.js} +14 -14
- package/dist/{index-4fdc7a25.js → index-d7e2a4a3.js} +2 -2
- package/dist/{index-0176180b.js → index-e7fbb597.js} +4 -4
- package/dist/{index-d5e3e4ba.js → index-f4cd8dd1.js} +3 -3
- package/dist/{index-a0c590f7.js → index-f886cf92.js} +2 -2
- package/dist/{index-95e1a01b.js → index-faade258.js} +3 -3
- package/dist/{localBatchGatewayRequest-8fd1b198.js → localBatchGatewayRequest-ade4aa2f.js} +3 -3
- package/dist/{main-7ddb238e.js → main-3b573cfc.js} +38694 -38472
- package/dist/{networks-d2ae1da7.js → networks-446d3512.js} +10 -10
- package/dist/{onramp-2966f1b1.js → onramp-57d19c5d.js} +19 -19
- package/dist/{parseSignature-fca372a1.js → parseSignature-783d626a.js} +8 -8
- package/dist/{pay-with-exchange-b0198b3f.js → pay-with-exchange-c59a5773.js} +22 -22
- package/dist/ping-widget.js +1 -1
- package/dist/ping-widget.umd.cjs +680 -680
- package/dist/{query.lcd-873499ca.js → query.lcd-447fb91a.js} +1 -1
- package/dist/{query.rpc.Query-d2bcf632.js → query.rpc.Query-97503d87.js} +1 -1
- package/dist/{receive-6fbb6662.js → receive-3073a49d.js} +6 -6
- package/dist/{ref-2c86b029.js → ref-6c3aabc7.js} +2 -2
- package/dist/{send-630ed203.js → send-42403797.js} +22 -22
- package/dist/{serializeAuthorizationList-e95a85d8.js → serializeAuthorizationList-70ec977c.js} +4 -4
- package/dist/{sha2-c04ffd62.js → sha2-249ae7eb.js} +2 -2
- package/dist/{socials-73a5efb0.js → socials-69b0cf18.js} +18 -18
- package/dist/{swaps-7b57265f.js → swaps-4e99bb0f.js} +18 -18
- package/dist/{transactions-876c066c.js → transactions-1d0c2669.js} +9 -9
- package/dist/{tx.rpc.msg-4d8bd1a4.js → tx.rpc.msg-8aa727ea.js} +1 -1
- package/dist/{tx.rpc.msg-d08b8ebe.js → tx.rpc.msg-a26b3557.js} +1 -1
- package/dist/{verifyHash-ee28e3d7.js → verifyHash-c8962067.js} +5 -5
- package/dist/{vue-bea1a08b.js → vue-9dc93a14.js} +10 -10
- package/dist/{w3m-modal-7d61c210.js → w3m-modal-291afec4.js} +25 -25
- package/dist/{zora-1091e7bb.js → zora-061565b0.js} +4 -4
- package/lib/components/ConnectWallet/index.vue +113 -31
- package/lib/wallet/KeplrSessionManager.ts +142 -0
- package/lib/wallet/WalletSessionManager.ts +111 -25
- package/lib/wallet/reown/EvmNetworkProvisioner.ts +97 -0
- package/lib/wallet/reown/ReownGateway.ts +22 -3
- package/package.json +1 -1
- package/test/components/ConnectWallet.test.ts +640 -2
- package/test/components/ConnectWalletStorage.test.ts +113 -3
- package/test/wallet/KeplrSessionManager.test.ts +269 -0
- package/test/wallet/WalletSessionManager.test.ts +901 -2
- package/test/wallet/reown/EvmNetworkProvisioner.test.ts +264 -0
- package/test/wallet/reown/ReownGateway.test.ts +66 -1
- package/dist/features-a2f2ff4f.js +0 -8
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createWallet,
|
|
3
|
+
removeWallet,
|
|
4
|
+
WalletName,
|
|
5
|
+
writeWallet,
|
|
6
|
+
type AbstractWallet,
|
|
7
|
+
type ConnectedWallet,
|
|
8
|
+
type WalletArgument,
|
|
9
|
+
} from './Wallet';
|
|
10
|
+
import {
|
|
11
|
+
normalizeWalletError,
|
|
12
|
+
type WalletUserError,
|
|
13
|
+
} from './WalletError';
|
|
14
|
+
|
|
15
|
+
export const KEPLR_KEYSTORE_EVENT = 'keplr_keystorechange';
|
|
16
|
+
|
|
17
|
+
export interface WalletEventTarget {
|
|
18
|
+
addEventListener(type: string, listener: EventListener): void;
|
|
19
|
+
removeEventListener(type: string, listener: EventListener): void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
type KeplrWalletFactory = (argument: WalletArgument) => AbstractWallet;
|
|
23
|
+
|
|
24
|
+
function defaultFactory(argument: WalletArgument): AbstractWallet {
|
|
25
|
+
return createWallet(WalletName.Keplr, argument);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export class KeplrSessionManager {
|
|
29
|
+
private listener?: EventListener;
|
|
30
|
+
private argument?: WalletArgument;
|
|
31
|
+
private onChange?: (wallet: ConnectedWallet | undefined) => void;
|
|
32
|
+
private onError: (error: WalletUserError) => void = () => undefined;
|
|
33
|
+
private lifecycleGeneration = 0;
|
|
34
|
+
private refreshGeneration = 0;
|
|
35
|
+
private refreshPromise?: Promise<void>;
|
|
36
|
+
private refreshQueued = false;
|
|
37
|
+
private refreshScheduled = false;
|
|
38
|
+
|
|
39
|
+
constructor(
|
|
40
|
+
private readonly hdPath: string,
|
|
41
|
+
private readonly walletFactory: KeplrWalletFactory = defaultFactory,
|
|
42
|
+
private readonly eventTarget: WalletEventTarget = window,
|
|
43
|
+
) {}
|
|
44
|
+
|
|
45
|
+
async start(
|
|
46
|
+
argument: WalletArgument,
|
|
47
|
+
onChange: (wallet: ConnectedWallet | undefined) => void,
|
|
48
|
+
onError: (error: WalletUserError) => void = () => undefined,
|
|
49
|
+
): Promise<void> {
|
|
50
|
+
this.dispose();
|
|
51
|
+
this.argument = argument;
|
|
52
|
+
this.onChange = onChange;
|
|
53
|
+
this.onError = onError;
|
|
54
|
+
const listenerLifecycleGeneration = this.lifecycleGeneration;
|
|
55
|
+
this.listener = () => {
|
|
56
|
+
if (listenerLifecycleGeneration !== this.lifecycleGeneration) return;
|
|
57
|
+
if (this.refreshScheduled) return;
|
|
58
|
+
this.refreshScheduled = true;
|
|
59
|
+
queueMicrotask(() => {
|
|
60
|
+
if (listenerLifecycleGeneration !== this.lifecycleGeneration) return;
|
|
61
|
+
this.refreshScheduled = false;
|
|
62
|
+
void this.refresh();
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
this.eventTarget.addEventListener(KEPLR_KEYSTORE_EVENT, this.listener);
|
|
66
|
+
await this.refresh();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async refresh(): Promise<void> {
|
|
70
|
+
if (!this.argument || !this.onChange) return;
|
|
71
|
+
if (this.refreshPromise) {
|
|
72
|
+
this.refreshGeneration += 1;
|
|
73
|
+
this.refreshQueued = true;
|
|
74
|
+
await this.refreshPromise;
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const lifecycleGeneration = this.lifecycleGeneration;
|
|
79
|
+
const refreshGeneration = ++this.refreshGeneration;
|
|
80
|
+
const argument = this.argument;
|
|
81
|
+
const onChange = this.onChange;
|
|
82
|
+
onChange(undefined);
|
|
83
|
+
|
|
84
|
+
const refreshing = (async () => {
|
|
85
|
+
try {
|
|
86
|
+
const [account] = await this.walletFactory(argument).getAccounts();
|
|
87
|
+
if (
|
|
88
|
+
lifecycleGeneration !== this.lifecycleGeneration ||
|
|
89
|
+
refreshGeneration !== this.refreshGeneration
|
|
90
|
+
) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
if (!account || typeof account.address !== 'string' || !account.address.trim()) {
|
|
94
|
+
throw new Error('Keplr returned no active account');
|
|
95
|
+
}
|
|
96
|
+
const connected: ConnectedWallet = {
|
|
97
|
+
wallet: WalletName.Keplr,
|
|
98
|
+
cosmosAddress: account.address,
|
|
99
|
+
hdPath: this.hdPath,
|
|
100
|
+
};
|
|
101
|
+
writeWallet(connected, this.hdPath);
|
|
102
|
+
onChange(connected);
|
|
103
|
+
} catch (error) {
|
|
104
|
+
if (
|
|
105
|
+
lifecycleGeneration !== this.lifecycleGeneration ||
|
|
106
|
+
refreshGeneration !== this.refreshGeneration
|
|
107
|
+
) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
removeWallet(this.hdPath);
|
|
111
|
+
this.onError(normalizeWalletError(error));
|
|
112
|
+
}
|
|
113
|
+
})().finally(() => {
|
|
114
|
+
if (this.refreshPromise !== refreshing) return;
|
|
115
|
+
this.refreshPromise = undefined;
|
|
116
|
+
if (
|
|
117
|
+
this.refreshQueued &&
|
|
118
|
+
lifecycleGeneration === this.lifecycleGeneration
|
|
119
|
+
) {
|
|
120
|
+
this.refreshQueued = false;
|
|
121
|
+
void this.refresh();
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
this.refreshPromise = refreshing;
|
|
126
|
+
return refreshing;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
dispose(): void {
|
|
130
|
+
this.lifecycleGeneration += 1;
|
|
131
|
+
this.refreshGeneration += 1;
|
|
132
|
+
if (this.listener) {
|
|
133
|
+
this.eventTarget.removeEventListener(KEPLR_KEYSTORE_EVENT, this.listener);
|
|
134
|
+
}
|
|
135
|
+
this.listener = undefined;
|
|
136
|
+
this.argument = undefined;
|
|
137
|
+
this.onChange = undefined;
|
|
138
|
+
this.refreshPromise = undefined;
|
|
139
|
+
this.refreshQueued = false;
|
|
140
|
+
this.refreshScheduled = false;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
getReownGateway,
|
|
22
22
|
type ReownAccountState,
|
|
23
23
|
type ReownGateway,
|
|
24
|
+
type ReownNetworkState,
|
|
24
25
|
} from './reown/ReownGateway';
|
|
25
26
|
import { EvmEip712Wallet } from './wallets/EvmEip712Wallet';
|
|
26
27
|
import { ethermintToEth } from '../utils/format';
|
|
@@ -92,6 +93,7 @@ export class WalletSessionManager {
|
|
|
92
93
|
walletArgument: WalletArgument,
|
|
93
94
|
onChange: (connected: ConnectedWallet | undefined) => void,
|
|
94
95
|
onError: (error: WalletUserError) => void = () => undefined,
|
|
96
|
+
provisionNetwork = false,
|
|
95
97
|
): Promise<ReownGateway> {
|
|
96
98
|
this.dispose();
|
|
97
99
|
const lifecycleGeneration = this.lifecycleGeneration;
|
|
@@ -105,6 +107,16 @@ export class WalletSessionManager {
|
|
|
105
107
|
|
|
106
108
|
let pendingAddress: string | undefined;
|
|
107
109
|
let verifiedAddress: string | undefined;
|
|
110
|
+
let authoritativeAddress: string | undefined;
|
|
111
|
+
let networkValid = true;
|
|
112
|
+
let provisioningAvailable = provisionNetwork;
|
|
113
|
+
let provisioningPending = false;
|
|
114
|
+
let provisioningFailed = false;
|
|
115
|
+
const clearVisibleState = () => {
|
|
116
|
+
clearRuntimeWallet(this.hdPath);
|
|
117
|
+
removeWallet(this.hdPath);
|
|
118
|
+
onChange(undefined);
|
|
119
|
+
};
|
|
108
120
|
const synchronizeAccount = async (state: ReownAccountState) => {
|
|
109
121
|
const evmAddress =
|
|
110
122
|
state.isConnected && state.address
|
|
@@ -112,23 +124,60 @@ export class WalletSessionManager {
|
|
|
112
124
|
: undefined;
|
|
113
125
|
if (!evmAddress) {
|
|
114
126
|
this.accountGeneration += 1;
|
|
127
|
+
authoritativeAddress = undefined;
|
|
115
128
|
pendingAddress = undefined;
|
|
116
129
|
verifiedAddress = undefined;
|
|
117
|
-
|
|
118
|
-
removeWallet(this.hdPath);
|
|
119
|
-
onChange(undefined);
|
|
130
|
+
clearVisibleState();
|
|
120
131
|
return;
|
|
121
132
|
}
|
|
133
|
+
if (evmAddress !== authoritativeAddress) {
|
|
134
|
+
this.accountGeneration += 1;
|
|
135
|
+
authoritativeAddress = evmAddress;
|
|
136
|
+
pendingAddress = undefined;
|
|
137
|
+
clearVisibleState();
|
|
138
|
+
}
|
|
139
|
+
if (provisioningPending || provisioningFailed) return;
|
|
140
|
+
if (!networkValid && !provisioningAvailable) return;
|
|
122
141
|
if (
|
|
123
142
|
evmAddress === pendingAddress ||
|
|
124
|
-
(evmAddress === verifiedAddress &&
|
|
143
|
+
(evmAddress === verifiedAddress &&
|
|
144
|
+
pendingAddress === undefined &&
|
|
145
|
+
runtimeWallets.has(this.hdPath))
|
|
125
146
|
) {
|
|
126
147
|
return;
|
|
127
148
|
}
|
|
128
149
|
|
|
150
|
+
const shouldProvision = provisioningAvailable;
|
|
151
|
+
if (shouldProvision) {
|
|
152
|
+
provisioningAvailable = false;
|
|
153
|
+
provisioningPending = true;
|
|
154
|
+
}
|
|
129
155
|
const accountGeneration = ++this.accountGeneration;
|
|
130
156
|
pendingAddress = evmAddress;
|
|
157
|
+
const ownsProvisioning = () =>
|
|
158
|
+
lifecycleGeneration === this.lifecycleGeneration &&
|
|
159
|
+
accountGeneration === this.accountGeneration &&
|
|
160
|
+
authoritativeAddress === evmAddress &&
|
|
161
|
+
provisioningPending;
|
|
131
162
|
try {
|
|
163
|
+
if (shouldProvision) {
|
|
164
|
+
await gateway.ensureNetwork(ownsProvisioning);
|
|
165
|
+
if (!ownsProvisioning()) {
|
|
166
|
+
provisioningPending = false;
|
|
167
|
+
provisioningFailed = true;
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
provisioningPending = false;
|
|
171
|
+
networkValid = true;
|
|
172
|
+
}
|
|
173
|
+
if (
|
|
174
|
+
lifecycleGeneration !== this.lifecycleGeneration ||
|
|
175
|
+
accountGeneration !== this.accountGeneration ||
|
|
176
|
+
authoritativeAddress !== evmAddress ||
|
|
177
|
+
!networkValid
|
|
178
|
+
) {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
132
181
|
const provider = gateway.getProvider();
|
|
133
182
|
if (!provider) throw new Error('EVM wallet provider is unavailable');
|
|
134
183
|
const wallet = this.walletFactory({
|
|
@@ -139,7 +188,9 @@ export class WalletSessionManager {
|
|
|
139
188
|
const accounts = await wallet.getAccounts();
|
|
140
189
|
if (
|
|
141
190
|
lifecycleGeneration !== this.lifecycleGeneration ||
|
|
142
|
-
accountGeneration !== this.accountGeneration
|
|
191
|
+
accountGeneration !== this.accountGeneration ||
|
|
192
|
+
authoritativeAddress !== evmAddress ||
|
|
193
|
+
!networkValid
|
|
143
194
|
) {
|
|
144
195
|
return;
|
|
145
196
|
}
|
|
@@ -168,6 +219,10 @@ export class WalletSessionManager {
|
|
|
168
219
|
writeWallet(connected, this.hdPath);
|
|
169
220
|
onChange(connected);
|
|
170
221
|
} catch (error) {
|
|
222
|
+
if (shouldProvision) {
|
|
223
|
+
provisioningPending = false;
|
|
224
|
+
provisioningFailed = true;
|
|
225
|
+
}
|
|
171
226
|
if (
|
|
172
227
|
lifecycleGeneration !== this.lifecycleGeneration ||
|
|
173
228
|
accountGeneration !== this.accountGeneration
|
|
@@ -180,6 +235,9 @@ export class WalletSessionManager {
|
|
|
180
235
|
onChange(undefined);
|
|
181
236
|
onError(normalizeWalletError(error));
|
|
182
237
|
} finally {
|
|
238
|
+
if (shouldProvision) {
|
|
239
|
+
provisioningPending = false;
|
|
240
|
+
}
|
|
183
241
|
if (
|
|
184
242
|
accountGeneration === this.accountGeneration &&
|
|
185
243
|
pendingAddress === evmAddress
|
|
@@ -189,29 +247,57 @@ export class WalletSessionManager {
|
|
|
189
247
|
}
|
|
190
248
|
};
|
|
191
249
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
250
|
+
const synchronizeNetwork = (state: ReownNetworkState) => {
|
|
251
|
+
const networkId = state.caipNetworkId;
|
|
252
|
+
if (networkId === undefined) return;
|
|
253
|
+
const nextNetworkValid = isExpectedNetwork(networkId, config);
|
|
254
|
+
if (!nextNetworkValid) {
|
|
255
|
+
if (!networkValid) return;
|
|
256
|
+
networkValid = false;
|
|
198
257
|
if (
|
|
199
|
-
|
|
200
|
-
|
|
258
|
+
provisioningPending ||
|
|
259
|
+
(provisioningAvailable && authoritativeAddress === undefined)
|
|
201
260
|
) {
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
if (!provisioningPending) {
|
|
202
264
|
this.accountGeneration += 1;
|
|
203
265
|
pendingAddress = undefined;
|
|
204
|
-
verifiedAddress = undefined;
|
|
205
|
-
clearRuntimeWallet(this.hdPath);
|
|
206
|
-
removeWallet(this.hdPath);
|
|
207
|
-
onChange(undefined);
|
|
208
|
-
onError(normalizeWalletError({ code: 4901 }));
|
|
209
266
|
}
|
|
267
|
+
verifiedAddress = undefined;
|
|
268
|
+
clearVisibleState();
|
|
269
|
+
onError(normalizeWalletError({ code: 4901 }));
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
if (networkValid) return;
|
|
273
|
+
networkValid = true;
|
|
274
|
+
const current = gateway.getAccount();
|
|
275
|
+
if (current) void synchronizeAccount(current);
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
this.unsubscribe.push(
|
|
279
|
+
gateway.subscribeAccount((state) => {
|
|
280
|
+
if (lifecycleGeneration !== this.lifecycleGeneration) return;
|
|
281
|
+
void synchronizeAccount(state);
|
|
282
|
+
}),
|
|
283
|
+
);
|
|
284
|
+
this.unsubscribe.push(
|
|
285
|
+
gateway.subscribeNetwork((state) => {
|
|
286
|
+
if (lifecycleGeneration !== this.lifecycleGeneration) return;
|
|
287
|
+
synchronizeNetwork(state);
|
|
210
288
|
}),
|
|
211
289
|
);
|
|
212
290
|
|
|
291
|
+
const currentNetwork = gateway.getNetwork();
|
|
292
|
+
if (currentNetwork) synchronizeNetwork(currentNetwork);
|
|
213
293
|
const current = gateway.getAccount();
|
|
214
294
|
if (current?.isConnected) await synchronizeAccount(current);
|
|
295
|
+
if (lifecycleGeneration !== this.lifecycleGeneration) {
|
|
296
|
+
throw new WalletUserError(
|
|
297
|
+
'disconnected',
|
|
298
|
+
'Wallet session changed before connection completed',
|
|
299
|
+
);
|
|
300
|
+
}
|
|
215
301
|
return gateway;
|
|
216
302
|
}
|
|
217
303
|
|
|
@@ -226,19 +312,18 @@ export class WalletSessionManager {
|
|
|
226
312
|
walletArgument,
|
|
227
313
|
onChange,
|
|
228
314
|
onError,
|
|
315
|
+
true,
|
|
229
316
|
);
|
|
230
|
-
|
|
317
|
+
if (!gateway.getAccount()?.isConnected) {
|
|
318
|
+
await gateway.open();
|
|
319
|
+
}
|
|
231
320
|
}
|
|
232
321
|
|
|
233
322
|
async disconnect(config: ReownWalletConfig): Promise<void> {
|
|
234
323
|
this.dispose();
|
|
324
|
+
removeWallet(this.hdPath);
|
|
235
325
|
const gateway = await this.gatewayFactory(config);
|
|
236
|
-
|
|
237
|
-
await gateway.disconnect();
|
|
238
|
-
} finally {
|
|
239
|
-
clearRuntimeWallet(this.hdPath);
|
|
240
|
-
removeWallet(this.hdPath);
|
|
241
|
-
}
|
|
326
|
+
await gateway.disconnect();
|
|
242
327
|
}
|
|
243
328
|
|
|
244
329
|
dispose(): void {
|
|
@@ -246,5 +331,6 @@ export class WalletSessionManager {
|
|
|
246
331
|
this.accountGeneration += 1;
|
|
247
332
|
for (const unsubscribe of this.unsubscribe) unsubscribe();
|
|
248
333
|
this.unsubscribe = [];
|
|
334
|
+
clearRuntimeWallet(this.hdPath);
|
|
249
335
|
}
|
|
250
336
|
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type { Eip1193Provider } from '../providers/Eip1193Provider';
|
|
2
|
+
import type { ReownNetwork } from './ReownConfig';
|
|
3
|
+
|
|
4
|
+
function isUnknownChainError(error: unknown): boolean {
|
|
5
|
+
type Match = 'none' | 'unknown-chain' | 'user-rejected';
|
|
6
|
+
const visited = new Set<object>();
|
|
7
|
+
const inspect = (candidate: unknown, depth: number): Match => {
|
|
8
|
+
if (
|
|
9
|
+
typeof candidate !== 'object' ||
|
|
10
|
+
candidate === null ||
|
|
11
|
+
depth > 4 ||
|
|
12
|
+
visited.has(candidate)
|
|
13
|
+
) {
|
|
14
|
+
return 'none';
|
|
15
|
+
}
|
|
16
|
+
visited.add(candidate);
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
const code = 'code' in candidate
|
|
20
|
+
? String(candidate.code).trim()
|
|
21
|
+
: undefined;
|
|
22
|
+
if (code === '4001') {
|
|
23
|
+
return 'user-rejected';
|
|
24
|
+
}
|
|
25
|
+
let match: Match = code === '4902' ? 'unknown-chain' : 'none';
|
|
26
|
+
for (const key of ['cause', 'error', 'data', 'originalError']) {
|
|
27
|
+
if (key in candidate) {
|
|
28
|
+
const nested = inspect(candidate[key], depth + 1);
|
|
29
|
+
if (nested === 'user-rejected') return nested;
|
|
30
|
+
if (nested === 'unknown-chain') match = nested;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return match;
|
|
34
|
+
} catch {
|
|
35
|
+
return 'none';
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
return inspect(error, 0) === 'unknown-chain';
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export async function ensureEvmNetwork(
|
|
43
|
+
provider: Eip1193Provider,
|
|
44
|
+
network: ReownNetwork,
|
|
45
|
+
isActive: () => boolean = () => true,
|
|
46
|
+
): Promise<void> {
|
|
47
|
+
const chainId = `0x${network.id.toString(16)}`;
|
|
48
|
+
const isExpectedChain = (value: unknown) =>
|
|
49
|
+
typeof value === 'string' && value.toLowerCase() === chainId;
|
|
50
|
+
const assertActive = () => {
|
|
51
|
+
if (!isActive()) {
|
|
52
|
+
throw new Error('EVM network request is no longer active');
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
assertActive();
|
|
57
|
+
const currentChain = await provider.request({ method: 'eth_chainId' });
|
|
58
|
+
assertActive();
|
|
59
|
+
if (isExpectedChain(currentChain)) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const switchRequest = {
|
|
64
|
+
method: 'wallet_switchEthereumChain',
|
|
65
|
+
params: [{ chainId }],
|
|
66
|
+
} as const;
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
await provider.request(switchRequest);
|
|
70
|
+
assertActive();
|
|
71
|
+
} catch (error) {
|
|
72
|
+
assertActive();
|
|
73
|
+
if (!isUnknownChainError(error)) throw error;
|
|
74
|
+
|
|
75
|
+
await provider.request({
|
|
76
|
+
method: 'wallet_addEthereumChain',
|
|
77
|
+
params: [{
|
|
78
|
+
chainId,
|
|
79
|
+
chainName: network.name,
|
|
80
|
+
nativeCurrency: network.nativeCurrency,
|
|
81
|
+
rpcUrls: [network.rpcUrl],
|
|
82
|
+
...(network.explorerUrl
|
|
83
|
+
? { blockExplorerUrls: [network.explorerUrl] }
|
|
84
|
+
: {}),
|
|
85
|
+
}],
|
|
86
|
+
});
|
|
87
|
+
assertActive();
|
|
88
|
+
await provider.request(switchRequest);
|
|
89
|
+
assertActive();
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const verifiedChain = await provider.request({ method: 'eth_chainId' });
|
|
93
|
+
assertActive();
|
|
94
|
+
if (!isExpectedChain(verifiedChain)) {
|
|
95
|
+
throw new Error('EVM wallet did not switch to configured network');
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { AppKit } from '@reown/appkit/vue';
|
|
2
2
|
import type { Eip1193Provider } from '../providers/Eip1193Provider';
|
|
3
3
|
import type { ReownWalletConfig } from './ReownConfig';
|
|
4
|
+
import { ensureEvmNetwork } from './EvmNetworkProvisioner';
|
|
4
5
|
|
|
5
6
|
export interface ReownAccountState {
|
|
6
7
|
address?: string;
|
|
@@ -21,8 +22,10 @@ export interface ReownWalletInfo {
|
|
|
21
22
|
export interface ReownGateway {
|
|
22
23
|
open(): Promise<void>;
|
|
23
24
|
disconnect(): Promise<void>;
|
|
25
|
+
ensureNetwork(isCurrent?: () => boolean): Promise<void>;
|
|
24
26
|
getProvider(): Eip1193Provider | undefined;
|
|
25
27
|
getAccount(): ReownAccountState | undefined;
|
|
28
|
+
getNetwork(): ReownNetworkState | undefined;
|
|
26
29
|
getWalletInfo(): ReownWalletInfo | undefined;
|
|
27
30
|
subscribeAccount(
|
|
28
31
|
callback: (account: ReownAccountState) => void,
|
|
@@ -59,7 +62,7 @@ export async function getReownGateway(
|
|
|
59
62
|
async function createGateway(
|
|
60
63
|
config: ReownWalletConfig,
|
|
61
64
|
): Promise<ReownGateway> {
|
|
62
|
-
const [{ createAppKit }, { EthersAdapter }, { defineChain }] =
|
|
65
|
+
const [{ createAppKit }, { EthersAdapter }, { defineChain, mainnet }] =
|
|
63
66
|
await Promise.all([
|
|
64
67
|
import('@reown/appkit/vue'),
|
|
65
68
|
import('@reown/appkit-adapter-ethers'),
|
|
@@ -87,8 +90,10 @@ async function createGateway(
|
|
|
87
90
|
|
|
88
91
|
const appKit: AppKit = createAppKit({
|
|
89
92
|
adapters: [new EthersAdapter()],
|
|
90
|
-
networks: [network],
|
|
91
|
-
defaultNetwork:
|
|
93
|
+
networks: [network, mainnet],
|
|
94
|
+
defaultNetwork: mainnet,
|
|
95
|
+
allowUnsupportedChain: true,
|
|
96
|
+
enableNetworkSwitch: false,
|
|
92
97
|
projectId: config.projectId,
|
|
93
98
|
metadata: config.metadata,
|
|
94
99
|
featuredWalletIds: config.featuredWalletIds,
|
|
@@ -117,6 +122,14 @@ async function createGateway(
|
|
|
117
122
|
await appKit.open({ view: 'Connect', namespace: 'eip155' });
|
|
118
123
|
},
|
|
119
124
|
disconnect: () => appKit.disconnect('eip155'),
|
|
125
|
+
ensureNetwork: async (isCurrent) => {
|
|
126
|
+
const provider =
|
|
127
|
+
appKit.getProvider<Eip1193Provider>('eip155');
|
|
128
|
+
if (!provider) {
|
|
129
|
+
throw new Error('EVM wallet provider is unavailable');
|
|
130
|
+
}
|
|
131
|
+
await ensureEvmNetwork(provider, config.network, isCurrent);
|
|
132
|
+
},
|
|
120
133
|
getProvider: () => appKit.getProvider<Eip1193Provider>('eip155'),
|
|
121
134
|
getAccount: () => {
|
|
122
135
|
const account = appKit.getAccount('eip155');
|
|
@@ -128,6 +141,12 @@ async function createGateway(
|
|
|
128
141
|
}
|
|
129
142
|
: undefined;
|
|
130
143
|
},
|
|
144
|
+
getNetwork: () => {
|
|
145
|
+
const network = appKit.getCaipNetwork('eip155');
|
|
146
|
+
return network
|
|
147
|
+
? { caipNetworkId: network.caipNetworkId }
|
|
148
|
+
: undefined;
|
|
149
|
+
},
|
|
131
150
|
getWalletInfo: () => {
|
|
132
151
|
const info = appKit.getWalletInfo('eip155');
|
|
133
152
|
return info
|