ABI编码 #
一、ABI编码概述 #
ABI(Application Binary Interface)编码是Solidity中数据序列化的标准方式,用于合约间通信和数据存储。
二、abi.encode #
2.1 基本用法 #
solidity
contract ABIEncode {
function encodeUint(uint256 value) public pure returns (bytes memory) {
return abi.encode(value);
}
function encodeMultiple(
uint256 a,
address b,
bool c
) public pure returns (bytes memory) {
return abi.encode(a, b, c);
}
function encodeArray(uint256[] memory arr) public pure returns (bytes memory) {
return abi.encode(arr);
}
}
2.2 编码特点 #
solidity
contract EncodeFeatures {
// abi.encode:包含类型信息
function encodeWithType(uint256 value) public pure returns (bytes memory) {
return abi.encode(value); // 32字节,包含填充
}
// 每个参数编码为32字节
function encodeSize() public pure returns (uint256) {
bytes memory data = abi.encode(uint256(1), uint256(2));
return data.length; // 64字节
}
}
三、abi.encodePacked #
3.1 基本用法 #
solidity
contract ABIEncodePacked {
function packUint(uint256 value) public pure returns (bytes memory) {
return abi.encodePacked(value);
}
function packMultiple(
uint256 a,
address b,
bool c
) public pure returns (bytes memory) {
return abi.encodePacked(a, b, c);
}
function packString(string memory str) public pure returns (bytes memory) {
return abi.encodePacked(str);
}
}
3.2 紧凑编码特点 #
solidity
contract PackedFeatures {
// abi.encodePacked:紧凑编码,不包含类型信息
function compareEncoding() public pure returns (bytes memory, bytes memory) {
uint256 value = 1;
return (abi.encode(value), abi.encodePacked(value));
// encode: 32字节
// encodePacked: 1字节
}
// 字符串拼接
function concatStrings(
string memory a,
string memory b
) public pure returns (string memory) {
return string(abi.encodePacked(a, b));
}
// 计算哈希
function hash(
address sender,
uint256 amount,
uint256 nonce
) public pure returns (bytes32) {
return keccak256(abi.encodePacked(sender, amount, nonce));
}
}
四、abi.encodeWithSelector #
4.1 基本用法 #
solidity
contract EncodeWithSelector {
function encodeTransfer(
address to,
uint256 amount
) public pure returns (bytes memory) {
return abi.encodeWithSelector(
bytes4(keccak256("transfer(address,uint256)")),
to,
amount
);
}
function encodeApprove(
address spender,
uint256 amount
) public pure returns (bytes memory) {
return abi.encodeWithSelector(
0x095ea7b3, // approve(address,uint256) 的选择器
spender,
amount
);
}
}
4.2 用于合约调用 #
solidity
contract UseSelector {
function callTransfer(
address token,
address to,
uint256 amount
) public returns (bool) {
bytes memory data = abi.encodeWithSelector(
bytes4(keccak256("transfer(address,uint256)")),
to,
amount
);
(bool success, bytes memory result) = token.call(data);
require(success, "Call failed");
return abi.decode(result, (bool));
}
}
五、abi.encodeWithSignature #
5.1 基本用法 #
solidity
contract EncodeWithSignature {
function encodeTransfer(
address to,
uint256 amount
) public pure returns (bytes memory) {
return abi.encodeWithSignature(
"transfer(address,uint256)",
to,
amount
);
}
// 等价于
function encodeWithSelectorEquivalent(
address to,
uint256 amount
) public pure returns (bytes memory) {
return abi.encodeWithSelector(
bytes4(keccak256("transfer(address,uint256)")),
to,
amount
);
}
}
六、abi.decode #
6.1 基本用法 #
solidity
contract ABIDecode {
function decodeUint(bytes memory data) public pure returns (uint256) {
return abi.decode(data, (uint256));
}
function decodeMultiple(
bytes memory data
) public pure returns (uint256, address, bool) {
return abi.decode(data, (uint256, address, bool));
}
function decodeArray(bytes memory data) public pure returns (uint256[] memory) {
return abi.decode(data, (uint256[]));
}
}
6.2 编码解码示例 #
solidity
contract EncodeDecode {
struct User {
address wallet;
string name;
uint256 balance;
}
function encodeUser(User memory user) public pure returns (bytes memory) {
return abi.encode(user);
}
function decodeUser(bytes memory data) public pure returns (User memory) {
return abi.decode(data, (User));
}
function roundTrip(User memory user) public pure returns (User memory) {
bytes memory data = encodeUser(user);
return decodeUser(data);
}
}
七、实际应用示例 #
7.1 签名验证 #
solidity
contract SignatureVerification {
function verify(
address signer,
bytes32 hash,
bytes memory signature
) public pure returns (bool) {
bytes32 r;
bytes32 s;
uint8 v;
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return ecrecover(hash, v, r, s) == signer;
}
function hashMessage(
address to,
uint256 amount,
uint256 nonce
) public pure returns (bytes32) {
return keccak256(abi.encodePacked(to, amount, nonce));
}
}
7.2 跨合约调用 #
solidity
contract CrossContractCall {
function callFunction(
address target,
string memory functionName,
uint256 value
) public returns (bytes memory) {
bytes memory data = abi.encodeWithSignature(
functionName,
value
);
(bool success, bytes memory result) = target.call(data);
require(success, "Call failed");
return result;
}
}
八、总结 #
ABI编码要点:
| 函数 | 说明 |
|---|---|
| abi.encode | 完整编码(含类型) |
| abi.encodePacked | 紧凑编码 |
| abi.encodeWithSelector | 带选择器编码 |
| abi.encodeWithSignature | 带签名编码 |
| abi.decode | 解码 |
使用建议:
- 使用encode进行标准编码
- 使用encodePacked节省空间
- 使用decode解析数据
接下来,让我们学习内联汇编!
最后更新:2026-03-27