-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathethGetter.js
More file actions
316 lines (267 loc) · 12.5 KB
/
ethGetter.js
File metadata and controls
316 lines (267 loc) · 12.5 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
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
import Web3 from 'web3';
import TBTC from '@keep-network/tbtc.js/src/TBTC.js';
import factoryAbi from '@keep-network/tbtc/artifacts/DepositFactory.json'
import tokenAbi from '@keep-network/tbtc/artifacts/TBTCToken.json'
import EthereumHelpers from '@keep-network/tbtc.js/src/EthereumHelpers.js'
import BitcoinHelpers from '@keep-network/tbtc.js/src/BitcoinHelpers.js'
import sqlite3 from 'sqlite3'
import dotenv from 'dotenv'
dotenv.config()
let tbtc
let web3
let db
let tBTCfactoryContract ={}
let tBTCtokenContract ={}
const MS_TO_GRAB_ALL_DATA = typeof process.env.MS_TO_GRAB_ALL_DATA === 'undefined' ? 3600000 : process.env.MS_TO_GRAB_ALL_DATA
const MS_TO_GRAB_LAST_DEPOSITS = typeof process.env.MS_TO_GRAB_LAST_DEPOSITS === 'undefined' ? 30000 : process.env.MS_TO_GRAB_LAST_DEPOSITS
const QTY_TO_GRAB_LAST_DEPOSITS = typeof process.env.QTY_TO_GRAB_LAST_DEPOSITS === 'undefined' ? 20 : process.env.QTY_TO_GRAB_LAST_DEPOSITS
function findThisState(configStates, nowStateInt){
for(let state in configStates){
if(parseInt(configStates[state]) === parseInt(nowStateInt))
return state
}
return {error: true, msg:'state not found'}
}
async function getAllEventsInTBTCtoken(shiftGetting, tBTCcontract, txHashesInDB){
//getting all DepositCloneCreated events (deposits) from factoryContract
let events
try{
events = await tBTCcontract.getPastEvents('DepositCloneCreated', {
fromBlock: 0,
toBlock: 'latest'
})}catch(e){return}
//calculate shift for only needed qty deposits
let startSearching = 0
if(shiftGetting !== 0)
startSearching= events.length - shiftGetting
for(let i=startSearching;i<events.length;i++){
if(typeof txHashesInDB[events[i].transactionHash] === 'undefined' || typeof txHashesInDB[events[i].transactionHash].depositAddress === 'undefined')
await getDeposit(events[i].transactionHash, null)
else
await getDeposit(null, txHashesInDB[events[i].transactionHash].depositAddress, txHashesInDB[events[i].transactionHash].nowConfirmations, txHashesInDB[events[i].transactionHash].requiredConfirmations, txHashesInDB[events[i].transactionHash].knownStatus, true)
}
//collect information about token
let tokenTotalSupply = parseInt(await tBTCtokenContract.methods.totalSupply().call())*0.000000000000000001
if(!isNaN(tokenTotalSupply)){
db.run(`INSERT INTO allInfo (key,value) VALUES ("TBTCtokenTotalSupply",${tokenTotalSupply})
ON CONFLICT (key) DO UPDATE SET value=${tokenTotalSupply} where key="TBTCtokenTotalSupply"`)
}
return
}
async function getDeposit(txHash=null, depositAddress = null, nowConfirmations = null, requiredConfirmations= null, knownStatus=null, isBackApi=false){
//If we know full info about deposit and this is goes from internal query - ignore it
if( (knownStatus == 'REDEEMED' || knownStatus == 'ACTIVE') && (parseInt(nowConfirmations)>parseInt(requiredConfirmations)) && isBackApi === true)
return
try{
//prepare output object
let thisDeposit = {}
if(txHash !== null)
thisDeposit.txHash = txHash
else if(depositAddress !== null)
thisDeposit.depositAddress = depositAddress
else
return false
//This is only for never seened depositAddress
if(depositAddress === null){
//here needed events
var transactionInfo = await web3.eth.getTransactionReceipt(thisDeposit.txHash)
//getting deposit's amount
var transactionsSatoshis = await (web3.eth.getTransaction(thisDeposit.txHash))
thisDeposit.BTCamount = parseFloat(web3.eth.abi.decodeParameter('uint64', transactionsSatoshis.input.slice(-64)))*0.00000001
// Mismatch web3 and EthereumHelpers versions
if(typeof transactionInfo.events == 'undefined'){
transactionInfo.events = transactionInfo.logs
for(let eventTX =0; eventTX < transactionInfo.events.length; eventTX++){
if(typeof transactionInfo.events[eventTX].raw =='undefined')
transactionInfo.events[eventTX].raw={
topics: transactionInfo.events[eventTX].topics,
data: transactionInfo.events[eventTX].data,
}
}
}
//End mismatch
//from events of transaction getting deposit address by factoryContract abi
thisDeposit.depositAddress = (await EthereumHelpers.readEventFromTransaction(web3,transactionInfo,tBTCfactoryContract,'DepositCloneCreated'))[0]
}
//try to get deposit instance
let deposit
try{
deposit = await tbtc.Deposit.withAddress(thisDeposit.depositAddress)
}catch(e){
console.log(e)
return
}
thisDeposit.bitcoinAddress = await deposit.bitcoinAddress
//getting state of contract instance
thisDeposit.state = findThisState(deposit.factory.State, await deposit.getCurrentState())
//if confirmations qty not reach needed yet - grab it from electrumX
if((parseInt(nowConfirmations) < parseInt(requiredConfirmations)) || nowConfirmations == null || requiredConfirmations == null || requiredConfirmations == 'null' || nowConfirmations == 'null'){
try{
let gettingTransaction = (await BitcoinHelpers.Transaction.findAllUnspent(thisDeposit.bitcoinAddress))[0]
if(typeof gettingTransaction.transactionID !=='undefined'){
thisDeposit.btcTransactionID= gettingTransaction.transactionID
thisDeposit.nowConfirmations = await BitcoinHelpers.Transaction.checkForConfirmations(thisDeposit.btcTransactionID ,0)
}
}catch(e){
console.log(e)
}
}else{
thisDeposit.nowConfirmations = nowConfirmations
}
if(thisDeposit.nowConfirmations == null || typeof thisDeposit.nowConfirmations == 'undefined' || thisDeposit.nowConfirmations == 'null' ){
if(thisDeposit.state === "AWAITING_BTC_FUNDING_PROOF")
thisDeposit.nowConfirmations = 0
else if(thisDeposit.state === "ACTIVE" || thisDeposit.state === "REDEEMED" || thisDeposit.state === "AWAITING_WITHDRAWAL_PROOF")
thisDeposit.nowConfirmations = requiredConfirmations != null ? parseInt(requiredConfirmations) : 6
}
//Only for new deposits
if(depositAddress === null){
thisDeposit.keepAddress = deposit.keepContract._address
//ts creating deposit at block of transaction
thisDeposit.timestamp = (await web3.eth.getBlock(transactionInfo.blockNumber)).timestamp
//needed confirmations. Mainly 6
thisDeposit.requiredConfirmations = await deposit.requiredConfirmations
}
//prepare deposit values to store in sqlite
let valuesToInsert = Object.values(thisDeposit).map((element)=>{
return `"${element}"`
}).toString()
//insert or update status of deposit
if(typeof thisDeposit.btcTransactionID =='undefined' || thisDeposit.btcTransactionID == null || thisDeposit.btcTransactionID == 'null'){
db.run(`INSERT INTO deposits ("id",${Object.keys(thisDeposit)}) values ((SELECT IFNULL(MAX(id), 0) + 1 FROM deposits), ${valuesToInsert})
ON CONFLICT(depositAddress) DO
UPDATE SET state="${thisDeposit.state}", nowConfirmations="${thisDeposit.nowConfirmations}" where depositAddress="${thisDeposit.depositAddress}"`)
}else{
db.run(`INSERT INTO deposits ("id",${Object.keys(thisDeposit)}) values ((SELECT IFNULL(MAX(id), 0) + 1 FROM deposits), ${valuesToInsert})
ON CONFLICT(depositAddress) DO
UPDATE SET state="${thisDeposit.state}", nowConfirmations="${thisDeposit.nowConfirmations}", btcTransactionID="${thisDeposit.btcTransactionID}" where depositAddress="${thisDeposit.depositAddress}"`)
}
return thisDeposit
}catch(e){console.log(e)}
}
async function getEvents(shiftSearching) {
try{
db.all(`SELECT depositAddress,txHash,nowConfirmations,requiredConfirmations,state FROM deposits`, async (err,rows)=>{
let txHashes = {}
for(let i=0; i< rows.length;i++){
txHashes[rows[i].txHash] = {
depositAddress:rows[i].depositAddress,
requiredConfirmations:rows[i].requiredConfirmations,
nowConfirmations:rows[i].nowConfirmations,
knownStatus:rows[i].state,
}
}
await getAllEventsInTBTCtoken(shiftSearching, tBTCfactoryContract, txHashes)
shiftSearching
})
}catch(e){console.log(e)}
}
async function connect(){
// connect or create local sqlite db
db = new sqlite3.Database('./database.db', (err) => {
if (err) {
console.error(err.message);
}
console.log('Connected to the deposits database.');
});
// Making 2 local tables:
// for store all deposits
// And for all potentially additional info
db.serialize(function() {
db.run(`CREATE TABLE IF NOT EXISTS deposits (
id INTEGER,
depositAddress TEXT PRIMARY KEY,
bitcoinAddress TEXT,
btcTransactionID TEXT,
txHash TEXT,
keepAddress TEXT,
requiredConfirmations TEXT,
state TEXT,
nowConfirmations TEXT,
timestamp TEXT,
BTCamount TEXT
)`);
})
db.serialize(function() {
db.run(`CREATE TABLE IF NOT EXISTS allInfo (
key TEXT PRIMARY KEY,
value TEXT
)`);
})
//establishing connection to mainnet eth with web3
web3 = await new Web3(process.env.WEB3_PROVIDER)
//now going to tbtc mainnet
tbtc = await TBTC.withConfig({
web3: web3,
bitcoinNetwork: "main",
electrum: {
server: process.env.ELECTRUM_SERVER,
port:process.env.ELECTRUM_PORT,
protocol: process.env.ELECTRUM_PROTOCOL
},
})
const tBTCfactoryAddress = '0x87EFFeF56C7fF13E2463b5d4dCE81bE2340FAf8b'
const tTBTCtokenAddress = '0x8dAEBADE922dF735c38C80C7eBD708Af50815fAa'
//creating tbtc factory contract object
tBTCfactoryContract = new web3.eth.Contract(factoryAbi.abi, web3.utils.toChecksumAddress(tBTCfactoryAddress));
//creating tbtc token contract object
tBTCtokenContract = new web3.eth.Contract(tokenAbi.abi, web3.utils.toChecksumAddress(tTBTCtokenAddress));
}
async function main(){
/*
At first startup - goes through all events - only then - starting 2 timers
1st - every ?60 minutes? - for actualazing all events
2s - every 40 seconds - for actualising last ?20 events/
*/
//connecting to db, web3, tbtc
await connect()
// Read DB and find already exists deposits if < 10 - we think it firstInitialize and grab all data
// If > 10 - then going to last 20 events only
db.all(`SELECT COUNT(id) from deposits`, (err,row) =>{
let count = row[0]['COUNT(id)']
if(count < 10){
getEvents(0).then(()=>{
fewLastEvents()
setInterval( ()=>{
getEvents(0)
.then(() => {
console.log("All done!")
})
.catch(error => {
console.log(error)
})
}, 3600000)
})
}else{
fewLastEvents()
setInterval( ()=>{
getEvents(0)
.then(() => {
console.log("All done!")
})
.catch(error => {
console.log(error)
})
}, MS_TO_GRAB_ALL_DATA)
}
});
//every ~30seconds grab last 20 deposits
function fewLastEvents(){
getEvents(QTY_TO_GRAB_LAST_DEPOSITS).then(() => {
console.log(`Last ${QTY_TO_GRAB_LAST_DEPOSITS} done!`)
setTimeout(fewLastEvents,MS_TO_GRAB_LAST_DEPOSITS)
})
}
}
function startAll(){
try{
main()
}catch(e){
console.log(e)
startAll()
}
}
export default {
startAll,
getDeposit
}