Example #1
0
    def test_should_cancel_the_only_buy_order_and_place_a_new_one_if_above_max(
            self, deployment: Deployment, tmpdir: py.path.local):
        # given
        config_file = BandConfig.sample_config(tmpdir)

        # and
        keeper = EtherDeltaMarketMakerKeeper(args=args(
            f"--eth-from {deployment.our_address} --config {config_file}"
            f" --tub-address {deployment.tub.address}"
            f" --etherdelta-address {deployment.etherdelta.address}"
            f" --etherdelta-socket https://127.0.0.1:99999/"
            f" --order-age 3600 --eth-reserve 10"
            f" --min-eth-deposit 1 --min-sai-deposit 400"),
                                             web3=deployment.web3)
        keeper.lifecycle = Web3Lifecycle(web3=keeper.web3)
        keeper.etherdelta_api.publish_order = MagicMock()

        # and
        self.mint_tokens(deployment)
        self.set_price(deployment, Wad.from_number(100))

        # and
        keeper.approve()

        # and
        # [one artificially created order above the max band threshold]
        keeper.our_orders.append(
            deployment.etherdelta.create_order(deployment.sai.address,
                                               Wad.from_number(170),
                                               EtherDelta.ETH_TOKEN,
                                               Wad.from_number(1.770805),
                                               1000000))

        # when
        keeper.synchronize_orders(
        )  # ... first call is so it can made deposits
        keeper.synchronize_orders(
        )  # ... second call is so the actual orders can get placed

        # then
        # [the artificial order gets cancelled, a new one gets created instead]
        assert len(self.orders(keeper)) == 2
        assert self.orders_by_token(
            keeper, deployment.sai.address)[0].maker == deployment.our_address
        assert self.orders_by_token(
            keeper,
            deployment.sai.address)[0].pay_amount == Wad.from_number(75)
        assert self.orders_by_token(
            keeper,
            deployment.sai.address)[0].pay_token == deployment.sai.address
        assert self.orders_by_token(
            keeper,
            deployment.sai.address)[0].buy_amount == Wad.from_number(0.78125)
        assert self.orders_by_token(
            keeper,
            deployment.sai.address)[0].buy_token == EtherDelta.ETH_TOKEN
Example #2
0
    def test_should_create_orders_in_multiple_bands(self,
                                                    deployment: Deployment,
                                                    tmpdir: py.path.local):
        # given
        config_file = BandConfig.two_adjacent_bands_config(tmpdir)

        # and
        keeper = EtherDeltaMarketMakerKeeper(args=args(
            f"--eth-from {deployment.our_address} --config {config_file}"
            f" --tub-address {deployment.tub.address}"
            f" --etherdelta-address {deployment.etherdelta.address}"
            f" --etherdelta-socket https://127.0.0.1:99999/"
            f" --order-age 3600 --eth-reserve 10"
            f" --min-eth-deposit 1 --min-sai-deposit 400"),
                                             web3=deployment.web3)
        keeper.lifecycle = Web3Lifecycle(web3=keeper.web3)
        keeper.etherdelta_api.publish_order = MagicMock()

        # and
        self.mint_tokens(deployment)
        self.set_price(deployment, Wad.from_number(100))

        # when
        keeper.approve()
        keeper.synchronize_orders(
        )  # ... first call is so it can made deposits
        keeper.synchronize_orders(
        )  # ... second call is so the actual orders can get placed

        # then
        assert len(self.orders(keeper)) == 2

        # and
        assert self.orders_sorted(
            self.orders(keeper))[0].maker == deployment.our_address
        assert self.orders_sorted(
            self.orders(keeper))[0].pay_amount == Wad.from_number(7.5)
        assert self.orders_sorted(
            self.orders(keeper))[0].pay_token == EtherDelta.ETH_TOKEN
        assert self.orders_sorted(
            self.orders(keeper))[0].buy_amount == Wad.from_number(780)
        assert self.orders_sorted(
            self.orders(keeper))[0].buy_token == deployment.sai.address

        # and
        assert self.orders_sorted(
            self.orders(keeper))[1].maker == deployment.our_address
        assert self.orders_sorted(
            self.orders(keeper))[1].pay_amount == Wad.from_number(9.5)
        assert self.orders_sorted(
            self.orders(keeper))[1].pay_token == EtherDelta.ETH_TOKEN
        assert self.orders_sorted(
            self.orders(keeper))[1].buy_amount == Wad.from_number(1026)
        assert self.orders_sorted(
            self.orders(keeper))[1].buy_token == deployment.sai.address
