Appchain development on Cosmos SDK

We design and develop full-cycle blockchain solutions: from smart contract architecture to launching DeFi protocols, NFT marketplaces and crypto exchanges. Security audits, tokenomics, integration with existing infrastructure.
Showing 1 of 1 servicesAll 1306 services
Appchain development on Cosmos SDK
Complex
from 2 weeks to 3 months
FAQ
Blockchain Development Services
Blockchain Development Stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1217
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    852
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1046
  • image_logo-advance_0.png
    B2B Advance company logo design
    561
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    823

Appchain Development on Cosmos SDK

The question "why not Ethereum L2" comes up first, and it needs an honest answer. Ethereum L2 (Arbitrum, Optimism, zkSync) gives you someone else's virtual machine, someone else's gas token, someone else's sequencer, someone else's rules. Cosmos SDK appchain — is your blockchain: own consensus, own gas token, own governance, own validation rules. The price — full responsibility for security and decentralization of validator set. For most applications, L2 is the right choice. For cases where you need full control over protocol economics, data sovereignty, or specialized consensus mechanisms — Cosmos SDK.

Cosmos SDK architecture

Modular structure

Cosmos SDK is built on modules. Each module is an isolated component with its own state (in IAVL tree), message types (Msgs), queries (Queries), and lifecycle hooks:

Application
├── x/auth          — accounts and signatures
├── x/bank          — token transfers
├── x/staking       — validator set, delegation
├── x/distribution  — staking rewards distribution
├── x/gov           — on-chain governance
├── x/slashing      — validator misbehavior penalties
├── x/ibc           — IBC protocol
└── x/yourapp       — your business logic

Your custom module lives in x/yourapp. This is where all your logic is.

Consensus: CometBFT (formerly Tendermint)

CometBFT — BFT consensus with instant finality. This is the key difference from PoW: if a block is committed — it's final, no fork risk. Finality latency: ~1–6 seconds depending on configuration and validator set size.

Limitations: BFT consensus requires >2/3 of voting stake online for liveness. At < 33% online — network stops (safety over liveness). This is a conscious trade-off.

Maximum practical validator set: 150–300 validators. More — network slows due to communication overhead in BFT round.

Custom module development

Module structure

x/
└── mymodule/
    ├── keeper/
    │   ├── keeper.go          — business logic, state access
    │   ├── msg_server.go      — transaction handlers
    │   └── query_server.go    — query handlers
    ├── types/
    │   ├── msgs.go            — message types
    │   ├── genesis.go         — initial state
    │   └── params.go          — module parameters (governance-managed)
    ├── module.go              — module registration
    └── proto/
        └── mymodule/          — Protobuf definitions

Keeper and state management

State is stored in IAVL tree via KVStore. Keeper is the only access point to state:

type Keeper struct {
    cdc        codec.BinaryCodec
    storeKey   storetypes.StoreKey
    bankKeeper types.BankKeeper    // dependency on bank module
    authKeeper types.AccountKeeper
}

func (k Keeper) SetOrder(ctx sdk.Context, order types.Order) {
    store := ctx.KVStore(k.storeKey)
    bz := k.cdc.MustMarshal(&order)
    store.Set(types.OrderKey(order.Id), bz)
}

func (k Keeper) GetOrder(ctx sdk.Context, id uint64) (types.Order, bool) {
    store := ctx.KVStore(k.storeKey)
    bz := store.Get(types.OrderKey(id))
    if bz == nil {
        return types.Order{}, false
    }
    var order types.Order
    k.cdc.MustUnmarshal(bz, &order)
    return order, true
}

Important: in Cosmos SDK there is no "transaction failed, state rolled back" in the EVM sense. If msg_server returns error, gas is burned but state unchanged. If returns nil — state changed and it's final. So all checks must come before state changes.

Msg Server: transaction handling

func (k msgServer) CreateOrder(
    goCtx context.Context, 
    msg *types.MsgCreateOrder,
) (*types.MsgCreateOrderResponse, error) {
    ctx := sdk.UnwrapSDKContext(goCtx)
    
    // 1. Validation
    if msg.Amount.IsZero() {
        return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "amount cannot be zero")
    }
    
    // 2. Check balance and lock funds
    err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, msg.Creator, types.ModuleName, sdk.NewCoins(msg.Amount))
    if err != nil {
        return nil, sdkerrors.Wrap(sdkerrors.ErrInsufficientFunds, err.Error())
    }
    
    // 3. State change
    order := types.Order{
        Id:        k.GetNextOrderID(ctx),
        Creator:   msg.Creator,
        Amount:    msg.Amount,
        CreatedAt: ctx.BlockTime().Unix(),
    }
    k.SetOrder(ctx, order)
    k.IncrementOrderID(ctx)
    
    // 4. Events for clients
    ctx.EventManager().EmitEvent(sdk.NewEvent(
        types.EventTypeCreateOrder,
        sdk.NewAttribute(types.AttributeOrderID, fmt.Sprintf("%d", order.Id)),
        sdk.NewAttribute(types.AttributeCreator, msg.Creator),
    ))
    
    return &types.MsgCreateOrderResponse{OrderId: order.Id}, nil
}

