get String value not as hex from smartcontract - solidity

I got a smartcontract function returning several values on of them as string
I've trying to transform this number to UTF with web3 and is not working.
If I try it on remix calling the smart contract it's works fine... but not from JS
my current code in the smart contract are
function getToken(uint256 _tokenId) public view returns (
string _tokenName,
string _cryptoCardID,
uint256 _price,
uint256 _nextPrice,
address _owner
) {
_tokenName = doggies[_tokenId].name;
_cryptoCardID = doggies[_tokenId].cryptoCardID;
_price = tokenIdToPrice[_tokenId];
_nextPrice = nextPriceOf(_tokenId);
_owner = tokenIdToOwner[_tokenId];
}
from JS
for ( var i = 0; i < result; i++){
myfunction.getToken.call( i , function (error, resultGetAll) {
console.log("Token ID:"+i+ "Data:"+JSON.stringify(resultGetAll)); //here i get _cryptoCardID as hex 0x000000...
}) // each one
}// for
what I expected is a string in readable form (utf8)

Contracts will store the binary data, so returning the data in hexadecimal form is a more efficient way of viewing this data.
You can always decode the hex to utf-8 with a utility function from the web3 library.
Note: this method may differ depending on your web3 version, see here for web3.utils.hexToUtf8 alternative.
Example:
$ web3.toUtf8("0x68656c6c6f20776f726c640000000000000000000000000000000000000000")
$ "hello world"
tested on web3 version: 0.20.3

Related

Copying of type struct.struct memory[] memory to storage not yet supported

I am working on a Solidity smart contract and I want to store an array of structs inside another struct. Here are my structs:
struct Product {
string productId;
string cabineNumber;
string productName;
string country;
string factoryNumber;
string productWeight;
string productAmount;
}
struct Form {
uint256 Id;
string purchId;
string customerName;
string customerPhone;
string contractNumber;
Product[] products;
uint256 created;
uint256 updated;
}
As you can see, the Form struct contains an array of Product structs called products.
I have a function to initialize a Product struct:
function initProduct(string[] memory product) public returns (Product memory) {
Product memory myproduct;
myproduct.productId = product[0];
myproduct.cabineNumber = product[1];
myproduct.productName = product[2];
myproduct.country = product[3];
myproduct.factoryNumber = product[4];
myproduct.productWeight = product[5];
myproduct.productAmount = product[6];
return myproduct;
}
I also have a function to create a Form struct:
function createForm(Form memory form, string[] memory product) public returns (bool) {
Product memory productEvi;
productEvi = initProduct(product);
Product[] memory products = new Product[](1);
products[0] = productEvi;
forms.push(Form(
form.Id,
form.purchId,
form.customerName,
form.customerPhone,
form.contractNumber,
products, // Error: copying of type struct Product[] memory to storage not yet supported
form.created,
form.updated
));
uint256 index = findFormIndex(form.Id);
forms[index].updated = block.timestamp;
forms[index].created = block.timestamp;
return true;
}
However, I am getting the error "Copying of type struct Product[] memory to storage not yet supported" when trying to store the products array in the Form struct. How can I fix this error and store an array of Product structs inside a Form struct?
I tried to store multiple instances of a struct Product inside another struct Form and push the Form object to an array. I expected the code to compile without any errors and to be able to store and retrieve multiple Product objects within a Form.

Conversion from string storage ref to bytes memory[] memory

