简体   繁体   中英

How to use BytesToUint function in Solidity (the one with assembly)?

I was using the following function to convert bytes to uint:

function bytesToUint(bytes b) public pure returns (uint){
    uint number;

    for(uint i=0;i<b.length;i++){
        number = number + uint(b[b.length-1-i])*(10**i);
    }

    return number;
}

Since explicit byte1 to uint conversion is no longer supported I found the following alternative:

function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) {
    require(_bytes.length >= (_start + 32), "Read out of bounds");
    uint256 tempUint;

    assembly {
        tempUint := mload(add(add(_bytes, 0x20), _start))
    }

    return tempUint;
}

The bytes is the input in the ApproveAndCall function of the ERC20 Token

function approveAndCall(address spender, uint tokens, bytes data) public returns (bool success) {
    allowed[msg.sender][spender] = tokens;
    emit Approval(msg.sender, spender, tokens);
    ApproveAndCallFallBack(spender).receiveApproval(msg.sender, tokens, this, data);
    return true;
}

which is sent over to the receiveApproval of my smart contract.

function receiveApproval(address _from, uint _token, address _tokenContract, bytes memory _data) public {
    
    if(!ERC20Interface(_tokenContract).transferFrom(_from, address(this), _token)) {
        revert();
    }
    
    _0xChangeLib.place_sell_order(exchange, _from, _tokenContract, _token, _0xChangeLib.toUint256(_data, 0));

}

Could someone explain how this new BytesToUint256 works? I can't get my head around the assembly code and how to use this function. I don't understand the uint256 _start argument. I am also not sure if I could use the same format as input as I was using. As argument I was converting a wei amount as a bytes, eg 100 wei = 0x100, with a simple function in javascript and sent over to the token address with Web3.js.

I would like within ReceiveApproval function of the smart contract to call the BytesToUint function to further process the data.

Thank you very much in advance for your help!

The _start basically points to the byte index in bytes array where the integer value starts. The first 32 (or 0x20 in hex) bytes contain the length of the bytes array and then starts the integer value which is stored in the next 32 bytes. The _start value is zero because second set of 32 bytes contain the integer value you need. You can essentially convert this function to this.

function toUint256(bytes memory _bytes)   
  internal
  pure
  returns (uint256 value) {

    assembly {
      value := mload(add(_bytes, 0x20))
    }
}

With regards to your comment 0x0 would mean bytes array has length 1 ie the second zero and the require statement expects the length of at least 32.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM