AttestationValidator

Description:

Multi-signature wallet contract requiring multiple confirmations for transaction execution.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "src/middlewares/AttestationValidator.sol": {
      "content": "// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.27;

import {NewtonMessage} from "../core/NewtonMessage.sol";
import {TaskLib} from "../libraries/TaskLib.sol";
import "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol";
import "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol";

contract AttestationValidator is Initializable, OwnableUpgradeable {
    /* CUSTOM ERRORS */
    error AttestationHashMismatch();
    error AttestationExpired();
    error AttestationAlreadySpent();
    error OnlyTaskManager();

    /* STORAGE */
    address public immutable taskManager;
    mapping(bytes32 => bytes32) public attestations;

    /* MODIFIERS */
    modifier onlyTaskManager() {
        require(msg.sender == taskManager, OnlyTaskManager());
        _;
    }

    /* CONSTRUCTOR */
    constructor(
        address _taskManager
    ) {
        taskManager = _taskManager;
    }

    /* INITIALIZER */
    function initialize(
        address _owner
    ) public initializer {
        __Ownable_init();
        _transferOwnership(_owner);
    }

    /* EXTERNAL FUNCTIONS */
    function validateAttestation(
        NewtonMessage.Attestation calldata attestation
    ) external onlyTaskManager returns (bool) {
        TaskLib.sanityCheckAttestation(attestation);
        bytes32 attestationHash = keccak256(abi.encode(attestation));
        require(attestations[attestation.taskId] == attestationHash, AttestationHashMismatch());
        require(uint32(block.number) <= attestation.expiration, AttestationExpired());
        // Prevent double spending of the same attestation by setting the attestation hash to 0
        require(attestations[attestation.taskId] != bytes32(0), AttestationAlreadySpent());
        attestations[attestation.taskId] = bytes32(0);
        return true;
    }

    function createAttestationHash(
        bytes32 taskId,
        bytes32 policyId,
        address policyClient,
        NewtonMessage.Intent calldata intent,
        uint32 expiration
    ) external onlyTaskManager returns (bytes32) {
        NewtonMessage.Attestation memory attestation =
            NewtonMessage.Attestation(taskId, policyId, policyClient, intent, expiration);
        bytes32 attestationHash = keccak256(abi.encode(attestation));
        attestations[taskId] = attestationHash;
        return attestationHash;
    }

    function isAttestationValid(
        NewtonMessage.Attestation calldata attestation
    ) external view returns (bool) {
        TaskLib.sanityCheckAttestation(attestation);
        bytes32 attestationHash = keccak256(abi.encode(attestation));
        return attestations[attestation.taskId] == attestationHash
            && uint32(block.number) <= attestation.expiration
            && attestations[attestation.taskId] != bytes32(0);
    }

    function getAttestationHash(
        bytes32 taskId
    ) external view returns (bytes32) {
        return attestations[taskId];
    }
}
"
    },
    "src/core/NewtonMessage.sol": {
      "content": "// SPDX-License-Identifier: MIT

pragma solidity ^0.8.27;

/// @notice Contract for a NewtonMessage
contract NewtonMessage {
    // STRUCTS
    /// @notice Intent struct for a transaction authorization
    struct Intent {
        // equivalent to tx.origin/from
        address from;
        // equivalent to to
        address to;
        // equivalent to msg.value
        uint256 value;
        // ABI-encoded calldata. function selector and arguments
        bytes data;
        // chain id of the chain that the transaction is on
        uint256 chainId;
        // encoded ABI of the function that is being called
        // e.g. abi.encodePacked("function transfer(address,uint256)")
        bytes functionSignature;
    }

    /// @notice Attestation struct for a transaction authorization
    struct Attestation {
        // task id
        bytes32 taskId;
        // policy id
        bytes32 policyId;
        // policy client
        address policyClient;
        // intent
        Intent intent;
        // expiration block number for the attestation
        uint32 expiration;
    }

    /// @notice PolicyData struct for a policy data and its attestation proof
    struct PolicyData {
        // encoded policy data
        bytes data;
        // attestation proof for the policy data.
        bytes attestation;
        // policy data address
        address policyDataAddress;
        // expiration block number for the policy data
        uint32 expireBlock;
    }

    /// @notice PolicyTaskData struct for a policy data
    struct PolicyTaskData {
        // policy id
        bytes32 policyId;
        // policy address
        address policyAddress;
        // policy program binary
        bytes policy;
        // an array of policy data with attestation
        // NOTE: order matters, the first policy data is the first policy data in the policy data set of the policy.
        PolicyData[] policyData;
    }

    /// @notice VerificationInfo struct for a policy data verification
    struct VerificationInfo {
        // verifier
        address verifier;
        // verified
        bool verified;
        // timestamp
        uint256 timestamp;
    }

    /// @notice error type for unauthorized access
    error Unauthorized(string reason);
}
"
    },
    "src/libraries/TaskLib.sol": {
      "content": "// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.27;

import {INewtonProverTaskManager} from "../interfaces/INewtonProverTaskManager.sol";
import {INewtonPolicy} from "../interfaces/INewtonPolicy.sol";
import {NewtonMessage} from "../core/NewtonMessage.sol";
import {INewtonPolicyClient} from "../interfaces/INewtonPolicyClient.sol";
import {IERC165} from "@openzeppelin/contracts/interfaces/IERC165.sol";
import {PolicyValidationLib} from "./PolicyValidationLib.sol";

/**
 * @title TaskLib
 * @dev Library for task evaluation and result processing
 */
library TaskLib {
    /* CUSTOM ERRORS */
    error TaskMismatch();
    error InvalidPolicyId();
    error InvalidPolicyClient();
    error InvalidPolicyAddress();
    error TaskAlreadyResponded();
    error TaskResponseTooLate(
        uint32 blockNumber, uint32 taskCreatedBlock, uint32 taskResponseWindowBlock
    );
    error OnlyPolicyClient();
    error InterfaceNotSupported();

    /* FUNCTIONS */

    function createTask(
        uint32 nonce,
        address policyClient,
        NewtonMessage.Intent calldata intent,
        NewtonMessage.PolicyTaskData calldata policyTaskData,
        bytes calldata quorumNumbers,
        uint32 quorumThresholdPercentage
    ) external view returns (INewtonProverTaskManager.Task memory) {
        // Validate policy client and get basic info
        (address policyAddress, bytes32 policyId) =
            PolicyValidationLib.checkVerifiedPolicy(policyClient, policyTaskData);

        uint32 currentBlock = uint32(block.number);

        // Validate policy data attestations
        PolicyValidationLib.validatePolicyData(policyAddress, policyTaskData, currentBlock);

        // Create task
        INewtonProverTaskManager.Task memory newTask = INewtonProverTaskManager.Task({
            nonce: nonce,
            intent: intent,
            policyId: policyId,
            policyClient: policyClient,
            policyTaskData: policyTaskData,
            policyConfig: INewtonPolicy(policyAddress).getPolicyConfig(policyId),
            taskCreatedBlock: currentBlock,
            quorumNumbers: quorumNumbers,
            quorumThresholdPercentage: quorumThresholdPercentage,
            taskId: bytes32(0)
        });

        bytes32 taskId = keccak256(abi.encode(newTask));
        newTask.taskId = taskId;

        return newTask;
    }

    /**
     * @dev Evaluates the result of a task execution
     * @param evaluationResult The result data to evaluate
     * @return bool True if the result indicates success/true
     */
    function evaluateResult(
        bytes memory evaluationResult
    ) external pure returns (bool) {
        uint256 length = evaluationResult.length;

        // Case 1: ABI-encoded bool true (32 bytes)
        if (length == 32) {
            uint256 val;
            assembly {
                val := mload(add(evaluationResult, 32))
            }
            return val == 1;
        }

        // Case 2: ABI-encoded "true" string (96+ bytes)
        if (length >= 96) {
            uint256 strLen;
            assembly {
                strLen := mload(add(evaluationResult, 64))
            }
            if (strLen == 4) {
                bytes32 strData;
                assembly {
                    strData := mload(add(evaluationResult, 96))
                }
                return strData == 0x7472756500000000000000000000000000000000000000000000000000000000;
            }
        }

        return false;
    }

    /**
     * @dev Sanity checks the task response. Throws if any of the checks fail.
     * @param task The task
     * @param taskResponse The task response
     * @param blockNumber The block number
     * @param responseWindowBlock The response window block
     */
    function sanityCheckTaskResponse(
        INewtonProverTaskManager.Task calldata task,
        INewtonProverTaskManager.TaskResponse calldata taskResponse,
        uint32 blockNumber,
        uint32 responseWindowBlock
    ) external pure {
        require(taskResponse.policyId == task.policyId, InvalidPolicyId());
        require(taskResponse.policyClient == task.policyClient, InvalidPolicyClient());
        require(
            taskResponse.policyAddress == task.policyTaskData.policyAddress, InvalidPolicyAddress()
        );
        require(
            blockNumber <= task.taskCreatedBlock + responseWindowBlock,
            TaskResponseTooLate(blockNumber, task.taskCreatedBlock, responseWindowBlock)
        );
    }

    function sanityCheckAttestation(
        NewtonMessage.Attestation calldata attestation
    ) external view {
        require(
            attestation.policyId == INewtonPolicyClient(attestation.policyClient).getPolicyId(),
            PolicyValidationLib.PolicyIdMismatch()
        );
        require(msg.sender == attestation.policyClient, InvalidPolicyClient());
    }

    // onlyPolicyClient is used to restrict validateAttestation from only being called by a policy client
    function onlyPolicyClient() external view {
        require(msg.sender.code.length > 0, OnlyPolicyClient());

        bytes4 interfaceId = type(INewtonPolicyClient).interfaceId;

        (bool success, bytes memory result) = msg.sender.staticcall(
            abi.encodeWithSelector(IERC165.supportsInterface.selector, interfaceId)
        );

        require(
            success && result.length == 32 && abi.decode(result, (bool)), InterfaceNotSupported()
        );
    }
}
"
    },
    "lib/eigenlayer-middleware/lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.2;

