Skip to main content

Explore the Code

LASR Chess program is composed of some core functions that define how it works. This page explores all these functionalities LASR Chess has to offer, presenting you details about each method available in the lasr-chess.ts file found in the cloned project.

Creating a Program

When you create a new program using LASR, you need to create a class that extends the Program class from @versatus/versatus-javascript, incorporating your specific methods. Below, you find all methods used within LASR Chess:

note

All LASR Chess methods leverage different functions from @versatus/versatus-javascript. Refer to the Methods Reference table for more information on each one.

Create

The create method is required in every program created with LASR, as it's executed during deployment. The create method utilizes parameters specified in the lasrctl deploy command to set up the program. For LASR Chess, this method creates an NFT.

The create method uses parameters provided in the lasrctl deploy command to establish the program's initial conditions and settings. This method sets up the program's metadata and data, and initiates any necessary initial distributions or configurations.

info

It's important to note that metadata in line 5 are the parameters required to create a program with LASR.

Below you find the code block exemplifying the method in LASR Chess followed by a breakdown of the steps taken by the method:

create(computeInputs: IComputeInputs) {
try {
const { transaction } = computeInputs;
const { from, to } = transaction;
const metadata = parseMetadata(computeInputs);
const { initializedSupply, totalSupply, symbol, name } = metadata;
const imgUrl =
"https://pbs.twimg.com/profile_images/1765199894539583488/RUiZn7jT_400x400.jpg";
const methods = "acceptGame, newGame, makeMove, registerUser";
const updateMetadata = updateProgramMetadata({
programAddress: THIS,
metadata: {
symbol,
name,
initializedSupply,
totalSupply,
},
});
const updateData = updateProgramData({
programAddress: THIS,
data: {
type: "chess",
imgUrl,
users: "{}",
methods,
},
});
const distributionInstruction = buildTokenDistribution({
programId: THIS,
initializedSupply,
currentSupply: "0",
to: THIS,
nonFungible: true,
});
const createAndDistributeInstruction = buildCreateInstruction({
from,
initializedSupply,
totalSupply,
programId: THIS,
programOwner: from,
programNamespace: THIS,
distributionInstruction,
});
return new Outputs(computeInputs, [
createAndDistributeInstruction,
updateData,
updateMetadata,
]).toJson();
} catch (e) {
throw e;
}
}
StepLinesDescription
Transaction and Input Parsing3-4It begins by parsing the transaction details and the inputs provided during the deployment command.
Metadata Handling5-6Parses and validates metadata associated with the program (like supply details, symbol, and name), which are crucial for the setup.
Data Setup7-9Constructs the initial data structure for the program, including image URLs, and available methods.
Update Metadata and Data10-27Updates the program metadata and data fields using the program's namespace and addresses.
Distribution and Creation Instructions28-43Handles the initial token distribution based on the initialized and current supply and creates the initial setup instructions for the program. For LASR Chess, it distributes the initialized supply to the program itself.
Output Generation44-48Outputs are generated and returned in JSON format, which includes all the instructions for creating and updating the program.

Register User

The registerUser method enables the addition of new users to LASR Chess, storing their information within the main program. This main program accumulates data from all users and the program itself. The registerUser method will manage and modify the user's NFT during the games. Below you find the code block exemplifying the method in LASR Chess followed by a breakdown of the steps taken by the method:

registerUser(computeInputs: IComputeInputs) {
try {
const txInputs = parseTxInputs(computeInputs);
const { programId } = computeInputs.transaction;
const { username, address } = txInputs;
validate(username, "missing username");
const programAccountData = parseProgramAccountData(computeInputs);
const currUsers = JSON.parse(programAccountData?.users);
validate(currUsers, "unable to parse users");
const addUserToChessMainProgram = updateProgramData({
programAddress: THIS,
data: {
users: validateAndCreateJsonString({
...currUsers,
[address]: username,
}),
},
});
const tokenIds = parseAvailableTokenIds(computeInputs);
const transferInstruction = buildTransferInstruction({
from: programId,
to: address,
tokenAddress: programId,
tokenIds: [tokenIds[0]],
});
return new Outputs(computeInputs, [
addUserToChessMainProgram,
transferInstruction,
]).toJson();
} catch (e) {
throw e;
}
}
StepLinesDescription
Transaction and Input Parsing3-4It begins by parsing the transaction details and the inputs provided during the deployment command.
User Validation5-6Validates the presence of the username provided in the inputs.
Program Account Data Parsing7-8Parses the program account data to get the current list of users.
User Data Validation9Validates the parsed users data to ensure it is correctly formatted and not null.
Update Program Data10-18Updates the program data to include the new user, constructing a JSON string with the updated user list.
Token Transfer Instruction19-25Handles the transfer of a token from the program to the new user, using the first available token ID.
Output Generation26-29Outputs are generated and returned in JSON format, which includes the instructions for adding the user and transferring the token.

