From 5b91969a6861970629dbc176cd4e828ed85e1d7d Mon Sep 17 00:00:00 2001 From: mingda Date: Sun, 7 Feb 2021 15:23:39 +0800 Subject: [PATCH] update vDODO: const ratio 1 vDODO = 100 DODO --- contracts/DODOToken/vDODOToken.sol | 248 +++++++++++++++-------------- 1 file changed, 131 insertions(+), 117 deletions(-) diff --git a/contracts/DODOToken/vDODOToken.sol b/contracts/DODOToken/vDODOToken.sol index e6ac02c..d60ef6f 100644 --- a/contracts/DODOToken/vDODOToken.sol +++ b/contracts/DODOToken/vDODOToken.sol @@ -33,7 +33,6 @@ contract vDODOToken is InitializableOwnable { string public name = "vDODO Token"; string public symbol = "vDODO"; uint8 public decimals = 18; - uint256 public totalSupply; mapping(address => mapping(address => uint256)) internal _ALLOWED_; // ============ Storage ============ @@ -47,19 +46,20 @@ contract vDODOToken is InitializableOwnable { bool public _CAN_TRANSFER_; // staking reward parameters - uint256 public dodoPerBlock; + uint256 public _DODO_PER_BLOCK_; uint256 public constant _SUPERIOR_RATIO_ = 10**17; // 0.1 - uint256 public constant _DODO_RATIO_ = 100 * 10**18; // 100 - uint256 public dodoFeeBurnRation; + uint256 public constant _DODO_RATIO_ = 100; // 100 + uint256 public _DODO_FEE_BURN_RATIO_; // accounting - uint128 public alpha = 10**18; // 1 + uint128 public alpha = 10**18; // 1 uint128 public lastRewardBlock; + uint256 public _TOTAL_STAKING_POWER_; mapping(address => UserInfo) public userInfo; struct UserInfo { - uint128 VDODOAmount; - uint128 superiorVDODO; + uint128 stakingPower; + uint128 superiorSP; address superior; uint256 credit; } @@ -67,11 +67,11 @@ contract vDODOToken is InitializableOwnable { // ============ Events ============ event MintVDODO(address user, address superior, uint256 amount); - event RedeemVDODO(address user, uint256 amount); + event RedeemVDODO(address user, uint256 receiveDODO, uint256 burnDODO, uint256 feeDODO); event SetCantransfer(bool allowed); event ChangePerReward(uint256 dodoPerBlock); - event UpdatedodoFeeBurnRation(uint256 dodoFeeBurnRation); + event UpdateDODOFeeBurnRatio(uint256 dodoFeeBurnRatio); event Transfer(address indexed from, address indexed to, uint256 amount); event Approval(address indexed owner, address indexed spender, uint256 amount); @@ -110,15 +110,15 @@ contract vDODOToken is InitializableOwnable { emit SetCantransfer(allowed); } - function changePerReward(uint256 _dodoPerBlock) public onlyOwner { + function changePerReward(uint256 dodoPerBlock) public onlyOwner { _updateAlpha(); - dodoPerBlock = _dodoPerBlock; - emit ChangePerReward(_dodoPerBlock); + _DODO_PER_BLOCK_ = dodoPerBlock; + emit ChangePerReward(dodoPerBlock); } - function updatedodoFeeBurnRation(uint256 _dodoFeeBurnRation) public onlyOwner { - dodoFeeBurnRation = _dodoFeeBurnRation; - emit UpdatedodoFeeBurnRation(_dodoFeeBurnRation); + function updateDODOFeeBurnRatio(uint256 dodoFeeBurnRatio) public onlyOwner { + _DODO_FEE_BURN_RATIO_ = dodoFeeBurnRatio; + emit UpdateDODOFeeBurnRatio(_DODO_FEE_BURN_RATIO_); } function updateDODOCirculationHelper(address helper) public onlyOwner { @@ -128,7 +128,7 @@ contract vDODOToken is InitializableOwnable { function updateGovernance(address governance) public onlyOwner { _DOOD_GOV_ = governance; } - + function emergencyWithdraw() public onlyOwner { uint256 dodoBalance = IERC20(_DODO_TOKEN_).balanceOf(address(this)); IERC20(_DODO_TOKEN_).transfer(_OWNER_, dodoBalance); @@ -137,11 +137,24 @@ contract vDODOToken is InitializableOwnable { // ============ Functions ============ function mint(uint256 dodoAmount, address superiorAddress) public { - require(superiorAddress != address(0) && superiorAddress != msg.sender, "vDODOToken: Superior INVALID"); + require( + superiorAddress != address(0) && superiorAddress != msg.sender, + "vDODOToken: Superior INVALID" + ); require(dodoAmount > 0, "vDODOToken: must mint greater than 0"); - + + UserInfo storage user = userInfo[msg.sender]; + + if (user.superior == address(0)) { + require( + superiorAddress == _DODO_TEAM_ || userInfo[superiorAddress].superior != address(0), + "vDODOToken: INVALID_SUPERIOR_ADDRESS" + ); + user.superior = superiorAddress; + } + _updateAlpha(); - + IDODOApproveProxy(_DODO_APPROVE_PROXY_).claimTokens( _DODO_TOKEN_, msg.sender, @@ -149,54 +162,47 @@ contract vDODOToken is InitializableOwnable { dodoAmount ); - uint256 newVdodoAmount = DecimalMath.divFloor(dodoAmount,_DODO_RATIO_); + uint256 newStakingPower = DecimalMath.divFloor(dodoAmount, alpha); - UserInfo storage user = userInfo[msg.sender]; - _mint(user, newVdodoAmount); + _mint(user, newStakingPower); - uint256 increSuperiorVDODO = DecimalMath.mulFloor(newVdodoAmount, _SUPERIOR_RATIO_); - - if (user.superior == address(0)) { - require(superiorAddress == _DODO_TEAM_ || userInfo[superiorAddress].superior != address(0), "vDODOToken: INVALID_SUPERIOR_ADDRESS"); - user.superior = superiorAddress; - } - - _mintToSuperior(user, increSuperiorVDODO); - emit MintVDODO(msg.sender, superiorAddress, dodoAmount); } - function redeem(uint256 dodoAmount) - public - balanceEnough(msg.sender, dodoAmount) - { + function redeem(uint256 vdodoAmount, bool all) public balanceEnough(msg.sender, vdodoAmount) { _updateAlpha(); - UserInfo storage user = userInfo[msg.sender]; - uint256 vDodoAmount = DecimalMath.divFloor(dodoAmount,_DODO_RATIO_); - _redeem(user, vDodoAmount); - if (user.superior != address(0)) { - uint256 superiorRedeemVDODO = DecimalMath.mulFloor(vDodoAmount, _SUPERIOR_RATIO_); - _redeemFromSuperior(user, superiorRedeemVDODO); + uint256 dodoAmount; + uint256 stakingPower; + + if (all) { + stakingPower = uint256(user.stakingPower).sub(DecimalMath.divFloor(user.credit, alpha)); + dodoAmount = DecimalMath.mulFloor(stakingPower, alpha); + } else { + dodoAmount = vdodoAmount.mul(_DODO_RATIO_); + stakingPower = DecimalMath.divFloor(dodoAmount, alpha); } - (uint256 dodoReceive, uint256 burnDodoAmount, uint256 withdrawFeeDodoAmount) = getWithdrawAmount(dodoAmount); - + _redeem(user, stakingPower); + + (uint256 dodoReceive, uint256 burnDodoAmount, uint256 withdrawFeeDodoAmount) = + getWithdrawResult(dodoAmount); IERC20(_DODO_TOKEN_).transfer(msg.sender, dodoReceive); - - if(burnDodoAmount > 0){ + if (burnDodoAmount > 0) { IERC20(_DODO_TOKEN_).transfer(address(0), burnDodoAmount); - } - - if(withdrawFeeDodoAmount > 0) { - alpha = uint128(uint256(alpha).add(DecimalMath.divFloor(withdrawFeeDodoAmount, totalSupply))); + } + if (withdrawFeeDodoAmount > 0) { + alpha = uint112( + uint256(alpha).add( + DecimalMath.divFloor(withdrawFeeDodoAmount, _TOTAL_STAKING_POWER_) + ) + ); } - emit RedeemVDODO(msg.sender, dodoAmount); + emit RedeemVDODO(msg.sender, dodoReceive, burnDodoAmount, withdrawFeeDodoAmount); } - function donate(uint256 dodoAmount) public { IDODOApproveProxy(_DODO_APPROVE_PROXY_).claimTokens( _DODO_TOKEN_, @@ -204,46 +210,55 @@ contract vDODOToken is InitializableOwnable { address(this), dodoAmount ); - alpha = uint128(uint256(alpha).add(DecimalMath.divFloor(dodoAmount, totalSupply))); + alpha = uint128( + uint256(alpha).add(DecimalMath.divFloor(dodoAmount, _TOTAL_STAKING_POWER_)) + ); } // ============ Functions(ERC20) ============ + function totalSupply() public view returns (uint256 vDODOSupply) { + vDODOSupply = IERC20(_DODO_TOKEN_).balanceOf(address(this)) / _DODO_RATIO_; + } + function balanceOf(address account) public view returns (uint256 dodoAmount) { UserInfo memory user = userInfo[account]; - dodoAmount = DecimalMath.mulFloor(uint256(user.VDODOAmount),_DODO_RATIO_.add(getLatestAlpha())).sub(user.credit); + dodoAmount = DecimalMath + .mulFloor(uint256(user.stakingPower), getLatestAlpha()) + .mul(_DODO_RATIO_) + .sub(user.credit); } function availableBalanceOf(address account) public view returns (uint256 balance) { - if(_DOOD_GOV_ == address(0)){ + if (_DOOD_GOV_ == address(0)) { balance = balanceOf(account); - }else { + } else { uint256 lockedBalance = IGovernance(_DOOD_GOV_).getLockedDODO(account); balance = balanceOf(account).sub(lockedBalance); } } - function transfer(address to, uint256 dodoAmount) public returns (bool) { + function transfer(address to, uint256 vDODOAmount) public returns (bool) { _updateAlpha(); - _transfer(msg.sender, to, dodoAmount); + _transfer(msg.sender, to, vDODOAmount); return true; } - function approve(address spender, uint256 dodoAmount) public returns (bool) { - _ALLOWED_[msg.sender][spender] = dodoAmount; - emit Approval(msg.sender, spender, dodoAmount); + function approve(address spender, uint256 vDODOAmount) public returns (bool) { + _ALLOWED_[msg.sender][spender] = vDODOAmount; + emit Approval(msg.sender, spender, vDODOAmount); return true; } function transferFrom( address from, address to, - uint256 dodoAmount + uint256 vDODOAmount ) public returns (bool) { - require(dodoAmount <= _ALLOWED_[from][msg.sender], "ALLOWANCE_NOT_ENOUGH"); + require(vDODOAmount <= _ALLOWED_[from][msg.sender], "ALLOWANCE_NOT_ENOUGH"); _updateAlpha(); - _transfer(from, to, dodoAmount); - _ALLOWED_[from][msg.sender] = _ALLOWED_[from][msg.sender].sub(dodoAmount); + _transfer(from, to, vDODOAmount); + _ALLOWED_[from][msg.sender] = _ALLOWED_[from][msg.sender].sub(vDODOAmount); return true; } @@ -253,31 +268,32 @@ contract vDODOToken is InitializableOwnable { // ============ View Functions ============ - function getLatestAlpha() public view returns(uint256) { - uint256 accuDODO = dodoPerBlock * (block.number - lastRewardBlock); - if (totalSupply > 0) { - return uint256(alpha).add(DecimalMath.divFloor(accuDODO, totalSupply)); + function getLatestAlpha() public view returns (uint256) { + uint256 accuDODO = _DODO_PER_BLOCK_ * (block.number - lastRewardBlock); + if (_TOTAL_STAKING_POWER_ > 0) { + return uint256(alpha).add(DecimalMath.divFloor(accuDODO, _TOTAL_STAKING_POWER_)); } else { return alpha; } } - function getWithdrawAmount(uint256 dodoAmount) public view returns(uint256 dodoReceive, uint256 burnDodoAmount, uint256 withdrawFeeDodoAmount) { - uint256 vDodoAmount = DecimalMath.divFloor(dodoAmount,_DODO_RATIO_); - uint256 feeRatio = IDODOCirculationHelper(_DODO_CIRCULATION_HELPER_).getDodoWithdrawFeeRatio(); + function getWithdrawResult(uint256 dodoAmount) + public + view + returns ( + uint256 dodoReceive, + uint256 burnDodoAmount, + uint256 withdrawFeeDodoAmount + ) + { + uint256 feeRatio = + IDODOCirculationHelper(_DODO_CIRCULATION_HELPER_).getDodoWithdrawFeeRatio(); - uint256 newAlpha = getLatestAlpha(); - uint256 withdrawDodoAmount = DecimalMath.mulFloor(vDodoAmount, _DODO_RATIO_.add(newAlpha)); + withdrawFeeDodoAmount = DecimalMath.mulFloor(dodoAmount, feeRatio); + dodoReceive = dodoAmount.sub(withdrawFeeDodoAmount); - withdrawFeeDodoAmount = DecimalMath.mulCeil(withdrawDodoAmount, feeRatio); - dodoReceive = withdrawDodoAmount.sub(withdrawFeeDodoAmount); - - if(dodoFeeBurnRation > 0){ - burnDodoAmount = DecimalMath.mulFloor(withdrawFeeDodoAmount,dodoFeeBurnRation); - withdrawFeeDodoAmount = withdrawFeeDodoAmount.sub(burnDodoAmount); - }else { - burnDodoAmount = 0; - } + burnDodoAmount = DecimalMath.mulFloor(withdrawFeeDodoAmount, _DODO_FEE_BURN_RATIO_); + withdrawFeeDodoAmount = withdrawFeeDodoAmount.sub(burnDodoAmount); } // ============ Internal Functions ============ @@ -289,45 +305,43 @@ contract vDODOToken is InitializableOwnable { lastRewardBlock = uint128(block.number); } - function _mint(UserInfo storage to, uint256 vdodoAmount) internal { - require(vdodoAmount <= uint128(-1), "OVERFLOW"); - to.VDODOAmount = uint128(uint256(to.VDODOAmount).add(vdodoAmount)); - totalSupply = totalSupply.add(vdodoAmount); + function _mint(UserInfo storage to, uint256 stakingPower) internal { + require(stakingPower <= uint128(-1), "OVERFLOW"); + UserInfo storage superior = userInfo[to.superior]; + uint256 superiorIncreSP = DecimalMath.mulFloor(stakingPower, _SUPERIOR_RATIO_); + uint256 superiorIncreCredit = DecimalMath.mulFloor(superiorIncreSP, alpha); + + to.stakingPower = uint128(uint256(to.stakingPower).add(stakingPower)); + to.superiorSP = uint128(uint256(to.superiorSP).add(superiorIncreSP)); + + superior.stakingPower = uint128(uint256(superior.stakingPower).add(superiorIncreSP)); + superior.credit = uint128(uint256(superior.credit).add(superiorIncreCredit)); + + _TOTAL_STAKING_POWER_ = _TOTAL_STAKING_POWER_.add(stakingPower).add(superiorIncreSP); } - function _mintToSuperior(UserInfo storage user, uint256 vdodoAmount) internal { - if (vdodoAmount > 0) { - user.superiorVDODO = uint128(uint256(user.superiorVDODO).add(vdodoAmount)); - UserInfo storage superiorUser = userInfo[user.superior]; - _mint(superiorUser, vdodoAmount); - uint256 dodoAmount = DecimalMath.mulCeil(vdodoAmount, _DODO_RATIO_.add(alpha)); - superiorUser.credit = superiorUser.credit.add(dodoAmount); + function _redeem(UserInfo storage from, uint256 stakingPower) internal { + from.stakingPower = uint128(uint256(from.stakingPower).sub(stakingPower)); + + // superior decrease sp = min(stakingPower*0.1, from.superiorSP) + uint256 superiorDecreSP = DecimalMath.mulFloor(stakingPower, _SUPERIOR_RATIO_); + superiorDecreSP = from.superiorSP <= superiorDecreSP ? from.superiorSP : superiorDecreSP; + from.superiorSP = uint128(uint256(from.superiorSP).sub(superiorDecreSP)); + + UserInfo storage superior = userInfo[from.superior]; + uint256 creditSP = DecimalMath.divFloor(superior.credit, alpha); + + if (superiorDecreSP >= creditSP) { + superior.credit = 0; + superior.stakingPower = uint128(uint256(superior.stakingPower).sub(creditSP)); + } else { + superior.credit = uint128( + uint256(superior.credit).sub(DecimalMath.mulFloor(superiorDecreSP, alpha)) + ); + superior.stakingPower = uint128(uint256(superior.stakingPower).sub(superiorDecreSP)); } - } - function _redeem(UserInfo storage from, uint256 vdodoAmount) internal { - from.VDODOAmount = uint128(uint256(from.VDODOAmount).sub(vdodoAmount)); - totalSupply = totalSupply.sub(vdodoAmount); - } - - function _redeemFromSuperior(UserInfo storage user, uint256 vdodoAmount) internal { - if (vdodoAmount > 0) { - vdodoAmount = user.superiorVDODO <= vdodoAmount ? user.superiorVDODO : vdodoAmount; - user.superiorVDODO = uint128(uint256(user.superiorVDODO).sub(vdodoAmount)); - - UserInfo storage superiorUser = userInfo[user.superior]; - uint256 creditVDODO = DecimalMath.divFloor(superiorUser.credit, _DODO_RATIO_.add(alpha)); - - if (vdodoAmount >= creditVDODO) { - superiorUser.credit = 0; - _redeem(superiorUser, creditVDODO); - } else { - superiorUser.credit = superiorUser.credit.sub( - DecimalMath.mulFloor(vdodoAmount, _DODO_RATIO_.add(alpha)) - ); - _redeem(superiorUser, vdodoAmount); - } - } + _TOTAL_STAKING_POWER_ = _TOTAL_STAKING_POWER_.sub(stakingPower).sub(superiorDecreSP); } function _transfer(