Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 7 from a total of 7 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Create Aggregato... | 19773931 | 290 days ago | IN | 0 ETH | 0.00517932 | ||||
Create Aggregato... | 19510861 | 327 days ago | IN | 0 ETH | 0.00916579 | ||||
Create Aggregato... | 18941597 | 407 days ago | IN | 0 ETH | 0.01054384 | ||||
Create Aggregato... | 18427809 | 479 days ago | IN | 0 ETH | 0.01300907 | ||||
Create Aggregato... | 18206647 | 510 days ago | IN | 0 ETH | 0.00332666 | ||||
Grant Role | 18206476 | 510 days ago | IN | 0 ETH | 0.00041636 | ||||
Create Aggregato... | 18119063 | 522 days ago | IN | 0 ETH | 0.00457686 |
Latest 6 internal transactions
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|
19773931 | 290 days ago | Contract Creation | 0 ETH | |||
19510861 | 327 days ago | Contract Creation | 0 ETH | |||
18941597 | 407 days ago | Contract Creation | 0 ETH | |||
18427809 | 479 days ago | Contract Creation | 0 ETH | |||
18206647 | 510 days ago | Contract Creation | 0 ETH | |||
18119063 | 522 days ago | Contract Creation | 0 ETH |
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 Source Code Verified (Exact Match)
Contract Name:
AggregatorsFactory
Compiler Version
v0.8.21+commit.d9974bed
Optimization Enabled:
Yes with 20000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {Clones} from "openzeppelin-contracts/contracts/proxy/Clones.sol"; import {AccessControl} from "openzeppelin-contracts/contracts/access/AccessControl.sol"; import {SharpFactsAggregator} from "../src/SharpFactsAggregator.sol"; /// @title AggregatorsFactory /// @author Herodotus Dev /// @notice A factory contract for creating new SharpFactsAggregator contracts /// and upgrading new one's starter template contract AggregatorsFactory is AccessControl { // Blank contract template address SharpFactsAggregator public template; // Timelock mechanism for upgrades proposals struct UpgradeProposalTimelock { uint256 timestamp; SharpFactsAggregator newTemplate; } // Upgrades timelocks mapping(uint256 => UpgradeProposalTimelock) public upgrades; // Upgrades tracker uint256 public upgradesCount; // Delay before an upgrade can be performed uint256 public constant DELAY = 3 days; // Aggregators indexing uint256 public aggregatorsCount; // Aggregators by id mapping(uint256 => SharpFactsAggregator) public aggregatorsById; // Access control bytes32 public constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE"); // Default roots for new aggregators: // poseidon_hash(1, "brave new world") bytes32 public constant POSEIDON_MMR_INITIAL_ROOT = 0x06759138078831011e3bc0b4a135af21c008dda64586363531697207fb5a2bae; // keccak_hash(1, "brave new world") bytes32 public constant KECCAK_MMR_INITIAL_ROOT = 0x5d8d23518dd388daa16925ff9475c5d1c06430d21e0422520d6a56402f42937b; // Events event UpgradeProposal(SharpFactsAggregator newTemplate); event Upgrade( SharpFactsAggregator oldTemplate, SharpFactsAggregator newTemplate ); event AggregatorCreation( SharpFactsAggregator aggregator, uint256 newAggregatorId, uint256 detachedFromAggregatorId ); /// Creates a new Factory contract and grants OPERATOR_ROLE to the deployer /// @param initialTemplate The address of the template contract to clone constructor(SharpFactsAggregator initialTemplate) { template = initialTemplate; _setRoleAdmin(OPERATOR_ROLE, OPERATOR_ROLE); _grantRole(OPERATOR_ROLE, _msgSender()); } /// @notice Reverts if the caller is not an operator modifier onlyOperator() { require( hasRole(OPERATOR_ROLE, _msgSender()), "Caller is not an operator" ); _; } /** * Creates a new aggregator contract by cloning the template contract * @param aggregatorId The id of an existing aggregator to attach to (0 for none) */ function createAggregator( uint256 aggregatorId ) external onlyOperator returns (address) { SharpFactsAggregator.AggregatorState memory initialAggregatorState; if (aggregatorId != 0) { // Attach from existing aggregator require(aggregatorId <= aggregatorsCount, "Invalid aggregator ID"); address existingAggregatorAddr = address( aggregatorsById[aggregatorId] ); require( existingAggregatorAddr != address(0), "Aggregator not found" ); SharpFactsAggregator existingAggregator = SharpFactsAggregator( existingAggregatorAddr ); ( bytes32 poseidonMmrRoot, bytes32 keccakMmrRoot, uint256 mmrSize, bytes32 continuableParentHash ) = existingAggregator.aggregatorState(); initialAggregatorState.poseidonMmrRoot = poseidonMmrRoot; initialAggregatorState.keccakMmrRoot = keccakMmrRoot; initialAggregatorState.mmrSize = mmrSize; initialAggregatorState .continuableParentHash = continuableParentHash; } else { // Create a new aggregator (detach from existing ones) initialAggregatorState = SharpFactsAggregator.AggregatorState({ poseidonMmrRoot: POSEIDON_MMR_INITIAL_ROOT, keccakMmrRoot: KECCAK_MMR_INITIAL_ROOT, mmrSize: 1, continuableParentHash: bytes32(0) }); } // Initialize the newly created aggregator bytes memory data = abi.encodeWithSignature( "initialize((bytes32,bytes32,uint256,bytes32))", initialAggregatorState ); // Clone the template contract address clone = Clones.clone(address(template)); // The data is the encoded initialize function (with initial parameters) (bool success, ) = clone.call(data); require(success, "Aggregator initialization failed"); aggregatorsById[++aggregatorsCount] = SharpFactsAggregator(clone); emit AggregatorCreation( SharpFactsAggregator(clone), aggregatorsCount, aggregatorId ); // Grant roles to the caller so that roles are not stuck in the Factory SharpFactsAggregator(clone).grantRole( keccak256("OPERATOR_ROLE"), _msgSender() ); SharpFactsAggregator(clone).grantRole( keccak256("UNLOCKER_ROLE"), _msgSender() ); return clone; } /** * Proposes an upgrade to the template (blank aggregator) contract * @param newTemplate The address of the new template contract to use for future aggregators */ function proposeUpgrade( SharpFactsAggregator newTemplate ) external onlyOperator { upgrades[++upgradesCount] = UpgradeProposalTimelock( block.timestamp + DELAY, newTemplate ); emit UpgradeProposal(newTemplate); } /** * Upgrades the template (blank aggregator) contract * @param updateId The id of the upgrade proposal to execute */ function upgrade(uint256 updateId) external onlyOperator { require(updateId == upgradesCount, "Invalid updateId"); uint256 timeLockTimestamp = upgrades[updateId].timestamp; require(timeLockTimestamp != 0, "TimeLock not set"); require(block.timestamp >= timeLockTimestamp, "TimeLock not expired"); address oldTemplate = address(template); template = SharpFactsAggregator(upgrades[updateId].newTemplate); // Clear timelock upgrades[updateId] = UpgradeProposalTimelock( 0, SharpFactsAggregator(address(0)) ); emit Upgrade(SharpFactsAggregator(oldTemplate), template); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (proxy/Clones.sol) pragma solidity ^0.8.20; /** * @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. */ library Clones { /** * @dev A clone instance deployment failed. */ error ERC1167FailedCreateClone(); /** * @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 { // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes // of the `implementation` address with the bytecode before the address. mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000)) // Packs the remaining 17 bytes of `implementation` with the bytecode after the address. mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3)) instance := create(0, 0x09, 0x37) } if (instance == address(0)) { revert ERC1167FailedCreateClone(); } } /** * @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 { // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes // of the `implementation` address with the bytecode before the address. mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000)) // Packs the remaining 17 bytes of `implementation` with the bytecode after the address. mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3)) instance := create2(0, 0x09, 0x37, salt) } if (instance == address(0)) { revert ERC1167FailedCreateClone(); } } /** * @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(add(ptr, 0x38), deployer) mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff) mstore(add(ptr, 0x14), implementation) mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73) mstore(add(ptr, 0x58), salt) mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37)) predicted := keccak256(add(ptr, 0x43), 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-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol) pragma solidity ^0.8.20; import {IAccessControl} from "./IAccessControl.sol"; import {Context} from "../utils/Context.sol"; import {ERC165} from "../utils/introspection/ERC165.sol"; /** * @dev Contract module that allows children to implement role-based access * control mechanisms. This is a lightweight version that doesn't allow enumerating role * members except through off-chain means by accessing the contract event logs. Some * applications may benefit from on-chain enumerability, for those cases see * {AccessControlEnumerable}. * * Roles are referred to by their `bytes32` identifier. These should be exposed * in the external API and be unique. The best way to achieve this is by * using `public constant` hash digests: * * ```solidity * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); * ``` * * Roles can be used to represent a set of permissions. To restrict access to a * function call, use {hasRole}: * * ```solidity * function foo() public { * require(hasRole(MY_ROLE, msg.sender)); * ... * } * ``` * * Roles can be granted and revoked dynamically via the {grantRole} and * {revokeRole} functions. Each role has an associated admin role, and only * accounts that have a role's admin role can call {grantRole} and {revokeRole}. * * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means * that only accounts with this role will be able to grant or revoke other * roles. More complex role relationships can be created by using * {_setRoleAdmin}. * * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to * grant and revoke this role. Extra precautions should be taken to secure * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} * to enforce additional security measures for this role. */ abstract contract AccessControl is Context, IAccessControl, ERC165 { struct RoleData { mapping(address => bool) members; bytes32 adminRole; } mapping(bytes32 => RoleData) private _roles; bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /** * @dev Modifier that checks that an account has a specific role. Reverts * with an {AccessControlUnauthorizedAccount} error including the required role. */ modifier onlyRole(bytes32 role) { _checkRole(role); _; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) public view virtual returns (bool) { return _roles[role].members[account]; } /** * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()` * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier. */ function _checkRole(bytes32 role) internal view virtual { _checkRole(role, _msgSender()); } /** * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account` * is missing `role`. */ function _checkRole(bytes32 role, address account) internal view virtual { if (!hasRole(role, account)) { revert AccessControlUnauthorizedAccount(account, role); } } /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) { return _roles[role].adminRole; } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleGranted} event. */ function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) { _grantRole(role, account); } /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleRevoked} event. */ function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) { _revokeRole(role, account); } /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been revoked `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `callerConfirmation`. * * May emit a {RoleRevoked} event. */ function renounceRole(bytes32 role, address callerConfirmation) public virtual { if (callerConfirmation != _msgSender()) { revert AccessControlBadConfirmation(); } _revokeRole(role, callerConfirmation); } /** * @dev Sets `adminRole` as ``role``'s admin role. * * Emits a {RoleAdminChanged} event. */ function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { bytes32 previousAdminRole = getRoleAdmin(role); _roles[role].adminRole = adminRole; emit RoleAdminChanged(role, previousAdminRole, adminRole); } /** * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted. * * Internal function without access restriction. * * May emit a {RoleGranted} event. */ function _grantRole(bytes32 role, address account) internal virtual returns (bool) { if (!hasRole(role, account)) { _roles[role].members[account] = true; emit RoleGranted(role, account, _msgSender()); return true; } else { return false; } } /** * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked. * * Internal function without access restriction. * * May emit a {RoleRevoked} event. */ function _revokeRole(bytes32 role, address account) internal virtual returns (bool) { if (hasRole(role, account)) { _roles[role].members[account] = false; emit RoleRevoked(role, account, _msgSender()); return true; } else { return false; } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {Initializable} from "openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol"; import {AccessControlUpgradeable} from "openzeppelin-contracts-upgradeable/contracts/access/AccessControlUpgradeable.sol"; import {IFactsRegistry} from "./interfaces/IFactsRegistry.sol"; import {Uint256Splitter} from "./lib/Uint256Splitter.sol"; /// @title SharpFactsAggregator /// @dev Aggregator contract to handle SHARP job outputs and update the global aggregator state. /// @author Herodotus Dev /// ------------------ /// Example: /// Blocks inside brackets are the ones processed during their SHARP job execution // 7 [8 9 10] 11 /// n = 10 /// r = 3 /// `r` is the number of blocks processed on a single SHARP job execution /// `blockNMinusRPlusOneParentHash` = 8.parentHash (oldestHash) /// `blockNPlusOneParentHash` = 11.parentHash (newestHash) /// ------------------ contract SharpFactsAggregator is Initializable, AccessControlUpgradeable { // Using inline library for efficient splitting and joining of uint256 values using Uint256Splitter for uint256; // Role definitions for access control bytes32 public constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE"); bytes32 public constant UNLOCKER_ROLE = keccak256("UNLOCKER_ROLE"); uint256 public constant MINIMUM_BLOCKS_CONFIRMATIONS = 20; uint256 public constant MAXIMUM_BLOCKS_CONFIRMATIONS = 255; // Sharp Facts Registry IFactsRegistry public immutable FACTS_REGISTRY; // Cairo program hash (i.e., the off-chain block headers accumulator program) bytes32 public constant PROGRAM_HASH = bytes32( uint256( 0x01eca36d586f5356fba096edbf7414017d51cd0ed24b8fde80f78b61a9216ed2 ) ); // Global aggregator state struct AggregatorState { bytes32 poseidonMmrRoot; bytes32 keccakMmrRoot; uint256 mmrSize; bytes32 continuableParentHash; } // Current __global__ state of this aggregator AggregatorState public aggregatorState; // Mapping to keep track of block number to its parent hash mapping(uint256 => bytes32) public blockNumberToParentHash; // Flag to control operator role requirements bool public isOperatorRequired; // Representation of the Cairo program's output (raw unpacked) struct JobOutput { uint256 fromBlockNumberHigh; uint256 toBlockNumberLow; bytes32 blockNPlusOneParentHashLow; bytes32 blockNPlusOneParentHashHigh; bytes32 blockNMinusRPlusOneParentHashLow; bytes32 blockNMinusRPlusOneParentHashHigh; bytes32 mmrPreviousRootPoseidon; bytes32 mmrPreviousRootKeccakLow; bytes32 mmrPreviousRootKeccakHigh; uint256 mmrPreviousSize; bytes32 mmrNewRootPoseidon; bytes32 mmrNewRootKeccakLow; bytes32 mmrNewRootKeccakHigh; uint256 mmrNewSize; } // Packed representation of the Cairo program's output (for gas efficiency) struct JobOutputPacked { uint256 blockNumbersPacked; bytes32 blockNPlusOneParentHash; bytes32 blockNMinusRPlusOneParentHash; bytes32 mmrPreviousRootPoseidon; bytes32 mmrPreviousRootKeccak; bytes32 mmrNewRootPoseidon; bytes32 mmrNewRootKeccak; uint256 mmrSizesPacked; } // Custom errors for better error handling and clarity error NotEnoughBlockConfirmations(); error TooManyBlocksConfirmations(); error NotEnoughJobs(); error UnknownParentHash(); error AggregationError(string message); // Generic error with a message error AggregationBlockMismatch(); error GenesisBlockReached(); error InvalidFact(); // Event emitted when a new range is registered // (i.e, when we want to allow aggregating from a more recent block) event NewRangeRegistered( uint256 targetBlock, bytes32 targetBlockParentHash ); // Event emitted when __at least__ one SHARP job is aggregated event Aggregate( uint256 fromBlockNumberHigh, uint256 toBlockNumberLow, bytes32 poseidonMmrRoot, bytes32 keccakMmrRoot, uint256 mmrSize, bytes32 continuableParentHash ); event OperatorRequirementChange(bool newRequirement); constructor(IFactsRegistry factsRegistry) { FACTS_REGISTRY = factsRegistry; } /** * @notice Initializes the contract with given parameters. * @param initialAggregatorState Initial state of the aggregator (i.e., initial trees state). */ function initialize( AggregatorState calldata initialAggregatorState ) public initializer { __AccessControl_init(); aggregatorState = initialAggregatorState; _setRoleAdmin(OPERATOR_ROLE, OPERATOR_ROLE); _setRoleAdmin(UNLOCKER_ROLE, OPERATOR_ROLE); // Grant operator role to the contract deployer // to be able to define new aggregate ranges _grantRole(OPERATOR_ROLE, _msgSender()); _grantRole(UNLOCKER_ROLE, _msgSender()); // Set operator role requirement to true by default isOperatorRequired = true; } /// @notice Reverts if the caller is not an operator and the operator role requirement is enabled modifier onlyOperator() { if (isOperatorRequired) { require( hasRole(OPERATOR_ROLE, _msgSender()), "Caller is not an operator" ); } _; } /// @notice Reverts if the caller is not an unlocker modifier onlyUnlocker() { require( hasRole(UNLOCKER_ROLE, _msgSender()), "Caller is not an unlocker" ); _; } /// @dev Modifies the contract's operator requirement function setOperatorRequired( bool _isOperatorRequired ) external onlyUnlocker { isOperatorRequired = _isOperatorRequired; emit OperatorRequirementChange(_isOperatorRequired); } /// Registers a new range to aggregate from /// @notice Caches a recent block hash (MINIMUM_BLOCKS_CONFIRMATIONS to -MAXIMUM_BLOCKS_CONFIRMATIONS from present), relying on the global `blockhash` Solidity function /// @param blocksConfirmations Number of blocks preceding the current block function registerNewRange( uint256 blocksConfirmations ) external onlyOperator { // Minimum blocks confirmations to avoid reorgs if (blocksConfirmations < MINIMUM_BLOCKS_CONFIRMATIONS) { revert NotEnoughBlockConfirmations(); } // Maximum MAXIMUM_BLOCKS_CONFIRMATIONS blocks confirmations to capture // an available block hash with Solidity `blockhash()` if (blocksConfirmations > MAXIMUM_BLOCKS_CONFIRMATIONS) { revert TooManyBlocksConfirmations(); } // Determine the target block number (i.e. the child block) uint256 targetBlock = block.number - blocksConfirmations; // Extract its parent hash. bytes32 targetBlockParentHash = blockhash(targetBlock - 1); // If the parent hash is not available, revert // (This should never happen under the current EVM rules) if (targetBlockParentHash == bytes32(0)) { revert UnknownParentHash(); } // Cache the parent hash so that we can later on continue accumlating from it blockNumberToParentHash[targetBlock] = targetBlockParentHash; // If we cannot aggregate further in the past (e.g., genesis block is reached or it's a new tree) if (aggregatorState.continuableParentHash == bytes32(0)) { // Set the aggregator state's `continuableParentHash` to the target block's parent hash // so we can easily continue aggregating from it without specifying `rightBoundStartBlock` in `aggregateSharpJobs` aggregatorState.continuableParentHash = targetBlockParentHash; } emit NewRangeRegistered(targetBlock, targetBlockParentHash); } /// @notice Aggregate SHARP jobs outputs (min. 1) to update the global aggregator state /// @param rightBoundStartBlock The reference block to start from. Defaults to continuing from the global state if set to `0` /// @param outputs Array of SHARP jobs outputs (packed for Solidity) function aggregateSharpJobs( uint256 rightBoundStartBlock, JobOutputPacked[] calldata outputs ) external onlyOperator { // Ensuring at least one job output is provided if (outputs.length < 1) { revert NotEnoughJobs(); } bytes32 rightBoundStartBlockParentHash = bytes32(0); // Start from a different block than the current state if `rightBoundStartBlock` is specified if (rightBoundStartBlock != 0) { // Retrieve from cache the parent hash of the block to start from rightBoundStartBlockParentHash = blockNumberToParentHash[ rightBoundStartBlock ]; // If not present in the cache, hash is not authenticated and we cannot continue from it if (rightBoundStartBlockParentHash == bytes32(0)) { revert UnknownParentHash(); } } JobOutputPacked calldata firstOutput = outputs[0]; // Ensure the first job is continuable ensureContinuable(rightBoundStartBlockParentHash, firstOutput); if (rightBoundStartBlockParentHash != bytes32(0)) { (uint256 fromBlockHighStart, ) = firstOutput .blockNumbersPacked .split128(); // We check that block numbers are consecutives if (fromBlockHighStart != rightBoundStartBlock - 1) { revert AggregationBlockMismatch(); } } uint256 limit = outputs.length - 1; // Iterate over the jobs outputs (aside from the last one) // and ensure jobs are correctly linked and valid for (uint256 i = 0; i < limit; ++i) { JobOutputPacked calldata curOutput = outputs[i]; JobOutputPacked calldata nextOutput = outputs[i + 1]; ensureValidFact(curOutput); ensureConsecutiveJobs(curOutput, nextOutput); } JobOutputPacked calldata lastOutput = outputs[limit]; ensureValidFact(lastOutput); // We save the latest output in the contract state for future calls (, uint256 mmrNewSize) = lastOutput.mmrSizesPacked.split128(); aggregatorState.poseidonMmrRoot = lastOutput.mmrNewRootPoseidon; aggregatorState.keccakMmrRoot = lastOutput.mmrNewRootKeccak; aggregatorState.mmrSize = mmrNewSize; aggregatorState.continuableParentHash = lastOutput .blockNMinusRPlusOneParentHash; (uint256 fromBlock, ) = firstOutput.blockNumbersPacked.split128(); (, uint256 toBlock) = lastOutput.blockNumbersPacked.split128(); emit Aggregate( fromBlock, toBlock, lastOutput.mmrNewRootPoseidon, lastOutput.mmrNewRootKeccak, mmrNewSize, lastOutput.blockNMinusRPlusOneParentHash ); } /// @notice Ensures the fact is registered on SHARP Facts Registry /// @param output SHARP job output (packed for Solidity) function ensureValidFact(JobOutputPacked memory output) internal view { (uint256 fromBlock, uint256 toBlock) = output .blockNumbersPacked .split128(); (uint256 mmrPreviousSize, uint256 mmrNewSize) = output .mmrSizesPacked .split128(); ( uint256 blockNPlusOneParentHashLow, uint256 blockNPlusOneParentHashHigh ) = uint256(output.blockNPlusOneParentHash).split128(); ( uint256 blockNMinusRPlusOneParentHashLow, uint256 blockNMinusRPlusOneParentHashHigh ) = uint256(output.blockNMinusRPlusOneParentHash).split128(); ( uint256 mmrPreviousRootKeccakLow, uint256 mmrPreviousRootKeccakHigh ) = uint256(output.mmrPreviousRootKeccak).split128(); (uint256 mmrNewRootKeccakLow, uint256 mmrNewRootKeccakHigh) = uint256( output.mmrNewRootKeccak ).split128(); // We assemble the outputs in a uint256 array uint256[] memory outputs = new uint256[](14); outputs[0] = fromBlock; outputs[1] = toBlock; outputs[2] = blockNPlusOneParentHashLow; outputs[3] = blockNPlusOneParentHashHigh; outputs[4] = blockNMinusRPlusOneParentHashLow; outputs[5] = blockNMinusRPlusOneParentHashHigh; outputs[6] = uint256(output.mmrPreviousRootPoseidon); outputs[7] = mmrPreviousRootKeccakLow; outputs[8] = mmrPreviousRootKeccakHigh; outputs[9] = mmrPreviousSize; outputs[10] = uint256(output.mmrNewRootPoseidon); outputs[11] = mmrNewRootKeccakLow; outputs[12] = mmrNewRootKeccakHigh; outputs[13] = mmrNewSize; // We hash the outputs bytes32 outputHash = keccak256(abi.encodePacked(outputs)); // We compute the deterministic fact bytes32 value bytes32 fact = keccak256(abi.encode(PROGRAM_HASH, outputHash)); // We ensure this fact has been registered on SHARP Facts Registry if (!FACTS_REGISTRY.isValid(fact)) { revert InvalidFact(); } } /// @notice Ensures the job output is cryptographically sound to continue from /// @param rightBoundStartParentHash The parent hash of the block to start from /// @param output The job output to check function ensureContinuable( bytes32 rightBoundStartParentHash, JobOutputPacked memory output ) internal view { (uint256 mmrPreviousSize, ) = output.mmrSizesPacked.split128(); // Check that the job's previous Poseidon MMR root is the same as the one stored in the contract state if (output.mmrPreviousRootPoseidon != aggregatorState.poseidonMmrRoot) revert AggregationError("Poseidon root mismatch"); // Check that the job's previous Keccak MMR root is the same as the one stored in the contract state if (output.mmrPreviousRootKeccak != aggregatorState.keccakMmrRoot) revert AggregationError("Keccak root mismatch"); // Check that the job's previous MMR size is the same as the one stored in the contract state if (mmrPreviousSize != aggregatorState.mmrSize) revert AggregationError("MMR size mismatch"); if (rightBoundStartParentHash == bytes32(0)) { // If the right bound start parent hash __is not__ specified, // we check that the job's `blockN + 1 parent hash` is matching with the previously stored parent hash if ( output.blockNPlusOneParentHash != aggregatorState.continuableParentHash ) { revert AggregationError("Global state: Parent hash mismatch"); } } else { // If the right bound start parent hash __is__ specified, // we check that the job's `blockN + 1 parent hash` is matching with a previously stored parent hash if (output.blockNPlusOneParentHash != rightBoundStartParentHash) { revert AggregationError("Parent hash mismatch"); } } } /// @notice Ensures the job outputs are correctly linked /// @param output The job output to check /// @param nextOutput The next job output to check function ensureConsecutiveJobs( JobOutputPacked memory output, JobOutputPacked memory nextOutput ) internal pure { (, uint256 toBlock) = output.blockNumbersPacked.split128(); // We cannot aggregate further past the genesis block if (toBlock == 0) { revert GenesisBlockReached(); } (uint256 nextFromBlock, ) = nextOutput.blockNumbersPacked.split128(); // We check that the next job's `from block` is the same as the previous job's `to block + 1` if (toBlock - 1 != nextFromBlock) revert AggregationBlockMismatch(); (, uint256 outputMmrNewSize) = output.mmrSizesPacked.split128(); (uint256 nextOutputMmrPreviousSize, ) = nextOutput .mmrSizesPacked .split128(); // We check that the previous job's new Poseidon MMR root matches the next job's previous Poseidon MMR root if (output.mmrNewRootPoseidon != nextOutput.mmrPreviousRootPoseidon) revert AggregationError("Poseidon root mismatch"); // We check that the previous job's new Keccak MMR root matches the next job's previous Keccak MMR root if (output.mmrNewRootKeccak != nextOutput.mmrPreviousRootKeccak) revert AggregationError("Keccak root mismatch"); // We check that the previous job's new MMR size matches the next job's previous MMR size if (outputMmrNewSize != nextOutputMmrPreviousSize) revert AggregationError("MMR size mismatch"); // We check that the previous job's lowest block hash matches the next job's highest block hash if ( output.blockNMinusRPlusOneParentHash != nextOutput.blockNPlusOneParentHash ) revert AggregationError("Parent hash mismatch"); } /// @dev Helper function to verify a fact based on a job output function verifyFact(uint256[] memory outputs) external view returns (bool) { bytes32 outputHash = keccak256(abi.encodePacked(outputs)); bytes32 fact = keccak256(abi.encode(PROGRAM_HASH, outputHash)); return FACTS_REGISTRY.isValid(fact); } /// @notice Returns the current root hash of the Keccak Merkle Mountain Range (MMR) tree function getMMRKeccakRoot() external view returns (bytes32) { return aggregatorState.keccakMmrRoot; } /// @notice Returns the current root hash of the Poseidon Merkle Mountain Range (MMR) tree function getMMRPoseidonRoot() external view returns (bytes32) { return aggregatorState.poseidonMmrRoot; } /// @notice Returns the current size of the Merkle Mountain Range (MMR) trees function getMMRSize() external view returns (uint256) { return aggregatorState.mmrSize; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) pragma solidity ^0.8.20; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControl { /** * @dev The `account` is missing a role. */ error AccessControlUnauthorizedAccount(address account, bytes32 neededRole); /** * @dev The caller of a function is not the expected one. * * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}. */ error AccessControlBadConfirmation(); /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {AccessControl-_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) external view returns (bool); /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {AccessControl-_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) external view returns (bytes32); /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) external; /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) external; /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `callerConfirmation`. */ function renounceRole(bytes32 role, address callerConfirmation) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.20; /** * @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 Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.20; import {IERC165} from "./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); * } * ``` */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.20; /** * @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. */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev The contract is already initialized. */ error AlreadyInitialized(); /** * @dev The contract is not initializing. */ error NotInitializing(); /** * @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; if (!(isTopLevelCall && _initialized < 1) && !(address(this).code.length == 0 && _initialized == 1)) { revert AlreadyInitialized(); } _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) { if (_initializing || _initialized >= version) { revert AlreadyInitialized(); } _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() { _checkInitializing(); _; } /** * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}. */ function _checkInitializing() internal view virtual { if (!_initializing) { revert NotInitializing(); } } /** * @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 { if (_initializing) { revert AlreadyInitialized(); } 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; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol) pragma solidity ^0.8.20; import { IAccessControlUpgradeable } from "./IAccessControlUpgradeable.sol"; import { ContextUpgradeable } from "../utils/ContextUpgradeable.sol"; import { ERC165Upgradeable } from "../utils/introspection/ERC165Upgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module that allows children to implement role-based access * control mechanisms. This is a lightweight version that doesn't allow enumerating role * members except through off-chain means by accessing the contract event logs. Some * applications may benefit from on-chain enumerability, for those cases see * {AccessControlEnumerable}. * * Roles are referred to by their `bytes32` identifier. These should be exposed * in the external API and be unique. The best way to achieve this is by * using `public constant` hash digests: * * ```solidity * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); * ``` * * Roles can be used to represent a set of permissions. To restrict access to a * function call, use {hasRole}: * * ```solidity * function foo() public { * require(hasRole(MY_ROLE, msg.sender)); * ... * } * ``` * * Roles can be granted and revoked dynamically via the {grantRole} and * {revokeRole} functions. Each role has an associated admin role, and only * accounts that have a role's admin role can call {grantRole} and {revokeRole}. * * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means * that only accounts with this role will be able to grant or revoke other * roles. More complex role relationships can be created by using * {_setRoleAdmin}. * * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to * grant and revoke this role. Extra precautions should be taken to secure * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} * to enforce additional security measures for this role. */ abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControlUpgradeable, ERC165Upgradeable { function __AccessControl_init() internal onlyInitializing { } function __AccessControl_init_unchained() internal onlyInitializing { } struct RoleData { mapping(address => bool) members; bytes32 adminRole; } mapping(bytes32 => RoleData) private _roles; bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /** * @dev Modifier that checks that an account has a specific role. Reverts * with an {AccessControlUnauthorizedAccount} error including the required role. */ modifier onlyRole(bytes32 role) { _checkRole(role); _; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControlUpgradeable).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) public view virtual returns (bool) { return _roles[role].members[account]; } /** * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()` * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier. */ function _checkRole(bytes32 role) internal view virtual { _checkRole(role, _msgSender()); } /** * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account` * is missing `role`. */ function _checkRole(bytes32 role, address account) internal view virtual { if (!hasRole(role, account)) { revert AccessControlUnauthorizedAccount(account, role); } } /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) { return _roles[role].adminRole; } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleGranted} event. */ function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) { _grantRole(role, account); } /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleRevoked} event. */ function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) { _revokeRole(role, account); } /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been revoked `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `callerConfirmation`. * * May emit a {RoleRevoked} event. */ function renounceRole(bytes32 role, address callerConfirmation) public virtual { if (callerConfirmation != _msgSender()) { revert AccessControlBadConfirmation(); } _revokeRole(role, callerConfirmation); } /** * @dev Sets `adminRole` as ``role``'s admin role. * * Emits a {RoleAdminChanged} event. */ function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { bytes32 previousAdminRole = getRoleAdmin(role); _roles[role].adminRole = adminRole; emit RoleAdminChanged(role, previousAdminRole, adminRole); } /** * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted. * * Internal function without access restriction. * * May emit a {RoleGranted} event. */ function _grantRole(bytes32 role, address account) internal virtual returns (bool) { if (!hasRole(role, account)) { _roles[role].members[account] = true; emit RoleGranted(role, account, _msgSender()); return true; } else { return false; } } /** * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked. * * Internal function without access restriction. * * May emit a {RoleRevoked} event. */ function _revokeRole(bytes32 role, address account) internal virtual returns (bool) { if (hasRole(role, account)) { _roles[role].members[account] = false; emit RoleRevoked(role, account, _msgSender()); return true; } else { return false; } } /** * @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; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IFactsRegistry { function isValid(bytes32 fact) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; library Uint256Splitter { uint256 constant _MASK = type(uint128).max; /// @notice Splits a uint256 into two uint128s (low, high) represented as uint256s. /// @param a The uint256 to split. function split128( uint256 a ) internal pure returns (uint256 lower, uint256 upper) { return (a & _MASK, a >> 128); } /// @notice Merges two uint128s (low, high) into one uint256. /// @param lower The lower uint256. The caller is required to pass a value that is less than 2^128 - 1. /// @param upper The upper uint256. function merge128( uint256 lower, uint256 upper ) internal pure returns (uint256 a) { require(lower <= _MASK, "Uint256Splitter: lower exceeds uint128"); // return (upper << 128) | lower; assembly { a := or(shl(128, upper), lower) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @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: MIT // OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) pragma solidity ^0.8.20; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControlUpgradeable { /** * @dev The `account` is missing a role. */ error AccessControlUnauthorizedAccount(address account, bytes32 neededRole); /** * @dev The caller of a function is not the expected one. * * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}. */ error AccessControlBadConfirmation(); /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {AccessControl-_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) external view returns (bool); /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {AccessControl-_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) external view returns (bytes32); /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) external; /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) external; /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `callerConfirmation`. */ function renounceRole(bytes32 role, address callerConfirmation) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.20; 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; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.20; import { IERC165Upgradeable } from "./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); * } * ``` */ 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 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; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @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 IERC165Upgradeable { /** * @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); }
{ "remappings": [ "ds-test/=lib/forge-std/lib/ds-test/src/", "erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/", "forge-std/=lib/forge-std/src/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/", "openzeppelin/=lib/openzeppelin-contracts-upgradeable/contracts/" ], "optimizer": { "enabled": true, "runs": 20000 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"contract SharpFactsAggregator","name":"initialTemplate","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ERC1167FailedCreateClone","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract SharpFactsAggregator","name":"aggregator","type":"address"},{"indexed":false,"internalType":"uint256","name":"newAggregatorId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"detachedFromAggregatorId","type":"uint256"}],"name":"AggregatorCreation","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract SharpFactsAggregator","name":"oldTemplate","type":"address"},{"indexed":false,"internalType":"contract SharpFactsAggregator","name":"newTemplate","type":"address"}],"name":"Upgrade","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract SharpFactsAggregator","name":"newTemplate","type":"address"}],"name":"UpgradeProposal","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DELAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"KECCAK_MMR_INITIAL_ROOT","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"OPERATOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"POSEIDON_MMR_INITIAL_ROOT","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"aggregatorsById","outputs":[{"internalType":"contract SharpFactsAggregator","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"aggregatorsCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"aggregatorId","type":"uint256"}],"name":"createAggregator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract SharpFactsAggregator","name":"newTemplate","type":"address"}],"name":"proposeUpgrade","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"template","outputs":[{"internalType":"contract SharpFactsAggregator","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"updateId","type":"uint256"}],"name":"upgrade","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"upgrades","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"contract SharpFactsAggregator","name":"newTemplate","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"upgradesCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b50604051620016a8380380620016a8833981016040819052620000349162000187565b600180546001600160a01b0319166001600160a01b0383161790556200006a60008051602062001688833981519152806200008d565b620000856000805160206200168883398151915233620000d8565b5050620001b9565b600082815260208190526040808220600101805490849055905190918391839186917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a4505050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff166200017d576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620001343390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600162000181565b5060005b92915050565b6000602082840312156200019a57600080fd5b81516001600160a01b0381168114620001b257600080fd5b9392505050565b6114bf80620001c96000396000f3fe608060405234801561001057600080fd5b50600436106101515760003560e01c80637931bbf1116100cd578063a217fddf11610081578063d547741f11610066578063d547741f14610395578063e454bd0c146103a8578063f5b541a6146103bb57600080fd5b8063a217fddf1461037a578063c915fc931461038257600080fd5b806382492228116100b25780638249222814610306578063850366721461030f57806391d148541461033657600080fd5b80637931bbf1146102a95780637b826922146102d057600080fd5b806336568abe1161012457806369b411701161010957806369b41170146101f35780636f2ddd93146101fd5780637386bbc51461024257600080fd5b806336568abe146101cd57806345977d03146101e057600080fd5b806301ffc9a714610156578063248a9ca31461017e5780632db692d4146101af5780632f2ff15d146101b8575b600080fd5b6101696101643660046112d9565b6103e2565b60405190151581526020015b60405180910390f35b6101a161018c366004611322565b60009081526020819052604090206001015490565b604051908152602001610175565b6101a160035481565b6101cb6101c636600461135d565b61047b565b005b6101cb6101db36600461135d565b6104a6565b6101cb6101ee366004611322565b610504565b6101a16203f48081565b60015461021d9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610175565b61027f610250366004611322565b6002602052600090815260409020805460019091015473ffffffffffffffffffffffffffffffffffffffff1682565b6040805192835273ffffffffffffffffffffffffffffffffffffffff909116602083015201610175565b6101a17f5d8d23518dd388daa16925ff9475c5d1c06430d21e0422520d6a56402f42937b81565b61021d6102de366004611322565b60056020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b6101a160045481565b6101a17f06759138078831011e3bc0b4a135af21c008dda64586363531697207fb5a2bae81565b61016961034436600461135d565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b6101a1600081565b6101cb61039036600461138d565b6107b7565b6101cb6103a336600461135d565b610933565b61021d6103b6366004611322565b610958565b6101a17f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b92981565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061047557507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b60008281526020819052604090206001015461049681610ff8565b6104a08383611005565b50505050565b73ffffffffffffffffffffffffffffffffffffffff811633146104f5576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104ff8282611101565b505050565b3360009081527fee57cd81e84075558e8fcc182a1f4393f91fc97f963a136e66b7f949a62f319f602052604090205460ff166105a1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f43616c6c6572206973206e6f7420616e206f70657261746f720000000000000060448201526064015b60405180910390fd5b600354811461060c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f496e76616c6964207570646174654964000000000000000000000000000000006044820152606401610598565b60008181526002602052604081205490819003610685576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f54696d654c6f636b206e6f7420736574000000000000000000000000000000006044820152606401610598565b804210156106ef576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f54696d654c6f636b206e6f7420657870697265640000000000000000000000006044820152606401610598565b60018054600084815260026020818152604080842080870180547fffffffffffffffffffffffff000000000000000000000000000000000000000080891673ffffffffffffffffffffffffffffffffffffffff928316178a5584518086018652888152808701898152988d9052968652955190925594518554908216941693909317909355935482519382168085529116938301939093527fd23ce5645530506727523fe6d7939e72bb49102454460bc72f0f5baec60ac718910160405180910390a1505050565b3360009081527fee57cd81e84075558e8fcc182a1f4393f91fc97f963a136e66b7f949a62f319f602052604090205460ff1661084f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f43616c6c6572206973206e6f7420616e206f70657261746f72000000000000006044820152606401610598565b60405180604001604052806203f4804261086991906113d9565b81526020018273ffffffffffffffffffffffffffffffffffffffff168152506002600060036000815461089b906113ec565b9182905550815260208082019290925260409081016000208351815592820151600190930180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9485161790555191831682527faf574319215a31df9b528258f1bdeef2b12b169dc85ff443a49373248c77493a910160405180910390a150565b60008281526020819052604090206001015461094e81610ff8565b6104a08383611101565b3360009081527fee57cd81e84075558e8fcc182a1f4393f91fc97f963a136e66b7f949a62f319f602052604081205460ff166109f0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f43616c6c6572206973206e6f7420616e206f70657261746f72000000000000006044820152606401610598565b6040805160808101825260008082526020820181905291810182905260608101919091528215610bad57600454831115610a86576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f496e76616c69642061676772656761746f7220494400000000000000000000006044820152606401610598565b60008381526005602052604090205473ffffffffffffffffffffffffffffffffffffffff1680610b12576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f41676772656761746f72206e6f7420666f756e640000000000000000000000006044820152606401610598565b60008190506000806000808473ffffffffffffffffffffffffffffffffffffffff1663cf90c31e6040518163ffffffff1660e01b8152600401608060405180830381865afa158015610b68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b8c9190611424565b928a5260208a01919091526040890152606088015250610c12945050505050565b50604080516080810182527f06759138078831011e3bc0b4a135af21c008dda64586363531697207fb5a2bae81527f5d8d23518dd388daa16925ff9475c5d1c06430d21e0422520d6a56402f42937b6020820152600191810191909152600060608201525b6040805182516024820152602083015160448201529082015160648201526060820151608482015260009060a401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f693d243600000000000000000000000000000000000000000000000000000000179052600154909150600090610cde9073ffffffffffffffffffffffffffffffffffffffff166111bc565b905060008173ffffffffffffffffffffffffffffffffffffffff1683604051610d07919061145a565b6000604051808303816000865af19150503d8060008114610d44576040519150601f19603f3d011682016040523d82523d6000602084013e610d49565b606091505b5050905080610db4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f41676772656761746f7220696e697469616c697a6174696f6e206661696c65646044820152606401610598565b8160056000600460008154610dc8906113ec565b91829055508152602080820192909252604090810160002080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff948516179055600454815193861684529183019190915281018790527fe0b55292344ac8b30a6d48109c7a6b8258d24c7767054d57d1dfef69b2f03a3a9060600160405180910390a173ffffffffffffffffffffffffffffffffffffffff8216632f2ff15d7f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b929336040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152600481019290925273ffffffffffffffffffffffffffffffffffffffff166024820152604401600060405180830381600087803b158015610f0c57600080fd5b505af1158015610f20573d6000803e3d6000fd5b505050508173ffffffffffffffffffffffffffffffffffffffff16632f2ff15d7fc806897caf4fd5068191157e44d3988e43139a37e0b97b6793e1ed1184140604610f683390565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152600481019290925273ffffffffffffffffffffffffffffffffffffffff166024820152604401600060405180830381600087803b158015610fd457600080fd5b505af1158015610fe8573d6000803e3d6000fd5b509396505050505050505b919050565b611002813361124f565b50565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff166110f95760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556110973390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610475565b506000610475565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16156110f95760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610475565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008260601b60e81c176000526e5af43d82803e903d91602b57fd5bf38260781b17602052603760096000f0905073ffffffffffffffffffffffffffffffffffffffff8116610ff3576040517fc2f868f400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff166112d5576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260248101839052604401610598565b5050565b6000602082840312156112eb57600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461131b57600080fd5b9392505050565b60006020828403121561133457600080fd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff8116811461100257600080fd5b6000806040838503121561137057600080fd5b8235915060208301356113828161133b565b809150509250929050565b60006020828403121561139f57600080fd5b813561131b8161133b565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610475576104756113aa565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361141d5761141d6113aa565b5060010190565b6000806000806080858703121561143a57600080fd5b505082516020840151604085015160609095015191969095509092509050565b6000825160005b8181101561147b5760208186018101518583015201611461565b50600092019182525091905056fea26469706673582212202f7eb2a534e57f2d8c4c40fd0773925f68a178aa5089c7fef5e5b1d88b4d5e0164736f6c6343000815003397667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b929000000000000000000000000ba5c971c3178ea8755bfb6996a42f3ae24e81344
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101515760003560e01c80637931bbf1116100cd578063a217fddf11610081578063d547741f11610066578063d547741f14610395578063e454bd0c146103a8578063f5b541a6146103bb57600080fd5b8063a217fddf1461037a578063c915fc931461038257600080fd5b806382492228116100b25780638249222814610306578063850366721461030f57806391d148541461033657600080fd5b80637931bbf1146102a95780637b826922146102d057600080fd5b806336568abe1161012457806369b411701161010957806369b41170146101f35780636f2ddd93146101fd5780637386bbc51461024257600080fd5b806336568abe146101cd57806345977d03146101e057600080fd5b806301ffc9a714610156578063248a9ca31461017e5780632db692d4146101af5780632f2ff15d146101b8575b600080fd5b6101696101643660046112d9565b6103e2565b60405190151581526020015b60405180910390f35b6101a161018c366004611322565b60009081526020819052604090206001015490565b604051908152602001610175565b6101a160035481565b6101cb6101c636600461135d565b61047b565b005b6101cb6101db36600461135d565b6104a6565b6101cb6101ee366004611322565b610504565b6101a16203f48081565b60015461021d9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610175565b61027f610250366004611322565b6002602052600090815260409020805460019091015473ffffffffffffffffffffffffffffffffffffffff1682565b6040805192835273ffffffffffffffffffffffffffffffffffffffff909116602083015201610175565b6101a17f5d8d23518dd388daa16925ff9475c5d1c06430d21e0422520d6a56402f42937b81565b61021d6102de366004611322565b60056020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b6101a160045481565b6101a17f06759138078831011e3bc0b4a135af21c008dda64586363531697207fb5a2bae81565b61016961034436600461135d565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b6101a1600081565b6101cb61039036600461138d565b6107b7565b6101cb6103a336600461135d565b610933565b61021d6103b6366004611322565b610958565b6101a17f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b92981565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061047557507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b60008281526020819052604090206001015461049681610ff8565b6104a08383611005565b50505050565b73ffffffffffffffffffffffffffffffffffffffff811633146104f5576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104ff8282611101565b505050565b3360009081527fee57cd81e84075558e8fcc182a1f4393f91fc97f963a136e66b7f949a62f319f602052604090205460ff166105a1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f43616c6c6572206973206e6f7420616e206f70657261746f720000000000000060448201526064015b60405180910390fd5b600354811461060c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f496e76616c6964207570646174654964000000000000000000000000000000006044820152606401610598565b60008181526002602052604081205490819003610685576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f54696d654c6f636b206e6f7420736574000000000000000000000000000000006044820152606401610598565b804210156106ef576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f54696d654c6f636b206e6f7420657870697265640000000000000000000000006044820152606401610598565b60018054600084815260026020818152604080842080870180547fffffffffffffffffffffffff000000000000000000000000000000000000000080891673ffffffffffffffffffffffffffffffffffffffff928316178a5584518086018652888152808701898152988d9052968652955190925594518554908216941693909317909355935482519382168085529116938301939093527fd23ce5645530506727523fe6d7939e72bb49102454460bc72f0f5baec60ac718910160405180910390a1505050565b3360009081527fee57cd81e84075558e8fcc182a1f4393f91fc97f963a136e66b7f949a62f319f602052604090205460ff1661084f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f43616c6c6572206973206e6f7420616e206f70657261746f72000000000000006044820152606401610598565b60405180604001604052806203f4804261086991906113d9565b81526020018273ffffffffffffffffffffffffffffffffffffffff168152506002600060036000815461089b906113ec565b9182905550815260208082019290925260409081016000208351815592820151600190930180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9485161790555191831682527faf574319215a31df9b528258f1bdeef2b12b169dc85ff443a49373248c77493a910160405180910390a150565b60008281526020819052604090206001015461094e81610ff8565b6104a08383611101565b3360009081527fee57cd81e84075558e8fcc182a1f4393f91fc97f963a136e66b7f949a62f319f602052604081205460ff166109f0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f43616c6c6572206973206e6f7420616e206f70657261746f72000000000000006044820152606401610598565b6040805160808101825260008082526020820181905291810182905260608101919091528215610bad57600454831115610a86576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f496e76616c69642061676772656761746f7220494400000000000000000000006044820152606401610598565b60008381526005602052604090205473ffffffffffffffffffffffffffffffffffffffff1680610b12576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f41676772656761746f72206e6f7420666f756e640000000000000000000000006044820152606401610598565b60008190506000806000808473ffffffffffffffffffffffffffffffffffffffff1663cf90c31e6040518163ffffffff1660e01b8152600401608060405180830381865afa158015610b68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b8c9190611424565b928a5260208a01919091526040890152606088015250610c12945050505050565b50604080516080810182527f06759138078831011e3bc0b4a135af21c008dda64586363531697207fb5a2bae81527f5d8d23518dd388daa16925ff9475c5d1c06430d21e0422520d6a56402f42937b6020820152600191810191909152600060608201525b6040805182516024820152602083015160448201529082015160648201526060820151608482015260009060a401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f693d243600000000000000000000000000000000000000000000000000000000179052600154909150600090610cde9073ffffffffffffffffffffffffffffffffffffffff166111bc565b905060008173ffffffffffffffffffffffffffffffffffffffff1683604051610d07919061145a565b6000604051808303816000865af19150503d8060008114610d44576040519150601f19603f3d011682016040523d82523d6000602084013e610d49565b606091505b5050905080610db4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f41676772656761746f7220696e697469616c697a6174696f6e206661696c65646044820152606401610598565b8160056000600460008154610dc8906113ec565b91829055508152602080820192909252604090810160002080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff948516179055600454815193861684529183019190915281018790527fe0b55292344ac8b30a6d48109c7a6b8258d24c7767054d57d1dfef69b2f03a3a9060600160405180910390a173ffffffffffffffffffffffffffffffffffffffff8216632f2ff15d7f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b929336040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152600481019290925273ffffffffffffffffffffffffffffffffffffffff166024820152604401600060405180830381600087803b158015610f0c57600080fd5b505af1158015610f20573d6000803e3d6000fd5b505050508173ffffffffffffffffffffffffffffffffffffffff16632f2ff15d7fc806897caf4fd5068191157e44d3988e43139a37e0b97b6793e1ed1184140604610f683390565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152600481019290925273ffffffffffffffffffffffffffffffffffffffff166024820152604401600060405180830381600087803b158015610fd457600080fd5b505af1158015610fe8573d6000803e3d6000fd5b509396505050505050505b919050565b611002813361124f565b50565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff166110f95760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556110973390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610475565b506000610475565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16156110f95760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610475565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008260601b60e81c176000526e5af43d82803e903d91602b57fd5bf38260781b17602052603760096000f0905073ffffffffffffffffffffffffffffffffffffffff8116610ff3576040517fc2f868f400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff166112d5576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260248101839052604401610598565b5050565b6000602082840312156112eb57600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461131b57600080fd5b9392505050565b60006020828403121561133457600080fd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff8116811461100257600080fd5b6000806040838503121561137057600080fd5b8235915060208301356113828161133b565b809150509250929050565b60006020828403121561139f57600080fd5b813561131b8161133b565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610475576104756113aa565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361141d5761141d6113aa565b5060010190565b6000806000806080858703121561143a57600080fd5b505082516020840151604085015160609095015191969095509092509050565b6000825160005b8181101561147b5760208186018101518583015201611461565b50600092019182525091905056fea26469706673582212202f7eb2a534e57f2d8c4c40fd0773925f68a178aa5089c7fef5e5b1d88b4d5e0164736f6c63430008150033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000ba5c971c3178ea8755bfb6996a42f3ae24e81344
-----Decoded View---------------
Arg [0] : initialTemplate (address): 0xBa5c971C3178Ea8755BfB6996A42f3AE24E81344
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000ba5c971c3178ea8755bfb6996a42f3ae24e81344
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 31 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.