I'm using ethers and hardhat to run my React application. I want to pass an object as a parameter to a Solidity function. The function should map the object (struct) to the id provided as a property in the object.

The following is my Solidity (^0.8.9) code:

 struct Mushroom {
    uint256 id;
    uint32 spores;
    string backgroundColor;
    string head;
    string eyes;
    string mouth;
    string element;
    string weapon;
    string armor;
    string accessory;
    uint256 level;

mapping(uint256 => Mushroom) public mushroomAttributes;

The struct is outside of the contract. Here is the Solidity function I am using to set the mapping.

function setMushroomData(Mushroom memory mushroom)
    mushroomAttributes[mushroom.id] = mushroom;

Here is the data that I am passing to the contract:

const data = {
  id: 1,
  spores: 0,
  backgroundColor: "blue",
  head: "round",
  eyes: "Wide",
  mouth: "Open",
  element: "Fire",
  weapon: "Axe",
  armor: "None",
  accessory: "Necklace",
  level: 3

const setData = await metadataContract.setMushroomData(data);
await setData.wait();
console.log("setDataTxn: ", setData);

I call the public mapping to get the returned details:

const attributes = await metadataContract.mushroomAttributes(1);
console.log("attributes: ", attributes);

This technically works well, however I am receiving the data with indexed integer values and the string property names like so:

0: BigNumber {_hex: '0x01', _isBigNumber: true},
1: 0,
2: "blue",
3: "round",
4: "Wide",
5: "Open",
6: "Fire",
7: "Axe",
8: "None",
9: "Necklace",
10: BigNumber {_hex: '0x03', _isBigNumber: true},
accessory: "Necklace",
armor: "None",
backgroundColor: "blue",
element: "Fire",
eyes: "Wide",
head: "round",
id: BigNumber {_hex: '0x01', _isBigNumber: true},
level: BigNumber {_hex: '0x03', _isBigNumber: true},
mouth: "Open",
spores: 0,
weapon: "Axe"

I would like to have this data, but without the indexed values (0,1,2,3,4 etc.). Only the string properties (accessory, id, weapon, armor, etc.) are necessary.

1 Answer 1


I'm facing the same issue. According to the Ethers documentation regarding calling a read-only method of a contract:

The type of the result depends on the ABI. If the method returns a single value, it will be returned directly, otherwise a Result object will be returned with each parameter available positionally and if the parameter is named, it will also be available by its name.


What I'm doing is converting the data to an object with just the named parameters, like this:

cleanAttributes = Object.fromEntries(Object.entries(attributes).slice(attributes.length))

Notice than attributes.length is the amount of positional parameters, so with the slice I'm omitting them. I'd suggest to put that into a function.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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