Example #3
0
    def test_should_fail_to_operate_if_bands_overlap(self,
                                                     deployment: Deployment,
                                                     tmpdir: py.path.local):
        # given
        config_file = BandConfig.bands_overlapping_invalid_config(tmpdir)

        # and
        keeper = EtherDeltaMarketMakerKeeper(args=args(
            f"--eth-from {deployment.our_address} --config {config_file}"
            f" --tub-address {deployment.tub.address}"
            f" --etherdelta-address {deployment.etherdelta.address}"
            f" --etherdelta-socket https://127.0.0.1:99999/"
            f" --order-age 3600 --eth-reserve 10"
            f" --min-eth-deposit 1 --min-sai-deposit 400"),
                                             web3=deployment.web3)
        keeper.lifecycle = Web3Lifecycle(web3=keeper.web3)
        keeper.etherdelta_api.publish_order = MagicMock()

        # and
        self.mint_tokens(deployment)
        self.set_price(deployment, Wad.from_number(100))

        # and
        keeper.approve()

        # expect
        with pytest.raises(Exception):
            keeper.synchronize_orders()
Example #4
0
    def test_should_support_config_files_with_variables(
            self, deployment: Deployment, tmpdir: py.path.local):
        # given
        config_file = BandConfig.with_variables_config(tmpdir)

        # and
        keeper = EtherDeltaMarketMakerKeeper(args=args(
            f"--eth-from {deployment.our_address} --config {config_file}"
            f" --tub-address {deployment.tub.address}"
            f" --etherdelta-address {deployment.etherdelta.address}"
            f" --etherdelta-socket https://127.0.0.1:99999/"
            f" --order-age 3600 --eth-reserve 10"
            f" --min-eth-deposit 1 --min-sai-deposit 400"
            f" --cancel-on-shutdown --withdraw-on-shutdown"),
                                             web3=deployment.web3)
        keeper.lifecycle = Web3Lifecycle(web3=keeper.web3)
        keeper.etherdelta_api.publish_order = MagicMock()

        # and
        self.mint_tokens(deployment)
        self.set_price(deployment, Wad.from_number(100))

        # when
        keeper.approve()
        keeper.synchronize_orders(
        )  # ... first call is so it can made deposits
        keeper.synchronize_orders(
        )  # ... second call is so the actual orders can get placed

        # then
        assert len(self.orders(keeper)) == 1

        # and
        assert self.orders_by_token(
            keeper, EtherDelta.ETH_TOKEN)[0].maker == deployment.our_address
        assert self.orders_by_token(
            keeper, EtherDelta.ETH_TOKEN)[0].pay_amount == Wad.from_number(5.0)
        assert self.orders_by_token(
            keeper, EtherDelta.ETH_TOKEN)[0].pay_token == EtherDelta.ETH_TOKEN
        assert self.orders_by_token(
            keeper, EtherDelta.ETH_TOKEN)[0].buy_amount == Wad.from_number(520)
        assert self.orders_by_token(
            keeper,
            EtherDelta.ETH_TOKEN)[0].buy_token == deployment.sai.address
Example #5
0
    def test_should_not_create_any_orders_but_not_terminate_if_eth_balance_before_minimum(
            self, deployment: Deployment, tmpdir: py.path.local):
        # given
        config_file = BandConfig.two_adjacent_bands_config(tmpdir)

        # and
        keeper = EtherDeltaMarketMakerKeeper(args=args(
            f"--eth-from {deployment.our_address} --config {config_file}"
            f" --tub-address {deployment.tub.address}"
            f" --etherdelta-address {deployment.etherdelta.address}"
            f" --etherdelta-socket https://127.0.0.1:99999/"
            f" --order-age 3600 --eth-reserve 200"
            f" --min-eth-balance 100.0"
            f" --min-eth-deposit 1 --min-sai-deposit 400"),
                                             web3=deployment.web3)
        keeper.lifecycle = Web3Lifecycle(web3=keeper.web3)
        keeper.etherdelta_api.publish_order = MagicMock()

        # and
        self.mint_tokens(deployment)
        self.set_price(deployment, Wad.from_number(100))

        # and
        self.leave_only_some_eth(deployment, Wad.from_number(
            10.0))  # there is a 5.0 ETH block reward even in testrpc,
        # that's why `--min-eth-balance` is higher than 10

        # when
        keeper.approve()
        keeper.synchronize_orders(
        )  # ... first call is so it can made deposits
        keeper.synchronize_orders(
        )  # ... second call is so the actual orders can get placed

        # then
        assert len(self.orders(keeper)) == 0
        assert not keeper.lifecycle.terminated_internally
