Популярные ошибки в Solidity
Нашел интересный пост с корявым переводом ошибок, которые могут появиться при проведении транзакций. Это точно не полный список, но теперь это будет постоянная рубрика на канале.
Если вы получили какую-то ошибку у себя в практике и решили ее, то поделитесь этим решением с другими участниками. А пока, вот небольшой список:
1. Error: VM Exception while processing transaction: out of gas
В Solidity нельзя настроить постоянное выполнение транзакций.
Транзакция может выполняться, пока не будет достигнут лимит газа. Как только это произойдет, транзакция выдаст ошибку и вернет "out of gas".
Чаще всего это происходит в циклах функций.
2. Error: VM Exception while processing transaction: invalid opcode
Смарт контракты порой используют assert() для выявления ошибок по выполнению определенных условий в функции. Но иногда они могут противоречить условиям самого контракта. Например,
function set(uint x) public {
assert(x == 0);
myVariable = x;
}
3. Error: VM Exception while processing transaction: revert (описание ошибки)
Обычно это происходит, когда условия модификатора не выполняются, например, модификатор onlyOwner, который может быть вызван только владельцем.
Как и с другими require(), если условие не выполнено, оно вернет "revert exception".
4. CompilerError: Stack too deep, try removing local variables.
Это зависит от сложности выражения внутри функции, где присутствует много (более 16) локальных переменных.
Решение:
-Удалите ненужные переменные;
- Разделите большие функции;
5. SyntaxError: Unexpected token in JSON at position 0
Ошибки с форматом данных json указывает на наличие проблемы при синтаксическом анализе файла .sol для создания файла .json.
Такого рода проблемы могут быть в Truffle.
6. Solidity error: Unexpected token h in JSON at position
Строку параметра необходимо передавать в двойных кавычках.
7. The transaction has been reverted to the initial state. Note: The called function should be payable if you send value and the value you send should be less than your current balance.
Одна из переменных или функций должа быть помечена как payable, чтобы была возможность перевода валюты или токенов.
8. Expected pragma, import directive or contract/interface/library definition...
Проверьте версию pragma в компиляторе и в контракте.
9. ParserError: Source file requires different compiler version (current compiler is 0.6.12+commit.27d51765.Windows.msvc) - note that nightly builds are
considered to be strictly less than the released version pragma solidity ^0.8.0;
И снова следите за версиями в компиляторе и контракте.
10. Cannot estimate gas; transaction may fail or may require manual gas limit.
Возможно, что функция потребует больше газа, чем может себе позволить. В этом случаем можно либо вручную указать количество газа, либо переписать функцию.
Иногда такие ошибки возникают при использовании сторонних сервисов, когда чужой контракт должен вызвать в нашем callback функции, и у нас нет средств оплатить этот вызов.
11. Undeclared identifier.
Вы пытаетесь использовать переменную, которая нигде ранее не появлялась. Проверьте ее на опечатку или регистр.
12. ParseError: Expected '(' but got identifier.
Проверьте закрыты ли все кавычки выше или в самой функции.
13. Warning: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: " to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code.
Скорее всего забыли прописать лицензию в начале кода смарт контракта, типа "SPDX-License-Identifier: MIT".
14. Error: invalid arrayify value
Означает, что в массиве передаете на правильный тип данных.
Читайте ошибки! По опыту могу сказать, что, внимательно прочитав ошибку, можно понять, из-за чего она появилась. Даже если вы не знаете английского языка, то онлайн переводчики отлично смогут помочь вам с этим.
В будущем поиск ошибок на канале можно будет выполнить по хештегу #error
#error
Нашел интересный пост с корявым переводом ошибок, которые могут появиться при проведении транзакций. Это точно не полный список, но теперь это будет постоянная рубрика на канале.
Если вы получили какую-то ошибку у себя в практике и решили ее, то поделитесь этим решением с другими участниками. А пока, вот небольшой список:
1. Error: VM Exception while processing transaction: out of gas
В Solidity нельзя настроить постоянное выполнение транзакций.
Транзакция может выполняться, пока не будет достигнут лимит газа. Как только это произойдет, транзакция выдаст ошибку и вернет "out of gas".
Чаще всего это происходит в циклах функций.
2. Error: VM Exception while processing transaction: invalid opcode
Смарт контракты порой используют assert() для выявления ошибок по выполнению определенных условий в функции. Но иногда они могут противоречить условиям самого контракта. Например,
function set(uint x) public {
assert(x == 0);
myVariable = x;
}
3. Error: VM Exception while processing transaction: revert (описание ошибки)
Обычно это происходит, когда условия модификатора не выполняются, например, модификатор onlyOwner, который может быть вызван только владельцем.
Как и с другими require(), если условие не выполнено, оно вернет "revert exception".
4. CompilerError: Stack too deep, try removing local variables.
Это зависит от сложности выражения внутри функции, где присутствует много (более 16) локальных переменных.
Решение:
-Удалите ненужные переменные;
- Разделите большие функции;
5. SyntaxError: Unexpected token in JSON at position 0
Ошибки с форматом данных json указывает на наличие проблемы при синтаксическом анализе файла .sol для создания файла .json.
Такого рода проблемы могут быть в Truffle.
6. Solidity error: Unexpected token h in JSON at position
Строку параметра необходимо передавать в двойных кавычках.
7. The transaction has been reverted to the initial state. Note: The called function should be payable if you send value and the value you send should be less than your current balance.
Одна из переменных или функций должа быть помечена как payable, чтобы была возможность перевода валюты или токенов.
8. Expected pragma, import directive or contract/interface/library definition...
Проверьте версию pragma в компиляторе и в контракте.
9. ParserError: Source file requires different compiler version (current compiler is 0.6.12+commit.27d51765.Windows.msvc) - note that nightly builds are
considered to be strictly less than the released version pragma solidity ^0.8.0;
И снова следите за версиями в компиляторе и контракте.
10. Cannot estimate gas; transaction may fail or may require manual gas limit.
Возможно, что функция потребует больше газа, чем может себе позволить. В этом случаем можно либо вручную указать количество газа, либо переписать функцию.
Иногда такие ошибки возникают при использовании сторонних сервисов, когда чужой контракт должен вызвать в нашем callback функции, и у нас нет средств оплатить этот вызов.
11. Undeclared identifier.
Вы пытаетесь использовать переменную, которая нигде ранее не появлялась. Проверьте ее на опечатку или регистр.
12. ParseError: Expected '(' but got identifier.
Проверьте закрыты ли все кавычки выше или в самой функции.
13. Warning: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: " to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code.
Скорее всего забыли прописать лицензию в начале кода смарт контракта, типа "SPDX-License-Identifier: MIT".
14. Error: invalid arrayify value
Означает, что в массиве передаете на правильный тип данных.
Читайте ошибки! По опыту могу сказать, что, внимательно прочитав ошибку, можно понять, из-за чего она появилась. Даже если вы не знаете английского языка, то онлайн переводчики отлично смогут помочь вам с этим.
В будущем поиск ошибок на канале можно будет выполнить по хештегу #error
#error
👍1
Заметка по работе с ошибками
Давно хотел написать небольшую заметку о работе с ошибками в программировании. Опять же из своего опыта.
Я состою в нескольких чатах, где пользователи активно делятся своими ошибками, дают и спрашивают совета, постят статьи и т.д.
И очень часто, складывается такое ощущение, что некоторым пользователям просто лень самим разбираться с возникающими ошибками в коде. Они делают скрин и постят в чат. Потом пишут, что не получилось и скрин новой ошибки и так до бесконечности.
Хочу дать вам пару советов, как лучше работать со своими ошибками в коде.
1. Самое первое - это прочитать ошибку. В 90% случаев вам будет понятно, в чем может быть проблема.
2. Погуглите ее. Так и пишите в поисковой строке: "Ошибка ..." и копируйте текст ошибки. Скорее всего в первых же выдачах она будет показана. Stackoverflow - наше все!
3. Если вы пошли в чат или на канал, то сначала также воспользуйтесь поиском. Велика вероятность, что у кого-то уже была такая же ошибка и сообщество помогло ее решить.
4. Если случилось невероятное, и вашей ошибки нет ни в гугле, ни в чатах, то опишите ошибку как можно подробнее! Не стоит делать скрин и спрашивать, что не так. Опишите язык программирования, который используете, покажите код или функцию, на каком этапе возникает и т.д.
Самое главное в работе с ошибками в программировании - это уметь гуглить и правильно составлять вопросы для поиска! Покопавшись несколько минут в документации вы не только сможете разобраться в данной ошибке, но и избежать ее в дальнейшем!
#error
Давно хотел написать небольшую заметку о работе с ошибками в программировании. Опять же из своего опыта.
Я состою в нескольких чатах, где пользователи активно делятся своими ошибками, дают и спрашивают совета, постят статьи и т.д.
И очень часто, складывается такое ощущение, что некоторым пользователям просто лень самим разбираться с возникающими ошибками в коде. Они делают скрин и постят в чат. Потом пишут, что не получилось и скрин новой ошибки и так до бесконечности.
Хочу дать вам пару советов, как лучше работать со своими ошибками в коде.
1. Самое первое - это прочитать ошибку. В 90% случаев вам будет понятно, в чем может быть проблема.
2. Погуглите ее. Так и пишите в поисковой строке: "Ошибка ..." и копируйте текст ошибки. Скорее всего в первых же выдачах она будет показана. Stackoverflow - наше все!
3. Если вы пошли в чат или на канал, то сначала также воспользуйтесь поиском. Велика вероятность, что у кого-то уже была такая же ошибка и сообщество помогло ее решить.
4. Если случилось невероятное, и вашей ошибки нет ни в гугле, ни в чатах, то опишите ошибку как можно подробнее! Не стоит делать скрин и спрашивать, что не так. Опишите язык программирования, который используете, покажите код или функцию, на каком этапе возникает и т.д.
Самое главное в работе с ошибками в программировании - это уметь гуглить и правильно составлять вопросы для поиска! Покопавшись несколько минут в документации вы не только сможете разобраться в данной ошибке, но и избежать ее в дальнейшем!
#error
👍1
Необычный require и работа с ошибками
Иногда я писал про интересные моменты в коде, которые встречаю в процессе аудита. Вот и сейчас хочу поделиться одной очень занимательной реализацией кода.
В протоколе Unitas сформирована не совсем стандартная работа с отслеживанием возникающих ошибок в функциях по типу тех, что мы обычно пишем в require. Напомню, что условия для проверки пишутся так:
require(condition, "Error message...");
Можно создавать свои кастомные ошибки, типа "error Unauthorized();", но тогда нам придется использовать if/else вместо require.
В данном протоколе команда пошла дальше. Они создали отдельную библиотеку, где обозначили все возможные ошибки для своего проекта, и записали из в простые uint, например:
uint256 internal constant ADDRESS_ZERO = 1000;
1000 - это код ошибки, а само ее описание сделано комментарием выше.
Далее они написали свою реализацию функции require:
function _require(bool condition, uint256 errorCode) pure {
if (!condition) {
_revert(errorCode);
}
}
И свою реализацию функции revert. Она достаточно длинная, поэтому ее можно будет посмотреть по ссылке ниже на файл протокола.
Теперь в рабочих контрактах протокола можно использовать свой require для вывода ошибок:
_require(amount <= portfolio, Errors.AMOUNT_INVALID);
На самом деле, очень удобная система, когда все ошибки находятся в одном файле под своим кодом.
Саму реализацию файла можно посмотреть тут.
Надеюсь и вам понравится эта система так же, как и мне.
#error #require
Иногда я писал про интересные моменты в коде, которые встречаю в процессе аудита. Вот и сейчас хочу поделиться одной очень занимательной реализацией кода.
В протоколе Unitas сформирована не совсем стандартная работа с отслеживанием возникающих ошибок в функциях по типу тех, что мы обычно пишем в require. Напомню, что условия для проверки пишутся так:
require(condition, "Error message...");
Можно создавать свои кастомные ошибки, типа "error Unauthorized();", но тогда нам придется использовать if/else вместо require.
В данном протоколе команда пошла дальше. Они создали отдельную библиотеку, где обозначили все возможные ошибки для своего проекта, и записали из в простые uint, например:
uint256 internal constant ADDRESS_ZERO = 1000;
1000 - это код ошибки, а само ее описание сделано комментарием выше.
Далее они написали свою реализацию функции require:
function _require(bool condition, uint256 errorCode) pure {
if (!condition) {
_revert(errorCode);
}
}
И свою реализацию функции revert. Она достаточно длинная, поэтому ее можно будет посмотреть по ссылке ниже на файл протокола.
Теперь в рабочих контрактах протокола можно использовать свой require для вывода ошибок:
_require(amount <= portfolio, Errors.AMOUNT_INVALID);
На самом деле, очень удобная система, когда все ошибки находятся в одном файле под своим кодом.
Саму реализацию файла можно посмотреть тут.
Надеюсь и вам понравится эта система так же, как и мне.
#error #require
👍22
Еще один пример работы с Error
В протоколе Dopex встретил хороший пример работы с ошибками (require / error) в контракте.
Была создана специальная функция для валидации входящих условий:
function _validate(bool _clause, uint256 _errorCode) internal pure {
if (!_clause) revert RdpxV2CoreError(_errorCode);
}
которая проверяет условие в родительской функции, и если не true, то порождает Error с нужным кодом. Сам Error выглядит максимально просто:
error RdpxV2CoreError(uint256);
ну, и в коде, в комментариях, есть список ошибок по номеру, например:
// ERROR CODES
// E1: "Insufficient bond amount",
// E2: "Bond has expired",
// E3: "Invalid parameters"
Как это работает? Например, у нас есть функция, которая должна принимать адрес в качестве аргумента:
function getAddress(address addr) external {...}
и нам нужно проверить, чтобы этот адрес не был нулевым, поэтому мы передаем условие в функцию _validate():
function getAddress(address addr) external {
_valudate(addr != address(0), 4);
}
Идет проверка, если адрес окажется нулевым, по код выдаст ошибку под номером 4, из чего мы узнаем о проваленной проверке.
Вот такое простое решение.
#error
В протоколе Dopex встретил хороший пример работы с ошибками (require / error) в контракте.
Была создана специальная функция для валидации входящих условий:
function _validate(bool _clause, uint256 _errorCode) internal pure {
if (!_clause) revert RdpxV2CoreError(_errorCode);
}
которая проверяет условие в родительской функции, и если не true, то порождает Error с нужным кодом. Сам Error выглядит максимально просто:
error RdpxV2CoreError(uint256);
ну, и в коде, в комментариях, есть список ошибок по номеру, например:
// ERROR CODES
// E1: "Insufficient bond amount",
// E2: "Bond has expired",
// E3: "Invalid parameters"
Как это работает? Например, у нас есть функция, которая должна принимать адрес в качестве аргумента:
function getAddress(address addr) external {...}
и нам нужно проверить, чтобы этот адрес не был нулевым, поэтому мы передаем условие в функцию _validate():
function getAddress(address addr) external {
_valudate(addr != address(0), 4);
}
Идет проверка, если адрес окажется нулевым, по код выдаст ошибку под номером 4, из чего мы узнаем о проваленной проверке.
Вот такое простое решение.
#error
👍5