lp-lib.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. const logger = require("../../utils/logger");
  2. const debug = require('./../../utils/debug')
  3. const BaseModel = require("../../model/base-model");
  4. const V2ToolAbi = require('../../abi/UNIV2_TOOLS_ABI.json')
  5. const V3ToolAbi = require('../../abi/UNIV3_TOOLS_ABI.json')
  6. const FactoryLib = require("./factory-lib");
  7. const TokenLib = require("./token-lib");
  8. module.exports = class LpLib {
  9. static LEVEL = {
  10. NOT: 'not',
  11. DISCARD: 'discard',
  12. INIT: 'init',
  13. NORMAL: 'normal',
  14. TOP: 'top'
  15. }
  16. static VERSION = {
  17. UNIV2: 'univ2',
  18. UNIV3: 'univ3'
  19. }
  20. constructor(web3, chain) {
  21. this.web3 = web3
  22. this.chain = chain
  23. this.factoryLib = new FactoryLib(this.web3, this.chain)
  24. this.tokenLib = new TokenLib(this.web3, this.chain)
  25. this.v2LpModel = new BaseModel(this.chain.id, BaseModel.MODULES.V2_LP)
  26. this.v3LpModel = new BaseModel(this.chain.id, BaseModel.MODULES.V3_LP)
  27. // 初始化V2工具箱
  28. this.v2Tool = new this.web3.eth.Contract(V2ToolAbi, this.chain.v2ToolAddress)
  29. // 初始化V3工具箱
  30. this.v3Tool = new this.web3.eth.Contract(V3ToolAbi, this.chain.v3ToolAddress)
  31. }
  32. async saveLp(factory, lp) {
  33. let saveRst = undefined
  34. if (factory.version === 'univ2') {
  35. saveRst = await this.v2LpModel.appendOrUpdate(lp)
  36. } else if (factory.version === 'univ3') {
  37. saveRst = await this.v3LpModel.appendOrUpdate(lp)
  38. } else {
  39. throw Error(`Unknown factory version: ${factory.version}, hash is: ${factory.hash}.`)
  40. }
  41. if (!saveRst.state) throw Error(saveRst.msg)
  42. }
  43. getEffectiveLp(factory, position, lp) {
  44. // lp对象标准化
  45. lp.symbol0 = this.tokenLib.getEffectiveSymbol(lp.symbol0)
  46. lp.symbol1 = this.tokenLib.getEffectiveSymbol(lp.symbol1)
  47. lp.name = `${factory.name}_${lp.symbol0}_${lp.symbol1}`
  48. lp.router = factory.router
  49. lp.factory = factory.hash
  50. lp.fee = factory.fee
  51. lp.positionId = position
  52. lp.r0Str = String(lp.r0)
  53. lp.r1Str = String(lp.r1)
  54. lp.level = LpLib.LEVEL.INIT
  55. // lp各种地址最小化
  56. lp.hash = lp.hash.toLowerCase()
  57. lp.token0 = lp.token0.toLowerCase()
  58. lp.token1 = lp.token1.toLowerCase()
  59. // 字符化数字
  60. lp.decimals0 = parseInt(lp.decimals0)
  61. lp.decimals1 = parseInt(lp.decimals1)
  62. // 链信息
  63. lp.chainId = this.chain.id
  64. return lp
  65. }
  66. async getV2Pool(factory, position) {
  67. const info = await this.v2Tool.methods.getPairIdInfo(factory.hash, position).call()
  68. const lp = {
  69. hash: info['0'],
  70. decimals0: info['3'],
  71. decimals1: info['7'],
  72. r0: info['4'],
  73. r1: info['8'],
  74. symbol0: info['2'],
  75. symbol1: info['6'],
  76. token0: info['1'],
  77. token1: info['5']
  78. }
  79. return this.getEffectiveLp(factory, position, lp)
  80. }
  81. async getV3Pool(factory, position) {
  82. const positionManager = this.factoryLib.getPositionManager(factory.positionManager)
  83. const positionInfo = await positionManager.methods.positions(position).call()
  84. const info = await this.v3Tool.methods.getMoreInfo(positionInfo.token0, positionInfo.token1, positionInfo.fee).call()
  85. const lp = {
  86. hash: info.lp,
  87. decimals0: info.decimals0,
  88. decimals1: info.decimals1,
  89. factory: factory.hash,
  90. feei: positionInfo.fee,
  91. id: position,
  92. r0: info.r0,
  93. r1: info.r1,
  94. router: factory.router,
  95. token0: positionInfo.token0,
  96. token1: positionInfo.token1,
  97. symbol0: info.symbol0,
  98. symbol1: info.symbol1
  99. }
  100. return this.getEffectiveLp(factory, position, lp)
  101. }
  102. async getLpByPosition(factory, position) {
  103. if (factory.version === LpLib.VERSION.UNIV2) {
  104. return await this.getV2Pool(factory, position)
  105. } else if (factory.version === LpLib.VERSION.UNIV3) {
  106. return await this.getV3Pool(factory, position)
  107. } else {
  108. throw Error(`Unknown factory version: ${factory.version}, hash is: ${factory.hash}.`)
  109. }
  110. }
  111. getHashListByLpList(lpList) {
  112. const hashList = []
  113. for (const lp of lpList) {
  114. hashList.push(lp.hash)
  115. }
  116. return hashList
  117. }
  118. async putR0AndR1(lpList) {
  119. // 生成所有lp的hash
  120. const hashList = this.getHashListByLpList(lpList)
  121. // 以段为单位,更新r0、r1。每一段有SIZE个元素
  122. const SIZE = 2000
  123. for (let from = 0; from < hashList.length; from += SIZE) {
  124. logger.debug(`${from}, ${hashList.length}`)
  125. // 拉取该段所有r0,r1
  126. const lpR0R1Info = await this.v2Tool.methods.getPairSBalance(hashList.slice(from, from + SIZE)).call()
  127. const r0s = lpR0R1Info.amounts0
  128. const r1s = lpR0R1Info.amounts1
  129. // 更新到lp中
  130. for (let index = from; index < from + SIZE; index++) {
  131. lpList.r0Str = r0s[index % SIZE]
  132. lpList.r0 = r0s[index % SIZE]
  133. lpList.r1Str = r1s[index % SIZE]
  134. lpList.r1 = r1s[index % SIZE]
  135. }
  136. }
  137. }
  138. calcSwapPrice() {
  139. }
  140. getMaxValueLpMap() {
  141. }
  142. async perfectLpInfo(lpList) {
  143. // 1. 更新所有lp的r0,r1
  144. await this.putR0AndR1(lpList)
  145. // 2. 获取每种交易对的最佳兑换池子(最佳:池子价值最高)
  146. // 按相同交易对分组的对象,通过token0+token1的字符串串联方式索引
  147. this.maxValueLpMap = this.getMaxValueLpMap()
  148. // 3. 计算token0与token1的相对价格(需要decimals0,decimals1)
  149. this.calcSwapPrice(lpList)
  150. // 4. 获取池子兑基本币价值
  151. }
  152. async getLpList(version) {
  153. let requestRst = undefined
  154. if (version === LpLib.VERSION.UNIV2) {
  155. requestRst = await this.v2LpModel.findByPaginate(1, debug.isDev() ? 200 : 10000000)
  156. } else if (version === LpLib.VERSION.UNIV3) {
  157. requestRst = await this.v3LpModel.findByPaginate(1, debug.isDev() ? 200 : 10000000)
  158. } else {
  159. throw Error(`Unknown lp version: ${version}.`)
  160. }
  161. if (requestRst.state) {
  162. return requestRst.data
  163. } else {
  164. logger.error(requestRst.msg)
  165. return []
  166. }
  167. }
  168. }