BEP20RewardApe-to-BEP20RewardApeV2

Created Diff never expires
1 removal
Lines
Total
Removed
Words
Total
Removed
To continue using this feature, upgrade to
Diffchecker logo
Diffchecker Pro
236 lines
14 additions
Lines
Total
Added
Words
Total
Added
To continue using this feature, upgrade to
Diffchecker logo
Diffchecker Pro
249 lines
pragma solidity 0.6.12;
pragma solidity 0.6.12;


/*
/*
* ApeSwapFinance
* ApeSwapFinance
* App: https://apeswap.finance
* App: https://apeswap.finance
* Medium: https://ape-swap.medium.com
* Medium: https://ape-swap.medium.com
* Twitter: https://twitter.com/ape_swap
* Twitter: https://twitter.com/ape_swap
* Telegram: https://t.me/ape_swap
* Telegram: https://t.me/ape_swap
* Announcements: https://t.me/ape_swap_news
* Announcements: https://t.me/ape_swap_news
* GitHub: https://github.com/ApeSwapFinance
* GitHub: https://github.com/ApeSwapFinance
*/
*/


import '@pancakeswap/pancake-swap-lib/contracts/math/SafeMath.sol';
import '@pancakeswap/pancake-swap-lib/contracts/math/SafeMath.sol';
import '@pancakeswap/pancake-swap-lib/contracts/token/BEP20/IBEP20.sol';
import '@pancakeswap/pancake-swap-lib/contracts/token/BEP20/IBEP20.sol';
import '@pancakeswap/pancake-swap-lib/contracts/token/BEP20/SafeBEP20.sol';
import '@pancakeswap/pancake-swap-lib/contracts/token/BEP20/SafeBEP20.sol';
import '@pancakeswap/pancake-swap-lib/contracts/access/Ownable.sol';
import '@pancakeswap/pancake-swap-lib/contracts/access/Ownable.sol';




contract BEP20RewardApe is Ownable {
contract BEP20RewardApeV2 is Ownable {
using SafeMath for uint256;
using SafeMath for uint256;
using SafeBEP20 for IBEP20;
using SafeBEP20 for IBEP20;


// 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.
}
}


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


// The stake token
// The stake token
IBEP20 public stakeToken;
IBEP20 public stakeToken;
// The reward token
// The reward token
IBEP20 public rewardToken;
IBEP20 public rewardToken;


// Reward tokens created per block.
// Reward tokens created per block.
uint256 public rewardPerBlock;
uint256 public rewardPerBlock;




// Info of each pool.
// Info of each pool.
PoolInfo[] public poolInfo;
PoolInfo[] public poolInfo;
// Info of each user that stakes LP tokens.
// Info of each user that stakes LP tokens.
mapping (address => UserInfo) public userInfo;
mapping (address => UserInfo) public userInfo;
// Total allocation poitns. Must be the sum of all allocation points in all pools.
// Total allocation poitns. Must be the sum of all allocation points in all pools.
uint256 private totalAllocPoint = 0;
uint256 private totalAllocPoint = 0;
// The block number when Reward mining starts.
// The block number when Reward mining starts.
uint256 public startBlock;
uint256 public startBlock;
// The block number when mining ends.
// The block number when mining ends.
uint256 public bonusEndBlock;
uint256 public bonusEndBlock;


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


constructor(
constructor(
IBEP20 _stakeToken,
IBEP20 _stakeToken,
IBEP20 _rewardToken,
IBEP20 _rewardToken,
uint256 _rewardPerBlock,
uint256 _rewardPerBlock,
uint256 _startBlock,
uint256 _startBlock,
uint256 _bonusEndBlock
uint256 _bonusEndBlock
) public {
) public {
stakeToken = _stakeToken;
stakeToken = _stakeToken;
rewardToken = _rewardToken;
rewardToken = _rewardToken;
rewardPerBlock = _rewardPerBlock;
rewardPerBlock = _rewardPerBlock;
startBlock = _startBlock;
startBlock = _startBlock;
bonusEndBlock = _bonusEndBlock;
bonusEndBlock = _bonusEndBlock;


// staking pool
// staking pool
poolInfo.push(PoolInfo({
poolInfo.push(PoolInfo({
lpToken: _stakeToken,
lpToken: _stakeToken,
allocPoint: 1000,
allocPoint: 1000,
lastRewardBlock: startBlock,
lastRewardBlock: startBlock,
accRewardTokenPerShare: 0
accRewardTokenPerShare: 0
}));
}));


totalAllocPoint = 1000;
totalAllocPoint = 1000;


}
}


