Vitreus ChainForge
All docs

Reference

Lookup material — pallets, rules, source pointers.

This page is the lookup surface. Tables, anchored entries, terse prose. If you arrived from an error message link elsewhere in the product, scroll straight to that anchor — you don't need to read the whole page.

Page audience: the developer extending a scaffolded project or debugging a failure. If you're a non-developer who landed here from a deep link, the entry you came for should give you what you need; the glossary at the bottom carries plain-English one-liners with links back out to the surfaces that own each term's introduction.

1. Pallet catalogue

Every pallet a shipped template wires, custom or SDK-supplied. The custom pallets are what ChainForge generates per-template; the SDK pallets come through the polkadot-sdk umbrella and the runtime template wires them automatically.

Custom pallets (one per template)

PalletTemplateExtrinsics
pallet_startergenericadd_item, clear_items
pallet_governancetoken-governanceendorse_hash, withdraw_endorsement, prune_account
pallet_prediction_marketprediction-marketcreate_market, place_bet, resolve_market
pallet_marketplacemarketplacelist_item, make_offer, accept_offer, cancel_listing

SDK pallets templates wire

PalletWhere it's wiredCanonical source
pallet_balancestoken-governance, prediction-market, marketplaceparitytech/polkadot-sdk/substrate/frame/balances
pallet_assetsmarketplace.../substrate/frame/assets
pallet_collectivetoken-governance.../substrate/frame/collective
pallet_democracytoken-governance.../substrate/frame/democracy
pallet_preimage, pallet_schedulertoken-governance (referenda machinery).../substrate/frame/preimage, /scheduler
pallet_timestamptoken-governance, prediction-market, marketplace.../substrate/frame/timestamp

Vitreus-canonical pallet repos are pending Foundation confirmation. Until they're fixed, the polkadot-sdk paths above are the reference points the templates link to and the CLAUDE.md fragments cite.

2. Validator rules (Vitreus-specific lints)

The Vitreus lint pass that catches chain-specific issues before testnet is not yet shipped. When it lands, this section will catalogue every rule it enforces — the pattern it matches, why it matters, and the fix template.

For now: The conventions a future validator will lint for already ship inside every generated CLAUDE.md (the “Substrate / Vitreus footguns to avoid” section). Your AI agent reads them on every prompt; you can apply the same rules during code review. The footguns section below lifts the load-bearing ones to plain English for the human reader.

3. Footguns and recovery

The mistakes that bite real chains in production. Each entry has a stable anchor so failure cards and CLAUDE.md fragments can deep-link straight to the fix.

#weight-zero · Zero-weight dispatchable

Symptom: #[pallet::weight(0)] or #[pallet::weight(Weight::zero())] ships to a chain that charges fees. Every caller pays zero — a free DoS vector.

Root cause: The macro accepts the literal zero and compiles it through; no compile error, no warning. Looks like a placeholder but isn't.

Fix: Use #[pallet::weight(T::WeightInfo::<extrinsic>())] with a benchmarked WeightInfo impl. For developer iteration, the () placeholder impl in the shipped templates uses Weight::from_parts(15_000, 0) — non-zero, clearly placeholder, replaced before any fee-charging deployment.

#unbounded-vec · Unbounded Vec in storage

Symptom: StorageValue<_, Vec<u32>, ValueQuery>. An attacker fills the Vec until reads exceed the runtime weight budget; the chain stalls.

Fix: Use BoundedVec — bounded storage; the type carries its own cap, and the compiler refuses to let you forget to check the length:

StorageValue<_, BoundedVec<u32, T::MaxItems>, ValueQuery>

#missing-decode-with-mem-tracking · Missing DecodeWithMemTracking derive

Symptom: error[E0277]: the trait bound `<YourType>: DecodeWithMemTracking` is not satisfied on a custom enum or struct used in storage / events / extrinsic args.

Root cause: polkadot-sdk stable2603 requires every SCALE-decodable type used in dispatchable arguments or events to derive DecodeWithMemTracking alongside Decode. Not auto-implied, not in the prelude.

