From 78ef3762a9c43900a9ea5701be90ab1d0012b5ac Mon Sep 17 00:00:00 2001 From: LanceUp Date: Mon, 3 May 2021 17:38:44 -0300 Subject: [PATCH 1/5] feat: booJoint --- contracts/BooJointWftmBoo.sol | 260 ++++++++++++++++++ .../{BooJoint.sol => BooJointWftmFusdt.sol} | 0 .../{CakeJoint.sol => CakeJointBnbEth.sol} | 0 3 files changed, 260 insertions(+) create mode 100644 contracts/BooJointWftmBoo.sol rename contracts/{BooJoint.sol => BooJointWftmFusdt.sol} (100%) rename contracts/{CakeJoint.sol => CakeJointBnbEth.sol} (100%) diff --git a/contracts/BooJointWftmBoo.sol b/contracts/BooJointWftmBoo.sol new file mode 100644 index 0000000..532c8d3 --- /dev/null +++ b/contracts/BooJointWftmBoo.sol @@ -0,0 +1,260 @@ +// SPDX-License-Identifier: AGPL-3.0 +pragma solidity 0.6.12; +pragma experimental ABIEncoderV2; + +import { + SafeERC20, + SafeMath, + IERC20, + Address +} from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; +import "@openzeppelin/contracts/math/Math.sol"; + +import "../interfaces/uni/IUniswapV2Router02.sol"; +import "../interfaces/uni/IUniswapV2Factory.sol"; +import "../interfaces/IMasterChef.sol"; + +interface IERC20Extended { + function decimals() external view returns (uint8); + + function name() external view returns (string memory); + + function symbol() external view returns (string memory); +} + +contract BooJointWftmBoo { + using SafeERC20 for IERC20; + using Address for address; + using SafeMath for uint256; + + address public tokenA; + address public providerA; + address public tokenB; + address public providerB; + + address public governance; + address public pendingGovernance; + address public strategist; + address public WETH; + address public reward; + address public router; + uint256 public pid; + IMasterchef public masterchef; + + modifier onlyGov { + require(msg.sender == governance); + _; + } + + modifier onlyGovOrStrategist { + require(msg.sender == governance || msg.sender == strategist); + _; + } + + constructor( + address _governance, + address _strategist, + address _tokenA, + address _tokenB, + address _router, + uint256 _pid + ) public { + _initialize(_governance, _strategist, _tokenA, _tokenB, _router, _pid); + } + + function _initialize( + address _governance, + address _strategist, + address _tokenA, + address _tokenB, + address _router, + uint256 _pid + ) internal { + require(address(tokenA) == address(0), "Joint already initialized"); + + governance = _governance; + strategist = _strategist; + tokenA = _tokenA; + tokenB = _tokenB; + router = _router; + pid = _pid; + + masterchef = IMasterchef( + address(0x2b2929E785374c651a81A63878Ab22742656DcDd) + ); + + reward = address(0x841FAD6EAe12c286d1Fd18d1d525DFfA75C7EFFE); + WETH = address(0x21be370D5312f44cB42ce377BC9b8a0cEF1A4C83); + + IERC20(getPair()).approve(address(masterchef), type(uint256).max); + IERC20(tokenA).approve(address(router), type(uint256).max); + IERC20(tokenB).approve(address(router), type(uint256).max); + IERC20(reward).approve(address(router), type(uint256).max); + IERC20(getPair()).approve(address(router), type(uint256).max); + } + + function name() external view returns (string memory) { + string memory ab = + string( + abi.encodePacked( + IERC20Extended(address(tokenA)).symbol(), + IERC20Extended(address(tokenB)).symbol() + ) + ); + + return string(abi.encodePacked("BooJointOf", ab)); + } + + function createLP() internal { + IUniswapV2Router02(router).addLiquidity( + tokenA, + tokenB, + balanceOfA(), + balanceOfB(), + 0, + 0, + address(this), + now + ); + } + + function depositLP() internal { + if (balanceOfPair() > 0) masterchef.deposit(pid, balanceOfPair()); + } + + function getReward() external onlyGovOrStrategist { + masterchef.deposit(pid, 0); + } + + function invest() external onlyGovOrStrategist { + createLP(); + depositLP(); + } + + // If there is a lot of impermanent loss, some capital will need to be sold + // To make both sides even + function sellCapital( + address _tokenFrom, + address _tokenTo, + uint256 _amount + ) external onlyGovOrStrategist { + IUniswapV2Router02(router) + .swapExactTokensForTokensSupportingFeeOnTransferTokens( + _amount, + 0, + getTokenOutPath(_tokenFrom, _tokenTo), + address(this), + now + ); + } + + function liquidatePosition() external onlyGovOrStrategist { + masterchef.withdraw(pid, balanceOfStake()); + IUniswapV2Router02(router).removeLiquidity( + tokenA, + tokenB, + balanceOfPair(), + 0, + 0, + address(this), + now + ); + } + + function distributeProfit() external onlyGovOrStrategist { + uint256 balanceA = balanceOfA(); + if (balanceA > 0) { + IERC20(tokenA).transfer(providerA, balanceA); + } + + uint256 balanceB = balanceOfB(); + if (balanceB > 0) { + IERC20(tokenB).transfer(providerB, balanceB); + } + } + + function setMasterChef(address _masterchef) external onlyGov { + masterchef = IMasterchef(_masterchef); + IERC20(getPair()).approve(_masterchef, type(uint256).max); + } + + function setPid(uint256 _newPid) external onlyGov { + pid = _newPid; + } + + function setWETH(address _weth) external onlyGov { + WETH = _weth; + } + + function getTokenOutPath(address _token_in, address _token_out) + internal + view + returns (address[] memory _path) + { + bool is_weth = + _token_in == address(WETH) || _token_out == address(WETH); + _path = new address[](is_weth ? 2 : 3); + _path[0] = _token_in; + if (is_weth) { + _path[1] = _token_out; + } else { + _path[1] = address(WETH); + _path[2] = _token_out; + } + } + + function getPair() public view returns (address) { + address factory = IUniswapV2Router02(router).factory(); + return IUniswapV2Factory(factory).getPair(tokenA, tokenB); + } + + function balanceOfPair() public view returns (uint256) { + return IERC20(getPair()).balanceOf(address(this)); + } + + function balanceOfA() public view returns (uint256) { + return IERC20(tokenA).balanceOf(address(this)); + } + + function balanceOfB() public view returns (uint256) { + return IERC20(tokenB).balanceOf(address(this)); + } + + function balanceOfReward() public view returns (uint256) { + return IERC20(reward).balanceOf(address(this)); + } + + function balanceOfStake() public view returns (uint256) { + return masterchef.userInfo(pid, address(this)).amount; + } + + function pendingReward() public view returns (uint256) { + return masterchef.pendingCake(pid, address(this)); + } + + function setProviderA(address _providerA) external onlyGov { + providerA = _providerA; + } + + function setProviderB(address _providerB) external onlyGov { + providerB = _providerB; + } + + function setReward(address _reward) external onlyGov { + reward = _reward; + } + + function setStrategist(address _strategist) external onlyGov { + strategist = _strategist; + } + + function setPendingGovernance(address _pendingGovernance) external onlyGov { + pendingGovernance = _pendingGovernance; + } + + function acceptGovernor() external { + require(msg.sender == pendingGovernance); + governance = pendingGovernance; + pendingGovernance = address(0); + } +} diff --git a/contracts/BooJoint.sol b/contracts/BooJointWftmFusdt.sol similarity index 100% rename from contracts/BooJoint.sol rename to contracts/BooJointWftmFusdt.sol diff --git a/contracts/CakeJoint.sol b/contracts/CakeJointBnbEth.sol similarity index 100% rename from contracts/CakeJoint.sol rename to contracts/CakeJointBnbEth.sol From 3a53dfb2d474699dde4f175936a092330f4ec64b Mon Sep 17 00:00:00 2001 From: LanceUp Date: Mon, 3 May 2021 18:09:38 -0300 Subject: [PATCH 2/5] feat: booJointV2 --- .../{BooJointWftmBoo.sol => BooJoint.sol} | 0 contracts/BooJointWftmFusdt.sol | 257 ------------------ .../{CakeJointBnbEth.sol => CakeJoint.sol} | 0 3 files changed, 257 deletions(-) rename contracts/{BooJointWftmBoo.sol => BooJoint.sol} (100%) delete mode 100644 contracts/BooJointWftmFusdt.sol rename contracts/{CakeJointBnbEth.sol => CakeJoint.sol} (100%) diff --git a/contracts/BooJointWftmBoo.sol b/contracts/BooJoint.sol similarity index 100% rename from contracts/BooJointWftmBoo.sol rename to contracts/BooJoint.sol diff --git a/contracts/BooJointWftmFusdt.sol b/contracts/BooJointWftmFusdt.sol deleted file mode 100644 index 9562a58..0000000 --- a/contracts/BooJointWftmFusdt.sol +++ /dev/null @@ -1,257 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.6.12; -pragma experimental ABIEncoderV2; - -import { - SafeERC20, - SafeMath, - IERC20, - Address -} from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; -import "@openzeppelin/contracts/math/Math.sol"; - -import "../interfaces/uni/IUniswapV2Router02.sol"; -import "../interfaces/uni/IUniswapV2Factory.sol"; -import "../interfaces/IMasterChef.sol"; - -interface IERC20Extended { - function decimals() external view returns (uint8); - - function name() external view returns (string memory); - - function symbol() external view returns (string memory); -} - -contract BooJoint { - using SafeERC20 for IERC20; - using Address for address; - using SafeMath for uint256; - - address public tokenA; - address public providerA; - address public tokenB; - address public providerB; - - address public governance; - address public pendingGovernance; - address public strategist; - address public WETH; - address public reward; - address public router; - uint256 public pid; - IMasterchef public masterchef; - - modifier onlyGov { - require(msg.sender == governance); - _; - } - - modifier onlyGovOrStrategist { - require(msg.sender == governance || msg.sender == strategist); - _; - } - - constructor( - address _governance, - address _strategist, - address _tokenA, - address _tokenB, - address _router - ) public { - _initialize(_governance, _strategist, _tokenA, _tokenB, _router); - } - - function _initialize( - address _governance, - address _strategist, - address _tokenA, - address _tokenB, - address _router - ) internal { - require(address(tokenA) == address(0), "Joint already initialized"); - - governance = _governance; - strategist = _strategist; - tokenA = _tokenA; - tokenB = _tokenB; - router = _router; - pid = 1; - - masterchef = IMasterchef( - address(0x2b2929E785374c651a81A63878Ab22742656DcDd) - ); - reward = address(0x841FAD6EAe12c286d1Fd18d1d525DFfA75C7EFFE); - WETH = address(0x21be370D5312f44cB42ce377BC9b8a0cEF1A4C83); - - IERC20(getPair()).approve(address(masterchef), type(uint256).max); - IERC20(tokenA).approve(address(router), type(uint256).max); - IERC20(tokenB).approve(address(router), type(uint256).max); - IERC20(reward).approve(address(router), type(uint256).max); - IERC20(getPair()).approve(address(router), type(uint256).max); - } - - function name() external view returns (string memory) { - string memory ab = - string( - abi.encodePacked( - IERC20Extended(address(tokenA)).symbol(), - IERC20Extended(address(tokenB)).symbol() - ) - ); - - return string(abi.encodePacked("BooJointOf", ab)); - } - - function createLP() internal { - IUniswapV2Router02(router).addLiquidity( - tokenA, - tokenB, - balanceOfA(), - balanceOfB(), - 0, - 0, - address(this), - now - ); - } - - function depositLP() internal { - if (balanceOfPair() > 0) masterchef.deposit(pid, balanceOfPair()); - } - - function getReward() external onlyGovOrStrategist { - masterchef.deposit(pid, 0); - } - - function invest() external onlyGovOrStrategist { - createLP(); - depositLP(); - } - - // If there is a lot of impermanent loss, some capital will need to be sold - // To make both sides even - function sellCapital( - address _tokenFrom, - address _tokenTo, - uint256 _amount - ) external onlyGovOrStrategist { - IUniswapV2Router02(router) - .swapExactTokensForTokensSupportingFeeOnTransferTokens( - _amount, - 0, - getTokenOutPath(_tokenFrom, _tokenTo), - address(this), - now - ); - } - - function liquidatePosition() external onlyGovOrStrategist { - masterchef.withdraw(pid, balanceOfStake()); - IUniswapV2Router02(router).removeLiquidity( - tokenA, - tokenB, - balanceOfPair(), - 0, - 0, - address(this), - now - ); - } - - function distributeProfit() external onlyGovOrStrategist { - uint256 balanceA = balanceOfA(); - if (balanceA > 0) { - IERC20(tokenA).transfer(providerA, balanceA); - } - - uint256 balanceB = balanceOfB(); - if (balanceB > 0) { - IERC20(tokenB).transfer(providerB, balanceB); - } - } - - function setMasterChef(address _masterchef) external onlyGov { - masterchef = IMasterchef(_masterchef); - IERC20(getPair()).approve(_masterchef, type(uint256).max); - } - - function setPid(uint256 _newPid) external onlyGov { - pid = _newPid; - } - - function setWETH(address _weth) external onlyGov { - WETH = _weth; - } - - function getTokenOutPath(address _token_in, address _token_out) - internal - view - returns (address[] memory _path) - { - bool is_weth = - _token_in == address(WETH) || _token_out == address(WETH); - _path = new address[](is_weth ? 2 : 3); - _path[0] = _token_in; - if (is_weth) { - _path[1] = _token_out; - } else { - _path[1] = address(WETH); - _path[2] = _token_out; - } - } - - function getPair() public view returns (address) { - address factory = IUniswapV2Router02(router).factory(); - return IUniswapV2Factory(factory).getPair(tokenA, tokenB); - } - - function balanceOfPair() public view returns (uint256) { - return IERC20(getPair()).balanceOf(address(this)); - } - - function balanceOfA() public view returns (uint256) { - return IERC20(tokenA).balanceOf(address(this)); - } - - function balanceOfB() public view returns (uint256) { - return IERC20(tokenB).balanceOf(address(this)); - } - - function balanceOfReward() public view returns (uint256) { - return IERC20(reward).balanceOf(address(this)); - } - - function balanceOfStake() public view returns (uint256) { - return masterchef.userInfo(pid, address(this)).amount; - } - - function pendingReward() public view returns (uint256) { - return masterchef.pendingBOO(pid, address(this)); - } - - function setProviderA(address _providerA) external onlyGov { - providerA = _providerA; - } - - function setProviderB(address _providerB) external onlyGov { - providerB = _providerB; - } - - function setReward(address _reward) external onlyGov { - reward = _reward; - } - - function setStrategist(address _strategist) external onlyGov { - strategist = _strategist; - } - - function setPendingGovernance(address _pendingGovernance) external onlyGov { - pendingGovernance = _pendingGovernance; - } - - function acceptGovernor() external { - require(msg.sender == pendingGovernance); - governance = pendingGovernance; - pendingGovernance = address(0); - } -} diff --git a/contracts/CakeJointBnbEth.sol b/contracts/CakeJoint.sol similarity index 100% rename from contracts/CakeJointBnbEth.sol rename to contracts/CakeJoint.sol From c95505d67b13a600648782f1396b443175657e39 Mon Sep 17 00:00:00 2001 From: LanceUp Date: Mon, 3 May 2021 18:31:29 -0300 Subject: [PATCH 3/5] feat: BooJointV3 --- contracts/BooJoint.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/BooJoint.sol b/contracts/BooJoint.sol index 532c8d3..5e926a3 100644 --- a/contracts/BooJoint.sol +++ b/contracts/BooJoint.sol @@ -22,7 +22,7 @@ interface IERC20Extended { function symbol() external view returns (string memory); } -contract BooJointWftmBoo { +contract BooJoint { using SafeERC20 for IERC20; using Address for address; using SafeMath for uint256; @@ -229,7 +229,7 @@ contract BooJointWftmBoo { } function pendingReward() public view returns (uint256) { - return masterchef.pendingCake(pid, address(this)); + return masterchef.pendingBoo(pid, address(this)); } function setProviderA(address _providerA) external onlyGov { From 6d40ba82df648c1fd884bfe0105c2c6201b44e40 Mon Sep 17 00:00:00 2001 From: LanceUp Date: Mon, 3 May 2021 22:00:20 -0300 Subject: [PATCH 4/5] feat: BooJointV4 --- contracts/BooJoint.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/BooJoint.sol b/contracts/BooJoint.sol index 5e926a3..253f7be 100644 --- a/contracts/BooJoint.sol +++ b/contracts/BooJoint.sol @@ -229,7 +229,7 @@ contract BooJoint { } function pendingReward() public view returns (uint256) { - return masterchef.pendingBoo(pid, address(this)); + return masterchef.pendingBOO(pid, address(this)); } function setProviderA(address _providerA) external onlyGov { From bd17d2373c747cd12eaf9921ed51d8114f489550 Mon Sep 17 00:00:00 2001 From: LanceUp Date: Wed, 19 May 2021 20:05:36 -0300 Subject: [PATCH 5/5] feat: name of joint --- contracts/CakeJoint.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/CakeJoint.sol b/contracts/CakeJoint.sol index b8082cf..01a2998 100644 --- a/contracts/CakeJoint.sol +++ b/contracts/CakeJoint.sol @@ -105,7 +105,7 @@ contract CakeJoint { ) ); - return string(abi.encodePacked("BooJointOf", ab)); + return string(abi.encodePacked("JointOf", ab)); } function createLP() internal {