const Web3 = require('web3');
const Web3WsProvider = require('web3-providers-ws');
const axios = require('axios');
const numeral = require('numeral');
// ENTER A VALID RPC URL!
const options = {
timeout: 30000, // ms
// Useful for credentialed urls, e.g: ws://username:password@localhost:8546
headers: {
authorization: 'Basic username:password'
},
clientConfig: {
// Useful if requests are large
maxReceivedFrameSize: 100000000, // bytes - default: 1MiB
maxReceivedMessageSize: 100000000, // bytes - default: 8MiB
// Useful to keep a connection alive
keepalive: true,
keepaliveInterval: 60000 // ms
},
// Enable auto reconnection
reconnect: {
auto: true,
delay: 10000, // ms
maxAttempts: 10,
onTimeout: false
}
};
//Icon constant
const GREEN_CIRCLE = '\xF0\x9F\x9F\xA2';
const RED_CIRCLE = '\xF0\x9F\x94\xB4';
const SWAP_BUTTON = '\xF0\x9F\x94\x81';
const MONEY_BAG = '\xF0\x9F\x92\xB0';
const POINTING_HAND = '\xF0\x9F\x91\x89';
const config = require('../../config');
const CONTRACT_ABI = require('../ABI/ABI.json');
const notiPrivateRepo = require('../repository/repo');
const telegram = require('../lib/telegram');
const repo = require('../repository/repo');
class NotiPrivate {
constructor(listHolder, tokenAddress, symbol, pancakePair, pancakePairAddress, minAmountToAlert, holder,telegramReceiver, isAlertTransfer, ignoreAddress, minAmountValidate, ggSheetURL) {
this.web3 = new Web3(new Web3WsProvider(config.WS_SERVER_URL, options));
this.contract = new this.web3.eth.Contract(CONTRACT_ABI, tokenAddress);
this.transactionQueue = [];
this.listFollowAddress = listHolder;
this.telegramQueue = [];
this.tokenAddress = tokenAddress;
this.pancakePairAddress = pancakePairAddress;
this.pancakePair = pancakePair;
this.minAmountToAlert = minAmountToAlert;
this.symbol = symbol;
this.holder = holder;
this.isAlertTransfer = isAlertTransfer;
this.telegramReceiver = telegramReceiver;
this.ignoreAddress = ignoreAddress;
this.minAmountValidate = minAmountValidate;
this.ggSheetURL = ggSheetURL;
this.getEvents();
this.excuteQueue();
this.excuteQueueTeleGram()
}
updateData({minAmountToAlert, holder, telegramReceiver,isAlertTransfer}){
this.minAmountToAlert = minAmountToAlert;
this.holder = holder;
this.telegramReceiver = telegramReceiver;
this.isAlertTransfer = isAlertTransfer;
}
async getEvents() {
const currentBlockNumber = await this.web3.eth.getBlockNumber();
let options = {
filter: {
value: [],
},
fromBlock: currentBlockNumber
};
this.contract.events.Transfer(options)
.on('data', async (event) => {
try {
let amount = parseInt(this.web3.utils.fromWei(event.returnValues.amount, 'ether'));
let sender = event.returnValues.from;
let receiver = event.returnValues.to;
let transactionHash = event.transactionHash;
if(amount > parseInt(this.minAmountValidate)){
let price = await axios.get(config.MORALIS_ADMIN_URL + `${this.tokenAddress}/price?chain=bsc`,
{
headers: {
"accept": "application/json",
"X-API-Key": config.MORALIS_KEY,
}
})
let atPrice = price && price.data && price.data.usdPrice;
let usdPrice = (price && price.data && price.data.usdPrice) * amount;
let isHolder = false;
let action = 'Transfer';
if (this.listFollowAddress.includes(sender)) {
isHolder = true;
} else if (this.listFollowAddress.includes(receiver)) {
isHolder = true;
}
if (sender.toLowerCase() == this.pancakePairAddress.toLowerCase()) {
action = 'Buy';
} else if (receiver.toLowerCase() == this.pancakePairAddress.toLowerCase()) {
action = 'Sell';
}
if (usdPrice > this.minAmountToAlert ||isHolder ) {
let transactionInfo = {
sender,
receiver,
amount,
transactionHash,
isHolder,
action,
tokenAddress: this.tokenAddress,
usdPrice,
atPrice,
time: Date.now()
};
this.transactionQueue.push(transactionInfo);
}
}
} catch (err) {
console.log(err);
console.log(err.message);
}
})
.on('changed', changed => console.log(changed))
.on('error', () =>{} )
.on('connected', str => console.log(str))
};
excuteQueue() {
var self = this;
setInterval(async function () {
try{
let listTransaction = (self.transactionQueue || []).splice(0, self.transactionQueue.length);
for (let i = 0; i < listTransaction.length; i++) {
// const balanceSender = await self.contract.methods.balanceOf(listTransaction[i].sender).call();
// const balanceReceiver = await self.contract.methods.balanceOf(listTransaction[i].receiver).call();
// let tx = await self.web3.eth.getTransaction(listTransaction[i].transactionHash);
// let txRe = await self.web3.eth.getTransactionReceipt(listTransaction[i].transactionHash);
await notiPrivateRepo.insertRadaTransaction(listTransaction[i]);
/* Insert holder */
// const senderInfo = {
// holderAddress: listTransaction[i].sender,
// tokenAddress: self.tokenAddress,
// totalAmount: self.web3.utils.fromWei(balanceSender, 'ether'),
// time: listTransaction[i].time
// }
// const receiverInfo = {
// holderAddress: listTransaction[i].receiver,
// tokenAddress: self.tokenAddress,
// totalAmount: self.web3.utils.fromWei(balanceReceiver, 'ether'),
// time: listTransaction[i].time
// }
// await notiPrivateRepo.insertRadaHolder(senderInfo);
// await notiPrivateRepo.insertRadaHolder(receiverInfo);
if (listTransaction[i].usdPrice > self.minAmountToAlert || listTransaction[i].isHolder ) {
let icon = "";
/* check sell/buy/transfer */
switch (listTransaction[i].action) {
case "Buy":
icon = GREEN_CIRCLE;
break;
case "Sell":
icon = RED_CIRCLE;
break;
case "Transfer":
icon = SWAP_BUTTON;
break;
default:
break;
}
/* Rating star */
let rating = '';
if (0 < listTransaction[i].usdPrice && listTransaction[i].usdPrice < 20000) {
rating += icon;
} else if (listTransaction[i].usdPrice >= 20000 && listTransaction[i].usdPrice < 30000) {
rating += `${icon}${icon}`;
} else if (listTransaction[i].usdPrice >= 30000 && listTransaction[i].usdPrice <= 40000) {
rating += `${icon}${icon}${icon}`;
} else if (listTransaction[i].usdPrice > 40000 && listTransaction[i].usdPrice < 50000) {
rating += `${icon}${icon}${icon}${icon}`;
} else if (listTransaction[i].usdPrice >= 50000) {
rating += `${icon}${icon}${icon}${icon}${icon}`;
}
let senderAddress = listTransaction[i].sender;
let receiverAddress = listTransaction[i].receiver;
let senderTele = '<em>' + listTransaction[i].sender.substring(0, 3) + '...' + listTransaction[i].sender.substring(listTransaction[i].sender.length - 5, listTransaction[i].sender.length - 1) + '</em>';
let receiverTele = '<em>' + listTransaction[i].receiver.substring(0, 3) + '...' + listTransaction[i].receiver.substring(listTransaction[i].receiver.length - 5, listTransaction[i].receiver.length - 1) + '</em>';
let transactionHashTele = listTransaction[i].transactionHash.substring(0, 3) + '...' + listTransaction[i].transactionHash.substring(listTransaction[i].transactionHash.length - 5, listTransaction[i].transactionHash.length - 1);
let titleSender = '';
let titleReceiver = '';
if (senderAddress == self.pancakePairAddress) {
titleSender = ` (${self.pancakePair})`;
}
if (receiverAddress == self.pancakePairAddress) {
titleReceiver += ` (${self.pancakePair})`;
}
const remainingPercent = await repo.getRemainingAmountPercent(self.tokenAddress, self.ignoreAddress);
const privateHolderPercent = remainingPercent.length > 0 && remainingPercent[0].remaining_amount_percent;
/* Format message*/
let msg = `${self.symbol} <b>${listTransaction[i].action}</b> Alert ${rating}\n` +
`<code>${numeral(listTransaction[i].amount).format('0,0.00')}</code> <code>$${self.symbol}</code> at <code>${numeral(listTransaction[i].atPrice).format('0,0.0000')}</code> ${MONEY_BAG} $${numeral(listTransaction[i].usdPrice).format('0,0')}\n` +
`<a href='https://bscscan.com/address/${listTransaction[i].sender}'>${senderTele}</a>${titleSender}` + ' \xE2\x9E\xA1 ' +
`<a href='https://bscscan.com/address/${listTransaction[i].receiver}'>${receiverTele}</a>${titleReceiver}` +
` ${POINTING_HAND} Tx: <a href='https://bscscan.com/tx/${listTransaction[i].transactionHash}'>${transactionHashTele}</a>\n` +
`<b>Remaining:</b> <code>${numeral(privateHolderPercent).format('0,0')}%</code>\n` +
`<a href='${self.ggSheetURL}'>See more...</a>\n\n`
if(self.isAlertTransfer || listTransaction[i].action != 'Transfer'){ //false + transfer
self.telegramQueue.push(msg);
}
}
}
}catch(err){
console.log(err);
}
}, 5000);
}
excuteQueueTeleGram() {
var self = this;
setInterval(async function () {
let message = self.telegramQueue.shift();
if (message) {
telegram.sendMessage(self.telegramReceiver, message);
}
}, 2000);
}
}
module.exports = NotiPrivate;