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
- why the offset is
0xC4
, I try to calculate the offset from the first argument of the the functiondeposit
. Is the offset ofdata
argument: 4bytes(method sig)+32bytes(bytes32)+32bytes(uint8)+32bytes(uint64)+32bytes(address)? But the sum up is not 0xC4. - why does
calldatacopy
use an offset0xE4
and0xE
- 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.