From c02e893cfc453435c126302ce67db72d5d65c5b7 Mon Sep 17 00:00:00 2001 From: Ladd Hoffman Date: Mon, 15 Apr 2024 15:10:58 -0500 Subject: [PATCH] handle the case where an author has insufficient REP to cover a negative citation --- ethereum/contracts/core/Forum.sol | 12 ++++++++- ethereum/test/Forum.js | 44 +++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/ethereum/contracts/core/Forum.sol b/ethereum/contracts/core/Forum.sol index 8d2edd7..7c1553a 100644 --- a/ethereum/contracts/core/Forum.sol +++ b/ethereum/contracts/core/Forum.sol @@ -152,7 +152,17 @@ contract Forum is Reputation { post.reputation -= uint(-amount); } else { refundToInbound = int(post.reputation) + amount; - _update(post.author, address(this), post.reputation); + if (balanceOf(post.author) < post.reputation) { + // If author has already lost reputation that was gained from this post, + // that means other DAO members gained it through policing. + // Here we preserve the sum of members REP but decrease the sum of posts REP. + refundToInbound -= int( + post.reputation - balanceOf(post.author) + ); + _update(post.author, address(this), balanceOf(post.author)); + } else { + _update(post.author, address(this), post.reputation); + } post.reputation = 0; } } diff --git a/ethereum/test/Forum.js b/ethereum/test/Forum.js index 1afcf50..2d53754 100644 --- a/ethereum/test/Forum.js +++ b/ethereum/test/Forum.js @@ -233,5 +233,49 @@ describe('Forum', () => { expect((await dao.posts(0)).reputation).to.equal(50); expect(await dao.totalSupply()).to.equal(50); }); + + it('handles the case where an author has already lost reputation gained from a later-downvoted post', async () => { + await dao.addPost(account1, 'content-id', []); + await initiateValidationPool({ postIndex: 0 }); + await dao.evaluateOutcome(0); + expect(await dao.balanceOf(account1)).to.equal(100); + expect(await dao.totalSupply()).to.equal(100); + expect((await dao.posts(0)).reputation).to.equal(100); + + await dao.addPost(account2, 'second-content-id', []); + await initiateValidationPool({ postIndex: 1 }); + await time.increase(POOL_DURATION + 1); + await dao.evaluateOutcome(1); + expect(await dao.balanceOf(account1)).to.equal(100); + expect(await dao.balanceOf(account2)).to.equal(100); + expect(await dao.totalSupply()).to.equal(200); + expect((await dao.posts(0)).reputation).to.equal(100); + expect((await dao.posts(1)).reputation).to.equal(100); + + // account1 stakes and loses + await initiateValidationPool({ postIndex: 1 }); + await dao.stakeOnValidationPool(2, 50, true); + await dao.connect(account2).stakeOnValidationPool(2, 60, false); + await time.increase(POOL_DURATION + 1); + await dao.evaluateOutcome(2); + expect(await dao.balanceOf(account1)).to.equal(50); + expect(await dao.balanceOf(account2)).to.equal(250); + expect(await dao.totalSupply()).to.equal(300); + expect((await dao.posts(0)).reputation).to.equal(100); + expect((await dao.posts(1)).reputation).to.equal(100); + + // account1's post is later negatively referenced + await dao.addPost(account3, 'third-content-id', [{ weightPercent: -100, targetPostIndex: 0 }]); + await initiateValidationPool({ postIndex: 2, fee: 200 }); + await time.increase(POOL_DURATION + 1); + await dao.evaluateOutcome(3); + expect(await dao.balanceOf(account1)).to.equal(0); + expect(await dao.balanceOf(account2)).to.equal(250); + expect(await dao.balanceOf(account3)).to.equal(250); + expect(await dao.totalSupply()).to.equal(500); + expect((await dao.posts(0)).reputation).to.equal(0); + expect((await dao.posts(1)).reputation).to.equal(100); + expect((await dao.posts(2)).reputation).to.equal(250); + }); }); });