Error in Remix "Error from IDE : Invalid account selected" - solidity

I'm new to Remix and Solidity and don't understand why I recieve error message "Error from IDE : Invalid account selected".
Below line is executed successfully:
await contract.methods.SetMaxSupply("600").send({from: accounts[0]});
Below line results in above mentioned error message:
let supply = await contract.methods.current_supply().call()
Solidity code:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol";
contract Test is Ownable {
uint public max_supply;
function SetMaxSupply(uint amount) public onlyOwner {
max_supply = amount;
}
function current_supply() public view returns(uint) {
return max_supply * 3;
}
}
Remix JS Script:
// Right click on the script name and hit "Run" to execute
(async () => {
try {
console.log('Running deployWithWeb3 script...')
// replace with contract address
const contractAddress = '0xd9145CCE52D386f254917e481eB44e9943F39138'
const contractName = 'Test' // Change this for other contract
// Note that the script needs the ABI which is generated from the compilation artifact.
// Make sure contract is compiled and artifacts are generated
const artifactsPath = `browser/contracts/StackOverflow/artifacts/${contractName}.json` // Change this for different path
const metadata = JSON.parse(await remix.call('fileManager', 'getFile', artifactsPath))
const abi = metadata.abi
// instantiate a new web3 Contract object
let contract = new web3.eth.Contract(abi, contractAddress)
const accounts = await web3.eth.getAccounts()
await contract.methods.SetMaxSupply("600").send({from: accounts[0]});
let supply = await contract.methods.current_supply().call()
console.log(supply)
} catch (e) {
console.log(e.message)
}
})()

Try changing the Account parameter in the Deploy & Run Transaction

Related

How to test the Solidity fallback() function via Hardhat?

I have a Solidity smart contract Demo which I am developing in Hardhat and testing on the RSK Testnet.
//SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
contract Demo {
event Error(string);
fallback() external {
emit Error("call of a non-existent function");
}
}
I want to make sure that the fallback function is called and the event Error is emitted. To this end, I am trying to call a nonExistentFunction on the smart contract:
const { expect } = require('chai');
const { ethers } = require('hardhat');
describe('Demo', () => {
let deployer;
let demoContract;
before(async () => {
[deployer] = await ethers.getSigners();
const factory = await ethers.getContractFactory('Demo');
demoContract = await factory.deploy().then((res) => res.deployed());
});
it('should invoke the fallback function', async () => {
const tx = demoContract.nonExistentFunction();
await expect(tx)
.to.emit(demoContract, 'Error')
.withArgs('call of a non-existent function');
});
});
However Hardhat throws a TypeError even before it actually connects to the smart contract on RSK:
Demo
1) should invoke the fallback function
0 passing (555ms)
1 failing
1) Demo
should invoke the fallback function:
TypeError: demoContract.nonExistentFunction is not a function
at Context.<anonymous> (test/Demo.js:13:29)
at processImmediate (internal/timers.js:461:21)
How can I outsmart Hardhat/Ethers.js and finally be able to call non-existent function thus invoking the fallback function in the smart contract?
For reference, this is my hardhat.config.js
require('#nomiclabs/hardhat-waffle');
const { mnemonic } = require('./.secret.json');
module.exports = {
solidity: '0.8.4',
networks: {
hardhat: {},
rsktestnet: {
chainId: 31,
url: 'https://public-node.testnet.rsk.co/',
accounts: {
mnemonic,
path: "m/44'/60'/0'/0",
},
},
},
mocha: {
timeout: 600000,
},
};
You can use the approach of injecting a non-existent function signature
into the smart contract object (ethers.Contract).
Create a function signature for nonExistentFunction:
const nonExistentFuncSignature =
'nonExistentFunction(uint256,uint256)';
Note that the parameter list should contain no whitespace,
and consists of parameter types only (no parameter names).
Then instantiate a new smart contract object.
When you do this you need to modify the ABI for Demo
such that it includes this additional function signature.:
const fakeDemoContract = new ethers.Contract(
demoContract.address,
[
...demoContract.interface.fragments,
`function ${nonExistentFuncSignature}`,
],
deployer,
);
Note that the contract that is deployed is the same as before -
it does not contain this new function.
However the client interacting with this smart contract -
the tests in this case -
does think that the smart contract has this function now.
At this point, you'll be able to run your original test,
with a minor modification:
const tx = fakeDemoContract[nonExistentFuncSignature](8, 9);
await expect(tx)
.to.emit(demoContract, 'Error')
.withArgs('call of a non-existent function');
Full test:
it('should invoke the fallback function', async () => {
const nonExistentFuncSignature = 'nonExistentFunc(uint256,uint256)';
const fakeDemoContract = new ethers.Contract(
demoContract.address,
[
...demoContract.interface.fragments,
`function ${nonExistentFuncSignature}`,
],
deployer,
);
const tx = fakeDemoContract[nonExistentFuncSignature](8, 9);
await expect(tx)
.to.emit(demoContract, 'Error')
.withArgs('call of a non-existent function');
});
Test result:
Demo
✔ should invoke the fallback function (77933ms)
1 passing (2m)
A transaction executing a function contains the function selector following its (ABI-encoded) input params in the data field.
The fallback() function gets executed when the transaction data field starts with a selector that does not match any existing function. For example an empty selector.
So you can generate a transaction to the contract address, with empty data field, which invokes the fallback() function.
it('should invoke the fallback function', async () => {
const tx = deployer.sendTransaction({
to: demoContract.address,
data: "0x",
});
await expect(tx)
.to.emit(demoContract, 'Error')
.withArgs('call of a non-existent function');
});
Note: If you also declared the receive() function, it takes precedence over fallback() in case of empty data field. However, fallback() still gets executed for every non-empty mismatching selector, while receive() is only invoked when the selector is empty.