BeginBlock / EndBlock hooks

Powerful mechanism: execute logic every block without external trigger. Examples:

  • Order matching — match orders at end of each block (DEX without matching gas)
  • Liquidations — check position health and liquidate if needed
  • Epoch transitions — staking epoch transitions, reward distribution
  • Oracle price updates — aggregating data from validators
func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate {
    keeper.ProcessExpiredOrders(ctx)
    keeper.MatchPendingOrders(ctx)
    return []abci.ValidatorUpdate{}
}

This is fundamentally impossible in EVM without external keeper bots — no native cron there.

IBC: inter-blockchain communication

IBC (Inter-Blockchain Communication Protocol) — killer feature of Cosmos. Allows sending tokens and arbitrary data between chains without bridge (trustless, via light client verification).

ICS-20: token transfer

Simplest IBC use case — transfer tokens between chains:

// Send tokens from your chain to Osmosis
transfer := channeltypes.NewMsgTransfer(
    "transfer",           // port
    "channel-0",          // channel to Osmosis
    sdk.NewCoin("uatom", amount),
    sender,
    receiver,
    timeoutHeight,
    timeoutTimestamp,
    "memo",
)

Recipient in Osmosis sees token as ibc/HASH — "wrapped" version of your token. For "native" representation you need ICS-20 + custom denom alias.

Custom IBC packets

For sending arbitrary logic between chains — custom IBC packets:

// Send arbitrary data
packet := channeltypes.NewPacket(
    modulePacketData, // your data, serialized to protobuf
    sequence,
    sourcePort, sourceChannel,
    destPort, destChannel,
    timeoutHeight, timeoutTimestamp,
)

Receiving chain verifies Merkle proof that packet was committed on sending chain — this is trustless, no oracle needed.

IBC latency: depends on block times of both chains and relayer speed. Usually 10–30 seconds for Cosmos-to-Cosmos transfer.

Relayer infrastructure

IBC packets don't deliver themselves — relayers needed. These are off-chain processes that read packets from one chain and submit them to another.

Two main implementations: Hermes (Rust, high performance) and Go relayer. For production — Hermes.

Hermes configuration for your chain → Osmosis:

[[chains]]
id = "yourchain-1"
rpc_addr = "http://localhost:26657"
grpc_addr = "http://localhost:9090"
key_name = "relayer"

[[chains]]
id = "osmosis-1"
rpc_addr = "https://osmosis-rpc.polkachu.com"
grpc_addr = "https://osmosis-grpc.polkachu.com:12590"
key_name = "relayer-osmosis"

Relayer should have tokens on both chains for gas. For mainnet — balance monitoring and auto-refill critical.

Governance and parameters

On-chain governance — one reason to choose Cosmos. Change protocol parameters through token holder voting:

// Module parameters, changeable via governance
type Params struct {
    MinOrderSize  sdk.Coin `json:"min_order_size"`
    TradingFeeRate sdk.Dec `json:"trading_fee_rate"`
    MaxOrdersPerBlock uint64 `json:"max_orders_per_block"`
}

Proposal → Deposit period → Voting period (usually 14 days) → Execution. If >50% of stake votes yes — parameters change automatically.

Testnet and launch

Localnet for development:

ignite chain serve  # Ignite CLI — quick start
# or
./scripts/run_node.sh  # custom initialization script

Public testnet:

  • Genesis file with initial validators
  • Faucet for test tokens
  • Explorer (Mintscan, Ping.pub) for visibility

Mainnet launch:

  1. Genesis parameters — discussed publicly
  2. Gentx from initial validators (each creates create-validator transaction)
  3. Collect gentx, form genesis.json
  4. Synchronous node launch by validators at genesis time

Validator onboarding: need to attract sufficiently decentralized and reliable validators. For serious mainnet — minimum 20–30 independent validators with geographic and jurisdictional diversification.

Stack and tools

Component Technology
Framework Cosmos SDK v0.50.x
Consensus CometBFT v0.38.x
Language Go 1.21+
Scaffolding Ignite CLI
Protobuf buf + cosmos-proto
Testing Go testing + simapp
Explorer Mintscan (Cosmostation) or custom
Relayer Hermes (Informal Systems)
Monitoring Prometheus + Grafana + Cosmos-specific dashboards

Development timeline for custom appchain with one-two business modules, IBC, governance: 4–7 months to testnet, +2–3 months to mainnet.