Chainlink VRF2 – How to Automate Raffle Games with Chainlink VRF and Automation

chainlinkchainlink-automationchainlink-vrfgamessolidity

i am writing a raffle game contract, I integrated Chainlink keepers to check how much time has passed and pick the winner to move on to next round.

    function checkUpkeep(
        bytes calldata 
    )
        external
        view
        override
        returns (bool upkeepNeeded, bytes memory)
    {
        upkeepNeeded = (!isPaused() && !awaitingRandomness && block.timestamp>=raffle[round.current()].endTime);
    }

    function performUpkeep(bytes calldata) external override {
       
        if (!isPaused() && !awaitingRandomness && block.timestamp>=raffle[round.current()].endTime) {
            pickWinner();
        }
    }

Then, to get a secure random value I integrated with VRF. When the pickWinner() function is called, It calls the requestRandomness function then just leaves the pickWinner() function.

function pickWinner() internal {
  
        if(raffle[round.current()].playerCount == 0){
            finishRound(address(0));
        } else if(raffle[round.current()].playerCount == 1){
            token.transfer(address(raffle[round.current()].players[0]), calculatePrize()); 
            token.transfer(address(treasuryAddress), getBalance());
            finishRound(address(raffle[round.current()].players[0]));
        } else{
               awaitingRandomness=true;
               uint256 requestId = requestRandomness(callbackGasLimit,requestConfirmations,numWords);

               randomnessIds[round.current()] = requestId;
               raffle[round.current()].status = GameStatus.PICKING_WINNER;
        }
        
    }

After this point, everything stops until fulfillRandomWords() function of VRFV2WrapperConsumerBase is called back. Inside that function, I get the randomWord and use it as index for array of addresses that I keep for the current raffle round and chooses the winner. Then, starts the next round.

function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal override {

        uint256 randomIndex = randomWords[0] % raffle[round.current()].players.length;
        address winner = raffle[round.current()].players[randomIndex];

        Game storage currentGameOfPlayer = players[winner][round.current()];
        currentGameOfPlayer.status = PlayerStatus.WIN;
        currentGameOfPlayer.earned = calculatePrize();
        currentGameOfPlayer.updatedAt = block.timestamp;
         
        raffle[round.current()].status = GameStatus.FINISHED;
        raffle[round.current()].winner = winner;
        token.transfer(winner, calculatePrize()); 
        token.transfer(address(treasuryAddress), getBalance());
        
        finishRound(winner);
    }

My problem is that fulfillRandomWords() function gets stuck because of gas limit. Also, even if it wasn't stuck, since all this automated logic is dependent on fulfillRandomWords() function being called, I am not sure if it is usable.

My question is:

-Is VRF service reliable enough to make this logic dependent on fulfillRandomWords() being called?

-Do you have any suggestions or examples for implementing this game? Maybe using another service or a different logic?

Best Answer

As a disclaimer, I am working at Gelato, which is Chainlink Keepers's competitor with Gelato Automate.

It is true that the callback gas limit can be very restrictive depending on your business logic.

In this case, I would decouple the fullFillRandomess() from the rest of the execution creating another Keeper that checks whether the random number has been delivered.

Something like this:

  • Automate/Keeper to launch VRF
  • VRF call back (update flag--> VRF available)
  • Automate/keeper to update winners, etc once VRF is available

I don't know how CL Keepers can create two Keepers in the same contract. Maybe someone else in the community can help us with that. Here you can find the Gelato Automate docs, where you can see that using the same contract as a resolver you can create n-keepers in the same contract: https://docs.gelato.network/developer-services/automate

And here is also an article on how to integrate Gelato with different VRF providers. https://medium.com/coinmonks/schedule-randomness-with-gelato-and-witnet-api3-chainlink-vrf-1ebc0aac37d

As in your use case, you have to decouple the Vrf fulfillment from the rest of the execution, you could also have a look into the part related to Witnet.

Hope it helps and you can build your raffle!

Related Topic