예제 #1
0
def mint_mkr(mkr: DSToken, recipient_address: Address, amount: Wad):
    assert isinstance(mkr, DSToken)
    assert isinstance(recipient_address, Address)
    assert isinstance(amount, Wad)
    assert amount > Wad(0)

    deployment_address = Address("0x00a329c0648769A73afAc7F9381E08FB43dBEA72")
    assert mkr.mint(amount).transact(from_address=deployment_address)
    assert mkr.balance_of(deployment_address) > Wad(0)
    assert mkr.approve(recipient_address).transact(from_address=deployment_address)
    assert mkr.transfer(recipient_address, amount).transact(from_address=deployment_address)
예제 #2
0
파일: test_dss.py 프로젝트: pcatana/keeper
def mint_mkr(mkr: DSToken, deployment_address: Address,
             recipient_address: Address, amount: Wad):
    assert isinstance(mkr, DSToken)
    assert isinstance(deployment_address, Address)
    assert isinstance(recipient_address, Address)
    assert isinstance(amount, Wad)
    assert amount > Wad(0)

    assert mkr.mint(amount).transact(from_address=deployment_address)
    assert mkr.balance_of(deployment_address) > Wad(0)
    assert mkr.approve(recipient_address).transact(
        from_address=deployment_address)
    assert mkr.transfer(recipient_address,
                        amount).transact(from_address=deployment_address)
