From 110d449caceb1a97ac8698bdece1882ae43555da Mon Sep 17 00:00:00 2001 From: Andrew Chiw Date: Wed, 25 Mar 2020 01:11:48 +0100 Subject: [PATCH] initial commit of AugmentedBondingCurve --- abcurve.py | 76 +++++++++++++++++++++++++++++++++++++++++++++++++ abcurve_test.py | 43 ++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+) create mode 100644 abcurve.py create mode 100644 abcurve_test.py diff --git a/abcurve.py b/abcurve.py new file mode 100644 index 0000000..cd51ba5 --- /dev/null +++ b/abcurve.py @@ -0,0 +1,76 @@ +#value function for a given state (R,S) +def invariant(R,S,kappa): + return (S**kappa)/R + +#given a value function (parameterized by kappa) +#and an invariant coeficient V0 +#return Supply S as a function of reserve R +def supply(R, kappa, V0): + return (V0*R)**(1/kappa) + +#given a value function (parameterized by kappa) +#and an invariant coeficient V0 +#return a spot price P as a function of reserve R +def spot_price(R, kappa, V0): + return kappa*R**((kappa-1)/kappa)/V0**(1/kappa) + +#for a given state (R,S) +#given a value function (parameterized by kappa) +#and an invariant coeficient V0 +#deposit deltaR to Mint deltaS +#with realized price deltaR/deltaS +def mint(deltaR, R,S, kappa, V0): + deltaS = (V0*(R+deltaR))**(1/kappa)-S + realized_price = deltaR/deltaS + return deltaS, realized_price + +#for a given state (R,S) +#given a value function (parameterized by kappa) +#and an invariant coeficient V0 +#burn deltaS to Withdraw deltaR +#with realized price deltaR/deltaS +def withdraw(deltaS, R,S, kappa, V0): + deltaR = R-((S-deltaS)**kappa)/V0 + realized_price = deltaR/deltaS + return deltaR, realized_price + +class AugmentedBondingCurve: + def __init__(self, initial_reserve, initial_token_supply, kappa=2): + """Create a stateful bonding curve. + + initial_reserve (millions of DAI) + initial_token_supply (millions) + kappa (the exponent part of the curve, default is 2) + """ + self.initial_reserve = initial_reserve + self.initial_token_supply = initial_token_supply + + self.current_reserve = self.initial_reserve + self.current_token_supply = self.initial_token_supply + + self.kappa = kappa + self.invariant = (self.initial_token_supply**kappa) / self.initial_reserve + + def __repr__(self): + return "ABC Reserve {} million; Token_Supply {} million; Current Token Price {}".format(self.current_reserve, self.current_token_supply, self.get_token_price()) + + def deposit(self, dai_million): + # Returns number of new tokens minted, and their realized price + tokens, realized_price = mint(dai_million, self.current_reserve, self.current_token_supply, self.kappa, self.invariant) + + self.current_reserve += dai_million + self.current_token_supply += tokens + return tokens, realized_price + + def burn(self, tokens_million): + # Returns number of DAI that will be returned (excluding exit tribute) when the user burns their tokens, with their realized price + dai_million, realized_price = withdraw(tokens_million, self.current_reserve, self.current_token_supply, self.kappa, self.invariant) + self.current_reserve -= dai_million + self.current_token_supply -= tokens_million + return dai_million, realized_price + + def get_token_price(self): + return spot_price(self.current_reserve, self.kappa, self.invariant) + + def get_token_supply(self): + return supply(self.current_reserve, self.kappa, self.invariant) diff --git a/abcurve_test.py b/abcurve_test.py new file mode 100644 index 0000000..b3745b7 --- /dev/null +++ b/abcurve_test.py @@ -0,0 +1,43 @@ +from abcurve import AugmentedBondingCurve +import unittest + +class TestAugmentedBondingCurve(unittest.TestCase): + def test_get_token_supply(self): + # R = 1, S0 = 1, V0 = 1.0, kappa = 2 should give this data: + # [0 1 2 3 4 5 6 7 8 9] -> [0.0, 1.0, 1.4142135623730951, 1.7320508075688772, 2.0, 2.23606797749979, 2.449489742783178, 2.6457513110645907, 2.8284271247461903, 3.0] + abc = AugmentedBondingCurve(1, 1, kappa=2) + self.assertEqual(abc.get_token_supply(), 1) + + abc.current_reserve = 2 + self.assertEqual(abc.get_token_supply(), 1.4142135623730951) + + def test_get_token_price(self): + # [0 1 2 3 4 5 6 7 8 9] -> [0.0, 0.02, 0.0282842712474619, 0.034641016151377546, 0.04, 0.044721359549995794, 0.04898979485566356, 0.052915026221291815, 0.0565685424949238, 0.06] + abc = AugmentedBondingCurve(1, 1, kappa=2) + self.assertEqual(abc.get_token_price(), 2.0) + + abc.current_reserve = 2 + self.assertEqual(abc.get_token_price(), 2.8284271247461903) + + def test_deposit(self): + abc = AugmentedBondingCurve(1, 1, kappa=2) + old_current_reserve = abc.current_reserve + old_token_supply = abc.current_token_supply + # print(abc) + tokens, realized_price = abc.deposit(4) + # print("The current price is", realized_price, "and you will get", tokens, "million tokens") + self.assertEqual(abc.current_token_supply, old_token_supply + tokens) + self.assertEqual(abc.current_reserve, old_current_reserve + 4) + # print(abc) + + def test_burn(self): + abc = AugmentedBondingCurve(1, 1, kappa=2) + + dai_million_returned, realized_price = abc.burn(0.5) + self.assertEqual(dai_million_returned, 0.75) + self.assertEqual(realized_price, 1.5) + + self.assertEqual(abc.current_reserve, 0.25) + self.assertEqual(abc.current_token_supply, 0.5) + self.assertLess(abc.current_reserve, abc.initial_reserve) + self.assertLess(abc.current_token_supply, abc.initial_token_supply) \ No newline at end of file