def test_transfer(self):
        # when
        self.token.transfer(self.second_address, Wad(500))

        # then
        self.token.balance_of(self.our_address) == Wad(999500)
        self.token.balance_of(self.second_address) == Wad(500)
Exemple #2
0
 def create_new_sell_order(self):
     """If our SAI engagement is below the minimum amount, create a new offer up to the maximum amount"""
     total_amount = self.total_amount(self.our_sell_orders())
     if total_amount < self.min_sai_amount:
         our_balance = self.sai.balance_of(
             self.our_address) + self.etherdelta.balance_of_token(
                 self.sai.address, self.our_address)
         have_amount = Wad.min(self.max_sai_amount,
                               our_balance) - total_amount
         if have_amount > Wad(0):
             want_amount = self.fix_amount(
                 have_amount * self.apply_sell_margin(
                     self.target_rate(), self.avg_margin))
             if self.offchain:
                 self.etherdelta.place_order_offchain(
                     token_get=EtherDelta.ETH_TOKEN,
                     amount_get=want_amount,
                     token_give=self.sai.address,
                     amount_give=have_amount,
                     expires=self.web3.eth.blockNumber + self.order_age)
             else:
                 self.etherdelta.place_order_onchain(
                     token_get=EtherDelta.ETH_TOKEN,
                     amount_get=want_amount,
                     token_give=self.sai.address,
                     amount_give=have_amount,
                     expires=self.web3.eth.blockNumber + self.order_age)
Exemple #3
0
    def __init__(self):
        super().__init__()
        self.offchain = self.arguments.offchain
        self.order_age = self.arguments.order_age
        self.max_eth_amount = Wad.from_number(self.arguments.max_eth_amount)
        self.min_eth_amount = Wad.from_number(self.arguments.min_eth_amount)
        self.max_sai_amount = Wad.from_number(self.arguments.max_sai_amount)
        self.min_sai_amount = Wad.from_number(self.arguments.min_sai_amount)
        self.eth_reserve = Wad.from_number(self.arguments.eth_reserve)
        self.min_margin = self.arguments.min_margin
        self.avg_margin = self.arguments.avg_margin
        self.max_margin = self.arguments.max_margin

        self.etherdelta_address = Address(
            self.config.get_config()["etherDelta"]["contract"])
        self.etherdelta_api_server = self.config.get_config()["etherDelta"]["apiServer"][1] \
            if "apiServer" in self.config.get_config()["etherDelta"] \
            else None
        self.etherdelta = EtherDelta(web3=self.web3,
                                     address=self.etherdelta_address,
                                     api_server=self.etherdelta_api_server)

        if self.offchain and not self.etherdelta.supports_offchain_orders():
            raise Exception(
                "Off-chain EtherDelta orders not supported on this chain")
    def close_position(self):
        cup_id = 8

        # (1) Exchange our ETH to SAI as we want to repay our SAI debt
        our_entire_gem = self.gem.balance_of(self.our_address)
        conversion = self.gem_to_sai_conversion()
        sequence = Sequence([conversion])
        if our_entire_gem > Wad.from_number(0.0001):
            sequence.set_amounts(our_entire_gem)
            receipt = sequence.steps[0].execute()
            if receipt:
                logging.info(receipt.transfers)

        self.print_balances()

        our_debt = self.tub.tab(cup_id)
        print(our_debt)
        our_sai_balanace = self.sai.balance_of(self.our_address)
        if our_sai_balanace < our_debt:
            logging.info("NOT ENOUGH SAI TO REPAY OUR DEBT!")
            exit(-1)

        # (2) Repay the debt and get back our SKR
        # some surplus of SAI will be left, this is the profit we made
        # self.tub.wipe(cup_id, Wad.from_number(1))
        logging.info(self.tub.shut(cup_id))
        self.print_balances()

        # (3) Exchange SKR back to ETH
        if self.skr.balance_of(self.our_address) > Wad(0):
            logging.info(self.tub.exit(self.skr.balance_of(self.our_address)))
            self.print_balances()
    def test_should_identify_multi_step_opportunities(self, token1, token2,
                                                      token3, token4):
        # given
        conversion1 = Conversion(token1, token2, Ray.from_number(1.02),
                                 Wad.from_number(10000), 'met1')
        conversion2 = Conversion(token2, token3, Ray.from_number(1.03),
                                 Wad.from_number(10000), 'met2')
        conversion3 = Conversion(token3, token4, Ray.from_number(1.05),
                                 Wad.from_number(10000), 'met3')
        conversion4 = Conversion(token4, token1, Ray.from_number(1.07),
                                 Wad.from_number(10000), 'met4')
        conversions = [conversion1, conversion2, conversion3, conversion4]
        base_token = token1

        # when
        opportunities = OpportunityFinder(conversions).find_opportunities(
            base_token, Wad.from_number(100))

        # then
        assert len(opportunities) == 1
        assert len(opportunities[0].steps) == 4
        assert opportunities[0].steps[0].method == "met1"
        assert opportunities[0].steps[1].method == "met2"
        assert opportunities[0].steps[2].method == "met3"
        assert opportunities[0].steps[3].method == "met4"
    def test_tag(self, sai: SaiDeployment):
        # when
        DSValue(web3=sai.web3, address=sai.tub.pip()).poke_with_int(
            Wad.from_number(250.45).value)

        # then
        assert sai.tub.tag() == Wad.from_number(250.45)
