Changing timezone convention for arrow modul
This commit is contained in:
parent
46ccce5f81
commit
273d805449
6
ranchimallflo-api/.gitignore
vendored
Normal file
6
ranchimallflo-api/.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
__pycache__/
|
||||
wsgi.py
|
||||
*.swp
|
||||
config.py
|
||||
.idea/
|
||||
py3.7/
|
||||
2
ranchimallflo-api/config-example.py
Normal file
2
ranchimallflo-api/config-example.py
Normal file
@ -0,0 +1,2 @@
|
||||
dbfolder = ''
|
||||
sse_pubKey = '<public key in the format of pybtc python library>'
|
||||
374
ranchimallflo-api/parsing.py
Normal file
374
ranchimallflo-api/parsing.py
Normal file
@ -0,0 +1,374 @@
|
||||
import re
|
||||
import arrow
|
||||
|
||||
marker = None
|
||||
operation = None
|
||||
address = None
|
||||
amount = None
|
||||
|
||||
months = { 'jan' : 1,
|
||||
'feb' : 2,
|
||||
'mar' : 3,
|
||||
'apr' : 4,
|
||||
'may' : 5,
|
||||
'jun' : 6,
|
||||
'jul' : 7,
|
||||
'aug' : 8,
|
||||
'sep' : 9,
|
||||
'oct' : 10,
|
||||
'nov' : 11,
|
||||
'dec' : 12 }
|
||||
|
||||
|
||||
def isTransfer(text):
|
||||
wordlist = ['transfer','send','give'] # keep everything lowercase
|
||||
textList = text.split(' ')
|
||||
for word in wordlist:
|
||||
if word in textList:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def isIncorp(text):
|
||||
wordlist = ['incorporate','create','start'] # keep everything lowercase
|
||||
textList = text.split(' ')
|
||||
for word in wordlist:
|
||||
if word in textList:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def isSmartContract(text):
|
||||
textList = text.split(' ')
|
||||
for word in textList:
|
||||
if word == '':
|
||||
continue
|
||||
if word.endswith('@') and len(word) != 1:
|
||||
return word
|
||||
return False
|
||||
|
||||
|
||||
def isSmartContractPay(text):
|
||||
wordlist = text.split(' ')
|
||||
if len(wordlist) != 2:
|
||||
return False
|
||||
smartContractTrigger = re.findall(r"smartContractTrigger:'.*'", text)[0].split('smartContractTrigger:')[1]
|
||||
smartContractTrigger = smartContractTrigger[1:-1]
|
||||
smartContractName = re.findall(r"smartContractName:.*@", text)[0].split('smartContractName:')[1]
|
||||
smartContractName = smartContractName[:-1]
|
||||
|
||||
if smartContractTrigger and smartContractName:
|
||||
contractconditions = { 'smartContractTrigger':smartContractTrigger, 'smartContractName':smartContractName }
|
||||
return contractconditions
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def extractAmount(text, marker):
|
||||
count = 0
|
||||
returnval = None
|
||||
splitText = text.split('userchoice')[0].split(' ')
|
||||
|
||||
for word in splitText:
|
||||
word = word.replace(marker, '')
|
||||
try:
|
||||
float(word)
|
||||
count = count + 1
|
||||
returnval = float(word)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
if count > 1:
|
||||
return 'Too many'
|
||||
return returnval
|
||||
|
||||
|
||||
def extractMarker(text):
|
||||
textList = text.split(' ')
|
||||
for word in textList:
|
||||
if word == '':
|
||||
continue
|
||||
if word.endswith('#') and len(word) != 1:
|
||||
return word
|
||||
return False
|
||||
|
||||
|
||||
def extractInitTokens(text):
|
||||
base_units = {'thousand':10**3 , 'million':10**6 ,'billion':10**9, 'trillion':10**12}
|
||||
textList = text.split(' ')
|
||||
counter = 0
|
||||
value = None
|
||||
for idx,word in enumerate(textList):
|
||||
try:
|
||||
result = float(word)
|
||||
if textList[idx + 1] in base_units:
|
||||
value = result * base_units[textList[idx + 1]]
|
||||
counter = counter + 1
|
||||
else:
|
||||
value = result
|
||||
counter = counter + 1
|
||||
except:
|
||||
for unit in base_units:
|
||||
result = word.split(unit)
|
||||
if len(result) == 2 and result[1]=='' and result[0]!='':
|
||||
try:
|
||||
value = float(result[0])*base_units[unit]
|
||||
counter = counter + 1
|
||||
except:
|
||||
continue
|
||||
|
||||
if counter == 1:
|
||||
return value
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def extractAddress(text):
|
||||
textList = text.split(' ')
|
||||
for word in textList:
|
||||
if word == '':
|
||||
continue
|
||||
if word[-1] == '$' and len(word) != 1:
|
||||
return word
|
||||
return None
|
||||
|
||||
|
||||
def extractContractType(text):
|
||||
operationList = ['one-time-event*'] # keep everything lowercase
|
||||
count = 0
|
||||
returnval = None
|
||||
for operation in operationList:
|
||||
count = count + text.count(operation)
|
||||
if count > 1:
|
||||
return 'Too many'
|
||||
if count == 1 and (returnval is None):
|
||||
returnval = operation
|
||||
return returnval
|
||||
|
||||
|
||||
def extractUserchoice(text):
|
||||
result = re.split('userchoice:\s*', text)
|
||||
if len(result) != 1 and result[1]!='':
|
||||
return result[1].strip().strip('"').strip("'")
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def brackets_toNumber(item):
|
||||
return float(item[1:-1])
|
||||
|
||||
|
||||
def extractContractConditions(text, contracttype, marker, blocktime):
|
||||
rulestext = re.split('contract-conditions:\s*', text)[-1]
|
||||
#rulelist = re.split('\d\.\s*', rulestext)
|
||||
rulelist = []
|
||||
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())
|
||||
|
||||
if contracttype == 'one-time-event*':
|
||||
extractedRules = {}
|
||||
|
||||
for rule in rulelist:
|
||||
if rule == '':
|
||||
continue
|
||||
elif rule[:10] == 'expirytime':
|
||||
expirytime = re.split('expirytime[\s]*=[\s]*', rule)[1].strip()
|
||||
|
||||
try:
|
||||
expirytime_split = expirytime.split(' ')
|
||||
parse_string = '{}/{}/{} {}'.format(expirytime_split[3], months[expirytime_split[1]], expirytime_split[2], expirytime_split[4])
|
||||
expirytime_object = arrow.get(parse_string, 'YYYY/M/D HH:mm:ss').replace(tzinfo=expirytime_split[5])
|
||||
blocktime_object = arrow.get(blocktime)
|
||||
if expirytime_object < blocktime_object:
|
||||
print('Expirytime of the contract is earlier than the block it is incorporated in. This incorporation will be rejected ')
|
||||
return None
|
||||
extractedRules['expiryTime'] = expirytime
|
||||
except:
|
||||
print('Expiry time not in right format')
|
||||
return None
|
||||
|
||||
for rule in rulelist:
|
||||
if rule=='':
|
||||
continue
|
||||
elif rule[:14] == 'contractamount':
|
||||
pattern = re.compile('[^contractamount\s*=\s*].*')
|
||||
searchResult = pattern.search(rule).group(0)
|
||||
contractamount = searchResult.split(marker)[0]
|
||||
try:
|
||||
extractedRules['contractAmount'] = float(contractamount)
|
||||
except:
|
||||
print("something is wrong with contract amount entered")
|
||||
elif rule[:11] == 'userchoices':
|
||||
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[:25] == 'minimumsubscriptionamount':
|
||||
pattern = re.compile('[^minimumsubscriptionamount\s*=\s*].*')
|
||||
searchResult = pattern.search(rule).group(0)
|
||||
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")
|
||||
elif rule[:12] == 'payeeAddress':
|
||||
pattern = re.compile('[^payeeAddress\s*=\s*].*')
|
||||
searchResult = pattern.search(rule).group(0)
|
||||
payeeAddress = searchResult.split(marker)[0]
|
||||
extractedRules['payeeAddress'] = payeeAddress
|
||||
|
||||
|
||||
if len(extractedRules)>1 and 'expiryTime' in extractedRules:
|
||||
return extractedRules
|
||||
else:
|
||||
return None
|
||||
return None
|
||||
|
||||
|
||||
def extractTriggerCondition(text):
|
||||
searchResult = re.search('\".*\"', text)
|
||||
if searchResult is None:
|
||||
searchResult = re.search('\'.*\'', text)
|
||||
return searchResult
|
||||
return searchResult
|
||||
|
||||
|
||||
# Combine test
|
||||
def parse_flodata(string, blockinfo):
|
||||
|
||||
# todo Rule 20 - remove 'text:' from the start of flodata if it exists
|
||||
if string[0:5] == 'text:':
|
||||
string = string.split('text:')[1]
|
||||
|
||||
# todo Rule 21 - Collapse multiple spaces into a single space in the whole of flodata
|
||||
# todo Rule 22 - convert flodata to lowercase to make the system case insensitive
|
||||
nospacestring = re.sub(' +', ' ', string)
|
||||
cleanstring = nospacestring.lower()
|
||||
|
||||
# todo Rule 23 - Count number of words ending with @ and #
|
||||
atList = []
|
||||
hashList = []
|
||||
|
||||
for word in cleanstring.split(' '):
|
||||
if word.endswith('@') and len(word) != 1:
|
||||
atList.append(word)
|
||||
if word.endswith('#') and len(word) != 1:
|
||||
hashList.append(word)
|
||||
|
||||
# todo Rule 24 - Reject the following conditions - a. number of # & number of @ is equal to 0 then reject
|
||||
# todo Rule 25 - If number of # or number of @ is greater than 1, reject
|
||||
# todo Rule 25.a - If a transaction is rejected, it means parsed_data type is noise
|
||||
# Filter noise first - check if the words end with either @ or #
|
||||
if (len(atList)==0 and len(hashList)==0) or len(atList)>1 or len(hashList)>1:
|
||||
parsed_data = {'type': 'noise'}
|
||||
|
||||
# todo Rule 26 - if number of # is 1 and number of @ is 0, then check if its token creation or token transfer transaction
|
||||
|
||||
elif len(hashList)==1 and len(atList)==0:
|
||||
# Passing the above check means token creation or transfer
|
||||
incorporation = isIncorp(cleanstring)
|
||||
transfer = isTransfer(cleanstring)
|
||||
|
||||
# todo Rule 27 - if (neither token incorporation and token transfer) OR both token incorporation and token transfer, reject
|
||||
if (not incorporation and not transfer) or (incorporation and transfer):
|
||||
parsed_data = {'type': 'noise'}
|
||||
|
||||
# todo Rule 28 - if token creation and not token transfer then it is confirmed that is it a token creation transaction
|
||||
# todo Rule 29 - Extract total number of tokens issued, if its not mentioned then reject
|
||||
elif incorporation and not transfer:
|
||||
initTokens = extractInitTokens(cleanstring)
|
||||
if initTokens is not None:
|
||||
parsed_data = {'type': 'tokenIncorporation', 'flodata': string, 'tokenIdentification': hashList[0][:-1],
|
||||
'tokenAmount': initTokens}
|
||||
else:
|
||||
parsed_data = {'type': 'noise'}
|
||||
|
||||
# todo Rule 30 - if not token creation and is token transfer then then process it for token transfer rules
|
||||
# todo Rule 31 - Extract number of tokens to be sent and the address to which to be sent, both data is mandatory
|
||||
elif not incorporation and transfer:
|
||||
amount = extractAmount(cleanstring, hashList[0][:-1])
|
||||
if None not in [amount]:
|
||||
parsed_data = {'type': 'transfer', 'transferType': 'token', 'flodata': string,
|
||||
'tokenIdentification': hashList[0][:-1],
|
||||
'tokenAmount': amount}
|
||||
else:
|
||||
parsed_data = {'type': 'noise'}
|
||||
|
||||
# todo Rule 32 - if number of # is 1 and number of @ is 1, then process for smart contract transfer or creation
|
||||
elif len(hashList)==1 and len(atList)==1:
|
||||
# Passing the above check means Smart Contract creation or transfer
|
||||
incorporation = isIncorp(cleanstring)
|
||||
transfer = isTransfer(cleanstring)
|
||||
|
||||
# todo Rule 33 - if a confusing smart contract command is given, like creating and sending at the same time, or no
|
||||
if (not incorporation and not transfer) or (incorporation and transfer):
|
||||
parsed_data = {'type': 'noise'}
|
||||
|
||||
# todo Rule 34 - if incorporation and not transfer, then extract type of contract, address of the contract and conditions of the contract. Reject if any of those is not present
|
||||
elif incorporation and not transfer:
|
||||
contracttype = extractContractType(cleanstring)
|
||||
contractaddress = extractAddress(nospacestring)
|
||||
contractconditions = extractContractConditions(cleanstring, contracttype, marker=hashList[0][:-1], blocktime=blockinfo['time'])
|
||||
|
||||
if None not in [contracttype, contractaddress, contractconditions]:
|
||||
parsed_data = {'type': 'smartContractIncorporation', 'contractType': contracttype[:-1],
|
||||
'tokenIdentification': hashList[0][:-1], 'contractName': atList[0][:-1],
|
||||
'contractAddress': contractaddress[:-1], 'flodata': string,
|
||||
'contractConditions': contractconditions}
|
||||
else:
|
||||
parsed_data = {'type': 'noise'}
|
||||
|
||||
# todo Rule 35 - if it is not incorporation and it is transfer, then extract smart contract amount to be locked and userPreference. If any of them is missing, then reject
|
||||
elif not incorporation and transfer:
|
||||
# We are at the send/transfer of smart contract
|
||||
amount = extractAmount(cleanstring, hashList[0][:-1])
|
||||
userChoice = extractUserchoice(cleanstring)
|
||||
contractaddress = extractAddress(nospacestring)
|
||||
if None not in [amount, userChoice]:
|
||||
parsed_data = {'type': 'transfer', 'transferType': 'smartContract', 'flodata': string,
|
||||
'tokenIdentification': hashList[0][:-1],
|
||||
'operation': 'transfer', 'tokenAmount': amount, 'contractName': atList[0][:-1],
|
||||
'userChoice': userChoice}
|
||||
if contractaddress:
|
||||
parsed_data['contractAddress'] = contractaddress[:-1]
|
||||
else:
|
||||
parsed_data = {'type': 'noise'}
|
||||
|
||||
|
||||
# todo Rule 36 - Check for only a single @ and the substring "smart contract system says" in flodata, else reject
|
||||
elif (len(hashList)==0 and len(atList)==1):
|
||||
# Passing the above check means Smart Contract pays | exitcondition triggered from the committee
|
||||
# todo Rule 37 - Extract the trigger condition given by the committee. If its missing, reject
|
||||
triggerCondition = extractTriggerCondition(cleanstring)
|
||||
if triggerCondition is not None:
|
||||
parsed_data = {'type': 'smartContractPays', 'contractName': atList[0][:-1], 'triggerCondition': triggerCondition.group().strip()[1:-1]}
|
||||
else:
|
||||
parsed_data = {'type':'noise'}
|
||||
else:
|
||||
parsed_data = {'type': 'noise'}
|
||||
|
||||
return parsed_data
|
||||
643
ranchimallflo-api/ranchimallflo_api.py
Normal file
643
ranchimallflo-api/ranchimallflo_api.py
Normal file
@ -0,0 +1,643 @@
|
||||
from collections import defaultdict
|
||||
import sqlite3
|
||||
import json
|
||||
import os
|
||||
import requests
|
||||
|
||||
from quart import jsonify, make_response, Quart, render_template, request, flash, redirect, url_for
|
||||
from quart import Quart
|
||||
from quart_cors import cors
|
||||
import asyncio
|
||||
from typing import Optional
|
||||
|
||||
from pybtc import verify_signature
|
||||
from config import *
|
||||
import parsing
|
||||
|
||||
|
||||
app = Quart(__name__)
|
||||
app = cors(app)
|
||||
|
||||
|
||||
# FLO TOKEN APIs
|
||||
|
||||
@app.route('/api/v1.0/getTokenList', methods=['GET'])
|
||||
async def getTokenList():
|
||||
filelist = []
|
||||
for item in os.listdir(os.path.join(dbfolder, 'tokens')):
|
||||
if os.path.isfile(os.path.join(dbfolder, 'tokens', item)):
|
||||
filelist.append(item[:-3])
|
||||
|
||||
return jsonify(tokens=filelist, result='ok')
|
||||
|
||||
|
||||
@app.route('/api/v1.0/getTokenInfo', methods=['GET'])
|
||||
async def getTokenInfo():
|
||||
token = request.args.get('token')
|
||||
|
||||
if token is None:
|
||||
return jsonify(result='error')
|
||||
|
||||
dblocation = dbfolder + '/tokens/' + str(token) + '.db'
|
||||
if os.path.exists(dblocation):
|
||||
conn = sqlite3.connect(dblocation)
|
||||
c = conn.cursor()
|
||||
else:
|
||||
return 'Token doesn\'t exist'
|
||||
c.execute('SELECT * FROM transactionHistory WHERE id=1')
|
||||
incorporationRow = c.fetchall()[0]
|
||||
c.execute('SELECT COUNT (DISTINCT address) FROM activeTable')
|
||||
numberOf_distinctAddresses = c.fetchall()[0][0]
|
||||
conn.close()
|
||||
return jsonify(result='ok', token=token, incorporationAddress=incorporationRow[1], tokenSupply=incorporationRow[3],
|
||||
transactionHash=incorporationRow[6], blockchainReference=incorporationRow[7],
|
||||
activeAddress_no=numberOf_distinctAddresses)
|
||||
|
||||
|
||||
@app.route('/api/v1.0/getTokenTransactions', methods=['GET'])
|
||||
async def getTokenTransactions():
|
||||
token = request.args.get('token')
|
||||
senderFloAddress = request.args.get('senderFloAddress')
|
||||
destFloAddress = request.args.get('destFloAddress')
|
||||
|
||||
if token is None:
|
||||
return jsonify(result='error')
|
||||
|
||||
dblocation = dbfolder + '/tokens/' + str(token) + '.db'
|
||||
if os.path.exists(dblocation):
|
||||
conn = sqlite3.connect(dblocation)
|
||||
conn.row_factory = sqlite3.Row
|
||||
c = conn.cursor()
|
||||
else:
|
||||
return 'Token doesn\'t exist'
|
||||
|
||||
if senderFloAddress and not destFloAddress:
|
||||
c.execute(
|
||||
'SELECT blockNumber, sourceFloAddress, destFloAddress, transferAmount, blockchainReference FROM transactionHistory WHERE sourceFloAddress="{}" ORDER BY id DESC LIMIT 100'.format(
|
||||
senderFloAddress))
|
||||
elif not senderFloAddress and destFloAddress:
|
||||
c.execute(
|
||||
'SELECT blockNumber, sourceFloAddress, destFloAddress, transferAmount, blockchainReference FROM transactionHistory WHERE destFloAddress="{}" ORDER BY id DESC LIMIT 100'.format(
|
||||
destFloAddress))
|
||||
elif senderFloAddress and destFloAddress:
|
||||
c.execute(
|
||||
'SELECT blockNumber, sourceFloAddress, destFloAddress, transferAmount, blockchainReference FROM transactionHistory WHERE sourceFloAddress="{}" AND destFloAddress="{}" ORDER BY id DESC LIMIT 100'.format(
|
||||
senderFloAddress, destFloAddress))
|
||||
|
||||
else:
|
||||
c.execute(
|
||||
'SELECT blockNumber, sourceFloAddress, destFloAddress, transferAmount, blockchainReference FROM transactionHistory ORDER BY id DESC LIMIT 100')
|
||||
latestTransactions = c.fetchall()
|
||||
conn.close()
|
||||
rowarray_list = []
|
||||
for row in latestTransactions:
|
||||
d = dict(zip(row.keys(), row)) # a dict with column names as keys
|
||||
rowarray_list.append(d)
|
||||
return jsonify(result='ok', transactions=rowarray_list)
|
||||
|
||||
|
||||
@app.route('/api/v1.0/getTokenBalances', methods=['GET'])
|
||||
async def getTokenBalances():
|
||||
token = request.args.get('token')
|
||||
if token is None:
|
||||
return jsonify(result='error')
|
||||
|
||||
dblocation = dbfolder + '/tokens/' + str(token) + '.db'
|
||||
if os.path.exists(dblocation):
|
||||
conn = sqlite3.connect(dblocation)
|
||||
c = conn.cursor()
|
||||
else:
|
||||
return 'Token doesn\'t exist'
|
||||
c.execute('SELECT address,SUM(transferBalance) FROM activeTable GROUP BY address')
|
||||
addressBalances = c.fetchall()
|
||||
|
||||
returnList = []
|
||||
|
||||
for address in addressBalances:
|
||||
tempdict = {}
|
||||
tempdict['floAddress'] = address[0]
|
||||
tempdict['balance'] = address[1]
|
||||
returnList.append(tempdict)
|
||||
|
||||
return jsonify(result='ok', balances=returnList)
|
||||
|
||||
|
||||
@app.route('/api/v1.0/getFloAddressDetails', methods=['GET'])
|
||||
async def getFloAddressDetails():
|
||||
floAddress = request.args.get('floAddress')
|
||||
|
||||
if floAddress is None:
|
||||
return jsonify(result='error', description='floAddress hasn\'t been passed')
|
||||
|
||||
dblocation = dbfolder + '/system.db'
|
||||
if os.path.exists(dblocation):
|
||||
conn = sqlite3.connect(dblocation)
|
||||
c = conn.cursor()
|
||||
c.execute('select token from tokenAddressMapping where tokenAddress="{}"'.format(floAddress))
|
||||
tokenNames = c.fetchall()
|
||||
|
||||
if len(tokenNames) != 0:
|
||||
detailList = []
|
||||
|
||||
for token in tokenNames:
|
||||
token = token[0]
|
||||
dblocation = dbfolder + '/tokens/' + str(token) + '.db'
|
||||
if os.path.exists(dblocation):
|
||||
tempdict = {}
|
||||
conn = sqlite3.connect(dblocation)
|
||||
c = conn.cursor()
|
||||
c.execute('SELECT SUM(transferBalance) FROM activeTable WHERE address="{}"'.format(floAddress))
|
||||
balance = c.fetchall()[0][0]
|
||||
tempdict['balance'] = balance
|
||||
tempdict['token'] = token
|
||||
detailList.append(tempdict)
|
||||
|
||||
return jsonify(result='ok', floAddress=floAddress, floAddressDetails=detailList)
|
||||
|
||||
else:
|
||||
# Address is not associated with any token
|
||||
return jsonify(result='error', description='FLO address is not associated with any tokens')
|
||||
|
||||
|
||||
@app.route('/api/v1.0/getFloAddressBalance', methods=['GET'])
|
||||
async def getAddressBalance():
|
||||
floAddress = request.args.get('floAddress')
|
||||
token = request.args.get('token')
|
||||
|
||||
if floAddress is None or token is None:
|
||||
return jsonify(result='error')
|
||||
|
||||
dblocation = dbfolder + '/tokens/' + str(token) + '.db'
|
||||
if os.path.exists(dblocation):
|
||||
conn = sqlite3.connect(dblocation)
|
||||
c = conn.cursor()
|
||||
else:
|
||||
return 'Token doesn\'t exist'
|
||||
c.execute('SELECT SUM(transferBalance) FROM activeTable WHERE address="{}"'.format(floAddress))
|
||||
balance = c.fetchall()[0][0]
|
||||
conn.close()
|
||||
return jsonify(result='ok', token=token, floAddress=floAddress, balance=balance)
|
||||
|
||||
|
||||
@app.route('/api/v1.0/getFloAddressTransactions', methods=['GET'])
|
||||
async def getAddressTransactions():
|
||||
floAddress = request.args.get('floAddress')
|
||||
|
||||
if floAddress is None:
|
||||
return jsonify(result='error', description='floAddress has not been passed')
|
||||
|
||||
dblocation = dbfolder + '/system.db'
|
||||
if os.path.exists(dblocation):
|
||||
conn = sqlite3.connect(dblocation)
|
||||
c = conn.cursor()
|
||||
c.execute('select token from tokenAddressMapping where tokenAddress="{}"'.format(floAddress))
|
||||
tokenNames = c.fetchall()
|
||||
|
||||
if len(tokenNames) != 0:
|
||||
allTransactionList = []
|
||||
|
||||
for token in tokenNames:
|
||||
token = token[0]
|
||||
dblocation = dbfolder + '/tokens/' + str(token) + '.db'
|
||||
if os.path.exists(dblocation):
|
||||
tempdict = {}
|
||||
conn = sqlite3.connect(dblocation)
|
||||
c = conn.cursor()
|
||||
c.execute('SELECT blockNumber, sourceFloAddress, destFloAddress, transferAmount, blockchainReference FROM transactionHistory ORDER BY id DESC LIMIT 100')
|
||||
latestTransactions = c.fetchall()
|
||||
conn.close()
|
||||
|
||||
rowarray_list = []
|
||||
for row in latestTransactions:
|
||||
row = list(row)
|
||||
d = {}
|
||||
d['blockNumber'] = row[0]
|
||||
d['sourceFloAddress'] = row[1]
|
||||
d['destFloAddress'] = row[2]
|
||||
d['transferAmount'] = row[3]
|
||||
d['blockchainReference'] = row[4]
|
||||
rowarray_list.append(d)
|
||||
|
||||
tempdict['token'] = token
|
||||
tempdict['transactions'] = rowarray_list
|
||||
allTransactionList.append(tempdict)
|
||||
|
||||
return jsonify(result='ok', floAddress=floAddress, allTransactions=allTransactionList)
|
||||
|
||||
|
||||
# SMART CONTRACT APIs
|
||||
|
||||
@app.route('/api/v1.0/getSmartContractList', methods=['GET'])
|
||||
async def getContractList():
|
||||
contractName = request.args.get('contractName')
|
||||
contractAddress = request.args.get('contractAddress')
|
||||
|
||||
conn = sqlite3.connect(os.path.join(dbfolder, 'system.db'))
|
||||
c = conn.cursor()
|
||||
|
||||
contractList = []
|
||||
|
||||
if contractName and contractAddress:
|
||||
c.execute('select * from activecontracts where contractName="{}" and contractAddress="{}"'.format(contractName, contractAddress))
|
||||
allcontractsDetailList = c.fetchall()
|
||||
for idx, contract in enumerate(allcontractsDetailList):
|
||||
contractDict = {}
|
||||
contractDict['contractName'] = contract[1]
|
||||
contractDict['contractAddress'] = contract[2]
|
||||
contractDict['status'] = contract[3]
|
||||
contractDict['transactionHash'] = contract[4]
|
||||
contractDict['incorporationDate'] = contract[5]
|
||||
if contract[6]:
|
||||
contractDict['expiryDate'] = contract[6]
|
||||
if contract[7]:
|
||||
contractDict['closeDate'] = contract[7]
|
||||
|
||||
contractList.append(contractDict)
|
||||
|
||||
elif contractName and not contractAddress:
|
||||
c.execute('select * from activecontracts where contractName="{}"'.format(contractName))
|
||||
allcontractsDetailList = c.fetchall()
|
||||
for idx, contract in enumerate(allcontractsDetailList):
|
||||
contractDict = {}
|
||||
contractDict['contractName'] = contract[1]
|
||||
contractDict['contractAddress'] = contract[2]
|
||||
contractDict['status'] = contract[3]
|
||||
contractDict['transactionHash'] = contract[4]
|
||||
contractDict['incorporationDate'] = contract[5]
|
||||
if contract[6]:
|
||||
contractDict['expiryDate'] = contract[6]
|
||||
if contract[7]:
|
||||
contractDict['closeDate'] = contract[7]
|
||||
|
||||
contractList.append(contractDict)
|
||||
|
||||
elif not contractName and contractAddress:
|
||||
c.execute('select * from activecontracts where contractAddress="{}"'.format(contractAddress))
|
||||
allcontractsDetailList = c.fetchall()
|
||||
for idx, contract in enumerate(allcontractsDetailList):
|
||||
contractDict = {}
|
||||
contractDict['contractName'] = contract[1]
|
||||
contractDict['contractAddress'] = contract[2]
|
||||
contractDict['status'] = contract[3]
|
||||
contractDict['transactionHash'] = contract[4]
|
||||
contractDict['incorporationDate'] = contract[5]
|
||||
if contract[6]:
|
||||
contractDict['expiryDate'] = contract[6]
|
||||
if contract[7]:
|
||||
contractDict['closeDate'] = contract[7]
|
||||
|
||||
contractList.append(contractDict)
|
||||
|
||||
else:
|
||||
c.execute('select * from activecontracts')
|
||||
allcontractsDetailList = c.fetchall()
|
||||
for idx, contract in enumerate(allcontractsDetailList):
|
||||
contractDict = {}
|
||||
contractDict['contractName'] = contract[1]
|
||||
contractDict['contractAddress'] = contract[2]
|
||||
contractDict['status'] = contract[3]
|
||||
contractDict['transactionHash'] = contract[4]
|
||||
contractDict['incorporationDate'] = contract[5]
|
||||
if contract[6]:
|
||||
contractDict['expiryDate'] = contract[6]
|
||||
if contract[7]:
|
||||
contractDict['closeDate'] = contract[7]
|
||||
|
||||
contractList.append(contractDict)
|
||||
|
||||
return jsonify(smartContracts=contractList, result='ok')
|
||||
|
||||
|
||||
@app.route('/api/v1.0/getSmartContractInfo', methods=['GET'])
|
||||
async def getContractInfo():
|
||||
contractName = request.args.get('contractName')
|
||||
contractAddress = request.args.get('contractAddress')
|
||||
|
||||
if contractName is None:
|
||||
return jsonify(result='error', details='Smart Contract\'s name hasn\'t been passed')
|
||||
|
||||
if contractAddress is None:
|
||||
return jsonify(result='error', details='Smart Contract\'s address hasn\'t been passed')
|
||||
|
||||
contractDbName = '{}-{}.db'.format(contractName.strip(), contractAddress.strip())
|
||||
filelocation = os.path.join(dbfolder, 'smartContracts', contractDbName)
|
||||
|
||||
if os.path.isfile(filelocation):
|
||||
# Make db connection and fetch data
|
||||
conn = sqlite3.connect(filelocation)
|
||||
c = conn.cursor()
|
||||
c.execute(
|
||||
'SELECT attribute,value FROM contractstructure')
|
||||
result = c.fetchall()
|
||||
|
||||
returnval = {'userChoice': []}
|
||||
temp = 0
|
||||
for row in result:
|
||||
if row[0] == 'exitconditions':
|
||||
if temp == 0:
|
||||
returnval["userChoice"] = [row[1]]
|
||||
temp = temp + 1
|
||||
else:
|
||||
returnval['userChoice'].append(row[1])
|
||||
continue
|
||||
returnval[row[0]] = row[1]
|
||||
|
||||
c.execute('select count(participantAddress) from contractparticipants')
|
||||
noOfParticipants = c.fetchall()[0][0]
|
||||
returnval['numberOfParticipants'] = noOfParticipants
|
||||
|
||||
c.execute('select sum(tokenAmount) from contractparticipants')
|
||||
totalAmount = c.fetchall()[0][0]
|
||||
returnval['tokenAmountDeposited'] = totalAmount
|
||||
conn.close()
|
||||
|
||||
conn = sqlite3.connect(os.path.join(dbfolder, 'system.db'))
|
||||
c = conn.cursor()
|
||||
c.execute('select status, incorporationDate, expiryDate, closeDate from activecontracts where contractName=="{}" and contractAddress=="{}"'.format(contractName.strip(), contractAddress.strip()))
|
||||
results = c.fetchall()
|
||||
|
||||
if len(results) == 1:
|
||||
for result in results:
|
||||
returnval['status'] = result[0]
|
||||
returnval['incorporationDate'] = result[1]
|
||||
if result[2]:
|
||||
returnval['expiryDate'] = result[2]
|
||||
if result[3]:
|
||||
returnval['closeDate'] = result[3]
|
||||
|
||||
return jsonify(result='ok', contractInfo=returnval)
|
||||
|
||||
else:
|
||||
return jsonify(result='error', details='Smart Contract with the given name doesn\'t exist')
|
||||
|
||||
|
||||
@app.route('/api/v1.0/getSmartContractParticipants', methods=['GET'])
|
||||
async def getcontractparticipants():
|
||||
contractName = request.args.get('contractName')
|
||||
contractAddress = request.args.get('contractAddress')
|
||||
|
||||
if contractName is None:
|
||||
return jsonify(result='error', details='Smart Contract\'s name hasn\'t been passed')
|
||||
|
||||
if contractAddress is None:
|
||||
return jsonify(result='error', details='Smart Contract\'s address hasn\'t been passed')
|
||||
|
||||
contractDbName = '{}-{}.db'.format(contractName.strip(), contractAddress.strip())
|
||||
filelocation = os.path.join(dbfolder, 'smartContracts', contractDbName)
|
||||
|
||||
if os.path.isfile(filelocation):
|
||||
# Make db connection and fetch data
|
||||
conn = sqlite3.connect(filelocation)
|
||||
c = conn.cursor()
|
||||
c.execute(
|
||||
'SELECT id,participantAddress, tokenAmount, userChoice, transactionHash, winningAmount FROM contractparticipants')
|
||||
result = c.fetchall()
|
||||
conn.close()
|
||||
returnval = {}
|
||||
for row in result:
|
||||
returnval[row[0]] = {'participantFloAddress': row[1], 'tokenAmount': row[2], 'userChoice': row[3], 'transactionHash': row[4], 'winningAmount': row[5]}
|
||||
|
||||
return jsonify(result='ok', participantInfo=returnval)
|
||||
|
||||
else:
|
||||
return jsonify(result='error', details='Smart Contract with the given name doesn\'t exist')
|
||||
|
||||
|
||||
@app.route('/api/v1.0/getParticipantDetails', methods=['GET'])
|
||||
async def getParticipantDetails():
|
||||
floAddress = request.args.get('floAddress')
|
||||
|
||||
if floAddress is None:
|
||||
return jsonify(result='error', details='FLO address hasn\'t been passed')
|
||||
dblocation = os.path.join(dbfolder, 'system.db')
|
||||
|
||||
print(dblocation)
|
||||
|
||||
if os.path.isfile(dblocation):
|
||||
# Make db connection and fetch data
|
||||
conn = sqlite3.connect(dblocation)
|
||||
c = conn.cursor()
|
||||
|
||||
# Check if its a contract address
|
||||
c.execute("select contractAddress from activecontracts")
|
||||
activeContracts = c.fetchall()
|
||||
activeContracts = list(zip(*activeContracts))
|
||||
|
||||
if floAddress in list(activeContracts[0]):
|
||||
c.execute("select contractName from activecontracts where contractAddress=='" + floAddress + "'")
|
||||
contract_names = c.fetchall()
|
||||
|
||||
if len(contract_names) != 0:
|
||||
|
||||
contractlist = []
|
||||
|
||||
for contract_name in contract_names:
|
||||
contractName = '{}-{}.db'.format(contract_name[0].strip(), floAddress.strip())
|
||||
filelocation = os.path.join(dbfolder, 'smartContracts', contractName)
|
||||
|
||||
if os.path.isfile(filelocation):
|
||||
# Make db connection and fetch data
|
||||
conn = sqlite3.connect(filelocation)
|
||||
c = conn.cursor()
|
||||
c.execute(
|
||||
'SELECT attribute,value FROM contractstructure')
|
||||
result = c.fetchall()
|
||||
|
||||
returnval = {'exitconditions': []}
|
||||
temp = 0
|
||||
for row in result:
|
||||
if row[0] == 'exitconditions':
|
||||
if temp == 0:
|
||||
returnval["exitconditions"] = [row[1]]
|
||||
temp = temp + 1
|
||||
else:
|
||||
returnval['exitconditions'].append(row[1])
|
||||
continue
|
||||
returnval[row[0]] = row[1]
|
||||
|
||||
c.execute('select count(participantAddress) from contractparticipants')
|
||||
noOfParticipants = c.fetchall()[0][0]
|
||||
returnval['numberOfParticipants'] = noOfParticipants
|
||||
|
||||
c.execute('select sum(tokenAmount) from contractparticipants')
|
||||
totalAmount = c.fetchall()[0][0]
|
||||
returnval['tokenAmountDeposited'] = totalAmount
|
||||
conn.close()
|
||||
|
||||
contractlist.append(returnval)
|
||||
|
||||
return jsonify(result='ok', floAddress=floAddress, type='contract', contractList=contractlist)
|
||||
|
||||
# Check if its a participant address
|
||||
queryString = "SELECT id, participantAddress,contractName, contractAddress, tokenAmount, transactionHash FROM contractParticipantMapping where participantAddress=='" + floAddress + "'"
|
||||
c.execute(queryString)
|
||||
result = c.fetchall()
|
||||
conn.close()
|
||||
if len(result) != 0:
|
||||
participationDetailsList = []
|
||||
for row in result:
|
||||
detailsDict = {}
|
||||
detailsDict['contractName'] = row[2]
|
||||
detailsDict['contractAddress'] = row[3]
|
||||
detailsDict['tokenAmount'] = row[4]
|
||||
detailsDict['transactionHash'] = row[5]
|
||||
participationDetailsList.append(detailsDict)
|
||||
return jsonify(result='ok', floAddress=floAddress, type='participant', participatedContracts=participationDetailsList)
|
||||
else:
|
||||
return jsonify(result='error', details='Address hasn\'t participanted in any other contract')
|
||||
else:
|
||||
return jsonify(result='error', details='System error. System db is missing')
|
||||
|
||||
|
||||
@app.route('/api/v1.0/getBlockDetails/<blockno>', methods=['GET'])
|
||||
async def getblockdetails(blockno):
|
||||
blockhash = requests.get('{}block-index/{}'.format(apiUrl,blockno))
|
||||
blockhash = json.loads(blockhash.content)
|
||||
|
||||
blockdetails = requests.get('{}block/{}'.format(apiUrl,blockhash['blockHash']))
|
||||
blockdetails = json.loads(blockdetails.content)
|
||||
|
||||
return jsonify(blockdetails)
|
||||
|
||||
|
||||
@app.route('/api/v1.0/getTransactionDetails/<transactionHash>', methods=['GET'])
|
||||
async def gettransactiondetails(transactionHash):
|
||||
transactionDetails = requests.get('{}tx/{}'.format(apiUrl,transactionHash))
|
||||
transactionDetails = json.loads(transactionDetails.content)
|
||||
|
||||
flodata = transactionDetails['floData']
|
||||
|
||||
blockdetails = requests.get('{}block/{}'.format(apiUrl,transactionDetails['blockhash']))
|
||||
blockdetails = json.loads(blockdetails.content)
|
||||
|
||||
parseResult = parsing.parse_flodata(flodata, blockdetails)
|
||||
return jsonify(parsingDetails=parseResult, transactionDetails=transactionDetails)
|
||||
|
||||
|
||||
@app.route('/api/v1.0/getVscoutDetails', methods=['GET'])
|
||||
async def getVscoutDetails():
|
||||
latestBlock = requests.get('{}blocks?limit=1'.format(apiUrl))
|
||||
latestBlock = json.loads(latestBlock)
|
||||
|
||||
# get details of the last s4 blocks
|
||||
blockurl = '{}block/{}'.format(apiUrl,latestBlock["blocks"]['hash'])
|
||||
blockdetails = requests.get('{}block/{}'.format(apiUrl,latestBlock["blocks"]['hash']))
|
||||
block4details = json.loads(blockdetails)
|
||||
return jsonify(block4details)
|
||||
|
||||
|
||||
@app.route('/api/v1.0/getLatestTransactionDetails', methods=['GET'])
|
||||
async def getLatestTransactionDetails():
|
||||
dblocation = dbfolder + '/latestCache.db'
|
||||
if os.path.exists(dblocation):
|
||||
conn = sqlite3.connect(dblocation)
|
||||
c = conn.cursor()
|
||||
else:
|
||||
return 'Latest transactions db doesn\'t exist. This is unusual, please report on https://github.com/ranchimall/ranchimallflo-api'
|
||||
c.execute('''SELECT * FROM ( SELECT * FROM latestTransactions ORDER BY id DESC LIMIT 10) ORDER BY id ASC;''')
|
||||
latestTransactions = c.fetchall()
|
||||
c.close()
|
||||
tempdict = []
|
||||
for idx, item in enumerate(latestTransactions):
|
||||
item = list(item)
|
||||
tx_parsed_details = {}
|
||||
tx_parsed_details['transactionDetails'] = json.loads(item[2])
|
||||
tx_parsed_details['parsedFloData'] = json.loads(item[4])
|
||||
tx_parsed_details['parsedFloData']['transactionType'] = item[3]
|
||||
tempdict.append(tx_parsed_details)
|
||||
return jsonify(result='ok', latestTransactions=tempdict, temp=item)
|
||||
|
||||
|
||||
@app.route('/api/v1.0/getLatestBlockDetails', methods=['GET'])
|
||||
async def getLatestBlockDetails():
|
||||
dblocation = dbfolder + '/latestCache.db'
|
||||
if os.path.exists(dblocation):
|
||||
conn = sqlite3.connect(dblocation)
|
||||
c = conn.cursor()
|
||||
else:
|
||||
return 'Latest transactions db doesn\'t exist. This is unusual, please report on https://github.com/ranchimall/ranchimallflo-api'
|
||||
c.execute('''SELECT * FROM ( SELECT * FROM latestBlocks ORDER BY id DESC LIMIT 4) ORDER BY id ASC;''')
|
||||
latestBlocks = c.fetchall()
|
||||
c.close()
|
||||
tempdict = []
|
||||
for idx, item in enumerate(latestBlocks):
|
||||
tempdict.append(json.loads(item[3]))
|
||||
return jsonify(result='ok', latestBlocks=tempdict)
|
||||
|
||||
|
||||
@app.route('/test')
|
||||
async def test():
|
||||
return render_template('test.html')
|
||||
|
||||
|
||||
class ServerSentEvent:
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
data: str,
|
||||
*,
|
||||
event: Optional[str]=None,
|
||||
id: Optional[int]=None,
|
||||
retry: Optional[int]=None,
|
||||
) -> None:
|
||||
self.data = data
|
||||
self.event = event
|
||||
self.id = id
|
||||
self.retry = retry
|
||||
|
||||
def encode(self) -> bytes:
|
||||
message = f"data: {self.data}"
|
||||
if self.event is not None:
|
||||
message = f"{message}\nevent: {self.event}"
|
||||
if self.id is not None:
|
||||
message = f"{message}\nid: {self.id}"
|
||||
if self.retry is not None:
|
||||
message = f"{message}\nretry: {self.retry}"
|
||||
message = f"{message}\r\n\r\n"
|
||||
return message.encode('utf-8')
|
||||
|
||||
|
||||
@app.route('/', methods=['GET'])
|
||||
async def index():
|
||||
return await render_template('index.html')
|
||||
|
||||
|
||||
@app.route('/', methods=['POST'])
|
||||
async def broadcast():
|
||||
signature = request.headers.get('Signature')
|
||||
data = await request.get_json()
|
||||
if verify_signature(signature.encode(), sse_pubKey, data['message'].encode()):
|
||||
for queue in app.clients:
|
||||
await queue.put(data['message'])
|
||||
return jsonify(True)
|
||||
else:
|
||||
return jsonify(False)
|
||||
|
||||
|
||||
@app.route('/sse')
|
||||
async def sse():
|
||||
queue = asyncio.Queue()
|
||||
app.clients.add(queue)
|
||||
|
||||
async def send_events():
|
||||
while True:
|
||||
try:
|
||||
data = await queue.get()
|
||||
event = ServerSentEvent(data)
|
||||
yield event.encode()
|
||||
except asyncio.CancelledError as error:
|
||||
app.clients.remove(queue)
|
||||
|
||||
response = await make_response(
|
||||
send_events(),
|
||||
{
|
||||
'Content-Type': 'text/event-stream',
|
||||
'Cache-Control': 'no-cache',
|
||||
'Transfer-Encoding': 'chunked',
|
||||
},
|
||||
)
|
||||
response.timeout = None
|
||||
return response
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(debug=True,host='0.0.0.0', port=5009)
|
||||
24
ranchimallflo-api/static/broadcast.js
Normal file
24
ranchimallflo-api/static/broadcast.js
Normal file
@ -0,0 +1,24 @@
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var es = new EventSource('/sse');
|
||||
es.onmessage = function (event) {
|
||||
var messages_dom = document.getElementsByTagName('ul')[0];
|
||||
var message_dom = document.createElement('li');
|
||||
var content_dom = document.createTextNode('Received: ' + event.data);
|
||||
message_dom.appendChild(content_dom);
|
||||
messages_dom.appendChild(message_dom);
|
||||
};
|
||||
|
||||
document.getElementById('send').onclick = function() {
|
||||
fetch('/', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify ({
|
||||
message: document.getElementsByName("message")[0].value,
|
||||
}),
|
||||
});
|
||||
document.getElementsByName("message")[0].value = "";
|
||||
};
|
||||
});
|
||||
12
ranchimallflo-api/templates/index.html
Normal file
12
ranchimallflo-api/templates/index.html
Normal file
@ -0,0 +1,12 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>SSSE example</title>
|
||||
</head>
|
||||
<body>
|
||||
<input name="message" type="text"></input>
|
||||
<button id="send">Send</button>
|
||||
<ul></ul>
|
||||
<script type="text/javascript" src="{{ url_for('static', filename='broadcast.js') }}"></script>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Reference in New Issue
Block a user