diff --git a/package-lock.json b/package-lock.json index ded870b2a..7a22c3ec0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,7 +44,7 @@ "stream-browserify": "^3.0.0", "stream-http": "^3.2.0", "tslib": "^2.3.0", - "ununifi-client": "^0.46.4", + "ununifi-client": "^0.46.5-dev2", "zone.js": "~0.11.4" }, "devDependencies": { @@ -40076,9 +40076,9 @@ } }, "node_modules/ununifi-client": { - "version": "0.46.4", - "resolved": "https://registry.npmjs.org/ununifi-client/-/ununifi-client-0.46.4.tgz", - "integrity": "sha512-oCPlLAWbMra5LhOYIJtTyA0LfH4zI2NPWcvBDgKvD25M7Ad0fx5nvrVE2vvwAqY//jxx0TBR8SSFBHNdCYPIZw==", + "version": "0.46.5-dev2", + "resolved": "https://registry.npmjs.org/ununifi-client/-/ununifi-client-0.46.5-dev2.tgz", + "integrity": "sha512-T9evt/03cUxl/5R6QJEJ0eUIssE1CK1+cZd2mrKfV7Cj0GVi8Yj00vCjO2TEURWXd35vIghtTujd8mpcfWg6kQ==", "dependencies": { "axios": "^0.21.1", "protobufjs": "^6.11.2" @@ -71540,9 +71540,9 @@ "dev": true }, "ununifi-client": { - "version": "0.46.4", - "resolved": "https://registry.npmjs.org/ununifi-client/-/ununifi-client-0.46.4.tgz", - "integrity": "sha512-oCPlLAWbMra5LhOYIJtTyA0LfH4zI2NPWcvBDgKvD25M7Ad0fx5nvrVE2vvwAqY//jxx0TBR8SSFBHNdCYPIZw==", + "version": "0.46.5-dev2", + "resolved": "https://registry.npmjs.org/ununifi-client/-/ununifi-client-0.46.5-dev2.tgz", + "integrity": "sha512-T9evt/03cUxl/5R6QJEJ0eUIssE1CK1+cZd2mrKfV7Cj0GVi8Yj00vCjO2TEURWXd35vIghtTujd8mpcfWg6kQ==", "requires": { "axios": "^0.21.1", "protobufjs": "^6.11.2" diff --git a/package.json b/package.json index de3d3ac7e..d757fc45c 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ "stream-browserify": "^3.0.0", "stream-http": "^3.2.0", "tslib": "^2.3.0", - "ununifi-client": "^0.46.4", + "ununifi-client": "^0.46.5-dev2", "zone.js": "~0.11.4" }, "devDependencies": { diff --git a/projects/portal/src/app/models/copy-trading/copy-trading.application.service.ts b/projects/portal/src/app/models/copy-trading/copy-trading.application.service.ts new file mode 100644 index 000000000..ff155a4f3 --- /dev/null +++ b/projects/portal/src/app/models/copy-trading/copy-trading.application.service.ts @@ -0,0 +1,270 @@ +import { + TxConfirmDialogComponent, + TxConfirmDialogData, +} from '../../views/dialogs/txs/tx-confirm/tx-confirm-dialog.component'; +import { TxCommonApplicationService } from '../cosmos/tx-common.application.service'; +import { CopyTradingService } from './copy-trading.service'; +import { Dialog } from '@angular/cdk/dialog'; +import { Injectable } from '@angular/core'; + +@Injectable({ + providedIn: 'root', +}) +export class CopyTradingApplicationService { + constructor( + private readonly dialog: Dialog, + private readonly copyTradingService: CopyTradingService, + private readonly txCommonApplication: TxCommonApplicationService, + ) {} + + async createExemplaryTrader(name: string, description: string, profitCommissionRate: number) { + const prerequisiteData = await this.txCommonApplication.getPrerequisiteData(); + if (!prerequisiteData) { + return; + } + const { address, publicKey, account, currentCosmosWallet, minimumGasPrice } = prerequisiteData; + + const msg = this.copyTradingService.buildMsgCreateExemplaryTrader( + address, + name, + description, + profitCommissionRate, + ); + + const simulationResult = await this.txCommonApplication.simulate( + msg, + publicKey, + account, + minimumGasPrice, + ); + if (!simulationResult) { + return; + } + const { gas, fee } = simulationResult; + + if (!(await this.txCommonApplication.confirmFeeIfUnUniFiWallet(currentCosmosWallet, fee))) { + return; + } + + const txHash = await this.txCommonApplication.broadcast( + msg, + currentCosmosWallet, + publicKey, + account, + gas, + fee, + ); + if (!txHash) { + return; + } + + if (txHash) { + await this.dialog + .open(TxConfirmDialogComponent, { + data: { txHash: txHash, msg: 'Successfully registered as an Exemplary Trader.' }, + }) + .closed.toPromise(); + location.reload(); + } + } + + async updateExemplaryTrader(name: string, description: string, profitCommissionRate: number) { + const prerequisiteData = await this.txCommonApplication.getPrerequisiteData(); + if (!prerequisiteData) { + return; + } + const { address, publicKey, account, currentCosmosWallet, minimumGasPrice } = prerequisiteData; + + const msg = this.copyTradingService.buildMsgUpdateExemplaryTrader( + address, + name, + description, + profitCommissionRate, + ); + + const simulationResult = await this.txCommonApplication.simulate( + msg, + publicKey, + account, + minimumGasPrice, + ); + if (!simulationResult) { + return; + } + const { gas, fee } = simulationResult; + + if (!(await this.txCommonApplication.confirmFeeIfUnUniFiWallet(currentCosmosWallet, fee))) { + return; + } + + const txHash = await this.txCommonApplication.broadcast( + msg, + currentCosmosWallet, + publicKey, + account, + gas, + fee, + ); + if (!txHash) { + return; + } + + if (txHash) { + await this.dialog + .open(TxConfirmDialogComponent, { + data: { txHash: txHash, msg: 'Successfully updated your Exemplary Trader.' }, + }) + .closed.toPromise(); + location.reload(); + } + } + + async deleteExemplaryTrader() { + const prerequisiteData = await this.txCommonApplication.getPrerequisiteData(); + if (!prerequisiteData) { + return; + } + const { address, publicKey, account, currentCosmosWallet, minimumGasPrice } = prerequisiteData; + + const msg = this.copyTradingService.buildMsgDeleteExemplaryTrader(address); + + const simulationResult = await this.txCommonApplication.simulate( + msg, + publicKey, + account, + minimumGasPrice, + ); + if (!simulationResult) { + return; + } + const { gas, fee } = simulationResult; + + if (!(await this.txCommonApplication.confirmFeeIfUnUniFiWallet(currentCosmosWallet, fee))) { + return; + } + + const txHash = await this.txCommonApplication.broadcast( + msg, + currentCosmosWallet, + publicKey, + account, + gas, + fee, + ); + if (!txHash) { + return; + } + + if (txHash) { + await this.dialog + .open(TxConfirmDialogComponent, { + data: { txHash: txHash, msg: 'Successfully deleted your Exemplary Trader.' }, + }) + .closed.toPromise(); + location.reload(); + } + } + + async createTracing( + exemplaryTrader: string, + sizeCoef: number, + leverageCoef: number, + reverse: boolean, + ) { + const prerequisiteData = await this.txCommonApplication.getPrerequisiteData(); + if (!prerequisiteData) { + return; + } + const { address, publicKey, account, currentCosmosWallet, minimumGasPrice } = prerequisiteData; + + const msg = this.copyTradingService.buildMsgCreateTracing( + address, + exemplaryTrader, + sizeCoef, + leverageCoef, + reverse, + ); + + const simulationResult = await this.txCommonApplication.simulate( + msg, + publicKey, + account, + minimumGasPrice, + ); + if (!simulationResult) { + return; + } + const { gas, fee } = simulationResult; + + if (!(await this.txCommonApplication.confirmFeeIfUnUniFiWallet(currentCosmosWallet, fee))) { + return; + } + + const txHash = await this.txCommonApplication.broadcast( + msg, + currentCosmosWallet, + publicKey, + account, + gas, + fee, + ); + if (!txHash) { + return; + } + + if (txHash) { + await this.dialog + .open(TxConfirmDialogComponent, { + data: { txHash: txHash, msg: 'Successfully create tracing the Exemplary Trader.' }, + }) + .closed.toPromise(); + location.reload(); + } + } + + async deleteTracing() { + const prerequisiteData = await this.txCommonApplication.getPrerequisiteData(); + if (!prerequisiteData) { + return; + } + const { address, publicKey, account, currentCosmosWallet, minimumGasPrice } = prerequisiteData; + + const msg = this.copyTradingService.buildMsgDeleteTracing(address); + + const simulationResult = await this.txCommonApplication.simulate( + msg, + publicKey, + account, + minimumGasPrice, + ); + if (!simulationResult) { + return; + } + const { gas, fee } = simulationResult; + + if (!(await this.txCommonApplication.confirmFeeIfUnUniFiWallet(currentCosmosWallet, fee))) { + return; + } + + const txHash = await this.txCommonApplication.broadcast( + msg, + currentCosmosWallet, + publicKey, + account, + gas, + fee, + ); + if (!txHash) { + return; + } + + if (txHash) { + await this.dialog + .open(TxConfirmDialogComponent, { + data: { txHash: txHash, msg: 'Successfully create tracing the Exemplary Trader.' }, + }) + .closed.toPromise(); + location.reload(); + } + } +} diff --git a/projects/portal/src/app/models/copy-trading/copy-trading.model.ts b/projects/portal/src/app/models/copy-trading/copy-trading.model.ts new file mode 100644 index 000000000..0b2dfb7db --- /dev/null +++ b/projects/portal/src/app/models/copy-trading/copy-trading.model.ts @@ -0,0 +1,18 @@ +export type CreateExemplaryTraderRequest = { + name: string; + description: string; + profitCommissionRate: number; +}; + +export type UpdateExemplaryTraderRequest = { + name: string; + description: string; + profitCommissionRate: number; +}; + +export type CreateTracingRequest = { + exemplaryTrader: string; + sizeCoef: number; + leverageCoef: number; + reverse: boolean; +}; diff --git a/projects/portal/src/app/models/copy-trading/copy-trading.query.service.ts b/projects/portal/src/app/models/copy-trading/copy-trading.query.service.ts new file mode 100644 index 000000000..a66b6414e --- /dev/null +++ b/projects/portal/src/app/models/copy-trading/copy-trading.query.service.ts @@ -0,0 +1,58 @@ +import { CosmosSDKService } from '../cosmos-sdk.service'; +import { Injectable } from '@angular/core'; +import { CosmosSDK } from '@cosmos-client/core/cjs/sdk'; +import { Observable } from 'rxjs'; +import { map, mergeMap, pluck } from 'rxjs/operators'; +import ununificlient from 'ununifi-client'; +import { + ExemplaryTraderAll200ResponseExemplaryTraderInner, + ExemplaryTraderTracing200ResponseTracingInner, +} from 'ununifi-client/esm/openapi'; + +@Injectable({ providedIn: 'root' }) +export class CopyTradingQueryService { + private restSdk$: Observable; + + constructor(private cosmosSDK: CosmosSDKService) { + this.restSdk$ = this.cosmosSDK.sdk$.pipe(pluck('rest')); + } + + listExemplaryTraders$(): Observable { + return this.restSdk$.pipe( + mergeMap((sdk) => ununificlient.rest.copyTrading.exemplaryTraderAll(sdk)), + map((res) => res.data.exemplaryTrader!), + ); + } + + getExemplaryTrader$( + address: string, + ): Observable { + return this.restSdk$.pipe( + mergeMap((sdk) => ununificlient.rest.copyTrading.exemplaryTrader(sdk, address)), + map((res) => res.data.exemplaryTrader!), + ); + } + + listTracingsExemplaryTrader$( + address: string, + ): Observable { + return this.restSdk$.pipe( + mergeMap((sdk) => ununificlient.rest.copyTrading.exemplaryTraderTracing(sdk, address)), + map((res) => res.data.tracing!), + ); + } + + listAllTracings$(): Observable { + return this.restSdk$.pipe( + mergeMap((sdk) => ununificlient.rest.copyTrading.tracingAll(sdk)), + map((res) => res.data.tracing!), + ); + } + + getTracing$(address: string): Observable { + return this.restSdk$.pipe( + mergeMap((sdk) => ununificlient.rest.copyTrading.tracing(sdk, address)), + map((res) => res.data.tracing!), + ); + } +} diff --git a/projects/portal/src/app/models/copy-trading/copy-trading.service.ts b/projects/portal/src/app/models/copy-trading/copy-trading.service.ts new file mode 100644 index 000000000..8cd83bcad --- /dev/null +++ b/projects/portal/src/app/models/copy-trading/copy-trading.service.ts @@ -0,0 +1,78 @@ +import { TxCommonService } from '../cosmos/tx-common.service'; +import { Injectable } from '@angular/core'; +import ununificlient from 'ununifi-client'; + +@Injectable({ + providedIn: 'root', +}) +export class CopyTradingService { + constructor(private readonly txCommon: TxCommonService) {} + + buildMsgCreateExemplaryTrader( + sender: string, + name: string, + description: string, + profitCommissionRate: number, + ) { + const decProfitCommissionRate = this.txCommon.numberToDecString(profitCommissionRate); + const msgCreateExemplaryTrader = + new ununificlient.proto.ununifi.copytrading.MsgCreateExemplaryTrader({ + sender, + name, + description, + profit_commission_rate: decProfitCommissionRate, + }); + return msgCreateExemplaryTrader; + } + + buildMsgUpdateExemplaryTrader( + sender: string, + name: string, + description: string, + profitCommissionRate: number, + ) { + const decProfitCommissionRate = this.txCommon.numberToDecString(profitCommissionRate); + const msgUpdateExemplaryTrader = + new ununificlient.proto.ununifi.copytrading.MsgUpdateExemplaryTrader({ + sender, + name, + description, + profit_commission_rate: decProfitCommissionRate, + }); + return msgUpdateExemplaryTrader; + } + + buildMsgDeleteExemplaryTrader(sender: string) { + const msgDeleteExemplaryTrader = + new ununificlient.proto.ununifi.copytrading.MsgDeleteExemplaryTrader({ + sender, + }); + return msgDeleteExemplaryTrader; + } + + buildMsgCreateTracing( + sender: string, + exemplaryTrader: string, + sizeCoef: number, + leverageCoef: number, + reverse: boolean, + ) { + const decSizeCoef = this.txCommon.numberToDecString(sizeCoef); + const decLeverageCoef = this.txCommon.numberToDecString(leverageCoef); + const msgCreateTracing = new ununificlient.proto.ununifi.copytrading.MsgCreateTracing({ + sender, + exemplary_trader: exemplaryTrader, + size_coefficient: decSizeCoef, + leverage_coefficient: decLeverageCoef, + reverse, + }); + return msgCreateTracing; + } + + buildMsgDeleteTracing(sender: string) { + const msgDeleteTracing = new ununificlient.proto.ununifi.copytrading.MsgDeleteTracing({ + sender, + }); + return msgDeleteTracing; + } +} diff --git a/projects/portal/src/app/models/derivatives/derivatives.application.service.ts b/projects/portal/src/app/models/derivatives/derivatives.application.service.ts index 9a6fa8608..6ca723957 100644 --- a/projects/portal/src/app/models/derivatives/derivatives.application.service.ts +++ b/projects/portal/src/app/models/derivatives/derivatives.application.service.ts @@ -172,13 +172,7 @@ export class DerivativesApplicationService { .toPromise(); const perpetualFuturesPositionInstance = - this.derivativesService.buildPerpetualFuturesPositionInstance( - baseSymbol, - positionType, - size * 10 ** 12, - leverage, - symbolMetadataMap, - ); + this.derivativesService.buildPerpetualFuturesPositionInstance(positionType, size, leverage); const positionInstance: cosmosclient.proto.google.protobuf.IAny = cosmosclient.codec.instanceToProtoAny(perpetualFuturesPositionInstance); diff --git a/projects/portal/src/app/models/derivatives/derivatives.query.service.ts b/projects/portal/src/app/models/derivatives/derivatives.query.service.ts index 1216b0389..ee458b060 100644 --- a/projects/portal/src/app/models/derivatives/derivatives.query.service.ts +++ b/projects/portal/src/app/models/derivatives/derivatives.query.service.ts @@ -2,9 +2,8 @@ import { CosmosSDKService } from '../cosmos-sdk.service'; import { Injectable } from '@angular/core'; import cosmosclient from '@cosmos-client/core'; import { CosmosSDK } from '@cosmos-client/core/cjs/sdk'; -import { AccAddress } from '@cosmos-client/core/cjs/types'; -import { Observable, zip } from 'rxjs'; -import { filter, map, mergeMap, pluck } from 'rxjs/operators'; +import { Observable } from 'rxjs'; +import { map, mergeMap, pluck } from 'rxjs/operators'; import ununificlient from 'ununifi-client'; import { AllPositions200ResponsePositionsInner, diff --git a/projects/portal/src/app/models/derivatives/derivatives.service.ts b/projects/portal/src/app/models/derivatives/derivatives.service.ts index 14fa421cf..f8ff026f5 100644 --- a/projects/portal/src/app/models/derivatives/derivatives.service.ts +++ b/projects/portal/src/app/models/derivatives/derivatives.service.ts @@ -1,5 +1,6 @@ import { CosmosSDKService } from '../cosmos-sdk.service'; import { BankService } from '../cosmos/bank.service'; +import { TxCommonService } from '../cosmos/tx-common.service'; import { Injectable } from '@angular/core'; import cosmosclient from '@cosmos-client/core'; import ununificlient from 'ununifi-client'; @@ -10,6 +11,7 @@ import ununificlient from 'ununifi-client'; export class DerivativesService { constructor( private readonly cosmosSDK: CosmosSDKService, + private readonly txCommonService: TxCommonService, private readonly bankService: BankService, ) {} @@ -57,7 +59,7 @@ export class DerivativesService { )[0]; const msgMintLiquidityProviderToken = - new ununificlient.proto.ununifi.derivatives.MsgMintLiquidityProviderToken({ + new ununificlient.proto.ununifi.derivatives.MsgDepositToPool({ sender: senderAddress, amount: coin, }); @@ -79,30 +81,23 @@ export class DerivativesService { const redeemDenom = symbolMetadataMap?.[redeemSymbol].base; const msgMintLiquidityProviderToken = - new ununificlient.proto.ununifi.derivatives.MsgBurnLiquidityProviderToken({ + new ununificlient.proto.ununifi.derivatives.MsgWithdrawFromPool({ sender: senderAddress, - amount: coin.amount, + lpt_amount: coin.amount, redeem_denom: redeemDenom, }); return msgMintLiquidityProviderToken; } buildPerpetualFuturesPositionInstance( - baseSymbol: string, positionType: ununificlient.proto.ununifi.derivatives.PositionType, size: number, leverage: number, - symbolMetadataMap: { [symbol: string]: cosmosclient.proto.cosmos.bank.v1beta1.IMetadata }, ) { - const position = this.bankService.convertSymbolAmountMapToCoins( - { [baseSymbol]: size }, - symbolMetadataMap, - )[0]; - const perpetualFuturesPositionInstance = new ununificlient.proto.ununifi.derivatives.PerpetualFuturesPositionInstance({ position_type: positionType, - size: position.amount, + size: this.txCommonService.numberToDecString(size), leverage: Math.floor(leverage), }); return perpetualFuturesPositionInstance; diff --git a/projects/portal/src/app/models/nft-pawnshops/nft-pawnshop.query.service.ts b/projects/portal/src/app/models/nft-pawnshops/nft-pawnshop.query.service.ts index f3822964e..7e670742e 100644 --- a/projects/portal/src/app/models/nft-pawnshops/nft-pawnshop.query.service.ts +++ b/projects/portal/src/app/models/nft-pawnshops/nft-pawnshop.query.service.ts @@ -12,6 +12,7 @@ import { Liquidation200ResponseLiquidations, ListedClass200Response, ListedNfts200ResponseListingsInner, + ListedNfts200ResponseListingsInnerListing, Loan200Response, Loans200ResponseLoansInner, NftmarketParams200ResponseParams, @@ -31,14 +32,20 @@ export class NftPawnshopQueryService { ); } - getNftListing$(classID: string, nftID: string): Observable { + getNftListing$( + classID: string, + nftID: string, + ): Observable { return this.restSdk$.pipe( mergeMap((sdk) => ununifi.rest.nftmarket.nftListing(sdk, classID, nftID)), map((res) => res.data.listing!), ); } - async getNftListing(classID: string, nftID: string): Promise { + async getNftListing( + classID: string, + nftID: string, + ): Promise { const sdk = await this.cosmosSDK.sdk().then((sdk) => sdk.rest); const res = await ununifi.rest.nftmarket.nftListing(sdk, classID, nftID); return res.data.listing!; diff --git a/projects/portal/src/app/pages/apps/app-derivatives/app-derivatives-routing.module.ts b/projects/portal/src/app/pages/apps/app-derivatives/app-derivatives-routing.module.ts index 89b93ac01..bc92e39c6 100644 --- a/projects/portal/src/app/pages/apps/app-derivatives/app-derivatives-routing.module.ts +++ b/projects/portal/src/app/pages/apps/app-derivatives/app-derivatives-routing.module.ts @@ -9,6 +9,12 @@ const routes: Routes = [ loadChildren: () => import('../../derivatives/derivatives.module').then((m) => m.AppDerivativesModule), }, + { + path: 'copy-trading', + component: AppDerivativesComponent, + loadChildren: () => + import('../../copy-trading/copy-trading.module').then((m) => m.AppCopyTradingModule), + }, ]; @NgModule({ diff --git a/projects/portal/src/app/pages/copy-trading/copy-trading-routing.module.ts b/projects/portal/src/app/pages/copy-trading/copy-trading-routing.module.ts new file mode 100644 index 000000000..3c7667f70 --- /dev/null +++ b/projects/portal/src/app/pages/copy-trading/copy-trading-routing.module.ts @@ -0,0 +1,26 @@ +import { CreateComponent } from './traders/create/create.component'; +import { TraderComponent } from './traders/trader/trader.component'; +import { TradersComponent } from './traders/traders.component'; +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +const routes: Routes = [ + { + path: 'traders', + component: TradersComponent, + }, + { + path: 'traders/create', + component: CreateComponent, + }, + { + path: 'traders/:address', + component: TraderComponent, + }, +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule], +}) +export class CopyTradingRoutingModule {} diff --git a/projects/portal/src/app/pages/copy-trading/copy-trading.module.ts b/projects/portal/src/app/pages/copy-trading/copy-trading.module.ts new file mode 100644 index 000000000..4270cc22a --- /dev/null +++ b/projects/portal/src/app/pages/copy-trading/copy-trading.module.ts @@ -0,0 +1,15 @@ +import { CreateModule } from '../../views/copy-trading/traders/create/create.module'; +import { TraderModule } from '../../views/copy-trading/traders/trader/trader.module'; +import { TradersModule } from '../../views/copy-trading/traders/traders.module'; +import { CopyTradingRoutingModule } from './copy-trading-routing.module'; +import { CreateComponent } from './traders/create/create.component'; +import { TraderComponent } from './traders/trader/trader.component'; +import { TradersComponent } from './traders/traders.component'; +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; + +@NgModule({ + declarations: [TradersComponent, TraderComponent, CreateComponent], + imports: [CommonModule, CopyTradingRoutingModule, TradersModule, TraderModule, CreateModule], +}) +export class AppCopyTradingModule {} diff --git a/projects/portal/src/app/pages/copy-trading/traders/create/create.component.css b/projects/portal/src/app/pages/copy-trading/traders/create/create.component.css new file mode 100644 index 000000000..e69de29bb diff --git a/projects/portal/src/app/pages/copy-trading/traders/create/create.component.html b/projects/portal/src/app/pages/copy-trading/traders/create/create.component.html new file mode 100644 index 000000000..d9824c302 --- /dev/null +++ b/projects/portal/src/app/pages/copy-trading/traders/create/create.component.html @@ -0,0 +1,10 @@ + diff --git a/projects/portal/src/app/pages/copy-trading/traders/create/create.component.ts b/projects/portal/src/app/pages/copy-trading/traders/create/create.component.ts new file mode 100644 index 000000000..a3cd7992d --- /dev/null +++ b/projects/portal/src/app/pages/copy-trading/traders/create/create.component.ts @@ -0,0 +1,65 @@ +import { Component, OnInit } from '@angular/core'; +import cosmosclient from '@cosmos-client/core'; +import { CopyTradingApplicationService } from 'projects/portal/src/app/models/copy-trading/copy-trading.application.service'; +import { + CreateExemplaryTraderRequest, + UpdateExemplaryTraderRequest, +} from 'projects/portal/src/app/models/copy-trading/copy-trading.model'; +import { CopyTradingQueryService } from 'projects/portal/src/app/models/copy-trading/copy-trading.query.service'; +import { StoredWallet } from 'projects/portal/src/app/models/wallets/wallet.model'; +import { WalletService } from 'projects/portal/src/app/models/wallets/wallet.service'; +import { Observable, combineLatest } from 'rxjs'; +import { filter, map } from 'rxjs/operators'; +import { ExemplaryTraderAll200ResponseExemplaryTraderInner } from 'ununifi-client/esm/openapi'; + +@Component({ + selector: 'app-create', + templateUrl: './create.component.html', + styleUrls: ['./create.component.css'], +}) +export class CreateComponent implements OnInit { + address$: Observable; + myExemplaryTrader$: Observable; + traderName$: Observable; + traderDescription$: Observable; + commissionRate$: Observable; + + constructor( + private readonly walletService: WalletService, + private readonly copyTradingQuery: CopyTradingQueryService, + private readonly copyTradingApplication: CopyTradingApplicationService, + ) { + const currentStoredWallet$ = this.walletService.currentStoredWallet$; + this.address$ = currentStoredWallet$.pipe( + filter((wallet): wallet is StoredWallet => wallet !== undefined && wallet !== null), + map((wallet) => cosmosclient.AccAddress.fromString(wallet.address).toString()), + ); + const exemplaryTraders$ = this.copyTradingQuery.listExemplaryTraders$(); + this.myExemplaryTrader$ = combineLatest([this.address$, exemplaryTraders$]).pipe( + map(([address, traders]) => traders.find((trader) => trader.address == address)), + ); + this.traderName$ = this.myExemplaryTrader$.pipe(map((trader) => trader?.name)); + this.traderDescription$ = this.myExemplaryTrader$.pipe(map((trader) => trader?.description)); + this.commissionRate$ = this.myExemplaryTrader$.pipe( + map((trader) => Number(trader?.profit_commission_rate)), + ); + } + + ngOnInit(): void {} + + onCreateTrader(data: CreateExemplaryTraderRequest) { + this.copyTradingApplication.createExemplaryTrader( + data.name, + data.description, + data.profitCommissionRate, + ); + } + + onUpdateTrader(data: UpdateExemplaryTraderRequest) { + this.copyTradingApplication.updateExemplaryTrader( + data.name, + data.description, + data.profitCommissionRate, + ); + } +} diff --git a/projects/portal/src/app/pages/copy-trading/traders/trader/trader.component.css b/projects/portal/src/app/pages/copy-trading/traders/trader/trader.component.css new file mode 100644 index 000000000..e69de29bb diff --git a/projects/portal/src/app/pages/copy-trading/traders/trader/trader.component.html b/projects/portal/src/app/pages/copy-trading/traders/trader/trader.component.html new file mode 100644 index 000000000..682ab5cad --- /dev/null +++ b/projects/portal/src/app/pages/copy-trading/traders/trader/trader.component.html @@ -0,0 +1,15 @@ + diff --git a/projects/portal/src/app/pages/copy-trading/traders/trader/trader.component.ts b/projects/portal/src/app/pages/copy-trading/traders/trader/trader.component.ts new file mode 100644 index 000000000..6fd8a8e3a --- /dev/null +++ b/projects/portal/src/app/pages/copy-trading/traders/trader/trader.component.ts @@ -0,0 +1,96 @@ +import { CopyTradingQueryService } from '../../../../models/copy-trading/copy-trading.query.service'; +import { StoredWallet } from '../../../../models/wallets/wallet.model'; +import { WalletService } from '../../../../models/wallets/wallet.service'; +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import cosmosclient from '@cosmos-client/core'; +import { CopyTradingApplicationService } from 'projects/portal/src/app/models/copy-trading/copy-trading.application.service'; +import { + CreateTracingRequest, + UpdateExemplaryTraderRequest, +} from 'projects/portal/src/app/models/copy-trading/copy-trading.model'; +import { Observable, combineLatest } from 'rxjs'; +import { filter, map, mergeMap } from 'rxjs/operators'; +import { + ExemplaryTraderAll200ResponseExemplaryTraderInner, + ExemplaryTraderTracing200ResponseTracingInner, +} from 'ununifi-client/esm/openapi'; + +@Component({ + selector: 'app-trader', + templateUrl: './trader.component.html', + styleUrls: ['./trader.component.css'], +}) +export class TraderComponent implements OnInit { + address$: Observable; + exemplaryTraderAddress$: Observable; + trader$: Observable; + tracing$: Observable; + isTracing$: Observable; + userCount$: Observable; + commissionRate$: Observable; + description$: Observable; + + constructor( + private route: ActivatedRoute, + private readonly walletService: WalletService, + private readonly copyTradingQuery: CopyTradingQueryService, + private readonly copyTradingApplication: CopyTradingApplicationService, + ) { + const currentStoredWallet$ = this.walletService.currentStoredWallet$; + this.address$ = currentStoredWallet$.pipe( + filter((wallet): wallet is StoredWallet => wallet !== undefined && wallet !== null), + map((wallet) => cosmosclient.AccAddress.fromString(wallet.address).toString()), + ); + this.exemplaryTraderAddress$ = this.route.params.pipe(map((params) => params.address)); + this.trader$ = this.exemplaryTraderAddress$.pipe( + mergeMap((exAddress) => this.copyTradingQuery.getExemplaryTrader$(exAddress)), + ); + this.tracing$ = this.address$.pipe( + mergeMap((address) => this.copyTradingQuery.getTracing$(address)), + ); + this.isTracing$ = combineLatest([this.tracing$, this.exemplaryTraderAddress$]).pipe( + map(([tracing, exAddress]) => tracing.exemplary_trader == exAddress), + ); + this.userCount$ = combineLatest([ + this.exemplaryTraderAddress$, + this.copyTradingQuery.listAllTracings$(), + ]).pipe( + map( + ([exAddress, tracings]) => + tracings.filter((tracing) => tracing.exemplary_trader == exAddress).length, + ), + ); + this.commissionRate$ = this.trader$.pipe( + map((trader) => Number(trader.profit_commission_rate || 0)), + ); + this.description$ = this.trader$.pipe(map((trader) => trader.description)); + } + + ngOnInit(): void {} + + onCreateTracing(data: CreateTracingRequest) { + this.copyTradingApplication.createTracing( + data.exemplaryTrader, + data.sizeCoef, + data.leverageCoef, + data.reverse, + ); + } + + onDeleteTracing() { + this.copyTradingApplication.deleteTracing(); + } + + onUpdateTrader(data: UpdateExemplaryTraderRequest) { + this.copyTradingApplication.updateExemplaryTrader( + data.name, + data.description, + data.profitCommissionRate, + ); + } + + onDeleteTrader() { + this.copyTradingApplication.deleteExemplaryTrader(); + } +} diff --git a/projects/portal/src/app/pages/copy-trading/traders/traders.component.css b/projects/portal/src/app/pages/copy-trading/traders/traders.component.css new file mode 100644 index 000000000..e69de29bb diff --git a/projects/portal/src/app/pages/copy-trading/traders/traders.component.html b/projects/portal/src/app/pages/copy-trading/traders/traders.component.html new file mode 100644 index 000000000..c7e764648 --- /dev/null +++ b/projects/portal/src/app/pages/copy-trading/traders/traders.component.html @@ -0,0 +1,9 @@ + diff --git a/projects/portal/src/app/pages/copy-trading/traders/traders.component.ts b/projects/portal/src/app/pages/copy-trading/traders/traders.component.ts new file mode 100644 index 000000000..01f77aa3c --- /dev/null +++ b/projects/portal/src/app/pages/copy-trading/traders/traders.component.ts @@ -0,0 +1,66 @@ +import { CopyTradingApplicationService } from '../../../models/copy-trading/copy-trading.application.service'; +import { CopyTradingQueryService } from '../../../models/copy-trading/copy-trading.query.service'; +import { StoredWallet } from '../../../models/wallets/wallet.model'; +import { WalletService } from '../../../models/wallets/wallet.service'; +import { Component, OnInit } from '@angular/core'; +import cosmosclient from '@cosmos-client/core'; +import { Observable, combineLatest } from 'rxjs'; +import { filter, map, mergeMap } from 'rxjs/operators'; +import { + ExemplaryTraderAll200ResponseExemplaryTraderInner, + ExemplaryTraderTracing200ResponseTracingInner, +} from 'ununifi-client/esm/openapi'; + +@Component({ + selector: 'app-traders', + templateUrl: './traders.component.html', + styleUrls: ['./traders.component.css'], +}) +export class TradersComponent implements OnInit { + address$: Observable; + exemplaryTraders$: Observable; + myExemplaryTrader$: Observable; + tracing$: Observable; + tracingTrader$: Observable; + userCounts$: Observable; + + constructor( + private readonly walletService: WalletService, + private readonly copyTradingQuery: CopyTradingQueryService, + private readonly copyTradingApplication: CopyTradingApplicationService, + ) { + const currentStoredWallet$ = this.walletService.currentStoredWallet$; + this.address$ = currentStoredWallet$.pipe( + filter((wallet): wallet is StoredWallet => wallet !== undefined && wallet !== null), + map((wallet) => cosmosclient.AccAddress.fromString(wallet.address).toString()), + ); + this.exemplaryTraders$ = this.copyTradingQuery.listExemplaryTraders$(); + this.myExemplaryTrader$ = combineLatest([this.address$, this.exemplaryTraders$]).pipe( + map(([address, traders]) => traders.find((trader) => trader.address == address)), + ); + this.tracing$ = this.address$.pipe( + mergeMap((address) => this.copyTradingQuery.getTracing$(address)), + ); + this.tracingTrader$ = combineLatest([this.tracing$, this.exemplaryTraders$]).pipe( + map(([tracing, traders]) => + traders.find((trader) => trader.address == tracing.exemplary_trader), + ), + ); + + const availableTracings$ = this.copyTradingQuery.listAllTracings$(); + this.userCounts$ = combineLatest([this.exemplaryTraders$, availableTracings$]).pipe( + map(([traders, tracings]) => + traders.map( + (trader) => + tracings.filter((tracing) => tracing.exemplary_trader == trader.address).length, + ), + ), + ); + } + + ngOnInit(): void {} + + onDeleteTracing() { + this.copyTradingApplication.deleteTracing(); + } +} diff --git a/projects/portal/src/app/pages/derivatives/derivatives-routing.module.ts b/projects/portal/src/app/pages/derivatives/derivatives-routing.module.ts index 96dd53bb0..4f55a5861 100644 --- a/projects/portal/src/app/pages/derivatives/derivatives-routing.module.ts +++ b/projects/portal/src/app/pages/derivatives/derivatives-routing.module.ts @@ -25,6 +25,11 @@ const routes: Routes = [ (m) => m.AppPerpetualFuturesModule, ), }, + { + path: 'copy-trading', + loadChildren: () => + import('../copy-trading/copy-trading.module').then((m) => m.AppCopyTradingModule), + }, ]; @NgModule({ diff --git a/projects/portal/src/app/pages/derivatives/pool/pool.component.ts b/projects/portal/src/app/pages/derivatives/pool/pool.component.ts index fd875e503..1aafbe861 100644 --- a/projects/portal/src/app/pages/derivatives/pool/pool.component.ts +++ b/projects/portal/src/app/pages/derivatives/pool/pool.component.ts @@ -6,7 +6,6 @@ import { StoredWallet } from '../../../models/wallets/wallet.model'; import { WalletService } from '../../../models/wallets/wallet.service'; import { BurnLPTEvent, MintLPTEvent } from '../../../views/derivatives/pool/pool.component'; import { Component, OnInit } from '@angular/core'; -import cosmosclient from '@cosmos-client/core'; import { BehaviorSubject, combineLatest, of, timer } from 'rxjs'; import { filter, map, mergeMap } from 'rxjs/operators'; diff --git a/projects/portal/src/app/pages/nft-pawnshop/borrowers/borrower-nfts/borrower-nft/borrow/borrow.component.ts b/projects/portal/src/app/pages/nft-pawnshop/borrowers/borrower-nfts/borrower-nft/borrow/borrow.component.ts index 6d400c566..1a0614639 100644 --- a/projects/portal/src/app/pages/nft-pawnshop/borrowers/borrower-nfts/borrower-nft/borrow/borrow.component.ts +++ b/projects/portal/src/app/pages/nft-pawnshop/borrowers/borrower-nfts/borrower-nft/borrow/borrow.component.ts @@ -9,7 +9,7 @@ import { Metadata } from 'projects/shared/src/lib/models/ununifi/query/nft/nft.m import { Observable, combineLatest, of } from 'rxjs'; import { map, mergeMap } from 'rxjs/operators'; import { - ListedNfts200ResponseListingsInner, + ListedNfts200ResponseListingsInnerListing, BidderBids200ResponseBidsInner, Loans200ResponseLoansInner, } from 'ununifi-client/esm/openapi'; @@ -22,7 +22,7 @@ import { export class BorrowComponent implements OnInit { classID$: Observable; nftID$: Observable; - listingInfo$: Observable; + listingInfo$: Observable; bidders$: Observable; loans$: Observable; nftMetadata$: Observable; @@ -48,7 +48,9 @@ export class BorrowComponent implements OnInit { this.bidders$ = nftCombine$.pipe( mergeMap(([classID, nftID]) => this.pawnshopQuery.listNftBids$(classID, nftID)), map((bidders) => - bidders.sort((a, b) => parseInt(b.deposit_amount?.amount!) - parseInt(a.deposit_amount?.amount!)), + bidders.sort( + (a, b) => parseInt(b.deposit_amount?.amount!) - parseInt(a.deposit_amount?.amount!), + ), ), ); this.borrowAmount$ = this.bidders$.pipe( diff --git a/projects/portal/src/app/pages/nft-pawnshop/borrowers/borrower-nfts/borrower-nft/borrower-nft.component.ts b/projects/portal/src/app/pages/nft-pawnshop/borrowers/borrower-nfts/borrower-nft/borrower-nft.component.ts index 32a9f1610..20ef0b096 100644 --- a/projects/portal/src/app/pages/nft-pawnshop/borrowers/borrower-nfts/borrower-nft/borrower-nft.component.ts +++ b/projects/portal/src/app/pages/nft-pawnshop/borrowers/borrower-nfts/borrower-nft/borrower-nft.component.ts @@ -6,9 +6,9 @@ import { NftPawnshopQueryService } from 'projects/portal/src/app/models/nft-pawn import { NftPawnshopService } from 'projects/portal/src/app/models/nft-pawnshops/nft-pawnshop.service'; import { Metadata } from 'projects/shared/src/lib/models/ununifi/query/nft/nft.model'; import { Observable, combineLatest } from 'rxjs'; -import { first, map, mergeMap } from 'rxjs/operators'; +import { map, mergeMap } from 'rxjs/operators'; import { - ListedNfts200ResponseListingsInner, + ListedNfts200ResponseListingsInnerListing, BidderBids200ResponseBidsInner, Loan200Response, Liquidation200ResponseLiquidations, @@ -22,7 +22,7 @@ import { export class BorrowerNftComponent implements OnInit { classID$: Observable; nftID$: Observable; - listingInfo$: Observable; + listingInfo$: Observable; bidders$: Observable; loan$: Observable; liquidation$: Observable; diff --git a/projects/portal/src/app/pages/nft-pawnshop/borrowers/borrower-nfts/borrower-nft/repay/repay.component.ts b/projects/portal/src/app/pages/nft-pawnshop/borrowers/borrower-nfts/borrower-nft/repay/repay.component.ts index 25ca1541c..60442be2d 100644 --- a/projects/portal/src/app/pages/nft-pawnshop/borrowers/borrower-nfts/borrower-nft/repay/repay.component.ts +++ b/projects/portal/src/app/pages/nft-pawnshop/borrowers/borrower-nfts/borrower-nft/repay/repay.component.ts @@ -8,12 +8,11 @@ import { NftPawnshopService } from 'projects/portal/src/app/models/nft-pawnshops import { Metadata } from 'projects/shared/src/lib/models/ununifi/query/nft/nft.model'; import { Observable, combineLatest, of } from 'rxjs'; import { map, mergeMap } from 'rxjs/operators'; -import { rewards } from 'ununifi-client/cjs/rest/nftmarket/module'; import { - ListedNfts200ResponseListingsInner, BidderBids200ResponseBidsInner, Loans200ResponseLoansInner, Liquidation200ResponseLiquidations, + ListedNfts200ResponseListingsInnerListing, } from 'ununifi-client/esm/openapi'; @Component({ @@ -24,7 +23,7 @@ import { export class RepayComponent implements OnInit { classID$: Observable; nftID$: Observable; - listingInfo$: Observable; + listingInfo$: Observable; bidders$: Observable; loans$: Observable; liquidation$: Observable; @@ -52,7 +51,9 @@ export class RepayComponent implements OnInit { mergeMap(([classID, nftID]) => this.pawnshopQuery.listNftBids$(classID, nftID)), map((bidders) => bidders.filter((bidder) => bidder.borrowings?.length)), map((bidders) => - bidders.sort((a, b) => parseInt(b.deposit_amount?.amount!) - parseInt(a.deposit_amount?.amount!)), + bidders.sort( + (a, b) => parseInt(b.deposit_amount?.amount!) - parseInt(a.deposit_amount?.amount!), + ), ), ); this.loans$ = nftCombine$.pipe( diff --git a/projects/portal/src/app/pages/nft-pawnshop/borrowers/borrower/borrower.component.ts b/projects/portal/src/app/pages/nft-pawnshop/borrowers/borrower/borrower.component.ts index 27e0aaef9..ec8028ad2 100644 --- a/projects/portal/src/app/pages/nft-pawnshop/borrowers/borrower/borrower.component.ts +++ b/projects/portal/src/app/pages/nft-pawnshop/borrowers/borrower/borrower.component.ts @@ -48,7 +48,7 @@ export class BorrowerComponent implements OnInit { mergeMap((address) => this.pawnshopQuery .listAllListedNfts$() - .pipe(map((nfts) => nfts.filter((nft) => nft.owner == address))), + .pipe(map((nfts) => nfts.filter((nft) => nft.listing?.owner == address))), ), ); @@ -56,8 +56,11 @@ export class BorrowerComponent implements OnInit { mergeMap((nfts) => Promise.all( nfts.map(async (nft) => { - if (nft.nft_id && nft.nft_id.class_id && nft.nft_id.nft_id) { - const res = await this.pawnshopQuery.getNft(nft.nft_id.class_id, nft.nft_id.nft_id); + if (nft.listing?.nft_id?.class_id && nft.listing?.nft_id?.nft_id) { + const res = await this.pawnshopQuery.getNft( + nft.listing.nft_id.class_id, + nft.listing.nft_id.nft_id, + ); return res.nft?.uri; } else { return ''; diff --git a/projects/portal/src/app/pages/nft-pawnshop/borrowers/borrowers.component.ts b/projects/portal/src/app/pages/nft-pawnshop/borrowers/borrowers.component.ts index faa5d5289..fcaf30c2d 100644 --- a/projects/portal/src/app/pages/nft-pawnshop/borrowers/borrowers.component.ts +++ b/projects/portal/src/app/pages/nft-pawnshop/borrowers/borrowers.component.ts @@ -34,7 +34,7 @@ export class BorrowersComponent implements OnInit { mergeMap((address) => this.pawnshopQuery .listAllListedNfts$() - .pipe(map((nfts) => nfts.filter((nft) => nft.owner == address))), + .pipe(map((nfts) => nfts.filter((nft) => nft.listing?.owner == address))), ), ); } diff --git a/projects/portal/src/app/pages/nft-pawnshop/lenders/lender-nfts/lender-nft/lender-nft.component.ts b/projects/portal/src/app/pages/nft-pawnshop/lenders/lender-nfts/lender-nft/lender-nft.component.ts index 4b10aefed..869a0f3e4 100644 --- a/projects/portal/src/app/pages/nft-pawnshop/lenders/lender-nfts/lender-nft/lender-nft.component.ts +++ b/projects/portal/src/app/pages/nft-pawnshop/lenders/lender-nfts/lender-nft/lender-nft.component.ts @@ -12,7 +12,7 @@ import { combineLatest, Observable } from 'rxjs'; import { filter, map, mergeMap } from 'rxjs/operators'; import { BidderBids200ResponseBidsInner, - ListedNfts200ResponseListingsInner, + ListedNfts200ResponseListingsInnerListing, } from 'ununifi-client/esm/openapi'; @Component({ @@ -25,7 +25,7 @@ export class LenderNftComponent implements OnInit { address$: Observable; classID$: Observable; nftID$: Observable; - listingInfo$: Observable; + listingInfo$: Observable; bidders$: Observable; nftMetadata$: Observable; nftImage$: Observable; diff --git a/projects/portal/src/app/pages/nft-pawnshop/lenders/lender-nfts/lender-nft/place-bid/place-bid.component.ts b/projects/portal/src/app/pages/nft-pawnshop/lenders/lender-nfts/lender-nft/place-bid/place-bid.component.ts index 3a4a9a9e0..caf9e7962 100644 --- a/projects/portal/src/app/pages/nft-pawnshop/lenders/lender-nfts/lender-nft/place-bid/place-bid.component.ts +++ b/projects/portal/src/app/pages/nft-pawnshop/lenders/lender-nfts/lender-nft/place-bid/place-bid.component.ts @@ -13,7 +13,7 @@ import { combineLatest, Observable, zip } from 'rxjs'; import { filter, map, mergeMap } from 'rxjs/operators'; import { BidderBids200ResponseBidsInner, - ListedNfts200ResponseListingsInner, + ListedNfts200ResponseListingsInnerListing, } from 'ununifi-client/esm/openapi'; @Component({ @@ -27,7 +27,7 @@ export class PlaceBidComponent implements OnInit { symbol$: Observable; currentStoredWallet$: Observable; balance$: Observable; - listingInfo$: Observable; + listingInfo$: Observable; bidders$: Observable; nftMetadata$: Observable; nftImage$: Observable; diff --git a/projects/portal/src/app/pages/nft-pawnshop/lenders/lender/lender.component.ts b/projects/portal/src/app/pages/nft-pawnshop/lenders/lender/lender.component.ts index 407ea7571..812e6d8d7 100644 --- a/projects/portal/src/app/pages/nft-pawnshop/lenders/lender/lender.component.ts +++ b/projects/portal/src/app/pages/nft-pawnshop/lenders/lender/lender.component.ts @@ -7,7 +7,7 @@ import { NftPawnshopService } from 'projects/portal/src/app/models/nft-pawnshops import { Metadata } from 'projects/shared/src/lib/models/ununifi/query/nft/nft.model'; import { Observable, pipe } from 'rxjs'; import { filter, map, mergeMap } from 'rxjs/operators'; -import { ListedNfts200ResponseListingsInner } from 'ununifi-client/esm/openapi'; +import { ListedNfts200ResponseListingsInnerListing } from 'ununifi-client/esm/openapi'; @Component({ selector: 'app-lender', @@ -16,7 +16,7 @@ import { ListedNfts200ResponseListingsInner } from 'ununifi-client/esm/openapi'; }) export class LenderComponent implements OnInit { address$: Observable; - biddingNfts$: Observable; + biddingNfts$: Observable; nftsMetadata$: Observable; nftImages$: Observable; diff --git a/projects/portal/src/app/pages/nft-pawnshop/lenders/lenders.component.ts b/projects/portal/src/app/pages/nft-pawnshop/lenders/lenders.component.ts index dfc09b3cd..27e8d08e7 100644 --- a/projects/portal/src/app/pages/nft-pawnshop/lenders/lenders.component.ts +++ b/projects/portal/src/app/pages/nft-pawnshop/lenders/lenders.component.ts @@ -14,6 +14,7 @@ import { BidderBids200ResponseBidsInner, ListedClass200Response, ListedNfts200ResponseListingsInner, + ListedNfts200ResponseListingsInnerListing, } from 'ununifi-client/esm/openapi'; export interface BidderNftsInfo { @@ -34,7 +35,7 @@ export class LendersComponent implements OnInit { bidderBids$: Observable; depositCoins$: Observable; lendCoins$: Observable; - biddingNfts$: Observable; + biddingNfts$: Observable; biddingNftsInfo$: Observable; rewards$: Observable; listedClasses$: Observable; @@ -160,10 +161,10 @@ export class LendersComponent implements OnInit { return []; } const filteredNfts = nfts.filter( - (nft) => nft.bid_token == selectedMetadata.denom_units![0].denom, + (nft) => nft.listing?.bid_token == selectedMetadata.denom_units![0].denom, ); return classes.filter((value) => - filteredNfts.find((nft) => nft.nft_id?.class_id == value.class_id), + filteredNfts.find((nft) => nft.listing?.nft_id?.class_id == value.class_id), ); }), ); diff --git a/projects/portal/src/app/views/apps/app-derivatives/app-derivatives.component.html b/projects/portal/src/app/views/apps/app-derivatives/app-derivatives.component.html index 1e4793bfe..d949cd632 100644 --- a/projects/portal/src/app/views/apps/app-derivatives/app-derivatives.component.html +++ b/projects/portal/src/app/views/apps/app-derivatives/app-derivatives.component.html @@ -72,6 +72,14 @@ Pool +
  • + +
  • +
  • + +