И вот последняя функция, на которую стоит обратить внимание.
Как я понял из урока, ее не было в ранних версиях Solidity, и появилась не так уж и давно.
Unchecked() позволяет отлавливать ошибки переполнения, и, если функция дошла до максимального или минимального значения, то она не вернет ошибку, а начнет сначала диапазона.
#unchecked #function
Как я понял из урока, ее не было в ранних версиях Solidity, и появилась не так уж и давно.
Unchecked() позволяет отлавливать ошибки переполнения, и, если функция дошла до максимального или минимального значения, то она не вернет ошибку, а начнет сначала диапазона.
#unchecked #function
👍1🔥1
Пара слов, которые нужно запомнить о типе данных string
1. Чем длиннее строка, тем больше это будет стоить! Не следует хранить в переменных большие предложения или тексты. В итоговом разворачивании контракта это может выйти буквально в несколько сот долларов!
2. Мы не можем померит длину строки, так как они хранятся в байтовых массивах.
3. Строки нельзя склеивать, сравнивать, или обращаться к буквам по индексу.
4. В функциях создаются только временные переменные string. При этом в рамках функций можно переопределять основные значения string, которые хранятся в блокчейне.
#string #function
1. Чем длиннее строка, тем больше это будет стоить! Не следует хранить в переменных большие предложения или тексты. В итоговом разворачивании контракта это может выйти буквально в несколько сот долларов!
2. Мы не можем померит длину строки, так как они хранятся в байтовых массивах.
3. Строки нельзя склеивать, сравнивать, или обращаться к буквам по индексу.
4. В функциях создаются только временные переменные string. При этом в рамках функций можно переопределять основные значения string, которые хранятся в блокчейне.
#string #function
👍1🔥1
В Solidity, на данный момент, есть четыре области видимости функций: Public, Private, External и Internal.
Основное, что нужно запомнить о них это:
Public - наиболее часто встречаемая в уроках область, которая позволяет вызывать функцию как извне контракта, так и внутри него.
Private - вызывает функции ТОЛЬКО внутри самого контракта.
External - вызывает функции ТОЛЬКО извне контракта, и не доступны для вызова внутри.
Internal - наоборот, вызывает функции ТОЛЬКО внутри самого контракта, и не доступны для вызова извне.
#областивидимости #функции #function
Основное, что нужно запомнить о них это:
Public - наиболее часто встречаемая в уроках область, которая позволяет вызывать функцию как извне контракта, так и внутри него.
Private - вызывает функции ТОЛЬКО внутри самого контракта.
External - вызывает функции ТОЛЬКО извне контракта, и не доступны для вызова внутри.
Internal - наоборот, вызывает функции ТОЛЬКО внутри самого контракта, и не доступны для вызова извне.
#областивидимости #функции #function
🔥1
Функция "fallback()" вызывается в том случае, если относительно смарт-контракта бала вызвана транзакция с неизвеным именем функции.
Это нужно для того чтобы, например, в случае, если на смарт-контракт придет транзакция с вызовом функции, которой нет, она не откатится, а покажет ошибку, которая была описана в "fallback".
Проще говоря, если к нам придет транзакция, которая запросит функцию возврата денег, а она не прописана у нас, то в "fallback" можно отловить этот момент и показать ошибку.
#fallback #функции #function
Это нужно для того чтобы, например, в случае, если на смарт-контракт придет транзакция с вызовом функции, которой нет, она не откатится, а покажет ошибку, которая была описана в "fallback".
Проще говоря, если к нам придет транзакция, которая запросит функцию возврата денег, а она не прописана у нас, то в "fallback" можно отловить этот момент и показать ошибку.
#fallback #функции #function
🔥1
Solidity полон сюрпризов
А знали ли вы, что mapping могут держать функции в качестве значения? Или, что функции могут принимать функции в качестве параметров?
Лично для меня это было в диковинку. Наткнулся на эту картинку, опять же, в Твиттере и сначала подумал, что это какой-то прикол. Более того, по указанной ссылке, да и в поиске я не смогу найти информации об этом.
Переписав код со скрина в Ремикс, он скомпилировался без проблем. Да и потом исполнился на раз!
Удивительно! Ни разу: ни в аудитах, ни в задачах, ни где, я не встречал таких примеров.
В комментариях оставляю код, чтобы вы могли скопипастить его в Ремикс и поиграться самим.
#mapping #function
А знали ли вы, что mapping могут держать функции в качестве значения? Или, что функции могут принимать функции в качестве параметров?
Лично для меня это было в диковинку. Наткнулся на эту картинку, опять же, в Твиттере и сначала подумал, что это какой-то прикол. Более того, по указанной ссылке, да и в поиске я не смогу найти информации об этом.
Переписав код со скрина в Ремикс, он скомпилировался без проблем. Да и потом исполнился на раз!
Удивительно! Ни разу: ни в аудитах, ни в задачах, ни где, я не встречал таких примеров.
В комментариях оставляю код, чтобы вы могли скопипастить его в Ремикс и поиграться самим.
#mapping #function
👍3
Необычная функция
Просто хочу поделиться необычной логикой работы функции, которую я вчера встретил в аудите. За все время обучения лично я столкнулся с этим впервые, что вызвало некоторые недоумения.
Я постараюсь разложить ее "по полочкам". Итак, вот сам контракт, если вдруг кому будет интересно.
И там есть такая функция (я ее обрезал, убрав не интересные части):
function stake (
AssetType _assetType,
uint256 _timelockId,
uint256,
uint256,
uint256
) external nonReentrant {
uint256 timelockOption = timelockOptions[_assetType][_timelockId];
function (uint256) _s1 = _stakeS1Citizen;
function (uint256) _s2 = _stakeS2Citizen;
function (uint256) _b = _stakeBytes;
function (uint256) _lp = _stakeLP;
function (uint256) _stake;
assembly {
switch _assetType
case 0 {
_stake := _s1
}
case 1 {
_stake := _s2
}
case 2 {
_stake := _b
}
case 3 {
_stake := _lp
}
default {}
}
_stake(timelockOption);
}
Возможно, для опытным разработчиков она окажется простой, но для других - интересным опытом.
Обратите внимание, что в параметрах функции 5 аргументов, 3 из которых обозначены просто как тип uint256 без переменных.
Далее, я не совсем разобрался, как называется это действие, но мы создаем некие поинтеры на другие функции в контракте и кладем их в переменные _s1, _s2, _b, _lp.
_stakeS1Citizen, _stakeS2Citizen, _stakeBytes, _stakeLP - да, это все функции в данном контракте, например:
function _stakeS1Citizen (uint256 _timelock) private {}
Также нужно учесть, что в данном примере, один из аргументов в функции, assetType - это enum. Вот как он выглядит:
enum AssetType {S1_CITIZEN, S2_CITIZEN, BYTES, LP}
Т.е. вы поняли, что происходит в функции?
Мы создали поинтеры на другие функции в контракте, а затем через assembler прогнались по enum и переопределили в поинтер _stake необходимую для нас опцию!
Другими словами, исполнение данной функции продолжится уже в другой функции, учитывая значения AssetType!
Дальше еще круче!
Помните те 3 безыменных аргумента uint256 в функции?
Они передаются в последующие функции, как calldata! Например, одна из функция такая:
function _stakeBytes (uint256) ) private {
uint256 amount;
uint256 citizenId;
uint256 seasonId;
assembly{
amount := calldataload(0x44)
citizenId := calldataload(0x64)
seasonId := calldataload(0x84)
}
}
Эта calldata из безымянных uint256 передается в другие функции и расшифровывается в assembly. И что самое интересное, во всех 4 функциях _stakeS1Citizen, _stakeS2Citizen, _stakeBytes, _stakeLP - расшифровываются разные calldata в зависимости от полученных в главное функции stake!
В общем, меня впечатлил данный контракт! Надеюсь и вам он понравится.
#function
Просто хочу поделиться необычной логикой работы функции, которую я вчера встретил в аудите. За все время обучения лично я столкнулся с этим впервые, что вызвало некоторые недоумения.
Я постараюсь разложить ее "по полочкам". Итак, вот сам контракт, если вдруг кому будет интересно.
И там есть такая функция (я ее обрезал, убрав не интересные части):
function stake (
AssetType _assetType,
uint256 _timelockId,
uint256,
uint256,
uint256
) external nonReentrant {
uint256 timelockOption = timelockOptions[_assetType][_timelockId];
function (uint256) _s1 = _stakeS1Citizen;
function (uint256) _s2 = _stakeS2Citizen;
function (uint256) _b = _stakeBytes;
function (uint256) _lp = _stakeLP;
function (uint256) _stake;
assembly {
switch _assetType
case 0 {
_stake := _s1
}
case 1 {
_stake := _s2
}
case 2 {
_stake := _b
}
case 3 {
_stake := _lp
}
default {}
}
_stake(timelockOption);
}
Возможно, для опытным разработчиков она окажется простой, но для других - интересным опытом.
Обратите внимание, что в параметрах функции 5 аргументов, 3 из которых обозначены просто как тип uint256 без переменных.
Далее, я не совсем разобрался, как называется это действие, но мы создаем некие поинтеры на другие функции в контракте и кладем их в переменные _s1, _s2, _b, _lp.
_stakeS1Citizen, _stakeS2Citizen, _stakeBytes, _stakeLP - да, это все функции в данном контракте, например:
function _stakeS1Citizen (uint256 _timelock) private {}
Также нужно учесть, что в данном примере, один из аргументов в функции, assetType - это enum. Вот как он выглядит:
enum AssetType {S1_CITIZEN, S2_CITIZEN, BYTES, LP}
Т.е. вы поняли, что происходит в функции?
Мы создали поинтеры на другие функции в контракте, а затем через assembler прогнались по enum и переопределили в поинтер _stake необходимую для нас опцию!
Другими словами, исполнение данной функции продолжится уже в другой функции, учитывая значения AssetType!
Дальше еще круче!
Помните те 3 безыменных аргумента uint256 в функции?
Они передаются в последующие функции, как calldata! Например, одна из функция такая:
function _stakeBytes (uint256) ) private {
uint256 amount;
uint256 citizenId;
uint256 seasonId;
assembly{
amount := calldataload(0x44)
citizenId := calldataload(0x64)
seasonId := calldataload(0x84)
}
}
Эта calldata из безымянных uint256 передается в другие функции и расшифровывается в assembly. И что самое интересное, во всех 4 функциях _stakeS1Citizen, _stakeS2Citizen, _stakeBytes, _stakeLP - расшифровываются разные calldata в зависимости от полученных в главное функции stake!
В общем, меня впечатлил данный контракт! Надеюсь и вам он понравится.
#function
👍7🤯1
Function pointer как аргумент
Для начала посмотрите на код ниже:
В предыдущем примере у нас есть три функции. f1 - самая простая и возвращает то, что получает в аргументах.
f2 функция с function pointer a ожидает в качестве аргумента функцию со специальной сигнатурой.
В f3 мы вызываем функцию f2 и передаем функцию f1, как параметр. И в данном примере она просто вернет число 27.
Достаточно необычный и редкий формат функций в смарт контрактах. Даже в конкурсных аудитах за все время я встречал их один или два раза.
#function #pointer
Для начала посмотрите на код ниже:
contract FunctionPointer {
function f1(uint256 x) internal pure returns(uint256) {
return x;
}
function f2(function(uint256) internal pure returns(uint256) a) internal pure returns(uint256) {
return a(27);
}
function f3() public pure returns(uint256) {
return f2(f1);
}
}
В Solidity вы можете создавать функции, которые будут принимать другие функции в качестве аргументов. Они называются function pointer.В предыдущем примере у нас есть три функции. f1 - самая простая и возвращает то, что получает в аргументах.
f2 функция с function pointer a ожидает в качестве аргумента функцию со специальной сигнатурой.
В f3 мы вызываем функцию f2 и передаем функцию f1, как параметр. И в данном примере она просто вернет число 27.
Достаточно необычный и редкий формат функций в смарт контрактах. Даже в конкурсных аудитах за все время я встречал их один или два раза.
#function #pointer
👍3🔥2