|
|
@@ -7,90 +7,14 @@ import {replaceAll} from "hardhat/internal/util/strings";
|
|
|
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 {
|
|
|
- fromHead: boolean = false
|
|
|
- isFirst: boolean = false
|
|
|
tokenInstance: any = {}
|
|
|
maxMemoryOfByte: number = 0
|
|
|
|
|
|
- constructor (_fromHead: boolean, _isFirst: boolean) {
|
|
|
- this.fromHead = _fromHead
|
|
|
- this.isFirst = _isFirst
|
|
|
- }
|
|
|
-
|
|
|
- async getV2PoolByPosition(routerObj: any, position: number, v2ToolBy410: any) {
|
|
|
- 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')
|
|
|
-
|
|
|
- const lp = {
|
|
|
- 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'],
|
|
|
- isEthW: routerObj.type == 'ETHW'
|
|
|
- }
|
|
|
-
|
|
|
- // 更新一次position
|
|
|
- // await History.appendOrUpdate('UNIV2DEX', routerObj.factory, {"now": position + 1})
|
|
|
-
|
|
|
- return lp
|
|
|
- } catch (e) {}
|
|
|
-
|
|
|
- return undefined
|
|
|
- }
|
|
|
-
|
|
|
- async getV3Pool(routerObj: any, position: number, v3Tool: any, positionManager: any) {
|
|
|
- try {
|
|
|
- const positionInfo = await positionManager.methods.positions(position).call()
|
|
|
- const info = await v3Tool.methods.getMoreInfo(positionInfo.token0, positionInfo.token1, positionInfo.fee).call()
|
|
|
-
|
|
|
- const symbol0 = info.symbol0.replace(/[^A-Za-z0-9 ]+/g, '').substring(0, 10)
|
|
|
- const symbol1 = info.symbol1.replace(/[^A-Za-z0-9 ]+/g, '').substring(0, 10)
|
|
|
- const name = `${routerObj.router.slice(2, 4) + routerObj.router.slice(-2)}_${symbol0}_${symbol1}`
|
|
|
- const sum2 = replaceAll(BigNumber.from(positionInfo.token0).add(BigNumber.from(positionInfo.token1))._hex, '0x0', '0x')
|
|
|
-
|
|
|
- const lp = {
|
|
|
- LP: info.lp,
|
|
|
- decimals0: info.decimals0,
|
|
|
- decimals1: info.decimals1,
|
|
|
- factory: routerObj.factory,
|
|
|
- feei: positionInfo.fee,
|
|
|
- id: position,
|
|
|
- name: name,
|
|
|
- r0: info.r0,
|
|
|
- r1: info.r1,
|
|
|
- router: routerObj.router,
|
|
|
- sum2: sum2,
|
|
|
- symbol0: symbol0,
|
|
|
- symbol1: symbol1,
|
|
|
- token0: positionInfo.token0,
|
|
|
- token1: positionInfo.token1
|
|
|
- }
|
|
|
-
|
|
|
- // await History.appendOrUpdate('UNIV3DEX', routerObj.router + '_router', {"now": position + 1})
|
|
|
-
|
|
|
- return lp
|
|
|
- } catch (e) {}
|
|
|
-
|
|
|
- return undefined
|
|
|
- }
|
|
|
-
|
|
|
async handleToken(pool: any, zero: boolean) {
|
|
|
const token = {
|
|
|
'address': zero ? pool.token0 : pool.token1,
|
|
|
@@ -115,132 +39,66 @@ export class LpMaintenance {
|
|
|
try {
|
|
|
const token = await this.handleToken(lp, true)
|
|
|
|
|
|
- // const saveRst = await history.appendOrUpdate(type, token.address, token)
|
|
|
- // logger.debug(`${token.name} ${saveRst.msg}`)
|
|
|
await history.appendOrUpdate(type, token.address, token)
|
|
|
} catch (e) {}
|
|
|
|
|
|
try {
|
|
|
const token = await this.handleToken(lp, false)
|
|
|
|
|
|
- // const saveRst = await history.appendOrUpdate(type, token.address, token)
|
|
|
- // logger.debug(`${token.name} ${saveRst.msg}`)
|
|
|
await history.appendOrUpdate(type, token.address, token)
|
|
|
} catch (e) {}
|
|
|
}
|
|
|
|
|
|
async saveLp(lp: any, type='0') {
|
|
|
- // const insertRst = await History.appendOrUpdate(type, lp.LP, lp)
|
|
|
- // logger.debug(`insert lp:${insertRst.msg}, hash: ${lp.LP}.}`)
|
|
|
await History.appendOrUpdate(type, lp.LP, lp)
|
|
|
}
|
|
|
|
|
|
- async filterLp(lp: any) {
|
|
|
- // const filterSizeNormal = 1
|
|
|
- const filterSizeTop = 10
|
|
|
-
|
|
|
- // WETH
|
|
|
- if (lp.token0.toLowerCase() === '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2') {
|
|
|
- return parseInt(lp.r0) > filterSizeTop * 1e18
|
|
|
- } else if (lp.token1.toLowerCase() === '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2') {
|
|
|
- return parseInt(lp.r1) > filterSizeTop * 1e18
|
|
|
+ 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 'topLp'
|
|
|
}
|
|
|
|
|
|
- // ETH
|
|
|
- if (lp.token0.toLowerCase() === '0xaf3ccfd9b59b36628cc2f659a09d6440795b2520') {
|
|
|
- return parseInt(lp.r0) > filterSizeTop * 1e18
|
|
|
- } else if (lp.token1.toLowerCase() === '0xaf3ccfd9b59b36628cc2f659a09d6440795b2520') {
|
|
|
- return parseInt(lp.r1) > filterSizeTop * 1e18
|
|
|
- }
|
|
|
-
|
|
|
- // WETHW
|
|
|
- if (lp.token0.toLowerCase() === '0x7bf88d2c0e32de92cdaf2d43ccdc23e8edfd5990') {
|
|
|
- return parseInt(lp.r0) > filterSizeTop * 1e18
|
|
|
- } else if (lp.token1.toLowerCase() === '0x7bf88d2c0e32de92cdaf2d43ccdc23e8edfd5990') {
|
|
|
- return parseInt(lp.r1) > filterSizeTop * 1e18
|
|
|
- }
|
|
|
-
|
|
|
- return true
|
|
|
- }
|
|
|
-
|
|
|
- parseFactory(router: any, factoryAbi: any, factoryAddress: string) {
|
|
|
- if (router.factoryObj == null) {
|
|
|
- router.factoryObj = new web3.eth.Contract(factoryAbi, factoryAddress)
|
|
|
- }
|
|
|
-
|
|
|
- return router.factoryObj
|
|
|
- }
|
|
|
-
|
|
|
- parsePositionManager(router: any, positionManagerAbi: any) {
|
|
|
- if (router.positionManager == null) {
|
|
|
- router.positionManager = new web3.eth.Contract(positionManagerAbi, router.position)
|
|
|
- }
|
|
|
-
|
|
|
- return router.positionManager
|
|
|
- }
|
|
|
-
|
|
|
- async checkPosition(pm: any, position: any) {
|
|
|
- try {
|
|
|
- await pm.methods.positions(position).call()
|
|
|
-
|
|
|
- return true
|
|
|
- } catch (e) {
|
|
|
- return false
|
|
|
+ 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
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // 二分法查length
|
|
|
- async getPositionLength(pm: any) {
|
|
|
- let low = 300_000
|
|
|
- let high = 1_000_000
|
|
|
- let lastLow = low
|
|
|
- let lastHigh = high
|
|
|
-
|
|
|
- let checkNumber = low
|
|
|
-
|
|
|
- // TODO 二分法算法
|
|
|
- // while (true) {
|
|
|
- //
|
|
|
- // }
|
|
|
-
|
|
|
- return checkNumber
|
|
|
+ async handleLp(lp: any) {
|
|
|
+ // 保存Lp信息
|
|
|
+ await this.saveLp(lp, '0')
|
|
|
+ // 保存Lp的Token到Token表
|
|
|
+ await this.saveToken(lp, 'token')
|
|
|
+ // 过滤Lp
|
|
|
+ const lpType = await this.checkLpType(lp)
|
|
|
+ // 保存筛选之后的的Token到TopToken表
|
|
|
+ await this.saveToken(lp, lpType)
|
|
|
+ // 保存过滤后的Lp到TopLp
|
|
|
+ await this.saveLp(lp, lpType)
|
|
|
}
|
|
|
|
|
|
- async handleLp(position: number, pairsLength: number,
|
|
|
- routerObj: any, v2ToolBy410: any, v3Tool: any, v3PositionManager: any) {
|
|
|
- // 获取lp
|
|
|
- let lp = undefined
|
|
|
- if (routerObj.type === 'univ2') {
|
|
|
- lp = await this.getV2PoolByPosition(routerObj, position, v2ToolBy410)
|
|
|
- } else if (routerObj.type === 'univ3') {
|
|
|
- // v3是从1开始
|
|
|
- lp = await this.getV3Pool(routerObj, position + 1, v3Tool, v3PositionManager)
|
|
|
- }
|
|
|
- // if (lp) {
|
|
|
- // // 保存Lp信息
|
|
|
- // await this.saveLp(lp, '0')
|
|
|
- // // 保存Lp的Token到Token表
|
|
|
- // await this.saveToken(lp, 'token')
|
|
|
- // // 过滤Lp
|
|
|
- // if (await this.filterLp(lp)) {
|
|
|
- // // 保存筛选之后的的Token到TopToken表
|
|
|
- // await this.saveToken(lp, 'topToken')
|
|
|
- // // 保存过滤后的Lp到TopLp
|
|
|
- // await this.saveLp(lp, 'topLp')
|
|
|
- // }
|
|
|
- // }
|
|
|
-
|
|
|
+ showMemory (mainInfo: string) {
|
|
|
const memoryUsage = process.memoryUsage()
|
|
|
if (this.maxMemoryOfByte < memoryUsage.rss) {
|
|
|
this.maxMemoryOfByte = memoryUsage.rss
|
|
|
}
|
|
|
- if (lp) {
|
|
|
- logger.debug(`${position + 1} / ${pairsLength}, ${lp.name}-${lp.LP}-${routerObj.chain}`
|
|
|
- + ` ${this.format(memoryUsage.rss)}/${this.format(this.maxMemoryOfByte)}`)
|
|
|
- } else {
|
|
|
- logger.debug(`lp get filed. ${position + 1} / ${pairsLength}, ${routerObj.name}-${routerObj.router}-${routerObj.chain}`
|
|
|
- + ` ${this.format(memoryUsage.rss)}/${this.format(this.maxMemoryOfByte)}`)
|
|
|
- }
|
|
|
+ logger.debug(`${mainInfo} ${this.format(memoryUsage.rss)}/${this.format(this.maxMemoryOfByte)}`)
|
|
|
}
|
|
|
|
|
|
format (bytes: any) {
|
|
|
@@ -248,68 +106,20 @@ export class LpMaintenance {
|
|
|
}
|
|
|
|
|
|
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')
|
|
|
- // 初始化v3相关
|
|
|
- const positionManagerAbi = require('../../abi/UNIV3_POSITION_MANAGER_ABI.json')
|
|
|
- const v3ToolAbi = require('../../artifacts/contracts/V3Tool.sol/V3Tool.json').abi
|
|
|
- const v3Tool = new web3.eth.Contract(v3ToolAbi, contracts.V3_TOOLS)
|
|
|
- // router
|
|
|
- const routerList: Array<any> = require('../../config/router-list.json')
|
|
|
+ logger.debug('LP maintenance start.')
|
|
|
|
|
|
while (true) {
|
|
|
- for (const routerObj of routerList) {
|
|
|
- let pairsLength = 0
|
|
|
-
|
|
|
- const factoryAddress = routerObj.factory
|
|
|
- // 获取当前pull状态
|
|
|
- let position = routerObj.fromPosition
|
|
|
- let v2Factory = undefined
|
|
|
- let v3PositionManager = undefined
|
|
|
- // v2,v3分开处理
|
|
|
- if (routerObj.type === 'univ2') {
|
|
|
- // 获取工厂实例
|
|
|
- v2Factory = this.parseFactory(routerObj, v2FactoryAbi, factoryAddress)
|
|
|
- // 获取当前pairsLength
|
|
|
- pairsLength = await v2Factory.methods.allPairsLength().call()
|
|
|
- } else if (routerObj.type === 'univ3') {
|
|
|
- // 获取positionManager
|
|
|
- v3PositionManager = this.parsePositionManager(routerObj, positionManagerAbi)
|
|
|
- pairsLength = await this.getPositionLength(v3PositionManager)
|
|
|
- }
|
|
|
-
|
|
|
- // log该router信息
|
|
|
- logger.debug(`Router address: ${routerObj.router}`)
|
|
|
- if (routerObj.type === 'univ2') {
|
|
|
- logger.debug(`factory: ${factoryAddress}, ${position + 1} / ${pairsLength}.`)
|
|
|
- } else {
|
|
|
- logger.debug(`position: ${routerObj.position}, ${position + 1} / ${pairsLength}.`)
|
|
|
- }
|
|
|
-
|
|
|
- // 挨个处理lp信息
|
|
|
- for (; position < pairsLength; position++) {
|
|
|
- await this.handleLp(position, pairsLength, routerObj, v2ToolBy410, v3Tool, v3PositionManager)
|
|
|
- }
|
|
|
-
|
|
|
- logger.debug('')
|
|
|
- logger.debug('')
|
|
|
- logger.debug('')
|
|
|
- }
|
|
|
+ const lpList: any = []
|
|
|
|
|
|
- if (this.fromHead && this.isFirst) {
|
|
|
- this.isFirst = false
|
|
|
- this.fromHead = false
|
|
|
+ for (const lp of lpList) {
|
|
|
+ await this.handleLp(lp)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
async function main() {
|
|
|
- await new LpMaintenance(true, true).run()
|
|
|
+ await new LpMaintenance().run()
|
|
|
}
|
|
|
|
|
|
main().catch((error) => {
|