contributions_to_token_batches(): takes desired_token_price as argument

TokenBatch: self.current_date to be set externally, unittests updated
Commons unittest: initialization and burn()
This commit is contained in:
Andrew Chiw 2020-05-08 01:14:21 +02:00
parent dd98402875
commit b77bb3a87e
2 changed files with 42 additions and 29 deletions

View File

@ -26,13 +26,14 @@ def hatch_raise_split_pools(total_hatch_raise, hatch_tribute) -> Tuple[float, fl
collateral_pool = total_hatch_raise * (1-hatch_tribute)
return funding_pool, collateral_pool
def contributions_to_token_batches(hatcher_contributions: List[int], initial_token_supply: int, vesting_80p_unlocked: int) -> List[float]:
def contributions_to_token_batches(hatcher_contributions: List[int], desired_token_price: float, vesting_80p_unlocked: int) -> Tuple[List[float], float]:
"""
hatcher_contributions: a list of hatcher contributions
initial_token_supply: NOT denominated in millions
hatcher_contributions: a list of hatcher contributions in DAI/ETH/whatever
desired_token_price: used to determine the initial token supply
vesting_80p_unlocked: vesting parameter - the number of days after which 80% of tokens will be unlocked, including the cliff period
"""
total_hatch_raise = sum(hatcher_contributions)
initial_token_supply = total_hatch_raise / desired_token_price
# In the hatch, everyone buys in at the same time, with the same price. So just split the token supply amongst the hatchers proportionally to their contributions
tokens_per_hatcher = [(x / total_hatch_raise) * initial_token_supply for x in hatcher_contributions]
@ -40,7 +41,7 @@ def contributions_to_token_batches(hatcher_contributions: List[int], initial_tok
cliff_days, halflife_days = convert_80p_to_cliff_and_halflife(vesting_80p_unlocked)
token_batches = [TokenBatch(x, cliff_days, halflife_days, hatch=True) for x in tokens_per_hatcher]
return token_batches
return token_batches, initial_token_supply
class TokenBatch:
def __init__(self, value: float, cliff_days: int, halflife_days: int, hatch = False):
@ -51,16 +52,18 @@ class TokenBatch:
self.halflife_days = halflife_days
self.spent = 0
self.current_date = datetime.today() # to be set externally before each spend check
def __repr__(self):
o = "TokenBatch {} {}, Unlocked: {}".format("Hatch" if self.hatch_tokens else "", self.value, self.unlocked_fraction(datetime.today()))
o = "TokenBatch {} {}, Unlocked: {}".format("Hatch" if self.hatch_tokens else "", self.value, self.unlocked_fraction())
return o
def unlocked_fraction(self, day: datetime = datetime.today()) -> float:
def unlocked_fraction(self) -> float:
"""
returns what fraction of the TokenBatch is unlocked to date
"""
if self.hatch_tokens:
days_delta = day - self.creation_date
days_delta = self.current_date - self.creation_date
u = vesting_curve(days_delta.days, self.cliff_days, self.halflife_days)
return u if u > 0 else 0
else:
@ -72,7 +75,7 @@ class TokenBatch:
returns the argument if successful for your convenience
"""
if x > self.spendable():
raise Exception("Not so many tokens are available for you to spend yet!")
raise Exception("Not so many tokens are available for you to spend yet ({})".format(self.current_date))
self.value -= x
self.spent += x
@ -98,7 +101,7 @@ class Commons:
# Options
self.exit_tribute = exit_tribute
def deposit(self, dai):
"""
Deposit DAI after the hatch phase. This means all the incoming deposit goes to the collateral pool.
@ -118,8 +121,8 @@ class Commons:
money_returned = dai
if self.exit_tribute:
self._funding_pool += commons.exit_tribute * dai
money_returned = (1-commons.exit_tribute) * dai
self._funding_pool += self.exit_tribute * dai
money_returned = (1-self.exit_tribute) * dai
return money_returned, realized_price

View File

@ -2,7 +2,7 @@ from hatch import *
import unittest
import datetime
class TestHatch(unittest.TestCase):
class HatchTest(unittest.TestCase):
def test_vesting_curve(self):
self.assertEqual(vesting_curve(90, 90, 90), 0) # At Day 90, the cliff has just ended and the vesting curve has begun at 0
self.assertEqual(vesting_curve(180, 90, 90), 0.5) # At Day 180, the cliff has ended and we are in the vesting curve, whose half-life is 90 as well, so at 180 we should get 0.5.
@ -16,9 +16,11 @@ class TokenBatchTest(unittest.TestCase):
tbh = TokenBatch(10000, 3, 3, True)
tb = TokenBatch(10000, 5, 10, False)
self. assertEqual(tbh.unlocked_fraction(), 0)
tbh.current_date = datetime.datetime.today() + datetime.timedelta(days=3)
self.assertEqual(tbh.unlocked_fraction(), 0)
self.assertEqual(tbh.unlocked_fraction(datetime.datetime.today() + datetime.timedelta(days=3)), 0)
self.assertEqual(tbh.unlocked_fraction(datetime.datetime.today() + datetime.timedelta(days=6)), 0.5)
tbh.current_date = datetime.datetime.today() + datetime.timedelta(days=6)
self.assertEqual(tbh.unlocked_fraction(), 0.5)
self.assertEqual(tb.unlocked_fraction(), 1.0)
@ -39,22 +41,30 @@ class TokenBatchTest(unittest.TestCase):
with self.assertRaises(Exception):
tb.spend(10000)
class TestSystem(unittest.TestCase):
def test_system(self):
class CommonsTest(unittest.TestCase):
def setUp(self):
# 100,000 DAI invested for 1,000,000 tokens.
desired_token_price = 0.1
hatcher_contributions = [25000, 25000, 50000]
token_supply_initial = sum(hatcher_contributions) / desired_token_price
token_batches = contributions_to_token_batches(hatcher_contributions, token_supply_initial, 90)
self.desired_token_price = 0.1
self.hatcher_contributions = [25000, 25000, 50000]
self.token_batches, self.token_supply_initial = contributions_to_token_batches(self.hatcher_contributions, self.desired_token_price, 90)
# Because of hatch_tribute, the collateral_pool is 0.7e6. This causes the token's post-hatch price to be 0.14.
o = Commons(sum(hatcher_contributions), token_supply_initial, hatch_tribute=0.3)
self.assertEqual(o._collateral_pool, 70000)
self.assertEqual(o._funding_pool, 30000)
self.assertEqual(o._token_supply, token_supply_initial)
self.commons = Commons(sum(self.hatcher_contributions), self.token_supply_initial, hatch_tribute=0.3)
self.assertEqual(o.token_price(), 0.14)
print(token_batches)
# print(o.deposit(100))
# print(o.token_price())
# print(o._collateral_pool)
def test_initialization(self):
self.assertEqual(self.commons._collateral_pool, 70000)
self.assertEqual(self.commons._funding_pool, 30000)
self.assertEqual(self.commons._token_supply, self.token_supply_initial)
self.assertEqual(self.commons.token_price(), 0.14)
def test_burn_without_exit_tribute(self):
old_token_supply = self.commons._token_supply
old_collateral_pool = self.commons._collateral_pool
money_returned, realized_price = self.commons.burn(50000)
self.assertEqual(money_returned, 6825.0)
self.assertEqual(realized_price, 0.1365)
self.assertEqual(self.commons._token_supply, old_token_supply-50000)
self.assertEqual(self.commons._collateral_pool, old_collateral_pool-money_returned)