Exemple #7
0
    def __init__(self):
        super().__init__()
        self.base_token = ERC20Token(web3=self.web3,
                                     address=ERC20Token.token_address_by_name(
                                         self.arguments.base_token))
        self.min_profit = Wad.from_number(self.arguments.min_profit)
        self.max_engagement = Wad.from_number(self.arguments.max_engagement)
        if len(self.arguments.excluded_makers) > 0:
            self.excluded_makers = set(
                map(lambda maker: Address(maker),
                    self.arguments.excluded_makers.split(',')))
        else:
            self.excluded_makers = set()
        self.max_errors = self.arguments.max_errors
        self.errors = 0

        if self.arguments.tx_manager:
            self.tx_manager_address = Address(self.arguments.tx_manager)
            self.tx_manager = TxManager(web3=self.web3,
                                        address=self.tx_manager_address)
            if self.tx_manager.owner() != self.our_address:
                logging.info(
                    f"The TxManager has to be owned by the address the keeper is operating from."
                )
                exit(-1)
        else:
            self.tx_manager_address = None
            self.tx_manager = None
Exemple #8
0
    def get_offer(self, offer_id: int) -> Optional[OfferInfo]:
        """Get the offer details.

        Args:
            offer_id: The id of the offer to get the details of.

        Returns:
            An instance of `OfferInfo` if the offer is still active, or `None` if the offer has been
            already completely taken.
        """

        # if an offer is None, it won't become not-None again for the same OTC instance
        if offer_id in self._none_offers:
            return None

        array = self._contract.call().offers(offer_id)
        if array[5] is not True:
            self._none_offers.add(offer_id)
            return None
        else:
            return OfferInfo(offer_id=offer_id,
                             sell_how_much=Wad(array[0]),
                             sell_which_token=Address(array[1]),
                             buy_how_much=Wad(array[2]),
                             buy_which_token=Address(array[3]),
                             owner=Address(array[4]),
                             timestamp=array[6])
Exemple #9
0
 def __init__(self, args):
     self.id = bytes_to_int(args['id'])
     self.maker = Address(args['maker'])
     self.have_token = Address(args['haveToken'])
     self.have_amount = Wad(args['haveAmount'])
     self.want_token = Address(args['wantToken'])
     self.want_amount = Wad(args['wantAmount'])
     self.timestamp = args['timestamp']
 def __init__(self, args):
     self.token_get = Address(args['tokenGet'])
     self.amount_get = Wad(args['amountGet'])
     self.token_give = Address(args['tokenGive'])
     self.amount_give = Wad(args['amountGive'])
     self.expires = args['expires']
     self.nonce = args['nonce']
     self.user = Address(args['user'])
    def test_cups(self, sai: SaiDeployment):
        # when
        sai.tub.open()

        # then
        assert sai.tub.cups(1).art == Wad(0)
        assert sai.tub.cups(1).ink == Wad(0)
        assert sai.tub.cups(1).lad == sai.our_address
    def test_withdraw(self):
        # given
        self.dsethtoken.deposit(Wad(100000))

        # when
        self.dsethtoken.withdraw(Wad(40000))

        # then
        assert self.dsethtoken.balance_of(self.our_address) == Wad(60000)
    def test_burn(self):
        # given
        self.dstoken.mint(Wad(100000))

        # when
        self.dstoken.burn(Wad(40000))

        # then
        assert self.dstoken.balance_of(self.our_address) == Wad(60000)
