|
|
@@ -2,6 +2,7 @@ import { web3 } from "hardhat";
|
|
|
import History from "../interface/history";
|
|
|
import contracts from "../../config/contracts";
|
|
|
import logger from "../../utils/logger";
|
|
|
+import {BigNumber} from "ethers";
|
|
|
|
|
|
// 初始化410 v2工具箱
|
|
|
const v2ToolBy410Abi = require('../../abi/410_V2_TOOLS.json')
|
|
|
@@ -19,53 +20,84 @@ export class LpMaintenance {
|
|
|
maxMemoryOfByte: number = 0
|
|
|
maxMemoryChanged: boolean = true
|
|
|
|
|
|
+ // 计算价格要用
|
|
|
+ allMaxValueLpGroupBySum: any = {}
|
|
|
+ baseTokenConvertEthValueMap: any = {}
|
|
|
+
|
|
|
async saveLp(lp: any, type='0') {
|
|
|
await History.appendOrUpdate(type, lp.LP, lp)
|
|
|
}
|
|
|
|
|
|
+ getLpEthValue(lp: any) {
|
|
|
+ const token0 = lp.token0.toLowerCase()
|
|
|
+ const token1 = lp.token1.toLowerCase()
|
|
|
+
|
|
|
+ // 1.两token之一能直接与ethw或wethw做直接池子的
|
|
|
+ // 2.两token之一能直接与baseToken做池子的
|
|
|
+ // 这两种情况直接带入baseTokenConvertEthValueMap计算
|
|
|
+ for (const baseTokenAddress of baseTokenAddressList) {
|
|
|
+ const token0AndBaseTokenLp = this.allMaxValueLpGroupBySum[this.getHexSum(token0, baseTokenAddress.toLowerCase())]
|
|
|
+ if (token0AndBaseTokenLp) {
|
|
|
+ if (ethTokenAddressList.indexOf(baseTokenAddress.toLowerCase()) == -1) {
|
|
|
+ logger.debug(`${lp}`)
|
|
|
+ logger.debug(`0, ${token0AndBaseTokenLp.zeroToOnePrice}, ${this.baseTokenConvertEthValueMap[baseTokenAddress]}`)
|
|
|
+ }
|
|
|
+
|
|
|
+ return {
|
|
|
+ '0': token0AndBaseTokenLp.zeroToOnePrice * this.baseTokenConvertEthValueMap[baseTokenAddress],
|
|
|
+ '1': 1 / token0AndBaseTokenLp.zeroToOnePrice * this.baseTokenConvertEthValueMap[baseTokenAddress]
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ const token1AndBaseTokenLp = this.allMaxValueLpGroupBySum[this.getHexSum(token1, baseTokenAddress.toLowerCase())]
|
|
|
+ if (token1AndBaseTokenLp) {
|
|
|
+ if (ethTokenAddressList.indexOf(baseTokenAddress.toLowerCase()) == -1) {
|
|
|
+ logger.debug(`${lp}`)
|
|
|
+ logger.debug(`1, ${token0AndBaseTokenLp.zeroToOnePrice}, ${this.baseTokenConvertEthValueMap[baseTokenAddress]}`)
|
|
|
+ }
|
|
|
+
|
|
|
+ return {
|
|
|
+ '0': 1 / token1AndBaseTokenLp.oneToZeroPrice * this.baseTokenConvertEthValueMap[baseTokenAddress],
|
|
|
+ '1': token1AndBaseTokenLp.oneToZeroPrice * this.baseTokenConvertEthValueMap[baseTokenAddress]
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3.两token都不能与baseToken做池子的
|
|
|
+ // 这种情况则视为lp类型池子
|
|
|
+ return {'0': 0, '1': 0}
|
|
|
+ }
|
|
|
+
|
|
|
async checkLpType(lp: any) {
|
|
|
// lp过滤后类型表
|
|
|
const filterTypeList = [
|
|
|
- { type: 'topLp', limit: 10 },
|
|
|
- { type: 'normalLp', limit: 1 },
|
|
|
+ { type: 'topLp', limit: 1 },
|
|
|
+ { type: 'normalLp', limit: 0.1 },
|
|
|
{ type: 'lp', limit: 0 },
|
|
|
]
|
|
|
// token折合成eth的价格
|
|
|
- let tokenConvertEthPrice = 1
|
|
|
-
|
|
|
- // token0和token1都不是baseToken的。视为lp
|
|
|
- if (baseTokenAddressList.indexOf(lp.token0.toLowerCase()) == -1
|
|
|
- && baseTokenAddressList.indexOf(lp.token1.toLowerCase()) == -1) {
|
|
|
- return 'lp'
|
|
|
+ let tokenConvertEthPrice: any = {
|
|
|
+ '0': 1,
|
|
|
+ '1': 1
|
|
|
}
|
|
|
|
|
|
- // token0和token1都不是eth的,视为usdx
|
|
|
+ // token0和token1都不是eth的,分三种情况探讨
|
|
|
if (ethTokenAddressList.indexOf(lp.token0.toLowerCase()) == -1
|
|
|
&& ethTokenAddressList.indexOf(lp.token1.toLowerCase()) == -1) {
|
|
|
- tokenConvertEthPrice = 0.142
|
|
|
+ tokenConvertEthPrice = this.getLpEthValue(lp)
|
|
|
}
|
|
|
|
|
|
// 从高到低遍历过滤条件
|
|
|
+ const decimals0 = parseInt(lp.decimals0)
|
|
|
+ const decimals1 = parseInt(lp.decimals0)
|
|
|
+ const realAmount0 = parseInt(lp.r0) * tokenConvertEthPrice['0'] / Math.pow(10, -decimals0)
|
|
|
+ const realAmount1 = parseInt(lp.r1) * tokenConvertEthPrice['1'] / Math.pow(10, -decimals1)
|
|
|
+
|
|
|
for (const filterType of filterTypeList) {
|
|
|
- // 从头到尾搜索baseToken
|
|
|
- for (const baseTokenAddress of baseTokenAddressList) {
|
|
|
- const baseToken = baseTokenMap[baseTokenAddress]
|
|
|
- const amountLimit = filterType.limit * Math.pow(10, baseToken.decimals)
|
|
|
-
|
|
|
- // 如果是token0是baseToken,则将token1根据价格折合成eth数量计算
|
|
|
- if (lp.token0.toLowerCase() === baseTokenAddress) {
|
|
|
- const convertedEthAmount = parseInt(lp.r0) * tokenConvertEthPrice
|
|
|
- if (convertedEthAmount >= amountLimit) {
|
|
|
- return filterType.type
|
|
|
- }
|
|
|
- }
|
|
|
- // 如果是token1是baseToken,则将token1根据价格折合成eth数量计算
|
|
|
- if (lp.token1.toLowerCase() === baseTokenAddress) {
|
|
|
- const convertedEthAmount = parseInt(lp.r1) * tokenConvertEthPrice
|
|
|
- if (convertedEthAmount >= amountLimit) {
|
|
|
- return filterType.type
|
|
|
- }
|
|
|
- }
|
|
|
+ const amountLimit = filterType.limit
|
|
|
+
|
|
|
+ if (realAmount0 >= amountLimit || realAmount1 >= amountLimit) {
|
|
|
+ return filterType.type
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -123,6 +155,53 @@ export class LpMaintenance {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ putAllLpGroupBySum(lpList: any) {
|
|
|
+ this.allMaxValueLpGroupBySum = {}
|
|
|
+
|
|
|
+ for (const lpDbObj of lpList) {
|
|
|
+ const lp = lpDbObj.dataObj
|
|
|
+
|
|
|
+ const notExist = !this.allMaxValueLpGroupBySum[lp.sum2]
|
|
|
+ const moreValueThanNowMax = !notExist && (parseInt(lp.r0) > this.allMaxValueLpGroupBySum[lp.sum2].r0)
|
|
|
+ if (notExist || moreValueThanNowMax) {
|
|
|
+ // 计算0换1的价格和1换0的价格
|
|
|
+ lp.zeroToOnePrice = parseInt(lp.r1) / parseInt(lp.r0) // 一个token0 = zeroToOnePrice个token1
|
|
|
+ lp.oneToZeroPrice = parseInt(lp.r0) / parseInt(lp.r1) // 一个token1 = oneForZeroPrice个token0
|
|
|
+
|
|
|
+ this.allMaxValueLpGroupBySum[lp.sum2] = lp
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ calcBaseTokenCovertEthValue() {
|
|
|
+ for (const baseTokenAddress of baseTokenAddressList) {
|
|
|
+ const isEthToken = ethTokenAddressList.indexOf(baseTokenAddress) != -1
|
|
|
+ // eth兑换eth价格当然是1:1啦
|
|
|
+ if (isEthToken) {
|
|
|
+ this.baseTokenConvertEthValueMap[baseTokenAddress] = 1
|
|
|
+ } else {
|
|
|
+ // 在ETH token中查找适合兑换的
|
|
|
+ for (const ethTokenAddress of ethTokenAddressList) {
|
|
|
+ const maxValueLp = this.allMaxValueLpGroupBySum[this.getHexSum(baseTokenAddress, ethTokenAddress)]
|
|
|
+ if (!maxValueLp) continue
|
|
|
+
|
|
|
+ const token0 = maxValueLp.token0.toLowerCase()
|
|
|
+ const token1 = maxValueLp.token1.toLowerCase()
|
|
|
+
|
|
|
+ if (baseTokenAddress.toLowerCase() == token0) {
|
|
|
+ this.baseTokenConvertEthValueMap[baseTokenAddress] = maxValueLp.zeroToOnePrice
|
|
|
+ } else if (baseTokenAddress.toLowerCase() == token1) {
|
|
|
+ this.baseTokenConvertEthValueMap[baseTokenAddress] = maxValueLp.oneToZeroPrice
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ getHexSum(hex0: string, hex1: string) {
|
|
|
+ return BigNumber.from(hex0).add(BigNumber.from(hex1))._hex
|
|
|
+ }
|
|
|
+
|
|
|
async run() {
|
|
|
logger.debug('LP maintenance start.')
|
|
|
while (true) {
|
|
|
@@ -141,6 +220,8 @@ export class LpMaintenance {
|
|
|
|
|
|
const allTypeLpList: any = topLpList.concat(lpList).concat(normalLpList)
|
|
|
const lpAddressList: any = this.generateAddressListByLpList(allTypeLpList)
|
|
|
+ // lp按sum分类
|
|
|
+ this.putAllLpGroupBySum(allTypeLpList)
|
|
|
// logger.debug(`${lpAddressList.length}`)
|
|
|
|
|
|
// 集中拉取r0,r1并更新本地的
|
|
|
@@ -154,6 +235,8 @@ export class LpMaintenance {
|
|
|
this.updateLocalLpListR0R1(allTypeLpList.slice(from, from + size), r0s, r1s)
|
|
|
}
|
|
|
|
|
|
+ this.calcBaseTokenCovertEthValue()
|
|
|
+
|
|
|
// 将lp类型有变动的全部更新
|
|
|
for (const lpDbObj of allTypeLpList) {
|
|
|
await this.handleLp(lpDbObj.dataObj, lpDbObj.block)
|