Skip to content

Instantly share code, notes, and snippets.

@itoonx
Created April 22, 2021 12:39
Show Gist options
  • Save itoonx/4dbdea972231fbb0bf304cd883158e27 to your computer and use it in GitHub Desktop.
Save itoonx/4dbdea972231fbb0bf304cd883158e27 to your computer and use it in GitHub Desktop.
/*
* @Author: itoonx
* @Date: 2018-05-01 22:55:25
* @Last Modified by: itoonx
* @Last Modified time: 2018-08-30 08:14:49
*/
const fs = require('fs')
const path = require('path')
const chalk = require('chalk')
const crypto = require('crypto')
const { web3, engine } = require('../../config/web3provider')
const WalletModel = require('../../api/wallet/wallet.model')
const TransactionModel = require('../../api/transaction/transaction.model')
const tokensConfig = JSON.parse(fs.readFileSync(path.join(__dirname, '../../../../shared/ethereum/abi/tokensConfig.json')))
var listOfCurrencyBaseOnEther = ['ETH']
tokensConfig.map((item) => {
listOfCurrencyBaseOnEther.push(item.symbol)
})
/**
* @param {object} block - Ethereum block file from web socket
*/
const parseAddressFromBlock = (block) => {
block.transactions.map( async (tx, index) => {
if (tx.to) {
try {
const blockNumber = Number.parseInt(tx.blockNumber.toString('hex'), 16)
const blockHash = tx.blockHash
const nonce = tx.nonce
const txHash = tx.hash
const senderAddress = tx.from
const recieverAddress = tx.to
const value = tx.value
const wallet = await WalletModel.findOne({ address: recieverAddress })
if (wallet) {
let ctx = new TransactionModel({
user_id: wallet.user_id,
currency_type: 'ETH',
block_hash: blockHash,
block_number: blockNumber,
tx_type: 'Deposit',
txhash: txHash,
from_address: senderAddress,
to_address: recieverAddress,
amount: Number.parseFloat(value.toString('hex'), 16) / 1e18, // Convert wei to ether by 18 decimal point
current_confirmation: 1,
sequence_hash: crypto.createHash('sha256').update(txHash, value + nonce).digest('base64'),
status: 'WaitingForConfirm'
})
console.log(`ETH: Found Transaction in block #${txHash}`)
await ctx.save()
/**
* Add deposit pending here....
* Fire data via socket.io
*/
}
} catch (err) {
throw new Error(err)
}
}
})
}
async function checkConfirmationAndUpdateBalance (block_number) {
let getBlockToConfirm = block_number - process.env.ETHEREUM_REQUIRED_CONFIRMATION
let context = {
status: 'WaitingForConfirm',
tx_type: 'Deposit',
currency_type: { $in: listOfCurrencyBaseOnEther },
block_number: { $lt: block_number },
}
let deposits = await TransactionModel.find(context)
// console.log('deposits', deposits)
for (let dptx of deposits) {
let dp = await TransactionModel.findById(dptx._id)
console.log('dp', dp)
// // ถ้า Block ปัจจุบัน - 16 แล้วยังไม่มากเท่า Block Number ของ TXID ที่เก็บเอาไว้ ให้อัพเดทจำนวน Confirm เฉยๆ
if (dptx.block_number > getBlockToConfirm) {
/**
* Update Confirmation
* - +=1 current_confirmation
* Fire data via socket.io
*/
dp.current_confirmation += 1
let save = await dp.save()
// ถ้ายอด Confirm เกิน 16 แล้วถือว่า Confirm
} else if (dptx.block_number <= getBlockToConfirm) {
/**
* Move balance pending to available
*/
// let amount = dptx.amount
dp.current_confirmation += 1
dp.status = 'Confirmed'
let save = await dp.save()
}
}
}
const watcherERC20TokenTransfer = async () => {
tokensConfig.forEach(tknConfig => {
if (tknConfig.enable === true && process.env.ETHEREUM_SERVER === tknConfig.network) {
console.log(`ERC20: ${tknConfig.tokenName} - Transfer Event Listening`)
// filter ethereum network for look up the event in token contract
web3.eth.filter({
fromBlock: 'latest', // lastest block only
address: tknConfig.contractAddress,
topics:[
web3.sha3(tknConfig.transferEvent) // Transfer Event
]
}).watch((err, incomingTx) => {
if (err) return err
let txHash = incomingTx.transactionHash
let blockNumber = incomingTx.blockNumber
let blockHash = incomingTx.blockHash
web3.eth.getTransactionReceipt(txHash, async (err, receipt) => {
if (err) return err
// if the transaction status = success
if (receipt) {
// console.log('receipt', receipt)
if (receipt.status != null || receipt.status != 'undefined') {
if (receipt.status === '0x1') {
const from_addr_with_0x = `0x${incomingTx.topics[1].slice(26)}`
const to_addr_with_0x = `0x${incomingTx.topics[2].slice(26)}`
const tokenAmount = Number.parseFloat( web3.toDecimal(incomingTx.data) / 10 ** tknConfig.decimals )
// console.log(`ERC20: - From ${from_addr_with_0x} | To ${to_addr_with_0x} | Amount ${tokenAmount} ${tknConfig.symbol}`)
// console.log('globals.blockNumber', globals.blockNumber)
const wallet = await WalletModel.findOne({ address: to_addr_with_0x })
if (wallet) {
let ctx = new TransactionModel({
user_id: wallet.user_id,
currency_type: tknConfig.symbol,
block_hash: blockHash,
block_number: blockNumber,
tx_type: 'Deposit',
txhash: txHash,
from_address: from_addr_with_0x,
to_address: to_addr_with_0x,
amount: tokenAmount,
current_confirmation: 0,
sequence_hash: crypto.createHash('sha256').update(txHash, tokenAmount).digest('base64'),
status: 'WaitingForConfirm'
})
console.log(`${tknConfig.symbol}: Found Transaction #${txHash} | Amount ${tokenAmount}`)
await ctx.save()
/**
* Add deposit pending here....
* Fire data via socket.io
*/
}
}
}
}
})
})
}
})
}
const watchEthereumBlock = () => {
engine.on('block', async (block) => {
const blockNumber = Number.parseInt(block.number.toString('hex'), 16)
const blockHash = `0x${block.hash.toString('hex')}`
console.log(chalk.yellow('ETH: BLOCK CHANGED:', '#'+blockNumber, blockHash))
parseAddressFromBlock(block)
checkConfirmationAndUpdateBalance(blockNumber)
})
}
setTimeout(() => {
watchEthereumBlock()
watcherERC20TokenTransfer()
}, 100)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment