update vDODO: const ratio 1 vDODO = 100 DODO

This commit is contained in:
mingda
2021-02-07 15:23:39 +08:00
committed by owen05
parent 24ab08ebfa
commit 5b91969a68

View File

@@ -33,7 +33,6 @@ contract vDODOToken is InitializableOwnable {
string public name = "vDODO Token"; string public name = "vDODO Token";
string public symbol = "vDODO"; string public symbol = "vDODO";
uint8 public decimals = 18; uint8 public decimals = 18;
uint256 public totalSupply;
mapping(address => mapping(address => uint256)) internal _ALLOWED_; mapping(address => mapping(address => uint256)) internal _ALLOWED_;
// ============ Storage ============ // ============ Storage ============
@@ -47,19 +46,20 @@ contract vDODOToken is InitializableOwnable {
bool public _CAN_TRANSFER_; bool public _CAN_TRANSFER_;
// staking reward parameters // staking reward parameters
uint256 public dodoPerBlock; uint256 public _DODO_PER_BLOCK_;
uint256 public constant _SUPERIOR_RATIO_ = 10**17; // 0.1 uint256 public constant _SUPERIOR_RATIO_ = 10**17; // 0.1
uint256 public constant _DODO_RATIO_ = 100 * 10**18; // 100 uint256 public constant _DODO_RATIO_ = 100; // 100
uint256 public dodoFeeBurnRation; uint256 public _DODO_FEE_BURN_RATIO_;
// accounting // accounting
uint128 public alpha = 10**18; // 1 uint128 public alpha = 10**18; // 1
uint128 public lastRewardBlock; uint128 public lastRewardBlock;
uint256 public _TOTAL_STAKING_POWER_;
mapping(address => UserInfo) public userInfo; mapping(address => UserInfo) public userInfo;
struct UserInfo { struct UserInfo {
uint128 VDODOAmount; uint128 stakingPower;
uint128 superiorVDODO; uint128 superiorSP;
address superior; address superior;
uint256 credit; uint256 credit;
} }
@@ -67,11 +67,11 @@ contract vDODOToken is InitializableOwnable {
// ============ Events ============ // ============ Events ============
event MintVDODO(address user, address superior, uint256 amount); 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 SetCantransfer(bool allowed);
event ChangePerReward(uint256 dodoPerBlock); event ChangePerReward(uint256 dodoPerBlock);
event UpdatedodoFeeBurnRation(uint256 dodoFeeBurnRation); event UpdateDODOFeeBurnRatio(uint256 dodoFeeBurnRatio);
event Transfer(address indexed from, address indexed to, uint256 amount); event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(address indexed owner, address indexed spender, uint256 amount); event Approval(address indexed owner, address indexed spender, uint256 amount);
@@ -110,15 +110,15 @@ contract vDODOToken is InitializableOwnable {
emit SetCantransfer(allowed); emit SetCantransfer(allowed);
} }
function changePerReward(uint256 _dodoPerBlock) public onlyOwner { function changePerReward(uint256 dodoPerBlock) public onlyOwner {
_updateAlpha(); _updateAlpha();
dodoPerBlock = _dodoPerBlock; _DODO_PER_BLOCK_ = dodoPerBlock;
emit ChangePerReward(_dodoPerBlock); emit ChangePerReward(dodoPerBlock);
} }
function updatedodoFeeBurnRation(uint256 _dodoFeeBurnRation) public onlyOwner { function updateDODOFeeBurnRatio(uint256 dodoFeeBurnRatio) public onlyOwner {
dodoFeeBurnRation = _dodoFeeBurnRation; _DODO_FEE_BURN_RATIO_ = dodoFeeBurnRatio;
emit UpdatedodoFeeBurnRation(_dodoFeeBurnRation); emit UpdateDODOFeeBurnRatio(_DODO_FEE_BURN_RATIO_);
} }
function updateDODOCirculationHelper(address helper) public onlyOwner { function updateDODOCirculationHelper(address helper) public onlyOwner {
@@ -128,7 +128,7 @@ contract vDODOToken is InitializableOwnable {
function updateGovernance(address governance) public onlyOwner { function updateGovernance(address governance) public onlyOwner {
_DOOD_GOV_ = governance; _DOOD_GOV_ = governance;
} }
function emergencyWithdraw() public onlyOwner { function emergencyWithdraw() public onlyOwner {
uint256 dodoBalance = IERC20(_DODO_TOKEN_).balanceOf(address(this)); uint256 dodoBalance = IERC20(_DODO_TOKEN_).balanceOf(address(this));
IERC20(_DODO_TOKEN_).transfer(_OWNER_, dodoBalance); IERC20(_DODO_TOKEN_).transfer(_OWNER_, dodoBalance);
@@ -137,11 +137,24 @@ contract vDODOToken is InitializableOwnable {
// ============ Functions ============ // ============ Functions ============
function mint(uint256 dodoAmount, address superiorAddress) public { 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"); 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(); _updateAlpha();
IDODOApproveProxy(_DODO_APPROVE_PROXY_).claimTokens( IDODOApproveProxy(_DODO_APPROVE_PROXY_).claimTokens(
_DODO_TOKEN_, _DODO_TOKEN_,
msg.sender, msg.sender,
@@ -149,54 +162,47 @@ contract vDODOToken is InitializableOwnable {
dodoAmount dodoAmount
); );
uint256 newVdodoAmount = DecimalMath.divFloor(dodoAmount,_DODO_RATIO_); uint256 newStakingPower = DecimalMath.divFloor(dodoAmount, alpha);
UserInfo storage user = userInfo[msg.sender]; _mint(user, newStakingPower);
_mint(user, newVdodoAmount);
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); emit MintVDODO(msg.sender, superiorAddress, dodoAmount);
} }
function redeem(uint256 dodoAmount) function redeem(uint256 vdodoAmount, bool all) public balanceEnough(msg.sender, vdodoAmount) {
public
balanceEnough(msg.sender, dodoAmount)
{
_updateAlpha(); _updateAlpha();
UserInfo storage user = userInfo[msg.sender]; UserInfo storage user = userInfo[msg.sender];
uint256 vDodoAmount = DecimalMath.divFloor(dodoAmount,_DODO_RATIO_);
_redeem(user, vDodoAmount);
if (user.superior != address(0)) { uint256 dodoAmount;
uint256 superiorRedeemVDODO = DecimalMath.mulFloor(vDodoAmount, _SUPERIOR_RATIO_); uint256 stakingPower;
_redeemFromSuperior(user, superiorRedeemVDODO);
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); IERC20(_DODO_TOKEN_).transfer(msg.sender, dodoReceive);
if (burnDodoAmount > 0) {
if(burnDodoAmount > 0){
IERC20(_DODO_TOKEN_).transfer(address(0), burnDodoAmount); IERC20(_DODO_TOKEN_).transfer(address(0), burnDodoAmount);
} }
if (withdrawFeeDodoAmount > 0) {
if(withdrawFeeDodoAmount > 0) { alpha = uint112(
alpha = uint128(uint256(alpha).add(DecimalMath.divFloor(withdrawFeeDodoAmount, totalSupply))); 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 { function donate(uint256 dodoAmount) public {
IDODOApproveProxy(_DODO_APPROVE_PROXY_).claimTokens( IDODOApproveProxy(_DODO_APPROVE_PROXY_).claimTokens(
_DODO_TOKEN_, _DODO_TOKEN_,
@@ -204,46 +210,55 @@ contract vDODOToken is InitializableOwnable {
address(this), address(this),
dodoAmount dodoAmount
); );
alpha = uint128(uint256(alpha).add(DecimalMath.divFloor(dodoAmount, totalSupply))); alpha = uint128(
uint256(alpha).add(DecimalMath.divFloor(dodoAmount, _TOTAL_STAKING_POWER_))
);
} }
// ============ Functions(ERC20) ============ // ============ 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) { function balanceOf(address account) public view returns (uint256 dodoAmount) {
UserInfo memory user = userInfo[account]; 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) { function availableBalanceOf(address account) public view returns (uint256 balance) {
if(_DOOD_GOV_ == address(0)){ if (_DOOD_GOV_ == address(0)) {
balance = balanceOf(account); balance = balanceOf(account);
}else { } else {
uint256 lockedBalance = IGovernance(_DOOD_GOV_).getLockedDODO(account); uint256 lockedBalance = IGovernance(_DOOD_GOV_).getLockedDODO(account);
balance = balanceOf(account).sub(lockedBalance); balance = balanceOf(account).sub(lockedBalance);
} }
} }
function transfer(address to, uint256 dodoAmount) public returns (bool) { function transfer(address to, uint256 vDODOAmount) public returns (bool) {
_updateAlpha(); _updateAlpha();
_transfer(msg.sender, to, dodoAmount); _transfer(msg.sender, to, vDODOAmount);
return true; return true;
} }
function approve(address spender, uint256 dodoAmount) public returns (bool) { function approve(address spender, uint256 vDODOAmount) public returns (bool) {
_ALLOWED_[msg.sender][spender] = dodoAmount; _ALLOWED_[msg.sender][spender] = vDODOAmount;
emit Approval(msg.sender, spender, dodoAmount); emit Approval(msg.sender, spender, vDODOAmount);
return true; return true;
} }
function transferFrom( function transferFrom(
address from, address from,
address to, address to,
uint256 dodoAmount uint256 vDODOAmount
) public returns (bool) { ) public returns (bool) {
require(dodoAmount <= _ALLOWED_[from][msg.sender], "ALLOWANCE_NOT_ENOUGH"); require(vDODOAmount <= _ALLOWED_[from][msg.sender], "ALLOWANCE_NOT_ENOUGH");
_updateAlpha(); _updateAlpha();
_transfer(from, to, dodoAmount); _transfer(from, to, vDODOAmount);
_ALLOWED_[from][msg.sender] = _ALLOWED_[from][msg.sender].sub(dodoAmount); _ALLOWED_[from][msg.sender] = _ALLOWED_[from][msg.sender].sub(vDODOAmount);
return true; return true;
} }
@@ -253,31 +268,32 @@ contract vDODOToken is InitializableOwnable {
// ============ View Functions ============ // ============ View Functions ============
function getLatestAlpha() public view returns(uint256) { function getLatestAlpha() public view returns (uint256) {
uint256 accuDODO = dodoPerBlock * (block.number - lastRewardBlock); uint256 accuDODO = _DODO_PER_BLOCK_ * (block.number - lastRewardBlock);
if (totalSupply > 0) { if (_TOTAL_STAKING_POWER_ > 0) {
return uint256(alpha).add(DecimalMath.divFloor(accuDODO, totalSupply)); return uint256(alpha).add(DecimalMath.divFloor(accuDODO, _TOTAL_STAKING_POWER_));
} else { } else {
return alpha; return alpha;
} }
} }
function getWithdrawAmount(uint256 dodoAmount) public view returns(uint256 dodoReceive, uint256 burnDodoAmount, uint256 withdrawFeeDodoAmount) { function getWithdrawResult(uint256 dodoAmount)
uint256 vDodoAmount = DecimalMath.divFloor(dodoAmount,_DODO_RATIO_); public
uint256 feeRatio = IDODOCirculationHelper(_DODO_CIRCULATION_HELPER_).getDodoWithdrawFeeRatio(); view
returns (
uint256 dodoReceive,
uint256 burnDodoAmount,
uint256 withdrawFeeDodoAmount
)
{
uint256 feeRatio =
IDODOCirculationHelper(_DODO_CIRCULATION_HELPER_).getDodoWithdrawFeeRatio();
uint256 newAlpha = getLatestAlpha(); withdrawFeeDodoAmount = DecimalMath.mulFloor(dodoAmount, feeRatio);
uint256 withdrawDodoAmount = DecimalMath.mulFloor(vDodoAmount, _DODO_RATIO_.add(newAlpha)); dodoReceive = dodoAmount.sub(withdrawFeeDodoAmount);
withdrawFeeDodoAmount = DecimalMath.mulCeil(withdrawDodoAmount, feeRatio); burnDodoAmount = DecimalMath.mulFloor(withdrawFeeDodoAmount, _DODO_FEE_BURN_RATIO_);
dodoReceive = withdrawDodoAmount.sub(withdrawFeeDodoAmount); withdrawFeeDodoAmount = withdrawFeeDodoAmount.sub(burnDodoAmount);
if(dodoFeeBurnRation > 0){
burnDodoAmount = DecimalMath.mulFloor(withdrawFeeDodoAmount,dodoFeeBurnRation);
withdrawFeeDodoAmount = withdrawFeeDodoAmount.sub(burnDodoAmount);
}else {
burnDodoAmount = 0;
}
} }
// ============ Internal Functions ============ // ============ Internal Functions ============
@@ -289,45 +305,43 @@ contract vDODOToken is InitializableOwnable {
lastRewardBlock = uint128(block.number); lastRewardBlock = uint128(block.number);
} }
function _mint(UserInfo storage to, uint256 vdodoAmount) internal { function _mint(UserInfo storage to, uint256 stakingPower) internal {
require(vdodoAmount <= uint128(-1), "OVERFLOW"); require(stakingPower <= uint128(-1), "OVERFLOW");
to.VDODOAmount = uint128(uint256(to.VDODOAmount).add(vdodoAmount)); UserInfo storage superior = userInfo[to.superior];
totalSupply = totalSupply.add(vdodoAmount); 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 { function _redeem(UserInfo storage from, uint256 stakingPower) internal {
if (vdodoAmount > 0) { from.stakingPower = uint128(uint256(from.stakingPower).sub(stakingPower));
user.superiorVDODO = uint128(uint256(user.superiorVDODO).add(vdodoAmount));
UserInfo storage superiorUser = userInfo[user.superior]; // superior decrease sp = min(stakingPower*0.1, from.superiorSP)
_mint(superiorUser, vdodoAmount); uint256 superiorDecreSP = DecimalMath.mulFloor(stakingPower, _SUPERIOR_RATIO_);
uint256 dodoAmount = DecimalMath.mulCeil(vdodoAmount, _DODO_RATIO_.add(alpha)); superiorDecreSP = from.superiorSP <= superiorDecreSP ? from.superiorSP : superiorDecreSP;
superiorUser.credit = superiorUser.credit.add(dodoAmount); 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 { _TOTAL_STAKING_POWER_ = _TOTAL_STAKING_POWER_.sub(stakingPower).sub(superiorDecreSP);
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);
}
}
} }
function _transfer( function _transfer(