@gooddollar/goodcontracts
Version:
GoodDollar Contracts
265 lines (245 loc) • 10.7 kB
JavaScript
const SimpleDAIStaking = artifacts.require("SimpleDAIStaking");
const DAIMock = artifacts.require("DAIMock");
const cDAIMock = artifacts.require("cDAIMock");
const GoodReserve = artifacts.require("GoodReserveCDai");
const MarketMaker = artifacts.require("GoodMarketMaker");
const GoodDollar = artifacts.require("GoodDollar");
const ContributionCalculation = artifacts.require("ContributionCalculation");
const SchemeRegistrar = artifacts.require("SchemeRegistrar");
const AbsoluteVote = artifacts.require("AbsoluteVote");
const SetMarketMaker = artifacts.require("SetMarketMaker");
const SetBlockInterval = artifacts.require("SetBlockInterval");
const SetContributionAddress = artifacts.require("SetContributionAddress");
const AddMinter = artifacts.require("AddMinter");
const fse = require("fs-extra");
const BN = web3.utils.BN;
export const NULL_ADDRESS = "0x0000000000000000000000000000000000000000";
export const NULL_HASH =
"0x0000000000000000000000000000000000000000000000000000000000000000";
const NETWORK = "test";
async function proposeAndRegister(
addr,
registrar,
proposalId,
absoluteVote,
avatarAddress,
fnd
) {
const transaction = await registrar.proposeScheme(
avatarAddress,
addr,
NULL_HASH,
"0x00000010",
NULL_HASH
);
proposalId = transaction.logs[0].args._proposalId;
const voteResult = await absoluteVote.vote(proposalId, 1, 0, fnd);
return voteResult.logs.some(e => e.event === "ExecuteProposal");
}
contract("GoodCDaiReserve - network e2e tests", ([founder, staker]) => {
let dai, cDAI, goodReserve, goodDollar, marketMaker, contribution;
let avatarAddress,
registrar,
absoluteVote,
proposalId,
setMarketMaker,
setBlockInterval,
setContributionAddress,
addMinter;
before(async function() {
let network = process.env.NETWORK;
if (network === "tdd") {
this.skip();
}
const staking_file = await fse.readFile("releases/deployment.json", "utf8");
const dao_file = await fse.readFile("../releases/deployment.json", "utf8");
const staking_deployment = await JSON.parse(staking_file);
const dao_deployment = await JSON.parse(dao_file);
const staking_addresses = staking_deployment[NETWORK];
const dao_addresses = dao_deployment[NETWORK];
avatarAddress = dao_addresses.Avatar;
dai = await DAIMock.at(staking_addresses.DAI);
cDAI = await cDAIMock.at(staking_addresses.cDAI);
goodReserve = await GoodReserve.at(staking_addresses.Reserve);
marketMaker = await MarketMaker.at(staking_addresses.MarketMaker);
contribution = await ContributionCalculation.at(staking_addresses.Contribution);
goodDollar = await GoodDollar.at(dao_addresses.GoodDollar);
registrar = await SchemeRegistrar.at(dao_addresses.SchemeRegistrar);
absoluteVote = await AbsoluteVote.at(dao_addresses.AbsoluteVote);
// schemes
setMarketMaker = await SetMarketMaker.new(
avatarAddress,
goodReserve.address,
marketMaker.address
);
setBlockInterval = await SetBlockInterval.new(
avatarAddress,
goodReserve.address,
5759
);
setContributionAddress = await SetContributionAddress.new(
avatarAddress,
goodReserve.address,
contribution.address
);
addMinter = await AddMinter.new(avatarAddress, goodReserve.address);
await proposeAndRegister(
addMinter.address,
registrar,
proposalId,
absoluteVote,
avatarAddress,
founder
);
await addMinter.addMinter();
});
it("should not set the marketmaker", async () => {
let error = await setMarketMaker.setMarketMaker().catch(e => e);
expect(error.message).not.to.be.empty;
});
it("should not set the block interval", async () => {
let error = await setBlockInterval.setBlockInterval().catch(e => e);
expect(error.message).not.to.be.empty;
});
it("should not set the contribution", async () => {
let error = await setContributionAddress.setContributionAddress().catch(e => e);
expect(error.message).not.to.be.empty;
});
it("should be able to set the marketmaker", async () => {
const executeProposalEventExists = await proposeAndRegister(
setMarketMaker.address,
registrar,
proposalId,
absoluteVote,
avatarAddress,
founder
);
// Verifies that the ExecuteProposal event has been emitted
expect(executeProposalEventExists).to.be.true;
await setMarketMaker.setMarketMaker();
const marketMaker2 = await goodReserve.marketMaker();
expect(marketMaker2).to.be.equal(marketMaker.address);
});
it("should be able to set the blockInterval", async () => {
const executeProposalEventExists = await proposeAndRegister(
setBlockInterval.address,
registrar,
proposalId,
absoluteVote,
avatarAddress,
founder
);
// Verifies that the ExecuteProposal event has been emitted
expect(executeProposalEventExists).to.be.true;
await setBlockInterval.setBlockInterval();
const blockInterval = await goodReserve.blockInterval();
expect(blockInterval.toString()).to.be.equal("5759");
});
it("should be able to set the contribution address", async () => {
const executeProposalEventExists = await proposeAndRegister(
setContributionAddress.address,
registrar,
proposalId,
absoluteVote,
avatarAddress,
founder
);
// Verifies that the ExecuteProposal event has been emitted
expect(executeProposalEventExists).to.be.true;
await setContributionAddress.setContributionAddress();
const contributionAddressT = await goodReserve.contribution();
expect(contributionAddressT).to.be.equal(contribution.address);
});
it("should returned fixed 0.005 market price", async () => {
const gdPrice = await goodReserve.currentPrice(cDAI.address);
const cdaiWorthInGD = gdPrice.mul(new BN("100000000", 10));
const gdFloatPrice = gdPrice.toNumber() / 10 ** 8; //cdai 8 decimals
expect(gdFloatPrice).to.be.equal(0.005);
expect(cdaiWorthInGD.toString()).to.be.equal("50000000000000"); //in 8 decimals precision
expect(cdaiWorthInGD.toNumber() / 10 ** 8).to.be.equal(500000);
});
it("should be able to buy gd with cDAI and reserve should be correct", async () => {
let amount = 1e8;
await dai.mint(web3.utils.toWei("100", "ether"));
dai.approve(cDAI.address, web3.utils.toWei("100", "ether"));
await cDAI.mint(web3.utils.toWei("100", "ether"));
let reserveToken = await marketMaker.reserveTokens(cDAI.address);
let reserveBalanceBefore = reserveToken.reserveSupply;
const cDAIBalanceReserveBefore = await cDAI.balanceOf(goodReserve.address);
await cDAI.approve(goodReserve.address, amount);
await goodReserve.buy(cDAI.address, amount, 0);
reserveToken = await marketMaker.reserveTokens(cDAI.address);
let reserveBalanceAfter = reserveToken.reserveSupply;
const cDAIBalanceReserveAfter = await cDAI.balanceOf(goodReserve.address);
expect((cDAIBalanceReserveAfter - cDAIBalanceReserveBefore).toString()).to.be.equal(
amount.toString()
);
expect((reserveBalanceAfter - reserveBalanceBefore).toString()).to.be.equal(
amount.toString()
);
});
it("should be able to buy gd with cDAI and the total gd should be increased", async () => {
let amount = 1e8;
await dai.mint(web3.utils.toWei("100", "ether"));
dai.approve(cDAI.address, web3.utils.toWei("100", "ether"));
await cDAI.mint(web3.utils.toWei("100", "ether"));
let reserveToken = await marketMaker.reserveTokens(cDAI.address);
let gdSupplyBefore = reserveToken.gdSupply;
await cDAI.approve(goodReserve.address, amount);
await goodReserve.buy(cDAI.address, amount, 0);
reserveToken = await marketMaker.reserveTokens(cDAI.address);
let gdSupplyAfter = reserveToken.gdSupply;
expect(gdSupplyAfter.gt(gdSupplyBefore)).to.be.true;
});
it("should be able to retain the precision when buying a low quantity of tokens", async () => {
let amount = 1e8;
await dai.mint(web3.utils.toWei("100", "ether"));
dai.approve(cDAI.address, web3.utils.toWei("100", "ether"));
await cDAI.mint(web3.utils.toWei("100", "ether"));
let reserveToken = await marketMaker.reserveTokens(cDAI.address);
const priceBefore = await goodReserve.currentPrice(cDAI.address);
await cDAI.approve(goodReserve.address, amount);
await goodReserve.buy(cDAI.address, amount, 0);
reserveToken = await marketMaker.reserveTokens(cDAI.address);
const priceAfter = await goodReserve.currentPrice(cDAI.address);
expect(Math.floor(priceAfter.toNumber() / 100).toString()).to.be.equal(
Math.floor(priceBefore.toNumber() / 100).toString()
);
});
it("should be able to sell gd to cDAI and reserve should be correct", async () => {
let reserveToken = await marketMaker.reserveTokens(cDAI.address);
let reserveBalance = reserveToken.reserveSupply.toNumber();
let supply = reserveToken.gdSupply.toNumber();
let amount = 1e4;
const cDAIBalanceBefore = await cDAI.balanceOf(founder);
const cDAIBalanceReserveBefore = await cDAI.balanceOf(goodReserve.address);
await goodDollar.approve(goodReserve.address, amount);
await goodReserve.sell(cDAI.address, amount, 0);
const cDAIBalanceAfter = await cDAI.balanceOf(founder);
const cDAIBalanceReserveAfter = await cDAI.balanceOf(goodReserve.address);
// return = reserveBalance * (1 - (1 - sellAmount / supply) ^ (1000000 / reserveRatio))
// reserve ratio is 100% so:
// return = reserve balance * (1 - (1 - sellAmount / supply))
// the contribution ratio is 20%
let expected = reserveBalance * (1 - (1 - amount / supply));
expected = Math.ceil(expected - 0.2 * expected);
expect(Math.floor((cDAIBalanceAfter.toNumber() - cDAIBalanceBefore.toNumber()) / 10 ** 8)).to.be.equal(
Math.floor(expected / 10 ** 8)
);
expect((cDAIBalanceReserveBefore - cDAIBalanceReserveAfter).toString()).to.be.equal(
expected.toString()
);
});
it("should be able to retain the precision when selling a low quantity of tokens", async () => {
let amount = 1e1;
let reserveToken = await marketMaker.reserveTokens(cDAI.address);
const priceBefore = await goodReserve.currentPrice(cDAI.address);
await goodDollar.approve(goodReserve.address, amount);
await goodReserve.sell(cDAI.address, amount, 0);
reserveToken = await marketMaker.reserveTokens(cDAI.address);
const priceAfter = await goodReserve.currentPrice(cDAI.address);
expect(Math.floor(priceAfter.toNumber() / 100).toString()).to.be.equal(
Math.floor(priceBefore.toNumber() / 100).toString()
);
});
});