Invalid asm.js: Invalid member of stdlib - solidity

(node:7894) V8: /var/www/html/testeth/node_modules/solc/soljson.js:3 Invalid asm.js: Invalid member of stdlib
i am making the test deploy on ganache-cli simple contract but it is showing that warning. Please help to resolve that problem.
Below the code of the "index.sol"
pragma solidity ^0.4.17;
contract testalk{
string public message;
function testalk(string initialMsg) public {
message = initialMsg;
}
function setMessage(string nwMsg) public {
message = nwMsg;
}
}
and i am testing it using "mocha" and ganache-cli provider as code below :-
const assert = require('assert');
const ganache = require('ganache-cli');
const Web3 = require('web3');
const web3 = new Web3(ganache.provider());
const { interface, bytecode} = require('../compile');
require('events').EventEmitter.defaultMaxListeners = 15;
let accounts;
let testeth;
beforeEach( async ()=>{
accounts = await web3.eth.getAccounts();
testeth = await new web3.eth.Contract(JSON.parse(interface))
.deploy({data: bytecode, arguments: ['Hi Alok!']})
.send({gas: '1000000',from: accounts['0']});
});
describe("testalk",() => {
it('deploy a contract', () =>{
assert.ok(testeth.options.address);
});
it('get the message', async () => {
const message = await testeth.methods.message().call();
assert.equal('Hi Alok!', message);
//console.log(message);
})
it('get the message', async () => {
await testeth.methods.setMessage("Bye Alok!").send({from: accounts[0], gas: '1000000'});
const message = await testeth.methods.message().call();
console.log(message);
});
});
I am using Ubuntu and nodejs.

I recommend you to select a newer version of the solc compiler (e.g. check Remix to see which version works with your code). Check that the version in the pragma sentence of your Solidity code is the same as the solc version you have installed with node. Check the sample usages in the solc releases and copy the JS code. I used 0.7.4 https://libraries.io/npm/solc/0.7.4
After that, you need to adapt the compile script to return the ABI and bytecode to your tests. The names must match exactly. Here I'm returning the values in JSON format so I don't have to use JSON.parse(interface) in my test file. Note that the bytecode is only the HEX value, therefore I'm returning the contract.evm.bytecode.object. Change Lottery by the name of your contract (if you have multiple contracts you want to check the docs or try a for loop).
const path = require('path');
const fs = require('fs');
const solc = require('solc');
const lotteryPath = path.resolve(__dirname, 'contracts', 'Lottery.sol');
const source = fs.readFileSync(lotteryPath, 'utf8')
var input = {
language: 'Solidity',
sources: {
'test.sol': {
content: source
}
},
settings: {
outputSelection: {
'*': {
'*': ['*']
}
}
}
};
var output = JSON.parse(solc.compile(JSON.stringify(input)));
var contract = output.contracts['test.sol'].Lottery;
var bytecode = contract.evm.bytecode.object;
var interface = contract.abi;
module.exports = {interface, bytecode};
My test file didn't change much, but here it is:
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 lottery;
let accounts;
beforeEach(async () => {
accounts = await web3.eth.getAccounts();
lottery = await new web3.eth.Contract(interface)
.deploy({ data: bytecode })
.send({ from: accounts[0], gas: '6000000' });
});
describe('Lottery Contract', () => {
it('deploys a contract', () => {
assert.ok(lottery.options.address);
});
});

This can happen because of many reasons. If you are using remix ide then by default asm is disabled in chrome that could be an issue. You could be using old compiler of Solidity in some incompatible way. There could be issues with your code itself. Unless you give all specifics of the code, the environment you are using like IDE and Operating System etc., anyone can only guess the max.

Try to install solc version >= 0.4.26.
Also, make sure you've correctly installed truffle-hdwallet-provider since it's been renamed to #truffle/hdwallet-provider.
https://www.npmjs.com/package/#truffle/hdwallet-provider

I have solved the invalid member of stdlib and "before each" hook for "deploys a contract" problems by deleting the "node-modules" folder in the current directory and then reinstall the modules from terminal:
npm install --save ganache-cli mocha web3#1.0.0-beta.37 solc#0.4.17
If you have anaconda installed on your computer you should deactivate it before installing these modules by using the
conda deactivate
command. I couldn't find a solution for this on internet and I hope this helps you to solve your problem as well...

Related

How to directly test a Solidity Library with Hardhat/Chai

