// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;/**
* @dev Collection of functions related to the address type
*/libraryAddress{
/**
* @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
* ====
*/functionisContract(address account) internalviewreturns (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-assemblyassembly {
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].
*/functionsendValue(addresspayable 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._
*/functionfunctionCall(address target, bytesmemory data)
internalreturns (bytesmemory)
{
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._
*/functionfunctionCall(address target,
bytesmemory data,
stringmemory errorMessage
) internalreturns (bytesmemory) {
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._
*/functionfunctionCallWithValue(address target,
bytesmemory data,
uint256 value
) internalreturns (bytesmemory) {
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._
*/functionfunctionCallWithValue(address target,
bytesmemory data,
uint256 value,
stringmemory errorMessage
) internalreturns (bytesmemory) {
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, bytesmemory 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._
*/functionfunctionStaticCall(address target, bytesmemory data)
internalviewreturns (bytesmemory)
{
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._
*/functionfunctionStaticCall(address target,
bytesmemory data,
stringmemory errorMessage
) internalviewreturns (bytesmemory) {
require(isContract(target), "Address: static call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytesmemory returndata) = target.staticcall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/functionfunctionDelegateCall(address target, bytesmemory data)
internalreturns (bytesmemory)
{
return
functionDelegateCall(
target,
data,
"Address: low-level delegate call failed"
);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/functionfunctionDelegateCall(address target,
bytesmemory data,
stringmemory errorMessage
) internalreturns (bytesmemory) {
require(isContract(target), "Address: delegate call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytesmemory returndata) = target.delegatecall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function_verifyCallResult(bool success,
bytesmemory returndata,
stringmemory errorMessage
) privatepurereturns (bytesmemory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if presentif (returndata.length>0) {
// The easiest way to bubble the revert reason is using memory via assembly// solhint-disable-next-line no-inline-assemblyassembly {
let returndata_size :=mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
Contract Source Code
File 2 of 8: Context.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;/*
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/abstractcontractContext{
function_msgSender() internalviewvirtualreturns (address) {
returnmsg.sender;
}
function_msgData() internalviewvirtualreturns (bytescalldata) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691returnmsg.data;
}
}
Contract Source Code
File 3 of 8: IERC20.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/interfaceIERC20{
/**
* @dev Returns the amount of tokens in existence.
*/functiontotalSupply() externalviewreturns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/functionbalanceOf(address account) externalviewreturns (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.
*/functiontransfer(address recipient, uint256 amount)
externalreturns (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.
*/functionallowance(address owner, address spender)
externalviewreturns (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.
*/functionapprove(address spender, uint256 amount) externalreturns (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.
*/functiontransferFrom(address sender,
address recipient,
uint256 amount
) externalreturns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/eventTransfer(addressindexedfrom, addressindexed 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.
*/eventApproval(addressindexed owner,
addressindexed spender,
uint256 value
);
}
Contract Source Code
File 4 of 8: Ownable.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;import"../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/abstractcontractOwnableisContext{
addressprivate _owner;
eventOwnershipTransferred(addressindexed previousOwner,
addressindexed newOwner
);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/constructor() {
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
/**
* @dev Returns the address of the current owner.
*/functionowner() publicviewvirtualreturns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/modifieronlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/functionrenounceOwnership() publicvirtualonlyOwner{
emit OwnershipTransferred(_owner, address(0));
_owner =address(0);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/functiontransferOwnership(address newOwner) publicvirtualonlyOwner{
require(
newOwner !=address(0),
"Ownable: new owner is the zero address"
);
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
Contract Source Code
File 5 of 8: SafeERC20.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;import"../IERC20.sol";
import"../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/librarySafeERC20{
usingAddressforaddress;
functionsafeTransfer(
IERC20 token,
address to,
uint256 value
) internal{
_callOptionalReturn(
token,
abi.encodeWithSelector(token.transfer.selector, to, value)
);
}
functionsafeTransferFrom(
IERC20 token,
addressfrom,
address to,
uint256 value
) internal{
_callOptionalReturn(
token,
abi.encodeWithSelector(token.transferFrom.selector, from, to, value)
);
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/functionsafeApprove(
IERC20 token,
address spender,
uint256 value
) internal{
// safeApprove should only be called when setting an initial allowance,// or when resetting it to zero. To increase and decrease it, use// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'// solhint-disable-next-line max-line-lengthrequire(
(value ==0) || (token.allowance(address(this), spender) ==0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(
token,
abi.encodeWithSelector(token.approve.selector, spender, value)
);
}
functionsafeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal{
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(
token,
abi.encodeWithSelector(
token.approve.selector,
spender,
newAllowance
)
);
}
functionsafeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal{
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(
oldAllowance >= value,
"SafeERC20: decreased allowance below zero"
);
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(
token,
abi.encodeWithSelector(
token.approve.selector,
spender,
newAllowance
)
);
}
}
/**
* @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, bytesmemory 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.bytesmemory returndata =address(token).functionCall(
data,
"SafeERC20: low-level call failed"
);
if (returndata.length>0) {
// Return data is optional// solhint-disable-next-line max-line-lengthrequire(
abi.decode(returndata, (bool)),
"SafeERC20: ERC20 operation did not succeed"
);
}
}
}
Contract Source Code
File 6 of 8: Sushiswap_ZapOut_General_V3.sol
// ███████╗░█████╗░██████╗░██████╗░███████╗██████╗░░░░███████╗██╗// ╚════██║██╔══██╗██╔══██╗██╔══██╗██╔════╝██╔══██╗░░░██╔════╝██║// ░░███╔═╝███████║██████╔╝██████╔╝█████╗░░██████╔╝░░░█████╗░░██║// ██╔══╝░░██╔══██║██╔═══╝░██╔═══╝░██╔══╝░░██╔══██╗░░░██╔══╝░░██║// ███████╗██║░░██║██║░░░░░██║░░░░░███████╗██║░░██║██╗██║░░░░░██║// ╚══════╝╚═╝░░╚═╝╚═╝░░░░░╚═╝░░░░░╚══════╝╚═╝░░╚═╝╚═╝╚═╝░░░░░╚═╝// Copyright (C) 2021 zapper// This program is free software: you can redistribute it and/or modify// it under the terms of the GNU Affero General Public License as published by// the Free Software Foundation, either version 2 of the License, or// (at your option) any later version.//// This program is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU Affero General Public License for more details.//// Visit <https://www.gnu.org/licenses/>for a copy of the GNU Affero General Public License///@author Zapper///@notice this contract implements one click removal of liquidity from Sushiswap pools, receiving ETH, ERC20 or both.// SPDX-License-Identifier: GPL-2.0pragmasolidity ^0.8.0;import"../_base/ZapOutBaseV3.sol";
interfaceIUniswapV2Factory{
functiongetPair(address tokenA, address tokenB)
externalviewreturns (address pair);
}
interfaceIUniswapV2Router02{
functionWETH() externalpurereturns (address);
functionremoveLiquidity(address tokenA,
address tokenB,
uint256 liquidity,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline
) externalreturns (uint256 amountA, uint256 amountB);
functionremoveLiquidityETH(address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
) externalreturns (uint256 amountToken, uint256 amountETH);
}
interfaceIUniswapV2Pair{
functiontoken0() externalpurereturns (address);
functiontoken1() externalpurereturns (address);
functionbalanceOf(address user) externalviewreturns (uint256);
functiontotalSupply() externalviewreturns (uint256);
functiongetReserves()
externalviewreturns (uint112 _reserve0,
uint112 _reserve1,
uint32 _blockTimestampLast
);
functionpermit(address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
}
interfaceIWETH{
functionwithdraw(uint256 wad) external;
}
contractSushiswap_ZapOut_General_V3isZapOutBaseV3{
usingSafeERC20forIERC20;
uint256privateconstant deadline =0xf000000000000000000000000000000000000000000000000000000000000000;
IUniswapV2Router02 privateconstant sushiswapRouter =
IUniswapV2Router02(0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F);
IUniswapV2Factory privateconstant sushiswapFactory =
IUniswapV2Factory(0xC0AEe478e3658e2610c5F7A4A2E1777cE9e4f2Ac);
addressprivateconstant wethTokenAddress =address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
constructor(uint256 _goodwill, uint256 _affiliateSplit)
ZapBaseV2(_goodwill, _affiliateSplit)
{
// 0x exchange
approvedTargets[0xDef1C0ded9bec7F1a1670819833240f027b25EfF] =true;
}
eventzapOut(address sender,
address pool,
address token,
uint256 tokensRec
);
/**
@notice Zap out in both tokens
@param fromPoolAddress Pool from which to remove liquidity
@param incomingLP Quantity of LP to remove from pool
@param affiliate Affiliate address
@return amountA Quantity of tokenA received after zapout
@return amountB Quantity of tokenB received after zapout
*/functionZapOut2PairToken(address fromPoolAddress,
uint256 incomingLP,
address affiliate
) publicstopInEmergencyreturns (uint256 amountA, uint256 amountB) {
IUniswapV2Pair pair = IUniswapV2Pair(fromPoolAddress);
require(address(pair) !=address(0), "Pool Cannot be Zero Address");
// get reservesaddress token0 = pair.token0();
address token1 = pair.token1();
IERC20(fromPoolAddress).safeTransferFrom(
msg.sender,
address(this),
incomingLP
);
_approveToken(fromPoolAddress, address(sushiswapRouter), incomingLP);
if (token0 == wethTokenAddress || token1 == wethTokenAddress) {
address _token = token0 == wethTokenAddress ? token1 : token0;
(amountA, amountB) = sushiswapRouter.removeLiquidityETH(
_token,
incomingLP,
1,
1,
address(this),
deadline
);
// subtract goodwilluint256 tokenGoodwill =
_subtractGoodwill(_token, amountA, affiliate, true);
uint256 ethGoodwill =
_subtractGoodwill(ETHAddress, amountB, affiliate, true);
// send tokens
IERC20(_token).safeTransfer(msg.sender, amountA - tokenGoodwill);
Address.sendValue(payable(msg.sender), amountB - ethGoodwill);
} else {
(amountA, amountB) = sushiswapRouter.removeLiquidity(
token0,
token1,
incomingLP,
1,
1,
address(this),
deadline
);
// subtract goodwilluint256 tokenAGoodwill =
_subtractGoodwill(token0, amountA, affiliate, true);
uint256 tokenBGoodwill =
_subtractGoodwill(token1, amountB, affiliate, true);
// send tokens
IERC20(token0).safeTransfer(msg.sender, amountA - tokenAGoodwill);
IERC20(token1).safeTransfer(msg.sender, amountB - tokenBGoodwill);
}
emit zapOut(msg.sender, fromPoolAddress, token0, amountA);
emit zapOut(msg.sender, fromPoolAddress, token1, amountB);
}
/**
@notice Zap out in a single token
@param toTokenAddress Address of desired token
@param fromPoolAddress Pool from which to remove liquidity
@param incomingLP Quantity of LP to remove from pool
@param minTokensRec Minimum quantity of tokens to receive
@param swapTargets Execution targets for swaps
@param swapData DEX swap data
@param affiliate Affiliate address
@param shouldSellEntireBalance If True transfers entrire allowable amount from another contract
*/functionZapOut(address toTokenAddress,
address fromPoolAddress,
uint256 incomingLP,
uint256 minTokensRec,
address[] memory swapTargets,
bytes[] memory swapData,
address affiliate,
bool shouldSellEntireBalance
) publicstopInEmergencyreturns (uint256 tokensRec) {
(uint256 amount0, uint256 amount1) =
_removeLiquidity(
fromPoolAddress,
incomingLP,
shouldSellEntireBalance
);
//swaps tokens to token
tokensRec = _swapTokens(
fromPoolAddress,
amount0,
amount1,
toTokenAddress,
swapTargets,
swapData
);
require(tokensRec >= minTokensRec, "High Slippage");
uint256 totalGoodwillPortion;
// transfer toTokens to senderif (toTokenAddress ==address(0)) {
totalGoodwillPortion = _subtractGoodwill(
ETHAddress,
tokensRec,
affiliate,
true
);
payable(msg.sender).transfer(tokensRec - totalGoodwillPortion);
} else {
totalGoodwillPortion = _subtractGoodwill(
toTokenAddress,
tokensRec,
affiliate,
true
);
IERC20(toTokenAddress).safeTransfer(
msg.sender,
tokensRec - totalGoodwillPortion
);
}
tokensRec = tokensRec - totalGoodwillPortion;
emit zapOut(msg.sender, fromPoolAddress, toTokenAddress, tokensRec);
return tokensRec;
}
/**
@notice Zap out in both tokens with permit
@param fromPoolAddress Pool from which to remove liquidity
@param incomingLP Quantity of LP to remove from pool
@param affiliate Affiliate address to share fees
@param permitData Encoded permit data, which contains owner, spender, value, deadline, r,s,v values
@return amountA Quantity of tokenA received
@return amountB Quantity of tokenB received
*/functionZapOut2PairTokenWithPermit(address fromPoolAddress,
uint256 incomingLP,
address affiliate,
bytescalldata permitData
) externalstopInEmergencyreturns (uint256 amountA, uint256 amountB) {
// permit
_validatePool(fromPoolAddress);
(bool success, ) = fromPoolAddress.call(permitData);
require(success, "Could Not Permit");
(amountA, amountB) = ZapOut2PairToken(
fromPoolAddress,
incomingLP,
affiliate
);
}
/**
@notice Zap out in a single token with permit
@param toTokenAddress Address of desired token
@param fromPoolAddress Pool from which to remove liquidity
@param incomingLP Quantity of LP to remove from pool
@param minTokensRec Minimum quantity of tokens to receive
@param swapTargets Execution targets for swaps
@param swapData DEX swap data
@param affiliate Affiliate address
*/functionZapOutWithPermit(address toTokenAddress,
address fromPoolAddress,
uint256 incomingLP,
uint256 minTokensRec,
bytesmemory permitData,
address[] memory swapTargets,
bytes[] memory swapData,
address affiliate
) publicstopInEmergencyreturns (uint256) {
// permit
_validatePool(fromPoolAddress);
(bool success, ) = fromPoolAddress.call(permitData);
require(success, "Could Not Permit");
return (
ZapOut(
toTokenAddress,
fromPoolAddress,
incomingLP,
minTokensRec,
swapTargets,
swapData,
affiliate,
false
)
);
}
function_validatePool(address poolAddress) internalview{
IUniswapV2Pair pair = IUniswapV2Pair(poolAddress);
address token0 = pair.token0();
address token1 = pair.token1();
address retrievedAddress = sushiswapFactory.getPair(token0, token1);
require(retrievedAddress == poolAddress, "Invalid Pool Address");
}
function_removeLiquidity(address fromPoolAddress,
uint256 incomingLP,
bool shouldSellEntireBalance
) internalreturns (uint256 amount0, uint256 amount1) {
IUniswapV2Pair pair = IUniswapV2Pair(fromPoolAddress);
require(address(pair) !=address(0), "Pool Cannot be Zero Address");
address token0 = pair.token0();
address token1 = pair.token1();
_pullTokens(fromPoolAddress, incomingLP, shouldSellEntireBalance);
_approveToken(fromPoolAddress, address(sushiswapRouter), incomingLP);
(amount0, amount1) = sushiswapRouter.removeLiquidity(
token0,
token1,
incomingLP,
1,
1,
address(this),
deadline
);
require(amount0 >0&& amount1 >0, "Removed Insufficient Liquidity");
}
function_swapTokens(address fromPoolAddress,
uint256 amount0,
uint256 amount1,
address toToken,
address[] memory swapTargets,
bytes[] memory swapData
) internalreturns (uint256 tokensBought) {
address token0 = IUniswapV2Pair(fromPoolAddress).token0();
address token1 = IUniswapV2Pair(fromPoolAddress).token1();
//swap token0 to toTokenif (token0 == toToken) {
tokensBought = tokensBought + amount0;
} else {
//swap token using 0x swap
tokensBought =
tokensBought +
_fillQuote(
token0,
toToken,
amount0,
swapTargets[0],
swapData[0]
);
}
//swap token1 to toTokenif (token1 == toToken) {
tokensBought = tokensBought + amount1;
} else {
//swap token using 0x swap
tokensBought =
tokensBought +
_fillQuote(
token1,
toToken,
amount1,
swapTargets[1],
swapData[1]
);
}
}
function_fillQuote(address fromTokenAddress,
address toToken,
uint256 amount,
address swapTarget,
bytesmemory swapData
) internalreturns (uint256) {
if (fromTokenAddress == wethTokenAddress && toToken ==address(0)) {
IWETH(wethTokenAddress).withdraw(amount);
return amount;
}
uint256 valueToSend;
if (fromTokenAddress ==address(0)) {
valueToSend = amount;
} else {
_approveToken(fromTokenAddress, swapTarget, amount);
}
uint256 initialBalance = _getBalance(toToken);
require(approvedTargets[swapTarget], "Target not Authorized");
(bool success, ) = swapTarget.call{ value: valueToSend }(swapData);
require(success, "Error Swapping Tokens");
uint256 finalBalance = _getBalance(toToken) - initialBalance;
require(finalBalance >0, "Swapped to Invalid Intermediate");
return finalBalance;
}
/**
@notice Utility function to determine quantity and addresses of tokens being removed
@param fromPoolAddress Pool from which to remove liquidity
@param liquidity Quantity of LP tokens to remove.
@return amountA Quantity of tokenA removed
@return amountB Quantity of tokenB removed
@return token0 Address of the underlying token to be removed
@return token1 Address of the underlying token to be removed
*/functionremoveLiquidityReturn(address fromPoolAddress, uint256 liquidity)
externalviewreturns (uint256 amountA,
uint256 amountB,
address token0,
address token1
)
{
IUniswapV2Pair pair = IUniswapV2Pair(fromPoolAddress);
token0 = pair.token0();
token1 = pair.token1();
uint256 balance0 = IERC20(token0).balanceOf(fromPoolAddress);
uint256 balance1 = IERC20(token1).balanceOf(fromPoolAddress);
uint256 _totalSupply = pair.totalSupply();
amountA = (liquidity * balance0) / _totalSupply;
amountB = (liquidity * balance1) / _totalSupply;
}
}