creation_sourcecode: // SPDX-License-Identifier: MIT
  pragma solidity =0.8.10;
  
  
  
  
  
  
  
  
  
  
  contract MainnetAuthAddresses {
      address internal constant ADMIN_VAULT_ADDR = 0xCCf3d848e08b94478Ed8f46fFead3008faF581fD;
      address internal constant DSGUARD_FACTORY_ADDRESS = 0x5a15566417e6C1c9546523066500bDDBc53F88C7;
      address internal constant ADMIN_ADDR = 0x25eFA336886C74eA8E282ac466BdCd0199f85BB9; // USED IN ADMIN VAULT CONSTRUCTOR
      address internal constant PROXY_AUTH_ADDRESS = 0x149667b6FAe2c63D1B4317C716b0D0e4d3E2bD70;
      address internal constant MODULE_AUTH_ADDRESS = 0x7407974DDBF539e552F1d051e44573090912CC3D;
  }
  
  
  
  
  
  
  
  contract AuthHelper is MainnetAuthAddresses {
  }
  
  
  
  
  
  
  
  
  contract AdminVault is AuthHelper {
      address public owner;
      address public admin;
  
      error SenderNotAdmin();
  
      constructor() {
          owner = msg.sender;
          admin = ADMIN_ADDR;
      }
  
      /// @notice Admin is able to change owner
      /// @param _owner Address of new owner
      function changeOwner(address _owner) public {
          if (admin != msg.sender){
              revert SenderNotAdmin();
          }
          owner = _owner;
      }
  
      /// @notice Admin is able to set new admin
      /// @param _admin Address of multisig that becomes new admin
      function changeAdmin(address _admin) public {
          if (admin != msg.sender){
              revert SenderNotAdmin();
          }
          admin = _admin;
      }
  
  }
  
  
  
  
  
  
  
  interface IERC20 {
      function name() external view returns (string memory);
      function symbol() external view returns (string memory);
      function decimals() external view returns (uint256 digits);
      function totalSupply() external view returns (uint256 supply);
  
      function balanceOf(address _owner) external view returns (uint256 balance);
  
      function transfer(address _to, uint256 _value) external returns (bool success);
  
      function transferFrom(
          address _from,
          address _to,
          uint256 _value
      ) external returns (bool success);
  
      function approve(address _spender, uint256 _value) external returns (bool success);
  
      function allowance(address _owner, address _spender) external view returns (uint256 remaining);
  
      event Approval(address indexed _owner, address indexed _spender, uint256 _value);
  }
  
  
  
  
  
  
  
  library Address {
      //insufficient balance
      error InsufficientBalance(uint256 available, uint256 required);
      //unable to send value, recipient may have reverted
      error SendingValueFail();
      //insufficient balance for call
      error InsufficientBalanceForCall(uint256 available, uint256 required);
      //call to non-contract
      error NonContractCall();
      
      function isContract(address account) internal view returns (bool) {
          // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
          // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
          // for accounts without code, i.e. `keccak256('')`
          bytes32 codehash;
          bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
          // solhint-disable-next-line no-inline-assembly
          assembly {
              codehash := extcodehash(account)
          }
          return (codehash != accountHash && codehash != 0x0);
      }
  
      function sendValue(address payable recipient, uint256 amount) internal {
          uint256 balance = address(this).balance;
          if (balance < amount){
              revert InsufficientBalance(balance, amount);
          }
  
          // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
          (bool success, ) = recipient.call{value: amount}("");
          if (!(success)){
              revert SendingValueFail();
          }
      }
  
      function functionCall(address target, bytes memory data) internal returns (bytes memory) {
          return functionCall(target, data, "Address: low-level call failed");
      }
  
      function functionCall(
          address target,
          bytes memory data,
          string memory errorMessage
      ) internal returns (bytes memory) {
          return _functionCallWithValue(target, data, 0, errorMessage);
      }
  
      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");
      }
  
      function functionCallWithValue(
          address target,
          bytes memory data,
          uint256 value,
          string memory errorMessage
      ) internal returns (bytes memory) {
          uint256 balance = address(this).balance;
          if (balance < value){
              revert InsufficientBalanceForCall(balance, value);
          }
          return _functionCallWithValue(target, data, value, errorMessage);
      }
  
      function _functionCallWithValue(
          address target,
          bytes memory data,
          uint256 weiValue,
          string memory errorMessage
      ) private returns (bytes memory) {
          if (!(isContract(target))){
              revert NonContractCall();
          }
  
          // solhint-disable-next-line avoid-low-level-calls
          (bool success, bytes memory returndata) = target.call{value: weiValue}(data);
          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);
              }
          }
      }
  }
  
  
  
  
  
  
  
  
  
  
  
  library SafeERC20 {
      using Address for address;
  
      /**
       * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
       * non-reverting calls are assumed to be successful.
       */
      function safeTransfer(IERC20 token, address to, uint256 value) internal {
          _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
      }
  
      /**
       * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
       * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
       */
      function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
          _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
      }
  
      /**
       * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
       * non-reverting calls are assumed to be successful. Compatible with tokens that require the approval to be set to
       * 0 before setting it to a non-zero value.
       */
      function safeApprove(IERC20 token, address spender, uint256 value) internal {
          bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
  
          if (!_callOptionalReturnBool(token, approvalCall)) {
              _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
              _callOptionalReturn(token, approvalCall);
          }
      }
  
      /**
       * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
       * on the return value: the return value is optional (but if data is returned, it must not be false).
       * @param token The token targeted by the call.
       * @param data The call data (encoded using abi.encode or one of its variants).
       */
      function _callOptionalReturn(IERC20 token, bytes memory data) private {
          // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
          // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
          // the target address contains contract code and also asserts for success in the low-level call.
  
          bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
          require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
      }
  
      /**
       * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
       * on the return value: the return value is optional (but if data is returned, it must not be false).
       * @param token The token targeted by the call.
       * @param data The call data (encoded using abi.encode or one of its variants).
       *
       * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
       */
      function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
          // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
          // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
          // and not revert is the subcall reverts.
  
          (bool success, bytes memory returndata) = address(token).call(data);
          return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
      }
  }
  
  
  
  
  
  
  
  
  
  
  contract AdminAuth is AuthHelper {
      using SafeERC20 for IERC20;
  
      AdminVault public constant adminVault = AdminVault(ADMIN_VAULT_ADDR);
  
      error SenderNotOwner();
      error SenderNotAdmin();
  
      modifier onlyOwner() {
          if (adminVault.owner() != msg.sender){
              revert SenderNotOwner();
          }
          _;
      }
  
      modifier onlyAdmin() {
          if (adminVault.admin() != msg.sender){
              revert SenderNotAdmin();
          }
          _;
      }
  
      /// @notice withdraw stuck funds
      function withdrawStuckFunds(address _token, address _receiver, uint256 _amount) public onlyOwner {
          if (_token == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) {
              payable(_receiver).transfer(_amount);
          } else {
              IERC20(_token).safeTransfer(_receiver, _amount);
          }
      }
  
      /// @notice Destroy the contract
      /// @dev Deprecated method, selfdestruct will soon just send eth
      function kill() public onlyAdmin {
          selfdestruct(payable(msg.sender));
      }
  }
  
  
  
  
  
  
  
  contract Discount is AdminAuth{
      mapping(address => bool) public serviceFeesDisabled;
  
      function reenableServiceFee(address _wallet) public onlyOwner{
          serviceFeesDisabled[_wallet] = false;
      }
  
      function disableServiceFee(address _wallet) public onlyOwner{
          serviceFeesDisabled[_wallet] = true;
      }
  }
  
  
  
  
  
  
  
  abstract contract IWETH {
      function allowance(address, address) public virtual view returns (uint256);
  
      function balanceOf(address) public virtual view returns (uint256);
  
      function approve(address, uint256) public virtual;
  
      function transfer(address, uint256) public virtual returns (bool);
  
      function transferFrom(
          address,
          address,
          uint256
      ) public virtual returns (bool);
  
      function deposit() public payable virtual;
  
      function withdraw(uint256) public virtual;
  }
  
  
  
  
  
  
  
  
  library TokenUtils {
      using SafeERC20 for IERC20;
  
      address public constant WETH_ADDR = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
      address public constant ETH_ADDR = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
  
      /// @dev Only approves the amount if allowance is lower than amount, does not decrease allowance
      function approveToken(
          address _tokenAddr,
          address _to,
          uint256 _amount
      ) internal {
          if (_tokenAddr == ETH_ADDR) return;
  
          if (IERC20(_tokenAddr).allowance(address(this), _to) < _amount) {
              IERC20(_tokenAddr).safeApprove(_to, _amount);
          }
      }
  
      function pullTokensIfNeeded(
          address _token,
          address _from,
          uint256 _amount
      ) internal returns (uint256) {
          // handle max uint amount
          if (_amount == type(uint256).max) {
              _amount = getBalance(_token, _from);
          }
  
          if (_from != address(0) && _from != address(this) && _token != ETH_ADDR && _amount != 0) {
              IERC20(_token).safeTransferFrom(_from, address(this), _amount);
          }
  
          return _amount;
      }
  
      function withdrawTokens(
          address _token,
          address _to,
          uint256 _amount
      ) internal returns (uint256) {
          if (_amount == type(uint256).max) {
              _amount = getBalance(_token, address(this));
          }
  
          if (_to != address(0) && _to != address(this) && _amount != 0) {
              if (_token != ETH_ADDR) {
                  IERC20(_token).safeTransfer(_to, _amount);
              } else {
                  (bool success, ) = _to.call{value: _amount}("");
                  require(success, "Eth send fail");
              }
          }
  
          return _amount;
      }
  
      function depositWeth(uint256 _amount) internal {
          IWETH(WETH_ADDR).deposit{value: _amount}();
      }
  
      function withdrawWeth(uint256 _amount) internal {
          IWETH(WETH_ADDR).withdraw(_amount);
      }
  
      function getBalance(address _tokenAddr, address _acc) internal view returns (uint256) {
          if (_tokenAddr == ETH_ADDR) {
              return _acc.balance;
          } else {
              return IERC20(_tokenAddr).balanceOf(_acc);
          }
      }
  
      function getTokenDecimals(address _token) internal view returns (uint256) {
          if (_token == ETH_ADDR) return 18;
  
          return IERC20(_token).decimals();
      }
  }
  
  
  
  
  
  
  
  
  contract DFSExchangeHelper {
      
      using TokenUtils for address;
      
      error InvalidOffchainData();
      error OutOfRangeSlicingError();
      //Order success but amount 0
      error ZeroTokensSwapped();
  
      using SafeERC20 for IERC20;
  
      function sendLeftover(
          address _srcAddr,
          address _destAddr,
          address payable _to
      ) internal {
          // clean out any eth leftover
          TokenUtils.ETH_ADDR.withdrawTokens(_to, type(uint256).max);
  
          _srcAddr.withdrawTokens(_to, type(uint256).max);
          _destAddr.withdrawTokens(_to, type(uint256).max);
      }
  
      function sliceUint(bytes memory bs, uint256 start) internal pure returns (uint256) {
          if (bs.length < start + 32){
              revert OutOfRangeSlicingError();
          }
  
          uint256 x;
          assembly {
              x := mload(add(bs, add(0x20, start)))
          }
  
          return x;
      }
  
      function writeUint256(
          bytes memory _b,
          uint256 _index,
          uint256 _input
      ) internal pure {
          if (_b.length < _index + 32) {
              revert InvalidOffchainData();
          }
  
          bytes32 input = bytes32(_input);
  
          _index += 32;
  
          // Read the bytes32 from array memory
          assembly {
              mstore(add(_b, _index), input)
          }
      }
  }
  
  
  
  
  
  
  
  contract MainnetWrapperAddresses {
  
      address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
      address internal constant KYBER_INTERFACE = 0x9AAb3f75489902f3a48495025729a0AF77d4b11e;
      address payable internal constant WALLET_ID = payable(0x322d58b9E75a6918f7e7849AEe0fF09369977e08);
      address internal constant UNI_V2_ROUTER = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D;
      address internal constant UNI_V3_ROUTER = 0xE592427A0AEce92De3Edee1F18E0157C05861564;
      address internal constant UNI_V3_QUOTER = 0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6;
      address internal constant CURVE_ADDRESS_PROVIDER = 0x0000000022D53366457F9d5E68Ec105046FC4383;
      address internal constant CURVE_ROUTER_NG = 0xF0d4c12A5768D806021F80a262B4d39d26C58b8D;
  }
  
  
  
  
  
  
  
  contract WrapperHelper is MainnetWrapperAddresses {
  }
  
  
  
  
  
  
  contract DSMath {
      function add(uint256 x, uint256 y) internal pure returns (uint256 z) {
          z = x + y;
      }
  
      function sub(uint256 x, uint256 y) internal pure returns (uint256 z) {
          z = x - y;
      }
  
      function mul(uint256 x, uint256 y) internal pure returns (uint256 z) {
          z = x * y;
      }
  
      function div(uint256 x, uint256 y) internal pure returns (uint256 z) {
          return x / y;
      }
  
      function min(uint256 x, uint256 y) internal pure returns (uint256 z) {
          return x <= y ? x : y;
      }
  
      function max(uint256 x, uint256 y) internal pure returns (uint256 z) {
          return x >= y ? x : y;
      }
  
      function imin(int256 x, int256 y) internal pure returns (int256 z) {
          return x <= y ? x : y;
      }
  
      function imax(int256 x, int256 y) internal pure returns (int256 z) {
          return x >= y ? x : y;
      }
  
      uint256 constant WAD = 10**18;
      uint256 constant RAY = 10**27;
  
      function wmul(uint256 x, uint256 y) internal pure returns (uint256 z) {
          z = add(mul(x, y), WAD / 2) / WAD;
      }
  
      function rmul(uint256 x, uint256 y) internal pure returns (uint256 z) {
          z = add(mul(x, y), RAY / 2) / RAY;
      }
  
      function wdiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
          z = add(mul(x, WAD), y / 2) / y;
      }
  
      function rdiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
          z = add(mul(x, RAY), y / 2) / y;
      }
  
      // This famous algorithm is called "exponentiation by squaring"
      // and calculates x^n with x as fixed-point and n as regular unsigned.
      //
      // It's O(log n), instead of O(n) for naive repeated multiplication.
      //
      // These facts are why it works:
      //
      //  If n is even, then x^n = (x^2)^(n/2).
      //  If n is odd,  then x^n = x * x^(n-1),
      //   and applying the equation for even x gives
      //    x^n = x * (x^2)^((n-1) / 2).
      //
      //  Also, EVM division is flooring and
      //    floor[(n-1) / 2] = floor[n / 2].
      //
      function rpow(uint256 x, uint256 n) internal pure returns (uint256 z) {
          z = n % 2 != 0 ? x : RAY;
  
          for (n /= 2; n != 0; n /= 2) {
              x = rmul(x, x);
  
              if (n % 2 != 0) {
                  z = rmul(z, x);
              }
          }
      }
  }
  
  
  
  
  
  
  
  interface IExchangeV3 {
      function sell(address _srcAddr, address _destAddr, uint _srcAmount, bytes memory _additionalData) external returns (uint);
      function getSellRate(address _srcAddr, address _destAddr, uint _srcAmount, bytes memory _additionalData) external returns (uint);
  }
  
  
  
  
  
  
  
  abstract contract KyberNetworkProxyInterface {
      function maxGasPrice() external virtual view returns (uint256);
  
      function getUserCapInWei(address user) external virtual view returns (uint256);
  
      function getUserCapInTokenWei(address user, IERC20 token) external virtual view returns (uint256);
  
      function enabled() external virtual view returns (bool);
  
      function info(bytes32 id) external virtual view returns (uint256);
  
      function getExpectedRate(IERC20 src, IERC20 dest, uint256 srcQty)
          public virtual
          view
          returns (uint256 expectedRate, uint256 slippageRate);
  
      function tradeWithHint(
          IERC20 src,
          uint256 srcAmount,
          IERC20 dest,
          address destAddress,
          uint256 maxDestAmount,
          uint256 minConversionRate,
          address walletId,
          bytes memory hint
      ) public virtual payable returns (uint256);
  
      function trade(
          IERC20 src,
          uint256 srcAmount,
          IERC20 dest,
          address destAddress,
          uint256 maxDestAmount,
          uint256 minConversionRate,
          address walletId
      ) public virtual payable returns (uint256);
  
      function swapEtherToToken(IERC20 token, uint256 minConversionRate)
          external virtual
          payable
          returns (uint256);
  
      function swapTokenToEther(IERC20 token, uint256 tokenQty, uint256 minRate)
          external virtual
          payable
          returns (uint256);
  
      function swapTokenToToken(IERC20 src, uint256 srcAmount, IERC20 dest, uint256 minConversionRate)
          public virtual
          returns (uint256);
  }
  
  
  
  
  
  
  
  
  
  
  
  
  
  contract KyberWrapperV3 is DSMath, IExchangeV3, AdminAuth, WrapperHelper, DFSExchangeHelper {
  
      error WrongDestAmountError(uint256, uint256);
      using SafeERC20 for IERC20;
  
      /// @notice Sells a _srcAmount of tokens at Kyber
      /// @param _srcAddr From token
      /// @param _destAddr To token
      /// @param _srcAmount From amount
      /// @return uint Destination amount
      function sell(address _srcAddr, address _destAddr, uint _srcAmount, bytes memory) external override returns (uint) {
          IERC20 srcToken = IERC20(_srcAddr);
          IERC20 destToken = IERC20(_destAddr);
  
          KyberNetworkProxyInterface kyberNetworkProxy = KyberNetworkProxyInterface(KYBER_INTERFACE);
  
          srcToken.safeApprove(address(kyberNetworkProxy), _srcAmount);
  
          /// @dev the amount of tokens received is checked in DFSExchangeCore
          /// @dev Exchange wrapper contracts should not be used on their own
          uint destAmount = kyberNetworkProxy.trade(
              srcToken,
              _srcAmount,
              destToken,
              msg.sender,
              type(uint).max,
              0, /// @dev DFSExchangeCore contains slippage check instead of writing it here
              WALLET_ID
          );
  
          sendLeftover(_srcAddr, _destAddr, payable(msg.sender));
  
          return destAmount;
      }
  
      /// @notice Return a rate for which we can sell an amount of tokens
      /// @dev Will fail if token is over 18 decimals
      /// @param _srcAddr From token
      /// @param _destAddr To token
      /// @param _srcAmount From amount
      /// @return rate Rate
      function getSellRate(address _srcAddr, address _destAddr, uint _srcAmount, bytes memory) public override view returns (uint rate) {
          (rate, ) = KyberNetworkProxyInterface(KYBER_INTERFACE)
              .getExpectedRate(IERC20(_srcAddr), IERC20(_destAddr), _srcAmount);
  
          // multiply with decimal difference in src token
          rate = rate * (10 ** (18 - getDecimals(_srcAddr)));
          // divide with decimal difference in dest token
          rate = rate / (10 ** (18 - getDecimals(_destAddr)));
      }
  
      // solhint-disable-next-line no-empty-blocks
      receive() payable external {}
  
      function getDecimals(address _token) internal view returns (uint256) {
          if (_token == TokenUtils.ETH_ADDR) return 18;
  
          return IERC20(_token).decimals();
      }
  }
  