How to receive a value returned by a Solidity smart contract transacting function?

I am writing an NFT smart contract which I am going to test via Hardhat and deploy on RSK.
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;
import "#openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
contract MyNFT is ERC721URIStorage {
uint private _counter;
address private _owner;
constructor() ERC721("My NFT", "MNFT") {
_owner = msg.sender;
}
function owner() public view returns (address) {
return _owner;
}
function mintNFT(address recipient, string memory tokenURI)
public returns (uint256)
{
require(msg.sender == owner(), "Only owner is allowed to mint");
uint newItemId = ++_counter;
ERC721._mint(recipient, newItemId);
ERC721URIStorage._setTokenURI(newItemId, tokenURI);
return newItemId;
}
}
Here I have two public functions: owner and mintNFT both returning some values. In my tests I would like to read the return values coming from these two functions. These are the tests I am running on Hardhat:
const { expect } = require("chai");
const { ethers } = require("hardhat");
describe("My NFT", () => {
let deployer;
let myNFT;
// deploy NFT before the tests
before(async () => {
[deployer] = await ethers.getSigners();
const MyNFT = await ethers.getContractFactory('MyNFT');
myNFT = await MyNFT.deploy();
await myNFT.deployed();
});
describe('Receiving a value returned by a view function', () => {
it('The deployer should be the s/c owner', async () => {
const owner = await myNFT.owner();
expect(owner).to.equal(deployer.address);
});
});
describe('Receiving a value returned by a transacting function', () => {
it('Should return a correct ID of the newly minted item', async () => {
const newMintItem = {
id: 1,
uri: 'ipfs://Qme3QxqsJih5psasse4d2FFLFLwaKx7wHXW3Topk3Q8b14',
};
const newItemId = await myNFT.mintNFT(deployer.address, newMintItem.uri);
expect(newItemId).to.equal(newMintItem.id);
});
});
});
In the case of the owner function I get what I expect: It returns my account address, and the first test passes successfully. However, when it comes to the mintNFT function, I don't get what I expect: Instead of the newly created item ID I get something very different and my second test fails.
Why do two very similar tests give me different results? How do I get a return value from a function that sends a transaction?
For reference, this is the hardhat.config.js file I'm using:
require("#nomiclabs/hardhat-waffle");
module.exports = {
solidity: "0.8.4",
defaultNetwork: 'rskregtest',
networks: {
rskregtest: {
chainId: 33,
url: 'http://localhost:4444',
},
},
};
Values returned from a transaction are not available outside of EVM.
You can either emit an event, or create a public view getter function of the value.
contract MyNFT is ERC721URIStorage {
// `public` visibility autogenerates view function named `_counter()`
uint public _counter;
event NFTMinted(uint256 indexed _id);
function mintNFT(address recipient, string memory tokenURI)
public returns (uint256)
{
// ...
emit NFTMinted(newItemId);
return newItemId;
}
}
it('Should return a correct ID of the newly minted item', async () => {
const newMintItem = {
id: 1,
uri: 'ipfs://Qme3QxqsJih5psasse4d2FFLFLwaKx7wHXW3Topk3Q8b14',
};
// testing the emitted event
await expect(myNFT.mintNFT(deployer.address, newMintItem.uri))
.to.emit(myNFT, "NFTMinted")
.withArgs(newMintItem.id);
// testing the getter value
const counter = await myNFT._counter();
expect(counter).to.equal(newMintItem.id);
});
Docs: https://ethereum-waffle.readthedocs.io/en/latest/matchers.html#emitting-events
You can not directly receive a return value coming from a function that you are sending a transaction to off-chain. You can only do so on-chain - i.e. when one SC function invokes another SC function.
However, in this particular case, you can obtain the value through events, as the ERC721 specification includes a Transfer event:
/// #dev This emits when ownership of any NFT changes by any mechanism.
/// This event emits when NFTs are created (`from` == 0) and destroyed
/// (`to` == 0). Exception: during contract creation, any number of NFTs
/// may be created and assigned without emitting Transfer. At the time of
/// any transfer, the approved address for that NFT (if any) is reset to none.
event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
In Ethers.js, which you are already using in your hardhat tests, instead of smart contract function return value, you get a transaction response object returned on this line:
const txResponse = await myNFT.mintNFT(deployer.address, newMintItem.uri);
Next you need to get a transaction receipt by calling wait on txResponse:
const txReceipt = await txResponse.wait();
In turn, txReceipt contains an events array which includes all events emitted by your transaction. In this case, expect it to include a single Transfer event indicating the first minted item transfer from the zero address to your account address. Get this event by extracting the first element from the events array:
const [transferEvent] = txReceipt.events;
Next take tokenId property from the transferEvent arguments and this will be the Id of your newly minted NFT:
const { tokenId } = transferEvent.args;
The whole test should look as follows:
describe('Receiving a value returned by a transacting function', () => {
it('Should return a correct ID of the newly minted item', async () => {
const newMintItem = {
id: 1,
uri: 'ipfs://QmY6KX35Rg25rnaffmZzGUFb3raRhtPA5JEFeSSWQA4GHL',
};
const txResponse = await myNFT.mintNFT(deployer.address, newMintItem.uri);
const txReceipt = await txResponse.wait();
const [transferEvent] = txReceipt.events;
const { tokenId } = transferEvent.args;
expect(tokenId).to.equal(newMintItem.id);
});
});

