Skip to content

Commit

Permalink
GET /token/winners
Browse files Browse the repository at this point in the history
  • Loading branch information
ArtemKolodko committed Nov 8, 2024
1 parent 1baf798 commit 860398e
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 8 deletions.
7 changes: 6 additions & 1 deletion src/app.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { ConfigService } from '@nestjs/config';
import {SkipThrottle} from "@nestjs/throttler";
import {AddCommentDto, GetCommentsDto} from "./dto/comment.dto";
import {AppService} from "./app.service";
import {GetTokenBalancesDto, GetTokensDto} from "./dto/token.dto";
import {GetTokenBalancesDto, GetTokensDto, GetTokenWinnersDto} from "./dto/token.dto";
import {GetTradesDto} from "./dto/trade.dto";
import {AddUserDto} from "./dto/user.dto";
import {UserService} from "./user/user.service";
Expand Down Expand Up @@ -55,6 +55,11 @@ export class AppController {
return this.appService.getTokenBalances(dto)
}

@Get('/token/winners')
getWinners(@Query() dto: GetTokenWinnersDto) {
return this.appService.getTokenWinners(dto)
}

@Get('/comments')
getComments(@Query() dto: GetCommentsDto) {
return this.appService.getComments(dto)
Expand Down
15 changes: 12 additions & 3 deletions src/app.service.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {Injectable, Logger} from '@nestjs/common';
import {Between, DataSource} from "typeorm";
import {Comment, Token, TokenBalance, UserAccount} from "./entities";
import {Comment, Token, TokenBalance, TokenWinner, UserAccount} from "./entities";
import {AddCommentDto, GetCommentsDto} from "./dto/comment.dto";
import {GetTokenBalancesDto, GetTokensDto} from "./dto/token.dto";
import {GetTokenBalancesDto, GetTokensDto, GetTokenWinnersDto} from "./dto/token.dto";
import {Trade} from "./entities";
import {GetTradesDto} from "./dto/trade.dto";
import {UserService} from "./user/user.service";
Expand Down Expand Up @@ -54,7 +54,6 @@ export class AppService {

async getTokenBalances(dto: GetTokenBalancesDto){
const { offset = 0, limit = 100 } = dto

return this.dataSource.manager.find(TokenBalance, {
where: {
token: {
Expand All @@ -69,6 +68,16 @@ export class AppService {
})
}

async getTokenWinners(dto: GetTokenWinnersDto) {
return await this.dataSource.manager.find(TokenWinner, {
order: {
timestamp: 'desc'
},
take: dto.limit,
skip: dto.offset,
})
}

async getTrades(dto: GetTradesDto){
return await this.dataSource.manager.find(Trade, {
where: {
Expand Down
14 changes: 14 additions & 0 deletions src/dto/token.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,17 @@ export class GetTokenBalancesDto {
@IsString()
offset: number;
}

export class GetTokenWinnersDto {
@ApiProperty({ type: Number, required: false, default: '100' })
// @Transform((limit) => limit.value.toNumber())
@Type(() => String)
@IsString()
limit: number;

@ApiProperty({ type: Number, required: false, default: '0' })
// @Transform((offset) => offset.value.toNumber())
@Type(() => String)
@IsString()
offset: number;
}
6 changes: 4 additions & 2 deletions src/entities/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,17 @@ import { IndexerState } from './indexer.state.entity';
import { Trade } from './trade.entity';
import { Comment } from './comment.entity';
import { TokenBalance } from './token.balances.entity';
import { TokenWinner } from './token.winner.entity';

const entities = [
UserAccount,
Token,
IndexerState,
Trade,
Comment,
TokenBalance
TokenBalance,
TokenWinner
];

export { UserAccount, Token, IndexerState, Trade, Comment, TokenBalance };
export { UserAccount, Token, IndexerState, Trade, Comment, TokenBalance, TokenWinner };
export default entities;
37 changes: 37 additions & 0 deletions src/entities/token.winner.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import {
Column,
CreateDateColumn,
Entity,
PrimaryGeneratedColumn,
ManyToOne
} from 'typeorm';
import { ApiProperty } from '@nestjs/swagger';
import {Token} from "./token.entity";

@Entity({ name: 'token_winners' })
export class TokenWinner {
@ApiProperty()
@PrimaryGeneratedColumn('uuid')
id: string;

@ManyToOne(() => Token, {
eager: true
})
token: Token

@ApiProperty()
@Column({ type: 'decimal', default: 0 })
timestamp: string;

@ApiProperty()
@Column()
txnHash: string;

@ApiProperty()
@Column({ type: 'integer' })
blockNumber: number;

@ApiProperty()
@CreateDateColumn({ name: 'createdAt' })
createdAt: Date;
}
45 changes: 43 additions & 2 deletions src/indexer/indexer.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {Contract, ContractAbi, EventLog, Web3} from "web3";
import {TokenMetadata, TradeEventLog, TradeType} from "../types";
import axios from "axios";
import process from "process";
import {IndexerState, Token, TokenBalance, Trade} from "../entities";
import {IndexerState, Token, TokenBalance, TokenWinner, Trade} from "../entities";
import {ConfigService} from "@nestjs/config";
import {UserService} from "../user/user.service";
import {DataSource} from "typeorm";
Expand Down Expand Up @@ -83,6 +83,42 @@ export class IndexerService {
}
}

private async processSetWinnerEvents(events: EventLog[]) {
for(const event of events) {
const txnHash = event.transactionHash.toLowerCase()
const blockNumber = Number(event.blockNumber)
const values = event.returnValues
const winnerAddress = (values['winner'] as string).toLowerCase()
const timestamp = String(values['timestamp'] as bigint)

const existedWinner = await this.dataSource.manager.findOne(TokenWinner, {
where: {
token: {
address: winnerAddress
},
timestamp
}
})

if(!existedWinner) {
const token = await this.appService.getTokenByAddress(winnerAddress)
if(!token) {
this.logger.error(`Winner token entry not found in database, winnerAddress=${winnerAddress} , exit`)
process.exit(1)
}
await this.dataSource.manager.insert(TokenWinner, {
token,
timestamp,
txnHash,
blockNumber
})
this.logger.log(`Added new token winner=${winnerAddress}, timestamp=${timestamp}`)
} else {
this.logger.warn(`Token winner=${winnerAddress}, timestamp=${timestamp} already exists, skip`)
}
}
}

private async processTradeEvents(events: TradeEventLog[]) {
for(const event of events) {
const { type, data } = event
Expand Down Expand Up @@ -208,6 +244,10 @@ export class IndexerService {
}

if(toBlock - fromBlock >= 1) {
const setWinnerEvents = await this.tokenFactoryContract.getPastEvents('allEvents', {
fromBlock, toBlock, topics: [ this.web3.utils.sha3('SetWinner(address,uint256)')],
}) as EventLog[];

const tokenCreatedEvents = await this.tokenFactoryContract.getPastEvents('allEvents', {
fromBlock,
toBlock,
Expand Down Expand Up @@ -289,9 +329,10 @@ export class IndexerService {
this.logger.log(`Create token: address=${tokenAddress}, name=${name}, symbol=${symbol}, uri=${uri}, creator=${creatorAddress}, txnHash=${txnHash}`);
}

await this.processSetWinnerEvents(setWinnerEvents)
await this.processTradeEvents(tradeEvents)

this.logger.log(`[${fromBlock}-${toBlock}] (${((toBlock - fromBlock + 1))} blocks), new tokens=${tokenCreatedEvents.length}, trade=${[...buyEvents, ...sellEvents].length} (buy=${buyEvents.length}, sell=${sellEvents.length})`)
this.logger.log(`[${fromBlock}-${toBlock}] (${((toBlock - fromBlock + 1))} blocks), new tokens=${tokenCreatedEvents.length}, trade=${[...buyEvents, ...sellEvents].length} (buy=${buyEvents.length}, sell=${sellEvents.length}), setWinner=${setWinnerEvents.length}`)
} else {
// Wait for blockchain
toBlock = fromBlockParam - 1
Expand Down

0 comments on commit 860398e

Please sign in to comment.