96 lines
3.6 KiB
Solidity
96 lines
3.6 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
|
|
pragma solidity ^0.8.20;
|
|
|
|
import {IERC5267} from "../interfaces/IERC5267.sol";
|
|
import {PackedUserOperation} from "../interfaces/draft-IERC4337.sol";
|
|
import {ERC4337Utils} from "../account/utils/draft-ERC4337Utils.sol";
|
|
import {ERC721Holder} from "../token/ERC721/utils/ERC721Holder.sol";
|
|
import {ERC1155Holder} from "../token/ERC1155/utils/ERC1155Holder.sol";
|
|
import {ERC165} from "../utils/introspection/ERC165.sol";
|
|
import {ECDSA} from "../utils/cryptography/ECDSA.sol";
|
|
import {ERC7739Signer} from "../utils/cryptography/draft-ERC7739Signer.sol";
|
|
import {MessageHashUtils} from "../utils/cryptography/MessageHashUtils.sol";
|
|
import {AccountBase} from "./draft-AccountBase.sol";
|
|
|
|
/**
|
|
* @dev Account implementation using {ECDSA} signatures and {ERC7739Signer} for replay protection.
|
|
*
|
|
* An {_initializeSigner} function is provided to set the account's signer address. Doing so it's
|
|
* easier for a factory, whose likely to use initializable clones of this contract.
|
|
*
|
|
* IMPORTANT: Avoiding to call {_initializeSigner} either during construction (if used standalone)
|
|
* or during initialization (if used as a clone) may leave the account unusable.
|
|
*/
|
|
abstract contract AccountECDSA is ERC165, IERC5267, AccountBase, ERC7739Signer, ERC721Holder, ERC1155Holder {
|
|
using MessageHashUtils for bytes32;
|
|
|
|
/**
|
|
* @dev The {signer} is already initialized.
|
|
*/
|
|
error AccountECDSAUninitializedSigner(address signer);
|
|
|
|
address private _signer;
|
|
|
|
/**
|
|
* @dev Initializes the account with the address of the native signer. This function is called only once.
|
|
*/
|
|
function _initializeSigner(address signerAddr) internal {
|
|
if (_signer != address(0)) revert AccountECDSAUninitializedSigner(signerAddr);
|
|
_signer = signerAddr;
|
|
}
|
|
|
|
/**
|
|
* @dev Return the account's signer address.
|
|
*/
|
|
function signer() public view virtual returns (address) {
|
|
return _signer;
|
|
}
|
|
|
|
/**
|
|
* @dev Returns the ERC-191 signed `userOpHash` hashed with keccak256 using `personal_sign`.
|
|
*/
|
|
function _userOpSignedHash(
|
|
PackedUserOperation calldata /* userOp */,
|
|
bytes32 userOpHash
|
|
) internal view virtual override returns (bytes32) {
|
|
return userOpHash.toEthSignedMessageHash();
|
|
}
|
|
|
|
/**
|
|
* @dev Internal version of {validateUserOp} that relies on {_validateSignature}.
|
|
*
|
|
* The `userOpSignedHash` is the digest from {_userOpSignedHash}.
|
|
*
|
|
* NOTE: To override the signature functionality, try overriding {_validateSignature} instead.
|
|
*/
|
|
function _validateUserOp(
|
|
PackedUserOperation calldata userOp,
|
|
bytes32 userOpSignedHash
|
|
) internal view virtual override returns (uint256) {
|
|
return
|
|
_isValidSignature(userOpSignedHash, userOp.signature)
|
|
? ERC4337Utils.SIG_VALIDATION_SUCCESS
|
|
: ERC4337Utils.SIG_VALIDATION_FAILED;
|
|
}
|
|
|
|
/**
|
|
* @dev Validates the signature using the account's signer.
|
|
*
|
|
* This function provides a nested EIP-712 hash. Developers must override only this
|
|
* function to ensure no raw message signing is possible.
|
|
*/
|
|
function _validateSignature(
|
|
bytes32 nestedEIP712Hash,
|
|
bytes calldata signature
|
|
) internal view virtual override returns (bool) {
|
|
(address recovered, ECDSA.RecoverError err, ) = ECDSA.tryRecover(nestedEIP712Hash, signature);
|
|
return signer() == recovered && err == ECDSA.RecoverError.NoError;
|
|
}
|
|
|
|
/// @inheritdoc ERC165
|
|
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, ERC1155Holder) returns (bool) {
|
|
return super.supportsInterface(interfaceId);
|
|
}
|
|
}
|