Web3.js 1.2 invocation smart contract method and can not return correct result - geth

When I invoke the smart contract deployed, I don't get the correct result!
I have googled, but can not fine any help.
Here is my contract:
pragma solidity >=0.4.22 <0.6.0;
contract LYQFirst{
function userRegister() public payable returns(string memory)
{
return "Hello World";
}
}
and my web3.js version is 1.2 and the web3.js code is as follows:
var Web3 = require('web3');
if (typeof web3 !== 'undefined') {
console.log("Hello World");
web3 = new Web3(web3.currentProvider);
} else {
// set the provider you want from Web3.providers
web3 = new Web3(new Web3.providers.HttpProvider ("http://localhost:8545"));
}
var contract1 = new web3.eth.Contract([
{
"constant": false,
"inputs": [],
"name": "userRegister",
"outputs": [
{
"name": "",
"type": "string"
}
],
"payable": true,
"stateMutability": "payable",
"type": "function"
}
],"0xd62f32665ac53749ded4a38d984d70f180d2908a");
contract1.methods.userRegister().send
({from: "0x18244fbf3b47175cd6b4a1183a476c9e70cb7368",gas:200000}).then (function(error,result){
console.log(error);
console.log("result="+result);
});
The geth including followings modules and their versions.
modules: admin:1.0 debug:1.0 eth:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0.
I installed web3.js 1.2 by npm install web3 for interacting with geth.
The result I got from web3 code is as following:
{ blockHash:
'0x4865c3845d88d7022962833b663ed298f1a0e5b2e7e4905c7b0c968972790174',
blockNumber: 3186,
contractAddress: null,
cumulativeGasUsed: 21847,
from: '0x18244fbf3b47175cd6b4a1183a476c9e70cb7368',
gasUsed: 21847,
logsBloom:
'0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
root:
'0x0141214730cebc516bf7036c8b36a24af0a29dbc11ef8ef9daf05448bb84eec5',
to: '0xd62f32665ac53749ded4a38d984d70f180d2908a',
transactionHash:
'0x804d4751eb7ab6b5f31f709dafc98bfa0b7433758ac9b0d58348b34173f832b8',
transactionIndex: 0,
events: {} }
result=undefined
<<< Process finished (PID=9824). (Exit code 0)

You cannot get return value if it's a transaction (send, not call) from Javascript. Transactions return transaction receipt, and that's what you got.
If you need the value, store it an a public storage variable and call it's getter function.

Related

Not getting event from smart contract on ethers.js

