예제 #1
0
def create_debt(web3: Web3, mcd: DssDeployment, our_address: Address, deployment_address: Address):
    assert isinstance(web3, Web3)
    assert isinstance(mcd, DssDeployment)
    assert isinstance(our_address, Address)
    assert isinstance(deployment_address, Address)

    # Create a vault
    collateral = mcd.collaterals['ETH-A']
    ilk = collateral.ilk
    wrap_eth(mcd, deployment_address, Wad.from_number(1))
    collateral.approve(deployment_address)
    assert collateral.adapter.join(deployment_address, Wad.from_number(1)).transact(
        from_address=deployment_address)
    frob(mcd, collateral, deployment_address, dink=Wad.from_number(1), dart=Wad(0))
    dart = max_dart(mcd, collateral, deployment_address) - Wad(1)
    frob(mcd, collateral, deployment_address, dink=Wad(0), dart=dart)
    assert not mcd.cat.can_bite(ilk, mcd.vat.urn(collateral.ilk, deployment_address))

    # Undercollateralize by dropping the spot price, and then bite the vault
    to_price = Wad(Web3.toInt(collateral.pip.read())) / Wad.from_number(2)
    set_collateral_price(mcd, collateral, to_price)
    urn = mcd.vat.urn(collateral.ilk, deployment_address)
    assert urn.ink is not None and urn.art is not None
    assert ilk.spot is not None
    safe = Ray(urn.art) * mcd.vat.ilk(ilk.name).rate <= Ray(urn.ink) * ilk.spot
    assert not safe
    assert mcd.cat.can_bite(collateral.ilk, urn)
    assert mcd.cat.bite(collateral.ilk, urn).transact()
    flip_kick = collateral.flipper.kicks()

    # Generate some Dai, bid on and win the flip auction without covering all the debt
    wrap_eth(mcd, our_address, Wad.from_number(10))
    collateral.approve(our_address)
    assert collateral.adapter.join(our_address, Wad.from_number(10)).transact(from_address=our_address)
    web3.eth.defaultAccount = our_address.address
    frob(mcd, collateral, our_address, dink=Wad.from_number(10), dart=Wad.from_number(200))
    collateral.flipper.approve(mcd.vat.address, approval_function=hope_directly())
    current_bid = collateral.flipper.bids(flip_kick)
    urn = mcd.vat.urn(collateral.ilk, our_address)
    assert Rad(urn.art) > current_bid.tab
    bid = Rad.from_number(6)
    TestFlipper.tend(collateral.flipper, flip_kick, our_address, current_bid.lot, bid)
    mcd.vat.can(our_address, collateral.flipper.address)
    wait(mcd, our_address, collateral.flipper.ttl()+1)
    assert collateral.flipper.deal(flip_kick).transact()

    # Raise debt from the queue (note that vow.wait is 0 on our testchain)
    bites = mcd.cat.past_bites(100)
    for bite in bites:
        era_bite = bite.era(web3)
        assert era_bite > int(datetime.now().timestamp()) - 120
        assert mcd.vow.sin_of(era_bite) > Rad(0)
        assert mcd.vow.flog(era_bite).transact()
        assert mcd.vow.sin_of(era_bite) == Rad(0)
    # Cancel out surplus and debt
    dai_vow = mcd.vat.dai(mcd.vow.address)
    assert dai_vow <= mcd.vow.woe()
    assert mcd.vow.heal(dai_vow).transact()
    assert mcd.vow.woe() >= mcd.vow.sump()
