How to Build, Deploy and Test a Waves RIDE dApp

Ilya Smagin
Jul 11, 2019 · 8 min read

In this article I will show how to write simple decentralised application(dApp) and run it on Waves node. We’ll take a look at the required development tools and good practices as well as a working example.

Development of a dApp is not(and should not be) radically different from development of a regular application: writing the code, writing automated tests, launching a dApp and testing it manually are the necessary steps.

1. Tooling

  1. docker for running a node and Waves Explorer
    Technically, this step is not necessary. You can use existing testnet / experimental-network, but unless you have your own node, your testing cycle will be dramatically slower because:
    - You might(most likely you will) constantly need new accounts with test tokens. The testnet faucet can give you just 10 WAVES every~10 minutes.
    - Average block time on testnet is 1 minute, while on private node it’s just 10 seconds. This can be critical if your script requires several blocks confirmations.
    - Public testnet nodes can have agressive caching turned on
    - Public testnet nodes may be under maintenance

For the sake of simplicity, in this example we’ll assume you’re working with a private node.

2. surfboard command line tool:`nodejs`

npm install -g @waves/surfboard

3. Visual Studio Code plugin waves-ride :

This step is not neccessary. If you are not a fan of IDEs and prefer plaintext editors — it’s not a problem, all the must-have tools are purely command-line utils. If you usevim — please checkout vim-ride plugin.

4. Waves Keeper browser extension:

https://wavesplatform.com/products-keeper

All set!

2. Run a private node & explorer

  1. Run a node:
docker run -d -p 6869:6869 wavesplatform/waves-private-node

Observe the node is running through REST API at http://localhost:6869:

swagger REST API interface for the node

2. Run an instance of Waves Explorer:

docker run -d -e API_NODE_URL=http://localhost:6869 -e NODE_LIST=http://localhost:6869 -p 3000:8080 wavesplatform/explorer

Open your browser and navigate to http://localhost:3000. You will see an empty chain of you local node rapidly being built.

Local Waves Explorer directed to the local node instance

It’s almost a time to put some transactions in there!

3. RIDE project structure and `surfboard` tool

Create an empty dir and type

surfboard init

This command will initialise a directory with a project structure and a sort-of-a-hello-world application and tests.

If you open that folder with VS Code, here’s what you’ll find:

surfboard.config.json

The important section is envs . Each environment is configured by

As you can see, the default surfboard.config.json supports multiple environments with local being default one(defaultEnv key is the setting to change).

4. Wallet-demo application

This section is not a guide to the RIDE language — it’s a glance at the app we’re deploying and testing so we can better understand what’s happening on the blockchain.

We’ll take a closer look at simple application called wallet-demo. Anyone can deposit as many Waves tokens to the dApp as he wants, but you can only withdraw your own waves. Two @Callable functions are available for invocation via InvokeScriptTransaction:

Throughout the dApp lifecycle, the the structure of
mapping(address →amount) will be maintained:

+=========================+==============================+
| Action | Resulting state |
+=========================+==============================+
| <initial> | <empty> |
+-------------------------+------------------------------+
| Alice deposits 5 Waves | <alice-address> → 500000000 |
+-------------------------+------------------------------+
| Bob deposits 2 Waves | <alice-address> → 500000000 |
| | <bob-address> → 200000000 |
+-------------------------+------------------------------+
| Bob withdraws 7 Waves | <DENIED!> |
+-------------------------+------------------------------+
| Alice withdraws 4 Waves | <alice-address> → 100000000 |
| | <bob-address> → 200000000 |
+-------------------------+------------------------------+

To get a full picture, here’s the code:

