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

success router and factory #5

Open
wants to merge 1 commit 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
4 changes: 4 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
MNEMONIC="call glow acoustic vintage front ring trade assist shuffle mimic volume reject"
INFURA_TOKEN="a30ce8978acb4d7da82e6d7e6b71afb7"
ETHERSCAN_KEY="HSR39CEBP479H5TBJTXR693XMATW8T68KE"
BSCSCAN_KEY="JQX4RQZFG69R7UUWEACP5VGSI7ZVREDY8S"
14 changes: 14 additions & 0 deletions contracts/GreenToken.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract GreenToken is ERC20, Ownable {
constructor() public ERC20("GREEN", "GREEN") {
_mint(msg.sender, 100000 ether);
}

function mint(address account, uint256 amount) external onlyOwner {
_mint(account, amount);
}
}
24 changes: 12 additions & 12 deletions contracts/PancakeRouter.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
pragma solidity =0.6.6;

import '@uniswap/v2-core/contracts/interfaces/IPancakeFactory.sol';
import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol';
import '@uniswap/lib/contracts/libraries/TransferHelper.sol';

import './interfaces/IPancakeRouter02.sol';
Expand Down Expand Up @@ -39,8 +39,8 @@ contract PancakeRouter is IPancakeRouter02 {
uint amountBMin
) internal virtual returns (uint amountA, uint amountB) {
// create the pair if it doesn't exist yet
if (IPancakeFactory(factory).getPair(tokenA, tokenB) == address(0)) {
IPancakeFactory(factory).createPair(tokenA, tokenB);
if (IUniswapV2Factory(factory).getPair(tokenA, tokenB) == address(0)) {
IUniswapV2Factory(factory).createPair(tokenA, tokenB);
}
(uint reserveA, uint reserveB) = PancakeLibrary.getReserves(factory, tokenA, tokenB);
if (reserveA == 0 && reserveB == 0) {
Expand Down Expand Up @@ -72,7 +72,7 @@ contract PancakeRouter is IPancakeRouter02 {
address pair = PancakeLibrary.pairFor(factory, tokenA, tokenB);
TransferHelper.safeTransferFrom(tokenA, msg.sender, pair, amountA);
TransferHelper.safeTransferFrom(tokenB, msg.sender, pair, amountB);
liquidity = IPancakePair(pair).mint(to);
liquidity = IUniswapV2Pair(pair).mint(to);
}
function addLiquidityETH(
address token,
Expand All @@ -94,7 +94,7 @@ contract PancakeRouter is IPancakeRouter02 {
TransferHelper.safeTransferFrom(token, msg.sender, pair, amountToken);
IWETH(WETH).deposit{value: amountETH}();
assert(IWETH(WETH).transfer(pair, amountETH));
liquidity = IPancakePair(pair).mint(to);
liquidity = IUniswapV2Pair(pair).mint(to);
// refund dust eth, if any
if (msg.value > amountETH) TransferHelper.safeTransferETH(msg.sender, msg.value - amountETH);
}
Expand All @@ -110,8 +110,8 @@ contract PancakeRouter is IPancakeRouter02 {
uint deadline
) public virtual override ensure(deadline) returns (uint amountA, uint amountB) {
address pair = PancakeLibrary.pairFor(factory, tokenA, tokenB);
IPancakePair(pair).transferFrom(msg.sender, pair, liquidity); // send liquidity to pair
(uint amount0, uint amount1) = IPancakePair(pair).burn(to);
IUniswapV2Pair(pair).transferFrom(msg.sender, pair, liquidity); // send liquidity to pair
(uint amount0, uint amount1) = IUniswapV2Pair(pair).burn(to);
(address token0,) = PancakeLibrary.sortTokens(tokenA, tokenB);
(amountA, amountB) = tokenA == token0 ? (amount0, amount1) : (amount1, amount0);
require(amountA >= amountAMin, 'PancakeRouter: INSUFFICIENT_A_AMOUNT');
Expand Down Expand Up @@ -150,7 +150,7 @@ contract PancakeRouter is IPancakeRouter02 {
) external virtual override returns (uint amountA, uint amountB) {
address pair = PancakeLibrary.pairFor(factory, tokenA, tokenB);
uint value = approveMax ? uint(-1) : liquidity;
IPancakePair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
IUniswapV2Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
(amountA, amountB) = removeLiquidity(tokenA, tokenB, liquidity, amountAMin, amountBMin, to, deadline);
}
function removeLiquidityETHWithPermit(
Expand All @@ -164,7 +164,7 @@ contract PancakeRouter is IPancakeRouter02 {
) external virtual override returns (uint amountToken, uint amountETH) {
address pair = PancakeLibrary.pairFor(factory, token, WETH);
uint value = approveMax ? uint(-1) : liquidity;
IPancakePair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
IUniswapV2Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
(amountToken, amountETH) = removeLiquidityETH(token, liquidity, amountTokenMin, amountETHMin, to, deadline);
}

Expand Down Expand Up @@ -201,7 +201,7 @@ contract PancakeRouter is IPancakeRouter02 {
) external virtual override returns (uint amountETH) {
address pair = PancakeLibrary.pairFor(factory, token, WETH);
uint value = approveMax ? uint(-1) : liquidity;
IPancakePair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
IUniswapV2Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
amountETH = removeLiquidityETHSupportingFeeOnTransferTokens(
token, liquidity, amountTokenMin, amountETHMin, to, deadline
);
Expand All @@ -216,7 +216,7 @@ contract PancakeRouter is IPancakeRouter02 {
uint amountOut = amounts[i + 1];
(uint amount0Out, uint amount1Out) = input == token0 ? (uint(0), amountOut) : (amountOut, uint(0));
address to = i < path.length - 2 ? PancakeLibrary.pairFor(factory, output, path[i + 2]) : _to;
IPancakePair(PancakeLibrary.pairFor(factory, input, output)).swap(
IUniswapV2Pair(PancakeLibrary.pairFor(factory, input, output)).swap(
amount0Out, amount1Out, to, new bytes(0)
);
}
Expand Down Expand Up @@ -322,7 +322,7 @@ contract PancakeRouter is IPancakeRouter02 {
for (uint i; i < path.length - 1; i++) {
(address input, address output) = (path[i], path[i + 1]);
(address token0,) = PancakeLibrary.sortTokens(input, output);
IPancakePair pair = IPancakePair(PancakeLibrary.pairFor(factory, input, output));
IUniswapV2Pair pair = IUniswapV2Pair(PancakeLibrary.pairFor(factory, input, output));
uint amountInput;
uint amountOutput;
{ // scope to avoid stack too deep errors
Expand Down
22 changes: 11 additions & 11 deletions contracts/PancakeRouter01.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
pragma solidity =0.6.6;

import '@uniswap/v2-core/contracts/interfaces/IPancakeFactory.sol';
import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol';
import '@uniswap/lib/contracts/libraries/TransferHelper.sol';

import './libraries/PancakeLibrary.sol';
Expand All @@ -26,7 +26,7 @@ contract PancakeRouter01 is IPancakeRouter01 {
assert(msg.sender == WETH); // only accept ETH via fallback from the WETH contract
}

// **** ADD LIQUIDITY ****
// **** ADD LIQUIDITY ****
function _addLiquidity(
address tokenA,
address tokenB,
Expand All @@ -36,8 +36,8 @@ contract PancakeRouter01 is IPancakeRouter01 {
uint amountBMin
) private returns (uint amountA, uint amountB) {
// create the pair if it doesn't exist yet
if (IPancakeFactory(factory).getPair(tokenA, tokenB) == address(0)) {
IPancakeFactory(factory).createPair(tokenA, tokenB);
if (IUniswapV2Factory(factory).getPair(tokenA, tokenB) == address(0)) {
IUniswapV2Factory(factory).createPair(tokenA, tokenB);
}
(uint reserveA, uint reserveB) = PancakeLibrary.getReserves(factory, tokenA, tokenB);
if (reserveA == 0 && reserveB == 0) {
Expand Down Expand Up @@ -69,7 +69,7 @@ contract PancakeRouter01 is IPancakeRouter01 {
address pair = PancakeLibrary.pairFor(factory, tokenA, tokenB);
TransferHelper.safeTransferFrom(tokenA, msg.sender, pair, amountA);
TransferHelper.safeTransferFrom(tokenB, msg.sender, pair, amountB);
liquidity = IPancakePair(pair).mint(to);
liquidity = IUniswapV2Pair(pair).mint(to);
}
function addLiquidityETH(
address token,
Expand All @@ -91,7 +91,7 @@ contract PancakeRouter01 is IPancakeRouter01 {
TransferHelper.safeTransferFrom(token, msg.sender, pair, amountToken);
IWETH(WETH).deposit{value: amountETH}();
assert(IWETH(WETH).transfer(pair, amountETH));
liquidity = IPancakePair(pair).mint(to);
liquidity = IUniswapV2Pair(pair).mint(to);
if (msg.value > amountETH) TransferHelper.safeTransferETH(msg.sender, msg.value - amountETH); // refund dust eth, if any
}

Expand All @@ -106,8 +106,8 @@ contract PancakeRouter01 is IPancakeRouter01 {
uint deadline
) public override ensure(deadline) returns (uint amountA, uint amountB) {
address pair = PancakeLibrary.pairFor(factory, tokenA, tokenB);
IPancakePair(pair).transferFrom(msg.sender, pair, liquidity); // send liquidity to pair
(uint amount0, uint amount1) = IPancakePair(pair).burn(to);
IUniswapV2Pair(pair).transferFrom(msg.sender, pair, liquidity); // send liquidity to pair
(uint amount0, uint amount1) = IUniswapV2Pair(pair).burn(to);
(address token0,) = PancakeLibrary.sortTokens(tokenA, tokenB);
(amountA, amountB) = tokenA == token0 ? (amount0, amount1) : (amount1, amount0);
require(amountA >= amountAMin, 'PancakeRouter: INSUFFICIENT_A_AMOUNT');
Expand Down Expand Up @@ -146,7 +146,7 @@ contract PancakeRouter01 is IPancakeRouter01 {
) external override returns (uint amountA, uint amountB) {
address pair = PancakeLibrary.pairFor(factory, tokenA, tokenB);
uint value = approveMax ? uint(-1) : liquidity;
IPancakePair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
IUniswapV2Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
(amountA, amountB) = removeLiquidity(tokenA, tokenB, liquidity, amountAMin, amountBMin, to, deadline);
}
function removeLiquidityETHWithPermit(
Expand All @@ -160,7 +160,7 @@ contract PancakeRouter01 is IPancakeRouter01 {
) external override returns (uint amountToken, uint amountETH) {
address pair = PancakeLibrary.pairFor(factory, token, WETH);
uint value = approveMax ? uint(-1) : liquidity;
IPancakePair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
IUniswapV2Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
(amountToken, amountETH) = removeLiquidityETH(token, liquidity, amountTokenMin, amountETHMin, to, deadline);
}

Expand All @@ -173,7 +173,7 @@ contract PancakeRouter01 is IPancakeRouter01 {
uint amountOut = amounts[i + 1];
(uint amount0Out, uint amount1Out) = input == token0 ? (uint(0), amountOut) : (amountOut, uint(0));
address to = i < path.length - 2 ? PancakeLibrary.pairFor(factory, output, path[i + 2]) : _to;
IPancakePair(PancakeLibrary.pairFor(factory, input, output)).swap(amount0Out, amount1Out, to, new bytes(0));
IUniswapV2Pair(PancakeLibrary.pairFor(factory, input, output)).swap(amount0Out, amount1Out, to, new bytes(0));
}
}
function swapExactTokensForTokens(
Expand Down
14 changes: 14 additions & 0 deletions contracts/WETH.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract WETH is ERC20, Ownable {
constructor() public ERC20("WETH", "WETH") {
_mint(msg.sender, 100000 ether);
}

function mint(address account, uint256 amount) external onlyOwner {
_mint(account, amount);
}
}
14 changes: 14 additions & 0 deletions contracts/YellowToken.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract YellowToken is ERC20, Ownable {
constructor() public ERC20("YELO", "YELO") {
_mint(msg.sender, 100000 ether);
}

function mint(address account, uint256 amount) external onlyOwner {
_mint(account, amount);
}
}
116 changes: 58 additions & 58 deletions contracts/examples/ExampleFlashSwap.sol
Original file line number Diff line number Diff line change
@@ -1,67 +1,67 @@
pragma solidity =0.6.6;

import '@uniswap/v2-core/contracts/interfaces/IPancakeCallee.sol';
// import '@uniswap/v2-core/contracts/interfaces/IPancakeCallee.sol';

import '../libraries/PancakeLibrary.sol';
import '../interfaces/V1/IUniswapV1Factory.sol';
import '../interfaces/V1/IUniswapV1Exchange.sol';
import '../interfaces/IPancakeRouter01.sol';
import '../interfaces/IERC20.sol';
import '../interfaces/IWETH.sol';
// import '../libraries/PancakeLibrary.sol';
// import '../interfaces/V1/IUniswapV1Factory.sol';
// import '../interfaces/V1/IUniswapV1Exchange.sol';
// import '../interfaces/IPancakeRouter01.sol';
// import '../interfaces/IERC20.sol';
// import '../interfaces/IWETH.sol';

contract ExampleFlashSwap is IPancakeCallee {
IUniswapV1Factory immutable factoryV1;
address immutable factory;
IWETH immutable WETH;
// contract ExampleFlashSwap is IPancakeCallee {
// IUniswapV1Factory immutable factoryV1;
// address immutable factory;
// IWETH immutable WETH;

constructor(address _factory, address _factoryV1, address router) public {
factoryV1 = IUniswapV1Factory(_factoryV1);
factory = _factory;
WETH = IWETH(IPancakeRouter01(router).WETH());
}
// constructor(address _factory, address _factoryV1, address router) public {
// factoryV1 = IUniswapV1Factory(_factoryV1);
// factory = _factory;
// WETH = IWETH(IPancakeRouter01(router).WETH());
// }

// needs to accept ETH from any V1 exchange and WETH. ideally this could be enforced, as in the router,
// but it's not possible because it requires a call to the v1 factory, which takes too much gas
receive() external payable {}
// // needs to accept ETH from any V1 exchange and WETH. ideally this could be enforced, as in the router,
// // but it's not possible because it requires a call to the v1 factory, which takes too much gas
// receive() external payable {}

// gets tokens/WETH via a V2 flash swap, swaps for the ETH/tokens on V1, repays V2, and keeps the rest!
function pancakeCall(address sender, uint amount0, uint amount1, bytes calldata data) external override {
address[] memory path = new address[](2);
uint amountToken;
uint amountETH;
{ // scope for token{0,1}, avoids stack too deep errors
address token0 = IPancakePair(msg.sender).token0();
address token1 = IPancakePair(msg.sender).token1();
assert(msg.sender == PancakeLibrary.pairFor(factory, token0, token1)); // ensure that msg.sender is actually a V2 pair
assert(amount0 == 0 || amount1 == 0); // this strategy is unidirectional
path[0] = amount0 == 0 ? token0 : token1;
path[1] = amount0 == 0 ? token1 : token0;
amountToken = token0 == address(WETH) ? amount1 : amount0;
amountETH = token0 == address(WETH) ? amount0 : amount1;
}
// // gets tokens/WETH via a V2 flash swap, swaps for the ETH/tokens on V1, repays V2, and keeps the rest!
// function pancakeCall(address sender, uint amount0, uint amount1, bytes calldata data) external override {
// address[] memory path = new address[](2);
// uint amountToken;
// uint amountETH;
// { // scope for token{0,1}, avoids stack too deep errors
// address token0 = IPancakePair(msg.sender).token0();
// address token1 = IPancakePair(msg.sender).token1();
// assert(msg.sender == PancakeLibrary.pairFor(factory, token0, token1)); // ensure that msg.sender is actually a V2 pair
// assert(amount0 == 0 || amount1 == 0); // this strategy is unidirectional
// path[0] = amount0 == 0 ? token0 : token1;
// path[1] = amount0 == 0 ? token1 : token0;
// amountToken = token0 == address(WETH) ? amount1 : amount0;
// amountETH = token0 == address(WETH) ? amount0 : amount1;
// }

assert(path[0] == address(WETH) || path[1] == address(WETH)); // this strategy only works with a V2 WETH pair
IERC20 token = IERC20(path[0] == address(WETH) ? path[1] : path[0]);
IUniswapV1Exchange exchangeV1 = IUniswapV1Exchange(factoryV1.getExchange(address(token))); // get V1 exchange
// assert(path[0] == address(WETH) || path[1] == address(WETH)); // this strategy only works with a V2 WETH pair
// IERC20 token = IERC20(path[0] == address(WETH) ? path[1] : path[0]);
// IUniswapV1Exchange exchangeV1 = IUniswapV1Exchange(factoryV1.getExchange(address(token))); // get V1 exchange

if (amountToken > 0) {
(uint minETH) = abi.decode(data, (uint)); // slippage parameter for V1, passed in by caller
token.approve(address(exchangeV1), amountToken);
uint amountReceived = exchangeV1.tokenToEthSwapInput(amountToken, minETH, uint(-1));
uint amountRequired = PancakeLibrary.getAmountsIn(factory, amountToken, path)[0];
assert(amountReceived > amountRequired); // fail if we didn't get enough ETH back to repay our flash loan
WETH.deposit{value: amountRequired}();
assert(WETH.transfer(msg.sender, amountRequired)); // return WETH to V2 pair
(bool success,) = sender.call{value: amountReceived - amountRequired}(new bytes(0)); // keep the rest! (ETH)
assert(success);
} else {
(uint minTokens) = abi.decode(data, (uint)); // slippage parameter for V1, passed in by caller
WETH.withdraw(amountETH);
uint amountReceived = exchangeV1.ethToTokenSwapInput{value: amountETH}(minTokens, uint(-1));
uint amountRequired = PancakeLibrary.getAmountsIn(factory, amountETH, path)[0];
assert(amountReceived > amountRequired); // fail if we didn't get enough tokens back to repay our flash loan
assert(token.transfer(msg.sender, amountRequired)); // return tokens to V2 pair
assert(token.transfer(sender, amountReceived - amountRequired)); // keep the rest! (tokens)
}
}
}
// if (amountToken > 0) {
// (uint minETH) = abi.decode(data, (uint)); // slippage parameter for V1, passed in by caller
// token.approve(address(exchangeV1), amountToken);
// uint amountReceived = exchangeV1.tokenToEthSwapInput(amountToken, minETH, uint(-1));
// uint amountRequired = PancakeLibrary.getAmountsIn(factory, amountToken, path)[0];
// assert(amountReceived > amountRequired); // fail if we didn't get enough ETH back to repay our flash loan
// WETH.deposit{value: amountRequired}();
// assert(WETH.transfer(msg.sender, amountRequired)); // return WETH to V2 pair
// (bool success,) = sender.call{value: amountReceived - amountRequired}(new bytes(0)); // keep the rest! (ETH)
// assert(success);
// } else {
// (uint minTokens) = abi.decode(data, (uint)); // slippage parameter for V1, passed in by caller
// WETH.withdraw(amountETH);
// uint amountReceived = exchangeV1.ethToTokenSwapInput{value: amountETH}(minTokens, uint(-1));
// uint amountRequired = PancakeLibrary.getAmountsIn(factory, amountETH, path)[0];
// assert(amountReceived > amountRequired); // fail if we didn't get enough tokens back to repay our flash loan
// assert(token.transfer(msg.sender, amountRequired)); // return tokens to V2 pair
// assert(token.transfer(sender, amountReceived - amountRequired)); // keep the rest! (tokens)
// }
// }
// }
Loading