文章目录
- bit bytes 0x uint
- 编码ASCII和BaseXX
- 1. encode 标准的对参数abi编码
- 2. encodePacked
- 3. decode对编码后的数据解码
- 4. encodeWithSelector 对方法keccak256和参数encode并拼接到一起返回
- 5. encodeWithSignature 相当于上面的简写
- 6. Storage Proxy中的属性要和impl的一致
- 7. delegatecall 调用编码后的方法 修改proxy中的值 读取的时候是proxy中的值
- 8. call 调用编码后的方法 修改impl中的值 staticcall-只能读取值,不能写值
- 9. 实例代码App
bit bytes 0x uint
bit 二进制位
byte 最小的存储单位 1 byte = 8bit (bytes1-32) bytes 不定长,引用类型
uint8 = 8 bit 最大值就是255 = 2^8-1 (uint(8-256))
0x 十六进制 一位 = 4bit 15 =2^4-1
一个数字或字母占一个字节,一个汉字占用3个字节
编码ASCII和BaseXX
- ASCII编码 7个bit位代表一个字符 0-127 每个数字对应一个字符也就是128个字符
[0, 31] 以及 127 (del) 这 33 个属于不可打印的控制字符才有了base64 MIME多媒体传递数据- Base32编码 A-Z(26) 2-7(6) 空白用= padding 5个bit代表一个字符 0-31 每个数字代表要给字符也就是32个字符
- Base64编码 A-Za-z(52) 0-9(10) + / 6个bit代表一个字符0-63 每个数字代表要给字符也就是64个字符
算法就是3个字节(3*8bit)转成4个base64字符(可打印的字符),不是3的倍数,用=号补充
ASCII对应的对应的字符 转成bit 然后转成base64显示出来
3*8bit=6bit(base64字符)*4- Base58 o0 1i +/ 去掉
1. encode 标准的对参数abi编码
abi.encode(address(0x630959E5aE57D1165c29B5aDC2F77C2bB8B730a0),127)
000000000000000000000000630959e5ae57d1165c29b5adc2f77c2bb8b730a0
000000000000000000000000000000000000000000000000000000000000007f
生成的abi会自动填充到32个byte 就是64个十六进制位
2. encodePacked
abi.encodePacked(address(0x630959E5aE57D1165c29B5aDC2F77C2bB8B730a0),uint8(127));
0x630959e5ae57d1165c29b5adc2f77c2bb8b730a0
7f
不会填充,紧编码数据
3. decode对编码后的数据解码
abi.encode(“a”,“b”)
abi.decode(data, (string, string))
4. encodeWithSelector 对方法keccak256和参数encode并拼接到一起返回
abi.encodeWithSelector(bytes4(keccak256(“set(uint256)”)),number)
5. encodeWithSignature 相当于上面的简写
abi.encodeWithSignature(“set(uint256)”,number)
6. Storage Proxy中的属性要和impl的一致
7. delegatecall 调用编码后的方法 修改proxy中的值 读取的时候是proxy中的值
8. call 调用编码后的方法 修改impl中的值 staticcall-只能读取值,不能写值
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
contract BytesStudy{
uint public setX;
bytes1 a2 = '1';
bytes5 hh = 0xffffffffff;
bytes2 b = '11';
bytes3 c = 0xffffff;
bytes32 d = '01234567890123456789012345678900';
function test() public view returns (bytes4, bytes1, bytes1, bytes1, bytes1,bytes1){
bytes4 a = 0x001122FF;
return (a, a[0], a[1], a[2], a[3],a2);
}
function concat(string memory _a, string memory _b) public pure returns (string memory) {
return string(abi.encodePacked(_a, _b));
}
//生成的abi需要填充到32个byte 就是64个十六进制位
function testEncode() public pure returns (bytes memory){
return abi.encode("a","b");
}
//
function decode(bytes memory data) public pure returns (string memory _str1, string memory _str2) {
(_str1, _str2) = abi.decode(data, (string, string));
}
//000000000000000000000000630959e5ae57d1165c29b5adc2f77c2bb8b730a0
//000000000000000000000000000000000000000000000000000000000000007f
function testEncode2() public pure returns (bytes memory){
return abi.encode(address(0x630959E5aE57D1165c29B5aDC2F77C2bB8B730a0),127);
}
//0xb63e800d000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000500e5eb0cf12736f237604bb90ee996a24def620000000000000000000000000aeb79c89bd801348da200c73533908562a1d726e00000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000
//去掉前面的方法id(0x+4个bytes(8个16进制位))就是参数值000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000500e5eb0cf12736f237604bb90ee996a24def620000000000000000000000000aeb79c89bd801348da200c73533908562a1d726e00000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000
function test4(bytes memory d) public pure returns (address[] memory,uint256,address,bytes memory,address,address,uint256,address){
return abi.decode(d, (address[],uint256,address,bytes,address,address,uint256,address));
}
//不会填充到64位 uint8=8bit = 1bytes = 2十六进制位
//0x630959e5ae57d1165c29b5adc2f77c2bb8b730a0
//7f
function testEncodePacked2() public pure returns (bytes memory){
return abi.encodePacked(address(0x630959E5aE57D1165c29B5aDC2F77C2bB8B730a0),uint8(127));
}
function testEncodePacked() public pure returns (bytes memory){
return abi.encodePacked("a","b");
}
//方法名和参数的abi编码1
//传入10返回
//0x60fe47b1
//000000000000000000000000000000000000000000000000000000000000000a
function testEncodeWithSelector(uint number) public pure returns (bytes memory){
return abi.encodeWithSelector(bytes4(keccak256("set(uint256)")),number);
}
function set(uint x) public {
setX = x;
}
//方法名和参数的abi编码2
function testEncodeWithSignature(uint number) public pure returns (bytes memory){
return abi.encodeWithSignature("set(uint256)",number);
}
}
contract MyProxy {
uint public setX;
//可以修改MyProxy-setX值
//0x60fe47b1
//000000000000000000000000000000000000000000000000000000000000000a
function doFunction(address _address,bytes calldata _calldata ) public returns (bool){
(bool success,) = _address.delegatecall(_calldata);
require(success);
return true;
}
//修改的是BytesStudy-setX值
function doFunction2(address _address,bytes calldata _calldata ) public returns (bool){
(bool success,) = _address.call(_calldata);
require(success);
return true;
}
}
contract TestPayable {
uint x;
uint y;
fallback() external payable { x = 1; y = msg.value; }
receive() external payable { x = 2; y = msg.value; }
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
contract TestPayable {
event Log(string methodName,uint _x,uint _y);
uint x;
uint y;
//调用没有对应的方法时候的回调
fallback() external payable {
x = 1;
y = msg.value;
emit Log("fallback",x,y);
}
//接受到eth的回调
receive() external payable {
x = 2;
y = msg.value;
emit Log("receive",x,y);
}
function clearXY() public returns (uint) {
x = 0;
y = 0;
emit Log("clearXY",x,y);
return 0;
}
function setXY(uint _x,uint _y) public {
x = _x;
y = _y;
emit Log("setXY",x,y);
}
function getValue() public pure returns (uint) {
return 0;
}
function getValue2() public pure returns (uint,uint) {
return (0,1);
}
}
contract TestSender {
event Log(string name,address _addre);
//msg.sender调用这个合约的地址(包括普通地址或者合约地址)
function testSender() public {
emit Log("TestSender",msg.sender);
}
}
contract TestProxy {
event Log(string name,address _addre);
event LogBool(string name,bool isOK, bytes dt);
// 测试msg.sender
function callTestSender(TestSender ts) public {
emit Log("TestProxy",msg.sender);
ts.testSender();
}
// 写的方法有1个返回值
function callTestPayable(address _address) public returns (bool) {
(bool success,bytes memory returnData) = _address.delegatecall(abi.encodeWithSignature("clearXY()"));
emit LogBool("callTestPayable-clearXY",success,returnData);
require(success);
return true;
}
// 读的方法有1个返回值
function callTestPayable2(address _address) public returns (bool) {
(bool success,bytes memory returnData) = _address.delegatecall(abi.encodeWithSignature("getValue()"));
emit LogBool("callTestPayable2-getValue",success,returnData);
require(success);
return true;
}
//没有对应的调用方法
function callTestPayableNo(address _address) public returns (bool) {
(bool success,) = _address.delegatecall(abi.encodeWithSignature("clearXYZ()"));
emit LogBool("callTestPayableNo-clearXYZ",success,'aaaa');
require(success);
return true;
}
// 读的方法有1个返回值
//0000000000000000000000000000000000000000000000000000000000000000
//0000000000000000000000000000000000000000000000000000000000000001
function callTestPayable3(address _address) public returns (bool) {
(bool success,bytes memory returnData) = _address.delegatecall(abi.encodeWithSignature("getValue2()"));
emit LogBool("callTestPayable3-getValue2",success,returnData);
require(success);
return true;
}
}
9. 实例代码App
MyApp
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
//属性存储插槽slot中,每个solt顺序合约A和aProxy一致,否则会报错
//定义不同的Storage来存储属性值 让合约A,aProxy继承来统一插槽
//用户信息
contract MyAppStorage {
struct User{
uint age;
uint sex;
bool isMember;
}
mapping (address => User) public users;
bool public isOpen;
string public appName;
}
contract OwnableStorage {
address public owner;
constructor() {
owner = msg.sender;
}
event OwnerUpdate(address _prevOwner, address _newOwner);
modifier onlyOwner {
require(msg.sender == owner,"only owner");
_;
}
function transferOwnership(address _newOwner) public onlyOwner {
require(_newOwner != owner, "Cannot transfer to yourself");
owner = _newOwner;
}
}
contract ProxyStorage {
/**
* Current contract to which we are proxing
*/
address public currentContract;
}
contract Storage is MyAppStorage,OwnableStorage,ProxyStorage {
}
interface IMyApp{
event RegisterUser(
address indexed _caller,
address indexed _deployer
);
event eOpen(
bool indexed rIsOpen
);
event logName(string name);
function updateOpen(bool _isOpen) external;
}
contract MyApp is Storage,IMyApp{
function initialize() external {
appName = "AppTest";
}
modifier onlyOpen {
require(isOpen,"only open");
_;
}
// 测试阶段用public,正式环境用external
function registerUser(address beneficiary) public onlyOpen{
require(beneficiary != address(0), "invalid address");
require(users[beneficiary].isMember == false, "address is already register");
User storage user = users[beneficiary];
user.isMember = true;
emit RegisterUser(msg.sender, beneficiary);
}
function updateOpen(bool _isOpen) override public onlyOwner{
isOpen = _isOpen;
emit eOpen(isOpen);
}
}
proxy
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
//用户信息
contract MyAppStorage {
struct User{
uint age;
uint sex;
bool isMember;
}
mapping (address => User) public users;
bool public isOpen;
string public appName;
}
contract OwnableStorage {
address public owner;
constructor() {
owner = msg.sender;
}
event OwnerUpdate(address _prevOwner, address _newOwner);
modifier onlyOwner {
require(msg.sender == owner,"only owner");
_;
}
function transferOwnership(address _newOwner) public onlyOwner {
require(_newOwner != owner, "Cannot transfer to yourself");
owner = _newOwner;
}
}
contract ProxyStorage {
/**
* Current contract to which we are proxing
*/
address public currentContract;
}
contract Storage is MyAppStorage,OwnableStorage,ProxyStorage {
}
contract DelegateProxy {
/**
* @dev Performs a delegatecall and returns whatever the delegatecall returned (entire context execution will return!)
* @param _dst Destination address to perform the delegatecall
* @param _calldata Calldata for the delegatecall
*/
function delegatedFwd(address _dst, bytes memory _calldata) internal {
require(isContract(_dst));
assembly {
let result := delegatecall(gas(), _dst, add(_calldata, 0x20), mload(_calldata), 0, 0)
let size := returndatasize()
let ptr := mload(0x40)
returndatacopy(ptr, 0, size)
// revert instead of invalid() bc if the underlying call failed with invalid() it already wasted gas.
// if the call returned error data, forward it
switch result case 0 { revert(ptr, size) }
default { return(ptr, size) }
}
}
function isContract(address _target) view internal returns (bool) {
uint256 size;
assembly { size := extcodesize(_target) }
return size > 0;
}
}
contract Proxy is Storage, DelegateProxy {
event UpgradeE(address indexed newContract);
event Fallback(bytes msgData);
function Upgrade(address _proxy) public onlyOwner {
currentContract = _proxy;
}
fallback() external payable {
emit Fallback(msg.data);
require(isContract(currentContract),"error currentContract");
delegatedFwd(currentContract,msg.data);
}
receive() external payable { }
}
contract MyAppProxy is Proxy {}