示例#1
0
 def test_divide(self):
     assert Rad.from_number(4) / Rad.from_number(2) == Rad.from_number(2)
     assert Rad(4) / Rad.from_number(2) == Rad(2)
     assert Rad(3) / Rad.from_number(2) == Rad(1)
     assert Rad(39) / Rad.from_number(20) == Rad(1)
     assert Rad(40) / Rad.from_number(20) == Rad(2)
     assert Rad.from_number(0.2) / Rad.from_number(0.1) == Rad.from_number(
         2)
    def test_should_start_a_new_model_and_provide_it_with_info_on_auction_start(
            self, auction_id):
        # given
        (model, model_factory) = models(self.keeper, auction_id)

        # when
        self.keeper.check_all_auctions()
        wait_for_other_threads()
        # then
        model_factory.create_model.assert_called_once_with(
            Parameters(collateral_auction_house=None,
                       surplus_auction_house=None,
                       debt_auction_house=self.debt_auction_house.address,
                       staked_token_auction_house=None,
                       id=auction_id))
        # and
        status = model.send_status.call_args[0][0]
        assert status.id == auction_id
        assert status.collateral_auction_house is None
        assert status.surplus_auction_house is None
        assert status.debt_auction_house == self.debt_auction_house.address
        assert status.bid_amount > Rad.from_number(0)
        assert status.amount_to_sell == self.geb.accounting_engine.initial_debt_auction_minted_tokens(
        )
        assert status.amount_to_raise is None
        assert status.bid_decrease > Wad.from_number(1)
        assert status.high_bidder == self.geb.accounting_engine.address
        assert status.block_time > 0
        assert status.auction_deadline < status.block_time + self.debt_auction_house.total_auction_length(
        ) + 1
        assert status.bid_expiry == 0
        assert status.price == Wad(status.bid_amount *
                                   self.geb.oracle_relayer.redemption_price() /
                                   Rad(status.amount_to_sell))
    def test_should_overbid_itself_if_model_has_updated_the_price(
            self, auction_id):
        # given
        (model, model_factory) = models(self.keeper, auction_id)

        # when
        simulate_model_output(model=model, price=Wad.from_number(100.0))
        # and
        self.keeper.check_all_auctions()
        self.keeper.check_for_bids()
        wait_for_other_threads()
        # then
        assert round(
            Rad(self.debt_auction_house.bids(auction_id).amount_to_sell),
            2) == round(self.debt_auction_bid_size / Rad.from_number(100.0), 2)

        # when
        simulate_model_output(model=model, price=Wad.from_number(110.0))
        self.keeper.check_all_auctions()
        self.keeper.check_for_bids()
        wait_for_other_threads()
        # then
        assert self.amount_to_sell_implies_price(auction_id,
                                                 Wad.from_number(110.0))

        # cleanup
        time_travel_by(self.web3, self.debt_auction_house.bid_duration() + 1)
        assert self.debt_auction_house.settle_auction(auction_id).transact()
    def test_should_restart_auction_if_auction_expired_due_to_total_auction_length(
            self, auction_id):
        # given
        (model, model_factory) = models(self.keeper, auction_id)

        # when
        self.keeper.check_all_auctions()
        wait_for_other_threads()
        # then
        model_factory.create_model.assert_called_once()
        model.terminate.assert_not_called()

        # when
        time_travel_by(self.web3,
                       self.debt_auction_house.total_auction_length() + 1)
        # and
        simulate_model_output(model=model, price=Wad.from_number(555.0))
        # and
        self.keeper.check_all_auctions()
        self.keeper.check_for_bids()
        wait_for_other_threads()
        # then
        model.terminate.assert_not_called()
        auction = self.debt_auction_house.bids(auction_id)
        assert round(
            auction.bid_amount * self.geb.oracle_relayer.redemption_price() /
            Rad(auction.amount_to_sell), 2) == round(Rad.from_number(555.0), 2)

        # cleanup
        time_travel_by(self.web3, self.debt_auction_house.bid_duration() + 1)
        model_factory.create_model.assert_called_once()
        self.keeper.check_all_auctions()
        model.terminate.assert_called_once()
    def test_should_bid_even_if_there_is_already_a_bidder(self, auction_id):
        # given
        (model, model_factory) = models(self.keeper, auction_id)
        prot_before = self.geb.prot.balance_of(self.keeper_address)
        # and
        amount_to_sell = Wad.from_number(0.000016)
        assert self.debt_auction_house.decrease_sold_amount(
            auction_id, amount_to_sell, self.debt_auction_bid_size).transact(
                from_address=self.other_address)
        assert self.debt_auction_house.bids(
            auction_id).amount_to_sell == amount_to_sell

        # when
        simulate_model_output(model=model, price=Wad.from_number(825.0))
        # and
        self.keeper.check_all_auctions()
        self.keeper.check_for_bids()
        wait_for_other_threads()
        # then
        auction = self.debt_auction_house.bids(auction_id)
        assert auction.amount_to_sell != amount_to_sell
        assert round(
            auction.bid_amount * self.geb.oracle_relayer.redemption_price() /
            Rad(auction.amount_to_sell), 2) == round(Rad.from_number(825.0), 2)
        prot_after = self.geb.prot.balance_of(self.keeper_address)
        assert prot_before == prot_after

        # cleanup
        time_travel_by(self.web3, self.debt_auction_house.bid_duration() + 1)
        assert self.debt_auction_house.settle_auction(auction_id).transact()
    def test_should_not_bid_on_rounding_errors_with_small_amounts(
            self, auction_id):
        # given
        (model, model_factory) = models(self.keeper, auction_id)

        # when
        simulate_model_output(model=model, price=Wad.from_number(1400.0))
        # and
        self.keeper.check_all_auctions()
        self.keeper.check_for_bids()
        wait_for_other_threads()
        # then
        assert self.debt_auction_house.bids(auction_id).amount_to_sell == Wad(
            self.debt_auction_bid_size *
            self.geb.oracle_relayer.redemption_price() /
            Rad.from_number(1400.0))

        # when
        tx_count = self.web3.eth.getTransactionCount(
            self.keeper_address.address)
        # and
        self.keeper.check_all_auctions()
        self.keeper.check_for_bids()
        wait_for_other_threads()
        # then
        assert self.web3.eth.getTransactionCount(
            self.keeper_address.address) == tx_count
