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.getStakeToken(
        market, [0, market.getNumTicks()])
    categoricalMarketDesignatedStake = localFixture.getStakeToken(
        categoricalMarket, [0, 0, categoricalMarket.getNumTicks()])
    scalarMarketDesignatedStake = localFixture.getStakeToken(
        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.getReportingFeeDivisor()
    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_multiple_round_crowdsourcer(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 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, tester.a0,
                    "Redeeming didn't refund REP"):
        assert initialReporter.redeem(tester.a0)

    expectedRep = winningDisputeCrowdsourcer1.getStake(
    ) + winningDisputeCrowdsourcer1.getStake() * 2 / 5
    with TokenDelta(reputationToken, expectedRep, tester.a2,
                    "Redeeming didn't refund REP"):
        assert winningDisputeCrowdsourcer1.redeem(tester.a2)

    expectedRep = winningDisputeCrowdsourcer2.getStake(
    ) + winningDisputeCrowdsourcer2.getStake() * 2 / 5
    with TokenDelta(reputationToken, expectedRep, tester.a3,
                    "Redeeming didn't refund REP"):
        assert winningDisputeCrowdsourcer2.redeem(tester.a3)

    # The losing reports get no REP
    with TokenDelta(reputationToken, 0, tester.a1, "Redeeming refunded REP"):
        assert losingDisputeCrowdsourcer1.redeem(tester.a1)

    with TokenDelta(reputationToken, 0, tester.a1, "Redeeming refunded REP"):
        assert losingDisputeCrowdsourcer2.redeem(tester.a1)
def test_failed_crowdsourcer(finalize, localFixture, universe, market, cash,
                             reputationToken):
    disputeWindow = localFixture.applySignature('DisputeWindow',
                                                market.getDisputeWindow())

    # We'll make the window active
    localFixture.contracts["Time"].setTimestamp(disputeWindow.getStartTime() +
                                                1)

    # We'll have testers contribute to a dispute but not reach the target
    amount = market.getParticipantStake()

    # confirm we can contribute 0
    assert market.contribute([0, 1, market.getNumTicks() - 1],
                             0,
                             "",
                             sender=tester.k1)

    with TokenDelta(reputationToken, -amount + 1, tester.a1,
                    "Disputing did not reduce REP balance correctly"):
        assert market.contribute([0, 1, market.getNumTicks() - 1],
                                 amount - 1,
                                 "",
                                 sender=tester.k1)

    with TokenDelta(reputationToken, -amount + 1, tester.a2,
                    "Disputing did not reduce REP balance correctly"):
        assert market.contribute([0, 1, market.getNumTicks() - 1],
                                 amount - 1,
                                 "",
                                 sender=tester.k2)

    assert market.getDisputeWindow() == disputeWindow.address

    payoutDistributionHash = market.derivePayoutDistributionHash(
        [0, 1, market.getNumTicks() - 1])
    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 dispute window is over and we can redeem to recieve the REP back
        localFixture.contracts["Time"].setTimestamp(
            disputeWindow.getEndTime() + 1)
    else:
        # Continue to the next round which will disavow failed crowdsourcers and let us redeem once the window is over
        market.contribute([0, 0, market.getNumTicks()], amount * 2, "")
        assert market.getDisputeWindow() != disputeWindow.address
        localFixture.contracts["Time"].setTimestamp(
            disputeWindow.getEndTime() + 1)

    with TokenDelta(reputationToken, amount - 1, tester.a1,
                    "Redeeming did not refund REP"):
        assert failedCrowdsourcer.redeem(tester.a1)

    with TokenDelta(reputationToken, amount - 1, tester.a2,
                    "Redeeming did not refund REP"):
        assert failedCrowdsourcer.redeem(tester.a2)
Beispiel #4
0
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 finalizeFork(fixture, market, universe, finalizeByMigration=True):
    reputationToken = fixture.applySignature('ReputationToken',
                                             universe.getReputationToken())

    # The universe forks and there is now a universe where NO and YES are the respective outcomes of each
    noPayoutNumerators = [0] * market.getNumberOfOutcomes()
    noPayoutNumerators[0] = market.getNumTicks()
    yesPayoutNumerators = noPayoutNumerators[::-1]
    noUniverse = fixture.applySignature(
        'Universe', universe.createChildUniverse(noPayoutNumerators, False))
    yesUniverse = fixture.applySignature(
        'Universe', universe.createChildUniverse(yesPayoutNumerators, False))
    noUniverseReputationToken = fixture.applySignature(
        'ReputationToken', noUniverse.getReputationToken())
    yesUniverseReputationToken = fixture.applySignature(
        'ReputationToken', yesUniverse.getReputationToken())
    assert noUniverse.address != universe.address
    assert yesUniverse.address != universe.address
    assert yesUniverse.address != noUniverse.address
    assert noUniverseReputationToken.address != yesUniverseReputationToken.address

    # Attempting to finalize the fork now will not succeed as no REP has been migrated and not enough time has passed
    with raises(TransactionFailed):
        market.finalizeFork()

    # A Tester moves some of their REP to the YES universe
    amount = 10**6 * 10**18
    bonus = amount / fixture.contracts[
        "Constants"].FORK_MIGRATION_PERCENTAGE_BONUS_DIVISOR()
    with TokenDelta(yesUniverseReputationToken, amount + bonus, tester.a0,
                    "Yes REP token balance was no correct"):
        reputationToken.migrateOut(yesUniverseReputationToken.address, amount)

    # Attempting to finalize the fork now will not succeed as a majority or REP has not yet migrated and fork end time has not been reached
    with raises(TransactionFailed):
        market.finalizeFork()

    if (finalizeByMigration):
        # Tester 0 moves more than 50% of REP
        amount = reputationToken.balanceOf(tester.a0) - 20
        bonus = amount / fixture.contracts[
            "Constants"].FORK_MIGRATION_PERCENTAGE_BONUS_DIVISOR()
        with TokenDelta(noUniverseReputationToken, amount + bonus, tester.a0,
                        "No REP token balance was no correct"):
            reputationToken.migrateOut(noUniverseReputationToken.address,
                                       amount)
        assert reputationToken.balanceOf(tester.a0) == 20
        assert market.getWinningPayoutDistributionHash(
        ) == noUniverse.getParentPayoutDistributionHash()
    else:
        # Time marches on past the fork end time
        fixture.contracts["Time"].setTimestamp(universe.getForkEndTime() + 1)
        assert market.finalize()
        assert market.getWinningPayoutDistributionHash(
        ) == yesUniverse.getParentPayoutDistributionHash()

    # if the fork finalized by migration we're still in the 60 day fork window and can still get a bonus for migrating. If the fork is past the fork period we can no longer get the 5% bonus
    amount = 20
    amountAdded = amount
    if finalizeByMigration:
        bonus = amount / fixture.contracts[
            "Constants"].FORK_MIGRATION_PERCENTAGE_BONUS_DIVISOR()
        amountAdded += bonus

    with TokenDelta(yesUniverseReputationToken, amountAdded, tester.a0,
                    "reputation migration bonus did not work correctly"):
        reputationToken.migrateOut(yesUniverseReputationToken.address, amount)

    # Finalize fork cannot be called again
    with raises(TransactionFailed):
        market.finalizeFork()
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_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)

    marketStake = marketInitialReport.getStake()
    expectedFees = reporterFees * marketStake / totalStake
    initialReporterRedeemedLog = {
        "reporter": bytesToHexString(tester.a0),
        "amountRedeemed": marketStake,
        "repReceived": marketStake,
        "reportingFeesReceived": expectedFees,
        "payoutNumerators": [market.getNumTicks(), 0],
        "universe": universe.address,
        "market": market.address
    }
    with AssertLog(localFixture, "InitialReporterRedeemed",
                   initialReporterRedeemedLog):
        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)
