Hardhat – Fixing ProviderError: Transaction Reverted Error

contract-debuggingdapp-debuggingdapp-developmenthardhatsolidity

I've been trying to debug this for about 8 hours now and have made no progress at all. I am new to programming and attempting to design a very basic DAO. Each time I attempt to deploy my contracts using 'npx hardhat run scripts/deploy.js –network localhost' it returns the following error:

ProviderError: Error: Transaction reverted: function call to a non-contract account
    at HttpProvider.request (/Users/angelachaseling/Desktop/_exchange/exchange/node_modules/hardhat/src/internal/core/providers/http.ts:78:19)
    at AutomaticSenderProvider.request (/Users/angelachaseling/Desktop/_exchange/exchange/node_modules/hardhat/src/internal/core/providers/accounts.ts:351:34)
    at AutomaticGasProvider.request (/Users/angelachaseling/Desktop/_exchange/exchange/node_modules/hardhat/src/internal/core/providers/gas-providers.ts:136:34)
    at AutomaticGasPriceProvider.request (/Users/angelachaseling/Desktop/_exchange/exchange/node_modules/hardhat/src/internal/core/providers/gas-providers.ts:213:34)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at EthersProviderWrapper.send (/Users/angelachaseling/Desktop/_exchange/exchange/node_modules/@nomiclabs/hardhat-ethers/src/internal/ethers-provider-wrapper.ts:13:20)

Here are my two basic smart contracts (*they are unfinished however any tips on where I've gone wrong would be appreciated), as well as my deployment script and hardhat config

nativeToken.sol

// 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 {

    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;
    }
}

Governance.sol

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

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

contract Governor {

    ERC20Basic public _token;
    address public contractAddress;

    uint public count;

    uint public contractBalance = _token.balanceOf(contractAddress);
    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() {
        contractAddress = address(this);
        count = 1;
    }


    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);
    }


}

deploy.js

const hre = require('hardhat');

async function main() {
  const Governance = await hre.ethers.getContractFactory('Governor');
  const governance = await Governance.deploy({ gasLimit: 150000 });

  await governance.deployed();

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

  const Token = await hre.ethers.getContractFactory('GovernorToken');
  const token = await Token.deploy({ gasLimit: 150000 });

  await token.deployed();

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

  

}

main()
  .then(() => process.exit(0))
  .catch((error) => {
    console.error(error);
    process.exit(1);
  });

hardhat.config.js

const fs = require('fs');
require('@nomiclabs/hardhat-waffle');

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

module.exports = {
  networks: {
    hardhat: {
      chainId: 31337,
    },
  },
  solidity: '0.8.4',
};

Best Answer

This might be an issue with the line:

 uint public contractBalance = _token.balanceOf(contractAddress);

As you can see in your code, you want to assign the contract balance to contractBalance before the contractAddress has been updated. You might want to move all the initializations in the constructor. So, for this case, you would need to:

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

Also, your _token is just a ERC20 instance. It needs a token address to actually get that balance you are looking for. I will recommend learning about interfaces. Your final constructor would be:

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