Skip to content

Commit 8336d72

Browse files
authored
Merge pull request #524 from AugurProject/disavowal_changes
make the automatic disavowal actually apply as disavowal. Add a function to markets to do disavowal of crowdsourcers
2 parents 2856280 + af3d021 commit 8336d72

File tree

4 files changed

+52
-29
lines changed

4 files changed

+52
-29
lines changed

source/contracts/reporting/BaseReportingParticipant.sol

+1-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ contract BaseReportingParticipant is Controlled, IReportingParticipant {
7272
}
7373

7474
function isDisavowed() public view returns (bool) {
75-
return market == IMarket(0);
75+
return market == IMarket(0) || !market.isContainerForReportingParticipant(this);
7676
}
7777

7878
function getPayoutNumerator(uint8 _outcome) public view returns (uint256) {

source/contracts/reporting/Market.sol

+11-3
Original file line numberDiff line numberDiff line change
@@ -271,16 +271,24 @@ contract Market is DelegationTarget, Extractable, ITyped, Initializable, Ownable
271271
// reset state back to Initial Reporter
272272
feeWindow = IFeeWindow(0);
273273
IInitialReporter _initialParticipant = getInitialReporter();
274-
for (uint8 i = 1; i < participants.length; ++i) {
275-
IDisputeCrowdsourcer(participants[i]).disavow();
276-
}
277274
delete participants;
278275
participants.push(_initialParticipant);
279276
_initialParticipant.resetReportTimestamp();
280277
crowdsourcers = MapFactory(controller.lookup("MapFactory")).createMap(controller, this);
281278
return true;
282279
}
283280

