1

In my contract I have a mapping like this mapping(uint => myStruct)

I have a check function where I give a uint id and I want to get all the info in the struct (there are strings, addresses, uints, ...) with a call function in my truffle app.js.

What's the best way to do that? Can I convert every field to a string and send an array of strings? Should I make a separate getter for each field and use as many call functions?

For now I just return struct and I get invalid solidity type!: tuple

  • You can't return a struct in solidity, at least for the ucrrent version. so you need to return each value on its own. something lik e: return ( struct.member1,struct.member2) – Kaki Master Of Time Mar 6 '18 at 10:48
  • Please note that there is work in progress for Solidity to support serialization of complex types blog.ricmoo.com/… – Mikko Ohtamaa Mar 6 '18 at 12:42
  • @MedMansour You can return each value separately in a single return? That changes everything if js can handle it! – Teleporting Goat Mar 6 '18 at 12:46
1

You don't need an extra solidity function to get the info from a struct. You can call the struct directly using web3.

It helps if you have a function on the contract to get the amount of tokens otherwise you might be stuck using while instead of for. Lets assume you have a function to give you struct.length

var OwnableList = [];

//to get one struct entry you do this.

function getStructData(tokenId) {

    myContract.Ownables(tokenId, function(error, details) {
        if(details == undefined) {
            return false;
        } else {
            var name = details[0];
            var creator = details[1];
            var currentOwner = details[2];
            var isDestructible = details[3];
            var price = parseInt(details[4]);
            OwnableList.push({name: name, creator: creator, currentOwner: currentOwner, isDestructible: isDestructible, price: price});
    })
    return true;
    }
}

//to get all struct entrys you do this

function dumpStructData() {
    myContract.totalOwnables(function(error, total) {
        for(i=0; i<parseInt(total); i++) {
            getStructData(i);
        }
    }
}

//now you can just read the struct

function showStruct() {
    console.log(JSON.stringify(OwnableList);
}
0

the best way for adding something into a struct and get all the records is :

pragma solidity ^0.4.17;

contract test {
    struct Record {
        string name;
        string homeAddress;
    }

    Record[] public records;

    function AddRecord(string Address , string Name) public {
        Record memory newRec = Record({
            name : Name,
            homeAddress : Address
        });

        records.push(newRec);
    }

    function recordsArrayLength() public view returns(uint256){
        return records.length;
    }

}

and in your ui use this code :

first use let len = await test.methods.recordsArrayLength().call() and get the length of records array and then hit this code :

let records = []

for(let i=0;i<len;i++){
    records.push(await test.methods.records(i))
}

and now you have all the struct

  • So instead of returning the struct, you return an array with one struct inside? – Teleporting Goat Mar 6 '18 at 12:00
  • yep that's right – shahabvshahabi Mar 6 '18 at 18:33
  • I'm not sure how you understood that, but I don't want to add something into a struct, I just want to get all the info inside of it. – Teleporting Goat Jul 10 '18 at 7:43
0

It's tangential to your question, but one of the best ways to organize data is a mapped struct with an index of keys. This makes it possible to access a particular record or verify its existence without knowing which row it's on and without searching through a list. The index is an unordered list of keys that makes it possible to count the keys and enumerate the keys that exist.

mapping(bytes32 => RecordStruct) public recordStructs;
bytes32 public recordKeys;

Have a look over here for some variants, implementation details and discussion of limitations and advantages of various approaches.

Are there well-solved and simple storage patterns for Solidity?

Also, though not shown in the examples, event emitters can make the storage state apparent to software clients. With comprehensive event logs, one can write the contract with the assumption that clients are aware of the complete state at all times. This reduces on-chain concerns considerably.

Hope it helps.

  • What do you mean "without knowing which row it's on" ? Your answer looks interesting but I'm not sure what you're trying to accomplish. – Teleporting Goat Jul 10 '18 at 7:46
  • You're mapping(uint => myStruct) has structs stored by number and the question is about migrating to an array (also by number). I want to retrieve by key (e.g. "ORD002" or "0x123...") and I don't want to search. I also want a list and a count. – Rob Hitchens - B9lab Jul 10 '18 at 12:23
  • I think you misunderstood my question. I don't want to migrate, I have a struct with several data of multiple types, and I want to write a function to call with truffle in order to get all that info. – Teleporting Goat Jul 10 '18 at 13:28
  • I wrote an answer about how I solved my problem, maybe you'll understand better what I meant. – Teleporting Goat Jul 10 '18 at 14:01
0

Apparently my question was misunderstood, but I solved the problem with the help of Mikko Ohtamaa in the comments.

For some reason I didn't realized I could return multiple variables (and of different types!) Once you know you can do this, there's no problem really. Javascript handles it very well.

My solution looks somewhat like this:

contract myContract {
  struct Ownable {
    string name;
    address creator;
    address currentOwner;
    bool isDestructible;
    uint price;
  }

  mapping (uint => Ownable) public Ownables;

  function getOwnableInfo(uint OwnableId) public view returns (string, address, address, bool, uint){
    Ownable o = Ownables[OwnableId];
    return (o.name, o.creator, o.currentOwner, o.isDestructible, o.price);
  }

  /.../
}

And in the corresponding truffle, the call will return an array with the variables of the return in order:

myContractInstance.getOwnableInfo.call(ownableId).then((resultArray => {
  name = resultArray[0];
  creator = resultArray[1];
  currentOwner = resultArray[2];
  /.../
});

Notes:

  • Don't look too much into the Ownable o = Ownables[OwnableId];, I did that to increase readability, I don't think it's useful or a good thing at all.
  • If one of the data is a big number (typically a wei price), I convert it using bignumber's resultArray[4].toNumber() so that JavaScript can handle it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.