ETH Price: $2,816.09 (-4.67%)

Contract

0xc0d3c0D3c0d3c0D3C0D3c0d3c0D3C0D3c3D30000
 

Overview

ETH Balance

0 ETH

ETH Value

$0.00

More Info

Private Name Tags

ContractCreator

N/A (Genesis Contract)

Multichain Info

No addresses found
Transaction Hash
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:

Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Genesis Bytecode Match Only)

Contract Name:
Shares

Compiler Version
v0.8.15+commit.e14f2714

Optimization Enabled:
Yes with 200 runs

Other Settings:
london EvmVersion, None license
// SPDX-License-Identifier: BSL 1.1 - Copyright 2024 MetaLayer Labs Ltd.
pragma solidity 0.8.15;

import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

import { Semver } from "src/universal/Semver.sol";
import { AddressAliasHelper } from "src/vendor/AddressAliasHelper.sol";
import { Predeploys } from "src/libraries/Predeploys.sol";
import { Blast, YieldMode, GasMode } from "src/L2/Blast.sol";

/// @custom:predeploy 0x4300000000000000000000000000000000000000
/// @title SharesBase
/// @notice Base contract to track share rebasing and yield reporting.
abstract contract SharesBase is Initializable {
    /// @notice Approved yield reporter.
    address public immutable REPORTER;

    /// @notice Share price. This value can only increase.
    uint256 public price;

    /// @notice Accumulated yield that has not been distributed
    ///         to the share price.
    uint256 public pending;

    /// @notice Reserve extra slots (to a total of 50) in the storage layout for future upgrades.
    ///         A gap size of 48 was chosen here, so that the first slot used in a child contract
    ///         would be a multiple of 50.
    uint256[48] private __gap;

    /// @notice Emitted when a new share price is set after a yield event.
    event NewPrice(uint256 price);

    error InvalidReporter();
    error DistributeFailed(uint256 count, uint256 pending);
    error PriceIsInitialized();

    /// @param _reporter Address of the approved yield reporter.
    constructor(address _reporter) {
        REPORTER = _reporter;
    }

    /// @notice Initializer.
    /// @param _price Initial share price.
    // solhint-disable-next-line func-name-mixedcase
    function __SharesBase_init(uint256 _price) internal onlyInitializing {
        if (price != 0) {
            revert PriceIsInitialized();
        }
        price = _price;
    }

    /// @notice Get the total number of shares. Needs to be
    ///         overridden by the child contract.
    /// @return Total number of shares.
    function count() public view virtual returns (uint256);

    /// @notice Report a yield event and update the share price.
    /// @param value Amount of new yield
    function addValue(uint256 value) external {
        _addValue(value);
    }

    function _addValue(uint256 value) internal virtual {
        if (AddressAliasHelper.undoL1ToL2Alias(msg.sender) != REPORTER) {
            revert InvalidReporter();
        }

        if (value > 0) {
            pending += value;
        }

        _tryDistributePending();
    }

    /// @notice Attempt to distribute pending yields if there
    ///         are sufficient pending yields to increase the
    ///         share price.
    /// @return True if there were sufficient pending yields to
    ///         increase the share price.
    function _tryDistributePending() internal returns (bool) {
        if (pending < count() || count() == 0) {
            return false;
        }

        price += pending / count();
        pending = pending % count();

        emit NewPrice(price);

        return true;
    }
}

