0

I'm prototyping a simple smart contract for donations. My intention is to have a mapping for balances and another mapping for structs. The issue is that I get the following error:

TypeError: Member "push" not found or not visible after argument-dependent lookup in struct donMapping.Donation storage ref. --> sc.sol:79:9: | 79 | donations[_recipient].push(Donation(id++,amount,_donor,_msg,block.timestamp)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^

I'm guessing that donations[_recipient] is not recognized as a struct, so push can't be used there (similar syntax as I use for pushing into a regular struct i.e. donation.push(Donation(...))).

What is the proper way to push a struct into a mapping of structs? I tried searching through existing questions in stackexchange with this error, but none seemed to apply to this case. Here's the full prototype code:

contract donMapping{
struct Donation {
    uint id;
    uint amount;
    string donor;
    string msg;
    uint timestamp; //seconds since unix start
}
uint amount = 0;
uint id = 0;
mapping(address => uint) public balances;
mapping(address => Donation) public donations;
Donation[] public donation;

function donate(address _recipient, string calldata _donor, string calldata _msg) public payable {
    require(msg.value > 0, "The donation needs to be >0 in order for it to go through");
    amount = msg.value;
    balances[_recipient] += amount;        
    donations[_recipient].push(Donation(id++,amount,_donor,_msg,block.timestamp));
  }
}

Thanks!

Edit: Thanks to bguiz's answer I realized what I wanted to do was have a mapping of struct arrays (so the only thing missing was the [] on the second mapping definition). Here's the working solution I came up with:

contract mappingOfArrayOfStructs{
    struct Donation {
        uint id;
        uint amount;
        string donor;
        string msg;
        uint timestamp; //seconds since unix start
    }
    uint amount = 0;
    uint id = 0;
    mapping(address => uint) public balances;
    mapping(address => Donation[]) public donationsMap;

    function donate(address _recipient, string calldata _donor, string calldata _msg) public payable {
        require(msg.value > 0, "The donation needs to be >0 in order for it to go through");
        amount = msg.value;
        balances[_recipient] += amount;        
       donationsMap[_recipient].push(Donation(id++,amount,_donor,_msg,block.timestamp));
  }
  
   function donations_getter(address _recipient, uint _id) public view returns (Donation[] memory){
        return donationsMap[_recipient];//shows up as a tuple
  }  
}
1
  • Mappings don't have a .push method. Unlike arrays, mappings already have all the keys possible already declared and mapped to 0 values. So you don't actually push a new element to the mapping, you just re-declare the key to be equal to the new value like in @bguiz's answer. – scorpion9979 Jun 10 at 6:19
2

Try replacing this line:

donations[_recipient].push(Donation(id++,amount,_donor,_msg,block.timestamp));

with this with this line:

donations[_recipient] = Donation(id++,amount,_donor,_msg,block.timestamp);

The square bracket syntax already identifies the key that you wish to set the new value of in the mapping.


The above answers your question about a mapping of structs, however, I notice that you also have an array of the same struct.

Donation[] public donation;

Note that the above suggestion will not add the struct to this array as well.

If that is the intent (where you wish to maintain both a mapping and an array), I suggest you name these variables dontationsMap and donationsList instead... and then replace the same line above with:

donationsMap[_recipient] = Donation(id++,amount,_donor,_msg,block.timestamp);
donationsList.push(Donation(id++,amount,_donor,_msg,block.timestamp));

(this is where you'd actually want to use .push())

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.