import "../../utils/AddressUpgradeable.sol";

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
 * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
 * case an upgrade adds a module that needs to be initialized.
 *
 * For example:
 *
 * [.hljs-theme-light.nopadding]
 * ```solidity
 * contract MyToken is ERC20Upgradeable {
 *     function initialize() initializer public {
 *         __ERC20_init("MyToken", "MTK");
 *     }
 * }
 *
 * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
 *     function initializeV2() reinitializer(2) public {
 *         __ERC20Permit_init("MyToken");
 *     }
 * }
 * ```
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
 * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() {
 *     _disableInitializers();
 * }
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Indicates that the contract has been initialized.
     * @custom:oz-retyped-from bool
     */
    uint8 private _initialized;

    /**
     * @dev Indicates that the contract is in the process of being initialized.
     */
    bool private _initializing;

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint8 version);

    /**
     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
     * `onlyInitializing` functions can be used to initialize parent contracts.
     *
     * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
     * constructor.
     *
     * Emits an {Initialized} event.
     */
    modifier initializer() {
        bool isTopLevelCall = !_initializing;
        require(
            (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
            "Initializable: contract is already initialized"
        );
        _initialized = 1;
        if (isTopLevelCall) {
            _initializing = true;
        }
        _;
        if (isTopLevelCall) {
            _initializing = false;
            emit Initialized(1);
        }
    }

    /**
     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
     * used to initialize parent contracts.
     *
     * A reinitializer may be used after the original initialization step. This is essential to configure modules that
     * are added through upgrades and that require initialization.
     *
     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
     * cannot be nested. If one is invoked in the context of another, execution will revert.
     *
     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
     * a contract, executing them in the right order is up to the developer or operator.
     *
     * WARNING: setting the version to 255 will prevent any future reinitialization.
     *
     * Emits an {Initialized} event.
     */
    modifier reinitializer(uint8 version) {
        require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
        _initialized = version;
        _initializing = true;
        _;
        _initializing = false;
        emit Initialized(version);
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} and {reinitializer} modifiers, directly or indirectly.
     */
    modifier onlyInitializing() {
        require(_initializing, "Initializable: contract is not initializing");
        _;
    }

    /**
     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
     * through proxies.
     *
     * Emits an {Initialized} event the first time it is successfully executed.
     */
    function _disableInitializers() internal virtual {
        require(!_initializing, "Initializable: contract is initializing");
        if (_initialized != type(uint8).max) {
            _initialized = type(uint8).max;
            emit Initialized(type(uint8).max);
        }
    }

    /**
     * @dev Returns the highest version that has been initialized. See {reinitializer}.
     */
    function _getInitializedVersion() internal view returns (uint8) {
        return _initialized;
    }

    /**
     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
     */
    function _isInitializing() internal view returns (bool) {
        return _initializing;
    }
}
"
    },
    "lib/eigenlayer-middleware/lib/openzeppelin-contracts-upgradeable/contracts/access/OwnableUpgradeable.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    function __Ownable_init() internal onlyInitializing {
        __Ownable_init_unchained();
    }

    function __Ownable_init_unchained() internal onlyInitializing {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[49] private __gap;
}
"
    },
    "src/interfaces/INewtonProverTaskManager.sol": {
      "content": "// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.27;

import "@eigenlayer-middleware/src/libraries/BN254.sol";
import "@eigenlayer-middleware/src/interfaces/IBLSSignatureChecker.sol";
import {NewtonMessage} from "../core/NewtonMessage.sol";
import {INewtonPolicy} from "./INewtonPolicy.sol";

interface INewtonProverTaskManager {
    // EVENTS
    event NewTaskCreated(bytes32 indexed taskId, Task task);

    event TaskResponded(TaskResponse taskResponse, ResponseCertificate responseCertificate);

    event TaskChallengedSuccessfully(bytes32 indexed taskId, address indexed challenger);

    event TaskChallengedUnsuccessfully(bytes32 indexed taskId, address indexed challenger);

    event AttestationSpent(bytes32 indexed taskId, NewtonMessage.Attestation attestation);

    // STRUCTS
    // task submitter decides on the criteria for a task to be completed
    // note that this does not mean the task was "correctly" answered (i.e. the number was proved correctly)
    //      this is for the challenge logic to verify
    // task is completed (and contract will accept its TaskResponse) when each quorumNumbers specified here
    // are signed by at least quorumThresholdPercentage of the operators
    // note that we set the quorumThresholdPercentage to be the same for all quorumNumbers, but this could be changed
    struct Task {
        // the unique identifier for the task
        bytes32 taskId;
        // policy client address
        address policyClient;
        // policy id
        bytes32 policyId;
        // the nonce of the task
        uint32 nonce;
        // the intent of the task
        NewtonMessage.Intent intent;
        // the policy task data of the task
        NewtonMessage.PolicyTaskData policyTaskData;
        // policy configuration for the policy program
        INewtonPolicy.PolicyConfig policyConfig;
        // the block number when the task was created
        uint32 taskCreatedBlock;
        // the quorum numbers of the task
        bytes quorumNumbers;
        // the quorum threshold percentage of the task
        uint32 quorumThresholdPercentage;
    }

    // Task response is hashed and signed by operators.
    // these signatures are aggregated and sent to the contract as response.
    struct TaskResponse {
        // Can be obtained by the operator from the event NewTaskCreated.
        bytes32 taskId;
        // policy client address
        address policyClient;
        // policy id of the task
        bytes32 policyId;
        // the policy address of the task
        address policyAddress;
        // the intent of the task
        NewtonMessage.Intent intent;
        // Policy evaluation result.
        bytes evaluationResult;
    }

    // Certificate is filled by the protocol contract for each taskResponse signed by operators.
    // This Certificate is used by policy clients to attest the validity of policy evaluation result
    // during intent execution.
    // This certificate is also used by the challenger, who monitors and if invalid, raises challenge
    // with zero-knowledge proof of the policy evaluation result discrepancy.
    // NOTE: this can be used as an attestation for not just single chain but multi-chain attestation.
    struct ResponseCertificate {
        // the block number when the response certificate is created
        uint32 referenceBlock;
        // the hash of the non-signers
        bytes32 hashOfNonSigners;
        // the non-signers and their stakes
        IBLSSignatureChecker.NonSignerStakesAndSignature nonSignerStakesAndSignature;
        // the block number when the task response expires
        uint32 responseExpireBlock;
    }

    // Challenge data is submitted by the challenger.
    // Contains the proof data and verification key for onchain verification of the policy evaluation result.
    // TODO: add support for risc0 zk proofs, and other proof types.
    struct ChallengeData {
        // Can be obtained by the operator from the event NewTaskCreated.
        bytes32 taskId;
        // sp1 zk proof to attest the policy evaluation result of the challenger
        bytes proof;
        // The committed proof output to verify against the task response data.
        bytes data;
    }

    // FUNCTIONS
    // NOTE: this function creates new task.
    function createNewTask(
        address policyClient,
        NewtonMessage.Intent calldata intent,
        NewtonMessage.PolicyTaskData calldata policyTaskData,
        bytes calldata quorumNumbers,
        uint32 quorumThresholdPercentage
    ) external;

    // NOTE: this function responds to existing tasks.
    function respondToTask(
        Task calldata task,
        TaskResponse calldata taskResponse,
        IBLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature
    ) external;

    // NOTE: this function raises challenge to existing tasks.
    function raiseAndResolveChallenge(
        Task calldata task,
        TaskResponse calldata taskResponse,
        ResponseCertificate calldata responseCertificate,
        ChallengeData calldata challenge,
        BN254.G1Point[] memory pubkeysOfNonSigningOperators
    ) external;

    // NOTE: this function authorizes existing task responses.
    function validateAttestation(
        NewtonMessage.Attestation calldata attestation
    ) external returns (bool);
}
"
    },
    "src/interfaces/INewtonPolicy.sol": {
      "content": "// SPDX-License-Identifier: MIT

pragma solidity ^0.8.27;

import {IERC165} from "@openzeppelin/contracts/interfaces/IERC165.sol";

/// @notice Interface for a NewtonPolicy
/// @dev For Rego policy grammar, refer to https://github.com/microsoft/regorus/blob/main/docs/grammar.md
interface INewtonPolicy is IERC165 {
    struct PolicyConfig {
        bytes policyParams;
        uint32 expireAfter;
    }

    struct SetPolicyInfo {
        bytes32 policyId;
        address policyAddress;
        address owner;
        string policyCid;
        string schemaCid;
        string entrypoint;
        PolicyConfig policyConfig;
        address[] policyData;
    }

    struct PolicyInfo {
        address policyAddress;
        address owner;
        string metadataCid;
        string policyCid;
        string schemaCid;
        string entrypoint;
        address[] policyData;
    }

    /* Events */
    event PolicySet(address indexed client, bytes32 indexed policyId, SetPolicyInfo policy);
    event policyMetadataCidUpdated(string metadataCid);

    /**
     * @notice Retrieves the metadata CID for the policy.
     * @return The metadata CID for the policy.
     */
    function getMetadataCid() external view returns (string memory);

    /**
     * @notice Sets the metadata CID for the policy.
     * @param metadataCid The metadata CID to set for the policy.
     */
    function setMetadataCid(
        string calldata metadataCid
    ) external;

    /**
     * @notice Retrieves the policyID for the calling address.
     * @return The policyID associated with the calling address.
     */
    function getPolicyId(
        address client
    ) external view returns (bytes32);

    /**
     * @notice Retrieves the policy evaluation entrypoint from the Rego policy
     * @return The policy evaluation entrypoint from the Rego policy
     * @dev Expected format is {package}.{output} for the Rego program
     */
    function getEntrypoint() external view returns (string memory);

    /**
     * @notice Retrieves the policy params schema from the Rego policy
     * @return The policy params schema from the Rego policy
     * @dev https://docs.rs/regorus/latest/regorus/struct.Schema.html
     */
    function getSchemaCid() external view returns (string memory);

    /**
     * @notice Retrieves the policy location for the policy.
     * @return The policy location for the policy.
     */
    function getPolicyCid() external view returns (string memory);

    /**
     * @notice Retrieves the policy configuration for the given policyID.
     * @param policyId The policyID to retrieve the policy configuration for.
     * @return The policy configuration for the given policyID.
     */
    function getPolicyConfig(
        bytes32 policyId
    ) external view returns (PolicyConfig memory);

    /**
     * @notice Retrieves the policy data contract addresses.
     * @return The policy data contract addresses.
     */
    function getPolicyData() external view returns (address[] memory);

    /**
     * @notice Retrieves the policy verified status.
     * @return The policy verified status.
     */
    function isPolicyVerified() external view returns (bool);
}
"
    },
    "src/interfaces/INewtonPolicyClient.sol": {
      "content": "// SPDX-License-Identifier: MIT

pragma solidity ^0.8.27;

import {IERC165} from "@openzeppelin/contracts/interfaces/IERC165.sol";

/// @notice Interface for a NewtonPolicyClient-type contract that enables clients to define execution rules or parameters for tasks they submit
interface INewtonPolicyClient is IERC165 {
    /// @notice error for when validate() is called with an incorrect policyID
    error InvalidPolicyID();

    /**
     * @notice Retrieves the policyID for the calling address.
     * @return The policyID associated with the calling address.
     */
    function getPolicyId() external view returns (bytes32);

    /**
     * @notice Retrieves the policy address for the calling address.
     * @return The policy address associated with the calling address.
     */
    function getPolicyAddress() external view returns (address);

    /**
     * @notice Function for getting the Newton PolicyTaskManager
     * @return address of the policy task manager
     */
    function getNewtonPolicyTaskManager() external view returns (address);
}
"
    },
    "lib/eigenlayer-middleware/lib/openzeppelin-contracts/contracts/interfaces/IERC165.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC165.sol)

