I am new to programming and attempting to design a very basic DAO which implements a native token for voting (as you'll see it is unfinished). Help would be greatly appreciated. I am currently running into the following error when deploying my contracts:

ProviderError: Error: Transaction reverted: function call to a non-contract account
    at HttpProvider.request

Or in the blockchain node:

Error: Transaction reverted: function call to a non-contract account
      at Governor.userBalance (contracts/Governance.sol:16)

The problems are with these parts:

uint public userBalance = _token.balanceOf(msg.sender);


constructor() {
    _token = ERC20Basic(_tokenAddress);
    contractAddress = address(this);
    contractBalance = _token.balanceOf(contractAddress);

How can I implement my custom token and fetch variables such as 'contractBalance' or 'userBalance' which relate to my custom token?

Full contracts, deployment script and hardhat config attached below:


// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import "hardhat/console.sol";
import "./nativeToken.sol";

contract Governor is ERC20Basic {

    ERC20Basic public _token;
    address public tokenAddress = address(_token);
    address public contractAddress;

    uint public count;

    uint public contractBalance;
    uint public userBalance = _token.balanceOf(msg.sender);

    mapping(uint => Proposal) proposals;

    event SubmitProposal(address proposer, address addressTo, uint startingTime, uint tokenAmount, string description);
    event SubmitVote(uint proposalID, address voter, uint votesYes, uint votesNo);
    event ProposalProcessed(uint proposalID, address addressTo, uint tokenAmount, string description);

    struct Proposal {
        address proposer;
        address addressTo;
        uint proposalID;
        uint startingTime;
        uint tokenAmount;
        uint votesYes;
        uint votesNo;
        string description;

constructor() {
        _token = ERC20Basic(_tokenAddress);
        contractAddress = address(this);
        contractBalance = _token.balanceOf(contractAddress);

    function createProposal(address _addressTo, uint _tokenAmount, string memory _description) public {
        uint proposalID = count;
        Proposal storage _proposal = proposals[proposalID];
        proposals[proposalID].proposer = msg.sender;
        _proposal.addressTo = _addressTo;
        _proposal.startingTime = block.timestamp;
        _proposal.tokenAmount = _tokenAmount;
        _proposal.votesYes = 0;
        _proposal.votesNo = 0;
        _proposal.description = _description;
        count += 1;
        emit SubmitProposal(msg.sender, _addressTo, block.timestamp, _tokenAmount, _description);

    function processProposal(uint proposalID) public returns (bool proposalPassed) {
        Proposal storage _proposal = proposals[proposalID];
        if (_proposal.votesYes > _proposal.votesNo) {
            proposalPassed = true;
        } else if (_proposal.votesYes <= _proposal.votesNo) {
            proposalPassed = false;
        if (proposalPassed = true) {
            contractBalance = contractBalance - _proposal.tokenAmount;
            userBalance = userBalance + _proposal.tokenAmount;
        emit ProposalProcessed(proposals[proposalID].proposalID, _proposal.addressTo, _proposal.tokenAmount, _proposal.description);

    function submitVote(bool vote, uint proposalID) public {
        Proposal storage _proposal = proposals[proposalID];
        if (vote = true) {
            _proposal.votesYes = _proposal.votesYes + userBalance;
        } else if (vote = false) {
            _proposal.votesNo = _proposal.votesNo + userBalance;
        emit SubmitVote(proposalID, msg.sender, _proposal.votesYes, _proposal.votesNo);



// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

interface IERC20 {

    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function allowance(address owner, address spender) external view returns (uint256);

    function transfer(address recipient, uint256 amount) external returns (bool);
    function approve(address spender, uint256 amount) external returns (bool);
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);

contract ERC20Basic is IERC20 {

    address public _tokenAddress = address(this);

    string public constant name = "GovernorToken";
    string public constant symbol = "GT";
    uint8 public constant decimals = 18;

    mapping(address => uint256) balances;

    mapping(address => mapping (address => uint256)) allowed;

    uint256 totalSupply_ = 10 ether;

   constructor() {
    balances[msg.sender] = totalSupply_;

    function totalSupply() public override view returns (uint256) {
    return totalSupply_;

    function balanceOf(address tokenOwner) public override view returns (uint256) {
        return balances[tokenOwner];

    function transfer(address receiver, uint256 numTokens) public override returns (bool) {
        require(numTokens <= balances[msg.sender]);
        balances[msg.sender] = balances[msg.sender]-numTokens;
        balances[receiver] = balances[receiver]+numTokens;
        emit Transfer(msg.sender, receiver, numTokens);
        return true;

    function approve(address delegate, uint256 numTokens) public override returns (bool) {
        allowed[msg.sender][delegate] = numTokens;
        emit Approval(msg.sender, delegate, numTokens);
        return true;

    function allowance(address owner, address delegate) public override view returns (uint) {
        return allowed[owner][delegate];

    function transferFrom(address owner, address buyer, uint256 numTokens) public override returns (bool) {
        require(numTokens <= balances[owner]);
        require(numTokens <= allowed[owner][msg.sender]);

        balances[owner] = balances[owner]-numTokens;
        allowed[owner][msg.sender] = allowed[owner][msg.sender]-numTokens;
        balances[buyer] = balances[buyer]+numTokens;
        emit Transfer(owner, buyer, numTokens);
        return true;


const hre = require('hardhat');

async function main() {

  const nativeToken = await hre.ethers.getContractFactory('ERC20Basic');
  const nativetoken = await nativeToken.deploy({ gasLimit: 2000000 });

  await nativetoken.deployed();

  console.log('Native Token deployed to:', nativetoken.address);

  const Governance = await hre.ethers.getContractFactory('Governor');
  const governance = await Governance.deploy({ gasLimit: 2000000 });

  await governance.deployed();

  console.log('Governance deployed to:', governance.address);  


  .then(() => process.exit(0))
  .catch((error) => {


const fs = require('fs');

const privateKey = fs.readFileSync('.secret').toString().trim();

module.exports = {
  networks: {
    hardhat: {
      chainId: 31337,
      allowUnlimitedContractSize: true
  solidity: '0.8.4',
  • The _token address isn't properly initialized in Governor. To initialize it pass nativetoken.address as input to Governor constructor. Then use it to initialize userBalance in the constructor. Also reserving a variable contractAddress isn't needed at all, use directly address(this) when needed. Likewise _tokenAddress isn't needed in ERC20Basic.
    – Ismael
    Jul 17 at 5:19

1 Answer 1


First, you need to modify the constructor in Governance.sol

constructor(address nativeToken) {
    _token = ERC20Basic(nativeToken);
    contractBalance = _token.balanceOf(address(this));
    userBalance = _token.balanceOf(msg.sender);

Then you need to update your deployment script.

const governance = await Governance.deploy(nativetoken.address,{ gasLimit: 2000000 });

Also, I think you should modify the initialization of user balance in Governance.sol

uint public userBalance; 

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.