def buy_collateral_with_system_coin( geb: GfDeployment, c: Collateral, collateral_auction_house: FixedDiscountCollateralAuctionHouse, id: int, address: Address, bid_amount: Wad): assert (isinstance(geb, GfDeployment)) assert (isinstance(c, Collateral)) assert (isinstance(collateral_auction_house, FixedDiscountCollateralAuctionHouse)) assert (isinstance(id, int)) assert (isinstance(bid_amount, Wad)) collateral_auction_house.approve( collateral_auction_house.safe_engine(), approval_function=approve_safe_modification_directly( from_address=address)) previous_bid = collateral_auction_house.bids(id) c.approve(address) reserve_system_coin(geb, c, address, bid_amount, extra_collateral=Wad.from_number(2)) TestAuctionKeeperCollateralFlashSwap.buy_collateral( collateral_auction_house, id, address, bid_amount)
def reserve_system_coin(geb: GfDeployment, c: Collateral, usr: Address, amount: Wad, extra_collateral=Wad.from_number(1)): assert isinstance(geb, GfDeployment) assert isinstance(c, Collateral) assert isinstance(usr, Address) assert isinstance(amount, Wad) assert amount > Wad(0) # Determine how much collateral is needed collateral_type = geb.safe_engine.collateral_type(c.collateral_type.name) accumulated_rate = collateral_type.accumulated_rate # Ray safety_price = collateral_type.safety_price # Ray assert accumulated_rate >= Ray.from_number(1) collateral_required = Wad((Ray(amount) / safety_price) * accumulated_rate) * extra_collateral + Wad(1) print(f'accumulated_rate {accumulated_rate}') print(f'extra_collateral {extra_collateral}') print(f'current safety price {safety_price}') print( f'collateral_required for {str(amount)} system_coin is {str(collateral_required)}' ) wrap_eth(geb, usr, collateral_required) c.approve(usr) assert c.adapter.join(usr, collateral_required).transact(from_address=usr) assert geb.safe_engine.modify_safe_collateralization( c.collateral_type, usr, collateral_required, amount).transact(from_address=usr) assert geb.safe_engine.safe(c.collateral_type, usr).generated_debt >= amount
def cleanup_safe(geb: GfDeployment, collateral: Collateral, address: Address): assert isinstance(geb, GfDeployment) assert isinstance(collateral, Collateral) assert isinstance(address, Address) safe = geb.safe_engine.safe(collateral.collateral_type, address) collateral_type = geb.safe_engine.collateral_type( collateral.collateral_type.name) # If tax_collector.tax_single has been called, we won't have sufficient system_coin to repay the SAFE #if collateral_type.accumulated_rate > Ray.from_number(1): # return # Return if this address doens't have enough system to coin to repay full debt amount_to_raise = Wad( Ray(safe.generated_debt) * collateral_type.accumulated_rate) if amount_to_raise > geb.system_coin.balance_of(address): return # Repay borrowed system coin geb.approve_system_coin(address) # Put all the user's system coin back into the safe engine if geb.system_coin.balance_of(address) >= Wad(0): assert geb.system_coin_adapter.join( address, geb.system_coin.balance_of(address)).transact(from_address=address) amount_to_raise = Wad( Ray(safe.generated_debt) * collateral_type.accumulated_rate) print( f'amount_to_raise={str(amount_to_raise)}, rate={str(collateral_type.accumulated_rate)}, system_coin={str(geb.safe_engine.coin_balance(address))}' ) if safe.generated_debt > Wad(0): wrap_modify_safe_collateralization(geb, collateral, address, Wad(0), amount_to_raise * -1) # Withdraw collateral collateral.approve(address) safe = geb.safe_engine.safe(collateral.collateral_type, address) # delta_collateral = Wad((Ray(safe.generated_debt) * collateral_type.accumulated_rate) / collateral_type.safety_price) # print(f'delta_collateral={str(delta_collateral)}, locked_collateral={str(safe.locked_collateral)}') if safe.generated_debt == Wad(0) and safe.locked_collateral > Wad(0): wrap_modify_safe_collateralization(geb, collateral, address, safe.locked_collateral * -1, Wad(0)) assert collateral.adapter.exit( address, geb.safe_engine.token_collateral( collateral.collateral_type, address)).transact(from_address=address) TestSAFEEngine.ensure_clean_safe(geb, collateral, address)
def open_safe(geb: GfDeployment, collateral: Collateral, address: Address): assert isinstance(geb, GfDeployment) assert isinstance(collateral, Collateral) assert isinstance(address, Address) collateral.approve(address) wrap_eth(geb, address, Wad.from_number(10)) assert collateral.adapter.join( address, Wad.from_number(10)).transact(from_address=address) wrap_modify_safe_collateralization(geb, collateral, address, Wad.from_number(10), Wad.from_number(15)) assert geb.safe_engine.global_debt() >= Rad(Wad.from_number(15)) assert geb.safe_engine.coin_balance(address) >= Rad.from_number(10)
def create_safe_with_surplus( geb: GfDeployment, c: Collateral, auction_income_recipient_address: Address) -> SAFE: assert isinstance(geb, GfDeployment) assert isinstance(c, Collateral) assert isinstance(auction_income_recipient_address, Address) print("in create_safe_with_surplus") # Ensure there is no debt which a previous test failed to clean up assert geb.safe_engine.debt_balance( geb.accounting_engine.address) == Rad(0) safe_collateral = Wad.from_number(300) safe_debt = Wad.from_number(3200) wrap_eth(geb, auction_income_recipient_address, safe_collateral) c.approve(auction_income_recipient_address) assert c.adapter.join(auction_income_recipient_address, safe_collateral).transact( from_address=auction_income_recipient_address) assert geb.safe_engine.modify_safe_collateralization( c.collateral_type, auction_income_recipient_address, delta_collateral=safe_collateral, delta_debt=safe_debt).transact( from_address=auction_income_recipient_address) assert geb.tax_collector.tax_single(c.collateral_type).transact( from_address=auction_income_recipient_address) # total surplus > total debt + surplus auction lot size + surplus buffer print( f"system_coin(accounting_engine)={str(geb.safe_engine.coin_balance(geb.accounting_engine.address))} >? " f"debt_balance(accounting_engine)={str(geb.safe_engine.debt_balance(geb.accounting_engine.address))} " f"+ accounting_engine.surplus_auction_amount_to_sell={str(geb.accounting_engine.surplus_auction_amount_to_sell())} " f"+ accounting_engine.surplus_buffer={str(geb.accounting_engine.surplus_buffer())}" ) assert geb.safe_engine.coin_balance(geb.accounting_engine.address) > \ geb.safe_engine.debt_balance(geb.accounting_engine.address) + \ geb.accounting_engine.surplus_auction_amount_to_sell() + \ geb.accounting_engine.surplus_buffer() return geb.safe_engine.safe(c.collateral_type, auction_income_recipient_address)
def from_json(web3: Web3, conf: str): conf = json.loads(conf) pause = DSPause(web3, Address(conf['GEB_PAUSE'])) safe_engine = SAFEEngine(web3, Address(conf['GEB_SAFE_ENGINE'])) accounting_engine = AccountingEngine( web3, Address(conf['GEB_ACCOUNTING_ENGINE'])) tax_collector = TaxCollector(web3, Address(conf['GEB_TAX_COLLECTOR'])) liquidation_engine = LiquidationEngine( web3, Address(conf['GEB_LIQUIDATION_ENGINE'])) system_coin = DSToken(web3, Address(conf['GEB_COIN'])) system_coin_adapter = CoinJoin(web3, Address(conf['GEB_COIN_JOIN'])) surplus_auction_house = PreSettlementSurplusAuctionHouse( web3, Address(conf['GEB_SURPLUS_AUCTION_HOUSE'])) debt_auction_house = DebtAuctionHouse( web3, Address(conf['GEB_DEBT_AUCTION_HOUSE'])) coin_savings_acct = CoinSavingsAccount(web3, Address(conf['GEB_COIN'])) oracle_relayer = OracleRelayer(web3, Address(conf['GEB_ORACLE_RELAYER'])) global_settlement = GlobalSettlement( web3, Address(conf['GEB_GLOBAL_SETTLEMENT'])) proxy_registry = ProxyRegistry(web3, Address(conf['PROXY_REGISTRY'])) proxy_actions = GebProxyActions(web3, Address(conf['PROXY_ACTIONS'])) safe_manager = SafeManager(web3, Address(conf['SAFE_MANAGER'])) mc_keeper_flash_proxy = GebMCKeeperFlashProxy( web3, Address( conf['GEB_UNISWAP_MULTI_COLLATERAL_KEEPER_FLASH_PROXY'])) starting_block_number = int(conf['STARTING_BLOCK_NUMBER']) # Kovan deployment current doesn't have PROT or ESM try: prot = DSToken(web3, Address(conf['GEB_PROT'])) except: prot = None try: esm = ESM(web3, Address(conf['GEB_ESM'])) except: esm = None try: uniswap_factory = Address(conf['UNISWAP_FACTORY']) except: uniswap_factory = None try: uniswap_router = Address(conf['UNISWAP_ROUTER']) except: uniswap_router = None collaterals = {} for name in GfDeployment.Config._infer_collaterals_from_addresses( conf.keys()): collateral_type = CollateralType(name[0].replace('_', '-')) if name[1] == "ETH": collateral = DSEthToken(web3, Address(conf[name[1]])) else: collateral = DSToken(web3, Address(conf[name[1]])) # osm_address contract may be a DSValue, OSM, DSM, or bogus address. osm_address = Address(conf[f'FEED_SECURITY_MODULE_{name[1]}']) network = GfDeployment.NETWORKS.get(web3.net.version, "testnet") osm = DSValue(web3, osm_address) if network == "testnet" else OSM( web3, osm_address) adapter = BasicCollateralJoin( web3, Address(conf[f'GEB_JOIN_{name[0]}'])) # Detect which auction house is used try: coll_auction_house = IncreasingDiscountCollateralAuctionHouse( web3, Address( conf[f'GEB_COLLATERAL_AUCTION_HOUSE_{name[0]}'])) except: try: coll_auction_house = EnglishCollateralAuctionHouse( web3, Address( conf[f'GEB_COLLATERAL_AUCTION_HOUSE_{name[0]}'] )) except: raise ValueError( f"Unknown auction house: GEB_COLLATERAL_AUCTION_HOUSE_{name[0]}" ) try: flash_proxy = GebETHKeeperFlashProxy( web3, Address(conf[ f'GEB_UNISWAP_SINGLE_KEEPER_FLASH_PROXY_{name[0]}'] )) except Exception as e: print(e) flash_proxy = None try: flash_proxy_dai_v3 = GebETHKeeperFlashProxy( web3, Address(conf[ f'GEB_UNISWAP_V3_MULTI_HOP_KEEPER_FLASH_PROXY_DAI_{name[0]}'] )) except Exception as e: print(e) flash_proxy_dai_v3 = None try: flash_proxy_usdc_v3 = GebETHKeeperFlashProxy( web3, Address(conf[ f'GEB_UNISWAP_V3_MULTI_HOP_KEEPER_FLASH_PROXY_USDC_{name[0]}'] )) except Exception as e: print(e) flash_proxy_usdc_v3 = None try: flash_proxy_v3 = GebETHKeeperFlashProxy( web3, Address(conf[ f'GEB_UNISWAP_V3_SINGLE_KEEPER_FLASH_PROXY_{name[0]}'] )) except Exception as e: print(e) flash_proxy_v3 = None collateral = Collateral( collateral_type=collateral_type, collateral=collateral, adapter=adapter, collateral_auction_house=coll_auction_house, keeper_flash_proxy=flash_proxy, keeper_flash_proxy_dai_v3=flash_proxy_dai_v3, keeper_flash_proxy_usdc_v3=flash_proxy_usdc_v3, keeper_flash_proxy_v3=flash_proxy_v3, osm=osm) collaterals[collateral_type.name] = collateral return GfDeployment.Config( pause, safe_engine, accounting_engine, tax_collector, liquidation_engine, surplus_auction_house, debt_auction_house, coin_savings_acct, system_coin, system_coin_adapter, prot, oracle_relayer, esm, global_settlement, proxy_registry, proxy_actions, safe_manager, uniswap_factory, uniswap_router, mc_keeper_flash_proxy, starting_block_number, collaterals)
def create_almost_risky_safe(geb: GfDeployment, c: Collateral, collateral_amount: Wad, auction_income_recipient_address: Address, draw_system_coin=True) -> SAFE: assert isinstance(geb, GfDeployment) assert isinstance(c, Collateral) assert isinstance(auction_income_recipient_address, Address) logging.debug("Creating almost risky safe") print("create_almost_risky") print( f"Liquidation price {geb.safe_engine.collateral_type(c.collateral_type.name).safety_price}" ) print( f"Safety price {geb.safe_engine.collateral_type(c.collateral_type.name).liquidation_price}" ) # Ensure vault isn't already unsafe (if so, this shouldn't be called) safe = geb.safe_engine.safe(c.collateral_type, auction_income_recipient_address) assert is_safe_safe( geb.safe_engine.collateral_type(c.collateral_type.name), safe) # Add collateral to auction_income_recipient vault if necessary c.approve(auction_income_recipient_address) token = Token(c.collateral_type.name, c.collateral.address, c.adapter.decimals()) print( f"collateral_amount={collateral_amount} locked_collateral={safe.locked_collateral}" ) delta_collateral = collateral_amount - safe.locked_collateral if delta_collateral > Wad(0): safe_engine_balance = geb.safe_engine.token_collateral( c.collateral_type, auction_income_recipient_address) balance = token.normalize_amount( c.collateral.balance_of(auction_income_recipient_address)) print( f"before join: delta_collateral={delta_collateral} safe_engine_balance={safe_engine_balance} balance={balance} safe_engine_gap={delta_collateral - safe_engine_balance}" ) if safe_engine_balance < delta_collateral: safe_engine_gap = delta_collateral - safe_engine_balance if balance < safe_engine_gap: if c.collateral_type.name.startswith("ETH"): wrap_eth(geb, auction_income_recipient_address, safe_engine_gap) else: raise RuntimeError("Insufficient collateral balance") amount_to_join = token.unnormalize_amount(safe_engine_gap) if amount_to_join == Wad( 0): # handle dusty balances with non-18-decimal tokens amount_to_join += token.unnormalize_amount(token.min_amount) assert c.adapter.join( auction_income_recipient_address, amount_to_join).transact( from_address=auction_income_recipient_address) safe_engine_balance = geb.safe_engine.token_collateral( c.collateral_type, auction_income_recipient_address) print( f"after join: delta_collateral={delta_collateral} safe_engine_balance={safe_engine_balance} balance={balance} safe_engine_gap={delta_collateral - safe_engine_balance}" ) assert safe_engine_balance >= delta_collateral assert geb.safe_engine.modify_safe_collateralization( c.collateral_type, auction_income_recipient_address, delta_collateral, Wad(0)).transact(from_address=auction_income_recipient_address) # Put auction_income_recipient SAFE at max possible debt delta_debt = max_delta_debt(geb, c, auction_income_recipient_address) - Wad(1) if delta_debt > Wad(0): print( f"Attempting to modify safe collateralization with delta_debt={delta_debt}" ) assert geb.safe_engine.modify_safe_collateralization( c.collateral_type, auction_income_recipient_address, Wad(0), delta_debt).transact(from_address=auction_income_recipient_address) # Draw our Dai, simulating the usual behavior safe = geb.safe_engine.safe(c.collateral_type, auction_income_recipient_address) if draw_system_coin and safe.generated_debt > Wad(0): geb.approve_system_coin(auction_income_recipient_address) assert geb.system_coin_adapter.exit( auction_income_recipient_address, safe.generated_debt).transact( from_address=auction_income_recipient_address) print(f"Exited {safe.generated_debt} System coin from safe") logging.debug("Almost risky safe created")