-
-
Save IllIllI000/63e170b9a07a321ceec79938ac804aa5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/hardhat.config.ts b/hardhat.config.ts | |
index 63bb978..1ed5b79 100644 | |
--- a/hardhat.config.ts | |
+++ b/hardhat.config.ts | |
@@ -49,6 +49,12 @@ const config: HardhatUserConfig = { | |
accountsBalance: "100000000000000000000000", // 100000 ETH | |
count: 20, | |
}, | |
+ gas: 5000000, | |
+ mining: { | |
+/* mempool: { | |
+ order: "fifo" | |
+ }*/ | |
+ } | |
}, | |
mainnet: { | |
url: `https://eth-mainnet.alchemyapi.io/v2/${process.env.ALCHEMY_MAINNET_API_KEY}`, | |
diff --git a/test/votingEscrowTest.ts b/test/votingEscrowTest.ts | |
index 7d3163d..6fb031b 100644 | |
--- a/test/votingEscrowTest.ts | |
+++ b/test/votingEscrowTest.ts | |
@@ -53,6 +53,49 @@ describe("VotingEscrow Tests", function () { | |
return (await ethers.provider.getBlock("latest")).timestamp; | |
} | |
+ async function dumpNyms(description: string, names: Map<string,SignerWithAddress>, primaryToNyms: Map<string,string[]>, block: number, isFinalState: boolean) { | |
+ console.log("dumpNyms:", description); | |
+ console.log("Nym vote info for block", block); | |
+ let balTotalAll = BigNumber.from(0); | |
+ let priorBalTotal = BigNumber.from(-1); | |
+ let priorVoteTotal = BigNumber.from(-1); | |
+ for (let key of primaryToNyms.keys()) { | |
+ console.log(" " + key + "'s nym info:") | |
+ let value = primaryToNyms.get(key); | |
+ if (!value) continue; | |
+ let balTotal = BigNumber.from(0); | |
+ let voteTotal = BigNumber.from(0); | |
+ for (let nymName of value) { | |
+ let nym = names.get(nymName) | |
+ if (!nym) continue; | |
+ let bal = await fdtMock.balanceOf(nym.address); | |
+ let vote = await ve.balanceOfAt(nym.address, block); | |
+ console.log(" Name:", nymName, " (", nym.address, ")", | |
+ "\n Balance:", bal.toString(), | |
+ "\n Votes:", vote.toString()) | |
+ balTotal = balTotal.add(bal); | |
+ voteTotal = voteTotal.add(vote); | |
+ } | |
+ console.log(" Total nyms balance:", balTotal.toString(), "Total votes:", voteTotal.toString()); | |
+ balTotalAll = balTotalAll.add(balTotal); | |
+ if (!priorBalTotal.eq(BigNumber.from(-1))) { | |
+ expect(priorBalTotal.sub(balTotal)).to.below(1); | |
+ if (isFinalState) { | |
+ // test must always be arranged in order of decreasing nym splits for the | |
+ // following condition to pass (so that larger splits are confirmed to be | |
+ // more expensive than smaller ones) | |
+ expect(voteTotal.sub(priorVoteTotal)).to.below(1); | |
+ } | |
+ } | |
+ priorBalTotal = balTotal; | |
+ priorVoteTotal = voteTotal; | |
+ } | |
+ console.log("\n All account total balance:", balTotalAll.toString()); | |
+ let veBal = await fdtMock.balanceOf(ve.address); | |
+ console.log(" Balance of ve:", veBal.toString()); | |
+ console.log(" Sum:", veBal.add(balTotalAll).toString()); | |
+ } | |
+ | |
before(async function () { | |
await createSnapshot(provider); | |
@@ -115,6 +158,105 @@ describe("VotingEscrow Tests", function () { | |
await restoreSnapshot(provider); | |
}); | |
+ | |
+ // to run: | |
+ // rm -Rf 2022-08-fiatdao || true && git clone https://github.com/code-423n4/2022-08-fiatdao && cd 2022-08-fiatdao && npm install && npm run build && wget https://gist.githubusercontent.com/IllIllI000/63e170b9a07a321ceec79938ac804aa5/raw/a28539747166b03c74a3bd7e398a08466cadba93/veFDT_mit_nym.diff && git apply veFDT_mit_nym.diff && npx hardhat test --config hardhat.config.test.ts test/votingEscrowTest.ts | |
+ | |
+ | |
+ describe("IllIllI Mitigation tests", async () => { | |
+ it("IllIllI - Ensure lots of small delegations are equal to one large one", async () => { | |
+ //await createSnapshot(provider); | |
+ const lockTime = 1 * WEEK + (await getTimestamp()); | |
+ | |
+ let names = new Map(); | |
+ names.set('alice', alice); | |
+ names.set('bob', bob); | |
+ names.set('charlie', charlie); | |
+ names.set('david', david); | |
+ names.set('eve', eve); | |
+ names.set('contract', contract); | |
+ names.set('ve', ve); | |
+ | |
+ let primaryToNyms = new Map(); | |
+ primaryToNyms.set('alice', [ 'alice', 'charlie', 'david' ]); | |
+ primaryToNyms.set('bob', [ 'bob', 'eve', 'contract' ]); | |
+ | |
+ // pre lock balances | |
+ let block = await getBlock(); | |
+ await dumpNyms("Initial state", names, primaryToNyms, block, false); | |
+ | |
+ let tx1, tx2, tx3, tx4, tx5, resp1, resp2, resp3, resp4, resp5 | |
+ await provider.send("evm_setAutomine", [false]); | |
+ await provider.send("evm_setIntervalMining", [0]); | |
+ await provider.send("evm_mine", []); | |
+ | |
+ // alice creates a lot of small nym locks, but bob creates one | |
+ | |
+ // +1 results in equality, ceil results in larger penalty for splitting, both larger for split | |
+ //let amountToLock = BigNumber.from("10000000000000000000"); | |
+ // +1 results in larger penalty for splitting, ceil results in larger penalty for splitting, both larger for split | |
+ //let amountToLock = BigNumber.from("10000000000"); | |
+ // +1 results in equality, ceil results in equality, both you can't quit | |
+ let amountToLock = BigNumber.from("1"); | |
+ | |
+ // In this test, since there are three splits for alice, but none for bob, | |
+ // if bob's left most penalty digit rounds up to three, and alice's | |
+ // each round up from zero to one, it's possible for rounding to cause bob's | |
+ // single penalty to equal alice's total penalty. Similarly it's possible | |
+ // for each of alice's fractions of a penalty to total less than one wei, | |
+ // but since they're each rounded separately, the over all penalty for | |
+ // alice is larger. Therefore, it's not possible to change the algorithm | |
+ // such that the penalty for splitting is always equal to the penalty for | |
+ // not splitting - the best one can do is to charge at _least_ as much | |
+ // for the split as for the non-split | |
+ | |
+ tx1 = await ve.connect(alice).createLock(amountToLock, lockTime); | |
+ tx2 = await ve.connect(charlie).createLock(amountToLock, lockTime); | |
+ tx3 = await ve.connect(david).createLock(amountToLock, lockTime); | |
+ tx4 = await ve.connect(bob).createLock(amountToLock.mul(3), lockTime); | |
+ for (let i = 0; i < 10; ++i) await provider.send("evm_mine", []); | |
+ | |
+ resp1 = await tx1.wait(); | |
+ resp2 = await tx2.wait(); | |
+ resp3 = await tx3.wait(); | |
+ resp4 = await tx4.wait(); | |
+ console.log(resp1.blockNumber, resp2.blockNumber, resp4.blockNumber, resp4.blockNumber); | |
+ | |
+ // everyone extends their lock then quits | |
+ const lockTime2 = 50 * WEEK + (await getTimestamp()); | |
+ tx1 = await ve.connect(alice).increaseUnlockTime(lockTime2); | |
+ tx2 = await ve.connect(bob).increaseUnlockTime(lockTime2); | |
+ tx3 = await ve.connect(charlie).increaseUnlockTime(lockTime2); | |
+ tx4 = await ve.connect(david).increaseUnlockTime(lockTime2); | |
+ for (let i = 0; i < 10; ++i) await provider.send("evm_mine", []); | |
+ resp1 = await tx1.wait(); | |
+ resp2 = await tx2.wait(); | |
+ resp3 = await tx3.wait(); | |
+ resp4 = await tx4.wait(); | |
+ console.log(resp1.blockNumber, resp2.blockNumber, resp3.blockNumber, resp4.blockNumber); | |
+ await dumpNyms("Everyone has extended", names, primaryToNyms, resp4.blockNumber, false); | |
+ | |
+ // note that in some runs, this happens in the same block number, but one second later, | |
+ // causing penalties to change | |
+ tx1 = await ve.connect(alice).quitLock(); | |
+ tx2 = await ve.connect(bob).quitLock(); | |
+ tx3 = await ve.connect(charlie).quitLock(); | |
+ tx4 = await ve.connect(david).quitLock(); | |
+ for (let i = 0; i < 10; ++i) await provider.send("evm_mine", []); | |
+ resp1 = await tx1.wait(); | |
+ resp2 = await tx2.wait(); | |
+ resp3 = await tx3.wait(); | |
+ resp4 = await tx4.wait(); | |
+ console.log(resp1.blockNumber, resp2.blockNumber, resp3.blockNumber, resp4.blockNumber); | |
+ | |
+ block = resp1.blockNumber; | |
+ await dumpNyms("Everyone has quit", names, primaryToNyms, block, true); | |
+ | |
+ await provider.send("evm_setAutomine", [true]); | |
+ await provider.send("evm_setIntervalMining", [5000]); | |
+ }); | |
+ }); | |
+/** | |
describe("Deployment", async () => { | |
it("Initialized properly", async () => { | |
expect(await ve.owner()).to.equal(admin.address); | |
@@ -856,5 +998,5 @@ describe("VotingEscrow Tests", function () { | |
await ve.connect(alice).quitLock(); | |
expect(await fdtMock.balanceOf(alice.address)).to.equal(aliceBalBefore); | |
}); | |
- }); | |
+ });/**/ | |
}); | |
diff --git a/tsconfig.json b/tsconfig.json | |
index a0e6c93..4100631 100644 | |
--- a/tsconfig.json | |
+++ b/tsconfig.json | |
@@ -12,6 +12,7 @@ | |
"typechain": ["./typechain"], | |
"typechain/*": ["./typechain/*"], | |
}, | |
+ "downlevelIteration": true | |
}, | |
"include": [ | |
"./scripts", | |
@@ -19,4 +20,4 @@ | |
"./typechain" | |
], | |
"files": ["./hardhat.config.ts", "./hardhat.config.test.ts"] | |
- } | |
\ No newline at end of file | |
+ } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment