Solady’s SafeTransferLib Part 1 — Safe ETH transfers

taha (gasgolfer.eth)
4 min readApr 4, 2023

--

its a work of art they say! looking at solady’s gas optimized solidity snippets

Let’s dive deep into Solady’s SafeTransferLib which is modified from Solmate’s SafeTransferLib to handle missing return values, Gracefully!

In this part, we will only look into ETH transfers.

Starting with custom errors

Customer errors are much cheaper than a string description because you can use the name of the error to describe it, which is encoded in only four bytes.

👍 for optimizing Solmate’s error handling

Error Instances

The comment above each is in NatSpec Format, check here to read more about it

safeTransferETH()

- SafeTransferETH

As per the function's name, it is used to transfer ETH from a contract to another account.

  • At line number 7
    if call(gas(), to, amount, 0, 0, 0, 0) is a success then
    returns 0 else returns 1

We are here to handle the missing return values, remember?
In this case, we will return an error with revert opcode and revert the transaction to save gas.
Hence if call(gas(), to, amount, 0, 0, 0, 0) == 0 then
iszero(0) is trueand the if condition satisfies so we enter into the if loop.

  • At line number 9, ETHtransferFailed() function selector 0xb12d13eb is stored at position 0 in the memory as 32 bytes (right padded with zeroes)
  • At line number 11revert opcode takes 2 args
    — offset: memory slot position, position 28 in this case
    — size: byte size to return, 4 bytes in this case

As shown in the image above, the function selector is 4 bytes and bytes<M> is left-aligned (while unit256 is right-aligned) we can get the function signature by returning 4 bytes from position 0x1c (28) to 0x1f (31), as the first memory slot stores 32 bytes of function signature (remaining 28 bytes padded with zeroes) that is why we revert(0x1c, 0x04)

For the sake of comparison, I have added a sample visual for uint<M> right-aligned

forceSafeTransferETH() with the three-argument version

forceSafeTransferETH(address, uint256, uint256)

let’s first see what Solady has to say about this function

Force sends amount (in wei) ETH to to, with a gasStipend. The gasStipend can be set to a low enough value to prevent storage writes or gas griefing.
If sending via the normal procedure fails, force sends the ETH by creating a temporary contract which uses SELFDESTRUCT to force send the ETH. Reverts if the current contract has insufficient balance.

  • From line number 5 to 10, it is checking the balance of the caller account using lt opcode, if it's less than the amount sending then it will revert with ETHTransferFailed().
  • From line number 12 to 20, if the call() fails and returns 0, it will create a temporary contract account withSELFDESTRUCT to remove the contract bytecode from EVM. As SELFDESTRUCT opcode takes an address as a parameter to send the current (contract) balance to the given
    address.
  • mstore(0x00, to) stores the 20 bytesto address at position 0, since bytes are left-aligned remaining 12 bytes are padded with 0s and the address is at position/offset 12 to 32.
  • mstore8(0x0b, 0x73) at position 11 of the above 32 byte memory slot, we store PUSH20 opcode to push 20 bytes to address to the stack.
  • mstore8(0x20, 0xff) stores SELFDESTRUCT opcode at position 33 (next starting byte)

Hence from position/offset 11 to 33, is our contract initialization code making the size of the code 22 bytes 0x16
create(amount, 0x0b, 0x16)

In the end, we use pop the opcode to remove the contract address from the EVM stack.
pop(create(amount, 0x0b, 0x16))

forceSafeTransferETH()

forceSafeTransferETH(address, uint256)

The only difference with the above forceSafeTransferETH() is that we are passing uint256 internal constant _GAS_STIPEND_NO_GRIEF = 100000 as gasStipend.

trySafeTransferETH()

trySafeTransferETH()

The above function does not revert upon failure, returns whether the transfer of ETH is successful instead.

In the next part, we will look into ERC20 transfers.

--

--