Beispiel #8
0
def test_basic_trading(contractsFixture, cash, market, universe):
    zeroXTradeToken = contractsFixture.contracts['ZeroXTradeToken']
    expirationTime = contractsFixture.contracts['Time'].getTimestamp() + 10000
    salt = 5

    # First we'll create a signed order
    rawZeroXOrderData, orderHash = zeroXTradeToken.createZeroXOrder(
        BID, fix(2), 60, market.address, YES, nullAddress, expirationTime,
        salt)
    signature = signOrder(orderHash, contractsFixture.privateKeys[0])
    zeroXExchange = contractsFixture.applySignature("ZeroXExchange",
                                                    zeroXTradeToken.exchange())
    assert zeroXExchange.isValidSignature(orderHash,
                                          contractsFixture.accounts[0],
                                          signature)

    fillAmount = fix(1)
    affiliateAddress = nullAddress
    tradeGroupId = longTo32Bytes(42)
    orders = [rawZeroXOrderData]
    signatures = [signature]

    yesShareToken = contractsFixture.applySignature("ShareToken",
                                                    market.getShareToken(YES))
    noShareToken = contractsFixture.applySignature("ShareToken",
                                                   market.getShareToken(NO))

    # Lets take the order as another user and confirm assets are traded
    assert cash.faucet(fix(1, 60))
    assert cash.faucet(fix(1, 40), sender=contractsFixture.accounts[1])
    with TokenDelta(yesShareToken, fix(1), contractsFixture.accounts[0],
                    "Tester 0 Shares not received"):
        with TokenDelta(noShareToken, fix(1), contractsFixture.accounts[1],
                        "Tester 1 Shares not received"):
            with TokenDelta(cash, -fix(1, 60), contractsFixture.accounts[0],
                            "Tester 0 cash not taken"):
                with TokenDelta(cash, -fix(1, 40),
                                contractsFixture.accounts[1],
                                "Tester 1 cash not taken"):
                    with PrintGasUsed(contractsFixture,
                                      "zeroXTradeToken.trade", 0):
                        amountRemaining = zeroXTradeToken.trade(
                            fillAmount,
                            affiliateAddress,
                            tradeGroupId,
                            orders,
                            signatures,
                            sender=contractsFixture.accounts[1])
                        assert amountRemaining == 0

    # Another user can fill the rest. We'll also ask to fill more than is available and see that we get back the remaining amount desired
    assert cash.faucet(fix(1, 60))
    assert cash.faucet(fix(1, 40), sender=contractsFixture.accounts[2])
    amountRemaining = zeroXTradeToken.trade(
        fillAmount + 1,
        affiliateAddress,
        tradeGroupId,
        orders,
        signatures,
        sender=contractsFixture.accounts[2])
    assert amountRemaining == 1

    # The order is completely filled so further attempts to take it will not actuall result in any trade occuring
    assert cash.faucet(fix(1, 60))
    assert cash.faucet(fix(1, 40), sender=contractsFixture.accounts[1])
    with TokenDelta(yesShareToken, 0, contractsFixture.accounts[0],
                    "Tester 0 Shares not received"):
        with TokenDelta(noShareToken, 0, contractsFixture.accounts[1],
                        "Tester 1 Shares not received"):
            with TokenDelta(cash, 0, contractsFixture.accounts[0],
                            "Tester 0 cash not taken"):
                with TokenDelta(cash, 0, contractsFixture.accounts[1],
                                "Tester 1 cash not taken"):
                    zeroXTradeToken.trade(fillAmount,
                                          affiliateAddress,
                                          tradeGroupId,
                                          orders,
                                          signatures,
                                          sender=contractsFixture.accounts[1])
Beispiel #9
0
def test_one_ask_on_books_buy_partial_order(contractsFixture, cash, market,
                                            universe):
    zeroXTradeToken = contractsFixture.contracts['ZeroXTradeToken']
    expirationTime = contractsFixture.contracts['Time'].getTimestamp() + 10000
    salt = 5
    tradeGroupID = longTo32Bytes(42)

    yesShareToken = contractsFixture.applySignature("ShareToken",
                                                    market.getShareToken(YES))
    noShareToken = contractsFixture.applySignature("ShareToken",
                                                   market.getShareToken(NO))

    # create signed order
    sender = contractsFixture.accounts[1]
    senderPrivateKey = contractsFixture.privateKeys[1]
    cash.faucet(fix('4', '40'), sender=sender)
    rawZeroXOrderData, orderHash = zeroXTradeToken.createZeroXOrder(
        ASK,
        fix(4),
        60,
        market.address,
        YES,
        nullAddress,
        expirationTime,
        salt,
        sender=sender)
    signature = signOrder(orderHash, senderPrivateKey)

    # fill signed order
    orderEventLog = {
        "eventType":
        2,
        "addressData": [
            nullAddress, contractsFixture.accounts[1],
            contractsFixture.accounts[2]
        ],
        "uint256Data": [
            60, 0, YES, 0, 0, 0,
            fix(2), contractsFixture.contracts['Time'].getTimestamp(), 0, 0
        ],
    }
    orders = [rawZeroXOrderData]
    signatures = [signature]
    assert cash.faucet(fix(2, 60), sender=contractsFixture.accounts[2])
    with AssertLog(contractsFixture, "OrderEvent", orderEventLog):
        with TokenDelta(noShareToken, fix(2), sender,
                        "Creator Shares not received"):
            with TokenDelta(yesShareToken, fix(2),
                            contractsFixture.accounts[2],
                            "Taker Shares not received"):
                with TokenDelta(cash, -fix(2, 40), sender,
                                "Creator cash not taken"):
                    with TokenDelta(cash, -fix(2, 60),
                                    contractsFixture.accounts[2],
                                    "Taker cash not taken"):
                        assert zeroXTradeToken.trade(
                            fix(2),
                            nullAddress,
                            tradeGroupID,
                            orders,
                            signatures,
                            sender=contractsFixture.accounts[2]) == 0
def test_uniswap_router(contractsFixture, cash, reputationToken):
    weth = contractsFixture.contracts["WETH9"]
    uniswap = contractsFixture.contracts["UniswapV2Router02"]

    account = contractsFixture.accounts[0]
    deadline = contractsFixture.eth_tester.backend.chain.header.timestamp + 1000000

    # We'll provide some liquidity to the REP/DAI exchange
    cashAmount = 100 * 10**18
    repAmount = 10 * 10**18
    cash.faucet(cashAmount)
    reputationToken.faucet(repAmount)
    cash.approve(uniswap.address, APPROVAL_AMOUNT)
    reputationToken.approve(uniswap.address, APPROVAL_AMOUNT)
    uniswap.addLiquidity(reputationToken.address, cash.address, repAmount,
                         cashAmount, 0, 0, account, deadline)

    # We'll provide liquidity to the ETH/DAI exchange now
    cashAmount = 1000 * 10**18
    ethAmount = 10 * 10**18
    cash.faucet(cashAmount)
    uniswap.addLiquidityETH(cash.address,
                            cashAmount,
                            cashAmount,
                            ethAmount,
                            account,
                            deadline,
                            value=ethAmount)

    # Now lets do some swaps. We'll pay some DAI get an exact amount of REP first
    exactRep = 10**17
    maxDAI = 1.1 * 10**18
    cash.faucet(maxDAI)
    with TokenDelta(reputationToken, exactRep, account,
                    "REP token balance wrong"):
        uniswap.swapTokensForExactTokens(
            exactRep, maxDAI, [cash.address, reputationToken.address], account,
            deadline)

    # Now we'll pay an exact amount of DAI to get some REP
    exactDAI = 10**18
    minRep = .95 * 10**17
    cash.faucet(exactDAI)
    with TokenDelta(cash, -exactDAI, account, "Cash token balance wrong"):
        uniswap.swapExactTokensForTokens(
            exactDAI, minRep, [cash.address, reputationToken.address], account,
            deadline)

    # Now lets pay some DAI to get an exact amount of ETH. We pay gas to execute this so we subtract a dust value to account for that
    exactETH = 10**16
    cash.faucet(maxDAI)
    initialETHBalance = contractsFixture.eth_tester.get_balance(account)
    uniswap.swapTokensForExactETH(exactETH, maxDAI,
                                  [cash.address, weth.address], account,
                                  deadline)
    newETHBalance = contractsFixture.eth_tester.get_balance(account)
    dust = 10**7
    assert newETHBalance - initialETHBalance > exactETH - dust

    # Now we pay an exact amount of DAI to get some ETH
    minETH = .95 * 10**16
    cash.faucet(exactDAI)
    with TokenDelta(cash, -exactDAI, account, "Cash token balance wrong"):
        uniswap.swapExactTokensForETH(exactDAI, minETH,
                                      [cash.address, weth.address], account,
                                      deadline)

    # Now lets pay some ETH to get an exact amount of DAI.
    maxETH = 1.1 * 10**16
    uniswap.swapETHForExactTokens(exactDAI, [weth.address, cash.address],
                                  account,
                                  deadline,
                                  value=maxETH)

    # Finally we pay an exact amount of ETH to get some DAI.
    minDAI = .95 * 10**18
    uniswap.swapExactETHForTokens(minDAI, [weth.address, cash.address],
                                  account,
                                  deadline,
                                  value=exactETH)
