I have created an unpacked extension that is working fine I want it to be injected and be able to connect it with apps like MetaMask
wallet does.
I have created a provider.js
script to do it. I want to know if that is the correct approach to do what I want because when trying to connect with a vue app I am running on localhost in Chrome I get Failed to connect extension not installed error
This is the provider script:
// Verus Web Wallet Provider Implementation
export const createVerusProvider = () => ({
isVerusWallet: true,
version: '1.0.0',
_isConnected: false,
_address: null,
_listeners: new Map(),
_connecting: null,
// Request account access (legacy method)
requestAccounts: function() {
console.log('requestAccounts called');
return this.connect().then(result => [result.address]);
},
// Connect to the wallet (new method)
connect: function() {
console.log('connect called');
// Return existing connection if already connected
if (this._isConnected && this._address) {
return Promise.resolve({ address: this._address });
}
// Return existing connection attempt if in progress
if (this._connecting) {
return this._connecting;
}
const that = this;
this._connecting = new Promise((resolve, reject) => {
const timeoutId = setTimeout(() => {
window.removeEventListener('message', handler);
reject(new Error('Connection request timed out'));
}, 30000); // 30 second timeout
function handler(event) {
if (event.source !== window) return;
if (event.data.type === 'VERUS_CONNECT_RESPONSE') {
clearTimeout(timeoutId);
window.removeEventListener('message', handler);
if (event.data.error) {
that._connecting = null;
reject(new Error(event.data.error));
} else {
that._isConnected = true;
that._address = event.data.result.address;
that._emitEvent('connect', { address: event.data.result.address });
resolve(event.data.result);
}
}
}
window.addEventListener('message', handler);
window.postMessage({ type: 'VERUS_CONNECT_REQUEST' }, '*');
}).finally(() => {
this._connecting = null;
});
return this._connecting;
},
// Get connected account
getAccount: function() {
console.log('getAccount called');
if (!this._isConnected) {
throw new Error('Wallet not connected');
}
return Promise.resolve(this._address);
},
// Send transaction
sendTransaction: function(params) {
console.log('sendTransaction called');
if (!this._isConnected) {
throw new Error('Wallet not connected');
}
return new Promise((resolve, reject) => {
window.addEventListener('message', function handler(event) {
if (event.source !== window) return;
if (event.data.type === 'VERUS_SEND_TRANSACTION_RESPONSE') {
window.removeEventListener('message', handler);
if (event.data.error) {
reject(new Error(event.data.error));
} else {
resolve(event.data.result);
}
}
});
window.postMessage({
type: 'VERUS_SEND_TRANSACTION_REQUEST',
params
}, '*');
});
},
// Event handling
on: function(eventName, callback) {
console.log('on called:', eventName);
if (!this._listeners.has(eventName)) {
this._listeners.set(eventName, new Set());
}
this._listeners.get(eventName).add(callback);
},
off: function(eventName, callback) {
console.log('off called:', eventName);
if (this._listeners.has(eventName)) {
this._listeners.get(eventName).delete(callback);
}
},
_emitEvent: function(eventName, data) {
console.log('_emitEvent called:', eventName, data);
if (this._listeners.has(eventName)) {
this._listeners.get(eventName).forEach(callback => {
try {
callback(data);
} catch (error) {
console.error('Error in event listener:', error);
}
});
}
}
});
It is a MetaMask style wallet that I am working on for Layer 1 blockchain Verus:
In my other App this is how I am trying to connect with the extension:
import { ref, onMounted } from 'vue';
export function useVerusWallet() {
const address = ref(null);
const isConnected = ref(false);
const error = ref(null);
// Check if Verus wallet is installed
const checkWalletInstalled = () => {
return window.isVerusWalletInstalled === true;
};
// Connect to wallet with timeout
const connectWallet = async () => {
try {
if (!checkWalletInstalled()) {
throw new Error('Verus Wallet extension not installed');
}
// Add timeout to the connection request
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => reject(new Error('Connection timeout')), 30000); // 30 second timeout
});
const connectionPromise = window.verus.requestAccounts();
const accounts = await Promise.race([connectionPromise, timeoutPromise]);
if (!accounts || accounts.length === 0) {
throw new Error('No accounts found');
}
address.value = accounts[0];
isConnected.value = true;
error.value = null;
return accounts[0];
} catch (err) {
error.value = err.message;
isConnected.value = false;
throw err;
}
};
// Get current account
const getAccount = async () => {
try {
if (!checkWalletInstalled()) {
throw new Error('Verus Wallet extension not installed');
}
const accounts = await window.verus.getAccounts();
if (!accounts || accounts.length === 0) {
throw new Error('No accounts found');
}
address.value = accounts[0];
isConnected.value = true;
return accounts[0];
} catch (err) {
error.value = err.message;
isConnected.value = false;
throw err;
}
};
// Listen for account changes
onMounted(() => {
if (checkWalletInstalled()) {
// Check initial connection status
window.verus.getAccounts().then(accounts => {
if (accounts && accounts.length > 0) {
address.value = accounts[0];
isConnected.value = true;
}
}).catch(() => {
isConnected.value = false;
});
// Listen for account changes
window.verus.on('accountsChanged', (accounts) => {
if (accounts && accounts.length > 0) {
address.value = accounts[0];
isConnected.value = true;
} else {
address.value = null;
isConnected.value = false;
}
});
// Listen for disconnect events
window.verus.on('disconnect', () => {
address.value = null;
isConnected.value = false;
});
}
});
return {
address,
isConnected,
error,
connectWallet,
getAccount,
checkWalletInstalled
};
}