TGViewer
Noobing Security Research Noobing Security Research @web3securityresearch · 278 subscribers
Post #55 156
Formal Verification, часть 4

Правило для проверки transfer в ERC-20

Сегодня разбираем как написать правило на примере стандартной реализации ERC-20

Проверяемое правило:
Баланс бенефициара увеличивается соответствующим образом

Правило простое, в общих чертах похожее на то, что стоило бы написать в обычном тесте

/** @title Transfer must move `amount` tokens from the caller's
* account to `recipient`
*/
rule transferSpec(address recipient, uint amount) {

env e;

// `mathint` is a type that represents an integer of any size
mathint balance_sender_before = balanceOf(e.msg.sender);
mathint balance_recip_before = balanceOf(recipient);

transfer(e, recipient, amount);

mathint balance_sender_after = balanceOf(e.msg.sender);
mathint balance_recip_after = balanceOf(recipient);

// Operations on mathints can never overflow nor underflow
assert balance_sender_after == balance_sender_before - amount,
"transfer must decrease sender's balance by amount";

assert balance_recip_after == balance_recip_before + amount,
"transfer must increase recipient's balance by amount";
}


Необычных вещей здесь несколько:
1) env e. Главное отличие ФВ от тестов в том, что она учитывает все возможные входные данные и все возможные контексты вызова. Как раз контекст передается через переменную env. Достаточно объявить одну, но можно использовать больше. Соответственно, она содержит/предоставляет такую информацию как: e.msg.sender, e.block.number и так далее. Передавать e следует первой из аргументов
2) mathint. Это собственный тип CVL для целых чисел произвольного размера. Позволяет не беспокоиться о переполнении и знаке
3) в CVL можно использовать только assert, а вот assertEq не поддерживается

Выполнение проверки этого правила завершится с ошибкой, отчет об этом на прикрепленном изображении
...
Finished verification request
ERROR: Prover found violations:

[rule] transferSpec: FAIL
report url: https://prover.certora.com/output/...

Violations were found


Ошибка возникает в случае, когда пользователь отправляет токены сам себе, так что assert'ы неверны

На экране отчета мы видим 4 столбца:
- слева мы видим проверяемые правила
- второй столбец содержит проверяемый код
- в третьем call trace вызова, в котором обнаружено нарушение
- в четвертом значения переменных и параметров

Для того, чтобы обрабатывать этот случай следует добавить следующий assert
    assert recipient == sender => balance_sender_after == balance_sender_before,
"transfer must not change sender's balancer when transferring to self";

То есть отдельно обработать случай, когда отправитель и получатель - один и тот же адрес. После этого правило должно выполняться во всех случаях

Ссылки:
- Туториал, взятый за основу
- Исследуемая реализация ERC-20, код
- Исходная спецификация
- Исправленная спецификация

https://t.me/web3securityresearch
  • ❤ 2
More from @web3securityresearch
  1. Sep 22, 2026Прочитал лекцию про атаки на память, оставлю слайды и здесь
  2. Sep 10, 2026Post #100
  3. Aug 27, 2026я бы рад писать короче, но тема очень широкая. Сегодня статья про HMAC-подписи записей аге…
  4. Aug 27, 2026Post #98
  5. Aug 18, 2026Post #97
  6. Aug 12, 2026Исследователи нашли первый подробно задокументированный, почти автономный, взлом государст…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →