ETH Price: $2,349.53 (+7.36%)

Transaction Decoder

Block:
18603980 at Nov-19-2023 06:10:23 AM +UTC
Transaction Fee:
0.002011768788547836 ETH $4.73
Gas Used:
113,436 Gas / 17.734835401 Gwei

Emitted Events:

48 GnosisSafeProxy.0x3d0ce9bfc3ed7d6862dbb28b2dea94561fe714a1b4d019aa8af39730d1ad7c3d( 0x3d0ce9bfc3ed7d6862dbb28b2dea94561fe714a1b4d019aa8af39730d1ad7c3d, 0x0000000000000000000000002b316b6e4ffd1984a2de9b33e42787923d77f390, 0000000000000000000000000000000000000000000000000de0b6b3a7640000 )
49 PreSaleDop.InvestedWithETH( by=[Sender] 0xf689192535270d35821841e9a992ab337b0eb911, code=9e05cb056a08ce4a218868842066d8b1e7593ce5310117326abc94cb644b705db0557c7ea16100c34105aba5cc022788|f51c92719299283ed7d07c4e86f2fff3, amountInvestedEth=1000000000000000000, round=8, roundPrice=18000000000000000, dopPurchased=108817890653333333333333 )

Account State Difference:

  Address   Before After State Difference Code
0x2B316b6E...23d77F390
0xA22baC86...1442f7279 860.430469341469446483 Eth861.430469341469446483 Eth1
(Flashbots: Builder)
13.869991188212205664 Eth13.870272294518280832 Eth0.000281106306075168
0xf6891925...37b0eB911
2.9285 Eth
Nonce: 0
1.926488231211452164 Eth
Nonce: 1
1.002011768788547836

Execution Trace