Fix: Add codec::DecodeWithMemTracking to the derive list:

#[derive(
    Clone, PartialEq, Eq, Debug,
    codec::Encode, codec::Decode, codec::DecodeWithMemTracking, codec::MaxEncodedLen,
    scale_info::TypeInfo,
)]

#missing-call-index · Missing call_index

Symptom: The FRAME macro refuses to expand without a #[pallet::call_index(N)] on every dispatchable.

Why it matters: Call indices are part of the API. Reordering or removing dispatchables without keeping indices stable breaks every signed extrinsic in flight on a live chain. Treat them like storage keys.

#mutate-instead-of-try-mutate · Using mutate where try_mutate is needed

Symptom: A storage closure that can fail uses Items::mutate instead of Items::try_mutate. The closure's Err gets swallowed; with BoundedVec::try_push the storage write panics on overflow.

Fix: try_mutate propagates the closure's error; the extrinsic returns it cleanly as a DispatchError.

#legacy-currency-reserve · Legacy Currency::reserve / transfer

Symptom: Code uses Currency::reserve or Currency::transfer on native balances. The trait family is deprecated; the future validator will flag.

Fix: Use the modern fungible::Mutate and fungible::MutateHold traits. The prediction-market template's place_bet extrinsic is the canonical example: stake held under a composite HoldReason::BetStake, released on resolution via NativeBalance::release.

#anonymous-extrinsic · Missing origin check

Symptom: A dispatchable mutates storage without calling ensure_signed or ensure_root (or a Config-trait origin guard). Anyone can fire it.

Fix: Always check origin. Default to let who = ensure_signed(origin)?; at the top of every dispatchable that writes. For root-only paths, ensure_root(origin)?. For seam-gated paths (oracle / multisig / council), an associated-type EnsureOrigin on Config — see the prediction-market template's ResolveOrigin.

4. Vitreus source pointers

When the CLAUDE.md fragments say “go read the canonical source,” this section is the map. By topic, with file paths.

Vitreus-canonical pallet repos are pending Foundation confirmation. Until they're published, the polkadot-sdk paths below are the working source of truth — Vitreus pallets follow the same conventions.

TopicWhere to look
FRAME macros, pallet shape, traitssubstrate/frame/support
Native token + holdssubstrate/frame/balances
Multi-asset registrysubstrate/frame/assets
Council / committee patternssubstrate/frame/collective
Referenda / public votingsubstrate/frame/democracy
NFTs (marketplace swap-target)substrate/frame/nfts
Timestamp (ambient)substrate/frame/timestamp

5. CLI reference

Commands the platform expects you to run locally. Flags that actually matter, not exhaustive option dumps.

Cargo (in your scaffold)

cargo check
Compile the project without producing a binary. Fastest way to confirm the code is well-formed. Run from the workspace root.
cargo build --release --target wasm32-unknown-unknown
Compile the runtime to a WASM blob. Run from runtime/ (or use -p chainforge-<template>-runtime from the workspace root). The resulting .wasm file in target/ is what the relay chain stores and executes.
cargo test
Run the unit tests. Most pallets in the shipped templates don't ship tests yet; this is forward-shaped scaffolding.

Substrate / polkadot-sdk tooling

substrate build-spec --raw > chain-spec.raw.json
Generate the raw chain spec from your project's chain_spec.rs. Run inside a clone of substrate-node-template that's been pointed at your runtime.
node-template --chain chain-spec.raw.json --base-path /tmp/<name>
Launch a node against your chain spec. Add --validator --alice for dev-validator mode in a single-node setup.

6. Configuration knobs and version pins

The pins and constants the shipped templates carry. Tune the constants in your project's runtime/src/lib.rs parameter_types! block; the pins live in the workspace Cargo.toml.

Version pins (all templates)

polkadot-sdk
2603.0.0 (polkadot-stable2603 release line).
Rust toolchain
channel 1.93, pinned via rust-toolchain.toml.
codec / scale-info
parity-scale-codec 3.6 / scale-info 2.11.

