ETH Price: $3,381.40 (-1.56%)

Contract

0x468dA0eE5570Bdb1Dd81bFd925BAf028A93Dce64

Overview

ETH Balance

0 ETH

ETH Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

Parent Transaction Hash Block From To
View All Internal Transactions

Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
SecurityCouncilManager

Compiler Version
v0.8.16+commit.07a7930e

Optimization Enabled:
Yes with 1500 runs

Other Settings:
london EvmVersion
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.16;

import "../ArbitrumTimelock.sol";
import "../UpgradeExecutor.sol";
import "../L1ArbitrumTimelock.sol";
import "./SecurityCouncilMgmtUtils.sol";
import "./interfaces/ISecurityCouncilManager.sol";
import "./SecurityCouncilMemberSyncAction.sol";
import "../UpgradeExecRouteBuilder.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import "./Common.sol";

/// @title  The Security Council Manager
/// @notice The source of truth for an array of Security Councils that are under management.
///         Can be used to change members, and replace whole cohorts, ensuring that all managed
///         Security Councils stay in sync.
/// @dev    The cohorts in the Security Council Manager can be updated from a number of different sources.
///         Care must be taken in the timing of these updates to avoid race conditions, as well as to avoid
///         invalidating other operations.
///         An example of this could be replacing a member whilst there is an ongoing election. This contract
///         ensures that a member cannot be in both cohorts, so if a cohort is elected but just prior the security
///         council decides to replace a member in the previous cohort, then a member could end up in both cohorts.
///         Since the functions in this contract ensure that this cannot be case, one of the transactions will fail.
///         To avoid this care must be taken whilst elections are ongoing.
contract SecurityCouncilManager is
    Initializable,
    AccessControlUpgradeable,
    ISecurityCouncilManager
{
    event CohortReplaced(address[] newCohort, Cohort indexed cohort);
    event MemberAdded(address indexed newMember, Cohort indexed cohort);
    event MemberRemoved(address indexed member, Cohort indexed cohort);
    event MemberReplaced(address indexed replacedMember, address indexed newMember, Cohort cohort);
    event MemberRotated(address indexed replacedAddress, address indexed newAddress, Cohort cohort);
    event SecurityCouncilAdded(
        address indexed securityCouncil,
        address indexed updateAction,
        uint256 securityCouncilsLength
    );
    event SecurityCouncilRemoved(
        address indexed securityCouncil,
        address indexed updateAction,
        uint256 securityCouncilsLength
    );
    event UpgradeExecRouteBuilderSet(address indexed UpgradeExecRouteBuilder);

    // The Security Council members are separated into two cohorts, allowing a whole cohort to be replaced, as
    // specified by the Arbitrum Constitution.
    // These two cohort arrays contain the source of truth for the members of the Security Council. When a membership
    // change needs to be made, a change to these arrays is first made here locally, then pushed to each of the Security Councils
    // A member cannot be in both cohorts at the same time
    address[] internal firstCohort;
    address[] internal secondCohort;

    /// @notice Address of the l2 timelock used by core governance
    address payable public l2CoreGovTimelock;

    /// @notice The list of Security Councils under management. Any changes to the cohorts in this manager
    ///         will be pushed to each of these security councils, ensuring that they all stay in sync
    SecurityCouncilData[] public securityCouncils;

    /// @notice Address of UpgradeExecRouteBuilder. Used to help create security council updates
    UpgradeExecRouteBuilder public router;

    /// @notice Maximum possible number of Security Councils to manage
    /// @dev    Since the councils array will be iterated this provides a safety check to make too many Sec Councils
    ///         aren't added to the array.
    uint256 public immutable MAX_SECURITY_COUNCILS = 500;

    /// @notice Nonce to ensure that scheduled updates create unique entries in the timelocks
    uint256 public updateNonce;

    /// @notice Size of cohort under ordinary circumstances
    uint256 public cohortSize;

    /// @notice Magic value used by the L1 timelock to indicate that a retryable ticket should be created
    ///         Value is defined in L1ArbitrumTimelock contract https://etherscan.io/address/0xE6841D92B0C345144506576eC13ECf5103aC7f49#readProxyContract#F5
    address public constant RETRYABLE_TICKET_MAGIC = 0xa723C008e76E379c55599D2E4d93879BeaFDa79C;

    bytes32 public constant COHORT_REPLACER_ROLE = keccak256("COHORT_REPLACER");
    bytes32 public constant MEMBER_ADDER_ROLE = keccak256("MEMBER_ADDER");
    bytes32 public constant MEMBER_REPLACER_ROLE = keccak256("MEMBER_REPLACER");
    bytes32 public constant MEMBER_ROTATOR_ROLE = keccak256("MEMBER_ROTATOR");
    bytes32 public constant MEMBER_REMOVER_ROLE = keccak256("MEMBER_REMOVER");

    constructor() {
        _disableInitializers();
    }

    function initialize(
        address[] memory _firstCohort,
        address[] memory _secondCohort,
        SecurityCouncilData[] memory _securityCouncils,
        SecurityCouncilManagerRoles memory _roles,
        address payable _l2CoreGovTimelock,
        UpgradeExecRouteBuilder _router
    ) external initializer {
        if (_firstCohort.length != _secondCohort.length) {
            revert CohortLengthMismatch(_firstCohort, _secondCohort);
        }
        firstCohort = _firstCohort;
        secondCohort = _secondCohort;
        cohortSize = _firstCohort.length;
        _grantRole(DEFAULT_ADMIN_ROLE, _roles.admin);
        _grantRole(COHORT_REPLACER_ROLE, _roles.cohortUpdator);
        _grantRole(MEMBER_ADDER_ROLE, _roles.memberAdder);
        for (uint256 i = 0; i < _roles.memberRemovers.length; i++) {
            _grantRole(MEMBER_REMOVER_ROLE, _roles.memberRemovers[i]);
        }
        _grantRole(MEMBER_ROTATOR_ROLE, _roles.memberRotator);
        _grantRole(MEMBER_REPLACER_ROLE, _roles.memberReplacer);

        if (!Address.isContract(_l2CoreGovTimelock)) {
            revert NotAContract({account: _l2CoreGovTimelock});
        }
        l2CoreGovTimelock = _l2CoreGovTimelock;

        _setUpgradeExecRouteBuilder(_router);
        for (uint256 i = 0; i < _securityCouncils.length; i++) {
            _addSecurityCouncil(_securityCouncils[i]);
        }
    }

    /// @inheritdoc ISecurityCouncilManager
    function replaceCohort(address[] memory _newCohort, Cohort _cohort)
        external
        onlyRole(COHORT_REPLACER_ROLE)
    {
        if (_newCohort.length != cohortSize) {
            revert InvalidNewCohortLength({cohort: _newCohort, cohortSize: cohortSize});
        }

        // delete the old cohort
        _cohort == Cohort.FIRST ? delete firstCohort : delete secondCohort;

        for (uint256 i = 0; i < _newCohort.length; i++) {
            _addMemberToCohortArray(_newCohort[i], _cohort);
        }

        _scheduleUpdate();
        emit CohortReplaced(_newCohort, _cohort);
    }

    function _addMemberToCohortArray(address _newMember, Cohort _cohort) internal {
        if (_newMember == address(0)) {
            revert ZeroAddress();
        }
        address[] storage cohort = _cohort == Cohort.FIRST ? firstCohort : secondCohort;
        if (cohort.length == cohortSize) {
            revert CohortFull({cohort: _cohort});
        }
        if (firstCohortIncludes(_newMember)) {
            revert MemberInCohort({member: _newMember, cohort: Cohort.FIRST});
        }
        if (secondCohortIncludes(_newMember)) {
            revert MemberInCohort({member: _newMember, cohort: Cohort.SECOND});
        }

        cohort.push(_newMember);
    }

    function _removeMemberFromCohortArray(address _member) internal returns (Cohort) {
        for (uint256 i = 0; i < 2; i++) {
            address[] storage cohort = i == 0 ? firstCohort : secondCohort;
            for (uint256 j = 0; j < cohort.length; j++) {
                if (_member == cohort[j]) {
                    cohort[j] = cohort[cohort.length - 1];
                    cohort.pop();
                    return i == 0 ? Cohort.FIRST : Cohort.SECOND;
                }
            }
        }
        revert NotAMember({member: _member});
    }

    /// @inheritdoc ISecurityCouncilManager
    function addMember(address _newMember, Cohort _cohort) external onlyRole(MEMBER_ADDER_ROLE) {
        _addMemberToCohortArray(_newMember, _cohort);
        _scheduleUpdate();
        emit MemberAdded(_newMember, _cohort);
    }

    /// @inheritdoc ISecurityCouncilManager
    function removeMember(address _member) external onlyRole(MEMBER_REMOVER_ROLE) {
        if (_member == address(0)) {
            revert ZeroAddress();
        }
        Cohort cohort = _removeMemberFromCohortArray(_member);
        _scheduleUpdate();
        emit MemberRemoved({member: _member, cohort: cohort});
    }

    /// @inheritdoc ISecurityCouncilManager
    function replaceMember(address _memberToReplace, address _newMember)
        external
        onlyRole(MEMBER_REPLACER_ROLE)
    {
        Cohort cohort = _swapMembers(_memberToReplace, _newMember);
        emit MemberReplaced({
            replacedMember: _memberToReplace,
            newMember: _newMember,
            cohort: cohort
        });
    }

    /// @inheritdoc ISecurityCouncilManager
    function rotateMember(address _currentAddress, address _newAddress)
        external
        onlyRole(MEMBER_ROTATOR_ROLE)
    {
        Cohort cohort = _swapMembers(_currentAddress, _newAddress);
        emit MemberRotated({
            replacedAddress: _currentAddress,
            newAddress: _newAddress,
            cohort: cohort
        });
    }

    function _swapMembers(address _addressToRemove, address _addressToAdd)
        internal
        returns (Cohort)
    {
        if (_addressToRemove == address(0) || _addressToAdd == address(0)) {
            revert ZeroAddress();
        }
        Cohort cohort = _removeMemberFromCohortArray(_addressToRemove);
        _addMemberToCohortArray(_addressToAdd, cohort);
        _scheduleUpdate();
        return cohort;
    }

    function _addSecurityCouncil(SecurityCouncilData memory _securityCouncilData) internal {
        if (securityCouncils.length == MAX_SECURITY_COUNCILS) {
            revert MaxSecurityCouncils(securityCouncils.length);
        }

        if (
            _securityCouncilData.updateAction == address(0)
                || _securityCouncilData.securityCouncil == address(0)
        ) {
            revert ZeroAddress();
        }

        if (_securityCouncilData.chainId == 0) {
            revert SecurityCouncilZeroChainID(_securityCouncilData);
        }

        if (!router.upExecLocationExists(_securityCouncilData.chainId)) {
            revert SecurityCouncilNotInRouter(_securityCouncilData);
        }

        for (uint256 i = 0; i < securityCouncils.length; i++) {
            SecurityCouncilData storage existantSecurityCouncil = securityCouncils[i];

            if (
                existantSecurityCouncil.chainId == _securityCouncilData.chainId
                    && existantSecurityCouncil.securityCouncil == _securityCouncilData.securityCouncil
            ) {
                revert SecurityCouncilAlreadyInRouter(_securityCouncilData);
            }
        }

        securityCouncils.push(_securityCouncilData);
        emit SecurityCouncilAdded(
            _securityCouncilData.securityCouncil,
            _securityCouncilData.updateAction,
            securityCouncils.length
        );
    }

    /// @inheritdoc ISecurityCouncilManager
    function addSecurityCouncil(SecurityCouncilData memory _securityCouncilData)
        external
        onlyRole(DEFAULT_ADMIN_ROLE)
    {
        _addSecurityCouncil(_securityCouncilData);
    }

    /// @inheritdoc ISecurityCouncilManager
    function removeSecurityCouncil(SecurityCouncilData memory _securityCouncilData)
        external
        onlyRole(DEFAULT_ADMIN_ROLE)
        returns (bool)
    {
        for (uint256 i = 0; i < securityCouncils.length; i++) {
            SecurityCouncilData storage securityCouncilData = securityCouncils[i];
            if (
                securityCouncilData.securityCouncil == _securityCouncilData.securityCouncil
                    && securityCouncilData.chainId == _securityCouncilData.chainId
                    && securityCouncilData.updateAction == _securityCouncilData.updateAction
            ) {
                SecurityCouncilData storage lastSecurityCouncil =
                    securityCouncils[securityCouncils.length - 1];

                securityCouncils[i] = lastSecurityCouncil;
                securityCouncils.pop();
                emit SecurityCouncilRemoved(
                    securityCouncilData.securityCouncil,
                    securityCouncilData.updateAction,
                    securityCouncils.length
                );
                return true;
            }
        }
        revert SecurityCouncilNotInManager(_securityCouncilData);
    }

    /// @inheritdoc ISecurityCouncilManager
    function setUpgradeExecRouteBuilder(UpgradeExecRouteBuilder _router)
        external
        onlyRole(DEFAULT_ADMIN_ROLE)
    {
        _setUpgradeExecRouteBuilder(_router);
    }

    function _setUpgradeExecRouteBuilder(UpgradeExecRouteBuilder _router) internal {
        address routerAddress = address(_router);

        if (!Address.isContract(routerAddress)) {
            revert NotAContract({account: routerAddress});
        }

        router = _router;
        emit UpgradeExecRouteBuilderSet(routerAddress);
    }

    /// @inheritdoc ISecurityCouncilManager
    function getFirstCohort() external view returns (address[] memory) {
        return firstCohort;
    }

    /// @inheritdoc ISecurityCouncilManager
    function getSecondCohort() external view returns (address[] memory) {
        return secondCohort;
    }

    /// @inheritdoc ISecurityCouncilManager
    function getBothCohorts() public view returns (address[] memory) {
        address[] memory members = new address[](firstCohort.length + secondCohort.length);
        for (uint256 i = 0; i < firstCohort.length; i++) {
            members[i] = firstCohort[i];
        }
        for (uint256 i = 0; i < secondCohort.length; i++) {
            members[firstCohort.length + i] = secondCohort[i];
        }
        return members;
    }

    /// @inheritdoc ISecurityCouncilManager
    function securityCouncilsLength() public view returns (uint256) {
        return securityCouncils.length;
    }

    /// @inheritdoc ISecurityCouncilManager
    function firstCohortIncludes(address account) public view returns (bool) {
        return cohortIncludes(Cohort.FIRST, account);
    }

    /// @inheritdoc ISecurityCouncilManager
    function secondCohortIncludes(address account) public view returns (bool) {
        return cohortIncludes(Cohort.SECOND, account);
    }

    /// @inheritdoc ISecurityCouncilManager
    function cohortIncludes(Cohort cohort, address account) public view returns (bool) {
        address[] memory cohortMembers = cohort == Cohort.FIRST ? firstCohort : secondCohort;
        return SecurityCouncilMgmtUtils.isInArray(account, cohortMembers);
    }

    /// @inheritdoc ISecurityCouncilManager
    function generateSalt(address[] memory _members, uint256 nonce)
        external
        pure
        returns (bytes32)
    {
        return keccak256(abi.encode(_members, nonce));
    }

    /// @inheritdoc ISecurityCouncilManager
    function getScheduleUpdateInnerData(uint256 nonce)
        public
        view
        returns (address[] memory, address, bytes memory)
    {
        // build a union array of security council members
        address[] memory newMembers = getBothCohorts();

        // build batch call to L1 timelock
        address[] memory actionAddresses = new address[](securityCouncils.length);
        bytes[] memory actionDatas = new bytes[](securityCouncils.length);
        uint256[] memory chainIds = new uint256[](securityCouncils.length);

        for (uint256 i = 0; i < securityCouncils.length; i++) {
            SecurityCouncilData memory securityCouncilData = securityCouncils[i];
            actionAddresses[i] = securityCouncilData.updateAction;
            chainIds[i] = securityCouncilData.chainId;
            actionDatas[i] = abi.encodeWithSelector(
                SecurityCouncilMemberSyncAction.perform.selector,
                securityCouncilData.securityCouncil,
                newMembers,
                nonce
            );
        }

        // unique salt used for replay protection in the L1 timelock
        bytes32 salt = this.generateSalt(newMembers, nonce);
        (address to, bytes memory data) = router.createActionRouteData(
            chainIds,
            actionAddresses,
            new uint256[](securityCouncils.length), // all values are always 0
            actionDatas,
            0,
            salt
        );

        return (newMembers, to, data);
    }

    /// @dev Create a union of the second and first cohort, then update all Security Councils under management with that unioned array.
    ///      Updates will need to be scheduled through timelocks and target upgrade executors
    function _scheduleUpdate() internal {
        // always update the nonce
        // this is used to ensure that proposals in the timelocks are unique
        // and calls to the upgradeExecutors are in the correct order
        updateNonce++;
        (address[] memory newMembers, address to, bytes memory data) =
            getScheduleUpdateInnerData(updateNonce);

        ArbitrumTimelock(l2CoreGovTimelock).schedule({
            target: to, // ArbSys address - this will trigger a call from L2->L1
            value: 0,
            // call to ArbSys.sendTxToL1; target the L1 timelock with the calldata previously constructed
            data: data,
            predecessor: bytes32(0),
            // must be unique as the proposal hash is used for replay protection in the L2 timelock
            // we cant be sure another proposal wont use this salt, and the same target + data
            // but in that case the proposal will do what we want it to do anyway
            // this can however block the execution of the election - so in this case the
            // Security Council would need to unblock it by setting the election to executed state
            // in the Member Election governor
            salt: this.generateSalt(newMembers, updateNonce),
            delay: ArbitrumTimelock(l2CoreGovTimelock).getMinDelay()
        });
    }
    /**
     * @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[43] private __gap;
}

// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.16;

import "@openzeppelin/contracts-upgradeable/governance/TimelockControllerUpgradeable.sol";

/// @title  Timelock to be used in Arbitrum governance
/// @notice Take care when using the predecessor field when scheduling. Since proposals
///         can make cross chain calls and those calls are async, it is not guaranteed that they will
//          be executed cross chain in the same order that they are executed in this timelock. Do not use
///         the predecessor field to preserve ordering in these situations.
/// @dev    This contract adds the ability to initialize TimelockControllerUpgradeable, and also has custom
///         logic for setting the min delay.
contract ArbitrumTimelock is TimelockControllerUpgradeable {
    constructor() {
        _disableInitializers();
    }

    // named differently to the private _minDelay on the base to avoid confusion
    uint256 private _arbMinDelay;

    /// @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;

    /// @notice Initialise the timelock
    /// @param minDelay The minimum amount of delay enforced by this timelock
    /// @param proposers The accounts allowed to propose actions
    /// @param executors The accounts allowed to execute action
    function initialize(uint256 minDelay, address[] memory proposers, address[] memory executors)
        external
        initializer
    {
        __ArbitrumTimelock_init(minDelay, proposers, executors);
    }

    function __ArbitrumTimelock_init(
        uint256 minDelay,
        address[] memory proposers,
        address[] memory executors
    ) internal onlyInitializing {
        // although we're passing minDelay into the TimelockController_init the state variable that it
        // sets will not be used since we override getMinDelay below. Given that we could pass in a 0
        // here to be clear that this param isn't used, however __TimelockController_init also emits the
        // MinDelayChange event so it's useful to keep the same value there as we are setting here
        __TimelockController_init(minDelay, proposers, executors);
        _arbMinDelay = minDelay;
    }

    /**
     * @dev Changes the minimum timelock duration for future operations.
     *
     * Emits a {MinDelayChange} event.
     *
     * Requirements:
     *
     * - the caller must have the TIMELOCK_ADMIN_ROLE role.
     *
     * This function is override to preserve the invariants that all changes to the system
     * must do a round trip, and must be executed from an UpgradeExecutor. The overriden function
     * only allows delay to be set by address(this). This is done by creating a proposal that has
     * address(this) as its target, and call updateDelay upon execution. This would mean that a
     * proposal could set the delay directly on the timelock, without originating from an UpgradeExecutor.
     * Here we override the the function and only allow it to be set by the timelock admin
     * which is expected to be the UpgradeExecutor to avoid the above scenario.
     *
     * It should be noted that although the avoided scenario does break the invariants we wish to
     * maintain, it doesn't pose a security risk as the proposal would still have to go through one timelock to change
     * the delay, and then future proposals would still need to go through the other timelocks.
     * So upon seeing the proposal to change the timelock users would still need to intiate their exits
     * before the timelock duration has passed, which is the same requirement we have for proposals
     * that properly do round trips.
     */
    function updateDelay(uint256 newDelay)
        external
        virtual
        override
        onlyRole(TIMELOCK_ADMIN_ROLE)
    {
        emit MinDelayChange(_arbMinDelay, newDelay);
        _arbMinDelay = newDelay;
    }

    /// @inheritdoc TimelockControllerUpgradeable
    function getMinDelay() public view virtual override returns (uint256 duration) {
        return _arbMinDelay;
    }
}

// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.16;

import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/Address.sol";

/// @title  A root contract from which it execute upgrades
/// @notice Does not contain upgrade logic itself, only the means to call upgrade contracts and execute them
/// @dev    We use these upgrade contracts as they allow multiple actions to take place in an upgrade
///         and for these actions to interact. However because we are delegatecalling into these upgrade
///         contracts, it's important that these upgrade contract do not touch or modify contract state.
contract UpgradeExecutor is Initializable, AccessControlUpgradeable, ReentrancyGuard {
    using Address for address;

    bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE");
    bytes32 public constant EXECUTOR_ROLE = keccak256("EXECUTOR_ROLE");

    /// @notice Emitted when an upgrade execution occurs
    event UpgradeExecuted(address indexed upgrade, uint256 value, bytes data);

    constructor() {
        _disableInitializers();
    }

    /// @notice Initialise the upgrade executor
    /// @param admin The admin who can update other roles, and itself - ADMIN_ROLE
    /// @param executors Can call the execute function - EXECUTOR_ROLE
    function initialize(address admin, address[] memory executors) public initializer {
        require(admin != address(0), "UpgradeExecutor: zero admin");

        __AccessControl_init();

        _setRoleAdmin(ADMIN_ROLE, ADMIN_ROLE);
        _setRoleAdmin(EXECUTOR_ROLE, ADMIN_ROLE);

        _setupRole(ADMIN_ROLE, admin);
        for (uint256 i = 0; i < executors.length; ++i) {
            _setupRole(EXECUTOR_ROLE, executors[i]);
        }
    }

    /// @notice Execute an upgrade by delegate calling an upgrade contract
    /// @dev    Only executor can call this. Since we're using a delegatecall here the Upgrade contract
    ///         will have access to the state of this contract - including the roles. Only upgrade contracts
    ///         that do not touch local state should be used.
    function execute(address upgrade, bytes memory upgradeCallData)
        public
        payable
        onlyRole(EXECUTOR_ROLE)
        nonReentrant
    {
        // OZ Address library check if the address is a contract and bubble up inner revert reason
        address(upgrade).functionDelegateCall(
            upgradeCallData, "UpgradeExecutor: inner delegate call failed without reason"
        );

        emit UpgradeExecuted(upgrade, msg.value, upgradeCallData);
    }
}

// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.16;

import "@arbitrum/nitro-contracts/src/bridge/IInbox.sol";
import "./L1ArbitrumMessenger.sol";
import "./ArbitrumTimelock.sol";

interface IInboxSubmissionFee {
    function calculateRetryableSubmissionFee(uint256 dataLength, uint256 baseFee)
        external
        view
        returns (uint256);
}

/// @title L1 timelock for executing propsals on L1 or forwarding them back to L2
/// @dev   Only accepts proposals from a counterparty L2 timelock
///        If ever upgrading to a later version of TimelockControllerUpgradeable be sure to check that
///        no new behaviour has been given to the PROPOSER role, as this is assigned to the bridge
///        and any new behaviour should be overriden to also include the 'onlyCounterpartTimelock' modifier check
contract L1ArbitrumTimelock is ArbitrumTimelock, L1ArbitrumMessenger {
    /// @notice The magic address to be used when a retryable ticket is to be created
    /// @dev When the target of an proposal is this magic value then the proposal
    ///      will be formed into a retryable ticket and posted to an inbox provided in
    ///      the data
    ///      address below is: address(bytes20(keccak256(bytes("retryable ticket magic"))));
    ///      we hardcode the bytes rather than the string as it's slightly cheaper
    ///      we use the bytes20 of the keccak since just the bytes20 of the string doesnt contain
    ///      many letters which would make EIP-55 checksum checking less useful
    address public constant RETRYABLE_TICKET_MAGIC = 0xa723C008e76E379c55599D2E4d93879BeaFDa79C;
    /// @notice The inbox for the L2 where governance is based
    address public governanceChainInbox;
    /// @notice The timelock of the governance contract on L2
    address public l2Timelock;

    constructor() {
        _disableInitializers();
    }

    /// @notice             Initialise the L1 timelock
    /// @param minDelay     The minimum amount of delay this timelock should enforce
    /// @param executors    The addresses that can execute a proposal (set address(0) for open execution)
    /// @param _governanceChainInbox       The address of the inbox contract, for the L2 chain on which governance is based.
    ///                     For the Arbitrum DAO this the Arb1 inbox
    /// @param _l2Timelock  The address of the timelock on the L2 where governance is based
    ///                     For the Arbitrum DAO this the Arbitrum DAO timelock on Arb1
    function initialize(
        uint256 minDelay,
        address[] memory executors,
        address _governanceChainInbox,
        address _l2Timelock
    ) external initializer {
        require(_governanceChainInbox != address(0), "L1ArbitrumTimelock: zero inbox");
        require(_l2Timelock != address(0), "L1ArbitrumTimelock: zero l2 timelock");
        // this timelock doesnt accept any proposers since they wont pass the
        // onlyCounterpartTimelock check
        address[] memory proposers;
        __ArbitrumTimelock_init(minDelay, proposers, executors);

        governanceChainInbox = _governanceChainInbox;
        l2Timelock = _l2Timelock;

        // the bridge is allowed to create proposals
        // and we ensure that the l2 caller is the l2timelock
        // by using the onlyCounterpartTimelock modifier
        address bridge = address(getBridge(_governanceChainInbox));
        grantRole(PROPOSER_ROLE, bridge);
    }

    modifier onlyCounterpartTimelock() {
        // this bridge == msg.sender check is redundant in all the places that
        // we currently use this modifier since we call a function on super
        // that also checks the proposer role, which we enforce is in the intializer above
        // so although the msg.sender is being checked against the bridge twice we
        // still leave this check here for consistency of this function and in case
        // onlyCounterpartTimelock is used on other functions without this proposer check
        // in future
        address govChainBridge = address(getBridge(governanceChainInbox));
        require(msg.sender == govChainBridge, "L1ArbitrumTimelock: not from bridge");

        // the outbox reports that the L2 address of the sender is the counterpart gateway
        address l2ToL1Sender = super.getL2ToL1Sender(governanceChainInbox);
        require(l2ToL1Sender == l2Timelock, "L1ArbitrumTimelock: not from l2 timelock");
        _;
    }

    /// @inheritdoc TimelockControllerUpgradeable
    /// @notice Care should be taken when batching together proposals that make cross chain calls
    ///         Since cross chain calls are async, it is not guaranteed that they will be executed cross
    ///         chain in the same order that they are executed in this timelock. Do not use
    ///         the predecessor field to preserve ordering in these situations.
    /// @dev Adds the restriction that only the counterparty timelock can call this func
    /// @param predecessor  Do not use predecessor to preserve ordering for proposals that make cross
    ///                     chain calls, since those calls are executed async it and do not preserve order themselves.
    function scheduleBatch(
        address[] calldata targets,
        uint256[] calldata values,
        bytes[] calldata payloads,
        bytes32 predecessor,
        bytes32 salt,
        uint256 delay
    ) public virtual override(TimelockControllerUpgradeable) onlyCounterpartTimelock {
        TimelockControllerUpgradeable.scheduleBatch(
            targets, values, payloads, predecessor, salt, delay
        );
    }

    /// @inheritdoc TimelockControllerUpgradeable
    /// @dev Adds the restriction that only the counterparty timelock can call this func
    /// @param predecessor  Do not use predecessor to preserve ordering for proposals that make cross
    ///                     chain calls, since those calls are executed async it and do not preserve order themselves.
    function schedule(
        address target,
        uint256 value,
        bytes calldata data,
        bytes32 predecessor,
        bytes32 salt,
        uint256 delay
    ) public virtual override(TimelockControllerUpgradeable) onlyCounterpartTimelock {
        TimelockControllerUpgradeable.schedule(target, value, data, predecessor, salt, delay);
    }

    /// @dev If the target is reserved "magic" retryable ticket address address(bytes20(bytes("retryable ticket magic")))
    /// we create a retryable ticket at provided inbox; otherwise, we execute directly
    function _execute(address target, uint256 value, bytes calldata data)
        internal
        virtual
        override
    {
        if (target == RETRYABLE_TICKET_MAGIC) {
            // if the target is reserved retryable ticket address,
            // we retrieve the inbox from the data object and
            // then we create a retryable ticket,
            (
                address targetInbox,
                address l2Target,
                uint256 l2Value,
                // it isn't strictly necessary to allow gasLimit and maxFeePerGas to be provided
                // here as these can be updated when executing the retryable on L2. However, a proposal
                // might provide reasonable values here, and in the optimistic case they will provide
                // enough gas for l2 execution, and therefore a manual redeem of the retryable on L2 won't
                // be required
                uint256 gasLimit,
                uint256 maxFeePerGas,
                bytes memory l2Calldata
            ) = abi.decode(data, (address, address, uint256, uint256, uint256, bytes));

            // submission fee is dependent on base fee, by looking this up here
            // and ensuring we send enough value to cover it we can be sure that
            // a retryable ticket will be created.
            uint256 submissionCost = IInboxSubmissionFee(targetInbox)
                .calculateRetryableSubmissionFee(l2Calldata.length, block.basefee);

            // create a retryable ticket
            // note that the "value" argument has been completely ignored as it cannot . The msg.sender then needs to supply value to this
            // function to cover the calculated value.
            sendTxToL2CustomRefund(
                targetInbox,
                l2Target,
                // we set the msg.sender as the fee refund address as the sender here as it may be hard
                // for the sender here to provide the exact amount of value (that depends on the current basefee)
                // so if they provide extra the leftovers will be sent to their address on L2
                msg.sender,
                // this is the callValueRefundAddress which is able to cancel() the retryable
                // it's important that only this address, or another DAO controlled one is able to
                // cancel, otherwise anyone could cancel, and therefore block, the upgrade
                address(this),
                // Enough value needs to be sent to cover both the l2 value and the l2 gas costs
                // The value for each of these must be injected via msg.value or via calling receive and providing value earlier
                // It is hard for the caller to estimate the submissionCost offchain since by the time the tx is mined the l1 base fee may have changed.
                // Therefore it is expected that the caller will need to provide slightly more value than is actually used,
                // leaving some surplus in this contrat after execution has completed. This contract does not
                // provide a way to retrieve this surplus, since it is expected that the surplus will be very small.
                // Should a caller wish to they could call this contract from another one which does the exact submission cost
                // estimation, but doing so would likely be more expensive than just sacrificing the surplus/
                l2Value + submissionCost + (gasLimit * maxFeePerGas),
                l2Value,
                L2GasParams({
                    _maxSubmissionCost: submissionCost,
                    _maxGas: gasLimit,
                    _gasPriceBid: maxFeePerGas
                }),
                l2Calldata
            );
        } else {
            if (data.length != 0) {
                // check the target has code if data was supplied
                // this is a bit more important than normal here since if the magic is improperly
                // specified in the proposal then we'll end up in this code block
                // generally though, all proposals with data that specify a target with no code should
                // be voted against
                uint256 size = target.code.length;
                require(size > 0, "L1ArbitrumTimelock: target must be contract");
            }

            // Not a retryable ticket, so we simply execute
            super._execute(target, value, data);
        }
    }
}

// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.16;

library SecurityCouncilMgmtUtils {
    function isInArray(address addr, address[] memory arr) internal pure returns (bool) {
        for (uint256 i = 0; i < arr.length; i++) {
            if (arr[i] == addr) {
                return true;
            }
        }
        return false;
    }

    // filters an array of addresses by removing any addresses that are in the excludeList
    function filterAddressesWithExcludeList(
        address[] memory input,
        mapping(address => bool) storage excludeList
    ) internal view returns (address[] memory) {
        address[] memory intermediate = new address[](input.length);
        uint256 intermediateLength = 0;

        for (uint256 i = 0; i < input.length; i++) {
            address nominee = input[i];
            if (!excludeList[nominee]) {
                intermediate[intermediateLength] = nominee;
                intermediateLength++;
            }
        }

        address[] memory output = new address[](intermediateLength);
        for (uint256 i = 0; i < intermediateLength; i++) {
            output[i] = intermediate[i];
        }

        return output;
    }
}

// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.16;

import "../../UpgradeExecRouteBuilder.sol";
import "../Common.sol";

/// @notice Addresses to be given specific roles on the Security Council Manager
struct SecurityCouncilManagerRoles {
    address admin;
    address cohortUpdator;
    address memberAdder;
    address[] memberRemovers;
    address memberRotator;
    address memberReplacer;
}

/// @notice Data for a Security Council to be managed
struct SecurityCouncilData {
    /// @notice Address of the Security Council
    address securityCouncil;
    /// @notice Address of the update action contract that contains the logic for
    ///         updating council membership. Will be delegate called by the upgrade executor
    address updateAction;
    uint256 chainId;
}

interface ISecurityCouncilManager {
    // security council cohort errors
    error NotAMember(address member);
    error MemberInCohort(address member, Cohort cohort);
    error CohortFull(Cohort cohort);
    error InvalidNewCohortLength(address[] cohort, uint256 cohortSize);
    error CohortLengthMismatch(address[] cohort1, address[] cohort2);
    error InvalidCohort(Cohort cohort);

    // security council data errors
    error MaxSecurityCouncils(uint256 securityCouncilCount);
    error SecurityCouncilZeroChainID(SecurityCouncilData securiyCouncilData);
    error SecurityCouncilNotInRouter(SecurityCouncilData securiyCouncilData);
    error SecurityCouncilNotInManager(SecurityCouncilData securiyCouncilData);
    error SecurityCouncilAlreadyInRouter(SecurityCouncilData securiyCouncilData);

    /// @notice initialize SecurityCouncilManager.
    /// @param _firstCohort addresses of first cohort
    /// @param _secondCohort addresses of second cohort
    /// @param _securityCouncils data of all security councils to manage
    /// @param _roles permissions for triggering modifications to security councils
    /// @param  _l2CoreGovTimelock timelock for core governance / constitutional proposal
    /// @param _router UpgradeExecRouteBuilder address
    function initialize(
        address[] memory _firstCohort,
        address[] memory _secondCohort,
        SecurityCouncilData[] memory _securityCouncils,
        SecurityCouncilManagerRoles memory _roles,
        address payable _l2CoreGovTimelock,
        UpgradeExecRouteBuilder _router
    ) external;
    /// @notice Replaces a whole cohort.
    /// @dev    Initiaties cross chain messages to update the individual Security Councils.
    /// @param _newCohort   New cohort members to replace existing cohort. Must have 6 members.
    /// @param _cohort      Cohort to replace.
    function replaceCohort(address[] memory _newCohort, Cohort _cohort) external;
    /// @notice Add a member to the specified cohort.
    ///         Cohorts cannot have more than 6 members, so the cohort must have less than 6 in order to call this.
    ///         New member cannot already be a member of either cohort.
    /// @dev    Initiaties cross chain messages to update the individual Security Councils.
    ///         When adding a member, make sure that the key does not conflict with any contenders/nominees of ongoing elections.
    /// @param _newMember   New member to add
    /// @param _cohort      Cohort to add member to
    function addMember(address _newMember, Cohort _cohort) external;
    /// @notice Remove a member.
    /// @dev    Searches both cohorts for the member.
    ///         Initiaties cross chain messages to update the individual Security Councils
    /// @param _member  Member to remove
    function removeMember(address _member) external;
    /// @notice Replace a member in a council - equivalent to removing a member, then adding another in its place.
    ///         Idendities of members should be different.
    ///         Functionality is equivalent to replaceMember,
    ///         though emits a different event to distinguish the security council's intent (different identities).
    /// @dev    Initiaties cross chain messages to update the individual Security Councils.
    ///         When replacing a member, make sure that the key does not conflict with any contenders/nominees of ongoing electoins.
    /// @param _memberToReplace Security Council member to remove
    /// @param _newMember       Security Council member to add in their place
    function replaceMember(address _memberToReplace, address _newMember) external;
    /// @notice Security council member can rotate out their address for a new one; _currentAddress and _newAddress should be of the same identity. Functionality is equivalent to replaceMember, tho emits a different event to distinguish the security council's intent (same identity).
    ///         Rotation must be initiated by the security council.
    /// @dev    Initiaties cross chain messages to update the individual Security Councils.
    ///         When rotating a member, make sure that the key does not conflict with any contenders/nominees of ongoing elections.
    /// @param _currentAddress  Address to rotate out
    /// @param _newAddress      Address to rotate in
    function rotateMember(address _currentAddress, address _newAddress) external;
    /// @notice Is the account a member of the first cohort
    function firstCohortIncludes(address account) external view returns (bool);
    /// @notice Is the account a member of the second cohort
    function secondCohortIncludes(address account) external view returns (bool);
    /// @notice Is the account a member of the specified cohort
    function cohortIncludes(Cohort cohort, address account) external view returns (bool);
    /// @notice All members of the first cohort
    function getFirstCohort() external view returns (address[] memory);
    /// @notice All members of the second cohort
    function getSecondCohort() external view returns (address[] memory);
    /// @notice All members of both cohorts
    function getBothCohorts() external view returns (address[] memory);
    /// @notice Length of security councils array
    function securityCouncilsLength() external view returns (uint256);
    /// @notice Size of cohort under ordinary circumstances
    function cohortSize() external view returns (uint256);
    /// @notice Add new security council to be included in security council management system.
    /// @param _securityCouncilData Security council info
    function addSecurityCouncil(SecurityCouncilData memory _securityCouncilData) external;
    /// @notice Remove security council from management system.
    /// @param _securityCouncilData   security council to be removed
    function removeSecurityCouncil(SecurityCouncilData memory _securityCouncilData)
        external
        returns (bool);
    /// @notice UpgradeExecRouteBuilder is immutable, so in lieu of upgrading it, it can be redeployed and reset here
    /// @param _router new router address
    function setUpgradeExecRouteBuilder(UpgradeExecRouteBuilder _router) external;
    /// @notice Gets the data that will be used to update each of the security councils
    /// @param nonce The nonce used to generate the timelock salts
    /// @return The new members to be added to the councils
    /// @return The address of the contract that will be called by the l2 timelock
    /// @return The data that will be called from the l2 timelock
    function getScheduleUpdateInnerData(uint256 nonce)
        external
        view
        returns (address[] memory, address, bytes memory);
    /// @notice Generate the salt used in the timelocks when scheduling an update
    /// @param _members The new members to be added
    /// @param nonce    The manager nonce to make the salt unique - current nonce can be found by calling updateNonce
    function generateSalt(address[] memory _members, uint256 nonce)
        external
        pure
        returns (bytes32);
    /// @notice Each update increments an internal nonce that keeps updates unique, current value stored here
    function updateNonce() external returns (uint256);
}

// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.16;

import "./interfaces/IGnosisSafe.sol";
import "./SecurityCouncilMgmtUtils.sol";
import "../gov-action-contracts/execution-record/ActionExecutionRecord.sol";

