ETH Price: $3,344.44 (-2.04%)

Contract

0x83acB050AA232F97810F32aFACDE003303465ca5
 

Overview

ETH Balance

0.0002 ETH

ETH Value

$0.67 (@ $3,344.44/ETH)

More Info

Private Name Tags

TokenTracker

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Withdraw134927552025-01-02 5:22:0518 days ago1735795325IN
0x83acB050...303465ca5
0 ETH0.000000040.00195634
Initialize134927342025-01-02 5:21:2318 days ago1735795283IN
0x83acB050...303465ca5
0 ETH0.000000040.00196428
Deposit51158982024-06-22 7:33:31212 days ago1719041611IN
0x83acB050...303465ca5
0.0001 ETH0.000019550.31
Deposit51154542024-06-22 7:18:43212 days ago1719040723IN
0x83acB050...303465ca5
0.0001 ETH0.000006520.31
Transfer44813412024-06-07 15:01:37227 days ago1717772497IN
0x83acB050...303465ca5
0 ETH0.000000720.01367554
Transfer43598742024-06-04 19:32:43229 days ago1717529563IN
0x83acB050...303465ca5
0 ETH0.000000310.01021668

Latest 1 internal transaction

Parent Transaction Hash Block From To
21828632024-04-15 10:05:41280 days ago1713175541
0x83acB050...303465ca5
0.0001 ETH

Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
WETHRebasing

Compiler Version
v0.8.15+commit.e14f2714

Optimization Enabled:
Yes with 200 runs

Other Settings:
london EvmVersion
File 1 of 30 : WETHRebasing.sol
// SPDX-License-Identifier: BSL 1.1 - Copyright 2024 MetaLayer Labs Ltd.
pragma solidity 0.8.15;

import { FixedPointMathLib } from "solmate/utils/FixedPointMathLib.sol";

import { Blast, YieldMode } from "src/L2/Blast.sol";
import { GasMode } from "src/L2/Gas.sol";
import { ERC20Rebasing } from "src/L2/ERC20Rebasing.sol";
import { SharesBase } from "src/L2/Shares.sol";
import { Predeploys } from "src/libraries/Predeploys.sol";
import { Semver } from "src/universal/Semver.sol";

/// @custom:proxied
/// @custom:predeploy 0x4300000000000000000000000000000000000004
/// @title WETHRebasing
/// @notice Rebasing ERC20 token that serves as WETH on Blast L2.
/// Although the WETH token builds on top of the already rebasing native ether,
/// it has its own configuration and shares accounting. However, it’s the only token
/// that does not receive a yield report.
///
/// An additional complexity with WETH is that since it holds native ether,
/// its own balance is rebasing. Therefore, we could just base the WETH share price on the ether price,
/// however, users and contracts are able to opt-out of receiving yield, while their funds are still
/// gaining yield for the WETH contract. Using the native ether share price would leave yields
/// in the WETH contract that are unallocated due to the VOID balances. To resolve this, WETH has
/// its own share price that’s computed based on its current balance and removing void funds
/// so the yields are only divided amongst the active funds.
contract WETHRebasing is ERC20Rebasing, Semver {
    /// @notice Emitted whenever tokens are deposited to an account.
    /// @param account Address of the account tokens are being deposited to.
    /// @param amount  Amount of tokens deposited.
    event Deposit(address indexed account, uint amount);

    /// @notice Emitted whenever tokens are withdrawn from an account.
    /// @param account Address of the account tokens are being withdrawn from.
    /// @param amount  Amount of tokens withdrawn.
    event Withdrawal(address indexed account, uint amount);

    error ETHTransferFailed();

    /// @custom:semver 1.0.0
    constructor()
        ERC20Rebasing(Predeploys.SHARES, 18)
        Semver(1, 0, 0)
    {
        _disableInitializers();
    }

    /// @notice Initializer.
    function initialize() external initializer {
        __ERC20Rebasing_init(
            "Wrapped Ether",
            "WETH",
            SharesBase(Predeploys.SHARES).price()
        );
        Blast(Predeploys.BLAST).configureContract(
            address(this),
            YieldMode.AUTOMATIC,
            GasMode.VOID,
            address(0xdead) /// don't set a governor
        );
    }

    /// @notice Allows a user to send ETH directly and have
    ///         their balance updated.
    receive() external payable {
        deposit();
    }

    /// @notice Deposit ETH and increase the wrapped balance.
    function deposit() public payable {
        address account = msg.sender;
        _deposit(account, msg.value);

        emit Deposit(account, msg.value);
    }

    /// @notice Withdraw ETH and decrease the wrapped balance.
    /// @param wad Amount to withdraw.
    function withdraw(uint256 wad) public {
        address account = msg.sender;
        _withdraw(account, wad);

        (bool success,) = account.call{value: wad}("");
        if (!success) revert ETHTransferFailed();

        emit Withdrawal(account, wad);
    }

    /// @notice Update the share price based on the rebased contract balance.
    function _addValue(uint256) internal override {
        if (msg.sender != REPORTER) {
            revert InvalidReporter();
        }

        uint256 yieldBearingEth = price * _totalShares;
        uint256 pending = address(this).balance - yieldBearingEth - _totalVoidAndRemainders;
        if (pending < _totalShares || _totalShares == 0) {
            return;
        }

        price += (pending / _totalShares);
    }

    /**
     * @dev The version parameter for the EIP712 domain.
     */
    function _EIP712Version() internal override view returns (string memory) {
        return version();
    }
}

File 2 of 30 : FixedPointMathLib.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

