def test_finalized_fork_migration(localFixture, universe, market, categoricalMarket): # Make the categorical market finalized proceedToNextRound(localFixture, categoricalMarket) feeWindow = localFixture.applySignature('FeeWindow', categoricalMarket.getFeeWindow()) # Time marches on and the market can be finalized localFixture.contracts["Time"].setTimestamp(feeWindow.getEndTime() + 1) assert categoricalMarket.finalize() # Proceed to Forking for the yesNo market and finalize it proceedToFork(localFixture, market, universe) finalizeFork(localFixture, market, universe) # The categorical market is finalized and cannot be migrated to the new universe with raises(TransactionFailed): categoricalMarket.migrateThroughOneFork() # We also can't disavow the crowdsourcers for this market with raises(TransactionFailed): categoricalMarket.disavowCrowdsourcers() # The forking market may not migrate or disavow crowdsourcers either with raises(TransactionFailed): market.migrateThroughOneFork() with raises(TransactionFailed): market.disavowCrowdsourcers()
def test_finalized_fork_migration(localFixture, universe, market, categoricalMarket): # Make the categorical market finalized proceedToNextRound(localFixture, categoricalMarket) feeWindow = localFixture.applySignature('FeeWindow', categoricalMarket.getFeeWindow()) # Time marches on and the market can be finalized localFixture.contracts["Time"].setTimestamp(feeWindow.getEndTime() + 1) assert categoricalMarket.finalize() # Proceed to Forking for the binary market and finalize it proceedToFork(localFixture, market, universe) finalizeFork(localFixture, market, universe) # The categorical market is finalized and cannot be migrated to the new universe with raises(TransactionFailed): categoricalMarket.migrateThroughOneFork() # We also can't disavow the crowdsourcers for this market with raises(TransactionFailed): categoricalMarket.disavowCrowdsourcers() # The forking market may not migrate or disavow crowdsourcers either with raises(TransactionFailed): market.migrateThroughOneFork() with raises(TransactionFailed): market.disavowCrowdsourcers()
def test_fork_migration_no_report(localFixture, universe, market, cash): # Proceed to Forking for the yesNo market but don't go all the way so that we can create the new market still for i in range(10): proceedToNextRound(localFixture, market) # Create a market before the fork occurs which has an end date past the forking window endTime = long(localFixture.contracts["Time"].getTimestamp() + timedelta(days=90).total_seconds()) longMarket = localFixture.createYesNoMarket(universe, endTime, 1, cash, tester.a0) # Go to the forking period proceedToFork(localFixture, market, universe) # Now finalize the fork so migration can occur finalizeFork(localFixture, market, universe) # Now when we migrate the market through the fork we'll place a new bond in the winning universe's REP oldReputationToken = localFixture.applySignature( "ReputationToken", universe.getReputationToken()) oldBalance = oldReputationToken.balanceOf(longMarket.address) newUniverse = localFixture.applySignature( "Universe", universe.getChildUniverse(market.getWinningPayoutDistributionHash())) newReputationToken = localFixture.applySignature( "ReputationToken", newUniverse.getReputationToken()) with TokenDelta(oldReputationToken, 0, longMarket.address, "Migrating didn't disavow old no show bond"): with TokenDelta(newReputationToken, oldBalance, longMarket.address, "Migrating didn't place new no show bond"): assert longMarket.migrateThroughOneFork([], False, "")
def test_forking(localFixture, universe, market, categoricalMarket, cash, reputationToken): # Let's do some initial disputes for the categorical market proceedToNextRound(localFixture, categoricalMarket, tester.k1, moveTimeForward = False) # Get to a fork testers = [tester.k0, tester.k1, tester.k2, tester.k3] testerIndex = 1 while (market.getForkingMarket() == longToHexString(0)): proceedToNextRound(localFixture, market, testers[testerIndex], True) testerIndex += 1 testerIndex = testerIndex % len(testers) # Have the participants fork and create new child universes reportingParticipant = localFixture.applySignature("DisputeCrowdsourcer", market.getReportingParticipant(0)) ReportingParticipantDisavowedLog = { "universe": universe.address, "market": market.address, "reportingParticipant": reportingParticipant.address, } with AssertLog(localFixture, "ReportingParticipantDisavowed", ReportingParticipantDisavowedLog): reportingParticipant.fork() for i in range(1, market.getNumParticipants()): reportingParticipant = localFixture.applySignature("DisputeCrowdsourcer", market.getReportingParticipant(i)) reportingParticipant.fork() # Finalize the fork finalizeFork(localFixture, market, universe) categoricalDisputeCrowdsourcer = localFixture.applySignature("DisputeCrowdsourcer", categoricalMarket.getReportingParticipant(1)) # Migrate the categorical market into the winning universe. This will disavow the dispute crowdsourcer on it, letting us redeem for original universe rep and eth assert categoricalMarket.migrateThroughOneFork() expectedRep = categoricalDisputeCrowdsourcer.getStake() expectedEth = getExpectedFees(localFixture, cash, categoricalDisputeCrowdsourcer, 2) with EtherDelta(expectedEth, tester.a1, localFixture.chain, "Redeeming didn't increase ETH correctly"): with TokenDelta(reputationToken, expectedRep, tester.a1, "Redeeming didn't increase REP correctly"): categoricalDisputeCrowdsourcer.redeem(tester.a1) # Now we'll redeem the forked reporting participants testers = [tester.a0, tester.a1, tester.a2, tester.a3] for i in range(market.getNumParticipants()): account = testers[i % 4] reportingParticipant = localFixture.applySignature("DisputeCrowdsourcer", market.getReportingParticipant(i)) expectedRep = reportingParticipant.getStake() expectedRep += expectedRep / localFixture.contracts["Constants"].FORK_MIGRATION_PERCENTAGE_BONUS_DIVISOR() expectedRep += reportingParticipant.getStake() / 2 expectedEth = cash.balanceOf(reportingParticipant.address) newReputationToken = localFixture.applySignature("ReputationToken", reportingParticipant.getReputationToken()) with EtherDelta(expectedEth, account, localFixture.chain, "Redeeming didn't increase ETH correctly"): with TokenDelta(newReputationToken, expectedRep, account, "Redeeming didn't increase REP correctly"): reportingParticipant.redeem(account)
def test_forking(finalizeByMigration, manuallyDisavow, localFixture, universe, market, categoricalMarket): # Let's go into the one dispute round for the categorical market proceedToNextRound(localFixture, categoricalMarket) proceedToNextRound(localFixture, categoricalMarket) # proceed to forking proceedToFork(localFixture, market, universe) with raises(TransactionFailed, message="We cannot migrate until the fork is finalized"): categoricalMarket.migrateThroughOneFork() # confirm that we can manually create a child universe from an outcome no one asserted was true during dispute numTicks = market.getNumTicks() childUniverse = universe.createChildUniverse( [numTicks / 4, numTicks * 3 / 4], False) # confirm that before the fork is finalized we can redeem stake in other markets crowdsourcers, which are disavowable categoricalDisputeCrowdsourcer = localFixture.applySignature( "DisputeCrowdsourcer", categoricalMarket.getReportingParticipant(1)) if manuallyDisavow: assert categoricalMarket.disavowCrowdsourcers() # We can redeem before the fork finalizes since disavowal has occured assert categoricalDisputeCrowdsourcer.redeem(tester.a0) # finalize the fork finalizeFork(localFixture, market, universe, finalizeByMigration) # The categorical market can be migrated to the winning universe assert categoricalMarket.migrateThroughOneFork() # The dispute crowdsourcer has been disavowed newUniverse = localFixture.applySignature("Universe", categoricalMarket.getUniverse()) assert newUniverse.address != universe.address assert categoricalDisputeCrowdsourcer.isDisavowed() assert not universe.isContainerForReportingParticipant( categoricalDisputeCrowdsourcer.address) assert not newUniverse.isContainerForReportingParticipant( categoricalDisputeCrowdsourcer.address) # The initial report is still present however categoricalInitialReport = localFixture.applySignature( "InitialReporter", categoricalMarket.getReportingParticipant(0)) assert categoricalMarket.getReportingParticipant( 0) == categoricalInitialReport.address assert not categoricalInitialReport.isDisavowed() assert not universe.isContainerForReportingParticipant( categoricalInitialReport.address) assert newUniverse.isContainerForReportingParticipant( categoricalInitialReport.address)
def test_forkAndRedeem(localFixture, universe, market, categoricalMarket, cash, reputationToken): # Let's do some initial disputes for the categorical market proceedToNextRound(localFixture, categoricalMarket, tester.k1, moveTimeForward = False) # Get to a fork testers = [tester.k0, tester.k1, tester.k2, tester.k3] testerIndex = 1 while (market.getForkingMarket() == longToHexString(0)): proceedToNextRound(localFixture, market, testers[testerIndex], True) testerIndex += 1 testerIndex = testerIndex % len(testers) # Have the participants fork and create new child universes for i in range(market.getNumParticipants()): reportingParticipant = localFixture.applySignature("DisputeCrowdsourcer", market.getReportingParticipant(i)) # Finalize the fork finalizeFork(localFixture, market, universe) categoricalDisputeCrowdsourcer = localFixture.applySignature("DisputeCrowdsourcer", categoricalMarket.getReportingParticipant(1)) # Migrate the categorical market into the winning universe. This will disavow the dispute crowdsourcer on it, letting us redeem for original universe rep and eth assert categoricalMarket.migrateThroughOneFork() expectedRep = categoricalDisputeCrowdsourcer.getStake() expectedEth = getExpectedFees(localFixture, cash, categoricalDisputeCrowdsourcer, 2) with EtherDelta(expectedEth, tester.a1, localFixture.chain, "Redeeming didn't increase ETH correctly"): with TokenDelta(reputationToken, expectedRep, tester.a1, "Redeeming didn't increase REP correctly"): categoricalDisputeCrowdsourcer.redeem(tester.a1) noPayoutNumerators = [0] * market.getNumberOfOutcomes() noPayoutNumerators[0] = market.getNumTicks() yesPayoutNumerators = noPayoutNumerators[::-1] noUniverse = localFixture.applySignature('Universe', universe.createChildUniverse(noPayoutNumerators, False)) yesUniverse = localFixture.applySignature('Universe', universe.createChildUniverse(yesPayoutNumerators, False)) noUniverseReputationToken = localFixture.applySignature('ReputationToken', noUniverse.getReputationToken()) yesUniverseReputationToken = localFixture.applySignature('ReputationToken', yesUniverse.getReputationToken()) # Now we'll fork and redeem the reporting participants for i in range(market.getNumParticipants()): account = localFixture.testerAddress[i % 4] key = localFixture.testerKey[i % 4] reportingParticipant = localFixture.applySignature("DisputeCrowdsourcer", market.getReportingParticipant(i)) expectedRep = reportingParticipant.getStake() expectedRep += expectedRep / localFixture.contracts["Constants"].FORK_MIGRATION_PERCENTAGE_BONUS_DIVISOR() expectedRep += reportingParticipant.getStake() / 2 repToken = noUniverseReputationToken if i % 2 == 0 else yesUniverseReputationToken with TokenDelta(repToken, expectedRep, account, "Redeeming didn't increase REP correctly for " + str(i)): assert reportingParticipant.forkAndRedeem(sender=key)
def test_forkAndRedeem(localFixture, universe, market, categoricalMarket, cash, reputationToken): # Let's do some initial disputes for the categorical market proceedToNextRound(localFixture, categoricalMarket, tester.k1, moveTimeForward = False) # Get to a fork testers = [tester.k0, tester.k1, tester.k2, tester.k3] testerIndex = 1 while (market.getForkingMarket() == longToHexString(0)): proceedToNextRound(localFixture, market, testers[testerIndex], True) testerIndex += 1 testerIndex = testerIndex % len(testers) # Have the participants fork and create new child universes for i in range(market.getNumParticipants()): reportingParticipant = localFixture.applySignature("DisputeCrowdsourcer", market.getReportingParticipant(i)) # Finalize the fork finalizeFork(localFixture, market, universe) categoricalDisputeCrowdsourcer = localFixture.applySignature("DisputeCrowdsourcer", categoricalMarket.getReportingParticipant(1)) # Migrate the categorical market into the winning universe. This will disavow the dispute crowdsourcer on it, letting us redeem for original universe rep and eth assert categoricalMarket.migrateThroughOneFork([0,0,categoricalMarket.getNumTicks()], False, "") expectedRep = categoricalDisputeCrowdsourcer.getStake() expectedEth = getExpectedFees(localFixture, cash, categoricalDisputeCrowdsourcer, 1) with EtherDelta(expectedEth, tester.a1, localFixture.chain, "Redeeming didn't increase ETH correctly"): with TokenDelta(reputationToken, expectedRep, tester.a1, "Redeeming didn't increase REP correctly"): categoricalDisputeCrowdsourcer.redeem(tester.a1) noPayoutNumerators = [0] * market.getNumberOfOutcomes() noPayoutNumerators[0] = market.getNumTicks() yesPayoutNumerators = noPayoutNumerators[::-1] noUniverse = localFixture.applySignature('Universe', universe.createChildUniverse(noPayoutNumerators, False)) yesUniverse = localFixture.applySignature('Universe', universe.createChildUniverse(yesPayoutNumerators, False)) noUniverseReputationToken = localFixture.applySignature('ReputationToken', noUniverse.getReputationToken()) yesUniverseReputationToken = localFixture.applySignature('ReputationToken', yesUniverse.getReputationToken()) # Now we'll fork and redeem the reporting participants for i in range(market.getNumParticipants()): account = localFixture.testerAddress[i % 4] key = localFixture.testerKey[i % 4] reportingParticipant = localFixture.applySignature("DisputeCrowdsourcer", market.getReportingParticipant(i)) expectedRep = reportingParticipant.getStake() expectedRep += reportingParticipant.getStake() / 2 repToken = noUniverseReputationToken if i % 2 == 0 else yesUniverseReputationToken with TokenDelta(repToken, expectedRep, account, "Redeeming didn't increase REP correctly for " + str(i)): assert reportingParticipant.forkAndRedeem(sender=key)
def test_forking_values(localFixture, universe, market, cash): reputationToken = localFixture.applySignature( "ReputationToken", universe.getReputationToken()) # proceed to forking proceedToFork(localFixture, market, universe) # finalize the fork finalizeFork(localFixture, market, universe) # We can see that the theoretical total REP supply in the winning child universe is higher than the initial REP supply winningPayoutHash = market.getWinningPayoutDistributionHash() childUniverse = localFixture.applySignature( "Universe", universe.getChildUniverse(winningPayoutHash)) childUniverseReputationToken = localFixture.applySignature( "ReputationToken", childUniverse.getReputationToken()) childUniverseTheoreticalSupply = childUniverseReputationToken.getTotalTheoreticalSupply( ) assert childUniverseTheoreticalSupply > reputationToken.getTotalTheoreticalSupply( ) # In fact it will be approximately the bonus REP migrated into the new universe more. delta = childUniverseTheoreticalSupply - reputationToken.getTotalTheoreticalSupply( ) migrationBonus = long(childUniverseReputationToken.getTotalMigrated() / 20L) participantIndex = 0 while True: try: reportingParticipant = localFixture.applySignature( "DisputeCrowdsourcer", market.getReportingParticipant(participantIndex)) participantIndex += 1 if reportingParticipant.getPayoutDistributionHash( ) != winningPayoutHash: continue migrationBonus += long(reportingParticipant.getSize() / 2L) except TransactionFailed: break assert delta == migrationBonus - 5 # rounding error dust buildup # The universe needs to be nudged to actually update values since there are potentially unbounded universes and updating the values derived by this total is not essential as a matter of normal procedure assert childUniverse.getForkReputationGoal( ) == universe.getForkReputationGoal() assert childUniverse.getDisputeThresholdForFork( ) == universe.getDisputeThresholdForFork() assert childUniverse.getInitialReportMinValue( ) == universe.getInitialReportMinValue() # The universe uses this theoretical total to calculate values such as the fork goal, fork dispute threshhold and the initial reporting defaults and floors assert childUniverse.updateForkValues() assert childUniverse.getForkReputationGoal( ) == childUniverseTheoreticalSupply / 2 assert childUniverse.getDisputeThresholdForFork() == long( childUniverseTheoreticalSupply / 40L) assert childUniverse.getInitialReportMinValue() == long( childUniverse.getDisputeThresholdForFork() / 3L / 2**18 + 1) # Now we'll fork again and confirm it still takes only 20 dispute rounds in the worst case newMarket = localFixture.createReasonableBinaryMarket(childUniverse, cash) proceedToFork(localFixture, newMarket, childUniverse) assert newMarket.getNumParticipants() == 21 # finalize the fork finalizeFork(localFixture, newMarket, childUniverse) # The total theoretical supply is again larger. childWinningPayoutHash = newMarket.getWinningPayoutDistributionHash() leafUniverse = localFixture.applySignature( "Universe", childUniverse.getChildUniverse(childWinningPayoutHash)) leafUniverseReputationToken = localFixture.applySignature( "ReputationToken", leafUniverse.getReputationToken()) leafUniverseTheoreticalSupply = leafUniverseReputationToken.getTotalTheoreticalSupply( ) assert leafUniverseTheoreticalSupply > childUniverseReputationToken.getTotalTheoreticalSupply( ) # We can make the child universe theoretical total more accurate by asking for a recomputation given a specific sibling universe to deduct from losingPayoutHash = market.derivePayoutDistributionHash( [0, market.getNumTicks()], False) siblingUniverse = localFixture.applySignature( "Universe", universe.getChildUniverse(losingPayoutHash)) siblingReputationToken = localFixture.applySignature( "ReputationToken", siblingUniverse.getReputationToken()) assert childUniverseReputationToken.updateSiblingMigrationTotal( siblingReputationToken.address) newChildTheoreticalSupply = childUniverseReputationToken.getTotalTheoreticalSupply( ) siblingMigrationAmount = siblingReputationToken.getTotalMigrated() assert childUniverseTheoreticalSupply - newChildTheoreticalSupply == siblingMigrationAmount # Now that the child universe has been updated we can ask the leaf universe to recompute based on its parent's new theoretical total supply assert leafUniverseReputationToken.updateParentTotalTheoreticalSupply() newLeafTheoreticalSupply = leafUniverseReputationToken.getTotalTheoreticalSupply( ) assert leafUniverseTheoreticalSupply - newLeafTheoreticalSupply == siblingMigrationAmount
def test_forking(finalizeByMigration, manuallyDisavow, localFixture, universe, market, categoricalMarket, scalarMarket): # Let's go into the one dispute round for the categorical market proceedToNextRound(localFixture, categoricalMarket) proceedToNextRound(localFixture, categoricalMarket) # proceed to forking proceedToFork(localFixture, market, universe) with raises(TransactionFailed, message="We cannot migrate until the fork is finalized"): categoricalMarket.migrateThroughOneFork() # confirm that we can manually create a child universe from an outcome no one asserted was true during dispute numTicks = market.getNumTicks() childUniverse = universe.createChildUniverse( [numTicks / 4, numTicks * 3 / 4], False) # confirm that before the fork is finalized we can redeem stake in other markets crowdsourcers, which are disavowable categoricalDisputeCrowdsourcer = localFixture.applySignature( "DisputeCrowdsourcer", categoricalMarket.getReportingParticipant(1)) if manuallyDisavow: assert categoricalMarket.disavowCrowdsourcers() # We can redeem before the fork finalizes since disavowal has occured assert categoricalDisputeCrowdsourcer.redeem(tester.a0) # We cannot contribute to a crowdsourcer during a fork with raises(TransactionFailed): categoricalMarket.contribute( [2, 2, categoricalMarket.getNumTicks() - 4], False, 1) # We cannot purchase new Participation Tokens during a fork feeWindowAddress = universe.getCurrentFeeWindow() feeWindow = localFixture.applySignature("FeeWindow", feeWindowAddress) with raises(TransactionFailed): feeWindow.buy(1) # finalize the fork finalizeFork(localFixture, market, universe, finalizeByMigration) # We cannot contribute to a crowdsourcer in a forked universe with raises(TransactionFailed): categoricalMarket.contribute( [2, 2, categoricalMarket.getNumTicks() - 4], False, 1) # The categorical market can be migrated to the winning universe assert categoricalMarket.migrateThroughOneFork() # The dispute crowdsourcer has been disavowed newUniverse = localFixture.applySignature("Universe", categoricalMarket.getUniverse()) assert newUniverse.address != universe.address assert categoricalDisputeCrowdsourcer.isDisavowed() assert not universe.isContainerForReportingParticipant( categoricalDisputeCrowdsourcer.address) assert not newUniverse.isContainerForReportingParticipant( categoricalDisputeCrowdsourcer.address) # The initial report is still present however categoricalInitialReport = localFixture.applySignature( "InitialReporter", categoricalMarket.getReportingParticipant(0)) assert categoricalMarket.getReportingParticipant( 0) == categoricalInitialReport.address assert not categoricalInitialReport.isDisavowed() assert not universe.isContainerForReportingParticipant( categoricalInitialReport.address) assert newUniverse.isContainerForReportingParticipant( categoricalInitialReport.address) # The categorical market has a new fee window since it was initially reported on and may be disputed now categoricalMarketFeeWindowAddress = categoricalMarket.getFeeWindow() categoricalMarketFeeWindow = localFixture.applySignature( "FeeWindow", categoricalMarketFeeWindowAddress) proceedToNextRound(localFixture, categoricalMarket, moveTimeForward=False) # We can also purchase Participation Tokens in this fee window assert categoricalMarketFeeWindow.buy(1) # We will finalize the categorical market in the new universe feeWindow = localFixture.applySignature('FeeWindow', categoricalMarket.getFeeWindow()) localFixture.contracts["Time"].setTimestamp(feeWindow.getEndTime() + 1) assert categoricalMarket.finalize() # We can migrate a market that has not had its initial reporting completed as well, and confirm its REP no show bond is in the new universe REP reputationToken = localFixture.applySignature( "ReputationToken", universe.getReputationToken()) previousREPBalance = reputationToken.balanceOf(scalarMarket.address) assert previousREPBalance > 0 bonus = previousREPBalance / localFixture.contracts[ "Constants"].FORK_MIGRATION_PERCENTAGE_BONUS_DIVISOR( ) if finalizeByMigration else 0 assert scalarMarket.migrateThroughOneFork() newUniverseREP = localFixture.applySignature( "ReputationToken", newUniverse.getReputationToken()) assert newUniverseREP.balanceOf( scalarMarket.address) == previousREPBalance + bonus # We can finalize this market as well proceedToNextRound(localFixture, scalarMarket) feeWindow = localFixture.applySignature('FeeWindow', scalarMarket.getFeeWindow()) localFixture.contracts["Time"].setTimestamp(feeWindow.getEndTime() + 1) assert scalarMarket.finalize()
def test_forking(localFixture, universe, market, categoricalMarket, cash, reputationToken): # Let's do some initial disputes for the categorical market proceedToNextRound(localFixture, categoricalMarket, tester.k1, moveTimeForward=False) # Get to a fork testers = [tester.k0, tester.k1, tester.k2, tester.k3] testerIndex = 1 while (market.getForkingMarket() == longToHexString(0)): proceedToNextRound(localFixture, market, testers[testerIndex], True) testerIndex += 1 testerIndex = testerIndex % len(testers) # Have the participants fork and create new child universes for i in range(market.getNumParticipants()): reportingParticipant = localFixture.applySignature( "DisputeCrowdsourcer", market.getReportingParticipant(i)) with PrintGasUsed(localFixture, "Fork:", 0): reportingParticipant.fork(startgas=long(6.7 * 10**6)) # Finalize the fork finalizeFork(localFixture, market, universe) categoricalDisputeCrowdsourcer = localFixture.applySignature( "DisputeCrowdsourcer", categoricalMarket.getReportingParticipant(1)) # Migrate the categorical market into the winning universe. This will disavow the dispute crowdsourcer on it, letting us redeem for original universe rep and eth assert categoricalMarket.migrateThroughOneFork() expectedRep = categoricalDisputeCrowdsourcer.getStake() expectedEth = getExpectedFees(localFixture, cash, categoricalDisputeCrowdsourcer, 2) with EtherDelta(expectedEth, tester.a1, localFixture.chain, "Redeeming didn't increase ETH correctly"): with TokenDelta(reputationToken, expectedRep, tester.a1, "Redeeming didn't increase REP correctly"): categoricalDisputeCrowdsourcer.redeem(tester.a1, startgas=long(6.7 * 10**6)) # Now we'll redeem the forked reporting participants testers = [tester.a0, tester.a1, tester.a2, tester.a3] for i in range(market.getNumParticipants()): account = testers[i % 4] reportingParticipant = localFixture.applySignature( "DisputeCrowdsourcer", market.getReportingParticipant(i)) expectedRep = reportingParticipant.getStake() expectedRep += expectedRep / localFixture.contracts[ "Constants"].FORK_MIGRATION_PERCENTAGE_BONUS_DIVISOR() expectedRep += reportingParticipant.getStake() / 2 expectedEth = cash.balanceOf(reportingParticipant.address) newReputationToken = localFixture.applySignature( "ReputationToken", reportingParticipant.getReputationToken()) with EtherDelta(expectedEth, account, localFixture.chain, "Redeeming didn't increase ETH correctly"): with TokenDelta(newReputationToken, expectedRep, account, "Redeeming didn't increase REP correctly"): reportingParticipant.redeem(account, startgas=long(6.7 * 10**6))
def test_forking_values(localFixture, universe, market): reputationToken = localFixture.applySignature("ReputationToken", universe.getReputationToken()) # Give some REP to another account reputationToken.transfer(tester.a1, 100) # proceed to forking proceedToFork(localFixture, market, universe) # finalize the fork finalizeFork(localFixture, market, universe) # We can see that the theoretical total REP supply in the winning child universe is equal to the parent supply winningPayoutHash = market.getWinningPayoutDistributionHash() childUniverse = localFixture.applySignature("Universe", universe.getChildUniverse(winningPayoutHash)) childUniverseReputationToken = localFixture.applySignature("ReputationToken", childUniverse.getReputationToken()) childUniverseTheoreticalSupply = childUniverseReputationToken.getTotalTheoreticalSupply() assert childUniverseTheoreticalSupply == reputationToken.getTotalTheoreticalSupply() # If we nudge the reputation token to update its theoretical balance we can see a lower total to account for sibling migrations assert childUniverseReputationToken.updateTotalTheoreticalSupply() assert childUniverseReputationToken.getTotalTheoreticalSupply() <= childUniverseTheoreticalSupply childUniverseTheoreticalSupply = childUniverseReputationToken.getTotalTheoreticalSupply() # If we migrate some REP to another Universe we can recalculate and see that amount deducted from the theoretical supply losingPayoutNumerators = [0, 0, market.getNumTicks()] losingUniverse = localFixture.applySignature('Universe', universe.createChildUniverse(losingPayoutNumerators)) losingUniverseReputationToken = localFixture.applySignature('ReputationToken', losingUniverse.getReputationToken()) assert reputationToken.migrateOut(losingUniverseReputationToken.address, 100, sender=tester.k1) assert childUniverseReputationToken.updateTotalTheoreticalSupply() lowerChildUniverseTheoreticalSupply = childUniverseReputationToken.getTotalTheoreticalSupply() assert lowerChildUniverseTheoreticalSupply == childUniverseTheoreticalSupply - 100 # If we move past the forking window end time and we update the theoretical supply however we will see that some REP was trapped in the parent and deducted from the supply localFixture.contracts["Time"].setTimestamp(universe.getForkEndTime() + 1) assert childUniverseReputationToken.updateTotalTheoreticalSupply() childUniverseTheoreticalSupply = childUniverseReputationToken.getTotalTheoreticalSupply() assert childUniverseTheoreticalSupply < lowerChildUniverseTheoreticalSupply # The universe needs to be nudged to actually update values since there are potentially unbounded universes and updating the values derived by this total is not essential as a matter of normal procedure # In a forked universe the total supply will be different so its childrens goals will not be the same initially if not localFixture.subFork: assert childUniverse.getForkReputationGoal() == universe.getForkReputationGoal() assert childUniverse.getDisputeThresholdForFork() == universe.getDisputeThresholdForFork() assert childUniverse.getInitialReportMinValue() == universe.getInitialReportMinValue() # The universe uses this theoretical total to calculate values such as the fork goal, fork dispute threshhold and the initial reporting defaults and floors assert childUniverse.updateForkValues() assert childUniverse.getForkReputationGoal() == childUniverseTheoreticalSupply / 2 assert childUniverse.getDisputeThresholdForFork() == long(childUniverseTheoreticalSupply / 40L) assert childUniverse.getInitialReportMinValue() == long(childUniverse.getDisputeThresholdForFork() / 3L / 2**18 + 1) # Now we'll fork again and confirm it still takes only 20 dispute rounds in the worst case newMarket = localFixture.createReasonableYesNoMarket(childUniverse) proceedToFork(localFixture, newMarket, childUniverse) assert newMarket.getNumParticipants() == 21 # finalize the fork finalizeFork(localFixture, newMarket, childUniverse) # The total theoretical supply is again the same as the parents during the fork childWinningPayoutHash = newMarket.getWinningPayoutDistributionHash() leafUniverse = localFixture.applySignature("Universe", childUniverse.getChildUniverse(childWinningPayoutHash)) leafUniverseReputationToken = localFixture.applySignature("ReputationToken", leafUniverse.getReputationToken()) leafUniverseTheoreticalSupply = leafUniverseReputationToken.getTotalTheoreticalSupply() assert leafUniverseTheoreticalSupply == childUniverseReputationToken.getTotalTheoreticalSupply() # After the fork window ends however we can again recalculate localFixture.contracts["Time"].setTimestamp(childUniverse.getForkEndTime() + 1) assert leafUniverseReputationToken.updateTotalTheoreticalSupply() leafUniverseTheoreticalSupply = leafUniverseReputationToken.getTotalTheoreticalSupply() assert leafUniverseTheoreticalSupply < childUniverseReputationToken.getTotalTheoreticalSupply()
def test_forking(finalizeByMigration, manuallyDisavow, localFixture, universe, market, categoricalMarket, scalarMarket): # Let's go into the one dispute round for the categorical market proceedToNextRound(localFixture, categoricalMarket) proceedToNextRound(localFixture, categoricalMarket) # proceed to forking proceedToFork(localFixture, market, universe) with raises(TransactionFailed): universe.fork() with raises(TransactionFailed, message="We cannot migrate until the fork is finalized"): categoricalMarket.migrateThroughOneFork([0,0,0,categoricalMarket.getNumTicks()], "") with raises(TransactionFailed, message="We cannot create markets during a fork"): time = localFixture.contracts["Time"].getTimestamp() localFixture.createYesNoMarket(universe, time + 1000, 1, tester.a0) # confirm that we can manually create a child universe from an outcome no one asserted was true during dispute numTicks = market.getNumTicks() childUniverse = universe.createChildUniverse([0, numTicks/ 4, numTicks * 3 / 4]) # confirm that before the fork is finalized we can redeem stake in other markets crowdsourcers, which are disavowable categoricalDisputeCrowdsourcer = localFixture.applySignature("DisputeCrowdsourcer", categoricalMarket.getReportingParticipant(1)) # confirm we cannot liquidate it with raises(TransactionFailed): categoricalDisputeCrowdsourcer.liquidateLosing() # confirm we cannot fork it with raises(TransactionFailed): categoricalDisputeCrowdsourcer.forkAndRedeem() if manuallyDisavow: marketParticipantsDisavowedLog = { "universe": universe.address, "market": categoricalMarket.address, } with AssertLog(localFixture, "MarketParticipantsDisavowed", marketParticipantsDisavowedLog): assert categoricalMarket.disavowCrowdsourcers() # We can redeem before the fork finalizes since disavowal has occured assert categoricalDisputeCrowdsourcer.redeem(tester.a0) # We cannot contribute to a crowdsourcer during a fork with raises(TransactionFailed): categoricalMarket.contribute([0,2,2,categoricalMarket.getNumTicks()-4], 1, "") # We cannot purchase new Participation Tokens during a fork disputeWindowAddress = universe.getCurrentDisputeWindow() disputeWindow = localFixture.applySignature("DisputeWindow", disputeWindowAddress) # finalize the fork marketFinalizedLog = { "universe": universe.address, "market": market.address, } with AssertLog(localFixture, "MarketFinalized", marketFinalizedLog): finalizeFork(localFixture, market, universe, finalizeByMigration) # We cannot contribute to a crowdsourcer in a forked universe with raises(TransactionFailed): categoricalMarket.contribute([0,2,2,categoricalMarket.getNumTicks()-4], 1, "") newUniverseAddress = universe.getWinningChildUniverse() # buy some complete sets to change OI completeSets = localFixture.contracts['CompleteSets'] numSets = 10 cost = categoricalMarket.getNumTicks() * numSets assert completeSets.publicBuyCompleteSets(categoricalMarket.address, 10, sender=tester.k1, value=cost) assert universe.getOpenInterestInAttoEth() == cost marketMigratedLog = { "market": categoricalMarket.address, "newUniverse": newUniverseAddress, "originalUniverse": universe.address, } with AssertLog(localFixture, "MarketMigrated", marketMigratedLog): assert categoricalMarket.migrateThroughOneFork([0,0,0,categoricalMarket.getNumTicks()], "") assert universe.getOpenInterestInAttoEth() == 0 # The dispute crowdsourcer has been disavowed newUniverse = localFixture.applySignature("Universe", categoricalMarket.getUniverse()) assert newUniverse.address != universe.address assert categoricalDisputeCrowdsourcer.isDisavowed() assert not universe.isContainerForReportingParticipant(categoricalDisputeCrowdsourcer.address) assert not newUniverse.isContainerForReportingParticipant(categoricalDisputeCrowdsourcer.address) assert newUniverse.getOpenInterestInAttoEth() == cost # The initial report is still present however categoricalInitialReport = localFixture.applySignature("InitialReporter", categoricalMarket.getReportingParticipant(0)) assert categoricalMarket.getReportingParticipant(0) == categoricalInitialReport.address assert not categoricalInitialReport.isDisavowed() assert not universe.isContainerForReportingParticipant(categoricalInitialReport.address) assert newUniverse.isContainerForReportingParticipant(categoricalInitialReport.address) # The categorical market has a new dispute window since it was initially reported on and may be disputed now categoricalMarketDisputeWindowAddress = categoricalMarket.getDisputeWindow() categoricalMarketDisputeWindow = localFixture.applySignature("DisputeWindow", categoricalMarketDisputeWindowAddress) proceedToNextRound(localFixture, categoricalMarket) # We will finalize the categorical market in the new universe disputeWindow = localFixture.applySignature('DisputeWindow', categoricalMarket.getDisputeWindow()) localFixture.contracts["Time"].setTimestamp(disputeWindow.getEndTime() + 1) assert categoricalMarket.finalize() # We can migrate a market that has not had its initial reporting completed as well, and confirm that the report is now made in the new universe reputationToken = localFixture.applySignature("ReputationToken", universe.getReputationToken()) previousREPBalance = reputationToken.balanceOf(scalarMarket.address) assert previousREPBalance > 0 assert scalarMarket.migrateThroughOneFork([0,0,scalarMarket.getNumTicks()], "") newUniverseREP = localFixture.applySignature("ReputationToken", newUniverse.getReputationToken()) initialReporter = localFixture.applySignature('InitialReporter', scalarMarket.getInitialReporter()) assert newUniverseREP.balanceOf(initialReporter.address) == newUniverse.getOrCacheDesignatedReportNoShowBond() # We can finalize this market as well proceedToNextRound(localFixture, scalarMarket) disputeWindow = localFixture.applySignature('DisputeWindow', scalarMarket.getDisputeWindow()) localFixture.contracts["Time"].setTimestamp(disputeWindow.getEndTime() + 1) assert scalarMarket.finalize()
def test_forking_values(localFixture, universe, market, cash): reputationToken = localFixture.applySignature("ReputationToken", universe.getReputationToken()) # proceed to forking proceedToFork(localFixture, market, universe) # finalize the fork finalizeFork(localFixture, market, universe) # We can see that the theoretical total REP supply in the winning child universe is higher than the initial REP supply winningPayoutHash = market.getWinningPayoutDistributionHash() childUniverse = localFixture.applySignature("Universe", universe.getChildUniverse(winningPayoutHash)) childUniverseReputationToken = localFixture.applySignature("ReputationToken", childUniverse.getReputationToken()) childUniverseTheoreticalSupply = childUniverseReputationToken.getTotalTheoreticalSupply() assert childUniverseTheoreticalSupply > reputationToken.getTotalTheoreticalSupply() # In fact it will be approximately the bonus REP migrated into the new universe more. delta = childUniverseTheoreticalSupply - reputationToken.getTotalTheoreticalSupply() migrationBonus = long(childUniverseReputationToken.getTotalMigrated() / 20L) participantIndex = 0 while True: try: reportingParticipant = localFixture.applySignature("DisputeCrowdsourcer", market.getReportingParticipant(participantIndex)) participantIndex += 1 if reportingParticipant.getPayoutDistributionHash() != winningPayoutHash: continue migrationBonus += long(reportingParticipant.getSize() / 2L) except TransactionFailed: break assert delta == migrationBonus - 5 # rounding error dust buildup # The universe needs to be nudged to actually update values since there are potentially unbounded universes and updating the values derived by this total is not essential as a matter of normal procedure assert childUniverse.getForkReputationGoal() == universe.getForkReputationGoal() assert childUniverse.getDisputeThresholdForFork() == universe.getDisputeThresholdForFork() assert childUniverse.getInitialReportMinValue() == universe.getInitialReportMinValue() # The universe uses this theoretical total to calculate values such as the fork goal, fork dispute threshhold and the initial reporting defaults and floors assert childUniverse.updateForkValues() assert childUniverse.getForkReputationGoal() == childUniverseTheoreticalSupply / 2 assert childUniverse.getDisputeThresholdForFork() == long(childUniverseTheoreticalSupply / 40L) assert childUniverse.getInitialReportMinValue() == long(childUniverse.getDisputeThresholdForFork() / 3L / 2**18 + 1) # Now we'll fork again and confirm it still takes only 20 dispute rounds in the worst case newMarket = localFixture.createReasonableBinaryMarket(childUniverse, cash) proceedToFork(localFixture, newMarket, childUniverse) assert newMarket.getNumParticipants() == 21 # finalize the fork finalizeFork(localFixture, newMarket, childUniverse) # The total theoretical supply is again larger. childWinningPayoutHash = newMarket.getWinningPayoutDistributionHash() leafUniverse = localFixture.applySignature("Universe", childUniverse.getChildUniverse(childWinningPayoutHash)) leafUniverseReputationToken = localFixture.applySignature("ReputationToken", leafUniverse.getReputationToken()) leafUniverseTheoreticalSupply = leafUniverseReputationToken.getTotalTheoreticalSupply() assert leafUniverseTheoreticalSupply > childUniverseReputationToken.getTotalTheoreticalSupply() # We can make the child universe theoretical total more accurate by asking for a recomputation given a specific sibling universe to deduct from losingPayoutHash = market.derivePayoutDistributionHash([0, market.getNumTicks()], False) siblingUniverse = localFixture.applySignature("Universe", universe.getChildUniverse(losingPayoutHash)) siblingReputationToken = localFixture.applySignature("ReputationToken", siblingUniverse.getReputationToken()) assert childUniverseReputationToken.updateSiblingMigrationTotal(siblingReputationToken.address) newChildTheoreticalSupply = childUniverseReputationToken.getTotalTheoreticalSupply() siblingMigrationAmount = siblingReputationToken.getTotalMigrated() assert childUniverseTheoreticalSupply - newChildTheoreticalSupply == siblingMigrationAmount # Now that the child universe has been updated we can ask the leaf universe to recompute based on its parent's new theoretical total supply assert leafUniverseReputationToken.updateParentTotalTheoreticalSupply() newLeafTheoreticalSupply = leafUniverseReputationToken.getTotalTheoreticalSupply() assert leafUniverseTheoreticalSupply - newLeafTheoreticalSupply == siblingMigrationAmount
def test_forking(finalizeByMigration, manuallyDisavow, localFixture, universe, cash, market, categoricalMarket, scalarMarket): # Let's go into the one dispute round for the categorical market proceedToNextRound(localFixture, categoricalMarket) proceedToNextRound(localFixture, categoricalMarket) # proceed to forking proceedToFork(localFixture, market, universe) with raises(TransactionFailed): universe.fork() with raises(TransactionFailed, message="We cannot migrate until the fork is finalized"): categoricalMarket.migrateThroughOneFork() with raises(TransactionFailed, message="We cannot create markets during a fork"): time = localFixture.contracts["Time"].getTimestamp() localFixture.createBinaryMarket(universe, time + 1000, 1, cash, tester.a0) # confirm that we can manually create a child universe from an outcome no one asserted was true during dispute numTicks = market.getNumTicks() childUniverse = universe.createChildUniverse([numTicks/ 4, numTicks * 3 / 4], False) # confirm that before the fork is finalized we can redeem stake in other markets crowdsourcers, which are disavowable categoricalDisputeCrowdsourcer = localFixture.applySignature("DisputeCrowdsourcer", categoricalMarket.getReportingParticipant(1)) # confirm we cannot migrate it with raises(TransactionFailed): categoricalDisputeCrowdsourcer.migrate() # confirm we cannot liquidate it with raises(TransactionFailed): categoricalDisputeCrowdsourcer.liquidateLosing() # confirm we cannot fork it with raises(TransactionFailed): categoricalDisputeCrowdsourcer.fork() if manuallyDisavow: marketParticipantsDisavowedLog = { "universe": universe.address, "market": categoricalMarket.address, } with AssertLog(localFixture, "MarketParticipantsDisavowed", marketParticipantsDisavowedLog): assert categoricalMarket.disavowCrowdsourcers() # We can redeem before the fork finalizes since disavowal has occured assert categoricalDisputeCrowdsourcer.redeem(tester.a0) # We cannot contribute to a crowdsourcer during a fork with raises(TransactionFailed): categoricalMarket.contribute([2,2,categoricalMarket.getNumTicks()-4], False, 1) # We cannot purchase new Participation Tokens during a fork feeWindowAddress = universe.getCurrentFeeWindow() feeWindow = localFixture.applySignature("FeeWindow", feeWindowAddress) with raises(TransactionFailed): feeWindow.buy(1) # finalize the fork marketFinalizedLog = { "universe": universe.address, "market": market.address, } with AssertLog(localFixture, "MarketFinalized", marketFinalizedLog): finalizeFork(localFixture, market, universe, finalizeByMigration) # We cannot contribute to a crowdsourcer in a forked universe with raises(TransactionFailed): categoricalMarket.contribute([2,2,categoricalMarket.getNumTicks()-4], False, 1) # The categorical market can be migrated to the winning universe newUniverseAddress = universe.getWinningChildUniverse() marketMigratedLog = { "market": categoricalMarket.address, "newUniverse": newUniverseAddress, "originalUniverse": universe.address, } with AssertLog(localFixture, "MarketMigrated", marketMigratedLog): assert categoricalMarket.migrateThroughOneFork() # The dispute crowdsourcer has been disavowed newUniverse = localFixture.applySignature("Universe", categoricalMarket.getUniverse()) assert newUniverse.address != universe.address assert categoricalDisputeCrowdsourcer.isDisavowed() assert not universe.isContainerForReportingParticipant(categoricalDisputeCrowdsourcer.address) assert not newUniverse.isContainerForReportingParticipant(categoricalDisputeCrowdsourcer.address) # The initial report is still present however categoricalInitialReport = localFixture.applySignature("InitialReporter", categoricalMarket.getReportingParticipant(0)) assert categoricalMarket.getReportingParticipant(0) == categoricalInitialReport.address assert not categoricalInitialReport.isDisavowed() assert not universe.isContainerForReportingParticipant(categoricalInitialReport.address) assert newUniverse.isContainerForReportingParticipant(categoricalInitialReport.address) # The categorical market has a new fee window since it was initially reported on and may be disputed now categoricalMarketFeeWindowAddress = categoricalMarket.getFeeWindow() categoricalMarketFeeWindow = localFixture.applySignature("FeeWindow", categoricalMarketFeeWindowAddress) proceedToNextRound(localFixture, categoricalMarket, moveTimeForward = False) # We can also purchase Participation Tokens in this fee window assert categoricalMarketFeeWindow.buy(1) # We will finalize the categorical market in the new universe feeWindow = localFixture.applySignature('FeeWindow', categoricalMarket.getFeeWindow()) localFixture.contracts["Time"].setTimestamp(feeWindow.getEndTime() + 1) assert categoricalMarket.finalize() # We can migrate a market that has not had its initial reporting completed as well, and confirm its REP no show bond is in the new universe REP reputationToken = localFixture.applySignature("ReputationToken", universe.getReputationToken()) previousREPBalance = reputationToken.balanceOf(scalarMarket.address) assert previousREPBalance > 0 bonus = previousREPBalance / localFixture.contracts["Constants"].FORK_MIGRATION_PERCENTAGE_BONUS_DIVISOR() if finalizeByMigration else 0 assert scalarMarket.migrateThroughOneFork() newUniverseREP = localFixture.applySignature("ReputationToken", newUniverse.getReputationToken()) assert newUniverseREP.balanceOf(scalarMarket.address) == previousREPBalance + bonus # We can finalize this market as well proceedToNextRound(localFixture, scalarMarket) feeWindow = localFixture.applySignature('FeeWindow', scalarMarket.getFeeWindow()) localFixture.contracts["Time"].setTimestamp(feeWindow.getEndTime() + 1) assert scalarMarket.finalize()