예제 #2
0
    def test_scenario(self, web3, mcd, flapper, our_address, other_address,
                      deployment_address):
        create_surplus(mcd, flapper, deployment_address)

        joy_before = mcd.vat.dai(mcd.vow.address)
        # total surplus > total debt + surplus auction lot size + surplus buffer
        assert joy_before > mcd.vat.sin(
            mcd.vow.address) + mcd.vow.bump() + mcd.vow.hump()
        assert (mcd.vat.sin(mcd.vow.address) -
                mcd.vow.sin()) - mcd.vow.ash() == Rad(0)
        assert mcd.vow.flap().transact()
        kick = flapper.kicks()
        assert kick == 1
        assert len(flapper.active_auctions()) == 1
        check_active_auctions(flapper)
        current_bid = flapper.bids(1)
        assert current_bid.lot > Rad(0)
        log = flapper.past_logs(1)[0]
        assert isinstance(log, Flapper.KickLog)
        assert log.id == kick
        assert log.lot == current_bid.lot
        assert log.bid == current_bid.bid

        # Allow the auction to expire, and then resurrect it
        wait(mcd, our_address, flapper.tau() + 1)
        assert flapper.tick(kick).transact()

        # Bid on the resurrected auction
        mint_mkr(mcd.mkr, our_address, Wad.from_number(10))
        flapper.approve(mcd.mkr.address, directly(from_address=our_address))
        bid = Wad.from_number(0.001)
        assert mcd.mkr.balance_of(our_address) > bid
        TestFlapper.tend(flapper, kick, our_address, current_bid.lot, bid)
        current_bid = flapper.bids(kick)
        assert current_bid.bid == bid
        assert current_bid.guy == our_address

        # Exercise _deal_ after bid has expired
        wait(mcd, our_address, flapper.ttl() + 1)
        now = datetime.now().timestamp()
        assert 0 < current_bid.tic < now or current_bid.end < now
        assert flapper.deal(kick).transact(from_address=our_address)
        joy_after = mcd.vat.dai(mcd.vow.address)
        print(f'joy_before={str(joy_before)}, joy_after={str(joy_after)}')
        assert joy_before - joy_after == mcd.vow.bump()
        log = flapper.past_logs(1)[0]
        assert isinstance(log, Flapper.DealLog)
        assert log.usr == our_address
        assert log.id == kick

        # Grab our dai
        mcd.approve_dai(our_address)
        assert mcd.dai_adapter.exit(our_address, Wad(
            current_bid.lot)).transact(from_address=our_address)
        assert mcd.dai.balance_of(our_address) >= Wad(current_bid.lot)
        assert (mcd.vat.sin(mcd.vow.address) -
                mcd.vow.sin()) - mcd.vow.ash() == Rad(0)
예제 #3
0
    def test_scenario(self, web3, mcd, flopper, our_address, other_address,
                      deployment_address):
        create_debt(web3, mcd, our_address, deployment_address)

        # Kick off the flop auction
        assert flopper.kicks() == 0
        assert len(flopper.active_auctions()) == 0
        assert mcd.vat.dai(mcd.vow.address) == Rad(0)
        assert mcd.vow.flop().transact()
        kick = flopper.kicks()
        assert kick == 1
        assert len(flopper.active_auctions()) == 1
        check_active_auctions(flopper)
        current_bid = flopper.bids(kick)
        log = flopper.past_logs(1)[0]
        assert isinstance(log, Flopper.KickLog)
        assert log.id == kick
        assert log.lot == current_bid.lot
        assert log.bid == current_bid.bid
        assert log.gal == mcd.vow.address

        # Allow the auction to expire, and then resurrect it
        wait(mcd, our_address, flopper.tau() + 1)
        assert flopper.tick(kick).transact()
        assert flopper.bids(kick).lot == current_bid.lot * flopper.pad()

        # Bid on the resurrected auction
        bid = Wad.from_number(0.000005)
        flopper.approve(mcd.vat.address, hope_directly())
        assert mcd.vat.can(our_address, flopper.address)
        TestFlopper.dent(flopper, kick, our_address, bid, current_bid.bid)
        current_bid = flopper.bids(kick)
        assert current_bid.guy == our_address

        # Confirm victory
        wait(mcd, our_address, flopper.ttl() + 1)
        assert flopper.live()
        now = int(datetime.now().timestamp())
        assert (current_bid.tic < now
                and current_bid.tic != 0) or current_bid.end < now
        mkr_before = mcd.mkr.balance_of(our_address)
        assert flopper.deal(kick).transact(from_address=our_address)
        mkr_after = mcd.mkr.balance_of(our_address)
        assert mkr_after > mkr_before
        log = flopper.past_logs(1)[0]
        assert isinstance(log, Flopper.DealLog)
        assert log.usr == our_address
        assert log.id == kick