/// @notice Action contract for updating security council members. Used by the security council management system.
///         Expected to be delegate called into by an Upgrade Executor
contract SecurityCouncilMemberSyncAction is ActionExecutionRecord {
    error PreviousOwnerNotFound(address targetOwner, address securityCouncil);
    error ExecFromModuleError(bytes data, address securityCouncil);

    event UpdateNonceTooLow(
        address indexed securityCouncil, uint256 currrentNonce, uint256 providedNonce
    );

    /// @dev Used in the gnosis safe as the first entry in their ownership linked list
    address public constant SENTINEL_OWNERS = address(0x1);

    constructor(KeyValueStore _store)
        ActionExecutionRecord(_store, "SecurityCouncilMemberSyncAction")
    {}

    /// @notice Updates members of security council multisig to match provided array
    /// @dev    This function contains O(n^2) operations, so doesnt scale for large numbers of members. Expected count is 12, which is acceptable.
    ///         Gnosis OwnerManager handles reverting if address(0) is passed to remove/add owner
    /// @param _securityCouncil The security council to update
    /// @param _updatedMembers  The new list of members. The Security Council will be updated to have this exact list of members
    /// @return res indicates whether an update took place
    function perform(address _securityCouncil, address[] memory _updatedMembers, uint256 _nonce)
        external
        returns (bool res)
    {
        // make sure that _nonce is greater than the last nonce
        // we do this to ensure that a previous update does not occur after a later one
        // the mechanism just checks greater, not n+1, because the Security Council Manager always
        // sends the latest full list of members so it doesn't matter if some updates are missed
        // Additionally a retryable ticket could be used to execute the update, and since tickets
        // expire if not executed after some time, then allowing updates to be skipped means that the
        // system will not be blocked if a retryable ticket is expires
        uint256 updateNonce = getUpdateNonce(_securityCouncil);
        if (_nonce <= updateNonce) {
            // when nonce is too now, we simply return, we don't revert.
            // this way an out of date update will actual execute, rather than remaining in an unexecuted state forever
            emit UpdateNonceTooLow(_securityCouncil, updateNonce, _nonce);
            return false;
        }

        // store the nonce as a record of execution
        // use security council as the key to ensure that updates to different security councils are kept separate
        _setUpdateNonce(_securityCouncil, _nonce);

        IGnosisSafe securityCouncil = IGnosisSafe(_securityCouncil);
        // preserve current threshold, the safe ensures that the threshold is never lower than the member count
        uint256 threshold = securityCouncil.getThreshold();

        address[] memory previousOwners = securityCouncil.getOwners();

        for (uint256 i = 0; i < _updatedMembers.length; i++) {
            address member = _updatedMembers[i];
            if (!securityCouncil.isOwner(member)) {
                _addMember(securityCouncil, member, threshold);
            }
        }

        for (uint256 i = 0; i < previousOwners.length; i++) {
            address owner = previousOwners[i];
            if (!SecurityCouncilMgmtUtils.isInArray(owner, _updatedMembers)) {
                _removeMember(securityCouncil, owner, threshold);
            }
        }
        return true;
    }

    function _addMember(IGnosisSafe securityCouncil, address _member, uint256 _threshold)
        internal
    {
        _execFromModule(
            securityCouncil,
            abi.encodeWithSelector(IGnosisSafe.addOwnerWithThreshold.selector, _member, _threshold)
        );
    }

    function _removeMember(IGnosisSafe securityCouncil, address _member, uint256 _threshold)
        internal
    {
        address previousOwner = getPrevOwner(securityCouncil, _member);
        _execFromModule(
            securityCouncil,
            abi.encodeWithSelector(
                IGnosisSafe.removeOwner.selector, previousOwner, _member, _threshold
            )
        );
    }

    function getPrevOwner(IGnosisSafe securityCouncil, address _owner)
        public
        view
        returns (address)
    {
        // owners are stored as a linked list and removal requires the previous owner
        address[] memory owners = securityCouncil.getOwners();
        address previousOwner = SENTINEL_OWNERS;
        for (uint256 i = 0; i < owners.length; i++) {
            address currentOwner = owners[i];
            if (currentOwner == _owner) {
                return previousOwner;
            }
            previousOwner = currentOwner;
        }
        revert PreviousOwnerNotFound({
            targetOwner: _owner,
            securityCouncil: address(securityCouncil)
        });
    }

    function getUpdateNonce(address securityCouncil) public view returns (uint256) {
        return _get(uint160(securityCouncil));
    }

    function _setUpdateNonce(address securityCouncil, uint256 nonce) internal {
        _set(uint160(securityCouncil), nonce);
    }

    /// @notice Execute provided operation via gnosis safe's trusted execTransactionFromModule entry point
    function _execFromModule(IGnosisSafe securityCouncil, bytes memory data) internal {
        if (
            !securityCouncil.execTransactionFromModule(
                address(securityCouncil), 0, data, OpEnum.Operation.Call
            )
        ) {
            revert ExecFromModuleError({data: data, securityCouncil: address(securityCouncil)});
        }
    }
}

// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.16;

import "@arbitrum/nitro-contracts/src/precompiles/ArbSys.sol";
import "./UpgradeExecutor.sol";
import "./L1ArbitrumTimelock.sol";
import "./security-council-mgmt/Common.sol";

interface DefaultGovAction {
    function perform() external;
}

/// @notice The location of an upgrade executor, relative to the host chain.
///         Inbox is set to address(0) if the upgrade executor is on the host chain.
///         Inbox is set to the address of the inbox of another Arbitrum chain if the upgrade executor is
///         is not on the host chain.
struct UpExecLocation {
    address inbox; // Inbox should be set to address(0) to signify that the upgrade executor is on the L1/host chain
    address upgradeExecutor;
}

struct ChainAndUpExecLocation {
    uint256 chainId;
    UpExecLocation location;
}

/// @notice Builds calldata to target the execution of action contracts in upgrade executors that exist on other chains.
///         Routes target an upgrade executor which is either on the host chain, or can be accessed via the inbox.
///         So routes are of two possible forms:
///         1. Withdrawal => L1Timelock => UpgradeExecutor
///         2. Withdrawal => L1Timelock => Inbox => UpgradeExecutor
/// @dev    This contract makes the following assumptions:
///         * It is deployed on an L2 - more specifically it has access to an ArbSys which allows it to make withdrawal
///           transactions to a host chain
///         * It can only target one upgrade executor per chain
///         * The upgrade executors being targeted are either on the host chain, or are Arbitrum chains reachable
///           via inboxes on the host chain
///         * There exists a L1 timelock on the host chain
contract UpgradeExecRouteBuilder {
    error UpgadeExecDoesntExist(uint256 chainId);
    error UpgradeExecAlreadyExists(uint256 chindId);
    error ParamLengthMismatch(uint256 len1, uint256 len2);
    error EmptyActionBytesData(bytes[]);

    /// @notice The magic value used by the L1 timelock to indicate that a retryable ticket should be created
    ///         See L1ArbitrumTimelock for more details
    address public constant RETRYABLE_TICKET_MAGIC = 0xa723C008e76E379c55599D2E4d93879BeaFDa79C;
    /// @notice Default args for creating a proposal, used by createProposalWithDefaulArgs and createProposalBatchWithDefaultArgs
    ///         Default is function selector for a perform function with no args: 'function perform() external'
    bytes public constant DEFAULT_GOV_ACTION_CALLDATA =
        abi.encodeWithSelector(DefaultGovAction.perform.selector);
    uint256 public constant DEFAULT_VALUE = 0;
    /// @notice Default predecessor used when calling the L1 timelock
    bytes32 public constant DEFAULT_PREDECESSOR = bytes32(0);

    /// @notice Address of the L1 timelock targeted by this route builder
    address public immutable l1TimelockAddr;
    /// @notice The minimum delay of the L1 timelock targeted by this route builder
    /// @dev    If the min delay for this timelock changes then a new route builder will need to be deployed
    uint256 public immutable l1TimelockMinDelay;
    /// @notice Upgrade Executor locations for each chain (chainId => location)
    mapping(uint256 => UpExecLocation) public upExecLocations;

    /// @param _upgradeExecutors    Locations of the upgrade executors on each chain
    /// @param _l1ArbitrumTimelock  Address of the core gov L1 timelock
    /// @param _l1TimelockMinDelay  Minimum delay for L1 timelock
    constructor(
        ChainAndUpExecLocation[] memory _upgradeExecutors,
        address _l1ArbitrumTimelock,
        uint256 _l1TimelockMinDelay
    ) {
        if (_l1ArbitrumTimelock == address(0)) {
            revert ZeroAddress();
        }

        for (uint256 i = 0; i < _upgradeExecutors.length; i++) {
            ChainAndUpExecLocation memory chainAndUpExecLocation = _upgradeExecutors[i];
            if (chainAndUpExecLocation.location.upgradeExecutor == address(0)) {
                revert ZeroAddress();
            }
            if (upExecLocationExists(chainAndUpExecLocation.chainId)) {
                revert UpgradeExecAlreadyExists(chainAndUpExecLocation.chainId);
            }
            upExecLocations[chainAndUpExecLocation.chainId] = chainAndUpExecLocation.location;
        }

        l1TimelockAddr = _l1ArbitrumTimelock;
        l1TimelockMinDelay = _l1TimelockMinDelay;
    }

    /// @notice Check if an upgrade executor exists for the supplied chain id
    /// @param _chainId ChainId for target UpExecLocation
    function upExecLocationExists(uint256 _chainId) public view returns (bool) {
        return upExecLocations[_chainId].upgradeExecutor != address(0);
    }

    /// @notice Creates the to address and calldata to be called to execute a route to a batch of action contracts.
    ///         See Governance Action Contracts for more details.
    /// @param chainIds         Chain ids containing the actions to be called
    /// @param actionAddresses  Addresses of the action contracts to be called
    /// @param actionValues     Values to call the action contracts with
    /// @param actionDatas      Call data to call the action contracts with
    /// @param predecessor      A predecessor value for the l1 timelock operation
    /// @param timelockSalt     A salt for the l1 timelock operation
    function createActionRouteData(
        uint256[] memory chainIds,
        address[] memory actionAddresses,
        uint256[] memory actionValues,
        bytes[] memory actionDatas,
        bytes32 predecessor,
        bytes32 timelockSalt
    ) public view returns (address, bytes memory) {
        if (chainIds.length != actionAddresses.length) {
            revert ParamLengthMismatch(chainIds.length, actionAddresses.length);
        }
        if (chainIds.length != actionValues.length) {
            revert ParamLengthMismatch(chainIds.length, actionValues.length);
        }
        if (chainIds.length != actionDatas.length) {
            revert ParamLengthMismatch(chainIds.length, actionDatas.length);
        }

        address[] memory schedTargets = new address[](chainIds.length);
        uint256[] memory schedValues = new uint256[](chainIds.length);
        bytes[] memory schedData = new bytes[](chainIds.length);

        // for each chain create calldata that targets the upgrade executor
        // from the l1 timelock
        for (uint256 i = 0; i < chainIds.length; i++) {
            UpExecLocation memory upExecLocation = upExecLocations[chainIds[i]];
            if (upExecLocation.upgradeExecutor == address(0)) {
                revert UpgadeExecDoesntExist(chainIds[i]);
            }
            if (actionDatas[i].length == 0) {
                revert EmptyActionBytesData(actionDatas);
            }

            bytes memory executorData = abi.encodeWithSelector(
                UpgradeExecutor.execute.selector, actionAddresses[i], actionDatas[i]
            );

            // for L1, inbox is set to address(0):
            if (upExecLocation.inbox == address(0)) {
                schedTargets[i] = upExecLocation.upgradeExecutor;
                schedValues[i] = actionValues[i];
                schedData[i] = executorData;
            } else {
                // For L2 actions, magic is top level target, and value and calldata are encoded in payload
                schedTargets[i] = RETRYABLE_TICKET_MAGIC;
                schedValues[i] = 0;
                schedData[i] = abi.encode(
                    upExecLocation.inbox,
                    upExecLocation.upgradeExecutor,
                    actionValues[i],
                    0,
                    0,
                    executorData
                );
            }
        }

        // batch those calls to execute from the l1 timelock
        bytes memory timelockCallData = abi.encodeWithSelector(
            L1ArbitrumTimelock.scheduleBatch.selector,
            schedTargets,
            schedValues,
            schedData,
            predecessor,
            timelockSalt,
            l1TimelockMinDelay
        );

        // create a message to initiate a withdrawal to the L1 timelock
        return (
            address(100),
            abi.encodeWithSelector(ArbSys.sendTxToL1.selector, l1TimelockAddr, timelockCallData)
        );
    }

    /// @notice Creates the to address and calldata to be called to execute a route to a batch of action contracts.
    ///         Uses common defaults for value, calldata and predecessor.
    ///         See Governance Action Contracts for more details.
    /// @param chainIds         Chain ids containing the actions to be called
    /// @param actionAddresses  Addresses of the action contracts to be called
    /// @param timelockSalt     A salt for the l1 timelock operation
    function createActionRouteDataWithDefaults(
        uint256[] memory chainIds,
        address[] memory actionAddresses,
        bytes32 timelockSalt
    ) public view returns (address, bytes memory) {
        uint256[] memory values = new uint256[](chainIds.length);
        bytes[] memory actionDatas = new bytes[](chainIds.length);
        for (uint256 i = 0; i < chainIds.length; i++) {
            actionDatas[i] = DEFAULT_GOV_ACTION_CALLDATA;
            values[i] = DEFAULT_VALUE;
        }
        return createActionRouteData(
            chainIds, actionAddresses, values, actionDatas, DEFAULT_PREDECESSOR, timelockSalt
        );
    }
}

File 9 of 34 : Initializable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.2;

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

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

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

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

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

    /**
     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
     * used to initialize parent contracts.
     *
     * `initializer` is equivalent to `reinitializer(1)`, so 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.
     *
     * 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.
     */
    modifier reinitializer(uint8 version) {
        require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
        _initialized = version;
        _initializing = true;
        _;
        _initializing = false;
        emit Initialized(version);
    }

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

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @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.0) (access/AccessControl.sol)

pragma solidity ^0.8.0;

