Solidity – Why Use Assembly calldataload at Offset 0xC4 in Solidity?

solidity

ChainBridge has a piece of solidity code:

assembly {

            amount := calldataload(0xC4)   // **why get data from 0xC4?

            recipientAddress := mload(0x40)
            lenRecipientAddress := calldataload(0xE4)   // offset 0x20 beside amount is the length variable, I know that.
            mstore(0x40, add(0x20, add(recipientAddress, lenRecipientAddress)))  // load address to the free memory

            calldatacopy(
                recipientAddress, // copy to destinationRecipientAddress
                0xE4, // copy from calldata @ 0x104        **Why copy from 0xE4?
                sub(calldatasize(), 0xE) // copy size (calldatasize - 0x104)    
                //** Why the length is calldatasize()-0xE? Is the original comment by the author correct?
            )
        }

The function deposit has 5 arguments, I know that the assembly code wants to get amount from the data argument. But I can't figure out

  1. why the offset is 0xC4, I try to calculate the offset from the first argument of the the function deposit. Is the offset of data argument: 4bytes(method sig)+32bytes(bytes32)+32bytes(uint8)+32bytes(uint64)+32bytes(address)? But the sum up is not 0xC4.
  2. why does calldatacopy use an offset 0xE4 and 0xE
  3. Is the original comment by the author correct?

The data argument consists of: amount, lenRecipientAddress and recipientAddress

The invocation path is : bridgeContract.depoist -> ERC20Handler.deposit, the input of data please refer the link, the data argument is passed transparently.

Another confuses me is that the ERC721Handler depoist function.
The input data is like this, the data consists of id,lenRecipientAddress and recipientAddress. The only difference is ERC721Handler use 32bytes id, the ERC20Handler use 32bytes amount, but their total length is the same. So from my perspective both of ERC20Handler and ERC721Handler should have the exact same code, but the last line code sub(calldatasize(), 0xE4) is different, the offset 0xE4 in ERC721Handler is different to the 0xE in the ERC20Handler.

The ERC721Handler's depoist:

calldatacopy(
                destinationRecipientAddress,    // copy to destinationRecipientAddress
                0xE4,                           // copy from calldata after destinationRecipientAddress length declaration @0xE4
                sub(calldatasize(), 0xE4)       // copy size (calldatasize - (0xE4 + 0x20))  
                //** Why use 0xE4? Is the original comment by the author correct?
            )

The invocation path is : bridgeContract.depoist -> ERC721Handler.deposit, the data argument is passed transparently.

Best Answer

1/ The calculation is missing the two slots required by data, first slot is the offset within the calldata, and the second slot is the length in bytes. That will be 4 + 32 x 4 + 32 x 2 = 196 = 0xc4.

2/ 0xe4 is the start of recipientAddress length. The 0xe seems to be a mistake, from the comment they wanted to write sub(calldatasize(), 0xe4). It shouldn't be a problem since data calldatacopy will return 0 for bytes outside calldatasize().

3/ It appears to be correct. The numbers are wrong.

Related Topic