An Intro To Near Dapp Development With Rust, WASM, Parcel and React -Part 2.

Panasthetik
Published in
11 min readMar 15, 2022

--

This article introduces existing Web3 developers to the Near Protocol with a simple, functional, start-to-finish example in three parts.

For those who are just joining us, feel free to look over Part 1 of this tutorial here to get up to speed!

The entire code repository for Part 1 and Part 2 of this tutorial can be found here.

Last week, we started our developer journey on the Near blockchain by covering some of the foundational prerequisites for creating a smart contract to deploy on Near Testnet, and were able to set up our Near wallet and Rust environment accordingly. We then finished Part 1 by doing a preliminary build of our contract to WASM using Cargo and the “build.sh” bash script inside our “contract” directory.

For today’s session, we will continue our project by first writing some Rust unit tests to run against our smart contract. We will then create a deployment sub-account in Near-CLI, deploy our contract to Near Testnet, and actually be able to interact with it in the developer console before we proceed to our React front-end integration in Part 3.

So let’s continue!

Writing Rust unit tests.

First, let’s take a second look at our ‘Event’ contract, and see which functions we need to test against in our Rust unit tests. If we open up “lib.rs” again inside our “src” folder, we see the following as written last time:

Since we know that this contract needs to 1) allow users signed in with their Near wallet to create an event, and 2) give users the ability to vote on the listed events — we can immediately designate a few functions to target with our unit tests.

The easiest way to do this in Rust is to first identify the two functions that initiate contract state change:

  1. add_event()

2. add_vote()

We will examine “add_event” and its associated functions first —

Lines 43–55 (in “lib.rs” above):

The “add event” function is the primary function in our contract — it opens up a project in the events listing with Title, Description, and suggested Budget. Once we call the “event” struct (which we declared our “models.rs” file) with “Event::new”, we are able to create a new event on the Near Blockchain that will later be referenced by our front end and displayed on the home page of our Dapp.

To verify that an event was added on-chain, we also have two other helper functions that first display the list of events…

// lines 57-61 (in “lib.rs” above)pub fn list_events()...

…and then also track the count of total events/projects within our contract…

// lines 63-65 (in “lib.rs” above)pub fn event_count()...

What we need to do is write a unit test to verify that this overall function works as expected, and therefore let’s add the following to the bottom of the “lib.rs” file:

IMPORTANT: the file above should be pasted outside the main “Contract” implementation braces (after line 82 in “lib.rs”). If you include the test code in the main Contract body, you will get a compilation error in Cargo that tells you it’s out of scope!!

Important things to consider in our test code above.

One of the awesome things about doing our smart contracts in Rust, is that we can also write our unit tests in Rust and run them in Cargo, leveraging the incredible compiler and error-handling capabilities straight away before we even think about doing our final deployment build to WASM.

Looking at the unit test we started with above, which tests against the “add_event” function, it becomes obvious just how readable and understandable this system is, compared to what might be a much more “verbose” testing environment in JavaScript, for example (i.e. Mocha).

So for the “add_event” function called from our main Contract:

contract.add_event()

We set up a test simulation environment (also called a “context” in our Near SDK) to be able to imagine a scenario where “alice” represents a Near account (see “alice.testnet” in the set-up code), interacts with a fresh contract instance (“Contract::new”)and then creates a new event within our “create_project” unit test.

Another related Contract function called in this overall test is assigned to the “result” variable as follows:

let result = contract.event_count()

What this does is verify our result for “add_event()” — it makes sure that a new event was indeed created in our test, and that the total events is then “1”:

assert_eq!(result, 1);

Great! So why not run this test and see if we pass, just initiating a context with Near SDK and having Cargo do the rest?

In your terminal, in the “contract” folder, execute the test script:

bash ./test.sh

Just like before during our preliminary build, Cargo will assemble our crates and dependencies, compile our code, create the “context” simulation environment from Near SDK, and run our unit test with a fresh Contract instance as it would be deployed on a real blockchain. Once this process is completed, you should see the following in your VSCode terminal:

Awesome, our first Rust unit test passed and it indicates that in the simulated “context” environment, a new event was created!

The next function we will build a unit test for is the “add_vote()” function. This is represented here in our main contract code:

Lines 67–75 (above, in “lib.rs”):

This function takes an event, makes it “mutable” so it can be modified with “votes” and executes the process of adding this information to the event mapped by event ID (“id: usize”). A “voter” here is anyone who is signed in to the Dapp with their Near wallet, which automatically gives them access to this function.

For additional information about Near accounts (“predecessor,” “signer” and “current”) please consult the official Near SDK documentation here as it is well beyond the scope of this article.

There is also a “helper” function at the end of the main contract (after add_vote) called “get_total_votes()” that helps confirm that a vote was added, and that we will also reference for our unit test:

Lines 77–81 (above, in “lib.rs”):

For our add_voter unit test below, we will create a very similar structure to what we did for our add_project unit test above. We will add the code below to the end of our unit tests at the bottom of “lib.rs”, as a second test block inside the “mod tests” braces {} (I will recap the entire “lib.rs” file shortly, so all the closures are clear):

Here, we do the same “context” building and account initialization for “alice” and “Contract::new” that we did for the previous test. In this case though, we added the code here instead…

contract.add_vote(0)

…where “0” is the event ID, and then…

let result = contract.get_total_votes(0)assert_eq!(result, 1)

One vote being exactly correct given that “alice” has both created a project here (project ID “0” in the events list), and cast a vote as well (“1” vote for project ID “0”).

Wrapping up unit tests in Cargo.

For now we will only include these two Rust unit tests, and if everything is correct we should have the following as our complete “lib.rs” file ready to run with both tests:

In our VSCode terminal inside the “contract” folder, let’s run our “test.sh” script again as follows:

bash ./test.sh

After a brief compilation period like always, we should now see both unit tests passing on the console like below:

Our Rust unit tests have passed, and we are ready to do a final build of our contract to WASM and then deploy it to the Near Testnet!

Setting up our WASM file before deployment and preparing a Near Testnet contract sub-account.

To briefly review what we did at the beginning of Part 1, we can recall that first we created a Near Testnet account at “wallet.testnet.near” as shown in the browser:

For the remainder of this lesson, we will spend most of our time in the VSCode terminal and the Near CLI. So first, let’s repeat our account sign-in process that we did in Part 1:

near login

With that, we go though the pop-up transaction approval in our browser until we get something similar to this again back in the VSCode terminal:

Next, we need to do something totally new — we need to assign a sub-account as a placeholder to “contain” our smart contract deployment on Near before we upload it.

Usually, it is a best practice to make this sub-account an address that derives from the main Testnet wallet you use, like so:

near-starter-dapp.<your account name>.testnet

…or, if our main account is “myaccount”:

near-starter-dapp.myaccount.testnet

So in the terminal using “myaccount.testnet” as our example base wallet address (yours will be different but should follow the same structure), we need to enter the following, paying close attention to the syntax here for Near CLI:

near create-account near-starter-dapp.myaccount.testnet --masterAccount myaccount.testnet

As a response, in the terminal you should then see this confirmation that your sub-account was created:

Saving key to '/Users/<yourusername>/.near-credentials/testnet/near-starter-dapp.myaccount.testnet.json'Account near-starter-dapp.myaccount.testnet for network "testnet" was created.

The keypair for this sub-account is stored in a .json file as part of your “.near-credentials” directory on your local machine, and now we are ready to prepare our contract for deployment at this sub-account address on Near.

Back in the “contract” folder of our project, we will now run “build.sh” one last time:

bash ./build.sh

Once this build is completed, check in the “res” directory inside our main “contract” folder. There should be a file called: “near_starter_dapp.wasm

Again in the terminal, let’s run the code below as our deploy script — this will actually start the deployment process to our sub-account:

near deploy --accountId near-starter-dapp.myaccount.testnet --wasmFile res/near_starter_dapp.wasm

If all goes successfully, you should see this confirmation in the console that your Near testnet smart contract is now deployed:

Starting deployment. Account id: near-starter-dapp.myaccount.testnet, node: https://rpc.testnet.near.org, helper: https://helper.testnet.near.org, file: res/near_starter_dapp.wasmTransaction Id 3fqzA9vpuKSSsrBry9jE2k2FjoKFZBCdwPU38fTcPVkTTo see the transaction in the transaction explorer, please open this url in your browserhttps://explorer.testnet.near.org/transactions/3fqzA9vpuKSSsrBry9jE2k2FjoKFZBCdwPU38fTcPVkT

PLEASE NOTE — your transaction ID will be different from the above!

I hope your contract deployed successfully — I know this process has been a long road, but I think once you have actually deployed on Near, you can agree that not only is this process pretty painless, it is very developer-friendly in its approach.

Smart contract interaction with the NEAR-CLI: Let’s talk to our contract!

Now that we have our contract on the Near Testnet, we can do the kind of contract calls many of you have already done via RPC on Ethereum or Solana. Here is an example of a contract call that actually creates a new event listing in our smart contract, just like in our unit tests. If we paste this exactly in our console:

