THIAGO DE BONIS
THIAGO DE BONIS

Reputation: 870

Transaction failed with execution error while call Function

I am receiving the following message:

"Warning! Error encountered during contract execution [execution reverted]"

What I'm trying to do is simple, I have a contract, where I don't get token, I just use ethereum and users just pay gas fee to miners.

What I'm trying to do here is call a contract function, but it adds data to the blockchain, which wastes gas.

Here's the contract:

https://goerli.etherscan.io/address/0xa46dc78595315b94904182013888adb439c6009f

Contract Code:

/**
 * @title Ballot
 * @dev Implements voting process along with vote delegation
 */
contract Ballot is IHelper, Guard, Logging {
    Confirmed[6] private _confirmedVotes;
    Abstention private _abstentionVotes;
    uint[6] private _candidates;
    uint private _totalConfirmedVotes;
    mapping(address => bool) private _electorHasAlreadyVoted;

    constructor() {
        _registerCandidates();

        emit LogStartElection("Beginning of the election period, ballot box released!", getResult());
    }

    /** @dev Register Candidates **/
    function _registerCandidates() private {
        for (uint i = 0; i < _candidates.length; i++) {
            _candidates[i] = i;
            _confirmedVotes[i].candidate = i;
        }
    }

    /**
     * @dev Return Elector Has Already Voted
     * @return value of '_electorHasAlreadyVoted'
     */
    function getElectorHasAlreadyVoted() public view returns (bool) {
        return _electorHasAlreadyVoted[msg.sender];
    }

    /**
     * @dev Return Electoral Result
     * @return value of 'ElectionResult'
     */
    function getResult() public view returns (ElectionResult memory) {
        return
            ElectionResult({
                candidates: _candidates,
                totalConfirmedVotes: _totalConfirmedVotes,
                confirmedVotes: _confirmedVotes,
                abstentionVotes: _abstentionVotes
            });
    }

    /**
     * @dev Elector Vote Confirmation
     * @param candidateID value to store
     */
    function confirmVote(
        uint candidateID
    ) public onlyCandidateRegistered(candidateID, _candidates.length) onlyElectorWhoDidNotVote(_electorHasAlreadyVoted[msg.sender]) {
        _confirmedVotes[candidateID].totalVotes++;
        _confirmedVotes[candidateID].elector.push(msg.sender);
        _confirmedVotes[candidateID].candidate = candidateID;

        _electorHasAlreadyVoted[msg.sender] = true;

        _totalConfirmedVotes++;

        emit LogElectorVote("Vote Confirmed and Computed!", getResult());
    }

    /** @dev Elector Vote Abstention **/
    function abstainVote() public onlyElectorWhoDidNotVote(_electorHasAlreadyVoted[msg.sender]) {
        _abstentionVotes.totalVotes++;
        _abstentionVotes.elector.push(msg.sender);

        _electorHasAlreadyVoted[msg.sender] = true;

        emit LogElectorVote("Vote Abstained and Computed!", getResult());
    }
}

DApp Ethers code:

    const PROVIDER = ethers.providers.InfuraProvider.getWebSocketProvider({ chainId: 5, name: 'goerli' });
    const PRIVATE_WALLET = new ethers.Wallet(process.env.REACT_APP_WALLET_PRIVATE_KEY || '', PROVIDER);
    const CONTRACT = new ethers.Contract(
                    process.env.REACT_APP_SOLIDITY_CONTRACT_ADDRESS || '',
                    BallotContract.abi,
                    PRIVATE_WALLET
                )
    
    const ELECTOR_SIGNER = CONTRACT.connect(ELECTOR_WALLET);
    const CONTRACT_ADDRESS = await infura.contract.resolvedAddress;
    const GAS_LIMIT = await ELECTOR_SIGNER.estimateGas.confirmVote(1);
    const TRANSACTION_HASH = await window.ethereum?.request({
                                method: 'eth_sendTransaction',
                                params: [
                                    {
                                        from: ELECTOR_SIGNER,
                                        to: CONTRACT_ADDRESS,
                                        gas: estimateGas._hex,
                                        value: 0,
                                    },
                                ],
                            })
const TRANSACTION_RECEIPT = await PROVIDER.waitForTransaction(TRANSACTION_HASH);
const RESPONSE = await ELECTOR_SIGNER.confirmVote(1);

enter image description here

Upvotes: 1

Views: 1374

Answers (1)

Petr Hejda
Petr Hejda

Reputation: 43491

For a contract to accept ETH (or generally native tokens - BNB on Binance Smart Chain, MATIC on Polygon, ...), it needs to implement either of the special functions - receive() or payable fallback(). If the contract doesn't implement any of these functions, it rejects the incoming transfer.

contract Ballot {
    // ...

    receive() external payable {
        // can be empty; or you can redirect the incoming transfer to an EOA
    }
}

When you just send empty value and empty data, it tries to invoke the fallback() function, that is also not present. So the solution is similar in this case - implement the fallback() special function.

contract Ballot {
    // ...

    fallback() external payable {
        // can be empty
    }
}

Upvotes: 1

Related Questions