def auction_id(web3: Web3, geb: GfDeployment, auction_income_recipient_address,
               other_address) -> int:

    total_surplus = geb.safe_engine.coin_balance(geb.accounting_engine.address)
    unqueued_unauctioned_debt = (
        geb.safe_engine.debt_balance(geb.accounting_engine.address) -
        geb.accounting_engine.total_queued_debt()
    ) - geb.accounting_engine.total_on_auction_debt()
    print(
        f'total_surplus={str(total_surplus)[:6]}, unqueued_unauctioned_debt={str(unqueued_unauctioned_debt)[:6]}'
    )

    if unqueued_unauctioned_debt < total_surplus or (
            unqueued_unauctioned_debt == Rad(0) and total_surplus == Rad(0)):
        # Liquidate SAFE
        c = geb.collaterals['ETH-B']
        critical_safe = create_critical_safe(geb,
                                             c,
                                             Wad.from_number(2),
                                             other_address,
                                             draw_system_coin=False)
        collateral_auction_id = liquidate(geb, c, critical_safe)

        # Generate some system coin, bid on and win the collateral auction without covering all the debt
        reserve_system_coin(geb,
                            c,
                            auction_income_recipient_address,
                            Wad.from_number(100),
                            extra_collateral=Wad.from_number(1.1))
        c.collateral_auction_house.approve(
            geb.safe_engine.address,
            approval_function=approve_safe_modification_directly(
                from_address=auction_income_recipient_address))
        current_bid = c.collateral_auction_house.bids(collateral_auction_id)
        bid_amount = Rad.from_number(1.9)
        assert geb.safe_engine.coin_balance(
            auction_income_recipient_address) > bid_amount
        #assert c.collateral_auction_house.increase_bid_size(collateral_auction_id, current_bid.amount_to_sell, bid_amount).transact(from_address=auction_income_recipient_address)
        #time_travel_by(web3, c.collateral_auction_house.bid_duration()+1)
        #assert c.collateral_auction_house.settle_auction(collateral_auction_id).transact()

    pop_debt_and_settle_debt(web3,
                             geb,
                             past_blocks=1200,
                             cancel_auctioned_debt=False)

    # Start the debt auction
    unqueued_unauctioned_debt = (
        geb.safe_engine.debt_balance(geb.accounting_engine.address) -
        geb.accounting_engine.total_queued_debt()
    ) - geb.accounting_engine.total_on_auction_debt()
    assert geb.accounting_engine.debt_auction_bid_size(
    ) <= unqueued_unauctioned_debt
    assert geb.safe_engine.coin_balance(
        geb.accounting_engine.address) == Rad(0)
    assert geb.accounting_engine.auction_debt().transact(
        from_address=auction_income_recipient_address)
    return geb.debt_auction_house.auctions_started()