# In this example multiple accounts can deposit their funds and safely take them back, no one can interfere with this.# An inner state is maintained as mapping `address=>waves`.{-# STDLIB_VERSION 3 #-}
{-# CONTENT_TYPE DAPP #-}
{-# SCRIPT_TYPE ACCOUNT #-}
@Callable(i)
func deposit() = {
let pmt = extract(i.payment)
if (isDefined(pmt.assetId))
then throw("works with waves only")
else {
let currentKey = toBase58String(i.caller.bytes)
let currentAmount = match getInteger(this, currentKey) {
case a:Int => a
case _ => 0
}
let newAmount = currentAmount + pmt.amount
WriteSet([DataEntry(currentKey, newAmount)])
}
}
@Callable(i)
func withdraw(amount: Int) = {
let currentKey = toBase58String(i.caller.bytes)
let currentAmount = match getInteger(this, currentKey) {
case a:Int => a
case _ => 0
}
let newAmount = currentAmount - amount
if (amount < 0)
then throw("Can't withdraw negative amount")
else if (newAmount < 0)
then throw("Not enough balance")
else ScriptResult(
WriteSet([DataEntry(currentKey, newAmount)]),
TransferSet([ScriptTransfer(i.caller, amount, unit)])
)
}
@Verifier(tx)
func verify() = false

A reference code example can also be found on github.

The VSCode plugin will carry out continuous compilation as you edit the file, so you can always follow the errors in thePROBLEMS tab:

To explicitly compile a file if you want to use any other text editor, use

surfboard compile ride/wallet.ride

It will output a base64 string of compiled RIDE code.

5. Test scenario for `wallet.ride`

Let’s briefly look at the test file. Powered by javascript’s Mocha framework, it has a before function and 3 tests:

6. Running the tests with `surfboard`, analyzing the results in Waves Explorer

To run the test, execute

surfboard test

By the way, if you have several scenarios (for instance, you need a separate deployment script), you can run a particular scenario by running

surfboard test my-scenario.js

Surfboard will pick up all the tests files in ./test/ folder and run the scenario over a node through the endpoint configured in surfboard.config.json . After several seconds, you will see something like this:

wallet test suite
Generating accounts with nonce: ce8d86ee
Account generated: foofoofoofoofoofoofoofoofoofoofoo#ce8d86ee - 3M763WgwDhmry95XzafZedf7WoBf5ixMwhX
Account generated: barbarbarbarbarbarbarbarbarbar#ce8d86ee - 3MAi9KhwnaAk5HSHmYPjLRdpCAnsSFpoY2v
Account generated: wallet#ce8d86ee - 3M5r6XYMZPUsRhxbwYf1ypaTB6MNs2Yo1Gb
Accounts successfully funded
Script has been set
√ Can deposit (4385ms)
√ Cannot withdraw more than was deposited
√ Can withdraw (108ms)
3 passing (15s)

Hooray! All tests have passed. Now we can look more closely at what happened using WavesExplorer by just browsing blocks or pasting one of the addresses above to the search box: transaction history, dApp state, decompiled binary, and other things can be found there.

Waves Explorer, an app we just deployed

A few surfboard tips:

  1. To test against a different environment like testnet, just use
surfboard test --env=testnet

To get free testnet tokens, use https://wavesexplorer.com/testnet/faucet

2. If you want to explore what information is sent to and from node during the calls of boradcast(...) in tests, run a test with -v (stands for “verbose”) to make surfboard produce extensive logs:

surfboard test -v

7. Using a deployed app with WavesKeeper

  1. Set your WavesKeeper to work with http://localhost:6869:
Waves Keeper configuration to work with local node

2. Import a seed with tokens for the network. For simplicity, just use the staking seed of your node: waves private node seed with waves tokens . The address would be 3M4qwDomRabJKLZxuXhwfqLApQkU592nWxF .

3. You can either start an instance of a 1-page serverless web appliction yourself using npm, or just navigate to the existing one: https://chrome-ext.wvservices.com/dapp-wallet.html

4. Enter a wallet address from your test run(highlighted in the example above) to the dApp address text field.

5. Enter a small number in ‘Deposit’ field and press theDeposit button:

Waves Keeper asking your permission to sign an InvokeScriptTransaction with attached payment of 10 WAVES

6. Accept the transaction:

The transaction has been created and broadcasted to the network. Its ID is visible below

7. Observe the transaction using explorer by pasting its ID into the search field:

8. Conclusion, further steps and resources

In this article, we explored the tools for developing, testing, deploying and using a simple dApp on Waves Platform. This briefly covers a lot of tools: RIDE language, VS Code, Waves Explorer, surfboard and WavesKeeper. Now you are all set to learn more about RIDE and build your first dApp!

Here’s a few links to help:

TL;DR in a gist: https://bit.ly/2YCFnwY

Waves Protocol

Open blockchain protocol and development toolset for Web 3.0 applications and decentralized solution

Waves Protocol

Waves is an open blockchain protocol and development toolset for Web 3.0 applications and decentralized solutions, aiming to raise security, reliability and speed of IT systems. It enables anyone to build their apps, fostering mass adoption of blockchain.

Ilya Smagin

Written by

Head of Development for Waves Smart Contracts

Waves Protocol

Waves is an open blockchain protocol and development toolset for Web 3.0 applications and decentralized solutions, aiming to raise security, reliability and speed of IT systems. It enables anyone to build their apps, fostering mass adoption of blockchain.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store