Test Smart Contract with arguments in constructor with truffle - solidity

I want to test smart contract with parameter in constructor but have error.
Here is my smart contract and test files:
pragma solidity >=0.4.25 <0.7.0;
contract Test {
string public test;
constructor(string memory _test) public {
test = _test;
}
}
const Test = artifacts.require("Test");
contract('Test', (accounts) => {
it('should init', async () => {
const instance = await Test.new("test");
const result = await instance.test;
assert.equal("test", result, "info is not equals");
});
});
And log:
Error: while migrating Test: Invalid number of parameters for "undefined". Got 0 expected 1!
at /usr/local/lib/node_modules/truffle/build/webpack:/packages/deployer/src/deployment.js:365:1
at processTicksAndRejections (internal/process/task_queues.js:97:5)
at Migration._deploy (/usr/local/lib/node_modules/truffle/build/webpack:/packages/migrate/Migration.js:68:1)
at Migration._load (/usr/local/lib/node_modules/truffle/build/webpack:/packages/migrate/Migration.js:55:1)
at Migration.run (/usr/local/lib/node_modules/truffle/build/webpack:/packages/migrate/Migration.js:171:1)
at Object.runMigrations (/usr/local/lib/node_modules/truffle/build/webpack:/packages/migrate/index.js:150:1)
at Object.runFrom (/usr/local/lib/node_modules/truffle/build/webpack:/packages/migrate/index.js:110:1)
at Object.runAll (/usr/local/lib/node_modules/truffle/build/webpack:/packages/migrate/index.js:114:1)
at Object.run (/usr/local/lib/node_modules/truffle/build/webpack:/packages/migrate/index.js:79:1)
at Object.run (/usr/local/lib/node_modules/truffle/build/webpack:/packages/core/lib/testing/Test.js:109:1)
at Object.run (/usr/local/lib/node_modules/truffle/build/webpack:/packages/core/lib/commands/test/index.js:192:1)
at Command.run (/usr/local/lib/node_modules/truffle/build/webpack:/packages/core/lib/command.js:136:1)
Truffle v5.1.64 (core: 5.1.64)
Node v12.16.3
How to solve it?

Your forgot to pass the transaction params including the sender (deployer) adddres.
const instance = await Test.new("test");
shoud be
const txParams = {
from: accounts[0]
};
const instance = await Test.new("test", txParams);
More info on the new() function: https://www.trufflesuite.com/docs/truffle/reference/contract-abstractions#-code-mycontract-new-arg1-arg2-tx-params-code-

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.

Error deploying smart contract using hardhat -- Cannot read property 'sendTransaction' of null

