Skip to content
On this page

GM world rollup ​

🌞 Introduction ​

This tutorial will guide you through building a sovereign gm-world rollup (gm stands for "good morning") using Rollkit. Unlike the quick start guide, this tutorial provides a more practical approach to understanding sovereign rollup development.

We will cover:

  • Building and configuring a Cosmos-SDK application-specific rollup blockchain.
  • Posting rollup data to a Data Availability (DA) network.
  • Executing transactions (the end goal).

No prior understanding of the build process is required, just that it utilizes the Cosmos SDK for blockchain applications.


This tutorial explores Rollkit, currently in Alpha. If you encounter bugs, please report them via a GitHub issue ticket or reach out in our Telegram group.

πŸ› οΈ Dependencies ​

Rollkit uses the Go programming language. Here's how to install it:

  • Linux or macOS: Run the provided script:

    curl -sSL | bash -s go1.22.3

🌐 Running a Local DA Network ​

Learn to run a local DA network, designed for educational purposes, on your machine.

To set up a mock DA network node:

curl -sSL | bash v0.1.0

This script builds and runs the node, now listening on port 7980.

πŸ—οΈ Building Your Sovereign Rollup ​

With the local DA network running, let’s prepare your rollup blockchain.

To make it simple we will download a repository with a gm-world rollup that has an script that does all the setup for you.

Download and build a gm-world rollup with an interactive script in a new terminal:


In order to run it you need to have the jq command line tool installed. You can install it by running sudo apt-get install jq on Ubuntu or brew install jq on macOS.


If you get errors of gmd not found, you may need to add the go/bin directory to your PATH. You can do this by running export PATH=$PATH:$HOME/go/bin and then running the script manually again.

cd $HOME && bash -c "$(curl -sSL"

πŸš€ Starting your rollup ​

Start the rollup, posting to the local DA network:

gmd start --rollkit.aggregator --minimum-gas-prices="0.025stake" --rollkit.da_address http://localhost:7980

Notice how we specified the DA network address along with a few other flags. Now you should see the logs of the running node:

12:21PM INF starting node with ABCI CometBFT in-process module=server
12:21PM INF starting node with Rollkit in-process module=server
12:21PM INF service start impl=multiAppConn module=proxy msg="Starting multiAppConn service"
12:21PM INF service start connection=query impl=localClient module=abci-client msg="Starting localClient service"
12:21PM INF service start connection=snapshot impl=localClient module=abci-client msg="Starting localClient service"
12:21PM INF service start connection=mempool impl=localClient module=abci-client msg="Starting localClient service"
12:21PM INF service start connection=consensus impl=localClient module=abci-client msg="Starting localClient service"
12:21PM INF service start impl=EventBus module=events msg="Starting EventBus service"
12:21PM INF service start impl=PubSub module=pubsub msg="Starting PubSub service"
12:21PM INF Using default mempool ttl MempoolTTL=25 module=BlockManager
12:21PM INF service start impl=IndexerService module=txindex msg="Starting IndexerService service"
12:21PM INF service start impl=RPC module=server msg="Starting RPC service"
12:21PM INF service start impl=Node module=server msg="Starting Node service"
12:21PM INF starting P2P client module=server
12:21PM INF serving HTTP listen address= module=server
12:21PM INF listening on address=/ip4/ module=p2p
12:21PM INF listening on address=/ip4/ module=p2p
12:21PM INF no seed nodes - only listening for connections module=p2p
12:21PM INF working in aggregator mode block time=1000 module=server
12:21PM INF Creating and publishing block height=22 module=BlockManager
12:21PM INF starting gRPC server... address= module=grpc-server
12:21PM INF finalized block block_app_hash=235D3710D61F347DBBBDD6FD63AA7687842D1EF9CB475C712856D7DA32F82F09 height=22 module=BlockManager num_txs_res=0 num_val_updates=0
12:21PM INF executed block app_hash=235D3710D61F347DBBBDD6FD63AA7687842D1EF9CB475C712856D7DA32F82F09 height=22 module=BlockManager
12:21PM INF indexed block events height=22 module=txindex

Good work so far, we have a Rollup node, DA network node, now we can start submitting transactions.

πŸ’Έ Transactions ​

First, list your keys:

gmd keys list --keyring-backend test

You should see an output like the following

- address: gm18k57hn42ujcccyn0n5v7r6ydpacycn2wkt7uh9
  name: gm-key-2
  pubkey: '{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"Al92dlOeLpuAiOUSIaJapkIveiwlhlEdz/O5CrniMdwH"}'
  type: local
- address: gm1e4fqspwdsy0dzkmzsdhkadfcrd0udngw0f88pw
  name: gm-key
  pubkey: '{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"AwdsLY+2US2VV+rbyfi60GB4/Ir/FeTIkLJ3CWVhUF6b"}'
  type: local
- address: gm1vvl79phavqruppr6f5zy4ypxy7znshrqam48qy
  name: gm-relay
  pubkey: '{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"AlnSEnBUv5GO86fMWe11qth1+R76g2e1lv8c1FWhLpqP"}'
  type: local

For convenience we export two of our keys like this:

export KEY1=gm18k57hn42ujcccyn0n5v7r6ydpacycn2wkt7uh9
export KEY2=gm1e4fqspwdsy0dzkmzsdhkadfcrd0udngw0f88pw

Now let's submit a transaction that sends coins from one account to another (don't worry about all the flags, for now, we just want to submit transaction from a high level perspective):

gmd tx bank send $KEY1 $KEY2 42069stake --keyring-backend test --chain-id gm --fees 5000stake

You'll be prompted to accept the transaction:

    amount: []
    gas_limit: "200000"
    granter: ""
    payer: ""
  signer_infos: []
  tip: null
  extension_options: []
  memo: ""
  - '@type': /
    - amount: "42069"
      denom: stake
    from_address: gm18k57hn42ujcccyn0n5v7r6ydpacycn2wkt7uh9 
    to_address: gm1e4fqspwdsy0dzkmzsdhkadfcrd0udngw0f88pw
  non_critical_extension_options: []
  timeout_height: "0"
signatures: []
confirm transaction before signing and broadcasting [y/N]: 

Confirm and sign the transaction as prompted. now you see the transaction hash at the output:


txhash: 677CAF6C80B85ACEF6F9EC7906FB3CB021322AAC78B015FA07D5112F2F824BFF

βš–οΈ Checking Balances ​

Query balances after the transaction:

gmd query bank balances $KEY2

The receiver’s balance should show an increase.

- amount: "10000000000000000000042069" 
  denom: stake
  next_key: null
  total: "0"

For the sender’s balance:

gmd query bank balances $KEY1


- amount: "9999999999999999999957931" 
  denom: stake
  next_key: null
  total: "0"

πŸŽ‰ Next steps ​

Congratulations! You've built a local rollup that posts to a local DA network. So far so good, keep diving deeper if you like it. Good luck!

Released under the APACHE-2.0 License