Send array of structs to a different contract

Viewed 579

It is mentioned here that ABIEncoderV2 should make it possible to pass structs from contract to contract. Solidity latest ABI spec mentions that it is possible to have tuple array as a input. Can you please say how array of structs / tuple[] should be sent in below example code from TupleArrayFactory to TupleArray?

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;

contract TupleArrayFactory {
    TupleArray newTuple;

    function createTuple() public {
        newTuple = new TupleArray("trait0", "display0", 0);
       
        // newTuple.pushAttribute([["trait1","display2",2]]);
        newTuple.pushAttribute(["trait1","display2",2]);
        // TypeError: Unable to deduce common type for array elements.
    }
}

contract TupleArray {
    struct Attribute {
        string trait_type;
        string display_type;
        uint8 value;
    }
    
    Attribute[] public attributes;
    Attribute[] public tempAttributeArr;

    constructor(string memory trait_type, string memory display_type, uint8 value) payable {
        Attribute memory Attribute0 = Attribute(trait_type, display_type, value);
        tempAttributeArr.push(Attribute0);
        pushAttribute(tempAttributeArr);
        
        //pushAttribute([trait_type, display_type, value]);
        // TypeError: Unable to deduce common type for array elements.
    }
    
    function pushAttribute(Attribute[] memory _attr) public payable {
        attributes.push(_attr[0]);
    }
}
1 Answers

Here's a working version of your example:

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;

contract TupleArrayFactory {
    TupleArray newTuple;

    function createTuple() public {
        newTuple = new TupleArray("trait0", "display0", 0);

        TupleArray.Attribute[] memory attributes = new TupleArray.Attribute[](1);
        attributes[0] = TupleArray.Attribute("trait1", "display2", 2);
        newTuple.pushAttribute(attributes);
    }
}

contract TupleArray {
    struct Attribute {
        string trait_type;
        string display_type;
        uint8 value;
    }

    Attribute[] public attributes;

    constructor(string memory trait_type, string memory display_type, uint8 value) payable {
        Attribute[] memory tempAttributeArr = new Attribute[](1);
        tempAttributeArr[0] = Attribute(trait_type, display_type, value);
        pushAttribute(tempAttributeArr);
    }

    function pushAttribute(Attribute[] memory _attr) public payable {
        attributes.push(_attr[0]);
    }
}

Some remarks:

  1. pushAttribute([["trait1","display2",2]]) won't work because an array is not implicitly convertible to a struct. You have to invoke the struct constructor.
  2. Even then pushAttribute([TupleArray.Attribute("trait1","display2",2)]) won't work because Solidity currently does not have dynamic array literals. If you want to pass a dynamic array into a function you have to create a variable for it.
  3. Your pushAttribute() takes an array but ignores all but the first element. So why make it an array at all? I'm assuming it's for the sake of the example but if not, you should make the function just accept a single struct.
  4. Putting tempAttributeArr in storage works but is not necessary. You can put it in memory, which is cheaper.

Solidity latest ABI spec mentions that it is possible to have tuple array as a input.

The docs you are linking to only describe how tuples (used for example to return named function arguments or return values) are formatted in the JSON describing the ABI.

Maybe you're referring to some other section on that page? In general, structs are encoded as tuples the ABI, which might be the source of confusion there. But this simply means that if you are encoding the parameters yourself (e.g. when you use off-chain code to issue a transaction), you should encode structs as tuples. If you are just calling external functions on chain, you do not have to do that. In fact you can't because structs and tuples are not convertible to each other. You have to use an actual struct when a function expects a struct and the struct type must be the exact one specified in function signature.

Related