How to send wei/eth to contract address? (using truffle javascript test) - testing

I'm trying to send wei/eth to the address of my solidity contract which have an external payable fallback function. My truffle javascript test below doesn't result in the balance of instance.address getting any wei. Is not instance.address the smart contract address receiving wei? Can anyone spot why console.logging the balance results in 0? Or spot what I'm missing?
Thanks!
const TestContract = artifacts.require("TestContract");
contract('TestContract', async (accounts) => {
it('should send 1 ether to TestContract', async () => {
let instance = await TestContract.deployed();
instance.send({from: accounts[1], value: 1000000000000000000});
let balance = await web3.eth.getBalance(instance.address);
console.log('instance.address balance: ' + parseInt(balance));
)}

Since you are not providing the contract in your question, I'm making an assumption here that your contract looks like below.
File path:
./contracts/TestContract.sol
pragma solidity ^0.4.23;
contract TestContract {
// all logic goes here...
function() public payable {
// payable fallback to receive and store ETH
}
}
With that, if you want to send ETH from accounts[1] to the TestContract using JS, here is how to do it:
File path:
./test/TestContract.js
const tc = artifacts.require("TestContract");
contract('TestContract', async (accounts) => {
let instance;
// Runs before all tests in this block.
// Read about .new() VS .deployed() here:
// https://twitter.com/zulhhandyplast/status/1026181801239171072
before(async () => {
instance = await tc.new();
})
it('TestContract balance should starts with 0 ETH', async () => {
let balance = await web3.eth.getBalance(instance.address);
assert.equal(balance, 0);
})
it('TestContract balance should has 1 ETH after deposit', async () => {
let one_eth = web3.toWei(1, "ether");
await web3.eth.sendTransaction({from: accounts[1], to: instance.address, value: one_eth});
let balance_wei = await web3.eth.getBalance(instance.address);
let balance_ether = web3.fromWei(balance_wei.toNumber(), "ether");
assert.equal(balance_ether, 1);
})
})
See my comment in above code to learn more about the differences between .new() and .deployed() keyword in Truffle.
Full source code for my solution can be found here.

Solved! I forgot I had to send a transaction via web3 and eth like this:
web3.eth.sendTransaction({})
Thanks anyway!

You myst send to an address, not an object.
instance.send({from: accounts[1], value: 1000000000000000000});

For using Web3.js v1.4.0 in your truffle test files.
const SolidityTest = artifacts.require('SolidityTest');
contract('SolidityTest', (accounts) => {
let solidityTest;
before(async () => {
solidityTest = await SolidityTest.new();
})
it('Test something', async () => {
// Send 100 wei to the contract.
// `sendEth` is your payable method.
await solidityTest.sendEth({from: accounts[1], value: 100});
// Check account 1 balance.
let acc1Balance = await web3.eth.getBalance(accounts[1]);
// Convert the unit from wei to eth
acc1Balance = web3.utils.fromWei(acc1Balance, 'ether')
console.log('acc1 balance:', acc1Balance)
// Check the contract balance.
let contractBalance = await web3.eth.getBalance(solidityTest.address);
contractBalance = web3.utils.fromWei(contractBalance, 'ether')
console.log('contract balance:', contractBalance)
});
});

Hello you just forgot the await before the instance.send, thus making the get balance call to do not “see” the ether sent, hope it will help future readers

Related

Testing the safeMint function

I am trying to successfully write a unit test for my safeMint function below.
Here is my current test:
const assert = require("assert");
const { accounts } = require("#openzeppelin/test-environment");
const ComNFT = artifacts.require("ComNFT");
const { expect } = require("chai");
// describe('ComNFT', () => {
// let accounts;
let comNFT;
beforeEach(async () => {
accounts = await web3.eth.getAccounts();
comNFT = await ComNFT.new({ from: accounts[0] });
//comNFT = await ComNFT.at("");
// console.log(comNFT.address);
});
it('should fail when called by a non-owner account', async () => {
try {
await web3.eth.sendTransaction({
from: accounts[1], // The non-owner account
to: comNFT.address, // The contract address
data: comNFT.methods.safeMint(accounts[1], 'token URI').encodeABI() // The function call and arguments, encoded as ABI
});
assert.fail('Expected error not thrown');
} catch (error) {
assert(error.message.includes('onlyOwner'), 'Expected "onlyOwner" error message not found');
}
});
it('should be able to mint a new token', async () => {
await web3.eth.sendTransaction({
from: accounts[0], // The owner account
to: comNFT.address, // The contract address
data: comNFT.methods.safeMint(accounts[1], 'token URI').encodeABI() // The function call and arguments, encoded as ABI
});
const tokenURI = await comNFT.tokenURI(1); // Assume the token ID is 1
assert.equal(tokenURI, 'token URI');
});
function safeMint(address to, string memory uri) public onlyOwner {
uint256 tokenId = _tokenIdCounter.current();
_tokenIdCounter.increment();
_safeMint(to, tokenId);
_setTokenURI(tokenId, uri);
}
I am getting a failure message after i run npx truffle test " 1) "before each" hook for "should fail when called by a non-owner account"
0 passing (3s)
1 failing
"before each" hook for "should fail when called by a non-owner account":
TypeError: Assignment to constant variable.
at Context. (test/ComNFT.js:11:12)"
Can someone suggest a way of me successfully writing a test that calls safeMint?
The other test "itshould fail when called by a non-owner account" is also not running?
Thanks
safeMint function has onlyowner modifir, you should call safeMint function with the owner address that is accounts[0] (not accounts[1])

Unable to set state variables during staging test on Goerli using Hardhat

I am able to set variables during my unit tests on the local Hardhat Node, however the same test fails on Goerli.
This is the code for my test:
const { getNamedAccounts, deployments, ethers, network } = require("hardhat")
const { developmentChains, networkConfig } = require("../../helper-hardhat-config")
const { assert, expect } = require("chai")
const fs = require("fs")
const path = require("path")
developmentChains.includes(network.name)
? describe.skip
: describe("Whoopy Staging Tests", function () {
let whoopy,
deployer,
player,
cloneAddress,
clonedContract,
txReceipt,
tx,
accountConnectedClone,
manager,
create
const chainId = network.config.chainId
beforeEach(async function () {
accounts = await ethers.getSigners()
deployer = accounts[0]
player = accounts[1]
await deployments.fixture(["all"])
const dir = path.resolve(
__dirname,
"/Users/boss/hardhat-smartcontract-whoopy/artifacts/contracts/Whoopy.sol/Whoopy.json"
)
const file = fs.readFileSync(dir, "utf8")
const json = JSON.parse(file)
const abi = json.abi
whoopy = await ethers.getContract("Whoopy", deployer)
manager = await ethers.getContract("VRFv2SubscriptionManager", deployer)
wf = await ethers.getContract("WhoopyFactory", deployer)
tx = await (await wf.connect(player).createClone(player.address))
txReceipt = await tx.wait(1)
cloneAddress = await txReceipt.events[1].args._instance
clonedContract = new ethers.Contract(cloneAddress, abi, player)
accountConnectedClone = clonedContract.connect(player)
})
describe("Whoopy Tests", function () {
beforeEach(async function () {
create = await accountConnectedClone.createWhoopy(
"Test",
1,
{
value: ethers.utils.parseUnits("10000000000000000", "wei"),
gasLimit: 3000000
})
console.log(create)
})
it("creates Whoopy correctly", async function () {
const whoopyName = await accountConnectedClone.getWhoopyName()
const num = await accountConnectedClone.getNum()
expect(whoopyName).to.equal("Test")
expect(num).to.equal(1)
})
})
Here is the function I am testing:
function createWhoopy( //to be created only once
string memory s_whoopyName,
uint256 s_num,
) public payable restricted {
whoopyName = s_whoopyName;
num = s_num;
}
Seems pretty straight forward but don't know why it's not working. My accounts have enough test eth and goerli is correctly set up in Hardhat config. The test reverts as follows:
AssertionError: expected '' to equal 'Test'
+ expected - actual
+Test
Any guidance would be appreciated! Thanks!
I figured it out. It was something stupid (as I thought it would be). I forgot to put await create.wait(6) which was needed to wait for the blocks to mine the transaction.
It went through on Hardhat because Hardhat mines blocks immediately, but since Goerli is a live Testnet you need to wait for the transaction to be mined.

Test cases failing due to custom modifier

I am new to solidity and trying to code it on my own before using open Zepplin plugins.
Here is the contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.5;
contract LeagueWinners {
struct Winner {
bool exists;
bool claimed;
uint256 reward;
}
mapping(address=>Winner) public winners;
mapping (address => bool) private AuthAccounts;
modifier onlyAuthAccounts() {
require(AuthAccounts[msg.sender], "Auth: caller is not the authorized");
_;
}
constructor () {
AuthAccounts[_addr_1] = true;
AuthAccounts[_addr_2] = true;
}
function addWinner(address _address, uint256 _amount ) public {
Winner storage winner = winners[_address];
winner.exists = true;
winner.reward = _amount;
}
}
I know we have the Ownable plugin from openzepplin. but just trying with my own modifier as I want 2 users to add winners.
The contract works well. but I am facing issues in writing test cases.
const { expect } = require("chai");
const { ethers } = require("hardhat");
const hre = require("hardhat");
describe("LeagueWinners", function () {
before(async () => {
LeagueWinners = await ethers.getContractFactory("LeagueWinners");
leagueWiners = await LeagueWinners.deploy();
await leagueWiners.deployed();
[owner] = await ethers.getSigners();
});
it("Claim Tokens to be deployed and verify owner", async function () {
expect(await leagueWiners.owner()).to.equal(owner.address);
});
it("Add Winner", async function () {
winner = await leagueWiners
.connect(owner)
.addWinner(
"_addr",
"50000000000000000000"
);
});
});
Add winner is getting failed, not sure how to pass the AuthAccounts. Any guidance will be great help
Error
Error: VM Exception while processing transaction: reverted with reason string 'Auth: caller is not the authorized'
You don't pass any addresses to the constructor here:
constructor () {
AuthAccounts[_addr_1] = true;
AuthAccounts[_addr_2] = true;
}
You need to add the _addr_1 and _addr_2 into the constructor like this:
constructor (address _addr_1, address _addr_2) {
AuthAccounts[_addr_1] = true;
AuthAccounts[_addr_2] = true;
}
The compiler shouldn't let you compile this contract so I'm not sure how it lets you deploy it.
Then in your test you need to pass the arguments like this:
before(async () => {
LeagueWinners = await ethers.getContractFactory("LeagueWinners");
leagueWiners = await LeagueWinners.deploy(addr1, addr2); // HERE
await leagueWiners.deployed();
[owner] = await ethers.getSigners();
});
After spending a few days, made a solution in this way.
constructor () {
AuthAccounts[msg.sender] = true;
AuthAccounts[_addr_1] = true;
AuthAccounts[_addr_2] = true;
}
As i was hardcoding other addresses, it was not possible to get signer info in the test cases. Passing msg.sender in AuthAccounts helped to achieve that and test cases got passed.
Let me know if there are any other work arounds.

How can I link library and contract in one file?

I am writing smart contract in solidity with hardhat and facing error like missing links for the following libraries.
I think I should do something with sample-nft-test.js, but I don't have any idea what to do.
Does any body know how to solve the problem?
% bin/npm-install
% bin/test
SampleNft
1) "before each" hook for "should be able to return token name by token id"
0 passing (2s)
1 failing
1) SampleNft
"before each" hook for "should be able to return token name by token id":
NomicLabsHardhatPluginError: The contract SampleNft is missing links for the following libraries:
* contracts/SampleNft.sol:TokenTrait
Learn more about linking contracts at https://hardhat.org/plugins/nomiclabs-hardhat-ethers.html#library-linking
at collectLibrariesAndLink (node_modules/#nomiclabs/hardhat-ethers/src/internal/helpers.ts:258:11)
at getContractFactoryFromArtifact (node_modules/#nomiclabs/hardhat-ethers/src/internal/helpers.ts:149:32)
at getContractFactory (node_modules/#nomiclabs/hardhat-ethers/src/internal/helpers.ts:93:12)
at Context.<anonymous> (test/sample-nft-test.js:13:29)
Source codes to reproduce the error
ArakakiEth/SampleNft
sample-nft-test.js
const {
expect,
} = require("chai");
const {
ethers,
} = require("hardhat");
describe("SampleNft", () => {
beforeEach(async () => {
signers = await ethers.getSigners();
const contractFactory = await ethers.getContractFactory("SampleNft", {
signer: signers[0],
});
contract = await contractFactory.deploy();
});
it("should be able to return token name by token id", async () => {
await contract.deployed();
await contract.getName();
});
});
SampleNft.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.4;
struct Token {
string name;
}
library TokenTrait {
function getName(Token memory token) external pure returns (string memory) {
return token.name;
}
}
contract SampleNft {
using TokenTrait for Token;
uint tokenId;
mapping(uint => Token) private _tokenIdTokenMap;
constructor() {
tokenId = 0;
}
function mint() external {
Token memory token = Token("First Token");
_tokenIdTokenMap[tokenId] = token;
}
function getName() external view returns (string memory) {
Token memory token = _tokenIdTokenMap[tokenId];
return token.getName();
}
}
library TokenTrait {
function getName(Token memory token) external pure returns (string memory) {
return token.name;
}
}
You set the visibility of the function as external.
In this case, you have to deploy the library and then need to specify a link for the library in contract deployment.
The way to fix your issue is to make the function visibility internal.
The library link should be added when deploying contract.
Please replace with the following code for beforeEach part
beforeEach(async () => {
signers = await ethers.getSigners();
const Lib = await ethers.getContractFactory("TokenTrait");
const lib = await Lib.deploy();
await lib.deployed();
const contractFactory = await ethers.getContractFactory("SampleNft", {
signer: signers[0],
libraries: {
TokenTrait: lib.address,
},
});
contract = await contractFactory.deploy();
});

Ethers.js, send money to a smart contract (receive function)

I have a smart contract with a receive function :
receive() external payable {
Wallets[msg.sender] += msg.value;
}
I have a front end and I want to send Ethers to this smart contract using the receive() function.
async function transfer() {
if(typeof window.ethereum !== 'undefined') {
const accounts = await window.ethereum.request({ method: 'eth_requestAccounts' });
const provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner();
const contract = new ethers.Contract(WalletAddress, Wallet.abi, signer);
const transaction = await contract.send({
from: accounts[0],
value: amount
})
await transaction.wait();
alert('ok');
setAmount('');
getBalance();
}
}
Saldy, there is no "send" function, what is the function I need to use there ?
Thx a lot !
When you want to invoke the receive() function, you need to send a transaction to the contract address with empty data field. The same way as if you were sending ETH to a non-contract address.
// not defining `data` field will use the default value - empty data
const transaction = signer.sendTransaction({
from: accounts[0],
to: WalletAddress,
value: amount
});