How to verify ink! smart contracts

Conor
Chainlens

--

The ink! programming language for Substrate is a popular choice for developers wishing to build on the Substrate platform. Whilst Solidity is supported via Solang, a number of developer and projects are keen to work with ink! due to it using the Rust programming language and compiling down to WASM.

A major hurdle for teams working with ink! Is that blockchain explorers for Substrate chains have no mechanism of easily decoding the information about activity taking place on-chain. Instead they would be presented with non-human readable bytecode.

This was due to the lack of a verification service that could take source code and verify that it matches the binary bytecode that was deployed on-chain.

This is now possible thanks to Web3 Labs ink! verifier server and Chainlens Substrate explorer.

This article will take you through this entire process, allowing you to:

  1. Create an ink! smart contract
  2. Deploy it to a parachain
  3. Verify its source code using the ink! verification service
  4. View the decoded ink! smart contract in Chainlens

Pre-requisites

You will need to have rustup installed with the latest version of Rust. If you’re running an old version, make sure you update it.

rustup update

Ensure you have the rust-src compiler component added.

rustup component add rust-src

Creating an ink! smart contract

The cargo-contract package provides a CLI for developing smart contracts using ink!. You will need to install it (note — verifiable builds can only be performed from version 2.0.2 onwards).

cargo install cargo-contract

In order to build the contract and generate a reproducible build, you need to make use of the ink! Verifier Service that we’ve created to create verifiable builds for ink! smart contracts. This ensures that the same build environment is used for both deployment and verification.

If, in the future, when the ink! team publishes an official image which supports deterministic builds, we will integrate the ink! Verifier Service with the official image.

This can be installed using the following command:

cargo install — git 
https://github.com/web3labs/ink-verifier-image.git

We now create our WASM smart contract. Using the cago-contract package we create the flipper contract, which is a simple contract that contains a boolean value and can flip it, hence the name.

cargo contract new flipper

Change to the contract directory

cd flipper
tree -L 1
.
├── Cargo.lock
├── Cargo.toml
└── lib.rs

Alternatively if you’re working with an existing contract you may use this instead. However, please ensure you are using contracts version 2.0.2 or greater.

Performing a verifiable build

You can run the verifiable build with the following command:

build-verifiable-ink -i ghcr.io/web3labs/ink-verifier .

Once completed, you should see output similar to the below.

...
[5/5] Generating bundle

Original wasm size: 20.6K, Optimized: 1.4K

The contract was built in RELEASE mode.

Your contract artifacts are ready. You can find them in:
/build/package/src/target/ink

