What is Parity’s “ink!”?

Supercolony
WASM conference
Published in
9 min readJun 8, 2022

--

written by Michael Muller, the Core Developer at Parity

Post Material after WASM conference 2022

This is a summary of the talk “What is Parity’s ink!?” which Michael Müller gave for the Wasm Conference 2022. Michi has been a developer at Parity for a couple of years now, working mostly on the ink! ecosystem for a while.

Before we can talk about ink! we need to clarify what Substrate and its pallet-contracts are first.
The substrate is a framework for building blockchains ‒ those can be standalone blockchains or blockchains connected to Kusama or Polkadot. The substrate contains a number of modules, in Substrate terminology those are called “pallets”. There’s a pallet for anything one wants to have in a modern blockchain ‒ fungible tokens, non-fungible tokens, governance, etc…

If a developer uses Substrate they can easily add smart contract functionality by including the pallet-contracts. See this how-to guide in case you’re interested in this. The readme of the pallet has more details.
How does ink! come into play here? Well, with ink! you can write smart contracts in Rust for blockchains built on the Substrate framework.

A confusing thing for people learning about Substrate, Polkadot, and Kusama (or as it’s also called the Dotsama universe) is the difference between when to write a Substrate pallet and when to use the smart contracts module.

The distinction here is that in the context of Polkadot and Kusama a parachain leases a slot for a couple of months for up to two years. As part of this lease the parachain can execute its state transition function with every block that is appended to Polkadot/Kusama.

So the code that the parachain executes during that time doesn’t get further validated ‒ it’s up to the parachain what it does with its slot time. It can build its own world and has all the freedom ‒ it can for example decide on how transaction fees work, how governance works, design its own crypto-economics, etc… A more detailed explanation can be found here.

For smart contracts, on the other hand, an existing parachain has to include the pallet-contracts for you to upload smart contracts there. The uploaded smart contract is always untrusted here. This is because anyone (or any program) that has tokens of the chain could upload any smart contract. The pallet-contracts has to assume that this program could be adversarial, so it has to put a number of safety pillars into place to ensure that the contract can not e.g. stall the chain (gas metering, etc.).

So developing a parachain runtime is different from developing a smart contract ‒ it’s on different layers, a smart contract sits on top of a parachain.

The trade-off is that with a parachain you write (nearly) all the rules by yourself, whereas with a smart contract your constrained by what the chain allows you to do and all the safety pillars that necessarily have to be in place.
A smart contract on the other hand is way easier to develop and deploy ‒ you don’t have to take care of governance, crypto-economics, etc… You just need a few tokens and then you can deploy your contract. The following schema shows the trade-off:

How the pallet-contracts works

We intentionally designed pallet-contracts in a way that is decoupled from the language that is used on top of it.

This means you can use ink!, but also other languages. Right now there are three languages you can choose from:

It’s not hard to add new languages. The language just needs to compile down to WebAssembly (Wasm) and implement the API of pallet-contracts. This API at the moment consists of about 15-20 functions for anything a smart contract may desire: storage access, crytpography functionality, environmental information like block numbers, access to functions to get random numbers or self-terminate the contract, etc… The language on top doesn’t have to implement all of those functions ‒ the ink! hello world requires just six. The following schema depicts this relationship:

Use Cases for pallet-contracts

There’s a couple use cases for the pallet.
An obvious one is a chain which has smart contracts as a “first class citizens”, meaning smart contracts are the central thing of the chain.

Those chains typically take the pallet-contracts and put some additional unique value proposition on top of it. For example, a big chain using the pallet-contracts has built some way of how contract developers can get a passive income from their contracts being used on top of the pallet.

The other big use case is to have smart contracts as “second class citizens”. The pallet provides an API (called chain extensions) with which a parachain can decide to expose certain parts of its business logic to smart contract developers. This way the parachain can adding customizability for parts of its business logic. Think for example of a decentralized exchange blockchain. That chain would have an orderbook to place bids and asks; it could now decide to expose this into smart contracts, thus giving developers the option of uploading trading algorithms as smart contracts to the chain.

Another big use case for the pallet is to prototype an idea as a smart contract before going for a dedicated parachain slot.
Since the threshold for developing a smart contract is way lower this can make sense depending on the use-case. One could deploy an MVP smart contract first, see if it gains traction and the idea works, and only subsequently once there is a need to control e.g. transaction fees or have some governance mechanism go for a dedicated parachain runtime. Since ink! and Substrate are both Rust and share similar primitives there is a clear path of graduating from a smart contract to its own runtime.

Readme

https://docs.substrate.io

Simple ink! program

ink! is really just Rust, that’s our overarching goal. We aim to be minimally invasive, enabling you to use
everything that you can use with Rust ‒ IDEs, cargo fmt, cargo clipy, code snippets, crates (no_std compatible ones), etc…

In the following picture you can see a simple ink! contract. The contract
here has one boolean in its storage. Once the contract is created it sets
the boolean to true by default. The contract exposes two functions: one
to read the current value of the boolean (get) and one to switch it to
its opposite boolean value (flip).

