From 07dcfbb009619cdb9e5c6047cdf6eb85129c34f4 Mon Sep 17 00:00:00 2001 From: Mike MacCana Date: Thu, 5 Nov 2026 22:52:32 +0000 Subject: [PATCH] Remove the repository-layout example Anchor 1.0 and later scaffold a multi-file program by default (`anchor init` writes lib.rs, constants.rs, error.rs, instructions.rs with an instructions/ directory, and state.rs), so the Anchor v1 and v2 copies teach what every new Anchor project already has. Quasar's starter is a single lib.rs, but 34 of the 56 Quasar programs here already use the lib.rs / error.rs / state.rs / instructions/ layout, escrow and counter among them, so the Quasar copy adds nothing either. Pinocchio and native alone do not justify keeping it. Drops the directory, its README entry, its workspace members, its entry in the Quasar README generator, and a mention in a comment in the CPI example; refreshes Cargo.lock. Claude-Session: https://claude.ai/code/session_01GZHin7uZN95tCycB2vWhog --- Cargo.lock | 80 +-------- Cargo.toml | 3 - README.md | 6 - .../hand/src/instructions/pull_lever.rs | 6 +- basics/repository-layout/README.md | 7 - .../repository-layout/anchor-v1/Anchor.toml | 16 -- .../repository-layout/anchor-v1/CHANGELOG.md | 5 - basics/repository-layout/anchor-v1/Cargo.toml | 14 -- basics/repository-layout/anchor-v1/README.md | 40 ----- .../anchor-v1/programs/carnival/Cargo.toml | 32 ---- .../anchor-v1/programs/carnival/Xargo.toml | 2 - .../anchor-v1/programs/carnival/src/error.rs | 17 -- .../carnival/src/instructions/eat_food.rs | 38 ---- .../carnival/src/instructions/get_on_ride.rs | 54 ------ .../programs/carnival/src/instructions/mod.rs | 3 - .../carnival/src/instructions/play_game.rs | 44 ----- .../anchor-v1/programs/carnival/src/lib.rs | 63 ------- .../programs/carnival/src/state/food.rs | 25 --- .../programs/carnival/src/state/game.rs | 29 --- .../programs/carnival/src/state/mod.rs | 3 - .../programs/carnival/src/state/ride.rs | 28 --- .../programs/carnival/tests/test_carnival.rs | 169 ------------------ basics/repository-layout/anchor/Anchor.toml | 16 -- basics/repository-layout/anchor/CHANGELOG.md | 5 - basics/repository-layout/anchor/Cargo.toml | 14 -- basics/repository-layout/anchor/README.md | 40 ----- .../anchor/programs/carnival/Cargo.toml | 55 ------ .../anchor/programs/carnival/Xargo.toml | 2 - .../anchor/programs/carnival/src/error.rs | 17 -- .../carnival/src/instructions/eat_food.rs | 38 ---- .../carnival/src/instructions/get_on_ride.rs | 54 ------ .../programs/carnival/src/instructions/mod.rs | 3 - .../carnival/src/instructions/play_game.rs | 44 ----- .../anchor/programs/carnival/src/lib.rs | 63 ------- .../programs/carnival/src/state/food.rs | 25 --- .../programs/carnival/src/state/game.rs | 29 --- .../anchor/programs/carnival/src/state/mod.rs | 3 - .../programs/carnival/src/state/ride.rs | 28 --- .../programs/carnival/tests/test_carnival.rs | 168 ----------------- basics/repository-layout/native/CHANGELOG.md | 5 - .../native/program/Cargo.toml | 27 --- .../native/program/src/error.rs | 1 - .../program/src/instructions/eat_food.rs | 36 ---- .../program/src/instructions/get_on_ride.rs | 52 ------ .../native/program/src/instructions/mod.rs | 3 - .../program/src/instructions/play_game.rs | 41 ----- .../native/program/src/lib.rs | 6 - .../native/program/src/processor.rs | 50 ------ .../native/program/src/state/food.rs | 25 --- .../native/program/src/state/game.rs | 29 --- .../native/program/src/state/mod.rs | 3 - .../native/program/src/state/ride.rs | 28 --- .../native/program/tests/test.rs | 97 ---------- .../repository-layout/pinocchio/CHANGELOG.md | 5 - basics/repository-layout/pinocchio/README.md | 22 --- .../pinocchio/program/Cargo.toml | 26 --- .../pinocchio/program/src/error.rs | 1 - .../program/src/instructions/eat_food.rs | 35 ---- .../program/src/instructions/get_on_ride.rs | 51 ------ .../pinocchio/program/src/instructions/mod.rs | 3 - .../program/src/instructions/play_game.rs | 40 ----- .../pinocchio/program/src/lib.rs | 13 -- .../pinocchio/program/src/processor.rs | 76 -------- .../pinocchio/program/src/state/food.rs | 25 --- .../pinocchio/program/src/state/game.rs | 31 ---- .../pinocchio/program/src/state/mod.rs | 3 - .../pinocchio/program/src/state/ride.rs | 35 ---- .../pinocchio/program/tests/test.rs | 122 ------------- basics/repository-layout/quasar/.gitignore | 12 -- basics/repository-layout/quasar/CHANGELOG.md | 17 -- basics/repository-layout/quasar/Cargo.toml | 41 ----- basics/repository-layout/quasar/Quasar.toml | 9 - basics/repository-layout/quasar/README.md | 34 ---- .../src/instructions/carnival_context.rs | 42 ----- .../quasar/src/instructions/eat_food.rs | 26 --- .../quasar/src/instructions/get_on_ride.rs | 43 ----- .../quasar/src/instructions/mod.rs | 6 - .../quasar/src/instructions/play_game.rs | 27 --- basics/repository-layout/quasar/src/lib.rs | 50 ------ .../quasar/src/state/food.rs | 31 ---- .../quasar/src/state/game.rs | 37 ---- .../repository-layout/quasar/src/state/mod.rs | 3 - .../quasar/src/state/ride.rs | 43 ----- basics/repository-layout/quasar/src/tests.rs | 152 ---------------- scripts/generate-quasar-readmes.mjs | 5 - 85 files changed, 5 insertions(+), 2752 deletions(-) delete mode 100644 basics/repository-layout/README.md delete mode 100644 basics/repository-layout/anchor-v1/Anchor.toml delete mode 100644 basics/repository-layout/anchor-v1/CHANGELOG.md delete mode 100644 basics/repository-layout/anchor-v1/Cargo.toml delete mode 100644 basics/repository-layout/anchor-v1/README.md delete mode 100644 basics/repository-layout/anchor-v1/programs/carnival/Cargo.toml delete mode 100644 basics/repository-layout/anchor-v1/programs/carnival/Xargo.toml delete mode 100644 basics/repository-layout/anchor-v1/programs/carnival/src/error.rs delete mode 100644 basics/repository-layout/anchor-v1/programs/carnival/src/instructions/eat_food.rs delete mode 100644 basics/repository-layout/anchor-v1/programs/carnival/src/instructions/get_on_ride.rs delete mode 100644 basics/repository-layout/anchor-v1/programs/carnival/src/instructions/mod.rs delete mode 100644 basics/repository-layout/anchor-v1/programs/carnival/src/instructions/play_game.rs delete mode 100644 basics/repository-layout/anchor-v1/programs/carnival/src/lib.rs delete mode 100644 basics/repository-layout/anchor-v1/programs/carnival/src/state/food.rs delete mode 100644 basics/repository-layout/anchor-v1/programs/carnival/src/state/game.rs delete mode 100644 basics/repository-layout/anchor-v1/programs/carnival/src/state/mod.rs delete mode 100644 basics/repository-layout/anchor-v1/programs/carnival/src/state/ride.rs delete mode 100644 basics/repository-layout/anchor-v1/programs/carnival/tests/test_carnival.rs delete mode 100644 basics/repository-layout/anchor/Anchor.toml delete mode 100644 basics/repository-layout/anchor/CHANGELOG.md delete mode 100644 basics/repository-layout/anchor/Cargo.toml delete mode 100644 basics/repository-layout/anchor/README.md delete mode 100644 basics/repository-layout/anchor/programs/carnival/Cargo.toml delete mode 100644 basics/repository-layout/anchor/programs/carnival/Xargo.toml delete mode 100644 basics/repository-layout/anchor/programs/carnival/src/error.rs delete mode 100644 basics/repository-layout/anchor/programs/carnival/src/instructions/eat_food.rs delete mode 100644 basics/repository-layout/anchor/programs/carnival/src/instructions/get_on_ride.rs delete mode 100644 basics/repository-layout/anchor/programs/carnival/src/instructions/mod.rs delete mode 100644 basics/repository-layout/anchor/programs/carnival/src/instructions/play_game.rs delete mode 100644 basics/repository-layout/anchor/programs/carnival/src/lib.rs delete mode 100644 basics/repository-layout/anchor/programs/carnival/src/state/food.rs delete mode 100644 basics/repository-layout/anchor/programs/carnival/src/state/game.rs delete mode 100644 basics/repository-layout/anchor/programs/carnival/src/state/mod.rs delete mode 100644 basics/repository-layout/anchor/programs/carnival/src/state/ride.rs delete mode 100644 basics/repository-layout/anchor/programs/carnival/tests/test_carnival.rs delete mode 100644 basics/repository-layout/native/CHANGELOG.md delete mode 100644 basics/repository-layout/native/program/Cargo.toml delete mode 100644 basics/repository-layout/native/program/src/error.rs delete mode 100644 basics/repository-layout/native/program/src/instructions/eat_food.rs delete mode 100644 basics/repository-layout/native/program/src/instructions/get_on_ride.rs delete mode 100644 basics/repository-layout/native/program/src/instructions/mod.rs delete mode 100644 basics/repository-layout/native/program/src/instructions/play_game.rs delete mode 100644 basics/repository-layout/native/program/src/lib.rs delete mode 100644 basics/repository-layout/native/program/src/processor.rs delete mode 100644 basics/repository-layout/native/program/src/state/food.rs delete mode 100644 basics/repository-layout/native/program/src/state/game.rs delete mode 100644 basics/repository-layout/native/program/src/state/mod.rs delete mode 100644 basics/repository-layout/native/program/src/state/ride.rs delete mode 100644 basics/repository-layout/native/program/tests/test.rs delete mode 100644 basics/repository-layout/pinocchio/CHANGELOG.md delete mode 100644 basics/repository-layout/pinocchio/README.md delete mode 100644 basics/repository-layout/pinocchio/program/Cargo.toml delete mode 100644 basics/repository-layout/pinocchio/program/src/error.rs delete mode 100644 basics/repository-layout/pinocchio/program/src/instructions/eat_food.rs delete mode 100644 basics/repository-layout/pinocchio/program/src/instructions/get_on_ride.rs delete mode 100644 basics/repository-layout/pinocchio/program/src/instructions/mod.rs delete mode 100644 basics/repository-layout/pinocchio/program/src/instructions/play_game.rs delete mode 100644 basics/repository-layout/pinocchio/program/src/lib.rs delete mode 100644 basics/repository-layout/pinocchio/program/src/processor.rs delete mode 100644 basics/repository-layout/pinocchio/program/src/state/food.rs delete mode 100644 basics/repository-layout/pinocchio/program/src/state/game.rs delete mode 100644 basics/repository-layout/pinocchio/program/src/state/mod.rs delete mode 100644 basics/repository-layout/pinocchio/program/src/state/ride.rs delete mode 100644 basics/repository-layout/pinocchio/program/tests/test.rs delete mode 100644 basics/repository-layout/quasar/.gitignore delete mode 100644 basics/repository-layout/quasar/CHANGELOG.md delete mode 100644 basics/repository-layout/quasar/Cargo.toml delete mode 100644 basics/repository-layout/quasar/Quasar.toml delete mode 100644 basics/repository-layout/quasar/README.md delete mode 100644 basics/repository-layout/quasar/src/instructions/carnival_context.rs delete mode 100644 basics/repository-layout/quasar/src/instructions/eat_food.rs delete mode 100644 basics/repository-layout/quasar/src/instructions/get_on_ride.rs delete mode 100644 basics/repository-layout/quasar/src/instructions/mod.rs delete mode 100644 basics/repository-layout/quasar/src/instructions/play_game.rs delete mode 100644 basics/repository-layout/quasar/src/lib.rs delete mode 100644 basics/repository-layout/quasar/src/state/food.rs delete mode 100644 basics/repository-layout/quasar/src/state/game.rs delete mode 100644 basics/repository-layout/quasar/src/state/mod.rs delete mode 100644 basics/repository-layout/quasar/src/state/ride.rs delete mode 100644 basics/repository-layout/quasar/src/tests.rs diff --git a/Cargo.lock b/Cargo.lock index c4869f266..21f6282ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -748,27 +748,14 @@ dependencies = [ "cfg_aliases", ] -[[package]] -name = "borsh-derive" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6441c552f230375d18e3cc377677914d2ca2b0d36e52129fe15450a2dce46775" -dependencies = [ - "borsh-derive-internal 0.9.3", - "borsh-schema-derive-internal 0.9.3", - "proc-macro-crate 0.1.5", - "proc-macro2", - "syn 1.0.109", -] - [[package]] name = "borsh-derive" version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "831213f80d9423998dd696e2c5345aba6be7a0bd8cd19e31c5243e13df1cef89" dependencies = [ - "borsh-derive-internal 0.10.4", - "borsh-schema-derive-internal 0.10.4", + "borsh-derive-internal", + "borsh-schema-derive-internal", "proc-macro-crate 0.1.5", "proc-macro2", "syn 1.0.109", @@ -787,17 +774,6 @@ dependencies = [ "syn 2.0.118", ] -[[package]] -name = "borsh-derive-internal" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5449c28a7b352f2d1e592a8a28bf139bc71afb0764a14f3c02500935d8c44065" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "borsh-derive-internal" version = "0.10.4" @@ -809,17 +785,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "borsh-schema-derive-internal" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdbd5696d8bfa21d53d9fe39a714a18538bad11492a42d066dbbc395fb1951c0" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "borsh-schema-derive-internal" version = "0.10.4" @@ -894,18 +859,6 @@ version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" -[[package]] -name = "carnival" -version = "0.1.0" -dependencies = [ - "anchor-lang", - "anchor-v2-testing", - "solana-fee", - "solana-kite", - "solana-program-runtime", - "wincode", -] - [[package]] name = "cc" version = "1.2.65" @@ -3779,35 +3732,6 @@ dependencies = [ "solana-transaction", ] -[[package]] -name = "repository-layout-pinocchio-program" -version = "0.1.0" -dependencies = [ - "litesvm", - "pinocchio 0.10.2", - "pinocchio-log", - "solana-instruction 3.5.1", - "solana-keypair", - "solana-native-token 3.0.0", - "solana-pubkey 4.3.0", - "solana-transaction", -] - -[[package]] -name = "repository-layout-program" -version = "0.1.0" -dependencies = [ - "borsh 1.7.0", - "borsh-derive 0.9.3", - "litesvm", - "solana-instruction 3.5.1", - "solana-keypair", - "solana-native-token 3.0.0", - "solana-program 4.0.0", - "solana-pubkey 4.3.0", - "solana-transaction", -] - [[package]] name = "rfc6979" version = "0.6.0" diff --git a/Cargo.toml b/Cargo.toml index c6f046762..4178f7f73 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,9 +57,6 @@ members = [ "basics/favorites/pinocchio/program", "basics/favorites/anchor/programs/favorites", "basics/pyth/anchor/programs/pythexample", - "basics/repository-layout/native/program", - "basics/repository-layout/pinocchio/program", - "basics/repository-layout/anchor/programs/*", "basics/transaction-v1/anchor/programs/transaction-v1", "basics/transfer-sol/native/program", "basics/transfer-sol/pinocchio/program", diff --git a/README.md b/README.md index a0df6f6ea..8e9a3a17a 100644 --- a/README.md +++ b/README.md @@ -179,12 +179,6 @@ Calculate an account's size to determine the minimum rent-exempt balance. [⚓ Anchor v1](./basics/rent/anchor-v1) [⚓ Anchor v2](./basics/rent/anchor) [💫 Quasar](./basics/rent/quasar) [🤥 Pinocchio](./basics/rent/pinocchio) [🦀 Native](./basics/rent/native) -### Repository Layout - -Structure a larger Solana program across multiple files and modules. - -[⚓ Anchor v1](./basics/repository-layout/anchor-v1) [⚓ Anchor v2](./basics/repository-layout/anchor) [💫 Quasar](./basics/repository-layout/quasar) [🦀 Native](./basics/repository-layout/native) - ### Transfer SOL Send SOL between two accounts. diff --git a/basics/cross-program-invocation/quasar/hand/src/instructions/pull_lever.rs b/basics/cross-program-invocation/quasar/hand/src/instructions/pull_lever.rs index 695296069..88d17ba10 100644 --- a/basics/cross-program-invocation/quasar/hand/src/instructions/pull_lever.rs +++ b/basics/cross-program-invocation/quasar/hand/src/instructions/pull_lever.rs @@ -24,9 +24,9 @@ pub fn handle_pull_lever( // // The lever's switch_power instruction takes `String<50>`, which Quasar // serialises with a single-byte length prefix (matching every other - // Quasar program: account-data, close-account, rent, realloc, - // repository-layout). An earlier version of this builder used a u32 - // length prefix, which sent a malformed payload on every CPI call. + // Quasar program: account-data, close-account, rent, realloc). An earlier + // version of this builder used a u32 length prefix, which sent a malformed + // payload on every CPI call. // // 128 bytes is enough for any reasonable name (max 50 + 1 + 1 = 52). let mut data = [0u8; 128]; diff --git a/basics/repository-layout/README.md b/basics/repository-layout/README.md deleted file mode 100644 index c0eadd757..000000000 --- a/basics/repository-layout/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# Recommended Program Layout - -A typical layout for a Solana [program](https://solana.com/docs/terminology#program) as it grows in size and starts to need multiple Rust files. Many programs follow this shape. - -> You can structure your `src` folder however you like, as long as it follows Cargo's conventions. This layout is shown so that the patterns in other programs are recognizable. - -The `native` and `anchor` layouts are similar. The main difference is the `processor.rs` file in the `native` setup - one of the things [Anchor](https://solana.com/docs/terminology#anchor) abstracts away for you. diff --git a/basics/repository-layout/anchor-v1/Anchor.toml b/basics/repository-layout/anchor-v1/Anchor.toml deleted file mode 100644 index 411ce3df7..000000000 --- a/basics/repository-layout/anchor-v1/Anchor.toml +++ /dev/null @@ -1,16 +0,0 @@ -[toolchain] -# Match the repo package manager (pnpm-lock.yaml at root); avoids Anchor's yarn default. -package_manager = "pnpm" -solana_version = "3.1.8" - -[features] -seeds = false -[programs.localnet] -carnival = "8t94SEJh9jVjDwV7cbiuT6BvEsHo4YHP9x9a5rYH1NpP" - -[provider] -cluster = "localnet" -wallet = "~/.config/solana/id.json" - -[scripts] -test = "cargo test" diff --git a/basics/repository-layout/anchor-v1/CHANGELOG.md b/basics/repository-layout/anchor-v1/CHANGELOG.md deleted file mode 100644 index 4f1163881..000000000 --- a/basics/repository-layout/anchor-v1/CHANGELOG.md +++ /dev/null @@ -1,5 +0,0 @@ -# Changelog - -## 2026-07-07 - -Added this changelog. Changes prior to this date were tracked in git history only. diff --git a/basics/repository-layout/anchor-v1/Cargo.toml b/basics/repository-layout/anchor-v1/Cargo.toml deleted file mode 100644 index f39770481..000000000 --- a/basics/repository-layout/anchor-v1/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[workspace] -members = [ - "programs/*" -] -resolver = "2" - -[profile.release] -overflow-checks = true -lto = "fat" -codegen-units = 1 -[profile.release.build-override] -opt-level = 3 -incremental = false -codegen-units = 1 diff --git a/basics/repository-layout/anchor-v1/README.md b/basics/repository-layout/anchor-v1/README.md deleted file mode 100644 index 8c966bc5e..000000000 --- a/basics/repository-layout/anchor-v1/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# Repository Layout (Anchor) - -> [!NOTE] -> This is the **Anchor v1** copy of this example, on Anchor 1.2.1, the current -> stable Anchor release. Every `anchor` command on this page needs the v1 CLI: -> `avm install 1.2.1 && avm use 1.2.1`. The Anchor v2 version of this example is in -> [`../anchor`](../anchor/). - -Organize a larger program across modules (state, instructions, errors) instead of a single file. - -See also: [Repository Layout overview](../README.md) and the [repository catalog](../../../README.md). - -## Major concepts - -- Multi-file Anchor layout -- Separating concerns by module - -## Setup - -From this directory (`basics/repository-layout/anchor/`): - -```bash -anchor build -``` - -Prerequisites: [Agave](https://docs.anza.xyz/) CLI (version in `Anchor.toml` `[toolchain]`), [Anchor](https://www.anchor-lang.com/docs). - -## Testing - -Tests run in-process with [LiteSVM](https://www.anchor-lang.com/docs/testing/litesvm). No local validator. - -```bash -anchor test -``` - -This runs `cargo test` as configured in `Anchor.toml`. Tests call instruction handlers and check onchain state. - -## Usage - -Read the program `programs/` source and `Anchor.toml` for deployed program IDs. For deployment, use `anchor build && anchor deploy` against your target cluster. diff --git a/basics/repository-layout/anchor-v1/programs/carnival/Cargo.toml b/basics/repository-layout/anchor-v1/programs/carnival/Cargo.toml deleted file mode 100644 index d4a9dc968..000000000 --- a/basics/repository-layout/anchor-v1/programs/carnival/Cargo.toml +++ /dev/null @@ -1,32 +0,0 @@ -[package] -name = "carnival" -version = "0.1.0" -description = "Created with Anchor" -edition = "2021" - -[lib] -crate-type = ["cdylib", "lib"] -name = "carnival" - -[features] -default = [] -cpi = ["no-entrypoint"] -no-entrypoint = [] -no-idl = [] -no-log-ix-name = [] -idl-build = ["anchor-lang/idl-build"] -anchor-debug = [] -custom-heap = [] -custom-panic = [] - -[dependencies] -anchor-lang = "1.2.1" - -[dev-dependencies] -litesvm = "0.16.0" -solana-signer = "3.0.0" -solana-keypair = "3.0.1" -solana-kite = "0.6.1" - -[lints.rust] -unexpected_cfgs = { level = "warn", check-cfg = ['cfg(target_os, values("solana"))'] } diff --git a/basics/repository-layout/anchor-v1/programs/carnival/Xargo.toml b/basics/repository-layout/anchor-v1/programs/carnival/Xargo.toml deleted file mode 100644 index 475fb71ed..000000000 --- a/basics/repository-layout/anchor-v1/programs/carnival/Xargo.toml +++ /dev/null @@ -1,2 +0,0 @@ -[target.bpfel-unknown-unknown.dependencies.std] -features = [] diff --git a/basics/repository-layout/anchor-v1/programs/carnival/src/error.rs b/basics/repository-layout/anchor-v1/programs/carnival/src/error.rs deleted file mode 100644 index fc136669d..000000000 --- a/basics/repository-layout/anchor-v1/programs/carnival/src/error.rs +++ /dev/null @@ -1,17 +0,0 @@ -use anchor_lang::prelude::*; - -// Real failure modes for the carnival examples. Previously this file was empty -// and the rejection branches in the instruction handlers just logged a message -// and returned Ok(()), which made it impossible for callers (or tests) to -// distinguish "the ride happened" from "the ride refused service". -#[error_code] -pub enum CarnivalError { - // The rider/gamer/eater did not bring enough tickets for the requested - // attraction. - #[msg("Not enough tickets for the requested attraction")] - NotEnoughTickets, - - // The rider is below the minimum height required for the ride. - #[msg("Rider is below the minimum height for this ride")] - RiderTooShort, -} diff --git a/basics/repository-layout/anchor-v1/programs/carnival/src/instructions/eat_food.rs b/basics/repository-layout/anchor-v1/programs/carnival/src/instructions/eat_food.rs deleted file mode 100644 index 2e3a62a06..000000000 --- a/basics/repository-layout/anchor-v1/programs/carnival/src/instructions/eat_food.rs +++ /dev/null @@ -1,38 +0,0 @@ -use anchor_lang::prelude::*; - -use crate::{error::CarnivalError, state::food}; - -// Instruction Data - -pub struct EatFoodInstructionData { - pub eater_name: String, - pub eater_ticket_count: u32, - pub food_stand: String, -} - -pub fn eat_food(ix: EatFoodInstructionData) -> Result<()> { - let food_stands_list = food::get_food_stands(); - - for food_stand in food_stands_list.iter() { - if ix.food_stand.eq(&food_stand.name) { - msg!("Welcome to {}! What can I get you?", food_stand.name); - - if ix.eater_ticket_count < food_stand.tickets { - msg!( - " Sorry {}, our {} is {} tickets!", - ix.eater_name, - food_stand.food_type, - food_stand.tickets - ); - // Refuse service rather than logging and returning Ok(()), so - // callers can distinguish a sale from a refusal. - return Err(CarnivalError::NotEnoughTickets.into()); - } - - msg!(" Enjoy your {}!", food_stand.food_type); - return Ok(()); - } - } - - Err(ProgramError::InvalidInstructionData.into()) -} diff --git a/basics/repository-layout/anchor-v1/programs/carnival/src/instructions/get_on_ride.rs b/basics/repository-layout/anchor-v1/programs/carnival/src/instructions/get_on_ride.rs deleted file mode 100644 index 0427f0c36..000000000 --- a/basics/repository-layout/anchor-v1/programs/carnival/src/instructions/get_on_ride.rs +++ /dev/null @@ -1,54 +0,0 @@ -use anchor_lang::prelude::*; - -use crate::{error::CarnivalError, state::ride}; - -// Instruction Data - -pub struct GetOnRideInstructionData { - pub rider_name: String, - pub rider_height: u32, - pub rider_ticket_count: u32, - pub ride: String, -} - -pub fn get_on_ride(ix: GetOnRideInstructionData) -> Result<()> { - let rides_list = ride::get_rides(); - - for ride in rides_list.iter() { - if ix.ride.eq(&ride.name) { - msg!("You're about to ride the {}!", ride.name); - - // Refuse service with a real error so callers and tests can - // distinguish a refused ride from a successful one. - if ix.rider_ticket_count < ride.tickets { - msg!( - " Sorry {}, you need {} tickets to ride the {}!", - ix.rider_name, - ride.tickets, - ride.name - ); - return Err(CarnivalError::NotEnoughTickets.into()); - }; - - if ix.rider_height < ride.min_height { - msg!( - " Sorry {}, you need to be {}\" tall to ride the {}!", - ix.rider_name, - ride.min_height, - ride.name - ); - return Err(CarnivalError::RiderTooShort.into()); - }; - - msg!(" Welcome aboard the {}!", ride.name); - - if ride.upside_down { - msg!(" Btw, this ride goes upside down. Hold on tight!"); - }; - - return Ok(()); - } - } - - Err(ProgramError::InvalidInstructionData.into()) -} diff --git a/basics/repository-layout/anchor-v1/programs/carnival/src/instructions/mod.rs b/basics/repository-layout/anchor-v1/programs/carnival/src/instructions/mod.rs deleted file mode 100644 index ee6ea6d1e..000000000 --- a/basics/repository-layout/anchor-v1/programs/carnival/src/instructions/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod eat_food; -pub mod get_on_ride; -pub mod play_game; diff --git a/basics/repository-layout/anchor-v1/programs/carnival/src/instructions/play_game.rs b/basics/repository-layout/anchor-v1/programs/carnival/src/instructions/play_game.rs deleted file mode 100644 index 4867f98e8..000000000 --- a/basics/repository-layout/anchor-v1/programs/carnival/src/instructions/play_game.rs +++ /dev/null @@ -1,44 +0,0 @@ -use anchor_lang::prelude::*; - -use crate::{error::CarnivalError, state::game}; - -// Instruction Data - -pub struct PlayGameInstructionData { - pub gamer_name: String, - pub gamer_ticket_count: u32, - pub game: String, -} - -pub fn play_game(ix: PlayGameInstructionData) -> Result<()> { - let games_list = game::get_games(); - - for game in games_list.iter() { - if ix.game.eq(&game.name) { - msg!("You're about to play {}!", game.name); - - if ix.gamer_ticket_count < game.tickets { - msg!( - " Sorry {}, you need {} tickets to play {}!", - ix.gamer_name, - game.tickets, - game.name - ); - // Refuse service rather than logging and returning Ok(()), so - // callers can tell a successful play from a refusal. - return Err(CarnivalError::NotEnoughTickets.into()); - } - - msg!(" Let's see what you got!"); - msg!( - " You get {} attempts and the prize is a {}!", - game.tries, - game.prize - ); - - return Ok(()); - } - } - - Err(ProgramError::InvalidInstructionData.into()) -} diff --git a/basics/repository-layout/anchor-v1/programs/carnival/src/lib.rs b/basics/repository-layout/anchor-v1/programs/carnival/src/lib.rs deleted file mode 100644 index 9d0bea35f..000000000 --- a/basics/repository-layout/anchor-v1/programs/carnival/src/lib.rs +++ /dev/null @@ -1,63 +0,0 @@ -use anchor_lang::prelude::*; - -pub mod error; -pub mod instructions; -pub mod state; - -use crate::instructions::{eat_food, get_on_ride, play_game}; - -// For setting up modules & configs - -declare_id!("8t94SEJh9jVjDwV7cbiuT6BvEsHo4YHP9x9a5rYH1NpP"); - -#[program] -pub mod carnival { - use super::*; - - pub fn go_on_ride( - _context: Context, - name: String, - height: u32, - ticket_count: u32, - ride_name: String, - ) -> Result<()> { - get_on_ride::get_on_ride(get_on_ride::GetOnRideInstructionData { - rider_name: name, - rider_height: height, - rider_ticket_count: ticket_count, - ride: ride_name, - }) - } - - pub fn play_game( - _context: Context, - name: String, - ticket_count: u32, - game_name: String, - ) -> Result<()> { - play_game::play_game(play_game::PlayGameInstructionData { - gamer_name: name, - gamer_ticket_count: ticket_count, - game: game_name, - }) - } - - pub fn eat_food( - _context: Context, - name: String, - ticket_count: u32, - food_stand_name: String, - ) -> Result<()> { - eat_food::eat_food(eat_food::EatFoodInstructionData { - eater_name: name, - eater_ticket_count: ticket_count, - food_stand: food_stand_name, - }) - } -} - -#[derive(Accounts)] -pub struct CarnivalAccountConstraints<'info> { - #[account(mut)] - pub payer: Signer<'info>, -} diff --git a/basics/repository-layout/anchor-v1/programs/carnival/src/state/food.rs b/basics/repository-layout/anchor-v1/programs/carnival/src/state/food.rs deleted file mode 100644 index 62b5e04d6..000000000 --- a/basics/repository-layout/anchor-v1/programs/carnival/src/state/food.rs +++ /dev/null @@ -1,25 +0,0 @@ -// Objects - -pub struct FoodStand { - pub name: String, - pub food_type: String, - pub tickets: u32, -} - -impl FoodStand { - pub fn new(name: String, food_type: String, tickets: u32) -> FoodStand { - FoodStand { - name, - food_type, - tickets, - } - } -} - -pub fn get_food_stands() -> Vec { - vec![ - FoodStand::new("Larry's Pizza".to_string(), "pizza".to_string(), 3), - FoodStand::new("Taco Shack".to_string(), "taco".to_string(), 2), - FoodStand::new("Dough Boy's".to_string(), "fried dough".to_string(), 1), - ] -} diff --git a/basics/repository-layout/anchor-v1/programs/carnival/src/state/game.rs b/basics/repository-layout/anchor-v1/programs/carnival/src/state/game.rs deleted file mode 100644 index 185547230..000000000 --- a/basics/repository-layout/anchor-v1/programs/carnival/src/state/game.rs +++ /dev/null @@ -1,29 +0,0 @@ -// Objects - -pub struct Game { - pub name: String, - pub tickets: u32, - pub tries: u32, - pub prize: String, -} - -const DEFAULT_TICKETS_TO_PLAY: u32 = 3; - -impl Game { - pub fn new(name: String, tries: u32, prize: String) -> Game { - Game { - name, - tickets: DEFAULT_TICKETS_TO_PLAY, - tries, - prize, - } - } -} - -pub fn get_games() -> Vec { - vec![ - Game::new("Ring Toss".to_string(), 5, "teddy bear".to_string()), - Game::new("I Got It!".to_string(), 12, "goldfish".to_string()), - Game::new("Ladder Climb".to_string(), 1, "popcorn bucket".to_string()), - ] -} diff --git a/basics/repository-layout/anchor-v1/programs/carnival/src/state/mod.rs b/basics/repository-layout/anchor-v1/programs/carnival/src/state/mod.rs deleted file mode 100644 index 12a92a2cf..000000000 --- a/basics/repository-layout/anchor-v1/programs/carnival/src/state/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod food; -pub mod game; -pub mod ride; diff --git a/basics/repository-layout/anchor-v1/programs/carnival/src/state/ride.rs b/basics/repository-layout/anchor-v1/programs/carnival/src/state/ride.rs deleted file mode 100644 index a3af23969..000000000 --- a/basics/repository-layout/anchor-v1/programs/carnival/src/state/ride.rs +++ /dev/null @@ -1,28 +0,0 @@ -// Objects - -pub struct Ride { - pub name: String, - pub upside_down: bool, - pub tickets: u32, - pub min_height: u32, -} - -impl Ride { - pub fn new(name: String, upside_down: bool, tickets: u32, min_height: u32) -> Ride { - Ride { - name, - upside_down, - tickets, - min_height, - } - } -} - -pub fn get_rides() -> Vec { - vec![ - Ride::new("Tilt-a-Whirl".to_string(), false, 3, 48), - Ride::new("Scrambler".to_string(), false, 3, 48), - Ride::new("Ferris Wheel".to_string(), false, 5, 55), - Ride::new("Zero Gravity".to_string(), true, 5, 60), - ] -} diff --git a/basics/repository-layout/anchor-v1/programs/carnival/tests/test_carnival.rs b/basics/repository-layout/anchor-v1/programs/carnival/tests/test_carnival.rs deleted file mode 100644 index 242ef42bf..000000000 --- a/basics/repository-layout/anchor-v1/programs/carnival/tests/test_carnival.rs +++ /dev/null @@ -1,169 +0,0 @@ -use { - anchor_lang::{solana_program::instruction::Instruction, InstructionData, ToAccountMetas}, - litesvm::LiteSVM, - solana_kite::{create_wallet, send_transaction_from_instructions}, - solana_signer::Signer, -}; - -fn setup() -> (LiteSVM, solana_keypair::Keypair) { - let program_id = carnival::id(); - let mut svm = LiteSVM::new(); - let bytes = include_bytes!("../../../target/deploy/carnival.so"); - svm.add_program(program_id, bytes).unwrap(); - let payer = create_wallet(&mut svm, 10_000_000_000).unwrap(); - (svm, payer) -} - -fn go_on_ride_ix( - payer: &solana_keypair::Keypair, - name: &str, - height: u32, - ticket_count: u32, - ride_name: &str, -) -> Instruction { - let accounts = carnival::accounts::CarnivalAccountConstraints { - payer: payer.pubkey(), - } - .to_account_metas(None); - Instruction::new_with_bytes( - carnival::id(), - &carnival::instruction::GoOnRide { - name: name.to_string(), - height, - ticket_count, - ride_name: ride_name.to_string(), - } - .data(), - accounts, - ) -} - -fn play_game_ix( - payer: &solana_keypair::Keypair, - name: &str, - ticket_count: u32, - game_name: &str, -) -> Instruction { - let accounts = carnival::accounts::CarnivalAccountConstraints { - payer: payer.pubkey(), - } - .to_account_metas(None); - Instruction::new_with_bytes( - carnival::id(), - &carnival::instruction::PlayGame { - name: name.to_string(), - ticket_count, - game_name: game_name.to_string(), - } - .data(), - accounts, - ) -} - -fn eat_food_ix( - payer: &solana_keypair::Keypair, - name: &str, - ticket_count: u32, - food_stand_name: &str, -) -> Instruction { - let accounts = carnival::accounts::CarnivalAccountConstraints { - payer: payer.pubkey(), - } - .to_account_metas(None); - Instruction::new_with_bytes( - carnival::id(), - &carnival::instruction::EatFood { - name: name.to_string(), - ticket_count, - food_stand_name: food_stand_name.to_string(), - } - .data(), - accounts, - ) -} - -// Riders that have enough tickets and meet the height requirement succeed. -#[test] -fn test_go_on_ride_succeeds() { - let (mut svm, payer) = setup(); - // Scrambler costs 3 tickets and requires 48" min height; Alice has 15 - // tickets and is 56" tall. - let ix = go_on_ride_ix(&payer, "Alice", 56, 15, "Scrambler"); - send_transaction_from_instructions(&mut svm, vec![ix], &[&payer], &payer.pubkey(), None) - .unwrap(); -} - -// Insufficient tickets must produce a real error (NotEnoughTickets), not a -// silent Ok(). -#[test] -fn test_go_on_ride_rejects_insufficient_tickets() { - let (mut svm, payer) = setup(); - // Tilt-a-Whirl costs 3 tickets; Bob only has 1. - let ix = go_on_ride_ix(&payer, "Bob", 49, 1, "Tilt-a-Whirl"); - let result = - send_transaction_from_instructions(&mut svm, vec![ix], &[&payer], &payer.pubkey(), None); - assert!(result.is_err(), "ride must reject insufficient tickets"); -} - -// A rider below the minimum height must be rejected with RiderTooShort. -#[test] -fn test_go_on_ride_rejects_too_short() { - let (mut svm, payer) = setup(); - // Ferris Wheel requires 55" min height; Jimmy is 36" tall but has plenty - // of tickets. - let ix = go_on_ride_ix(&payer, "Jimmy", 36, 15, "Ferris Wheel"); - let result = - send_transaction_from_instructions(&mut svm, vec![ix], &[&payer], &payer.pubkey(), None); - assert!(result.is_err(), "ride must reject riders below min height"); -} - -// Unknown attraction name routes to ProgramError::InvalidInstructionData. -#[test] -fn test_go_on_ride_rejects_unknown_ride() { - let (mut svm, payer) = setup(); - let ix = go_on_ride_ix(&payer, "Alice", 60, 100, "Quantum Coaster"); - let result = - send_transaction_from_instructions(&mut svm, vec![ix], &[&payer], &payer.pubkey(), None); - assert!(result.is_err(), "unknown ride must be rejected"); -} - -#[test] -fn test_play_game_succeeds() { - let (mut svm, payer) = setup(); - // Ring Toss costs 3 tickets; Alice has 15. - let ix = play_game_ix(&payer, "Alice", 15, "Ring Toss"); - send_transaction_from_instructions(&mut svm, vec![ix], &[&payer], &payer.pubkey(), None) - .unwrap(); -} - -#[test] -fn test_play_game_rejects_insufficient_tickets() { - let (mut svm, payer) = setup(); - // Ring Toss costs 3 tickets; Mary only has 1. - let ix = play_game_ix(&payer, "Mary", 1, "Ring Toss"); - let result = - send_transaction_from_instructions(&mut svm, vec![ix], &[&payer], &payer.pubkey(), None); - assert!(result.is_err(), "game must reject insufficient tickets"); -} - -#[test] -fn test_eat_food_succeeds() { - let (mut svm, payer) = setup(); - // Dough Boy's costs 1 ticket; Bob has 6. - let ix = eat_food_ix(&payer, "Bob", 6, "Dough Boy's"); - send_transaction_from_instructions(&mut svm, vec![ix], &[&payer], &payer.pubkey(), None) - .unwrap(); -} - -#[test] -fn test_eat_food_rejects_insufficient_tickets() { - let (mut svm, payer) = setup(); - // Larry's Pizza costs 3 tickets; Mary has 1. - let ix = eat_food_ix(&payer, "Mary", 1, "Larry's Pizza"); - let result = - send_transaction_from_instructions(&mut svm, vec![ix], &[&payer], &payer.pubkey(), None); - assert!( - result.is_err(), - "food stand must reject insufficient tickets" - ); -} diff --git a/basics/repository-layout/anchor/Anchor.toml b/basics/repository-layout/anchor/Anchor.toml deleted file mode 100644 index 411ce3df7..000000000 --- a/basics/repository-layout/anchor/Anchor.toml +++ /dev/null @@ -1,16 +0,0 @@ -[toolchain] -# Match the repo package manager (pnpm-lock.yaml at root); avoids Anchor's yarn default. -package_manager = "pnpm" -solana_version = "3.1.8" - -[features] -seeds = false -[programs.localnet] -carnival = "8t94SEJh9jVjDwV7cbiuT6BvEsHo4YHP9x9a5rYH1NpP" - -[provider] -cluster = "localnet" -wallet = "~/.config/solana/id.json" - -[scripts] -test = "cargo test" diff --git a/basics/repository-layout/anchor/CHANGELOG.md b/basics/repository-layout/anchor/CHANGELOG.md deleted file mode 100644 index 4f1163881..000000000 --- a/basics/repository-layout/anchor/CHANGELOG.md +++ /dev/null @@ -1,5 +0,0 @@ -# Changelog - -## 2026-07-07 - -Added this changelog. Changes prior to this date were tracked in git history only. diff --git a/basics/repository-layout/anchor/Cargo.toml b/basics/repository-layout/anchor/Cargo.toml deleted file mode 100644 index f39770481..000000000 --- a/basics/repository-layout/anchor/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[workspace] -members = [ - "programs/*" -] -resolver = "2" - -[profile.release] -overflow-checks = true -lto = "fat" -codegen-units = 1 -[profile.release.build-override] -opt-level = 3 -incremental = false -codegen-units = 1 diff --git a/basics/repository-layout/anchor/README.md b/basics/repository-layout/anchor/README.md deleted file mode 100644 index b71da90e3..000000000 --- a/basics/repository-layout/anchor/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# Repository Layout (Anchor) - -> [!NOTE] -> This is the **Anchor v2** copy of this example. Every `anchor` command on this page -> needs the v2 CLI: `cargo install anchor-cli --version 2.0.0-rc.2 --locked` (avm has -> no prebuilt binary for this pre-release). The Anchor v1 version of this example is in -> [`../anchor-v1`](../anchor-v1/). - -Organize a larger program across modules (state, instructions, errors) instead of a single file. - -See also: [Repository Layout overview](../README.md) and the [repository catalog](../../../README.md). - -## Major concepts - -- Multi-file Anchor layout -- Separating concerns by module - -## Setup - -From this directory (`basics/repository-layout/anchor/`): - -```bash -anchor build -``` - -Prerequisites: [Agave](https://docs.anza.xyz/) CLI (version in `Anchor.toml` `[toolchain]`), [Anchor](https://www.anchor-lang.com/docs). - -## Testing - -Tests run in-process with [LiteSVM](https://www.anchor-lang.com/docs/testing/litesvm). No local validator. - -```bash -anchor test -``` - -This runs `cargo test` as configured in `Anchor.toml`. Tests call instruction handlers and check onchain state. - -## Usage - -Read the program `programs/` source and `Anchor.toml` for deployed program IDs. For deployment, use `anchor build && anchor deploy` against your target cluster. diff --git a/basics/repository-layout/anchor/programs/carnival/Cargo.toml b/basics/repository-layout/anchor/programs/carnival/Cargo.toml deleted file mode 100644 index 0f4ad9a2c..000000000 --- a/basics/repository-layout/anchor/programs/carnival/Cargo.toml +++ /dev/null @@ -1,55 +0,0 @@ -[package] -name = "carnival" -version = "0.1.0" -description = "Created with Anchor" -edition = "2021" - -[lib] -crate-type = ["cdylib", "lib"] -name = "carnival" - -[features] -default = [] -cpi = ["no-entrypoint"] -no-entrypoint = [] -no-idl = [] -no-log-ix-name = [] -idl-build = ["anchor-lang/idl-build"] -anchor-debug = [] -custom-heap = [] -custom-panic = [] -# Forwards to the harness so `anchor test --profile` can turn tracing on. -profile = ["anchor-v2-testing/profile"] - -[dependencies] -anchor-lang = "2.0.0-rc.2" -# The `#[program]` macro expands to `wincode` paths for instruction-data -# (de)serialization, so the crate has to be a direct dependency. -wincode = { version = "0.6", features = ["derive"] } - -[dev-dependencies] -# Anchor v2's own LiteSVM harness. `svm()` is `LiteSVM::new()` until the -# `profile` feature is on, when it also records the SBF register traces that -# `anchor test --profile`, `anchor debugger` and `anchor coverage` read. Tests -# that call `LiteSVM::new()` directly still pass but produce no traces, so -# those three tools see nothing. -# -# Published only from git: crates.io has no `anchor-v2-testing`. Pinned to a -# revision rather than tracking `anchor-next`, so a CI run cannot change -# behaviour because upstream moved between builds. -# -# Bump the rev deliberately, never automatically: `anchor-next` is where v2 -# development happens, so a later revision can carry breakage as easily as -# fixes. When `anchor-v2-testing` reaches crates.io, drop the git source for -# an ordinary version. -anchor-v2-testing = { git = "https://github.com/otter-sec/anchor.git", rev = "a20660219882af5f199d56ea3f9326f387f89d8b" } -# LiteSVM 0.18.1 asks for the Agave crates with `^4.3` ranges but does not -# compile against Agave 4.4.0. These two hold the Agave crates at 4.3; the rest -# follow, because Agave pins its own crates to one another exactly. Remove both -# once a LiteSVM release builds against Agave 4.4. -solana-program-runtime = "~4.3" -solana-fee = "~4.3" -solana-kite = "0.7.0" - -[lints.rust] -unexpected_cfgs = { level = "warn", check-cfg = ['cfg(target_os, values("solana"))'] } diff --git a/basics/repository-layout/anchor/programs/carnival/Xargo.toml b/basics/repository-layout/anchor/programs/carnival/Xargo.toml deleted file mode 100644 index 475fb71ed..000000000 --- a/basics/repository-layout/anchor/programs/carnival/Xargo.toml +++ /dev/null @@ -1,2 +0,0 @@ -[target.bpfel-unknown-unknown.dependencies.std] -features = [] diff --git a/basics/repository-layout/anchor/programs/carnival/src/error.rs b/basics/repository-layout/anchor/programs/carnival/src/error.rs deleted file mode 100644 index fc136669d..000000000 --- a/basics/repository-layout/anchor/programs/carnival/src/error.rs +++ /dev/null @@ -1,17 +0,0 @@ -use anchor_lang::prelude::*; - -// Real failure modes for the carnival examples. Previously this file was empty -// and the rejection branches in the instruction handlers just logged a message -// and returned Ok(()), which made it impossible for callers (or tests) to -// distinguish "the ride happened" from "the ride refused service". -#[error_code] -pub enum CarnivalError { - // The rider/gamer/eater did not bring enough tickets for the requested - // attraction. - #[msg("Not enough tickets for the requested attraction")] - NotEnoughTickets, - - // The rider is below the minimum height required for the ride. - #[msg("Rider is below the minimum height for this ride")] - RiderTooShort, -} diff --git a/basics/repository-layout/anchor/programs/carnival/src/instructions/eat_food.rs b/basics/repository-layout/anchor/programs/carnival/src/instructions/eat_food.rs deleted file mode 100644 index 555c6623a..000000000 --- a/basics/repository-layout/anchor/programs/carnival/src/instructions/eat_food.rs +++ /dev/null @@ -1,38 +0,0 @@ -use anchor_lang::prelude::*; - -use crate::{error::CarnivalError, state::food}; - -// Instruction Data - -pub struct EatFoodInstructionData { - pub eater_name: String, - pub eater_ticket_count: u32, - pub food_stand: String, -} - -pub fn eat_food(ix: EatFoodInstructionData) -> Result<()> { - let food_stands_list = food::get_food_stands(); - - for food_stand in food_stands_list.iter() { - if ix.food_stand.eq(&food_stand.name) { - msg!("Welcome to {}! What can I get you?", food_stand.name); - - if ix.eater_ticket_count < food_stand.tickets { - msg!( - " Sorry {}, our {} is {} tickets!", - ix.eater_name, - food_stand.food_type, - food_stand.tickets - ); - // Refuse service rather than logging and returning Ok(()), so - // callers can distinguish a sale from a refusal. - return Err(CarnivalError::NotEnoughTickets.into()); - } - - msg!(" Enjoy your {}!", food_stand.food_type); - return Ok(()); - } - } - - Err(ProgramError::InvalidInstructionData) -} diff --git a/basics/repository-layout/anchor/programs/carnival/src/instructions/get_on_ride.rs b/basics/repository-layout/anchor/programs/carnival/src/instructions/get_on_ride.rs deleted file mode 100644 index 43fb2f10b..000000000 --- a/basics/repository-layout/anchor/programs/carnival/src/instructions/get_on_ride.rs +++ /dev/null @@ -1,54 +0,0 @@ -use anchor_lang::prelude::*; - -use crate::{error::CarnivalError, state::ride}; - -// Instruction Data - -pub struct GetOnRideInstructionData { - pub rider_name: String, - pub rider_height: u32, - pub rider_ticket_count: u32, - pub ride: String, -} - -pub fn get_on_ride(ix: GetOnRideInstructionData) -> Result<()> { - let rides_list = ride::get_rides(); - - for ride in rides_list.iter() { - if ix.ride.eq(&ride.name) { - msg!("You're about to ride the {}!", ride.name); - - // Refuse service with a real error so callers and tests can - // distinguish a refused ride from a successful one. - if ix.rider_ticket_count < ride.tickets { - msg!( - " Sorry {}, you need {} tickets to ride the {}!", - ix.rider_name, - ride.tickets, - ride.name - ); - return Err(CarnivalError::NotEnoughTickets.into()); - }; - - if ix.rider_height < ride.min_height { - msg!( - " Sorry {}, you need to be {}\" tall to ride the {}!", - ix.rider_name, - ride.min_height, - ride.name - ); - return Err(CarnivalError::RiderTooShort.into()); - }; - - msg!(" Welcome aboard the {}!", ride.name); - - if ride.upside_down { - msg!(" Btw, this ride goes upside down. Hold on tight!"); - }; - - return Ok(()); - } - } - - Err(ProgramError::InvalidInstructionData) -} diff --git a/basics/repository-layout/anchor/programs/carnival/src/instructions/mod.rs b/basics/repository-layout/anchor/programs/carnival/src/instructions/mod.rs deleted file mode 100644 index ee6ea6d1e..000000000 --- a/basics/repository-layout/anchor/programs/carnival/src/instructions/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod eat_food; -pub mod get_on_ride; -pub mod play_game; diff --git a/basics/repository-layout/anchor/programs/carnival/src/instructions/play_game.rs b/basics/repository-layout/anchor/programs/carnival/src/instructions/play_game.rs deleted file mode 100644 index 5613fc778..000000000 --- a/basics/repository-layout/anchor/programs/carnival/src/instructions/play_game.rs +++ /dev/null @@ -1,44 +0,0 @@ -use anchor_lang::prelude::*; - -use crate::{error::CarnivalError, state::game}; - -// Instruction Data - -pub struct PlayGameInstructionData { - pub gamer_name: String, - pub gamer_ticket_count: u32, - pub game: String, -} - -pub fn play_game(ix: PlayGameInstructionData) -> Result<()> { - let games_list = game::get_games(); - - for game in games_list.iter() { - if ix.game.eq(&game.name) { - msg!("You're about to play {}!", game.name); - - if ix.gamer_ticket_count < game.tickets { - msg!( - " Sorry {}, you need {} tickets to play {}!", - ix.gamer_name, - game.tickets, - game.name - ); - // Refuse service rather than logging and returning Ok(()), so - // callers can tell a successful play from a refusal. - return Err(CarnivalError::NotEnoughTickets.into()); - } - - msg!(" Let's see what you got!"); - msg!( - " You get {} attempts and the prize is a {}!", - game.tries, - game.prize - ); - - return Ok(()); - } - } - - Err(ProgramError::InvalidInstructionData) -} diff --git a/basics/repository-layout/anchor/programs/carnival/src/lib.rs b/basics/repository-layout/anchor/programs/carnival/src/lib.rs deleted file mode 100644 index 4a542c28a..000000000 --- a/basics/repository-layout/anchor/programs/carnival/src/lib.rs +++ /dev/null @@ -1,63 +0,0 @@ -use anchor_lang::prelude::*; - -pub mod error; -pub mod instructions; -pub mod state; - -use crate::instructions::{eat_food, get_on_ride, play_game}; - -// For setting up modules & configs - -declare_id!("8t94SEJh9jVjDwV7cbiuT6BvEsHo4YHP9x9a5rYH1NpP"); - -#[program] -pub mod carnival { - use super::*; - - pub fn go_on_ride( - _context: &mut Context, - name: String, - height: u32, - ticket_count: u32, - ride_name: String, - ) -> Result<()> { - get_on_ride::get_on_ride(get_on_ride::GetOnRideInstructionData { - rider_name: name, - rider_height: height, - rider_ticket_count: ticket_count, - ride: ride_name, - }) - } - - pub fn play_game( - _context: &mut Context, - name: String, - ticket_count: u32, - game_name: String, - ) -> Result<()> { - play_game::play_game(play_game::PlayGameInstructionData { - gamer_name: name, - gamer_ticket_count: ticket_count, - game: game_name, - }) - } - - pub fn eat_food( - _context: &mut Context, - name: String, - ticket_count: u32, - food_stand_name: String, - ) -> Result<()> { - eat_food::eat_food(eat_food::EatFoodInstructionData { - eater_name: name, - eater_ticket_count: ticket_count, - food_stand: food_stand_name, - }) - } -} - -#[derive(Accounts)] -pub struct CarnivalAccountConstraints { - #[account(mut)] - pub payer: Signer, -} diff --git a/basics/repository-layout/anchor/programs/carnival/src/state/food.rs b/basics/repository-layout/anchor/programs/carnival/src/state/food.rs deleted file mode 100644 index 62b5e04d6..000000000 --- a/basics/repository-layout/anchor/programs/carnival/src/state/food.rs +++ /dev/null @@ -1,25 +0,0 @@ -// Objects - -pub struct FoodStand { - pub name: String, - pub food_type: String, - pub tickets: u32, -} - -impl FoodStand { - pub fn new(name: String, food_type: String, tickets: u32) -> FoodStand { - FoodStand { - name, - food_type, - tickets, - } - } -} - -pub fn get_food_stands() -> Vec { - vec![ - FoodStand::new("Larry's Pizza".to_string(), "pizza".to_string(), 3), - FoodStand::new("Taco Shack".to_string(), "taco".to_string(), 2), - FoodStand::new("Dough Boy's".to_string(), "fried dough".to_string(), 1), - ] -} diff --git a/basics/repository-layout/anchor/programs/carnival/src/state/game.rs b/basics/repository-layout/anchor/programs/carnival/src/state/game.rs deleted file mode 100644 index 185547230..000000000 --- a/basics/repository-layout/anchor/programs/carnival/src/state/game.rs +++ /dev/null @@ -1,29 +0,0 @@ -// Objects - -pub struct Game { - pub name: String, - pub tickets: u32, - pub tries: u32, - pub prize: String, -} - -const DEFAULT_TICKETS_TO_PLAY: u32 = 3; - -impl Game { - pub fn new(name: String, tries: u32, prize: String) -> Game { - Game { - name, - tickets: DEFAULT_TICKETS_TO_PLAY, - tries, - prize, - } - } -} - -pub fn get_games() -> Vec { - vec![ - Game::new("Ring Toss".to_string(), 5, "teddy bear".to_string()), - Game::new("I Got It!".to_string(), 12, "goldfish".to_string()), - Game::new("Ladder Climb".to_string(), 1, "popcorn bucket".to_string()), - ] -} diff --git a/basics/repository-layout/anchor/programs/carnival/src/state/mod.rs b/basics/repository-layout/anchor/programs/carnival/src/state/mod.rs deleted file mode 100644 index 12a92a2cf..000000000 --- a/basics/repository-layout/anchor/programs/carnival/src/state/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod food; -pub mod game; -pub mod ride; diff --git a/basics/repository-layout/anchor/programs/carnival/src/state/ride.rs b/basics/repository-layout/anchor/programs/carnival/src/state/ride.rs deleted file mode 100644 index a3af23969..000000000 --- a/basics/repository-layout/anchor/programs/carnival/src/state/ride.rs +++ /dev/null @@ -1,28 +0,0 @@ -// Objects - -pub struct Ride { - pub name: String, - pub upside_down: bool, - pub tickets: u32, - pub min_height: u32, -} - -impl Ride { - pub fn new(name: String, upside_down: bool, tickets: u32, min_height: u32) -> Ride { - Ride { - name, - upside_down, - tickets, - min_height, - } - } -} - -pub fn get_rides() -> Vec { - vec![ - Ride::new("Tilt-a-Whirl".to_string(), false, 3, 48), - Ride::new("Scrambler".to_string(), false, 3, 48), - Ride::new("Ferris Wheel".to_string(), false, 5, 55), - Ride::new("Zero Gravity".to_string(), true, 5, 60), - ] -} diff --git a/basics/repository-layout/anchor/programs/carnival/tests/test_carnival.rs b/basics/repository-layout/anchor/programs/carnival/tests/test_carnival.rs deleted file mode 100644 index 19ffcd977..000000000 --- a/basics/repository-layout/anchor/programs/carnival/tests/test_carnival.rs +++ /dev/null @@ -1,168 +0,0 @@ -use { - anchor_lang::{solana_program::instruction::Instruction, InstructionData, ToAccountMetas}, - anchor_v2_testing::{litesvm::LiteSVM, Signer}, - solana_kite::{create_wallet, send_transaction_from_instructions}, -}; - -fn setup() -> (LiteSVM, anchor_v2_testing::Keypair) { - let program_id = carnival::id(); - let mut svm = anchor_v2_testing::svm(); - let bytes = include_bytes!("../../../target/deploy/carnival.so"); - svm.add_program(program_id, bytes).unwrap(); - let payer = create_wallet(&mut svm, 10_000_000_000).unwrap(); - (svm, payer) -} - -fn go_on_ride_ix( - payer: &anchor_v2_testing::Keypair, - name: &str, - height: u32, - ticket_count: u32, - ride_name: &str, -) -> Instruction { - let accounts = carnival::accounts::CarnivalAccountConstraints { - payer: payer.pubkey(), - } - .to_account_metas(None); - Instruction::new_with_bytes( - carnival::id(), - &carnival::instruction::GoOnRide { - name: name.to_string(), - height, - ticket_count, - ride_name: ride_name.to_string(), - } - .data(), - accounts, - ) -} - -fn play_game_ix( - payer: &anchor_v2_testing::Keypair, - name: &str, - ticket_count: u32, - game_name: &str, -) -> Instruction { - let accounts = carnival::accounts::CarnivalAccountConstraints { - payer: payer.pubkey(), - } - .to_account_metas(None); - Instruction::new_with_bytes( - carnival::id(), - &carnival::instruction::PlayGame { - name: name.to_string(), - ticket_count, - game_name: game_name.to_string(), - } - .data(), - accounts, - ) -} - -fn eat_food_ix( - payer: &anchor_v2_testing::Keypair, - name: &str, - ticket_count: u32, - food_stand_name: &str, -) -> Instruction { - let accounts = carnival::accounts::CarnivalAccountConstraints { - payer: payer.pubkey(), - } - .to_account_metas(None); - Instruction::new_with_bytes( - carnival::id(), - &carnival::instruction::EatFood { - name: name.to_string(), - ticket_count, - food_stand_name: food_stand_name.to_string(), - } - .data(), - accounts, - ) -} - -// Riders that have enough tickets and meet the height requirement succeed. -#[test] -fn test_go_on_ride_succeeds() { - let (mut svm, payer) = setup(); - // Scrambler costs 3 tickets and requires 48" min height; Alice has 15 - // tickets and is 56" tall. - let ix = go_on_ride_ix(&payer, "Alice", 56, 15, "Scrambler"); - send_transaction_from_instructions(&mut svm, vec![ix], &[&payer], &payer.pubkey(), None) - .unwrap(); -} - -// Insufficient tickets must produce a real error (NotEnoughTickets), not a -// silent Ok(). -#[test] -fn test_go_on_ride_rejects_insufficient_tickets() { - let (mut svm, payer) = setup(); - // Tilt-a-Whirl costs 3 tickets; Bob only has 1. - let ix = go_on_ride_ix(&payer, "Bob", 49, 1, "Tilt-a-Whirl"); - let result = - send_transaction_from_instructions(&mut svm, vec![ix], &[&payer], &payer.pubkey(), None); - assert!(result.is_err(), "ride must reject insufficient tickets"); -} - -// A rider below the minimum height must be rejected with RiderTooShort. -#[test] -fn test_go_on_ride_rejects_too_short() { - let (mut svm, payer) = setup(); - // Ferris Wheel requires 55" min height; Jimmy is 36" tall but has plenty - // of tickets. - let ix = go_on_ride_ix(&payer, "Jimmy", 36, 15, "Ferris Wheel"); - let result = - send_transaction_from_instructions(&mut svm, vec![ix], &[&payer], &payer.pubkey(), None); - assert!(result.is_err(), "ride must reject riders below min height"); -} - -// Unknown attraction name routes to ProgramError::InvalidInstructionData. -#[test] -fn test_go_on_ride_rejects_unknown_ride() { - let (mut svm, payer) = setup(); - let ix = go_on_ride_ix(&payer, "Alice", 60, 100, "Quantum Coaster"); - let result = - send_transaction_from_instructions(&mut svm, vec![ix], &[&payer], &payer.pubkey(), None); - assert!(result.is_err(), "unknown ride must be rejected"); -} - -#[test] -fn test_play_game_succeeds() { - let (mut svm, payer) = setup(); - // Ring Toss costs 3 tickets; Alice has 15. - let ix = play_game_ix(&payer, "Alice", 15, "Ring Toss"); - send_transaction_from_instructions(&mut svm, vec![ix], &[&payer], &payer.pubkey(), None) - .unwrap(); -} - -#[test] -fn test_play_game_rejects_insufficient_tickets() { - let (mut svm, payer) = setup(); - // Ring Toss costs 3 tickets; Mary only has 1. - let ix = play_game_ix(&payer, "Mary", 1, "Ring Toss"); - let result = - send_transaction_from_instructions(&mut svm, vec![ix], &[&payer], &payer.pubkey(), None); - assert!(result.is_err(), "game must reject insufficient tickets"); -} - -#[test] -fn test_eat_food_succeeds() { - let (mut svm, payer) = setup(); - // Dough Boy's costs 1 ticket; Bob has 6. - let ix = eat_food_ix(&payer, "Bob", 6, "Dough Boy's"); - send_transaction_from_instructions(&mut svm, vec![ix], &[&payer], &payer.pubkey(), None) - .unwrap(); -} - -#[test] -fn test_eat_food_rejects_insufficient_tickets() { - let (mut svm, payer) = setup(); - // Larry's Pizza costs 3 tickets; Mary has 1. - let ix = eat_food_ix(&payer, "Mary", 1, "Larry's Pizza"); - let result = - send_transaction_from_instructions(&mut svm, vec![ix], &[&payer], &payer.pubkey(), None); - assert!( - result.is_err(), - "food stand must reject insufficient tickets" - ); -} diff --git a/basics/repository-layout/native/CHANGELOG.md b/basics/repository-layout/native/CHANGELOG.md deleted file mode 100644 index 4f1163881..000000000 --- a/basics/repository-layout/native/CHANGELOG.md +++ /dev/null @@ -1,5 +0,0 @@ -# Changelog - -## 2026-07-07 - -Added this changelog. Changes prior to this date were tracked in git history only. diff --git a/basics/repository-layout/native/program/Cargo.toml b/basics/repository-layout/native/program/Cargo.toml deleted file mode 100644 index 232bf4574..000000000 --- a/basics/repository-layout/native/program/Cargo.toml +++ /dev/null @@ -1,27 +0,0 @@ -[package] -name = "repository-layout-program" -version = "0.1.0" -edition = "2021" - -[dependencies] -borsh = "1.6.1" -borsh-derive = "0.9.1" -solana-program = "4.0" - -[lib] -crate-type = ["cdylib", "lib"] - -[features] -custom-heap = [] -custom-panic = [] - -[lints.rust] -unexpected_cfgs = { level = "warn", check-cfg = ['cfg(target_os, values("solana"))'] } - -[dev-dependencies] -litesvm = "0.18.1" -solana-instruction = "3.0.0" -solana-keypair = "3.0.1" -solana-native-token = "3.0.0" -solana-pubkey = "4.3" -solana-transaction = "4.2" diff --git a/basics/repository-layout/native/program/src/error.rs b/basics/repository-layout/native/program/src/error.rs deleted file mode 100644 index 9db2fad45..000000000 --- a/basics/repository-layout/native/program/src/error.rs +++ /dev/null @@ -1 +0,0 @@ -// For any custom errors diff --git a/basics/repository-layout/native/program/src/instructions/eat_food.rs b/basics/repository-layout/native/program/src/instructions/eat_food.rs deleted file mode 100644 index b5b0cc2e5..000000000 --- a/basics/repository-layout/native/program/src/instructions/eat_food.rs +++ /dev/null @@ -1,36 +0,0 @@ -use solana_program::{entrypoint::ProgramResult, msg, program_error::ProgramError}; - -use crate::state::food; - -// InstructionData Data - -pub struct EatFoodInstructionData { - pub eater_name: String, - pub eater_ticket_count: u32, - pub food_stand: String, -} - -pub fn eat_food(ix: EatFoodInstructionData) -> ProgramResult { - let food_stands_list = food::get_food_stands(); - - for food_stand in food_stands_list.iter() { - if ix.food_stand.eq(&food_stand.name) { - msg!("Welcome to {}! What can I get you?", food_stand.name); - - if ix.eater_ticket_count < food_stand.tickets { - msg!( - " Sorry {}, our {} is {} tickets!", - ix.eater_name, - food_stand.food_type, - food_stand.tickets - ); - } else { - msg!(" Enjoy your {}!", food_stand.food_type); - }; - - return Ok(()); - } - } - - Err(ProgramError::InvalidInstructionData) -} diff --git a/basics/repository-layout/native/program/src/instructions/get_on_ride.rs b/basics/repository-layout/native/program/src/instructions/get_on_ride.rs deleted file mode 100644 index 638d5d294..000000000 --- a/basics/repository-layout/native/program/src/instructions/get_on_ride.rs +++ /dev/null @@ -1,52 +0,0 @@ -use solana_program::{entrypoint::ProgramResult, msg, program_error::ProgramError}; - -use crate::state::ride; - -// InstructionData Data - -pub struct GetOnRideInstructionData { - pub rider_name: String, - pub rider_height: u32, - pub rider_ticket_count: u32, - pub ride: String, -} - -pub fn get_on_ride(ix: GetOnRideInstructionData) -> ProgramResult { - let rides_list = ride::get_rides(); - - for ride in rides_list.iter() { - if ix.ride.eq(&ride.name) { - msg!("You're about to ride the {}!", ride.name); - - if ix.rider_ticket_count < ride.tickets { - msg!( - " Sorry {}, you need {} tickets to ride the {}!", - ix.rider_name, - ride.tickets, - ride.name - ); - return Ok(()); - }; - - if ix.rider_height < ride.min_height { - msg!( - " Sorry {}, you need to be {}\" tall to ride the {}!", - ix.rider_name, - ride.min_height, - ride.name - ); - return Ok(()); - }; - - msg!(" Welcome aboard the {}!", ride.name); - - if ride.upside_down { - msg!(" Btw, this ride goes upside down. Hold on tight!"); - }; - - return Ok(()); - } - } - - Err(ProgramError::InvalidInstructionData) -} diff --git a/basics/repository-layout/native/program/src/instructions/mod.rs b/basics/repository-layout/native/program/src/instructions/mod.rs deleted file mode 100644 index ee6ea6d1e..000000000 --- a/basics/repository-layout/native/program/src/instructions/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod eat_food; -pub mod get_on_ride; -pub mod play_game; diff --git a/basics/repository-layout/native/program/src/instructions/play_game.rs b/basics/repository-layout/native/program/src/instructions/play_game.rs deleted file mode 100644 index d78712bed..000000000 --- a/basics/repository-layout/native/program/src/instructions/play_game.rs +++ /dev/null @@ -1,41 +0,0 @@ -use solana_program::{entrypoint::ProgramResult, msg, program_error::ProgramError}; - -use crate::state::game; - -// InstructionData Data - -pub struct PlayGameInstructionData { - pub gamer_name: String, - pub gamer_ticket_count: u32, - pub game: String, -} - -pub fn play_game(ix: PlayGameInstructionData) -> ProgramResult { - let games_list = game::get_games(); - - for game in games_list.iter() { - if ix.game.eq(&game.name) { - msg!("You're about to play {}!", game.name); - - if ix.gamer_ticket_count < game.tickets { - msg!( - " Sorry {}, you need {} tickets to play {}!", - ix.gamer_name, - game.tickets, - game.name - ); - } else { - msg!(" Let's see what you got!"); - msg!( - " You get {} attempts and the prize is a {}!", - game.tries, - game.prize - ); - }; - - return Ok(()); - } - } - - Err(ProgramError::InvalidInstructionData) -} diff --git a/basics/repository-layout/native/program/src/lib.rs b/basics/repository-layout/native/program/src/lib.rs deleted file mode 100644 index f01f0620e..000000000 --- a/basics/repository-layout/native/program/src/lib.rs +++ /dev/null @@ -1,6 +0,0 @@ -// For setting up modules & configs - -pub mod error; -pub mod instructions; -pub mod processor; -pub mod state; diff --git a/basics/repository-layout/native/program/src/processor.rs b/basics/repository-layout/native/program/src/processor.rs deleted file mode 100644 index ae36137b4..000000000 --- a/basics/repository-layout/native/program/src/processor.rs +++ /dev/null @@ -1,50 +0,0 @@ -use borsh::{BorshDeserialize, BorshSerialize}; -use solana_program::{ - account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, msg, - program_error::ProgramError, pubkey::Pubkey, -}; - -use crate::instructions::{eat_food, get_on_ride, play_game}; - -// For processing everything at the entrypoint - -entrypoint!(process_instruction); - -#[derive(BorshSerialize, BorshDeserialize, Debug)] -pub struct CarnivalInstructionData { - pub name: String, - pub height: u32, - pub ticket_count: u32, - pub attraction: String, - pub attraction_name: String, -} - -pub fn process_instruction( - _program_id: &Pubkey, - _accounts: &[AccountInfo], - instruction_data: &[u8], -) -> ProgramResult { - let ix_data_object = CarnivalInstructionData::try_from_slice(instruction_data)?; - - msg!("Welcome to the carnival, {}!", ix_data_object.name); - - match ix_data_object.attraction.as_str() { - "ride" => get_on_ride::get_on_ride(get_on_ride::GetOnRideInstructionData { - rider_name: ix_data_object.name, - rider_height: ix_data_object.height, - rider_ticket_count: ix_data_object.ticket_count, - ride: ix_data_object.attraction_name, - }), - "game" => play_game::play_game(play_game::PlayGameInstructionData { - gamer_name: ix_data_object.name, - gamer_ticket_count: ix_data_object.ticket_count, - game: ix_data_object.attraction_name, - }), - "food" => eat_food::eat_food(eat_food::EatFoodInstructionData { - eater_name: ix_data_object.name, - eater_ticket_count: ix_data_object.ticket_count, - food_stand: ix_data_object.attraction_name, - }), - _ => Err(ProgramError::InvalidInstructionData), - } -} diff --git a/basics/repository-layout/native/program/src/state/food.rs b/basics/repository-layout/native/program/src/state/food.rs deleted file mode 100644 index 62b5e04d6..000000000 --- a/basics/repository-layout/native/program/src/state/food.rs +++ /dev/null @@ -1,25 +0,0 @@ -// Objects - -pub struct FoodStand { - pub name: String, - pub food_type: String, - pub tickets: u32, -} - -impl FoodStand { - pub fn new(name: String, food_type: String, tickets: u32) -> FoodStand { - FoodStand { - name, - food_type, - tickets, - } - } -} - -pub fn get_food_stands() -> Vec { - vec![ - FoodStand::new("Larry's Pizza".to_string(), "pizza".to_string(), 3), - FoodStand::new("Taco Shack".to_string(), "taco".to_string(), 2), - FoodStand::new("Dough Boy's".to_string(), "fried dough".to_string(), 1), - ] -} diff --git a/basics/repository-layout/native/program/src/state/game.rs b/basics/repository-layout/native/program/src/state/game.rs deleted file mode 100644 index 185547230..000000000 --- a/basics/repository-layout/native/program/src/state/game.rs +++ /dev/null @@ -1,29 +0,0 @@ -// Objects - -pub struct Game { - pub name: String, - pub tickets: u32, - pub tries: u32, - pub prize: String, -} - -const DEFAULT_TICKETS_TO_PLAY: u32 = 3; - -impl Game { - pub fn new(name: String, tries: u32, prize: String) -> Game { - Game { - name, - tickets: DEFAULT_TICKETS_TO_PLAY, - tries, - prize, - } - } -} - -pub fn get_games() -> Vec { - vec![ - Game::new("Ring Toss".to_string(), 5, "teddy bear".to_string()), - Game::new("I Got It!".to_string(), 12, "goldfish".to_string()), - Game::new("Ladder Climb".to_string(), 1, "popcorn bucket".to_string()), - ] -} diff --git a/basics/repository-layout/native/program/src/state/mod.rs b/basics/repository-layout/native/program/src/state/mod.rs deleted file mode 100644 index 12a92a2cf..000000000 --- a/basics/repository-layout/native/program/src/state/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod food; -pub mod game; -pub mod ride; diff --git a/basics/repository-layout/native/program/src/state/ride.rs b/basics/repository-layout/native/program/src/state/ride.rs deleted file mode 100644 index a3af23969..000000000 --- a/basics/repository-layout/native/program/src/state/ride.rs +++ /dev/null @@ -1,28 +0,0 @@ -// Objects - -pub struct Ride { - pub name: String, - pub upside_down: bool, - pub tickets: u32, - pub min_height: u32, -} - -impl Ride { - pub fn new(name: String, upside_down: bool, tickets: u32, min_height: u32) -> Ride { - Ride { - name, - upside_down, - tickets, - min_height, - } - } -} - -pub fn get_rides() -> Vec { - vec![ - Ride::new("Tilt-a-Whirl".to_string(), false, 3, 48), - Ride::new("Scrambler".to_string(), false, 3, 48), - Ride::new("Ferris Wheel".to_string(), false, 5, 55), - Ride::new("Zero Gravity".to_string(), true, 5, 60), - ] -} diff --git a/basics/repository-layout/native/program/tests/test.rs b/basics/repository-layout/native/program/tests/test.rs deleted file mode 100644 index e75b5d8e7..000000000 --- a/basics/repository-layout/native/program/tests/test.rs +++ /dev/null @@ -1,97 +0,0 @@ -use litesvm::LiteSVM; - -use repository_layout_program::processor::CarnivalInstructionData; -use solana_instruction::{AccountMeta, Instruction}; -use solana_keypair::{Keypair, Signer}; -use solana_program::native_token::LAMPORTS_PER_SOL; -use solana_pubkey::Pubkey; -use solana_transaction::Transaction; - -#[test] -fn test_repo_layout() { - let mut svm = LiteSVM::new(); - - let program_id = Pubkey::new_unique(); - // The .so is built into the workspace target/deploy by - // `cargo build-sbf --manifest-path=./program/Cargo.toml` (run from the project - // root). Rebuild after every program change: the binary is embedded at - // test-compile time, so a stale .so silently tests old code. - let program_bytes = include_bytes!("../../../../../target/deploy/repository_layout_program.so"); - - svm.add_program(program_id, program_bytes).unwrap(); - - let payer = Keypair::new(); - svm.airdrop(&payer.pubkey(), LAMPORTS_PER_SOL * 10).unwrap(); - - let data = borsh::to_vec(&CarnivalInstructionData { - name: "Jimmy".to_string(), - height: 36, - ticket_count: 15, - attraction: "ride".to_string(), - attraction_name: "Scrambler".to_string(), - }) - .unwrap(); - - let ix = Instruction { - program_id, - accounts: vec![AccountMeta::new(payer.pubkey(), true)], - data, - }; - - let tx = Transaction::new_signed_with_payer( - &[ix], - Some(&payer.pubkey()), - &[&payer], - svm.latest_blockhash(), - ); - - assert!(svm.send_transaction(tx).is_ok()); - - let data = borsh::to_vec(&CarnivalInstructionData { - name: "Jimmy".to_string(), - height: 36, - ticket_count: 15, - attraction: "game".to_string(), - attraction_name: "I Got It!".to_string(), - }) - .unwrap(); - - let ix = Instruction { - program_id, - accounts: vec![AccountMeta::new(payer.pubkey(), true)], - data, - }; - - let tx = Transaction::new_signed_with_payer( - &[ix], - Some(&payer.pubkey()), - &[&payer], - svm.latest_blockhash(), - ); - - assert!(svm.send_transaction(tx).is_ok()); - - let data = borsh::to_vec(&CarnivalInstructionData { - name: "Jimmy".to_string(), - height: 36, - ticket_count: 15, - attraction: "food".to_string(), - attraction_name: "Taco Shack".to_string(), - }) - .unwrap(); - - let ix = Instruction { - program_id, - accounts: vec![AccountMeta::new(payer.pubkey(), true)], - data, - }; - - let tx = Transaction::new_signed_with_payer( - &[ix], - Some(&payer.pubkey()), - &[&payer], - svm.latest_blockhash(), - ); - - assert!(svm.send_transaction(tx).is_ok()); -} diff --git a/basics/repository-layout/pinocchio/CHANGELOG.md b/basics/repository-layout/pinocchio/CHANGELOG.md deleted file mode 100644 index 4f1163881..000000000 --- a/basics/repository-layout/pinocchio/CHANGELOG.md +++ /dev/null @@ -1,5 +0,0 @@ -# Changelog - -## 2026-07-07 - -Added this changelog. Changes prior to this date were tracked in git history only. diff --git a/basics/repository-layout/pinocchio/README.md b/basics/repository-layout/pinocchio/README.md deleted file mode 100644 index df9728ab9..000000000 --- a/basics/repository-layout/pinocchio/README.md +++ /dev/null @@ -1,22 +0,0 @@ -# Recommended Program Layout: Solana Pinocchio - -The recommended multi-file layout for a Solana [program](https://solana.com/docs/terminology#program), written using the [Pinocchio](https://github.com/anza-xyz/pinocchio) framework with only the Solana toolchain. - -The `src` folder splits responsibilities the same way the `native` and `anchor` examples do: - -- `lib.rs` - module declarations and the program entrypoint -- `processor.rs` - decodes instruction data and dispatches to the right instruction -- `instructions/` - one file per instruction (`get_on_ride`, `play_game`, `eat_food`) -- `state/` - the program's data objects (`ride`, `game`, `food`) -- `error.rs` - custom errors - -## Setup - -1. Build the [program](https://solana.com/docs/terminology#program): `cargo build-sbf --manifest-path=./program/Cargo.toml` -2. Run the Rust + LiteSVM tests: `cargo test --manifest-path=./program/Cargo.toml` - -Rebuild the program after every change before re-running the tests: the tests embed the `.so` at compile time, so a stale binary silently tests old code. - -## Credits - -Ported from the [Pinocchio repository-layout example](https://github.com/solana-developers/program-examples/pull/582) contributed by [@MarkFeder](https://github.com/MarkFeder) to solana-developers/program-examples. diff --git a/basics/repository-layout/pinocchio/program/Cargo.toml b/basics/repository-layout/pinocchio/program/Cargo.toml deleted file mode 100644 index f926f1ef7..000000000 --- a/basics/repository-layout/pinocchio/program/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[package] -name = "repository-layout-pinocchio-program" -version = "0.1.0" -edition = "2021" - -[dependencies] -pinocchio.workspace = true -pinocchio-log.workspace = true - -[lib] -crate-type = ["cdylib", "lib"] - -[features] -custom-heap = [] -custom-panic = [] - -[lints.rust] -unexpected_cfgs = { level = "warn", check-cfg = ['cfg(target_os, values("solana"))'] } - -[dev-dependencies] -litesvm = "0.18.1" -solana-instruction = "3.0.0" -solana-keypair = "3.0.1" -solana-pubkey = "4.3" -solana-transaction = "4.2" -solana-native-token = "3.0.0" diff --git a/basics/repository-layout/pinocchio/program/src/error.rs b/basics/repository-layout/pinocchio/program/src/error.rs deleted file mode 100644 index 9db2fad45..000000000 --- a/basics/repository-layout/pinocchio/program/src/error.rs +++ /dev/null @@ -1 +0,0 @@ -// For any custom errors diff --git a/basics/repository-layout/pinocchio/program/src/instructions/eat_food.rs b/basics/repository-layout/pinocchio/program/src/instructions/eat_food.rs deleted file mode 100644 index f435e8281..000000000 --- a/basics/repository-layout/pinocchio/program/src/instructions/eat_food.rs +++ /dev/null @@ -1,35 +0,0 @@ -use pinocchio::{error::ProgramError, ProgramResult}; -use pinocchio_log::log; - -use crate::state::food; - -// InstructionData Data - -pub struct EatFoodInstructionData<'a> { - pub eater_name: &'a str, - pub eater_ticket_count: u32, - pub food_stand: &'a str, -} - -pub fn eat_food(ix: EatFoodInstructionData) -> ProgramResult { - for food_stand in food::FOOD_STANDS.iter() { - if ix.food_stand == food_stand.name { - log!("Welcome to {}! What can I get you?", food_stand.name); - - if ix.eater_ticket_count < food_stand.tickets { - log!( - " Sorry {}, our {} is {} tickets!", - ix.eater_name, - food_stand.food_type, - food_stand.tickets - ); - } else { - log!(" Enjoy your {}!", food_stand.food_type); - }; - - return Ok(()); - } - } - - Err(ProgramError::InvalidInstructionData) -} diff --git a/basics/repository-layout/pinocchio/program/src/instructions/get_on_ride.rs b/basics/repository-layout/pinocchio/program/src/instructions/get_on_ride.rs deleted file mode 100644 index a8946eabf..000000000 --- a/basics/repository-layout/pinocchio/program/src/instructions/get_on_ride.rs +++ /dev/null @@ -1,51 +0,0 @@ -use pinocchio::{error::ProgramError, ProgramResult}; -use pinocchio_log::log; - -use crate::state::ride; - -// InstructionData Data - -pub struct GetOnRideInstructionData<'a> { - pub rider_name: &'a str, - pub rider_height: u32, - pub rider_ticket_count: u32, - pub ride: &'a str, -} - -pub fn get_on_ride(ix: GetOnRideInstructionData) -> ProgramResult { - for ride in ride::RIDES.iter() { - if ix.ride == ride.name { - log!("You're about to ride the {}!", ride.name); - - if ix.rider_ticket_count < ride.tickets { - log!( - " Sorry {}, you need {} tickets to ride the {}!", - ix.rider_name, - ride.tickets, - ride.name - ); - return Ok(()); - }; - - if ix.rider_height < ride.min_height { - log!( - " Sorry {}, you need to be {} tall to ride the {}!", - ix.rider_name, - ride.min_height, - ride.name - ); - return Ok(()); - }; - - log!(" Welcome aboard the {}!", ride.name); - - if ride.upside_down { - log!(" Btw, this ride goes upside down. Hold on tight!"); - }; - - return Ok(()); - } - } - - Err(ProgramError::InvalidInstructionData) -} diff --git a/basics/repository-layout/pinocchio/program/src/instructions/mod.rs b/basics/repository-layout/pinocchio/program/src/instructions/mod.rs deleted file mode 100644 index ee6ea6d1e..000000000 --- a/basics/repository-layout/pinocchio/program/src/instructions/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod eat_food; -pub mod get_on_ride; -pub mod play_game; diff --git a/basics/repository-layout/pinocchio/program/src/instructions/play_game.rs b/basics/repository-layout/pinocchio/program/src/instructions/play_game.rs deleted file mode 100644 index 132fb09f6..000000000 --- a/basics/repository-layout/pinocchio/program/src/instructions/play_game.rs +++ /dev/null @@ -1,40 +0,0 @@ -use pinocchio::{error::ProgramError, ProgramResult}; -use pinocchio_log::log; - -use crate::state::game; - -// InstructionData Data - -pub struct PlayGameInstructionData<'a> { - pub gamer_name: &'a str, - pub gamer_ticket_count: u32, - pub game: &'a str, -} - -pub fn play_game(ix: PlayGameInstructionData) -> ProgramResult { - for game in game::GAMES.iter() { - if ix.game == game.name { - log!("You're about to play {}!", game.name); - - if ix.gamer_ticket_count < game.tickets { - log!( - " Sorry {}, you need {} tickets to play {}!", - ix.gamer_name, - game.tickets, - game.name - ); - } else { - log!(" Let's see what you got!"); - log!( - " You get {} attempts and the prize is a {}!", - game.tries, - game.prize - ); - }; - - return Ok(()); - } - } - - Err(ProgramError::InvalidInstructionData) -} diff --git a/basics/repository-layout/pinocchio/program/src/lib.rs b/basics/repository-layout/pinocchio/program/src/lib.rs deleted file mode 100644 index adf936c09..000000000 --- a/basics/repository-layout/pinocchio/program/src/lib.rs +++ /dev/null @@ -1,13 +0,0 @@ -#![no_std] - -// For setting up modules & configs - -pub mod error; -pub mod instructions; -pub mod processor; -pub mod state; - -use pinocchio::{entrypoint, nostd_panic_handler}; - -entrypoint!(processor::process_instruction); -nostd_panic_handler!(); diff --git a/basics/repository-layout/pinocchio/program/src/processor.rs b/basics/repository-layout/pinocchio/program/src/processor.rs deleted file mode 100644 index 2529de207..000000000 --- a/basics/repository-layout/pinocchio/program/src/processor.rs +++ /dev/null @@ -1,76 +0,0 @@ -use pinocchio::{error::ProgramError, AccountView, Address, ProgramResult}; -use pinocchio_log::log; - -use crate::instructions::{eat_food, get_on_ride, play_game}; - -// For processing everything at the entrypoint -// -// Instruction data layout (matches the native borsh layout): -// - name: u32 LE length + utf-8 bytes -// - height: u32 LE -// - ticket_count: u32 LE -// - attraction: u32 LE length + utf-8 bytes ("ride" | "game" | "food") -// - attraction_name: u32 LE length + utf-8 bytes - -pub fn process_instruction( - _program_id: &Address, - _accounts: &[AccountView], - instruction_data: &[u8], -) -> ProgramResult { - let mut cursor = 0; - let name = read_str(instruction_data, &mut cursor)?; - let height = read_u32(instruction_data, &mut cursor)?; - let ticket_count = read_u32(instruction_data, &mut cursor)?; - let attraction = read_str(instruction_data, &mut cursor)?; - let attraction_name = read_str(instruction_data, &mut cursor)?; - - log!("Welcome to the carnival, {}!", name); - - match attraction { - "ride" => get_on_ride::get_on_ride(get_on_ride::GetOnRideInstructionData { - rider_name: name, - rider_height: height, - rider_ticket_count: ticket_count, - ride: attraction_name, - }), - "game" => play_game::play_game(play_game::PlayGameInstructionData { - gamer_name: name, - gamer_ticket_count: ticket_count, - game: attraction_name, - }), - "food" => eat_food::eat_food(eat_food::EatFoodInstructionData { - eater_name: name, - eater_ticket_count: ticket_count, - food_stand: attraction_name, - }), - _ => Err(ProgramError::InvalidInstructionData), - } -} - -fn read_u32(data: &[u8], cursor: &mut usize) -> Result { - let end = cursor - .checked_add(4) - .ok_or(ProgramError::InvalidInstructionData)?; - if end > data.len() { - return Err(ProgramError::InvalidInstructionData); - } - let bytes: [u8; 4] = data[*cursor..end] - .try_into() - .map_err(|_| ProgramError::InvalidInstructionData)?; - *cursor = end; - Ok(u32::from_le_bytes(bytes)) -} - -fn read_str<'a>(data: &'a [u8], cursor: &mut usize) -> Result<&'a str, ProgramError> { - let len = read_u32(data, cursor)? as usize; - let end = cursor - .checked_add(len) - .ok_or(ProgramError::InvalidInstructionData)?; - if end > data.len() { - return Err(ProgramError::InvalidInstructionData); - } - let s = core::str::from_utf8(&data[*cursor..end]) - .map_err(|_| ProgramError::InvalidInstructionData)?; - *cursor = end; - Ok(s) -} diff --git a/basics/repository-layout/pinocchio/program/src/state/food.rs b/basics/repository-layout/pinocchio/program/src/state/food.rs deleted file mode 100644 index ecf1313f7..000000000 --- a/basics/repository-layout/pinocchio/program/src/state/food.rs +++ /dev/null @@ -1,25 +0,0 @@ -// Objects - -pub struct FoodStand { - pub name: &'static str, - pub food_type: &'static str, - pub tickets: u32, -} - -pub const FOOD_STANDS: &[FoodStand] = &[ - FoodStand { - name: "Larry's Pizza", - food_type: "pizza", - tickets: 3, - }, - FoodStand { - name: "Taco Shack", - food_type: "taco", - tickets: 2, - }, - FoodStand { - name: "Dough Boy's", - food_type: "fried dough", - tickets: 1, - }, -]; diff --git a/basics/repository-layout/pinocchio/program/src/state/game.rs b/basics/repository-layout/pinocchio/program/src/state/game.rs deleted file mode 100644 index 2f1e6423f..000000000 --- a/basics/repository-layout/pinocchio/program/src/state/game.rs +++ /dev/null @@ -1,31 +0,0 @@ -// Objects - -pub struct Game { - pub name: &'static str, - pub tickets: u32, - pub tries: u32, - pub prize: &'static str, -} - -const DEFAULT_TICKETS_TO_PLAY: u32 = 3; - -pub const GAMES: &[Game] = &[ - Game { - name: "Ring Toss", - tickets: DEFAULT_TICKETS_TO_PLAY, - tries: 5, - prize: "teddy bear", - }, - Game { - name: "I Got It!", - tickets: DEFAULT_TICKETS_TO_PLAY, - tries: 12, - prize: "goldfish", - }, - Game { - name: "Ladder Climb", - tickets: DEFAULT_TICKETS_TO_PLAY, - tries: 1, - prize: "popcorn bucket", - }, -]; diff --git a/basics/repository-layout/pinocchio/program/src/state/mod.rs b/basics/repository-layout/pinocchio/program/src/state/mod.rs deleted file mode 100644 index 12a92a2cf..000000000 --- a/basics/repository-layout/pinocchio/program/src/state/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod food; -pub mod game; -pub mod ride; diff --git a/basics/repository-layout/pinocchio/program/src/state/ride.rs b/basics/repository-layout/pinocchio/program/src/state/ride.rs deleted file mode 100644 index 2746d80e1..000000000 --- a/basics/repository-layout/pinocchio/program/src/state/ride.rs +++ /dev/null @@ -1,35 +0,0 @@ -// Objects - -pub struct Ride { - pub name: &'static str, - pub upside_down: bool, - pub tickets: u32, - pub min_height: u32, -} - -pub const RIDES: &[Ride] = &[ - Ride { - name: "Tilt-a-Whirl", - upside_down: false, - tickets: 3, - min_height: 48, - }, - Ride { - name: "Scrambler", - upside_down: false, - tickets: 3, - min_height: 48, - }, - Ride { - name: "Ferris Wheel", - upside_down: false, - tickets: 5, - min_height: 55, - }, - Ride { - name: "Zero Gravity", - upside_down: true, - tickets: 5, - min_height: 60, - }, -]; diff --git a/basics/repository-layout/pinocchio/program/tests/test.rs b/basics/repository-layout/pinocchio/program/tests/test.rs deleted file mode 100644 index bf10fd808..000000000 --- a/basics/repository-layout/pinocchio/program/tests/test.rs +++ /dev/null @@ -1,122 +0,0 @@ -use litesvm::LiteSVM; -use solana_instruction::{AccountMeta, Instruction}; -use solana_keypair::{Keypair, Signer}; -use solana_native_token::LAMPORTS_PER_SOL; -use solana_pubkey::Pubkey; -use solana_transaction::Transaction; - -// The .so is built into the workspace target/deploy by -// `cargo build-sbf --manifest-path=./program/Cargo.toml` (run from the project -// root). Rebuild after every program change: the binary is embedded at -// test-compile time, so a stale .so silently tests old code. -const PROGRAM_SO: &[u8] = - include_bytes!("../../../../../target/deploy/repository_layout_pinocchio_program.so"); - -// Builds the carnival instruction data in the wire format the program decodes: -// name (str), height (u32), ticket_count (u32), attraction (str), attraction_name (str) -// where each str is a u32 LE length followed by its utf-8 bytes. -fn carnival_ix_data( - name: &str, - height: u32, - ticket_count: u32, - attraction: &str, - attraction_name: &str, -) -> Vec { - fn push_str(buf: &mut Vec, s: &str) { - buf.extend_from_slice(&(s.len() as u32).to_le_bytes()); - buf.extend_from_slice(s.as_bytes()); - } - - let mut data = Vec::new(); - push_str(&mut data, name); - data.extend_from_slice(&height.to_le_bytes()); - data.extend_from_slice(&ticket_count.to_le_bytes()); - push_str(&mut data, attraction); - push_str(&mut data, attraction_name); - data -} - -fn setup() -> (LiteSVM, Pubkey, Keypair) { - let program_id = Pubkey::new_unique(); - - let mut svm = LiteSVM::new(); - svm.add_program(program_id, PROGRAM_SO).unwrap(); - - let payer = Keypair::new(); - svm.airdrop(&payer.pubkey(), LAMPORTS_PER_SOL * 10).unwrap(); - - (svm, program_id, payer) -} - -// The program ignores accounts entirely, so a single signer is all we need. -fn send_carnival(svm: &mut LiteSVM, program_id: Pubkey, payer: &Keypair, data: Vec) -> bool { - let ix = Instruction { - program_id, - accounts: vec![AccountMeta::new(payer.pubkey(), true)], - data, - }; - let tx = Transaction::new_signed_with_payer( - &[ix], - Some(&payer.pubkey()), - &[payer], - svm.latest_blockhash(), - ); - svm.send_transaction(tx).is_ok() -} - -#[test] -fn test_go_on_a_ride() { - let (mut svm, program_id, payer) = setup(); - assert!(send_carnival( - &mut svm, - program_id, - &payer, - carnival_ix_data("Alice", 56, 15, "ride", "Scrambler") - )); -} - -#[test] -fn test_play_a_game() { - let (mut svm, program_id, payer) = setup(); - assert!(send_carnival( - &mut svm, - program_id, - &payer, - carnival_ix_data("Bob", 49, 6, "game", "Ring Toss") - )); -} - -#[test] -fn test_eat_some_food() { - let (mut svm, program_id, payer) = setup(); - assert!(send_carnival( - &mut svm, - program_id, - &payer, - carnival_ix_data("Mary", 52, 3, "food", "Taco Shack") - )); -} - -#[test] -fn test_unknown_attraction_name_fails() { - let (mut svm, program_id, payer) = setup(); - // "ride" is a valid attraction type, but there is no ride by this name, so the - // program falls through its lookup table and returns InvalidInstructionData. - assert!(!send_carnival( - &mut svm, - program_id, - &payer, - carnival_ix_data("Jimmy", 40, 5, "ride", "Roller Coaster") - )); -} - -#[test] -fn test_unknown_attraction_type_fails() { - let (mut svm, program_id, payer) = setup(); - assert!(!send_carnival( - &mut svm, - program_id, - &payer, - carnival_ix_data("Jimmy", 40, 5, "spaceship", "Apollo") - )); -} diff --git a/basics/repository-layout/quasar/.gitignore b/basics/repository-layout/quasar/.gitignore deleted file mode 100644 index 262226bcb..000000000 --- a/basics/repository-layout/quasar/.gitignore +++ /dev/null @@ -1,12 +0,0 @@ -# Build artifacts -/target - -# Dependencies -node_modules - -# Environment -.env -.env.* - -# OS -.DS_Store diff --git a/basics/repository-layout/quasar/CHANGELOG.md b/basics/repository-layout/quasar/CHANGELOG.md deleted file mode 100644 index fd1f535cc..000000000 --- a/basics/repository-layout/quasar/CHANGELOG.md +++ /dev/null @@ -1,17 +0,0 @@ -# Changelog - -## [2026-07-22] - -### Changed - -- Migrated to Quasar 0.1.0 (`0.1.0-release` branch, rev `be60fca`): Quasar.toml - rewritten to the 0.1.0 schema, `idl-build` feature and `lib` crate-type added, - and tests rewritten from the direct QuasarSVM harness to `quasar-test` - (`#[quasar_test]` fixtures, `crate::cpi` instruction builders, `Outcome` - assertions). The `quasar-svm` git dev-dependency is gone; the hand-built - wire-format instruction encoding in tests was replaced by the generated - `GoOnRide`/`PlayGame`/`EatFood` instruction builders. - -## 2026-07-07 - -Added this changelog. Changes prior to this date were tracked in git history only. diff --git a/basics/repository-layout/quasar/Cargo.toml b/basics/repository-layout/quasar/Cargo.toml deleted file mode 100644 index 7767f26fc..000000000 --- a/basics/repository-layout/quasar/Cargo.toml +++ /dev/null @@ -1,41 +0,0 @@ -[package] -name = "quasar-carnival" -version = "0.1.0" -edition = "2021" - -# Standalone workspace - not part of the root program-examples workspace. -# Quasar uses a different resolver and dependency tree. -[workspace] - -[lints.rust.unexpected_cfgs] -level = "warn" -check-cfg = [ - 'cfg(target_os, values("solana"))', -] - -[lib] -# "lib" is required alongside "cdylib": the 0.1.0 IDL build compiles the -# crate as a host library. -crate-type = ["cdylib", "lib"] - -[features] -alloc = [] -client = [] -debug = [] -idl-build = ["quasar-lang/idl-build"] - -[dependencies] -# Quasar 0.1.0-release, pinned by rev: crates.io still hosts 0.0.0 -# placeholders for quasar-lang/quasar-cli, so the release line installs from -# git. Keep this rev in lockstep with the CLI rev installed by -# .github/workflows/quasar.yml. -quasar-lang = { git = "https://github.com/blueshift-gg/quasar", rev = "be60fca" } -# Pinned: quasar-lang asks for zeropod "0.3.3" and wincode 0.4, but zeropod -# 0.3.4 moved to wincode 0.5, so a fresh resolve (no lockfile is committed) -# splits the graph across two wincode versions and every Pod* trait bound -# fails. Unpin when quasar-lang's pinned rev accepts zeropod 0.3.4+. -zeropod = "=0.3.3" -solana-instruction = { version = "3.2.0" } - -[dev-dependencies] -quasar-test = { git = "https://github.com/blueshift-gg/quasar", rev = "be60fca" } diff --git a/basics/repository-layout/quasar/Quasar.toml b/basics/repository-layout/quasar/Quasar.toml deleted file mode 100644 index 2cd6f148a..000000000 --- a/basics/repository-layout/quasar/Quasar.toml +++ /dev/null @@ -1,9 +0,0 @@ -[project] -name = "quasar-carnival" - -[testing] -command = { program = "cargo", args = ["test"] } - -[clients] -path = "target/client" -targets = ["rust"] diff --git a/basics/repository-layout/quasar/README.md b/basics/repository-layout/quasar/README.md deleted file mode 100644 index af19e1874..000000000 --- a/basics/repository-layout/quasar/README.md +++ /dev/null @@ -1,34 +0,0 @@ -# Repository Layout (Quasar) - -Organize a program across modules (state, handlers, errors). - -See also: [Repository Layout overview](../README.md) and the [repository catalog](../../../README.md). - -## Major concepts - -- Multi-file layout -- Separation of concerns - -## Setup - -From `basics/repository-layout/quasar/`: - -```bash -quasar build -``` - -Prerequisites: [Quasar](https://quasar-lang.com/docs) CLI and [Agave](https://docs.anza.xyz/) toolchain (see `Quasar.toml`). - -## Testing - -In-process tests via **Quasar SVM** (`quasar-svm` in `Quasar.toml`): - -```bash -cargo test -``` - -Tests invoke instruction handlers and assert onchain state. No local validator. - -## Usage - -Read `src/` and `Quasar.toml`. Compare with the [Anchor](../anchor/) variant in the same example where present. diff --git a/basics/repository-layout/quasar/src/instructions/carnival_context.rs b/basics/repository-layout/quasar/src/instructions/carnival_context.rs deleted file mode 100644 index c990a8c79..000000000 --- a/basics/repository-layout/quasar/src/instructions/carnival_context.rs +++ /dev/null @@ -1,42 +0,0 @@ -use quasar_lang::prelude::*; - -use super::{eat_food, get_on_ride, play_game}; - -/// Minimal accounts context - a signer submits the transaction. -/// The instructions just process instruction data (no onchain state). -#[derive(Accounts)] -pub struct CarnivalAccountConstraints { - #[allow(dead_code)] - pub payer: Signer, -} - -#[inline(always)] -pub fn handle_go_on_ride( - _accounts: &mut CarnivalAccountConstraints, - name: &str, - height: u32, - ticket_count: u32, - ride_name: &str, -) -> Result<(), ProgramError> { - get_on_ride::get_on_ride(name, height, ticket_count, ride_name) -} - -#[inline(always)] -pub fn handle_play_game( - _accounts: &mut CarnivalAccountConstraints, - name: &str, - ticket_count: u32, - game_name: &str, -) -> Result<(), ProgramError> { - play_game::play_game(name, ticket_count, game_name) -} - -#[inline(always)] -pub fn handle_eat_food( - _accounts: &mut CarnivalAccountConstraints, - name: &str, - ticket_count: u32, - food_stand_name: &str, -) -> Result<(), ProgramError> { - eat_food::eat_food(name, ticket_count, food_stand_name) -} diff --git a/basics/repository-layout/quasar/src/instructions/eat_food.rs b/basics/repository-layout/quasar/src/instructions/eat_food.rs deleted file mode 100644 index 5fd0628a6..000000000 --- a/basics/repository-layout/quasar/src/instructions/eat_food.rs +++ /dev/null @@ -1,26 +0,0 @@ -use quasar_lang::prelude::*; - -use crate::state::food; - -/// Validate food stand ticket requirements and log the result. -pub fn eat_food(_name: &str, ticket_count: u32, food_stand_name: &str) -> Result<(), ProgramError> { - let stands = food::get_food_stands(); - - let mut i = 0; - while i < stands.len() { - if food::food_stand_name_matches(&stands[i], food_stand_name) { - log("Welcome to the food stand!"); - - if ticket_count < stands[i].tickets { - log("Sorry, you don't have enough tickets for this food!"); - } else { - log("Enjoy your food!"); - } - - return Ok(()); - } - i += 1; - } - - Err(ProgramError::InvalidInstructionData) -} diff --git a/basics/repository-layout/quasar/src/instructions/get_on_ride.rs b/basics/repository-layout/quasar/src/instructions/get_on_ride.rs deleted file mode 100644 index a817e63ce..000000000 --- a/basics/repository-layout/quasar/src/instructions/get_on_ride.rs +++ /dev/null @@ -1,43 +0,0 @@ -use quasar_lang::prelude::*; - -use crate::state::ride; - -/// Validate rider requirements and log the result. -/// Quasar's `log()` takes &str - no format! in no_std - so we use static -/// messages matching the Anchor version's logic without string interpolation. -pub fn get_on_ride( - _name: &str, - height: u32, - ticket_count: u32, - ride_name: &str, -) -> Result<(), ProgramError> { - let rides = ride::get_rides(); - - let mut i = 0; - while i < rides.len() { - if ride::ride_name_matches(&rides[i], ride_name) { - log("You're about to go on a ride!"); - - if ticket_count < rides[i].tickets { - log("Sorry, you don't have enough tickets for this ride!"); - return Ok(()); - } - - if height < rides[i].min_height { - log("Sorry, you're not tall enough for this ride!"); - return Ok(()); - } - - log("Welcome aboard the ride!"); - - if rides[i].upside_down { - log("This ride goes upside down. Hold on tight!"); - } - - return Ok(()); - } - i += 1; - } - - Err(ProgramError::InvalidInstructionData) -} diff --git a/basics/repository-layout/quasar/src/instructions/mod.rs b/basics/repository-layout/quasar/src/instructions/mod.rs deleted file mode 100644 index 8ec137d67..000000000 --- a/basics/repository-layout/quasar/src/instructions/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -pub mod carnival_context; -pub mod eat_food; -pub mod get_on_ride; -pub mod play_game; - -pub use carnival_context::*; diff --git a/basics/repository-layout/quasar/src/instructions/play_game.rs b/basics/repository-layout/quasar/src/instructions/play_game.rs deleted file mode 100644 index aec74f533..000000000 --- a/basics/repository-layout/quasar/src/instructions/play_game.rs +++ /dev/null @@ -1,27 +0,0 @@ -use quasar_lang::prelude::*; - -use crate::state::game; - -/// Validate game ticket requirements and log the result. -pub fn play_game(_name: &str, ticket_count: u32, game_name: &str) -> Result<(), ProgramError> { - let games = game::get_games(); - - let mut i = 0; - while i < games.len() { - if game::game_name_matches(&games[i], game_name) { - log("You're about to play a game!"); - - if ticket_count < games[i].tickets { - log("Sorry, you don't have enough tickets for this game!"); - } else { - log("Let's see what you got!"); - log("Good luck winning the prize!"); - } - - return Ok(()); - } - i += 1; - } - - Err(ProgramError::InvalidInstructionData) -} diff --git a/basics/repository-layout/quasar/src/lib.rs b/basics/repository-layout/quasar/src/lib.rs deleted file mode 100644 index 30a7cee71..000000000 --- a/basics/repository-layout/quasar/src/lib.rs +++ /dev/null @@ -1,50 +0,0 @@ -#![cfg_attr(not(test), no_std)] - -use quasar_lang::prelude::*; - -pub mod instructions; -use instructions::*; -pub mod state; -#[cfg(test)] -mod tests; - -declare_id!("8t94SEJh9jVjDwV7cbiuT6BvEsHo4YHP9x9a5rYH1NpP"); - -#[program] -mod quasar_carnival { - use super::*; - - /// Ride a carnival ride. Validates height and ticket requirements. - #[instruction(discriminator = 0)] - pub fn go_on_ride( - ctx: Ctx, - height: u32, - ticket_count: u32, - name: String<50>, - ride_name: String<50>, - ) -> Result<(), ProgramError> { - instructions::handle_go_on_ride(&mut ctx.accounts, name, height, ticket_count, ride_name) - } - - /// Play a carnival game. Validates ticket requirements. - #[instruction(discriminator = 1)] - pub fn play_game( - ctx: Ctx, - ticket_count: u32, - name: String<50>, - game_name: String<50>, - ) -> Result<(), ProgramError> { - instructions::handle_play_game(&mut ctx.accounts, name, ticket_count, game_name) - } - - /// Eat at a carnival food stand. Validates ticket requirements. - #[instruction(discriminator = 2)] - pub fn eat_food( - ctx: Ctx, - ticket_count: u32, - name: String<50>, - food_stand_name: String<50>, - ) -> Result<(), ProgramError> { - instructions::handle_eat_food(&mut ctx.accounts, name, ticket_count, food_stand_name) - } -} diff --git a/basics/repository-layout/quasar/src/state/food.rs b/basics/repository-layout/quasar/src/state/food.rs deleted file mode 100644 index a9f92591e..000000000 --- a/basics/repository-layout/quasar/src/state/food.rs +++ /dev/null @@ -1,31 +0,0 @@ -/// A carnival food stand. -pub struct FoodStand { - pub name: &'static str, - pub food_type: &'static str, - pub tickets: u32, -} - -pub fn food_stand_name_matches(stand: &FoodStand, other: &str) -> bool { - stand.name.as_bytes() == other.as_bytes() -} - -/// Static list of food stands. -pub fn get_food_stands() -> &'static [FoodStand] { - &[ - FoodStand { - name: "Larry's Pizza", - food_type: "pizza", - tickets: 3, - }, - FoodStand { - name: "Taco Shack", - food_type: "taco", - tickets: 2, - }, - FoodStand { - name: "Dough Boy's", - food_type: "fried dough", - tickets: 1, - }, - ] -} diff --git a/basics/repository-layout/quasar/src/state/game.rs b/basics/repository-layout/quasar/src/state/game.rs deleted file mode 100644 index b088c1570..000000000 --- a/basics/repository-layout/quasar/src/state/game.rs +++ /dev/null @@ -1,37 +0,0 @@ -/// A carnival game with ticket cost, attempts, and prize. -pub struct Game { - pub name: &'static str, - pub tickets: u32, - pub tries: u32, - pub prize: &'static str, -} - -const DEFAULT_TICKETS_TO_PLAY: u32 = 3; - -pub fn game_name_matches(game: &Game, other: &str) -> bool { - game.name.as_bytes() == other.as_bytes() -} - -/// Static list of carnival games. -pub fn get_games() -> &'static [Game] { - &[ - Game { - name: "Ring Toss", - tickets: DEFAULT_TICKETS_TO_PLAY, - tries: 5, - prize: "teddy bear", - }, - Game { - name: "I Got It!", - tickets: DEFAULT_TICKETS_TO_PLAY, - tries: 12, - prize: "goldfish", - }, - Game { - name: "Ladder Climb", - tickets: DEFAULT_TICKETS_TO_PLAY, - tries: 1, - prize: "popcorn bucket", - }, - ] -} diff --git a/basics/repository-layout/quasar/src/state/mod.rs b/basics/repository-layout/quasar/src/state/mod.rs deleted file mode 100644 index 12a92a2cf..000000000 --- a/basics/repository-layout/quasar/src/state/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod food; -pub mod game; -pub mod ride; diff --git a/basics/repository-layout/quasar/src/state/ride.rs b/basics/repository-layout/quasar/src/state/ride.rs deleted file mode 100644 index 644bb40c3..000000000 --- a/basics/repository-layout/quasar/src/state/ride.rs +++ /dev/null @@ -1,43 +0,0 @@ -/// A carnival ride with requirements. -/// Uses &'static str instead of String for no_std compatibility. -pub struct Ride { - pub name: &'static str, - pub upside_down: bool, - pub tickets: u32, - pub min_height: u32, -} - -/// Check if a ride name matches (byte comparison, no alloc). -pub fn ride_name_matches(ride: &Ride, other: &str) -> bool { - ride.name.as_bytes() == other.as_bytes() -} - -/// Static list of carnival rides. -pub fn get_rides() -> &'static [Ride] { - &[ - Ride { - name: "Tilt-a-Whirl", - upside_down: false, - tickets: 3, - min_height: 48, - }, - Ride { - name: "Scrambler", - upside_down: false, - tickets: 3, - min_height: 48, - }, - Ride { - name: "Ferris Wheel", - upside_down: false, - tickets: 5, - min_height: 55, - }, - Ride { - name: "Zero Gravity", - upside_down: true, - tickets: 5, - min_height: 60, - }, - ] -} diff --git a/basics/repository-layout/quasar/src/tests.rs b/basics/repository-layout/quasar/src/tests.rs deleted file mode 100644 index 04c7127a5..000000000 --- a/basics/repository-layout/quasar/src/tests.rs +++ /dev/null @@ -1,152 +0,0 @@ -use { - crate::cpi::{EatFoodInstruction, GoOnRideInstruction, PlayGameInstruction}, - quasar_test::prelude::*, -}; - -// Deterministic addresses keep tests independent of discovery order. -const USER: Pubkey = Pubkey::new_from_array([1; 32]); - -fn go_on_ride(name: &str, height: u32, ticket_count: u32, ride_name: &str) -> GoOnRideInstruction { - GoOnRideInstruction { - payer: USER, - height, - ticket_count, - name: name.to_string().into(), - ride_name: ride_name.to_string().into(), - } -} - -fn play_game(name: &str, ticket_count: u32, game_name: &str) -> PlayGameInstruction { - PlayGameInstruction { - payer: USER, - ticket_count, - name: name.to_string().into(), - game_name: game_name.to_string().into(), - } -} - -fn eat_food(name: &str, ticket_count: u32, food_stand_name: &str) -> EatFoodInstruction { - EatFoodInstruction { - payer: USER, - ticket_count, - name: name.to_string().into(), - food_stand_name: food_stand_name.to_string().into(), - } -} - -#[quasar_test] -fn tall_rider_with_tickets_boards_the_ride(test: &mut Test) { - test.add(Wallet::new().at(USER)); - - let outcome = test.send(go_on_ride("Alice", 60, 5, "Ferris Wheel")); - outcome.succeeds(); - - let logs = outcome.logs().join("\n"); - assert!( - logs.contains("about to go on a ride"), - "should announce ride" - ); - assert!(logs.contains("Welcome aboard"), "should welcome aboard"); -} - -#[quasar_test] -fn short_rider_is_turned_away(test: &mut Test) { - test.add(Wallet::new().at(USER)); - - let outcome = test.send(go_on_ride("Bob", 40, 5, "Ferris Wheel")); - outcome.succeeds(); - - let logs = outcome.logs().join("\n"); - assert!( - logs.contains("not tall enough"), - "should reject short rider" - ); -} - -#[quasar_test] -fn rider_without_enough_tickets_is_turned_away(test: &mut Test) { - test.add(Wallet::new().at(USER)); - - let outcome = test.send(go_on_ride("Charlie", 60, 1, "Zero Gravity")); - outcome.succeeds(); - - let logs = outcome.logs().join("\n"); - assert!( - logs.contains("enough tickets"), - "should reject insufficient tickets" - ); -} - -#[quasar_test] -fn upside_down_ride_warns_the_rider(test: &mut Test) { - test.add(Wallet::new().at(USER)); - - let outcome = test.send(go_on_ride("Dave", 65, 5, "Zero Gravity")); - outcome.succeeds(); - - let logs = outcome.logs().join("\n"); - assert!( - logs.contains("upside down"), - "should warn about upside down" - ); -} - -#[quasar_test] -fn player_with_tickets_plays_the_game(test: &mut Test) { - test.add(Wallet::new().at(USER)); - - let outcome = test.send(play_game("Alice", 5, "Ring Toss")); - outcome.succeeds(); - - let logs = outcome.logs().join("\n"); - assert!(logs.contains("about to play"), "should announce game"); - assert!(logs.contains("what you got"), "should encourage player"); -} - -#[quasar_test] -fn player_without_enough_tickets_is_turned_away(test: &mut Test) { - test.add(Wallet::new().at(USER)); - - let outcome = test.send(play_game("Bob", 1, "Ring Toss")); - outcome.succeeds(); - - let logs = outcome.logs().join("\n"); - assert!( - logs.contains("enough tickets"), - "should reject insufficient tickets" - ); -} - -#[quasar_test] -fn visitor_with_tickets_eats_at_the_stand(test: &mut Test) { - test.add(Wallet::new().at(USER)); - - let outcome = test.send(eat_food("Alice", 3, "Larry's Pizza")); - outcome.succeeds(); - - let logs = outcome.logs().join("\n"); - assert!(logs.contains("food stand"), "should welcome to food stand"); - assert!(logs.contains("Enjoy"), "should say enjoy"); -} - -#[quasar_test] -fn visitor_without_enough_tickets_cannot_eat(test: &mut Test) { - test.add(Wallet::new().at(USER)); - - let outcome = test.send(eat_food("Bob", 0, "Larry's Pizza")); - outcome.succeeds(); - - let logs = outcome.logs().join("\n"); - assert!( - logs.contains("enough tickets"), - "should reject insufficient tickets" - ); -} - -#[quasar_test] -fn unknown_ride_name_is_rejected(test: &mut Test) { - test.add(Wallet::new().at(USER)); - - test.send(go_on_ride("Eve", 60, 5, "Nonexistent Ride")) - .fails(ProgramError::InvalidInstructionData); -} diff --git a/scripts/generate-quasar-readmes.mjs b/scripts/generate-quasar-readmes.mjs index fbe1160dc..aae62dca0 100644 --- a/scripts/generate-quasar-readmes.mjs +++ b/scripts/generate-quasar-readmes.mjs @@ -80,11 +80,6 @@ const examples = { purpose: "Compute account size and minimum rent-exempt [lamports](https://solana.com/docs/terminology#lamport).", concepts: ["Rent-exempt balance", "Space planning"], }, - "basics/repository-layout/quasar": { - title: "Repository Layout", - purpose: "Organize a program across modules (state, handlers, errors).", - concepts: ["Multi-file layout", "Separation of concerns"], - }, "basics/transfer-sol/quasar": { title: "Transfer SOL", purpose: "Transfer native SOL via the System Program.",