- flipper.contract (code + metadata)
- flipper.wasm (the contract's code)
- flipper.json (the contract's metadata)
adding: src/ (stored 0%)
adding: src/Cargo.lock (deflated 75%)
adding: src/Cargo.toml (deflated 52%)
adding: src/lib.rs (deflated 72%)
adding: flipper.contract (deflated 64%)
Verification package in /build/target/ink/package.zip
Archive: /build/target/ink/package.zip
Length Date Time Name
--------- ---------- ----- ----
0 2023-03-08 21:41 src/
105695 2023-03-08 21:28 src/Cargo.lock
573 2023-03-08 20:40 src/Cargo.toml
5177 2023-03-08 20:40 src/lib.rs
5278 2023-03-08 21:41 flipper.contract
--------- -------
116723 5 files

If you have any issues running the build, you can built it yourself by running the following commands:

cd ../
git clone https://github.com/web3labs/ink-verifier-image.git
cd ink-verifier-image
docker build . -t ink-verifier:develop
cd ../flipper
build-verifiable-ink -t develop .

There will now be a package zipfile available which contains the contract source code, metadata and WASM binary (you can install jq and tree via homebrew if on OS X).

tree -L 3
.
├── Cargo.lock
├── Cargo.toml
├── lib.rs
└── target
└── ink
└── package.zip

We then extract the files.

unzip -qq -p target/ink/package.zip "*.contract" > target/ink/flipper.contract
unzip -qq -p target/ink/package.zip "*.contract" | jq "del(.source.wasm)" > target/ink/metadata.json
unzip -qq -p target/ink/package.zip "*.contract" | jq -r ".source.wasm" | xxd -r -p > target/ink/flipper.wasm

Deploying your smart contract

Now that you have a verified build, we will deploy this contract to the Rococo testnet. There is already an instance of Chainlens Substrate running on Rococo available at substrate.sirato.xyz.

Sirato Substrate Blockchain Explorer

If you require ROC tokens for Rococo, you can view instructions for getting them here.

You can now use the cargo-contract tool to upload the code to Rococo and deploy a new instance of the contract.

cargo contract instantiate \
--constructor new \
--args false \
--url wss://rococo-contracts-rpc.polkadot.io \
--suri "your twelve or twenty-four word wallet seed phrase"

Once the upload and deployment has completed, you will see details of the code hash and contract listed.

Dry-running new (skip with --skip-dry-run)
Success! Gas required estimated at Weight(ref_time: 330944206, proof_size: 0)
Confirm transaction details: (skip with --skip-confirm)
Constructor new
Args false
Gas limit Weight(ref_time: 330944206, proof_size: 0)
Submit? (Y/n):
Events
Event Balances ➜ Withdraw
who: 5Gc1RWvH2MtDYB7NKrMEuMsVTMApG3rCjYjPpYvZ8yh2yD3X
amount: 52.442068μROC

...

Code hash 0xbb42a8a8f4c8478c402eda3bca3cf86c6495e9e5c9eb41900c69e05ce15217bb
Contract 5D4K82dkLh3CLQrSLiRYV8EwY3NBjogAAeyWkZyjLBUcDP9u

Performing verification

You can then head to the Chainlens Rococo explorer and look for the contract under “Latest Contracts”.

Sirato Rococo Explorer Latest Contracts View

From there you can navigate to the deployed code by clicking on the Code reference that matches the code hash returned by the cargo contract instantiate call.

Alternatively, you can navigate directly by entering the URL https://substrate.sirato.xyz/codes/0x<code-hash>.

Now click on the source code tab:

Then upload the package.zip file that you generated earlier.

You can now start the verification process which kicks off a build of the provided resources.

Once the process has finished you will see the message Contract successfully verified.

Clicking Browse verified files will display the associated metadata and source files for your contract.

If we then browse back to our contract instance, any methods or events will now be decoded.

We can verify this by invoking a method on the contract. For our deployed contract, we invoke the flip method.

cargo contract call \
--contract 5D4K82dkLh3CLQrSLiRYV8EwY3NBjogAAeyWkZyjLBUcDP9u \
--message flip \
--url wss://rococo-contracts-rpc.polkadot.io \
--suri "your twelve or twenty-four words"

We can now see the decoded method that was called in Chainlens.

Chainlens does support other mechanisms for providing metadata for smart contracts. You can upload an ABI file with a signature from the account that deployed the code to do this. For further information, you can refer to the following tutorial.

Supporting the next generation of Web3 networks

The ability to reliably interpret the activity of ink! smart contracts on-chain is essential for developers and users of Substrate networks utilising this next generation of tooling. Web3 Labs is committed to continuing to build out this infrastructure to support the Substrate and Dotsama community.

The public verification service is not limited to the Rococo network. It works with any Substrate networks that have been defined in the @polkadot/apps-config package. It is also accessible also via its API, which you can view here.

Your users will however require an instance of the Chainlens explorer running against your network to display the decoded information about activity and events taking place with the ink! smart contracts.

If you’d like to experiment with the Chainlens Substrate explorer, its GitHub repository is available here. However, if you’d prefer for someone to spin up and manage an instance for your network on your behalf, feel free to reach out to the team to learn more about deployment options.

--

--