Skip to content

Commit

Permalink
add get all balances endpoint in ccxt format
Browse files Browse the repository at this point in the history
  • Loading branch information
zed-wong committed Dec 13, 2024
1 parent c3f5bbb commit 248a894
Show file tree
Hide file tree
Showing 13 changed files with 86 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<div class="text-xl font-bold">{$_("actions")}</div>

<!-- Actions Section -->
<div class="grid grid-cols-5 gap-4">
<div class="grid grid-cols-2 md:grid-cols-2 xl:grid-cols-5 justify-center items-center gap-4">
{#each items as item}
<div class="stats shadow">
<div class="stat">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script>
import { _ } from "svelte-i18n";

Check failure on line 2 in interface/src/lib/components/admin/rebalance/balance/balanceSimpleCard.svelte

View workflow job for this annotation

GitHub Actions / lint (18.x)

'_' is defined but never used
import { goto } from "$app/navigation";
import emptyToken from '$lib/images/empty-token.svg';
import { findExchangeIconByIdentifier } from "$lib/helpers/helpers";
export let info = {
"key_id": 2,
Expand Down Expand Up @@ -29,20 +30,19 @@
</script>

<div class="tooltip tooltip-top" data-tip={`ID: ${info.key_id}`}>
<button class="text-left stats shadow" on:click={() => {goto(`/manage/rebalance/balances/${info.name}`)}}>
<div class="stat">
<div class="stat-value">{info.name}</div>
<div class="stat-title">
{Object.keys(info.balance.total).length} {$_("assets")}
</div>

<div class="stat-figure text-secondary pl-6">
<button class="stats shadow" on:click={() => {goto(`/manage/rebalance/balances/${info.name}`)}}>
<div class="stat text-left">
<div class="stat-figure text-green-500">
<div class="avatar">
<div class="w-12 rounded-full">
<img src={findExchangeIconByIdentifier(info.exchange)} alt="" />
<div class="mask mask-squircle w-8 h-8">
<img src={findExchangeIconByIdentifier(info.exchange) || emptyToken} alt="" />
</div>
</div>
</div>
<div class="stat-title">
<span class="capitalize">{info.name}</span>
</div>
<div class="stat-value my-1 mr-2">{Object.keys(info.balance.total).length} assets</div>
</div>
</button>
</div>
9 changes: 9 additions & 0 deletions interface/src/lib/helpers/hufi/admin.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { createHash } from "crypto";
import { goto } from "$app/navigation";
import toast from 'svelte-french-toast';
import { HUFI_BACKEND_URL } from "../constants"
import type { AdminPasswordResp } from "$lib/types/hufi/admin"
import { submitted, checked, correct } from "$lib/stores/admin";
Expand Down Expand Up @@ -60,5 +61,13 @@ export const exit = () => {
correct.set(false);
localStorage.removeItem('admin-password')
localStorage.removeItem('admin-access-token')
toast.error('Session expired', {position:'top-center', duration: 2000})
goto('/manage')
}

export const tokenExpired = () => {
correct.set(false);
submitted.set(false);
checked.set(false);
goto('/manage')
}
6 changes: 6 additions & 0 deletions interface/src/lib/helpers/hufi/common.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import { tokenExpired } from "$lib/helpers/hufi/admin";

export const getHeaders = (token: string) => ({
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
});

export const handleApiResponse = async (response: Response) => {
if (response.status === 401) {
tokenExpired();
throw new Error('Unauthorized access - possibly invalid token');
}
if (!response.ok) {
const errorText = await response.text();
throw new Error(`Network response was not ok: ${errorText}`);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script>
import { page } from '$app/stores';
</script>


Expand Down
10 changes: 5 additions & 5 deletions server/src/common/constants/pairs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,13 @@ export const SYMBOL_ASSET_ID_MAP = {
BTC: 'c6d0c728-2624-429b-8e0d-d9d19b6592fa',
ETH: '67b6b3b5-78ce-33c2-b7e2-9e5b24f19b29',
XIN: '9437ebfa-873a-3032-8295-eedb8a3c86c7',
'USDT-ERC20': '4d8c508b-91c5-375b-92b0-ee702ed2dac5',
'USDT@ERC20': '4d8c508b-91c5-375b-92b0-ee702ed2dac5',
DOGE: '6770a1e5-6086-44d5-b60f-545f9d9e8ffd',
UNI: 'a31e847e-ca87-3162-b4d1-322bc552e831',
pUSD: '31d2ea9c-95eb-3355-b65b-ba096853bc18',
EOS: '6cfe566e-4aad-470b-8c9a-2fd35b49c68d',
eETH: 'f51ced0d-c99f-3efd-9e17-7c8e7efc2dab',
'USDT-TRC20': 'b91e18ff-a9ae-3dc7-8679-e935d9a4b34b',
'USDT@TRC20': 'b91e18ff-a9ae-3dc7-8679-e935d9a4b34b',
DOT: '54c61a72-b982-4034-a556-0d99e3c21e39',
HMT: '235d8ced-3d41-3c2f-8368-7dba52cb9868',
WOO: 'b829139c-cdb2-362c-a46d-57c66dce4fcc',
Expand Down Expand Up @@ -92,10 +92,10 @@ export const SYMBOL_ASSET_ID_MAP = {
XLM: '56e63c06-b506-4ec5-885a-4a5ac17b83c1',
ZEN: 'a2c5d22b-62a2-4c13-b3f0-013290dbac60',
'3056.HK': '5c392265-1e05-3520-a25b-2fe9e36510d7',
'USDT-MATIC': '218bc6f4-7927-3f8e-8568-3a3725b74361',
'USDT@MATIC': '218bc6f4-7927-3f8e-8568-3a3725b74361',
NEAR: 'd6ac94f7-c932-4e11-97dd-617867f0669e',
IQ: '336d5d97-329c-330d-8e62-2b7c9ba40ea0',
'USDT-BNB': '94213408-4ee7-3150-a9c4-9c5cce421c78',
'USDT@BNB': '94213408-4ee7-3150-a9c4-9c5cce421c78',
VGX: 'b1375fc0-b5a5-3d62-b06d-567f8dc3c905',
DYDX: 'fd86e3bc-faeb-3f62-ad09-b59d2ebcc59c',
PEOPLE: '1886815e-7dbe-3f43-9602-bb54ea46b254',
Expand All @@ -104,7 +104,7 @@ export const SYMBOL_ASSET_ID_MAP = {
eUSD: '659c407a-0489-30bf-9e6f-84ef25c971c9',
BTT: '47b13785-25e2-3c5c-ac6b-3713e9c31c22',
BSV: '574388fd-b93f-4034-a682-01c2bc095d17',
'USDT-BTC': '815b0b1a-2764-3736-8faa-42d694fa620a',
'USDT@BTC': '815b0b1a-2764-3736-8faa-42d694fa620a',
DAI: '8549b4ad-917c-3461-a646-481adc5d7f7f',
ENS: 'e9521558-81e1-30ec-9a07-9746f397ff69',
AKITA: 'aa189c4c-99ca-39eb-8d96-71a8f6f7218a',
Expand Down
6 changes: 2 additions & 4 deletions server/src/common/helpers/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,8 @@ export const getAssetIDBySymbol = (value: PairsMapValue) => {
};
};

export const getSymbolByAssetID = (
asset_id: SymbolAssetIdMapValue,
): SymbolAssetIdMapKey => {
return SYMBOL_ASSET_ID_MAP[asset_id] || '';
export const getSymbolByAssetID = (asset_id: string): string => {
return ASSET_ID_SYMBOL_MAP[asset_id] || '';
};

export const getRFC3339Timestamp = () => {
Expand Down
2 changes: 2 additions & 0 deletions server/src/modules/admin/admin.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,14 @@ import { AdminSpotController } from './spotData/adminSpot.controller';
import { AdminGrowController } from './growdata/adminGrow.controller';
import { AdminMixinMessageController } from './mixinMessage/adminMixinMessage.controller';
import { MixinMessageModule } from '../mixin/message/message.module';
import { SnapshotsModule } from '../mixin/snapshots/snapshots.module';

@Module({
imports: [
ExchangeInitModule,
GrowdataModule,
SpotdataModule,
SnapshotsModule,
TypeOrmModule.forFeature([
MarketMakingHistory,
ArbitrageHistory,
Expand Down
15 changes: 11 additions & 4 deletions server/src/modules/admin/rebalance/adminRebalance.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,28 @@
import { Injectable } from '@nestjs/common';
import { CustomLogger } from 'src/modules/logger/logger.service';
import { ExchangeService } from 'src/modules/mixin/exchange/exchange.service';
import { SnapshotsService } from 'src/modules/mixin/snapshots/snapshots.service';

@Injectable()
export class AdminRebalanceService {
private readonly logger = new CustomLogger(AdminRebalanceService.name);
constructor(private exchangeService: ExchangeService) {}
constructor(
private exchangeService: ExchangeService,
private snapshotService: SnapshotsService,
) {}

// 1. Get all balances
async getAllBalances() {
this.logger.log('Getting all balances');
return await this.exchangeService.getAllAPIKeysBalance();
this.logger.debug('Getting all balances');
const snapshot = await this.snapshotService.getAllAssetBalancesCCXT();
const exchange = await this.exchangeService.getAllAPIKeysBalance();
exchange.push(snapshot);
return exchange;
}

// 2. Get balance by key label
async getBalanceByKeyLabel(keyLabel: string) {
this.logger.log(`Getting balance for key label: ${keyLabel}`);
this.logger.debug(`Getting balance for key label: ${keyLabel}`);
return await this.exchangeService.getBalanceByKeyLabel(keyLabel);
}

Expand Down
8 changes: 4 additions & 4 deletions server/src/modules/admin/spotData/adminSpot.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,26 +19,26 @@ export class AdminSpotController {
constructor(private readonly adminSpotService: AdminSpotService) {}

// Spot trading pair endpoints
@Post('spot/trading-pair/add')
@Post('trading-pair/add')
@ApiOperation({ summary: 'Add a new spot trading pair' })
@ApiBody({ type: SpotdataTradingPairDto })
async addTradingPair(@Body() pairDto: SpotdataTradingPairDto) {
return this.adminSpotService.addTradingPair(pairDto);
}

@Delete('spot/trading-pair/remove/:id')
@Delete('trading-pair/remove/:id')
@ApiOperation({ summary: 'Remove a spot trading pair' })
async removeTradingPair(@Param('id') id: string) {
return this.adminSpotService.removeTradingPair(id);
}

@Delete('spot/trading-pair/remove-all')
@Delete('trading-pair/remove-all')
@ApiOperation({ summary: 'Remove all spot trading pairs' })
async removeAllTradingPairs() {
return this.adminSpotService.removeAllTradingPairs();
}

@Post('spot/trading-pair/update/:id')
@Post('trading-pair/update/:id')
@ApiOperation({ summary: 'Update a spot trading pair' })
@ApiBody({ type: SpotdataTradingPairDto })
async updateTradingPair(
Expand Down
2 changes: 1 addition & 1 deletion server/src/modules/auth/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export class AuthService {
}

const payload = { username: 'admin' };
return this.jwtService.sign(payload, { expiresIn: '120m' });
return this.jwtService.sign(payload, { expiresIn: '1d' });
}

/**
Expand Down
2 changes: 1 addition & 1 deletion server/src/modules/campaign/campaign.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export class CampaignService {
this.logger.log('Finished getting HuFi campaigns');
return data;
} catch (error) {
this.logger.error('Error getting HuFi campaigns', error.message);
this.logger.error(`Error getting HuFi campaigns: ${error.message}`);
return [];
}
}
Expand Down
38 changes: 33 additions & 5 deletions server/src/modules/mixin/snapshots/snapshots.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
decodeMarketMakingCreateMemo,
decodeSimplyGrowCreateMemo,
} from 'src/common/helpers/mixin/memo';
import { getSymbolByAssetID } from 'src/common/helpers/utils';

@Injectable()
export class SnapshotsService {
Expand Down Expand Up @@ -387,25 +388,52 @@ export class SnapshotsService {
return acc;
}, {});

// Calculate total balance for each asset
const assetBalances = Object.entries(groupedByAssetId).reduce(
// Calculate total balance for each asset and map to symbols
const symbolBalances = Object.entries(groupedByAssetId).reduce(
(acc, [assetId, outputs]) => {
// @ts-expect-error types
const totalBalance = getTotalBalanceFromOutputs(outputs);
acc[assetId] = totalBalance.toString(); // Assuming you want the balance as a string
const symbol = getSymbolByAssetID(assetId); // Convert asset ID to symbol
if (symbol) {
acc[symbol] = totalBalance.toString(); // Assuming you want the balance as a string
} else {
this.logger.warn(`Symbol not found for asset ID: ${assetId}`);
}
return acc;
},
{},
);

// map of AssetID: Balance
return assetBalances;
// map of Symbol: Balance
return symbolBalances;
} catch (error) {
this.logger.error(`Error fetching asset balances: ${error.message}`);
throw error;
}
}

async getAllAssetBalancesCCXT() {
try {
const symbolBalances = await this.getAllAssetBalances();

const formattedBalances = {
balance: {
free: symbolBalances,
total: symbolBalances,
used: {},
},
exchange: 'mixin',
key_id: 0,
name: 'Mixin',
};

return formattedBalances;
} catch (error) {
this.logger.error(`Error formatting balances to CCXT: ${error.message}`);
throw error;
}
}

async getAssetBalance(asset_id: SymbolAssetIdMapValue): Promise<string> {
try {
return await this.client.utxo.safeAssetBalance({ asset: asset_id });
Expand Down

0 comments on commit 248a894

Please sign in to comment.