Non-Ethereum browser detected. You should consider trying MetaMask - javascript

Im having a simple UI where i need a metamask connect button
but when i use this code i keep getting the
"Non-Ethereum browser detected. You should consider trying MetaMask!" error even though i have metamsk up an running in my browser
This is the code here:
window.addEventListener('load', async () => {
// Modern dapp browsers...
if (window.ethereum) {
window.web3 = new Web3(ethereum);
try {
await ethereum.enable();
var accounts= await web3.eth.getAccounts();
var option={from: accounts[0] };
} catch (error) {
// User denied account access...
}
}
// Legacy dapp browsers...
else if (window.web3) {
window.web3 = new Web3(web3.currentProvider);
// Acccounts always exposed
web3.eth.sendTransaction({/* ... */});
}
// Non-dapp browsers...
else {
console.log('Non-Ethereum browser detected. You should consider trying MetaMask!');
}
const ethereumButton = document.querySelector('.enableEthereumButton');
const showAccount = document.querySelector('.showAccount');
ethereumButton.addEventListener('click', () => {
getAccount();
});
async function getAccount() {
const accounts = await ethereum.request({ method: 'eth_requestAccounts' });
const account = accounts[0];
showAccount.innerHTML = account;
};
and this are the 2 buttons for account and to connect
<button class="enableEthereumButton">Enable Ethereum</button>
<h2>Account: <span class="showAccount"></span></h2>
What do I need to do to make this work, i followed the metamask tutorial but they are written so bad, they are almost useless

You dont need to use window for metamask access. You can try replacing your if with somthing like this.
if (window.ethereum) {
const web3 = new Web3(ethereum);
try {
await ethereum.enable();
var accounts = await web3.eth.getAccounts();
console.log(accounts)
} catch (error) {
// User denied account access...
}
}
The getAccount() function isn't neccesary as you should be able to pull everything from the web3.eth.* anyway.

Related

How to handle web3JS without using external wallets

I wanted to use web3JS config without using external wallets like metamask. To handle automated functions using cron jobs which are supposed to run every week. Since metamask asks for permission to use send() method to remove that I wanted to use a account where I will upload private key and stuff. I got this code from internet it works for locally/browser wallets dont know where to edit.
import Web3 from "web3";
const getWeb3 = () =>
new Promise((resolve, reject) => {
// Wait for loading completion to avoid race conditions with web3 injection timing.
window.addEventListener("load", async () => {
// Modern dapp browsers...
if (window.ethereum) {
const web3 = new Web3(window.ethereum);
try {
// Request account access if needed
await window.ethereum.enable();
// Accounts now exposed
resolve(web3);
console.log("enabled", web3);
console.log("MetaMask injected");
} catch (error) {
reject(error);
}
}
// Legacy dapp browsers...
else if (window.web3) {
// Use Mist/MetaMask's provider.
const web3 = window.web3;
// const web3 = window.web3.currentProvider.enable();
console.log("Injected web3 detected.");
resolve(web3);
}
// Fallback to localhost; use dev console port by default...
else {
const provider = new Web3.providers.HttpProvider(
"http://127.0.0.1:7545"
);
const web3 = new Web3(provider);
console.log("No web3 instance injected, using Local web3.");
resolve(web3);
}
});
});
export default getWeb3;
solved it
const Web3 = require("web3");
const WalletProvider = require("#truffle/hdwallet-provider");
let provider = new WalletProvider({
mnemonic: {
phrase:
"*******",
},
providerOrUrl: "https://goerli.infura.io/v3/****************",
});
const web3 = new Web3(provider);
const fetch123 = async () => {
const accounts = await web3.eth.getAccounts();
console.log(accounts);
};
fetch123();

Uncaught (in promise) ReferenceError: Buffer is not defined. Using Phantom Wallet, Solana and React to make a transaction

I created a simple CRA app to figure out how to use the Phantom wallet to make Solana transactions(I still don't know If that is even possible). I referenced two Stackoverflow questions source and source and came up with a somewhat working code as in the airdrop is working perfectly fine but the main transaction is not.
This is my code:
import "./App.css";
import { useEffect, useState } from "react";
const web3 = require("#solana/web3.js");
function App() {
const [provider, setProvider] = useState(null);
const [walletKey, setWalletKey] = useState(null);
const getProvider = () => {
if ("solana" in window) {
const provider = window.solana;
if (provider.isPhantom) {
return provider;
}
}
};
const connectWallet = async () => {
const provider = getProvider();
if (provider) {
try {
const response = await provider.connect();
const pubKey = await provider.publicKey;
console.log(pubKey);
setProvider(provider);
setWalletKey(response.publicKey.toString());
} catch (err) {
// { code: 4001, message: 'User rejected the request.' }
}
}
};
useEffect(() => connectWallet, []);
const airDropSol = async (connection, publicKey) => {
try {
const airdropSignature = await connection.requestAirdrop(
publicKey,
web3.LAMPORTS_PER_SOL
);
const latestBlockHash = await connection.getLatestBlockhash();
// Confirming that the airdrop went through
await connection.confirmTransaction({
blockhash: latestBlockHash.blockhash,
lastValidBlockHeight: latestBlockHash.lastValidBlockHeight,
signature: airdropSignature,
});
console.log("Airdropped");
} catch (error) {
console.error(error);
}
};
async function transferSOL() {
//Changes are only here, in the beginning
const phantomProvider = provider;
if (!phantomProvider) {
console.log("No provider found", phantomProvider);
}
const pubKey = await phantomProvider.publicKey;
console.log("Public Key: ", pubKey);
// Establishing connection
var connection = new web3.Connection(web3.clusterApiUrl("devnet"));
// I have hardcoded my secondary wallet address here. You can take this address either from user input or your DB or wherever
var recieverWallet = new web3.PublicKey(
"Wallet Key I want to send SOL to here"
);
// Airdrop some SOL to the sender's wallet, so that it can handle the txn fee
airDropSol(connection, pubKey);
console.log("WORKED 1");
const transaction = new web3.Transaction();
const instructions = web3.SystemProgram.transfer({
fromPubkey: pubKey,
toPubkey: recieverWallet,
lamports: web3.LAMPORTS_PER_SOL, //Investing 1 SOL. Remember 1 Lamport = 10^-9 SOL.
});
transaction.add(instructions);
console.log("WORKED 2");
// Setting the variables for the transaction
transaction.feePayer = pubKey;
let blockhashObj = await connection.getLatestBlockhash();
transaction.recentBlockhash = blockhashObj.blockhash;
const signature = await phantomProvider.signAndSendTransaction(
connection,
transaction,
[pubKey]
);
await connection.confirmTransaction(signature);
console.log(signature);
}
return (
<div className="App">
<header className="App-header">
<h2>Tutorial: Connect to Phantom Wallet</h2>
{provider && walletKey && <p>Connected account {walletKey}</p>}
{provider && walletKey && <button onClick={transferSOL}>TEST</button>}
{!provider && (
<p>
No provider found. Install{" "}
Phantom Browser extension
</p>
)}
</header>
</div>
);
}
export default App;
This is the error generated in and I don't know how to fix it. Can anyone help? Error in browser console
Also when I run npm start this error in vcode console also gets shown.
All I want to do is simply send SOL from one phantom wallet to another like sending money in real life, I have spent alot of time trying to figure this out someone please point out the problem and help
Use #solana/web3.js version 1.30.2
New versions form web3 libraries need some dependencies and webpack configurations.
You can use a code I'm sharing:-
Refer my code on this link
With Webpack 5 you need to polyfill Buffer.
Here is a tutorial on how to do so https://viglucci.io/how-to-polyfill-buffer-with-webpack-5
And here is an example of a webpack config of a Solana dApp UI made with CRA https://github.com/Bonfida/serverless-merch/blob/master/ui/config-overrides.js

How to check if Metamask is connected after page refreshing

My dApp have to connect to MetaMask. There are two rude solutions in the docs: make user to click connect btn every time manually or just pop up connection confirmation after page load. I want to implement the only convenient solution: first time user connect manually by clicking the connect btn and interacting with MetaMask popup and then my dApp detect that connection is still established and use this connection. I can't find the solution, but i saw this in other dApps (Capture the ether for example) I use:
import detectEthereumProvider from '#metamask/detect-provider';
const provider = await detectEthereumProvider();
if (provider) {
connect(provider)
} else {
// kind of "Install the MetaMask please!"
}
function connect(provider) {
// How to check if the connection is here
if (//connection established) {
// Show the user connected account address
} else {
// Connect
provider.request({ method: "eth_requestAccounts" })
.then // some logic
}
}
I finally found a possible solution and it turned out to be as simple as it should be. There is an eth_accounts method in Ethereum JSON-RPC which allow us to ask for available accounts without actually requesting them. This way we can check if metamask is still connected (if there are any accounts) and avoid auto requesting or need of manually clicking "connect" every time. Simple example implementation could be:
// detect provider using #metamask/detect-provider
detectEthereumProvider().then((provider) => {
if (provider && provider.isMetaMask) {
provider.on('accountsChanged', handleAccountsChanged);
// connect btn is initially disabled
$('#connect-btn').addEventListener('click', connect);
checkConnection();
} else {
console.log('Please install MetaMask!');
}
});
function connect() {
ethereum
.request({ method: 'eth_requestAccounts' })
.then(handleAccountsChanged)
.catch((err) => {
if (err.code === 4001) {
console.log('Please connect to MetaMask.');
} else {
console.error(err);
}
});
}
function checkConnection() {
ethereum.request({ method: 'eth_accounts' }).then(handleAccountsChanged).catch(console.error);
}
function handleAccountsChanged(accounts) {
console.log(accounts);
if (accounts.length === 0) {
$('#connection-status').innerText = "You're not connected to MetaMask";
$('#connect-btn').disabled = false;
} else if (accounts[0] !== currentAccount) {
currentAccount = accounts[0];
$('#connection-status').innerText = `Address: ${currentAccount}`;
$('#connect-btn').disabled = true;
}
}
Use window.onload to initiate the isConnected() function when the webpage is loaded. The browser console will return a wallet address if it is connected.
window.onload = (event) => {
isConnected();
};
async function isConnected() {
const accounts = await ethereum.request({method: 'eth_accounts'});
if (accounts.length) {
console.log(`You're connected to: ${accounts[0]}`);
} else {
console.log("Metamask is not connected");
}
}
I assume you have already found Metamask docs on Ethereum Provider API. This section specifies three steps you need to do to make your app work:
Detect the Ethereum provider (window.ethereum)
Detect which Ethereum network the user is connected to
Get the user's Ethereum account(s)
Your snippet does the first part - it detects the provider.
As per this section, to detect network you can use the following code
const chainId = await ethereum.request({ method: 'eth_chainId' });
handleChainChanged(chainId);
ethereum.on('chainChanged', handleChainChanged);
function handleChainChanged(_chainId) {
window.location.reload();
}
And the most crucial part - fetching user account.
let currentAccount = null;
function handleAccountsChanged(accounts) {
if (accounts.length === 0) {
console.log('Please connect to MetaMask.');
} else if (accounts[0] !== currentAccount) {
currentAccount = accounts[0];
}
}
document.getElementById('connectButton', connect);
function connect() {
ethereum
.request({ method: 'eth_requestAccounts' })
.then(handleAccountsChanged)
.catch((err) => {
if (err.code === 4001) {
console.log('Please connect to MetaMask.');
} else {
console.error(err);
}
});
After the user logs in the first time, Metamask won't show the pop-up next time.
I think it's help you. In some case you noticedethereum.window.once('connect',()=>{}) is not worked and then disconnect event too.. i also face this problem and i don't know how to get userAccount address automatically after refresh so i started research on many youtube video and metamask api document. finally i got the answer.
import React, {useState,useEffect} from 'react';
import { ethers} from 'ethers';
function App(){
let [userAccount,setUserAccount] = useState({
isConnect:false,
Account:""
})
let isItConnect = async()=>{
let provider = new ethers.providers.Web3Provider(window.ethereum);
let accounts = await provider.send("eth_requestAccounts",[]);
console.log(accounts.length)
if(accounts.length>0){
return {
status:true,
userAddress:accounts[0]
}
}
else{
return {
status:false,
userAddress:""
}
}
}
let connect = async()=>{
let Status = await isItConnect();
localStorage.setItem('isConnected',Status.status)
setUserAccount((prev)=>{
return {...prev,Account:Status.userAddress}
})
}
window.ethereum.on('accountsChanged',async()=>{
localStorage.removeItem('isConnected');
setUserAccount((prev)=>{
return {...prev,Account:""}
})
connect()
})
useEffect(()=>{
let status = localStorage.getItem('isConnected')
if(status){
connect()
}
if(status === null){
if(window.ethereum.selectedAddress === null){
console.log('welcome User!')
}
else{
connect()
}
}
},[])
return (
<>
{userAccount.Account===""&& <button onClick={connect}>Connect Metamask!
</button>}
{userAccount.Account !==""&& <>
<p>{userAccount.Account}</p>
<p>Connected</p>
</>
)
}
Try using window.ethereum._state.account it will show array of accounts if connected else it will show an empty array, and use the length property to further access if connected to metamask or not.
This would get you the wallet address. returns false if not connected.
const getAccount = async () => await window.ethereum.request({method: 'eth_accounts'})[0] || false;
basic call from the DOM:
window.onload = event => {
const account = getAccount();
console.log(account ? `You're connected to: ${accounts}` : 'Metamask is not connected');
};
if using react:
componentDidMount() {
const account = getAccount();
console.log(account ? `You're connected to: ${accounts}` : 'Metamask is not connected');
}

How to check if a web3 wallet is unlocked?

How do I check to see if metamask or other web3 wallets are unlocked with ethers.js?
I currently use this:
window.ethereum._metamask.isUnlocked()
But it is reported as experimental methods by the metamask documentation.
That's my own resolution if anyone need it :
isUnlocked$ = new BehaviorSubject<boolean>(false);
async isWalletUnlocked() {
const web3Provider = new ethers.providers.Web3Provider(window.ethereum, 'any');
const signer = await this.web3Provider.getSigner();
signer
.getAddress()
.then((address: string) => {
this.isUnlocked$.next(true);
})
.catch((err) => this.isUnlocked$.next(false));
}
What my experimentation found was that listAccounts returns an array of strings and if the wallet is not unlocked, it returns an empty array.
For MetaMask specifically, I know you can't have an account without having an address.
Therefore the function I came up with was:
async function isUnlocked() {
const provider = new ethers.providers.Web3Provider(window.ethereum);
let unlocked;
try {
const accounts = await provider.listAccounts();
unlocked = accounts.length > 0;
} catch (e) {
unlocked = false;
}
return unlocked;
}

Await Keeps on Waiting - React, React Router

I am using Truffle React Box. When I use React Router to open a component. Await in ComponentDidMount doesn't return anything. However, after refreshing page, it works fine.
This is my code:
componentDidMount = async () => {
try {
console.log("1");
const web3 = await getWeb3();
console.log("2")
const accounts = await web3.eth.getAccounts();
const Contract = truffleContract(PrototypeStateContract);
Contract.setProvider(web3.currentProvider);
const instance = await Contract.deployed();
this.setState({ web3, accounts, contract: instance });
} catch (error) {
alert(
`Failed to load web3, accounts, or contract. Check console for details.`
);
console.log(error);
}
};
When using react router "Link to" to access a component, only "1" gets printed.
When refreshing the same page, both "1" and "2" gets printed as expected.
How can I solve this?
The problem is resolved after making these changes to getWeb3.js.
import Web3 from "web3";
const getWeb3 = () =>
new Promise( async(resolve, reject) => {
// Wait for loading completion to avoid race conditions with web3 injection timing.
// Modern dapp browsers...
if (window.ethereum) {
const web3 = new Web3(window.ethereum);
try {
// Request account access if needed
await window.ethereum.enable();
// Acccounts now exposed
resolve(web3);
} catch (error) {
reject(error);
}
}
// Legacy dapp browsers...
else if (window.web3) {
// Use Mist/MetaMask's provider.
const web3 = window.web3;
console.log("Injected web3 detected.");
resolve(web3);
}
// Fallback to localhost; use dev console port by default...
else {
const provider = new Web3.providers.HttpProvider(
"http://127.0.0.1:9545"
);
const web3 = new Web3(provider);
console.log("No web3 instance injected, using Local web3.");
resolve(web3);
}
});
export default getWeb3;
I have removed the event listener as window doesn't load when accessing from react-router Link.

Categories

Resources