Знаете то чувство в процессе своего обучения, когда ты вроде бы понял тему и можешь ее рассказать, но спустя какое-то время возвращаешься к ней и пытаешься разобраться вновь?
У меня так происходит с некоторыми задачами (Ethernaut, DVD и другими). Вот я решил задачу, написал контракт, понял, как это делается, но вот что-то непонятное так и "не зацепилось". Сейчас я хочу с вами еще раз пройти одну тему и после разобрать задачу на видео. Может после этого, все сложится как надо.
Итак, у нас есть простая функция:
function flipSwitch(bytes memory _data) public onlyOff {
(bool success, ) = address(this).call(_data);
require(success, "call failed :(");
}Вы знаете, как будут располагаться данные в аргументах функции? Если да - то вообще здорово, если нет - давайте разбираться.
В Solidity существуют статичные типы данных:
uint, int, address, bool, bytes - n, tuple
Они представлены в шестнадцатеричном формате, дополненные нулями, чтобы занять весь слот в 32 байта.
Например:
Input: 23 (uint256)
Output:
0x0000000000000000000000000000000000000000000000000000000000000017
Input: 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f (address of Uniswap)
Output:
0x000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f
А также есть динамические типы данных:
string, bytes, array
Для них кодирование calldata будет выглядеть так:
- Первые 32 байта - смещение;
- Следующие 32 байта - длинна;
- Затем - значения;
Например, для байтов:
Input: 0x123
Output:
0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000021234000000000000000000000000000000000000000000000000000000000000
где:
offset:
0000000000000000000000000000000000000000000000000000000000000020
length(the value is 2 bytes length = 4 chrs):
0000000000000000000000000000000000000000000000000000000000000002
value(the value of string and bytes starts right after the length):
1234000000000000000000000000000000000000000000000000000000000000
Для строк:
Input: “GM Frens”
Output:
0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000008474d204672656e73000000000000000000000000000000000000000000000000
где:
offset:
0000000000000000000000000000000000000000000000000000000000000020
length:
0000000000000000000000000000000000000000000000000000000000000008
value(“GM Frens” in hex):
474d204672656e73000000000000000000000000000000000000000000000000
И для массивов:
Input: [1,3,42] → uint256 array
Output:
0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000002a
где:
offset:
0000000000000000000000000000000000000000000000000000000000000020
length (3 elements in the array):
0000000000000000000000000000000000000000000000000000000000000003
first element value(1):
0000000000000000000000000000000000000000000000000000000000000001
second element value(3):
0000000000000000000000000000000000000000000000000000000000000003
third element value(42):
000000000000000000000000000000000000000000000000000000000000002a
С примерами кода посты получаются большими, поэтому в следующем мы поговорим про offset.
#calldata