import { web3 } from "hardhat"; import History from "../interface/history"; import contracts from "../../config/contracts"; import logger from "../../utils/logger"; import history from "../interface/history"; const ierc20abi = require('../../abi/IERC20_ABI.json') // 初始化410 v2工具箱 const v2ToolBy410Abi = require('../../abi/410_V2_TOOLS.json') const v2ToolBy410 = new web3.eth.Contract(v2ToolBy410Abi, contracts.V2_TOOLS_BY_410) export class LpMaintenance { tokenInstance: any = {} maxMemoryOfByte: number = 0 maxMemoryChanged: boolean = true async saveLp(lp: any, type='0') { await History.appendOrUpdate(type, lp.LP, lp) } async checkLpType(lp: any) { const ethTokenList = [ '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', // WETH '0xaf3ccfd9b59b36628cc2f659a09d6440795b2520', // ETH '0x7bf88d2c0e32de92cdaf2d43ccdc23e8edfd5990' // WETHW ] const filterTypeList = [ { type: 'topLp', limit: 10 * 1e18 }, { type: 'normalLp', limit: 1 * 1e18 }, { type: 'lp', limit: 0 }, ] if (ethTokenList.indexOf(lp.token0.toLowerCase()) == -1 && ethTokenList.indexOf(lp.token1.toLowerCase()) == -1) { return 'normalLp' } for (const filterType of filterTypeList) { if (ethTokenList.indexOf(lp.token0.toLowerCase()) != -1) { if (parseInt(lp.r0) >= filterType.limit) return filterType.type } else if (ethTokenList.indexOf(lp.token1.toLowerCase()) != -1) { if (parseInt(lp.r1) >= filterType.limit) return filterType.type } } } async handleLp(lp: any, oldType: any) { // 过滤Lp let lpType = await this.checkLpType(lp) // 一共12w个池子,非ethw的垃圾池子就不拉了 if (lpType == 'lp' && !lp.isEthW) { lpType = 'ethLp' } if (lpType != oldType) { // 保存变更之后的的Token // await this.saveToken(lp, lpType) // 保存变更后的Lp await this.saveLp(lp, lpType) logger.debug(`lp:${lp.LP},${oldType}->${lpType}.`) } } showMemory (mainInfo: string) { const memoryUsage = process.memoryUsage() if (this.maxMemoryOfByte < memoryUsage.rss) { this.maxMemoryOfByte = memoryUsage.rss this.maxMemoryChanged = true } if (this.maxMemoryChanged) { logger.debug(`${mainInfo} ${this.format(memoryUsage.rss)}/${this.format(this.maxMemoryOfByte)}`) this.maxMemoryChanged = false } } format (bytes: any) { return (bytes / 1024 / 1024).toFixed(2) + ' MB'; } generateAddressListByLpList (lpList: any) { const lpAddressList: any = [] for (const lp of lpList) { lp.dataObj = JSON.parse(lp.data) lpAddressList.push(lp.dataObj.LP) } return lpAddressList } updateLocalLpListR0R1(lpList: any, r0s: any, r1s: any) { for (let index = 0; index < lpList.length; index++) { lpList[index].dataObj.r0 = r0s[index] lpList[index].dataObj.r1 = r1s[index] } } async run() { logger.debug('LP maintenance start.') while (true) { this.showMemory('a loop...') const topLpPullRst = await history.findByBlock('topLp') if (!topLpPullRst.state) continue const topLpList = topLpPullRst.data const lpPullRst = await history.findByBlock('lp') if (!lpPullRst.state) continue const lpList = lpPullRst.data const normalLpPullRst = await history.findByBlock('normalLp') if (!normalLpPullRst.state) continue const normalLpList = normalLpPullRst.data const zeroLpPullRst = await history.findByBlock('0') if (!zeroLpPullRst.state) continue const zeroLpList = zeroLpPullRst.data const allTypeLpList: any = [].concat(topLpList).concat(lpList).concat(normalLpList).concat(zeroLpList) const lpAddressList: any = this.generateAddressListByLpList(allTypeLpList) // logger.debug(`${lpAddressList.length}`) // 集中拉取r0,r1并更新本地的 const size = 2000 for (let from = 0; from < allTypeLpList.length; from += size) { // logger.debug(`${from}, ${allTypeLpList.length}`) const lpR0R1Info: any = await v2ToolBy410.methods.getPairSBalance(lpAddressList.slice(from, from + size)).call() const r0s = lpR0R1Info.amounts0 const r1s = lpR0R1Info.amounts1 this.updateLocalLpListR0R1(allTypeLpList.slice(from, from + size), r0s, r1s) } // 将lp类型有变动的全部更新 for (const lpDbObj of allTypeLpList) { await this.handleLp(lpDbObj.dataObj, lpDbObj.block) } } } } async function main() { await new LpMaintenance().run() } main().catch((error) => { console.error(error); process.exitCode = 1; })