return multiple array in solidity - solidity

I am trying to return multiple array from a function.
My code is looks like this:
struct Document{
bytes32 _documentNumber;
bytes32 _documentStatus;
uint _documentScore;
}
mapping(bytes32=>Document) public mapDocuments; // Holds Docno as key
mapping(address=>bytes32[]) public mapUserDocNos; // Holds User address as key with valuehaving array of all document nos
mapping(bytes32=>DocumentDetails) public mapDocumentDetails; // Holds Docno as key
//And i am storing data in map like this:
function addDocument(address _user, bytes32 _docNo,
bytes32 _documentStatus,uint _documentScore,
uint _createdDateStr) returns (bool status){
DocumentDebuggingLog(block.timestamp, "Step 1",_user);
Document memory document;
DocumentDebuggingLog(block.timestamp, "Step 2",_user);
document._customerAccountAddress= _user;
document._documentNumber= _docNo;
document._documentScore=_documentScore;
document._documentStatus=_documentStatus;
mapDocuments[_docNo]=document;
mapUserDocNos[_user].push(_docNo);
return true;
}
//trying to retrieve :
function getDocumentListByUser(address _user) returns (bytes32[] _docNumber,
bytes32[] _docStatus,uint[] _docScore){
bytes32[] _documentNumber;
bytes32[] _documentStatus;
uint[] _documentScore;
DocumentDebuggingLog(block.timestamp, "step 1 in getDocumentListByUser",_user);
for(uint i=0;i<mapUserDocNos[_user].length;i++){
//bytes32 dockey= mapUserDocNos[_user][i];
//DocumentDebuggingLog(block.timestamp, dockey,_user);
_documentNumber.push( mapDocuments[mapUserDocNos[_user][i]]._documentNumber);
_documentStatus.push( mapDocuments[mapUserDocNos[_user][i]]._documentStatus);
_documentScore.push( mapDocuments[mapUserDocNos[_user][i]]._documentScore);
}
return (_documentNumber,_documentStatus,_documentScore);
}
But i am not able to get any data from above function.Where i am doing wrong? is there any other way to return multiple array from a function in solidity?

Try to change below in function getDocumentListByUser
FROM:
bytes32[] _documentNumber;
bytes32[] _documentStatus;
uint[] _documentScore;
TO:
uint256 arrLength = mapUserDocNos[_user].length
bytes32[] memory _documentNumber = new bytes32[](arrLength);
bytes32[] memory _documentStatus = new bytes32[](arrLength);
uint[] memory _documentScore = new uint[](arrLength);
Try below:
function getDocumentListByUser(address _user) returns (bytes32[] _docNumber, bytes32[] _docStatus,uint[] _docScore) {
uint256 arrLength = mapUserDocNos[_user].length
bytes32[] memory _documentNumber = new bytes32[](arrLength);
bytes32[] memory _documentStatus = new bytes32[](arrLength);
uint[] memory _documentScore = new uint[](arrLength);
DocumentDebuggingLog(block.timestamp, "step 1 in getDocumentListByUser",_user);
for(uint i=0;i<mapUserDocNos[_user].length;i++){
//bytes32 dockey= mapUserDocNos[_user][i];
//DocumentDebuggingLog(block.timestamp, dockey,_user);
_documentNumber.push( mapDocuments[mapUserDocNos[_user][i]]._documentNumber);
_documentStatus.push( mapDocuments[mapUserDocNos[_user][i]]._documentStatus);
_documentScore.push( mapDocuments[mapUserDocNos[_user][i]]._documentScore);
}
return (_documentNumber,_documentStatus,_documentScore);
}

Due to the limitations of Ethereum Virtual Machine, you can currently return only a fixed sized array. Please look at the answer with code examples from the official solidity faq.

Related

Failed to call solidity function with array argument

