2019-07-07 12:58:35 -07:00
|
|
|
const axios = require('axios')
|
|
|
|
const BN = require('bignumber.js')
|
|
|
|
const fs = require('fs')
|
2019-07-15 12:41:02 -07:00
|
|
|
const { computeAddress } = require('ethers').utils
|
2019-07-07 12:58:35 -07:00
|
|
|
|
2019-10-06 03:36:29 -07:00
|
|
|
const logger = require('./logger')
|
2019-10-08 10:45:28 -07:00
|
|
|
const redis = require('./db')
|
|
|
|
const { publicKeyToAddress } = require('./crypto')
|
2019-10-06 03:36:29 -07:00
|
|
|
|
2019-07-15 12:41:02 -07:00
|
|
|
const { FOREIGN_URL, PROXY_URL, FOREIGN_ASSET } = process.env
|
2019-07-07 12:58:35 -07:00
|
|
|
|
2019-11-01 11:43:25 -07:00
|
|
|
const FOREIGN_START_TIME = parseInt(process.env.FOREIGN_START_TIME, 10)
|
|
|
|
const FOREIGN_FETCH_INTERVAL = parseInt(process.env.FOREIGN_FETCH_INTERVAL, 10)
|
|
|
|
const FOREIGN_FETCH_BLOCK_TIME_OFFSET = parseInt(process.env.FOREIGN_FETCH_BLOCK_TIME_OFFSET, 10)
|
2019-10-31 12:43:34 -07:00
|
|
|
|
2019-07-07 12:58:35 -07:00
|
|
|
const foreignHttpClient = axios.create({ baseURL: FOREIGN_URL })
|
|
|
|
const proxyHttpClient = axios.create({ baseURL: PROXY_URL })
|
|
|
|
|
2019-11-01 11:43:25 -07:00
|
|
|
function getLastForeignAddress() {
|
|
|
|
const epoch = Math.max(0, ...fs.readdirSync('/keys')
|
|
|
|
.map((x) => parseInt(x.split('.')[0].substr(4), 10)))
|
|
|
|
if (epoch === 0) {
|
|
|
|
return null
|
2019-07-07 12:58:35 -07:00
|
|
|
}
|
2019-11-01 11:43:25 -07:00
|
|
|
const keysFile = `/keys/keys${epoch}.store`
|
|
|
|
const publicKey = JSON.parse(fs.readFileSync(keysFile))[5]
|
|
|
|
return publicKeyToAddress(publicKey)
|
2019-07-07 12:58:35 -07:00
|
|
|
}
|
|
|
|
|
2019-11-01 11:43:25 -07:00
|
|
|
function getTx(hash) {
|
2019-07-15 12:41:02 -07:00
|
|
|
return foreignHttpClient
|
|
|
|
.get(`/api/v1/tx/${hash}`, {
|
|
|
|
params: {
|
|
|
|
format: 'json'
|
|
|
|
}
|
|
|
|
})
|
2019-11-01 11:43:25 -07:00
|
|
|
.then((res) => res.data.tx.value)
|
2019-07-15 12:41:02 -07:00
|
|
|
.catch(() => getTx(hash))
|
|
|
|
}
|
|
|
|
|
2019-11-01 11:43:25 -07:00
|
|
|
function getBlockTime() {
|
2019-10-31 08:46:14 -07:00
|
|
|
return foreignHttpClient
|
2019-11-01 11:43:25 -07:00
|
|
|
.get('/api/v1/time')
|
|
|
|
.then((res) => Date.parse(res.data.block_time) - FOREIGN_FETCH_BLOCK_TIME_OFFSET)
|
2019-10-31 08:46:14 -07:00
|
|
|
.catch(() => getBlockTime())
|
|
|
|
}
|
|
|
|
|
2019-11-01 11:43:25 -07:00
|
|
|
async function fetchNewTransactions() {
|
2019-10-06 03:36:29 -07:00
|
|
|
logger.debug('Fetching new transactions')
|
2019-11-01 11:43:25 -07:00
|
|
|
const startTime = parseInt(await redis.get('foreignTime'), 10) + 1
|
2019-10-07 06:49:20 -07:00
|
|
|
const address = getLastForeignAddress()
|
2019-10-31 12:43:34 -07:00
|
|
|
const endTime = Math.min(startTime + 3 * 30 * 24 * 60 * 60 * 1000, await getBlockTime())
|
2019-11-01 11:43:25 -07:00
|
|
|
if (address === null) {
|
2019-10-31 08:46:14 -07:00
|
|
|
return {}
|
2019-11-01 11:43:25 -07:00
|
|
|
}
|
2019-10-06 03:36:29 -07:00
|
|
|
logger.debug('Sending api transactions request')
|
2019-10-31 08:46:14 -07:00
|
|
|
const params = {
|
|
|
|
address,
|
|
|
|
side: 'RECEIVE',
|
|
|
|
txAsset: FOREIGN_ASSET,
|
|
|
|
txType: 'TRANSFER',
|
|
|
|
startTime,
|
2019-11-01 11:43:25 -07:00
|
|
|
endTime
|
2019-10-31 08:46:14 -07:00
|
|
|
}
|
|
|
|
try {
|
|
|
|
logger.trace('%o', params)
|
|
|
|
const transactions = (await foreignHttpClient
|
|
|
|
.get('/api/v1/transactions', { params })).data.tx
|
2019-11-01 11:43:25 -07:00
|
|
|
return {
|
|
|
|
transactions,
|
|
|
|
endTime
|
|
|
|
}
|
2019-10-31 08:46:14 -07:00
|
|
|
} catch (e) {
|
|
|
|
return await fetchNewTransactions()
|
|
|
|
}
|
2019-07-07 12:58:35 -07:00
|
|
|
}
|
|
|
|
|
2019-11-01 11:43:25 -07:00
|
|
|
async function initialize() {
|
|
|
|
if (await redis.get('foreignTime') === null) {
|
|
|
|
logger.info('Set default foreign time')
|
|
|
|
await redis.set('foreignTime', FOREIGN_START_TIME)
|
|
|
|
}
|
2019-07-07 12:58:35 -07:00
|
|
|
}
|
|
|
|
|
2019-11-01 11:43:25 -07:00
|
|
|
async function main() {
|
|
|
|
const { transactions, endTime } = await fetchNewTransactions()
|
|
|
|
if (!transactions || transactions.length === 0) {
|
|
|
|
logger.debug('Found 0 new transactions')
|
|
|
|
await new Promise((r) => setTimeout(r, FOREIGN_FETCH_INTERVAL))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
logger.info(`Found ${transactions.length} new transactions`)
|
|
|
|
logger.trace('%o', transactions)
|
|
|
|
|
|
|
|
for (let i = transactions.length - 1; i >= 0; i -= 1) {
|
|
|
|
const tx = transactions[i]
|
|
|
|
if (tx.memo !== 'funding') {
|
|
|
|
const publicKeyEncoded = (await getTx(tx.txHash)).signatures[0].pub_key.value
|
|
|
|
await proxyHttpClient
|
|
|
|
.post('/transfer', {
|
|
|
|
to: computeAddress(Buffer.from(publicKeyEncoded, 'base64')),
|
|
|
|
value: new BN(tx.value).multipliedBy(10 ** 18)
|
|
|
|
.integerValue(),
|
|
|
|
hash: `0x${tx.txHash}`
|
|
|
|
})
|
|
|
|
}
|
2019-07-07 12:58:35 -07:00
|
|
|
}
|
2019-11-01 11:43:25 -07:00
|
|
|
await redis.set('foreignTime', endTime)
|
|
|
|
}
|
|
|
|
|
|
|
|
initialize()
|
|
|
|
.then(async () => {
|
|
|
|
while (true) {
|
|
|
|
await main()
|
|
|
|
}
|
|
|
|
})
|