How can I return an array of struct in solidity?
Asked Answered
R

3

14

I am designing a solution for an ethereum smart contract that does bidding. The use-case includes reserving a name eg. "myName" and assigning to an address. And then, people can bid for that name (in this case myName). There can be multiple such biddings happening for multiple names.

struct Bid {
  address bidOwner;
  uint bidAmount;
  bytes32 nameEntity;
}

mapping(bytes32 => Bid[]) highestBidder;

So, as you can see above, Bid struct holds data for one bidder, similarly, the key (eg. myName) in the mapping highestBidder points to an array of such bidders.

Now, I am facing a problem when I try to return something like highestBidder[myName].

Apparently, solidity does not support returning an array of structs (dynamic data). I either need to rearchitect my solution or find some workaround to make it work.

If you guys have any concerns regarding the question, please let me know, I will try to make it clear.

I am stuck here any help would be appreciated.

Rapeseed answered 20/2, 2018 at 4:34 Comment(0)
E
9

As you mentioned, this is not yet supported in Solidity. The powers that be are planning on changing it so you can, but for now, you have to retrieve the number of elements and then retrieve the decomposed struct as a tuple.

function getBidCount(bytes32 name) public constant returns (uint) {
    return highestBidder[name].length;
}

function getBid(bytes32 name, uint index) public constant returns (address, uint, bytes32) {
    Bid storage bid = highestBidder[name][index];

    return (bid.bidOwner, bid.bidAmount, bid.nameEntity);
}

Edit to address question in comment regarding storage vs memory in this case

Local storage variables are pointers to state variables (which are always in storage). From the Solidity docs:

The type of the local variable x is uint[] storage, but since storage is not dynamically allocated, it has to be assigned from a state variable before it can be used. So no space in storage will be allocated for x, but instead it functions only as an alias for a pre-existing variable in storage.

This is referring to an example where the varable used is uint[] x. Same applies to my code with Bid bid. In other words, no new storage is being created.

In terms of cost:

getBid("foo", 0) using Bid memory bid:

enter image description here

getBid("foo", 0) using Bid storage bid:

enter image description here

In this case, storage is cheaper.

Espresso answered 20/2, 2018 at 6:53 Comment(4)
This solves my problem, Thanks! Just a small doubt why did you use "Bid storage bid" in your answer. We can use "memory", which will save some gas.Rapeseed
@AdamKipnis Which tool did you use to get the details for the screenshots above ? information like txn cost Vs execution cost and "decoded input data" is very useful.Eberly
It’s from the transaction results in Remix (remix.ethereum.org).Espresso
In 2022, it seems we can just return an array of struct straightforwardly. ethereum.stackexchange.com/questions/3589/…Interracial
K
8

Return an array of struct in solidity?
In below function getBid returns array of bid structure.

contract BidHistory {
  struct Bid {
    address bidOwner;
    uint bidAmount;
    bytes32 nameEntity;
  }
  mapping (uint => Bid) public bids;
  uint public bidCount;

  constructor() public {
    bidCount = 0;
    storeBid("address0",0,0);
    storeBid("address1",1,1);
  }
  function storeBid(address memory _bidOwner, uint memory _bidAmount, bytes32 memory _nameEntity) public  {
    bids[tripcount] = Bid(_bidOwner, _bidAmount,_nameEntity);
    bidCount++;
  }
  //return Array of structure
  function getBid() public view returns (Bid[] memory){
      Bid[] memory lBids = new Bid[](tripcount);
      for (uint i = 0; i < bidCount; i++) {
          Bid storage lBid = bids[i];
          lBids[i] = lBid;
      }
      return lBids;
  }
}
Kissable answered 28/8, 2019 at 11:20 Comment(0)
H
7

About "returning an array of structs"... just a small workaround in order to return an array of structs extracted from medium

pragma solidity ^0.4.13;

contract Project
{
    struct Person {
        address addr;
        uint funds;
    }

    Person[] people;

    function getPeople(uint[] indexes)
    public
    returns (address[], uint[]) {
        address[] memory addrs = new address[](indexes.length);
        uint[]    memory funds = new uint[](indexes.length);

        for (uint i = 0; i < indexes.length; i++) {
            Person storage person = people[indexes[i]];
            addrs[i] = person.addr;
            funds[i] = person.funds;
        }

        return (addrs, funds);
    }
}

The uint[] index parameters should contain the indexes that you want to access.

Best

Hygrothermograph answered 5/4, 2019 at 10:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.