solidity encode encodePacked encodeWithSignature delegatecall

简介: solidity encode encodePacked encodeWithSignature delegatecall
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
  1. ASCII编码 7个bit位代表一个字符 0-127 每个数字对应一个字符也就是128个字符

  [0, 31] 以及 127 (del) 这 33 个属于不可打印的控制字符才有了base64 MIME多媒体传递数据

  1. Base32编码 A-Z(26) 2-7(6) 空白用= padding 5个bit代表一个字符 0-31 每个数字代表要给字符也就是32个字符
  1. 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

  1. 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 {}


相关文章
|
7月前
|
存储 Python
Python中encode和encoding的区别
Python中encode和encoding的区别
104 0
|
6月前
|
Go 数据安全/隐私保护
go 基于gin编写encode、decode、base64加密接口
go 基于gin编写encode、decode、base64加密接口
59 2
|
6月前
|
编解码 数据可视化 Java
Java如何进行Base64的编码(Encode)与解码(Decode)?
Java如何进行Base64的编码(Encode)与解码(Decode)?
301 1
|
存储 JSON 安全
base64_encode()和base64_decode(),URL的加密解密详解
base64_encode()和base64_decode(),URL的加密解密详解
436 0
|
自然语言处理 测试技术 Python
软件测试|深入理解Python的encode()和decode()方法
软件测试|深入理解Python的encode()和decode()方法
|
Python
Python3 ‘str‘ object has no attribute ‘decode‘. Did you mean: ‘encode‘?
Python3 ‘str‘ object has no attribute ‘decode‘. Did you mean: ‘encode‘?
287 0
|
Cloud Native 关系型数据库 OLAP
可以使用内置的函数`encode()`
可以使用内置的函数`encode()`
129 0
|
编解码 测试技术 Python
Python UnicodeEncodeError 'ascii' codec can't encode character 错误解决方法
Python UnicodeEncodeError 'ascii' codec can't encode character 错误解决方法
110 0
|
存储 自然语言处理 JavaScript
python 的encode和decode
python 的encode和decode
python 的encode和decode
|
编解码 JSON 数据格式
Python常见问题 - requests请求参数包含中文报错:UnicodeEncodeError: 'latin-1' codec can't encode characters in position 13-14: 小明 is not valid Latin-1. Use body.encode('utf-8')
Python常见问题 - requests请求参数包含中文报错:UnicodeEncodeError: 'latin-1' codec can't encode characters in position 13-14: 小明 is not valid Latin-1. Use body.encode('utf-8')
1942 0