Skip to content

Commit

Permalink
milestone and category list interface.
Browse files Browse the repository at this point in the history
  • Loading branch information
robert-zklink committed Jun 27, 2024
1 parent 978e29d commit af9e8a7
Show file tree
Hide file tree
Showing 13 changed files with 323 additions and 7 deletions.
2 changes: 2 additions & 0 deletions src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import { PositionsService } from "./positions/positions.service";
import { PositionsController } from "./positions/positions.controller";
import { TvlController } from "./tvl/tvl.controller";
import { TvlService } from "./tvl/tvl.service";
import { TxDataOfPointsRepository } from "./repositories/txDataOfPoints.repository";

@Module({
imports: [
Expand Down Expand Up @@ -129,6 +130,7 @@ import { TvlService } from "./tvl/tvl.service";
SwethApiService,
PositionsService,
TvlService,
TxDataOfPointsRepository,
],
})
export class AppModule {}
6 changes: 5 additions & 1 deletion src/config/projectCategory.config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const categoryBaseConfig = [
{
name: "spotdex",
items: ["novaswap", "izumi", "wagmi", "eddy"],
items: ["izumi", "wagmi", "eddy"],
},
{
name: "perpdex",
Expand All @@ -15,6 +15,10 @@ const categoryBaseConfig = [
name: "gamefi",
items: ["allspark"],
},
{
name: "nativeboost",
items: ["novaswap"],
},
{
name: "other",
items: ["rubic", "interport", "orbiter", "symbiosis", "meson"],
Expand Down
1 change: 1 addition & 0 deletions src/entities/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export * from "./user.entity";
export * from "./userHolding.entity";
export * from "./userStaked.entity";
export * from "./userWithdraw.entity";
export * from "./transactionDataOfPoints.entity";
39 changes: 39 additions & 0 deletions src/entities/transactionDataOfPoints.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
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: "transactionDataOfPoints" })
@Index(["userAddress", "txHash", "nonce"], { unique: true })
export class TransactionDataOfPoints extends BaseEntity {
@PrimaryColumn({ type: "bytea", transformer: hexTransformer })
public readonly userAddress: string;

@PrimaryColumn({ type: "bytea", transformer: hexTransformer })
public readonly contractAddress: string;

@PrimaryColumn({ type: "bytea", transformer: hexTransformer })
public readonly tokenAddress: string;

@PrimaryColumn({ type: "smallint" })
public readonly decimals: number;

@Column({ type: "varchar", length: 100, nullable: true })
public readonly price: string;

@Column({ type: "bigint", transformer: bigIntNumberTransformer })
public readonly quantity: string;

@Column({ type: "varchar", length: 100 })
public readonly nonce: string;

@Column({ type: "timestamp" })
public readonly timestamp: Date;

@PrimaryColumn({ type: "bytea", transformer: hexTransformer })
public readonly txHash: string;

@Index()
@Column({ type: "bigint", transformer: bigIntNumberTransformer })
public readonly blockNumber: number;
}
40 changes: 40 additions & 0 deletions src/nova/nova.balance.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -248,4 +248,44 @@ export class NovaBalanceService {
}
return projectCategoryPoints;
}

public async getPointsListByCategory(
category: string,
page: number = 1,
pageSize: number = 100,
): Promise<
{
username: string;
address: string;
totalPoint: number;
}[]
> {
// 1. get all projects in the category
// 2. get all pairAddress in the projects
// 3. get sum points in pairAddress group by address
// 4. sort by points
// 5. return
const startTime = "2024-05-30 00:00:00";
const endTime = "2024-07-14 00:00:00";
const projects = projectCategoryConfig
.filter((x) => x.category === category)
.map((x) => x.project);
const pairAddresses =
await this.projectRepository.getPairAddressesByProjects(projects);
const pointsList =
await this.blockAddressPointOfLpRepository.getAddressPagingOrderByTotalPointsPairAddresses(
pairAddresses,
page,
pageSize,
startTime,
endTime,
);
return pointsList.map((item) => {
return {
username: item.address,
address: item.address,
totalPoint: item.totalPoints,
};
});
}
}
27 changes: 26 additions & 1 deletion src/nova/nova.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import { NovaBalanceService } from "./nova.balance.service";
import { PagingOptionsDto } from "../common/pagingOptionsDto.dto";
import { PagingMetaDto } from "../common/paging.dto";
import { ResponseDto } from "src/common/response.dto";
import { CategoryPointsDto } from "./nova.dto";
import { CategoryPointsDto, CategoryPointsListDto } from "./nova.dto";

