Merge pull request #6 from DODOEX/feature/V2

Feature/v2
This commit is contained in:
owen05
2021-02-04 15:34:19 +08:00
committed by GitHub
18 changed files with 1670 additions and 5 deletions

View File

@@ -32,3 +32,4 @@ Anyone who reports a unique, previously-unreported vulnerability that results in
## Contact Us
Send E-mail to contact@dodoex.io

View 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);
}
}

View 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);
}
}
}

View 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);
}
}

View 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
}
}

View 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);
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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
}

View File

@@ -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;

View File

@@ -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
View 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
View 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
View 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))
});
})
});

View 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")
});
})
});

View File

@@ -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,

View File

@@ -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