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;
}
Related
I get All NFTs token ID when I only should get the one that belongs to the current account.
I'm Also getting the token ID for the current account but also all the other Tokens ID.
How do i resolve this ?
This is the code
const { enableWeb3, account, isWeb3Enabled, Moralis, deactivateWeb3 } = useMoralis();
useEffect(() => {
if(isWeb3Enabled) return
if(typeof window !== 'undefined'){
if(window.localStorage.getItem('connected')){
enableWeb3();
}
}
}, [isWeb3Enabled])
useEffect(() => {
Moralis.onAccountChanged((account) => {
if(account == null){
window.localStorage.removeItem('connected')
deactivateWeb3();
}
})
}, [])
const Web3 = require("web3");
const web3 = new Web3(new Web3.providers.HttpProvider("https://dxt.dexit.network"));
const contractAddress = "0x075D8f52dC5B1F35005dBa8Db40734CBcaBEbd8F"; // replace with the actual contract address
const abi = require('../abi.json'); // replace with the actual ABI of the contract
const contract = new web3.eth.Contract(abi.abi, contractAddress);
async function getNFTs(address) {
const events = await contract.getPastEvents("Transfer", {
filter: { to: address },
fromBlock: 0,
toBlock: "latest"
});
return events.map(event => event.returnValues.tokenId);
}
const test2 = async () => {
console.log(await getNFTs(account));
}
test2();
This is the result As you can see i get all NFTs but I only want token ID 45
return events.map(event => event.returnValues.tokenId);
you are mapping all the events that have returnValues.tokenId truthy. That means if returnValues.tokenIdhas any value you will map them into the new array. This is the logic of .map in javascript, you are mapping all the elements that satisfy the given condition.
You are most likely emitting an event when you create an NFT.
event NftItemCreated(
// you have returnValues
// I dont know what ReturnValuesStruct is, maybe you have address recorded here
ReturnValuesStruct returnValues,
// you should also add this field
address creator,
);
Now you will be logging the creator address of the NFT. Then you should write this logic
async function getNFTs(address) {
const events = await contract.getPastEvents("Transfer", {
filter: { to: address },
fromBlock: 0,
toBlock: "latest"
});
const addressNfts=events.map((event)=>{
if (event.creator===address){
return event.returnValues.tokenId
}
})
return addressNfts
}
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();
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
I want to call a payable function in a smart contract I deployed, but it does not work. This is the error I am getting:
Error: Returned error: The method eth_sendTransaction does not exist/is not available
The answer I could find is to just use a private key, because infura does not cater this method, however I want the user to sign the transaction to the smart contract with MetaMask.
This is my code:
export async function helloworld() {
const rpcURL =
"https://ropsten.infura.io/v3/KEY";
const web3 = new Web3(rpcURL);
let provider = window.ethereum;
if (typeof provider !== "undefined") {
provider
.request({ method: "eth_requestAccounts" })
.then((accounts) => {
selectedAccount = accounts[0];
console.log(`Selected account is ${selectedAccount}`);
})
.catch((err) => {
console.log(err);
return;
});
window.ethereum.on("accountsChanged", function (accounts) {
selectedAccount = accounts[0];
console.log(`Selected account changed to ${selectedAccount}`);
});
}
const networkId = await web3.eth.net.getId();
const thecontract = new web3.eth.Contract(
simpleContractAbi,
"0x50A404efF9A057900f87ad0E0dEfA0D485931464"
);
isInitialized = true;
investit(thecontract, selectedAccount);
}
and this is the code that actually throws the error:
export const investit = async (thecontract, selectedAccount) => {
if (!isInitialized) {
await helloworld();
}
thecontract.methods
.invest()
.send({ from: selectedAccount, value: 10000 })
.catch(function (err) {
console.log(err);
});
};
I am completely lost, since if I use the normal window.ethereum.request (https://docs.metamask.io/guide/sending-transactions.html#example) to send a transaction, metamask opens up and I can sign it. With the contract call it simply does not work.
Do you know the reason? How can I fix this?
This must be the issue. you are just passing an url:
const rpcURL ="https://ropsten.infura.io/v3/KEY";
instead:
const web3 = new Web3(new Web3.providers.HttpProvider("https://ropsten.infura.io/v3/KEY"))
eth_sendTransaction requires you holding the private key to sign the transaction before broadcasting it to the network. Infura doesn’t maintain any private keys. In order to send a transaction, you need to sign the transaction on your end with your private key.
The way you check providers is not correct. window.ethereum is also a provider which is provided by metamask. provider itself is meaningless, it has to be injected into the new Web3().
I tried to make a call to the state of a contract developed on truffle, using web3.js in React, the problem is this, when I try to see the price of the token (already defined) it throws an error:
Unhandled error: This contract object doesn't have address set yet, please set an address first
This is the code of my App.js:
const [AccountData, setAccountData] = useState({
web3: 'undefined',
account: '',
balance: 0
})
const [Contracts, SetContracts] = useState({
Token: '',
Sale: ''
})
const PreLoad =async()=>{
if (typeof window.ethereum !== 'undefined') {
const web3 = new Web3(window.ethereum)
const netId = await web3.eth.net.getId()
const accounts = await web3.eth.getAccounts()
if (typeof accounts[0] !== 'undefined') {
const balance = await web3.eth.getBalance(accounts[0])
setAccountData({ account: accounts[0], balance: web3.utils.fromWei(balance) })
} else {
window.alert('Please Login with MetaMask')
}
try{
const Token = new web3.eth.Contract(SuperToken.abi, SuperToken.networks[netId.address])
const Sale = new web3.eth.Contract(TokenSale.abi, TokenSale.networks[netId.address])
SetContracts({Token, Sale})
}
catch(err){
console.log(err)
alert('Error, see the console')
}
}
else{
alert('please install MetaMask or any provider!!')
}
}
useEffect( () => {
PreLoad()
}, [])
const BuyToken = async(e)=>{
e.preventDefault()
console.log('Buying')
let price = await Contracts.Sale.methods.tokenPrice().call()
console.log(price)
}
I think I'm following good the documentation from web3, and loading good the contracts on the useEffect, so I don't really know why this is happening.
Migrating OP's solution from the question to an answer:
There was an error when I called the contract with web3js, this is the correct way:
SuperToken.abi, SuperToken.networks[netId].address