BEP20RewardApe-to-BEP20RewardApeV2
1 removal
Words removed | 1 |
Total words | 835 |
Words removed (%) | 0.12 |
236 lines
14 additions
Words added | 59 |
Total words | 893 |
Words added (%) | 6.61 |
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);
}
}
}
}