Защита от MEV с помощью Jito DontFront

Защита от MEV с помощью Jito DontFront

Максимально извлекаемая ценность (MEV) — это ценность, которую можно получить путём переупорядочивания, включения или исключения транзакций внутри блока. MEV не является уникальным явлением для какой-либо отдельной сети; это фундаментальное свойство любого блокчейна, в котором производители блоков контролируют порядок транзакций. Некоторые формы MEV, например арбитраж, способствуют эффективности рынков, устраняя ценовые расхождения между DEX. Другие, как сэндвич-атаки, извлекают ценность непосредственно из средств пользователей. Для разработчиков, создающих DeFi-приложения, это может означать ухудшение исполнения сделок и потерю прибыли.

Это руководство посвящено сэндвич-атакам — распространённой форме вредоносного MEV — и способам их предотвращения с помощью функции dontfront от Jito.

Рекомендуется предварительно ознакомиться с: Jito Bundles

MEV в Solana

Архитектура Solana уже сама по себе сокращает поверхность атаки MEV по сравнению с сетями с открытыми мемпулами. Транзакции напрямую передаются предстоящему лидеру блока, а не ожидают в общем мемпуле, и необработанные транзакции истекают примерно через 150 блоков (~1 минута). Это существенно сужает окно возможностей для исследователей, наблюдающих за ожидающими транзакциями и реагирующих на них.

Тем не менее извлечение MEV всё равно происходит. Исследователи с оптимизированной инфраструктурой и прямыми подключениями к validator'ам могут отслеживать поток транзакций и реагировать на него. Большая часть MEV-активности в Solana — это атомарный арбитраж: боты, устраняющие ценовые расхождения между DEX в рамках одной транзакции. Такой тип MEV в целом считается полезным, поскольку улучшает согласованность цен на рынках.

Вредоносная разновидность — сэндвич-атаки — это то, от чего разработчикам следует активно защищаться.

Что такое сэндвич-атака?

Сэндвич-атака происходит, когда исследователь обнаруживает ожидающий своп и использует управление порядком транзакций:

  1. Фронтраннинг: исследователь покупает токен до вашей сделки, поднимая цену вверх
  2. Ваша сделка исполняется по цене хуже ожидаемой
  3. Бэкраннинг: исследователь продаёт токен после вашей сделки, получая разницу в свою пользу

В Solana это может происходить через Jito bundles. Исследователь отправляет бандл транзакций вида: [frontrun_tx, your_tx, backrun_tx], и блок-движок выполняет их атомарно по порядку. Жертва получает худшую цену исполнения, тогда как исследователь извлекает прибыль из спреда.

Как работает DontFront

DontFront — это функция блок-движка Jito, которая предотвращает размещение исследователями своих транзакций перед вашей в бандле.

Механизм: добавьте любой валидный публичный ключ Solana, начинающийся с jitodontfront, в любую инструкцию вашей транзакции. Блок-движок распознаёт этот префикс и применяет правило: любой бандл, содержащий вашу транзакцию, обязан размещать её под индексом 0.

Without dontfront: [frontrun_tx, your_tx, backrun_tx] ← sandwich possible
With dontfront: [your_tx, ...] ← your tx must be first

Пошаговая инструкция

  1. Выберите валидный адрес, начинающийся с jitodontfront (например, jitodontfront111111111111111111111111111111). Аккаунт не обязан существовать в сети; он никогда не читается и не записывается. Вы можете проверить, является ли строка валидным адресом, с помощью функции assertIsAddress из @solana/kit, или ввести адрес в Solana Explorer, чтобы убедиться в его корректности. Вот пример невалидного адреса.

  2. Добавьте его как аккаунт только для чтения без права подписи в любую инструкцию вашей транзакции. Пометьте его как только для чтения для оптимальной скорости попадания в блок. Большинство программ (включая System Program) игнорируют дополнительные аккаунты сверх ожидаемых.

  3. Отправьте через блок-движок Jito:

    • sendTransaction: https://mainnet.block-engine.jito.wtf/api/v1/transactions
    • sendBundle: https://mainnet.block-engine.jito.wtf/api/v1/bundles

    Документация: sendTransaction и sendBundle

  4. Блок-движок обнаруживает префикс jitodontfront и применяет правила упорядочивания.

Что происходит на уровне блок-движка

Когда блок-движок видит транзакцию, содержащую аккаунт jitodontfront:

  • Через sendTransaction: транзакция защищена. Ни один бандл не может разместить другую транзакцию перед ней
  • Через sendBundle: транзакция должна находиться под индексом 0, иначе весь бандл отклоняется

Транзакции и бандлы, не содержащие аккаунт jitodontfront, не затрагиваются.