// 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) {
if (_to <= bonusEndBlock) {
if (_to <= bonusEndBlock) {
return _to.sub(_from);
return _to.sub(_from);
} else if (_from >= bonusEndBlock) {
} else if (_from >= bonusEndBlock) {
return 0;
return 0;
} else {
} else {
return bonusEndBlock.sub(_from);
return bonusEndBlock.sub(_from);
}
}
}
}


// View function to see pending Reward on frontend.
// View function to see pending Reward on frontend.
function pendingReward(address _user) external view returns (uint256) {
function pendingReward(address _user) external view returns (uint256) {
PoolInfo storage pool = poolInfo[0];
PoolInfo storage pool = poolInfo[0];
UserInfo storage user = userInfo[_user];
UserInfo storage user = userInfo[_user];
uint256 accRewardTokenPerShare = pool.accRewardTokenPerShare;
uint256 accRewardTokenPerShare = pool.accRewardTokenPerShare;
uint256 lpSupply = pool.lpToken.balanceOf(address(this));
uint256 lpSupply = pool.lpToken.balanceOf(address(this));
if (block.number > pool.lastRewardBlock && lpSupply != 0) {
if (block.number > pool.lastRewardBlock && lpSupply != 0) {
uint256 multiplier = getMultiplier(pool.lastRewardBlock, block.number);
uint256 multiplier = getMultiplier(pool.lastRewardBlock, block.number);
uint256 tokenReward = multiplier.mul(rewardPerBlock).mul(pool.allocPoint).div(totalAllocPoint);
uint256 tokenReward = multiplier.mul(rewardPerBlock).mul(pool.allocPoint).div(totalAllocPoint);
accRewardTokenPerShare = accRewardTokenPerShare.add(tokenReward.mul(1e12).div(lpSupply));
accRewardTokenPerShare = accRewardTokenPerShare.add(tokenReward.mul(1e12).div(lpSupply));
}
}
return user.amount.mul(accRewardTokenPerShare).div(1e12).sub(user.rewardDebt);
return user.amount.mul(accRewardTokenPerShare).div(1e12).sub(user.rewardDebt);
}
}


// 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.number <= pool.lastRewardBlock) {
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.lastRewardBlock = block.number;
return;
return;
}
}
uint256 multiplier = getMultiplier(pool.lastRewardBlock, block.number);
uint256 multiplier = getMultiplier(pool.lastRewardBlock, block.number);
uint256 tokenReward = multiplier.mul(rewardPerBlock).mul(pool.allocPoint).div(totalAllocPoint);
uint256 tokenReward = multiplier.mul(rewardPerBlock).mul(pool.allocPoint).div(totalAllocPoint);
pool.accRewardTokenPerShare = pool.accRewardTokenPerShare.add(tokenReward.mul(1e12).div(lpSupply));
pool.accRewardTokenPerShare = pool.accRewardTokenPerShare.add(tokenReward.mul(1e12).div(lpSupply));
pool.lastRewardBlock = block.number;
pool.lastRewardBlock = block.number;
}
}


// 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);
}
}
}
}




