Skip to content

Commit

Permalink
add checking your top binance tokens using discord command
Browse files Browse the repository at this point in the history
  • Loading branch information
radekm2000 committed Jun 9, 2024
1 parent 5994355 commit b603a29
Show file tree
Hide file tree
Showing 14 changed files with 374 additions and 19 deletions.
2 changes: 2 additions & 0 deletions server/ecommerce/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { DiscordGuildModule } from './discord-guild/discord-guild.module';
import { EventEmitterModule } from '@nestjs/event-emitter';
import { UserSyncModule } from './user-sync/user-sync.module';
import { ScheduleModule } from '@nestjs/schedule';
import { BinanceModule } from './binance/binance.module';

@Module({
imports: [
Expand All @@ -49,6 +50,7 @@ import { ScheduleModule } from '@nestjs/schedule';
EventEmitterModule.forRoot(),
UserSyncModule,
ScheduleModule.forRoot(),
BinanceModule,
],
controllers: [AppController],
providers: [AppService],
Expand Down
1 change: 0 additions & 1 deletion server/ecommerce/src/auth/auth.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ export class AuthController {
@Get('discord/redirect')
async disordAuthRedirect(@Req() request: Request, @Res() response: Response) {
const user = request.user as DiscordProfile;
console.log(user);
const refreshToken = await this.authService.generateRefreshTokenFor(
Number(user.id),
);
Expand Down
44 changes: 44 additions & 0 deletions server/ecommerce/src/binance/binance-client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { Logger } from '@nestjs/common';
import Binance from 'binance-api-node';
import 'dotenv/config';
import { TickerPrice, TickerPriceType } from 'src/utils/dtos/binance.dto';

type Config = {
BINANCE_API_KEY: string;
BINANCE_SECRET_KEY: string;
};

export class BinanceClient {
private client: any;
private logger: Logger;

constructor(config: Config) {
this.client = Binance({
apiKey: config.BINANCE_API_KEY,
apiSecret: config.BINANCE_SECRET_KEY,
});
this.logger = new Logger(BinanceClient.name);
}

public getBinanceAccountInfo = async () => {
return await this.client.accountInfo();
};

public getSymbolTickerPrice = async (
symbol: string,
): Promise<TickerPriceType> => {
try {
const tickerResponse: TickerPriceType = await this.client.prices({
symbol,
});

const ticker: TickerPrice = {
symbol: symbol,
price: tickerResponse[symbol],
};
return ticker;
} catch (error) {
this.logger.error(`Error when getting price for symbol ${symbol}`);
}
};
}
13 changes: 13 additions & 0 deletions server/ecommerce/src/binance/binance.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Controller, Get, UsePipes } from '@nestjs/common';
import { BinanceService } from './binance.service';
import { BinanceAccountInfo } from 'src/utils/dtos/binance.dto';

@Controller('binance')
export class BinanceController {
constructor(private readonly binanceService: BinanceService) {}

@Get('/accountInfo')
public async getBinanceAccountInfo() {
return await this.binanceService.getAccountInfo(3);
}
}
10 changes: 10 additions & 0 deletions server/ecommerce/src/binance/binance.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Module } from '@nestjs/common';
import { BinanceService } from './binance.service';
import { BinanceController } from './binance.controller';

@Module({
providers: [BinanceService],
exports: [BinanceService],
controllers: [BinanceController],
})
export class BinanceModule {}
147 changes: 147 additions & 0 deletions server/ecommerce/src/binance/binance.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
import 'dotenv/config';
import { Injectable, Logger } from '@nestjs/common';
import { BinanceClient } from './binance-client';
import {
BinanceAccountInfo,
BinanceAccountInfoSchema,
BinanceBalance,
BinanceBalanceWithTotalValueAndSymbol,
TickerPriceType,
} from 'src/utils/dtos/binance.dto';

const CURRENCY_FOR_TOKEN_PRICES = 'USDT';

@Injectable()
export class BinanceService {
private logger: Logger;
private binanceClient: BinanceClient;

constructor() {
this.logger = new Logger(BinanceService.name);
this.binanceClient = new BinanceClient({
BINANCE_API_KEY: process.env.BINANCE_API_KEY ?? '',
BINANCE_SECRET_KEY: process.env.BINANCE_SECRET_KEY ?? '',
});
}

public getAccountInfo = async (
numberOfTopBalances: number,
currencyName?: string,
): Promise<BinanceBalanceWithTotalValueAndSymbol[]> => {
try {
const accountInfo = await this.binanceClient.getBinanceAccountInfo();
const parseResult = BinanceAccountInfoSchema.safeParse(accountInfo);
if (parseResult.success) {
const topBalances = this.mapBinanceAccountInfo(
parseResult.data,
numberOfTopBalances,
currencyName,
);
return topBalances;
} else if (parseResult.success === false) {
this.logger.error(
`Validation errors when parsing account info ${parseResult.error.errors}`,
);
}
} catch (error) {
this.logger.error(
`Error when parsing binance account info ${error.message}`,
);
}
};

private mapBinanceAccountInfo = async (
account: BinanceAccountInfo,
numberOfTopBalances: number,
currencyName?: string,
) => {
const accountBalancesWithMinValue = account.balances.filter(
(balance) => parseFloat(balance.free) >= 0.1,
);

const balancesWithTotalValueCalculated: BinanceBalanceWithTotalValueAndSymbol[] =
await this.addTotalValueAndCurrencySymbolToBalances(
accountBalancesWithMinValue,
currencyName,
);

const sortedBalances = this.sortBalancesByTotalValue(
balancesWithTotalValueCalculated,
);

const revertedBalances = this.revertBalances(sortedBalances);

const topBalances = revertedBalances.slice(0, numberOfTopBalances);

return topBalances;
};

private sortBalancesByTotalValue = (
balances: BinanceBalanceWithTotalValueAndSymbol[],
) => {
return balances.sort(
(a, b) => parseFloat(b.totalValue) - parseFloat(a.totalValue),
);
};

private revertBalances = (
balances: BinanceBalanceWithTotalValueAndSymbol[],
) => {
return balances.map((balance) => ({
asset: balance.asset,
free: balance.free,
locked: balance.locked,
symbol: balance.symbol,
totalValue: balance.totalValue,
}));
};

private addTotalValueAndCurrencySymbolToBalances = async (
balances: BinanceBalance[],
currencyName?: string,
) => {
return await Promise.all(
balances.map(async (balance) => {
const symbol = currencyName
? `${balance.asset}${currencyName.toUpperCase()}`
: `${balance.asset}${CURRENCY_FOR_TOKEN_PRICES}`;
if (balance.asset === CURRENCY_FOR_TOKEN_PRICES) {
return {
asset: balance.asset,
free: balance.free,
locked: balance.locked,
symbol: balance.asset,
totalValue: balance.free,
};
}
const tickerResponse =
await this.binanceClient.getSymbolTickerPrice(symbol);

const totalValue = this.calculateTotalSymbolValue(
balance,
tickerResponse,
);
return {
asset: balance.asset,
free: balance.free,
locked: balance.locked,
symbol: symbol,
totalValue: totalValue ?? 'Unavailable',
};
}),
);
};

private calculateTotalSymbolValue = (
balance: BinanceBalance,
tickerResponse: TickerPriceType,
) => {
if (!tickerResponse) {
return '';
}
const price = tickerResponse.price;
const tokenAmount = balance.free;

return (parseFloat(price) * parseFloat(tokenAmount)).toFixed(4);
};
}
6 changes: 2 additions & 4 deletions server/ecommerce/src/discord-bot/discord-bot.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,14 @@ import { Avatar } from 'src/utils/entities/avatar.entity';
import { ProductsService } from 'src/products/products.service';
import { Image } from 'src/utils/entities/image.entity';
import { Product } from 'src/utils/entities/product.entity';
import { ProductNotificationService } from 'src/product-notification/product-notification.service';
import { ProductNotification } from 'src/utils/entities/product-notification.entity';
import { FollowersService } from 'src/followers/followers.service';
import { DiscordNotificationsService } from 'src/discord-notifications/discord-notifications.service';
import { IProductsService } from 'src/spi/products';
import { DiscordGuildModule } from 'src/discord-guild/discord-guild.module';
import { DiscordGuildService } from 'src/discord-guild/discord-guild.service';
import { DiscordNotificationsModule } from 'src/discord-notifications/discord-notifications.module';
import { ProductsModule } from 'src/products/products.module';
import { ItemNotifierModule } from './src/commands/notifiers/item-notifier.module';
import { ProductNotificationModule } from 'src/product-notification/product-notification.module';
import { BinanceModule } from 'src/binance/binance.module';

@Module({
controllers: [DiscordBotController],
Expand All @@ -45,6 +42,7 @@ import { ProductNotificationModule } from 'src/product-notification/product-noti
ItemNotifierModule,
DiscordNotificationsModule,
ProductNotificationModule,
BinanceModule,
],
exports: [DiscordBotService],
})
Expand Down
4 changes: 4 additions & 0 deletions server/ecommerce/src/discord-bot/discord-bot.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import { FollowersService } from 'src/followers/followers.service';
import { StartTrackingCommand } from './src/commands/trackers/start-tracking';
import { StopTrackingCommand } from './src/commands/trackers/stop-tracking';
import { IProductsService } from 'src/spi/products';
import { BinanceAccountTokenInfo } from './src/commands/binance-account-token-info';
import { BinanceService } from 'src/binance/binance.service';

@Injectable()
export class DiscordBotService implements OnModuleInit {
Expand All @@ -31,6 +33,7 @@ export class DiscordBotService implements OnModuleInit {
private userService: UsersService,
@Inject(IProductsService) private productsService: IProductsService,
private followersService: FollowersService,
private binanceService: BinanceService,
) {
this.botToken = process.env.DISCORD_BOT_TOKEN;
this.botApplicationId = process.env.DISCORD_CLIENT_ID;
Expand Down Expand Up @@ -70,6 +73,7 @@ export class DiscordBotService implements OnModuleInit {
followersService: this.followersService,
usersService: this.userService,
}),
new BinanceAccountTokenInfo({ binanceService: this.binanceService }),
],
});
}
Expand Down
Loading

0 comments on commit b603a29

Please sign in to comment.