Skip to content

Commit 9951206

Browse files
committed
chore: value zero validation on non value enforcers
1 parent e8d8457 commit 9951206

10 files changed

Lines changed: 87 additions & 6 deletions

src/enforcers/ERC20PeriodTransferEnforcer.sol

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,8 +178,9 @@ contract ERC20PeriodTransferEnforcer is CaveatEnforcer {
178178
)
179179
private
180180
{
181-
(address target_,, bytes calldata callData_) = _executionCallData.decodeSingle();
181+
(address target_, uint256 value_, bytes calldata callData_) = _executionCallData.decodeSingle();
182182

183+
require(value_ == 0, "ERC20PeriodTransferEnforcer:invalid-value");
183184
require(callData_.length == 68, "ERC20PeriodTransferEnforcer:invalid-execution-length");
184185

185186
(address token_, uint256 periodAmount_, uint256 periodDuration_, uint256 startDate_) = getTermsInfo(_terms);

src/enforcers/ERC20StreamingEnforcer.sol

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,9 @@ contract ERC20StreamingEnforcer is CaveatEnforcer {
155155
)
156156
private
157157
{
158-
(address target_,, bytes calldata callData_) = _executionCallData.decodeSingle();
158+
(address target_, uint256 value_, bytes calldata callData_) = _executionCallData.decodeSingle();
159159

160+
require(value_ == 0, "ERC20StreamingEnforcer:invalid-value");
160161
require(callData_.length == 68, "ERC20StreamingEnforcer:invalid-execution-length");
161162

162163
(address token_, uint256 initialAmount_, uint256 maxAmount_, uint256 amountPerSecond_, uint256 startTime_) =

src/enforcers/ERC20TransferAmountEnforcer.sol

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,9 @@ contract ERC20TransferAmountEnforcer is CaveatEnforcer {
8282
internal
8383
returns (uint256 limit_, uint256 spent_)
8484
{
85-
(address target_,, bytes calldata callData_) = _executionCallData.decodeSingle();
85+
(address target_, uint256 value_, bytes calldata callData_) = _executionCallData.decodeSingle();
8686

87+
require(value_ == 0, "ERC20TransferAmountEnforcer:invalid-value");
8788
require(callData_.length == 68, "ERC20TransferAmountEnforcer:invalid-execution-length");
8889

8990
address allowedContract_;

src/enforcers/ERC721TransferEnforcer.sol

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ contract ERC721TransferEnforcer is CaveatEnforcer {
3737
onlyDefaultExecutionMode(_mode)
3838
{
3939
(address permittedContract_, uint256 permittedTokenId_) = getTermsInfo(_terms);
40-
(address target_,, bytes calldata callData_) = ExecutionLib.decodeSingle(_executionCallData);
40+
(address target_, uint256 value_, bytes calldata callData_) = ExecutionLib.decodeSingle(_executionCallData);
41+
require(value_ == 0, "ERC721TransferEnforcer:invalid-value");
4142

4243
// Decode the remaining callData into NFT transfer parameters
4344
// The calldata should be at least 100 bytes (4 bytes for the selector + 96 bytes for the parameters)

src/enforcers/OwnershipTransferEnforcer.sol

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,9 @@ contract OwnershipTransferEnforcer is CaveatEnforcer {
7272
pure
7373
returns (address newOwner_)
7474
{
75-
(address target_,, bytes calldata callData_) = _executionCallData.decodeSingle();
75+
(address target_, uint256 value_, bytes calldata callData_) = _executionCallData.decodeSingle();
7676

77+
require(value_ == 0, "OwnershipTransferEnforcer:invalid-value");
7778
require(callData_.length == 36, "OwnershipTransferEnforcer:invalid-execution-length");
7879

7980
bytes4 selector_ = bytes4(callData_[0:4]);

test/enforcers/ERC20PeriodTransferEnforcer.t.sol

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,15 @@ contract ERC20PeriodTransferEnforcerTest is CaveatEnforcerBaseTest {
215215
assertEq(availableAfter2, periodAmount - 600);
216216
}
217217

218+
/// @notice Reverts if the execution value is not zero.
219+
function test_invalidValue() public {
220+
bytes memory terms_ = abi.encodePacked(address(basicERC20), periodAmount, periodDuration, startDate);
221+
bytes memory callData_ = _encodeERC20Transfer(bob, 100);
222+
bytes memory execData_ = _encodeSingleExecution(address(basicERC20), 1 ether, callData_);
223+
vm.expectRevert("ERC20PeriodTransferEnforcer:invalid-value");
224+
erc20PeriodTransferEnforcer.beforeHook(terms_, "", singleDefaultMode, execData_, dummyDelegationHash, address(0), redeemer);
225+
}
226+
218227
// should fail with invalid call type mode (batch instead of single mode)
219228
function test_revertWithInvalidCallTypeMode() public {
220229
bytes memory executionCallData_ = ExecutionLib.encodeBatch(new Execution[](2));

test/enforcers/ERC20StreamingEnforcer.t.sol

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,19 @@ contract ERC20StreamingEnforcerTest is CaveatEnforcerBaseTest {
172172
erc20StreamingEnforcer.beforeHook(terms_, bytes(""), singleDefaultMode, execData_, bytes32(0), address(0), alice);
173173
}
174174

175+
/// @notice Reverts if the execution value is not zero.
176+
function test_invalidValue() public {
177+
uint256 initialAmount_ = 100 ether;
178+
uint256 maxAmount_ = 100 ether;
179+
uint256 amountPerSecond_ = 1 ether;
180+
uint256 startTime_ = block.timestamp;
181+
bytes memory terms_ = abi.encodePacked(address(basicERC20), initialAmount_, maxAmount_, amountPerSecond_, startTime_);
182+
bytes memory callData_ = _encodeERC20Transfer(bob, 100);
183+
bytes memory execData_ = _encodeSingleExecution(address(basicERC20), 1 ether, callData_);
184+
vm.expectRevert("ERC20StreamingEnforcer:invalid-value");
185+
erc20StreamingEnforcer.beforeHook(terms_, "", singleDefaultMode, execData_, bytes32(0), address(0), alice);
186+
}
187+
175188
//////////////////// Valid cases //////////////////////
176189
/**
177190
* @notice Test getTermsInfo() on correct 148-byte terms
@@ -418,7 +431,7 @@ contract ERC20StreamingEnforcerTest is CaveatEnforcerBaseTest {
418431
/**
419432
* @notice Integration test: Successful native token streaming via delegation.
420433
* A delegation is created that uses the erc20StreamingEnforcer. Two native token transfers
421-
* (user ops) are executed sequentially. The test verifies that the enforcers state is updated
434+
* (user ops) are executed sequentially. The test verifies that the enforcer's state is updated
422435
* correctly and that the available amount decreases as expected.
423436
*/
424437
function test_nativeTokenStreamingIntegration_Success() public {

test/enforcers/ERC20TransferAmountEnforcer.t.sol

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,34 @@ contract ERC20TransferAmountEnforcerTest is CaveatEnforcerBaseTest {
446446
function _getEnforcer() internal view override returns (ICaveatEnforcer) {
447447
return ICaveatEnforcer(address(erc20TransferAmountEnforcer));
448448
}
449+
450+
/// @notice Reverts if the execution value is not zero.
451+
function test_invalidValue() public {
452+
uint256 spendingLimit_ = 1 ether;
453+
Execution memory execution_ = Execution({
454+
target: address(basicERC20),
455+
value: 1 ether,
456+
callData: abi.encodeWithSelector(IERC20.transfer.selector, address(users.bob.deleGator), spendingLimit_)
457+
});
458+
bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData);
459+
bytes memory inputTerms_ = abi.encodePacked(address(basicERC20), spendingLimit_);
460+
Caveat[] memory caveats_ = new Caveat[](1);
461+
caveats_[0] = Caveat({ args: hex"", enforcer: address(erc20TransferAmountEnforcer), terms: inputTerms_ });
462+
Delegation memory delegation_ = Delegation({
463+
delegate: address(users.bob.deleGator),
464+
delegator: address(users.alice.deleGator),
465+
authority: ROOT_AUTHORITY,
466+
caveats: caveats_,
467+
salt: 0,
468+
signature: hex""
469+
});
470+
bytes32 delegationHash_ = EncoderLib._getDelegationHash(delegation_);
471+
vm.prank(address(delegationManager));
472+
vm.expectRevert("ERC20TransferAmountEnforcer:invalid-value");
473+
erc20TransferAmountEnforcer.beforeHook(
474+
inputTerms_, hex"", singleDefaultMode, executionCallData_, delegationHash_, address(0), address(0)
475+
);
476+
}
449477
}
450478

451479
/// @notice A mock token that allows us to simulate failed transfers.

test/enforcers/ERC721TransferEnforcer.t.sol

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,15 @@ contract ERC721TransferEnforcerTest is CaveatEnforcerBaseTest {
209209
erc721TransferEnforcer.beforeHook(hex"", hex"", singleTryMode, hex"", bytes32(0), address(0), address(0));
210210
}
211211

212+
/// @notice Reverts if the execution value is not zero.
213+
function test_invalidValue() public {
214+
bytes memory terms_ = abi.encodePacked(address(token), TOKEN_ID);
215+
bytes memory callData_ = abi.encodeWithSelector(IERC721.transferFrom.selector, address(this), address(0xBEEF), TOKEN_ID);
216+
bytes memory execData_ = ExecutionLib.encodeSingle(address(token), 1 ether, callData_);
217+
vm.expectRevert("ERC721TransferEnforcer:invalid-value");
218+
erc721TransferEnforcer.beforeHook(terms_, "", singleDefaultMode, execData_, keccak256(""), address(0), address(0));
219+
}
220+
212221
////////////////////// Integration //////////////////////
213222

214223
/// @notice Integration test for valid transfer using transferFrom selector.

test/enforcers/OwnershipTransferEnforcer.t.sol

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,23 @@ contract OwnershipTransferEnforcerTest is CaveatEnforcerBaseTest {
138138
enforcer.beforeHook(hex"", hex"", singleTryMode, hex"", bytes32(0), address(0), address(0));
139139
}
140140

141+
/// @notice Reverts if the execution value is not zero.
142+
function test_invalidValue() public {
143+
bytes memory terms_ = abi.encodePacked(mockContract);
144+
transferOwnershipExecution = Execution({
145+
target: mockContract,
146+
value: 1 ether,
147+
callData: abi.encodeWithSelector(bytes4(keccak256("transferOwnership(address)")), delegate)
148+
});
149+
transferOwnershipExecutionCallData = ExecutionLib.encodeSingle(
150+
transferOwnershipExecution.target, transferOwnershipExecution.value, transferOwnershipExecution.callData
151+
);
152+
153+
vm.prank(dm);
154+
vm.expectRevert("OwnershipTransferEnforcer:invalid-value");
155+
enforcer.beforeHook(terms_, hex"", singleDefaultMode, transferOwnershipExecutionCallData, bytes32(0), delegator, delegate);
156+
}
157+
141158
function _getEnforcer() internal view override returns (ICaveatEnforcer) {
142159
return ICaveatEnforcer(address(enforcer));
143160
}

0 commit comments

Comments
 (0)