Solidity – TypeError: Invalid BytesLike Value in Testing Raffle Contract

ethereumjshardhatjavascriptsolidity

While testing the Raffle contract, I am getting error in the line written
"await network.provider.send("evm_increaseTime", [Number(interval) + 1]);
await network.provider.send("evm_mine", []);
"

Here is Raffle.sol contract

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.15;

import "@chainlink/contracts/src/v0.8/vrf/VRFConsumerBaseV2.sol";
import "@chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol";
import "@chainlink/contracts/src/v0.8/automation/AutomationCompatible.sol";

error Raffle__EntranceFeeNotEnough();
error Raffle__TransferFailed();
error Raffle__NotOpen();
error Raffle_UpkeepNotNeeded(uint256 currentBalance, uint256 numPlayers, uint256 raffleState);

/**
 * @title A sample Raffle Contract
 * @author nik_arjun
 * @notice This contract is for creating untamperable decentralized smart contract
 * @dev This implements Chainlink VRF v2 and Chainlink Keepers
 */

contract Raffle is VRFConsumerBaseV2, AutomationCompatibleInterface {
   /* Type Declaration */
   enum RaffleState {
      OPEN,
      CALCULATING
   } // Equivalent to uint256 =  0: OPEN, 1:CALCULATING

   /* State Variable */
   uint256 private i_entranceFee;
   address payable[] private s_players;
   VRFCoordinatorV2Interface private immutable i_vrfCoordinator;
   bytes32 private immutable i_gasLane;
   uint64 private immutable i_subscriptionId;
   uint32 private immutable i_callbackGasLimit;
   uint16 private constant REQUEST_CONFIRMATIONS = 3;
   uint32 private constant NUM_WORDS = 1;

   /* Lottery Variables */
   address private s_recentWinner;
   RaffleState private s_raffleState;
   uint256 private s_lastTimeStamp;
   uint256 private immutable i_interval;

   /* Events */
   event RaffleEnter(address indexed player);
   event RequestedRaffleWinner(uint256 indexed requestId);
   event WinnerPicked(address indexed winner);

   constructor(
      address vrfCoordinatorV2,
      uint256 entranceFee,
      bytes32 gasLane,
      uint64 subscriptionId,
      uint32 callbackGasLimit,
      uint256 interval
   ) VRFConsumerBaseV2(vrfCoordinatorV2) {
      i_entranceFee = entranceFee;
      i_vrfCoordinator = VRFCoordinatorV2Interface(vrfCoordinatorV2);
      i_gasLane = gasLane;
      i_subscriptionId = subscriptionId;
      i_callbackGasLimit = callbackGasLimit;
      s_raffleState = RaffleState.OPEN; // or RaffleState(0)
      s_lastTimeStamp = block.timestamp;
      i_interval = interval;
   }

   function enterRaffle() public payable {
      if (msg.value < i_entranceFee) {
         revert Raffle__EntranceFeeNotEnough();
      }

      if (s_raffleState != RaffleState.OPEN) {
         revert Raffle__NotOpen();
      }

      s_players.push(payable(msg.sender));
      // Emit a event when we update the dynamic array or mapping
      // Named event with function name reversed
      emit RaffleEnter(msg.sender);
   }

   /**
    * @dev This is the function that the Chainlink Keeper nodes call
    * they look for `upkeepNeeded` to return True.
    * the following should be true for this to return true:
    * 1. The time interval has passed between raffle runs.
    * 2. The lottery is open.
    * 3. The contract has atleast 1 player and some ETH.
    * 4. Implicity, your subscription is funded with LINK.
    */

   function checkUpkeep(
      bytes memory /* performData */
   ) public override returns (bool upkeepNeeded, bytes memory /* performData */) {
      bool isOpen = (s_raffleState == RaffleState.OPEN);
      bool timePassed = ((block.timestamp - s_lastTimeStamp) > i_interval);
      bool hasPlayers = (s_players.length > 0);
      bool hasBalance = (address(this).balance > 0);

      upkeepNeeded = (isOpen && timePassed && hasPlayers && hasBalance);
   }

   function performUpkeep(bytes calldata /* performData */) external override {
      // Request Random Number
      // Once we get it, we will do something
      // 2 transaction process
      (bool upkeepNeeded, ) = checkUpkeep("");
      if (!upkeepNeeded) {
         revert Raffle_UpkeepNotNeeded(
            address(this).balance,
            s_players.length,
            uint256(s_raffleState)
         );
      }
      s_raffleState = RaffleState.CALCULATING;
      uint256 requestId = i_vrfCoordinator.requestRandomWords(
         i_gasLane, // gasLane
         i_subscriptionId,
         REQUEST_CONFIRMATIONS,
         i_callbackGasLimit,
         NUM_WORDS
      );

      emit RequestedRaffleWinner(requestId);
   }

   function fulfillRandomWords(
      uint256 /*requestId*/,
      uint256[] memory randomWords
   ) internal override {
      uint256 indexOfWinner = randomWords[0] % s_players.length;
      address payable recentWinner = s_players[indexOfWinner];
      s_recentWinner = recentWinner;
      s_lastTimeStamp = block.timestamp;
      s_raffleState = RaffleState.OPEN;
      s_players = new address payable[](0);
      (bool success, ) = recentWinner.call{value: address(this).balance}("");

      if (!success) {
         revert Raffle__TransferFailed();
      }

      emit WinnerPicked(recentWinner);
   }

   /* View/Pure Functions */
   function getEntranceFee() public view returns (uint256) {
      return i_entranceFee;
   }

   function getPlayer(uint256 index) public view returns (address) {
      return s_players[index];
   }

   function getRecentWinner() public view returns (address) {
      return s_recentWinner;
   }

   function getRaffleState() public view returns (RaffleState) {
      return s_raffleState;
   }

   function getNumWords() public pure returns (uint32) {
      return NUM_WORDS;
   }

   function getNumberOfPlayers() public view returns (uint256) {
      return s_players.length;
   }

   function getTimeStamp() public view returns (uint256) {
      return s_lastTimeStamp;
   }

   function getInterval() public view returns (uint256) {
      return i_interval;
   }

   function getRequestConfirmations() public pure returns (uint16) {
      return REQUEST_CONFIRMATIONS;
   }
}