pragma solidity ^0.8.0;

import "../utils/introspection/IERC165.sol";
"
    },
    "src/libraries/PolicyValidationLib.sol": {
      "content": "// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.27;

import {INewtonPolicy} from "../interfaces/INewtonPolicy.sol";
import {INewtonPolicyData} from "../interfaces/INewtonPolicyData.sol";
import {INewtonPolicyClient} from "../interfaces/INewtonPolicyClient.sol";
import {NewtonMessage} from "../core/NewtonMessage.sol";
import {ChainLib} from "./ChainLib.sol";

/**
 * @title PolicyValidationLib
 * @dev Library for policy and data validation
 */
library PolicyValidationLib {
    error PolicyIdMismatch();
    error PolicyAddressMismatch();
    error PolicyDataLengthMismatch();
    error PolicyDataAddressMismatch();
    error PolicyDataAttestationFailed();
    error PolicyDataExpired();
    error PolicyNotVerified();
    error PolicyDataNotVerified();

    /**
     * @dev Checks if the policy is a verified policy. Only used for mainnet.
     */
    function checkVerifiedPolicy(
        address policyClient,
        NewtonMessage.PolicyTaskData calldata policyTaskData
    ) external view returns (address policyAddress, bytes32 policyId) {
        policyAddress = INewtonPolicyClient(policyClient).getPolicyAddress();
        policyId = INewtonPolicyClient(policyClient).getPolicyId();

        require(policyTaskData.policyId == policyId, PolicyIdMismatch());
        require(policyTaskData.policyAddress == policyAddress, PolicyAddressMismatch());

        require(INewtonPolicy(policyAddress).isPolicyVerified(), PolicyNotVerified());
    }

    /**
     * @dev Validates policy data attestations
     */
    function validatePolicyData(
        address policyAddress,
        NewtonMessage.PolicyTaskData calldata policyTaskData,
        uint32 currentBlock
    ) external view {
        address[] memory policyDataAddresses = INewtonPolicy(policyAddress).getPolicyData();
        NewtonMessage.PolicyData[] memory policyData = policyTaskData.policyData;

        require(policyData.length == policyDataAddresses.length, PolicyDataLengthMismatch());

        for (uint256 i; i < policyDataAddresses.length;) {
            require(
                policyData[i].policyDataAddress == policyDataAddresses[i],
                PolicyDataAddressMismatch()
            );

            require(
                INewtonPolicyData(policyTaskData.policyData[i].policyDataAddress)
                    .isPolicyDataVerified(),
                PolicyDataNotVerified()
            );

            require(
                INewtonPolicyData(policyDataAddresses[i]).attest(policyData[i]),
                PolicyDataAttestationFailed()
            );
            require(policyData[i].expireBlock >= currentBlock, PolicyDataExpired());

            unchecked {
                ++i;
            }
        }
    }
}
"
    },
    "lib/eigenlayer-middleware/lib/openzeppelin-contracts-upgradeable/contracts/utils/AddressUpgradeable.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library AddressUpgradeable {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     *
     * Furthermore, `isContract` will also return true if the target contract within
     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
     * which only has an effect at the end of a transaction.
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}
"
    },
    "lib/eigenlayer-middleware/lib/openzeppelin-contracts-upgradeable/contracts/utils/ContextUpgradeable.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract ContextUpgradeable is Initializable {
    function __Context_init() internal onlyInitializing {
    }

    function __Context_init_unchained() internal onlyInitializing {
    }
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}
"
    },
    "lib/eigenlayer-middleware/src/libraries/BN254.sol": {
      "content": "// SPDX-License-Identifier: MIT
// several functions are taken or adapted from https://github.com/HarryR/solcrypto/blob/master/contracts/altbn128.sol (MIT license):
// Copyright 2017 Christian Reitwiessner
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.

// The remainder of the code in this library is written by LayrLabs Inc. and is also under an MIT license

pragma solidity ^0.8.27;

/**
 * @title Library for operations on the BN254 elliptic curve.
 * @author Layr Labs, Inc.
 * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
 * @notice Contains BN254 parameters, common operations (addition, scalar mul, pairing), and BLS signature functionality.
 */
library BN254 {
    // modulus for the underlying field F_p of the elliptic curve
    uint256 internal constant FP_MODULUS =
        21888242871839275222246405745257275088696311157297823662689037894645226208583;
    // modulus for the underlying field F_r of the elliptic curve
    uint256 internal constant FR_MODULUS =
        21888242871839275222246405745257275088548364400416034343698204186575808495617;

    struct G1Point {
        uint256 X;
        uint256 Y;
    }

    // Encoding of field elements is: X[1] * i + X[0]
    struct G2Point {
        uint256[2] X;
        uint256[2] Y;
    }

    /// @dev Thrown when the sum of two points of G1 fails
    error ECAddFailed();
    /// @dev Thrown when the scalar multiplication of a point of G1 fails
    error ECMulFailed();
    /// @dev Thrown when the scalar is too large.
    error ScalarTooLarge();
    /// @dev Thrown when the pairing check fails
    error ECPairingFailed();
    /// @dev Thrown when the exponentiation mod fails
    error ExpModFailed();

    function generatorG1() internal pure returns (G1Point memory) {
        return G1Point(1, 2);
    }

    // generator of group G2
    /// @dev Generator point in F_q2 is of the form: (x0 + ix1, y0 + iy1).
    uint256 internal constant G2x1 =
        11559732032986387107991004021392285783925812861821192530917403151452391805634;
    uint256 internal constant G2x0 =
        10857046999023057135944570762232829481370756359578518086990519993285655852781;
    uint256 internal constant G2y1 =
        4082367875863433681332203403145435568316851327593401208105741076214120093531;
    uint256 internal constant G2y0 =
        8495653923123431417604973247489272438418190587263600148770280649306958101930;

    /// @notice returns the G2 generator
    /// @dev mind the ordering of the 1s and 0s!
    ///      this is because of the (unknown to us) convention used in the bn254 pairing precompile contract
    ///      "Elements a * i + b of F_p^2 are encoded as two elements of F_p, (a, b)."
    ///      https://github.com/ethereum/EIPs/blob/master/EIPS/eip-197.md#encoding
    function generatorG2() internal pure returns (G2Point memory) {
        return G2Point([G2x1, G2x0], [G2y1, G2y0]);
    }

    // negation of the generator of group G2
    /// @dev Generator point in F_q2 is of the form: (x0 + ix1, y0 + iy1).
    uint256 internal constant nG2x1 =
        11559732032986387107991004021392285783925812861821192530917403151452391805634;
    uint256 internal constant nG2x0 =
        10857046999023057135944570762232829481370756359578518086990519993285655852781;
    uint256 internal constant nG2y1 =
        17805874995975841540914202342111839520379459829704422454583296818431106115052;
    uint256 internal constant nG2y0 =
        13392588948715843804641432497768002650278120570034223513918757245338268106653;

    function negGeneratorG2() internal pure returns (G2Point memory) {
        return G2Point([nG2x1, nG2x0], [nG2y1, nG2y0]);
    }

    bytes32 internal constant powersOfTauMerkleRoot =
        0x22c998e49752bbb1918ba87d6d59dd0e83620a311ba91dd4b2cc84990b31b56f;

    /**
     * @param p Some point in G1.
     * @return The negation of `p`, i.e. p.plus(p.negate()) should be zero.
     */
    function negate(
        G1Point memory p
    ) internal pure returns (G1Point memory) {
        // The prime q in the base field F_q for G1
        if (p.X == 0 && p.Y == 0) {
            return G1Point(0, 0);
        } else {
            return G1Point(p.X, FP_MODULUS - (p.Y % FP_MODULUS));
        }
    }

    /**
     * @return r the sum of two points of G1
     */
    function plus(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
        uint256[4] memory input;
        input[0] = p1.X;
        input[1] = p1.Y;
        input[2] = p2.X;
        input[3] = p2.Y;
        bool success;

        // solium-disable-next-line security/no-inline-assembly
        assembly {
            success := staticcall(sub(gas(), 2000), 6, input, 0x80, r, 0x40)
            // Use "invalid" to make gas estimation work
            switch success
            case 0 { invalid() }
        }

        require(success, ECAddFailed());
    }

    /**
     * @notice an optimized ecMul implementation that takes O(log_2(s)) ecAdds
     * @param p the point to multiply
     * @param s the scalar to multiply by
     * @dev this function is only safe to use if the scalar is 9 bits or less
     */
    function scalar_mul_tiny(
        BN254.G1Point memory p,
        uint16 s
    ) internal view returns (BN254.G1Point memory) {
        require(s < 2 ** 9, ScalarTooLarge());

        // if s is 1 return p
        if (s == 1) {
            return p;
        }

        // the accumulated product to return
        BN254.G1Point memory acc = BN254.G1Point(0, 0);
        // the 2^n*p to add to the accumulated product in each iteration
        BN254.G1Point memory p2n = p;
        // value of most significant bit
        uint16 m = 1;
        // index of most significant bit
        uint8 i = 0;

        //loop until we reach the most significant bit
        while (s >= m) {
            unchecked {
                // if the  current bit is 1, add the 2^n*p to the accumulated product
                if ((s >> i) & 1 == 1) {
                    acc = plus(acc, p2n);
                }
                // double the 2^n*p for the next iteration
                p2n = plus(p2n, p2n);

                // increment the index and double the value of the most significant bit
                m <<= 1;
                ++i;
            }
        }

        // return the accumulated product
        return acc;
    }

    /**
     * @return r the product of a point on G1 and a scalar, i.e.
     *         p == p.scalar_mul(1) and p.plus(p) == p.scalar_mul(2) for all
     *         points p.
     */
    function scalar_mul(G1Point memory p, uint256 s) internal view returns (G1Point memory r) {
        uint256[3] memory input;
        input[0] = p.X;
        input[1] = p.Y;
        input[2] = s;
        bool success;
        // solium-disable-next-line security/no-inline-assembly
        assembly {
            success := staticcall(sub(gas(), 2000), 7, input, 0x60, r, 0x40)
            // Use "invalid" to make gas estimation work
            switch success
            case 0 { invalid() }
        }
        require(success, ECMulFailed());
    }

    /**
     *  @return The result of computing the pairing check
     *         e(p1[0], p2[0]) *  .... * e(p1[n], p2[n]) == 1
     *         For example,
     *         pairing([P1(), P1().negate()], [P2(), P2()]) should return true.
     */
    function pairing(
        G1Point memory a1,
        G2Point memory a2,
        G1Point memory b1,
        G2Point memory b2
    ) internal view returns (bool) {
        G1Point[2] memory p1 = [a1, b1];
        G2Point[2] memory p2 = [a2, b2];

        uint256[12] memory input;

        for (uint256 i = 0; i < 2; i++) {
            uint256 j = i * 6;
            input[j + 0] = p1[i].X;
            input[j + 1] = p1[i].Y;
            input[j + 2] = p2[i].X[0];
            input[j + 3] = p2[i].X[1];
            input[j + 4] = p2[i].Y[0];
            input[j + 5] = p2[i].Y[1];
        }

        uint256[1] memory out;
        bool success;

        // solium-disable-next-line security/no-inline-assembly
        assembly {
            success := staticcall(sub(gas(), 2000), 8, input, mul(12, 0x20), out, 0x20)
            // Use "invalid" to make gas estimation work
            switch success
            case 0 { invalid() }
        }

        require(success, ECPairingFailed());

        return out[0] != 0;
    }

    /**
     * @notice This function is functionally the same as pairing(), however it specifies a gas limit
     *         the user can set, as a precompile may use the entire gas budget if it reverts.
     */
    function safePairing(
        G1Point memory a1,
        G2Point memory a2,
        G1Point memory b1,
        G2Point memory b2,
        uint256 pairingGas
    ) internal view returns (bool, bool) {
        G1Point[2] memory p1 = [a1, b1];
        G2Point[2] memory p2 = [a2, b2];

        uint256[12] memory input;

        for (uint256 i = 0; i < 2; i++) {
            uint256 j = i * 6;
            input[j + 0] = p1[i].X;
            input[j + 1] = p1[i].Y;
            input[j + 2] = p2[i].X[0];
            input[j + 3] = p2[i].X[1];
            input[j + 4] = p2[i].Y[0];
            input[j + 5] = p2[i].Y[1];
        }

        uint256[1] memory out;
        bool success;

        // solium-disable-next-line security/no-inline-assembly
        assembly {
            success := staticcall(pairingGas, 8, input, mul(12, 0x20), out, 0x20)
        }

        //Out is the output of the pairing precompile, either 0 or 1 based on whether the two pairings are equal.
        //Success is true if the precompile actually goes through (aka all inputs are valid)

        return (success, out[0] != 0);
    }

    /// @return hashedG1 the keccak256 hash of the G1 Point
    /// @dev used for BLS signatures
    function hashG1Point(
        BN254.G1Point memory pk
    ) internal pure returns (bytes32 hashedG1) {
        assembly {
            mstore(0, mload(pk))
            mstore(0x20, mload(add(0x20, pk)))
            hashedG1 := keccak256(0, 0x40)
        }
    }

    /// @return the keccak256 hash of the G2 Point
    /// @dev used for BLS signatures
    function hashG2Point(
        BN254.G2Point memory pk
    ) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked(pk.X[0], pk.X[1], pk.Y[0], pk.Y[1]));
    }

    /**
     * @notice adapted from https://github.com/HarryR/solcrypto/blob/master/contracts/altbn128.sol
     */
    function hashToG1(
        bytes32 _x
    ) internal view returns (G1Point memory) {
        uint256 beta = 0;
        uint256 y = 0;

        uint256 x = uint256(_x) % FP_MODULUS;

        while (true) {
            (beta, y) = findYFromX(x);

            // y^2 == beta
            if (beta == mulmod(y, y, FP_MODULUS)) {
                return G1Point(x, y);
            }

            x = addmod(x, 1, FP_MODULUS);
        }
        return G1Point(0, 0);
    }

    /**
     * Given X, find Y
     *
     *   where y = sqrt(x^3 + b)
     *
     * Returns: (x^3 + b), y
     */
    function findYFromX(
        uint256 x
    ) internal view returns (uint256, uint256) {
        // beta = (x^3 + b) % p
        uint256 beta = addmod(mulmod(mulmod(x, x, FP_MODULUS), x, FP_MODULUS), 3, FP_MODULUS);

        // y^2 = x^3 + b
        // this acts like: y = sqrt(beta) = beta^((p+1) / 4)
        uint256 y = expMod(
            beta, 0xc19139cb84c680a6e14116da060561765e05aa45a1c72a34f082305b61f3f52, FP_MODULUS
        );

        return (beta, y);
    }

    function expMod(
        uint256 _base,
        uint256 _exponent,
        uint256 _modulus
    ) internal view returns (uint256 retval) {
        bool success;
        uint256[1] memory output;
        uint256[6] memory input;
        input[0] = 0x20; // baseLen = new(big.Int).SetBytes(getData(input, 0, 32))
        input[1] = 0x20; // expLen  = new(big.Int).SetBytes(getData(input, 32, 32))
        input[2] = 0x20; // modLen  = new(big.Int).SetBytes(getData(input, 64, 32))
        input[3] = _base;
        input[4] = _exponent;
        input[5] = _modulus;
        assembly {
            success := staticcall(sub(gas(), 2000), 5, input, 0xc0, output, 0x20)
            // Use "invalid" to make gas estimation work
            switch success
            case 0 { invalid() }
        }
        require(success, ExpModFailed());
        return output[0];
    }
}
"
    },
    "lib/eigenlayer-middleware/src/interfaces/IBLSSignatureChecker.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;

