Array of structs init and getter - solidity

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})

Related

Contract call returns error "Found input with 28 bits, expected 8". Polkadot.js and ink contracts

as the title suggest, Im trying to call PSP22 token contract and read balanceOf() function, but i get error that im passing a too big of a input (27 instead of 8)
Im trying to invoke balanceOf() PSP22 ink! contract.
When i initializing the token it works correctly and i can see the abi:
alanceOf: function createQuery(origin, options)
​​​​​
length: 2
​​​​​
meta: Object { isMutating: false, isPayable: false, identifier: "balance_of", … }
​​​​​​
args: Array [ {…} ]
​​​​​​​
0: Object { name: "owner", type: {…} }
​​​​​​​​
name: "owner"
​​​​​​​​
type: Object { info: 10, type: "AccountId" }
Here is the code:
const tokenContract = new ContractPromise(api, abiToken, "5FmJDyLBoYKfiaoPUcfR3WKh13HkwvXr2CYTNg5RLykNXY3A");
dispatch(set_token_contract(tokenContract));
const value = 0; // only useful on isPayable messages
// NOTE the apps UI specified these in mega units
const gasLimit = 3000n * 1000000n;
// (We perform the send from an account, here using Alice's address)
let alice = "5DaYseV9GSrGKrJYmKU5yymF9izPM2ZzG8f93xQK6hectHuo"
const { gasConsumed, result, output } = await tokenContract.query.balanceOf(alice, { gasLimit }alice);
here is the error:
RPC-CORE: call(callRequest: ContractCallRequest, at?: BlockHash): ContractExecResult:: createType(ContractExecResult):: Struct: failed on result: {"_enum":{"Ok":"ContractExecResultOk","Err":"ContractExecResultErr"}}:: Enum(Err):: Enum(Module):: Struct: failed on error: u8:: u8: Input too large. Found input with 28 bits, expected 8

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).

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

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.

Solidity - Solidity code to Input JSON Description

I want to compile my ethereum HelloWorld.sol smart contract. In all the tutorials is that you do it like this:
var solc = require('solc');
var compiledContract = solc.compile(fs.readFileSync('HelloWorld.sol').toString();
where HelloWorld.sol is:
pragma solidity ^0.5.1;
contract HelloWorld {
bytes32 message;
constructor(bytes32 myMessage) public {
message = myMessage;
}
function getMessage() public view returns(bytes32){
return message;
}
}
In other words, I put my raw Solidity contract code into the solc.compile() method. But this process gives me this error in compiledContract:
'{"errors":[{"component":"general","formattedMessage":"* Line 1, Column 1\\n Syntax error: value, object or array expected.\\n* Line 1, Column 2\\n Extra non-whitespace after JSON value.\\n","message":"* Line 1, Column 1\\n Syntax error: value, object or array expected.\\n* Line 1, Column 2\\n Extra non-whitespace after JSON value.\\n","severity":"error","type":"JSONError"}]}'
I was looking for a solution for quite a long time, but the only thing I found is that
"The high-level API consists of a single method, compile, which
expects the Compiler Standard Input and Output JSON."
(link). The standard input JSON looks like some combination of JSON and this solidity code. So my question is -
How to transfer the solidity contract code into a compiler standard input JSON?
Am I correct that this is the only way how to compile the contract?
This code works for me, index.js
const solc = require('solc')
const fs = require('fs')
const CONTRACT_FILE = 'HelloWorld.sol'
const content = fs.readFileSync(CONTRACT_FILE).toString()
const input = {
language: 'Solidity',
sources: {
[CONTRACT_FILE]: {
content: content
}
},
settings: {
outputSelection: {
'*': {
'*': ['*']
}
}
}
}
const output = JSON.parse(solc.compile(JSON.stringify(input)))
for (const contractName in output.contracts[CONTRACT_FILE]) {
console.log(output.contracts[CONTRACT_FILE][contractName].evm.bytecode.object)
}
HelloWorld.sol
contract HelloWorld {
bytes32 message;
constructor(bytes32 myMessage) public {
message = myMessage;
}
function getMessage() public view returns(bytes32){
return message;
}
}
Alternatively, you can run the solc (command line tool) with the below command and with input data
solc --standard-json -o outputDirectory --bin --ast --asm HelloWorld.sol
Where in the above command when --standard-json expects a input json file that you can give.
You can find an example of how an input file should be in the below link.
Source: https://solidity.readthedocs.io/en/v0.4.24/using-the-compiler.html
const solc = require("solc");
// file system - read and write files to your computer
const fs = require("fs");
// reading the file contents of the smart contract
const fileContent = fs.readFileSync("HelloWorld.sol").toString();
// create an input structure for my solidity compiler
var input = {
language: "Solidity",
sources: {
"HelloWorld.sol": {
content: fileContent,
},
},
settings: {
outputSelection: {
"*": {
"*": ["*"],
},
},
},
};
var output = JSON.parse(solc.compile(JSON.stringify(input)));
// console.log("Output: ", output);
const ABI = output.contracts["HelloWorld.sol"]["Demo"].abi;
const byteCode = output.contracts["HelloWorld.sol"]["Demo"].evm.bytecode.object;
// console.log("abi: ",ABI)
// console.log("byte code: ",byteCode)
npm run yorfilename.js

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/