Blockwell

Sushiswap_ZapIn_V4

About

Stats

Public Functions 13
Event Types 2
Code Size 39,381 bytes

Library Use

Uses SafeERC20 for IERC20.

Events (2) keyboard_arrow_up

OwnershipTransferred Event

Parameters help
previousOwner
address help
newOwner
address help

zapIn Event

Parameters help
sender
address help
pool
address help
tokensRec
uint256 help

sushiSwapFactoryAddress Constant

IUniswapV2Factory help

sushiSwapRouter Constant

IUniswapV2Router02 help

wethTokenAddress Constant

address help

deadline Constant

uint256 help
0xf000000000000000000000000000000000000000000000000000000000000000

ETHAddress Constant

address help

stopped Variable

bool help

goodwill Variable

uint256 help

feeWhitelist Variable

mapping(address => bool) help

affiliates Variable

mapping(address => bool) help

totalAffiliateBalance Variable

mapping(address => uint256) help

approvedTargets Variable

mapping(address => bool) help

affiliateSplit Variable

uint256 help
Internal Variable

affiliateBalance Variable

mapping(address => mapping(address => uint256)) help
Internal Variable

_owner Variable

address help
Internal Variable

Functions Expand All Collapse All

owner keyboard_arrow_up

Parameters help

This function has no parameters.

Properties

Visibility help public
Mutability help view
Source Code
function owner() public view virtual returns (address) {
  return _owner;
}

renounceOwnership keyboard_arrow_up

Parameters help

This function has no parameters.

Properties

Visibility help public
Mutability help transaction

Modifiers help

Source Code
function renounceOwnership() public virtual onlyOwner {
  emit OwnershipTransferred(_owner, address(0));
  _owner = address(0);
}

transferOwnership keyboard_arrow_up

Parameters help

Name Type
newOwner
address help

Properties

Visibility help public
Mutability help transaction

Modifiers help

Requirements help

Source Code
function transferOwnership(address newOwner) public virtual onlyOwner {
  require(newOwner != address(0), "Ownable: new owner is the zero address");
  emit OwnershipTransferred(_owner, newOwner);
  _owner = newOwner;
}

toggleContractActive keyboard_arrow_up

Parameters help

This function has no parameters.

Properties

Visibility help public
Mutability help transaction

Modifiers help

Source Code
function toggleContractActive() public onlyOwner {
  stopped = !stopped;
}

set_feeWhitelist keyboard_arrow_up

Parameters help

Name Type
zapAddress
address help
status
bool help

Properties

Visibility help public
Mutability help transaction

Modifiers help

Source Code
function set_feeWhitelist(address zapAddress, bool status) external onlyOwner {
  feeWhitelist[zapAddress] = status;
}

set_new_goodwill keyboard_arrow_up

Parameters help

Name Type
_new_goodwill
uint256 help

Properties

Visibility help public
Mutability help transaction

Modifiers help

Requirements help

Source Code
function set_new_goodwill(uint256 _new_goodwill) public onlyOwner {
  require(
    _new_goodwill >= 0 && _new_goodwill <= 100,
    "GoodWill Value not allowed"
  );
  goodwill = _new_goodwill;
}

set_new_affiliateSplit keyboard_arrow_up

Parameters help

Name Type
_new_affiliateSplit
uint256 help

Properties

Visibility help public
Mutability help transaction

Modifiers help

Requirements help

Source Code
function set_new_affiliateSplit(uint256 _new_affiliateSplit)
  external
  onlyOwner
{
  require(_new_affiliateSplit <= 100, "Affiliate Split Value not allowed");
  affiliateSplit = _new_affiliateSplit;
}

set_affiliate keyboard_arrow_up

Parameters help

Name Type
_affiliate
address help
_status
bool help

Properties

Visibility help public
Mutability help transaction

Modifiers help

Source Code
function set_affiliate(address _affiliate, bool _status) external onlyOwner {
  affiliates[_affiliate] = _status;
}

withdrawTokens keyboard_arrow_up

Parameters help

Name Type
tokens
address[] help

Properties

Visibility help public
Mutability help transaction

Modifiers help