示例#8
0
 def test_prepare_coins_for_redeeming(self, geb, our_address):
     assert geb.global_settlement.coin_bag(our_address) == Wad(0)
     assert geb.global_settlement.outstanding_coin_supply() > Rad(0)
     assert geb.system_coin.approve(
         geb.global_settlement.address).transact()
     assert geb.safe_engine.coin_balance(our_address) >= Rad.from_number(10)
     # FIXME: `prepareCoinsForRedeeming` fails, possibly because we're passing 0 to `safeEngine.transfer_collateral`
     assert geb.global_settlement.prepare_coins_for_redeeming(
         Wad.from_number(10)).transact()
     assert geb.global_settlement.coin_bag(our_address) == Wad.from_number(
         10)
示例#9
0
 def test_should_cast_to_int(self):
     assert int(Rad.from_number(-4.5)) == -4
     assert int(Rad.from_number(0.99)) == 0
     assert int(Rad.from_number(1)) == 1
     assert int(Rad.from_number(1.0)) == 1
     assert int(Rad.from_number(1.5)) == 1
     assert int(Rad.from_number(1.9999999999)) == 1
示例#10
0
 def test_should_cast_to_float(self):
     assert float(Rad.from_number(-4.5)) == -4.5
     assert float(Rad.from_number(0.99)) == 0.99
     assert float(Rad.from_number(1)) == 1.0
     assert float(Rad.from_number(1.0)) == 1.0
     assert float(Rad.from_number(1.5)) == 1.5
     assert float(Rad.from_number(1.9999999999)) == 1.9999999999
示例#11
0
def pop_debt_and_settle_debt(web3: Web3,
                             geb: GfDeployment,
                             past_blocks=8,
                             cancel_auctioned_debt=True,
                             require_settle_debt=True):
    # Raise debt from the queue (note that accounting_engine.wait is 0 on our testchain)
    liquidations = geb.liquidation_engine.past_liquidations(past_blocks)
    for liquidation in liquidations:
        block_time_liquidation = liquidation.block_time(web3)
        debt_queue = geb.accounting_engine.debt_queue_of(
            block_time_liquidation)
        if debt_queue > Rad(0):
            print(
                f'popping debt era={block_time_liquidation} from block={liquidation.raw["blockNumber"]} '
                f'with debt_queue={str(geb.accounting_engine.debt_queue_of(block_time_liquidation))}'
            )
            assert geb.accounting_engine.pop_debt_from_queue(
                block_time_liquidation).transact()
            assert geb.accounting_engine.debt_queue_of(
                block_time_liquidation) == Rad(0)

    # Ensure there is no on-auction debt which a previous test failed to clean up
    if cancel_auctioned_debt and geb.accounting_engine.total_on_auction_debt(
    ) > Rad.from_number(0):
        assert geb.accounting_engine.cancel_auctioned_debt_with_surplus(
            geb.accounting_engine.total_on_auction_debt()).transact()
        assert geb.accounting_engine.total_on_auction_debt(
        ) == Rad.from_number(0)

    # Cancel out surplus and debt
    total_surplus = geb.safe_engine.coin_balance(geb.accounting_engine.address)
    unqueued_unauctioned_debt = geb.accounting_engine.unqueued_unauctioned_debt(
    )
    if require_settle_debt:
        assert total_surplus <= unqueued_unauctioned_debt
    if total_surplus <= unqueued_unauctioned_debt:
        assert geb.accounting_engine.settle_debt(total_surplus).transact()
示例#12
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)
class MockDebtAuctionHouse:
    bid_amount = Rad.from_number(50000)
    debt_auction_bid_size = Wad.from_number(50000)

    def __init__(self):
        self.total_auction_length = 259200
        self.bid_duration = 21600
        self.amount_to_sell = self.debt_auction_bid_size
        pass

    def bids(self, id: int):
        return DebtAuctionHouse.Bid(
            id=id,
            bid_amount=self.bid_amount,
            amount_to_sell=self.amount_to_sell,
            high_bidder=Address("0x0000000000000000000000000000000000000000"),
            bid_expiry=0,
            auction_deadline=int(datetime.now(tz=timezone.utc).timestamp()) +
            self.total_auction_length)
示例#14
0
    def test_balance_added_after_startup(self, mocker):
        try:
            # given collateral balances after starting keeper
            token_balance_before = self.get_system_coin_token_balance()
            self.create_keeper(mocker)
            time.sleep(6)  # wait for keeper to join everything on startup
            safe_engine_balance_before = self.get_system_coin_safe_engine_balance(
            )
            assert self.get_system_coin_token_balance() == Wad(0)
            assert safe_engine_balance_before == Wad(0)

            # when adding SystemCoin
            purchase_system_coin(Wad.from_number(77), self.keeper_address)
            assert self.get_system_coin_token_balance() == Wad.from_number(77)
            # and pretending there's a bid which requires SystemCoin
            reservoir = Reservoir(
                self.keeper.safe_engine.coin_balance(self.keeper_address))
            assert self.keeper.check_bid_cost(id=1,
                                              cost=Rad.from_number(20),
                                              reservoir=reservoir)

            # then ensure all SystemCoin is joined
            assert self.get_system_coin_token_balance() == Wad(0)
            assert self.get_system_coin_safe_engine_balance(
            ) == Wad.from_number(77)

            # when adding more SystemCoin and pretending there's a bid we cannot cover
            purchase_system_coin(Wad.from_number(23), self.keeper_address)
            assert self.get_system_coin_token_balance() == Wad.from_number(23)
            reservoir = Reservoir(
                self.keeper.safe_engine.coin_balance(self.keeper_address))
            assert not self.keeper.check_bid_cost(
                id=2, cost=Rad(Wad.from_number(120)), reservoir=reservoir)

            # then ensure the added SystemCoin was joined anyway
            assert self.get_system_coin_token_balance() == Wad(0)
            assert self.get_system_coin_safe_engine_balance(
            ) == Wad.from_number(100)

        finally:
            self.shutdown_keeper()
            self.give_away_system_coin()
示例#15
0
    def test_fixed_system_coin_target(self, mocker):
        try:
            # given a keeper configured to maintained a fixed amount of SystemCoin
            target = Wad.from_number(100)
            purchase_system_coin(target * 2, self.keeper_address)
            assert self.get_system_coin_token_balance() == Wad.from_number(200)

            self.create_keeper(mocker, target)
            time.sleep(6)  # wait for keeper to join 100 on startup
            safe_engine_balance_before = self.get_system_coin_safe_engine_balance(
            )
            assert safe_engine_balance_before == target

            # when spending SystemCoin
            assert self.keeper.system_coin_join.exit(
                self.keeper_address, Wad.from_number(22)).transact()
            assert self.get_system_coin_safe_engine_balance(
            ) == Wad.from_number(78)
            # and pretending there's a bid which requires more SystemCoin
            reservoir = Reservoir(
                self.keeper.safe_engine.coin_balance(self.keeper_address))
            assert self.keeper.check_bid_cost(id=3,
                                              cost=Rad.from_number(79),
                                              reservoir=reservoir)

            # then ensure SystemCoin was joined up to the target
            assert self.get_system_coin_safe_engine_balance() == target

            # when pretending there's a bid which we have plenty of SystemCoin to cover
            reservoir = Reservoir(
                self.keeper.safe_engine.coin_balance(self.keeper_address))
            assert self.keeper.check_bid_cost(id=4,
                                              cost=Rad(Wad.from_number(1)),
                                              reservoir=reservoir)

            # then ensure SystemCoin levels haven't changed
            assert self.get_system_coin_safe_engine_balance() == target

        finally:
            self.shutdown_keeper()
    def test_should_make_initial_bid(self):
        # given
        auction_id = self.debt_auction_house.auctions_started()
        (model, model_factory) = models(self.keeper, auction_id)
        prot_before = self.geb.prot.balance_of(self.keeper_address)

        # when
        simulate_model_output(model=model, price=Wad.from_number(575.0))
        # and
        self.keeper.check_all_auctions()
        self.keeper.check_for_bids()
        wait_for_other_threads()
        # then
        auction = self.debt_auction_house.bids(auction_id)
        assert round(
            auction.bid_amount * self.geb.oracle_relayer.redemption_price() /
            Rad(auction.amount_to_sell), 2) == round(Rad.from_number(575.0), 2)
        prot_after = self.geb.prot.balance_of(self.keeper_address)
        assert prot_before == prot_after

        # cleanup
        time_travel_by(self.web3, self.debt_auction_house.bid_duration() + 1)
        assert self.debt_auction_house.settle_auction(auction_id).transact()
