diff --git a/contracts/CrowdPooling/impl/CP.sol b/contracts/CrowdPooling/impl/CP.sol index 5878180..fd123f2 100644 --- a/contracts/CrowdPooling/impl/CP.sol +++ b/contracts/CrowdPooling/impl/CP.sol @@ -33,6 +33,8 @@ contract CP is CPVesting { 6. poolFactory */ + require(addressList.length == 7, "LIST_LENGTH_WRONG"); + initOwner(addressList[0]); _MAINTAINER_ = addressList[1]; _BASE_TOKEN_ = IERC20(addressList[2]); @@ -49,7 +51,7 @@ contract CP is CPVesting { 3. freeze duration */ - require(block.timestamp <= timeLine[0], "TIMELINE_WRONG"); + require(timeLine.length == 4, "LIST_LENGTH_WRONG"); _PHASE_BID_STARTTIME_ = timeLine[0]; _PHASE_BID_ENDTIME_ = _PHASE_BID_STARTTIME_.add(timeLine[1]); @@ -57,26 +59,27 @@ contract CP is CPVesting { _FREEZE_DURATION_ = timeLine[3]; + require(block.timestamp <= _PHASE_BID_STARTTIME_, "TIMELINE_WRONG"); + /* Value List 0. pool quote cap - 1. pool base reserve - 2. owner quote ratio - 3. k - 4 i + 1. owner quote ratio + 2. k + 3. i */ - require(valueList[4] > 0 && valueList[4] <= 10**36, "I_VALUE_WRONG"); - require(valueList[3] <= 10**18, "K_VALUE_WRONG"); - require(valueList[2] <= 10**18, "OWNER_RATIO_WRONG"); + require(valueList.length == 4, "LIST_LENGTH_WRONG"); _POOL_QUOTE_CAP_ = valueList[0]; - _POOL_BASE_RESERVE_ = valueList[1]; - _OWNER_QUOTE_RATIO_ = valueList[2]; + _OWNER_QUOTE_RATIO_ = valueList[1]; _K_ = valueList[2]; _I_ = valueList[3]; + require(_I_ > 0 && _I_ <= 10**36, "I_VALUE_WRONG"); + require(_K_ <= 10**18, "K_VALUE_WRONG"); + require(_OWNER_QUOTE_RATIO_ <= 10**18, "OWNER_RATIO_WRONG"); + _TOTAL_BASE_ = _BASE_TOKEN_.balanceOf(address(this)); - require(_TOTAL_BASE_ >= _POOL_BASE_RESERVE_, "BASE_TOKEN_NOT_ENOUGH"); } } diff --git a/contracts/CrowdPooling/impl/CPFunding.sol b/contracts/CrowdPooling/impl/CPFunding.sol index a9b9604..6d5e723 100644 --- a/contracts/CrowdPooling/impl/CPFunding.sol +++ b/contracts/CrowdPooling/impl/CPFunding.sol @@ -55,8 +55,7 @@ contract CPFunding is CPStorage { // ============ SETTLEMENT ============ function settle() external phaseSettlement preventReentrant { - require(!_SETTLED_, "ALREADY_SETTLED"); - _SETTLED_ = true; + _settle(); (uint256 poolBase, uint256 poolQuote, uint256 ownerQuote) = getSettleResult(); _UNUSED_QUOTE_ = _QUOTE_TOKEN_.balanceOf(address(this)).sub(poolQuote).sub(ownerQuote); @@ -80,15 +79,17 @@ contract CPFunding is CPStorage { _poolQuoteToken = address(_QUOTE_TOKEN_); _poolI = 1; } else if (poolQuote < baseDepth) { + // poolI up round _poolBaseToken = address(_BASE_TOKEN_); _poolQuoteToken = address(_QUOTE_TOKEN_); - uint256 ratio = DecimalMath.ONE.sub(DecimalMath.divFloor(poolQuote, baseDepth)); + uint256 ratio = DecimalMath.ONE.sub(DecimalMath.divCeil(poolQuote, baseDepth)); _poolI = avgPrice.mul(ratio).mul(ratio).divCeil(DecimalMath.ONE2); } else if (poolQuote > baseDepth) { + // poolI down round _poolBaseToken = address(_QUOTE_TOKEN_); _poolQuoteToken = address(_BASE_TOKEN_); uint256 ratio = DecimalMath.ONE.sub(DecimalMath.divFloor(baseDepth, poolQuote)); - _poolI = DecimalMath.reciprocalFloor(avgPrice).mul(ratio).mul(ratio).divCeil( + _poolI = DecimalMath.reciprocalFloor(avgPrice).mul(ratio).mul(ratio).div( DecimalMath.ONE2 ); } @@ -96,11 +97,11 @@ contract CPFunding is CPStorage { address(this), _poolBaseToken, _poolQuoteToken, - 3e15, - 0, + 3e15, // 0.3% _poolI, DecimalMath.ONE ); + _AVG_SETTLED_PRICE_ = avgPrice; } _transferBaseOut(_POOL_, poolBase); @@ -112,16 +113,18 @@ contract CPFunding is CPStorage { // in case something wrong with base token contract function emergencySettle() external phaseSettlement preventReentrant { - require(!_SETTLED_, "ALREADY_SETTLED"); - require( - block.timestamp > _PHASE_CALM_ENDTIME_.add(_SETTLEMENT_EXPIRED_TIME_), - "NOT_EMERGENCY" - ); - _SETTLED_ = true; + require(block.timestamp > _PHASE_CALM_ENDTIME_.add(_SETTLEMENT_EXPIRE_), "NOT_EMERGENCY"); + _settle(); _UNUSED_QUOTE_ = _QUOTE_TOKEN_.balanceOf(address(this)); _UNUSED_BASE_ = _BASE_TOKEN_.balanceOf(address(this)); } + function _settle() internal { + require(!_SETTLED_, "ALREADY_SETTLED"); + _SETTLED_ = true; + _SETTLED_TIME_ = block.timestamp; + } + // ============ Pricing ============ function getSettleResult() @@ -139,9 +142,6 @@ contract CPFunding is CPStorage { } (uint256 soldBase, ) = PMMPricing.sellQuoteToken(_getPMMState(), poolQuote); poolBase = _TOTAL_BASE_.sub(soldBase); - if (poolBase < _POOL_BASE_RESERVE_) { - poolBase = _POOL_BASE_RESERVE_; - } ownerQuote = DecimalMath.mulFloor(poolQuote, _OWNER_QUOTE_RATIO_); poolQuote = poolQuote.sub(ownerQuote); } @@ -156,6 +156,16 @@ contract CPFunding is CPStorage { state.R = PMMPricing.RState.ONE; } + function getExpectedAvgPrice() external view returns (uint256) { + require(!_SETTLED_, "ALREADY_SETTLED"); + (uint256 poolBase, uint256 poolQuote, uint256 ownerQuote) = getSettleResult(); + return + DecimalMath.divCeil( + poolQuote.add(ownerQuote), + _BASE_TOKEN_.balanceOf(address(this)).sub(poolBase) + ); + } + // ============ Asset In ============ function _getQuoteInput() internal view returns (uint256 input) { @@ -184,4 +194,10 @@ contract CPFunding is CPStorage { _QUOTE_TOKEN_.safeTransfer(to, amount); } } + + // ============ Asset Out ============ + + function getShares(address user) external view returns (uint256) { + return _SHARES_[user]; + } } diff --git a/contracts/CrowdPooling/impl/CPStorage.sol b/contracts/CrowdPooling/impl/CPStorage.sol index 13dc195..2920c83 100644 --- a/contracts/CrowdPooling/impl/CPStorage.sol +++ b/contracts/CrowdPooling/impl/CPStorage.sol @@ -18,15 +18,16 @@ import {IERC20} from "../../intf/IERC20.sol"; contract CPStorage is InitializableOwnable, ReentrancyGuard { using SafeMath for uint256; - uint256 internal constant _SETTLEMENT_EXPIRED_TIME_ = 86400 * 7; + uint256 internal constant _SETTLEMENT_EXPIRE_ = 86400 * 7; // ============ Timeline ============ - uint256 _PHASE_BID_STARTTIME_; - uint256 _PHASE_BID_ENDTIME_; - uint256 _PHASE_CALM_ENDTIME_; - uint256 _FREEZE_DURATION_; - bool _SETTLED_; + uint256 public _PHASE_BID_STARTTIME_; + uint256 public _PHASE_BID_ENDTIME_; + uint256 public _PHASE_CALM_ENDTIME_; + uint256 public _SETTLED_TIME_; + uint256 public _FREEZE_DURATION_; + bool public _SETTLED_; // ============ Core Address ============ @@ -35,11 +36,10 @@ contract CPStorage is InitializableOwnable, ReentrancyGuard { // ============ Distribution Parameters ============ - uint256 _OWNER_QUOTE_RATIO_; // 抽取一部分 - uint256 _TOTAL_BASE_; + uint256 public _OWNER_QUOTE_RATIO_; // 抽取一部分 + uint256 public _TOTAL_BASE_; - uint256 _POOL_QUOTE_CAP_; - uint256 _POOL_BASE_RESERVE_; + uint256 public _POOL_QUOTE_CAP_; // ============ Settlement ============ @@ -53,8 +53,9 @@ contract CPStorage is InitializableOwnable, ReentrancyGuard { mapping(address => bool) internal _QUOTE_CLAIMED_; mapping(address => bool) internal _BASE_CLAIMED_; - address _POOL_FACTORY_; - address _POOL_; + address public _POOL_FACTORY_; + address public _POOL_; + uint256 public _AVG_SETTLED_PRICE_; // ============ Advanced Control ============ diff --git a/contracts/CrowdPooling/impl/CPVesting.sol b/contracts/CrowdPooling/impl/CPVesting.sol index ff8ace0..907f06e 100644 --- a/contracts/CrowdPooling/impl/CPVesting.sol +++ b/contracts/CrowdPooling/impl/CPVesting.sol @@ -32,7 +32,7 @@ contract CPVesting is CPFunding { } modifier afterFreeze() { - require(block.timestamp >= _PHASE_CALM_ENDTIME_.add(_FREEZE_DURATION_), "FREEZED"); + require(block.timestamp >= _SETTLED_TIME_.add(_FREEZE_DURATION_), "FREEZED"); _; } diff --git a/contracts/Factory/UnownedDVMFactory.sol b/contracts/Factory/UnownedDVMFactory.sol index a8ddd97..d99e82a 100644 --- a/contracts/Factory/UnownedDVMFactory.sol +++ b/contracts/Factory/UnownedDVMFactory.sol @@ -21,7 +21,6 @@ interface IUnownedDVMFactory { address baseToken, address quoteToken, uint256 lpFeeRate, - uint256 mtFeeRate, uint256 i, uint256 k ) external returns (address newVendingMachine); diff --git a/test/CrowdPooling/CPBid.test.ts b/test/CrowdPooling/CPBid.test.ts index 5ef337a..57ddb91 100644 --- a/test/CrowdPooling/CPBid.test.ts +++ b/test/CrowdPooling/CPBid.test.ts @@ -8,10 +8,10 @@ // import * as assert from 'assert'; import { decimalStr } from '../utils/Converter'; -// import { logGas } from '../utils/Log'; +import { logGas } from '../utils/Log'; import { CPContext, CPContextInitConfig } from '../utils/CrowdPoolingContext'; -// import { assert } from 'chai'; import BigNumber from 'bignumber.js'; +import { assert } from 'chai'; const truffleAssert = require('truffle-assertions'); let bidder1: string; @@ -32,7 +32,6 @@ describe("Funding", () => { before(async () => { config = { totalBase: decimalStr("10000"), - poolBaseReserve: decimalStr("5000"), poolQuoteCap: decimalStr("50000"), ownerQuoteRatio: decimalStr("0.1"), k: decimalStr("0.5"), @@ -59,7 +58,23 @@ describe("Funding", () => { it("bid", async () => { await ctx.QUOTE.methods.transfer(ctx.CP.options.address, decimalStr("100")).send(ctx.sendParam(bidder1)) - await ctx.CP.methods.bid(bidder1).send(ctx.sendParam(bidder1)) + await logGas(ctx.CP.methods.bid(bidder1), ctx.sendParam(bidder1), "bid") + assert.equal(await ctx.CP.methods.getShares(bidder1).call(), decimalStr("99.9")) + assert.equal(await ctx.CP.methods._TOTAL_SHARES_().call(), decimalStr("99.9")) + assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), decimalStr("0.1")) + + await ctx.QUOTE.methods.transfer(ctx.CP.options.address, decimalStr("50")).send(ctx.sendParam(bidder2)) + await ctx.CP.methods.bid(bidder2).send(ctx.sendParam(bidder2)) + assert.equal(await ctx.CP.methods.getShares(bidder2).call(), decimalStr("49.95")) + assert.equal(await ctx.CP.methods._TOTAL_SHARES_().call(), decimalStr("149.85")) + assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), decimalStr("0.15")) + + await ctx.EVM.increaseTime(86400) + await logGas(ctx.CP.methods.cancel(bidder1, decimalStr("20")), ctx.sendParam(bidder1), "cancel") + assert.equal(await ctx.CP.methods.getShares(bidder1).call(), decimalStr("79.9")) + assert.equal(await ctx.CP.methods._TOTAL_SHARES_().call(), decimalStr("129.85")) + assert.equal(await ctx.QUOTE.methods.balanceOf(bidder1).call(), decimalStr("920")) }) + }) }) \ No newline at end of file diff --git a/test/CrowdPooling/CPSettle.test.ts b/test/CrowdPooling/CPSettle.test.ts new file mode 100644 index 0000000..db0fb81 --- /dev/null +++ b/test/CrowdPooling/CPSettle.test.ts @@ -0,0 +1,114 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +import { decimalStr } from '../utils/Converter'; +import { logGas } from '../utils/Log'; +import { CPContext, CPContextInitConfig } from '../utils/CrowdPoolingContext'; +import BigNumber from 'bignumber.js'; +import { assert } from 'chai'; +import { DVM_NAME, getContractWithAddress, UNOWNED_DVM_FACTORY_NAME } from '../utils/Contracts'; +const truffleAssert = require('truffle-assertions'); + +let bidder1: string; +let bidder2: string; +let config: CPContextInitConfig + +async function init(ctx: CPContext): Promise { + bidder1 = ctx.SpareAccounts[1] + bidder2 = ctx.SpareAccounts[2] + await ctx.QUOTE.methods.mint(bidder1, decimalStr("1000")).send(ctx.sendParam(ctx.Deployer)) + await ctx.QUOTE.methods.mint(bidder2, decimalStr("1000")).send(ctx.sendParam(ctx.Deployer)) +} + +describe("Funding", () => { + let snapshotId: string; + let ctx: CPContext; + + before(async () => { + config = { + totalBase: decimalStr("10000"), + poolQuoteCap: decimalStr("50000"), + ownerQuoteRatio: decimalStr("0.1"), + k: decimalStr("0.5"), + i: decimalStr("10"), + lpFeeRate: decimalStr("0.002"), + bidDuration: new BigNumber(86400), + calmDuration: new BigNumber(86400), + freezeDuration: new BigNumber(86400), + } + ctx = new CPContext(); + await ctx.init(config); + await init(ctx); + }); + + beforeEach(async () => { + snapshotId = await ctx.EVM.snapshot(); + }); + + afterEach(async () => { + await ctx.EVM.reset(snapshotId); + }); + + describe("settle", () => { + + it("bid not exceed cap", async () => { + await ctx.QUOTE.methods.transfer(ctx.CP.options.address, decimalStr("1000")).send(ctx.sendParam(bidder1)) + await ctx.CP.methods.bid(bidder1).send(ctx.sendParam(bidder1)) + + await ctx.EVM.increaseTime(86400 * 2) + await truffleAssert.reverts(ctx.CP.methods.bid(bidder1).send(ctx.sendParam(bidder1)), "NOT_PHASE_BID") + + await logGas(ctx.CP.methods.settle(), ctx.sendParam(ctx.Deployer), "settle") + assert.equal(await ctx.CP.methods._SETTLED_().call(), true) + + var poolAddress = await ctx.CP.methods._POOL_().call() + var pool = getContractWithAddress(DVM_NAME, poolAddress) + + assert.equal(await pool.methods.getMidPrice().call(), "10050199494025273102") + assert.equal(await ctx.CP.methods._AVG_SETTLED_PRICE_().call(), "10050199494025273136") + + assert.equal(await ctx.CP.methods._UNUSED_QUOTE_().call(), "0") + assert.equal(await ctx.CP.methods._UNUSED_BASE_().call(), "99401011949453729399") + + assert.equal(await ctx.BASE.methods.balanceOf(ctx.Deployer).call(), "0") + assert.equal(await ctx.BASE.methods.balanceOf(poolAddress).call(), "9900598988050546270601") + assert.equal(await ctx.BASE.methods.balanceOf(ctx.CP.options.address).call(), "99401011949453729399") + + assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.Deployer).call(), decimalStr("99.9")) + assert.equal(await ctx.QUOTE.methods.balanceOf(poolAddress).call(), decimalStr("899.1")) + assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.CP.options.address).call(), "0") + }) + + it("bid exceed cap", async () => { + await ctx.QUOTE.methods.mint(ctx.CP.options.address, decimalStr("100000")).send(ctx.sendParam(ctx.Deployer)) + await ctx.CP.methods.bid(bidder1).send(ctx.sendParam(bidder1)) + + await ctx.EVM.increaseTime(86400 * 2) + + await logGas(ctx.CP.methods.settle(), ctx.sendParam(ctx.Deployer), "settle") + assert.equal(await ctx.CP.methods._SETTLED_().call(), true) + + var poolAddress = await ctx.CP.methods._POOL_().call() + var pool = getContractWithAddress(DVM_NAME, poolAddress) + + assert.equal(await pool.methods.getMidPrice().call(), "13090169943749474216") + assert.equal(await ctx.CP.methods._AVG_SETTLED_PRICE_().call(), "13090169943749474242") + + assert.equal(await ctx.CP.methods._UNUSED_QUOTE_().call(), decimalStr("49900")) + assert.equal(await ctx.CP.methods._UNUSED_BASE_().call(), "3819660112501051517955") + + assert.equal(await ctx.BASE.methods.balanceOf(ctx.Deployer).call(), "0") + assert.equal(await ctx.BASE.methods.balanceOf(poolAddress).call(), "6180339887498948482045") + assert.equal(await ctx.BASE.methods.balanceOf(ctx.CP.options.address).call(), "3819660112501051517955") + + assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.Deployer).call(), decimalStr("5000")) + assert.equal(await ctx.QUOTE.methods.balanceOf(poolAddress).call(), decimalStr("45000")) + assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.CP.options.address).call(), decimalStr("49900")) + }) + + }) +}) \ No newline at end of file diff --git a/test/CrowdPooling/CPSettleReversePool.test.ts b/test/CrowdPooling/CPSettleReversePool.test.ts new file mode 100644 index 0000000..63debf5 --- /dev/null +++ b/test/CrowdPooling/CPSettleReversePool.test.ts @@ -0,0 +1,87 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +import { decimalStr } from '../utils/Converter'; +import { logGas } from '../utils/Log'; +import { CPContext, CPContextInitConfig } from '../utils/CrowdPoolingContext'; +import BigNumber from 'bignumber.js'; +// import { assert } from 'chai'; +import { DVM_NAME, getContractWithAddress, UNOWNED_DVM_FACTORY_NAME } from '../utils/Contracts'; +import { assert } from 'chai'; +const truffleAssert = require('truffle-assertions'); + +let bidder1: string; +let bidder2: string; +let config: CPContextInitConfig + +async function init(ctx: CPContext): Promise { + bidder1 = ctx.SpareAccounts[1] + bidder2 = ctx.SpareAccounts[2] + await ctx.QUOTE.methods.mint(bidder1, decimalStr("1000")).send(ctx.sendParam(ctx.Deployer)) + await ctx.QUOTE.methods.mint(bidder2, decimalStr("1000")).send(ctx.sendParam(ctx.Deployer)) +} + +describe("Funding", () => { + let snapshotId: string; + let ctx: CPContext; + + before(async () => { + config = { + totalBase: decimalStr("10000"), + poolQuoteCap: decimalStr("100000"), + ownerQuoteRatio: decimalStr("0.1"), + k: decimalStr("0.1"), + i: decimalStr("10"), + lpFeeRate: decimalStr("0.002"), + bidDuration: new BigNumber(86400), + calmDuration: new BigNumber(86400), + freezeDuration: new BigNumber(86400), + } + ctx = new CPContext(); + await ctx.init(config); + await init(ctx); + }); + + beforeEach(async () => { + snapshotId = await ctx.EVM.snapshot(); + }); + + afterEach(async () => { + await ctx.EVM.reset(snapshotId); + }); + + describe("settle", () => { + + it("bid not exceed cap", async () => { + await ctx.QUOTE.methods.mint(ctx.CP.options.address, decimalStr("100000")).send(ctx.sendParam(ctx.Deployer)) + await ctx.CP.methods.bid(bidder1).send(ctx.sendParam(bidder1)) + + await ctx.EVM.increaseTime(86400 * 2) + + await logGas(ctx.CP.methods.settle(), ctx.sendParam(ctx.Deployer), "settle") + assert.equal(await ctx.CP.methods._SETTLED_().call(), true) + + var poolAddress = await ctx.CP.methods._POOL_().call() + var pool = getContractWithAddress(DVM_NAME, poolAddress) + + assert.equal(await pool.methods.getMidPrice().call(), "76012678448689469") + assert.equal(await ctx.CP.methods._AVG_SETTLED_PRICE_().call(), "13155700080678329720") + + assert.equal(await ctx.CP.methods._UNUSED_QUOTE_().call(), "0") + assert.equal(await ctx.CP.methods._UNUSED_BASE_().call(), "7593666577024078089065") + + assert.equal(await ctx.BASE.methods.balanceOf(ctx.Deployer).call(), "0") + assert.equal(await ctx.BASE.methods.balanceOf(poolAddress).call(), "2406333422975921910935") + assert.equal(await ctx.BASE.methods.balanceOf(ctx.CP.options.address).call(), "7593666577024078089065") + + assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.Deployer).call(), decimalStr("9990")) + assert.equal(await ctx.QUOTE.methods.balanceOf(poolAddress).call(), decimalStr("89910")) + assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.CP.options.address).call(), "0") + }) + + }) +}) \ No newline at end of file diff --git a/test/CrowdPooling/CPVesting.test.ts b/test/CrowdPooling/CPVesting.test.ts new file mode 100644 index 0000000..d6d2c5e --- /dev/null +++ b/test/CrowdPooling/CPVesting.test.ts @@ -0,0 +1,132 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +import { decimalStr, MAX_UINT256 } from '../utils/Converter'; +import { logGas } from '../utils/Log'; +import { CPContext, CPContextInitConfig } from '../utils/CrowdPoolingContext'; +import BigNumber from 'bignumber.js'; +import { assert } from 'chai'; +import { DVM_NAME, getContractWithAddress } from '../utils/Contracts'; +import { Contract } from 'web3-eth-contract'; +const truffleAssert = require('truffle-assertions'); + +let bidder1: string; +let bidder2: string; +let config: CPContextInitConfig + +async function init(ctx: CPContext): Promise { + bidder1 = ctx.SpareAccounts[1] + bidder2 = ctx.SpareAccounts[2] +} + +describe("Funding", () => { + let snapshotId: string; + let ctx: CPContext; + + before(async () => { + config = { + totalBase: decimalStr("10000"), + poolQuoteCap: decimalStr("50000"), + ownerQuoteRatio: decimalStr("0.1"), + k: decimalStr("0.5"), + i: decimalStr("10"), + lpFeeRate: decimalStr("0.002"), + bidDuration: new BigNumber(86400), + calmDuration: new BigNumber(86400), + freezeDuration: new BigNumber(86400), + } + ctx = new CPContext(); + await ctx.init(config); + await init(ctx); + }); + + beforeEach(async () => { + snapshotId = await ctx.EVM.snapshot(); + }); + + afterEach(async () => { + await ctx.EVM.reset(snapshotId); + }); + + describe("settle", () => { + + it("bid not exceed cap", async () => { + + await ctx.QUOTE.methods.mint(ctx.CP.options.address, decimalStr("10000")).send(ctx.sendParam(ctx.Deployer)) + await ctx.CP.methods.bid(bidder1).send(ctx.sendParam(bidder1)) + await ctx.QUOTE.methods.mint(ctx.CP.options.address, decimalStr("20000")).send(ctx.sendParam(ctx.Deployer)) + await ctx.CP.methods.bid(bidder2).send(ctx.sendParam(bidder2)) + + await ctx.EVM.increaseTime(86400 * 2) + + await logGas(ctx.CP.methods.settle(), ctx.sendParam(ctx.Deployer), "settle") + + assert.equal(await ctx.BASE.methods.balanceOf(ctx.CP.options.address).call(), "2557555139280633184959") + assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.CP.options.address).call(), "0") + + await ctx.CP.methods.claimBase().send(ctx.sendParam(bidder1)) + await ctx.CP.methods.claimQuote().send(ctx.sendParam(bidder1)) + assert.equal(await ctx.BASE.methods.balanceOf(bidder1).call(), "852518379760211061653") + assert.equal(await ctx.QUOTE.methods.balanceOf(bidder1).call(), "0") + + await ctx.CP.methods.claimBase().send(ctx.sendParam(bidder2)) + await ctx.CP.methods.claimQuote().send(ctx.sendParam(bidder2)) + assert.equal(await ctx.BASE.methods.balanceOf(bidder2).call(), "1705036759520422123306") + assert.equal(await ctx.QUOTE.methods.balanceOf(bidder2).call(), "0") + + }) + + it("bid exceed cap", async () => { + await ctx.QUOTE.methods.mint(ctx.CP.options.address, decimalStr("30000")).send(ctx.sendParam(ctx.Deployer)) + await ctx.CP.methods.bid(bidder1).send(ctx.sendParam(bidder1)) + await ctx.QUOTE.methods.mint(ctx.CP.options.address, decimalStr("60000")).send(ctx.sendParam(ctx.Deployer)) + await ctx.CP.methods.bid(bidder2).send(ctx.sendParam(bidder2)) + + await ctx.EVM.increaseTime(86400 * 2) + + await logGas(ctx.CP.methods.settle(), ctx.sendParam(ctx.Deployer), "settle") + + assert.equal(await ctx.BASE.methods.balanceOf(ctx.CP.options.address).call(), "3819660112501051517955") + assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.CP.options.address).call(), decimalStr("39910")) + + await ctx.CP.methods.claimBase().send(ctx.sendParam(bidder1)) + await ctx.CP.methods.claimQuote().send(ctx.sendParam(bidder1)) + assert.equal(await ctx.BASE.methods.balanceOf(bidder1).call(), "1273220037500350505985") + assert.equal(await ctx.QUOTE.methods.balanceOf(bidder1).call(), "13303333333333333333333") + + await ctx.CP.methods.claimBase().send(ctx.sendParam(bidder2)) + await ctx.CP.methods.claimQuote().send(ctx.sendParam(bidder2)) + assert.equal(await ctx.BASE.methods.balanceOf(bidder2).call(), "2546440075000701011970") + assert.equal(await ctx.QUOTE.methods.balanceOf(bidder2).call(), "26606666666666666666666") + }) + + it("withdraw lp token", async () => { + await ctx.QUOTE.methods.mint(ctx.CP.options.address, decimalStr("30000")).send(ctx.sendParam(ctx.Deployer)) + await ctx.CP.methods.bid(bidder1).send(ctx.sendParam(bidder1)) + await ctx.QUOTE.methods.mint(ctx.CP.options.address, decimalStr("60000")).send(ctx.sendParam(ctx.Deployer)) + await ctx.CP.methods.bid(bidder2).send(ctx.sendParam(bidder2)) + + await ctx.EVM.increaseTime(86400 * 2) + await logGas(ctx.CP.methods.settle(), ctx.sendParam(ctx.Deployer), "settle") + await truffleAssert.reverts(ctx.CP.methods.claimLPToken().send(ctx.sendParam(ctx.Deployer)), "FREEZED") + + await ctx.EVM.increaseTime(86400) + await ctx.CP.methods.claimLPToken().send(ctx.sendParam(ctx.Deployer)) + + var poolAddress = await ctx.CP.methods._POOL_().call() + var pool = getContractWithAddress(DVM_NAME, poolAddress) + + await pool.methods.sellShares("6180339887498948482045", bidder1, 0, 0, "0x", MAX_UINT256).send(ctx.sendParam(ctx.Deployer)) + assert.equal(await ctx.BASE.methods.balanceOf(bidder1).call(), "6180339887498948482045") + assert.equal(await ctx.QUOTE.methods.balanceOf(bidder1).call(), "45000000000000000000000") + + assert.equal(await ctx.BASE.methods.balanceOf(poolAddress).call(), "0") + assert.equal(await ctx.QUOTE.methods.balanceOf(poolAddress).call(), "0") + }) + + }) +}) \ No newline at end of file diff --git a/test/utils/CrowdPoolingContext.ts b/test/utils/CrowdPoolingContext.ts index 1d9784e..2c2aed2 100644 --- a/test/utils/CrowdPoolingContext.ts +++ b/test/utils/CrowdPoolingContext.ts @@ -21,7 +21,6 @@ BigNumber.config({ export interface CPContextInitConfig { totalBase: string; - poolBaseReserve: string; poolQuoteCap: string; ownerQuoteRatio: string; k: string; @@ -105,7 +104,6 @@ export class CPContext { ], [ config.poolQuoteCap, - config.poolBaseReserve, config.ownerQuoteRatio, config.k, config.i