Beispiel #11
0
def test_fee_pot_main(contractsFixture, universe, reputationToken, cash):
    if not contractsFixture.paraAugur:
        return

    feePot = contractsFixture.getFeePot(universe)

    bob = contractsFixture.accounts[0]
    alice = contractsFixture.accounts[1]

    reputationToken.faucet(100, sender=bob)
    reputationToken.faucet(100, sender=alice)

    cash.faucet(10000)
    cash.approve(feePot.address, 10000000000000000)

    reputationToken.approve(feePot.address, 10000000000000000, sender=bob)
    reputationToken.approve(feePot.address, 10000000000000000, sender=alice)

    # Put 10 Cash in
    feePot.depositFees(10)

    # Alice puts in 1 REP
    feePot.stake(1, sender=alice)

    # Nothing owed yet
    assert feePot.withdrawableFeesOf(alice) == 0

    # Put 10 Cash in
    feePot.depositFees(10)

    # Alice owed all 20
    assert feePot.withdrawableFeesOf(alice) == 20

    # Put 10 Cash in
    feePot.depositFees(10)

    # Alice owed all 30
    assert feePot.withdrawableFeesOf(alice) == 30

    # Bob puts in 2 REP
    feePot.stake(2, sender=bob)

    # Alice still owed all 30
    assert feePot.withdrawableFeesOf(alice) == 30

    # Bob owed nothing
    assert feePot.withdrawableFeesOf(bob) == 0

    # Put 30 Cash in
    feePot.depositFees(30)

    # Alice owed 40
    assert feePot.withdrawableFeesOf(alice) == 40

    # Bob owed 20
    assert feePot.withdrawableFeesOf(bob) == 20

    # Alice redeems and gets 40 Cash and 0 REP
    with TokenDelta(reputationToken, 0, alice, "Alice got REP back for redeeming incorrectly"):
        with TokenDelta(cash, 40, alice, "Alice didnt get fees"):
            feePot.redeem(sender=alice)

    # Alice owed 0
    assert feePot.withdrawableFeesOf(alice) == 0

    # Bob owed 20
    assert feePot.withdrawableFeesOf(bob) == 20

    # Bob transfers 1 REP to Alice
    feePot.transfer(alice, 1, sender=bob)

    # Alice owed 0
    assert feePot.withdrawableFeesOf(alice) == 0

    # Bob owed 20
    assert feePot.withdrawableFeesOf(bob) == 20

    # Put in 90
    feePot.depositFees(90)

    # Alice owed 60
    assert feePot.withdrawableFeesOf(alice) == 60

    # Bob owed 50
    assert feePot.withdrawableFeesOf(bob) == 50

    # Bob exits and gets 30 Cash and 1 REP
    with TokenDelta(reputationToken, 1, bob, "Bob didn't get back REP"):
        with TokenDelta(cash, 50, bob, "Bob didnt get fees"):
            feePot.exit(1, sender=bob)

    # Alice owed 60
    assert feePot.withdrawableFeesOf(alice) == 60

    # Bob owed 0
    assert feePot.withdrawableFeesOf(bob) == 0
def test_redeem_shares_affiliate(kitchenSinkFixture, universe, cash, market):
    affiliates = kitchenSinkFixture.contracts['Affiliates']
    shareToken = kitchenSinkFixture.contracts['ShareToken']
    expectedValue = 100 * market.getNumTicks()
    expectedReporterFees = expectedValue / universe.getOrCacheReportingFeeDivisor(
    )
    expectedMarketCreatorFees = expectedValue / market.getMarketCreatorSettlementFeeDivisor(
    )
    expectedSettlementFees = expectedReporterFees + expectedMarketCreatorFees
    expectedPayout = expectedValue - expectedSettlementFees
    expectedAffiliateFees = expectedMarketCreatorFees / market.affiliateFeeDivisor(
    )
    expectedMarketCreatorFees = expectedMarketCreatorFees - expectedAffiliateFees
    sourceKickback = expectedAffiliateFees / 5
    expectedAffiliateFees -= sourceKickback
    fingerprint = longTo32Bytes(11)

    assert universe.getOpenInterestInAttoCash() == 0
    affiliateAddress = kitchenSinkFixture.accounts[5]
    affiliates.setReferrer(affiliateAddress,
                           longTo32Bytes(0),
                           sender=kitchenSinkFixture.accounts[1])
    affiliates.setReferrer(affiliateAddress,
                           longTo32Bytes(0),
                           sender=kitchenSinkFixture.accounts[2])

    # get YES shares with a1
    acquireLongShares(kitchenSinkFixture,
                      cash,
                      market,
                      YES,
                      100,
                      shareToken.address,
                      sender=kitchenSinkFixture.accounts[1])
    # get NO shares with a2
    acquireShortShareSet(kitchenSinkFixture,
                         cash,
                         market,
                         YES,
                         100,
                         shareToken.address,
                         sender=kitchenSinkFixture.accounts[2])
    finalizeMarket(kitchenSinkFixture, market, [0, 0, 10**2])

    with TokenDelta(cash, expectedMarketCreatorFees, market.getOwner(),
                    "market creator fees not paid"):
        with TokenDelta(cash, expectedAffiliateFees, affiliateAddress,
                        "affiliate fees not paid"):
            # redeem shares with a1
            shareToken.claimTradingProceeds(market.address,
                                            kitchenSinkFixture.accounts[1],
                                            fingerprint)
            # redeem shares with a2
            shareToken.claimTradingProceeds(market.address,
                                            kitchenSinkFixture.accounts[2],
                                            fingerprint)

    # assert a1 ends up with cash (minus fees) and a2 does not
    assert cash.balanceOf(
        kitchenSinkFixture.accounts[1]) == expectedPayout + sourceKickback
    assert shareToken.balanceOfMarketOutcome(
        market.address, YES, kitchenSinkFixture.accounts[1]) == 0
    assert shareToken.balanceOfMarketOutcome(
        market.address, YES, kitchenSinkFixture.accounts[2]) == 0
    assert shareToken.balanceOfMarketOutcome(
        market.address, NO, kitchenSinkFixture.accounts[1]) == 0
