diff --git a/contracts/DODOToken/DODOMineV2/BaseMine.sol b/contracts/DODOToken/DODOMineV2/BaseMine.sol index 2bd5d03..4687527 100644 --- a/contracts/DODOToken/DODOMineV2/BaseMine.sol +++ b/contracts/DODOToken/DODOMineV2/BaseMine.sol @@ -1,6 +1,6 @@ /* - Copyright 2020 DODO ZOO. + Copyright 2021 DODO ZOO. SPDX-License-Identifier: Apache-2.0 */ @@ -45,24 +45,23 @@ contract BaseMine is InitializableOwnable { event NewRewardToken(uint256 indexed i, address rewardToken); event RemoveRewardToken(address rewardToken); - // ============ Modifier ========== // ============ View ============ function getPendingReward(address user, uint256 i) public view returns (uint256) { - RewardTokenInfo memory rt = rewardTokenInfos[i]; + RewardTokenInfo storage rt = rewardTokenInfos[i]; uint256 accRewardPerShare = rt.accRewardPerShare; if (rt.lastRewardBlock != block.number) { - accRewardPerShare = _getAccRewardPerShare(i) + accRewardPerShare = _getAccRewardPerShare(i); } return DecimalMath.mulFloor( balanceOf(user), - accRewardPerShare.sub(rt.userRewardPeSharenPaid[user]) + accRewardPerShare.sub(rt.userRewardPerSharePaid[user]) ).add(rt.userRewards[user]); } - function getPendingReward(address user, address rewardToken) public view returns (uint256) { + function getPendingRewardByToken(address user, address rewardToken) public view returns (uint256) { return getPendingReward(user, getIdByRewardToken(rewardToken)); } @@ -85,7 +84,7 @@ contract BaseMine is InitializableOwnable { for (uint256 i = 0; i < len; i++) { if (rewardToken == rewardTokenInfos[i].rewardToken) { return i; - }; + } } require(true, "DODOMineV2: TOKEN_NOT_FOUND"); } @@ -114,6 +113,7 @@ contract BaseMine is InitializableOwnable { function addRewardToken( address rewardToken, + uint256 rewardPerBlock, uint256 startBlock, uint256 endBlock ) external onlyOwner { @@ -133,6 +133,7 @@ contract BaseMine is InitializableOwnable { rt.rewardToken = rewardToken; rt.startBlock = startBlock; rt.endBlock = endBlock; + rt.rewardPerBlock = rewardPerBlock; rt.rewardVault = address(new RewardVault(rewardToken)); emit NewRewardToken(len, rewardToken); @@ -202,7 +203,7 @@ contract BaseMine is InitializableOwnable { if (block.number < rt.startBlock || rt.lastRewardBlock > rt.endBlock) { return 0; } - uint256 start = rt.startBlock > block.number ? rt.startBlock : block.number; + uint256 start = rt.lastRewardBlock < rt.startBlock ? rt.startBlock : rt.lastRewardBlock; uint256 end = rt.endBlock < block.number ? rt.endBlock : block.number; return end.sub(start); } diff --git a/contracts/DODOToken/DODOMineV2/ERC20Mine.sol b/contracts/DODOToken/DODOMineV2/ERC20Mine.sol index 1056b50..0224ad6 100644 --- a/contracts/DODOToken/DODOMineV2/ERC20Mine.sol +++ b/contracts/DODOToken/DODOMineV2/ERC20Mine.sol @@ -1,6 +1,6 @@ /* - Copyright 2020 DODO ZOO. + Copyright 2021 DODO ZOO. SPDX-License-Identifier: Apache-2.0 */ @@ -31,7 +31,7 @@ contract ERC20Mine is BaseMine { // ============ Deposit && Withdraw && Exit ============ - function deposit(uint256 amount) public { + function deposit(uint256 amount) external { require(amount > 0, "DODOMineV2: CANNOT_DEPOSIT_ZERO"); _updateAllReward(msg.sender); @@ -42,7 +42,7 @@ contract ERC20Mine is BaseMine { emit Deposit(msg.sender, amount); } - function withdraw(uint256 amount) public { + function withdraw(uint256 amount) external { require(amount > 0, "DODOMineV2: CANNOT_WITHDRAW_ZERO"); _updateAllReward(msg.sender); diff --git a/contracts/DODOToken/DODOMineV2/vDODOMine.sol b/contracts/DODOToken/DODOMineV2/vDODOMine.sol index 661b34c..0b79e37 100644 --- a/contracts/DODOToken/DODOMineV2/vDODOMine.sol +++ b/contracts/DODOToken/DODOMineV2/vDODOMine.sol @@ -1,6 +1,6 @@ /* - Copyright 2020 DODO ZOO. + Copyright 2021 DODO ZOO. SPDX-License-Identifier: Apache-2.0 */ @@ -34,20 +34,22 @@ contract vDODOMine is BaseMine { // ============ Deposit && Withdraw && Exit ============ - function deposit(uint256 amount) public { + function deposit(uint256 amount) external { require(amount > 0, "DODOMineV2: CANNOT_DEPOSIT_ZERO"); require( amount <= IVDODOToken(_vDODO_TOKEN_).availableBalanceOf(msg.sender), "DODOMineV2: vDODO_NOT_ENOUGH" ); + _updateAllReward(msg.sender); _totalSupply = _totalSupply.add(amount); _balances[msg.sender] = _balances[msg.sender].add(amount); emit Deposit(msg.sender, amount); } - function withdraw(uint256 amount) public { + function withdraw(uint256 amount) external { require(amount > 0, "DODOMineV2: CANNOT_WITHDRAW_ZERO"); require(amount <= _balances[msg.sender], "DODOMineV2: WITHDRAW_BALANCE_NOT_ENOUGH"); + _updateAllReward(msg.sender); _totalSupply = _totalSupply.sub(amount); _balances[msg.sender] = _balances[msg.sender].sub(amount); emit Withdraw(msg.sender, amount); diff --git a/test/DODOMineV2/erc20Mine.test.ts b/test/DODOMineV2/erc20Mine.test.ts index 6e9a61a..20d3c7a 100644 --- a/test/DODOMineV2/erc20Mine.test.ts +++ b/test/DODOMineV2/erc20Mine.test.ts @@ -9,7 +9,6 @@ import { decimalStr, fromWei } from '../utils/Converter'; import { logGas } from '../utils/Log'; import { DODOMineV2Context, getDODOMineContext } from '../utils/DODOMineV2Context'; import { assert } from 'chai'; -import BigNumber from 'bignumber.js'; import { Contract } from 'web3-eth-contract'; let account0: string; @@ -33,37 +32,37 @@ async function init(ctx: DODOMineV2Context): Promise { await ctx.approveProxy(account1, ctx.ERC20Mine.options.address, ctx.ERC20); } -async function addRewardToken(ctx: DODOMineV2Context, token: Contract, start: number, end: number) { +async function addRewardToken(ctx: DODOMineV2Context, token: Contract, start: number, end: number, rewardPerBlock: string) { await ctx.ERC20Mine.methods.addRewardToken( token.options.address, + rewardPerBlock, start, end ).send(ctx.sendParam(projector)); - let idx = await ctx.ERC20Mine.methods.getIdxByRewardToken(token.options.address).call(); + let idx = await ctx.ERC20Mine.methods.getIdByRewardToken(token.options.address).call(); let rewardInfo = await ctx.ERC20Mine.methods.rewardTokenInfos(idx).call(); - await token.methods.transfer(rewardInfo.vault, decimalStr("10000")).send(this.sendParam(this.Deployer)); + await token.methods.transfer(rewardInfo.rewardVault, decimalStr("10000")).send(ctx.sendParam(projector)); } -async function balanceInfo(ctx: DODOMineV2Context, idx:number,user: string,logInfo?:string) { - +async function stakeInfo(ctx: DODOMineV2Context, user: string, logInfo?: string) { + console.log(logInfo) + let totalSupply = await ctx.ERC20Mine.methods.totalSupply().call(); + let balance = await ctx.ERC20Mine.methods.balanceOf(user).call(); + console.log("totalSupply:" + fromWei(totalSupply, "ether") + " balance:" + fromWei(balance, "ether")); } async function getRewardInfo(ctx: DODOMineV2Context, idx: number, user: string, logInfo?: string) { let erc20Mine = ctx.ERC20Mine let obj = await erc20Mine.methods.rewardTokenInfos(idx).call(); + let curBlock = await ctx.Web3.eth.getBlockNumber(); console.log(logInfo); - console.log("Static-Data: rewardToken:" + obj.rewardToken + " " + ) - console.log("startBlock:", obj.startBlock) - console.log("endBlock:", obj.endBlock) - console.log("rewardVault:", obj.rewardVault) - console.log("rewardPerBlock:", obj.rewardPerBlock) - console.log("accRewardPerShare:", obj.accRewardPerShare) - console.log("lastRewardBlock:", obj.lastRewardBlock) + // console.log("Static-Data: rewardToken:" + obj.rewardToken + " rewardVault:" + obj.rewardVault + " rewardPerBlock:" + fromWei(obj.rewardPerBlock, "ether")); + console.log("Dynamic-Data: start:" + obj.startBlock + " end:" + obj.endBlock + " accRewardPerShare:" + fromWei(obj.accRewardPerShare, "ether") + " lastRewardBlock:" + obj.lastRewardBlock + " curBlock:" + curBlock); var pendingReward = null; if (user != null) { - pendingReward = await erc20Mine.methods.getPendingReward(idx, user).call(); - console.log("pendingReward:", pendingReward); + pendingReward = await erc20Mine.methods.getPendingReward(user, idx).call(); + console.log("User-pendingReward:" + fromWei(pendingReward, "ether")); } return [obj, pendingReward]; } @@ -73,7 +72,7 @@ describe("erc20Mine", () => { let ctx: DODOMineV2Context; before(async () => { - ctx = await getDODOMineContext(); + ctx = await getDODOMineContext(null); await init(ctx); }); @@ -93,6 +92,7 @@ describe("erc20Mine", () => { var curBlock = await ctx.Web3.eth.getBlockNumber(); await erc20Mine.methods.addRewardToken( ctx.REWARD_1.options.address, + decimalStr("0"), curBlock + 2, curBlock + 1000 ).send(ctx.sendParam(projector)); @@ -103,8 +103,8 @@ describe("erc20Mine", () => { it("removeRewardToken", async () => { let erc20Mine = ctx.ERC20Mine; var curBlock = await ctx.Web3.eth.getBlockNumber(); - await addRewardToken(ctx, ctx.REWARD_1, curBlock + 10, curBlock + 110); - await addRewardToken(ctx, ctx.REWARD_2, curBlock + 10, curBlock + 110); + await addRewardToken(ctx, ctx.REWARD_1, curBlock + 10, curBlock + 110, decimalStr("0")); + await addRewardToken(ctx, ctx.REWARD_2, curBlock + 10, curBlock + 110, decimalStr("0")); let [rewardTokenInfo,] = await getRewardInfo(ctx, 0, null, ""); await erc20Mine.methods.removeRewardToken( rewardTokenInfo.rewardToken @@ -112,15 +112,6 @@ describe("erc20Mine", () => { [rewardTokenInfo,] = await getRewardInfo(ctx, 0, null, ""); assert(rewardTokenInfo.rewardToken, ctx.REWARD_2.options.address) }); - - it("setReward", async () => { - - }); - - it("setEndBlock", async () => { - - }); - // =========================== }) @@ -129,40 +120,238 @@ describe("erc20Mine", () => { it("deposit", async () => { var curBlock = await ctx.Web3.eth.getBlockNumber(); - await addRewardToken(ctx, ctx.REWARD_1, curBlock + 2, curBlock + 102); + await addRewardToken(ctx, ctx.REWARD_1, curBlock + 2, curBlock + 102, decimalStr("10")); + await stakeInfo(ctx, account0, "UserStakeInfo - Before"); + await getRewardInfo(ctx, 0, account0, "UserRewardInfo - Before"); + //增加区块 + await ctx.increBlock(3); + + // curBlock = await ctx.Web3.eth.getBlockNumber(); + // console.log("deposit curBlock:", curBlock) + await logGas(await ctx.ERC20Mine.methods.deposit( + decimalStr("5") + ), ctx.sendParam(account0), "deposit"); await logGas(await ctx.ERC20Mine.methods.deposit( decimalStr("10") ), ctx.sendParam(account0), "deposit"); + await logGas(await ctx.ERC20Mine.methods.deposit( + decimalStr("5") + ), ctx.sendParam(account0), "deposit"); + await stakeInfo(ctx, account0, "UserStakeInfo - After"); + await getRewardInfo(ctx, 0, account0, "UserRewardInfo - After - 1"); //增加区块 - await ctx.mintTestToken(account0, ctx.ERC20, decimalStr("0")); - await ctx.mintTestToken(account0, ctx.ERC20, decimalStr("0")); - await ctx.mintTestToken(account0, ctx.ERC20, decimalStr("0")); - + await ctx.increBlock(3); + let [obj, pendingReward] = await getRewardInfo(ctx, 0, account0, "UserRewardInfo - After - 2"); + assert.equal(obj.accRewardPerShare, "2666666666666666666"); + assert.equal(pendingReward, "49999999999999999990"); }); it("withdraw", async () => { + var curBlock = await ctx.Web3.eth.getBlockNumber(); + await addRewardToken(ctx, ctx.REWARD_1, curBlock + 2, curBlock + 102, decimalStr("10")); + // await stakeInfo(ctx, account0, "UserStakeInfo - Before"); + // await getRewardInfo(ctx, 0, account0, "UserRewardInfo - Before"); + //增加区块 + await ctx.increBlock(3); - }); + await logGas(await ctx.ERC20Mine.methods.deposit( + decimalStr("20") + ), ctx.sendParam(account0), "deposit - account0"); + await logGas(await ctx.ERC20Mine.methods.deposit( + decimalStr("10") + ), ctx.sendParam(account1), "deposit - account1"); - it("withdrawAll", async () => { + await getRewardInfo(ctx, 0, account0, "UserRewardInfo - After - 1"); + await ctx.increBlock(3); + await getRewardInfo(ctx, 0, account0, "UserRewardInfo - After - 2"); + await logGas(await ctx.ERC20Mine.methods.withdraw( + decimalStr("10") + ), ctx.sendParam(account0), "withdraw"); + await getRewardInfo(ctx, 0, account0, "UserRewardInfo - After - 3"); + await logGas(await ctx.ERC20Mine.methods.withdraw( + decimalStr("10") + ), ctx.sendParam(account0), "withdraw"); + + //增加区块 + await ctx.increBlock(3); + let [obj, pendingReward] = await getRewardInfo(ctx, 0, account0, "UserRewardInfo - After - 4"); + + assert.equal(obj.accRewardPerShare, "2333333333333333333"); + assert.equal(pendingReward, "41666666666666666660"); }); it("getReward", async () => { + var curBlock = await ctx.Web3.eth.getBlockNumber(); + await addRewardToken(ctx, ctx.REWARD_1, curBlock + 2, curBlock + 102, decimalStr("10")); + await stakeInfo(ctx, account0, "UserStakeInfo - Before"); + await getRewardInfo(ctx, 0, account0, "UserRewardInfo - Before"); + + //增加区块 + await ctx.increBlock(3); + + await logGas(await ctx.ERC20Mine.methods.deposit( + decimalStr("10") + ), ctx.sendParam(account0), "deposit"); + await logGas(await ctx.ERC20Mine.methods.deposit( + decimalStr("10") + ), ctx.sendParam(account1), "deposit"); + + //增加区块 + await ctx.increBlock(3); + + await getRewardInfo(ctx, 0, account0, "UserRewardInfo - After"); + await logGas(await ctx.ERC20Mine.methods.claimReward(0), ctx.sendParam(account0), "claimReward - 0"); + + let rewardBalance = await ctx.REWARD_1.methods.balanceOf(account0).call(); + assert.equal(rewardBalance, "30000000000000000000"); }); it("getRewardAll", async () => { + var curBlock = await ctx.Web3.eth.getBlockNumber(); + await addRewardToken(ctx, ctx.REWARD_1, curBlock + 5, curBlock + 103, decimalStr("10")); + await addRewardToken(ctx, ctx.REWARD_2, curBlock + 5, curBlock + 103, decimalStr("5")); + await stakeInfo(ctx, account0, "UserStakeInfo - Before"); + await getRewardInfo(ctx, 0, account0, "UserRewardInfo - Before"); + //增加区块 + await ctx.increBlock(10); + + await logGas(await ctx.ERC20Mine.methods.deposit( + decimalStr("10") + ), ctx.sendParam(account0), "deposit"); + await logGas(await ctx.ERC20Mine.methods.deposit( + decimalStr("10") + ), ctx.sendParam(account1), "deposit"); + + //增加区块 + await ctx.increBlock(3); + + await getRewardInfo(ctx, 0, account0, "UserRewardInfo - After"); + await logGas(await ctx.ERC20Mine.methods.claimAllRewards(), ctx.sendParam(account0), "claimReward - 0"); + + let rewardBalance0 = await ctx.REWARD_1.methods.balanceOf(account0).call(); + let rewardBalance1 = await ctx.REWARD_2.methods.balanceOf(account0).call(); + assert.equal(rewardBalance0, "30000000000000000000"); + assert.equal(rewardBalance1, "15000000000000000000"); }); - it("exit", async () => { + it("setReward - beforeStart", async () => { + var curBlock = await ctx.Web3.eth.getBlockNumber(); + await addRewardToken(ctx, ctx.REWARD_1, curBlock + 10, curBlock + 100, decimalStr("10")); + await ctx.ERC20Mine.methods.setReward(0, decimalStr("5")).send(ctx.sendParam(projector)); + + //增加区块 + await ctx.increBlock(10); + + await logGas(await ctx.ERC20Mine.methods.deposit( + decimalStr("10") + ), ctx.sendParam(account0), "deposit"); + await logGas(await ctx.ERC20Mine.methods.deposit( + decimalStr("10") + ), ctx.sendParam(account1), "deposit"); + + //增加区块 + await ctx.increBlock(3); + + await getRewardInfo(ctx, 0, account0, "UserRewardInfo - After"); + await logGas(await ctx.ERC20Mine.methods.claimReward(0), ctx.sendParam(account0), "claimReward - 0"); + + let rewardBalance = await ctx.REWARD_1.methods.balanceOf(account0).call(); + assert.equal(rewardBalance, "15000000000000000000"); + }) + + it("setReward - ing", async () => { + var curBlock = await ctx.Web3.eth.getBlockNumber(); + await addRewardToken(ctx, ctx.REWARD_1, curBlock + 2, curBlock + 100, decimalStr("10")); + + //增加区块 + await ctx.increBlock(3); + + await logGas(await ctx.ERC20Mine.methods.deposit( + decimalStr("10") + ), ctx.sendParam(account0), "deposit"); + await logGas(await ctx.ERC20Mine.methods.deposit( + decimalStr("10") + ), ctx.sendParam(account1), "deposit"); + + //增加区块 + await ctx.increBlock(3); + + let [, pendingReward] = await getRewardInfo(ctx, 0, account0, "UserRewardInfo - After"); + assert.equal(pendingReward, "25000000000000000000"); + + await ctx.ERC20Mine.methods.setReward(0, decimalStr("5")).send(ctx.sendParam(projector)); + + //增加区块 + await ctx.increBlock(3); + + [, pendingReward] = await getRewardInfo(ctx, 0, account0, "UserRewardInfo - After"); + await logGas(await ctx.ERC20Mine.methods.claimReward(0), ctx.sendParam(account0), "claimReward - 0"); + + let rewardBalance = await ctx.REWARD_1.methods.balanceOf(account0).call(); + assert.equal(rewardBalance, "40000000000000000000"); + }) + + it("setReward - after", async () => { + var curBlock = await ctx.Web3.eth.getBlockNumber(); + await addRewardToken(ctx, ctx.REWARD_1, curBlock + 2, curBlock + 10, decimalStr("10")); + + //增加区块 + await ctx.increBlock(3); + + await logGas(await ctx.ERC20Mine.methods.deposit( + decimalStr("10") + ), ctx.sendParam(account0), "deposit"); + await logGas(await ctx.ERC20Mine.methods.deposit( + decimalStr("10") + ), ctx.sendParam(account1), "deposit"); + + //增加区块 + await ctx.increBlock(3); + + let [, pendingReward] = await getRewardInfo(ctx, 0, account0, "UserRewardInfo - After"); + assert.equal(pendingReward, "25000000000000000000"); + + await ctx.ERC20Mine.methods.setReward(0, decimalStr("5")).send(ctx.sendParam(projector)); + + //增加区块 + await ctx.increBlock(3); + + [, pendingReward] = await getRewardInfo(ctx, 0, account0, "UserRewardInfo - After"); + await logGas(await ctx.ERC20Mine.methods.claimReward(0), ctx.sendParam(account0), "claimReward - 0"); + + let rewardBalance = await ctx.REWARD_1.methods.balanceOf(account0).call(); + assert.equal(rewardBalance, "25000000000000000000"); + }) + + it("setEndBlock", async () => { + var curBlock = await ctx.Web3.eth.getBlockNumber(); + await addRewardToken(ctx, ctx.REWARD_1, curBlock + 2, curBlock + 100, decimalStr("10")); + + //增加区块 + await ctx.increBlock(3); + + await logGas(await ctx.ERC20Mine.methods.deposit( + decimalStr("10") + ), ctx.sendParam(account0), "deposit"); + await logGas(await ctx.ERC20Mine.methods.deposit( + decimalStr("10") + ), ctx.sendParam(account1), "deposit"); + + //增加区块 + await ctx.increBlock(3); + + await ctx.ERC20Mine.methods.setEndBlock(0, curBlock + 120).send(ctx.sendParam(projector)); + let [obj,] = await getRewardInfo(ctx, 0, account0, "UserRewardInfo - After"); + assert(obj.endBlock - curBlock - 100, "20"); + }) - }); }) }); diff --git a/test/DODOMineV2/vDODOMine.test.ts b/test/DODOMineV2/vDODOMine.test.ts index e69de29..9fb1ac2 100644 --- a/test/DODOMineV2/vDODOMine.test.ts +++ b/test/DODOMineV2/vDODOMine.test.ts @@ -0,0 +1,194 @@ +/* + + Copyright 2021 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +import { decimalStr, fromWei } from '../utils/Converter'; +import { logGas } from '../utils/Log'; +import { DODOMineV2Context, getDODOMineContext } from '../utils/DODOMineV2Context'; +import { VDODOContext, getVDODOContext } from '../utils/VDODOContext'; +import { assert } from 'chai'; +import { Contract } from 'web3-eth-contract'; +const truffleAssert = require('truffle-assertions'); + +let account0: string; +let account1: string; +let projector: string; +let dodoTeam: string; + +async function init(ctx: DODOMineV2Context): Promise { + projector = ctx.Deployer; + account0 = ctx.SpareAccounts[0]; + account1 = ctx.SpareAccounts[1]; + + //For Project + await ctx.mintTestToken(projector, ctx.REWARD_1, decimalStr("1000000")); + await ctx.mintTestToken(projector, ctx.REWARD_2, decimalStr("1000000")); + + await ctx.approveProxy(account0, ctx.VDODOMine.options.address, ctx.ERC20); + await ctx.approveProxy(account1, ctx.VDODOMine.options.address, ctx.ERC20); +} + +async function initVdodo(ctx: VDODOContext): Promise { + dodoTeam = ctx.Deployer; + await ctx.mintTestToken(account0, decimalStr("10000")); + await ctx.mintTestToken(account1, decimalStr("10000")); + + await ctx.approveProxy(account0); + await ctx.approveProxy(account1); +} + +async function mint(ctx: VDODOContext, user: string, mintAmount: string, superior: string) { + await ctx.VDODO.methods.mint( + mintAmount, + superior + ).send(ctx.sendParam(user)); +} + +async function addRewardToken(ctx: DODOMineV2Context, token: Contract, start: number, end: number, rewardPerBlock: string) { + await ctx.VDODOMine.methods.addRewardToken( + token.options.address, + rewardPerBlock, + start, + end + ).send(ctx.sendParam(projector)); + + let idx = await ctx.VDODOMine.methods.getIdByRewardToken(token.options.address).call(); + let rewardInfo = await ctx.VDODOMine.methods.rewardTokenInfos(idx).call(); + await token.methods.transfer(rewardInfo.rewardVault, decimalStr("10000")).send(ctx.sendParam(projector)); +} + +async function stakeInfo(ctx: DODOMineV2Context, user: string, logInfo?: string) { + console.log(logInfo) + let totalSupply = await ctx.VDODOMine.methods.totalSupply().call(); + let balance = await ctx.VDODOMine.methods.balanceOf(user).call(); + console.log("totalSupply:" + fromWei(totalSupply, "ether") + " balance:" + fromWei(balance, "ether")); +} + +async function vdodoBalance(ctx: VDODOContext, user: string, logInfo?: string) { + console.log(logInfo) + let dodoBalance = await ctx.VDODO.methods.dodoBalanceOf(user).call(); + let availableBalance = await ctx.VDODO.methods.availableBalanceOf(user).call(); + console.log("dodoBalance:" + fromWei(dodoBalance, "ether") + " availableBalance:" + fromWei(availableBalance, "ether")); + return [dodoBalance, availableBalance] +} + +async function getRewardInfo(ctx: DODOMineV2Context, idx: number, user: string, logInfo?: string) { + let VDODOMine = ctx.VDODOMine + let obj = await VDODOMine.methods.rewardTokenInfos(idx).call(); + let curBlock = await ctx.Web3.eth.getBlockNumber(); + console.log(logInfo); + // console.log("Static-Data: rewardToken:" + obj.rewardToken + " rewardVault:" + obj.rewardVault + " rewardPerBlock:" + fromWei(obj.rewardPerBlock, "ether")); + console.log("Dynamic-Data: start:" + obj.startBlock + " end:" + obj.endBlock + " accRewardPerShare:" + fromWei(obj.accRewardPerShare, "ether") + " lastRewardBlock:" + obj.lastRewardBlock + " curBlock:" + curBlock); + var pendingReward = null; + if (user != null) { + pendingReward = await VDODOMine.methods.getPendingReward(user, idx).call(); + console.log("User-pendingReward:" + fromWei(pendingReward, "ether")); + } + return [obj, pendingReward]; +} + +describe("VDODOMine", () => { + let snapshotId: string; + let ctx: DODOMineV2Context; + let ctxVdodo: VDODOContext; + + before(async () => { + ctxVdodo = await getVDODOContext(); + ctx = await getDODOMineContext(ctxVdodo.VDODO.options.address); + await init(ctx); + await initVdodo(ctxVdodo); + await ctxVdodo.VDODO.methods.updateGovernance(ctx.VDODOMine.options.address).send(ctxVdodo.sendParam(ctxVdodo.Deployer)); + }); + + beforeEach(async () => { + snapshotId = await ctx.EVM.snapshot(); + }); + + afterEach(async () => { + await ctx.EVM.reset(snapshotId); + }); + + describe("VDODOMine", () => { + + it("deposit", async () => { + await mint(ctxVdodo, account0, decimalStr("10000"), dodoTeam); + await vdodoBalance(ctxVdodo, account0, "vDODOBalance - before"); + + var curBlock = await ctx.Web3.eth.getBlockNumber(); + await addRewardToken(ctx, ctx.REWARD_1, curBlock + 2, curBlock + 102, decimalStr("10")); + await stakeInfo(ctx, account0, "UserStakeInfo - Before"); + await getRewardInfo(ctx, 0, account0, "UserRewardInfo - Before"); + + //增加区块 + await ctx.increBlock(3); + + await logGas(await ctx.VDODOMine.methods.deposit( + decimalStr("5") + ), ctx.sendParam(account0), "deposit - 0"); + + await logGas(await ctx.VDODOMine.methods.deposit( + decimalStr("5") + ), ctx.sendParam(account0), "deposit - 1"); + + await stakeInfo(ctx, account0, "UserStakeInfo - After"); + let [, pendingReward] = await getRewardInfo(ctx, 0, account0, "UserRewardInfo - After - 1"); + let [, availableBalance] = await vdodoBalance(ctxVdodo, account0, "vDODOBalance - after"); + + assert.equal(pendingReward, decimalStr("10")); + assert.equal(availableBalance, "90063636363636363600"); + }); + + + it("withdraw", async () => { + await mint(ctxVdodo, account0, decimalStr("10000"), dodoTeam); + await vdodoBalance(ctxVdodo, account0, "vDODOBalance - before"); + + var curBlock = await ctx.Web3.eth.getBlockNumber(); + await addRewardToken(ctx, ctx.REWARD_1, curBlock + 2, curBlock + 102, decimalStr("10")); + await stakeInfo(ctx, account0, "UserStakeInfo - Before"); + await getRewardInfo(ctx, 0, account0, "UserRewardInfo - Before"); + + await ctx.increBlock(3); + + await logGas(await ctx.VDODOMine.methods.deposit( + decimalStr("10") + ), ctx.sendParam(account0), "deposit"); + + await ctx.increBlock(3); + + await logGas(await ctx.VDODOMine.methods.withdraw( + decimalStr("5") + ), ctx.sendParam(account0), "withdraw"); + + await stakeInfo(ctx, account0, "UserStakeInfo - After"); + let [, pendingReward] = await getRewardInfo(ctx, 0, account0, "UserRewardInfo - After"); + let [, availableBalance] = await vdodoBalance(ctxVdodo, account0, "vDODOBalance - after"); + + assert.equal(pendingReward, decimalStr("40")); + assert.equal(availableBalance, "95090909090909090900"); + }); + + + it("revert case", async () => { + await mint(ctxVdodo, account0, decimalStr("10000"), dodoTeam); + + var curBlock = await ctx.Web3.eth.getBlockNumber(); + await addRewardToken(ctx, ctx.REWARD_1, curBlock + 2, curBlock + 102, decimalStr("10")); + + //增加区块 + await ctx.increBlock(3); + + await logGas(await ctx.VDODOMine.methods.deposit( + decimalStr("10") + ), ctx.sendParam(account0), "deposit - 0"); + + await truffleAssert.reverts( + ctxVdodo.VDODO.methods.redeem(decimalStr("95"), false).send(ctxVdodo.sendParam(account0)), + "vDODOToken: available amount not enough" + ) + }) + }) +}); diff --git a/test/utils/DODOMineV2Context.ts b/test/utils/DODOMineV2Context.ts index b76179b..5cd1a96 100644 --- a/test/utils/DODOMineV2Context.ts +++ b/test/utils/DODOMineV2Context.ts @@ -26,6 +26,7 @@ export class DODOMineV2Context { //contract ERC20Mine: Contract; + VDODOMine: Contract; //account Deployer: string; @@ -38,7 +39,7 @@ export class DODOMineV2Context { ERC20: Contract; - async init() { + async init(vdodo: string) { this.EVM = new EVM(); this.Web3 = getDefaultWeb3(); @@ -62,6 +63,14 @@ export class DODOMineV2Context { ["REWARD_2 Token", "REWARD_2", 18] ); + if (vdodo != null) { + this.VDODOMine = await contracts.newContract( + contracts.VDODO_MINE, + [vdodo] + ); + await this.VDODOMine.methods.initOwner(this.Deployer).send(this.sendParam(this.Deployer)); + } + this.ERC20Mine = await contracts.newContract( contracts.ERC20_MINE, [this.ERC20.options.address] @@ -69,7 +78,7 @@ export class DODOMineV2Context { await this.ERC20Mine.methods.initOwner(this.Deployer).send(this.sendParam(this.Deployer)); - console.log(log.blueText("[Init ERC20Mine context]")); + console.log(log.blueText("[Init DODOMine context]")); } sendParam(sender, value = "0") { @@ -85,6 +94,12 @@ export class DODOMineV2Context { await token.methods.mint(to, amount).send(this.sendParam(this.Deployer)); } + async increBlock(num: number) { + for (let i = 0; i < num; i++) { + await this.mintTestToken(this.Deployer, this.ERC20, decimalStr("0")); + } + } + async approveProxy(account: string, target: string, token: Contract) { await token.methods .approve(target, MAX_UINT256) @@ -92,8 +107,8 @@ export class DODOMineV2Context { } } -export async function getDODOMineContext(): Promise { +export async function getDODOMineContext(vdodo: string): Promise { var context = new DODOMineV2Context(); - await context.init(); + await context.init(vdodo); return context; } \ No newline at end of file diff --git a/truffle-test.sh b/truffle-test.sh index fc4c4b6..1f3794d 100644 --- a/truffle-test.sh +++ b/truffle-test.sh @@ -50,6 +50,12 @@ if [ "$1"x = "erc20-mine"x ] then truffle test ./test/DODOMineV2/erc20Mine.test.ts fi + +if [ "$1"x = "vdodo-mine"x ] +then + truffle test ./test/DODOMineV2/vDODOMine.test.ts +fi + # if [ "$1"x = "route-incentive"x ] # then # truffle test ./test/Route/Incentive.test.ts