Error:
Invalid type for argument in function call. Invalid implicit conversion from string storage ref to bytes memory[] memory requested.
Code:
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
import "./hip-206/HederaTokenService.sol";
import "./hip-206/HederaResponseCodes.sol";
contract Mint is HederaTokenService{
address tokenAddress
string public uri = "abc"
function mint(uint64 _amount) external {
(
int256 response,
uint64 newTotalSupply,
) = HederaTokenService.mintToken(tokenAddress, _amount, uri);
if (response != HederaResponseCodes.SUCCESS) {
revert("Mint Failed");
}
The issue arrises when I try to call the function HederaTokenService.mintToken because it expects the uri to be a bytes memory[] memory. Not sure how to convert it.
The following is the function of mintToken:
/// Mints an amount of the token to the defined treasury account
/// #param token The token for which to mint tokens. If token does not exist, transaction results in
/// INVALID_TOKEN_ID
/// #param amount Applicable to tokens of type FUNGIBLE_COMMON. The amount to mint to the Treasury Account.
/// Amount must be a positive non-zero number represented in the lowest denomination of the
/// token. The new supply must be lower than 2^63.
/// #param metadata Applicable to tokens of type NON_FUNGIBLE_UNIQUE. A list of metadata that are being created.
/// Maximum allowed size of each metadata is 100 bytes
/// #return responseCode The response code for the status of the request. SUCCESS is 22.
/// #return newTotalSupply The new supply of tokens. For NFTs it is the total count of NFTs
/// #return serialNumbers If the token is an NFT the newly generate serial numbers, otherwise empty.
function mintToken(address token, uint64 amount, bytes[] memory metadata) internal
returns (int responseCode, uint64 newTotalSupply, int64[] memory serialNumbers)
{
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.mintToken.selector,
token, amount, metadata));
(responseCode, newTotalSupply, serialNumbers) =
success
? abi.decode(result, (int32, uint64, int64[]))
: (HederaResponseCodes.UNKNOWN, 0, new int64[](0));
}
Just casting it works for me:
bytes memory var = bytes(<storage string>);

how to use the ECDSA.sol module correctly?

I have this contract using the ECDSA library.
import "./ECDSA.sol";
struct Signature {
uint8 v;
bytes32 r;
bytes32 s;
}
function make(Signature memory sign) public returns(bool)
I try to understand the parameters I have to use in this case. What I can see it's a tuple type value, but I can't figure out what it looks like for v, r, s. Where can I get these values from my address?
The v, r, and s parameters are a result of signing a message with a private key. The signature has 65 bytes, which are split into 3 parts:
65 byte array (of type bytes in Solidity) arranged the following way: [[v (1)], [r (32)], [s (32)]].
Source: OpenZeppelin
Sign off-chain (because you're using a private key).
Note the address in the comment, we'll verify it on-chain later.
const signature = await web3.eth.accounts.sign(
'Hello world',
// below is private key to the address `0x0647EcF0D64F65AdA7991A44cF5E7361fd131643`
'02ed07b6d5f2e29907962d2bfde8f46f03c46e79d5f2ded0b1e0c27fa82f1384'
);
console.log(signature);
Output
{
message: 'Hello world',
messageHash: '0x8144a6fa26be252b86456491fbcd43c1de7e022241845ffea1c3df066f7cfede',
v: '0x1c',
r: '0x285e6fbb504b57dca3ceacc851a7bfa37743c79b5c53fb184f4cc0b10ebff6ad',
s: '0x245f558fa13540029f0ee2dc0bd73264cf04f28ba9c2520ad63ddb1f2e7e9b24',
signature: '0x285e6fbb504b57dca3ceacc851a7bfa37743c79b5c53fb184f4cc0b10ebff6ad245f558fa13540029f0ee2dc0bd73264cf04f28ba9c2520ad63ddb1f2e7e9b241c'
}
Note that v is the last byte of signature, r is the first half, and s is the second half (excluding the last byte).
Verify on-chain
pragma solidity ^0.8;
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/ECDSA.sol";
contract MyContract {
function foo() external pure returns (bool) {
address recovered = ECDSA.recover(
0x8144a6fa26be252b86456491fbcd43c1de7e022241845ffea1c3df066f7cfede, // messageHash
0x1c, // v
0x285e6fbb504b57dca3ceacc851a7bfa37743c79b5c53fb184f4cc0b10ebff6ad, // r
0x245f558fa13540029f0ee2dc0bd73264cf04f28ba9c2520ad63ddb1f2e7e9b24 // s
);
return recovered == address(0x0647EcF0D64F65AdA7991A44cF5E7361fd131643);
}
}

Migrating contract with truffle gives me transaction revert

My contract .sol file looks like this:
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;
import "#openzeppelin/contracts/token/ERC777/ERC777.sol";
contract ERC777MainToken is ERC777{
constructor(address[] memory defaultOperators) ERC777("COIN", "COIN", defaultOperators) { }
}
And the migration looks like this:
const ERC777MainToken = artifacts.require("ERC777MainToken");
module.exports = async function(_deployer) {
const mainToken = await _deployer.deploy(ERC777MainToken, ["0x5d95F05Dd72A5cB9ea2ee2DC271B03A41C933Cad"])
};
On truffle migrate I get the following error:
"ERC777MainToken" hit a require or revert statement somewhere in its constructor. Try:
* Verifying that your constructor params satisfy all require conditions.
* Adding reason strings to your require statements.
at /usr/local/lib/node_modules/truffle/build/webpack:/packages/deployer/src/deployment.js:365:1
at processTicksAndRejections (internal/process/task_queues.js:93:5)
at Migration._deploy (/usr/local/lib/node_modules/truffle/build/webpack:/packages/migrate/Migration.js:74:1)
at Migration._load (/usr/local/lib/node_modules/truffle/build/webpack:/packages/migrate/Migration.js:61:1)
at Migration.run (/usr/local/lib/node_modules/truffle/build/webpack:/packages/migrate/Migration.js:212: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 runMigrations (/usr/local/lib/node_modules/truffle/build/webpack:/packages/core/lib/commands/migrate.js:263:1)
at Object.run (/usr/local/lib/node_modules/truffle/build/webpack:/packages/core/lib/commands/migrate.js:228:1)
at Command.run (/usr/local/lib/node_modules/truffle/build/webpack:/packages/core/lib/command.js:136:1)
Any Ideas why? I have check every constructor and no one has any require conditions.
I find the problem. The ERC777 contract from open zeppelin has an hardcoded memeber _ERC1820_REGISTRY = IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24) which is the global ERC1820 Registry for the main net but since I am on local net this address is at most nothing.
contract ERC777 is Context, IERC777, IERC20 {
using Address for address;
IERC1820Registry constant internal _ERC1820_REGISTRY = IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24);
mapping(address => uint256) private _balances;
....
}
And the constructor is tring to access the contract on this address:
constructor(
string memory name_,
string memory symbol_,
address[] memory defaultOperators_
) {
_name = name_;
_symbol = symbol_;
_defaultOperatorsArray = defaultOperators_;
for (uint256 i = 0; i < defaultOperators_.length; i++) {
_defaultOperators[defaultOperators_[i]] = true;
}
// register interfaces
_ERC1820_REGISTRY.setInterfaceImplementer(address(this), keccak256("ERC777Token"), address(this));
_ERC1820_REGISTRY.setInterfaceImplementer(address(this), keccak256("ERC20Token"), address(this));
}
But since this address on the local net might be empty and 100% is not what it should be the transaction is reverted.
If in your code you have a require or revert statement in your contract, add an error message like this: require(condition, errorMessage); or revert (errorMessage);