예제 #4
0
    def test_scenario(self, web3, mcd, flopper, our_address, other_address,
                      deployment_address):
        self.create_debt(web3, mcd, our_address, deployment_address)

        # Kick off the flop auction
        assert flopper.kicks() == 0
        assert len(flopper.active_auctions()) == 0
        assert mcd.vat.dai(mcd.vow.address) == Rad(0)
        # TODO: Get bid_id return value from transaction rather than guessing bid_id==1
        assert mcd.vow.flop().transact()
        kick = flopper.kicks()
        assert kick == 1
        assert len(flopper.active_auctions()) == 1
        current_bid = flopper.bids(kick)

        # Allow the auction to expire, and then resurrect it
        wait(mcd, our_address, flopper.tau() + 1)
        assert flopper.tick(kick).transact()

        # Bid on the resurrected auction
        flopper.approve(mcd.vat.address, hope_directly())
        assert mcd.vat.can(our_address, flopper.address)
        TestFlopper.dent(flopper, kick, our_address, Wad.from_number(0.5),
                         current_bid.bid)
        current_bid = flopper.bids(kick)
        assert current_bid.guy == our_address

        # Confirm victory
        wait(mcd, our_address, flopper.ttl() + 1)
        assert flopper.live()
        now = int(datetime.now().timestamp())
        assert (current_bid.tic < now
                and current_bid.tic != 0) or current_bid.end < now
        mkr_before = mcd.mkr.balance_of(our_address)
        assert flopper.deal(kick).transact(from_address=our_address)
        mkr_after = mcd.mkr.balance_of(our_address)
        assert mkr_after > mkr_before