Per-template constants (defaults)

These are the ConstU32 / ConstU128 values each runtime wires. The defaults are sane for dev; tune before any deployment that processes real volume.

TemplateConstantDefault
genericMaxItems32
token-governanceMaxProposalsPerAccount32
prediction-marketMaxQuestionLen256 bytes
prediction-marketMaxBetsPerMarket32
prediction-marketMinStake1_000 plancks
marketplaceMaxOffersPerListing64
marketplaceMinPrice1_000 plancks

7. Running the validator in CI

If you're wiring the validator into a CI pipeline — running it as a gate before pushes, in pull-request checks, or as a pre-commit hook — the existing /api/validate and /api/validate/git endpoints are the CI surface. No separate endpoint to script against, no special format flag. The JSON response is structured for both human reading and machine parsing.

The load-bearing field for a CI gate is summary.pass true when no high-severity findings remain after filters apply, false otherwise. Wire pass to your job's exit code and you have a working gate.

7.1 — Worked example: paste mode

RESPONSE=$(curl -s -X POST https://chainforge.build/api/validate \
  -H "Content-Type: application/json" \
  -H "Cookie: chainforge_session=$CHAINFORGE_SESSION" \
  -d "$(jq -n --arg src "$(cat pallets/pallet_starter/src/lib.rs)" '{source: $src}')")

PASS=$(echo "$RESPONSE" | jq -r '.summary.pass')
if [ "$PASS" = "true" ]; then
  echo "✓ Validator passed"
  exit 0
fi

echo "✗ Validator failed:"
echo "$RESPONSE" | jq -r '.findings[] | "  [\(.severity)] \(.file):\(.line) \(.rule_id) — \(.reason)"'
exit 1

The session cookie comes from a logged-in browser session today (extract via document.cookie in DevTools, paste into a CI secret). API-key auth for CI is a planned addition; the cookie approach is the current state.

7.2 — Worked example: git mode

RESPONSE=$(curl -s -X POST https://chainforge.build/api/validate/git \
  -H "Content-Type: application/json" \
  -H "Cookie: chainforge_session=$CHAINFORGE_SESSION" \
  -d "$(jq -n --arg url "$GIT_URL" --arg ref "$GITHUB_SHA" '{git_url: $url, ref: $ref}')")

PASS=$(echo "$RESPONSE" | jq -r '.summary.pass')
[ "$PASS" = "true" ] || { echo "$RESPONSE" | jq '.findings'; exit 1; }

$GITHUB_SHA is the canonical “validate this exact commit” pattern in GitHub Actions. Substitute the equivalent for other CI providers.

7.3 — Tuning the gate with filters

Two filter parameters let CI gates be specific about what they fail on:

  • rule_ids — allowlist of rule_id strings. Pass ["unbounded_vec", "weight_zero"] to gate only on those two rules; everything else gets reported but doesn't fail the gate. Passing an empty list ([]) gates on nothing — all findings drop. Omit the field entirely to apply no rule filter.
  • min_severity — severity floor. "high" keeps only high-severity findings; "medium" keeps high + medium; "low" and "info" are progressively more permissive.

Both filters apply before summary.pass is computed, so the gate reflects the filtered view, not the unfiltered catalog.

When constructing bookmarkable filter URLs in the browser, use ?rules= (the URL form); when constructing API request bodies, use rule_ids (the API form). Same meaning, different field name.

Example — fail only on high-severity findings, ignore everything else:

curl -s -X POST https://chainforge.build/api/validate/git \
  -H "Content-Type: application/json" \
  -H "Cookie: chainforge_session=$CHAINFORGE_SESSION" \
  -d '{"git_url": "https://github.com/owner/repo", "min_severity": "high"}' \
  | jq '.summary.pass'

7.4 — Exit codes

