Skip to content

Commit

Permalink
Merge branch 'feat-transfer-faild-v2' of github.com:zkLinkProtocol/lr…
Browse files Browse the repository at this point in the history
…t-points-distribute into feat-transfer-faild-v2
  • Loading branch information
robert-zklink committed May 6, 2024
2 parents 6ebd849 + 7f7f5dd commit 79d8f17
Show file tree
Hide file tree
Showing 4 changed files with 251 additions and 5 deletions.
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,4 @@ L1_ERC20_BRIDGE_LINEA=0x62cE247f34dc316f93D3830e4Bf10959FCe630f8
L1_ERC20_BRIDGE_BLAST=0x8Df0c2bA3916bF4789c50dEc5A79b2fc719F500b

NOVA_POINT_REDISTRIBUTE_GRAPH_API=
NOVA_POINT_PUFFER_EL_POINTS_GRAPH_API=
NOVA_POINT_PUFFER_EL_POINTS_GRAPH_API=http://3.114.68.110:8000/subgraphs/name/puffer-eth-points-v2
65 changes: 64 additions & 1 deletion src/puffer/points.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ import {
ElPointsDto,
PointsDto,
ElPointsDtoItem,
LayerBankPufferPointQueryOptionsDto,
PufferPointUserBalance,
} from "./points.dto";
import { TokensDto } from "./tokens.dto";
import { NovaService } from "src/nova/nova.service";
Expand Down Expand Up @@ -501,7 +503,7 @@ export class PointsController {
@Get("/puffer")
@ApiOkResponse({
description:
"Return paginated results of all users' Puffer Eigenlayer Points. The rule is to add 30 points per hour.\nTiming starts from the user's first deposit, with each user having an independent timer.",
"Return paginated results of all users' Puffer Points. The rule is to add 30 points per hour.\nTiming starts from the user's first deposit, with each user having an independent timer.",
type: ElPointsDto,
})
@ApiBadRequestResponse({
Expand Down Expand Up @@ -611,4 +613,65 @@ export class PointsController {

return res;
}

@Get("/puffer/:address/balances")
@ApiOkResponse({
description:
"Return users' puffer balance. Including the withdrawing and staked balance in dapp.",
type: ElPointsDto,
})
@ApiBadRequestResponse({
description: '{ "message": "Not Found", "statusCode": 404 }',
})
public async queryUserPufferHistoricData(
@Param("address", new ParseAddressPipe()) address: string,
@Query() queryOptions: LayerBankPufferPointQueryOptionsDto,
): Promise<PufferPointUserBalance> {
let res: PufferPointUserBalance;
try {
const [userPosition, pools] =
await this.puffPointsService.getPufferUserBalance(
address,
queryOptions.time,
);

const dappBalance = userPosition.positionHistory.map((item) => {
const pool = pools.find((i) => i.pool === item.pool);
return {
dappName: item.poolName,
balance: Number(
ethers.formatEther(
(BigInt(pool.balance) * BigInt(item.supplied)) /
BigInt(pool.totalSupplied),
),
).toFixed(6),
};
});
res = {
errno: 0,
errmsg: "no error",
data: {
dappBalance: dappBalance,
withdrawingBalance: Number(
ethers.formatEther(
userPosition.withdrawHistory.reduce((prev, cur) => {
return prev + BigInt(cur.balance);
}, BigInt(0)),
),
).toFixed(6),
},
};
} catch (e) {
res = {
errno: 1,
errmsg: "Not Found",
data: {
dappBalance: [],
withdrawingBalance: "0",
},
};
}

return res;
}
}
60 changes: 59 additions & 1 deletion src/puffer/points.dto.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ApiProperty } from "@nestjs/swagger";
import { Type } from "class-transformer";
// import { IsArray, IsNumber, IsString } from "class-validator";
import { IsDateString } from "class-validator";

export class PointsDto {
@ApiProperty({
Expand Down Expand Up @@ -220,3 +220,61 @@ export class ElPointsDto {
})
public readonly data: ElPointsDtoData;
}

export class LayerBankPufferPointQueryOptionsDto {
@ApiProperty({
type: Number,
description: "date time to query",
example: "2024-04-28 10:20:22",
})
@IsDateString()
public readonly time: string;
}

export class PufferPointUserBalanceData {
@ApiProperty({
type: String,
description: "withdrawing balance",
example: "0.020000",
})
public readonly withdrawingBalance: string;

@ApiProperty({
type: LiquidityDetails,
description: "user staked details on dapps",
example: [
{
dappName: "LayerBank",
balance: "0.000023",
},
{
dappName: "Aqua",
balance: "0.010000",
},
],
})
public readonly dappBalance: LiquidityDetails[];
}

export class PufferPointUserBalance {
@ApiProperty({
type: Number,
description: "error code",
example: 0,
})
public readonly errno: number;
//err msg
@ApiProperty({
type: String,
description: "error message",
example: "no error",
})
public readonly errmsg: string;

@ApiProperty({
type: PufferPointUserBalanceData,
description: "puffer points data",
nullable: true,
})
public readonly data: PufferPointUserBalanceData;
}
129 changes: 127 additions & 2 deletions src/puffer/puffPoints.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,22 @@ interface PufferElPoints {
userPositions: EigenlayerPosition[];
}

type PufferUserBalance = [
{
id: string;
balance: string;
positionHistory: {
id: string;
pool: string;
supplied: string;
token: string;
poolName: string;
}[];
withdrawHistory: WithdrawnItem[];
},
Array<EigenlayerPool & { pool: string }>,
];

const LAYERBANK_LPUFFER =
"0xdd6105865380984716C6B2a1591F9643e6ED1C48".toLocaleLowerCase();
const AQUA_LPUFFER =
Expand Down Expand Up @@ -315,7 +331,7 @@ export class PuffPointsService {
.toNumber(),
}));
}