Exemple #14
0
 def __init__(self):
     super().__init__()
     self.max_weth_amount = Wad.from_number(self.arguments.max_weth_amount)
     self.min_weth_amount = Wad.from_number(self.arguments.min_weth_amount)
     self.max_sai_amount = Wad.from_number(self.arguments.max_sai_amount)
     self.min_sai_amount = Wad.from_number(self.arguments.min_sai_amount)
     self.min_margin = self.arguments.min_margin
     self.avg_margin = self.arguments.avg_margin
     self.max_margin = self.arguments.max_margin
    def test_cork_and_hat(self, sai: SaiDeployment):
        # given
        assert sai.tub.hat() == Wad(0)

        # when
        sai.tub.cork(Wad.from_number(150000))

        # then
        assert sai.tub.hat() == Wad.from_number(150000)
Exemple #16
0
 def _net_value(self, transfer: Transfer, our_address: Address):
     if transfer.from_address == our_address and transfer.to_address == our_address:
         return Wad(0)
     elif transfer.from_address == our_address:
         return Wad(0) - transfer.value
     elif transfer.to_address == our_address:
         return transfer.value
     else:
         return Wad(0)
Exemple #17
0
    def withdraw_everything(self):
        eth_balance = self.etherdelta.balance_of(self.our_address)
        if eth_balance > Wad(0):
            self.etherdelta.withdraw(eth_balance)

        sai_balance = self.etherdelta.balance_of_token(self.sai.address,
                                                       self.our_address)
        if sai_balance > Wad(0):
            self.etherdelta.withdraw_token(self.sai.address, sai_balance)
    def test_jump_and_gap(self, sai: SaiDeployment):
        # given
        assert sai.tap.gap() == Wad.from_number(1)

        # when
        sai.tap.jump(Wad.from_number(1.05))

        # then
        assert sai.tap.gap() == Wad.from_number(1.05)
    def test_s2s_and_bid_and_ask(self, sai: SaiDeployment):
        # when
        DSValue(web3=sai.web3, address=sai.tub.pip()).poke_with_int(
            Wad.from_number(500).value)
        sai.tap.jump(Wad.from_number(1.05))

        # then
        assert sai.tap.bid() == Wad.from_number(475)
        assert sai.tap.s2s() == Wad.from_number(500)
        assert sai.tap.ask() == Wad.from_number(525)
Exemple #20
0
def test_should_format_two_different_tokens(token1, token2, some_address):
    # given
    transfer1 = Transfer(token1, some_address, some_address,
                         Wad.from_number(105))
    transfer2 = Transfer(token2, some_address, some_address,
                         Wad.from_number(17))

    # expect
    assert TransferFormatter().format([transfer1, transfer2]) \
        == "105.000000000000000000 TK1 and 17.000000000000000000 TK2"
 def test_should_calculate_tx_costs(self, token1):
     # expect the tx_costs to be non negative and to increase with the number of steps
     steps = []
     prev_tx_costs = Wad.from_number(0)
     for i in range(10):
         steps.append(Conversion(token1, token1, Ray(0), Wad(0), 'met'))
         opportunity = Sequence(steps)
         tx_costs = opportunity.tx_costs()
         assert (tx_costs > prev_tx_costs)
         prev_tx_costs = tx_costs
Exemple #22
0
def test_should_format_net_balances(token1, our_address, some_address):
    # given
    transfer1 = Transfer(token1, our_address, some_address,
                         Wad.from_number(15))
    transfer2 = Transfer(token1, some_address, our_address,
                         Wad.from_number(17))

    # expect
    assert TransferFormatter().format_net([transfer1, transfer2], our_address) \
        == "2.000000000000000000 TK1"
