Skip to content

Commit

Permalink
Fix permit approval check in deposit functions
Browse files Browse the repository at this point in the history
  • Loading branch information
vgorkavenko committed Nov 8, 2023
1 parent 6622db3 commit d12dc9e
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 20 deletions.
45 changes: 25 additions & 20 deletions src/CSAccounting.sol
Original file line number Diff line number Diff line change
Expand Up @@ -470,16 +470,18 @@ contract CSAccounting is CSAccountingBase, AccessControlEnumerable {
PermitInput calldata permit
) external onlyExistingNodeOperator(nodeOperatorId) returns (uint256) {
from = (from == address(0)) ? msg.sender : from;
// solhint-disable-next-line func-named-parameters
_lido().permit(
from,
address(this),
permit.value,
permit.deadline,
permit.v,
permit.r,
permit.s
);
if (_lido().allowance(from, address(this)) < permit.value) {
// solhint-disable-next-line func-named-parameters
_lido().permit(
from,
address(this),
permit.value,
permit.deadline,
permit.v,
permit.r,
permit.s
);
}
return _depositStETH(from, nodeOperatorId, stETHAmount);
}

Expand Down Expand Up @@ -520,16 +522,19 @@ contract CSAccounting is CSAccountingBase, AccessControlEnumerable {
uint256 wstETHAmount,
PermitInput calldata permit
) external onlyExistingNodeOperator(nodeOperatorId) returns (uint256) {
// solhint-disable-next-line func-named-parameters
WSTETH.permit(
from,
address(this),
permit.value,
permit.deadline,
permit.v,
permit.r,
permit.s
);
from = (from == address(0)) ? msg.sender : from;
if (WSTETH.allowance(from, address(this)) < permit.value) {
// solhint-disable-next-line func-named-parameters
WSTETH.permit(
from,
address(this),
permit.value,
permit.deadline,
permit.v,
permit.r,
permit.s
);
}
return _depositWstETH(from, nodeOperatorId, wstETHAmount);
}

Expand Down
5 changes: 5 additions & 0 deletions src/interfaces/IStETH.sol
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,9 @@ interface IStETH {
bytes32 r,
bytes32 s
) external;

function allowance(
address _owner,
address _spender
) external view returns (uint256);
}
5 changes: 5 additions & 0 deletions src/interfaces/IWstETH.sol
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,9 @@ interface IWstETH {
bytes32 r,
bytes32 s
) external;

function allowance(
address _owner,
address _spender
) external view returns (uint256);
}
88 changes: 88 additions & 0 deletions test/CSAccounting.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,49 @@ contract CSAccountingTest is
);
}

function test_depositStETHWithPermit_alreadyPermitted() public {
_createNodeOperator({ ongoingVals: 16, withdrawnVals: 0 });
vm.deal(user, 32 ether);
vm.prank(user);
stETH.submit{ value: 32 ether }({ _referal: address(0) });

vm.expectEmit(true, true, true, true, address(accounting));
emit StETHBondDeposited(0, user, 32 ether);

vm.mockCall(
address(stETH),
abi.encodeWithSelector(
stETH.permit.selector,
user,
address(accounting)
),
abi.encode(32 ether)
);

vm.recordLogs();

vm.prank(stranger);
accounting.depositStETHWithPermit(
user,
0,
32 ether,
CSAccounting.PermitInput({
value: 32 ether,
deadline: type(uint256).max,
// mock permit signature
v: 0,
r: 0,
s: 0
})
);

assertEq(
vm.getRecordedLogs().length,
1,
"should emit only one event about deposit"
);
}

function test_depositWstETHWithPermit() public {
_createNodeOperator({ ongoingVals: 16, withdrawnVals: 0 });
vm.deal(user, 32 ether);
Expand Down Expand Up @@ -461,6 +504,51 @@ contract CSAccountingTest is
);
}

function test_depositWstETHWithPermit_alreadyPermitted() public {
_createNodeOperator({ ongoingVals: 16, withdrawnVals: 0 });
vm.deal(user, 32 ether);
vm.startPrank(user);
stETH.submit{ value: 32 ether }({ _referal: address(0) });
uint256 wstETHAmount = wstETH.wrap(32 ether);
vm.stopPrank();

vm.expectEmit(true, true, true, true, address(accounting));
emit WstETHBondDeposited(0, user, wstETHAmount);

vm.mockCall(
address(wstETH),
abi.encodeWithSelector(
wstETH.permit.selector,
user,
address(accounting)
),
abi.encode(32 ether)
);

vm.recordLogs();

vm.prank(stranger);
accounting.depositWstETHWithPermit(
user,
0,
wstETHAmount,
CSAccounting.PermitInput({
value: 32 ether,
deadline: type(uint256).max,
// mock permit signature
v: 0,
r: 0,
s: 0
})
);

assertEq(
vm.getRecordedLogs().length,
1,
"should emit only one event about deposit"
);
}

function test_deposit_RevertIfNotExistedOperator() public {
vm.expectRevert("node operator does not exist");
accounting.depositStETH(user, 0, 32 ether);
Expand Down
7 changes: 7 additions & 0 deletions test/helpers/Permit.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ contract PermitTokenBase {
) external {
emit Approval(owner, spender, value);
}

function allowance(
address owner,
address spender
) external view returns (uint256) {
return 0;
}
}

// https://eips.ethereum.org/EIPS/eip-2612
Expand Down

0 comments on commit d12dc9e

Please sign in to comment.