The colored lines are ink!-specific annotations for the code.

Unit and integration tests can be written also as just Rust:

#[ink::test]
fn default_works() {
let flipper = Flipper::default();
assert_eq!(flipper.get(), false);
}

The #[ink::test] annotation has the effect of wrapping the test in a mocked blockchain environment.
This enables you to mock e.g. the value that is transferred to a contract, its sender, block numbers, etc…
For example, you can use ink_env::test::set_value_transferred within an #[ink::test] to mock the value (i.e. tokens) send to a contract.
You can see the full list of ink_env::test functions in the crate documentation here.

Cargo-contract

For building ink! smart contracts you have to go through cargo-contract, which is a command-line tool that mirrors cargo. It’s kind of a swiss army knife for ink! smart contracts, it can do much more besides just building a contract, but we’ll talk about that later.

For building contracts you use cargo contract build. Note that the typical Rust cargo build behavior is that you need to supply --release if you want the smallest possible binary size, same with cargo contract build --release.
If you run this command you’ll see that cargo-contract executes the “normal” cargo build on your contract, but it does some more stuff as well. The three most important additional steps it does are:

  • It runs a linter for ink! contracts that works analog to Rusts’s clippy, it checks your contract for idiomatic use of ink!. We’re constantly improving this linter and plan to add detections of common security pitfalls there as well.
  • It post-processes and compresses your contracts binary. This is done because it reduces the costs of deploying the contract, as well as the gas fees for users interacting with the contract. The contract size also correlates to the throughput a chain can achieve.
  • It generates metadata for the contract. With metadata we refer to anything that is needed to interact with the contract binary. The binary itself will be just a Wasm blob ‒ byte code of the contract that without further information doesn’t make any sense. In order to know what functions the contract exposes, what arguments they take, etc. you need to have the metadata.
    You might also know this concept under the term ABI from other blockchains. In our case the metadata contains a bit more than just the ABI though, it also has information on e.g. how the contract stores its data, this is helpful for off-chain tooling (e.g. a block explorer).

As part of cargo contract build you get three files:

  • my_contract.contract: the contract’s WebAssembly blob in hex encoding + the contract’s metadata.
  • my_contract.wasm: the contract’s WebAssembly blob.
  • metadata.json: the contract’s metadata.

Each of those files has a different use case:

The WebAssembly is the only part that is actually stored on-chain. This is because storing data on-chain should be only done for the things
that are strictly necessary. The metadata is not necessary to be on-chain, if you have a Dapp the Dapp can contain the hardcoded metadata.

The *.contract bundle is only needed if you’re developing a smart contract, then you can upload this file to a Developer UI and it will deploy it and give you all the options of interacting with the contract.

Developing?

For development you can use any testnet or tooling of existing parachains that support the pallet-contracts and ink!.

We’re providing a couple of handy things as well:

  • substrate-contracts-node
    This repository contains Substrate’s node-template configured to include pallet-contracts.
    This node is tracking Substrate’s master and has been modified
    to make it a great fit for development and testing. For example, it doesn’t have any fixed block time,
    everything is processed immediately. This comes at the cost of making the node unsuitable for production use, but great for e.g. CI’s.
    If you’re looking for production templates take a look at Substrate’s node or the How-To guide in Substrate’s documentation on how to add the pallet-contracts (link here).
  • We maintain a testnet named plainly Contracts on Rococo. Rococo is a testnet for anything Polkadot and Kusama. This means many parachains are connected to Rococo with their own testnets. You can read more about it in our documentation.

There’s also a number of community testnets, you can find an overview on https://github.com/paritytech/awesome-ink.

For Developer UI’s you have currently those choices:

  • Contracts UI: Ideal for beginners, gives helpful hints and assists.
  • polkadots.js: Advanced interface that exposes any functionality you could possibly ever want.
  • ink! playground: A playground to try out ink! in the browser or share permalinks to code snippets. This is very handy if you’re asking questions on our StackExchange.
  • cargo-contract: If you’re looking to deploy contracts from the command-line, call them, decode their output, etc. then this tool provides a handy option to do all of that as a CLI. You can also use the tool for e.g. scripting or CI integrations.

In terms of ink! documentation the resources are:

  • If you are looking for a quickstart,
    ink!’s Guided Tutorial for Beginners provides a great starting point.
  • Other than that, ink.substrate.io is our documentation portal.
  • Since ink! is just Rust you can also check out the crate docs. For example, the ink_env crate is the one which has all the functions you might need in your contract: https://docs.rs/ink_env/latest/ink_env/.
    We’ve linked other relevant crate docs in our readme here, e.g. the crate for data structures (ink_storage) is linked there.

If you have any questions whatsoever its best to ask them on our StackExchange site or open an issue in the fitting repository.

--

--

Supercolony
WASM conference

Supercolony is a venture studio, that creates, funds, and builds Polkadot and cross-chain companies.