Source Code
function withdrawTokens(address[] calldata tokens) external onlyOwner {
  for (uint256 i = 0; i < tokens.length; i++) {
    uint256 qty;

    if (tokens[i] == ETHAddress) {
      qty = address(this).balance - totalAffiliateBalance[tokens[i]];

      Address.sendValue(payable(owner()), qty);
    } else {
      qty =
        IERC20(tokens[i]).balanceOf(address(this)) -
        totalAffiliateBalance[tokens[i]];
      IERC20(tokens[i]).safeTransfer(owner(), qty);
    }
  }
}

affilliateWithdraw keyboard_arrow_up

Parameters help

Name Type
tokens
address[] help

Properties

Visibility help public
Mutability help transaction
Source Code
function affilliateWithdraw(address[] calldata tokens) external {
  uint256 tokenBal;
  for (uint256 i = 0; i < tokens.length; i++) {
    tokenBal = affiliateBalance[msg.sender][tokens[i]];
    affiliateBalance[msg.sender][tokens[i]] = 0;
    totalAffiliateBalance[tokens[i]] =
      totalAffiliateBalance[tokens[i]] -
      tokenBal;

    if (tokens[i] == ETHAddress) {
      Address.sendValue(payable(msg.sender), tokenBal);
    } else {
      IERC20(tokens[i]).safeTransfer(msg.sender, tokenBal);
    }
  }
}

setApprovedTargets keyboard_arrow_up

Parameters help

Name Type
targets
address[] help
isApproved
bool[] help

Properties

Visibility help public
Mutability help transaction

Modifiers help

Source Code
function setApprovedTargets(
  address[] calldata targets,
  bool[] calldata isApproved
) external onlyOwner {
  require(targets.length == isApproved.length, "Invalid Input length");

  for (uint256 i = 0; i < targets.length; i++) {
    approvedTargets[targets[i]] = isApproved[i];
  }
}

constructor keyboard_arrow_up

Parameters help

This function has no parameters.

Properties

Visibility help public
Mutability help payable

Requirements help

Source Code
receive() external payable {
  require(msg.sender != tx.origin, "Do not send ETH directly");
}

ZapIn keyboard_arrow_up

Parameters help

Name Type
_FromTokenContractAddress
address help
_pairAddress
address help
_amount
uint256 help
_minPoolTokens
uint256 help
_swapTarget
address help
swapData
bytes help
affiliate
address help
transferResidual
bool help
shouldSellEntireBalance
bool help

Properties

Visibility help public
Mutability help payable

Modifiers help

stopInEmergency checks for the following:
Source Code
function ZapIn(
  address _FromTokenContractAddress,
  address _pairAddress,
  uint256 _amount,
  uint256 _minPoolTokens,
  address _swapTarget,
  bytes calldata swapData,
  address affiliate,
  bool transferResidual,
  bool shouldSellEntireBalance
) external payable stopInEmergency returns (uint256) {
  uint256 toInvest = _pullTokens(
    _FromTokenContractAddress,
    _amount,
    affiliate,
    true,
    shouldSellEntireBalance
  );

  uint256 LPBought = _performZapIn(
    _FromTokenContractAddress,
    _pairAddress,
    toInvest,
    _swapTarget,
    swapData,
    transferResidual
  );
  require(LPBought >= _minPoolTokens, "High Slippage");

  emit zapIn(msg.sender, _pairAddress, LPBought);

  IERC20(_pairAddress).safeTransfer(msg.sender, LPBought);
  return LPBought;
}

Internal Functions Expand All Collapse All

Internal functions are parts of the contract that can't be used directly, but instead are used by the public functions listed above.

internal Sushiswap_ZapIn_V4._getPairTokens keyboard_arrow_up

Parameters help

Name Type
_pairAddress
address help

Properties

Visibility help internal
Mutability help pure
Source Code
function _getPairTokens(address _pairAddress)
  internal
  pure
  returns (address token0, address token1)
{
  IUniswapV2Pair uniPair = IUniswapV2Pair(_pairAddress);
  token0 = uniPair.token0();
  token1 = uniPair.token1();
}

internal Sushiswap_ZapIn_V4._performZapIn keyboard_arrow_up

