Smart Contract Verification

secdao
6 min readApr 8, 2022

Recently someone asked securityDAO, “How can I trust that a smart contract on-chain in Juno is the same as the version in Github?”.

This is different from the question of “Does the smart contract do what it’s supposed to do securely”. In this blog post we’re explaining how one can make sure that the contract published on git is the same as on chain. Evaluating the intent of a smart contract compared to its content is best answered by smart contract developers and security experts via an audit. Important smart contract projects should be audited by 3rd party experts, enjoy the remediation of issues discovered and the audit subsequently published.

All members of the Juno community should be able to verify that the on-chain CosmWasm smart contract matches the source code commits referenced in an audit when engaging with dApps and DeFi instruments in the Juno ecosystem.

About Juno

Juno is a permissionless smart contract chain in the Cosmos ecosystem. Juno is an ecosystem unto itself with tooling for DAOs, NFTs, DeFi and all sorts of dApps.

Anyone can verify that source code matches bytecode if the source code is publicly available on Github.

This tutorial serves as a guide for how to do this.

The verification process can be broken into 4 steps:

  1. downloading cosmwasm .wasm file from on-chain using junod
  2. finding the most likely commit from the contract github repo and building into .wasm
  3. converting .wasm files to wat files or comparing hashes
  4. repeating steps 1–3 until a matching commit and compiler settings are found

Previous approaches focused on comparing hashes

Why not just hashes instead of WAT?

Hashes don’t provide insight into where differences in contracts lie, and may be affected by optimizations applied to the resulting compiled contract. WAT can guide you towards the commits in repo with dependency changes and other key signals to help understand why a hash may not be matching and where to check next.

Prerequisites:

This tutorial should work for macOS (not M1) and Linux (Ubuntu 20.04). Windows may need to change the path slash direction and escaping differently. Windows users should strongly consider using Ubuntu 20.04 WSL. macOS M1 arm processor laptops are not yet fully supported by the software stack so this tutorial may not work with arm chips now but that may change in the future.

Getting the contract on-chain

to get a contract on chain you can use an rpc query from the cosmos sdk equivalent for the chain you are using (wasmd, junod etc)

To identify smart contracts in Juno you will need to know the smart contract code.

Smart Contracts can be viewed using sdk commands or from mintscan

https://www.mintscan.io/juno/wasm

  1. find our contract of interest
  2. write down the id column of mintscan Id this is the wasm code , this code increments for every new contract so a new contact should have one of the largest codes
  3. write down the created timestamp
  4. write down Contract name field
  5. ensure that you know who the Creator address belongs to

using juno sdk

sdk can also be used but its more difficult to aggregate contract metadata

Example:

Find the crates.io:cw3-multisig named WAGMI

Click on WAGMI

Note: the wasm code for the WAGMI contract (42)

For cosmos chains other than juno the rpc endpoint and command tree may be different:

For Juno:

Building wasm from repo

  1. find the code repo or be given access to the repo if its a private code repo
  2. follow the steps in https://docs.cosmwasm.com/docs/1.0/smart-contracts/compilation to produce wasm (summarized below )
  • cd into the contract folder.
  • run %sudo docker run — rm -v “(pwd)”:/code −−mounttype=volume,source=”(basename “$(pwd)”)_cache”,target=/code/target
    — mount type=volume,source=registry_cache,target=/usr/local/cargo/registry
    cosmwasm/workspace-optimizer:0.12.4
  • cd into artifact folder in root of the github repo
  • the compiled .wasm file should be within

Notes:

  • contract folders are often under contracts/cw-<nameofcontract>/
  • a cargo.toml should be in the folder
  • make sure you are in the right contract folder with the right commit if the project has multiple contracts
  • if you build on a different commit than deployed you may see a different version built
  • if the contract was deployed a long time a go try to determine the commit(possibly release) that was used when the contract was deployed.
  • if the contract was deployed recently than the latest commit on the main repo branch is the likey one to use or the latest release if one is provided
  • if the contract was built without an optimzer or different compiler settings than the files will not match completely

Verify Contract Matching

We have 3 options:

Check the hash

  1. check the hash (sha-256) of the wasm files ( if the checksum matches we have a winner)
  2. check the creator address of the contract
  3. covert wasm to wat and look at the differences between the files (git diff)
  4. checking hash
  • $HASHSOURCE = sha256sum WAGMI_SOURCE.wasm
  • $HASHONCHAIN = sha256sum WAGMI_ONCHAIN.wasm
  • diff <(echo “HASHSOURCE”)<(echo”HASHONCHAIN”)>

See cosmwasm docs: https://docs.cosmwasm.com/docs/1.0/smart-contracts/verify/

Check the creators address

Ask the following questions of the creator address to see if any red flags stand out:

  • Does this address match previous uploads or other contracts?
  • Are you familiar with the creator address?
  • Have others used contracts from this creator address before?

Convert wasm to wat

https://webassembly.github.io/wabt/demo/wasm2wat/

  • click upload
  • select .wasm file
  • copy and paste .wat output into new text file in editor and save as WAGMI_ONCHAIN.wat

OR use wasm2wat cli tool

OR use vscode extension

Once installed you can now right or cmd click on a file and select save as Webassemby text file to save a wat file from wasm

Repeat the process for the source file but save new text file in editor as WAGMI_SOURCE.wat

You should now have 2 wat files one source and one from chain

Analyzing WAT Files

  • run git diff --no-index --unified=0 WAGMI_ONCHAIN.wat WAGMI_SOURCE.wat
  • if there is no output response than the files are the same , you can check the command against 2 paths to the same file to verify this
  • if there is output you will see the highlighted difference and can exit the terminal by pressing esc and than q

If there is no git output then congrats you have verified this contracts source code without relying on anyone else.

Ultimately the goal is that there should be no differences between wat. With some differences you may not be sure as to what code is different.

Differences from the chain version can be due to

  • different compiler optimization or flags
  • upgrading dependencies
  • difference in commit used for building the contract
  • bad actor trying to slip in a dangerous update

Binary authorization and transparent builds

If you must be 100% sure the contract you are using is the correct one than you must prove that the CosmWasm contract source code matches the on chain wasm, and that it is indeed authored by the repo owner.

While many of the web2 concepts like binary authorization of builds is implicit in the contract ownership structure of CosmWasm, i.e. cryptographic identity of Junø wallets for the deployed artifacts is sufficient to establish upload-time identity. However, everything up until the upload step can and should be additionally secured the Verified committer process on GitHub — cryptographically signing the code at a specific commit hash;

An additional layer of transparency can be to gain access to the logs and resulting artifacts of the build itself in the build system used by the repo authors, e.g. GitHub Action, GitLab CI etc.

If you need help with smart contract audits, on-chain analytics for Cosmos / IBC, SecurityDAO can be reached through the means listed below.

--

--