import {ISlashingRegistryCoordinator} from "./ISlashingRegistryCoordinator.sol";
import {IBLSApkRegistry} from "./IBLSApkRegistry.sol";
import {IStakeRegistry, IDelegationManager} from "./IStakeRegistry.sol";

import {BN254} from "../libraries/BN254.sol";

interface IBLSSignatureCheckerErrors {
    /// @notice Thrown when the caller is not the registry coordinator owner.
    error OnlyRegistryCoordinatorOwner();
    /// @notice Thrown when the quorum numbers input in is empty.
    error InputEmptyQuorumNumbers();
    /// @notice Thrown when two array parameters have mismatching lengths.
    error InputArrayLengthMismatch();
    /// @notice Thrown when the non-signer pubkey length does not match non-signer bitmap indices length.
    error InputNonSignerLengthMismatch();
    /// @notice Thrown when the reference block number is invalid.
    error InvalidReferenceBlocknumber();
    /// @notice Thrown when the non signer pubkeys are not sorted.
    error NonSignerPubkeysNotSorted();
    /// @notice Thrown when StakeRegistry updates have not been updated within withdrawalDelayBlocks window
    error StaleStakesForbidden();
    /// @notice Thrown when the quorum apk hash in storage does not match provided quorum apk.
    error InvalidQuorumApkHash();
    /// @notice Thrown when BLS pairing precompile call fails.
    error InvalidBLSPairingKey();
    /// @notice Thrown when BLS signature is invalid.
    error InvalidBLSSignature();
}