Stack too deep, try using less variables on creating contract

I am trying to create a contract from a contract factory using the following function:
function createContract(string _var1, string _var2,
uint32 _var3, string _var4, string _var5,
string _var6, uint32 _var7, uint32 _var8, uint32 _var9,
uint32 _var10, uint32 _var11)
public returns (address contractAddress) {
return new Contract(_var1, random1, random2, _var2,
_var3, _var4, _var5, _var6, _var7, _var8,
_var9, _var10, _var11);
}
N.B. random1 and random2 are fields in the contract factory.
This function throws Stack too deep, try using less variables. I have read that I should split up the function etc. to get around this, but obviously, that is not an option here. Is there a way to get this working?
So, initially I tried grouping the variables by type into this:
function createContract(string[] _var1, uint32[] _var2)
public returns (address contractAddress) {
return new Contract(_var1, random1, random2, _var2);
}
However, nested dynamic arrays are not supported at this time. As string is represented as byte[] in EVM, a string[] is in fact passed as a byte[][].
I ended up grouping the uint32 and leaving the strings:
function createContract(string _var1, string _var2, uint32[] _var3,
string _var4, string _var5, string _var6)
public returns (address contractAddress) {
return new Contract(_var1, random1, random2, _var2,
_var3, _var4, _var5, _var6);
}
EDIT: Even though this method works, it is badly designed. See my other answer for a better workaround for this.
I went one step further with this as having an array of unit32 is ambiguous and confusing in terms of the position of a specific argument.
My final attempt utilized the struct type to provide a less ambiguous implementation. This struct is in a library in a separate file Library.sol:
struct ContractArgs {
uint32 var1;
string var2;
uint32 var3;
....
}
The factory method looks like this:
function createContract(Library.ContractArgs _contractArgs)
public returns (address contractAddress) {
return new Contract(_contractArgs, random1, random2);
}
And my constructor looks like this:
function Contract(Library.ContructorArgs _contractorArgs,
uint32 _supplierId, string _supplierName) {
contractArgs = _contractArgs;
random1 = _random1;
random2 = _random2;
}