Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00Latest 1 from a total of 1 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Create Proof Sub... | 20734314 | 536 days ago | IN | 0.01 ETH | 0.00077437 |
Latest 3 internal transactions
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| Deposit To | 20734314 | 536 days ago | 0.01 ETH | ||||
| 0x3d602d80 | 20734314 | 536 days ago | Contract Creation | 0 ETH | |||
| 0x60e03462 | 20734307 | 536 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
ProofSubmitterFactory
Compiler Version
v0.8.17+commit.8df45f5f
Optimization Enabled:
Yes with 200 runs
Other Settings:
london EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-FileCopyrightText: 2024 P2P Validator <info@p2p.org>
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import "../proofSubmitter/ProofSubmitter.sol";
import "./IProofSubmitterFactory.sol";
import "../lib/@openzeppelin/contracts/utils/introspection/ERC165.sol";
import "../lib/@openzeppelin/contracts/proxy/Clones.sol";
/// @title ProofSubmitterFactory
/// @notice Factory for creating ProofSubmitter contract instances
contract ProofSubmitterFactory is ERC165, IProofSubmitterFactory {
/// @notice Singleton ERC-4337 entryPoint 0.6.0
address payable public constant entryPoint =
payable(0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789);
/// @notice Reference ProofSubmitter contract
ProofSubmitter public immutable i_referenceProofSubmitter;
constructor() {
i_referenceProofSubmitter = new ProofSubmitter(this);
}
/// @notice Creates a new ProofSubmitter contract instance
/// @return proofSubmitter The new ProofSubmitter contract instance
function createProofSubmitter()
external
payable
returns (ProofSubmitter proofSubmitter)
{
address proofSubmitterAddress = predictProofSubmitterAddress(
msg.sender
);
uint256 codeSize = proofSubmitterAddress.code.length;
if (codeSize > 0) {
return ProofSubmitter(payable(proofSubmitterAddress));
}
proofSubmitter = ProofSubmitter(
payable(
Clones.cloneDeterministic(
address(i_referenceProofSubmitter),
bytes32(uint256(uint160(msg.sender)))
)
)
);
proofSubmitter.initialize(msg.sender);
IEntryPointStakeManager(entryPoint).depositTo{value: msg.value}(
proofSubmitterAddress
);
}
/// @notice Predicts the address of a ProofSubmitter contract instance
/// @param _owner The owner of the ProofSubmitter contract instance
/// @return The address of the ProofSubmitter contract instance
function predictProofSubmitterAddress(
address _owner
) public view returns (address) {
return
Clones.predictDeterministicAddress(
address(i_referenceProofSubmitter),
bytes32(uint256(uint160(_owner)))
);
}
/// @notice Returns the address of the reference ProofSubmitter contract
/// @return The address of the reference ProofSubmitter contract
function getReferenceProofSubmitter() external view returns (address) {
return address(i_referenceProofSubmitter);
}
/// @inheritdoc ERC165
function supportsInterface(
bytes4 interfaceId
) public view virtual override(ERC165, IERC165) returns (bool) {
return
interfaceId == type(IProofSubmitterFactory).interfaceId ||
super.supportsInterface(interfaceId);
}
}// SPDX-FileCopyrightText: 2024 P2P Validator <info@p2p.org>
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import "./Erc4337Account.sol";
import "./IProofSubmitter.sol";
import "../proofSubmitterFactory/IProofSubmitterFactory.sol";
import "./ProofSubmitterErrors.sol";
import "./ProofSubmitterStructs.sol";
import "../lib/eigenLayer/IEigenPodManager.sol";
import "../lib/eigenLayer/IRewardsCoordinator.sol";
import "../lib/@openzeppelin/contracts/utils/Address.sol";
import "../lib/@openzeppelin/contracts/utils/introspection/ERC165.sol";
import "../lib/@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";
/// @title ProofSubmitter
/// @notice This contract is used to submit proofs to the EigenLayer EigenPod
/// @dev It uses ERC-4337 for gas sponsorship
contract ProofSubmitter is
Erc4337Account,
ProofSubmitterErrors,
ProofSubmitterStructs,
ERC165,
IProofSubmitter
{
/// @notice The EigenPodManager contract
IEigenPodManager private immutable i_eigenPodManager;
/// @notice The RewardsCoordinator contract
IRewardsCoordinator private immutable i_rewardsCoordinator;
/// @notice The ProofSubmitterFactory contract
IProofSubmitterFactory private immutable i_factory;
/// @notice The owner of the ProofSubmitter instance
address private s_owner;
/// @notice Mapping to track if an address is an operator
mapping(address => bool) private s_isOperator;
/// @notice Mapping to track allowed calldata for specific contracts and selectors
mapping(address => mapping(bytes4 => AllowedCalldata))
private s_allowedFunctionsForContracts;
/// @notice If caller is any account other than the operator or the owner, revert
modifier onlyOperatorOrOwner() {
if (!isOperator(msg.sender) && msg.sender != owner()) {
revert ProofSubmitter__CallerNeitherOperatorNorOwner(msg.sender);
}
_;
}
/// @notice If caller is any account other than the EntryPoint or the owner, revert
modifier onlyEntryPointOrOwner() {
if (msg.sender != entryPoint && msg.sender != owner()) {
revert ProofSubmitter__CallerNeitherEntryPointNorOwner(msg.sender);
}
_;
}
/// @notice If caller not factory, revert
modifier onlyFactory() {
if (msg.sender != address(i_factory)) {
revert ProofSubmitter__NotFactoryCalled(
msg.sender,
address(i_factory)
);
}
_;
}
/// @notice Constructor for ProofSubmitter template
/// @param _factory The ProofSubmitterFactory contract
constructor(IProofSubmitterFactory _factory) {
i_factory = _factory;
i_eigenPodManager = (block.chainid == 1)
? IEigenPodManager(0x91E677b07F7AF907ec9a428aafA9fc14a0d3A338)
: IEigenPodManager(0x30770d7E3e71112d7A6b7259542D1f680a70e315);
i_rewardsCoordinator = (block.chainid == 1)
? IRewardsCoordinator(0x7750d328b314EfFa365A0402CcfD489B80B0adda)
: IRewardsCoordinator(0xAcc1fb458a1317E886dB376Fc8141540537E68fE);
}
/// @inheritdoc IProofSubmitter
function initialize(address _owner) external onlyFactory {
if (_owner == address(0)) {
revert ProofSubmitter__ZeroAddressOwner();
}
bool hasPod = i_eigenPodManager.hasPod(_owner);
if (!hasPod) {
revert ProofSubmitter__OwnerShouldHaveEigenPod();
}
s_owner = _owner;
emit ProofSubmitter__Initialized(_owner);
_setInitialRules(_owner);
}
/// @inheritdoc IProofSubmitter
function setOperator(address _newOperator) external onlyOperatorOrOwner {
s_isOperator[_newOperator] = true;
emit ProofSubmitter__OperatorSet(_newOperator);
}
/// @inheritdoc IProofSubmitter
function dismissOperator(address _operator) external onlyOwner {
s_isOperator[_operator] = false;
emit ProofSubmitter__OperatorDismissed(_operator);
}
/// @inheritdoc IProofSubmitter
function setAllowedFunctionForContract(
address _contract,
bytes4 _selector,
AllowedCalldata calldata _allowedCalldata
) external onlyOwner {
_setAllowedFunctionForContract(_contract, _selector, _allowedCalldata);
}
/// @inheritdoc IProofSubmitter
function removeAllowedFunctionForContract(
address _contract,
bytes4 _selector
) external onlyOwner {
delete s_allowedFunctionsForContracts[_contract][_selector];
emit ProofSubmitter__AllowedFunctionForContractRemoved(
_contract,
_selector
);
}
/// @inheritdoc IProofSubmitter
function execute(
address _target,
bytes calldata _data
) external onlyEntryPointOrOwner {
_call(_target, _data);
}
/// @inheritdoc IProofSubmitter
function executeBatch(
address[] calldata _targets,
bytes[] calldata _data
) external onlyEntryPointOrOwner {
if (_targets.length != _data.length) {
revert ProofSubmitter__WrongArrayLengths(
_targets.length,
_data.length
);
}
for (uint256 i = 0; i < _targets.length; i++) {
_call(_targets[i], _data[i]);
}
}
/// @notice Set initial rules for the ProofSubmitter instance
/// @dev This function sets the allowed calldata for the EigenPod and the RewardsCoordinator
/// @param _owner The owner of the ProofSubmitter instance
function _setInitialRules(address _owner) private {
address pod = i_eigenPodManager.getPod(_owner);
_setAllowedFunctionForContract(
pod,
IEigenPod.startCheckpoint.selector,
AllowedCalldata({
rule: Rule({
ruleType: RuleType.AnyCalldata,
bytesCount: 0,
startIndex: 0
}),
allowedBytes: ""
})
);
_setAllowedFunctionForContract(
pod,
IEigenPod.verifyWithdrawalCredentials.selector,
AllowedCalldata({
rule: Rule({
ruleType: RuleType.AnyCalldata,
bytesCount: 0,
startIndex: 0
}),
allowedBytes: ""
})
);
_setAllowedFunctionForContract(
pod,
IEigenPod.verifyCheckpointProofs.selector,
AllowedCalldata({
rule: Rule({
ruleType: RuleType.AnyCalldata,
bytesCount: 0,
startIndex: 0
}),
allowedBytes: ""
})
);
_setAllowedFunctionForContract(
address(i_rewardsCoordinator),
IRewardsCoordinator.processClaim.selector,
AllowedCalldata({
rule: Rule({
ruleType: RuleType.Between,
bytesCount: 20,
startIndex: 44
}),
allowedBytes: abi.encodePacked(_owner)
})
);
}
/// @notice Set allowed calldata for a specific contract and selector
/// @param _contract The contract address
/// @param _selector The selector of the function
/// @param _allowedCalldata The allowed calldata for the function
function _setAllowedFunctionForContract(
address _contract,
bytes4 _selector,
AllowedCalldata memory _allowedCalldata
) private {
s_allowedFunctionsForContracts[_contract][_selector] = _allowedCalldata;
emit ProofSubmitter__AllowedFunctionForContractSet(
_contract,
_selector,
_allowedCalldata
);
}
/// @notice Call a function on a specific contract
/// @param _target The target address of the function call
/// @param _data The calldata of the function call
function _call(address _target, bytes calldata _data) private {
bytes4 selector = _getFunctionSelector(_data);
bool isAllowed = isAllowedCalldata(_target, selector, _data[4:]);
if (isAllowed) {
Address.functionCall(_target, _data);
} else {
revert ProofSubmitter__NotAllowedToCall(_target, selector);
}
}
/// @notice Returns function selector (first 4 bytes of data)
/// @param _data calldata (encoded signature + arguments)
/// @return functionSelector function selector
function _getFunctionSelector(
bytes calldata _data
) private pure returns (bytes4 functionSelector) {
if (_data.length < 4) {
revert ProofSubmitter__DataTooShort();
}
return bytes4(_data[:4]);
}
/// @inheritdoc IProofSubmitter
function getAllowedCalldata(
address _target,
bytes4 _selector
) external view returns (AllowedCalldata memory) {
return s_allowedFunctionsForContracts[_target][_selector];
}
/// @inheritdoc IProofSubmitter
function isAllowedCalldata(
address _target,
bytes4 _selector,
bytes calldata _calldataAfterSelector
) public view returns (bool) {
AllowedCalldata
storage allowedCalldata = s_allowedFunctionsForContracts[_target][
_selector
];
Rule memory rule = allowedCalldata.rule;
RuleType ruleType = rule.ruleType;
uint32 bytesCount = rule.bytesCount;
uint32 startIndex = rule.startIndex;
if (ruleType == RuleType.None) {
return false;
} else if (ruleType == RuleType.AnyCalldata) {
return true;
} else if (ruleType == RuleType.StartsWith) {
// Ensure the calldata is at least as long as bytesCount
if (_calldataAfterSelector.length < bytesCount) return false;
// Compare the beginning of the calldata with the allowed bytes
return
keccak256(_calldataAfterSelector[:bytesCount]) ==
keccak256(allowedCalldata.allowedBytes);
} else if (ruleType == RuleType.EndsWith) {
// Ensure the calldata is at least as long as bytesCount
if (_calldataAfterSelector.length < bytesCount) return false;
// Compare the end of the calldata with the allowed bytes
return
keccak256(
_calldataAfterSelector[_calldataAfterSelector.length -
bytesCount:]
) == keccak256(allowedCalldata.allowedBytes);
} else if (ruleType == RuleType.Between) {
// Ensure the calldata is at least as long as the range defined by startIndex and bytesCount
if (_calldataAfterSelector.length < startIndex + bytesCount)
return false;
// Compare the specified range in the calldata with the allowed bytes
return
keccak256(
_calldataAfterSelector[startIndex:startIndex + bytesCount]
) == keccak256(allowedCalldata.allowedBytes);
}
// Default to false if none of the conditions are met
return false;
}
/// @notice Get the owner of the ProofSubmitter instance
/// @return owner The owner address
function owner() public view override(Erc4337Account) returns (address) {
return s_owner;
}
/// @notice Check if an address is an operator
/// @param _address The address to check
/// @return isOperator true if the address is an operator, false otherwise
function isOperator(
address _address
) public view override(Erc4337Account) returns (bool) {
return s_isOperator[_address];
}
/// @notice Get the factory address
/// @return factory The factory address
function factory() public view override returns (address) {
return address(i_factory);
}
/// @inheritdoc ERC165
function supportsInterface(
bytes4 interfaceId
) public view virtual override(ERC165, IERC165) returns (bool) {
return
interfaceId == type(IProofSubmitter).interfaceId ||
super.supportsInterface(interfaceId);
}
}// SPDX-FileCopyrightText: 2024 P2P Validator <info@p2p.org>
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import "../lib/@openzeppelin/contracts/utils/introspection/IERC165.sol";
import "../proofSubmitter/ProofSubmitter.sol";
/// @dev External interface of ProofSubmitterFactory declared to support ERC165 detection.
interface IProofSubmitterFactory is IERC165 {
/// @notice Creates a new ProofSubmitter contract instance
/// @return proofSubmitter The new ProofSubmitter contract instance
function createProofSubmitter()
external
payable
returns (ProofSubmitter proofSubmitter);
/// @notice Predicts the address of a ProofSubmitter contract instance
/// @param _owner The owner of the ProofSubmitter contract instance
/// @return The address of the ProofSubmitter contract instance
function predictProofSubmitterAddress(
address _owner
) external view returns (address);
/// @notice Returns the address of the reference ProofSubmitter contract
/// @return The address of the reference ProofSubmitter contract
function getReferenceProofSubmitter() external view returns (address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity 0.8.17;
import "./IERC165.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 ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (proxy/Clones.sol)
pragma solidity 0.8.17;
/**
* @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for
* deploying minimal proxy contracts, also known as "clones".
*
* > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
* > a minimal bytecode implementation that delegates all calls to a known, fixed address.
*
* The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
* (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
* deterministic method.
*
* _Available since v3.4._
*/
library Clones {
/**
* @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
*
* This function uses the create opcode, which should never revert.
*/
function clone(address implementation) internal returns (address instance) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
mstore(add(ptr, 0x14), shl(0x60, implementation))
mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
instance := create(0, ptr, 0x37)
}
require(instance != address(0), "ERC1167: create failed");
}
/**
* @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
*
* This function uses the create2 opcode and a `salt` to deterministically deploy
* the clone. Using the same `implementation` and `salt` multiple time will revert, since
* the clones cannot be deployed twice at the same address.
*/
function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
mstore(add(ptr, 0x14), shl(0x60, implementation))
mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
instance := create2(0, ptr, 0x37, salt)
}
require(instance != address(0), "ERC1167: create2 failed");
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(
address implementation,
bytes32 salt,
address deployer
) internal pure returns (address predicted) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
mstore(add(ptr, 0x14), shl(0x60, implementation))
mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000)
mstore(add(ptr, 0x38), shl(0x60, deployer))
mstore(add(ptr, 0x4c), salt)
mstore(add(ptr, 0x6c), keccak256(ptr, 0x37))
predicted := keccak256(add(ptr, 0x37), 0x55)
}
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(address implementation, bytes32 salt)
internal
view
returns (address predicted)
{
return predictDeterministicAddress(implementation, salt, address(this));
}
}// SPDX-FileCopyrightText: 2024 P2P Validator <info@p2p.org>
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import "../lib/erc4337/UserOperation.sol";
import "../lib/erc4337/IAccount.sol";
import "../lib/erc4337/IEntryPointStakeManager.sol";
import "../lib/@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
/// @notice passed address should be the owner
/// @param _passedAddress passed address
error Erc4337Account__NotOwner(address _passedAddress, address _owner);
/// @notice passed address should be a valid ERC-4337 entryPoint
/// @param _passedAddress passed address
error Erc4337Account__NotEntryPoint(address _passedAddress);
/// @title ERC-4337 smart wallet account
abstract contract Erc4337Account is IAccount {
using ECDSA for bytes32;
/// @notice Singleton ERC-4337 entryPoint 0.6.0
address payable constant entryPoint =
payable(0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789);
/// @notice If caller not factory, revert
modifier onlyEntryPoint() {
if (msg.sender != entryPoint) {
revert Erc4337Account__NotEntryPoint(msg.sender);
}
_;
}
/// @notice If caller not owner, revert
modifier onlyOwner() {
if (msg.sender != owner()) {
revert Erc4337Account__NotOwner(msg.sender, owner());
}
_;
}
/// @inheritdoc IAccount
/// @notice Validates a user operation and pays the required prefund
/// @param userOp The user operation to validate
/// @param userOpHash The hash of the user operation
/// @param missingAccountFunds The amount of funds missing from the account
/// @return validationData 0 if the operation is valid, 1 if it's invalid
function validateUserOp(
UserOperation calldata userOp,
bytes32 userOpHash,
uint256 missingAccountFunds
) external override onlyEntryPoint returns (uint256 validationData) {
validationData = _validateSignature(userOp, userOpHash);
_payPrefund(missingAccountFunds);
}
/// @notice Withdraw this contract's balance from EntryPoint back to the owner
function withdrawFromEntryPoint() external onlyOwner {
uint256 balance = IEntryPointStakeManager(entryPoint).balanceOf(
address(this)
);
IEntryPointStakeManager(entryPoint).withdrawTo(
payable(owner()),
balance
);
}
/// @notice Deposit ETH to this contract's balance in EntryPoint
function depositToEntryPoint() external payable {
IEntryPointStakeManager(entryPoint).depositTo{value: msg.value}(
address(this)
);
}
/// @notice Validates the signature of a user operation.
/// @param _userOp the operation that is about to be executed.
/// @param _userOpHash hash of the user's request data. can be used as the basis for signature.
/// @return validationData 0 for valid signature, 1 to mark signature failure
function _validateSignature(
UserOperation calldata _userOp,
bytes32 _userOpHash
) private view returns (uint256 validationData) {
bytes32 hash = _userOpHash.toEthSignedMessageHash();
address signer = hash.recover(_userOp.signature);
if (isOperator(signer) || signer == owner()) {
validationData = 0;
} else {
validationData = 1;
}
}
/// @notice sends to the entrypoint (msg.sender) the missing funds for this transaction.
/// @param _missingAccountFunds the minimum value this method should send the entrypoint.
/// this value MAY be zero, in case there is enough deposit, or the userOp has a paymaster.
function _payPrefund(uint256 _missingAccountFunds) private {
if (_missingAccountFunds != 0) {
(bool success, ) = payable(msg.sender).call{
value: _missingAccountFunds,
gas: type(uint256).max
}("");
(success);
//ignore failure (its EntryPoint's job to verify, not account.)
}
}
/// @notice Returns the owner of the account
/// @return owner The owner of the account
function owner() public view virtual returns (address);
/// @notice Returns the balance of the account in the EntryPoint
/// @return balance The balance of the account
function getBalance() external view returns (uint256) {
return IEntryPointStakeManager(entryPoint).balanceOf(address(this));
}
/// @notice Checks if an address is an operator
/// @param _address The address to check
/// @return isOperator True if the address is an operator, false otherwise
function isOperator(address _address) public view virtual returns (bool);
}// SPDX-FileCopyrightText: 2024 P2P Validator <info@p2p.org>
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import "../lib/@openzeppelin/contracts/utils/introspection/IERC165.sol";
import "./ProofSubmitterStructs.sol";
/// @dev External interface of ProofSubmitter declared to support ERC165 detection.
interface IProofSubmitter is IERC165 {
/// @notice Emitted when the ProofSubmitter contract is initialized
/// @param _owner The address of the owner set during initialization
event ProofSubmitter__Initialized(address _owner);
/// @notice Emitted when a new operator is set
/// @param _newOperator The address of the new operator
event ProofSubmitter__OperatorSet(address _newOperator);
/// @notice Emitted when an operator is dismissed
/// @param _operator The address of the operator dismissed
event ProofSubmitter__OperatorDismissed(address _operator);
/// @notice Emitted when a new allowed function for a contract is set
/// @param _contract The address of the contract
/// @param _selector The selector of the function
/// @param _allowedCalldata The allowed calldata for the function
event ProofSubmitter__AllowedFunctionForContractSet(
address indexed _contract,
bytes4 indexed _selector,
ProofSubmitterStructs.AllowedCalldata _allowedCalldata
);
/// @notice Emitted when an allowed function for a contract is removed
/// @param _contract The address of the contract
/// @param _selector The selector of the function
event ProofSubmitter__AllowedFunctionForContractRemoved(
address _contract,
bytes4 _selector
);
/// @notice Set owner address.
/// @dev Could not be in the constructor since it is different for different owners.
/// @param _owner owner address
function initialize(address _owner) external;
/// @notice Set operator for the ProofSubmitter instance
/// @param _newOperator The new operator address
function setOperator(address _newOperator) external;
/// @notice Dismiss operator for the ProofSubmitter instance
/// @param _operator The operator address to dismiss
function dismissOperator(address _operator) external;
/// @notice Set allowed calldata for a specific contract and selector
/// @param _contract The contract address
/// @param _selector The selector of the function
/// @param _allowedCalldata The allowed calldata for the function
function setAllowedFunctionForContract(
address _contract,
bytes4 _selector,
ProofSubmitterStructs.AllowedCalldata calldata _allowedCalldata
) external;
/// @notice Remove allowed calldata for a specific contract and selector
/// @param _contract The contract address
/// @param _selector The selector of the function
function removeAllowedFunctionForContract(
address _contract,
bytes4 _selector
) external;
/// @notice Execute a transaction (called directly from owner, or by entryPoint)
/// @param _target The target address of the transaction
/// @param _data The calldata of the transaction
function execute(address _target, bytes calldata _data) external;
/// @notice Execute a sequence of transactions
/// @param _targets The target addresses of the transactions
/// @param _data The calldata of the transactions
function executeBatch(
address[] calldata _targets,
bytes[] calldata _data
) external;
/// @notice Get allowed calldata for a specific contract and selector
/// @param _target The contract address
/// @param _selector The selector of the function
/// @return allowedCalldata The allowed calldata for the function
function getAllowedCalldata(
address _target,
bytes4 _selector
) external view returns (ProofSubmitterStructs.AllowedCalldata memory);
/// @notice Check if calldata is allowed for a specific contract and selector
/// @param _target The contract address
/// @param _selector The selector of the function
/// @param _calldataAfterSelector The calldata after the selector
/// @return isAllowed true if calldata is allowed, false otherwise
function isAllowedCalldata(
address _target,
bytes4 _selector,
bytes calldata _calldataAfterSelector
) external view returns (bool);
/// @notice Returns the factory address
/// @return address factory address
function factory() external view returns (address);
}// SPDX-FileCopyrightText: 2024 P2P Validator <info@p2p.org>
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
contract ProofSubmitterErrors {
/// @notice data length should be at least 4 byte to be a function signature
error ProofSubmitter__DataTooShort();
/// @notice The caller is not allowed to call the function
/// @param _target The target address
/// @param _selector The selector of the function
error ProofSubmitter__NotAllowedToCall(address _target, bytes4 _selector);
/// @notice The caller is neither an operator nor the owner
/// @param _caller The address of the caller
error ProofSubmitter__CallerNeitherOperatorNorOwner(address _caller);
/// @notice The caller is neither an entry point nor the owner
/// @param _caller The address of the caller
error ProofSubmitter__CallerNeitherEntryPointNorOwner(address _caller);
/// @notice The caller is not the factory
/// @param _caller The address of the caller
/// @param _factory The address of the factory
error ProofSubmitter__NotFactoryCalled(address _caller, address _factory);
/// @notice The owner address should not be zero
error ProofSubmitter__ZeroAddressOwner();
/// @notice The owner should have a valid EigenPod
error ProofSubmitter__OwnerShouldHaveEigenPod();
/// @notice The lengths of the targets and data arrays should be the same
/// @param _targetsLength The length of the targets array
/// @param _dataLength The length of the data array
error ProofSubmitter__WrongArrayLengths(
uint256 _targetsLength,
uint256 _dataLength
);
}// SPDX-FileCopyrightText: 2024 P2P Validator <info@p2p.org>
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
/// @title ProofSubmitterStructs
/// @notice Structs used in the ProofSubmitter contract
contract ProofSubmitterStructs {
/// @notice Enum representing the type of rule for allowed calldata
enum RuleType {
None,
AnyCalldata,
StartsWith,
EndsWith,
Between
}
/// @notice Struct representing a rule for allowed calldata
/// @param ruleType The type of rule
/// @param bytesCount The number of bytes to check
/// @param startIndex The start index of the bytes to check
struct Rule {
RuleType ruleType;
uint32 bytesCount;
uint32 startIndex;
}
/// @notice Struct representing allowed calldata
/// @param rule The rule for allowed calldata
/// @param allowedBytes The allowed bytes
struct AllowedCalldata {
Rule rule;
bytes allowedBytes;
}
}// SPDX-FileCopyrightText: 2024 P2P Validator <info@p2p.org>
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import "./IEigenPod.sol";
interface IEigenPodManager {
/// @notice Returns 'true' if the `podOwner` has created an EigenPod, and 'false' otherwise.
function hasPod(address podOwner) external view returns (bool);
/// @notice Returns the address of the `podOwner`'s EigenPod (whether it is deployed yet or not).
function getPod(address podOwner) external view returns (address);
}// SPDX-FileCopyrightText: 2024 P2P Validator <info@p2p.org>
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
interface IRewardsCoordinator {
/**
* @notice Internal leaf in the merkle tree for the earner's account leaf
* @param earner The address of the earner
* @param earnerTokenRoot The merkle root of the earner's token subtree
* Each leaf in the earner's token subtree is a TokenTreeMerkleLeaf
*/
struct EarnerTreeMerkleLeaf {
address earner;
bytes32 earnerTokenRoot;
}
/**
* @notice The actual leaves in the distribution merkle tree specifying the token earnings
* for the respective earner's subtree. Each leaf is a claimable amount of a token for an earner.
* @param token The token for which the earnings are being claimed
* @param cumulativeEarnings The cumulative earnings of the earner for the token
*/
struct TokenTreeMerkleLeaf {
address token;
uint256 cumulativeEarnings;
}
/**
* @notice A claim against a distribution root called by an
* earners claimer (could be the earner themselves). Each token claim will claim the difference
* between the cumulativeEarnings of the earner and the cumulativeClaimed of the claimer.
* Each claim can specify which of the earner's earned tokens they want to claim.
* See `processClaim()` for more details.
* @param rootIndex The index of the root in the list of DistributionRoots
* @param earnerIndex The index of the earner's account root in the merkle tree
* @param earnerTreeProof The proof of the earner's EarnerTreeMerkleLeaf against the merkle root
* @param earnerLeaf The earner's EarnerTreeMerkleLeaf struct, providing the earner address and earnerTokenRoot
* @param tokenIndices The indices of the token leaves in the earner's subtree
* @param tokenTreeProofs The proofs of the token leaves against the earner's earnerTokenRoot
* @param tokenLeaves The token leaves to be claimed
* @dev The merkle tree is structured with the merkle root at the top and EarnerTreeMerkleLeaf as internal leaves
* in the tree. Each earner leaf has its own subtree with TokenTreeMerkleLeaf as leaves in the subtree.
* To prove a claim against a specified rootIndex(which specifies the distributionRoot being used),
* the claim will first verify inclusion of the earner leaf in the tree against _distributionRoots[rootIndex].root.
* Then for each token, it will verify inclusion of the token leaf in the earner's subtree against the earner's earnerTokenRoot.
*/
struct RewardsMerkleClaim {
uint32 rootIndex;
uint32 earnerIndex;
bytes earnerTreeProof;
EarnerTreeMerkleLeaf earnerLeaf;
uint32[] tokenIndices;
bytes[] tokenTreeProofs;
TokenTreeMerkleLeaf[] tokenLeaves;
}
/**
* @notice Claim rewards against a given root (read from _distributionRoots[claim.rootIndex]).
* Earnings are cumulative so earners don't have to claim against all distribution roots they have earnings for,
* they can simply claim against the latest root and the contract will calculate the difference between
* their cumulativeEarnings and cumulativeClaimed. This difference is then transferred to recipient address.
* @param claim The RewardsMerkleClaim to be processed.
* Contains the root index, earner, token leaves, and required proofs
* @param recipient The address recipient that receives the ERC20 rewards
* @dev only callable by the valid claimer, that is
* if claimerFor[claim.earner] is address(0) then only the earner can claim, otherwise only
* claimerFor[claim.earner] can claim the rewards.
*/
function processClaim(RewardsMerkleClaim calldata claim, address recipient) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)
pragma solidity 0.8.17;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @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
* ====
*
* [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://diligence.consensys.net/posts/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.5.11/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 functionCall(target, data, "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");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(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) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(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) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason 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 {
// 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);
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.2) (utils/introspection/ERC165Checker.sol)
pragma solidity 0.8.17;
import "./IERC165.sol";
/**
* @dev Library used to query support of an interface declared via {IERC165}.
*
* Note that these functions return the actual result of the query: they do not
* `revert` if an interface is not supported. It is up to the caller to decide
* what to do in these cases.
*/
library ERC165Checker {
// As per the EIP-165 spec, no interface should ever match 0xffffffff
bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff;
/**
* @dev Returns true if `account` supports the {IERC165} interface,
*/
function supportsERC165(address account) internal view returns (bool) {
// Any contract that implements ERC165 must explicitly indicate support of
// InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid
return
_supportsERC165Interface(account, type(IERC165).interfaceId) &&
!_supportsERC165Interface(account, _INTERFACE_ID_INVALID);
}
/**
* @dev Returns true if `account` supports the interface defined by
* `interfaceId`. Support for {IERC165} itself is queried automatically.
*
* See {IERC165-supportsInterface}.
*/
function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) {
// query support of both ERC165 as per the spec and support of _interfaceId
return supportsERC165(account) && _supportsERC165Interface(account, interfaceId);
}
/**
* @dev Returns a boolean array where each value corresponds to the
* interfaces passed in and whether they're supported or not. This allows
* you to batch check interfaces for a contract where your expectation
* is that some interfaces may not be supported.
*
* See {IERC165-supportsInterface}.
*
* _Available since v3.4._
*/
function getSupportedInterfaces(address account, bytes4[] memory interfaceIds)
internal
view
returns (bool[] memory)
{
// an array of booleans corresponding to interfaceIds and whether they're supported or not
bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length);
// query support of ERC165 itself
if (supportsERC165(account)) {
// query support of each interface in interfaceIds
for (uint256 i = 0; i < interfaceIds.length; i++) {
interfaceIdsSupported[i] = _supportsERC165Interface(account, interfaceIds[i]);
}
}
return interfaceIdsSupported;
}
/**
* @dev Returns true if `account` supports all the interfaces defined in
* `interfaceIds`. Support for {IERC165} itself is queried automatically.
*
* Batch-querying can lead to gas savings by skipping repeated checks for
* {IERC165} support.
*
* See {IERC165-supportsInterface}.
*/
function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) {
// query support of ERC165 itself
if (!supportsERC165(account)) {
return false;
}
// query support of each interface in _interfaceIds
for (uint256 i = 0; i < interfaceIds.length; i++) {
if (!_supportsERC165Interface(account, interfaceIds[i])) {
return false;
}
}
// all interfaces supported
return true;
}
/**
* @notice Query if a contract implements an interface, does not check ERC165 support
* @param account The address of the contract to query for support of an interface
* @param interfaceId The interface identifier, as specified in ERC-165
* @return true if the contract at account indicates support of the interface with
* identifier interfaceId, false otherwise
* @dev Assumes that account contains a contract that supports ERC165, otherwise
* the behavior of this method is undefined. This precondition can be checked
* with {supportsERC165}.
* Interface identification is specified in ERC-165.
*/
function _supportsERC165Interface(address account, bytes4 interfaceId) private view returns (bool) {
// prepare call
bytes memory encodedParams = abi.encodeWithSelector(IERC165.supportsInterface.selector, interfaceId);
// perform static call
bool success;
uint256 returnSize;
uint256 returnValue;
assembly {
success := staticcall(30000, account, add(encodedParams, 0x20), mload(encodedParams), 0x00, 0x20)
returnSize := returndatasize()
returnValue := mload(0x00)
}
return success && returnSize >= 0x20 && returnValue > 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity 0.8.17;
/**
* @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);
}// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.17;
/**
* User Operation struct
* @param sender the sender account of this request.
* @param nonce unique value the sender uses to verify it is not a replay.
* @param initCode if set, the account contract will be created by this constructor/
* @param callData the method call to execute on this account.
* @param callGasLimit the gas limit passed to the callData method call.
* @param verificationGasLimit gas used for validateUserOp and validatePaymasterUserOp.
* @param preVerificationGas gas not calculated by the handleOps method, but added to the gas paid. Covers batch overhead.
* @param maxFeePerGas same as EIP-1559 gas parameter.
* @param maxPriorityFeePerGas same as EIP-1559 gas parameter.
* @param paymasterAndData if set, this field holds the paymaster address and paymaster-specific data. the paymaster will pay for the transaction instead of the sender.
* @param signature sender-verified signature over the entire request, the EntryPoint address and the chain ID.
*/
struct UserOperation {
address sender;
uint256 nonce;
bytes initCode;
bytes callData;
uint256 callGasLimit;
uint256 verificationGasLimit;
uint256 preVerificationGas;
uint256 maxFeePerGas;
uint256 maxPriorityFeePerGas;
bytes paymasterAndData;
bytes signature;
}// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.17;
import "./UserOperation.sol";
interface IAccount {
/**
* Validate user's signature and nonce
* the entryPoint will make the call to the recipient only if this validation call returns successfully.
* signature failure should be reported by returning SIG_VALIDATION_FAILED (1).
* This allows making a "simulation call" without a valid signature
* Other failures (e.g. nonce mismatch, or invalid signature format) should still revert to signal failure.
*
* @dev Must validate caller is the entryPoint.
* Must validate the signature and nonce
* @param userOp the operation that is about to be executed.
* @param userOpHash hash of the user's request data. can be used as the basis for signature.
* @param missingAccountFunds missing funds on the account's deposit in the entrypoint.
* This is the minimum amount to transfer to the sender(entryPoint) to be able to make the call.
* The excess is left as a deposit in the entrypoint, for future calls.
* can be withdrawn anytime using "entryPoint.withdrawTo()"
* In case there is a paymaster in the request (or the current deposit is high enough), this value will be zero.
* @return validationData packaged ValidationData structure. use `_packValidationData` and `_unpackValidationData` to encode and decode
* <20-byte> sigAuthorizer - 0 for valid signature, 1 to mark signature failure,
* otherwise, an address of an "authorizer" contract.
* <6-byte> validUntil - last timestamp this operation is valid. 0 for "indefinite"
* <6-byte> validAfter - first timestamp this operation is valid
* If an account doesn't use time-range, it is enough to return SIG_VALIDATION_FAILED value (1) for signature failure.
* Note that the validation code cannot use block.timestamp (or block.number) directly.
*/
function validateUserOp(UserOperation calldata userOp, bytes32 userOpHash, uint256 missingAccountFunds)
external returns (uint256 validationData);
}// SPDX-FileCopyrightText: 2024 P2P Validator <info@p2p.org>
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
interface IEntryPointStakeManager {
/// @return the deposit (for gas payment) of the account
function balanceOf(address account) external view returns (uint256);
/**
* add to the deposit of the given account
*/
function depositTo(address account) external payable;
/**
* withdraw from the deposit.
* @param withdrawAddress the address to send withdrawn value.
* @param withdrawAmount the amount to withdraw.
*/
function withdrawTo(address payable withdrawAddress, uint256 withdrawAmount) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/cryptography/ECDSA.sol)
pragma solidity 0.8.17;
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
}
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");
} else if (error == RecoverError.InvalidSignatureV) {
revert("ECDSA: invalid signature 'v' 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) {
// Check the signature length
// - case 65: r,s,v signature (standard)
// - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._
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.
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 if (signature.length == 64) {
bytes32 r;
bytes32 vs;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
assembly {
r := mload(add(signature, 0x20))
vs := mload(add(signature, 0x40))
}
return tryRecover(hash, r, vs);
} 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;
uint8 v;
assembly {
s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
v := add(shr(255, vs), 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 (v != 27 && v != 28) {
return (address(0), RecoverError.InvalidSignatureV);
}
// 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) {
// 32 is the length in bytes of hash,
// enforced by the type signature above
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
}
/**
* @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:\n", 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) {
return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
}
}// SPDX-FileCopyrightText: 2024 P2P Validator <info@p2p.org>
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
interface IEigenPod {
/// @notice Contains a beacon state root and a merkle proof verifying its inclusion under a beacon block root
struct StateRootProof {
bytes32 beaconStateRoot;
bytes proof;
}
/// @notice Contains a beacon balance container root and a proof of this root under a beacon block root
struct BalanceContainerProof {
bytes32 balanceContainerRoot;
bytes proof;
}
/// @notice Contains a validator balance root and a proof of its inclusion under a balance container root
struct BalanceProof {
bytes32 pubkeyHash;
bytes32 balanceRoot;
bytes proof;
}
/**
* @dev Create a checkpoint used to prove this pod's active validator set. Checkpoints are completed
* by submitting one checkpoint proof per ACTIVE validator. During the checkpoint process, the total
* change in ACTIVE validator balance is tracked, and any validators with 0 balance are marked `WITHDRAWN`.
* @dev Once finalized, the pod owner is awarded shares corresponding to:
* - the total change in their ACTIVE validator balances
* - any ETH in the pod not already awarded shares
* @dev A checkpoint cannot be created if the pod already has an outstanding checkpoint. If
* this is the case, the pod owner MUST complete the existing checkpoint before starting a new one.
* @param revertIfNoBalance Forces a revert if the pod ETH balance is 0. This allows the pod owner
* to prevent accidentally starting a checkpoint that will not increase their shares
*/
function startCheckpoint(bool revertIfNoBalance) external;
/**
* @dev Verify one or more validators have their withdrawal credentials pointed at this EigenPod, and award
* shares based on their effective balance. Proven validators are marked `ACTIVE` within the EigenPod, and
* future checkpoint proofs will need to include them.
* @dev Withdrawal credential proofs MUST NOT be older than `currentCheckpointTimestamp`.
* @dev Validators proven via this method MUST NOT have an exit epoch set already.
* @param beaconTimestamp the beacon chain timestamp sent to the 4788 oracle contract. Corresponds
* to the parent beacon block root against which the proof is verified.
* @param stateRootProof proves a beacon state root against a beacon block root
* @param validatorIndices a list of validator indices being proven
* @param validatorFieldsProofs proofs of each validator's `validatorFields` against the beacon state root
* @param validatorFields the fields of the beacon chain "Validator" container. See consensus specs for
* details: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#validator
*/
function verifyWithdrawalCredentials(
uint64 beaconTimestamp,
StateRootProof calldata stateRootProof,
uint40[] calldata validatorIndices,
bytes[] calldata validatorFieldsProofs,
bytes32[][] calldata validatorFields
) external;
/**
* @dev Progress the current checkpoint towards completion by submitting one or more validator
* checkpoint proofs. Anyone can call this method to submit proofs towards the current checkpoint.
* For each validator proven, the current checkpoint's `proofsRemaining` decreases.
* @dev If the checkpoint's `proofsRemaining` reaches 0, the checkpoint is finalized.
* (see `_updateCheckpoint` for more details)
* @dev This method can only be called when there is a currently-active checkpoint.
* @param balanceContainerProof proves the beacon's current balance container root against a checkpoint's `beaconBlockRoot`
* @param proofs Proofs for one or more validator current balances against the `balanceContainerRoot`
*/
function verifyCheckpointProofs(
BalanceContainerProof calldata balanceContainerProof,
BalanceProof[] calldata proofs
) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)
pragma solidity 0.8.17;
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
// Inspired by OraclizeAPI's implementation - MIT licence
// https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0x00";
}
uint256 temp = value;
uint256 length = 0;
while (temp != 0) {
length++;
temp >>= 8;
}
return toHexString(value, length);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _HEX_SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
}{
"remappings": [
"forge-std/=lib/forge-std/src/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs"
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "london",
"viaIR": true,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"createProofSubmitter","outputs":[{"internalType":"contract ProofSubmitter","name":"proofSubmitter","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"entryPoint","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getReferenceProofSubmitter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"i_referenceProofSubmitter","outputs":[{"internalType":"contract ProofSubmitter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"predictProofSubmitterAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]Contract Creation Code
60a0806040523461008757611f5d818101906001600160401b038211838310176100715760209183916104c883393081520301906000f080156100655760805260405161043b908161008d8239608051818181610110015281816101f4015261038a0152f35b6040513d6000823e3d90fd5b634e487b7160e01b600052604160045260246000fd5b600080fdfe60806040818152600436101561001457600080fd5b600091823560e01c90816301ffc9a71461013f57508063075212d4146100fc57806370747833146100fc57806374332eed146100d4578063aab0a209146100955763b0d691fe1461006457600080fd5b3461009157816003193601126100915760209051735ff137d4b0fdcd49dca30c7cf57e578a026d27898152f35b5080fd5b503461009157602036600319011261009157600435916001600160a01b039081841684036100d157506100c960209361036b565b915191168152f35b80fd5b5081600319360112610091576020906100eb6101c2565b90516001600160a01b039091168152f35b5034610091578160031936011261009157517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b8390346100915760203660031901126100915760043563ffffffff60e01b81168091036101945760209250630d9d19e360e41b8114908115610183575b5015158152f35b6301ffc9a760e01b1490508361017c565b8280fd5b67ffffffffffffffff81116101ac57604052565b634e487b7160e01b600052604160045260246000fd5b6101cb3361036b565b906000823b61035c5760408051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81527f000000000000000000000000000000000000000000000000000000000000000060601b6bffffffffffffffffffffffff191660148201526e5af43d82803e903d91602b57fd5bf360881b60288201526001600160a01b039491908590339060379086f5169485156103185785803b156102f757848091602485518094819363189acdbd60e31b83523360048401525af1801561030e576102fb575b50735ff137d4b0fdcd49dca30c7cf57e578a026d278992833b156102f757825163b760faf960e01b8152911660048201529183908390602490829034905af19081156102ee57506102dd575050565b6102e78291610198565b6100d15750565b513d84823e3d90fd5b8480fd5b61030790949194610198565b923861028e565b83513d87823e3d90fd5b815162461bcd60e51b815260206004820152601760248201527f455243313136373a2063726561746532206661696c65640000000000000000006044820152606490fd5b506001600160a01b0390911690565b604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81527f0000000000000000000000000000000000000000000000000000000000000000606090811b6bffffffffffffffffffffffff191660148301526f5af43d82803e903d91602b57fd5bf3ff60801b602883015230901b60388201526001600160a01b03909116604c8201526037808220606c83015260559101209056fea2646970667358221220a7273510a4c4213f1937da83e4fef3956c959024b9e135c376d0c51e0af9349a64736f6c6343000811003360e0346200010957601f62001f5d38819003918201601f19168301916001600160401b038311848410176200010e578084926020946040528339810103126200010957516001600160a01b0381168103620001095760c052466001148015620000ee577391e677b07f7af907ec9a428aafa9fc14a0d3a3385b60805215620000d357737750d328b314effa365a0402ccfd489b80b0adda5b60a052604051611e389081620001258239608051818181610dce015261148a015260a051816115bd015260c051818181610d1c0152610d730152f35b73acc1fb458a1317e886db376fc8141540537e68fe62000097565b7330770d7e3e71112d7a6b7259542d1f680a70e31562000078565b600080fd5b634e487b7160e01b600052604160045260246000fdfe60806040526004361015610013575b600080fd5b60003560e01c806301ffc9a714610167578063046c73d81461015e57806312065fe01461015557806318dfb3c71461014c5780631b3ba101146101435780631cff79cd1461013a5780633a871cdd146101315780633b1cdf57146101285780635b4306231461011f5780636d70f7ae1461011657806385ddf7261461010d5780638da5cb5b146101045780638eb9b324146100fb578063a54df723146100f2578063b3ab15fb146100e9578063c45a0155146100e05763c4d66de8146100d857600080fd5b61000e610d4b565b5061000e610d05565b5061000e610c4e565b5061000e610b01565b5061000e610a00565b5061000e6109d6565b5061000e61095d565b5061000e61091a565b5061000e610806565b5061000e6107a8565b5061000e61065b565b5061000e6105db565b5061000e610539565b5061000e610429565b5061000e610362565b5061000e610298565b5061000e610187565b602435906001600160e01b03198216820361000e57565b503461000e57602036600319011261000e5760043563ffffffff60e01b811680910361000e5760209063f3a419e560e01b81149081156101cd575b506040519015158152f35b6301ffc9a760e01b149050386101c2565b6001600160a01b0381160361000e57565b600511156101f957565b634e487b7160e01b600052602160045260246000fd5b919082519283825260005b84811061023b575050826000602080949584010152601f8019910116010190565b60208183018101518483018201520161021a565b60a060206102959381845280518051610267816101ef565b83860152604063ffffffff91828582015116828801520151166060850152015191608080820152019061020f565b90565b503461000e5760408060031936011261000e57610353906103216004356102be816101de565b6102c6610170565b906060602085516102d681610ef9565b86516102e181610f21565b600081526000838201526000888201528152015260018060a01b03166000526002602052826000209063ffffffff60e01b16600052602052604060002090565b90610344600182519361033385610ef9565b61033c81611b2e565b855201611b69565b6020830152519182918261024f565b0390f35b600091031261000e57565b503461000e57600036600319011261000e576040516370a0823160e01b81523060048201526020908181602481735ff137d4b0fdcd49dca30c7cf57e578a026d27895afa9081156103ec575b6000916103bf575b50604051908152f35b6103df9150823d81116103e5575b6103d78183610f4f565b810190610f70565b386103b6565b503d6103cd565b6103f4610f7f565b6103ae565b9181601f8401121561000e578235916001600160401b03831161000e576020808501948460051b01011161000e57565b503461000e57604036600319011261000e576001600160401b0360043581811161000e5761045b9036906004016103f9565b909160243590811161000e576104759036906004016103f9565b9290735ff137d4b0fdcd49dca30c7cf57e578a026d278933141580610524575b61050c578383036104ee5760005b8381106104ac57005b806104d16104c060019360051b8601611403565b6104cb83898761140d565b916119bf565b60001981146104e1575b016104a3565b6104e96113ec565b6104db565b6044838560405191632c9a52fd60e21b835260048301526024820152fd5b604051630a69dabf60e11b8152336004820152602490fd5b506000546001600160a01b0316331415610495565b506000806003193601126105ab57735ff137d4b0fdcd49dca30c7cf57e578a026d278981813b156105ab5760405163b760faf960e01b8152306004820152918290602490829034905af1801561059e575b610592575080f35b61059b90610f3c565b80f35b6105a6610f7f565b61058a565b80fd5b9181601f8401121561000e578235916001600160401b03831161000e576020838186019501011161000e57565b503461000e57604036600319011261000e576004356105f9816101de565b6024356001600160401b03811161000e576106189036906004016105ae565b90735ff137d4b0fdcd49dca30c7cf57e578a026d278933141580610646575b61050c57610644926119bf565b005b506000546001600160a01b0316331415610637565b503461000e5760031960603682011261000e57600435906001600160401b03821161000e5761016090823603011261000e57735ff137d4b0fdcd49dca30c7cf57e578a026d278933036107905761071e61071660009261071061070960405160208101907f19457468657265756d205369676e6564204d6573736167653a0a3332000000008252602435603c820152603c81526106f781610f21565b51902092610144810190600401610f8c565b3691611004565b906111bc565b91909161103b565b6001600160a01b039081168083526001602052604083205490919060ff16928315610779575b50505060001461076f5761035360005b61075f604435611339565b6040519081529081906020820190565b6103536001610754565b54919250166001600160a01b031614388080610744565b604051632b5e9c1960e11b8152336004820152602490fd5b503461000e57606036600319011261000e576004356107c6816101de565b6107ce610170565b604435906001600160401b03821161000e576020926107f46107fc9336906004016105ae565b929091611c3a565b6040519015158152f35b503461000e5760031960603682011261000e57600435610825816101de565b61082d610170565b90604435916001600160401b039384841161000e5783360301916080831261000e57600080549095906001600160a01b0316338190036108ed575060606040519461087786610ef9565b126108e55760405161088881610f21565b856004013560058110156108e95781526108a46024870161136f565b60208201526108b56044870161136f565b6040820152845260648501359081116108e55761059b9460046108db9236920101611380565b60208401526118db565b8580fd5b8780fd5b604051638a71ba7960e01b81523360048201526001600160a01b03919091166024820152604490fd5b0390fd5b503461000e57602036600319011261000e57600435610938816101de565b60018060a01b03166000526001602052602060ff604060002054166040519015158152f35b503461000e57602036600319011261000e5760043561097b816101de565b6000546001600160a01b0391908216338190036108ed577fb1abccd6379628accfa275299c69dc6ea17d42b11780750865115b124637cf7d60208484168060005260018252604060002060ff198154169055604051908152a1005b503461000e57600036600319011261000e576000546040516001600160a01b039091168152602090f35b503461000e576000806003193601126105ab5780546001600160a01b0316338190036108ed576040516370a0823160e01b81523060048201528290735ff137d4b0fdcd49dca30c7cf57e578a026d2789602082602481845afa918215610af4575b8392610ad4575b50803b15610ad05760405163040b850f60e31b81526001600160a01b0394909416600485015260248401919091528290604490829084905af18015610ac3575b610ab0575080f35b80610abd61059b92610f3c565b80610357565b610acb610f7f565b610aa8565b8280fd5b610aed91925060203d81116103e5576103d78183610f4f565b9038610a68565b610afc610f7f565b610a61565b503461000e57604036600319011261000e57600435610b1f816101de565b610b27610170565b600080546001600160a01b03908116939192919033859003610c27577fefa27eb31305cc84502626eb9615e9adb1bdee209217b923fd86d987748caac5939450811684526002602052836001610b9384604084209063ffffffff60e01b16600052602052604060002090565b82815501610ba1815461139b565b80610bd2575b5050604080516001600160a01b039390931683526001600160e01b031993909316602083015250a180f35b601f8111600114610be85750555b833880610ba7565b610c229250610c12906001601f610c0485600052602060002090565b920160051c820191016113d5565b6000908082528160208120915555565b610be0565b604051638a71ba7960e01b81523360048201526001600160a01b0386166024820152604490fd5b503461000e57602036600319011261000e57600435610c6c816101de565b600090338252600160205260ff6040832054161580610cf1575b610cd9576001600160a01b0316808252600160208181526040808520805460ff191690931790925590519182527fc278342b92ef5bde57dae49fd66842fc102270f9a876a3f090c8aeea4facf0f491a180f35b604051630ab67a0f60e31b8152336004820152602490fd5b5081546001600160a01b0316331415610c86565b503461000e57600036600319011261000e576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b503461000e57602036600319011261000e57600435610d69816101de565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811633819003610eb9575080821615610ea757604051633da1234960e21b81526001600160a01b038316600482015290602090829060249082907f0000000000000000000000000000000000000000000000000000000000000000165afa908115610e9a575b600091610e6c575b5015610e5a57600080546001600160a01b0319166001600160a01b03831690811790915560405190815261064491907f4eb83cbb152a20f6bb433897cb1e07cb74825ae4e8e9cee183661a0fde5caab890602090a161144f565b604051638bcbc26f60e01b8152600490fd5b610e8d915060203d8111610e93575b610e858183610f4f565b810190611357565b38610e00565b503d610e7b565b610ea2610f7f565b610df8565b60405163021b1a8f60e11b8152600490fd5b60405163cb86bd8b60e01b81523360048201526001600160a01b03919091166024820152604490fd5b50634e487b7160e01b600052604160045260246000fd5b604081019081106001600160401b03821117610f1457604052565b610f1c610ee2565b604052565b606081019081106001600160401b03821117610f1457604052565b6001600160401b038111610f1457604052565b90601f801991011681019081106001600160401b03821117610f1457604052565b9081602091031261000e575190565b506040513d6000823e3d90fd5b903590601e198136030182121561000e57018035906001600160401b03821161000e5760200191813603831361000e57565b60405190610fcb82610f21565b565b60405190610fcb82610ef9565b6020906001600160401b038111610ff7575b601f01601f19160190565b610fff610ee2565b610fec565b92919261101082610fda565b9161101e6040519384610f4f565b82948184528183011161000e578281602093846000960137010152565b611044816101ef565b8061104c5750565b611055816101ef565b600181036110a25760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606490fd5b6110ab816101ef565b600281036110f85760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606490fd5b611101816101ef565b600381036111595760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608490fd5b806111656004926101ef565b1461116c57565b60405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b6064820152608490fd5b8151604181036111e95750906111e5916020820151906060604084015193015160001a90611222565b9091565b6040036112185760208201516040909201516111e5926001600160ff1b03821692909160ff1c601b0190611222565b5050600090600290565b9291907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083116112cc5760ff16601b811415806112c1575b6112b5579160809493916020936040519384528484015260408301526060820152600093849182805260015afa156112a8575b81516001600160a01b038116156112a2579190565b50600190565b6112b0610f7f565b61128d565b50505050600090600490565b50601c81141561125a565b50505050600090600390565b60405190602082018281106001600160401b038211176112fc575b60405260008252565b611304610ee2565b6112f3565b3d15611334573d9061131a82610fda565b916113286040519384610f4f565b82523d6000602084013e565b606090565b806113415750565b600080808093338219f150611354611309565b50565b9081602091031261000e5751801515810361000e5790565b359063ffffffff8216820361000e57565b9080601f8301121561000e5781602061029593359101611004565b90600182811c921680156113cb575b60208310146113b557565b634e487b7160e01b600052602260045260246000fd5b91607f16916113aa565b8181106113e0575050565b600081556001016113d5565b50634e487b7160e01b600052601160045260246000fd5b35610295816101de565b90821015611424576111e59160051b810190610f8c565b634e487b7160e01b600052603260045260246000fd5b9081602091031261000e5751610295816101de565b6040805163a38406a360e01b81526001600160a01b038381166004830152610fcb93909161159f916020916115ad91906115639084816024817f00000000000000000000000000000000000000000000000000000000000000008b165afa90811561160f575b6000916115e2575b506114f66114c9610fbe565b6001815260008782015260008a8201526114e1610fcd565b9081526114ec6112d8565b878201528261173d565b61152e611501610fbe565b6001815260008782015260008a820152611519610fcd565b9081526115246112d8565b87820152826117ee565b611536610fbe565b600181529060008683015260008983015261154f610fcd565b91825261155a6112d8565b8683015261183d565b61156b610fbe565b6004815295601487850152602c87820152519384918483016014916bffffffffffffffffffffffff199060601b1681520190565b03601f198101845283610f4f565b6115b5610fcd565b9384528301527f00000000000000000000000000000000000000000000000000000000000000001661188c565b6116029150853d8711611608575b6115fa8183610f4f565b81019061143a565b386114bd565b503d6115f0565b611617610f7f565b6114b5565b9190601f811161162b57505050565b610fcb926000526020600020906020601f840160051c83019310611657575b601f0160051c01906113d5565b909150819061164a565b91909182516001600160401b038111611730575b61168981611683845461139b565b8461161c565b602080601f83116001146116c55750819293946000926116ba575b50508160011b916000199060031b1c1916179055565b0151905038806116a4565b90601f198316956116db85600052602060002090565b926000905b888210611718575050836001959697106116ff575b505050811b019055565b015160001960f88460031b161c191690553880806116f5565b806001859682949686015181550195019301906116e0565b611738610ee2565b611675565b60018060a01b0316806000526002602052600080516020611de38339815191526117e96040600020936388676cad60e01b94856000526020526117dd6040600020825180519061178c826101ef565b611795826101ef565b825460ff68ffffffff0000000000604064ffffffff00602086015160081b1694015160281b1693169068ffffffffffffffffff19161717178155600160208401519101611661565b6040519182918261024f565b0390a3565b60018060a01b0316806000526002602052600080516020611de38339815191526117e9604060002093633f65cf1960e01b94856000526020526117dd6040600020825180519061178c826101ef565b60018060a01b0316806000526002602052600080516020611de38339815191526117e960406000209363783a5d3160e11b94856000526020526117dd6040600020825180519061178c826101ef565b60018060a01b0316806000526002602052600080516020611de38339815191526117e9604060002093633ccc861d60e01b94856000526020526117dd6040600020825180519061178c826101ef565b6117e9600080516020611de38339815191529160018060a01b0316928360005260026020526119836119248260406000209063ffffffff60e01b16600052602052604060002090565b8651805190611932826101ef565b61193b826101ef565b825460ff68ffffffff0000000000604064ffffffff00602086015160081b1694015160281b1693169068ffffffffffffffffff19161717178155600160208801519101611661565b60405191829163ffffffff60e01b16958261024f565b90929192831161000e579190565b9093929384831161000e57841161000e578101920390565b90600492838110611add5780841161000e5781356001600160e01b0319166119ef60031983018685018387611c3a565b15611aa6575090611a01913691611004565b9060405192611a0f84610ef9565b601e84527f416464726573733a206c6f772d6c6576656c2063616c6c206661696c656400006020850152813b15611a62575060008281928260206113549796519301915af1611a5c611309565b90611aee565b60649060206040519162461bcd60e51b8352820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152fd5b60408051633cba07e560e11b81526001600160a01b0386168188019081526001600160e01b03199093166020840152918291010390fd5b60405163437d066b60e01b81528490fd5b90919015611afa575090565b815115611b0a5750805190602001fd5b60405162461bcd60e51b81526020600482015290819061091690602483019061020f565b90604051611b3b81610f21565b604081935460ff8116611b4d816101ef565b835263ffffffff90818160081c16602085015260281c16910152565b9060405191826000825492611b7d8461139b565b908184526001948581169081600014611bea5750600114611ba7575b5050610fcb92500383610f4f565b9093915060005260209081600020936000915b818310611bd2575050610fcb93508201013880611b99565b85548884018501529485019487945091830191611bba565b915050610fcb94506020925060ff191682840152151560051b8201013880611b99565b91909163ffffffff80809416911601918211611c2557565b610fcb6113ec565b91908203918211611c2557565b6001600160a01b03166000908152600260205260409020611c6c9163ffffffff60e01b16600052602052604060002090565b91611c7683611b2e565b91825191611c83836101ef565b602093611ca76040611c9b8784015163ffffffff1690565b92015163ffffffff1690565b93611cb1816101ef565b80611cc25750505050505050600090565b611ccb816101ef565b60018103611cdf5750505050505050600190565b611ce8816101ef565b60028103611d36575063ffffffff919293501690818110611d2c57610709600192611d1692611d2395611999565b8381519101209301611b69565b80519101201490565b5050505050600090565b611d3f816101ef565b60038103611d76575063ffffffff16925090828210611d2c5761070982611d169281611d70611d2397600197611c2d565b916119a7565b80611d826004926101ef565b14611d9257505050505050600090565b611da8611d9f8286611c0d565b63ffffffff1690565b8210611dd757611d2393600193611d1693611dce6107099463ffffffff91829186611c0d565b169316916119a7565b50505050505060009056fe0d380530551240eda2332db808a0d86579e9c1d1468950194f9774c58aac9029a2646970667358221220c3aab3189d56868a4ea2b9edddd3e5b5888c39699bde5439d29a2ed761d424c164736f6c63430008110033
Deployed Bytecode
0x60806040818152600436101561001457600080fd5b600091823560e01c90816301ffc9a71461013f57508063075212d4146100fc57806370747833146100fc57806374332eed146100d4578063aab0a209146100955763b0d691fe1461006457600080fd5b3461009157816003193601126100915760209051735ff137d4b0fdcd49dca30c7cf57e578a026d27898152f35b5080fd5b503461009157602036600319011261009157600435916001600160a01b039081841684036100d157506100c960209361036b565b915191168152f35b80fd5b5081600319360112610091576020906100eb6101c2565b90516001600160a01b039091168152f35b5034610091578160031936011261009157517f000000000000000000000000dd0cf5f4f98e564bc5a1ee8cc3a5a06eb53327836001600160a01b03168152602090f35b8390346100915760203660031901126100915760043563ffffffff60e01b81168091036101945760209250630d9d19e360e41b8114908115610183575b5015158152f35b6301ffc9a760e01b1490508361017c565b8280fd5b67ffffffffffffffff81116101ac57604052565b634e487b7160e01b600052604160045260246000fd5b6101cb3361036b565b906000823b61035c5760408051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81527f000000000000000000000000dd0cf5f4f98e564bc5a1ee8cc3a5a06eb533278360601b6bffffffffffffffffffffffff191660148201526e5af43d82803e903d91602b57fd5bf360881b60288201526001600160a01b039491908590339060379086f5169485156103185785803b156102f757848091602485518094819363189acdbd60e31b83523360048401525af1801561030e576102fb575b50735ff137d4b0fdcd49dca30c7cf57e578a026d278992833b156102f757825163b760faf960e01b8152911660048201529183908390602490829034905af19081156102ee57506102dd575050565b6102e78291610198565b6100d15750565b513d84823e3d90fd5b8480fd5b61030790949194610198565b923861028e565b83513d87823e3d90fd5b815162461bcd60e51b815260206004820152601760248201527f455243313136373a2063726561746532206661696c65640000000000000000006044820152606490fd5b506001600160a01b0390911690565b604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81527f000000000000000000000000dd0cf5f4f98e564bc5a1ee8cc3a5a06eb5332783606090811b6bffffffffffffffffffffffff191660148301526f5af43d82803e903d91602b57fd5bf3ff60801b602883015230901b60388201526001600160a01b03909116604c8201526037808220606c83015260559101209056fea2646970667358221220a7273510a4c4213f1937da83e4fef3956c959024b9e135c376d0c51e0af9349a64736f6c63430008110033
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.