Web3: No provider set - javascript

I'm writing a script using web3 (1.0.0-beta.27), where I'm trying to deploy a contract and listen for an event.
Here's the simplified version of the code:
const Web3 = require('web3');
let web3 = new Web3('http://localhost:8545');
let MyContract = new web3.eth.Contract(abi);
let accounts = await web3.eth.getAccounts();
let contract = await MyContract.deploy({data: code})
.send({from: accounts[0], gas: 1000000});
contract.events.MyEvent((error, result) => {
if (error) {
return console.error(error);
}
}
However, when I run the code, I get the following error:
Error: No provider set.
at Subscription.subscribe (/node_modules/web3-core-subscriptions/src/subscription.js:199:20)
at Contract._on (/node_modules/web3-eth-contract/src/index.js:634:18)
My understanding was that passing the URL to the Web3 constructor would set the provider, but that doesn't seem to be working.

You need to pass in an HttpProvider when creating Web3. Change
let web3 = new Web3('http://localhost:8545');
to
let web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:8545'));
or, you can set the provider after creating Web3:
const web3 = new Web3();
web3.setProvider(new web3.providers.HttpProvider('http://localhost:8545'));

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();

Using Metamask but get Error: Returned error: The method eth_sendTransaction does not exist/is not available

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().

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;
}

How to fix Timeout exceeded error for async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves

I am trying to deploy a simple contract using mocha and ganache, but I got this error:
Acontract
1) "before each" hook for "Deploys a Contract"
0 passing (30s)
1 failing
1) "before each" hook for "Deploys a Contract":
Error: Timeout of 30000ms exceeded. For async tests and hooks, ensure
"done()" is called; if returning a Promise, ensure it resolves.
The contract code :
pragma solidity ^0.4.17;
contract Acontract {
string public message; // new variable
function Acontract(string initialMessage) public {
message = initialMessage;
}
function setMessage(string newMessage) public {
message = newMessage;
}
}
The test file code:
const assert = require('assert');
const ganache = require('ganache-cli');
const Web3 = require('web3');
const web3 = new Web3(ganache.provider());
const { interface, bytecode} = require('../compile');
let accounts;
let result;
beforeEach( async () => {
accounts = await web3.eth.getAccounts();
result = await new web3.eth.Contract(JSON.parse(interface))
.deploy ({ data: bytecode, arguments: ['WOW'] })
.send({ from: accounts[0], gas: '1000000'});
});
describe('Acontract', ()=> {
it('Deploys a Contract', async ()=>{
console.log(result)
});
});
How to solve this error, the code is simple, I tested getting accounts and it was ok, also deploy seems ok, when it comes to sending the code does not work! any suggestions?
I ran into a similar issue and fixed it like this: (You may try number 2 first).
Installed web3#1.0.0-beta.37 (Note: your dependencies can be very different from mine as you are using solidity ^0.4.17)
Added ganache provider in the code.
const assert = require('assert');
const ganache = require('ganache-cli');
const Web3 = require('web3');
//Ganache Provider
const provider = ganache.provider();
const web3 = new Web3(provider);
const { interface, bytecode} = require('../compile');
let accounts;
let result;
beforeEach( async () => {
accounts = await web3.eth.getAccounts();
result = await new web3.eth.Contract(JSON.parse(interface))
.deploy ({ data: bytecode, arguments: ['WOW'] })
.send({ from: accounts[0], gas: '1000000'});
//Set provider
result.setProvider(provider);
});
describe('Acontract', ()=> {
it('Deploys a Contract', async ()=>{
console.log(result)
});
});
"Contract" object structure is changed a bit in this version. So, I had to update compile.js export a bit as well (You may not need it with your version of solidity compiler).

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