ETH Price: $2,439.03 (-4.37%)

Transaction Decoder

Block:
15016544 at Jun-24-2022 04:36:55 AM +UTC
Transaction Fee:
0.002125017926165568 ETH $5.18
Gas Used:
70,728 Gas / 30.044931656 Gwei

Emitted Events:

78 PercentSplit.ETHTransferred( account=0x6027b4c9ad98ad5dc9ee984ed699a2079d401416, amount=20413500000000000 )
79 PercentSplit.ETHTransferred( account=0x448129d729b7c0b5750dab613b9f35be091a2e83, amount=57838250000000000 )
80 PercentSplit.ETHTransferred( account=0x2f367c13871b48b9f328bd3a103d9a6ac5f18b1f, amount=57838250000000000 )

Account State Difference:

  Address   Before After State Difference Code
0x0B7a4347...eA4173B22
533.213834887952275473 Eth
Nonce: 153968
533.075619870026109905 Eth
Nonce: 153969
0.138215017926165568
0x2f367c13...Ac5f18b1f 0.17104637762514 Eth0.22888462762514 Eth0.05783825
0x448129D7...E091a2E83 5.765114943141855697 Eth5.822953193141855697 Eth0.05783825
0x6027B4c9...79d401416 260.794337742025097187 Eth260.814751242025097187 Eth0.0204135
(Poolin 4)
1,825.638835867995090849 Eth1,825.639139905625275473 Eth0.000304037630184624

Execution Trace