Here is Raffle.test.js

const { network, deployments, ethers, getNamedAccounts, getChainId } = require("hardhat");
const { developementChains, networkConfig } = require("../../helper-hardhat-config");
const { assert, expect } = require("chai");

!developementChains.includes(network.name)
   ? describe.skip
   : describe("Raffle Unit Test", async function () {
        let raffle, VRFCoordinatorV2Mock, raffleEntranceFee, deployer, interval;

        beforeEach(async function () {
           deployer = (await getNamedAccounts()).deployer;
           await deployments.fixture(["all"]);
           const raffleAddress = (await deployments.get("Raffle")).address;
           const vrfCoordinatorV2Address = (await deployments.get("VRFCoordinatorV2Mock")).address;
           raffle = await ethers.getContract("Raffle", deployer);
           VRFCoordinatorV2Mock = await ethers.getContract("VRFCoordinatorV2Mock", deployer);
           raffleEntranceFee = await networkConfig[await getChainId()]["entranceFee"];
           interval = await raffle.getInterval();
        });

        describe("constructor", function () {
           it("Initializes Raffle Correctly", async function () {
              const raffleState = await raffle.getRaffleState();
              assert.equal(raffleState.toString(), "0");
              assert.equal(interval.toString(), networkConfig[await getChainId()]["interval"]);
           });
        });

        describe("Enter Raffle", function () {
           it("Reverts if you don't have enough ETH", async function () {
              await expect(raffle.enterRaffle()).to.be.revertedWithCustomError(
                 raffle,
                 "Raffle__EntranceFeeNotEnough()"
              );
           });

           it("Records player when it enters the Raffle", async function () {
              await raffle.enterRaffle({ value: raffleEntranceFee });
              const player_zero = await raffle.getPlayer(0);

              assert.equal(player_zero, deployer);
           });

           it("Doesn't allow entrance if Raffle State is close", async function () {
              await raffle.enterRaffle({ value: raffleEntranceFee });
              await network.provider.send("evm_increaseTime", [Number(interval) + 1]);
              await network.provider.send("evm_mine", []);
              // Perform upkeep by pretending as a Chainlink keeper
              await raffle.performUpkeep([]);

              await expect(
                 raffle.enterRaffle({ value: raffleEntranceFee })
              ).to.be.revertedWithCustomError(raffle, Raffle__NotOpen);
           });

           it("Emits an event on entering the raffle", async function () {
              await expect(await raffle.enterRaffle({ value: raffleEntranceFee })).to.emit(
                 raffle,
                 "RaffleEnter"
              );
           });
        });
     });

And this is the error I am getting while running it :

TypeError: invalid BytesLike value (argument="value", value=[  ], code=INVALID_ARGUMENT, version=6.10.0)
      at makeError (node_modules/ethers/src.ts/utils/errors.ts:687:21)
      at assert (node_modules/ethers/src.ts/utils/errors.ts:715:25)
      at assertArgument (node_modules/ethers/src.ts/utils/errors.ts:727:5)
      at _getBytes (node_modules/ethers/src.ts/utils/data.ts:44:19)
      at getBytesCopy (node_modules/ethers/src.ts/utils/data.ts:66:12)
      at BytesCoder.encode (node_modules/ethers/src.ts/abi/coders/bytes.ts:21:29)
      at /home/nraj07054/hardhat-fcc/hardhat-smartcontract-lottery-fcc/node_modules/ethers/src.ts/abi/coders/array.ts:55:19
      at Array.forEach (<anonymous>)
      at pack (node_modules/ethers/src.ts/abi/coders/array.ts:47:12)
      at TupleCoder.encode (node_modules/ethers/src.ts/abi/coders/tuple.ts:62:20)

Best Answer

The empty array you're passing "" is not a valid BytesLike value. You need to pass a valid hexadecimal string or an array of bytes.

Try this:

await raffle.performUpkeep("0x");
Related Topic