2

I am trying to create the following objects:

Bounty[] public bounties;

struct Bounty {
    address issuer;
    uint256 fulfillmentAmount;
    uint256 balance;
    bool bountyOpen;
    Fulfillment[] fulfillments;
    mapping (bytes32 => bool) used;
}

struct Fulfillment {
    uint256 fulfillmentAmount;
    address fulfiller;
}

A brief explanation is that I want to have an array of "Bounties" which can be satisfied multiple times. Each bounty has a number of properties, one of which is an array of "Fulfillments". The fulfillments describe and store the different times the bounty was fulfilled.

When trying to create a new bounty, I use the following:

bounties.push(Bounty(msg.sender, _fulfillmentAmount, msg.value, true));

This gives me the error that I have one fewer parameters than needed to initialize the object, because I am missing the Fulfillment[] array. (I do not need the mapping to be initialized.)

When I try to initialize with the array object like so:

bounties.push(Bounty(msg.sender, _fulfillmentAmount, msg.value, true, new Fullfillment[](0)));

I get the following error:

UnimplementedFeatureError: Copying of type struct ContractName.Fulfillment memory[] memory to storage not yet supported.

I have looked at a number of similar questions: [1] [2] [3]

They seem to imply that creating an object like this is not supported. Instead, I could turn Fullfillment[] fulfillments into:

uint fulfillmentLength;
mapping(uint => Fullfilment) fullfillments;

Keeping track of the length myself and doing some tricks to replace push().

Is this the best practice here? Or should I look at other alternatives like having the fulfillments be an object outside of the Bounty.

This is what Bounties-Network/StandardBounties seems to do:

https://github.com/Bounties-Network/StandardBounties/blob/master/contracts/StandardBounties.sol

Looking for best practice advice here.

1

It worked a lot better using a mapping to store the struct.

I used user-supplied keys for random access to the mapped structs and added a list of the keys in case iteration is important.

pragma solidity 0.4.24;

contract Bounties {

    // an unordered list of keys

    bytes32[] public bountyList;

    struct Bounty {
        bool isBounty; // simple collision check
        address issuer;
        uint256 fulfillmentAmount;
        uint256 balance;
        bool bountyOpen;
        Fulfillment[] fulfillments;
        mapping (bytes32 => bool) used;
    }

    struct Fulfillment {
        uint256 fulfillmentAmount;
        address fulfiller;
    }

    // a mapping to the Bounty structs
    mapping(bytes32 => Bounty) public bountyStructs;

    function isBounty(bytes32 key) public view returns(bool isIndeed) {
        return bountyStructs[key].isBounty;
    }

    function newBounty(bytes32 key, address _issuer, uint amount) public payable returns(bool success) {
        require(!isBounty(key)); // no duplicates
        bountyList.push(key);
        bountyStructs[key].isBounty = true;
        bountyStructs[key].issuer = _issuer;
        bountyStructs[key].fulfillmentAmount = amount;
        bountyStructs[key].balance = msg.value;
        bountyStructs[key].bountyOpen = true;
        // no need to initialize the mapping
        // should emit an event here
        return true;
    }

    function appendFulfillment(bytes32 bountyKey) public payable returns(bool success) {
        require(isBounty(bountyKey));
        Fulfillment memory f;
        f.fulfillmentAmount = msg.value;
        f.fulfiller = msg.sender;
        bountyStructs[bountyKey].fulfillments.push(f);
        // should emit an event here.
        return true;
    }

}

Hope it helps.

  • This makes sense. Two questions. First, is my original structure proposal not possible in Solidity today? As in there is no syntax error, it just won't work. Second, is there a benefit to your design vs StandardBounty.sol, or is it mostly just preference at that point? – Shawn Tabrizi Aug 16 '18 at 1:32
  • Without looking too deeply into it, I imagine the original issue is a limitation of the interface design. That's why I tried to stay with the nesting - to show it's not inherently wrong. Both structures seem reasonable enough. I don't see an obvious way to enumerate fulfillments by bounty in their structure. Although I didn't write the getter function, your way inclines in that direction, if that's what you're hoping for. Thanks for accepting the answer. ;-) – Rob Hitchens - B9lab Aug 16 '18 at 1:51

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.