Parameters help

Name Type
_FromTokenContractAddress
address help
_pairAddress
address help
_amount
uint256 help
_swapTarget
address help
swapData
bytes help
transferResidual
bool help

Properties

Visibility help internal
Mutability help transaction
Source Code
function _performZapIn(
  address _FromTokenContractAddress,
  address _pairAddress,
  uint256 _amount,
  address _swapTarget,
  bytes memory swapData,
  bool transferResidual
) internal returns (uint256) {
  uint256 intermediateAmt;
  address intermediateToken;
  (address _ToUniswapToken0, address _ToUniswapToken1) = _getPairTokens(
    _pairAddress
  );

  if (
    _FromTokenContractAddress != _ToUniswapToken0 &&
    _FromTokenContractAddress != _ToUniswapToken1
  ) {
    // swap to intermediate
    (intermediateAmt, intermediateToken) = _fillQuote(
      _FromTokenContractAddress,
      _pairAddress,
      _amount,
      _swapTarget,
      swapData
    );
  } else {
    intermediateToken = _FromTokenContractAddress;
    intermediateAmt = _amount;
  }

  // divide intermediate into appropriate amount to add liquidity
  (uint256 token0Bought, uint256 token1Bought) = _swapIntermediate(
    intermediateToken,
    _ToUniswapToken0,
    _ToUniswapToken1,
    intermediateAmt
  );

  return
    _uniDeposit(
      _ToUniswapToken0,
      _ToUniswapToken1,
      token0Bought,
      token1Bought,
      transferResidual
    );
}

internal Sushiswap_ZapIn_V4._uniDeposit keyboard_arrow_up

Parameters help

Name Type
_ToUnipoolToken0
address help
_ToUnipoolToken1
address help
token0Bought
uint256 help
token1Bought
uint256 help
transferResidual
bool help

Properties

Visibility help internal
Mutability help transaction
Source Code
function _uniDeposit(
  address _ToUnipoolToken0,
  address _ToUnipoolToken1,
  uint256 token0Bought,
  uint256 token1Bought,
  bool transferResidual
) internal returns (uint256) {
  _approveToken(_ToUnipoolToken0, address(sushiSwapRouter), token0Bought);
  _approveToken(_ToUnipoolToken1, address(sushiSwapRouter), token1Bought);

  (uint256 amountA, uint256 amountB, uint256 LP) = sushiSwapRouter.addLiquidity(
    _ToUnipoolToken0,
    _ToUnipoolToken1,
    token0Bought,
    token1Bought,
    1,
    1,
    address(this),
    deadline
  );

  if (transferResidual) {
    //Returning Residue in token0, if any.
    if (token0Bought - amountA > 0) {
      IERC20(_ToUnipoolToken0).safeTransfer(msg.sender, token0Bought - amountA);
    }

    //Returning Residue in token1, if any
    if (token1Bought - amountB > 0) {
      IERC20(_ToUnipoolToken1).safeTransfer(msg.sender, token1Bought - amountB);
    }
  }

  return LP;
}

internal Sushiswap_ZapIn_V4._fillQuote keyboard_arrow_up

Parameters help

Name Type
_fromTokenAddress
address help
_pairAddress
address help
_amount
uint256 help
_swapTarget
address help
swapData
bytes help

Properties

Visibility help internal
Mutability help transaction
Source Code
function _fillQuote(
  address _fromTokenAddress,
  address _pairAddress,
  uint256 _amount,
  address _swapTarget,
  bytes memory swapData
) internal returns (uint256 amountBought, address intermediateToken) {
  if (_swapTarget == wethTokenAddress) {
    IWETH(wethTokenAddress).deposit{value: _amount}();
    return (_amount, wethTokenAddress);
  }

  uint256 valueToSend;
  if (_fromTokenAddress == address(0)) {
    valueToSend = _amount;
  } else {
    _approveToken(_fromTokenAddress, _swapTarget, _amount);
  }

  (address _token0, address _token1) = _getPairTokens(_pairAddress);
  IERC20 token0 = IERC20(_token0);
  IERC20 token1 = IERC20(_token1);
  uint256 initialBalance0 = token0.balanceOf(address(this));
  uint256 initialBalance1 = token1.balanceOf(address(this));

  require(approvedTargets[_swapTarget], "Target not Authorized");
  (bool success, ) = _swapTarget.call{value: valueToSend}(swapData);
  require(success, "Error Swapping Tokens 1");

  uint256 finalBalance0 = token0.balanceOf(address(this)) - initialBalance0;
  uint256 finalBalance1 = token1.balanceOf(address(this)) - initialBalance1;

  if (finalBalance0 > finalBalance1) {
    amountBought = finalBalance0;
    intermediateToken = _token0;
  } else {
    amountBought = finalBalance1;
    intermediateToken = _token1;
  }

  require(amountBought > 0, "Swapped to Invalid Intermediate");
}