interface IBLSSignatureCheckerTypes {
    /// @notice Contains bitmap and pubkey hash information for non-signing operators.
    /// @param quorumBitmaps Array of bitmaps indicating which quorums each non-signer was registered for.
    /// @param pubkeyHashes Array of BLS public key hashes for each non-signer.
    struct NonSignerInfo {
        uint256[] quorumBitmaps;
        bytes32[] pubkeyHashes;
    }

    /// @notice Contains non-signer information and aggregated signature data for BLS verification.
    /// @param nonSignerQuorumBitmapIndices The indices of all non-signer quorum bitmaps.
    /// @param nonSignerPubkeys The G1 public keys of all non-signers.
    /// @param quorumApks The aggregate G1 public key of each quorum.
    /// @param apkG2 The aggregate G2 public key of all signers.
    /// @param sigma The aggregate G1 signature of all signers.
    /// @param quorumApkIndices The indices of each quorum's aggregate public key in the APK registry.
    /// @param totalStakeIndices The indices of each quorum's total stake in the stake registry.
    /// @param nonSignerStakeIndices The indices of each non-signer's stake within each quorum.
    /// @dev Used as input to checkSignatures() to verify BLS signatures.
    struct NonSignerStakesAndSignature {
        uint32[] nonSignerQuorumBitmapIndices;
        BN254.G1Point[] nonSignerPubkeys;
        BN254.G1Point[] quorumApks;
        BN254.G2Point apkG2;
        BN254.G1Point sigma;
        uint32[] quorumApkIndices;
        uint32[] totalStakeIndices;
        uint32[][] nonSignerStakeIndices;
    }

