Waves Protocol
Published in

Waves Protocol

Waves 1.3 Stagenet Release

Following 4.5 months of development, the Waves protocol’s version 1.3 is now available on the stagenet.

The upgraded version features the implementation of two Waves Enhancement Proposals, and , as well as a new version of the Ride standard library.

The update contains unique functionality for operating decentralized apps, which you won’t find in any other protocol.

Detailed information on all the improvements is available on the release page

Protocol improvements


One of the protocol improvements is continuations, a concept originally by Ilya Smagin in late 2019.

Thanks to continuations, you can write scripts with a maximum exceeding 4,000 (which is a limit for scripts on the mainnet now).

Previously, for complex computations, an app’s logic had to be split into several methods and invoke them, one by one, in separate transactions. Thanks to continuations, execution of a script with a complexity exceeding 4,000 is split into several stages: the first stage is executed within an invoke script transaction, and the remaining ones are generated without the user’s involvement in continuation transactions.

Calling a dApp from another one

A dApp script’s callable function can execute attached calls. From a dApp, another or the same dApp’s @Callable function can be invoked. The callable function can also invoke itself. All invoked functions are executed within the same invoke script transaction. The complexity of executable scripts is limited.

Thanks to this improvement, two dApps can communicate not only through account storage but also directly by calling each other.

Changes for developers

To support the improvements described above, changes for developers were added to the protocol. Primarily, a new transaction type has been added, which is a continuation transaction. A continuation transaction is created by a block generator automatically, in case of an incomplete computation chain. A continuation transaction can’t be sent by a user.

Also, version 3 invoke script transaction has been added, enabling invocation of scripts with a complexity exceeding 4,000.

Changes to the Ride language

Version 5 of the standard library has been released, to which the Invoke function for calling a dApp from another one has been added. Calling one dApp from another one could look like this:

Eager variables called with the keyword strict have been added. They are different from regular ‘lazy’ variables, called with the let keyword, and are computed until the next expression, to guarantee the order of execution and application of callable functions’ scripts.

The format of a @Callable function’s result has been changed: a returned value as the final part of a tuple has been added:

In version 1.2, new script actions were added, including Issue, Burn and Reissue, but Lease and LeaseCancel, which a callable function could execute, were lacking. In the new version, those functions have been added, and, thanks to this, a smart contract can lease out WAVES or cancel leasing.

Thanks to Lease and LeaseCancel, a leasing amount can be changed or part of the total leased amount can be withdrawn. If in one script invocation, the leasing of a larger amount is canceled and a smaller amount is leased out to the same recipient, the generating balance will decrease by one. However, if two separate transactions are sent — a lease cancel transaction and a lease transaction, — and they are added to different blocks, the generating balance will immediately decrease by the canceled leasing amount, and the new leasing amount will be added to it only after 1,000 blocks.

In other words, thanks to support for Lease and LeaseCancel, partial leasing cancellation has been made possible.

For the convenience of leasing operations, the in-built function has been added to receive a leasing ID, formed by the Lease structure. The principle of using is identical to that of calculateAssetId.

In Ride’s new version, account data storage functions have been added, enabling a dApp script to read data from its own storage at any computation stage:

  • getBinary(key: String): ByteVector|Unit
  • getBinaryValue(key: String): ByteVector
  • getBoolean(key: String): Boolean|Unit
  • getBooleanValue(key: String): Boolean
  • getInteger(key: String): Int|Unit
  • getIntegerValue(key: String): Int
  • getString(key: String): String|Unit
  • getStringValue(key: String): String

Another major improvement is the addition of another data type — . This is a supertype for all types: a value of any type can be a line, a number, a unit, a structure, a list, a tuple, etc.

Please, pay attention to changes in REST API, which break backward compatibility. A detailed description is available on the .

How to test?

The new functionalities of calling a dApp from another one and, specifically, continuations have led to substantial changes in app development experience on Waves. You can already start testing your dApps on the stagenet.

To do it, use the and nodes from the .

If you have questions or issues, discuss them in the developer chat at

If you have ideas for improving the functionalities of continuations or calling one dApp from another one, welcome to the discussion forum for Waves Enhancement Proposals:



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.

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
Inal Kardanov

Co-founder & CTO of Billy. Software engineer. Blockchain, ML&AI developer. All opinions are my own.