示例#17
0
    def test_healthy_safe(self, web3, geb, our_address):
        collateral = geb.collaterals['ETH-B']
        collateral_type = collateral.collateral_type
        TestSAFEEngine.ensure_clean_safe(geb, collateral, our_address)
        initial_system_coin = geb.safe_engine.coin_balance(our_address)
        wrap_eth(geb, our_address, Wad.from_number(90))

        # Ensure our collateral enters the safe
        collateral_balance_before = collateral.collateral.balance_of(
            our_address)
        collateral.approve(our_address)
        assert collateral.adapter.join(our_address,
                                       Wad.from_number(90)).transact()
        assert collateral.collateral.balance_of(
            our_address) == collateral_balance_before - Wad.from_number(90)

        # Add collateral without generating system coin
        wrap_modify_safe_collateralization(
            geb,
            collateral,
            our_address,
            delta_collateral=Wad.from_number(30),
            delta_debt=Wad(0))
        print(
            f"After adding collateral:         {geb.safe_engine.safe(collateral_type, our_address)}"
        )
        assert geb.safe_engine.safe(
            collateral_type,
            our_address).locked_collateral == Wad.from_number(30)
        assert geb.safe_engine.safe(collateral_type,
                                    our_address).generated_debt == Wad(0)
        assert geb.safe_engine.token_collateral(
            collateral_type,
            our_address) == Wad.from_number(90) - geb.safe_engine.safe(
                collateral_type, our_address).locked_collateral
        assert geb.safe_engine.coin_balance(our_address) == initial_system_coin

        # Generate some system coin
        wrap_modify_safe_collateralization(geb,
                                           collateral,
                                           our_address,
                                           delta_collateral=Wad(0),
                                           delta_debt=Wad.from_number(153))
        return
        print(
            f"After generating system_coin:            {geb.safe_engine.safe(collateral_type, our_address)}"
        )
        assert geb.safe_engine.safe(
            collateral_type,
            our_address).locked_collateral == Wad.from_number(30)
        assert geb.safe_engine.safe(
            collateral_type,
            our_address).generated_debt == Wad.from_number(153)
        assert geb.safe_engine.coin_balance(
            our_address) == initial_system_coin + Rad.from_number(153)

        # Add collateral and generate some more system coin
        wrap_modify_safe_collateralization(
            geb,
            collateral,
            our_address,
            delta_collateral=Wad.from_number(60),
            delta_debt=Wad.from_number(180))
        print(
            f"After adding collateral and system_coin: {geb.safe_engine.safe(collateral_type, our_address)}"
        )
        assert geb.safe_engine.safe(
            collateral_type,
            our_address).locked_collateral == Wad.from_number(90)
        assert geb.safe_engine.token_collateral(collateral_type,
                                                our_address) == Wad(0)
        assert geb.safe_engine.safe(
            collateral_type,
            our_address).generated_debt == Wad.from_number(333)
        assert geb.safe_engine.coin_balance(
            our_address) == initial_system_coin + Rad.from_number(333)

        # Mint and withdraw our system coin
        system_coin_balance_before = geb.system_coin.balance_of(our_address)
        geb.approve_system_coin(our_address)
        assert isinstance(geb.system_coin_adapter, CoinJoin)
        assert geb.system_coin_adapter.exit(our_address,
                                            Wad.from_number(333)).transact()
        assert geb.system_coin.balance_of(
            our_address) == system_coin_balance_before + Wad.from_number(333)
        assert geb.safe_engine.coin_balance(our_address) == initial_system_coin
        assert geb.safe_engine.global_debt(
        ) >= initial_system_coin + Rad.from_number(333)

        # Repay (and burn) our system coin
        assert geb.system_coin_adapter.join(our_address,
                                            Wad.from_number(333)).transact()
        assert geb.system_coin.balance_of(our_address) == Wad(0)
        assert geb.safe_engine.coin_balance(
            our_address) == initial_system_coin + Rad.from_number(333)

        # Withdraw our collateral
        wrap_modify_safe_collateralization(geb,
                                           collateral,
                                           our_address,
                                           delta_collateral=Wad(0),
                                           delta_debt=Wad.from_number(-333))
        wrap_modify_safe_collateralization(
            geb,
            collateral,
            our_address,
            delta_collateral=Wad.from_number(-90),
            delta_debt=Wad(0))
        assert geb.safe_engine.token_collateral(
            collateral_type, our_address) == Wad.from_number(90)
        assert collateral.adapter.exit(our_address,
                                       Wad.from_number(90)).transact()
        collateral_balance_after = collateral.collateral.balance_of(
            our_address)
        assert collateral_balance_before == collateral_balance_after

        # Cleanup
        cleanup_safe(geb, collateral, our_address)
