You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When a method such as transfer(address, uint256) is defined the Solidity compiler will add the following runtime checks:
calldatasize is at least 68 bytes long (4 selector, 64-bytes ABI-encoded params)
the address parameter is not encoded with any dirty bytes i.e. calldataload(0x4) == and(calldataload(0x4), 0xffffffffffffffffffffffffffffffffffffffff)
For the Solady tokens the second 2 check is arguably unnecessary and could be removed as all methods already account for and make sure to clean dirty bits in address parameters. The calldatasize check (1.) is arguably also unnecessary as it historically was mainly added to save users who had defective ABI-encoding implementations and would incorrectly concatenate parameters together.
I wanted to open the discussion to removing both of this in Solady with the following approach:
Find signatures for methods such as transfer, balanceOf etc. whereby the selector is the same but the signature is a parameter-less function (this ensures the Solidity compiler does not add the additional calldatasize check)
For these external methods load the parameters directly in inline-assembly from calldata e.g. let to := calldataload(0x4)
As a demo ERC20's transfer method would become:
function transfer_50eMP04() externalvirtualreturns (bool) {
address to;
uint256 amount;
/// @solidity memory-safe-assemblyassembly {
to :=calldataload(0x4)
amount :=calldataload(0x24)
}
_beforeTokenTransfer(msg.sender, to, amount);
/// @solidity memory-safe-assemblyassembly {
// Compute the balance slot and load its value.mstore(0x0c, _BALANCE_SLOT_SEED)
mstore(0x00, caller())
let fromBalanceSlot :=keccak256(0x0c, 0x20)
let fromBalance :=sload(fromBalanceSlot)
// Revert if insufficient balance.ifgt(amount, fromBalance) {
mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.revert(0x1c, 0x04)
}
// Subtract and store the updated balance.sstore(fromBalanceSlot, sub(fromBalance, amount))
// Compute the balance slot of `to`.mstore(0x00, to)
let toBalanceSlot :=keccak256(0x0c, 0x20)
// Add and store the updated balance of `to`.// Will not overflow because the sum of all user balances// cannot exceed the maximum uint256 value.sstore(toBalanceSlot, add(sload(toBalanceSlot), amount))
// Emit the {Transfer} event.mstore(0x20, amount)
log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, caller(), shr(96, mload(0x0c)))
}
_afterTokenTransfer(msg.sender, to, amount);
returntrue;
}
To mitigate their incorrect use this methods would have to be marked as external
The text was updated successfully, but these errors were encountered:
When a method such as
transfer(address, uint256)
is defined the Solidity compiler will add the following runtime checks:address
parameter is not encoded with any dirty bytes i.e.calldataload(0x4) == and(calldataload(0x4), 0xffffffffffffffffffffffffffffffffffffffff)
For the Solady tokens the second 2 check is arguably unnecessary and could be removed as all methods already account for and make sure to clean dirty bits in
address
parameters. The calldatasize check (1.) is arguably also unnecessary as it historically was mainly added to save users who had defective ABI-encoding implementations and would incorrectly concatenate parameters together.I wanted to open the discussion to removing both of this in Solady with the following approach:
transfer
,balanceOf
etc. whereby the selector is the same but the signature is a parameter-less function (this ensures the Solidity compiler does not add the additional calldatasize check)let to := calldataload(0x4)
As a demo ERC20's
transfer
method would become:To mitigate their incorrect use this methods would have to be marked as
external
The text was updated successfully, but these errors were encountered: