const logger = require("../../utils/logger"); const debug = require('./../../utils/debug') const BaseModel = require("../../model/base-model"); const V2ToolAbi = require('../../abi/UNIV2_TOOLS_ABI.json') const V3ToolAbi = require('../../abi/UNIV3_TOOLS_ABI.json') const FactoryLib = require("./factory-lib"); const TokenLib = require("./token-lib"); module.exports = class LpLib { static LEVEL = { NOT: 'not', DISCARD: 'discard', INIT: 'init', NORMAL: 'normal', TOP: 'top' } static VERSION = { UNIV2: 'univ2', UNIV3: 'univ3' } constructor(web3, chain) { this.web3 = web3 this.chain = chain this.factoryLib = new FactoryLib(this.web3, this.chain) this.tokenLib = new TokenLib(this.web3, this.chain) this.v2LpModel = new BaseModel(this.chain.id, BaseModel.MODULES.V2_LP) this.v3LpModel = new BaseModel(this.chain.id, BaseModel.MODULES.V3_LP) // 初始化V2工具箱 this.v2Tool = new this.web3.eth.Contract(V2ToolAbi, this.chain.v2ToolAddress) // 初始化V3工具箱 this.v3Tool = new this.web3.eth.Contract(V3ToolAbi, this.chain.v3ToolAddress) } async saveLp(factory, lp) { let saveRst = undefined if (factory.version === 'univ2') { saveRst = await this.v2LpModel.appendOrUpdate(lp) } else if (factory.version === 'univ3') { saveRst = await this.v3LpModel.appendOrUpdate(lp) } else { throw Error(`Unknown factory version: ${factory.version}, hash is: ${factory.hash}.`) } if (!saveRst.state) throw Error(saveRst.msg) } getEffectiveLp(factory, position, lp) { // lp对象标准化 lp.symbol0 = this.tokenLib.getEffectiveSymbol(lp.symbol0) lp.symbol1 = this.tokenLib.getEffectiveSymbol(lp.symbol1) lp.name = `${factory.name}_${lp.symbol0}_${lp.symbol1}` lp.router = factory.router lp.factory = factory.hash lp.fee = factory.fee lp.positionId = position lp.r0Str = String(lp.r0) lp.r1Str = String(lp.r1) lp.level = LpLib.LEVEL.INIT // lp各种地址最小化 lp.hash = lp.hash.toLowerCase() lp.token0 = lp.token0.toLowerCase() lp.token1 = lp.token1.toLowerCase() // 字符化数字 lp.decimals0 = parseInt(lp.decimals0) lp.decimals1 = parseInt(lp.decimals1) // 链信息 lp.chainId = this.chain.id return lp } async getV2Pool(factory, position) { const info = await this.v2Tool.methods.getPairIdInfo(factory.hash, position).call() const lp = { hash: info['0'], decimals0: info['3'], decimals1: info['7'], r0: info['4'], r1: info['8'], symbol0: info['2'], symbol1: info['6'], token0: info['1'], token1: info['5'] } return this.getEffectiveLp(factory, position, lp) } async getV3Pool(factory, position) { const positionManager = this.factoryLib.getPositionManager(factory.positionManager) const positionInfo = await positionManager.methods.positions(position).call() const info = await this.v3Tool.methods.getMoreInfo(positionInfo.token0, positionInfo.token1, positionInfo.fee).call() const lp = { hash: info.lp, decimals0: info.decimals0, decimals1: info.decimals1, factory: factory.hash, feei: positionInfo.fee, id: position, r0: info.r0, r1: info.r1, router: factory.router, token0: positionInfo.token0, token1: positionInfo.token1, symbol0: info.symbol0, symbol1: info.symbol1 } return this.getEffectiveLp(factory, position, lp) } async getLpByPosition(factory, position) { if (factory.version === LpLib.VERSION.UNIV2) { return await this.getV2Pool(factory, position) } else if (factory.version === LpLib.VERSION.UNIV3) { return await this.getV3Pool(factory, position) } else { throw Error(`Unknown factory version: ${factory.version}, hash is: ${factory.hash}.`) } } getHashListByLpList(lpList) { const hashList = [] for (const lp of lpList) { hashList.push(lp.hash) } return hashList } async putR0AndR1(lpList) { // 生成所有lp的hash const hashList = this.getHashListByLpList(lpList) // 以段为单位,更新r0、r1。每一段有SIZE个元素 const SIZE = 2000 for (let from = 0; from < hashList.length; from += SIZE) { logger.debug(`${from}, ${hashList.length}`) // 拉取该段所有r0,r1 const lpR0R1Info = await this.v2Tool.methods.getPairSBalance(hashList.slice(from, from + SIZE)).call() const r0s = lpR0R1Info.amounts0 const r1s = lpR0R1Info.amounts1 // 更新到lp中 for (let index = from; index < from + SIZE && index < hashList.length; index++) { const lp = lpList[index] const relativeIndex = index % SIZE lp.r0Str = r0s[relativeIndex] lp.r0 = parseInt(lp.r0Str) lp.r1Str = r1s[relativeIndex] lp.r1 = parseInt(lp.r1Str) } } } calcSwapPrice(lpList) { for (const lp of lpList) { const r0RealAmount = parseInt(lp.r0) / Math.pow(10, parseInt(lp.decimals0)) const r1RealAmount = parseInt(lp.r1) / Math.pow(10, parseInt(lp.decimals1)) // 计算0换1的价格和1换0的价格 lp.in1Token0OutToken1 = r1RealAmount / r0RealAmount // 一个token0 = in1Token0OutToken1个token1 lp.in1Token1OutToken0 = r0RealAmount / r1RealAmount // 一个token1 = in1Token1OutToken0个token0 } } calcLpValue(lpList) { } getMaxValueLpMap(lpList) { const maxValueLpMap = {} for (const lp of lpList) { const key = lp.token0 + lp.token1 const isExists = !!maxValueLpMap[key] const isMoreThanNowMax = isExists && maxValueLpMap[key].r0 < lp.r0 if (!isExists) maxValueLpMap[key] = lp if (isMoreThanNowMax) maxValueLpMap[key] = lp } return maxValueLpMap } async getLpList(version) { let requestRst = undefined if (version === LpLib.VERSION.UNIV2) { requestRst = await this.v2LpModel.findByPaginate(1, debug.isDev() ? 200 : 10000000) } else if (version === LpLib.VERSION.UNIV3) { requestRst = await this.v3LpModel.findByPaginate(1, debug.isDev() ? 200 : 10000000) } else { throw Error(`Unknown lp version: ${version}.`) } if (requestRst.state) { return requestRst.data } else { logger.error(requestRst.msg) return [] } } }