|
3 | 3 | * |
4 | 4 | * This script is injected into the <head> of the deployed HTML file and provides: |
5 | 5 | * 1. EIP-6963 provider discovery |
6 | | - * 2. A Proxy on window.ethereum that intercepts eth_requestAccounts |
7 | | - * 3. A minimal wallet selection modal (inline HTML/CSS) |
| 6 | + * 2. A wallet selection modal (inline HTML/CSS) |
| 7 | + * 3. A global `window.__qdapp_getProvider()` function for DApp code to call |
8 | 8 | * 4. localStorage-based auto-reconnect on page refresh |
9 | 9 | * |
| 10 | + * It does NOT override `window.ethereum` — avoids conflicts with MetaMask/Coinbase. |
10 | 11 | * It is NOT injected in the IDE preview (VM Bridge or parent.ethereum are used there). |
11 | 12 | */ |
12 | 13 | export function generateWalletSelectionScript(): string { |
@@ -83,11 +84,11 @@ export function generateWalletSelectionScript(): string { |
83 | 84 | return resolve(_providers[0].provider); |
84 | 85 | } |
85 | 86 |
|
86 | | - // No providers? Fall back to legacy window.ethereum if captured |
| 87 | + // No providers? Fall back to legacy window.ethereum |
87 | 88 | if (_providers.length === 0) { |
88 | | - if (window.__qdapp_legacy_ethereum) { |
| 89 | + if (window.ethereum) { |
89 | 90 | _modalPromise = null; |
90 | | - return resolve(window.__qdapp_legacy_ethereum); |
| 91 | + return resolve(window.ethereum); |
91 | 92 | } |
92 | 93 | _modalPromise = null; |
93 | 94 | return reject(new Error('No Ethereum wallet detected. Please install a wallet extension.')); |
@@ -178,119 +179,14 @@ export function generateWalletSelectionScript(): string { |
178 | 179 | return div.innerHTML; |
179 | 180 | } |
180 | 181 |
|
181 | | - // ── 4. Proxy window.ethereum ──────────────────────────────── |
182 | | - // Capture any existing window.ethereum (e.g. from legacy injection) |
183 | | - if (window.ethereum) { |
184 | | - window.__qdapp_legacy_ethereum = window.ethereum; |
185 | | - } |
186 | | -
|
187 | | - var _resolved = false; |
188 | | - var _selectedProvider = null; |
189 | | - var _eventListeners = {}; |
190 | | -
|
191 | | - function getProviderOrProxy() { |
192 | | - if (_resolved && _selectedProvider) return _selectedProvider; |
193 | | -
|
194 | | - return new Proxy({ |
195 | | - isMetaMask: true, // Some DApps check this |
196 | | - _isQuickDappProxy: true, |
197 | | -
|
198 | | - request: function(args) { |
199 | | - if (_resolved && _selectedProvider) { |
200 | | - return _selectedProvider.request(args); |
201 | | - } |
202 | | - return showWalletModal().then(function(provider) { |
203 | | - _selectedProvider = provider; |
204 | | - _resolved = true; |
205 | | - // Object.defineProperty getter will now return _selectedProvider |
206 | | - // Replay any buffered event listeners |
207 | | - Object.keys(_eventListeners).forEach(function(evt) { |
208 | | - _eventListeners[evt].forEach(function(cb) { |
209 | | - try { provider.on(evt, cb); } catch(e) {} |
210 | | - }); |
211 | | - }); |
212 | | - return provider.request(args); |
213 | | - }); |
214 | | - }, |
215 | | -
|
216 | | - on: function(event, cb) { |
217 | | - if (_resolved && _selectedProvider) { |
218 | | - return _selectedProvider.on(event, cb); |
219 | | - } |
220 | | - // Buffer listeners for later replay |
221 | | - if (!_eventListeners[event]) _eventListeners[event] = []; |
222 | | - _eventListeners[event].push(cb); |
223 | | - return this; |
224 | | - }, |
225 | | -
|
226 | | - removeListener: function(event, cb) { |
227 | | - if (_resolved && _selectedProvider) { |
228 | | - return _selectedProvider.removeListener(event, cb); |
229 | | - } |
230 | | - if (_eventListeners[event]) { |
231 | | - _eventListeners[event] = _eventListeners[event].filter(function(l) { return l !== cb; }); |
232 | | - } |
233 | | - return this; |
234 | | - }, |
235 | | -
|
236 | | - removeAllListeners: function() { |
237 | | - if (_resolved && _selectedProvider) { |
238 | | - return _selectedProvider.removeAllListeners(); |
239 | | - } |
240 | | - _eventListeners = {}; |
241 | | - return this; |
242 | | - } |
243 | | - }, { |
244 | | - get: function(target, prop) { |
245 | | - // If we already resolved, delegate everything |
246 | | - if (_resolved && _selectedProvider) { |
247 | | - var val = _selectedProvider[prop]; |
248 | | - if (typeof val === 'function') return val.bind(_selectedProvider); |
249 | | - return val; |
250 | | - } |
251 | | - // Return target's own methods |
252 | | - if (prop in target) { |
253 | | - var v = target[prop]; |
254 | | - if (typeof v === 'function') return v.bind(target); |
255 | | - return v; |
256 | | - } |
257 | | - return undefined; |
258 | | - } |
259 | | - }); |
260 | | - } |
261 | | -
|
262 | | - // Use Object.defineProperty to prevent wallet extensions from overwriting our Proxy. |
263 | | - // When MetaMask/Coinbase content scripts try to set window.ethereum, we capture |
264 | | - // their provider but keep our Proxy in control until the user selects a wallet. |
265 | | - var _proxyProvider = getProviderOrProxy(); |
266 | | -
|
267 | | - try { |
268 | | - Object.defineProperty(window, 'ethereum', { |
269 | | - get: function() { |
270 | | - if (_resolved && _selectedProvider) return _selectedProvider; |
271 | | - return _proxyProvider; |
272 | | - }, |
273 | | - set: function(val) { |
274 | | - if (val && !val._isQuickDappProxy) { |
275 | | - window.__qdapp_legacy_ethereum = val; |
276 | | - } |
277 | | - if (_resolved) { |
278 | | - _selectedProvider = val; |
279 | | - } |
280 | | - }, |
281 | | - configurable: true, |
282 | | - enumerable: true |
283 | | - }); |
284 | | - } catch (e) { |
285 | | - // MetaMask (Chrome) may define window.ethereum as non-configurable before us. |
286 | | - // Fall back to using the existing provider directly. |
287 | | - console.warn('[QuickDapp] Cannot override window.ethereum:', e.message); |
288 | | - if (window.ethereum) { |
289 | | - window.__qdapp_legacy_ethereum = window.ethereum; |
290 | | - } |
291 | | - } |
| 182 | + // ── 4. Expose global provider getter ──────────────────────── |
| 183 | + // DApp code calls: window.__qdapp_getProvider() |
| 184 | + // Returns a Promise<EIP1193Provider> — either auto-selected or user-picked. |
| 185 | + window.__qdapp_getProvider = function() { |
| 186 | + return showWalletModal(); |
| 187 | + }; |
292 | 188 |
|
293 | | - console.log('[QuickDapp] Wallet selection script loaded. Detected', _providers.length, 'EIP-6963 providers.'); |
| 189 | + console.log('[QuickDapp] Wallet selection script loaded.'); |
294 | 190 | })(); |
295 | 191 | </script>`; |
296 | 192 | } |
0 commit comments