Skip to content

Commit

Permalink
Add user accounts and connect it to the token accounts
Browse files Browse the repository at this point in the history
  • Loading branch information
ArtemKolodko committed Oct 30, 2024
1 parent 040c8ef commit f30f366
Show file tree
Hide file tree
Showing 8 changed files with 148 additions and 23 deletions.
39 changes: 37 additions & 2 deletions src/app.controller.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,33 @@
import {Body, Controller, Get, NotFoundException, Post, Query} from '@nestjs/common';
import {
BadRequestException,
Body,
Controller,
Get,
Logger,
NotFoundException,
Param,
Post,
Query
} from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { ConfigService } from '@nestjs/config';
import {SkipThrottle} from "@nestjs/throttler";
import {AddCommentDto, GetCommentsDto} from "./dto/comment.dto";
import {AppService} from "./app.service";
import {GetTokensDto} from "./dto/token.dto";
import {GetTradesDto} from "./dto/trade.dto";
import {AddUserDto, GetUsersDto} from "./dto/user.dto";
import {UserService} from "./user/user.service";

@SkipThrottle()
@ApiTags('app')
@Controller()
export class AppController {
private readonly logger = new Logger(AppController.name);
constructor(
private readonly configService: ConfigService,
private readonly appService: AppService
private readonly appService: AppService,
private readonly userService: UserService
) {}
@Get('/version')
getVersion() {
Expand Down Expand Up @@ -48,4 +62,25 @@ export class AppController {
getTrades(@Query() dto: GetTradesDto) {
return this.appService.getTrades(dto)
}

@Post('/user')
async addUser(@Body() dto: AddUserDto) {
console.log('dto', dto)
const user = await this.userService.getUserByAddress(dto.address)
if(user) {
throw new BadRequestException('User already exists')
}
const userId = await this.userService.addNewUser(dto);
this.logger.log(`Created new user: address=${dto.address}, id=${userId}`)
return await this.userService.getUserByAddress(dto.address)
}

@Get('/user/:address')
async getUserByAddress(@Param('address') address: string) {
const user = await this.userService.getUserByAddress(address)
if(!user) {
throw new NotFoundException('User not found')
}
return user
}
}
4 changes: 3 additions & 1 deletion src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { typeormConfig } from './config/typeorm';
import {ThrottlerGuard, ThrottlerModule} from "@nestjs/throttler";
import {APP_GUARD} from "@nestjs/core";
import {ScheduleModule} from "@nestjs/schedule";
import { UserService } from './user/user.service';

@Module({
imports: [
Expand All @@ -35,7 +36,8 @@ import {ScheduleModule} from "@nestjs/schedule";
{
provide: APP_GUARD,
useClass: ThrottlerGuard
}
},
UserService
],
})
export class AppModule {}
18 changes: 16 additions & 2 deletions src/app.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {Contract, ContractAbi, EventLog, Web3} from "web3";
import * as TokenFactoryABI from './abi/TokenFactory.json'
import * as TokenABI from './abi/Token.json'
import {Between, DataSource} from "typeorm";
import {IndexerState, Token} from "./entities";
import {IndexerState, Token, UserAccount} from "./entities";
import {AddCommentDto, GetCommentsDto} from "./dto/comment.dto";
import {Comment} from "./entities";
import {GetTokensDto} from "./dto/token.dto";
Expand All @@ -13,6 +13,7 @@ import {Trade, TradeType} from "./entities/trade.entity";
import {Cron, CronExpression} from "@nestjs/schedule";
import * as moment from "moment";
import {GetTradesDto} from "./dto/trade.dto";
import {UserService} from "./user/user.service";

@Injectable()
export class AppService {
Expand All @@ -22,6 +23,7 @@ export class AppService {
private readonly blocksIndexingRange = 1000
constructor(
private configService: ConfigService,
private userService: UserService,
private dataSource: DataSource,
) {
const rpcUrl = configService.get('RPC_URL')
Expand Down Expand Up @@ -70,6 +72,9 @@ export class AppService {
})
this.logger.log(`Set initial blockNumber=${blockNumber}`)
}

await this.userService.addNewUser({ address: '0x98f0c3d42b8dafb1f73d8f105344c6a4434a0109' })
await this.userService.addNewUser({ address: '0x2AB4eF5E937CcC03a9c0eAfC7C00836774B149E0' })
} catch (e) {
this.logger.error(`Failed to bootstrap, exit`, e)
process.exit(1)
Expand Down Expand Up @@ -175,6 +180,14 @@ export class AppService {
const tokenAddress = values['token'] as string
const timestamp = Number(values['timestamp'] as bigint)

const tx = await this.web3.eth.getTransaction(txnHash)
const userAddress = tx.from
const user = await this.dataSource.manager.findOne(UserAccount, {
where: {
address: userAddress.toLowerCase()
}
})

const tokenContract = new this.web3.eth.Contract(TokenABI, tokenAddress);
const name = await tokenContract.methods.name().call() as string
const symbol = await tokenContract.methods.symbol().call() as string
Expand All @@ -186,8 +199,9 @@ export class AppService {
name,
symbol,
timestamp,
user
});
this.logger.log(`New token: address=${tokenAddress}, name=${name}, symbol=${symbol}, txnHash=${txnHash}`);
this.logger.log(`New token: address=${tokenAddress}, name=${name}, symbol=${symbol}, user=${userAddress}, txnHash=${txnHash}`);
}

await this.processTradeEvents(buyEvents, TradeType.buy)
Expand Down
25 changes: 25 additions & 0 deletions src/dto/user.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { ApiProperty } from '@nestjs/swagger';
import {IsString} from 'class-validator';
import {Transform, Type} from "class-transformer";

export class AddUserDto {
@ApiProperty({ type: String, required: true })
@Transform((address) => address.value.trim().toLowerCase())
@Type(() => String)
@IsString()
address: string;
}

export class GetUsersDto {
@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;
}
22 changes: 12 additions & 10 deletions src/entities/token.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ import {
PrimaryGeneratedColumn,
UpdateDateColumn,
ManyToMany,
JoinTable
JoinTable, AfterLoad, AfterInsert, AfterUpdate, OneToOne, ManyToOne
} from 'typeorm';
import { ApiProperty } from '@nestjs/swagger';
import {Comment} from "./comment.entity";
import {UserAccount} from "./user-account.entity";

@Entity({ name: 'tokens' })
export class Token {
Expand Down Expand Up @@ -38,10 +39,18 @@ export class Token {
symbol: string;

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

@OneToMany(() => Comment, (comment) => comment.token, { eager: true })
@ManyToOne(() => UserAccount, (user) => user.tokens, {
eager: true
})
@JoinTable()
user: UserAccount

@OneToMany(() => Comment, (comment) => comment.token, {
eager: true
})
@JoinTable()
comments: Comment[]

Expand All @@ -52,11 +61,4 @@ export class Token {
@ApiProperty()
@UpdateDateColumn({ name: 'updatedAt' })
updatedAt: Date;

// getBlockchainAccounts(): IBlockchainAccount[] {
// return this.blockchainAccounts.map(item => ({
// id: item.id,
// address: item.address,
// }))
// }
}
17 changes: 9 additions & 8 deletions src/entities/user-account.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ import {
PrimaryGeneratedColumn,
UpdateDateColumn,
ManyToMany,
JoinTable
JoinTable, ManyToOne
} from 'typeorm';
import { ApiProperty } from '@nestjs/swagger';
import {Token} from "./token.entity";

@Entity({ name: 'users' })
export class UserAccount {
Expand All @@ -20,18 +21,18 @@ export class UserAccount {
@Column({ unique: true })
address: string;

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

@OneToMany(() => Token, (token) => token.user)
tokens: Token[]

@ApiProperty()
@CreateDateColumn({ name: 'createdAt' })
createdAt: Date;

@ApiProperty()
@UpdateDateColumn({ name: 'updatedAt' })
updatedAt: Date;

// getBlockchainAccounts(): IBlockchainAccount[] {
// return this.blockchainAccounts.map(item => ({
// id: item.id,
// address: item.address,
// }))
// }
}
18 changes: 18 additions & 0 deletions src/user/user.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { UserService } from './user.service';

describe('UserService', () => {
let service: UserService;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [UserService],
}).compile();

service = module.get<UserService>(UserService);
});

it('should be defined', () => {
expect(service).toBeDefined();
});
});
28 changes: 28 additions & 0 deletions src/user/user.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Injectable } from '@nestjs/common';
import {DataSource} from "typeorm";
import {Token, UserAccount} from "../entities";
import {AddUserDto, GetUsersDto} from "../dto/user.dto";

@Injectable()
export class UserService {
constructor(private dataSource: DataSource,) {
}

async addNewUser(dto: AddUserDto) {
const { address } = dto

const data = await this.dataSource.manager.insert(UserAccount, {
address: address.toLowerCase(),
username: address.replaceAll('0x', '').slice(0, 6)
})
return data.identifiers[0].id
}

async getUserByAddress(address: string) {
return await this.dataSource.manager.findOne(UserAccount, {
where: {
address: address.toLowerCase(),
},
})
}
}

0 comments on commit f30f366

Please sign in to comment.