Here we will show you how you can deploy and interact with a smart contract on Substrate.
Starting Your Node
After successfully installing Substrate, you can start a local development chain by running:
Note: If you have run this command in the past, you probably want to purge your chain so that you run through this tutorial with a clean slate. You can do this easily with
substrate purge-chain --dev.
You should start to see blocks being produced by your node in your terminal.
You can interact with your node using the Polkadot UI:
Note: You will need to use Google Chrome to have this site interact with your local node. The Polkadot UI is hosted on a secure server, and your local node is not, which may cause compatibility issues on Firefox or Linux based Chromium. The other option is to clone and run the Polkadot UI locally.
If you go into the Explorer tab of the UI, you should also see blocks being produced!
Creating the Flipper "Hello World" Contract
This guide will not teach you about developing smart contracts on Substrate. For that, you can look at our tutorials for smart contract development.
Instead, we will use the Flipper contract, which is the default template generated by the ink! CLI. Make sure you are in your working directory, and then run:
cargo contract new flipper cd flipper/ ./build.sh
You can learn more about
cargo contract here.
Deploying Your Contract
Now that we have generated a Wasm binary from our source code, we want to deploy this contract onto our Substrate blockchain.
Smart contract deployment on Substrate is a little different than on traditional smart contract blockchains like Ethereum.
Whereas a completely new blob of smart contract source code is deployed each time you push a contract to Ethereum, Substrate opts to optimize this behavior. 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 take up space on Ethereum 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.
Putting Your Code on the Blockchain
With your Substrate development node running, you can go back to the Polkadot UI where you will be able to interact with your blockchain.
Open the specially designed Contracts section of the UI.
In the Code section, select upload WASM.
Choose a deployment account with some account balance like Alice. In compiled contract WASM, select the
flipper-pruned.wasm file we generated. For the contract ABI, select the JSON file generated for your contract. Finally, set the maximum gas allowed to
After you press Upload and a new block is formed, an extrinsic event is emitted with
contract.codeStored. This means that you have successfully stored your Wasm contract on your Substrate blockchain!
Creating an Instance of Your Contract
Like Ethereum, smart contracts exist as an extension of the account 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.
You will notice the contract you uploaded is now available to you on the Code section:
To create an instance of your contract, press the Deploy button, which will bring you to the deployment page:
To instantiate our contract we just need to give this contract account an endowment of
10,000 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. This is why we set the
When you press Deploy, you should see a flurry of events appear including the creation of a new account (
balances.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! Flipper only has 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
deploy() function, we set the initial value of the Flipper contract to
false. Let's check that this is the case.
In the Contracts section, press execute.
Set the message to send to
get(): bool. Set the maximum gas allowed to
100,000. You do not need to set a value here since we don't want to transfer any tokens to the contract.
Contract calls cannot return a value to the outside world. So when you press Call, you will get a pretty unsatisfying
system.ExtrinsicSuccess message. However, ink! provides a debugging tool to enable you to print messages to your node's terminal.
If we take a look, we can actually see our storage value:
printlnis only allowed on
--devchains for debugging purposes. If you try to deploy a contract with
printlnon a non-dev chain, it will not succeed.
While this is not a great long term solution, it works very well for debugging contracts, and is a placeholder for more mature solutions like contract events and dedicated view RPCs which are still under development.
So let's make the value turn
The alternative message to send we can make with the UI is
flip(). Again, we will send a value of
1 and a maximum gas allowed of
If the extrinsic was successful, we should then be able to go back to the
get() function and see our updated storage:
Woohoo! You deployed a smart contract!
If you are interested to learn how to write ink! smart contracts, check out our tutorials page.