Основи моделі комісій Solana

Base fee та priority fee: дві складові

Кожна транзакція в Solana складається з двох комісійних компонентів: base fee та priority fee. Base fee — це фіксована плата за кожен підпис у транзакції, яка становить 5 000 lamports. Цей параметр є константою протоколу, визначеною в runtime, і не залежить від стану мережі чи навантаження.

Priority fee — це змінна складова, яку відправник транзакції встановлює добровільно. Вона визначається як ціна за одиницю обчислювальних ресурсів (compute unit) і вимірюється в мікроламелях (micro-lamports). Один мікроламель дорівнює 0,000001 lamports.

Формула загальної комісії транзакції:

Total fee = (base_fee × num_signatures) + (compute_unit_price × compute_unit_limit) / 1 000 000

де:

  • base_fee — 5 000 lamports (константа протоколу);
  • num_signatures — кількість підписів у транзакції;
  • compute_unit_price — priority fee в мікроламелях за один compute unit;
  • compute_unit_limit — заявлений ліміт обчислювальних одиниць для транзакції.

Приклад: транзакція з одним підписом, що запитує 200 000 compute units із compute_unit_price, рівним 500 000 micro-lamports:

  • Base fee: 5 000 × 1 = 5 000 lamports
  • Priority fee: (500 000 × 200 000) / 1 000 000 = 100 000 lamports
  • Загальна комісія: 105 000 lamports

Як комісії спалюються (fee burner)

У протоколі Solana реалізовано механізм fee burner, що передбачає часткове спалювання комісій транзакцій — безповоротне вилучення цих коштів з обігу. Історично 100% комісій надходили лідеру слота як пряма винагорода за обробку.

Точне поточне співвідношення між спаленою частиною та частиною, що надходить лідеру, варто перевірити за актуальною специфікацією протоколу, оскільки цей параметр регулюється через governance-процес (зокрема пропозиція SIMD-0096). Для валідаторів це означає, що дохід від комісій не дорівнює сумі всіх сплачених користувачами fee, а для аналітиків — що частина комісій створює дефляційний тиск на пропозицію SOL.

Механізм priority fees

Як встановлюється мікроламель (compute unit price)

Compute unit price — це параметр, який відправник вказує в інструкції ComputeBudgetInstruction::SetComputeUnitPrice. Значення встановлюється в мікроламелях за один compute unit і визначає пріоритет транзакції в черзі лідера.

Крім ціни, транзакція повинна вказати ліміт обчислювальних одиниць через ComputeBudgetInstruction::SetComputeUnitLimit. Якщо цей ліміт не вказано явно, RPC-вузол за замовчуванням призначає 200 000 compute units. Максимальний ліміт на одну транзакцію становить 1 400 000 compute units — це жорстке обмеження протоколу.

Критичний нюанс: compute_unit_price — це ціна за запитаний ліміт, а не за фактично спожиті ресурси. Навіть якщо транзакція використала лише 10 000 compute units із заявлених 200 000, комісія розраховується за повні 200 000. Це ключова відмінність від моделі pay-per-use і джерело типових помилок при формуванні транзакцій.

Аукціон за місце в блоку: як лідер обирає транзакції

Лідер слота підтримує чергу транзакцій і формує блоки з урахуванням обмежень обчислювального бюджету. Механізм вибору транзакцій працює як неявний аукціон.

Порядок обробки лідером:

  1. Лідер приймає всі валідні транзакції, що надійшли через gossip-мережу або прямі RPC-запити.
  2. Транзакції сортуються за compute_unit_price у порядку спадання.
  3. Лідер послідовно додає транзакції в блок, відстежуючи сумарний обчислювальний бюджет.
  4. Коли бюджет блоку вичерпано, решта транзакцій не включається до поточного слота.

Фундаментальна властивість цієї моделі: якщо в блоці є вільний обчислювальний бюджет, транзакції з нульовим priority fee також включаються. Аукціон виникає лише за умови конкуренції за обмежений ресурс. У періоди низької активності можна встановити compute_unit_price на нуль, і транзакція буде оброблена без додаткових витрат.

Лідер не максимізує власний дохід від комісій у межах одного слота — алгоритм сортує за compute_unit_price, а не за абсолютною сумою комісії. Транзакція з високим compute_unit_price, але малим compute_unit_limit матиме вищий пріоритет, ніж транзакція з нижчою ціною, але більшим лімітом, навіть якщо абсолютна сума priority fee в другому випадку вища.

Практичні аспекти

Як розрахувати оптимальну комісію

