Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- tad_contract = importlib.import_module('con_tad_tst_001')
- vaults = Hash(default_value=0)
- stability_rate = Hash(default_value=1)
- cdp = Hash(default_value=0)
- stability_pool = Hash(default_value=0)
- temporary_var = Variable()
- @construct
- def seed():
- vaults['OWNER'] = ctx.caller
- cdp['current_value'] = 0
- vaults['list'] = [0]
- vaults['current_number'] = 1
- vaults['oracle'] = 'oracle' # dummy for testing purposes
- vaults[0, 'collateral_type'] = 'currency'
- vaults[0, 'minimum_collateralization'] = 1.5
- vaults[0, 'minimum_auction_time'] = 259200
- vaults[0, 'cap'] = 100000
- vaults[0, 'weight'] = 10
- stability_rate[0] = 1.0000000015469297 # default value, change on deployment
- @export
- def get_timestamp():
- # https://developers.lamden.io/docs/smart-contracts/datetime-module/
- td = now - datetime.datetime(1970, 1, 1, 0, 0, 0)
- return fix_decimal(td.seconds)
- @export
- def create_vault(vault_type: int, amount_of_tad: float,
- amount_of_collateral: float):
- assert vault_type in vaults['list'], 'Not an available contract!'
- # interface enforcement is unnecessary because collateral types should be pre-vetted
- collateral = importlib.import_module(
- vaults[vault_type, 'collateral_type'])
- oracle = importlib.import_module(vaults['oracle'])
- price = oracle.get_price(vault_type)
- assert amount_of_tad > 0, 'Amount of tad must be positive!'
- assert vaults[vault_type, 'total'] + amount_of_tad <= vaults[vault_type,
- 'cap'], 'The allowance is not sufficent!'
- assert fix_decimal((amount_of_collateral * price) / \
- amount_of_tad) >= vaults[vault_type,
- 'minimum_collateralization'], 'Not enough collateral!'
- cdp_number = cdp['current_value']
- cdp['current_value'] += 1
- cdp[cdp_number, 'owner'] = ctx.caller
- cdp[cdp_number, 'open'] = True
- cdp[cdp_number, 'collateral_type'] = vaults[vault_type, 'collateral_type']
- cdp[cdp_number, 'vault_type'] = vault_type
- cdp[cdp_number, 'tad'] = amount_of_tad
- cdp[cdp_number, 'collateral_amount'] = amount_of_collateral
- cdp[cdp_number, 'time'] = get_timestamp()
- collateral.approve(amount=amount_of_collateral, to=ctx.this)
- collateral.transfer_from(amount=amount_of_collateral,
- to=ctx.this, main_account=ctx.caller)
- tad_contract.mint(amount=amount_of_tad)
- tad_contract.transfer(amount=amount_of_tad, to=ctx.caller)
- vaults[vault_type, 'issued'] += amount_of_tad
- vaults[vault_type, 'total'] += amount_of_tad
- return cdp_number
- @export
- def close_vault(cdp_number: int):
- assert cdp[cdp_number, 'owner'] == ctx.caller, 'Not the owner!'
- assert cdp[cdp_number, 'open'] == True, 'Vault has already been closed!'
- collateral = importlib.import_module(
- vaults[cdp[cdp_number, 'vault_type'], 'collateral_type'])
- stability_ratio = fix_decimal(vaults[cdp[cdp_number, 'vault_type'], 'total'] / \
- vaults[cdp[cdp_number, 'vault_type'], 'issued'])
- redemption_cost = cdp[cdp_number, 'tad'] * stability_ratio
- fee = redemption_cost * \
- (stability_rate[cdp[cdp_number, 'vault_type']] **
- (get_timestamp() - cdp[cdp_number, 'time'])) - redemption_cost
- amount = redemption_cost + fee
- tad_contract.transfer_from(
- amount=amount, to=ctx.this, main_account=ctx.caller)
- tad_contract.burn(amount=redemption_cost)
- stability_pool[cdp[cdp_number, 'vault_type']] += fee
- vaults[cdp[cdp_number, 'vault_type'], 'issued'] -= cdp[cdp_number, 'tad']
- # This is only different if the ratio is different
- vaults[cdp[cdp_number, 'vault_type'], 'total'] -= redemption_cost
- cdp[cdp_number, 'open'] = False
- # Return collateral
- collateral.transfer(
- amount=cdp[cdp_number, 'collateral_amount'], to=ctx.caller)
- return amount
- @export
- def fast_force_close_vault(cdp_number: int):
- assert_insufficent_collateral(cdp_number=cdp_number)
- assert cdp[cdp_number, 'open'] is True, 'Vault has already been closed!'
- collateral = importlib.import_module(
- vaults[cdp[cdp_number, 'vault_type'], 'collateral_type'])
- oracle = importlib.import_module(vaults['oracle'])
- stability_ratio = fix_decimal(vaults[cdp[cdp_number, 'vault_type'],
- 'total'] / vaults[cdp[cdp_number, 'vault_type'], 'issued'])
- redemption_cost_without_fee = cdp[cdp_number,
- 'tad'] * stability_ratio
- redemption_cost = redemption_cost_without_fee * fix_decimal(1.1)
- fee = redemption_cost_without_fee * \
- (stability_rate[cdp[cdp_number, 'vault_type']]
- ** (get_timestamp() - cdp[cdp_number, 'time'])) - redemption_cost_without_fee
- redemption_cost += fee
- amount_of_collateral = cdp[cdp_number, 'collateral_amount']
- price = oracle.get_price(cdp[cdp_number, 'vault_type'])
- collateral_percent = fix_decimal((amount_of_collateral * price) / \
- redemption_cost)
- if collateral_percent >= fix_decimal(1.03):
- tad_contract.transfer_from(
- amount=redemption_cost, to=ctx.this, main_account=ctx.caller)
- tad_contract.burn(amount=redemption_cost_without_fee)
- amount = fix_decimal((redemption_cost * fix_decimal(1.03)) / price) # Double check this math is correct
- collateral.transfer(amount=amount, to=ctx.caller)
- collateral.transfer(amount=amount_of_collateral -
- amount, to=cdp[cdp_number, 'owner'])
- vaults[cdp[cdp_number, 'vault_type'],
- 'issued'] -= cdp[cdp_number, 'tad']
- vaults[cdp[cdp_number, 'vault_type'],
- 'total'] -= redemption_cost_without_fee
- else:
- redemption_cost, redemption_cost_without_fee = redemption_cost * \
- fix_decimal(collateral_percent / fix_decimal(1.03)), redemption_cost_without_fee * \
- fix_decimal(collateral_percent / fix_decimal(1.03))
- tad_contract.transfer_from(
- amount=redemption_cost, to=ctx.this, main_account=ctx.caller)
- tad_contract.burn(amount=redemption_cost_without_fee)
- amount = cdp[cdp_number, 'collateral_amount']
- collateral.transfer(amount=amount, to=ctx.caller)
- vaults[cdp[cdp_number, 'vault_type'],
- 'issued'] -= cdp[cdp_number, 'tad']
- vaults[cdp[cdp_number, 'vault_type'],
- 'total'] -= redemption_cost_without_fee
- stability_pool[cdp[cdp_number, 'vault_type']
- ] += redemption_cost - redemption_cost_without_fee
- cdp[cdp_number, 'open'] = False
- return amount
- @export
- def open_force_close_auction(cdp_number: int):
- assert_insufficent_collateral(cdp_number=cdp_number)
- assert cdp[cdp_number, 'owner'] != 0, 'Nonexistent cdp'
- assert cdp[cdp_number, 'auction',
- 'open'] is not True, 'Auction is already taking place!' # Probably a redundant check, can be removed
- assert cdp[cdp_number, 'open'] is True, 'Vault has already been closed!'
- # This contract may only be bid on, and not closed
- cdp[cdp_number, 'open'] = False
- cdp[cdp_number, 'auction', 'open'] = True
- cdp[cdp_number, 'auction', 'highest_bidder'] = ctx.caller
- cdp[cdp_number, 'auction', 'top_bid'] = 0.0
- cdp[cdp_number, 'auction', 'time'] = get_timestamp()
- return True
- @export
- def bid_on_force_close(cdp_number: int, amount: float):
- assert cdp[cdp_number, 'owner'] != 0, 'Nonexistent cdp'
- assert cdp[cdp_number, 'auction',
- 'open'] is True, 'Auction is not open!'
- assert amount > cdp[cdp_number, 'auction',
- 'top_bid'], 'There is already a higher bid!'
- if cdp[cdp_number, 'auction', ctx.caller, 'bid'] is not None:
- tad_contract.transfer_from(
- amount=amount - cdp[cdp_number, 'auction', ctx.caller, 'bid'],
- to=ctx.this, main_account=ctx.caller)
- else:
- tad_contract.transfer_from(
- amount=amount, to=ctx.this, main_account=ctx.caller)
- cdp[cdp_number, 'auction', 'highest_bidder'] = ctx.caller
- cdp[cdp_number, 'auction', 'top_bid'] = amount
- cdp[cdp_number, 'auction', ctx.caller, 'bid'] = amount
- return True
- @export
- def settle_force_close(cdp_number: int):
- assert cdp[cdp_number, 'owner'] != 0, 'Nonexistent cdp'
- assert cdp[cdp_number, 'auction', 'open'] is True, 'Auction is not open!'
- assert get_timestamp() - cdp[cdp_number, 'auction', 'time'] > vaults[cdp[cdp_number, 'vault_type'],
- 'minimum_auction_time'], 'Auction is still open!'
- collateral = importlib.import_module(
- vaults[cdp[cdp_number, 'vault_type'], 'collateral_type'])
- cdp[cdp_number, 'auction', 'settled'] = True
- cdp[cdp_number, 'open'] = False
- cdp[cdp_number, 'auction', 'open'] = False
- cdp[cdp_number, 'auction', cdp[cdp_number,
- 'auction', 'highest_bidder'], 'bid'] = 0
- fee = cdp[cdp_number, 'auction', 'top_bid'] * 0.1
- collateral.transfer_from(
- amount=cdp[cdp_number, 'collateral_amount'], to=ctx.caller, main_account=ctx.this)
- tad_contract.burn(amount=cdp[cdp_number, 'auction', 'top_bid'] - fee)
- stability_pool[cdp[cdp_number, 'vault_type']] += fee
- vaults[cdp[cdp_number, 'vault_type'], 'issued'] -= cdp[cdp_number, 'tad']
- vaults[cdp[cdp_number, 'vault_type'],
- 'total'] -= cdp[cdp_number, 'auction', 'top_bid'] - fee # Fee is not burned, so it does not count
- return cdp[cdp_number, 'auction', 'highest_bidder'], cdp[cdp_number,
- 'auction', 'top_bid']
- @export
- def claim_unwon_bid(cdp_number: int):
- assert cdp[cdp_number, 'owner'] != 0, 'Nonexistent cdp'
- assert cdp[cdp_number, 'auction',
- 'settled'] is True, 'Auction is still open or not opened!'
- tad_contract.transfer(
- to=ctx.caller, amount=cdp[cdp_number, 'auction', ctx.caller, 'bid'])
- cdp[cdp_number, 'auction', ctx.caller, 'bid'] = 0
- return True
- @export
- def sync_stability_pool(vault_type: int):
- assert vault_type in vaults['list'], 'Not an available contract!'
- default_amount = vaults[vault_type, 'total'] - vaults[vault_type, 'issued']
- if default_amount > stability_pool[vault_type]:
- vaults[vault_type, 'issued'] += stability_pool[vault_type]
- stability_pool[vault_type] = 0
- # Return new ratio
- return fix_decimal(vaults[vault_type, 'issued'] / vaults[vault_type, 'total'])
- else: # This also applies to negatives and zeros, although those situations are unlikely
- vaults[vault_type, 'issued'] = vaults[vault_type, 'total']
- stability_pool[vault_type] -= default_amount
- return 1.0 # The ratio is perfectly equal
- @export
- def export_rewards(vault_type: int, amount: float):
- assert vaults[vault_type, 'DSR', 'owner'] == ctx.caller, 'Not the owner!'
- assert stability_pool[vault_type] >= amount, 'Not enough tad in stability pool to export!'
- stability_pool[vault_type] -= amount
- tad_contract.transfer(to=ctx.caller, amount=amount)
- return True
- @export
- def mint_rewards(amount: float):
- assert vaults['mint', 'DSR', 'owner'] == ctx.caller, 'Not the owner!'
- assert amount > 0, 'Cannot mint negative amount!'
- tad_contract.mint(amount=amount)
- tad_contract.transfer(to=ctx.caller, amount=amount)
- total_weight = 0
- total_funds = amount
- for vault_type in vaults['list']:
- total_weight += vaults[vault_type, 'weight']
- # To make the contract more robust, and to prevent floating point errors
- for vault_type in vaults['list']:
- funds_transferred = fix_decimal(
- vaults[vault_type, 'weight'] / total_weight) * total_funds
- vaults[vault_type, 'total'] += funds_transferred
- total_funds -= funds_transferred
- total_weight -= vaults[vault_type, 'weight']
- return True
- @export
- def sync_burn(vault_type: int, amount: float):
- assert vault_type in vaults['list'], 'Not an available contract!'
- tad_contract.transfer_from(
- to=ctx.this, amount=amount, main_account=ctx.caller)
- tad_contract.burn(amount=amount)
- vaults[vault_type, 'total'] -= amount
- return vaults[vault_type, 'total']
- @export
- def add_vault(collateral_type: str, collateral_amount: float, auction_time: float,
- max_minted: float, s_rate: float, weight: float):
- assert vaults['OWNER'] == ctx.caller, 'Not the owner!'
- vault_number = vaults['current_number']
- vaults['list'].append(vault_number)
- vaults['current_number'] += 1
- vaults[vault_number, 'collateral_type'] = collateral_type
- vaults[vault_number, 'minimum_collateralization'] = collateral_amount
- vaults[vault_number, 'minimum_auction_time'] = auction_time
- vaults[vault_number, 'cap'] = max_minted
- vaults[vault_number, 'weight'] = weight
- stability_rate[vault_number] = s_rate
- return vault_number
- @export
- def remove_vault(vault_type: int):
- assert vaults['OWNER'] == ctx.caller, 'Not the owner!'
- vaults['list'].remove(vault_type)
- @export
- def change_state(key: str, new_value: str, convert_to_decimal: bool = False):
- assert vaults['OWNER'] == ctx.caller, 'Not the owner!'
- assert type(key) == str, 'Invalid type for key'
- assert type(new_value) == str, 'Invalid type for new value'
- if convert_to_decimal:
- new_value = decimal(new_value)
- vaults[key] = new_value
- return new_value
- @export
- def change_any_state(key: Any, new_value: Any, convert_to_tuple: bool = False):
- assert vaults['OWNER'] == ctx.caller, 'Not the owner!'
- if convert_to_tuple:
- key = tuple(key)
- vaults[key] = new_value
- return new_value
- @export
- def change_stability_rate(key: int, new_value: float):
- assert vaults['OWNER'] == ctx.caller, 'Not the owner!'
- stability_rate[key] = new_value
- return new_value
- @export
- def get_collateralization_percent(cdp_number: int):
- assert cdp[cdp_number, 'owner'] != 0, 'Nonexistent cdp'
- oracle = importlib.import_module(vaults['oracle'])
- return cdp[cdp_number, 'collateral_amount'] * oracle.get_price(cdp[cdp_number, 'vault_type']) / cdp[cdp_number, 'tad']
- def assert_insufficent_collateral(cdp_number: int):
- assert cdp[cdp_number, 'owner'] != 0, 'Nonexistent cdp'
- oracle = importlib.import_module(vaults['oracle'])
- assert (cdp[cdp_number, 'collateral_amount'] * oracle.get_price(cdp[cdp_number, 'vault_type']) / cdp[cdp_number, 'tad']) < \
- vaults[cdp[cdp_number, 'collateral_type'], 'minimum_collateralization'], 'Vault above minimum collateralization!'
- def fix_decimal(old_decimal: float):
- temporary_var.set(old_decimal)
- new_decimal = temporary_var.get()
- return new_decimal
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement