1

I'm trying to send ETH to a contract in tests using hardhat await owner.sendTransaction({to: greeter.address, value: "1000000"}), but it reverts with "function selector was not recognized" error.

You can reproduce this with a basic project -

npm init -y
npm i -D hardhat
npx hardhat # use defaults

edit test/sample-test.js and add the following test case -

  it("Should send ETH to the contract", async function () {
    [owner] = await ethers.getSigners();
    const Greeter = await ethers.getContractFactory("Greeter");
    const greeter = await Greeter.deploy("Hello, world!");
    await greeter.deployed();
    await owner.sendTransaction({to: greeter.address, value: "1000000"});
  });

run tests npx hardhat test and the newly added test will fail with Error: Transaction reverted: function selector was not recognized and there's no fallback nor receive function.

Full test log -

Deploying a Greeter with greeting: Hello, world!
Changing greeting from 'Hello, world!' to 'Hola, mundo!'
    ✔ Should return the new greeting once it's changed (626ms)
Deploying a Greeter with greeting: Hello, world!
    1) Should send ETH to the contract


  1 passing (745ms)
  1 failing

  1) Greeter
       Should send ETH to the contract:
     Error: Transaction reverted: function selector was not recognized and there's no fallback nor receive function
    at Greeter.<unrecognized-selector> (contracts/Greeter.sol:6)
    at EthModule._estimateGasAction (/Users/tal/dev/solidity/SendEthToContract/node_modules/hardhat/src/internal/hardhat-network/provider/modules/eth.ts:425:7)
    at HardhatNetworkProvider.request (/Users/tal/dev/solidity/SendEthToContract/node_modules/hardhat/src/internal/hardhat-network/provider/provider.ts:118:18)
    at EthersProviderWrapper.send (/Users/tal/dev/solidity/SendEthToContract/node_modules/@nomiclabs/hardhat-ethers/src/internal/ethers-provider-wrapper.ts:13:20)

Any idea how to send ETH to the contract?

2 Answers 2

2

I stumbled into this question while writing a test on a forked hardhat network, where I wanted to send ETH to a 3rd party contract that doesn't have a receive function or a payable fallback function. I needed this because I then wanted to impersonate the contract to call a permissioned method on another contract that only accepts calls from the first contract.

In case anyone is in the same situation, I'll share my solution using the hardhat_setBalance RPC method, through hardhat-network-helpers library. This can set any balance arbitrarily.

import * as helpers from "@nomicfoundation/hardhat-network-helpers";

// ...

await helpers.setBalance(MyContract.address, hre.ethers.utils.parseEther("1"));
0

Update: As pointed out by @Nergon, there's an answer that explains this phenomena.

To send ETH to a contract without using a payable function, it needs to have a function using special solidity keyword receive to allow receiving ETH without calling a function.

receive() external payable

Seems that a contract can receive ETH only through a payable function.

ETH receiving function should look something like this -

function receiveETH() public payable {
    // code
}

it can then receive ETH in tests using -

await farmer.receiveETH({value: ethers.utils.parseEther("1.0")});
12
  • While exploring your own options and posting an answer to yourself is definitely useful, maybe searching for answers before creating a question is better to improve the quality of the content in SO.
    – Nergon
    Apr 29, 2022 at 6:24
  • Now as to your question and answer, this answer explains how to properly receive eth in your contract.
    – Nergon
    Apr 29, 2022 at 6:25
  • I have searched for a few hours and couldn't find a satisfactory answer. Also, I'm quite familiar with SO, they have other exchanges so don't rely on the ethereum exchange score to assume I don't know how to produce quality content.
    – Kof
    Apr 29, 2022 at 6:29
  • Checking the answer you've linked, it does help but the question asks "What is the receive keyword in solidity?", unless I'm already familiar with the concept it would be hard to find it; which explains why I didn't find it. Thus, adding a question to SO that rephrases the question is very helpful to the community, hopefully save some time to others.
    – Kof
    Apr 29, 2022 at 6:32
  • Given that you asked and a moment later you answered your own question, allow me to disagree. Also the answer i've posted took less than a minute to find.
    – Nergon
    Apr 29, 2022 at 6:33

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.