0

I want to write a test for the transferFrom(). I'm doing it by checking that the address balances change after the function is called. When I run the test, I get the error below. It's caused by the require statement in my ERC20.sol. How do I make the require statement pass?

test

it("checks trasfer is succesful", async () => {
                  // increase time to match tokenTradeTime
                  await network.provider.send("evm_increaseTime", [3600 + 3600])

                  // mine a block by using a write fuction to change block time
                  await deployer.sendTransaction({ to: ethers.constants.AddressZero })

                  // at this point the ico has ended and an hour has lapsed.
                  const icoState = await ico.getState()
                  assert.equal(icoState, 1) // state [1] = afterEnd on our ICO.sol

                  // check transfer succesful
                  await ico.transferFrom(
                      deployer.address,
                      "0x7F000649C3f42C2D80dc3bd99F3F5e7CB737092C",
                      100
                  )
                  const balOfAddr = await ico.getAddressBalance(
                      "0x7F000649C3f42C2D80dc3bd99F3F5e7CB737092C"
                  )
                  const balOfDeployer = await ico.getAddressBalance(deployer.address)
                  console.log(balOfDeployer.toString())

                  assert.equal(balOfAddr.toString(), "100")
                  assert.equal(balOfDeployer.toString(), "99900")
              })

Error

 Error: Transaction reverted without a reason string
      at ICO.transferFrom (contracts/ERC20.sol:158)
      at ICO.transferFrom (contracts/ICO.sol:157)
      at processTicksAndRejections (node:internal/process/task_queues:96:5)
      at runNextTicks (node:internal/process/task_queues:65:3)
      at listOnTimeout (node:internal/timers:528:9)
      at processTimers (node:internal/timers:502:7)
      at HardhatNode._mineBlockWithPendingTxs (node_modules/hardhat/src/internal/hardhat-network/provider/node.ts:1840:23)
      at HardhatNode.mineBlock (node_modules/hardhat/src/internal/hardhat-network/provider/node.ts:517:16)
      at EthModule._sendTransactionAndReturnHash (node_modules/hardhat/src/internal/hardhat-network/provider/modules/eth.ts:1532:18)

ERC20.sol transferFrom func

function transferFrom(
        address sender,
        address recipient,
        uint256 tokens
    ) public virtual override returns (bool) {

        // THE ERROR IS DUE TO THIS FUCNTION FAILING.
        require(allowed[sender][recipient] >= tokens);
        
        require(
            balances[sender] >= tokens,
            "you cannot transfer more than you have"
        );

        // transfering
        balances[sender] -= tokens;
        balances[recipient] += tokens;
        return true;
    }

Repo

https://github.com/kihiuFrank/ICO

1 Answer 1

1

The error is due to the require statement that checks if the recipient is allowed to spend tokens on behalf of the sender. To make the require statement pass, you need to first approve the recipient to spend tokens on behalf of the sender by calling the approve function. You can do this in your test before calling the transferFrom function.

Here's how you can update your test to fix the error:

it("checks trasfer is succesful", async () => {
    // increase time to match tokenTradeTime
    await network.provider.send("evm_increaseTime", [3600 + 3600])

    // mine a block by using a write fuction to change block time
    await deployer.sendTransaction({ to: ethers.constants.AddressZero })

    // at this point the ico has ended and an hour has lapsed.
    const icoState = await ico.getState()
    assert.equal(icoState, 1) // state [1] = afterEnd on our ICO.sol

    // Approve the recipient to spend tokens on behalf of the sender (deployer)
    await ico.approve("0x7F000649C3f42C2D80dc3bd99F3F5e7CB737092C", 100)

    // check transfer succesful
    await ico.transferFrom(
        deployer.address,
        "0x7F000649C3f42C2D80dc3bd99F3F5e7CB737092C",
        100
    )
    const balOfAddr = await ico.getAddressBalance(
        "0x7F000649C3f42C2D80dc3bd99F3F5e7CB737092C"
    )
    const balOfDeployer = await ico.getAddressBalance(deployer.address)
    console.log(balOfDeployer.toString())

    assert.equal(balOfAddr.toString(), "100")
    assert.equal(balOfDeployer.toString(), "99900")
})

By adding the approve function call, you're granting the specified allowance to the recipient, which will satisfy the require statement and allow the transferFrom function to execute successfully.

1
  • 1
    Thanks a lot. I was trying to override the allowance function in my Ico.sol to try call it in my tests. it failed. Didn't know I could just say ico.approve. Thanks again.
    – kihiuFrank
    May 7, 2023 at 8:10

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.