/// @notice Arithmetic library with operations for fixed-point numbers.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/FixedPointMathLib.sol)
library FixedPointMathLib {
    /*//////////////////////////////////////////////////////////////
                    SIMPLIFIED FIXED POINT OPERATIONS
    //////////////////////////////////////////////////////////////*/

    uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s.

    function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down.
    }

    function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up.
    }

    function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down.
    }

    function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up.
    }

    function powWad(int256 x, int256 y) internal pure returns (int256) {
        // Equivalent to x to the power of y because x ** y = (e ** ln(x)) ** y = e ** (ln(x) * y)
        return expWad((lnWad(x) * y) / int256(WAD)); // Using ln(x) means x must be greater than 0.
    }

    function expWad(int256 x) internal pure returns (int256 r) {
        unchecked {
            // When the result is < 0.5 we return zero. This happens when
            // x <= floor(log(0.5e18) * 1e18) ~ -42e18
            if (x <= -42139678854452767551) return 0;

            // When the result is > (2**255 - 1) / 1e18 we can not represent it as an
            // int. This happens when x >= floor(log((2**255 - 1) / 1e18) * 1e18) ~ 135.
            if (x >= 135305999368893231589) revert("EXP_OVERFLOW");

            // x is now in the range (-42, 136) * 1e18. Convert to (-42, 136) * 2**96
            // for more intermediate precision and a binary basis. This base conversion
            // is a multiplication by 1e18 / 2**96 = 5**18 / 2**78.
            x = (x << 78) / 5**18;

            // Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers
            // of two such that exp(x) = exp(x') * 2**k, where k is an integer.
            // Solving this gives k = round(x / log(2)) and x' = x - k * log(2).
            int256 k = ((x << 96) / 54916777467707473351141471128 + 2**95) >> 96;
            x = x - k * 54916777467707473351141471128;

            // k is in the range [-61, 195].

            // Evaluate using a (6, 7)-term rational approximation.
            // p is made monic, we'll multiply by a scale factor later.
            int256 y = x + 1346386616545796478920950773328;
            y = ((y * x) >> 96) + 57155421227552351082224309758442;
            int256 p = y + x - 94201549194550492254356042504812;
            p = ((p * y) >> 96) + 28719021644029726153956944680412240;
            p = p * x + (4385272521454847904659076985693276 << 96);

            // We leave p in 2**192 basis so we don't need to scale it back up for the division.
            int256 q = x - 2855989394907223263936484059900;
            q = ((q * x) >> 96) + 50020603652535783019961831881945;
            q = ((q * x) >> 96) - 533845033583426703283633433725380;
            q = ((q * x) >> 96) + 3604857256930695427073651918091429;
            q = ((q * x) >> 96) - 14423608567350463180887372962807573;
            q = ((q * x) >> 96) + 26449188498355588339934803723976023;

            assembly {
                // Div in assembly because solidity adds a zero check despite the unchecked.
                // The q polynomial won't have zeros in the domain as all its roots are complex.
                // No scaling is necessary because p is already 2**96 too large.
                r := sdiv(p, q)
            }

            // r should be in the range (0.09, 0.25) * 2**96.

            // We now need to multiply r by:
            // * the scale factor s = ~6.031367120.
            // * the 2**k factor from the range reduction.
            // * the 1e18 / 2**96 factor for base conversion.
            // We do this all at once, with an intermediate result in 2**213
            // basis, so the final right shift is always by a positive amount.
            r = int256((uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k));
        }
    }

    function lnWad(int256 x) internal pure returns (int256 r) {
        unchecked {
            require(x > 0, "UNDEFINED");

            // We want to convert x from 10**18 fixed point to 2**96 fixed point.
            // We do this by multiplying by 2**96 / 10**18. But since
            // ln(x * C) = ln(x) + ln(C), we can simply do nothing here
            // and add ln(2**96 / 10**18) at the end.

            // Reduce range of x to (1, 2) * 2**96
            // ln(2^k * x) = k * ln(2) + ln(x)
            int256 k = int256(log2(uint256(x))) - 96;
            x <<= uint256(159 - k);
            x = int256(uint256(x) >> 159);

            // Evaluate using a (8, 8)-term rational approximation.
            // p is made monic, we will multiply by a scale factor later.
            int256 p = x + 3273285459638523848632254066296;
            p = ((p * x) >> 96) + 24828157081833163892658089445524;
            p = ((p * x) >> 96) + 43456485725739037958740375743393;
            p = ((p * x) >> 96) - 11111509109440967052023855526967;
            p = ((p * x) >> 96) - 45023709667254063763336534515857;
            p = ((p * x) >> 96) - 14706773417378608786704636184526;
            p = p * x - (795164235651350426258249787498 << 96);

            // We leave p in 2**192 basis so we don't need to scale it back up for the division.
            // q is monic by convention.
            int256 q = x + 5573035233440673466300451813936;
            q = ((q * x) >> 96) + 71694874799317883764090561454958;
            q = ((q * x) >> 96) + 283447036172924575727196451306956;
            q = ((q * x) >> 96) + 401686690394027663651624208769553;
            q = ((q * x) >> 96) + 204048457590392012362485061816622;
            q = ((q * x) >> 96) + 31853899698501571402653359427138;
            q = ((q * x) >> 96) + 909429971244387300277376558375;
            assembly {
                // Div in assembly because solidity adds a zero check despite the unchecked.
                // The q polynomial is known not to have zeros in the domain.
                // No scaling required because p is already 2**96 too large.
                r := sdiv(p, q)
            }

            // r is in the range (0, 0.125) * 2**96

            // Finalization, we need to:
            // * multiply by the scale factor s = 5.549…
            // * add ln(2**96 / 10**18)
            // * add k * ln(2)
            // * multiply by 10**18 / 2**96 = 5**18 >> 78

            // mul s * 5e18 * 2**96, base is now 5**18 * 2**192
            r *= 1677202110996718588342820967067443963516166;
            // add ln(2) * k * 5e18 * 2**192
            r += 16597577552685614221487285958193947469193820559219878177908093499208371 * k;
            // add ln(2**96 / 10**18) * 5e18 * 2**192
            r += 600920179829731861736702779321621459595472258049074101567377883020018308;
            // base conversion: mul 2**18 / 2**192
            r >>= 174;
        }
    }

    /*//////////////////////////////////////////////////////////////
                    LOW LEVEL FIXED POINT OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function mulDivDown(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 z) {
        assembly {
            // Store x * y in z for now.
            z := mul(x, y)

            // Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y))
            if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) {
                revert(0, 0)
            }

            // Divide z by the denominator.
            z := div(z, denominator)
        }
    }

    function mulDivUp(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 z) {
        assembly {
            // Store x * y in z for now.
            z := mul(x, y)

            // Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y))
            if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) {
                revert(0, 0)
            }

            // First, divide z - 1 by the denominator and add 1.
            // We allow z - 1 to underflow if z is 0, because we multiply the
            // end result by 0 if z is zero, ensuring we return 0 if z is zero.
            z := mul(iszero(iszero(z)), add(div(sub(z, 1), denominator), 1))
        }
    }

    function rpow(
        uint256 x,
        uint256 n,
        uint256 scalar
    ) internal pure returns (uint256 z) {
        assembly {
            switch x
            case 0 {
                switch n
                case 0 {
                    // 0 ** 0 = 1
                    z := scalar
                }
                default {
                    // 0 ** n = 0
                    z := 0
                }
            }
            default {
                switch mod(n, 2)
                case 0 {
                    // If n is even, store scalar in z for now.
                    z := scalar
                }
                default {
                    // If n is odd, store x in z for now.
                    z := x
                }

                // Shifting right by 1 is like dividing by 2.
                let half := shr(1, scalar)

                for {
                    // Shift n right by 1 before looping to halve it.
                    n := shr(1, n)
                } n {
                    // Shift n right by 1 each iteration to halve it.
                    n := shr(1, n)
                } {
                    // Revert immediately if x ** 2 would overflow.
                    // Equivalent to iszero(eq(div(xx, x), x)) here.
                    if shr(128, x) {
                        revert(0, 0)
                    }

                    // Store x squared.
                    let xx := mul(x, x)

                    // Round to the nearest number.
                    let xxRound := add(xx, half)

                    // Revert if xx + half overflowed.
                    if lt(xxRound, xx) {
                        revert(0, 0)
                    }

                    // Set x to scaled xxRound.
                    x := div(xxRound, scalar)

                    // If n is even:
                    if mod(n, 2) {
                        // Compute z * x.
                        let zx := mul(z, x)

                        // If z * x overflowed:
                        if iszero(eq(div(zx, x), z)) {
                            // Revert if x is non-zero.
                            if iszero(iszero(x)) {
                                revert(0, 0)
                            }
                        }

                        // Round to the nearest number.
                        let zxRound := add(zx, half)

                        // Revert if zx + half overflowed.
                        if lt(zxRound, zx) {
                            revert(0, 0)
                        }

                        // Return properly scaled zxRound.
                        z := div(zxRound, scalar)
                    }
                }
            }
        }
    }

    /*//////////////////////////////////////////////////////////////
                        GENERAL NUMBER UTILITIES
    //////////////////////////////////////////////////////////////*/

    function sqrt(uint256 x) internal pure returns (uint256 z) {
        assembly {
            let y := x // We start y at x, which will help us make our initial estimate.

            z := 181 // The "correct" value is 1, but this saves a multiplication later.

            // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad
            // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.

            // We check y >= 2^(k + 8) but shift right by k bits
            // each branch to ensure that if x >= 256, then y >= 256.
            if iszero(lt(y, 0x10000000000000000000000000000000000)) {
                y := shr(128, y)
                z := shl(64, z)
            }
            if iszero(lt(y, 0x1000000000000000000)) {
                y := shr(64, y)
                z := shl(32, z)
            }
            if iszero(lt(y, 0x10000000000)) {
                y := shr(32, y)
                z := shl(16, z)
            }
            if iszero(lt(y, 0x1000000)) {
                y := shr(16, y)
                z := shl(8, z)
            }

            // Goal was to get z*z*y within a small factor of x. More iterations could
            // get y in a tighter range. Currently, we will have y in [256, 256*2^16).
            // We ensured y >= 256 so that the relative difference between y and y+1 is small.
            // That's not possible if x < 256 but we can just verify those cases exhaustively.

            // Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256.
            // Correctness can be checked exhaustively for x < 256, so we assume y >= 256.
            // Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps.

            // For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range
            // (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256.

            // Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate
            // sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18.

            // There is no overflow risk here since y < 2^136 after the first branch above.
            z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181.

            // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))

            // If x+1 is a perfect square, the Babylonian method cycles between
            // floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor.
            // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
            // Since the ceil is rare, we save gas on the assignment and repeat division in the rare case.
            // If you don't care whether the floor or ceil square root is returned, you can remove this statement.
            z := sub(z, lt(div(x, z), z))
        }
    }

    function log2(uint256 x) internal pure returns (uint256 r) {
        require(x > 0, "UNDEFINED");

        assembly {
            r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
            r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
            r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
            r := or(r, shl(4, lt(0xffff, shr(r, x))))
            r := or(r, shl(3, lt(0xff, shr(r, x))))
            r := or(r, shl(2, lt(0xf, shr(r, x))))
            r := or(r, shl(1, lt(0x3, shr(r, x))))
            r := or(r, lt(0x1, shr(r, x)))
        }
    }
}

File 3 of 30 : 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);
    }
}

File 4 of 30 : Gas.sol
// 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)
        }
    }
}

