LPStaking.sol 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. // SPDX-License-Identifier: BUSL-1.1
  2. pragma solidity 0.7.6;
  3. // imports
  4. import "@openzeppelin/contracts/utils/EnumerableSet.sol";
  5. import "@openzeppelin/contracts/access/Ownable.sol";
  6. import "./MirrorgateToken.sol";
  7. // interfaces
  8. import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
  9. // libraries
  10. import "@openzeppelin/contracts/math/SafeMath.sol";
  11. import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
  12. contract LPStaking is Ownable {
  13. using SafeMath for uint256;
  14. using SafeERC20 for IERC20;
  15. // Info of each user.
  16. struct UserInfo {
  17. uint256 amount; // How many LP tokens the user has provided.
  18. uint256 rewardDebt; // Reward debt. See explanation below.
  19. //
  20. // We do some fancy math here. Basically, any point in time, the amount of STGs
  21. // entitled to a user but is pending to be distributed is:
  22. //
  23. // pending reward = (user.amount * pool.accStargatePerShare) - user.rewardDebt
  24. //
  25. // Whenever a user deposits or withdraws LP tokens to a pool. Here's what happens:
  26. // 1. The pool's `accStargatePerShare` (and `lastRewardBlock`) gets updated.
  27. // 2. User receives the pending reward sent to his/her address.
  28. // 3. User's `amount` gets updated.
  29. // 4. User's `rewardDebt` gets updated.
  30. }
  31. // Info of each pool.
  32. struct PoolInfo {
  33. IERC20 lpToken; // Address of LP token contract.
  34. uint256 allocPoint; // How many allocation points assigned to this pool. STGs to distribute per block.
  35. uint256 lastRewardBlock; // Last block number that STGs distribution occurs.
  36. uint256 accMirrorgatePerShare; // Accumulated STGs per share, times 1e12. See below.
  37. }
  38. // The STG TOKEN!
  39. MirrorgateToken public mirrorgate;
  40. // Block number when bonus STG period ends.
  41. uint256 public bonusEndBlock;
  42. // STG tokens created per block.
  43. uint256 public mirrorgatePerBlock;
  44. // Bonus multiplier for early stargate makers.
  45. uint256 public constant BONUS_MULTIPLIER = 1;
  46. // Track which tokens have been added.
  47. mapping(address => bool) private addedLPTokens;
  48. mapping(uint256 => uint256) public lpBalances;
  49. // Info of each pool.
  50. PoolInfo[] public poolInfo;
  51. // Info of each user that stakes LP tokens.
  52. mapping(uint256 => mapping(address => UserInfo)) public userInfo;
  53. // Total allocation points. Must be the sum of all allocation points in all pools.
  54. uint256 public totalAllocPoint = 0;
  55. // The block number when STG mining starts.
  56. uint256 public startBlock;
  57. event Deposit(address indexed user, uint256 indexed pid, uint256 amount);
  58. event Withdraw(address indexed user, uint256 indexed pid, uint256 amount);
  59. event EmergencyWithdraw(address indexed user, uint256 indexed pid, uint256 amount);
  60. constructor(
  61. MirrorgateToken _mirrorgate,
  62. uint256 _mirrorgatePerBlock,
  63. uint256 _startBlock,
  64. uint256 _bonusEndBlock
  65. ) {
  66. require(_startBlock >= block.number, "LPStaking: _startBlock must be >= current block");
  67. require(_bonusEndBlock >= _startBlock, "LPStaking: _bonusEndBlock must be > than _startBlock");
  68. require(address(_mirrorgate) != address(0x0), "Mirrorgate: _mirrorgate cannot be 0x0");
  69. mirrorgate = _mirrorgate;
  70. mirrorgatePerBlock = _mirrorgatePerBlock;
  71. startBlock = _startBlock;
  72. bonusEndBlock = _bonusEndBlock;
  73. }
  74. function poolLength() external view returns (uint256) {
  75. return poolInfo.length;
  76. }
  77. /// @notice handles adding a new LP token (Can only be called by the owner)
  78. /// @param _allocPoint The alloc point is used as the weight of the pool against all other alloc points added.
  79. /// @param _lpToken The lp token address
  80. function add(uint256 _allocPoint, IERC20 _lpToken) public onlyOwner {
  81. massUpdatePools();
  82. require(address(_lpToken) != address(0x0), "Mirrorgate: lpToken cant be 0x0");
  83. require(addedLPTokens[address(_lpToken)] == false, "Mirrorgate: _lpToken already exists");
  84. addedLPTokens[address(_lpToken)] = true;
  85. uint256 lastRewardBlock = block.number > startBlock ? block.number : startBlock;
  86. totalAllocPoint = totalAllocPoint.add(_allocPoint);
  87. poolInfo.push(PoolInfo({lpToken: _lpToken, allocPoint: _allocPoint, lastRewardBlock: lastRewardBlock, accMirrorgatePerShare: 0}));
  88. }
  89. function set(uint256 _pid, uint256 _allocPoint) public onlyOwner {
  90. massUpdatePools();
  91. totalAllocPoint = totalAllocPoint.sub(poolInfo[_pid].allocPoint).add(_allocPoint);
  92. poolInfo[_pid].allocPoint = _allocPoint;
  93. }
  94. function getMultiplier(uint256 _from, uint256 _to) public view returns (uint256) {
  95. if (_to <= bonusEndBlock) {
  96. return _to.sub(_from).mul(BONUS_MULTIPLIER);
  97. } else if (_from >= bonusEndBlock) {
  98. return _to.sub(_from);
  99. } else {
  100. return bonusEndBlock.sub(_from).mul(BONUS_MULTIPLIER).add(_to.sub(bonusEndBlock));
  101. }
  102. }
  103. function pendingMirrorgate(uint256 _pid, address _user) external view returns (uint256) {
  104. PoolInfo storage pool = poolInfo[_pid];
  105. UserInfo storage user = userInfo[_pid][_user];
  106. uint256 accMirrorgatePerShare = pool.accMirrorgatePerShare;
  107. uint256 lpSupply = pool.lpToken.balanceOf(address(this));
  108. if (block.number > pool.lastRewardBlock && lpSupply != 0) {
  109. uint256 multiplier = getMultiplier(pool.lastRewardBlock, block.number);
  110. uint256 mirrorgateReward = multiplier.mul(mirrorgatePerBlock).mul(pool.allocPoint).div(totalAllocPoint);
  111. accMirrorgatePerShare = accMirrorgatePerShare.add(mirrorgateReward.mul(1e12).div(lpSupply));
  112. }
  113. return user.amount.mul(accMirrorgatePerShare).div(1e12).sub(user.rewardDebt);
  114. }
  115. function massUpdatePools() public {
  116. uint256 length = poolInfo.length;
  117. for (uint256 pid = 0; pid < length; ++pid) {
  118. updatePool(pid);
  119. }
  120. }
  121. function updatePool(uint256 _pid) public {
  122. PoolInfo storage pool = poolInfo[_pid];
  123. if (block.number <= pool.lastRewardBlock) {
  124. return;
  125. }
  126. uint256 lpSupply = pool.lpToken.balanceOf(address(this));
  127. if (lpSupply == 0) {
  128. pool.lastRewardBlock = block.number;
  129. return;
  130. }
  131. uint256 multiplier = getMultiplier(pool.lastRewardBlock, block.number);
  132. uint256 mirrorgateReward = multiplier.mul(mirrorgatePerBlock).mul(pool.allocPoint).div(totalAllocPoint);
  133. pool.accMirrorgatePerShare = pool.accMirrorgatePerShare.add(mirrorgateReward.mul(1e12).div(lpSupply));
  134. pool.lastRewardBlock = block.number;
  135. }
  136. function deposit(uint256 _pid, uint256 _amount) public {
  137. PoolInfo storage pool = poolInfo[_pid];
  138. UserInfo storage user = userInfo[_pid][msg.sender];
  139. updatePool(_pid);
  140. if (user.amount > 0) {
  141. uint256 pending = user.amount.mul(pool.accMirrorgatePerShare).div(1e12).sub(user.rewardDebt);
  142. safeMirrorgateTransfer(msg.sender, pending);
  143. }
  144. pool.lpToken.safeTransferFrom(address(msg.sender), address(this), _amount);
  145. user.amount = user.amount.add(_amount);
  146. user.rewardDebt = user.amount.mul(pool.accMirrorgatePerShare).div(1e12);
  147. lpBalances[_pid] = lpBalances[_pid].add(_amount);
  148. emit Deposit(msg.sender, _pid, _amount);
  149. }
  150. function withdraw(uint256 _pid, uint256 _amount) public {
  151. PoolInfo storage pool = poolInfo[_pid];
  152. UserInfo storage user = userInfo[_pid][msg.sender];
  153. require(user.amount >= _amount, "withdraw: _amount is too large");
  154. updatePool(_pid);
  155. uint256 pending = user.amount.mul(pool.accMirrorgatePerShare).div(1e12).sub(user.rewardDebt);
  156. safeMirrorgateTransfer(msg.sender, pending);
  157. user.amount = user.amount.sub(_amount);
  158. user.rewardDebt = user.amount.mul(pool.accMirrorgatePerShare).div(1e12);
  159. pool.lpToken.safeTransfer(address(msg.sender), _amount);
  160. lpBalances[_pid] = lpBalances[_pid].sub(_amount);
  161. emit Withdraw(msg.sender, _pid, _amount);
  162. }
  163. /// @notice Withdraw without caring about rewards.
  164. /// @param _pid The pid specifies the pool
  165. function emergencyWithdraw(uint256 _pid) public {
  166. PoolInfo storage pool = poolInfo[_pid];
  167. UserInfo storage user = userInfo[_pid][msg.sender];
  168. uint256 userAmount = user.amount;
  169. user.amount = 0;
  170. user.rewardDebt = 0;
  171. pool.lpToken.safeTransfer(address(msg.sender), userAmount);
  172. lpBalances[_pid] = lpBalances[_pid].sub(userAmount);
  173. emit EmergencyWithdraw(msg.sender, _pid, userAmount);
  174. }
  175. /// @notice Safe transfer function, just in case if rounding error causes pool to not have enough STGs.
  176. /// @param _to The address to transfer tokens to
  177. /// @param _amount The quantity to transfer
  178. function safeMirrorgateTransfer(address _to, uint256 _amount) internal {
  179. uint256 mirrorgateBal = mirrorgate.balanceOf(address(this));
  180. if (_amount > mirrorgateBal) {
  181. IERC20(mirrorgate).safeTransfer(_to, mirrorgateBal);
  182. } else {
  183. IERC20(mirrorgate).safeTransfer(_to, _amount);
  184. }
  185. }
  186. function setMirrorgatePerBlock(uint256 _mirrorgatePerBlock) external onlyOwner {
  187. massUpdatePools();
  188. mirrorgatePerBlock = _mirrorgatePerBlock;
  189. }
  190. // Override the renounce ownership inherited by zeppelin ownable
  191. function renounceOwnership() public override onlyOwner {}
  192. }