I have contract this part is simply creating smart contract for NFT. At the end of the createToken() I am emitting event.
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity ^0.8.3;
import "#openzeppelin/contracts/token/ERC721/ERC721.sol";
import "#openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "#openzeppelin/contracts/utils/Counters.sol";
contract NFT is ERC721URIStorage {
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
address contractAddress;
event ItemCreated(
uint256 indexed tokenId
);
constructor(address marketplaceAddress) ERC721("Metaverse Tokens", "METT") {
contractAddress = marketplaceAddress;
}
function createToken(string memory tokenURI) public returns (uint) {
_tokenIds.increment();
uint256 newItemId = _tokenIds.current();
_mint(msg.sender, newItemId);
_setTokenURI(newItemId, tokenURI);
setApprovalForAll(contractAddress, true);
emit ItemCreated(newItemId);
}
}
I am trying to read event ItemCreated on ethers.js
const web3Model = new Web3Modal()
const connection = await web3Model.connect()
const provider = new ethers.providers.Web3Provider(connection)
const signer = provider.getSigner()
let contract = new ethers.Contract(nftaddress, NFT.abi, signer)
let transaction = await contract.createToken(url)
let tx = await transaction.wait()
console.log('tx' ,tx)
let event = tx.events[0]
console.log('event', event)
Unfortunately, the response is not giving me any event
Please see below response. evens property is empty
{
"to": "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512",
"from": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
"contractAddress": null,
"transactionIndex": 0,
"gasUsed": {
"type": "BigNumber",
"hex": "0x5858"
},
"logsBloom": "0x0000000000000...",
"blockHash": "0xe66248c22832b34776c6720a6bec19bf20e9ba9af4a63ff25bd0f0689f19f037",
"transactionHash": "0xc6de2da6186ca972cc69efa265c7da5e6d780a0c25d4ad849aa4be4be9cac501",
"logs": [],
"blockNumber": 1,
"confirmations": 1,
"cumulativeGasUsed": {
"type": "BigNumber",
"hex": "0x5858"
},
"effectiveGasPrice": {
"type": "BigNumber",
"hex": "0x8d8f9fc0"
},
"status": 1,
"type": 2,
"byzantium": true,
"events": []
}
events are empty
I am sure event is emitted as I checked in hardhat-tracker
npx hardhat test --logs
NFT market
[Receiver] Transfer(from=0x0000000000000000000000000000000000000000, to=[Sender], tokenId=1)
[Receiver] ApprovalForAll(owner=[Sender], operator=0x5FbDB2315678afecb367f032d93F642f64180aa3, approved=true)
[Receiver] ItemCreated(tokenId=1)
[Receiver] Transfer(from=0x0000000000000000000000000000000000000000, to=[Sender], tokenId=2)
[Receiver] ApprovalForAll(owner=[Sender], operator=0x5FbDB2315678afecb367f032d93F642f64180aa3, approved=true)
[Receiver] ItemCreated(tokenId=2)
Any idea what I am dong wrong?
Below link to the repo https://github.com/Filip-Konkowski/Polygon-nft-market
Are you sure you have selected the correct network in your metamask? The same thing happened to me once :D Also, be sure to deploy using the network parameter such as npx hardhat run scripts/deploy.js --network localhost

Could not interact with contract in BSC mainnet but succeed in testnet (but still a standard transfer)

