“In the game of innovation, like in sports, every function plays a crucial role; it’s not just about having star players, but how every part works together seamlessly.”
OverviewWelcome to the digital arena, where the players are smart contracts, and the game is as strategic as any sport you’ve ever seen. Today, we’re diving into the playbook (functions) of our MVP, RandomTeamSelector.sol, dissecting its moves and strategies to understand how it scores points in the blockchain league. If you missed part 1, you can read it here.
Imagine a football coach picking players for a dream team, but instead of athletes, we’re drafting functions, each with a unique role that contributes to the victory of our smart contract. From the kickoff with requestRandomTeamNames to the final whistle with chooseTeam, we’ll explore how each function interacts, strategizes, and executes plays that would make even the most seasoned sports analysts take notes.
So, lace up your cleats, don your jerseys, and let’s get ready to rumble through the code, play by play, ensuring you understand the Xs and Os of our smart contract’s game plan.
The Draft Pick: Initiating the Random Team SelectionIn the grand league of smart contracts, the requestRandomTeamNames function is the first-round draft pick, setting the stage for a fair and unpredictable selection process. It’s the crucial coin toss, the unbiased referee, ensuring that every team manager gets a shot at glory in the blockchain championship.
Here’s the play-by-play:
Let’s break down each line of the requestRandomTeamNames function for clarity:
function requestRandomTeamNames(This line declares the function requestRandomTeamNames, which takes one parameter: the address of the manager. It’s a public function, meaning it can be called by anyone, but with the onlyOwner modifier, it restricts access so only the contract owner can execute it. The function is set to return a uint256 variable named requestId.
if (s_managerSelections[manager].teamOptions.length > 0) {Here, we’re checking if the manager has already selected a team. If the teamOptions array for this manager is not empty (length > 0), the function will stop and revert the transaction with a custom error RandomTeamSelector__AlreadySelected.
requestId = s_vrfCoordinator.requestRandomWords(This line assigns a new requestId by calling the requestRandomWords function from the s_vrfCoordinator, which is a reference to a Chainlink VRF Coordinator contract that provides secure and verifiable randomness. More specifically, you can see the requestRandomWords function directly in VRFCoordinatorV2.5.sol . It's in the lib folder
/lib/chainlink/contracts/src/v0.8/vrf/dev/VRFCoordinatorV2_5.sol
VRFV2PlusClient.RandomWordsRequest({This section is constructing a RandomWordsRequest struct with various parameters:
This line maps the requestId to the manager’s address, storing the association in a state variable.
s_managerSelections[manager].selectedTeam = SELECTION_ONGOING;Here, the function sets the selectedTeam status to SELECTION_ONGOING for the manager, indicating that the selection process is currently underway.
emit SelectionMade(requestId, manager);Finally, the function emits an event SelectionMade with the requestId and manager’s address, signaling to the blockchain that a selection process has been initiated.
This function sets up the initial request for randomness, which is the first step in the process of selecting a random team. It ensures that the selection is fair and hasn’t been tampered with by using a verifiable source of randomness.
The Playmaker: fulfillRandomWords FunctionIn the playbook of our smart contract, the fulfillRandomWords function is the playmaker, the one who receives the pass (randomness) and makes the strategic moves (assigns team options). Here’s how it orchestrates the play:
This function is the core of the selection process, taking the randomness provided by the VRF and translating it into actionable choices for the manager. It’s the moment when the crowd holds its breath as the playmaker weaves through the opposition, setting up for a score.
Let’s take a deeper look at the code.
function fulfillRandomWords(This function is an internal callback that is called by the VRF Coordinator when randomness is delivered. It overrides a function from the inherited VRFConsumerBaseV2Plus contract. The parameters are the ID of the request for randomness and the array of random numbers provided by the VRF.
address manager = s_requestToManager[requestId];This line retrieves the manager’s address that is associated with the given requestId from a mapping called s_requestToManager.
uint256[] memory teamOptions = new uint256;Here, a new temporary array called teamOptions is created in memory to store the team IDs that will be generated from the random words.
for (uint256 i = 0; i < numWords; i++) {This loop goes through each of the random numbers provided, uses modulo operation to ensure each number is within the range of 1 to 40, and assigns the result to the teamOptions array.
s_managerSelections[manager] = ManagerSelection({The s_managerSelections mapping is updated for the manager with a new ManagerSelection struct, which includes the teamOptions array and sets the selectedTeam status to SELECTION_ONGOING.
emit SelectionRevealed(requestId, teamOptions);Finally, the SelectionRevealed event is emitted, which includes the requestId and the teamOptions array, indicating that the selection options have been successfully generated and revealed.
Let’s proceed with the next function, teamName, which retrieves the name of the team chosen by a player.
The Selector: teamName FunctionIn the arena of our smart contract, the teamName function is like the referee announcing the chosen player to the eager crowd. It’s the moment of truth where the selection is revealed and the anticipation turns into reality.
Play by Play:
Line by Line Code Breakdown:
function teamName(address player) public view returns (string memory) {This line declares the function teamName, which is a public function that anyone can call. It’s a view function, meaning it doesn’t modify the state on the blockchain. It takes one parameter, the address of the player, and returns a string representing the name of the team.
ManagerSelection storage selection = s_managerSelections[player];Here, the function retrieves the ManagerSelection struct from the s_managerSelections mapping for the given player address and stores it in a local variable selection.
if (selection.selectedTeam == 0) {This line checks if the selectedTeam property of the selection is 0, which would indicate that no selection has been made. If that’s the case, it reverts the transaction with a custom error RandomTeamSelector__SelectionNotMade.
return getTeamName(selection.selectedTeam);Finally, the function returns the name of the selected team by calling another function getTeamName and passing the selectedTeam ID from the selection.
Moving on to the next function, let’s explore getTeamOptions, which retrieves all the team options available for a manager.
The Strategist: getTeamOptions FunctionIn the tactical game of our smart contract, the getTeamOptions function is akin to a coach reviewing the playbook. It’s where the manager surveys all possible moves before making the crucial decision.
Play by Play:
Line by Line Code Breakdown:
function getTeamOptions(This line declares the function getTeamOptions, which is publicly accessible and doesn’t alter the state on the blockchain. It takes the manager’s address as a parameter and returns an array of unsigned integers, which represent the team IDs.
ManagerSelection storage selection = s_managerSelections[manager];Here, the function retrieves the ManagerSelection struct associated with the manager’s address from the s_managerSelections mapping.
if (selection.selectedTeam != SELECTION_ONGOING) {This line checks if the selection process is not ongoing (meaning either not started or already completed). If so, it reverts the transaction with the error RandomTeamSelector__NoSelectionOptionsAvailable.
return selection.teamOptions;Finally, the function returns the teamOptions array from the selection, which contains the IDs of the available teams.
Let’s move on to the chooseTeam function, which allows a manager to finalize their team selection.
The Decision Maker: chooseTeam FunctionIn the strategic game of our smart contract, the chooseTeam function is like the final whistle that seals the fate of the match. It’s where the manager makes the definitive call, locking in their team choice.
Play by Play:
Line by Line Code Breakdown:
function chooseTeam(uint256 teamId) public {This line declares the function chooseTeam, which is a public function that allows managers to choose a team. It takes one parameter, teamId, which is the ID of the team being chosen.
ManagerSelection storage selection = s_managerSelections[msg.sender];Here, the function retrieves the ManagerSelection struct for the manager calling the function (indicated by msg.sender) from the s_managerSelections mapping.
require(This line checks that the selection process is currently ongoing for the manager. If not, it will revert the transaction with an error message.
bool validChoice = false;The function then iterates through the teamOptions array to check if the teamId provided is a valid option. If it finds a match, it sets validChoice to true.
if (!validChoice) {If no valid option is found (validChoice remains false), the function reverts the transaction with the error RandomTeamSelector__InvalidTeamChoice.
selection.selectedTeam = teamId;Once a valid choice is confirmed, the function sets the selectedTeam to the chosen teamId and emits the TeamChosen event, indicating that the manager has made their selection.
Smart Contract Function Flow SummaryThe RandomTeamSelector.sol smart contract orchestrates a series of functions to manage the process of random team selection. Here’s a summary of the flow:
Each function plays a critical role in ensuring the integrity and fairness of the random team selection process within the smart contract environment. The functions work together to manage the selection from initiation to finalization, providing transparency and control to the contract owner and participating managers.
And this is where I stand right now on the project. I know that I’ll have to do some refactoring with some of these functions, but I’ll likely leave that until after I write some tests and possibly after some interaction with a front-end.
Building Randomness with Chainlink VRF: Part 2 was originally published in Coinmonks on Medium, where people are continuing the conversation by highlighting and responding to this story.
All Rights Reserved. Copyright , Central Coast Communications, Inc.