Ejemplo n.º 1
0
 def __init__(self):
     super().__init__()
     self.liquidation_ratio = self.tub.mat()
     self.minimum_ratio = self.liquidation_ratio + Ray.from_number(
         self.arguments.min_margin)
     self.target_ratio = self.liquidation_ratio + Ray.from_number(
         self.arguments.top_up_margin)
    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_should_ignore_irrelevant_conversions(self, token1, token2, token3,
                                                  token4):
        # given
        conversion1 = Conversion(token1, token2, Ray.from_number(1.02),
                                 Wad.from_number(10000), 'met1')
        conversion2 = Conversion(token2, token1, Ray.from_number(1.03),
                                 Wad.from_number(10000), 'met2')
        conversion3 = Conversion(token1, token3, Ray.from_number(1.04),
                                 Wad.from_number(10000), 'met3')
        conversion4 = Conversion(token1, token4, Ray.from_number(1.07),
                                 Wad.from_number(10000), 'met4')
        conversion5 = Conversion(token2, token4, Ray.from_number(1.08),
                                 Wad.from_number(10000), 'met5')
        conversions = [
            conversion1, conversion2, conversion3, conversion4, conversion5
        ]
        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) == 2
        assert opportunities[0].steps[0].method == "met1"
        assert opportunities[0].steps[1].method == "met2"
    def test_should_adjust_amounts_based_on_max_source_amount(
            self, token1, token2, token3, token4):
        # given
        conversion1 = Conversion(token1, token2, Ray.from_number(2.0),
                                 Wad.from_number(10000), 'met1')
        conversion2 = Conversion(token2, token3, Ray.from_number(1.6),
                                 Wad.from_number(10000), 'met2')
        conversion3 = Conversion(token3, token4, Ray.from_number(1.2),
                                 Wad.from_number(100), 'met3')
        conversion4 = Conversion(token4, token1, Ray.from_number(1.1),
                                 Wad.from_number(10000), 'met4')
        conversions = [conversion1, conversion4, conversion3, conversion2]
        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[0].source_amount == Wad.from_number(
            31.25)
        assert opportunities[0].steps[0].target_amount == Wad.from_number(62.5)
        assert opportunities[0].steps[1].method == "met2"
        assert opportunities[0].steps[1].source_amount == Wad.from_number(62.5)
        assert opportunities[0].steps[1].target_amount == Wad.from_number(100)
        assert opportunities[0].steps[2].method == "met3"
        assert opportunities[0].steps[2].source_amount == Wad.from_number(100)
        assert opportunities[0].steps[2].target_amount == Wad.from_number(120)
        assert opportunities[0].steps[3].method == "met4"
        assert opportunities[0].steps[3].source_amount == Wad.from_number(120)
        assert opportunities[0].steps[3].target_amount == Wad.from_number(132)
Ejemplo n.º 5
0
 def __init__(self, tub: Tub, tap: Tap):
     self.tub = tub
     self.tap = tap
     super().__init__(source_token=self.tub.sai(),
                      target_token=self.tub.skr(),
                      rate=(Ray.from_number(1) / Ray(tap.ask())),
                      max_source_amount=self.bustable_amount_in_sai(tap),
                      method="tub.bust()")
Ejemplo n.º 6
0
 def __init__(self, otc: SimpleMarket, offer: OfferInfo):
     self.otc = otc
     self.offer = offer
     super().__init__(source_token=offer.buy_which_token,
                      target_token=offer.sell_which_token,
                      rate=Ray(offer.sell_how_much)/Ray(offer.buy_how_much),
                      max_source_amount=offer.buy_how_much,
                      method=f"opc.take({self.offer.offer_id})")
Ejemplo n.º 7
0
    def test_coax_and_way(self, sai: SaiDeployment):
        # given
        assert sai.tub.way() == Ray.from_number(1)

        # when
        sai.tub.coax(Ray.from_number(1.00000000000000007))

        # then
        assert sai.tub.way() == Ray.from_number(1.00000000000000007)
Ejemplo n.º 8
0
    def test_cuff_and_mat(self, sai: SaiDeployment):
        # given
        assert sai.tub.mat() == Ray.from_number(1)

        # when
        sai.tub.cuff(Ray.from_number(1.5))

        # then
        assert sai.tub.mat() == Ray.from_number(1.5)
Ejemplo n.º 9
0
    def test_crop_and_tax(self, sai: SaiDeployment):
        # given
        assert sai.tub.tax() == Ray.from_number(1)

        # when
        sai.tub.crop(Ray.from_number(1.00000000000000002))

        # then
        assert sai.tub.tax() == Ray.from_number(1.00000000000000002)
Ejemplo n.º 10
0
    def test_chop_and_axe(self, sai: SaiDeployment):
        # given
        assert sai.tub.axe() == Ray.from_number(1)
        sai.tub.cuff(Ray.from_number(1.5))

        # when
        sai.tub.chop(Ray.from_number(1.2))

        # then
        assert sai.tub.axe() == Ray.from_number(1.2)
Ejemplo n.º 11
0
    def test_safe(self, sai: SaiDeployment):
        # given
        sai.tub.cuff(Ray.from_number(1.5))
        sai.tub.chop(Ray.from_number(1.2))

        # when
        sai.tub.open()

        # then
        assert sai.tub.safe(1)
Ejemplo n.º 12
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)
Ejemplo n.º 13
0
    def per(self) -> Ray:
        """Get the lps per ref ratio.

        Returns:
            The current lps per ref ratio.
        """
        return Ray(self._contract.call().per())