Getting the below error while trying to deploy a smart contract from hardhat. Error details
TypeError: Cannot read property 'sendTransaction' of null
at ContractFactory.<anonymous> (C:\Collection\node_modules\#ethersproject\contracts\src.ts\index.ts:1249:38)
at step (C:\Collection\node_modules\#ethersproject\contracts\lib\index.js:48:23)
at Object.next (C:\Collection\node_modules\#ethersproject\contracts\lib\index.js:29:53)
at fulfilled (C:\Collection\node_modules\#ethersproject\contracts\lib\index.js:20:58)
Here are the config files
hardhat.config.js
require('#nomiclabs/hardhat-waffle');
require("#nomiclabs/hardhat-ethers");
require("dotenv").config();
// This is a sample Hardhat task. To learn how to create your own go to
// https://hardhat.org/guides/create-task.html
task("accounts", "Prints the list of accounts", async (taskArgs, hre) => {
const accounts = await hre.ethers.getSigners();
for (const account of accounts) {
console.log(account.address);
}
});
// You need to export an object to set up your config
// Go to https://hardhat.org/config/ to learn more
/**
* #type import('hardhat/config').HardhatUserConfig
*/
module.exports = {
solidity: "0.8.2",
networks: {
mumbai: {
url: process.env.MUMBAI_URL,
account: process.env.PRIVATE_KEY
}
}
};
deploy.js
const {ethers} = require("hardhat");
async function main() {
const SuperMario = await ethers.getContractFactory("SuperMario");
const superInstance = await SuperMario.deploy("SuperMarioCollection", "SMC");
await superInstance.deployed();
console.log("contract was deployed to:", superInstance.address());
await superInstance.mint("https://ipfs.io/ipfs/XXXXXXX");
}
// We recommend this pattern to be able to use async/await everywhere
// and properly handle errors.
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
I am trying to deploy it using the following command
npx hardhat run scripts/deploy.js --network mumbai
thanks
Change account to accounts in the network config
found the fix. There was an error in the hardhat.config file
instead of account:, it should have been
accounts:[process.env.PRIVATE_KEY]

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.

Understanding truffle test

I am following a tutorial to create a smart contract using truffle. I would like to have a better understanding about the test created in the tutorial.
This is one of the tests:
it("increases myDonationsCount", async () => {
const currentDonationsCount = await fundraiser.myDonationsCount(
{from: donor}
);
await fundraiser.donate({from: donor, value});
const newDonationsCount = await fundraiser.myDonationsCount(
{from: donor}
);
assert.equal(
1,
newDonationsCount - currentDonationsCount,
"myDonationsCount should increment by 1");
})
where does this object come from? {from: donor, value}
And for this test:
it("throws an error when called from a different account", async () =>{
try {
await fundraiser.setBeneficiary(newBeneficiary, {from: accounts[3]});
assert.fail("withdraw was not restricted to owners")
} catch(err) {
const expectedError = "Ownable: caller is not the owner"
const actualError = err.reason;
assert.equal(actualError, expectedError, "should not be permitted")
}
})
In the 3rd line from the above test they are passing 2 parameters fundraiser.setBeneficiary(newBeneficiary, {from: accounts[3]});.
How is this possible if the original function only receives one?
The function:
function setBeneficiary(address payable _beneficiary) public onlyOwner {
beneficiary = _beneficiary;
}
It's the transaction params.
Truffle allows you to override the default transaction params by specifying the overrides in the last argument, after you've passed all arguments defined in the Solidity function.
Docs: https://www.trufflesuite.com/docs/truffle/getting-started/interacting-with-your-contracts#making-a-transaction

Truffle and Ganache-cli test case fails

So I have this setup : truffle and ganache-cli
I'm sending some ether to my contract, here is the related part of my contract:
mapping(address => uint256) public balanceOf;
function () payable public {
uint amount = msg.value;
balanceOf[msg.sender] += amount;
}
In truffle this is how I send the ether.
it("Test if can be payed", function(){
return web3.eth.sendTransaction({
from:fromAddr,
to:MyContract.address,
value:amountToSend
}).then(function(res){
expect(res).to.not.be.an("error"); // test passed
});
});
it("Test if contract received ether", function(){
return web3.eth.getBalance(MyContract.address,
function(err, res){
expect(parseInt(res)).to.be.at.least(1000000000000000000); // test passed
});
});
it("Catch if balanceOf "+fromAddr, function(){
return sale.balanceOf.call(fromAddr).then(function(res){
expect(parseInt(res)).to.be.at.least(1); // fails the test
});
});
Am I doing it right? What could be the reason for failed test?
truffle test output :
AssertionError: expected 0 to be at least 1
+ expected - actual
-0
+1
I can provide more info if needed.
UPDATE :
for clarification on sale which is global variable.
it("Test if MyContract is deployed", function(){
return MyContract.deployed().then(function(instance){
sale = instance;
});
});
I think this is what you are looking for:
File path:
test/vault.js
const Vault = artifacts.require("Vault");
contract("Vault test", async accounts => {
// Rely on one instance for all tests.
let vault;
let fromAccount = accounts[0];
let oneEtherInWei = web3.utils.toWei('1', 'ether');
// Runs before all tests.
// https://mochajs.org/#hooks
before(async () => {
vault = await Vault.deployed();
});
// The `receipt` will return boolean.
// https://web3js.readthedocs.io/en/1.0/web3-eth.html#gettransactionreceipt
it("Test if 1 ether can be paid", async () => {
let receipt = await web3.eth.sendTransaction({
from: fromAccount,
to: vault.address,
value: oneEtherInWei
});
expect(receipt.status).to.equal(true);
});
it("Test if contract received 1 ether", async () => {
let balance = await web3.eth.getBalance(vault.address);
expect(balance).to.equal(oneEtherInWei);
});
// In Web3JS v1.0, `fromWei` will return string.
// In order to use `at.least`, string needs to be parsed to integer.
it("Test if balanceOf fromAccount is at least 1 ether in the contract", async () => {
let balanceOf = await vault.balanceOf.call(fromAccount);
let balanceOfInt = parseInt(web3.utils.fromWei(balanceOf, 'ether'));
expect(balanceOfInt).to.be.at.least(1);
});
});
You can see the full project here. Do note that I'm using Truffle v5 and Ganache v2. See the README file inside that GitLab repository.
Back to your question, there were 2 mistakes:
The sale is not defined. I have a feeling that you were actually referring to MyContract.
In order to use the least method in ChaiJS, you need to make sure you are passing integers. The balanceOf call is returning BigNumber or BN object and you can't use it with .least method.
FYI, Truffle v5 is now using BN by default (previously BigNumber). More about it here.
Let me know if this helps.