Exemple #23
0
def test_nicely_convert_to_string_with_amounts(token1, token2):
    # given
    conversion = Conversion(token1, token2, Ray.from_number(1.01),
                            Wad.from_number(1000), 'met()')
    conversion.source_amount = Wad.from_number(50)
    conversion.target_amount = Wad.from_number(50.5)

    # expect
    assert str(conversion) == "[50.000000000000000000 TK1 -> 50.500000000000000000 TK2 @1.010000000000000000000000000" \
                              " by met() (max=1000.000000000000000000 TK1)]"
Exemple #24
0
 def deposit_for_sell_orders(self):
     order_total = self.total_amount(self.our_sell_orders())
     currently_deposited = self.etherdelta.balance_of_token(
         self.sai.address, self.our_address)
     if order_total > currently_deposited:
         additional_deposit = Wad.min(order_total - currently_deposited,
                                      self.sai.balance_of(self.our_address))
         if additional_deposit > Wad(0):
             self.etherdelta.deposit_token(self.sai.address,
                                           additional_deposit)
Exemple #25
0
 def deposit_for_buy_orders(self):
     order_total = self.total_amount(self.our_buy_orders())
     currently_deposited = self.etherdelta.balance_of(self.our_address)
     if order_total > currently_deposited:
         depositable_eth = Wad.max(
             self.eth_balance(self.our_address) - self.eth_reserve, Wad(0))
         additional_deposit = Wad.min(order_total - currently_deposited,
                                      depositable_eth)
         if additional_deposit > Wad(0):
             self.etherdelta.deposit(additional_deposit)
 def prepare_balances(self):
     recipient = Address('0x002ca7F9b416B2304cDd20c26882d1EF5c53F611')
     if self.sai.balance_of(self.our_address) > Wad(0):
         self.sai.transfer(recipient, self.sai.balance_of(self.our_address))
     if self.skr.balance_of(self.our_address) > Wad(0):
         self.skr.transfer(recipient, self.skr.balance_of(self.our_address))
     if self.gem.balance_of(self.our_address) > Wad.from_number(0.5):
         self.gem.transfer(
             recipient,
             self.gem.balance_of(self.our_address) - Wad.from_number(0.5))
Exemple #27
0
def test_should_format_net_balances_excluding_transfers_between_us(
        token1, our_address, some_address):
    # given
    transfer1 = Transfer(token1, some_address, our_address, Wad.from_number(4))
    transfer2 = Transfer(token1, our_address, some_address,
                         Wad.from_number(1.5))
    transfer3 = Transfer(token1, our_address, our_address, Wad.from_number(50))

    # expect
    assert TransferFormatter().format_net([transfer1, transfer2, transfer3], our_address) \
        == "2.500000000000000000 TK1"
Exemple #28
0
    def bustable_amount_in_sai(self, tap: Tap):
        #TODO we always try to bust 10 SAI less than what the Tub reports
        #in order to discount the growth of `joy()` that might've have happened since the last drip
        #of course this is not the right solution and it won't even work properly if the last
        #drip happened enough time ago
        bustable_woe = tap.woe() - tap.joy() - Wad.from_number(10)

        # we deduct 0.000001 in order to avoid rounding errors
        bustable_fog = tap.fog() * tap.ask() - Wad.from_number(0.000001)

        return Wad.max(bustable_woe, bustable_fog, Wad.from_number(0))
    def test_should_calculate_total_rate(self, token1, token2):
        # given
        step1 = Conversion(token1, token2, Ray.from_number(1.01),
                           Wad.from_number(1000), 'met1')
        step2 = Conversion(token2, token1, Ray.from_number(1.02),
                           Wad.from_number(1000), 'met2')

        # when
        sequence = Sequence([step1, step2])

        # then
        assert sequence.total_rate() == Ray.from_number(1.0302)
 def required_top_up(self, cup):
     pro = cup.ink * self.tub.tag()
     tab = self.tub.tab(cup.cup_id)
     if tab > Wad(0):
         current_ratio = Ray(pro / tab)
         if current_ratio < self.minimum_ratio:
             return tab * (Wad(self.target_ratio - current_ratio) /
                           self.tub.tag())
         else:
             return None
     else:
         return None