def test_preemptive_crowdsourcer_contributions_disputed_wins(localFixture, universe, market, reputationToken): # We can pre-emptively stake REP in case someone disputes our initial report preemptiveBondSize = 200 * 10 ** 18 # We'll have one user buy all the stake that will award an ROI and another user buy the remaining stake which will not initialStake = market.getParticipantStake() realBondSize = initialStake * 3 assert market.contributeToTentative([0, market.getNumTicks(), 0], realBondSize, "") assert market.contributeToTentative([0, market.getNumTicks(), 0], preemptiveBondSize - realBondSize, "", sender = localFixture.accounts[1]) preemptiveDisputeCrowdsourcer = localFixture.applySignature('DisputeCrowdsourcer', market.preemptiveDisputeCrowdsourcer()) # Now we'll dispute the intial report proceedToNextRound(localFixture, market) # By disputing we actually cause the preemptive bond to get placed. assert market.getParticipantStake() == preemptiveBondSize + initialStake * 3 # We'll simply move time forward and let this bond placed on the initial report outcome win disputeWindow = localFixture.applySignature('DisputeWindow', market.getDisputeWindow()) # Time marches on and the market can be finalized localFixture.contracts["Time"].setTimestamp(disputeWindow.getEndTime() + 1) assert market.finalize() # The account which placed stake first and got normal tokens will make the normal 40% ROI expectedWinnings = realBondSize * .4 with TokenDelta(reputationToken, realBondSize + expectedWinnings, localFixture.accounts[0], "Redeeming didn't refund REP"): assert preemptiveDisputeCrowdsourcer.redeem(localFixture.accounts[0]) # The account which placed stake later and got overload tokens will not make any ROI with TokenDelta(reputationToken, preemptiveBondSize - realBondSize, localFixture.accounts[1], "Redeeming didn't refund REP"): assert preemptiveDisputeCrowdsourcer.redeem(localFixture.accounts[1])
def test_fork_bonus(contractsFixture, market, universe): # proceed to forking while (market.getForkingMarket() == longToHexString(0)): proceedToNextRound(contractsFixture, market) reputationToken = contractsFixture.applySignature('ReputationToken', universe.getReputationToken()) payoutHash = market.derivePayoutDistributionHash([market.getNumTicks(), 0], False) childUniverse = contractsFixture.applySignature("Universe", universe.createChildUniverse([market.getNumTicks(), 0], False)) childReputationToken = contractsFixture.applySignature("ReputationToken", childUniverse.getReputationToken()) # We'll transfer some additional REP to the initial reporter contract to try and get a larger bonus initialReporterAddress = market.getInitialReporter() extraAmount = 10000 assert reputationToken.transfer(initialReporterAddress, extraAmount) # When we redeem the bonus we will only be given a bonus relative to the legitimate stake in the bond designatedReportCost = universe.getOrCacheDesignatedReportStake() initialReporter = contractsFixture.applySignature('InitialReporter', initialReporterAddress) # Skip to after the fork end to not deal with 5% bonus math contractsFixture.contracts["Time"].setTimestamp(universe.getForkEndTime() + 1) expectedPayout = designatedReportCost + (designatedReportCost / 2) + extraAmount with TokenDelta(childReputationToken, expectedPayout, tester.a0, "Redeeming forked bond didn't result in the expected amount"): assert initialReporter.forkAndRedeem()
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_preemptive_crowdsourcer_contributions_disputed_loses(localFixture, universe, market, reputationToken): # We can pre-emptively stake REP in case someone disputes our initial report preemptiveBondSize = 200 * 10 ** 18 assert market.contributeToTentative([0, market.getNumTicks(), 0], preemptiveBondSize, "") initialStake = market.getParticipantStake() preemptiveDisputeCrowdsourcer = localFixture.applySignature('DisputeCrowdsourcer', market.preemptiveDisputeCrowdsourcer()) # Now we'll dispute the intial report proceedToNextRound(localFixture, market) # By disputing we actually cause the preemptive bond to get placed. assert market.getParticipantStake() == preemptiveBondSize + initialStake * 3 # We'll dispute this newly placed bond made from the preemptive contributions proceedToNextRound(localFixture, market) # And now we'll let the dispute win disputeWindow = localFixture.applySignature('DisputeWindow', market.getDisputeWindow()) # Time marches on and the market can be finalized localFixture.contracts["Time"].setTimestamp(disputeWindow.getEndTime() + 1) assert market.finalize() # The preemptive bond has been liquidated assert reputationToken.balanceOf(preemptiveDisputeCrowdsourcer.address) == 0
def test_crowdsourcer_minimum_remaining(localFixture, universe, market): proceedToNextRound(localFixture, market, moveTimeForward = False) payoutNumerators = [0, 0, market.getNumTicks()] initialReporter = localFixture.applySignature('InitialReporter', market.getInitialReporter()) initialReportSize = initialReporter.getSize() totalBondSize = initialReportSize * 2 # We cannot leave only 1 attoREP remaining to fill with raises(TransactionFailed): market.contribute(payoutNumerators, totalBondSize - 1, "") # We cannot leave anything less than the initial report size left to fill in fact with raises(TransactionFailed): market.contribute(payoutNumerators, totalBondSize - initialReportSize + 1, "") # Lets fill up to the initial report size mintLog = { "target": localFixture.accounts[0], "market": market.address, "amount": totalBondSize - initialReportSize, "totalSupply": totalBondSize - initialReportSize } with AssertLog(localFixture, "TokensMinted", mintLog): assert market.contribute(payoutNumerators, totalBondSize - initialReportSize, "") # Now we'll completely fill the bond assert market.contribute(payoutNumerators, initialReportSize, "")
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_preemptive_crowdsourcer_contributions_disputed_wins(localFixture, universe, market, reputationToken): # We can pre-emptively stake REP in case someone disputes our initial report preemptiveBondSize = 200 * 10 ** 18 # We'll have one user buy all the stake that will award an ROI and another user buy the remaining stake which will not initialStake = market.getParticipantStake() realBondSize = initialStake * 3 assert market.contributeToTentative([0, market.getNumTicks(), 0], realBondSize, "") assert market.contributeToTentative([0, market.getNumTicks(), 0], preemptiveBondSize - realBondSize, "", sender = localFixture.accounts[1]) preemptiveDisputeCrowdsourcer = localFixture.applySignature('DisputeCrowdsourcer', market.preemptiveDisputeCrowdsourcer()) # Now we'll dispute the intial report proceedToNextRound(localFixture, market) # By disputing we actually cause the preemptive bond to get placed. assert market.getParticipantStake() == preemptiveBondSize + initialStake * 3 # We'll simply move time forward and let this bond placed on the initial report outcome win disputeWindow = localFixture.applySignature('DisputeWindow', market.getDisputeWindow()) # Time marches on and the market can be finalized localFixture.contracts["Time"].setTimestamp(disputeWindow.getEndTime() + 1) assert market.finalize() # Both accounts will get a lower than 40% ROI for their contributions to the tentative outcome expectedReturn = reputationToken.balanceOf(preemptiveDisputeCrowdsourcer.address) * realBondSize / preemptiveDisputeCrowdsourcer.totalSupply() with TokenDelta(reputationToken, expectedReturn, localFixture.accounts[0], "Redeeming didn't refund REP"): assert preemptiveDisputeCrowdsourcer.redeem(localFixture.accounts[0]) expectedReturn = reputationToken.balanceOf(preemptiveDisputeCrowdsourcer.address) * (preemptiveBondSize - realBondSize) / preemptiveDisputeCrowdsourcer.totalSupply() with TokenDelta(reputationToken, expectedReturn, localFixture.accounts[1], "Redeeming didn't refund REP"): assert preemptiveDisputeCrowdsourcer.redeem(localFixture.accounts[1])
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_redeem_reporting_participants(kitchenSinkFixture, market, categoricalMarket, scalarMarket, universe, cash): reputationToken = kitchenSinkFixture.applySignature("ReputationToken", universe.getReputationToken()) constants = kitchenSinkFixture.contracts["Constants"] # Initial Report proceedToNextRound(kitchenSinkFixture, market, doGenerateFees = True) # Initial Report Losing proceedToNextRound(kitchenSinkFixture, market, doGenerateFees = True) # Initial Report Winning proceedToNextRound(kitchenSinkFixture, market, doGenerateFees = True) # Initial Report Losing proceedToNextRound(kitchenSinkFixture, market, doGenerateFees = True) # Initial Report Winning proceedToNextRound(kitchenSinkFixture, market, doGenerateFees = True) # Get the winning reporting participants initialReporter = kitchenSinkFixture.applySignature('InitialReporter', market.getReportingParticipant(0)) winningDisputeCrowdsourcer1 = kitchenSinkFixture.applySignature('DisputeCrowdsourcer', market.getReportingParticipant(2)) winningDisputeCrowdsourcer2 = kitchenSinkFixture.applySignature('DisputeCrowdsourcer', market.getReportingParticipant(4)) # Fast forward time until the new fee window is over and we can redeem feeWindow = kitchenSinkFixture.applySignature("FeeWindow", market.getFeeWindow()) kitchenSinkFixture.contracts["Time"].setTimestamp(feeWindow.getEndTime() + 1) assert market.finalize() expectedFees = getExpectedFees(kitchenSinkFixture, cash, winningDisputeCrowdsourcer1, 4) expectedFees += getExpectedFees(kitchenSinkFixture, cash, winningDisputeCrowdsourcer2, 2) expectedFees += getExpectedFees(kitchenSinkFixture, cash, initialReporter, 5) expectedRep = long(winningDisputeCrowdsourcer2.getStake() + winningDisputeCrowdsourcer1.getStake()) expectedRep = long(expectedRep + expectedRep / 2) expectedRep += long(initialReporter.getStake() + initialReporter.getStake() / 2) with TokenDelta(reputationToken, expectedRep, tester.a0, "Redeeming didn't refund REP"): with PrintGasUsed(kitchenSinkFixture, "Universe Redeem:", 0): assert universe.redeemStake([initialReporter.address, winningDisputeCrowdsourcer1.address, winningDisputeCrowdsourcer2.address], [])
def test_redeem_reporting_participants(kitchenSinkFixture, market, categoricalMarket, scalarMarket, universe, cash): redeemStake = kitchenSinkFixture.contracts["RedeemStake"] reputationToken = kitchenSinkFixture.applySignature( "ReputationToken", universe.getReputationToken()) constants = kitchenSinkFixture.contracts["Constants"] # Initial Report proceedToNextRound(kitchenSinkFixture, market, doGenerateFees=True) # Initial Report Losing proceedToNextRound(kitchenSinkFixture, market, doGenerateFees=True) # Initial Report Winning proceedToNextRound(kitchenSinkFixture, market, doGenerateFees=True) # Initial Report Losing proceedToNextRound(kitchenSinkFixture, market, doGenerateFees=True) # Initial Report Winning proceedToNextRound(kitchenSinkFixture, market, doGenerateFees=True) # Get the winning reporting participants initialReporter = kitchenSinkFixture.applySignature( 'InitialReporter', market.getReportingParticipant(0)) winningDisputeCrowdsourcer1 = kitchenSinkFixture.applySignature( 'DisputeCrowdsourcer', market.getReportingParticipant(2)) winningDisputeCrowdsourcer2 = kitchenSinkFixture.applySignature( 'DisputeCrowdsourcer', market.getReportingParticipant(4)) # Fast forward time until the new dispute window is over and we can redeem disputeWindow = kitchenSinkFixture.applySignature( "DisputeWindow", market.getDisputeWindow()) # Purchase PTs and inject fees into the window ptAmount = 10**18 additionalfees = 10**18 assert cash.faucet(additionalfees) assert cash.transfer(disputeWindow.address, additionalfees) assert disputeWindow.buy(ptAmount) kitchenSinkFixture.contracts["Time"].setTimestamp( disputeWindow.getEndTime() + 1) assert market.finalize() expectedRep = winningDisputeCrowdsourcer2.getStake( ) + winningDisputeCrowdsourcer1.getStake() + initialReporter.getStake() expectedRep = expectedRep + expectedRep * 2 / 5 expectedRep += ptAmount expectedRep -= 1 # Rounding error fees = cash.balanceOf(disputeWindow.address) with TokenDelta(reputationToken, expectedRep, kitchenSinkFixture.accounts[0], "Redeeming didn't refund REP"): with TokenDelta(cash, fees, kitchenSinkFixture.accounts[0], "Redeeming didn't pay out fees"): with PrintGasUsed(kitchenSinkFixture, "Universe Redeem:", 0): assert redeemStake.redeemStake([ initialReporter.address, winningDisputeCrowdsourcer1.address, winningDisputeCrowdsourcer2.address ], [disputeWindow.address])
def test_marketFinalization(localFixture, universe, market): proceedToNextRound(localFixture, market) feeWindow = localFixture.applySignature('FeeWindow', market.getFeeWindow()) localFixture.contracts["Time"].setTimestamp(feeWindow.getEndTime() + 1) with PrintGasUsed(localFixture, "Market:finalize", MARKET_FINALIZATION): assert market.finalize()
def test_marketFinalization(localFixture, universe, market): proceedToNextRound(localFixture, market) feeWindow = localFixture.applySignature('FeeWindow', market.getFeeWindow()) localFixture.contracts["Time"].setTimestamp(feeWindow.getEndTime() + 1) with PrintGasUsed(localFixture, "Market:finalize", MARKET_FINALIZATION): assert market.finalize()
def test_roundsOfReporting(rounds, localFixture, market, universe): disputeWindow = universe.getOrCreateCurrentDisputeWindow(False) marketRepBond = market.repBond() # Do the initial report proceedToNextRound(localFixture, market, moveTimeForward = False) initialDisputeWindow = localFixture.applySignature('DisputeWindow', market.getDisputeWindow()) assert initialDisputeWindow.duration() == localFixture.contracts["Constants"].INITIAL_DISPUTE_ROUND_DURATION_SECONDS() # Do the first round outside of the loop and test logging crowdsourcerCreatedLog = { "universe": universe.address, "market": market.address, "size": marketRepBond * 2, "payoutNumerators": [0, 0, market.getNumTicks()], } crowdsourcerContributionLog = { "universe": universe.address, "reporter": localFixture.accounts[0], "market": market.address, "amountStaked": marketRepBond * 2, "description": "Clearly incorrect", "payoutNumerators": [0, 0, market.getNumTicks()], "currentStake": marketRepBond * 2, "stakeRemaining": 0, } disputeWindow = localFixture.applySignature("DisputeWindow", universe.getOrCreateNextDisputeWindow(False)) crowdsourcerCompletedLog = { "universe": universe.address, "market": market.address, "nextWindowStartTime": disputeWindow.getStartTime(), "nextWindowEndTime": disputeWindow.getEndTime(), "totalRepStakedInMarket": marketRepBond * 3, "disputeRound": 2, "payoutNumerators": [0, 0, market.getNumTicks()], "totalRepStakedInPayout": marketRepBond * 2, } with AssertLog(localFixture, "DisputeCrowdsourcerCreated", crowdsourcerCreatedLog): with AssertLog(localFixture, "DisputeCrowdsourcerContribution", crowdsourcerContributionLog): with AssertLog(localFixture, "DisputeCrowdsourcerCompleted", crowdsourcerCompletedLog): market.contribute([0, 0, market.getNumTicks()], universe.getInitialReportMinValue() * 2, "Clearly incorrect", sender=localFixture.accounts[0]) newDisputeWindow = localFixture.applySignature('DisputeWindow', market.getDisputeWindow()) assert newDisputeWindow.duration() == localFixture.contracts["Constants"].DISPUTE_ROUND_DURATION_SECONDS() # proceed through several rounds of disputing for i in range(rounds - 2): proceedToNextRound(localFixture, market) assert disputeWindow != market.getDisputeWindow() disputeWindow = market.getDisputeWindow() assert disputeWindow == universe.getOrCreateCurrentDisputeWindow(False)
def test_redeem_participation_tokens(kitchenSinkFixture, universe, market, cash): reputationToken = kitchenSinkFixture.applySignature("ReputationToken", universe.getReputationToken()) # proceed to the next round and buy some more fee window tokens proceedToNextRound(kitchenSinkFixture, market, doGenerateFees = True) feeWindow = kitchenSinkFixture.applySignature('FeeWindow', market.getFeeWindow()) # We'll make the window active then purchase some participation tokens kitchenSinkFixture.contracts["Time"].setTimestamp(feeWindow.getStartTime() + 1) feeWindowAmount = 100 # Distribute REP for testAccount in [tester.a1, tester.a2, tester.a3]: reputationToken.transfer(testAccount, 1 * 10**6 * 10**18) assert feeWindow.buy(feeWindowAmount, sender=tester.k1) assert feeWindow.buy(feeWindowAmount, sender=tester.k2) assert feeWindow.buy(feeWindowAmount, sender=tester.k3) # proceed to the next round and buy some more fee window tokens proceedToNextRound(kitchenSinkFixture, market, doGenerateFees = True) newFeeWindow = kitchenSinkFixture.applySignature('FeeWindow', market.getFeeWindow()) assert newFeeWindow.buy(feeWindowAmount, sender=tester.k1) assert newFeeWindow.buy(feeWindowAmount, sender=tester.k2) assert newFeeWindow.buy(feeWindowAmount, sender=tester.k3) # Now end the window kitchenSinkFixture.contracts["Time"].setTimestamp(newFeeWindow.getEndTime() + 1) reporterFees = 1000 * market.getNumTicks() / universe.getOrCacheReportingFeeDivisor() totalStake = feeWindow.getTotalFeeStake() + newFeeWindow.getTotalFeeStake() assert cash.balanceOf(feeWindow.address) == reporterFees assert cash.balanceOf(newFeeWindow.address) == reporterFees expectedParticipationFees = reporterFees * feeWindowAmount * 2 / totalStake # Cashing out Participation tokens will awards fees proportional to the total winning stake in the window with TokenDelta(reputationToken, feeWindowAmount * 2, tester.a3, "Redeeming participation tokens didn't refund REP"): with TokenDelta(feeWindow, -feeWindowAmount, tester.a3, "Redeeming participation tokens didn't decrease participation token balance correctly"): with EtherDelta(expectedParticipationFees, tester.a3, kitchenSinkFixture.chain, "Redeeming participation tokens didn't increase ETH correctly"): with PrintGasUsed(kitchenSinkFixture, "Universe Redeem:", 0): assert universe.redeemStake([], [feeWindow.address, newFeeWindow.address], sender = tester.k3) with TokenDelta(reputationToken, feeWindowAmount * 2, tester.a1, "Redeeming participation tokens didn't refund REP"): with TokenDelta(feeWindow, -feeWindowAmount, tester.a1, "Redeeming participation tokens didn't decrease participation token balance correctly"): with EtherDelta(expectedParticipationFees, tester.a1, kitchenSinkFixture.chain, "Redeeming participation tokens didn't increase ETH correctly"): assert universe.redeemStake([], [feeWindow.address, newFeeWindow.address], sender = tester.k1) with TokenDelta(reputationToken, feeWindowAmount * 2, tester.a2, "Redeeming participation tokens didn't refund REP"): with TokenDelta(feeWindow, -feeWindowAmount, tester.a2, "Redeeming participation tokens didn't decrease participation token balance correctly"): with EtherDelta(expectedParticipationFees, tester.a2, kitchenSinkFixture.chain, "Redeeming participation tokens didn't increase ETH correctly"): assert universe.redeemStake([], [feeWindow.address, newFeeWindow.address], sender = tester.k2)
def test_fees_from_trades(finalized, contractsFixture, cash, market): createOrder = contractsFixture.contracts['CreateOrder'] trade = contractsFixture.contracts['Trade'] orders = contractsFixture.contracts['Orders'] completeSets = contractsFixture.contracts['CompleteSets'] firstShareToken = contractsFixture.applySignature('ShareToken', market.getShareToken(0)) secondShareToken = contractsFixture.applySignature('ShareToken', market.getShareToken(1)) if finalized: proceedToNextRound(contractsFixture, market) disputeWindow = contractsFixture.applySignature('DisputeWindow', market.getDisputeWindow()) contractsFixture.contracts["Time"].setTimestamp(disputeWindow.getEndTime() + 1) assert market.finalize() # buy complete sets for both users numTicks = market.getNumTicks() with BuyWithCash(cash, fix('1', numTicks), tester.k1, "buy complete set"): assert completeSets.publicBuyCompleteSets(market.address, fix(1), sender=tester.k1) with BuyWithCash(cash, fix('1', numTicks), tester.k2, "buy complete set"): assert completeSets.publicBuyCompleteSets(market.address, fix(1), sender=tester.k2) assert firstShareToken.balanceOf(tester.a1) == firstShareToken.balanceOf(tester.a2) == fix(1) assert secondShareToken.balanceOf(tester.a1) == secondShareToken.balanceOf(tester.a2) == fix(1) # create order with shares orderID = createOrder.publicCreateOrder(ASK, fix(1), 6000, market.address, 0, longTo32Bytes(0), longTo32Bytes(0), longTo32Bytes(42), False, nullAddress, sender=tester.k1) assert orderID expectedAffiliateFees = fix(10000) * 0.01 * .25 cash.faucet(fix(6000), sender=tester.k2) # Trade and specify an affiliate address. if finalized: with TokenDelta(cash, expectedAffiliateFees, tester.a3, "Affiliate did not recieve the correct fees"): assert trade.publicFillBestOrder(BID, market.address, 0, fix(1), 6000, "43", 6, False, tester.a3, nullAddress, sender=tester.k2) == 0 else: assert trade.publicFillBestOrder(BID, market.address, 0, fix(1), 6000, "43", 6, False, tester.a3, nullAddress, sender=tester.k2) == 0 assert firstShareToken.balanceOf(tester.a1) == 0 assert secondShareToken.balanceOf(tester.a1) == fix(1) # The second user sold the complete set they ended up holding from this transaction, which extracts fees assert firstShareToken.balanceOf(tester.a2) == fix(1) assert secondShareToken.balanceOf(tester.a2) == fix(0) if not finalized: # We can confirm that the 3rd test account has an affiliate fee balance of 25% of the market creator fee 1% taken from the 1 ETH order assert market.affiliateFeesAttoCash(tester.a3) == expectedAffiliateFees # The affiliate can withdraw their fees with TokenDelta(cash, expectedAffiliateFees, tester.a3, "Affiliate did not recieve the correct fees"): market.withdrawAffiliateFees(tester.a3) # No more fees can be withdrawn with TokenDelta(cash, 0, tester.a3, "Affiliate double received fees"): market.withdrawAffiliateFees(tester.a3)
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_market_escape_hatch_partial_fees(localFixture, market, reputationToken, constants, controller): reputationToken.transfer(tester.a1, 1 * 10**6 * 10**18) proceedToNextRound(localFixture, market, contributor = tester.k1) # Emergency Stop assert controller.emergencyStop() # We will only get back the validity bond since our REP bond and first reporter bond were forfeit already with EtherDelta(constants.DEFAULT_VALIDITY_BOND(), market.getOwner(), localFixture.chain, "Remaining ETH balance was not given to the market owner"): with TokenDelta(reputationToken, 0, market.getOwner(), "REP balance was somehow given to the market owner"): assert market.withdrawInEmergency()
def test_redeem_reporting_participants(kitchenSinkFixture, market, categoricalMarket, scalarMarket, universe, cash): reputationToken = kitchenSinkFixture.applySignature( "ReputationToken", universe.getReputationToken()) constants = kitchenSinkFixture.contracts["Constants"] # Initial Report proceedToNextRound(kitchenSinkFixture, market, doGenerateFees=True) # Initial Report Losing proceedToNextRound(kitchenSinkFixture, market, doGenerateFees=True) # Initial Report Winning proceedToNextRound(kitchenSinkFixture, market, doGenerateFees=True) # Initial Report Losing proceedToNextRound(kitchenSinkFixture, market, doGenerateFees=True) # Initial Report Winning proceedToNextRound(kitchenSinkFixture, market, doGenerateFees=True) # Get the winning reporting participants initialReporter = kitchenSinkFixture.applySignature( 'InitialReporter', market.getReportingParticipant(0)) winningDisputeCrowdsourcer1 = kitchenSinkFixture.applySignature( 'DisputeCrowdsourcer', market.getReportingParticipant(2)) winningDisputeCrowdsourcer2 = kitchenSinkFixture.applySignature( 'DisputeCrowdsourcer', market.getReportingParticipant(4)) # Fast forward time until the new fee window is over and we can redeem feeWindow = kitchenSinkFixture.applySignature("FeeWindow", market.getFeeWindow()) kitchenSinkFixture.contracts["Time"].setTimestamp(feeWindow.getEndTime() + 1) assert market.finalize() expectedFees = getExpectedFees(kitchenSinkFixture, cash, winningDisputeCrowdsourcer1, 4) expectedFees += getExpectedFees(kitchenSinkFixture, cash, winningDisputeCrowdsourcer2, 2) expectedFees += getExpectedFees(kitchenSinkFixture, cash, initialReporter, 5) expectedRep = long(winningDisputeCrowdsourcer2.getStake() + winningDisputeCrowdsourcer1.getStake()) expectedRep = long(expectedRep + expectedRep / 2) expectedRep += long(initialReporter.getStake() + initialReporter.getStake() / 2) expectedGasBond = 2 * constants.GAS_TO_REPORT( ) * constants.DEFAULT_REPORTING_GAS_PRICE() with TokenDelta(reputationToken, expectedRep, tester.a0, "Redeeming didn't refund REP"): with PrintGasUsed(kitchenSinkFixture, "Universe Redeem:", 0): assert universe.redeemStake([ initialReporter.address, winningDisputeCrowdsourcer1.address, winningDisputeCrowdsourcer2.address ], [])
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_dispute_pacing_threshold(localFixture, universe, market): # We'll dispute until we reach the dispute pacing threshold while not market.getDisputePacingOn(): proceedToNextRound(localFixture, market, moveTimeForward = False) # Now if we try to immediately dispute without the newly assigned dispute window being active the tx will fail with raises(TransactionFailed): market.contribute([0, market.getNumTicks(), 0], 1, "") # If we move time forward to the dispute window start we succeed disputeWindow = localFixture.applySignature('DisputeWindow', market.getDisputeWindow()) assert localFixture.contracts["Time"].setTimestamp(disputeWindow.getStartTime() + 1) assert market.contribute([0, market.getNumTicks(), 0], 1, "")
def test_preemptive_crowdsourcer_after_initial(localFixture, universe, market, reputationToken): initialStake = market.getParticipantStake() # First we'll dispute the intial report proceedToNextRound(localFixture, market) # Now we'll place a large pre-emptive bond largeBond = initialStake * 50 assert market.contributeToTentative([0, 0, market.getNumTicks()], largeBond, "") preemptiveDisputeCrowdsourcer = localFixture.applySignature('DisputeCrowdsourcer', market.preemptiveDisputeCrowdsourcer()) # Now we'll dispute the dispute proceedToNextRound(localFixture, market) # By disputing we actually cause the preemptive bond to get placed. assert market.getParticipantStake() == largeBond + initialStake * 6 # We'll dispute this newly placed bond made from the preemptive contributions proceedToNextRound(localFixture, market) # And now we'll do one more dispute in favor of the initial dispute proceedToNextRound(localFixture, market) # Now we finalize the market disputeWindow = localFixture.applySignature('DisputeWindow', market.getDisputeWindow()) # Time marches on and the market can be finalized localFixture.contracts["Time"].setTimestamp(disputeWindow.getEndTime() + 1) assert market.finalize() # Because the overloaded bond was disputed there is now sufficient REP to award the overload tokens with ROI as well with TokenDelta(reputationToken, largeBond * 1.4, localFixture.accounts[0], "Redeeming didn't refund REP"): assert preemptiveDisputeCrowdsourcer.redeem(localFixture.accounts[0])
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_preemptive_crowdsourcer_contributions_dont_fill_bonds(localFixture, universe, market, reputationToken): # We can pre-emptively stake REP in case someone disputes our initial report preemptiveBondSize = 1 initialStake = market.getParticipantStake() realBondSize = initialStake * 3 assert market.contributeToTentative([0, market.getNumTicks(), 0], preemptiveBondSize, "") preemptiveDisputeCrowdsourcer = localFixture.applySignature('DisputeCrowdsourcer', market.preemptiveDisputeCrowdsourcer()) # Now we'll dispute the initial report proceedToNextRound(localFixture, market) # We can see that the tentative winning outcome is the one suggested in the dispute still since not enouhg pre-emptive REP was placed to fill the bond assert market.getWinningReportingParticipant() != preemptiveDisputeCrowdsourcer.address assert market.getCrowdsourcer(preemptiveDisputeCrowdsourcer.getPayoutDistributionHash()) == preemptiveDisputeCrowdsourcer.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([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_market_escape_hatch_partial_fees(localFixture, market, reputationToken, constants, controller): reputationToken.transfer(tester.a1, 1 * 10**6 * 10**18) proceedToNextRound(localFixture, market, contributor=tester.k1) # Emergency Stop assert controller.emergencyStop() # We will only get back the validity bond since our REP bond and first reporter bond were forfeit already with EtherDelta(constants.DEFAULT_VALIDITY_BOND(), market.getOwner(), localFixture.chain, "Remaining ETH balance was not given to the market owner"): with TokenDelta(reputationToken, 0, market.getOwner(), "REP balance was somehow given to the market owner"): assert market.withdrawInEmergency()
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_redeem_reporting_participants(kitchenSinkFixture, market, categoricalMarket, scalarMarket, universe, cash): reputationToken = kitchenSinkFixture.applySignature( "ReputationToken", universe.getReputationToken()) constants = kitchenSinkFixture.contracts["Constants"] # Initial Report proceedToNextRound(kitchenSinkFixture, market, doGenerateFees=True) # Initial Report Losing proceedToNextRound(kitchenSinkFixture, market, doGenerateFees=True) # Initial Report Winning proceedToNextRound(kitchenSinkFixture, market, doGenerateFees=True) # Initial Report Losing proceedToNextRound(kitchenSinkFixture, market, doGenerateFees=True) # Initial Report Winning proceedToNextRound(kitchenSinkFixture, market, doGenerateFees=True) # Get the winning reporting participants initialReporter = kitchenSinkFixture.applySignature( 'InitialReporter', market.getReportingParticipant(0)) winningDisputeCrowdsourcer1 = kitchenSinkFixture.applySignature( 'DisputeCrowdsourcer', market.getReportingParticipant(2)) winningDisputeCrowdsourcer2 = kitchenSinkFixture.applySignature( 'DisputeCrowdsourcer', market.getReportingParticipant(4)) # Fast forward time until the new dispute window is over and we can redeem disputeWindow = kitchenSinkFixture.applySignature( "DisputeWindow", market.getDisputeWindow()) kitchenSinkFixture.contracts["Time"].setTimestamp( disputeWindow.getEndTime() + 1) assert market.finalize() expectedRep = winningDisputeCrowdsourcer2.getStake( ) + winningDisputeCrowdsourcer1.getStake() + initialReporter.getStake() expectedRep = expectedRep + expectedRep * 2 / 5 expectedRep -= 1 # Rounding error with TokenDelta(reputationToken, expectedRep, tester.a0, "Redeeming didn't refund REP"): with PrintGasUsed(kitchenSinkFixture, "Universe Redeem:", 0): assert universe.redeemStake([ initialReporter.address, winningDisputeCrowdsourcer1.address, winningDisputeCrowdsourcer2.address ])
def test_multiple_round_crowdsourcer(localFixture, universe, market, cash, reputationToken): constants = localFixture.contracts["Constants"] # Initial Report disputed proceedToNextRound(localFixture, market, localFixture.accounts[1], True) # Initial Report winning proceedToNextRound(localFixture, market, localFixture.accounts[2], True) # Initial Report disputed proceedToNextRound(localFixture, market, localFixture.accounts[1], True, randomPayoutNumerators=True) # Initial Report winning proceedToNextRound(localFixture, market, localFixture.accounts[3], True) # Get all the winning Reporting Participants initialReporter = localFixture.applySignature('InitialReporter', market.getReportingParticipant(0)) winningDisputeCrowdsourcer1 = localFixture.applySignature('DisputeCrowdsourcer', market.getReportingParticipant(2)) winningDisputeCrowdsourcer2 = localFixture.applySignature('DisputeCrowdsourcer', market.getReportingParticipant(4)) # Get losing Reporting Participants losingDisputeCrowdsourcer1 = localFixture.applySignature('DisputeCrowdsourcer', market.getReportingParticipant(1)) losingDisputeCrowdsourcer2 = localFixture.applySignature('DisputeCrowdsourcer', market.getReportingParticipant(3)) # We can't redeem yet as the market isn't finalized with raises(TransactionFailed): initialReporter.redeem(localFixture.accounts[0]) with raises(TransactionFailed): winningDisputeCrowdsourcer1.redeem(localFixture.accounts[2]) # Fast forward time until the new dispute window is over disputeWindow = localFixture.applySignature("DisputeWindow", market.getDisputeWindow()) localFixture.contracts["Time"].setTimestamp(disputeWindow.getEndTime() + 1) assert market.finalize() expectedRep = initialReporter.getStake() + initialReporter.getStake() * 2 / 5 with TokenDelta(reputationToken, expectedRep, localFixture.accounts[0], "Redeeming didn't refund REP"): assert initialReporter.redeem(localFixture.accounts[0]) expectedRep = winningDisputeCrowdsourcer1.getStake() + winningDisputeCrowdsourcer1.getStake() * 2 / 5 with TokenDelta(reputationToken, expectedRep, localFixture.accounts[2], "Redeeming didn't refund REP"): assert winningDisputeCrowdsourcer1.redeem(localFixture.accounts[2]) expectedRep = winningDisputeCrowdsourcer2.getStake() + winningDisputeCrowdsourcer2.getStake() * 2 / 5 with TokenDelta(reputationToken, expectedRep, localFixture.accounts[3], "Redeeming didn't refund REP"): assert winningDisputeCrowdsourcer2.redeem(localFixture.accounts[3]) # The losing reports get no REP with TokenDelta(reputationToken, 0, localFixture.accounts[1], "Redeeming refunded REP"): assert losingDisputeCrowdsourcer1.redeem(localFixture.accounts[1]) with TokenDelta(reputationToken, 0, localFixture.accounts[1], "Redeeming refunded REP"): assert losingDisputeCrowdsourcer2.redeem(localFixture.accounts[1])
def test_redeem(localFixture, universe, cash, market): # Initial report proceedToNextRound(localFixture, market) # Initial losing proceedToNextRound(localFixture, market) # Initial Winning proceedToNextRound(localFixture, market, doGenerateFees = True) initialReporter = localFixture.applySignature('InitialReporter', market.getReportingParticipant(0)) winningDisputeCrowdsourcer1 = localFixture.applySignature('DisputeCrowdsourcer', market.getReportingParticipant(2)) feeWindow = localFixture.applySignature('FeeWindow', market.getFeeWindow()) assert feeWindow.buy(100) localFixture.contracts["Time"].setTimestamp(feeWindow.getEndTime() + 1) assert market.finalize() with PrintGasUsed(localFixture, "InitialReporter:redeem", INITIAL_REPORT_REDEMPTION): initialReporter.redeem(tester.a0) with PrintGasUsed(localFixture, "DisputeCrowdsourcer:redeem", CROWDSOURCER_REDEMPTION): winningDisputeCrowdsourcer1.redeem(tester.a0) with PrintGasUsed(localFixture, "FeeWindow:redeem", PARTICIPATION_TOKEN_REDEMPTION): feeWindow.redeem(tester.a0)
def test_reporting_participant_escape_hatch(localFixture, controller, reputationToken, market, constants, cash): # Initial Reporting proceedToNextRound(localFixture, market) # Crowdsourcer 1 proceedToNextRound(localFixture, market) # Crowdsourcer 2 proceedToNextRound(localFixture, market) initialReporter = localFixture.applySignature("InitialReporter", market.getReportingParticipant(0)) crowdsourcer1 = localFixture.applySignature("DisputeCrowdsourcer", market.getReportingParticipant(1)) crowdsourcer2 = localFixture.applySignature("DisputeCrowdsourcer", market.getReportingParticipant(2)) # We cannot call the escape hatches yet with raises(TransactionFailed): initialReporter.withdrawInEmergency() with raises(TransactionFailed): crowdsourcer1.withdrawInEmergency() with raises(TransactionFailed): crowdsourcer2.withdrawInEmergency() # Emergency Stop assert controller.emergencyStop() # We can now call the escape hatch with TokenDelta(reputationToken, reputationToken.balanceOf(initialReporter.address), tester.a0, "REP was not given back"): assert initialReporter.withdrawInEmergency() with TokenDelta(reputationToken, reputationToken.balanceOf(crowdsourcer1.address), tester.a0, "REP was not given back"): assert crowdsourcer1.withdrawInEmergency() with TokenDelta(reputationToken, reputationToken.balanceOf(crowdsourcer2.address), tester.a0, "REP was not given back"): assert crowdsourcer2.withdrawInEmergency()
def test_redeem(localFixture, universe, cash, market): # Initial report proceedToNextRound(localFixture, market) # Initial losing proceedToNextRound(localFixture, market) # Initial Winning proceedToNextRound(localFixture, market, doGenerateFees=True) initialReporter = localFixture.applySignature( 'InitialReporter', market.getReportingParticipant(0)) winningDisputeCrowdsourcer1 = localFixture.applySignature( 'DisputeCrowdsourcer', market.getReportingParticipant(2)) feeWindow = localFixture.applySignature('FeeWindow', market.getFeeWindow()) assert feeWindow.buy(100) localFixture.contracts["Time"].setTimestamp(feeWindow.getEndTime() + 1) assert market.finalize() with PrintGasUsed(localFixture, "InitialReporter:redeem", INITIAL_REPORT_REDEMPTION): initialReporter.redeem(tester.a0) with PrintGasUsed(localFixture, "DisputeCrowdsourcer:redeem", CROWDSOURCER_REDEMPTION): winningDisputeCrowdsourcer1.redeem(tester.a0) with PrintGasUsed(localFixture, "FeeWindow:redeem", PARTICIPATION_TOKEN_REDEMPTION): feeWindow.redeem(tester.a0)
def test_roundsOfReporting(rounds, localFixture, market, universe): disputeWindow = universe.getOrCreateCurrentDisputeWindow(False) # Do the initial report proceedToNextRound(localFixture, market, moveTimeForward=False) initialDisputeWindow = localFixture.applySignature( 'DisputeWindow', market.getDisputeWindow()) assert initialDisputeWindow.duration() == localFixture.contracts[ "Constants"].INITIAL_DISPUTE_ROUND_DURATION_SECONDS() # Do the first round outside of the loop and test logging crowdsourcerCreatedLog = { "universe": universe.address, "market": market.address, "size": universe.getInitialReportMinValue() * 2, "payoutNumerators": [0, 0, market.getNumTicks()], } crowdsourcerContributionLog = { "universe": universe.address, "reporter": bytesToHexString(tester.a0), "market": market.address, "amountStaked": universe.getInitialReportMinValue() * 2, "description": "Clearly incorrect", } crowdsourcerCompletedLog = { "universe": universe.address, "market": market.address } with AssertLog(localFixture, "DisputeCrowdsourcerCreated", crowdsourcerCreatedLog): with AssertLog(localFixture, "DisputeCrowdsourcerContribution", crowdsourcerContributionLog): with AssertLog(localFixture, "DisputeCrowdsourcerCompleted", crowdsourcerCompletedLog): proceedToNextRound(localFixture, market, description="Clearly incorrect") newDisputeWindow = localFixture.applySignature('DisputeWindow', market.getDisputeWindow()) assert newDisputeWindow.duration( ) == localFixture.contracts["Constants"].DISPUTE_ROUND_DURATION_SECONDS() # proceed through several rounds of disputing for i in range(rounds - 2): proceedToNextRound(localFixture, market) assert disputeWindow != market.getDisputeWindow() disputeWindow = market.getDisputeWindow() assert disputeWindow == universe.getCurrentDisputeWindow(False)
def test_reporting(kitchenSinkFixture, augur, cash, market): hotLoading = kitchenSinkFixture.contracts[ "HotLoadingUniversal"] if kitchenSinkFixture.paraAugur else kitchenSinkFixture.contracts[ "HotLoading"] if kitchenSinkFixture.paraAugur: augur = kitchenSinkFixture.contracts["ParaAugur"] fillOrder = kitchenSinkFixture.contracts["FillOrder"] orders = kitchenSinkFixture.contracts["Orders"] account = kitchenSinkFixture.accounts[0] # Get to Designated Reporting proceedToDesignatedReporting(kitchenSinkFixture, market) marketData = getMarketData(hotLoading, augur, market, fillOrder, orders) assert marketData.reportingState == 1 assert marketData.disputeRound == 0 # Get to Open Reporting proceedToInitialReporting(kitchenSinkFixture, market) marketData = getMarketData(hotLoading, augur, market, fillOrder, orders) assert marketData.reportingState == 2 assert marketData.disputeRound == 0 # Get to Disputing proceedToNextRound(kitchenSinkFixture, market) marketData = getMarketData(hotLoading, augur, market, fillOrder, orders) assert marketData.reportingState == 3 assert marketData.disputeRound == 0 # Proceed to next round proceedToNextRound(kitchenSinkFixture, market) marketData = getMarketData(hotLoading, augur, market, fillOrder, orders) assert marketData.reportingState == 3 assert marketData.disputeRound == 1 # Get to Awaiting Next Window while not market.getDisputePacingOn(): proceedToNextRound(kitchenSinkFixture, market, moveTimeForward=False) marketData = getMarketData(hotLoading, augur, market, fillOrder, orders) assert marketData.reportingState == 4 assert marketData.disputeRound == 11 # Get to AwaitingFinalization kitchenSinkFixture.contracts["Time"].incrementTimestamp(30 * 24 * 60 * 60) marketData = getMarketData(hotLoading, augur, market, fillOrder, orders) assert marketData.reportingState == 5 # get to Finalized market.finalize() marketData = getMarketData(hotLoading, augur, market, fillOrder, orders) assert marketData.reportingState == 6
def test_crowdsourcer_transfer(contractsFixture, market, universe): proceedToNextRound(contractsFixture, market) proceedToNextRound(contractsFixture, market) proceedToNextRound(contractsFixture, market) crowdsourcer = contractsFixture.applySignature( "DisputeCrowdsourcer", market.getWinningReportingParticipant()) transferAmount = 1 tester0Balance = crowdsourcer.balanceOf( contractsFixture.accounts[0]) - transferAmount tester1Balance = crowdsourcer.balanceOf( contractsFixture.accounts[1]) + transferAmount crowdsourcerTokenTransferLog = { 'from': contractsFixture.accounts[0], 'to': contractsFixture.accounts[1], 'token': crowdsourcer.address, 'universe': universe.address, 'tokenType': 1, 'value': transferAmount, } crowdsourcerTokenBalance0Log = { 'owner': contractsFixture.accounts[0], 'token': crowdsourcer.address, 'universe': universe.address, 'tokenType': 1, 'balance': tester0Balance, } crowdsourcerTokenBalance1Log = { 'owner': contractsFixture.accounts[1], 'token': crowdsourcer.address, 'universe': universe.address, 'tokenType': 1, 'balance': tester1Balance, } with AssertLog(contractsFixture, "TokensTransferred", crowdsourcerTokenTransferLog): with AssertLog(contractsFixture, "TokenBalanceChanged", crowdsourcerTokenBalance0Log): with AssertLog(contractsFixture, "TokenBalanceChanged", crowdsourcerTokenBalance1Log, skip=1): assert crowdsourcer.transfer(contractsFixture.accounts[1], transferAmount)
def test_preemptive_crowdsourcer_contributions_disputed_twice_wins( localFixture, universe, market, reputationToken): # We can pre-emptively stake REP in case someone disputes our initial report preemptiveBondSize = 200 * 10**18 # We'll have two users buy stake in varying amounts initialStake = market.getParticipantStake() realBondSize = initialStake * 3 assert market.contributeToTentative([0, market.getNumTicks(), 0], realBondSize, "") assert market.contributeToTentative([0, market.getNumTicks(), 0], preemptiveBondSize - realBondSize, "", sender=localFixture.accounts[1]) preemptiveDisputeCrowdsourcer = localFixture.applySignature( 'DisputeCrowdsourcer', market.preemptiveDisputeCrowdsourcer()) # Now we'll dispute the intial report proceedToNextRound(localFixture, market) # By disputing we actually cause the preemptive bond to get placed. assert market.getParticipantStake( ) == preemptiveBondSize + initialStake * 3 # We'll dispute this newly placed bond made from the preemptive contributions proceedToNextRound(localFixture, market) # And now we'll do one more dispute in favor of the initial report proceedToNextRound(localFixture, market) # Now we finalize the market disputeWindow = localFixture.applySignature('DisputeWindow', market.getDisputeWindow()) # Time marches on and the market can be finalized localFixture.contracts["Time"].setTimestamp(disputeWindow.getEndTime() + 1) assert market.finalize() # Because the overloaded bond was disputed there is now sufficient REP to award the overload tokens with ROI as well so both users will receive a 40% ROI expectedWinnings = realBondSize * .4 with TokenDelta(reputationToken, realBondSize + expectedWinnings, localFixture.accounts[0], "Redeeming didn't refund REP"): assert preemptiveDisputeCrowdsourcer.redeem(localFixture.accounts[0]) overloadStake = preemptiveBondSize - realBondSize expectedWinnings = overloadStake * .4 with TokenDelta(reputationToken, overloadStake + expectedWinnings, localFixture.accounts[1], "Redeeming didn't refund REP"): assert preemptiveDisputeCrowdsourcer.redeem(localFixture.accounts[1])
def test_crowdsourcer_transfer(contractsFixture, market, universe): proceedToNextRound(contractsFixture, market) proceedToNextRound(contractsFixture, market) proceedToNextRound(contractsFixture, market) crowdsourcer = contractsFixture.applySignature("DisputeCrowdsourcer", market.getWinningReportingParticipant()) crowdsourcerTokenTransferLog = { 'from': bytesToHexString(tester.a0), 'to': bytesToHexString(tester.a1), 'token': crowdsourcer.address, 'universe': universe.address, 'tokenType': 2, 'value': 0, } with AssertLog(contractsFixture, "TokensTransferred", crowdsourcerTokenTransferLog): assert crowdsourcer.transfer(tester.a1, 0)
def test_contribute(localFixture, universe, cash, market): proceedToNextRound(localFixture, market) with PrintGasUsed(localFixture, "Market.contribute", FIRST_CONTRIBUTE): market.contribute([0, market.getNumTicks()], False, 1) with PrintGasUsed(localFixture, "Market.contribute", FIRST_COMPLETED_CONTRIBUTE): market.contribute([0, market.getNumTicks()], False, market.getParticipantStake()) for i in range(9): proceedToNextRound(localFixture, market, randomPayoutNumerators = True) with PrintGasUsed(localFixture, "Market.contribute", LAST_COMPLETED_CONTRIBUTE): proceedToNextRound(localFixture, market, randomPayoutNumerators = True) with PrintGasUsed(localFixture, "Market.contribute", FORKING_CONTRIBUTE): market.contribute([market.getNumTicks() / 2, market.getNumTicks() / 2], False, market.getParticipantStake())
def test_contribute(localFixture, universe, cash, market): proceedToNextRound(localFixture, market) with PrintGasUsed(localFixture, "Market.contribute", FIRST_CONTRIBUTE): market.contribute([0, market.getNumTicks()], False, 1) with PrintGasUsed(localFixture, "Market.contribute", FIRST_COMPLETED_CONTRIBUTE): market.contribute([0, market.getNumTicks()], False, market.getParticipantStake()) for i in range(9): proceedToNextRound(localFixture, market, randomPayoutNumerators = True) with PrintGasUsed(localFixture, "Market.contribute", LAST_COMPLETED_CONTRIBUTE): proceedToNextRound(localFixture, market, randomPayoutNumerators = True) with PrintGasUsed(localFixture, "Market.contribute", FORKING_CONTRIBUTE): market.contribute([market.getNumTicks() / 2, market.getNumTicks() / 2], False, market.getParticipantStake())
def test_reporting_participant_escape_hatch(localFixture, controller, reputationToken, market, constants, cash): # Initial Reporting proceedToNextRound(localFixture, market) # Crowdsourcer 1 proceedToNextRound(localFixture, market) # Crowdsourcer 2 proceedToNextRound(localFixture, market) initialReporter = localFixture.applySignature( "InitialReporter", market.getReportingParticipant(0)) crowdsourcer1 = localFixture.applySignature( "DisputeCrowdsourcer", market.getReportingParticipant(1)) crowdsourcer2 = localFixture.applySignature( "DisputeCrowdsourcer", market.getReportingParticipant(2)) # We cannot call the escape hatches yet with raises(TransactionFailed): initialReporter.withdrawInEmergency() with raises(TransactionFailed): crowdsourcer1.withdrawInEmergency() with raises(TransactionFailed): crowdsourcer2.withdrawInEmergency() # Emergency Stop assert controller.emergencyStop() # We can now call the escape hatch with TokenDelta(reputationToken, reputationToken.balanceOf(initialReporter.address), tester.a0, "REP was not given back"): assert initialReporter.withdrawInEmergency() with TokenDelta(reputationToken, reputationToken.balanceOf(crowdsourcer1.address), tester.a0, "REP was not given back"): assert crowdsourcer1.withdrawInEmergency() with TokenDelta(reputationToken, reputationToken.balanceOf(crowdsourcer2.address), tester.a0, "REP was not given back"): assert crowdsourcer2.withdrawInEmergency()
def test_roundsOfReporting(rounds, localFixture, market, universe): feeWindow = universe.getOrCreateCurrentFeeWindow() # Do the initial report proceedToNextRound(localFixture, market, moveTimeForward=False) # We can't contribute to a crowdsourcer now since the new fee window is not yet active with raises(TransactionFailed): market.contribute([0, market.getNumTicks()], False) # Do the first round outside of the loop and test logging crowdsourcerCreatedLog = { "universe": universe.address, "market": market.address, "size": universe.getInitialReportMinValue() * 2, "payoutNumerators": [0, market.getNumTicks()], "invalid": False } crowdsourcerContributionLog = { "universe": universe.address, "reporter": bytesToHexString(tester.a0), "market": market.address, "amountStaked": universe.getInitialReportMinValue() * 2 } crowdsourcerCompletedLog = { "universe": universe.address, "market": market.address } with AssertLog(localFixture, "DisputeCrowdsourcerCreated", crowdsourcerCreatedLog): with AssertLog(localFixture, "DisputeCrowdsourcerContribution", crowdsourcerContributionLog): with AssertLog(localFixture, "DisputeCrowdsourcerCompleted", crowdsourcerCompletedLog): proceedToNextRound(localFixture, market) # proceed through several rounds of disputing for i in range(rounds - 2): proceedToNextRound(localFixture, market) assert feeWindow != market.getFeeWindow() feeWindow = market.getFeeWindow() assert feeWindow == universe.getCurrentFeeWindow()
def test_roundsOfReporting(rounds, localFixture, market, universe): feeWindow = universe.getOrCreateCurrentFeeWindow() # Do the initial report proceedToNextRound(localFixture, market, moveTimeForward=False) # Do the first round outside of the loop and test logging crowdsourcerCreatedLog = { "universe": universe.address, "market": market.address, "size": universe.getInitialReportMinValue() * 2, "payoutNumerators": [0, market.getNumTicks()], "invalid": False } crowdsourcerContributionLog = { "universe": universe.address, "reporter": bytesToHexString(tester.a0), "market": market.address, "amountStaked": universe.getInitialReportMinValue() * 2, "description": "Clearly incorrect", } crowdsourcerCompletedLog = { "universe": universe.address, "market": market.address } with AssertLog(localFixture, "DisputeCrowdsourcerCreated", crowdsourcerCreatedLog): with AssertLog(localFixture, "DisputeCrowdsourcerContribution", crowdsourcerContributionLog): with AssertLog(localFixture, "DisputeCrowdsourcerCompleted", crowdsourcerCompletedLog): proceedToNextRound(localFixture, market, description="Clearly incorrect") # proceed through several rounds of disputing for i in range(rounds - 2): proceedToNextRound(localFixture, market) assert feeWindow != market.getFeeWindow() feeWindow = market.getFeeWindow() assert feeWindow == universe.getCurrentFeeWindow()
def test_roundsOfReporting(rounds, localFixture, market, universe): feeWindow = universe.getOrCreateCurrentFeeWindow() # Do the initial report proceedToNextRound(localFixture, market, moveTimeForward = False) # We can't contribute to a crowdsourcer now since the new fee window is not yet active with raises(TransactionFailed): market.contribute([0, market.getNumTicks()], False) # Do the first round outside of the loop and test logging crowdsourcerCreatedLog = { "universe": universe.address, "market": market.address, "size": universe.getInitialReportMinValue() * 2, "payoutNumerators": [0, market.getNumTicks()], "invalid": False } crowdsourcerContributionLog = { "universe": universe.address, "reporter": bytesToHexString(tester.a0), "market": market.address, "amountStaked": universe.getInitialReportMinValue() * 2 } crowdsourcerCompletedLog = { "universe": universe.address, "market": market.address } with AssertLog(localFixture, "DisputeCrowdsourcerCreated", crowdsourcerCreatedLog): with AssertLog(localFixture, "DisputeCrowdsourcerContribution", crowdsourcerContributionLog): with AssertLog(localFixture, "DisputeCrowdsourcerCompleted", crowdsourcerCompletedLog): proceedToNextRound(localFixture, market) # proceed through several rounds of disputing for i in range(rounds - 2): proceedToNextRound(localFixture, market) assert feeWindow != market.getFeeWindow() feeWindow = market.getFeeWindow() assert feeWindow == universe.getCurrentFeeWindow()
def test_multiple_round_crowdsourcer_fees(localFixture, universe, market, cash, reputationToken): constants = localFixture.contracts["Constants"] # Initial Report disputed proceedToNextRound(localFixture, market, tester.k1, True) # Initial Report winning proceedToNextRound(localFixture, market, tester.k2, True) # Initial Report disputed proceedToNextRound(localFixture, market, tester.k1, True, randomPayoutNumerators=True) # Initial Report winning proceedToNextRound(localFixture, market, tester.k3, True) # Get all the winning Reporting Participants initialReporter = localFixture.applySignature('InitialReporter', market.getReportingParticipant(0)) winningDisputeCrowdsourcer1 = localFixture.applySignature('DisputeCrowdsourcer', market.getReportingParticipant(2)) winningDisputeCrowdsourcer2 = localFixture.applySignature('DisputeCrowdsourcer', market.getReportingParticipant(4)) # Get losing Reporting Participants losingDisputeCrowdsourcer1 = localFixture.applySignature('DisputeCrowdsourcer', market.getReportingParticipant(1)) losingDisputeCrowdsourcer2 = localFixture.applySignature('DisputeCrowdsourcer', market.getReportingParticipant(3)) # We can't redeem yet as the market isn't finalized with raises(TransactionFailed): initialReporter.redeem(tester.a0) with raises(TransactionFailed): winningDisputeCrowdsourcer1.redeem(tester.a2) # Fast forward time until the new fee window is over and we can receive fees feeWindow = localFixture.applySignature("FeeWindow", market.getFeeWindow()) localFixture.contracts["Time"].setTimestamp(feeWindow.getEndTime() + 1) assert market.finalize() # The initial reporter locked in REP for 5 rounds. expectedInitialReporterFees = getExpectedFees(localFixture, cash, initialReporter, 5) expectedRep = long(initialReporter.getStake() + initialReporter.getStake() / 2) with TokenDelta(reputationToken, expectedRep, tester.a0, "Redeeming didn't refund REP"): with EtherDelta(expectedInitialReporterFees, tester.a0, localFixture.chain, "Redeeming didn't increase ETH correctly"): assert initialReporter.redeem(tester.a0) # The first winning dispute crowdsourcer will get fees for 4 rounds expectedWinningDisputeCrowdsourcer1Fees = getExpectedFees(localFixture, cash, winningDisputeCrowdsourcer1, 4) expectedRep = long(winningDisputeCrowdsourcer1.getStake() + winningDisputeCrowdsourcer1.getStake() / 2) with TokenDelta(reputationToken, expectedRep, tester.a2, "Redeeming didn't refund REP"): with EtherDelta(expectedWinningDisputeCrowdsourcer1Fees, tester.a2, localFixture.chain, "Redeeming didn't increase ETH correctly"): assert winningDisputeCrowdsourcer1.redeem(tester.a2) # The final winning dispute crowdsourcer will get fees for 2 rounds expectedWinningDisputeCrowdsourcer2Fees = getExpectedFees(localFixture, cash, winningDisputeCrowdsourcer2, 2) expectedRep = long(winningDisputeCrowdsourcer2.getStake() + winningDisputeCrowdsourcer2.getStake() / 2) with TokenDelta(reputationToken, expectedRep, tester.a3, "Redeeming didn't refund REP"): with EtherDelta(expectedWinningDisputeCrowdsourcer2Fees, tester.a3, localFixture.chain, "Redeeming didn't increase ETH correctly"): assert winningDisputeCrowdsourcer2.redeem(tester.a3) # The losing reports get fees as well but no REP # The first losing bond has fees from 5 rounds expectedLosingDisputeCrowdsourcer1Fees = getExpectedFees(localFixture, cash, losingDisputeCrowdsourcer1, 5) with TokenDelta(reputationToken, 0, tester.a1, "Redeeming refunded REP"): with EtherDelta(expectedLosingDisputeCrowdsourcer1Fees, tester.a1, localFixture.chain, "Redeeming didn't increase ETH correctly"): assert losingDisputeCrowdsourcer1.redeem(tester.a1) # The second losing bond has fees from 3 rounds expectedLosingDisputeCrowdsourcer2Fees = getExpectedFees(localFixture, cash, losingDisputeCrowdsourcer2, 3) with TokenDelta(reputationToken, 0, tester.a1, "Redeeming refunded REP"): with EtherDelta(expectedLosingDisputeCrowdsourcer2Fees, tester.a1, localFixture.chain, "Redeeming didn't increase ETH correctly"): assert losingDisputeCrowdsourcer2.redeem(tester.a1)
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()