File 5 of 30 : ERC20Rebasing.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 { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol";

import { SharesBase } from "src/L2/Shares.sol";
import { YieldMode } from "src/L2/Blast.sol";
import { ERC20PermitUpgradeable } from "src/L2/ERC20PermitUpgradeable.sol";

/// @custom:upgradeable
/// @title ERC20Rebasing
/// @notice ERC20 implementation with rebasing token balances. There are 3 yield
/// modes with different rebasing behaviors.
///
/// AUTOMATIC dynamically updates the balance as the share price increases.
///
/// VOID fixes the balance and exempts the account from receiving yields.
///
/// CLAIMABLE fixes the balance and allows the account to claim yields to
/// another account.
///
/// The child implementation is responsible for deciding how the share price is set.
abstract contract ERC20Rebasing is ERC20PermitUpgradeable, SharesBase, IERC20 {
    /// @notice Number of decimals.
    uint8 public immutable decimals;

    /// @notice Name of the token.
    string public name;
    /// @notice Symbol of the token.
    string public symbol;

    /// @notice Mapping that stores the number of shares for each account.
    mapping(address => uint256) private _shares;

    /// @notice Total number of shares distributed.
    uint256 internal _totalShares;

    /// @notice Mapping that stores the number of remainder tokens for each account.
    mapping(address => uint256) private _remainders;

    /// @notice Mapping that stores the number of fixed tokens for each account.
    mapping(address => uint256) private _fixed;

    /// @notice Total number of non-rebasing tokens.
    uint256 internal _totalVoidAndRemainders;

    /// @notice Mapping that stores the configured yield mode for each account.
    mapping(address => YieldMode) private _yieldMode;

    /// @notice Mapping that stores the allowance for a given spender and operator pair.
    mapping(address => mapping(address => uint256)) private _allowances;

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

    /// @notice Emitted when an account configures their yield mode.
    /// @param account   Address of the account.
    /// @param yieldMode Yield mode that was configured.
    event Configure(address indexed account, YieldMode yieldMode);

    /// @notice Emitted when a CLAIMABLE account claims their yield.
    /// @param account   Address of the account.
    /// @param recipient Address of the recipient.
    /// @param amount    Amount of yield claimed.
    event Claim(address indexed account, address indexed recipient, uint256 amount);

    error InsufficientBalance();
    error InsufficientAllowance();
    error TransferFromZeroAddress();
    error TransferToZeroAddress();
    error ApproveFromZeroAddress();
    error ApproveToZeroAddress();
    error ClaimToZeroAddress();
    error NotClaimableAccount();

    /// @param _decimals Number of decimals.
    constructor(address _reporter, uint8 _decimals) SharesBase(_reporter) {
        decimals = _decimals;
    }

    /// @param _name     Token name.
    /// @param _symbol   Token symbol.
    /// @param _price    Initial share price.
    function __ERC20Rebasing_init(string memory _name, string memory _symbol, uint256 _price) internal onlyInitializing {
        __ERC20Permit_init(_name);
        __SharesBase_init({ _price: _price });
        name = _name;
        symbol = _symbol;
    }

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

    /// @notice --- ERC20 Interface ---

    /// @inheritdoc IERC20
    function totalSupply() external view returns (uint256) {
        return price * _totalShares + _totalVoidAndRemainders;
    }

    /// @inheritdoc IERC20
    function balanceOf(address account)
        public
        view
        virtual
        returns (uint256 value)
    {
        YieldMode yieldMode = _yieldMode[account];
        if (yieldMode == YieldMode.AUTOMATIC) {
            value = _computeShareValue(_shares[account], _remainders[account]);
        } else {
            value = _fixed[account];
        }
    }

    /// @inheritdoc IERC20
    function allowance(address owner, address spender)
        public
        view
        virtual
        returns (uint256)
    {
        return _allowances[owner][spender];
    }

    /// @inheritdoc IERC20
    function transfer(address to, uint256 amount)
        public
        virtual
        returns (bool)
    {
        _transfer(msg.sender, to, amount);
        return true;
    }

    /// @inheritdoc IERC20
    function approve(address spender, uint256 amount)
        public
        virtual
        returns (bool)
    {
        address owner = msg.sender;
        _approve(owner, spender, amount);
        return true;
    }

    /// @inheritdoc IERC20
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual returns (bool) {
        _spendAllowance(from, msg.sender, amount);
        _transfer(from, to, amount);
        return true;
    }

    /// @notice --- Blast Interface ---

    /// @notice Query an account's configured yield mode.
    /// @param account Address to query the configuration.
    /// @return Configured yield mode.
    function getConfiguration(address account) public view returns (YieldMode) {
        return _yieldMode[account];
    }

    /// @notice Query an CLAIMABLE account's claimable yield.
    /// @param account Address to query the claimable amount.
    /// @return amount Claimable amount.
    function getClaimableAmount(address account) public view returns (uint256) {
        if (getConfiguration(account) != YieldMode.CLAIMABLE) {
            revert NotClaimableAccount();
        }

        uint256 shareValue = _computeShareValue(_shares[account], _remainders[account]);
        return shareValue - _fixed[account];
    }

    /// @notice Claim yield from a CLAIMABLE account and send to
    ///         a recipient.
    /// @param recipient Address to receive the claimed balance.
    /// @param amount    Amount to claim.
    /// @return Amount claimed.
    function claim(address recipient, uint256 amount) external returns (uint256) {
        address account = msg.sender;
        if (recipient == address(0)) {
            revert ClaimToZeroAddress();
        }

        if (getConfiguration(account) != YieldMode.CLAIMABLE) {
            revert NotClaimableAccount();
        }

        uint256 shareValue = _computeShareValue(_shares[account], _remainders[account]);

        uint256 claimableAmount = shareValue - _fixed[account];
        if (amount > claimableAmount) {
            revert InsufficientBalance();
        }

        (uint256 newShares, uint256 newRemainder) = _computeSharesAndRemainder(shareValue - amount);

        _updateBalance(account, newShares, newRemainder, _fixed[account]);
        _deposit(recipient, amount);

        emit Claim(msg.sender, recipient, amount);

        return amount;
    }

    /// @notice Change the yield mode of the caller and update the
    ///         balance to reflect the configuration.
    /// @param yieldMode Yield mode to configure
    /// @return Current user balance
    function configure(YieldMode yieldMode) external returns (uint256) {
        _configure(msg.sender, yieldMode);

        emit Configure(msg.sender, yieldMode);

        return balanceOf(msg.sender);
    }

    /// @notice Moves `amount` of tokens from `from` to `to`.
    /// @param from   Address of the sender.
    /// @param to     Address of the recipient.
    /// @param amount Amount of tokens to send.
    function _transfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {
        if (from == address(0)) revert TransferFromZeroAddress();
        if (to == address(0)) revert TransferToZeroAddress();

        _withdraw(from, amount);
        _deposit(to, amount);

        emit Transfer(from, to, amount);
    }

    /// @notice Sets `amount` as the allowance of `spender` over the `owner` s tokens.
    /// @param owner   Address of the owner.
    /// @param spender Address of the spender.
    /// @param amount  Amount of tokens to approve.
    function _approve(
        address owner,
        address spender,
        uint256 amount
    ) internal override {
        if (owner == address(0)) revert ApproveFromZeroAddress();
        if (spender == address(0)) revert ApproveToZeroAddress();

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    /// @notice Updates `owner` s allowance for `spender` based on spent `amount`.
    /// @param owner   Address of the owner.
    /// @param spender Address of the spender.
    /// @param amount  Amount of tokens to spender.
    function _spendAllowance(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance != type(uint256).max) {
            if (amount > currentAllowance) revert InsufficientAllowance();
            unchecked {
                _approve(owner, spender, currentAllowance - amount);
            }
        }
    }

    /// @notice Deposit to an account.
    /// @param account Address of the account to deposit to.
    /// @param amount  Amount to deposit to the account.
    function _deposit(address account, uint256 amount) internal {
        uint256 balanceAfter = balanceOf(account) + amount;
        _setBalance(account, balanceAfter, false);

        /// If the user is configured as VOID, then the amount
        /// is added to the total voided funds.
        YieldMode yieldMode = getConfiguration(account);
        if (yieldMode == YieldMode.VOID) {
            _totalVoidAndRemainders += amount;
        }
    }

    /// @notice Withdraw from an account.
    /// @param account Address of the account to withdraw from.
    /// @param amount  Amount to withdraw to the account.
    function _withdraw(address account, uint256 amount) internal {
        uint256 balance = balanceOf(account);
        if (amount > balance) {
            revert InsufficientBalance();
        }

        unchecked {
            _setBalance(account, balance - amount, false);
        }

        /// If the user is configured as VOID, then the amount
        /// is deducted from the total voided funds.
        YieldMode yieldMode = getConfiguration(account);
        if (yieldMode == YieldMode.VOID) {
            _totalVoidAndRemainders -= amount;
        }
    }

    /// @notice Configures a new yield mode for an account and updates
    ///         the balance storage to reflect the change.
    /// @param account      Address of the account to configure.
    /// @param newYieldMode New yield mode to configure.
    function _configure(address account, YieldMode newYieldMode) internal {
        YieldMode prevYieldMode = getConfiguration(account);

        uint256 balance;
        if (prevYieldMode == YieldMode.CLAIMABLE) {
            /// If the balance is claimable, we need to use their share balance so they
            /// don't lose their claimable yield.
            balance = _computeShareValue(_shares[account], _remainders[account]);
        } else {
            balance = balanceOf(account);
        }

        _yieldMode[account] = newYieldMode;

        uint256 prevFixed = _fixed[account];

        _setBalance(account, balance, true);

        /// If the previous yield mode was VOID, then the amount
        /// is deducted from the total voided funds.
        if (prevYieldMode == YieldMode.VOID) {
            _totalVoidAndRemainders -= prevFixed;
        }

        /// If the new yield mode is VOID, then the amount
        /// is added to the total voided funds.
        if (newYieldMode == YieldMode.VOID) {
            _totalVoidAndRemainders += balance;
        }
    }

    /// @notice Sets the balance of an account according to its yield mode
    ///         configuration.
    /// @param account           Address of the account to set the balance of.
    /// @param amount            Balance to set for the account.
    /// @param resetClaimable    If the account is CLAIMABLE, true if the share
    ///                          balance should be set to the amount. Should only be true when
    ///                          configuring the account.
    function _setBalance(address account, uint256 amount, bool resetClaimable) internal {
        uint256 newShares; uint256 newRemainder; uint256 newFixed;
        YieldMode yieldMode = getConfiguration(account);
        if (yieldMode == YieldMode.AUTOMATIC) {
            (newShares, newRemainder) = _computeSharesAndRemainder(amount);
        } else if (yieldMode == YieldMode.VOID) {
            newFixed = amount;
        } else if (yieldMode == YieldMode.CLAIMABLE) {
            newFixed = amount;
            uint256 shareValue = amount;
            if (!resetClaimable) {
                /// In order to not reset the claimable balance, we have to compute
                /// the user's current share balance and add or subtract the change in
                /// fixed balance before computing the new shares balance parameters.
                shareValue = _computeShareValue(_shares[account], _remainders[account]);
                shareValue = shareValue + amount - _fixed[account];
            }
            (newShares, newRemainder) = _computeSharesAndRemainder(shareValue);
        }

        _updateBalance(account, newShares, newRemainder, newFixed);
    }

    /// @notice Update the balance parameters of an account and appropriately refresh the global sums
    ///         to reflect the change of allocation.
    /// @param account      Address of account to update.
    /// @param newShares    New shares value for account.
    /// @param newRemainder New remainder value for account.
    /// @param newFixed     New fixed value for account.
    function _updateBalance(address account, uint256 newShares, uint256 newRemainder, uint256 newFixed) internal {
        _totalShares = _totalShares + newShares - _shares[account];
        _totalVoidAndRemainders = _totalVoidAndRemainders + newRemainder - _remainders[account];

        _shares[account] = newShares;
        _remainders[account] = newRemainder;
        _fixed[account] = newFixed;
    }

    /// @notice Convert nominal value to number of shares with remainder.
    /// @param value Amount to convert to shares (wad).
    /// @return shares Number of shares (wad), remainder Remainder (wad).
    function _computeSharesAndRemainder(uint256 value) internal view returns (uint256 shares, uint256 remainder) {
        if (price == 0) {
            remainder = value;
        } else {
            shares = value / price;
            remainder = value % price;
        }
    }

    /// @notice Compute nominal value from number of shares.
    /// @param shares     Number of shares (wad).
    /// @param remainders Amount of remainder (wad).
    /// @return value (wad).
    function _computeShareValue(uint256 shares, uint256 remainders) internal view returns (uint256) {
        return price * shares + remainders;
    }

    /**
     * @dev The name parameter for the EIP712 domain.
     */
    function _EIP712Name() internal override view returns (string memory) {
        return name;
    }
}

File 6 of 30 : Shares.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 { 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);
    }
}

File 7 of 30 : 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 8 of 30 : 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)
            )
        );
    }
}

File 9 of 30 : Initializable.sol
// 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 10 of 30 : SafeTransferLib.sol
// 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");
    }
}

File 11 of 30 : Math.sol
// 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;
    }
}

File 12 of 30 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC20.sol)

pragma solidity ^0.8.0;

import "../token/ERC20/IERC20.sol";

File 13 of 30 : ERC20PermitUpgradeable.sol
// SPDX-License-Identifier: BSL 1.1 - Copyright 2024 MetaLayer Labs Ltd.
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/ERC20Permit.sol)

pragma solidity ^0.8.0;

import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20PermitUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/cryptography/ECDSAUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/cryptography/EIP712Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/CountersUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

/**
 * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 *
 * _Available since v3.4._
 *
 * @custom:storage-size 51
 */
