Full lesson
carbon
Carbon is an indexing framework on Solana.
What it does
From the project README:
Carbon is built around a pipeline: datasources stream Solana updates into the runtime, decoders turn raw account and transaction data into typed Rust structures, and processors handle the decoded output in order to build data pipelines and indexers for your applications. Each part is modular, so you can swap RPC streams for Geyser streams, generated decoders for custom ones, or logging processors for Postgres, GraphQL, analytics, bots, and other application-specific sinks.
- Original
- sevenlabs-hq/carbon
- SuperStack fork
- Blockchains/carbon @
bebd108 - Stars
- 638
- Last push (original)
- 2026-11-02
- Languages
- Rust, TypeScript, Nunjucks, JavaScript, Shell
- Detected stack
- Native Rust
- Categories
- DeFiInfrastructure & Tooling
- Licence
- MIT
Architecture
11233 source files. By extension: .rs ×11192, .ts ×41.
| Top-level directory | Source files |
|---|---|
decoders | 11111 |
packages | 41 |
crates | 35 |
examples | 24 |
datasources | 18 |
metrics | 2 |
misc | 2 |
Dapp: deploying
This fork is queued for its own live dapp on Sol.College, with a Devnet/Mainnet switch. It appears here, at /dapps/carbon/, once it is deployed and checked on devnet. Until then, run it locally with the commands below.
Key code, explained
Excerpts chosen automatically where the code uses the most Solana concepts, pinned to the fork's commit.
decoders/token-2022-decoder/src/instructions/mod.rs L121–144 @ bebd108 · MIT · original initialize_token_group_member::*, initialize_token_metadata::*, initialize_transfer_fee_config::*, initialize_transfer_hook::*, mint_to::*, mint_to_checked::*, pause::*, permissioned_burn::*, permissioned_burn_checked::*, reallocate::*, remove_token_metadata_key::*, resume::*, revoke::*, set_authority::*, set_transfer_fee::*, sync_native::*, thaw_account::*, transfer::*, transfer_checked::*, transfer_checked_with_fee::*, ui_amount_to_amount::*, unwrap_lamports::*, update_confidential_transfer_mint::*, update_default_account_state::*, update_group_member_pointer::*, update_group_pointer::*, update_metadata_pointer::*, update_multiplier_scaled_ui_mint::*, update_rate_interest_bearing_mint::*, update_token_group_max_size::*, update_token_group_update_authority::*, update_token_metadata_field::*, update_token_metadata_update_authority::*, update_transfer_hook::*, withdraw_excess_lamports::*, withdraw_withheld_tokens_from_accounts::*, withdraw_withheld_tokens_from_accounts_for_confidential_transfer_fee::*, withdraw_withheld_tokens_from_mint::*, withdraw_withheld_tokens_from_mint_for_confidential_transfer_fee::*,}; #[derive(Debug, Clone, PartialEq)]#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]#[cfg_attr(feature = "serde", serde(tag = "type", content = "data"))]pub enum Token2022Instruction { AmountToUiAmount { program_id: solana_pubkey::Pubkey,- Line 122
initialize_transfer_fee_config::*, initialize_transfer_hook::*, mint_to::*, mint_to_checke: Mints new tokens. The mint authority must sign. - Line 125
sync_native::*, thaw_account::*, transfer::*, transfer_checked::*,: A checked token transfer, which also verifies the mint and decimals. - Line 142
pub enum Token2022Instruction {: Targets the Token-2022 program instead of the original Token Program.
decoders/token-2022-decoder/src/instructions/postgres/mod.rs L337–360 @ bebd108 · MIT · original let row = thaw_account_row::ThawAccountRow::from_parts(data.clone(), metadata.clone(), raw_accounts.clone()); row.insert(pool).await?; Ok(()) } Token2022Instruction::TransferChecked { data, .. } => { let row = transfer_checked_row::TransferCheckedRow::from_parts(data.clone(), metadata.clone(), raw_accounts.clone()); row.insert(pool).await?; Ok(()) } Token2022Instruction::ApproveChecked { data, .. } => { let row = approve_checked_row::ApproveCheckedRow::from_parts(data.clone(), metadata.clone(), raw_accounts.clone()); row.insert(pool).await?; Ok(()) } Token2022Instruction::MintToChecked { data, .. } => { let row = mint_to_checked_row::MintToCheckedRow::from_parts(data.clone(), metadata.clone(), raw_accounts.clone()); row.insert(pool).await?; Ok(()) } Token2022Instruction::BurnChecked { data, .. } => { let row = burn_checked_row::BurnCheckedRow::from_parts(data.clone(), metadata.clone(), raw_accounts.clone()); row.insert(pool).await?; Ok(()) }- Line 341
Token2022Instruction::TransferChecked { data, .. } => {: A checked token transfer, which also verifies the mint and decimals. - Line 341
Token2022Instruction::TransferChecked { data, .. } => {: Targets the Token-2022 program instead of the original Token Program. - Line 351
Token2022Instruction::MintToChecked { data, .. } => {: Mints new tokens. The mint authority must sign.
decoders/jupiter-perpetuals-decoder/src/accounts/stake_info.rs L1–24 @ bebd108 · MIT · original//! This code was AUTOGENERATED using the Codama library.use solana_pubkey::Pubkey; #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]#[derive(Debug, Clone, borsh::BorshSerialize, borsh::BorshDeserialize, PartialEq)]pub struct StakeInfo { pub pool: Pubkey, pub stake_account: Pubkey, pub current_staked_amount_lamports: u64, pub total_staking_rewards_lamports: u64, pub last_updated_at: i64, pub deactivating: bool, pub stake_account_index: u64, pub bump: u8,} impl StakeInfo { pub fn decode(data: &[u8]) -> Option<Self> { if data.len() < 8 { return None; } let discriminator = &data[0..8]; if discriminator != [66, 62, 68, 70, 108, 179, 183, 235] { return None;- Line 10
pub total_staking_rewards_lamports: u64,: Touches staking state: the amount locked and when it was locked. - Line 14
pub bump: u8,: Uses the bump seed, the extra byte that pushes the derived address off the ed25519 curve.
decoders/jupiter-perpetuals-decoder/src/accounts/postgres/stake_info_row.rs L1–24 @ bebd108 · MIT · original//! This code was AUTOGENERATED using the Codama library.use carbon_core::{ account::AccountMetadata, postgres::{ metadata::AccountRowMetadata, primitives::{Pubkey, U64, U8}, },}; #[derive(sqlx::FromRow, Debug, Clone)]pub struct StakeInfoRow { #[sqlx(flatten)] pub account_metadata: AccountRowMetadata, pub pool: Pubkey, pub stake_account: Pubkey, pub current_staked_amount_lamports: U64, pub total_staking_rewards_lamports: U64, pub last_updated_at: i64, pub deactivating: bool, pub stake_account_index: U64, pub bump: U8,} impl StakeInfoRow {- Line 17
pub total_staking_rewards_lamports: U64,: Touches staking state: the amount locked and when it was locked. - Line 21
pub bump: U8,: Uses the bump seed, the extra byte that pushes the derived address off the ed25519 curve.
How to run, build and test
These commands come from the repo's own manifests (package.json scripts, Anchor.toml, Cargo, go.mod, Makefile). Check the README for prerequisites and environment variables.
| Directory | Command | Runs |
|---|---|---|
. | npm run dev | turbo run dev |
. | npm run build | turbo run build |
. | npm run test | turbo run test |
. | npm run lint | turbo run lint |
packages/renderer | npm run dev | tsup --watch |
packages/renderer | npm run build | tsup && cp -r templates dist/ |
packages/renderer | npm run test | node --test tests/*.test.mjs |
packages/renderer | npm run lint | echo 'No linting configured' |
packages/versions | npm run dev | tsup --watch |
packages/versions | npm run build | tsup |
packages/versions | npm run test | node --test tests/*.test.mjs |
packages/cli | npm run dev | tsup --watch |
packages/cli | npm run build | tsup |
packages/cli | npm run test | node --test tests/*.test.mjs |
. | cargo build | Rust workspace build |
. | cargo test | Rust tests |
What you could build from it
- Fork the SuperStack copy and extend it within the DeFi gaps listed on the idea page.
- Learn the pattern first: Program Derived Addresses (PDAs)
- Learn the pattern first: Cross-Program Invocations (CPIs)
- Learn the pattern first: SPL Tokens: mints, accounts and transfers