diff --git a/src/app.module.ts b/src/app.module.ts index 5415b4a..47f8bd3 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -37,9 +37,12 @@ import { BlockAddressPointOfLp } from "./entities/blockAddressPointOfLp.entity"; import { BlockAddressPointOfLpRepository } from "./repositories/blockAddressPointOfLp.repository"; import { Cache } from "./entities/cache.entity"; import { CacheRepository } from "./repositories/cache.repository"; +import { BalanceOfLp } from "./entities/balanceOfLp.entity"; +import { BalanceOfLpRepository } from "./repositories/balanceOfLp.repository"; import { NovaBalanceService } from "./nova/nova.balance.service"; import { CacheController } from "./cache/cache.controller"; import { CacheService } from "./cache/cache.service"; +import { AquaService } from "./nova/aqua.service"; @Module({ imports: [ @@ -60,6 +63,7 @@ import { CacheService } from "./cache/cache.service"; PointsOfLp, BlockAddressPointOfLp, Cache, + BalanceOfLp, ]), MetricsModule, UnitOfWorkModule, @@ -100,8 +104,10 @@ import { CacheService } from "./cache/cache.service"; ProjectRepository, PointsOfLpRepository, BlockAddressPointOfLpRepository, + BalanceOfLpRepository, CacheRepository, CacheService, + AquaService, ], }) export class AppModule {} diff --git a/src/common/service/projectGraph.service.ts b/src/common/service/projectGraph.service.ts index ae8064c..bbc5551 100644 --- a/src/common/service/projectGraph.service.ts +++ b/src/common/service/projectGraph.service.ts @@ -3,9 +3,9 @@ import { GraphPoint, GraphQueryService, GraphTotalPoint, -} from "src/common/service/graphQuery.service"; +} from "./graphQuery.service"; import { BigNumber } from "bignumber.js"; -import { WithdrawService } from "src/common/service/withdraw.service"; +import { WithdrawService } from "./withdraw.service"; import transferFaildData from "../transferFaild.json"; export interface LocalPointsItem { diff --git a/src/common/service/withdraw.service.ts b/src/common/service/withdraw.service.ts index 8315395..d99659b 100644 --- a/src/common/service/withdraw.service.ts +++ b/src/common/service/withdraw.service.ts @@ -1,8 +1,5 @@ import { Injectable, Logger, OnModuleInit } from "@nestjs/common"; -import { - GraphQueryService, - GraphWithdrawPoint, -} from "src/common/service/graphQuery.service"; +import { GraphQueryService, GraphWithdrawPoint } from "./graphQuery.service"; export interface WithdrawPoint { project: string; @@ -56,6 +53,11 @@ const timeToPeriod = [ end: 1714233600, // 2024-04-28 00:00:00 period: 7 * 24 * 3600, }, + { + start: 1714147200, // 2024-04-28 00:00:00 + end: 2029766400, // 2034-04-28 00:00:00 + period: 7 * 24 * 3600, + }, ]; @Injectable() diff --git a/src/common/transferFaild.json.ts b/src/common/transferFaild.json.ts index 1a978b7..37a5d01 100644 --- a/src/common/transferFaild.json.ts +++ b/src/common/transferFaild.json.ts @@ -1,5 +1,6 @@ // address, tokenAddress, balance, decimal const transferFaildData = [ + // puffer [ "0x590f4590487Bd83D7A456b5DD2863810A076D1eC", "0x1B49eCf1A8323Db4abf48b2F5EFaA33F7DdAB3FC", @@ -7,21 +8,28 @@ const transferFaildData = [ "18", ], [ - "0xF74BAC410bcF3c55af7A9A0CAef8F9c83087a3A4", - "0xdA7Fa837112511F6E353091D7e388A4c45Ce7D6C", - "1.85", + "0x04c82fFd5dbA2ac0e00dD1F9Be955bd025Dec048", + "0x1B49eCf1A8323Db4abf48b2F5EFaA33F7DdAB3FC", + "0.9992", "18", ], [ - "0xB84F419FD6DC9C30cCAA6ecbF5d194Af065A33ff", - "0x7b1fcd81F8b91C5eF3743c4d56bf7C1E52c93360", - "1.0499", + "0x63c43a9879AAac04127CB84105a5f2a3F9Bbba17", + "0x1B49eCf1A8323Db4abf48b2F5EFaA33F7DdAB3FC", + "0.489", "18", ], [ - "0x04c82fFd5dbA2ac0e00dD1F9Be955bd025Dec048", + "0xE26E90e8F6f1170fda099B771e483cD30d5ba2Af", "0x1B49eCf1A8323Db4abf48b2F5EFaA33F7DdAB3FC", - "0.9992", + "0.489", + "18", + ], + // magpie + [ + "0xB84F419FD6DC9C30cCAA6ecbF5d194Af065A33ff", + "0x7b1fcd81F8b91C5eF3743c4d56bf7C1E52c93360", + "1.0499", "18", ], [ @@ -31,15 +39,47 @@ const transferFaildData = [ "18", ], [ - "0x63c43a9879AAac04127CB84105a5f2a3F9Bbba17", - "0x1B49eCf1A8323Db4abf48b2F5EFaA33F7DdAB3FC", - "0.489", + "0x90fe3e64530B81D5613698cBAA5d99E8AebaDc69", + "0x7F62B7a0A9848D5e261960Ff4B4009206aD00bd5", + "19.9966", "18", ], [ - "0xE26E90e8F6f1170fda099B771e483cD30d5ba2Af", - "0x1B49eCf1A8323Db4abf48b2F5EFaA33F7DdAB3FC", - "0.489", + "0xB84F419FD6DC9C30cCAA6ecbF5d194Af065A33ff", + "0xBB68f4548A1c26B6611cbB8087c25A616eDd8569", + "0.572", + "18", + ], + // rseth + [ + "0xbd2ca315098e13e91f9a91a4744052d62c8e9092", + "0x4A2da287deB06163fB4D77c52901683d69bD06f4", + "0.25", + "18", + ], + [ + "0x9f90230b05a8f3802923038eb99538000fc5a1cc", + "0x4A2da287deB06163fB4D77c52901683d69bD06f4", + "0.25055", + "18", + ], + [ + "0x2c443310faa7d98c95d3d44e7e43965ef74e184d", + "0x4A2da287deB06163fB4D77c52901683d69bD06f4", + "0.25", + "18", + ], + [ + "0x137eb1280e77ea4bec921644eb575e87356a474e", + "0x4A2da287deB06163fB4D77c52901683d69bD06f4", + "0.25065", + "18", + ], + // renzo + [ + "0xF74BAC410bcF3c55af7A9A0CAef8F9c83087a3A4", + "0xdA7Fa837112511F6E353091D7e388A4c45Ce7D6C", + "1.85", "18", ], [ @@ -66,12 +106,6 @@ const transferFaildData = [ "0.2375", "18", ], - [ - "0xbd2ca315098e13e91f9a91a4744052d62c8e9092", - "0x4A2da287deB06163fB4D77c52901683d69bD06f4", - "0.25", - "18", - ], [ "0x75411b249de43f61f138eedf775f2f5df1509ba1", "0x3FDB1939daB8e2d4F7a04212F142469Cd52d6402", @@ -96,12 +130,6 @@ const transferFaildData = [ "0.2463", "18", ], - [ - "0x9f90230b05a8f3802923038eb99538000fc5a1cc", - "0x4A2da287deB06163fB4D77c52901683d69bD06f4", - "0.25055", - "18", - ], [ "0x6b16602eb27141bd32b8b26402ea2e580637ae48", "0x3DabBd8A31a411E85f628278d6601fCeD82f6844", diff --git a/src/entities/balanceOfLp.entity.ts b/src/entities/balanceOfLp.entity.ts new file mode 100644 index 0000000..aac02fd --- /dev/null +++ b/src/entities/balanceOfLp.entity.ts @@ -0,0 +1,23 @@ +import { Entity, Column, PrimaryColumn, Index } from "typeorm"; +import { BaseEntity } from "./base.entity"; +import { bigIntNumberTransformer } from "../transformers/bigIntNumber.transformer"; +import { hexTransformer } from "../transformers/hex.transformer"; + +@Entity({ name: "balancesOfLp" }) +@Index(["blockNumber", "balance"]) +export class BalanceOfLp extends BaseEntity { + @PrimaryColumn({ type: "bytea", transformer: hexTransformer }) + public readonly address: string; + + @PrimaryColumn({ type: "bytea", transformer: hexTransformer }) + public readonly tokenAddress: string; + + @PrimaryColumn({ type: "bytea", transformer: hexTransformer }) + public readonly pairAddress: string; + + @PrimaryColumn({ type: "bigint", transformer: bigIntNumberTransformer }) + public readonly blockNumber: number; + + @Column({ type: "varchar", length: 50 }) + public readonly balance: string; +} diff --git a/src/magpie/magpie.service.ts b/src/magpie/magpie.service.ts index bf93525..5f49f14 100644 --- a/src/magpie/magpie.service.ts +++ b/src/magpie/magpie.service.ts @@ -1,5 +1,7 @@ import { Injectable, Logger } from "@nestjs/common"; import { cloneDeep } from "lodash"; +import { GraphQueryService } from "../common/service/graphQuery.service"; +import { LocalPointsItem } from "../common/service/projectGraph.service"; import { LocalPointData, ProjectGraphService, @@ -40,6 +42,7 @@ export interface MagpieData { export class MagpieService { private readonly projectName: string = "magpie"; private readonly logger: Logger; + public tokenAddress: string[]; private magpieData: MagpieData = { localTotalPoints: 0n, @@ -49,6 +52,7 @@ export class MagpieService { }; public constructor( + private readonly graphQueryService: GraphQueryService, private readonly projectGraphService: ProjectGraphService, private readonly magpieGraphQueryService: MagpieGraphQueryService, ) { @@ -70,13 +74,62 @@ export class MagpieService { // load points data public async loadPointsData() { + // get tokens from graph + const tokens = this.graphQueryService.getAllTokenAddresses( + this.projectName, + ); + if (tokens.length <= 0) { + this.logger.log(`Graph don't have ${this.projectName} tokens`); + return; + } + this.tokenAddress = tokens; + const realTotalPointsData = await this.getRealPointsData(); const localPointsData = await this.getLocalPointsData(); const localPoints = localPointsData.localPoints; const localTotalPoints = localPointsData.localTotalPoints; - let data: MagpiePointItemWithBalance[] = []; + // start added transferFaildPoint + const transferFaildPoints = this.projectGraphService.getTransferFaildPoints( + this.tokenAddress, + ); + const localPointsMap = new Map(); + const totalPointsPerTokenMap = new Map(); + const now = (new Date().getTime() / 1000) | 0; for (const item of localPoints) { + const key = `${item.address}_${item.token}`; + totalPointsPerTokenMap.set(item.token, item.totalPointsPerToken); + localPointsMap.set(key, item); + } + // loop transferFaildData, and added transferFaildPoint to localPoints + for (const item of transferFaildPoints) { + const key = `${item.address}_${item.tokenAddress}`; + const transferFaildTotalPoint = + this.projectGraphService.getTransferFaildTotalPoint(item.tokenAddress); + if (!localPointsMap.has(key)) { + const tmpTotalPointsPerToken = + totalPointsPerTokenMap.get(item.tokenAddress) ?? BigInt(0); + localPointsMap.set(key, { + address: item.address, + points: item.points, + withdrawPoints: BigInt(0), + withdrawTotalPointsPerToken: BigInt(0), + totalPointsPerToken: tmpTotalPointsPerToken + transferFaildTotalPoint, + balance: BigInt(0), + token: item.tokenAddress, + updatedAt: now, + }); + } else { + const localPoint = localPointsMap.get(key); + localPoint.totalPointsPerToken = + localPoint.totalPointsPerToken + transferFaildTotalPoint; + localPoint.points = localPoint.points + item.points; + } + } + // end added transferFaildPoint + + let data: MagpiePointItemWithBalance[] = []; + for (const [, item] of localPointsMap) { const realEigenpiePoints = (BigInt(item.points) * BigInt(realTotalPointsData.eigenpiePoints)) / BigInt(localTotalPoints); diff --git a/src/nova/aqua.service.ts b/src/nova/aqua.service.ts new file mode 100644 index 0000000..48d84e1 --- /dev/null +++ b/src/nova/aqua.service.ts @@ -0,0 +1,45 @@ +import { Injectable, Logger } from "@nestjs/common"; +import { GraphQueryService } from "src/common/service/graphQuery.service"; +import { NovaService, PointData } from "src/nova/nova.service"; + +@Injectable() +export class AquaService { + private readonly logger: Logger; + private readonly projectName: string = "aqua"; + + public constructor( + private graphQueryService: GraphQueryService, + private novaService: NovaService, + ) { + this.logger = new Logger(NovaService.name); + } + + public async getPoints( + tokenAddress: string, + addresses: string[], + ): Promise { + const finalPoints = []; + const finalTotalPoints = BigInt(0); + const projects = this.graphQueryService.getAllProjectIds(this.projectName); + const project = `${this.projectName}-${tokenAddress}`; + if (!projects.includes(project)) { + this.logger.error(`Notfound GraphQL data, project is : ${project} .`); + return { finalPoints, finalTotalPoints }; + } + + const [points, totalPoints] = + await this.graphQueryService.queryPointsRedistributedByAddress( + addresses, + project, + ); + + if (Array.isArray(points) && totalPoints) { + return this.novaService.getPointData(points, totalPoints); + } else { + // Exception in fetching GraphQL data. + throw new Error( + `Exception in fetching GraphQL data, project is : ${project}.`, + ); + } + } +} diff --git a/src/nova/nova.balance.service.ts b/src/nova/nova.balance.service.ts index 77b1120..dad1943 100644 --- a/src/nova/nova.balance.service.ts +++ b/src/nova/nova.balance.service.ts @@ -3,6 +3,7 @@ import { ProjectRepository } from "src/repositories/project.repository"; import { PointsOfLpRepository } from "src/repositories/pointsOfLp.repository"; import { PointsOfLp } from "src/entities/pointsOfLp.entity"; import { BlockAddressPointOfLpRepository } from "src/repositories/blockAddressPointOfLp.repository"; +import { BalanceOfLpRepository } from "src/repositories/balanceOfLp.repository"; interface ProjectPoints { name: string; @@ -23,6 +24,7 @@ export class NovaBalanceService { private readonly projectRepository: ProjectRepository, private readonly pointsOfLpRepository: PointsOfLpRepository, private readonly blockAddressPointOfLpRepository: BlockAddressPointOfLpRepository, + private readonly balanceOfLp: BalanceOfLpRepository, ) { this.logger = new Logger(NovaBalanceService.name); } @@ -174,4 +176,33 @@ export class NovaBalanceService { yesterdayEndStr, ); } + + /** + * Get the balance of the address in the pair by blockNumber + */ + public async getBalanceByBlockNumber( + addresses: string[], + tokenAddress: string, + pairAddress: string, + blockNumber: number = 0, + ): Promise { + // if blockNumber is 0, get the latest balance + let data; + if (blockNumber == 0) { + data = await this.balanceOfLp.getLastList( + addresses, + tokenAddress, + pairAddress, + ); + } else { + data = await this.balanceOfLp.getListByBlockNumber( + addresses, + tokenAddress, + pairAddress, + blockNumber, + ); + } + + return data ? BigInt(data.balance) : BigInt(0); + } } diff --git a/src/nova/nova.service.ts b/src/nova/nova.service.ts index 04e29dd..1d84d70 100644 --- a/src/nova/nova.service.ts +++ b/src/nova/nova.service.ts @@ -202,7 +202,7 @@ export class NovaService { } } - private getPointData( + public getPointData( points: GraphPoint[], totalPoints: GraphTotalPoint, ): PointData { diff --git a/src/puffer/points.controller.spec.ts b/src/puffer/points.controller.spec.ts deleted file mode 100644 index 1a7d161..0000000 --- a/src/puffer/points.controller.spec.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { Test, TestingModule } from "@nestjs/testing"; -import { PointsController } from "./points.controller"; -import { AppModule } from "../app.module"; -import { mock } from "jest-mock-extended"; - -import { RenzoService } from "../renzo/renzo.service"; -import { ConfigService } from "@nestjs/config"; -import { PuffPointsService } from "./puffPoints.service"; -import { PointsRepository } from "../repositories/points.repository"; -describe("PointsController", () => { - let pointsController: PointsController; - let puffPointsMock: PuffPointsService; - let renzoServiceMock: RenzoService; - let configServiceMock: ConfigService; - let pointsRepositoryMock: PointsRepository; - beforeEach(async () => { - puffPointsMock = mock(); - renzoServiceMock = mock(); - configServiceMock = mock(); - pointsRepositoryMock = mock(); - - const point: TestingModule = await Test.createTestingModule({ - imports: [AppModule], - controllers: [PointsController], - providers: [ - { - provide: PuffPointsService, - useValue: puffPointsMock, - }, - { - provide: RenzoService, - - useValue: renzoServiceMock, - }, - { - provide: ConfigService, - useValue: configServiceMock, - }, - { - provide: PointsRepository, - useValue: pointsRepositoryMock, - }, - ], - }).compile(); - pointsController = point.get(PointsController); - }); -}); diff --git a/src/puffer/points.controller.ts b/src/puffer/points.controller.ts index 8bada78..d84e594 100644 --- a/src/puffer/points.controller.ts +++ b/src/puffer/points.controller.ts @@ -40,6 +40,7 @@ import { } from "./points.dto"; import { TokensDto } from "./tokens.dto"; import { NovaService } from "src/nova/nova.service"; +import { NovaBalanceService } from "../nova/nova.balance.service"; const options = { // how long to live in ms @@ -66,6 +67,7 @@ export class PointsController { private readonly graphQueryService: GraphQueryService, private configService: ConfigService, private readonly novaService: NovaService, + private readonly novaBalanceService: NovaBalanceService, ) { this.puffPointsTokenAddress = configService.get( "puffPoints.tokenAddress", @@ -193,6 +195,11 @@ export class PointsController { // layerbank point const layerbankPoint = await this.puffPointsService.getLayerBankPoint(address); + // aqua point + const aquaPoint = await this.puffPointsService.getAquaPoint(address); + this.logger.log( + `layerbankPoint: ${layerbankPoint}, aquaPoint: ${aquaPoint}`, + ); const point = data.items[0]; res = { errno: 0, @@ -202,7 +209,7 @@ export class PointsController { { address: point.address, tokenAddress: point.tokenAddress, - points: (point.realPoints + layerbankPoint).toString(), + points: (point.realPoints + layerbankPoint + aquaPoint).toString(), balance: Number(ethers.formatEther(point.balance)).toFixed(6), updated_at: point.updatedAt, }, @@ -231,12 +238,20 @@ export class PointsController { const pufPointsData = this.puffPointsService.getPointsData( address.toLocaleLowerCase(), ); + if (pufPointsData.items.length == 0) { + throw new NotFoundException(); + } // layerbank point const layerbankPoint = await this.puffPointsService.getLayerBankPoint(address); + // aqua point + const aquaPoint = await this.puffPointsService.getAquaPoint(address); + const pufferPoints = ( - pufPointsData.items[0].realPoints + layerbankPoint + pufPointsData.items[0].realPoints + + layerbankPoint + + aquaPoint ).toString(); const { userPosition, pools } = @@ -252,29 +267,25 @@ export class PointsController { const balanceFromDappTotal = userPosition?.positions.reduce((prev, cur) => { const pool = pools.find((pool) => pool.id === cur.pool); - if (pool?.name === "LayerBank") { - const shareBalance = - (BigInt(pool.balance) * BigInt(cur.supplied)) / - BigInt(pool.totalSupplied); - return prev + shareBalance; - } - return prev; + const shareBalance = + (BigInt(pool.balance) * BigInt(cur.supplied)) / + BigInt(pool.totalSupplied); + return prev + shareBalance; }, BigInt(0)) ?? BigInt(0); const liquidityDetails = userPosition?.positions .map((position) => { const pool = pools.find((pool) => pool.id === position.pool); - if (pool?.name === "LayerBank") - return { - dappName: pool.name, - balance: Number( - ethers.formatEther( - (BigInt(pool.balance) * BigInt(position.supplied)) / - BigInt(pool.totalSupplied), - ), - ).toFixed(6), - }; + return { + dappName: pool.name, + balance: Number( + ethers.formatEther( + (BigInt(pool.balance) * BigInt(position.supplied)) / + BigInt(pool.totalSupplied), + ), + ).toFixed(6), + }; }) .filter((i) => !!i) ?? []; @@ -506,11 +517,13 @@ export class PointsController { const data = this.puffPointsService.getPointsData(); const { pools, userPositions } = await this.puffPointsService.getPuffElPoints(pagingOptions); + const addresses = userPositions.map((i) => i.id); // layerbank point const layerbankPoints = - await this.puffPointsService.getLayerBankPointList( - userPositions.map((i) => i.id), - ); + await this.puffPointsService.getLayerBankPointList(addresses); + // aqua point + const aquaPoints = + await this.puffPointsService.getAquaPointList(addresses); res = { errno: 0, @@ -525,6 +538,10 @@ export class PointsController { (layerbankPoint) => layerbankPoint.address === p.id, )?.layerbankPoint ?? 0; + const aquaPoint = + aquaPoints.find((aquaPoint) => aquaPoint.address === p.id) + ?.aquaPoint ?? 0; + const liquidityBalance = p.positions.reduce((prev, cur) => { const pool = pools.find((pool) => pool.id === cur.pool); if (!pool) return prev; @@ -565,7 +582,7 @@ export class PointsController { userAddress: p.id, pufEthAddress: "0x1B49eCf1A8323Db4abf48b2F5EFaA33F7DdAB3FC", pufferPoints: ( - userPointData?.realPoints ?? 0 + layerbankPoint + userPointData?.realPoints ?? 0 + layerbankPoint + aquaPoint ).toString(), totalBalance: totalBalance, withdrawingBalance: Number( diff --git a/src/puffer/puffPoints.service.ts b/src/puffer/puffPoints.service.ts index e31cfcc..48b6f7c 100644 --- a/src/puffer/puffPoints.service.ts +++ b/src/puffer/puffPoints.service.ts @@ -2,12 +2,14 @@ import { Injectable, Logger } from "@nestjs/common"; import { LocalPointData, ProjectGraphService, -} from "src/common/service/projectGraph.service"; -import { GraphQueryService } from "src/common/service/graphQuery.service"; + LocalPointsItem, +} from "../common/service/projectGraph.service"; +import { GraphQueryService } from "../common/service/graphQuery.service"; import BigNumber from "bignumber.js"; -import { NovaService } from "src/nova/nova.service"; +import { NovaService } from "../nova/nova.service"; import { ConfigService } from "@nestjs/config"; -import { PagingOptionsDto } from "src/common/pagingOptionsDto.dto"; +import { PagingOptionsDto } from "../common/pagingOptionsDto.dto"; +import { AquaService } from "../nova/aqua.service"; export interface PufferPointItem { address: string; @@ -83,7 +85,10 @@ type PufferUserBalance = [ const LAYERBANK_LPUFFER = "0xdd6105865380984716C6B2a1591F9643e6ED1C48".toLocaleLowerCase(); - +const AQUA_LPUFFER = + "0xc2be3CC06Ab964f9E22e492414399DC4A58f96D3".toLocaleLowerCase(); +const AQUA_VAULT = + "0x4AC97E2727B0e92AE32F5796b97b7f98dc47F059".toLocaleLowerCase(); @Injectable() export class PuffPointsService { public tokenAddress: string; @@ -93,11 +98,13 @@ export class PuffPointsService { private localTotalPoints: bigint = BigInt(0); private localPoints: PufferPointItem[] = []; private puffElPointsGraphApi: string; + private readonly poolsName = ["LayerBank", "Aqua"]; public constructor( private readonly projectGraphService: ProjectGraphService, private readonly graphQueryService: GraphQueryService, private readonly novaService: NovaService, + private readonly aquaService: AquaService, private readonly configService: ConfigService, ) { this.logger = new Logger(PuffPointsService.name); @@ -125,17 +132,58 @@ export class PuffPointsService { const tokens = this.graphQueryService.getAllTokenAddresses( this.projectName, ); - if (tokens.length > 0) { - this.tokenAddress = tokens[0]; + if (tokens.length <= 0) { + this.logger.log(`Graph don't have ${this.projectName} tokens`); + return; } + this.tokenAddress = tokens[0].toLowerCase(); this.realTotalPoints = await this.getRealPointsData(); const pointsData = await this.getLocalPointsData(); this.localTotalPoints = pointsData.localTotalPoints; const _localPoints = pointsData.localPoints; + + // start added transferFaildPoint + const transferFaildPoints = this.projectGraphService.getTransferFaildPoints( + [this.tokenAddress], + ); + const localPointsMap = new Map(); + const totalPointsPerTokenMap = new Map(); + const now = (new Date().getTime() / 1000) | 0; + for (const item of _localPoints) { + const key = `${item.address}_${item.token}`; + totalPointsPerTokenMap.set(item.token, item.totalPointsPerToken); + localPointsMap.set(key, item); + } + // loop transferFaildData, and added transferFaildPoint to localPoints + for (const item of transferFaildPoints) { + const key = `${item.address}_${item.tokenAddress}`; + const transferFaildTotalPoint = + this.projectGraphService.getTransferFaildTotalPoint(item.tokenAddress); + if (!localPointsMap.has(key)) { + const tmpTotalPointsPerToken = + totalPointsPerTokenMap.get(item.tokenAddress) ?? BigInt(0); + localPointsMap.set(key, { + address: item.address, + points: item.points, + withdrawPoints: BigInt(0), + withdrawTotalPointsPerToken: BigInt(0), + totalPointsPerToken: tmpTotalPointsPerToken + transferFaildTotalPoint, + balance: BigInt(0), + token: item.tokenAddress, + updatedAt: now, + }); + } else { + const localPoint = localPointsMap.get(key); + localPoint.totalPointsPerToken = + localPoint.totalPointsPerToken + transferFaildTotalPoint; + localPoint.points = localPoint.points + item.points; + } + } + // end added transferFaildPoint + const localPoints = []; - for (let i = 0; i < _localPoints.length; i++) { - const item = _localPoints[i]; + for (const [, item] of localPointsMap) { const realPoints = new BigNumber(item.points.toString()) .multipliedBy(this.realTotalPoints) .div(item.totalPointsPerToken.toString()) @@ -162,11 +210,16 @@ export class PuffPointsService { realTotalPoints: this.realTotalPoints, items: this.localPoints, } as PufferData; + const needRemoveAddress = [LAYERBANK_LPUFFER, AQUA_VAULT]; if (address && this.localPoints.length > 0) { const _address = address.toLocaleLowerCase(); - result.items = this.localPoints.filter( - (item) => item.address === _address, - ); + if (needRemoveAddress.includes(_address)) { + result.items = []; + } else { + result.items = this.localPoints.filter( + (item) => item.address === _address, + ); + } } return result; } @@ -232,6 +285,29 @@ export class PuffPointsService { return 0; } + //get aqua point + public async getAquaPoint(address: string): Promise { + const _lpuffer = this.localPoints.filter( + (item) => item.address === AQUA_VAULT, + ); + if (_lpuffer.length == 0) { + return 0; + } + const lpuffer = _lpuffer[0]; + const lpufferPointData = await this.aquaService.getPoints(AQUA_LPUFFER, [ + address, + ]); + const lpufferFinalPoints = lpufferPointData.finalPoints; + const lpufferFinalTotalPoints = lpufferPointData.finalTotalPoints; + if (lpufferFinalPoints.length > 0) { + return new BigNumber(lpufferFinalPoints[0].points.toString()) + .multipliedBy(lpuffer.realPoints) + .div(lpufferFinalTotalPoints.toString()) + .toNumber(); + } + return 0; + } + //get layerbank point public async getLayerBankPointList( addresses: string[], @@ -255,11 +331,35 @@ export class PuffPointsService { .toNumber(), })); } + + //get aqua point + public async getAquaPointList( + addresses: string[], + ): Promise> { + const lpuffer = this.localPoints.find( + (item) => item.address === AQUA_VAULT, + ); + + const lpufferPointData = await this.aquaService.getPoints( + AQUA_LPUFFER, + addresses, + ); + const lpufferFinalPoints = lpufferPointData.finalPoints; + const lpufferFinalTotalPoints = lpufferPointData.finalTotalPoints; + return lpufferFinalPoints.map((lpufferFinalPoint) => ({ + address: lpufferFinalPoint.address, + aquaPoint: new BigNumber(lpufferFinalPoint.points.toString()) + .multipliedBy(lpuffer?.realPoints ?? 0) + .div(lpufferFinalTotalPoints.toString()) + .toNumber(), + })); + } + public async getPuffElPointsByAddress( address: string, ): Promise { - const protocolName = "LayerBank"; + const protocolName = this.poolsName; //"LayerBank"; const withdrawTime = Math.floor( (new Date().getTime() - 7 * 24 * 60 * 60 * 1000) / 1000, ); @@ -278,7 +378,7 @@ export class PuffPointsService { userPosition(id: "${address}") { id balance - positions( where: {poolName: ${JSON.stringify(protocolName)}}) { + positions( where: {poolName_in: ${JSON.stringify(protocolName)}}) { id pool supplied @@ -422,7 +522,7 @@ export class PuffPointsService { pagingOption: PagingOptionsDto, ): Promise { const { limit = 10, page = 1 } = pagingOption; - const protocolName = "LayerBank"; + const protocolName = this.poolsName; //"LayerBank"; const withdrawTime = Math.floor( (new Date().getTime() - 7 * 24 * 60 * 60 * 1000) / 1000, ); @@ -448,7 +548,7 @@ export class PuffPointsService { ) { id balance - positions(first: 1000, where: {poolName: ${JSON.stringify(protocolName)}}) { + positions(first: 1000, where: {poolName_in: ${JSON.stringify(protocolName)}}) { id pool poolName diff --git a/src/renzo/renzo.service.ts b/src/renzo/renzo.service.ts index b5daa04..9251a98 100644 --- a/src/renzo/renzo.service.ts +++ b/src/renzo/renzo.service.ts @@ -138,7 +138,7 @@ export class RenzoService { withdrawPoints: BigInt(0), withdrawTotalPointsPerToken: BigInt(0), totalPointsPerToken: tmpTotalPointsPerToken + transferFaildTotalPoint, - balance: item.balance, + balance: BigInt(0), token: item.tokenAddress, updatedAt: now, }); diff --git a/src/repositories/balanceOfLp.repository.ts b/src/repositories/balanceOfLp.repository.ts new file mode 100644 index 0000000..14beb7f --- /dev/null +++ b/src/repositories/balanceOfLp.repository.ts @@ -0,0 +1,74 @@ +import { Injectable } from "@nestjs/common"; +import { UnitOfWork } from "../unitOfWork"; +import { BaseRepository } from "./base.repository"; +import { BalanceOfLp } from "../entities/balanceOfLp.entity"; + +@Injectable() +export class BalanceOfLpRepository extends BaseRepository { + public constructor(unitOfWork: UnitOfWork) { + super(BalanceOfLp, unitOfWork); + } + + public async getLastList( + addresses: string[], + tokenAddress: string, + pairAddress: string, + ): Promise { + const addressesBuffer = addresses.map((address) => + Buffer.from(address.substring(2), "hex"), + ); + const transactionManager = this.unitOfWork.getTransactionManager(); + const query = ` + SELECT * FROM "balancesOfLp" AS a + LEFT JOIN + ( + SELECT address, "pairAddress", "tokenAddress", MAX("blockNumber") AS "blockNumber" + FROM "balancesOfLp" + WHERE "tokenAddress" = $1 AND "pairAddress" = $2 AND address = ANY($3) + GROUP BY address, "pairAddress", "tokenAddress" + ) AS b + ON a.address = b.address + AND a."tokenAddress" = b."tokenAddress" + AND a."pairAddress" = b."pairAddress" + AND a."blockNumber" = b."blockNumber"; + `; + const result = await transactionManager.query(query, [ + tokenAddress, + pairAddress, + addressesBuffer, + ]); + return result.map((row) => { + row.address = "0x" + row.address.toString("hex"); + row.tokenAddress = "0x" + row.tokenAddress.toString("hex"); + row.pairAddress = "0x" + row.pairAddress.toString("hex"); + return row; + }); + } + + public async getListByBlockNumber( + addresses: string[], + tokenAddress: string, + pairAddress: string, + blockNumber: number, + ): Promise { + const addressesBuffer = addresses.map((address) => + Buffer.from(address.substring(2), "hex"), + ); + const transactionManager = this.unitOfWork.getTransactionManager(); + const query = ` + SELECT * FROM "balancesOfLp" WHERE "tokenAddress" = $1 AND "pairAddress" = $2 AND address = ANY($3) AND "blockNumber" = $4; + `; + const result = await transactionManager.query(query, [ + tokenAddress, + pairAddress, + addressesBuffer, + blockNumber, + ]); + return result.map((row) => { + row.address = "0x" + row.address.toString("hex"); + row.tokenAddress = "0x" + row.tokenAddress.toString("hex"); + row.pairAddress = "0x" + row.pairAddress.toString("hex"); + return row; + }); + } +} diff --git a/src/repositories/blockAddressPointOfLp.repository.ts b/src/repositories/blockAddressPointOfLp.repository.ts index ba402b0..7ea1cf5 100644 --- a/src/repositories/blockAddressPointOfLp.repository.ts +++ b/src/repositories/blockAddressPointOfLp.repository.ts @@ -48,7 +48,7 @@ export class BlockAddressPointOfLpRepository extends BaseRepository { const transactionManager = this.unitOfWork.getTransactionManager(); - const query = `SELECT COUNT(DISTINCT "address") FROM "blockAddressPointOfLp" WHERE "createdAt" >= '${startTime}' AND "createdAt" <= '${endTime}'`; + const query = `SELECT COUNT(DISTINCT "address") FROM "blockAddressPointOfLp" WHERE "createdAt" >= '${startTime}' AND "createdAt" < '${endTime}'`; const result = await transactionManager.query(query); return parseInt(result[0].count); } @@ -59,7 +59,7 @@ export class BlockAddressPointOfLpRepository extends BaseRepository { const transactionManager = this.unitOfWork.getTransactionManager(); - const query = `SELECT b.name, a."address", SUM(a."holdPoint") as "totalPoints" FROM "blockAddressPointOfLp" AS a LEFT JOIN project AS b ON a."pairAddress" = b."pairAddress" WHERE a.address = ANY($1) AND a."createdAt" >= '${startTime}' AND a."createdAt" <= '${endTime}' GROUP BY b.name, a."address"`; + const query = `SELECT b.name, a."address", SUM(a."holdPoint") as "totalPoints" FROM "blockAddressPointOfLp" AS a LEFT JOIN project AS b ON a."pairAddress" = b."pairAddress" WHERE a.address = ANY($1) AND a."createdAt" >= '${startTime}' AND a."createdAt" < '${endTime}' GROUP BY b.name, a."address"`; const result = await transactionManager.query(query, [addresses]); return result.map((row: any) => { row.name = row.name == "owlet" ? "owlto" : row.name; diff --git a/src/rseth/rseth.service.ts b/src/rseth/rseth.service.ts index 92a4fee..55d4b7c 100644 --- a/src/rseth/rseth.service.ts +++ b/src/rseth/rseth.service.ts @@ -10,6 +10,7 @@ import { ExplorerService } from "src/common/service/explorer.service"; import { ConfigService } from "@nestjs/config"; import BigNumber from "bignumber.js"; import waitFor from "src/utils/waitFor"; +import { LocalPointsItem } from "../common/service/projectGraph.service"; export interface RsethPointItemWithBalance { address: string; @@ -99,6 +100,45 @@ export class RsethService { const localPoints = localPointsData.localPoints; const localTotalPoints = localPointsData.localTotalPoints; + // start added transferFaildPoint + const transferFaildPoints = this.projectGraphService.getTransferFaildPoints( + this.tokenAddress, + ); + const localPointsMap = new Map(); + const totalPointsPerTokenMap = new Map(); + const now = (new Date().getTime() / 1000) | 0; + for (const item of localPoints) { + const key = `${item.address}_${item.token}`; + totalPointsPerTokenMap.set(item.token, item.totalPointsPerToken); + localPointsMap.set(key, item); + } + // loop transferFaildData, and added transferFaildPoint to localPoints + for (const item of transferFaildPoints) { + const key = `${item.address}_${item.tokenAddress}`; + const transferFaildTotalPoint = + this.projectGraphService.getTransferFaildTotalPoint(item.tokenAddress); + if (!localPointsMap.has(key)) { + const tmpTotalPointsPerToken = + totalPointsPerTokenMap.get(item.tokenAddress) ?? BigInt(0); + localPointsMap.set(key, { + address: item.address, + points: item.points, + withdrawPoints: BigInt(0), + withdrawTotalPointsPerToken: BigInt(0), + totalPointsPerToken: tmpTotalPointsPerToken + transferFaildTotalPoint, + balance: BigInt(0), + token: item.tokenAddress, + updatedAt: now, + }); + } else { + const localPoint = localPointsMap.get(key); + localPoint.totalPointsPerToken = + localPoint.totalPointsPerToken + transferFaildTotalPoint; + localPoint.points = localPoint.points + item.points; + } + } + // end added transferFaildPoint + // define a variable to store the matched bridge token const tokensMapBridgeTokens = await this.getTokensMapBriageTokens(); // define a variable to store the real total el points and kelp miles @@ -107,7 +147,7 @@ export class RsethService { const data: RsethPointItemWithBalance[] = []; // calculate real points = local points * real total points / local total points - for (const item of localPoints) { + for (const [, item] of localPointsMap) { const bridgeToken = tokensMapBridgeTokens.get(item.token); // if the token is not in the bridge token list, skip it if (!bridgeToken) {