Files
eoa-contracts/contracts/smart-account/test/vulnerable/VulnerableERC20SessionValidationModule.sol

87 lines
3.2 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import "../../modules/SessionValidationModules/ISessionValidationModule.sol";
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
/**
* @title ERC20 Session Validation Module for Biconomy Smart Accounts.
* @dev Validates userOps for ERC20 transfers and approvals using a session key signature.
* - Recommended to use with standard ERC20 tokens only
* - Can be used with any method of any contract which implement
* method(address, uint256) interface
*
* @author Fil Makarov - <[email protected]>
*/
contract VulnerableERC20SessionValidationModule is ISessionValidationModule {
/**
* @dev validates if the _op (UserOperation) matches the SessionKey permissions
* and that _op has been signed by this SessionKey
* @param _op User Operation to be validated.
* @param _userOpHash Hash of the User Operation to be validated.
* @param _sessionKeyData SessionKey data, that describes sessionKey permissions
* @param _sessionKeySignature Signature over the the _userOpHash.
* @return true if the _op is valid, false otherwise.
*/
function validateSessionUserOp(
UserOperation calldata _op,
bytes32 _userOpHash,
bytes calldata _sessionKeyData,
bytes calldata _sessionKeySignature
) external pure override returns (bool) {
(
address sessionKey,
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 tokenAddr, uint256 callValue, ) = abi.decode(
_op.callData[4:], // skip selector
(address, uint256, bytes)
);
if (tokenAddr != token) {
revert("ERC20SV Wrong Token");
}
if (callValue != 0) {
revert("ERC20SV Non Zero Value");
}
}
// working with userOp.callData
// 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 `IERC20.transfer(address, uint256)` calldata
data = _op.callData[4 + offset + 32:4 + offset + 32 + length];
}
if (address(bytes20(data[16:36])) != recipient) {
revert("ERC20SV Wrong Recipient");
}
if (uint256(bytes32(data[36:68])) > maxAmount) {
revert("ERC20SV Max Amount Exceeded");
}
return
ECDSA.recover(
ECDSA.toEthSignedMessageHash(_userOpHash),
_sessionKeySignature
) == sessionKey;
}
function validateSessionParams(
address,
uint256 callValue,
bytes calldata,
bytes calldata,
bytes calldata
) external pure override returns (address) {
callValue;
return address(0);
}
}