@@ -10,6 +10,18 @@ import {
10
10
11
11
import { ConduitBatch1155Transfer } from "../conduit/lib/ConduitStructs.sol " ;
12
12
13
+ /**
14
+ * @title TokenTransferrer
15
+ * @author 0age
16
+ * @custom:coauthor d1ll0n
17
+ * @custom:coauthor transmissions11
18
+ * @notice TokenTransferrer is a library for performing optimized ERC20, ERC721,
19
+ * ERC1155, and batch ERC1155 transfers, used by both Seaport as well as
20
+ * by conduits deployed by the ConduitController. Use great caution when
21
+ * considering these functions for use in other codebases, as there are
22
+ * significant side effects and edge cases that need to be thoroughly
23
+ * understood and carefully addressed.
24
+ */
13
25
contract TokenTransferrer is TokenTransferrerErrors {
14
26
/**
15
27
* @dev Internal function to transfer ERC20 tokens from a given originator
@@ -40,6 +52,11 @@ contract TokenTransferrer is TokenTransferrerErrors {
40
52
mstore (ERC20_transferFrom_amount_ptr , amount)
41
53
42
54
// Make call & copy up to 32 bytes of return data to scratch space.
55
+ // Scratch space does not need to be cleared ahead of time, as the
56
+ // subsequent check will ensure that either at least a full word of
57
+ // return data is received (in which case it will be overwritten) or
58
+ // that no data is received (in which case scratch space will be
59
+ // ignored) on a successful call to the given token.
43
60
let callStatus := call (
44
61
gas (),
45
62
token,
@@ -62,8 +79,8 @@ contract TokenTransferrer is TokenTransferrerErrors {
62
79
callStatus
63
80
)
64
81
65
- // If the transfer failed or it returned nothing:
66
- // Group these because they should be uncommon .
82
+ // Handle cases where either the transfer failed or no data was
83
+ // returned. Group these, as most transfers will succeed with data .
67
84
// Equivalent to `or(iszero(success), iszero(returndatasize()))`
68
85
// but after it's inverted for JUMPI this expression is cheaper.
69
86
if iszero (and (success, iszero (iszero (returndatasize ())))) {
@@ -190,14 +207,14 @@ contract TokenTransferrer is TokenTransferrerErrors {
190
207
)
191
208
}
192
209
193
- // Otherwise revert with error about token not having code:
210
+ // Otherwise, revert with error about token not having code:
194
211
mstore (NoContract_error_sig_ptr, NoContract_error_signature)
195
212
mstore (NoContract_error_token_ptr, token)
196
213
revert (NoContract_error_sig_ptr, NoContract_error_length)
197
214
}
198
215
199
- // Otherwise the token just returned nothing but otherwise
200
- // succeeded; no need to optimize for this as it's not
216
+ // Otherwise, the token just returned no data despite the call
217
+ // having succeeded; no need to optimize for this as it's not
201
218
// technically ERC20 compliant.
202
219
}
203
220
@@ -747,6 +764,8 @@ contract TokenTransferrer is TokenTransferrerErrors {
747
764
748
765
// Reset the free memory pointer to the default value; memory must
749
766
// be assumed to be dirtied and not reused from this point forward.
767
+ // Also note that the zero slot is not reset to zero, meaning empty
768
+ // arrays cannot be safely created or utilized until it is restored.
750
769
mstore (FreeMemoryPointerSlot, DefaultFreeMemoryPointer)
751
770
}
752
771
}
0 commit comments