I'm trying to execute contract's function use abi encode and call function, but I'm getting an error. Don't know how to resolve this issue.
pragma solidity >=0.8.0;
contract AbiTest {
event A(uint);
event Out(bytes);
function test() public {
bytes4 func = bytes4(keccak256("callMe(uint[])"));
uint[] memory arr = new uint[](3);
arr[0] = 3;
arr[1] = 4;
(bool res, bytes memory data) = address(this).call(abi.encode(func, arr));
emit Out(data);
require(res);
}
function callMe(uint[] memory array) public {
emit A(array[0]);
emit A(array[1]);
}
}
This solution works well, if arguments sizes are known at compile time, but with dynamic sizes this doesn't work.
How can I resolve it?
I think this solution should work just fine. This is compatible with dynamic array lengths.
function test() public {
uint[] memory arr = new uint[](2);
arr[0] = 3;
arr[1] = 4;
(bool success, ) = address(this).call
(
abi.encodeWithSignature(
"callMe(uint[])",
arr
)
);
}
Need to use abi.encodePacked see Solidity doc instead of abi.encode because second one don't compress items and therefore uses 32 bytes for the function name.
pragma solidity >=0.8.0;
contract Abi2Test {
function getByte() public returns (bytes memory) {
bytes4 func = bytes4(keccak256("callMe(uint256[])"));
return abi.encode(func);
}
function getByte2() public returns (bytes memory) {
bytes4 func = bytes4(keccak256("callMe(uint256[])"));
return abi.encodePacked(func);
}
}
getByte output: 0x6600981c00000000000000000000000000000000000000000000000000000000
getByte2 output: 0x6600981c
Therefore, when you use encode with function signature additionally will be allocated 28 bytes and EVM can't correctly parse passed value.
So, to correctly call function with abi.encode and abi.encodePacked you need to pack arguments with encode at the first, and at the second group function's signature with encoded bytes.
pragma solidity >=0.8.0;
contract Abi2Test {
event A(uint256);
event Out(bytes);
event Out1(bytes);
function test() public {
bytes4 func = bytes4(keccak256("callMe(uint256[])"));
uint256[] memory arr = new uint256[](3);
arr[0] = 3;
arr[1] = 4;
(bool res, bytes memory data) = address(this).call(abi.encodePacked(func, abi.encode(arr)));
emit Out(data);
require(res);
}
function callMe(uint256[] memory array) public {
emit A(array.length);
emit Out1(msg.data);
}
}

What type of input should I give to this function?

