// SPDX-License-Identifier: MIT pragma solidity ^0.8.23; import { IERC7579Account } from "../erc-7579/IMSA.sol"; /** * @title Example7710Manager * @notice Not for production use.A minimal reference implementation for ERC-7710 focusing on delegation redemption. * @dev This is an intentionally simplified implementation to demonstrate core concepts. * For a complete production implementation with features like conditional permission enforcement and revocation, see MetaMask's Delegation Framework: * https://github.com/MetaMask/delegation-framework/blob/main/src/DelegationManager.sol */ contract Example7710Manager { ////////////////////////////// Types ////////////////////////////// struct Delegation { address delegator; // The address delegating authority address delegate; // The address receiving authority bytes32 authority; // The authority being delegated (or ROOT_AUTHORITY) bytes signature; // The delegator's signature authorizing this delegation } ////////////////////////////// Errors ////////////////////////////// error TupleDataLengthMismatch(); error InvalidDelegate(); error InvalidAuthority(); error InvalidSignature(); ////////////////////////////// Constants ////////////////////////////// /// @dev Special authority value indicating the delegator is the root authority bytes32 public constant ROOT_AUTHORITY = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff; ////////////////////////////// External Methods ////////////////////////////// /** * @notice Validates and executes delegated actions through a chain of authority. * @param _permissionContexts Array of delegation chains, each ordered from leaf to root. * Each chain demonstrates authority where: * - Index 0 is the leaf delegation (msg.sender's authority) * - Each delegation points to its authority via the previous delegation's hash * - The last delegation must have ROOT_AUTHORITY * @param _modes Execution modes for each action (see ERC-7579) * @param _executionCallDatas Encoded actions to execute */ function redeemDelegations( bytes[] calldata _permissionContexts, bytes32[] calldata _modes, bytes[] calldata _executionCallDatas ) external { uint256 batchSize_ = _permissionContexts.length; if (batchSize_ != _executionCallDatas.length || batchSize_ != _modes.length) { revert TupleDataLengthMismatch(); } Delegation[][] memory batchDelegations_ = new Delegation[][](batchSize_); // Process each batch for (uint256 batchIndex_; batchIndex_ < batchSize_; ++batchIndex_) { Delegation[] memory delegations_ = abi.decode(_permissionContexts[batchIndex_], (Delegation[])); batchDelegations_[batchIndex_] = delegations_; // Validate caller is the delegate if (delegations_[0].delegate != msg.sender) { revert InvalidDelegate(); } // Validate each delegation in chain for (uint256 i = 0; i < delegations_.length; i++) { Delegation memory delegation_ = delegations_[i]; bytes32 delegationHash_ = _getDelegationHash(delegation_); // Note: In a production implementation, you would want to use EIP-712 for typed data signing // and proper signature validation for both EOA and contract signatures. // This is simplified for demonstration purposes. if (!_isValidSignature(delegationHash_, delegation_.signature, delegation_.delegator)) { revert InvalidSignature(); } // Validate authority chain if (i != delegations_.length - 1) { if (delegation_.authority != _getDelegationHash(delegations_[i + 1])) { revert InvalidAuthority(); } // Validate delegate chain address nextDelegate_ = delegations_[i + 1].delegate; if (delegation_.delegator != nextDelegate_) { revert InvalidDelegate(); } } else if (delegation_.authority != ROOT_AUTHORITY) { revert InvalidAuthority(); } } // Execute the delegated action on the root delegator IERC7579Account(delegations_[delegations_.length - 1].delegator).executeFromExecutor( _modes[batchIndex_], _executionCallDatas[batchIndex_] ); } } ////////////////////////////// Internal Methods ////////////////////////////// /** * @notice Creates a simple hash of a Delegation struct * @dev In production, use EIP-712 for typed data hashing */ function _getDelegationHash(Delegation memory delegation) internal pure returns (bytes32) { return keccak256(abi.encode( delegation.delegator, delegation.delegate, delegation.authority )); } /** * @notice Basic signature validation (simplified for example purposes) * @dev In production, use EIP-712 and proper signature validation */ function _isValidSignature( bytes32 hash, bytes memory signature, address signer ) internal pure returns (bool) { // ECDSA recover // or ERC1271 isValidSignature // Logic would go here return true; // Simplified for example } }