@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,567 @@
|
|
|
1
|
+
import { Component } from '@monygroupcorp/microact';
|
|
2
|
+
import WalletModal from './WalletModal.js';
|
|
3
|
+
|
|
4
|
+
export class WalletSplash extends Component {
|
|
5
|
+
constructor(props) {
|
|
6
|
+
super(props);
|
|
7
|
+
this.onConnected = props.onConnected;
|
|
8
|
+
this.this.walletService = props.this.walletService;
|
|
9
|
+
this.this.eventBus = props.this.eventBus;
|
|
10
|
+
|
|
11
|
+
this.walletModal = null;
|
|
12
|
+
this.state = {
|
|
13
|
+
walletConnected: false,
|
|
14
|
+
checking: true,
|
|
15
|
+
walletAvailable: false,
|
|
16
|
+
loadingLightNode: false
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async onMount() {
|
|
21
|
+
// Check if wallet is already connected
|
|
22
|
+
await this.checkWalletConnection();
|
|
23
|
+
|
|
24
|
+
// Set up event listeners
|
|
25
|
+
this.setupEventListeners();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Detect which wallet provider is being used
|
|
30
|
+
* @returns {string|null} Wallet type or null
|
|
31
|
+
*/
|
|
32
|
+
detectWalletType() {
|
|
33
|
+
if (typeof window.ethereum === 'undefined') {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Check for specific wallet identifiers
|
|
38
|
+
if (window.ethereum.isRabby) {
|
|
39
|
+
return 'rabby';
|
|
40
|
+
}
|
|
41
|
+
if (window.ethereum.isRainbow) {
|
|
42
|
+
return 'rainbow';
|
|
43
|
+
}
|
|
44
|
+
if (window.phantom && window.phantom.ethereum) {
|
|
45
|
+
return 'phantom';
|
|
46
|
+
}
|
|
47
|
+
if (window.ethereum.isMetaMask) {
|
|
48
|
+
return 'metamask';
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Default to metamask if window.ethereum exists but no specific identifier
|
|
52
|
+
return 'metamask';
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async checkWalletConnection() {
|
|
56
|
+
try {
|
|
57
|
+
// Check if web3 wallet is available (window.ethereum exists)
|
|
58
|
+
const walletAvailable = typeof window.ethereum !== 'undefined';
|
|
59
|
+
|
|
60
|
+
// Initialize wallet service if needed
|
|
61
|
+
if (!this.walletService.isInitialized) {
|
|
62
|
+
await this.walletService.initialize();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Check if wallet service thinks it's connected
|
|
66
|
+
let isConnected = this.walletService.isConnected();
|
|
67
|
+
|
|
68
|
+
// If not connected, try to auto-reconnect to the last used wallet
|
|
69
|
+
// This allows auto-reconnect on refresh without annoying prompts
|
|
70
|
+
if (!isConnected && typeof window.ethereum !== 'undefined') {
|
|
71
|
+
try {
|
|
72
|
+
// Get the last used wallet from localStorage
|
|
73
|
+
const lastWallet = localStorage.getItem('ms2fun_lastWallet');
|
|
74
|
+
|
|
75
|
+
if (lastWallet) {
|
|
76
|
+
// Check if that wallet has accounts (without prompting)
|
|
77
|
+
let hasAccounts = false;
|
|
78
|
+
try {
|
|
79
|
+
// Get the provider for the last wallet
|
|
80
|
+
const providerMap = {
|
|
81
|
+
rabby: () => window.ethereum?.isRabby ? window.ethereum : null,
|
|
82
|
+
rainbow: () => window.ethereum?.isRainbow ? window.ethereum : null,
|
|
83
|
+
phantom: () => window.phantom?.ethereum || null,
|
|
84
|
+
metamask: () => window.ethereum || null
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const getProvider = providerMap[lastWallet];
|
|
88
|
+
if (getProvider) {
|
|
89
|
+
const provider = getProvider();
|
|
90
|
+
if (provider) {
|
|
91
|
+
const accounts = await provider.request({ method: 'eth_accounts' });
|
|
92
|
+
hasAccounts = accounts && accounts.length > 0;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
} catch (error) {
|
|
96
|
+
// Can't check - that's fine
|
|
97
|
+
console.log('Could not check accounts for last wallet:', error);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Only try to reconnect if the last wallet has accounts
|
|
101
|
+
if (hasAccounts) {
|
|
102
|
+
try {
|
|
103
|
+
// Select the last used wallet (doesn't prompt)
|
|
104
|
+
await this.walletService.selectWallet(lastWallet);
|
|
105
|
+
// Try to connect (this will use existing connection if available)
|
|
106
|
+
// If it needs approval, it will fail gracefully and user can click button
|
|
107
|
+
await this.walletService.connect();
|
|
108
|
+
isConnected = this.walletService.isConnected();
|
|
109
|
+
if (isConnected) {
|
|
110
|
+
console.log('Auto-reconnected to', lastWallet);
|
|
111
|
+
}
|
|
112
|
+
} catch (connectError) {
|
|
113
|
+
// Connection failed (user needs to approve) - that's fine
|
|
114
|
+
// Don't log as error, just continue to show wallet selection
|
|
115
|
+
console.log('Auto-reconnect not possible, user will need to select wallet');
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
} catch (accountsError) {
|
|
120
|
+
// Can't check accounts - that's fine, show wallet selection
|
|
121
|
+
console.log('Could not check existing accounts:', accountsError);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
this.setState({
|
|
126
|
+
walletConnected: isConnected,
|
|
127
|
+
checking: false,
|
|
128
|
+
walletAvailable: walletAvailable
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// If already connected, call onConnected callback
|
|
132
|
+
if (isConnected && this.onConnected) {
|
|
133
|
+
this.onConnected();
|
|
134
|
+
} else {
|
|
135
|
+
// If not connected, ensure wallet modal is set up
|
|
136
|
+
// Use setTimeout to ensure state update has processed
|
|
137
|
+
this.setTimeout(() => {
|
|
138
|
+
this.setupWalletModal();
|
|
139
|
+
}, 100);
|
|
140
|
+
}
|
|
141
|
+
} catch (error) {
|
|
142
|
+
console.error('Error checking wallet connection:', error);
|
|
143
|
+
// Check wallet availability even on error
|
|
144
|
+
const walletAvailable = typeof window.ethereum !== 'undefined';
|
|
145
|
+
this.setState({
|
|
146
|
+
walletConnected: false,
|
|
147
|
+
checking: false,
|
|
148
|
+
walletAvailable: walletAvailable
|
|
149
|
+
});
|
|
150
|
+
// Ensure wallet modal is set up even on error
|
|
151
|
+
this.setTimeout(() => {
|
|
152
|
+
this.setupWalletModal();
|
|
153
|
+
}, 100);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
setupEventListeners() {
|
|
158
|
+
// Listen for wallet connection
|
|
159
|
+
const unsubscribeConnected = this.eventBus.on('wallet:connected', () => {
|
|
160
|
+
this.setState({ walletConnected: true });
|
|
161
|
+
if (this.onConnected) {
|
|
162
|
+
this.onConnected();
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
// Listen for wallet disconnection
|
|
167
|
+
const unsubscribeDisconnected = this.eventBus.on('wallet:disconnected', () => {
|
|
168
|
+
this.setState({ walletConnected: false });
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
// Register cleanup
|
|
172
|
+
this.registerCleanup(() => {
|
|
173
|
+
unsubscribeConnected();
|
|
174
|
+
unsubscribeDisconnected();
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
render() {
|
|
179
|
+
if (this.state.checking) {
|
|
180
|
+
return `
|
|
181
|
+
<div class="wallet-splash">
|
|
182
|
+
<div class="splash-content marble-bg">
|
|
183
|
+
<div class="splash-spinner"></div>
|
|
184
|
+
<h2>Checking wallet connection...</h2>
|
|
185
|
+
</div>
|
|
186
|
+
</div>
|
|
187
|
+
`;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (this.state.walletConnected) {
|
|
191
|
+
// Wallet is connected, hide splash (content will be shown)
|
|
192
|
+
return '<div class="wallet-splash-connected" style="display: none;"></div>';
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Wallet not connected, show splash screen
|
|
196
|
+
const walletAvailable = this.state.walletAvailable;
|
|
197
|
+
const loadingLightNode = this.state.loadingLightNode;
|
|
198
|
+
|
|
199
|
+
return `
|
|
200
|
+
<div class="wallet-splash">
|
|
201
|
+
<div class="splash-content marble-bg">
|
|
202
|
+
<div class="splash-header">
|
|
203
|
+
<h1>Connect Your Wallet</h1>
|
|
204
|
+
<p class="splash-subtitle">Connect your wallet to access the MS2.FUN launchpad</p>
|
|
205
|
+
</div>
|
|
206
|
+
|
|
207
|
+
<div class="splash-description">
|
|
208
|
+
<p>This application requires a connected wallet to access on-chain data and interact with projects.</p>
|
|
209
|
+
${walletAvailable
|
|
210
|
+
? '<p>You can connect your wallet or continue using your wallet\'s RPC for read-only access.</p>'
|
|
211
|
+
: '<p>No wallet detected. You can continue with read-only mode using a light node.</p>'}
|
|
212
|
+
</div>
|
|
213
|
+
|
|
214
|
+
<div class="wallet-connector-container" data-ref="wallet-connector">
|
|
215
|
+
<div class="contract-status">
|
|
216
|
+
<div id="contractStatus" class="status-message">${loadingLightNode ? 'DOWNLOADING LIGHT NODE...' : 'INITIALIZING SYSTEM...'}</div>
|
|
217
|
+
|
|
218
|
+
<div id="selectedWalletDisplay" class="selected-wallet-display" style="display: none;">
|
|
219
|
+
<img id="selectedWalletIcon" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71'/%3E%3Cpath d='M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71'/%3E%3C/svg%3E" alt="Selected Wallet">
|
|
220
|
+
<span class="wallet-name" id="selectedWalletName"></span>
|
|
221
|
+
</div>
|
|
222
|
+
<div id="continuePrompt" class="continue-prompt" style="display: none;">
|
|
223
|
+
CONTINUE IN YOUR WALLET
|
|
224
|
+
</div>
|
|
225
|
+
|
|
226
|
+
<button id="selectWallet" class="connect-button" ${!walletAvailable ? 'disabled' : ''} style="${!walletAvailable ? 'opacity: 0.5; cursor: not-allowed;' : ''}">
|
|
227
|
+
<span class="button-text">SELECT WALLET</span>
|
|
228
|
+
</button>
|
|
229
|
+
|
|
230
|
+
<button id="continueButton" class="connect-button" style="margin-top: 1rem; ${loadingLightNode ? 'opacity: 0.7; cursor: wait;' : ''}">
|
|
231
|
+
<span class="button-text">${loadingLightNode ? 'LOADING...' : 'CONTINUE'}</span>
|
|
232
|
+
</button>
|
|
233
|
+
|
|
234
|
+
${!walletAvailable ? `
|
|
235
|
+
<p class="light-node-explainer" style="margin-top: 1rem; font-size: 0.875rem; color: rgba(255, 255, 255, 0.7); text-align: center; max-width: 400px; margin-left: auto; margin-right: auto;">
|
|
236
|
+
This will download and run a light node to enable read-only blockchain access without a wallet.
|
|
237
|
+
</p>
|
|
238
|
+
` : ''}
|
|
239
|
+
</div>
|
|
240
|
+
|
|
241
|
+
<!-- Wallet Selection Modal (same as CultExecsPage) -->
|
|
242
|
+
<div id="walletModal" class="wallet-modal">
|
|
243
|
+
<div class="wallet-modal-content">
|
|
244
|
+
<div class="wallet-modal-header">
|
|
245
|
+
<h3>Select Your Wallet</h3>
|
|
246
|
+
<button class="wallet-modal-close" data-ref="modal-close">×</button>
|
|
247
|
+
</div>
|
|
248
|
+
<div class="wallet-options">
|
|
249
|
+
<button class="wallet-option" data-wallet="rabby">
|
|
250
|
+
<picture>
|
|
251
|
+
<source srcset="public/wallets/rabby.avif" type="image/avif">
|
|
252
|
+
<source srcset="public/wallets/rabby.webp" type="image/webp">
|
|
253
|
+
<img src="public/wallets/rabby.png" alt="Rabby">
|
|
254
|
+
</picture>
|
|
255
|
+
<span>Rabby</span>
|
|
256
|
+
</button>
|
|
257
|
+
<button class="wallet-option" data-wallet="rainbow">
|
|
258
|
+
<picture>
|
|
259
|
+
<source srcset="public/wallets/rainbow.avif" type="image/avif">
|
|
260
|
+
<source srcset="public/wallets/rainbow.webp" type="image/webp">
|
|
261
|
+
<img src="public/wallets/rainbow.png" alt="Rainbow">
|
|
262
|
+
</picture>
|
|
263
|
+
<span>Rainbow</span>
|
|
264
|
+
</button>
|
|
265
|
+
<button class="wallet-option" data-wallet="phantom">
|
|
266
|
+
<picture>
|
|
267
|
+
<source srcset="public/wallets/phantom.avif" type="image/avif">
|
|
268
|
+
<source srcset="public/wallets/phantom.webp" type="image/webp">
|
|
269
|
+
<img src="public/wallets/phantom.png" alt="Phantom">
|
|
270
|
+
</picture>
|
|
271
|
+
<span>Phantom</span>
|
|
272
|
+
</button>
|
|
273
|
+
<button class="wallet-option" data-wallet="metamask">
|
|
274
|
+
<picture>
|
|
275
|
+
<source srcset="/public/wallets/MetaMask.avif" type="image/avif">
|
|
276
|
+
<source srcset="/public/wallets/MetaMask.webp" type="image/webp">
|
|
277
|
+
<img src="/public/wallets/MetaMask.webp" alt="MetaMask" onerror="this.src='/public/wallets/MetaMask.webp'">
|
|
278
|
+
</picture>
|
|
279
|
+
<span>MetaMask</span>
|
|
280
|
+
</button>
|
|
281
|
+
</div>
|
|
282
|
+
</div>
|
|
283
|
+
</div>
|
|
284
|
+
</div>
|
|
285
|
+
</div>
|
|
286
|
+
</div>
|
|
287
|
+
`;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
mount(element) {
|
|
291
|
+
super.mount(element);
|
|
292
|
+
|
|
293
|
+
// Set up wallet modal after mount
|
|
294
|
+
this.setTimeout(() => {
|
|
295
|
+
this.setupWalletModal();
|
|
296
|
+
}, 0);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
setupWalletModal() {
|
|
300
|
+
// Only set up if wallet is not connected
|
|
301
|
+
if (this.state.walletConnected) {
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Prevent infinite retry loops
|
|
306
|
+
if (!this._setupRetryCount) {
|
|
307
|
+
this._setupRetryCount = 0;
|
|
308
|
+
}
|
|
309
|
+
if (this._setupRetryCount > 10) {
|
|
310
|
+
console.error('Wallet modal setup failed after 10 retries - giving up');
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
this._setupRetryCount++;
|
|
314
|
+
|
|
315
|
+
// Wait for DOM to be ready
|
|
316
|
+
this.setTimeout(() => {
|
|
317
|
+
const modal = document.getElementById('walletModal');
|
|
318
|
+
const selectButton = document.getElementById('selectWallet');
|
|
319
|
+
|
|
320
|
+
if (!modal || !selectButton) {
|
|
321
|
+
console.error('Wallet modal or select button not found, retry', this._setupRetryCount);
|
|
322
|
+
// Retry after a short delay if elements aren't ready yet
|
|
323
|
+
if (this.mounted && this._setupRetryCount <= 10) {
|
|
324
|
+
this.setTimeout(() => {
|
|
325
|
+
this.setupWalletModal();
|
|
326
|
+
}, 200);
|
|
327
|
+
}
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Reset retry count on success
|
|
332
|
+
this._setupRetryCount = 0;
|
|
333
|
+
|
|
334
|
+
// Create WalletModal instance
|
|
335
|
+
if (!this.walletModal) {
|
|
336
|
+
// Get provider map and icons from this.walletService
|
|
337
|
+
const providerMap = {
|
|
338
|
+
rabby: () => window.ethereum?.isRabby ? window.ethereum : null,
|
|
339
|
+
rainbow: () => window.ethereum?.isRainbow ? window.ethereum : null,
|
|
340
|
+
phantom: () => window.phantom?.ethereum || null,
|
|
341
|
+
metamask: () => window.ethereum || null
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
const walletIcons = {
|
|
345
|
+
rabby: '/public/wallets/rabby.webp',
|
|
346
|
+
rainbow: '/public/wallets/rainbow.webp',
|
|
347
|
+
phantom: '/public/wallets/phantom.webp',
|
|
348
|
+
metamask: '/public/wallets/MetaMask.webp'
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
// Create WalletModal with callback
|
|
352
|
+
this.walletModal = new WalletModal(
|
|
353
|
+
providerMap,
|
|
354
|
+
walletIcons,
|
|
355
|
+
async (walletType) => {
|
|
356
|
+
await this.handleWalletSelection(walletType);
|
|
357
|
+
}
|
|
358
|
+
);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// Set up select button click handler
|
|
362
|
+
// Clone button to remove any existing handlers
|
|
363
|
+
const newButton = selectButton.cloneNode(true);
|
|
364
|
+
selectButton.parentNode.replaceChild(newButton, selectButton);
|
|
365
|
+
|
|
366
|
+
newButton.addEventListener('click', (e) => {
|
|
367
|
+
e.preventDefault();
|
|
368
|
+
e.stopPropagation();
|
|
369
|
+
|
|
370
|
+
// Don't do anything if wallet is not available
|
|
371
|
+
if (!this.state.walletAvailable) {
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
console.log('SELECT WALLET button clicked');
|
|
376
|
+
|
|
377
|
+
if (this.walletModal) {
|
|
378
|
+
console.log('Calling walletModal.show()');
|
|
379
|
+
this.walletModal.show();
|
|
380
|
+
|
|
381
|
+
// Double-check modal is visible
|
|
382
|
+
const modalEl = document.getElementById('walletModal');
|
|
383
|
+
if (modalEl) {
|
|
384
|
+
console.log('Modal element found, checking visibility');
|
|
385
|
+
console.log('Modal classes:', modalEl.className);
|
|
386
|
+
console.log('Modal display:', window.getComputedStyle(modalEl).display);
|
|
387
|
+
modalEl.style.display = 'flex';
|
|
388
|
+
modalEl.classList.add('active');
|
|
389
|
+
} else {
|
|
390
|
+
console.error('Modal element not found after show()');
|
|
391
|
+
}
|
|
392
|
+
} else {
|
|
393
|
+
console.error('WalletModal not initialized');
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
// Set up continue button click handler
|
|
398
|
+
const continueButton = document.getElementById('continueButton');
|
|
399
|
+
if (continueButton) {
|
|
400
|
+
const newContinueButton = continueButton.cloneNode(true);
|
|
401
|
+
continueButton.parentNode.replaceChild(newContinueButton, continueButton);
|
|
402
|
+
|
|
403
|
+
newContinueButton.addEventListener('click', async (e) => {
|
|
404
|
+
e.preventDefault();
|
|
405
|
+
e.stopPropagation();
|
|
406
|
+
|
|
407
|
+
// If wallet is available (detected), just continue
|
|
408
|
+
// The site can use window.ethereum for RPC reads even if not connected
|
|
409
|
+
if (this.state.walletAvailable) {
|
|
410
|
+
if (this.onConnected) {
|
|
411
|
+
this.onConnected();
|
|
412
|
+
}
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// If no wallet available, load light node
|
|
417
|
+
if (!this.state.walletAvailable) {
|
|
418
|
+
await this.handleContinueWithoutWallet();
|
|
419
|
+
}
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// Set up close button handler
|
|
424
|
+
const closeButton = modal.querySelector('.wallet-modal-close');
|
|
425
|
+
if (closeButton) {
|
|
426
|
+
// Remove any existing listeners by cloning
|
|
427
|
+
const newCloseButton = closeButton.cloneNode(true);
|
|
428
|
+
closeButton.parentNode.replaceChild(newCloseButton, closeButton);
|
|
429
|
+
|
|
430
|
+
newCloseButton.addEventListener('click', (e) => {
|
|
431
|
+
e.preventDefault();
|
|
432
|
+
e.stopPropagation();
|
|
433
|
+
if (this.walletModal) {
|
|
434
|
+
this.walletModal.hide();
|
|
435
|
+
} else {
|
|
436
|
+
// Fallback if walletModal not initialized
|
|
437
|
+
const modalEl = document.getElementById('walletModal');
|
|
438
|
+
if (modalEl) {
|
|
439
|
+
modalEl.classList.remove('active');
|
|
440
|
+
modalEl.style.display = 'none';
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// Set up click outside to close
|
|
447
|
+
// WalletModal already has this, but we'll ensure it works
|
|
448
|
+
// Don't clone modal as it breaks WalletModal's reference
|
|
449
|
+
const handleModalClick = (e) => {
|
|
450
|
+
if (e.target === modal) {
|
|
451
|
+
if (this.walletModal) {
|
|
452
|
+
this.walletModal.hide();
|
|
453
|
+
} else {
|
|
454
|
+
modal.classList.remove('active');
|
|
455
|
+
modal.style.display = 'none';
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
// Remove existing listener if any, then add new one
|
|
461
|
+
modal.removeEventListener('click', handleModalClick);
|
|
462
|
+
modal.addEventListener('click', handleModalClick);
|
|
463
|
+
}, 100);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
async handleWalletSelection(walletType) {
|
|
467
|
+
try {
|
|
468
|
+
// Select the wallet
|
|
469
|
+
await this.walletService.selectWallet(walletType);
|
|
470
|
+
|
|
471
|
+
// Store the selected wallet in localStorage for future auto-reconnect
|
|
472
|
+
localStorage.setItem('ms2fun_lastWallet', walletType);
|
|
473
|
+
|
|
474
|
+
// Connect to the wallet
|
|
475
|
+
await this.walletService.connect();
|
|
476
|
+
|
|
477
|
+
// Wallet is now connected
|
|
478
|
+
this.setState({ walletConnected: true });
|
|
479
|
+
|
|
480
|
+
if (this.onConnected) {
|
|
481
|
+
this.onConnected();
|
|
482
|
+
}
|
|
483
|
+
} catch (error) {
|
|
484
|
+
console.error('Error connecting wallet:', error);
|
|
485
|
+
// Show error - could use MessagePopup here
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* Handle continue button click when no wallet is available
|
|
491
|
+
* Lazy-loads the light node and initializes read-only mode
|
|
492
|
+
*/
|
|
493
|
+
async handleContinueWithoutWallet() {
|
|
494
|
+
if (this.state.loadingLightNode) {
|
|
495
|
+
return; // Already loading
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
this.setState({ loadingLightNode: true });
|
|
499
|
+
|
|
500
|
+
try {
|
|
501
|
+
console.log('[WalletSplash] Loading light node for read-only mode...');
|
|
502
|
+
|
|
503
|
+
// Dynamically import and initialize read-only mode
|
|
504
|
+
const { initializeReadOnlyMode } = await import('../../index.js');
|
|
505
|
+
const success = await initializeReadOnlyMode();
|
|
506
|
+
|
|
507
|
+
if (success) {
|
|
508
|
+
console.log('[WalletSplash] Light node loaded successfully');
|
|
509
|
+
// Continue to app (read-only mode)
|
|
510
|
+
if (this.onConnected) {
|
|
511
|
+
this.onConnected();
|
|
512
|
+
}
|
|
513
|
+
} else {
|
|
514
|
+
console.error('[WalletSplash] Failed to load light node');
|
|
515
|
+
// Show error message
|
|
516
|
+
const statusEl = document.getElementById('contractStatus');
|
|
517
|
+
if (statusEl) {
|
|
518
|
+
statusEl.textContent = 'FAILED TO LOAD LIGHT NODE. PLEASE TRY AGAIN.';
|
|
519
|
+
}
|
|
520
|
+
this.setState({ loadingLightNode: false });
|
|
521
|
+
}
|
|
522
|
+
} catch (error) {
|
|
523
|
+
console.error('[WalletSplash] Error loading light node:', error);
|
|
524
|
+
const statusEl = document.getElementById('contractStatus');
|
|
525
|
+
if (statusEl) {
|
|
526
|
+
statusEl.textContent = 'ERROR: ' + error.message;
|
|
527
|
+
}
|
|
528
|
+
this.setState({ loadingLightNode: false });
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
onStateUpdate(oldState, newState) {
|
|
533
|
+
// When wallet connects, hide splash
|
|
534
|
+
if (!oldState.walletConnected && newState.walletConnected) {
|
|
535
|
+
// Hide the splash screen
|
|
536
|
+
if (this.element) {
|
|
537
|
+
this.element.style.display = 'none';
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
// Hide modal if open
|
|
541
|
+
if (this.walletModal) {
|
|
542
|
+
this.walletModal.hide();
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
// When wallet disconnects, show splash again
|
|
547
|
+
if (oldState.walletConnected && !newState.walletConnected) {
|
|
548
|
+
// Show the splash screen
|
|
549
|
+
if (this.element) {
|
|
550
|
+
this.element.style.display = 'flex';
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
this.setTimeout(() => {
|
|
554
|
+
this.setupWalletModal();
|
|
555
|
+
}, 0);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
onUnmount() {
|
|
560
|
+
// Clean up wallet modal
|
|
561
|
+
if (this.walletModal) {
|
|
562
|
+
this.walletModal.hide();
|
|
563
|
+
this.walletModal = null;
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
|
package/src/index.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// Services
|
|
2
|
+
import BlockchainService from './services/BlockchainService.js';
|
|
3
|
+
import WalletService from './services/WalletService.js';
|
|
4
|
+
import ContractCache from './services/ContractCache.js';
|
|
5
|
+
import PriceService from './services/PriceService.js';
|
|
6
|
+
import * as IpfsService from './services/IpfsService.js';
|
|
7
|
+
|
|
8
|
+
// UI Components
|
|
9
|
+
import { WalletSplash } from './components/Wallet/WalletSplash.js';
|
|
10
|
+
import { WalletModal } from './components/Wallet/WalletModal.js';
|
|
11
|
+
import { IpfsImage } from './components/Ipfs/IpfsImage.js';
|
|
12
|
+
import { SwapInterface } from './components/Swap/SwapInterface.js';
|
|
13
|
+
import { SwapInputs } from './components/Swap/SwapInputs.js';
|
|
14
|
+
import { SwapButton } from './components/Swap/SwapButton.js';
|
|
15
|
+
import { TransactionOptions } from './components/Swap/TransactionOptions.js';
|
|
16
|
+
import { ApprovalModal } from './components/Modal/ApprovalModal.js';
|
|
17
|
+
import { BondingCurve } from './components/BondingCurve/BondingCurve.js';
|
|
18
|
+
import { PriceDisplay } from './components/Display/PriceDisplay.js';
|
|
19
|
+
import { BalanceDisplay } from './components/Display/BalanceDisplay.js';
|
|
20
|
+
import { MessagePopup } from './components/Util/MessagePopup.js';
|
|
21
|
+
|
|
22
|
+
export {
|
|
23
|
+
// Services
|
|
24
|
+
BlockchainService,
|
|
25
|
+
WalletService,
|
|
26
|
+
ContractCache,
|
|
27
|
+
PriceService,
|
|
28
|
+
IpfsService,
|
|
29
|
+
|
|
30
|
+
// UI Components
|
|
31
|
+
WalletSplash,
|
|
32
|
+
WalletModal,
|
|
33
|
+
IpfsImage,
|
|
34
|
+
SwapInterface,
|
|
35
|
+
SwapInputs,
|
|
36
|
+
SwapButton,
|
|
37
|
+
TransactionOptions,
|
|
38
|
+
ApprovalModal,
|
|
39
|
+
BondingCurve,
|
|
40
|
+
PriceDisplay,
|
|
41
|
+
BalanceDisplay,
|
|
42
|
+
MessagePopup
|
|
43
|
+
};
|