Diff
checker
Text
Text
Bilder
Dokumente
Excel
Ordner
Legal
Enterprise
Desktop-App
Preise
Einloggen
Diffchecker Desktop herunterladen
Texte vergleichen
Finde den Unterschied zwischen zwei Textdateien
Werkzeuge
Verlauf
Live-Editor
Gleiches ausblenden
Zeilenumbruch aus
Ansicht
Zweispaltig
Einspaltig
Vergleichsgenauigkeit
Intelligent
Wort
Zeichen
Syntaxhervorhebung
Syntax auswählen
Ignorieren
Text umwandeln
Zur ersten Änderung
Eingabe bearbeiten
Diffchecker Desktop
Der sicherste Weg, Diffchecker zu nutzen. Hol dir die Desktop-App: Deine Diffs verlassen nie deinen Computer!
Desktop holen
VaultSushiFlipToFlip.sol
Erstellt
vor 5 Jahren
Diff läuft nie ab
Löschen
Exportieren
Teilen
Erklären
0 Entfernungen
Zeilen
Gesamt
Entfernt
Zeichen
Gesamt
Entfernt
Um diese Funktion weiterhin zu nutzen, aktualisiere auf
Diff
checker
Pro
Preise anzeigen
310 Zeilen
Kopieren
17 Hinzufügungen
Zeilen
Gesamt
Hinzugefügt
Zeichen
Gesamt
Hinzugefügt
Um diese Funktion weiterhin zu nutzen, aktualisiere auf
Diff
checker
Pro
Preise anzeigen
327 Zeilen
Kopieren
// SPDX-License-Identifier: MIT
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;
pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;
pragma experimental ABIEncoderV2;
/*
/*
___ _ _
___ _ _
| _ )_ _ _ _ _ _ _ _ | | | |
| _ )_ _ _ _ _ _ _ _ | | | |
| _ \ || | ' \| ' \ || | |_| |_|
| _ \ || | ' \| ' \ || | |_| |_|
|___/\_,_|_||_|_||_\_, | (_) (_)
|___/\_,_|_||_|_||_\_, | (_) (_)
|__/
|__/
*
*
* MIT License
* MIT License
* ===========
* ===========
*
*
* Copyright (c) 2020 BunnyFinance
* Copyright (c) 2020 BunnyFinance
*
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* furnished to do so, subject to the following conditions:
*
*
* The above copyright notice and this permission notice shall be included in all
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* copies or substantial portions of the Software.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
*/
*/
import "@pancakeswap/pancake-swap-lib/contracts/token/BEP20/SafeBEP20.sol";
import "@pancakeswap/pancake-swap-lib/contracts/token/BEP20/SafeBEP20.sol";
import "@openzeppelin/contracts/math/Math.sol";
import "@openzeppelin/contracts/math/Math.sol";
import {PoolConstant} from "../library/PoolConstant.sol";
import {PoolConstant} from "../library/PoolConstant.sol";
import "../interfaces/IUniswapV2Pair.sol";
import "../interfaces/IUniswapV2Pair.sol";
import "../interfaces/IUniswapV2Factory.sol";
import "../interfaces/IUniswapV2Factory.sol";
import "../interfaces/IStrategy.sol";
import "../interfaces/IStrategy.sol";
import "../interfaces/ISushiMiniChefV2.sol";
import "../interfaces/ISushiMiniChefV2.sol";
import "../interfaces/IZap.sol";
import "../interfaces/IZap.sol";
import "./VaultController.sol";
import "./VaultController.sol";
contract VaultSushiFlipToFlip is VaultController, IStrategy {
contract VaultSushiFlipToFlip is VaultController, IStrategy {
using SafeBEP20 for IBEP20;
using SafeBEP20 for IBEP20;
using SafeMath for uint256;
using SafeMath for uint256;
/* ========== CONSTANTS ============= */
/* ========== CONSTANTS ============= */
IBEP20 private constant SUSHI = IBEP20(0x0b3F868E0BE5597D5DB7fEB59E1CADBb0fdDa50a);
IBEP20 private constant SUSHI = IBEP20(0x0b3F868E0BE5597D5DB7fEB59E1CADBb0fdDa50a);
IBEP20 private constant WMATIC = IBEP20(0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270);
IBEP20 private constant WMATIC = IBEP20(0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270);
PoolConstant.PoolTypes public constant override poolType = PoolConstant.PoolTypes.FlipToFlip;
PoolConstant.PoolTypes public constant override poolType = PoolConstant.PoolTypes.FlipToFlip;
ISushiMiniChefV2 private constant SUSHI_MINI_CHEF = ISushiMiniChefV2(0x0769fd68dFb93167989C6f7254cd0D766Fb2841F);
ISushiMiniChefV2 private constant SUSHI_MINI_CHEF = ISushiMiniChefV2(0x0769fd68dFb93167989C6f7254cd0D766Fb2841F);
IZap private constant zap = IZap(0x93bCE7E49E26AF0f87b74583Ba6551DF5E4867B7);
IZap private constant zap = IZap(0x93bCE7E49E26AF0f87b74583Ba6551DF5E4867B7);
uint private constant DUST = 1000;
uint private constant DUST = 1000;
/* ========== STATE VARIABLES ========== */
/* ========== STATE VARIABLES ========== */
uint public override pid;
uint public override pid;
address private _token0;
address private _token0;
address private _token1;
address private _token1;
uint public totalShares;
uint public totalShares;
mapping (address => uint) private _shares;
mapping (address => uint) private _shares;
mapping (address => uint) private _principal;
mapping (address => uint) private _principal;
mapping (address => uint) private _depositedAt;
mapping (address => uint) private _depositedAt;
uint public sushiHarvested;
uint public sushiHarvested;
uint public wmaticHarvested;
uint public wmaticHarvested;
Kopieren
Kopiert
Kopieren
Kopiert
uint public totalBalance;
/* ========== MODIFIER ========== */
/* ========== MODIFIER ========== */
modifier updateSushiHarvested {
modifier updateSushiHarvested {
uint _before = SUSHI.balanceOf(address(this));
uint _before = SUSHI.balanceOf(address(this));
uint _beforeWmatic = WMATIC.balanceOf(address(this));
uint _beforeWmatic = WMATIC.balanceOf(address(this));
_;
_;
uint _after = SUSHI.balanceOf(address(this));
uint _after = SUSHI.balanceOf(address(this));
uint _afterWmatic = WMATIC.balanceOf(address(this));
uint _afterWmatic = WMATIC.balanceOf(address(this));
sushiHarvested = sushiHarvested.add(_after).sub(_before);
sushiHarvested = sushiHarvested.add(_after).sub(_before);
wmaticHarvested = wmaticHarvested.add(_afterWmatic).sub(_beforeWmatic);
wmaticHarvested = wmaticHarvested.add(_afterWmatic).sub(_beforeWmatic);
}
}
/* ========== INITIALIZER ========== */
/* ========== INITIALIZER ========== */
function initialize(uint _pid, address _token) external initializer {
function initialize(uint _pid, address _token) external initializer {
__VaultController_init(IBEP20(_token));
__VaultController_init(IBEP20(_token));
_stakingToken.safeApprove(address(SUSHI_MINI_CHEF), uint(- 1));
_stakingToken.safeApprove(address(SUSHI_MINI_CHEF), uint(- 1));
pid = _pid;
pid = _pid;
SUSHI.safeApprove(address(zap), uint(- 1));
SUSHI.safeApprove(address(zap), uint(- 1));
WMATIC.safeApprove(address(zap), uint(- 1));
WMATIC.safeApprove(address(zap), uint(- 1));
}
}
/* ========== VIEW FUNCTIONS ========== */
/* ========== VIEW FUNCTIONS ========== */
function totalSupply() external view override returns (uint) {
function totalSupply() external view override returns (uint) {
return totalShares;
return totalShares;
}
}
function balance() public view override returns (uint amount) {
function balance() public view override returns (uint amount) {
(amount,) = SUSHI_MINI_CHEF.userInfo(pid, address(this));
(amount,) = SUSHI_MINI_CHEF.userInfo(pid, address(this));
Kopieren
Kopiert
Kopieren
Kopiert
amount = Math.min(amount, totalBalance);
}
}
function balanceOf(address account) public view override returns(uint) {
function balanceOf(address account) public view override returns(uint) {
if (totalShares == 0) return 0;
if (totalShares == 0) return 0;
return balance().mul(sharesOf(account)).div(totalShares);
return balance().mul(sharesOf(account)).div(totalShares);
}
}
function withdrawableBalanceOf(address account) public view override returns (uint) {
function withdrawableBalanceOf(address account) public view override returns (uint) {
return balanceOf(account);
return balanceOf(account);
}
}
function sharesOf(address account) public view override returns (uint) {
function sharesOf(address account) public view override returns (uint) {
return _shares[account];
return _shares[account];
}
}
function principalOf(address account) public view override returns (uint) {
function principalOf(address account) public view override returns (uint) {
return _principal[account];
return _principal[account];
}
}
function earned(address account) public view override returns (uint) {
function earned(address account) public view override returns (uint) {
if (balanceOf(account) >= principalOf(account) + DUST) {
if (balanceOf(account) >= principalOf(account) + DUST) {
return balanceOf(account).sub(principalOf(account));
return balanceOf(account).sub(principalOf(account));
} else {
} else {
return 0;
return 0;
}
}
}
}
function depositedAt(address account) external view override returns (uint) {
function depositedAt(address account) external view override returns (uint) {
return _depositedAt[account];
return _depositedAt[account];
}
}
function rewardsToken() external view override returns (address) {
function rewardsToken() external view override returns (address) {
return address(_stakingToken);
return address(_stakingToken);
}
}
function priceShare() external view override returns(uint) {
function priceShare() external view override returns(uint) {
if (totalShares == 0) return 1e18;
if (totalShares == 0) return 1e18;
return balance().mul(1e18).div(totalShares);
return balance().mul(1e18).div(totalShares);
}
}
/* ========== MUTATIVE FUNCTIONS ========== */
/* ========== MUTATIVE FUNCTIONS ========== */
function deposit(uint _amount) public override {
function deposit(uint _amount) public override {
_depositTo(_amount, msg.sender);
_depositTo(_amount, msg.sender);
}
}
function depositAll() external override {
function depositAll() external override {
deposit(_stakingToken.balanceOf(msg.sender));
deposit(_stakingToken.balanceOf(msg.sender));
}
}
function withdrawAll() external override {
function withdrawAll() external override {
uint amount = balanceOf(msg.sender);
uint amount = balanceOf(msg.sender);
uint principal = principalOf(msg.sender);
uint principal = principalOf(msg.sender);
uint depositTimestamp = _depositedAt[msg.sender];
uint depositTimestamp = _depositedAt[msg.sender];
Kopieren
Kopiert
Kopieren
Kopiert
totalBalance = totalBalance.sub(amount);
totalShares = totalShares.sub(_shares[msg.sender]);
totalShares = totalShares.sub(_shares[msg.sender]);
delete _shares[msg.sender];
delete _shares[msg.sender];
delete _principal[msg.sender];
delete _principal[msg.sender];
delete _depositedAt[msg.sender];
delete _depositedAt[msg.sender];
amount = _withdrawTokenWithCorrection(amount);
amount = _withdrawTokenWithCorrection(amount);
uint profit = amount > principal ? amount.sub(principal) : 0;
uint profit = amount > principal ? amount.sub(principal) : 0;
uint withdrawalFee = canMint() ? _minter.withdrawalFee(principal, depositTimestamp) : 0;
uint withdrawalFee = canMint() ? _minter.withdrawalFee(principal, depositTimestamp) : 0;
uint performanceFee = canMint() ? _minter.performanceFee(profit) : 0;
uint performanceFee = canMint() ? _minter.performanceFee(profit) : 0;
if (withdrawalFee.add(performanceFee) > DUST) {
if (withdrawalFee.add(performanceFee) > DUST) {
_minter.mintForV2(address(_stakingToken), withdrawalFee, performanceFee, msg.sender, depositTimestamp);
_minter.mintForV2(address(_stakingToken), withdrawalFee, performanceFee, msg.sender, depositTimestamp);
if (performanceFee > 0) {
if (performanceFee > 0) {
emit ProfitPaid(msg.sender, profit, performanceFee);
emit ProfitPaid(msg.sender, profit, performanceFee);
}
}
amount = amount.sub(withdrawalFee).sub(performanceFee);
amount = amount.sub(withdrawalFee).sub(performanceFee);
}
}
_stakingToken.safeTransfer(msg.sender, amount);
_stakingToken.safeTransfer(msg.sender, amount);
emit Withdrawn(msg.sender, amount, withdrawalFee);
emit Withdrawn(msg.sender, amount, withdrawalFee);
}
}
function harvest() external override onlyKeeper {
function harvest() external override onlyKeeper {
_harvest();
_harvest();
uint before = _stakingToken.balanceOf(address(this));
uint before = _stakingToken.balanceOf(address(this));
zap.zapInToken(address(SUSHI), sushiHarvested, address(_stakingToken));
zap.zapInToken(address(SUSHI), sushiHarvested, address(_stakingToken));
zap.zapInToken(address(WMATIC), wmaticHarvested, address(_stakingToken));
zap.zapInToken(address(WMATIC), wmaticHarvested, address(_stakingToken));
uint harvested = _stakingToken.balanceOf(address(this)).sub(before);
uint harvested = _stakingToken.balanceOf(address(this)).sub(before);
Kopieren
Kopiert
Kopieren
Kopiert
totalBalance = totalBalance.add(harvested);
SUSHI_MINI_CHEF.deposit(pid, harvested, address(this));
SUSHI_MINI_CHEF.deposit(pid, harvested, address(this));
emit Harvested(harvested);
emit Harvested(harvested);
sushiHarvested = 0;
sushiHarvested = 0;
wmaticHarvested = 0;
wmaticHarvested = 0;
}
}
function _harvest() private updateSushiHarvested {
function _harvest() private updateSushiHarvested {
SUSHI_MINI_CHEF.harvest(pid, address(this));
SUSHI_MINI_CHEF.harvest(pid, address(this));
}
}
function withdraw(uint shares) external override onlyWhitelisted {
function withdraw(uint shares) external override onlyWhitelisted {
uint amount = balance().mul(shares).div(totalShares);
uint amount = balance().mul(shares).div(totalShares);
Kopieren
Kopiert
Kopieren
Kopiert
totalBalance = totalBalance.sub(amount);
totalShares = totalShares.sub(shares);
totalShares = totalShares.sub(shares);
_shares[msg.sender] = _shares[msg.sender].sub(shares);
_shares[msg.sender] = _shares[msg.sender].sub(shares);
amount = _withdrawTokenWithCorrection(amount);
amount = _withdrawTokenWithCorrection(amount);
_stakingToken.safeTransfer(msg.sender, amount);
_stakingToken.safeTransfer(msg.sender, amount);
emit Withdrawn(msg.sender, amount, 0);
emit Withdrawn(msg.sender, amount, 0);
}
}
// @dev underlying only + withdrawal fee + no perf fee
// @dev underlying only + withdrawal fee + no perf fee
function withdrawUnderlying(uint _amount) external {
function withdrawUnderlying(uint _amount) external {
uint amount = Math.min(_amount, _principal[msg.sender]);
uint amount = Math.min(_amount, _principal[msg.sender]);
uint shares = Math.min(amount.mul(totalShares).div(balance()), _shares[msg.sender]);
uint shares = Math.min(amount.mul(totalShares).div(balance()), _shares[msg.sender]);
Kopieren
Kopiert
Kopieren
Kopiert
totalBalance = totalBalance.sub(amount);
totalShares = totalShares.sub(shares);
totalShares = totalShares.sub(shares);
_shares[msg.sender] = _shares[msg.sender].sub(shares);
_shares[msg.sender] = _shares[msg.sender].sub(shares);
_principal[msg.sender] = _principal[msg.sender].sub(amount);
_principal[msg.sender] = _principal[msg.sender].sub(amount);
amount = _withdrawTokenWithCorrection(amount);
amount = _withdrawTokenWithCorrection(amount);
uint depositTimestamp = _depositedAt[msg.sender];
uint depositTimestamp = _depositedAt[msg.sender];
uint withdrawalFee = canMint() ? _minter.withdrawalFee(amount, depositTimestamp) : 0;
uint withdrawalFee = canMint() ? _minter.withdrawalFee(amount, depositTimestamp) : 0;
if (withdrawalFee > DUST) {
if (withdrawalFee > DUST) {
_minter.mintForV2(address(_stakingToken), withdrawalFee, 0, msg.sender, depositTimestamp);
_minter.mintForV2(address(_stakingToken), withdrawalFee, 0, msg.sender, depositTimestamp);
amount = amount.sub(withdrawalFee);
amount = amount.sub(withdrawalFee);
}
}
_stakingToken.safeTransfer(msg.sender, amount);
_stakingToken.safeTransfer(msg.sender, amount);
emit Withdrawn(msg.sender, amount, withdrawalFee);
emit Withdrawn(msg.sender, amount, withdrawalFee);
}
}
// @dev profits only (underlying + bunny) + no withdraw fee + perf fee
// @dev profits only (underlying + bunny) + no withdraw fee + perf fee
function getReward() external override {
function getReward() external override {
uint amount = earned(msg.sender);
uint amount = earned(msg.sender);
uint shares = Math.min(amount.mul(totalShares).div(balance()), _shares[msg.sender]);
uint shares = Math.min(amount.mul(totalShares).div(balance()), _shares[msg.sender]);
Kopieren
Kopiert
Kopieren
Kopiert
totalBalance = totalBalance.sub(amount);
totalShares = totalShares.sub(shares);
totalShares = totalShares.sub(shares);
_shares[msg.sender] = _shares[msg.sender].sub(shares);
_shares[msg.sender] = _shares[msg.sender].sub(shares);
_cleanupIfDustShares();
_cleanupIfDustShares();
amount = _withdrawTokenWithCorrection(amount);
amount = _withdrawTokenWithCorrection(amount);
uint depositTimestamp = _depositedAt[msg.sender];
uint depositTimestamp = _depositedAt[msg.sender];
uint performanceFee = canMint() ? _minter.performanceFee(amount) : 0;
uint performanceFee = canMint() ? _minter.performanceFee(amount) : 0;
if (performanceFee > DUST) {
if (performanceFee > DUST) {
_minter.mintForV2(address(_stakingToken), 0, performanceFee, msg.sender, depositTimestamp);
_minter.mintForV2(address(_stakingToken), 0, performanceFee, msg.sender, depositTimestamp);
amount = amount.sub(performanceFee);
amount = amount.sub(performanceFee);
}
}
_stakingToken.safeTransfer(msg.sender, amount);
_stakingToken.safeTransfer(msg.sender, amount);
emit ProfitPaid(msg.sender, amount, performanceFee);
emit ProfitPaid(msg.sender, amount, performanceFee);
}
}
/* ========== PRIVATE FUNCTIONS ========== */
/* ========== PRIVATE FUNCTIONS ========== */
function _depositTo(uint _amount, address _to) private notPaused updateSushiHarvested {
function _depositTo(uint _amount, address _to) private notPaused updateSushiHarvested {
uint _pool = balance();
uint _pool = balance();
uint _before = _stakingToken.balanceOf(address(this));
uint _before = _stakingToken.balanceOf(address(this));
_stakingToken.safeTransferFrom(msg.sender, address(this), _amount);
_stakingToken.safeTransferFrom(msg.sender, address(this), _amount);
uint _after = _stakingToken.balanceOf(address(this));
uint _after = _stakingToken.balanceOf(address(this));
_amount = _after.sub(_before); // Additional check for deflationary tokens
_amount = _after.sub(_before); // Additional check for deflationary tokens
uint shares = 0;
uint shares = 0;
if (totalShares == 0) {
if (totalShares == 0) {
shares = _amount;
shares = _amount;
} else {
} else {
shares = (_amount.mul(totalShares)).div(_pool);
shares = (_amount.mul(totalShares)).div(_pool);
}
}
Kopieren
Kopiert
Kopieren
Kopiert
totalBalance = totalBalance.add(_amount);
totalShares = totalShares.add(shares);
totalShares = totalShares.add(shares);
_shares[_to] = _shares[_to].add(shares);
_shares[_to] = _shares[_to].add(shares);
_principal[_to] = _principal[_to].add(_amount);
_principal[_to] = _principal[_to].add(_amount);
_depositedAt[_to] = block.timestamp;
_depositedAt[_to] = block.timestamp;
SUSHI_MINI_CHEF.deposit(pid, _amount, address(this));
SUSHI_MINI_CHEF.deposit(pid, _amount, address(this));
emit Deposited(_to, _amount);
emit Deposited(_to, _amount);
}
}
function _withdrawTokenWithCorrection(uint amount) private updateSushiHarvested returns (uint) {
function _withdrawTokenWithCorrection(uint amount) private updateSushiHarvested returns (uint) {
uint before = _stakingToken.balanceOf(address(this));
uint before = _stakingToken.balanceOf(address(this));
SUSHI_MINI_CHEF.withdraw(pid, amount, address(this));
SUSHI_MINI_CHEF.withdraw(pid, amount, address(this));
return _stakingToken.balanceOf(address(this)).sub(before);
return _stakingToken.balanceOf(address(this)).sub(before);
}
}
function _cleanupIfDustShares() private {
function _cleanupIfDustShares() private {
uint shares = _shares[msg.sender];
uint shares = _shares[msg.sender];
if (shares > 0 && shares < DUST) {
if (shares > 0 && shares < DUST) {
totalShares = totalShares.sub(shares);
totalShares = totalShares.sub(shares);
delete _shares[msg.sender];
delete _shares[msg.sender];
}
}
}
}
/* ========== SALVAGE PURPOSE ONLY ========== */
/* ========== SALVAGE PURPOSE ONLY ========== */
// @dev stakingToken must not remain balance in this contract. So dev should salvage staking token transferred by mistake.
// @dev stakingToken must not remain balance in this contract. So dev should salvage staking token transferred by mistake.
function recoverToken(address token, uint amount) external override onlyOwner {
function recoverToken(address token, uint amount) external override onlyOwner {
if (token == address(SUSHI)) {
if (token == address(SUSHI)) {
uint sushiBalance = SUSHI.balanceOf(address(this));
uint sushiBalance = SUSHI.balanceOf(address(this));
require(amount <= sushiBalance.sub(sushiHarvested), "VaultFlipToFlip: cannot recover lp's harvested sushi");
require(amount <= sushiBalance.sub(sushiHarvested), "VaultFlipToFlip: cannot recover lp's harvested sushi");
}
}
if (token == address(WMATIC)){
if (token == address(WMATIC)){
uint wmaticBalance = WMATIC.balanceOf(address(this));
uint wmaticBalance = WMATIC.balanceOf(address(this));
require(amount <= wmaticBalance.sub(wmaticHarvested));
require(amount <= wmaticBalance.sub(wmaticHarvested));
}
}
IBEP20(token).safeTransfer(owner(), amount);
IBEP20(token).safeTransfer(owner(), amount);
emit Recovered(token, amount);
emit Recovered(token, amount);
}
}
Kopieren
Kopiert
Kopieren
Kopiert
function setTotalBalance() external onlyOwner {
require(totalBalance == 0, "VaultSushiFlipToFlip: can't update totalBalance");
(uint amount,) = SUSHI_MINI_CHEF.userInfo(pid, address(this));
totalBalance = amount;
}
}
}
Kopieren
Kopiert
Kopieren
Kopiert
Gespeicherte Diffs
Originaltext
Datei öffnen
// SPDX-License-Identifier: MIT pragma solidity ^0.6.12; pragma experimental ABIEncoderV2; /* ___ _ _ | _ )_ _ _ _ _ _ _ _ | | | | | _ \ || | ' \| ' \ || | |_| |_| |___/\_,_|_||_|_||_\_, | (_) (_) |__/ * * MIT License * =========== * * Copyright (c) 2020 BunnyFinance * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ import "@pancakeswap/pancake-swap-lib/contracts/token/BEP20/SafeBEP20.sol"; import "@openzeppelin/contracts/math/Math.sol"; import {PoolConstant} from "../library/PoolConstant.sol"; import "../interfaces/IUniswapV2Pair.sol"; import "../interfaces/IUniswapV2Factory.sol"; import "../interfaces/IStrategy.sol"; import "../interfaces/ISushiMiniChefV2.sol"; import "../interfaces/IZap.sol"; import "./VaultController.sol"; contract VaultSushiFlipToFlip is VaultController, IStrategy { using SafeBEP20 for IBEP20; using SafeMath for uint256; /* ========== CONSTANTS ============= */ IBEP20 private constant SUSHI = IBEP20(0x0b3F868E0BE5597D5DB7fEB59E1CADBb0fdDa50a); IBEP20 private constant WMATIC = IBEP20(0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270); PoolConstant.PoolTypes public constant override poolType = PoolConstant.PoolTypes.FlipToFlip; ISushiMiniChefV2 private constant SUSHI_MINI_CHEF = ISushiMiniChefV2(0x0769fd68dFb93167989C6f7254cd0D766Fb2841F); IZap private constant zap = IZap(0x93bCE7E49E26AF0f87b74583Ba6551DF5E4867B7); uint private constant DUST = 1000; /* ========== STATE VARIABLES ========== */ uint public override pid; address private _token0; address private _token1; uint public totalShares; mapping (address => uint) private _shares; mapping (address => uint) private _principal; mapping (address => uint) private _depositedAt; uint public sushiHarvested; uint public wmaticHarvested; /* ========== MODIFIER ========== */ modifier updateSushiHarvested { uint _before = SUSHI.balanceOf(address(this)); uint _beforeWmatic = WMATIC.balanceOf(address(this)); _; uint _after = SUSHI.balanceOf(address(this)); uint _afterWmatic = WMATIC.balanceOf(address(this)); sushiHarvested = sushiHarvested.add(_after).sub(_before); wmaticHarvested = wmaticHarvested.add(_afterWmatic).sub(_beforeWmatic); } /* ========== INITIALIZER ========== */ function initialize(uint _pid, address _token) external initializer { __VaultController_init(IBEP20(_token)); _stakingToken.safeApprove(address(SUSHI_MINI_CHEF), uint(- 1)); pid = _pid; SUSHI.safeApprove(address(zap), uint(- 1)); WMATIC.safeApprove(address(zap), uint(- 1)); } /* ========== VIEW FUNCTIONS ========== */ function totalSupply() external view override returns (uint) { return totalShares; } function balance() public view override returns (uint amount) { (amount,) = SUSHI_MINI_CHEF.userInfo(pid, address(this)); } function balanceOf(address account) public view override returns(uint) { if (totalShares == 0) return 0; return balance().mul(sharesOf(account)).div(totalShares); } function withdrawableBalanceOf(address account) public view override returns (uint) { return balanceOf(account); } function sharesOf(address account) public view override returns (uint) { return _shares[account]; } function principalOf(address account) public view override returns (uint) { return _principal[account]; } function earned(address account) public view override returns (uint) { if (balanceOf(account) >= principalOf(account) + DUST) { return balanceOf(account).sub(principalOf(account)); } else { return 0; } } function depositedAt(address account) external view override returns (uint) { return _depositedAt[account]; } function rewardsToken() external view override returns (address) { return address(_stakingToken); } function priceShare() external view override returns(uint) { if (totalShares == 0) return 1e18; return balance().mul(1e18).div(totalShares); } /* ========== MUTATIVE FUNCTIONS ========== */ function deposit(uint _amount) public override { _depositTo(_amount, msg.sender); } function depositAll() external override { deposit(_stakingToken.balanceOf(msg.sender)); } function withdrawAll() external override { uint amount = balanceOf(msg.sender); uint principal = principalOf(msg.sender); uint depositTimestamp = _depositedAt[msg.sender]; totalShares = totalShares.sub(_shares[msg.sender]); delete _shares[msg.sender]; delete _principal[msg.sender]; delete _depositedAt[msg.sender]; amount = _withdrawTokenWithCorrection(amount); uint profit = amount > principal ? amount.sub(principal) : 0; uint withdrawalFee = canMint() ? _minter.withdrawalFee(principal, depositTimestamp) : 0; uint performanceFee = canMint() ? _minter.performanceFee(profit) : 0; if (withdrawalFee.add(performanceFee) > DUST) { _minter.mintForV2(address(_stakingToken), withdrawalFee, performanceFee, msg.sender, depositTimestamp); if (performanceFee > 0) { emit ProfitPaid(msg.sender, profit, performanceFee); } amount = amount.sub(withdrawalFee).sub(performanceFee); } _stakingToken.safeTransfer(msg.sender, amount); emit Withdrawn(msg.sender, amount, withdrawalFee); } function harvest() external override onlyKeeper { _harvest(); uint before = _stakingToken.balanceOf(address(this)); zap.zapInToken(address(SUSHI), sushiHarvested, address(_stakingToken)); zap.zapInToken(address(WMATIC), wmaticHarvested, address(_stakingToken)); uint harvested = _stakingToken.balanceOf(address(this)).sub(before); SUSHI_MINI_CHEF.deposit(pid, harvested, address(this)); emit Harvested(harvested); sushiHarvested = 0; wmaticHarvested = 0; } function _harvest() private updateSushiHarvested { SUSHI_MINI_CHEF.harvest(pid, address(this)); } function withdraw(uint shares) external override onlyWhitelisted { uint amount = balance().mul(shares).div(totalShares); totalShares = totalShares.sub(shares); _shares[msg.sender] = _shares[msg.sender].sub(shares); amount = _withdrawTokenWithCorrection(amount); _stakingToken.safeTransfer(msg.sender, amount); emit Withdrawn(msg.sender, amount, 0); } // @dev underlying only + withdrawal fee + no perf fee function withdrawUnderlying(uint _amount) external { uint amount = Math.min(_amount, _principal[msg.sender]); uint shares = Math.min(amount.mul(totalShares).div(balance()), _shares[msg.sender]); totalShares = totalShares.sub(shares); _shares[msg.sender] = _shares[msg.sender].sub(shares); _principal[msg.sender] = _principal[msg.sender].sub(amount); amount = _withdrawTokenWithCorrection(amount); uint depositTimestamp = _depositedAt[msg.sender]; uint withdrawalFee = canMint() ? _minter.withdrawalFee(amount, depositTimestamp) : 0; if (withdrawalFee > DUST) { _minter.mintForV2(address(_stakingToken), withdrawalFee, 0, msg.sender, depositTimestamp); amount = amount.sub(withdrawalFee); } _stakingToken.safeTransfer(msg.sender, amount); emit Withdrawn(msg.sender, amount, withdrawalFee); } // @dev profits only (underlying + bunny) + no withdraw fee + perf fee function getReward() external override { uint amount = earned(msg.sender); uint shares = Math.min(amount.mul(totalShares).div(balance()), _shares[msg.sender]); totalShares = totalShares.sub(shares); _shares[msg.sender] = _shares[msg.sender].sub(shares); _cleanupIfDustShares(); amount = _withdrawTokenWithCorrection(amount); uint depositTimestamp = _depositedAt[msg.sender]; uint performanceFee = canMint() ? _minter.performanceFee(amount) : 0; if (performanceFee > DUST) { _minter.mintForV2(address(_stakingToken), 0, performanceFee, msg.sender, depositTimestamp); amount = amount.sub(performanceFee); } _stakingToken.safeTransfer(msg.sender, amount); emit ProfitPaid(msg.sender, amount, performanceFee); } /* ========== PRIVATE FUNCTIONS ========== */ function _depositTo(uint _amount, address _to) private notPaused updateSushiHarvested { uint _pool = balance(); uint _before = _stakingToken.balanceOf(address(this)); _stakingToken.safeTransferFrom(msg.sender, address(this), _amount); uint _after = _stakingToken.balanceOf(address(this)); _amount = _after.sub(_before); // Additional check for deflationary tokens uint shares = 0; if (totalShares == 0) { shares = _amount; } else { shares = (_amount.mul(totalShares)).div(_pool); } totalShares = totalShares.add(shares); _shares[_to] = _shares[_to].add(shares); _principal[_to] = _principal[_to].add(_amount); _depositedAt[_to] = block.timestamp; SUSHI_MINI_CHEF.deposit(pid, _amount, address(this)); emit Deposited(_to, _amount); } function _withdrawTokenWithCorrection(uint amount) private updateSushiHarvested returns (uint) { uint before = _stakingToken.balanceOf(address(this)); SUSHI_MINI_CHEF.withdraw(pid, amount, address(this)); return _stakingToken.balanceOf(address(this)).sub(before); } function _cleanupIfDustShares() private { uint shares = _shares[msg.sender]; if (shares > 0 && shares < DUST) { totalShares = totalShares.sub(shares); delete _shares[msg.sender]; } } /* ========== SALVAGE PURPOSE ONLY ========== */ // @dev stakingToken must not remain balance in this contract. So dev should salvage staking token transferred by mistake. function recoverToken(address token, uint amount) external override onlyOwner { if (token == address(SUSHI)) { uint sushiBalance = SUSHI.balanceOf(address(this)); require(amount <= sushiBalance.sub(sushiHarvested), "VaultFlipToFlip: cannot recover lp's harvested sushi"); } if (token == address(WMATIC)){ uint wmaticBalance = WMATIC.balanceOf(address(this)); require(amount <= wmaticBalance.sub(wmaticHarvested)); } IBEP20(token).safeTransfer(owner(), amount); emit Recovered(token, amount); } }
Bearbeitung
Datei öffnen
// SPDX-License-Identifier: MIT pragma solidity ^0.6.12; pragma experimental ABIEncoderV2; /* ___ _ _ | _ )_ _ _ _ _ _ _ _ | | | | | _ \ || | ' \| ' \ || | |_| |_| |___/\_,_|_||_|_||_\_, | (_) (_) |__/ * * MIT License * =========== * * Copyright (c) 2020 BunnyFinance * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ import "@pancakeswap/pancake-swap-lib/contracts/token/BEP20/SafeBEP20.sol"; import "@openzeppelin/contracts/math/Math.sol"; import {PoolConstant} from "../library/PoolConstant.sol"; import "../interfaces/IUniswapV2Pair.sol"; import "../interfaces/IUniswapV2Factory.sol"; import "../interfaces/IStrategy.sol"; import "../interfaces/ISushiMiniChefV2.sol"; import "../interfaces/IZap.sol"; import "./VaultController.sol"; contract VaultSushiFlipToFlip is VaultController, IStrategy { using SafeBEP20 for IBEP20; using SafeMath for uint256; /* ========== CONSTANTS ============= */ IBEP20 private constant SUSHI = IBEP20(0x0b3F868E0BE5597D5DB7fEB59E1CADBb0fdDa50a); IBEP20 private constant WMATIC = IBEP20(0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270); PoolConstant.PoolTypes public constant override poolType = PoolConstant.PoolTypes.FlipToFlip; ISushiMiniChefV2 private constant SUSHI_MINI_CHEF = ISushiMiniChefV2(0x0769fd68dFb93167989C6f7254cd0D766Fb2841F); IZap private constant zap = IZap(0x93bCE7E49E26AF0f87b74583Ba6551DF5E4867B7); uint private constant DUST = 1000; /* ========== STATE VARIABLES ========== */ uint public override pid; address private _token0; address private _token1; uint public totalShares; mapping (address => uint) private _shares; mapping (address => uint) private _principal; mapping (address => uint) private _depositedAt; uint public sushiHarvested; uint public wmaticHarvested; uint public totalBalance; /* ========== MODIFIER ========== */ modifier updateSushiHarvested { uint _before = SUSHI.balanceOf(address(this)); uint _beforeWmatic = WMATIC.balanceOf(address(this)); _; uint _after = SUSHI.balanceOf(address(this)); uint _afterWmatic = WMATIC.balanceOf(address(this)); sushiHarvested = sushiHarvested.add(_after).sub(_before); wmaticHarvested = wmaticHarvested.add(_afterWmatic).sub(_beforeWmatic); } /* ========== INITIALIZER ========== */ function initialize(uint _pid, address _token) external initializer { __VaultController_init(IBEP20(_token)); _stakingToken.safeApprove(address(SUSHI_MINI_CHEF), uint(- 1)); pid = _pid; SUSHI.safeApprove(address(zap), uint(- 1)); WMATIC.safeApprove(address(zap), uint(- 1)); } /* ========== VIEW FUNCTIONS ========== */ function totalSupply() external view override returns (uint) { return totalShares; } function balance() public view override returns (uint amount) { (amount,) = SUSHI_MINI_CHEF.userInfo(pid, address(this)); amount = Math.min(amount, totalBalance); } function balanceOf(address account) public view override returns(uint) { if (totalShares == 0) return 0; return balance().mul(sharesOf(account)).div(totalShares); } function withdrawableBalanceOf(address account) public view override returns (uint) { return balanceOf(account); } function sharesOf(address account) public view override returns (uint) { return _shares[account]; } function principalOf(address account) public view override returns (uint) { return _principal[account]; } function earned(address account) public view override returns (uint) { if (balanceOf(account) >= principalOf(account) + DUST) { return balanceOf(account).sub(principalOf(account)); } else { return 0; } } function depositedAt(address account) external view override returns (uint) { return _depositedAt[account]; } function rewardsToken() external view override returns (address) { return address(_stakingToken); } function priceShare() external view override returns(uint) { if (totalShares == 0) return 1e18; return balance().mul(1e18).div(totalShares); } /* ========== MUTATIVE FUNCTIONS ========== */ function deposit(uint _amount) public override { _depositTo(_amount, msg.sender); } function depositAll() external override { deposit(_stakingToken.balanceOf(msg.sender)); } function withdrawAll() external override { uint amount = balanceOf(msg.sender); uint principal = principalOf(msg.sender); uint depositTimestamp = _depositedAt[msg.sender]; totalBalance = totalBalance.sub(amount); totalShares = totalShares.sub(_shares[msg.sender]); delete _shares[msg.sender]; delete _principal[msg.sender]; delete _depositedAt[msg.sender]; amount = _withdrawTokenWithCorrection(amount); uint profit = amount > principal ? amount.sub(principal) : 0; uint withdrawalFee = canMint() ? _minter.withdrawalFee(principal, depositTimestamp) : 0; uint performanceFee = canMint() ? _minter.performanceFee(profit) : 0; if (withdrawalFee.add(performanceFee) > DUST) { _minter.mintForV2(address(_stakingToken), withdrawalFee, performanceFee, msg.sender, depositTimestamp); if (performanceFee > 0) { emit ProfitPaid(msg.sender, profit, performanceFee); } amount = amount.sub(withdrawalFee).sub(performanceFee); } _stakingToken.safeTransfer(msg.sender, amount); emit Withdrawn(msg.sender, amount, withdrawalFee); } function harvest() external override onlyKeeper { _harvest(); uint before = _stakingToken.balanceOf(address(this)); zap.zapInToken(address(SUSHI), sushiHarvested, address(_stakingToken)); zap.zapInToken(address(WMATIC), wmaticHarvested, address(_stakingToken)); uint harvested = _stakingToken.balanceOf(address(this)).sub(before); totalBalance = totalBalance.add(harvested); SUSHI_MINI_CHEF.deposit(pid, harvested, address(this)); emit Harvested(harvested); sushiHarvested = 0; wmaticHarvested = 0; } function _harvest() private updateSushiHarvested { SUSHI_MINI_CHEF.harvest(pid, address(this)); } function withdraw(uint shares) external override onlyWhitelisted { uint amount = balance().mul(shares).div(totalShares); totalBalance = totalBalance.sub(amount); totalShares = totalShares.sub(shares); _shares[msg.sender] = _shares[msg.sender].sub(shares); amount = _withdrawTokenWithCorrection(amount); _stakingToken.safeTransfer(msg.sender, amount); emit Withdrawn(msg.sender, amount, 0); } // @dev underlying only + withdrawal fee + no perf fee function withdrawUnderlying(uint _amount) external { uint amount = Math.min(_amount, _principal[msg.sender]); uint shares = Math.min(amount.mul(totalShares).div(balance()), _shares[msg.sender]); totalBalance = totalBalance.sub(amount); totalShares = totalShares.sub(shares); _shares[msg.sender] = _shares[msg.sender].sub(shares); _principal[msg.sender] = _principal[msg.sender].sub(amount); amount = _withdrawTokenWithCorrection(amount); uint depositTimestamp = _depositedAt[msg.sender]; uint withdrawalFee = canMint() ? _minter.withdrawalFee(amount, depositTimestamp) : 0; if (withdrawalFee > DUST) { _minter.mintForV2(address(_stakingToken), withdrawalFee, 0, msg.sender, depositTimestamp); amount = amount.sub(withdrawalFee); } _stakingToken.safeTransfer(msg.sender, amount); emit Withdrawn(msg.sender, amount, withdrawalFee); } // @dev profits only (underlying + bunny) + no withdraw fee + perf fee function getReward() external override { uint amount = earned(msg.sender); uint shares = Math.min(amount.mul(totalShares).div(balance()), _shares[msg.sender]); totalBalance = totalBalance.sub(amount); totalShares = totalShares.sub(shares); _shares[msg.sender] = _shares[msg.sender].sub(shares); _cleanupIfDustShares(); amount = _withdrawTokenWithCorrection(amount); uint depositTimestamp = _depositedAt[msg.sender]; uint performanceFee = canMint() ? _minter.performanceFee(amount) : 0; if (performanceFee > DUST) { _minter.mintForV2(address(_stakingToken), 0, performanceFee, msg.sender, depositTimestamp); amount = amount.sub(performanceFee); } _stakingToken.safeTransfer(msg.sender, amount); emit ProfitPaid(msg.sender, amount, performanceFee); } /* ========== PRIVATE FUNCTIONS ========== */ function _depositTo(uint _amount, address _to) private notPaused updateSushiHarvested { uint _pool = balance(); uint _before = _stakingToken.balanceOf(address(this)); _stakingToken.safeTransferFrom(msg.sender, address(this), _amount); uint _after = _stakingToken.balanceOf(address(this)); _amount = _after.sub(_before); // Additional check for deflationary tokens uint shares = 0; if (totalShares == 0) { shares = _amount; } else { shares = (_amount.mul(totalShares)).div(_pool); } totalBalance = totalBalance.add(_amount); totalShares = totalShares.add(shares); _shares[_to] = _shares[_to].add(shares); _principal[_to] = _principal[_to].add(_amount); _depositedAt[_to] = block.timestamp; SUSHI_MINI_CHEF.deposit(pid, _amount, address(this)); emit Deposited(_to, _amount); } function _withdrawTokenWithCorrection(uint amount) private updateSushiHarvested returns (uint) { uint before = _stakingToken.balanceOf(address(this)); SUSHI_MINI_CHEF.withdraw(pid, amount, address(this)); return _stakingToken.balanceOf(address(this)).sub(before); } function _cleanupIfDustShares() private { uint shares = _shares[msg.sender]; if (shares > 0 && shares < DUST) { totalShares = totalShares.sub(shares); delete _shares[msg.sender]; } } /* ========== SALVAGE PURPOSE ONLY ========== */ // @dev stakingToken must not remain balance in this contract. So dev should salvage staking token transferred by mistake. function recoverToken(address token, uint amount) external override onlyOwner { if (token == address(SUSHI)) { uint sushiBalance = SUSHI.balanceOf(address(this)); require(amount <= sushiBalance.sub(sushiHarvested), "VaultFlipToFlip: cannot recover lp's harvested sushi"); } if (token == address(WMATIC)){ uint wmaticBalance = WMATIC.balanceOf(address(this)); require(amount <= wmaticBalance.sub(wmaticHarvested)); } IBEP20(token).safeTransfer(owner(), amount); emit Recovered(token, amount); } function setTotalBalance() external onlyOwner { require(totalBalance == 0, "VaultSushiFlipToFlip: can't update totalBalance"); (uint amount,) = SUSHI_MINI_CHEF.userInfo(pid, address(this)); totalBalance = amount; } }
Unterschied finden