/// Deposit staking token into the contract to earn rewards.
/// Deposit staking token into the contract to earn rewards.
/// @dev Since this contract needs to be supplied with rewards we are
/// @dev Since this contract needs to be supplied with rewards we are
/// sending the balance of the contract if the pending rewards are higher
/// sending the balance of the contract if the pending rewards are higher
/// @param _amount The amount of staking tokens to deposit
/// @param _amount The amount of staking tokens to deposit
function deposit(uint256 _amount) public {
function deposit(uint256 _amount) public {
PoolInfo storage pool = poolInfo[0];
PoolInfo storage pool = poolInfo[0];
UserInfo storage user = userInfo[msg.sender];
UserInfo storage user = userInfo[msg.sender];
updatePool(0);
updatePool(0);
if (user.amount > 0) {
if (user.amount > 0) {
uint256 pending = user.amount.mul(pool.accRewardTokenPerShare).div(1e12).sub(user.rewardDebt);
uint256 pending = user.amount.mul(pool.accRewardTokenPerShare).div(1e12).sub(user.rewardDebt);
if(pending > 0) {
if(pending > 0) {
uint256 currentRewardBalance = rewardBalance();
uint256 currentRewardBalance = rewardBalance();
if(currentRewardBalance > 0) {
if(currentRewardBalance > 0) {
if(pending > currentRewardBalance) {
if(pending > currentRewardBalance) {
safeTransferReward(address(msg.sender), currentRewardBalance);
safeTransferReward(address(msg.sender), currentRewardBalance);
} else {
} else {
safeTransferReward(address(msg.sender), pending);
safeTransferReward(address(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.accRewardTokenPerShare).div(1e12);
user.rewardDebt = user.amount.mul(pool.accRewardTokenPerShare).div(1e12);


emit Deposit(msg.sender, _amount);
emit Deposit(msg.sender, _amount);
}
}


/// Withdraw rewards and/or staked tokens. Pass a 0 amount to withdraw only rewards
/// Withdraw rewards and/or staked tokens. Pass a 0 amount to withdraw only rewards
/// @param _amount The amount of staking tokens to withdraw
/// @param _amount The amount of staking tokens to withdraw
function withdraw(uint256 _amount) public {
function withdraw(uint256 _amount) public {
PoolInfo storage pool = poolInfo[0];
PoolInfo storage pool = poolInfo[0];
UserInfo storage user = userInfo[msg.sender];
UserInfo storage user = userInfo[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.accRewardTokenPerShare).div(1e12).sub(user.rewardDebt);
uint256 pending = user.amount.mul(pool.accRewardTokenPerShare).div(1e12).sub(user.rewardDebt);
if(pending > 0) {
if(pending > 0) {
uint256 currentRewardBalance = rewardBalance();
uint256 currentRewardBalance = rewardBalance();
if(currentRewardBalance > 0) {
if(currentRewardBalance > 0) {
if(pending > currentRewardBalance) {
if(pending > currentRewardBalance) {
safeTransferReward(address(msg.sender), currentRewardBalance);
safeTransferReward(address(msg.sender), currentRewardBalance);
} else {
} else {
safeTransferReward(address(msg.sender), pending);
safeTransferReward(address(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.accRewardTokenPerShare).div(1e12);
user.rewardDebt = user.amount.mul(pool.accRewardTokenPerShare).div(1e12);


emit Withdraw(msg.sender, _amount);
emit Withdraw(msg.sender, _amount);
}
}


/// Obtain the reward balance of this contract
/// Obtain the reward balance of this contract
/// @return wei balace of conract
/// @return wei balace of conract
function rewardBalance() public view returns (uint256) {
function rewardBalance() public view returns (uint256) {
return rewardToken.balanceOf(address(this));
return rewardToken.balanceOf(address(this));
}
}


// Deposit Rewards into contract
// Deposit Rewards into contract
function depositRewards(uint256 _amount) external {
function depositRewards(uint256 _amount) external {
require(_amount > 0, 'Deposit value must be greater than 0.');
require(_amount > 0, 'Deposit value must be greater than 0.');
rewardToken.safeTransferFrom(address(msg.sender), address(this), _amount);
rewardToken.safeTransferFrom(address(msg.sender), address(this), _amount);
emit DepositRewards(_amount);
emit DepositRewards(_amount);
}
}


/// @param _to address to send reward token to
/// @param _to address to send reward token to
/// @param _amount value of reward token to transfer
/// @param _amount value of reward token to transfer
function safeTransferReward(address _to, uint256 _amount) internal {
function safeTransferReward(address _to, uint256 _amount) internal {
rewardToken.safeTransfer(_to, _amount);
rewardToken.safeTransfer(_to, _amount);
}
}


/* Admin Functions */

/// @param _rewardPerBlock The amount of reward tokens to be given per block
function setRewardPerBlock(uint256 _rewardPerBlock) external onlyOwner {
rewardPerBlock = _rewardPerBlock;
}
/// @param _bonusEndBlock The block when rewards will end
function setBonusEndBlock(uint256 _bonusEndBlock) external onlyOwner {
require(_bonusEndBlock > bonusEndBlock, 'new bonus end block must be greater than current');
bonusEndBlock = _bonusEndBlock;
}

/* Emergency Functions */
/* Emergency Functions */


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


// Withdraw reward. EMERGENCY ONLY.
// Withdraw reward. EMERGENCY ONLY.
function emergencyRewardWithdraw(uint256 _amount) external onlyOwner {
function emergencyRewardWithdraw(uint256 _amount) external onlyOwner {
require(_amount <= rewardBalance(), 'not enough rewards');
require(_amount <= rewardBalance(), 'not enough rewards');
// Withdraw rewards
// Withdraw rewards
safeTransferReward(address(msg.sender), _amount);
safeTransferReward(address(msg.sender), _amount);
emit EmergencyRewardWithdraw(msg.sender, _amount);
emit EmergencyRewardWithdraw(msg.sender, _amount);
}
}


}
}