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++) { lpList.r0Str = r0s[index % SIZE] lpList.r0 = r0s[index % SIZE] lpList.r1Str = r1s[index % SIZE] lpList.r1 = r1s[index % SIZE] } } } calcSwapPrice() { } getMaxValueLpMap() { } async perfectLpInfo(lpList) { // 1. 更新所有lp的r0,r1 await this.putR0AndR1(lpList) // 2. 获取每种交易对的最佳兑换池子(最佳:池子价值最高) // 按相同交易对分组的对象,通过token0+token1的字符串串联方式索引 this.maxValueLpMap = this.getMaxValueLpMap() // 3. 计算token0与token1的相对价格(需要decimals0,decimals1) this.calcSwapPrice(lpList) // 4. 获取池子兑基本币价值 } 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 [] } } }