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/core/NewtonPolicyDataFactory.sol": {
"content": "// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.27;
import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
import "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
import "@openzeppelin/contracts/utils/Create2.sol";
import {IERC165} from "@openzeppelin/contracts/interfaces/IERC165.sol";
import {NewtonMessage} from "./NewtonMessage.sol";
import {INewtonPolicyData} from "../interfaces/INewtonPolicyData.sol";
import {NewtonPolicyData} from "./NewtonPolicyData.sol";
import {ChainLib} from "../libraries/ChainLib.sol";
contract NewtonPolicyDataFactory is OwnableUpgradeable {
address public implementation;
ProxyAdmin public proxyAdmin;
mapping(address => NewtonMessage.VerificationInfo) public policyDataVerifications;
mapping(address => bool) public verifiers;
mapping(address => address[]) public ownersToPolicyData;
address[] public policyDataOwners;
event PolicyDataVerificationUpdated(
address policyData, NewtonMessage.VerificationInfo verificationInfo
);
event PolicyDataDeployed(address policyData, INewtonPolicyData.PolicyDataInfo policyDataInfo);
event VerifierAdded(address verifier);
event VerifierRemoved(address verifier);
constructor() {
_disableInitializers();
}
function initialize(
address owner
) public initializer {
__Ownable_init();
_transferOwnership(owner);
implementation = address(new NewtonPolicyData());
proxyAdmin = new ProxyAdmin();
verifiers[owner] = true;
}
/* ERRORS */
error OnlyNewtonPolicyData();
error InterfaceNotSupported();
error OnlyVerifiers();
/* Modifiers */
modifier onlyNewtonPolicyData() {
require(msg.sender.code.length > 0, OnlyNewtonPolicyData());
bytes4 interfaceId = type(INewtonPolicyData).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()
);
_;
}
modifier onlyVerifiers() {
require(msg.sender == owner() || verifiers[msg.sender], OnlyVerifiers());
_;
}
function deployPolicyData(
string memory _wasmCid,
string memory _wasmArgs,
uint32 _expireAfter,
string memory _metadataCid,
address _owner
) external returns (address policyDataAddr) {
bytes memory initData = abi.encodeWithSelector(
NewtonPolicyData.initialize.selector,
address(this),
_wasmCid,
_wasmArgs,
_expireAfter,
_metadataCid,
_owner
);
bytes32 salt = keccak256(
abi.encodePacked(address(this), _wasmCid, _wasmArgs, _expireAfter, _metadataCid, _owner)
);
bytes memory bytecode = abi.encodePacked(
type(TransparentUpgradeableProxy).creationCode,
abi.encode(implementation, address(proxyAdmin), initData)
);
address proxy;
assembly {
proxy := create2(0, add(bytecode, 32), mload(bytecode), salt)
if iszero(proxy) { revert(0, 0) }
}
policyDataAddr = proxy;
ChainLib.requireSupportedChain();
if (ChainLib.isMainnet()) {
policyDataVerifications[policyDataAddr] =
NewtonMessage.VerificationInfo(address(0), false, 0);
} else {
// set policy verification to default true for testnet
policyDataVerifications[policyDataAddr] =
NewtonMessage.VerificationInfo(owner(), true, block.timestamp);
}
if (ownersToPolicyData[_owner].length == 0) {
policyDataOwners.push(_owner);
}
ownersToPolicyData[_owner].push(policyDataAddr);
emit PolicyDataDeployed(
policyDataAddr,
INewtonPolicyData.PolicyDataInfo(
policyDataAddr, _owner, _metadataCid, _wasmCid, _wasmArgs, _expireAfter
)
);
}
function computePolicyDataAddress(
string memory _wasmCid,
string memory _wasmArgs,
uint32 _expireAfter,
string memory _metadataCid,
address _owner
) public view returns (address predicted) {
bytes memory initData = abi.encodeWithSelector(
NewtonPolicyData.initialize.selector,
address(this),
_wasmCid,
_wasmArgs,
_expireAfter,
_metadataCid,
_owner
);
bytes32 salt = keccak256(
abi.encodePacked(address(this), _wasmCid, _wasmArgs, _expireAfter, _metadataCid, _owner)
);
bytes memory bytecode = abi.encodePacked(
type(TransparentUpgradeableProxy).creationCode,
abi.encode(implementation, address(proxyAdmin), initData)
);
predicted = Create2.computeAddress(salt, keccak256(bytecode));
}
function setPolicyDataVerified(address policyDataAddr, bool verified) external onlyVerifiers {
policyDataVerifications[policyDataAddr] =
NewtonMessage.VerificationInfo(msg.sender, verified, block.timestamp);
emit PolicyDataVerificationUpdated(policyDataAddr, policyDataVerifications[policyDataAddr]);
}
function getPolicyDataVerificationInfo(
address policyDataAddr
) external view returns (NewtonMessage.VerificationInfo memory) {
return policyDataVerifications[policyDataAddr];
}
function addVerifier(
address verifier
) external onlyOwner {
verifiers[verifier] = true;
emit VerifierAdded(verifier);
}
function removeVerifier(
address verifier
) external onlyOwner {
verifiers[verifier] = false;
emit VerifierRemoved(verifier);
}
function getAllPolicyDataByOwner(
address owner
) external view returns (address[] memory) {
return ownersToPolicyData[owner];
}
function getAllPolicyDataOwners() external view returns (address[] memory) {
return policyDataOwners;
}
}
"
},
"lib/eigenlayer-middleware/lib/openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/transparent/TransparentUpgradeableProxy.sol)
pragma solidity ^0.8.0;
import "../ERC1967/ERC1967Proxy.sol";
/**
* @dev Interface for {TransparentUpgradeableProxy}. In order to implement transparency, {TransparentUpgradeableProxy}
* does not implement this interface directly, and some of its functions are implemented by an internal dispatch
* mechanism. The compiler is unaware that these functions are implemented by {TransparentUpgradeableProxy} and will not
* include them in the ABI so this interface must be used to interact with it.
*/
interface ITransparentUpgradeableProxy is IERC1967 {
function admin() external view returns (address);
function implementation() external view returns (address);
function changeAdmin(address) external;
function upgradeTo(address) external;
function upgradeToAndCall(address, bytes memory) external payable;
}
/**
* @dev This contract implements a proxy that is upgradeable by an admin.
*
* To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector
* clashing], which can potentially be used in an attack, this contract uses the
* https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two
* things that go hand in hand:
*
* 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if
* that call matches one of the admin functions exposed by the proxy itself.
* 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the
* implementation. If the admin tries to call a function on the implementation it will fail with an error that says
* "admin cannot fallback to proxy target".
*
* These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing
* the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due
* to sudden errors when trying to call a function from the proxy implementation.
*
* Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way,
* you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy.
*
* NOTE: The real interface of this proxy is that defined in `ITransparentUpgradeableProxy`. This contract does not
* inherit from that interface, and instead the admin functions are implicitly implemented using a custom dispatch
* mechanism in `_fallback`. Consequently, the compiler will not produce an ABI for this contract. This is necessary to
* fully implement transparency without decoding reverts caused by selector clashes between the proxy and the
* implementation.
*
* WARNING: It is not recommended to extend this contract to add additional external functions. If you do so, the compiler
* will not check that there are no selector conflicts, due to the note above. A selector clash between any new function
* and the functions declared in {ITransparentUpgradeableProxy} will be resolved in favor of the new one. This could
* render the admin operations inaccessible, which could prevent upgradeability. Transparency may also be compromised.
*/
contract TransparentUpgradeableProxy is ERC1967Proxy {
/**
* @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and
* optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}.
*/
constructor(address _logic, address admin_, bytes memory _data) payable ERC1967Proxy(_logic, _data) {
_changeAdmin(admin_);
}
/**
* @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin.
*
* CAUTION: This modifier is deprecated, as it could cause issues if the modified function has arguments, and the
* implementation provides a function with the same selector.
*/
modifier ifAdmin() {
if (msg.sender == _getAdmin()) {
_;
} else {
_fallback();
}
}
/**
* @dev If caller is the admin process the call internally, otherwise transparently fallback to the proxy behavior
*/
function _fallback() internal virtual override {
if (msg.sender == _getAdmin()) {
bytes memory ret;
bytes4 selector = msg.sig;
if (selector == ITransparentUpgradeableProxy.upgradeTo.selector) {
ret = _dispatchUpgradeTo();
} else if (selector == ITransparentUpgradeableProxy.upgradeToAndCall.selector) {
ret = _dispatchUpgradeToAndCall();
} else if (selector == ITransparentUpgradeableProxy.changeAdmin.selector) {
ret = _dispatchChangeAdmin();
} else if (selector == ITransparentUpgradeableProxy.admin.selector) {
ret = _dispatchAdmin();
} else if (selector == ITransparentUpgradeableProxy.implementation.selector) {
ret = _dispatchImplementation();
} else {
revert("TransparentUpgradeableProxy: admin cannot fallback to proxy target");
}
assembly {
return(add(ret, 0x20), mload(ret))
}
} else {
super._fallback();
}
}
/**
* @dev Returns the current admin.
*
* TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
* https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
* `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
*/
function _dispatchAdmin() private returns (bytes memory) {
_requireZeroValue();
address admin = _getAdmin();
return abi.encode(admin);
}
/**
* @dev Returns the current implementation.
*
* TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
* https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
* `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`
*/
function _dispatchImplementation() private returns (bytes memory) {
_requireZeroValue();
address implementation = _implementation();
return abi.encode(implementation);
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {AdminChanged} event.
*/
function _dispatchChangeAdmin() private returns (bytes memory) {
_requireZeroValue();
address newAdmin = abi.decode(msg.data[4:], (address));
_changeAdmin(newAdmin);
return "";
}
/**
* @dev Upgrade the implementation of the proxy.
*/
function _dispatchUpgradeTo() private returns (bytes memory) {
_requireZeroValue();
address newImplementation = abi.decode(msg.data[4:], (address));
_upgradeToAndCall(newImplementation, bytes(""), false);
return "";
}
/**
* @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified
* by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the
* proxied contract.
*/
function _dispatchUpgradeToAndCall() private returns (bytes memory) {
(address newImplementation, bytes memory data) = abi.decode(msg.data[4:], (address, bytes));
_upgradeToAndCall(newImplementation, data, true);
return "";
}
/**
* @dev Returns the current admin.
*
* CAUTION: This function is deprecated. Use {ERC1967Upgrade-_getAdmin} instead.
*/
function _admin() internal view virtual returns (address) {
return _getAdmin();
}
/**
* @dev To keep this contract fully transparent, all `ifAdmin` functions must be payable. This helper is here to
* emulate some proxy functions being non-payable while still allowing value to pass through.
*/
function _requireZeroValue() private {
require(msg.value == 0);
}
}
"
},
"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;
}
"
},
"lib/eigenlayer-middleware/lib/openzeppelin-contracts/contracts/proxy/transparent/ProxyAdmin.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.3) (proxy/transparent/ProxyAdmin.sol)
pragma solidity ^0.8.0;
import "./TransparentUpgradeableProxy.sol";
import "../../access/Ownable.sol";
/**
* @dev This is an auxiliary contract meant to be assigned as the admin of a {TransparentUpgradeableProxy}. For an
* explanation of why you would want to use this see the documentation for {TransparentUpgradeableProxy}.
*/
contract ProxyAdmin is Ownable {
/**
* @dev Returns the current implementation of `proxy`.
*
* Requirements:
*
* - This contract must be the admin of `proxy`.
*/
function getProxyImplementation(ITransparentUpgradeableProxy proxy) public view virtual returns (address) {
// We need to manually run the static call since the getter cannot be flagged as view
// bytes4(keccak256("implementation()")) == 0x5c60da1b
(bool success, bytes memory returndata) = address(proxy).staticcall(hex"5c60da1b");
require(success);
return abi.decode(returndata, (address));
}
/**
* @dev Returns the current admin of `proxy`.
*
* Requirements:
*
* - This contract must be the admin of `proxy`.
*/
function getProxyAdmin(ITransparentUpgradeableProxy proxy) public view virtual returns (address) {
// We need to manually run the static call since the getter cannot be flagged as view
// bytes4(keccak256("admin()")) == 0xf851a440
(bool success, bytes memory returndata) = address(proxy).staticcall(hex"f851a440");
require(success);
return abi.decode(returndata, (address));
}
/**
* @dev Changes the admin of `proxy` to `newAdmin`.
*
* Requirements:
*
* - This contract must be the current admin of `proxy`.
*/
function changeProxyAdmin(ITransparentUpgradeableProxy proxy, address newAdmin) public virtual onlyOwner {
proxy.changeAdmin(newAdmin);
}
/**
* @dev Upgrades `proxy` to `implementation`. See {TransparentUpgradeableProxy-upgradeTo}.
*
* Requirements:
*
* - This contract must be the admin of `proxy`.
*/
function upgrade(ITransparentUpgradeableProxy proxy, address implementation) public virtual onlyOwner {
proxy.upgradeTo(implementation);
}
/**
* @dev Upgrades `proxy` to `implementation` and calls a function on the new implementation. See
* {TransparentUpgradeableProxy-upgradeToAndCall}.
*
* Requirements:
*
* - This contract must be the admin of `proxy`.
*/
function upgradeAndCall(
ITransparentUpgradeableProxy proxy,
address implementation,
bytes memory data
) public payable virtual onlyOwner {
proxy.upgradeToAndCall{value: msg.value}(implementation, data);
}
}
"
},
"lib/eigenlayer-middleware/lib/openzeppelin-contracts/contracts/utils/Create2.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Create2.sol)
pragma solidity ^0.8.0;
/**
* @dev Helper to make usage of the `CREATE2` EVM opcode easier and safer.
* `CREATE2` can be used to compute in advance the address where a smart
* contract will be deployed, which allows for interesting new mechanisms known
* as 'counterfactual interactions'.
*
* See the https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP] for more
* information.
*/
library Create2 {
/**
* @dev Deploys a contract using `CREATE2`. The address where the contract
* will be deployed can be known in advance via {computeAddress}.
*
* The bytecode for a contract can be obtained from Solidity with
* `type(contractName).creationCode`.
*
* Requirements:
*
* - `bytecode` must not be empty.
* - `salt` must have not been used for `bytecode` already.
* - the factory must have a balance of at least `amount`.
* - if `amount` is non-zero, `bytecode` must have a `payable` constructor.
*/
function deploy(uint256 amount, bytes32 salt, bytes memory bytecode) internal returns (address addr) {
require(address(this).balance >= amount, "Create2: insufficient balance");
require(bytecode.length != 0, "Create2: bytecode length is zero");
/// @solidity memory-safe-assembly
assembly {
addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt)
}
require(addr != address(0), "Create2: Failed on deploy");
}
/**
* @dev Returns the address where a contract will be stored if deployed via {deploy}. Any change in the
* `bytecodeHash` or `salt` will result in a new destination address.
*/
function computeAddress(bytes32 salt, bytes32 bytecodeHash) internal view returns (address) {
return computeAddress(salt, bytecodeHash, address(this));
}
/**
* @dev Returns the address where a contract will be stored if deployed via {deploy} from a contract located at
* `deployer`. If `deployer` is this contract's address, returns the same value as {computeAddress}.
*/
function computeAddress(bytes32 salt, bytes32 bytecodeHash, address deployer) internal pure returns (address addr) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40) // Get free memory pointer
// | | ↓ ptr ... ↓ ptr + 0x0B (start) ... ↓ ptr + 0x20 ... ↓ ptr + 0x40 ... |
// |-------------------|---------------------------------------------------------------------------|
// | bytecodeHash | CCCCCCCCCCCCC...CC |
// | salt | BBBBBBBBBBBBB...BB |
// | deployer | 000000...0000AAAAAAAAAAAAAAAAAAA...AA |
// | 0xFF | FF |
// |-------------------|---------------------------------------------------------------------------|
// | memory | 000000...00FFAAAAAAAAAAAAAAAAAAA...AABBBBBBBBBBBBB...BBCCCCCCCCCCCCC...CC |
// | keccak(start, 85) | ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ |
mstore(add(ptr, 0x40), bytecodeHash)
mstore(add(ptr, 0x20), salt)
mstore(ptr, deployer) // Right-aligned with 12 preceding garbage bytes
let start := add(ptr, 0x0b) // The hashed data starts at the final garbage byte which we will set to 0xff
mstore8(start, 0xff)
addr := keccak256(start, 85)
}
}
}
"
},
"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/core/NewtonMessage.sol": {
"content": "// SPDX-License-Identifier: Apache-2.0
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/interfaces/INewtonPolicyData.sol": {
"content": "// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.27;
import {IERC165} from "@openzeppelin/contracts/interfaces/IERC165.sol";
import {NewtonMessage} from "../core/NewtonMessage.sol";
/// @notice Interface for a NewtonPolicyData
interface INewtonPolicyData is IERC165 {
enum AttestationType {
ECDSA,
BN254,
BLS12_381,
GROTH16
}
struct PolicyDataInfo {
address policyDataAddress;
address owner;
string metadataCid;
string wasmCid;
string wasmArgsCid;
uint32 expireAfter;
}
struct AttestationInfo {
/// Only used for ECDSA or BLS signature attestation type
address[] attesters;
/// The attestation type for the policy data
AttestationType attestationType;
/// The verifier contract address. Only used for ZK-SNARK groth16 attestation type
address verifier;
/// Only used for ZK-SNARK groth16 attestation type
bytes32 verificationKey;
}
/**
* @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 data.
* @param metadataCid The metadata CID to set for the policy data.
*/
function setMetadataCid(
string calldata metadataCid
) external;
/**
* @notice Retrieves the attestation info for the policy.
* @return The attestation info for the policy.
*/
function getAttestationInfo() external view returns (AttestationInfo memory);
/**
* @notice Sets the attestation info for the policy data.
* @param attestationInfo The attestation info to set for the policy data.
*/
function setAttestationInfo(
AttestationInfo calldata attestationInfo
) external;
/**
* @notice Retrieves the policy data location (IPFS CID for WASM plugin).
* @return The policy data location for the policy data contract.
*/
function getWasmCid() external view returns (string memory);
/**
* @notice Retrieves the policy data arguments location (IPFS CID for WASM plugin args).
* @return The policy data arguments location for the policy data contract.
*/
function getWasmArgsCid() external view returns (string memory);
/**
* @notice Retrieves the expire after block number for the policy data.
* @return The block number after which the policy data should expire.
*/
function getExpireAfter() external view returns (uint32);
/**
* @notice Attest the policy data for the given task.
* @param policyData The policy data to attest.
* @return True if the policy data is valid, false otherwise.
*/
function attest(
NewtonMessage.PolicyData calldata policyData
) external view returns (bool);
/**
* @notice Retrieves the policy data verified status.
* @return The policy data verified status.
*/
function isPolicyDataVerified() external view returns (bool);
}
"
},
"src/core/NewtonPolicyData.sol": {
"content": "// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.27;
import "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol";
import "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
import "@openzeppelin-upgrades/contracts/utils/introspection/ERC165Upgradeable.sol";
import "@openzeppelin/contracts/interfaces/IERC165.sol";
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import "@openzeppelin/contracts/utils/Create2.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "./NewtonPolicyDataFactory.sol";
import "../interfaces/INewtonPolicyData.sol";
import "../interfaces/INewtonPolicy.sol";
import "./NewtonMessage.sol";
contract NewtonPolicyData is
Initializable,
OwnableUpgradeable,
ERC165Upgradeable,
INewtonPolicyData
{
using ECDSA for bytes32;
/* STORAGE */
address public factory;
string private _wasmCid;
string private _wasmArgs;
uint32 private _expireAfter;
string private _metadataCid;
INewtonPolicyData.AttestationInfo private _attestationInfo;
/* ERRORS */
error OnlyNewtonPolicy();
error InterfaceNotSupported();
error InvalidSignature();
error SignatureVerificationFailed();
error InvalidPolicyData(bytes data);
error InvalidAttestationInfo();
/* EVENTS */
event PolicyDataMetadataCidUpdated(string metadataCid);
event AttestationInfoUpdated(INewtonPolicyData.AttestationInfo attestationInfo);
/* Modifiers */
modifier onlyNewtonPolicy() {
require(msg.sender.code.length > 0, OnlyNewtonPolicy());
bytes4 interfaceId = type(INewtonPolicy).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()
);
_;
}
function initialize(
address _factory,
string calldata wasmCid,
string calldata wasmArgs,
uint32 expireAfter,
string calldata metadataCid,
address _owner
) public initializer {
__Ownable_init();
_transferOwnership(_owner);
__ERC165_init();
factory = _factory;
_wasmCid = wasmCid;
_wasmArgs = wasmArgs;
_expireAfter = expireAfter;
_metadataCid = metadataCid;
}
function getMetadataCid() public view returns (string memory) {
return _metadataCid;
}
function setMetadataCid(
string calldata metadataCid
) public onlyOwner {
_metadataCid = metadataCid;
emit PolicyDataMetadataCidUpdated(metadataCid);
}
function getWasmCid() public view returns (string memory) {
return _wasmCid;
}
function getWasmArgsCid() public view returns (string memory) {
return _wasmArgs;
}
function getAttestationInfo() public view returns (INewtonPolicyData.AttestationInfo memory) {
return _attestationInfo;
}
function setAttestationInfo(
INewtonPolicyData.AttestationInfo calldata attestationInfo
) public onlyOwner {
if (
attestationInfo.attestationType == AttestationType.ECDSA
|| attestationInfo.attestationType == AttestationType.BLS12_381
|| attestationInfo.attestationType == AttestationType.BN254
) {
require(attestationInfo.attesters.length > 0, InvalidAttestationInfo());
} else if (attestationInfo.attestationType == AttestationType.GROTH16) {
require(
attestationInfo.verifier != address(0)
&& attestationInfo.verificationKey != bytes32(0),
InvalidAttestationInfo()
);
}
_attestationInfo = attestationInfo;
emit AttestationInfoUpdated(attestationInfo);
}
function getExpireAfter() public view returns (uint32) {
return _expireAfter;
}
// TODO: implement the attest function
function attest(
NewtonMessage.PolicyData calldata policyData
) external view returns (bool) {
require(policyData.data.length > 0, InvalidPolicyData(policyData.data));
if (_attestationInfo.attestationType == INewtonPolicyData.AttestationType.ECDSA) {
return _verifyECDSASignature(policyData);
}
// TODO: implement other validation type verications
return false;
}
/// @notice Verifies ECDSA signature for policy data attestation
/// @param policyData The policy data containing the attestation signature
/// @return True if signature is valid, false otherwise
function _verifyECDSASignature(
NewtonMessage.PolicyData calldata policyData
) internal view returns (bool) {
// Check if attestation has the correct length (65 bytes for ECDSA signature)
if (policyData.attestation.length != 65) {
return false;
}
(address signer, ECDSA.RecoverError error) = ECDSA.tryRecover(
keccak256(
abi.encodePacked(
policyData.data,
policyData.policyDataAddress,
policyData.expireBlock,
_wasmCid,
_wasmArgs
)
),
policyData.attestation
);
if (error != ECDSA.RecoverError.NoError) {
return false;
}
// Check if the signer is in the attesters list
for (uint256 i; i < _attestationInfo.attesters.length; ++i) {
if (signer == _attestationInfo.attesters[i]) {
return true;
}
}
return false;
}
function isPolicyDataVerified() external view returns (bool) {
return
NewtonPolicyDataFactory(factory).getPolicyDataVerificationInfo(address(this)).verified;
}
/// @notice Function to check if a contract implements an interface
/// @param interfaceId The interface identifier to check
/// @return True if the contract implements the interface, false otherwise
function supportsInterface(
bytes4 interfaceId
) public view virtual override(ERC165Upgradeable, IERC165) returns (bool) {
return interfaceId == type(INewtonPolicyData).interfaceId
|| super.supportsInterface(interfaceId);
}
}
"
},
"src/libraries/ChainLib.sol": {
"content": "// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.27;
library ChainLib {
error ChainNotSupported(uint256 chainId);
// NOTE: make sure to use with requireSupportedChain modifier
function isMainnet() internal view returns (bool) {
uint256 chainId = block.chainid;
return chainId == 1 // Ethereum mainnet
|| chainId == 10 // Optimism mainnet
|| chainId == 42161 // Arbitrum One mainnet
|| chainId == 137 // Polygon mainnet
|| chainId == 8453; // Base mainnet
}
// NOTE: make sure to use with requireSupportedChain modifier
function isTestnet() internal view returns (bool) {
uint256 chainId = block.chainid;
return chainId == 11155111 // Sepolia testnet
|| chainId == 17000 // Holesky testnet
|| chainId == 84532 // Base Sepolia testnet
|| chainId == 11155420 // Optimism Sepolia testnet
|| chainId == 421614 // Arbitrum One Sepolia testnet
|| chainId == 80002; // Polygon Amoy testnet
}
// NOTE: make sure to use with requireSupportedChain modifier
function isLocal() internal view returns (bool) {
return block.chainid == 31337;
}
function isSupportedChain() internal view returns (bool) {
return isMainnet() || isTestnet() || isLocal();
}
function requireSupportedChain() internal view {
require(isSupportedChain(), ChainNotSupported(block.chainid));
}
}
"
},
"lib/eigenlayer-middleware/lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (proxy/ERC1967/ERC1967Proxy.sol)
pragma solidity ^0.8.0;
import "../Proxy.sol";
import "./ERC1967Upgrade.sol";
/**
* @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
* implementation address that can be changed. This address is stored in storage in the location specified by
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the
* implementation behind the proxy.
*/
contract ERC1967Proxy is Proxy, ERC1967Upgrade {
/**
* @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.
*
* If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded
* function call, and allows initializing the storage of the proxy like a Solidity constructor.
*/
constructor(address _logic, bytes memory _data) payable {
_upgradeToAndCall(_logic, _data, false);
}
/**
* @dev Returns the current implementation address.
*/
function _implementation() internal view virtual override returns (address impl) {
return ERC1967Upgrade._getImplementation();
}
}
"
},
"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/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/contracts/access/Ownable.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.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 Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_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);
}
}
"
},
"lib/eigenlayer-middleware/lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
"
},
"lib/eigenlayer-middleware/lib/openzeppelin-contracts-upgradeable/contracts/utils/introspection/ERC165Upgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165Upgradeable.sol";
import "../../proxy/utils/Initializable.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable {
function __ERC165_init() internal onlyInitializing {
}
function __ERC165_init_unchained() internal onlyInitializing {
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165Upgradeable).interfaceId;
}
/**
* @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/lib/openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.0;
import "../Strings.sol";
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS,
InvalidSignatureV // Deprecated in v4.8
}
function _throwError(RecoverError error) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert("ECDSA: invalid signature");
} else if (error == RecoverError.InvalidSignatureLength) {
revert("ECDSA: invalid signature length");
} else if (error == RecoverError.InvalidSignatureS) {
revert("ECDSA: invalid signature 's' value");
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature` or error string. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
/// @solidity memory-safe-assembly
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else {
return (address(0), RecoverError.InvalidSignatureLength);
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, signature);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError) {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*
* _Available since v4.2._
*/
function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, r, vs);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS);
}
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature);
}
return (signer, RecoverError.NoError);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, v, r, s);
_throwError(error);
return recovered;
}
/**
* @dev Returns an Ethereum Signed Message, created from a `hash`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) {
// 32 is the length in bytes of hash,
// enforced by the type signature above
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, "\x19Ethereum Signed Message:\
32")
mstore(0x1c, hash)
message := keccak256(0x00, 0x3c)
}
}
/**
* @dev Returns an Ethereum Signed Message, created from `s`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\
", Strings.toString(s.length), s));
}
/**
* @dev Returns an Ethereum Signed Typed Data, created from a
* `domainSeparator` and a `structHash`. This produces hash corresponding
* to the one signed with the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
* JSON-RPC method as part of EIP-712.
*
* See {recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 data) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr, "\x19\x01")
mstore(add(ptr, 0x02), domainSeparator)
mstore(add(ptr, 0x22), structHash)
data := keccak256(ptr, 0x42)
}
}
/**
* @dev Returns an Ethereum Signed Data with intended validator, created from a
* `validator` and `data` according to the version 0 of EIP-191.
*
* See {recover}.
*/
function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x00", validator, data));
}
}
"
},
"src/interfaces/INewtonPolicy.sol": {
"content": "// SPDX-License-Identifier: Apache-2.0
pragma so
Submitted on: 2025-10-14 18:38:30
Comments
Log in to comment.
No comments yet.