Sth about Solidity

随便记录的草稿, 别看~

1. About ABI

ABI: Application Binary Interface

function selector: use front 4 bytes as function selector to locate the function.

how to calculate: use keccak256 to get front 4 bytes.。

bytes4(keccak256("foo(uint32,bool)"))

an example:

function: function baz(uint32 x, bool y)

call it: baz(69, true)

function selector:  0xcdcd77c0     bytes4(keccak256("baz(uint32,bool)"))

0x0000000000000000000000000000000000000000000000000000000000000045
+ first param, uint32:69, should append 0 to get 32 bytes

0x0000000000000000000000000000000000000000000000000000000000000001
+ second param, bool:true

https://abi.hashex.org/

use abi.hashex try it, will get:

cdcd77c000000000000000000000000000000000000000000000000000000000000000450000000000000000000000000000000000000000000000000000000000000001

another example:

function: fn1(uint8[], bool, string)

call it: fn1([5,6], true, “hello world!“)

abi:  0dbb9c190000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c68656c6c6f20776f726c64210000000000000000000000000000000000000000

[analysis]:

  • front 4 bytes: 0dbb9c19 as function selector.

  • following 32 bytes: 0000000000000000000000000000000000000000000000000000000000000060 as first param is non-fixed type, so record it’s offset(96, 3 x 32, the value’s location after third 32bytes)

  • following 32 bytes: 0000000000000000000000000000000000000000000000000000000000000001 as second param: bool value (fixed length param)

  • following 32 bytes: 00000000000000000000000000000000000000000000000000000000000000c0 as third param is non-fixed type, so record it’s offset(192, 6 x 32, the value’s location after 6th 32bytes)

  • following 32 bytes: 0000000000000000000000000000000000000000000000000000000000000002 as first param : array length (non-fixed length param)

  • following 32 bytes: 0000000000000000000000000000000000000000000000000000000000000005 as first param : array element[0]

  • following 32 bytes: 0000000000000000000000000000000000000000000000000000000000000006 as first param : array element[1]

  • following 32 bytes: 000000000000000000000000000000000000000000000000000000000000000c as third param: string length(12) (non-fixed length param)

  • following 32 bytes: 68656c6c6f20776f726c64210000000000000000000000000000000000000000 as third param: string value(hex 2 = 1 char, such as ‘h‘ is 0x68, 0x6c is ‘l‘)


1. About Call/Callcode/Delegatecall/Staticcall

differences among these approaches:

  • call: call is a low level function to interact with other contracts, is recommended.

  • callcode: CALL modifies the storage of the callee, and CALLCODE modifies the storage of the caller.

  • delegatecall: DELEGATECALL can be considered a bugfix version of CALLCODE, and CALLCODE is no longer officially recommended. The difference is that MSG. SENDER is different**.** DELEGATECALL WILL ALWAYS USE THE ADDRESS OF THE ORIGINAL CALLER, WHILE CALLCODE WILL NOT.

  • staticcall: is currently no low-level API in Solidity that can call it directly, but it is planned to compile functions calling view and pure types into STATIC call instructions at the compiler level in the future.

pragma solidity ^0.8.0;

contract A {
    int public x;
    
    function inc_call(address _contractAddress) public {
        _contractAddress.call(bytes4(keccak256("inc()")));
    }
    function inc_callcode(address _contractAddress) public {
        _contractAddress.callcode(bytes4(keccak256("inc()")));
    }
}

contract B {
    int public x;
    
    function inc() public {
        x++;
    }
}
post image
pragma solidity ^0.4.25;

contract A {
    int public x;
    
    function inc_callcode(address _contractAddress) public {
        _contractAddress.callcode(bytes4(keccak256("inc()")));
    }
    function inc_delegatecall(address _contractAddress) public {
        _contractAddress.delegatecall(bytes4(keccak256("inc()")));
    }
}

contract B {
    int public x;
    
    event senderAddr(address);
    function inc() public {
        x++;
        emit senderAddr(msg.sender);
    }
}
post image