Terra Protocol

Getting Started With Terra Protocol

Rahul Ravindran

Terra is a decentralized financial infrastructure and blockchain protocol that introduces some unique concepts and theories into the market. The network leverages a native token, stablecoin protocol, oracle system, and smart contracts to bring users programmable money for the internet.

The project offers multiple stablecoin options that provide instant settlement. To accomplish this task, Terra relies on a price-stability algorithm that actively alters the monetary supply of an asset to retain value. In this way, Terra can provide users with lower fees, more stability, seamless cross-border exchanges, and highly responsive financial assets.

Terra has a development-focused agenda. The network allows programmers to build smart contracts in Rust. Additionally, you can add extra functionality to your Dapp through the use of the network’s oracles. Oracles are off-chain sensors that have the ability to communicate data to-and-from the blockchain. Oracles are critical to many blockchain networks, especially when used for price discovery purposes. In this article we will discuss how to create your first smart contract in Terra.

What are we building?

We will create a simple counter app. Our app will have a function to increment the counter state variable, which will enable to understand how the contract persists state. I’m assuming that you have some experience with blockchain development and have a basic understanding of what a smart contract is. If you do not have this knowledge yet. Please feel free to watch checkout courses like 6-Figure Blockchain Developer or Web Development For Blockchain.

Terra Developer Tooling

Terra has official SDKs that developers can use to get started. The following table maps commonly-used Ethereum developer tools to their Terra counterparts.

Terra Ethereum
Frontend SDK Terra.js, Terra SDK Web3.js, Web3py
Browser Extension Station CX MetaMask, MEW
Local Testnet LocalTerra Ganache
Contract Language Rust Solidity, Vyper

For more info check official documentation.


Environment Setup

As a smart contract developer, you will need to write, compile, upload, and test your contracts before deploying them to be used on the Columbus mainnet. As this development process can involve manually juggling multiple moving parts over many iterations, it is helpful to first set up a specialized environment to streamline development.

In order to work with Terra Smart Contracts, you should have access to a Terra network that includes the WASM integration. For local development, we are going to use LocalTerra, a package used to setup private terra network.

1. Setup LocalTerra

To use LocalTerra, you should first make sure Docker is installed on your computer by following the Docker get-started tutorial . You will also need to set up and configure Docker Composeon your machine.

git clone --branch v0.5.2 --depth 1 https://github.com/terra-money/localterra
cd localterra
docker-compose up

You should now have a local testnet running on your machine, with the following configurations:

The account with the following mnemonic is the sole validator on the network and has enough funds to get started with smart contracts.

satisfy adjust timber high purchase tuition stool faith fine install that you unaware feed domain license impose boss human eager hat rent enjoy dawn

2. Install Rust

Follow the installation steps on https://www.rust-lang.org/tools/install to setup rust language if you don’t have it already. Check out the Rust Crash Course for getting started with rust.

IMPORTANT: Configure you path variables

In the Rust development environment, all tools are installed to the ~/.cargo/bin directory, and this is where you will find the Rust toolchain, including rustc, cargo, and rustup.

Accordingly, it is customary for Rust developers to include this directory in their PATH environment variable. During installation rustup will attempt to configure the PATH. Because of differences between platforms, command shells, and bugs in rustup, the modifications to PATH may not take effect until the console is restarted, or the user is logged out, or it may not succeed at all.

If, after installation, running rustc --version in the console fails, this is the most likely reason.

Once you’ll installed Rust and its toolchain (cargo et al.), you’ll need to add the wasm32-unknown-unknown compilation target.

rustup default stable
rustup target add wasm32-unknown-unknown

Then, install cargo-generate, which we will need for bootstrapping new CosmWasm smart contracts via a template.

    cargo install cargo-generate --features vendored-openssl

3. Writing your first smart contract

Terra has a template you can use as a starter kit. Lets go ahead and clone it:

cargo generate --git https://github.com/CosmWasm/cw-template.git --branch 0.16 --name counter-dapp
cd counter-dapp

Lets review the project structure of the template

the src folder has 4 rust files: – state.rs: stores state of our contract i.e the data we wish to persist on the blockchain. – contract.rs: stores our contract logic which will get executed when a user performs a query. – error.rs: handles error messages – lib.rs: is used to package our contract as a library

We will start with setting up state of our contract


use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

