Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

zapper update #183

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion contracts/interfaces/kyber.sol
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,3 @@ interface IKyberFactory {
interface IDMMPool {
function kLast() external view returns (uint256);
}

104 changes: 96 additions & 8 deletions contracts/zapper-contract/SnowglobeZapperPangolin.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,66 @@ contract SnowglobeZapAvaxPangolin is ZapperBase {

}

/**
* @notice Returns the token pair and vault at the snowglobe address
* @param snowglobe address of the lp pair
*/
function _getVaultPair(address snowglobe) internal view returns (IGlobe vault, IPangolinPair pair){

vault = IGlobe(snowglobe);
pair = IPangolinPair(vault.token());

require(pair.factory() == IPangolinPair(router).factory(), "Incompatible liquidity pair factory");
}

/**
* @notice Zaps into the liquidity pair with AVAX
* @param snowglobe
* @param tokenAmontOutMin
* @param tokenIn
*/
function zapInAVAX(address snowglobe, uint256 tokenAmountOutMin, address tokenIn) external payable override {
require(msg.value >= minimumAmount, "Insignificant input amount");

// Get balance of native AVAX and wrap AVAX into ERC20 (WAVAX)
WAVAX(wavax).deposit{value: msg.value}();

// gets the token pair in the lp
(, IPangolinPair pair) = _getVaultPair(snowglobe);

(uint256 reserveA, uint256 reserveB, ) = pair.getReserves();
require(reserveA > minimumAmount && reserveB > minimumAmount, "Liquidity pair reserves too low");

address token0 = pair.token0(); // first token in the pool
address token1 = pair.token1(); // second token in the pool

bool isInputA = token0 == tokenIn;
require(isInputA || token1 == tokenIn, "Input token not present in liquidity pair");

// allows us to zapIn if avax isn't part of the original pair
if (tokenIn != wavax){
uint256 _amount = IERC20(wavax).balanceOf(address(this));

// Use the kyber router to find a direct root from wavax to the desired tokenIn
// then swap the wavax for the tokenIn and add liquidity for the pool
uint256 swapAmountIn = _getSwapAmount(_amount, reserveA, reserveB);
_swapToken(wavax, tokenIn, swapAmountIn);
_swapAndStake(snowglobe, tokenAmountOutMin, tokenIn);
} else {
_swapAndStake(snowglobe, tokenAmountOutMin, tokenIn);
}
}

/**
* @notice Zaps out of the liquidity pair to a desired token
* @param snowglobe
* @param withdrawAmount
* @param desiredToken
* @param desiredTokenOutMin
*/
function zapOutAndSwap(address snowglobe, uint256 withdrawAmount, address desiredToken, uint256 desiredTokenOutMin) public override {

(IGlobe vault, IUniPair pair) = _getVaultPair(snowglobe);
(IGlobe vault, IPangolinPair pair) = _getVaultPair(snowglobe);
address token0 = pair.token0();
address token1 = pair.token1();
require(token0 == desiredToken || token1 == desiredToken, "desired token not present in liquidity pair");
Expand All @@ -24,6 +81,7 @@ contract SnowglobeZapAvaxPangolin is ZapperBase {
_removeLiquidity(address(pair), address(this));

address swapToken = token1 == desiredToken ? token0 : token1;
_approveTokenIfNeeded(swapToken, address(router));
address[] memory path = new address[](2);
path[0] = swapToken;
path[1] = desiredToken;
Expand All @@ -36,22 +94,30 @@ contract SnowglobeZapAvaxPangolin is ZapperBase {
address(this),
block.timestamp
);

_returnAssets(path);
}

/**
* @notice Stakes into the liquidty pair with either token0 or token1 in the liquidty pair
* @param snowglobe
* @param tokenAmountOutMin
* @param tokenIn
*/
function _swapAndStake(address snowglobe, uint256 tokenAmountOutMin, address tokenIn) public override {
(IGlobe vault, IUniPair pair) = _getVaultPair(snowglobe);
(IGlobe vault, IPangolinPair pair) = _getVaultPair(snowglobe);

(uint256 reserveA, uint256 reserveB, ) = pair.getReserves();
require(reserveA > minimumAmount && reserveB > minimumAmount, "Liquidity pair reserves too low");

bool isInputA = pair.token0() == tokenIn;
require(isInputA || pair.token1() == tokenIn, "Input token not present in liquidity pair");
address token0 = pair.token0(); // first token in the pool
address token1 = pair.token1(); // second token in the pool

bool isInputA = token0 == tokenIn;
require(isInputA || token1 == tokenIn, "Input token not present in liquidity pair");

address[] memory path = new address[](2);
path[0] = tokenIn;
path[1] = isInputA ? pair.token1() : pair.token0();
path[1] = isInputA ? token1 : token0;

uint256 fullInvestment = IERC20(tokenIn).balanceOf(address(this));
uint256 swapAmountIn;
Expand All @@ -62,7 +128,7 @@ contract SnowglobeZapAvaxPangolin is ZapperBase {
}

_approveTokenIfNeeded(path[0], address(router));
uint256[] memory swappedAmounts = IPangolinRouter(router).swapExactTokensForTokens(
uint256[] memory swappedAmounts = IPangolinRouter(router).swapExactTokensForTokens(
swapAmountIn,
tokenAmountOutMin,
path,
Expand Down Expand Up @@ -117,7 +183,7 @@ contract SnowglobeZapAvaxPangolin is ZapperBase {
}

function estimateSwap(address snowglobe, address tokenIn, uint256 fullInvestmentIn) public view returns (uint256 swapAmountIn, uint256 swapAmountOut, address swapTokenOut){
(, IUniPair pair) = _getVaultPair(snowglobe);
(, IPangolinPair pair) = _getVaultPair(snowglobe);

bool isInputA = pair.token0() == tokenIn;
require(isInputA || pair.token1() == tokenIn, "Input token not present in liquidity pair");
Expand All @@ -134,4 +200,26 @@ contract SnowglobeZapAvaxPangolin is ZapperBase {
swapTokenOut = isInputA ? pair.token1() : pair.token0();
}

function zapOut(address snowglobe, uint256 withdrawAmount) external override {
(IGlobe vault, IPangolinPair pair) = _getVaultPair(snowglobe);
address token0 = pair.token0();
address token1 = pair.token1();

IERC20(snowglobe).safeTransferFrom(msg.sender, address(this), withdrawAmount);
vault.withdraw(withdrawAmount);

if (pair.token0() != wavax && pair.token1() != wavax) {
return _removeLiquidity(address(pair), msg.sender);
}


_removeLiquidity(address(pair), address(this));

address[] memory tokens = new address[](2);
tokens[0] = token0;
tokens[1] = token1;

_returnAssets(tokens);
}

}
81 changes: 72 additions & 9 deletions contracts/zapper-contract/SnowglobeZapperTraderJoe.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,63 @@ contract SnowglobeZapAvaxTraderJoe is ZapperBase {

}

/**
* @notice Returns the token pair and vault at the snowglobe address
* @param snowglobe address of the lp pair
*/
function _getVaultPair(address snowglobe) internal view returns (IGlobe vault, IJoePair pair){

vault = IGlobe(snowglobe);
pair = IJoePair(vault.token());

require(pair.factory() == IJoePair(router).factory(), "Incompatible liquidity pair factory");
}

/**
* @notice Zaps into the liquidity pair with AVAX
* @param snowglobe
* @param tokenAmontOutMin
* @param tokenIn
*/
function zapInAVAX(address snowglobe, uint256 tokenAmountOutMin, address tokenIn) external payable override {
require(msg.value >= minimumAmount, "Insignificant input amount");

// Get balance of native AVAX and wrap AVAX into ERC20 (WAVAX)
WAVAX(wavax).deposit{value: msg.value}();

// gets the token pair in the lp
(, IJoePair pair) = _getVaultPair(snowglobe);

(uint256 reserveA, uint256 reserveB, ) = pair.getReserves();
require(reserveA > minimumAmount && reserveB > minimumAmount, "Liquidity pair reserves too low");

address token0 = pair.token0(); // first token in the pool
address token1 = pair.token1(); // second token in the pool

bool isInputA = token0 == tokenIn;
require(isInputA || token1 == tokenIn, "Input token not present in liquidity pair");

// allows us to zapIn if avax isn't part of the original pair
if (tokenIn != wavax){
uint256 _amount = IERC20(wavax).balanceOf(address(this));

// Use the kyber router to find a direct root from wavax to the desired tokenIn
// then swap the wavax for the tokenIn and add liquidity for the pool
uint256 swapAmountIn = _getSwapAmount(_amount, reserveA, reserveB);
_swapToken(wavax, tokenIn, swapAmountIn);
_swapAndStake(snowglobe, tokenAmountOutMin, tokenIn);
} else {
_swapAndStake(snowglobe, tokenAmountOutMin, tokenIn);
}
}

/**
* @notice Zaps out of the liquidity pair to a desired token
* @param snowglobe
* @param withdrawAmount
* @param desiredToken
* @param desiredTokenOutMin
*/
function zapOutAndSwap(address snowglobe, uint256 withdrawAmount, address desiredToken, uint256 desiredTokenOutMin) public override {
(IGlobe vault, IUniPair pair) = _getVaultPair(snowglobe);
address token0 = pair.token0();
Expand All @@ -23,6 +80,7 @@ contract SnowglobeZapAvaxTraderJoe is ZapperBase {
_removeLiquidity(address(pair), address(this));

address swapToken = token1 == desiredToken ? token0 : token1;
_approveTokenIfNeeded(swapToken, address(router));
address[] memory path = new address[](2);
path[0] = swapToken;
path[1] = desiredToken;
Expand All @@ -35,22 +93,30 @@ contract SnowglobeZapAvaxTraderJoe is ZapperBase {
address(this),
block.timestamp
);

_returnAssets(path);
}

/**
* @notice Stakes into the liquidty pair with either token0 or token1 in the liquidty pair
* @param snowglobe
* @param tokenAmountOutMin
* @param tokenIn
*/
function _swapAndStake(address snowglobe, uint256 tokenAmountOutMin, address tokenIn) public override {
(IGlobe vault, IUniPair pair) = _getVaultPair(snowglobe);

(uint256 reserveA, uint256 reserveB, ) = pair.getReserves();
require(reserveA > minimumAmount && reserveB > minimumAmount, "Liquidity pair reserves too low");

bool isInputA = pair.token0() == tokenIn;
require(isInputA || pair.token1() == tokenIn, "Input token not present in liquidity pair");
address token0 = pair.token0(); // first token in the pool
address token1 = pair.token1(); // second token in the pool

bool isInputA = token0 == tokenIn;
require(isInputA || token1 == tokenIn, "Input token not present in liquidity pair");

address[] memory path = new address[](2);
path[0] = tokenIn;
path[1] = isInputA ? pair.token1() : pair.token0();
path[1] = isInputA ? token1 : token0;

uint256 fullInvestment = IERC20(tokenIn).balanceOf(address(this));
uint256 swapAmountIn;
Expand All @@ -61,7 +127,7 @@ contract SnowglobeZapAvaxTraderJoe is ZapperBase {
}

_approveTokenIfNeeded(path[0], address(router));
uint256[] memory swappedAmounts = IJoeRouter(router)
uint256[] memory swappedAmounts = IJoeRouter(router)
.swapExactTokensForTokens(
swapAmountIn,
tokenAmountOutMin,
Expand All @@ -85,9 +151,6 @@ contract SnowglobeZapAvaxTraderJoe is ZapperBase {
_approveTokenIfNeeded(address(pair), address(vault));
vault.deposit(amountLiquidity);

//add to guage if possible instead of returning to user, and so no receipt token
vault.safeTransfer(msg.sender, vault.balanceOf(address(this)));

//taking receipt token and sending back to user
vault.safeTransfer(msg.sender, vault.balanceOf(address(this)));

Expand Down Expand Up @@ -120,7 +183,7 @@ contract SnowglobeZapAvaxTraderJoe is ZapperBase {
}

function estimateSwap(address snowglobe, address tokenIn, uint256 fullInvestmentIn) public view returns (uint256 swapAmountIn, uint256 swapAmountOut, address swapTokenOut){
(, IUniPair pair) = _getVaultPair(snowglobe);
(, IJoePair pair) = _getVaultPair(snowglobe);

bool isInputA = pair.token0() == tokenIn;
require(isInputA || pair.token1() == tokenIn, "Input token not present in liquidity pair");
Expand Down
Loading