281+
function disavowCrowdsourcers() public onlyInGoodTimes returns (bool) {
282+
IMarket _forkingMarket = getForkingMarket();
283+
require(_forkingMarket != IMarket(0));
284+
require(_forkingMarket != this);
285+
IInitialReporter _initialParticipant = getInitialReporter();
286+
delete participants;
287+
participants.push(_initialParticipant);
288+
crowdsourcers = MapFactory(controller.lookup("MapFactory")).createMap(controller, this);
289+
return true;
290+
}
291+
284292
function withdrawInEmergency() public onlyInBadTimes onlyOwner returns (bool) {
285293
IReputationToken _reputationToken = getReputationToken();
286294
uint256 _repBalance = _reputationToken.balanceOf(this);

tests/reporting/test_fee_distribution.py

+24-16
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,11 @@ def test_initial_report_and_participation_fee_collection(localFixture, universe,
7979
with EtherDelta(expectedFees, tester.a0, localFixture.chain, "Redeeming didn't increase ETH correctly"):
8080
assert categoricalInitialReport.redeem(tester.a0)
8181

82-
def test_failed_crowdsourcer_fees(localFixture, universe, market, cash, reputationToken):
82+
@mark.parametrize('finalize', [
83+
True,
84+
False,
85+
])
86+
def test_failed_crowdsourcer_fees(finalize, localFixture, universe, market, cash, reputationToken):
8387
feeWindow = localFixture.applySignature('FeeWindow', market.getFeeWindow())
8488

8589
# generate some fees
@@ -92,31 +96,35 @@ def test_failed_crowdsourcer_fees(localFixture, universe, market, cash, reputati
9296
generateFees(localFixture, universe, market)
9397

9498
# We'll have testers contribute to a dispute but not reach the target
95-
amount = market.getTotalStake() - 1
99+
amount = market.getTotalStake()
96100

97-
with TokenDelta(reputationToken, -amount, tester.a1, "Disputing did not reduce REP balance correctly"):
98-
assert market.contribute([0, market.getNumTicks()], False, amount, sender=tester.k1, startgas=long(6.7 * 10**6))
101+
with TokenDelta(reputationToken, -amount + 1, tester.a1, "Disputing did not reduce REP balance correctly"):
102+
assert market.contribute([1, market.getNumTicks()-1], False, amount - 1, sender=tester.k1, startgas=long(6.7 * 10**6))
99103

100-
with TokenDelta(reputationToken, -amount, tester.a2, "Disputing did not reduce REP balance correctly"):
101-
assert market.contribute([0, market.getNumTicks()], False, amount, sender=tester.k2, startgas=long(6.7 * 10**6))
104+
with TokenDelta(reputationToken, -amount + 1, tester.a2, "Disputing did not reduce REP balance correctly"):
105+
assert market.contribute([1, market.getNumTicks()-1], False, amount - 1, sender=tester.k2, startgas=long(6.7 * 10**6))
102106

103107
assert market.getFeeWindow() == feeWindow.address
104108

105-
payoutDistributionHash = market.derivePayoutDistributionHash([0, market.getNumTicks()], False)
109+
payoutDistributionHash = market.derivePayoutDistributionHash([1, market.getNumTicks()-1], False)
106110
failedCrowdsourcer = localFixture.applySignature("DisputeCrowdsourcer", market.getCrowdsourcer(payoutDistributionHash))
107111

108-
# Fast forward time until the fee window is over and we can redeem to recieve the REP back and fees
109-
localFixture.contracts["Time"].setTimestamp(feeWindow.getEndTime() + 1)
110-
assert market.finalize()
111-
112-
# The dispute crowdsourcer contributor locked in REP for 2 rounds, as did the Initial Reporter
113-
expectedTotalFees = getExpectedFees(localFixture, cash, failedCrowdsourcer, 1)
114-
115-
with TokenDelta(reputationToken, amount, tester.a1, "Redeeming did not refund REP"):
112+
if finalize:
113+
# Fast forward time until the fee window is over and we can redeem to recieve the REP back and fees
114+
localFixture.contracts["Time"].setTimestamp(feeWindow.getEndTime() + 1)
115+
expectedTotalFees = getExpectedFees(localFixture, cash, failedCrowdsourcer, 1)
116+
else:
117+
# Continue to the next round which will disavow failed crowdsourcers and let us redeem once the window is over
118+
market.contribute([0, market.getNumTicks()], False, amount * 2, startgas=long(6.7 * 10**6))
119+
assert market.getFeeWindow() != feeWindow.address
120+
localFixture.contracts["Time"].setTimestamp(feeWindow.getEndTime() + 1)
121+
expectedTotalFees = getExpectedFees(localFixture, cash, failedCrowdsourcer, 1)
122+
123+
with TokenDelta(reputationToken, amount - 1, tester.a1, "Redeeming did not refund REP"):
116124
with EtherDelta(expectedTotalFees / 2, tester.a1, localFixture.chain, "Redeeming didn't increase ETH correctly"):
117125
assert failedCrowdsourcer.redeem(tester.a1)
118126

119-
with TokenDelta(reputationToken, amount, tester.a2, "Redeeming did not refund REP"):
127+
with TokenDelta(reputationToken, amount - 1, tester.a2, "Redeeming did not refund REP"):
120128
with EtherDelta(cash.balanceOf(failedCrowdsourcer.address), tester.a2, localFixture.chain, "Redeeming didn't increase ETH correctly"):
121129
assert failedCrowdsourcer.redeem(tester.a2)
122130

tests/reporting/test_reporting.py

+16-9
Original file line numberDiff line numberDiff line change
@@ -146,11 +146,13 @@ def test_roundsOfReporting(rounds, localFixture, market, universe):
146146
feeWindow = market.getFeeWindow()
147147
assert feeWindow == universe.getCurrentFeeWindow()
148148

149-
@mark.parametrize('finalizeByMigration', [
150-
True,
151-
False
149+
@mark.parametrize('finalizeByMigration, manuallyDisavow', [
150+
(True, True),
151+
(False, True),
152+
(True, False),
153+
(False, False),
152154
])
153-
def test_forking(finalizeByMigration, localFixture, universe, market, categoricalMarket):
155+
def test_forking(finalizeByMigration, manuallyDisavow, localFixture, universe, market, categoricalMarket):
154156
# Let's go into the one dispute round for the categorical market
155157
proceedToNextRound(localFixture, categoricalMarket)
156158
proceedToNextRound(localFixture, categoricalMarket)
@@ -165,24 +167,29 @@ def test_forking(finalizeByMigration, localFixture, universe, market, categorica
165167
numTicks = market.getNumTicks()
166168
childUniverse = universe.createChildUniverse([numTicks/ 4, numTicks * 3 / 4], False)
167169

170+
# confirm that before the fork is finalized we can redeem stake in other markets crowdsourcers, which are disavowable
171+
categoricalDisputeCrowdsourcer = localFixture.applySignature("DisputeCrowdsourcer", categoricalMarket.getReportingParticipant(1))
172+
173+
if manuallyDisavow:
174+
assert categoricalMarket.disavowCrowdsourcers()
175+
# We can redeem before the fork finalizes since disavowal has occured
176+
assert categoricalDisputeCrowdsourcer.redeem(tester.a0)
177+
168178
# finalize the fork
169179
finalizeFork(localFixture, market, universe, finalizeByMigration)
170180

171-
# get the reporting participants for the categorical market before they may be disavowed
172-
categoricalInitialReport = localFixture.applySignature("InitialReporter", categoricalMarket.getReportingParticipant(0))
173-
categoricalDisputeCrowdsourcer = localFixture.applySignature("DisputeCrowdsourcer", categoricalMarket.getReportingParticipant(1))
174-
175181
# The categorical market can be migrated to the winning universe
176182
assert categoricalMarket.migrateThroughOneFork()
177183

178-
# This disavows the dispute crowdsourcer
184+
# The dispute crowdsourcer has been disavowed
179185
newUniverse = localFixture.applySignature("Universe", categoricalMarket.getUniverse())
180186
assert newUniverse.address != universe.address
181187
assert categoricalDisputeCrowdsourcer.isDisavowed()
182188
assert not universe.isContainerForReportingParticipant(categoricalDisputeCrowdsourcer.address)
183189
assert not newUniverse.isContainerForReportingParticipant(categoricalDisputeCrowdsourcer.address)
184190

185191
# The initial report is still present however
192+
categoricalInitialReport = localFixture.applySignature("InitialReporter", categoricalMarket.getReportingParticipant(0))
186193
assert categoricalMarket.getReportingParticipant(0) == categoricalInitialReport.address
187194
assert not categoricalInitialReport.isDisavowed()
188195
assert not universe.isContainerForReportingParticipant(categoricalInitialReport.address)

0 commit comments

Comments
 (0)