near call near-starter-dapp.myaccount.testnet add_event '{"title": "New Contemporary Art Show", "estimated_budget": 300, "description":"Lots of amazing artists from all over the world, from the fields of painting, sculpture and photography"}' --accountId myaccount.testnet

We will get the following result:

Scheduling a call: near-starter-dapp.myaccount.testnet.add_event({"title": "New Contemporary Art Show", "estimated_budget": 300, "description":"Lots of amazing artists from all over the world, from the fields of painting, sculpture and photography"})Doing account.functionCall()Receipt: 6Dm3ez8cYjB5xnpqQiJPVREk9zh6MJGeXo8pjKw58ksPLog [near-starter-dapp.myaccount.testnet]: Added a new event!Transaction Id 3dXoVaUV68Nm5kj1qS4A1cXavPJbsc2nwewBVtAk3BSjTo see the transaction in the transaction explorer, please open this url in your browserhttps://explorer.testnet.near.org/transactions/3dXoVaUV68Nm5kj1qS4A1cXavPJbsc2nwewBVtAk3BSj

Wow! It worked, and our contract now has been deployed and it even has an event added already.

Now, how can we confirm that the contract really contains our “contemporary art” event out there on Near? Sure we can just check the explorer URL as indicated in the terminal above. But what about just from the CLI?

Well, that’s even easier — we will just do a couple more contract calls, starting with:

near call near-starter-dapp.myaccount.testnet list_events --accountId myaccount.testnet

And when we run it, we will get this in return:

Scheduling a call: near-starter-dapp.myaccount.testnet.list_events()
Doing account.functionCall()
Transaction Id ASzDxXDHqVT82gs5kM3wwfcezJ75Wk9NGCizvvY7f5Ci
To see the transaction in the transaction explorer, please open this url in your browser
https://explorer.testnet.near.org/transactions/ASzDxXDHqVT82gs5kM3wwfcezJ75Wk9NGCizvvY7f5Ci
[
{
id: 0,
creator: 'myaccount.testnet',
created_at: 1646505825772610600,
title: 'New Contemporary Art Show',
estimated_budget: 300,
total_votes: 0,
description: 'Lots of amazing artists from all over the world, from the fields of painting, sculpture and photography',
votes: []
},
]

If we wanted to repeat this same process to add a vote to our contract for the event (at project ID “0”), we can just run this:

near call near-starter-dapp.myaccount.testnet add_vote '{"id":0}' --accountId myaccount.testnet

Then, to verify our votes we can repeat the above “list_events” call in the console and we should finally have this result:

Scheduling a call: near-starter-dapp.myaccount.testnet.list_events()
Doing account.functionCall()
Transaction Id ASzDxXDHqVT82gs5kM3wwfcezJ75Wk9NGCizvvY7f5Ci
To see the transaction in the transaction explorer, please open this url in your browser
https://explorer.testnet.near.org/transactions/ASzDxXDHqVT82gs5kM3wwfcezJ75Wk9NGCizvvY7f5Ci
[
{
id: 0,
creator: 'myaccount.testnet',
created_at: 1646505825772610600,
title: 'New Contemporary Art Show',
estimated_budget: 300,
total_votes: 1,
description: 'Lots of amazing artists from all over the world, from the fields of painting, sculpture and photography',
votes: [myaccount.testnet]
},
]

Finishing up this section, next steps and what we will do in Part 3.

If you’re still here, I want to extend a huge congratulations for deploying your first smart contract on Near, doing the Rust unit tests, setting up your Near developer environment, doing some simple contract calls, and making it this far generally!

For next week’s session, we will tie up a few “loose ends” from Part 2 by illustrating how to quickly “upgrade” your contract by clearing out the sub-address, recreating it in Near CLI, rebuilding the WASM file, and re-deploying once your Rust contract has been changed/edited.

For the third and final part of this tutorial, we will be switching gears quite a bit by moving over to the React / JavaScript world and connecting our smart contract to a simple but elegant front-end template! This template is based on an existing design, although I have simplified it immensely by using the latest Parcel exclusively as the bundler, transpiler, and final dev server.

As we will ultimately see, it should be easy to make this project your main starter kit for Near development in the future.

Thanks again for reading, and see you next time… — Panasthetik

Resources:

Join Coinmonks Telegram Channel and Youtube Channel learn about crypto trading and investing

Also, Read

--

--

Panasthetik
Coinmonks

Web3 Developer and Researcher — Blockchain, Generative Art, Decentralized Identity.