def test_warp_sync_gets_forked(contractsFixture, augur, universe, reputationToken, warpSync): account = contractsFixture.accounts[0] time = contractsFixture.contracts["Time"] # See warp sync market warpSync.initializeUniverse(universe.address) market = contractsFixture.applySignature( "Market", warpSync.markets(universe.address)) # Fork warp sync market proceedToFork(contractsFixture, market, universe) finalize(contractsFixture, market, universe) # See that market finalizes but no new warp sync market exists assert market.isFinalized() assert market.address == warpSync.markets(universe.address) # See warp sync markets dont exists for child universes initially until initialization shortPayoutNumerators = [0] * market.getNumberOfOutcomes() shortPayoutNumerators[1] = market.getNumTicks() longPayoutNumerators = [0] * market.getNumberOfOutcomes() longPayoutNumerators[2] = market.getNumTicks() shortUniverse = contractsFixture.applySignature( 'Universe', universe.createChildUniverse(shortPayoutNumerators)) longUniverse = contractsFixture.applySignature( 'Universe', universe.createChildUniverse(longPayoutNumerators)) warpSync.initializeUniverse(shortUniverse.address) warpSync.initializeUniverse(longUniverse.address) shortUniverseMarket = contractsFixture.applySignature( "Market", warpSync.markets(shortUniverse.address)) longUniverseMarket = contractsFixture.applySignature( "Market", warpSync.markets(longUniverse.address)) assert shortUniverseMarket.address != nullAddress assert longUniverseMarket.address != nullAddress # Initially there is no warp sync data for the child universe assert warpSync.data(shortUniverseMarket.address) == [0, 0] # Finalize the warp sync market with some value proceedToInitialReporting(contractsFixture, shortUniverseMarket) numTicks = shortUniverseMarket.getNumTicks() assert shortUniverseMarket.doInitialReport([0, 0, numTicks], "", 0) disputeWindow = contractsFixture.applySignature( "DisputeWindow", shortUniverseMarket.getDisputeWindow()) time.setTimestamp(disputeWindow.getEndTime()) assert shortUniverseMarket.finalize() # Check Warp Sync contract for universe and see existing value assert warpSync.data( shortUniverse.address) == [numTicks, shortUniverseMarket.getEndTime()] # See new warp sync market newWarpSyncMarket = contractsFixture.applySignature( "Market", warpSync.markets(shortUniverse.address)) assert newWarpSyncMarket.address != shortUniverseMarket.address
def test_warp_sync_in_fork(contractsFixture, augur, universe, reputationToken, warpSync, market): account = contractsFixture.accounts[0] time = contractsFixture.contracts["Time"] # Get warp sync market warpSync.initializeUniverse(universe.address) warpMarket = contractsFixture.applySignature( "Market", warpSync.markets(universe.address)) # Fork the standard market proceedToFork(contractsFixture, market, universe) finalize(contractsFixture, market, universe) # See that we cannot migrate the warp sync market numTicks = market.getNumTicks() with raises(TransactionFailed): assert warpMarket.migrateThroughOneFork([0, 0, numTicks], "") # Instead we just create a new warp sync market as usual for the new universe winningUniverse = universe.getChildUniverse( market.getWinningPayoutDistributionHash()) warpSync.initializeUniverse(winningUniverse) # The market now exists assert not warpSync.markets(winningUniverse) == nullAddress
def test_finalized_fork_migration(localFixture, universe, market, categoricalMarket): # Make the categorical market finalized proceedToNextRound(localFixture, categoricalMarket) disputeWindow = localFixture.applySignature('DisputeWindow', categoricalMarket.getDisputeWindow()) # Time marches on and the market can be finalized localFixture.contracts["Time"].setTimestamp(disputeWindow.getEndTime() + 1) assert categoricalMarket.finalize() # Proceed to Forking for the yesNo market and finalize it proceedToFork(localFixture, market, universe) finalize(localFixture, market, universe) # The categorical market is finalized and cannot be migrated to the new universe with raises(TransactionFailed): categoricalMarket.migrateThroughOneFork([0,0,0,categoricalMarket.getNumTicks()], "") # 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([0,0,market.getNumTicks()], "") with raises(TransactionFailed): market.disavowCrowdsourcers()
def test_fork_migration_no_report(localFixture, universe, market): # 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 = localFixture.contracts["Time"].getTimestamp() + timedelta( days=90).total_seconds() longMarket = localFixture.createYesNoMarket(universe, endTime, 1, 0, localFixture.accounts[0]) # Go to the forking period proceedToFork(localFixture, market, universe) # Now finalize the fork so migration can occur finalize(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([], "")
def test_forking_values(localFixture, universe, market): reputationToken = localFixture.applySignature("ReputationToken", universe.getReputationToken()) # Give some REP to another account reputationToken.transfer(localFixture.accounts[1], 100) # proceed to forking proceedToFork(localFixture, market, universe) # finalize the fork finalize(localFixture, market, universe) # We can see that the theoretical total REP supply in the winning child universe is a lower total to account for sibling migrations winningPayoutHash = market.getWinningPayoutDistributionHash() childUniverse = localFixture.applySignature("Universe", universe.getChildUniverse(winningPayoutHash)) childUniverseReputationToken = localFixture.applySignature("ReputationToken", childUniverse.getReputationToken()) childUniverseTheoreticalSupply = childUniverseReputationToken.getTotalTheoreticalSupply() assert childUniverseReputationToken.getTotalTheoreticalSupply() <= childUniverseTheoreticalSupply # If we migrate some REP to another Universe we can 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.migrateOutByPayout(losingPayoutNumerators, 100, sender=localFixture.accounts[1]) lowerChildUniverseTheoreticalSupply = childUniverseReputationToken.getTotalTheoreticalSupply() assert lowerChildUniverseTheoreticalSupply == childUniverseTheoreticalSupply - 100 # If we move past the forking window end time however we will see that some REP was trapped in the parent and deducted from the supply localFixture.contracts["Time"].setTimestamp(universe.getForkEndTime() + 1) childUniverseTheoreticalSupply = childUniverseReputationToken.getTotalTheoreticalSupply() assert childUniverseTheoreticalSupply < lowerChildUniverseTheoreticalSupply # In a forked universe the total supply will be different so its childrens goals will not be the same initially childUniverse.updateForkValues() assert childUniverse.getForkReputationGoal() == int(Decimal(childUniverseTheoreticalSupply) / 2) assert childUniverse.getDisputeThresholdForFork() == int(Decimal(childUniverseTheoreticalSupply) / 40) assert childUniverse.getInitialReportMinValue() == int(Decimal(childUniverse.getDisputeThresholdForFork()) / 3 / 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 finalize(localFixture, newMarket, childUniverse) # The total theoretical supply is the total supply of the token plus that of the parent childWinningPayoutHash = newMarket.getWinningPayoutDistributionHash() leafUniverse = localFixture.applySignature("Universe", childUniverse.getChildUniverse(childWinningPayoutHash)) leafUniverseReputationToken = localFixture.applySignature("ReputationToken", leafUniverse.getReputationToken()) leafUniverseTheoreticalSupply = leafUniverseReputationToken.getTotalTheoreticalSupply() assert leafUniverseTheoreticalSupply == leafUniverseReputationToken.totalSupply() + childUniverseReputationToken.totalSupply() # After the fork window ends however we can again recalculate localFixture.contracts["Time"].setTimestamp(childUniverse.getForkEndTime() + 1) leafUniverseTheoreticalSupply = leafUniverseReputationToken.getTotalTheoreticalSupply() assert leafUniverseTheoreticalSupply == leafUniverseReputationToken.totalSupply()
def test_forked_symbol(contractsFixture, universe, market, scalarMarket): account0 = contractsFixture.accounts[0] endTime = contractsFixture.contracts["Time"].getTimestamp() + 1000 categoricalMarket = contractsFixture.createCategoricalMarket( universe, 3, endTime, 0, 0, account0, ["Trump", "Warren", "Yang"]) # proceed to forking proceedToFork(contractsFixture, market, universe) # finalize the fork finalize(contractsFixture, market, universe) # Migrate the markets assert scalarMarket.migrateThroughOneFork( [0, 0, scalarMarket.getNumTicks()], "") assert categoricalMarket.migrateThroughOneFork( [0, 0, 0, categoricalMarket.getNumTicks()], "") newUniverse = contractsFixture.applySignature("Universe", scalarMarket.getUniverse()) fork1ReputationToken = contractsFixture.applySignature( "ReputationToken", newUniverse.getReputationToken()) assert fork1ReputationToken.symbol() == "REPv2_NO_1" # Fork the scalar market proceedToFork(contractsFixture, scalarMarket, newUniverse) # finalize the fork finalize(contractsFixture, scalarMarket, newUniverse) # Migrate the cat market assert categoricalMarket.migrateThroughOneFork( [0, 0, 0, categoricalMarket.getNumTicks()], "") newUniverse = contractsFixture.applySignature( "Universe", categoricalMarket.getUniverse()) fork2ReputationToken = contractsFixture.applySignature( "ReputationToken", newUniverse.getReputationToken()) assert fork2ReputationToken.symbol() == "REPv2_0_2" # Fork the categorical market proceedToFork(contractsFixture, categoricalMarket, newUniverse) # Create a child universe and check its REP symbol: newUniverse = contractsFixture.applySignature( "Universe", newUniverse.createChildUniverse([0, 100, 0, 0])) fork3ReputationToken = contractsFixture.applySignature( "ReputationToken", newUniverse.getReputationToken()) assert fork3ReputationToken.symbol() == "REPv2_Trump_3"
def test_forkAndRedeem(localFixture, universe, market, categoricalMarket, cash, reputationToken): # Let's do some initial disputes for the categorical market proceedToNextRound(localFixture, categoricalMarket, localFixture.accounts[1], moveTimeForward = False) # Get to a fork testers = [localFixture.accounts[0], localFixture.accounts[1], localFixture.accounts[2], localFixture.accounts[3]] 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 finalize(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 assert categoricalMarket.migrateThroughOneFork([0,0,0,categoricalMarket.getNumTicks()], "") expectedRep = categoricalDisputeCrowdsourcer.getStake() with TokenDelta(reputationToken, expectedRep, localFixture.accounts[1], "Redeeming didn't increase REP correctly"): categoricalDisputeCrowdsourcer.redeem(localFixture.accounts[1]) noPayoutNumerators = [0] * market.getNumberOfOutcomes() noPayoutNumerators[1] = market.getNumTicks() yesPayoutNumerators = [0] * market.getNumberOfOutcomes() yesPayoutNumerators[2] = market.getNumTicks() noUniverse = localFixture.applySignature('Universe', universe.createChildUniverse(noPayoutNumerators)) yesUniverse = localFixture.applySignature('Universe', universe.createChildUniverse(yesPayoutNumerators)) 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.accounts[i % 4] reportingParticipant = localFixture.applySignature("DisputeCrowdsourcer", market.getReportingParticipant(i)) expectedRep = reputationToken.balanceOf(reportingParticipant.address) * 7 / 5 # * 1.4 to account for the minting reward of 40% 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=account)
def test_completeSets_fork(contractsFixture, augur, universe, cash, market, scalarMarket): if not contractsFixture.paraAugur: return shareToken = contractsFixture.getShareToken() openInterestCashAddress = getOpenInterestCashAddress( contractsFixture, universe) openInterestCash = contractsFixture.applySignature( "ParaOICash", openInterestCashAddress) account1 = contractsFixture.accounts[0] depositAmount = 10 * 10**18 assert cash.faucet(depositAmount) with TokenDelta(cash, -depositAmount, account1): assert openInterestCash.deposit(depositAmount) # Now we'll cause a fork and migrate the market paraAugur = contractsFixture.contracts["ParaAugur"] proceedToFork(contractsFixture, scalarMarket, universe) finalize(contractsFixture, scalarMarket, universe, True) market.migrateThroughOneFork([0, 0, market.getNumTicks()], "") paraAugur.generateParaUniverse(market.getUniverse()) # We are still able to purchase complete sets in a child universe's market numCompleteSets = 10**14 initialFeesPaid = openInterestCash.feesPaid() assert openInterestCash.buyCompleteSets(market.address, numCompleteSets) for i in range(0, 3): assert shareToken.balanceOfMarketOutcome(market.address, i, account1) == numCompleteSets assert openInterestCash.feesPaid() == initialFeesPaid
def test_universe_creation(localFixture, augur, market, universe): proceedToFork(localFixture, market, universe) finalize(localFixture, market, universe) with PrintGasUsed(localFixture, "UNIVERSE_CREATE", UNIVERSE_CREATE): universe.createChildUniverse([0, 1, market.getNumTicks() - 1])
def test_forking(finalizeByMigration, manuallyDisavow, localFixture, universe, market, cash, categoricalMarket, scalarMarket): claimTradingProceeds = localFixture.contracts["ClaimTradingProceeds"] # 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): categoricalMarket.migrateThroughOneFork([0,0,0,categoricalMarket.getNumTicks()], "") with raises(TransactionFailed): time = localFixture.contracts["Time"].getTimestamp() localFixture.createYesNoMarket(universe, time + 1000, 1, 0, localFixture.accounts[0]) # 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(localFixture.accounts[0]) # 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.getOrCreateCurrentDisputeWindow(False) disputeWindow = localFixture.applySignature("DisputeWindow", disputeWindowAddress) # finalize the fork finalize(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() newUniverse = localFixture.applySignature("Universe", newUniverseAddress) # Let's make sure fork payouts work correctly for the forking market completeSets = localFixture.contracts['CompleteSets'] numSets = 10 cost = market.getNumTicks() * numSets with BuyWithCash(cash, cost, localFixture.accounts[0], "buy complete set"): assert completeSets.publicBuyCompleteSets(market.address, numSets) yesShare = localFixture.applySignature("ShareToken", market.getShareToken(YES)) noShare = localFixture.applySignature("ShareToken", market.getShareToken(NO)) noShare.transfer(localFixture.accounts[1], noShare.balanceOf(localFixture.accounts[0])) expectedYesOutcomePayout = newUniverse.payoutNumerators(YES) expectedNoOutcomePayout = newUniverse.payoutNumerators(NO) expectedYesPayout = expectedYesOutcomePayout * yesShare.balanceOf(localFixture.accounts[0]) * .99 # to account for fees (creator fee goes to the claimer in this case) with TokenDelta(cash, expectedYesPayout, localFixture.accounts[0], "Payout for Yes Shares was wrong in forking market"): claimTradingProceeds.claimTradingProceeds(market.address, localFixture.accounts[0], nullAddress) expectedNoPayout = expectedNoOutcomePayout * noShare.balanceOf(localFixture.accounts[1]) * .98 # to account for fees with TokenDelta(cash, expectedNoPayout, localFixture.accounts[1], "Payout for No Shares was wrong in forking market"): claimTradingProceeds.claimTradingProceeds(market.address, localFixture.accounts[1], nullAddress) # buy some complete sets to change OI of the cat market numSets = 10 cost = categoricalMarket.getNumTicks() * numSets with BuyWithCash(cash, cost, localFixture.accounts[0], "buy complete set"): assert completeSets.publicBuyCompleteSets(categoricalMarket.address, numSets) assert universe.getOpenInterestInAttoCash() == 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.getOpenInterestInAttoCash() == 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.getOpenInterestInAttoCash() == 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 newReputationToken = localFixture.applySignature("ReputationToken", newUniverse.getReputationToken()) with TokenDelta(reputationToken, previousREPBalance, scalarMarket.repBondOwner(), "Market did not transfer rep balance to rep bond owner"): with TokenDelta(newReputationToken, -newUniverse.getOrCacheMarketRepBond(), localFixture.accounts[0], "Migrator did not pay new REP bond"): 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 cannot migrate legacy REP to the new Universe REP legacyRepToken = localFixture.applySignature('LegacyReputationToken', newUniverseREP.getLegacyRepToken()) assert legacyRepToken.faucet(500) totalSupply = legacyRepToken.balanceOf(localFixture.accounts[0]) legacyRepToken.approve(newUniverseREP.address, totalSupply) with raises(TransactionFailed): newUniverseREP.migrateFromLegacyReputationToken() # 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): reputationToken = localFixture.applySignature( "ReputationToken", universe.getReputationToken()) # Give some REP to another account reputationToken.transfer(localFixture.accounts[1], 100) # proceed to forking proceedToFork(localFixture, market, universe) # finalize the fork finalize(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=localFixture.accounts[1]) 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() == int( Decimal(childUniverseTheoreticalSupply) / 2) assert childUniverse.getDisputeThresholdForFork() == int( Decimal(childUniverseTheoreticalSupply) / 40) assert childUniverse.getInitialReportMinValue() == int( Decimal(childUniverse.getDisputeThresholdForFork()) / 3 / 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 finalize(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, cash, 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): categoricalMarket.migrateThroughOneFork( [0, 0, 0, categoricalMarket.getNumTicks()], "") with raises(TransactionFailed): time = localFixture.contracts["Time"].getTimestamp() localFixture.createYesNoMarket(universe, time + 1000, 1, 0, localFixture.accounts[0]) # 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(localFixture.accounts[0]) # 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(False) disputeWindow = localFixture.applySignature("DisputeWindow", disputeWindowAddress) # finalize the fork finalize(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 with BuyWithCash(cash, cost, localFixture.accounts[1], "buy complete set"): assert completeSets.publicBuyCompleteSets( categoricalMarket.address, 10, sender=localFixture.accounts[1]) assert universe.getOpenInterestInAttoCash() == 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.getOpenInterestInAttoCash() == 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.getOpenInterestInAttoCash() == 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()