Anchor
Anchor для початківців

Anchor для початківців

Anchor 101

Вступ до Anchor

What is Anchor

Anchor — це провідний фреймворк для розробки смарт-контрактів на Solana, що пропонує повний робочий процес для написання, тестування, розгортання та взаємодії з програмами в мережі.

Ключові переваги

  • Зменшення шаблонного коду: Anchor абстрагує повторювану роботу з управління обліковими записами, серіалізації інструкцій та обробки помилок, щоб ви могли зосередитися лише на основній бізнес-логіці.
  • Вбудована безпека: Ретельні перевірки, такі як верифікація власності облікових записів та валідація даних, працюють з коробки, запобігаючи багатьом поширеним вразливостям ще до їх появи.

Макроси Anchor

  • declare_id!(): Оголошує, за якою адресою в мережі розміщується програма.
  • #[program]: Позначає модуль, що містить кожну точку входу інструкції та функцію бізнес-логіки.
  • #[derive(Accounts)]: Перераховує облікові записи, які потребує інструкція, та автоматично забезпечує їхні обмеження.
  • #[error_code]: Визначає користувацькі, зрозумілі типи помилок, які роблять налагодження чіткішим і швидшим.

Разом ці процедурні макроси абстрагують низькорівневе управління байтами, дозволяючи вам створювати безпечні, готові до виробництва програми Solana з набагато меншими зусиллями.

Структура програми

Почнімо з базової версії програми, щоб детально пояснити, що насправді робить кожен макрос:

rust
declare_id!("22222222222222222222222222222222222222222222");
 
#[program]
pub mod blueshift_anchor_vault {
    use super::*;
 
    pub fn deposit(ctx: Context<VaultAction>, amount: u64) -> Result<()> {
        // ...
        Ok(())
    }
 
    pub fn withdraw(ctx: Context<VaultAction>) -> Result<()> {
        // ...
        Ok(())
    }
}
 
#[derive(Accounts)]
pub struct VaultAction<'info> {
    // ...
}
 
#[error_code]
pub enum VaultError {
    // ...
}

Це трансформується у сфокусовані модулі замість того, щоб усе запихати в lib.rs для більш структурованих програм. Дерево папок програми виглядатиме приблизно так:

 
src
├── instructions
│       ├── instruction1.rs
│       ├── mod.rs
│       ├── instruction2.rs
│       └── instruction3.rs
├── errors.rs
├── lib.rs
└── state.rs

declare_id!()

Макрос declare_id!() призначає вашій програмі її адресу в мережі; унікальний відкритий ключ, отриманий з пари ключів у папці target проєкту. Ця пара ключів підписує та розгортає скомпільований бінарний файл .so, що містить усю логіку та дані програми.

Примітка: Ми використовуємо заповнювач 222222... у прикладах Blueshift через наш внутрішній набір тестів. У виробничому середовищі Anchor згенерує для вас новий ідентифікатор програми, коли ви запустите стандартні команди збірки та розгортання.

#[program] і #[derive(Accounts)]

Кожна інструкція має власну структуру Context, яка перераховує всі облікові записи і, за потреби, будь-які дані, які знадобляться інструкції.

У цьому прикладі deposit і withdraw використовують одні й ті самі облікові записи; з цієї причини ми створимо єдину структуру облікового запису під назвою VaultAction, щоб зробити все ефективнішим і простішим.

Детальніше про макрос #[derive(Accounts)]

rust
#[derive(Accounts)]
pub struct VaultAction<'info> {
  #[account(mut)]
  pub signer: Signer<'info>,
 
  #[account(
    mut,
    seeds = [b"vault", signer.key().as_ref()],
    bump,
  )]
  pub vault: SystemAccount<'info>,
 
  pub system_program: Program<'info, System>,
}

Як ми бачимо з фрагмента коду, макрос #[derive(Accounts)] виконує три критично важливі функції:

  • Оголошує всі облікові записи, які потрібні конкретній інструкції.
  • Автоматично застосовує перевірки обмежень, блокуючи багато помилок і потенційних вразливостей під час виконання.
  • Генерує допоміжні методи, які дозволяють безпечно отримувати доступ до облікових записів і змінювати їх.

Він досягає цього за допомогою комбінації типів облікових записів та вбудованих атрибутів.

Типи облікових записів у нашому прикладі

  • Signer<'info>: Перевіряє, чи обліковий запис підписав транзакцію; важливо для безпеки та для CPI, які вимагають підпису.
  • SystemAccount<'info>: Підтверджує, що обліковий запис належить System Program.
  • Program<'info, System>: Гарантує, що обліковий запис є виконуваним і відповідає ідентифікатору System Program, що дозволяє виконувати CPI, такі як створення облікового запису або переказ лампортів.

Вбудовані атрибути, з якими ви зустрінетесь

  • mut: Позначає обліковий запис як змінюваний; обов'язково, коли його баланс лампортів або дані можуть змінюватися.
  • seeds & bump: Перевіряє, чи обліковий запис є адресою, похідною від програми (PDA), згенерованою з наданих початкових значень плюс байт корекції.

Примітка PDA важливі, тому що:

  • Коли їх використовує програма, якій вони належать, PDA можуть підписувати CPI від імені програми.
  • Вони надають детерміновані, перевірювані адреси для збереження стану програми.

#[error_code]

Макрос #[error_code] дозволяє визначати чіткі, користувацькі помилки всередині програми.

rust
#[error_code]
pub enum VaultError {
    #[msg("Vault already exists")]
    VaultAlreadyExists,
    #[msg("Invalid amount")]
    InvalidAmount,
}

Кожен варіант перерахування може містити атрибут #[msg(...)], який записує описовий рядок щоразу, коли виникає помилка; це набагато корисніше, ніж просто числовий код під час налагодження.

Blueshift © 2025Commit: 6d01265
Blueshift | Anchor для початківців | Основи Anchor