MasterChef

Created Diff never expires
148 removals
332 lines
163 additions
347 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;
pragma solidity 0.6.12;


import '@pancakeswap/pancake-swap-lib/contracts/math/SafeMath.sol';
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import '@pancakeswap/pancake-swap-lib/contracts/token/BEP20/IBEP20.sol';
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import '@pancakeswap/pancake-swap-lib/contracts/token/BEP20/SafeBEP20.sol';
import "@openzeppelin/contracts/utils/EnumerableSet.sol";
import '@pancakeswap/pancake-swap-lib/contracts/access/Ownable.sol';
import "@openzeppelin/contracts/math/SafeMath.sol";

import "@openzeppelin/contracts/access/Ownable.sol";
import "./CakeToken.sol";
import "./SyrupBar.sol";


// import "@nomiclabs/buidler/console.sol";
import "./FinToken.sol";
import "./CaviarBar.sol";


interface IMigratorChef {
interface IMigratorChef {
// Perform LP token migration from legacy PancakeSwap to CakeSwap.
// Perform LP token migration from legacy FinSwap to new FinSwap.
// Take the current LP token address and return the new LP token address.
// Take the current LP token address and return the new LP token address.
// Migrator should have full access to the caller's LP token.
// Migrator should have full access to the caller's LP token.
// Return the new LP token address.
// Return the new LP token address.
//
//
// XXX Migrator must have allowance access to PancakeSwap LP tokens.
// XXX Migrator must have allowance access to FinSwap LP tokens.
// CakeSwap must mint EXACTLY the same amount of CakeSwap LP tokens or
// FinSwap must mint EXACTLY the same amount of FinSwap LP tokens or
// else something bad will happen. Traditional PancakeSwap does not
// else something bad will happen. Traditional FinSwap does not
// do that so be careful!
// do that so be careful!
function migrate(IBEP20 token) external returns (IBEP20);
function migrate(IERC20 token) external returns (IERC20);
}
}


