-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
using the safe erc20 with 32 length error
- Loading branch information
Showing
2 changed files
with
248 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,247 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.4; | ||
|
||
/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values. | ||
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol) | ||
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol) | ||
/// @dev Caution! This library won't check that a token has code, responsibility is delegated to the caller. | ||
library SafeTransferLib { | ||
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ | ||
/* CUSTOM ERRORS */ | ||
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ | ||
|
||
/// @dev The ETH transfer has failed. | ||
error ETHTransferFailed(); | ||
|
||
/// @dev The ERC20 `transferFrom` has failed. | ||
error TransferFromFailed(); | ||
|
||
/// @dev The ERC20 `transfer` has failed. | ||
error TransferFailed(); | ||
|
||
/// @dev The ERC20 `approve` has failed. | ||
error ApproveFailed(); | ||
|
||
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ | ||
/* CONSTANTS */ | ||
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ | ||
|
||
/// @dev Suggested gas stipend for contract receiving ETH | ||
/// that disallows any storage writes. | ||
uint256 internal constant _GAS_STIPEND_NO_STORAGE_WRITES = 2300; | ||
|
||
/// @dev Suggested gas stipend for contract receiving ETH to perform a few | ||
/// storage reads and writes, but low enough to prevent griefing. | ||
/// Multiply by a small constant (e.g. 2), if needed. | ||
uint256 internal constant _GAS_STIPEND_NO_GRIEF = 100000; | ||
|
||
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ | ||
/* ERC20 OPERATIONS */ | ||
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ | ||
|
||
/// @dev Sends `amount` of ERC20 `token` from `from` to `to`. | ||
/// Reverts upon failure. | ||
/// | ||
/// The `from` account must have at least `amount` approved for | ||
/// the current contract to manage. | ||
function safeTransferFrom(address token, address from, address to, uint256 amount) internal { | ||
/// @solidity memory-safe-assembly | ||
assembly { | ||
let m := mload(0x40) // Cache the free memory pointer. | ||
|
||
mstore(0x60, amount) // Store the `amount` argument. | ||
mstore(0x40, to) // Store the `to` argument. | ||
mstore(0x2c, shl(96, from)) // Store the `from` argument. | ||
// Store the function selector of `transferFrom(address,address,uint256)`. | ||
mstore(0x0c, 0x23b872dd000000000000000000000000) | ||
|
||
if iszero( | ||
and( // The arguments of `and` are evaluated from right to left. | ||
// Set success to whether the call reverted, if not we check it either | ||
// returned exactly 1 (can't just be non-zero data), or had no return data. | ||
or(eq(mload(0x00), 1), iszero(returndatasize())), | ||
call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20) | ||
) | ||
) { | ||
// Store the function selector of `TransferFromFailed()`. | ||
mstore(0x00, 0x7939f424) | ||
// Revert with (offset, size). | ||
revert(0x1c, 0x20) | ||
} | ||
|
||
mstore(0x60, 0) // Restore the zero slot to zero. | ||
mstore(0x40, m) // Restore the free memory pointer. | ||
} | ||
} | ||
|
||
/// @dev Sends all of ERC20 `token` from `from` to `to`. | ||
/// Reverts upon failure. | ||
/// | ||
/// The `from` account must have at least `amount` approved for | ||
/// the current contract to manage. | ||
function safeTransferAllFrom(address token, address from, address to) | ||
internal | ||
returns (uint256 amount) | ||
{ | ||
/// @solidity memory-safe-assembly | ||
assembly { | ||
let m := mload(0x40) // Cache the free memory pointer. | ||
|
||
mstore(0x40, to) // Store the `to` argument. | ||
mstore(0x2c, shl(96, from)) // Store the `from` argument. | ||
// Store the function selector of `balanceOf(address)`. | ||
mstore(0x0c, 0x70a08231000000000000000000000000) | ||
if iszero( | ||
and( // The arguments of `and` are evaluated from right to left. | ||
gt(returndatasize(), 0x1f), // At least 32 bytes returned. | ||
staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20) | ||
) | ||
) { | ||
// Store the function selector of `TransferFromFailed()`. | ||
mstore(0x00, 0x7939f424) | ||
// Revert with (offset, size). | ||
revert(0x1c, 0x20) | ||
} | ||
|
||
// Store the function selector of `transferFrom(address,address,uint256)`. | ||
mstore(0x00, 0x23b872dd) | ||
// The `amount` argument is already written to the memory word at 0x6c. | ||
amount := mload(0x60) | ||
|
||
if iszero( | ||
and( // The arguments of `and` are evaluated from right to left. | ||
// Set success to whether the call reverted, if not we check it either | ||
// returned exactly 1 (can't just be non-zero data), or had no return data. | ||
or(eq(mload(0x00), 1), iszero(returndatasize())), | ||
call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20) | ||
) | ||
) { | ||
// Store the function selector of `TransferFromFailed()`. | ||
mstore(0x00, 0x7939f424) | ||
// Revert with (offset, size). | ||
revert(0x1c, 0x20) | ||
} | ||
|
||
mstore(0x60, 0) // Restore the zero slot to zero. | ||
mstore(0x40, m) // Restore the free memory pointer. | ||
} | ||
} | ||
|
||
/// @dev Sends `amount` of ERC20 `token` from the current contract to `to`. | ||
/// Reverts upon failure. | ||
function safeTransfer(address token, address to, uint256 amount) internal { | ||
/// @solidity memory-safe-assembly | ||
assembly { | ||
mstore(0x14, to) // Store the `to` argument. | ||
mstore(0x34, amount) // Store the `amount` argument. | ||
// Store the function selector of `transfer(address,uint256)`. | ||
mstore(0x00, 0xa9059cbb000000000000000000000000) | ||
|
||
if iszero( | ||
and( // The arguments of `and` are evaluated from right to left. | ||
// Set success to whether the call reverted, if not we check it either | ||
// returned exactly 1 (can't just be non-zero data), or had no return data. | ||
or(eq(mload(0x00), 1), iszero(returndatasize())), | ||
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) | ||
) | ||
) { | ||
// Store the function selector of `TransferFailed()`. | ||
mstore(0x00, 0x90b8ec18) | ||
// Revert with (offset, size). | ||
revert(0x1c, 0x20) | ||
} | ||
// Restore the part of the free memory pointer that was overwritten. | ||
mstore(0x34, 0) | ||
} | ||
} | ||
|
||
/// @dev Sends all of ERC20 `token` from the current contract to `to`. | ||
/// Reverts upon failure. | ||
function safeTransferAll(address token, address to) internal returns (uint256 amount) { | ||
/// @solidity memory-safe-assembly | ||
assembly { | ||
mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`. | ||
mstore(0x20, address()) // Store the address of the current contract. | ||
if iszero( | ||
and( // The arguments of `and` are evaluated from right to left. | ||
gt(returndatasize(), 0x1f), // At least 32 bytes returned. | ||
staticcall(gas(), token, 0x1c, 0x24, 0x34, 0x20) | ||
) | ||
) { | ||
// Store the function selector of `TransferFailed()`. | ||
mstore(0x00, 0x90b8ec18) | ||
// Revert with (offset, size). | ||
revert(0x1c, 0x20) | ||
} | ||
|
||
mstore(0x14, to) // Store the `to` argument. | ||
// The `amount` argument is already written to the memory word at 0x34. | ||
amount := mload(0x34) | ||
// Store the function selector of `transfer(address,uint256)`. | ||
mstore(0x00, 0xa9059cbb000000000000000000000000) | ||
|
||
if iszero( | ||
and( // The arguments of `and` are evaluated from right to left. | ||
// Set success to whether the call reverted, if not we check it either | ||
// returned exactly 1 (can't just be non-zero data), or had no return data. | ||
or(eq(mload(0x00), 1), iszero(returndatasize())), | ||
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) | ||
) | ||
) { | ||
// Store the function selector of `TransferFailed()`. | ||
mstore(0x00, 0x90b8ec18) | ||
// Revert with (offset, size). | ||
revert(0x1c, 0x20) | ||
} | ||
// Restore the part of the free memory pointer that was overwritten. | ||
mstore(0x34, 0) | ||
} | ||
} | ||
|
||
/// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract. | ||
/// Reverts upon failure. | ||
function safeApprove(address token, address to, uint256 amount) internal { | ||
/// @solidity memory-safe-assembly | ||
assembly { | ||
mstore(0x14, to) // Store the `to` argument. | ||
mstore(0x34, amount) // Store the `amount` argument. | ||
// Store the function selector of `approve(address,uint256)`. | ||
mstore(0x00, 0x095ea7b3000000000000000000000000) | ||
|
||
if iszero( | ||
and( // The arguments of `and` are evaluated from right to left. | ||
// Set success to whether the call reverted, if not we check it either | ||
// returned exactly 1 (can't just be non-zero data), or had no return data. | ||
or(eq(mload(0x00), 1), iszero(returndatasize())), | ||
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) | ||
) | ||
) { | ||
// Store the function selector of `ApproveFailed()`. | ||
mstore(0x00, 0x3e3f8f73) | ||
// Revert with (offset, size). | ||
revert(0x1c, 0x20) | ||
} | ||
// Restore the part of the free memory pointer that was overwritten. | ||
mstore(0x34, 0) | ||
} | ||
} | ||
|
||
/// @dev Returns the amount of ERC20 `token` owned by `account`. | ||
/// Returns zero if the `token` does not exist. | ||
function balanceOf(address token, address account) internal view returns (uint256 amount) { | ||
/// @solidity memory-safe-assembly | ||
assembly { | ||
mstore(0x14, account) // Store the `account` argument. | ||
// Store the function selector of `balanceOf(address)`. | ||
mstore(0x00, 0x70a08231000000000000000000000000) | ||
amount := | ||
mul( | ||
mload(0x20), | ||
and( // The arguments of `and` are evaluated from right to left. | ||
gt(returndatasize(), 0x1f), // At least 32 bytes returned. | ||
staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20) | ||
) | ||
) | ||
} | ||
} | ||
} |