status-network-token/scripts/ceiling_curve_calc.py

141 lines
4.9 KiB
Python
Executable File

#!/usr/bin/env python3
''' Calculate ceiling characteristics based on curve parameters '''
import argparse
import decimal
from decimal import Decimal
import math
import statistics
from typing import List, Sequence
decimal.getcontext().rounding = decimal.ROUND_DOWN
def args_parse(arguments: Sequence[str] = None) -> argparse.Namespace:
''' Parse arguments '''
par0 = argparse.ArgumentParser(
description='Calculate ceiling characteristics based on curve parameters')
# Required
par0.add_argument('--limit', metavar='LIMIT', required=True, type=Decimal,
help='Ceiling limit')
par0.add_argument('--curve-factor', metavar='FACTOR', required=True, type=Decimal,
help='Curve factor')
# Optional
par0.add_argument('--collected-start', metavar='WEI', type=Decimal,
default=Decimal('0'), help='Amount collected at start of curve')
par0.add_argument('--gas-per-tx', metavar='AMOUNT', type=Decimal,
default=Decimal('71429'), help='Gas used per transaction')
par0.add_argument('--gas-price', metavar='WEI', type=Decimal,
default=Decimal('50000000000'), help='Gas price')
par0.add_argument('--fee-token', metavar='FRACTION', type=Decimal,
default=Decimal('0.1'), help='Fee cost as fraction of token value')
par0.add_argument('--collect-min', metavar='WEI', type=Decimal,
help='Minimum collection amount')
par0.add_argument('--gas-limit', metavar='AMOUNT', type=Decimal,
default=Decimal('4700000'), help='Gas limit per block')
par0.add_argument('--secs-per-block', metavar='SECONDS', type=Decimal,
default=Decimal('16.4'), help='Average seconds per block')
par0.add_argument('--print-txs', action='store_true',
default=False, help='Print every individual transaction')
args0 = par0.parse_args(arguments)
return args0
def transactions_calc(
limit: Decimal,
curve_factor: Decimal,
collect_minimum: Decimal,
collected_start: Decimal = Decimal(0),
) -> List[Decimal]:
''' Calculate transactions '''
collected = collected_start
transactions = []
while True:
difference = limit - collected
to_collect = difference / curve_factor
if to_collect <= collect_minimum:
if difference > collect_minimum:
to_collect = collect_minimum
else:
to_collect = difference
collected += to_collect
transactions.append(to_collect)
if collected >= limit:
break
return transactions
def fmt_wei(value: Decimal, shift: bool = False) -> str:
''' Format wei value '''
fmt_val = f'{value:.0f}'
if shift:
return f'{"w" + fmt_val: >26}' # type: ignore
return f'{"w" + fmt_val}' # type: ignore
def fmt_eth(value: Decimal, shift: bool = False) -> str:
''' Format wei value into ether '''
fmt_val = f'{value / 10**18:.18f}'
if shift:
return f'{"Ξ" + fmt_val: >26}' # type: ignore
return f'{"Ξ" + fmt_val}' # type: ignore
def main() -> None:
''' Main '''
tx_fee = ARGS.gas_per_tx * ARGS.gas_price
tx_fee_token_limit = tx_fee / ARGS.fee_token
collect_min = ARGS.collect_min if ARGS.collect_min is not None else tx_fee_token_limit
transactions = transactions_calc(
ARGS.limit,
ARGS.curve_factor,
collect_min,
collected_start=ARGS.collected_start,
)
collect_fee_total = 0
collect_minimum_total = 0
for n, transaction in enumerate(transactions):
if transaction <= collect_min:
collect_minimum_total += 1
if transaction < tx_fee_token_limit:
collect_fee_total += 1
if ARGS.print_txs:
print(f'{(n + 1): >4}: {fmt_wei(transaction, shift=True)} '
f' {fmt_eth(transaction, shift=True)}')
print()
print(f'Token fee limit: {fmt_wei(tx_fee_token_limit)} {fmt_eth(tx_fee_token_limit)}')
print(f'Minimum collect: {fmt_wei(collect_min)} {fmt_eth(collect_min)}')
transactions_len = len(transactions)
print(f'Number of transactions: {transactions_len}')
print(f'Number of transactions <= minimum collect: {collect_minimum_total}')
print(f'Number of transactions < token fee limit: {collect_fee_total}')
average = statistics.mean(transactions)
print(f'Average contribution: {fmt_wei(average)} {fmt_eth(average)}')
median = statistics.median(transactions)
print(f'Median contribution: {fmt_wei(median)} {fmt_eth(median)}')
decimal.getcontext().rounding = decimal.ROUND_HALF_EVEN
blocks = math.ceil((transactions_len * ARGS.gas_per_tx) / ARGS.gas_limit)
print(f'Minimum blocks for curve: {blocks}')
print(f'Minimum time for curve: {blocks * ARGS.secs_per_block:.2f}s')
decimal.getcontext().rounding = decimal.ROUND_DOWN
if __name__ == '__main__':
ARGS = args_parse()
main()