diff --git a/contracts/DODOToken/DODOCirculationHelper.sol b/contracts/DODOToken/DODOCirculationHelper.sol index f048713..7cabe22 100644 --- a/contracts/DODOToken/DODOCirculationHelper.sol +++ b/contracts/DODOToken/DODOCirculationHelper.sol @@ -10,7 +10,7 @@ pragma experimental ABIEncoderV2; import {IERC20} from "../intf/IERC20.sol"; import {SafeMath} from "../lib/SafeMath.sol"; import {DecimalMath} from "../lib/DecimalMath.sol"; -import {Ownable} from "../lib/Ownable.sol"; +import {InitializableOwnable} from "../lib/InitializableOwnable.sol"; interface IDODOCirculationHelper { // vDODO 锁仓不算流通 @@ -19,28 +19,29 @@ interface IDODOCirculationHelper { function getVDODOWithdrawFeeRatio() external returns (uint256); } -contract DODOCirculationHelper is Ownable { +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 dodoToken) public { + constructor(address vDodoToken,address dodoToken) public { + _VDODO_TOKEN_ = vDodoToken; _DODO_TOKEN_ = dodoToken; - } // todo + } function addLockedContractAddress(address lockedContract) external onlyOwner {} // todo function removeLockedContractAddress(address lockedContract) external onlyOwner {} // todo function getCirculation() public view returns (uint256 circulation) { - circulation = 10**9; - //TODO circulation 需要乘以decimals吗? + circulation = 10**10 * 10**18; for (uint256 i = 0; i < _LOCKED_CONTRACT_ADDRESS_.length; i++) { circulation -= IERC20(_DODO_TOKEN_).balanceOf(_LOCKED_CONTRACT_ADDRESS_[i]); } @@ -55,7 +56,7 @@ contract DODOCirculationHelper is Ownable { uint256 x = DecimalMath.divCeil( dodoCirculationAmout, - IERC20(_DODO_TOKEN_).balanceOf(address(this))// TODO 这里应该是vdodo的值吧? + IERC20(_VDODO_TOKEN_).totalSupply() ); if (x <= 10**18) { diff --git a/contracts/DODOToken/vDODOToken.sol b/contracts/DODOToken/vDODOToken.sol index a143596..c546211 100644 --- a/contracts/DODOToken/vDODOToken.sol +++ b/contracts/DODOToken/vDODOToken.sol @@ -254,7 +254,7 @@ contract vDODOToken is InitializableOwnable, ReentrancyGuard { } function getLatestAlpha() public view returns(uint256) { - uint256 accuDODO = dodoPerBlock * (block.number.sub(lastRewardBlock)); + uint256 accuDODO = dodoPerBlock * (block.number - lastRewardBlock); if (totalSupply > 0) { return uint256(alpha).add(DecimalMath.divFloor(accuDODO, totalSupply)); } else { @@ -299,8 +299,8 @@ contract vDODOToken is InitializableOwnable, ReentrancyGuard { user.superiorVDODO = uint128(uint256(user.superiorVDODO).add(vdodoAmount)); UserInfo storage superiorUser = userInfo[user.superior]; _mint(superiorUser, vdodoAmount); - uint256 dodoAmount = DecimalMath.mulFloor(vdodoAmount, alpha); - superiorUser.credit = superiorUser.credit.add(DecimalMath.mulFloor(dodoAmount, _SUPERIOR_RATIO_)); + uint256 dodoAmount = DecimalMath.mulCeil(vdodoAmount, alpha); + superiorUser.credit = superiorUser.credit.add(dodoAmount); } } diff --git a/test/utils/Converter.ts b/test/utils/Converter.ts index e01ac5d..d1d67b9 100644 --- a/test/utils/Converter.ts +++ b/test/utils/Converter.ts @@ -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); } \ No newline at end of file diff --git a/test/utils/VDODOContext.ts b/test/utils/VDODOContext.ts index 814e516..c04775c 100644 --- a/test/utils/VDODOContext.ts +++ b/test/utils/VDODOContext.ts @@ -36,8 +36,8 @@ export class VDODOContext { DODOCirculationHelper: Contract; Governance: Contract; - lastRewardBlock:number; - alpha:number; + lastRewardBlock: number; + alpha: number; @@ -57,12 +57,6 @@ export class VDODOContext { ["DODO Token", "DODO", 18] ); - this.DODOCirculationHelper = await contracts.newContract( - contracts.DODO_CULATION_HELPER, - [ - this.DODO.options.address - ] - ); this.DODOApprove = await contracts.newContract( contracts.SMART_APPROVE ); @@ -84,22 +78,29 @@ export class VDODOContext { [ this.Governance.options.address, this.DODO.options.address, - this.DODOCirculationHelper.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)) - + ).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.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)); @@ -108,11 +109,12 @@ export class VDODOContext { ).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); diff --git a/test/vDODO/mintRedeem.test.ts b/test/vDODO/mintRedeem.test.ts index cbbbaa8..b2fdc18 100644 --- a/test/vDODO/mintRedeem.test.ts +++ b/test/vDODO/mintRedeem.test.ts @@ -5,18 +5,19 @@ */ -import { decimalStr, MAX_UINT256 } from '../utils/Converter'; +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; +let account2: string; async function init(ctx: VDODOContext): Promise { account0 = ctx.SpareAccounts[0]; account1 = ctx.SpareAccounts[1]; + account2 = ctx.SpareAccounts[2]; await ctx.mintTestToken(account0, decimalStr("1000")); await ctx.mintTestToken(account1, decimalStr("1000")); @@ -25,7 +26,40 @@ async function init(ctx: VDODOContext): Promise { await ctx.approveProxy(account1); } -//TODO: 抽象出来mint func +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; @@ -47,40 +81,124 @@ describe("VDODO", () => { describe("vdodo", () => { it("vdodo-mint-first", async () => { - //第一次mint 后 - //alpha lastRewardBlock 状态 - //user superior info 状态 - //vDODO 总量变化,以及vDODO合约dodo余额,user dodo余额 - var b_alpha = await ctx.VDODO.methods.getLatestAlpha().call(); - var b_lastRewardBlock = await ctx.VDODO.methods.lastRewardBlock().call(); - var b_dodo_contract = await ctx.DODO.methods.balanceOf(ctx.DODO.options.address).call(); - var b_dodo_account = await ctx.DODO.methods.balanceOf(account0).call(); + await getGlobalState(ctx, "before"); + await getUserInfo(ctx, account0, "User before"); + await getUserInfo(ctx, account1, "Superior before") + await dodoBalance(ctx, account0, "before") - var userInfo = await ctx.VDODO.methods.userInfo(account0).call(); + await logGas(await ctx.VDODO.methods.mint( + decimalStr("100"), + account1 + ), ctx.sendParam(account0), "mint-fisrt"); - console.log("userInfo:", userInfo) + //增加两个区块 + await ctx.mintTestToken(account0, decimalStr("0")); + await ctx.mintTestToken(account0, decimalStr("0")); + let [alpha,] = await getGlobalState(ctx, "after"); + assert.equal(alpha, "101818181818181818181"); + 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(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, "900000000000000000000") }); it("vdodo-mint-second", async () => { - //第二次mint 后(传入之前的superior地址) - //alpha lastRewardBlock 状态 - //user superior info 状态 - //vDODO 总量变化,以及vDODO合约dodo余额,user dodo余额 + 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"); + assert.equal(alpha, "101365693130399012751"); + 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(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, "800000000000000000000") }); it("vdodo-mint-second-otherSuperior", async () => { - //第二次mint 后(传入非之前superior地址) - //alpha lastRewardBlock 状态 - //user superior info 状态 - //vDODO 总量变化,以及vDODO合约dodo余额,user dodo余额 + 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"); + assert.equal(alpha, "101365693130399012751"); + 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(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, "800000000000000000000") }); - it("redeem-amount-read", async () => { - //正确读取 withdrawAmount 字段 + it.only("redeem-amount-read", async () => { + await mint(ctx, account0, decimalStr("100"), account1) + + let [dodoReceive, burnDodoAmount, withdrawFeeDodoAmount] = await ctx.VDODO.methods.getWithdrawAmount(decimalStr("1")).call(); + + console.log("dodoReceive:", dodoReceive) + console.log("burnDodoAmount:", burnDodoAmount) + console.log("withdrawFeeDodoAmount:", withdrawFeeDodoAmount) + }); it("redeem-partial-haveMint", async () => { @@ -89,7 +207,7 @@ describe("VDODO", () => { it("redeem-partial-NotMint", async () => { //多个下级引用 - + }); it("redeem-all-haveMint", async () => { @@ -100,36 +218,5 @@ describe("VDODO", () => { //多个下级引用 }); - - // it("vdodo first mint with no superior", async () => { - - // await ctx.VDODO.methods.mint(decimalStr("10"),"0x0000000000000000000000000000000000000000").send(ctx.sendParam(account0)) - // assert.equal( - // await ctx.DODO.methods.balanceOf(account0).call(), - // decimalStr("990") - // ); - // assert.equal( - // await await ctx.VDODO.methods.alpha().call(), - // await ctx.alpha - // ); - // assert.equal( - // await ctx.DODO.methods.balanceOf(ctx.VDODO.options.address).call(), - // decimalStr("10") - // ); - // assert.equal( - // await ctx.VDODO.methods.balanceOf(account0).call(), - // decimalStr("0.1") - // ); - - // assert.equal( - // await ctx.VDODO.methods.totalSupply().call(), - // decimalStr("0.1") - // ); - // assert.notEqual( - // await ctx.VDODO.methods.lastRewardBlock().call(), - // ctx.lastRewardBlock - // ); - // }); - }) });