I have been absolutely racking my brain trying to understand this line of code from OpenZeppelin's ERC721.sol file. It is inside the function _checkOnERC721Received. I've already dove into a bunch of documentation and I just can't find anything that makes this line truly make sense
assembly { revert(add(32, reason), mload(reason)) }
taken from
function _checkOnERC721Received(
address from,
address to,
uint256 tokenId,
bytes memory data
) private returns (bool) {
if (to.isContract()) {
try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) {
return retval == IERC721Receiver.onERC721Received.selector;
} catch (bytes memory reason) {
if (reason.length == 0) {
revert("ERC721: transfer to non ERC721Receiver implementer");
} else {
/// @solidity memory-safe-assembly
assembly {
revert(add(32, reason), mload(reason))
}
}
}
} else {
return true;
}
}
Why 32 is added to reason and the starting point of revert? Is revert using 32 as bits of bytes? From my understanding it would be the difference between a fresh 256 bit block(32*8) and the 32 bits that the reason variable takes up. reason is a "bytes memory" type, which is a size of 32 bits. reason is equivalent to the error variable in a try{} catch{}. With bytes type being big endian the 32 addition, in bits, would completely skip over the reason variable into the bit immediately after reason. Either way both of these options skip over reason completely, which, from my understanding, is what revert is supposed to return. How can it return anything if revert is of the general format revert(start, end). The only way I see this working out is if revert is of the general format revert(end, start).