Skip to content

Commit 0260e43

Browse files
gretzkeshuhuiluo
andauthored
Optimize CurrencyLibrary.transfer (#717)
* Optimize `CurrencyLibrary.transfer` (#710) * Refactor ETH transfer in `CurrencyLibrary` The ETH transfer process in the Currency.sol file is now refactored using memory-safe assembly code. A new approach has been introduced to handle the transfer failure, instead of just setting the `success` variable value, the process now directly reverts with a `NativeTransferFailed` error. This ensures a more robust and reliable transfer process. * Refactor ERC20 transfer error handling The code has been streamlined by removing the `success` variable used in the ERC20 transfer method, and directly integrating the error handling into the function call. This change helps minimize unnecessary variable usage and allows more immediate error feedback, improving the program's efficiency and clarity. * Use Solady `SafeTransferLib.safeTransfer` --------- Co-authored-by: Daniel Gretzke <daniel@gretzke.de> * regenerate gas snapshots * update commit to audited version of solady * more accurate descriptions of modifications made to code * add code explanation * regenerate gas snapshots --------- Co-authored-by: Shuhui Luo <107524008+shuhuiluo@users.noreply.github.com>
1 parent d50bfc5 commit 0260e43

25 files changed

+48
-53
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
326027
1+
325929
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
139529
1+
139505
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
57275
1+
57229
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
59520
1+
59496
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
19871
1+
19837
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
181644
1+
181448
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
135933
1+
135835
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
115761
1+
115664
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
96504
1+
96455
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
88544
1+
88495
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
114348
1+
114299

.forge-snapshots/simple swap.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
129513
1+
129464
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
132045
1+
131947
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
178951
1+
178853
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
110009
1+
109936
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
121356
1+
121307
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
132744
1+
132695
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
122135
1+
122086
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
216725
1+
216627
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
144786
1+
144737

.forge-snapshots/swap with hooks.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
138356
1+
138307
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
175722
1+
175673
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
151822
1+
151773
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
154464
1+
154415

src/types/Currency.sol

Lines changed: 24 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -36,43 +36,38 @@ library CurrencyLibrary {
3636
Currency public constant NATIVE = Currency.wrap(address(0));
3737

3838
function transfer(Currency currency, address to, uint256 amount) internal {
39-
// implementation from
40-
// https://github.com/transmissions11/solmate/blob/e8f96f25d48fe702117ce76c79228ca4f20206cb/src/utils/SafeTransferLib.sol
39+
// altered from https://github.com/Vectorized/solady/blob/89101d53b7c8784cca935c1f2f6403639cee48b2/src/utils/SafeTransferLib.sol
40+
// modified custom error selectors
4141

42-
bool success;
4342
if (currency.isNative()) {
43+
/// @solidity memory-safe-assembly
4444
assembly {
45-
// Transfer the ETH and store if it succeeded or not.
46-
success := call(gas(), to, amount, 0, 0, 0, 0)
45+
// Transfer the ETH and revert if it fails.
46+
if iszero(call(gas(), to, amount, 0x00, 0x00, 0x00, 0x00)) {
47+
mstore(0x00, 0xf4b3b1bc) // `NativeTransferFailed()`.
48+
revert(0x1c, 0x04)
49+
}
4750
}
48-
49-
if (!success) revert NativeTransferFailed();
5051
} else {
52+
/// @solidity memory-safe-assembly
5153
assembly {
52-
// We'll write our calldata to this slot below, but restore it later.
53-
let memPointer := mload(0x40)
54-
55-
// Write the abi-encoded calldata into memory, beginning with the function selector.
56-
mstore(0, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
57-
mstore(4, to) // Append the "to" argument.
58-
mstore(36, amount) // Append the "amount" argument.
59-
60-
success :=
61-
and(
62-
// Set success to whether the call reverted, if not we check it either
63-
// returned exactly 1 (can't just be non-zero data), or had no return data.
64-
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
65-
// We use 68 because that's the total length of our calldata (4 + 32 * 2)
66-
// Counterintuitively, this call() must be positioned after the or() in the
67-
// surrounding and() because and() evaluates its arguments from right to left.
68-
call(gas(), currency, 0, 0, 68, 0, 32)
54+
mstore(0x14, to) // Store the `to` address in [0x20, 0x34).
55+
mstore(0x34, amount) // Store the `amount` argument in [0x34, 0x54).
56+
// Store the selector of `transfer(address,uint256)` in [0x10, 0x14).
57+
// also cleans the upper bits of `to`
58+
mstore(0x00, 0xa9059cbb000000000000000000000000)
59+
// Perform the transfer, reverting upon failure.
60+
if iszero(
61+
and( // The arguments of `and` are evaluated from right to left.
62+
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
63+
call(gas(), currency, 0, 0x10, 0x44, 0x00, 0x20)
6964
)
70-
71-
mstore(0x60, 0) // Restore the zero slot to zero.
72-
mstore(0x40, memPointer) // Restore the memPointer.
65+
) {
66+
mstore(0x00, 0xf27f64e4) // `ERC20TransferFailed()`.
67+
revert(0x1c, 0x04)
68+
}
69+
mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
7370
}
74-
75-
if (!success) revert ERC20TransferFailed();
7671
}
7772
}
7873

0 commit comments

Comments
 (0)