ETH 0.13609 PercentSplit.CALL( )
  • ETH 0.13609 PercentSplit.DELEGATECALL( )
    • ETH 0.0204135 0x6027b4c9ad98ad5dc9ee984ed699a2079d401416.CALL( )
    • ETH 0.05783825 0x448129d729b7c0b5750dab613b9f35be091a2e83.CALL( )
    • ETH 0.05783825 0x2f367c13871b48b9f328bd3a103d9a6ac5f18b1f.CALL( )
      File 1 of 2: PercentSplit
      /*
        ・
         * ★
            ・ 。
               ・ ゚☆ 。
            * ★ ゚・。 *  。
                  * ☆ 。・゚*.。
               ゚ *.。☆。★ ・
      ​
                            `                     .-:::::-.`              `-::---...```
                           `-:`               .:+ssssoooo++//:.`       .-/+shhhhhhhhhhhhhyyyssooo:
                          .--::.            .+ossso+/////++/:://-`   .////+shhhhhhhhhhhhhhhhhhhhhy
                        `-----::.         `/+////+++///+++/:--:/+/-  -////+shhhhhhhhhhhhhhhhhhhhhy
                       `------:::-`      `//-.``.-/+ooosso+:-.-/oso- -////+shhhhhhhhhhhhhhhhhhhhhy
                      .--------:::-`     :+:.`  .-/osyyyyyyso++syhyo.-////+shhhhhhhhhhhhhhhhhhhhhy
                    `-----------:::-.    +o+:-.-:/oyhhhhhhdhhhhhdddy:-////+shhhhhhhhhhhhhhhhhhhhhy
                   .------------::::--  `oys+/::/+shhhhhhhdddddddddy/-////+shhhhhhhhhhhhhhhhhhhhhy
                  .--------------:::::-` +ys+////+yhhhhhhhddddddddhy:-////+yhhhhhhhhhhhhhhhhhhhhhy
                `----------------::::::-`.ss+/:::+oyhhhhhhhhhhhhhhho`-////+shhhhhhhhhhhhhhhhhhhhhy
               .------------------:::::::.-so//::/+osyyyhhhhhhhhhys` -////+shhhhhhhhhhhhhhhhhhhhhy
             `.-------------------::/:::::..+o+////+oosssyyyyyyys+`  .////+shhhhhhhhhhhhhhhhhhhhhy
             .--------------------::/:::.`   -+o++++++oooosssss/.     `-//+shhhhhhhhhhhhhhhhhhhhyo
           .-------   ``````.......--`        `-/+ooooosso+/-`          `./++++///:::--...``hhhhyo
                                                    `````
         * 
            ・ 。
          ・  ゚☆ 。
            * ★ ゚・。 *  。
                  * ☆ 。・゚*.。
               ゚ *.。☆。★ ・
          *  ゚。·*・。 ゚*
           ☆゚・。°*. ゚
        ・ ゚*。・゚★。
        ・ *゚。   *
       ・゚*。★・
       ☆∴。 *
      ・ 。
      */
      // SPDX-License-Identifier: MIT OR Apache-2.0
      pragma solidity ^0.7.0;
      pragma abicoder v2; // solhint-disable-line
      import "@openzeppelin/contracts-upgradeable/proxy/Initializable.sol";
      import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
      import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol";
      import "@openzeppelin/contracts/proxy/Clones.sol";
      import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
      import "./mixins/Constants.sol";
      /**
       * @notice Deploys contracts which auto-forwards any ETH sent to it to a list of recipients
       * considering their percent share of the payment received.
       * @dev Uses create2 counterfactual addresses so that the destination is known from the terms of the split.
       */
      contract PercentSplit is Constants, Initializable {
        using AddressUpgradeable for address payable;
        using AddressUpgradeable for address;
        using SafeMathUpgradeable for uint256;
        struct Share {
          address payable recipient;
          uint256 percentInBasisPoints;
        }
        Share[] private _shares;
        event PercentSplitCreated(address indexed contractAddress);
        event PercentSplitShare(address indexed recipient, uint256 percentInBasisPoints);
        event ETHTransferred(address indexed account, uint256 amount);
        event ERC20Transferred(address indexed erc20Contract, address indexed account, uint256 amount);
        /**
         * @dev Requires that the msg.sender is one of the recipients in this split.
         */
        modifier onlyRecipient() {
          for (uint256 i = 0; i < _shares.length; i++) {
            if (_shares[i].recipient == msg.sender) {
              _;
              return;
            }
          }
          revert("Split: Can only be called by one of the recipients");
        }
        /**
         * @notice Creates a new minimal proxy contract and initializes it with the given split terms.
         * If the contract had already been created, its address is returned.
         * This must be called on the original implementation and not a proxy created previously.
         */
        function createSplit(Share[] memory shares) public returns (PercentSplit splitInstance) {
          bytes32 salt = keccak256(abi.encode(shares));
          address clone = Clones.predictDeterministicAddress(address(this), salt);
          splitInstance = PercentSplit(payable(clone));
          if (!clone.isContract()) {
            emit PercentSplitCreated(clone);
            Clones.cloneDeterministic(address(this), salt);
            splitInstance.initialize(shares);
          }
        }
        /**
         * @notice Returns the address for the proxy contract which would represent the given split terms.
         * @dev The contract may or may not already be deployed at the address returned.
         * Ensure that it is deployed before sending funds to this address.
         */
        function getPredictedSplitAddress(Share[] memory shares) public view returns (address) {
          bytes32 salt = keccak256(abi.encode(shares));
          return Clones.predictDeterministicAddress(address(this), salt);
        }
        /**
         * @notice Called once to configure the contract after the initial deployment.
         * @dev This will be called by `createSplit` after deploying the proxy so it should never be called directly.
         */
        function initialize(Share[] memory shares) public initializer {
          require(shares.length >= 2, "Split: Too few recipients");
          require(shares.length <= 5, "Split: Too many recipients");
          uint256 total;
          for (uint256 i = 0; i < shares.length; i++) {
            total = total.add(shares[i].percentInBasisPoints);
            _shares.push(shares[i]);
            emit PercentSplitShare(shares[i].recipient, shares[i].percentInBasisPoints);
          }
          require(total == BASIS_POINTS, "Split: Total amount must equal 100%");
        }
        /**
         * @notice Returns a tuple with the terms of this split.
         */
        function getShares() public view returns (Share[] memory) {
          return _shares;
        }
        /**
         * @notice Returns how many recipients are part of this split.
         */
        function getShareLength() public view returns (uint256) {
          return _shares.length;
        }
        /**
         * @notice Returns a recipient in this split.
         */
        function getShareRecipientByIndex(uint256 index) public view returns (address payable) {
          return _shares[index].recipient;
        }
        /**
         * @notice Returns a recipient's percent share in basis points.
         */
        function getPercentInBasisPointsByIndex(uint256 index) public view returns (uint256) {
          return _shares[index].percentInBasisPoints;
        }
        /**
         * @notice Forwards any ETH received to the recipients in this split.
         * @dev Each recipient increases the gas required to split
         * and contract recipients may significantly increase the gas required.
         */
        receive() external payable {
          _splitETH(msg.value);
        }
        /**
         * @notice Allows any ETH stored by the contract to be split among recipients.
         */
        function splitETH() public {
          _splitETH(address(this).balance);
        }
        function _splitETH(uint256 value) internal {
          if (value > 0) {
            uint256 totalSent;
            uint256 amountToSend;
            for (uint256 i = _shares.length - 1; i > 0; i--) {
              Share memory share = _shares[i];
              amountToSend = (value * share.percentInBasisPoints) / BASIS_POINTS;
              totalSent += amountToSend;
              share.recipient.sendValue(amountToSend);
              emit ETHTransferred(share.recipient, amountToSend);
            }
            // Favor the 1st recipient if there are any rounding issues
            amountToSend = value - totalSent;
            _shares[0].recipient.sendValue(amountToSend);
            emit ETHTransferred(_shares[0].recipient, amountToSend);
          }
        }
        /**
         * @notice Anyone can call this function to split all available tokens at the provided address between the recipients.
         */
        function splitERC20Tokens(IERC20 erc20Contract) public {
          require(_splitERC20Tokens(erc20Contract), "Split: ERC20 split failed");
        }
        /**
         * @dev Anyone can call this function to split all available tokens at the provided address between the recipients.
         * Returns false on fail instead of reverting.
         */
        function _splitERC20Tokens(IERC20 erc20Contract) internal returns (bool) {
          try erc20Contract.balanceOf(address(this)) returns (uint256 balance) {
            if (balance == 0) {
              return false;
            }
            uint256 amountToSend;
            uint256 totalSent;
            for (uint256 i = _shares.length - 1; i > 0; i--) {
              Share memory share = _shares[i];
              bool success;
              (success, amountToSend) = balance.tryMul(share.percentInBasisPoints);
              if (!success) {
                return false;
              }
              amountToSend /= BASIS_POINTS;
              totalSent += amountToSend;
              try erc20Contract.transfer(share.recipient, amountToSend) {
                emit ERC20Transferred(address(erc20Contract), share.recipient, amountToSend);
              } catch {
                return false;
              }
            }
            // Favor the 1st recipient if there are any rounding issues
            amountToSend = balance - totalSent;
            try erc20Contract.transfer(_shares[0].recipient, amountToSend) {
              emit ERC20Transferred(address(erc20Contract), _shares[0].recipient, amountToSend);
            } catch {
              return false;
            }
            return true;
          } catch {
            return false;
          }
        }
        /**
         * @notice Allows the split recipients to make an arbitrary contract call.
         * @dev This is provided to allow recovering from unexpected scenarios,
         * such as receiving an NFT at this address.
         * It will first attempt a fair split of ERC20 tokens before proceeding.
         */
        function proxyCall(address payable target, bytes memory callData) public onlyRecipient {
          _splitERC20Tokens(IERC20(target));
          target.functionCall(callData);
        }
      }
      // SPDX-License-Identifier: MIT
      // solhint-disable-next-line compiler-version
      pragma solidity >=0.4.24 <0.8.0;
      import "../utils/AddressUpgradeable.sol";
      /**
       * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
       * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an
       * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
       * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
       *
       * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
       * possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}.
       *
       * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
       * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
       */
      abstract contract Initializable {
          /**
           * @dev Indicates that the contract has been initialized.
           */
          bool private _initialized;
          /**
           * @dev Indicates that the contract is in the process of being initialized.
           */
          bool private _initializing;
          /**
           * @dev Modifier to protect an initializer function from being invoked twice.
           */
          modifier initializer() {
              require(_initializing || _isConstructor() || !_initialized, "Initializable: contract is already initialized");
              bool isTopLevelCall = !_initializing;
              if (isTopLevelCall) {
                  _initializing = true;
                  _initialized = true;
              }
              _;
              if (isTopLevelCall) {
                  _initializing = false;
              }
          }
          /// @dev Returns true if and only if the function is running in the constructor
          function _isConstructor() private view returns (bool) {
              return !AddressUpgradeable.isContract(address(this));
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.7.0;
      /**
       * @dev Collection of functions related to the address type
       */
      library AddressUpgradeable {
          /**
           * @dev Returns true if `account` is a contract.
           *
           * [IMPORTANT]
           * ====
           * It is unsafe to assume that an address for which this function returns
           * false is an externally-owned account (EOA) and not a contract.
           *
           * Among others, `isContract` will return false for the following
           * types of addresses:
           *
           *  - an externally-owned account
           *  - a contract in construction
           *  - an address where a contract will be created
           *  - an address where a contract lived, but was destroyed
           * ====
           */
          function isContract(address account) internal view returns (bool) {
              // This method relies on extcodesize, which returns 0 for contracts in
              // construction, since the code is only stored at the end of the
              // constructor execution.
              uint256 size;
              // solhint-disable-next-line no-inline-assembly
              assembly { size := extcodesize(account) }
              return size > 0;
          }
          /**
           * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
           * `recipient`, forwarding all available gas and reverting on errors.
           *
           * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
           * of certain opcodes, possibly making contracts go over the 2300 gas limit
           * imposed by `transfer`, making them unable to receive funds via
           * `transfer`. {sendValue} removes this limitation.
           *
           * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
           *
           * IMPORTANT: because control is transferred to `recipient`, care must be
           * taken to not create reentrancy vulnerabilities. Consider using
           * {ReentrancyGuard} or the
           * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
           */
          function sendValue(address payable recipient, uint256 amount) internal {
              require(address(this).balance >= amount, "Address: insufficient balance");
              // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
              (bool success, ) = recipient.call{ value: amount }("");
              require(success, "Address: unable to send value, recipient may have reverted");
          }
          /**
           * @dev Performs a Solidity function call using a low level `call`. A
           * plain`call` is an unsafe replacement for a function call: use this
           * function instead.
           *
           * If `target` reverts with a revert reason, it is bubbled up by this
           * function (like regular Solidity function calls).
           *
           * Returns the raw returned data. To convert to the expected return value,
           * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
           *
           * Requirements:
           *
           * - `target` must be a contract.
           * - calling `target` with `data` must not revert.
           *
           * _Available since v3.1._
           */
          function functionCall(address target, bytes memory data) internal returns (bytes memory) {
            return functionCall(target, data, "Address: low-level call failed");
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
           * `errorMessage` as a fallback revert reason when `target` reverts.
           *
           * _Available since v3.1._
           */
          function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
              return functionCallWithValue(target, data, 0, errorMessage);
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
           * but also transferring `value` wei to `target`.
           *
           * Requirements:
           *
           * - the calling contract must have an ETH balance of at least `value`.
           * - the called Solidity function must be `payable`.
           *
           * _Available since v3.1._
           */
          function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
              return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
          }
          /**
           * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
           * with `errorMessage` as a fallback revert reason when `target` reverts.
           *
           * _Available since v3.1._
           */
          function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
              require(address(this).balance >= value, "Address: insufficient balance for call");
              require(isContract(target), "Address: call to non-contract");
              // solhint-disable-next-line avoid-low-level-calls
              (bool success, bytes memory returndata) = target.call{ value: value }(data);
              return _verifyCallResult(success, returndata, errorMessage);
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
           * but performing a static call.
           *
           * _Available since v3.3._
           */
          function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
              return functionStaticCall(target, data, "Address: low-level static call failed");
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
           * but performing a static call.
           *
           * _Available since v3.3._
           */
          function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
              require(isContract(target), "Address: static call to non-contract");
              // solhint-disable-next-line avoid-low-level-calls
              (bool success, bytes memory returndata) = target.staticcall(data);
              return _verifyCallResult(success, returndata, errorMessage);
          }
          function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
              if (success) {
                  return returndata;
              } else {
                  // Look for revert reason and bubble it up if present
                  if (returndata.length > 0) {
                      // The easiest way to bubble the revert reason is using memory via assembly
                      // solhint-disable-next-line no-inline-assembly
                      assembly {
                          let returndata_size := mload(returndata)
                          revert(add(32, returndata), returndata_size)
                      }
                  } else {
                      revert(errorMessage);
                  }
              }
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.7.0;
      /**
       * @dev Wrappers over Solidity's arithmetic operations with added overflow
       * checks.
       *
       * Arithmetic operations in Solidity wrap on overflow. This can easily result
       * in bugs, because programmers usually assume that an overflow raises an
       * error, which is the standard behavior in high level programming languages.
       * `SafeMath` restores this intuition by reverting the transaction when an
       * operation overflows.
       *
       * Using this library instead of the unchecked operations eliminates an entire
       * class of bugs, so it's recommended to use it always.
       */
      library SafeMathUpgradeable {
          /**
           * @dev Returns the addition of two unsigned integers, with an overflow flag.
           *
           * _Available since v3.4._
           */
          function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
              uint256 c = a + b;
              if (c < a) return (false, 0);
              return (true, c);
          }
          /**
           * @dev Returns the substraction of two unsigned integers, with an overflow flag.
           *
           * _Available since v3.4._
           */
          function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
              if (b > a) return (false, 0);
              return (true, a - b);
          }
          /**
           * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
           *
           * _Available since v3.4._
           */
          function tryMul(uint256 a, uint256 b) internal pure returns (bool, 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-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.
           *
           * _Available since v3.4._
           */
          function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
              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.
           *
           * _Available since v3.4._
           */
          function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
              if (b == 0) return (false, 0);
              return (true, a % b);
          }
          /**
           * @dev Returns the addition of two unsigned integers, reverting on
           * overflow.
           *
           * Counterpart to Solidity's `+` operator.
           *
           * Requirements:
           *
           * - Addition cannot overflow.
           */
          function add(uint256 a, uint256 b) internal pure returns (uint256) {
              uint256 c = a + b;
              require(c >= a, "SafeMath: addition overflow");
              return c;
          }
          /**
           * @dev Returns the subtraction of two unsigned integers, reverting on
           * overflow (when the result is negative).
           *
           * Counterpart to Solidity's `-` operator.
           *
           * Requirements:
           *
           * - Subtraction cannot overflow.
           */
          function sub(uint256 a, uint256 b) internal pure returns (uint256) {
              require(b <= a, "SafeMath: subtraction overflow");
              return a - b;
          }
          /**
           * @dev Returns the multiplication of two unsigned integers, reverting on
           * overflow.
           *
           * Counterpart to Solidity's `*` operator.
           *
           * Requirements:
           *
           * - Multiplication cannot overflow.
           */
          function mul(uint256 a, uint256 b) internal pure returns (uint256) {
              if (a == 0) return 0;
              uint256 c = a * b;
              require(c / a == b, "SafeMath: multiplication overflow");
              return c;
          }
          /**
           * @dev Returns the integer division of two unsigned integers, reverting on
           * division by zero. The result is rounded towards zero.
           *
           * Counterpart to Solidity's `/` operator. Note: this function uses a
           * `revert` opcode (which leaves remaining gas untouched) while Solidity
           * uses an invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           *
           * - The divisor cannot be zero.
           */
          function div(uint256 a, uint256 b) internal pure returns (uint256) {
              require(b > 0, "SafeMath: division by zero");
              return a / b;
          }
          /**
           * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
           * reverting when dividing by zero.
           *
           * Counterpart to Solidity's `%` operator. This function uses a `revert`
           * opcode (which leaves remaining gas untouched) while Solidity uses an
           * invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           *
           * - The divisor cannot be zero.
           */
          function mod(uint256 a, uint256 b) internal pure returns (uint256) {
              require(b > 0, "SafeMath: modulo by zero");
              return a % b;
          }
          /**
           * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
           * overflow (when the result is negative).
           *
           * CAUTION: This function is deprecated because it requires allocating memory for the error
           * message unnecessarily. For custom revert reasons use {trySub}.
           *
           * Counterpart to Solidity's `-` operator.
           *
           * Requirements:
           *
           * - Subtraction cannot overflow.
           */
          function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
              require(b <= a, errorMessage);
              return a - b;
          }
          /**
           * @dev Returns the integer division of two unsigned integers, reverting with custom message on
           * division by zero. The result is rounded towards zero.
           *
           * CAUTION: This function is deprecated because it requires allocating memory for the error
           * message unnecessarily. For custom revert reasons use {tryDiv}.
           *
           * Counterpart to Solidity's `/` operator. Note: this function uses a
           * `revert` opcode (which leaves remaining gas untouched) while Solidity
           * uses an invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           *
           * - The divisor cannot be zero.
           */
          function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
              require(b > 0, errorMessage);
              return a / b;
          }
          /**
           * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
           * reverting with custom message when dividing by zero.
           *
           * CAUTION: This function is deprecated because it requires allocating memory for the error
           * message unnecessarily. For custom revert reasons use {tryMod}.
           *
           * Counterpart to Solidity's `%` operator. This function uses a `revert`
           * opcode (which leaves remaining gas untouched) while Solidity uses an
           * invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           *
           * - The divisor cannot be zero.
           */
          function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
              require(b > 0, errorMessage);
              return a % b;
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity >=0.6.0 <0.8.0;
      /**
       * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for
       * deploying minimal proxy contracts, also known as "clones".
       *
       * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
       * > a minimal bytecode implementation that delegates all calls to a known, fixed address.
       *
       * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
       * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
       * deterministic method.
       *
       * _Available since v3.4._
       */
      library Clones {
          /**
           * @dev Deploys and returns the address of a clone that mimics the behaviour of `master`.
           *
           * This function uses the create opcode, which should never revert.
           */
          function clone(address master) internal returns (address instance) {
              // solhint-disable-next-line no-inline-assembly
              assembly {
                  let ptr := mload(0x40)
                  mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
                  mstore(add(ptr, 0x14), shl(0x60, master))
                  mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
                  instance := create(0, ptr, 0x37)
              }
              require(instance != address(0), "ERC1167: create failed");
          }
          /**
           * @dev Deploys and returns the address of a clone that mimics the behaviour of `master`.
           *
           * This function uses the create2 opcode and a `salt` to deterministically deploy
           * the clone. Using the same `master` and `salt` multiple time will revert, since
           * the clones cannot be deployed twice at the same address.
           */
          function cloneDeterministic(address master, bytes32 salt) internal returns (address instance) {
              // solhint-disable-next-line no-inline-assembly
              assembly {
                  let ptr := mload(0x40)
                  mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
                  mstore(add(ptr, 0x14), shl(0x60, master))
                  mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
                  instance := create2(0, ptr, 0x37, salt)
              }
              require(instance != address(0), "ERC1167: create2 failed");
          }
          /**
           * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
           */
          function predictDeterministicAddress(address master, bytes32 salt, address deployer) internal pure returns (address predicted) {
              // solhint-disable-next-line no-inline-assembly
              assembly {
                  let ptr := mload(0x40)
                  mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
                  mstore(add(ptr, 0x14), shl(0x60, master))
                  mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000)
                  mstore(add(ptr, 0x38), shl(0x60, deployer))
                  mstore(add(ptr, 0x4c), salt)
                  mstore(add(ptr, 0x6c), keccak256(ptr, 0x37))
                  predicted := keccak256(add(ptr, 0x37), 0x55)
              }
          }
          /**
           * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
           */
          function predictDeterministicAddress(address master, bytes32 salt) internal view returns (address predicted) {
              return predictDeterministicAddress(master, salt, address(this));
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.7.0;
      /**
       * @dev Interface of the ERC20 standard as defined in the EIP.
       */
      interface IERC20 {
          /**
           * @dev Returns the amount of tokens in existence.
           */
          function totalSupply() external view returns (uint256);
          /**
           * @dev Returns the amount of tokens owned by `account`.
           */
          function balanceOf(address account) external view returns (uint256);
          /**
           * @dev Moves `amount` tokens from the caller's account to `recipient`.
           *
           * Returns a boolean value indicating whether the operation succeeded.
           *
           * Emits a {Transfer} event.
           */
          function transfer(address recipient, uint256 amount) external returns (bool);
          /**
           * @dev Returns the remaining number of tokens that `spender` will be
           * allowed to spend on behalf of `owner` through {transferFrom}. This is
           * zero by default.
           *
           * This value changes when {approve} or {transferFrom} are called.
           */
          function allowance(address owner, address spender) external view returns (uint256);
          /**
           * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
           *
           * Returns a boolean value indicating whether the operation succeeded.
           *
           * IMPORTANT: Beware that changing an allowance with this method brings the risk
           * that someone may use both the old and the new allowance by unfortunate
           * transaction ordering. One possible solution to mitigate this race
           * condition is to first reduce the spender's allowance to 0 and set the
           * desired value afterwards:
           * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
           *
           * Emits an {Approval} event.
           */
          function approve(address spender, uint256 amount) external returns (bool);
          /**
           * @dev Moves `amount` tokens from `sender` to `recipient` using the
           * allowance mechanism. `amount` is then deducted from the caller's
           * allowance.
           *
           * Returns a boolean value indicating whether the operation succeeded.
           *
           * Emits a {Transfer} event.
           */
          function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
          /**
           * @dev Emitted when `value` tokens are moved from one account (`from`) to
           * another (`to`).
           *
           * Note that `value` may be zero.
           */
          event Transfer(address indexed from, address indexed to, uint256 value);
          /**
           * @dev Emitted when the allowance of a `spender` for an `owner` is set by
           * a call to {approve}. `value` is the new allowance.
           */
          event Approval(address indexed owner, address indexed spender, uint256 value);
      }
      // SPDX-License-Identifier: MIT OR Apache-2.0
      pragma solidity ^0.7.0;
      /**
       * @dev Constant values shared across mixins.
       */
      abstract contract Constants {
        uint256 internal constant BASIS_POINTS = 10000;
      }
      

      File 2 of 2: PercentSplit
      /*
        ・
         * ★
            ・ 。
               ・ ゚☆ 。
            * ★ ゚・。 *  。
                  * ☆ 。・゚*.。
               ゚ *.。☆。★ ・
      ​
                            `                     .-:::::-.`              `-::---...```
                           `-:`               .:+ssssoooo++//:.`       .-/+shhhhhhhhhhhhhyyyssooo:
                          .--::.            .+ossso+/////++/:://-`   .////+shhhhhhhhhhhhhhhhhhhhhy
                        `-----::.         `/+////+++///+++/:--:/+/-  -////+shhhhhhhhhhhhhhhhhhhhhy
                       `------:::-`      `//-.``.-/+ooosso+:-.-/oso- -////+shhhhhhhhhhhhhhhhhhhhhy
                      .--------:::-`     :+:.`  .-/osyyyyyyso++syhyo.-////+shhhhhhhhhhhhhhhhhhhhhy
                    `-----------:::-.    +o+:-.-:/oyhhhhhhdhhhhhdddy:-////+shhhhhhhhhhhhhhhhhhhhhy
                   .------------::::--  `oys+/::/+shhhhhhhdddddddddy/-////+shhhhhhhhhhhhhhhhhhhhhy
                  .--------------:::::-` +ys+////+yhhhhhhhddddddddhy:-////+yhhhhhhhhhhhhhhhhhhhhhy
                `----------------::::::-`.ss+/:::+oyhhhhhhhhhhhhhhho`-////+shhhhhhhhhhhhhhhhhhhhhy
               .------------------:::::::.-so//::/+osyyyhhhhhhhhhys` -////+shhhhhhhhhhhhhhhhhhhhhy
             `.-------------------::/:::::..+o+////+oosssyyyyyyys+`  .////+shhhhhhhhhhhhhhhhhhhhhy
             .--------------------::/:::.`   -+o++++++oooosssss/.     `-//+shhhhhhhhhhhhhhhhhhhhyo
           .-------   ``````.......--`        `-/+ooooosso+/-`          `./++++///:::--...``hhhhyo
                                                    `````
         * 
            ・ 。
          ・  ゚☆ 。
            * ★ ゚・。 *  。
                  * ☆ 。・゚*.。
               ゚ *.。☆。★ ・
          *  ゚。·*・。 ゚*
           ☆゚・。°*. ゚
        ・ ゚*。・゚★。
        ・ *゚。   *
       ・゚*。★・
       ☆∴。 *
      ・ 。
      */
      // SPDX-License-Identifier: MIT OR Apache-2.0
      pragma solidity ^0.7.0;
      pragma abicoder v2; // solhint-disable-line
      import "@openzeppelin/contracts-upgradeable/proxy/Initializable.sol";
      import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
      import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol";
      import "@openzeppelin/contracts/proxy/Clones.sol";
      import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
      import "./mixins/Constants.sol";
      /**
       * @notice Deploys contracts which auto-forwards any ETH sent to it to a list of recipients
       * considering their percent share of the payment received.
       * @dev Uses create2 counterfactual addresses so that the destination is known from the terms of the split.
       */
      contract PercentSplit is Constants, Initializable {
        using AddressUpgradeable for address payable;
        using AddressUpgradeable for address;
        using SafeMathUpgradeable for uint256;
        struct Share {
          address payable recipient;
          uint256 percentInBasisPoints;
        }
        Share[] private _shares;
        event PercentSplitCreated(address indexed contractAddress);
        event PercentSplitShare(address indexed recipient, uint256 percentInBasisPoints);
        event ETHTransferred(address indexed account, uint256 amount);
        event ERC20Transferred(address indexed erc20Contract, address indexed account, uint256 amount);
        /**
         * @dev Requires that the msg.sender is one of the recipients in this split.
         */
        modifier onlyRecipient() {
          for (uint256 i = 0; i < _shares.length; i++) {
            if (_shares[i].recipient == msg.sender) {
              _;
              return;
            }
          }
          revert("Split: Can only be called by one of the recipients");
        }
        /**
         * @notice Creates a new minimal proxy contract and initializes it with the given split terms.
         * If the contract had already been created, its address is returned.
         * This must be called on the original implementation and not a proxy created previously.
         */
        function createSplit(Share[] memory shares) public returns (PercentSplit splitInstance) {
          bytes32 salt = keccak256(abi.encode(shares));
          address clone = Clones.predictDeterministicAddress(address(this), salt);
          splitInstance = PercentSplit(payable(clone));
          if (!clone.isContract()) {
            emit PercentSplitCreated(clone);
            Clones.cloneDeterministic(address(this), salt);
            splitInstance.initialize(shares);
          }
        }
        /**
         * @notice Returns the address for the proxy contract which would represent the given split terms.
         * @dev The contract may or may not already be deployed at the address returned.
         * Ensure that it is deployed before sending funds to this address.
         */
        function getPredictedSplitAddress(Share[] memory shares) public view returns (address) {
          bytes32 salt = keccak256(abi.encode(shares));
          return Clones.predictDeterministicAddress(address(this), salt);
        }
        /**
         * @notice Called once to configure the contract after the initial deployment.
         * @dev This will be called by `createSplit` after deploying the proxy so it should never be called directly.
         */
        function initialize(Share[] memory shares) public initializer {
          require(shares.length >= 2, "Split: Too few recipients");
          require(shares.length <= 5, "Split: Too many recipients");
          uint256 total;
          for (uint256 i = 0; i < shares.length; i++) {
            total = total.add(shares[i].percentInBasisPoints);
            _shares.push(shares[i]);
            emit PercentSplitShare(shares[i].recipient, shares[i].percentInBasisPoints);
          }
          require(total == BASIS_POINTS, "Split: Total amount must equal 100%");
        }
        /**
         * @notice Returns a tuple with the terms of this split.
         */
        function getShares() public view returns (Share[] memory) {
          return _shares;
        }
        /**
         * @notice Returns how many recipients are part of this split.
         */
        function getShareLength() public view returns (uint256) {
          return _shares.length;
        }
        /**
         * @notice Returns a recipient in this split.
         */
        function getShareRecipientByIndex(uint256 index) public view returns (address payable) {
          return _shares[index].recipient;
        }
        /**
         * @notice Returns a recipient's percent share in basis points.
         */
        function getPercentInBasisPointsByIndex(uint256 index) public view returns (uint256) {
          return _shares[index].percentInBasisPoints;
        }
        /**
         * @notice Forwards any ETH received to the recipients in this split.
         * @dev Each recipient increases the gas required to split
         * and contract recipients may significantly increase the gas required.
         */
        receive() external payable {
          _splitETH(msg.value);
        }
        /**
         * @notice Allows any ETH stored by the contract to be split among recipients.
         */
        function splitETH() public {
          _splitETH(address(this).balance);
        }
        function _splitETH(uint256 value) internal {
          if (value > 0) {
            uint256 totalSent;
            uint256 amountToSend;
            for (uint256 i = _shares.length - 1; i > 0; i--) {
              Share memory share = _shares[i];
              amountToSend = (value * share.percentInBasisPoints) / BASIS_POINTS;
              totalSent += amountToSend;
              share.recipient.sendValue(amountToSend);
              emit ETHTransferred(share.recipient, amountToSend);
            }
            // Favor the 1st recipient if there are any rounding issues
            amountToSend = value - totalSent;
            _shares[0].recipient.sendValue(amountToSend);
            emit ETHTransferred(_shares[0].recipient, amountToSend);
          }
        }
        /**
         * @notice Anyone can call this function to split all available tokens at the provided address between the recipients.
         */
        function splitERC20Tokens(IERC20 erc20Contract) public {
          require(_splitERC20Tokens(erc20Contract), "Split: ERC20 split failed");
        }
        /**
         * @dev Anyone can call this function to split all available tokens at the provided address between the recipients.
         * Returns false on fail instead of reverting.
         */
        function _splitERC20Tokens(IERC20 erc20Contract) internal returns (bool) {
          try erc20Contract.balanceOf(address(this)) returns (uint256 balance) {
            if (balance == 0) {
              return false;
            }
            uint256 amountToSend;
            uint256 totalSent;
            for (uint256 i = _shares.length - 1; i > 0; i--) {
              Share memory share = _shares[i];
              bool success;
              (success, amountToSend) = balance.tryMul(share.percentInBasisPoints);
              if (!success) {
                return false;
              }
              amountToSend /= BASIS_POINTS;
              totalSent += amountToSend;
              try erc20Contract.transfer(share.recipient, amountToSend) {
                emit ERC20Transferred(address(erc20Contract), share.recipient, amountToSend);
              } catch {
                return false;
              }
            }
            // Favor the 1st recipient if there are any rounding issues
            amountToSend = balance - totalSent;
            try erc20Contract.transfer(_shares[0].recipient, amountToSend) {
              emit ERC20Transferred(address(erc20Contract), _shares[0].recipient, amountToSend);
            } catch {
              return false;
            }
            return true;
          } catch {
            return false;
          }
        }
        /**
         * @notice Allows the split recipients to make an arbitrary contract call.
         * @dev This is provided to allow recovering from unexpected scenarios,
         * such as receiving an NFT at this address.
         * It will first attempt a fair split of ERC20 tokens before proceeding.
         */
        function proxyCall(address payable target, bytes memory callData) public onlyRecipient {
          _splitERC20Tokens(IERC20(target));
          target.functionCall(callData);
        }
      }
      // SPDX-License-Identifier: MIT
      // solhint-disable-next-line compiler-version
      pragma solidity >=0.4.24 <0.8.0;
      import "../utils/AddressUpgradeable.sol";
      /**
       * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
       * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an
       * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
       * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
       *
       * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
       * possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}.
       *
       * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
       * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
       */
      abstract contract Initializable {
          /**
           * @dev Indicates that the contract has been initialized.
           */
          bool private _initialized;
          /**
           * @dev Indicates that the contract is in the process of being initialized.
           */
          bool private _initializing;
          /**
           * @dev Modifier to protect an initializer function from being invoked twice.
           */
          modifier initializer() {
              require(_initializing || _isConstructor() || !_initialized, "Initializable: contract is already initialized");
              bool isTopLevelCall = !_initializing;
              if (isTopLevelCall) {
                  _initializing = true;
                  _initialized = true;
              }
              _;
              if (isTopLevelCall) {
                  _initializing = false;
              }
          }
          /// @dev Returns true if and only if the function is running in the constructor
          function _isConstructor() private view returns (bool) {
              return !AddressUpgradeable.isContract(address(this));
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.7.0;
      /**
       * @dev Collection of functions related to the address type
       */
      library AddressUpgradeable {
          /**
           * @dev Returns true if `account` is a contract.
           *
           * [IMPORTANT]
           * ====
           * It is unsafe to assume that an address for which this function returns
           * false is an externally-owned account (EOA) and not a contract.
           *
           * Among others, `isContract` will return false for the following
           * types of addresses:
           *
           *  - an externally-owned account
           *  - a contract in construction
           *  - an address where a contract will be created
           *  - an address where a contract lived, but was destroyed
           * ====
           */
          function isContract(address account) internal view returns (bool) {
              // This method relies on extcodesize, which returns 0 for contracts in
              // construction, since the code is only stored at the end of the
              // constructor execution.
              uint256 size;
              // solhint-disable-next-line no-inline-assembly
              assembly { size := extcodesize(account) }
              return size > 0;
          }
          /**
           * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
           * `recipient`, forwarding all available gas and reverting on errors.
           *
           * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
           * of certain opcodes, possibly making contracts go over the 2300 gas limit
           * imposed by `transfer`, making them unable to receive funds via
           * `transfer`. {sendValue} removes this limitation.
           *
           * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
           *
           * IMPORTANT: because control is transferred to `recipient`, care must be
           * taken to not create reentrancy vulnerabilities. Consider using
           * {ReentrancyGuard} or the
           * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
           */
          function sendValue(address payable recipient, uint256 amount) internal {
              require(address(this).balance >= amount, "Address: insufficient balance");
              // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
              (bool success, ) = recipient.call{ value: amount }("");
              require(success, "Address: unable to send value, recipient may have reverted");
          }
          /**
           * @dev Performs a Solidity function call using a low level `call`. A
           * plain`call` is an unsafe replacement for a function call: use this
           * function instead.
           *
           * If `target` reverts with a revert reason, it is bubbled up by this
           * function (like regular Solidity function calls).
           *
           * Returns the raw returned data. To convert to the expected return value,
           * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
           *
           * Requirements:
           *
           * - `target` must be a contract.
           * - calling `target` with `data` must not revert.
           *
           * _Available since v3.1._
           */
          function functionCall(address target, bytes memory data) internal returns (bytes memory) {
            return functionCall(target, data, "Address: low-level call failed");
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
           * `errorMessage` as a fallback revert reason when `target` reverts.
           *
           * _Available since v3.1._
           */
          function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
              return functionCallWithValue(target, data, 0, errorMessage);
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
           * but also transferring `value` wei to `target`.
           *
           * Requirements:
           *
           * - the calling contract must have an ETH balance of at least `value`.
           * - the called Solidity function must be `payable`.
           *
           * _Available since v3.1._
           */
          function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
              return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
          }
          /**
           * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
           * with `errorMessage` as a fallback revert reason when `target` reverts.
           *
           * _Available since v3.1._
           */
          function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
              require(address(this).balance >= value, "Address: insufficient balance for call");
              require(isContract(target), "Address: call to non-contract");
              // solhint-disable-next-line avoid-low-level-calls
              (bool success, bytes memory returndata) = target.call{ value: value }(data);
              return _verifyCallResult(success, returndata, errorMessage);
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
           * but performing a static call.
           *
           * _Available since v3.3._
           */
          function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
              return functionStaticCall(target, data, "Address: low-level static call failed");
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
           * but performing a static call.
           *
           * _Available since v3.3._
           */
          function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
              require(isContract(target), "Address: static call to non-contract");
              // solhint-disable-next-line avoid-low-level-calls
              (bool success, bytes memory returndata) = target.staticcall(data);
              return _verifyCallResult(success, returndata, errorMessage);
          }
          function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
              if (success) {
                  return returndata;
              } else {
                  // Look for revert reason and bubble it up if present
                  if (returndata.length > 0) {
                      // The easiest way to bubble the revert reason is using memory via assembly
                      // solhint-disable-next-line no-inline-assembly
                      assembly {
                          let returndata_size := mload(returndata)
                          revert(add(32, returndata), returndata_size)
                      }
                  } else {
                      revert(errorMessage);
                  }
              }
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.7.0;
      /**
       * @dev Wrappers over Solidity's arithmetic operations with added overflow
       * checks.
       *
       * Arithmetic operations in Solidity wrap on overflow. This can easily result
       * in bugs, because programmers usually assume that an overflow raises an
       * error, which is the standard behavior in high level programming languages.
       * `SafeMath` restores this intuition by reverting the transaction when an
       * operation overflows.
       *
       * Using this library instead of the unchecked operations eliminates an entire
       * class of bugs, so it's recommended to use it always.
       */
      library SafeMathUpgradeable {
          /**
           * @dev Returns the addition of two unsigned integers, with an overflow flag.
           *
           * _Available since v3.4._
           */
          function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
              uint256 c = a + b;
              if (c < a) return (false, 0);
              return (true, c);
          }
          /**
           * @dev Returns the substraction of two unsigned integers, with an overflow flag.
           *
           * _Available since v3.4._
           */
          function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
              if (b > a) return (false, 0);
              return (true, a - b);
          }
          /**
           * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
           *
           * _Available since v3.4._
           */
          function tryMul(uint256 a, uint256 b) internal pure returns (bool, 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-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.
           *
           * _Available since v3.4._
           */
          function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
              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.
           *
           * _Available since v3.4._
           */
          function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
              if (b == 0) return (false, 0);
              return (true, a % b);
          }
          /**
           * @dev Returns the addition of two unsigned integers, reverting on
           * overflow.
           *
           * Counterpart to Solidity's `+` operator.
           *
           * Requirements:
           *
           * - Addition cannot overflow.
           */
          function add(uint256 a, uint256 b) internal pure returns (uint256) {
              uint256 c = a + b;
              require(c >= a, "SafeMath: addition overflow");
              return c;
          }
          /**
           * @dev Returns the subtraction of two unsigned integers, reverting on
           * overflow (when the result is negative).
           *
           * Counterpart to Solidity's `-` operator.
           *
           * Requirements:
           *
           * - Subtraction cannot overflow.
           */
          function sub(uint256 a, uint256 b) internal pure returns (uint256) {
              require(b <= a, "SafeMath: subtraction overflow");
              return a - b;
          }
          /**
           * @dev Returns the multiplication of two unsigned integers, reverting on
           * overflow.
           *
           * Counterpart to Solidity's `*` operator.
           *
           * Requirements:
           *
           * - Multiplication cannot overflow.
           */
          function mul(uint256 a, uint256 b) internal pure returns (uint256) {
              if (a == 0) return 0;
              uint256 c = a * b;
              require(c / a == b, "SafeMath: multiplication overflow");
              return c;
          }
          /**
           * @dev Returns the integer division of two unsigned integers, reverting on
           * division by zero. The result is rounded towards zero.
           *
           * Counterpart to Solidity's `/` operator. Note: this function uses a
           * `revert` opcode (which leaves remaining gas untouched) while Solidity
           * uses an invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           *
           * - The divisor cannot be zero.
           */
          function div(uint256 a, uint256 b) internal pure returns (uint256) {
              require(b > 0, "SafeMath: division by zero");
              return a / b;
          }
          /**
           * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
           * reverting when dividing by zero.
           *
           * Counterpart to Solidity's `%` operator. This function uses a `revert`
           * opcode (which leaves remaining gas untouched) while Solidity uses an
           * invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           *
           * - The divisor cannot be zero.
           */
          function mod(uint256 a, uint256 b) internal pure returns (uint256) {
              require(b > 0, "SafeMath: modulo by zero");
              return a % b;
          }
          /**
           * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
           * overflow (when the result is negative).
           *
           * CAUTION: This function is deprecated because it requires allocating memory for the error
           * message unnecessarily. For custom revert reasons use {trySub}.
           *
           * Counterpart to Solidity's `-` operator.
           *
           * Requirements:
           *
           * - Subtraction cannot overflow.
           */
          function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
              require(b <= a, errorMessage);
              return a - b;
          }
          /**
           * @dev Returns the integer division of two unsigned integers, reverting with custom message on
           * division by zero. The result is rounded towards zero.
           *
           * CAUTION: This function is deprecated because it requires allocating memory for the error
           * message unnecessarily. For custom revert reasons use {tryDiv}.
           *
           * Counterpart to Solidity's `/` operator. Note: this function uses a
           * `revert` opcode (which leaves remaining gas untouched) while Solidity
           * uses an invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           *
           * - The divisor cannot be zero.
           */
          function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
              require(b > 0, errorMessage);
              return a / b;
          }
          /**
           * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
           * reverting with custom message when dividing by zero.
           *
           * CAUTION: This function is deprecated because it requires allocating memory for the error
           * message unnecessarily. For custom revert reasons use {tryMod}.
           *
           * Counterpart to Solidity's `%` operator. This function uses a `revert`
           * opcode (which leaves remaining gas untouched) while Solidity uses an
           * invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           *
           * - The divisor cannot be zero.
           */
          function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
              require(b > 0, errorMessage);
              return a % b;
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity >=0.6.0 <0.8.0;
      /**
       * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for
       * deploying minimal proxy contracts, also known as "clones".
       *
       * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
       * > a minimal bytecode implementation that delegates all calls to a known, fixed address.
       *
       * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
       * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
       * deterministic method.
       *
       * _Available since v3.4._
       */
      library Clones {
          /**
           * @dev Deploys and returns the address of a clone that mimics the behaviour of `master`.
           *
           * This function uses the create opcode, which should never revert.
           */
          function clone(address master) internal returns (address instance) {
              // solhint-disable-next-line no-inline-assembly
              assembly {
                  let ptr := mload(0x40)
                  mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
                  mstore(add(ptr, 0x14), shl(0x60, master))
                  mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
                  instance := create(0, ptr, 0x37)
              }
              require(instance != address(0), "ERC1167: create failed");
          }
          /**
           * @dev Deploys and returns the address of a clone that mimics the behaviour of `master`.
           *
           * This function uses the create2 opcode and a `salt` to deterministically deploy
           * the clone. Using the same `master` and `salt` multiple time will revert, since
           * the clones cannot be deployed twice at the same address.
           */
          function cloneDeterministic(address master, bytes32 salt) internal returns (address instance) {
              // solhint-disable-next-line no-inline-assembly
              assembly {
                  let ptr := mload(0x40)
                  mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
                  mstore(add(ptr, 0x14), shl(0x60, master))
                  mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
                  instance := create2(0, ptr, 0x37, salt)
              }
              require(instance != address(0), "ERC1167: create2 failed");
          }
          /**
           * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
           */
          function predictDeterministicAddress(address master, bytes32 salt, address deployer) internal pure returns (address predicted) {
              // solhint-disable-next-line no-inline-assembly
              assembly {
                  let ptr := mload(0x40)
                  mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
                  mstore(add(ptr, 0x14), shl(0x60, master))
                  mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000)
                  mstore(add(ptr, 0x38), shl(0x60, deployer))
                  mstore(add(ptr, 0x4c), salt)
                  mstore(add(ptr, 0x6c), keccak256(ptr, 0x37))
                  predicted := keccak256(add(ptr, 0x37), 0x55)
              }
          }
          /**
           * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
           */
          function predictDeterministicAddress(address master, bytes32 salt) internal view returns (address predicted) {
              return predictDeterministicAddress(master, salt, address(this));
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.7.0;
      /**
       * @dev Interface of the ERC20 standard as defined in the EIP.
       */
      interface IERC20 {
          /**
           * @dev Returns the amount of tokens in existence.
           */
          function totalSupply() external view returns (uint256);
          /**
           * @dev Returns the amount of tokens owned by `account`.
           */
          function balanceOf(address account) external view returns (uint256);
          /**
           * @dev Moves `amount` tokens from the caller's account to `recipient`.
           *
           * Returns a boolean value indicating whether the operation succeeded.
           *
           * Emits a {Transfer} event.
           */
          function transfer(address recipient, uint256 amount) external returns (bool);
          /**
           * @dev Returns the remaining number of tokens that `spender` will be
           * allowed to spend on behalf of `owner` through {transferFrom}. This is
           * zero by default.
           *
           * This value changes when {approve} or {transferFrom} are called.
           */
          function allowance(address owner, address spender) external view returns (uint256);
          /**
           * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
           *
           * Returns a boolean value indicating whether the operation succeeded.
           *
           * IMPORTANT: Beware that changing an allowance with this method brings the risk
           * that someone may use both the old and the new allowance by unfortunate
           * transaction ordering. One possible solution to mitigate this race
           * condition is to first reduce the spender's allowance to 0 and set the
           * desired value afterwards:
           * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
           *
           * Emits an {Approval} event.
           */
          function approve(address spender, uint256 amount) external returns (bool);
          /**
           * @dev Moves `amount` tokens from `sender` to `recipient` using the
           * allowance mechanism. `amount` is then deducted from the caller's
           * allowance.
           *
           * Returns a boolean value indicating whether the operation succeeded.
           *
           * Emits a {Transfer} event.
           */
          function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
          /**
           * @dev Emitted when `value` tokens are moved from one account (`from`) to
           * another (`to`).
           *
           * Note that `value` may be zero.
           */
          event Transfer(address indexed from, address indexed to, uint256 value);
          /**
           * @dev Emitted when the allowance of a `spender` for an `owner` is set by
           * a call to {approve}. `value` is the new allowance.
           */
          event Approval(address indexed owner, address indexed spender, uint256 value);
      }
      // SPDX-License-Identifier: MIT OR Apache-2.0
      pragma solidity ^0.7.0;
      /**
       * @dev Constant values shared across mixins.
       */
      abstract contract Constants {
        uint256 internal constant BASIS_POINTS = 10000;
      }