import "./IAccessControlUpgradeable.sol";
import "../utils/ContextUpgradeable.sol";
import "../utils/StringsUpgradeable.sol";
import "../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:
 *
 * ```
 * 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}:
 *
 * ```
 * 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.
 */
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 a standardized message including the required role.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     *
     * _Available since v4.1._
     */
    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 override returns (bool) {
        return _roles[role].members[account];
    }

    /**
     * @dev Revert with a standard message if `_msgSender()` is missing `role`.
     * Overriding this function changes the behavior of the {onlyRole} modifier.
     *
     * Format of the revert message is described in {_checkRole}.
     *
     * _Available since v4.6._
     */
    function _checkRole(bytes32 role) internal view virtual {
        _checkRole(role, _msgSender());
    }

    /**
     * @dev Revert with a standard message if `account` is missing `role`.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     */
    function _checkRole(bytes32 role, address account) internal view virtual {
        if (!hasRole(role, account)) {
            revert(
                string(
                    abi.encodePacked(
                        "AccessControl: account ",
                        StringsUpgradeable.toHexString(uint160(account), 20),
                        " is missing role ",
                        StringsUpgradeable.toHexString(uint256(role), 32)
                    )
                )
            );
        }
    }

    /**
     * @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 override 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 override 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 override 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 `account`.
     *
     * May emit a {RoleRevoked} event.
     */
    function renounceRole(bytes32 role, address account) public virtual override {
        require(account == _msgSender(), "AccessControl: can only renounce roles for self");

        _revokeRole(role, account);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event. Note that unlike {grantRole}, this function doesn't perform any
     * checks on the calling account.
     *
     * May emit a {RoleGranted} event.
     *
     * [WARNING]
     * ====
     * This function should only be called from the constructor when setting
     * up the initial roles for the system.
     *
     * Using this function in any other way is effectively circumventing the admin
     * system imposed by {AccessControl}.
     * ====
     *
     * NOTE: This function is deprecated in favor of {_grantRole}.
     */
    function _setupRole(bytes32 role, address account) internal virtual {
        _grantRole(role, account);
    }

    /**
     * @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 Grants `role` to `account`.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleGranted} event.
     */
    function _grantRole(bytes32 role, address account) internal virtual {
        if (!hasRole(role, account)) {
            _roles[role].members[account] = true;
            emit RoleGranted(role, account, _msgSender());
        }
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleRevoked} event.
     */
    function _revokeRole(bytes32 role, address account) internal virtual {
        if (hasRole(role, account)) {
            _roles[role].members[account] = false;
            emit RoleRevoked(role, account, _msgSender());
        }
    }

    /**
     * @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;
}

File 12 of 34 : Common.sol
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.16;

/// @notice Security council members are members of one of two cohorts.
///         Periodically all the positions on a cohort are put up for election,
///         and the are members replaced with new ones.
enum Cohort {
    FIRST,
    SECOND
}

/// @notice Date struct for convenience
struct Date {
    uint256 year;
    uint256 month;
    uint256 day;
    uint256 hour;
}

error ZeroAddress();
error NotAContract(address account);

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (governance/TimelockController.sol)

pragma solidity ^0.8.0;

import "../access/AccessControlUpgradeable.sol";
import "../token/ERC721/IERC721ReceiverUpgradeable.sol";
import "../token/ERC1155/IERC1155ReceiverUpgradeable.sol";
import "../utils/AddressUpgradeable.sol";
import "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module which acts as a timelocked controller. When set as the
 * owner of an `Ownable` smart contract, it enforces a timelock on all
 * `onlyOwner` maintenance operations. This gives time for users of the
 * controlled contract to exit before a potentially dangerous maintenance
 * operation is applied.
 *
 * By default, this contract is self administered, meaning administration tasks
 * have to go through the timelock process. The proposer (resp executor) role
 * is in charge of proposing (resp executing) operations. A common use case is
 * to position this {TimelockController} as the owner of a smart contract, with
 * a multisig or a DAO as the sole proposer.
 *
 * _Available since v3.3._
 */
contract TimelockControllerUpgradeable is Initializable, AccessControlUpgradeable, IERC721ReceiverUpgradeable, IERC1155ReceiverUpgradeable {
    bytes32 public constant TIMELOCK_ADMIN_ROLE = keccak256("TIMELOCK_ADMIN_ROLE");
    bytes32 public constant PROPOSER_ROLE = keccak256("PROPOSER_ROLE");
    bytes32 public constant EXECUTOR_ROLE = keccak256("EXECUTOR_ROLE");
    bytes32 public constant CANCELLER_ROLE = keccak256("CANCELLER_ROLE");
    uint256 internal constant _DONE_TIMESTAMP = uint256(1);

    mapping(bytes32 => uint256) private _timestamps;
    uint256 private _minDelay;

    /**
     * @dev Emitted when a call is scheduled as part of operation `id`.
     */
    event CallScheduled(
        bytes32 indexed id,
        uint256 indexed index,
        address target,
        uint256 value,
        bytes data,
        bytes32 predecessor,
        uint256 delay
    );

    /**
     * @dev Emitted when a call is performed as part of operation `id`.
     */
    event CallExecuted(bytes32 indexed id, uint256 indexed index, address target, uint256 value, bytes data);

    /**
     * @dev Emitted when operation `id` is cancelled.
     */
    event Cancelled(bytes32 indexed id);

    /**
     * @dev Emitted when the minimum delay for future operations is modified.
     */
    event MinDelayChange(uint256 oldDuration, uint256 newDuration);

    /**
     * @dev Initializes the contract with a given `minDelay`, and a list of
     * initial proposers and executors. The proposers receive both the
     * proposer and the canceller role (for backward compatibility). The
     * executors receive the executor role.
     *
     * NOTE: At construction, both the deployer and the timelock itself are
     * administrators. This helps further configuration of the timelock by the
     * deployer. After configuration is done, it is recommended that the
     * deployer renounces its admin position and relies on timelocked
     * operations to perform future maintenance.
     */
    function __TimelockController_init(
        uint256 minDelay,
        address[] memory proposers,
        address[] memory executors
    ) internal onlyInitializing {
        __TimelockController_init_unchained(minDelay, proposers, executors);
    }

    function __TimelockController_init_unchained(
        uint256 minDelay,
        address[] memory proposers,
        address[] memory executors
    ) internal onlyInitializing {
        _setRoleAdmin(TIMELOCK_ADMIN_ROLE, TIMELOCK_ADMIN_ROLE);
        _setRoleAdmin(PROPOSER_ROLE, TIMELOCK_ADMIN_ROLE);
        _setRoleAdmin(EXECUTOR_ROLE, TIMELOCK_ADMIN_ROLE);
        _setRoleAdmin(CANCELLER_ROLE, TIMELOCK_ADMIN_ROLE);

        // deployer + self administration
        _setupRole(TIMELOCK_ADMIN_ROLE, _msgSender());
        _setupRole(TIMELOCK_ADMIN_ROLE, address(this));

        // register proposers and cancellers
        for (uint256 i = 0; i < proposers.length; ++i) {
            _setupRole(PROPOSER_ROLE, proposers[i]);
            _setupRole(CANCELLER_ROLE, proposers[i]);
        }

        // register executors
        for (uint256 i = 0; i < executors.length; ++i) {
            _setupRole(EXECUTOR_ROLE, executors[i]);
        }

        _minDelay = minDelay;
        emit MinDelayChange(0, minDelay);
    }

    /**
     * @dev Modifier to make a function callable only by a certain role. In
     * addition to checking the sender's role, `address(0)` 's role is also
     * considered. Granting a role to `address(0)` is equivalent to enabling
     * this role for everyone.
     */
    modifier onlyRoleOrOpenRole(bytes32 role) {
        if (!hasRole(role, address(0))) {
            _checkRole(role, _msgSender());
        }
        _;
    }

    /**
     * @dev Contract might receive/hold ETH as part of the maintenance process.
     */
    receive() external payable {}

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165Upgradeable, AccessControlUpgradeable) returns (bool) {
        return interfaceId == type(IERC1155ReceiverUpgradeable).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev Returns whether an id correspond to a registered operation. This
     * includes both Pending, Ready and Done operations.
     */
    function isOperation(bytes32 id) public view virtual returns (bool registered) {
        return getTimestamp(id) > 0;
    }

    /**
     * @dev Returns whether an operation is pending or not.
     */
    function isOperationPending(bytes32 id) public view virtual returns (bool pending) {
        return getTimestamp(id) > _DONE_TIMESTAMP;
    }

    /**
     * @dev Returns whether an operation is ready or not.
     */
    function isOperationReady(bytes32 id) public view virtual returns (bool ready) {
        uint256 timestamp = getTimestamp(id);
        return timestamp > _DONE_TIMESTAMP && timestamp <= block.timestamp;
    }

    /**
     * @dev Returns whether an operation is done or not.
     */
    function isOperationDone(bytes32 id) public view virtual returns (bool done) {
        return getTimestamp(id) == _DONE_TIMESTAMP;
    }

    /**
     * @dev Returns the timestamp at with an operation becomes ready (0 for
     * unset operations, 1 for done operations).
     */
    function getTimestamp(bytes32 id) public view virtual returns (uint256 timestamp) {
        return _timestamps[id];
    }

    /**
     * @dev Returns the minimum delay for an operation to become valid.
     *
     * This value can be changed by executing an operation that calls `updateDelay`.
     */
    function getMinDelay() public view virtual returns (uint256 duration) {
        return _minDelay;
    }

    /**
     * @dev Returns the identifier of an operation containing a single
     * transaction.
     */
    function hashOperation(
        address target,
        uint256 value,
        bytes calldata data,
        bytes32 predecessor,
        bytes32 salt
    ) public pure virtual returns (bytes32 hash) {
        return keccak256(abi.encode(target, value, data, predecessor, salt));
    }

    /**
     * @dev Returns the identifier of an operation containing a batch of
     * transactions.
     */
    function hashOperationBatch(
        address[] calldata targets,
        uint256[] calldata values,
        bytes[] calldata payloads,
        bytes32 predecessor,
        bytes32 salt
    ) public pure virtual returns (bytes32 hash) {
        return keccak256(abi.encode(targets, values, payloads, predecessor, salt));
    }

    /**
     * @dev Schedule an operation containing a single transaction.
     *
     * Emits a {CallScheduled} event.
     *
     * Requirements:
     *
     * - the caller must have the 'proposer' role.
     */
    function schedule(
        address target,
        uint256 value,
        bytes calldata data,
        bytes32 predecessor,
        bytes32 salt,
        uint256 delay
    ) public virtual onlyRole(PROPOSER_ROLE) {
        bytes32 id = hashOperation(target, value, data, predecessor, salt);
        _schedule(id, delay);
        emit CallScheduled(id, 0, target, value, data, predecessor, delay);
    }

    /**
     * @dev Schedule an operation containing a batch of transactions.
     *
     * Emits one {CallScheduled} event per transaction in the batch.
     *
     * Requirements:
     *
     * - the caller must have the 'proposer' role.
     */
    function scheduleBatch(
        address[] calldata targets,
        uint256[] calldata values,
        bytes[] calldata payloads,
        bytes32 predecessor,
        bytes32 salt,
        uint256 delay
    ) public virtual onlyRole(PROPOSER_ROLE) {
        require(targets.length == values.length, "TimelockController: length mismatch");
        require(targets.length == payloads.length, "TimelockController: length mismatch");

        bytes32 id = hashOperationBatch(targets, values, payloads, predecessor, salt);
        _schedule(id, delay);
        for (uint256 i = 0; i < targets.length; ++i) {
            emit CallScheduled(id, i, targets[i], values[i], payloads[i], predecessor, delay);
        }
    }

    /**
     * @dev Schedule an operation that is to becomes valid after a given delay.
     */
    function _schedule(bytes32 id, uint256 delay) private {
        require(!isOperation(id), "TimelockController: operation already scheduled");
        require(delay >= getMinDelay(), "TimelockController: insufficient delay");
        _timestamps[id] = block.timestamp + delay;
    }

    /**
     * @dev Cancel an operation.
     *
     * Requirements:
     *
     * - the caller must have the 'canceller' role.
     */
    function cancel(bytes32 id) public virtual onlyRole(CANCELLER_ROLE) {
        require(isOperationPending(id), "TimelockController: operation cannot be cancelled");
        delete _timestamps[id];

        emit Cancelled(id);
    }

    /**
     * @dev Execute an (ready) operation containing a single transaction.
     *
     * Emits a {CallExecuted} event.
     *
     * Requirements:
     *
     * - the caller must have the 'executor' role.
     */
    // This function can reenter, but it doesn't pose a risk because _afterCall checks that the proposal is pending,
    // thus any modifications to the operation during reentrancy should be caught.
    // slither-disable-next-line reentrancy-eth
    function execute(
        address target,
        uint256 value,
        bytes calldata payload,
        bytes32 predecessor,
        bytes32 salt
    ) public payable virtual onlyRoleOrOpenRole(EXECUTOR_ROLE) {
        bytes32 id = hashOperation(target, value, payload, predecessor, salt);

        _beforeCall(id, predecessor);
        _execute(target, value, payload);
        emit CallExecuted(id, 0, target, value, payload);
        _afterCall(id);
    }

    /**
     * @dev Execute an (ready) operation containing a batch of transactions.
     *
     * Emits one {CallExecuted} event per transaction in the batch.
     *
     * Requirements:
     *
     * - the caller must have the 'executor' role.
     */
    function executeBatch(
        address[] calldata targets,
        uint256[] calldata values,
        bytes[] calldata payloads,
        bytes32 predecessor,
        bytes32 salt
    ) public payable virtual onlyRoleOrOpenRole(EXECUTOR_ROLE) {
        require(targets.length == values.length, "TimelockController: length mismatch");
        require(targets.length == payloads.length, "TimelockController: length mismatch");

        bytes32 id = hashOperationBatch(targets, values, payloads, predecessor, salt);

        _beforeCall(id, predecessor);
        for (uint256 i = 0; i < targets.length; ++i) {
            address target = targets[i];
            uint256 value = values[i];
            bytes calldata payload = payloads[i];
            _execute(target, value, payload);
            emit CallExecuted(id, i, target, value, payload);
        }
        _afterCall(id);
    }

    /**
     * @dev Execute an operation's call.
     */
    function _execute(
        address target,
        uint256 value,
        bytes calldata data
    ) internal virtual {
        (bool success, ) = target.call{value: value}(data);
        require(success, "TimelockController: underlying transaction reverted");
    }

    /**
     * @dev Checks before execution of an operation's calls.
     */
    function _beforeCall(bytes32 id, bytes32 predecessor) private view {
        require(isOperationReady(id), "TimelockController: operation is not ready");
        require(predecessor == bytes32(0) || isOperationDone(predecessor), "TimelockController: missing dependency");
    }

    /**
     * @dev Checks after execution of an operation's calls.
     */
    function _afterCall(bytes32 id) private {
        require(isOperationReady(id), "TimelockController: operation is not ready");
        _timestamps[id] = _DONE_TIMESTAMP;
    }

    /**
     * @dev Changes the minimum timelock duration for future operations.
     *
     * Emits a {MinDelayChange} event.
     *
     * Requirements:
     *
     * - the caller must be the timelock itself. This can only be achieved by scheduling and later executing
     * an operation where the timelock is the target and the data is the ABI-encoded call to this function.
     */
    function updateDelay(uint256 newDelay) external virtual {
        require(msg.sender == address(this), "TimelockController: caller must be timelock");
        emit MinDelayChange(_minDelay, newDelay);
        _minDelay = newDelay;
    }

    /**
     * @dev See {IERC721Receiver-onERC721Received}.
     */
    function onERC721Received(
        address,
        address,
        uint256,
        bytes memory
    ) public virtual override returns (bytes4) {
        return this.onERC721Received.selector;
    }

    /**
     * @dev See {IERC1155Receiver-onERC1155Received}.
     */
    function onERC1155Received(
        address,
        address,
        uint256,
        uint256,
        bytes memory
    ) public virtual override returns (bytes4) {
        return this.onERC1155Received.selector;
    }

    /**
     * @dev See {IERC1155Receiver-onERC1155BatchReceived}.
     */
    function onERC1155BatchReceived(
        address,
        address,
        uint256[] memory,
        uint256[] memory,
        bytes memory
    ) public virtual override returns (bytes4) {
        return this.onERC1155BatchReceived.selector;
    }

    /**
     * @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[48] private __gap;
}

File 14 of 34 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;

        _;

        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }
}

// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1

// solhint-disable-next-line compiler-version
pragma solidity >=0.6.9 <0.9.0;

import "./IBridge.sol";
import "./IDelayedMessageProvider.sol";
import "./ISequencerInbox.sol";

interface IInbox is IDelayedMessageProvider {
    function bridge() external view returns (IBridge);

    function sequencerInbox() external view returns (ISequencerInbox);

    /**
     * @notice Send a generic L2 message to the chain
     * @dev This method is an optimization to avoid having to emit the entirety of the messageData in a log. Instead validators are expected to be able to parse the data from the transaction's input
     *      This method will be disabled upon L1 fork to prevent replay attacks on L2
     * @param messageData Data of the message being sent
     */
    function sendL2MessageFromOrigin(bytes calldata messageData) external returns (uint256);

    /**
     * @notice Send a generic L2 message to the chain
     * @dev This method can be used to send any type of message that doesn't require L1 validation
     *      This method will be disabled upon L1 fork to prevent replay attacks on L2
     * @param messageData Data of the message being sent
     */
    function sendL2Message(bytes calldata messageData) external returns (uint256);

    function sendL1FundedUnsignedTransaction(
        uint256 gasLimit,
        uint256 maxFeePerGas,
        uint256 nonce,
        address to,
        bytes calldata data
    ) external payable returns (uint256);

    function sendL1FundedContractTransaction(
        uint256 gasLimit,
        uint256 maxFeePerGas,
        address to,
        bytes calldata data
    ) external payable returns (uint256);

    function sendUnsignedTransaction(
        uint256 gasLimit,
        uint256 maxFeePerGas,
        uint256 nonce,
        address to,
        uint256 value,
        bytes calldata data
    ) external returns (uint256);

    function sendContractTransaction(
        uint256 gasLimit,
        uint256 maxFeePerGas,
        address to,
        uint256 value,
        bytes calldata data
    ) external returns (uint256);

    /**
     * @dev This method can only be called upon L1 fork and will not alias the caller
     *      This method will revert if not called from origin
     */
    function sendL1FundedUnsignedTransactionToFork(
        uint256 gasLimit,
        uint256 maxFeePerGas,
        uint256 nonce,
        address to,
        bytes calldata data
    ) external payable returns (uint256);

    /**
     * @dev This method can only be called upon L1 fork and will not alias the caller
     *      This method will revert if not called from origin
     */
    function sendUnsignedTransactionToFork(
        uint256 gasLimit,
        uint256 maxFeePerGas,
        uint256 nonce,
        address to,
        uint256 value,
        bytes calldata data
    ) external returns (uint256);

    /**
     * @notice Send a message to initiate L2 withdrawal
     * @dev This method can only be called upon L1 fork and will not alias the caller
     *      This method will revert if not called from origin
     */
    function sendWithdrawEthToFork(
        uint256 gasLimit,
        uint256 maxFeePerGas,
        uint256 nonce,
        uint256 value,
        address withdrawTo
    ) external returns (uint256);

    /**
     * @notice Get the L1 fee for submitting a retryable
     * @dev This fee can be paid by funds already in the L2 aliased address or by the current message value
     * @dev This formula may change in the future, to future proof your code query this method instead of inlining!!
     * @param dataLength The length of the retryable's calldata, in bytes
     * @param baseFee The block basefee when the retryable is included in the chain, if 0 current block.basefee will be used
     */
    function calculateRetryableSubmissionFee(uint256 dataLength, uint256 baseFee)
        external
        view
        returns (uint256);

    /**
     * @notice Deposit eth from L1 to L2 to address of the sender if sender is an EOA, and to its aliased address if the sender is a contract
     * @dev This does not trigger the fallback function when receiving in the L2 side.
     *      Look into retryable tickets if you are interested in this functionality.
     * @dev This function should not be called inside contract constructors
     */
    function depositEth() external payable returns (uint256);

    /**
     * @notice Put a message in the L2 inbox that can be reexecuted for some fixed amount of time if it reverts
     * @dev all msg.value will deposited to callValueRefundAddress on L2
     * @dev Gas limit and maxFeePerGas should not be set to 1 as that is used to trigger the RetryableData error
     * @param to destination L2 contract address
     * @param l2CallValue call value for retryable L2 message
     * @param maxSubmissionCost Max gas deducted from user's L2 balance to cover base submission fee
     * @param excessFeeRefundAddress gasLimit x maxFeePerGas - execution cost gets credited here on L2 balance
     * @param callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled
     * @param gasLimit Max gas deducted from user's L2 balance to cover L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error)
     * @param maxFeePerGas price bid for L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error)
     * @param data ABI encoded data of L2 message
     * @return unique message number of the retryable transaction
     */
    function createRetryableTicket(
        address to,
        uint256 l2CallValue,
        uint256 maxSubmissionCost,
        address excessFeeRefundAddress,
        address callValueRefundAddress,
        uint256 gasLimit,
        uint256 maxFeePerGas,
        bytes calldata data
    ) external payable returns (uint256);

    /**
     * @notice Put a message in the L2 inbox that can be reexecuted for some fixed amount of time if it reverts
     * @dev Same as createRetryableTicket, but does not guarantee that submission will succeed by requiring the needed funds
     * come from the deposit alone, rather than falling back on the user's L2 balance
     * @dev Advanced usage only (does not rewrite aliases for excessFeeRefundAddress and callValueRefundAddress).
     * createRetryableTicket method is the recommended standard.
     * @dev Gas limit and maxFeePerGas should not be set to 1 as that is used to trigger the RetryableData error
     * @param to destination L2 contract address
     * @param l2CallValue call value for retryable L2 message
     * @param maxSubmissionCost Max gas deducted from user's L2 balance to cover base submission fee
     * @param excessFeeRefundAddress gasLimit x maxFeePerGas - execution cost gets credited here on L2 balance
     * @param callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled
     * @param gasLimit Max gas deducted from user's L2 balance to cover L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error)
     * @param maxFeePerGas price bid for L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error)
     * @param data ABI encoded data of L2 message
     * @return unique message number of the retryable transaction
     */
    function unsafeCreateRetryableTicket(
        address to,
        uint256 l2CallValue,
        uint256 maxSubmissionCost,
        address excessFeeRefundAddress,
        address callValueRefundAddress,
        uint256 gasLimit,
        uint256 maxFeePerGas,
        bytes calldata data
    ) external payable returns (uint256);

    // ---------- onlyRollupOrOwner functions ----------

    /// @notice pauses all inbox functionality
    function pause() external;

    /// @notice unpauses all inbox functionality
    function unpause() external;

    // ---------- initializer ----------

    /**
     * @dev function to be called one time during the inbox upgrade process
     *      this is used to fix the storage slots
     */
    function postUpgradeInit(IBridge _bridge) external;

    function initialize(IBridge _bridge, ISequencerInbox _sequencerInbox) external;
}

// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2020, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.8.16;

import "@arbitrum/nitro-contracts/src/bridge/IInbox.sol";
import "@arbitrum/nitro-contracts/src/bridge/IOutbox.sol";

// Direct copy of https://github.com/OffchainLabs/token-bridge-contracts/blob/7f5800351175008ba676ae6ee166a6069f659c20/contracts/tokenbridge/ethereum/L1ArbitrumMessenger.sol
// Copied rather than imported because of clashing solidity versions

/// @notice L1 utility contract to assist with L1 <=> L2 interactions
/// @dev this is an abstract contract instead of library so the functions can be easily overriden when testing
abstract contract L1ArbitrumMessenger {
    event TxToL2(address indexed _from, address indexed _to, uint256 indexed _seqNum, bytes _data);

    struct L2GasParams {
        uint256 _maxSubmissionCost;
        uint256 _maxGas;
        uint256 _gasPriceBid;
    }

    function sendTxToL2CustomRefund(
        address _inbox,
        address _to,
        address _refundTo,
        address _user,
        uint256 _l1CallValue,
        uint256 _l2CallValue,
        L2GasParams memory _l2GasParams,
        bytes memory _data
    ) internal returns (uint256) {
        // alternative function entry point when struggling with the stack size
        return sendTxToL2CustomRefund(
            _inbox,
            _to,
            _refundTo,
            _user,
            _l1CallValue,
            _l2CallValue,
            _l2GasParams._maxSubmissionCost,
            _l2GasParams._maxGas,
            _l2GasParams._gasPriceBid,
            _data
        );
    }

    function sendTxToL2(
        address _inbox,
        address _to,
        address _user,
        uint256 _l1CallValue,
        uint256 _l2CallValue,
        L2GasParams memory _l2GasParams,
        bytes memory _data
    ) internal returns (uint256) {
        // alternative function entry point when struggling with the stack size
        return sendTxToL2(
            _inbox,
            _to,
            _user,
            _l1CallValue,
            _l2CallValue,
            _l2GasParams._maxSubmissionCost,
            _l2GasParams._maxGas,
            _l2GasParams._gasPriceBid,
            _data
        );
    }

    function sendTxToL2CustomRefund(
        address _inbox,
        address _to,
        address _refundTo,
        address _user,
        uint256 _l1CallValue,
        uint256 _l2CallValue,
        uint256 _maxSubmissionCost,
        uint256 _maxGas,
        uint256 _gasPriceBid,
        bytes memory _data
    ) internal returns (uint256) {
        uint256 seqNum = IInbox(_inbox).createRetryableTicket{value: _l1CallValue}(
            _to,
            _l2CallValue,
            _maxSubmissionCost,
            _refundTo, // only refund excess fee to the custom address
            _user, // user can cancel the retryable and receive call value refund
            _maxGas,
            _gasPriceBid,
            _data
        );
        emit TxToL2(_user, _to, seqNum, _data);
        return seqNum;
    }

    function sendTxToL2(
        address _inbox,
        address _to,
        address _user,
        uint256 _l1CallValue,
        uint256 _l2CallValue,
        uint256 _maxSubmissionCost,
        uint256 _maxGas,
        uint256 _gasPriceBid,
        bytes memory _data
    ) internal returns (uint256) {
        return sendTxToL2CustomRefund(
            _inbox,
            _to,
            _user,
            _user,
            _l1CallValue,
            _l2CallValue,
            _maxSubmissionCost,
            _maxGas,
            _gasPriceBid,
            _data
        );
    }

    function getBridge(address _inbox) internal view returns (IBridge) {
        return IInbox(_inbox).bridge();
    }

    /// @dev the l2ToL1Sender behaves as the tx.origin, the msg.sender should be validated to protect against reentrancies
    function getL2ToL1Sender(address _inbox) internal returns (address) {
        IOutbox outbox = IOutbox(getBridge(_inbox).activeOutbox());
        address l2ToL1Sender = outbox.l2ToL1Sender();

        require(l2ToL1Sender != address(0), "NO_SENDER");
        return l2ToL1Sender;
    }
}

// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.16;

abstract contract OpEnum {
    enum Operation {
        Call,
        DelegateCall
    }
}

interface IGnosisSafe {
    function getOwners() external view returns (address[] memory);
    function getThreshold() external view returns (uint256);
    function isOwner(address owner) external view returns (bool);
    function isModuleEnabled(address module) external view returns (bool);
    function addOwnerWithThreshold(address owner, uint256 threshold) external;
    function removeOwner(address prevOwner, address owner, uint256 threshold) external;
    function execTransactionFromModule(
        address to,
        uint256 value,
        bytes memory data,
        OpEnum.Operation operation
    ) external returns (bool success);
}

// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.16;

import "./KeyValueStore.sol";

/// @notice Stores a record that the action executed.
///         Can be useful for enforcing dependency between actions
/// @dev    This contract is designed to be inherited by action contracts, so it
///         it must not use any local storage
contract ActionExecutionRecord {
    /// @notice The key value store used to record the execution
    /// @dev    Local storage cannot be used in action contracts as they're delegate called into
    KeyValueStore public immutable store;

    /// @notice A unique id for this action contract
    bytes32 public immutable actionContractId;

    constructor(KeyValueStore _store, string memory _uniqueActionName) {
        store = _store;
        actionContractId = keccak256(bytes(_uniqueActionName));
    }

    /// @notice Sets a value in the store
    /// @dev    Combines the provided key with the action contract id
    function _set(uint256 key, uint256 value) internal {
        store.set(computeKey(key), value);
    }

    /// @notice Gets a value from the store
    /// @dev    Combines the provided key with the action contract id
    function _get(uint256 key) internal view returns (uint256) {
        return store.get(computeKey(key));
    }

    /// @notice This contract uses a composite key of the provided key and the action contract id.
    ///         This function can be used to calculate the composite key
    function computeKey(uint256 key) public view returns (uint256) {
        return uint256(keccak256(abi.encode(actionContractId, key)));
    }
}

// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1

pragma solidity >=0.4.21 <0.9.0;

/**
 * @title System level functionality
 * @notice For use by contracts to interact with core L2-specific functionality.
 * Precompiled contract that exists in every Arbitrum chain at address(100), 0x0000000000000000000000000000000000000064.
 */
interface ArbSys {
    /**
     * @notice Get Arbitrum block number (distinct from L1 block number; Arbitrum genesis block has block number 0)
     * @return block number as int
     */
    function arbBlockNumber() external view returns (uint256);

    /**
     * @notice Get Arbitrum block hash (reverts unless currentBlockNum-256 <= arbBlockNum < currentBlockNum)
     * @return block hash
     */
    function arbBlockHash(uint256 arbBlockNum) external view returns (bytes32);

    /**
     * @notice Gets the rollup's unique chain identifier
     * @return Chain identifier as int
     */
    function arbChainID() external view returns (uint256);

    /**
     * @notice Get internal version number identifying an ArbOS build
     * @return version number as int
     */
    function arbOSVersion() external view returns (uint256);

    /**
     * @notice Returns 0 since Nitro has no concept of storage gas
     * @return uint 0
     */
    function getStorageGasAvailable() external view returns (uint256);

    /**
     * @notice (deprecated) check if current call is top level (meaning it was triggered by an EoA or a L1 contract)
     * @dev this call has been deprecated and may be removed in a future release
     * @return true if current execution frame is not a call by another L2 contract
     */
    function isTopLevelCall() external view returns (bool);

    /**
     * @notice map L1 sender contract address to its L2 alias
     * @param sender sender address
     * @param unused argument no longer used
     * @return aliased sender address
     */
    function mapL1SenderContractAddressToL2Alias(address sender, address unused)
        external
        pure
        returns (address);

    /**
     * @notice check if the caller (of this caller of this) is an aliased L1 contract address
     * @return true iff the caller's address is an alias for an L1 contract address
     */
    function wasMyCallersAddressAliased() external view returns (bool);

    /**
     * @notice return the address of the caller (of this caller of this), without applying L1 contract address aliasing
     * @return address of the caller's caller, without applying L1 contract address aliasing
     */
    function myCallersAddressWithoutAliasing() external view returns (address);

    /**
     * @notice Send given amount of Eth to dest from sender.
     * This is a convenience function, which is equivalent to calling sendTxToL1 with empty data.
     * @param destination recipient address on L1
     * @return unique identifier for this L2-to-L1 transaction.
     */
    function withdrawEth(address destination) external payable returns (uint256);

    /**
     * @notice Send a transaction to L1
     * @dev it is not possible to execute on the L1 any L2-to-L1 transaction which contains data
     * to a contract address without any code (as enforced by the Bridge contract).
     * @param destination recipient address on L1
     * @param data (optional) calldata for L1 contract call
     * @return a unique identifier for this L2-to-L1 transaction.
     */
    function sendTxToL1(address destination, bytes calldata data)
        external
        payable
        returns (uint256);

    /**
     * @notice Get send Merkle tree state
     * @return size number of sends in the history
     * @return root root hash of the send history
     * @return partials hashes of partial subtrees in the send history tree
     */
    function sendMerkleTreeState()
        external
        view
        returns (
            uint256 size,
            bytes32 root,
            bytes32[] memory partials
        );

    /**
     * @notice creates a send txn from L2 to L1
     * @param position = (level << 192) + leaf = (0 << 192) + leaf = leaf
     */
    event L2ToL1Tx(
        address caller,
        address indexed destination,
        uint256 indexed hash,
        uint256 indexed position,
        uint256 arbBlockNum,
        uint256 ethBlockNum,
        uint256 timestamp,
        uint256 callvalue,
        bytes data
    );

    /// @dev DEPRECATED in favour of the new L2ToL1Tx event above after the nitro upgrade
    event L2ToL1Transaction(
        address caller,
        address indexed destination,
        uint256 indexed uniqueId,
        uint256 indexed batchNumber,
        uint256 indexInBatch,
        uint256 arbBlockNum,
        uint256 ethBlockNum,
        uint256 timestamp,
        uint256 callvalue,
        bytes data
    );

    /**
     * @notice logs a merkle branch for proof synthesis
     * @param reserved an index meant only to align the 4th index with L2ToL1Transaction's 4th event
     * @param hash the merkle hash
     * @param position = (level << 192) + leaf
     */
    event SendMerkleUpdate(
        uint256 indexed reserved,
        bytes32 indexed hash,
        uint256 indexed position
    );
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library AddressUpgradeable {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [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 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 v4.4.1 (access/IAccessControl.sol)

pragma solidity ^0.8.0;

/**
 * @dev External interface of AccessControl declared to support ERC165 detection.
 */
interface IAccessControlUpgradeable {
    /**
     * @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.
     *
     * _Available since v3.1._
     */
    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 `account`.
     */
    function renounceRole(bytes32 role, address account) external;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

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

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

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

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

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)

pragma solidity ^0.8.0;

/**
 * @dev String operations.
 */
library StringsUpgradeable {
    bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
    uint8 private constant _ADDRESS_LENGTH = 20;

    /**
     * @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);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)

pragma solidity ^0.8.0;

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

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable {
    function __ERC165_init() internal onlyInitializing {
    }

    function __ERC165_init_unchained() internal onlyInitializing {
    }
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165Upgradeable).interfaceId;
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}

File 25 of 34 : IERC721ReceiverUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)

pragma solidity ^0.8.0;

/**
 * @title ERC721 token receiver interface
 * @dev Interface for any contract that wants to support safeTransfers
 * from ERC721 asset contracts.
 */
interface IERC721ReceiverUpgradeable {
    /**
     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
     * by `operator` from `from`, this function is called.
     *
     * It must return its Solidity selector to confirm the token transfer.
     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
     *
     * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
     */
    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) external returns (bytes4);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165Upgradeable.sol";

/**
 * @dev _Available since v3.1._
 */
interface IERC1155ReceiverUpgradeable is IERC165Upgradeable {
    /**
     * @dev Handles the receipt of a single ERC1155 token type. This function is
     * called at the end of a `safeTransferFrom` after the balance has been updated.
     *
     * NOTE: To accept the transfer, this must return
     * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
     * (i.e. 0xf23a6e61, or its own function selector).
     *
     * @param operator The address which initiated the transfer (i.e. msg.sender)
     * @param from The address which previously owned the token
     * @param id The ID of the token being transferred
     * @param value The amount of tokens being transferred
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
     */
    function onERC1155Received(
        address operator,
        address from,
        uint256 id,
        uint256 value,
        bytes calldata data
    ) external returns (bytes4);

    /**
     * @dev Handles the receipt of a multiple ERC1155 token types. This function
     * is called at the end of a `safeBatchTransferFrom` after the balances have
     * been updated.
     *
     * NOTE: To accept the transfer(s), this must return
     * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
     * (i.e. 0xbc197c81, or its own function selector).
     *
     * @param operator The address which initiated the batch transfer (i.e. msg.sender)
     * @param from The address which previously owned the token
     * @param ids An array containing ids of each token being transferred (order and length must match values array)
     * @param values An array containing amounts of each token being transferred (order and length must match ids array)
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
     */
    function onERC1155BatchReceived(
        address operator,
        address from,
        uint256[] calldata ids,
        uint256[] calldata values,
        bytes calldata data
    ) external returns (bytes4);
}

// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1

// solhint-disable-next-line compiler-version
pragma solidity >=0.6.9 <0.9.0;

import "./IOwnable.sol";

interface IBridge {
    event MessageDelivered(
        uint256 indexed messageIndex,
        bytes32 indexed beforeInboxAcc,
        address inbox,
        uint8 kind,
        address sender,
        bytes32 messageDataHash,
        uint256 baseFeeL1,
        uint64 timestamp
    );

    event BridgeCallTriggered(
        address indexed outbox,
        address indexed to,
        uint256 value,
        bytes data
    );

    event InboxToggle(address indexed inbox, bool enabled);

    event OutboxToggle(address indexed outbox, bool enabled);

    event SequencerInboxUpdated(address newSequencerInbox);

    function allowedDelayedInboxList(uint256) external returns (address);

    function allowedOutboxList(uint256) external returns (address);

    /// @dev Accumulator for delayed inbox messages; tail represents hash of the current state; each element represents the inclusion of a new message.
    function delayedInboxAccs(uint256) external view returns (bytes32);

    /// @dev Accumulator for sequencer inbox messages; tail represents hash of the current state; each element represents the inclusion of a new message.
    function sequencerInboxAccs(uint256) external view returns (bytes32);

    function rollup() external view returns (IOwnable);

    function sequencerInbox() external view returns (address);

    function activeOutbox() external view returns (address);

    function allowedDelayedInboxes(address inbox) external view returns (bool);

    function allowedOutboxes(address outbox) external view returns (bool);

    function sequencerReportedSubMessageCount() external view returns (uint256);

    /**
     * @dev Enqueue a message in the delayed inbox accumulator.
     *      These messages are later sequenced in the SequencerInbox, either
     *      by the sequencer as part of a normal batch, or by force inclusion.
     */
    function enqueueDelayedMessage(
        uint8 kind,
        address sender,
        bytes32 messageDataHash
    ) external payable returns (uint256);

    function executeCall(
        address to,
        uint256 value,
        bytes calldata data
    ) external returns (bool success, bytes memory returnData);

    function delayedMessageCount() external view returns (uint256);

    function sequencerMessageCount() external view returns (uint256);

    // ---------- onlySequencerInbox functions ----------

    function enqueueSequencerMessage(
        bytes32 dataHash,
        uint256 afterDelayedMessagesRead,
        uint256 prevMessageCount,
        uint256 newMessageCount
    )
        external
        returns (
            uint256 seqMessageIndex,
            bytes32 beforeAcc,
            bytes32 delayedAcc,
            bytes32 acc
        );

    /**
     * @dev Allows the sequencer inbox to submit a delayed message of the batchPostingReport type
     *      This is done through a separate function entrypoint instead of allowing the sequencer inbox
     *      to call `enqueueDelayedMessage` to avoid the gas overhead of an extra SLOAD in either
     *      every delayed inbox or every sequencer inbox call.
     */
    function submitBatchSpendingReport(address batchPoster, bytes32 dataHash)
        external
        returns (uint256 msgNum);

    // ---------- onlyRollupOrOwner functions ----------

    function setSequencerInbox(address _sequencerInbox) external;

    function setDelayedInbox(address inbox, bool enabled) external;

    function setOutbox(address inbox, bool enabled) external;

    // ---------- initializer ----------

    function initialize(IOwnable rollup_) external;
}

File 28 of 34 : IDelayedMessageProvider.sol
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1

// solhint-disable-next-line compiler-version
pragma solidity >=0.6.9 <0.9.0;

interface IDelayedMessageProvider {
    /// @dev event emitted when a inbox message is added to the Bridge's delayed accumulator
    event InboxMessageDelivered(uint256 indexed messageNum, bytes data);

    /// @dev event emitted when a inbox message is added to the Bridge's delayed accumulator
    /// same as InboxMessageDelivered but the batch data is available in tx.input
    event InboxMessageDeliveredFromOrigin(uint256 indexed messageNum);
}

// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1

// solhint-disable-next-line compiler-version
pragma solidity >=0.6.9 <0.9.0;
pragma experimental ABIEncoderV2;

import "../libraries/IGasRefunder.sol";
import "./IDelayedMessageProvider.sol";
import "./IBridge.sol";

interface ISequencerInbox is IDelayedMessageProvider {
    struct MaxTimeVariation {
        uint256 delayBlocks;
        uint256 futureBlocks;
        uint256 delaySeconds;
        uint256 futureSeconds;
    }

    struct TimeBounds {
        uint64 minTimestamp;
        uint64 maxTimestamp;
        uint64 minBlockNumber;
        uint64 maxBlockNumber;
    }

    enum BatchDataLocation {
        TxInput,
        SeparateBatchEvent,
        NoData
    }

    event SequencerBatchDelivered(
        uint256 indexed batchSequenceNumber,
        bytes32 indexed beforeAcc,
        bytes32 indexed afterAcc,
        bytes32 delayedAcc,
        uint256 afterDelayedMessagesRead,
        TimeBounds timeBounds,
        BatchDataLocation dataLocation
    );

    event OwnerFunctionCalled(uint256 indexed id);

    /// @dev a separate event that emits batch data when this isn't easily accessible in the tx.input
    event SequencerBatchData(uint256 indexed batchSequenceNumber, bytes data);

    /// @dev a valid keyset was added
    event SetValidKeyset(bytes32 indexed keysetHash, bytes keysetBytes);

    /// @dev a keyset was invalidated
    event InvalidateKeyset(bytes32 indexed keysetHash);

    function totalDelayedMessagesRead() external view returns (uint256);

    function bridge() external view returns (IBridge);

    /// @dev The size of the batch header
    // solhint-disable-next-line func-name-mixedcase
    function HEADER_LENGTH() external view returns (uint256);

    /// @dev If the first batch data byte after the header has this bit set,
    ///      the sequencer inbox has authenticated the data. Currently not used.
    // solhint-disable-next-line func-name-mixedcase
    function DATA_AUTHENTICATED_FLAG() external view returns (bytes1);

    function rollup() external view returns (IOwnable);

    function isBatchPoster(address) external view returns (bool);

    struct DasKeySetInfo {
        bool isValidKeyset;
        uint64 creationBlock;
    }

    // https://github.com/ethereum/solidity/issues/11826
    // function maxTimeVariation() external view returns (MaxTimeVariation calldata);
    // function dasKeySetInfo(bytes32) external view returns (DasKeySetInfo calldata);

    /// @notice Remove force inclusion delay after a L1 chainId fork
    function removeDelayAfterFork() external;

    /// @notice Force messages from the delayed inbox to be included in the chain
    ///         Callable by any address, but message can only be force-included after maxTimeVariation.delayBlocks and
    ///         maxTimeVariation.delaySeconds has elapsed. As part of normal behaviour the sequencer will include these
    ///         messages so it's only necessary to call this if the sequencer is down, or not including any delayed messages.
    /// @param _totalDelayedMessagesRead The total number of messages to read up to
    /// @param kind The kind of the last message to be included
    /// @param l1BlockAndTime The l1 block and the l1 timestamp of the last message to be included
    /// @param baseFeeL1 The l1 gas price of the last message to be included
    /// @param sender The sender of the last message to be included
    /// @param messageDataHash The messageDataHash of the last message to be included
    function forceInclusion(
        uint256 _totalDelayedMessagesRead,
        uint8 kind,
        uint64[2] calldata l1BlockAndTime,
        uint256 baseFeeL1,
        address sender,
        bytes32 messageDataHash
    ) external;

    function inboxAccs(uint256 index) external view returns (bytes32);

    function batchCount() external view returns (uint256);

    function isValidKeysetHash(bytes32 ksHash) external view returns (bool);

    /// @notice the creation block is intended to still be available after a keyset is deleted
    function getKeysetCreationBlock(bytes32 ksHash) external view returns (uint256);

    // ---------- BatchPoster functions ----------

    function addSequencerL2BatchFromOrigin(
        uint256 sequenceNumber,
        bytes calldata data,
        uint256 afterDelayedMessagesRead,
        IGasRefunder gasRefunder
    ) external;

    function addSequencerL2Batch(
        uint256 sequenceNumber,
        bytes calldata data,
        uint256 afterDelayedMessagesRead,
        IGasRefunder gasRefunder,
        uint256 prevMessageCount,
        uint256 newMessageCount
    ) external;

    // ---------- onlyRollupOrOwner functions ----------

    /**
     * @notice Set max delay for sequencer inbox
     * @param maxTimeVariation_ the maximum time variation parameters
     */
    function setMaxTimeVariation(MaxTimeVariation memory maxTimeVariation_) external;

    /**
     * @notice Updates whether an address is authorized to be a batch poster at the sequencer inbox
     * @param addr the address
     * @param isBatchPoster_ if the specified address should be authorized as a batch poster
     */
    function setIsBatchPoster(address addr, bool isBatchPoster_) external;

    /**
     * @notice Makes Data Availability Service keyset valid
     * @param keysetBytes bytes of the serialized keyset
     */
    function setValidKeyset(bytes calldata keysetBytes) external;

    /**
     * @notice Invalidates a Data Availability Service keyset
     * @param ksHash hash of the keyset
     */
    function invalidateKeysetHash(bytes32 ksHash) external;

    // ---------- initializer ----------

    function initialize(IBridge bridge_, MaxTimeVariation calldata maxTimeVariation_) external;
}

// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1

// solhint-disable-next-line compiler-version
pragma solidity >=0.6.9 <0.9.0;

import "./IBridge.sol";

interface IOutbox {
    event SendRootUpdated(bytes32 indexed outputRoot, bytes32 indexed l2BlockHash);
    event OutBoxTransactionExecuted(
        address indexed to,
        address indexed l2Sender,
        uint256 indexed zero,
        uint256 transactionIndex
    );

    function rollup() external view returns (address); // the rollup contract

    function bridge() external view returns (IBridge); // the bridge contract

    function spent(uint256) external view returns (bytes32); // packed spent bitmap

    function roots(bytes32) external view returns (bytes32); // maps root hashes => L2 block hash

    // solhint-disable-next-line func-name-mixedcase
    function OUTBOX_VERSION() external view returns (uint128); // the outbox version

    function updateSendRoot(bytes32 sendRoot, bytes32 l2BlockHash) external;

    /// @notice When l2ToL1Sender returns a nonzero address, the message was originated by an L2 account
    ///         When the return value is zero, that means this is a system message
    /// @dev the l2ToL1Sender behaves as the tx.origin, the msg.sender should be validated to protect against reentrancies
    function l2ToL1Sender() external view returns (address);

    /// @return l2Block return L2 block when the L2 tx was initiated or 0 if no L2 to L1 transaction is active
    function l2ToL1Block() external view returns (uint256);

    /// @return l1Block return L1 block when the L2 tx was initiated or 0 if no L2 to L1 transaction is active
    function l2ToL1EthBlock() external view returns (uint256);

    /// @return timestamp return L2 timestamp when the L2 tx was initiated or 0 if no L2 to L1 transaction is active
    function l2ToL1Timestamp() external view returns (uint256);

    /// @return outputId returns the unique output identifier of the L2 to L1 tx or 0 if no L2 to L1 transaction is active
    function l2ToL1OutputId() external view returns (bytes32);

    /**
     * @notice Executes a messages in an Outbox entry.
     * @dev Reverts if dispute period hasn't expired, since the outbox entry
     *      is only created once the rollup confirms the respective assertion.
     * @dev it is not possible to execute any L2-to-L1 transaction which contains data
     *      to a contract address without any code (as enforced by the Bridge contract).
     * @param proof Merkle proof of message inclusion in send root
     * @param index Merkle path to message
     * @param l2Sender sender if original message (i.e., caller of ArbSys.sendTxToL1)
     * @param to destination address for L1 contract call
     * @param l2Block l2 block number at which sendTxToL1 call was made
     * @param l1Block l1 block number at which sendTxToL1 call was made
     * @param l2Timestamp l2 Timestamp at which sendTxToL1 call was made
     * @param value wei in L1 message
     * @param data abi-encoded L1 message data
     */
    function executeTransaction(
        bytes32[] calldata proof,
        uint256 index,
        address l2Sender,
        address to,
        uint256 l2Block,
        uint256 l1Block,
        uint256 l2Timestamp,
        uint256 value,
        bytes calldata data
    ) external;

    /**
     *  @dev function used to simulate the result of a particular function call from the outbox
     *       it is useful for things such as gas estimates. This function includes all costs except for
     *       proof validation (which can be considered offchain as a somewhat of a fixed cost - it's
     *       not really a fixed cost, but can be treated as so with a fixed overhead for gas estimation).
     *       We can't include the cost of proof validation since this is intended to be used to simulate txs
     *       that are included in yet-to-be confirmed merkle roots. The simulation entrypoint could instead pretend
     *       to confirm a pending merkle root, but that would be less practical for integrating with tooling.
     *       It is only possible to trigger it when the msg sender is address zero, which should be impossible
     *       unless under simulation in an eth_call or eth_estimateGas
     */
    function executeTransactionSimulation(
        uint256 index,
        address l2Sender,
        address to,
        uint256 l2Block,
        uint256 l1Block,
        uint256 l2Timestamp,
        uint256 value,
        bytes calldata data
    ) external;

    /**
     * @param index Merkle path to message
     * @return true if the message has been spent
     */
    function isSpent(uint256 index) external view returns (bool);

    function calculateItemHash(
        address l2Sender,
        address to,
        uint256 l2Block,
        uint256 l1Block,
        uint256 l2Timestamp,
        uint256 value,
        bytes calldata data
    ) external pure returns (bytes32);

    function calculateMerkleRoot(
        bytes32[] memory proof,
        uint256 path,
        bytes32 item
    ) external pure returns (bytes32);
}

// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.16;

/// @title  A global key value store
/// @notice Stores values against a key, combines msg.sender with the provided key to ensure uniqueness
contract KeyValueStore {
    event ValueSet(address indexed sender, uint256 indexed key, uint256 value);

    mapping(uint256 => uint256) public store;

    /// @notice Sets a value in the store
    /// @dev    Combines the provided key with the msg.sender to ensure uniqueness
    function set(uint256 key, uint256 value) external {
        store[computeKey(msg.sender, key)] = value;
        emit ValueSet({sender: msg.sender, key: key, value: value});
    }

    /// @notice Get a value from the store for the current msg.sender
    function get(uint256 key) external view returns (uint256) {
        return _get(msg.sender, key);
    }

    /// @notice Get a value from the store for any sender
    function get(address owner, uint256 key) external view returns (uint256) {
        return _get(owner, key);
    }

    /// @notice Compute the composite key for a specific user
    function computeKey(address owner, uint256 key) public pure returns (uint256) {
        return uint256(keccak256(abi.encode(owner, key)));
    }

    function _get(address owner, uint256 key) internal view returns (uint256) {
        return store[computeKey(owner, key)];
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface 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);
}

File 33 of 34 : IOwnable.sol
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1

// solhint-disable-next-line compiler-version
pragma solidity >=0.4.21 <0.9.0;

interface IOwnable {
    function owner() external view returns (address);
}

File 34 of 34 : IGasRefunder.sol
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1

// solhint-disable-next-line compiler-version
pragma solidity >=0.6.9 <0.9.0;

interface IGasRefunder {
    function onGasSpent(
        address payable spender,
        uint256 gasUsed,
        uint256 calldataSize
    ) external returns (bool success);
}

abstract contract GasRefundEnabled {
    /// @dev this refunds the sender for execution costs of the tx
    /// calldata costs are only refunded if `msg.sender == tx.origin` to guarantee the value refunded relates to charging
    /// for the `tx.input`. this avoids a possible attack where you generate large calldata from a contract and get over-refunded
    modifier refundsGas(IGasRefunder gasRefunder) {
        uint256 startGasLeft = gasleft();
        _;
        if (address(gasRefunder) != address(0)) {
            uint256 calldataSize;
            assembly {
                calldataSize := calldatasize()
            }
            uint256 calldataWords = (calldataSize + 31) / 32;
            // account for the CALLDATACOPY cost of the proxy contract, including the memory expansion cost
            startGasLeft += calldataWords * 6 + (calldataWords**2) / 512;
            // if triggered in a contract call, the spender may be overrefunded by appending dummy data to the call
            // so we check if it is a top level call, which would mean the sender paid calldata as part of tx.input
            // solhint-disable-next-line avoid-tx-origin
            if (msg.sender != tx.origin) {
                // We can't be sure if this calldata came from the top level tx,
                // so to be safe we tell the gas refunder there was no calldata.
                calldataSize = 0;
            }
            gasRefunder.onGasSpent(payable(msg.sender), startGasLeft - gasleft(), calldataSize);
        }
    }
}

Settings
{
  "remappings": [
    "@arbitrum/nitro-contracts/=node_modules/@arbitrum/nitro-contracts/",
    "@arbitrum/token-bridge-contracts/=node_modules/@arbitrum/token-bridge-contracts/",
    "@gnosis.pm/safe-contracts/=node_modules/@gnosis.pm/safe-contracts/",
    "@openzeppelin/contracts-upgradeable/=node_modules/@openzeppelin/contracts-upgradeable/",
    "@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/",
    "solady/=lib/solady/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 1500
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "london",
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"enum Cohort","name":"cohort","type":"uint8"}],"name":"CohortFull","type":"error"},{"inputs":[{"internalType":"address[]","name":"cohort1","type":"address[]"},{"internalType":"address[]","name":"cohort2","type":"address[]"}],"name":"CohortLengthMismatch","type":"error"},{"inputs":[{"internalType":"enum Cohort","name":"cohort","type":"uint8"}],"name":"InvalidCohort","type":"error"},{"inputs":[{"internalType":"address[]","name":"cohort","type":"address[]"},{"internalType":"uint256","name":"cohortSize","type":"uint256"}],"name":"InvalidNewCohortLength","type":"error"},{"inputs":[{"internalType":"uint256","name":"securityCouncilCount","type":"uint256"}],"name":"MaxSecurityCouncils","type":"error"},{"inputs":[{"internalType":"address","name":"member","type":"address"},{"internalType":"enum Cohort","name":"cohort","type":"uint8"}],"name":"MemberInCohort","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"NotAContract","type":"error"},{"inputs":[{"internalType":"address","name":"member","type":"address"}],"name":"NotAMember","type":"error"},{"inputs":[{"components":[{"internalType":"address","name":"securityCouncil","type":"address"},{"internalType":"address","name":"updateAction","type":"address"},{"internalType":"uint256","name":"chainId","type":"uint256"}],"internalType":"struct SecurityCouncilData","name":"securiyCouncilData","type":"tuple"}],"name":"SecurityCouncilAlreadyInRouter","type":"error"},{"inputs":[{"components":[{"internalType":"address","name":"securityCouncil","type":"address"},{"internalType":"address","name":"updateAction","type":"address"},{"internalType":"uint256","name":"chainId","type":"uint256"}],"internalType":"struct SecurityCouncilData","name":"securiyCouncilData","type":"tuple"}],"name":"SecurityCouncilNotInManager","type":"error"},{"inputs":[{"components":[{"internalType":"address","name":"securityCouncil","type":"address"},{"internalType":"address","name":"updateAction","type":"address"},{"internalType":"uint256","name":"chainId","type":"uint256"}],"internalType":"struct SecurityCouncilData","name":"securiyCouncilData","type":"tuple"}],"name":"SecurityCouncilNotInRouter","type":"error"},{"inputs":[{"components":[{"internalType":"address","name":"securityCouncil","type":"address"},{"internalType":"address","name":"updateAction","type":"address"},{"internalType":"uint256","name":"chainId","type":"uint256"}],"internalType":"struct SecurityCouncilData","name":"securiyCouncilData","type":"tuple"}],"name":"SecurityCouncilZeroChainID","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"newCohort","type":"address[]"},{"indexed":true,"internalType":"enum Cohort","name":"cohort","type":"uint8"}],"name":"CohortReplaced","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newMember","type":"address"},{"indexed":true,"internalType":"enum Cohort","name":"cohort","type":"uint8"}],"name":"MemberAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"member","type":"address"},{"indexed":true,"internalType":"enum Cohort","name":"cohort","type":"uint8"}],"name":"MemberRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"replacedMember","type":"address"},{"indexed":true,"internalType":"address","name":"newMember","type":"address"},{"indexed":false,"internalType":"enum Cohort","name":"cohort","type":"uint8"}],"name":"MemberReplaced","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"replacedAddress","type":"address"},{"indexed":true,"internalType":"address","name":"newAddress","type":"address"},{"indexed":false,"internalType":"enum Cohort","name":"cohort","type":"uint8"}],"name":"MemberRotated","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":true,"internalType":"address","name":"securityCouncil","type":"address"},{"indexed":true,"internalType":"address","name":"updateAction","type":"address"},{"indexed":false,"internalType":"uint256","name":"securityCouncilsLength","type":"uint256"}],"name":"SecurityCouncilAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"securityCouncil","type":"address"},{"indexed":true,"internalType":"address","name":"updateAction","type":"address"},{"indexed":false,"internalType":"uint256","name":"securityCouncilsLength","type":"uint256"}],"name":"SecurityCouncilRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"UpgradeExecRouteBuilder","type":"address"}],"name":"UpgradeExecRouteBuilderSet","type":"event"},{"inputs":[],"name":"COHORT_REPLACER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_SECURITY_COUNCILS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MEMBER_ADDER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MEMBER_REMOVER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MEMBER_REPLACER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MEMBER_ROTATOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RETRYABLE_TICKET_MAGIC","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newMember","type":"address"},{"internalType":"enum Cohort","name":"_cohort","type":"uint8"}],"name":"addMember","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"securityCouncil","type":"address"},{"internalType":"address","name":"updateAction","type":"address"},{"internalType":"uint256","name":"chainId","type":"uint256"}],"internalType":"struct SecurityCouncilData","name":"_securityCouncilData","type":"tuple"}],"name":"addSecurityCouncil","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum Cohort","name":"cohort","type":"uint8"},{"internalType":"address","name":"account","type":"address"}],"name":"cohortIncludes","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cohortSize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"firstCohortIncludes","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_members","type":"address[]"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"generateSalt","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getBothCohorts","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFirstCohort","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"getScheduleUpdateInnerData","outputs":[{"internalType":"address[]","name":"","type":"address[]"},{"internalType":"address","name":"","type":"address"},{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSecondCohort","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"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":"address[]","name":"_firstCohort","type":"address[]"},{"internalType":"address[]","name":"_secondCohort","type":"address[]"},{"components":[{"internalType":"address","name":"securityCouncil","type":"address"},{"internalType":"address","name":"updateAction","type":"address"},{"internalType":"uint256","name":"chainId","type":"uint256"}],"internalType":"struct SecurityCouncilData[]","name":"_securityCouncils","type":"tuple[]"},{"components":[{"internalType":"address","name":"admin","type":"address"},{"internalType":"address","name":"cohortUpdator","type":"address"},{"internalType":"address","name":"memberAdder","type":"address"},{"internalType":"address[]","name":"memberRemovers","type":"address[]"},{"internalType":"address","name":"memberRotator","type":"address"},{"internalType":"address","name":"memberReplacer","type":"address"}],"internalType":"struct SecurityCouncilManagerRoles","name":"_roles","type":"tuple"},{"internalType":"address payable","name":"_l2CoreGovTimelock","type":"address"},{"internalType":"contract UpgradeExecRouteBuilder","name":"_router","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"l2CoreGovTimelock","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_member","type":"address"}],"name":"removeMember","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"securityCouncil","type":"address"},{"internalType":"address","name":"updateAction","type":"address"},{"internalType":"uint256","name":"chainId","type":"uint256"}],"internalType":"struct SecurityCouncilData","name":"_securityCouncilData","type":"tuple"}],"name":"removeSecurityCouncil","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_newCohort","type":"address[]"},{"internalType":"enum Cohort","name":"_cohort","type":"uint8"}],"name":"replaceCohort","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_memberToReplace","type":"address"},{"internalType":"address","name":"_newMember","type":"address"}],"name":"replaceMember","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":"address","name":"_currentAddress","type":"address"},{"internalType":"address","name":"_newAddress","type":"address"}],"name":"rotateMember","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"router","outputs":[{"internalType":"contract UpgradeExecRouteBuilder","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"secondCohortIncludes","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"securityCouncils","outputs":[{"internalType":"address","name":"securityCouncil","type":"address"},{"internalType":"address","name":"updateAction","type":"address"},{"internalType":"uint256","name":"chainId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"securityCouncilsLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract UpgradeExecRouteBuilder","name":"_router","type":"address"}],"name":"setUpgradeExecRouteBuilder","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":"updateNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]