File won't get deployed? (HardhatError: HH700: Artifact not found.)

I'm following this tutorial here: https://ethereum.org/en/developers/tutorials/hello-world-smart-contract-fullstack/ and I'm stuck with this error message:
HardhatError: HH700: Artifact for contract "HelloWorld" not found.
From what I found on the forums it seems to be a naming problem but the name for the contract & what is being deployed is the same:
pragma solidity >=0.7.3;
contract HelloWorld {
event UpdatedMessages(string oldStr, string newStr);
string public message;
constructor(string memory initMessage) {
message = initMessage;
}
function update(string memory newMessage) public {
string memory oldMsg = message;
message = newMessage;
emit UpdatedMessages(oldMsg, newMessage);
}
}
and this is the deploy.js file:
async function main() {
const HelloWorld = await ethers.getContractFactory("HelloWorld")
// Start deployment, returning a promise that resolves to a contract object
const hello_world = await HelloWorld.deploy("Hello World!")
console.log("Contract deployed to address:", hello_world.address)
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error)
process.exit(1)
})
When I compile it just says "Nothing to compile" and running this command: npx hardhat run scripts/deploy.js --network ropsten given mentioned HH700 error.
Can anyone please help?
const hello_world = await HelloWorld.deploy("Hello World!")
should be
const hello_world = await deploy("HelloWorld!")
Could be that you are missing the “npx hardhat compile” before the test. The artifacts are created when you compile.

MetaMask - RPC Error: Internal JSON-RPC error