New Game

The newGame method creates a new game by updating the user's NFT, adding the new game information to it, starting the match with a new "FEN", the user's address, the wager, and a game state of initialized. Below you find the code block exemplifying the method in LASR Chess followed by a breakdown of the steps taken by the method:

newGame(computeInputs: IComputeInputs) {
try {
const { from } = computeInputs.transaction;
const txInputs = parseTxInputs(computeInputs);
const { wager } = txInputs;
const gameId = generateGameId();
const updateProgramDataInstruction = updateTokenData({
accountAddress: from,
programAddress: THIS,
data: {
[`game-${gameId}-fen`]: NEW_GAME_FEN,
[`game-${gameId}-address1`]: from,
[`game-${gameId}-gameState`]: "initialized",
[`game-${gameId}-wager`]: wager,
},
});
const amountNeededForWager = parseAmountToBigInt(wager ?? "0");
const transferToProgram = buildTransferInstruction({
from: from,
to: THIS,
tokenAddress: VERSE_PROGRAM_ADDRESS,
amount: amountNeededForWager,
});
return new Outputs(computeInputs, [
updateProgramDataInstruction,
transferToProgram,
]).toJson();
} catch (e) {
throw e;
}
}
StepLinesDescription
Transaction Parsing3-4It begins by parsing the transaction details from the inputs provided during the command.
Input Parsing5Parses additional inputs, including the wager for the new game.
Game ID Generation6Generates a unique game ID for the new game using an auxiliary function.
Update Program Data Instruction7-16Constructs the data to update the program, including the game state, player address, and wager, then creates the instruction to update the token data with this information.
Wager Parsing and Transfer Instruction17-23Parses the wager amount to a big integer and constructs the instruction to transfer the wager amount from the player to the program.
Output Generation24-27Outputs are generated and returned in JSON format, which includes the instructions for updating the program data and transferring the wager amount.

Accept Game

The acceptGame method will add a second player to a previously created game, and change its state to in progress. This is the process of adding a second player to the match. Below you find the code block exemplifying the method in LASR Chess followed by a breakdown of the steps taken by the method:

acceptGame(computeInputs: IComputeInputs) {
try {
const { from } = computeInputs.transaction;
const txInputs = parseTxInputs(computeInputs);
const { gameId, address1, wager } = txInputs;
const updateGameStateInstruction = updateTokenData({
accountAddress: address1,
programAddress: THIS,
data: {
[`game-${gameId}-gameState`]: "inProgress",
[`game-${gameId}-address2`]: from,
},
});
const amountNeededForWager = parseAmountToBigInt(wager ?? "0");
const transferToProgram = buildTransferInstruction({
from: from,
to: "this", // Represents the program's address.
tokenAddress: VERSE_PROGRAM_ADDRESS,
amount: amountNeededForWager,
});
return new Outputs(computeInputs, [
updateGameStateInstruction,
transferToProgram,
]).toJson();
} catch (e) {
throw e;
}
}
StepLinesDescription
Transaction Parsing3-4It begins by parsing the transaction details from the inputs provided during the command.
Input Parsing5Parses additional inputs, including the game ID, address of the first player, and the wager for the game.
Update Game State Instruction6-13Constructs the data to update the game state to "inProgress" and adds the second player's address, then creates the instruction to update the token data with this information.
Wager Parsing and Transfer Instruction14-20Parses the wager amount to a big integer and constructs the instruction to transfer the wager amount from the second player to the program.
Output Generation21-24Outputs are generated and returned in JSON format, which includes the instructions for updating the game state and transferring the wager amount.

Make Move

Everytime a player makes a move, being it the first or second player, the makeMove method is called. This method will leverage the chess.js library, using the FEN received to execute a move. After, it will take different actions based on the state of the game. If it is over, it will transfer the wager to the winner. if not, it will keep the game in progress until it finishes. Below you find the code block exemplifying the method in LASR Chess followed by a breakdown of the steps taken by the method:

