Розробка смарт-контрактів на Rust (Solana)

Проєктуємо та розробляємо блокчейн-рішення повного циклу: від архітектури смарт-контрактів до запуску DeFi-протоколів, NFT-маркетплейсів та криптобірж. Аудит безпеки, токеноміка, інтеграція з наявною інфраструктурою.
Показано 1 з 1Усі 1306 послуг
Розробка смарт-контрактів на Rust (Solana)
Складний
~3-5 днів
Часті запитання

Напрямки блокчейн-розробки

Етапи блокчейн-розробки

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1308
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1221
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    921
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1149
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    612
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    886

Розробка смарт-контрактів на Rust (Solana)

Solana привертає розробників субсекундною фінальністю та вартістю транзакції $0.00025. Але за цією швидкістю стоїть принципово інша модель виконання: accounts model замість contract storage, stateless programs, PDA-дериватів замість mapping. Розробник, який прийшов з EVM, перші два тижні думає, що Solana сломана — тому що звичні паттерни Solidity тут або не працюють, або приводять до уразливостей іншого класу.

Чому Solana-програми ламають EVM-розробника

У EVM контракт зберігає свій стан всередині себе. У Solana програма — це stateless executable, а дані живуть в окремих accounts, які програма не володіє — вона тільки авторизує операції над ними. Це означає, що кожний виклик інструкції вимагає явної передачі всіх accounts, які будуть задіяні.

Перша грабля: missing signer check. Програма отримує account через AccountInfo, але не перевіряє, що переданий authority дійсно підписав транзакцію. У Anchor це ловиться через атрибут #[account(signer)] або тип Signer<'info>. У нативному Rust — через явну перевірку if !authority.is_signer { return Err(...) }. Легко пропустити, коли пишеш перші програми.

Друга класична уразливість — account substitution. Програма приймає token_account та authority, але не перевіряє, що token_account.owner збігається з переданим authority. Атакуючий передає свій token_account та чужого authority — програма виконується без помилок та дренує чужі токени.

Третя біль — PDA derivation mismatch. Program Derived Address обчислюється з seeds + program_id. Якщо seeds не перевірені явно через find_program_address з constraint в Anchor (seeds = [b"vault", user.key().as_ref()]), атакуючий може передати довільний account, який випадково збігається з PDA по адресі, але не є легітимним.

Як Anchor змінює рівняння безпеки

Працюємо переважно через Anchor framework (поточна версія 0.30.x). Anchor генерує discriminator для кожного типу account та перевіряє його при десеріалізації — це автоматично закриває цілий клас type confusion атак, де атакуючий передає account не того типу.

Типова структура інструкції в нашій кодовій базі:

#[derive(Accounts)]
pub struct Deposit<'info> {
    #[account(
        mut,
        seeds = [b"vault", user.key().as_ref()],
        bump,
        constraint = vault.authority == user.key() @ ErrorCode::Unauthorized
    )]
    pub vault: Account<'info, VaultState>,

    #[account(
        mut,
        associated_token::mint = mint,
        associated_token::authority = user
    )]
    pub user_token_account: Account<'info, TokenAccount>,

    pub user: Signer<'info>,
    pub mint: Account<'info, Mint>,
    pub token_program: Program<'info, Token>,
    pub system_program: Program<'info, System>,
}

Constraints у #[account(...)] — це не просто синтаксичний цукор. Вони компілюються у явні перевірки перед виконанням інструкції. Якщо constraint порушено — транзакція откатується до того, як логіка інструкції виконалася.

Тестування: Bankrun vs Localnet

Для більшості unit-тестів використовуємо solana-bankrun — він поднімає синтетичний runtime у пам'яті без запуску validator-а. Тест, який на localnet займав би 3 секунди (400мс на слот), виконується за 50мс. Критично для fuzzing.

Інтеграційні тесты — на localnet через anchor test. Додаємо --skip-local-validator, де тестовий сценарій вимагає реальних програм (Associated Token Program, Metaplex) — клонуємо їх стан з mainnet через --clone.

Для фаззингу SPL-програм використовуємо Trident (fuzzer від Ackee Blockchain). Він генерує випадкові послідовності інструкцій та шукає panics, несподіване стан account, integer overflow. На одному проекті Trident за 4 години знайшла сценарій, де init → close → reinit приводив до повторної ініціалізації з чужими даними — Anchor discriminator при цьому проходив, тому що reinit використав той же тип.

Оптимізація: Compute Units

Solana обмежує кожну транзакцію до 1.4M compute units за замовчуванням (можна запросити до 1.4M через SetComputeUnitLimit). Серіалізація/десеріалізація через Borsh — дороговизна для великих структур.

Практика: розбиваємо великі state структури на кілька accounts. Замість одного ProgramState з 50 полями — кілька спеціалізованих accounts. Менше дані десеріалізуються на кожен виклик — менше CU витрачається.

Другий прийом: zero_copy accounts через #[account(zero_copy)] у Anchor. Дані читаються прямо з пам'яті без Borsh-десеріалізації. На структурах >1KB економія 30-50% CU.

Підхід CU на десеріалізацію 1KB Мутабельність
Стандартний Borsh ~8000 CU Повна
zero_copy (bytemuck) ~500 CU Обмежена (repr(C))

Процес розробки

Аналітика та проектування (2-5 днів). Розбираємо accounts model під завдання: які PDA потрібні, які seeds, де потрібен CPI до Token Program або Associated Token Program. Проектуємо state до написання коду — переробка accounts структури на етапі тестування дорога.

Розробка (3-10 днів залежно від складності). Anchor + Rust stable. Покриваємо кожну інструкцію тестами через Bankrun. Складні сценарії (PDA lifecycle, CPI chains) — на localnet.

Security review. Прогоняємо через Soteria (статичний аналіз Solana-програм) та ручний review за чеклістом: missing signer, ownership checks, PDA validation, integer arithmetic (використовуємо checked_add, checked_mul скрізь).

Деплой. anchor deploy з multisig upgrade authority (Squads Protocol). Upgrade authority не повинна бути EOA — якщо приватник витече, програму можна переписати.

Терміни: 3-5 днів для стандартного SPL-сумісного контракту, до 3 тижнів для складного протоколу з кількома програмами та CPI-ланцюжками.