def create_flip_auction(mcd: DssDeployment, deployment_address: Address, our_address: Address): assert isinstance(mcd, DssDeployment) assert isinstance(our_address, Address) assert isinstance(deployment_address, Address) # Create a CDP 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) # Undercollateralize and bite the CDP to_price = Wad(mcd.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) 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(deployment_address)) assert mcd.cat.bite(collateral.ilk, Urn(deployment_address)).transact() flip_kick = collateral.flipper.kicks() # Generate some Dai, bid on 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) mcd.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) tend(collateral.flipper, flip_kick, our_address, current_bid.lot, bid)
def d(web3, our_address, keeper_address, gal_address): # dss = """ # {"MCD_MOM": "0xD3F7637ace900b381a0A6Bf878639E5BCa564B53", "MCD_VAT": "0x7dc681a82de642cf86cc05d6c938aA0021a6807F", "MCD_VOW": "0x68A75d6CaC097fFE5FC1e912EaDc8832bC1D8f36", "MCD_DRIP": "0x58B21768D30433481FbE87C2065Cc081eF982898", "MCD_PIT": "0x0D64bE75122D4Cb0F65776a973f3c03eb83177Ff", "MCD_CAT": "0x49A4177032a6cA5f419E764a154B6CE710418e6a", "MCD_FLAP": "0x90194dC5E16C203EE8debEc949130Ed60D97Af96", "MCD_FLOP": "0x27c232d542B3F9503c327Ff087582983E2086c61", "MCD_DAI": "0xdBA593D53D5C5AA91D73402DB3622d63463620Dd", "MCD_JOIN_DAI": "0xD2E5103366FEf1F6D387d0e11132Cef95ae3F8c8", "MCD_MOVE_DAI": "0x86a1f3308dA49e7b3C8e64a6702AD19f72Ca4aEB", "MCD_GOV": "0xD6be7670e94E88b28143F057944DAAA8900629AE", "COLLATERALS": ["WETH"], "WETH": "0x820f809525024513a5A45e74f5Cf36C67b98F2D7", "MCD_JOIN_WETH": "0xe058f7252743064ee497cF5Caa10F312B00691e9", "MCD_MOVE_WETH": "0x4dFcCEBCF5Ae068AE41503B93f7d4e8234087800", "MCD_FLIP_WETH": "0xec8e3dFdfD4665f19971B4ffE2a78b51095f349b", "MCD_SPOT_WETH": "0xc323B27F990C4AA3C9297Da8738d765Bac3ca8df", "PIP_WETH": "0xaCab49615c32e56a59097855a08d3653cAb0e473"} # """ # return DssDeployment.from_json(web3=web3, conf=dss) d = DssDeployment.deploy(web3=web3, debt_ceiling=Wad.from_number(100000000)) c = d.collaterals[0] assert d.pit.file_line(c.ilk, Wad.from_number(100000000)).transact() # Set collateral debt ceiling assert d.cat.file_lump(c.ilk, Wad.from_number(100)).transact() # Set liquidation Quantity of c at 100 # mint gem for cdp frob() by gal_address and our_address to draw dai assert c.gem.mint(Wad.from_number(2000000)).transact() assert c.gem.transfer(gal_address, Wad.from_number(1000000)).transact() # Require to join the adapter assert c.gem.approve(c.adapter.address).transact() assert c.gem.approve(c.adapter.address).transact(from_address=gal_address) # draw dai for our_address assert c.adapter.join(Urn(our_address), Wad.from_number(1000000)).transact() assert d.pit.frob(c.ilk, Wad.from_number(1000000), Wad.from_number(1000000)).transact() assert d.dai_move.move(our_address, keeper_address, Wad.from_number(10000)).transact() # mint MKR for the keeper assert d.mkr.mint(Wad.from_number(100)).transact() assert d.mkr.transfer(keeper_address, Wad.from_number(100)).transact() return d
def urn_from_vdb_node(self, node: dict) -> Urn: assert isinstance(node, dict) address = Address(node['urnIdentifier']) ink = Wad(int(node['ink'])) art = Wad(int(node['art'])) return Urn(address, self.ilk, ink, art)
def urn_from_tokenflow_item(self, item: dict) -> Urn: assert isinstance(item, dict) address = Address(to_checksum_address(item['urn'])) ink = max(Wad(0), Wad.from_number(float(item['collateral']))) art = Wad(item['art']) return Urn(address, self.ilk, ink, art)
def test_gem(self, our_address: Address, d: DssDeployment): collateral = d.collaterals[0] # when assert collateral.adapter.join(Urn(our_address), Wad(10)).transact() # then assert d.vat.gem(collateral.ilk, our_address) == Rad(Wad(10))
def test_bite(self, our_address, d: DssDeployment): # given collateral = d.collaterals[0] assert collateral.adapter.join(Urn(our_address), Wad.from_number(2)).transact() assert d.pit.frob(collateral.ilk, Wad.from_number(2), Wad(0)).transact() our_urn = d.vat.urn(collateral.ilk, our_address) max_dart = our_urn.ink * d.pit.spot(collateral.ilk) - our_urn.art to_price = Wad(Web3.toInt(collateral.pip.read())) - Wad.from_number(10) # when assert d.pit.frob(collateral.ilk, Wad(0), max_dart).transact() assert collateral.pip.poke_with_int(to_price.value).transact() assert collateral.spotter.poke().transact() # then assert d.cat.bite(collateral.ilk, Urn(our_address)).transact()
def bite(web3: Web3, mcd: DssDeployment, our_address: Address): collateral = mcd.collaterals['ETH-A'] # Add collateral to our CDP dink = Wad.from_number(1) wrap_eth(mcd, our_address, dink) assert collateral.gem.balance_of(our_address) >= dink assert collateral.adapter.join(our_address, dink).transact() frob(mcd, collateral, our_address, dink, Wad(0)) # Define required bite parameters to_price = Wad(Web3.toInt(collateral.pip.read())) / Wad.from_number(2) # Manipulate price to make our CDP underwater # Note this will only work on a testchain deployed with fixed prices, where PIP is a DSValue frob(mcd, collateral, our_address, Wad(0), max_dart(mcd, collateral, our_address)) set_collateral_price(mcd, collateral, to_price) # Bite the CDP assert mcd.cat.can_bite(collateral.ilk, Urn(our_address)) assert mcd.cat.bite(collateral.ilk, Urn(our_address)).transact()
def urn_from_node(self, node: dict) -> Urn: assert isinstance(node, dict) address = Address(node['identifier']) ink = Wad(0) art = Wad(0) for frob in node['vatFrobsByUrnId']['nodes']: ink += Wad(int(frob['dink'])) art += Wad(int(frob['dart'])) for bite in node['bitesByUrnId']['nodes']: ink -= Wad(int(bite['ink'])) art -= Wad(int(bite['art'])) return Urn(address, self.ilk, ink, art)
def bite_event(our_address: Address, d: DssDeployment): collateral = d.collaterals[0] # Add collateral to our CDP assert collateral.adapter.join(Urn(our_address), Wad.from_number(1)).transact() assert d.pit.frob(collateral.ilk, Wad.from_number(1), Wad(0)).transact() # Define required bite parameters our_urn = d.vat.urn(collateral.ilk, our_address) max_dart = our_urn.ink * d.pit.spot(collateral.ilk) - our_urn.art to_price = Wad(Web3.toInt(collateral.pip.read())) - Wad.from_number(1) # Manipulate price to make our CDP underwater assert d.pit.frob(collateral.ilk, Wad(0), max_dart).transact() assert collateral.pip.poke_with_int(to_price.value).transact() assert collateral.spotter.poke().transact() # Bite the CDP assert d.cat.bite(collateral.ilk, Urn(our_address)).transact() # Return the corresponding event return d.cat.past_bite(1)[0]
def unsafe_cdp(our_address, gal_address, d: DssDeployment, c: Collateral): # Add collateral to gal CDP assert c.adapter.join(Urn(gal_address), Wad.from_number(1)).transact(from_address=gal_address) assert d.pit.frob(c.ilk, Wad.from_number(1), Wad(0)).transact(from_address=gal_address) # Put gal CDP at max possible debt our_urn = d.vat.urn(c.ilk, gal_address) max_dart = our_urn.ink * d.pit.spot(c.ilk) - our_urn.art to_price = Wad(c.pip.read_as_int()) - Wad.from_number(1) assert d.pit.frob(c.ilk, Wad(0), max_dart).transact(from_address=gal_address) # Manipulate price to make gal CDP underwater assert c.pip.poke_with_int(to_price.value).transact(from_address=our_address) assert c.spotter.poke().transact() return d.vat.urn(c.ilk, gal_address)
def test_flap(self, web3, our_address, d: DssDeployment): # given snap_id = snapshot(web3) c = d.collaterals[0] assert c.adapter.join(Urn(our_address), Wad.from_number(200)).transact() assert d.pit.frob(c.ilk, Wad.from_number(200), Wad.from_number(11000)).transact() assert d.dai_move.move(our_address, d.vow.address, Wad.from_number(11000)).transact() # when assert d.vow.heal(d.vow.woe()).transact() assert d.vow.joy() >= (d.vow.awe() + d.vow.bump() + d.vow.hump()) assert d.vow.woe() == Wad(0) # then assert d.vow.flap().transact() # cleanup reset(web3, snap_id)
def d(web3, our_address, keeper_address, gal_address): # dss = """ # {"MCD_VAT": "0x08a3a91978B277c5797747A3671bDb6eE86e900E", "MCD_VOW": "0x7ef07c8DfddEECC23D50672b09310e45C8692ad2", "MCD_DRIP": "0xdc127E4DfF5F68740B8e21dEA687A4C3C690c176", "MCD_PIT": "0xaccbA2bB146405241507D7F3e39B85C5d1179d2B", "MCD_CAT": "0x41541A8692e00b9F5db706305dA1ee395Ba4680E", "MCD_FLOP": "0x5958E69d5795823F0F84b2ccbCE8D210cb67f418", "MCD_DAI": "0x787Cb94B57C23b9617265F1a6B80569d10dAaa42", "MCD_JOIN_DAI": "0xCc13a1a2E5AE9F6eC05CA7aF762967c5BD1Dd53f", "MCD_MOVE_DAI": "0x18792385d6c9AE2236cAc48473eb30D7d669BfFC", "MCD_GOV": "0xbE8Ae37bE4a1b1e22bAFD0cDdD921bc8FD5aD134", "COLLATERALS": ["WETH"], "WETH": "0x4Cdd635f050f9ca5bD7533D8c86044c4B86339A5", "MCD_JOIN_WETH": "0x050B6E24a805A027E3a31e7D4dE7E79A88A84e6D", "MCD_MOVE_WETH": "0x2ae154E870F53AC72f0D2E39FA2bb3a812b6A55d", "MCD_FLIP_WETH": "0x0953b1f31BBFA2633d7Ec92eb0C16511269aD4d0", "MCD_SPOT_WETH": "0x3731b266f67A9307CfaC6407D893070944F0684F", "PIP_WETH": "0x4C4EC6939152E7cD455D6586BC3eb5fF22ED94BE"} # """ # return DssDeployment.from_json(web3=web3, conf=dss) d = DssDeployment.deploy(web3=web3, debt_ceiling=Wad.from_number(100000000)) c = d.collaterals[0] assert d.pit.file_line(c.ilk, Wad.from_number(100000000)).transact() # Set collateral debt ceiling assert d.cat.file_lump(c.ilk, Wad.from_number(100)).transact() # Set liquidation Quantity of c at 100 # mint gem for cdp frob() by gal_address and our_address to draw dai assert c.gem.mint(Wad.from_number(2000000)).transact() assert c.gem.transfer(gal_address, Wad.from_number(1000000)).transact() # Require to join the adapter assert c.gem.approve(c.adapter.address).transact() assert c.gem.approve(c.adapter.address).transact(from_address=gal_address) # draw dai for our_address assert c.adapter.join(Urn(our_address), Wad.from_number(1000000)).transact() assert d.pit.frob(c.ilk, Wad.from_number(1000000), Wad.from_number(1000000)).transact() assert d.dai_move.move(our_address, keeper_address, Wad.from_number(10000)).transact() return d
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 CDP 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) # Undercollateralize and bite 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) safe = Ray(urn.art) * mcd.vat.ilk(ilk.name).rate <= Ray(urn.ink) * ilk.spot assert not safe simulate_bite(mcd, collateral, deployment_address) assert mcd.cat.bite(collateral.ilk, Urn(deployment_address)).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, 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 join(self, urn: Urn, value: Wad) -> Transact: assert (isinstance(urn, Urn)) assert (isinstance(value, Wad)) return Transact(self, self.web3, self.abi, self.address, self._contract, 'join', [urn.toBytes(), value.value])
def test_empty_flips(self, d: DssDeployment): nflip = d.cat.nflip() assert d.cat.flips(nflip + 1) == Cat.Flip( nflip + 1, Urn(Address('0x0000000000000000000000000000000000000000')), Wad(0))