The validator endpoints return HTTP status codes, not exit codes — the CI script translates HTTP → exit. Typical patterns:

  • HTTP 200 + summary.pass == true → exit 0
  • HTTP 200 + summary.pass == false → exit 1 (gate fail)
  • HTTP 422 → exit 2 (request invalid: bad URL, bad ref, malformed filter params)
  • HTTP 503 → exit 3 (validator infrastructure issue: clone failed, sandbox unavailable)

The detail field on non-200 responses carries a user-facing message safe to echo in CI logs.

8. Glossary

One-line definitions for every load-bearing term the four guides, the FAQ, the scaffold form, and the rendered CLAUDE.md introduce. Alphabetical. Each entry cross-links to the surface that owns the term's first-appearance layering, so if you want the full plain-English introduction you can follow the link out.

BoundedVec
Bounded storage; the type carries its own cap. The compiler refuses to let you forget to check the length. Use everywhere Vec would be tempting in storage. See footguns #unbounded-vec.
cargo / cargo check
Rust's build tool; cargo check verifies a project compiles without producing a binary. First-introduced in getting started, step 4.
chain spec
The configuration your chain starts with — who has tokens at block zero, what the chain calls itself, what network it joins. First-introduced in deploying §2.
clone (verb)
To make a working copy of a remote repository on your machine. Standard command is git clone <url>. First-introduced in getting started, step 4.
collator
The node software that runs your chain and submits its blocks to the relay chain. Different role from a validator — validators run the relay; collators run your chain. First laid out in deploying §4.
dispatch error
What a Substrate extrinsic returns when it fails. Each dispatch error has a module + index + name; the failure card maps them to plain-English copy.
extrinsic
A signed transaction in Substrate — the unit a user submits to change chain state. Signed by an account (so the chain knows who pays); the chain runs the dispatchable, which either succeeds or returns a dispatch error.
genesis
The formal name for “block zero” — the state the chain starts with. Configured by the chain spec. First-introduced in deploying §2.
pallets
The building blocks the scaffold generator wires up — each pallet provides a focused unit of chain behaviour (balances, governance, your custom logic). Composable via the runtime. First-introduced on the scaffold form helper.
parachain
A chain that lives inside a larger network (Vitreus, for ChainForge projects). The larger network handles security, finality, validator economics; your chain inherits the rest. First-introduced on the FAQ.
polkadot.js apps
The official browser UI for talking to any Substrate chain. What you use to sign extrinsics and watch blocks when there's no chain-specific UI yet. First-introduced in deploying §5.
relay chain
The Vitreus relay handles the heavy-duty pieces — security, finality, validator economics. Your parachain joins it as a tenant. First-introduced in deploying §4.
runtime
The state-transition logic of your chain. Compiles to a WASM blob the relay chain stores and executes. Upgradable without a redeploy. First-introduced in the rendered CLAUDE.md + the FAQ.
runtime upgrade
Replacing the runtime WASM blob in storage via a single transaction. The chain switches to the new logic at the next block. Not a redeploy.
signed extrinsic
An extrinsic that carries a signature from an account — the chain knows who's paying for it. The standard form most user-facing actions take.
Substrate parachain
A parachain built on Substrate (the framework Vitreus uses). What ChainForge generates. First-introduced in the rendered CLAUDE.md.
substrate-node-template
The upstream Substrate project that ships a working node binary. The current-state manual path for running your scaffolded runtime: clone it, point its runtime dep at your project, build.
testnet faucet
A service that gives out test tokens for free. You need a small amount to sign the registration extrinsic when putting your chain on testnet. Vitreus testnet faucet URL pending Foundation confirmation.
validator
A node running the relay chain itself. Validators secure the relay; they don't run your chain (collators do that).
WASM / WASM blob
WebAssembly bytecode. Substrate runtimes compile to WASM so the relay chain can store and execute them. First- introduced in deploying §3.
WeightInfo / Weight::from_parts
The benchmarked weight estimate for a dispatchable; what tells the chain how much CPU/storage a call costs. The shipped templates use placeholder values; replace before any fee-charging deployment. See footguns #weight-zero.