diff --git a/models.py b/models.py index 3e33d7f..8ff2c11 100644 --- a/models.py +++ b/models.py @@ -79,3 +79,12 @@ class SystemData(SystemBase): attribute = Column('attribute', String) value = Column('value', String) +class ContractParticipantMapping(SystemBase): + __tablename__ = "contractParticipantMapping" + + id = Column('id', Integer, primary_key=True) + participantAddress = Column('participantAddress', String) + contractName = Column('contractName', String) + tokenAmount = Column('tokenAmount', Float) + + diff --git a/parsing.py b/parsing.py index 4445a18..a0e0083 100644 --- a/parsing.py +++ b/parsing.py @@ -54,7 +54,7 @@ def isSmartContractPay(text): def extractAmount(text, marker): count = 0 returnval = None - splitText = re.split("\W+", text) + splitText = text.split('userchoice')[0].split(' ') for word in splitText: word = word.replace(marker, '') @@ -141,11 +141,28 @@ def extractUserchoice(text): return None +def brackets_toNumber(item): + return float(item[1:-1]) + + def extractContractConditions(text, contracttype, marker): rulestext = re.split('contract-conditions:\s*', text)[-1] #rulelist = re.split('\d\.\s*', rulestext) rulelist = [] - for i in range(3): + numberList = re.findall(r'\(\d\d*\)', rulestext) + + for idx,item in enumerate(numberList): + numberList[idx] = int(item[1:-1]) + + numberList = sorted(numberList) + for idx, item in enumerate(numberList): + if numberList[idx] + 1 != numberList[idx + 1]: + print('Contract condition numbers are not in order') + return None + if idx == len(numberList) - 2: + break + + for i in range(len(numberList)): rule = rulestext.split('({})'.format(i+1))[1].split('({})'.format(i+2))[0] rulelist.append(rule.strip()) @@ -155,7 +172,7 @@ def extractContractConditions(text, contracttype, marker): if rule=='': continue elif rule[:14]=='contractamount': - pattern = re.compile('[^contractamount=].*') + pattern = re.compile('[^contractamount\s*=\s*].*') searchResult = pattern.search(rule).group(0) contractamount = searchResult.split(marker)[0] try: @@ -163,17 +180,38 @@ def extractContractConditions(text, contracttype, marker): except: print("something is wrong with contract amount entered") elif rule[:11]=='userchoices': - conditions = rule.split('userchoices=')[1] + pattern = re.compile('[^userchoices\s*=\s*].*') + conditions = pattern.search(rule).group(0) conditionlist = conditions.split('|') extractedRules['userchoices'] = {} for idx, condition in enumerate(conditionlist): extractedRules['userchoices'][idx] = condition.strip() elif rule[:10]=='expirytime': - pattern = re.compile('[^expirytime=].*') + pattern = re.compile('[^expirytime\s*=\s*].*') + searchResult = pattern.search(rule).group(0).strip() + if searchResult == 'date-time': + continue + else: + extractedRules['expirytime'] = searchResult + elif rule[:25] == 'minimumsubscriptionamount': + pattern = re.compile('[^minimumsubscriptionamount\s*=\s*].*') searchResult = pattern.search(rule).group(0) - extractedRules['expirytime'] = searchResult + minimumsubscriptionamount = searchResult.split(marker)[0] + try: + extractedRules['minimumsubscriptionamount'] = float(minimumsubscriptionamount) + except: + print("something is wrong with minimum subscription amount entered") + elif rule[:25] == 'maximumsubscriptionamount': + pattern = re.compile('[^maximumsubscriptionamount\s*=\s*].*') + searchResult = pattern.search(rule).group(0) + maximumsubscriptionamount = searchResult.split(marker)[0] + try: + extractedRules['maximumsubscriptionamount'] = float(maximumsubscriptionamount) + except: + print("something is wrong with maximum subscription amount entered") - if 'contractamount' in extractedRules and 'userchoices' in extractedRules and 'expirytime' in extractedRules: + + if 'contractamount' in extractedRules and 'userchoices' in extractedRules: return extractedRules else: return None diff --git a/tracktokens-smartcontracts.py b/tracktokens-smartcontracts.py index 6eed002..71dde71 100755 --- a/tracktokens-smartcontracts.py +++ b/tracktokens-smartcontracts.py @@ -11,7 +11,7 @@ import os import shutil from sqlalchemy.orm import sessionmaker, relationship from sqlalchemy import create_engine, func, desc -from models import SystemData, ActiveTable, ConsumedTable, TransferLogs, TransactionHistory, Base, ContractStructure, ContractBase, ContractParticipants, SystemBase, ActiveContracts +from models import SystemData, ActiveTable, ConsumedTable, TransferLogs, TransactionHistory, Base, ContractStructure, ContractBase, ContractParticipants, SystemBase, ActiveContracts, ContractParticipantMapping months = { 'jan' : 1, @@ -262,12 +262,19 @@ def startWorking(transaction_data, parsed_data, blockinfo): # todo Rule 46 - If the transfer type is smart contract, then call the function transferToken to do sanity checks & lock the balance elif parsed_data['transferType'] == 'smartContract': + + #Check if the db exists + apppath = os.path.dirname(os.path.realpath(__file__)) + dirpath = os.path.join(apppath, 'smartContracts','{}.db'.format(parsed_data['contractName'])) + if not os.path.exists(dirpath): + print('Smart contract with the given name doesn\'t exist') + return + # Check if the contract has expired engine = create_engine('sqlite:///smartContracts/{}.db'.format(parsed_data['contractName']), echo=True) - Base.metadata.create_all(bind=engine) + ContractBase.metadata.create_all(bind=engine) session = sessionmaker(bind=engine)() result = session.query(ContractStructure).filter_by(attribute='expirytime').all() - if result: #now parse the expiry time in python expirytime = result[0].value.strip() @@ -281,16 +288,52 @@ def startWorking(transaction_data, parsed_data, blockinfo): return session.close() + + # Check if maximum subscription amount has reached + engine = create_engine('sqlite:///smartContracts/{}.db'.format(parsed_data['contractName']), echo=True) + ContractBase.metadata.create_all(bind=engine) + session = sessionmaker(bind=engine)() + result = session.query(ContractStructure).filter_by(attribute='maximumsubscriptionamount').all() + session.close() + if result: + # now parse the expiry time in python + maximumsubscriptionamount = float(result[0].value.strip()) + engine = create_engine('sqlite:///smartContracts/{}.db'.format(parsed_data['contractName']), echo=True) + ContractBase.metadata.create_all(bind=engine) + session = sessionmaker(bind=engine)() + result = session.query(ContractStructure).filter_by(attribute='maximumsubscriptionamount').all() + amountDeposited = session.query(func.sum(ContractParticipants.tokenAmount)).all()[0][0] + session.close() + + if amountDeposited is None: + amountDeposited = 0 + + if amountDeposited >= maximumsubscriptionamount: + print('Maximum subscription amount reached') + return + + # Check if the tokenAmount being transferred exists in the address & do the token transfer returnval = transferToken(parsed_data['tokenIdentification'], parsed_data['tokenAmount'], inputlist[0], outputlist[0]) if returnval is not None: # Store participant details in the smart contract's db engine = create_engine('sqlite:///smartContracts/{}.db'.format(parsed_data['contractName']), echo=True) - Base.metadata.create_all(bind=engine) + ContractBase.metadata.create_all(bind=engine) session = sessionmaker(bind=engine)() session.add(ContractParticipants(participantAddress=inputadd, tokenAmount=parsed_data['tokenAmount'], userChoice=parsed_data['userChoice'])) session.commit() session.close() + + # Store a mapping of participant address -> Contract participated in + engine = create_engine('sqlite:///system.db', echo=True) + SystemBase.metadata.create_all(bind=engine) + session = sessionmaker(bind=engine)() + session.add(ContractParticipantMapping(participantAddress=inputadd, tokenAmount=parsed_data['tokenAmount'], + contractName = parsed_data['contractName'])) + session.commit() + session.close() + + else: print("Something went wrong in the smartcontract token transfer method") @@ -344,9 +387,18 @@ def startWorking(transaction_data, parsed_data, blockinfo): session.add( ContractStructure(attribute='contractamount', index=0, value=parsed_data['contractConditions']['contractamount'])) - session.add( + if 'expirytime' in parsed_data['contractConditions']: + session.add( ContractStructure(attribute='expirytime', index=0, value=parsed_data['contractConditions']['expirytime'])) + if 'minimumsubscriptionamount' in parsed_data['contractConditions']: + session.add( + ContractStructure(attribute='minimumsubscriptionamount', index=0, + value=parsed_data['contractConditions']['minimumsubscriptionamount'])) + if 'maximumsubscriptionamount' in parsed_data['contractConditions']: + session.add( + ContractStructure(attribute='maximumsubscriptionamount', index=0, + value=parsed_data['contractConditions']['maximumsubscriptionamount'])) for key, value in parsed_data['contractConditions']['userchoices'].items(): session.add(ContractStructure(attribute='exitconditions', index=key, value=value)) session.commit() @@ -366,6 +418,7 @@ def startWorking(transaction_data, parsed_data, blockinfo): elif parsed_data['type'] == 'smartContractPays': print('Found a transaction of the type smartContractPays') + # Check if input address is a committee address if inputlist[0] in committeeAddressList: @@ -379,6 +432,30 @@ def startWorking(transaction_data, parsed_data, blockinfo): activeContracts = list(zip(*activeContracts)) if outputlist[0] in activeContracts[2] and parsed_data['contractName'] in activeContracts[1]: + # Check if the minimum subscription amount has been reached if it exists as part of the structure + engine = create_engine('sqlite:///smartContracts/{}.db'.format(parsed_data['contractName']), echo=True) + ContractBase.metadata.create_all(bind=engine) + session = sessionmaker(bind=engine)() + result = session.query(ContractStructure).filter_by(attribute='minimumsubscriptionamount').all() + session.close() + if result: + # now parse the expiry time in python + minimumsubscriptionamount = float(result[0].value.strip()) + engine = create_engine('sqlite:///smartContracts/{}.db'.format(parsed_data['contractName']), + echo=True) + ContractBase.metadata.create_all(bind=engine) + session = sessionmaker(bind=engine)() + result = session.query(ContractStructure).filter_by(attribute='minimumsubscriptionamount').all() + amountDeposited = session.query(func.sum(ContractParticipants.tokenAmount)).all()[0][0] + session.close() + + if amountDeposited is None: + amountDeposited = 0 + + if amountDeposited < minimumsubscriptionamount: + print('Minimum subscription amount reached') + return + engine = create_engine('sqlite:///smartContracts/{}.db'.format(parsed_data['contractName']), echo=True) connection = engine.connect() contractWinners = connection.execute('select * from contractparticipants where userChoice="{}"'.format(parsed_data['triggerCondition'])).fetchall() @@ -479,7 +556,7 @@ print("current_block_height : " + str(current_index)) for blockindex in range( startblock, current_index ): print(blockindex) - if blockindex == 590327: + if blockindex == 590795: print('hello') # Scan every block