I'm trying to test a Solidity Library directly using hardhat and chaï.
This is a Library example I would like to test:
library LibTest {
function testFunc() public view returns(bool) {
return true;
}
}
and this is how I'm trying to test it.
beforeEach(async () => {
const LibTest = await ethers.getContractFactory("LibTest");
const libTest = await LibTest.deploy();
await libTest.deployed();
})
describe('Testing test()', function () {
it("is working testFunc ?", async function () {
console.log(await libTest.testFunc());
})
})
But I have the error message:
ReferenceError: libTest is not defined
I read everything I can on Chai doc and Hardhat doc but can't found any solution
I would say to use fixture and also utilize waffle and to deploy the library contract once and save the snapshot of the contract:
const {loadFixture } = require('#nomicfoundation/hardhat-network-helpers');
const {expect} = require('chai');
const {ethers, waffle} = require('hardhat');
const {deployContract} = waffle;
const LibArtifact = require('../artifacts/contracts/lib.sol/LibTest.json');
describe("Lib tests", function () {
// We define a fixture to reuse the same setup in every test.
// We use loadFixture to run this setup once, snapshot that state,
// and reset Hardhat Network to that snapshopt in every test.
async function deployOnceFixture() {
const [owner, ...otherAccounts] = await ethers.getSigners();
lib = (await deployContract(owner, LibArtifact));
return { lib, owner, otherAccounts };
}
describe("Testing test()", function () {
it("s working testFunc ?", async function () {
const { lib } = await loadFixture(deployOnceFixture);
expect(await lib.testFunc()).to.be.true;
});
});
});
Instructions to add the waffle plugin:
Hardhat-waffle
Basically, you need to install the libraries:
npm install --save-dev #nomiclabs/hardhat-waffle 'ethereum-waffle#^3.0.0' #nomiclabs/hardhat-ethers 'ethers#^5.0.0'
And then import hardhat-waffle in the hardhat-config.js file:
require("#nomiclabs/hardhat-waffle");
Also, notice I put the test file in a test directory so I needed to go back one folder to find artifacts generated by running npx hardhat compile.
For convenience I pushed the solution in a Github repo: https://github.com/Tahlil/run-solidity-lib
The best way I have found to go about this is to create a LibTest.sol contract that invokes and tests the Lib itself. And just running abstracted tests in JS/TS to invoke the LibTest contract, connecting the Lib.sol contract to it during deployment in Hardhat.
const Lib = await ethers.getContractFactory("Lib");
const lib = await Lib.deploy();
const LibTest = await ethers.getContractFactory("LibTest", {
libraries: {
Lib: lib.address,
},
});
const libTest = await LibTest.deploy();
/// later: console.log(await libTest.testLibFunc());
LibTest.sol:
import "./Lib.sol";
library LibTest {
function testLibFunc() public view returns(bool) {
bool response = Lib.testFunc();
return response;
}
}
Were you able to find a better method?

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]

Mocking runtime config value with sinon

I am adding some config values before hapi server start. Application is works fine although in test I can not use config.get(). I can get around with proxyquire. So I was wondering
Is adding config file "dynamically" is bad design?
Is there a way I can use config.get() in such suitation?
Any alternative approach?
//initialize.js
const config = require('config');
async function startServe() {
const someConfigVal = await callAPIToGetSomeJSONObject();
config.dynamicValue = someConfigVal;
server.start();
}
//doSomething.js
const config = require('config');
function doesWork() {
const valFromConfig = config.dynamicValue.X;
// In test I can use proxiquire by creating config object
...
}
function doesNotWork() {
const valFromConfig = config.get('dynamicValue.X');
// Does not work with sinon mocking as this value does not exist in config when test run.
// sinon.stub(config, 'get').withArgs('dynamicValue.X').returns(someVal);
.....
}
Context: testing.
Is adding config file "dynamically" is bad design? => No. I have done it before. The test code changes configuration file: default.json in mid test to check whether function under test behaves as expected. I used several config utilities.
Is there a way I can use config.get() in such suitation? => Yes. For sinon usage, see the example below, which use mocha. You need to define the stub/mock before the function under test use it, and do not forget to restore the stub/mock. Also there is official documentation related to this: Altering configuration values for testing at runtime, but not using sinon.
const config = require('config');
const sinon = require('sinon');
const { expect } = require('chai');
// Example: simple function under test.
function other() {
const valFromConfig = config.get('dynamicValue.X');
return valFromConfig;
}
describe('Config', function () {
it ('without stub or mock.', function () {
// Config dynamicValue.X is not exist.
// Expect to throw error.
try {
other();
expect.fail('expect never get here');
} catch (error) {
expect(error.message).to.equal('Configuration property "dynamicValue.X" is not defined');
}
});
it('get using stub.', function () {
// Create stub.
const stubConfigGet = sinon.stub(config, 'get');
stubConfigGet.withArgs('dynamicValue.X').returns(false);
// Call get.
const test = other();
// Validate te result.
expect(test).to.equal(false);
expect(stubConfigGet.calledOnce).to.equal(true);
// Restore stub.
stubConfigGet.restore();
});
it('get using mock.', function () {
// Create mock.
const mockConfig = sinon.mock(config);
mockConfig.expects('get').once().withArgs('dynamicValue.X').returns(false);
// Call get.
const test = other();
// Validate te result.
expect(test).to.equal(false);
// Restore mock.
expect(mockConfig.verify()).to.equal(true);
});
});
Hope this helps.

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