Оптимальна комісія — це мінімальне значення compute_unit_price, за якого транзакція потрапляє в блок протягом прийнятного часу. Практичний алгоритм:

  1. Збір даних. Отримайте інформацію про останні оброблені блоки через RPC-метод getBlock із параметром, що включає транзакції та їхні метадати. Альтернативно використовуйте getFeeForMessage для оцінки, але цей метод не дає даних про розподіл комісій у блоці.
  2. Екстракція compute_unit_price. З кожної транзакції витягніть значення compute_unit_price з метаданих. У відповіді getBlock ця інформація доступна через парсинг інструкцій ComputeBudget у кожній транзакції.
  3. Аналіз розподілу. Побудуйте розподіл значень compute_unit_price за останні N блоків (наприклад, 10–20 блоків). Визначте медіану та вибрані перцентилі (50-й, 75-й, 90-й).
  4. Встановлення ціни. Для стандартних транзакцій достатньо встановити compute_unit_price на рівні медіани або 75-го перцентиля. Для часово-чутливих транзакцій (арбітраж, ліквідації) орієнтуйтеся на 90-й перцентиль або вище.

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

Типові помилки при встановленні комісій

Занижений compute_unit_limit. Якщо вказати ліміт, менший за фактично необхідний для виконання транзакції, вона завершиться помилкою Computational budget exceeded незалежно від рівня priority fee. Комісія в цьому випадку все одно сплачується. Рішення: профілюйте транзакцію в локальному середовищі (наприклад, через simulateTransaction RPC-метод) і встановлюйте ліміт із запасом 10–20%.

Завищений compute_unit_limit. Оскільки комісія розраховується за запитаний ліміт, завищення призводить до прямої переплати. Якщо транзакція потребує 50 000 CU, а ви вказали 400 000 CU, priority fee буде в 8 разів вищим за необхідний мінімум. Рішення: використовуйте simulateTransaction для визначення фактичного споживання і встановлюйте ліміт точково.

Ігнорування кількості підписів. Base fee множиться на кількість підписів. Транзакції з кількома підписами (multisig-операції, складні CPI-ланцюжки з крос-програмними викликами) мають значно вищу базову складову. При мінімальних priority fees саме base fee може становити основну частину комісії.

Нульовий priority fee під час завантаження мережі. У періоди високої активності транзакції з нульовим пріоритетом можуть не потрапляти в блоки тривалий час. Якщо транзакція має обмежений TTL (time-to-live), вона буде відкинута до підтвердження. Рішення: завжди перевіряйте поточний рівень медіанного compute_unit_price перед відправкою.

Конфлікт інструкцій ComputeBudget. Транзакція не може містити дві інструкції SetComputeUnitLimit або дві SetComputeUnitPrice. Це призводить до миттєвого відхилення транзакції на етапі валідації.

Вплив завантаження мережі на рівень комісій

Рівень priority fees прямо корелює з утилізацією обчислювального бюджету блоків. Коли утилізація низька — значна частина бюджету блоку залишається незайнятою — навіть мінімальні або нульові priority fees достатні для включення транзакції.

Коли утилізація наближається до 100%, формується конкурентне середовище з такими характеристиками:

  • Нелінійне зростання медіани. Останні доступні одиниці бюджету блоку коштують значно дорожче за перші. Крива пропозиції обчислювального простору в межах одного слота є лінійною (фіксований бюджет), але крива попиту зазвичай має ступінчастий характер, що створює різкі стрибки на межі заповнення.
  • Підвищена волатильність. Невеликі зміни в патерні відправки транзакцій спричиняють значні коливання compute_unit_price між сусідніми слотами.
  • Асиметрія впливу розміру транзакції. Транзакції з великим compute_unit_limit швидше вичерпують залишок бюджету блоку, що посилює конкуренцію для всіх наступних транзакцій у цьому слоті.

Типові сценарії підвищеного навантаження: масові mint NFT-колекцій, сплески активності в DeFi-протоколах під час волатильності ринку, запуски нових токенів та airdrop-події. У такі моменти адаптивне встановлення комісій із моніторингом останніх блоків стає не оптимізацією, а необхідною умовою надійності відправки транзакцій.

Для валідаторів та інфраструктурних провайдерів важливо розуміти, що priority fees не є стабільним джерелом доходу — вони характеризуються високою дисперсією як у міжслотовому розрізі, так і в довгостроковій перспективі. Аналіз доходів від комісій має враховувати цю волатильність і проводитися на достатньо довгих часових інтервалах.

Джерела