I started coding project and I got error when trying to test him. When I trying to call some contract function from js tester i got error:
Error: call revert exception [ See: https://links.ethers.org/v5-errors-CALL_EXCEPTION ] (method="getEntranceFee()", data="0x", errorArgs=null, errorName=null, errorSignature=null, reason=null, code=CALL_EXCEPTION, version=abi/5.7.0)
at Logger.makeError (node_modules\@ethersproject\logger\src.ts\index.ts:269:28)
at Logger.throwError (node_modules\@ethersproject\logger\src.ts\index.ts:281:20)
at Interface.decodeFunctionResult (node_modules\@ethersproject\abi\src.ts\interface.ts:427:23)
at Contract.<anonymous> (node_modules\@ethersproject\contracts\src.ts\index.ts:400:44)
at step (node_modules\@ethersproject\contracts\lib\index.js:48:23)
at Object.next (node_modules\@ethersproject\contracts\lib\index.js:29:53)
at fulfilled (node_modules\@ethersproject\contracts\lib\index.js:20:58)
at processTicksAndRejections (node:internal/process/task_queues:95:5)
at runNextTicks (node:internal/process/task_queues:64:3)
at listOnTimeout (node:internal/timers:540:9)
Here is my codes:
!developmentChains.includes(network.name) ? describe.skip : describe("Lottery Unit Test", () => {
let lottery, vrfCoordinatorV2Mock, lotteryEntranceFee, deployer, interval;
const chainId = network.config.chainId;
beforeEach(async () => { // before all testing we do this part of code (get our contracts)
deployer = (await getNamedAccounts()).deployer;
await deployments.fixture(["all"]); // means that we want deploy everything
lottery = await ethers.getContractAt("Lottery", deployer);
vrfCoordinatorV2Mock = await ethers.getContractAt("VRFCoordinatorV2Mock", deployer);
lotteryEntranceFee = await lottery.getEntranceFee(); // here I got error
interval = await lottery.getInterval(); // and here I got error
})
})
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "@chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol";
import "@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol";
import "@chainlink/contracts/src/v0.8/interfaces/KeeperCompatibleInterface.sol";
import "hardhat/console.sol";
/* using error instead of require is gas efficient */
error Lottery__NotEnoughFund();
error Lottery__TransferFailed();
error Lottery__LotteryIsClosed();
error Lottery__UpkeepNotNeeded(
uint256 curBalance,
uint256 numPlayers,
uint256 lotteryState
);
/**
* @title A sample Lottery contract
* @author me
* @notice This contract is for creation untamperable decentralized smart contract
* @dev This contract is using Chainlink VRF v2 and Chainlink Keepers
*/
contract Lottery is VRFConsumerBaseV2, KeeperCompatibleInterface {
// here: 0 - OPEN, 1 - PENDING and etc.
enum LotteryState {
OPEN,
PENDING
}
uint256 private constant ENTRANCE_FEE = 0.01 ether;
uint8 private constant REQUEST_CONFIRMATION = 3;
uint8 private constant NUM_WORD = 1; // we need only one random number
address payable[] private s_players; // if somebody from players array wins we should pay them and its why we put here 'payable'
address private s_winner;
VRFCoordinatorV2Interface private immutable i_vrfCoordinator;
bytes32 private immutable i_gasLane;
uint64 private immutable i_subId;
uint32 private immutable i_callbackGasLimit;
uint256 private immutable i_interval;
uint256 private s_lastTimeStamp;
LotteryState private s_lotteryState;
/*'event' use for getting some info from blockchain when in blockchain something happens (winning in lottery like example) */
event LotteryEnter(address indexed player); // 'indexed' means that value will be easier to read
event RequestedLotteryWinner(uint256 indexed requestId);
event PickedWinner(address indexed winner);
constructor(
address vrfCoordinatorV2, // contract
bytes32 gasLane, // keyHash
uint64 subscriptionId,
uint32 callbackGasLimit,
uint256 interval
) VRFConsumerBaseV2(vrfCoordinatorV2) {
i_vrfCoordinator = VRFCoordinatorV2Interface(vrfCoordinatorV2);
i_gasLane = gasLane;
i_subId = subscriptionId;
i_callbackGasLimit = callbackGasLimit;
s_lotteryState = LotteryState.OPEN; // checker if lottery is open or closed
s_lastTimeStamp = block.timestamp;
i_interval = interval;
}
function enterLottery() public payable {
if (msg.value < ENTRANCE_FEE) {
revert Lottery__NotEnoughFund(); // instead a require to be gas efficient
}
if (s_lotteryState != LotteryState.OPEN) {
revert Lottery__LotteryIsClosed();
}
s_players.push(payable(msg.sender));
emit LotteryEnter(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 ETH.
* 4. Implicity, your subscription is funded with LINK.
*/
function checkUpkeep(
bytes memory /* checkData */ // also function don't use it but needed
)
public
view
override
returns (
bool upkeepNeeded,
bytes memory /* performData */ // use if we want that 'checkUpkeep' doing some other stuff
)
{
bool isOpen = (s_lotteryState == LotteryState.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); // check all indicators
}
function performUpkeep(bytes calldata /* performData */) external override {
(bool upkeepNeeded, ) = checkUpkeep("");
if (!upkeepNeeded) {
revert Lottery__UpkeepNotNeeded(
address(this).balance,
s_players.length,
uint256(s_lotteryState)
);
}
s_lotteryState = LotteryState.PENDING; // while we pick a random winner we put our state pending
/* this is also call event like emit */
uint256 requestId = i_vrfCoordinator.requestRandomWords(
i_gasLane, // maximum size of gas for number
i_subId, // Id that this contract uses for funding requests
REQUEST_CONFIRMATION, // how many confirmations we should wait to get result (recommend min. 2)
i_callbackGasLimit, // limit how much gas uses to callback requests
NUM_WORD // how much numbers we get
);
/* this is redundant event because in the top requestId also call event */
emit RequestedLotteryWinner(requestId);
}
function fulfillRandomWords(
uint256 /* requestId */, // we make 'requestId' unused instead of delete because we didn't use this value but out function are needed this
uint256[] memory randomWords
) internal override {
uint256 indexOfWinner = randomWords[0] % s_players.length;
address payable winner = s_players[indexOfWinner];
s_winner = winner;
s_players = new address payable[](0);
s_lastTimeStamp = block.timestamp;
(bool success, ) = winner.call{value: address(this).balance}(""); // we tranfer all money to address of winner
if (!success) {
revert Lottery__TransferFailed();
}
s_lotteryState = LotteryState.OPEN;
emit PickedWinner(winner);
}
function getInterval() public view returns (uint256) {
return i_interval;
}
function getEntranceFee() public pure returns (uint256) {
return ENTRANCE_FEE;
}
function getPlayer(uint256 index) public view returns (address) {
return s_players[index];
}
function getWinner() public view returns (address) {
return s_winner;
}
function getLotteryState() public view returns (LotteryState) {
return s_lotteryState;
}
function getNumWords() public pure returns (uint256) {
// function 'pure' instead of 'view' because we return constant variable
return NUM_WORD;
}
function getNumberOfPlayers() public view returns (uint256) {
return s_players.length;
}
function getLatestTimeStamp() public view returns (uint256) {
return s_lastTimeStamp;
}
function getRequestConfirmation() public pure returns (uint256) {
return REQUEST_CONFIRMATION;
}
}
Please help