Now we can start playing the game. Every move is a call to the contract and triggers a change in the state of the contract. The interaction between the web application and the contract occurs at this stage.
Calling the contract requires the following steps:
Create a new contract instance via the .next()
method of the current instance. Update the state of the new instance to the latest.
Add a transaction builder to the move()
method of the TicTacToe
contract through the bindTxBuilder
method, which builds the calling transaction.
Finally call the methods
public method on the contract instance to send the transaction to call the contract. Every public method xxx
has a function of the same name under contractInstance.methods.xxx
. It takes the same parameters, plus an MethodCallOptions
.
If the public method has a signature parameter, a callback function is required to return the signature. The Signer
connected to the contract will use the default private key to sign, and the signature will be returned through the parameter sigResps
of the callback function. Use findSig()
to find the signature associated with a public key.
Through pubKeyOrAddrToSign
in MethodCallOptions
, you can specify which address/public key to sign against.
const { tx: callTx } = await p2pkh.methods.unlock( (sigResponses: SignatureResponse[]) => findSig(sigResponses, $publickey), $publickey, { pubKeyOrAddrToSign: $publickey.toAddress() } as MethodCallOptions<P2PKH> );
The code implementation of the above steps:
// 1. create nextInstance const current = props.contract as TicTacToe; const nextInstance = current.next(); // convert latest game data to contract state with Utils.toContractState and update nextInstance state Object.assign(nextInstance, Utils.toContractState(latestGameData)); // 2. bind a tx builder for move current.bindTxBuilder('move', async (current: SmartContract, options: MethodCallOptions<SmartContract>, n: bigint, sig: Sig) => { ... return Promise.resolve({ tx: unsignedTx, atInputIndex: 0, nexts: [ { instance: nextInstance, atOutputIndex: 0, balance: initBalance } ] }) } // 3. call contract.methods.move(...) to broadcast transaction const {tx, next} = await current.methods.move( BigInt(i), (sigResponses: SignatureResponse[]) => findSig(sigResponses, $publickey) ); // 4. save latest contract instance props.setContract(next?.instance)
So far, we have completed the interaction between the TicTacToe
contract and the web frond-end. Every move will prompt the player to sign and submit a transaction on the blockchain.