abstract contract ERC20PermitUpgradeable is Initializable, IERC20PermitUpgradeable, EIP712Upgradeable {
    using CountersUpgradeable for CountersUpgradeable.Counter;

    mapping(address => CountersUpgradeable.Counter) private _nonces;

    // solhint-disable-next-line var-name-mixedcase
    bytes32 public constant PERMIT_TYPEHASH =
        keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
    /**
     * @dev In previous versions `_PERMIT_TYPEHASH` was declared as `immutable`.
     * However, to ensure consistency with the upgradeable transpiler, we will continue
     * to reserve a slot.
     * @custom:oz-renamed-from _PERMIT_TYPEHASH
     */
    // solhint-disable-next-line var-name-mixedcase
    bytes32 private _PERMIT_TYPEHASH_DEPRECATED_SLOT;

    /**
     * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`.
     *
     * It's a good idea to use the same `name` that is defined as the ERC20 token name.
     */
    function __ERC20Permit_init(string memory name) internal onlyInitializing {
        __EIP712_init_unchained(name, "1");
    }

    function __ERC20Permit_init_unchained(string memory) internal onlyInitializing {}

    /**
     * @dev See {IERC20Permit-permit}.
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public virtual override {
        require(block.timestamp <= deadline, "ERC20Permit: expired deadline");

        bytes32 structHash = keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline));

        bytes32 hash = _hashTypedDataV4(structHash);

        address signer = ECDSAUpgradeable.recover(hash, v, r, s);
        require(signer == owner, "ERC20Permit: invalid signature");

        _approve(owner, spender, value);
    }

    /**
     * @dev See {IERC20Permit-nonces}.
     */
    function nonces(address owner) public view virtual override returns (uint256) {
        return _nonces[owner].current();
    }

    /**
     * @dev See {IERC20Permit-DOMAIN_SEPARATOR}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view override returns (bytes32) {
        return _domainSeparatorV4();
    }

    /**
     * @dev "Consume a nonce": return the current value and increment.
     *
     * _Available since v4.1._
     */
    function _useNonce(address owner) internal virtual returns (uint256 current) {
        CountersUpgradeable.Counter storage nonce = _nonces[owner];
        current = nonce.current();
        nonce.increment();
    }

    /**
     * @dev See {ERC20-_approve}.
     */
    function _approve(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual;

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

File 14 of 30 : AddressAliasHelper.sol
// 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 15 of 30 : Strings.sol
// 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);
    }
}

File 16 of 30 : AddressUpgradeable.sol
// 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);
        }
    }
}

File 17 of 30 : ERC20.sol
// 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);
    }
}

File 18 of 30 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool);
}

File 19 of 30 : IERC20PermitUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
interface IERC20PermitUpgradeable {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

File 20 of 30 : ERC20Upgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol)

pragma solidity ^0.8.0;

import "./IERC20Upgradeable.sol";
import "./extensions/IERC20MetadataUpgradeable.sol";
import "../../utils/ContextUpgradeable.sol";
import "../../proxy/utils/Initializable.sol";

/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 * For a generic mechanism see {ERC20PresetMinterPauser}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * The default value of {decimals} is 18. To change this, you should override
 * this function so it returns a different value.
 *
 * We have followed general OpenZeppelin Contracts guidelines: functions revert
 * instead returning `false` on failure. This behavior is nonetheless
 * conventional and does not conflict with the expectations of ERC20
 * applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 *
 * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
 * functions have been added to mitigate the well-known issues around setting
 * allowances. See {IERC20-approve}.
 */
contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeable, IERC20MetadataUpgradeable {
    mapping(address => uint256) private _balances;

    mapping(address => mapping(address => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * All two of these values are immutable: they can only be set once during
     * construction.
     */
    function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing {
        __ERC20_init_unchained(name_, symbol_);
    }

    function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5.05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the default value returned by this function, unless
     * it's overridden.
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view virtual override returns (uint8) {
        return 18;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view virtual override returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view virtual override returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address to, uint256 amount) public virtual override returns (bool) {
        address owner = _msgSender();
        _transfer(owner, to, amount);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view virtual override returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
     * `transferFrom`. This is semantically equivalent to an infinite approval.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount) public virtual override returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, amount);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20}.
     *
     * NOTE: Does not update the allowance if the current allowance
     * is the maximum `uint256`.
     *
     * Requirements:
     *
     * - `from` and `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     * - the caller must have allowance for ``from``'s tokens of at least
     * `amount`.
     */
    function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {
        address spender = _msgSender();
        _spendAllowance(from, spender, amount);
        _transfer(from, to, amount);
        return true;
    }

    /**
     * @dev Atomically increases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, allowance(owner, spender) + addedValue);
        return true;
    }

    /**
     * @dev Atomically decreases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `spender` must have allowance for the caller of at least
     * `subtractedValue`.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
        address owner = _msgSender();
        uint256 currentAllowance = allowance(owner, spender);
        require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
        unchecked {
            _approve(owner, spender, currentAllowance - subtractedValue);
        }

        return true;
    }

    /**
     * @dev Moves `amount` of tokens from `from` to `to`.
     *
     * This internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     */
    function _transfer(address from, address to, uint256 amount) internal virtual {
        require(from != address(0), "ERC20: transfer from the zero address");
        require(to != address(0), "ERC20: transfer to the zero address");

        _beforeTokenTransfer(from, to, amount);

        uint256 fromBalance = _balances[from];
        require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
        unchecked {
            _balances[from] = fromBalance - amount;
            // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
            // decrementing then incrementing.
            _balances[to] += amount;
        }

        emit Transfer(from, to, amount);

        _afterTokenTransfer(from, to, amount);
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function _mint(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: mint to the zero address");

        _beforeTokenTransfer(address(0), account, amount);

        _totalSupply += amount;
        unchecked {
            // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
            _balances[account] += amount;
        }
        emit Transfer(address(0), account, amount);

        _afterTokenTransfer(address(0), account, amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: burn from the zero address");

        _beforeTokenTransfer(account, address(0), amount);

        uint256 accountBalance = _balances[account];
        require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
        unchecked {
            _balances[account] = accountBalance - amount;
            // Overflow not possible: amount <= accountBalance <= totalSupply.
            _totalSupply -= amount;
        }

        emit Transfer(account, address(0), amount);

        _afterTokenTransfer(account, address(0), amount);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(address owner, address spender, uint256 amount) internal virtual {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    /**
     * @dev Updates `owner` s allowance for `spender` based on spent `amount`.
     *
     * Does not update the allowance amount in case of infinite allowance.
     * Revert if not enough allowance is available.
     *
     * Might emit an {Approval} event.
     */
    function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance != type(uint256).max) {
            require(currentAllowance >= amount, "ERC20: insufficient allowance");
            unchecked {
                _approve(owner, spender, currentAllowance - amount);
            }
        }
    }

    /**
     * @dev Hook that is called before any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * will be transferred to `to`.
     * - when `from` is zero, `amount` tokens will be minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}

    /**
     * @dev Hook that is called after any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * has been transferred to `to`.
     * - when `from` is zero, `amount` tokens have been minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}

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

File 21 of 30 : ECDSAUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/ECDSA.sol)

pragma solidity ^0.8.0;

import "../StringsUpgradeable.sol";

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSAUpgradeable {
    enum RecoverError {
        NoError,
        InvalidSignature,
        InvalidSignatureLength,
        InvalidSignatureS,
        InvalidSignatureV // Deprecated in v4.8
    }

    function _throwError(RecoverError error) private pure {
        if (error == RecoverError.NoError) {
            return; // no error: do nothing
        } else if (error == RecoverError.InvalidSignature) {
            revert("ECDSA: invalid signature");
        } else if (error == RecoverError.InvalidSignatureLength) {
            revert("ECDSA: invalid signature length");
        } else if (error == RecoverError.InvalidSignatureS) {
            revert("ECDSA: invalid signature 's' value");
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature` or error string. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     *
     * Documentation for signature generation:
     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
     *
     * _Available since v4.3._
     */
    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            /// @solidity memory-safe-assembly
            assembly {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
            return tryRecover(hash, v, r, s);
        } else {
            return (address(0), RecoverError.InvalidSignatureLength);
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, signature);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
     *
     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
     *
     * _Available since v4.3._
     */
    function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError) {
        bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
        uint8 v = uint8((uint256(vs) >> 255) + 27);
        return tryRecover(hash, v, r, s);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
     *
     * _Available since v4.2._
     */
    function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, r, vs);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
     * `r` and `s` signature fields separately.
     *
     * _Available since v4.3._
     */
    function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) {
        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return (address(0), RecoverError.InvalidSignatureS);
        }

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        if (signer == address(0)) {
            return (address(0), RecoverError.InvalidSignature);
        }

        return (signer, RecoverError.NoError);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from a `hash`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) {
        // 32 is the length in bytes of hash,
        // enforced by the type signature above
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, "\x19Ethereum Signed Message:\n32")
            mstore(0x1c, hash)
            message := keccak256(0x00, 0x3c)
        }
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from `s`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", StringsUpgradeable.toString(s.length), s));
    }

    /**
     * @dev Returns an Ethereum Signed Typed Data, created from a
     * `domainSeparator` and a `structHash`. This produces hash corresponding
     * to the one signed with the
     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
     * JSON-RPC method as part of EIP-712.
     *
     * See {recover}.
     */
    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 data) {
        /// @solidity memory-safe-assembly
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, "\x19\x01")
            mstore(add(ptr, 0x02), domainSeparator)
            mstore(add(ptr, 0x22), structHash)
            data := keccak256(ptr, 0x42)
        }
    }

    /**
     * @dev Returns an Ethereum Signed Data with intended validator, created from a
     * `validator` and `data` according to the version 0 of EIP-191.
     *
     * See {recover}.
     */
    function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19\x00", validator, data));
    }
}

File 22 of 30 : EIP712Upgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/EIP712.sol)

pragma solidity ^0.8.8;

import "./ECDSAUpgradeable.sol";
import "../../interfaces/IERC5267Upgradeable.sol";
import "../../proxy/utils/Initializable.sol";

/**
 * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
 *
 * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,
 * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding
 * they need in their contracts using a combination of `abi.encode` and `keccak256`.
 *
 * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
 * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
 * ({_hashTypedDataV4}).
 *
 * The implementation of the domain separator was designed to be as efficient as possible while still properly updating
 * the chain id to protect against replay attacks on an eventual fork of the chain.
 *
 * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
 * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
 *
 * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain
 * separator of the implementation contract. This will cause the `_domainSeparatorV4` function to always rebuild the
 * separator from the immutable values, which is cheaper than accessing a cached version in cold storage.
 *
 * _Available since v3.4._
 *
 * @custom:storage-size 52
 */