const options = {
// how long to live in ms
Expand Down Expand Up @@ -455,6 +455,31 @@ export class NovaController {
};
}

@Get("/category/:category/list")
@ApiOperation({ summary: "User score ranking under a category" })
@ApiBadRequestResponse({
description: '{ "errno": 1, "errmsg": "Service exception" }',
})
@ApiNotFoundResponse({
description: '{ "errno": 1, "errmsg": "not found" }',
})
public async getNovaCategoryPointsRank(
@Param("category") category: string,
@Query() pagingOptions: PagingOptionsDto,
): Promise<ResponseDto<CategoryPointsListDto[]>> {
const { page = 1, limit = 100 } = pagingOptions;
const data = await this.novaBalanceService.getPointsListByCategory(
category,
page,
limit,
);
return {
errno: 0,
errmsg: "no error",
data: data,
};
}

private getReturnData(
finalPoints: any[],
finnalTotalPoints: bigint,
Expand Down
20 changes: 20 additions & 0 deletions src/nova/nova.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,23 @@ export class CategoryPointsDto {
})
public readonly refPoints: number;
}

export class CategoryPointsListDto {
@ApiProperty({
type: String,
description: "Address of the user",
})
public readonly address: string;

@ApiProperty({
type: String,
description: "Name of the user",
})
public readonly username: string;

@ApiProperty({
type: Number,
description: "Total point of the user",
})
public readonly totalPoint: number;
}
34 changes: 33 additions & 1 deletion src/repositories/blockAddressPointOfLp.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export class BlockAddressPointOfLpRepository extends BaseRepository<BlockAddress
GROUP BY "address"
) AS a ORDER BY "totalPoints" DESC LIMIT ${limit} OFFSET ${page * limit}`;
const result = await transactionManager.query(query);
const existsAddresses: String[] = [
const existsAddresses: string[] = [
"0xacb35c2d11fea8849cd9f5ff6fbc56bb5296641b",
"0x047597323b957cd25b595377cb0d694f496b0fd8",
"0x99ce1b33765d0ab9f9d38905685b7d0caba89b60",
Expand All @@ -53,6 +53,38 @@ export class BlockAddressPointOfLpRepository extends BaseRepository<BlockAddress
});
}

public async getAddressPagingOrderByTotalPointsPairAddresses(
pairAddresses: string[],
page: number,
limit: number,
startTime: string,
endTime: string,
): Promise<
{
address: string;
totalPoints: number;
}[]
> {
page = page - 1;
page = page < 0 ? 0 : page;
const pairAddressesBuf = pairAddresses.map((pairAddress) =>
Buffer.from(pairAddress.substring(2), "hex"),
);
const transactionManager = this.unitOfWork.getTransactionManager();
const query = `SELECT * FROM (
SELECT "address", SUM("holdPoint") as "totalPoints"
FROM "blockAddressPointOfLp"
WHERE "createdAt" >= '${startTime}' AND "createdAt" <= '${endTime}'
AND "pairAddress" = ANY($1)
GROUP BY "address"
) AS a ORDER BY "totalPoints" DESC LIMIT ${limit} OFFSET ${page * limit}`;
const result = await transactionManager.query(query, [pairAddressesBuf]);
return result.map((row: any) => {
row.address = "0x" + row.address.toString("hex");
return row;
});
}

public async getAddressDailyCount(
startTime: string,
endTime: string,
Expand Down
12 changes: 12 additions & 0 deletions src/repositories/project.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,18 @@ export class ProjectRepository extends BaseRepository<Project> {
return result.map((row: any) => row.pairAddress);
}

// select pairAddress from project where name = projectName
public async getPairAddressesByProjects(
projectNames: string[],
): Promise<string[]> {
const transactionManager = this.unitOfWork.getTransactionManager();
const result = await transactionManager.query(
`select "pairAddress" from project where name = ANY($1)`,
[projectNames],
);
return result.map((row: any) => "0x" + row.pairAddress.toString("hex"));
}

// get all projects
public async getAllProjects(): Promise<string[]> {
const transactionManager = this.unitOfWork.getTransactionManager();
Expand Down
48 changes: 48 additions & 0 deletions src/repositories/txDataOfPoints.repository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { Injectable } from "@nestjs/common";
import { UnitOfWork as UnitOfWork } from "../unitOfWork";
import { BaseRepository } from "./base.repository";
import { TransactionDataOfPoints } from "../entities";

export interface TransactionDataOfPointsDto {
userAddress: string;
contractAddress: string;
tokenAddress: string;
decimals: number;
price: string;
quantity: bigint;
nonce: string;
timestamp: Date;
txHash: string;
blockNumber: number;
projectName: string;
}
@Injectable()
export class TxDataOfPointsRepository extends BaseRepository<TransactionDataOfPoints> {
public constructor(unitOfWork: UnitOfWork) {
super(TransactionDataOfPoints, unitOfWork);
}

public async getListByTime(
startTime: string,
endTime: string,
pairAddress: string[],
): Promise<TransactionDataOfPointsDto[]> {
const pairAddressBuffer = pairAddress.map((item) =>
Buffer.from(item.slice(2), "hex"),
);
const transactionManager = this.unitOfWork.getTransactionManager();
const result = await transactionManager.query(
`SELECT * FROM public."transactionDataOfPoints" WHERE "timestamp">='${startTime}' AND "timestamp"<'${endTime}' AND "contractAddress"=ANY($1);`,
[pairAddressBuffer],
);
return result.map((row: any) => {
row.userAddress = "0x" + row.userAddress.toString("hex").toLowerCase();
row.contractAddress =
"0x" + row.contractAddress.toString("hex").toLowerCase();
row.tokenAddress = "0x" + row.tokenAddress.toString("hex").toLowerCase();
row.txHash = "0x" + row.txHash.toString("hex").toLowerCase();
row.timestamp = new Date(row.timestamp);
return row;
});
}
}
25 changes: 22 additions & 3 deletions src/tvl/tvl.controller.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Controller, Get, Logger } from "@nestjs/common";
import { ApiExcludeController, ApiOperation, ApiTags } from "@nestjs/swagger";
import { ResponseDto } from "src/common/response.dto";
import { CategoryTvlDto } from "./tvl.dto";
import { CategoryMilestoneDto, CategoryTvlDto } from "./tvl.dto";
import { TvlService } from "./tvl.service";

@ApiTags("tvl")
Expand All @@ -13,8 +13,8 @@ export class TvlController {
constructor(private tvlService: TvlService) {}

@Get("/category")
@ApiOperation({ summary: "Get token personal points" })
public async getNovaPoints(): Promise<ResponseDto<CategoryTvlDto[]>> {
@ApiOperation({ summary: "Retrieve tvl of the project category" })
public async getCategoryTvl(): Promise<ResponseDto<CategoryTvlDto[]>> {
const data = await this.tvlService.getCategoryTvl();
return {
errno: 0,
Expand All @@ -27,4 +27,23 @@ export class TvlController {
}),
};
}

@Get("/category/milestone")
@ApiOperation({ summary: "Retrieve milestone of the project category" })
public async getCategoryMilestone(): Promise<
ResponseDto<CategoryMilestoneDto[]>
> {
const data = await this.tvlService.getCategoryMilestone();
return {
errno: 0,
errmsg: "no error",
data: data.map((item) => {
return {
name: item.name,
data: item.data.toFixed(4),
type: item.type,
};
}),
};
}
}
23 changes: 23 additions & 0 deletions src/tvl/tvl.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,26 @@ export class CategoryTvlDto {
})
public readonly tvl: string;
}

export class CategoryMilestoneDto {
@ApiProperty({
type: String,
description: "Name of the category, is unique identifier for the category",
example: "spotdex",
})
public readonly name: string;

@ApiProperty({
type: String,
description: "tvl or volume of the project in category",
example: "5986.2523",
})
public readonly data: string;

@ApiProperty({
type: String,
description: "tvl or volume",
example: "tvl",
})
public readonly type: string;
}
Loading

0 comments on commit af9e8a7

Please sign in to comment.