ETH Price: $1,982.84 (-4.35%)

Transaction Decoder

Block:
16388251 at Jan-12-2023 04:11:23 AM +UTC
Transaction Fee:
0.00097998 ETH $1.94
Gas Used:
65,332 Gas / 15 Gwei

Emitted Events:

616 SDL.Transfer( from=[Receiver] RetroactiveVesting, to=[Sender] 0xf6bed2bb9ab681b0b736f347351faca63231e84d, value=27183531698927965381052 )
617 RetroactiveVesting.Claimed( account=[Sender] 0xf6bed2bb9ab681b0b736f347351faca63231e84d, amount=27183531698927965381052 )

Account State Difference:

  Address   Before After State Difference Code
0x5DCA2706...250198a03
(Flashbots: Builder)
1.211735700991102026 Eth1.211737573772146558 Eth0.000001872781044532
0xf1Dc500F...2BC4F6871
0xf6Bed2bb...63231e84D
50.222209494407289121 Eth
Nonce: 1566
50.221229514407289121 Eth
Nonce: 1567
0.00097998

Execution Trace

RetroactiveVesting.claimReward( account=0xf6Bed2bb9aB681b0B736f347351FAca63231e84D )
  • SDL.transfer( recipient=0xf6Bed2bb9aB681b0B736f347351FAca63231e84D, amount=27183531698927965381052 ) => ( True )
    File 1 of 2: RetroactiveVesting
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    /**
     * @dev Interface of the ERC20 standard as defined in the EIP.
     */
    interface IERC20 {
        /**
         * @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 `recipient`.
         *
         * Returns a boolean value indicating whether the operation succeeded.
         *
         * Emits a {Transfer} event.
         */
        function transfer(address recipient, 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 `sender` to `recipient` 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 sender,
            address recipient,
            uint256 amount
        ) external returns (bool);
        /**
         * @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);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    import "../IERC20.sol";
    import "../../../utils/Address.sol";
    /**
     * @title SafeERC20
     * @dev Wrappers around ERC20 operations that throw on failure (when the token
     * contract returns false). Tokens that return no value (and instead revert or
     * throw on failure) are also supported, non-reverting calls are assumed to be
     * successful.
     * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
     * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
     */
    library SafeERC20 {
        using Address for address;
        function safeTransfer(
            IERC20 token,
            address to,
            uint256 value
        ) internal {
            _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
        }
        function safeTransferFrom(
            IERC20 token,
            address from,
            address to,
            uint256 value
        ) internal {
            _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
        }
        /**
         * @dev Deprecated. This function has issues similar to the ones found in
         * {IERC20-approve}, and its usage is discouraged.
         *
         * Whenever possible, use {safeIncreaseAllowance} and
         * {safeDecreaseAllowance} instead.
         */
        function safeApprove(
            IERC20 token,
            address spender,
            uint256 value
        ) internal {
            // safeApprove should only be called when setting an initial allowance,
            // or when resetting it to zero. To increase and decrease it, use
            // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
            require(
                (value == 0) || (token.allowance(address(this), spender) == 0),
                "SafeERC20: approve from non-zero to non-zero allowance"
            );
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
        }
        function safeIncreaseAllowance(
            IERC20 token,
            address spender,
            uint256 value
        ) internal {
            uint256 newAllowance = token.allowance(address(this), spender) + value;
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
        function safeDecreaseAllowance(
            IERC20 token,
            address spender,
            uint256 value
        ) internal {
            unchecked {
                uint256 oldAllowance = token.allowance(address(this), spender);
                require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
                uint256 newAllowance = oldAllowance - value;
                _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
            }
        }
        /**
         * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
         * on the return value: the return value is optional (but if data is returned, it must not be false).
         * @param token The token targeted by the call.
         * @param data The call data (encoded using abi.encode or one of its variants).
         */
        function _callOptionalReturn(IERC20 token, bytes memory data) private {
            // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
            // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
            // the target address contains contract code and also asserts for success in the low-level call.
            bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
            if (returndata.length > 0) {
                // Return data is optional
                require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
            }
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    /**
     * @dev Collection of functions related to the address type
     */
    library Address {
        /**
         * @dev Returns true if `account` is a contract.
         *
         * [IMPORTANT]
         * ====
         * It is unsafe to assume that an address for which this function returns
         * false is an externally-owned account (EOA) and not a contract.
         *
         * Among others, `isContract` will return false for the following
         * types of addresses:
         *
         *  - an externally-owned account
         *  - a contract in construction
         *  - an address where a contract will be created
         *  - an address where a contract lived, but was destroyed
         * ====
         */
        function isContract(address account) internal view returns (bool) {
            // This method relies on extcodesize, which returns 0 for contracts in
            // construction, since the code is only stored at the end of the
            // constructor execution.
            uint256 size;
            assembly {
                size := extcodesize(account)
            }
            return size > 0;
        }
        /**
         * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
         * `recipient`, forwarding all available gas and reverting on errors.
         *
         * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
         * of certain opcodes, possibly making contracts go over the 2300 gas limit
         * imposed by `transfer`, making them unable to receive funds via
         * `transfer`. {sendValue} removes this limitation.
         *
         * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
         *
         * IMPORTANT: because control is transferred to `recipient`, care must be
         * taken to not create reentrancy vulnerabilities. Consider using
         * {ReentrancyGuard} or the
         * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
         */
        function sendValue(address payable recipient, uint256 amount) internal {
            require(address(this).balance >= amount, "Address: insufficient balance");
            (bool success, ) = recipient.call{value: amount}("");
            require(success, "Address: unable to send value, recipient may have reverted");
        }
        /**
         * @dev Performs a Solidity function call using a low level `call`. A
         * plain `call` is an unsafe replacement for a function call: use this
         * function instead.
         *
         * If `target` reverts with a revert reason, it is bubbled up by this
         * function (like regular Solidity function calls).
         *
         * Returns the raw returned data. To convert to the expected return value,
         * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
         *
         * Requirements:
         *
         * - `target` must be a contract.
         * - calling `target` with `data` must not revert.
         *
         * _Available since v3.1._
         */
        function functionCall(address target, bytes memory data) internal returns (bytes memory) {
            return functionCall(target, data, "Address: low-level call failed");
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
         * `errorMessage` as a fallback revert reason when `target` reverts.
         *
         * _Available since v3.1._
         */
        function functionCall(
            address target,
            bytes memory data,
            string memory errorMessage
        ) internal returns (bytes memory) {
            return functionCallWithValue(target, data, 0, errorMessage);
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but also transferring `value` wei to `target`.
         *
         * Requirements:
         *
         * - the calling contract must have an ETH balance of at least `value`.
         * - the called Solidity function must be `payable`.
         *
         * _Available since v3.1._
         */
        function functionCallWithValue(
            address target,
            bytes memory data,
            uint256 value
        ) internal returns (bytes memory) {
            return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
        }
        /**
         * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
         * with `errorMessage` as a fallback revert reason when `target` reverts.
         *
         * _Available since v3.1._
         */
        function functionCallWithValue(
            address target,
            bytes memory data,
            uint256 value,
            string memory errorMessage
        ) internal returns (bytes memory) {
            require(address(this).balance >= value, "Address: insufficient balance for call");
            require(isContract(target), "Address: call to non-contract");
            (bool success, bytes memory returndata) = target.call{value: value}(data);
            return _verifyCallResult(success, returndata, errorMessage);
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but performing a static call.
         *
         * _Available since v3.3._
         */
        function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
            return functionStaticCall(target, data, "Address: low-level static call failed");
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
         * but performing a static call.
         *
         * _Available since v3.3._
         */
        function functionStaticCall(
            address target,
            bytes memory data,
            string memory errorMessage
        ) internal view returns (bytes memory) {
            require(isContract(target), "Address: static call to non-contract");
            (bool success, bytes memory returndata) = target.staticcall(data);
            return _verifyCallResult(success, returndata, errorMessage);
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but performing a delegate call.
         *
         * _Available since v3.4._
         */
        function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
            return functionDelegateCall(target, data, "Address: low-level delegate call failed");
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
         * but performing a delegate call.
         *
         * _Available since v3.4._
         */
        function functionDelegateCall(
            address target,
            bytes memory data,
            string memory errorMessage
        ) internal returns (bytes memory) {
            require(isContract(target), "Address: delegate call to non-contract");
            (bool success, bytes memory returndata) = target.delegatecall(data);
            return _verifyCallResult(success, returndata, errorMessage);
        }
        function _verifyCallResult(
            bool success,
            bytes memory returndata,
            string memory errorMessage
        ) private pure returns (bytes memory) {
            if (success) {
                return returndata;
            } else {
                // Look for revert reason and bubble it up if present
                if (returndata.length > 0) {
                    // The easiest way to bubble the revert reason is using memory via assembly
                    assembly {
                        let returndata_size := mload(returndata)
                        revert(add(32, returndata), returndata_size)
                    }
                } else {
                    revert(errorMessage);
                }
            }
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    /**
     * @dev These functions deal with verification of Merkle Trees proofs.
     *
     * The proofs can be generated using the JavaScript library
     * https://github.com/miguelmota/merkletreejs[merkletreejs].
     * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.
     *
     * See `test/utils/cryptography/MerkleProof.test.js` for some examples.
     */
    library MerkleProof {
        /**
         * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
         * defined by `root`. For this, a `proof` must be provided, containing
         * sibling hashes on the branch from the leaf to the root of the tree. Each
         * pair of leaves and each pair of pre-images are assumed to be sorted.
         */
        function verify(
            bytes32[] memory proof,
            bytes32 root,
            bytes32 leaf
        ) internal pure returns (bool) {
            bytes32 computedHash = leaf;
            for (uint256 i = 0; i < proof.length; i++) {
                bytes32 proofElement = proof[i];
                if (computedHash <= proofElement) {
                    // Hash(current computed hash + current element of the proof)
                    computedHash = keccak256(abi.encodePacked(computedHash, proofElement));
                } else {
                    // Hash(current element of the proof + current computed hash)
                    computedHash = keccak256(abi.encodePacked(proofElement, computedHash));
                }
            }
            // Check if the computed hash (root) is equal to the provided root
            return computedHash == root;
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.6;
    import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
    import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
    /**
     * @title RetroactiveVesting
     * @notice A token holder contract that can release its token balance linearly over
     * the vesting period of 2 years. Respective address and the amount are included in each merkle node.
     */
    contract RetroactiveVesting {
        using SafeERC20 for IERC20;
        struct VestingData {
            bool isVerified;
            uint120 totalAmount;
            uint120 released;
        }
        event Claimed(address indexed account, uint256 amount);
        // Address of the token that is subject to vesting
        IERC20 public immutable token;
        // Merkle root used to verify the beneficiary address and the amount of the tokens
        bytes32 public immutable merkleRoot;
        // Epoch unix timestamp in seconds when the vesting starts to decay
        uint256 public immutable startTimestamp;
        // Vesting period of 2 years
        uint256 public constant DURATION = 2 * (52 weeks);
        mapping(address => VestingData) public vestings;
        /**
         * @notice Deploys this contract with given parameters
         * @dev The information about the method used to generate the merkle root and how to replicate it
         * can be found on https://docs.saddle.finance.
         * @param token_ Address of the token that will be vested
         * @param merkleRoot_ Bytes of the merkle root node which is generated off chain.
         * @param startTimestamp_ Timestamp in seconds when to start vesting. This can be backdated as well.
         */
        constructor(
            IERC20 token_,
            bytes32 merkleRoot_,
            uint256 startTimestamp_
        ) public {
            require(address(token_) != address(0), "token_ cannot be empty");
            require(merkleRoot_[0] != 0, "merkleRoot_ cannot be empty");
            require(startTimestamp_ != 0, "startTimestamp_ cannot be 0");
            token = token_;
            merkleRoot = merkleRoot_;
            startTimestamp = startTimestamp_;
        }
        /**
         * @notice Verifies the given account is eligible for the given amount. Then claims the
         * vested amount out of the total amount eligible.
         * @param account Address of the account that the caller is verifying for
         * @param totalAmount Total amount that will be vested linearly
         * @param merkleProof Merkle proof that was generated off chain.
         */
        function verifyAndClaimReward(
            address account,
            uint256 totalAmount,
            bytes32[] calldata merkleProof
        ) external {
            require(
                totalAmount > 0 && totalAmount < type(uint120).max,
                "totalAmount cannot be 0 or larger than max uint120 value"
            );
            VestingData storage vesting = vestings[account];
            if (!vesting.isVerified) {
                // Verify the merkle proof.
                bytes32 node = keccak256(abi.encodePacked(account, totalAmount));
                require(
                    MerkleProof.verify(merkleProof, merkleRoot, node),
                    "could not verify merkleProof"
                );
                // Save the verified state
                vesting.isVerified = true;
                vesting.totalAmount = uint120(totalAmount);
            }
            _claimReward(account);
        }
        /**
         * @notice Claims the vested amount out of the total amount eligible for the given account.
         * @param account Address of the account that the caller is claiming for. If this is set
         * to `address(0)`, it will use the `msg.sender` instead.
         */
        function claimReward(address account) external {
            if (account == address(0)) {
                account = msg.sender;
            }
            require(vestings[account].isVerified, "must verify first");
            _claimReward(account);
        }
        function _claimReward(address account) internal {
            VestingData storage vesting = vestings[account];
            uint256 released = vesting.released;
            uint256 amount = _vestedAmount(
                vesting.totalAmount,
                released,
                startTimestamp,
                DURATION
            );
            uint256 newReleased = amount + released;
            require(
                newReleased < type(uint120).max,
                "newReleased is too big to be cast uint120"
            );
            vesting.released = uint120(newReleased);
            token.safeTransfer(account, amount);
            emit Claimed(account, amount);
        }
        /**
         * @notice Calculated the amount that has already vested but hasn't been released yet.
         * Reverts if the given account has not been verified.
         * @param account Address to calculate the vested amount for
         */
        function vestedAmount(address account) external view returns (uint256) {
            require(vestings[account].isVerified, "must verify first");
            return
                _vestedAmount(
                    vestings[account].totalAmount,
                    vestings[account].released,
                    startTimestamp,
                    DURATION
                );
        }
        /**
         * @notice Calculates the amount that has already vested but hasn't been released yet.
         */
        function _vestedAmount(
            uint256 total,
            uint256 released,
            uint256 startTimestamp,
            uint256 durationInSeconds
        ) internal view returns (uint256) {
            uint256 blockTimestamp = block.timestamp;
            // If current block is before the start, there are no vested amount.
            if (blockTimestamp < startTimestamp) {
                return 0;
            }
            uint256 elapsedTime = blockTimestamp - startTimestamp;
            uint256 vested;
            // If over vesting duration, all tokens vested
            if (elapsedTime >= durationInSeconds) {
                vested = total;
            } else {
                vested = (total * elapsedTime) / durationInSeconds;
            }
            return vested - released;
        }
    }
    

    File 2 of 2: SDL
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    /**
     * @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 a proxied contract can't have 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.
     *
     * 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.
     */
    abstract contract Initializable {
        /**
         * @dev Indicates that the contract has been initialized.
         */
        bool private _initialized;
        /**
         * @dev Indicates that the contract is in the process of being initialized.
         */
        bool private _initializing;
        /**
         * @dev Modifier to protect an initializer function from being invoked twice.
         */
        modifier initializer() {
            require(_initializing || !_initialized, "Initializable: contract is already initialized");
            bool isTopLevelCall = !_initializing;
            if (isTopLevelCall) {
                _initializing = true;
                _initialized = true;
            }
            _;
            if (isTopLevelCall) {
                _initializing = false;
            }
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    /**
     * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for
     * deploying minimal proxy contracts, also known as "clones".
     *
     * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
     * > a minimal bytecode implementation that delegates all calls to a known, fixed address.
     *
     * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
     * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
     * deterministic method.
     *
     * _Available since v3.4._
     */
    library Clones {
        /**
         * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
         *
         * This function uses the create opcode, which should never revert.
         */
        function clone(address implementation) internal returns (address instance) {
            assembly {
                let ptr := mload(0x40)
                mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
                mstore(add(ptr, 0x14), shl(0x60, implementation))
                mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
                instance := create(0, ptr, 0x37)
            }
            require(instance != address(0), "ERC1167: create failed");
        }
        /**
         * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
         *
         * This function uses the create2 opcode and a `salt` to deterministically deploy
         * the clone. Using the same `implementation` and `salt` multiple time will revert, since
         * the clones cannot be deployed twice at the same address.
         */
        function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
            assembly {
                let ptr := mload(0x40)
                mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
                mstore(add(ptr, 0x14), shl(0x60, implementation))
                mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
                instance := create2(0, ptr, 0x37, salt)
            }
            require(instance != address(0), "ERC1167: create2 failed");
        }
        /**
         * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
         */
        function predictDeterministicAddress(
            address implementation,
            bytes32 salt,
            address deployer
        ) internal pure returns (address predicted) {
            assembly {
                let ptr := mload(0x40)
                mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
                mstore(add(ptr, 0x14), shl(0x60, implementation))
                mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000)
                mstore(add(ptr, 0x38), shl(0x60, deployer))
                mstore(add(ptr, 0x4c), salt)
                mstore(add(ptr, 0x6c), keccak256(ptr, 0x37))
                predicted := keccak256(add(ptr, 0x37), 0x55)
            }
        }
        /**
         * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
         */
        function predictDeterministicAddress(address implementation, bytes32 salt)
            internal
            view
            returns (address predicted)
        {
            return predictDeterministicAddress(implementation, salt, address(this));
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    import "../utils/Context.sol";
    /**
     * @dev Contract module which allows children to implement an emergency stop
     * mechanism that can be triggered by an authorized account.
     *
     * This module is used through inheritance. It will make available the
     * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
     * the functions of your contract. Note that they will not be pausable by
     * simply including this module, only once the modifiers are put in place.
     */
    abstract contract Pausable is Context {
        /**
         * @dev Emitted when the pause is triggered by `account`.
         */
        event Paused(address account);
        /**
         * @dev Emitted when the pause is lifted by `account`.
         */
        event Unpaused(address account);
        bool private _paused;
        /**
         * @dev Initializes the contract in unpaused state.
         */
        constructor() {
            _paused = false;
        }
        /**
         * @dev Returns true if the contract is paused, and false otherwise.
         */
        function paused() public view virtual returns (bool) {
            return _paused;
        }
        /**
         * @dev Modifier to make a function callable only when the contract is not paused.
         *
         * Requirements:
         *
         * - The contract must not be paused.
         */
        modifier whenNotPaused() {
            require(!paused(), "Pausable: paused");
            _;
        }
        /**
         * @dev Modifier to make a function callable only when the contract is paused.
         *
         * Requirements:
         *
         * - The contract must be paused.
         */
        modifier whenPaused() {
            require(paused(), "Pausable: not paused");
            _;
        }
        /**
         * @dev Triggers stopped state.
         *
         * Requirements:
         *
         * - The contract must not be paused.
         */
        function _pause() internal virtual whenNotPaused {
            _paused = true;
            emit Paused(_msgSender());
        }
        /**
         * @dev Returns to normal state.
         *
         * Requirements:
         *
         * - The contract must be paused.
         */
        function _unpause() internal virtual whenPaused {
            _paused = false;
            emit Unpaused(_msgSender());
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    import "./IERC20.sol";
    import "./extensions/IERC20Metadata.sol";
    import "../../utils/Context.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.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
     * to implement supply mechanisms].
     *
     * We have followed general OpenZeppelin guidelines: functions revert instead
     * of 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 ERC20 is Context, IERC20, IERC20Metadata {
        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}.
         *
         * The default value of {decimals} is 18. To select a different value for
         * {decimals} you should overload it.
         *
         * All two of these values are immutable: they can only be set once during
         * construction.
         */
        constructor(string memory name_, string memory symbol_) {
            _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 value {ERC20} uses, unless this function is
         * 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:
         *
         * - `recipient` cannot be the zero address.
         * - the caller must have a balance of at least `amount`.
         */
        function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
            _transfer(_msgSender(), recipient, 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}.
         *
         * Requirements:
         *
         * - `spender` cannot be the zero address.
         */
        function approve(address spender, uint256 amount) public virtual override returns (bool) {
            _approve(_msgSender(), 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}.
         *
         * Requirements:
         *
         * - `sender` and `recipient` cannot be the zero address.
         * - `sender` must have a balance of at least `amount`.
         * - the caller must have allowance for ``sender``'s tokens of at least
         * `amount`.
         */
        function transferFrom(
            address sender,
            address recipient,
            uint256 amount
        ) public virtual override returns (bool) {
            _transfer(sender, recipient, amount);
            uint256 currentAllowance = _allowances[sender][_msgSender()];
            require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance");
            unchecked {
                _approve(sender, _msgSender(), currentAllowance - 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) {
            _approve(_msgSender(), spender, _allowances[_msgSender()][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) {
            uint256 currentAllowance = _allowances[_msgSender()][spender];
            require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
            unchecked {
                _approve(_msgSender(), spender, currentAllowance - subtractedValue);
            }
            return true;
        }
        /**
         * @dev Moves `amount` of tokens from `sender` to `recipient`.
         *
         * 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:
         *
         * - `sender` cannot be the zero address.
         * - `recipient` cannot be the zero address.
         * - `sender` must have a balance of at least `amount`.
         */
        function _transfer(
            address sender,
            address recipient,
            uint256 amount
        ) internal virtual {
            require(sender != address(0), "ERC20: transfer from the zero address");
            require(recipient != address(0), "ERC20: transfer to the zero address");
            _beforeTokenTransfer(sender, recipient, amount);
            uint256 senderBalance = _balances[sender];
            require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");
            unchecked {
                _balances[sender] = senderBalance - amount;
            }
            _balances[recipient] += amount;
            emit Transfer(sender, recipient, amount);
            _afterTokenTransfer(sender, recipient, 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;
            _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;
            }
            _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 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 {}
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    /**
     * @dev Interface of the ERC20 standard as defined in the EIP.
     */
    interface IERC20 {
        /**
         * @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 `recipient`.
         *
         * Returns a boolean value indicating whether the operation succeeded.
         *
         * Emits a {Transfer} event.
         */
        function transfer(address recipient, 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 `sender` to `recipient` 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 sender,
            address recipient,
            uint256 amount
        ) external returns (bool);
        /**
         * @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);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    import "./draft-ERC20Permit.sol";
    import "../../../utils/math/Math.sol";
    import "../../../utils/math/SafeCast.sol";
    import "../../../utils/cryptography/ECDSA.sol";
    /**
     * @dev Extension of ERC20 to support Compound-like voting and delegation. This version is more generic than Compound's,
     * and supports token supply up to 2^224^ - 1, while COMP is limited to 2^96^ - 1.
     *
     * NOTE: If exact COMP compatibility is required, use the {ERC20VotesComp} variant of this module.
     *
     * This extension keeps a history (checkpoints) of each account's vote power. Vote power can be delegated either
     * by calling the {delegate} function directly, or by providing a signature to be used with {delegateBySig}. Voting
     * power can be queried through the public accessors {getVotes} and {getPastVotes}.
     *
     * By default, token balance does not account for voting power. This makes transfers cheaper. The downside is that it
     * requires users to delegate to themselves in order to activate checkpoints and have their voting power tracked.
     * Enabling self-delegation can easily be done by overriding the {delegates} function. Keep in mind however that this
     * will significantly increase the base gas cost of transfers.
     *
     * _Available since v4.2._
     */
    abstract contract ERC20Votes is ERC20Permit {
        struct Checkpoint {
            uint32 fromBlock;
            uint224 votes;
        }
        bytes32 private constant _DELEGATION_TYPEHASH =
            keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");
        mapping(address => address) private _delegates;
        mapping(address => Checkpoint[]) private _checkpoints;
        Checkpoint[] private _totalSupplyCheckpoints;
        /**
         * @dev Emitted when an account changes their delegate.
         */
        event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);
        /**
         * @dev Emitted when a token transfer or delegate change results in changes to an account's voting power.
         */
        event DelegateVotesChanged(address indexed delegate, uint256 previousBalance, uint256 newBalance);
        /**
         * @dev Get the `pos`-th checkpoint for `account`.
         */
        function checkpoints(address account, uint32 pos) public view virtual returns (Checkpoint memory) {
            return _checkpoints[account][pos];
        }
        /**
         * @dev Get number of checkpoints for `account`.
         */
        function numCheckpoints(address account) public view virtual returns (uint32) {
            return SafeCast.toUint32(_checkpoints[account].length);
        }
        /**
         * @dev Get the address `account` is currently delegating to.
         */
        function delegates(address account) public view virtual returns (address) {
            return _delegates[account];
        }
        /**
         * @dev Gets the current votes balance for `account`
         */
        function getVotes(address account) public view returns (uint256) {
            uint256 pos = _checkpoints[account].length;
            return pos == 0 ? 0 : _checkpoints[account][pos - 1].votes;
        }
        /**
         * @dev Retrieve the number of votes for `account` at the end of `blockNumber`.
         *
         * Requirements:
         *
         * - `blockNumber` must have been already mined
         */
        function getPastVotes(address account, uint256 blockNumber) public view returns (uint256) {
            require(blockNumber < block.number, "ERC20Votes: block not yet mined");
            return _checkpointsLookup(_checkpoints[account], blockNumber);
        }
        /**
         * @dev Retrieve the `totalSupply` at the end of `blockNumber`. Note, this value is the sum of all balances.
         * It is but NOT the sum of all the delegated votes!
         *
         * Requirements:
         *
         * - `blockNumber` must have been already mined
         */
        function getPastTotalSupply(uint256 blockNumber) public view returns (uint256) {
            require(blockNumber < block.number, "ERC20Votes: block not yet mined");
            return _checkpointsLookup(_totalSupplyCheckpoints, blockNumber);
        }
        /**
         * @dev Lookup a value in a list of (sorted) checkpoints.
         */
        function _checkpointsLookup(Checkpoint[] storage ckpts, uint256 blockNumber) private view returns (uint256) {
            // We run a binary search to look for the earliest checkpoint taken after `blockNumber`.
            //
            // During the loop, the index of the wanted checkpoint remains in the range [low, high).
            // With each iteration, either `low` or `high` is moved towards the middle of the range to maintain the invariant.
            // - If the middle checkpoint is after `blockNumber`, we look in [low, mid)
            // - If the middle checkpoint is before `blockNumber`, we look in [mid+1, high)
            // Once we reach a single value (when low == high), we've found the right checkpoint at the index high-1, if not
            // out of bounds (in which case we're looking too far in the past and the result is 0).
            // Note that if the latest checkpoint available is exactly for `blockNumber`, we end up with an index that is
            // past the end of the array, so we technically don't find a checkpoint after `blockNumber`, but it works out
            // the same.
            uint256 high = ckpts.length;
            uint256 low = 0;
            while (low < high) {
                uint256 mid = Math.average(low, high);
                if (ckpts[mid].fromBlock > blockNumber) {
                    high = mid;
                } else {
                    low = mid + 1;
                }
            }
            return high == 0 ? 0 : ckpts[high - 1].votes;
        }
        /**
         * @dev Delegate votes from the sender to `delegatee`.
         */
        function delegate(address delegatee) public virtual {
            return _delegate(_msgSender(), delegatee);
        }
        /**
         * @dev Delegates votes from signer to `delegatee`
         */
        function delegateBySig(
            address delegatee,
            uint256 nonce,
            uint256 expiry,
            uint8 v,
            bytes32 r,
            bytes32 s
        ) public virtual {
            require(block.timestamp <= expiry, "ERC20Votes: signature expired");
            address signer = ECDSA.recover(
                _hashTypedDataV4(keccak256(abi.encode(_DELEGATION_TYPEHASH, delegatee, nonce, expiry))),
                v,
                r,
                s
            );
            require(nonce == _useNonce(signer), "ERC20Votes: invalid nonce");
            return _delegate(signer, delegatee);
        }
        /**
         * @dev Maximum token supply. Defaults to `type(uint224).max` (2^224^ - 1).
         */
        function _maxSupply() internal view virtual returns (uint224) {
            return type(uint224).max;
        }
        /**
         * @dev Snapshots the totalSupply after it has been increased.
         */
        function _mint(address account, uint256 amount) internal virtual override {
            super._mint(account, amount);
            require(totalSupply() <= _maxSupply(), "ERC20Votes: total supply risks overflowing votes");
            _writeCheckpoint(_totalSupplyCheckpoints, _add, amount);
        }
        /**
         * @dev Snapshots the totalSupply after it has been decreased.
         */
        function _burn(address account, uint256 amount) internal virtual override {
            super._burn(account, amount);
            _writeCheckpoint(_totalSupplyCheckpoints, _subtract, amount);
        }
        /**
         * @dev Move voting power when tokens are transferred.
         *
         * Emits a {DelegateVotesChanged} event.
         */
        function _afterTokenTransfer(
            address from,
            address to,
            uint256 amount
        ) internal virtual override {
            super._afterTokenTransfer(from, to, amount);
            _moveVotingPower(delegates(from), delegates(to), amount);
        }
        /**
         * @dev Change delegation for `delegator` to `delegatee`.
         *
         * Emits events {DelegateChanged} and {DelegateVotesChanged}.
         */
        function _delegate(address delegator, address delegatee) internal virtual {
            address currentDelegate = delegates(delegator);
            uint256 delegatorBalance = balanceOf(delegator);
            _delegates[delegator] = delegatee;
            emit DelegateChanged(delegator, currentDelegate, delegatee);
            _moveVotingPower(currentDelegate, delegatee, delegatorBalance);
        }
        function _moveVotingPower(
            address src,
            address dst,
            uint256 amount
        ) private {
            if (src != dst && amount > 0) {
                if (src != address(0)) {
                    (uint256 oldWeight, uint256 newWeight) = _writeCheckpoint(_checkpoints[src], _subtract, amount);
                    emit DelegateVotesChanged(src, oldWeight, newWeight);
                }
                if (dst != address(0)) {
                    (uint256 oldWeight, uint256 newWeight) = _writeCheckpoint(_checkpoints[dst], _add, amount);
                    emit DelegateVotesChanged(dst, oldWeight, newWeight);
                }
            }
        }
        function _writeCheckpoint(
            Checkpoint[] storage ckpts,
            function(uint256, uint256) view returns (uint256) op,
            uint256 delta
        ) private returns (uint256 oldWeight, uint256 newWeight) {
            uint256 pos = ckpts.length;
            oldWeight = pos == 0 ? 0 : ckpts[pos - 1].votes;
            newWeight = op(oldWeight, delta);
            if (pos > 0 && ckpts[pos - 1].fromBlock == block.number) {
                ckpts[pos - 1].votes = SafeCast.toUint224(newWeight);
            } else {
                ckpts.push(Checkpoint({fromBlock: SafeCast.toUint32(block.number), votes: SafeCast.toUint224(newWeight)}));
            }
        }
        function _add(uint256 a, uint256 b) private pure returns (uint256) {
            return a + b;
        }
        function _subtract(uint256 a, uint256 b) private pure returns (uint256) {
            return a - b;
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    import "./ERC20Votes.sol";
    /**
     * @dev Extension of ERC20 to support Compound's voting and delegation. This version exactly matches Compound's
     * interface, with the drawback of only supporting supply up to (2^96^ - 1).
     *
     * NOTE: You should use this contract if you need exact compatibility with COMP (for example in order to use your token
     * with Governor Alpha or Bravo) and if you are sure the supply cap of 2^96^ is enough for you. Otherwise, use the
     * {ERC20Votes} variant of this module.
     *
     * This extensions keeps a history (checkpoints) of each account's vote power. Vote power can be delegated either
     * by calling the {delegate} function directly, or by providing a signature to be used with {delegateBySig}. Voting
     * power can be queried through the public accessors {getCurrentVotes} and {getPriorVotes}.
     *
     * By default, token balance does not account for voting power. This makes transfers cheaper. The downside is that it
     * requires users to delegate to themselves in order to activate checkpoints and have their voting power tracked.
     * Enabling self-delegation can easily be done by overriding the {delegates} function. Keep in mind however that this
     * will significantly increase the base gas cost of transfers.
     *
     * _Available since v4.2._
     */
    abstract contract ERC20VotesComp is ERC20Votes {
        /**
         * @dev Comp version of the {getVotes} accessor, with `uint96` return type.
         */
        function getCurrentVotes(address account) external view returns (uint96) {
            return SafeCast.toUint96(getVotes(account));
        }
        /**
         * @dev Comp version of the {getPastVotes} accessor, with `uint96` return type.
         */
        function getPriorVotes(address account, uint256 blockNumber) external view returns (uint96) {
            return SafeCast.toUint96(getPastVotes(account, blockNumber));
        }
        /**
         * @dev Maximum token supply. Reduced to `type(uint96).max` (2^96^ - 1) to fit COMP interface.
         */
        function _maxSupply() internal view virtual override returns (uint224) {
            return type(uint96).max;
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    import "../IERC20.sol";
    /**
     * @dev Interface for the optional metadata functions from the ERC20 standard.
     *
     * _Available since v4.1._
     */
    interface IERC20Metadata is IERC20 {
        /**
         * @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);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    import "./draft-IERC20Permit.sol";
    import "../ERC20.sol";
    import "../../../utils/cryptography/draft-EIP712.sol";
    import "../../../utils/cryptography/ECDSA.sol";
    import "../../../utils/Counters.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._
     */
    abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 {
        using Counters for Counters.Counter;
        mapping(address => Counters.Counter) private _nonces;
        // solhint-disable-next-line var-name-mixedcase
        bytes32 private immutable _PERMIT_TYPEHASH =
            keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
        /**
         * @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.
         */
        constructor(string memory name) EIP712(name, "1") {}
        /**
         * @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 = ECDSA.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) {
            Counters.Counter storage nonce = _nonces[owner];
            current = nonce.current();
            nonce.increment();
        }
    }
    // SPDX-License-Identifier: MIT
    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 IERC20Permit {
        /**
         * @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);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    import "../IERC20.sol";
    import "../../../utils/Address.sol";
    /**
     * @title SafeERC20
     * @dev Wrappers around ERC20 operations that throw on failure (when the token
     * contract returns false). Tokens that return no value (and instead revert or
     * throw on failure) are also supported, non-reverting calls are assumed to be
     * successful.
     * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
     * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
     */
    library SafeERC20 {
        using Address for address;
        function safeTransfer(
            IERC20 token,
            address to,
            uint256 value
        ) internal {
            _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
        }
        function safeTransferFrom(
            IERC20 token,
            address from,
            address to,
            uint256 value
        ) internal {
            _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
        }
        /**
         * @dev Deprecated. This function has issues similar to the ones found in
         * {IERC20-approve}, and its usage is discouraged.
         *
         * Whenever possible, use {safeIncreaseAllowance} and
         * {safeDecreaseAllowance} instead.
         */
        function safeApprove(
            IERC20 token,
            address spender,
            uint256 value
        ) internal {
            // safeApprove should only be called when setting an initial allowance,
            // or when resetting it to zero. To increase and decrease it, use
            // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
            require(
                (value == 0) || (token.allowance(address(this), spender) == 0),
                "SafeERC20: approve from non-zero to non-zero allowance"
            );
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
        }
        function safeIncreaseAllowance(
            IERC20 token,
            address spender,
            uint256 value
        ) internal {
            uint256 newAllowance = token.allowance(address(this), spender) + value;
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
        function safeDecreaseAllowance(
            IERC20 token,
            address spender,
            uint256 value
        ) internal {
            unchecked {
                uint256 oldAllowance = token.allowance(address(this), spender);
                require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
                uint256 newAllowance = oldAllowance - value;
                _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
            }
        }
        /**
         * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
         * on the return value: the return value is optional (but if data is returned, it must not be false).
         * @param token The token targeted by the call.
         * @param data The call data (encoded using abi.encode or one of its variants).
         */
        function _callOptionalReturn(IERC20 token, bytes memory data) private {
            // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
            // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
            // the target address contains contract code and also asserts for success in the low-level call.
            bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
            if (returndata.length > 0) {
                // Return data is optional
                require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
            }
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    /**
     * @dev Collection of functions related to the address type
     */
    library Address {
        /**
         * @dev Returns true if `account` is a contract.
         *
         * [IMPORTANT]
         * ====
         * It is unsafe to assume that an address for which this function returns
         * false is an externally-owned account (EOA) and not a contract.
         *
         * Among others, `isContract` will return false for the following
         * types of addresses:
         *
         *  - an externally-owned account
         *  - a contract in construction
         *  - an address where a contract will be created
         *  - an address where a contract lived, but was destroyed
         * ====
         */
        function isContract(address account) internal view returns (bool) {
            // This method relies on extcodesize, which returns 0 for contracts in
            // construction, since the code is only stored at the end of the
            // constructor execution.
            uint256 size;
            assembly {
                size := extcodesize(account)
            }
            return size > 0;
        }
        /**
         * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
         * `recipient`, forwarding all available gas and reverting on errors.
         *
         * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
         * of certain opcodes, possibly making contracts go over the 2300 gas limit
         * imposed by `transfer`, making them unable to receive funds via
         * `transfer`. {sendValue} removes this limitation.
         *
         * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
         *
         * IMPORTANT: because control is transferred to `recipient`, care must be
         * taken to not create reentrancy vulnerabilities. Consider using
         * {ReentrancyGuard} or the
         * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
         */
        function sendValue(address payable recipient, uint256 amount) internal {
            require(address(this).balance >= amount, "Address: insufficient balance");
            (bool success, ) = recipient.call{value: amount}("");
            require(success, "Address: unable to send value, recipient may have reverted");
        }
        /**
         * @dev Performs a Solidity function call using a low level `call`. A
         * plain `call` is an unsafe replacement for a function call: use this
         * function instead.
         *
         * If `target` reverts with a revert reason, it is bubbled up by this
         * function (like regular Solidity function calls).
         *
         * Returns the raw returned data. To convert to the expected return value,
         * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
         *
         * Requirements:
         *
         * - `target` must be a contract.
         * - calling `target` with `data` must not revert.
         *
         * _Available since v3.1._
         */
        function functionCall(address target, bytes memory data) internal returns (bytes memory) {
            return functionCall(target, data, "Address: low-level call failed");
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
         * `errorMessage` as a fallback revert reason when `target` reverts.
         *
         * _Available since v3.1._
         */
        function functionCall(
            address target,
            bytes memory data,
            string memory errorMessage
        ) internal returns (bytes memory) {
            return functionCallWithValue(target, data, 0, errorMessage);
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but also transferring `value` wei to `target`.
         *
         * Requirements:
         *
         * - the calling contract must have an ETH balance of at least `value`.
         * - the called Solidity function must be `payable`.
         *
         * _Available since v3.1._
         */
        function functionCallWithValue(
            address target,
            bytes memory data,
            uint256 value
        ) internal returns (bytes memory) {
            return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
        }
        /**
         * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
         * with `errorMessage` as a fallback revert reason when `target` reverts.
         *
         * _Available since v3.1._
         */
        function functionCallWithValue(
            address target,
            bytes memory data,
            uint256 value,
            string memory errorMessage
        ) internal returns (bytes memory) {
            require(address(this).balance >= value, "Address: insufficient balance for call");
            require(isContract(target), "Address: call to non-contract");
            (bool success, bytes memory returndata) = target.call{value: value}(data);
            return _verifyCallResult(success, returndata, errorMessage);
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but performing a static call.
         *
         * _Available since v3.3._
         */
        function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
            return functionStaticCall(target, data, "Address: low-level static call failed");
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
         * but performing a static call.
         *
         * _Available since v3.3._
         */
        function functionStaticCall(
            address target,
            bytes memory data,
            string memory errorMessage
        ) internal view returns (bytes memory) {
            require(isContract(target), "Address: static call to non-contract");
            (bool success, bytes memory returndata) = target.staticcall(data);
            return _verifyCallResult(success, returndata, errorMessage);
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but performing a delegate call.
         *
         * _Available since v3.4._
         */
        function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
            return functionDelegateCall(target, data, "Address: low-level delegate call failed");
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
         * but performing a delegate call.
         *
         * _Available since v3.4._
         */
        function functionDelegateCall(
            address target,
            bytes memory data,
            string memory errorMessage
        ) internal returns (bytes memory) {
            require(isContract(target), "Address: delegate call to non-contract");
            (bool success, bytes memory returndata) = target.delegatecall(data);
            return _verifyCallResult(success, returndata, errorMessage);
        }
        function _verifyCallResult(
            bool success,
            bytes memory returndata,
            string memory errorMessage
        ) private pure returns (bytes memory) {
            if (success) {
                return returndata;
            } else {
                // Look for revert reason and bubble it up if present
                if (returndata.length > 0) {
                    // The easiest way to bubble the revert reason is using memory via assembly
                    assembly {
                        let returndata_size := mload(returndata)
                        revert(add(32, returndata), returndata_size)
                    }
                } else {
                    revert(errorMessage);
                }
            }
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    /*
     * @dev Provides information about the current execution context, including the
     * sender of the transaction and its data. While these are generally available
     * via msg.sender and msg.data, they should not be accessed in such a direct
     * manner, since when dealing with meta-transactions the account sending and
     * paying for execution may not be the actual sender (as far as an application
     * is concerned).
     *
     * This contract is only required for intermediate, library-like contracts.
     */
    abstract contract Context {
        function _msgSender() internal view virtual returns (address) {
            return msg.sender;
        }
        function _msgData() internal view virtual returns (bytes calldata) {
            return msg.data;
        }
    }
    // SPDX-License-Identifier: MIT
    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 Counters {
        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;
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    /**
     * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
     *
     * These functions can be used to verify that a message was signed by the holder
     * of the private keys of a given address.
     */
    library ECDSA {
        /**
         * @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.
         *
         * 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]
         */
        function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
            // Check the signature length
            // - case 65: r,s,v signature (standard)
            // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._
            if (signature.length == 65) {
                bytes32 r;
                bytes32 s;
                uint8 v;
                // ecrecover takes the signature parameters, and the only way to get them
                // currently is to use assembly.
                assembly {
                    r := mload(add(signature, 0x20))
                    s := mload(add(signature, 0x40))
                    v := byte(0, mload(add(signature, 0x60)))
                }
                return recover(hash, v, r, s);
            } else if (signature.length == 64) {
                bytes32 r;
                bytes32 vs;
                // ecrecover takes the signature parameters, and the only way to get them
                // currently is to use assembly.
                assembly {
                    r := mload(add(signature, 0x20))
                    vs := mload(add(signature, 0x40))
                }
                return recover(hash, r, vs);
            } else {
                revert("ECDSA: invalid signature length");
            }
        }
        /**
         * @dev Overload of {ECDSA-recover} 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.2._
         */
        function recover(
            bytes32 hash,
            bytes32 r,
            bytes32 vs
        ) internal pure returns (address) {
            bytes32 s;
            uint8 v;
            assembly {
                s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
                v := add(shr(255, vs), 27)
            }
            return recover(hash, v, r, s);
        }
        /**
         * @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) {
            // 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 (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): 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.
            require(
                uint256(s) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0,
                "ECDSA: invalid signature 's' value"
            );
            require(v == 27 || v == 28, "ECDSA: invalid signature 'v' value");
            // If the signature is valid (and not malleable), return the signer address
            address signer = ecrecover(hash, v, r, s);
            require(signer != address(0), "ECDSA: invalid signature");
            return signer;
        }
        /**
         * @dev Returns an Ethereum Signed Message, created from a `hash`. This
         * produces hash corresponding to the one signed with the
         * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
         * JSON-RPC method as part of EIP-191.
         *
         * See {recover}.
         */
        function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
            // 32 is the length in bytes of hash,
            // enforced by the type signature above
            return keccak256(abi.encodePacked("\\x19Ethereum Signed Message:\
    32", hash));
        }
        /**
         * @dev Returns an Ethereum Signed Typed Data, created from a
         * `domainSeparator` and a `structHash`. This produces hash corresponding
         * to the one signed with the
         * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
         * JSON-RPC method as part of EIP-712.
         *
         * See {recover}.
         */
        function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
            return keccak256(abi.encodePacked("\\x19\\x01", domainSeparator, structHash));
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    import "./ECDSA.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].
     *
     * _Available since v3.4._
     */
    abstract contract EIP712 {
        /* solhint-disable var-name-mixedcase */
        // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
        // invalidate the cached domain separator if the chain id changes.
        bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;
        uint256 private immutable _CACHED_CHAIN_ID;
        bytes32 private immutable _HASHED_NAME;
        bytes32 private immutable _HASHED_VERSION;
        bytes32 private immutable _TYPE_HASH;
        /* solhint-enable var-name-mixedcase */
        /**
         * @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].
         */
        constructor(string memory name, string memory version) {
            bytes32 hashedName = keccak256(bytes(name));
            bytes32 hashedVersion = keccak256(bytes(version));
            bytes32 typeHash = keccak256(
                "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
            );
            _HASHED_NAME = hashedName;
            _HASHED_VERSION = hashedVersion;
            _CACHED_CHAIN_ID = block.chainid;
            _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);
            _TYPE_HASH = typeHash;
        }
        /**
         * @dev Returns the domain separator for the current chain.
         */
        function _domainSeparatorV4() internal view returns (bytes32) {
            if (block.chainid == _CACHED_CHAIN_ID) {
                return _CACHED_DOMAIN_SEPARATOR;
            } else {
                return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);
            }
        }
        function _buildDomainSeparator(
            bytes32 typeHash,
            bytes32 nameHash,
            bytes32 versionHash
        ) private view returns (bytes32) {
            return keccak256(abi.encode(typeHash, nameHash, versionHash, 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 ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    /**
     * @dev Standard math utilities missing in the Solidity language.
     */
    library Math {
        /**
         * @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, so we distribute.
            return (a / 2) + (b / 2) + (((a % 2) + (b % 2)) / 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 / b + (a % b == 0 ? 0 : 1);
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    /**
     * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
     * checks.
     *
     * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
     * easily result in undesired exploitation or bugs, since developers usually
     * assume that overflows raise errors. `SafeCast` restores this intuition by
     * reverting the transaction when such an operation overflows.
     *
     * Using this library instead of the unchecked operations eliminates an entire
     * class of bugs, so it's recommended to use it always.
     *
     * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
     * all math on `uint256` and `int256` and then downcasting.
     */
    library SafeCast {
        /**
         * @dev Returns the downcasted uint224 from uint256, reverting on
         * overflow (when the input is greater than largest uint224).
         *
         * Counterpart to Solidity's `uint224` operator.
         *
         * Requirements:
         *
         * - input must fit into 224 bits
         */
        function toUint224(uint256 value) internal pure returns (uint224) {
            require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
            return uint224(value);
        }
        /**
         * @dev Returns the downcasted uint128 from uint256, reverting on
         * overflow (when the input is greater than largest uint128).
         *
         * Counterpart to Solidity's `uint128` operator.
         *
         * Requirements:
         *
         * - input must fit into 128 bits
         */
        function toUint128(uint256 value) internal pure returns (uint128) {
            require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
            return uint128(value);
        }
        /**
         * @dev Returns the downcasted uint96 from uint256, reverting on
         * overflow (when the input is greater than largest uint96).
         *
         * Counterpart to Solidity's `uint96` operator.
         *
         * Requirements:
         *
         * - input must fit into 96 bits
         */
        function toUint96(uint256 value) internal pure returns (uint96) {
            require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
            return uint96(value);
        }
        /**
         * @dev Returns the downcasted uint64 from uint256, reverting on
         * overflow (when the input is greater than largest uint64).
         *
         * Counterpart to Solidity's `uint64` operator.
         *
         * Requirements:
         *
         * - input must fit into 64 bits
         */
        function toUint64(uint256 value) internal pure returns (uint64) {
            require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
            return uint64(value);
        }
        /**
         * @dev Returns the downcasted uint32 from uint256, reverting on
         * overflow (when the input is greater than largest uint32).
         *
         * Counterpart to Solidity's `uint32` operator.
         *
         * Requirements:
         *
         * - input must fit into 32 bits
         */
        function toUint32(uint256 value) internal pure returns (uint32) {
            require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
            return uint32(value);
        }
        /**
         * @dev Returns the downcasted uint16 from uint256, reverting on
         * overflow (when the input is greater than largest uint16).
         *
         * Counterpart to Solidity's `uint16` operator.
         *
         * Requirements:
         *
         * - input must fit into 16 bits
         */
        function toUint16(uint256 value) internal pure returns (uint16) {
            require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
            return uint16(value);
        }
        /**
         * @dev Returns the downcasted uint8 from uint256, reverting on
         * overflow (when the input is greater than largest uint8).
         *
         * Counterpart to Solidity's `uint8` operator.
         *
         * Requirements:
         *
         * - input must fit into 8 bits.
         */
        function toUint8(uint256 value) internal pure returns (uint8) {
            require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
            return uint8(value);
        }
        /**
         * @dev Converts a signed int256 into an unsigned uint256.
         *
         * Requirements:
         *
         * - input must be greater than or equal to 0.
         */
        function toUint256(int256 value) internal pure returns (uint256) {
            require(value >= 0, "SafeCast: value must be positive");
            return uint256(value);
        }
        /**
         * @dev Returns the downcasted int128 from int256, reverting on
         * overflow (when the input is less than smallest int128 or
         * greater than largest int128).
         *
         * Counterpart to Solidity's `int128` operator.
         *
         * Requirements:
         *
         * - input must fit into 128 bits
         *
         * _Available since v3.1._
         */
        function toInt128(int256 value) internal pure returns (int128) {
            require(value >= type(int128).min && value <= type(int128).max, "SafeCast: value doesn't fit in 128 bits");
            return int128(value);
        }
        /**
         * @dev Returns the downcasted int64 from int256, reverting on
         * overflow (when the input is less than smallest int64 or
         * greater than largest int64).
         *
         * Counterpart to Solidity's `int64` operator.
         *
         * Requirements:
         *
         * - input must fit into 64 bits
         *
         * _Available since v3.1._
         */
        function toInt64(int256 value) internal pure returns (int64) {
            require(value >= type(int64).min && value <= type(int64).max, "SafeCast: value doesn't fit in 64 bits");
            return int64(value);
        }
        /**
         * @dev Returns the downcasted int32 from int256, reverting on
         * overflow (when the input is less than smallest int32 or
         * greater than largest int32).
         *
         * Counterpart to Solidity's `int32` operator.
         *
         * Requirements:
         *
         * - input must fit into 32 bits
         *
         * _Available since v3.1._
         */
        function toInt32(int256 value) internal pure returns (int32) {
            require(value >= type(int32).min && value <= type(int32).max, "SafeCast: value doesn't fit in 32 bits");
            return int32(value);
        }
        /**
         * @dev Returns the downcasted int16 from int256, reverting on
         * overflow (when the input is less than smallest int16 or
         * greater than largest int16).
         *
         * Counterpart to Solidity's `int16` operator.
         *
         * Requirements:
         *
         * - input must fit into 16 bits
         *
         * _Available since v3.1._
         */
        function toInt16(int256 value) internal pure returns (int16) {
            require(value >= type(int16).min && value <= type(int16).max, "SafeCast: value doesn't fit in 16 bits");
            return int16(value);
        }
        /**
         * @dev Returns the downcasted int8 from int256, reverting on
         * overflow (when the input is less than smallest int8 or
         * greater than largest int8).
         *
         * Counterpart to Solidity's `int8` operator.
         *
         * Requirements:
         *
         * - input must fit into 8 bits.
         *
         * _Available since v3.1._
         */
        function toInt8(int256 value) internal pure returns (int8) {
            require(value >= type(int8).min && value <= type(int8).max, "SafeCast: value doesn't fit in 8 bits");
            return int8(value);
        }
        /**
         * @dev Converts an unsigned uint256 into a signed int256.
         *
         * Requirements:
         *
         * - input must be less than or equal to maxInt256.
         */
        function toInt256(uint256 value) internal pure returns (int256) {
            // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
            require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
            return int256(value);
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.6;
    import "@openzeppelin/contracts/security/Pausable.sol";
    import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
    import "@openzeppelin/contracts/proxy/Clones.sol";
    import "@openzeppelin/contracts/token/ERC20/extensions/ERC20VotesComp.sol";
    import "./Vesting.sol";
    import "./SimpleGovernance.sol";
    /**
     * @title Saddle DAO token
     * @notice A token that is deployed with fixed amount and appropriate vesting contracts.
     * Transfer is blocked for a period of time until the governance can toggle the transferability.
     */
    contract SDL is ERC20Permit, Pausable, SimpleGovernance {
        using SafeERC20 for IERC20;
        // Token max supply is 1,000,000,000 * 1e18 = 1e27
        uint256 public constant MAX_SUPPLY = 1e9 ether;
        uint256 public immutable govCanUnpauseAfter;
        uint256 public immutable anyoneCanUnpauseAfter;
        address public immutable vestingContractTarget;
        mapping(address => bool) public allowedTransferee;
        event Allowed(address indexed target);
        event Disallowed(address indexed target);
        event VestingContractDeployed(
            address indexed beneficiary,
            address vestingContract
        );
        struct Recipient {
            address to;
            uint256 amount;
            uint256 startTimestamp;
            uint256 cliffPeriod;
            uint256 durationPeriod;
        }
        /**
         * @notice Initializes SDL token with specified governance address and recipients. For vesting
         * durations and amounts, please refer to our documentation on token distribution schedule.
         * @param governance_ address of the governance who will own this contract
         * @param pausePeriod_ time in seconds since the deployment. After this period, this token can be unpaused
         * by the governance.
         * @param vestingContractTarget_ logic contract of Vesting.sol to use for cloning
         */
        constructor(
            address governance_,
            uint256 pausePeriod_,
            address vestingContractTarget_
        ) public ERC20("Saddle DAO", "SDL") ERC20Permit("Saddle DAO") {
            require(governance_ != address(0), "SDL: governance cannot be empty");
            require(
                vestingContractTarget_ != address(0),
                "SDL: vesting contract target cannot be empty"
            );
            require(
                pausePeriod_ > 0 && pausePeriod_ <= 52 weeks,
                "SDL: pausePeriod must be in between 0 and 52 weeks"
            );
            // Set state variables
            vestingContractTarget = vestingContractTarget_;
            governance = governance_;
            govCanUnpauseAfter = block.timestamp + pausePeriod_;
            anyoneCanUnpauseAfter = block.timestamp + 52 weeks;
            // Allow governance to transfer tokens
            allowedTransferee[governance_] = true;
            // Mint tokens to governance
            _mint(governance, MAX_SUPPLY);
            // Pause transfers at deployment
            if (pausePeriod_ > 0) {
                _pause();
            }
            emit SetGovernance(governance_);
        }
        /**
         * @notice Deploys a clone of the vesting contract for the given recipient. Details about vesting and token
         * release schedule can be found on https://docs.saddle.finance
         * @param recipient Recipient of the token through the vesting schedule.
         */
        function deployNewVestingContract(Recipient memory recipient)
            public
            onlyGovernance
            returns (address)
        {
            require(
                recipient.durationPeriod > 0,
                "SDL: duration for vesting cannot be 0"
            );
            // Deploy a clone rather than deploying a whole new contract
            Vesting vestingContract = Vesting(Clones.clone(vestingContractTarget));
            // Initialize the clone contract for the recipient
            vestingContract.initialize(
                address(this),
                recipient.to,
                recipient.startTimestamp,
                recipient.cliffPeriod,
                recipient.durationPeriod
            );
            // Send tokens to the contract
            IERC20(address(this)).safeTransferFrom(
                msg.sender,
                address(vestingContract),
                recipient.amount
            );
            // Add the vesting contract to the allowed transferee list
            allowedTransferee[address(vestingContract)] = true;
            emit Allowed(address(vestingContract));
            emit VestingContractDeployed(recipient.to, address(vestingContract));
            return address(vestingContract);
        }
        /**
         * @notice Changes the transferability of this token.
         * @dev When the transfer is not enabled, only those in allowedTransferee array can
         * transfer this token.
         */
        function enableTransfer() external {
            require(paused(), "SDL: transfer is enabled");
            uint256 unpauseAfter = msg.sender == governance
                ? govCanUnpauseAfter
                : anyoneCanUnpauseAfter;
            require(
                block.timestamp > unpauseAfter,
                "SDL: cannot enable transfer yet"
            );
            _unpause();
        }
        /**
         * @notice Add the given addresses to the list of allowed addresses that can transfer during paused period.
         * Governance will add auxiliary contracts to the allowed list to facilitate distribution during the paused period.
         * @param targets Array of addresses to add
         */
        function addToAllowedList(address[] memory targets)
            external
            onlyGovernance
        {
            for (uint256 i = 0; i < targets.length; i++) {
                allowedTransferee[targets[i]] = true;
                emit Allowed(targets[i]);
            }
        }
        /**
         * @notice Remove the given addresses from the list of allowed addresses that can transfer during paused period.
         * @param targets Array of addresses to remove
         */
        function removeFromAllowedList(address[] memory targets)
            external
            onlyGovernance
        {
            for (uint256 i = 0; i < targets.length; i++) {
                allowedTransferee[targets[i]] = false;
                emit Disallowed(targets[i]);
            }
        }
        function _beforeTokenTransfer(
            address from,
            address to,
            uint256 amount
        ) internal override {
            super._beforeTokenTransfer(from, to, amount);
            require(!paused() || allowedTransferee[from], "SDL: paused");
            require(to != address(this), "SDL: invalid recipient");
        }
        /**
         * @notice Transfers any stuck tokens or ether out to the given destination.
         * @dev Method to claim junk and accidentally sent tokens. This will be only used to rescue
         * tokens that are mistakenly sent by users to this contract.
         * @param token Address of the ERC20 token to transfer out. Set to address(0) to transfer ether instead.
         * @param to Destination address that will receive the tokens.
         * @param balance Amount to transfer out. Set to 0 to select all available amount.
         */
        function rescueTokens(
            IERC20 token,
            address payable to,
            uint256 balance
        ) external onlyGovernance {
            require(to != address(0), "SDL: invalid recipient");
            if (token == IERC20(address(0))) {
                // for Ether
                uint256 totalBalance = address(this).balance;
                balance = balance == 0
                    ? totalBalance
                    : Math.min(totalBalance, balance);
                require(balance > 0, "SDL: trying to send 0 ETH");
                // slither-disable-next-line arbitrary-send
                (bool success, ) = to.call{value: balance}("");
                require(success, "SDL: ETH transfer failed");
            } else {
                // any other erc20
                uint256 totalBalance = token.balanceOf(address(this));
                balance = balance == 0
                    ? totalBalance
                    : Math.min(totalBalance, balance);
                require(balance > 0, "SDL: trying to send 0 balance");
                token.safeTransfer(to, balance);
            }
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.6;
    import "@openzeppelin/contracts/utils/Context.sol";
    abstract contract SimpleGovernance is Context {
        address public governance;
        address public pendingGovernance;
        event SetGovernance(address indexed governance);
        /**
         * @notice Changes governance of this contract
         */
        modifier onlyGovernance() {
            require(
                _msgSender() == governance,
                "only governance can perform this action"
            );
            _;
        }
        /**
         * @notice Changes governance of this contract
         * @dev Only governance can call this function. The new governance must call `acceptGovernance` after.
         * @param newGovernance new address to become the governance
         */
        function changeGovernance(address newGovernance) external onlyGovernance {
            require(
                newGovernance != governance,
                "governance must be different from current one"
            );
            require(newGovernance != address(0), "governance cannot be empty");
            pendingGovernance = newGovernance;
        }
        /**
         * @notice Accept the new role of governance
         * @dev `changeGovernance` must be called first to set `pendingGovernance`
         */
        function acceptGovernance() external {
            address _pendingGovernance = pendingGovernance;
            require(
                _pendingGovernance != address(0),
                "changeGovernance must be called first"
            );
            require(
                _msgSender() == _pendingGovernance,
                "only pendingGovernance can accept this role"
            );
            pendingGovernance = address(0);
            governance = _msgSender();
            emit SetGovernance(_msgSender());
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.6;
    import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
    import "@openzeppelin/contracts/utils/math/Math.sol";
    import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
    import "@openzeppelin/contracts/utils/Context.sol";
    import "./SimpleGovernance.sol";
    /**
     * @title Vesting
     * @dev A token holder contract that can release its token balance gradually like a
     * typical vesting scheme, with a cliff and vesting period. Owner has the power
     * to change the beneficiary who receives the vested tokens.
     */
    contract Vesting is Initializable, Context {
        using SafeERC20 for IERC20;
        event Released(uint256 amount);
        event VestingInitialized(
            address indexed beneficiary,
            uint256 startTimestamp,
            uint256 cliff,
            uint256 duration
        );
        event SetBeneficiary(address indexed beneficiary);
        // beneficiary of tokens after they are released
        address public beneficiary;
        IERC20 public token;
        uint256 public cliffInSeconds;
        uint256 public durationInSeconds;
        uint256 public startTimestamp;
        uint256 public released;
        /**
         * @dev Sets the beneficiary to _msgSender() on deploying this contract. This prevents others from
         * initializing the logic contract.
         */
        constructor() public {
            beneficiary = _msgSender();
        }
        /**
         * @dev Limits certain functions to be called by governance
         */
        modifier onlyGovernance() {
            require(
                _msgSender() == governance(),
                "only governance can perform this action"
            );
            _;
        }
        /**
         * @dev Initializes a vesting contract that vests its balance of any ERC20 token to the
         * _beneficiary, monthly in a linear fashion until duration has passed. By then all
         * of the balance will have vested.
         * @param _token address of the token that is subject to vesting
         * @param _beneficiary address of the beneficiary to whom vested tokens are transferred
         * @param _cliffInSeconds duration in months of the cliff in which tokens will begin to vest
         * @param _durationInSeconds duration in months of the period in which the tokens will vest
         * @param _startTimestamp start timestamp when the cliff and vesting should start to count
         */
        function initialize(
            address _token,
            address _beneficiary,
            uint256 _startTimestamp,
            uint256 _cliffInSeconds,
            uint256 _durationInSeconds
        ) external initializer {
            require(_token != address(0), "_token cannot be empty");
            // dev: beneficiary is set to msg.sender on logic contracts during deployment
            require(beneficiary == address(0), "cannot initialize logic contract");
            require(_beneficiary != address(0), "_beneficiary cannot be empty");
            require(_startTimestamp != 0, "startTimestamp cannot be 0");
            require(
                _startTimestamp <= block.timestamp,
                "startTimestamp cannot be from the future"
            );
            require(_durationInSeconds != 0, "duration cannot be 0");
            require(
                _cliffInSeconds <= _durationInSeconds,
                "cliff is greater than duration"
            );
            token = IERC20(_token);
            beneficiary = _beneficiary;
            startTimestamp = _startTimestamp;
            durationInSeconds = _durationInSeconds;
            cliffInSeconds = _cliffInSeconds;
            emit VestingInitialized(
                _beneficiary,
                _startTimestamp,
                _cliffInSeconds,
                _durationInSeconds
            );
        }
        /**
         * @notice Transfers vested tokens to beneficiary.
         */
        function release() external {
            uint256 vested = vestedAmount();
            require(vested > 0, "No tokens to release");
            released = released + vested;
            emit Released(vested);
            token.safeTransfer(beneficiary, vested);
        }
        /**
         * @notice Calculates the amount that has already vested but hasn't been released yet.
         */
        function vestedAmount() public view returns (uint256) {
            uint256 blockTimestamp = block.timestamp;
            uint256 _durationInSeconds = durationInSeconds;
            uint256 elapsedTime = blockTimestamp - startTimestamp; // @dev startTimestamp is always less than blockTimestamp
            if (elapsedTime < cliffInSeconds) {
                return 0;
            }
            // If over vesting duration, all tokens vested
            if (elapsedTime >= _durationInSeconds) {
                return token.balanceOf(address(this));
            } else {
                uint256 currentBalance = token.balanceOf(address(this));
                // If there are no tokens in this contract yet, return 0.
                if (currentBalance == 0) {
                    return 0;
                }
                uint256 totalBalance = currentBalance + released;
                uint256 vested = (totalBalance * elapsedTime) / _durationInSeconds;
                uint256 unreleased = vested - released;
                return unreleased;
            }
        }
        /**
         * @notice Changes beneficiary who receives the vested token.
         * @dev Only governance can call this function. This is to be used in case the target address
         * needs to be updated. If the previous beneficiary has any unclaimed tokens, the new beneficiary
         * will be able to claim them and the rest of the vested tokens.
         * @param newBeneficiary new address to become the beneficiary
         */
        function changeBeneficiary(address newBeneficiary) external onlyGovernance {
            require(
                newBeneficiary != beneficiary,
                "beneficiary must be different from current one"
            );
            require(newBeneficiary != address(0), "beneficiary cannot be empty");
            beneficiary = newBeneficiary;
            emit SetBeneficiary(newBeneficiary);
        }
        /**
         * @notice Governance who owns this contract.
         * @dev Governance of the token contract also owns this vesting contract.
         */
        function governance() public view returns (address) {
            return SimpleGovernance(address(token)).governance();
        }
    }