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()
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)
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
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
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)
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)