abstract contract EIP712Upgradeable is Initializable, IERC5267Upgradeable {
    bytes32 private constant _TYPE_HASH =
        keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");

    /// @custom:oz-renamed-from _HASHED_NAME
    bytes32 private _hashedName;
    /// @custom:oz-renamed-from _HASHED_VERSION
    bytes32 private _hashedVersion;

    string private _name;
    string private _version;

    /**
     * @dev Initializes the domain separator and parameter caches.
     *
     * The meaning of `name` and `version` is specified in
     * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
     *
     * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
     * - `version`: the current major version of the signing domain.
     *
     * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
     * contract upgrade].
     */
    function __EIP712_init(string memory name, string memory version) internal onlyInitializing {
        __EIP712_init_unchained(name, version);
    }

    function __EIP712_init_unchained(string memory name, string memory version) internal onlyInitializing {
        _name = name;
        _version = version;

        // Reset prior values in storage if upgrading
        _hashedName = 0;
        _hashedVersion = 0;
    }

    /**
     * @dev Returns the domain separator for the current chain.
     */
    function _domainSeparatorV4() internal view returns (bytes32) {
        return _buildDomainSeparator();
    }

    function _buildDomainSeparator() private view returns (bytes32) {
        return keccak256(abi.encode(_TYPE_HASH, _EIP712NameHash(), _EIP712VersionHash(), block.chainid, address(this)));
    }

    /**
     * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
     * function returns the hash of the fully encoded EIP712 message for this domain.
     *
     * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
     *
     * ```solidity
     * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
     *     keccak256("Mail(address to,string contents)"),
     *     mailTo,
     *     keccak256(bytes(mailContents))
     * )));
     * address signer = ECDSA.recover(digest, signature);
     * ```
     */
    function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
        return ECDSAUpgradeable.toTypedDataHash(_domainSeparatorV4(), structHash);
    }

    /**
     * @dev See {EIP-5267}.
     *
     * _Available since v4.9._
     */
    function eip712Domain()
        public
        view
        virtual
        override
        returns (
            bytes1 fields,
            string memory name,
            string memory version,
            uint256 chainId,
            address verifyingContract,
            bytes32 salt,
            uint256[] memory extensions
        )
    {
        // If the hashed name and version in storage are non-zero, the contract hasn't been properly initialized
        // and the EIP712 domain is not reliable, as it will be missing name and version.
        require(_hashedName == 0 && _hashedVersion == 0, "EIP712: Uninitialized");

        return (
            hex"0f", // 01111
            _EIP712Name(),
            _EIP712Version(),
            block.chainid,
            address(this),
            bytes32(0),
            new uint256[](0)
        );
    }

    /**
     * @dev The name parameter for the EIP712 domain.
     *
     * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs
     * are a concern.
     */
    function _EIP712Name() internal virtual view returns (string memory) {
        return _name;
    }

    /**
     * @dev The version parameter for the EIP712 domain.
     *
     * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs
     * are a concern.
     */
    function _EIP712Version() internal virtual view returns (string memory) {
        return _version;
    }

    /**
     * @dev The hash of the name parameter for the EIP712 domain.
     *
     * NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Name` instead.
     */
    function _EIP712NameHash() internal view returns (bytes32) {
        string memory name = _EIP712Name();
        if (bytes(name).length > 0) {
            return keccak256(bytes(name));
        } else {
            // If the name is empty, the contract may have been upgraded without initializing the new storage.
            // We return the name hash in storage if non-zero, otherwise we assume the name is empty by design.
            bytes32 hashedName = _hashedName;
            if (hashedName != 0) {
                return hashedName;
            } else {
                return keccak256("");
            }
        }
    }

    /**
     * @dev The hash of the version parameter for the EIP712 domain.
     *
     * NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Version` instead.
     */
    function _EIP712VersionHash() internal view returns (bytes32) {
        string memory version = _EIP712Version();
        if (bytes(version).length > 0) {
            return keccak256(bytes(version));
        } else {
            // If the version is empty, the contract may have been upgraded without initializing the new storage.
            // We return the version hash in storage if non-zero, otherwise we assume the version is empty by design.
            bytes32 hashedVersion = _hashedVersion;
            if (hashedVersion != 0) {
                return hashedVersion;
            } else {
                return keccak256("");
            }
        }
    }

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

File 23 of 30 : CountersUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)

pragma solidity ^0.8.0;

/**
 * @title Counters
 * @author Matt Condon (@shrugs)
 * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number
 * of elements in a mapping, issuing ERC721 ids, or counting request ids.
 *
 * Include with `using Counters for Counters.Counter;`
 */
library CountersUpgradeable {
    struct Counter {
        // This variable should never be directly accessed by users of the library: interactions must be restricted to
        // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
        // this feature: see https://github.com/ethereum/solidity/issues/4637
        uint256 _value; // default: 0
    }

    function current(Counter storage counter) internal view returns (uint256) {
        return counter._value;
    }

    function increment(Counter storage counter) internal {
        unchecked {
            counter._value += 1;
        }
    }

    function decrement(Counter storage counter) internal {
        uint256 value = counter._value;
        require(value > 0, "Counter: decrement overflow");
        unchecked {
            counter._value = value - 1;
        }
    }

    function reset(Counter storage counter) internal {
        counter._value = 0;
    }
}

File 24 of 30 : IERC20Upgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20Upgradeable {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
}

File 25 of 30 : IERC20MetadataUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.0;

import "../IERC20Upgradeable.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
interface IERC20MetadataUpgradeable is IERC20Upgradeable {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

File 26 of 30 : ContextUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

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

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

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

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

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

File 27 of 30 : StringsUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)

pragma solidity ^0.8.0;

import "./math/MathUpgradeable.sol";
import "./math/SignedMathUpgradeable.sol";

/**
 * @dev String operations.
 */
library StringsUpgradeable {
    bytes16 private constant _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) {
        unchecked {
            uint256 length = MathUpgradeable.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `int256` to its ASCII `string` decimal representation.
     */
    function toString(int256 value) internal pure returns (string memory) {
        return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMathUpgradeable.abs(value))));
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, MathUpgradeable.log256(value) + 1);
        }
    }

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

    /**
     * @dev Returns true if the two strings are equal.
     */
    function equal(string memory a, string memory b) internal pure returns (bool) {
        return keccak256(bytes(a)) == keccak256(bytes(b));
    }
}

File 28 of 30 : IERC5267Upgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC5267.sol)

pragma solidity ^0.8.0;

interface IERC5267Upgradeable {
    /**
     * @dev MAY be emitted to signal that the domain could have changed.
     */
    event EIP712DomainChanged();

    /**
     * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712
     * signature.
     */
    function eip712Domain()
        external
        view
        returns (
            bytes1 fields,
            string memory name,
            string memory version,
            uint256 chainId,
            address verifyingContract,
            bytes32 salt,
            uint256[] memory extensions
        );
}

File 29 of 30 : MathUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library MathUpgradeable {
    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) {
                // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                // The surrounding unchecked block does not change this fact.
                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            require(denominator > prod1, "Math: mulDiv overflow");

            ///////////////////////////////////////////////
            // 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. If 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)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 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) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10 ** 64) {
                value /= 10 ** 64;
                result += 64;
            }
            if (value >= 10 ** 32) {
                value /= 10 ** 32;
                result += 32;
            }
            if (value >= 10 ** 16) {
                value /= 10 ** 16;
                result += 16;
            }
            if (value >= 10 ** 8) {
                value /= 10 ** 8;
                result += 8;
            }
            if (value >= 10 ** 4) {
                value /= 10 ** 4;
                result += 4;
            }
            if (value >= 10 ** 2) {
                value /= 10 ** 2;
                result += 2;
            }
            if (value >= 10 ** 1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256, rounded down, of a positive value.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
        }
    }
}

File 30 of 30 : SignedMathUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard signed math utilities missing in the Solidity language.
 */
