@monygroupcorp/micro-web3 0.1.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/README.md +87 -0
- package/dist/micro-web3.cjs.js +10 -0
- package/dist/micro-web3.cjs.js.map +1 -0
- package/dist/micro-web3.esm.js +10 -0
- package/dist/micro-web3.esm.js.map +1 -0
- package/dist/micro-web3.umd.js +10 -0
- package/dist/micro-web3.umd.js.map +1 -0
- package/package.json +34 -0
- package/rollup.config.cjs +36 -0
- package/src/components/BondingCurve/BondingCurve.js +296 -0
- package/src/components/Display/BalanceDisplay.js +81 -0
- package/src/components/Display/PriceDisplay.js +214 -0
- package/src/components/Ipfs/IpfsImage.js +265 -0
- package/src/components/Modal/ApprovalModal.js +398 -0
- package/src/components/Swap/SwapButton.js +81 -0
- package/src/components/Swap/SwapInputs.js +137 -0
- package/src/components/Swap/SwapInterface.js +972 -0
- package/src/components/Swap/TransactionOptions.js +238 -0
- package/src/components/Util/MessagePopup.js +159 -0
- package/src/components/Wallet/WalletModal.js +69 -0
- package/src/components/Wallet/WalletSplash.js +567 -0
- package/src/index.js +43 -0
- package/src/services/BlockchainService.js +1576 -0
- package/src/services/ContractCache.js +348 -0
- package/src/services/IpfsService.js +249 -0
- package/src/services/PriceService.js +191 -0
- package/src/services/WalletService.js +541 -0
|
@@ -0,0 +1,541 @@
|
|
|
1
|
+
import { ethers } from 'ethers';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* WalletService - Handles wallet connection, detection, and interactions
|
|
5
|
+
*/
|
|
6
|
+
class WalletService {
|
|
7
|
+
constructor(eventBus) {
|
|
8
|
+
if (!eventBus) {
|
|
9
|
+
throw new Error('WalletService requires an eventBus instance.');
|
|
10
|
+
}
|
|
11
|
+
this.eventBus = eventBus;
|
|
12
|
+
this.provider = null;
|
|
13
|
+
this.signer = null;
|
|
14
|
+
this.connectedAddress = null;
|
|
15
|
+
this.selectedWallet = null;
|
|
16
|
+
this.connected = false;
|
|
17
|
+
this.ethers = ethers;
|
|
18
|
+
this.isInitialized = false;
|
|
19
|
+
|
|
20
|
+
// Supported wallet providers - using a more careful detection approach
|
|
21
|
+
this.providerMap = {
|
|
22
|
+
rabby: () => {
|
|
23
|
+
if (window.ethereum && window.ethereum.isRabby) {
|
|
24
|
+
return window.ethereum;
|
|
25
|
+
}
|
|
26
|
+
return null;
|
|
27
|
+
},
|
|
28
|
+
rainbow: () => {
|
|
29
|
+
if (window.ethereum && window.ethereum.isRainbow) {
|
|
30
|
+
return window.ethereum;
|
|
31
|
+
}
|
|
32
|
+
return window.rainbow || null;
|
|
33
|
+
},
|
|
34
|
+
phantom: () => {
|
|
35
|
+
if (window.phantom && window.phantom.ethereum) {
|
|
36
|
+
return window.phantom.ethereum;
|
|
37
|
+
}
|
|
38
|
+
return null;
|
|
39
|
+
},
|
|
40
|
+
metamask: () => {
|
|
41
|
+
// Simplified approach - just use window.ethereum directly
|
|
42
|
+
console.log('Checking for MetaMask with direct window.ethereum access');
|
|
43
|
+
return window.ethereum || null;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// Wallet icons mapping
|
|
48
|
+
this.walletIcons = {
|
|
49
|
+
rabby: '/public/wallets/rabby.webp',
|
|
50
|
+
rainbow: '/public/wallets/rainbow.webp',
|
|
51
|
+
phantom: '/public/wallets/phantom.webp',
|
|
52
|
+
metamask: '/public/wallets/MetaMask.webp',
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// We'll set up event listeners after a wallet is selected, not in constructor
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Initialize the wallet service - just check for wallet presence
|
|
60
|
+
*/
|
|
61
|
+
async initialize() {
|
|
62
|
+
try {
|
|
63
|
+
console.log('Initializing WalletService...');
|
|
64
|
+
|
|
65
|
+
// Check if window.ethereum exists
|
|
66
|
+
if (typeof window.ethereum !== 'undefined') {
|
|
67
|
+
// Log that we found a wallet provider
|
|
68
|
+
console.log('Found Ethereum provider');
|
|
69
|
+
|
|
70
|
+
// Let other components know a wallet was detected
|
|
71
|
+
this.eventBus.emit('wallet:detected');
|
|
72
|
+
|
|
73
|
+
// Check if the provider is in MetaMask compatibility mode
|
|
74
|
+
this.isMetaMask = window.ethereum.isMetaMask;
|
|
75
|
+
|
|
76
|
+
// Set up event listeners for wallet changes
|
|
77
|
+
this.setupEventListeners();
|
|
78
|
+
} else {
|
|
79
|
+
console.log('No Ethereum provider found');
|
|
80
|
+
this.eventBus.emit('wallet:notdetected');
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Mark as initialized
|
|
84
|
+
this.isInitialized = true;
|
|
85
|
+
|
|
86
|
+
return true;
|
|
87
|
+
} catch (error) {
|
|
88
|
+
console.error('Error initializing WalletService:', error);
|
|
89
|
+
throw error;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Format error to provide better context
|
|
95
|
+
* @private
|
|
96
|
+
*/
|
|
97
|
+
formatError(error, context = '') {
|
|
98
|
+
// If error is a string, convert to Error object
|
|
99
|
+
if (typeof error === 'string') {
|
|
100
|
+
return new Error(`${context}: ${error}`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// If error has a message, add context
|
|
104
|
+
if (error && error.message) {
|
|
105
|
+
// Common wallet errors, make more user-friendly
|
|
106
|
+
const message = this.getUserFriendlyErrorMessage(error, context);
|
|
107
|
+
const formattedError = new Error(message);
|
|
108
|
+
|
|
109
|
+
// Copy properties
|
|
110
|
+
formattedError.code = error.code;
|
|
111
|
+
formattedError.originalError = error;
|
|
112
|
+
|
|
113
|
+
return formattedError;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Default case
|
|
117
|
+
return new Error(`${context}: Unknown error`);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Convert technical errors to user-friendly messages
|
|
122
|
+
* @private
|
|
123
|
+
*/
|
|
124
|
+
getUserFriendlyErrorMessage(error, context) {
|
|
125
|
+
const message = error.message || 'Unknown error';
|
|
126
|
+
|
|
127
|
+
// Handle common wallet error codes
|
|
128
|
+
if (error.code === 4001) {
|
|
129
|
+
return 'Connection request rejected by user';
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (error.code === 4902) {
|
|
133
|
+
return 'Network needs to be added to your wallet';
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (message.includes('redefine property') || message.includes('which has only a getter')) {
|
|
137
|
+
return 'Wallet conflict detected. Please disable all wallet extensions except the one you want to use, then refresh.';
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (message.includes('user rejected')) {
|
|
141
|
+
return 'Connection rejected by user';
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (message.includes('already pending')) {
|
|
145
|
+
return 'A wallet request is already pending, please check your wallet';
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// If no specific handling, add context
|
|
149
|
+
return context ? `${context}: ${message}` : message;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Get all available wallet providers
|
|
154
|
+
* @returns {Object} Map of wallet providers
|
|
155
|
+
*/
|
|
156
|
+
getAvailableWallets() {
|
|
157
|
+
const available = {};
|
|
158
|
+
|
|
159
|
+
console.log('Checking for available wallets...');
|
|
160
|
+
|
|
161
|
+
// First check if window.ethereum exists at all
|
|
162
|
+
if (window.ethereum) {
|
|
163
|
+
console.log('window.ethereum is available');
|
|
164
|
+
} else {
|
|
165
|
+
console.log('window.ethereum is not available');
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
for (const [name, getProvider] of Object.entries(this.providerMap)) {
|
|
169
|
+
try {
|
|
170
|
+
console.log(`Checking for ${name} wallet...`);
|
|
171
|
+
const provider = getProvider();
|
|
172
|
+
if (provider) {
|
|
173
|
+
console.log(`Found ${name} wallet`);
|
|
174
|
+
available[name] = {
|
|
175
|
+
name,
|
|
176
|
+
icon: this.walletIcons[name],
|
|
177
|
+
provider: provider
|
|
178
|
+
};
|
|
179
|
+
} else {
|
|
180
|
+
console.log(`${name} wallet not detected`);
|
|
181
|
+
}
|
|
182
|
+
} catch (error) {
|
|
183
|
+
console.warn(`Error detecting ${name} wallet:`, error);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// If no specific wallets detected but ethereum provider exists,
|
|
188
|
+
// add metamask as a fallback option
|
|
189
|
+
if (Object.keys(available).length === 0 && window.ethereum) {
|
|
190
|
+
console.log('No specific wallets detected, but window.ethereum exists. Adding MetaMask as fallback.');
|
|
191
|
+
available['metamask'] = {
|
|
192
|
+
name: 'metamask',
|
|
193
|
+
icon: this.walletIcons['metamask'],
|
|
194
|
+
provider: window.ethereum
|
|
195
|
+
};
|
|
196
|
+
} else if (!available['metamask'] && window.ethereum) {
|
|
197
|
+
// Always add MetaMask if ethereum is available and not already added
|
|
198
|
+
console.log('window.ethereum exists. Adding MetaMask option regardless of detection.');
|
|
199
|
+
available['metamask'] = {
|
|
200
|
+
name: 'metamask',
|
|
201
|
+
icon: this.walletIcons['metamask'],
|
|
202
|
+
provider: window.ethereum
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
console.log('Available wallets:', Object.keys(available));
|
|
207
|
+
return available;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Select a specific wallet provider
|
|
212
|
+
* @param {string} walletType - The type of wallet to select
|
|
213
|
+
*/
|
|
214
|
+
async selectWallet(walletType) {
|
|
215
|
+
try {
|
|
216
|
+
// Clear any previous wallet selection
|
|
217
|
+
this.cleanup();
|
|
218
|
+
|
|
219
|
+
if (!this.providerMap[walletType]) {
|
|
220
|
+
throw new Error(`Unsupported wallet: ${walletType}`);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const provider = this.providerMap[walletType]();
|
|
224
|
+
|
|
225
|
+
if (!provider) {
|
|
226
|
+
throw new Error(`${walletType} not detected. Please install it first.`);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
this.selectedWallet = walletType;
|
|
230
|
+
this.provider = provider;
|
|
231
|
+
|
|
232
|
+
// Set up event listeners now that we have a provider
|
|
233
|
+
this.setupEventListeners();
|
|
234
|
+
|
|
235
|
+
this.eventBus.emit('wallet:selected', {
|
|
236
|
+
type: walletType,
|
|
237
|
+
provider: provider
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
return walletType;
|
|
241
|
+
} catch (error) {
|
|
242
|
+
const formattedError = this.formatError(error, 'Wallet selection failed');
|
|
243
|
+
this.eventBus.emit('wallet:error', formattedError);
|
|
244
|
+
throw formattedError;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Set up event listeners for the selected wallet
|
|
250
|
+
* @private
|
|
251
|
+
*/
|
|
252
|
+
setupEventListeners() {
|
|
253
|
+
if (this.provider) {
|
|
254
|
+
// Remove any existing listeners to avoid duplicates
|
|
255
|
+
try {
|
|
256
|
+
this.provider.removeListener('chainChanged', this.handleNetworkChange);
|
|
257
|
+
this.provider.removeListener('accountsChanged', this.handleAccountChange);
|
|
258
|
+
} catch (error) {
|
|
259
|
+
// Ignore errors when removing non-existent listeners
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Add new listeners
|
|
263
|
+
this.provider.on('chainChanged', () => this.handleNetworkChange());
|
|
264
|
+
this.provider.on('accountsChanged', (accounts) => this.handleAccountChange(accounts));
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Clean up resources when switching wallets
|
|
270
|
+
* @private
|
|
271
|
+
*/
|
|
272
|
+
cleanup() {
|
|
273
|
+
if (this.provider) {
|
|
274
|
+
try {
|
|
275
|
+
this.provider.removeListener('chainChanged', this.handleNetworkChange);
|
|
276
|
+
this.provider.removeListener('accountsChanged', this.handleAccountChange);
|
|
277
|
+
} catch (error) {
|
|
278
|
+
// Ignore errors when removing non-existent listeners
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
this.provider = null;
|
|
283
|
+
this.signer = null;
|
|
284
|
+
this.connectedAddress = null;
|
|
285
|
+
this.connected = false;
|
|
286
|
+
this.ethersProvider = null;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Connect to the selected wallet
|
|
291
|
+
* @returns {string} The connected address
|
|
292
|
+
*/
|
|
293
|
+
async connect() {
|
|
294
|
+
try {
|
|
295
|
+
if (!this.selectedWallet || !this.provider) {
|
|
296
|
+
throw new Error('Please select a wallet first');
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
this.eventBus.emit('wallet:connecting');
|
|
300
|
+
console.log(`Attempting to connect to ${this.selectedWallet}...`);
|
|
301
|
+
|
|
302
|
+
let accounts;
|
|
303
|
+
|
|
304
|
+
try {
|
|
305
|
+
// Give the wallet time to initialize if needed
|
|
306
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
307
|
+
|
|
308
|
+
// Handle wallet-specific connection methods
|
|
309
|
+
if (this.selectedWallet === 'phantom' && window.phantom && window.phantom.ethereum) {
|
|
310
|
+
console.log('Using phantom-specific connection method');
|
|
311
|
+
accounts = await window.phantom.ethereum.request({
|
|
312
|
+
method: 'eth_requestAccounts'
|
|
313
|
+
});
|
|
314
|
+
} else {
|
|
315
|
+
console.log(`Using standard connection method for ${this.selectedWallet}`);
|
|
316
|
+
// Try to check if the wallet has any accounts before requesting new ones
|
|
317
|
+
try {
|
|
318
|
+
const existingAccounts = await this.provider.request({
|
|
319
|
+
method: 'eth_accounts'
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
console.log('Existing accounts:', existingAccounts);
|
|
323
|
+
|
|
324
|
+
// If no accounts, explicitly check before requesting
|
|
325
|
+
if (!existingAccounts || existingAccounts.length === 0) {
|
|
326
|
+
console.log('No existing accounts found, requesting user approval...');
|
|
327
|
+
}
|
|
328
|
+
} catch (accountCheckError) {
|
|
329
|
+
console.warn('Error checking existing accounts:', accountCheckError);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// Request accounts with explicit params
|
|
333
|
+
accounts = await this.provider.request({
|
|
334
|
+
method: 'eth_requestAccounts',
|
|
335
|
+
params: []
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
} catch (error) {
|
|
339
|
+
console.error('Error requesting accounts:', error);
|
|
340
|
+
|
|
341
|
+
if (error && error.code === 4001) {
|
|
342
|
+
throw this.formatError(error, 'Wallet connection rejected');
|
|
343
|
+
} else if (error && error.message && error.message.includes('wallet must has at least one account')) {
|
|
344
|
+
throw new Error('Your wallet has no accounts. Please create at least one account in your wallet and try again.');
|
|
345
|
+
} else {
|
|
346
|
+
throw error;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
console.log('Accounts received:', accounts);
|
|
351
|
+
|
|
352
|
+
if (!accounts || !accounts[0]) {
|
|
353
|
+
throw new Error('No accounts found. Please unlock your wallet and make sure you have at least one account set up.');
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
this.connectedAddress = accounts[0];
|
|
357
|
+
this.connected = true;
|
|
358
|
+
|
|
359
|
+
console.log(`Successfully connected to account: ${this.connectedAddress}`);
|
|
360
|
+
|
|
361
|
+
// Store the selected wallet in localStorage for future auto-reconnect
|
|
362
|
+
if (this.selectedWallet) {
|
|
363
|
+
localStorage.setItem('ms2fun_lastWallet', this.selectedWallet);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// Create ethers provider
|
|
367
|
+
this.ethersProvider = new ethers.providers.Web3Provider(this.provider, 'any');
|
|
368
|
+
this.signer = this.ethersProvider.getSigner();
|
|
369
|
+
|
|
370
|
+
this.eventBus.emit('wallet:connected', {
|
|
371
|
+
address: this.connectedAddress,
|
|
372
|
+
walletType: this.selectedWallet,
|
|
373
|
+
provider: this.provider,
|
|
374
|
+
ethersProvider: this.ethersProvider,
|
|
375
|
+
signer: this.signer
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
return this.connectedAddress;
|
|
379
|
+
} catch (error) {
|
|
380
|
+
console.error('Wallet connection error:', error);
|
|
381
|
+
|
|
382
|
+
// Better handle the specific "must have at least one account" error
|
|
383
|
+
if (error.message && (
|
|
384
|
+
error.message.includes('at least one account') ||
|
|
385
|
+
error.message.includes('wallet must has') ||
|
|
386
|
+
error.message.includes('no accounts')
|
|
387
|
+
)) {
|
|
388
|
+
const friendlyMessage = 'Your wallet has no accounts. Please create at least one account in your wallet and try again.';
|
|
389
|
+
const formattedError = new Error(friendlyMessage);
|
|
390
|
+
formattedError.code = error.code;
|
|
391
|
+
formattedError.originalError = error;
|
|
392
|
+
|
|
393
|
+
this.eventBus.emit('wallet:error', formattedError);
|
|
394
|
+
throw formattedError;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
const formattedError = this.formatError(error, 'Wallet connection failed');
|
|
398
|
+
this.eventBus.emit('wallet:error', formattedError);
|
|
399
|
+
throw formattedError;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* Switch to a specific network
|
|
405
|
+
* @param {number} networkId - The network ID to switch to
|
|
406
|
+
*/
|
|
407
|
+
async switchNetwork(networkId) {
|
|
408
|
+
try {
|
|
409
|
+
if (!this.provider) {
|
|
410
|
+
throw new Error('No wallet connected');
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
const hexChainId = `0x${Number(networkId).toString(16)}`;
|
|
414
|
+
|
|
415
|
+
this.eventBus.emit('network:switching', {
|
|
416
|
+
to: networkId,
|
|
417
|
+
automatic: false
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
try {
|
|
421
|
+
await this.provider.request({
|
|
422
|
+
method: 'wallet_switchEthereumChain',
|
|
423
|
+
params: [{ chainId: hexChainId }],
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
// Refresh provider after switch
|
|
427
|
+
this.ethersProvider = new ethers.providers.Web3Provider(this.provider, 'any');
|
|
428
|
+
this.signer = this.ethersProvider.getSigner();
|
|
429
|
+
|
|
430
|
+
this.eventBus.emit('network:switched', {
|
|
431
|
+
to: networkId,
|
|
432
|
+
success: true
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
return true;
|
|
436
|
+
} catch (switchError) {
|
|
437
|
+
// Network needs to be added
|
|
438
|
+
if (switchError.code === 4902) {
|
|
439
|
+
// You would need network metadata here to add properly
|
|
440
|
+
throw new Error('Network needs to be added first');
|
|
441
|
+
} else {
|
|
442
|
+
throw switchError;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
} catch (error) {
|
|
446
|
+
const formattedError = this.formatError(error, 'Network switch failed');
|
|
447
|
+
|
|
448
|
+
// Emit error event for consistency with BlockchainService
|
|
449
|
+
this.eventBus.emit('network:switch:error', {
|
|
450
|
+
from: null,
|
|
451
|
+
to: networkId,
|
|
452
|
+
error: formattedError.message,
|
|
453
|
+
originalError: error
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
// Also emit switched event with success: false for backward compatibility
|
|
457
|
+
this.eventBus.emit('network:switched', {
|
|
458
|
+
to: networkId,
|
|
459
|
+
success: false,
|
|
460
|
+
error: formattedError.message
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
throw formattedError;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Get the currently connected address
|
|
469
|
+
* @returns {string|null} The connected address or null
|
|
470
|
+
*/
|
|
471
|
+
getAddress() {
|
|
472
|
+
return this.connectedAddress;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* Check if a wallet is connected
|
|
477
|
+
* @returns {boolean} Whether a wallet is connected
|
|
478
|
+
*/
|
|
479
|
+
isConnected() {
|
|
480
|
+
return this.connected && !!this.connectedAddress;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/**
|
|
484
|
+
* Get the ethers provider and signer
|
|
485
|
+
* @returns {Object} The provider and signer
|
|
486
|
+
*/
|
|
487
|
+
getProviderAndSigner() {
|
|
488
|
+
return {
|
|
489
|
+
provider: this.ethersProvider,
|
|
490
|
+
signer: this.signer
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
/**
|
|
495
|
+
* Handle network changes
|
|
496
|
+
* @private
|
|
497
|
+
*/
|
|
498
|
+
handleNetworkChange() {
|
|
499
|
+
// Refresh provider
|
|
500
|
+
if (this.provider) {
|
|
501
|
+
this.ethersProvider = new ethers.providers.Web3Provider(this.provider, 'any');
|
|
502
|
+
this.signer = this.ethersProvider.getSigner();
|
|
503
|
+
|
|
504
|
+
// Don't emit network:changed here - BlockchainService handles it
|
|
505
|
+
// This prevents duplicate messages when both services detect the change
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* Handle account changes
|
|
511
|
+
* @private
|
|
512
|
+
*/
|
|
513
|
+
handleAccountChange(accounts) {
|
|
514
|
+
if (!accounts || !Array.isArray(accounts)) {
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
if (accounts.length === 0) {
|
|
519
|
+
// Disconnected
|
|
520
|
+
this.connected = false;
|
|
521
|
+
this.connectedAddress = null;
|
|
522
|
+
this.eventBus.emit('wallet:disconnected');
|
|
523
|
+
} else if (accounts[0] !== this.connectedAddress) {
|
|
524
|
+
// Changed account
|
|
525
|
+
this.connectedAddress = accounts[0];
|
|
526
|
+
this.eventBus.emit('wallet:changed', { address: accounts[0] });
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
/**
|
|
531
|
+
* Disconnect from the wallet (if supported)
|
|
532
|
+
*/
|
|
533
|
+
async disconnect() {
|
|
534
|
+
// Most wallets don't support programmatic disconnect
|
|
535
|
+
// But we can reset our state
|
|
536
|
+
this.cleanup();
|
|
537
|
+
this.eventBus.emit('wallet:disconnected');
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
export default WalletService;
|