//get aqua point
public async getAquaPointList(
addresses: string[],
Expand All @@ -339,7 +355,7 @@ export class PuffPointsService {
.toNumber(),
}));
}

public async getPuffElPointsByAddress(
address: string,
): Promise<PufferElPointsByAddress> {
Expand Down Expand Up @@ -393,6 +409,115 @@ export class PuffPointsService {
}
}

public async getPufferUserBalance(
address: string,
date: string,
): Promise<PufferUserBalance> {
const protocolName = ["LayerBank"]; // "Aqua" to be added

const specialDateTime = new Date("2024-05-05 00:00:00").getTime();
const queryDateTime = new Date(date).getTime();

const queryUnixTime = Math.floor(queryDateTime) / 1000;
const queryWithdrawnUnixTime =
queryDateTime > specialDateTime
? Math.floor((queryDateTime - 7 * 24 * 60 * 60 * 1000) / 1000)
: Math.floor((queryDateTime - 14 * 24 * 60 * 60 * 1000) / 1000);

try {
const balanceQueryBody = {
query: `{
userPosition(id: "${address}") {
id
balance
positionHistory(
where: {
poolName_in: ${JSON.stringify(protocolName)}
blockTimestamp_lte: "${queryUnixTime}"
}
first: 1
orderBy: blockNumber
orderDirection: desc
) {
id
pool
supplied
token
poolName
blockNumber
blockTimestamp
}
withdrawHistory(first: 1000, where: {
blockTimestamp_gte: "${queryWithdrawnUnixTime}",
blockTimestamp_lte: "${queryUnixTime}",
token: "0x1B49eCf1A8323Db4abf48b2F5EFaA33F7DdAB3FC"}
) {
token
id
blockTimestamp
blockNumber
balance
}
}
}`,
};

const response = await fetch(this.puffElPointsGraphApi, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(balanceQueryBody),
});
const { data } = await response.json();

const historicData = data.userPosition.positionHistory.map((i) => ({
poolId: i.pool,
}));

const genPoolQueryBody = (poolId: string) => ({
query: `{
poolHistoricItems(
where: {
pool: "${poolId}"
blockTimestamp_lte: "${queryUnixTime}"
}
orderBy: blockTimestamp
orderDirection: desc
first: 1
) {
decimals
id
pool
name
symbol
totalSupplied
underlying
balance
blockTimestamp
blockNumber
}
}`,
});

const poolData = await Promise.all(
historicData.map(async (item) => {
const queryString = genPoolQueryBody(item.poolId);
const response = await fetch(this.puffElPointsGraphApi, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(queryString),
});
const { data } = await response.json();
return data.poolHistoricItems[0];
}),
);

return [data.userPosition, poolData];
} catch (err) {
this.logger.error("Fetch puffer points by address data fail", err.stack);
return undefined;
}
}

public async getPuffElPoints(
pagingOption: PagingOptionsDto,
): Promise<PufferElPoints> {
Expand Down

0 comments on commit 79d8f17

Please sign in to comment.