Beispiel #13
0
def test_forking(finalizeByMigration, manuallyDisavow, localFixture, universe,
                 market, cash, categoricalMarket, scalarMarket):
    claimTradingProceeds = localFixture.contracts["ClaimTradingProceeds"]

    # Let's go into the one dispute round for the categorical market
    proceedToNextRound(localFixture, categoricalMarket)
    proceedToNextRound(localFixture, categoricalMarket)

    # proceed to forking
    proceedToFork(localFixture, market, universe)

    with raises(TransactionFailed):
        universe.fork()

    with raises(TransactionFailed):
        categoricalMarket.migrateThroughOneFork(
            [0, 0, 0, categoricalMarket.getNumTicks()], "")

    with raises(TransactionFailed):
        time = localFixture.contracts["Time"].getTimestamp()
        localFixture.createYesNoMarket(universe, time + 1000, 1, 0,
                                       localFixture.accounts[0])

    # confirm that we can manually create a child universe from an outcome no one asserted was true during dispute
    numTicks = market.getNumTicks()
    childUniverse = universe.createChildUniverse(
        [0, numTicks / 4, numTicks * 3 / 4])

    # confirm that before the fork is finalized we can redeem stake in other markets crowdsourcers, which are disavowable
    categoricalDisputeCrowdsourcer = localFixture.applySignature(
        "DisputeCrowdsourcer", categoricalMarket.getReportingParticipant(1))

    # confirm we cannot liquidate it
    with raises(TransactionFailed):
        categoricalDisputeCrowdsourcer.liquidateLosing()

    # confirm we cannot fork it
    with raises(TransactionFailed):
        categoricalDisputeCrowdsourcer.forkAndRedeem()

    if manuallyDisavow:
        marketParticipantsDisavowedLog = {
            "universe": universe.address,
            "market": categoricalMarket.address,
        }
        with AssertLog(localFixture, "MarketParticipantsDisavowed",
                       marketParticipantsDisavowedLog):
            assert categoricalMarket.disavowCrowdsourcers()
        # We can redeem before the fork finalizes since disavowal has occured
        assert categoricalDisputeCrowdsourcer.redeem(localFixture.accounts[0])

    # We cannot contribute to a crowdsourcer during a fork
    with raises(TransactionFailed):
        categoricalMarket.contribute(
            [0, 2, 2, categoricalMarket.getNumTicks() - 4], 1, "")

    # We cannot purchase new Participation Tokens during a fork
    disputeWindowAddress = universe.getOrCreateCurrentDisputeWindow(False)
    disputeWindow = localFixture.applySignature("DisputeWindow",
                                                disputeWindowAddress)

    # finalize the fork
    finalize(localFixture, market, universe, finalizeByMigration)

    # We cannot contribute to a crowdsourcer in a forked universe
    with raises(TransactionFailed):
        categoricalMarket.contribute(
            [0, 2, 2, categoricalMarket.getNumTicks() - 4], 1, "")

    newUniverseAddress = universe.getWinningChildUniverse()
    newUniverse = localFixture.applySignature("Universe", newUniverseAddress)

    # Let's make sure fork payouts work correctly for the forking market
    completeSets = localFixture.contracts['CompleteSets']
    numSets = 10
    cost = market.getNumTicks() * numSets
    with BuyWithCash(cash, cost, localFixture.accounts[0], "buy complete set"):
        assert completeSets.publicBuyCompleteSets(market.address, numSets)

    yesShare = localFixture.applySignature("ShareToken",
                                           market.getShareToken(YES))
    noShare = localFixture.applySignature("ShareToken",
                                          market.getShareToken(NO))

    noShare.transfer(localFixture.accounts[1],
                     noShare.balanceOf(localFixture.accounts[0]))

    expectedYesOutcomePayout = newUniverse.payoutNumerators(YES)
    expectedNoOutcomePayout = newUniverse.payoutNumerators(NO)

    expectedYesPayout = expectedYesOutcomePayout * yesShare.balanceOf(
        localFixture.accounts[0]
    ) * .99  # to account for fees (creator fee goes to the claimer in this case)
    with TokenDelta(cash, expectedYesPayout, localFixture.accounts[0],
                    "Payout for Yes Shares was wrong in forking market"):
        claimTradingProceeds.claimTradingProceeds(market.address,
                                                  localFixture.accounts[0])

    expectedNoPayout = expectedNoOutcomePayout * noShare.balanceOf(
        localFixture.accounts[1]) * .98  # to account for fees
    with TokenDelta(cash, expectedNoPayout, localFixture.accounts[1],
                    "Payout for No Shares was wrong in forking market"):
        claimTradingProceeds.claimTradingProceeds(market.address,
                                                  localFixture.accounts[1])

    # buy some complete sets to change OI of the cat market
    numSets = 10
    cost = categoricalMarket.getNumTicks() * numSets
    with BuyWithCash(cash, cost, localFixture.accounts[0], "buy complete set"):
        assert completeSets.publicBuyCompleteSets(categoricalMarket.address,
                                                  numSets)
    assert universe.getOpenInterestInAttoCash() == cost

    marketMigratedLog = {
        "market": categoricalMarket.address,
        "newUniverse": newUniverseAddress,
        "originalUniverse": universe.address,
    }
    with AssertLog(localFixture, "MarketMigrated", marketMigratedLog):
        assert categoricalMarket.migrateThroughOneFork(
            [0, 0, 0, categoricalMarket.getNumTicks()], "")

    assert universe.getOpenInterestInAttoCash() == 0

    # The dispute crowdsourcer has been disavowed
    newUniverse = localFixture.applySignature("Universe",
                                              categoricalMarket.getUniverse())
    assert newUniverse.address != universe.address
    assert categoricalDisputeCrowdsourcer.isDisavowed()
    assert not universe.isContainerForReportingParticipant(
        categoricalDisputeCrowdsourcer.address)
    assert not newUniverse.isContainerForReportingParticipant(
        categoricalDisputeCrowdsourcer.address)
    assert newUniverse.getOpenInterestInAttoCash() == cost

    # The initial report is still present however
    categoricalInitialReport = localFixture.applySignature(
        "InitialReporter", categoricalMarket.getReportingParticipant(0))
    assert categoricalMarket.getReportingParticipant(
        0) == categoricalInitialReport.address
    assert not categoricalInitialReport.isDisavowed()
    assert not universe.isContainerForReportingParticipant(
        categoricalInitialReport.address)
    assert newUniverse.isContainerForReportingParticipant(
        categoricalInitialReport.address)

    # The categorical market has a new dispute window since it was initially reported on and may be disputed now
    categoricalMarketDisputeWindowAddress = categoricalMarket.getDisputeWindow(
    )
    categoricalMarketDisputeWindow = localFixture.applySignature(
        "DisputeWindow", categoricalMarketDisputeWindowAddress)

    proceedToNextRound(localFixture, categoricalMarket)

    # We will finalize the categorical market in the new universe
    disputeWindow = localFixture.applySignature(
        'DisputeWindow', categoricalMarket.getDisputeWindow())
    localFixture.contracts["Time"].setTimestamp(disputeWindow.getEndTime() + 1)

    assert categoricalMarket.finalize()

    # We can migrate a market that has not had its initial reporting completed as well, and confirm that the report is now made in the new universe
    reputationToken = localFixture.applySignature(
        "ReputationToken", universe.getReputationToken())
    previousREPBalance = reputationToken.balanceOf(scalarMarket.address)
    assert previousREPBalance > 0
    newReputationToken = localFixture.applySignature(
        "ReputationToken", newUniverse.getReputationToken())
    with TokenDelta(reputationToken, previousREPBalance,
                    scalarMarket.repBondOwner(),
                    "Market did not transfer rep balance to rep bond owner"):
        with TokenDelta(newReputationToken,
                        -newUniverse.getOrCacheMarketRepBond(),
                        localFixture.accounts[0],
                        "Migrator did not pay new REP bond"):
            assert scalarMarket.migrateThroughOneFork(
                [0, 0, scalarMarket.getNumTicks()], "")
    newUniverseREP = localFixture.applySignature(
        "ReputationToken", newUniverse.getReputationToken())
    initialReporter = localFixture.applySignature(
        'InitialReporter', scalarMarket.getInitialReporter())
    assert newUniverseREP.balanceOf(
        initialReporter.address
    ) == newUniverse.getOrCacheDesignatedReportNoShowBond()

    # We cannot migrate legacy REP to the new Universe REP
    legacyRepToken = localFixture.applySignature(
        'LegacyReputationToken', newUniverseREP.getLegacyRepToken())
    assert legacyRepToken.faucet(500)
    totalSupply = legacyRepToken.balanceOf(localFixture.accounts[0])
    legacyRepToken.approve(newUniverseREP.address, totalSupply)
    with raises(TransactionFailed):
        newUniverseREP.migrateFromLegacyReputationToken()

    # We can finalize this market as well
    proceedToNextRound(localFixture, scalarMarket)
    disputeWindow = localFixture.applySignature(
        'DisputeWindow', scalarMarket.getDisputeWindow())
    localFixture.contracts["Time"].setTimestamp(disputeWindow.getEndTime() + 1)

    assert scalarMarket.finalize()
Beispiel #14
0
def test_initialReport_methods(localFixture, universe, market, 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, 0, market.getNumTicks()],
                                  "",
                                  0,
                                  sender=localFixture.accounts[1])

    # the market is now assigned a dispute window
    newDisputeWindowAddress = market.getDisputeWindow()
    assert newDisputeWindowAddress
    disputeWindow = localFixture.applySignature('DisputeWindow',
                                                newDisputeWindowAddress)

    # time marches on and the market can be finalized
    localFixture.contracts["Time"].setTimestamp(disputeWindow.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": localFixture.accounts[1],
        "to": initialReporter.getDesignatedReporter(),
    }
    with AssertLog(localFixture, "InitialReporterTransferred", transferLog):
        assert initialReporter.transferOwnership(
            initialReporter.getDesignatedReporter(),
            sender=localFixture.accounts[1])

    # Transfering to the owner is a noop
    assert initialReporter.transferOwnership(
        initialReporter.getDesignatedReporter())

    # The market still correctly indicates the designated reporter did not show up
    assert not market.designatedReporterShowed()

    # confirm we cannot call protected methods on the initial reporter which only the market may use
    with raises(TransactionFailed):
        initialReporter.report(localFixture.accounts[0], "", [], 1)

    with raises(TransactionFailed):
        initialReporter.returnRepFromDisavow()

    with raises(TransactionFailed):
        initialReporter.migrateToNewUniverse(localFixture.accounts[0])

    # When we redeem the initialReporter it goes to the correct party as well
    expectedRep = initialReporter.getStake()
    owner = initialReporter.getOwner()

    with TokenDelta(reputationToken, expectedRep, owner,
                    "Redeeming didn't refund REP"):
        assert initialReporter.redeem(owner)
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)
Beispiel #16
0
def test_two_asks_on_books_buy_full_and_partial(contractsFixture, cash,
                                                market):
    zeroXTradeToken = contractsFixture.contracts['ZeroXTradeToken']
    expirationTime = contractsFixture.contracts['Time'].getTimestamp() + 10000
    salt = 5
    tradeGroupID = longTo32Bytes(42)

    yesShareToken = contractsFixture.applySignature("ShareToken",
                                                    market.getShareToken(YES))
    noShareToken = contractsFixture.applySignature("ShareToken",
                                                   market.getShareToken(NO))

    # create signed order 1
    cash.faucet(fix('1', '40'), sender=contractsFixture.accounts[1])
    rawZeroXOrderData1, orderHash1 = zeroXTradeToken.createZeroXOrder(
        ASK,
        fix(1),
        60,
        market.address,
        YES,
        nullAddress,
        expirationTime,
        salt,
        sender=contractsFixture.accounts[1])
    signature1 = signOrder(orderHash1, contractsFixture.privateKeys[1])

    # create signed order 2
    cash.faucet(fix('4', '40'), sender=contractsFixture.accounts[3])
    rawZeroXOrderData2, orderHash2 = zeroXTradeToken.createZeroXOrder(
        ASK,
        fix(4),
        60,
        market.address,
        YES,
        nullAddress,
        expirationTime,
        salt,
        sender=contractsFixture.accounts[3])
    signature2 = signOrder(orderHash2, contractsFixture.privateKeys[3])

    orders = [rawZeroXOrderData1, rawZeroXOrderData2]
    signatures = [signature1, signature2]

    # fill signed orders
    cash.faucet(fix('3', '60'), sender=contractsFixture.accounts[2])
    with TokenDelta(noShareToken, fix(1), contractsFixture.accounts[1],
                    "Creator Shares not received"):
        with TokenDelta(noShareToken, fix(2), contractsFixture.accounts[3],
                        "Creator Shares not received"):
            with TokenDelta(yesShareToken, fix(3),
                            contractsFixture.accounts[2],
                            "Taker Shares not received"):
                with TokenDelta(cash, -fix(1, 40),
                                contractsFixture.accounts[1],
                                "Creator cash not taken"):
                    with TokenDelta(cash, -fix(2, 40),
                                    contractsFixture.accounts[3],
                                    "Creator cash not taken"):
                        with TokenDelta(cash, -fix(3, 60),
                                        contractsFixture.accounts[2],
                                        "Taker cash not taken"):
                            assert zeroXTradeToken.trade(
                                fix(3),
                                nullAddress,
                                tradeGroupID,
                                orders,
                                signatures,
                                sender=contractsFixture.accounts[2]) == 0
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)
Beispiel #18
0
def test_take_best_order_with_shares_escrowed_buy_with_shares_categorical(
        contractsFixture, cash, categoricalMarket, universe):
    market = categoricalMarket
    zeroXTradeToken = contractsFixture.contracts['ZeroXTradeToken']
    completeSets = contractsFixture.contracts['CompleteSets']
    expirationTime = contractsFixture.contracts['Time'].getTimestamp() + 10000
    salt = 5
    tradeGroupID = longTo32Bytes(42)

    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()
    with BuyWithCash(cash, fix('1', numTicks), contractsFixture.accounts[1],
                     "buy complete set"):
        assert completeSets.publicBuyCompleteSets(
            market.address, fix(1), sender=contractsFixture.accounts[1])
    with BuyWithCash(cash, fix('1', numTicks), contractsFixture.accounts[2],
                     "buy complete set"):
        assert completeSets.publicBuyCompleteSets(
            market.address, fix(1), sender=contractsFixture.accounts[2])
    assert firstShareToken.balanceOf(
        contractsFixture.accounts[1]) == firstShareToken.balanceOf(
            contractsFixture.accounts[2]) == fix(1)
    assert secondShareToken.balanceOf(
        contractsFixture.accounts[1]) == secondShareToken.balanceOf(
            contractsFixture.accounts[2]) == fix(1)
    assert thirdShareToken.balanceOf(
        contractsFixture.accounts[1]) == thirdShareToken.balanceOf(
            contractsFixture.accounts[2]) == fix(1)

    # create signed order
    rawZeroXOrderData, orderHash = zeroXTradeToken.createZeroXOrder(
        ASK,
        fix(1),
        60,
        market.address,
        0,
        nullAddress,
        expirationTime,
        salt,
        sender=contractsFixture.accounts[1])
    signature = signOrder(orderHash, contractsFixture.privateKeys[1])

    # fill order with shares and see payouts occur
    orders = [rawZeroXOrderData]
    signatures = [signature]
    totalProceeds = fix(1, numTicks)
    totalProceeds -= fix(
        1, numTicks) / market.getMarketCreatorSettlementFeeDivisor()
    totalProceeds -= fix(1,
                         numTicks) / universe.getOrCacheReportingFeeDivisor()
    expectedTester1Payout = totalProceeds * 60 / numTicks
    expectedTester2Payout = totalProceeds * (numTicks - 60) / numTicks
    with TokenDelta(cash, expectedTester1Payout, contractsFixture.accounts[1],
                    "Tester 1 Cash delta wrong"):
        with TokenDelta(cash, expectedTester2Payout,
                        contractsFixture.accounts[2],
                        "Tester 2 Cash delta wrong"):
            assert zeroXTradeToken.trade(
                fix(1),
                nullAddress,
                tradeGroupID,
                orders,
                signatures,
                sender=contractsFixture.accounts[2]) == 0

    assert firstShareToken.balanceOf(contractsFixture.accounts[1]) == 0
    assert secondShareToken.balanceOf(contractsFixture.accounts[1]) == fix(1)
    assert thirdShareToken.balanceOf(contractsFixture.accounts[1]) == fix(1)

    assert firstShareToken.balanceOf(contractsFixture.accounts[2]) == fix(1)
    assert secondShareToken.balanceOf(contractsFixture.accounts[2]) == 0
    assert thirdShareToken.balanceOf(contractsFixture.accounts[2]) == 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)
