Skip to content

Commit

Permalink
Merge pull request #205 from Neufund/rfix/tests-eto-commitment-overflows
Browse files Browse the repository at this point in the history
tests eto commitment overflows
  • Loading branch information
rudolfix authored Nov 26, 2018
2 parents f2769f9 + fa319a7 commit 209e92d
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 6 deletions.
3 changes: 3 additions & 0 deletions contracts/ETO/ETOCommitment.sol
Original file line number Diff line number Diff line change
Expand Up @@ -790,8 +790,11 @@ contract ETOCommitment is
}
// issue equity token
assert(equityTokenInt256 + ticket.equityTokenInt < 2**32);
// this will also check ticket.amountEurUlps + uint96(amount) as ticket.equivEurUlps is always >= ticket.amountEurUlps
assert(equivEurUlps + ticket.equivEurUlps < 2**96);
assert(amount < 2**96);
// practically impossible: would require price of ETH smaller than 1 EUR and > 2**96 amount of ether
assert(uint256(ticket.amountEth) + amount < 2**96);
EQUITY_TOKEN.issueTokens(uint32(equityTokenInt256));
// update total investment
_totalEquivEurUlps += uint96(equivEurUlps);
Expand Down
4 changes: 4 additions & 0 deletions scripts/deployETO.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
/* eslint-disable no-continue */

require("babel-register");
const moment = require("moment");
const commandLineArgs = require("command-line-args");
const confirm = require("node-ask").confirm;
const fs = require("fs");
Expand Down Expand Up @@ -70,6 +71,9 @@ module.exports = async function deploy() {
console.log(
`${k}: ${terms[k].toString(10)} == ${terms[k].div(Q18).toString(10)} * 10**18`,
);
} else if (k.endsWith("_DURATION")) {
const duration = moment.duration(terms[k].toNumber() * 1000);
console.log(`${k}: ${terms[k].toString(10)} = ${duration.humanize()}`);
} else {
console.log(`${k}: ${terms[k].toString(10)}`);
}
Expand Down
81 changes: 75 additions & 6 deletions test/ETO/ETOCommitment.js
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,15 @@ contract("ETOCommitment", ([deployer, admin, company, nominee, ...investors]) =>
);
});

it("rejects setting agreement by nominee when start date is set");
it("rejects setting agreement by nominee when start date is set", async () => {
await etoCommitment.amendAgreement("ABBA", { from: nominee });
startDate = new web3.BigNumber(await latestTimestamp()).add(1);
startDate = startDate.add(await platformTerms.DATE_TO_WHITELIST_MIN_DURATION());
await etoCommitment.setStartDate(etoTerms.address, equityToken.address, startDate, {
from: company,
});
await expect(etoCommitment.amendAgreement("ABBA", { from: nominee })).to.be.revert;
});
});

describe("MockETOCommitment tests", () => {
Expand Down Expand Up @@ -793,9 +801,6 @@ contract("ETOCommitment", ([deployer, admin, company, nominee, ...investors]) =>
).to.be.rejectedWith("NF_ETO_MAX_TOK_CAP");
});

it("sign to claim with feeDisbursal as simple address");
// it("sign to claim with feeDisbursal as contract implementing fallback");