I may send raw transaction by sendSignedTransaction to contract address on BSC testnet, and it succeed but this is just a standard transaction; it's not contract call like I want.
But on BSC mainnet, it always failed with error: Warning! Error encountered during contract execution [execution reverted]
Please help me check code below then tell me where issue, any comment, reply or guess welcome; many thanks.
For testnet, it always succeed but it was a a standard transaction, link to image. While I wanna interact with contract, result should show field Interacted With (To)
var minABI = [
{
"constant": true,
"inputs": [
{
"name": "_claimer",
"type": "uint256"
},
{
"name": "_amount",
"type": "uint256"
},
{
"name": "_sig",
"type": "bytes"
}
],
"name": "claim",
"outputs": [],
"payable": true,
"stateMutability": "payable",
"type": "function"
}
];
var web3 = new Web3('https://data-seed-prebsc-1-s1.binance.org:8545'); // testnet
//var web3 = new Web3('https://bsc-dataseed.binance.org:443'); // mainnet
var _from = '0x2151...';
var _to = '0x7f617...';
var _sign = '0x5eddd...';
var PRIVATE_KEY = 'da65f...';
var contract = new web3.eth.Contract(minABI, _to, {from: _from});
var _nonce = await web3.eth.getTransactionCount(_from, 'latest');
var _signEncoded = contract.methods.claim(_nonce, '17390000000000000000', _sign).encodeABI();
var esGas = await web3.eth.estimateGas({
"from" : _from,
"nonce" : _nonce,
"to" : _to,
"data" : _signEncoded
});
var sentValue = gasPrice * esGas;
var transaction = {
'to': _to,
'value': sentValue,
'gas': esGas,
'nonce': _nonce,
'data': _signEncoded,
};
var signedTx = await web3.eth.accounts.signTransaction(transaction, PRIVATE_KEY);
var tx = await web3.eth.sendSignedTransaction(signedTx.rawTransaction);
For mainet, if I used _signEncoded in web3.eth.estimateGas it returns error: execution reverted: Invalid signature, I must use _sign to send transaction but it still always failed with error Warning! Error encountered during contract execution [execution reverted] link to image
var esGas = await web3.eth.estimateGas({
"from" : _from,
"nonce" : _nonce,
"to" : _to,
"data" : _sign
});
Contract deployed on mainnet
But the JS snippet is trying to call the contract on testnet (where it's not deployed).
var web3 = new Web3('https://data-seed-prebsc-1-s1.binance.org:8545'); // testnet
//var web3 = new Web3('https://bsc-dataseed.binance.org:443'); // mainnet
So you need to either deploy it on testnet as well, or use a mainnet (where it's already deployed) web3 provider.
if I want to call this claim, I must call via its contract: contract.methods.claim(_nonce, 'amount', _sign).call() ? sendSignedTransaction is just a normal transfer and could not be used in my case?
The contract.methods.claim(...).call() is an shorthad for calling the function. sendSignedTransaction() can be used to send a transaction - by default without invoking any function, but you can also define its data param to execute the claim() function.
Mind that there's a difference between a call (read-only; performed by the functionName().call() in web3) and a transaction (read-write; performed by the functionName().send() function in web3). Based on the context of your question, I'm guessing you want to send a transaction (executing the claim() function) - not perform a call (to the claim() function).

How to set custom error in strong-error-handler when debug mode is false

I'm using Loopback v3.x, and strong-error-handler for handling my project errors. The error response was fine in the development mode but when in production mode, it throws a different error back to the client.
I realised that it was the "debug": false" that makes it throw an { error: { statusCode: 500, message: 'Internal Server Error' } } (based from the Loopback documentation about strong-error-handler)
But I wanted to show my error in the production when I throw new Error('Error Messages') with "debug": false (to keep the sensitive data such as file paths, URLs, and stack traces out from exposure)
Below are my config files:
config.json
{
...
"remoting": {
"rest": {
"normalizeHttpPath": false,
"xml": false,
"handleErrors": false
}
}
}
middleware.development.json
{
"final:after": {
"strong-error-handler": {
"params": {
"debug": true,
"log": true,
"safeFields": [
"code"
]
}
}
}
}
middleware.json
{
"final:after": {
"strong-error-handler": {
"params": {
"debug": false,
"log": true,
"safeFields": [
"code"
]
}
}
}
}
I wanted the response to show the Error that I have thrown, like below:
Instead, now it receives:
I have went to strongloop-error-handler GitHub library but couldn't find any documentation about throwing the original error. Is it possible to do so?
So I went digging around the strong-error-handler library and found out that it is technically possible to do so if we set a statusCode into the error manually, and has to be within 400 - 499.
in buildResponseData() function:
if (data.statusCode >= 400 && data.statusCode <= 499) {
fillBadRequestError(data, err);
} else {
fillInternalError(data, err);
}
https://github.com/strongloop/strong-error-handler/blob/master/lib/data-builder.js#L37
and the fillBadRequestError() will return the original error
function fillBadRequestError(data, err) {
data.name = err.name;
data.message = err.message;
data.code = err.code;
data.details = err.details;
}
https://github.com/strongloop/strong-error-handler/blob/master/lib/data-builder.js#L69
So, before throwing the error, we can set:
const error = new Error();
error.name = 'Custom Error';
error.message = 'Error Message';
error.statusCode = 404;
throw error;
Then it will return the error even with "debug": false mode

Array of structs init and getter

I'm quite new to Solidity development and I'm struggling with structs for now.
I followed several examples but can't get a way to add a struct to my array of structs. My last try is:
pragma solidity ^0.4.18;
contract Iceicebaby {
struct Parcel {
string state;
string flavour;
uint256 weight;
address holder;
}
Parcel[] public parcels;
function newParcel(string _flavour, uint256 _weight) public {
parcels.length++;
parcels[parcels.length-1].state="ORDERED";
parcels[parcels.length-1].flavour=_flavour;
parcels[parcels.length-1].weight=_weight;
parcels[parcels.length-1].holder=msg.sender;
}
function getParcelsCount () view public returns (uint){
return parcels.length;
}
function getParcel(uint256 index) view public returns (string, string, uint256, address) {
return (parcels[index].state, parcels[index].flavour, parcels[index].weight ,parcels[index].holder);
}}
For now I get :
myInstance.order("Flavour",1) :
{ tx: '0xfad42f92c158557c46496df3fd104d7a09899e641e66748e57b03262f4f5fc62',
receipt:
{ transactionHash: '0xfad42f92c158557c46496df3fd104d7a09899e641e66748e57b03262f4f5fc62',
transactionIndex: 0,
blockHash: '0xc39e94e8e9e9a26fd372ad12d2eba4a72f06251d2f29c4a344cd9e58849d9e49',
blockNumber: 17,
gasUsed: 22168,
cumulativeGasUsed: 22168,
contractAddress: null,
logs: [],
status: 1 },
logs: [] }
myInstance.getParcelsCount()
BigNumber { s: 1, e: 0, c: [ 0 ] }
myInstance.getParcel(0) or myInstance.getParcel(1)
[ '', '', BigNumber { s: 1, e: 0, c: [ 0 ] }, '0x' ]
I tried several other solutions, mapping the structure and stuff like this but can't deal with this thing which should be easy, no?
Also, I can't find how to properly debbug and display logs, is there any standards for this ? I'm using truffle and a local ganache network.
Thanks !
It seems the transaction is not having enough gas to executing the code to store the data.
By default web3 sends 90000 gas (needs confirmation), which is not enough for the transaction you are trying to execute.
Change the following line of code with an extra optional parameter. Here I am providing 150000 gas to the transaction. You can have an easy estimation how much gas is required for a transaction by looking at transaction logs of remix.
myInstance.order("Flavour",1)
myInstance.order("Flavour",1, {from: web3.eth.accounts[0], gas: 150000})

Solidity (Truffle): Works fine with truffle console, but fails with truffle test

I'm running something with truffle console that works fine, but fails with truffle test.
The code is:
contract Geekt {
address[] usersByAddress;
function registerNewUser(string handle, bytes32 city, bytes32 state, bytes32 country) public returns (bool success) {
address newUserAddress = msg.sender;
usersByAddress.push(newUserAddress);
return true;
}
function getUsers() public constant returns (address[]) {
return usersByAddress;
}
}
And the tests are:
var Geekt = artifacts.require("Geekt");
contract('Geekt', function (accounts) {
it('should get initial users as empty array', function () {
return Geekt.deployed().then(function (instance) {
return instance.getUsers.call();
}).then(function (res) {
assert.equal(res.length, 0, "Expected empty array after init.");
});
});
it('should successfully add user', function () {
var geekt;
return Geekt.deployed().then(function (instance) {
geekt = instance;
return geekt.registerNewUser.call("elie222", "London", "State", "UK");
}).then(function (res) {
assert.equal(res, true, "Expected registerNewUser to return true.");
}).then(function (res) {
return geekt.getUsers.call();
}).then(function (res) {
// for debugging, but this assert passes: assert.equal(res.length, 0, "Expected array of size 0 after registerNewUser.");
// res == [] so the next line fails:
assert.equal(res.length, 1, "Expected array of size 1 after registerNewUser.");
});
});
});
It works great with truffle console:
truffle(development)> Geekt.then(function(instance){return instance.registerNewUser("Tectract","Denver","CO","USA");})
{ tx: '0x8eeea303ff9f5ceee56d71fd1265da61991749aa3d5e82db0d2d630a98fd6eb5',
receipt:
{ transactionHash: '0x8eeea303ff9f5ceee56d71fd1265da61991749aa3d5e82db0d2d630a98fd6eb5',
transactionIndex: 0,
blockHash: '0xf9a0da5ec0aba80a3338781f6d6414ceb43ec0fc023c31649a1cc347a4aba2ea',
blockNumber: 14,
gasUsed: 24566,
cumulativeGasUsed: 24566,
contractAddress: null,
logs: [] },
logs: [] }
truffle(development)> Geekt.then(function(instance){return instance.getUsers();})
[ '0x1a004a36a6bc9bcde42c6d2b237c6477cf0f535f' ]
How could this happen? What am I doing wrong?
The issue was that I was doing a call instead of a transaction.
Transactions change state whereas method calls do not and are only to read from the network.
You can read more about it here:
https://truffle.readthedocs.io/en/beta/getting_started/contracts/