Example #6
0
    def test_should_refuse_to_start_if_eth_reserve_lower_than_min_eth_balance(
            self, deployment: Deployment, tmpdir: py.path.local):
        # given
        config_file = BandConfig.two_adjacent_bands_config(tmpdir)

        # expect
        with pytest.raises(
                Exception,
                match="--eth-reserve must be higher than --min-eth-balance"):
            EtherDeltaMarketMakerKeeper(args=args(
                f"--eth-from {deployment.our_address} --config {config_file}"
                f" --tub-address {deployment.tub.address}"
                f" --etherdelta-address {deployment.etherdelta.address}"
                f" --etherdelta-socket https://127.0.0.1:99999/"
                f" --order-age 3600 --eth-reserve 99.9"
                f" --min-eth-balance 100.0"
                f" --min-eth-deposit 1 --min-sai-deposit 400"),
                                        web3=deployment.web3)
Example #7
0
    def test_should_use_specified_gas_price_for_all_transactions(
            self, deployment: Deployment, tmpdir: py.path.local):
        # given
        config_file = BandConfig.sample_config(tmpdir)

        # and
        keeper = EtherDeltaMarketMakerKeeper(args=args(
            f"--eth-from {deployment.our_address} --config {config_file}"
            f" --tub-address {deployment.tub.address}"
            f" --etherdelta-address {deployment.etherdelta.address}"
            f" --etherdelta-socket https://127.0.0.1:99999/"
            f" --order-age 3600 --eth-reserve 10"
            f" --min-eth-deposit 1 --min-sai-deposit 400"
            f" --cancel-on-shutdown"
            f" --gas-price 69000000000"),
                                             web3=deployment.web3)
        keeper.lifecycle = Web3Lifecycle(web3=keeper.web3)
        keeper.etherdelta_api.publish_order = MagicMock()

        # and
        self.mint_tokens(deployment)
        self.set_price(deployment, Wad.from_number(100))

        # and
        start_block_number = deployment.web3.eth.blockNumber

        # when
        keeper.approve()
        keeper.synchronize_orders(
        )  # ... first call is so it can made deposits
        keeper.synchronize_orders(
        )  # ... second call is so the actual orders can get placed
        keeper.shutdown()

        # then
        for block_number in range(start_block_number + 1,
                                  deployment.web3.eth.blockNumber + 1):
            for transaction in deployment.web3.eth.getBlock(
                    block_number, full_transactions=True).transactions:
                assert transaction.gasPrice == 69000000000
Example #8
0
    def test_should_cancel_all_orders_outside_bands(self,
                                                    deployment: Deployment,
                                                    tmpdir: py.path.local):
        # given
        config_file = BandConfig.sample_config(tmpdir)

        # and
        keeper = EtherDeltaMarketMakerKeeper(args=args(
            f"--eth-from {deployment.our_address} --config {config_file}"
            f" --tub-address {deployment.tub.address}"
            f" --etherdelta-address {deployment.etherdelta.address}"
            f" --etherdelta-socket https://127.0.0.1:99999/"
            f" --order-age 3600 --eth-reserve 10"
            f" --min-eth-deposit 1 --min-sai-deposit 400"),
                                             web3=deployment.web3)
        keeper.lifecycle = Web3Lifecycle(web3=keeper.web3)
        keeper.etherdelta_api.publish_order = MagicMock()

        # and
        self.mint_tokens(deployment)
        self.set_price(deployment, Wad.from_number(100))

        # and
        keeper.approve()
        keeper.synchronize_orders(
        )  # ... first call is so it can made deposits
        keeper.synchronize_orders(
        )  # ... second call is so the actual orders can get placed
        assert len(self.orders(keeper)) == 2

        # when
        keeper.our_orders.append(
            deployment.etherdelta.create_order(
                deployment.sai.address,
                Wad.from_number(5), EtherDelta.ETH_TOKEN,
                Wad.from_number(0.0538), 1000000))  #price=92.936802973977695
        keeper.our_orders.append(
            deployment.etherdelta.create_order(deployment.sai.address,
                                               Wad.from_number(5),
                                               EtherDelta.ETH_TOKEN,
                                               Wad.from_number(0.0505),
                                               1000000))  #price=99.0
        keeper.our_orders.append(
            deployment.etherdelta.create_order(EtherDelta.ETH_TOKEN,
                                               Wad.from_number(0.5),
                                               deployment.sai.address,
                                               Wad.from_number(50.5),
                                               1000000))  #price=101
        keeper.our_orders.append(
            deployment.etherdelta.create_order(EtherDelta.ETH_TOKEN,
                                               Wad.from_number(0.5),
                                               deployment.sai.address,
                                               Wad.from_number(53.5),
                                               1000000))  #price=107
        assert len(self.orders(keeper)) == 6
        # and
        keeper.synchronize_orders(
        )  # ... first call is so it can made deposits
        keeper.synchronize_orders(
        )  # ... second call is so the actual orders can get placed
        # then
        assert len(self.orders(keeper)) == 2