makeMove(computeInputs: IComputeInputs) {
try {
const { from } = computeInputs.transaction;
const { move, fen, address1, gameId, wager } = parseTxInputs(computeInputs);
validate(move, "missing move");
validate(gameId, "missing gameId");
validate(fen, "missing fen");
const chess = new Chess(fen);
chess.move(move);
const instructions = [];

if (chess.isGameOver()) {
const payoutAmount = parseAmountToBigInt(wager ?? "0") * BigInt(2);
const transferPayoutToWinner = buildTransferInstruction({
from: THIS,
to: from,
tokenAddress: VERSE_PROGRAM_ADDRESS,
amount: payoutAmount,
});
instructions.push(
updateTokenData({
accountAddress: address1,
programAddress: THIS,
data: {
[`game-${gameId}-fen`]: chess.fen(),
[`game-${gameId}-winnerAddress`]: from,
[`game-${gameId}-gameState`]: "finished",
},
}),
transferPayoutToWinner,
);
} else {
instructions.push(
updateTokenData({
accountAddress: address1,
programAddress: THIS,
data: {
[`game-${gameId}-fen`]: chess.fen(),
[`game-${gameId}-gameState`]: "inProgress",
},
}),
);
}

return new Outputs(computeInputs, instructions).toJson();
} catch (e) {
throw e;
}
}
StepLinesDescription
Transaction Parsing3-4It begins by parsing the transaction details from the inputs provided during the command.
Input Parsing and Validation5-7Parses additional inputs, including the move, FEN, address of the first player, game ID, and the wager, and validates their presence.
Chess Move Execution8-10Creates a new chess instance with the provided FEN, makes the move, and prepares for the game state update.
Game Over Check and Instructions12-43Checks if the game is over. If it is, constructs instructions to update the game state to "finished", set the winner's address, and transfer the payout to the winner. If not, constructs instructions to update the game state to "inProgress" with the new FEN.
Output Generation45Outputs are generated and returned in JSON format, which includes the instructions for updating the game state and transferring the payout if the game is over.

Methods Reference

Below you find all @versatus/versatus-javascript methods used in the LASR Chess program, along with descriptions for what each one does:

MethodDescription
buildCreateInstructionConstructs an create instruction for modifying a token or program's properties. This function simplifies the instruction creation by utilizing an CreateInstructionBuilder to incorporate the specified updates into a single instruction.
buildTokenDistributionConstructs a sequence of minting instructions that represent the process of transferring payment tokens to a program and then transferring the minted tokens (or specified token IDs for NFTs) back to the caller. The token distribution is passed into the CreateInstruction. The create instruction creates tokenIds or balance, and then the token distribution instruction (passed into the create instruction) will distribute them to the recipients.
buildTokenUpdateFieldConstructs a ProgramUpdateField object for updating program fields with specified actions such as insert, extend, or remove. This function supports various field types including metadata, data, and status, with specific actions tailored to each field type. It validates the field and action types and constructs the appropriate update action object.
buildTransferInstructionConstructs a transfer instruction for moving tokens from one address to another. This function facilitates specifying the sender and receiver addresses, the token to be transferred, and the amount or specific token IDs to transfer. It supports both fungible and non-fungible tokens through the optional amount and tokenIds parameters.
parseAmountToBigIntConverts a numerical amount (string
parseAvailableTokenIdsExtracts and returns a list of available token IDs from the computeInputs, allowing identification of which tokens are available for operations such as transfers or updates.
parseMetadataReturns the metadata (name, symbol, initializedSupply, and totalSupply) from the computeInputs parameter.
parseProgramAccountDataExtracts and parses the account data of the main program from the computeInputs, allowing access to the current state and data fields of the main program.
parseTxInputsParses the transaction inputs from the computeInputs, extracting and returning relevant details such as the transaction's parameters and additional inputs provided.
updateProgramDataUpdates the specific key from the data of a given program on LASR. This method will replace keys/values that already exist in the main programs data store.
updateProgramMetadataUpdates the metadata for a given program on LASR.
updateTokenDataUpdates the specific key from the data of a given token on LASR. This lets a user / program update a token's data field. In this use-case, the main program uses updateTokenData to update the user's chess NFT with game states.
validateValidates that the values are truthy. If it's truthy, returns the value itself.
validateAndCreateJsonStringValidates that none of the values are undefined and then creates a JSON string from it.