/// @custom:predeploy 0x4300000000000000000000000000000000000000
/// @title Shares
/// @notice Integrated EVM contract to manage native ether share
///         rebasing from yield reports.
contract Shares is SharesBase, Semver {
    /// @notice Total number of shares. This value is modified directly
    ///         by the sequencer EVM.
    uint256 private _count;

    /// @notice _reporter Address of approved yield reporter.
    constructor(address _reporter) SharesBase(_reporter) Semver(1, 0, 0) {
        _disableInitializers();
    }

    /// @notice Initializer.
    function initialize(uint256 _price) public initializer {
        __SharesBase_init({ _price: _price });
        Blast(Predeploys.BLAST).configureContract(
            address(this),
            YieldMode.VOID,
            GasMode.VOID,
            address(0xdead) /// don't set a governor
        );
    }

    /// @inheritdoc SharesBase
    function count() public view override returns (uint256) {
        return _count;
    }

    function _addValue(uint256 value) internal override {
        super._addValue(value);

        SharesBase(Predeploys.WETH_REBASING).addValue(value);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.2;

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

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

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

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

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

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

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

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

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

    /**
     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
     */
    function _isInitializing() internal view returns (bool) {
        return _initializing;
    }
}

File 3 of 12 : Semver.sol
// SPDX-License-Identifier: BSL 1.1 - Copyright 2024 MetaLayer Labs Ltd.
pragma solidity ^0.8.0;

import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";

/// @title Semver
/// @notice Semver is a simple contract for managing contract versions.
contract Semver {
    /// @notice Contract version number (major).
    uint256 private immutable MAJOR_VERSION;

    /// @notice Contract version number (minor).
    uint256 private immutable MINOR_VERSION;

    /// @notice Contract version number (patch).
    uint256 private immutable PATCH_VERSION;

    /// @param _major Version number (major).
    /// @param _minor Version number (minor).
    /// @param _patch Version number (patch).
    constructor(uint256 _major, uint256 _minor, uint256 _patch) {
        MAJOR_VERSION = _major;
        MINOR_VERSION = _minor;
        PATCH_VERSION = _patch;
    }

    /// @notice Returns the full semver contract version.
    /// @return Semver contract version as a string.
    function version() public view returns (string memory) {
        return string(
            abi.encodePacked(
                Strings.toString(MAJOR_VERSION),
                ".",
                Strings.toString(MINOR_VERSION),
                ".",
                Strings.toString(PATCH_VERSION)
            )
        );
    }
}

// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2019-2021, 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.0;

library AddressAliasHelper {
    uint160 constant offset = uint160(0x1111000000000000000000000000000000001111);

    /// @notice Utility function that converts the address in the L1 that submitted a tx to
    /// the inbox to the msg.sender viewed in the L2
    /// @param l1Address the address in the L1 that triggered the tx to L2
    /// @return l2Address L2 address as viewed in msg.sender
    function applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {
        unchecked {
            l2Address = address(uint160(l1Address) + offset);
        }
    }

    /// @notice Utility function that converts the msg.sender viewed in the L2 to the
    /// address in the L1 that submitted a tx to the inbox
    /// @param l2Address L2 address as viewed in msg.sender
    /// @return l1Address the address in the L1 that triggered the tx to L2
    function undoL1ToL2Alias(address l2Address) internal pure returns (address l1Address) {
        unchecked {
            l1Address = address(uint160(l2Address) - offset);
        }
    }
}

File 5 of 12 : Predeploys.sol
// SPDX-License-Identifier: BSL 1.1 - Copyright 2024 MetaLayer Labs Ltd.
pragma solidity ^0.8.0;

/// @title Predeploys
/// @notice Contains constant addresses for contracts that are pre-deployed to the L2 system.
library Predeploys {
    /// @notice Address of the L2ToL1MessagePasser predeploy.
    address internal constant L2_TO_L1_MESSAGE_PASSER = 0x4200000000000000000000000000000000000016;

    /// @notice Address of the L2CrossDomainMessenger predeploy.
    address internal constant L2_CROSS_DOMAIN_MESSENGER = 0x4200000000000000000000000000000000000007;

    /// @notice Address of the L2StandardBridge predeploy.
    address internal constant L2_STANDARD_BRIDGE = 0x4200000000000000000000000000000000000010;

    /// @notice Address of the L2ERC721Bridge predeploy.
    address internal constant L2_ERC721_BRIDGE = 0x4200000000000000000000000000000000000014;

    //// @notice Address of the SequencerFeeWallet predeploy.
    address internal constant SEQUENCER_FEE_WALLET = 0x4200000000000000000000000000000000000011;

    /// @notice Address of the OptimismMintableERC20Factory predeploy.
    address internal constant OPTIMISM_MINTABLE_ERC20_FACTORY = 0x4200000000000000000000000000000000000012;

    /// @notice Address of the OptimismMintableERC721Factory predeploy.
    address internal constant OPTIMISM_MINTABLE_ERC721_FACTORY = 0x4200000000000000000000000000000000000017;

    /// @notice Address of the L1Block predeploy.
    address internal constant L1_BLOCK_ATTRIBUTES = 0x4200000000000000000000000000000000000015;

    /// @notice Address of the GasPriceOracle predeploy. Includes fee information
    ///         and helpers for computing the L1 portion of the transaction fee.
    address internal constant GAS_PRICE_ORACLE = 0x420000000000000000000000000000000000000F;

    /// @custom:legacy
    /// @notice Address of the L1MessageSender predeploy. Deprecated. Use L2CrossDomainMessenger
    ///         or access tx.origin (or msg.sender) in a L1 to L2 transaction instead.
    address internal constant L1_MESSAGE_SENDER = 0x4200000000000000000000000000000000000001;

    /// @custom:legacy
    /// @notice Address of the DeployerWhitelist predeploy. No longer active.
    address internal constant DEPLOYER_WHITELIST = 0x4200000000000000000000000000000000000002;

    /// @custom:legacy
    /// @notice Address of the LegacyERC20ETH predeploy. Deprecated. Balances are migrated to the
    ///         state trie as of the Bedrock upgrade. Contract has been locked and write functions
    ///         can no longer be accessed.
    address internal constant LEGACY_ERC20_ETH = 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000;

    /// @custom:legacy
    /// @notice Address of the L1BlockNumber predeploy. Deprecated. Use the L1Block predeploy
    ///         instead, which exposes more information about the L1 state.
    address internal constant L1_BLOCK_NUMBER = 0x4200000000000000000000000000000000000013;

    /// @custom:legacy
    /// @notice Address of the LegacyMessagePasser predeploy. Deprecate. Use the updated
    ///         L2ToL1MessagePasser contract instead.
    address internal constant LEGACY_MESSAGE_PASSER = 0x4200000000000000000000000000000000000000;

    /// @notice Address of the ProxyAdmin predeploy.
    address internal constant PROXY_ADMIN = 0x4200000000000000000000000000000000000018;

    /// @notice Address of the BaseFeeVault predeploy.
    address internal constant BASE_FEE_VAULT = 0x4200000000000000000000000000000000000019;

    /// @notice Address of the L1FeeVault predeploy.
    address internal constant L1_FEE_VAULT = 0x420000000000000000000000000000000000001A;

    /// @notice Address of the GovernanceToken predeploy.
    address internal constant GOVERNANCE_TOKEN = 0x4200000000000000000000000000000000000042;

    /// @notice Address of the SchemaRegistry predeploy.
    address internal constant SCHEMA_REGISTRY = 0x4200000000000000000000000000000000000020;

    /// @notice Address of the EAS predeploy.
    address internal constant EAS = 0x4200000000000000000000000000000000000021;

    /// @notice Address of the Shares predeploy.
    address internal constant SHARES = 0x4300000000000000000000000000000000000000;

    /// @notice Address of the Gas predeploy.
    address internal constant GAS = 0x4300000000000000000000000000000000000001;

    /// @notice Address of the Blast predeploy.
    address internal constant BLAST = 0x4300000000000000000000000000000000000002;

    /// @notice Address of the USDB predeploy.
    address internal constant USDB = 0x4300000000000000000000000000000000000003;

    /// @notice Address of the WETH predeploy.
    address internal constant WETH_REBASING = 0x4300000000000000000000000000000000000004;

    /// @notice Address of the L2BlastBridge predeploy.
    address internal constant L2_BLAST_BRIDGE = 0x4300000000000000000000000000000000000005;
}

File 6 of 12 : Blast.sol
// SPDX-License-Identifier: BSL 1.1 - Copyright 2024 MetaLayer Labs Ltd.
pragma solidity 0.8.15;

import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

import { Semver } from "src/universal/Semver.sol";
import { GasMode, IGas } from "src/L2/Gas.sol";

enum YieldMode {
    AUTOMATIC,
    VOID,
    CLAIMABLE
}

interface IYield {
    function configure(address contractAddress, uint8 flags) external returns (uint256);
    function claim(address contractAddress, address recipientOfYield, uint256 desiredAmount) external returns (uint256);
    function getClaimableAmount(address contractAddress) external view returns (uint256);
    function getConfiguration(address contractAddress) external view returns (uint8);
}

interface IBlast{
    // configure
    function configureContract(address contractAddress, YieldMode _yield, GasMode gasMode, address governor) external;
    function configure(YieldMode _yield, GasMode gasMode, address governor) external;

    // base configuration options
    function configureClaimableYield() external;
    function configureClaimableYieldOnBehalf(address contractAddress) external;
    function configureAutomaticYield() external;
    function configureAutomaticYieldOnBehalf(address contractAddress) external;
    function configureVoidYield() external;
    function configureVoidYieldOnBehalf(address contractAddress) external;
    function configureClaimableGas() external;
    function configureClaimableGasOnBehalf(address contractAddress) external;
    function configureVoidGas() external;
    function configureVoidGasOnBehalf(address contractAddress) external;
    function configureGovernor(address _governor) external;
    function configureGovernorOnBehalf(address _newGovernor, address contractAddress) external;

    // claim yield
    function claimYield(address contractAddress, address recipientOfYield, uint256 amount) external returns (uint256);
    function claimAllYield(address contractAddress, address recipientOfYield) external returns (uint256);

    // claim gas
    function claimAllGas(address contractAddress, address recipientOfGas) external returns (uint256);
    // NOTE: can be off by 1 bip
    function claimGasAtMinClaimRate(address contractAddress, address recipientOfGas, uint256 minClaimRateBips) external returns (uint256);
    function claimMaxGas(address contractAddress, address recipientOfGas) external returns (uint256);
    function claimGas(address contractAddress, address recipientOfGas, uint256 gasToClaim, uint256 gasSecondsToConsume) external returns (uint256);

    // read functions
    function readClaimableYield(address contractAddress) external view returns (uint256);
    function readYieldConfiguration(address contractAddress) external view returns (uint8);
    function readGasParams(address contractAddress) external view returns (uint256 etherSeconds, uint256 etherBalance, uint256 lastUpdated, GasMode);
}

/// @custom:predeploy 0x4300000000000000000000000000000000000002
/// @title Blast
contract Blast is IBlast, Initializable, Semver {
    address public immutable YIELD_CONTRACT;
    address public immutable GAS_CONTRACT;

    mapping(address => address) public governorMap;

    constructor(address _gasContract, address _yieldContract) Semver(1, 0, 0) {
        GAS_CONTRACT = _gasContract;
        YIELD_CONTRACT = _yieldContract;
        _disableInitializers();
    }

    function initialize() public initializer {}

    /**
     * @notice Checks if the caller is the governor of the contract
     * @param contractAddress The address of the contract
     * @return A boolean indicating if the caller is the governor
     */
    function isGovernor(address contractAddress) public view returns (bool) {
        return msg.sender == governorMap[contractAddress];
    }
    /**
     * @notice Checks if the governor is not set for the contract
     * @param contractAddress The address of the contract
     * @return boolean indicating if the governor is not set
     */
    function governorNotSet(address contractAddress) internal view returns (bool) {
        return governorMap[contractAddress] == address(0);
    }
    /**
     * @notice Checks if the caller is authorized
     * @param contractAddress The address of the contract
     * @return A boolean indicating if the caller is authorized
     */
    function isAuthorized(address contractAddress) public view returns (bool) {
        return isGovernor(contractAddress) || (governorNotSet(contractAddress) && msg.sender == contractAddress);
    }

    /**
     * @notice contract configures its yield and gas modes and sets the governor. called by contract
     * @param _yieldMode The yield mode to be set
     * @param _gasMode The gas mode to be set
     * @param governor The address of the governor to be set
     */
    function configure(YieldMode _yieldMode, GasMode _gasMode, address governor) external {
        // requires that no governor is set for contract
        require(isAuthorized(msg.sender), "not authorized to configure contract");
        // set governor
        governorMap[msg.sender] = governor;
        // set gas mode
        IGas(GAS_CONTRACT).setGasMode(msg.sender, _gasMode);
        // set yield mode
        IYield(YIELD_CONTRACT).configure(msg.sender, uint8(_yieldMode));
    }

    /**
     * @notice Configures the yield and gas modes and sets the governor for a specific contract. called by authorized user
     * @param contractAddress The address of the contract to be configured
     * @param _yieldMode The yield mode to be set
     * @param _gasMode The gas mode to be set
     * @param _newGovernor The address of the new governor to be set
     */
    function configureContract(address contractAddress, YieldMode _yieldMode, GasMode _gasMode, address _newGovernor) external {
        // only allow governor, or if no governor is set, the contract itself to configure
        require(isAuthorized(contractAddress), "not authorized to configure contract");
        // set governor
        governorMap[contractAddress] = _newGovernor;
        // set gas mode
        IGas(GAS_CONTRACT).setGasMode(contractAddress, _gasMode);
        // set yield mode
        IYield(YIELD_CONTRACT).configure(contractAddress, uint8(_yieldMode));
    }

    /**
     * @notice Configures the yield mode to CLAIMABLE for the contract that calls this function
     */
    function configureClaimableYield() external {
        require(isAuthorized(msg.sender), "not authorized to configure contract");
        IYield(YIELD_CONTRACT).configure(msg.sender, uint8(YieldMode.CLAIMABLE));
    }

    /**
     * @notice Configures the yield mode to CLAIMABLE for a specific contract. Called by an authorized user
     * @param contractAddress The address of the contract to be configured
     */
    function configureClaimableYieldOnBehalf(address contractAddress) external {
        require(isAuthorized(contractAddress), "not authorized to configure contract");
        IYield(YIELD_CONTRACT).configure(contractAddress, uint8(YieldMode.CLAIMABLE));
    }

    /**
     * @notice Configures the yield mode to AUTOMATIC for the contract that calls this function
     */
    function configureAutomaticYield() external {
        require(isAuthorized(msg.sender), "not authorized to configure contract");
        IYield(YIELD_CONTRACT).configure(msg.sender, uint8(YieldMode.AUTOMATIC));
    }

    /**
     * @notice Configures the yield mode to AUTOMATIC for a specific contract. Called by an authorized user
     * @param contractAddress The address of the contract to be configured
     */
    function configureAutomaticYieldOnBehalf(address contractAddress) external {
        require(isAuthorized(contractAddress), "not authorized to configure contract");
        IYield(YIELD_CONTRACT).configure(contractAddress, uint8(YieldMode.AUTOMATIC));
    }

    /**
     * @notice Configures the yield mode to VOID for the contract that calls this function
     */
    function configureVoidYield() external {
        require(isAuthorized(msg.sender), "not authorized to configure contract");
        IYield(YIELD_CONTRACT).configure(msg.sender, uint8(YieldMode.VOID));
    }

    /**
     * @notice Configures the yield mode to VOID for a specific contract. Called by an authorized user
     * @param contractAddress The address of the contract to be configured
     */
    function configureVoidYieldOnBehalf(address contractAddress) external {
        require(isAuthorized(contractAddress), "not authorized to configure contract");
        IYield(YIELD_CONTRACT).configure(contractAddress, uint8(YieldMode.VOID));
    }

    /**
     * @notice Configures the gas mode to CLAIMABLE for the contract that calls this function
     */
    function configureClaimableGas() external {
        require(isAuthorized(msg.sender), "not authorized to configure contract");
        IGas(GAS_CONTRACT).setGasMode(msg.sender, GasMode.CLAIMABLE);
    }

    /**
     * @notice Configures the gas mode to CLAIMABLE for a specific contract. Called by an authorized user
     * @param contractAddress The address of the contract to be configured
     */
    function configureClaimableGasOnBehalf(address contractAddress) external {
        require(isAuthorized(contractAddress), "not authorized to configure contract");
        IGas(GAS_CONTRACT).setGasMode(contractAddress, GasMode.CLAIMABLE);
    }

    /**
     * @notice Configures the gas mode to VOID for the contract that calls this function
     */
    function configureVoidGas() external {
        require(isAuthorized(msg.sender), "not authorized to configure contract");
        IGas(GAS_CONTRACT).setGasMode(msg.sender, GasMode.VOID);
    }

    /**
     * @notice Configures the gas mode to void for a specific contract. Called by an authorized user
     * @param contractAddress The address of the contract to be configured
     */
    function configureVoidGasOnBehalf(address contractAddress) external {
        require(isAuthorized(contractAddress), "not authorized to configure contract");
        IGas(GAS_CONTRACT).setGasMode(contractAddress, GasMode.VOID);
    }

    /**
     * @notice Configures the governor for the contract that calls this function
     */
    function configureGovernor(address _governor) external {
        require(isAuthorized(msg.sender), "not authorized to configure contract");
        governorMap[msg.sender] = _governor;
    }

    /**
     * @notice Configures the governor for a specific contract. Called by an authorized user
     * @param contractAddress The address of the contract to be configured
     */
    function configureGovernorOnBehalf(address _newGovernor, address contractAddress) external {
        require(isAuthorized(contractAddress), "not authorized to configure contract");
        governorMap[contractAddress] = _newGovernor;
    }


    // claim methods

    /**
     * @notice Claims yield for a specific contract. Called by an authorized user
     * @param contractAddress The address of the contract for which yield is to be claimed
     * @param recipientOfYield The address of the recipient of the yield
     * @param amount The amount of yield to be claimed
     * @return The amount of yield that was claimed
     */
    function claimYield(address contractAddress, address recipientOfYield, uint256 amount) external returns (uint256) {
        require(isAuthorized(contractAddress), "Not authorized to claim yield");
        return  IYield(YIELD_CONTRACT).claim(contractAddress, recipientOfYield, amount);
    }
    /**
     * @notice Claims all yield for a specific contract. Called by an authorized user
     * @param contractAddress The address of the contract for which all yield is to be claimed
     * @param recipientOfYield The address of the recipient of the yield
     * @return The amount of yield that was claimed
     */
    function claimAllYield(address contractAddress, address recipientOfYield) external returns (uint256) {
        require(isAuthorized(contractAddress), "Not authorized to claim yield");
        uint256 amount = IYield(YIELD_CONTRACT).getClaimableAmount(contractAddress);
        return  IYield(YIELD_CONTRACT).claim(contractAddress, recipientOfYield, amount);
    }

    /**
     * @notice Claims all gas for a specific contract. Called by an authorized user
     * @param contractAddress The address of the contract for which all gas is to be claimed
     * @param recipientOfGas The address of the recipient of the gas
     * @return The amount of gas that was claimed
     */
    function claimAllGas(address contractAddress, address recipientOfGas) external returns (uint256) {
        require(isAuthorized(contractAddress), "Not allowed to claim all gas");
        return IGas(GAS_CONTRACT).claimAll(contractAddress, recipientOfGas);
    }

    /**
     * @notice Claims gas at a minimum claim rate for a specific contract, with error rate '1'. Called by an authorized user
     * @param contractAddress The address of the contract for which gas is to be claimed
     * @param recipientOfGas The address of the recipient of the gas
     * @param minClaimRateBips The minimum claim rate in basis points
     * @return The amount of gas that was claimed
     */
    function claimGasAtMinClaimRate(address contractAddress, address recipientOfGas, uint256 minClaimRateBips) external returns (uint256) {
        require(isAuthorized(contractAddress), "Not allowed to claim gas at min claim rate");
        return IGas(GAS_CONTRACT).claimGasAtMinClaimRate(contractAddress, recipientOfGas, minClaimRateBips);
    }

    /**
     * @notice Claims gas available to be claimed at max claim rate for a specific contract. Called by an authorized user
     * @param contractAddress The address of the contract for which maximum gas is to be claimed
     * @param recipientOfGas The address of the recipient of the gas
     * @return The amount of gas that was claimed
     */
    function claimMaxGas(address contractAddress, address recipientOfGas) external returns (uint256) {
        require(isAuthorized(contractAddress), "Not allowed to claim max gas");
        return IGas(GAS_CONTRACT).claimMax(contractAddress, recipientOfGas);
    }
    /**
     * @notice Claims a specific amount of gas for a specific contract. claim rate governed by integral of gas over time
     * @param contractAddress The address of the contract for which gas is to be claimed
     * @param recipientOfGas The address of the recipient of the gas
     * @param gasToClaim The amount of gas to be claimed
     * @param gasSecondsToConsume The amount of gas seconds to consume
     * @return The amount of gas that was claimed
     */
    function claimGas(address contractAddress, address recipientOfGas, uint256 gasToClaim, uint256 gasSecondsToConsume) external returns (uint256) {
        require(isAuthorized(contractAddress), "Not allowed to claim gas");
        return IGas(GAS_CONTRACT).claim(contractAddress, recipientOfGas, gasToClaim, gasSecondsToConsume);
    }

    /**
     * @notice Reads the claimable yield for a specific contract
     * @param contractAddress The address of the contract for which the claimable yield is to be read
     * @return claimable yield
     */
    function readClaimableYield(address contractAddress) public view returns (uint256) {
        return IYield(YIELD_CONTRACT).getClaimableAmount(contractAddress);
    }
    /**
     * @notice Reads the yield configuration for a specific contract
     * @param contractAddress The address of the contract for which the yield configuration is to be read
     * @return uint8 representing yield enum
     */

    function readYieldConfiguration(address contractAddress) public view returns (uint8) {
        return IYield(YIELD_CONTRACT).getConfiguration(contractAddress);
    }
    /**
     * @notice Reads the gas parameters for a specific contract
     * @param contractAddress The address of the contract for which the gas parameters are to be read
     * @return uint256 representing the accumulated ether seconds
     * @return uint256 representing ether balance
     * @return uint256 representing last update timestamp
     * @return GasMode representing the gas mode (VOID, CLAIMABLE)
     */
    function readGasParams(address contractAddress) public view returns (uint256, uint256, uint256, GasMode) {
        return IGas(GAS_CONTRACT).readGasParams(contractAddress);
    }
}

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

pragma solidity ^0.8.1;

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

        return account.code.length > 0;
    }

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

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

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

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

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

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

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

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

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

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

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

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

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}

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