    /// @notice Records the total stake amounts for operators in each quorum.
    /// @param signedStakeForQuorum Array of total stake amounts from operators who signed, per quorum.
    /// @param totalStakeForQuorum Array of total stake amounts from all operators, per quorum.
    /// @dev Used to track stake distribution and calculate quorum thresholds. Array indices correspond to quorum numbers.
    struct QuorumStakeTotals {
        uint96[] signedStakeForQuorum;
        uint96[] totalStakeForQuorum;
    }
}

interface IBLSSignatureCheckerEvents is IBLSSignatureCheckerTypes {
    /// @notice Emitted when `staleStakesForbiddenUpdate` is set.
    event StaleStakesForbiddenUpdate(bool value);
}

interface IBLSSignatureChecker is IBLSSignatureCheckerErrors, IBLSSignatureCheckerEvents {
    /* STATE */

    /*
     * @notice Returns the address of the registry coordinator contract.
     * @return The address of the registry coordinator.
     * @dev This value is immutable and set during contract construction.
     */
    function registryCoordinator() external view returns (ISlashingRegistryCoordinator);

    /*
     * @notice Returns the address of the stake registry contract.
     * @return The address of the stake registry.
     * @dev This value is immutable and set during contract construction.
     */
    function stakeRegistry() external view returns (IStakeRegistry);

    /*
     * @notice Returns the address of the BLS APK registry contract.
     * @return The address of the BLS APK registry.
     * @dev This value is immutable and set during contract construction.
     */
    function blsApkRegistry() external view returns (IBLSApkRegistry);

    /*
     * @notice Returns the address of the delegation manager contract.
     * @return The address of the delegation manager.
     * @dev This value is immutable and set during contract construction.
     */
    function delegation() external view returns (IDelegationManager);

    /*
     * @notice Returns whether stale stakes are forbidden in signature verification.
     * @return True if stal

Tags:
ERC20, ERC165, Multisig, Voting, Upgradeable, Multi-Signature, Factory|addr:0x9f0b51b48bd8c1daa334e7a12cdf8dc1124da620|verified:true|block:23472334|tx:0x14a4b70b7964d5da739dbf1c577ebaa6a2199792fb63ec20a5e4c817628c9d47|first_check:1759221177

Submitted on: 2025-09-30 10:32:58

Comments

Log in to comment.

No comments yet.