-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapi.js
More file actions
89 lines (73 loc) · 3.06 KB
/
api.js
File metadata and controls
89 lines (73 loc) · 3.06 KB
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
const axios = require('axios');
const fs = require('fs');
const Web3 = require('web3');
const promisify = require('es6-promisify')
const config = require('./config');
const Cacher = require('./cacher');
const web3 = new Web3(new Web3.providers.HttpProvider(config.parityURL));
const contractABICache = new Cacher('./db/contracts/', getContractABI);
const historyCache = new Cacher('./db/history', getVariableHistory,
({address, variable}) => address + '/' + variable);
const blockTimeCache = new Cacher('./db/blocks', getBlockTime,
x => Math.round(x / 1000) * 1000);
module.exports.getContractMetadata = async function (address) {
const abiJSON = await (contractABICache.get(address));
const contract = web3.eth.contract(abiJSON).at(address);
return {
address,
abi: contract.abi,
variables: extractVariables(contract.abi)
};
}
module.exports.getVariableHistory = function (address, variable) {
return historyCache.get({address, variable});
};
async function getContractABI(address) {
const url = 'https://api.etherscan.io/api?module=contract&action=getabi'
+ '&address='+ address + '&apikey=' + config.etherscan_api_key;
const response = await axios.get(url);
const abi = JSON.parse(response.data.result);
return abi;
}
async function getVariableHistory({address, variable}) {
console.time('Whole history');
console.time('Contract retrieval');
const abiJSON = await (contractABICache.get(address));
const contract = web3.eth.contract(abiJSON).at(address);
console.timeEnd('Contract retrieval');
const startBlock = web3.eth.blockNumber - 75000;
console.log('From block:', startBlock);
console.log('Sending trace filter request');
console.time('Trace filter request');
const events = await promisify(web3.trace.filter, web3.trace)({
"fromBlock": "0x" + startBlock.toString(16),
"toAddress": [address]
});
console.timeEnd('Trace filter request');
console.log('Browsing through ' + events.length + ' transactions');
var history = [];
var i = 0;
await Promise.all(events.map(async ({blockNumber}) => {
console.log('Requesting data for block number #' + blockNumber)
const timePromise = blockTimeCache.get(blockNumber);
const valPromise = promisify(contract[variable], contract)(blockNumber);
history.push({time: await timePromise, value: await valPromise});
console.log(`Fetched: ${i++} values`);
}));
history.sort((a, b) => a[0] - b[0]);
console.timeEnd('Whole history');
return history;
};
async function getBlockTime(blockNumber) {
const block = await promisify(web3.eth.getBlock, web3.eth)(blockNumber);
return block.timestamp;
};
function isVar(item) {
return item.outputs && item.outputs.length === 1
&& item.outputs[0].type.slice(0, 4) === 'uint' && item.inputs.length === 0;
}
function extractVariables(abi) {
const isVar = item => item.outputs && item.outputs.length === 1
&& item.inputs.length === 0 && item.outputs[0].type.match(/u?int/) !== null;
return abi.filter(isVar).map(item => item.name);
}