Beispiel #20
0
def test_fees_from_trades(finalized, invalid, contractsFixture, cash, market,
                          universe):
    zeroXTradeToken = contractsFixture.contracts['ZeroXTradeToken']
    completeSets = contractsFixture.contracts['CompleteSets']
    expirationTime = contractsFixture.contracts['Time'].getTimestamp() + 10000
    salt = 5
    tradeGroupID = longTo32Bytes(42)
    completeSets = contractsFixture.contracts['CompleteSets']
    firstShareToken = contractsFixture.applySignature('ShareToken',
                                                      market.getShareToken(0))
    secondShareToken = contractsFixture.applySignature('ShareToken',
                                                       market.getShareToken(1))

    if finalized:
        if invalid:
            contractsFixture.contracts["Time"].setTimestamp(
                market.getDesignatedReportingEndTime() + 1)
            market.doInitialReport([market.getNumTicks(), 0, 0], "", 0)
        else:
            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), contractsFixture.accounts[1],
                     "buy complete set"):
        assert completeSets.publicBuyCompleteSets(
            market.address, fix(1), sender=contractsFixture.accounts[1])
    with BuyWithCash(cash, fix('1', numTicks), contractsFixture.accounts[2],
                     "buy complete set"):
        assert completeSets.publicBuyCompleteSets(
            market.address, fix(1), sender=contractsFixture.accounts[2])
    assert firstShareToken.balanceOf(
        contractsFixture.accounts[1]) == firstShareToken.balanceOf(
            contractsFixture.accounts[2]) == fix(1)
    assert secondShareToken.balanceOf(
        contractsFixture.accounts[1]) == secondShareToken.balanceOf(
            contractsFixture.accounts[2]) == fix(1)

    # create order with shares
    rawZeroXOrderData, orderHash = zeroXTradeToken.createZeroXOrder(
        ASK,
        fix(1),
        60,
        market.address,
        0,
        nullAddress,
        expirationTime,
        salt,
        sender=contractsFixture.accounts[1])
    signature = signOrder(orderHash, contractsFixture.privateKeys[1])
    orders = [rawZeroXOrderData]
    signatures = [signature]

    expectedAffiliateFees = fix(100) / 400
    cash.faucet(fix(60), sender=contractsFixture.accounts[2])
    # Trade and specify an affiliate address.
    if finalized:
        if invalid:
            nextDisputeWindowAddress = universe.getOrCreateNextDisputeWindow(
                False)
            totalFees = fix(100) / 50  # Market fees + reporting fees
            with TokenDelta(cash, totalFees, nextDisputeWindowAddress,
                            "Dispute Window did not recieve the correct fees"):
                assert zeroXTradeToken.trade(
                    fix(1),
                    contractsFixture.accounts[3],
                    tradeGroupID,
                    orders,
                    signatures,
                    sender=contractsFixture.accounts[2]) == 0
        else:
            with TokenDelta(cash, expectedAffiliateFees,
                            contractsFixture.accounts[3],
                            "Affiliate did not recieve the correct fees"):
                assert zeroXTradeToken.trade(
                    fix(1),
                    contractsFixture.accounts[3],
                    tradeGroupID,
                    orders,
                    signatures,
                    sender=contractsFixture.accounts[2]) == 0
    else:
        assert zeroXTradeToken.trade(fix(1),
                                     contractsFixture.accounts[3],
                                     tradeGroupID,
                                     orders,
                                     signatures,
                                     sender=contractsFixture.accounts[2]) == 0

    assert firstShareToken.balanceOf(contractsFixture.accounts[1]) == 0
    assert secondShareToken.balanceOf(contractsFixture.accounts[1]) == fix(1)

    # The second user sold the complete set they ended up holding from this transaction, which extracts fees
    assert firstShareToken.balanceOf(contractsFixture.accounts[2]) == fix(1)
    assert secondShareToken.balanceOf(contractsFixture.accounts[2]) == 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(
            contractsFixture.accounts[3]) == expectedAffiliateFees

        # The affiliate can withdraw their fees only after the market is finalized as valid
        with raises(TransactionFailed):
            market.withdrawAffiliateFees(contractsFixture.accounts[3])

        if invalid:
            contractsFixture.contracts["Time"].setTimestamp(
                market.getDesignatedReportingEndTime() + 1)
            market.doInitialReport([market.getNumTicks(), 0, 0], "", 0)
        else:
            proceedToNextRound(contractsFixture, market)

        disputeWindow = contractsFixture.applySignature(
            'DisputeWindow', market.getDisputeWindow())
        contractsFixture.contracts["Time"].setTimestamp(
            disputeWindow.getEndTime() + 1)
        totalCollectedFees = market.marketCreatorFeesAttoCash(
        ) + market.totalAffiliateFeesAttoCash() + market.validityBondAttoCash(
        )
        nextDisputeWindowAddress = universe.getOrCreateNextDisputeWindow(False)
        nextDisputeWindowBalanceBeforeFinalization = cash.balanceOf(
            universe.getOrCreateNextDisputeWindow(False))
        assert market.finalize()

        if invalid:
            with raises(TransactionFailed):
                market.withdrawAffiliateFees(contractsFixture.accounts[3])
            assert cash.balanceOf(
                universe.getOrCreateNextDisputeWindow(False)
            ) == nextDisputeWindowBalanceBeforeFinalization + totalCollectedFees
        else:
            with TokenDelta(cash, expectedAffiliateFees,
                            contractsFixture.accounts[3],
                            "Affiliate did not recieve the correct fees"):
                market.withdrawAffiliateFees(contractsFixture.accounts[3])

    # No more fees can be withdrawn
    if not invalid:
        with TokenDelta(cash, 0, contractsFixture.accounts[3],
                        "Affiliate double received fees"):
            market.withdrawAffiliateFees(contractsFixture.accounts[3])
