Test linearization fail
This commit is contained in:
143
contracts/account/draft-AccountBase.sol
Normal file
143
contracts/account/draft-AccountBase.sol
Normal file
@ -0,0 +1,143 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {PackedUserOperation, IAccount, IEntryPoint, IAccountExecute} from "../interfaces/draft-IERC4337.sol";
|
||||
import {Address} from "../utils/Address.sol";
|
||||
|
||||
/**
|
||||
* @dev A simple ERC4337 account implementation.
|
||||
*
|
||||
* This base implementation only includes the minimal logic to process user operations.
|
||||
* Developers must implement the {_validateUserOp} function to define the account's validation logic.
|
||||
*/
|
||||
abstract contract AccountBase is IAccount, IAccountExecute {
|
||||
/**
|
||||
* @dev Unauthorized call to the account.
|
||||
*/
|
||||
error AccountUnauthorized(address sender);
|
||||
|
||||
/**
|
||||
* @dev Revert if the caller is not the entry point or the account itself.
|
||||
*/
|
||||
modifier onlyEntryPointOrSelf() {
|
||||
_checkEntryPointOrSelf();
|
||||
_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Revert if the caller is not the entry point.
|
||||
*/
|
||||
modifier onlyEntryPoint() {
|
||||
_checkEntryPoint();
|
||||
_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Canonical entry point for the account that forwards and validates user operations.
|
||||
*/
|
||||
function entryPoint() public view virtual returns (IEntryPoint) {
|
||||
return IEntryPoint(0x0000000071727De22E5E9d8BAf0edAc6f37da032);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return the account nonce for the canonical sequence.
|
||||
*/
|
||||
function getNonce() public view virtual returns (uint256) {
|
||||
return getNonce(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return the account nonce for a given sequence (key).
|
||||
*/
|
||||
function getNonce(uint192 key) public view virtual returns (uint256) {
|
||||
return entryPoint().getNonce(address(this), key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the digest the offchain signer signed instead of the opaque `userOpHash`.
|
||||
*
|
||||
* Given the `userOpHash` calculation is defined by ERC-4337, offchain signers
|
||||
* may need to sign again this hash by rehashing it with other schemes.
|
||||
*
|
||||
* Returns the `userOpHash` by default.
|
||||
*/
|
||||
function _userOpSignedHash(
|
||||
PackedUserOperation calldata /* userOp */,
|
||||
bytes32 userOpHash
|
||||
) internal view virtual returns (bytes32) {
|
||||
return userOpHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc IAccount
|
||||
*/
|
||||
function validateUserOp(
|
||||
PackedUserOperation calldata userOp,
|
||||
bytes32 userOpHash,
|
||||
uint256 missingAccountFunds
|
||||
) public virtual onlyEntryPoint returns (uint256) {
|
||||
uint256 validationData = _validateUserOp(userOp, _userOpSignedHash(userOp, userOpHash));
|
||||
_payPrefund(missingAccountFunds);
|
||||
return validationData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc IAccountExecute
|
||||
*/
|
||||
function executeUserOp(
|
||||
PackedUserOperation calldata userOp,
|
||||
bytes32 /*userOpHash*/
|
||||
) public virtual onlyEntryPointOrSelf {
|
||||
(address target, uint256 value, bytes memory data) = abi.decode(userOp.callData[4:], (address, uint256, bytes));
|
||||
Address.functionCallWithValue(target, data, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Validation logic for {validateUserOp}. The `userOpSignedHash` is the digest from {_userOpSignedHash}.
|
||||
*
|
||||
* IMPORTANT: Implementing a mechanism to validate user operations is a security-sensitive operation
|
||||
* as it may allow an attacker to bypass the account's security measures. Check out {AccountECDSA},
|
||||
* {AccountP256}, or {AccountRSA} for digital signature validation implementations.
|
||||
*/
|
||||
function _validateUserOp(
|
||||
PackedUserOperation calldata userOp,
|
||||
bytes32 userOpSignedHash
|
||||
) internal view virtual returns (uint256 validationData);
|
||||
|
||||
/**
|
||||
* @dev Sends the missing funds for executing the user operation to the {entrypoint}.
|
||||
* The `missingAccountFunds` must be defined by the entrypoint when calling {validateUserOp}.
|
||||
*/
|
||||
function _payPrefund(uint256 missingAccountFunds) internal virtual {
|
||||
if (missingAccountFunds > 0) {
|
||||
(bool success, ) = payable(msg.sender).call{value: missingAccountFunds}("");
|
||||
success; // Silence warning. The entrypoint should validate the result.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Ensures the caller is the {entrypoint}.
|
||||
*/
|
||||
function _checkEntryPoint() internal view virtual {
|
||||
address sender = msg.sender;
|
||||
if (sender != address(entryPoint())) {
|
||||
revert AccountUnauthorized(sender);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Ensures the caller is the {entrypoint} or the account itself.
|
||||
*/
|
||||
function _checkEntryPointOrSelf() internal view virtual {
|
||||
address sender = msg.sender;
|
||||
if (sender != address(this) && sender != address(entryPoint())) {
|
||||
revert AccountUnauthorized(sender);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Receive Ether.
|
||||
*/
|
||||
receive() external payable virtual {}
|
||||
}
|
||||
97
contracts/account/draft-AccountECDSA.sol
Normal file
97
contracts/account/draft-AccountECDSA.sol
Normal file
@ -0,0 +1,97 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {PackedUserOperation} from "../interfaces/draft-IERC4337.sol";
|
||||
import {ERC4337Utils} from "../account/utils/draft-ERC4337Utils.sol";
|
||||
import {ERC721Holder} from "../token/ERC721/utils/ERC721Holder.sol";
|
||||
// import {ERC1155HolderLean, IERC1155Receiver} from "../token/ERC1155/utils/ERC1155HolderLean.sol";
|
||||
import {ERC1155Holder, IERC1155Receiver} from "../token/ERC1155/utils/ERC1155Holder.sol";
|
||||
import {ERC165} from "../utils/introspection/ERC165.sol";
|
||||
import {IERC165} from "../utils/introspection/IERC165.sol";
|
||||
import {ECDSA} from "../utils/cryptography/ECDSA.sol";
|
||||
import {MessageHashUtils} from "../utils/cryptography/MessageHashUtils.sol";
|
||||
import {AccountBase} from "./draft-AccountBase.sol";
|
||||
import {ERC7739Signer, EIP712} from "../utils/cryptography/draft-ERC7739Signer.sol";
|
||||
import {Initializable} from "../proxy/utils/Initializable.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, ERC721Holder, ERC1155Holder, ERC7739Signer, AccountBase {
|
||||
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 interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user