Diff
checker
テキスト
テキスト
画像
ドキュメント
Excel
フォルダ
Legal
Enterprise
デスクトップ
料金
ログイン
Diffchecker デスクトップのダウンロード
テキスト比較
2 つのテキスト ファイルの違いを見つける
ツール
履歴
ライブエディター
未変更行を折りたたむ
折り返しなし
レイアウト
分割
統合
比較精度
スマート
単語
文字
シンタックスハイライト
構文を選択
無視
テキスト変換
最初の差分へ移動
入力を編集
Diffchecker Desktop
Diffcheckerを実行する最も安全な方法。Diffchecker Desktopアプリを入手:あなたの差分はコンピューターから出ることはありません!
Desktopを入手
VaultSushiFlipToFlip.sol
作成日
5 年前
差分は期限切れになりません
クリア
エクスポート
共有
説明
0 削除
行
合計
削除
文字
合計
削除
この機能を引き続き使用するには、アップグレードしてください
Diff
checker
Pro
価格を見る
310 行
すべてコピー
17 追加
行
合計
追加
文字
合計
追加
この機能を引き続き使用するには、アップグレードしてください
Diff
checker
Pro
価格を見る
327 行
すべてコピー
// 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;
コピー
コピー済み
コピー
コピー済み
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));
コピー
コピー済み
コピー
コピー済み
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];
コピー
コピー済み
コピー
コピー済み
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);
コピー
コピー済み
コピー
コピー済み
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);
コピー
コピー済み
コピー
コピー済み
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]);
コピー
コピー済み
コピー
コピー済み
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]);
コピー
コピー済み
コピー
コピー済み
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);
}
}
コピー
コピー済み
コピー
コピー済み
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);
}
}
コピー
コピー済み
コピー
コピー済み
function setTotalBalance() external onlyOwner {
require(totalBalance == 0, "VaultSushiFlipToFlip: can't update totalBalance");
(uint amount,) = SUSHI_MINI_CHEF.userInfo(pid, address(this));
totalBalance = amount;
}
}
}
コピー
コピー済み
コピー
コピー済み
保存された差分
原文
ファイルを開く
// 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); } }
変更されたテキスト
ファイルを開く
// 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; } }
違いを見つける