Substrate & ink!
Build blockchains with Substrate FRAME pallets and smart contracts with ink! - Rust-native Web3 infrastructure.
Recipe
Minimal ink! contract skeleton:
#[ink::contract]
mod flipper {
#[ink(storage)]
pub struct Flipper {
value: bool,
}
impl Flipper {
#[ink(constructor)]
pub fn new(init: bool) -> Self {
Self { value: init }
}
#[ink(message)]
pub fn flip(&mut self) {
self.value = !self.value;
}
#[ink(message)]
pub fn get(&self) -> bool {
self.value
}
}
}When to reach for this:
- Launching a custom L1/L2 with tailored consensus and fees
- Polkadot/Kusama parachains or solochains
- Wasm contracts when EVM is not required
Working Example
Pallet storage and dispatch pattern (conceptual FRAME snippet):
#[frame_support::pallet]
pub mod pallet {
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*;
#[pallet::pallet]
pub struct Pallet<T>(_);
#[pallet::config]
pub trait Config: frame_system::Config {}
#[pallet::storage]
pub type Value<T> = StorageValue<_, u32, ValueQuery>;
#[pallet::call]
impl<T: Config> Pallet<T> {
#[pallet::call_index(0)]
#[pallet::weight(10_000)]
pub fn set(origin: OriginFor<T>, v: u32) -> DispatchResult {
ensure_signed(origin)?;
<Value<T>>::put(v);
Ok(())
}
}
}What this demonstrates:
- Storage items typed and namespaced per pallet
ensure_signedauthorization guard- Weight annotation for block limits
Deep Dive
How It Works
- Substrate node runs networking, consensus, and Wasm runtime executor.
- Runtime is compiled Wasm blob upgraded via
set_codegovernance. - ink! contracts deploy to
pallet-contractswith rent and storage trie. - Extrinsics are transactions; storage uses efficient key-value maps.
Substrate vs ink!
| Layer | Responsibility |
|---|---|
| FRAME pallet | Chain logic, tokens, governance |
| ink! contract | User-deployed app logic on chain |
Gotchas
- Runtime bloating - too many pallets increases Wasm size and compile time. Fix: feature-gate experimental pallets.
- Storage unbounded growth - maps without deposit fees spam chain. Fix: charge rent or require bonds per entry.
- ink! panic becomes revert - no Rust panic recovery on-chain. Fix: return
Resultfrom messages, avoidunwrap. - Weight underestimation - blocks full, chain stalls. Fix: benchmark with
frame_benchmarking. - Off-chain worker trust - unsigned submissions need validation. Fix: verify signatures and staleness on-chain.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
| Solana programs | Deploy on existing high-TPS chain | Need custom consensus |
| Cosmos SDK (Go) | Team Go-heavy | Want Rust end-to-end |
| Hardhat Solidity | EVM liquidity | Custom Substrate runtime features |
| Rollup framework | Ethereum security | Standalone L1 requirements |
FAQs
Substrate vs ink! first?
Chain-level rules in pallets; user apps in ink! if contracts pallet enabled on runtime.
Local dev node?
substrate-node-template or pop up for local chain with instant blocks for tests.
How are upgrades done?
Governance proposal calls set_code with new Wasm runtime - plan migration storage hooks.
ink! vs Solidity?
ink! is Rust/Wasm; tooling smaller than EVM but fits Polkadot ecosystem.
Testing ink!?
#[ink::test] unit tests run on host; integration needs substrate-contracts-node.
XCM cross-chain?
Polkadot parachains use XCM for asset messaging - separate learning path from basic pallet.
Fees and weights?
Transaction payment pallet charges based on weight and length; benchmark honestly.
Storage deposits?
#[ink(storage)] fields cost rent; design minimal state per contract instance.
Consensus choice?
Aura/BABE/GRANDPA etc. depend on node template - solochain vs parachain differs.
Security?
Audit pallet dispatchables and ink! messages - see Security & Auditing.
Related
- Blockchain Basics in Rust - hashing and keys
- Consensus & P2P - networking layer
- Applied Cryptography - crypto primitives
- Solana Programs - alternative on-chain model
Stack versions: This page was written for Rust 1.97.0 (edition 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, and Polars 0.46+.