Ejemplo n.º 14
0
    def test_should_recognize_if_there_are_no_opportunities(
            self, token1, token2, token3):
        # 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')
        conversions = [conversion1, conversion2]
        base_token = token1

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

        # then
        assert len(opportunities) == 0
Ejemplo n.º 15
0
    def jar_bid(self) -> Ray:
        """Get the current `exit()` price (GEM per SKR).

        Returns:
            The GEM per SKR price that will be used on `exit()`.
        """
        return Ray(self._contractJar.call().bid())
Ejemplo n.º 16
0
    def mat(self) -> Ray:
        """Get the liquidation ratio.

        Returns:
            The liquidation ratio. `1.5` means the liquidation ratio is 150%.
        """
        return Ray(self._contractTub.call().mat())
Ejemplo n.º 17
0
 def __init__(self, tub: Tub):
     self.tub = tub
     super().__init__(source_token=self.tub.gem(),
                      target_token=self.tub.skr(),
                      rate=(Ray.from_number(1) / tub.jar_ask()),
                      max_source_amount=Wad.from_number(1000000),  #1 mio ETH = infinity ;)
                      method="tub.join()")
Ejemplo n.º 18
0
    def tax(self) -> Ray:
        """Get the stability fee.

        Returns:
            Per-second value of the stability fee. `1.0` means no stability fee.
        """
        return Ray(self._contractTub.call().tax())
Ejemplo n.º 19
0
    def way(self) -> Ray:
        """Get the holder fee (interest rate).

        Returns:
            Per-second value of the holder fee. `1.0` means no holder fee.
        """
        return Ray(self._contractTip.call().way())
Ejemplo n.º 20
0
    def total_rate(self) -> Ray:
        """Calculates the multiplication of all conversion rates forming this sequence.

        A `total_rate` > 1.0 is a general indication that executing this sequence may be profitable.
        """
        return reduce(operator.mul, map(lambda step: step.rate, self.steps),
                      Ray.from_number(1.0))
Ejemplo n.º 21
0
    def fix(self) -> Ray:
        """Get the GEM per SAI settlement price.

        Returns:
            The GEM per SAI settlement (kill) price.
        """
        return Ray(self._contract.call().fix())
Ejemplo n.º 22
0
    def jar_ask(self) -> Ray:
        """Get the current `join()` price (GEM per SKR).

        Returns:
            The GEM per SKR price that will be used on `join()`.
        """
        return Ray(self._contractJar.call().ask())
Ejemplo n.º 23
0
    def axe(self) -> Ray:
        """Get the liquidation penalty.

        Returns:
            The liquidation penalty. `1.0` means no penalty. `1.2` means 20% penalty.
        """
        return Ray(self._contractTub.call().axe())
Ejemplo n.º 24
0
    def fit(self) -> Ray:
        """Get the GEM per SKR settlement price.

        Returns:
            The GEM per SKR settlement (kill) price.
        """
        return Ray(self._contractTub.call().fit())
Ejemplo n.º 25
0
 def __init__(self, tub: Tub, tap: Tap):
     self.tub = tub
     self.tap = tap
     super().__init__(source_token=self.tub.skr(),
                      target_token=self.tub.sai(),
                      rate=Ray(tap.bid()),
                      max_source_amount=self.boomable_amount_in_skr(tap),
                      method="tub.boom()")
Ejemplo n.º 26
0
def test_nicely_convert_to_string_without_amounts(token1, token2):
    # given
    conversion = Conversion(token1, token2, Ray.from_number(1.01),
                            Wad.from_number(1000), 'met()')

    # expect
    assert str(
        conversion
    ) == "[TK1 -> TK2 @1.010000000000000000000000000 by met() (max=1000.000000000000000000 TK1)]"
Ejemplo n.º 27
0
    def test_should_identify_opportunity(self, token1, token2):
        # given
        conversion1 = Conversion(token1, token2, Ray.from_number(1.02),
                                 Wad.from_number(10000), 'met1')
        conversion2 = Conversion(token2, token1, Ray.from_number(1.03),
                                 Wad.from_number(10000), 'met2')
        conversions = [conversion1, conversion2]
        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) == 2
        assert opportunities[0].steps[0].method == "met1"
        assert opportunities[0].steps[1].method == "met2"
Ejemplo n.º 28
0
 def __init__(self, lpc: Lpc):
     self.lpc = lpc
     rate = Ray(self.lpc.par() / (self.lpc.tag() * self.lpc.gap()))
     #TODO we always leave 0.000001 in the liquidity pool, in case of some rounding errors
     max_entry_ref = Wad.max((ERC20Token(web3=lpc.web3, address=lpc.alt()).balance_of(lpc.address) / Wad(rate)) - Wad.from_number(0.000001), Wad.from_number(0))
     super().__init__(source_token=self.lpc.ref(),
                      target_token=self.lpc.alt(),
                      rate=rate,
                      max_source_amount=max_entry_ref,
                      method="lpc.take(alt)")
Ejemplo n.º 29
0
    def test_should_identify_all_opportunities_regardless_whether_they_are_profitable(
            self, token1, token2):
        # given
        conversion1 = Conversion(token1, token2, Ray.from_number(1.1),
                                 Wad.from_number(10000), 'met1')
        conversion2 = Conversion(token2, token1, Ray.from_number(0.6),
                                 Wad.from_number(10000), 'met2')
        conversions = [conversion1, conversion2]
        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) == 2
        assert opportunities[0].steps[0].method == "met1"
        assert opportunities[0].steps[1].method == "met2"
Ejemplo n.º 30
0
 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