Solidity - Why default getter of a public Struct variable doesn't return every variable inside Struct
Asked Answered
L

2

7

I am currently learning Solidity language and I've noticed that when I'm trying to get the value of a Struct inside my JS code, Solidity returns every variable without arrays. I have to create custom getter to access all the data inside my struct.

I've made a very simple example of a contract with a Struct initialized inside the constructor.

I'm accessing the variable with my custom getter and generated one inside JS code.

Test.sol

pragma solidity ^0.8.4;

contract Test {

    struct Data {
        string foo;
        address[] bar;
        address ctrt;
    }

    Data public d;

    constructor() {
        d.foo = "HELLO WORLD";
        d.bar.push(msg.sender);
        d.ctrt = address(this);
    }

    function getD() public view returns (Data memory) {
        return d;
    }
}

Test.js

const {ethers} = require('hardhat');

describe('Test', function () {
  it('should test something', async function() {
    const factory = await ethers.getContractFactory('Test')
    const test = await factory.deploy();
    console.log("Result from var:");
    console.log(await test.d());
    console.log("Result from getter:");
    console.log(await test.getD());
  })
});

Result in console:

Result from var:
[
  'HELLO WORLD',
  '0x5FbDB2315678afecb367f032d93F642f64180aa3',
  foo: 'HELLO WORLD',
  ctrt: '0x5FbDB2315678afecb367f032d93F642f64180aa3'
]
Result from getter:
[
  'HELLO WORLD',
  [ '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266' ],
  '0x5FbDB2315678afecb367f032d93F642f64180aa3',
  foo: 'HELLO WORLD',
  bar: [ '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266' ],
  ctrt: '0x5FbDB2315678afecb367f032d93F642f64180aa3'
]

What is the point to explicitly say that a variable is public if some part of the data is not visible?

Luci answered 28/5, 2021 at 14:29 Comment(1)
great question, but next time better to post on the ethereum stackoverflow :)Weylin
W
3

The automatic getters that are made for structs return all members in the struct except for members that are mappings and arrays. The Solidity docs explain:

The mapping and arrays (with the exception of byte arrays) in the struct are omitted because there is no good way to select individual struct members or provide a key for the mapping

So for your example the auto-generated getter looks like this:

function d() public returns (string foo, address ctrt) {
    foo = d.foo;
    ctrt = d.ctrt;
}

And as expected, in your example the auto-generated getter returns all struct members that are not mappings or arrays, and your getter returns all members.

Weylin answered 26/8, 2022 at 16:46 Comment(0)
G
1

Quoting docs:

If you have a public state variable of array type, then you can only retrieve single elements of the array via the generated getter function. This mechanism exists to avoid high gas costs when returning an entire array.

That's why when you make the call using ethers.js you don't see that value.

Solution is to create a getDataBar(uint i) function that returns bar contents.

Gillette answered 30/5, 2021 at 10:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.