internal Sushiswap_ZapIn_V4._swapIntermediate keyboard_arrow_up

Parameters help

Name Type
_toContractAddress
address help
_ToUnipoolToken0
address help
_ToUnipoolToken1
address help
_amount
uint256 help

Properties

Visibility help internal
Mutability help transaction
Source Code
function _swapIntermediate(
  address _toContractAddress,
  address _ToUnipoolToken0,
  address _ToUnipoolToken1,
  uint256 _amount
) internal returns (uint256 token0Bought, uint256 token1Bought) {
  IUniswapV2Pair pair = IUniswapV2Pair(
    sushiSwapFactoryAddress.getPair(_ToUnipoolToken0, _ToUnipoolToken1)
  );
  (uint256 res0, uint256 res1, ) = pair.getReserves();
  if (_toContractAddress == _ToUnipoolToken0) {
    uint256 amountToSwap = calculateSwapInAmount(res0, _amount);
    //if no reserve or a new pair is created
    if (amountToSwap <= 0) amountToSwap = _amount / 2;
    token1Bought = _token2Token(
      _toContractAddress,
      _ToUnipoolToken1,
      amountToSwap
    );
    token0Bought = _amount - amountToSwap;
  } else {
    uint256 amountToSwap = calculateSwapInAmount(res1, _amount);
    //if no reserve or a new pair is created
    if (amountToSwap <= 0) amountToSwap = _amount / 2;
    token0Bought = _token2Token(
      _toContractAddress,
      _ToUnipoolToken0,
      amountToSwap
    );
    token1Bought = _amount - amountToSwap;
  }
}

internal Sushiswap_ZapIn_V4.calculateSwapInAmount keyboard_arrow_up

Parameters help

Name Type
reserveIn
uint256 help
userIn
uint256 help

Properties

Visibility help internal
Mutability help pure
Source Code
function calculateSwapInAmount(uint256 reserveIn, uint256 userIn)
  internal
  pure
  returns (uint256)
{
  return
    (Babylonian.sqrt(reserveIn * ((userIn * 3988000) + (reserveIn * 3988009))) -
      (reserveIn * 1997)) / 1994;
}

internal Sushiswap_ZapIn_V4._token2Token keyboard_arrow_up

Parameters help

Name Type
_FromTokenContractAddress
address help
_ToTokenContractAddress
address help
tokens2Trade
uint256 help

Properties

Visibility help internal
Mutability help transaction

Requirements help

Source Code
function _token2Token(
  address _FromTokenContractAddress,
  address _ToTokenContractAddress,
  uint256 tokens2Trade
) internal returns (uint256 tokenBought) {
  if (_FromTokenContractAddress == _ToTokenContractAddress) {
    return tokens2Trade;
  }

  _approveToken(
    _FromTokenContractAddress,
    address(sushiSwapRouter),
    tokens2Trade
  );

  address pair = sushiSwapFactoryAddress.getPair(
    _FromTokenContractAddress,
    _ToTokenContractAddress
  );
  require(pair != address(0), "No Swap Available");
  address[] memory path = new address[](2);
  path[0] = _FromTokenContractAddress;
  path[1] = _ToTokenContractAddress;

  tokenBought = sushiSwapRouter.swapExactTokensForTokens(
    tokens2Trade,
    1,
    path,
    address(this),
    deadline
  )[path.length - 1];

  require(tokenBought > 0, "Error Swapping Tokens 2");
}