use cosmwasm_std::Addr;
use cw_storage_plus::Item;

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct State {
    pub count: i32,
    pub owner: Addr,

pub const STATE: Item<State> = Item::new("state");

Here we have declared 2 state variables. pub count stores the value of count and pub owner store the address of the contract owner.

State values are initialised in the contract constructor function which will get executed when our contract is deployed.

// src/contract.rs

// version info for migration info
const CONTRACT_NAME: &str = "crates.io:{{project-name}}";

pub fn instantiate(
    deps: DepsMut,
    _env: Env,
    info: MessageInfo,
    msg: InstantiateMsg,
) -> Result<Response, ContractError> {
    let state = State {
        count: msg.count,
        owner: info.sender.clone(),
    set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
    STATE.save(deps.storage, &state)?;

        .add_attribute("method", "instantiate")
        .add_attribute("owner", info.sender)
        .add_attribute("count", msg.count.to_string()))

The constructor sets the value of the count variable and sets the message sender as the owner of contract.

Lets add a function to increment the counter

// src/contract.rs

pub fn try_increment(deps: DepsMut) -> Result<Response, ContractError> {
    STATE.update(deps.storage, |mut state| -> Result<_, ContractError> {
        state.count += 1;

    Ok(Response::new().add_attribute("method", "try_increment"))

This function increments the state variable by 1 every time its invoked.

Lets also add another function to query the current value of count

// src/contract.rs

fn query_count(deps: Deps) -> StdResult<CountResponse> {
    let state = STATE.load(deps.storage)?;
    Ok(CountResponse { count: state.count })

4. Deploying your contract to LocalTerra

Please ensure the LocalTerra is running as described in step 1. We first need to add a test account. We can use the following command to set it up from a mnemonic:

terrad keys add test1 --recover
satisfy adjust timber high purchase tuition stool faith fine install that you unaware feed domain license impose boss human eager hat rent enjoy dawn

Run the following command to create a WASM build in your directory

cargo run-script optimize

Finally to publish your code to LocalTerra run the following command.

terrad tx wasm store artifacts/counter_dapp.wasm --from test1 --chain-id=localterra --gas=auto --fees=100000uluna --broadcast-mode=block

You should see a similar output:

height: 6
txhash: 83BB9C6FDBA1D2291E068D5CF7DDF7E0BE459C6AF547EC82652C52507CED8A9F
codespace: ""
code: 0
data: ""
rawlog: '[{"msg_index":0,"log":"","events":[{"type":"message","attributes":[{"key":"action","value":"store_code"},{"key":"module","value":"wasm"}]},{"type":"store_code","attributes":[{"key":"sender","value":"terra1dcegyrekltswvyy0xy69ydgxn9x8x32zdtapd8"},{"key":"code_id","value":"1"}]}]}]'
- msgindex: 0
  log: ""
  - type: message
    - key: action
      value: store_code
    - key: module
      value: wasm
  - type: store_code
    - key: sender
      value: terra1dcegyrekltswvyy0xy69ydgxn9x8x32zdtapd8
    - key: code_id
      value: "1"
info: ""
gaswanted: 681907
gasused: 680262
tx: null
timestamp: ""

You will have to manually create the contract after the code has been deployed. This is an additional step in Terra as compared to something like Ethereum where the contract is instantly published and deployed.

Lets initialise the contract with count 0

terrad tx wasm instantiate 1 '{"count":0}' --from test1 --chain-id=localterra --fees=10000uluna --gas=auto --broadcast-mode=block

You should see the a similar message once contract is deployed successfully.

height: 41
txhash: AEF6F2FA570029A5D4C0DA5ACFA4A2B614D5811E29EEE10FF59F821AFECCD399
codespace: ""
code: 0
data: ""
rawlog: '[{"msg_index":0,"log":"","events":[{"type":"instantiate_contract","attributes":[{"key":"owner","value":"terra1dcegyrekltswvyy0xy69ydgxn9x8x32zdtapd8"},{"key":"code_id","value":"1"},{"key":"contract_address","value":"terra18vd8fpwxzck93qlwghaj6arh4p7c5n896xzem5"}]},{"type":"message","attributes":[{"key":"action","value":"instantiate_contract"},{"key":"module","value":"wasm"}]}]}]'
- msgindex: 0
  log: ""
  - type: instantiate_contract
    - key: owner
      value: terra1dcegyrekltswvyy0xy69ydgxn9x8x32zdtapd8
    - key: code_id
      value: "1"
    - key: contract_address
      value: terra18vd8fpwxzck93qlwghaj6arh4p7c5n896xzem5
  - type: message
    - key: action
      value: instantiate_contract
    - key: module
      value: wasm
info: ""
gaswanted: 120751
gasused: 120170
tx: null
timestamp: ""

Keep note of contract_address key i.e “terra18vd8fpwxzck93qlwghaj6arh4p7c5n896xzem5”, we’ll need this to interact with our contract.

5. Interacting with our contract

Lets query contract info.

terrad query wasm contract terra18vd8fpwxzck93qlwghaj6arh4p7c5n896xzem5

You should see an output like so

address: terra18vd8fpwxzck93qlwghaj6arh4p7c5n896xzem5
owner: terra1dcegyrekltswvyy0xy69ydgxn9x8x32zdtapd8
codeid: 1
initmsg: eyJjb3VudCI6MH0=
migratable: false

The initmsg is the value we passed during contract creation which is encoded in base64 format. You can decode base64 data here

Lets increment our counter by calling the increment function

terrad tx wasm execute terra18vd8fpwxzck93qlwghaj6arh4p7c5n896xzem5 '{"increment":{}}' --from test1 --chain-id=localterra --gas=auto --fees=1000000uluna --broadcast-mode=block

Lets see if the state has changed. We can use the get_count method to check the value of our count state variable.

terrad query wasm contract-store terra18vd8fpwxzck93qlwghaj6arh4p7c5n896xzem5 '{"get_count":{}}'

You should get the following output:

  count: 1

Great! you have created your first smart contract in Terra protocol.


We have just explored how the terra blockchain development workflow is setup. You can challenge yourself by creating a CW20 Token which is the terra equivalent of Ethereum’s ERC20 standard. You can find out more in the official CW20 documentation. Also checkout more smart contract examples in the offical terra repository.


Leave a Reply

More great articles

How To Contribute To Open Source Crypto Projects

How To Contribute To Open Source Crypto Projects

Open source contributions are a great way to learn, engage and understand how some of the biggest crypto startups actually…

Read Story

How Solana Provides Affordable Daap Scaling

Solana is well positioned providing the infrastructure to support the four pillars of the metaverse: Web 3.0, Decentralized Crypto Trading,…

Read Story

An Introduction to Celo Blockchain

Introducing Celo’s Technology Celo is a blockchain ecosystem focused on increasing cryptocurrency adoption among smartphone users. By using phone numbers…

Read Story

Never miss a minute

Get great content to your inbox every week. No spam.
[contact-form-7 id="6" title="Footer CTA Subscribe Form"]