示例#18
0
    auction_state = json.loads(auction_input)

    # If we are already the high bidder, do nothing
    if auction_state['high_bidder'] == os.environ['KEEPER_ADDRESS']:
        continue

    # Ensure our custom bid increase is at least the minimum allowed
    MY_BID_DECREASE = max(Wad.from_number(MY_BID_DECREASE), Wad.from_number(auction_state['bid_decrease']))

    # Add slight amount to account for possible redemption price change between the time of model output and bid placement
    MY_BID_DECREASE += Wad.from_number(1e-4)

    # Bid price using `MY_BID_INCREASE`
    my_bid_amount = Wad.from_number(auction_state['amount_to_sell']) / MY_BID_DECREASE
    # Round up from Rad to Wad
    my_bid_price = Wad(Rad.from_number(auction_state['bid_amount']) * redemption_price / Rad(my_bid_amount)) + Wad(1)

    # Bid price using minimum bid increase allowed
    min_bid_amount = Wad.from_number(auction_state['amount_to_sell']) / Wad.from_number(auction_state['bid_decrease'])
    # Round up from Rad to Wad
    min_bid_price = Wad(Rad.from_number(auction_state['bid_amount']) * redemption_price  / Rad(min_bid_amount)) + Wad(1)

    # Try our bid increase first
    # If price is too low, then try minimum bid increase
    if my_bid_price <= Wad.from_number(MAXIMUM_FLX_MULTIPLIER * current_flx_usd_price):
        bid = {'price': str(my_bid_price)}
        print(json.dumps(bid), flush=True)
    elif min_bid_price <= Wad.from_number(MAXIMUM_FLX_MULTIPLIER * current_flx_usd_price):
        bid = {'price': str(min_bid_price)}
        print(json.dumps(bid), flush=True)
def create_collateral_auction(geb: GfDeployment, deployment_address: Address,
                              our_address: Address):
    assert isinstance(geb, GfDeployment)
    assert isinstance(our_address, Address)
    assert isinstance(deployment_address, Address)

    # Create a SAFE
    collateral = geb.collaterals['ETH-A']
    collateral_type = collateral.collateral_type
    wrap_eth(geb, 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)
    wrap_modify_safe_collateralization(geb,
                                       collateral,
                                       deployment_address,
                                       delta_collateral=Wad.from_number(1),
                                       delta_debt=Wad(0))
    delta_debt = max_delta_debt(geb, collateral, deployment_address) - Wad(1)
    wrap_modify_safe_collateralization(geb,
                                       collateral,
                                       deployment_address,
                                       delta_collateral=Wad(0),
                                       delta_debt=delta_debt)

    # Undercollateralize and bite the SAFE
    to_price = Wad(geb.web3.toInt(collateral.osm.read())) / Wad.from_number(2)
    set_collateral_price(geb, collateral, to_price)
    safe = geb.safe_engine.safe(collateral.collateral_type, deployment_address)
    collateral_type = geb.safe_engine.collateral_type(collateral_type.name)
    safe = Ray(safe.generated_debt) * geb.safe_engine.collateral_type(
        collateral_type.name).accumulated_rate <= Ray(
            safe.locked_collateral) * collateral_type.safety_price
    assert not safe
    assert geb.liquidation_engine.can_liquidate(collateral.collateral_type,
                                                SAFE(deployment_address))
    assert geb.liquidation_engine.liquidate_safe(
        collateral.collateral_type, SAFE(deployment_address)).transact()
    auction_id = collateral.collateral_auction_house.auctions_started()

    # Generate some system coin, bid on the collateral auction without covering all the debt
    wrap_eth(geb, 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)
    geb.web3.eth.defaultAccount = our_address.address
    wrap_modify_safe_collateralization(geb,
                                       collateral,
                                       our_address,
                                       delta_collateral=Wad.from_number(10),
                                       delta_debt=Wad.from_number(50))
    collateral.collateral_auction_house.approve(
        geb.safe_engine.address,
        approval_function=approve_safe_modification_directly())
    current_bid = collateral.collateral_auction_house.bids(auction_id)
    safe = geb.safe_engine.safe(collateral.collateral_type, our_address)
    assert Rad(safe.generated_debt) > current_bid.amount_to_raise
    bid_amount = Rad.from_number(6)
    if isinstance(collateral.collateral_auction_house,
                  EnglishCollateralAuctionHouse):
        increase_bid_size(collateral.collateral_auction_house, auction_id,
                          our_address, current_bid.amount_to_sell, bid_amount)
    elif isinstance(collateral.collateral_auction_house,
                    FixedDiscountCollateralAuctionHouse):
        assert collateral.collateral_auction_house.get_collateral_bought(
            auction_id, Wad(bid_amount)).transact(from_address=our_address)
        assert collateral.collateral_auction_house.buy_collateral(
            auction_id, Wad(bid_amount)).transact(from_address=our_address)