pragma solidity ^0.8.0;

/**
 * @dev String operations.
 */
library Strings {
    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: BSL 1.1 - Copyright 2024 MetaLayer Labs Ltd.
pragma solidity 0.8.15;

import { SafeTransferLib } from "solmate/utils/SafeTransferLib.sol";
import { Math } from "@openzeppelin/contracts/utils/math/Math.sol";
import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

import { Semver } from "src/universal/Semver.sol";

enum GasMode {
    VOID,
    CLAIMABLE
}

interface IGas {
    function readGasParams(address contractAddress) external view returns (uint256, uint256, uint256, GasMode);
    function setGasMode(address contractAddress, GasMode mode) external;
    function claimGasAtMinClaimRate(address contractAddress, address recipient, uint256 minClaimRateBips) external returns (uint256);
    function claimAll(address contractAddress, address recipient) external returns (uint256);
    function claimMax(address contractAddress, address recipient) external returns (uint256);
    function claim(address contractAddress, address recipient, uint256 gasToClaim, uint256 gasSecondsToConsume) external returns (uint256);
}

/// @custom:predeploy 0x4300000000000000000000000000000000000001
/// @title Gas
contract Gas is IGas, Initializable, Semver {
    address public immutable admin;

    // Blast.sol --> controls all dAPP accesses to Gas.sol
    address public immutable blastConfigurationContract;

    // BaseFeeVault.sol -> fees from gas claims directed here
    address public immutable blastFeeVault;

    // zero claim rate in bps -> percent of gas user is able to claim
    // without consuming any gas seconds
    uint256 public zeroClaimRate; // bps

    // base claim rate in bps -> percent of gas user is able to claim
    // by consuming base gas seconds
    uint256 public baseGasSeconds;
    uint256 public baseClaimRate; // bps

    // ceil claim rate in bps -> percent of gas user is able to claim
    // by consuming ceil gas seconds or more
    uint256 public ceilGasSeconds;
    uint256 public ceilClaimRate; // bps

    /**
     * @notice Constructs the blast gas contract.
     * @param _admin The address of the admin.
     * @param _blastConfigurationContract The address of the Blast configuration contract.
     * @param _blastFeeVault The address of the Blast fee vault.
    */
    constructor (
        address _admin,
        address _blastConfigurationContract,
        address _blastFeeVault
    ) Semver(1, 0, 0) {
        admin =  _admin;
        blastConfigurationContract = _blastConfigurationContract;
        blastFeeVault = _blastFeeVault;
        _disableInitializers();
    }

    /**
     * @notice Initializer.
     * @param _zeroClaimRate The zero claim rate.
     * @param _baseGasSeconds The base gas seconds.
     * @param _baseClaimRate The base claim rate.
     * @param _ceilGasSeconds The ceiling gas seconds.
     * @param _ceilClaimRate The ceiling claim rate.
     */
    function initialize(
        uint256 _zeroClaimRate,
        uint256 _baseGasSeconds,
        uint256 _baseClaimRate,
        uint256 _ceilGasSeconds,
        uint256 _ceilClaimRate
    ) public initializer {
        require(_zeroClaimRate < _baseClaimRate, "zero claim rate must be < base claim rate");
        require(_baseClaimRate < _ceilClaimRate, "base claim rate must be < ceil claim rate");
        require(_baseGasSeconds < _ceilGasSeconds, "base gas seconds must be < ceil gas seconds");
        require(_baseGasSeconds > 0, "base gas seconds must be > 0");
        require(_ceilClaimRate <= 10000, "ceil claim rate must be less than or equal to 10_000 bips");
        // admin vars
        zeroClaimRate = _zeroClaimRate;
        baseGasSeconds = _baseGasSeconds;
        baseClaimRate = _baseClaimRate;
        ceilGasSeconds = _ceilGasSeconds;
        ceilClaimRate = _ceilClaimRate;
    }

    /**
     * @notice Allows only the admin to call a function
     */
    modifier onlyAdmin() {
        require(msg.sender == admin, "Caller is not the admin");
        _;
    }
    /**
     * @notice Allows only the Blast Configuration Contract to call a function
     */
    modifier onlyBlastConfigurationContract() {
        require(msg.sender == blastConfigurationContract, "Caller must be blast configuration contract");
        _;
    }

    /**
     * @notice Allows the admin to update the parameters
     * @param _zeroClaimRate The new zero claim rate
     * @param _baseGasSeconds The new base gas seconds
     * @param _baseClaimRate The new base claim rate
     * @param _ceilGasSeconds The new ceiling gas seconds
     * @param _ceilClaimRate The new ceiling claim rate
     */
    function updateAdminParameters(
        uint256 _zeroClaimRate,
        uint256 _baseGasSeconds,
        uint256 _baseClaimRate,
        uint256 _ceilGasSeconds,
        uint256 _ceilClaimRate
    ) external onlyAdmin {
        require(_zeroClaimRate < _baseClaimRate, "zero claim rate must be < base claim rate");
        require(_baseClaimRate < _ceilClaimRate, "base claim rate must be < ceil claim rate");
        require(_baseGasSeconds < _ceilGasSeconds, "base gas seconds must be < ceil gas seconds");
        require(_baseGasSeconds > 0, "base gas seconds must be > 0");
        require(_ceilClaimRate <= 10000, "ceil claim rate must be less than or equal to 10_000 bips");

        zeroClaimRate = _zeroClaimRate;
        baseGasSeconds = _baseGasSeconds;
        baseClaimRate = _baseClaimRate;
        ceilGasSeconds = _ceilGasSeconds;
        ceilClaimRate = _ceilClaimRate;
    }

    /**
     * @notice Allows the admin to claim the gas of any address
     * @param contractAddress The address of the contract
     * @return The amount of ether balance claimed
     */
    function adminClaimGas(address contractAddress) external onlyAdmin returns (uint256) {
        (, uint256 etherBalance,,) = readGasParams(contractAddress);
        _updateGasParams(contractAddress, 0, 0, GasMode.VOID);
        SafeTransferLib.safeTransferETH(blastFeeVault, etherBalance);
        return etherBalance;
    }
    /**
     * @notice Allows an authorized user to set the gas mode for a contract via the BlastConfigurationContract
     * @param contractAddress The address of the contract
     * @param mode The new gas mode for the contract
     */
    function setGasMode(address contractAddress, GasMode mode) external onlyBlastConfigurationContract {
        // retrieve gas params
        (uint256 etherSeconds, uint256 etherBalance,,) = readGasParams(contractAddress);
        _updateGasParams(contractAddress, etherSeconds, etherBalance, mode);
    }

    /**
     * @notice Allows a user to claim gas at a minimum claim rate (error = 1 bip)
     * @param contractAddress The address of the contract
     * @param recipientOfGas The address of the recipient of the gas
     * @param minClaimRateBips The minimum claim rate in basis points
     * @return The amount of gas claimed
     */
    function claimGasAtMinClaimRate(address contractAddress, address recipientOfGas, uint256 minClaimRateBips) public returns (uint256) {
        require(minClaimRateBips <= ceilClaimRate, "desired claim rate exceeds maximum");

        (uint256 etherSeconds, uint256 etherBalance,,) = readGasParams(contractAddress);
        if (minClaimRateBips <= zeroClaimRate) {
            return claimAll(contractAddress, recipientOfGas);
        }

        // set minClaimRate to baseClaimRate in this case
        if (minClaimRateBips < baseClaimRate) {
            minClaimRateBips = baseClaimRate;
        }

        uint256 bipsDiff = minClaimRateBips - baseClaimRate;
        uint256 secondsDiff = ceilGasSeconds - baseGasSeconds;
        uint256 rateDiff = ceilClaimRate - baseClaimRate;
        uint256 minSecondsStaked = baseGasSeconds + Math.ceilDiv(bipsDiff * secondsDiff, rateDiff);
        uint256 maxEtherClaimable = etherSeconds / minSecondsStaked;
        if (maxEtherClaimable > etherBalance)  {
            maxEtherClaimable = etherBalance;
        }
        uint256 secondsToConsume = maxEtherClaimable * minSecondsStaked;
        return claim(contractAddress, recipientOfGas, maxEtherClaimable, secondsToConsume);
    }

    /**
     * @notice Allows a contract to claim all gas
     * @param contractAddress The address of the contract
     * @param recipientOfGas The address of the recipient of the gas
     * @return The amount of gas claimed
     */
    function claimAll(address contractAddress, address recipientOfGas) public returns (uint256) {
        (uint256 etherSeconds, uint256 etherBalance,,) = readGasParams(contractAddress);
        return claim(contractAddress, recipientOfGas, etherBalance, etherSeconds);
    }

    /**
     * @notice Allows a contract to claim all gas at the highest possible claim rate
     * @param contractAddress The address of the contract
     * @param recipientOfGas The address of the recipient of the gas
     * @return The amount of gas claimed
     */
    function claimMax(address contractAddress, address recipientOfGas) public returns (uint256) {
        return claimGasAtMinClaimRate(contractAddress, recipientOfGas, ceilClaimRate);
    }
    /**
     * @notice Allows a contract to claim a specified amount of gas, at a claim rate set by the number of gas seconds
     * @param contractAddress The address of the contract
     * @param recipientOfGas The address of the recipient of the gas
     * @param gasToClaim The amount of gas to claim
     * @param gasSecondsToConsume The amount of gas seconds to consume
     * @return The amount of gas claimed (gasToClaim - penalty)
     */

    function claim(address contractAddress, address recipientOfGas, uint256 gasToClaim, uint256 gasSecondsToConsume) public onlyBlastConfigurationContract() returns (uint256)  {
        // retrieve gas params
        (uint256 etherSeconds, uint256 etherBalance,, GasMode mode) = readGasParams(contractAddress);

        // check validity requirements
        require(gasToClaim > 0, "must withdraw non-zero amount");
        require(gasToClaim <= etherBalance, "too much to withdraw");
        require(gasSecondsToConsume <= etherSeconds, "not enough gas seconds");

        // get claim rate
        (uint256 claimRate, uint256 gasSecondsToConsumeNormalized) = getClaimRateBps(gasSecondsToConsume, gasToClaim);

        // calculate tax
        uint256 userEther = gasToClaim * claimRate / 10_000;
        uint256 penalty = gasToClaim - userEther;

        _updateGasParams(contractAddress, etherSeconds - gasSecondsToConsumeNormalized, etherBalance - gasToClaim, mode);

        SafeTransferLib.safeTransferETH(recipientOfGas, userEther);
        if (penalty > 0) {
            SafeTransferLib.safeTransferETH(blastFeeVault, penalty);
        }

        return userEther;
    }
    /**
     * @notice Calculates the claim rate in basis points based on gasSeconds, gasToClaim
     * @param gasSecondsToConsume The amount of gas seconds to consume
     * @param gasToClaim The amount of gas to claim
     * @return claimRate The calculated claim rate in basis points
     * @return gasSecondsToConsume The normalized gas seconds to consume (<= gasSecondsToConsume)
     */
    function getClaimRateBps(uint256 gasSecondsToConsume, uint256 gasToClaim) public view returns (uint256, uint256) {
        uint256 secondsStaked = gasSecondsToConsume / gasToClaim;
        if (secondsStaked < baseGasSeconds) {
            return (zeroClaimRate, 0);
        }
        if (secondsStaked >= ceilGasSeconds) {
            uint256 gasToConsumeNormalized = gasToClaim * ceilGasSeconds;
            return (ceilClaimRate, gasToConsumeNormalized);
        }

        uint256 rateDiff = ceilClaimRate - baseClaimRate;
        uint256 secondsDiff = ceilGasSeconds - baseGasSeconds;
        uint256 secondsStakedDiff = secondsStaked - baseGasSeconds;
        uint256 additionalClaimRate = rateDiff * secondsStakedDiff / secondsDiff;
        uint256 claimRate = baseClaimRate + additionalClaimRate;
        return (claimRate, gasSecondsToConsume);
    }

    /**
     * @notice Reads the gas parameters for a given user
     * @param user The address of the user
     * @return etherSeconds The integral of ether over time (ether * seconds vested)
     * @return etherBalance The total ether balance for the user
     * @return lastUpdated The last updated timestamp for the user's gas parameters
     * @return mode The current gas mode for the user
     */
     function readGasParams(address user) public view returns (uint256 etherSeconds, uint256 etherBalance, uint256 lastUpdated, GasMode mode) {
        bytes32 paramsHash = keccak256(abi.encodePacked(user, "parameters"));
        bytes32 packedParams;
        // read params
        assembly {
            packedParams := sload(paramsHash)
        }

        // unpack params
        // - The first byte (most significant byte) represents the mode
        // - The next 12 bytes represent the etherBalance
        // - The following 15 bytes represent the etherSeconds
        // - The last 4 bytes (least significant bytes) represent the lastUpdated timestamp
        mode         = GasMode(uint8(packedParams[0]));
        etherBalance = uint256((packedParams << (1             * 8)) >> ((32 - 12) * 8));
        etherSeconds = uint256((packedParams << ((1 + 12)      * 8)) >> ((32 - 15) * 8));
        lastUpdated  = uint256((packedParams << ((1 + 12 + 15) * 8)) >> ((32 -  4) * 8));

        // update ether seconds
        etherSeconds = etherSeconds + etherBalance * (block.timestamp - lastUpdated);
    }

    /**
     * @notice Updates the gas parameters for a given contract address
     * @param contractAddress The address of the contract
     * @param etherSeconds The integral of ether over time (ether * seconds vested)
     * @param etherBalance The total ether balance for the contract
     */
    function _updateGasParams(address contractAddress, uint256 etherSeconds, uint256 etherBalance, GasMode mode) internal {
        if (
            etherBalance >= 1 << (12 * 8) ||
            etherSeconds >= 1 << (15 * 8)
        ) {
            revert("Unexpected packing issue due to overflow");
        }

        uint256 updatedTimestamp = block.timestamp; // Known to fit in 4 bytes

        bytes32 paramsHash = keccak256(abi.encodePacked(contractAddress, "parameters"));
        bytes32 packedParams;
        packedParams = (
            (bytes32(uint256(mode)) << ((12 + 15 + 4) * 8)) | // Shift mode to the most significant byte
            (bytes32(etherBalance)  << ((15 + 4) * 8))      | // Shift etherBalance to start after 1 byte of mode
            (bytes32(etherSeconds)  << (4 * 8))             | // Shift etherSeconds to start after mode and etherBalance
            bytes32(updatedTimestamp)                         // Keep updatedTimestamp in the least significant bytes
        );

        assembly {
            sstore(paramsHash, packedParams)
        }
    }
}

// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

import {ERC20} from "../tokens/ERC20.sol";

/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @dev Caution! This library won't check that a token has code, responsibility is delegated to the caller.
library SafeTransferLib {
    /*//////////////////////////////////////////////////////////////
                             ETH OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function safeTransferETH(address to, uint256 amount) internal {
        bool success;

        assembly {
            // Transfer the ETH and store if it succeeded or not.
            success := call(gas(), to, amount, 0, 0, 0, 0)
        }

        require(success, "ETH_TRANSFER_FAILED");
    }

    /*//////////////////////////////////////////////////////////////
                            ERC20 OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function safeTransferFrom(
        ERC20 token,
        address from,
        address to,
        uint256 amount
    ) internal {
        bool success;

        assembly {
            // We'll write our calldata to this slot below, but restore it later.
            let memPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(0, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
            mstore(4, from) // Append the "from" argument.
            mstore(36, to) // Append the "to" argument.
            mstore(68, amount) // Append the "amount" argument.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 100 because that's the total length of our calldata (4 + 32 * 3)
                // Counterintuitively, this call() must be positioned after the or() in the
                // surrounding and() because and() evaluates its arguments from right to left.
                call(gas(), token, 0, 0, 100, 0, 32)
            )

            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, memPointer) // Restore the memPointer.
        }

        require(success, "TRANSFER_FROM_FAILED");
    }

    function safeTransfer(
        ERC20 token,
        address to,
        uint256 amount
    ) internal {
        bool success;

        assembly {
            // We'll write our calldata to this slot below, but restore it later.
            let memPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(0, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
            mstore(4, to) // Append the "to" argument.
            mstore(36, amount) // Append the "amount" argument.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 68 because that's the total length of our calldata (4 + 32 * 2)
                // Counterintuitively, this call() must be positioned after the or() in the
                // surrounding and() because and() evaluates its arguments from right to left.
                call(gas(), token, 0, 0, 68, 0, 32)
            )

            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, memPointer) // Restore the memPointer.
        }

        require(success, "TRANSFER_FAILED");
    }

    function safeApprove(
        ERC20 token,
        address to,
        uint256 amount
    ) internal {
        bool success;

        assembly {
            // We'll write our calldata to this slot below, but restore it later.
            let memPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(0, 0x095ea7b300000000000000000000000000000000000000000000000000000000)
            mstore(4, to) // Append the "to" argument.
            mstore(36, amount) // Append the "amount" argument.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 68 because that's the total length of our calldata (4 + 32 * 2)
                // Counterintuitively, this call() must be positioned after the or() in the
                // surrounding and() because and() evaluates its arguments from right to left.
                call(gas(), token, 0, 0, 68, 0, 32)
            )

            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, memPointer) // Restore the memPointer.
        }

        require(success, "APPROVE_FAILED");
    }
}

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