Правила упорядочивания бандлов

Эти правила применяются, когда транзакция с jitodontfront находится в бандле.

Допустимые паттерны

[tx_with_dontfront, tip]
[tx_with_dontfront, arbitrage, tip]
[tx_with_dontfront_signer1, tx_with_dontfront_signer1_and_signer2, tip]

Несколько транзакций DontFront в одном бандле

Несколько dontfront-транзакций в одном бандле допускаются при выполнении обоих условий:

  1. Все dontfront-транзакции идут подряд в начале бандла
  2. Каждая dontfront-транзакция имеет хотя бы одного общего подписанта с первой dontfront-транзакцией
✅ [txA_df, txB_df, txC_df, arbitrage, tip]
(contiguous at front, overlapping signers)
✅ [txA_df_signer1_signer2, txB_df_signer1_signer3, txC_df_signer2_signer4]
(each shares a signer with txA)

Недопустимые паттерны

❌ [tip, tx_with_dontfront]
→ dontfront tx is not at index 0
❌ [txA_df_signer1, txB_df_signer2]
→ no overlapping signer between txA and txB
❌ [trade, tx_with_dontfront, arbitrage, tip]
→ dontfront tx is not at the front

Примеры интеграции

Для быстрого примера кода см. запись в кулинарной книге по защите от MEV.

TypeScript (@solana/kit)

Основная идея — вспомогательная функция, добавляющая dontfront-аккаунт к любой инструкции:

import {
address,
AccountRole,
type Instruction,
type Address
} from "@solana/kit";
const DONT_FRONT: Address = address(
"jitodontfront111111111111111111111111111111"
);
function withDontFront(ix: Instruction): Instruction {
return {
...ix,
accounts: [
...(ix.accounts ?? []),
{ address: DONT_FRONT, role: AccountRole.READONLY }
]
};
}

Затем отправьте подписанную транзакцию в блок-движок Jito вместо стандартного RPC-узла. Всегда используйте кодировку base64. Base58 устарел в API Jito.

const response = await fetch(
"https://mainnet.block-engine.jito.wtf/api/v1/transactions",
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
jsonrpc: "2.0",
id: 1,
method: "sendTransaction",
params: [base64Tx, { encoding: "base64" }]
})
}
);

Лучшие практики

DontFront — это один уровень защиты. Надёжная стратегия снижения MEV-рисков сочетает в себе несколько подходов:

Защита на уровне транзакций

  • Устанавливайте жёсткие допуски проскальзывания. Самая эффективная защита от сэндвич-атак — ограничение допустимого проскальзывания при свопах. Меньшее окно проскальзывания снижает потенциальную прибыль атакующих, делая вашу транзакцию менее привлекательной для сэндвичинга.

  • Устанавливайте подходящие чаевые и приоритетные комиссии. В периоды перегрузки более высокие чаевые и приоритетные комиссии повышают вероятность быстрого попадания вашей транзакции/бандла в блок, сокращая окно возможностей для исследователей. Подробнее о правильной настройке чаевых см. в документации Jito по Tip Amounts.

  • Оптимизируйте использование вычислительных единиц. Каждый блок имеет ограниченное количество доступных вычислительных единиц (и аккаунты также имеют ограниченное количество вычислительных единиц, доступных на блок). Чтобы максимизировать вероятность включения вашей транзакции/бандла в блок, следует оптимизировать использование вычислительных единиц. Подробности см. в руководстве How to Optimize Compute Usage on Solana.

Специфические рекомендации для DontFront

  1. Помечайте dontfront-аккаунт как только для чтения. Запись тоже работает, но режим только для чтения оптимизирует скорость попадания в блок.

  2. Используйте уникальный dontfront pubkey для каждого приложения. Подойдёт любой pubkey, начинающийся с jitodontfront. Использование уникального варианта (например, jitodontfront111111111111111111111111111123) позволяет различать использование по приложениям при анализе данных в сети.

  3. DontFront поддерживает Address Lookup Tables. Dontfront-аккаунт может быть включён через ALT. Однако не используйте ALT для аккаунтов чаевых.

Ограничения

  • Только блок-движок. DontFront применяется блок-движком Jito. Транзакции, отправленные напрямую к validator'ам (в обход Jito), не защищены.

  • Не гарантия. Из документации Jito: «Эта функция может помочь снизить количество сэндвич-атак, но не гарантирует этого и не является решением для всех вариантов упорядочивания транзакций, включая любое упорядочивание, осуществляемое третьими сторонами.»

  • Только Mainnet/Testnet. Это функция блок-движка Jito. Она не работает в devnet или на localhost.

Ссылки

Is this page helpful?