const web3 = require('hardhat').web3 const logger = require("../../utils/logger") const BigNumber = require('ethers').BigNumber const replaceAll = require("hardhat/internal/util/strings").replaceAll const Time = require("../../utils/time") const Chain = require("../../model/chain") const ierc20abi = require('../../abi/IERC20_ABI.json') const contracts = require('../../config/contracts') class LpGenerate { tokenInstance = {} lpInstance = {} async handlePosition(routerObj) { const block = routerObj.type === 'univ2' ? 'UNIV2DEX' : 'UNIV3DEX' const hash = routerObj.type === 'univ2' ? routerObj.factory : routerObj.router + '_router' try { // 拉取当前pull状态信息 const pullState = await History.findByHashOrBlockOrDataVague(block, hash, '', 0, 200) let nowPosition = 0 // 没有状态信息的情况 if (pullState.data.length == 0) { await History.appendOrUpdate(block, hash, {"next": 0}) } else { nowPosition = pullState.data[0].dataObj.next } return nowPosition } catch (e) { logger.error(`Pull state error, router: ${routerObj.router}, factory: ${routerObj.factory}`) logger.error(e) } return 0 } async getV2PoolByPosition(routerObj, position, v2ToolBy410) { try { const info = await v2ToolBy410.methods.getPairIdInfo(routerObj.factory, position).call() const symbol0 = info['2'].replace(/[^A-Za-z0-9]+/g, '').substring(0, 10) const symbol1 = info['6'].replace(/[^A-Za-z0-9]+/g, '').substring(0, 10) const name = `${routerObj.name}_${symbol0}_${symbol1}` const sum2 = replaceAll(BigNumber.from(info['1']).add(BigNumber.from(info['5']))._hex, '0x0', '0x') return { LP: info['0'], decimals0: info['3'], decimals1: info['7'], factory: routerObj.factory, feei: routerObj.fee, id: position, name: name, r0: info['4'], r1: info['8'], router: routerObj.router, sum2: sum2, symbol0: symbol0, symbol1: symbol1, token0: info['1'], token1: info['5'] } } catch (e) { logger.info(e) } return undefined } async handleToken(pool, zero) { const token = { 'address': zero ? pool.token0 : pool.token1, 'symbol': zero ? pool.symbol0 : pool.symbol1, 'decimals': zero ? pool.decimals0 : pool.decimals1, 'name': 'xxxxxxxx' } let tokenObj = this.tokenInstance[token.address] if (!tokenObj) { tokenObj = new web3.eth.Contract(ierc20abi, token.address) this.tokenInstance[token.address] = tokenObj } token.name = await tokenObj.methods.name().call() token.name = token.name.replace(/[^A-Za-z0-9 ]+/g, '').substring(0, 37) return token } async saveToken(lp, type = 'token') { try { const token = await this.handleToken(lp, true) // token的hash不同时为lp的情况才更新 if (!this.lpInstance[token.address.toLowerCase()]) { await history.appendOrUpdate(type, token.address, token) } } catch (e) { } try { const token = await this.handleToken(lp, false) // token的hash不同时为lp的情况才更新 if (!this.lpInstance[token.address.toLowerCase()]) { await history.appendOrUpdate(type, token.address, token) } } catch (e) { } } async saveLp(lp, type = '0') { // 本地lp实例存档 this.lpInstance[lp.LP.toLowerCase()] = lp await History.appendOrUpdate(type, lp.LP, lp) } parseFactory(router, factoryAbi, factoryAddress) { if (router.factoryObj == null) { router.factoryObj = new web3.eth.Contract(factoryAbi, factoryAddress) } return router.factoryObj } async handleLp(position, pairsLength, routerObj, v2ToolBy410) { // 1. 获取lp let lp = undefined if (routerObj.type === 'univ2') { lp = await this.getV2PoolByPosition(routerObj, position, v2ToolBy410) } if (lp) { // 2. 保存Lp信息 await this.saveLp(lp, 'lp') // 3. 保存Lp的Token到Token表 await this.saveToken(lp, 'token') } if (lp) { logger.debug(`${position + 1} / ${pairsLength}, ${lp.name}-${lp.LP}-${routerObj.chain}`) } else { logger.debug(`lp get filed. ${position + 1} / ${pairsLength}, ${routerObj.name}-${routerObj.router}-${routerObj.chain}`) } } async run() { logger.debug('Pull lp start.') // 初始化410 v2工具箱 const v2ToolBy410Abi = require('../../abi/410_V2_TOOLS.json') const v2ToolBy410 = new web3.eth.Contract(v2ToolBy410Abi, contracts.V2_TOOLS_BY_410) const v2FactoryAbi = require('../../abi/UNIV2_FACTORY_ABI.json') // router const routerList = require('../../config/router-list.json') while (true) { for (const routerObj of routerList) { try { let pairsLength = 0 const factoryAddress = routerObj.factory // 获取当前pull状态 let position = await this.handlePosition(routerObj) let v2Factory = undefined // v2,v3分开处理 if (routerObj.type === 'univ2') { // 获取工厂实例 v2Factory = this.parseFactory(routerObj, v2FactoryAbi, factoryAddress) // 获取当前pairsLength pairsLength = await v2Factory.methods.allPairsLength().call() } // 如果有未获取的池子 const haveNewLp = position < pairsLength // 打印信息 if (haveNewLp) { logger.debug(`Router address: ${routerObj.router}`) if (routerObj.type === 'univ2') { logger.debug(`factory: ${factoryAddress}, ${position} / ${pairsLength}.`) } else { logger.debug(`position: ${routerObj.position}, ${position} / ${pairsLength}.`) } } // 挨个处理lp信息 for (; position < pairsLength; position++) { await this.handleLp(position, pairsLength, routerObj, v2ToolBy410) } if (haveNewLp) { if (routerObj.type === 'univ2') { await History.appendOrUpdate('UNIV2DEX', routerObj.factory, {"next": position}) } logger.debug('') logger.debug('') logger.debug('') } } catch (e) { logger.debug(e) } } await Time.delay(12000) } } } async function main() { logger.info(await Chain.getAll()) } main().catch((error) => { console.error(error); process.exitCode = 1; })