I am developing a NFT Minting Website on CELO. My mint function looks like this:
function safeMint(address to) public payable {
require(msg.value >= mintPrice, "Not enough ETH sent; check price!");
uint256 tokenId = _tokenIdCounter.current();
_safeMint(to, tokenId);
_tokenIdCounter.increment();
// string memory token_uri=tokenURI(tokenId);
}
My react front end looks like this:
async function mintNFT() {
if (typeof window.ethereum !== 'undefined') {
await requestAccount()
const provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner();
const contract = new ethers.Contract(t_tokenAddress, Token.abi, signer);
try{
await window.ethereum.enable();
const transation = await contract.safeMint(userAccount);
await transation.wait();
fetchNFTIndex();
}
catch(e){
console.log(e.data.message);
}
}
}
I get the following error when I run the transaction with mintPrice =1 wei or ether:
Error
When I run the transaction with mintPrice=0 ether or wei it works fine. I dont know what is the problem here. I have 5 celos in my account so I have enough funds, I assume that ethers are converted and paid in CELO.
Can anyone understand the problem here!
The linked error contains the custom message "Not enough ETH sent", which means the error originates from the require() condition.
require(msg.value >= mintPrice, "Not enough ETH sent; check price!");
Your JS snippet executes the function, but doesn't send any ETH value with the transaction.
In order to send ETH value, you need to define it in the overrides parameter.
const transation = await contract.safeMint(userAccount, {
// send along 1 wei
value: 1
});

Solidity issue passing parameters to a function

I have a Smart Contract with the function:
contract Example {
event claimed(address owner);
function claimStar() public {
owner = msg.sender;
emit claimed(msg.sender);
}
}
I'm using Truffle V5.0 and the Webpack box as a boiler plate code.
In my truffle-config.js file I have the in the networks configuration:
development:{
host:"127.0.0.1",
port: 9545,
network_id:"*"
}
Everything compile fine using:
- truffle develop
- compile
- migrate --reset
It says Truffle Develop started at http://127.0.0.1:9545
In my index.js file I have the following code:
import Web3 from "web3";
import starNotaryArtifact from "../../build/contracts/StarNotary.json";
const App = {
web3: null,
account: null,
meta: null,
start: async function() {
const { web3 } = this;
try {
// get contract instance
const networkId = await web3.eth.net.getId();
const deployedNetwork = starNotaryArtifact.networks[networkId];
this.meta = new web3.eth.Contract(
starNotaryArtifact.abi,
deployedNetwork.address,
);
// get accounts
const accounts = await web3.eth.getAccounts();
this.account = accounts[0];
} catch (error) {
console.error("Could not connect to contract or chain.");
}
},
setStatus: function(message) {
const status = document.getElementById("status");
status.innerHTML = message;
},
claimStarFunc: async function(){
const { claimStar } = this.meta.methods;
await claimStar();
App.setStatus("New Star Owner is " + this.account + ".");
}
};
window.App = App;
window.addEventListener("load", async function() {
if (window.ethereum) {
// use MetaMask's provider
App.web3 = new Web3(window.ethereum);
await window.ethereum.enable(); // get permission to access accounts
} else {
console.warn("No web3 detected. Falling back to http://127.0.0.1:9545. You should remove this fallback when you deploy live",);
// fallback - use your fallback strategy (local node / hosted node + in-dapp id mgmt / fail)
App.web3 = new Web3(new Web3.providers.HttpProvider("http://127.0.0.1:9545"),);
}
App.start();
});
In my browser I have Metamask installed and I added a Private Network with the same URL and also imported two accounts.
When I start the application and opened in the browser it opens Metamask to request permission because I'm using window.ethereum.enable();.
But when I click on the button to claim it doesn't do anything.
The normal behavior is to Metamask open a prompt to ask for confirmation but it never happen.
I created also a new property in the contract for test and it works fine showing me the value assigned in the contract constructor.
My question is, Am I missing something?
I also tried to change the functionawait claimStar(); to await claimStar({from: this.account}); but in this case I got an error saying that claimStar doesn't expect parameters.
I would appreciate any help. Thanks
I solved the issue, the problem was in the function claimStarFunc
It should be in this way:
claimStarFunc: async function(){
const { claimStar } = this.meta.methods;
await claimStar().send({from:this.account});
App.setStatus("New Star Owner is " + this.account + ".");
}
Because I'm sending a transaction.
Thanks