@@ -32,3 +32,4 @@ Anyone who reports a unique, previously-unreported vulnerability that results in
|
||||
## Contact Us
|
||||
|
||||
Send E-mail to contact@dodoex.io
|
||||
|
||||
|
||||
95
contracts/DODOToken/DODOBscToken.sol
Normal file
95
contracts/DODOToken/DODOBscToken.sol
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 DODO ZOO.
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity 0.6.9;
|
||||
|
||||
import {SafeMath} from "../lib/SafeMath.sol";
|
||||
import {InitializableOwnable} from "../lib/InitializableOwnable.sol";
|
||||
|
||||
/**
|
||||
* @title DODO Token Mapped on BSC
|
||||
* @author DODO Breeder
|
||||
*/
|
||||
contract DODOBscToken is InitializableOwnable {
|
||||
using SafeMath for uint256;
|
||||
|
||||
string public name = "DODO bird";
|
||||
uint256 public decimals = 18;
|
||||
string public symbol = "DODO";
|
||||
uint256 public totalSupply;
|
||||
|
||||
mapping(address => uint256) balances;
|
||||
mapping(address => mapping(address => uint256)) internal allowed;
|
||||
|
||||
|
||||
event Transfer(address indexed from, address indexed to, uint256 amount);
|
||||
event Approval(address indexed owner, address indexed spender, uint256 amount);
|
||||
event Mint(address indexed user, uint256 value);
|
||||
event Burn(address indexed user, uint256 value);
|
||||
event Redeem(address indexed sender, address indexed redeemToEthAccount, uint256 value);
|
||||
|
||||
function transfer(address to, uint256 amount) public returns (bool) {
|
||||
require(to != address(0), "TO_ADDRESS_IS_EMPTY");
|
||||
require(amount <= balances[msg.sender], "BALANCE_NOT_ENOUGH");
|
||||
|
||||
balances[msg.sender] = balances[msg.sender].sub(amount);
|
||||
balances[to] = balances[to].add(amount);
|
||||
emit Transfer(msg.sender, to, amount);
|
||||
return true;
|
||||
}
|
||||
|
||||
function balanceOf(address owner) public view returns (uint256 balance) {
|
||||
return balances[owner];
|
||||
}
|
||||
|
||||
function transferFrom(
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
) public returns (bool) {
|
||||
require(to != address(0), "TO_ADDRESS_IS_EMPTY");
|
||||
require(amount <= balances[from], "BALANCE_NOT_ENOUGH");
|
||||
require(amount <= allowed[from][msg.sender], "ALLOWANCE_NOT_ENOUGH");
|
||||
|
||||
balances[from] = balances[from].sub(amount);
|
||||
balances[to] = balances[to].add(amount);
|
||||
allowed[from][msg.sender] = allowed[from][msg.sender].sub(amount);
|
||||
emit Transfer(from, to, amount);
|
||||
return true;
|
||||
}
|
||||
|
||||
function approve(address spender, uint256 amount) public returns (bool) {
|
||||
allowed[msg.sender][spender] = amount;
|
||||
emit Approval(msg.sender, spender, amount);
|
||||
return true;
|
||||
}
|
||||
|
||||
function allowance(address owner, address spender) public view returns (uint256) {
|
||||
return allowed[owner][spender];
|
||||
}
|
||||
|
||||
function redeem(uint256 amount, uint256 value, address redeemToEthAccount) external {
|
||||
require(balances[msg.sender] >= value, "DODOBscToken: NOT_ENOUGH");
|
||||
balances[msg.sender] = balances[msg.sender].sub(value);
|
||||
totalSupply = totalSupply.sub(value);
|
||||
emit Redeem(msg.sender, redeemToEthAccount, value);
|
||||
}
|
||||
|
||||
function mint(address user, uint256 value) external onlyOwner {
|
||||
balances[user] = balances[user].add(value);
|
||||
totalSupply = totalSupply.add(value);
|
||||
emit Mint(user, value);
|
||||
emit Transfer(address(0), user, value);
|
||||
}
|
||||
|
||||
function burn(address user, uint256 value) external onlyOwner {
|
||||
balances[user] = balances[user].sub(value);
|
||||
totalSupply = totalSupply.sub(value);
|
||||
emit Burn(user, value);
|
||||
emit Transfer(user, address(0), value);
|
||||
}
|
||||
}
|
||||
88
contracts/DODOToken/DODOCirculationHelper.sol
Normal file
88
contracts/DODOToken/DODOCirculationHelper.sol
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 DODO ZOO.
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
*/
|
||||
pragma solidity 0.6.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import {IERC20} from "../intf/IERC20.sol";
|
||||
import {SafeMath} from "../lib/SafeMath.sol";
|
||||
import {DecimalMath} from "../lib/DecimalMath.sol";
|
||||
import {InitializableOwnable} from "../lib/InitializableOwnable.sol";
|
||||
|
||||
|
||||
contract DODOCirculationHelper is InitializableOwnable {
|
||||
using SafeMath for uint256;
|
||||
|
||||
// ============ Storage ============
|
||||
|
||||
address immutable _VDODO_TOKEN_;
|
||||
address immutable _DODO_TOKEN_;
|
||||
address[] _LOCKED_CONTRACT_ADDRESS_;
|
||||
|
||||
uint256 public _MIN_PENALTY_RATIO_ = 5 * 10**16; // 5%
|
||||
uint256 public _MAX_PENALTY_RATIO_ = 15 * 10**16; // 15%
|
||||
|
||||
constructor(address vDodoToken,address dodoToken) public {
|
||||
_VDODO_TOKEN_ = vDodoToken;
|
||||
_DODO_TOKEN_ = dodoToken;
|
||||
}
|
||||
|
||||
function addLockedContractAddress(address lockedContract) external onlyOwner {
|
||||
require(lockedContract != address(0));
|
||||
_LOCKED_CONTRACT_ADDRESS_.push(lockedContract);
|
||||
}
|
||||
|
||||
function removeLockedContractAddress(address lockedContract) external onlyOwner {
|
||||
require(lockedContract != address(0));
|
||||
address[] memory lockedContractAddress = _LOCKED_CONTRACT_ADDRESS_;
|
||||
for (uint256 i = 0; i < lockedContractAddress.length; i++) {
|
||||
if (lockedContractAddress[i] == lockedContract) {
|
||||
lockedContractAddress[i] = lockedContractAddress[lockedContractAddress.length - 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
_LOCKED_CONTRACT_ADDRESS_ = lockedContractAddress;
|
||||
_LOCKED_CONTRACT_ADDRESS_.pop();
|
||||
}
|
||||
|
||||
function getCirculation() public view returns (uint256 circulation) {
|
||||
circulation = 10**10 * 10**18;
|
||||
for (uint256 i = 0; i < _LOCKED_CONTRACT_ADDRESS_.length; i++) {
|
||||
circulation -= IERC20(_DODO_TOKEN_).balanceOf(_LOCKED_CONTRACT_ADDRESS_[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function getVDODOWithdrawFeeRatio() external view returns (uint256 ratio) {
|
||||
uint256 dodoCirculationAmout = getCirculation();
|
||||
uint256 x =
|
||||
DecimalMath.divCeil(
|
||||
dodoCirculationAmout,
|
||||
IERC20(_VDODO_TOKEN_).totalSupply()
|
||||
);
|
||||
|
||||
ratio = geRatioValue(x);
|
||||
}
|
||||
|
||||
function geRatioValue(uint256 input) public view returns (uint256 ratio) {
|
||||
|
||||
// (x - 1)^2 / 81 + (y - 15)^2 / 100 = 1
|
||||
// y = 5% (x ≤ 1)
|
||||
// y = 15% (x ≥ 10)
|
||||
// y = 15% - 10% * sqrt(1-[(x-1)/9]^2)
|
||||
|
||||
if (input <= 10**18) {
|
||||
return _MIN_PENALTY_RATIO_;
|
||||
} else if (input >= 10**19) {
|
||||
return _MAX_PENALTY_RATIO_;
|
||||
} else {
|
||||
uint256 xTemp = input.sub(DecimalMath.ONE).div(9);
|
||||
uint256 premium = DecimalMath.ONE2.sub(xTemp.mul(xTemp)).sqrt();
|
||||
ratio =
|
||||
_MAX_PENALTY_RATIO_ -
|
||||
DecimalMath.mulFloor(_MAX_PENALTY_RATIO_ - _MIN_PENALTY_RATIO_, premium);
|
||||
}
|
||||
}
|
||||
}
|
||||
58
contracts/DODOToken/DODOMigrationBSC.sol
Normal file
58
contracts/DODOToken/DODOMigrationBSC.sol
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 DODO ZOO.
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
*/
|
||||
pragma solidity 0.6.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import {IERC20} from "../intf/IERC20.sol";
|
||||
import {SafeMath} from "../lib/SafeMath.sol";
|
||||
import {InitializableOwnable} from "../lib/InitializableOwnable.sol";
|
||||
import {IDODOApproveProxy} from "../SmartRoute/DODOApproveProxy.sol";
|
||||
|
||||
/**
|
||||
* @title DODOMigration between Ethereum and BSC
|
||||
* @author DODO Breeder
|
||||
*/
|
||||
contract DODOMigrationBSC is InitializableOwnable {
|
||||
using SafeMath for uint256;
|
||||
|
||||
// ============ Storage ============
|
||||
|
||||
address immutable _ETH_DODO_TOKEN_;
|
||||
address immutable _DODO_APPROVE_PROXY_;
|
||||
mapping(address => uint256) internal balances;
|
||||
|
||||
constructor(address ethDodoToken, address dodoApproveProxy) public {
|
||||
_ETH_DODO_TOKEN_ = ethDodoToken;
|
||||
_DODO_APPROVE_PROXY_ = dodoApproveProxy;
|
||||
}
|
||||
|
||||
// ============ Events ============
|
||||
|
||||
event Lock(address indexed sender, address indexed mintToBscAccount, uint256 amount);
|
||||
event Unlock(address indexed to, uint256 amount);
|
||||
|
||||
// ============ Functions ============
|
||||
|
||||
function lock(uint256 amount, address mintToBscAccount) external {
|
||||
IDODOApproveProxy(_DODO_APPROVE_PROXY_).claimTokens(
|
||||
_ETH_DODO_TOKEN_,
|
||||
msg.sender,
|
||||
address(this),
|
||||
amount
|
||||
);
|
||||
balances[msg.sender] = balances[msg.sender].add(amount);
|
||||
emit Lock(msg.sender, mintToBscAccount, amount);
|
||||
}
|
||||
|
||||
function unlock(address unlockTo, uint256 amount) external onlyOwner {
|
||||
require(balances[unlockTo] >= amount);
|
||||
balances[unlockTo] = balances[unlockTo].sub(amount);
|
||||
IERC20(_ETH_DODO_TOKEN_).transfer(unlockTo, amount);
|
||||
emit Unlock(unlockTo, amount);
|
||||
}
|
||||
|
||||
}
|
||||
26
contracts/DODOToken/Governance.sol
Normal file
26
contracts/DODOToken/Governance.sol
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 DODO ZOO.
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
*/
|
||||
pragma solidity 0.6.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import {InitializableOwnable} from "../lib/InitializableOwnable.sol";
|
||||
|
||||
//todo
|
||||
contract Governance is InitializableOwnable {
|
||||
|
||||
// ============ Storage ============
|
||||
|
||||
address _VDODO_TOKEN_;
|
||||
|
||||
function setVDODOAddress(address vodoToken) public onlyOwner{
|
||||
_VDODO_TOKEN_ = vodoToken;
|
||||
}
|
||||
|
||||
function getLockedvDODO(address account) external pure returns (uint256 lockedvDODO) {
|
||||
lockedvDODO = 0;//todo for test
|
||||
}
|
||||
}
|
||||
361
contracts/DODOToken/vDODOToken.sol
Normal file
361
contracts/DODOToken/vDODOToken.sol
Normal file
@@ -0,0 +1,361 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 DODO ZOO.
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
*/
|
||||
pragma solidity 0.6.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import {IERC20} from "../intf/IERC20.sol";
|
||||
import {SafeMath} from "../lib/SafeMath.sol";
|
||||
import {DecimalMath} from "../lib/DecimalMath.sol";
|
||||
import {InitializableOwnable} from "../lib/InitializableOwnable.sol";
|
||||
import {SafeERC20} from "../lib/SafeERC20.sol";
|
||||
import {IDODOApproveProxy} from "../SmartRoute/DODOApproveProxy.sol";
|
||||
|
||||
interface IGovernance {
|
||||
function getLockedvDODO(address account) external view returns (uint256);
|
||||
}
|
||||
|
||||
interface IDODOCirculationHelper {
|
||||
// Locked vDOOD not counted in circulation
|
||||
function getCirculation() external view returns (uint256);
|
||||
|
||||
function getVDODOWithdrawFeeRatio() external view returns (uint256);
|
||||
}
|
||||
|
||||
contract vDODOToken is InitializableOwnable {
|
||||
using SafeMath for uint256;
|
||||
|
||||
// ============ Storage(ERC20) ============
|
||||
|
||||
string public name;
|
||||
string public symbol;
|
||||
uint8 public decimals;
|
||||
uint256 public totalSupply;
|
||||
mapping(address => mapping(address => uint256)) internal _ALLOWED_;
|
||||
|
||||
// ============ Storage ============
|
||||
|
||||
address immutable _DODO_TOKEN_;
|
||||
address immutable _DODO_APPROVE_PROXY_;
|
||||
address public _DOOD_GOV_;
|
||||
address public _DODO_CIRCULATION_HELPER_;
|
||||
|
||||
bool public _CAN_TRANSFER_;
|
||||
|
||||
// staking reward parameters
|
||||
uint256 public dodoPerBlock;
|
||||
uint256 public constant _SUPERIOR_RATIO_ = 10**17; // 0.1
|
||||
uint256 public dodoFeeBurnRation;
|
||||
|
||||
// accounting
|
||||
uint128 public alpha = 100 * 10**18; // 100
|
||||
uint128 public lastRewardBlock;
|
||||
mapping(address => UserInfo) public userInfo;
|
||||
|
||||
struct UserInfo {
|
||||
uint128 VDODOAmount;
|
||||
uint128 superiorVDODO;
|
||||
address superior;
|
||||
uint256 credit;
|
||||
}
|
||||
|
||||
// ============ Events ============
|
||||
|
||||
event MintVDODO(address user, address superior, uint256 amount);
|
||||
event RedeemVDODO(address user, uint256 amount);
|
||||
event SetCantransfer(bool allowed);
|
||||
|
||||
event ChangePerReward(uint256 dodoPerBlock);
|
||||
event UpdatedodoFeeBurnRation(uint256 dodoFeeBurnRation);
|
||||
|
||||
event Transfer(address indexed from, address indexed to, uint256 amount);
|
||||
event Approval(address indexed owner, address indexed spender, uint256 amount);
|
||||
|
||||
// ============ Modifiers ============
|
||||
|
||||
modifier canTransfer() {
|
||||
require(_CAN_TRANSFER_, "vDODOToken: not allowed transfer");
|
||||
_;
|
||||
}
|
||||
|
||||
modifier balanceEnough(address account, uint256 amount) {
|
||||
require(availableBalanceOf(account) >= amount, "vDODOToken: available amount not enough");
|
||||
_;
|
||||
}
|
||||
|
||||
// ============ Constructor ============
|
||||
|
||||
constructor(
|
||||
address dodoGov,
|
||||
address dodoToken,
|
||||
address dodoCirculationHelper,
|
||||
address dodoApproveProxy,
|
||||
string memory _name,
|
||||
string memory _symbol
|
||||
) public {
|
||||
name = _name;
|
||||
symbol = _symbol;
|
||||
decimals = 18;
|
||||
_DODO_APPROVE_PROXY_ = dodoApproveProxy;
|
||||
_DOOD_GOV_ = dodoGov;
|
||||
_DODO_CIRCULATION_HELPER_ = dodoCirculationHelper;
|
||||
_DODO_TOKEN_ = dodoToken;
|
||||
lastRewardBlock = uint128(block.number);
|
||||
}
|
||||
|
||||
// ============ Ownable Functions ============`
|
||||
|
||||
function setCantransfer(bool allowed) public onlyOwner {
|
||||
_CAN_TRANSFER_ = allowed;
|
||||
emit SetCantransfer(allowed);
|
||||
}
|
||||
|
||||
function changePerReward(uint256 _dodoPerBlock) public onlyOwner {
|
||||
_updateAlpha();
|
||||
dodoPerBlock = _dodoPerBlock;
|
||||
emit ChangePerReward(_dodoPerBlock);
|
||||
}
|
||||
|
||||
function updatedodoFeeBurnRation(uint256 _dodoFeeBurnRation) public onlyOwner {
|
||||
dodoFeeBurnRation = _dodoFeeBurnRation;
|
||||
emit UpdatedodoFeeBurnRation(_dodoFeeBurnRation);
|
||||
}
|
||||
|
||||
function updateDODOCirculationHelper(address helper) public onlyOwner {
|
||||
_DODO_CIRCULATION_HELPER_ = helper;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// ============ Functions ============
|
||||
|
||||
function mint(uint256 dodoAmount, address superiorAddress) public {
|
||||
require(superiorAddress != address(0) && superiorAddress != msg.sender, "vDODOToken: Superior INVALID");
|
||||
require(dodoAmount > 0, "vDODOToken: must mint greater than 0");
|
||||
|
||||
_updateAlpha();
|
||||
|
||||
IDODOApproveProxy(_DODO_APPROVE_PROXY_).claimTokens(
|
||||
_DODO_TOKEN_,
|
||||
msg.sender,
|
||||
address(this),
|
||||
dodoAmount
|
||||
);
|
||||
|
||||
uint256 newVdodoAmount = DecimalMath.divFloor(dodoAmount, alpha);
|
||||
|
||||
UserInfo storage user = userInfo[msg.sender];
|
||||
_mint(user, newVdodoAmount);
|
||||
|
||||
uint256 increSuperiorVDODO = DecimalMath.mulFloor(newVdodoAmount, _SUPERIOR_RATIO_);
|
||||
|
||||
if (user.superior == address(0)) {
|
||||
user.superior = superiorAddress;
|
||||
}
|
||||
|
||||
_mintToSuperior(user, increSuperiorVDODO);
|
||||
|
||||
emit MintVDODO(msg.sender, superiorAddress, dodoAmount);
|
||||
}
|
||||
|
||||
function redeem(uint256 vDodoAmount)
|
||||
public
|
||||
balanceEnough(msg.sender, vDodoAmount)
|
||||
{
|
||||
_updateAlpha();
|
||||
|
||||
UserInfo storage user = userInfo[msg.sender];
|
||||
_redeem(user, vDodoAmount);
|
||||
|
||||
if (user.superior != address(0)) {
|
||||
uint256 superiorRedeemVDODO = DecimalMath.mulFloor(vDodoAmount, _SUPERIOR_RATIO_);
|
||||
_redeemFromSuperior(user, superiorRedeemVDODO);
|
||||
}
|
||||
|
||||
(uint256 dodoReceive, uint256 burnDodoAmount, uint256 withdrawFeeDodoAmount) = getWithdrawAmount(vDodoAmount);
|
||||
|
||||
IERC20(_DODO_TOKEN_).transfer(msg.sender, dodoReceive);
|
||||
|
||||
if(burnDodoAmount > 0){
|
||||
_transfer(address(this), address(0), burnDodoAmount);
|
||||
}
|
||||
|
||||
if(withdrawFeeDodoAmount > 0) {
|
||||
alpha = uint128(uint256(alpha).add(DecimalMath.divFloor(withdrawFeeDodoAmount, totalSupply)));
|
||||
}
|
||||
|
||||
emit RedeemVDODO(msg.sender, vDodoAmount);
|
||||
}
|
||||
|
||||
|
||||
function donate(uint256 dodoAmount) public {
|
||||
IDODOApproveProxy(_DODO_APPROVE_PROXY_).claimTokens(
|
||||
_DODO_TOKEN_,
|
||||
msg.sender,
|
||||
address(this),
|
||||
dodoAmount
|
||||
);
|
||||
alpha = uint128(uint256(alpha).add(DecimalMath.divFloor(dodoAmount, totalSupply)));
|
||||
}
|
||||
|
||||
// ============ Functions(ERC20) ============
|
||||
|
||||
function balanceOf(address account) public view returns (uint256 balance) {
|
||||
UserInfo memory user = userInfo[account];
|
||||
balance = uint256(user.VDODOAmount).sub(DecimalMath.divFloor(user.credit, getLatestAlpha()));
|
||||
}
|
||||
|
||||
function availableBalanceOf(address account) public view returns (uint256 balance) {
|
||||
uint256 lockedBalance = IGovernance(_DOOD_GOV_).getLockedvDODO(account);
|
||||
balance = balanceOf(account).sub(lockedBalance);
|
||||
}
|
||||
|
||||
function transfer(address to, uint256 amount) public returns (bool) {
|
||||
_updateAlpha();
|
||||
_transfer(msg.sender, to, amount);
|
||||
return true;
|
||||
}
|
||||
|
||||
function approve(address spender, uint256 amount) public returns (bool) {
|
||||
_ALLOWED_[msg.sender][spender] = amount;
|
||||
emit Approval(msg.sender, spender, amount);
|
||||
return true;
|
||||
}
|
||||
|
||||
function transferFrom(
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
) public returns (bool) {
|
||||
require(amount <= _ALLOWED_[from][msg.sender], "ALLOWANCE_NOT_ENOUGH");
|
||||
_updateAlpha();
|
||||
_transfer(from, to, amount);
|
||||
_ALLOWED_[from][msg.sender] = _ALLOWED_[from][msg.sender].sub(amount);
|
||||
emit Transfer(from, to, amount);
|
||||
return true;
|
||||
}
|
||||
|
||||
function allowance(address owner, address spender) public view returns (uint256) {
|
||||
return _ALLOWED_[owner][spender];
|
||||
}
|
||||
|
||||
// ============ View Functions ============
|
||||
|
||||
function dodoBalanceOf(address account) public view returns (uint256 dodoAmount) {
|
||||
UserInfo memory user = userInfo[account];
|
||||
dodoAmount = DecimalMath.mulFloor(uint256(user.VDODOAmount),getLatestAlpha()).sub(user.credit);
|
||||
}
|
||||
|
||||
function getLatestAlpha() public view returns(uint256) {
|
||||
uint256 accuDODO = dodoPerBlock * (block.number - lastRewardBlock);
|
||||
if (totalSupply > 0) {
|
||||
return uint256(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() internal {
|
||||
uint256 newAlpha = getLatestAlpha();
|
||||
require(newAlpha <= uint128(-1), "OVERFLOW");
|
||||
alpha = uint128(newAlpha);
|
||||
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 _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, alpha);
|
||||
superiorUser.credit = superiorUser.credit.add(dodoAmount);
|
||||
}
|
||||
}
|
||||
|
||||
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, alpha);
|
||||
|
||||
if (vdodoAmount >= creditVDODO) {
|
||||
superiorUser.credit = 0;
|
||||
_redeem(superiorUser, creditVDODO);
|
||||
} else {
|
||||
superiorUser.credit = superiorUser.credit.sub(
|
||||
DecimalMath.mulFloor(vdodoAmount, alpha)
|
||||
);
|
||||
_redeem(superiorUser, vdodoAmount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _transfer(
|
||||
address from,
|
||||
address to,
|
||||
uint256 _amount
|
||||
) internal balanceEnough(from, _amount) canTransfer {
|
||||
require(from != address(0), "transfer from the zero address");
|
||||
require(to != address(0), "transfer to the zero address");
|
||||
|
||||
UserInfo storage fromUser = userInfo[from];
|
||||
fromUser.VDODOAmount = uint128(uint256(fromUser.VDODOAmount).sub(_amount));
|
||||
|
||||
UserInfo storage toUser = userInfo[to];
|
||||
toUser.VDODOAmount = uint128(uint256(toUser.VDODOAmount).add(_amount));
|
||||
|
||||
uint256 superiorRedeemVDODO = DecimalMath.mulFloor(_amount, _SUPERIOR_RATIO_);
|
||||
|
||||
if (fromUser.superior != address(0)) {
|
||||
_redeemFromSuperior(fromUser, superiorRedeemVDODO);
|
||||
}
|
||||
|
||||
if (toUser.superior != address(0)) {
|
||||
_mintToSuperior(toUser, superiorRedeemVDODO);
|
||||
}
|
||||
|
||||
emit Transfer(from, to, _amount);
|
||||
}
|
||||
}
|
||||
@@ -76,7 +76,9 @@ contract DODOCalleeHelper is ReentrancyGuard {
|
||||
to.transfer(amount);
|
||||
}
|
||||
} else {
|
||||
SafeERC20.safeTransfer(IERC20(token), to, amount);
|
||||
if (amount > 0) {
|
||||
SafeERC20.safeTransfer(IERC20(token), to, amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,3 +112,11 @@ Deploy time: 2021/1/26 下午5:41:41
|
||||
Deploy type: Proxy
|
||||
DODOV1Proxy04 Address: 0xa2CB66EBB947D217f61510882096F6e95c1DE97D
|
||||
Set DODOProxy Owner tx: 0xe49234c67bc710a7f4797aacbb2ef26fac458832f101e856d8113cc21721cd81
|
||||
====================================================
|
||||
network type: kovan
|
||||
Deploy time: 2021/2/1 下午11:07:47
|
||||
Deploy type: Proxy
|
||||
====================================================
|
||||
network type: kovan
|
||||
Deploy time: 2021/2/1 下午11:08:57
|
||||
Deploy type: Proxy
|
||||
|
||||
@@ -542,3 +542,33 @@ Deploy time: 2021/1/26 下午5:29:51
|
||||
====================================================
|
||||
network type: live
|
||||
Deploy time: 2021/1/26 下午5:42:23
|
||||
====================================================
|
||||
network type: kovan
|
||||
Deploy time: 2021/2/1 下午11:09:38
|
||||
Deploy type: V2
|
||||
DODOApprove Address: 0x929ce7b28aA759a1C0E6e855ff2545f9e5ca846A
|
||||
DODOApproveProxy Address: 0x8a61c59e2DE32af51A252d754c7f852aA44191C8
|
||||
DODOV2Proxy02 Address: 0xf47BEA4D26026810787b56670502E058CEe5c386
|
||||
Init DODOProxyV2 Tx: 0x48c4de1d6008c96d82a92da63747385b218b56fe3451d4256b9b8429623d34f4
|
||||
DODOApproveProxy Init tx: 0xb12443d847d426fbeed3c0c3d0e796d52b214ebff65ca604a72dd7400b94e42c
|
||||
DODOApprove Init tx: 0x26d3f4be069eccf94b0b6d3ee1db07a534cadc98c4dd2b96fd5921d00f57403c
|
||||
DODOIncentive ChangeProxy tx: 0x9564307e19b26aed9980d9ac007dc88b789450893540426618de4f1039f5584f
|
||||
====================================================
|
||||
network type: kovan
|
||||
Deploy time: 2021/2/2 下午2:28:36
|
||||
====================================================
|
||||
network type: kovan
|
||||
Deploy time: 2021/2/2 下午2:38:26
|
||||
Deploy type: V2
|
||||
DppTemplateAddress: 0x6b9Db3908ddFD853AD2A42Ab75b5de3f22f137a5
|
||||
DppAdminTemplateAddress: 0x2d69731283ac620760309d8b561De11C6166a5F5
|
||||
DODOApprove Address: 0x7BD4dBc1F3cd0333E910aa9eeA14A2d96e3684C2
|
||||
DODOApproveProxy Address: 0x0cB68c60E4C2F023C4fdbC6Cbe283aAb34866e8a
|
||||
DppFactoryAddress: 0x80c03749C22Acbe5EaFEb1d550a32C707a67fc34
|
||||
Init DppFactory Tx: 0x643c1fdcefe736f782f0c1be2478ff09515030eb9e6c6030f0ec9513bd327bf7
|
||||
DODOV2RouteHelper Address: 0xD5171044E369Ef316125da5A0Af8E75ea6Cd3A90
|
||||
DODOV2Proxy02 Address: 0xFC6840905E7E550A209B3856f313C523D2f9a3e3
|
||||
Init DODOProxyV2 Tx: 0xb41219ef20f0496c8c2088bf8d30a64dd3fa1ef5cdaeaa9161a6da52349dd76d
|
||||
DODOApproveProxy Init tx: 0x38ced5f643938891ad553b40bafe55ffc6065a15e4bbc81f4cdfbe4f3a0b9494
|
||||
DODOApprove Init tx: 0x7eac3f1fa6dbe499351ea52066623980615bdc7901a84f2afa8fc67e34e4be59
|
||||
DODOIncentive ChangeProxy tx: 0x6d64bae7ee09f12db0bfc18823ac8e2ca1d682184c1ed3cc157f2b39641409e3
|
||||
|
||||
@@ -85,7 +85,7 @@ module.exports = async (deployer, network, accounts) => {
|
||||
DefaultPermissionAddress = "0xACc7E23368261e1E02103c4e5ae672E7D01f5797";
|
||||
|
||||
DvmTemplateAddress = "0xA6384D1501842e9907D43148E2ca0d50E4ad56E2";
|
||||
DppTemplateAddress = "0x044b48D64E77Ab8854C46c8456dC05C540c9dd53";
|
||||
DppTemplateAddress = "";
|
||||
DppAdminTemplateAddress = "";
|
||||
CpTemplateAddress = "0x81c802080c3CE0dE98fcb625670A14Eb8440184a";
|
||||
//Factory
|
||||
@@ -379,8 +379,8 @@ module.exports = async (deployer, network, accounts) => {
|
||||
logger.log("DODOIncentive ChangeProxy tx: ", tx.tx);
|
||||
|
||||
//3. Open trade incentive
|
||||
var tx = await DODOIncentiveInstance.changePerReward("10000000000000000000");
|
||||
logger.log("DODOIncentive OpenSwitch tx: ", tx.tx);
|
||||
// var tx = await DODOIncentiveInstance.changePerReward("10000000000000000000");
|
||||
// logger.log("DODOIncentive OpenSwitch tx: ", tx.tx);
|
||||
|
||||
//4. Transfer DODO to Trade Incentive
|
||||
}
|
||||
|
||||
@@ -47,6 +47,9 @@ export const DODO_CALLEE_HELPER_NAME = "DODOCalleeHelper"
|
||||
export const CROWD_POOLING_NAME = "CP"
|
||||
export const CROWD_POOLING_FACTORY = "CrowdPoolingFactory"
|
||||
export const DODO_INCENTIVE = "DODOIncentive"
|
||||
export const VDODO_NAME = "vDODOToken"
|
||||
export const DODO_CULATION_HELPER = "DODOCirculationHelper"
|
||||
export const DODO_GOVERNANCE = "Governance"
|
||||
|
||||
interface ContractJson {
|
||||
abi: any;
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import BigNumber from "bignumber.js";
|
||||
import { getDefaultWeb3 } from './EVM';
|
||||
|
||||
|
||||
export const MAX_UINT256 = "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
|
||||
|
||||
@@ -12,4 +14,9 @@ export function gweiStr(gwei: string): string {
|
||||
|
||||
export function mweiStr(gwei: string): string {
|
||||
return new BigNumber(gwei).multipliedBy(10 ** 6).toFixed(0, BigNumber.ROUND_DOWN)
|
||||
}
|
||||
|
||||
export function fromWei(value: string, unit: any): string {
|
||||
var web3 = getDefaultWeb3();
|
||||
return web3.utils.fromWei(value, unit);
|
||||
}
|
||||
148
test/utils/VDODOContext.ts
Normal file
148
test/utils/VDODOContext.ts
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
|
||||
Copyright 2021 DODO ZOO.
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
*/
|
||||
|
||||
import BigNumber from 'bignumber.js';
|
||||
import Web3 from 'web3';
|
||||
import { Contract } from 'web3-eth-contract';
|
||||
|
||||
import * as contracts from './Contracts';
|
||||
import { decimalStr, MAX_UINT256 } from './Converter';
|
||||
import { EVM, getDefaultWeb3 } from './EVM';
|
||||
import * as log from './Log';
|
||||
|
||||
BigNumber.config({
|
||||
EXPONENTIAL_AT: 1000,
|
||||
DECIMAL_PLACES: 80,
|
||||
});
|
||||
|
||||
export class VDODOContext {
|
||||
EVM: EVM;
|
||||
Web3: Web3;
|
||||
Deployer: string;
|
||||
Maintainer: string;
|
||||
SpareAccounts: string[];
|
||||
|
||||
//token
|
||||
DODO: Contract;
|
||||
VDODO: Contract;
|
||||
|
||||
DODOApprove: Contract;
|
||||
DODOApproveProxy: Contract;
|
||||
|
||||
DODOCirculationHelper: Contract;
|
||||
Governance: Contract;
|
||||
|
||||
lastRewardBlock: number;
|
||||
alpha: number;
|
||||
|
||||
|
||||
|
||||
constructor() { }
|
||||
|
||||
async init() {
|
||||
this.EVM = new EVM();
|
||||
this.Web3 = getDefaultWeb3();
|
||||
|
||||
const allAccounts = await this.Web3.eth.getAccounts();
|
||||
this.Deployer = allAccounts[0];
|
||||
this.Maintainer = allAccounts[1];
|
||||
this.SpareAccounts = allAccounts.slice(2, 10);
|
||||
|
||||
this.DODO = await contracts.newContract(
|
||||
contracts.MINTABLE_ERC20_CONTRACT_NAME,
|
||||
["DODO Token", "DODO", 18]
|
||||
);
|
||||
|
||||
this.DODOApprove = await contracts.newContract(
|
||||
contracts.SMART_APPROVE
|
||||
);
|
||||
|
||||
this.DODOApproveProxy = await contracts.newContract(
|
||||
contracts.SMART_APPROVE_PROXY,
|
||||
[this.DODOApprove.options.address]
|
||||
)
|
||||
|
||||
this.Governance = await contracts.newContract(
|
||||
contracts.DODO_GOVERNANCE,
|
||||
[
|
||||
this.DODO.options.address
|
||||
]
|
||||
)
|
||||
|
||||
this.VDODO = await contracts.newContract(
|
||||
contracts.VDODO_NAME,
|
||||
[
|
||||
this.Governance.options.address,
|
||||
this.DODO.options.address,
|
||||
"0x0000000000000000000000000000000000000000",
|
||||
this.DODOApproveProxy.options.address,
|
||||
"VDODO Token", "VDODO"
|
||||
]
|
||||
)
|
||||
|
||||
this.DODOCirculationHelper = await contracts.newContract(
|
||||
contracts.DODO_CULATION_HELPER,
|
||||
[
|
||||
this.VDODO.options.address,
|
||||
this.DODO.options.address
|
||||
]
|
||||
);
|
||||
|
||||
await this.Governance.methods.initOwner(
|
||||
this.Deployer
|
||||
).send(this.sendParam(this.Deployer))
|
||||
|
||||
await this.Governance.methods.setVDODOAddress(
|
||||
this.VDODO.options.address
|
||||
).send(this.sendParam(this.Deployer))
|
||||
|
||||
await this.DODOApprove.methods.init(this.Deployer, this.DODOApproveProxy.options.address).send(this.sendParam(this.Deployer));
|
||||
await this.DODOApproveProxy.methods.init(this.Deployer, [this.VDODO.options.address]).send(this.sendParam(this.Deployer));
|
||||
|
||||
|
||||
await this.VDODO.methods.initOwner(
|
||||
this.Deployer
|
||||
).send(this.sendParam(this.Deployer))
|
||||
|
||||
await this.VDODO.methods.changePerReward(decimalStr("1")).send(this.sendParam(this.Deployer));
|
||||
await this.VDODO.methods.updateDODOCirculationHelper(this.DODOCirculationHelper.options.address).send(this.sendParam(this.Deployer));
|
||||
await this.mintTestToken(this.VDODO.options.address, decimalStr("100000"));
|
||||
|
||||
this.alpha = await this.VDODO.methods.alpha().call();
|
||||
this.lastRewardBlock = await this.VDODO.methods.lastRewardBlock().call();
|
||||
|
||||
console.log(log.blueText("[Init VDODO context]"));
|
||||
|
||||
console.log("init alpha = " + this.alpha);
|
||||
console.log("init lastRewardBlock = " + this.lastRewardBlock);
|
||||
}
|
||||
|
||||
sendParam(sender, value = "0") {
|
||||
return {
|
||||
from: sender,
|
||||
gas: process.env["COVERAGE"] ? 10000000000 : 7000000,
|
||||
gasPrice: process.env.GAS_PRICE,
|
||||
value: decimalStr(value),
|
||||
};
|
||||
}
|
||||
|
||||
async mintTestToken(to: string, amount: string) {
|
||||
await this.DODO.methods.mint(to, amount).send(this.sendParam(this.Deployer));
|
||||
}
|
||||
|
||||
async approveProxy(account: string) {
|
||||
await this.DODO.methods
|
||||
.approve(this.DODOApprove.options.address, MAX_UINT256)
|
||||
.send(this.sendParam(account));
|
||||
}
|
||||
}
|
||||
|
||||
export async function getVDODOContext(): Promise<VDODOContext> {
|
||||
var context = new VDODOContext();
|
||||
await context.init();
|
||||
return context;
|
||||
}
|
||||
346
test/vDODO/erc20.test.ts
Normal file
346
test/vDODO/erc20.test.ts
Normal file
@@ -0,0 +1,346 @@
|
||||
/*
|
||||
|
||||
Copyright 2021 DODO ZOO.
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
*/
|
||||
|
||||
import { decimalStr, fromWei } from '../utils/Converter';
|
||||
import { logGas } from '../utils/Log';
|
||||
import { VDODOContext, getVDODOContext } from '../utils/VDODOContext';
|
||||
import { assert } from 'chai';
|
||||
import BigNumber from 'bignumber.js';
|
||||
const truffleAssert = require('truffle-assertions');
|
||||
|
||||
let account0: string;
|
||||
let account1: string;
|
||||
let account2: string;
|
||||
let account3: string;
|
||||
let defaultSuperAddress: string;
|
||||
let owner: string;
|
||||
|
||||
async function init(ctx: VDODOContext): Promise<void> {
|
||||
account0 = ctx.SpareAccounts[0];
|
||||
account1 = ctx.SpareAccounts[1];
|
||||
account2 = ctx.SpareAccounts[2];
|
||||
account3 = ctx.SpareAccounts[3];
|
||||
defaultSuperAddress = ctx.Maintainer
|
||||
owner = ctx.Deployer
|
||||
|
||||
await ctx.mintTestToken(account0, decimalStr("1000"));
|
||||
await ctx.mintTestToken(account2, decimalStr("1000"));
|
||||
|
||||
await ctx.approveProxy(account0);
|
||||
await ctx.approveProxy(account1);
|
||||
await ctx.approveProxy(account2);
|
||||
await ctx.approveProxy(account3);
|
||||
|
||||
await ctx.VDODO.methods.setCantransfer(true).send(ctx.sendParam(owner))
|
||||
}
|
||||
|
||||
async function getGlobalState(ctx: VDODOContext, logInfo?: string) {
|
||||
var alpha = await ctx.VDODO.methods.getLatestAlpha().call();
|
||||
var lastRewardBlock = await ctx.VDODO.methods.lastRewardBlock().call();
|
||||
var totalSuppy = await ctx.VDODO.methods.totalSupply().call();
|
||||
// console.log(logInfo + " alpha:" + fromWei(alpha, 'ether') + " lastRewardBlock:" + lastRewardBlock + " totalSuppy:" + fromWei(totalSuppy, 'ether'));
|
||||
return [alpha, lastRewardBlock,totalSuppy]
|
||||
}
|
||||
|
||||
async function dodoBalance(ctx: VDODOContext, user: string, logInfo?: string) {
|
||||
var dodo_contract = await ctx.DODO.methods.balanceOf(ctx.VDODO.options.address).call();
|
||||
var dodo_account = await ctx.DODO.methods.balanceOf(user).call();
|
||||
|
||||
// console.log(logInfo + " DODO:" + fromWei(dodo_contract, 'ether') + " account:" + fromWei(dodo_account, 'ether'));
|
||||
return [dodo_contract, dodo_account]
|
||||
}
|
||||
|
||||
async function getUserInfo(ctx: VDODOContext, user: string, logInfo?: string) {
|
||||
var info = await ctx.VDODO.methods.userInfo(user).call();
|
||||
var res = {
|
||||
"VDODOAmount": info.VDODOAmount,
|
||||
"superiorVDODO": info.superiorVDODO,
|
||||
"superior": info.superior,
|
||||
"credit": info.credit
|
||||
}
|
||||
// console.log(logInfo + " VDODOAmount:" + fromWei(info.VDODOAmount, 'ether') + " superiorVDODO:" + fromWei(info.superiorVDODO, 'ether') + " superior:" + info.superior + " credit:" + fromWei(info.credit, 'ether'));
|
||||
return res
|
||||
}
|
||||
|
||||
async function mint(ctx: VDODOContext, user: string, mintAmount: string, superior: string) {
|
||||
await ctx.VDODO.methods.mint(
|
||||
mintAmount,
|
||||
superior
|
||||
).send(ctx.sendParam(user));
|
||||
}
|
||||
|
||||
describe("vDODO-erc20", () => {
|
||||
let snapshotId: string;
|
||||
let ctx: VDODOContext;
|
||||
|
||||
before(async () => {
|
||||
ctx = await getVDODOContext();
|
||||
//打开transfer开关
|
||||
await init(ctx);
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
snapshotId = await ctx.EVM.snapshot();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await ctx.EVM.reset(snapshotId);
|
||||
});
|
||||
|
||||
describe("vdodo-erc20", () => {
|
||||
|
||||
it("transfer-vdodo", async () => {
|
||||
//检查四个人 【包括from, to 以及各自的上级】,info变化
|
||||
//alpha lastRewardBlock
|
||||
//各自dodo余额变化
|
||||
|
||||
let [,lastRewardBlockStart,] = await getGlobalState(ctx, "before");
|
||||
await ctx.VDODO.methods.mint(decimalStr("10"),account1).send(ctx.sendParam(account0))
|
||||
await ctx.VDODO.methods.mint(decimalStr("10"),account3).send(ctx.sendParam(account2))
|
||||
|
||||
//增加一个区块
|
||||
await ctx.mintTestToken(account0, decimalStr("0"));
|
||||
let [alpha,lastRewardBlock,] = await getGlobalState(ctx, "after");
|
||||
|
||||
assert.equal(lastRewardBlock,Number(lastRewardBlockStart)+11);
|
||||
|
||||
assert.equal(alpha, "113833992094861660108");
|
||||
var totalSuppy = await ctx.VDODO.methods.totalSupply().call();
|
||||
assert.equal(
|
||||
totalSuppy
|
||||
, decimalStr("0.210833333333333332"));
|
||||
|
||||
|
||||
|
||||
let userInfo0 = await getUserInfo(ctx, account0, "User0 ");
|
||||
assert.equal(userInfo0.VDODOAmount, decimalStr("0.1"));
|
||||
assert.equal(userInfo0.superiorVDODO, decimalStr("0.01"));
|
||||
assert.equal(userInfo0.credit, "0");
|
||||
let userInfo1 = await getUserInfo(ctx, account1, "User0 Superior ")
|
||||
assert.equal(userInfo1.VDODOAmount, decimalStr("0.01"));
|
||||
assert.equal(userInfo1.superiorVDODO, decimalStr("0"));
|
||||
assert.equal(userInfo1.credit, decimalStr("1"));
|
||||
|
||||
let userInfo2 = await getUserInfo(ctx, account2, "User2 ");
|
||||
assert.equal(userInfo2.VDODOAmount, decimalStr("0.091666666666666666"));
|
||||
assert.equal(userInfo2.superiorVDODO, decimalStr("0.009166666666666666"));
|
||||
assert.equal(userInfo2.credit, decimalStr("0"));
|
||||
let userInfo3 = await getUserInfo(ctx, account3, "User2 Superior");
|
||||
assert.equal(userInfo3.VDODOAmount, decimalStr("0.009166666666666666"));
|
||||
assert.equal(userInfo3.superiorVDODO, decimalStr("0"));
|
||||
assert.equal(userInfo3.credit, decimalStr("0.999999999999999928"));
|
||||
|
||||
|
||||
let [, dodo_u0] = await dodoBalance(ctx, account0, "start")
|
||||
assert.equal(dodo_u0, "990000000000000000000");
|
||||
let [, dodo_u1] = await dodoBalance(ctx, account1, "start")
|
||||
assert.equal(dodo_u1, "0");
|
||||
let [, dodo_u2] = await dodoBalance(ctx, account2, "start")
|
||||
assert.equal(dodo_u2, "990000000000000000000");
|
||||
let [, dodo_u3] = await dodoBalance(ctx, account3, "start")
|
||||
assert.equal(dodo_u3, "0");
|
||||
|
||||
await logGas(await ctx.VDODO.methods.transfer(
|
||||
account2,
|
||||
decimalStr("0.1")
|
||||
), ctx.sendParam(account0), "transfer");
|
||||
|
||||
|
||||
// await ctx.VDODO.methods.transfer(account2,decimalStr("0.1")).send(ctx.sendParam(account0))
|
||||
|
||||
let userInfo0_after = await getUserInfo(ctx, account0, "userInfo0_after");
|
||||
let userInfo1_after = await getUserInfo(ctx, account1, "userInfo1_after");
|
||||
let userInfo2_after = await getUserInfo(ctx, account2, "userInfo2_after");
|
||||
let userInfo3_after = await getUserInfo(ctx, account3, "userInfo3_after");
|
||||
|
||||
|
||||
assert.equal(userInfo0_after.VDODOAmount, "0");
|
||||
assert.equal(userInfo0_after.superiorVDODO, "0");
|
||||
assert.equal(userInfo0_after.credit, "0");
|
||||
|
||||
assert.equal(userInfo1_after.VDODOAmount, decimalStr("0.001566666666666667"));
|
||||
assert.equal(userInfo1_after.superiorVDODO, decimalStr("0"));
|
||||
assert.equal(userInfo1_after.credit, "0");
|
||||
|
||||
assert.equal(userInfo2_after.VDODOAmount, decimalStr("0.191666666666666666"));
|
||||
assert.equal(userInfo2_after.superiorVDODO, decimalStr("0.019166666666666666"));
|
||||
assert.equal(userInfo2_after.credit, "0");
|
||||
|
||||
assert.equal(userInfo3_after.VDODOAmount, decimalStr("0.019166666666666666"));
|
||||
assert.equal(userInfo3_after.superiorVDODO, decimalStr("0"));
|
||||
assert.equal(userInfo3_after.credit, decimalStr("2.185770750988142222"));
|
||||
|
||||
|
||||
|
||||
let [alphaEnd,lastRewardBlockEnd,totalSuppyEnd] = await getGlobalState(ctx, "end");
|
||||
assert.equal(alphaEnd, decimalStr("118.577075098814229308"));
|
||||
assert.equal(totalSuppyEnd, decimalStr("0.212399999999999999"));
|
||||
assert.equal(lastRewardBlockEnd,Number(lastRewardBlock)+2);
|
||||
|
||||
|
||||
let [, dodo_u0_end] = await dodoBalance(ctx, account0, "end")
|
||||
assert.equal(dodo_u0_end, "990000000000000000000");
|
||||
let [, dodo_u1_end] = await dodoBalance(ctx, account1, "end")
|
||||
assert.equal(dodo_u1_end, "0");
|
||||
let [, dodo_u2_end] = await dodoBalance(ctx, account2, "end")
|
||||
assert.equal(dodo_u2_end, "990000000000000000000");
|
||||
let [, dodo_u3_end] = await dodoBalance(ctx, account3, "end")
|
||||
assert.equal(dodo_u3_end, "0");
|
||||
|
||||
});
|
||||
|
||||
it("transferFrom-vdodo", async () => {
|
||||
//检查四个人 【包括from, to 以及各自的上级】,info变化
|
||||
//alpha lastRewardBlock
|
||||
//各自dodo余额变化
|
||||
//approve 状态变化
|
||||
|
||||
let [,lastRewardBlockStart,] = await getGlobalState(ctx, "before");
|
||||
await ctx.VDODO.methods.mint(decimalStr("10"),account1).send(ctx.sendParam(account0))
|
||||
await ctx.VDODO.methods.mint(decimalStr("10"),account3).send(ctx.sendParam(account2))
|
||||
|
||||
//增加一个区块
|
||||
await ctx.mintTestToken(account0, decimalStr("0"));
|
||||
let [alpha,lastRewardBlock,] = await getGlobalState(ctx, "after");
|
||||
|
||||
assert.equal(lastRewardBlock,Number(lastRewardBlockStart)+11);
|
||||
|
||||
assert.equal(alpha, "113833992094861660108");
|
||||
var totalSuppy = await ctx.VDODO.methods.totalSupply().call();
|
||||
assert.equal(
|
||||
totalSuppy
|
||||
, decimalStr("0.210833333333333332"));
|
||||
|
||||
|
||||
|
||||
let userInfo0 = await getUserInfo(ctx, account0, "User0 ");
|
||||
assert.equal(userInfo0.VDODOAmount, decimalStr("0.1"));
|
||||
assert.equal(userInfo0.superiorVDODO, decimalStr("0.01"));
|
||||
assert.equal(userInfo0.credit, "0");
|
||||
let userInfo1 = await getUserInfo(ctx, account1, "User0 Superior ")
|
||||
assert.equal(userInfo1.VDODOAmount, decimalStr("0.01"));
|
||||
assert.equal(userInfo1.superiorVDODO, decimalStr("0"));
|
||||
assert.equal(userInfo1.credit, decimalStr("1"));
|
||||
|
||||
let userInfo2 = await getUserInfo(ctx, account2, "User2 ");
|
||||
assert.equal(userInfo2.VDODOAmount, decimalStr("0.091666666666666666"));
|
||||
assert.equal(userInfo2.superiorVDODO, decimalStr("0.009166666666666666"));
|
||||
assert.equal(userInfo2.credit, decimalStr("0"));
|
||||
let userInfo3 = await getUserInfo(ctx, account3, "User2 Superior");
|
||||
assert.equal(userInfo3.VDODOAmount, decimalStr("0.009166666666666666"));
|
||||
assert.equal(userInfo3.superiorVDODO, decimalStr("0"));
|
||||
assert.equal(userInfo3.credit, decimalStr("0.999999999999999928"));
|
||||
|
||||
|
||||
let [, dodo_u0] = await dodoBalance(ctx, account0, "start")
|
||||
assert.equal(dodo_u0, "990000000000000000000");
|
||||
let [, dodo_u1] = await dodoBalance(ctx, account1, "start")
|
||||
assert.equal(dodo_u1, "0");
|
||||
let [, dodo_u2] = await dodoBalance(ctx, account2, "start")
|
||||
assert.equal(dodo_u2, "990000000000000000000");
|
||||
let [, dodo_u3] = await dodoBalance(ctx, account3, "start")
|
||||
assert.equal(dodo_u3, "0");
|
||||
|
||||
|
||||
await logGas(await ctx.VDODO.methods.approve(
|
||||
account3,
|
||||
decimalStr("0.1")
|
||||
), ctx.sendParam(account0), "approve");
|
||||
|
||||
await logGas(await ctx.VDODO.methods.transferFrom(
|
||||
account0,
|
||||
account2,
|
||||
decimalStr("0.1")
|
||||
), ctx.sendParam(account3), "transferFrom");
|
||||
|
||||
let userInfo0_after = await getUserInfo(ctx, account0, "userInfo0_after");
|
||||
let userInfo1_after = await getUserInfo(ctx, account1, "userInfo1_after");
|
||||
let userInfo2_after = await getUserInfo(ctx, account2, "userInfo2_after");
|
||||
let userInfo3_after = await getUserInfo(ctx, account3, "userInfo3_after");
|
||||
|
||||
|
||||
assert.equal(userInfo0_after.VDODOAmount, "0");
|
||||
assert.equal(userInfo0_after.superiorVDODO, "0");
|
||||
assert.equal(userInfo0_after.credit, "0");
|
||||
|
||||
assert.equal(userInfo1_after.VDODOAmount, decimalStr("0.001891025641025642"));
|
||||
assert.equal(userInfo1_after.superiorVDODO, decimalStr("0"));
|
||||
assert.equal(userInfo1_after.credit, "0");
|
||||
|
||||
assert.equal(userInfo2_after.VDODOAmount, decimalStr("0.191666666666666666"));
|
||||
assert.equal(userInfo2_after.superiorVDODO, decimalStr("0.019166666666666666"));
|
||||
assert.equal(userInfo2_after.credit, "0");
|
||||
|
||||
assert.equal(userInfo3_after.VDODOAmount, decimalStr("0.019166666666666666"));
|
||||
assert.equal(userInfo3_after.superiorVDODO, decimalStr("0"));
|
||||
assert.equal(userInfo3_after.credit, decimalStr("2.233201581027667914"));
|
||||
|
||||
|
||||
|
||||
let [alphaEnd,lastRewardBlockEnd,totalSuppyEnd] = await getGlobalState(ctx, "end");
|
||||
assert.equal(alphaEnd, decimalStr("123.320158102766798508"));
|
||||
assert.equal(totalSuppyEnd, decimalStr("0.212724358974358974"));
|
||||
assert.equal(lastRewardBlockEnd,Number(lastRewardBlock)+3);
|
||||
|
||||
|
||||
let [, dodo_u0_end] = await dodoBalance(ctx, account0, "end")
|
||||
assert.equal(dodo_u0_end, "990000000000000000000");
|
||||
let [, dodo_u1_end] = await dodoBalance(ctx, account1, "end")
|
||||
assert.equal(dodo_u1_end, "0");
|
||||
let [, dodo_u2_end] = await dodoBalance(ctx, account2, "end")
|
||||
assert.equal(dodo_u2_end, "990000000000000000000");
|
||||
let [, dodo_u3_end] = await dodoBalance(ctx, account3, "end")
|
||||
assert.equal(dodo_u3_end, "0");
|
||||
|
||||
|
||||
//再次transferFrom 预期revert
|
||||
//预期revert
|
||||
await truffleAssert.reverts(
|
||||
ctx.VDODO.methods.transferFrom(account0,account2,decimalStr("0.1")).send(ctx.sendParam(account3)),
|
||||
"ALLOWANCE_NOT_ENOUGH"
|
||||
)
|
||||
});
|
||||
|
||||
it("transfer - close", async () => {
|
||||
|
||||
await ctx.VDODO.methods.setCantransfer(false).send(ctx.sendParam(owner))
|
||||
|
||||
await ctx.VDODO.methods.mint(decimalStr("10"),defaultSuperAddress).send(ctx.sendParam(account0))
|
||||
assert.equal(
|
||||
await ctx.DODO.methods.balanceOf(account0).call(),
|
||||
decimalStr("990")
|
||||
);
|
||||
assert.equal(
|
||||
await ctx.DODO.methods.balanceOf(ctx.VDODO.options.address).call(),
|
||||
decimalStr("100010")
|
||||
);
|
||||
assert.equal(
|
||||
await ctx.VDODO.methods.balanceOf(account0).call(),
|
||||
decimalStr("0.1")
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
await ctx.VDODO.methods.balanceOf(account1).call(),
|
||||
decimalStr("0")
|
||||
);
|
||||
//预期revert
|
||||
await truffleAssert.reverts(
|
||||
ctx.VDODO.methods.transfer(account1,decimalStr("0.1")).send(ctx.sendParam(account0)),
|
||||
"vDODOToken: not allowed transfer"
|
||||
)
|
||||
assert.equal(
|
||||
await ctx.VDODO.methods.balanceOf(account0).call(),
|
||||
decimalStr("0.1")
|
||||
);
|
||||
assert.equal(
|
||||
await ctx.VDODO.methods.balanceOf(account1).call(),
|
||||
decimalStr("0")
|
||||
);
|
||||
|
||||
});
|
||||
})
|
||||
});
|
||||
132
test/vDODO/global.test.ts
Normal file
132
test/vDODO/global.test.ts
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
|
||||
Copyright 2021 DODO ZOO.
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
*/
|
||||
|
||||
import { decimalStr, fromWei } from '../utils/Converter';
|
||||
import { logGas } from '../utils/Log';
|
||||
import { VDODOContext, getVDODOContext } from '../utils/VDODOContext';
|
||||
import { assert } from 'chai';
|
||||
import BigNumber from 'bignumber.js';
|
||||
|
||||
let account0: string;
|
||||
let account1: string;
|
||||
|
||||
async function init(ctx: VDODOContext): Promise<void> {
|
||||
account0 = ctx.SpareAccounts[0];
|
||||
account1 = ctx.SpareAccounts[1];
|
||||
|
||||
await ctx.mintTestToken(account0, decimalStr("1000"));
|
||||
await ctx.mintTestToken(account1, decimalStr("1000"));
|
||||
|
||||
await ctx.approveProxy(account0);
|
||||
await ctx.approveProxy(account1);
|
||||
}
|
||||
|
||||
async function getGlobalState(ctx: VDODOContext, logInfo?: string) {
|
||||
var alpha = await ctx.VDODO.methods.getLatestAlpha().call();
|
||||
var lastRewardBlock = await ctx.VDODO.methods.lastRewardBlock().call();
|
||||
var totalSuppy = await ctx.VDODO.methods.totalSupply().call();
|
||||
var dodoPerBlock = await ctx.VDODO.methods.dodoPerBlock().call();
|
||||
// console.log(logInfo + "==> alpha:" + fromWei(alpha, 'ether') + " lastRewardBlock:" + lastRewardBlock + " totalSuppy:" + fromWei(totalSuppy, 'ether')+ " dodoPerBlock:" + fromWei(dodoPerBlock, 'ether'));
|
||||
return [alpha, lastRewardBlock,dodoPerBlock]
|
||||
}
|
||||
describe("vDODO-owner", () => {
|
||||
let snapshotId: string;
|
||||
let ctx: VDODOContext;
|
||||
|
||||
before(async () => {
|
||||
ctx = await getVDODOContext();
|
||||
await init(ctx);
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
snapshotId = await ctx.EVM.snapshot();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await ctx.EVM.reset(snapshotId);
|
||||
});
|
||||
|
||||
describe("vdodo-erc20", () => {
|
||||
|
||||
it("change-reward", async () => {
|
||||
//改变前alpha lastRewardBlock 状态
|
||||
let [alpha,lastRewardBlock,dodoPerBlock] = await getGlobalState(ctx, "before");
|
||||
|
||||
//change-reward
|
||||
await ctx.VDODO.methods.changePerReward(decimalStr("2")).send(ctx.sendParam(ctx.Deployer))
|
||||
//改变后状态
|
||||
let [alphaAfter,lastRewardBlockAfter,dodoPerBlockAfter] = await getGlobalState(ctx, "after");
|
||||
|
||||
assert.equal(
|
||||
await lastRewardBlock,
|
||||
Number(lastRewardBlockAfter)-7
|
||||
);
|
||||
assert.equal(//totalSupply==0
|
||||
await alpha,
|
||||
alphaAfter
|
||||
);
|
||||
assert.notEqual(
|
||||
await dodoPerBlock,
|
||||
dodoPerBlockAfter
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
it("donate", async () => {
|
||||
//改变前alpha lastRewardBlock 状态
|
||||
let [before,lastRewardBlock,] = await getGlobalState(ctx, "before");
|
||||
|
||||
await logGas(await ctx.VDODO.methods.mint(
|
||||
decimalStr("100"),
|
||||
account1
|
||||
), ctx.sendParam(account0), "mint-fisrt");
|
||||
|
||||
await logGas(await ctx.VDODO.methods.donate(
|
||||
decimalStr("100")
|
||||
), ctx.sendParam(account0), "donate");
|
||||
|
||||
|
||||
let [alphaAfter,lastRewardBlockAfter,] = await getGlobalState(ctx, "after");
|
||||
assert.notEqual(
|
||||
before,
|
||||
alphaAfter
|
||||
);
|
||||
assert.equal(
|
||||
alphaAfter,
|
||||
"191818181818181818180"//newAlpha +amount/totalSupply
|
||||
);
|
||||
assert.equal(
|
||||
lastRewardBlock,
|
||||
Number(lastRewardBlockAfter)-7
|
||||
);
|
||||
});
|
||||
it("read-helper", async () => {
|
||||
//不同amount对应的feeRatio (5 5-15 15)
|
||||
let ratio0 = await ctx.DODOCirculationHelper.methods.geRatioValue(decimalStr("0.2")).call()//<=1 ->5
|
||||
assert.equal(
|
||||
ratio0,
|
||||
decimalStr("0.05")
|
||||
);
|
||||
|
||||
let ratio1 = await ctx.DODOCirculationHelper.methods.geRatioValue(decimalStr("11")).call()//>=10 ->15
|
||||
assert.equal(
|
||||
ratio1,
|
||||
decimalStr("0.15")
|
||||
);
|
||||
|
||||
let ratio2 = await ctx.DODOCirculationHelper.methods.geRatioValue(decimalStr("6")).call()//-->5-15
|
||||
assert.equal(
|
||||
ratio2,
|
||||
decimalStr("0.066852058071690192")
|
||||
);
|
||||
// console.log("ratio2 = "+ fromWei(ratio2, 'ether'));
|
||||
assert.isAbove(Number(ratio2),Number(ratio0))
|
||||
assert.isBelow(Number(ratio2),Number(ratio1))
|
||||
|
||||
});
|
||||
})
|
||||
});
|
||||
354
test/vDODO/mintRedeem.test.ts
Normal file
354
test/vDODO/mintRedeem.test.ts
Normal file
@@ -0,0 +1,354 @@
|
||||
/*
|
||||
|
||||
Copyright 2021 DODO ZOO.
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
*/
|
||||
|
||||
import { decimalStr, fromWei } from '../utils/Converter';
|
||||
import { logGas } from '../utils/Log';
|
||||
import { VDODOContext, getVDODOContext } from '../utils/VDODOContext';
|
||||
import { assert } from 'chai';
|
||||
|
||||
let account0: string;
|
||||
let account1: string;
|
||||
let account2: string;
|
||||
let account3: string;
|
||||
let account4: string;
|
||||
|
||||
async function init(ctx: VDODOContext): Promise<void> {
|
||||
account0 = ctx.SpareAccounts[0];
|
||||
account1 = ctx.SpareAccounts[1];
|
||||
account2 = ctx.SpareAccounts[2];
|
||||
account3 = ctx.SpareAccounts[3];
|
||||
account4 = ctx.SpareAccounts[4];
|
||||
|
||||
await ctx.mintTestToken(account0, decimalStr("100000"));
|
||||
await ctx.mintTestToken(account1, decimalStr("1000"));
|
||||
await ctx.mintTestToken(account2, decimalStr("1000"));
|
||||
await ctx.mintTestToken(account3, decimalStr("1000"));
|
||||
await ctx.mintTestToken(account4, decimalStr("1000"));
|
||||
|
||||
await ctx.approveProxy(account0);
|
||||
await ctx.approveProxy(account1);
|
||||
await ctx.approveProxy(account2);
|
||||
await ctx.approveProxy(account3);
|
||||
await ctx.approveProxy(account4);
|
||||
}
|
||||
|
||||
async function getGlobalState(ctx: VDODOContext, logInfo?: string) {
|
||||
var alpha = await ctx.VDODO.methods.getLatestAlpha().call();
|
||||
var lastRewardBlock = await ctx.VDODO.methods.lastRewardBlock().call();
|
||||
var totalSuppy = await ctx.VDODO.methods.totalSupply().call();
|
||||
console.log(logInfo + " alpha:" + fromWei(alpha, 'ether') + " lastRewardBlock:" + lastRewardBlock + " totalSuppy:" + fromWei(totalSuppy, 'ether'));
|
||||
return [alpha, lastRewardBlock]
|
||||
}
|
||||
|
||||
async function dodoBalance(ctx: VDODOContext, user: string, logInfo?: string) {
|
||||
var dodo_contract = await ctx.DODO.methods.balanceOf(ctx.VDODO.options.address).call();
|
||||
var dodo_account = await ctx.DODO.methods.balanceOf(user).call();
|
||||
|
||||
console.log(logInfo + " DODO:" + fromWei(dodo_contract, 'ether') + " account:" + fromWei(dodo_account, 'ether'));
|
||||
return [dodo_contract, dodo_account]
|
||||
}
|
||||
|
||||
async function getUserInfo(ctx: VDODOContext, user: string, logInfo?: string) {
|
||||
var info = await ctx.VDODO.methods.userInfo(user).call();
|
||||
var res = {
|
||||
"VDODOAmount": info.VDODOAmount,
|
||||
"superiorVDODO": info.superiorVDODO,
|
||||
"superior": info.superior,
|
||||
"credit": info.credit
|
||||
}
|
||||
console.log(logInfo + " VDODOAmount:" + fromWei(info.VDODOAmount, 'ether') + " superiorVDODO:" + fromWei(info.superiorVDODO, 'ether') + " superior:" + info.superior + " credit:" + fromWei(info.credit, 'ether'));
|
||||
return res
|
||||
}
|
||||
|
||||
async function mint(ctx: VDODOContext, user: string, mintAmount: string, superior: string) {
|
||||
await ctx.VDODO.methods.mint(
|
||||
mintAmount,
|
||||
superior
|
||||
).send(ctx.sendParam(user));
|
||||
}
|
||||
|
||||
describe("VDODO", () => {
|
||||
let snapshotId: string;
|
||||
let ctx: VDODOContext;
|
||||
|
||||
before(async () => {
|
||||
ctx = await getVDODOContext();
|
||||
await init(ctx);
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
snapshotId = await ctx.EVM.snapshot();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await ctx.EVM.reset(snapshotId);
|
||||
});
|
||||
|
||||
describe("vdodo", () => {
|
||||
|
||||
it("vdodo-mint-first", async () => {
|
||||
await getGlobalState(ctx, "before");
|
||||
await getUserInfo(ctx, account0, "User before");
|
||||
await getUserInfo(ctx, account1, "Superior before")
|
||||
await dodoBalance(ctx, account0, "before")
|
||||
|
||||
await logGas(await ctx.VDODO.methods.mint(
|
||||
decimalStr("100"),
|
||||
account1
|
||||
), ctx.sendParam(account0), "mint-fisrt");
|
||||
|
||||
//增加两个区块
|
||||
await ctx.mintTestToken(account0, decimalStr("0"));
|
||||
await ctx.mintTestToken(account0, decimalStr("0"));
|
||||
|
||||
let [alpha,] = await getGlobalState(ctx, "after");
|
||||
let userInfo = await getUserInfo(ctx, account0, "User after");
|
||||
let superiorInfo = await getUserInfo(ctx, account1, "Superior after")
|
||||
let [, dodo_u] = await dodoBalance(ctx, account0, "after")
|
||||
|
||||
assert.equal(alpha, "101818181818181818181");
|
||||
assert.equal(userInfo.VDODOAmount, "1000000000000000000");
|
||||
assert.equal(userInfo.superiorVDODO, "100000000000000000");
|
||||
assert.equal(userInfo.credit, "0");
|
||||
assert.equal(userInfo.superior, account1);
|
||||
|
||||
assert.equal(superiorInfo.VDODOAmount, "100000000000000000");
|
||||
assert.equal(superiorInfo.superiorVDODO, "0");
|
||||
assert.equal(superiorInfo.credit, "10000000000000000000");
|
||||
assert.equal(superiorInfo.superior, "0x0000000000000000000000000000000000000000");
|
||||
|
||||
assert.equal(dodo_u, "99900000000000000000000")
|
||||
});
|
||||
|
||||
it("vdodo-mint-second", async () => {
|
||||
await mint(ctx, account0, decimalStr("100"), account1)
|
||||
|
||||
await getGlobalState(ctx, "before");
|
||||
await getUserInfo(ctx, account0, "User before");
|
||||
await getUserInfo(ctx, account1, "Superior before")
|
||||
await dodoBalance(ctx, account0, "before")
|
||||
|
||||
await logGas(await ctx.VDODO.methods.mint(
|
||||
decimalStr("100"),
|
||||
account1
|
||||
), ctx.sendParam(account0), "mint-second");
|
||||
|
||||
//增加一个区块
|
||||
await ctx.mintTestToken(account0, decimalStr("0"));
|
||||
|
||||
let [alpha,] = await getGlobalState(ctx, "after");
|
||||
let userInfo = await getUserInfo(ctx, account0, "User after");
|
||||
let superiorInfo = await getUserInfo(ctx, account1, "Superior after")
|
||||
let [, dodo_u] = await dodoBalance(ctx, account0, "after")
|
||||
|
||||
assert.equal(alpha, "101365693130399012751");
|
||||
assert.equal(userInfo.VDODOAmount, "1990990990990990990");
|
||||
assert.equal(userInfo.superiorVDODO, "199099099099099099");
|
||||
assert.equal(userInfo.credit, "0");
|
||||
assert.equal(userInfo.superior, account1);
|
||||
|
||||
assert.equal(superiorInfo.VDODOAmount, "199099099099099099");
|
||||
assert.equal(superiorInfo.superiorVDODO, "0");
|
||||
assert.equal(superiorInfo.credit, "19999999999999999990");
|
||||
assert.equal(superiorInfo.superior, "0x0000000000000000000000000000000000000000");
|
||||
|
||||
assert.equal(dodo_u, "99800000000000000000000")
|
||||
});
|
||||
|
||||
|
||||
it("vdodo-mint-second-otherSuperior", async () => {
|
||||
await mint(ctx, account0, decimalStr("100"), account1)
|
||||
|
||||
await getGlobalState(ctx, "before");
|
||||
await getUserInfo(ctx, account0, "User before");
|
||||
await getUserInfo(ctx, account1, "Superior before")
|
||||
await dodoBalance(ctx, account0, "before")
|
||||
|
||||
await logGas(await ctx.VDODO.methods.mint(
|
||||
decimalStr("100"),
|
||||
account2
|
||||
), ctx.sendParam(account0), "mint-second");
|
||||
|
||||
//增加一个区块
|
||||
await ctx.mintTestToken(account0, decimalStr("0"));
|
||||
|
||||
let [alpha,] = await getGlobalState(ctx, "after");
|
||||
let userInfo = await getUserInfo(ctx, account0, "User after");
|
||||
let superiorInfo = await getUserInfo(ctx, account1, "Superior after")
|
||||
let [, dodo_u] = await dodoBalance(ctx, account0, "after")
|
||||
|
||||
assert.equal(alpha, "101365693130399012751");
|
||||
assert.equal(userInfo.VDODOAmount, "1990990990990990990");
|
||||
assert.equal(userInfo.superiorVDODO, "199099099099099099");
|
||||
assert.equal(userInfo.credit, "0");
|
||||
assert.equal(userInfo.superior, account1);
|
||||
|
||||
assert.equal(superiorInfo.VDODOAmount, "199099099099099099");
|
||||
assert.equal(superiorInfo.superiorVDODO, "0");
|
||||
assert.equal(superiorInfo.credit, "19999999999999999990");
|
||||
assert.equal(superiorInfo.superior, "0x0000000000000000000000000000000000000000");
|
||||
|
||||
let otherInfo = await getUserInfo(ctx, account2, "Superior after")
|
||||
|
||||
assert.equal(otherInfo.VDODOAmount, "0");
|
||||
assert.equal(otherInfo.superiorVDODO, "0");
|
||||
assert.equal(otherInfo.credit, "0");
|
||||
assert.equal(otherInfo.superior, "0x0000000000000000000000000000000000000000");
|
||||
|
||||
assert.equal(dodo_u, "99800000000000000000000")
|
||||
});
|
||||
|
||||
|
||||
it("redeem-amount-read", async () => {
|
||||
await mint(ctx, account0, decimalStr("100"), account1)
|
||||
|
||||
let [dodoReceive, burnDodoAmount, withdrawFeeDodoAmount] = await ctx.VDODO.methods.getWithdrawAmount(decimalStr("1")).call();
|
||||
|
||||
assert.equal(dodoReceive, decimalStr("85"));
|
||||
assert.equal(burnDodoAmount, decimalStr("0"));
|
||||
assert.equal(withdrawFeeDodoAmount, decimalStr("15"));
|
||||
});
|
||||
|
||||
|
||||
it("redeem-partial-haveMint", async () => {
|
||||
await mint(ctx, account0, decimalStr("10000"), account1)
|
||||
|
||||
await getGlobalState(ctx, "before");
|
||||
await getUserInfo(ctx, account0, "User before");
|
||||
await getUserInfo(ctx, account1, "Superior before")
|
||||
await dodoBalance(ctx, account0, "before")
|
||||
|
||||
await logGas(await ctx.VDODO.methods.redeem(decimalStr("10")), ctx.sendParam(account0), "redeem-partial-haveMint");
|
||||
|
||||
let [alpha,] = await getGlobalState(ctx, "after");
|
||||
let userInfo = await getUserInfo(ctx, account0, "User after");
|
||||
let superiorInfo = await getUserInfo(ctx, account1, "Superior after")
|
||||
let [, dodo_u] = await dodoBalance(ctx, account0, "after")
|
||||
|
||||
assert.equal(alpha, "101524380165289256197");
|
||||
assert.equal(userInfo.VDODOAmount, "90000000000000000000");
|
||||
assert.equal(userInfo.superiorVDODO, "9000000000000000000");
|
||||
assert.equal(userInfo.credit, "0");
|
||||
assert.equal(userInfo.superior, account1);
|
||||
|
||||
assert.equal(superiorInfo.VDODOAmount, "9000000000000000000");
|
||||
assert.equal(superiorInfo.superiorVDODO, "0");
|
||||
assert.equal(superiorInfo.credit, "899990909090909090910");
|
||||
assert.equal(superiorInfo.superior, "0x0000000000000000000000000000000000000000");
|
||||
|
||||
assert.equal(dodo_u, "90850077272727272727265")
|
||||
|
||||
});
|
||||
|
||||
|
||||
it("redeem-partial-NotMint", async () => {
|
||||
//多个下级引用
|
||||
await mint(ctx, account1, decimalStr("100"), account0)
|
||||
await mint(ctx, account2, decimalStr("100"), account0)
|
||||
await mint(ctx, account3, decimalStr("100"), account0)
|
||||
await mint(ctx, account4, decimalStr("100"), account0)
|
||||
|
||||
await getGlobalState(ctx, "before");
|
||||
await getUserInfo(ctx, account0, "User before");
|
||||
await getUserInfo(ctx, account3, "One of referer before");
|
||||
await dodoBalance(ctx, account0, "before")
|
||||
|
||||
let account0VdodoAmount = await ctx.VDODO.methods.balanceOf(account0).call()
|
||||
|
||||
await logGas(await ctx.VDODO.methods.redeem((account0VdodoAmount - 3000) + ""), ctx.sendParam(account0), "redeem-partial-NotMint");
|
||||
|
||||
let [alpha,] = await getGlobalState(ctx, "after");
|
||||
let userInfo = await getUserInfo(ctx, account0, "User after");
|
||||
let superiorInfo = await getUserInfo(ctx, account3, "One of referer after")
|
||||
let [, dodo_u] = await dodoBalance(ctx, account0, "after")
|
||||
|
||||
assert.equal(alpha, "101909933011338172201");
|
||||
assert.equal(userInfo.VDODOAmount, "393425809544634067");
|
||||
assert.equal(userInfo.superiorVDODO, "0");
|
||||
assert.equal(userInfo.credit, "39999999999999999876");
|
||||
assert.equal(userInfo.superior, "0x0000000000000000000000000000000000000000");
|
||||
|
||||
assert.equal(superiorInfo.VDODOAmount, "986527067608148689");
|
||||
assert.equal(superiorInfo.superiorVDODO, "98652706760814868");
|
||||
assert.equal(superiorInfo.credit, "0");
|
||||
assert.equal(superiorInfo.superior, account0);
|
||||
|
||||
assert.equal(dodo_u, "100000232341473424735076")
|
||||
});
|
||||
|
||||
|
||||
it("redeem-all-haveMint", async () => {
|
||||
//第一笔mint不动,防止totalSupply过小
|
||||
await mint(ctx, account0, decimalStr("10000"), account1)
|
||||
await mint(ctx, account1, decimalStr("100"), account2)
|
||||
|
||||
await getGlobalState(ctx, "before");
|
||||
await getUserInfo(ctx, account1, "User before");
|
||||
await getUserInfo(ctx, account2, "Superior before")
|
||||
await dodoBalance(ctx, account1, "before")
|
||||
|
||||
let account1VdodoAmount = await ctx.VDODO.methods.balanceOf(account1).call()
|
||||
|
||||
await logGas(await ctx.VDODO.methods.redeem(account1VdodoAmount), ctx.sendParam(account1), "redeem-all-haveMint");
|
||||
|
||||
let [alpha,] = await getGlobalState(ctx, "after");
|
||||
let userInfo = await getUserInfo(ctx, account1, "User after");
|
||||
let superiorInfo = await getUserInfo(ctx, account2, "Superior after")
|
||||
let [, dodo_u] = await dodoBalance(ctx, account1, "after")
|
||||
|
||||
assert.equal(alpha, "100154592821433302856");
|
||||
assert.equal(userInfo.VDODOAmount, "9999090991728024725");
|
||||
assert.equal(userInfo.superiorVDODO, "0");
|
||||
assert.equal(userInfo.credit, "1000000000000000000000");
|
||||
assert.equal(userInfo.superior, account2);
|
||||
|
||||
assert.equal(superiorInfo.VDODOAmount, "8998462015594");
|
||||
assert.equal(superiorInfo.superiorVDODO, "0");
|
||||
assert.equal(superiorInfo.credit, "0");
|
||||
assert.equal(superiorInfo.superior, "0x0000000000000000000000000000000000000000");
|
||||
|
||||
assert.equal(dodo_u, "985084929758388492933")
|
||||
|
||||
});
|
||||
|
||||
|
||||
it("redeem-all-NoMint", async () => {
|
||||
//多个下级引用
|
||||
await mint(ctx, account1, decimalStr("100"), account0)
|
||||
await mint(ctx, account2, decimalStr("100"), account0)
|
||||
await mint(ctx, account3, decimalStr("100"), account0)
|
||||
await mint(ctx, account4, decimalStr("100"), account0)
|
||||
|
||||
await getGlobalState(ctx, "before");
|
||||
await getUserInfo(ctx, account0, "User before");
|
||||
await getUserInfo(ctx, account3, "One of referer before");
|
||||
await dodoBalance(ctx, account0, "before")
|
||||
|
||||
let account0VdodoAmount = await ctx.VDODO.methods.balanceOf(account0).call()
|
||||
|
||||
await logGas(await ctx.VDODO.methods.redeem(account0VdodoAmount), ctx.sendParam(account0), "redeem-all-NotMint");
|
||||
|
||||
let [alpha,] = await getGlobalState(ctx, "after");
|
||||
let userInfo = await getUserInfo(ctx, account0, "User after");
|
||||
let superiorInfo = await getUserInfo(ctx, account3, "One of referer after")
|
||||
let [, dodo_u] = await dodoBalance(ctx, account0, "after")
|
||||
|
||||
assert.equal(alpha, "101909933011338182738");
|
||||
assert.equal(userInfo.VDODOAmount, "393425809544631067");
|
||||
assert.equal(userInfo.superiorVDODO, "0");
|
||||
assert.equal(userInfo.credit, "39999999999999999876");
|
||||
assert.equal(userInfo.superior, "0x0000000000000000000000000000000000000000");
|
||||
|
||||
assert.equal(superiorInfo.VDODOAmount, "986527067608148689");
|
||||
assert.equal(superiorInfo.superiorVDODO, "98652706760814868");
|
||||
assert.equal(superiorInfo.credit, "0");
|
||||
assert.equal(superiorInfo.superior, account0);
|
||||
|
||||
assert.equal(dodo_u, "100000232341473424994923")
|
||||
});
|
||||
})
|
||||
});
|
||||
@@ -38,7 +38,7 @@ module.exports = {
|
||||
* $ truffle test --network <network-name>
|
||||
*/
|
||||
deploySwitch: {
|
||||
DEPLOY_V1: true,
|
||||
DEPLOY_V1: false,
|
||||
DEPLOY_V2: false,
|
||||
ADAPTER: false,
|
||||
MOCK_TOKEN: false,
|
||||
|
||||
@@ -36,6 +36,12 @@ then
|
||||
truffle test ./test/V2Proxy/proxy.twap.test.ts
|
||||
fi
|
||||
|
||||
if [ "$1"x = "vdodo-mintRedeem"x ]
|
||||
then
|
||||
truffle test ./test/vDODO/mintRedeem.test.ts
|
||||
fi
|
||||
|
||||
|
||||
# if [ "$1"x = "route-incentive"x ]
|
||||
# then
|
||||
# truffle test ./test/Route/Incentive.test.ts
|
||||
|
||||
Reference in New Issue
Block a user