diff --git a/bin/MasterDistiller.py b/bin/MasterDistiller.py index 310153ead93e2fa1507253e8c10ec6028692aeb3..d1ff4f53324fd4f80ea88b5d33a0838451dfd09e 100755 --- a/bin/MasterDistiller.py +++ b/bin/MasterDistiller.py @@ -2,13 +2,16 @@ import sys import os +if not os.environ.get('BFAHOME'): + print("$BFAHOME not set. Did you source bfa/bin/env ?", file=sys.stderr) + exit(1) import json import re import decimal -os.environ['BFAHOME']='/home/bfa/bfa' +import argparse sys.path.append( os.path.join(os.environ['BFAHOME'],'bin' )) import libbfa -bfa = libbfa.Bfa('prod') +bfa = None notation = dict() janitor = None distillery = None @@ -16,7 +19,15 @@ distillery = None def distbalance() -> int: return bfa.w3.eth.getBalance(distillery.address) -def editAccount(entry:str, pallet:list): +def distribute(): + # trigger distribution + beforeBal = distbalance() + rcpt = janitor.transact( web3=bfa.w3, function=distillery.functions.distribute, extragas=4000000) + print('Distribute returned succesfully in block# {} using {} gas.'.format(rcpt.blockNumber, rcpt.gasUsed)) + afterBal = distbalance() + print('Distributed {} {}.'.format( int(decimal.Decimal(beforeBal - afterBal) / notation['num']), notation['name'])) + +def editAccount(entry:str, beneflist:list): acct = None # is it an account address? if entry == '': @@ -25,15 +36,10 @@ def editAccount(entry:str, pallet:list): elif re.search('^0x[0-9a-fA-F]{40}$', entry): acct = entry.lower() # is it a known account address? - elif re.search('^[0-9]+$', entry) and int(entry) < len(pallet): - acct = pallet[int(entry)].addr + elif re.search('^[0-9]+$', entry) and int(entry) < len(beneflist): + acct = beneflist[int(entry)].addr elif entry == 'x': - # trigger distribution - beforeBal = distbalance() - rcpt = janitor.transact( web3=bfa.w3, function=distillery.functions.distribute, extragas=4000000) - print('Distribute returned succesfully in block# {} using {} gas.'.format(rcpt.blockNumber, rcpt.gasUsed)) - afterBal = distbalance() - print('Distributed {} {}.'.format( int(decimal.Decimal(beforeBal - afterBal) / notation['num']), notation['name'])) + distribute() else: print('I do not know what to do with "{}".'.format(entry), file=sys.stderr) exit(1) @@ -51,27 +57,27 @@ def editAccount(entry:str, pallet:list): else: print('Update failed.') -def getPallet() -> list: +def getBeneficiaries() -> list: count = distillery.functions.numberOfBeneficiaries().call() - pallet = list() + beneflist = list() # Fetch addresses from the list in the contract. for i in range(count): print("Indexing accounts ({}/{})...\x1B[J\r".format(i,count), end='') (addr,topuplimit) = distillery.functions.atPosition(i).call() bal = bfa.w3.eth.getBalance( addr ) - pallet.append( { "addr": addr, "topuplimit": topuplimit, "balance": bal } ) + beneflist.append( { "addr": addr, "topuplimit": topuplimit, "balance": bal } ) print("\r\x1B[J".format(i,count), end='') s = lambda x:x['addr'].lower() - pallet.sort(key=s) - return pallet + beneflist.sort(key=s) + return beneflist -def printPallet(pallet:list): +def print_beneficiary_list(beneflist:list): # find the length of the longest number-string longestlimit = 1 longestbalance = 1 numformat = notation['strformat'].format - for i in range(len(pallet)): - entry = pallet[i] + for i in range(len(beneflist)): + entry = beneflist[i] numstr = numformat(decimal.Decimal(entry['topuplimit']) / notation['num']) thislen = len(numstr) if thislen > longestlimit: @@ -81,9 +87,18 @@ def printPallet(pallet:list): if thislen > longestbalance: longestbalance = thislen # print them all - theformat = '{:' + str(len(str(len(pallet)-1))) + '}: {} fills to {:' + str(longestlimit) + '.' + str(notation['potency']) + 'f} {} (has {:' + str(longestbalance) + '.' + str(notation['potency']) + 'f}).' - for i in range(len(pallet)): - entry = pallet[i] + theformat = '{:' + str(len(str(len(beneflist)-1))) + \ + '}: {} fills to {:' + \ + str(longestlimit) + \ + '.' + \ + str(notation['potency']) + \ + 'f} {} (has {:' + \ + str(longestbalance) + \ + '.' + \ + str(notation['potency']) + \ + 'f}).' + for i in range(len(beneflist)): + entry = beneflist[i] numstr = numformat(decimal.Decimal(entry['topuplimit']) / notation['num']) while len(numstr) < longestlimit: numstr = ' ' + numstr @@ -96,36 +111,29 @@ def printPallet(pallet:list): )) def overview(): - print( "The contract's account ({}) has {} {}.".format( - distillery.address, - int(decimal.Decimal(distbalance()) / notation['num']), - notation['name'] - )) - pallet = getPallet() - printPallet(pallet) - answer = input("\n[ Q=quit x=distribute ]\nWhich account to edit (enter index number or full account number)?: ") - if answer is None or answer.upper() == 'Q': - exit( 0 ) - editAccount(answer, pallet) + while True: + print( "The contract's account ({}) has {} {}.".format( + distillery.address, + int(decimal.Decimal(distbalance()) / notation['num']), + notation['name'] + )) + beneflist = getBeneficiaries() + print_beneficiary_list(beneflist) + answer = input("\n[ Q=quit x=distribute ]\n" + + "Which account to edit (enter index number or full account number)?: ") + if answer is None or answer.upper() == 'Q': + exit( 0 ) + editAccount(answer, beneflist) -def init(): - global janitor, notation, distillery; - janitor = libbfa.Account('0xd15dd6dbbe722b451156a013c01b29d91e23c3d6') - table = dict([ - (6, 'Mwei'), - (9, 'Gwei'), - (12, 'micro'), - (15, 'finney'), - (18, 'ether'), - (21, 'kether'), - (24, 'grand'), - (27, 'mether'), - (30, 'gether'), - (33, 'tether'), - ]) +def init(**kwargs): + global janitor, notation, distillery, bfa; + bfa = libbfa.Bfa(kwargs.get('uri')) + janitor = libbfa.Account(kwargs.get('sender_addr')) + table = ('Kwei', 'Mwei', 'Gwei', 'micro', 'finney', 'ether', + 'kether', 'grand', 'mether', 'gether', 'tether') potency = 18 notation['potency'] = potency - notation['name'] = table[potency] + notation['name'] = table[int(potency/3-1)] notation['num'] = pow(10, potency) notation['strformat'] = '{' + ':.{}f'.format(potency) + '}' abifile = '' @@ -137,9 +145,34 @@ def init(): with open(abifile, 'rt', encoding='utf-8') as infile: abitxt = infile.read() abi = json.loads(abitxt) - addr = '0xECB6aFF6e38dC58C4d9AaE2F7927A282bcB77AC2' - distillery = bfa.w3.eth.contract(address=addr, abi=abi) + distillery = bfa.w3.eth.contract(address=kwargs.get('sc_addr'), abi=abi) -init() -while True: +parser = argparse.ArgumentParser(description="Command interface for BFA2018 distillery1.") +parser.add_argument( + '--uri', + metavar='URI', + nargs=1, + default='prod', + help='URI of node to connect to.') +parser.add_argument( + '--sender-addr', + metavar='ADDR', + nargs=1, + default='0xd15dd6dbbe722b451156a013c01b29d91e23c3d6', + help='Address of controller of the smart contract.') +parser.add_argument( + '--sc-addr', + metavar='ADDR', + nargs=1, + default='0xECB6aFF6e38dC58C4d9AaE2F7927A282bcB77AC2', + help='Address of smart contract.') +parser.add_argument( + '--distribute', + action='store_true', + help='Run distribute once and then exit.') +parsed = parser.parse_args() +init(uri=parsed.uri, sc_addr=parsed.sc_addr, sender_addr=parsed.sender_addr) +if parsed.distribute: + distribute() +else: overview()