示例#20
0
 def test_should_instantiate_from_a_wad(self):
     assert Rad(Wad(10000000000000000000)) == Rad.from_number(10)
示例#21
0
 def test_should_instantiate_from_a_ray(self):
     assert Rad(Ray.from_number(10)) == Rad.from_number(10)
示例#22
0
 def test_multiply(self):
     assert Rad.from_number(2) * Rad.from_number(3) == Rad.from_number(6)
     assert Rad.from_number(2) * Rad(3) == Rad(6)
     assert Rad.from_number(2.5) * Rad(3) == Rad(7)
     assert Rad.from_number(2.99999) * Rad(3) == Rad(8)
示例#23
0
 def test_should_have_nice_printable_representation(self):
     for ray in [Rad(1), Rad(100), Rad.from_number(2.5), Rad(-1)]:
         assert repr(ray) == f"Rad({ray.value})"
示例#24
0
 def test_multiply_by_wad(self):
     assert Rad.from_number(2) * Wad.from_number(3) == Rad.from_number(6)
     assert Rad.from_number(2) * Wad(3) == Rad(6000000000000000000000000000)
     assert Rad(2) * Wad(3) == Rad(0)
     assert Rad(2) * Wad(999999999999999999) == Rad(1)
     assert Rad(2) * Wad(1000000000000000000) == Rad(2)
示例#25
0
 def test_multiply_by_ray(self):
     assert Rad.from_number(2) * Ray.from_number(3) == Rad.from_number(6)
     assert Rad.from_number(2) * Ray(3) == Rad(6000000000000000000)
     assert Rad(2) * Ray(3) == Rad(0)
     assert Rad(2) * Ray(999999999999999999999999999) == Rad(1)
     assert Rad(2) * Ray(1000000000000000000000000000) == Rad(2)
示例#26
0
 def test_multiply_by_int(self):
     assert Rad.from_number(2) * 3 == Rad.from_number(6)
     assert Rad.from_number(2) * 1 == Rad.from_number(2)
    def test_should_provide_model_with_updated_info_after_our_partial_bid(self, auction_id):
        # given
        collateral_auction_house = self.collateral.collateral_auction_house
        if not isinstance(collateral_auction_house, FixedDiscountCollateralAuctionHouse):
            return

        (model, model_factory) = models(self.keeper, auction_id)

        # when
        self.keeper.check_all_auctions()
        wait_for_other_threads()
        initial_status = collateral_auction_house.bids(model.id)
        # then
        assert model.send_status.call_count == 1

        # when bidding less than the full amount
        our_balance = Wad(initial_status.amount_to_raise) / Wad.from_number(2)
        reserve_system_coin(self.geb, self.collateral, self.keeper_address, our_balance)

        assert initial_status.amount_to_raise != Rad(0)
        assert self.geb.safe_engine.coin_balance(self.keeper_address) > Rad(0)

        # Make our balance lte half of the auction size
        half_amount_to_raise = initial_status.amount_to_raise / Rad.from_number(2)
        if self.geb.safe_engine.coin_balance(self.keeper_address) >= half_amount_to_raise:
            burn_amount = self.geb.safe_engine.coin_balance(self.keeper_address) - half_amount_to_raise
            assert burn_amount < self.geb.safe_engine.coin_balance(self.keeper_address)
            self.geb.safe_engine.transfer_internal_coins(self.keeper_address, Address("0x0000000000000000000000000000000000000000"), burn_amount).transact()

        assert self.geb.safe_engine.coin_balance(self.keeper_address) <= half_amount_to_raise
        assert self.geb.safe_engine.coin_balance(self.keeper_address) > Rad(0)

        simulate_model_output(model=model, price=None)
        self.keeper.check_for_bids()

        # and checking auction status and sending auction status to model
        self.keeper.check_all_auctions()
        wait_for_other_threads()
        # and
        self.keeper.check_all_auctions()
        wait_for_other_threads()

        # then
        assert model.send_status.call_count > 1

        # ensure our bid was processed
        current_status = collateral_auction_house.bids(model.id)
        assert current_status.amount_to_raise == initial_status.amount_to_raise
        assert current_status.amount_to_sell == initial_status.amount_to_sell
        assert current_status.auction_deadline == initial_status.auction_deadline
        assert current_status.raised_amount == Rad(our_balance)

        # and the last status sent to our model reflects our bid
        status = model.send_status.call_args[0][0]
        assert status.id == auction_id
        assert status.collateral_auction_house == collateral_auction_house.address
        assert status.surplus_auction_house is None
        assert status.debt_auction_house is None
        assert status.amount_to_sell == initial_status.amount_to_sell
        assert status.amount_to_raise == initial_status.amount_to_raise
        assert status.raised_amount == Rad(our_balance)
        assert status.auction_deadline == initial_status.auction_deadline

        # and auction is still active
        final_status = collateral_auction_house.bids(model.id)
        assert final_status.amount_to_raise == initial_status.amount_to_raise
        assert final_status.amount_to_sell == initial_status.amount_to_sell
        assert final_status.auction_deadline == initial_status.auction_deadline
        assert final_status.raised_amount == Rad(our_balance)

        #cleanup 
        our_balance = Wad(initial_status.amount_to_raise) + Wad(1)
        reserve_system_coin(self.geb, self.collateral, self.keeper_address, our_balance)
        assert self.geb.safe_engine.coin_balance(self.keeper_address) >= initial_status.amount_to_raise
        simulate_model_output(model=model, price=None)
        self.keeper.check_for_bids()
        self.keeper.check_all_auctions()
        wait_for_other_threads()

        # ensure auction has been deleted
        current_status = collateral_auction_house.bids(model.id)
        assert current_status.raised_amount == Rad(0)
        assert current_status.sold_amount == Wad(0)
        assert current_status.amount_to_raise == Rad(0)
        assert current_status.amount_to_sell == Wad(0)
        assert current_status.auction_deadline == 0
        assert current_status.raised_amount == Rad(0)