예제 #5
0
    def test_scenario(self, web3, mcd, collateral, flipper, our_address,
                      other_address, deployment_address):
        # Create a CDP
        collateral = mcd.collaterals['ETH-A']
        kicks_before = flipper.kicks()
        ilk = collateral.ilk
        wrap_eth(mcd, deployment_address, Wad.from_number(1))
        collateral.approve(deployment_address)
        assert collateral.adapter.join(
            deployment_address,
            Wad.from_number(1)).transact(from_address=deployment_address)
        frob(mcd,
             collateral,
             deployment_address,
             dink=Wad.from_number(1),
             dart=Wad(0))
        dart = max_dart(mcd, collateral, deployment_address) - Wad(1)
        frob(mcd, collateral, deployment_address, dink=Wad(0), dart=dart)

        # Mint and withdraw all the Dai
        mcd.approve_dai(deployment_address)
        assert mcd.dai_adapter.exit(
            deployment_address, dart).transact(from_address=deployment_address)
        assert mcd.dai.balance_of(deployment_address) == dart
        assert mcd.vat.dai(deployment_address) == Rad(0)

        # Undercollateralize the CDP
        to_price = Wad(Web3.toInt(collateral.pip.read())) / Wad.from_number(2)
        set_collateral_price(mcd, collateral, to_price)
        urn = mcd.vat.urn(collateral.ilk, deployment_address)
        ilk = mcd.vat.ilk(ilk.name)
        assert ilk.rate is not None
        assert ilk.spot is not None
        safe = Ray(urn.art) * mcd.vat.ilk(ilk.name).rate <= Ray(
            urn.ink) * ilk.spot
        assert not safe
        assert len(flipper.active_auctions()) == 0

        # Bite the CDP, which moves debt to the vow and kicks the flipper
        urn = mcd.vat.urn(collateral.ilk, deployment_address)
        assert urn.ink > Wad(0)
        lot = min(urn.ink, mcd.cat.lump(ilk))  # Wad
        art = min(urn.art, (lot * urn.art) / urn.ink)  # Wad
        tab = art * ilk.rate  # Wad
        assert tab == dart
        simulate_bite(mcd, collateral, deployment_address)
        assert mcd.cat.bite(collateral.ilk, Urn(deployment_address)).transact()
        kick = flipper.kicks()
        assert kick == kicks_before + 1
        urn = mcd.vat.urn(collateral.ilk, deployment_address)
        # Check vat, vow, and cat
        assert urn.ink == Wad(0)
        assert urn.art == dart - art
        assert mcd.vat.vice() > Rad(0)
        assert mcd.vow.sin() == Rad(tab)
        bites = mcd.cat.past_bites(1)
        assert len(bites) == 1
        last_bite = bites[0]
        assert last_bite.tab > Rad(0)
        # Check the flipper
        current_bid = flipper.bids(kick)
        assert isinstance(current_bid, Flipper.Bid)
        assert current_bid.lot > Wad(0)
        assert current_bid.tab > Rad(0)
        assert current_bid.bid == Rad(0)
        # Cat doesn't incorporate the liquidation penalty (chop), but the kicker includes it.
        # Awaiting word from @dc why this is so.
        #assert last_bite.tab == current_bid.tab
        log = flipper.past_logs(1)[0]
        assert isinstance(log, Flipper.KickLog)
        assert log.id == kick
        assert log.lot == current_bid.lot
        assert log.bid == current_bid.bid
        assert log.tab == current_bid.tab
        assert log.usr == deployment_address
        assert log.gal == mcd.vow.address

        # Allow the auction to expire, and then resurrect it
        wait(mcd, our_address, flipper.tau() + 1)
        assert flipper.tick(kick).transact()

        # Wrap some eth and handle approvals before bidding
        eth_required = Wad(
            current_bid.tab / Rad(ilk.spot)) * Wad.from_number(1.1)
        wrap_eth(mcd, other_address, eth_required)
        collateral.approve(other_address)
        assert collateral.adapter.join(
            other_address, eth_required).transact(from_address=other_address)
        wrap_eth(mcd, our_address, eth_required)
        collateral.approve(our_address)
        assert collateral.adapter.join(
            our_address, eth_required).transact(from_address=our_address)

        # Test the _tend_ phase of the auction
        flipper.approve(
            mcd.vat.address,
            approval_function=hope_directly(from_address=other_address))
        # Add Wad(1) to counter precision error converting tab from Rad to Wad
        frob(mcd,
             collateral,
             other_address,
             dink=eth_required,
             dart=Wad(current_bid.tab) + Wad(1))
        urn = mcd.vat.urn(collateral.ilk, other_address)
        assert Rad(urn.art) >= current_bid.tab
        # Bid the tab to instantly transition to dent stage
        TestFlipper.tend(flipper, kick, other_address, current_bid.lot,
                         current_bid.tab)
        current_bid = flipper.bids(kick)
        assert current_bid.guy == other_address
        assert current_bid.bid == current_bid.tab
        assert len(flipper.active_auctions()) == 1
        check_active_auctions(flipper)
        log = flipper.past_logs(1)[0]
        assert isinstance(log, Flipper.TendLog)
        assert log.guy == current_bid.guy
        assert log.id == current_bid.id
        assert log.lot == current_bid.lot
        assert log.bid == current_bid.bid

        # Test the _dent_ phase of the auction
        flipper.approve(
            mcd.vat.address,
            approval_function=hope_directly(from_address=our_address))
        frob(mcd,
             collateral,
             our_address,
             dink=eth_required,
             dart=Wad(current_bid.tab) + Wad(1))
        lot = current_bid.lot - Wad.from_number(0.2)
        assert flipper.beg() * lot <= current_bid.lot
        assert mcd.vat.can(our_address, flipper.address)
        TestFlipper.dent(flipper, kick, our_address, lot, current_bid.tab)
        current_bid = flipper.bids(kick)
        assert current_bid.guy == our_address
        assert current_bid.bid == current_bid.tab
        assert current_bid.lot == lot
        log = flipper.past_logs(1)[0]
        assert isinstance(log, Flipper.DentLog)
        assert log.guy == current_bid.guy
        assert log.id == current_bid.id
        assert log.lot == current_bid.lot
        assert log.bid == current_bid.bid

        # Exercise _deal_ after bid has expired
        wait(mcd, our_address, flipper.ttl() + 1)
        now = datetime.now().timestamp()
        assert 0 < current_bid.tic < now or current_bid.end < now
        assert flipper.deal(kick).transact(from_address=our_address)
        assert len(flipper.active_auctions()) == 0
        log = flipper.past_logs(1)[0]
        assert isinstance(log, Flipper.DealLog)
        assert log.usr == our_address

        # Grab our collateral
        collateral_before = collateral.gem.balance_of(our_address)
        assert collateral.adapter.exit(
            our_address, current_bid.lot).transact(from_address=our_address)
        collateral_after = collateral.gem.balance_of(our_address)
        assert collateral_before < collateral_after

        # Cleanup
        set_collateral_price(mcd, collateral, Wad.from_number(230))
        cleanup_urn(mcd, collateral, other_address)
