I have been following a tutorial on how to create my first Web3js application with solidity and react.
The tutorial was going great until I fall into this problem with metamask RPC.
The tutorial I have been following is this: https://www.youtube.com/watch?v=Wn_Kb3MR_cU&t=6333s&ab_channel=JavaScriptMastery
Right now I'm getting the following errors when trying to run function from ethereum:
inpage.js:1 MetaMask - RPC Error: The method "accounts " does not exist / is not available.
inpage.js:1 MetaMask - RPC Error: The method "eth_accounts " does not exist / is not available.
uncaught (in promise) {code: -32601, message: 'The method "eth_accounts " does not exist / is not available.', data: {…}, stack: '{\n "code": -32601,\n "message": "The method \\"eth…beogaeaoehlefnkodbefgpgknn/common-0.js:18:167275)'}
uncaught (in promise) {code: -32601, message: 'The method "eth_requestAccounts " does not exist / is not available.', data: {…}, stack: '{\n "code": -32601,\n "message": "The method \\"eth…beogaeaoehlefnkodbefgpgknn/common-0.js:18:167275)'}
The file that runs this is a context file TransactionContext.tsx:
import React, { useEffect, useState } from 'react';
import { ethers } from 'ethers';
import { contractABI, contractAddress } from '../utils/constants';
export const TransactionContext = React.createContext({} as any);
const { ethereum } = window as any;
const getEthereumContract = () => {
const provider = new ethers.providers.Web3Provider(ethereum);
const signer = provider.getSigner();
const transactionsContract = new ethers.Contract(contractAddress, contractABI, signer);
console.log({
provider,
signer,
transactionsContract
})
}
export const TransactionProvider = ({ children }: any) => {
const [currentAccount, setCurrentAccount] = useState('');
const checkIfWalletIsConnected = async () => {
if (!ethereum) return alert("Please install metamask!");
const accounts = await ethereum.request({ method: 'eth_accounts '});
console.log(accounts);
}
const connectWallet = async () => {
try {
if (!ethereum) return alert("Please install metamask!");
const accounts = await ethereum.request({ method: 'eth_requestAccounts '});
setCurrentAccount(accounts[0]);
} catch (e) {
console.log(e);
throw new Error('No Ethereum object.')
}
}
useEffect(() => {
checkIfWalletIsConnected();
}, [])
return (
<TransactionContext.Provider value={{ connectWallet }}>
{children}
</TransactionContext.Provider>
)
}
I see 3 issues in your contract:
1- you are not returning the contract from getEthereumContract. it should be
const getEthereumContract = () => {
const provider = new ethers.providers.Web3Provider(ethereum);
const signer = provider.getSigner();
const transactionsContract = new ethers.Contract(contractAddress, contractABI, signer);
return transactionsContract
}
I dont see you are using here yet but you might get bug in the future:
2- Error says 'The method "eth_accounts " does not exist ... you have extra space here "eth_accounts ". should be
const accounts = await ethereum.request({ method: 'eth_accounts'});
3- this is similar to second. You have extra space
const accounts = await ethereum.request({ method: 'eth_requestAccounts'});
You need to specify for which account you want to get the signer provider.getSigner(account)
On click of your connect button add this
async function connectWalletHandler() {
if (!ethereum) {
console.log("Make sure you have Metamask installed");
return;
} else {
console.log("Wallet exist");
}
const accounts = await ethereum.request({ method: "eth_requestAccounts" });
if (accounts.length !== 0) {
} else {
console.log("No authorized account found");
}
And put this code in you app.js
const [user,setUser]=useState(null);
Useeffect(()=>{
if (window.ethereum) {
const isMetaMaskConnected = async () => {
let provider = new ethers.providers.Web3Provider(window.ethereum);
const accounts = await provider.listAccounts();
let account = null;
if (accounts.length > 0) {
account = accounts[0];
}
let signer = provider.getSigner(account);
setUser({ provider: provider, signer: signer, account: account });
};
isMetaMaskConnected();
window.ethereum.on("chainChanged", (chainId) => {
window.location.reload();
});
window.ethereum.on("accountsChanged", () => {
window.location.reload();
});
} else {
}},[])
From now you have 3 option first user is null metamask not installed
2 user.account="" or null metamask installed and connected but locket
3 user.account have value this is when the wallet connected to the website and every thing 👍
Related
I encounter the following error while trying to run a dapp made using React, Truffle & Ganache. I'm also using web3 version 1.7.1. The problem is that the code enters in a catch(error) sequence of a try/catch and then displays what it is intended correctly. Why is this happening and why does the following error appears?
index.js:1 TypeError: Cannot read properties of undefined (reading 'methods')
at HomePage.componentDidMount
What the code should do: Display something like "Address is: 0x0D05b3220E9cC7A90623fc506cEB64Ab885FD6C6"
What the code does: It shows me the prompt "Failed to load web3, accounts, or contract. Check console for details" AND THEN "Address is: 0x0D05b3220E9cC7A90623fc506cEB64Ab885FD6C6"
The code is the following:
import React, { Component } from "react";
import MySmartContract from "../contracts/MySmartContract.json";
import getWeb3 from "../getWeb3";
//Importing components
class HomePage extends Component {
constructor(props) {
super(props);
this.state = {
ContractInstance: undefined,
account: null,
web3: null,
isOwner: false
}
}
componentDidMount = async () => {
// For refreshing the page a single time
// so that web3 and instance is loaded every time
if (!window.location.hash) {
window.location = window.location + '#loaded';
window.location.reload();
}
try {
// Get network provider and web3 instance.
const web3 = await getWeb3();
// Use web3 to get the user's accounts.
const accounts = await web3.eth.getAccounts();
// Get the contract instance.
const networkId = await web3.eth.net.getId();
const deployedNetwork = MySmartContract.networks[networkId];
const instance = new web3.eth.Contract(
MySmartContract.abi,
deployedNetwork && deployedNetwork.address,
);
// Set web3, accounts, and contract to the state, and then proceed with an
// example of interacting with the contract's methods.
this.setState({ ContractInstance: instance, web3: web3, account: accounts[0] });
const owner = await this.state.ContractInstance.methods.getOwnerAddress().call();
if (this.state.account === owner) {
this.setState({ isOwner: true });
}
} catch (error) {
// Catch any errors for any of the above operations.
alert(
`Failed to load web3, accounts, or contract. Check console for details.`,
);
console.error(error);
}
};
render() {
if (!this.state.web3) {
return (
<h1>
Loading Web3, accounts and contract...
</h1>
)
}
return (
<div><h1>Address is: {this.state.account}</h1></div>
)
}
}
export default HomePage;
The content of getWeb3.js is the following:
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);
} 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:8545"
);
const web3 = new Web3(provider);
console.log("No web3 instance injected, using Local web3.");
resolve(web3);
}
});
});
export default getWeb3;
This code seems to be wrong!
this.setState({ ContractInstance: instance, web3: web3, account: accounts[0] });
const owner = await this.state.ContractInstance.methods.getOwnerAddress().call();
You should not try to use state value as soon as you set up.
So you need to call your function in the second line like this:
const owner = await instance.methods.getOwnerAddress().call();
Injected connector code sample
const ConnectToInjected = async () => {
let provider = null;
if (typeof window.ethereum !== 'undefined') {
provider = window.ethereum;
try {
await provider.request({ method: 'eth_requestAccounts' })
} catch (error) {
throw new Error("User Rejected");
}
} else if (window.web3) {
provider = window.web3.currentProvider;
} else if (window.celo) {
provider = window.celo;
} else {
throw new Error("No Web3 Provider found");
}
return provider;
};
export default ConnectToInjected;
Usage:
const provider = await ConnectToInjected();
// Open metamask
await provider.request({ method: 'eth_requestAccounts' });
const web3 = new Web3(provider)
I'm trying to update some code, taking into account new sdk versions. I have the new api call in one file:
import { CognitoIdentityProviderClient, ListUsersCommand } from "#aws-sdk/client-cognito-identity-provider";
import awsmobile from "../../aws-exports";
import { Auth } from "aws-amplify";
export default async function ListUsers() {
await Auth.currentCredentials().then((data) => {
const client = new CognitoIdentityProviderClient({
region: awsmobile.aws_project_region,
credentials: data
});
const params = {
UserPoolId: awsmobile.aws_user_pools_id
};
const command = new ListUsersCommand(params);
client.send(command).then(
(data) => {
return data
},
(error) => {
console.log(error)
}
);
});
}
I'm trying to retrive the data in another file:
import ListUsers from "../../../API/cognito/ListUsers";
import ListUsersInGroup from "../../../API/cognito/ListUsersInGroup";
import { useState, useEffect, useRef } from "react";
import PortalUsersTable from "../../../components/tables/PortalUsersTable";
export default function ManageUsers() {
const [userDetails, setUserDetails] = useState("");
const refUsers = useRef();
const refUsersExec = useRef();
const refUsersAdmin = useRef();
const refUsersGroups = useRef();
useEffect(() => {
function getUsers() {
refUsers.current = ListUsers();
refUsersExec.current = ListUsersInGroup("usersAdmin");
refUsersAdmin.current = ListUsersInGroup("usersExec");
//setUsersTloOfficers(apiTloOfficers);
refUsersGroups.current = ListUsersInGroup("usersGroups");
let userData = [];
let arrUsersExec = [];
for (let a in refUsersExec.current.Users) {
arrUsersExec.push(refUsersExec.current.Users[a].Username);
}
let arrUsersAdmin = [];
for (let b in refUsersAdmin.current.Users) {
arrUsersAdmin.push(refUsersAdmin.current.Users[b].Username);
}
let arrUsersGroups = [];
for (let b in refUsersNtigGroups.current.Users) {
arrUsersGroups.push(refUsersGroups.current.Users[b].Username);
}
for (let i in refUsers.current.Users) {
let email = null;
for (let x in refUsers.current.Users[i].Attributes) {
if (refUsers.current.Users[i].Attributes[x].Name === "email") {
email = refUsers.current.Users[i].Attributes[x].Value;
break;
}
}
let memberExec = arrUsersExec.includes(refUsers.current.Users[i].Username);
let memberAdmin = arrUsersAdmin.includes(refUsers.current.Users[i].Username);
let memberGroups = arrUsersGroups.includes(refUsers.current.Users[i].Username);
userData.push({
id: i,
Username: refUsers.current.Users[i].Username,
AccountStatus: refUsers.current.Users[i].UserStatus,
Email: email,
Users: memberGroups,
Exec: memberExec,
Admin: memberAdmin,
});
}
setUserDetails(userData);
}
getUsers();
}, []);
return (
<>
<h2>Manage Portal Users</h2>
<PortalUsersTable userDetails={userDetails} />
</>
);
}
The logic to handle the API data is sound.
This is the old API call:
import AWS from "aws-sdk";
import awsmobile from "../../aws-exports";
import { Auth } from "aws-amplify";
export default async function ListUsers() {
let idToken = "";
await Auth.currentAuthenticatedUser().then((user) => {
idToken = user.signInUserSession.idToken.getJwtToken();
});
AWS.config.region = awsmobile.aws_cognito_region;
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: awsmobile.aws_cognito_identity_pool_id,
RoleArn: "arn:aws:iam::xxxxxxxxx:role/xxxxxxxxxxxxx",
Logins: { "xxxxxxxxxxxxxxxxxxxx": idToken }
});
let cognitoidentityserviceprovider = new AWS.CognitoIdentityServiceProvider();
let params = {
UserPoolId: awsmobile.aws_user_pools_id,
AttributesToGet: ["email"]
};
return new Promise((resolve, reject) => {
cognitoidentityserviceprovider.listUsers(params, function (err, result) {
if (err) {
console.log(err);
//onError(err);
reject(err);
return;
}
if (result) {
resolve(result);
}
});
});
}
I can see the new API call is returning the correct data in the console. I think I'm not passing the data between files correctly.
I've tried various ways of changing the API call function, reading the cognito sdk description but it's not the API call that is incorrect.
How can I use the API call data in the separate file?
Even if your API call if correct, it looks like you are not returning anything from your function ListUsers. You are mixing async/await pattern with the then. I assume you have added a console.log right before the return data. Refactoring your function using async/await would look like this :
export default async function ListUsers() {
try {
const data = await Auth.currentCredentials();
const client = new CognitoIdentityProviderClient({
region: awsmobile.aws_project_region,
credentials: data,
});
const params = {
UserPoolId: awsmobile.aws_user_pools_id,
};
const command = new ListUsersCommand(params);
const commandData = await client.send(command);
return commandData;
} catch (error) {
console.log(error);
}
}
how can I see the metadata from the NFT mint on react? And get access to them as soon as I press the mint button on the page? after clicking on the mint I have access to some information from the transaction, such as "hash", does it help?
mint file function
async function handleMint() {
if (window.ethereum) {
const provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner();
const contract = new ethers.Contract(
mintExampleAddress,
mintExampleABI.abi,
signer
);
try {
const cost = await contract.cost();
const response = await contract.mint(mint, {
value: cost.mul(BigNumber.from(mint)),
});
console.log(response);
toast.success("Mint successfully!", {
theme: "dark",
});
} catch (err) {
console.log(err);
}
}
}
I'm using this stripe extension and I am trying to pass the uid it gives me error firebase__WEBPACK_IMPORTED_MODULE_3___default.a.auth.onAuthStateChanged is not a function But I have Never seen this error before. please see the code below
import {loadStripe} from '#stripe/stripe-js';
import firebase from 'firebase';
const firestore = firebase.firestore();
firebase.auth().onAuthStateChanged((user) => {
if(user) {
console.log(user.uid) ;
}
});
export async function createCheckoutSession(uid){
firebase.auth.onAuthStateChanged((user) => {
if (user){
const checkoutSessionRef = firestore
.collection('customers')
.doc(user.uid)
.collection('checkout_sessions')
.add({
price: 'price id',
success_url: window.location.origin,
cancel_url: window.location.origin,
});
// Wait for the CheckoutSession to get attached by the extension
checkoutSessionRef.onSnapshot((snap) => {
const { error, sessionId } = snap.data();
if (error) {
// Show an error to your customer and
// inspect your Cloud Function logs in the Firebase console.
alert(`An error occured: ${error.message}`);
}
if (sessionId) {
// We have a session, let's redirect to Checkout
// Init Stripe
const stripe = loadStripe('pk_test_1234');
stripe.redirectToCheckout({ sessionId });
}
});
}
}
)}
Does anyone have any suggestions?
Try this:
(async () =>{
await firebase.auth().onAuthStateChanged((user) => {
if(user) {
console.log(user.uid) ;
}
});
} )();
I am trying to send the validation email upon the account registration, using firebase. The registration is being done successfully but whenever I try to code email verification it gives me an error. Probably because I don't know where to place it. All my firebase methods are on Fire.js, which are the following:
import firebaseKeys from './Config';
import firebase from 'firebase';
require("firebase/firestore");
class Fire {
constructor() {
if (!firebase.apps.length) {
firebase.initializeApp(firebaseKeys);
}
}
addPost = async ({ text, localUri }) => {
const remoteUri = await this.uploadPhotoAsync(localUri, 'photos/${this.uid}/${Date.now()}');
return new Promise((res, rej) => {
this.firestore.collection('posts').add({
text,
uid: this.uid,
timestamp: this.timestamp,
image: remoteUri
})
.then(ref => {
res(ref);
})
.catch(error => {
rej(error);
});
});
}
uploadPhotoAsync = async (uri, filename) => {
return new Promise(async (res, rej) => {
const response = await fetch(uri);
const file = await response.blob();
let upload = firebase
.storage()
.ref(filename)
.put(file);
upload.on(
"state_changed",
snapshot => {},
err => {
rej(err);
},
async () => {
const url = await upload.snapshot.ref.getDownloadURL();
res(url);
}
);
});
}
createUser = async user => {
let remoteUri = null
try {
await firebase.auth().createUserWithEmailAndPassword(user.email, user.password)
//I tried to code it here with user.sendEmailVerification();
let db = this.firestore.collection("users").doc(this.uid)
db.set({
name: user.name,
email: user.email,
avatar: null
})
if (user.avatar) {
remoteUri = await this.uploadPhotoAsync(user.avatar, 'avatars/${this.uid}')
db.set({avatar: remoteUri}, {merge: true});
}
} catch (error) {
alert("Error: ", error);
}
};
get firestore() {
return firebase.firestore();
}
get uid() {
return (firebase.auth().currentUser || {}).uid;
}
get timestamp() {
return Date.now();
}
}
Fire.shared = new Fire();
export default Fire;
The createUserWithEmailAndPassword() method returns a Promise which resolves with a UserCredential AND (as the the doc indicates) "on successful creation of the user account, this user will also be signed in to your application."
So you can easily get the signed in user by using the user property of the UserCredential, and call the sendEmailVerification() method, as follows:
try {
const userCredential = await firebase.auth().createUserWithEmailAndPassword(user.email, user.password);
await userCredential.user.sendEmailVerification();
//In the next line, you should most probably use userCredential.user.uid as the ID of the Firestore document (instead of this.uid)
cont db = this.firestore.collection("users").doc(this.uid);
//...
} catch (...)
Note that you may pass an ActionCodeSettings object to the sendEmailVerification() method, see the doc.