In the first part of our tutorial, we have seen how to interact with the VM state of our sidechain Deku-P.
The goal of this article is to create a front web application using this state!
1. Read and do the first blog article
2. Having an up & running Deku-P Cluster (explained in the first blog article)
3. Having a working front application
We assume you have front web development skills or experiences. Hence, we will only focus on the mandatory tasks to interact with Deku-P from the outside world.
You already interacted with the VM state using deku-cli in the previous blog post. On a front web application, we have to do some actions before submitting:
1. Retrieve the actual state of the Deku VM
2. Retrieve the current height
3. Create the operation we want to submit
4. Submit the operation
We will explain in detail how to perform each of these actions.
A naive working front
Before going deeper into how to create and submit our operation, we create a simple front web with several buttons, one per action:
- One button to mint cookies
- One button to mint cursor
- One button to mint grandma
We will also display several useful information saved in our state, like:
- Current amount of cookies
- Current “cookies per second”
- Current amount of cursors
- Current amount of grandma
- Next cost for Cursor
- Next cost for Grandma
Here is the current front we have on Decookies:
I think you guessed it:
- if we click on the cookie, it mints a cookie.
- If we click on the cursor, it will mint a cursor.
- And if we click on the beautiful grandma… It will mint a Grandma!
Of course, you need sufficient funds to buy Cursors, Grandmas and the other buildings.
Defining our state
The first thing to do is to have an equivalent of the State we defined in our VM.
Remember how it is in the end of the first blog article:
Let’s define the exact same on our front web application.
In our case, we decided to use the reducer pattern. Hence, the cookieBaker type will be wrapped in a state type, containing other useful information.
Minting your first cookie
Now that we have defined our state and created our reducer to perform the correct actions regarding the clicked button, our reducer kinda looks like:
You can have a look at the defined actions, this is not the purpose of this article, and I won’t explain the details. You are free not to use the reducer pattern.
For security and gameplay purposes, we are not going to ask the private key of the gamer. Hence, we generate a new one, based on the chosen nickname.
This is where we are going to use the Beacon SDK. We will sign the user nickname, then generate a Key pair (public and private key) from this signed nickname.
1. Because using Beacon SDK to sign every transaction, would make the user signing every transaction to mint a cookie causing the gameplay to be far away from a cookie-clicker game.
2. Because the VM-state of Deku is public we cannot store anything important in it (like your random secret or a way to retrieve it), moreover, in Deku, the state is saved for a public address. Hence, we need to remember who you are.
Using the Beacon SDK to sign your nickname, then using this signed-nickname as a seed to generate a KeyPair, is the best/quickest way to do so.
As soon as the user has fulfilled the nickname and node URI fields, we can use the Beacon SDK to sign the nickname when you click on the Beacon Wallet button.
We don’t only store the cookieBaker in our state. We also dispatch some other useful information for our case (the generated keyPair and the Wallet)
Mint your first cookie!
Let’s define the business function!
We want to make the VM state to be successfully updated when our user clicks on the cookie. The action to perform is to add one cookie to the current amount of this user.
This function will create the correct payload to submit our operation with. Here is its signature:
vmOperation is our type wrapping the “cookie” payload of the first tutorial:
On the Deku side, every payload must be signed.
We initialize an InMemorySigner from taquito with the keyPair we have generated before. The first step is to create a new one, given our private key:
Submit Operation using the Deku Toolkit (recommended)
Using the Deku toolkit is the easiest way to submit operations to Deku. It is available here.
There are four steps:
1. Create a InMemorySigner
2. Create a DekuSigner from the previous InMemorySigner
3. Create a DekuToolkit with the DekuSigner and the Node URI
4. Submit the operation
If you choose to use the Deku Toolkit, you can directly go to the “Voilà” section. Because you already successfully submitted your first operation to Deku, and can get your first cookie!
Submit operation using fetch (not recommended)
Construct the payload
The payload we must provide to Deku is a bit complex, here is its structure in a JSON format:
I start by explaining the operation nested object:
- level is the block-level you want your operation to be included (must be +15 actual blockchain level or -15) (see level section)
- nonce a random integer value lower than maximum int64 in OCaml (see nonce section)
- source is the public address we created in the first blog article using deku-cli create-wallet command
- content is a polymorphic array, whose first element is always the string "Vm_transaction" and second element is a JSON record where operation is the payload needed by our application (a simple string in our case). This is the last argument of deku-cli create-custom-transaction command in the previous blog post. In our case, the correct payload for this action is “cookie” which is a valid JSON object since it is a string.
To generate such a payload from our web front application, we can do something like:
On the Deku side, the nonce is just a random integer, we can easily do the same on our web front application using the following function:
This value must come from the Deku-P side. Hence, we need to fetch it from our Deku cluster!
Once you have successfully run your Deku Cluster (see in the first article on “How to run Deku cluster”)
You can simply copy/paste the following code, which requests the good endpoint:
And finally, we sign the operation, to get its signature:
Submit the operation
Next and final step: submit this operation to the /api/v1/operations endpoint of one of our Deku nodes!
You can access the Node URI on localhost:8080 and perform the following:
It returns the hash of the operation. This can be useful in some cases (not our cookie clicker game) to fetch another endpoint of Deku to get the list of included operations. Fetching it, will allow you to ensure your operation has been included!
You successfully submitted your first operation to Deku!!!!
Now, we can fetch the actual state of our VM to verify it has been successfully modified!
This is the endpoint we are going to fetch to get the famous cookieBaker we have defined!
To do so, you can simply copy/paste the following code snippet, which is simply getting data from one of the Deku nodes, and parsing it to only return the state corresponding to the user address:
And call it wherever it makes sense in your application. In the near future, you will be able to fetch directly on /api/v1/state/unix/tz1xxxx and avoid doing this parsing!
From now, we already were able to:
- Call several HTTP endpoints of our Deku nodes
- Update our VM state by minting a cookie
- Retrieve the updated state
Mint your first cursor
Since we already provide the action (payload of deku-cli) we can easily mint our first cursor now, by defining the correct action in our reducer and simply calling the mint function with a different action!
The mint function is simply wrapping the correct payload we give it, to create the corresponding operation record type!
🎉 Voilà!! 👏
You guessed it, it will be easy to add the action to mint a Grandma!
We successfully created a front web application interacting with the VM State we had defined in the first blog article!
Here is the complete mint function without the Deku toolkit:
You can find the whole code of our front application directly on our GitHub!
If you want to know more about Marigold, please follow us on social media (Twitter, Reddit, Linkedin)!