Skip to content

Commit 2d6c642

Browse files
Copilot0xrinegade
andcommitted
Fix critical MetaMask provider conflicts and c.homedir errors - enhanced multi-provider support
Co-authored-by: 0xrinegade <[email protected]>
1 parent 7baef80 commit 2d6c642

File tree

4 files changed

+273
-62
lines changed

4 files changed

+273
-62
lines changed

public/buffer-polyfill.js

Lines changed: 95 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@
183183
var global = window;
184184
}
185185

186-
// Add defensive handling for wallet extension conflicts
186+
// Enhanced defensive handling for wallet extension conflicts
187187
(function() {
188188
try {
189189
// Store reference to any existing ethereum provider
@@ -193,39 +193,118 @@
193193
if (!window.ethereumHandlersInitialized) {
194194
window.ethereumHandlersInitialized = true;
195195

196-
// Create a non-conflicting ethereum property wrapper
197-
Object.defineProperty(window, '_svmseekEthereumSafe', {
198-
value: existingEthereum,
199-
writable: false,
200-
configurable: false
196+
// Create a multiple provider management system
197+
const providerRegistry = new Map();
198+
let primaryProvider = existingEthereum;
199+
200+
// Register existing provider if any
201+
if (existingEthereum) {
202+
if (existingEthereum.isMetaMask) {
203+
providerRegistry.set('metamask', existingEthereum);
204+
} else if (existingEthereum.isPhantom) {
205+
providerRegistry.set('phantom', existingEthereum);
206+
} else {
207+
providerRegistry.set('unknown', existingEthereum);
208+
}
209+
}
210+
211+
// Create a proxy ethereum object that can handle multiple providers
212+
const ethereumProxy = new Proxy(primaryProvider || {}, {
213+
get: function(target, prop) {
214+
// Handle provider-specific access
215+
if (prop === 'providers' && providerRegistry.size > 0) {
216+
return Array.from(providerRegistry.values());
217+
}
218+
if (prop === 'getProvider') {
219+
return function(name) {
220+
return providerRegistry.get(name) || primaryProvider;
221+
};
222+
}
223+
if (prop === 'isMultiProvider') {
224+
return providerRegistry.size > 1;
225+
}
226+
227+
// Delegate to primary provider or target
228+
const provider = primaryProvider || target;
229+
if (provider && typeof provider[prop] !== 'undefined') {
230+
const value = provider[prop];
231+
return typeof value === 'function' ? value.bind(provider) : value;
232+
}
233+
234+
return target[prop];
235+
},
236+
set: function(target, prop, value) {
237+
if (primaryProvider) {
238+
primaryProvider[prop] = value;
239+
} else {
240+
target[prop] = value;
241+
}
242+
return true;
243+
}
201244
});
202245

203-
// Override Object.defineProperty to handle ethereum property conflicts
246+
// Override Object.defineProperty to handle ethereum property conflicts gracefully
204247
const originalDefineProperty = Object.defineProperty;
205248
Object.defineProperty = function(obj, prop, descriptor) {
206249
if (obj === window && prop === 'ethereum') {
207250
try {
208-
// If ethereum already exists and is non-configurable, skip redefinition
209-
const existingDescriptor = Object.getOwnPropertyDescriptor(window, 'ethereum');
210-
if (existingDescriptor && !existingDescriptor.configurable) {
211-
console.warn('SVMSeek: Skipping ethereum property redefinition to prevent conflicts');
212-
return obj;
251+
// Check if we're dealing with a new provider
252+
const newProvider = descriptor.value;
253+
if (newProvider && typeof newProvider === 'object') {
254+
// Register the new provider
255+
let providerName = 'unknown';
256+
if (newProvider.isMetaMask) providerName = 'metamask';
257+
else if (newProvider.isPhantom) providerName = 'phantom';
258+
else if (newProvider.isSVMSeek) providerName = 'svmseek';
259+
else if (newProvider.isWalletConnect) providerName = 'walletconnect';
260+
261+
providerRegistry.set(providerName, newProvider);
262+
263+
// Update primary provider if this is the first or a preferred provider
264+
if (!primaryProvider || newProvider.isMetaMask) {
265+
primaryProvider = newProvider;
266+
}
267+
268+
console.log('SVMSeek: Registered ethereum provider:', providerName);
269+
270+
// Return the proxy instead of setting directly
271+
return originalDefineProperty.call(this, obj, prop, {
272+
value: ethereumProxy,
273+
writable: descriptor.writable,
274+
configurable: descriptor.configurable,
275+
enumerable: descriptor.enumerable
276+
});
213277
}
214278

215-
// Allow the definition but catch any errors
279+
// Allow the definition for non-provider values
216280
return originalDefineProperty.call(this, obj, prop, descriptor);
217281
} catch (error) {
218-
console.warn('SVMSeek: Prevented ethereum property conflict:', error.message);
282+
console.warn('SVMSeek: Handled ethereum property conflict gracefully:', error.message);
283+
// Don't throw, just log and continue
219284
return obj;
220285
}
221286
}
222287
return originalDefineProperty.call(this, obj, prop, descriptor);
223288
};
224289

225-
console.log('SVMSeek: Ethereum property conflict protection enabled');
290+
// Set initial ethereum proxy if we have providers
291+
if (providerRegistry.size > 0 || primaryProvider) {
292+
try {
293+
originalDefineProperty.call(Object, window, 'ethereum', {
294+
value: ethereumProxy,
295+
writable: true,
296+
configurable: true,
297+
enumerable: true
298+
});
299+
} catch (error) {
300+
console.warn('SVMSeek: Could not set initial ethereum proxy:', error.message);
301+
}
302+
}
303+
304+
console.log('SVMSeek: Enhanced ethereum provider management enabled');
226305
}
227306
} catch (error) {
228-
console.warn('SVMSeek: Failed to setup ethereum conflict protection:', error);
307+
console.warn('SVMSeek: Failed to setup enhanced ethereum conflict protection:', error);
229308
}
230309
})();
231310

src/polyfills/ultimate-fix.js

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ function setupSecureErrorHandling() {
137137
colno,
138138
error,
139139
) {
140-
// Handle homedir errors specifically
140+
// Handle homedir errors specifically with enhanced recovery
141141
if (
142142
typeof message === 'string' &&
143143
(message.includes('c.homedir is not a function') ||
@@ -153,18 +153,54 @@ function setupSecureErrorHandling() {
153153
) {
154154
logError('OS/Buffer access error intercepted:', message);
155155

156-
// Emergency polyfill injection
156+
// Emergency polyfill injection with enhanced coverage
157157
try {
158158
if (typeof window !== 'undefined') {
159159
// Ensure os polyfill is available
160160
if (!window.os || !window.os.homedir) {
161161
window.os = osPolyfill;
162162
}
163+
163164
// Fix any undefined 'c' object that might be causing issues
164165
if (typeof window.c === 'undefined') {
165-
window.c = { homedir: osPolyfill.homedir };
166+
window.c = {
167+
homedir: osPolyfill.homedir,
168+
resolve: function(...args) {
169+
// Basic path resolution for compatibility
170+
return args.join('/').replace(/\/+/g, '/');
171+
}
172+
};
166173
} else if (window.c && !window.c.homedir) {
167174
window.c.homedir = osPolyfill.homedir;
175+
if (!window.c.resolve) {
176+
window.c.resolve = function(...args) {
177+
return args.join('/').replace(/\/+/g, '/');
178+
};
179+
}
180+
}
181+
182+
// Also ensure global path resolution is available
183+
if (!window.path) {
184+
window.path = {
185+
resolve: function(...args) {
186+
return args.join('/').replace(/\/+/g, '/');
187+
},
188+
join: function(...args) {
189+
return args.join('/').replace(/\/+/g, '/');
190+
},
191+
dirname: function(p) {
192+
return p.split('/').slice(0, -1).join('/') || '/';
193+
},
194+
basename: function(p) {
195+
return p.split('/').pop() || '';
196+
}
197+
};
198+
}
199+
200+
// Add to require cache if available
201+
if (window.require && typeof window.require.cache === 'object') {
202+
window.require.cache['os'] = { exports: window.os };
203+
window.require.cache['path'] = { exports: window.path };
168204
}
169205
}
170206
} catch (recoveryError) {

src/services/WalletInjectionScript.ts

Lines changed: 50 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -298,30 +298,50 @@ export function createWalletInjectionScript(): string {
298298
const phantomProvider = createWalletProvider('phantom');
299299
const svmseekProvider = createWalletProvider('svmseek');
300300
301+
// Check for existing providers to avoid conflicts
302+
const existingProviders = {
303+
solana: window.solana,
304+
phantom: window.phantom,
305+
svmseek: window.svmseek
306+
};
307+
301308
// Inject providers with proper property descriptors for security
302-
Object.defineProperty(window, 'solana', {
303-
value: solanaProvider,
304-
writable: false,
305-
configurable: false,
306-
enumerable: true
307-
});
309+
// Only inject if not already present to avoid conflicts
310+
if (!existingProviders.solana) {
311+
Object.defineProperty(window, 'solana', {
312+
value: solanaProvider,
313+
writable: false,
314+
configurable: false,
315+
enumerable: true
316+
});
317+
} else {
318+
console.warn('SVMSeek: Solana provider already exists, skipping injection');
319+
}
308320
309-
Object.defineProperty(window, 'phantom', {
310-
value: {
311-
solana: phantomProvider,
312-
isPhantom: true
313-
},
314-
writable: false,
315-
configurable: false,
316-
enumerable: true
317-
});
321+
if (!existingProviders.phantom) {
322+
Object.defineProperty(window, 'phantom', {
323+
value: {
324+
solana: phantomProvider,
325+
isPhantom: true
326+
},
327+
writable: false,
328+
configurable: false,
329+
enumerable: true
330+
});
331+
} else {
332+
console.warn('SVMSeek: Phantom provider already exists, skipping injection');
333+
}
318334
319-
Object.defineProperty(window, 'svmseek', {
320-
value: svmseekProvider,
321-
writable: false,
322-
configurable: false,
323-
enumerable: true
324-
});
335+
if (!existingProviders.svmseek) {
336+
Object.defineProperty(window, 'svmseek', {
337+
value: svmseekProvider,
338+
writable: false,
339+
configurable: false,
340+
enumerable: true
341+
});
342+
} else {
343+
console.warn('SVMSeek: SVMSeek provider already exists, skipping injection');
344+
}
325345
326346
// Mark injection as complete
327347
Object.defineProperty(window, 'svmseekWalletInjected', {
@@ -334,9 +354,9 @@ export function createWalletInjectionScript(): string {
334354
// Store provider references for external access
335355
Object.defineProperty(window, 'svmseekProviders', {
336356
value: {
337-
solana: solanaProvider,
338-
phantom: phantomProvider,
339-
svmseek: svmseekProvider
357+
solana: window.solana || solanaProvider,
358+
phantom: window.phantom?.solana || phantomProvider,
359+
svmseek: window.svmseek || svmseekProvider
340360
},
341361
writable: false,
342362
configurable: false,
@@ -348,11 +368,15 @@ export function createWalletInjectionScript(): string {
348368
detail: {
349369
version: '1.0.0',
350370
providers: ['solana', 'phantom', 'svmseek'],
351-
timestamp: Date.now()
371+
timestamp: Date.now(),
372+
conflictsDetected: Object.values(existingProviders).some(p => p !== undefined)
352373
}
353374
}));
354375
355-
console.log('SVMSeek: Wallet providers injected successfully');
376+
console.log('SVMSeek: Wallet providers injected successfully', {
377+
conflictsDetected: Object.values(existingProviders).some(p => p !== undefined),
378+
existingProviders: Object.keys(existingProviders).filter(key => existingProviders[key])
379+
});
356380
357381
} catch (error) {
358382
console.error('SVMSeek: Failed to inject wallet providers:', error);

0 commit comments

Comments
 (0)