Example #9
0
    def test_should_cancel_selected_sell_orders_to_bring_the_band_total_below_max_and_closest_to_it(
            self, deployment: Deployment, tmpdir: py.path.local):
        # given
        config_file = BandConfig.sample_config(tmpdir)

        # and
        keeper = EtherDeltaMarketMakerKeeper(args=args(
            f"--eth-from {deployment.our_address} --config {config_file}"
            f" --tub-address {deployment.tub.address}"
            f" --etherdelta-address {deployment.etherdelta.address}"
            f" --etherdelta-socket https://127.0.0.1:99999/"
            f" --order-age 3600 --eth-reserve 10"
            f" --min-eth-deposit 1 --min-sai-deposit 400"),
                                             web3=deployment.web3)
        keeper.lifecycle = Web3Lifecycle(web3=keeper.web3)
        keeper.etherdelta_api.publish_order = MagicMock()

        # and
        self.mint_tokens(deployment)
        self.set_price(deployment, Wad.from_number(100))

        # and
        keeper.approve()
        keeper.synchronize_orders(
        )  # ... first call is so it can made deposits
        keeper.synchronize_orders(
        )  # ... second call is so the actual orders can get placed
        assert len(self.orders(keeper)) == 2

        # when [7.5+2.0 = 9.5]
        keeper.our_orders.append(
            deployment.etherdelta.create_order(EtherDelta.ETH_TOKEN,
                                               Wad.from_number(2),
                                               deployment.sai.address,
                                               Wad.from_number(208), 1000000))
        # and
        keeper.synchronize_orders(
        )  # ... first call is so it can made deposits
        keeper.synchronize_orders(
        )  # ... second call is so the actual orders can get placed
        # then
        assert len(self.orders(keeper)) == 3

        # when [9.5+0.5 = 10]
        keeper.our_orders.append(
            deployment.etherdelta.create_order(EtherDelta.ETH_TOKEN,
                                               Wad.from_number(0.5),
                                               deployment.sai.address,
                                               Wad.from_number(52), 1000000))
        # and
        keeper.synchronize_orders(
        )  # ... first call is so it can made deposits
        keeper.synchronize_orders(
        )  # ... second call is so the actual orders can get placed
        # then
        assert len(self.orders(keeper)) == 4

        # when [10+0.1 = 10.1] --> above max!
        keeper.our_orders.append(
            deployment.etherdelta.create_order(EtherDelta.ETH_TOKEN,
                                               Wad.from_number(0.1),
                                               deployment.sai.address,
                                               Wad.from_number(10.4), 1000000))
        # and
        keeper.synchronize_orders(
        )  # ... first call is so it can made deposits
        keeper.synchronize_orders(
        )  # ... second call is so the actual orders can get placed
        # then
        assert len(self.orders(keeper)) == 4
        assert reduce(Wad.__add__, map(lambda order: order.pay_amount, self.orders_by_token(keeper, EtherDelta.ETH_TOKEN)), Wad(0)) \
               == Wad.from_number(10.0)
