forked from panoptic-labs/panoptic-v1-core
-
Notifications
You must be signed in to change notification settings - Fork 1
/
SafeTransferLib.sol
68 lines (56 loc) · 3.36 KB
/
SafeTransferLib.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
// Libraries
import {Errors} from "@libraries/Errors.sol";
/// @notice Safe ERC20 transfer library that gracefully handles missing return values.
/// @author Axicon Labs Limited
/// @author Modified from Solmate (https://github.com/Rari-Capital/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 {
/*//////////////////////////////////////////////////////////////
ERC20 OPERATIONS
//////////////////////////////////////////////////////////////*/
function safeTransferFrom(address token, address from, address to, uint256 amount) internal {
bool success;
assembly ("memory-safe") {
// Get free memory pointer - we will store our calldata in scratch space starting at the offset specified here.
let p := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(p, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
mstore(add(4, p), from) // Append the "from" argument.
mstore(add(36, p), to) // Append the "to" argument.
mstore(add(68, p), amount) // Append the "amount" argument.
success := and(
// 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(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
// We use 100 because that's the total length of our calldata (4 + 32 * 3)
// Counterintuitively, this call() must be positioned after the or() in the
// surrounding and() because and() evaluates its arguments from right to left.
call(gas(), token, 0, p, 100, 0, 32)
)
}
if (!success) revert Errors.TransferFailed();
}
function safeTransfer(address token, address to, uint256 amount) internal {
bool success;
assembly ("memory-safe") {
// Get free memory pointer - we will store our calldata in scratch space starting at the offset specified here.
let p := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(p, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
mstore(add(4, p), to) // Append the "to" argument.
mstore(add(36, p), amount) // Append the "amount" argument.
success := and(
// 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(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
// We use 68 because that's the total length of our calldata (4 + 32 * 2)
// Counterintuitively, this call() must be positioned after the or() in the
// surrounding and() because and() evaluates its arguments from right to left.
call(gas(), token, 0, p, 68, 0, 32)
)
}
if (!success) revert Errors.TransferFailed();
}
}