struct khatian{
uint64 khatianiId;
bytes32 plotHash;
uint16 percentOwn;
bytes32 buyFrom;
bytes32[] sellTo;
uint16[] sellPercentage;
uint[] ownerArray;
uint16[] perOwnerPercentage;
bool isExist;
}
function addKhatianFromOld(uint64 _khatianiId, bytes32 _plotHash, uint16 _percentOwn, bytes32 _buyFrom, uint[] _user, uint16[] _percentage) public{
require(msg.sender == contarctOwner, "Sender is not authorized");
require(plotMapping[_plotHash].isExist == true, "Plot doesn't exist");
bytes32 khatianHash = keccak256(abi.encodePacked(_khatianiId, _plotHash));
require(khatianMapping[khatianHash].isExist != true, "Khatian already exists");
require(khatianMapping[_buyFrom].isExist, "previous Khatian doesn't exist");
require(khatianMapping[_buyFrom].percentOwn >= _percentOwn, "Not enough land to sell");
for(uint j = 0; j< _user.length; j++){
require(userMapping[_user[j]].isExist == true, "User's NID doesn't exist");
}
This are my code snippet. I getting this error
''Error: expected array value (argument=null, value="1", code=INVALID_ARGUMENT, version=abi/5.5.0)''
What type of data should I give input here? specially in bytes32_buyFrom, uint[] _user, uint16[] _percentage?
I tried to give address and other string as input
Add memory / calldata keyword after declaring uint[] just like this uint[] memory _user and uint16[] memory _percentage let me know if it works
First of all, you must change the signature method adding the where memorized the data passed in input. In detail, you can consider that adding in memory the arrays.
Insomuch, change your method signature method in this way:
function addKhatianFromOld(uint64 _khatianiId, bytes32 _plotHash, uint16 _percentOwn, bytes32 _buyFrom, uint[] memory _user, uint16[] memory _percentage) public{
// your logic
}
To reply about your question:
In bytes32 parameter, in this function, you must give a format bytes32 from a string. You can see my answer to this thread for convert string to bytes32;
In uint[] array parameter, you must filled it with integer number starting from a maximum range value: 115792089237316195423570985008687907853269984665640564039457584007913129639935
(2**256);
In uint16[] array parameter, you must filled it with integer number starting from a maximum range value:
65536
(2**16)
In following attach an example of request with vainput

Member "Push" not found... I tried to run my code the same way I did earlier with the Strings but this time with uints and it didn't work. New to Sol

I'm new to solidty so any new keyword is appreciated. I like the language so far, the syntax is close to Java and C#. I'm still a college student and the lack of info about solidity is a killer. I hope someone can help :/
pragma solidity ^0.8.7;
contract MyTestContarct{
Person[] public people;
uint256 public peopleCount;
struct Person {
string _firstName;
string _lastName;
}
function addPerson(string memory _firstName, string memory _lastName) public{
people.push(Person(_firstName, _lastName));
peopleCount +=1;
}
uint[] IntArrayTest;
uint256 public elementsCounter;
struct Numbers{
uint _number;
}
function addElements(uint _number) public{
IntArrayTest.push(Numbers(_number));
elementsCounter +=1;
} //It worked with string, why not with uint?
}
IntArrayTest is of type uint[] (array of unsigned integers), so you can only push uint items to this array.
However Numbers(_number) is not an uint - its type is Numbers.
You can create a Numbers variable in memory, and then pass its _number member (which has the uint type) to the IntArrayTest array.
uint[] IntArrayTest;
function addElements(uint _number) public{
Numbers memory numbers = Numbers(_number);
IntArrayTest.push(numbers._number);
elementsCounter +=1;
}
Or if you want to pass the Numbers type to an array, you'll need to delcare an array of this type.
struct Numbers{
uint _number;
}
Numbers[] NumbersArrayTest;
function addElements(uint _number) public{
NumbersArrayTest.push(Numbers(_number));
elementsCounter +=1;
}

There is Array.push function in solidity how it is return length of the array?

pragma solidity >=0.5.0 <0.6.0;
contract ZombieFactory {
event NewZombie(uint zombieId, string name, uint dna);
uint dnaDigits = 16;
uint dnaModulus = 10 ** dnaDigits;
struct Zombie {
string name;
uint dna;
}
Zombie[] public zombies;
function _createZombie(string memory _name, uint _dna) private {
uint id = zombies.push(Zombie(_name, _dna)) - 1; //**here how it is return length of array**
emit NewZombie(id, _name, _dna);
}
function _generateRandomDna(string memory _str) private view returns (uint) {
uint rand = uint(keccak256(abi.encodePacked(_str)));
return rand % dnaModulus;
}
function createRandomZombie(string memory _name) public {
uint randDna = _generateRandomDna(_name);
_createZombie(_name, randDna);
}
}
I want to know how it is working i tired to searched in google but i cant get exact results try to explain how it returning length of array and basically it just add the element ...
before solidity v0.6.
Arrays have a member "push" define as :
Dynamic storage arrays and bytes (not string) have a member function called push that you can use to append an element at the end of the array. The element will be zero-initialised. The function returns the new length.
It's changed after v0.6.
Reference https://docs.soliditylang.org/en/v0.8.12/060-breaking-changes.html

ERC1155 _mintBatch() issue

Trying to create a function to mint a specific set of ERC1155 tokens but for some reason when executing no tokens are minted. Code for mintSingle() works fine. I've tried multiple ways of constructing the dynamic array that's required as an input to the OpenZeppelin ERC1155 contract function _mintBatch(address to, uint256[] ids, uint256[] amounts, bytes data), but nothing is working. What am I doing wrong? Thank you.
contract ExampleProject is ERC1155 {
uint256 public constant ROWA = 0;
uint256 public constant ROWBA = 30;
constructor() public ERC1155("ipfs://Example/metadata/{id}.json") {
}
function mintRowA()
public
{
uint256[] memory a = new uint256[](2);
a[0] = ROWA;
a[1] = ROWBA;
uint256[] memory b = new uint256[](2);
b[0] = 1;
b[1] = 1;
_mintBatch(msg.sender, a, b, "" );
}
function mintSingle()
public
{
_mint(msg.sender, ROWBA, 1, "");
}
}