Example #10
0
    def test_should_place_extra_order_only_if_order_brought_below_min(
            self, deployment: Deployment, tmpdir: py.path.local):
        # given
        config_file = BandConfig.sample_config(tmpdir)

        # and
        keeper = EtherDeltaMarketMakerKeeper(args=args(
            f"--eth-from {deployment.our_address} --config {config_file}"
            f" --tub-address {deployment.tub.address}"
            f" --etherdelta-address {deployment.etherdelta.address}"
            f" --etherdelta-socket https://127.0.0.1:99999/"
            f" --order-age 3600 --eth-reserve 10"
            f" --min-eth-deposit 1 --min-sai-deposit 400"),
                                             web3=deployment.web3)
        keeper.lifecycle = Web3Lifecycle(web3=keeper.web3)
        keeper.etherdelta_api.publish_order = MagicMock()

        # and
        self.mint_tokens(deployment)
        self.set_price(deployment, Wad.from_number(100))

        # and
        keeper.approve()
        keeper.synchronize_orders(
        )  # ... first call is so it can made deposits
        keeper.synchronize_orders(
        )  # ... second call is so the actual orders can get placed
        assert len(self.orders(keeper)) == 2
        sai_order = self.orders_by_token(keeper, deployment.sai.address)[0]

        # when
        print(sai_order.sell_to_buy_price)
        print(sai_order.buy_to_sell_price)
        deployment.etherdelta.trade(sai_order,
                                    Wad.from_number(20) /
                                    Wad.from_number(96)).transact()
        # and
        keeper.synchronize_orders()
        # then
        assert len(self.orders(keeper)) == 2

        # when
        deployment.etherdelta.trade(sai_order,
                                    Wad.from_number(5) /
                                    Wad.from_number(96)).transact()
        # and
        keeper.synchronize_orders()
        # then
        assert len(self.orders(keeper)) == 2

        # when
        deployment.etherdelta.trade(sai_order,
                                    Wad.from_number(1) /
                                    Wad.from_number(96)).transact()
        # and
        keeper.synchronize_orders()
        # then
        assert len(self.orders(keeper)) == 3
        assert self.orders(keeper)[2].pay_amount == Wad.from_number(26)
        assert self.orders(keeper)[2].pay_token == deployment.sai.address
        assert self.orders(keeper)[2].buy_amount == Wad(270833333000000000)
        assert self.orders(keeper)[2].buy_token == EtherDelta.ETH_TOKEN
Example #11
0
    def test_should_reload_config_file_if_changed(self, deployment: Deployment,
                                                  tmpdir: py.path.local):
        # given
        config_file = BandConfig.with_variables_config(tmpdir)

        # and
        keeper = EtherDeltaMarketMakerKeeper(args=args(
            f"--eth-from {deployment.our_address} --config {config_file}"
            f" --tub-address {deployment.tub.address}"
            f" --etherdelta-address {deployment.etherdelta.address}"
            f" --etherdelta-socket https://127.0.0.1:99999/"
            f" --order-age 3600 --eth-reserve 10"
            f" --min-eth-deposit 1 --min-sai-deposit 400"),
                                             web3=deployment.web3)
        keeper.lifecycle = Web3Lifecycle(web3=keeper.web3)
        keeper.etherdelta_api.publish_order = MagicMock()

        # and
        self.mint_tokens(deployment)
        self.set_price(deployment, Wad.from_number(100))

        # when
        keeper.approve()
        keeper.synchronize_orders(
        )  # ... first call is so it can made deposits
        keeper.synchronize_orders(
        )  # ... second call is so the actual orders can get placed

        # then
        assert len(self.orders(keeper)) == 1

        # when
        second_config_file = BandConfig.sample_config(tmpdir)
        shutil.copyfile(second_config_file, config_file)

        # and
        keeper.synchronize_orders(
        )  # ... first call is so it can made deposits
        keeper.synchronize_orders(
        )  # ... second call is so the actual orders can get placed

        # then
        assert len(self.orders(keeper)) == 2
Example #12
0
    def test_should_cancel_orders_on_shutdown_and_withdraw_if_asked_to_do_so(
            self, deployment: Deployment, tmpdir: py.path.local):
        # given
        config_file = BandConfig.sample_config(tmpdir)

        # and
        keeper = EtherDeltaMarketMakerKeeper(args=args(
            f"--eth-from {deployment.our_address} --config {config_file}"
            f" --tub-address {deployment.tub.address}"
            f" --etherdelta-address {deployment.etherdelta.address}"
            f" --etherdelta-socket https://127.0.0.1:99999/"
            f" --order-age 3600 --eth-reserve 10"
            f" --min-eth-deposit 1 --min-sai-deposit 400"
            f" --cancel-on-shutdown --withdraw-on-shutdown"),
                                             web3=deployment.web3)
        keeper.lifecycle = Web3Lifecycle(web3=keeper.web3)
        keeper.etherdelta_api.publish_order = MagicMock()

        # and
        self.mint_tokens(deployment)
        self.set_price(deployment, Wad.from_number(100))

        # and
        keeper.approve()
        keeper.synchronize_orders(
        )  # ... first call is so it can made deposits
        keeper.synchronize_orders(
        )  # ... second call is so the actual orders can get placed
        assert len(self.orders(keeper)) == 2

        # when
        keeper.shutdown()

        # then
        assert len(self.orders(keeper)) == 0

        # and
        assert deployment.etherdelta.balance_of(
            deployment.our_address) == Wad(0)
        assert deployment.etherdelta.balance_of_token(
            deployment.sai.address, deployment.our_address) == Wad(0)