예제 #6
0
    def test_scenario(self, web3, mcd, flapper, our_address, other_address,
                      deployment_address):
        joy = mcd.vat.dai(mcd.vow.address)

        if joy == Rad(0):
            # Create a CDP with surplus
            print('Creating a CDP with surplus')
            collateral = mcd.collaterals['ETH-B']
            assert flapper.kicks() == 0
            wrap_eth(mcd, deployment_address, Wad.from_number(0.1))
            collateral.approve(deployment_address)
            assert collateral.adapter.join(
                deployment_address,
                Wad.from_number(0.1)).transact(from_address=deployment_address)
            frob(mcd,
                 collateral,
                 deployment_address,
                 dink=Wad.from_number(0.1),
                 dart=Wad.from_number(10))
            assert mcd.jug.drip(
                collateral.ilk).transact(from_address=deployment_address)
        else:
            print('Surplus already exists; skipping CDP creation')
        joy_before = mcd.vat.dai(mcd.vow.address)
        # total surplus > total debt + surplus auction lot size + surplus buffer
        assert joy_before > mcd.vat.sin(
            mcd.vow.address) + mcd.vow.bump() + mcd.vow.hump()
        assert (mcd.vat.sin(mcd.vow.address) -
                mcd.vow.sin()) - mcd.vow.ash() == Rad(0)
        assert mcd.vow.flap().transact()
        kick = flapper.kicks()
        assert kick == 1
        assert len(flapper.active_auctions()) == 1
        current_bid = flapper.bids(1)
        assert current_bid.lot > Rad(0)

        # Bid on the surplus
        mint_mkr(mcd.mkr, deployment_address, our_address, Wad.from_number(10))
        flapper.approve(mcd.mkr.address, directly(from_address=our_address))
        bid = Wad.from_number(0.001)
        assert mcd.mkr.balance_of(our_address) > bid
        TestFlapper.tend(flapper, kick, our_address, current_bid.lot, bid)
        current_bid = flapper.bids(kick)
        assert current_bid.bid == bid
        assert current_bid.guy == our_address

        # Exercise _deal_ after bid has expired
        wait(mcd, our_address, flapper.ttl() + 1)
        now = datetime.now().timestamp()
        assert 0 < current_bid.tic < now or current_bid.end < now
        assert flapper.deal(kick).transact(from_address=our_address)
        joy_after = mcd.vat.dai(mcd.vow.address)
        print(f'joy_before={str(joy_before)}, joy_after={str(joy_after)}')
        assert joy_before - joy_after == mcd.vow.bump()

        # Grab our dai
        mcd.approve_dai(our_address)
        assert mcd.dai_adapter.exit(our_address, Wad(
            current_bid.lot)).transact(from_address=our_address)
        assert mcd.dai.balance_of(our_address) >= Wad(current_bid.lot)
        assert (mcd.vat.sin(mcd.vow.address) -
                mcd.vow.sin()) - mcd.vow.ash() == Rad(0)