// MasterChef is the master of Cake. He can make Cake and he is a fair guy.
// MasterChef is the master of Fins. He can make Fins and he is a fair guy.
//
//
// Note that it's ownable and the owner wields tremendous power. The ownership
// Note that it's ownable and the owner wields tremendous power. The ownership
// will be transferred to a governance smart contract once CAKE is sufficiently
// will be transferred to a governance smart contract once FINS is sufficiently
// distributed and the community can show to govern itself.
// distributed and the community can show to govern itself.
//
//
// Have fun reading it. Hopefully it's bug-free. God bless.
// Have fun reading it. Hopefully it's bug-free. God bless.
contract MasterChef is Ownable {
contract MasterChef is Ownable {
using SafeMath for uint256;
using SafeMath for uint256;
using SafeBEP20 for IBEP20;
using SafeERC20 for IERC20;


// Info of each user.
// Info of each user.
struct UserInfo {
struct UserInfo {
uint256 amount; // How many LP tokens the user has provided.
uint256 amount; // How many LP tokens the user has provided.
uint256 rewardDebt; // Reward debt. See explanation below.
uint256 rewardDebt; // Reward debt. See explanation below.
//
//
// We do some fancy math here. Basically, any point in time, the amount of CAKEs
// We do some fancy math here. Basically, any point in time, the amount of FINSs
// entitled to a user but is pending to be distributed is:
// entitled to a user but is pending to be distributed is:
//
//
// pending reward = (user.amount * pool.accCakePerShare) - user.rewardDebt
// pending reward = (user.amount * pool.accFinsPerShare) - user.rewardDebt
//
//
// Whenever a user deposits or withdraws LP tokens to a pool. Here's what happens:
// Whenever a user deposits or withdraws LP tokens to a pool. Here's what happens:
// 1. The pool's `accCakePerShare` (and `lastRewardBlock`) gets updated.
// 1. The pool's `accFinsPerShare` (and `lastRewardTime`) gets updated.
// 2. User receives the pending reward sent to his/her address.
// 2. User receives the pending reward sent to his/her address.
// 3. User's `amount` gets updated.
// 3. User's `amount` gets updated.
// 4. User's `rewardDebt` gets updated.
// 4. User's `rewardDebt` gets updated.
}
}


// Info of each pool.
// Info of each pool.
struct PoolInfo {
struct PoolInfo {
IBEP20 lpToken; // Address of LP token contract.
IERC20 lpToken; // Address of LP token contract.
uint256 allocPoint; // How many allocation points assigned to this pool. CAKEs to distribute per block.
uint256 allocPoint; // How many allocation points assigned to this pool. FINS to distribute per block.
uint256 lastRewardBlock; // Last block number that CAKEs distribution occurs.
uint256 lastRewardTime; // Last block number that FINS distribution occurs.
uint256 accCakePerShare; // Accumulated CAKEs per share, times 1e12. See below.
uint256 accFinsPerShare; // Accumulated FINS per share, times 1e12. See below.
}
}


// The CAKE TOKEN!
// The FINS TOKEN!
CakeToken public cake;
FinToken public fins;
// The SYRUP TOKEN!
// The caviar TOKEN!
SyrupBar public syrup;
CaviarBar public caviar;
// Dev address.
// Dev address.
address public devaddr;
address public devaddr;
// CAKE tokens created per block.
// FINS tokens created per second.
uint256 public cakePerBlock;
uint256 public finsPerSecond;
// Bonus muliplier for early cake makers.
// Max finsPerSecond keep never ol
uint256 public BONUS_MULTIPLIER = 1;
uint256 public constant maxFinsPerSecond = 1e18;

// The migrator contract. It has a lot of power. Can only be set through governance (owner).
// The migrator contract. It has a lot of power. Can only be set through governance (owner).
IMigratorChef public migrator;
IMigratorChef public migrator;


// Info of each pool.
// Info of each pool.
PoolInfo[] public poolInfo;
PoolInfo[] public poolInfo;

// add the same LP token only once
mapping(address => bool) lpExists;

// Info of each user that stakes LP tokens.
// Info of each user that stakes LP tokens.
mapping (uint256 => mapping (address => UserInfo)) public userInfo;
mapping (uint256 => mapping (address => UserInfo)) public userInfo;
// Total allocation points. Must be the sum of all allocation points in all pools.
// Total allocation points. Must be the sum of all allocation points in all pools.
uint256 public totalAllocPoint = 0;
uint256 public totalAllocPoint = 0;
// The block number when CAKE mining starts.
// The block number when FINS mining starts.
uint256 public startBlock;
uint256 public startTime;


event Deposit(address indexed user, uint256 indexed pid, uint256 amount);
event Deposit(address indexed user, uint256 indexed pid, uint256 amount);
event Withdraw(address indexed user, uint256 indexed pid, uint256 amount);
event Withdraw(address indexed user, uint256 indexed pid, uint256 amount);
event EmergencyWithdraw(address indexed user, uint256 indexed pid, uint256 amount);
event EmergencyWithdraw(address indexed user, uint256 indexed pid, uint256 amount);


constructor(
constructor(
CakeToken _cake,
FinToken _fins,
SyrupBar _syrup,
CaviarBar _caviar,
address _devaddr,
address _devaddr,
uint256 _cakePerBlock,
uint256 _finsPerSecond,
uint256 _startBlock
uint256 _startTime
) public {
) public {
cake = _cake;
fins = _fins;
syrup = _syrup;
caviar = _caviar;
devaddr = _devaddr;
devaddr = _devaddr;
cakePerBlock = _cakePerBlock;
finsPerSecond = _finsPerSecond;
startBlock = _startBlock;
startTime = _startTime;


// staking pool
// staking pool
poolInfo.push(PoolInfo({
poolInfo.push(PoolInfo({
lpToken: _cake,
lpToken: _fins,
allocPoint: 1000,
allocPoint: 1000,
lastRewardBlock: startBlock,
lastRewardTime: startTime,
accCakePerShare: 0
accFinsPerShare: 0
}));
}));


totalAllocPoint = 1000;
totalAllocPoint = 1000;


}

function updateMultiplier(uint256 multiplierNumber) public onlyOwner {
BONUS_MULTIPLIER = multiplierNumber;
}
}


function poolLength() external view returns (uint256) {
function poolLength() external view returns (uint256) {
return poolInfo.length;
return poolInfo.length;
}
}


// Add a new lp to the pool. Can only be called by the owner.
// Add a new lp to the pool. Can only be called by the owner.
// XXX DO NOT add the same LP token more than once. Rewards will be messed up if you do.
// XXX DO NOT add the same LP token more than once. Rewards will be messed up if you do.
function add(uint256 _allocPoint, IBEP20 _lpToken, bool _withUpdate) public onlyOwner {
function add(uint256 _allocPoint, IERC20 _lpToken, bool _withUpdate) public onlyOwner {
require(!lpExists[address(_lpToken)], "!lpToken exists");

if (_withUpdate) {
if (_withUpdate) {
massUpdatePools();
massUpdatePools();
}
}
uint256 lastRewardBlock = block.number > startBlock ? block.number : startBlock;
uint256 lastRewardTime = block.timestamp > startTime ? block.timestamp : startTime;
totalAllocPoint = totalAllocPoint.add(_allocPoint);
totalAllocPoint = totalAllocPoint.add(_allocPoint);
poolInfo.push(PoolInfo({
poolInfo.push(PoolInfo({
lpToken: _lpToken,
lpToken: _lpToken,
allocPoint: _allocPoint,
allocPoint: _allocPoint,
lastRewardBlock: lastRewardBlock,
lastRewardTime: lastRewardTime,
accCakePerShare: 0
accFinsPerShare: 0
}));
}));
updateStakingPool();
updateStakingPool();
lpExists[address(_lpToken)] = true;
}
}


// Update the given pool's CAKE allocation point. Can only be called by the owner.
// Update the given pool's FINS allocation point. Can only be called by the owner.
function set(uint256 _pid, uint256 _allocPoint, bool _withUpdate) public onlyOwner {
function set(uint256 _pid, uint256 _allocPoint, bool _withUpdate) public onlyOwner {
if (_withUpdate) {
if (_withUpdate) {
massUpdatePools();
massUpdatePools();
}
}
uint256 prevAllocPoint = poolInfo[_pid].allocPoint;
uint256 prevAllocPoint = poolInfo[_pid].allocPoint;
poolInfo[_pid].allocPoint = _allocPoint;
poolInfo[_pid].allocPoint = _allocPoint;
if (prevAllocPoint != _allocPoint) {
if (prevAllocPoint != _allocPoint) {
totalAllocPoint = totalAllocPoint.sub(prevAllocPoint).add(_allocPoint);
totalAllocPoint = totalAllocPoint.sub(prevAllocPoint).add(_allocPoint);
updateStakingPool();
updateStakingPool();
}
}
}
}


function updateStakingPool() internal {
function updateStakingPool() internal {
uint256 length = poolInfo.length;
uint256 length = poolInfo.length;
uint256 points = 0;
uint256 points = 0;
for (uint256 pid = 1; pid < length; ++pid) {
for (uint256 pid = 1; pid < length; ++pid) {
points = points.add(poolInfo[pid].allocPoint);
points = points.add(poolInfo[pid].allocPoint);
}
}
if (points != 0) {
if (points != 0) {
points = points.div(3);
points = points.div(3);
totalAllocPoint = totalAllocPoint.sub(poolInfo[0].allocPoint).add(points);
totalAllocPoint = totalAllocPoint.sub(poolInfo[0].allocPoint).add(points);
poolInfo[0].allocPoint = points;
poolInfo[0].allocPoint = points;
}
}
}
}


// Set the migrator contract. Can only be called by the owner.
// Set the migrator contract. Can only be called by the owner.
function setMigrator(IMigratorChef _migrator) public onlyOwner {
function setMigrator(IMigratorChef _migrator) public onlyOwner {
migrator = _migrator;
migrator = _migrator;
}
}


// Migrate lp token to another lp contract. Can be called by anyone. We trust that migrator contract is good.
// Migrate lp token to another lp contract. Can be called by anyone. We trust that migrator contract is good.
function migrate(uint256 _pid) public {
function migrate(uint256 _pid) public {
require(address(migrator) != address(0), "migrate: no migrator");
require(address(migrator) != address(0), "migrate: no migrator");
PoolInfo storage pool = poolInfo[_pid];
PoolInfo storage pool = poolInfo[_pid];
IBEP20 lpToken = pool.lpToken;
IERC20 lpToken = pool.lpToken;
uint256 bal = lpToken.balanceOf(address(this));
uint256 bal = lpToken.balanceOf(address(this));
lpToken.safeApprove(address(migrator), bal);
lpToken.safeApprove(address(migrator), bal);
IBEP20 newLpToken = migrator.migrate(lpToken);
IERC20 newLpToken = migrator.migrate(lpToken);
require(bal == newLpToken.balanceOf(address(this)), "migrate: bad");
require(bal == newLpToken.balanceOf(address(this)), "migrate: bad");
pool.lpToken = newLpToken;
pool.lpToken = newLpToken;
}
}


// Return reward multiplier over the given _from to _to block.
// Return reward multiplier over the given _from to _to block.
function getMultiplier(uint256 _from, uint256 _to) public view returns (uint256) {
function getMultiplier(uint256 _from, uint256 _to) public view returns (uint256) {
return _to.sub(_from).mul(BONUS_MULTIPLIER);
_from = _from > startTime ? _from : startTime;
if (_to < startTime) {
return 0;
}
return _to.sub(_from);
}
}


// View function to see pending CAKEs on frontend.
// View function to see pending FINS on frontend.
function pendingCake(uint256 _pid, address _user) external view returns (uint256) {
function pendingFins(uint256 _pid, address _user) external view returns (uint256) {
PoolInfo storage pool = poolInfo[_pid];
PoolInfo storage pool = poolInfo[_pid];
UserInfo storage user = userInfo[_pid][_user];
UserInfo storage user = userInfo[_pid][_user];
uint256 accCakePerShare = pool.accCakePerShare;
uint256 accFinsPerShare = pool.accFinsPerShare;
uint256 lpSupply = pool.lpToken.balanceOf(address(this));
uint256 lpSupply = pool.lpToken.balanceOf(address(this));
if (block.number > pool.lastRewardBlock && lpSupply != 0) {
if (block.timestamp > pool.lastRewardTime && lpSupply != 0) {
uint256 multiplier = getMultiplier(pool.lastRewardBlock, block.number);
uint256 multiplier = getMultiplier(pool.lastRewardTime, block.timestamp);
uint256 cakeReward = multiplier.mul(cakePerBlock).mul(pool.allocPoint).div(totalAllocPoint);
uint256 finsReward = multiplier.mul(finsPerSecond).mul(pool.allocPoint).div(totalAllocPoint);
accCakePerShare = accCakePerShare.add(cakeReward.mul(1e12).div(lpSupply));
accFinsPerShare = accFinsPerShare.add(finsReward.mul(1e12).div(lpSupply));
}
}
return user.amount.mul(accCakePerShare).div(1e12).sub(user.rewardDebt);
return user.amount.mul(accFinsPerShare).div(1e12).sub(user.rewardDebt);
}
}


// Update reward variables for all pools. Be careful of gas spending!
// Update reward variables for all pools. Be careful of gas spending!
function massUpdatePools() public {
function massUpdatePools() public {
uint256 length = poolInfo.length;
uint256 length = poolInfo.length;
for (uint256 pid = 0; pid < length; ++pid) {
for (uint256 pid = 0; pid < length; ++pid) {
updatePool(pid);
updatePool(pid);
}
}
}
}




// Update reward variables of the given pool to be up-to-date.
// Update reward variables of the given pool to be up-to-date.
function updatePool(uint256 _pid) public {
function updatePool(uint256 _pid) public {
PoolInfo storage pool = poolInfo[_pid];
PoolInfo storage pool = poolInfo[_pid];
if (block.number <= pool.lastRewardBlock) {
if (block.timestamp <= pool.lastRewardTime) {
return;
return;
}
}
uint256 lpSupply = pool.lpToken.balanceOf(address(this));
uint256 lpSupply = pool.lpToken.balanceOf(address(this));
if (lpSupply == 0) {
if (lpSupply == 0) {
pool.lastRewardBlock = block.number;
pool.lastRewardTime = block.timestamp;
return;
return;
}
}
uint256 multiplier = getMultiplier(pool.lastRewardBlock, block.number);
uint256 multiplier = getMultiplier(pool.lastRewardTime, block.timestamp);
uint256 cakeReward = multiplier.mul(cakePerBlock).mul(pool.allocPoint).div(totalAllocPoint);
uint256 finsReward = multiplier.mul(finsPerSecond).mul(pool.allocPoint).div(totalAllocPoint);
cake.mint(devaddr, cakeReward.div(10));
fins.mint(devaddr, finsReward.div(10));
cake.mint(address(syrup), cakeReward);
fins.mint(address(caviar), finsReward);
pool.accCakePerShare = pool.accCakePerShare.add(cakeReward.mul(1e12).div(lpSupply));
pool.accFinsPerShare = pool.accFinsPerShare.add(finsReward.mul(1e12).div(lpSupply));
pool.lastRewardBlock = block.number;
pool.lastRewardTime = block.timestamp;
}
}


// Deposit LP tokens to MasterChef for CAKE allocation.
// Deposit LP tokens to MasterChef for FINS allocation.
function deposit(uint256 _pid, uint256 _amount) public {
function deposit(uint256 _pid, uint256 _amount) public {


require (_pid != 0, 'deposit CAKE by staking');
require (_pid != 0, 'deposit FINS by staking');


PoolInfo storage pool = poolInfo[_pid];
PoolInfo storage pool = poolInfo[_pid];
UserInfo storage user = userInfo[_pid][msg.sender];
UserInfo storage user = userInfo[_pid][msg.sender];
updatePool(_pid);
updatePool(_pid);
if (user.amount > 0) {
if (user.amount > 0) {
uint256 pending = user.amount.mul(pool.accCakePerShare).div(1e12).sub(user.rewardDebt);
uint256 pending = user.amount.mul(pool.accFinsPerShare).div(1e12).sub(user.rewardDebt);
if(pending > 0) {
if(pending > 0) {
safeCakeTransfer(msg.sender, pending);
safeFinsTransfer(msg.sender, pending);
}
}
}
}
if (_amount > 0) {
if (_amount > 0) {
pool.lpToken.safeTransferFrom(address(msg.sender), address(this), _amount);
pool.lpToken.safeTransferFrom(address(msg.sender), address(this), _amount);
user.amount = user.amount.add(_amount);
user.amount = user.amount.add(_amount);
}
}
user.rewardDebt = user.amount.mul(pool.accCakePerShare).div(1e12);
user.rewardDebt = user.amount.mul(pool.accFinsPerShare).div(1e12);
emit Deposit(msg.sender, _pid, _amount);
emit Deposit(msg.sender, _pid, _amount);
}
}


// Withdraw LP tokens from MasterChef.
// Withdraw LP tokens from MasterChef.
function withdraw(uint256 _pid, uint256 _amount) public {
function withdraw(uint256 _pid, uint256 _amount) public {


require (_pid != 0, 'withdraw CAKE by unstaking');
require (_pid != 0, 'withdraw FINS by unstaking');
PoolInfo storage pool = poolInfo[_pid];
PoolInfo storage pool = poolInfo[_pid];
UserInfo storage user = userInfo[_pid][msg.sender];
UserInfo storage user = userInfo[_pid][msg.sender];
require(user.amount >= _amount, "withdraw: not good");
require(user.amount >= _amount, "withdraw: not good");


updatePool(_pid);
updatePool(_pid);
uint256 pending = user.amount.mul(pool.accCakePerShare).div(1e12).sub(user.rewardDebt);
uint256 pending = user.amount.mul(pool.accFinsPerShare).div(1e12).sub(user.rewardDebt);
if(pending > 0) {
if(pending > 0) {
safeCakeTransfer(msg.sender, pending);
safeFinsTransfer(msg.sender, pending);
}
}
if(_amount > 0) {
if(_amount > 0) {
user.amount = user.amount.sub(_amount);
user.amount = user.amount.sub(_amount);
pool.lpToken.safeTransfer(address(msg.sender), _amount);
pool.lpToken.safeTransfer(address(msg.sender), _amount);
}
}
user.rewardDebt = user.amount.mul(pool.accCakePerShare).div(1e12);
user.rewardDebt = user.amount.mul(pool.accFinsPerShare).div(1e12);
emit Withdraw(msg.sender, _pid, _amount);
emit Withdraw(msg.sender, _pid, _amount);
}
}


// Stake CAKE tokens to MasterChef
// Stake FINS tokens to MasterChef
function enterStaking(uint256 _amount) public {
function enterStaking(uint256 _amount) public {
PoolInfo storage pool = poolInfo[0];
PoolInfo storage pool = poolInfo[0];
UserInfo storage user = userInfo[0][msg.sender];
UserInfo storage user = userInfo[0][msg.sender];
updatePool(0);
updatePool(0);
if (user.amount > 0) {
if (user.amount > 0) {
uint256 pending = user.amount.mul(pool.accCakePerShare).div(1e12).sub(user.rewardDebt);
uint256 pending = user.amount.mul(pool.accFinsPerShare).div(1e12).sub(user.rewardDebt);
if(pending > 0) {
if(pending > 0) {
safeCakeTransfer(msg.sender, pending);
safeFinsTransfer(msg.sender, pending);
}
}
}
}
if(_amount > 0) {
if(_amount > 0) {
pool.lpToken.safeTransferFrom(address(msg.sender), address(this), _amount);
pool.lpToken.safeTransferFrom(address(msg.sender), address(this), _amount);
user.amount = user.amount.add(_amount);
user.amount = user.amount.add(_amount);
}
}
user.rewardDebt = user.amount.mul(pool.accCakePerShare).div(1e12);
user.rewardDebt = user.amount.mul(pool.accFinsPerShare).div(1e12);


syrup.mint(msg.sender, _amount);
caviar.mint(msg.sender, _amount);
emit Deposit(msg.sender, 0, _amount);
emit Deposit(msg.sender, 0, _amount);
}
}


// Withdraw CAKE tokens from STAKING.
// Withdraw FINS tokens from STAKING.
function leaveStaking(uint256 _amount) public {
function leaveStaking(uint256 _amount) public {
PoolInfo storage pool = poolInfo[0];
PoolInfo storage pool = poolInfo[0];
UserInfo storage user = userInfo[0][msg.sender];
UserInfo storage user = userInfo[0][msg.sender];
require(user.amount >= _amount, "withdraw: not good");
require(user.amount >= _amount, "withdraw: not good");
updatePool(0);
updatePool(0);
uint256 pending = user.amount.mul(pool.accCakePerShare).div(1e12).sub(user.rewardDebt);
uint256 pending = user.amount.mul(pool.accFinsPerShare).div(1e12).sub(user.rewardDebt);
if(pending > 0) {
if(pending > 0) {
safeCakeTransfer(msg.sender, pending);
safeFinsTransfer(msg.sender, pending);
}
}
if(_amount > 0) {
if(_amount > 0) {
user.amount = user.amount.sub(_amount);
user.amount = user.amount.sub(_amount);
pool.lpToken.safeTransfer(address(msg.sender), _amount);
pool.lpToken.safeTransfer(address(msg.sender), _amount);
}
}
user.rewardDebt = user.amount.mul(pool.accCakePerShare).div(1e12);
user.rewardDebt = user.amount.mul(pool.accFinsPerShare).div(1e12);


syrup.burn(msg.sender, _amount);
caviar.burn(msg.sender, _amount);
emit Withdraw(msg.sender, 0, _amount);
emit Withdraw(msg.sender, 0, _amount);
}
}


// Withdraw without caring about rewards. EMERGENCY ONLY.
// Withdraw without caring about rewards. EMERGENCY ONLY.
function emergencyWithdraw(uint256 _pid) public {
function emergencyWithdraw(uint256 _pid) public {
PoolInfo storage pool = poolInfo[_pid];
PoolInfo storage pool = poolInfo[_pid];
UserInfo storage user = userInfo[_pid][msg.sender];
UserInfo storage user = userInfo[_pid][msg.sender];
pool.lpToken.safeTransfer(address(msg.sender), user.amount);
pool.lpToken.safeTransfer(address(msg.sender), user.amount);
emit EmergencyWithdraw(msg.sender, _pid, user.amount);
emit EmergencyWithdraw(msg.sender, _pid, user.amount);
user.amount = 0;
user.amount = 0;
user.rewardDebt = 0;
user.rewardDebt = 0;
}
}


// Safe cake transfer function, just in case if rounding error causes pool to not have enough CAKEs.
// Safe fins transfer function, just in case if rounding error causes pool to not have enough fins.
function safeCakeTransfer(address _to, uint256 _amount) internal {
function safeFinsTransfer(address _to, uint256 _amount) internal {
syrup.safeCakeTransfer(_to, _amount);
caviar.safeFinsTransfer(_to, _amount);
}
}


// Update dev address by the previous dev.
// Update dev address by the previous dev.
function dev(address _devaddr) public {
function setDevAddress(address _devaddr) public {
require(msg.sender == devaddr, "dev: wut?");
require(msg.sender == devaddr, "dev: wut?");
devaddr = _devaddr;
devaddr = _devaddr;
}

function setFinsPerSecond(uint256 _finsPerSecond) public onlyOwner {
require(_finsPerSecond <= maxFinsPerSecond, "finsPerSecond: ol?");
massUpdatePools();
finsPerSecond = _finsPerSecond;
}
}
}
}