Integrate with Js Frontend

This guide helps you understand built gameplay image can be used in the frontend, and how a prove is generated to be ready to submitted on-chain.

Importing Gameplay Image

No need to do anything for this step

We have provided a boiler plate code in the scaffold project under <project-folder>/frontend/src/gameplay/gameplay.ts

This file will handle the necessary import of gameplay images. Allowing us to run code we have written in Rust from Javascript environment.

Using Spin Games Helper

The package @zkspin/lib provides the essential tools for working with the gameplay and generating proofs.

Prerequisite

npm install @zkspin/lib

Importing

import * from "@zkspin/lib";

Interact with the Gameplay

Initialize a SpinGame Instance

let spin: SpinGame<SpinOPZKProverInput, SpinOPZKProverOutput> = new SpinGame({
        gameplay: new Gameplay(),
        gameplayProver: new SpinOPZKProver(
            {
                operator_url: OPZK_OPERATOR_URL,
            },
            getPlayerNonce,
            getPlayerSignature
        ),
    });

const getPlayerNonce = async () => {
    const player_address = getAccount(config).address;

    if (!player_address) {
        console.error("player address not found");
        throw new Error("player address not found");
    }

    const player_nonce = await readContract(config, {
        abi: SpinOPZKGameContractABI.abi,
        address: GAME_CONTRACT_ADDRESS,
        functionName: "getSubmissionNonce",
        args: [player_address],
    });

    return player_nonce;
};

const getPlayerSignature = async (submissionHash: string) => {
    // get player address

    const player_address = getAccount(config).address;

    if (!player_address) {
        console.error("player address not found");
        throw new Error("player address not found");
    }

    const player_signature = await signMessage(config, {
        message: {
            raw: ethers.getBytes(submissionHash),
        },
    });

    return { player_address, player_signature };
};

For local development, obtain OPERATOR_URL by deploy a copy locally Deploy locally for dev

Start a New Gameplay

await spin.newGame({
    initialStates: [total_steps, current_position],
});

Get Current Game State

const s: BigUint64Array = spin.getCurrentGameState();
console.log(s)
// [10, 1]

Generate a Prove for Submission

const submissionData = await spin.generateSubmission({
    initialState: [
        10 // total_steps
        1, // current_position
    ],
    playerActions: [0, 1, 1, 1], 
    metaData: {
        game_id: BigInt(123),
    },
});

The submissionData will be used to interact with the blockchain to prove and save the states.

Trouble Shooting

Handling Changes In Gameplay File Path

Our scaffold project after running zkspin init ... provides a working example, but the frontend assumes the position of the gameplay/export folder relatively.

For whatever reason, if the path to the export/ folder changes, you can adjust this in gameplay.ts file.

// frontend/src/gameplay/gameplay.ts
import { GameplayAbstract } from "@zkspin/lib";

import {
    default as init,
    initialize_game,
    step as _step,
    get_game_state,
} from "../../../gameplay/export/js/esm";
//    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ change this path

Last updated