Версії для прикладів у «Структура Anchor-проєкту: каталоги та файли» перевірено 2 серпня 2026 року. Стабільна гілка Anchor v1 має релізи 1.0.x і орієнтується на Solana 3.x; Anchor v2 у документації позначений як alpha. Приклади для Anchor 0.29–0.32 залишаються лише відтворюваними прикладами для зафіксованого legacy-середовища: їх не слід переносити в новий проєкт без міграції залежностей і повторного тестування.
Після виконання anchor init ви отримуєте готовий каркас проєкту. Кожен каталог і файл у ньому має чітке призначення. Розуміння цієї структури дозволяє впорядковано додавати модулі, писати тести та налаштовувати розгортання без хаотичного копіювання файлів. Нижче — детальний розбір кожного елемента з орієнтиром на Anchor 0.30.1, Rust 1.77.0 та кластер Devnet.
Каталог programs/
Це ядро проєкту: саме тут reside смарт-контракти (у термінології Solana — програми) мовою Rust. Кожна підпапка всередині programs/ — це окрема програма з власним Cargo.toml. У найпростішому випадку після ініціалізації ви побачите одну підпапку, назва якої збігається з іменем проєкту.
Організація модулів у lib.rs
Файл programs/<name>/src/lib.rs</name> — точка входу програми. Саме тут Anchor-макрос #[program] реєструє всі інструкції (functions), які будуть доступні зовні через RPC-виклики. Типова структура lib.rs для однофайлової програми виглядає так:
use anchor_lang::prelude::*; declare_id!("YOUR_PROGRAM_ID_HERE"); #[program] pub mod my_program { use super::*; pub fn initialize(ctx: Context<Initialize>) -> Result<()> { Ok(()) } } #[derive(Accounts)] pub struct Initialize {}
Коли програма росте, утримувати все в одному файлі стає незручно. Anchor не нав'язує сувору архітектуру, але практика показує, що розбиття на модулі суттєво полегшує навігацію.
Розділення на файли: state.rs, instructions.rs, errors.rs
Поширений і зручний патерн — винести визначення стану, інструкції та помилки в окремі файли. Приклад структури src/:
- state.rs — структури акаунтів (з макросом
#[derive(Accounts)]) та серіалізовні дані (з#[account]). Це місце, де ви описуєте, які поля зберігатиме ваш акаунт і які обмеження на нього накладаються. - instructions.rs — логіка кожної інструкції. Файл імпортує структури з
state.rsі містить функції всередині блоку#[program]або як окремі модулі. - errors.rs — кастомні коди помилок через
#[error_code]. Відокремлення дозволяє централізовано керувати переліком помилок і уникати циклічних залежностей. - lib.rs — залишається точкою входу, яка збирає модулі разом.
Приклад errors.rs:
use anchor_lang::prelude::*; #[error_code] pub enum MyProgramError { #[msg("Недостатньо коштів для операції")] InsufficientFunds, #[msg("Невірний власник акаунта")] InvalidOwner, }
Після створення файлів не забудьте додати mod state;, mod instructions;, mod errors; у lib.rs.
Каталог tests/
Каталог tests/ містить інтеграційні тести. Вони не виконуються всередині Rust-компілятора програми — це окремі TypeScript-файли, які запускаються через anchor test і взаємодіють з програмою через RPC, як це робив би реальний клієнт.
Інтеграційні тести на TypeScript
Типовий файл tests/my_program.ts починається з імпорту Anchor-клієнта та IDL (Interface Definition Language), який генерується автоматично під час збірки:
import * as anchor from "@coral-xyz/anchor"; import { Program } from "@coral-xyz/anchor"; import { MyProgram } from "../target/types/my_program"; import { assert } from "chai"; describe("my_program", () => { anchor.setProvider(anchor.AnchorProvider.env()); const program = anchor.workspace.MyProgram as Program<MyProgram>; it("Ініціалізує програму", async () => { const tx = await program.methods.initialize().rpc(); console.log("Транзакція:", tx); }); });
IDL зберігається у target/idl/ після виконання anchor build. Тести читають його звідти, тому перед запуском тестів обов'язково виконайте збірку.
Як тести взаємодіють з локальним validator
Команда anchor test виконує три кроки послідовно:
- Запускає локальний
solana-test-validatorу фоновому режимі. - Розгортає вашу програму на цьому локальному валідаторі.
- Запускає Mocha-тести з TypeScript, підключаючись до локального RPC-ендпоінту (зазвичай
http://127.0.0.1:8899).
Після завершення тестів валідатор зупиняється автоматично. Якщо вам потрібно залишити валідатор працюючим для ручної перевірки (наприклад, через Solana Explorer у локальному режимі), використовуйте anchor test --skip-build після попереднього ручного запуску валідатора.
Обмеження: локальний валідатор не відтворює повну поведінку мережі Devnet. Зокрема, таймінг слотів, навантаження на мережу та деякі edge-case-сценарії можуть відрізнятися. Тому позитивний результат локальних тестів не гарантує ідентичну поведінку на Devnet.
Каталог migrations/
Каталог migrations/ містить скрипти розгортання. У стандартному шаблоні Anchor тут є єдиний файл deploy.sh.
Скрипти розгортання (deploy)
Типовий вміст deploy.sh мінімальний:
#!/bin/bash anchor deploy
У реальних проєктах цей скрипт розширюють: додають ініціалізацію конкретних акаунтів, створення токен-майнт-акаунтів, завантаження початкових даних тощо. Наприклад, якщо вашій програмі потрібен SPL Token mint, його створення логічно розмістити саме тут.
Залежність від Anchor.toml
Скрипт deploy.sh не приймає параметри безпосередньо — він покладається на конфігурацію з Anchor.toml. Зокрема, команда anchor deploy читає параметр [programs.<cluster>], щоб визначити, куди саме розгортати байткод, і wallet, щоб підписати транзакцію. Якщо Anchor.toml налаштований на localnet, а ви очікуєте розгортання на Devnet, скрипт розгорне програму не туди.
Файл Anchor.toml
Це центральний конфігураційний файл проєкту. Anchor CLI читає його перед будь-якою командою: build, test, deploy, run.
Ключові параметри: cluster, wallet, scripts
Мінімальний робочий Anchor.toml для локальної розробки:
[features] seeds = false [programs.localnet] my_program = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS" [registry] url = "https://api.apr.dev" [provider] cluster = "localnet" wallet = "~/.config/solana/id.json" [scripts] test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"
Розбір ключових полів:
- [programs.<cluster>] — мапінг імені програми на її Program ID (адреса в мережі). Кластер у ключі (наприклад,
localnet,devnet) має збігатися зі значеннямclusterу секції[provider]. Якщо збігу немає — Anchor не знайде Program ID і видасть помилку. - cluster — цільовий кластер:
localnet,devnet,testnetабо URL кастомного RPC. - wallet — шлях до файлу з ключовою парою (keypair), який підписуватиме транзакції. Для Devnet це має бути акаунт із SOL (отримати через faucet).
- scripts.test — команда, яку виконує
anchor test. Зазвичай це запуск ts-mocha.
Як налаштувати для Devnet
Для переходу на Devnet потрібно внести дві зміни:
- Додати секцію
[programs.devnet]з Program ID, який ви отримали після першого розгортання (або згенерували черезsolana-keygen pubkey). - Змінити
clusterнаdevnet.
[programs.devnet] my_program = "YourRealDevnetProgramIDHere" [provider] cluster = "devnet" wallet = "~/.config/solana/devnet-wallet.json"
Після цього anchor deploy відправить програму на Devnet, а anchor test спробує підключитися до публічного Devnet-RPC. Важливо: для тестів на Devnet ваш гаманець має мати достатньо SOL для оплати транзакцій, а тести повинні бути написані з урахуванням реальної затримки мережі (додайте commitment: "confirmed" або збільште таймаути).
Файл Cargo.toml програми
Кожна програма в programs/ має власний Cargo.toml — стандартний файл конфігурації для Rust-проєктів. Anchor додає сюди специфічні залежності та налаштування.
Залежності: anchor-lang, spl-token
Типовий programs/my_program/Cargo.toml:
[package] name = "my_program" version = "0.1.0" description = "Created with Anchor" edition = "2021" [lib] crate-type = ["cdylib", "lib"] name = "my_program" [features] no-entrypoint = [] no-idl = [] no-log-ix-name = [] cpi = ["no-entrypoint"] default = [] [dependencies] anchor-lang = "0.30.1" spl-token = "4.0.0"
Ключові моменти:
- crate-type:
cdylibпотрібен для компіляції у WebAssembly (формат, який використовує Solana Runtime).lib— для локальних тестів та генерації IDL. - anchor-lang: основна бібліотека Anchor. Версія має збігатися з версією Anchor CLI (
anchor --version). Несумісність версій призводить до неочевидних помилок компіляції. - spl-token: додається, якщо програма працює з SPL Token. Якщо ви не використовуєте токени, не додавайте цю залежність — вона збільшує розмір байткоду.
Якщо вам потрібні додаткові SPL-програми (наприклад, spl-associated-token-account), додавайте їх окремо і стежте за сумісністю версій. Бібліотеки з простору spl-* мають бути узгоджені між собою.
Фічі та профілі компіляції
Секція [features] у Cargo.toml програми керує поведінкою компіляції:
- no-entrypoint — виключає стандартну точку входу Solana. Використовується, коли програма викликається через CPI (Cross-Program Invocation) і не повинна приймати прямі транзакції.
- no-idl — не генерує IDL при збірці. Корисно для production, якщо ви не хочете розкривати інтерфейс програми.
- no-log-ix-name — виключає логування імен інструкцій, що зменшує розмір байткоду.
Щодо профілів компіляції: у стандартному шаблоні Anchor не додає кастомні профілі до Cargo.toml програми. Проте для production-збірки з оптимізаціями можна додати:
[profile.release] overflow-checks = true lto = true codegen-units = 1
Це зменшує розмір байткоду та покращує продуктивність, але збільшує час компіляції. Для розробки на Devnet стандартних налаштувань достатньо.
Обмеження, про яке варто знати: максимальний розмір програми на Solana становить 200 КБ (з урахуванням усіх залежностей). Якщо після додавання spl-token та інших крейтів ви наближаєтесь до цієї межі, перевірте розмір через solana program show <PROGRAM_ID> після розгортання на Devnet.
Наступний логічний крок після освоєння структури проєкту — зрозуміти, як Anchor перевіряє коректність переданих акаунтів під час виклику інструкцій. Це тема наступного розділу: Anchor constraints: обмеження та перевірки в програмах.