예제 #3
0
class TestAuctionKeeperFlipper(TransactionIgnoringTest):
    def setup_method(self):
        self.web3 = Web3(HTTPProvider("http://localhost:8555"))
        self.web3.eth.defaultAccount = self.web3.eth.accounts[0]
        self.keeper_address = Address(self.web3.eth.defaultAccount)
        self.gal_address = Address(self.web3.eth.accounts[1])
        self.other_address = Address(self.web3.eth.accounts[2])

        # GemMock version of DSToken with push(bytes32, uint function) an hope(address)
        gem_abi = Contract._load_abi(__name__,
                                     '../lib/pymaker/tests/abi/GemMock.abi')
        gem_bin = Contract._load_bin(__name__,
                                     '../lib/pymaker/tests/abi/GemMock.bin')

        self.gem_addr = Contract._deploy(self.web3, gem_abi, gem_bin, [b'ABC'])
        self.gem = DSToken(web3=self.web3, address=self.gem_addr)

        self.dai_addr = Contract._deploy(self.web3, gem_abi, gem_bin, [b'DAI'])
        self.dai = DSToken(web3=self.web3, address=self.dai_addr)

        self.flipper = Flipper.deploy(self.web3, self.dai.address,
                                      self.gem.address)

        # Set allowance to allow flipper to move dai and gem
        self.dai.approve(self.flipper.address).transact()
        self.dai.approve(
            self.flipper.address).transact(from_address=self.gal_address)
        self.dai.approve(
            self.flipper.address).transact(from_address=self.other_address)
        self.gem.approve(
            self.flipper.address).transact(from_address=self.gal_address)
        self.gem.approve(
            self.flipper.address).transact(from_address=self.other_address)

        self.keeper = AuctionKeeper(args=args(
            f"--eth-from {self.keeper_address} "
            f"--flipper {self.flipper.address} "
            f"--model ./bogus-model.sh"),
                                    web3=self.web3)

        self.keeper.approve()

        # So that `keeper_address` and `other_address` can bid in auctions,
        # they both need to have DAI in their accounts.
        self.dai.mint(Wad.from_number(20000000)).transact()
        self.dai.transfer(self.other_address,
                          Wad.from_number(10000000)).transact()

        # So that `gal_address` can kick auction he need to have GEM in his accounts
        self.gem.mint(Wad.from_number(1000000)).transact()
        self.gem.transfer(self.gal_address,
                          Wad.from_number(1000000)).transact()

        self.model = MagicMock()
        self.model.get_stance = MagicMock(return_value=None)
        self.model_factory = self.keeper.auctions.model_factory
        self.model_factory.create_model = MagicMock(return_value=self.model)

    def gem_balance(self, address: Address) -> Wad:
        assert (isinstance(address, Address))
        return Wad(self.gem.balance_of(address))

    def simulate_model_output(self,
                              price: Wad,
                              gas_price: Optional[int] = None):
        self.model.get_stance = MagicMock(
            return_value=Stance(price=price, gas_price=gas_price))

    def models(self, keeper):
        model = MagicMock()
        model.get_stance = MagicMock(return_value=None)
        model_factory = keeper.auctions.model_factory
        model_factory.create_model = MagicMock(return_value=model)

        return (model, model_factory)

    def test_should_start_a_new_model_and_provide_it_with_info_on_auction_kick(
            self, bid_id, d, keeper, c):
        # given
        (model, model_factory) = self.models(keeper)

        # when
        keeper.check_all_auctions()
        wait_for_other_threads()
        # then
        model_factory.create_model.assert_called_once_with(
            Parameters(flipper=c.flipper.address,
                       flapper=None,
                       flopper=None,
                       id=bid_id))
        # and
        assert model.send_status.call_args[0][0].id == bid_id
        assert model.send_status.call_args[0][0].flipper == c.flipper.address
        assert model.send_status.call_args[0][0].flapper is None
        assert model.send_status.call_args[0][0].flopper is None
        assert model.send_status.call_args[0][0].bid == Wad.from_number(0)
        assert model.send_status.call_args[0][0].lot == Wad(684931506849315068)
        assert model.send_status.call_args[0][0].tab == Wad.from_number(100)
        assert model.send_status.call_args[0][0].beg == Ray.from_number(1.05)
        assert model.send_status.call_args[0][0].guy == d.cat.address
        assert model.send_status.call_args[0][0].era > 0
        assert model.send_status.call_args[
            0][0].end < model.send_status.call_args[0][0].era + c.flipper.tau(
            ) + 1
        assert model.send_status.call_args[0][0].tic == 0
        assert model.send_status.call_args[0][0].price == Wad(0)

    def test_should_provide_model_with_updated_info_after_our_own_bid(self):
        # given
        self.flipper.kick(self.gal_address, self.gal_address, Wad.from_number(5000), Wad.from_number(100),
                          Wad.from_number(1000)) \
            .transact(from_address=self.gal_address)

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

        # when
        self.simulate_model_output(price=Wad.from_number(15.0))
        # and
        self.keeper.check_all_auctions()
        wait_for_other_threads()
        # and
        self.keeper.check_all_auctions()
        wait_for_other_threads()
        # then
        assert self.model.send_status.call_count > 1
        # and
        assert self.model.send_status.call_args[0][0].id == 1
        assert self.model.send_status.call_args[0][
            0].flipper == self.flipper.address
        assert self.model.send_status.call_args[0][0].flapper is None
        assert self.model.send_status.call_args[0][0].flopper is None
        assert self.model.send_status.call_args[0][0].bid == Wad.from_number(
            1500)
        assert self.model.send_status.call_args[0][0].lot == Wad.from_number(
            100)
        assert self.model.send_status.call_args[0][0].tab == Wad.from_number(
            5000)
        assert self.model.send_status.call_args[0][0].beg == Ray.from_number(
            1.05)
        assert self.model.send_status.call_args[0][
            0].guy == self.keeper_address
        assert self.model.send_status.call_args[0][0].era > 0
        assert self.model.send_status.call_args[0][
            0].end > self.model.send_status.call_args[0][0].era + 3600
        assert self.model.send_status.call_args[0][
            0].tic > self.model.send_status.call_args[0][0].era + 3600
        assert self.model.send_status.call_args[0][0].price == Wad.from_number(
            15.0)

    def test_should_provide_model_with_updated_info_after_somebody_else_bids(
            self):
        # given
        self.flipper.kick(self.gal_address, self.gal_address, Wad.from_number(5000), Wad.from_number(100),
                          Wad.from_number(1000)) \
            .transact(from_address=self.gal_address)

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

        # when
        self.flipper.tend(
            1, Wad.from_number(100),
            Wad.from_number(1700)).transact(from_address=self.other_address)
        # and
        self.keeper.check_all_auctions()
        wait_for_other_threads()
        # then
        assert self.model.send_status.call_count > 1
        # and
        assert self.model.send_status.call_args[0][0].id == 1
        assert self.model.send_status.call_args[0][
            0].flipper == self.flipper.address
        assert self.model.send_status.call_args[0][0].flapper is None
        assert self.model.send_status.call_args[0][0].flopper is None
        assert self.model.send_status.call_args[0][0].bid == Wad.from_number(
            1700)
        assert self.model.send_status.call_args[0][0].lot == Wad.from_number(
            100)
        assert self.model.send_status.call_args[0][0].tab == Wad.from_number(
            5000)
        assert self.model.send_status.call_args[0][0].beg == Ray.from_number(
            1.05)
        assert self.model.send_status.call_args[0][0].guy == self.other_address
        assert self.model.send_status.call_args[0][0].era > 0
        assert self.model.send_status.call_args[0][
            0].end > self.model.send_status.call_args[0][0].era + 3600
        assert self.model.send_status.call_args[0][
            0].tic > self.model.send_status.call_args[0][0].era + 3600
        assert self.model.send_status.call_args[0][0].price == Wad.from_number(
            17.0)

    def test_should_terminate_model_if_auction_expired_due_to_tau(self):
        # given
        self.flipper.kick(self.gal_address, self.gal_address, Wad.from_number(5000), Wad.from_number(100),
                          Wad.from_number(1000)) \
            .transact(from_address=self.gal_address)

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

        # when
        time_travel_by(self.web3, self.flipper.tau() + 5)
        # and
        self.keeper.check_all_auctions()
        wait_for_other_threads()
        # then
        self.model_factory.create_model.assert_called_once()
        self.model.terminate.assert_called_once()

    def test_should_terminate_model_if_auction_expired_due_to_ttl_and_somebody_else_won_it(
            self):
        # given
        self.flipper.kick(self.gal_address, self.gal_address, Wad.from_number(5000), Wad.from_number(100),
                          Wad.from_number(1000)) \
            .transact(from_address=self.gal_address)

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

        # when
        self.flipper.tend(
            1, Wad.from_number(100),
            Wad.from_number(1600)).transact(from_address=self.other_address)
        # and
        time_travel_by(self.web3, self.flipper.ttl() + 5)
        # and
        self.keeper.check_all_auctions()
        wait_for_other_threads()
        # then
        self.model_factory.create_model.assert_called_once()
        self.model.terminate.assert_called_once()

    def test_should_terminate_model_if_auction_is_dealt(self):
        # given
        self.flipper.kick(self.gal_address, self.gal_address, Wad.from_number(5000), Wad.from_number(100),
                          Wad.from_number(1000)) \
            .transact(from_address=self.gal_address)

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

        # when
        self.flipper.tend(
            1, Wad.from_number(100),
            Wad.from_number(1600)).transact(from_address=self.other_address)
        # and
        time_travel_by(self.web3, self.flipper.ttl() + 5)
        # and
        self.flipper.deal(1).transact(from_address=self.other_address)
        # and
        self.keeper.check_all_auctions()
        wait_for_other_threads()
        # then
        self.model_factory.create_model.assert_called_once()
        self.model.terminate.assert_called_once()

    def test_should_not_instantiate_model_if_auction_is_dealt(self):
        # given
        self.flipper.kick(self.gal_address, self.gal_address, Wad.from_number(5000), Wad.from_number(100),
                          Wad.from_number(1000)) \
            .transact(from_address=self.gal_address)
        # and
        self.flipper.tend(
            1, Wad.from_number(100),
            Wad.from_number(1600)).transact(from_address=self.other_address)
        # and
        time_travel_by(self.web3, self.flipper.ttl() + 5)
        # and
        self.flipper.deal(1).transact(from_address=self.other_address)

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

    def test_should_not_do_anything_if_no_output_from_model(self):
        # given
        self.flipper.kick(self.gal_address, self.gal_address, Wad.from_number(5000), Wad.from_number(100),
                          Wad.from_number(1000)) \
            .transact(from_address=self.gal_address)

        previous_block_number = self.web3.eth.blockNumber

        # when
        # [no output from model]
        # and
        self.keeper.check_all_auctions()
        wait_for_other_threads()
        # then
        assert self.web3.eth.blockNumber == previous_block_number

    def test_should_make_initial_bid(self):
        # given
        self.flipper.kick(self.gal_address, self.gal_address, Wad.from_number(5000), Wad.from_number(100),
                          Wad.from_number(1000)) \
            .transact(from_address=self.gal_address)

        # when
        self.simulate_model_output(price=Wad.from_number(16.0))
        # and
        self.keeper.check_all_auctions()
        wait_for_other_threads()
        # then
        auction = self.flipper.bids(1)
        assert round(auction.bid / auction.lot,
                     2) == round(Wad.from_number(16.0), 2)

    def test_should_bid_even_if_there_is_already_a_bidder(self):
        # given
        self.flipper.kick(self.gal_address, self.gal_address, Wad.from_number(5000), Wad.from_number(100),
                          Wad.from_number(1000)) \
            .transact(from_address=self.gal_address)
        # and
        self.flipper.tend(
            1, Wad.from_number(100),
            Wad.from_number(1600)).transact(from_address=self.other_address)
        assert self.flipper.bids(1).bid == Wad.from_number(1600)

        # when
        self.simulate_model_output(price=Wad.from_number(19.0))
        # and
        self.keeper.check_all_auctions()
        wait_for_other_threads()
        # then
        auction = self.flipper.bids(1)
        assert self.flipper.bids(1).bid == Wad.from_number(1900)
        assert round(auction.bid / auction.lot,
                     2) == round(Wad.from_number(19.0), 2)

    def test_should_sequentially_tend_and_dent_if_price_takes_us_to_the_dent_phrase(
            self):
        # given
        self.flipper.kick(self.gal_address, self.gal_address, Wad.from_number(5000), Wad.from_number(100),
                          Wad.from_number(1000)) \
            .transact(from_address=self.gal_address)

        # when
        self.simulate_model_output(price=Wad.from_number(80.0))
        # and
        self.keeper.check_all_auctions()
        wait_for_other_threads()
        # then
        auction = self.flipper.bids(1)
        assert self.flipper.bids(1).bid == Wad.from_number(5000)
        assert self.flipper.bids(1).lot == Wad.from_number(100)
        assert round(auction.bid / auction.lot,
                     2) == round(Wad.from_number(50.0), 2)

        # when
        self.keeper.check_all_auctions()
        wait_for_other_threads()
        # then
        auction = self.flipper.bids(1)
        assert self.flipper.bids(1).bid == Wad.from_number(5000)
        assert self.flipper.bids(1).lot == Wad.from_number(62.5)
        assert round(auction.bid / auction.lot,
                     2) == round(Wad.from_number(80.0), 2)

    def test_should_use_most_up_to_date_price_for_dent_even_if_it_gets_updated_during_tend(
            self):
        # given
        self.flipper.kick(self.gal_address, self.gal_address, Wad.from_number(5000), Wad.from_number(100),
                          Wad.from_number(1000)) \
            .transact(from_address=self.gal_address)

        # when
        self.simulate_model_output(price=Wad.from_number(80.0))
        # and
        self.keeper.check_all_auctions()
        wait_for_other_threads()
        # then
        auction = self.flipper.bids(1)
        assert self.flipper.bids(1).bid == Wad.from_number(5000)
        assert self.flipper.bids(1).lot == Wad.from_number(100)
        assert round(auction.bid / auction.lot,
                     2) == round(Wad.from_number(50.0), 2)

        # when
        self.simulate_model_output(price=Wad.from_number(100.0))
        # and
        self.keeper.check_all_auctions()
        wait_for_other_threads()
        # then
        auction = self.flipper.bids(1)
        assert self.flipper.bids(1).bid == Wad.from_number(5000)
        assert self.flipper.bids(1).lot == Wad.from_number(50.0)
        assert round(auction.bid / auction.lot,
                     2) == round(Wad.from_number(100.0), 2)

    def test_should_only_tend_if_bid_is_only_slightly_above_tab(self):
        # given
        self.flipper.kick(self.gal_address, self.gal_address, Wad.from_number(5000), Wad.from_number(100),
                          Wad.from_number(1000)) \
            .transact(from_address=self.gal_address)

        # when
        self.simulate_model_output(price=Wad.from_number(50.1))
        # and
        self.keeper.check_all_auctions()
        wait_for_other_threads()
        # then
        auction = self.flipper.bids(1)
        assert self.flipper.bids(1).bid == Wad.from_number(5000)
        assert self.flipper.bids(1).lot == Wad.from_number(100)
        assert round(auction.bid / auction.lot,
                     2) == round(Wad.from_number(50.0), 2)

        # when
        self.keeper.check_all_auctions()
        wait_for_other_threads()
        # then
        auction = self.flipper.bids(1)
        assert self.flipper.bids(1).bid == Wad.from_number(5000)
        assert self.flipper.bids(1).lot == Wad.from_number(100)
        assert round(auction.bid / auction.lot,
                     2) == round(Wad.from_number(50.0), 2)

    def test_should_tend_up_to_exactly_tab_if_bid_is_only_slightly_below_tab(
            self):
        # given
        self.flipper.kick(self.gal_address, self.gal_address, Wad.from_number(5000), Wad.from_number(100),
                          Wad.from_number(1000)) \
            .transact(from_address=self.gal_address)

        # when
        self.simulate_model_output(price=Wad.from_number(49.99))
        # and
        self.keeper.check_all_auctions()
        wait_for_other_threads()
        # then
        auction = self.flipper.bids(1)
        assert self.flipper.bids(1).bid == Wad.from_number(4999)
        assert self.flipper.bids(1).lot == Wad.from_number(100)
        assert round(auction.bid / auction.lot,
                     2) == round(Wad.from_number(49.99), 2)

        # when
        self.simulate_model_output(price=Wad.from_number(50.0))
        # and
        self.keeper.check_all_auctions()
        wait_for_other_threads()
        # then
        auction = self.flipper.bids(1)
        assert self.flipper.bids(1).bid == Wad.from_number(5000)
        assert self.flipper.bids(1).lot == Wad.from_number(100)
        assert round(auction.bid / auction.lot,
                     2) == round(Wad.from_number(50.0), 2)

    def test_should_overbid_itself_if_model_has_updated_the_price(self):
        # given
        self.flipper.kick(self.gal_address, self.gal_address, Wad.from_number(5000), Wad.from_number(100),
                          Wad.from_number(1000)) \
            .transact(from_address=self.gal_address)

        # when
        self.simulate_model_output(price=Wad.from_number(15.0))
        # and
        self.keeper.check_all_auctions()
        wait_for_other_threads()
        # then
        assert self.flipper.bids(1).bid == Wad.from_number(1500.0)

        # when
        self.simulate_model_output(price=Wad.from_number(20.0))
        self.keeper.check_all_auctions()
        wait_for_other_threads()
        # then
        assert self.flipper.bids(1).bid == Wad.from_number(2000.0)

    def test_should_increase_gas_price_of_pending_transactions_if_model_increases_gas_price(
            self):
        # given
        self.flipper.kick(self.gal_address, self.gal_address, Wad.from_number(5000), Wad.from_number(100),
                          Wad.from_number(1000)) \
            .transact(from_address=self.gal_address)

        # when
        self.simulate_model_output(price=Wad.from_number(20.0), gas_price=10)
        # and
        self.start_ignoring_transactions()
        # and
        self.keeper.check_all_auctions()
        # and
        time.sleep(5)
        # and
        self.end_ignoring_transactions()
        # and
        self.simulate_model_output(price=Wad.from_number(20.0), gas_price=15)
        # and
        self.keeper.check_all_auctions()
        wait_for_other_threads()
        # then
        assert self.flipper.bids(1).bid == Wad.from_number(2000.0)
        assert self.web3.eth.getBlock(
            'latest', full_transactions=True).transactions[0].gasPrice == 15

    def test_should_replace_pending_transactions_if_model_raises_bid_and_increases_gas_price(
            self):
        # given
        self.flipper.kick(self.gal_address, self.gal_address, Wad.from_number(5000), Wad.from_number(100),
                          Wad.from_number(1000)) \
            .transact(from_address=self.gal_address)

        # when
        self.simulate_model_output(price=Wad.from_number(15.0), gas_price=10)
        # and
        self.start_ignoring_transactions()
        # and
        self.keeper.check_all_auctions()
        # and
        time.sleep(5)
        # and
        self.end_ignoring_transactions()
        # and
        self.simulate_model_output(price=Wad.from_number(20.0), gas_price=15)
        # and
        self.keeper.check_all_auctions()
        wait_for_other_threads()
        # then
        assert self.flipper.bids(1).bid == Wad.from_number(2000.0)
        assert self.web3.eth.getBlock(
            'latest', full_transactions=True).transactions[0].gasPrice == 15

    def test_should_replace_pending_transactions_if_model_lowers_bid_and_increases_gas_price(
            self):
        # given
        self.flipper.kick(self.gal_address, self.gal_address, Wad.from_number(5000), Wad.from_number(100),
                          Wad.from_number(1000)) \
            .transact(from_address=self.gal_address)

        # when
        self.simulate_model_output(price=Wad.from_number(20.0), gas_price=10)
        # and
        self.start_ignoring_transactions()
        # and
        self.keeper.check_all_auctions()
        # and
        time.sleep(5)
        # and
        self.end_ignoring_transactions()
        # and
        self.simulate_model_output(price=Wad.from_number(15.0), gas_price=15)
        # and
        self.keeper.check_all_auctions()
        wait_for_other_threads()
        # then
        assert self.flipper.bids(1).bid == Wad.from_number(1500.0)
        assert self.web3.eth.getBlock(
            'latest', full_transactions=True).transactions[0].gasPrice == 15

    def test_should_not_tend_on_rounding_errors_with_small_amounts(self):
        # given
        self.flipper.kick(self.gal_address, self.gal_address, Wad(5000), Wad(2), Wad(4)) \
            .transact(from_address=self.gal_address)

        # when
        self.simulate_model_output(price=Wad.from_number(3.0))
        # and
        self.keeper.check_all_auctions()
        wait_for_other_threads()
        # then
        assert self.flipper.bids(1).bid == Wad(6)

        # when
        tx_count = self.web3.eth.getTransactionCount(
            self.keeper_address.address)
        # and
        self.keeper.check_all_auctions()
        wait_for_other_threads()
        # then
        assert self.web3.eth.getTransactionCount(
            self.keeper_address.address) == tx_count

    def test_should_not_dent_on_rounding_errors_with_small_amounts(self):
        # given
        self.flipper.kick(self.gal_address, self.gal_address, Wad(5000), Wad(10), Wad(5000)) \
            .transact(from_address=self.gal_address)

        # when
        self.simulate_model_output(price=Wad.from_number(1000.0))
        # and
        self.keeper.check_all_auctions()
        wait_for_other_threads()
        # then
        assert self.flipper.bids(1).lot == Wad(5)

        # when
        tx_count = self.web3.eth.getTransactionCount(
            self.keeper_address.address)
        # and
        self.keeper.check_all_auctions()
        wait_for_other_threads()
        # then
        assert self.web3.eth.getTransactionCount(
            self.keeper_address.address) == tx_count

    def test_should_deal_when_we_won_the_auction(self):
        # given
        self.flipper.kick(self.gal_address, self.gal_address, Wad.from_number(5000), Wad.from_number(100),
                          Wad.from_number(1000)) \
            .transact(from_address=self.gal_address)

        # when
        self.simulate_model_output(price=Wad.from_number(15.0))
        # and
        self.keeper.check_all_auctions()
        wait_for_other_threads()
        # then
        auction = self.flipper.bids(1)
        assert round(auction.bid / auction.lot,
                     2) == round(Wad.from_number(15.0), 2)
        assert self.gem_balance(self.keeper_address) == Wad(0)

        # when
        time_travel_by(self.web3, self.flipper.ttl() + 5)
        # and
        self.keeper.check_all_auctions()
        wait_for_other_threads()
        # then
        assert self.gem_balance(self.keeper_address) > Wad(0)

    def test_should_not_deal_when_auction_finished_but_somebody_else_won(self):
        # given
        self.flipper.kick(self.gal_address, self.gal_address, Wad.from_number(5000), Wad.from_number(100),
                          Wad.from_number(1000)) \
            .transact(from_address=self.gal_address)
        # and
        self.flipper.tend(
            1, Wad.from_number(100),
            Wad.from_number(1500)).transact(from_address=self.other_address)
        assert self.flipper.bids(1).bid == Wad.from_number(1500)

        # when
        time_travel_by(self.web3, self.flipper.ttl() + 5)
        # and
        self.keeper.check_all_auctions()
        wait_for_other_threads()
        # then
        assert self.gem_balance(self.other_address) == Wad(0)

    def test_should_obey_gas_price_provided_by_the_model(self):
        # given
        self.flipper.kick(self.gal_address, self.gal_address, Wad.from_number(5000), Wad.from_number(100),
                          Wad.from_number(1000)) \
            .transact(from_address=self.gal_address)

        # when
        self.simulate_model_output(price=Wad.from_number(15.0),
                                   gas_price=175000)
        # and
        self.keeper.check_all_auctions()
        wait_for_other_threads()
        # then
        assert self.web3.eth.getBlock(
            'latest',
            full_transactions=True).transactions[0].gasPrice == 175000

    def test_should_use_default_gas_price_if_not_provided_by_the_model(self):
        # given
        self.flipper.kick(self.gal_address, self.gal_address, Wad.from_number(5000), Wad.from_number(100),
                          Wad.from_number(1000)) \
            .transact(from_address=self.gal_address)

        # when
        self.simulate_model_output(price=Wad.from_number(15.0))
        # and
        self.keeper.check_all_auctions()
        wait_for_other_threads()
        # then
        assert self.web3.eth.getBlock(
            'latest', full_transactions=True
        ).transactions[0].gasPrice == self.web3.eth.gasPrice
