Easy Substrate Smart Contract Deployment Tutorial: Flipper
In this article, we will go through how to deploy basic ink! contract and getting in touch with the stack around Substrate.
What will you learn
You will learn to
- install prerequisites on your computer,
- using the ink!
cargo-contractplugin to bootstrap a new project
- building and testing our contract, deploying our contract on a local Substrate node
- Interacting with our contract using the Polkadot UI Apps.
I made this tutorial working on OSX, but it should work on most popular Linux distributions.
First, we need to get Rust and environment in play
curl https://getsubstrate.io -sSf | bash -s -- --fastrustup target add wasm32-unknown-unknown --toolchain stable
rustup component add rust-src --toolchain nightly
rustup toolchain install nightly-2020-06-01
rustup target add wasm32-unknown-unknown --toolchain nightly-2020-06-01
Then we will need to install the Substrate local node. This would install version 2.0.0-rc4 on your computer. This may take up to 30–40 minutes, depends on the specs of your computer. You may move on to installing ink! CLI meanwhile.
cargo +nightly-2020-06-01 install node-cli --git https://github.com/paritytech/substrate.git --tag v2.0.0-rc4 --force --locked
(Optional) However, if you are in hurry and have docker with you, you can run, or leverage docker-compose I’ve made
docker run -it -p 0.0.0.0:9944:9944 parity/polkadot:latest "--dev"
To set up the Substrate smart contract project we will need CLI utility which comes with 🔋 batteries included, you can install utility using Cargo:
cargo install cargo-contract --vers 0.6.2 --force
There is a help page if you want to explore other commands
cargo contract --help
Don’t forget, as during writing this manual everything worked with versions cargo-contract-0.6.2 and substrate node v2.0.0-rc4. Substrate ecosystem is under heavy development and may have changed since writing this tutorial.
Creating an ink! project with Flipper
We will now use ink! CLI to generate the file structure we need for Substrate smart contract project. In your working directory run
cargo contract new flipper
It will create a file structure in a folder called a flipper, which we can go explore
Contract Source Code
ink! CLI automatically generates the source code for the Flipper contract, which is about the simplest smart contract you can build.
The Flipper contract is just
bool which gets flipped from true to false through the
flip() function. You can view the whole source code here.
Testing Your Contract
You will see at the bottom of the source code there is a simple test which verifies the functionality of the contract. We can quickly test that this code is functioning as expected using the off-chain test environment that ink! provides.
cargo +nightly test
You should see successful test completion with passed tests
Now, we can feel confident that things are working, we can actually compile this contract to WASM.
Building Your Contract
To compile your smart contract, run the following command
cargo +nightly contract build
This unique command will turn your ink! project into a WASM binary that you can deploy to your chain. If all goes well, you should see a
target the folder which contains this
Now we need some contract ABI, we call it metadata
cargo +nightly contract generate-metadata
We will have a new JSON file
metadata.json in the same target directory. We can look at the structure of the file
You can see this file describes all the interfaces that can be used to interact with your contract.
registryprovides the strings and custom types used throughout the rest of the JSON.
- Storage defines all the storage items managed by your contract and how to ultimately access them.
- Contract stores information about the callable functions like constructors and messages a user can call to interact with your contract. It also has helpful information like the events that are emitted by the contract or any docs.
Polkadot JS apps use this file to generate a friendly interface for deploying and interacting with your contract.
While writing this article, there is upcoming version ink! 2.0 support and in future there will be 3.0, so maybe this obsolete tutorial obsolete afterwards as I doubt backward compatibility in Apps, but let me surprise.
Running a Substrate Node
Meanwhile, you should have done installing Substrate node and ready to go launch your local development chain
You should see something like this. If you run this command in past, I may suggest you run
substrate purge-chain --devto have a fresh environment.
Interact with you node
You will see something like this. It’s dashboard apps which help us interact with Substrate and read heavy loads of information it produces and interact back.
In the dashboard click on the upper left logo and the sidebar with network selector should show up
Click on development and choose a local node and click on switch.
Important: The UI needs a data type override for v2.0.0-rc4 and older versions. The contracts pallet (SEAL) is getting some breaking changes to adjust it for the next version of ink! Go to Settings > Developer and define the type override.
When you go to Explorer tab of UI, you should also see blocks being produced!
Deploying Your Contract
Now we have generated WASM binary and metadata from our source code and started Substrate node, we want to deploy this contract onto our Substrate blockchain.
Smart contract deployment on Substrate is now a little different than traditional deployment.
Whereas a completely new blob of smart contract source code is deployed each time you push a contract on other platforms, Substrate opts to optimize this behaviour. For example, the standard ERC20 token has been deployed to Ethereum thousands of times, sometimes only with changes to the initial configuration (through the Solidity
constructor function). Each of these instances takes up space on the blockchain equivalent to the contract source code size, even though no code was actually changed.
In Substrate, the contract deployment process is split into two halves:
- Putting your code on the blockchain
- Creating an instance of your contract
With this pattern, contract code like the ERC20 standard can be put on the blockchain a single time, but instantiated any number of times. No need to continually upload the same source code over and waste space on the blockchain.
Apps have specially designed Contract UI where you can fiddle with your contracts. You can find it under Developer>Contracts.
Then you select Upload WASM
Now it’s time to send your bytes off your disk to the chain. Now we have however the local environment, but later it would be distributed all around other nodes (worldwide).
Click on compiled contract WASM and pick
flipper.wasm then you pick contract ABI — metadata we’ve generated (JSON file) and you should see a screen like this.
Yes, you can click Upload and Sign and Submit extrinsic (transaction) a new block is formed and a system event is emitted with
contracts.PutCode If the transaction succeeds you will get an
system.ExtrinsicSuccess event and your WASM contract will be stored on your Substrate blockchain.
Note: If you get a
system.ExtrinsicFailederror message, you may not have allowed enough gas to execute the call. You can verify that this is the cause by looking at the logs in the terminal. This may occur on this or any subsequent contract instantiations or calls.
In Explorer tab, you could notice it’s stored and you will get a hash of the contract.
Creating an Instance of Your Contract
Smart contracts exist as an extension of the accounting system on the blockchain. Thus creating an instance of this contract will create a new
AccountId which will store any balance managed by the smart contract and allow us to interact with the contract.
In Code tab there is a new object that represents our smart contract. We now need to deploy our smart contract to create an instance.
To instantiate our contract, we just need to give this contract account of endowment (contract rent) of
10 Units in order to pay the storage rent and again set the maximum gas allowed to
Note: As mentioned earlier, contract creation involves creation of a new Account. As such, you must be sure to give the contract account at least the existential deposit defined by your blockchain. We also need to be able to pay the contract’s rent (
endowment). If we consume all of this deposit, the contract will become invalid. We can always refill the contract's balance and keep it on chain.
When you hit Deploy, you should see a flurry of events appear including the creation of a new account (
system.NewAccount ) and the instantiation of the contract (
Calling Your Contract
Now that your contract has been fully deployed, we can start to interact with it! Finally.
Flipper has only two functions, so we will show you what it’s like to play with both of them.
If you take a look back at our contract’s
on_deploy() function, we set the initial value of the Flipper contract to
false. Let's check that this is the case.
Click on Execute button in Contracts section.
Set the message to send to
get() bool , set the maximum gas allowed to 100000. After pressing Call, you should see it returns the value
NOTE: You might be wondering: “Why did we need to specify gas when reading a value from a contract?”
If you notice right above the “Call” button is a toggle which allows you to “send call as transaction” or “send as RPC call”. For a read-only request like this, we can simply use an RPC call which will simulate a transaction, but not actually store anything on-chain. Thus, you will still need to specify the right amount of gas to cover your “virtual fee”, but don’t worry, nothing will be charged when making a call this way. :)
It’s time to flip the value to
true now! Notice we are sending this as a transaction, don’t forget to flip toggle.
Now we can verify that state by calling
🔊 Ta-da, you’ve managed to deploy your first smart contract on Substrate with ink!
The Substrate contract pallet has a state rent system that forces contracts to stay funded if they want to stay on the blockchain. This means that the more you use a contract, the more fees are taken from it, and at some point, the contract will run out of fees and turn into a non-functioning tombstone. We try to avoid this by giving the contract a large endowment when we initially deploy it. However, if your contract does become a tombstone, for the purposes of this tutorial, the best solution is to just redeploy your contract to the chain.
The best way to prevent this, in general, is to make sure your contract stays well funded. In real-world scenarios, there is a process that you can go through to recover a tombstone contract and get it functioning again, however this is beyond the scope of this tutorial.
Want to continue?
About the Author — Matej Nemček 💫🎋
Early in Bitcoin, Ethereum, founder of hackerspace Progressbar
Founder of Future Space company without satellites