Solidity. Смарт контракты и аудит
2.62K subscribers
246 photos
7 videos
18 files
547 links
Обучение Solidity. Уроки, аудит, разбор кода и популярных сервисов
Download Telegram
И вот последняя функция, на которую стоит обратить внимание.

Как я понял из урока, ее не было в ранних версиях Solidity, и появилась не так уж и давно.

Unchecked() позволяет отлавливать ошибки переполнения, и, если функция дошла до максимального или минимального значения, то она не вернет ошибку, а начнет сначала диапазона.

#unchecked #function
👍1🔥1
Пара слов, которые нужно запомнить о типе данных string

1. Чем длиннее строка, тем больше это будет стоить! Не следует хранить в переменных большие предложения или тексты. В итоговом разворачивании контракта это может выйти буквально в несколько сот долларов!

2. Мы не можем померит длину строки, так как они хранятся в байтовых массивах.

3. Строки нельзя склеивать, сравнивать, или обращаться к буквам по индексу.

4. В функциях создаются только временные переменные string. При этом в рамках функций можно переопределять основные значения string, которые хранятся в блокчейне.

#string #function
👍1🔥1
В Solidity, на данный момент, есть четыре области видимости функций: Public, Private, External и Internal.

Основное, что нужно запомнить о них это:

Public - наиболее часто встречаемая в уроках область, которая позволяет вызывать функцию как извне контракта, так и внутри него.

Private - вызывает функции ТОЛЬКО внутри самого контракта.

External - вызывает функции ТОЛЬКО извне контракта, и не доступны для вызова внутри.

Internal - наоборот, вызывает функции ТОЛЬКО внутри самого контракта, и не доступны для вызова извне.

#областивидимости #функции #function
🔥1
В данном уроке приводятся два модификатора практически одинаковых: view и pure. Так чем же они различаются?

А тем, что view - может читать внешние переменные и модифицировать их, а pure - работает только с переменными внутри самой функции.

#функции #function #pure #view
🔥1
Обратите внимание, что в заголовке функции мы пишем "returns" с буквой "S" на конце, а в теле функции просто "return". У меня, с непривычки, были пара проблем из-за этого.

#функции #function
🔥1
Модификатор "payable" служит для обозначения, что данная функция может принимать или отправлять денежные средства.

#payable #функции #function
🔥1
Функция "receive()" появилась в одной из последних версий языка, как я понял из видео, и служит, чтобы просто принимать деньги без вызова каких-либо функци.

Обратите внимание, что слово "function" тут писать не надо.

#payable #функции #function
🔥1
Функция "fallback()" вызывается в том случае, если относительно смарт-контракта бала вызвана транзакция с неизвеным именем функции.

Это нужно для того чтобы, например, в случае, если на смарт-контракт придет транзакция с вызовом функции, которой нет, она не откатится, а покажет ошибку, которая была описана в "fallback".

Проще говоря, если к нам придет транзакция, которая запросит функцию возврата денег, а она не прописана у нас, то в "fallback" можно отловить этот момент и показать ошибку.

#fallback #функции #function
🔥1
Solidity полон сюрпризов

А знали ли вы, что 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
👍7🤯1
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