it("should refund if company signs too late", async () => {
await skipTimeTo(publicStartDate.add(1));
const missingAmount = tokenTermsDict.MAX_NUMBER_OF_TOKENS.mul(
Expand Down Expand Up @@ -946,7 +951,6 @@ contract("ETOCommitment", ([deployer, admin, company, nominee, ...investors]) =>
);
});

it("reverts on euro token overflow > 2**96");
// simulates abandoned ETO
it("go from Setup with start date to Refund with one large increase time");
it(
Expand All @@ -955,6 +959,41 @@ contract("ETOCommitment", ([deployer, admin, company, nominee, ...investors]) =>
});

describe("special ETO configurations", () => {
it("reverts overflow on internal equity token 32 bit", async () => {
// equity tokens in investor ticket are stored in 32bit uint, test below tries to overflow it
const two = new web3.BigNumber(2);
await deployETO({
ovrETOTerms: { MAX_TICKET_EUR_ULPS: two.pow(128) },
ovrTokenTerms: { TOKEN_PRICE_EUR_ULPS: two.pow(64), MAX_NUMBER_OF_TOKENS: two.pow(128) },
});
await prepareETOForPublic();
await skipTimeTo(publicStartDate);
await etoCommitment.handleStateTransitions();
// will generate exactly 2^32 - 2 tokens
await investAmount(investors[0], two.pow(96).sub(two.pow(64).mul(2)), "EUR");
// will generate 1 token
await investAmount(investors[0], two.pow(64), "EUR");
await expect(investAmount(investors[0], two.pow(64), "EUR")).to.be.revert;
});

it("reverts on euro token overflow > 2**96", async () => {
// investor ticket stores eurt equivalend in 96bit, this attempts to overflow it (without overflowing equity tokens)
const two = new web3.BigNumber(2);
await deployETO({
ovrETOTerms: { MAX_TICKET_EUR_ULPS: two.pow(128), MIN_TICKET_EUR_ULPS: two.pow(90) },
ovrTokenTerms: { TOKEN_PRICE_EUR_ULPS: two.pow(90), MAX_NUMBER_OF_TOKENS: two.pow(128) },
});
await prepareETOForPublic();
await skipTimeTo(publicStartDate);
await etoCommitment.handleStateTransitions();
// will generate 62 tokens
await investAmount(investors[0], two.pow(96).sub(two.pow(90).mul(2)), "EUR");
// will generate 1 token
await investAmount(investors[0], two.pow(90), "EUR");
expect(await equityToken.balanceOf(etoCommitment.address)).to.be.bignumber.eq(63);
await expect(investAmount(investors[0], two.pow(90), "EUR")).to.be.revert;
});

it("should skip whitelist in ETO with 0 whitelist period", async () => {
await deployETO({ ovrDurations: { WHITELIST_DURATION: new web3.BigNumber(0) } });
await prepareETOForPublic();
Expand Down Expand Up @@ -1112,6 +1151,33 @@ contract("ETOCommitment", ([deployer, admin, company, nominee, ...investors]) =>
// large tickets only
it("should invest in non-retail commitment");

it("sign to claim with feeDisbursal as simple address", async () => {
// set simple address as fee disbursal
const simpleAccountDisbursal = investors[3];
await universe.setSingleton(knownInterfaces.feeDisbursal, simpleAccountDisbursal, {
from: admin,
});
// allow to receive eurt
await euroTokenController.setAllowedTransferTo(simpleAccountDisbursal, true, { from: admin });
await deployETO({ ovrETOTerms: { MAX_TICKET_EUR_ULPS: Q18.mul(15000000) } });
await prepareETOForPublic();
await skipTimeTo(publicStartDate);
const missingAmount = tokenTermsDict.MAX_NUMBER_OF_TOKENS.mul(
tokenTermsDict.TOKEN_PRICE_EUR_ULPS,
);
await investAmount(investors[1], missingAmount, "EUR");
await moveETOToClaim(1, new web3.BigNumber(0));
await claimInvestor(investors[1]);
const currDate = new web3.BigNumber(await latestTimestamp());
const payoutDate = currDate.add(durTable[CommitmentState.Claim]);
await skipTimeTo(payoutDate);
await etoCommitment.payout();
// check if disbursal happened
expect(await euroToken.balanceOf(simpleAccountDisbursal)).to.be.bignumber.eq(
missingAmount.mul(0.03).round(0, 4),
);
});

it("should invest in ETO with public discount and have full valuation", async () => {
const publicDiscount = Q18.mul(0.2);
await deployETO({
Expand Down Expand Up @@ -2742,7 +2808,10 @@ contract("ETOCommitment", ([deployer, admin, company, nominee, ...investors]) =>
token = euroToken;
}
// we take one wei of NEU so we do not have to deal with rounding errors
const expectedNeu = investorShare(await neumark.incremental(eurEquiv)).sub(1);
let expectedNeu = investorShare(await neumark.incremental(eurEquiv));
if (expectedNeu.gt(0)) {
expectedNeu = expectedNeu.sub(1);
}
// use overloaded erc223 to transfer to contract with callback
const tx = await token.transfer["address,uint256,bytes"](etoCommitment.address, amount, "", {
from: investor,
Expand Down

0 comments on commit 209e92d

Please sign in to comment.