예제 #4
0
class TestFlipper:
    def setup_method(self):
        self.web3 = Web3(HTTPProvider("http://localhost:8555"))
        self.web3.eth.defaultAccount = self.web3.eth.accounts[0]
        self.our_address = Address(self.web3.eth.defaultAccount)
        self.other_address_1 = Address(self.web3.eth.accounts[1])
        self.other_address_2 = Address(self.web3.eth.accounts[2])

        self.dai = DSToken.deploy(self.web3, 'DAI')

        # we need a GemLike version of DSToken with push(bytes32, uint function)
        self.gem_addr = Contract._deploy(self.web3, Contract._load_abi(__name__, 'abi/GemMock.abi'), Contract._load_bin(__name__, 'abi/GemMock.bin'), [b'ABC'])
        self.gem = DSToken(web3=self.web3, address=self.gem_addr)

        self.flipper = Flipper.deploy(self.web3, self.dai.address, self.gem.address)

        # Set allowance to allow flipper to move dai and gem
        # With full deployment kick is only done by Cat via flip() which take care of allowance via gem.hope()
        self.gem.approve(self.flipper.address).transact()
        self.gem.approve(self.flipper.address).transact(from_address=self.other_address_1)
        self.dai.approve(self.flipper.address).transact()

    def dai_balance(self, address: Address) -> Wad:
        assert(isinstance(address, Address))
        return self.dai.balance_of(address)

    def dai_mint(self, amount: Wad):
        assert(isinstance(amount, Wad))
        assert self.dai.mint(amount).transact()

    def gem_balance(self, address: Address) -> Wad:
        assert(isinstance(address, Address))
        return self.gem.balance_of(address)

    def test_beg(self):
        assert self.flipper.beg() == Ray.from_number(1.05)

    def test_ttl(self):
        assert self.flipper.ttl() == 3*60*60  # 3 hours

    def test_tau(self):
        assert self.flipper.tau() == 2*24*60*60  # 2 days

    def test_read(self):
        # given
        assert self.gem.mint(Wad.from_number(100)).transact()
        assert self.gem_balance(self.our_address) == Wad.from_number(100)

        # when
        assert self.flipper.kick(urn=self.other_address_1,
                                 gal=self.other_address_2,
                                 tab=Wad.from_number(5000),
                                 lot=Wad.from_number(100),
                                 bid=Wad.from_number(100)).transact()

        # then
        assert self.flipper.kicks() == 1
        # and
        auction = self.flipper.bids(1)
        assert auction.lad == self.other_address_1
        assert auction.gal == self.other_address_2
        assert auction.bid == Wad.from_number(100)
        assert auction.lot == Wad.from_number(100)
        assert auction.tab == Wad.from_number(5000)
        assert auction.guy == self.our_address
        assert auction.tic == 0
        assert auction.end > 0

    def test_scenario(self):
        # given
        self.dai_mint(Wad.from_number(100000))
        assert self.gem.mint(Wad.from_number(100)).transact()
        assert self.gem.transfer(self.other_address_1, Wad.from_number(100)).transact()
        assert self.dai_balance(self.our_address) == Wad.from_number(100000)

        # when
        self.flipper.kick(urn=self.other_address_1,
                          gal=self.other_address_1,
                          tab=Wad.from_number(5000),
                          lot=Wad.from_number(100),
                          bid=Wad.from_number(1000)).transact(from_address=self.other_address_1)
        # then
        assert self.dai_balance(self.our_address) == Wad.from_number(100000)
        assert self.dai_balance(self.other_address_1) == Wad.from_number(0)
        assert self.gem_balance(self.our_address) == Wad.from_number(0)
        assert self.gem_balance(self.other_address_1) == Wad.from_number(0)

        # when
        self.flipper.tend(1, Wad.from_number(100), Wad.from_number(2000)).transact()
        assert self.dai_balance(self.our_address) == Wad.from_number(100000) - Wad.from_number(2000)
        assert self.dai_balance(self.other_address_1) == Wad.from_number(2000)
        assert self.gem_balance(self.our_address) == Wad.from_number(0)
        assert self.gem_balance(self.other_address_1) == Wad.from_number(0)

        # when
        self.flipper.tend(1, Wad.from_number(100), Wad.from_number(5000)).transact()
        assert self.dai_balance(self.our_address) == Wad.from_number(100000) - Wad.from_number(5000)
        assert self.dai_balance(self.other_address_1) == Wad.from_number(5000)
        assert self.gem_balance(self.our_address) == Wad.from_number(0)
        assert self.gem_balance(self.other_address_1) == Wad.from_number(0)

        # when
        self.flipper.dent(1, Wad.from_number(80), Wad.from_number(5000)).transact()
        assert self.dai_balance(self.our_address) == Wad.from_number(100000) - Wad.from_number(5000)
        assert self.dai_balance(self.other_address_1) == Wad.from_number(5000)
        assert self.gem_balance(self.our_address) == Wad.from_number(0)
        assert self.gem_balance(self.other_address_1) == Wad.from_number(20)

        time_travel_by(self.web3, 60*60*24*8)

        # when
        self.flipper.deal(1).transact()
        assert self.dai_balance(self.our_address) == Wad.from_number(100000) - Wad.from_number(5000)
        assert self.dai_balance(self.other_address_1) == Wad.from_number(5000)
        assert self.gem_balance(self.our_address) == Wad.from_number(80)
        assert self.gem_balance(self.other_address_1) == Wad.from_number(20)