-
Notifications
You must be signed in to change notification settings - Fork 69
BT-950💥 added Account Abstraction for Identity contract #131
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,15 +6,15 @@ | |
| import { Errors } from "./libraries/Errors.sol"; | ||
| import { KeyPurposes } from "./libraries/KeyPurposes.sol"; | ||
|
|
||
| contract ClaimIssuer is IClaimIssuer, Identity { | ||
|
Check warning on line 9 in contracts/ClaimIssuer.sol
|
||
| mapping(bytes => bool) public revokedClaims; | ||
|
Check warning on line 10 in contracts/ClaimIssuer.sol
|
||
|
|
||
| /** | ||
| * @notice Constructor for direct deployments (non-proxy) | ||
| * @param initialManagementKey The initial management key for the ClaimIssuer | ||
| */ | ||
| // solhint-disable-next-line no-empty-blocks | ||
| constructor( | ||
|
Check warning on line 17 in contracts/ClaimIssuer.sol
|
||
| address initialManagementKey | ||
| ) Identity(initialManagementKey, false) {} | ||
|
|
||
|
|
@@ -32,7 +32,7 @@ | |
| /** | ||
| * @dev See {IClaimIssuer-revokeClaimBySignature}. | ||
| */ | ||
| function revokeClaimBySignature( | ||
|
Check warning on line 35 in contracts/ClaimIssuer.sol
|
||
| bytes calldata signature | ||
| ) external override delegatedOnly onlyManager { | ||
| require(!revokedClaims[signature], Errors.ClaimAlreadyRevoked()); | ||
|
|
@@ -144,6 +144,9 @@ | |
| // Initialize UUPS upgradeability | ||
| __UUPSUpgradeable_init(); | ||
|
|
||
| // Initialize IdentitySmartAccount functionality | ||
| __IdentitySmartAccount_init(); | ||
|
|
||
| // Initialize Identity functionality | ||
| __Identity_init(initialManagementKey); | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,14 +5,22 @@ import { MulticallUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/ | |
| import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; | ||
| import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; | ||
| import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; | ||
| import { IdentitySmartAccount } from "./IdentitySmartAccount.sol"; | ||
| import { | ||
| SIG_VALIDATION_FAILED, | ||
| SIG_VALIDATION_SUCCESS | ||
| } from "@account-abstraction/contracts/core/Helpers.sol"; | ||
| import { PackedUserOperation } from "@account-abstraction/contracts/interfaces/PackedUserOperation.sol"; | ||
| import { IEntryPoint } from "@account-abstraction/contracts/interfaces/IEntryPoint.sol"; | ||
| import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; | ||
| import { Exec } from "@account-abstraction/contracts/utils/Exec.sol"; | ||
| import { IIdentity } from "./interface/IIdentity.sol"; | ||
| import { IClaimIssuer } from "./interface/IClaimIssuer.sol"; | ||
| import { IERC734 } from "./interface/IERC734.sol"; | ||
| import { IERC735 } from "./interface/IERC735.sol"; | ||
| import { Version } from "./version/Version.sol"; | ||
| import { Errors } from "./libraries/Errors.sol"; | ||
| import { KeyPurposes } from "./libraries/KeyPurposes.sol"; | ||
| import { KeyTypes } from "./libraries/KeyTypes.sol"; | ||
| import { Structs } from "./storage/Structs.sol"; | ||
| import { KeyManager } from "./KeyManager.sol"; | ||
|
|
||
|
|
@@ -41,6 +49,7 @@ contract Identity is | |
| Initializable, | ||
| UUPSUpgradeable, | ||
| IIdentity, | ||
| IdentitySmartAccount, | ||
| Version, | ||
| KeyManager, | ||
| MulticallUpgradeable | ||
|
|
@@ -112,6 +121,44 @@ contract Identity is | |
| } | ||
| } | ||
|
|
||
| /** | ||
| * @dev See {IERC734-execute}. | ||
| * @notice Executes a single call from the account (ERC-734 compatible) | ||
| */ | ||
| function execute( | ||
| address _to, | ||
| uint256 _value, | ||
| bytes calldata _data | ||
| ) | ||
| external | ||
| payable | ||
| virtual | ||
| override(IERC734, KeyManager) | ||
| returns (uint256 executionId) | ||
| { | ||
| // Allow entry point calls | ||
| if (msg.sender == address(entryPoint())) { | ||
| // For entry point calls, use direct execution | ||
| _executeDirect(_to, _value, _data); | ||
| return 0; // Return 0 for entry point calls | ||
| } | ||
|
|
||
| // For regular calls, use KeyManager's execution logic | ||
| KeyStorage storage ks = _getKeyStorage(); | ||
| executionId = ks.executionNonce; | ||
| ks.executions[executionId].to = _to; | ||
| ks.executions[executionId].value = _value; | ||
| ks.executions[executionId].data = _data; | ||
| ks.executionNonce++; | ||
|
|
||
| emit ExecutionRequested(executionId, _to, _value, _data); | ||
|
|
||
| // Check if execution can be auto-approved | ||
| if (_canAutoApproveExecution(_to)) { | ||
| _approve(executionId, true); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * @notice When using this contract as an implementation for a proxy, call this initializer with a delegatecall. | ||
| * @dev This function initializes the upgradeable contract and sets up the initial management key. | ||
|
|
@@ -123,6 +170,7 @@ contract Identity is | |
| ) external virtual initializer { | ||
| require(initialManagementKey != address(0), Errors.ZeroAddress()); | ||
| __UUPSUpgradeable_init(); | ||
| __IdentitySmartAccount_init(); | ||
| __Identity_init(initialManagementKey); | ||
| __Version_init("2.2.2"); | ||
| } | ||
|
|
@@ -438,7 +486,12 @@ contract Identity is | |
| */ | ||
| function _authorizeUpgrade( | ||
| address newImplementation | ||
| ) internal virtual override onlyManager { | ||
| ) | ||
| internal | ||
| virtual | ||
| override(IdentitySmartAccount, UUPSUpgradeable) | ||
| onlyManager | ||
| { | ||
| // Only management keys can authorize upgrades | ||
| // This prevents unauthorized upgrades and potential rug pulls | ||
| } | ||
|
|
@@ -554,6 +607,88 @@ contract Identity is | |
| } | ||
| } | ||
|
|
||
| /** | ||
| * @dev Internal function for direct execution (used by entry point) | ||
| * @param _to The target address | ||
| * @param _value The value to send | ||
| * @param _data The calldata | ||
| * | ||
| * @notice Uses the professional Exec library pattern from BaseAccount for consistent | ||
| * and gas-optimized execution with proper error handling. | ||
| */ | ||
| function _executeDirect( | ||
| address _to, | ||
| uint256 _value, | ||
| bytes calldata _data | ||
| ) internal { | ||
| bool ok = Exec.call(_to, _value, _data, gasleft()); | ||
| if (!ok) { | ||
| Exec.revertWithReturnData(); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * @dev See {IdentitySmartAccount-_requireManager}. | ||
| * @notice Requires the caller to have management permissions | ||
| */ | ||
| function _requireManager() internal view override onlyManager { | ||
| // The onlyManager modifier handles the access control | ||
| } | ||
|
|
||
| /** | ||
| * @dev See {IdentitySmartAccount-_validateSignature}. | ||
| * @notice Validates the signature of a UserOperation and the signer's permissions | ||
| * This function performs complete validation: | ||
| * 1. Recovers the signer address from the signature | ||
| * 2. Validates that the signature is valid (not address(0)) | ||
| * 3. Validates that the signer has required permissions (ERC4337_SIGNER or MANAGEMENT) | ||
| * @param userOp The UserOperation to validate | ||
| * @param userOpHash The hash of the UserOperation | ||
| * @return validationData Packed validation data (0 for success, 1 for signature/permission failure) | ||
| */ | ||
| function _validateSignature( | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. your signature validation just returns 0 ro 1 |
||
| PackedUserOperation calldata userOp, | ||
| bytes32 userOpHash | ||
| ) internal view override returns (uint256 validationData) { | ||
| // 1. Recover the signer address from the signature | ||
| address signer = ECDSA.recover(userOpHash, userOp.signature); | ||
|
|
||
| // 2. Validate that the signature is valid | ||
| if (signer == address(0)) { | ||
| return SIG_VALIDATION_FAILED; | ||
| } | ||
|
|
||
| // 3. Validate that the signer has required permissions | ||
| if ( | ||
| !keyHasPurpose( | ||
| keccak256(abi.encode(signer)), | ||
| KeyPurposes.ERC4337_SIGNER | ||
| ) && | ||
| !keyHasPurpose( | ||
| keccak256(abi.encode(signer)), | ||
| KeyPurposes.MANAGEMENT | ||
| ) | ||
| ) { | ||
| return SIG_VALIDATION_FAILED; | ||
| } | ||
|
|
||
| return SIG_VALIDATION_SUCCESS; | ||
| } | ||
|
|
||
| /** | ||
| * @dev See {IdentitySmartAccount-_requireForExecute}. | ||
| * @notice Requires the caller to be authorized for execution | ||
| */ | ||
| function _requireForExecute() internal view override { | ||
| // Allow entry point calls | ||
| if (msg.sender == address(entryPoint())) { | ||
| return; | ||
| } | ||
|
|
||
| // For all other calls, require management permissions | ||
| _requireManager(); | ||
| } | ||
|
|
||
| /** | ||
| * @dev Internal helper to validate claim with external issuer. | ||
| * | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
execute() does two different things
if called by EntryPoint runs directly adn if called by anyone else it goes through 734 flow
I think is kinda messy can be confusing maybe separate functions or force EntryPoint to use executeBatch