ETH 1 PreSaleDop.purchaseTokenWithEth( code=9e05cb056a08ce4a218868842066d8b1e7593ce5310117326abc94cb644b705db0557c7ea16100c34105aba5cc022788|f51c92719299283ed7d07c4e86f2fff3, round=8, deadline=1700374627, minAmountDop=107729711100000000000000, v=28, r=ACAA7FE18B270EDA86AAF7027439F4EE6B53D1786CCFDD2B945DC027086DBB50, s=1D2097673A5CF2B0621AD6EE905B6FB240FBCE6F765AA4914D4E522EB7A1D55B )
  • Null: 0x000...001.68f3788a( )
  • EACAggregatorProxy.STATICCALL( )
    • AccessControlledOffchainAggregator.STATICCALL( )
    • ETH 1 GnosisSafeProxy.CALL( )
      • ETH 1 GnosisSafe.DELEGATECALL( )
        File 1 of 5: PreSaleDop
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        interface AggregatorV3Interface {
          function decimals() external view returns (uint8);
          function description() external view returns (string memory);
          function version() external view returns (uint256);
          function getRoundData(uint80 _roundId)
            external
            view
            returns (
              uint80 roundId,
              int256 answer,
              uint256 startedAt,
              uint256 updatedAt,
              uint80 answeredInRound
            );
          function latestRoundData()
            external
            view
            returns (
              uint80 roundId,
              int256 answer,
              uint256 startedAt,
              uint256 updatedAt,
              uint80 answeredInRound
            );
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
        pragma solidity ^0.8.20;
        import {Context} from "../utils/Context.sol";
        /**
         * @dev Contract module which provides a basic access control mechanism, where
         * there is an account (an owner) that can be granted exclusive access to
         * specific functions.
         *
         * The initial owner is set to the address provided by the deployer. This can
         * later be changed with {transferOwnership}.
         *
         * This module is used through inheritance. It will make available the modifier
         * `onlyOwner`, which can be applied to your functions to restrict their use to
         * the owner.
         */
        abstract contract Ownable is Context {
            address private _owner;
            /**
             * @dev The caller account is not authorized to perform an operation.
             */
            error OwnableUnauthorizedAccount(address account);
            /**
             * @dev The owner is not a valid owner account. (eg. `address(0)`)
             */
            error OwnableInvalidOwner(address owner);
            event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
            /**
             * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
             */
            constructor(address initialOwner) {
                if (initialOwner == address(0)) {
                    revert OwnableInvalidOwner(address(0));
                }
                _transferOwnership(initialOwner);
            }
            /**
             * @dev Throws if called by any account other than the owner.
             */
            modifier onlyOwner() {
                _checkOwner();
                _;
            }
            /**
             * @dev Returns the address of the current owner.
             */
            function owner() public view virtual returns (address) {
                return _owner;
            }
            /**
             * @dev Throws if the sender is not the owner.
             */
            function _checkOwner() internal view virtual {
                if (owner() != _msgSender()) {
                    revert OwnableUnauthorizedAccount(_msgSender());
                }
            }
            /**
             * @dev Leaves the contract without owner. It will not be possible to call
             * `onlyOwner` functions. Can only be called by the current owner.
             *
             * NOTE: Renouncing ownership will leave the contract without an owner,
             * thereby disabling any functionality that is only available to the owner.
             */
            function renounceOwnership() public virtual onlyOwner {
                _transferOwnership(address(0));
            }
            /**
             * @dev Transfers ownership of the contract to a new account (`newOwner`).
             * Can only be called by the current owner.
             */
            function transferOwnership(address newOwner) public virtual onlyOwner {
                if (newOwner == address(0)) {
                    revert OwnableInvalidOwner(address(0));
                }
                _transferOwnership(newOwner);
            }
            /**
             * @dev Transfers ownership of the contract to a new account (`newOwner`).
             * Internal function without access restriction.
             */
            function _transferOwnership(address newOwner) internal virtual {
                address oldOwner = _owner;
                _owner = newOwner;
                emit OwnershipTransferred(oldOwner, newOwner);
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)
        pragma solidity ^0.8.20;
        /**
         * @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.
         *
         * ==== Security Considerations
         *
         * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
         * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
         * considered as an intention to spend the allowance in any specific way. The second is that because permits have
         * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
         * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
         * generally recommended is:
         *
         * ```solidity
         * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
         *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
         *     doThing(..., value);
         * }
         *
         * function doThing(..., uint256 value) public {
         *     token.safeTransferFrom(msg.sender, address(this), value);
         *     ...
         * }
         * ```
         *
         * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
         * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
         * {SafeERC20-safeTransferFrom}).
         *
         * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
         * contracts should have entry points that don't rely on permit.
         */
        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].
             *
             * CAUTION: See Security Considerations above.
             */
            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
        // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
        pragma solidity ^0.8.20;
        /**
         * @dev Interface of the ERC20 standard as defined in the EIP.
         */
        interface IERC20 {
            /**
             * @dev Emitted when `value` tokens are moved from one account (`from`) to
             * another (`to`).
             *
             * Note that `value` may be zero.
             */
            event Transfer(address indexed from, address indexed to, uint256 value);
            /**
             * @dev Emitted when the allowance of a `spender` for an `owner` is set by
             * a call to {approve}. `value` is the new allowance.
             */
            event Approval(address indexed owner, address indexed spender, uint256 value);
            /**
             * @dev Returns the value of tokens in existence.
             */
            function totalSupply() external view returns (uint256);
            /**
             * @dev Returns the value of tokens owned by `account`.
             */
            function balanceOf(address account) external view returns (uint256);
            /**
             * @dev Moves a `value` amount of tokens from the caller's account to `to`.
             *
             * Returns a boolean value indicating whether the operation succeeded.
             *
             * Emits a {Transfer} event.
             */
            function transfer(address to, uint256 value) 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 a `value` amount of tokens 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 value) external returns (bool);
            /**
             * @dev Moves a `value` amount of tokens from `from` to `to` using the
             * allowance mechanism. `value` is then deducted from the caller's
             * allowance.
             *
             * Returns a boolean value indicating whether the operation succeeded.
             *
             * Emits a {Transfer} event.
             */
            function transferFrom(address from, address to, uint256 value) external returns (bool);
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)
        pragma solidity ^0.8.20;
        import {IERC20} from "../IERC20.sol";
        import {IERC20Permit} from "../extensions/IERC20Permit.sol";
        import {Address} from "../../../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;
            /**
             * @dev An operation with an ERC20 token failed.
             */
            error SafeERC20FailedOperation(address token);
            /**
             * @dev Indicates a failed `decreaseAllowance` request.
             */
            error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
            /**
             * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
             * non-reverting calls are assumed to be successful.
             */
            function safeTransfer(IERC20 token, address to, uint256 value) internal {
                _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
            }
            /**
             * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
             * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
             */
            function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
                _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
            }
            /**
             * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
             * non-reverting calls are assumed to be successful.
             */
            function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
                uint256 oldAllowance = token.allowance(address(this), spender);
                forceApprove(token, spender, oldAllowance + value);
            }
            /**
             * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
             * value, non-reverting calls are assumed to be successful.
             */
            function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
                unchecked {
                    uint256 currentAllowance = token.allowance(address(this), spender);
                    if (currentAllowance < requestedDecrease) {
                        revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
                    }
                    forceApprove(token, spender, currentAllowance - requestedDecrease);
                }
            }
            /**
             * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
             * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
             * to be set to zero before setting it to a non-zero value, such as USDT.
             */
            function forceApprove(IERC20 token, address spender, uint256 value) internal {
                bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
                if (!_callOptionalReturnBool(token, approvalCall)) {
                    _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
                    _callOptionalReturn(token, approvalCall);
                }
            }
            /**
             * @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);
                if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
                    revert SafeERC20FailedOperation(address(token));
                }
            }
            /**
             * @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).
             *
             * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
             */
            function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
                // 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 cannot use {Address-functionCall} here since this should return false
                // and not revert is the subcall reverts.
                (bool success, bytes memory returndata) = address(token).call(data);
                return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
        pragma solidity ^0.8.20;
        /**
         * @dev Collection of functions related to the address type
         */
        library Address {
            /**
             * @dev The ETH balance of the account is not enough to perform the operation.
             */
            error AddressInsufficientBalance(address account);
            /**
             * @dev There's no code at `target` (it is not a contract).
             */
            error AddressEmptyCode(address target);
            /**
             * @dev A call to an address target failed. The target may have reverted.
             */
            error FailedInnerCall();
            /**
             * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
             * `recipient`, forwarding all available gas and reverting on errors.
             *
             * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
             * of certain opcodes, possibly making contracts go over the 2300 gas limit
             * imposed by `transfer`, making them unable to receive funds via
             * `transfer`. {sendValue} removes this limitation.
             *
             * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
             *
             * IMPORTANT: because control is transferred to `recipient`, care must be
             * taken to not create reentrancy vulnerabilities. Consider using
             * {ReentrancyGuard} or the
             * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
             */
            function sendValue(address payable recipient, uint256 amount) internal {
                if (address(this).balance < amount) {
                    revert AddressInsufficientBalance(address(this));
                }
                (bool success, ) = recipient.call{value: amount}("");
                if (!success) {
                    revert FailedInnerCall();
                }
            }
            /**
             * @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 or custom error, it is bubbled
             * up by this function (like regular Solidity function calls). However, if
             * the call reverted with no returned reason, this function reverts with a
             * {FailedInnerCall} error.
             *
             * 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.
             */
            function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                return functionCallWithValue(target, data, 0);
            }
            /**
             * @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`.
             */
            function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
                if (address(this).balance < value) {
                    revert AddressInsufficientBalance(address(this));
                }
                (bool success, bytes memory returndata) = target.call{value: value}(data);
                return verifyCallResultFromTarget(target, success, returndata);
            }
            /**
             * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
             * but performing a static call.
             */
            function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                (bool success, bytes memory returndata) = target.staticcall(data);
                return verifyCallResultFromTarget(target, success, returndata);
            }
            /**
             * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
             * but performing a delegate call.
             */
            function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                (bool success, bytes memory returndata) = target.delegatecall(data);
                return verifyCallResultFromTarget(target, success, returndata);
            }
            /**
             * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
             * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
             * unsuccessful call.
             */
            function verifyCallResultFromTarget(
                address target,
                bool success,
                bytes memory returndata
            ) internal view returns (bytes memory) {
                if (!success) {
                    _revert(returndata);
                } else {
                    // only check if target is a contract if the call was successful and the return data is empty
                    // otherwise we already know that it was a contract
                    if (returndata.length == 0 && target.code.length == 0) {
                        revert AddressEmptyCode(target);
                    }
                    return returndata;
                }
            }
            /**
             * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
             * revert reason or with a default {FailedInnerCall} error.
             */
            function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
                if (!success) {
                    _revert(returndata);
                } else {
                    return returndata;
                }
            }
            /**
             * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
             */
            function _revert(bytes memory returndata) private pure {
                // Look for revert reason and bubble it up if present
                if (returndata.length > 0) {
                    // The easiest way to bubble the revert reason is using memory via assembly
                    /// @solidity memory-safe-assembly
                    assembly {
                        let returndata_size := mload(returndata)
                        revert(add(32, returndata), returndata_size)
                    }
                } else {
                    revert FailedInnerCall();
                }
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v5.0.0) (utils/Context.sol)
        pragma solidity ^0.8.20;
        /**
         * @dev Provides information about the current execution context, including the
         * sender of the transaction and its data. While these are generally available
         * via msg.sender and msg.data, they should not be accessed in such a direct
         * manner, since when dealing with meta-transactions the account sending and
         * paying for execution may not be the actual sender (as far as an application
         * is concerned).
         *
         * This contract is only required for intermediate, library-like contracts.
         */
        abstract contract Context {
            function _msgSender() internal view virtual returns (address) {
                return msg.sender;
            }
            function _msgData() internal view virtual returns (bytes calldata) {
                return msg.data;
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/ECDSA.sol)
        pragma solidity ^0.8.20;
        /**
         * @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 {
            enum RecoverError {
                NoError,
                InvalidSignature,
                InvalidSignatureLength,
                InvalidSignatureS
            }
            /**
             * @dev The signature derives the `address(0)`.
             */
            error ECDSAInvalidSignature();
            /**
             * @dev The signature has an invalid length.
             */
            error ECDSAInvalidSignatureLength(uint256 length);
            /**
             * @dev The signature has an S value that is in the upper half order.
             */
            error ECDSAInvalidSignatureS(bytes32 s);
            /**
             * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not
             * return address(0) without also returning an error description. Errors are documented using an enum (error type)
             * and a bytes32 providing additional information about the error.
             *
             * If no error is returned, then the address can be used for verification purposes.
             *
             * The `ecrecover` EVM precompile 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 {MessageHashUtils-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 tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) {
                if (signature.length == 65) {
                    bytes32 r;
                    bytes32 s;
                    uint8 v;
                    // ecrecover takes the signature parameters, and the only way to get them
                    // currently is to use assembly.
                    /// @solidity memory-safe-assembly
                    assembly {
                        r := mload(add(signature, 0x20))
                        s := mload(add(signature, 0x40))
                        v := byte(0, mload(add(signature, 0x60)))
                    }
                    return tryRecover(hash, v, r, s);
                } else {
                    return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
                }
            }
            /**
             * @dev Returns the address that signed a hashed message (`hash`) with
             * `signature`. This address can then be used for verification purposes.
             *
             * The `ecrecover` EVM precompile 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 {MessageHashUtils-toEthSignedMessageHash} on it.
             */
            function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
                (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
                _throwError(error, errorArg);
                return recovered;
            }
            /**
             * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
             *
             * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
             */
            function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) {
                unchecked {
                    bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
                    // We do not check for an overflow here since the shift operation results in 0 or 1.
                    uint8 v = uint8((uint256(vs) >> 255) + 27);
                    return tryRecover(hash, v, r, s);
                }
            }
            /**
             * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
             */
            function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
                (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
                _throwError(error, errorArg);
                return recovered;
            }
            /**
             * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
             * `r` and `s` signature fields separately.
             */
            function tryRecover(
                bytes32 hash,
                uint8 v,
                bytes32 r,
                bytes32 s
            ) internal pure returns (address, RecoverError, bytes32) {
                // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
                // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
                // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
                // signatures from current libraries generate a unique signature with an s-value in the lower half order.
                //
                // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
                // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
                // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
                // these malleable signatures as well.
                if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
                    return (address(0), RecoverError.InvalidSignatureS, s);
                }
                // If the signature is valid (and not malleable), return the signer address
                address signer = ecrecover(hash, v, r, s);
                if (signer == address(0)) {
                    return (address(0), RecoverError.InvalidSignature, bytes32(0));
                }
                return (signer, RecoverError.NoError, bytes32(0));
            }
            /**
             * @dev Overload of {ECDSA-recover} that receives the `v`,
             * `r` and `s` signature fields separately.
             */
            function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
                (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);
                _throwError(error, errorArg);
                return recovered;
            }
            /**
             * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
             */
            function _throwError(RecoverError error, bytes32 errorArg) private pure {
                if (error == RecoverError.NoError) {
                    return; // no error: do nothing
                } else if (error == RecoverError.InvalidSignature) {
                    revert ECDSAInvalidSignature();
                } else if (error == RecoverError.InvalidSignatureLength) {
                    revert ECDSAInvalidSignatureLength(uint256(errorArg));
                } else if (error == RecoverError.InvalidSignatureS) {
                    revert ECDSAInvalidSignatureS(errorArg);
                }
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MessageHashUtils.sol)
        pragma solidity ^0.8.20;
        import {Strings} from "../Strings.sol";
        /**
         * @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing.
         *
         * The library provides methods for generating a hash of a message that conforms to the
         * https://eips.ethereum.org/EIPS/eip-191[EIP 191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712]
         * specifications.
         */
        library MessageHashUtils {
            /**
             * @dev Returns the keccak256 digest of an EIP-191 signed data with version
             * `0x45` (`personal_sign` messages).
             *
             * The digest is calculated by prefixing a bytes32 `messageHash` with
             * `"\\x19Ethereum Signed Message:\
        32"` and hashing the result. It corresponds with the
             * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
             *
             * NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with
             * keccak256, although any bytes32 value can be safely used because the final digest will
             * be re-hashed.
             *
             * See {ECDSA-recover}.
             */
            function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) {
                /// @solidity memory-safe-assembly
                assembly {
                    mstore(0x00, "\\x19Ethereum Signed Message:\
        32") // 32 is the bytes-length of messageHash
                    mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix
                    digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20)
                }
            }
            /**
             * @dev Returns the keccak256 digest of an EIP-191 signed data with version
             * `0x45` (`personal_sign` messages).
             *
             * The digest is calculated by prefixing an arbitrary `message` with
             * `"\\x19Ethereum Signed Message:\
        " + len(message)` and hashing the result. It corresponds with the
             * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
             *
             * See {ECDSA-recover}.
             */
            function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) {
                return
                    keccak256(bytes.concat("\\x19Ethereum Signed Message:\
        ", bytes(Strings.toString(message.length)), message));
            }
            /**
             * @dev Returns the keccak256 digest of an EIP-191 signed data with version
             * `0x00` (data with intended validator).
             *
             * The digest is calculated by prefixing an arbitrary `data` with `"\\x19\\x00"` and the intended
             * `validator` address. Then hashing the result.
             *
             * See {ECDSA-recover}.
             */
            function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
                return keccak256(abi.encodePacked(hex"19_00", validator, data));
            }
            /**
             * @dev Returns the keccak256 digest of an EIP-712 typed data (EIP-191 version `0x01`).
             *
             * The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with
             * `\\x19\\x01` and hashing the result. It corresponds to the hash signed by the
             * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712.
             *
             * See {ECDSA-recover}.
             */
            function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) {
                /// @solidity memory-safe-assembly
                assembly {
                    let ptr := mload(0x40)
                    mstore(ptr, hex"19_01")
                    mstore(add(ptr, 0x02), domainSeparator)
                    mstore(add(ptr, 0x22), structHash)
                    digest := keccak256(ptr, 0x42)
                }
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)
        pragma solidity ^0.8.20;
        /**
         * @dev Standard math utilities missing in the Solidity language.
         */
        library Math {
            /**
             * @dev Muldiv operation overflow.
             */
            error MathOverflowedMulDiv();
            enum Rounding {
                Floor, // Toward negative infinity
                Ceil, // Toward positive infinity
                Trunc, // Toward zero
                Expand // Away from zero
            }
            /**
             * @dev Returns the addition of two unsigned integers, with an overflow flag.
             */
            function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                unchecked {
                    uint256 c = a + b;
                    if (c < a) return (false, 0);
                    return (true, c);
                }
            }
            /**
             * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
             */
            function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                unchecked {
                    if (b > a) return (false, 0);
                    return (true, a - b);
                }
            }
            /**
             * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
             */
            function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                unchecked {
                    // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                    // benefit is lost if 'b' is also tested.
                    // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
                    if (a == 0) return (true, 0);
                    uint256 c = a * b;
                    if (c / a != b) return (false, 0);
                    return (true, c);
                }
            }
            /**
             * @dev Returns the division of two unsigned integers, with a division by zero flag.
             */
            function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                unchecked {
                    if (b == 0) return (false, 0);
                    return (true, a / b);
                }
            }
            /**
             * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
             */
            function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                unchecked {
                    if (b == 0) return (false, 0);
                    return (true, a % b);
                }
            }
            /**
             * @dev Returns the largest of two numbers.
             */
            function max(uint256 a, uint256 b) internal pure returns (uint256) {
                return a > b ? a : b;
            }
            /**
             * @dev Returns the smallest of two numbers.
             */
            function min(uint256 a, uint256 b) internal pure returns (uint256) {
                return a < b ? a : b;
            }
            /**
             * @dev Returns the average of two numbers. The result is rounded towards
             * zero.
             */
            function average(uint256 a, uint256 b) internal pure returns (uint256) {
                // (a + b) / 2 can overflow.
                return (a & b) + (a ^ b) / 2;
            }
            /**
             * @dev Returns the ceiling of the division of two numbers.
             *
             * This differs from standard division with `/` in that it rounds towards infinity instead
             * of rounding towards zero.
             */
            function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
                if (b == 0) {
                    // Guarantee the same behavior as in a regular Solidity division.
                    return a / b;
                }
                // (a + b - 1) / b can overflow on addition, so we distribute.
                return a == 0 ? 0 : (a - 1) / b + 1;
            }
            /**
             * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
             * denominator == 0.
             * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
             * Uniswap Labs also under MIT license.
             */
            function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
                unchecked {
                    // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
                    // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
                    // variables such that product = prod1 * 2^256 + prod0.
                    uint256 prod0 = x * y; // Least significant 256 bits of the product
                    uint256 prod1; // Most significant 256 bits of the product
                    assembly {
                        let mm := mulmod(x, y, not(0))
                        prod1 := sub(sub(mm, prod0), lt(mm, prod0))
                    }
                    // Handle non-overflow cases, 256 by 256 division.
                    if (prod1 == 0) {
                        // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                        // The surrounding unchecked block does not change this fact.
                        // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                        return prod0 / denominator;
                    }
                    // Make sure the result is less than 2^256. Also prevents denominator == 0.
                    if (denominator <= prod1) {
                        revert MathOverflowedMulDiv();
                    }
                    ///////////////////////////////////////////////
                    // 512 by 256 division.
                    ///////////////////////////////////////////////
                    // Make division exact by subtracting the remainder from [prod1 prod0].
                    uint256 remainder;
                    assembly {
                        // Compute remainder using mulmod.
                        remainder := mulmod(x, y, denominator)
                        // Subtract 256 bit number from 512 bit number.
                        prod1 := sub(prod1, gt(remainder, prod0))
                        prod0 := sub(prod0, remainder)
                    }
                    // Factor powers of two out of denominator and compute largest power of two divisor of denominator.
                    // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.
                    uint256 twos = denominator & (0 - denominator);
                    assembly {
                        // Divide denominator by twos.
                        denominator := div(denominator, twos)
                        // Divide [prod1 prod0] by twos.
                        prod0 := div(prod0, twos)
                        // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                        twos := add(div(sub(0, twos), twos), 1)
                    }
                    // Shift in bits from prod1 into prod0.
                    prod0 |= prod1 * twos;
                    // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
                    // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
                    // four bits. That is, denominator * inv = 1 mod 2^4.
                    uint256 inverse = (3 * denominator) ^ 2;
                    // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
                    // works in modular arithmetic, doubling the correct bits in each step.
                    inverse *= 2 - denominator * inverse; // inverse mod 2^8
                    inverse *= 2 - denominator * inverse; // inverse mod 2^16
                    inverse *= 2 - denominator * inverse; // inverse mod 2^32
                    inverse *= 2 - denominator * inverse; // inverse mod 2^64
                    inverse *= 2 - denominator * inverse; // inverse mod 2^128
                    inverse *= 2 - denominator * inverse; // inverse mod 2^256
                    // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
                    // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
                    // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
                    // is no longer required.
                    result = prod0 * inverse;
                    return result;
                }
            }
            /**
             * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
             */
            function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
                uint256 result = mulDiv(x, y, denominator);
                if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
                    result += 1;
                }
                return result;
            }
            /**
             * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
             * towards zero.
             *
             * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
             */
            function sqrt(uint256 a) internal pure returns (uint256) {
                if (a == 0) {
                    return 0;
                }
                // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
                //
                // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
                // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
                //
                // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
                // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
                // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
                //
                // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
                uint256 result = 1 << (log2(a) >> 1);
                // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
                // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
                // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
                // into the expected uint128 result.
                unchecked {
                    result = (result + a / result) >> 1;
                    result = (result + a / result) >> 1;
                    result = (result + a / result) >> 1;
                    result = (result + a / result) >> 1;
                    result = (result + a / result) >> 1;
                    result = (result + a / result) >> 1;
                    result = (result + a / result) >> 1;
                    return min(result, a / result);
                }
            }
            /**
             * @notice Calculates sqrt(a), following the selected rounding direction.
             */
            function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
                unchecked {
                    uint256 result = sqrt(a);
                    return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
                }
            }
            /**
             * @dev Return the log in base 2 of a positive value rounded towards zero.
             * Returns 0 if given 0.
             */
            function log2(uint256 value) internal pure returns (uint256) {
                uint256 result = 0;
                unchecked {
                    if (value >> 128 > 0) {
                        value >>= 128;
                        result += 128;
                    }
                    if (value >> 64 > 0) {
                        value >>= 64;
                        result += 64;
                    }
                    if (value >> 32 > 0) {
                        value >>= 32;
                        result += 32;
                    }
                    if (value >> 16 > 0) {
                        value >>= 16;
                        result += 16;
                    }
                    if (value >> 8 > 0) {
                        value >>= 8;
                        result += 8;
                    }
                    if (value >> 4 > 0) {
                        value >>= 4;
                        result += 4;
                    }
                    if (value >> 2 > 0) {
                        value >>= 2;
                        result += 2;
                    }
                    if (value >> 1 > 0) {
                        result += 1;
                    }
                }
                return result;
            }
            /**
             * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
             * Returns 0 if given 0.
             */
            function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
                unchecked {
                    uint256 result = log2(value);
                    return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
                }
            }
            /**
             * @dev Return the log in base 10 of a positive value rounded towards zero.
             * Returns 0 if given 0.
             */
            function log10(uint256 value) internal pure returns (uint256) {
                uint256 result = 0;
                unchecked {
                    if (value >= 10 ** 64) {
                        value /= 10 ** 64;
                        result += 64;
                    }
                    if (value >= 10 ** 32) {
                        value /= 10 ** 32;
                        result += 32;
                    }
                    if (value >= 10 ** 16) {
                        value /= 10 ** 16;
                        result += 16;
                    }
                    if (value >= 10 ** 8) {
                        value /= 10 ** 8;
                        result += 8;
                    }
                    if (value >= 10 ** 4) {
                        value /= 10 ** 4;
                        result += 4;
                    }
                    if (value >= 10 ** 2) {
                        value /= 10 ** 2;
                        result += 2;
                    }
                    if (value >= 10 ** 1) {
                        result += 1;
                    }
                }
                return result;
            }
            /**
             * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
             * Returns 0 if given 0.
             */
            function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
                unchecked {
                    uint256 result = log10(value);
                    return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
                }
            }
            /**
             * @dev Return the log in base 256 of a positive value rounded towards zero.
             * Returns 0 if given 0.
             *
             * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
             */
            function log256(uint256 value) internal pure returns (uint256) {
                uint256 result = 0;
                unchecked {
                    if (value >> 128 > 0) {
                        value >>= 128;
                        result += 16;
                    }
                    if (value >> 64 > 0) {
                        value >>= 64;
                        result += 8;
                    }
                    if (value >> 32 > 0) {
                        value >>= 32;
                        result += 4;
                    }
                    if (value >> 16 > 0) {
                        value >>= 16;
                        result += 2;
                    }
                    if (value >> 8 > 0) {
                        result += 1;
                    }
                }
                return result;
            }
            /**
             * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
             * Returns 0 if given 0.
             */
            function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
                unchecked {
                    uint256 result = log256(value);
                    return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
                }
            }
            /**
             * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
             */
            function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
                return uint8(rounding) % 2 == 1;
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)
        pragma solidity ^0.8.20;
        /**
         * @dev Standard signed math utilities missing in the Solidity language.
         */
        library SignedMath {
            /**
             * @dev Returns the largest of two signed numbers.
             */
            function max(int256 a, int256 b) internal pure returns (int256) {
                return a > b ? a : b;
            }
            /**
             * @dev Returns the smallest of two signed numbers.
             */
            function min(int256 a, int256 b) internal pure returns (int256) {
                return a < b ? a : b;
            }
            /**
             * @dev Returns the average of two signed numbers without overflow.
             * The result is rounded towards zero.
             */
            function average(int256 a, int256 b) internal pure returns (int256) {
                // Formula from the book "Hacker's Delight"
                int256 x = (a & b) + ((a ^ b) >> 1);
                return x + (int256(uint256(x) >> 255) & (a ^ b));
            }
            /**
             * @dev Returns the absolute unsigned value of a signed value.
             */
            function abs(int256 n) internal pure returns (uint256) {
                unchecked {
                    // must be unchecked in order to support `n = type(int256).min`
                    return uint256(n >= 0 ? n : -n);
                }
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)
        pragma solidity ^0.8.20;
        /**
         * @dev Contract module that helps prevent reentrant calls to a function.
         *
         * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
         * available, which can be applied to functions to make sure there are no nested
         * (reentrant) calls to them.
         *
         * Note that because there is a single `nonReentrant` guard, functions marked as
         * `nonReentrant` may not call one another. This can be worked around by making
         * those functions `private`, and then adding `external` `nonReentrant` entry
         * points to them.
         *
         * TIP: If you would like to learn more about reentrancy and alternative ways
         * to protect against it, check out our blog post
         * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
         */
        abstract contract ReentrancyGuard {
            // Booleans are more expensive than uint256 or any type that takes up a full
            // word because each write operation emits an extra SLOAD to first read the
            // slot's contents, replace the bits taken up by the boolean, and then write
            // back. This is the compiler's defense against contract upgrades and
            // pointer aliasing, and it cannot be disabled.
            // The values being non-zero value makes deployment a bit more expensive,
            // but in exchange the refund on every call to nonReentrant will be lower in
            // amount. Since refunds are capped to a percentage of the total
            // transaction's gas, it is best to keep them low in cases like this one, to
            // increase the likelihood of the full refund coming into effect.
            uint256 private constant NOT_ENTERED = 1;
            uint256 private constant ENTERED = 2;
            uint256 private _status;
            /**
             * @dev Unauthorized reentrant call.
             */
            error ReentrancyGuardReentrantCall();
            constructor() {
                _status = NOT_ENTERED;
            }
            /**
             * @dev Prevents a contract from calling itself, directly or indirectly.
             * Calling a `nonReentrant` function from another `nonReentrant`
             * function is not supported. It is possible to prevent this from happening
             * by making the `nonReentrant` function external, and making it call a
             * `private` function that does the actual work.
             */
            modifier nonReentrant() {
                _nonReentrantBefore();
                _;
                _nonReentrantAfter();
            }
            function _nonReentrantBefore() private {
                // On the first call to nonReentrant, _status will be NOT_ENTERED
                if (_status == ENTERED) {
                    revert ReentrancyGuardReentrantCall();
                }
                // Any calls to nonReentrant after this point will fail
                _status = ENTERED;
            }
            function _nonReentrantAfter() private {
                // By storing the original value once again, a refund is triggered (see
                // https://eips.ethereum.org/EIPS/eip-2200)
                _status = NOT_ENTERED;
            }
            /**
             * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
             * `nonReentrant` function in the call stack.
             */
            function _reentrancyGuardEntered() internal view returns (bool) {
                return _status == ENTERED;
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)
        pragma solidity ^0.8.20;
        import {Math} from "./math/Math.sol";
        import {SignedMath} from "./math/SignedMath.sol";
        /**
         * @dev String operations.
         */
        library Strings {
            bytes16 private constant HEX_DIGITS = "0123456789abcdef";
            uint8 private constant ADDRESS_LENGTH = 20;
            /**
             * @dev The `value` string doesn't fit in the specified `length`.
             */
            error StringsInsufficientHexLength(uint256 value, uint256 length);
            /**
             * @dev Converts a `uint256` to its ASCII `string` decimal representation.
             */
            function toString(uint256 value) internal pure returns (string memory) {
                unchecked {
                    uint256 length = Math.log10(value) + 1;
                    string memory buffer = new string(length);
                    uint256 ptr;
                    /// @solidity memory-safe-assembly
                    assembly {
                        ptr := add(buffer, add(32, length))
                    }
                    while (true) {
                        ptr--;
                        /// @solidity memory-safe-assembly
                        assembly {
                            mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
                        }
                        value /= 10;
                        if (value == 0) break;
                    }
                    return buffer;
                }
            }
            /**
             * @dev Converts a `int256` to its ASCII `string` decimal representation.
             */
            function toStringSigned(int256 value) internal pure returns (string memory) {
                return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
            }
            /**
             * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
             */
            function toHexString(uint256 value) internal pure returns (string memory) {
                unchecked {
                    return toHexString(value, Math.log256(value) + 1);
                }
            }
            /**
             * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
             */
            function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
                uint256 localValue = value;
                bytes memory buffer = new bytes(2 * length + 2);
                buffer[0] = "0";
                buffer[1] = "x";
                for (uint256 i = 2 * length + 1; i > 1; --i) {
                    buffer[i] = HEX_DIGITS[localValue & 0xf];
                    localValue >>= 4;
                }
                if (localValue != 0) {
                    revert StringsInsufficientHexLength(value, length);
                }
                return string(buffer);
            }
            /**
             * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal
             * representation.
             */
            function toHexString(address addr) internal pure returns (string memory) {
                return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
            }
            /**
             * @dev Returns true if the two strings are equal.
             */
            function equal(string memory a, string memory b) internal pure returns (bool) {
                return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity 0.8.22;
        import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
        /// @notice Thrown when updating an address with zero address
        error ZeroAddress();
        /// @notice Thrown when updating with an array of no values
        error ZeroLengthArray();
        /// @notice Thrown when updating with the same value as previously stored
        error IdenticalValue();
        /// @notice Thrown when two array lengths does not match
        error ArrayLengthMismatch();
        /// @dev The address of the Ethereum
        IERC20 constant ETH = IERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
        // SPDX-License-Identifier: MIT
        pragma solidity 0.8.22;
        import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
        import {IRounds} from "./IRounds.sol";
        interface IPreSaleDop is IRounds {
            /// @notice Purchases Dop token with claim amount
            /// @param token The address of investment token
            /// @param tokenPrice The current price of token in 10 decimals
            /// @param referenceNormalizationFactor The value to handle decimals
            /// @param amount The investment amount
            /// @param minAmountDop The minimum amount of dop recipient will get
            /// @param recipient The address of the recipient
            /// @param round The round in which user will purchase
            function purchaseWithClaim(
                IERC20 token,
                uint256 tokenPrice,
                uint8 referenceNormalizationFactor,
                uint256 amount,
                uint256 minAmountDop,
                address recipient,
                uint32 round
            ) external payable;
            /// @notice The helper function which verifies signature, signed by signerWallet, reverts if invalidSignature
            function verifyPurchaseWithClaim(
                address recipient,
                uint32 round,
                uint256 deadline,
                uint256[] calldata tokenPrices,
                uint8[] calldata normalizationFactors,
                IERC20[] calldata tokens,
                uint256[] calldata amounts,
                uint8 v,
                bytes32 r,
                bytes32 s
            ) external;
        }
        // SPDX-License-Identifier: MIT
        pragma solidity 0.8.22;
        interface IRounds {
            /// @notice Returns the round details of the round numberz
            function rounds(
                uint32 round
            ) external view returns (uint256 startTime, uint256 endTime, uint256 price);
        }
        // SPDX-License-Identifier: MIT
        pragma solidity 0.8.22;
        import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
        import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
        import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
        import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";
        import {Address} from "@openzeppelin/contracts/utils/Address.sol";
        import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
        import {Rounds, Ownable} from "./Rounds.sol";
        import {IPreSaleDop} from "./IPreSaleDop.sol";
        import "./Common.sol";
        /// @title PreSaleDop contract
        /// @notice Implements the preSale of Dop Token
        /// @dev The presale contract allows you to purchase dop token with allowed tokens,
        /// and there will be certain rounds.
        /// @dev The recorded DOP tokens and NFT claims will be distributed later using another distributor contract.
        contract PreSaleDop is IPreSaleDop, Rounds, ReentrancyGuard {
            using SafeERC20 for IERC20;
            using Address for address payable;
            /// @notice Thrown when address is blacklisted
            error Blacklisted();
            /// @notice Thrown when buy is disabled
            error BuyNotEnable();
            /// @notice Thrown when sign deadline is expired
            error DeadlineExpired();
            /// @notice Thrown when Sign is invalid
            error InvalidSignature();
            /// @notice Thrown when Eth price suddenly drops while purchasing with ETH
            error UnexpectedPriceDifference();
            /// @notice Thrown when value to transfer is zero
            error ZeroValue();
            /// @notice Thrown when price from pricefeed is zero
            error PriceNotFound();
            /// @notice Thrown when caller is not claimsContract
            error OnlyClaims();
            /// @notice Thrown when investment is less than nft prices combined
            error InvalidInvestment();
            /// @notice Thrown when both pricefeed and reference price are non zero
            error CodeSyncIssue();
            /// @notice That buyEnable or not
            bool public buyEnable = true;
            /// @notice The address of signerWallet
            address public signerWallet;
            /// @notice The address of claimsContract
            address public claimsContract;
            /// @notice The address of fundsWallet
            address public fundsWallet;
            /// @notice The array of prices of each nft
            uint256[] public nftPricing;
            /// @notice Gives claim info of user in every round
            mapping(address => mapping(uint32 => uint256)) public claims;
            /// @notice Gives info about address's permission
            mapping(address => bool) public blacklistAddress;
            /// @notice Gives claim info of user nft in every round
            mapping(address => mapping(uint32 => ClaimNFT[])) public claimNFT;
            /// @member nftAmounts The nft amounts
            /// @member roundPrice The round number
            struct ClaimNFT {
                uint256[] nftAmounts;
                uint256 roundPrice;
            }
            /// @member price The price of token from priceFeed
            /// @member normalizationFactorForToken The normalization factor to achieve return value of 18 decimals ,while calculating dop token purchases and always with different token decimals
            /// @member normalizationFactorForNFT The normalization factor is the value which helps us to convert decimals of USDT to investment token decimals and always with different token decimals
            struct TokenInfo {
                uint256 latestPrice;
                uint8 normalizationFactorForToken;
                uint8 normalizationFactorForNFT;
            }
            /// @dev Emitted when dop is purchased with ETH
            event InvestedWithETH(
                address indexed by,
                string code,
                uint256 amountInvestedEth,
                uint32 indexed round,
                uint256 indexed roundPrice,
                uint256 dopPurchased
            );
            /// @dev Emitted when dop is purchased with Token
            event InvestedWithToken(
                IERC20 indexed token,
                uint256 tokenPrice,
                address indexed by,
                string code,
                uint256 amountInvested,
                uint256 dopPurchased,
                uint32 indexed round
            );
            /// @dev Emitted when dop NFT is purchased with ETH
            event InvestedWithETHForNFT(
                address indexed by,
                string code,
                uint256 amountInEth,
                uint256 ethPrice,
                uint32 indexed round,
                uint256 roundPrice,
                uint256[] nftAmounts
            );
            /// @dev Emitted when dop NFT is purchased with token
            event InvestedWithTokenForNFT(
                IERC20 indexed token,
                uint256 tokenPrice,
                address indexed by,
                string code,
                uint256 amountInvested,
                uint32 indexed round,
                uint256 roundPrice,
                uint256[] nftAmounts
            );
            /// @dev Emitted when dop is purchased claim amount
            event InvestedWithClaimAmount(
                address indexed by,
                uint256 amount,
                IERC20 token,
                uint32 indexed round,
                uint256 indexed tokenPrice,
                uint256 dopPurchased
            );
            /// @dev Emitted when address of signer is updated
            event SignerUpdated(address oldSigner, address newSigner);
            /// @dev Emitted when address of funds wallet is updated
            event FundsWalletUpdated(address oldAddress, address newAddress);
            /// @dev Emitted when blacklist access of address is updated
            event BlacklistUpdated(address which, bool accessNow);
            /// @dev Emitted when buying access changes
            event BuyEnableUpdated(bool oldAccess, bool newAccess);
            /// @dev Emitted when dop NFT prices are updated
            event PricingUpdated(uint256 oldPrice, uint256 newPrice);
            /// @notice Restricts when updating wallet/contract address to zero address
            modifier checkAddressZero(address which) {
                if (which == address(0)) {
                    revert ZeroAddress();
                }
                _;
            }
            /// @notice Ensures that buy is enabled when buying
            modifier canBuy() {
                if (!buyEnable) {
                    revert BuyNotEnable();
                }
                _;
            }
            /// @dev Constructor.
            /// @param fundsWalletAddress The address of funds wallet
            /// @param signerAddress The address of signer wallet
            /// @param claimsContractAddress The address of claim contract
            /// @param lastRound The last round created
            /// @param nftPrices The prices of the dop NFTs
            constructor(
                address fundsWalletAddress,
                address signerAddress,
                address claimsContractAddress,
                address owner,
                uint32 lastRound,
                uint256[] memory nftPrices
            ) Rounds(lastRound) Ownable(owner) {
                if (
                    fundsWalletAddress == address(0) ||
                    signerAddress == address(0) ||
                    claimsContractAddress == address(0) ||
                    owner == address(0)
                ) {
                    revert ZeroAddress();
                }
                fundsWallet = fundsWalletAddress;
                signerWallet = signerAddress;
                claimsContract = claimsContractAddress;
                if (nftPrices.length == 0) {
                    revert ZeroLengthArray();
                }
                for (uint256 i = 0; i < nftPrices.length; ++i) {
                    _checkValue(nftPrices[i]);
                }
                nftPricing = nftPrices;
            }
            /// @notice Changes access of buying
            /// @param enabled The decision about buying
            function enableBuy(bool enabled) external onlyOwner {
                if (buyEnable == enabled) {
                    revert IdenticalValue();
                }
                emit BuyEnableUpdated({oldAccess: buyEnable, newAccess: enabled});
                buyEnable = enabled;
            }
            /// @notice Changes signer wallet address
            /// @param newSigner The address of the new signer wallet
            function changeSigner(
                address newSigner
            ) external checkAddressZero(newSigner) onlyOwner {
                address oldSigner = signerWallet;
                if (oldSigner == newSigner) {
                    revert IdenticalValue();
                }
                emit SignerUpdated({oldSigner: oldSigner, newSigner: newSigner});
                signerWallet = newSigner;
            }
            /// @notice Changes funds wallet to a new address
            /// @param newFundsWallet The address of the new funds wallet
            function changeFundsWallet(
                address newFundsWallet
            ) external checkAddressZero(newFundsWallet) onlyOwner {
                address oldWallet = fundsWallet;
                if (oldWallet == newFundsWallet) {
                    revert IdenticalValue();
                }
                emit FundsWalletUpdated({
                    oldAddress: oldWallet,
                    newAddress: newFundsWallet
                });
                fundsWallet = newFundsWallet;
            }
            /// @notice Changes the access of any address in contract interaction
            /// @param which The address for which access is updated
            /// @param access The access decision of `which` address
            function updateBlackListedUser(
                address which,
                bool access
            ) external checkAddressZero(which) onlyOwner {
                bool oldAccess = blacklistAddress[which];
                if (oldAccess == access) {
                    revert IdenticalValue();
                }
                emit BlacklistUpdated({which: which, accessNow: access});
                blacklistAddress[which] = access;
            }
            /// @notice Purchases dopToken with Eth
            /// @param code The code is used to verify signature of the user
            /// @param round The round in which user wants to purchase
            /// @param deadline The deadline is validity of the signature
            /// @param minAmountDop The minAmountDop user agrees to purchase
            /// @param v The `v` signature parameter
            /// @param r The `r` signature parameter
            /// @param s The `s` signature parameter
            function purchaseTokenWithEth(
                string memory code,
                uint32 round,
                uint256 deadline,
                uint256 minAmountDop,
                uint8 v,
                bytes32 r,
                bytes32 s
            ) external payable canBuy {
                // The input must have been signed by the presale signer
                _validatePurchaseWithEth(msg.value, round, deadline, code, v, r, s);
                uint256 roundPrice = _getRoundPriceForToken(round, ETH);
                TokenInfo memory tokenInfo = getLatestPrice(ETH);
                if (tokenInfo.latestPrice == 0) {
                    revert PriceNotFound();
                }
                uint256 toReturn = _calculateDop(
                    msg.value,
                    tokenInfo.latestPrice,
                    tokenInfo.normalizationFactorForToken,
                    roundPrice
                );
                if (toReturn < minAmountDop) {
                    revert UnexpectedPriceDifference();
                }
                claims[msg.sender][round] += toReturn;
                payable(fundsWallet).sendValue(msg.value);
                emit InvestedWithETH({
                    by: msg.sender,
                    code: code,
                    amountInvestedEth: msg.value,
                    round: round,
                    roundPrice: roundPrice,
                    dopPurchased: toReturn
                });
            }
            /// @notice Purchases dopToken with any token
            /// @param token The address of investment token
            /// @param referenceNormalizationFactor The normalization factor
            /// @param referenceTokenPrice The current price of token in 10 decimals
            /// @param investment The Investment amount
            /// @param minAmountDop The minAmountDop user agrees to purchase
            /// @param code The code is used to verify signature of the user
            /// @param round The round in which user wants to purchase
            /// @param deadline The deadline is validity of the signature
            /// @param v The `v` signature parameter
            /// @param r The `r` signature parameter
            /// @param s The `s` signature parameter
            function purchaseTokenWithToken(
                IERC20 token,
                uint8 referenceNormalizationFactor,
                uint256 referenceTokenPrice,
                uint256 investment,
                uint256 minAmountDop,
                string memory code,
                uint32 round,
                uint256 deadline,
                uint8 v,
                bytes32 r,
                bytes32 s
            ) external canBuy nonReentrant {
                // The input must have been signed by the presale signer
                _validatePurchaseWithToken(
                    token,
                    round,
                    deadline,
                    code,
                    referenceTokenPrice,
                    referenceNormalizationFactor,
                    v,
                    r,
                    s
                );
                _checkValue(investment);
                uint256 roundPrice = _getRoundPriceForToken(round, token);
                (uint256 latestPrice, uint256 normalizationFactor) = _validatePrice(
                    token,
                    referenceTokenPrice,
                    referenceNormalizationFactor
                );
                uint256 toReturn = _calculateDop(
                    investment,
                    latestPrice,
                    normalizationFactor,
                    roundPrice
                );
                if (toReturn < minAmountDop) {
                    revert UnexpectedPriceDifference();
                }
                claims[msg.sender][round] += toReturn;
                token.safeTransferFrom(msg.sender, fundsWallet, investment);
                emit InvestedWithToken({
                    token: token,
                    tokenPrice: latestPrice,
                    by: msg.sender,
                    code: code,
                    amountInvested: investment,
                    dopPurchased: toReturn,
                    round: round
                });
            }
            /// @notice Purchases NFT with Eth
            /// @param code The code is used to verify signature of the user
            /// @param round The round in which user wants to purchase
            /// @param nftAmounts The nftAmounts is array of nfts selected
            /// @param deadline The deadline is validity of the signature
            /// @param v The `v` signature parameter
            /// @param r The `r` signature parameter
            /// @param s The `s` signature parameter
            function purchaseNFTWithEth(
                string memory code,
                uint32 round,
                uint256[] calldata nftAmounts,
                uint256 deadline,
                uint8 v,
                bytes32 r,
                bytes32 s
            ) external payable canBuy nonReentrant {
                uint256[] memory nftPrices = nftPricing;
                _validateArrays(nftAmounts.length, nftPrices.length);
                // The input must have been signed by the presale signer
                _validatePurchaseWithEth(msg.value, round, deadline, code, v, r, s);
                TokenInfo memory tokenInfo = getLatestPrice(ETH);
                if (tokenInfo.latestPrice == 0) {
                    revert PriceNotFound();
                }
                (uint256 value, uint256 roundPrice) = _processPurchaseNFT(
                    ETH,
                    tokenInfo.latestPrice,
                    tokenInfo.normalizationFactorForNFT,
                    round,
                    nftAmounts,
                    nftPrices
                );
                if (msg.value < value) {
                    revert InvalidInvestment();
                }
                _checkValue(value);
                uint256 amountUnused = msg.value - value;
                if (amountUnused > 0) {
                    payable(msg.sender).sendValue(amountUnused);
                }
                payable(fundsWallet).sendValue(value);
                emit InvestedWithETHForNFT({
                    by: msg.sender,
                    code: code,
                    amountInEth: value,
                    ethPrice: tokenInfo.latestPrice,
                    round: round,
                    roundPrice: roundPrice,
                    nftAmounts: nftAmounts
                });
            }
            /// @notice Purchases NFT with token
            /// @param token The address of investment token
            /// @param referenceTokenPrice The current price of token in 10 decimals
            /// @param referenceNormalizationFactor The normalization factor
            /// @param code The code is used to verify signature of the user
            /// @param round The round in which user wants to purchase
            /// @param nftAmounts The nftAmounts is array of nfts selected
            /// @param deadline The deadline is validity of the signature
            /// @param v The `v` signature parameter
            /// @param r The `r` signature parameter
            /// @param s The `s` signature parameter
            function purchaseNFTWithToken(
                IERC20 token,
                uint256 referenceTokenPrice,
                uint8 referenceNormalizationFactor,
                string memory code,
                uint32 round,
                uint256[] calldata nftAmounts,
                uint256 deadline,
                uint8 v,
                bytes32 r,
                bytes32 s
            ) external canBuy nonReentrant {
                uint256[] memory nftPrices = nftPricing;
                _validateArrays(nftAmounts.length, nftPrices.length);
                // The input must have been signed by the presale signer
                _validatePurchaseWithToken(
                    token,
                    round,
                    deadline,
                    code,
                    referenceTokenPrice,
                    referenceNormalizationFactor,
                    v,
                    r,
                    s
                );
                TokenInfo memory tokenInfo = getLatestPrice(token);
                if (tokenInfo.latestPrice != 0) {
                    if (referenceTokenPrice != 0 || referenceNormalizationFactor != 0) {
                        revert CodeSyncIssue();
                    }
                }
                //  If price feed isn't available,we fallback to the reference price
                if (tokenInfo.latestPrice == 0) {
                    if (referenceTokenPrice == 0 || referenceNormalizationFactor == 0) {
                        revert ZeroValue();
                    }
                    tokenInfo.latestPrice = referenceTokenPrice;
                    tokenInfo.normalizationFactorForNFT = referenceNormalizationFactor;
                }
                (uint256 value, uint256 roundPrice) = _processPurchaseNFT(
                    token,
                    tokenInfo.latestPrice,
                    tokenInfo.normalizationFactorForNFT,
                    round,
                    nftAmounts,
                    nftPrices
                );
                _checkValue(value);
                token.safeTransferFrom(msg.sender, fundsWallet, value);
                emit InvestedWithTokenForNFT({
                    token: token,
                    tokenPrice: tokenInfo.latestPrice,
                    by: msg.sender,
                    code: code,
                    amountInvested: value,
                    round: round,
                    roundPrice: roundPrice,
                    nftAmounts: nftAmounts
                });
            }
            /// @inheritdoc IPreSaleDop
            function purchaseWithClaim(
                IERC20 token,
                uint256 referenceTokenPrice,
                uint8 referenceNormalizationFactor,
                uint256 amount,
                uint256 minAmountDop,
                address recipient,
                uint32 round
            ) external payable canBuy nonReentrant {
                if (msg.sender != claimsContract) {
                    revert OnlyClaims();
                }
                _checkBlacklist(recipient);
                if (!allowedTokens[round][token].access) {
                    revert TokenDisallowed();
                }
                uint256 roundPrice = _getRoundPriceForToken(round, token);
                (uint256 latestPrice, uint256 normalizationFactor) = _validatePrice(
                    token,
                    referenceTokenPrice,
                    referenceNormalizationFactor
                );
                uint256 toReturn = _calculateDop(
                    amount,
                    latestPrice,
                    normalizationFactor,
                    roundPrice
                );
                if (toReturn < minAmountDop) {
                    revert UnexpectedPriceDifference();
                }
                claims[recipient][round] += toReturn;
                if (token == ETH) {
                    payable(fundsWallet).sendValue(msg.value);
                } else {
                    token.safeTransferFrom(claimsContract, fundsWallet, amount);
                }
                emit InvestedWithClaimAmount({
                    by: recipient,
                    amount: amount,
                    token: token,
                    round: round,
                    tokenPrice: latestPrice,
                    dopPurchased: toReturn
                });
            }
            /// @notice Changes the access of any address in contract interaction
            /// @param newPrices The new prices of NFTs
            function updatePricing(uint256[] memory newPrices) external onlyOwner {
                uint256[] memory oldPrices = nftPricing;
                if (newPrices.length != oldPrices.length) {
                    revert ArrayLengthMismatch();
                }
                for (uint256 i = 0; i < newPrices.length; ++i) {
                    uint256 newPrice = newPrices[i];
                    _checkValue(newPrice);
                    emit PricingUpdated({oldPrice: oldPrices[i], newPrice: newPrice});
                }
                nftPricing = newPrices;
            }
            /// @inheritdoc IPreSaleDop
            function verifyPurchaseWithClaim(
                address recipient,
                uint32 round,
                uint256 deadline,
                uint256[] calldata tokenPrices,
                uint8[] calldata normalizationFactors,
                IERC20[] calldata tokens,
                uint256[] calldata amounts,
                uint8 v,
                bytes32 r,
                bytes32 s
            ) external view {
                if (msg.sender != claimsContract) {
                    revert OnlyClaims();
                }
                bytes32 encodedMessageHash = keccak256(
                    abi.encodePacked(
                        recipient,
                        round,
                        tokenPrices,
                        normalizationFactors,
                        deadline,
                        tokens,
                        amounts
                    )
                );
                _verifyMessage(encodedMessageHash, v, r, s);
            }
            /// @notice The Chainlink inherited function, give us tokens live price
            function getLatestPrice(
                IERC20 token
            ) public view returns (TokenInfo memory) {
                PriceFeedData memory data = tokenData[token];
                TokenInfo memory tokenInfo;
                if (address(data.priceFeed) == address(0)) {
                    return tokenInfo;
                }
                (
                    ,
                    /*uint80 roundID*/ int price /*uint256 startedAt*/ /*uint80 answeredInRound*/,
                    ,
                    ,
                ) = /*uint256 timeStamp*/ data.priceFeed.latestRoundData();
                tokenInfo = TokenInfo({
                    latestPrice: uint256(price),
                    normalizationFactorForToken: data.normalizationFactorForToken,
                    normalizationFactorForNFT: data.normalizationFactorForNFT
                });
                return tokenInfo;
            }
            /// @notice Checks value, if zero then reverts
            function _checkValue(uint256 value) private pure {
                if (value == 0) {
                    revert ZeroValue();
                }
            }
            /// @notice Validates blacklist address, round and deadline
            function _validatePurchase(
                uint32 round,
                uint256 deadline,
                IERC20 token
            ) private view {
                if (block.timestamp > deadline) {
                    revert DeadlineExpired();
                }
                _checkBlacklist(msg.sender);
                if (!allowedTokens[round][token].access) {
                    revert TokenDisallowed();
                }
                _verifyInRound(round);
            }
            /// @notice The helper function which verifies signature, signed by signerWallet, reverts if Invalid
            function _verifyCode(
                string memory code,
                uint256 deadline,
                uint8 v,
                bytes32 r,
                bytes32 s
            ) private view {
                bytes32 encodedMessageHash = keccak256(
                    abi.encodePacked(msg.sender, code, deadline)
                );
                _verifyMessage(encodedMessageHash, v, r, s);
            }
            /// @notice The helper function which verifies signature, signed by signerWallet, reverts if Invalid
            function _verifyCodeWithPrice(
                string memory code,
                uint256 deadline,
                uint256 referenceTokenPrice,
                IERC20 token,
                uint256 normalizationFactor,
                uint8 v,
                bytes32 r,
                bytes32 s
            ) private view {
                bytes32 encodedMessageHash = keccak256(
                    abi.encodePacked(
                        msg.sender,
                        code,
                        referenceTokenPrice,
                        deadline,
                        token,
                        normalizationFactor
                    )
                );
                _verifyMessage(encodedMessageHash, v, r, s);
            }
            /// @notice Verifies the address that signed a hashed message (`hash`) with
            /// `signature`
            function _verifyMessage(
                bytes32 encodedMessageHash,
                uint8 v,
                bytes32 r,
                bytes32 s
            ) private view {
                if (
                    signerWallet !=
                    ECDSA.recover(
                        MessageHashUtils.toEthSignedMessageHash(encodedMessageHash),
                        v,
                        r,
                        s
                    )
                ) {
                    revert InvalidSignature();
                }
            }
            /// @notice Process nft purchase by calculating nft prices and investment amount
            function _processPurchaseNFT(
                IERC20 token,
                uint256 price,
                uint256 normalizationFactor,
                uint32 round,
                uint256[] calldata nftAmounts,
                uint256[] memory nftPrices
            ) private returns (uint256, uint256) {
                uint256 value = 0;
                for (uint256 i = 0; i < nftPrices.length; ++i) {
                    //  (10**0 * 10**6 +10**10) -10**10 = 6 decimals
                    value +=
                        (nftAmounts[i] * nftPrices[i] * (10 ** (normalizationFactor))) /
                        price;
                }
                uint256 roundPrice = _getRoundPriceForToken(round, token);
                ClaimNFT memory amounts = ClaimNFT({
                    nftAmounts: nftAmounts,
                    roundPrice: roundPrice
                });
                claimNFT[msg.sender][round].push(amounts);
                return (value, roundPrice);
            }
            /// @notice Checks that address is blacklisted or not
            function _checkBlacklist(address which) private view {
                if (blacklistAddress[which]) {
                    revert Blacklisted();
                }
            }
            /// @notice Validates round, deadline and signature
            function _validatePurchaseWithEth(
                uint256 amount,
                uint32 round,
                uint256 deadline,
                string memory code,
                uint8 v,
                bytes32 r,
                bytes32 s
            ) private view {
                _checkValue(amount);
                _validatePurchase(round, deadline, ETH);
                _verifyCode(code, deadline, v, r, s);
            }
            /// @notice Validates round, deadline and signature
            function _validatePurchaseWithToken(
                IERC20 token,
                uint32 round,
                uint256 deadline,
                string memory code,
                uint256 referenceTokenPrice,
                uint256 normalizationFactor,
                uint8 v,
                bytes32 r,
                bytes32 s
            ) private view {
                _validatePurchase(round, deadline, token);
                _verifyCodeWithPrice(
                    code,
                    deadline,
                    referenceTokenPrice,
                    token,
                    normalizationFactor,
                    v,
                    r,
                    s
                );
            }
            /// @notice Validates round, deadline and signature
            function _getRoundPriceForToken(
                uint32 round,
                IERC20 token
            ) private view returns (uint256) {
                uint256 customPrice = allowedTokens[round][token].customPrice;
                uint256 roundPrice = customPrice > 0
                    ? customPrice
                    : rounds[round].price;
                return roundPrice;
            }
            /// @notice Calculates the dop amount
            function _calculateDop(
                uint256 investment,
                uint256 referenceTokenPrice,
                uint256 normalizationFactor,
                uint256 roundPrice
            ) private pure returns (uint256) {
                // toReturn= (10**11 * 10**10 +10**15) -10**18 = 18 decimals
                uint256 toReturn = (investment *
                    referenceTokenPrice *
                    (10 ** normalizationFactor)) / roundPrice;
                return toReturn;
            }
            function _validatePrice(
                IERC20 token,
                uint256 referenceTokenPrice,
                uint8 referenceNormalizationFactor
            ) private view returns (uint256, uint256) {
                TokenInfo memory tokenInfo = getLatestPrice(token);
                if (tokenInfo.latestPrice != 0) {
                    if (referenceTokenPrice != 0 || referenceNormalizationFactor != 0) {
                        revert CodeSyncIssue();
                    }
                }
                //  If price feed isn't available,we fallback to the reference price
                if (tokenInfo.latestPrice == 0) {
                    if (referenceTokenPrice == 0 || referenceNormalizationFactor == 0) {
                        revert ZeroValue();
                    }
                    tokenInfo.latestPrice = referenceTokenPrice;
                    tokenInfo
                        .normalizationFactorForToken = referenceNormalizationFactor;
                }
                return (tokenInfo.latestPrice, tokenInfo.normalizationFactorForToken);
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity 0.8.22;
        import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
        import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
        import {TokensRegistry} from "./TokensRegistry.sol";
        import {IRounds} from "./IRounds.sol";
        import {ZeroAddress, ArrayLengthMismatch, ZeroLengthArray} from "./Common.sol";
        /// @title Rounds contract
        /// @notice Implements the Round creation and updating of presale
        /// @dev The Rounds contract allows you to create a round, update a round
        abstract contract Rounds is IRounds, Ownable, TokensRegistry {
            /// @notice Thrown when round time is not started
            error RoundNotStarted();
            /// @notice Thrown when round time is ended
            error RoundEnded();
            /// @notice Thrown when Round is not created
            error IncorrectRound();
            /// @notice Thrown when new round price is less than previous round price
            error PriceLessThanOldRound();
            /// @notice Thrown when round start time is invalid
            error InvalidStartTime();
            /// @notice Thrown when round end time is invalid
            error InvalidEndTime();
            /// @notice Thrown when new price is invalid
            error PriceInvalid();
            /// @notice Thrown when startTime is incorrect when updating round
            error IncorrectStartTime();
            /// @notice Thrown when endTime is incorrect when updating round
            error IncorrectEndTime();
            /// @notice Thrown when round price is greater than next round while updating
            error PriceGreaterThanNextRound();
            /// @notice Thrown when Token is restricted in given round
            error TokenDisallowed();
            /// @notice The round index of last round created
            uint32 internal immutable _startRound;
            /// @notice The count of rounds created
            uint32 internal _roundIndex;
            /// @notice mapping gives us access info of the token in a given round
            mapping(uint32 => mapping(IERC20 => AllowedToken)) public allowedTokens;
            /// @notice mapping gives Round Data of each round
            mapping(uint32 => RoundData) public rounds;
            /// @member access The access of the token
            /// @member customPrice The customPrice price in the round for the token
            struct AllowedToken {
                bool access;
                uint256 customPrice;
            }
            /// @member startTime The start time of round
            /// @member endTime The end time of round
            /// @member price The price in usd per DOP
            struct RoundData {
                uint256 startTime;
                uint256 endTime;
                uint256 price;
            }
            /// @dev Emitted when creating a new round
            event RoundCreated(uint32 indexed newRound, RoundData roundData);
            /// @dev Emitted when round is updated
            event RoundUpdated(uint32 indexed round, RoundData roundData);
            /// @dev Emitted when token access is updated
            event TokensAccessUpdated(
                uint32 indexed round,
                IERC20 indexed token,
                bool indexed access,
                uint256 customPrice
            );
            /// @dev Constructor.
            /// @param lastRound The last round created
            constructor(uint32 lastRound) {
                _startRound = lastRound;
                _roundIndex = lastRound;
            }
            /// @notice Creates a new Round
            /// @param startTime The startTime of the round
            /// @param endTime The endTime of the round
            /// @param price The dopToken price in 18 decimals, because our calculations returns a value in 36 decimals and toget returning value in 18 decimals we divide by round price
            function createNewRound(
                uint256 startTime,
                uint256 endTime,
                uint256 price
            ) external onlyOwner {
                RoundData memory prevRoundData = rounds[_roundIndex];
                uint32 newRound = ++_roundIndex;
                if (price < prevRoundData.price) {
                    revert PriceLessThanOldRound();
                }
                if (startTime < prevRoundData.endTime) {
                    revert InvalidStartTime();
                }
                _verifyRound(startTime, endTime, price);
                prevRoundData = RoundData({
                    startTime: startTime,
                    endTime: endTime,
                    price: price
                });
                rounds[newRound] = prevRoundData;
                emit RoundCreated({newRound: newRound, roundData: prevRoundData});
            }
            /// @notice Updates the access of tokens in a given round
            /// @param round The round in which you want to update
            /// @param tokens addresses of the tokens
            /// @param accesses The access for the tokens
            /// @param customPrices The customPrice prices if any for the tokens
            function updateAllowedTokens(
                uint32 round,
                IERC20[] calldata tokens,
                bool[] memory accesses,
                uint256[] memory customPrices
            ) external onlyOwner {
                if (tokens.length == 0) {
                    revert ZeroLengthArray();
                }
                if (
                    tokens.length != accesses.length ||
                    accesses.length != customPrices.length
                ) {
                    revert ArrayLengthMismatch();
                }
                mapping(IERC20 => AllowedToken) storage selectedRound = allowedTokens[
                    round
                ];
                for (uint256 i = 0; i < tokens.length; ++i) {
                    IERC20 token = tokens[i];
                    if (address(token) == address(0)) {
                        revert ZeroAddress();
                    }
                    AllowedToken memory allowedToken = AllowedToken({
                        access: accesses[i],
                        customPrice: customPrices[i]
                    });
                    selectedRound[token] = allowedToken;
                    emit TokensAccessUpdated({
                        round: round,
                        token: token,
                        access: allowedToken.access,
                        customPrice: allowedToken.customPrice
                    });
                }
            }
            /// @notice Updates round data
            /// @param round The Round that will be updated
            /// @param startTime The StartTime of the round
            /// @param endTime The EndTime of the round
            /// @param price The price of the round in 18 decimals
            function updateRound(
                uint32 round,
                uint256 startTime,
                uint256 endTime,
                uint256 price
            ) external onlyOwner {
                if (round <= _startRound || round > _roundIndex) {
                    revert IncorrectRound();
                }
                RoundData memory previousRound = rounds[round - 1];
                RoundData memory nextRound = rounds[round + 1];
                if (startTime < previousRound.endTime) {
                    revert IncorrectStartTime();
                }
                if (round != _roundIndex && endTime > nextRound.startTime) {
                    revert IncorrectEndTime();
                }
                if (price < previousRound.price) {
                    revert PriceLessThanOldRound();
                }
                if (round != _roundIndex && price > nextRound.price) {
                    revert PriceGreaterThanNextRound();
                }
                _verifyRound(startTime, endTime, price);
                rounds[round] = RoundData({
                    startTime: startTime,
                    endTime: endTime,
                    price: price
                });
                emit RoundUpdated({round: round, roundData: rounds[round]});
            }
            /// @notice Returns total rounds created
            /// @return The Round count
            function getRoundCount() external view returns (uint32) {
                return _roundIndex;
            }
            /// @notice Validates array length and values
            function _validateArrays(
                uint256 firstLength,
                uint256 secondLength
            ) internal pure {
                if (firstLength == 0) {
                    revert ZeroLengthArray();
                }
                if (firstLength != secondLength) {
                    revert ArrayLengthMismatch();
                }
            }
            /// @notice Checks round start and end time, reverts if Invalid
            function _verifyInRound(uint32 round) internal view {
                RoundData memory dataRound = rounds[round];
                if (block.timestamp < dataRound.startTime) {
                    revert RoundNotStarted();
                }
                if (block.timestamp >= dataRound.endTime) {
                    revert RoundEnded();
                }
            }
            /// @notice Checks the validity of startTime, endTime and price
            function _verifyRound(
                uint256 startTime,
                uint256 endTime,
                uint256 price
            ) internal view {
                if (startTime < block.timestamp) {
                    revert InvalidStartTime();
                }
                if (endTime <= startTime) {
                    revert InvalidEndTime();
                }
                if (price == 0) {
                    revert PriceInvalid();
                }
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity 0.8.22;
        import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
        import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
        import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
        import {ZeroAddress, ArrayLengthMismatch, ZeroLengthArray, IdenticalValue} from "./Common.sol";
        /// @title TokensRegistry contract
        /// @notice Implements the pricefeed of the tokens
        abstract contract TokensRegistry is Ownable {
            /// @notice The USDT normalization factor between DOP and USDT
            uint256 internal constant NORMALIZATION_FACTOR_DOP_USDT = 1e30;
            /// @notice Gives us onchain price oracle address of the token
            mapping(IERC20 => PriceFeedData) public tokenData;
            /// @dev Emitted when address of Chainlink priceFeed contract is added for the token
            event TokenDataAdded(IERC20 token, AggregatorV3Interface priceFeed);
            /// @member priceFeed The Chainlink priceFeed address
            /// @member normalizationFactorForToken The normalization factor to achieve return value of 18 decimals ,while calculating dop token purchases and always with different token decimals
            /// @member normalizationFactorForNFT The normalization factor is the value which helps us to convert decimals of USDT to investment token decimals and always with different token decimals
            struct PriceFeedData {
                AggregatorV3Interface priceFeed;
                uint8 normalizationFactorForToken;
                uint8 normalizationFactorForNFT;
            }
            /// @notice Of Chainlink price feed contracts
            /// @param tokens The addresses of the tokens
            /// @param priceFeedData Contains the priceFeed of the tokens and the normalization factor
            function setTokenPriceFeed(
                IERC20[] calldata tokens,
                PriceFeedData[] calldata priceFeedData
            ) external onlyOwner {
                if (tokens.length == 0) {
                    revert ZeroLengthArray();
                }
                if (tokens.length != priceFeedData.length) {
                    revert ArrayLengthMismatch();
                }
                for (uint256 i = 0; i < tokens.length; ++i) {
                    PriceFeedData memory data = priceFeedData[i];
                    IERC20 token = tokens[i];
                    PriceFeedData memory currentPriceFeedData = tokenData[token];
                    if (
                        address(token) == address(0) ||
                        address(data.priceFeed) == address(0)
                    ) {
                        revert ZeroAddress();
                    }
                    if (
                        currentPriceFeedData.priceFeed == data.priceFeed &&
                        currentPriceFeedData.normalizationFactorForToken ==
                        data.normalizationFactorForToken &&
                        currentPriceFeedData.normalizationFactorForNFT ==
                        data.normalizationFactorForNFT
                    ) {
                        revert IdenticalValue();
                    }
                    emit TokenDataAdded({token: token, priceFeed: data.priceFeed});
                    tokenData[token] = data;
                }
            }
        }
        

        File 2 of 5: GnosisSafeProxy
        // SPDX-License-Identifier: LGPL-3.0-only
        pragma solidity >=0.7.0 <0.9.0;
        
        /// @title IProxy - Helper interface to access masterCopy of the Proxy on-chain
        /// @author Richard Meissner - <[email protected]>
        interface IProxy {
            function masterCopy() external view returns (address);
        }
        
        /// @title GnosisSafeProxy - Generic proxy contract allows to execute all transactions applying the code of a master contract.
        /// @author Stefan George - <[email protected]>
        /// @author Richard Meissner - <[email protected]>
        contract GnosisSafeProxy {
            // singleton always needs to be first declared variable, to ensure that it is at the same location in the contracts to which calls are delegated.
            // To reduce deployment costs this variable is internal and needs to be retrieved via `getStorageAt`
            address internal singleton;
        
            /// @dev Constructor function sets address of singleton contract.
            /// @param _singleton Singleton address.
            constructor(address _singleton) {
                require(_singleton != address(0), "Invalid singleton address provided");
                singleton = _singleton;
            }
        
            /// @dev Fallback function forwards all transactions and returns all received return data.
            fallback() external payable {
                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let _singleton := and(sload(0), 0xffffffffffffffffffffffffffffffffffffffff)
                    // 0xa619486e == keccak("masterCopy()"). The value is right padded to 32-bytes with 0s
                    if eq(calldataload(0), 0xa619486e00000000000000000000000000000000000000000000000000000000) {
                        mstore(0, _singleton)
                        return(0, 0x20)
                    }
                    calldatacopy(0, 0, calldatasize())
                    let success := delegatecall(gas(), _singleton, 0, calldatasize(), 0, 0)
                    returndatacopy(0, 0, returndatasize())
                    if eq(success, 0) {
                        revert(0, returndatasize())
                    }
                    return(0, returndatasize())
                }
            }
        }
        
        /// @title Proxy Factory - Allows to create new proxy contact and execute a message call to the new proxy within one transaction.
        /// @author Stefan George - <[email protected]>
        contract GnosisSafeProxyFactory {
            event ProxyCreation(GnosisSafeProxy proxy, address singleton);
        
            /// @dev Allows to create new proxy contact and execute a message call to the new proxy within one transaction.
            /// @param singleton Address of singleton contract.
            /// @param data Payload for message call sent to new proxy contract.
            function createProxy(address singleton, bytes memory data) public returns (GnosisSafeProxy proxy) {
                proxy = new GnosisSafeProxy(singleton);
                if (data.length > 0)
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        if eq(call(gas(), proxy, 0, add(data, 0x20), mload(data), 0, 0), 0) {
                            revert(0, 0)
                        }
                    }
                emit ProxyCreation(proxy, singleton);
            }
        
            /// @dev Allows to retrieve the runtime code of a deployed Proxy. This can be used to check that the expected Proxy was deployed.
            function proxyRuntimeCode() public pure returns (bytes memory) {
                return type(GnosisSafeProxy).runtimeCode;
            }
        
            /// @dev Allows to retrieve the creation code used for the Proxy deployment. With this it is easily possible to calculate predicted address.
            function proxyCreationCode() public pure returns (bytes memory) {
                return type(GnosisSafeProxy).creationCode;
            }
        
            /// @dev Allows to create new proxy contact using CREATE2 but it doesn't run the initializer.
            ///      This method is only meant as an utility to be called from other methods
            /// @param _singleton Address of singleton contract.
            /// @param initializer Payload for message call sent to new proxy contract.
            /// @param saltNonce Nonce that will be used to generate the salt to calculate the address of the new proxy contract.
            function deployProxyWithNonce(
                address _singleton,
                bytes memory initializer,
                uint256 saltNonce
            ) internal returns (GnosisSafeProxy proxy) {
                // If the initializer changes the proxy address should change too. Hashing the initializer data is cheaper than just concatinating it
                bytes32 salt = keccak256(abi.encodePacked(keccak256(initializer), saltNonce));
                bytes memory deploymentData = abi.encodePacked(type(GnosisSafeProxy).creationCode, uint256(uint160(_singleton)));
                // solhint-disable-next-line no-inline-assembly
                assembly {
                    proxy := create2(0x0, add(0x20, deploymentData), mload(deploymentData), salt)
                }
                require(address(proxy) != address(0), "Create2 call failed");
            }
        
            /// @dev Allows to create new proxy contact and execute a message call to the new proxy within one transaction.
            /// @param _singleton Address of singleton contract.
            /// @param initializer Payload for message call sent to new proxy contract.
            /// @param saltNonce Nonce that will be used to generate the salt to calculate the address of the new proxy contract.
            function createProxyWithNonce(
                address _singleton,
                bytes memory initializer,
                uint256 saltNonce
            ) public returns (GnosisSafeProxy proxy) {
                proxy = deployProxyWithNonce(_singleton, initializer, saltNonce);
                if (initializer.length > 0)
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        if eq(call(gas(), proxy, 0, add(initializer, 0x20), mload(initializer), 0, 0), 0) {
                            revert(0, 0)
                        }
                    }
                emit ProxyCreation(proxy, _singleton);
            }
        
            /// @dev Allows to create new proxy contact, execute a message call to the new proxy and call a specified callback within one transaction
            /// @param _singleton Address of singleton contract.
            /// @param initializer Payload for message call sent to new proxy contract.
            /// @param saltNonce Nonce that will be used to generate the salt to calculate the address of the new proxy contract.
            /// @param callback Callback that will be invoced after the new proxy contract has been successfully deployed and initialized.
            function createProxyWithCallback(
                address _singleton,
                bytes memory initializer,
                uint256 saltNonce,
                IProxyCreationCallback callback
            ) public returns (GnosisSafeProxy proxy) {
                uint256 saltNonceWithCallback = uint256(keccak256(abi.encodePacked(saltNonce, callback)));
                proxy = createProxyWithNonce(_singleton, initializer, saltNonceWithCallback);
                if (address(callback) != address(0)) callback.proxyCreated(proxy, _singleton, initializer, saltNonce);
            }
        
            /// @dev Allows to get the address for a new proxy contact created via `createProxyWithNonce`
            ///      This method is only meant for address calculation purpose when you use an initializer that would revert,
            ///      therefore the response is returned with a revert. When calling this method set `from` to the address of the proxy factory.
            /// @param _singleton Address of singleton contract.
            /// @param initializer Payload for message call sent to new proxy contract.
            /// @param saltNonce Nonce that will be used to generate the salt to calculate the address of the new proxy contract.
            function calculateCreateProxyWithNonceAddress(
                address _singleton,
                bytes calldata initializer,
                uint256 saltNonce
            ) external returns (GnosisSafeProxy proxy) {
                proxy = deployProxyWithNonce(_singleton, initializer, saltNonce);
                revert(string(abi.encodePacked(proxy)));
            }
        }
        
        interface IProxyCreationCallback {
            function proxyCreated(
                GnosisSafeProxy proxy,
                address _singleton,
                bytes calldata initializer,
                uint256 saltNonce
            ) external;
        }

        File 3 of 5: EACAggregatorProxy
        pragma solidity 0.6.6;
        
        
        /**
         * @title The Owned contract
         * @notice A contract with helpers for basic contract ownership.
         */
        contract Owned {
        
          address payable public owner;
          address private pendingOwner;
        
          event OwnershipTransferRequested(
            address indexed from,
            address indexed to
          );
          event OwnershipTransferred(
            address indexed from,
            address indexed to
          );
        
          constructor() public {
            owner = msg.sender;
          }
        
          /**
           * @dev Allows an owner to begin transferring ownership to a new address,
           * pending.
           */
          function transferOwnership(address _to)
            external
            onlyOwner()
          {
            pendingOwner = _to;
        
            emit OwnershipTransferRequested(owner, _to);
          }
        
          /**
           * @dev Allows an ownership transfer to be completed by the recipient.
           */
          function acceptOwnership()
            external
          {
            require(msg.sender == pendingOwner, "Must be proposed owner");
        
            address oldOwner = owner;
            owner = msg.sender;
            pendingOwner = address(0);
        
            emit OwnershipTransferred(oldOwner, msg.sender);
          }
        
          /**
           * @dev Reverts if called by anyone other than the contract owner.
           */
          modifier onlyOwner() {
            require(msg.sender == owner, "Only callable by owner");
            _;
          }
        
        }
        
        interface AggregatorInterface {
          function latestAnswer() external view returns (int256);
          function latestTimestamp() external view returns (uint256);
          function latestRound() external view returns (uint256);
          function getAnswer(uint256 roundId) external view returns (int256);
          function getTimestamp(uint256 roundId) external view returns (uint256);
        
          event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 updatedAt);
          event NewRound(uint256 indexed roundId, address indexed startedBy, uint256 startedAt);
        }
        
        interface AggregatorV3Interface {
        
          function decimals() external view returns (uint8);
          function description() external view returns (string memory);
          function version() external view returns (uint256);
        
          // getRoundData and latestRoundData should both raise "No data present"
          // if they do not have data to report, instead of returning unset values
          // which could be misinterpreted as actual reported values.
          function getRoundData(uint80 _roundId)
            external
            view
            returns (
              uint80 roundId,
              int256 answer,
              uint256 startedAt,
              uint256 updatedAt,
              uint80 answeredInRound
            );
          function latestRoundData()
            external
            view
            returns (
              uint80 roundId,
              int256 answer,
              uint256 startedAt,
              uint256 updatedAt,
              uint80 answeredInRound
            );
        
        }
        
        interface AggregatorV2V3Interface is AggregatorInterface, AggregatorV3Interface
        {
        }
        
        /**
         * @title A trusted proxy for updating where current answers are read from
         * @notice This contract provides a consistent address for the
         * CurrentAnwerInterface but delegates where it reads from to the owner, who is
         * trusted to update it.
         */
        contract AggregatorProxy is AggregatorV2V3Interface, Owned {
        
          struct Phase {
            uint16 id;
            AggregatorV2V3Interface aggregator;
          }
          Phase private currentPhase;
          AggregatorV2V3Interface public proposedAggregator;
          mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators;
        
          uint256 constant private PHASE_OFFSET = 64;
          uint256 constant private PHASE_SIZE = 16;
          uint256 constant private MAX_ID = 2**(PHASE_OFFSET+PHASE_SIZE) - 1;
        
          constructor(address _aggregator) public Owned() {
            setAggregator(_aggregator);
          }
        
          /**
           * @notice Reads the current answer from aggregator delegated to.
           *
           * @dev #[deprecated] Use latestRoundData instead. This does not error if no
           * answer has been reached, it will simply return 0. Either wait to point to
           * an already answered Aggregator or use the recommended latestRoundData
           * instead which includes better verification information.
           */
          function latestAnswer()
            public
            view
            virtual
            override
            returns (int256 answer)
          {
            return currentPhase.aggregator.latestAnswer();
          }
        
          /**
           * @notice Reads the last updated height from aggregator delegated to.
           *
           * @dev #[deprecated] Use latestRoundData instead. This does not error if no
           * answer has been reached, it will simply return 0. Either wait to point to
           * an already answered Aggregator or use the recommended latestRoundData
           * instead which includes better verification information.
           */
          function latestTimestamp()
            public
            view
            virtual
            override
            returns (uint256 updatedAt)
          {
            return currentPhase.aggregator.latestTimestamp();
          }
        
          /**
           * @notice get past rounds answers
           * @param _roundId the answer number to retrieve the answer for
           *
           * @dev #[deprecated] Use getRoundData instead. This does not error if no
           * answer has been reached, it will simply return 0. Either wait to point to
           * an already answered Aggregator or use the recommended getRoundData
           * instead which includes better verification information.
           */
          function getAnswer(uint256 _roundId)
            public
            view
            virtual
            override
            returns (int256 answer)
          {
            if (_roundId > MAX_ID) return 0;
        
            (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId);
            AggregatorV2V3Interface aggregator = phaseAggregators[phaseId];
            if (address(aggregator) == address(0)) return 0;
        
            return aggregator.getAnswer(aggregatorRoundId);
          }
        
          /**
           * @notice get block timestamp when an answer was last updated
           * @param _roundId the answer number to retrieve the updated timestamp for
           *
           * @dev #[deprecated] Use getRoundData instead. This does not error if no
           * answer has been reached, it will simply return 0. Either wait to point to
           * an already answered Aggregator or use the recommended getRoundData
           * instead which includes better verification information.
           */
          function getTimestamp(uint256 _roundId)
            public
            view
            virtual
            override
            returns (uint256 updatedAt)
          {
            if (_roundId > MAX_ID) return 0;
        
            (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId);
            AggregatorV2V3Interface aggregator = phaseAggregators[phaseId];
            if (address(aggregator) == address(0)) return 0;
        
            return aggregator.getTimestamp(aggregatorRoundId);
          }
        
          /**
           * @notice get the latest completed round where the answer was updated. This
           * ID includes the proxy's phase, to make sure round IDs increase even when
           * switching to a newly deployed aggregator.
           *
           * @dev #[deprecated] Use latestRoundData instead. This does not error if no
           * answer has been reached, it will simply return 0. Either wait to point to
           * an already answered Aggregator or use the recommended latestRoundData
           * instead which includes better verification information.
           */
          function latestRound()
            public
            view
            virtual
            override
            returns (uint256 roundId)
          {
            Phase memory phase = currentPhase; // cache storage reads
            return addPhase(phase.id, uint64(phase.aggregator.latestRound()));
          }
        
          /**
           * @notice get data about a round. Consumers are encouraged to check
           * that they're receiving fresh data by inspecting the updatedAt and
           * answeredInRound return values.
           * Note that different underlying implementations of AggregatorV3Interface
           * have slightly different semantics for some of the return values. Consumers
           * should determine what implementations they expect to receive
           * data from and validate that they can properly handle return data from all
           * of them.
           * @param _roundId the requested round ID as presented through the proxy, this
           * is made up of the aggregator's round ID with the phase ID encoded in the
           * two highest order bytes
           * @return roundId is the round ID from the aggregator for which the data was
           * retrieved combined with an phase to ensure that round IDs get larger as
           * time moves forward.
           * @return answer is the answer for the given round
           * @return startedAt is the timestamp when the round was started.
           * (Only some AggregatorV3Interface implementations return meaningful values)
           * @return updatedAt is the timestamp when the round last was updated (i.e.
           * answer was last computed)
           * @return answeredInRound is the round ID of the round in which the answer
           * was computed.
           * (Only some AggregatorV3Interface implementations return meaningful values)
           * @dev Note that answer and updatedAt may change between queries.
           */
          function getRoundData(uint80 _roundId)
            public
            view
            virtual
            override
            returns (
              uint80 roundId,
              int256 answer,
              uint256 startedAt,
              uint256 updatedAt,
              uint80 answeredInRound
            )
          {
            (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId);
        
            (
              uint80 roundId,
              int256 answer,
              uint256 startedAt,
              uint256 updatedAt,
              uint80 ansIn
            ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId);
        
            return addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId);
          }
        
          /**
           * @notice get data about the latest round. Consumers are encouraged to check
           * that they're receiving fresh data by inspecting the updatedAt and
           * answeredInRound return values.
           * Note that different underlying implementations of AggregatorV3Interface
           * have slightly different semantics for some of the return values. Consumers
           * should determine what implementations they expect to receive
           * data from and validate that they can properly handle return data from all
           * of them.
           * @return roundId is the round ID from the aggregator for which the data was
           * retrieved combined with an phase to ensure that round IDs get larger as
           * time moves forward.
           * @return answer is the answer for the given round
           * @return startedAt is the timestamp when the round was started.
           * (Only some AggregatorV3Interface implementations return meaningful values)
           * @return updatedAt is the timestamp when the round last was updated (i.e.
           * answer was last computed)
           * @return answeredInRound is the round ID of the round in which the answer
           * was computed.
           * (Only some AggregatorV3Interface implementations return meaningful values)
           * @dev Note that answer and updatedAt may change between queries.
           */
          function latestRoundData()
            public
            view
            virtual
            override
            returns (
              uint80 roundId,
              int256 answer,
              uint256 startedAt,
              uint256 updatedAt,
              uint80 answeredInRound
            )
          {
            Phase memory current = currentPhase; // cache storage reads
        
            (
              uint80 roundId,
              int256 answer,
              uint256 startedAt,
              uint256 updatedAt,
              uint80 ansIn
            ) = current.aggregator.latestRoundData();
        
            return addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, current.id);
          }
        
          /**
           * @notice Used if an aggregator contract has been proposed.
           * @param _roundId the round ID to retrieve the round data for
           * @return roundId is the round ID for which data was retrieved
           * @return answer is the answer for the given round
           * @return startedAt is the timestamp when the round was started.
           * (Only some AggregatorV3Interface implementations return meaningful values)
           * @return updatedAt is the timestamp when the round last was updated (i.e.
           * answer was last computed)
           * @return answeredInRound is the round ID of the round in which the answer
           * was computed.
          */
          function proposedGetRoundData(uint80 _roundId)
            public
            view
            virtual
            hasProposal()
            returns (
              uint80 roundId,
              int256 answer,
              uint256 startedAt,
              uint256 updatedAt,
              uint80 answeredInRound
            )
          {
            return proposedAggregator.getRoundData(_roundId);
          }
        
          /**
           * @notice Used if an aggregator contract has been proposed.
           * @return roundId is the round ID for which data was retrieved
           * @return answer is the answer for the given round
           * @return startedAt is the timestamp when the round was started.
           * (Only some AggregatorV3Interface implementations return meaningful values)
           * @return updatedAt is the timestamp when the round last was updated (i.e.
           * answer was last computed)
           * @return answeredInRound is the round ID of the round in which the answer
           * was computed.
          */
          function proposedLatestRoundData()
            public
            view
            virtual
            hasProposal()
            returns (
              uint80 roundId,
              int256 answer,
              uint256 startedAt,
              uint256 updatedAt,
              uint80 answeredInRound
            )
          {
            return proposedAggregator.latestRoundData();
          }
        
          /**
           * @notice returns the current phase's aggregator address.
           */
          function aggregator()
            external
            view
            returns (address)
          {
            return address(currentPhase.aggregator);
          }
        
          /**
           * @notice returns the current phase's ID.
           */
          function phaseId()
            external
            view
            returns (uint16)
          {
            return currentPhase.id;
          }
        
          /**
           * @notice represents the number of decimals the aggregator responses represent.
           */
          function decimals()
            external
            view
            override
            returns (uint8)
          {
            return currentPhase.aggregator.decimals();
          }
        
          /**
           * @notice the version number representing the type of aggregator the proxy
           * points to.
           */
          function version()
            external
            view
            override
            returns (uint256)
          {
            return currentPhase.aggregator.version();
          }
        
          /**
           * @notice returns the description of the aggregator the proxy points to.
           */
          function description()
            external
            view
            override
            returns (string memory)
          {
            return currentPhase.aggregator.description();
          }
        
          /**
           * @notice Allows the owner to propose a new address for the aggregator
           * @param _aggregator The new address for the aggregator contract
           */
          function proposeAggregator(address _aggregator)
            external
            onlyOwner()
          {
            proposedAggregator = AggregatorV2V3Interface(_aggregator);
          }
        
          /**
           * @notice Allows the owner to confirm and change the address
           * to the proposed aggregator
           * @dev Reverts if the given address doesn't match what was previously
           * proposed
           * @param _aggregator The new address for the aggregator contract
           */
          function confirmAggregator(address _aggregator)
            external
            onlyOwner()
          {
            require(_aggregator == address(proposedAggregator), "Invalid proposed aggregator");
            delete proposedAggregator;
            setAggregator(_aggregator);
          }
        
        
          /*
           * Internal
           */
        
          function setAggregator(address _aggregator)
            internal
          {
            uint16 id = currentPhase.id + 1;
            currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator));
            phaseAggregators[id] = AggregatorV2V3Interface(_aggregator);
          }
        
          function addPhase(
            uint16 _phase,
            uint64 _originalId
          )
            internal
            view
            returns (uint80)
          {
            return uint80(uint256(_phase) << PHASE_OFFSET | _originalId);
          }
        
          function parseIds(
            uint256 _roundId
          )
            internal
            view
            returns (uint16, uint64)
          {
            uint16 phaseId = uint16(_roundId >> PHASE_OFFSET);
            uint64 aggregatorRoundId = uint64(_roundId);
        
            return (phaseId, aggregatorRoundId);
          }
        
          function addPhaseIds(
              uint80 roundId,
              int256 answer,
              uint256 startedAt,
              uint256 updatedAt,
              uint80 answeredInRound,
              uint16 phaseId
          )
            internal
            view
            returns (uint80, int256, uint256, uint256, uint80)
          {
            return (
              addPhase(phaseId, uint64(roundId)),
              answer,
              startedAt,
              updatedAt,
              addPhase(phaseId, uint64(answeredInRound))
            );
          }
        
          /*
           * Modifiers
           */
        
          modifier hasProposal() {
            require(address(proposedAggregator) != address(0), "No proposed aggregator present");
            _;
          }
        
        }
        
        interface AccessControllerInterface {
          function hasAccess(address user, bytes calldata data) external view returns (bool);
        }
        
        /**
         * @title External Access Controlled Aggregator Proxy
         * @notice A trusted proxy for updating where current answers are read from
         * @notice This contract provides a consistent address for the
         * Aggregator and AggregatorV3Interface but delegates where it reads from to the owner, who is
         * trusted to update it.
         * @notice Only access enabled addresses are allowed to access getters for
         * aggregated answers and round information.
         */
        contract EACAggregatorProxy is AggregatorProxy {
        
          AccessControllerInterface public accessController;
        
          constructor(
            address _aggregator,
            address _accessController
          )
            public
            AggregatorProxy(_aggregator)
          {
            setController(_accessController);
          }
        
          /**
           * @notice Allows the owner to update the accessController contract address.
           * @param _accessController The new address for the accessController contract
           */
          function setController(address _accessController)
            public
            onlyOwner()
          {
            accessController = AccessControllerInterface(_accessController);
          }
        
          /**
           * @notice Reads the current answer from aggregator delegated to.
           * @dev overridden function to add the checkAccess() modifier
           *
           * @dev #[deprecated] Use latestRoundData instead. This does not error if no
           * answer has been reached, it will simply return 0. Either wait to point to
           * an already answered Aggregator or use the recommended latestRoundData
           * instead which includes better verification information.
           */
          function latestAnswer()
            public
            view
            override
            checkAccess()
            returns (int256)
          {
            return super.latestAnswer();
          }
        
          /**
           * @notice get the latest completed round where the answer was updated. This
           * ID includes the proxy's phase, to make sure round IDs increase even when
           * switching to a newly deployed aggregator.
           *
           * @dev #[deprecated] Use latestRoundData instead. This does not error if no
           * answer has been reached, it will simply return 0. Either wait to point to
           * an already answered Aggregator or use the recommended latestRoundData
           * instead which includes better verification information.
           */
          function latestTimestamp()
            public
            view
            override
            checkAccess()
            returns (uint256)
          {
            return super.latestTimestamp();
          }
        
          /**
           * @notice get past rounds answers
           * @param _roundId the answer number to retrieve the answer for
           * @dev overridden function to add the checkAccess() modifier
           *
           * @dev #[deprecated] Use getRoundData instead. This does not error if no
           * answer has been reached, it will simply return 0. Either wait to point to
           * an already answered Aggregator or use the recommended getRoundData
           * instead which includes better verification information.
           */
          function getAnswer(uint256 _roundId)
            public
            view
            override
            checkAccess()
            returns (int256)
          {
            return super.getAnswer(_roundId);
          }
        
          /**
           * @notice get block timestamp when an answer was last updated
           * @param _roundId the answer number to retrieve the updated timestamp for
           * @dev overridden function to add the checkAccess() modifier
           *
           * @dev #[deprecated] Use getRoundData instead. This does not error if no
           * answer has been reached, it will simply return 0. Either wait to point to
           * an already answered Aggregator or use the recommended getRoundData
           * instead which includes better verification information.
           */
          function getTimestamp(uint256 _roundId)
            public
            view
            override
            checkAccess()
            returns (uint256)
          {
            return super.getTimestamp(_roundId);
          }
        
          /**
           * @notice get the latest completed round where the answer was updated
           * @dev overridden function to add the checkAccess() modifier
           *
           * @dev #[deprecated] Use latestRoundData instead. This does not error if no
           * answer has been reached, it will simply return 0. Either wait to point to
           * an already answered Aggregator or use the recommended latestRoundData
           * instead which includes better verification information.
           */
          function latestRound()
            public
            view
            override
            checkAccess()
            returns (uint256)
          {
            return super.latestRound();
          }
        
          /**
           * @notice get data about a round. Consumers are encouraged to check
           * that they're receiving fresh data by inspecting the updatedAt and
           * answeredInRound return values.
           * Note that different underlying implementations of AggregatorV3Interface
           * have slightly different semantics for some of the return values. Consumers
           * should determine what implementations they expect to receive
           * data from and validate that they can properly handle return data from all
           * of them.
           * @param _roundId the round ID to retrieve the round data for
           * @return roundId is the round ID from the aggregator for which the data was
           * retrieved combined with a phase to ensure that round IDs get larger as
           * time moves forward.
           * @return answer is the answer for the given round
           * @return startedAt is the timestamp when the round was started.
           * (Only some AggregatorV3Interface implementations return meaningful values)
           * @return updatedAt is the timestamp when the round last was updated (i.e.
           * answer was last computed)
           * @return answeredInRound is the round ID of the round in which the answer
           * was computed.
           * (Only some AggregatorV3Interface implementations return meaningful values)
           * @dev Note that answer and updatedAt may change between queries.
           */
          function getRoundData(uint80 _roundId)
            public
            view
            checkAccess()
            override
            returns (
              uint80 roundId,
              int256 answer,
              uint256 startedAt,
              uint256 updatedAt,
              uint80 answeredInRound
            )
          {
            return super.getRoundData(_roundId);
          }
        
          /**
           * @notice get data about the latest round. Consumers are encouraged to check
           * that they're receiving fresh data by inspecting the updatedAt and
           * answeredInRound return values.
           * Note that different underlying implementations of AggregatorV3Interface
           * have slightly different semantics for some of the return values. Consumers
           * should determine what implementations they expect to receive
           * data from and validate that they can properly handle return data from all
           * of them.
           * @return roundId is the round ID from the aggregator for which the data was
           * retrieved combined with a phase to ensure that round IDs get larger as
           * time moves forward.
           * @return answer is the answer for the given round
           * @return startedAt is the timestamp when the round was started.
           * (Only some AggregatorV3Interface implementations return meaningful values)
           * @return updatedAt is the timestamp when the round last was updated (i.e.
           * answer was last computed)
           * @return answeredInRound is the round ID of the round in which the answer
           * was computed.
           * (Only some AggregatorV3Interface implementations return meaningful values)
           * @dev Note that answer and updatedAt may change between queries.
           */
          function latestRoundData()
            public
            view
            checkAccess()
            override
            returns (
              uint80 roundId,
              int256 answer,
              uint256 startedAt,
              uint256 updatedAt,
              uint80 answeredInRound
            )
          {
            return super.latestRoundData();
          }
        
          /**
           * @notice Used if an aggregator contract has been proposed.
           * @param _roundId the round ID to retrieve the round data for
           * @return roundId is the round ID for which data was retrieved
           * @return answer is the answer for the given round
           * @return startedAt is the timestamp when the round was started.
           * (Only some AggregatorV3Interface implementations return meaningful values)
           * @return updatedAt is the timestamp when the round last was updated (i.e.
           * answer was last computed)
           * @return answeredInRound is the round ID of the round in which the answer
           * was computed.
          */
          function proposedGetRoundData(uint80 _roundId)
            public
            view
            checkAccess()
            hasProposal()
            override
            returns (
              uint80 roundId,
              int256 answer,
              uint256 startedAt,
              uint256 updatedAt,
              uint80 answeredInRound
            )
          {
            return super.proposedGetRoundData(_roundId);
          }
        
          /**
           * @notice Used if an aggregator contract has been proposed.
           * @return roundId is the round ID for which data was retrieved
           * @return answer is the answer for the given round
           * @return startedAt is the timestamp when the round was started.
           * (Only some AggregatorV3Interface implementations return meaningful values)
           * @return updatedAt is the timestamp when the round last was updated (i.e.
           * answer was last computed)
           * @return answeredInRound is the round ID of the round in which the answer
           * was computed.
          */
          function proposedLatestRoundData()
            public
            view
            checkAccess()
            hasProposal()
            override
            returns (
              uint80 roundId,
              int256 answer,
              uint256 startedAt,
              uint256 updatedAt,
              uint80 answeredInRound
            )
          {
            return super.proposedLatestRoundData();
          }
        
          /**
           * @dev reverts if the caller does not have access by the accessController
           * contract or is the contract itself.
           */
          modifier checkAccess() {
            AccessControllerInterface ac = accessController;
            require(address(ac) == address(0) || ac.hasAccess(msg.sender, msg.data), "No access");
            _;
          }
        }

        File 4 of 5: AccessControlledOffchainAggregator
        // SPDX-License-Identifier: MIT
        pragma solidity 0.7.6;
        import "./OffchainAggregator.sol";
        import "./SimpleReadAccessController.sol";
        /**
         * @notice Wrapper of OffchainAggregator which checks read access on Aggregator-interface methods
         */
        contract AccessControlledOffchainAggregator is OffchainAggregator, SimpleReadAccessController {
          constructor(
            uint32 _maximumGasPrice,
            uint32 _reasonableGasPrice,
            uint32 _microLinkPerEth,
            uint32 _linkGweiPerObservation,
            uint32 _linkGweiPerTransmission,
            LinkTokenInterface _link,
            int192 _minAnswer,
            int192 _maxAnswer,
            AccessControllerInterface _billingAccessController,
            AccessControllerInterface _requesterAccessController,
            uint8 _decimals,
            string memory description
          )
            OffchainAggregator(
              _maximumGasPrice,
              _reasonableGasPrice,
              _microLinkPerEth,
              _linkGweiPerObservation,
              _linkGweiPerTransmission,
              _link,
              _minAnswer,
              _maxAnswer,
              _billingAccessController,
              _requesterAccessController,
              _decimals,
              description
            ) {
            }
          /*
           * Versioning
           */
          function typeAndVersion()
            external
            override
            pure
            virtual
            returns (string memory)
          {
            return "AccessControlledOffchainAggregator 4.0.0";
          }
          /*
           * v2 Aggregator interface
           */
          /// @inheritdoc OffchainAggregator
          function latestAnswer()
            public
            override
            view
            checkAccess()
            returns (int256)
          {
            return super.latestAnswer();
          }
          /// @inheritdoc OffchainAggregator
          function latestTimestamp()
            public
            override
            view
            checkAccess()
            returns (uint256)
          {
            return super.latestTimestamp();
          }
          /// @inheritdoc OffchainAggregator
          function latestRound()
            public
            override
            view
            checkAccess()
            returns (uint256)
          {
            return super.latestRound();
          }
          /// @inheritdoc OffchainAggregator
          function getAnswer(uint256 _roundId)
            public
            override
            view
            checkAccess()
            returns (int256)
          {
            return super.getAnswer(_roundId);
          }
          /// @inheritdoc OffchainAggregator
          function getTimestamp(uint256 _roundId)
            public
            override
            view
            checkAccess()
            returns (uint256)
          {
            return super.getTimestamp(_roundId);
          }
          /*
           * v3 Aggregator interface
           */
          /// @inheritdoc OffchainAggregator
          function description()
            public
            override
            view
            checkAccess()
            returns (string memory)
          {
            return super.description();
          }
          /// @inheritdoc OffchainAggregator
          function getRoundData(uint80 _roundId)
            public
            override
            view
            checkAccess()
            returns (
              uint80 roundId,
              int256 answer,
              uint256 startedAt,
              uint256 updatedAt,
              uint80 answeredInRound
            )
          {
            return super.getRoundData(_roundId);
          }
          /// @inheritdoc OffchainAggregator
          function latestRoundData()
            public
            override
            view
            checkAccess()
            returns (
              uint80 roundId,
              int256 answer,
              uint256 startedAt,
              uint256 updatedAt,
              uint80 answeredInRound
            )
          {
            return super.latestRoundData();
          }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.7.0;
        interface AccessControllerInterface {
          function hasAccess(address user, bytes calldata data) external view returns (bool);
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.7.0;
        interface AggregatorInterface {
          function latestAnswer() external view returns (int256);
          function latestTimestamp() external view returns (uint256);
          function latestRound() external view returns (uint256);
          function getAnswer(uint256 roundId) external view returns (int256);
          function getTimestamp(uint256 roundId) external view returns (uint256);
          event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 updatedAt);
          event NewRound(uint256 indexed roundId, address indexed startedBy, uint256 startedAt);
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.7.0;
        import "./AggregatorInterface.sol";
        import "./AggregatorV3Interface.sol";
        interface AggregatorV2V3Interface is AggregatorInterface, AggregatorV3Interface
        {
        }// SPDX-License-Identifier: MIT
        pragma solidity ^0.7.0;
        interface AggregatorV3Interface {
          function decimals() external view returns (uint8);
          function description() external view returns (string memory);
          function version() external view returns (uint256);
          function getRoundData(uint80 _roundId)
            external
            view
            returns (
              uint80 roundId,
              int256 answer,
              uint256 startedAt,
              uint256 updatedAt,
              uint80 answeredInRound
            );
          function latestRoundData()
            external
            view
            returns (
              uint80 roundId,
              int256 answer,
              uint256 startedAt,
              uint256 updatedAt,
              uint80 answeredInRound
            );
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.7.0;
        interface AggregatorValidatorInterface {
          function validate(
            uint256 previousRoundId,
            int256 previousAnswer,
            uint256 currentRoundId,
            int256 currentAnswer
          ) external returns (bool);
        }// SPDX-License-Identifier: MIT
        pragma solidity ^0.7.0;
        interface LinkTokenInterface {
          function allowance(address owner, address spender) external view returns (uint256 remaining);
          function approve(address spender, uint256 value) external returns (bool success);
          function balanceOf(address owner) external view returns (uint256 balance);
          function decimals() external view returns (uint8 decimalPlaces);
          function decreaseApproval(address spender, uint256 addedValue) external returns (bool success);
          function increaseApproval(address spender, uint256 subtractedValue) external;
          function name() external view returns (string memory tokenName);
          function symbol() external view returns (string memory tokenSymbol);
          function totalSupply() external view returns (uint256 totalTokensIssued);
          function transfer(address to, uint256 value) external returns (bool success);
          function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool success);
          function transferFrom(address from, address to, uint256 value) external returns (bool success);
        }
        // SPDX-License-Identifier: MIT
        pragma solidity 0.7.6;
        import "./AccessControllerInterface.sol";
        import "./AggregatorV2V3Interface.sol";
        import "./AggregatorValidatorInterface.sol";
        import "./LinkTokenInterface.sol";
        import "./Owned.sol";
        import "./OffchainAggregatorBilling.sol";
        import "./TypeAndVersionInterface.sol";
        /**
          * @notice Onchain verification of reports from the offchain reporting protocol
          * @dev For details on its operation, see the offchain reporting protocol design
          * @dev doc, which refers to this contract as simply the "contract".
        */
        contract OffchainAggregator is Owned, OffchainAggregatorBilling, AggregatorV2V3Interface, TypeAndVersionInterface {
          uint256 constant private maxUint32 = (1 << 32) - 1;
          // Storing these fields used on the hot path in a HotVars variable reduces the
          // retrieval of all of them to a single SLOAD. If any further fields are
          // added, make sure that storage of the struct still takes at most 32 bytes.
          struct HotVars {
            // Provides 128 bits of security against 2nd pre-image attacks, but only
            // 64 bits against collisions. This is acceptable, since a malicious owner has
            // easier way of messing up the protocol than to find hash collisions.
            bytes16 latestConfigDigest;
            uint40 latestEpochAndRound; // 32 most sig bits for epoch, 8 least sig bits for round
            // Current bound assumed on number of faulty/dishonest oracles participating
            // in the protocol, this value is referred to as f in the design
            uint8 threshold;
            // Chainlink Aggregators expose a roundId to consumers. The offchain reporting
            // protocol does not use this id anywhere. We increment it whenever a new
            // transmission is made to provide callers with contiguous ids for successive
            // reports.
            uint32 latestAggregatorRoundId;
          }
          HotVars internal s_hotVars;
          // Transmission records the median answer from the transmit transaction at
          // time timestamp
          struct Transmission {
            int192 answer; // 192 bits ought to be enough for anyone
            uint64 timestamp;
          }
          mapping(uint32 /* aggregator round ID */ => Transmission) internal s_transmissions;
          // incremented each time a new config is posted. This count is incorporated
          // into the config digest, to prevent replay attacks.
          uint32 internal s_configCount;
          uint32 internal s_latestConfigBlockNumber; // makes it easier for offchain systems
                                                     // to extract config from logs.
          // Lowest answer the system is allowed to report in response to transmissions
          int192 immutable public minAnswer;
          // Highest answer the system is allowed to report in response to transmissions
          int192 immutable public maxAnswer;
          /*
           * @param _maximumGasPrice highest gas price for which transmitter will be compensated
           * @param _reasonableGasPrice transmitter will receive reward for gas prices under this value
           * @param _microLinkPerEth reimbursement per ETH of gas cost, in 1e-6LINK units
           * @param _linkGweiPerObservation reward to oracle for contributing an observation to a successfully transmitted report, in 1e-9LINK units
           * @param _linkGweiPerTransmission reward to transmitter of a successful report, in 1e-9LINK units
           * @param _link address of the LINK contract
           * @param _minAnswer lowest answer the median of a report is allowed to be
           * @param _maxAnswer highest answer the median of a report is allowed to be
           * @param _billingAccessController access controller for billing admin functions
           * @param _requesterAccessController access controller for requesting new rounds
           * @param _decimals answers are stored in fixed-point format, with this many digits of precision
           * @param _description short human-readable description of observable this contract's answers pertain to
           */
          constructor(
            uint32 _maximumGasPrice,
            uint32 _reasonableGasPrice,
            uint32 _microLinkPerEth,
            uint32 _linkGweiPerObservation,
            uint32 _linkGweiPerTransmission,
            LinkTokenInterface _link,
            int192 _minAnswer,
            int192 _maxAnswer,
            AccessControllerInterface _billingAccessController,
            AccessControllerInterface _requesterAccessController,
            uint8 _decimals,
            string memory _description
          )
            OffchainAggregatorBilling(_maximumGasPrice, _reasonableGasPrice, _microLinkPerEth,
              _linkGweiPerObservation, _linkGweiPerTransmission, _link,
              _billingAccessController
            )
          {
            decimals = _decimals;
            s_description = _description;
            setRequesterAccessController(_requesterAccessController);
            setValidatorConfig(AggregatorValidatorInterface(0x0), 0);
            minAnswer = _minAnswer;
            maxAnswer = _maxAnswer;
          }
          /*
           * Versioning
           */
          function typeAndVersion()
            external
            override
            pure
            virtual
            returns (string memory)
          {
            return "OffchainAggregator 4.0.0";
          }
          /*
           * Config logic
           */
          /**
           * @notice triggers a new run of the offchain reporting protocol
           * @param previousConfigBlockNumber block in which the previous config was set, to simplify historic analysis
           * @param configCount ordinal number of this config setting among all config settings over the life of this contract
           * @param signers ith element is address ith oracle uses to sign a report
           * @param transmitters ith element is address ith oracle uses to transmit a report via the transmit method
           * @param threshold maximum number of faulty/dishonest oracles the protocol can tolerate while still working correctly
           * @param encodedConfigVersion version of the serialization format used for "encoded" parameter
           * @param encoded serialized data used by oracles to configure their offchain operation
           */
          event ConfigSet(
            uint32 previousConfigBlockNumber,
            uint64 configCount,
            address[] signers,
            address[] transmitters,
            uint8 threshold,
            uint64 encodedConfigVersion,
            bytes encoded
          );
          // Reverts transaction if config args are invalid
          modifier checkConfigValid (
            uint256 _numSigners, uint256 _numTransmitters, uint256 _threshold
          ) {
            require(_numSigners <= maxNumOracles, "too many signers");
            require(_threshold > 0, "threshold must be positive");
            require(
              _numSigners == _numTransmitters,
              "oracle addresses out of registration"
            );
            require(_numSigners > 3*_threshold, "faulty-oracle threshold too high");
            _;
          }
          /**
           * @notice sets offchain reporting protocol configuration incl. participating oracles
           * @param _signers addresses with which oracles sign the reports
           * @param _transmitters addresses oracles use to transmit the reports
           * @param _threshold number of faulty oracles the system can tolerate
           * @param _encodedConfigVersion version number for offchainEncoding schema
           * @param _encoded encoded off-chain oracle configuration
           */
          function setConfig(
            address[] calldata _signers,
            address[] calldata _transmitters,
            uint8 _threshold,
            uint64 _encodedConfigVersion,
            bytes calldata _encoded
          )
            external
            checkConfigValid(_signers.length, _transmitters.length, _threshold)
            onlyOwner()
          {
            while (s_signers.length != 0) { // remove any old signer/transmitter addresses
              uint lastIdx = s_signers.length - 1;
              address signer = s_signers[lastIdx];
              address transmitter = s_transmitters[lastIdx];
              payOracle(transmitter);
              delete s_oracles[signer];
              delete s_oracles[transmitter];
              s_signers.pop();
              s_transmitters.pop();
            }
            for (uint i = 0; i < _signers.length; i++) { // add new signer/transmitter addresses
              require(
                s_oracles[_signers[i]].role == Role.Unset,
                "repeated signer address"
              );
              s_oracles[_signers[i]] = Oracle(uint8(i), Role.Signer);
              require(s_payees[_transmitters[i]] != address(0), "payee must be set");
              require(
                s_oracles[_transmitters[i]].role == Role.Unset,
                "repeated transmitter address"
              );
              s_oracles[_transmitters[i]] = Oracle(uint8(i), Role.Transmitter);
              s_signers.push(_signers[i]);
              s_transmitters.push(_transmitters[i]);
            }
            s_hotVars.threshold = _threshold;
            uint32 previousConfigBlockNumber = s_latestConfigBlockNumber;
            s_latestConfigBlockNumber = uint32(block.number);
            s_configCount += 1;
            uint64 configCount = s_configCount;
            {
              s_hotVars.latestConfigDigest = configDigestFromConfigData(
                address(this),
                configCount,
                _signers,
                _transmitters,
                _threshold,
                _encodedConfigVersion,
                _encoded
              );
              s_hotVars.latestEpochAndRound = 0;
            }
            emit ConfigSet(
              previousConfigBlockNumber,
              configCount,
              _signers,
              _transmitters,
              _threshold,
              _encodedConfigVersion,
              _encoded
            );
          }
          function configDigestFromConfigData(
            address _contractAddress,
            uint64 _configCount,
            address[] calldata _signers,
            address[] calldata _transmitters,
            uint8 _threshold,
            uint64 _encodedConfigVersion,
            bytes calldata _encodedConfig
          ) internal pure returns (bytes16) {
            return bytes16(keccak256(abi.encode(_contractAddress, _configCount,
              _signers, _transmitters, _threshold, _encodedConfigVersion, _encodedConfig
            )));
          }
          /**
           * @notice information about current offchain reporting protocol configuration
           * @return configCount ordinal number of current config, out of all configs applied to this contract so far
           * @return blockNumber block at which this config was set
           * @return configDigest domain-separation tag for current config (see configDigestFromConfigData)
           */
          function latestConfigDetails()
            external
            view
            returns (
              uint32 configCount,
              uint32 blockNumber,
              bytes16 configDigest
            )
          {
            return (s_configCount, s_latestConfigBlockNumber, s_hotVars.latestConfigDigest);
          }
          /**
           * @return list of addresses permitted to transmit reports to this contract
           * @dev The list will match the order used to specify the transmitter during setConfig
           */
          function transmitters()
            external
            view
            returns(address[] memory)
          {
              return s_transmitters;
          }
          /*
           * On-chain validation logc
           */
          // Configuration for validator
          struct ValidatorConfig {
            AggregatorValidatorInterface validator;
            uint32 gasLimit;
          }
          ValidatorConfig private s_validatorConfig;
          /**
           * @notice indicates that the validator configuration has been set
           * @param previousValidator previous validator contract
           * @param previousGasLimit previous gas limit for validate calls
           * @param currentValidator current validator contract
           * @param currentGasLimit current gas limit for validate calls
           */
          event ValidatorConfigSet(
            AggregatorValidatorInterface indexed previousValidator,
            uint32 previousGasLimit,
            AggregatorValidatorInterface indexed currentValidator,
            uint32 currentGasLimit
          );
          /**
           * @notice validator configuration
           * @return validator validator contract
           * @return gasLimit gas limit for validate calls
           */
          function validatorConfig()
            external
            view
            returns (AggregatorValidatorInterface validator, uint32 gasLimit)
          {
            ValidatorConfig memory vc = s_validatorConfig;
            return (vc.validator, vc.gasLimit);
          }
          /**
           * @notice sets validator configuration
           * @dev set _newValidator to 0x0 to disable validate calls
           * @param _newValidator address of the new validator contract
           * @param _newGasLimit new gas limit for validate calls
           */
          function setValidatorConfig(AggregatorValidatorInterface _newValidator, uint32 _newGasLimit)
            public
            onlyOwner()
          {
            ValidatorConfig memory previous = s_validatorConfig;
            if (previous.validator != _newValidator || previous.gasLimit != _newGasLimit) {
              s_validatorConfig = ValidatorConfig({
                validator: _newValidator,
                gasLimit: _newGasLimit
              });
              emit ValidatorConfigSet(previous.validator, previous.gasLimit, _newValidator, _newGasLimit);
            }
          }
          function validateAnswer(
            uint32 _aggregatorRoundId,
            int256 _answer
          )
            private
          {
            ValidatorConfig memory vc = s_validatorConfig;
            if (address(vc.validator) == address(0)) {
              return;
            }
            uint32 prevAggregatorRoundId = _aggregatorRoundId - 1;
            int256 prevAggregatorRoundAnswer = s_transmissions[prevAggregatorRoundId].answer;
            require(
              callWithExactGasEvenIfTargetIsNoContract(
                vc.gasLimit,
                address(vc.validator),
                abi.encodeWithSignature(
                  "validate(uint256,int256,uint256,int256)",
                  uint256(prevAggregatorRoundId),
                  prevAggregatorRoundAnswer,
                  uint256(_aggregatorRoundId),
                  _answer
                )
              ),
              "insufficient gas"
            );
          }
          uint256 private constant CALL_WITH_EXACT_GAS_CUSHION = 5_000;
          /**
           * @dev calls target address with exactly gasAmount gas and data as calldata
           * or reverts if at least gasAmount gas is not available.
           */
          function callWithExactGasEvenIfTargetIsNoContract(
            uint256 _gasAmount,
            address _target,
            bytes memory _data
          )
            private
            returns (bool sufficientGas)
          {
            // solhint-disable-next-line no-inline-assembly
            assembly {
              let g := gas()
              // Compute g -= CALL_WITH_EXACT_GAS_CUSHION and check for underflow. We
              // need the cushion since the logic following the above call to gas also
              // costs gas which we cannot account for exactly. So cushion is a
              // conservative upper bound for the cost of this logic.
              if iszero(lt(g, CALL_WITH_EXACT_GAS_CUSHION)) {
                g := sub(g, CALL_WITH_EXACT_GAS_CUSHION)
                // If g - g//64 <= _gasAmount, we don't have enough gas. (We subtract g//64
                // because of EIP-150.)
                if gt(sub(g, div(g, 64)), _gasAmount) {
                  // Call and ignore success/return data. Note that we did not check
                  // whether a contract actually exists at the _target address.
                  pop(call(_gasAmount, _target, 0, add(_data, 0x20), mload(_data), 0, 0))
                  sufficientGas := true
                }
              }
            }
          }
          /*
           * requestNewRound logic
           */
          AccessControllerInterface internal s_requesterAccessController;
          /**
           * @notice emitted when a new requester access controller contract is set
           * @param old the address prior to the current setting
           * @param current the address of the new access controller contract
           */
          event RequesterAccessControllerSet(AccessControllerInterface old, AccessControllerInterface current);
          /**
           * @notice emitted to immediately request a new round
           * @param requester the address of the requester
           * @param configDigest the latest transmission's configDigest
           * @param epoch the latest transmission's epoch
           * @param round the latest transmission's round
           */
          event RoundRequested(address indexed requester, bytes16 configDigest, uint32 epoch, uint8 round);
          /**
           * @notice address of the requester access controller contract
           * @return requester access controller address
           */
          function requesterAccessController()
            external
            view
            returns (AccessControllerInterface)
          {
            return s_requesterAccessController;
          }
          /**
           * @notice sets the requester access controller
           * @param _requesterAccessController designates the address of the new requester access controller
           */
          function setRequesterAccessController(AccessControllerInterface _requesterAccessController)
            public
            onlyOwner()
          {
            AccessControllerInterface oldController = s_requesterAccessController;
            if (_requesterAccessController != oldController) {
              s_requesterAccessController = AccessControllerInterface(_requesterAccessController);
              emit RequesterAccessControllerSet(oldController, _requesterAccessController);
            }
          }
          /**
           * @notice immediately requests a new round
           * @return the aggregatorRoundId of the next round. Note: The report for this round may have been
           * transmitted (but not yet mined) *before* requestNewRound() was even called. There is *no*
           * guarantee of causality between the request and the report at aggregatorRoundId.
           */
          function requestNewRound() external returns (uint80) {
            require(msg.sender == owner || s_requesterAccessController.hasAccess(msg.sender, msg.data),
              "Only owner&requester can call");
            HotVars memory hotVars = s_hotVars;
            emit RoundRequested(
              msg.sender,
              hotVars.latestConfigDigest,
              uint32(s_hotVars.latestEpochAndRound >> 8),
              uint8(s_hotVars.latestEpochAndRound)
            );
            return hotVars.latestAggregatorRoundId + 1;
          }
          /*
           * Transmission logic
           */
          /**
           * @notice indicates that a new report was transmitted
           * @param aggregatorRoundId the round to which this report was assigned
           * @param answer median of the observations attached this report
           * @param transmitter address from which the report was transmitted
           * @param observations observations transmitted with this report
           * @param rawReportContext signature-replay-prevention domain-separation tag
           */
          event NewTransmission(
            uint32 indexed aggregatorRoundId,
            int192 answer,
            address transmitter,
            int192[] observations,
            bytes observers,
            bytes32 rawReportContext
          );
          // decodeReport is used to check that the solidity and go code are using the
          // same format. See TestOffchainAggregator.testDecodeReport and TestReportParsing
          function decodeReport(bytes memory _report)
            internal
            pure
            returns (
              bytes32 rawReportContext,
              bytes32 rawObservers,
              int192[] memory observations
            )
          {
            (rawReportContext, rawObservers, observations) = abi.decode(_report,
              (bytes32, bytes32, int192[]));
          }
          // Used to relieve stack pressure in transmit
          struct ReportData {
            HotVars hotVars; // Only read from storage once
            bytes observers; // ith element is the index of the ith observer
            int192[] observations; // ith element is the ith observation
            bytes vs; // jth element is the v component of the jth signature
            bytes32 rawReportContext;
          }
          /*
           * @notice details about the most recent report
           * @return configDigest domain separation tag for the latest report
           * @return epoch epoch in which the latest report was generated
           * @return round OCR round in which the latest report was generated
           * @return latestAnswer median value from latest report
           * @return latestTimestamp when the latest report was transmitted
           */
          function latestTransmissionDetails()
            external
            view
            returns (
              bytes16 configDigest,
              uint32 epoch,
              uint8 round,
              int192 latestAnswer,
              uint64 latestTimestamp
            )
          {
            require(msg.sender == tx.origin, "Only callable by EOA");
            return (
              s_hotVars.latestConfigDigest,
              uint32(s_hotVars.latestEpochAndRound >> 8),
              uint8(s_hotVars.latestEpochAndRound),
              s_transmissions[s_hotVars.latestAggregatorRoundId].answer,
              s_transmissions[s_hotVars.latestAggregatorRoundId].timestamp
            );
          }
          // The constant-length components of the msg.data sent to transmit.
          // See the "If we wanted to call sam" example on for example reasoning
          // https://solidity.readthedocs.io/en/v0.7.2/abi-spec.html
          uint16 private constant TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT =
            4 + // function selector
            32 + // word containing start location of abiencoded _report value
            32 + // word containing location start of abiencoded  _rs value
            32 + // word containing start location of abiencoded _ss value
            32 + // _rawVs value
            32 + // word containing length of _report
            32 + // word containing length _rs
            32 + // word containing length of _ss
            0; // placeholder
          function expectedMsgDataLength(
            bytes calldata _report, bytes32[] calldata _rs, bytes32[] calldata _ss
          ) private pure returns (uint256 length)
          {
            // calldata will never be big enough to make this overflow
            return uint256(TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT) +
              _report.length + // one byte pure entry in _report
              _rs.length * 32 + // 32 bytes per entry in _rs
              _ss.length * 32 + // 32 bytes per entry in _ss
              0; // placeholder
          }
          /**
           * @notice transmit is called to post a new report to the contract
           * @param _report serialized report, which the signatures are signing. See parsing code below for format. The ith element of the observers component must be the index in s_signers of the address for the ith signature
           * @param _rs ith element is the R components of the ith signature on report. Must have at most maxNumOracles entries
           * @param _ss ith element is the S components of the ith signature on report. Must have at most maxNumOracles entries
           * @param _rawVs ith element is the the V component of the ith signature
           */
          function transmit(
            // NOTE: If these parameters are changed, expectedMsgDataLength and/or
            // TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT need to be changed accordingly
            bytes calldata _report,
            bytes32[] calldata _rs, bytes32[] calldata _ss, bytes32 _rawVs // signatures
          )
            external
          {
            uint256 initialGas = gasleft(); // This line must come first
            // Make sure the transmit message-length matches the inputs. Otherwise, the
            // transmitter could append an arbitrarily long (up to gas-block limit)
            // string of 0 bytes, which we would reimburse at a rate of 16 gas/byte, but
            // which would only cost the transmitter 4 gas/byte. (Appendix G of the
            // yellow paper, p. 25, for G_txdatazero and EIP 2028 for G_txdatanonzero.)
            // This could amount to reimbursement profit of 36 million gas, given a 3MB
            // zero tail.
            require(msg.data.length == expectedMsgDataLength(_report, _rs, _ss),
              "transmit message too long");
            ReportData memory r; // Relieves stack pressure
            {
              r.hotVars = s_hotVars; // cache read from storage
              bytes32 rawObservers;
              (r.rawReportContext, rawObservers, r.observations) = abi.decode(
                _report, (bytes32, bytes32, int192[])
              );
              // rawReportContext consists of:
              // 11-byte zero padding
              // 16-byte configDigest
              // 4-byte epoch
              // 1-byte round
              bytes16 configDigest = bytes16(r.rawReportContext << 88);
              require(
                r.hotVars.latestConfigDigest == configDigest,
                "configDigest mismatch"
              );
              uint40 epochAndRound = uint40(uint256(r.rawReportContext));
              // direct numerical comparison works here, because
              //
              //   ((e,r) <= (e',r')) implies (epochAndRound <= epochAndRound')
              //
              // because alphabetic ordering implies e <= e', and if e = e', then r<=r',
              // so e*256+r <= e'*256+r', because r, r' < 256
              require(r.hotVars.latestEpochAndRound < epochAndRound, "stale report");
              require(_rs.length > r.hotVars.threshold, "not enough signatures");
              require(_rs.length <= maxNumOracles, "too many signatures");
              require(_ss.length == _rs.length, "signatures out of registration");
              require(r.observations.length <= maxNumOracles,
                      "num observations out of bounds");
              require(r.observations.length > 2 * r.hotVars.threshold,
                      "too few values to trust median");
              // Copy signature parities in bytes32 _rawVs to bytes r.v
              r.vs = new bytes(_rs.length);
              for (uint8 i = 0; i < _rs.length; i++) {
                r.vs[i] = _rawVs[i];
              }
              // Copy observer identities in bytes32 rawObservers to bytes r.observers
              r.observers = new bytes(r.observations.length);
              bool[maxNumOracles] memory seen;
              for (uint8 i = 0; i < r.observations.length; i++) {
                uint8 observerIdx = uint8(rawObservers[i]);
                require(!seen[observerIdx], "observer index repeated");
                seen[observerIdx] = true;
                r.observers[i] = rawObservers[i];
              }
              Oracle memory transmitter = s_oracles[msg.sender];
              require( // Check that sender is authorized to report
                transmitter.role == Role.Transmitter &&
                msg.sender == s_transmitters[transmitter.index],
                "unauthorized transmitter"
              );
              // record epochAndRound here, so that we don't have to carry the local
              // variable in transmit. The change is reverted if something fails later.
              r.hotVars.latestEpochAndRound = epochAndRound;
            }
            { // Verify signatures attached to report
              bytes32 h = keccak256(_report);
              bool[maxNumOracles] memory signed;
              Oracle memory o;
              for (uint i = 0; i < _rs.length; i++) {
                address signer = ecrecover(h, uint8(r.vs[i])+27, _rs[i], _ss[i]);
                o = s_oracles[signer];
                require(o.role == Role.Signer, "address not authorized to sign");
                require(!signed[o.index], "non-unique signature");
                signed[o.index] = true;
              }
            }
            { // Check the report contents, and record the result
              for (uint i = 0; i < r.observations.length - 1; i++) {
                bool inOrder = r.observations[i] <= r.observations[i+1];
                require(inOrder, "observations not sorted");
              }
              int192 median = r.observations[r.observations.length/2];
              require(minAnswer <= median && median <= maxAnswer, "median is out of min-max range");
              r.hotVars.latestAggregatorRoundId++;
              s_transmissions[r.hotVars.latestAggregatorRoundId] =
                Transmission(median, uint64(block.timestamp));
              emit NewTransmission(
                r.hotVars.latestAggregatorRoundId,
                median,
                msg.sender,
                r.observations,
                r.observers,
                r.rawReportContext
              );
              // Emit these for backwards compatability with offchain consumers
              // that only support legacy events
              emit NewRound(
                r.hotVars.latestAggregatorRoundId,
                address(0x0), // use zero address since we don't have anybody "starting" the round here
                block.timestamp
              );
              emit AnswerUpdated(
                median,
                r.hotVars.latestAggregatorRoundId,
                block.timestamp
              );
              validateAnswer(r.hotVars.latestAggregatorRoundId, median);
            }
            s_hotVars = r.hotVars;
            assert(initialGas < maxUint32);
            reimburseAndRewardOracles(uint32(initialGas), r.observers);
          }
          /*
           * v2 Aggregator interface
           */
          /**
           * @notice median from the most recent report
           */
          function latestAnswer()
            public
            override
            view
            virtual
            returns (int256)
          {
            return s_transmissions[s_hotVars.latestAggregatorRoundId].answer;
          }
          /**
           * @notice timestamp of block in which last report was transmitted
           */
          function latestTimestamp()
            public
            override
            view
            virtual
            returns (uint256)
          {
            return s_transmissions[s_hotVars.latestAggregatorRoundId].timestamp;
          }
          /**
           * @notice Aggregator round (NOT OCR round) in which last report was transmitted
           */
          function latestRound()
            public
            override
            view
            virtual
            returns (uint256)
          {
            return s_hotVars.latestAggregatorRoundId;
          }
          /**
           * @notice median of report from given aggregator round (NOT OCR round)
           * @param _roundId the aggregator round of the target report
           */
          function getAnswer(uint256 _roundId)
            public
            override
            view
            virtual
            returns (int256)
          {
            if (_roundId > 0xFFFFFFFF) { return 0; }
            return s_transmissions[uint32(_roundId)].answer;
          }
          /**
           * @notice timestamp of block in which report from given aggregator round was transmitted
           * @param _roundId aggregator round (NOT OCR round) of target report
           */
          function getTimestamp(uint256 _roundId)
            public
            override
            view
            virtual
            returns (uint256)
          {
            if (_roundId > 0xFFFFFFFF) { return 0; }
            return s_transmissions[uint32(_roundId)].timestamp;
          }
          /*
           * v3 Aggregator interface
           */
          string constant private V3_NO_DATA_ERROR = "No data present";
          /**
           * @return answers are stored in fixed-point format, with this many digits of precision
           */
          uint8 immutable public override decimals;
          /**
           * @notice aggregator contract version
           */
          uint256 constant public override version = 4;
          string internal s_description;
          /**
           * @notice human-readable description of observable this contract is reporting on
           */
          function description()
            public
            override
            view
            virtual
            returns (string memory)
          {
            return s_description;
          }
          /**
           * @notice details for the given aggregator round
           * @param _roundId target aggregator round (NOT OCR round). Must fit in uint32
           * @return roundId _roundId
           * @return answer median of report from given _roundId
           * @return startedAt timestamp of block in which report from given _roundId was transmitted
           * @return updatedAt timestamp of block in which report from given _roundId was transmitted
           * @return answeredInRound _roundId
           */
          function getRoundData(uint80 _roundId)
            public
            override
            view
            virtual
            returns (
              uint80 roundId,
              int256 answer,
              uint256 startedAt,
              uint256 updatedAt,
              uint80 answeredInRound
            )
          {
            require(_roundId <= 0xFFFFFFFF, V3_NO_DATA_ERROR);
            Transmission memory transmission = s_transmissions[uint32(_roundId)];
            return (
              _roundId,
              transmission.answer,
              transmission.timestamp,
              transmission.timestamp,
              _roundId
            );
          }
          /**
           * @notice aggregator details for the most recently transmitted report
           * @return roundId aggregator round of latest report (NOT OCR round)
           * @return answer median of latest report
           * @return startedAt timestamp of block containing latest report
           * @return updatedAt timestamp of block containing latest report
           * @return answeredInRound aggregator round of latest report
           */
          function latestRoundData()
            public
            override
            view
            virtual
            returns (
              uint80 roundId,
              int256 answer,
              uint256 startedAt,
              uint256 updatedAt,
              uint80 answeredInRound
            )
          {
            roundId = s_hotVars.latestAggregatorRoundId;
            // Skipped for compatability with existing FluxAggregator in which latestRoundData never reverts.
            // require(roundId != 0, V3_NO_DATA_ERROR);
            Transmission memory transmission = s_transmissions[uint32(roundId)];
            return (
              roundId,
              transmission.answer,
              transmission.timestamp,
              transmission.timestamp,
              roundId
            );
          }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity 0.7.6;
        import "./AccessControllerInterface.sol";
        import "./LinkTokenInterface.sol";
        import "./Owned.sol";
        /**
         * @notice tracks administration of oracle-reward and gas-reimbursement parameters.
         * @dev
         * If you read or change this, be sure to read or adjust the comments. They
         * track the units of the values under consideration, and are crucial to
         * the readability of the operations it specifies.
         * @notice
         * Trust Model:
         * Nothing in this contract prevents a billing admin from setting insane
         * values for the billing parameters in setBilling. Oracles
         * participating in this contract should regularly check that the
         * parameters make sense. Similarly, the outstanding obligations of this
         * contract to the oracles can exceed the funds held by the contract.
         * Oracles participating in this contract should regularly check that it
         * holds sufficient funds and stop interacting with it if funding runs
         * out.
         * This still leaves oracles with some risk due to TOCTOU issues.
         * However, since the sums involved are pretty small (Ethereum
         * transactions aren't that expensive in the end) and an oracle would
         * likely stop participating in a contract it repeatedly lost money on,
         * this risk is deemed acceptable. Oracles should also regularly
         * withdraw any funds in the contract to prevent issues where the
         * contract becomes underfunded at a later time, and different oracles
         * are competing for the left-over funds.
         * Finally, note that any change to the set of oracles or to the billing
         * parameters will trigger payout of all oracles first (using the old
         * parameters), a billing admin cannot take away funds that are already
         * marked for payment.
        */
        contract OffchainAggregatorBilling is Owned {
          // Maximum number of oracles the offchain reporting protocol is designed for
          uint256 constant internal maxNumOracles = 31;
          // Parameters for oracle payments
          struct Billing {
            // Highest compensated gas price, in ETH-gwei uints
            uint32 maximumGasPrice;
            // If gas price is less (in ETH-gwei units), transmitter gets half the savings
            uint32 reasonableGasPrice;
            // Pay transmitter back this much LINK per unit eth spent on gas
            // (1e-6LINK/ETH units)
            uint32 microLinkPerEth;
            // Fixed LINK reward for each observer, in LINK-gwei units
            uint32 linkGweiPerObservation;
            // Fixed reward for transmitter, in linkGweiPerObservation units
            uint32 linkGweiPerTransmission;
          }
          Billing internal s_billing;
          // We assume that the token contract is correct. This contract is not written
          // to handle misbehaving ERC20 tokens!
          LinkTokenInterface internal s_linkToken;
          AccessControllerInterface internal s_billingAccessController;
          // ith element is number of observation rewards due to ith process, plus one.
          // This is expected to saturate after an oracle has submitted 65,535
          // observations, or about 65535/(3*24*20) = 45 days, given a transmission
          // every 3 minutes.
          //
          // This is always one greater than the actual value, so that when the value is
          // reset to zero, we don't end up with a zero value in storage (which would
          // result in a higher gas cost, the next time the value is incremented.)
          // Calculations using this variable need to take that offset into account.
          uint16[maxNumOracles] internal s_oracleObservationsCounts;
          // Addresses at which oracles want to receive payments, by transmitter address
          mapping (address /* transmitter */ => address /* payment address */)
            internal
            s_payees;
          // Payee addresses which must be approved by the owner
          mapping (address /* transmitter */ => address /* payment address */)
            internal
            s_proposedPayees;
          // LINK-wei-denominated reimbursements for gas used by transmitters.
          //
          // This is always one greater than the actual value, so that when the value is
          // reset to zero, we don't end up with a zero value in storage (which would
          // result in a higher gas cost, the next time the value is incremented.)
          // Calculations using this variable need to take that offset into account.
          //
          // Argument for overflow safety:
          // We have the following maximum intermediate values:
          // - 2**40 additions to this variable (epochAndRound is a uint40)
          // - 2**32 gas price in ethgwei/gas
          // - 1e9 ethwei/ethgwei
          // - 2**32 gas since the block gas limit is at ~20 million
          // - 2**32 (microlink/eth)
          // And we have 2**40 * 2**32 * 1e9 * 2**32 * 2**32 < 2**166
          // (we also divide in some places, but that only makes the value smaller)
          // We can thus safely use uint256 intermediate values for the computation
          // updating this variable.
          uint256[maxNumOracles] internal s_gasReimbursementsLinkWei;
          // Used for s_oracles[a].role, where a is an address, to track the purpose
          // of the address, or to indicate that the address is unset.
          enum Role {
            // No oracle role has been set for address a
            Unset,
            // Signing address for the s_oracles[a].index'th oracle. I.e., report
            // signatures from this oracle should ecrecover back to address a.
            Signer,
            // Transmission address for the s_oracles[a].index'th oracle. I.e., if a
            // report is received by OffchainAggregator.transmit in which msg.sender is
            // a, it is attributed to the s_oracles[a].index'th oracle.
            Transmitter
          }
          struct Oracle {
            uint8 index; // Index of oracle in s_signers/s_transmitters
            Role role;   // Role of the address which mapped to this struct
          }
          mapping (address /* signer OR transmitter address */ => Oracle)
            internal s_oracles;
          // s_signers contains the signing address of each oracle
          address[] internal s_signers;
          // s_transmitters contains the transmission address of each oracle,
          // i.e. the address the oracle actually sends transactions to the contract from
          address[] internal s_transmitters;
          uint256 constant private  maxUint16 = (1 << 16) - 1;
          uint256 constant internal maxUint128 = (1 << 128) - 1;
          constructor(
            uint32 _maximumGasPrice,
            uint32 _reasonableGasPrice,
            uint32 _microLinkPerEth,
            uint32 _linkGweiPerObservation,
            uint32 _linkGweiPerTransmission,
            LinkTokenInterface _link,
            AccessControllerInterface _billingAccessController
          )
          {
            setBillingInternal(_maximumGasPrice, _reasonableGasPrice, _microLinkPerEth,
              _linkGweiPerObservation, _linkGweiPerTransmission);
            s_linkToken = _link;
            emit LinkTokenSet(LinkTokenInterface(address(0)), _link);
            setBillingAccessControllerInternal(_billingAccessController);
            uint16[maxNumOracles] memory counts; // See s_oracleObservationsCounts docstring
            uint256[maxNumOracles] memory gas; // see s_gasReimbursementsLinkWei docstring
            for (uint8 i = 0; i < maxNumOracles; i++) {
              counts[i] = 1;
              gas[i] = 1;
            }
            s_oracleObservationsCounts = counts;
            s_gasReimbursementsLinkWei = gas;
          }
          /*
           * @notice emitted when the LINK token contract is set
           * @param _oldLinkToken the address of the old LINK token contract
           * @param _newLinkToken the address of the new LINK token contract
           */
          event LinkTokenSet(
            LinkTokenInterface indexed _oldLinkToken,
            LinkTokenInterface indexed _newLinkToken
          );
          /*
           * @notice sets the LINK token contract used for paying oracles
           * @param _linkToken the address of the LINK token contract
           * @param _recipient remaining funds from the previous token contract are transfered
           * here
           * @dev this function will return early (without an error) without changing any state
           * if _linkToken equals getLinkToken().
           * @dev this will trigger a payout so that a malicious owner cannot take from oracles
           * what is already owed to them.
           * @dev we assume that the token contract is correct. This contract is not written
           * to handle misbehaving ERC20 tokens!
           */
          function setLinkToken(
            LinkTokenInterface _linkToken,
            address _recipient
          ) external
            onlyOwner()
          {
            LinkTokenInterface oldLinkToken = s_linkToken;
            if (_linkToken == oldLinkToken) {
              // No change, nothing to be done
              return;
            }
            // call balanceOf as a sanity check on whether we're talking to a token
            // contract
            _linkToken.balanceOf(address(this));
            // we break CEI here, but that's okay because we're dealing with a correct
            // token contract (by assumption).
            payOracles();
            uint256 remainingBalance = oldLinkToken.balanceOf(address(this));
            require(oldLinkToken.transfer(_recipient, remainingBalance), "transfer remaining funds failed");
            s_linkToken = _linkToken;
            emit LinkTokenSet(oldLinkToken, _linkToken);
          }
          /*
           * @notice gets the LINK token contract used for paying oracles
           * @return linkToken the address of the LINK token contract
           */
          function getLinkToken()
            external
            view
            returns(LinkTokenInterface linkToken)
          {
            return s_linkToken;
          }
          /**
           * @notice emitted when billing parameters are set
           * @param maximumGasPrice highest gas price for which transmitter will be compensated
           * @param reasonableGasPrice transmitter will receive reward for gas prices under this value
           * @param microLinkPerEth reimbursement per ETH of gas cost, in 1e-6LINK units
           * @param linkGweiPerObservation reward to oracle for contributing an observation to a successfully transmitted report, in 1e-9LINK units
           * @param linkGweiPerTransmission reward to transmitter of a successful report, in 1e-9LINK units
           */
          event BillingSet(
            uint32 maximumGasPrice,
            uint32 reasonableGasPrice,
            uint32 microLinkPerEth,
            uint32 linkGweiPerObservation,
            uint32 linkGweiPerTransmission
          );
          function setBillingInternal(
            uint32 _maximumGasPrice,
            uint32 _reasonableGasPrice,
            uint32 _microLinkPerEth,
            uint32 _linkGweiPerObservation,
            uint32 _linkGweiPerTransmission
          )
            internal
          {
            s_billing = Billing(_maximumGasPrice, _reasonableGasPrice, _microLinkPerEth,
              _linkGweiPerObservation, _linkGweiPerTransmission);
            emit BillingSet(_maximumGasPrice, _reasonableGasPrice, _microLinkPerEth,
              _linkGweiPerObservation, _linkGweiPerTransmission);
          }
          /**
           * @notice sets billing parameters
           * @param _maximumGasPrice highest gas price for which transmitter will be compensated
           * @param _reasonableGasPrice transmitter will receive reward for gas prices under this value
           * @param _microLinkPerEth reimbursement per ETH of gas cost, in 1e-6LINK units
           * @param _linkGweiPerObservation reward to oracle for contributing an observation to a successfully transmitted report, in 1e-9LINK units
           * @param _linkGweiPerTransmission reward to transmitter of a successful report, in 1e-9LINK units
           * @dev access control provided by billingAccessController
           */
          function setBilling(
            uint32 _maximumGasPrice,
            uint32 _reasonableGasPrice,
            uint32 _microLinkPerEth,
            uint32 _linkGweiPerObservation,
            uint32 _linkGweiPerTransmission
          )
            external
          {
            AccessControllerInterface access = s_billingAccessController;
            require(msg.sender == owner || access.hasAccess(msg.sender, msg.data),
              "Only owner&billingAdmin can call");
            payOracles();
            setBillingInternal(_maximumGasPrice, _reasonableGasPrice, _microLinkPerEth,
              _linkGweiPerObservation, _linkGweiPerTransmission);
          }
          /**
           * @notice gets billing parameters
           * @param maximumGasPrice highest gas price for which transmitter will be compensated
           * @param reasonableGasPrice transmitter will receive reward for gas prices under this value
           * @param microLinkPerEth reimbursement per ETH of gas cost, in 1e-6LINK units
           * @param linkGweiPerObservation reward to oracle for contributing an observation to a successfully transmitted report, in 1e-9LINK units
           * @param linkGweiPerTransmission reward to transmitter of a successful report, in 1e-9LINK units
           */
          function getBilling()
            external
            view
            returns (
              uint32 maximumGasPrice,
              uint32 reasonableGasPrice,
              uint32 microLinkPerEth,
              uint32 linkGweiPerObservation,
              uint32 linkGweiPerTransmission
            )
          {
            Billing memory billing = s_billing;
            return (
              billing.maximumGasPrice,
              billing.reasonableGasPrice,
              billing.microLinkPerEth,
              billing.linkGweiPerObservation,
              billing.linkGweiPerTransmission
            );
          }
          /**
           * @notice emitted when a new access-control contract is set
           * @param old the address prior to the current setting
           * @param current the address of the new access-control contract
           */
          event BillingAccessControllerSet(AccessControllerInterface old, AccessControllerInterface current);
          function setBillingAccessControllerInternal(AccessControllerInterface _billingAccessController)
            internal
          {
            AccessControllerInterface oldController = s_billingAccessController;
            if (_billingAccessController != oldController) {
              s_billingAccessController = _billingAccessController;
              emit BillingAccessControllerSet(
                oldController,
                _billingAccessController
              );
            }
          }
          /**
           * @notice sets billingAccessController
           * @param _billingAccessController new billingAccessController contract address
           * @dev only owner can call this
           */
          function setBillingAccessController(AccessControllerInterface _billingAccessController)
            external
            onlyOwner
          {
            setBillingAccessControllerInternal(_billingAccessController);
          }
          /**
           * @notice gets billingAccessController
           * @return address of billingAccessController contract
           */
          function billingAccessController()
            external
            view
            returns (AccessControllerInterface)
          {
            return s_billingAccessController;
          }
          /**
           * @notice withdraws an oracle's payment from the contract
           * @param _transmitter the transmitter address of the oracle
           * @dev must be called by oracle's payee address
           */
          function withdrawPayment(address _transmitter)
            external
          {
            require(msg.sender == s_payees[_transmitter], "Only payee can withdraw");
            payOracle(_transmitter);
          }
          /**
           * @notice query an oracle's payment amount
           * @param _transmitter the transmitter address of the oracle
           */
          function owedPayment(address _transmitter)
            public
            view
            returns (uint256)
          {
            Oracle memory oracle = s_oracles[_transmitter];
            if (oracle.role == Role.Unset) { return 0; }
            Billing memory billing = s_billing;
            uint256 linkWeiAmount =
              uint256(s_oracleObservationsCounts[oracle.index] - 1) *
              uint256(billing.linkGweiPerObservation) *
              (1 gwei);
            linkWeiAmount += s_gasReimbursementsLinkWei[oracle.index] - 1;
            return linkWeiAmount;
          }
          /**
           * @notice emitted when an oracle has been paid LINK
           * @param transmitter address from which the oracle sends reports to the transmit method
           * @param payee address to which the payment is sent
           * @param amount amount of LINK sent
           * @param linkToken address of the LINK token contract
           */
          event OraclePaid(
            address indexed transmitter,
            address indexed payee,
            uint256 amount,
            LinkTokenInterface indexed linkToken
          );
          // payOracle pays out _transmitter's balance to the corresponding payee, and zeros it out
          function payOracle(address _transmitter)
            internal
          {
            Oracle memory oracle = s_oracles[_transmitter];
            uint256 linkWeiAmount = owedPayment(_transmitter);
            if (linkWeiAmount > 0) {
              address payee = s_payees[_transmitter];
              // Poses no re-entrancy issues, because LINK.transfer does not yield
              // control flow.
              require(s_linkToken.transfer(payee, linkWeiAmount), "insufficient funds");
              s_oracleObservationsCounts[oracle.index] = 1; // "zero" the counts. see var's docstring
              s_gasReimbursementsLinkWei[oracle.index] = 1; // "zero" the counts. see var's docstring
              emit OraclePaid(_transmitter, payee, linkWeiAmount, s_linkToken);
            }
          }
          // payOracles pays out all transmitters, and zeros out their balances.
          //
          // It's much more gas-efficient to do this as a single operation, to avoid
          // hitting storage too much.
          function payOracles()
            internal
          {
            Billing memory billing = s_billing;
            LinkTokenInterface linkToken = s_linkToken;
            uint16[maxNumOracles] memory observationsCounts = s_oracleObservationsCounts;
            uint256[maxNumOracles] memory gasReimbursementsLinkWei =
              s_gasReimbursementsLinkWei;
            address[] memory transmitters = s_transmitters;
            for (uint transmitteridx = 0; transmitteridx < transmitters.length; transmitteridx++) {
              uint256 reimbursementAmountLinkWei = gasReimbursementsLinkWei[transmitteridx] - 1;
              uint256 obsCount = observationsCounts[transmitteridx] - 1;
              uint256 linkWeiAmount =
                obsCount * uint256(billing.linkGweiPerObservation) * (1 gwei) + reimbursementAmountLinkWei;
              if (linkWeiAmount > 0) {
                  address payee = s_payees[transmitters[transmitteridx]];
                  // Poses no re-entrancy issues, because LINK.transfer does not yield
                  // control flow.
                  require(linkToken.transfer(payee, linkWeiAmount), "insufficient funds");
                  observationsCounts[transmitteridx] = 1;       // "zero" the counts.
                  gasReimbursementsLinkWei[transmitteridx] = 1; // "zero" the counts.
                  emit OraclePaid(transmitters[transmitteridx], payee, linkWeiAmount, linkToken);
                }
            }
            // "Zero" the accounting storage variables
            s_oracleObservationsCounts = observationsCounts;
            s_gasReimbursementsLinkWei = gasReimbursementsLinkWei;
          }
          function oracleRewards(
            bytes memory observers,
            uint16[maxNumOracles] memory observations
          )
            internal
            pure
            returns (uint16[maxNumOracles] memory)
          {
            // reward each observer-participant with the observer reward
            for (uint obsIdx = 0; obsIdx < observers.length; obsIdx++) {
              uint8 observer = uint8(observers[obsIdx]);
              observations[observer] = saturatingAddUint16(observations[observer], 1);
            }
            return observations;
          }
          // This value needs to change if maxNumOracles is increased, or the accounting
          // calculations at the bottom of reimburseAndRewardOracles change.
          //
          // To recalculate it, run the profiler as described in
          // ../../profile/README.md, and add up the gas-usage values reported for the
          // lines in reimburseAndRewardOracles following the "gasLeft = gasleft()"
          // line. E.g., you will see output like this:
          //
          //      7        uint256 gasLeft = gasleft();
          //     29        uint256 gasCostEthWei = transmitterGasCostEthWei(
          //      9          uint256(initialGas),
          //      3          gasPrice,
          //      3          callDataGasCost,
          //      3          gasLeft
          //      .
          //      .
          //      .
          //     59        uint256 gasCostLinkWei = (gasCostEthWei * billing.microLinkPerEth)/ 1e6;
          //      .
          //      .
          //      .
          //   5047        s_gasReimbursementsLinkWei[txOracle.index] =
          //    856          s_gasReimbursementsLinkWei[txOracle.index] + gasCostLinkWei +
          //     26          uint256(billing.linkGweiPerTransmission) * (1 gwei);
          //
          // If those were the only lines to be accounted for, you would add up
          // 29+9+3+3+3+59+5047+856+26=6035.
          uint256 internal constant accountingGasCost = 6035;
          // Uncomment the following declaration to compute the remaining gas cost after
          // above gasleft(). (This must exist in a base class to OffchainAggregator, so
          // it can't go in TestOffchainAggregator.)
          //
          // uint256 public gasUsedInAccounting;
          // Gas price at which the transmitter should be reimbursed, in ETH-gwei/gas
          function impliedGasPrice(
            uint256 txGasPrice,         // ETH-gwei/gas units
            uint256 reasonableGasPrice, // ETH-gwei/gas units
            uint256 maximumGasPrice     // ETH-gwei/gas units
          )
            internal
            pure
            returns (uint256)
          {
            // Reward the transmitter for choosing an efficient gas price: if they manage
            // to come in lower than considered reasonable, give them half the savings.
            //
            // The following calculations are all in units of gwei/gas, i.e. 1e-9ETH/gas
            uint256 gasPrice = txGasPrice;
            if (txGasPrice < reasonableGasPrice) {
              // Give transmitter half the savings for coming in under the reasonable gas price
              gasPrice += (reasonableGasPrice - txGasPrice) / 2;
            }
            // Don't reimburse a gas price higher than maximumGasPrice
            return min(gasPrice, maximumGasPrice);
          }
          // gas reimbursement due the transmitter, in ETH-wei
          //
          // If this function is changed, accountingGasCost needs to change, too. See
          // its docstring
          function transmitterGasCostEthWei(
            uint256 initialGas,
            uint256 gasPrice, // ETH-gwei/gas units
            uint256 callDataCost, // gas units
            uint256 gasLeft
          )
            internal
            pure
            returns (uint128 gasCostEthWei)
          {
            require(initialGas >= gasLeft, "gasLeft cannot exceed initialGas");
            uint256 gasUsed = // gas units
              initialGas - gasLeft + // observed gas usage
              callDataCost + accountingGasCost; // estimated gas usage
            // gasUsed is in gas units, gasPrice is in ETH-gwei/gas units; convert to ETH-wei
            uint256 fullGasCostEthWei = gasUsed * gasPrice * (1 gwei);
            assert(fullGasCostEthWei < maxUint128); // the entire ETH supply fits in a uint128...
            return uint128(fullGasCostEthWei);
          }
          /**
           * @notice withdraw any available funds left in the contract, up to _amount, after accounting for the funds due to participants in past reports
           * @param _recipient address to send funds to
           * @param _amount maximum amount to withdraw, denominated in LINK-wei.
           * @dev access control provided by billingAccessController
           */
          function withdrawFunds(address _recipient, uint256 _amount)
            external
          {
            require(msg.sender == owner || s_billingAccessController.hasAccess(msg.sender, msg.data),
              "Only owner&billingAdmin can call");
            uint256 linkDue = totalLINKDue();
            uint256 linkBalance = s_linkToken.balanceOf(address(this));
            require(linkBalance >= linkDue, "insufficient balance");
            require(s_linkToken.transfer(_recipient, min(linkBalance - linkDue, _amount)), "insufficient funds");
          }
          // Total LINK due to participants in past reports.
          function totalLINKDue()
            internal
            view
            returns (uint256 linkDue)
          {
            // Argument for overflow safety: We do all computations in
            // uint256s. The inputs to linkDue are:
            // - the <= 31 observation rewards each of which has less than
            //   64 bits (32 bits for billing.linkGweiPerObservation, 32 bits
            //   for wei/gwei conversion). Hence 69 bits are sufficient for this part.
            // - the <= 31 gas reimbursements, each of which consists of at most 166
            //   bits (see s_gasReimbursementsLinkWei docstring). Hence 171 bits are
            //   sufficient for this part
            // In total, 172 bits are enough.
            uint16[maxNumOracles] memory observationCounts = s_oracleObservationsCounts;
            for (uint i = 0; i < maxNumOracles; i++) {
              linkDue += observationCounts[i] - 1; // Stored value is one greater than actual value
            }
            Billing memory billing = s_billing;
            // Convert linkGweiPerObservation to uint256, or this overflows!
            linkDue *= uint256(billing.linkGweiPerObservation) * (1 gwei);
            address[] memory transmitters = s_transmitters;
            uint256[maxNumOracles] memory gasReimbursementsLinkWei =
              s_gasReimbursementsLinkWei;
            for (uint i = 0; i < transmitters.length; i++) {
              linkDue += uint256(gasReimbursementsLinkWei[i]-1); // Stored value is one greater than actual value
            }
          }
          /**
           * @notice allows oracles to check that sufficient LINK balance is available
           * @return availableBalance LINK available on this contract, after accounting for outstanding obligations. can become negative
           */
          function linkAvailableForPayment()
            external
            view
            returns (int256 availableBalance)
          {
            // there are at most one billion LINK, so this cast is safe
            int256 balance = int256(s_linkToken.balanceOf(address(this)));
            // according to the argument in the definition of totalLINKDue,
            // totalLINKDue is never greater than 2**172, so this cast is safe
            int256 due = int256(totalLINKDue());
            // safe from overflow according to above sizes
            return int256(balance) - int256(due);
          }
          /**
           * @notice number of observations oracle is due to be reimbursed for
           * @param _signerOrTransmitter address used by oracle for signing or transmitting reports
           */
          function oracleObservationCount(address _signerOrTransmitter)
            external
            view
            returns (uint16)
          {
            Oracle memory oracle = s_oracles[_signerOrTransmitter];
            if (oracle.role == Role.Unset) { return 0; }
            return s_oracleObservationsCounts[oracle.index] - 1;
          }
          function reimburseAndRewardOracles(
            uint32 initialGas,
            bytes memory observers
          )
            internal
          {
            Oracle memory txOracle = s_oracles[msg.sender];
            Billing memory billing = s_billing;
            // Reward oracles for providing observations. Oracles are not rewarded
            // for providing signatures, because signing is essentially free.
            s_oracleObservationsCounts =
              oracleRewards(observers, s_oracleObservationsCounts);
            // Reimburse transmitter of the report for gas usage
            require(txOracle.role == Role.Transmitter,
              "sent by undesignated transmitter"
            );
            uint256 gasPrice = impliedGasPrice(
              tx.gasprice / (1 gwei), // convert to ETH-gwei units
              billing.reasonableGasPrice,
              billing.maximumGasPrice
            );
            // The following is only an upper bound, as it ignores the cheaper cost for
            // 0 bytes. Safe from overflow, because calldata just isn't that long.
            uint256 callDataGasCost = 16 * msg.data.length;
            // If any changes are made to subsequent calculations, accountingGasCost
            // needs to change, too.
            uint256 gasLeft = gasleft();
            uint256 gasCostEthWei = transmitterGasCostEthWei(
              uint256(initialGas),
              gasPrice,
              callDataGasCost,
              gasLeft
            );
            // microLinkPerEth is 1e-6LINK/ETH units, gasCostEthWei is 1e-18ETH units
            // (ETH-wei), product is 1e-24LINK-wei units, dividing by 1e6 gives
            // 1e-18LINK units, i.e. LINK-wei units
            // Safe from over/underflow, since all components are non-negative,
            // gasCostEthWei will always fit into uint128 and microLinkPerEth is a
            // uint32 (128+32 < 256!).
            uint256 gasCostLinkWei = (gasCostEthWei * billing.microLinkPerEth)/ 1e6;
            // Safe from overflow, because gasCostLinkWei < 2**160 and
            // billing.linkGweiPerTransmission * (1 gwei) < 2**64 and we increment
            // s_gasReimbursementsLinkWei[txOracle.index] at most 2**40 times.
            s_gasReimbursementsLinkWei[txOracle.index] =
              s_gasReimbursementsLinkWei[txOracle.index] + gasCostLinkWei +
              uint256(billing.linkGweiPerTransmission) * (1 gwei); // convert from linkGwei to linkWei
            // Uncomment next line to compute the remaining gas cost after above gasleft().
            // See OffchainAggregatorBilling.accountingGasCost docstring for more information.
            //
            // gasUsedInAccounting = gasLeft - gasleft();
          }
          /*
           * Payee management
           */
          /**
           * @notice emitted when a transfer of an oracle's payee address has been initiated
           * @param transmitter address from which the oracle sends reports to the transmit method
           * @param current the payeee address for the oracle, prior to this setting
           * @param proposed the proposed new payee address for the oracle
           */
          event PayeeshipTransferRequested(
            address indexed transmitter,
            address indexed current,
            address indexed proposed
          );
          /**
           * @notice emitted when a transfer of an oracle's payee address has been completed
           * @param transmitter address from which the oracle sends reports to the transmit method
           * @param current the payeee address for the oracle, prior to this setting
           */
          event PayeeshipTransferred(
            address indexed transmitter,
            address indexed previous,
            address indexed current
          );
          /**
           * @notice sets the payees for transmitting addresses
           * @param _transmitters addresses oracles use to transmit the reports
           * @param _payees addresses of payees corresponding to list of transmitters
           * @dev must be called by owner
           * @dev cannot be used to change payee addresses, only to initially populate them
           */
          function setPayees(
            address[] calldata _transmitters,
            address[] calldata _payees
          )
            external
            onlyOwner()
          {
            require(_transmitters.length == _payees.length, "transmitters.size != payees.size");
            for (uint i = 0; i < _transmitters.length; i++) {
              address transmitter = _transmitters[i];
              address payee = _payees[i];
              address currentPayee = s_payees[transmitter];
              bool zeroedOut = currentPayee == address(0);
              require(zeroedOut || currentPayee == payee, "payee already set");
              s_payees[transmitter] = payee;
              if (currentPayee != payee) {
                emit PayeeshipTransferred(transmitter, currentPayee, payee);
              }
            }
          }
          /**
           * @notice first step of payeeship transfer (safe transfer pattern)
           * @param _transmitter transmitter address of oracle whose payee is changing
           * @param _proposed new payee address
           * @dev can only be called by payee address
           */
          function transferPayeeship(
            address _transmitter,
            address _proposed
          )
            external
          {
              require(msg.sender == s_payees[_transmitter], "only current payee can update");
              require(msg.sender != _proposed, "cannot transfer to self");
              address previousProposed = s_proposedPayees[_transmitter];
              s_proposedPayees[_transmitter] = _proposed;
              if (previousProposed != _proposed) {
                emit PayeeshipTransferRequested(_transmitter, msg.sender, _proposed);
              }
          }
          /**
           * @notice second step of payeeship transfer (safe transfer pattern)
           * @param _transmitter transmitter address of oracle whose payee is changing
           * @dev can only be called by proposed new payee address
           */
          function acceptPayeeship(
            address _transmitter
          )
            external
          {
            require(msg.sender == s_proposedPayees[_transmitter], "only proposed payees can accept");
            address currentPayee = s_payees[_transmitter];
            s_payees[_transmitter] = msg.sender;
            s_proposedPayees[_transmitter] = address(0);
            emit PayeeshipTransferred(_transmitter, currentPayee, msg.sender);
          }
          /*
           * Helper functions
           */
          function saturatingAddUint16(uint16 _x, uint16 _y)
            internal
            pure
            returns (uint16)
          {
            return uint16(min(uint256(_x)+uint256(_y), maxUint16));
          }
          function min(uint256 a, uint256 b)
            internal
            pure
            returns (uint256)
          {
            if (a < b) { return a; }
            return b;
          }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity 0.7.6;
        /**
         * @title The Owned contract
         * @notice A contract with helpers for basic contract ownership.
         */
        contract Owned {
          address payable public owner;
          address private pendingOwner;
          event OwnershipTransferRequested(
            address indexed from,
            address indexed to
          );
          event OwnershipTransferred(
            address indexed from,
            address indexed to
          );
          constructor() {
            owner = msg.sender;
          }
          /**
           * @dev Allows an owner to begin transferring ownership to a new address,
           * pending.
           */
          function transferOwnership(address _to)
            external
            onlyOwner()
          {
            pendingOwner = _to;
            emit OwnershipTransferRequested(owner, _to);
          }
          /**
           * @dev Allows an ownership transfer to be completed by the recipient.
           */
          function acceptOwnership()
            external
          {
            require(msg.sender == pendingOwner, "Must be proposed owner");
            address oldOwner = owner;
            owner = msg.sender;
            pendingOwner = address(0);
            emit OwnershipTransferred(oldOwner, msg.sender);
          }
          /**
           * @dev Reverts if called by anyone other than the contract owner.
           */
          modifier onlyOwner() {
            require(msg.sender == owner, "Only callable by owner");
            _;
          }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity 0.7.6;
        import "./SimpleWriteAccessController.sol";
        /**
         * @title SimpleReadAccessController
         * @notice Gives access to:
         * - any externally owned account (note that offchain actors can always read
         * any contract storage regardless of onchain access control measures, so this
         * does not weaken the access control while improving usability)
         * - accounts explicitly added to an access list
         * @dev SimpleReadAccessController is not suitable for access controlling writes
         * since it grants any externally owned account access! See
         * SimpleWriteAccessController for that.
         */
        contract SimpleReadAccessController is SimpleWriteAccessController {
          /**
           * @notice Returns the access of an address
           * @param _user The address to query
           */
          function hasAccess(
            address _user,
            bytes memory _calldata
          )
            public
            view
            virtual
            override
            returns (bool)
          {
            return super.hasAccess(_user, _calldata) || _user == tx.origin;
          }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity 0.7.6;
        import "./Owned.sol";
        import "./AccessControllerInterface.sol";
        /**
         * @title SimpleWriteAccessController
         * @notice Gives access to accounts explicitly added to an access list by the
         * controller's owner.
         * @dev does not make any special permissions for externally, see
         * SimpleReadAccessController for that.
         */
        contract SimpleWriteAccessController is AccessControllerInterface, Owned {
          bool public checkEnabled;
          mapping(address => bool) internal accessList;
          event AddedAccess(address user);
          event RemovedAccess(address user);
          event CheckAccessEnabled();
          event CheckAccessDisabled();
          constructor()
          {
            checkEnabled = true;
          }
          /**
           * @notice Returns the access of an address
           * @param _user The address to query
           */
          function hasAccess(
            address _user,
            bytes memory
          )
            public
            view
            virtual
            override
            returns (bool)
          {
            return accessList[_user] || !checkEnabled;
          }
          /**
           * @notice Adds an address to the access list
           * @param _user The address to add
           */
          function addAccess(address _user) external onlyOwner() {
            addAccessInternal(_user);
          }
          function addAccessInternal(address _user) internal {
            if (!accessList[_user]) {
              accessList[_user] = true;
              emit AddedAccess(_user);
            }
          }
          /**
           * @notice Removes an address from the access list
           * @param _user The address to remove
           */
          function removeAccess(address _user)
            external
            onlyOwner()
          {
            if (accessList[_user]) {
              accessList[_user] = false;
              emit RemovedAccess(_user);
            }
          }
          /**
           * @notice makes the access check enforced
           */
          function enableAccessCheck()
            external
            onlyOwner()
          {
            if (!checkEnabled) {
              checkEnabled = true;
              emit CheckAccessEnabled();
            }
          }
          /**
           * @notice makes the access check unenforced
           */
          function disableAccessCheck()
            external
            onlyOwner()
          {
            if (checkEnabled) {
              checkEnabled = false;
              emit CheckAccessDisabled();
            }
          }
          /**
           * @dev reverts if the caller does not have access
           */
          modifier checkAccess() {
            require(hasAccess(msg.sender, msg.data), "No access");
            _;
          }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.7.0;
        abstract contract TypeAndVersionInterface{
          function typeAndVersion()
            external
            pure
            virtual
            returns (string memory);
        }

        File 5 of 5: GnosisSafe
        // SPDX-License-Identifier: LGPL-3.0-only
        pragma solidity >=0.7.0 <0.9.0;
        import "./base/ModuleManager.sol";
        import "./base/OwnerManager.sol";
        import "./base/FallbackManager.sol";
        import "./base/GuardManager.sol";
        import "./common/EtherPaymentFallback.sol";
        import "./common/Singleton.sol";
        import "./common/SignatureDecoder.sol";
        import "./common/SecuredTokenTransfer.sol";
        import "./common/StorageAccessible.sol";
        import "./interfaces/ISignatureValidator.sol";
        import "./external/GnosisSafeMath.sol";
        /// @title Gnosis Safe - A multisignature wallet with support for confirmations using signed messages based on ERC191.
        /// @author Stefan George - <[email protected]>
        /// @author Richard Meissner - <[email protected]>
        contract GnosisSafe is
            EtherPaymentFallback,
            Singleton,
            ModuleManager,
            OwnerManager,
            SignatureDecoder,
            SecuredTokenTransfer,
            ISignatureValidatorConstants,
            FallbackManager,
            StorageAccessible,
            GuardManager
        {
            using GnosisSafeMath for uint256;
            string public constant VERSION = "1.3.0";
            // keccak256(
            //     "EIP712Domain(uint256 chainId,address verifyingContract)"
            // );
            bytes32 private constant DOMAIN_SEPARATOR_TYPEHASH = 0x47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a79469218;
            // keccak256(
            //     "SafeTx(address to,uint256 value,bytes data,uint8 operation,uint256 safeTxGas,uint256 baseGas,uint256 gasPrice,address gasToken,address refundReceiver,uint256 nonce)"
            // );
            bytes32 private constant SAFE_TX_TYPEHASH = 0xbb8310d486368db6bd6f849402fdd73ad53d316b5a4b2644ad6efe0f941286d8;
            event SafeSetup(address indexed initiator, address[] owners, uint256 threshold, address initializer, address fallbackHandler);
            event ApproveHash(bytes32 indexed approvedHash, address indexed owner);
            event SignMsg(bytes32 indexed msgHash);
            event ExecutionFailure(bytes32 txHash, uint256 payment);
            event ExecutionSuccess(bytes32 txHash, uint256 payment);
            uint256 public nonce;
            bytes32 private _deprecatedDomainSeparator;
            // Mapping to keep track of all message hashes that have been approve by ALL REQUIRED owners
            mapping(bytes32 => uint256) public signedMessages;
            // Mapping to keep track of all hashes (message or transaction) that have been approve by ANY owners
            mapping(address => mapping(bytes32 => uint256)) public approvedHashes;
            // This constructor ensures that this contract can only be used as a master copy for Proxy contracts
            constructor() {
                // By setting the threshold it is not possible to call setup anymore,
                // so we create a Safe with 0 owners and threshold 1.
                // This is an unusable Safe, perfect for the singleton
                threshold = 1;
            }
            /// @dev Setup function sets initial storage of contract.
            /// @param _owners List of Safe owners.
            /// @param _threshold Number of required confirmations for a Safe transaction.
            /// @param to Contract address for optional delegate call.
            /// @param data Data payload for optional delegate call.
            /// @param fallbackHandler Handler for fallback calls to this contract
            /// @param paymentToken Token that should be used for the payment (0 is ETH)
            /// @param payment Value that should be paid
            /// @param paymentReceiver Adddress that should receive the payment (or 0 if tx.origin)
            function setup(
                address[] calldata _owners,
                uint256 _threshold,
                address to,
                bytes calldata data,
                address fallbackHandler,
                address paymentToken,
                uint256 payment,
                address payable paymentReceiver
            ) external {
                // setupOwners checks if the Threshold is already set, therefore preventing that this method is called twice
                setupOwners(_owners, _threshold);
                if (fallbackHandler != address(0)) internalSetFallbackHandler(fallbackHandler);
                // As setupOwners can only be called if the contract has not been initialized we don't need a check for setupModules
                setupModules(to, data);
                if (payment > 0) {
                    // To avoid running into issues with EIP-170 we reuse the handlePayment function (to avoid adjusting code of that has been verified we do not adjust the method itself)
                    // baseGas = 0, gasPrice = 1 and gas = payment => amount = (payment + 0) * 1 = payment
                    handlePayment(payment, 0, 1, paymentToken, paymentReceiver);
                }
                emit SafeSetup(msg.sender, _owners, _threshold, to, fallbackHandler);
            }
            /// @dev Allows to execute a Safe transaction confirmed by required number of owners and then pays the account that submitted the transaction.
            ///      Note: The fees are always transferred, even if the user transaction fails.
            /// @param to Destination address of Safe transaction.
            /// @param value Ether value of Safe transaction.
            /// @param data Data payload of Safe transaction.
            /// @param operation Operation type of Safe transaction.
            /// @param safeTxGas Gas that should be used for the Safe transaction.
            /// @param baseGas Gas costs that are independent of the transaction execution(e.g. base transaction fee, signature check, payment of the refund)
            /// @param gasPrice Gas price that should be used for the payment calculation.
            /// @param gasToken Token address (or 0 if ETH) that is used for the payment.
            /// @param refundReceiver Address of receiver of gas payment (or 0 if tx.origin).
            /// @param signatures Packed signature data ({bytes32 r}{bytes32 s}{uint8 v})
            function execTransaction(
                address to,
                uint256 value,
                bytes calldata data,
                Enum.Operation operation,
                uint256 safeTxGas,
                uint256 baseGas,
                uint256 gasPrice,
                address gasToken,
                address payable refundReceiver,
                bytes memory signatures
            ) public payable virtual returns (bool success) {
                bytes32 txHash;
                // Use scope here to limit variable lifetime and prevent `stack too deep` errors
                {
                    bytes memory txHashData =
                        encodeTransactionData(
                            // Transaction info
                            to,
                            value,
                            data,
                            operation,
                            safeTxGas,
                            // Payment info
                            baseGas,
                            gasPrice,
                            gasToken,
                            refundReceiver,
                            // Signature info
                            nonce
                        );
                    // Increase nonce and execute transaction.
                    nonce++;
                    txHash = keccak256(txHashData);
                    checkSignatures(txHash, txHashData, signatures);
                }
                address guard = getGuard();
                {
                    if (guard != address(0)) {
                        Guard(guard).checkTransaction(
                            // Transaction info
                            to,
                            value,
                            data,
                            operation,
                            safeTxGas,
                            // Payment info
                            baseGas,
                            gasPrice,
                            gasToken,
                            refundReceiver,
                            // Signature info
                            signatures,
                            msg.sender
                        );
                    }
                }
                // We require some gas to emit the events (at least 2500) after the execution and some to perform code until the execution (500)
                // We also include the 1/64 in the check that is not send along with a call to counteract potential shortings because of EIP-150
                require(gasleft() >= ((safeTxGas * 64) / 63).max(safeTxGas + 2500) + 500, "GS010");
                // Use scope here to limit variable lifetime and prevent `stack too deep` errors
                {
                    uint256 gasUsed = gasleft();
                    // If the gasPrice is 0 we assume that nearly all available gas can be used (it is always more than safeTxGas)
                    // We only substract 2500 (compared to the 3000 before) to ensure that the amount passed is still higher than safeTxGas
                    success = execute(to, value, data, operation, gasPrice == 0 ? (gasleft() - 2500) : safeTxGas);
                    gasUsed = gasUsed.sub(gasleft());
                    // If no safeTxGas and no gasPrice was set (e.g. both are 0), then the internal tx is required to be successful
                    // This makes it possible to use `estimateGas` without issues, as it searches for the minimum gas where the tx doesn't revert
                    require(success || safeTxGas != 0 || gasPrice != 0, "GS013");
                    // We transfer the calculated tx costs to the tx.origin to avoid sending it to intermediate contracts that have made calls
                    uint256 payment = 0;
                    if (gasPrice > 0) {
                        payment = handlePayment(gasUsed, baseGas, gasPrice, gasToken, refundReceiver);
                    }
                    if (success) emit ExecutionSuccess(txHash, payment);
                    else emit ExecutionFailure(txHash, payment);
                }
                {
                    if (guard != address(0)) {
                        Guard(guard).checkAfterExecution(txHash, success);
                    }
                }
            }
            function handlePayment(
                uint256 gasUsed,
                uint256 baseGas,
                uint256 gasPrice,
                address gasToken,
                address payable refundReceiver
            ) private returns (uint256 payment) {
                // solhint-disable-next-line avoid-tx-origin
                address payable receiver = refundReceiver == address(0) ? payable(tx.origin) : refundReceiver;
                if (gasToken == address(0)) {
                    // For ETH we will only adjust the gas price to not be higher than the actual used gas price
                    payment = gasUsed.add(baseGas).mul(gasPrice < tx.gasprice ? gasPrice : tx.gasprice);
                    require(receiver.send(payment), "GS011");
                } else {
                    payment = gasUsed.add(baseGas).mul(gasPrice);
                    require(transferToken(gasToken, receiver, payment), "GS012");
                }
            }
            /**
             * @dev Checks whether the signature provided is valid for the provided data, hash. Will revert otherwise.
             * @param dataHash Hash of the data (could be either a message hash or transaction hash)
             * @param data That should be signed (this is passed to an external validator contract)
             * @param signatures Signature data that should be verified. Can be ECDSA signature, contract signature (EIP-1271) or approved hash.
             */
            function checkSignatures(
                bytes32 dataHash,
                bytes memory data,
                bytes memory signatures
            ) public view {
                // Load threshold to avoid multiple storage loads
                uint256 _threshold = threshold;
                // Check that a threshold is set
                require(_threshold > 0, "GS001");
                checkNSignatures(dataHash, data, signatures, _threshold);
            }
            /**
             * @dev Checks whether the signature provided is valid for the provided data, hash. Will revert otherwise.
             * @param dataHash Hash of the data (could be either a message hash or transaction hash)
             * @param data That should be signed (this is passed to an external validator contract)
             * @param signatures Signature data that should be verified. Can be ECDSA signature, contract signature (EIP-1271) or approved hash.
             * @param requiredSignatures Amount of required valid signatures.
             */
            function checkNSignatures(
                bytes32 dataHash,
                bytes memory data,
                bytes memory signatures,
                uint256 requiredSignatures
            ) public view {
                // Check that the provided signature data is not too short
                require(signatures.length >= requiredSignatures.mul(65), "GS020");
                // There cannot be an owner with address 0.
                address lastOwner = address(0);
                address currentOwner;
                uint8 v;
                bytes32 r;
                bytes32 s;
                uint256 i;
                for (i = 0; i < requiredSignatures; i++) {
                    (v, r, s) = signatureSplit(signatures, i);
                    if (v == 0) {
                        // If v is 0 then it is a contract signature
                        // When handling contract signatures the address of the contract is encoded into r
                        currentOwner = address(uint160(uint256(r)));
                        // Check that signature data pointer (s) is not pointing inside the static part of the signatures bytes
                        // This check is not completely accurate, since it is possible that more signatures than the threshold are send.
                        // Here we only check that the pointer is not pointing inside the part that is being processed
                        require(uint256(s) >= requiredSignatures.mul(65), "GS021");
                        // Check that signature data pointer (s) is in bounds (points to the length of data -> 32 bytes)
                        require(uint256(s).add(32) <= signatures.length, "GS022");
                        // Check if the contract signature is in bounds: start of data is s + 32 and end is start + signature length
                        uint256 contractSignatureLen;
                        // solhint-disable-next-line no-inline-assembly
                        assembly {
                            contractSignatureLen := mload(add(add(signatures, s), 0x20))
                        }
                        require(uint256(s).add(32).add(contractSignatureLen) <= signatures.length, "GS023");
                        // Check signature
                        bytes memory contractSignature;
                        // solhint-disable-next-line no-inline-assembly
                        assembly {
                            // The signature data for contract signatures is appended to the concatenated signatures and the offset is stored in s
                            contractSignature := add(add(signatures, s), 0x20)
                        }
                        require(ISignatureValidator(currentOwner).isValidSignature(data, contractSignature) == EIP1271_MAGIC_VALUE, "GS024");
                    } else if (v == 1) {
                        // If v is 1 then it is an approved hash
                        // When handling approved hashes the address of the approver is encoded into r
                        currentOwner = address(uint160(uint256(r)));
                        // Hashes are automatically approved by the sender of the message or when they have been pre-approved via a separate transaction
                        require(msg.sender == currentOwner || approvedHashes[currentOwner][dataHash] != 0, "GS025");
                    } else if (v > 30) {
                        // If v > 30 then default va (27,28) has been adjusted for eth_sign flow
                        // To support eth_sign and similar we adjust v and hash the messageHash with the Ethereum message prefix before applying ecrecover
                        currentOwner = ecrecover(keccak256(abi.encodePacked("\\x19Ethereum Signed Message:\
        32", dataHash)), v - 4, r, s);
                    } else {
                        // Default is the ecrecover flow with the provided data hash
                        // Use ecrecover with the messageHash for EOA signatures
                        currentOwner = ecrecover(dataHash, v, r, s);
                    }
                    require(currentOwner > lastOwner && owners[currentOwner] != address(0) && currentOwner != SENTINEL_OWNERS, "GS026");
                    lastOwner = currentOwner;
                }
            }
            /// @dev Allows to estimate a Safe transaction.
            ///      This method is only meant for estimation purpose, therefore the call will always revert and encode the result in the revert data.
            ///      Since the `estimateGas` function includes refunds, call this method to get an estimated of the costs that are deducted from the safe with `execTransaction`
            /// @param to Destination address of Safe transaction.
            /// @param value Ether value of Safe transaction.
            /// @param data Data payload of Safe transaction.
            /// @param operation Operation type of Safe transaction.
            /// @return Estimate without refunds and overhead fees (base transaction and payload data gas costs).
            /// @notice Deprecated in favor of common/StorageAccessible.sol and will be removed in next version.
            function requiredTxGas(
                address to,
                uint256 value,
                bytes calldata data,
                Enum.Operation operation
            ) external returns (uint256) {
                uint256 startGas = gasleft();
                // We don't provide an error message here, as we use it to return the estimate
                require(execute(to, value, data, operation, gasleft()));
                uint256 requiredGas = startGas - gasleft();
                // Convert response to string and return via error message
                revert(string(abi.encodePacked(requiredGas)));
            }
            /**
             * @dev Marks a hash as approved. This can be used to validate a hash that is used by a signature.
             * @param hashToApprove The hash that should be marked as approved for signatures that are verified by this contract.
             */
            function approveHash(bytes32 hashToApprove) external {
                require(owners[msg.sender] != address(0), "GS030");
                approvedHashes[msg.sender][hashToApprove] = 1;
                emit ApproveHash(hashToApprove, msg.sender);
            }
            /// @dev Returns the chain id used by this contract.
            function getChainId() public view returns (uint256) {
                uint256 id;
                // solhint-disable-next-line no-inline-assembly
                assembly {
                    id := chainid()
                }
                return id;
            }
            function domainSeparator() public view returns (bytes32) {
                return keccak256(abi.encode(DOMAIN_SEPARATOR_TYPEHASH, getChainId(), this));
            }
            /// @dev Returns the bytes that are hashed to be signed by owners.
            /// @param to Destination address.
            /// @param value Ether value.
            /// @param data Data payload.
            /// @param operation Operation type.
            /// @param safeTxGas Gas that should be used for the safe transaction.
            /// @param baseGas Gas costs for that are independent of the transaction execution(e.g. base transaction fee, signature check, payment of the refund)
            /// @param gasPrice Maximum gas price that should be used for this transaction.
            /// @param gasToken Token address (or 0 if ETH) that is used for the payment.
            /// @param refundReceiver Address of receiver of gas payment (or 0 if tx.origin).
            /// @param _nonce Transaction nonce.
            /// @return Transaction hash bytes.
            function encodeTransactionData(
                address to,
                uint256 value,
                bytes calldata data,
                Enum.Operation operation,
                uint256 safeTxGas,
                uint256 baseGas,
                uint256 gasPrice,
                address gasToken,
                address refundReceiver,
                uint256 _nonce
            ) public view returns (bytes memory) {
                bytes32 safeTxHash =
                    keccak256(
                        abi.encode(
                            SAFE_TX_TYPEHASH,
                            to,
                            value,
                            keccak256(data),
                            operation,
                            safeTxGas,
                            baseGas,
                            gasPrice,
                            gasToken,
                            refundReceiver,
                            _nonce
                        )
                    );
                return abi.encodePacked(bytes1(0x19), bytes1(0x01), domainSeparator(), safeTxHash);
            }
            /// @dev Returns hash to be signed by owners.
            /// @param to Destination address.
            /// @param value Ether value.
            /// @param data Data payload.
            /// @param operation Operation type.
            /// @param safeTxGas Fas that should be used for the safe transaction.
            /// @param baseGas Gas costs for data used to trigger the safe transaction.
            /// @param gasPrice Maximum gas price that should be used for this transaction.
            /// @param gasToken Token address (or 0 if ETH) that is used for the payment.
            /// @param refundReceiver Address of receiver of gas payment (or 0 if tx.origin).
            /// @param _nonce Transaction nonce.
            /// @return Transaction hash.
            function getTransactionHash(
                address to,
                uint256 value,
                bytes calldata data,
                Enum.Operation operation,
                uint256 safeTxGas,
                uint256 baseGas,
                uint256 gasPrice,
                address gasToken,
                address refundReceiver,
                uint256 _nonce
            ) public view returns (bytes32) {
                return keccak256(encodeTransactionData(to, value, data, operation, safeTxGas, baseGas, gasPrice, gasToken, refundReceiver, _nonce));
            }
        }
        // SPDX-License-Identifier: LGPL-3.0-only
        pragma solidity >=0.7.0 <0.9.0;
        import "../common/Enum.sol";
        /// @title Executor - A contract that can execute transactions
        /// @author Richard Meissner - <[email protected]>
        contract Executor {
            function execute(
                address to,
                uint256 value,
                bytes memory data,
                Enum.Operation operation,
                uint256 txGas
            ) internal returns (bool success) {
                if (operation == Enum.Operation.DelegateCall) {
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        success := delegatecall(txGas, to, add(data, 0x20), mload(data), 0, 0)
                    }
                } else {
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        success := call(txGas, to, value, add(data, 0x20), mload(data), 0, 0)
                    }
                }
            }
        }
        // SPDX-License-Identifier: LGPL-3.0-only
        pragma solidity >=0.7.0 <0.9.0;
        import "../common/SelfAuthorized.sol";
        /// @title Fallback Manager - A contract that manages fallback calls made to this contract
        /// @author Richard Meissner - <[email protected]>
        contract FallbackManager is SelfAuthorized {
            event ChangedFallbackHandler(address handler);
            // keccak256("fallback_manager.handler.address")
            bytes32 internal constant FALLBACK_HANDLER_STORAGE_SLOT = 0x6c9a6c4a39284e37ed1cf53d337577d14212a4870fb976a4366c693b939918d5;
            function internalSetFallbackHandler(address handler) internal {
                bytes32 slot = FALLBACK_HANDLER_STORAGE_SLOT;
                // solhint-disable-next-line no-inline-assembly
                assembly {
                    sstore(slot, handler)
                }
            }
            /// @dev Allows to add a contract to handle fallback calls.
            ///      Only fallback calls without value and with data will be forwarded.
            ///      This can only be done via a Safe transaction.
            /// @param handler contract to handle fallbacks calls.
            function setFallbackHandler(address handler) public authorized {
                internalSetFallbackHandler(handler);
                emit ChangedFallbackHandler(handler);
            }
            // solhint-disable-next-line payable-fallback,no-complex-fallback
            fallback() external {
                bytes32 slot = FALLBACK_HANDLER_STORAGE_SLOT;
                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let handler := sload(slot)
                    if iszero(handler) {
                        return(0, 0)
                    }
                    calldatacopy(0, 0, calldatasize())
                    // The msg.sender address is shifted to the left by 12 bytes to remove the padding
                    // Then the address without padding is stored right after the calldata
                    mstore(calldatasize(), shl(96, caller()))
                    // Add 20 bytes for the address appended add the end
                    let success := call(gas(), handler, 0, 0, add(calldatasize(), 20), 0, 0)
                    returndatacopy(0, 0, returndatasize())
                    if iszero(success) {
                        revert(0, returndatasize())
                    }
                    return(0, returndatasize())
                }
            }
        }
        // SPDX-License-Identifier: LGPL-3.0-only
        pragma solidity >=0.7.0 <0.9.0;
        import "../common/Enum.sol";
        import "../common/SelfAuthorized.sol";
        interface Guard {
            function checkTransaction(
                address to,
                uint256 value,
                bytes memory data,
                Enum.Operation operation,
                uint256 safeTxGas,
                uint256 baseGas,
                uint256 gasPrice,
                address gasToken,
                address payable refundReceiver,
                bytes memory signatures,
                address msgSender
            ) external;
            function checkAfterExecution(bytes32 txHash, bool success) external;
        }
        /// @title Fallback Manager - A contract that manages fallback calls made to this contract
        /// @author Richard Meissner - <[email protected]>
        contract GuardManager is SelfAuthorized {
            event ChangedGuard(address guard);
            // keccak256("guard_manager.guard.address")
            bytes32 internal constant GUARD_STORAGE_SLOT = 0x4a204f620c8c5ccdca3fd54d003badd85ba500436a431f0cbda4f558c93c34c8;
            /// @dev Set a guard that checks transactions before execution
            /// @param guard The address of the guard to be used or the 0 address to disable the guard
            function setGuard(address guard) external authorized {
                bytes32 slot = GUARD_STORAGE_SLOT;
                // solhint-disable-next-line no-inline-assembly
                assembly {
                    sstore(slot, guard)
                }
                emit ChangedGuard(guard);
            }
            function getGuard() internal view returns (address guard) {
                bytes32 slot = GUARD_STORAGE_SLOT;
                // solhint-disable-next-line no-inline-assembly
                assembly {
                    guard := sload(slot)
                }
            }
        }
        // SPDX-License-Identifier: LGPL-3.0-only
        pragma solidity >=0.7.0 <0.9.0;
        import "../common/Enum.sol";
        import "../common/SelfAuthorized.sol";
        import "./Executor.sol";
        /// @title Module Manager - A contract that manages modules that can execute transactions via this contract
        /// @author Stefan George - <[email protected]>
        /// @author Richard Meissner - <[email protected]>
        contract ModuleManager is SelfAuthorized, Executor {
            event EnabledModule(address module);
            event DisabledModule(address module);
            event ExecutionFromModuleSuccess(address indexed module);
            event ExecutionFromModuleFailure(address indexed module);
            address internal constant SENTINEL_MODULES = address(0x1);
            mapping(address => address) internal modules;
            function setupModules(address to, bytes memory data) internal {
                require(modules[SENTINEL_MODULES] == address(0), "GS100");
                modules[SENTINEL_MODULES] = SENTINEL_MODULES;
                if (to != address(0))
                    // Setup has to complete successfully or transaction fails.
                    require(execute(to, 0, data, Enum.Operation.DelegateCall, gasleft()), "GS000");
            }
            /// @dev Allows to add a module to the whitelist.
            ///      This can only be done via a Safe transaction.
            /// @notice Enables the module `module` for the Safe.
            /// @param module Module to be whitelisted.
            function enableModule(address module) public authorized {
                // Module address cannot be null or sentinel.
                require(module != address(0) && module != SENTINEL_MODULES, "GS101");
                // Module cannot be added twice.
                require(modules[module] == address(0), "GS102");
                modules[module] = modules[SENTINEL_MODULES];
                modules[SENTINEL_MODULES] = module;
                emit EnabledModule(module);
            }
            /// @dev Allows to remove a module from the whitelist.
            ///      This can only be done via a Safe transaction.
            /// @notice Disables the module `module` for the Safe.
            /// @param prevModule Module that pointed to the module to be removed in the linked list
            /// @param module Module to be removed.
            function disableModule(address prevModule, address module) public authorized {
                // Validate module address and check that it corresponds to module index.
                require(module != address(0) && module != SENTINEL_MODULES, "GS101");
                require(modules[prevModule] == module, "GS103");
                modules[prevModule] = modules[module];
                modules[module] = address(0);
                emit DisabledModule(module);
            }
            /// @dev Allows a Module to execute a Safe transaction without any further confirmations.
            /// @param to Destination address of module transaction.
            /// @param value Ether value of module transaction.
            /// @param data Data payload of module transaction.
            /// @param operation Operation type of module transaction.
            function execTransactionFromModule(
                address to,
                uint256 value,
                bytes memory data,
                Enum.Operation operation
            ) public virtual returns (bool success) {
                // Only whitelisted modules are allowed.
                require(msg.sender != SENTINEL_MODULES && modules[msg.sender] != address(0), "GS104");
                // Execute transaction without further confirmations.
                success = execute(to, value, data, operation, gasleft());
                if (success) emit ExecutionFromModuleSuccess(msg.sender);
                else emit ExecutionFromModuleFailure(msg.sender);
            }
            /// @dev Allows a Module to execute a Safe transaction without any further confirmations and return data
            /// @param to Destination address of module transaction.
            /// @param value Ether value of module transaction.
            /// @param data Data payload of module transaction.
            /// @param operation Operation type of module transaction.
            function execTransactionFromModuleReturnData(
                address to,
                uint256 value,
                bytes memory data,
                Enum.Operation operation
            ) public returns (bool success, bytes memory returnData) {
                success = execTransactionFromModule(to, value, data, operation);
                // solhint-disable-next-line no-inline-assembly
                assembly {
                    // Load free memory location
                    let ptr := mload(0x40)
                    // We allocate memory for the return data by setting the free memory location to
                    // current free memory location + data size + 32 bytes for data size value
                    mstore(0x40, add(ptr, add(returndatasize(), 0x20)))
                    // Store the size
                    mstore(ptr, returndatasize())
                    // Store the data
                    returndatacopy(add(ptr, 0x20), 0, returndatasize())
                    // Point the return data to the correct memory location
                    returnData := ptr
                }
            }
            /// @dev Returns if an module is enabled
            /// @return True if the module is enabled
            function isModuleEnabled(address module) public view returns (bool) {
                return SENTINEL_MODULES != module && modules[module] != address(0);
            }
            /// @dev Returns array of modules.
            /// @param start Start of the page.
            /// @param pageSize Maximum number of modules that should be returned.
            /// @return array Array of modules.
            /// @return next Start of the next page.
            function getModulesPaginated(address start, uint256 pageSize) external view returns (address[] memory array, address next) {
                // Init array with max page size
                array = new address[](pageSize);
                // Populate return array
                uint256 moduleCount = 0;
                address currentModule = modules[start];
                while (currentModule != address(0x0) && currentModule != SENTINEL_MODULES && moduleCount < pageSize) {
                    array[moduleCount] = currentModule;
                    currentModule = modules[currentModule];
                    moduleCount++;
                }
                next = currentModule;
                // Set correct size of returned array
                // solhint-disable-next-line no-inline-assembly
                assembly {
                    mstore(array, moduleCount)
                }
            }
        }
        // SPDX-License-Identifier: LGPL-3.0-only
        pragma solidity >=0.7.0 <0.9.0;
        import "../common/SelfAuthorized.sol";
        /// @title OwnerManager - Manages a set of owners and a threshold to perform actions.
        /// @author Stefan George - <[email protected]>
        /// @author Richard Meissner - <[email protected]>
        contract OwnerManager is SelfAuthorized {
            event AddedOwner(address owner);
            event RemovedOwner(address owner);
            event ChangedThreshold(uint256 threshold);
            address internal constant SENTINEL_OWNERS = address(0x1);
            mapping(address => address) internal owners;
            uint256 internal ownerCount;
            uint256 internal threshold;
            /// @dev Setup function sets initial storage of contract.
            /// @param _owners List of Safe owners.
            /// @param _threshold Number of required confirmations for a Safe transaction.
            function setupOwners(address[] memory _owners, uint256 _threshold) internal {
                // Threshold can only be 0 at initialization.
                // Check ensures that setup function can only be called once.
                require(threshold == 0, "GS200");
                // Validate that threshold is smaller than number of added owners.
                require(_threshold <= _owners.length, "GS201");
                // There has to be at least one Safe owner.
                require(_threshold >= 1, "GS202");
                // Initializing Safe owners.
                address currentOwner = SENTINEL_OWNERS;
                for (uint256 i = 0; i < _owners.length; i++) {
                    // Owner address cannot be null.
                    address owner = _owners[i];
                    require(owner != address(0) && owner != SENTINEL_OWNERS && owner != address(this) && currentOwner != owner, "GS203");
                    // No duplicate owners allowed.
                    require(owners[owner] == address(0), "GS204");
                    owners[currentOwner] = owner;
                    currentOwner = owner;
                }
                owners[currentOwner] = SENTINEL_OWNERS;
                ownerCount = _owners.length;
                threshold = _threshold;
            }
            /// @dev Allows to add a new owner to the Safe and update the threshold at the same time.
            ///      This can only be done via a Safe transaction.
            /// @notice Adds the owner `owner` to the Safe and updates the threshold to `_threshold`.
            /// @param owner New owner address.
            /// @param _threshold New threshold.
            function addOwnerWithThreshold(address owner, uint256 _threshold) public authorized {
                // Owner address cannot be null, the sentinel or the Safe itself.
                require(owner != address(0) && owner != SENTINEL_OWNERS && owner != address(this), "GS203");
                // No duplicate owners allowed.
                require(owners[owner] == address(0), "GS204");
                owners[owner] = owners[SENTINEL_OWNERS];
                owners[SENTINEL_OWNERS] = owner;
                ownerCount++;
                emit AddedOwner(owner);
                // Change threshold if threshold was changed.
                if (threshold != _threshold) changeThreshold(_threshold);
            }
            /// @dev Allows to remove an owner from the Safe and update the threshold at the same time.
            ///      This can only be done via a Safe transaction.
            /// @notice Removes the owner `owner` from the Safe and updates the threshold to `_threshold`.
            /// @param prevOwner Owner that pointed to the owner to be removed in the linked list
            /// @param owner Owner address to be removed.
            /// @param _threshold New threshold.
            function removeOwner(
                address prevOwner,
                address owner,
                uint256 _threshold
            ) public authorized {
                // Only allow to remove an owner, if threshold can still be reached.
                require(ownerCount - 1 >= _threshold, "GS201");
                // Validate owner address and check that it corresponds to owner index.
                require(owner != address(0) && owner != SENTINEL_OWNERS, "GS203");
                require(owners[prevOwner] == owner, "GS205");
                owners[prevOwner] = owners[owner];
                owners[owner] = address(0);
                ownerCount--;
                emit RemovedOwner(owner);
                // Change threshold if threshold was changed.
                if (threshold != _threshold) changeThreshold(_threshold);
            }
            /// @dev Allows to swap/replace an owner from the Safe with another address.
            ///      This can only be done via a Safe transaction.
            /// @notice Replaces the owner `oldOwner` in the Safe with `newOwner`.
            /// @param prevOwner Owner that pointed to the owner to be replaced in the linked list
            /// @param oldOwner Owner address to be replaced.
            /// @param newOwner New owner address.
            function swapOwner(
                address prevOwner,
                address oldOwner,
                address newOwner
            ) public authorized {
                // Owner address cannot be null, the sentinel or the Safe itself.
                require(newOwner != address(0) && newOwner != SENTINEL_OWNERS && newOwner != address(this), "GS203");
                // No duplicate owners allowed.
                require(owners[newOwner] == address(0), "GS204");
                // Validate oldOwner address and check that it corresponds to owner index.
                require(oldOwner != address(0) && oldOwner != SENTINEL_OWNERS, "GS203");
                require(owners[prevOwner] == oldOwner, "GS205");
                owners[newOwner] = owners[oldOwner];
                owners[prevOwner] = newOwner;
                owners[oldOwner] = address(0);
                emit RemovedOwner(oldOwner);
                emit AddedOwner(newOwner);
            }
            /// @dev Allows to update the number of required confirmations by Safe owners.
            ///      This can only be done via a Safe transaction.
            /// @notice Changes the threshold of the Safe to `_threshold`.
            /// @param _threshold New threshold.
            function changeThreshold(uint256 _threshold) public authorized {
                // Validate that threshold is smaller than number of owners.
                require(_threshold <= ownerCount, "GS201");
                // There has to be at least one Safe owner.
                require(_threshold >= 1, "GS202");
                threshold = _threshold;
                emit ChangedThreshold(threshold);
            }
            function getThreshold() public view returns (uint256) {
                return threshold;
            }
            function isOwner(address owner) public view returns (bool) {
                return owner != SENTINEL_OWNERS && owners[owner] != address(0);
            }
            /// @dev Returns array of owners.
            /// @return Array of Safe owners.
            function getOwners() public view returns (address[] memory) {
                address[] memory array = new address[](ownerCount);
                // populate return array
                uint256 index = 0;
                address currentOwner = owners[SENTINEL_OWNERS];
                while (currentOwner != SENTINEL_OWNERS) {
                    array[index] = currentOwner;
                    currentOwner = owners[currentOwner];
                    index++;
                }
                return array;
            }
        }
        // SPDX-License-Identifier: LGPL-3.0-only
        pragma solidity >=0.7.0 <0.9.0;
        /// @title Enum - Collection of enums
        /// @author Richard Meissner - <[email protected]>
        contract Enum {
            enum Operation {Call, DelegateCall}
        }
        // SPDX-License-Identifier: LGPL-3.0-only
        pragma solidity >=0.7.0 <0.9.0;
        /// @title EtherPaymentFallback - A contract that has a fallback to accept ether payments
        /// @author Richard Meissner - <[email protected]>
        contract EtherPaymentFallback {
            event SafeReceived(address indexed sender, uint256 value);
            /// @dev Fallback function accepts Ether transactions.
            receive() external payable {
                emit SafeReceived(msg.sender, msg.value);
            }
        }
        // SPDX-License-Identifier: LGPL-3.0-only
        pragma solidity >=0.7.0 <0.9.0;
        /// @title SecuredTokenTransfer - Secure token transfer
        /// @author Richard Meissner - <[email protected]>
        contract SecuredTokenTransfer {
            /// @dev Transfers a token and returns if it was a success
            /// @param token Token that should be transferred
            /// @param receiver Receiver to whom the token should be transferred
            /// @param amount The amount of tokens that should be transferred
            function transferToken(
                address token,
                address receiver,
                uint256 amount
            ) internal returns (bool transferred) {
                // 0xa9059cbb - keccack("transfer(address,uint256)")
                bytes memory data = abi.encodeWithSelector(0xa9059cbb, receiver, amount);
                // solhint-disable-next-line no-inline-assembly
                assembly {
                    // We write the return value to scratch space.
                    // See https://docs.soliditylang.org/en/v0.7.6/internals/layout_in_memory.html#layout-in-memory
                    let success := call(sub(gas(), 10000), token, 0, add(data, 0x20), mload(data), 0, 0x20)
                    switch returndatasize()
                        case 0 {
                            transferred := success
                        }
                        case 0x20 {
                            transferred := iszero(or(iszero(success), iszero(mload(0))))
                        }
                        default {
                            transferred := 0
                        }
                }
            }
        }
        // SPDX-License-Identifier: LGPL-3.0-only
        pragma solidity >=0.7.0 <0.9.0;
        /// @title SelfAuthorized - authorizes current contract to perform actions
        /// @author Richard Meissner - <[email protected]>
        contract SelfAuthorized {
            function requireSelfCall() private view {
                require(msg.sender == address(this), "GS031");
            }
            modifier authorized() {
                // This is a function call as it minimized the bytecode size
                requireSelfCall();
                _;
            }
        }
        // SPDX-License-Identifier: LGPL-3.0-only
        pragma solidity >=0.7.0 <0.9.0;
        /// @title SignatureDecoder - Decodes signatures that a encoded as bytes
        /// @author Richard Meissner - <[email protected]>
        contract SignatureDecoder {
            /// @dev divides bytes signature into `uint8 v, bytes32 r, bytes32 s`.
            /// @notice Make sure to peform a bounds check for @param pos, to avoid out of bounds access on @param signatures
            /// @param pos which signature to read. A prior bounds check of this parameter should be performed, to avoid out of bounds access
            /// @param signatures concatenated rsv signatures
            function signatureSplit(bytes memory signatures, uint256 pos)
                internal
                pure
                returns (
                    uint8 v,
                    bytes32 r,
                    bytes32 s
                )
            {
                // The signature format is a compact form of:
                //   {bytes32 r}{bytes32 s}{uint8 v}
                // Compact means, uint8 is not padded to 32 bytes.
                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let signaturePos := mul(0x41, pos)
                    r := mload(add(signatures, add(signaturePos, 0x20)))
                    s := mload(add(signatures, add(signaturePos, 0x40)))
                    // Here we are loading the last 32 bytes, including 31 bytes
                    // of 's'. There is no 'mload8' to do this.
                    //
                    // 'byte' is not working due to the Solidity parser, so lets
                    // use the second best option, 'and'
                    v := and(mload(add(signatures, add(signaturePos, 0x41))), 0xff)
                }
            }
        }
        // SPDX-License-Identifier: LGPL-3.0-only
        pragma solidity >=0.7.0 <0.9.0;
        /// @title Singleton - Base for singleton contracts (should always be first super contract)
        ///         This contract is tightly coupled to our proxy contract (see `proxies/GnosisSafeProxy.sol`)
        /// @author Richard Meissner - <[email protected]>
        contract Singleton {
            // singleton always needs to be first declared variable, to ensure that it is at the same location as in the Proxy contract.
            // It should also always be ensured that the address is stored alone (uses a full word)
            address private singleton;
        }
        // SPDX-License-Identifier: LGPL-3.0-only
        pragma solidity >=0.7.0 <0.9.0;
        /// @title StorageAccessible - generic base contract that allows callers to access all internal storage.
        /// @notice See https://github.com/gnosis/util-contracts/blob/bb5fe5fb5df6d8400998094fb1b32a178a47c3a1/contracts/StorageAccessible.sol
        contract StorageAccessible {
            /**
             * @dev Reads `length` bytes of storage in the currents contract
             * @param offset - the offset in the current contract's storage in words to start reading from
             * @param length - the number of words (32 bytes) of data to read
             * @return the bytes that were read.
             */
            function getStorageAt(uint256 offset, uint256 length) public view returns (bytes memory) {
                bytes memory result = new bytes(length * 32);
                for (uint256 index = 0; index < length; index++) {
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        let word := sload(add(offset, index))
                        mstore(add(add(result, 0x20), mul(index, 0x20)), word)
                    }
                }
                return result;
            }
            /**
             * @dev Performs a delegetecall on a targetContract in the context of self.
             * Internally reverts execution to avoid side effects (making it static).
             *
             * This method reverts with data equal to `abi.encode(bool(success), bytes(response))`.
             * Specifically, the `returndata` after a call to this method will be:
             * `success:bool || response.length:uint256 || response:bytes`.
             *
             * @param targetContract Address of the contract containing the code to execute.
             * @param calldataPayload Calldata that should be sent to the target contract (encoded method name and arguments).
             */
            function simulateAndRevert(address targetContract, bytes memory calldataPayload) external {
                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let success := delegatecall(gas(), targetContract, add(calldataPayload, 0x20), mload(calldataPayload), 0, 0)
                    mstore(0x00, success)
                    mstore(0x20, returndatasize())
                    returndatacopy(0x40, 0, returndatasize())
                    revert(0, add(returndatasize(), 0x40))
                }
            }
        }
        // SPDX-License-Identifier: LGPL-3.0-only
        pragma solidity >=0.7.0 <0.9.0;
        /**
         * @title GnosisSafeMath
         * @dev Math operations with safety checks that revert on error
         * Renamed from SafeMath to GnosisSafeMath to avoid conflicts
         * TODO: remove once open zeppelin update to solc 0.5.0
         */
        library GnosisSafeMath {
            /**
             * @dev Multiplies two numbers, reverts on overflow.
             */
            function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                // benefit is lost if 'b' is also tested.
                // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
                if (a == 0) {
                    return 0;
                }
                uint256 c = a * b;
                require(c / a == b);
                return c;
            }
            /**
             * @dev Subtracts two numbers, reverts on overflow (i.e. if subtrahend is greater than minuend).
             */
            function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                require(b <= a);
                uint256 c = a - b;
                return c;
            }
            /**
             * @dev Adds two numbers, reverts on overflow.
             */
            function add(uint256 a, uint256 b) internal pure returns (uint256) {
                uint256 c = a + b;
                require(c >= a);
                return c;
            }
            /**
             * @dev Returns the largest of two numbers.
             */
            function max(uint256 a, uint256 b) internal pure returns (uint256) {
                return a >= b ? a : b;
            }
        }
        // SPDX-License-Identifier: LGPL-3.0-only
        pragma solidity >=0.7.0 <0.9.0;
        contract ISignatureValidatorConstants {
            // bytes4(keccak256("isValidSignature(bytes,bytes)")
            bytes4 internal constant EIP1271_MAGIC_VALUE = 0x20c13b0b;
        }
        abstract contract ISignatureValidator is ISignatureValidatorConstants {
            /**
             * @dev Should return whether the signature provided is valid for the provided data
             * @param _data Arbitrary length data signed on the behalf of address(this)
             * @param _signature Signature byte array associated with _data
             *
             * MUST return the bytes4 magic value 0x20c13b0b when function passes.
             * MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for solc > 0.5)
             * MUST allow external calls
             */
            function isValidSignature(bytes memory _data, bytes memory _signature) public view virtual returns (bytes4);
        }