generated from Kwenta/foundry-scaffold
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
e7cbbb0
commit d5704c0
Showing
1 changed file
with
163 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
diff --git a/src/SMv2SessionValidationModule.sol b/src/SMv2SessionValidationModule.sol | ||
index f8d6e03..916aabc 100644 | ||
--- a/src/SMv2SessionValidationModule.sol | ||
+++ b/src/SMv2SessionValidationModule.sol | ||
@@ -1,11 +1,9 @@ | ||
-// SPDX-License-Identifier: GPL-3.0-or-later | ||
-pragma solidity 0.8.18; | ||
+// SPDX-License-Identifier: MIT | ||
+pragma solidity ^0.8.17; | ||
|
||
-import { | ||
- ISessionValidationModule, | ||
- UserOperation | ||
-} from "src/biconomy/interfaces/ISessionValidationModule.sol"; | ||
-import {ECDSA} from "src/openzeppelin/ECDSA.sol"; | ||
+import {ISessionValidationModule, UserOperation} from | ||
+ "src/interfaces/ISessionValidationModule.sol"; | ||
+// import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; | ||
|
||
/** | ||
* @title Kwenta Smart Margin v2 Session Validation Module for Biconomy Smart Accounts. | ||
@@ -13,12 +11,8 @@ import {ECDSA} from "src/openzeppelin/ECDSA.sol"; | ||
* @author Fil Makarov - <[email protected]> | ||
* @author JaredBorders ([email protected]) | ||
*/ | ||
-contract SMv2SessionValidationModule is ISessionValidationModule { | ||
- error InvalidSelector(); | ||
- error InvalidSMv2Selector(); | ||
- error InvalidDestinationContract(); | ||
- error InvalidCallValue(); | ||
|
||
+contract SMv2SessionValidationModule is ISessionValidationModule { | ||
/** | ||
* @dev validates that the call (destinationContract, callValue, funcCallData) | ||
* complies with the Session Key permissions represented by sessionKeyData | ||
@@ -36,32 +30,19 @@ contract SMv2SessionValidationModule is ISessionValidationModule { | ||
) external virtual override returns (address) { | ||
( | ||
address sessionKey, | ||
- address smv2ProxyAccount, | ||
- bytes4 smv2ExecuteSelector | ||
- ) = abi.decode(_sessionKeyData, (address, address, bytes4)); | ||
- | ||
- /// @dev ensure destinationContract is the SMv2ProxyAccount | ||
- if (destinationContract != smv2ProxyAccount) { | ||
- revert InvalidDestinationContract(); | ||
- } | ||
- | ||
- /// @dev ensure the function selector is the `SmartAccount.execute` selector | ||
- if (bytes4(_funcCallData[0:4]) != smv2ExecuteSelector) { | ||
- revert InvalidSMv2Selector(); | ||
- } | ||
- | ||
- /// @dev ensure call value is zero | ||
- if (callValue != 0) { | ||
- revert InvalidCallValue(); | ||
- } | ||
+ address token, | ||
+ address recipient, | ||
+ uint256 maxAmount | ||
+ ) = abi.decode(_sessionKeyData, (address, address, address, uint256)); | ||
|
||
- // (IAccount.Command[] memory _commands, bytes[] memory _inputs) = abi.decode( | ||
- // _funcCallData[4:], | ||
- // (IAccount.Command[], bytes[]) | ||
- // ); | ||
+ require(destinationContract == token, "ERC20SV Invalid Token"); | ||
+ require(callValue == 0, "ERC20SV Non Zero Value"); | ||
|
||
- /// @custom:add-param-validation-here-if-needed | ||
+ (address recipientCalled, uint256 amount) = | ||
+ abi.decode(_funcCallData[4:], (address, uint256)); | ||
|
||
+ require(recipient == recipientCalled, "ERC20SV Wrong Recipient"); | ||
+ require(amount <= maxAmount, "ERC20SV Max Amount Exceeded"); | ||
return sessionKey; | ||
} | ||
|
||
@@ -81,58 +62,53 @@ contract SMv2SessionValidationModule is ISessionValidationModule { | ||
bytes calldata _sessionKeyData, | ||
bytes calldata _sessionKeySignature | ||
) external pure override returns (bool) { | ||
- /// @dev ensure function selector is `IAccount.execute` | ||
- if ( | ||
- bytes4(_op.callData[0:4]) != EXECUTE_SELECTOR | ||
- && bytes4(_op.callData[0:4]) != EXECUTE_OPTIMIZED_SELECTOR | ||
- ) { | ||
- revert InvalidSelector(); | ||
- } | ||
+ require( | ||
+ bytes4(_op.callData[0:4]) == EXECUTE_OPTIMIZED_SELECTOR | ||
+ || bytes4(_op.callData[0:4]) == EXECUTE_SELECTOR, | ||
+ "ERC20SV Invalid Selector" | ||
+ ); | ||
|
||
( | ||
address sessionKey, | ||
- address smv2ProxyAccount, | ||
- bytes4 smv2ExecuteSelector | ||
- ) = abi.decode(_sessionKeyData, (address, address, bytes4)); | ||
+ address token, | ||
+ address recipient, | ||
+ uint256 maxAmount | ||
+ ) = abi.decode(_sessionKeyData, (address, address, address, uint256)); | ||
|
||
{ | ||
// we expect _op.callData to be `SmartAccount.execute(to, value, calldata)` calldata | ||
- (address destinationContract, uint256 callValue,) = abi.decode( | ||
+ (address tokenAddr, uint256 callValue,) = abi.decode( | ||
_op.callData[4:], // skip selector | ||
(address, uint256, bytes) | ||
); | ||
- | ||
- /// @dev ensure destinationContract is the SMv2ProxyAccount | ||
- if (destinationContract != smv2ProxyAccount) { | ||
- revert InvalidDestinationContract(); | ||
+ if (tokenAddr != token) { | ||
+ revert("ERC20SV Wrong Token"); | ||
} | ||
- | ||
- /// @dev ensure call value is zero | ||
if (callValue != 0) { | ||
- revert InvalidCallValue(); | ||
+ revert("ERC20SV Non Zero Value"); | ||
} | ||
} | ||
- | ||
// working with userOp.callData | ||
- // check if the call is conforms to `IAccount.execute` | ||
+ // check if the call is to the allowed recepient and amount is not more than allowed | ||
bytes calldata data; | ||
{ | ||
uint256 offset = uint256(bytes32(_op.callData[4 + 64:4 + 96])); | ||
uint256 length = | ||
uint256(bytes32(_op.callData[4 + offset:4 + offset + 32])); | ||
- // we expect data to be the `IAccount.execute(Command[] _commands, bytes[] _inputs)` calldata | ||
+ //we expect data to be the `IERC20.transfer(address, uint256)` calldata | ||
data = _op.callData[4 + offset + 32:4 + offset + 32 + length]; | ||
} | ||
- | ||
- /// @dev ensure the function selector is the smv2ExecuteSelector selector | ||
- if (bytes4(data[0:4]) != smv2ExecuteSelector) { | ||
- revert InvalidSMv2Selector(); | ||
+ if (address(bytes20(data[16:36])) != recipient) { | ||
+ revert("ERC20SV Wrong Recipient"); | ||
} | ||
- | ||
- /// @dev this method of signature validation is out-of-date | ||
- /// see https://github.com/OpenZeppelin/openzeppelin-sdk/blob/7d96de7248ae2e7e81a743513ccc617a2e6bba21/packages/lib/contracts/cryptography/ECDSA.sol#L6 | ||
- return ECDSA.recover( | ||
- ECDSA.toEthSignedMessageHash(_userOpHash), _sessionKeySignature | ||
- ) == sessionKey; | ||
+ if (uint256(bytes32(data[36:68])) > maxAmount) { | ||
+ revert("ERC20SV Max Amount Exceeded"); | ||
+ } | ||
+ return | ||
+ // ECDSA.recover( | ||
+ // ECDSA.toEthSignedMessageHash(_userOpHash), | ||
+ // _sessionKeySignature | ||
+ // ) == sessionKey; | ||
+ true; | ||
} | ||
} |