internal ZapInBaseV3._pullTokens keyboard_arrow_up

Parameters help

Name Type
token
address help
amount
uint256 help
affiliate
address help
enableGoodwill
bool help
shouldSellEntireBalance
bool help

Properties

Visibility help internal
Mutability help transaction

Requirements help

Source Code
function _pullTokens(
  address token,
  uint256 amount,
  address affiliate,
  bool enableGoodwill,
  bool shouldSellEntireBalance
) internal returns (uint256 value) {
  uint256 totalGoodwillPortion;

  if (token == address(0)) {
    require(msg.value > 0, "No eth sent");

    // subtract goodwill
    totalGoodwillPortion = _subtractGoodwill(
      ETHAddress,
      msg.value,
      affiliate,
      enableGoodwill
    );

    return msg.value - totalGoodwillPortion;
  }
  require(amount > 0, "Invalid token amount");
  require(msg.value == 0, "Eth sent with token");

  //transfer token
  if (shouldSellEntireBalance) {
    require(
      Address.isContract(msg.sender),
      "ERR: shouldSellEntireBalance is true for EOA"
    );
    amount = IERC20(token).allowance(msg.sender, address(this));
  }
  IERC20(token).safeTransferFrom(msg.sender, address(this), amount);

  // subtract goodwill
  totalGoodwillPortion = _subtractGoodwill(
    token,
    amount,
    affiliate,
    enableGoodwill
  );

  return amount - totalGoodwillPortion;
}

internal ZapInBaseV3._subtractGoodwill keyboard_arrow_up

Parameters help

Name Type
token
address help
amount
uint256 help
affiliate
address help
enableGoodwill
bool help

Properties

Visibility help internal
Mutability help transaction
Source Code
function _subtractGoodwill(
  address token,
  uint256 amount,
  address affiliate,
  bool enableGoodwill
) internal returns (uint256 totalGoodwillPortion) {
  bool whitelisted = feeWhitelist[msg.sender];
  if (enableGoodwill && !whitelisted && goodwill > 0) {
    totalGoodwillPortion = (amount * goodwill) / 10000;

    if (affiliates[affiliate]) {
      if (token == address(0)) {
        token = ETHAddress;
      }

      uint256 affiliatePortion = (totalGoodwillPortion * affiliateSplit) / 100;
      affiliateBalance[affiliate][token] += affiliatePortion;
      totalAffiliateBalance[token] += affiliatePortion;
    }
  }
}

internal ZapBaseV2._getBalance keyboard_arrow_up

Parameters help

Name Type
token
address help

Properties

Visibility help internal
Mutability help view
Source Code
function _getBalance(address token) internal view returns (uint256 balance) {
  if (token == address(0)) {
    balance = address(this).balance;
  } else {
    balance = IERC20(token).balanceOf(address(this));
  }
}

internal ZapBaseV2._approveToken keyboard_arrow_up

Parameters help

Name Type
token
address help
spender
address help

Properties

Visibility help internal
Mutability help transaction
Source Code
function _approveToken(address token, address spender) internal {
  IERC20 _token = IERC20(token);
  if (_token.allowance(address(this), spender) > 0) return;
  else {
    _token.safeApprove(spender, type(uint256).max);
  }
}

internal ZapBaseV2._approveToken keyboard_arrow_up

Parameters help

Name Type
token
address help
spender
address help
amount
uint256 help

Properties

Visibility help internal
Mutability help transaction
Source Code
function _approveToken(
  address token,
  address spender,
  uint256 amount
) internal {
  IERC20(token).safeApprove(spender, 0);
  IERC20(token).safeApprove(spender, amount);
}

internal Context._msgSender keyboard_arrow_up

Parameters help

This function has no parameters.

Properties

Visibility help internal
Mutability help view
Source Code
function _msgSender() internal view virtual returns (address) {
  return msg.sender;
}

internal Context._msgData keyboard_arrow_up

Parameters help

This function has no parameters.

Properties

Visibility help internal
Mutability help view
Source Code
function _msgData() internal view virtual returns (bytes calldata) {
  this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
  return msg.data;
}