I am trying to test my voting ballot contract using Hardhat/ethers/TypeChain, but for some reason, the Ballot struct's typescript interface is NOT showing the array of choices struct field I have defined in the smart contract.

enter image description here

Below, is the TypeScript test file that isn't showing the Choice[] choices field in the ballot returned from the ballots mapping.

Smart Contract defining the Structs

Here is the entire smart contract code: // SPDX-License-Identifier: MIT pragma solidity ^0.8.0;

contract Voting {

// @dev for voters we need to check address has been approved for voting using mapping
mapping(address => bool) public voters;
// e.g. inflate jewel by 5% - id: 1, string: 5% inflation, votes: (0)
struct Choice {
    uint id;
    string name;
    uint votes;
// e.g. Ballot = vote, id: 1, name: jewel inflation, list of choices, end of ballot/time
struct Ballot {
    uint id;
    string name;
    Choice[] choices;
    uint end; 
// @dev id of each ballot
mapping(uint => Ballot) public ballots;
uint nextBallotId;
address public admin;
// @dev check if address of voter has already voted for a given ballot
mapping(address => mapping(uint => bool)) public votes;

constructor() {
    admin = msg.sender;
// [0xef..., 0xerfdf..]
function addVoters(address[] calldata _voters) onlyAdmin() external {
    for(uint i = 0; i < _voters.length; i++) {
        // e.g. voters[[0xef]] = true 
        voters[_voters[i]] = true;

function createBallot(
    string memory name,
    string[] memory _choices,
    uint offset
) public onlyAdmin() {
    // @dev can't assign due to Choices[] array as ballot's data location is STORAGE not MEMORY
    // e.g. Choice[] memory _choices = new ... 
    // ballots[nextBallotId] = Ballot(nextBallotId, name, **_choices**, end)

    // @dev can acccess field of struct that hasn't been created yet
    ballots[nextBallotId].id = nextBallotId;
    ballots[nextBallotId].name = name;
    ballots[nextBallotId].end = block.timestamp + offset;
    for(uint i = 0; i < _choices.length; i++) {
        ballots[nextBallotId].choices.push(Choice(i, _choices[i],  0));


function vote(uint ballotId, uint choiceId) external {
    require(voters[msg.sender] = true, 'only voters can vote');
    require(votes[msg.sender][ballotId] == false, 'voter can only vote once per ballot');
    require(block.timestamp < ballots[ballotId].end, 'can only vote after ballot end date');
    votes[msg.sender][ballotId] = true;


function results(uint ballotId) 
    returns(Choice[] memory) {
        require(block.timestamp >= ballots[ballotId].end, 'cannot see the ballot result before ballot end');
        return ballots[ballotId].choices;

modifier onlyAdmin() {
    require(msg.sender == admin, 'only admin');


  • Can you include all your smart contract code? Apr 4, 2022 at 15:28
  • @Kerry99, Yeah, i've added the full code now.
    – Keem
    Apr 8, 2022 at 19:04

1 Answer 1


Attention, in your code that you posted you haven't specify ballots variable with public visibility.

You must to specify the public visibility of ballots state variable. In your case change this:

mapping(uint => Ballot) ballots;

and replace it with:

mapping(uint => Ballot) public ballots;

When you define public, the compiler generate automatically generate getter function for variable which allow to view the values or handle it.

More information about visibility here.

  • Oh yeah, I did have that in the first screenshot but must've forgotten. This has fixed that ballots property but the original problem still stands.
    – Keem
    Apr 8, 2022 at 19:42

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.