creation_sourcecode: {{
    "language": "Solidity",
    "settings": {
      "evmVersion": "paris",
      "libraries": {},
      "metadata": {
        "bytecodeHash": "ipfs",
        "useLiteralContent": true
      },
      "optimizer": {
        "enabled": true,
        "runs": 200
      },
      "remappings": [],
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      }
    },
    "sources": {
      "src/ERC20/IERC20.sol": {
        "content": "/**\n* SPDX-License-Identifier: MIT\n*\n* Copyright (c) 2016-2019 zOS Global Limited\n*\n*/\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP. Does not include\n * the optional functions; to access them see `ERC20Detailed`.\n */\n\ninterface IERC20 {\n\n    // Optional functions\n    function name() external view returns (string memory);\n\n    function symbol() external view returns (string memory);\n\n    function decimals() external view returns (uint8);\n\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller's account to `recipient`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a `Transfer` event.\n     */\n    function transfer(address recipient, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through `transferFrom`. This is\n     * zero by default.\n     *\n     * This value changes when `approve` or `transferFrom` are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * > Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an `Approval` event.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `sender` to `recipient` using the\n     * allowance mechanism. `amount` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a `Transfer` event.\n     */\n    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to `approve`. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n}"
      },
      "src/ERC20/IERC20Permit.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\n// Copied from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\ninterface IERC20Permit is IERC20 {\n\n    /*//////////////////////////////////////////////////////////////\n                            Custom errors\n\t//////////////////////////////////////////////////////////////*/\n    /// Block timestamp must to be before deadline.\n    /// @param deadline The deadline of the permit.\n    /// @param blockTimestamp The timestamp of the execution block.\n    error Permit_DeadlineExpired(uint256 deadline, uint256 blockTimestamp);\n    /// Recovered address must be owner and not zero address.\n    /// @param signerAddress The recovered signer address.\n    error Permit_InvalidSigner(address signerAddress);\n\n    /**\n     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n     * given ``owner``'s signed approval.\n     *\n     * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n     * ordering also apply here.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `deadline` must be a timestamp in the future.\n     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n     * over the EIP712-formatted function arguments.\n     * - the signature must use ``owner``'s current nonce (see {nonces}).\n     *\n     * For more information on the signature format, see the\n     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n     * section].\n     */\n    function permit(\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external;\n\n    /**\n     * @dev Returns the current nonce for `owner`. This value must be\n     * included whenever a signature is generated for {permit}.\n     *\n     * Every successful call to {permit} increases ``owner``'s nonce by one. This\n     * prevents a signature from being used multiple times.\n     */\n    function nonces(address owner) external view returns (uint256);\n\n    /**\n     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n     */\n    // solhint-disable-next-line func-name-mixedcase\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\n}"
      },
      "src/ERC20/IERC677Receiver.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n// Given that development on ERC 677 has stalled, we should consider supporting EIP 1363: https://eips.ethereum.org/EIPS/eip-1363\ninterface IERC677Receiver {\n\n    error IERC677_OnTokenTransferFailed();\n    \n    function onTokenTransfer(address from, uint256 amount, bytes calldata data) external returns (bool);\n\n}"
      },
      "src/brokerbot/Brokerbot.sol": {
        "content": "/**\n* SPDX-License-Identifier: LicenseRef-Aktionariat\n*\n* Proprietary License\n*\n* This code cannot be used without an explicit permission from the copyright holder.\n* If you wish to use the Aktionariat Brokerbot, you can either use the open version\n* named Brokerbot.sol that can be used under an MIT License with Automated License Fee Payments,\n* or you can get in touch with use to negotiate a license to use LicensedBrokerbot.sol .\n*\n* Copyright (c) 2021 Aktionariat AG (aktionariat.com), All rights reserved.\n*/\npragma solidity ^0.8.0;\n\nimport \"../utils/Ownable.sol\";\nimport \"../ERC20/IERC20.sol\";\nimport \"../ERC20/IERC20Permit.sol\";\nimport \"../ERC20/IERC677Receiver.sol\";\nimport \"./IBrokerbot.sol\";\nimport \"../utils/SafeERC20.sol\";\n\ncontract Brokerbot is IBrokerbot, Ownable {\n\n    using SafeERC20 for IERC20;\n\n    address public override paymenthub;\n\n    IERC20 public override immutable base;  // ERC-20 currency\n    IERC20Permit public override immutable token; // ERC-20 share token\n\n    uint256 private price; // current offer price in base currency, without drift\n    uint256 public increment; // increment step the price in/decreases when buying/selling\n\n    uint256 public driftStart;\n    uint256 public timeToDrift; // seconds until drift pushes price by one drift increment\n    int256 public driftIncrement;\n\n    // Note that these settings might be hard-coded in various places, so better not change these values.\n    uint8 private constant BUYING_ENABLED = 0x1;\n    uint8 private constant SELLING_ENABLED = 0x2;\n    // note that in the UI, we call the setting \"convert ether\", which is the opposite\n    uint8 private constant KEEP_ETHER = 0x4;\n\n    // Version history\n    // Version 2: added ability to process bank orders even if buying disabled\n    // Version 3: added various events, removed license fee\n    // Version 4: made version field public so it is actually usable    \n    // Version 5: added target address for withdrawEther\n    // Version 6: added costs field to notifyTrade\n    // Version 7: added withdraw eth event\n    // Version 8: use SafeERC20\n    uint8 public constant VERSION = 0x8;\n\n    // more bits to be used by payment hub\n    uint256 public override settings = BUYING_ENABLED | SELLING_ENABLED;\n\n    event Trade(IERC20Permit indexed token, address who, bytes ref, int amount, IERC20 base, uint totPrice, uint fee, uint newprice);\n    event PaymentHubUpdate(address indexed paymentHub);\n    event PriceSet(uint256 price, uint256 increment);\n    event DriftSet(uint256 timeToDrift, int256 driftIncrement);\n    event SettingsChange(uint256 setting);\n    // ETH in/out events\n    event Received(address indexed from, uint amountETH, uint amountBase);\n    event Withdrawn(address indexed target, uint amountETH);\n    \n    constructor(\n        IERC20Permit _token,\n        uint256 _price,\n        uint256 _increment,\n        IERC20 _base,\n        address _owner,\n        address _paymentHub\n    )\n        Ownable(_owner)\n    {\n        base = _base;\n        token = _token;\n        price = _price;\n        increment = _increment;\n        paymenthub = _paymentHub;\n        // Should we disabled recoverability in the recovery hub here?\n        // No, if someone attacks us, we can always trigger a transfer and recover the tokens as well as the collateral.\n    }\n\n    function setPrice(uint256 _price, uint256 _increment) external onlyOwner {\n        anchorPrice(_price);\n        increment = _increment;\n        emit PriceSet(_price, _increment);\n    }\n\n    function hasDrift() public view returns (bool) {\n        return timeToDrift != 0;\n    }\n\n    // secondsPerStep should be negative for downwards drift\n    function setDrift(uint256 secondsPerStep, int256 _driftIncrement) external onlyOwner {\n        anchorPrice(getPrice());\n        timeToDrift = secondsPerStep;\n        driftIncrement = _driftIncrement;\n        emit DriftSet(secondsPerStep, _driftIncrement);\n    }\n\n    function anchorPrice(uint256 currentPrice) private {\n        price = currentPrice;\n        // rely on time stamp is ok, no exact time stamp needed\n        // solhint-disable-next-line not-rely-on-time\n        driftStart = block.timestamp;\n    }\n\n    function getPrice() public view returns (uint256) {\n        // rely on time stamp is ok, no exact time stamp needed\n        // solhint-disable-next-line not-rely-on-time\n        return getPriceAtTime(block.timestamp);\n    }\n\n    function getPriceAtTime(uint256 timestamp) public view returns (uint256) {\n        if (hasDrift()){\n            uint256 passed = timestamp - driftStart;\n            int256 drifted = int256(passed / timeToDrift) * driftIncrement;\n            int256 driftedPrice = int256(price) + drifted;\n            if (driftedPrice < 0){\n                return 0;\n            } else {\n                return uint256(driftedPrice);\n            }\n        } else {\n            return price;\n        }\n    }\n\n    function buy(address from, uint256 paid, bytes calldata ref) internal returns (uint256) {\n        if (!hasSetting(BUYING_ENABLED)) {\n            revert Brokerbot_BuyingDisabled();\n        }\n        uint shares = getShares(paid);\n        uint costs = getBuyPrice(shares);\n        notifyTraded(from, shares, costs, ref);\n        if (costs < paid){\n            base.safeTransfer(from, paid - costs);\n        }\n        IERC20(token).safeTransfer(from, shares);\n        return shares;\n    }\n\n    // Callers must verify that (hasSetting(BUYING_ENABLED) || msg.sender == owner) holds!\n    function notifyTraded(address from, uint256 shares, uint256 costs, bytes calldata ref) internal returns (uint256) {\n        // disabling the requirement below for efficiency as this always holds once we reach this point\n        // require(hasSetting(BUYING_ENABLED) || msg.sender == owner, \"buying disabled\");\n        price = price + (shares * increment);\n        emit Trade(token, from, ref, int256(shares), base, costs, 0, getPrice());\n        return costs;\n    }\n\n    function notifyTrade(address buyer, uint256 shares, uint256 costs, bytes calldata ref) external onlyOwner {\n        notifyTraded(buyer, shares, costs, ref);\n    }\n\n    function notifyTradeAndTransfer(address buyer, uint256 shares, uint256 costs, bytes calldata ref) public onlyOwner {\n        notifyTraded(buyer, shares, costs, ref);\n        IERC20(token).safeTransfer(buyer, shares);\n    }\n\n    function notifyTrades(address[] calldata buyers, uint256[] calldata shares, uint256[] calldata costs, bytes[] calldata ref) external onlyOwner {\n        for (uint i = 0; i < buyers.length; i++) {\n            notifyTraded(buyers[i], shares[i], costs[i], ref[i]);\n        }\n    }\n\n    function notifyTradesAndTransfer(address[] calldata buyers, uint256[] calldata shares, uint256[] calldata costs, bytes[] calldata ref) external onlyOwner {\n        for (uint i = 0; i < buyers.length; i++) {\n            notifyTradeAndTransfer(buyers[i], shares[i], costs[i], ref[i]);\n        }\n    }\n\n    /**\n     * @notice Payment hub might actually have sent another accepted token, including Ether.\n     * @dev Is either called from payment hub or from transferAndCall of the share token (via onTokenTransfer).\n     * @param incomingAsset the erc20 address of either base currency or the share token.\n     * @param from Who iniciated the sell/buy.\n     * @param amount The amount of shares the are sold / The base amount paid to buy sharees.\n     * @param ref Reference data blob.\n     * @return The amount of shares bought / The amount received for selling the shares. \n     */\n    function processIncoming(IERC20 incomingAsset, address from, uint256 amount, bytes calldata ref) public override payable returns (uint256) {\n        if (msg.sender != address(incomingAsset) && msg.sender != paymenthub) {\n            revert Brokerbot_InvalidSender(msg.sender);\n        }\n        if(msg.value > 0) {\n            emit Received(from, msg.value, amount);\n        }\n        if (incomingAsset == token){\n            return sell(from, amount, ref);\n        } else if (incomingAsset == base){\n            return buy(from, amount, ref);\n        } else {\n            revert(\"invalid token\");\n        }\n    }\n\n    // ERC-677 recipient\n    function onTokenTransfer(address from, uint256 amount, bytes calldata ref) external returns (bool) {\n        processIncoming(IERC20(msg.sender), from, amount, ref);\n        return true;\n    }\n\n    function hasSetting(uint256 setting) private view returns (bool) {\n        return settings & setting == setting;\n    }\n\n    /**\n     * ref 0x01 or old format sells shares for base currency.\n     * ref 0x02 indicates a sell via bank transfer.\n     */\n    function isDirectSale(bytes calldata ref) internal pure returns (bool) {\n        if (ref.length == 0 || ref.length == 20) {\n            return true; // old format\n        } else {\n            if (ref[0] == bytes1(0x01)){\n                return true;\n            } else if (ref[0] == bytes1(0x02)) {\n                return false;\n            } else {\n                revert(\"unknown ref\");\n            }\n        }\n    }\n\n\n    function sell(address recipient, uint256 amount, bytes calldata ref) internal returns (uint256) {\n        if (!hasSetting(SELLING_ENABLED)) {\n            revert Brokerbot_SellingDisabled();\n        }\n        uint256 totPrice = getSellPrice(amount);\n        price -= amount * increment;\n        if (isDirectSale(ref)){\n            base.safeTransfer(recipient, totPrice);\n        }\n        emit Trade(token, recipient, ref, -int256(amount), base, totPrice, 0, getPrice());\n        return totPrice;\n    }\n\n    function getSellPrice(uint256 shares) public view override returns (uint256) {\n        return getPrice(getPrice() - (shares * increment), shares);\n    }\n\n    function getBuyPrice(uint256 shares) public view override returns (uint256) {\n        return getPrice(getPrice(), shares);\n    }\n\n    function getPrice(uint256 lowest, uint256 shares) internal view returns (uint256){\n        if (shares == 0) {\n            return 0;\n        } else {\n            uint256 highest = lowest + (shares - 1) * increment;\n            return (lowest + highest) * shares / 2;\n        }\n    }\n\n    function getShares(uint256 money) public view returns (uint256) {\n        uint256 currentPrice = getPrice();\n        uint256 min = 0;\n        uint256 max = money / currentPrice;\n        while (min < max){\n            uint256 middle = (min + max)/2;\n            uint256 totalPrice = getPrice(currentPrice, middle);\n            if (money > totalPrice){\n                min = middle + 1;\n            } else {\n                max = middle;\n            }\n        }\n        return min;\n    }\n\n    function withdrawEther(address target, uint256 amount) public ownerOrHub() {\n        (bool success, ) = payable(target).call{value:amount}(\"\");\n        if (!success) {\n            revert Brokerbot_WithdrawFailed(target, amount);\n        }\n        emit Withdrawn(target, amount);\n    }\n\n    function withdrawEther(uint256 amount) external ownerOrHub() {\n        withdrawEther(msg.sender, amount);\n    }\n\n    function approve(address erc20, address who, uint256 amount) external onlyOwner() {\n        IERC20(erc20).approve(who, amount);\n    }\n\n    function withdraw(IERC20 ercAddress, address to, uint256 amount) external ownerOrHub() {\n        ercAddress.safeTransfer(to, amount);\n    }\n\n    function setPaymentHub(address hub) external onlyOwner() {\n        paymenthub = hub;\n        emit PaymentHubUpdate(paymenthub);\n    }\n\n    function setSettings(uint256 _settings) public onlyOwner() {\n        settings = _settings;\n        emit SettingsChange(_settings);\n    }\n\n    function setEnabled(bool _buyingEnabled, bool _sellingEnabled) external onlyOwner() {\n        uint256 _settings = settings;\n        if (_buyingEnabled != hasSetting(BUYING_ENABLED)){\n            _settings ^= BUYING_ENABLED;\n        }\n        if (_sellingEnabled != hasSetting(SELLING_ENABLED)){\n            _settings ^= SELLING_ENABLED;\n        }\n        setSettings(_settings);\n    }\n    \n    modifier ownerOrHub() {\n        if (owner != msg.sender && paymenthub != msg.sender) {\n            revert Brokerbot_NotAuthorized(msg.sender);\n        }\n        _;\n    }\n}\n"
      },
      "src/brokerbot/IBrokerbot.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../ERC20/IERC20.sol\";\nimport \"../ERC20/IERC20Permit.sol\";\n\ninterface IBrokerbot {\n\n\t/*//////////////////////////////////////////////////////////////\n                            Custom errors\n  //////////////////////////////////////////////////////////////*/\n  error Brokerbot_BuyingDisabled();\n  error Brokerbot_SellingDisabled();\n  /// Sender(msg.sender) has to be incoming token or paymenthub.\n  /// @param sender The msg.sender.\n  error Brokerbot_InvalidSender(address sender);\n  /// target.call() wasn't successful.\n  /// @param target The receiver of the Eth.\n  /// @param amount The withdraw amount.\n  error Brokerbot_WithdrawFailed(address target, uint256 amount);\n  /// Sender(msg.sender) needs to be owner or paymenthub.\n  /// @param sender The msg.sender.\n  error Brokerbot_NotAuthorized(address sender);\n\n  function paymenthub() external view returns (address);\n\n  function base() external view returns (IERC20);\n\n  function token() external view returns (IERC20Permit);\n  \n  function settings() external view returns (uint256);\n\n  // @return The amount of shares bought on buying or how much in the base currency is transfered on selling\n  function processIncoming(IERC20 token_, address from, uint256 amount, bytes calldata ref) external payable returns (uint256);\n\n  function getBuyPrice(uint256 shares) external view returns (uint256);\n\n  function getSellPrice(uint256 shares) external view returns (uint256);\n\n}"
      },
      "src/utils/Address.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// Copied from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Address.sol\n// and modified it.\n\npragma solidity ^0.8.0;\n\nlibrary Address {\n\n    /// @param target Target address to call the function on.\n    error Address_NotTransferNorContract(address target);\n\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n        return account.code.length > 0;\n    }\n    \n    /**\n     * @dev Performs a Solidity function call using a low level `call`. A\n     * plain `call` is an unsafe replacement for a function call: use this\n     * function instead.\n     *\n     * If `target` reverts with a revert reason or custom error, it is bubbled\n     * up by this function (like regular Solidity function calls). However, if\n     * the call reverted with no returned reason, this function reverts with a\n     * {FailedInnerCall} error.\n     *\n     * Returns the raw returned data. To convert to the expected return value,\n     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n     *\n     * Requirements:\n     *\n     * - `target` must be a contract.\n     * - calling `target` with `data` must not revert.\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0);\n    }\n\n    function functionCallWithValue(address target, bytes memory data, uint256 weiValue) internal returns (bytes memory) {\n        if (data.length != 0 && !isContract(target)) {\n            revert Address_NotTransferNorContract(target);\n        }\n        // solhint-disable-next-line avoid-low-level-calls\n        (bool success, bytes memory returndata) = target.call{ value: weiValue }(data);\n        if (success) {\n            return returndata;\n        } else if (returndata.length > 0) {\n            assembly{\n                revert (add (returndata, 0x20), mload (returndata))\n            }\n        } else {\n           revert(\"failed\");\n        }\n    }\n}"
      },
      "src/utils/Ownable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n//\n// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol\n//\n// Modifications:\n// - Replaced Context._msgSender() with msg.sender\n// - Made leaner\n// - Extracted interface\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\ncontract Ownable {\n\n    address public owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    error Ownable_NotOwner(address sender);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor (address initialOwner) {\n        owner = initialOwner;\n        emit OwnershipTransferred(address(0), owner);\n    }\n\n    modifier onlyOwner() {\n        _checkOwner();\n        _;\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) external onlyOwner {\n        emit OwnershipTransferred(owner, newOwner);\n        owner = newOwner;\n    }\n\n    function _checkOwner() internal view {\n        if (msg.sender != owner) {\n            revert Ownable_NotOwner(msg.sender);\n        }\n    }\n}"
      },
      "src/utils/SafeERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// coppied and adjusted from OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../ERC20/IERC20.sol\";\nimport {IERC20Permit} from \"../ERC20/IERC20Permit.sol\";\nimport {Address} from \"./Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n    using Address for address;\n\n    /**\n     * @dev An operation with an ERC20 token failed.\n     */\n    error SafeERC20FailedOperation(address token);\n\n    /**\n     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeTransfer(IERC20 token, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n    }\n\n    /**\n     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n     */\n    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n    }\n\n    /**\n     * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.\n     * Revert on invalid signature.\n     */\n    function safePermit(\n        IERC20Permit token,\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal {\n        uint256 nonceBefore = token.nonces(owner);\n        token.permit(owner, spender, value, deadline, v, r, s);\n        uint256 nonceAfter = token.nonces(owner);\n        if (nonceAfter != nonceBefore + 1) {\n            revert SafeERC20FailedOperation(address(token));\n        }\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     */\n    function _callOptionalReturn(IERC20 token, bytes memory data) private {\n        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n        // the target address contains contract code and also asserts for success in the low-level call.\n\n        bytes memory returndata = address(token).functionCall(data);\n        if (returndata.length != 0 && !abi.decode(returndata, (bool))) {\n            revert SafeERC20FailedOperation(address(token));\n        }\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     *\n     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n     */\n    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n        // and not revert is the subcall reverts.\n\n        (bool success, bytes memory returndata) = address(token).call(data);\n        return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;\n    }\n}"
      }
    }
  }}