diff --git a/contracts/DODOToken/vDODOToken.sol b/contracts/DODOToken/vDODOToken.sol index b15ab36..79c6c69 100644 --- a/contracts/DODOToken/vDODOToken.sol +++ b/contracts/DODOToken/vDODOToken.sol @@ -16,14 +16,14 @@ import {ReentrancyGuard} from "../lib/ReentrancyGuard.sol"; import {IDODOApproveProxy} from "../SmartRoute/DODOApproveProxy.sol"; interface IGovernance { - function getLockedvDODO(address account) external returns (uint256); + function getLockedvDODO(address account) external view returns (uint256); } interface IDODOCirculationHelper { // vDODO 锁仓不算流通 - function getCirculation() external returns (uint256); + function getCirculation() external view returns (uint256); - function getVDODOWithdrawFeeRatio() external returns (uint256); + function getVDODOWithdrawFeeRatio() external view returns (uint256); } contract vDODOToken is InitializableOwnable, ReentrancyGuard { @@ -49,7 +49,7 @@ contract vDODOToken is InitializableOwnable, ReentrancyGuard { // staking reward parameters uint256 public dodoPerBlock; uint256 public constant _SUPERIOR_RATIO_ = 10**17; // 0.1 - uint256 public dodoFeeDestroyRatio; + uint256 public dodoFeeBurnRation; // accounting uint256 public alpha = 100 * 10**18; // 100 @@ -70,7 +70,7 @@ contract vDODOToken is InitializableOwnable, ReentrancyGuard { event SetCantransfer(bool allowed); event ChangePerReward(uint256 dodoPerBlock); - event UpdateDodoFeeDestroyRatio(uint256 dodoFeeDestroyRatio); + event UpdatedodoFeeBurnRation(uint256 dodoFeeBurnRation); event Transfer(address indexed from, address indexed to, uint256 amount); event Approval(address indexed owner, address indexed spender, uint256 amount); @@ -90,44 +90,44 @@ contract vDODOToken is InitializableOwnable, ReentrancyGuard { // ============ Constructor ============ constructor( - // address _dodoGov, - address _dodoToken, - address _dodoCirculationHelper, - address _dodoApproveProxy, - string memory _name, - string memory _symbol + address dodoGov, + address dodoToken, + address dodoCirculationHelper, + address dodoApproveProxy, + string memory name, + string memory symbol ) public { initOwner(msg.sender); - name = _name; - symbol = _symbol; + name = name; + symbol = symbol; decimals = 18; - _DODO_APPROVE_PROXY_ = _dodoApproveProxy; - // _DOOD_GOV_ = _dodoGov; - _DODO_CIRCULATION_HELPER_ = _dodoCirculationHelper; - _DODO_TOKEN_ = _dodoToken; + _DODO_APPROVE_PROXY_ = dodoApproveProxy; + _DOOD_GOV_ = dodoGov; + _DODO_CIRCULATION_HELPER_ = dodoCirculationHelper; + _DODO_TOKEN_ = dodoToken; lastRewardBlock = block.number; } // ============ Ownable Functions ============` - function setCantransfer(bool _allowed) public onlyOwner { - _CAN_TRANSFER_ = _allowed; - emit SetCantransfer(_allowed); + function setCantransfer(bool allowed) public onlyOwner { + _CAN_TRANSFER_ = allowed; + emit SetCantransfer(allowed); } - function changePerReward(uint256 _dodoPerBlock) public onlyOwner { - _updateAlpha(); - dodoPerBlock = _dodoPerBlock; + function changePerReward(uint256 dodoPerBlock) public onlyOwner { + _updateAlpha(getLatestAlpha()); + dodoPerBlock = dodoPerBlock; emit ChangePerReward(dodoPerBlock); } - function updateDodoFeeDestroyRatio(uint256 _dodoFeeDestroyRatio) public onlyOwner { - dodoFeeDestroyRatio = _dodoFeeDestroyRatio; - emit UpdateDodoFeeDestroyRatio(_dodoFeeDestroyRatio); + function updatedodoFeeBurnRation(uint256 dodoFeeBurnRation) public onlyOwner { + dodoFeeBurnRation = dodoFeeBurnRation; + emit UpdatedodoFeeBurnRation(dodoFeeBurnRation); } - function updateDODOCirculationHelper(address _helper) public onlyOwner { - _DODO_CIRCULATION_HELPER_ = _helper; + function updateDODOCirculationHelper(address helper) public onlyOwner { + _DODO_CIRCULATION_HELPER_ = helper; } function updateGovernance(address _governance) public onlyOwner { _DOOD_GOV_ = _governance; @@ -135,66 +135,78 @@ contract vDODOToken is InitializableOwnable, ReentrancyGuard { // ============ Functions ============ - function mint(uint256 _dodoAmount, address _superiorAddress) public preventReentrant { - require(_dodoAmount > 0, "vDODOToken: must deposit greater than 0"); + function mint(uint256 dodoAmount, address superiorAddress) public preventReentrant { + require(dodoAmount > 0, "vDODOToken: must mint greater than 0"); IDODOApproveProxy(_DODO_APPROVE_PROXY_).claimTokens( _DODO_TOKEN_, msg.sender, address(this), - _dodoAmount + dodoAmount ); + uint256 newAlpha = getLatestAlpha(); - _updateAlpha(); - uint256 newVdodoAmount = DecimalMath.divFloor(_dodoAmount, alpha); + uint256 newVdodoAmount = DecimalMath.divFloor(dodoAmount, newAlpha); UserInfo storage user = userInfo[msg.sender]; _mint(user, newVdodoAmount); uint256 superiorVDODO; - if (user.superior == address(0) && _superiorAddress != address(0) && _superiorAddress != msg.sender ) { - require(_superiorAddress != msg.sender, "COULD NOT SET SELF AS SUPERIOR"); - superiorVDODO = DecimalMath.divFloor(user.VDODOAmount, _SUPERIOR_RATIO_); - user.superior = _superiorAddress; + if (user.superior == address(0) && superiorAddress != address(0)) { + require(superiorAddress != msg.sender, "COULD NOT SET SELF AS SUPERIOR"); + superiorVDODO = DecimalMath.mulFloor(user.VDODOAmount, _SUPERIOR_RATIO_); + user.superior = superiorAddress; } else if (user.superior != address(0)) { - superiorVDODO = DecimalMath.divFloor(newVdodoAmount, _SUPERIOR_RATIO_); + superiorVDODO = DecimalMath.mulFloor(newVdodoAmount, _SUPERIOR_RATIO_); } _mintToSuperior(user, superiorVDODO); + + _updateAlpha(newAlpha); - emit Deposit(msg.sender, _superiorAddress, _dodoAmount); + emit Deposit(msg.sender, superiorAddress, dodoAmount); } - function redeem(uint256 _vDodoAmount) + function redeem(uint256 vDodoAmount) public preventReentrant - balanceEnough(msg.sender, _vDodoAmount) + balanceEnough(msg.sender, vDodoAmount) { - _updateAlpha(); + uint256 newAlpha = getLatestAlpha(); UserInfo storage user = userInfo[msg.sender]; - _redeem(user, _vDodoAmount); + _redeem(user, vDodoAmount); if (user.superior != address(0)) { - uint256 superiorRedeemVDODO = DecimalMath.divFloor(_vDodoAmount, _SUPERIOR_RATIO_); + uint256 superiorRedeemVDODO = DecimalMath.mulFloor(vDodoAmount, _SUPERIOR_RATIO_); _redeemFromSuperior(user, superiorRedeemVDODO); } - (uint256 dodoReceive, uint256 destroyDodoAmount, uint256 withdrawFeeDodoAmount) = getWithdrawAmount(_vDodoAmount); + (uint256 dodoReceive, uint256 burnDodoAmount, uint256 withdrawFeeDodoAmount) = getWithdrawAmount(vDodoAmount); IERC20(_DODO_TOKEN_).transfer(msg.sender, dodoReceive); - _transfer(address(this), address(0), destroyDodoAmount); + _transfer(address(this), address(0), burnDodoAmount); - tmpAlpha = tmpAlpha.add(DecimalMath.divFloor(withdrawFeeDodoAmount, totalSupply)); - _updateAlpha(tmpAlpha); + newAlpha = newAlpha.add(DecimalMath.divFloor(withdrawFeeDodoAmount, totalSupply)); + _updateAlpha(newAlpha); - emit Withdraw(msg.sender, _vDodoAmount); + emit Withdraw(msg.sender, vDodoAmount); + } + + function donate(uint256 dodoAmount) public { + IDODOApproveProxy(_DODO_APPROVE_PROXY_).claimTokens( + _DODO_TOKEN_, + msg.sender, + address(this), + dodoAmount + ); + alpha = alpha.add(DecimalMath.divFloor(dodoAmount, totalSupply)); } // ============ Functions(ERC20) ============ function balanceOf(address account) public view returns (uint256 balance) { UserInfo memory user = userInfo[account]; - balance = user.VDODOAmount.sub(DecimalMath.divFloor(user.credit, alpha)); + balance = user.VDODOAmount.sub(DecimalMath.divFloor(user.credit, getLatestAlpha())); } function availableBalanceOf(address account) public returns (uint256 balance) { @@ -231,56 +243,82 @@ contract vDODOToken is InitializableOwnable, ReentrancyGuard { // ============ View Functions ============ - function canWithDraw(address _address) public view returns (uint256 withDrawAmount) { - UserInfo memory user = userInfo[_address]; - withDrawAmount = user.VDODOAmount.mul(alpha).sub(user.credit); + function canWithdraw(address account) public view returns (uint256 dodoAmount) { + UserInfo memory user = userInfo[account]; + dodoAmount = DecimalMath.mulFloor(user.VDODOAmount,getLatestAlpha()).sub(user.credit); } - // ============ internal function ============ - - function _updateAlpha() internal { + function getLatestAlpha() public view returns(uint256) { uint256 accuDODO = dodoPerBlock * (block.number.sub(lastRewardBlock)); if (totalSupply > 0) { - alpha = alpha.add(DecimalMath.divFloor(accuDODO, totalSupply)); + return alpha.add(DecimalMath.divFloor(accuDODO, totalSupply)); + } else { + return alpha; } + } + + function getWithdrawAmount(uint256 vDodoAmount) public view returns(uint256 dodoReceive, uint256 burnDodoAmount, uint256 withdrawFeeDodoAmount) { + uint256 feeRatio = IDODOCirculationHelper(_DODO_CIRCULATION_HELPER_).getVDODOWithdrawFeeRatio(); + + uint256 newAlpha = getLatestAlpha(); + uint256 withdrawDodoAmount = DecimalMath.mulFloor(vDodoAmount, newAlpha); + + withdrawFeeDodoAmount = DecimalMath.mulCeil(withdrawDodoAmount, feeRatio); + dodoReceive = withdrawDodoAmount.sub(withdrawFeeDodoAmount); + + if(dodoFeeBurnRation > 0){ + burnDodoAmount = DecimalMath.mulFloor(withdrawFeeDodoAmount,dodoFeeBurnRation); + withdrawFeeDodoAmount = withdrawFeeDodoAmount.sub(burnDodoAmount); + }else { + burnDodoAmount = 0; + } + } + + // ============ Internal Functions ============ + + function _updateAlpha(uint256 newAlpha) internal { + alpha = newAlpha; lastRewardBlock = block.number; } - function _mint(UserInfo storage to, uint256 amount) internal { - to.VDODOAmount = to.VDODOAmount.add(amount); - totalSupply = totalSupply.add(amount); + function _mint(UserInfo storage to, uint256 vdodoAmount) internal { + to.VDODOAmount = to.VDODOAmount.add(vdodoAmount); + totalSupply = totalSupply.add(vdodoAmount); } function _mintToSuperior(UserInfo storage user, uint256 vdodoAmount) internal { if (vdodoAmount > 0) { + uint256 newAlpha = getLatestAlpha(); + user.superiorVDODO = user.superiorVDODO.add(vdodoAmount); UserInfo storage superiorUser = userInfo[user.superior]; _mint(superiorUser, vdodoAmount); - superiorUser.credit = superiorUser.credit.add(DecimalMath.mulFloor(vdodoAmount, alpha)); + uint256 dodoAmount = DecimalMath.mulFloor(vdodoAmount, newAlpha); + superiorUser.credit = superiorUser.credit.add(DecimalMath.mulFloor(dodoAmount, _SUPERIOR_RATIO_)); } } - function _redeem(UserInfo storage from, uint256 amount) internal { - from.VDODOAmount = from.VDODOAmount.sub(amount); - totalSupply = totalSupply.sub(amount); + function _redeem(UserInfo storage from, uint256 vdodoAmount) internal { + from.VDODOAmount = from.VDODOAmount.sub(vdodoAmount); + totalSupply = totalSupply.sub(vdodoAmount); } function _redeemFromSuperior(UserInfo storage user, uint256 vdodoAmount) internal { if (vdodoAmount > 0) { - // 最多撤销当时给superior的 + uint256 newAlpha = getLatestAlpha(); + vdodoAmount = user.superiorVDODO <= vdodoAmount ? user.superiorVDODO : vdodoAmount; user.superiorVDODO = user.superiorVDODO.sub(vdodoAmount); - // 最多撤销superior的全部credit UserInfo storage superiorUser = userInfo[user.superior]; - uint256 creditVDODO = DecimalMath.divFloor(superiorUser.credit, alpha); + uint256 creditVDODO = DecimalMath.divFloor(superiorUser.credit, newAlpha); if (vdodoAmount >= creditVDODO) { superiorUser.credit = 0; _redeem(superiorUser, creditVDODO); } else { superiorUser.credit = superiorUser.credit.sub( - DecimalMath.mulFloor(vdodoAmount, alpha) + DecimalMath.mulFloor(vdodoAmount, newAlpha) ); _redeem(superiorUser, vdodoAmount); } @@ -301,47 +339,16 @@ contract vDODOToken is InitializableOwnable, ReentrancyGuard { UserInfo storage toUser = userInfo[to]; toUser.VDODOAmount = toUser.VDODOAmount.add(_amount); - uint256 superiorRedeemVDODO = DecimalMath.divFloor(_amount, _SUPERIOR_RATIO_); + uint256 superiorRedeemVDODO = DecimalMath.mulFloor(_amount, _SUPERIOR_RATIO_); - address fromSuperiorAddr = fromUser.superior; - if (fromSuperiorAddr != address(0)) { + if (fromUser.superior != address(0)) { _redeemFromSuperior(fromUser, superiorRedeemVDODO); + } - address toSuperiorAddr = toUser.superior; - if (toSuperiorAddr != address(0)) { + if (toUser.superior != address(0)) { _mintToSuperior(toUser, superiorRedeemVDODO); } emit Transfer(from, to, _amount); - - } - - function getWithdrawAmount(uint256 vDodoAmount) public view returns(uint256 dodoReceive, uint256 destroyDodoAmount, uint256 withdrawFeeDodoAmount) { - - uint256 feeRatio = - IDODOCirculationHelper(_DODO_CIRCULATION_HELPER_).getVDODOWithdrawFeeRatio(); - - uint256 tmpAlpha = getAlpha(); - uint256 withdrawDodoAmount = DecimalMath.mulFloor(_vDodoAmount, tmpAlpha); - - withdrawFeeDodoAmount = DecimalMath.mulCeil(withdrawDodoAmount, feeRatio); - dodoReceive = withdrawDodoAmount.sub(withdrawFeeDodoAmount); - - if(dodoFeeDestroyRatio > 0){ - destroyDodoAmount = DecimalMath.mulCeil(withdrawDodoAmount,dodoFeeDestroyRatio).div(100); - withdrawFeeDodoAmount = withdrawFeeDodoAmount.sub(destroyDodoAmount); - }else { - destroyDodoAmount = 0; - } - - // ============ internal function ============ - function _updateAlpha(uint256 newAlpha) internal { - alpha = newAlpha; - lastRewardBlock = block.number; - } - - function donate(uint256 amount) public { - IERC20(_DODO_TOKEN_).transferFrom(msg.sender, address(this), amount); - alpha = alpha.add(DecimalMath.divFloor(amount, totalSupply)); } }