Skip to content

Commit acc1d12

Browse files
committed
Remove TransferFrom Functionality, Rename
1 parent 5f784aa commit acc1d12

3 files changed

Lines changed: 39 additions & 129 deletions

File tree

contracts/src/forwarders/ERC20Forwarder.sol

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -54,40 +54,27 @@ contract ERC20Forwarder is EmergencyMigratableForwarderBase {
5454
function _forwardCall(bytes calldata input) internal override returns (bytes memory output) {
5555
ERC20ForwarderInput.CallType callType = ERC20ForwarderInput.CallType(uint8(input[31]));
5656

57-
if (callType == ERC20ForwarderInput.CallType.Transfer) {
57+
if (callType == ERC20ForwarderInput.CallType.Unwrap) {
5858
// slither-disable-next-line unused-return
5959
(
6060
, // CallType
6161
address token,
6262
address to,
6363
uint256 value
64-
) = input.decodeTransfer();
64+
) = input.decodeUnwrap();
6565

6666
emit Unwrapped({token: token, to: to, value: value});
6767

6868
IERC20(token).safeTransfer({to: to, value: value});
69-
} else if (callType == ERC20ForwarderInput.CallType.TransferFrom) {
70-
// slither-disable-next-line unused-return
71-
(
72-
, // CallType
73-
address token,
74-
address from,
75-
uint256 value
76-
) = input.decodeTransferFrom();
77-
78-
emit Wrapped({token: token, from: from, value: value});
79-
80-
// slither-disable-next-line arbitrary-send-erc20
81-
IERC20(token).safeTransferFrom({from: from, to: address(this), value: value});
82-
} else if (callType == ERC20ForwarderInput.CallType.PermitWitnessTransferFrom) {
69+
} else if (callType == ERC20ForwarderInput.CallType.Wrap) {
8370
// slither-disable-next-line unused-return
8471
(
8572
, // CallType
8673
address from,
8774
ISignatureTransfer.PermitTransferFrom memory permit,
8875
bytes32 witness,
8976
bytes memory signature
90-
) = input.decodePermitWitnessTransferFrom();
77+
) = input.decodeWrap();
9178

9279
if (permit.permitted.amount > type(uint128).max) {
9380
revert TypeOverflow({limit: type(uint128).max, actual: permit.permitted.amount});

contracts/src/forwarders/ERC20ForwarderInput.sol

Lines changed: 8 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,17 @@ import {ISignatureTransfer} from "@permit2/src/interfaces/IPermit2.sol";
1010
/// @custom:security-contact security@anoma.foundation
1111
library ERC20ForwarderInput {
1212
enum CallType {
13-
Transfer,
14-
TransferFrom,
15-
PermitWitnessTransferFrom
13+
Unwrap,
14+
Wrap
1615
}
1716

1817
/// @notice Encodes the input for the ERC-20 transfer call.
1918
/// @param token The ERC-20 token.
2019
/// @param to The address receiving the tokens.
2120
/// @param value The value to send.
2221
/// @return input The encoded input.
23-
function encodeTransfer(address token, address to, uint128 value) public pure returns (bytes memory input) {
24-
input = abi.encode(CallType.Transfer, token, to, value);
22+
function encodeUnwrap(address token, address to, uint128 value) public pure returns (bytes memory input) {
23+
input = abi.encode(CallType.Unwrap, token, to, value);
2524
}
2625

2726
/// @notice Decodes the input for the ERC-20 transfer call.
@@ -31,51 +30,27 @@ library ERC20ForwarderInput {
3130
/// @return to The address receiving the tokens.
3231
/// @return value The value to send. Note that value is limited to `uint128` to fit the in the
3332
/// `Resource.quantity` field.
34-
function decodeTransfer(bytes calldata input)
33+
function decodeUnwrap(bytes calldata input)
3534
public
3635
pure
3736
returns (CallType callType, address token, address to, uint128 value)
3837
{
3938
(callType, token, to, value) = abi.decode(input, (CallType, address, address, uint128));
4039
}
4140

42-
/// @notice Encodes the input for the ERC-20 `transferFrom` call.
43-
/// @param token The ERC-20 token.
44-
/// @param from The address to withdraw the tokens from.
45-
/// @param value The value to send.
46-
/// @return input The encoded input.
47-
function encodeTransferFrom(address token, address from, uint256 value) public pure returns (bytes memory input) {
48-
input = abi.encode(CallType.TransferFrom, token, from, value);
49-
}
50-
51-
/// @notice Decodes the input for the ERC-20 `transferFrom` call.
52-
53-
/// @param input The encoded input.
54-
/// @return callType The call type.
55-
/// @return token The ERC-20 token.
56-
/// @return from The address to withdraw the tokens from.
57-
/// @return value The value to send.
58-
function decodeTransferFrom(bytes calldata input)
59-
public
60-
pure
61-
returns (CallType callType, address token, address from, uint128 value)
62-
{
63-
(callType, token, from, value) = abi.decode(input, (CallType, address, address, uint128));
64-
}
65-
6641
/// @notice Encodes the input for the Permit2 `permitWitnessTransferFrom` call.
6742
/// @param from The address to withdraw the tokens from.
6843
/// @param permit The permit data constituted by the token address, token amount, nonce, and deadline.
6944
/// @param witness The witness information.
7045
/// @param signature The signature over the `PermitWitnessTransferFrom` message.
7146
/// @return input The encoded input.
72-
function encodePermitWitnessTransferFrom(
47+
function encodeWrap(
7348
address from,
7449
ISignatureTransfer.PermitTransferFrom memory permit,
7550
bytes32 witness,
7651
bytes memory signature
7752
) public pure returns (bytes memory input) {
78-
input = abi.encode(CallType.PermitWitnessTransferFrom, from, permit, witness, signature);
53+
input = abi.encode(CallType.Wrap, from, permit, witness, signature);
7954
}
8055

8156
/// @notice Decodes the input for the Permit2 `permitWitnessTransferFrom` call.
@@ -85,7 +60,7 @@ library ERC20ForwarderInput {
8560
/// @return permit The permit data constituted by the token address, token amount, nonce, and deadline.
8661
/// @return witness The witness information.
8762
/// @return signature The signature over the `PermitWitnessTransferFrom` message.
88-
function decodePermitWitnessTransferFrom(bytes calldata input)
63+
function decodeWrap(bytes calldata input)
8964
public
9065
pure
9166
returns (

contracts/test/ERC20Forwarder.t.sol

Lines changed: 27 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// SPDX-License-Identifier: MIT
22
pragma solidity ^0.8.30;
33

4-
import {IERC20Errors} from "@openzeppelin-contracts/interfaces/draft-IERC6093.sol";
54
import {ERC20} from "@openzeppelin-contracts/token/ERC20/ERC20.sol";
65
import {Time} from "@openzeppelin-contracts/utils/types/Time.sol";
76
import {IPermit2, ISignatureTransfer} from "@permit2/src/interfaces/IPermit2.sol";
@@ -95,13 +94,13 @@ contract ERC20ForwarderTest is Test {
9594
}
9695
}
9796

98-
function test_forwardCall_Transfer_call_sends_funds_to_the_user() public {
97+
function test_forwardCall_Unwrap_call_sends_funds_to_the_user() public {
9998
_erc20.mint({to: _fwd, value: _TRANSFER_AMOUNT});
10099
uint256 startBalanceAlice = _erc20.balanceOf(_alice);
101100
uint256 startBalanceForwarder = _erc20.balanceOf(_fwd);
102101

103102
bytes memory input =
104-
ERC20ForwarderInput.encodeTransfer({token: address(_erc20), to: _alice, value: _TRANSFER_AMOUNT});
103+
ERC20ForwarderInput.encodeUnwrap({token: address(_erc20), to: _alice, value: _TRANSFER_AMOUNT});
105104

106105
vm.prank(_pa);
107106
bytes memory output = ERC20Forwarder(_fwd).forwardCall({logicRef: _CALLDATA_CARRIER_LOGIC_REF, input: input});
@@ -111,76 +110,25 @@ contract ERC20ForwarderTest is Test {
111110
assertEq(_erc20.balanceOf(_fwd), startBalanceForwarder - _TRANSFER_AMOUNT);
112111
}
113112

114-
function test_forwardCall_Transfer_call_emits_the_Unwrapped_event() public {
113+
function test_forwardCall_Unwrap_call_emits_the_Unwrapped_event() public {
115114
_erc20.mint({to: _fwd, value: _TRANSFER_AMOUNT});
116115
bytes memory input =
117-
ERC20ForwarderInput.encodeTransfer({token: address(_erc20), to: _alice, value: _TRANSFER_AMOUNT});
116+
ERC20ForwarderInput.encodeUnwrap({token: address(_erc20), to: _alice, value: _TRANSFER_AMOUNT});
118117

119118
vm.prank(_pa);
120119
vm.expectEmit(address(_fwd));
121120
emit ERC20Forwarder.Unwrapped({token: address(_erc20), to: _alice, value: _TRANSFER_AMOUNT});
122121
ERC20Forwarder(_fwd).forwardCall({logicRef: _CALLDATA_CARRIER_LOGIC_REF, input: input});
123122
}
124123

125-
function test_forwardCall_TransferFrom_call_reverts_if_user_did_not_approve_the_forwarder() public {
124+
function test_forwardCall_Wrap_call_reverts_if_user_did_not_approve_permit2() public {
126125
_erc20.mint({to: _alice, value: _TRANSFER_AMOUNT});
127126

128-
bytes memory input =
129-
ERC20ForwarderInput.encodeTransferFrom({token: address(_erc20), from: _alice, value: _TRANSFER_AMOUNT});
130-
131-
uint256 allowance = _erc20.allowance({owner: _alice, spender: _fwd});
132-
133-
vm.prank(_pa);
134-
vm.expectRevert(
135-
abi.encodeWithSelector(
136-
IERC20Errors.ERC20InsufficientAllowance.selector, address(_fwd), allowance, _TRANSFER_AMOUNT
137-
),
138-
address(_erc20)
139-
);
140-
ERC20Forwarder(_fwd).forwardCall({logicRef: _CALLDATA_CARRIER_LOGIC_REF, input: input});
141-
}
142-
143-
function test_forwardCall_TransferFrom_call_pulls_funds_from_user() public {
144-
_erc20.mint({to: _alice, value: _TRANSFER_AMOUNT});
145-
uint256 startBalanceAlice = _erc20.balanceOf(_alice);
146-
uint256 startBalanceForwarder = _erc20.balanceOf(_fwd);
147-
148-
vm.prank(_alice);
149-
_erc20.approve(_fwd, type(uint256).max);
150-
151-
bytes memory input =
152-
ERC20ForwarderInput.encodeTransferFrom({token: address(_erc20), from: _alice, value: _TRANSFER_AMOUNT});
153-
154-
vm.prank(_pa);
155-
bytes memory output = ERC20Forwarder(_fwd).forwardCall({logicRef: _CALLDATA_CARRIER_LOGIC_REF, input: input});
156-
157-
assertEq(keccak256(output), keccak256(_EXPECTED_OUTPUT));
158-
assertEq(_erc20.balanceOf(_alice), startBalanceAlice - _TRANSFER_AMOUNT);
159-
assertEq(_erc20.balanceOf(_fwd), startBalanceForwarder + _TRANSFER_AMOUNT);
160-
}
161-
162-
function test_forwardCall_TransferFrom_call_emits_the_Wrapped_event() public {
163-
_erc20.mint({to: _alice, value: _TRANSFER_AMOUNT});
164-
vm.prank(_alice);
165-
_erc20.approve(_fwd, type(uint256).max);
166-
167-
bytes memory input =
168-
ERC20ForwarderInput.encodeTransferFrom({token: address(_erc20), from: _alice, value: _TRANSFER_AMOUNT});
169-
170-
vm.prank(_pa);
171-
vm.expectEmit(address(_fwd));
172-
emit ERC20Forwarder.Wrapped({token: address(_erc20), from: _alice, value: _TRANSFER_AMOUNT});
173-
ERC20Forwarder(_fwd).forwardCall({logicRef: _CALLDATA_CARRIER_LOGIC_REF, input: input});
174-
}
175-
176-
function test_forwardCall_PermitTransferFrom_call_reverts_if_user_did_not_approve_permit2() public {
177-
_erc20.mint({to: _alice, value: _TRANSFER_AMOUNT});
178-
179-
bytes memory input = ERC20ForwarderInput.encodePermitWitnessTransferFrom({
127+
bytes memory input = ERC20ForwarderInput.encodeWrap({
180128
from: _alice,
181129
permit: _defaultPermit,
182130
witness: _ACTION_TREE_ROOT,
183-
signature: _createPermitWitnessTransferFromSignature({
131+
signature: _createWrapSignature({
184132
permit: _defaultPermit,
185133
privateKey: _ALICE_PRIVATE_KEY,
186134
spender: _fwd,
@@ -193,16 +141,16 @@ contract ERC20ForwarderTest is Test {
193141
ERC20Forwarder(_fwd).forwardCall({logicRef: _CALLDATA_CARRIER_LOGIC_REF, input: input});
194142
}
195143

196-
function test_forwardCall_PermitTransferFrom_call_reverts_if_the_signature_expired() public {
144+
function test_forwardCall_Wrap_call_reverts_if_the_signature_expired() public {
197145
_erc20.mint({to: _alice, value: _TRANSFER_AMOUNT});
198146
vm.prank(_alice);
199147
_erc20.approve(address(_permit2), type(uint256).max);
200148

201-
bytes memory input = ERC20ForwarderInput.encodePermitWitnessTransferFrom({
149+
bytes memory input = ERC20ForwarderInput.encodeWrap({
202150
from: _alice,
203151
permit: _defaultPermit,
204152
witness: _ACTION_TREE_ROOT,
205-
signature: _createPermitWitnessTransferFromSignature({
153+
signature: _createWrapSignature({
206154
permit: _defaultPermit,
207155
privateKey: _ALICE_PRIVATE_KEY,
208156
spender: _fwd,
@@ -218,16 +166,16 @@ contract ERC20ForwarderTest is Test {
218166
ERC20Forwarder(_fwd).forwardCall({logicRef: _CALLDATA_CARRIER_LOGIC_REF, input: input});
219167
}
220168

221-
function test_forwardCall_PermitTransferFrom_call_reverts_if_the_signature_was_already_used() public {
169+
function test_forwardCall_Wrap_call_reverts_if_the_signature_was_already_used() public {
222170
_erc20.mint({to: _alice, value: 2 * _TRANSFER_AMOUNT});
223171
vm.prank(_alice);
224172
_erc20.approve(address(_permit2), type(uint256).max);
225173

226-
bytes memory input = ERC20ForwarderInput.encodePermitWitnessTransferFrom({
174+
bytes memory input = ERC20ForwarderInput.encodeWrap({
227175
from: _alice,
228176
permit: _defaultPermit,
229177
witness: _ACTION_TREE_ROOT,
230-
signature: _createPermitWitnessTransferFromSignature({
178+
signature: _createWrapSignature({
231179
permit: _defaultPermit,
232180
privateKey: _ALICE_PRIVATE_KEY,
233181
spender: _fwd,
@@ -244,7 +192,7 @@ contract ERC20ForwarderTest is Test {
244192
ERC20Forwarder(_fwd).forwardCall({logicRef: _CALLDATA_CARRIER_LOGIC_REF, input: input});
245193
}
246194

247-
function test_forwardCall_PermitWitnessTransferFrom_call_reverts_if_the_amount_to_be_wrapped_overflows() public {
195+
function test_forwardCall_Wrap_call_reverts_if_the_amount_to_be_wrapped_overflows() public {
248196
uint256 maxAmount = type(uint128).max;
249197

250198
_erc20.mint({to: _alice, value: maxAmount + 1});
@@ -257,11 +205,11 @@ contract ERC20ForwarderTest is Test {
257205
deadline: Time.timestamp() + 5 minutes
258206
});
259207

260-
bytes memory input = ERC20ForwarderInput.encodePermitWitnessTransferFrom({
208+
bytes memory input = ERC20ForwarderInput.encodeWrap({
261209
from: _alice,
262210
permit: permit,
263211
witness: _ACTION_TREE_ROOT,
264-
signature: _createPermitWitnessTransferFromSignature({
212+
signature: _createWrapSignature({
265213
permit: permit,
266214
privateKey: _ALICE_PRIVATE_KEY,
267215
spender: _fwd,
@@ -284,11 +232,11 @@ contract ERC20ForwarderTest is Test {
284232
vm.prank(_alice);
285233
_erc20.approve(address(_permit2), type(uint256).max);
286234

287-
bytes memory input = ERC20ForwarderInput.encodePermitWitnessTransferFrom({
235+
bytes memory input = ERC20ForwarderInput.encodeWrap({
288236
from: _alice,
289237
permit: _defaultPermit,
290238
witness: _ACTION_TREE_ROOT,
291-
signature: _createPermitWitnessTransferFromSignature({
239+
signature: _createWrapSignature({
292240
permit: _defaultPermit,
293241
privateKey: _ALICE_PRIVATE_KEY,
294242
spender: _fwd,
@@ -310,11 +258,11 @@ contract ERC20ForwarderTest is Test {
310258
vm.prank(_alice);
311259
_erc20.approve(address(_permit2), type(uint256).max);
312260

313-
bytes memory input = ERC20ForwarderInput.encodePermitWitnessTransferFrom({
261+
bytes memory input = ERC20ForwarderInput.encodeWrap({
314262
from: _alice,
315263
permit: _defaultPermit,
316264
witness: _ACTION_TREE_ROOT,
317-
signature: _createPermitWitnessTransferFromSignature({
265+
signature: _createWrapSignature({
318266
permit: _defaultPermit,
319267
privateKey: _ALICE_PRIVATE_KEY,
320268
spender: _fwd,
@@ -328,13 +276,13 @@ contract ERC20ForwarderTest is Test {
328276
ERC20Forwarder(_fwd).forwardCall({logicRef: _CALLDATA_CARRIER_LOGIC_REF, input: input});
329277
}
330278

331-
function _createPermitWitnessTransferFromSignature(
279+
function _createWrapSignature(
332280
ISignatureTransfer.PermitTransferFrom memory permit,
333281
address spender,
334282
uint256 privateKey,
335283
bytes32 witness
336284
) internal view returns (bytes memory signature) {
337-
bytes32 digest = _computePermitWitnessTransferFromDigest({permit: permit, spender: spender, witness: witness});
285+
bytes32 digest = _computeWrapDigest({permit: permit, spender: spender, witness: witness});
338286

339287
(uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, digest);
340288
return abi.encodePacked(r, s, v);
@@ -345,11 +293,11 @@ contract ERC20ForwarderTest is Test {
345293
/// @param spender The address being allowed to execute the `permitWitnessTransferFrom` call.
346294
/// @param witness The witness information.
347295
/// @return digest The digest.
348-
function _computePermitWitnessTransferFromDigest(
349-
ISignatureTransfer.PermitTransferFrom memory permit,
350-
address spender,
351-
bytes32 witness
352-
) internal view returns (bytes32 digest) {
296+
function _computeWrapDigest(ISignatureTransfer.PermitTransferFrom memory permit, address spender, bytes32 witness)
297+
internal
298+
view
299+
returns (bytes32 digest)
300+
{
353301
string memory witnessTypeString = "bytes32 witness";
354302

355303
bytes32 structHash = keccak256(

0 commit comments

Comments
 (0)