diff --git a/cn b/cn new file mode 160000 index 0000000..dde6d47 --- /dev/null +++ b/cn @@ -0,0 +1 @@ +Subproject commit dde6d47d3b4adb3e187957074596b809f43a462e diff --git a/contracts/DODOToken/DODOMineV2/BaseMine.sol b/contracts/DODOToken/DODOMineV2/BaseMine.sol index 393212a..13bd9f1 100644 --- a/contracts/DODOToken/DODOMineV2/BaseMine.sol +++ b/contracts/DODOToken/DODOMineV2/BaseMine.sol @@ -14,24 +14,21 @@ import {DecimalMath} from "../../lib/DecimalMath.sol"; import {InitializableOwnable} from "../../lib/InitializableOwnable.sol"; import {IRewardVault, RewardVault} from "./RewardVault.sol"; - contract BaseMine is InitializableOwnable { using SafeERC20 for IERC20; using SafeMath for uint256; // ============ Storage ============ - + struct RewardTokenInfo { address rewardToken; uint256 startBlock; uint256 endBlock; address rewardVault; - uint256 rewardPerBlock; uint256 accRewardPerShare; uint256 lastRewardBlock; - - mapping(address => uint256) userRewardPerTokenPaid; + mapping(address => uint256) userRewardPerSharePaid; mapping(address => uint256) userRewards; } @@ -50,54 +47,19 @@ contract BaseMine is InitializableOwnable { // ============ Modifier ========== - modifier updateReward(address user) { - uint256 len = rewardTokenInfos.length; - for (uint i = 0; i < len; i++) { - RewardTokenInfo storage rt = rewardTokenInfos[i]; - rt.accRewardPerShare = rewardPerToken(i); - rt.lastRewardBlock = lastBlockRewardApplicable(i); - if (user != address(0)) { - rt.userRewards[user] = getPendingReward(i, user); - rt.userRewardPerTokenPaid[user] = rt.accRewardPerShare; - } - } - _; - } - // ============ View ============ - function lastBlockRewardApplicable(uint i) public view returns (uint256) { - uint256 startBlock = rewardTokenInfos[i].startBlock; - uint256 endBlock = rewardTokenInfos[i].endBlock; - if(block.number < endBlock) { - if(block.number < startBlock) - return startBlock; - else - return block.number; - }else { - return endBlock; - } - } - - function rewardPerToken(uint i) public view returns (uint256) { + function getPendingReward(address user, uint256 i) public view returns (uint256) { RewardTokenInfo memory rt = rewardTokenInfos[i]; - if (totalSupply() == 0) { - return rt.accRewardPerShare; + uint256 accRewardPerShare = rt.accRewardPerShare; + if (rt.lastRewardBlock != block.number) { + accRewardPerShare = _getAccRewardPerShare(i) } - return rt.accRewardPerShare.add( - DecimalMath.divFloor( - lastBlockRewardApplicable(i).sub(rt.lastRewardBlock).mul(rt.rewardPerBlock), - totalSupply() - ) - ); - } - - function getPendingReward(uint i, address user) public view returns (uint256) { - RewardTokenInfo storage rt = rewardTokenInfos[i]; - return DecimalMath.mulFloor( - balanceOf(user), - rewardPerToken(i).sub(rt.userRewardPerTokenPaid[user]) - ).add(rt.userRewards[user]); + return + DecimalMath.mulFloor( + balanceOf(user), + accRewardPerShare.sub(rt.userRewardPeSharenPaid[user]) + ).add(rt.userRewards[user]); } function totalSupply() public view returns (uint256) { @@ -108,14 +70,26 @@ contract BaseMine is InitializableOwnable { return _balances[user]; } - function getRewardTokenByIdx(uint i) public view returns (address) { + function getRewardTokenById(uint256 i) public view returns (address) { + require(i 0) { @@ -125,23 +99,30 @@ contract BaseMine is InitializableOwnable { } } - function getAllRewards() public { + function claimAllRewards() public { uint256 len = rewardTokenInfos.length; - for (uint i = 0; i < len; i++) { - getReward(i); + for (uint256 i = 0; i < len; i++) { + claimReward(i); } } // =============== Ownable ================ - function addRewardToken(address rewardToken, uint256 startBlock, uint256 endBlock) external onlyOwner { - require(rewardToken != address(0),"DODOMineV2: TOKEN_INVALID"); + function addRewardToken( + address rewardToken, + uint256 startBlock, + uint256 endBlock + ) external onlyOwner { + require(rewardToken != address(0), "DODOMineV2: TOKEN_INVALID"); require(startBlock > block.number, "DODOMineV2: START_BLOCK_INVALID"); - require(endBlock > startBlock ,"DODOMineV2: DURATION_INVALID"); + require(endBlock > startBlock, "DODOMineV2: DURATION_INVALID"); uint256 len = rewardTokenInfos.length; - for (uint i = 0; i < len; i++) { - require(rewardToken != rewardTokenInfos[i].rewardToken, "DODOMineV2: TOKEN_ALREADY_ADDED"); + for (uint256 i = 0; i < len; i++) { + require( + rewardToken != rewardTokenInfos[i].rewardToken, + "DODOMineV2: TOKEN_ALREADY_ADDED" + ); } RewardTokenInfo storage rt = rewardTokenInfos.push(); @@ -165,21 +146,72 @@ contract BaseMine is InitializableOwnable { } } - function setEndBlock(uint i, uint256 newEndBlock) external onlyOwner updateReward(address(0)) { - require(block.number < newEndBlock, "DODOMineV2: END_BLOCK_INVALID"); + function setEndBlock(uint256 i, uint256 newEndBlock) + external + onlyOwner + { + _updateReward(address(0), i); RewardTokenInfo storage rt = rewardTokenInfos[i]; + + require(block.number < newEndBlock, "DODOMineV2: END_BLOCK_INVALID"); require(block.number > rt.startBlock, "DODOMineV2: NOT_START"); require(block.number < rt.endBlock, "DODOMineV2: ALREADY_CLOSE"); + rt.endBlock = newEndBlock; - rt.lastRewardBlock = block.number; emit UpdateEndBlock(i, newEndBlock); } - function setReward(uint i, uint256 newRewardPerBlock) external onlyOwner updateReward(address(0)) { + function setReward(uint256 i, uint256 newRewardPerBlock) + external + onlyOwner + { + _updateReward(address(0), i); RewardTokenInfo storage rt = rewardTokenInfos[i]; - uint256 endBlock = rt.endBlock; - require(block.number < endBlock, "DODOMineV2: ALREADY_FINISHED"); rt.rewardPerBlock = newRewardPerBlock; emit UpdateReward(i, newRewardPerBlock); } + + + // ============ Internal ============ + + function _updateReward(address user, uint256 i) internal { + RewardTokenInfo storage rt = rewardTokenInfos[i]; + if (rt.lastRewardBlock != block.number){ + rt.accRewardPerShare = _getAccRewardPerShare(i); + rt.lastRewardBlock = block.number; + } + if (user != address(0)) { + rt.userRewards[user] = getPendingReward(user, i); + rt.userRewardPerSharePaid[user] = rt.accRewardPerShare; + } + } + + function _updateAllReward(address user) internal { + uint256 len = rewardTokenInfos.length; + for (uint256 i = 0; i < len; i++) { + _updateReward(user, i); + } + } + + function _getUnrewardBlockNum(uint256 i) internal view returns (uint256) { + RewardTokenInfo memory rt = rewardTokenInfos[i]; + if (block.number < rt.startBlock || rt.lastRewardBlock > rt.endBlock) { + return 0; + } + uint256 start = rt.startBlock > block.number ? rt.startBlock : block.number; + uint256 end = rt.endBlock < block.number ? rt.endBlock : block.number; + return end.sub(start); + } + + function _getAccRewardPerShare(uint256 i) internal view returns (uint256) { + RewardTokenInfo memory rt = rewardTokenInfos[i]; + if (totalSupply() == 0) { + return rt.accRewardPerShare; + } + return + rt.accRewardPerShare.add( + DecimalMath.divFloor(_getUnrewardBlockNum(i).mul(rt.rewardPerBlock), totalSupply()) + ); + } + } diff --git a/contracts/DODOToken/DODOMineV2/LpMine.sol b/contracts/DODOToken/DODOMineV2/LpMine.sol index 099cd16..1056b50 100644 --- a/contracts/DODOToken/DODOMineV2/LpMine.sol +++ b/contracts/DODOToken/DODOMineV2/LpMine.sol @@ -17,7 +17,7 @@ contract ERC20Mine is BaseMine { using SafeMath for uint256; // ============ Storage ============ - + address public immutable _TOKEN_; constructor(address token) public { @@ -25,34 +25,31 @@ contract ERC20Mine is BaseMine { } // ============ Event ============ + event Deposit(address indexed user, uint256 amount); event Withdraw(address indexed user, uint256 amount); - // ============ Deposit && Withdraw && Exit ============ - function deposit(uint256 amount) virtual public updateReward(msg.sender) { + function deposit(uint256 amount) public { require(amount > 0, "DODOMineV2: CANNOT_DEPOSIT_ZERO"); + + _updateAllReward(msg.sender); _totalSupply = _totalSupply.add(amount); _balances[msg.sender] = _balances[msg.sender].add(amount); IERC20(_TOKEN_).safeTransferFrom(msg.sender, address(this), amount); + emit Deposit(msg.sender, amount); } - function withdraw(uint256 amount) virtual public updateReward(msg.sender) { + function withdraw(uint256 amount) public { require(amount > 0, "DODOMineV2: CANNOT_WITHDRAW_ZERO"); + + _updateAllReward(msg.sender); _totalSupply = _totalSupply.sub(amount); _balances[msg.sender] = _balances[msg.sender].sub(amount); IERC20(_TOKEN_).safeTransfer(msg.sender, amount); + emit Withdraw(msg.sender, amount); } - - function withdrawAll() external { - withdraw(balanceOf(msg.sender)); - } - - function exit() external { - withdraw(balanceOf(msg.sender)); - getAllRewards(); - } } diff --git a/contracts/DODOToken/DODOMineV2/vDODOMine.sol b/contracts/DODOToken/DODOMineV2/vDODOMine.sol index 73ec96b..fb5dd03 100644 --- a/contracts/DODOToken/DODOMineV2/vDODOMine.sol +++ b/contracts/DODOToken/DODOMineV2/vDODOMine.sol @@ -36,7 +36,10 @@ contract vDODOMine is BaseMine { function deposit(uint256 amount) public { require(amount > 0, "vDODOMineETH: CANNOT_DEPOSIT_ZERO"); - require(IVDODOToken(_vDODO_TOKEN_).availableBalanceOf(msg.sender) >= amount, "vDODOMineETH: vDODO_NOT_ENOUGH"); + require( + amount <= IVDODOToken(_vDODO_TOKEN_).availableBalanceOf(msg.sender), + "vDODOMineETH: vDODO_NOT_ENOUGH" + ); _totalSupply = _totalSupply.add(amount); _balances[msg.sender] = _balances[msg.sender].add(amount); emit Deposit(msg.sender, amount); @@ -44,39 +47,30 @@ contract vDODOMine is BaseMine { function withdraw(uint256 amount) public { require(amount > 0, "DODOMineV2: CANNOT_WITHDRAW_ZERO"); + require(amount <= _balances[msg.sender], "DODOMineV2: WITHDRAW_BALANCE_NOT_ENOUGH"); _totalSupply = _totalSupply.sub(amount); _balances[msg.sender] = _balances[msg.sender].sub(amount); emit Withdraw(msg.sender, amount); } - function withdrawAll() external { - withdraw(balanceOf(msg.sender)); - } - - function exit() external { - withdraw(balanceOf(msg.sender)); - getAllRewards(); - } - // ============ View ============ function getLockedvDODO(address account) external view returns (uint256) { return balanceOf(account); } - // =============== Ownable ================ - function syncBalance(address[] calldata accountList, uint256[] calldata amountList) external onlyOwner { - require(accountList.length == amountList.length, "DODOMineV2: LENGTH_NOT_MATCH"); - for (uint256 i = 0; i < accountList.length; ++i) { - uint256 curBalance = balanceOf(accountList[i]); - if(curBalance > amountList[i]) { - uint256 subAmount = curBalance.sub(amountList[i]); - _totalSupply = _totalSupply.sub(subAmount); - _balances[accountList[i]] = amountList[i]; + function syncBalance(address[] calldata userList) external onlyOwner { + for (uint256 i = 0; i < userList.length; ++i) { + address user = userList[i]; + uint256 curBalance = balanceOf(user); + uint256 vDODOBalance = IERC20(_vDODO_TOKEN_).balanceOf(user); + if (curBalance > vDODOBalance) { + _updateAllReward(user); + _totalSupply = _totalSupply.add(vDODOBalance).sub(curBalance); + _balances[user] = vDODOBalance; } } } - -} \ No newline at end of file +}