60a06040526101f46080523480156200001757600080fd5b506200002262000028565b620000ea565b600054610100900460ff1615620000955760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff9081161015620000e8576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b608051612fe66200010d600039600081816105890152611e020152612fe66000f3fe608060405234801561001057600080fd5b50600436106102775760003560e01c806391d1485411610160578063bef3f745116100d8578063e577e32e1161008c578063eea3e4d411610071578063eea3e4d4146105ec578063f5f4fde0146105ff578063f887ea401461061257600080fd5b8063e577e32e146105c6578063e9d9f048146105d957600080fd5b8063c7b3f5ca116100bd578063c7b3f5ca14610584578063d0946961146105ab578063d547741f146105b357600080fd5b8063bef3f74514610542578063c6db81291461057b57600080fd5b8063a7b20c291161012f578063b8df7c7f11610114578063b8df7c7f14610500578063b9862f2714610527578063bdc9f17c1461053a57600080fd5b8063a7b20c29146104c4578063ab738506146104d957600080fd5b806391d148541461045d578063927a038014610496578063a217fddf146104a9578063a386a802146104b157600080fd5b80633994073d116101f35780636eaff79e116101c25780638bbd5149116101a75780638bbd5149146103ed5780638e8c32101461040f578063903e7ad61461043657600080fd5b80636eaff79e146103d25780637889acb2146103e557600080fd5b80633994073d1461036657806353901f8f1461039957806360052890146103ac57806362d0d1c3146103bf57600080fd5b80630feca68a1161024a578063279684e21161022f578063279684e2146103195780632f2ff15d1461034057806336568abe1461035357600080fd5b80630feca68a146102df578063248a9ca3146102f657600080fd5b806301ffc9a71461027c5780630931d37e146102a45780630b1ca49a146102b95780630e5e43d7146102cc575b600080fd5b61028f61028a36600461254d565b610625565b60405190151581526020015b60405180910390f35b6102b76102b23660046125b4565b6106be565b005b6102b76102c73660046125ed565b610747565b6102b76102da3660046125ed565b6107f8565b6102e8609c5481565b60405190815260200161029b565b6102e861030436600461260a565b60009081526065602052604090206001015490565b6102e87f1b3e51262cf8f48cf0dc9fdd7d86c0378cf467608e72e72cd4da66efe423f19581565b6102b761034e366004612623565b610810565b6102b7610361366004612623565b61083a565b61038173a723c008e76e379c55599d2e4d93879beafda79c81565b6040516001600160a01b03909116815260200161029b565b61028f6103a73660046125ed565b6108c7565b61028f6103ba3660046126fb565b6108d4565b6102b76103cd366004612726565b610b0f565b6102b76103e03660046126fb565b610b96565b609a546102e8565b6104006103fb36600461260a565b610baa565b60405161029b939291906127ef565b6102e87fbc0a6794965897e766f364ebb1616218e4b9b088c2e6fa66bc81beb32118e60081565b6102e87fa44e94d0336494999bf078b89dcb976c3a263d47c50d54108482296643cc399d81565b61028f61046b366004612623565b60009182526065602090815260408084206001600160a01b0393909316845291905290205460ff1690565b6102e86104a43660046128c5565b610f73565b6102e8600081565b6102b76104bf366004612a42565b610fa6565b6104cc6112f8565b60405161029b9190612b0f565b6102e87f2f56750d3d98dff016e42fad39837f716b90445c26a7897ff841b45443b88baf81565b6102e87f1f53fe8d2028e3a743c2a9f8a37ec4e6497bdeb138c332a42c6b247ed57af6bc81565b6102b7610535366004612b22565b61135a565b6104cc611493565b61055561055036600461260a565b6114f3565b604080516001600160a01b0394851681529390921660208401529082015260600161029b565b6102e8609d5481565b6102e87f000000000000000000000000000000000000000000000000000000000000000081565b6104cc611533565b6102b76105c1366004612623565b61168a565b6102b76105d43660046125b4565b6116af565b61028f6105e73660046125ed565b61172a565b609954610381906001600160a01b031681565b61028f61060d366004612b67565b611733565b609b54610381906001600160a01b031681565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806106b857507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b7fa44e94d0336494999bf078b89dcb976c3a263d47c50d54108482296643cc399d6106e8816117c5565b60006106f484846117d2565b9050826001600160a01b0316846001600160a01b03167fd472135fb76619bc8ce55016956e8ebc668347e5010fddcfdc76c13e23353c8c836040516107399190612bbb565b60405180910390a350505050565b7f1f53fe8d2028e3a743c2a9f8a37ec4e6497bdeb138c332a42c6b247ed57af6bc610771816117c5565b6001600160a01b0382166107985760405163d92e233d60e01b815260040160405180910390fd5b60006107a383611835565b90506107ad6119c1565b8060018111156107bf576107bf612b83565b6040516001600160a01b038516907fcdb539c2ca5d882daa8ece3f0ee4a67d0622ab2821dfa1e20c58de079db232b490600090a3505050565b6000610803816117c5565b61080c82611b39565b5050565b60008281526065602052604090206001015461082b816117c5565b6108358383611bbe565b505050565b6001600160a01b03811633146108bd5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c66000000000000000000000000000000000060648201526084015b60405180910390fd5b61080c8282611c60565b60006106b8600083611733565b6000806108e0816117c5565b60005b609a54811015610ab3576000609a828154811061090257610902612bc9565b60009182526020909120865160039092020180549092506001600160a01b03908116911614801561093a575084604001518160020154145b801561095a5750602085015160018201546001600160a01b039081169116145b15610aa057609a80546000919061097390600190612bf5565b8154811061098357610983612bc9565b9060005260206000209060030201905080609a84815481106109a7576109a7612bc9565b60009182526020909120825460039092020180546001600160a01b039283166001600160a01b0319918216178255600180850154908301805491909416911617909155600291820154910155609a805480610a0457610a04612c08565b60008281526020812060036000199093019283020180546001600160a01b031990811682556001828101805490921690915560029091019190915591558201548254609a546040516001600160a01b039384169392909216917f1c2d9d3629f98c70662355f889a352a32e95cf1871476a177bae42fa6817465b91610a8c9190815260200190565b60405180910390a360019450505050610b09565b5080610aab81612c1e565b9150506108e3565b50604080517f4ca2cac500000000000000000000000000000000000000000000000000000000815284516001600160a01b03908116600483015260208601511660248201529084015160448201526064016108b4565b50919050565b7f2f56750d3d98dff016e42fad39837f716b90445c26a7897ff841b45443b88baf610b39816117c5565b610b438383611ce3565b610b4b6119c1565b816001811115610b5d57610b5d612b83565b6040516001600160a01b038516907ff833c29297cb62e4d5e38257097ec5d6575967915f151215dd8fc03f8f548ce890600090a3505050565b6000610ba1816117c5565b61080c82611dfd565b6060600060606000610bba611533565b609a5490915060009067ffffffffffffffff811115610bdb57610bdb612648565b604051908082528060200260200182016040528015610c04578160200160208202803683370190505b50609a5490915060009067ffffffffffffffff811115610c2657610c26612648565b604051908082528060200260200182016040528015610c5957816020015b6060815260200190600190039081610c445790505b50609a5490915060009067ffffffffffffffff811115610c7b57610c7b612648565b604051908082528060200260200182016040528015610ca4578160200160208202803683370190505b50905060005b609a54811015610e27576000609a8281548110610cc957610cc9612bc9565b600091825260209182902060408051606081018252600390930290910180546001600160a01b03908116845260018201541693830184905260020154908201528651909250869084908110610d2057610d20612bc9565b60200260200101906001600160a01b031690816001600160a01b0316815250508060400151838381518110610d5757610d57612bc9565b602090810291909101015280516040517f536d89440000000000000000000000000000000000000000000000000000000091610d999189908e90602401612c37565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050848381518110610e0857610e08612bc9565b6020026020010181905250508080610e1f90612c1e565b915050610caa565b50604051630124f40760e71b8152600090309063927a038090610e509088908d90600401612c69565b602060405180830381865afa158015610e6d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e919190612c8b565b609b54609a5491925060009182916001600160a01b03169063035a5724908690899067ffffffffffffffff811115610ecb57610ecb612648565b604051908082528060200260200182016040528015610ef4578160200160208202803683370190505b50896000896040518763ffffffff1660e01b8152600401610f1a96959493929190612cd4565b600060405180830381865afa158015610f37573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610f5f9190810190612d7f565b979c909b5096995095975050505050505050565b60008282604051602001610f88929190612c69565b60405160208183030381529060405280519060200120905092915050565b600054610100900460ff1615808015610fc65750600054600160ff909116105b80610fe05750303b158015610fe0575060005460ff166001145b6110525760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084016108b4565b6000805460ff191660011790558015611075576000805461ff0019166101001790555b85518751146110b45786866040517f6810b96d0000000000000000000000000000000000000000000000000000000081526004016108b4929190612e29565b86516110c79060979060208a01906124b9565b5085516110db9060989060208901906124b9565b508651609d5583516110ef90600090611bbe565b61111d7f1b3e51262cf8f48cf0dc9fdd7d86c0378cf467608e72e72cd4da66efe423f1958560200151611bbe565b61114b7f2f56750d3d98dff016e42fad39837f716b90445c26a7897ff841b45443b88baf8560400151611bbe565b60005b8460600151518110156111b4576111a27f1f53fe8d2028e3a743c2a9f8a37ec4e6497bdeb138c332a42c6b247ed57af6bc8660600151838151811061119557611195612bc9565b6020026020010151611bbe565b806111ac81612c1e565b91505061114e565b506111e37fa44e94d0336494999bf078b89dcb976c3a263d47c50d54108482296643cc399d8560800151611bbe565b6112117fbc0a6794965897e766f364ebb1616218e4b9b088c2e6fa66bc81beb32118e6008560a00151611bbe565b6001600160a01b0383163b611244576040516322a2d07b60e21b81526001600160a01b03841660048201526024016108b4565b609980546001600160a01b0319166001600160a01b03851617905561126882611b39565b60005b85518110156112a85761129686828151811061128957611289612bc9565b6020026020010151611dfd565b806112a081612c1e565b91505061126b565b5080156112ef576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b6060609780548060200260200160405190810160405280929190818152602001828054801561135057602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611332575b5050505050905090565b7f1b3e51262cf8f48cf0dc9fdd7d86c0378cf467608e72e72cd4da66efe423f195611384816117c5565b609d548351146113c557609d546040517fccd0fd400000000000000000000000000000000000000000000000000000000081526108b4918591600401612c69565b60008260018111156113d9576113d9612b83565b146113ef576113ea6098600061251e565b6113fb565b6113fb6097600061251e565b60005b835181101561143c5761142a84828151811061141c5761141c612bc9565b602002602001015184611ce3565b8061143481612c1e565b9150506113fe565b506114456119c1565b81600181111561145757611457612b83565b7fd5e8716d6660a059b6c8a80f6cc297286cdb3ea2e4c5f6ba24544068d164cadb846040516114869190612b0f565b60405180910390a2505050565b60606098805480602002602001604051908101604052809291908181526020018280548015611350576020028201919060005260206000209081546001600160a01b03168152600190910190602001808311611332575050505050905090565b609a818154811061150357600080fd5b60009182526020909120600390910201805460018201546002909201546001600160a01b03918216935091169083565b6098546097546060916000916115499190612e4e565b67ffffffffffffffff81111561156157611561612648565b60405190808252806020026020018201604052801561158a578160200160208202803683370190505b50905060005b60975481101561160757609781815481106115ad576115ad612bc9565b9060005260206000200160009054906101000a90046001600160a01b03168282815181106115dd576115dd612bc9565b6001600160a01b0390921660209283029190910190910152806115ff81612c1e565b915050611590565b5060005b609854811015610b09576098818154811061162857611628612bc9565b6000918252602090912001546097546001600160a01b03909116908390611650908490612e4e565b8151811061166057611660612bc9565b6001600160a01b03909216602092830291909101909101528061168281612c1e565b91505061160b565b6000828152606560205260409020600101546116a5816117c5565b6108358383611c60565b7fbc0a6794965897e766f364ebb1616218e4b9b088c2e6fa66bc81beb32118e6006116d9816117c5565b60006116e584846117d2565b9050826001600160a01b0316846001600160a01b03167f89ccdb5f09b32bde0f554abe57fe1752d09aa2cad4a43fa9a48b1d1f153a975f836040516107399190612bbb565b60006106b86001835b6000808084600181111561174957611749612b83565b14611755576098611758565b60975b8054806020026020016040519081016040528092919081815260200182805480156117ac57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161178e575b505050505090506117bd83826121ab565b949350505050565b6117cf8133612210565b50565b60006001600160a01b03831615806117f157506001600160a01b038216155b1561180f5760405163d92e233d60e01b815260040160405180910390fd5b600061181a84611835565b90506118268382611ce3565b61182e6119c1565b9392505050565b6000805b60028110156119835760008115611851576098611854565b60975b905060005b815481101561196e5781818154811061187457611874612bc9565b6000918252602090912001546001600160a01b039081169086160361195c57815482906118a390600190612bf5565b815481106118b3576118b3612bc9565b9060005260206000200160009054906101000a90046001600160a01b03168282815481106118e3576118e3612bc9565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055508180548061192157611921612c08565b600082815260209020810160001990810180546001600160a01b03191690550190558215611950576001611953565b60005b95945050505050565b8061196681612c1e565b915050611859565b5050808061197b90612c1e565b915050611839565b506040517fc74f99ae0000000000000000000000000000000000000000000000000000000081526001600160a01b03831660048201526024016108b4565b609c80549060006119d183612c1e565b919050555060008060006119e6609c54610baa565b609954609c54604051630124f40760e71b81529497509295509093506001600160a01b0316916301d5062a91859160009186918391309163927a038091611a32918d9190600401612c69565b602060405180830381865afa158015611a4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a739190612c8b565b609960009054906101000a90046001600160a01b03166001600160a01b031663f27a0c926040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ac6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aea9190612c8b565b6040518763ffffffff1660e01b8152600401611b0b96959493929190612e61565b600060405180830381600087803b158015611b2557600080fd5b505af11580156112ef573d6000803e3d6000fd5b806001600160a01b0381163b611b6d576040516322a2d07b60e21b81526001600160a01b03821660048201526024016108b4565b609b80546001600160a01b0319166001600160a01b0384811691909117909155604051908216907f80559aaa0b216d869e732384a4e97b6a0cbfeb3779a81774281988d977bf3e6a90600090a25050565b60008281526065602090815260408083206001600160a01b038516845290915290205460ff1661080c5760008281526065602090815260408083206001600160a01b03851684529091529020805460ff19166001179055611c1c3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b60008281526065602090815260408083206001600160a01b038516845290915290205460ff161561080c5760008281526065602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6001600160a01b038216611d0a5760405163d92e233d60e01b815260040160405180910390fd5b600080826001811115611d1f57611d1f612b83565b14611d2b576098611d2e565b60975b609d5481549192509003611d7057816040517f8f1d3f5a0000000000000000000000000000000000000000000000000000000081526004016108b49190612bbb565b611d79836108c7565b15611d9c5782600060405163f43031b360e01b81526004016108b4929190612ea7565b611da58361172a565b15611dc85782600160405163f43031b360e01b81526004016108b4929190612ea7565b8054600181018255600091825260209091200180546001600160a01b0319166001600160a01b03939093169290921790915550565b609a547f00000000000000000000000000000000000000000000000000000000000000009003611e6057609a546040517f4b2d2c4300000000000000000000000000000000000000000000000000000000815260048101919091526024016108b4565b60208101516001600160a01b03161580611e82575080516001600160a01b0316155b15611ea05760405163d92e233d60e01b815260040160405180910390fd5b8060400151600003611f0157604080517f4c9bdd2f00000000000000000000000000000000000000000000000000000000815282516001600160a01b03908116600483015260208401511660248201529082015160448201526064016108b4565b609b5460408083015190517fee382a710000000000000000000000000000000000000000000000000000000081526001600160a01b039092169163ee382a7191611f519160040190815260200190565b602060405180830381865afa158015611f6e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f929190612ec4565b611feb57604080517f9f4c6b2b00000000000000000000000000000000000000000000000000000000815282516001600160a01b03908116600483015260208401511660248201529082015160448201526064016108b4565b60005b609a548110156120af576000609a828154811061200d5761200d612bc9565b90600052602060002090600302019050826040015181600201541480156120425750825181546001600160a01b039081169116145b1561209c57604080517f92122f8f00000000000000000000000000000000000000000000000000000000815284516001600160a01b03908116600483015260208601511660248201529084015160448201526064016108b4565b50806120a781612c1e565b915050611fee565b50609a80546001810182556000829052825160039091027f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be4810180546001600160a01b039384166001600160a01b0319918216811790925560208601517f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be58401805491909516911681179093556040808601517f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be690930192909255925490519192917f1fb036a9ae4b15f2a623a7e54c2bcf8d6d3e2e29a80c73ca472ad00d812ac147916121a09190815260200190565b60405180910390a350565b6000805b825181101561220657836001600160a01b03168382815181106121d4576121d4612bc9565b60200260200101516001600160a01b0316036121f45760019150506106b8565b806121fe81612c1e565b9150506121af565b5060009392505050565b60008281526065602090815260408083206001600160a01b038516845290915290205460ff1661080c5761224e816001600160a01b03166014612290565b612259836020612290565b60405160200161226a929190612ee6565b60408051601f198184030181529082905262461bcd60e51b82526108b491600401612f67565b6060600061229f836002612f7a565b6122aa906002612e4e565b67ffffffffffffffff8111156122c2576122c2612648565b6040519080825280601f01601f1916602001820160405280156122ec576020820181803683370190505b5090507f30000000000000000000000000000000000000000000000000000000000000008160008151811061232357612323612bc9565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f78000000000000000000000000000000000000000000000000000000000000008160018151811061238657612386612bc9565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060006123c2846002612f7a565b6123cd906001612e4e565b90505b600181111561246a577f303132333435363738396162636465660000000000000000000000000000000085600f166010811061240e5761240e612bc9565b1a60f81b82828151811061242457612424612bc9565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c9361246381612f99565b90506123d0565b50831561182e5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016108b4565b82805482825590600052602060002090810192821561250e579160200282015b8281111561250e57825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906124d9565b5061251a929150612538565b5090565b50805460008255906000526020600020908101906117cf91905b5b8082111561251a5760008155600101612539565b60006020828403121561255f57600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461182e57600080fd5b6001600160a01b03811681146117cf57600080fd5b80356125af8161258f565b919050565b600080604083850312156125c757600080fd5b82356125d28161258f565b915060208301356125e28161258f565b809150509250929050565b6000602082840312156125ff57600080fd5b813561182e8161258f565b60006020828403121561261c57600080fd5b5035919050565b6000806040838503121561263657600080fd5b8235915060208301356125e28161258f565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561268757612687612648565b604052919050565b6000606082840312156126a157600080fd5b6040516060810181811067ffffffffffffffff821117156126c4576126c4612648565b60405290508082356126d58161258f565b815260208301356126e58161258f565b6020820152604092830135920191909152919050565b60006060828403121561270d57600080fd5b61182e838361268f565b8035600281106125af57600080fd5b6000806040838503121561273957600080fd5b82356127448161258f565b915061275260208401612717565b90509250929050565b600081518084526020808501945080840160005b838110156127945781516001600160a01b03168752958201959082019060010161276f565b509495945050505050565b60005b838110156127ba5781810151838201526020016127a2565b50506000910152565b600081518084526127db81602086016020860161279f565b601f01601f19169290920160200192915050565b606081526000612802606083018661275b565b6001600160a01b0385166020840152828103604084015261282381856127c3565b9695505050505050565b600067ffffffffffffffff82111561284757612847612648565b5060051b60200190565b600082601f83011261286257600080fd5b813560206128776128728361282d565b61265e565b82815260059290921b8401810191818101908684111561289657600080fd5b8286015b848110156128ba5780356128ad8161258f565b835291830191830161289a565b509695505050505050565b600080604083850312156128d857600080fd5b823567ffffffffffffffff8111156128ef57600080fd5b6128fb85828601612851565b95602094909401359450505050565b600082601f83011261291b57600080fd5b8135602061292b6128728361282d565b8281526060928302850182019282820191908785111561294a57600080fd5b8387015b8581101561296d57612960898261268f565b845292840192810161294e565b5090979650505050505050565b600060c0828403121561298c57600080fd5b60405160c0810167ffffffffffffffff82821081831117156129b0576129b0612648565b81604052829350843591506129c48261258f565b9082526020840135906129d68261258f565b816020840152604085013591506129ec8261258f565b8160408401526060850135915080821115612a0657600080fd5b50612a1385828601612851565b606083015250612a25608084016125a4565b6080820152612a3660a084016125a4565b60a08201525092915050565b60008060008060008060c08789031215612a5b57600080fd5b863567ffffffffffffffff80821115612a7357600080fd5b612a7f8a838b01612851565b97506020890135915080821115612a9557600080fd5b612aa18a838b01612851565b96506040890135915080821115612ab757600080fd5b612ac38a838b0161290a565b95506060890135915080821115612ad957600080fd5b50612ae689828a0161297a565b935050612af5608088016125a4565b9150612b0360a088016125a4565b90509295509295509295565b60208152600061182e602083018461275b565b60008060408385031215612b3557600080fd5b823567ffffffffffffffff811115612b4c57600080fd5b612b5885828601612851565b92505061275260208401612717565b60008060408385031215612b7a57600080fd5b6125d283612717565b634e487b7160e01b600052602160045260246000fd5b60028110612bb757634e487b7160e01b600052602160045260246000fd5b9052565b602081016106b88284612b99565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b818103818111156106b8576106b8612bdf565b634e487b7160e01b600052603160045260246000fd5b600060018201612c3057612c30612bdf565b5060010190565b6001600160a01b0384168152606060208201526000612c59606083018561275b565b9050826040830152949350505050565b604081526000612c7c604083018561275b565b90508260208301529392505050565b600060208284031215612c9d57600080fd5b5051919050565b600081518084526020808501945080840160005b8381101561279457815187529582019590820190600101612cb8565b60c081526000612ce760c0830189612ca4565b602083820381850152612cfa828a61275b565b91508382036040850152612d0e8289612ca4565b915083820360608501528187518084528284019150828160051b850101838a0160005b83811015612d5f57601f19878403018552612d4d8383516127c3565b94860194925090850190600101612d31565b505060808701989098525050505060a09091019190915250949350505050565b60008060408385031215612d9257600080fd5b8251612d9d8161258f565b602084015190925067ffffffffffffffff80821115612dbb57600080fd5b818501915085601f830112612dcf57600080fd5b815181811115612de157612de1612648565b612df4601f8201601f191660200161265e565b9150808252866020828501011115612e0b57600080fd5b612e1c81602084016020860161279f565b5080925050509250929050565b604081526000612e3c604083018561275b565b8281036020840152611953818561275b565b808201808211156106b8576106b8612bdf565b6001600160a01b038716815285602082015260c060408201526000612e8960c08301876127c3565b606083019590955250608081019290925260a0909101529392505050565b6001600160a01b03831681526040810161182e6020830184612b99565b600060208284031215612ed657600080fd5b8151801515811461182e57600080fd5b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351612f1e81601785016020880161279f565b7f206973206d697373696e6720726f6c65200000000000000000000000000000006017918401918201528351612f5b81602884016020880161279f565b01602801949350505050565b60208152600061182e60208301846127c3565b6000816000190483118215151615612f9457612f94612bdf565b500290565b600081612fa857612fa8612bdf565b50600019019056fea2646970667358221220470c294f844a6607a400ab11f1249e66205e0179bee9c2ccb7f4f10acf83910064736f6c63430008100033

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106102775760003560e01c806391d1485411610160578063bef3f745116100d8578063e577e32e1161008c578063eea3e4d411610071578063eea3e4d4146105ec578063f5f4fde0146105ff578063f887ea401461061257600080fd5b8063e577e32e146105c6578063e9d9f048146105d957600080fd5b8063c7b3f5ca116100bd578063c7b3f5ca14610584578063d0946961146105ab578063d547741f146105b357600080fd5b8063bef3f74514610542578063c6db81291461057b57600080fd5b8063a7b20c291161012f578063b8df7c7f11610114578063b8df7c7f14610500578063b9862f2714610527578063bdc9f17c1461053a57600080fd5b8063a7b20c29146104c4578063ab738506146104d957600080fd5b806391d148541461045d578063927a038014610496578063a217fddf146104a9578063a386a802146104b157600080fd5b80633994073d116101f35780636eaff79e116101c25780638bbd5149116101a75780638bbd5149146103ed5780638e8c32101461040f578063903e7ad61461043657600080fd5b80636eaff79e146103d25780637889acb2146103e557600080fd5b80633994073d1461036657806353901f8f1461039957806360052890146103ac57806362d0d1c3146103bf57600080fd5b80630feca68a1161024a578063279684e21161022f578063279684e2146103195780632f2ff15d1461034057806336568abe1461035357600080fd5b80630feca68a146102df578063248a9ca3146102f657600080fd5b806301ffc9a71461027c5780630931d37e146102a45780630b1ca49a146102b95780630e5e43d7146102cc575b600080fd5b61028f61028a36600461254d565b610625565b60405190151581526020015b60405180910390f35b6102b76102b23660046125b4565b6106be565b005b6102b76102c73660046125ed565b610747565b6102b76102da3660046125ed565b6107f8565b6102e8609c5481565b60405190815260200161029b565b6102e861030436600461260a565b60009081526065602052604090206001015490565b6102e87f1b3e51262cf8f48cf0dc9fdd7d86c0378cf467608e72e72cd4da66efe423f19581565b6102b761034e366004612623565b610810565b6102b7610361366004612623565b61083a565b61038173a723c008e76e379c55599d2e4d93879beafda79c81565b6040516001600160a01b03909116815260200161029b565b61028f6103a73660046125ed565b6108c7565b61028f6103ba3660046126fb565b6108d4565b6102b76103cd366004612726565b610b0f565b6102b76103e03660046126fb565b610b96565b609a546102e8565b6104006103fb36600461260a565b610baa565b60405161029b939291906127ef565b6102e87fbc0a6794965897e766f364ebb1616218e4b9b088c2e6fa66bc81beb32118e60081565b6102e87fa44e94d0336494999bf078b89dcb976c3a263d47c50d54108482296643cc399d81565b61028f61046b366004612623565b60009182526065602090815260408084206001600160a01b0393909316845291905290205460ff1690565b6102e86104a43660046128c5565b610f73565b6102e8600081565b6102b76104bf366004612a42565b610fa6565b6104cc6112f8565b60405161029b9190612b0f565b6102e87f2f56750d3d98dff016e42fad39837f716b90445c26a7897ff841b45443b88baf81565b6102e87f1f53fe8d2028e3a743c2a9f8a37ec4e6497bdeb138c332a42c6b247ed57af6bc81565b6102b7610535366004612b22565b61135a565b6104cc611493565b61055561055036600461260a565b6114f3565b604080516001600160a01b0394851681529390921660208401529082015260600161029b565b6102e8609d5481565b6102e87f00000000000000000000000000000000000000000000000000000000000001f481565b6104cc611533565b6102b76105c1366004612623565b61168a565b6102b76105d43660046125b4565b6116af565b61028f6105e73660046125ed565b61172a565b609954610381906001600160a01b031681565b61028f61060d366004612b67565b611733565b609b54610381906001600160a01b031681565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806106b857507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b7fa44e94d0336494999bf078b89dcb976c3a263d47c50d54108482296643cc399d6106e8816117c5565b60006106f484846117d2565b9050826001600160a01b0316846001600160a01b03167fd472135fb76619bc8ce55016956e8ebc668347e5010fddcfdc76c13e23353c8c836040516107399190612bbb565b60405180910390a350505050565b7f1f53fe8d2028e3a743c2a9f8a37ec4e6497bdeb138c332a42c6b247ed57af6bc610771816117c5565b6001600160a01b0382166107985760405163d92e233d60e01b815260040160405180910390fd5b60006107a383611835565b90506107ad6119c1565b8060018111156107bf576107bf612b83565b6040516001600160a01b038516907fcdb539c2ca5d882daa8ece3f0ee4a67d0622ab2821dfa1e20c58de079db232b490600090a3505050565b6000610803816117c5565b61080c82611b39565b5050565b60008281526065602052604090206001015461082b816117c5565b6108358383611bbe565b505050565b6001600160a01b03811633146108bd5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c66000000000000000000000000000000000060648201526084015b60405180910390fd5b61080c8282611c60565b60006106b8600083611733565b6000806108e0816117c5565b60005b609a54811015610ab3576000609a828154811061090257610902612bc9565b60009182526020909120865160039092020180549092506001600160a01b03908116911614801561093a575084604001518160020154145b801561095a5750602085015160018201546001600160a01b039081169116145b15610aa057609a80546000919061097390600190612bf5565b8154811061098357610983612bc9565b9060005260206000209060030201905080609a84815481106109a7576109a7612bc9565b60009182526020909120825460039092020180546001600160a01b039283166001600160a01b0319918216178255600180850154908301805491909416911617909155600291820154910155609a805480610a0457610a04612c08565b60008281526020812060036000199093019283020180546001600160a01b031990811682556001828101805490921690915560029091019190915591558201548254609a546040516001600160a01b039384169392909216917f1c2d9d3629f98c70662355f889a352a32e95cf1871476a177bae42fa6817465b91610a8c9190815260200190565b60405180910390a360019450505050610b09565b5080610aab81612c1e565b9150506108e3565b50604080517f4ca2cac500000000000000000000000000000000000000000000000000000000815284516001600160a01b03908116600483015260208601511660248201529084015160448201526064016108b4565b50919050565b7f2f56750d3d98dff016e42fad39837f716b90445c26a7897ff841b45443b88baf610b39816117c5565b610b438383611ce3565b610b4b6119c1565b816001811115610b5d57610b5d612b83565b6040516001600160a01b038516907ff833c29297cb62e4d5e38257097ec5d6575967915f151215dd8fc03f8f548ce890600090a3505050565b6000610ba1816117c5565b61080c82611dfd565b6060600060606000610bba611533565b609a5490915060009067ffffffffffffffff811115610bdb57610bdb612648565b604051908082528060200260200182016040528015610c04578160200160208202803683370190505b50609a5490915060009067ffffffffffffffff811115610c2657610c26612648565b604051908082528060200260200182016040528015610c5957816020015b6060815260200190600190039081610c445790505b50609a5490915060009067ffffffffffffffff811115610c7b57610c7b612648565b604051908082528060200260200182016040528015610ca4578160200160208202803683370190505b50905060005b609a54811015610e27576000609a8281548110610cc957610cc9612bc9565b600091825260209182902060408051606081018252600390930290910180546001600160a01b03908116845260018201541693830184905260020154908201528651909250869084908110610d2057610d20612bc9565b60200260200101906001600160a01b031690816001600160a01b0316815250508060400151838381518110610d5757610d57612bc9565b602090810291909101015280516040517f536d89440000000000000000000000000000000000000000000000000000000091610d999189908e90602401612c37565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050848381518110610e0857610e08612bc9565b6020026020010181905250508080610e1f90612c1e565b915050610caa565b50604051630124f40760e71b8152600090309063927a038090610e509088908d90600401612c69565b602060405180830381865afa158015610e6d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e919190612c8b565b609b54609a5491925060009182916001600160a01b03169063035a5724908690899067ffffffffffffffff811115610ecb57610ecb612648565b604051908082528060200260200182016040528015610ef4578160200160208202803683370190505b50896000896040518763ffffffff1660e01b8152600401610f1a96959493929190612cd4565b600060405180830381865afa158015610f37573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610f5f9190810190612d7f565b979c909b5096995095975050505050505050565b60008282604051602001610f88929190612c69565b60405160208183030381529060405280519060200120905092915050565b600054610100900460ff1615808015610fc65750600054600160ff909116105b80610fe05750303b158015610fe0575060005460ff166001145b6110525760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084016108b4565b6000805460ff191660011790558015611075576000805461ff0019166101001790555b85518751146110b45786866040517f6810b96d0000000000000000000000000000000000000000000000000000000081526004016108b4929190612e29565b86516110c79060979060208a01906124b9565b5085516110db9060989060208901906124b9565b508651609d5583516110ef90600090611bbe565b61111d7f1b3e51262cf8f48cf0dc9fdd7d86c0378cf467608e72e72cd4da66efe423f1958560200151611bbe565b61114b7f2f56750d3d98dff016e42fad39837f716b90445c26a7897ff841b45443b88baf8560400151611bbe565b60005b8460600151518110156111b4576111a27f1f53fe8d2028e3a743c2a9f8a37ec4e6497bdeb138c332a42c6b247ed57af6bc8660600151838151811061119557611195612bc9565b6020026020010151611bbe565b806111ac81612c1e565b91505061114e565b506111e37fa44e94d0336494999bf078b89dcb976c3a263d47c50d54108482296643cc399d8560800151611bbe565b6112117fbc0a6794965897e766f364ebb1616218e4b9b088c2e6fa66bc81beb32118e6008560a00151611bbe565b6001600160a01b0383163b611244576040516322a2d07b60e21b81526001600160a01b03841660048201526024016108b4565b609980546001600160a01b0319166001600160a01b03851617905561126882611b39565b60005b85518110156112a85761129686828151811061128957611289612bc9565b6020026020010151611dfd565b806112a081612c1e565b91505061126b565b5080156112ef576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b6060609780548060200260200160405190810160405280929190818152602001828054801561135057602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611332575b5050505050905090565b7f1b3e51262cf8f48cf0dc9fdd7d86c0378cf467608e72e72cd4da66efe423f195611384816117c5565b609d548351146113c557609d546040517fccd0fd400000000000000000000000000000000000000000000000000000000081526108b4918591600401612c69565b60008260018111156113d9576113d9612b83565b146113ef576113ea6098600061251e565b6113fb565b6113fb6097600061251e565b60005b835181101561143c5761142a84828151811061141c5761141c612bc9565b602002602001015184611ce3565b8061143481612c1e565b9150506113fe565b506114456119c1565b81600181111561145757611457612b83565b7fd5e8716d6660a059b6c8a80f6cc297286cdb3ea2e4c5f6ba24544068d164cadb846040516114869190612b0f565b60405180910390a2505050565b60606098805480602002602001604051908101604052809291908181526020018280548015611350576020028201919060005260206000209081546001600160a01b03168152600190910190602001808311611332575050505050905090565b609a818154811061150357600080fd5b60009182526020909120600390910201805460018201546002909201546001600160a01b03918216935091169083565b6098546097546060916000916115499190612e4e565b67ffffffffffffffff81111561156157611561612648565b60405190808252806020026020018201604052801561158a578160200160208202803683370190505b50905060005b60975481101561160757609781815481106115ad576115ad612bc9565b9060005260206000200160009054906101000a90046001600160a01b03168282815181106115dd576115dd612bc9565b6001600160a01b0390921660209283029190910190910152806115ff81612c1e565b915050611590565b5060005b609854811015610b09576098818154811061162857611628612bc9565b6000918252602090912001546097546001600160a01b03909116908390611650908490612e4e565b8151811061166057611660612bc9565b6001600160a01b03909216602092830291909101909101528061168281612c1e565b91505061160b565b6000828152606560205260409020600101546116a5816117c5565b6108358383611c60565b7fbc0a6794965897e766f364ebb1616218e4b9b088c2e6fa66bc81beb32118e6006116d9816117c5565b60006116e584846117d2565b9050826001600160a01b0316846001600160a01b03167f89ccdb5f09b32bde0f554abe57fe1752d09aa2cad4a43fa9a48b1d1f153a975f836040516107399190612bbb565b60006106b86001835b6000808084600181111561174957611749612b83565b14611755576098611758565b60975b8054806020026020016040519081016040528092919081815260200182805480156117ac57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161178e575b505050505090506117bd83826121ab565b949350505050565b6117cf8133612210565b50565b60006001600160a01b03831615806117f157506001600160a01b038216155b1561180f5760405163d92e233d60e01b815260040160405180910390fd5b600061181a84611835565b90506118268382611ce3565b61182e6119c1565b9392505050565b6000805b60028110156119835760008115611851576098611854565b60975b905060005b815481101561196e5781818154811061187457611874612bc9565b6000918252602090912001546001600160a01b039081169086160361195c57815482906118a390600190612bf5565b815481106118b3576118b3612bc9565b9060005260206000200160009054906101000a90046001600160a01b03168282815481106118e3576118e3612bc9565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055508180548061192157611921612c08565b600082815260209020810160001990810180546001600160a01b03191690550190558215611950576001611953565b60005b95945050505050565b8061196681612c1e565b915050611859565b5050808061197b90612c1e565b915050611839565b506040517fc74f99ae0000000000000000000000000000000000000000000000000000000081526001600160a01b03831660048201526024016108b4565b609c80549060006119d183612c1e565b919050555060008060006119e6609c54610baa565b609954609c54604051630124f40760e71b81529497509295509093506001600160a01b0316916301d5062a91859160009186918391309163927a038091611a32918d9190600401612c69565b602060405180830381865afa158015611a4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a739190612c8b565b609960009054906101000a90046001600160a01b03166001600160a01b031663f27a0c926040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ac6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aea9190612c8b565b6040518763ffffffff1660e01b8152600401611b0b96959493929190612e61565b600060405180830381600087803b158015611b2557600080fd5b505af11580156112ef573d6000803e3d6000fd5b806001600160a01b0381163b611b6d576040516322a2d07b60e21b81526001600160a01b03821660048201526024016108b4565b609b80546001600160a01b0319166001600160a01b0384811691909117909155604051908216907f80559aaa0b216d869e732384a4e97b6a0cbfeb3779a81774281988d977bf3e6a90600090a25050565b60008281526065602090815260408083206001600160a01b038516845290915290205460ff1661080c5760008281526065602090815260408083206001600160a01b03851684529091529020805460ff19166001179055611c1c3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b60008281526065602090815260408083206001600160a01b038516845290915290205460ff161561080c5760008281526065602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6001600160a01b038216611d0a5760405163d92e233d60e01b815260040160405180910390fd5b600080826001811115611d1f57611d1f612b83565b14611d2b576098611d2e565b60975b609d5481549192509003611d7057816040517f8f1d3f5a0000000000000000000000000000000000000000000000000000000081526004016108b49190612bbb565b611d79836108c7565b15611d9c5782600060405163f43031b360e01b81526004016108b4929190612ea7565b611da58361172a565b15611dc85782600160405163f43031b360e01b81526004016108b4929190612ea7565b8054600181018255600091825260209091200180546001600160a01b0319166001600160a01b03939093169290921790915550565b609a547f00000000000000000000000000000000000000000000000000000000000001f49003611e6057609a546040517f4b2d2c4300000000000000000000000000000000000000000000000000000000815260048101919091526024016108b4565b60208101516001600160a01b03161580611e82575080516001600160a01b0316155b15611ea05760405163d92e233d60e01b815260040160405180910390fd5b8060400151600003611f0157604080517f4c9bdd2f00000000000000000000000000000000000000000000000000000000815282516001600160a01b03908116600483015260208401511660248201529082015160448201526064016108b4565b609b5460408083015190517fee382a710000000000000000000000000000000000000000000000000000000081526001600160a01b039092169163ee382a7191611f519160040190815260200190565b602060405180830381865afa158015611f6e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f929190612ec4565b611feb57604080517f9f4c6b2b00000000000000000000000000000000000000000000000000000000815282516001600160a01b03908116600483015260208401511660248201529082015160448201526064016108b4565b60005b609a548110156120af576000609a828154811061200d5761200d612bc9565b90600052602060002090600302019050826040015181600201541480156120425750825181546001600160a01b039081169116145b1561209c57604080517f92122f8f00000000000000000000000000000000000000000000000000000000815284516001600160a01b03908116600483015260208601511660248201529084015160448201526064016108b4565b50806120a781612c1e565b915050611fee565b50609a80546001810182556000829052825160039091027f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be4810180546001600160a01b039384166001600160a01b0319918216811790925560208601517f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be58401805491909516911681179093556040808601517f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be690930192909255925490519192917f1fb036a9ae4b15f2a623a7e54c2bcf8d6d3e2e29a80c73ca472ad00d812ac147916121a09190815260200190565b60405180910390a350565b6000805b825181101561220657836001600160a01b03168382815181106121d4576121d4612bc9565b60200260200101516001600160a01b0316036121f45760019150506106b8565b806121fe81612c1e565b9150506121af565b5060009392505050565b60008281526065602090815260408083206001600160a01b038516845290915290205460ff1661080c5761224e816001600160a01b03166014612290565b612259836020612290565b60405160200161226a929190612ee6565b60408051601f198184030181529082905262461bcd60e51b82526108b491600401612f67565b6060600061229f836002612f7a565b6122aa906002612e4e565b67ffffffffffffffff8111156122c2576122c2612648565b6040519080825280601f01601f1916602001820160405280156122ec576020820181803683370190505b5090507f30000000000000000000000000000000000000000000000000000000000000008160008151811061232357612323612bc9565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f78000000000000000000000000000000000000000000000000000000000000008160018151811061238657612386612bc9565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060006123c2846002612f7a565b6123cd906001612e4e565b90505b600181111561246a577f303132333435363738396162636465660000000000000000000000000000000085600f166010811061240e5761240e612bc9565b1a60f81b82828151811061242457612424612bc9565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c9361246381612f99565b90506123d0565b50831561182e5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016108b4565b82805482825590600052602060002090810192821561250e579160200282015b8281111561250e57825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906124d9565b5061251a929150612538565b5090565b50805460008255906000526020600020908101906117cf91905b5b8082111561251a5760008155600101612539565b60006020828403121561255f57600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461182e57600080fd5b6001600160a01b03811681146117cf57600080fd5b80356125af8161258f565b919050565b600080604083850312156125c757600080fd5b82356125d28161258f565b915060208301356125e28161258f565b809150509250929050565b6000602082840312156125ff57600080fd5b813561182e8161258f565b60006020828403121561261c57600080fd5b5035919050565b6000806040838503121561263657600080fd5b8235915060208301356125e28161258f565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561268757612687612648565b604052919050565b6000606082840312156126a157600080fd5b6040516060810181811067ffffffffffffffff821117156126c4576126c4612648565b60405290508082356126d58161258f565b815260208301356126e58161258f565b6020820152604092830135920191909152919050565b60006060828403121561270d57600080fd5b61182e838361268f565b8035600281106125af57600080fd5b6000806040838503121561273957600080fd5b82356127448161258f565b915061275260208401612717565b90509250929050565b600081518084526020808501945080840160005b838110156127945781516001600160a01b03168752958201959082019060010161276f565b509495945050505050565b60005b838110156127ba5781810151838201526020016127a2565b50506000910152565b600081518084526127db81602086016020860161279f565b601f01601f19169290920160200192915050565b606081526000612802606083018661275b565b6001600160a01b0385166020840152828103604084015261282381856127c3565b9695505050505050565b600067ffffffffffffffff82111561284757612847612648565b5060051b60200190565b600082601f83011261286257600080fd5b813560206128776128728361282d565b61265e565b82815260059290921b8401810191818101908684111561289657600080fd5b8286015b848110156128ba5780356128ad8161258f565b835291830191830161289a565b509695505050505050565b600080604083850312156128d857600080fd5b823567ffffffffffffffff8111156128ef57600080fd5b6128fb85828601612851565b95602094909401359450505050565b600082601f83011261291b57600080fd5b8135602061292b6128728361282d565b8281526060928302850182019282820191908785111561294a57600080fd5b8387015b8581101561296d57612960898261268f565b845292840192810161294e565b5090979650505050505050565b600060c0828403121561298c57600080fd5b60405160c0810167ffffffffffffffff82821081831117156129b0576129b0612648565b81604052829350843591506129c48261258f565b9082526020840135906129d68261258f565b816020840152604085013591506129ec8261258f565b8160408401526060850135915080821115612a0657600080fd5b50612a1385828601612851565b606083015250612a25608084016125a4565b6080820152612a3660a084016125a4565b60a08201525092915050565b60008060008060008060c08789031215612a5b57600080fd5b863567ffffffffffffffff80821115612a7357600080fd5b612a7f8a838b01612851565b97506020890135915080821115612a9557600080fd5b612aa18a838b01612851565b96506040890135915080821115612ab757600080fd5b612ac38a838b0161290a565b95506060890135915080821115612ad957600080fd5b50612ae689828a0161297a565b935050612af5608088016125a4565b9150612b0360a088016125a4565b90509295509295509295565b60208152600061182e602083018461275b565b60008060408385031215612b3557600080fd5b823567ffffffffffffffff811115612b4c57600080fd5b612b5885828601612851565b92505061275260208401612717565b60008060408385031215612b7a57600080fd5b6125d283612717565b634e487b7160e01b600052602160045260246000fd5b60028110612bb757634e487b7160e01b600052602160045260246000fd5b9052565b602081016106b88284612b99565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b818103818111156106b8576106b8612bdf565b634e487b7160e01b600052603160045260246000fd5b600060018201612c3057612c30612bdf565b5060010190565b6001600160a01b0384168152606060208201526000612c59606083018561275b565b9050826040830152949350505050565b604081526000612c7c604083018561275b565b90508260208301529392505050565b600060208284031215612c9d57600080fd5b5051919050565b600081518084526020808501945080840160005b8381101561279457815187529582019590820190600101612cb8565b60c081526000612ce760c0830189612ca4565b602083820381850152612cfa828a61275b565b91508382036040850152612d0e8289612ca4565b915083820360608501528187518084528284019150828160051b850101838a0160005b83811015612d5f57601f19878403018552612d4d8383516127c3565b94860194925090850190600101612d31565b505060808701989098525050505060a09091019190915250949350505050565b60008060408385031215612d9257600080fd5b8251612d9d8161258f565b602084015190925067ffffffffffffffff80821115612dbb57600080fd5b818501915085601f830112612dcf57600080fd5b815181811115612de157612de1612648565b612df4601f8201601f191660200161265e565b9150808252866020828501011115612e0b57600080fd5b612e1c81602084016020860161279f565b5080925050509250929050565b604081526000612e3c604083018561275b565b8281036020840152611953818561275b565b808201808211156106b8576106b8612bdf565b6001600160a01b038716815285602082015260c060408201526000612e8960c08301876127c3565b606083019590955250608081019290925260a0909101529392505050565b6001600160a01b03831681526040810161182e6020830184612b99565b600060208284031215612ed657600080fd5b8151801515811461182e57600080fd5b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351612f1e81601785016020880161279f565b7f206973206d697373696e6720726f6c65200000000000000000000000000000006017918401918201528351612f5b81602884016020880161279f565b01602801949350505050565b60208152600061182e60208301846127c3565b6000816000190483118215151615612f9457612f94612bdf565b500290565b600081612fa857612fa8612bdf565b50600019019056fea2646970667358221220470c294f844a6607a400ab11f1249e66205e0179bee9c2ccb7f4f10acf83910064736f6c63430008100033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits

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.