示例#28
0
    def test_should_replace_pending_transactions_if_model_raises_bid_and_increases_gas_price(self, auction_id):
        # given
        (model, model_factory) = models(self.keeper, auction_id)
        amount_to_sell = self.surplus_auction_house.bids(auction_id).amount_to_sell

        # when
        simulate_model_output(model=model, price=Wad.from_number(9.0), gas_price=10)
        # and
        self.start_ignoring_transactions()
        # and
        self.keeper.check_all_auctions()
        self.keeper.check_for_bids()
        # and
        self.end_ignoring_transactions()
        # and
        simulate_model_output(model=model, price=Wad.from_number(8.0), gas_price=15)
        # and
        self.keeper.check_for_bids()
        wait_for_other_threads()
        # then
        assert round(self.surplus_auction_house.bids(auction_id).bid_amount, 2) == round(Wad(amount_to_sell / Rad.from_number(8.0)), 2)
        assert self.web3.eth.getBlock('latest', full_transactions=True).transactions[0].gasPrice == 15

        # cleanup
        time_travel_by(self.web3, self.surplus_auction_house.bid_duration() + 1)
        assert self.surplus_auction_house.settle_auction(auction_id).transact()
示例#29
0
 def test_round(self):
     assert round(Rad.from_number(123.4567), 2) == Rad.from_number(123.46)
     assert round(Rad.from_number(123.4567), 0) == Rad.from_number(123.0)
     assert round(Rad.from_number(123.4567), -2) == Rad.from_number(100.0)
示例#30
0
    def test_should_provide_model_with_updated_info_after_our_own_bid(self):
        # given
        auction_id = self.surplus_auction_house.auctions_started()
        (model, model_factory) = models(self.keeper, auction_id)

        # when
        self.keeper.check_all_auctions()
        wait_for_other_threads()
        # then
        assert model.send_status.call_count == 1

        # when
        simulate_model_output(model=model, price=Wad.from_number(9))
        # and
        self.keeper.check_all_auctions()
        self.keeper.check_for_bids()
        wait_for_other_threads()
        # and
        self.keeper.check_all_auctions()
        wait_for_other_threads()
        # then
        assert model.send_status.call_count > 1
        # and
        status = model.send_status.call_args[0][0]
        assert status.id == auction_id
        assert status.collateral_auction_house is None
        assert status.surplus_auction_house == self.surplus_auction_house.address
        assert status.debt_auction_house is None
        assert status.bid_amount == Wad(self.surplus_auction_house.bids(auction_id).amount_to_sell * self.geb.oracle_relayer.redemption_price() / Rad.from_number(9))
        assert status.amount_to_sell == self.geb.accounting_engine.surplus_auction_amount_to_sell()
        assert status.amount_to_raise is None
        assert status.bid_increase == self.geb.surplus_auction_house.bid_increase()
        assert status.high_bidder == self.keeper_address
        assert status.block_time > 0
        assert status.auction_deadline > status.block_time
        assert status.bid_expiry > status.block_time
        assert round(status.price, 2) == round(Wad.from_number(9), 2)

        # cleanup
        time_travel_by(self.web3, self.surplus_auction_house.bid_duration() + 1)
        assert self.surplus_auction_house.settle_auction(auction_id).transact()