/
app.py
114 lines (99 loc) · 3.04 KB
/
app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import eth_abi
import json
import os
import re
import sys
import urllib.request
iexec_out = os.environ['IEXEC_OUT']
iexec_in = os.environ['IEXEC_IN']
class Lib:
def parseValue(rawValue, ethType, power):
if re.search('^u?int[0-9]*$', ethType):
return round(float(rawValue) * 10 ** int(power))
else:
return rawValue
def formatArgs(args):
return '&'.join('{}={}'.format(k,v) for k,v in args.items())
def getAPIKey():
try:
with open(iexec_in + '/' + 'key.txt', 'r') as dataset_file:
apiKey = dataset_file.read().strip()
if not re.search('^[0-9a-zA-Z]{1,128}$', apiKey):
raise Exception('Invalid API key')
return apiKey
except FileNotFoundError:
raise Exception('Missing API key dataset')
def fetchMarketData(region, endpoint, params):
print('Request https://{region}.market-api.kaiko.io/v1/data/trades.v1/{endpoint}?{params}'.format(
region = region,
endpoint = endpoint,
params = params,
))
return json.loads(
urllib.request.urlopen(
urllib.request.Request(
'https://{region}.market-api.kaiko.io/v1/data/trades.v1/{endpoint}?{params}'.format(
region = region,
endpoint = endpoint,
params = params,
),
headers = {
'X-Api-Key': Lib.getAPIKey(),
'User-Agent': 'Kaiko iExec Adapter',
}
)
).read()
)
class PriceFeed:
def fetchRate(baseAsset, quoteAsset):
return Lib.fetchMarketData(
'us',
'spot_direct_exchange_rate/{baseAsset}/{quoteAsset}/recent'.format(baseAsset=baseAsset, quoteAsset=quoteAsset),
Lib.formatArgs({
'interval': '1m',
'limit': 720,
})
)
def run(baseAsset, quoteAsset, power):
response = PriceFeed.fetchRate(
baseAsset = baseAsset,
quoteAsset = quoteAsset,
)
try:
data = response.get('data')[0]
timestamp = data.get('timestamp')
details = 'Price-{base}/{quote}-{power}'.format(base=baseAsset.upper(), quote=quoteAsset.upper(), power=power)
rawValue = data.get('price')
value = Lib.parseValue(rawValue, 'uint256', power)
return (timestamp, details, value)
except Exception as e:
raise Exception('API response parsing failure: {}'.format(e))
# Example usage:
# btc usd 9
if __name__ == '__main__':
print('PriceFeed started')
success = False
data = (0, '', 0) # default returned value to avoid attack on scheduler
try:
# EXECUTE CALL
data = PriceFeed.run(
baseAsset = sys.argv[1],
quoteAsset = sys.argv[2],
power = sys.argv[3],
)
success = True
print('- Success: {} {} {}'.format(*data))
except IndexError as e:
print('Error: missing arguments')
except Exception as e:
print('Execution Failure: {}'.format(e))
# GENERATE CALLBACK
callback_data = eth_abi.encode_abi(['uint256', 'string', 'uint256'], [*data]).hex()
callback_data = '0x{}'.format(callback_data)
print('Offchain Computing for Smart-Contracts [data:{}, callback_data:{}]'.format(data, callback_data))
with open(iexec_out + '/computed.json', 'w+') as f:
json.dump({ "callback-data" : callback_data}, f)
if success:
print('PriceFeed completed')
else:
print('PriceFeed failed')