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)
Example #2
0
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
Example #3
0
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)
Example #4
0
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)
Example #5
0
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)
Example #6
0
        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)
Example #7
0
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")