pragma solidity ^0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    enum Rounding {
        Down, // Toward negative infinity
        Up, // Toward infinity
        Zero // Toward zero
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a >= b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds up instead
     * of rounding down.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
     * with further edits by Uniswap Labs also under MIT license.
     */
    function mulDiv(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod0 := mul(x, y)
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            require(denominator > prod1);

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
            // See https://cs.stackexchange.com/q/138556/92363.

            // Does not overflow because the denominator cannot be zero at this stage in the function.
            uint256 twos = denominator & (~denominator + 1);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
            // in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(
        uint256 x,
        uint256 y,
        uint256 denominator,
        Rounding rounding
    ) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. It the number is not a perfect square, the value is rounded down.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`.
        // We also know that `k`, the position of the most significant bit, is such that `msb(a) = 2**k`.
        // This gives `2**k < a <= 2**(k+1)` → `2**(k/2) <= sqrt(a) < 2 ** (k/2+1)`.
        // Using an algorithm similar to the msb conmputation, we are able to compute `result = 2**(k/2)` which is a
        // good first aproximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1;
        uint256 x = a;
        if (x >> 128 > 0) {
            x >>= 128;
            result <<= 64;
        }
        if (x >> 64 > 0) {
            x >>= 64;
            result <<= 32;
        }
        if (x >> 32 > 0) {
            x >>= 32;
            result <<= 16;
        }
        if (x >> 16 > 0) {
            x >>= 16;
            result <<= 8;
        }
        if (x >> 8 > 0) {
            x >>= 8;
            result <<= 4;
        }
        if (x >> 4 > 0) {
            x >>= 4;
            result <<= 2;
        }
        if (x >> 2 > 0) {
            result <<= 1;
        }

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        uint256 result = sqrt(a);
        if (rounding == Rounding.Up && result * result < a) {
            result += 1;
        }
        return result;
    }
}

// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract ERC20 {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event Transfer(address indexed from, address indexed to, uint256 amount);

    event Approval(address indexed owner, address indexed spender, uint256 amount);

    /*//////////////////////////////////////////////////////////////
                            METADATA STORAGE
    //////////////////////////////////////////////////////////////*/

    string public name;

    string public symbol;

    uint8 public immutable decimals;

    /*//////////////////////////////////////////////////////////////
                              ERC20 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 public totalSupply;

    mapping(address => uint256) public balanceOf;

    mapping(address => mapping(address => uint256)) public allowance;

    /*//////////////////////////////////////////////////////////////
                            EIP-2612 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 internal immutable INITIAL_CHAIN_ID;

    bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;

    mapping(address => uint256) public nonces;

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(
        string memory _name,
        string memory _symbol,
        uint8 _decimals
    ) {
        name = _name;
        symbol = _symbol;
        decimals = _decimals;

        INITIAL_CHAIN_ID = block.chainid;
        INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
    }

    /*//////////////////////////////////////////////////////////////
                               ERC20 LOGIC
    //////////////////////////////////////////////////////////////*/

    function approve(address spender, uint256 amount) public virtual returns (bool) {
        allowance[msg.sender][spender] = amount;

        emit Approval(msg.sender, spender, amount);

        return true;
    }

    function transfer(address to, uint256 amount) public virtual returns (bool) {
        balanceOf[msg.sender] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(msg.sender, to, amount);

        return true;
    }

    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual returns (bool) {
        uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.

        if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;

        balanceOf[from] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(from, to, amount);

        return true;
    }

    /*//////////////////////////////////////////////////////////////
                             EIP-2612 LOGIC
    //////////////////////////////////////////////////////////////*/

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public virtual {
        require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");

        // Unchecked because the only math done is incrementing
        // the owner's nonce which cannot realistically overflow.
        unchecked {
            address recoveredAddress = ecrecover(
                keccak256(
                    abi.encodePacked(
                        "\x19\x01",
                        DOMAIN_SEPARATOR(),
                        keccak256(
                            abi.encode(
                                keccak256(
                                    "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
                                ),
                                owner,
                                spender,
                                value,
                                nonces[owner]++,
                                deadline
                            )
                        )
                    )
                ),
                v,
                r,
                s
            );

            require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");

            allowance[recoveredAddress][spender] = value;
        }

        emit Approval(owner, spender, value);
    }

    function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
        return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
    }

    function computeDomainSeparator() internal view virtual returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                    keccak256(bytes(name)),
                    keccak256("1"),
                    block.chainid,
                    address(this)
                )
            );
    }

    /*//////////////////////////////////////////////////////////////
                        INTERNAL MINT/BURN LOGIC
    //////////////////////////////////////////////////////////////*/

    function _mint(address to, uint256 amount) internal virtual {
        totalSupply += amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(address(0), to, amount);
    }

    function _burn(address from, uint256 amount) internal virtual {
        balanceOf[from] -= amount;

        // Cannot underflow because a user's balance
        // will never be larger than the total supply.
        unchecked {
            totalSupply -= amount;
        }

        emit Transfer(from, address(0), amount);
    }
}

Settings
{
  "remappings": [
    "@cwia/=lib/clones-with-immutable-args/src/",
    "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
    "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
    "@rari-capital/solmate/=lib/solmate/",
    "clones-with-immutable-args/=lib/clones-with-immutable-args/src/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "openzeppelin/=lib/openzeppelin-contracts-upgradeable/contracts/",
    "safe-contracts/=lib/safe-contracts/contracts/",
    "solmate/=lib/solmate/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "bytecodeHash": "none"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  },
  "evmVersion": "london",
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_reporter","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"count","type":"uint256"},{"internalType":"uint256","name":"pending","type":"uint256"}],"name":"DistributeFailed","type":"error"},{"inputs":[],"name":"InvalidReporter","type":"error"},{"inputs":[],"name":"PriceIsInitialized","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"}],"name":"NewPrice","type":"event"},{"inputs":[],"name":"REPORTER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"addValue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"count","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_price","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pending","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"price","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}]

608060405234801561001057600080fd5b506004361061007d5760003560e01c80637ae556b51161005b5780637ae556b5146100c3578063a035b1fe14610102578063e20ccec31461010b578063fe4b84df1461011457600080fd5b806306661abd1461008257806354fd4d50146100995780635b9af12b146100ae575b600080fd5b6033545b6040519081526020015b60405180910390f35b6100a1610127565b60405161009091906106a6565b6100c16100bc3660046106d9565b6101ca565b005b6100ea7f00000000000000000000000098078db053902644191f93988341e31289e1c8fe81565b6040516001600160a01b039091168152602001610090565b61008660015481565b61008660025481565b6100c16101223660046106d9565b6101d6565b60606101527f0000000000000000000000000000000000000000000000000000000000000001610354565b61017b7f0000000000000000000000000000000000000000000000000000000000000000610354565b6101a47f0000000000000000000000000000000000000000000000000000000000000000610354565b6040516020016101b6939291906106f2565b604051602081830303815290604052905090565b6101d38161045d565b50565b600054610100900460ff16158080156101f65750600054600160ff909116105b806102105750303b158015610210575060005460ff166001145b6102785760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff19166001179055801561029b576000805461ff0019166101001790555b6102a4826104c1565b60405163099005e760e31b81526002604360981b0190634c802f38906102d890309060019060009061dead90600401610762565b600060405180830381600087803b1580156102f257600080fd5b505af1158015610306573d6000803e3d6000fd5b505050508015610350576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b60608160000361037b5750506040805180820190915260018152600360fc1b602082015290565b8160005b81156103a5578061038f816107c8565b915061039e9050600a836107f7565b915061037f565b60008167ffffffffffffffff8111156103c0576103c061080b565b6040519080825280601f01601f1916602001820160405280156103ea576020820181803683370190505b5090505b8415610455576103ff600183610821565b915061040c600a86610838565b61041790603061084c565b60f81b81838151811061042c5761042c610864565b60200101906001600160f81b031916908160001a90535061044e600a866107f7565b94506103ee565b949350505050565b61046681610552565b604051635b9af12b60e01b8152600481018290526004604360981b0190635b9af12b90602401600060405180830381600087803b1580156104a657600080fd5b505af11580156104ba573d6000803e3d6000fd5b5050505050565b600054610100900460ff1661052c5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b606482015260840161026f565b6001541561054d5760405163131cb46d60e21b815260040160405180910390fd5b600155565b6001600160a01b037f00000000000000000000000098078db053902644191f93988341e31289e1c8fe167311110000000000000000000000000000000011101933016001600160a01b0316146105bb57604051631d73770560e11b815260040160405180910390fd5b80156105d95780600260008282546105d3919061084c565b90915550505b61035060006105e760335490565b60025410806105f65750603354155b156106015750600090565b60335460025461061191906107f7565b60016000828254610622919061084c565b90915550506033546002546106379190610838565b6002556001546040519081527f270b316b51ab2cf3a3bb8ca4d22e76a327d05e762fcaa8bd6afaf8cfde9270b79060200160405180910390a150600190565b60005b83811015610691578181015183820152602001610679565b838111156106a0576000848401525b50505050565b60208152600082518060208401526106c5816040850160208701610676565b601f01601f19169190910160400192915050565b6000602082840312156106eb57600080fd5b5035919050565b60008451610704818460208901610676565b8083019050601760f91b8082528551610724816001850160208a01610676565b6001920191820152835161073f816002840160208801610676565b0160020195945050505050565b634e487b7160e01b600052602160045260246000fd5b6001600160a01b0385811682526080820190600386106107845761078461074c565b8560208401526002851061079a5761079a61074c565b84604084015280841660608401525095945050505050565b634e487b7160e01b600052601160045260246000fd5b6000600182016107da576107da6107b2565b5060010190565b634e487b7160e01b600052601260045260246000fd5b600082610806576108066107e1565b500490565b634e487b7160e01b600052604160045260246000fd5b600082821015610833576108336107b2565b500390565b600082610847576108476107e1565b500690565b6000821982111561085f5761085f6107b2565b500190565b634e487b7160e01b600052603260045260246000fdfea164736f6c634300080f000a

Deployed Bytecode

0x608060405234801561001057600080fd5b506004361061007d5760003560e01c80637ae556b51161005b5780637ae556b5146100c3578063a035b1fe14610102578063e20ccec31461010b578063fe4b84df1461011457600080fd5b806306661abd1461008257806354fd4d50146100995780635b9af12b146100ae575b600080fd5b6033545b6040519081526020015b60405180910390f35b6100a1610127565b60405161009091906106a6565b6100c16100bc3660046106d9565b6101ca565b005b6100ea7f00000000000000000000000098078db053902644191f93988341e31289e1c8fe81565b6040516001600160a01b039091168152602001610090565b61008660015481565b61008660025481565b6100c16101223660046106d9565b6101d6565b60606101527f0000000000000000000000000000000000000000000000000000000000000001610354565b61017b7f0000000000000000000000000000000000000000000000000000000000000000610354565b6101a47f0000000000000000000000000000000000000000000000000000000000000000610354565b6040516020016101b6939291906106f2565b604051602081830303815290604052905090565b6101d38161045d565b50565b600054610100900460ff16158080156101f65750600054600160ff909116105b806102105750303b158015610210575060005460ff166001145b6102785760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff19166001179055801561029b576000805461ff0019166101001790555b6102a4826104c1565b60405163099005e760e31b81526002604360981b0190634c802f38906102d890309060019060009061dead90600401610762565b600060405180830381600087803b1580156102f257600080fd5b505af1158015610306573d6000803e3d6000fd5b505050508015610350576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b60608160000361037b5750506040805180820190915260018152600360fc1b602082015290565b8160005b81156103a5578061038f816107c8565b915061039e9050600a836107f7565b915061037f565b60008167ffffffffffffffff8111156103c0576103c061080b565b6040519080825280601f01601f1916602001820160405280156103ea576020820181803683370190505b5090505b8415610455576103ff600183610821565b915061040c600a86610838565b61041790603061084c565b60f81b81838151811061042c5761042c610864565b60200101906001600160f81b031916908160001a90535061044e600a866107f7565b94506103ee565b949350505050565b61046681610552565b604051635b9af12b60e01b8152600481018290526004604360981b0190635b9af12b90602401600060405180830381600087803b1580156104a657600080fd5b505af11580156104ba573d6000803e3d6000fd5b5050505050565b600054610100900460ff1661052c5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b606482015260840161026f565b6001541561054d5760405163131cb46d60e21b815260040160405180910390fd5b600155565b6001600160a01b037f00000000000000000000000098078db053902644191f93988341e31289e1c8fe167311110000000000000000000000000000000011101933016001600160a01b0316146105bb57604051631d73770560e11b815260040160405180910390fd5b80156105d95780600260008282546105d3919061084c565b90915550505b61035060006105e760335490565b60025410806105f65750603354155b156106015750600090565b60335460025461061191906107f7565b60016000828254610622919061084c565b90915550506033546002546106379190610838565b6002556001546040519081527f270b316b51ab2cf3a3bb8ca4d22e76a327d05e762fcaa8bd6afaf8cfde9270b79060200160405180910390a150600190565b60005b83811015610691578181015183820152602001610679565b838111156106a0576000848401525b50505050565b60208152600082518060208401526106c5816040850160208701610676565b601f01601f19169190910160400192915050565b6000602082840312156106eb57600080fd5b5035919050565b60008451610704818460208901610676565b8083019050601760f91b8082528551610724816001850160208a01610676565b6001920191820152835161073f816002840160208801610676565b0160020195945050505050565b634e487b7160e01b600052602160045260246000fd5b6001600160a01b0385811682526080820190600386106107845761078461074c565b8560208401526002851061079a5761079a61074c565b84604084015280841660608401525095945050505050565b634e487b7160e01b600052601160045260246000fd5b6000600182016107da576107da6107b2565b5060010190565b634e487b7160e01b600052601260045260246000fd5b600082610806576108066107e1565b500490565b634e487b7160e01b600052604160045260246000fd5b600082821015610833576108336107b2565b500390565b600082610847576108476107e1565b500690565b6000821982111561085f5761085f6107b2565b500190565b634e487b7160e01b600052603260045260246000fdfea164736f6c634300080f000a

Deployed Bytecode Sourcemap

3409:1009:8:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4161:88;4235:6;;4161:88;;;160:25:12;;;148:2;133:18;4161:88:8;;;;;;;;1011:338:10;;;:::i;:::-;;;;;;;:::i;2275:77:8:-;;;;;;:::i;:::-;;:::i;:::-;;709:33;;;;;;;;-1:-1:-1;;;;;1196:32:12;;;1178:51;;1166:2;1151:18;709:33:8;1032:203:12;811:20:8;;;;;;942:22;;;;;;3808:313;;;;;;:::i;:::-;;:::i;1011:338:10:-;1051:13;1140:31;1157:13;1140:16;:31::i;:::-;1212;1229:13;1212:16;:31::i;:::-;1284;1301:13;1284:16;:31::i;:::-;1105:225;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;1077:264;;1011:338;:::o;2275:77:8:-;2328:16;2338:5;2328:9;:16::i;:::-;2275:77;:::o;3808:313::-;3363:19:0;3386:13;;;;;;3385:14;;3433:34;;;;-1:-1:-1;3451:12:0;;3466:1;3451:12;;;;:16;3433:34;3432:108;;;-1:-1:-1;3512:4:0;1757:19:1;:23;;;3473:66:0;;-1:-1:-1;3522:12:0;;;;;:17;3473:66;3410:204;;;;-1:-1:-1;;;3410:204:0;;2407:2:12;3410:204:0;;;2389:21:12;2446:2;2426:18;;;2419:30;2485:34;2465:18;;;2458:62;-1:-1:-1;;;2536:18:12;;;2529:44;2590:19;;3410:204:0;;;;;;;;;3625:12;:16;;-1:-1:-1;;3625:16:0;3640:1;3625:16;;;3652:67;;;;3687:13;:20;;-1:-1:-1;;3687:20:0;;;;;3652:67;3874:37:8::1;3902:6;3874:17;:37::i;:::-;3922:191;::::0;-1:-1:-1;;;3922:191:8;;-1:-1:-1;;;;;4496:42:9;3922:41:8::1;::::0;:191:::1;::::0;3986:4:::1;::::0;4006:14:::1;::::0;4035:12:::1;::::0;4070:6:::1;::::0;3922:191:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;3745:14:0::0;3741:102;;;3792:5;3776:21;;-1:-1:-1;;3776:21:0;;;3817:14;;-1:-1:-1;3490:36:12;;3817:14:0;;3478:2:12;3463:18;3817:14:0;;;;;;;3741:102;3352:498;3808:313:8;:::o;407:723:2:-;463:13;684:5;693:1;684:10;680:53;;-1:-1:-1;;711:10:2;;;;;;;;;;;;-1:-1:-1;;;711:10:2;;;;;407:723::o;680:53::-;758:5;743:12;799:78;806:9;;799:78;;832:8;;;;:::i;:::-;;-1:-1:-1;855:10:2;;-1:-1:-1;863:2:2;855:10;;:::i;:::-;;;799:78;;;887:19;919:6;909:17;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;909:17:2;;887:39;;937:154;944:10;;937:154;;971:11;981:1;971:11;;:::i;:::-;;-1:-1:-1;1040:10:2;1048:2;1040:5;:10;:::i;:::-;1027:24;;:2;:24;:::i;:::-;1014:39;;997:6;1004;997:14;;;;;;;;:::i;:::-;;;;:56;-1:-1:-1;;;;;997:56:2;;;;;;;;-1:-1:-1;1068:11:2;1077:2;1068:11;;:::i;:::-;;;937:154;;;1115:6;407:723;-1:-1:-1;;;;407:723:2:o;4257:158:8:-;4320:22;4336:5;4320:15;:22::i;:::-;4355:52;;-1:-1:-1;;;4355:52:8;;;;;160:25:12;;;-1:-1:-1;;;;;4769:42:9;4355:45:8;;133:18:12;;4355:52:8;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4257:158;:::o;1761:182::-;5506:13:0;;;;;;;5498:69;;;;-1:-1:-1;;;5498:69:0;;4912:2:12;5498:69:0;;;4894:21:12;4951:2;4931:18;;;4924:30;4990:34;4970:18;;;4963:62;-1:-1:-1;;;5041:18:12;;;5034:41;5092:19;;5498:69:0;4710:407:12;5498:69:0;1845:5:8::1;::::0;:10;1841:70:::1;;1879:20;;-1:-1:-1::0;;;1879:20:8::1;;;;;;;;;;;1841:70;1921:5;:14:::0;1761:182::o;2360:290::-;-1:-1:-1;;;;;2476:8:8;2426:58;-1:-1:-1;;2461:10:8;1724:27:11;-1:-1:-1;;;;;2426:58:8;;2422:115;;2508:17;;-1:-1:-1;;;2508:17:8;;;;;;;;;;;2422:115;2553:9;;2549:58;;2590:5;2579:7;;:16;;;;;;;:::i;:::-;;;;-1:-1:-1;;2549:58:8;2619:23;2973:4;3004:7;4235:6;;;4161:88;3004:7;2994;;:17;:33;;;-1:-1:-1;4235:6:8;;3015:12;2994:33;2990:78;;;-1:-1:-1;3051:5:8;;2922:287::o;2990:78::-;4235:6;;3089:7;;:17;;;;:::i;:::-;3080:5;;:26;;;;;;;:::i;:::-;;;;-1:-1:-1;;4235:6:8;;3127:7;;:17;;;;:::i;:::-;3117:7;:27;3171:5;;3162:15;;160:25:12;;;3162:15:8;;148:2:12;133:18;3162:15:8;;;;;;;-1:-1:-1;3197:4:8;;2922:287::o;196:258:12:-;268:1;278:113;292:6;289:1;286:13;278:113;;;368:11;;;362:18;349:11;;;342:39;314:2;307:10;278:113;;;409:6;406:1;403:13;400:48;;;444:1;435:6;430:3;426:16;419:27;400:48;;196:258;;;:::o;459:383::-;608:2;597:9;590:21;571:4;640:6;634:13;683:6;678:2;667:9;663:18;656:34;699:66;758:6;753:2;742:9;738:18;733:2;725:6;721:15;699:66;:::i;:::-;826:2;805:15;-1:-1:-1;;801:29:12;786:45;;;;833:2;782:54;;459:383;-1:-1:-1;;459:383:12:o;847:180::-;906:6;959:2;947:9;938:7;934:23;930:32;927:52;;;975:1;972;965:12;927:52;-1:-1:-1;998:23:12;;847:180;-1:-1:-1;847:180:12:o;1240:960::-;1669:3;1707:6;1701:13;1723:53;1769:6;1764:3;1757:4;1749:6;1745:17;1723:53;:::i;:::-;1807:6;1802:3;1798:16;1785:29;;-1:-1:-1;;;1859:2:12;1852:5;1845:17;1893:6;1887:13;1909:65;1965:8;1961:1;1954:5;1950:13;1943:4;1935:6;1931:17;1909:65;:::i;:::-;2037:1;1993:20;;2029:10;;;2022:22;2069:13;;2091:62;2069:13;2140:1;2132:10;;2125:4;2113:17;;2091:62;:::i;:::-;2173:17;2192:1;2169:25;;1240:960;-1:-1:-1;;;;;1240:960:12:o;2620:127::-;2681:10;2676:3;2672:20;2669:1;2662:31;2712:4;2709:1;2702:15;2736:4;2733:1;2726:15;2752:581;-1:-1:-1;;;;;3061:15:12;;;3043:34;;2992:3;2977:19;;;3107:1;3096:13;;3086:47;;3113:18;;:::i;:::-;3169:6;3164:2;3153:9;3149:18;3142:34;3206:1;3198:6;3195:13;3185:47;;3212:18;;:::i;:::-;3268:6;3263:2;3252:9;3248:18;3241:34;3323:2;3315:6;3311:15;3306:2;3295:9;3291:18;3284:43;;2752:581;;;;;;;:::o;3537:127::-;3598:10;3593:3;3589:20;3586:1;3579:31;3629:4;3626:1;3619:15;3653:4;3650:1;3643:15;3669:135;3708:3;3729:17;;;3726:43;;3749:18;;:::i;:::-;-1:-1:-1;3796:1:12;3785:13;;3669:135::o;3809:127::-;3870:10;3865:3;3861:20;3858:1;3851:31;3901:4;3898:1;3891:15;3925:4;3922:1;3915:15;3941:120;3981:1;4007;3997:35;;4012:18;;:::i;:::-;-1:-1:-1;4046:9:12;;3941:120::o;4066:127::-;4127:10;4122:3;4118:20;4115:1;4108:31;4158:4;4155:1;4148:15;4182:4;4179:1;4172:15;4198:125;4238:4;4266:1;4263;4260:8;4257:34;;;4271:18;;:::i;:::-;-1:-1:-1;4308:9:12;;4198:125::o;4328:112::-;4360:1;4386;4376:35;;4391:18;;:::i;:::-;-1:-1:-1;4425:9:12;;4328:112::o;4445:128::-;4485:3;4516:1;4512:6;4509:1;4506:13;4503:39;;;4522:18;;:::i;:::-;-1:-1:-1;4558:9:12;;4445:128::o;4578:127::-;4639:10;4634:3;4630:20;4627:1;4620:31;4670:4;4667:1;4660:15;4694:4;4691:1;4684:15

Swarm Source

none

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
Loading...
Loading

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.