Пример #1
0
    def test_fixed_dai_target(self, mocker):
        try:
            # given a keeper configured to maintained a fixed amount of Dai
            target = Wad.from_number(100)
            purchase_dai(target * 2, self.keeper_address)
            assert self.get_dai_token_balance() == Wad.from_number(200)

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

            # when spending Dai
            assert self.keeper.dai_join.exit(self.keeper_address, Wad.from_number(22)).transact()
            assert self.get_dai_vat_balance() == Wad.from_number(78)
            # and pretending there's a bid which requires more Dai
            reservoir = Reservoir(self.keeper.vat.dai(self.keeper_address))
            assert self.keeper.check_bid_cost(id=3, cost=Rad.from_number(79), reservoir=reservoir)

            # then ensure Dai was joined up to the target
            assert self.get_dai_vat_balance() == target

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

            # then ensure Dai levels haven't changed
            assert self.get_dai_vat_balance() == target

        finally:
            self.shutdown_keeper()
Пример #2
0
    def test_balance_added_after_startup(self, mocker):
        try:
            # given gem balances after starting keeper
            token_balance_before = self.get_dai_token_balance()
            self.create_keeper(mocker)
            time.sleep(6)  # wait for keeper to join everything on startup
            vat_balance_before = self.get_dai_vat_balance()
            assert self.get_dai_token_balance() == Wad(0)
            assert vat_balance_before == Wad(0)

            # when adding Dai
            purchase_dai(Wad.from_number(77), self.keeper_address)
            assert self.get_dai_token_balance() == Wad.from_number(77)
            # and pretending there's a bid which requires Dai
            reservoir = Reservoir(self.keeper.vat.dai(self.keeper_address))
            assert self.keeper.check_bid_cost(id=1, cost=Rad.from_number(20), reservoir=reservoir)

            # then ensure all Dai is joined
            assert self.get_dai_token_balance() == Wad(0)
            assert self.get_dai_vat_balance() == Wad.from_number(77)

            # when adding more Dai and pretending there's a bid we cannot cover
            purchase_dai(Wad.from_number(23), self.keeper_address)
            assert self.get_dai_token_balance() == Wad.from_number(23)
            reservoir = Reservoir(self.keeper.vat.dai(self.keeper_address))
            assert not self.keeper.check_bid_cost(id=2, cost=Rad(Wad.from_number(120)), reservoir=reservoir)

            # then ensure the added Dai was joined anyway
            assert self.get_dai_token_balance() == Wad(0)
            assert self.get_dai_vat_balance() == Wad.from_number(100)

        finally:
            self.shutdown_keeper()
            self.give_away_dai()
Пример #3
0
    def check_bid_cost(self, id: int, cost: Rad, reservoir: Reservoir, already_rebalanced=False) -> bool:
        assert isinstance(id, int)
        assert isinstance(cost, Rad)

        # If this is an auction where we bid with Dai...
        if self.flipper or self.flopper:
            if not reservoir.check_bid_cost(id, cost):
                if not already_rebalanced:
                    # Try to synchronously join Dai the Vat
                    if self.is_joining_dai:
                        self.logger.info(f"Bid cost {str(cost)} exceeds reservoir level of {reservoir.level}; "
                                          "waiting for Dai to rebalance")
                        return False
                    else:
                        rebalanced = self.rebalance_dai()
                        if rebalanced and rebalanced > Wad(0):
                            reservoir.refill(Rad(rebalanced))
                            return self.check_bid_cost(id, cost, reservoir, already_rebalanced=True)

                self.logger.info(f"Bid cost {str(cost)} exceeds reservoir level of {reservoir.level}; "
                                  "bid will not be submitted")
                return False
        # If this is an auction where we bid with MKR...
        elif self.flapper:
            mkr_balance = self.mkr.balance_of(self.our_address)
            if cost > Rad(mkr_balance):
                self.logger.debug(f"Bid cost {str(cost)} exceeds reservoir level of {reservoir.level}; "
                                  "bid will not be submitted")
                return False
        return True
Пример #4
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()
Пример #5
0
    def check_for_bids(self):
        # Initialize the reservoir with Dai/MKR balance for this round of bid submissions.
        # This isn't a perfect solution as it omits the cost of bids submitted from the last round.
        # Recreating the reservoir preserves the stateless design of this keeper.
        if self.auction_type in ['clip', 'flip', 'flop']:
            reservoir = Reservoir(self.vat.dai(self.our_address))
        elif self.auction_type == 'flap':
            reservoir = Reservoir(Rad(self.mkr.balance_of(self.our_address)))
        else:
            raise RuntimeError("Unsupported auction type")

        with self.auctions_lock:
            for id, auction in self.auctions.auctions.items():
                # If we're exiting, release the lock around checking price models
                if self.is_shutting_down():
                    return

                if not self.auction_handled_by_this_shard(id):
                    continue
                self.handle_bid(id=id, auction=auction, reservoir=reservoir)