def test_multiply_by_ray(self): assert Wad.from_number(2) * Ray.from_number(3) == Wad.from_number(6) assert Wad.from_number(2) * Ray(3) == Wad(0) assert Wad(2) * Ray(499999999999999999999999999) == Wad(0) assert Wad(2) * Ray(500000000000000000000000000) == Wad(1) assert Wad(2) * Ray(999999999999999999999999999) == Wad(1) assert Wad(2) * Ray(1000000000000000000000000000) == Wad(2)
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})")
def test_crop_and_tax(self, sai: SaiDeployment): # given assert sai.tub.tax() == Ray.from_number(1) # when sai.tub.crop(Ray(1000000000000000020000000000)).transact() # then assert sai.tub.tax() == Ray(1000000000000000020000000000)
def test_coax_and_way(self, sai: SaiDeployment): # given assert sai.tub.way() == Ray.from_number(1) # when sai.tub.coax(Ray(1000000000000000070000000000)).transact() # then assert sai.tub.way() == Ray(1000000000000000070000000000)
def test_divide(self): assert Ray.from_number(4) / Ray.from_number(2) == Ray.from_number(2) assert Ray(4) / Ray.from_number(2) == Ray(2) assert Ray(3) / Ray.from_number(2) == Ray(1) assert Ray(39) / Ray.from_number(20) == Ray(1) assert Ray(40) / Ray.from_number(20) == Ray(2) assert Ray.from_number(0.2) / Ray.from_number(0.1) == Ray.from_number( 2)
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())
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())
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())
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())
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())
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())
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())
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())
def per(self) -> Ray: """Get the lps per ref ratio. Returns: The current lps per ref ratio. """ return Ray(self._contract.call().per())
def test_joy_and_boom(self, sai: SaiDeployment): # given sai.tub.join(Wad.from_number(10)).transact() sai.tub.cork(Wad.from_number(100000)).transact() sai.tub.crop(Ray(1000100000000000000000000000)).transact() DSValue(web3=sai.web3, address=sai.tub.pip()).poke_with_int( Wad.from_number(250).value).transact() # and sai.tub.open().transact() sai.tub.lock(1, Wad.from_number(4)).transact() sai.tub.draw(1, Wad.from_number(1000)).transact() # when sai.tub.drip().transact() sai.tub.warp(3600).transact() sai.tub.drip().transact() # then assert sai.skr.balance_of(sai.our_address) == Wad.from_number(6) assert sai.tap.joy() == Wad(433303616582911495481) # when sai.tap.boom(Wad.from_number(1)).transact() # then assert sai.skr.balance_of(sai.our_address) == Wad.from_number(5) assert sai.tap.joy() == Wad(183303616582911495481)
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()")
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()")
def per(self) -> Ray: """Get the current average entry/exit price (GEM per SKR). In order to get the price that will be actually used on `join()` or `exit()`, see `jar_ask()` and `jar_bid()` respectively. Returns: The current GEM per SKR price. """ return Ray(self._contractJar.call().per())
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
def chi(self) -> Ray: """Get the internal debt price. Every invocation of this method calls `drip()` internally, so the value you receive is always up-to-date. But as calling it doesn't result in an Ethereum transaction, the actual `_chi` value in the smart contract storage does not get updated. Returns: The internal debt price in SAI. """ return Ray(self._contractTub.call().chi())
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
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)")
def test_prod_and_par_and_tau(self, sai: SaiDeployment): # given sai.tub.coax(Ray(1000000000000000070000000000)).transact() old_par = sai.tub.par() old_tau = sai.tub.tau() # when sai.tub.warp(1000).transact() sai.tub.prod().transact() # then assert sai.tub.par() > old_par assert sai.tub.tau() > old_tau
def test_drip_and_chi_and_rho(self, sai: SaiDeployment): # given sai.tub.crop(Ray(1000000000000000020000000000)).transact() old_chi = sai.tub.chi() old_rho = sai.tub.rho() # when sai.tub.warp(1000).transact() sai.tub.drip().transact() # then assert sai.tub.chi() > old_chi assert sai.tub.rho() > old_rho
def test_should_reject_comparison_with_ints(self): with pytest.raises(ArithmeticError): assert Ray(1000) == 100 with pytest.raises(ArithmeticError): assert Ray(1000) != 999 with pytest.raises(ArithmeticError): assert Ray(1000) > 999 with pytest.raises(ArithmeticError): assert Ray(999) < 1000 with pytest.raises(ArithmeticError): assert Ray(999) <= 1000 with pytest.raises(ArithmeticError): assert Ray(1000) <= 1000 with pytest.raises(ArithmeticError): assert Ray(1000) >= 1000 with pytest.raises(ArithmeticError): assert Ray(1000) >= 999
def test_should_reject_comparison_with_rays(self): with pytest.raises(ArithmeticError): assert Wad(1000) == Ray(1000) with pytest.raises(ArithmeticError): assert Wad(1000) != Ray(999) with pytest.raises(ArithmeticError): assert Wad(1000) > Ray(999) with pytest.raises(ArithmeticError): assert Wad(999) < Ray(1000) with pytest.raises(ArithmeticError): assert Wad(999) <= Ray(1000) with pytest.raises(ArithmeticError): assert Wad(1000) <= Ray(1000) with pytest.raises(ArithmeticError): assert Wad(1000) >= Ray(1000) with pytest.raises(ArithmeticError): assert Wad(1000) >= Ray(999)
def test_should_reject_comparison_with_wads(self): with pytest.raises(ArithmeticError): assert Ray(1000) == Wad(1000) with pytest.raises(ArithmeticError): assert Ray(1000) != Wad(999) with pytest.raises(ArithmeticError): assert Ray(1000) > Wad(999) with pytest.raises(ArithmeticError): assert Ray(999) < Wad(1000) with pytest.raises(ArithmeticError): assert Ray(999) <= Wad(1000) with pytest.raises(ArithmeticError): assert Ray(1000) <= Wad(1000) with pytest.raises(ArithmeticError): assert Ray(1000) >= Wad(1000) with pytest.raises(ArithmeticError): assert Ray(1000) >= Wad(999)
def test_should_format_to_string_nicely(self): assert str(Ray(1)) == "0.000000000000000000000000001" assert str(Ray( 500000000000000000000000000)) == "0.500000000000000000000000000" assert str(Ray( 1500000000000000000000000000)) == "1.500000000000000000000000000" assert str(Ray( -1500000000000000000000000000)) == "-1.500000000000000000000000000" assert str(Ray( -500000000000000000000000000)) == "-0.500000000000000000000000000" assert str(Ray(-1)) == "-0.000000000000000000000000001"
def set_amounts(self, initial_amount: Wad): def recalculate_previous_amounts(from_step_id: int): for id in range(from_step_id, -1, -1): self.steps[id].target_amount = self.steps[id + 1].source_amount self.steps[id].source_amount = Wad( Ray(self.steps[id].target_amount) / self.steps[id].rate) assert (isinstance(initial_amount, Wad)) for i in range(len(self.steps)): if i == 0: self.steps[0].source_amount = initial_amount else: self.steps[i].source_amount = self.steps[i - 1].target_amount if self.steps[i].source_amount > self.steps[i].max_source_amount: self.steps[i].source_amount = self.steps[i].max_source_amount recalculate_previous_amounts(i - 1) self.steps[i].target_amount = Wad( Ray(self.steps[i].source_amount) * self.steps[i].rate)
def recalculate_previous_amounts(from_step_id: int): for id in range(from_step_id, -1, -1): self.steps[id].target_amount = self.steps[id + 1].source_amount self.steps[id].source_amount = Wad( Ray(self.steps[id].target_amount) / self.steps[id].rate)