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()
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()
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
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()
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)