library SignedMathUpgradeable {
    /**
     * @dev Returns the largest of two signed numbers.
     */
    function max(int256 a, int256 b) internal pure returns (int256) {
        return a > b ? a : b;
    }

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

    /**
     * @dev Returns the average of two signed numbers without overflow.
     * The result is rounded towards zero.
     */
    function average(int256 a, int256 b) internal pure returns (int256) {
        // Formula from the book "Hacker's Delight"
        int256 x = (a & b) + ((a ^ b) >> 1);
        return x + (int256(uint256(x) >> 255) & (a ^ b));
    }

    /**
     * @dev Returns the absolute unsigned value of a signed value.
     */
    function abs(int256 n) internal pure returns (uint256) {
        unchecked {
            // must be unchecked in order to support `n = type(int256).min`
            return uint256(n >= 0 ? n : -n);
        }
    }
}

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

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ApproveFromZeroAddress","type":"error"},{"inputs":[],"name":"ApproveToZeroAddress","type":"error"},{"inputs":[],"name":"ClaimToZeroAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"count","type":"uint256"},{"internalType":"uint256","name":"pending","type":"uint256"}],"name":"DistributeFailed","type":"error"},{"inputs":[],"name":"ETHTransferFailed","type":"error"},{"inputs":[],"name":"InsufficientAllowance","type":"error"},{"inputs":[],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"InvalidReporter","type":"error"},{"inputs":[],"name":"NotClaimableAccount","type":"error"},{"inputs":[],"name":"PriceIsInitialized","type":"error"},{"inputs":[],"name":"TransferFromZeroAddress","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Claim","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"enum YieldMode","name":"yieldMode","type":"uint8"}],"name":"Configure","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[],"name":"EIP712DomainChanged","type":"event"},{"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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdrawal","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERMIT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"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":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"claim","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum YieldMode","name":"yieldMode","type":"uint8"}],"name":"configure","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"count","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getClaimableAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getConfiguration","outputs":[{"internalType":"enum YieldMode","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pending","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"price","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

61012060405234801561001157600080fd5b50604360981b608052601260a052600160c052600060e08190526101005261003761003c565b6100fb565b600054610100900460ff16156100a85760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff908116146100f9576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b60805160a05160c05160e05161010051612271620001476000396000610827015260006107fe015260006107d5015260006102e5015260008181610395015261148001526122716000f3fe6080604052600436106101a05760003560e01c80637ae556b5116100ec578063aad3ec961161008a578063d505accf11610064578063d505accf146104cc578063dd62ed3e146104ec578063e12f3a6114610532578063e20ccec31461055257600080fd5b8063aad3ec9614610477578063c44b11f714610497578063d0e30db0146104c457600080fd5b806384b0196e116100c657806384b0196e1461040457806395d89b411461042c578063a035b1fe14610441578063a9059cbb1461045757600080fd5b80637ae556b5146103835780637ecebe00146103cf5780638129fc1c146103ef57600080fd5b80632e1a7d4d116101595780633644e515116101335780633644e5151461031957806354fd4d501461032e5780635b9af12b1461034357806370a082311461036357600080fd5b80632e1a7d4d1461027f57806330adf81f1461029f578063313ce567146102d357600080fd5b806306661abd146101b457806306fdde03146101d8578063095ea7b3146101fa57806318160ddd1461022a5780631a33757d1461023f57806323b872dd1461025f57600080fd5b366101af576101ad610568565b005b600080fd5b3480156101c057600080fd5b50609d545b6040519081526020015b60405180910390f35b3480156101e457600080fd5b506101ed6105b9565b6040516101cf9190611cd7565b34801561020657600080fd5b5061021a610215366004611d06565b610647565b60405190151581526020016101cf565b34801561023657600080fd5b506101c5610661565b34801561024b57600080fd5b506101c561025a366004611d30565b610685565b34801561026b57600080fd5b5061021a61027a366004611d51565b6106db565b34801561028b57600080fd5b506101ad61029a366004611d8d565b6106fd565b3480156102ab57600080fd5b506101c57f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b3480156102df57600080fd5b506103077f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff90911681526020016101cf565b34801561032557600080fd5b506101c56107c4565b34801561033a57600080fd5b506101ed6107ce565b34801561034f57600080fd5b506101ad61035e366004611d8d565b610871565b34801561036f57600080fd5b506101c561037e366004611da6565b61087d565b34801561038f57600080fd5b506103b77f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016101cf565b3480156103db57600080fd5b506101c56103ea366004611da6565b610909565b3480156103fb57600080fd5b506101ad610927565b34801561041057600080fd5b50610419610b4a565b6040516101cf9796959493929190611dc1565b34801561043857600080fd5b506101ed610be8565b34801561044d57600080fd5b506101c560685481565b34801561046357600080fd5b5061021a610472366004611d06565b610bf5565b34801561048357600080fd5b506101c5610492366004611d06565b610c0b565b3480156104a357600080fd5b506104b76104b2366004611da6565b610d87565b6040516101cf9190611e81565b6101ad610568565b3480156104d857600080fd5b506101ad6104e7366004611e8f565b610da5565b3480156104f857600080fd5b506101c5610507366004611f02565b6001600160a01b03918216600090815260a26020908152604080832093909416825291909152205490565b34801561053e57600080fd5b506101c561054d366004611da6565b610f09565b34801561055e57600080fd5b506101c560695481565b336105738134610fa0565b806001600160a01b03167fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c346040516105ae91815260200190565b60405180910390a250565b609a80546105c690611f35565b80601f01602080910402602001604051908101604052809291908181526020018280546105f290611f35565b801561063f5780601f106106145761010080835404028352916020019161063f565b820191906000526020600020905b81548152906001019060200180831161062257829003601f168201915b505050505081565b600033610655818585611008565b60019150505b92915050565b600060a054609d546068546106769190611f7f565b6106809190611f9e565b905090565b600061069133836110b8565b336001600160a01b03167fcaa97ab28bae75adcb5a02786c64b44d0d3139aa521bf831cdfbe280ef246e36836040516106ca9190611e81565b60405180910390a261065b3361087d565b60006106e88433846111ea565b6106f3848484611247565b5060019392505050565b3361070881836112ee565b6000816001600160a01b03168360405160006040518083038185875af1925050503d8060008114610755576040519150601f19603f3d011682016040523d82523d6000602084013e61075a565b606091505b505090508061077c5760405163b12d13eb60e01b815260040160405180910390fd5b816001600160a01b03167f7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65846040516107b791815260200190565b60405180910390a2505050565b6000610680611362565b60606107f97f000000000000000000000000000000000000000000000000000000000000000061136c565b6108227f000000000000000000000000000000000000000000000000000000000000000061136c565b61084b7f000000000000000000000000000000000000000000000000000000000000000061136c565b60405160200161085d93929190611fb6565b604051602081830303815290604052905090565b61087a81611475565b50565b6001600160a01b038116600090815260a1602052604081205460ff16818160028111156108ac576108ac611e57565b036108e7576001600160a01b0383166000908152609c6020908152604080832054609e909252909120546108e09190611531565b9150610903565b6001600160a01b0383166000908152609f602052604090205491505b50919050565b6001600160a01b03811660009081526035602052604081205461065b565b600054610100900460ff16158080156109475750600054600160ff909116105b806109615750303b158015610961575060005460ff166001145b6109c95760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff1916600117905580156109ec576000805461ff0019166101001790555b610a9d6040518060400160405280600d81526020016c2bb930b83832b21022ba3432b960991b815250604051806040016040528060048152602001630ae8aa8960e31b815250604360981b6001600160a01b031663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a989190612010565b61154c565b60405163099005e760e31b81526002604360981b0190634c802f3890610ad0903090600090819061dead90600401612029565b600060405180830381600087803b158015610aea57600080fd5b505af1158015610afe573d6000803e3d6000fd5b50505050801561087a576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150565b6000606080600080600060606001546000801b148015610b6a5750600254155b610bae5760405162461bcd60e51b81526020600482015260156024820152741152540dcc4c8e88155b9a5b9a5d1a585b1a5e9959605a1b60448201526064016109c0565b610bb661159e565b610bbe611630565b60408051600080825260208201909252600f60f81b9b939a50919850469750309650945092509050565b609b80546105c690611f35565b6000610c02338484611247565b50600192915050565b6000336001600160a01b038416610c355760405163088d6c0d60e31b815260040160405180910390fd5b6002610c4082610d87565b6002811115610c5157610c51611e57565b14610c6f5760405163ebf953c760e01b815260040160405180910390fd5b6001600160a01b0381166000908152609c6020908152604080832054609e909252822054610c9d9190611531565b6001600160a01b0383166000908152609f602052604081205491925090610cc49083612086565b905080851115610ce757604051631e9acf1760e31b815260040160405180910390fd5b600080610cfc610cf78886612086565b61163a565b91509150610d31858383609f60008a6001600160a01b03166001600160a01b031681526020019081526020016000205461166f565b610d3b8888610fa0565b6040518781526001600160a01b0389169033907f70eb43c4a8ae8c40502dcf22436c509c28d6ff421cf07c491be56984bd9870689060200160405180910390a350949695505050505050565b6001600160a01b0316600090815260a1602052604090205460ff1690565b83421115610df55760405162461bcd60e51b815260206004820152601d60248201527f45524332305065726d69743a206578706972656420646561646c696e6500000060448201526064016109c0565b60007f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9888888610e248c61170b565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e0016040516020818303038152906040528051906020012090506000610e7f82611731565b90506000610e8f8287878761175e565b9050896001600160a01b0316816001600160a01b031614610ef25760405162461bcd60e51b815260206004820152601e60248201527f45524332305065726d69743a20696e76616c6964207369676e6174757265000060448201526064016109c0565b610efd8a8a8a611008565b50505050505050505050565b60006002610f1683610d87565b6002811115610f2757610f27611e57565b14610f455760405163ebf953c760e01b815260040160405180910390fd5b6001600160a01b0382166000908152609c6020908152604080832054609e909252822054610f739190611531565b6001600160a01b0384166000908152609f6020526040902054909150610f999082612086565b9392505050565b600081610fac8461087d565b610fb69190611f9e565b9050610fc483826000611786565b6000610fcf84610d87565b90506001816002811115610fe557610fe5611e57565b03611002578260a06000828254610ffc9190611f9e565b90915550505b50505050565b6001600160a01b03831661102f5760405163eb3b083560e01b815260040160405180910390fd5b6001600160a01b0382166110565760405163076e33c360e31b815260040160405180910390fd5b6001600160a01b03838116600081815260a2602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b60006110c383610d87565b9050600060028260028111156110db576110db611e57565b03611116576001600160a01b0384166000908152609c6020908152604080832054609e9092529091205461110f9190611531565b9050611122565b61111f8461087d565b90505b6001600160a01b038416600090815260a160205260409020805484919060ff1916600183600281111561115757611157611e57565b02179055506001600160a01b0384166000908152609f602052604090205461118185836001611786565b600183600281111561119557611195611e57565b036111b2578060a060008282546111ac9190612086565b90915550505b60018460028111156111c6576111c6611e57565b036111e3578160a060008282546111dd9190611f9e565b90915550505b5050505050565b6001600160a01b03838116600090815260a260209081526040808320938616835292905220546000198114611002578082111561123a576040516313be252b60e01b815260040160405180910390fd5b6110028484848403611008565b6001600160a01b03831661126e57604051630b07e54560e11b815260040160405180910390fd5b6001600160a01b03821661129557604051633a954ecd60e21b815260040160405180910390fd5b61129f83826112ee565b6112a98282610fa0565b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516110ab91815260200190565b60006112f98361087d565b90508082111561131c57604051631e9acf1760e31b815260040160405180910390fd5b61132a838383036000611786565b600061133584610d87565b9050600181600281111561134b5761134b611e57565b03611002578260a06000828254610ffc9190612086565b600061068061188d565b6060816000036113935750506040805180820190915260018152600360fc1b602082015290565b8160005b81156113bd57806113a78161209d565b91506113b69050600a836120cc565b9150611397565b60008167ffffffffffffffff8111156113d8576113d8612070565b6040519080825280601f01601f191660200182016040528015611402576020820181803683370190505b5090505b841561146d57611417600183612086565b9150611424600a866120e0565b61142f906030611f9e565b60f81b818381518110611444576114446120f4565b60200101906001600160f81b031916908160001a905350611466600a866120cc565b9450611406565b949350505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146114be57604051631d73770560e11b815260040160405180910390fd5b6000609d546068546114d09190611f7f565b9050600060a05482476114e39190612086565b6114ed9190612086565b9050609d548110806114ff5750609d54155b1561150957505050565b609d5461151690826120cc565b606860008282546115279190611f9e565b9091555050505050565b600081836068546115429190611f7f565b610f999190611f9e565b600054610100900460ff166115735760405162461bcd60e51b81526004016109c09061210a565b61157c83611901565b6115858161194b565b609a61159184826121a4565b50609b61100283826121a4565b6060609a80546115ad90611f35565b80601f01602080910402602001604051908101604052809291908181526020018280546115d990611f35565b80156116265780601f106115fb57610100808354040283529160200191611626565b820191906000526020600020905b81548152906001019060200180831161160957829003601f168201915b5050505050905090565b60606106806107ce565b60008060685460000361164b575091565b60685461165890846120cc565b91506068548361166891906120e0565b9050915091565b6001600160a01b0384166000908152609c6020526040902054609d54611696908590611f9e565b6116a09190612086565b609d556001600160a01b0384166000908152609e602052604090205460a0546116ca908490611f9e565b6116d49190612086565b60a0556001600160a01b039093166000908152609c6020908152604080832094909455609e815283822092909255609f9091522055565b6001600160a01b0381166000908152603560205260409020805460018101825590610903565b600061065b61173e611362565b8360405161190160f01b8152600281019290925260228201526042902090565b600080600061176f87878787611998565b9150915061177c81611a5c565b5095945050505050565b60008060008061179587610d87565b905060008160028111156117ab576117ab611e57565b036117c3576117b98661163a565b9094509250611878565b60018160028111156117d7576117d7611e57565b036117e457859150611878565b60028160028111156117f8576117f8611e57565b03611878578591508185611868576001600160a01b0388166000908152609c6020908152604080832054609e909252909120546118359190611531565b6001600160a01b0389166000908152609f602052604090205490915061185b8883611f9e565b6118659190612086565b90505b6118718161163a565b9095509350505b6118848785858561166f565b50505050505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6118b8611ba6565b6118c0611bff565b60408051602081019490945283019190915260608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b600054610100900460ff166119285760405162461bcd60e51b81526004016109c09061210a565b61087a81604051806040016040528060018152602001603160f81b815250611c30565b600054610100900460ff166119725760405162461bcd60e51b81526004016109c09061210a565b606854156119935760405163131cb46d60e21b815260040160405180910390fd5b606855565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156119cf5750600090506003611a53565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015611a23573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116611a4c57600060019250925050611a53565b9150600090505b94509492505050565b6000816004811115611a7057611a70611e57565b03611a785750565b6001816004811115611a8c57611a8c611e57565b03611ad95760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e6174757265000000000000000060448201526064016109c0565b6002816004811115611aed57611aed611e57565b03611b3a5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016109c0565b6003816004811115611b4e57611b4e611e57565b0361087a5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b60648201526084016109c0565b600080611bb161159e565b805190915015611bc8578051602090910120919050565b6001548015611bd75792915050565b7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4709250505090565b600080611c0a611630565b805190915015611c21578051602090910120919050565b6002548015611bd75792915050565b600054610100900460ff16611c575760405162461bcd60e51b81526004016109c09061210a565b6003611c6383826121a4565b506004611c7082826121a4565b50506000600181905560025550565b60005b83811015611c9a578181015183820152602001611c82565b838111156110025750506000910152565b60008151808452611cc3816020860160208601611c7f565b601f01601f19169290920160200192915050565b602081526000610f996020830184611cab565b80356001600160a01b0381168114611d0157600080fd5b919050565b60008060408385031215611d1957600080fd5b611d2283611cea565b946020939093013593505050565b600060208284031215611d4257600080fd5b813560038110610f9957600080fd5b600080600060608486031215611d6657600080fd5b611d6f84611cea565b9250611d7d60208501611cea565b9150604084013590509250925092565b600060208284031215611d9f57600080fd5b5035919050565b600060208284031215611db857600080fd5b610f9982611cea565b60ff60f81b881681526000602060e081840152611de160e084018a611cab565b8381036040850152611df3818a611cab565b606085018990526001600160a01b038816608086015260a0850187905284810360c0860152855180825283870192509083019060005b81811015611e4557835183529284019291840191600101611e29565b50909c9b505050505050505050505050565b634e487b7160e01b600052602160045260246000fd5b60038110611e7d57611e7d611e57565b9052565b6020810161065b8284611e6d565b600080600080600080600060e0888a031215611eaa57600080fd5b611eb388611cea565b9650611ec160208901611cea565b95506040880135945060608801359350608088013560ff81168114611ee557600080fd5b9699959850939692959460a0840135945060c09093013592915050565b60008060408385031215611f1557600080fd5b611f1e83611cea565b9150611f2c60208401611cea565b90509250929050565b600181811c90821680611f4957607f821691505b60208210810361090357634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000816000190483118215151615611f9957611f99611f69565b500290565b60008219821115611fb157611fb1611f69565b500190565b60008451611fc8818460208901611c7f565b8083019050601760f91b8082528551611fe8816001850160208a01611c7f565b60019201918201528351612003816002840160208801611c7f565b0160020195945050505050565b60006020828403121561202257600080fd5b5051919050565b6001600160a01b03858116825260808201906120486020840187611e6d565b6002851061205857612058611e57565b84604084015280841660608401525095945050505050565b634e487b7160e01b600052604160045260246000fd5b60008282101561209857612098611f69565b500390565b6000600182016120af576120af611f69565b5060010190565b634e487b7160e01b600052601260045260246000fd5b6000826120db576120db6120b6565b500490565b6000826120ef576120ef6120b6565b500690565b634e487b7160e01b600052603260045260246000fd5b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b601f82111561219f57600081815260208120601f850160051c8101602086101561217c5750805b601f850160051c820191505b8181101561219b57828155600101612188565b5050505b505050565b815167ffffffffffffffff8111156121be576121be612070565b6121d2816121cc8454611f35565b84612155565b602080601f83116001811461220757600084156121ef5750858301515b600019600386901b1c1916600185901b17855561219b565b600085815260208120601f198616915b8281101561223657888601518255948401946001909101908401612217565b50858210156122545787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fea164736f6c634300080f000a

Deployed Bytecode

0x6080604052600436106101a05760003560e01c80637ae556b5116100ec578063aad3ec961161008a578063d505accf11610064578063d505accf146104cc578063dd62ed3e146104ec578063e12f3a6114610532578063e20ccec31461055257600080fd5b8063aad3ec9614610477578063c44b11f714610497578063d0e30db0146104c457600080fd5b806384b0196e116100c657806384b0196e1461040457806395d89b411461042c578063a035b1fe14610441578063a9059cbb1461045757600080fd5b80637ae556b5146103835780637ecebe00146103cf5780638129fc1c146103ef57600080fd5b80632e1a7d4d116101595780633644e515116101335780633644e5151461031957806354fd4d501461032e5780635b9af12b1461034357806370a082311461036357600080fd5b80632e1a7d4d1461027f57806330adf81f1461029f578063313ce567146102d357600080fd5b806306661abd146101b457806306fdde03146101d8578063095ea7b3146101fa57806318160ddd1461022a5780631a33757d1461023f57806323b872dd1461025f57600080fd5b366101af576101ad610568565b005b600080fd5b3480156101c057600080fd5b50609d545b6040519081526020015b60405180910390f35b3480156101e457600080fd5b506101ed6105b9565b6040516101cf9190611cd7565b34801561020657600080fd5b5061021a610215366004611d06565b610647565b60405190151581526020016101cf565b34801561023657600080fd5b506101c5610661565b34801561024b57600080fd5b506101c561025a366004611d30565b610685565b34801561026b57600080fd5b5061021a61027a366004611d51565b6106db565b34801561028b57600080fd5b506101ad61029a366004611d8d565b6106fd565b3480156102ab57600080fd5b506101c57f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b3480156102df57600080fd5b506103077f000000000000000000000000000000000000000000000000000000000000001281565b60405160ff90911681526020016101cf565b34801561032557600080fd5b506101c56107c4565b34801561033a57600080fd5b506101ed6107ce565b34801561034f57600080fd5b506101ad61035e366004611d8d565b610871565b34801561036f57600080fd5b506101c561037e366004611da6565b61087d565b34801561038f57600080fd5b506103b77f000000000000000000000000430000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016101cf565b3480156103db57600080fd5b506101c56103ea366004611da6565b610909565b3480156103fb57600080fd5b506101ad610927565b34801561041057600080fd5b50610419610b4a565b6040516101cf9796959493929190611dc1565b34801561043857600080fd5b506101ed610be8565b34801561044d57600080fd5b506101c560685481565b34801561046357600080fd5b5061021a610472366004611d06565b610bf5565b34801561048357600080fd5b506101c5610492366004611d06565b610c0b565b3480156104a357600080fd5b506104b76104b2366004611da6565b610d87565b6040516101cf9190611e81565b6101ad610568565b3480156104d857600080fd5b506101ad6104e7366004611e8f565b610da5565b3480156104f857600080fd5b506101c5610507366004611f02565b6001600160a01b03918216600090815260a26020908152604080832093909416825291909152205490565b34801561053e57600080fd5b506101c561054d366004611da6565b610f09565b34801561055e57600080fd5b506101c560695481565b336105738134610fa0565b806001600160a01b03167fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c346040516105ae91815260200190565b60405180910390a250565b609a80546105c690611f35565b80601f01602080910402602001604051908101604052809291908181526020018280546105f290611f35565b801561063f5780601f106106145761010080835404028352916020019161063f565b820191906000526020600020905b81548152906001019060200180831161062257829003601f168201915b505050505081565b600033610655818585611008565b60019150505b92915050565b600060a054609d546068546106769190611f7f565b6106809190611f9e565b905090565b600061069133836110b8565b336001600160a01b03167fcaa97ab28bae75adcb5a02786c64b44d0d3139aa521bf831cdfbe280ef246e36836040516106ca9190611e81565b60405180910390a261065b3361087d565b60006106e88433846111ea565b6106f3848484611247565b5060019392505050565b3361070881836112ee565b6000816001600160a01b03168360405160006040518083038185875af1925050503d8060008114610755576040519150601f19603f3d011682016040523d82523d6000602084013e61075a565b606091505b505090508061077c5760405163b12d13eb60e01b815260040160405180910390fd5b816001600160a01b03167f7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65846040516107b791815260200190565b60405180910390a2505050565b6000610680611362565b60606107f97f000000000000000000000000000000000000000000000000000000000000000161136c565b6108227f000000000000000000000000000000000000000000000000000000000000000061136c565b61084b7f000000000000000000000000000000000000000000000000000000000000000061136c565b60405160200161085d93929190611fb6565b604051602081830303815290604052905090565b61087a81611475565b50565b6001600160a01b038116600090815260a1602052604081205460ff16818160028111156108ac576108ac611e57565b036108e7576001600160a01b0383166000908152609c6020908152604080832054609e909252909120546108e09190611531565b9150610903565b6001600160a01b0383166000908152609f602052604090205491505b50919050565b6001600160a01b03811660009081526035602052604081205461065b565b600054610100900460ff16158080156109475750600054600160ff909116105b806109615750303b158015610961575060005460ff166001145b6109c95760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff1916600117905580156109ec576000805461ff0019166101001790555b610a9d6040518060400160405280600d81526020016c2bb930b83832b21022ba3432b960991b815250604051806040016040528060048152602001630ae8aa8960e31b815250604360981b6001600160a01b031663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a989190612010565b61154c565b60405163099005e760e31b81526002604360981b0190634c802f3890610ad0903090600090819061dead90600401612029565b600060405180830381600087803b158015610aea57600080fd5b505af1158015610afe573d6000803e3d6000fd5b50505050801561087a576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150565b6000606080600080600060606001546000801b148015610b6a5750600254155b610bae5760405162461bcd60e51b81526020600482015260156024820152741152540dcc4c8e88155b9a5b9a5d1a585b1a5e9959605a1b60448201526064016109c0565b610bb661159e565b610bbe611630565b60408051600080825260208201909252600f60f81b9b939a50919850469750309650945092509050565b609b80546105c690611f35565b6000610c02338484611247565b50600192915050565b6000336001600160a01b038416610c355760405163088d6c0d60e31b815260040160405180910390fd5b6002610c4082610d87565b6002811115610c5157610c51611e57565b14610c6f5760405163ebf953c760e01b815260040160405180910390fd5b6001600160a01b0381166000908152609c6020908152604080832054609e909252822054610c9d9190611531565b6001600160a01b0383166000908152609f602052604081205491925090610cc49083612086565b905080851115610ce757604051631e9acf1760e31b815260040160405180910390fd5b600080610cfc610cf78886612086565b61163a565b91509150610d31858383609f60008a6001600160a01b03166001600160a01b031681526020019081526020016000205461166f565b610d3b8888610fa0565b6040518781526001600160a01b0389169033907f70eb43c4a8ae8c40502dcf22436c509c28d6ff421cf07c491be56984bd9870689060200160405180910390a350949695505050505050565b6001600160a01b0316600090815260a1602052604090205460ff1690565b83421115610df55760405162461bcd60e51b815260206004820152601d60248201527f45524332305065726d69743a206578706972656420646561646c696e6500000060448201526064016109c0565b60007f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9888888610e248c61170b565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e0016040516020818303038152906040528051906020012090506000610e7f82611731565b90506000610e8f8287878761175e565b9050896001600160a01b0316816001600160a01b031614610ef25760405162461bcd60e51b815260206004820152601e60248201527f45524332305065726d69743a20696e76616c6964207369676e6174757265000060448201526064016109c0565b610efd8a8a8a611008565b50505050505050505050565b60006002610f1683610d87565b6002811115610f2757610f27611e57565b14610f455760405163ebf953c760e01b815260040160405180910390fd5b6001600160a01b0382166000908152609c6020908152604080832054609e909252822054610f739190611531565b6001600160a01b0384166000908152609f6020526040902054909150610f999082612086565b9392505050565b600081610fac8461087d565b610fb69190611f9e565b9050610fc483826000611786565b6000610fcf84610d87565b90506001816002811115610fe557610fe5611e57565b03611002578260a06000828254610ffc9190611f9e565b90915550505b50505050565b6001600160a01b03831661102f5760405163eb3b083560e01b815260040160405180910390fd5b6001600160a01b0382166110565760405163076e33c360e31b815260040160405180910390fd5b6001600160a01b03838116600081815260a2602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b60006110c383610d87565b9050600060028260028111156110db576110db611e57565b03611116576001600160a01b0384166000908152609c6020908152604080832054609e9092529091205461110f9190611531565b9050611122565b61111f8461087d565b90505b6001600160a01b038416600090815260a160205260409020805484919060ff1916600183600281111561115757611157611e57565b02179055506001600160a01b0384166000908152609f602052604090205461118185836001611786565b600183600281111561119557611195611e57565b036111b2578060a060008282546111ac9190612086565b90915550505b60018460028111156111c6576111c6611e57565b036111e3578160a060008282546111dd9190611f9e565b90915550505b5050505050565b6001600160a01b03838116600090815260a260209081526040808320938616835292905220546000198114611002578082111561123a576040516313be252b60e01b815260040160405180910390fd5b6110028484848403611008565b6001600160a01b03831661126e57604051630b07e54560e11b815260040160405180910390fd5b6001600160a01b03821661129557604051633a954ecd60e21b815260040160405180910390fd5b61129f83826112ee565b6112a98282610fa0565b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516110ab91815260200190565b60006112f98361087d565b90508082111561131c57604051631e9acf1760e31b815260040160405180910390fd5b61132a838383036000611786565b600061133584610d87565b9050600181600281111561134b5761134b611e57565b03611002578260a06000828254610ffc9190612086565b600061068061188d565b6060816000036113935750506040805180820190915260018152600360fc1b602082015290565b8160005b81156113bd57806113a78161209d565b91506113b69050600a836120cc565b9150611397565b60008167ffffffffffffffff8111156113d8576113d8612070565b6040519080825280601f01601f191660200182016040528015611402576020820181803683370190505b5090505b841561146d57611417600183612086565b9150611424600a866120e0565b61142f906030611f9e565b60f81b818381518110611444576114446120f4565b60200101906001600160f81b031916908160001a905350611466600a866120cc565b9450611406565b949350505050565b336001600160a01b037f000000000000000000000000430000000000000000000000000000000000000016146114be57604051631d73770560e11b815260040160405180910390fd5b6000609d546068546114d09190611f7f565b9050600060a05482476114e39190612086565b6114ed9190612086565b9050609d548110806114ff5750609d54155b1561150957505050565b609d5461151690826120cc565b606860008282546115279190611f9e565b9091555050505050565b600081836068546115429190611f7f565b610f999190611f9e565b600054610100900460ff166115735760405162461bcd60e51b81526004016109c09061210a565b61157c83611901565b6115858161194b565b609a61159184826121a4565b50609b61100283826121a4565b6060609a80546115ad90611f35565b80601f01602080910402602001604051908101604052809291908181526020018280546115d990611f35565b80156116265780601f106115fb57610100808354040283529160200191611626565b820191906000526020600020905b81548152906001019060200180831161160957829003601f168201915b5050505050905090565b60606106806107ce565b60008060685460000361164b575091565b60685461165890846120cc565b91506068548361166891906120e0565b9050915091565b6001600160a01b0384166000908152609c6020526040902054609d54611696908590611f9e565b6116a09190612086565b609d556001600160a01b0384166000908152609e602052604090205460a0546116ca908490611f9e565b6116d49190612086565b60a0556001600160a01b039093166000908152609c6020908152604080832094909455609e815283822092909255609f9091522055565b6001600160a01b0381166000908152603560205260409020805460018101825590610903565b600061065b61173e611362565b8360405161190160f01b8152600281019290925260228201526042902090565b600080600061176f87878787611998565b9150915061177c81611a5c565b5095945050505050565b60008060008061179587610d87565b905060008160028111156117ab576117ab611e57565b036117c3576117b98661163a565b9094509250611878565b60018160028111156117d7576117d7611e57565b036117e457859150611878565b60028160028111156117f8576117f8611e57565b03611878578591508185611868576001600160a01b0388166000908152609c6020908152604080832054609e909252909120546118359190611531565b6001600160a01b0389166000908152609f602052604090205490915061185b8883611f9e565b6118659190612086565b90505b6118718161163a565b9095509350505b6118848785858561166f565b50505050505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6118b8611ba6565b6118c0611bff565b60408051602081019490945283019190915260608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b600054610100900460ff166119285760405162461bcd60e51b81526004016109c09061210a565b61087a81604051806040016040528060018152602001603160f81b815250611c30565b600054610100900460ff166119725760405162461bcd60e51b81526004016109c09061210a565b606854156119935760405163131cb46d60e21b815260040160405180910390fd5b606855565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156119cf5750600090506003611a53565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015611a23573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116611a4c57600060019250925050611a53565b9150600090505b94509492505050565b6000816004811115611a7057611a70611e57565b03611a785750565b6001816004811115611a8c57611a8c611e57565b03611ad95760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e6174757265000000000000000060448201526064016109c0565b6002816004811115611aed57611aed611e57565b03611b3a5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016109c0565b6003816004811115611b4e57611b4e611e57565b0361087a5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b60648201526084016109c0565b600080611bb161159e565b805190915015611bc8578051602090910120919050565b6001548015611bd75792915050565b7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4709250505090565b600080611c0a611630565b805190915015611c21578051602090910120919050565b6002548015611bd75792915050565b600054610100900460ff16611c575760405162461bcd60e51b81526004016109c09061210a565b6003611c6383826121a4565b506004611c7082826121a4565b50506000600181905560025550565b60005b83811015611c9a578181015183820152602001611c82565b838111156110025750506000910152565b60008151808452611cc3816020860160208601611c7f565b601f01601f19169290920160200192915050565b602081526000610f996020830184611cab565b80356001600160a01b0381168114611d0157600080fd5b919050565b60008060408385031215611d1957600080fd5b611d2283611cea565b946020939093013593505050565b600060208284031215611d4257600080fd5b813560038110610f9957600080fd5b600080600060608486031215611d6657600080fd5b611d6f84611cea565b9250611d7d60208501611cea565b9150604084013590509250925092565b600060208284031215611d9f57600080fd5b5035919050565b600060208284031215611db857600080fd5b610f9982611cea565b60ff60f81b881681526000602060e081840152611de160e084018a611cab565b8381036040850152611df3818a611cab565b606085018990526001600160a01b038816608086015260a0850187905284810360c0860152855180825283870192509083019060005b81811015611e4557835183529284019291840191600101611e29565b50909c9b505050505050505050505050565b634e487b7160e01b600052602160045260246000fd5b60038110611e7d57611e7d611e57565b9052565b6020810161065b8284611e6d565b600080600080600080600060e0888a031215611eaa57600080fd5b611eb388611cea565b9650611ec160208901611cea565b95506040880135945060608801359350608088013560ff81168114611ee557600080fd5b9699959850939692959460a0840135945060c09093013592915050565b60008060408385031215611f1557600080fd5b611f1e83611cea565b9150611f2c60208401611cea565b90509250929050565b600181811c90821680611f4957607f821691505b60208210810361090357634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000816000190483118215151615611f9957611f99611f69565b500290565b60008219821115611fb157611fb1611f69565b500190565b60008451611fc8818460208901611c7f565b8083019050601760f91b8082528551611fe8816001850160208a01611c7f565b60019201918201528351612003816002840160208801611c7f565b0160020195945050505050565b60006020828403121561202257600080fd5b5051919050565b6001600160a01b03858116825260808201906120486020840187611e6d565b6002851061205857612058611e57565b84604084015280841660608401525095945050505050565b634e487b7160e01b600052604160045260246000fd5b60008282101561209857612098611f69565b500390565b6000600182016120af576120af611f69565b5060010190565b634e487b7160e01b600052601260045260246000fd5b6000826120db576120db6120b6565b500490565b6000826120ef576120ef6120b6565b500690565b634e487b7160e01b600052603260045260246000fd5b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b601f82111561219f57600081815260208120601f850160051c8101602086101561217c5750805b601f850160051c820191505b8181101561219b57828155600101612188565b5050505b505050565b815167ffffffffffffffff8111156121be576121be612070565b6121d2816121cc8454611f35565b84612155565b602080601f83116001811461220757600084156121ef5750858301515b600019600386901b1c1916600185901b17855561219b565b600085815260208120601f198616915b8281101561223657888601518255948401946001909101908401612217565b50858210156122545787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fea164736f6c634300080f000a

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.