Beispiel #21
0
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.getOrCacheReportingFeeDivisor(
    )
    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**4])

    initialLongHolderETH = kitchenSinkFixture.chain.head_state.get_balance(
        tester.a1)
    initialShortHolderETH = kitchenSinkFixture.chain.head_state.get_balance(
        tester.a2)

    tradingProceedsClaimedLog = {
        'market': market.address,
        'shareToken': yesShareToken.address,
        'numPayoutTokens': expectedPayout,
        'numShares': 1,
        'sender': bytesToHexString(tester.a1),
        'finalTokenBalance': initialLongHolderETH + expectedPayout,
    }

    with TokenDelta(cash, expectedMarketCreatorFees,
                    market.getMarketCreatorMailbox(),
                    "Market creator fees not paid"):
        with TokenDelta(cash, expectedReporterFees,
                        universe.getOrCreateNextFeeWindow(),
                        "Reporter fees not paid"):
            # redeem shares with a1
            with AssertLog(kitchenSinkFixture, "TradingProceedsClaimed",
                           tradingProceedsClaimedLog):
                claimTradingProceeds.claimTradingProceeds(
                    market.address, tester.a1)
            # redeem shares with a2
            claimTradingProceeds.claimTradingProceeds(market.address,
                                                      tester.a2)

    # 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
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.getOrCacheReportingFeeDivisor(
    )
    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**4])

    logs = []
    captureFilteredLogs(kitchenSinkFixture.chain.head_state,
                        kitchenSinkFixture.contracts['Augur'], logs)

    with TokenDelta(cash, expectedMarketCreatorFees,
                    market.getMarketCreatorMailbox(),
                    "Market creator fees not paid"):
        with TokenDelta(cash, expectedReporterFees,
                        universe.getOrCreateNextFeeWindow(),
                        "Reporter fees not paid"):
            # redeem shares with a1
            initialLongHolderETH = kitchenSinkFixture.chain.head_state.get_balance(
                tester.a1)
            claimTradingProceeds.claimTradingProceeds(market.address,
                                                      tester.a1)
            # redeem shares with a2
            initialShortHolderETH = kitchenSinkFixture.chain.head_state.get_balance(
                tester.a2)
            claimTradingProceeds.claimTradingProceeds(market.address,
                                                      tester.a2)

    # Confirm claim proceeds logging works correctly
    assert len(logs) == 6
    assert logs[3]['_event_type'] == 'TradingProceedsClaimed'
    assert logs[3]['market'] == market.address
    assert logs[3]['shareToken'] == yesShareToken.address
    assert logs[3]['numPayoutTokens'] == expectedPayout
    assert logs[3]['numShares'] == 1
    assert logs[3]['sender'] == bytesToHexString(tester.a1)
    assert logs[3][
        '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
Beispiel #23
0
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()
Beispiel #24
0
def test_warp_sync(contractsFixture, augur, universe, reputationToken,
                   warpSync, cash):
    account = contractsFixture.accounts[0]
    time = contractsFixture.contracts["Time"]

    # See that warp sync market does not exist initially
    assert warpSync.markets(universe.address) == nullAddress

    # We can initialize the warp sync market for a universe and be rewarded with REP based on how long since the universe was created
    expectedCreationReward = warpSync.getCreationReward(universe.address)
    with PrintGasUsed(contractsFixture, "WS Market Finalization Cost", 0):
        with TokenDelta(reputationToken, expectedCreationReward, account,
                        "REP reward not minted for initializing universe"):
            warpSync.initializeUniverse(universe.address)

    # The market now exists
    market = contractsFixture.applySignature(
        "Market", warpSync.markets(universe.address))

    # Initially there is no warp sync data for this universe
    assert warpSync.data(universe.address) == [0, 0]

    # Finalize the warp sync market with some value
    proceedToDesignatedReporting(contractsFixture, market)
    numTicks = market.getNumTicks()
    assert warpSync.doInitialReport(universe.address, [0, 0, numTicks], "")
    disputeWindow = contractsFixture.applySignature("DisputeWindow",
                                                    market.getDisputeWindow())

    time.setTimestamp(disputeWindow.getEndTime())

    # Finalizing the warp sync market will award the finalizer REP based on time since it became finalizable
    # This will also trigger a sweep of accumulated interest
    expectedFinalizationReward = warpSync.getFinalizationReward(market.address)
    WarpSyncDataUpdatedLog = {
        "universe": universe.address,
        "warpSyncHash": numTicks,
        "marketEndTime": market.getEndTime()
    }
    nextDisputeWindow = universe.getOrCreateNextDisputeWindow(False)
    initialFeesBalance = cash.balanceOf(nextDisputeWindow)
    with AssertLog(contractsFixture, "WarpSyncDataUpdated",
                   WarpSyncDataUpdatedLog):
        with PrintGasUsed(contractsFixture, "WS Market Finalization Cost", 0):
            with TokenDelta(reputationToken, expectedFinalizationReward,
                            account, "REP reward not minted for finalizer"):
                assert market.finalize()

    assert cash.balanceOf(nextDisputeWindow) > initialFeesBalance

    # Check Warp Sync contract for universe and see existing value
    assert warpSync.data(universe.address) == [numTicks, market.getEndTime()]

    # See new warp sync market
    newWarpSyncMarket = contractsFixture.applySignature(
        "Market", warpSync.markets(universe.address))
    assert newWarpSyncMarket.address != market.address

    # Finalize it
    proceedToInitialReporting(contractsFixture, newWarpSyncMarket)
    numTicks = newWarpSyncMarket.getNumTicks()
    assert newWarpSyncMarket.doInitialReport([0, 1, numTicks - 1], "", 0)
    disputeWindow = contractsFixture.applySignature(
        "DisputeWindow", newWarpSyncMarket.getDisputeWindow())

    time.setTimestamp(disputeWindow.getEndTime())
    assert newWarpSyncMarket.finalize()

    # See new warp sync value
    assert warpSync.data(
        universe.address) == [numTicks - 1,
                              newWarpSyncMarket.getEndTime()]

    # See another new market
    assert newWarpSyncMarket.address != warpSync.markets(universe.address)
Beispiel #25
0
def finalize(fixture, market, universe, finalizeByMigration = True):
    account0 = fixture.accounts[0]
    reputationToken = fixture.applySignature('ReputationToken', universe.getReputationToken())

    # The universe forks and there is now a universe where NO and YES are the respective outcomes of each
    noPayoutNumerators = [0] * market.getNumberOfOutcomes()
    noPayoutNumerators[1] = market.getNumTicks()
    yesPayoutNumerators = [0] * market.getNumberOfOutcomes()
    yesPayoutNumerators[2] = market.getNumTicks()
    noUniverse =  fixture.applySignature('Universe', universe.createChildUniverse(noPayoutNumerators))
    yesUniverse =  fixture.applySignature('Universe', universe.createChildUniverse(yesPayoutNumerators))
    noUniverseReputationToken = fixture.applySignature('ReputationToken', noUniverse.getReputationToken())
    yesUniverseReputationToken = fixture.applySignature('ReputationToken', yesUniverse.getReputationToken())
    assert noUniverse.address != universe.address
    assert yesUniverse.address != universe.address
    assert yesUniverse.address != noUniverse.address
    assert noUniverseReputationToken.address != yesUniverseReputationToken.address

    # Attempting to finalize the fork now will not succeed as no REP has been migrated and not enough time has passed
    with raises(TransactionFailed):
        market.finalize()

    # A Tester moves some of their REP to the YES universe
    amount = 10 ** 6 * 10 ** 18

    with raises(TransactionFailed):
        reputationToken.migrateOutByPayout(yesPayoutNumerators, 0)

    with TokenDelta(yesUniverseReputationToken, amount, account0, "Yes REP token balance was no correct"):
        reputationToken.migrateOutByPayout(yesPayoutNumerators, amount)

    # Attempting to finalize the fork now will not succeed as a majority or REP has not yet migrated and fork end time has not been reached
    with raises(TransactionFailed):
        market.finalize()

    if (finalizeByMigration):
        # Tester 0 moves more than 50% of REP
        amount = reputationToken.balanceOf(account0) - 20
        marketFinalizedLog = {
            "universe": universe.address,
            "market": market.address,
        }
        with AssertLog(fixture, "MarketFinalized", marketFinalizedLog):
            with TokenDelta(noUniverseReputationToken, amount, account0, "No REP token balance was no correct"):
                reputationToken.migrateOutByPayout(noPayoutNumerators, amount)
        assert reputationToken.balanceOf(account0) == 20
        assert market.getWinningPayoutDistributionHash() == noUniverse.getParentPayoutDistributionHash()
    else:
        # Time marches on past the fork end time
        fixture.contracts["Time"].setTimestamp(universe.getForkEndTime() + 1)
        marketFinalizedLog = {
            "universe": universe.address,
            "market": market.address,
        }
        with AssertLog(fixture, "MarketFinalized", marketFinalizedLog):
            assert market.finalize()
        assert market.getWinningPayoutDistributionHash() == yesUniverse.getParentPayoutDistributionHash()
        # If the fork is past the fork period we can not migrate
        with raises(TransactionFailed):
            reputationToken.migrateOutByPayout(noPayoutNumerators, 1)

    # Finalize fork cannot be called again
    with raises(TransactionFailed):
        market.finalize()
Beispiel #26
0
def test_affiliate_validator(kitchenSinkFixture, universe, cash):
    affiliates = kitchenSinkFixture.contracts['Affiliates']
    affiliateValidator = kitchenSinkFixture.applySignature(
        "AffiliateValidator", affiliates.createAffiliateValidator())
    shareToken = kitchenSinkFixture.getShareToken()

    market = kitchenSinkFixture.createReasonableYesNoMarket(
        universe, affiliateValidator=affiliateValidator.address)

    accountFingerprint = longTo32Bytes(11)
    affiliateFingerprint = longTo32Bytes(12)

    account = kitchenSinkFixture.accounts[0]
    affiliate = kitchenSinkFixture.accounts[1]
    affiliateValidatorOperator = kitchenSinkFixture.accounts[5]
    affiliateValidatorOperatorPrivKey = kitchenSinkFixture.privateKeys[5]

    affiliates.setFingerprint(accountFingerprint, sender=account)
    affiliates.setFingerprint(affiliateFingerprint, sender=affiliate)
    affiliates.setReferrer(affiliate)

    accountKey = longTo32Bytes(21)
    salt = 0
    accountHash = affiliateValidator.getKeyHash(accountKey, account, salt)

    # A bad signature will be rejected
    with raises(TransactionFailed):
        affiliateValidator.addKey(accountKey,
                                  salt,
                                  longTo32Bytes(0),
                                  longTo32Bytes(0),
                                  8,
                                  sender=account)

    # This includes being signed by a non operator. So the same sig will fail initially but work once the signer is approved as an operator
    r, s, v = signHash(accountHash, affiliateValidatorOperatorPrivKey)
    with raises(TransactionFailed):
        affiliateValidator.addKey(accountKey, salt, r, s, v, sender=account)

    # Succesfully add the key for the trader account
    affiliateValidator.addOperator(affiliateValidatorOperator)
    affiliateValidator.addKey(accountKey, salt, r, s, v, sender=account)

    # Re-using a salt will not work
    with raises(TransactionFailed):
        affiliateValidator.addKey(accountKey, salt, r, s, v, sender=account)

    affiliateKey = longTo32Bytes(22)
    salt += 1
    affiliateHash = affiliateValidator.getKeyHash(affiliateKey, affiliate,
                                                  salt)
    r, s, v = signHash(affiliateHash, affiliateValidatorOperatorPrivKey)
    affiliateValidator.addKey(affiliateKey, salt, r, s, v, sender=affiliate)

    numSets = 10
    cost = numSets * market.getNumTicks()
    expectedAffiliateFees = cost * .0025
    expectedAffiliateFees *= .8
    cash.faucet(cost)
    shareToken.buyCompleteSets(market.address, account, numSets)
    with TokenDelta(cash, expectedAffiliateFees, affiliate):
        shareToken.sellCompleteSets(market.address, account, account, numSets,
                                    accountFingerprint)

    # If we try to use an account that has registered an affiliate key which is the same as the referrer the affiliate fees do not apply and will remain what they were before complete set sale
    dupeAccount = kitchenSinkFixture.accounts[2]
    affiliates.setReferrer(affiliate, sender=dupeAccount)
    salt += 1
    affiliateHash = affiliateValidator.getKeyHash(affiliateKey, dupeAccount,
                                                  salt)
    r, s, v = signHash(affiliateHash, affiliateValidatorOperatorPrivKey)
    affiliateValidator.addKey(affiliateKey, salt, r, s, v, sender=dupeAccount)

    cash.faucet(cost, sender=dupeAccount)
    shareToken.buyCompleteSets(market.address,
                               dupeAccount,
                               numSets,
                               sender=dupeAccount)
    expectedAffiliateAmount = 20 if kitchenSinkFixture.paraAugur else 0
    with TokenDelta(cash, expectedAffiliateAmount, affiliate):
        shareToken.sellCompleteSets(market.address,
                                    dupeAccount,
                                    dupeAccount,
                                    numSets,
                                    accountFingerprint,
                                    sender=dupeAccount)

    # It will also not work if the account or the referrer does not have a key registered with the validator
    noKeyAccount = kitchenSinkFixture.accounts[3]
    affiliates.setReferrer(affiliate, sender=noKeyAccount)

    cash.faucet(cost, sender=noKeyAccount)
    shareToken.buyCompleteSets(market.address,
                               noKeyAccount,
                               numSets,
                               sender=noKeyAccount)
    with TokenDelta(cash, expectedAffiliateAmount, affiliate):
        shareToken.sellCompleteSets(market.address,
                                    noKeyAccount,
                                    noKeyAccount,
                                    numSets,
                                    accountFingerprint,
                                    sender=noKeyAccount)
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
    assert categoricalMarket.migrateThroughOneFork(
        [0, 0, 0, categoricalMarket.getNumTicks()], "")

    expectedRep = categoricalDisputeCrowdsourcer.getStake()
    with TokenDelta(reputationToken, expectedRep, tester.a1,
                    "Redeeming didn't increase REP correctly"):
        categoricalDisputeCrowdsourcer.redeem(tester.a1)

    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.testerAddress[i % 4]
        key = localFixture.testerKey[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=key)
Beispiel #28
0
def test_initialReport_methods(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, "InitialReporterTransferred", transferLog):
        assert initialReporter.transferOwnership(
            initialReporter.getDesignatedReporter(), sender=tester.k1)

    # Transfering to the owner is a noop
    assert initialReporter.transferOwnership(
        initialReporter.getDesignatedReporter())

    # The market still correctly indicates the designated reporter did not show up
    assert not market.designatedReporterShowed()

    # confirm we cannot call protected methods on the initial reporter which only the market may use
    with raises(TransactionFailed):
        initialReporter.report(tester.a0, "", [], False)

    with raises(TransactionFailed):
        initialReporter.resetReportTimestamp()

    with raises(TransactionFailed):
        initialReporter.migrateREP()

    # 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)
Beispiel #29
0
def test_reporting_fee_from_auction(localFixture, universe, auction,
                                    reputationToken, time, cash):
    # We'll quickly do the bootstrap auction and seed it with some CASH
    startTime = auction.getAuctionStartTime()
    assert time.setTimestamp(startTime)

    # Buy 1000 REP
    repSalePrice = auction.getRepSalePriceInAttoCash()
    repAuctionToken = localFixture.applySignature("AuctionToken",
                                                  auction.repAuctionToken())
    repAmount = 1000 * 10**18
    cost = repAmount * repSalePrice / 10**18
    with BuyWithCash(cash, cost, localFixture.accounts[0],
                     "trade cash for rep"):
        with TokenDelta(cash, cost, auction.address,
                        "CASH was not transferred to auction correctly"):
            with TokenDelta(repAuctionToken, cost, localFixture.accounts[0],
                            "REP was not transferred to the user correctly"):
                assert auction.tradeCashForRep(repAmount)

    # Now we'll go to the first real auction, which will be a reported auction, meaning the result affects the reported REP price
    endTime = auction.getAuctionEndTime()
    assert time.setTimestamp(endTime + 1)

    # Now we can redeem the tokens we received for the amount of REP we purchased
    expectedREP = reputationToken.balanceOf(repAuctionToken.address)
    with TokenDelta(
            reputationToken, expectedREP, localFixture.accounts[0],
            "REP was not distributed correctly from auction token redemption"):
        repAuctionToken.redeem()

    startTime = auction.getAuctionStartTime()
    assert time.setTimestamp(startTime)

    # Initially the REP price of the auction will simply be what was provided as the constant initialized value
    assert auction.getRepPriceInAttoCash(
    ) == auction.initialRepPriceInAttoCash()
    repSalePrice = auction.getRepSalePriceInAttoCash()
    repAuctionToken = localFixture.applySignature("AuctionToken",
                                                  auction.repAuctionToken())
    cashAuctionToken = localFixture.applySignature("AuctionToken",
                                                   auction.cashAuctionToken())

    # Purchasing REP or CASH will update the current auctions derived price, though until the auction ends it will be very innacurate so we dont bother checking here. We'll purchase 1/4 of the available supply of each at the initial price
    repAmount = auction.getCurrentAttoRepBalance() / 4
    cost = int(Decimal(repAmount) * Decimal(repSalePrice) / Decimal(10**18))
    with BuyWithCash(cash, cost, localFixture.accounts[0],
                     "trade cash for rep"):
        assert auction.tradeCashForRep(repAmount)

    cashSalePrice = auction.getCashSalePriceInAttoRep()
    cashAmount = auction.getCurrentAttoCashBalance() / 4
    assert auction.tradeRepForCash(cashAmount)

    # We'll let some time pass and buy the rest of the REP and CASH and the halfpoint prices
    assert time.incrementTimestamp(12 * 60 * 60)

    newRepSalePrice = auction.getRepSalePriceInAttoCash()
    repAmount = auction.getCurrentAttoRepBalance()
    cost = int(Decimal(repAmount) * Decimal(newRepSalePrice) / Decimal(10**18))
    with BuyWithCash(cash, cost, localFixture.accounts[0],
                     "trade cash for rep"):
        assert auction.tradeCashForRep(repAmount)

    # Now we'll purchase 2 CASH
    newCashSalePrice = auction.getCashSalePriceInAttoRep()
    cashAmount = auction.getCurrentAttoCashBalance()
    assert auction.tradeRepForCash(cashAmount)

    # We can observe that the recorded lower bound weighs this purchase more since more CASH was purchased
    lowerBoundRepPrice = int(
        Decimal(auction.initialAttoCashBalance()) * Decimal(10**18) /
        Decimal(cashAuctionToken.maxSupply()))
    upperBoundRepPrice = int(
        Decimal(repAuctionToken.maxSupply()) * Decimal(10**18) /
        Decimal(auction.initialAttoRepBalance()))
    derivedRepPrice = int(Decimal(lowerBoundRepPrice + upperBoundRepPrice) / 2)
    assert auction.getDerivedRepPriceInAttoCash() == derivedRepPrice

    # Lets turn on auction price reporting and move time so that this auction is considered over
    assert time.setTimestamp(auction.getAuctionEndTime() + 1)

    # We can see now that the auction will use the derived rep price when we request the price of rep for reporting fee purposes
    assert auction.getRepPriceInAttoCash() == derivedRepPrice

    # If we move time forward to the next auction we can confirm the price is still the derived price
    assert time.setTimestamp(auction.getAuctionStartTime())
    assert auction.getRepPriceInAttoCash() == derivedRepPrice

    # Lets purchase REP and CASH in this auction and confirm that it does not change the reported rep price, but is recorded for use internally to set auction pricing
    repSalePrice = auction.getRepSalePriceInAttoCash()

    # Note that the repSalePrice now starts at 4 x the previous auctions derived price
    assert auction.initialRepSalePrice() == 4 * derivedRepPrice

    repAmount = auction.getCurrentAttoRepBalance()
    cost = int(Decimal(repAmount) * Decimal(repSalePrice) / Decimal(10**18))
    with BuyWithCash(cash, cost, localFixture.accounts[0],
                     "trade cash for rep"):
        assert auction.tradeCashForRep(repAmount)

    # Now we'll purchase 1 CASH
    cashSalePrice = auction.getCashSalePriceInAttoRep()

    # Note that the cashSalePrice is now 4 x the previous auctions derived price in terms of CASH
    assert auction.initialCashSalePrice() == int(4 * Decimal(10**36) /
                                                 Decimal(derivedRepPrice))

    cashAmount = auction.getCurrentAttoCashBalance()
    assert auction.tradeRepForCash(cashAmount)

    # And as before the recorded REP price is the mean of the two bounds
    repAuctionToken = localFixture.applySignature("AuctionToken",
                                                  auction.repAuctionToken())
    cashAuctionToken = localFixture.applySignature("AuctionToken",
                                                   auction.cashAuctionToken())
    lowerBoundRepPrice = int(
        Decimal(auction.initialAttoCashBalance()) * Decimal(10**18) /
        Decimal(cashAuctionToken.maxSupply()))
    upperBoundRepPrice = int(
        Decimal(repAuctionToken.maxSupply()) * Decimal(10**18) /
        Decimal(auction.initialAttoRepBalance()))
    newDerivedRepPrice = int(
        Decimal(lowerBoundRepPrice + upperBoundRepPrice) / 2)
    assert auction.getDerivedRepPriceInAttoCash() == newDerivedRepPrice

    # Now lets go to the dormant state and confirm that the reported rep price is still the previous recorded auctions derived REP price
    assert time.setTimestamp(auction.getAuctionEndTime() + 1)
    assert auction.getRepPriceInAttoCash() == derivedRepPrice

    # In the next auction we will see the newly derived REP price used as the basis for auction pricing but NOT used as the reported rep price for fees
    assert time.setTimestamp(auction.getAuctionStartTime())
    assert auction.initializeNewAuction()
    assert auction.getRepPriceInAttoCash() == derivedRepPrice
    assert auction.lastRepPrice() == newDerivedRepPrice
    assert auction.initialRepSalePrice() == 4 * newDerivedRepPrice
    assert auction.initialCashSalePrice() == int(4 * Decimal(10**36) /
                                                 Decimal(newDerivedRepPrice))
def test_forking(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
    otherOutcomeStake = 10**18
    assert market.disputeDesignatedReport([market.getNumTicks(), 0],
                                          otherOutcomeStake,
                                          False,
                                          sender=tester.k1)
    assert categoricalMarket.disputeDesignatedReport(
        [categoricalMarket.getNumTicks(), 0, 0],
        otherOutcomeStake,
        False,
        sender=tester.k2)
    assert scalarMarket.disputeDesignatedReport(
        [scalarMarket.getNumTicks(), 0],
        otherOutcomeStake,
        False,
        sender=tester.k3)

    reporterFees = 1000 * market.getNumTicks(
    ) / universe.getReportingFeeDivisor()
    totalWinningStake = reportingWindow.getTotalWinningStake()
    assert cash.balanceOf(reportingWindow.address) == reporterFees

    # Progress to the Limited dispute phase and dispute one of the markets. This should migrate fees to the reporting window the market migrates to proportional to its stake
    localFixture.chain.head_state.timestamp = reportingWindow.getDisputeStartTime(
    ) + 1

    assert market.disputeFirstReporters([market.getNumTicks() - 1, 1],
                                        otherOutcomeStake,
                                        False,
                                        sender=tester.k4,
                                        startgas=long(6.7 * 10**6))
    assert categoricalMarket.disputeFirstReporters(
        [categoricalMarket.getNumTicks() - 1, 1, 0],
        otherOutcomeStake,
        False,
        sender=tester.k4,
        startgas=long(6.7 * 10**6))
    assert scalarMarket.disputeFirstReporters(
        [scalarMarket.getNumTicks() - 1, 1],
        otherOutcomeStake,
        False,
        sender=tester.k4,
        startgas=long(6.7 * 10**6))

    # Progress into last dispute and cause a fork
    reportingWindow = localFixture.applySignature("ReportingWindow",
                                                  market.getReportingWindow())
    localFixture.chain.head_state.timestamp = reportingWindow.getDisputeStartTime(
    ) + 1

    forkDuration = lastDisputeCost = localFixture.contracts[
        "Constants"].FORK_DURATION_SECONDS()
    nextReportingWindow = localFixture.applySignature(
        "ReportingWindow",
        universe.getReportingWindowByTimestamp(
            localFixture.chain.head_state.timestamp + forkDuration))
    scalarMarketStake = scalarMarket.getTotalStake()
    lastDisputeCost = localFixture.contracts[
        "Constants"].LAST_REPORTERS_DISPUTE_BOND_AMOUNT()
    totalScalarMarketStakeMoved = scalarMarketStake + lastDisputeCost
    migratedFees = reporterFees * (scalarMarketStake + lastDisputeCost) / (
        reportingWindow.getTotalStake() + lastDisputeCost)

    with TokenDelta(cash, -migratedFees, reportingWindow.address,
                    "Disputing in last didn't migrate ETH out correctly"):
        with TokenDelta(cash, migratedFees, nextReportingWindow.address,
                        "Disputing in last didn't migrate ETH in correctly"):
            with StakeDelta(
                    lastDisputeCost, -scalarMarketStake, 0, scalarMarket,
                    reportingWindow,
                    "Disputing in last is not migrating stake out correctly"):
                with StakeDelta(
                        lastDisputeCost, totalScalarMarketStakeMoved, 0,
                        scalarMarket, nextReportingWindow,
                        "Disputing in last is not migrating stake in correctly"
                ):
                    assert scalarMarket.disputeLastReporters(sender=tester.k5)

    # We migrate REP to a new universe and finalize the forking market
    newUniverse = localFixture.getOrCreateChildUniverse(
        universe, scalarMarket, [0, scalarMarket.getNumTicks()])
    newUniverseReputationToken = localFixture.applySignature(
        'ReputationToken', newUniverse.getReputationToken())

    # Testers all move their REP to the new universe
    for i in range(0, 5):
        reputationToken.migrateOut(newUniverseReputationToken.address,
                                   localFixture.testerAddress[i],
                                   reputationToken.balanceOf(
                                       localFixture.testerAddress[i]),
                                   sender=localFixture.testerKey[i])

    # Finalize the forking market
    assert scalarMarket.tryFinalize()

    # migrate one of the markets to the winning universe and confirm fees went with it
    oldReportingWindowAddress = market.getReportingWindow()
    designatedReportingDuration = localFixture.contracts[
        "Constants"].DESIGNATED_REPORTING_DURATION_SECONDS()
    newReportingWindowAddress = newUniverse.getReportingWindowByMarketEndTime(
        localFixture.chain.head_state.timestamp - designatedReportingDuration)
    migratedFees = cash.balanceOf(oldReportingWindowAddress)
    with TokenDelta(
            cash, -migratedFees, oldReportingWindowAddress,
            "Migrating to a new universe didn't migrate ETH out correctly"):
        with TokenDelta(
                cash, migratedFees, newReportingWindowAddress,
                "Migrating to a new universe didn't migrate ETH in correctly"):
            market.migrateThroughAllForks()