Native support for ES6 in PhantomJS

is there a way to make PhantomJS natively support ES6, I have a bunch of ES6 code which is converted to ES5 via Babel, what I need to accomplish is accurate measurement of code coverage which is done for ES6 code rather than ES5. It's a requirement from client, so I can't just tell him to stop requesting such thing...
Afaik NodeJS already has native support for ES6, is there a way to do that with PhantomJS?
I've ended up using raw NodeJS (without PhantomJs) + Express + JSDom (https://github.com/tmpvar/jsdom), the POC looks like this:
"use strict"
const $module = require('module');
const path = require('path');
const babel = require("babel-core");
const Jasmine = require('jasmine');
const reporters = require('jasmine-reporters');
const express = require('express');
const jsdom = require("jsdom");
const app = express();
const vm = require('vm');
const fs = require("fs");
app.get('/', function (req, res) {
res.sendFile('index.html', { root: __dirname });
});
app.use('/bower_components', express.static('bower_components'));
const load = function (filename) {
return fs.readFileSync(`./bower_components/${filename}`, "utf-8");
};
const packages = [
fs.readFileSync('./bower_components/jquery/dist/jquery.js', "utf-8"),
fs.readFileSync('./bower_components/angular/angular.js', "utf-8"),
fs.readFileSync('./bower_components/angular-mocks/angular-mocks.js', "utf-8")
];
const sut = {
'./js/code.js': fs.readFileSync('./js/code.js', "utf-8")
};
const tests = {
'./tests/test.js': fs.readFileSync('./tests/test.js', "utf-8")
};
function navigate(FakeFileSystem, root, cwd, filename) {
// Normalize path according to root
let relative = path.relative(root, path.resolve(root, cwd, filename));
let parts = relative.split(path.sep);
let iterator = FakeFileSystem;
for (let part of parts) {
iterator = iterator[part] || (iterator[part] = { });
}
return iterator;
}
const server = app.listen(3333, function () {
const host = server.address().address;
const port = server.address().port;
const url = `http://${host === '::' ? 'localhost' : host}:${port}`;
console.log(`Server launched at ${ url }`);
console.log(`Running tests...`)
jsdom.env({
url: url,
src: packages,
done: function (err, window) {
let jasmine = new Jasmine();
let FakeFileSystem = {};
let descriptors = [];
jasmine.configureDefaultReporter({ showColors: true });
let env = jasmine.env;
for (let propertyName in env) {
if (env.hasOwnProperty(propertyName)) {
window[propertyName] = env[propertyName];
}
}
let context = vm.createContext(window);
let collections = [sut, tests];
for (let collection of collections) {
for (let filename in collection) {
let descriptor = navigate(FakeFileSystem, __dirname, '.', filename);
let source = collection[filename];
let transpiled = babel.transform(source, { "plugins": ["transform-es2015-modules-commonjs"] });
let code = $module.wrap(transpiled.code);
let _exports = {};
let _module = { exports: _exports };
descriptor.code = vm.runInContext(code, context);
descriptor.module = _module;
descriptor.exports = _exports;
descriptor.filename = filename;
descriptors.push(descriptor);
}
}
for (let descriptor of descriptors) {
let cwd = path.dirname(path.relative(__dirname, descriptor.filename));
descriptor.code.call(
undefined,
descriptor.exports,
// Closure is used to capture cwd
(function (cwd) {
return function (filename) { // Fake require function
return navigate(FakeFileSystem, __dirname, cwd, filename).exports;
}
})(cwd),
descriptor.module,
descriptor.filename
);
}
jasmine.execute();
server.close();
}
});
});
The beauty of this approach is that there is no need in transpiling code with babel, it allows frontend packages such as Angular to get loaded from bower, while all the config stuff comes from npm...
EDIT
I've stumbled upon the fact that NodeJS doesn't support all ES6 features yet, and such feature as ES6 modules is a real pain, they aren't supported anywhere, so I've ended up with doing partial transpilation of code with babel, with the expectation that as NodeJS will start providing richer and richer support for ES6 I will eventually turn-off babel features step by step and switch to native support when it will become available...