Различные abi.encode
В чате участник задавал вопрос про abi.encodeCall и мне захотелось сделать небольшой пост-напоминалку про различные виды кодирования abi. Думаю, многим будет полезно напомнить себе, в чем тут разница и как их использовать.
1. abi.encode - кодирует параметры, используя ABI specs. Сами закодированные параметры занимают по 32 байта. Возвращает байтовый массив данных. Если мы, к примеру, попробуем зашифровать строку "Hello" через abi.encode, то получим следующие зашифрованные данные:
1. Первые 32 байта - это, так называемый, offset (смещение), которые указывает, где начинаются данные.
2. Вторые 32 байта - размер строки.
3. Третьи 32 байта - значение строки.
Пример:
function getEncode(address _add, uint256 _value) pure public returns(bytes memory){
return abi.encode(_add, _value);
}
2. abi.encodePacked - тоже, что и abi.encode, только параметры пакуются, чтобы занимать меньше места. Например, если мы зашифруем туже строку "Hello", то вместо 3 слотов по 32 байта, получим всего 1 слот со значением строки.
function getEncodePacked(address _add, uint256 _value) pure public returns(bytes memory){
return abi.encodePacked(_add, _value);
}
P.S. При этом нужно быть аккуратным с данным видом кодирования, так как тут возможна популярная уязвимость с использованием динамических типов данных. Подробнее тут.
3. abi.encodeWithSignature - тоже, что и abi.encode, но добавляется еще подпись функции, как первый параметр.
function getEncodeWithSignature(address _add, uint256 _value) pure public returns(bytes memory){
bytes memory data = abi.encodeWithSignature("transfer(address,uint)",_add,_value);
return data;
}
4. abi.encodeWithSelector - тоже, что и abi.encode, но добавляется еще селектор функции, как первый параметр. Сам селектор кодируется с помощью keccak256 и берутся первые 4 байта.
function getEncodeWithSelector(address _add,uint256 _value) pure public returns(bytes memory){
bytes4 selector = bytes4(keccak256(bytes("transfer(address,uint)")));
bytes memory data = abi.encodeWithSelector(selector,_add,_value );
return data;
}
5. abi.encodeCall - тоже, что и abi.encode, но добавляет проверку типов данных на соответствие функции, которая была указана в аргументах. Результат кодирования схож с abi.encodeWithSelector.
function encodeCallData(address _to, uint _value) public pure returns (bytes memory) {
return abi.encodeCall(IERC20.transfer, (_to, _value));
}
6. abi.decode() - служит для расшифровывания байтовых массивов указанных выше. Принимает в качестве аргументов байтовый массив и ожидаемые типы данных.
function decodeData(bytes memory data) pure public returns(address, uint256){
(address add, uint256 value) = abi.decode(data, (address,uint256));
return (add,value);
}
Вроде как, вспомнил все abi.encode. Если что-то забыл или успели появиться новые с обновлениями языка, дайте знать в комментах.
#abi #encode
В чате участник задавал вопрос про abi.encodeCall и мне захотелось сделать небольшой пост-напоминалку про различные виды кодирования abi. Думаю, многим будет полезно напомнить себе, в чем тут разница и как их использовать.
1. abi.encode - кодирует параметры, используя ABI specs. Сами закодированные параметры занимают по 32 байта. Возвращает байтовый массив данных. Если мы, к примеру, попробуем зашифровать строку "Hello" через abi.encode, то получим следующие зашифрованные данные:
1. Первые 32 байта - это, так называемый, offset (смещение), которые указывает, где начинаются данные.
2. Вторые 32 байта - размер строки.
3. Третьи 32 байта - значение строки.
Пример:
function getEncode(address _add, uint256 _value) pure public returns(bytes memory){
return abi.encode(_add, _value);
}
2. abi.encodePacked - тоже, что и abi.encode, только параметры пакуются, чтобы занимать меньше места. Например, если мы зашифруем туже строку "Hello", то вместо 3 слотов по 32 байта, получим всего 1 слот со значением строки.
function getEncodePacked(address _add, uint256 _value) pure public returns(bytes memory){
return abi.encodePacked(_add, _value);
}
P.S. При этом нужно быть аккуратным с данным видом кодирования, так как тут возможна популярная уязвимость с использованием динамических типов данных. Подробнее тут.
3. abi.encodeWithSignature - тоже, что и abi.encode, но добавляется еще подпись функции, как первый параметр.
function getEncodeWithSignature(address _add, uint256 _value) pure public returns(bytes memory){
bytes memory data = abi.encodeWithSignature("transfer(address,uint)",_add,_value);
return data;
}
4. abi.encodeWithSelector - тоже, что и abi.encode, но добавляется еще селектор функции, как первый параметр. Сам селектор кодируется с помощью keccak256 и берутся первые 4 байта.
function getEncodeWithSelector(address _add,uint256 _value) pure public returns(bytes memory){
bytes4 selector = bytes4(keccak256(bytes("transfer(address,uint)")));
bytes memory data = abi.encodeWithSelector(selector,_add,_value );
return data;
}
5. abi.encodeCall - тоже, что и abi.encode, но добавляет проверку типов данных на соответствие функции, которая была указана в аргументах. Результат кодирования схож с abi.encodeWithSelector.
function encodeCallData(address _to, uint _value) public pure returns (bytes memory) {
return abi.encodeCall(IERC20.transfer, (_to, _value));
}
6. abi.decode() - служит для расшифровывания байтовых массивов указанных выше. Принимает в качестве аргументов байтовый массив и ожидаемые типы данных.
function decodeData(bytes memory data) pure public returns(address, uint256){
(address add, uint256 value) = abi.decode(data, (address,uint256));
return (add,value);
}
Вроде как, вспомнил все abi.encode. Если что-то забыл или успели появиться новые с обновлениями языка, дайте знать в комментах.
#abi #encode
🔥16🙏1🌭1