def test_multiple_contributors_crowdsourcer_fees(localFixture, universe, market, cash, reputationToken): feeWindow = localFixture.applySignature('FeeWindow', market.getFeeWindow()) # We'll make the window active localFixture.contracts["Time"].setTimestamp(feeWindow.getStartTime() + 1) # generate some fees generateFees(localFixture, universe, market) # We'll have testers push markets into the next round by funding dispute crowdsourcers amount = market.getTotalStake() with TokenDelta(reputationToken, -amount, tester.a1, "Disputing did not reduce REP balance correctly"): assert market.contribute([0, market.getNumTicks()], False, amount, sender=tester.k1, startgas=long(6.7 * 10**6)) with TokenDelta(reputationToken, -amount, tester.a2, "Disputing did not reduce REP balance correctly"): assert market.contribute([0, market.getNumTicks()], False, amount, sender=tester.k2, startgas=long(6.7 * 10**6)) newFeeWindowAddress = market.getFeeWindow() assert newFeeWindowAddress != feeWindow.address # fast forward time to the fee new window and generate additional fees feeWindow = localFixture.applySignature('FeeWindow', newFeeWindowAddress) localFixture.contracts["Time"].setTimestamp(feeWindow.getStartTime() + 1) # Fast forward time until the new fee window is over and we can redeem our winning stake, and dispute bond tokens and receive fees localFixture.contracts["Time"].setTimestamp(feeWindow.getEndTime() + 1) assert market.finalize() marketDisputeCrowdsourcer = localFixture.applySignature( 'DisputeCrowdsourcer', market.getReportingParticipant(1)) # The dispute crowdsourcer contributors locked in REP for 2 rounds and staked twice the initial reporter so they split 2/3 of the total stake expectedFees = cash.balanceOf(feeWindow.address) + cash.balanceOf( universe.getOrCreateFeeWindowBefore(feeWindow.address)) expectedFees = expectedFees / 3 * 2 expectedRep = long(amount + amount / 2) with TokenDelta(reputationToken, expectedRep, tester.a1, "Redeeming didn't refund REP"): with EtherDelta(expectedFees / 2, tester.a1, localFixture.chain, "Redeeming didn't increase ETH correctly"): assert marketDisputeCrowdsourcer.redeem(tester.a1) with TokenDelta(reputationToken, expectedRep + 1, tester.a2, "Redeeming didn't refund REP"): with EtherDelta(expectedFees - expectedFees / 2, tester.a2, localFixture.chain, "Redeeming didn't increase ETH correctly"): assert marketDisputeCrowdsourcer.redeem(tester.a2)
def test_market_escape_hatch_partial_fees(localFixture, market, reputationToken, reportingWindow, constants, controller): # We'll skip to Limited reporting and make a report localFixture.chain.head_state.timestamp = reportingWindow.getStartTime( ) + 1 stakeToken = localFixture.getStakeToken(market, [0, market.getNumTicks()], False) MarketEtherDelta = constants.DEFAULT_VALIDITY_BOND( ) - localFixture.chain.head_state.get_balance(market.address) with EtherDelta(MarketEtherDelta, market.address, localFixture.chain, "First reporter gas fee was not given to first reporter"): with TokenDelta(reputationToken, -reputationToken.balanceOf(market.address), market.address, "REP balance was not given to the first reporter"): stakeToken.buy(0, sender=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_mailbox_eth_happy_path(localFixture, mailbox): # We can send some ETH to the mailbox with EtherDelta(100, mailbox.address, localFixture.chain, "Deposit did not work"): assert mailbox.depositEther(value=100) # We can also withdraw the ETH balance of the mailbox with EtherDelta(100, tester.a0, localFixture.chain, "Withdraw did not work"): assert mailbox.withdrawEther()
def test_one_round_crowdsourcer_fees(localFixture, universe, market, cash, reputationToken): feeWindow = localFixture.applySignature('FeeWindow', market.getFeeWindow()) constants = localFixture.contracts["Constants"] # We'll make the window active localFixture.contracts["Time"].setTimestamp(feeWindow.getStartTime() + 1) # generate some fees generateFees(localFixture, universe, market) # We'll have testers push markets into the next round by funding dispute crowdsourcers amount = 2 * market.getParticipantStake() with TokenDelta(reputationToken, -amount, tester.a1, "Disputing did not reduce REP balance correctly"): assert market.contribute([0, market.getNumTicks()], False, amount, "", sender=tester.k1) newFeeWindowAddress = market.getFeeWindow() assert newFeeWindowAddress != feeWindow.address # fast forward time to the fee new window and generate additional fees feeWindow = localFixture.applySignature('FeeWindow', newFeeWindowAddress) localFixture.contracts["Time"].setTimestamp(feeWindow.getStartTime() + 1) # Fast forward time until the new fee window is over and we can redeem our winning stake, and dispute bond tokens and receive fees localFixture.contracts["Time"].setTimestamp(feeWindow.getEndTime() + 1) assert market.finalize() initialReporter = localFixture.applySignature('InitialReporter', market.getReportingParticipant(0)) marketDisputeCrowdsourcer = localFixture.applySignature('DisputeCrowdsourcer', market.getReportingParticipant(1)) # The dispute crowdsourcer contributor locked in REP for 2 rounds, as did the Initial Reporter expectedTotalFees = cash.balanceOf(feeWindow.address) + cash.balanceOf(universe.getOrCreateFeeWindowBefore(feeWindow.address)) expectedFees = expectedTotalFees * 2 / 3 expectedRep = market.getParticipantStake() assert expectedRep == long(marketDisputeCrowdsourcer.getStake() + marketDisputeCrowdsourcer.getStake() / 2) disputeCrowdsourcerRedeemedLog = { "reporter": bytesToHexString(tester.a1), "disputeCrowdsourcer": marketDisputeCrowdsourcer.address, "amountRedeemed": marketDisputeCrowdsourcer.getStake(), "repReceived": expectedRep, "reportingFeesReceived": expectedFees, "payoutNumerators": [0, market.getNumTicks()], "universe": universe.address, "market": market.address } with AssertLog(localFixture, "DisputeCrowdsourcerRedeemed", disputeCrowdsourcerRedeemedLog): with TokenDelta(reputationToken, expectedRep, tester.a1, "Redeeming didn't refund REP"): with EtherDelta(expectedFees, tester.a1, localFixture.chain, "Redeeming didn't increase ETH correctly"): assert marketDisputeCrowdsourcer.redeem(tester.a1, sender=tester.k1) # The initial reporter gets fees even though they were not correct. They do not get their REP back though expectedFees = cash.balanceOf(feeWindow.address) + cash.balanceOf(universe.getOrCreateFeeWindowBefore(feeWindow.address)) with TokenDelta(reputationToken, 0, tester.a0, "Redeeming didn't refund REP"): with EtherDelta(expectedFees, tester.a0, localFixture.chain, "Redeeming didn't increase ETH correctly"): assert initialReporter.redeem(tester.a0)
def test_failed_crowdsourcer_fees(finalize, localFixture, universe, market, cash, reputationToken): feeWindow = localFixture.applySignature('FeeWindow', market.getFeeWindow()) # generate some fees generateFees(localFixture, universe, market) # We'll make the window active localFixture.contracts["Time"].setTimestamp(feeWindow.getStartTime() + 1) # generate some fees generateFees(localFixture, universe, market) # We'll have testers contribute to a dispute but not reach the target amount = market.getParticipantStake() # confirm we can contribute 0 assert market.contribute([1, market.getNumTicks()-1], False, 0, "", sender=tester.k1) with TokenDelta(reputationToken, -amount + 1, tester.a1, "Disputing did not reduce REP balance correctly"): assert market.contribute([1, market.getNumTicks()-1], False, amount - 1, "", sender=tester.k1) with TokenDelta(reputationToken, -amount + 1, tester.a2, "Disputing did not reduce REP balance correctly"): assert market.contribute([1, market.getNumTicks()-1], False, amount - 1, "", sender=tester.k2) assert market.getFeeWindow() == feeWindow.address payoutDistributionHash = market.derivePayoutDistributionHash([1, market.getNumTicks()-1], False) failedCrowdsourcer = localFixture.applySignature("DisputeCrowdsourcer", market.getCrowdsourcer(payoutDistributionHash)) # confirm we cannot contribute directly to a crowdsourcer without going through the market with raises(TransactionFailed): failedCrowdsourcer.contribute(tester.a0, 1) if finalize: # Fast forward time until the fee window is over and we can redeem to recieve the REP back and fees localFixture.contracts["Time"].setTimestamp(feeWindow.getEndTime() + 1) expectedTotalFees = getExpectedFees(localFixture, cash, failedCrowdsourcer, 1) else: # Continue to the next round which will disavow failed crowdsourcers and let us redeem once the window is over market.contribute([0, market.getNumTicks()], False, amount * 2, "") assert market.getFeeWindow() != feeWindow.address localFixture.contracts["Time"].setTimestamp(feeWindow.getEndTime() + 1) expectedTotalFees = getExpectedFees(localFixture, cash, failedCrowdsourcer, 1) with TokenDelta(reputationToken, amount - 1, tester.a1, "Redeeming did not refund REP"): with EtherDelta(expectedTotalFees / 2, tester.a1, localFixture.chain, "Redeeming didn't increase ETH correctly"): assert failedCrowdsourcer.redeem(tester.a1) with TokenDelta(reputationToken, amount - 1, tester.a2, "Redeeming did not refund REP"): with EtherDelta(cash.balanceOf(failedCrowdsourcer.address), tester.a2, localFixture.chain, "Redeeming didn't increase ETH correctly"): assert failedCrowdsourcer.redeem(tester.a2)
def test_take_best_order_with_shares_escrowed_buy_with_shares_categorical(contractsFixture, cash, categoricalMarket, universe): market = categoricalMarket 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)) thirdShareToken = contractsFixture.applySignature('ShareToken', market.getShareToken(2)) # buy complete sets for both users numTicks = market.getNumTicks() assert completeSets.publicBuyCompleteSets(market.address, fix(1), sender=tester.k1, value=fix('1', numTicks)) assert completeSets.publicBuyCompleteSets(market.address, fix(1), sender=tester.k2, value=fix('1', numTicks)) assert firstShareToken.balanceOf(tester.a1) == firstShareToken.balanceOf(tester.a2) == fix(1) assert secondShareToken.balanceOf(tester.a1) == secondShareToken.balanceOf(tester.a2) == fix(1) assert thirdShareToken.balanceOf(tester.a1) == thirdShareToken.balanceOf(tester.a2) == fix(1) # create order with shares orderID = createOrder.publicCreateOrder(ASK, fix(1), 6000, market.address, 0, longTo32Bytes(0), longTo32Bytes(0), "42", sender=tester.k1) assert orderID # fill order with shares using on-chain matcher totalProceeds = fix(1, numTicks) totalProceeds -= fix(1, numTicks) / market.getMarketCreatorSettlementFeeDivisor() totalProceeds -= fix(1, numTicks) / universe.getOrCacheReportingFeeDivisor() expectedTester1Payout = totalProceeds * 6000 / numTicks expectedTester2Payout = totalProceeds * (numTicks - 6000) / numTicks with EtherDelta(expectedTester1Payout, tester.a1, contractsFixture.chain, "Tester 1 ETH delta wrong"): with EtherDelta(expectedTester2Payout, tester.a2, contractsFixture.chain, "Tester 2 ETH delta wrong"): with PrintGasUsed(contractsFixture, "categoricalFill", 0): assert trade.publicFillBestOrder(BID, market.address, 0, fix(1), 6000, "43", sender=tester.k2) == 0 assert firstShareToken.balanceOf(tester.a1) == 0 assert secondShareToken.balanceOf(tester.a1) == fix(1) assert thirdShareToken.balanceOf(tester.a1) == fix(1) assert firstShareToken.balanceOf(tester.a2) == fix(1) assert secondShareToken.balanceOf(tester.a2) == 0 assert thirdShareToken.balanceOf(tester.a2) == 0 assert orders.getAmount(orderID) == 0 assert orders.getPrice(orderID) == 0 assert orders.getOrderCreator(orderID) == longToHexString(0) assert orders.getOrderMoneyEscrowed(orderID) == 0 assert orders.getOrderSharesEscrowed(orderID) == 0 assert orders.getBetterOrderId(orderID) == longTo32Bytes(0) assert orders.getWorseOrderId(orderID) == longTo32Bytes(0)
def generateFees(fixture, universe, market): completeSets = fixture.contracts['CompleteSets'] cash = fixture.contracts['Cash'] mailbox = fixture.applySignature('Mailbox', market.getMarketCreatorMailbox()) assert mailbox.withdrawEther() cost = 1000 * market.getNumTicks() marketCreatorFees = cost / market.getMarketCreatorSettlementFeeDivisor() completeSets.publicBuyCompleteSets(market.address, 1000, sender=tester.k1, value=cost) with TokenDelta( cash, marketCreatorFees, mailbox.address, "The market creator mailbox didn't get their share of fees from complete set sale" ): completeSets.publicSellCompleteSets(market.address, 1000, sender=tester.k1) with EtherDelta( marketCreatorFees, market.getOwner(), fixture.chain, "The market creator did not get their fees when withdrawing ETH from the mailbox" ): assert mailbox.withdrawEther() fees = cash.balanceOf(universe.getNextFeeWindow()) reporterFees = cost / universe.getOrCacheReportingFeeDivisor() assert fees == reporterFees, "Cash balance of window higher by: " + str( fees - reporterFees)
def test_duplicate_creation_transaction(contractsFixture, cash, market): orders = contractsFixture.contracts['Orders'] createOrder = contractsFixture.contracts['CreateOrder'] with EtherDelta(-fix(1, 4000), tester.a0, contractsFixture.chain): orderID = createOrder.publicCreateOrder(BID, fix(1), 4000, market.address, 1, longTo32Bytes(0), longTo32Bytes(0), "7", value=fix(1, 4000)) assert orderID with raises(TransactionFailed): createOrder.publicCreateOrder(BID, fix(1), 4000, market.address, 1, longTo32Bytes(0), longTo32Bytes(0), "7", value=fix(1, 4000))
def test_market_escape_hatch_all_fees(localFixture, controller, market, reputationToken): # We can't call the Market escape hatch when things are alright with raises(TransactionFailed): market.withdrawInEmergency() # Emergency Stop escapeHatchChangedLog = { "isOn": True, } with AssertLog(localFixture, "EscapeHatchChanged", escapeHatchChangedLog): assert controller.emergencyStop() # Now we can call the market escape hatch and get back all the fees paid in creation with EtherDelta(localFixture.chain.head_state.get_balance(market.address), market.getOwner(), localFixture.chain, "ETH balance was not given to the market owner"): with TokenDelta(reputationToken, reputationToken.balanceOf(market.address), market.getOwner(), "REP balance was not given to the market owner"): assert market.withdrawInEmergency() escapeHatchChangedLog = { "isOn": False, } with AssertLog(localFixture, "EscapeHatchChanged", escapeHatchChangedLog): assert controller.release()
def test_mailbox_eth_failure(localFixture, mailbox): # We send some ETH to the mailbox with EtherDelta(100, mailbox.address, localFixture.chain, "Deposit did not work"): assert mailbox.depositEther(value=100) # Withdrawing as someone other than the owner will fail with raises(TransactionFailed): mailbox.withdrawEther(sender=tester.k1)
def test_mailbox_cash_happy_path(localFixture, mailbox, cash): # We can send some Cash to the mailbox assert cash.depositEther(value=100) assert cash.balanceOf(tester.a0) == 100 with TokenDelta(cash, 100, mailbox.address, "Deposit did not work"): assert cash.transfer(mailbox.address, 100) # We can withdraw "Ether" and the Cash balance in the mailbox will be given to the owner as Ether with EtherDelta(100, tester.a0, localFixture.chain, "Withdraw did not work"): assert mailbox.withdrawEther()
def test_initialReport_transfer_ownership(localFixture, universe, market, cash, constants): reputationToken = localFixture.applySignature( "ReputationToken", universe.getReputationToken()) # proceed to the initial reporting period proceedToInitialReporting(localFixture, market) # do an initial report as someone other than the designated reporter assert market.doInitialReport([0, market.getNumTicks()], False, sender=tester.k1) # the market is now assigned a fee window newFeeWindowAddress = market.getFeeWindow() assert newFeeWindowAddress feeWindow = localFixture.applySignature('FeeWindow', newFeeWindowAddress) # time marches on and the market can be finalized localFixture.contracts["Time"].setTimestamp(feeWindow.getEndTime() + 1) assert market.finalize() # We can see that the market reports the designated reporter did not show assert not market.designatedReporterShowed() # Let's get a reference to the Initial Reporter bond and transfer it to the original designated reporter account initialReporter = localFixture.applySignature("InitialReporter", market.getInitialReporter()) transferLog = { "universe": universe.address, "market": market.address, "from": bytesToHexString(tester.a1), "to": initialReporter.getDesignatedReporter(), } with AssertLog(localFixture, "InitialReporterTransfered", transferLog): assert initialReporter.transferOwnership( initialReporter.getDesignatedReporter(), sender=tester.k1) # The market still correctly indicates the designated reporter did not show up assert not market.designatedReporterShowed() # When we redeem the initialReporter it goes to the correct party as well expectedRep = initialReporter.getStake() owner = initialReporter.getOwner() expectedGasBond = 2 * constants.GAS_TO_REPORT( ) * constants.DEFAULT_REPORTING_GAS_PRICE() with EtherDelta( expectedGasBond, owner, localFixture.chain, "Initial reporter did not get the reporting gas cost bond"): with TokenDelta(reputationToken, expectedRep, owner, "Redeeming didn't refund REP"): assert initialReporter.redeem(owner)
def localSnapshot(fixture, kitchenSinkSnapshot): fixture.resetToSnapshot(kitchenSinkSnapshot) universe = ABIContract(fixture.chain, kitchenSinkSnapshot['universe'].translator, kitchenSinkSnapshot['universe'].address) market = ABIContract(fixture.chain, kitchenSinkSnapshot['binaryMarket'].translator, kitchenSinkSnapshot['binaryMarket'].address) categoricalMarket = ABIContract( fixture.chain, kitchenSinkSnapshot['categoricalMarket'].translator, kitchenSinkSnapshot['categoricalMarket'].address) scalarMarket = ABIContract(fixture.chain, kitchenSinkSnapshot['scalarMarket'].translator, kitchenSinkSnapshot['scalarMarket'].address) cash = ABIContract(fixture.chain, kitchenSinkSnapshot['cash'].translator, kitchenSinkSnapshot['cash'].address) completeSets = fixture.contracts['CompleteSets'] mailbox = fixture.applySignature('Mailbox', market.getMarketCreatorMailbox()) # Generate the fees in our initial reporting window cost = 1000 * market.getNumTicks() marketCreatorFees = cost / market.getMarketCreatorSettlementFeeDivisor() completeSets.publicBuyCompleteSets(market.address, 1000, sender=tester.k1, value=cost) with TokenDelta( cash, marketCreatorFees, mailbox.address, "The market creator mailbox didn't get their share of fees from complete set sale" ): completeSets.publicSellCompleteSets(market.address, 1000, sender=tester.k1) with EtherDelta( marketCreatorFees, market.getOwner(), fixture.chain, "The market creator did not get their fees when withdrawing ETH from the mailbox" ): assert mailbox.withdrawEther() fees = cash.balanceOf(market.getReportingWindow()) reporterFees = cost / universe.getOrCacheReportingFeeDivisor() assert fees == reporterFees # Distribute REP reputationToken = fixture.applySignature('ReputationToken', universe.getReputationToken()) for testAccount in [tester.a1, tester.a2, tester.a3, tester.a4, tester.a5]: reputationToken.transfer(testAccount, 1 * 10**6 * 10**18) return fixture.createSnapshot()
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_market_escape_hatch_all_fees(localFixture, controller, market, reputationToken): # We can't call the Market escape hatch when things are alright with raises(TransactionFailed): market.withdrawInEmergency() # Emergency Stop assert controller.registerContract("EmergencyStop", 1, "0", "0") # Now we can call the market escape hatch and get back all the fees paid in creation with EtherDelta(localFixture.chain.head_state.get_balance(market.address), market.getOwner(), localFixture.chain, "ETH balance was not given to the market owner"): with TokenDelta(reputationToken, reputationToken.balanceOf(market.address), market.getOwner(), "REP balance was not given to the market owner"): assert market.withdrawInEmergency()
def test_variable_validity_bond(invalid, contractsFixture, universe, cash): # We can't make a market with less than the minimum required validity bond minimumValidityBond = universe.getOrCacheMarketCreationCost() with raises(TransactionFailed): contractsFixture.createReasonableYesNoMarket( universe, cash, validityBond=minimumValidityBond - 1) # But we can make one with a greater bond higherValidityBond = minimumValidityBond + 1 market = contractsFixture.createReasonableYesNoMarket( universe, cash, validityBond=higherValidityBond) assert market.getValidityBondAttoEth() == higherValidityBond # If we resolve the market the bond in it's entirety will go to the fee pool or to the market creator if the resolution was not invalid proceedToDesignatedReporting(contractsFixture, market) if invalid: market.doInitialReport( [market.getNumTicks() / 2, market.getNumTicks() / 2], True, "") else: market.doInitialReport([0, market.getNumTicks()], False, "") # Move time forward so we can finalize and see the bond move feeWindow = contractsFixture.applySignature('FeeWindow', market.getFeeWindow()) assert contractsFixture.contracts["Time"].setTimestamp( feeWindow.getEndTime() + 1) if invalid: with TokenDelta(cash, higherValidityBond, universe.getAuction(), "Validity bond did not go to the auction"): market.finalize() else: with EtherDelta(higherValidityBond, market.getMarketCreatorMailbox(), contractsFixture.chain, "Validity bond did not go to the market creator"): market.finalize()
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_initial_report_and_participation_fee_collection( localFixture, universe, market, categoricalMarket, scalarMarket, cash, reputationToken): feeWindow = localFixture.applySignature('FeeWindow', market.getFeeWindow()) constants = localFixture.contracts["Constants"] # We cannot purchase participation tokens yet since the window isn't active with raises(TransactionFailed): feeWindow.buy(1) # generate some fees generateFees(localFixture, universe, market) # We'll make the window active then purchase some participation tokens localFixture.contracts["Time"].setTimestamp(feeWindow.getStartTime() + 1) feeWindowAmount = 100 with TokenDelta(reputationToken, -feeWindowAmount, tester.a0, "Buying participation tokens didn't deduct REP correctly"): with TokenDelta( feeWindow, feeWindowAmount, tester.a0, "Buying participation tokens didn't increase participation token balance correctly" ): assert feeWindow.buy(feeWindowAmount) # As other testers we'll buy some more assert feeWindow.buy(feeWindowAmount, sender=tester.k1) assert feeWindow.buy(feeWindowAmount, sender=tester.k2) assert feeWindow.buy(feeWindowAmount, sender=tester.k3) # We can't redeem the participation tokens yet since the window isn't over with raises(TransactionFailed): feeWindow.redeem(False) # Now end the window and finalize localFixture.contracts["Time"].setTimestamp(feeWindow.getEndTime() + 1) assert market.finalize() assert categoricalMarket.finalize() assert scalarMarket.finalize() marketInitialReport = localFixture.applySignature( 'InitialReporter', market.getInitialReporter()) categoricalInitialReport = localFixture.applySignature( 'InitialReporter', categoricalMarket.getInitialReporter()) scalarInitialReport = localFixture.applySignature( 'InitialReporter', scalarMarket.getInitialReporter()) reporterFees = 1000 * market.getNumTicks( ) / universe.getOrCacheReportingFeeDivisor() totalStake = feeWindow.getTotalFeeStake() assert cash.balanceOf(feeWindow.address) == reporterFees expectedParticipationFees = reporterFees * feeWindowAmount / totalStake # Cashing out Participation tokens will awards fees proportional to the total winning stake in the window with TokenDelta(reputationToken, feeWindowAmount, tester.a0, "Redeeming participation tokens didn't refund REP"): with TokenDelta( feeWindow, -feeWindowAmount, tester.a0, "Redeeming participation tokens didn't decrease participation token balance correctly" ): with EtherDelta( expectedParticipationFees, tester.a0, localFixture.chain, "Redeeming participation tokens didn't increase ETH correctly" ): assert feeWindow.redeem(tester.a0) with TokenDelta(reputationToken, feeWindowAmount, 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, localFixture.chain, "Redeeming participation tokens didn't increase ETH correctly" ): assert feeWindow.redeem(tester.a1) with TokenDelta(reputationToken, feeWindowAmount, 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, localFixture.chain, "Redeeming participation tokens didn't increase ETH correctly" ): assert feeWindow.redeem(tester.a2) logs = [] captureFilteredLogs(localFixture.chain.head_state, localFixture.contracts['Augur'], logs) marketStake = marketInitialReport.getStake() expectedFees = reporterFees * marketStake / totalStake winningsRedeemedLog = { "reporter": bytesToHexString(tester.a0), "reportingParticipant": marketInitialReport.address, "amountRedeemed": marketStake, "reportingFeesReceived": expectedFees, "payoutNumerators": [market.getNumTicks(), 0], "universe": universe.address, "market": market.address } with AssertLog(localFixture, "WinningsRedeemed", winningsRedeemedLog): with TokenDelta(reputationToken, marketStake, tester.a0, "Redeeming didn't refund REP"): with EtherDelta(expectedFees, tester.a0, localFixture.chain, "Redeeming didn't increase ETH correctly"): assert marketInitialReport.redeem(tester.a0) categoricalMarketStake = categoricalInitialReport.getStake() expectedFees = reporterFees * categoricalMarketStake / totalStake with TokenDelta(reputationToken, categoricalMarketStake, tester.a0, "Redeeming didn't refund REP"): with EtherDelta(expectedFees, tester.a0, localFixture.chain, "Redeeming didn't increase ETH correctly"): assert categoricalInitialReport.redeem(tester.a0)
def test_forking(localFixture, universe, market, categoricalMarket, cash, reputationToken): # Let's do some initial disputes for the categorical market proceedToNextRound(localFixture, categoricalMarket, tester.k1, moveTimeForward=False) # Get to a fork testers = [tester.k0, tester.k1, tester.k2, tester.k3] testerIndex = 1 while (market.getForkingMarket() == longToHexString(0)): proceedToNextRound(localFixture, market, testers[testerIndex], True) testerIndex += 1 testerIndex = testerIndex % len(testers) # Have the participants fork and create new child universes for i in range(market.getNumParticipants()): reportingParticipant = localFixture.applySignature( "DisputeCrowdsourcer", market.getReportingParticipant(i)) with PrintGasUsed(localFixture, "Fork:", 0): reportingParticipant.fork(startgas=long(6.7 * 10**6)) # Finalize the fork finalizeFork(localFixture, market, universe) categoricalDisputeCrowdsourcer = localFixture.applySignature( "DisputeCrowdsourcer", categoricalMarket.getReportingParticipant(1)) # Migrate the categorical market into the winning universe. This will disavow the dispute crowdsourcer on it, letting us redeem for original universe rep and eth assert categoricalMarket.migrateThroughOneFork() expectedRep = categoricalDisputeCrowdsourcer.getStake() expectedEth = getExpectedFees(localFixture, cash, categoricalDisputeCrowdsourcer, 2) with EtherDelta(expectedEth, tester.a1, localFixture.chain, "Redeeming didn't increase ETH correctly"): with TokenDelta(reputationToken, expectedRep, tester.a1, "Redeeming didn't increase REP correctly"): categoricalDisputeCrowdsourcer.redeem(tester.a1, startgas=long(6.7 * 10**6)) # Now we'll redeem the forked reporting participants testers = [tester.a0, tester.a1, tester.a2, tester.a3] for i in range(market.getNumParticipants()): account = testers[i % 4] reportingParticipant = localFixture.applySignature( "DisputeCrowdsourcer", market.getReportingParticipant(i)) expectedRep = reportingParticipant.getStake() expectedRep += expectedRep / localFixture.contracts[ "Constants"].FORK_MIGRATION_PERCENTAGE_BONUS_DIVISOR() expectedRep += reportingParticipant.getStake() / 2 expectedEth = cash.balanceOf(reportingParticipant.address) newReputationToken = localFixture.applySignature( "ReputationToken", reportingParticipant.getReputationToken()) with EtherDelta(expectedEth, account, localFixture.chain, "Redeeming didn't increase ETH correctly"): with TokenDelta(newReputationToken, expectedRep, account, "Redeeming didn't increase REP correctly"): reportingParticipant.redeem(account, startgas=long(6.7 * 10**6))
def test_bootstrap(localFixture, universe, reputationToken, auction, time, cash): # Lets confirm the auction is in the dormant state initially and also in bootstrap mode assert auction.getRoundType() == 0 assert auction.bootstrapMode() assert not auction.isActive() # If we move time forward to the next auction start time we can see that the auction is now active. startTime = auction.getAuctionStartTime() assert time.setTimestamp(startTime) assert auction.getRoundType() == 2 assert auction.bootstrapMode() assert auction.isActive() # We can get the price of ETH in REP assert auction.getRepSalePriceInAttoEth() == auction.initialRepSalePrice() # However since we're in bootstrap mode we cannot yet sell REP for ETH. with raises(TransactionFailed): auction.getEthSalePriceInAttoRep() # If we move time forward but stay in the auction the sale price of the REP will drop accordingly. We'll move forward an hour and confirm the price is 1/24th less repSalePrice = auction.initialRepSalePrice() * 23 / 24 assert time.incrementTimestamp(60 * 60) assert auction.getRepSalePriceInAttoEth() == repSalePrice # Before we do any trading lets confirm the contract balances are as expected repAuctionToken = localFixture.applySignature("AuctionToken", auction.repAuctionToken()) assert auction.initialAttoRepBalance() == reputationToken.balanceOf( repAuctionToken.address) assert auction.initialAttoRepBalance() == 11 * 10**6 * 10**18 / 400 assert localFixture.chain.head_state.get_balance(auction.address) == 0 # We can purchase some of the REP now. We'll send some extra ETH to confirm it just gets returned too repAmount = 10**18 cost = repAmount * repSalePrice / 10**18 with TokenDelta(cash, cost, auction.address, "ETH was not transfered to auction correctly"): with TokenDelta( repAuctionToken, cost, tester.a0, "REP auction token was not transferred to the user correctly"): assert auction.tradeEthForRep(repAmount, value=cost + 20) # Lets purchase the remaining REP in the auction repAmount = auction.getCurrentAttoRepBalance() cost = repAmount * repSalePrice / 10**18 with TokenDelta(cash, cost, auction.address, "ETH was not transfered to auction correctly"): with TokenDelta( repAuctionToken, cost, tester.a0, "REP auction token was not transferred to the user correctly"): assert auction.tradeEthForRep(repAmount, value=cost) # If we try to purchase any more the transaction will fail with raises(TransactionFailed): auction.tradeEthForRep(repAmount, value=cost) # Lets end this auction then move time to the next auction endTime = auction.getAuctionEndTime() assert time.setTimestamp(endTime + 1) assert auction.getRoundType() == 3 assert auction.bootstrapMode() assert not auction.isActive() # Now we can redeem the tokens we received for the amount of REP we purchased expectedREP = reputationToken.balanceOf(repAuctionToken.address) with TokenDelta( reputationToken, expectedREP, tester.a0, "REP was not distributed correctly from auction token redemption"): repAuctionToken.redeem() startTime = auction.getAuctionStartTime() assert time.setTimestamp(startTime) # We can see that the ETH and REP auctions are active assert auction.getRoundType() == 6 assert auction.isActive() assert auction.getRepSalePriceInAttoEth() == auction.initialRepSalePrice() assert auction.getEthSalePriceInAttoRep() == auction.initialEthSalePrice() assert not auction.bootstrapMode() ethAuctionToken = localFixture.applySignature("AuctionToken", auction.ethAuctionToken()) ethSalePrice = auction.initialEthSalePrice() ethAmount = 10**18 cost = ethAmount * ethSalePrice / 10**18 with TokenDelta( ethAuctionToken, cost, tester.a0, "ETH auction token was not transferred to the user correctly"): with TokenDelta(reputationToken, cost, auction.address, "REP was not transferred to the auction correctly"): assert auction.tradeRepForEth(ethAmount) endTime = auction.getAuctionEndTime() assert time.setTimestamp(endTime + 1) # We can redeem the eth auction tokens for ETH. Since the auction ended with no other bids we get all the ETH with EtherDelta( cash.balanceOf(ethAuctionToken.address), tester.a0, localFixture.chain, "ETH redemption from eth auction token did not work correctly"): assert ethAuctionToken.redeem()
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_dispute_bond_fee_collection(localFixture, universe, market, categoricalMarket, scalarMarket, cash, reputationToken, reportingWindow): # We'll have testers put up dispute bonds against the designated reports and place stake in other outcomes disputeStake = localFixture.contracts[ "Constants"].DESIGNATED_REPORTER_DISPUTE_BOND_AMOUNT() otherOutcomeStake = 10**18 totalCost = disputeStake + otherOutcomeStake with TokenDelta(reputationToken, -totalCost, tester.a1, "Disputing did not reduce REP balance correctly"): with StakeDelta(totalCost, totalCost, 0, market, reportingWindow, "Disputing is not adjust stake accounting correctly"): assert market.disputeDesignatedReport([market.getNumTicks(), 0], otherOutcomeStake, False, sender=tester.k1) with StakeDelta(totalCost, totalCost, 0, categoricalMarket, reportingWindow, "Disputing is not adjust stake accounting correctly"): with TokenDelta(reputationToken, -totalCost, tester.a2, "Disputing did not reduce REP balance correctly"): assert categoricalMarket.disputeDesignatedReport( [categoricalMarket.getNumTicks(), 0, 0], otherOutcomeStake, False, sender=tester.k2) with TokenDelta(reputationToken, -totalCost, tester.a3, "Disputing did not reduce REP balance correctly"): with StakeDelta(totalCost, totalCost, 0, scalarMarket, reportingWindow, "Disputing is not adjust stake accounting correctly"): assert scalarMarket.disputeDesignatedReport( [scalarMarket.getNumTicks(), 0], otherOutcomeStake, False, sender=tester.k3) # Fast forward time until the window is over and we can redeem our winning stake, and dispute bond tokens and receive fees localFixture.chain.head_state.timestamp = reportingWindow.getEndTime() + 1 assert market.tryFinalize() assert categoricalMarket.tryFinalize() assert scalarMarket.tryFinalize() marketDesignatedStake = localFixture.getOrCreateStakeToken( market, [market.getNumTicks(), 0]) categoricalMarketDesignatedStake = localFixture.getOrCreateStakeToken( categoricalMarket, [categoricalMarket.getNumTicks(), 0, 0]) scalarMarketDesignatedStake = localFixture.getOrCreateStakeToken( scalarMarket, [scalarMarket.getNumTicks(), 0]) reporterFees = 1000 * market.getNumTicks( ) / universe.getOrCacheReportingFeeDivisor() totalWinningStake = reportingWindow.getTotalWinningStake() assert cash.balanceOf(reportingWindow.address) == reporterFees # Tester 0 placed losing designated reports so that stake is worthless. The other testers have both stake and bonds that can be redeemed for a share of fees marketStake = marketDesignatedStake.balanceOf(tester.a1) expectedFees = reporterFees * marketStake / totalWinningStake with EtherDelta(expectedFees, tester.a1, localFixture.chain, "Redeeming Stake tokens didn't increase ETH correctly"): with TokenDelta( marketDesignatedStake, -marketStake, tester.a1, "Redeeming Stake tokens didn't decrease Stake token balance correctly" ): assert marketDesignatedStake.redeemWinningTokens(False, sender=tester.k1) categoricalMarketStake = categoricalMarketDesignatedStake.balanceOf( tester.a2) expectedFees = reporterFees * categoricalMarketStake / totalWinningStake with EtherDelta(expectedFees, tester.a2, localFixture.chain, "Redeeming Stake tokens didn't increase ETH correctly"): with TokenDelta( categoricalMarketDesignatedStake, -categoricalMarketStake, tester.a2, "Redeeming Stake tokens didn't decrease Stake token balance correctly" ): assert categoricalMarketDesignatedStake.redeemWinningTokens( False, sender=tester.k2) scalarMarketStake = scalarMarketDesignatedStake.balanceOf(tester.a3) expectedFees = reporterFees * scalarMarketStake / totalWinningStake with EtherDelta(expectedFees, tester.a3, localFixture.chain, "Redeeming Stake tokens didn't increase ETH correctly"): with TokenDelta( scalarMarketDesignatedStake, -scalarMarketStake, tester.a3, "Redeeming Stake tokens didn't decrease Stake token balance correctly" ): assert scalarMarketDesignatedStake.redeemWinningTokens( False, sender=tester.k3) # Now we'll redeem the dispute bonds marketDisputeBond = localFixture.applySignature( "DisputeBond", market.getDesignatedReporterDisputeBond()) categoricalMarketDisputeBond = localFixture.applySignature( "DisputeBond", categoricalMarket.getDesignatedReporterDisputeBond()) scalarMarketDisputeBond = localFixture.applySignature( "DisputeBond", scalarMarket.getDesignatedReporterDisputeBond()) expectedDisputeFees = reporterFees * disputeStake / totalWinningStake with EtherDelta( expectedDisputeFees, tester.a1, localFixture.chain, "Redeeming Dispute Bond token didn't increase ETH correctly"): assert marketDisputeBond.withdraw(False, sender=tester.k1) with EtherDelta( expectedDisputeFees, tester.a2, localFixture.chain, "Redeeming Dispute Bond token didn't increase ETH correctly"): assert categoricalMarketDisputeBond.withdraw(False, sender=tester.k2) remainingFees = cash.balanceOf(reportingWindow.address) with EtherDelta( remainingFees, tester.a3, localFixture.chain, "Redeeming Dispute Bond token didn't increase ETH correctly"): assert scalarMarketDisputeBond.withdraw(False, sender=tester.k3)
def test_token_fee_collection(localFixture, universe, market, categoricalMarket, scalarMarket, cash, reputationToken, reportingWindow): # We'll progress past the designated dispute phase and finalize all the markets localFixture.chain.head_state.timestamp = market.getEndTime( ) + localFixture.contracts[ "Constants"].DESIGNATED_REPORTING_DURATION_SECONDS() + 1 assert market.tryFinalize() assert categoricalMarket.tryFinalize() assert scalarMarket.tryFinalize() # We can't redeem the stake used to do the designated report for fees yet since the window is not yet over marketDesignatedStake = localFixture.getOrCreateStakeToken( market, [0, market.getNumTicks()]) categoricalMarketDesignatedStake = localFixture.getOrCreateStakeToken( categoricalMarket, [0, 0, categoricalMarket.getNumTicks()]) scalarMarketDesignatedStake = localFixture.getOrCreateStakeToken( scalarMarket, [0, scalarMarket.getNumTicks()]) with raises(TransactionFailed): marketDesignatedStake.redeemWinningTokens(False) # If we forgo fees we can redeem however. We'll do this for the scalar market. Note that the market total stake isn't decreased. Market total stake only decreases once it is finalized at which point it can no longer migrate so the value doesn't matter scalarStake = scalarMarketDesignatedStake.balanceOf(tester.a0) with TokenDelta(reputationToken, scalarStake, tester.a0, "Forgoing fees resulting in an incorrect REP refund"): with EtherDelta(0, tester.a0, localFixture.chain, "Forgoing fees gave fees incorrectly"): with StakeDelta( 0, -scalarStake, -scalarStake, scalarMarket, reportingWindow, "Forgoing fees incorrectly updated stake accounting"): assert scalarMarketDesignatedStake.redeemWinningTokens(True) # We cannot purchase participation tokens yet since the window isn't active participationToken = localFixture.applySignature( "ParticipationToken", reportingWindow.getParticipationToken()) with raises(TransactionFailed): participationToken.buy(1) # We'll progress to the start of the window and purchase some participation tokens localFixture.chain.head_state.timestamp = reportingWindow.getStartTime( ) + 1 participationTokenAmount = 100 with TokenDelta(reputationToken, -participationTokenAmount, tester.a0, "Buying participation tokens didn't deduct REP correctly"): with TokenDelta( participationToken, participationTokenAmount, tester.a0, "Buying participation tokens didn't increase participation token balance correctly" ): with StakeDelta( 0, participationTokenAmount, participationTokenAmount, market, reportingWindow, "Buying participation tokens din't adjust stake accounting correctly" ): assert participationToken.buy(participationTokenAmount) # As other testers we'll buy some more with StakeDelta( 0, participationTokenAmount * 3, participationTokenAmount * 3, market, reportingWindow, "Buying participation tokens din't adjust stake accounting correctly" ): with TokenDelta( participationToken, participationTokenAmount, tester.a1, "Buying participation tokens didn't increase participation token balance correctly" ): assert participationToken.buy(participationTokenAmount, sender=tester.k1) with TokenDelta( participationToken, participationTokenAmount, tester.a2, "Buying participation tokens didn't increase participation token balance correctly" ): assert participationToken.buy(participationTokenAmount, sender=tester.k2) with TokenDelta( participationToken, participationTokenAmount, tester.a3, "Buying participation tokens didn't increase participation token balance correctly" ): assert participationToken.buy(participationTokenAmount, sender=tester.k3) # We can't redeem the participation tokens for fees yet since the window isn't over with raises(TransactionFailed): participationToken.redeem(False) # We can redeem them to just get back REP. We'll have tester 3 do this participationValue = participationToken.balanceOf(tester.a3) with TokenDelta(reputationToken, participationValue, tester.a3, "Forgoing fees resulting in an incorrect REP refund"): with TokenDelta( participationToken, -participationTokenAmount, tester.a3, "Redeeming participation tokens didn't decrease participation token balance correctly" ): with EtherDelta(0, tester.a0, localFixture.chain, "Forgoing fees gave fees incorrectly"): with StakeDelta( 0, -participationValue, -participationValue, market, reportingWindow, "Forgoing fees incorrectly updated stake accounting"): assert participationToken.redeem(True, sender=tester.k3) # Fast forward time until the window is over and we can redeem our winning stake and participation tokens and receive fees localFixture.chain.head_state.timestamp = reportingWindow.getEndTime() + 1 reporterFees = 1000 * market.getNumTicks( ) / universe.getOrCacheReportingFeeDivisor() totalWinningStake = reportingWindow.getTotalWinningStake() assert cash.balanceOf(reportingWindow.address) == reporterFees expectedParticipationFees = reporterFees * participationTokenAmount / totalWinningStake # Cashing out Participation tokens or Stake tokens will awards fees proportional to the total winning stake in the window with TokenDelta( participationToken, -participationTokenAmount, tester.a0, "Redeeming participation tokens didn't decrease participation token balance correctly" ): with EtherDelta( expectedParticipationFees, tester.a0, localFixture.chain, "Redeeming participation tokens didn't increase ETH correctly" ): assert participationToken.redeem(False) with TokenDelta( participationToken, -participationTokenAmount, tester.a1, "Redeeming participation tokens didn't decrease participation token balance correctly" ): with EtherDelta( expectedParticipationFees, tester.a1, localFixture.chain, "Redeeming participation tokens didn't increase ETH correctly" ): assert participationToken.redeem(False, sender=tester.k1) with TokenDelta( participationToken, -participationTokenAmount, tester.a2, "Redeeming participation tokens didn't decrease participation token balance correctly" ): with EtherDelta( expectedParticipationFees, tester.a2, localFixture.chain, "Redeeming participation tokens didn't increase ETH correctly" ): assert participationToken.redeem(False, sender=tester.k2) logs = [] captureFilteredLogs(localFixture.chain.head_state, localFixture.contracts['Augur'], logs) marketStake = marketDesignatedStake.balanceOf(tester.a0) expectedFees = reporterFees * marketStake / totalWinningStake + 1 # Rounding error with EtherDelta(expectedFees, tester.a0, localFixture.chain, "Redeeming Stake tokens didn't increase ETH correctly"): with TokenDelta( marketDesignatedStake, -marketStake, tester.a0, "Redeeming Stake tokens didn't decrease Stake token balance correctly" ): assert marketDesignatedStake.redeemWinningTokens(False) # Confirm redeeming stake tokens logs appropriately assert len(logs) == 3 assert logs[2]['_event_type'] == 'WinningTokensRedeemed' assert logs[2]['reporter'] == bytesToHexString(tester.a0) assert logs[2]['reportingFeesReceived'] == expectedFees assert logs[2]['stakeToken'] == marketDesignatedStake.address assert logs[2]['market'] == market.address assert logs[2]['amountRedeemed'] == marketStake assert logs[2]['payoutNumerators'] == [0, market.getNumTicks()] categoricalMarketStake = categoricalMarketDesignatedStake.balanceOf( tester.a0) expectedFees = reporterFees * categoricalMarketStake / totalWinningStake + 1 # Rounding error with EtherDelta(expectedFees, tester.a0, localFixture.chain, "Redeeming Stake tokens didn't increase ETH correctly"): with TokenDelta( categoricalMarketDesignatedStake, -categoricalMarketStake, tester.a0, "Redeeming Stake tokens didn't decrease Stake token balance correctly" ): assert categoricalMarketDesignatedStake.redeemWinningTokens(False)
def test_redeem_shares_in_binary_market(kitchenSinkFixture, universe, cash, market): claimTradingProceeds = kitchenSinkFixture.contracts['ClaimTradingProceeds'] yesShareToken = kitchenSinkFixture.applySignature( 'ShareToken', market.getShareToken(YES)) noShareToken = kitchenSinkFixture.applySignature('ShareToken', market.getShareToken(NO)) expectedValue = 1 * market.getNumTicks() expectedReporterFees = expectedValue / universe.getReportingFeeDivisor() expectedMarketCreatorFees = expectedValue / market.getMarketCreatorSettlementFeeDivisor( ) expectedSettlementFees = expectedReporterFees + expectedMarketCreatorFees expectedPayout = long(expectedValue - expectedSettlementFees) assert universe.getOpenInterestInAttoEth() == 0 # get YES shares with a1 acquireLongShares(kitchenSinkFixture, cash, market, YES, 1, claimTradingProceeds.address, sender=tester.k1) assert universe.getOpenInterestInAttoEth() == 1 * market.getNumTicks() # get NO shares with a2 acquireShortShareSet(kitchenSinkFixture, cash, market, YES, 1, claimTradingProceeds.address, sender=tester.k2) assert universe.getOpenInterestInAttoEth() == 2 * market.getNumTicks() finalizeMarket(kitchenSinkFixture, market, [0, 10**18]) logs = [] captureFilteredLogs(kitchenSinkFixture.chain.head_state, kitchenSinkFixture.contracts['Augur'], logs) with EtherDelta(expectedMarketCreatorFees, tester.a0, kitchenSinkFixture.chain, "Market creator fees not paid"): with TokenDelta(cash, expectedReporterFees, market.getReportingWindow(), "Reporter fees not paid"): # redeem shares with a1 initialLongHolderETH = kitchenSinkFixture.chain.head_state.get_balance( tester.a1) claimTradingProceeds.claimTradingProceeds(market.address, sender=tester.k1) # redeem shares with a2 initialShortHolderETH = kitchenSinkFixture.chain.head_state.get_balance( tester.a2) claimTradingProceeds.claimTradingProceeds(market.address, sender=tester.k2) # Confirm claim proceeds logging works correctly assert len(logs) == 4 assert logs[1]['_event_type'] == 'TradingProceedsClaimed' assert logs[1]['market'] == market.address assert logs[1]['shareToken'] == yesShareToken.address assert logs[1]['numPayoutTokens'] == expectedPayout assert logs[1]['numShares'] == 1 assert logs[1]['sender'] == bytesToHexString(tester.a1) assert logs[1][ 'finalTokenBalance'] == initialLongHolderETH + expectedPayout # assert a1 ends up with cash (minus fees) and a2 does not assert kitchenSinkFixture.chain.head_state.get_balance( tester.a1) == initialLongHolderETH + expectedPayout assert kitchenSinkFixture.chain.head_state.get_balance( tester.a2) == initialShortHolderETH assert yesShareToken.balanceOf(tester.a1) == 0 assert yesShareToken.balanceOf(tester.a2) == 0 assert noShareToken.balanceOf(tester.a1) == 0 assert noShareToken.balanceOf(tester.a2) == 0 assert universe.getOpenInterestInAttoEth() == 1 * market.getNumTicks( ) # The corresponding share for tester2's complete set has not been redeemed