diff --git a/angular.json b/angular.json index eb55914df..eddc3c8a7 100644 --- a/angular.json +++ b/angular.json @@ -30,7 +30,11 @@ "@cosmjs/stargate", "simplebar", "simplebar-angular", - "@cosmjs/cosmwasm-stargate" + "@cosmjs/cosmwasm-stargate", + "@cosmjs/math", + "@cosmjs/amino", + "buffer", + "exceljs" ], "outputPath": "dist/frontend", "index": "src/index.html", diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 3317ac912..b7565aba8 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -4,6 +4,8 @@ import { CommonService } from './core/services/common.service'; import { TokenService } from './core/services/token.service'; import { getInfo } from './core/utils/common/info-common'; import { Globals } from './global/global'; +// import eruda from 'eruda'; +import { EnvironmentService } from 'src/app/core/data-services/environment.service'; @Component({ selector: 'app-root', @@ -11,20 +13,42 @@ import { Globals } from './global/global'; styleUrls: ['./app.component.scss'], }) export class AppComponent implements OnInit { - constructor(private commonService: CommonService, private globals: Globals, private tokenService: TokenService) {} + // chainInfo = this.env.configValue.chain_info; + // TESTNET = ['aura-testnet-2', 'serenity-testnet-001']; + // isTestnet = this.TESTNET.includes( + // this.chainInfo?.chainId || '' + // ); + constructor( + private commonService: CommonService, + private globals: Globals, + private tokenService: TokenService, + ) // private env: EnvironmentService + {} ngOnInit(): void { + this.getListNameTag(); this.getInfoCommon(); this.getPriceToken(); setInterval(() => { + this.getListNameTag(); this.getInfoCommon(); this.getPriceToken(); }, 60000); + + // if (this.isTestnet) { + // let el = document.createElement('div'); + // document.body.appendChild(el); + // + // eruda.init({ + // container: el, + // tool: ['console', 'elements', 'resources', 'network'], + // }); + // } } getInfoCommon(): void { this.commonService.status().subscribe((res) => { - getInfo(this.globals, res.data); + getInfo(this.globals, res); }); } @@ -37,4 +61,15 @@ export class AppComponent implements OnInit { this.globals.price.btc = res.data || 0; }); } + + getListNameTag(): void { + const payload = { + limit: 500, + keyword: [], + nextKey: 0, + }; + this.commonService.getListNameTag(payload).subscribe((res) => { + this.globals.listNameTag = this.commonService.listNameTag = res.data?.nameTags; + }); + } } diff --git a/src/app/app.module.ts b/src/app/app.module.ts index df3dbc826..2e6cfa748 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -1,5 +1,5 @@ import { DatePipe } from '@angular/common'; -import { HttpClient, HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; +import { HTTP_INTERCEPTORS, HttpClient, HttpClientModule } from '@angular/common/http'; import { APP_INITIALIZER, ErrorHandler, NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MAT_MOMENT_DATE_ADAPTER_OPTIONS, MomentDateAdapter } from '@angular/material-moment-adapter'; @@ -9,7 +9,7 @@ import { MatButtonToggleModule } from '@angular/material/button-toggle'; import { MatCardModule } from '@angular/material/card'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatChipsModule } from '@angular/material/chips'; -import { DateAdapter, MatNativeDateModule, MAT_DATE_FORMATS, MAT_DATE_LOCALE } from '@angular/material/core'; +import { DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE, MatNativeDateModule } from '@angular/material/core'; import { MatDatepickerModule } from '@angular/material/datepicker'; import { MatDialogModule } from '@angular/material/dialog'; import { MatExpansionModule } from '@angular/material/expansion'; @@ -33,7 +33,6 @@ import { MatStepperModule } from '@angular/material/stepper'; import { MatTableModule } from '@angular/material/table'; import { MatTabsModule } from '@angular/material/tabs'; import { MatToolbarModule } from '@angular/material/toolbar'; -import { MatTooltipModule } from '@angular/material/tooltip'; import { BrowserModule } from '@angular/platform-browser'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { NgbModule, NgbNavModule, NgbPopoverModule, NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap'; @@ -110,7 +109,6 @@ export const MY_FORMATS = { MatTableModule, MatTabsModule, MatToolbarModule, - MatTooltipModule, MatNativeDateModule, MatFormFieldModule, SchemaViewerModule, diff --git a/src/app/core/constants/common.constant.ts b/src/app/core/constants/common.constant.ts index 4824009e2..ed17f7606 100644 --- a/src/app/core/constants/common.constant.ts +++ b/src/app/core/constants/common.constant.ts @@ -27,7 +27,7 @@ export const NETWORK = [ export const DATEFORMAT = { DATETIME_UTC: 'yyyy-MM-dd HH:mm:ss', - DATE_ONLY: 'dd/MM/yyyy', + DATE_ONLY: 'yyyy-MM-dd', }; export const NUMBER_CONVERT = 1000000; //10^6 satoshi unit @@ -68,8 +68,6 @@ export const TOKEN_ID_GET_PRICE = { BTC: 'bitcoin' }; -export const LIST_TYPE_CONTRACT_ADDRESS = ['revoke_all', 'approve_all', 'revoke', 'approve']; - export enum MEDIA_TYPE { IMG = 'img', VIDEO = 'video', diff --git a/src/app/core/constants/contract.constant.ts b/src/app/core/constants/contract.constant.ts index 0dcdc2b0c..53554ce81 100644 --- a/src/app/core/constants/contract.constant.ts +++ b/src/app/core/constants/contract.constant.ts @@ -35,20 +35,13 @@ export const MAX_LENGTH_SEARCH_CONTRACT = 200; export const CONTRACT_TABLE_TEMPLATES: Array = [ // { matColumnDef: 'popover', headerCellDef: '', type: 'popover', headerWidth: 4 }, { matColumnDef: 'txHash', headerCellDef: 'Txn Hash', type: 'hash-url', headerWidth: 12, isUrl: '/transaction' }, - { matColumnDef: 'method', headerCellDef: 'Method', type: 'status', headerWidth: 10 }, - { matColumnDef: 'status', headerCellDef: 'Result', type: 'result', headerWidth: 10 }, - { - matColumnDef: 'blockHeight', - headerCellDef: 'Block', - type: 'hash-url', - headerWidth: 6, - isUrl: '/blocks' - }, + { matColumnDef: 'method', headerCellDef: 'Method', type: 'status', headerWidth: 12 }, + { matColumnDef: 'status', headerCellDef: 'Result', type: 'result', headerWidth: 9 }, + { matColumnDef: 'blockHeight', headerCellDef: 'Block', type: 'hash-url', headerWidth: 6, isUrl: '/blocks' }, { matColumnDef: 'time', headerCellDef: 'Time', type: 'time-distance', headerWidth: 8, suffix: 'ago' }, - { matColumnDef: 'from', headerCellDef: 'From', type: 'hash-url', headerWidth: 12, isUrl: '/account' }, - { matColumnDef: 'label', headerCellDef: '', type: 'status', headerWidth: 6, justify: 'center' }, - { matColumnDef: 'to', headerCellDef: 'To', type: 'hash-url', headerWidth: 12, isUrl: '/contracts' }, - { matColumnDef: 'value', headerCellDef: 'Value', type: 'numb', suffix: 'AURA', headerWidth: 10 }, + { matColumnDef: 'from', headerCellDef: 'From', type: 'hash-url', headerWidth: 12, isUrl: '/account', isNameTag: true }, + { matColumnDef: 'label', headerCellDef: '', type: 'type', headerWidth: 6, justify: 'center' }, + { matColumnDef: 'to', headerCellDef: 'To', type: 'hash-url', headerWidth: 12, isUrl: '/contracts', isNameTag: true }, { matColumnDef: 'fee', headerCellDef: 'Txn Fee', type: 'numb', headerWidth: 10 }, ]; @@ -72,6 +65,7 @@ export const CONTRACT_VERSIONS = [ { label: 'cosmwasm/rust-optimizer:0.12.11', value: 'cosmwasm/rust-optimizer:0.12.11' }, { label: 'cosmwasm/rust-optimizer:0.12.12', value: 'cosmwasm/rust-optimizer:0.12.12' }, { label: 'cosmwasm/rust-optimizer:0.12.13', value: 'cosmwasm/rust-optimizer:0.12.13' }, + { label: 'cosmwasm/rust-optimizer:0.13.0', value: 'cosmwasm/rust-optimizer:0.13.0' }, // { label: 'cosmwasm/rust-optimizer-arm64:0.12.4', value: 'cosmwasm/rust-optimizer-arm64:0.12.4' }, // { label: 'cosmwasm/rust-optimizer-arm64:0.12.5', value: 'cosmwasm/rust-optimizer-arm64:0.12.5' }, @@ -97,6 +91,7 @@ export const CONTRACT_VERSIONS = [ { label: 'cosmwasm/workspace-optimizer:0.12.11', value: 'cosmwasm/workspace-optimizer:0.12.11' }, { label: 'cosmwasm/workspace-optimizer:0.12.12', value: 'cosmwasm/workspace-optimizer:0.12.12' }, { label: 'cosmwasm/workspace-optimizer:0.12.13', value: 'cosmwasm/workspace-optimizer:0.12.13' }, + { label: 'cosmwasm/workspace-optimizer:0.13.0', value: 'cosmwasm/workspace-optimizer:0.13.0' }, // { label: 'cosmwasm/workspace-optimizer-arm64:0.12.4', value: 'cosmwasm/workspace-optimizer-arm64:0.12.4' }, // { label: 'cosmwasm/workspace-optimizer-arm64:0.12.5', value: 'cosmwasm/workspace-optimizer-arm64:0.12.5' }, @@ -118,7 +113,6 @@ export const REGISTER_CONTRACT = [ }, ]; - export const LIST_ZEROES = [ { value: '6', @@ -134,3 +128,4 @@ export const LIST_ZEROES = [ }, ]; +export const TYPE_CW4973 = 'crates.io:cw4973'; diff --git a/src/app/core/constants/contract.enum.ts b/src/app/core/constants/contract.enum.ts index 80b17032c..e411498be 100644 --- a/src/app/core/constants/contract.enum.ts +++ b/src/app/core/constants/contract.enum.ts @@ -8,9 +8,9 @@ export enum ContractTab { export enum ContractVerifyType { Unverified = 'UNVERIFIED', - Verified = 'VERIFIED', - VerifiedFail = 'VERIFYFAIL', - Verifying = 'VERIFYING' + Verified = 'SUCCESS', + VerifiedFail = 'FAIL', + Verifying = 'VERIFYING', } export enum ContractTransactionType { diff --git a/src/app/core/constants/proposal.constant.ts b/src/app/core/constants/proposal.constant.ts index 08d738bd2..e37d10525 100644 --- a/src/app/core/constants/proposal.constant.ts +++ b/src/app/core/constants/proposal.constant.ts @@ -4,7 +4,7 @@ export enum VOTING_STATUS { PROPOSAL_STATUS_VOTING_PERIOD = 'PROPOSAL_STATUS_VOTING_PERIOD', PROPOSAL_STATUS_DEPOSIT_PERIOD = 'PROPOSAL_STATUS_DEPOSIT_PERIOD', PROPOSAL_STATUS_FAILED = 'PROPOSAL_STATUS_FAILED', - PROPOSAL_STATUS_NOT_ENOUGH_DEPOSIT = 'PROPOSAL_STATUS_NOT_ENOUGH_DEPOSIT' + PROPOSAL_STATUS_NOT_ENOUGH_DEPOSIT = 'PROPOSAL_STATUS_NOT_ENOUGH_DEPOSIT', } export const PROPOSAL_STATUS = [ @@ -36,42 +36,42 @@ export const PROPOSAL_STATUS = [ ]; export enum VOTE_OPTION { - VOTE_OPTION_NULL = 'null', - VOTE_OPTION_UNSPECIFIED = 'VOTE_OPTION_UNSPECIFIED', - VOTE_OPTION_YES = 'VOTE_OPTION_YES', - VOTE_OPTION_ABSTAIN = 'VOTE_OPTION_ABSTAIN', - VOTE_OPTION_NO = 'VOTE_OPTION_NO', - VOTE_OPTION_NO_WITH_VETO = 'VOTE_OPTION_NO_WITH_VETO', - VOTE_OPTION_EMPTY = 'VOTE_OPTION_EMPTY' + NULL = 'null', + UNSPECIFIED = 'VOTE_OPTION_UNSPECIFIED', + YES = 'VOTE_OPTION_YES', + ABSTAIN = 'VOTE_OPTION_ABSTAIN', + NO = 'VOTE_OPTION_NO', + NO_WITH_VETO = 'VOTE_OPTION_NO_WITH_VETO', + EMPTY = 'VOTE_OPTION_EMPTY', } export const PROPOSAL_VOTE = [ { - key: VOTE_OPTION.VOTE_OPTION_UNSPECIFIED, + key: VOTE_OPTION.UNSPECIFIED, value: 'All', class: '', voteOption: '', }, { - key: VOTE_OPTION.VOTE_OPTION_YES, + key: VOTE_OPTION.YES, value: 'Yes', class: 'primary', voteOption: 'Yes', }, { - key: VOTE_OPTION.VOTE_OPTION_NO, + key: VOTE_OPTION.NO, value: 'No', class: 'danger', voteOption: 'No', }, { - key: VOTE_OPTION.VOTE_OPTION_NO_WITH_VETO, + key: VOTE_OPTION.NO_WITH_VETO, value: 'NoWithVeto', class: 'info', voteOption: 'NoWithVeto', }, { - key: VOTE_OPTION.VOTE_OPTION_ABSTAIN, + key: VOTE_OPTION.ABSTAIN, value: 'Abstain', class: 'secondary', voteOption: 'Abstain', @@ -96,11 +96,11 @@ export enum VOTING_SUBTITLE { REJECT_1 = 'This proposal is rejected because there are more than {{proposalDetail.noWithVetoPercent}}% of No With Veto votes.', REJECT_2 = 'This proposal is rejected because it is above the threshold and received more than 50.00% of No votes.', REJECT_3 = 'This proposal is failed because it did not reach the quorum.', - FAILED = 'This proposal is failed because the upgrade can\'t be executed', + FAILED = "This proposal is failed because the upgrade can't be executed", } export enum VOTING_QUORUM { - REACHED= '(Reached)', + REACHED = '(Reached)', NOT_REACHED = '(Not Reached)', } @@ -108,4 +108,4 @@ export enum PROPOSAL_TABLE_MODE { VOTES = 'VOTES', DEPOSITORS = 'DEPOSITORS', VALIDATORS_VOTES = 'VALIDATORS_VOTES', -} \ No newline at end of file +} diff --git a/src/app/core/constants/transaction.constant.ts b/src/app/core/constants/transaction.constant.ts index b3a77ca16..2d86f9078 100644 --- a/src/app/core/constants/transaction.constant.ts +++ b/src/app/core/constants/transaction.constant.ts @@ -10,6 +10,7 @@ export const TYPE_TRANSACTION = [ { label: TRANSACTION_TYPE_ENUM.IBCConnectionOpenInit, value: TypeTransaction.IBCConnectionOpenInit }, { label: TRANSACTION_TYPE_ENUM.IBCCreateClient, value: TypeTransaction.IBCCreateClient }, { label: TRANSACTION_TYPE_ENUM.IBCChannelOpenAck, value: TypeTransaction.IBCChannelOpenAck }, + { label: TRANSACTION_TYPE_ENUM.IBCMsgConnectionOpenTry, value: TypeTransaction.IBCMsgConnectionOpenTry }, { label: TRANSACTION_TYPE_ENUM.Send, value: TypeTransaction.Send }, { label: TRANSACTION_TYPE_ENUM.MultiSend, value: TypeTransaction.MultiSend }, { label: TRANSACTION_TYPE_ENUM.Delegate, value: TypeTransaction.Delegate }, diff --git a/src/app/core/constants/transaction.enum.ts b/src/app/core/constants/transaction.enum.ts index 03a3a0d11..626217e7c 100644 --- a/src/app/core/constants/transaction.enum.ts +++ b/src/app/core/constants/transaction.enum.ts @@ -8,9 +8,10 @@ export enum TypeTransaction { IBCConnectionOpenInit = 'IBC Connect Open Init', IBCCreateClient = 'IBC Create Client', IBCChannelOpenAck = 'IBC Channel Open Ack', + IBCMsgConnectionOpenTry = 'Connection Open Try', Send = 'Send', Received = 'Receive', - MultiSend = 'Multi Send', + MultiSend = 'Multisend', Delegate = 'Delegate', Undelegate = 'Undelegate', Redelegate = 'Redelegate', @@ -56,6 +57,7 @@ export enum TRANSACTION_TYPE_ENUM { IBCConnectionOpenInit = '/ibc.core.connection.v1.MsgConnectionOpenInit', IBCCreateClient = '/ibc.core.client.v1.MsgCreateClient', IBCChannelOpenAck = '/ibc.core.channel.v1.MsgChannelOpenAck', + IBCMsgConnectionOpenTry = '/ibc.core.connection.v1.MsgConnectionOpenTry', Send = '/cosmos.bank.v1beta1.MsgSend', MultiSend = '/cosmos.bank.v1beta1.MsgMultiSend', Delegate = '/cosmos.staking.v1beta1.MsgDelegate', diff --git a/src/app/core/constants/url.constant.ts b/src/app/core/constants/url.constant.ts index 6c25312cf..f10992442 100644 --- a/src/app/core/constants/url.constant.ts +++ b/src/app/core/constants/url.constant.ts @@ -3,5 +3,8 @@ export const LCD_COSMOS = { TX: 'cosmos/tx/v1beta1', SLASHING: 'cosmos/slashing/v1beta1', BLOCK: 'cosmos/base/tendermint/v1beta1/blocks', - DISTRIBUTION: 'cosmos/distribution/v1beta1/community_pool' + DISTRIBUTION: 'cosmos/distribution/v1beta1/community_pool', + BALANCE: 'cosmos/bank/v1beta1/balances', + DELEGATION: 'cosmos/staking/v1beta1/delegations', + REWARD: 'cosmos/distribution/v1beta1/delegators' }; diff --git a/src/app/core/constants/validator.enum.ts b/src/app/core/constants/validator.enum.ts index 6b9ee39ff..b0f499848 100644 --- a/src/app/core/constants/validator.enum.ts +++ b/src/app/core/constants/validator.enum.ts @@ -14,4 +14,10 @@ export enum DIALOG_STAKE_MODE { Manage = 'manage', Undelegate = 'undelegate', Redelegate = 'redelegate', +} + +export enum VOTING_POWER_LEVEL { + GREEN = '1', + YELLOW = '2', + RED = '3', } \ No newline at end of file diff --git a/src/app/core/helpers/jwt.interceptor.ts b/src/app/core/helpers/jwt.interceptor.ts index 20f42869c..8be34ef25 100644 --- a/src/app/core/helpers/jwt.interceptor.ts +++ b/src/app/core/helpers/jwt.interceptor.ts @@ -1,32 +1,18 @@ import { Injectable } from '@angular/core'; -import { - HttpRequest, - HttpHandler, - HttpEvent, - HttpInterceptor, -} from '@angular/common/http'; +import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http'; import { Observable } from 'rxjs'; - import { AuthenticationService } from '../services/auth.service'; @Injectable() export class JwtInterceptor implements HttpInterceptor { - constructor( - private authenticationService: AuthenticationService, - ) { } + constructor(private authenticationService: AuthenticationService) {} - intercept( - request: HttpRequest, - next: HttpHandler - ): Observable> { - const currentUser = this.authenticationService.currentUserValue; - if (currentUser && currentUser.data && currentUser.data.access_token) { - request = request.clone({ - setHeaders: { - Authorization: `Bearer ${currentUser.data.access_token}`, - }, - }); - } - return next.handle(request); - } + intercept(request: HttpRequest, next: HttpHandler): Observable> { + const currentUser = this.authenticationService.currentUserValue; + request = request.clone({ + setHeaders: { + }, + }); + return next.handle(request); + } } diff --git a/src/app/core/models/common.model.ts b/src/app/core/models/common.model.ts index 769e2c236..8276ac5c3 100644 --- a/src/app/core/models/common.model.ts +++ b/src/app/core/models/common.model.ts @@ -13,6 +13,7 @@ export interface IResponsesError { error: { statusCode: number; message: string; + Message?: string; errorName: string; path: string; requestId: string; @@ -36,6 +37,7 @@ export class TableTemplate { suffix?: string; prefix?: string; headerWidth?: number; + isNameTag?: boolean; justify?: 'center' | 'flex-start' | 'flex-end' } @@ -125,17 +127,17 @@ export class ResponseDto { } export class CommonDataDto { - block_height?: number; + total_blocks?: number; block_time: string; bonded_tokens: number; community_pool: number; inflation: string; - total_txs_num: number; + total_transactions: number; total_validator_active_num: number; total_validator_num: number; bonded_tokens_format: number; community_pool_format: number; - supply: number; + total_aura: number; } export interface DataDelegateDto { @@ -165,4 +167,4 @@ export enum RangeType { day = 'd', hour = 'h', minute = 'm', -} \ No newline at end of file +} diff --git a/src/app/core/models/proposal.model.ts b/src/app/core/models/proposal.model.ts index 08cddb1fc..9f2dd893b 100644 --- a/src/app/core/models/proposal.model.ts +++ b/src/app/core/models/proposal.model.ts @@ -1,5 +1,5 @@ export interface IListVoteQuery { - proposalid: number; + proposalId: number; pageLimit: number; nextKey?: string; } diff --git a/src/app/core/pipes/common-pipe.module.ts b/src/app/core/pipes/common-pipe.module.ts index a9c46c6a2..713bbd954 100644 --- a/src/app/core/pipes/common-pipe.module.ts +++ b/src/app/core/pipes/common-pipe.module.ts @@ -9,6 +9,8 @@ import { StringEllipsis, ReplaceIpfs, ConvertUauraToAura, + convertLogAmount, + decodeData, } from './common.pipe'; import { JsonPipe } from './json.pipe'; @@ -23,6 +25,8 @@ import { JsonPipe } from './json.pipe'; BalanceOf, ReplaceIpfs, ConvertUauraToAura, + convertLogAmount, + decodeData ], imports: [CommonModule], exports: [ @@ -35,6 +39,8 @@ import { JsonPipe } from './json.pipe'; BalanceOf, ReplaceIpfs, ConvertUauraToAura, + convertLogAmount, + decodeData ], }) export class CommonPipeModule {} diff --git a/src/app/core/pipes/common.pipe.ts b/src/app/core/pipes/common.pipe.ts index b9e2ec44d..7519e2fa1 100644 --- a/src/app/core/pipes/common.pipe.ts +++ b/src/app/core/pipes/common.pipe.ts @@ -2,6 +2,9 @@ import { formatDate } from '@angular/common'; import { Pipe, PipeTransform } from '@angular/core'; import BigNumber from 'bignumber.js'; import { EnvironmentService } from '../data-services/environment.service'; +import { CommonService } from '../services/common.service'; +import { balanceOf } from '../utils/common/parsing'; +import { MaskPipe } from 'ngx-mask'; @Pipe({ name: 'calDate' }) export class pipeCalDate implements PipeTransform { @@ -27,7 +30,7 @@ export class pipeCalDate implements PipeTransform { export class PipeCutString implements PipeTransform { transform(value: string, start: number, end?: number): string { let endChar = end || 0; - if (value && value.length > (start + endChar)) { + if (value && value.length > start + endChar) { if (end) { const firstChar = value.substring(0, start); const lastChar = value.substring(value.length - end); @@ -76,7 +79,7 @@ export class CustomDate implements PipeTransform { @Pipe({ name: 'balanceOf' }) export class BalanceOf implements PipeTransform { transform(amount: string | number, decimal = 6) { - return +(new BigNumber(amount).toNumber() / Math.pow(10, 6)).toFixed(decimal); + return +(new BigNumber(amount).toNumber() / Math.pow(10, decimal)).toFixed(decimal); } } @@ -94,3 +97,27 @@ export class ConvertUauraToAura implements PipeTransform { return value / Math.pow(10, powNum); } } + +@Pipe({ name: 'convertLogAmount' }) +export class convertLogAmount implements PipeTransform { + constructor(private commonService: CommonService, private mask: MaskPipe) {} + transform(value: string, getDenomOnly = false): string { + let amount = value.match(/\d+/g)[0]; + let data = this.commonService.mappingNameIBC(value); + if (getDenomOnly) { + return data['display']; + } + amount = this.mask.transform(balanceOf(amount, data['decimals']), 'separator.6'); + if (+amount <= 0) { + return '-'; + } + return amount + `` + data['display'] + ``; + } +} + +@Pipe({ name: 'decodeData' }) +export class decodeData implements PipeTransform { + transform(value: string): string { + return atob(value); + } +} diff --git a/src/app/core/services/account.service.ts b/src/app/core/services/account.service.ts index 1e27b8cf3..f7777c2cf 100644 --- a/src/app/core/services/account.service.ts +++ b/src/app/core/services/account.service.ts @@ -3,6 +3,9 @@ import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; import { EnvironmentService } from '../data-services/environment.service'; import { CommonService } from './common.service'; +import { map } from 'rxjs/operators'; +import { TYPE_CW4973 } from '../constants/contract.constant'; +import { LENGTH_CHARACTER } from '../constants/common.constant'; @Injectable() export class AccountService extends CommonService { @@ -17,11 +20,76 @@ export class AccountService extends CommonService { } getAssetCW20ByOwner(payload): Observable { - return this.http.post(`${this.apiUrl}/cw20-tokens/get-by-owner/`,payload); + return this.http.post(`${this.apiUrl}/cw20-tokens/get-by-owner/`, payload); } getAssetCW721ByOwner(payload): Observable { - return this.http.post(`${this.apiUrl}/cw721-tokens/get-by-owner/`,payload); + if (payload.keyword?.length >= LENGTH_CHARACTER.ADDRESS) { + payload.contractAddress = payload.keyword; + } else if (payload.keyword?.length > 0) { + payload.token_id = payload.keyword; + } + const operationsDoc = ` + query queryAssetCW721( + $contract_address: String + $limit: Int = 10 + $tokenId: String = null + $owner: String = null + $offset: Int = 0 + ) { + ${this.envDB} { + cw721_token( + limit: $limit + offset: $offset + where: { + cw721_contract: { + smart_contract: { address: { _eq: $contract_address }, name: {_neq: "${TYPE_CW4973}"} } + } + token_id: { _eq: $tokenId } + owner: { _eq: $owner } + burned: {_eq: false} + } + order_by: [{ last_updated_height: desc }, { id: desc }] + ) { + id + token_id + owner + media_info + last_updated_height + created_at + burned + cw721_contract { + name + symbol + smart_contract { + name + address + } + } + } + cw721_token_aggregate(where: {cw721_contract: {smart_contract: {address: {_eq: $contract_address}, name: {_neq: "${TYPE_CW4973}"}}}, token_id: {_eq: $tokenId}, owner: {_eq: $owner}, burned: {_eq: false}}, order_by: [{last_updated_height: desc}, {id: desc}]) { + aggregate { + count + } + } + } + } + `; + return this.http + .post(this.graphUrl, { + query: operationsDoc, + variables: { + limit: payload?.limit || 20, + offset: payload.offset, + contract_address: payload?.contractAddress, + nextKeyLastUpdatedHeight: payload?.nextKey, + nextKeyId: payload?.nextKeyId, + tokenId: payload?.token_id, + owner: payload?.owner, + }, + operationName: 'queryAssetCW721', + }) + .pipe(map((res) => (res?.data ? res?.data[this.envDB] : null))); } getTotalAssets(account_id: string): Observable { diff --git a/src/app/core/services/block.service.ts b/src/app/core/services/block.service.ts index ed4e31c6f..ec04dacae 100644 --- a/src/app/core/services/block.service.ts +++ b/src/app/core/services/block.service.ts @@ -2,6 +2,7 @@ import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import * as _ from 'lodash'; import { Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; import { EnvironmentService } from '../data-services/environment.service'; import { CommonService } from './common.service'; @@ -9,46 +10,47 @@ import { CommonService } from './common.service'; export class BlockService extends CommonService { apiUrl = `${this.environmentService.configValue.beUri}`; chainInfo = this.environmentService.configValue.chain_info; - indexerUrl = `${this.environmentService.configValue.indexerUri}`; constructor(private http: HttpClient, private environmentService: EnvironmentService) { super(http, environmentService); } - blocksIndexer(pageLimit: string | number, blockHeight = null): Observable { - const params = _({ - chainid: this.chainInfo.chainId, - pageLimit, - blockHeight, - }) - .omitBy(_.isNull) - .omitBy(_.isUndefined) - .value(); - - return this.http.get(`${this.indexerUrl}/block`, { - params, - }); - } - - blockWithOperator(pageLimit: string | number, operatorAddress: string, nextKey = null): Observable { - const params = _({ - chainid: this.chainInfo.chainId, - pageLimit, - operatorAddress, - nextKey, - }) - .omitBy(_.isNull) - .omitBy(_.isUndefined) - .value(); - - return this.http.get(`${this.indexerUrl}/block`, { - params, - }); - } - getBlockAndTxs(type: string): Observable { - this.setURL(); const date = new Date(); return this.http.get(`${this.apiUrl}/metrics/transactions?range=${type}&timezone=${date.getTimezoneOffset()}`); } + + getDataBlock(payload) { + const operationsDoc = ` + query queryBlock($limit: Int = 100, $order: order_by = desc, $height: Int = null, $hash: String = null, $operatorAddress: String = null, $heightGT: Int = null, $heightLT: Int = null) { + ${this.envDB} { + block(limit: $limit, order_by: {height: $order}, where: {height: {_eq: $height, _gt: $heightGT, _lt: $heightLT}, hash: {_eq: $hash}, validator: {operator_address: {_eq: $operatorAddress}}}) { + data + validator { + operator_address + description + } + hash + height + time + } + } + } + `; + return this.http + .post(this.graphUrl, { + query: operationsDoc, + variables: { + limit: payload.limit, + order: 'desc', + hash: null, + height: payload.height, + operatorAddress: payload.address, + heightGT: null, + heightLT: payload.nextHeight, + }, + operationName: 'queryBlock', + }) + .pipe(map((res) => (res?.data ? res?.data[this.envDB] : null))); + } } diff --git a/src/app/core/services/chart.service.ts b/src/app/core/services/chart.service.ts deleted file mode 100644 index 59b551cb6..000000000 --- a/src/app/core/services/chart.service.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { HttpClient } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { BehaviorSubject, Observable } from 'rxjs'; -import {EnvironmentService} from "src/app/core/data-services/environment.service"; -import {CommonService} from "src/app/core/services/common.service"; - -@Injectable({ providedIn: 'root' }) -export class ChartService extends CommonService { - public dailyTransactionChart: Observable; - public uniqueAddressChart: Observable; - public dailyAddressChart: Observable; - - constructor( - private http: HttpClient, - private environmentService: EnvironmentService - ) { - super(http, environmentService); - // setInterval(()=> { - // this.dailyAddressChart = this.getDailyAddressChartData(); - // this.uniqueAddressChart = this.getUniqueAddressChartData(); - // this.dailyTransactionChart = this.getDailyTransactionChartData() - // }, 8000); - } - - // getDailyTransactionChartData(): Observable { - // // return this.http.get(`${this.apiUrl}/`); - // return ''; - // } - - // getUniqueAddressChartData(): Observable { - // // return this.http.get(`${this.apiUrl}/`); - // return ''; - // } - - // getDailyAddressChartData(): Observable { - // // return this.http.get(`${this.apiUrl}/`); - // return ''; - // } -} diff --git a/src/app/core/services/common.service.ts b/src/app/core/services/common.service.ts index 3dd54b633..9302ba488 100644 --- a/src/app/core/services/common.service.ts +++ b/src/app/core/services/common.service.ts @@ -2,22 +2,30 @@ import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import axios from 'axios'; import { formatDistanceToNowStrict } from 'date-fns'; -import * as _ from 'lodash'; import * as moment from 'moment'; -import { BehaviorSubject, Observable } from 'rxjs'; -import { CHART_RANGE, DATEFORMAT } from '../constants/common.constant'; +import { BehaviorSubject, Observable, Subject } from 'rxjs'; +import { DATEFORMAT } from '../constants/common.constant'; import { STATUS_VALIDATOR } from '../constants/validator.enum'; import { EnvironmentService } from '../data-services/environment.service'; import { formatTimeInWords, formatWithSchema } from '../helpers/date'; +import { Globals } from 'src/app/global/global'; @Injectable() export class CommonService { apiUrl = ''; coins = this._environmentService.configValue.coins; - indexerUrl = `${this._environmentService.configValue.indexerUri}`; private networkQuerySubject: BehaviorSubject; public networkQueryOb: Observable; chainInfo = this._environmentService.configValue.chain_info; + horoscopeApi = `${ + this._environmentService.configValue.horoscopeUrl + this._environmentService.configValue.horoscopePathApi + }`; + graphUrl = `${ + this._environmentService.configValue.horoscopeUrl + this._environmentService.configValue.horoscopePathGraphql + }`; + envDB = this._environmentService.configValue.horoscopeSelectedChain; + chainId = this._environmentService.configValue.chainId; + listNameTag = []; constructor(private _http: HttpClient, private _environmentService: EnvironmentService) { this.apiUrl = `${this._environmentService.configValue.beUri}`; @@ -35,31 +43,15 @@ export class CommonService { } status(): Observable { - this.setURL(); - return this._http.get(`${this.apiUrl}/status`); + return this._http.get(`${this.horoscopeApi}/dashboard-statistics?chainid=${this.chainId}`); } - getParamFromIndexer() { - const params = _({ - chainid: this.chainInfo.chainId, - module: 'gov', - }) - .omitBy(_.isNull) - .omitBy(_.isUndefined) - .value(); - - return this._http.get(`${this.indexerUrl}/param`, { - params, - }); + getParamTallyingFromLCD() { + return axios.get(`${this.chainInfo.rest}/cosmos/gov/v1beta1/params/tallying`); } - setURL() { - if (this.networkQuerySubject.value === 1) { - this.apiUrl = `${this._environmentService.configValue.fabric}`; - } - if (this.networkQuerySubject.value === 2) { - this.apiUrl = `${this._environmentService.configValue.beUri}`; - } + getAccountDistribution() { + return axios.get(`${this.chainInfo.rest}/cosmos/auth/v1beta1/module_accounts/distribution`); } getDateValue(time, isCustom = true) { @@ -92,36 +84,77 @@ export class CommonService { } } - getValidatorImg(identity: string) { - return axios.get(`https://keybase.io/_/api/1.0/user/lookup.json?key_suffix=${identity}&fields=pictures`); - } - mappingNameIBC(value) { - let result = value; + let result = {}; if (value.indexOf('ibc') >= 0) { + try { + if (!value.startsWith('ibc')) { + let temp = value?.match(/\d+/g)[0]; + value = value?.replace(temp, ''); + } + } catch {} + result = { display: value, decimals: 6 }; let temp = value.slice(value.indexOf('ibc')); - result = this.coins.find((k) => k.denom === temp)?.display || {}; + result = this.coins.find((k) => k.denom === temp) || {}; + result['display'] = result['display'] || value; } else { - result = this.chainInfo.currencies[0].coinDenom; + result = { display: this.chainInfo.currencies[0].coinDenom, decimals: 6 }; } return result; } - isValidatorJailed(jail, status) { - let result = jail && status === STATUS_VALIDATOR.Jail ? true : false; - return result; - } - getCommunityTax() { return axios.get(`${this._environmentService.configValue.chain_info.rest}/cosmos/distribution/v1beta1/params`); } - getTokenByCoinId(range: string, id: string) { - this.setURL(); - return this._http.get(`${this.apiUrl}/metrics/token?range=${range}&coidId=${id}`); - } - getDefaultImg() { return this._environmentService.configValue.image_s3 + 'images/aura__ntf-default-img.png'; } + + getListNameTag(payload) { + return this._http.post(`${this.apiUrl}/name-tag/get-name-tag`, payload); + } + + setNameTag(address, listNameTag = []) { + this.listNameTag = this.listNameTag?.length > 0 ? this.listNameTag : listNameTag; + const nameTag = this.listNameTag?.find((k) => k.address === address); + return nameTag?.name_tag || address; + } + + findNameTag(keySearch, listNameTag = []) { + this.listNameTag = this.listNameTag?.length > 0 ? this.listNameTag : listNameTag; + if (this.listNameTag?.length > 0) { + const result = this.listNameTag?.find((k) => k.name_tag?.trim() === keySearch?.trim())?.address || ''; + return result; + } + } + + checkDisplayTooltip(address): boolean { + let result = false; + const nameTag = this.listNameTag?.find((k) => k.address === address); + if (!nameTag || nameTag?.name_tag === address) { + result = true; + } + return result; + } + + showToolTip(element) { + if (element.classList.contains('disabled-hover')) { + element.classList.remove('disabled-hover'); + element.classList.add('show'); + setTimeout(function () { + element.classList.remove('show'); + element.classList.add('disabled-hover'); + }, 800); + } + } + + findUrlNameTag(address) { + let result = ''; + const nameTag = this.listNameTag?.find((k) => k.address === address); + if (nameTag?.enterpriseUrl?.length > 0) { + result = nameTag?.enterpriseUrl; + } + return result; + } } diff --git a/src/app/core/services/contract.service.ts b/src/app/core/services/contract.service.ts index 0631f095f..e6b7db006 100644 --- a/src/app/core/services/contract.service.ts +++ b/src/app/core/services/contract.service.ts @@ -1,61 +1,223 @@ import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import axios from 'axios'; -import * as _ from 'lodash'; import { BehaviorSubject, Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; +import { LCD_COSMOS } from 'src/app/core/constants/url.constant'; import { IResponsesTemplates } from 'src/app/core/models/common.model'; -import { DeployContractListReq, SmartContractListReq } from 'src/app/core/models/contract.model'; +import { SmartContractListReq } from 'src/app/core/models/contract.model'; +import { LENGTH_CHARACTER } from '../constants/common.constant'; import { EnvironmentService } from '../data-services/environment.service'; import { CommonService } from './common.service'; +import { Globals } from 'src/app/global/global'; @Injectable() export class ContractService extends CommonService { private contract$ = new BehaviorSubject(null); contractObservable: Observable; chainInfo = this.environmentService.configValue.chain_info; - indexerUrl = `${this.environmentService.configValue.indexerUri}`; apiUrl = `${this.environmentService.configValue.beUri}`; get contract() { return this.contract$.value; } - constructor(private http: HttpClient, private environmentService: EnvironmentService) { + constructor(private http: HttpClient, private environmentService: EnvironmentService, private global: Globals) { super(http, environmentService); - this.contractObservable = this.contract$.asObservable(); } - getListContract(data: any): Observable { - return this.http.post(`${this.apiUrl}/contracts`, data); + getListContract({ + codeId, + creator, + address, + name, + keyword, + limit, + offset, + contractType, + }: { + codeId?: number; + creator?: string; + address?: string; + name?: string; + keyword?: string; + limit?: number; + offset?: number; + contractType?: string[]; + }) { + let updateQuery = ''; + const isFilterCW4973 = contractType?.includes('CW4973'); + let typeQuery = 'code: {_or: [{type: {_in: $type}}, {_and: {type: {_is_null: true}}}]}'; + if (isFilterCW4973) { + typeQuery = contractType?.includes('') + ? '_or: [{code: {_or: [{type: {_in: $type}}, {_and: {type: {_is_null: true}}}]}}, {name: {_eq: "crates.io:cw4973"}}],' + : '_or: [{code: {type: {_in: $type}}}, {name: {_eq: "crates.io:cw4973"}}],'; + } else if (contractType?.includes('CW721') || contractType?.includes('CW20')) { + typeQuery = contractType?.includes('') + ? 'code: {_or: [{type: {_in: $type}}, {_and: {type: {_is_null: true}}}]}, name: {_neq: "crates.io:cw4973"}' + : 'code: {type: {_in: $type}}, name: {_neq: "crates.io:cw4973"}'; + } + + const addressNameTag = this.findNameTag(keyword, this.global.listNameTag); + if (addressNameTag?.length > 0) { + keyword = addressNameTag; + } + + if (keyword?.length >= LENGTH_CHARACTER.CONTRACT) { + address = keyword; + } else if (keyword?.length >= LENGTH_CHARACTER.ADDRESS) { + creator = keyword; + } else if (/^\d+$/.test(keyword)) { + codeId = +keyword; + name = '%' + keyword + '%'; + updateQuery = `_and: {_or: [{name: {_like: "${name}"}}, {code_id: {_eq: ${codeId}}}]},`; + } else if (keyword?.length > 0) { + name = '%' + keyword + '%'; + updateQuery = `name: {_ilike: "${name}"},`; + } else { + updateQuery = ''; + } + const operationsDoc = ` + query querySmartContractList($limit: Int = 100, $offset: Int = 0, $type: [String!], $address: String = null, $creator: String =null) { + ${this.envDB} { + smart_contract(limit: $limit, offset: $offset, order_by: {updated_at: desc}, where: {${typeQuery} ${updateQuery} address: {_eq: $address}, creator: {_eq: $creator}}) { + address + name + code_id + code { + type + code_id_verifications(order_by: {updated_at: desc}) { + compiler_version + verified_at + verification_status + } + } + updated_at + creator + } + smart_contract_aggregate(where: {${typeQuery} ${updateQuery} address: {_eq: $address}, creator: {_eq: $creator}}) { + aggregate { + count + } + } + } + } + `; + return this.http + .post(this.graphUrl, { + query: operationsDoc, + variables: { + limit: limit, + offset: offset, + type: contractType, + creator: creator, + address: address, + }, + operationName: 'querySmartContractList', + }) + .pipe(map((res) => (res?.data ? res?.data[this.envDB] : null))); } - getTransactionsIndexer( - pageLimit: string | number, - contractAddress = '', - type: string, - nextKey = null, - ): Observable { - const params = _({ - chainid: this.chainInfo.chainId, - searchType: type, - searchKey: '_contract_address', - searchValue: contractAddress, - pageLimit, - nextKey, - // countTotal: true, - }) - .omitBy(_.isNull) - .omitBy(_.isUndefined) - .value(); + loadContractDetail(contractAddress): Observable { + const contractDoc = ` + query queryContractDetail($contractAddress: String = null) { + ${this.envDB} { + smart_contract(limit: 1, where: {address: {_eq: $contractAddress}}) { + address + creator + instantiate_hash + name + cw721_contract { + name + symbol + } + cw20_contract { + name + symbol + } + code { + type + code_id + code_id_verifications(order_by: {updated_at: desc}) { + code_id + compiler_version + created_at + data_hash + execute_msg_schema + github_url + id + instantiate_msg_schema + query_msg_schema + updated_at + verification_status + verified_at + s3_location + } + } + } + } + } + `; + return this.http + .post(this.graphUrl, { + query: contractDoc, + variables: { + contractAddress: contractAddress, + }, + operationName: 'queryContractDetail', + }) + .pipe(map((res) => (res?.data ? res?.data[this.envDB] : null))); + } - return this.http.get(`${this.indexerUrl}/transaction`, { - params, - }); + getListContractByCode(payload): Observable { + const contractDoc = ` + query queryListContractByCodeID($limit: Int = 100, $offset: Int = 0, $code_id: Int = 0) { + ${this.envDB} { + smart_contract(limit: $limit, offset: $offset, where: {code_id: {_eq: $code_id}}, order_by: {updated_at: desc}) { + id + instantiate_hash + name + creator + created_at + code_id + address + code { + status + type + creator + code_id_verifications(order_by: {updated_at: desc}) { + verified_at + } + } + } + smart_contract_aggregate(where: {code_id: {_eq: $code_id}}) { + aggregate { + count + } + } + } + } + `; + return this.http + .post(this.graphUrl, { + query: contractDoc, + variables: { + code_id: payload.codeId, + limit: payload.limit, + offset: payload.offset, + }, + operationName: 'queryListContractByCodeID', + }) + .pipe(map((res) => (res?.data ? res?.data[this.envDB] : null))); } - getContractDetail(contractAddress): Observable { - return this.http.get(`${this.apiUrl}/contracts/${contractAddress}`); + getContractBalance(contractAddress) { + return axios.get(`${this.chainInfo.rest}/${LCD_COSMOS.BALANCE}/${contractAddress}`); + } + + setContract(contract: any) { + this.contract$.next(contract); } verifyCodeID(data: any): Observable { @@ -66,12 +228,6 @@ export class ContractService extends CommonService { return this.http.get(`${this.apiUrl}/contracts/verify/status/${codeID}`); } - loadContractDetail(contractAddress): void { - this.http.get(`${this.apiUrl}/contracts/${contractAddress}`).subscribe((res) => { - this.contract$.next(res); - }); - } - registerContractType(data: any): Observable { return this.http.post(`${this.apiUrl}/contract-codes`, data); } @@ -93,23 +249,145 @@ export class ContractService extends CommonService { ); } - getNFTDetail(contractAddress: string, tokenId): Observable { + getDetailCW4973(contractAddress: string, tokenId): Observable { return this.http.get(`${this.apiUrl}/contracts/${contractAddress}/nft/${tokenId}`); } - getListContractById(codeId: number): Observable { - return this.http.get(`${this.apiUrl}/contract-codes/${codeId}`); + getNFTDetail(address, tokenId): Observable { + const contractDoc = ` + query queryCW721Owner($address: String, $tokenId: String) { + ${this.envDB} { + data: smart_contract(where: {address: {_eq: $address}}) { + name + creator + address + cw721_contract { + name + minter + symbol + cw721_tokens(where: {token_id: {_eq: $tokenId}}) { + id + token_id + owner + media_info + burned + } + } + code { + code_id_verifications { + id + verification_status + } + } + } + } + } + `; + return this.http + .post(this.graphUrl, { + query: contractDoc, + variables: { + address: address, + tokenId: tokenId, + }, + operationName: 'queryCW721Owner', + }) + .pipe(map((res) => (res?.data ? res?.data[this.envDB] : null))); } getVerifyCodeStep(codeId: number): Observable { return this.http.get(`${this.apiUrl}/contracts/verify-code-id/${codeId}`); } - getListCodeID(data: any): Observable { - return this.http.post(`${this.apiUrl}/contracts/contract-code/list`, data); + getListCodeId(data: any): Observable { + let keyword = data?.keyword ? data?.keyword : null; + let subQuery = ''; + if (keyword) { + if (keyword.length >= LENGTH_CHARACTER.CONTRACT) { + subQuery = `smart_contracts: {address: {_eq: "${keyword}"}}`; + } else if (keyword.length >= LENGTH_CHARACTER.ADDRESS) { + subQuery = `creator: {_eq: "${keyword}"}`; + } else { + subQuery = `code_id: {_eq: ${keyword}}`; + } + } + + const query = `query queryContractCode($limit: Int, $offset: Int) { + ${this.envDB} { + code(where: {${subQuery}}, order_by: {code_id: desc}, limit: $limit, offset: $offset) { + code_id + creator + store_hash + type + status + created_at + code_id_verifications(order_by: {updated_at: desc}) { + verified_at + compiler_version + github_url + verification_status + } + smart_contracts { + name + } + smart_contracts_aggregate { + aggregate { + count + } + } + } + code_aggregate(where: { ${subQuery} }) { + aggregate { + count + } + } + } + }`; + return this.http + .post(this.graphUrl, { + query: query, + variables: { + limit: data?.limit, + offset: data?.offset, + }, + operationName: 'queryContractCode', + }) + .pipe(map((res) => (res?.data ? res?.data[this.envDB] : null))); } getCodeIDDetail(codeId: number): Observable { - return this.http.get(`${this.apiUrl}/contracts/contract-code/${codeId}`); + const query = `query queryContractCodeDetail($codeId: Int) { + ${this.envDB} { + code(where: {code_id: {_eq: ${codeId}}}) { + code_id + creator + store_hash + type + status + created_at + code_id_verifications(order_by: {updated_at: desc}) { + verified_at + compiler_version + github_url + verification_status + } + smart_contracts { + name + } + smart_contracts_aggregate { + aggregate { + count + } + } + } + } + }`; + return this.http + .post(this.graphUrl, { + query: query, + variables: {}, + operationName: 'queryContractCodeDetail', + }) + .pipe(map((res) => (res?.data ? res?.data[this.envDB] : null))); } } diff --git a/src/app/core/services/feegrant.service.ts b/src/app/core/services/feegrant.service.ts index 9253aa414..cdc40d93a 100644 --- a/src/app/core/services/feegrant.service.ts +++ b/src/app/core/services/feegrant.service.ts @@ -1,8 +1,7 @@ import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; -import axios from 'axios'; -import * as _ from 'lodash'; import { Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; import { LENGTH_CHARACTER } from '../constants/common.constant'; import { EnvironmentService } from '../data-services/environment.service'; import { CommonService } from './common.service'; @@ -10,57 +9,95 @@ import { CommonService } from './common.service'; @Injectable() export class FeeGrantService extends CommonService { chainInfo = this.environmentService.configValue.chain_info; - indexerUrl = `${this.environmentService.configValue.indexerUri}`; constructor(private http: HttpClient, private environmentService: EnvironmentService) { super(http, environmentService); } - getListFeeGrants(filterSearch, currentAddress, nextKey = null, isGranter = false): Observable { - let granter; - let grantee; - let isSearchAddress = true; - if (filterSearch['textSearch']?.length === LENGTH_CHARACTER.TRANSACTION) { - isSearchAddress = false; + getListFeeGrants( + { + limit, + hash, + isGranter, + granter, + grantee, + isActive, + offset, + }: { + limit?: number; + hash?: string; + isGranter?: boolean; + granter?: string; + grantee?: string; + isActive?: boolean; + offset?: number; + }, + textSearch = '', + ): Observable { + if (textSearch?.length > 0) { + if (textSearch?.length === LENGTH_CHARACTER.TRANSACTION) { + hash = textSearch; + } else { + if (isGranter) { + granter = textSearch; + } else { + grantee = textSearch; + } + } } - if (isGranter) { - grantee = currentAddress; - granter = isSearchAddress ? filterSearch['textSearch'] : null; + + let updateQuery = ''; + if (isActive) { + updateQuery = ', status: {_eq: "Available"}'; } else { - granter = currentAddress; - grantee = isSearchAddress ? filterSearch['textSearch'] : null; + updateQuery = ', status: {_neq: "Available"}'; } - const params = _({ - chainid: this.chainInfo.chainId, - granter: granter, - grantee: grantee, - status: filterSearch['isActive'] ? 'Available' : 'Use up,Revoked,Fail', - pageLimit: 100, - nextKey: nextKey, - txhash: !isSearchAddress ? filterSearch['textSearch'] : null, - }) - .omitBy(_.isNull) - .omitBy(_.isUndefined) - .value(); - - return this.http.get(`${this.indexerUrl}/feegrant/get-grants`, { - params, - }); - } - checkAddressValid(granter, grantee) { - const params = _({ - chainid: this.chainInfo.chainId, - grantee: grantee, - granter: granter, - status: 'Available', - pageLimit: 1, - expired: true, - }) - .omitBy(_.isNull) - .omitBy(_.isUndefined) - .value(); + const operationsDoc = ` + query queryFeegrant($limit: Int = 100, $offset: Int = 0, $granter: String = null, $hash: String = null, $grantee: String = null) { + ${this.envDB} { + feegrant(limit: $limit, offset: $offset, where: {granter: {_eq: $granter}, transaction: {hash: {_eq: $hash}}, grantee: {_eq: $grantee} ${updateQuery} }, order_by: {init_tx_id: desc}) { + grantee + granter + expiration + type + status + spend_limit + denom + init_tx_id + transaction { + hash + timestamp + } + revoke_tx { + hash + } + feegrant_histories(where: {action: {_eq: "create"}}) { + id + amount + } + } + feegrant_aggregate(where: {granter: {_eq: $granter}, transaction: {hash: {_eq: $hash}}, grantee: {_eq: $grantee} ${updateQuery} }) { + aggregate { + count + } + } + } + } + `; - return axios.get(`${this.indexerUrl}/feegrant/get-grants`, { params }); + return this.http + .post(this.graphUrl, { + query: operationsDoc, + variables: { + limit: limit || 20, + granter: granter || null, + hash: hash || null, + grantee: grantee || null, + offset: offset || 0, + }, + operationName: 'queryFeegrant', + }) + .pipe(map((res) => (res?.data ? res?.data[this.envDB] : null))); } } diff --git a/src/app/core/services/proposal.service.ts b/src/app/core/services/proposal.service.ts index 6c54fb220..63b09abcb 100644 --- a/src/app/core/services/proposal.service.ts +++ b/src/app/core/services/proposal.service.ts @@ -5,13 +5,13 @@ import { Observable, Subject } from 'rxjs'; import { VOTE_OPTION } from '../constants/proposal.constant'; import { EnvironmentService } from '../data-services/environment.service'; import { CommonService } from './common.service'; +import { map } from 'rxjs/operators'; @Injectable() export class ProposalService extends CommonService { chainInfo = this.environmentService.configValue.chain_info; - indexerUrl = `${this.environmentService.configValue.indexerUri}`; + maxValidator = `${this.environmentService.configValue.maxValidator}`; reloadList$ = new Subject(); - pageIndexObj = {}; reloadList() { this.reloadList$.next(true); @@ -21,79 +21,218 @@ export class ProposalService extends CommonService { super(http, environmentService); } - getVotes(payload) { - const params = _({ - chainid: this.chainInfo.chainId, - searchValue: payload.proposalId, - searchType: 'proposal_vote', - searchKey: 'proposal_id', - ['queryAnd[]']: 'transfer.sender='+payload.wallet, - }) - .omitBy(_.isNull) - .omitBy(_.isUndefined) - .value(); - - return this.http.get(`${this.indexerUrl}/transaction`, { params }); + getValidatorVotesFromIndexer( + proposalId: number, + { limit, offset }: { limit: number; offset?: number; voteOption?: string }, + ): Observable { + const operationsDoc = ` + query queryValidatorVotes($proposalId: Int = null, $limit: Int = 10, $offset: Int = 0) { + ${this.envDB} { + validator(where: {status: {_eq: "BOND_STATUS_BONDED"}}, order_by: {percent_voting_power: desc}, limit: $limit, offset: $offset) { + vote(where: {proposal_id: {_eq: $proposalId}}) { + id + vote_option + txhash + proposal_id + updated_at + } + description + operator_address + image_url + } + } + } + `; + return this.http + .post(this.graphUrl, { + query: operationsDoc, + variables: { + proposalId: proposalId, + limit: limit, + offset: offset || 0, + }, + operationName: 'queryValidatorVotes', + }) + .pipe(map((res) => (res?.data ? res?.data[this.envDB] : null))); } - getValidatorVotesFromIndexer(proposalid): Observable { - const params = _({ - chainid: this.chainInfo.chainId, - proposalid: proposalid, - }) - .omitBy(_.isNull) - .omitBy(_.isUndefined) - .value(); - - return this.http.get(`${this.indexerUrl}/votes/validators`, { params }); + getProposalData({ + limit, + offset, + proposalId, + type, + }: { + limit: number; + offset?: number; + proposalId?: number; + type?: string; + }) { + const operationsDoc = ` + query queryProposal($limit: Int = 10, $offset: Int = 0, $order: order_by = desc, $proposalId: Int = null, $type: String = null, $n_status : String = "PROPOSAL_STATUS_NOT_ENOUGH_DEPOSIT") { + ${this.envDB} { + proposal(limit: $limit, offset: $offset, where: {proposal_id: {_eq: $proposalId}, type: {_eq: $type}, status: {_neq: $n_status}}, order_by: {proposal_id: $order}) { + content + deposit_end_time + description + initial_deposit + proposal_id + proposer_address + count_vote + proposer { + description + operator_address + account_address + } + status + submit_time + tally + title + total_deposit + turnout + type + updated_at + voting_end_time + voting_start_time + } + proposal_aggregate(where: {proposal_id: {_eq: $proposalId}, type: {_eq: $type}, status: {_neq: "PROPOSAL_STATUS_NOT_ENOUGH_DEPOSIT"}}) { + aggregate { + count + } + } + } + } + `; + return this.http + .post(this.graphUrl, { + query: operationsDoc, + variables: { + n_status: 'PROPOSAL_STATUS_NOT_ENOUGH_DEPOSIT', + order: 'desc', + limit, + offset, + proposalId, + type, + }, + operationName: 'queryProposal', + }) + .pipe(map((res) => (res?.data ? res?.data[this.envDB] : null))); } - getDepositors(payload) { - const params = _({ - chainid: this.chainInfo.chainId, - searchValue: payload.proposalId, - searchType: 'proposal_deposit', - searchKey: 'proposal_id', - pageLimit: payload.pageLimit, - nextKey: payload.nextKey, - // countTotal: true, - }) - .omitBy(_.isNull) - .omitBy(_.isUndefined) - .value(); - - return this.http.get(`${this.indexerUrl}/transaction`, { params }); + getCountProposal() { + const operationsDoc = ` + query getCountProposal { + ${this.envDB} { + proposal_aggregate { + aggregate { + count + } + } + } + } + `; + return this.http + .post(this.graphUrl, { + query: operationsDoc, + variables: {}, + operationName: 'getCountProposal', + }) + .pipe(map((res) => (res?.data ? res?.data[this.envDB] : null))); } getListVoteFromIndexer(payload, option): Observable { - const params = _({ - chainid: this.chainInfo.chainId, - nextKey: payload.nextKey, - reverse: false, - pageLimit: payload.pageLimit, - answer: option, - proposalid: payload.proposalid, - }) - .omitBy(_.isNull) - .omitBy(_.isUndefined) - .value(); - - return this.http.get(`${this.indexerUrl}/votes`, { params }); + const operationsDoc = ` + query queryVote($limit: Int = 10, $offset: Int = 0, $order: order_by = desc, $proposalId: Int = null, $voteOption: String = null) { + ${this.envDB} { + vote(limit: $limit, offset: $offset, where: {proposal_id: {_eq: $proposalId}, vote_option: {_eq: $voteOption}}, order_by: {height: $order}) { + height + proposal_id + txhash + vote_option + voter + transaction { + timestamp + } + } + vote_aggregate(where: {proposal_id: {_eq: $proposalId}, vote_option: {_eq: $voteOption}}) { + aggregate { + count + } + } + } + } + `; + return this.http + .post(this.graphUrl, { + query: operationsDoc, + variables: { + limit: payload.pageLimit, + order: 'desc', + proposalId: payload.proposalId, + voteOption: option || null, + offset: payload?.offset, + }, + operationName: 'queryVote', + }) + .pipe(map((res) => (res?.data ? res?.data[this.envDB] : null))); } - getProposalList(pageLimit = 20, nextKey = null, proposalId = null): Observable { - const params = _({ - chainid: this.chainInfo.chainId, - pageLimit: pageLimit, - nextKey, - reverse: false, - proposalId: proposalId, - }) - .omitBy(_.isNull) - .omitBy(_.isUndefined) - .value(); + getProposalVoteTotal(proposalId: number) { + const operationsDoc = ` + query queryProposalVoteTotal($proposalId: Int) { + ${this.envDB} { + ALL: vote_aggregate(where: {proposal_id: {_eq: $proposalId}}) { + ...aggregateCountFragment + } + VOTE_OPTION_YES: vote_aggregate(where: {proposal_id: {_eq: $proposalId}, vote_option: {_eq: "VOTE_OPTION_YES"}}) { + ...aggregateCountFragment + } + VOTE_OPTION_ABSTAIN: vote_aggregate(where: {proposal_id: {_eq: $proposalId}, vote_option: {_eq: "VOTE_OPTION_ABSTAIN"}}) { + ...aggregateCountFragment + } + VOTE_OPTION_NO: vote_aggregate(where: {proposal_id: {_eq: $proposalId}, vote_option: {_eq: "VOTE_OPTION_NO"}}) { + ...aggregateCountFragment + } + VOTE_OPTION_NO_WITH_VETO: vote_aggregate(where: {proposal_id: {_eq: $proposalId}, vote_option: {_eq: "VOTE_OPTION_NO_WITH_VETO"}}) { + ...aggregateCountFragment + } + } + } + + fragment aggregateCountFragment on ${this.envDB}_vote_aggregate { + aggregate { + count + } + } + `; + return this.http + .post(this.graphUrl, { + query: operationsDoc, + variables: { proposalId }, + operationName: 'queryProposalVoteTotal', + }) + .pipe(map((res) => (res?.data ? res?.data[this.envDB] : null))); + } - return this.http.get(`${this.indexerUrl}/proposal`, { params }); + getVotedResult(payload) { + const operationsDoc = ` + query getVotedResult($proposalId: Int = 0, $voter: String = null) { + ${this.envDB} { + vote(where: {proposal_id: {_eq: $proposalId}, transaction: {votes: {voter: {_eq: $voter}}}}) { + vote_option + } + } + } + `; + return this.http + .post(this.graphUrl, { + query: operationsDoc, + variables: { + proposalId: payload.proposal_id, + voter: payload.address, + }, + operationName: 'getVotedResult', + }) + .pipe(map((res) => (res?.data ? res?.data[this.envDB] : null))); } getVoteMessageByConstant(option: any) { @@ -103,19 +242,19 @@ export class ProposalService extends CommonService { let result = ''; switch (option) { case 1: - result = VOTE_OPTION.VOTE_OPTION_YES; + result = VOTE_OPTION.YES; break; case 2: - result = VOTE_OPTION.VOTE_OPTION_ABSTAIN; + result = VOTE_OPTION.ABSTAIN; break; case 3: - result = VOTE_OPTION.VOTE_OPTION_NO; + result = VOTE_OPTION.NO; break; case 4: - result = VOTE_OPTION.VOTE_OPTION_NO_WITH_VETO; + result = VOTE_OPTION.NO_WITH_VETO; break; default: - result = VOTE_OPTION.VOTE_OPTION_EMPTY; + result = VOTE_OPTION.EMPTY; break; } return result; diff --git a/src/app/core/services/soulbound.service.ts b/src/app/core/services/soulbound.service.ts index 5ec4cd212..4b1f7841b 100644 --- a/src/app/core/services/soulbound.service.ts +++ b/src/app/core/services/soulbound.service.ts @@ -4,11 +4,11 @@ import * as _ from 'lodash'; import { Observable } from 'rxjs'; import { EnvironmentService } from '../data-services/environment.service'; import { CommonService } from './common.service'; +import { map } from 'rxjs/operators'; @Injectable() export class SoulboundService extends CommonService { chainInfo = this.environmentService.configValue.chain_info; - indexerUrl = `${this.environmentService.configValue.indexerUri}`; apiUrl = `${this.environmentService.configValue.beUri}`; constructor(private http: HttpClient, private environmentService: EnvironmentService) { @@ -60,10 +60,57 @@ export class SoulboundService extends CommonService { } getListABT(payload): Observable { - const params = _(payload).omitBy(_.isNull).omitBy(_.isUndefined).value(); - return this.http.get(`${this.apiUrl}/soulbound-token/tokens-list`, { - params - }); + const operationsDoc = ` + query queryCW4973ListToken( + $keyword: String, + $limit: Int, + $offset: Int + ) { + ${this.envDB} { + cw721_contract( + limit: $limit, + where: { + smart_contract: { + name: {_eq: "crates.io:cw4973"} + }, + _or: [{name: {_ilike: $keyword}}, {smart_contract: {_or:[{address: {_like: $keyword}}, {creator: {_like: $keyword}}]}}] + }, + offset: $offset, + order_by: {updated_at: desc} + ) { + name + symbol + smart_contract { + address + name + creator + } + } + cw721_contract_aggregate( + where: { + smart_contract: { + name: {_eq: "crates.io:cw4973"} + }, + _or: [{name: {_ilike: $keyword}}, {smart_contract: {_or:[{address: {_like: $keyword}}, {creator: {_like: $keyword}}]}}] + }) { + aggregate { + count + } + } + } + }`; + + return this.http + .post(this.graphUrl, { + query: operationsDoc, + variables: { + limit: payload.limit, + offset: payload.offset, + keyword: payload.keyword ? `%${payload.keyword}%` : null, + }, + operationName: 'queryCW4973ListToken', + }) + .pipe(map((res) => (res?.data ? res?.data[this.envDB] : null))); } updateNotify(contractAddress: string, tokenId): Observable { diff --git a/src/app/core/services/token.service.ts b/src/app/core/services/token.service.ts index 105999cbc..88f968514 100644 --- a/src/app/core/services/token.service.ts +++ b/src/app/core/services/token.service.ts @@ -1,106 +1,298 @@ import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import axios from 'axios'; -import * as _ from 'lodash'; import { Observable } from 'rxjs'; -import { LENGTH_CHARACTER } from '../constants/common.constant'; +import { map } from 'rxjs/operators'; +import { LCD_COSMOS } from '../constants/url.constant'; import { EnvironmentService } from '../data-services/environment.service'; import { RangeType } from '../models/common.model'; import { CommonService } from './common.service'; -import { LCD_COSMOS } from '../constants/url.constant'; @Injectable() export class TokenService extends CommonService { chainInfo = this.environmentService.configValue.chain_info; - indexerUrl = `${this.environmentService.configValue.indexerUri}`; constructor(private http: HttpClient, private environmentService: EnvironmentService) { super(http, environmentService); } getListToken(payload): Observable { - return this.http.post(`${this.apiUrl}/cw20-tokens`, payload); + const operationsDoc = `query queryCW20ListToken($name: String, $address: String, $limit: Int, $offset: Int, $date: date) { + ${this.envDB} { + cw20_contract(where: {_or: [{name: {_ilike: $name}}, {smart_contract: {address: {_eq: $address}}}]}, limit: $limit, offset: $offset) { + marketing_info + name + symbol + smart_contract { + address + } + cw20_holders_aggregate(where: {amount: {_gt: "0"}}) { + aggregate { + count + } + } + cw20_total_holder_stats(where: {date: {_gte: $date}}) { + date + total_holder + } + } + cw20_contract_aggregate(where: {_or: [{name: {_ilike: $name}}, {smart_contract: {address: {_eq: $address}}}]}) { + aggregate { + count + } + } + } + }`; + return this.http + .post(this.graphUrl, { + query: operationsDoc, + variables: { + name: payload?.keyword ? `%${payload?.keyword}%` : null, + address: payload?.keyword ? payload?.keyword : null, + limit: payload?.limit, + offset: payload?.offset, + date: payload?.date + }, + operationName: 'queryCW20ListToken', + }) + .pipe(map((res) => (res?.data ? res?.data[this.envDB] : null))); } - getListCW721Token(payload): Observable { - return this.http.post(`${this.apiUrl}/cw721-tokens`, payload); + getTokenMarketData(payload = {}): Observable { + return this.http.post(`${this.apiUrl}/cw20-tokens/token-market`, payload); } - getTokenDetail(address): Observable { - return this.http.get(`${this.apiUrl}/contracts/token/${address}`); + getListCW721Token(payload, textSearch = null): Observable { + if (textSearch?.length > 0) { + textSearch = '%' + textSearch + '%'; + } + let querySort = `, order_by: {${payload.sort_column}: ${payload.sort_order}}`; + const operationsDoc = ` + query queryListCW721($limit: Int = 10, $offset: Int = 0, $contract_address: String = null, $name: String = null) { + ${this.envDB} { + list_token: cw721_contract_stats(limit: $limit, offset: $offset ${querySort}, where: {_or:[ {cw721_contract: {smart_contract: {address: {_like: $contract_address}}}}, { cw721_contract: {name: {_ilike: $name}}} ]}) { + transfer_24h + total_activity + cw721_contract { + name + symbol + smart_contract { + address + } + } + } + total_token: cw721_contract_stats_aggregate (where: {_or:[ {cw721_contract: {smart_contract: {address: {_like: $contract_address}}}}, { cw721_contract: {name: {_ilike: $name}}} ]}) { + aggregate { + count + } + } + } + } + `; + return this.http + .post(this.graphUrl, { + query: operationsDoc, + variables: { + limit: payload.limit || 20, + offset: payload.offset || 0, + contract_address: textSearch || null, + name: textSearch || null, + }, + operationName: 'queryListCW721', + }) + .pipe(map((res) => (res?.data ? res?.data[this.envDB] : null))); } - getTokenCW721Detail(address): Observable { - return this.http.get(`${this.apiUrl}/cw721-tokens/${address}`); + getTokenDetail(address, date): Observable { + const operationsDoc = `query queryCW20Detail($address: String, $date: date) { + ${this.envDB} { smart_contract(where: {address: {_eq: $address}}) { + address + cw20_contract { + name + symbol + marketing_info + decimal + cw20_holders { + address + amount + } + cw20_total_holder_stats(where: {date: {_gte: $date}}) { + date + total_holder + } + } + code { + code_id_verifications(order_by: {updated_at: desc}) { + verification_status + } + } + } + } + }`; + + return this.http + .post(this.graphUrl, { + query: operationsDoc, + variables: { + address: address, + date: date + }, + operationName: 'queryCW20Detail', + }) + .pipe(map((res) => (res?.data ? res?.data[this.envDB] : null))); } - getListTokenTransferIndexer(pageLimit: string | number, contractAddress: string, filterData: any, nextKey = null) { - const params = _({ - chainid: this.chainInfo.chainId, - searchType: 'execute', - searchKey: '_contract_address', - searchValue: contractAddress, - needFullLog: true, - pageLimit, - nextKey, - // countTotal: true, - }) - .omitBy(_.isNull) - .omitBy(_.isUndefined) - .value(); - - if (filterData?.keyWord) { - if ( - filterData?.keyWord.length === LENGTH_CHARACTER.TRANSACTION && - filterData?.keyWord == filterData?.keyWord.toUpperCase() - ) { - params['txHash'] = filterData?.keyWord; - } else if (filterData['isSearchWallet']) { - params['addressInContract'] = filterData?.keyWord; - } else { - params['query'] = 'wasm.token_id=' + filterData?.keyWord; + getListTokenNFTFromIndexer(payload): Observable { + const operationsDoc = ` + query queryListInventory( + $contract_address: String + $limit: Int = 10 + $tokenId: String = null + $owner: String = null + $offset: Int = 0 + ) { + ${this.envDB} { + cw721_token( + limit: $limit + offset: $offset + where: { + cw721_contract: { + smart_contract: { address: { _eq: $contract_address } } + } + token_id: { _eq: $tokenId } + owner: { _eq: $owner } + burned: {_eq: false} + } + order_by: [{ last_updated_height: desc }, { id: desc }] + ) { + id + token_id + owner + media_info + last_updated_height + created_at + burned + } + cw721_token_aggregate( + where: { + cw721_contract: { + smart_contract: { + address: { _eq: $contract_address } + } + } + token_id: { _eq: $tokenId } + owner: { _eq: $owner } + burned: {_eq: false} + } + ) { + aggregate { + count + } + } } } - - return axios.get(`${this.indexerUrl}/transaction`, { params }); + `; + return this.http + .post(this.graphUrl, { + query: operationsDoc, + variables: { + limit: payload?.limit || 20, + offset: payload.offset, + contract_address: payload?.contractAddress, + tokenId: payload?.token_id, + owner: payload?.owner, + }, + operationName: 'queryListInventory', + }) + .pipe(map((res) => (res?.data ? res?.data[this.envDB] : null))); } - getListTokenNFTFromIndexer(payload): Observable { - const params = _({ - chainid: this.chainInfo.chainId, - owner: payload.owner, - tokenId: payload.token_id, - contractAddress: payload.contractAddress, - pageLimit: payload.pageLimit, - pageOffset: payload.pageOffset, - // countTotal: true, - contractType: payload.contractType, - isBurned: false, - }) - .omitBy(_.isNull) - .omitBy(_.isUndefined) - .value(); - return this.http.get(`${this.indexerUrl}/asset/getByOwner`, { - params, - }); + countTotalTokenCW721(contract_address): Observable { + const operationsDoc = ` + query queryCountTotalToken721($contract_address: String) { + ${this.envDB} { + cw721_token_aggregate(where: {cw721_contract: {smart_contract: {address: {_eq: $contract_address}}}, burned: {_eq: false}}) { + aggregate { + count + } + } + } + } + `; + return this.http + .post(this.graphUrl, { + query: operationsDoc, + variables: { + contract_address: contract_address, + }, + operationName: 'queryCountTotalToken721', + }) + .pipe(map((res) => (res?.data ? res?.data[this.envDB] : null))); } getListTokenHolder( limit: string | number, offset: string | number, - contractType: string, contractAddress: string, ): Observable { - let url = `${this.indexerUrl}/asset/holder?chainid=${this.chainInfo.chainId}&contractType=${contractType}&contractAddress=${contractAddress}&pageOffset=${offset}&pageLimit=${limit}&countTotal=true&reverse=false`; - return this.http.get(url); - } + const operationsDoc = `query queryCW20ListHolder($address: String, $limit: Int, $offset: Int) { + ${this.envDB} { + cw20_holder(where: {cw20_contract: {smart_contract: {address: {_eq: $address}}}, amount: {_gt: "0"}}, limit: $limit, offset: $offset, order_by: {amount: desc}) { + amount + address + cw20_contract { + total_supply + decimal + } + } + cw20_holder_aggregate(where: {cw20_contract: {smart_contract: {address: {_eq: $address}}}, amount: {_gt: "0"}}) { + aggregate { + count + } + } + } + } + `; - getContractDetail(tokenAddress): Observable { - return this.http.get(`${this.apiUrl}/contracts/${tokenAddress}`); + return this.http + .post(this.graphUrl, { + query: operationsDoc, + variables: { + limit: limit, + offset: offset, + address: contractAddress, + }, + operationName: 'queryCW20ListHolder', + }) + .pipe(map((res) => (res?.data ? res?.data[this.envDB] : null))); } - getNFTDetail(contractAddress: string, tokenId): Observable { - return this.http.get(`${this.apiUrl}/cw721-tokens/${contractAddress}/nft/${tokenId}`); + getListTokenHolderNFT(payload) { + const operationsDoc = ` + query queryListHolderNFT($contract_address: String, $limit: Int = 10) { + ${this.envDB} { + view_count_holder_cw721(limit: $limit, where: {contract_address: {_eq: $contract_address}}, order_by: {count: desc}) { + count + owner + } + view_count_holder_cw721_aggregate(where: {contract_address: {_eq: $contract_address}}) { + aggregate { + count + } + } + } + } + `; + return this.http + .post(this.graphUrl, { + query: operationsDoc, + variables: { + limit: payload?.limit || 20, + contract_address: payload?.contractAddress, + }, + operationName: 'queryListHolderNFT', + }) + .pipe(map((res) => (res?.data ? res?.data[this.envDB] : null))); } getPriceToken(tokenId: string): Observable { diff --git a/src/app/core/services/transaction.service.ts b/src/app/core/services/transaction.service.ts index 7fa2795d0..bbbc083f1 100644 --- a/src/app/core/services/transaction.service.ts +++ b/src/app/core/services/transaction.service.ts @@ -1,8 +1,8 @@ import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import axios from 'axios'; -import * as _ from 'lodash'; import { Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; import { LCD_COSMOS } from '../constants/url.constant'; import { EnvironmentService } from '../data-services/environment.service'; import { CommonService } from './common.service'; @@ -11,60 +11,269 @@ import { CommonService } from './common.service'; export class TransactionService extends CommonService { apiUrl = `${this.environmentService.configValue.beUri}`; chainInfo = this.environmentService.configValue.chain_info; - indexerUrl = `${this.environmentService.configValue.indexerUri}`; constructor(private http: HttpClient, private environmentService: EnvironmentService) { super(http, environmentService); } - txsIndexer(pageLimit: string | number, offset: string | number, txHash = ''): Observable { - const params = _({ - chainid: this.chainInfo.chainId, - pageLimit, - offset, - txHash, - }) - .omitBy(_.isNull) - .omitBy(_.isUndefined) - .value(); - - return this.http.get(`${this.indexerUrl}/transaction`, { - params, - }); + getListTx(payload) { + const operationsDoc = ` + query queryListTopTransaction( + $limit: Int = 100 + $order: order_by = desc + $heightGT: Int = null + $heightLT: Int = null + $indexGT: Int = null + $indexLT: Int = null + $hash: String = null + $height: Int = null + ) { + ${this.envDB} { + transaction( + limit: $limit + where: { + hash: { _eq: $hash } + height: { _eq: $height } + _and: [ + { height: { _gt: $heightGT } } + { index: { _gt: $indexGT } } + { height: { _lt: $heightLT } } + { index: { _lt: $indexLT } } + ] + } + order_by: [{ height: $order}, {index: $order }] + ) { + id + height + hash + timestamp + code + gas_used + gas_wanted + data + } + } + } + `; + return this.http + .post(this.graphUrl, { + query: operationsDoc, + variables: { + limit: payload.limit, + order: 'desc', + hash: payload.hash, + value: payload.value, + key: payload.key, + heightGT: null, + heightLT: payload.heightLT, + indexGT: null, + indexLT: null, + height: null, + }, + operationName: 'queryListTopTransaction', + }) + .pipe(map((res) => (res?.data ? res?.data[this.envDB] : null))); } - txsDetailLcd(txhash: string) { - return axios.get(`${this.chainInfo.rest}/${LCD_COSMOS.TX}/txs/${txhash}`); + getListTxCondition(payload) { + const operationsDoc = ` + query queryTransaction( + $limit: Int = 100 + $order: order_by = desc + $compositeKey: String = null + $value: String = null + $key: String = null + $compositeKeyIn: [String!] = null + $valueIn: [String!] = null + $keyIn: [String!] = null + $heightGT: Int = null + $heightLT: Int = null + $indexGT: Int = null + $indexLT: Int = null + $hash: String = null + $height: Int = null + ) { + ${this.envDB} { + transaction( + limit: $limit + where: { + hash: { _eq: $hash } + height: { _eq: $height } + event_attribute_index: { + value: { _eq: $value, _in: $valueIn } + composite_key: { _eq: $compositeKey, _in: $compositeKeyIn } + key: { _eq: $key, _in: $keyIn } + } + _and: [ + { height: { _gt: $heightGT } } + { index: { _gt: $indexGT } } + { height: { _lt: $heightLT } } + { index: { _lt: $indexLT } } + ] + } + order_by: [{ height: $order}, {index: $order }] + ) { + id + height + hash + timestamp + code + gas_used + gas_wanted + data + } + } + } + `; + return this.http + .post(this.graphUrl, { + query: operationsDoc, + variables: { + limit: payload.limit, + order: 'desc', + hash: payload.hash, + compositeKey: payload.compositeKey, + value: payload.value, + key: payload.key, + heightGT: null, + heightLT: payload.heightLT, + indexGT: null, + indexLT: null, + height: null, + }, + operationName: 'queryTransaction', + }) + .pipe(map((res) => (res?.data ? res?.data[this.envDB] : null))); } - getAccountTxFromHoroscope(chainId: string, address: string, pageLimit = 10, nextKey = null): Observable { - const params = _({ - chainid: chainId, - address, - pageLimit, - nextKey, - }) - .omitBy(_.isNull) - .omitBy(_.isUndefined) - .value(); - - return this.http.get(`${this.indexerUrl}/transaction`, { - params, - }); + getListTxMultiCondition(payload) { + const operationsDoc = ` + query queryTransactionMultiCondition( + $limit: Int = 100 + $order: order_by = desc + $compositeKey: String = null + $value: String = null + $key: String = null + $compositeKey2: String = null + $value2: String = null + $key2: String = null + $compositeKeyIn: [String!] = null + $valueIn: [String!] = null + $keyIn: [String!] = null + $compositeKeyIn2: [String!] = null + $valueIn2: [String!] = null + $keyIn2: [String!] = null + $heightGT: Int = null + $heightLT: Int = null + $indexGT: Int = null + $indexLT: Int = null + $hash: String = null + $height: Int = null + ) { + ${this.envDB} { + transaction( + limit: $limit + where: { + hash: { _eq: $hash } + height: { _eq: $height } + event_attribute_index: { + value: { _eq: $value, _in: $valueIn } + composite_key: { _eq: $compositeKey, _in: $compositeKeyIn } + key: { _eq: $key, _in: $keyIn } + } + _and: [ + { height: { _gt: $heightGT } } + { index: { _gt: $indexGT } } + { height: { _lt: $heightLT } } + { index: { _lt: $indexLT } } + { + event_attribute_index: { + value: { _eq: $value2, _in: $valueIn2 } + composite_key: { _eq: $compositeKey2, _in: $compositeKeyIn2 } + key: { _eq: $key2, _in: $keyIn2 } + } + } + ] + } + order_by: [{ height: $order}, {index: $order }] + ) { + id + height + hash + timestamp + code + gas_used + gas_wanted + data + } + } + } + `; + return this.http + .post(this.graphUrl, { + query: operationsDoc, + variables: { + limit: payload.limit, + order: 'desc', + hash: payload.hash, + compositeKey: payload.compositeKey, + value: payload.value, + key: payload.key, + heightGT: null, + heightLT: payload.heightLT, + indexGT: null, + indexLT: null, + height: null, + compositeKey2: payload.compositeKey2, + value2: payload.value2, + key2: payload.key2, + }, + operationName: 'queryTransactionMultiCondition', + }) + .pipe(map((res) => (res?.data ? res?.data[this.envDB] : null))); } - getListIBCSequence(sequence): Observable { - const params = _({ - chainid: this.chainInfo.chainId, - pageLimit: 20, - sequenceIBC: sequence, - }) - .omitBy(_.isNull) - .omitBy(_.isUndefined) - .value(); + txsDetailLcd(txhash: string) { + return axios.get(`${this.chainInfo.rest}/${LCD_COSMOS.TX}/txs/${txhash}`); + } - return this.http.get(`${this.indexerUrl}/transaction`, { - params, - }); + getListIBCSequence(sequence, channel): Observable { + const operationsDoc = ` + query queryListSequence($limit: Int, $compositeKey: [String!] = "", $value: String = "", $channel: String = "") { + ${this.envDB} { + transaction(limit: $limit, where: {event_attributes: {composite_key: {_in: ["acknowledge_packet.packet_src_channel", "send_packet.packet_src_channel", "recv_packet.packet_src_channel"]}, value: {_eq: $channel}}, _and: {event_attributes: {composite_key: {_in: $compositeKey}, value: {_eq: $value}}}}) { + height + hash + timestamp + code + gas_used + gas_wanted + data + event_attributes (where: {_and: {composite_key: {_eq: "transfer.amount"}, value: {_like: "%ibc%"}}}) { + value + composite_key + key + } + } + } + } + `; + return this.http + .post(this.graphUrl, { + query: operationsDoc, + variables: { + limit: 20, + compositeKey: [ + 'send_packet.packet_sequence', + 'recv_packet.packet_sequence', + 'acknowledge_packet.packet_sequence', + 'timeout_packet.packet_sequence', + ], + value: sequence, + channel: channel + }, + operationName: 'queryListSequence', + }) + .pipe(map((res) => (res?.data ? res?.data[this.envDB] : null))); } } diff --git a/src/app/core/services/validator.service.ts b/src/app/core/services/validator.service.ts index 6f7a681c3..19ad2a172 100644 --- a/src/app/core/services/validator.service.ts +++ b/src/app/core/services/validator.service.ts @@ -1,12 +1,12 @@ import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import axios from 'axios'; -import * as _ from 'lodash'; -import { BehaviorSubject, Observable } from 'rxjs'; +import { BehaviorSubject } from 'rxjs'; +import { map } from 'rxjs/operators'; import { EnvironmentService } from 'src/app/core/data-services/environment.service'; import { CommonService } from 'src/app/core/services/common.service'; -import { LCD_COSMOS } from '../constants/url.constant'; import { Globals } from 'src/app/global/global'; +import { LCD_COSMOS } from '../constants/url.constant'; @Injectable({ providedIn: 'root', @@ -14,7 +14,6 @@ import { Globals } from 'src/app/global/global'; export class ValidatorService extends CommonService { apiUrl = `${this.environmentService.configValue.beUri}`; chainInfo = this.environmentService.configValue.chain_info; - indexerUrl = `${this.environmentService.configValue.indexerUri}`; stakingAPRSubject: BehaviorSubject; constructor( @@ -37,86 +36,192 @@ export class ValidatorService extends CommonService { if (!inflation && !bonded_tokens && !supply) { inflation = this.global.dataHeader.inflation.slice(0, -1); bonded_tokens = this.global.dataHeader.bonded_tokens.toString().slice(0, -1); - supply = this.global.dataHeader.supply.toString().slice(0, -1); + supply = this.global.dataHeader.total_aura.toString().slice(0, -1); this.stakingAPRSubject.next((inflation * (1 - communityTax)) / (bonded_tokens / supply)); } }, 500); } - validators(): Observable { - this.setURL(); - return this.http.get(`${this.apiUrl}/validators`); - } - - validatorsFromIndexer(address: string): Observable { - const params = _({ - chainid: this.chainInfo.chainId, - operatorAddress: address, - pageLimit: 100, - }) - .omitBy(_.isNull) - .omitBy(_.isUndefined) - .value(); - - return this.http.get(`${this.indexerUrl}/validator`, { - params, - }); - } - - validatorsDetail(address: string): Observable { - this.setURL(); - return this.http.get(`${this.apiUrl}/validators/${address}`); - } - - validatorsDetailListPower(address: string, pageLimit = 10, nextKey = null): Observable { - const params = _({ - chainid: this.chainInfo.chainId, - address, - pageLimit, - nextKey, - }) - .omitBy(_.isNull) - .omitBy(_.isUndefined) - .value(); - - return this.http.get(`${this.indexerUrl}/transaction/power-event`, { - params, - }); + getDataValidator(payload) { + const operationsDoc = ` + query getDataValidator($offset: Int = 0, $limit: Int = 10, $operatorAddress: String = null) { + ${this.envDB} { + validator(limit: $limit, offset: $offset, order_by: {tokens: desc}, where: {operator_address: {_eq: $operatorAddress}}) { + account_address + commission + consensus_address + consensus_hex_address + created_at + consensus_pubkey + delegator_shares + delegators_count + delegators_last_height + description + index_offset + jailed + jailed_until + min_self_delegation + missed_blocks_counter + operator_address + percent_voting_power + self_delegation_balance + start_height + status + tokens + tombstoned + unbonding_height + unbonding_time + uptime + missed_blocks_counter + image_url + vote_aggregate { + aggregate { + count + } + } + } + validator_aggregate(where: {status: {_eq: "BOND_STATUS_BONDED"}}) { + aggregate { + count + } + } + } + } + `; + return this.http + .post(this.graphUrl, { + query: operationsDoc, + variables: { + limit: payload?.limit || 200, + offset: payload?.offset || 0, + operatorAddress: payload?.operatorAddress || null, + }, + operationName: 'getDataValidator', + }) + .pipe(map((res) => (res?.data ? res?.data[this.envDB] : null))); } - validatorsDetailWallet(address: string): Observable { - this.setURL(); - return this.http.get(`${this.apiUrl}/validators/delegations/${address}`); + getValidatorByListAddress(arrAddress) { + const operationsDoc = ` + query getValidatorByListAddress($arrAddress: [String!]) { + ${this.envDB} { + validator(where: {operator_address: {_in: $arrAddress}}, order_by: {tokens: desc}) { + account_address + commission + consensus_address + consensus_hex_address + created_at + delegator_shares + delegators_count + delegators_last_height + description + jailed + operator_address + status + tokens + image_url + } + } + } + `; + return this.http + .post(this.graphUrl, { + query: operationsDoc, + variables: { + arrAddress: arrAddress || null, + }, + operationName: 'getValidatorByListAddress', + }) + .pipe(map((res) => (res?.data ? res?.data[this.envDB] : null))); } - validatorsListUndelegateWallet(address: string): Observable { - return this.http.get( - `${this.indexerUrl}/account-unbonds?chainid=${this.chainInfo.chainId}&address=${address}`, - ); + validatorsDetailListPower(address: string, limit = 10, nextKey = null) { + const operationsDoc = ` + query validatorsDetailListPower($operator_address: String, $limit: Int = 10, $nextKey: Int = null) { + ${this.envDB} { + power_event(order_by: {height: desc}, where: {_or: [{validatorDst: {operator_address: {_eq: $operator_address}}}, {validatorSrc: {operator_address: {_eq: $operator_address}}}], id: {_lt: $nextKey}}, limit: $limit) { + id + time + height + transaction { + hash + } + type + amount + validatorSrc { + operator_address + } + validatorDst { + operator_address + } + } + } + } + `; + return this.http + .post(this.graphUrl, { + query: operationsDoc, + variables: { + operator_address: address, + limit: limit, + nextKey: nextKey, + }, + operationName: 'validatorsDetailListPower', + }) + .pipe(map((res) => (res?.data ? res?.data[this.envDB] : null))); } - delegators(pageLimit = 100, address: string, nextKey = null) { + delegator(pageLimit = 100, address: string, nextKey = null) { return axios.get( `${this.chainInfo.rest}/${LCD_COSMOS.STAKING}/validators/${address}/delegations?pagination.limit=${pageLimit}&pagination.key=${nextKey}&pagination.reverse=true`, ); } - getValidatorAvatar(validatorAddress: string): string { - return `${this.environmentService.configValue.validator_s3}/${validatorAddress}.png`; + getUptimeLCD(block = null) { + if (!block) { + block = 'latest'; + } + return axios.get(`${this.chainInfo.rest}/${LCD_COSMOS.BLOCK}/${block}`); } - getValidatorInfoByList(addressList: string[]): Observable { - return this.http.get(`${this.apiUrl}/validators/validator-info?address=${addressList}`); + getUptimeIndexer(consAddress = null, limit = 100, height = null) { + const operationsDoc = ` + query getUptimeIndexer($cons_address: String, $limit: Int = 100, $height: Int = 0) { + ${this.envDB} { + block(order_by: {height: desc}, limit: $limit, where: {height: {_eq: $height}}) { + height + hash + block_signatures(where: {validator_address: {_eq: $cons_address}}) { + signature + block_id_flag + timestamp + } + } + } + } + `; + return this.http + .post(this.graphUrl, { + query: operationsDoc, + variables: { + cons_address: consAddress, + limit: limit, + height: height, + }, + operationName: 'getUptimeIndexer', + }) + .pipe(map((res) => (res?.data ? res?.data[this.envDB] : null))); } - getStakeInfo(delegatorAddress: string): Observable { - return this.http.get(`${this.apiUrl}/validators/delegations/delegator/${delegatorAddress}`); + getListUndelegateLCD(address) { + return axios.get(`${this.chainInfo.rest}/${LCD_COSMOS.STAKING}/delegators/${address}/unbonding_delegations`); } - getUptimeLCD(block = null) { - if (!block) { - block = 'latest'; - } - return axios.get(`${this.chainInfo.rest}/${LCD_COSMOS.BLOCK}/${block}`); + getDelegationLCD(address) { + return axios.get(`${this.chainInfo.rest}/${LCD_COSMOS.DELEGATION}/${address}`); + } + + getRewardLCD(address) { + return axios.get(`${this.chainInfo.rest}/${LCD_COSMOS.REWARD}/${address}/rewards`); } } diff --git a/src/app/core/services/wallet.service.ts b/src/app/core/services/wallet.service.ts index 519cc18e9..89a112804 100644 --- a/src/app/core/services/wallet.service.ts +++ b/src/app/core/services/wallet.service.ts @@ -1,17 +1,14 @@ import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout'; import { HttpClient } from '@angular/common/http'; import { Injectable, OnDestroy } from '@angular/core'; -import { makeSignDoc, StdSignDoc } from '@cosmjs/amino'; +import { StdSignDoc, makeSignDoc } from '@cosmjs/amino'; import { SigningCosmWasmClient } from '@cosmjs/cosmwasm-stargate'; import { Decimal } from '@cosmjs/math'; -import { StdFee } from '@cosmjs/stargate'; import { ChainInfo, Keplr, Key } from '@keplr-wallet/types'; import { TranslateService } from '@ngx-translate/core'; -import * as _ from 'lodash'; import * as moment from 'moment'; import { BehaviorSubject, Observable, Subject } from 'rxjs'; import { map, takeUntil } from 'rxjs/operators'; -import { EAccountType } from 'src/app/core/constants/account.enum'; import { AccountResponse, Coin98Client } from 'src/app/core/utils/coin98-client'; import { messageCreators } from 'src/app/core/utils/signing/messages'; import { createSignBroadcast, getNetworkFee } from 'src/app/core/utils/signing/transaction-manager'; @@ -31,7 +28,9 @@ export class WalletService implements OnDestroy { apiUrl = `${this.environmentService.configValue.beUri}`; chainId = this.environmentService.configValue.chainId; chainInfo = this.environmentService.configValue.chain_info; - urlIndexer = this.environmentService.configValue.indexerUri; + graphUrl = `${ + this.environmentService.configValue.horoscopeUrl + this.environmentService.configValue.horoscopePathGraphql + }`; coin98Client: Coin98Client; destroyed$ = new Subject(); @@ -314,38 +313,49 @@ export class WalletService implements OnDestroy { } private makeSignDocData(address, signDoc: Partial): Observable { - return this.http.get(`${this.urlIndexer}/account-info?address=${address}&chainId=${signDoc.chain_id}`).pipe( - map((res) => { - let accountAuth; - accountAuth = _.get(res, 'data.account_auth.account'); - let account: { - account_number: number | string; - sequence: number | string; - }; - - if (accountAuth && accountAuth['@type'] === EAccountType.BaseAccount) { - account = accountAuth; - } else { - account = _.get(accountAuth, 'base_vesting_account.base_account'); + const envDB = this.environmentService.configValue.horoscopeSelectedChain; + const operationsDoc = ` + query getAccountInfo ($address: String) { + ${envDB} { + account (where: {address: {_eq: $address}}) { + account_number + sequence + type } - - if (!account.account_number) { + } + } + `; + return this.http + .post(this.graphUrl, { + query: operationsDoc, + variables: { + address, + }, + operationName: 'getAccountInfo', + }) + .pipe( + map((res) => { + if (!res?.data[envDB].account[0]) { + throw new Error('Can not get Account'); + } + const accountAuth: { + account_number: number | string; + sequence: number | string; + } = res?.data[envDB].account[0]; + + if (accountAuth) { + return makeSignDoc( + signDoc.msgs, + signDoc.fee, + signDoc.chain_id, + signDoc.memo, + accountAuth.account_number, + accountAuth.sequence || 0, + ); + } throw new Error('Can not get Account'); - } - - if (account) { - return makeSignDoc( - signDoc.msgs, - signDoc.fee, - signDoc.chain_id, - signDoc.memo, - account.account_number, - account.sequence || 0, - ); - } - throw new Error('Can not get Account'); - }), - ); + }), + ); } signMessage(base64String: string) { diff --git a/src/app/core/services/ws.service.ts b/src/app/core/services/ws.service.ts index 5d3b6a857..dc24f827f 100644 --- a/src/app/core/services/ws.service.ts +++ b/src/app/core/services/ws.service.ts @@ -1,9 +1,7 @@ import { Injectable } from '@angular/core'; import { BehaviorSubject, Observable } from 'rxjs'; -import { take } from 'rxjs/operators'; import io, { Socket } from 'socket.io-client'; import { EnvironmentService } from 'src/app/core/data-services/environment.service'; -import { NgxToastrService } from 'src/app/core/services/ngx-toastr.service'; import { SoulboundService } from './soulbound.service'; import { WalletService } from './wallet.service'; @@ -34,7 +32,6 @@ export class WSService { constructor( private environmentService: EnvironmentService, - private toastr: NgxToastrService, private soulboundService: SoulboundService, private walletService: WalletService, ) { diff --git a/src/app/core/utils/common/info-common.ts b/src/app/core/utils/common/info-common.ts index 2175a121d..2ab8c1d44 100644 --- a/src/app/core/utils/common/info-common.ts +++ b/src/app/core/utils/common/info-common.ts @@ -8,10 +8,11 @@ import { balanceOf } from './parsing'; export function getInfo(globals: any, data: any): void { globals.dataHeader = data; globals.dataHeader.bonded_tokens = formatNumber(globals.dataHeader.bonded_tokens / NUMBER_CONVERT) || 0; - globals.dataHeader.supply = formatNumber(globals?.dataHeader?.supply / NUMBER_CONVERT); + globals.dataHeader.total_aura = formatNumber(+globals?.dataHeader?.total_aura / NUMBER_CONVERT); globals.dataHeader.bonded_tokens_format = formatNumber(globals?.dataHeader?.bonded_tokens); globals.dataHeader.community_pool = Math.round(globals?.dataHeader?.community_pool / NUMBER_CONVERT); globals.dataHeader.community_pool_format = formatNumber(globals?.dataHeader?.community_pool); + globals.dataHeader.inflation = globals?.dataHeader?.inflation * 100 + '%'; } export function formatNumber(number: number, args?: any): any { @@ -50,29 +51,24 @@ export function formatNumber(number: number, args?: any): any { } export function parseDataTransaction(trans: any, coinMinimalDenom: string, tokenID = '') { - let typeOrigin = trans.tx_response?.tx?.body?.messages[0]['@type']; + let typeOrigin = trans.data?.tx?.body?.messages[0]['@type']; const typeTrans = TYPE_TRANSACTION.find((f) => f.label.toLowerCase() === typeOrigin?.toLowerCase()); - trans.tx_hash = trans.tx_response?.txhash; + trans.tx_hash = trans.hash; //get amount of transaction - trans.amount = getAmount( - trans.tx_response?.tx?.body?.messages, - typeOrigin, - trans.tx_response?.raw_log, - coinMinimalDenom, - ); - trans.fee = balanceOf(trans?.tx_response?.tx?.auth_info?.fee?.amount[0]?.amount); - trans.gas_limit = balanceOf(trans?.tx_response?.tx?.auth_info?.fee?.gas_limit); - trans.height = trans.tx_response?.height; - trans.timestamp = trans.tx_response?.timestamp; + trans.amount = getAmount(trans.data?.tx?.body?.messages, typeOrigin, trans.tx_response?.raw_log, coinMinimalDenom); + trans.fee = balanceOf(trans?.data?.auth_info?.fee?.amount[0]?.amount); + trans.gas_limit = balanceOf(trans?.data?.auth_info?.fee?.gas_limit); + trans.height = trans?.height; + trans.timestamp = trans?.timestamp; trans.status = StatusTransaction.Fail; - if (Number(trans.tx_response?.code) === CodeTransaction.Success) { + if (Number(trans?.code) === CodeTransaction.Success) { trans.status = StatusTransaction.Success; } [trans.from_address, trans.to_address, trans.amountToken, trans.method, trans.token_id, trans.modeExecute] = - getDataInfo(trans.tx_response?.tx?.body?.messages, tokenID, trans.tx_response?.raw_log); + getDataInfo(trans.data?.tx?.body?.messages, tokenID, trans.data?.tx_response?.raw_log); trans.type = trans.method || typeTrans?.value; - trans.depositors = trans.tx_response?.tx?.body?.messages[0]?.depositor; - trans.price = balanceOf(_.get(trans, 'tx_response.tx.body.messages[0].funds[0].amount')); + trans.depositors = trans.data?.tx?.body?.messages[0]?.depositor; + trans.price = balanceOf(_.get(trans, 'data.body.messages[0].funds[0].amount')); return trans; } @@ -80,11 +76,15 @@ export function checkTypeFile(nft: any) { let nftType = nft.img_type || ''; let content_type = ''; if (!nftType) { - if (nft?.animation) { - nftType = nft?.animation?.content_type || ''; + if ( + (typeof nft?.media_info?.offchain?.animation === 'object' && + Object.keys(nft?.media_info?.offchain?.animation)?.length > 0) || + nft?.animation + ) { + nftType = nft?.media_info?.offchain?.animation?.content_type || nft?.animation?.content_type || ''; } - if (nft?.image && nftType == '') { - nftType = nft?.image?.content_type || ''; + if (nftType == '' && (nft?.media_info?.offchain?.image || nft?.image?.link_s3)) { + nftType = nft?.media_info?.offchain?.image?.content_type || nft?.image?.content_type || ''; } } @@ -116,4 +116,3 @@ export function checkTypeFile(nft: any) { } return content_type; } - diff --git a/src/app/core/utils/signing/messages.ts b/src/app/core/utils/signing/messages.ts index 040918ef7..b08e70da7 100644 --- a/src/app/core/utils/signing/messages.ts +++ b/src/app/core/utils/signing/messages.ts @@ -1,10 +1,10 @@ import { ChainInfo } from '@keplr-wallet/types'; import { MsgWithdrawDelegatorReward } from 'cosmjs-types/cosmos/distribution/v1beta1/tx'; -import { MsgBeginRedelegate, MsgDelegate, MsgUndelegate } from 'cosmjs-types/cosmos/staking/v1beta1/tx'; +import { BasicAllowance, PeriodicAllowance } from 'cosmjs-types/cosmos/feegrant/v1beta1/feegrant'; import { MsgGrantAllowance, MsgRevokeAllowance } from 'cosmjs-types/cosmos/feegrant/v1beta1/tx'; -import { BasicAllowance, PeriodicAllowance, AllowedMsgAllowance } from 'cosmjs-types/cosmos/feegrant/v1beta1/feegrant'; -import { Timestamp } from 'cosmjs-types/google/protobuf/timestamp'; +import { MsgBeginRedelegate, MsgDelegate, MsgUndelegate } from 'cosmjs-types/cosmos/staking/v1beta1/tx'; import { Duration } from 'cosmjs-types/google/protobuf/duration'; +import { Timestamp } from 'cosmjs-types/google/protobuf/timestamp'; import { TRANSACTION_TYPE_ENUM } from '../../constants/transaction.enum'; import AllowedContractAllowance from './custom-feegrant'; // Staking @@ -217,24 +217,6 @@ export function GrantMsgAllowance( }); } - //comment allow message for version 0.45 - // const allowanceValue = { - // allowance: itemAllowance, - // allowedMessages: allowedMessages, - // }; - - // const allowanceEncode = AllowedMsgAllowance.encode(allowanceValue as any).finish(); - - // const allowance = { - // typeUrl: TRANSACTION_TYPE_ENUM.AllowedMsgAllowance, - // value: Uint8Array.from(allowanceEncode), - // }; - - // const allowedContractMsg = { - // allowance: allowance, - // allowedAddress: allowedAddress.length > 0 ? allowedAddress : [], - // }; - const allowedContractMsg = { allowance: itemAllowance, allowedAddress: allowedAddress.length > 0 ? allowedAddress : [], diff --git a/src/app/core/utils/signing/transaction-manager.ts b/src/app/core/utils/signing/transaction-manager.ts index df6fd3382..7614c4f1e 100644 --- a/src/app/core/utils/signing/transaction-manager.ts +++ b/src/app/core/utils/signing/transaction-manager.ts @@ -3,7 +3,6 @@ import { calculateFee, DeliverTxResponse, SigningStargateClient, StdFee } from ' import { ChainInfo } from '@keplr-wallet/types'; import { TRANSACTION_TYPE_ENUM } from '../../constants/transaction.enum'; import { KEPLR_ERRORS } from '../../constants/wallet.constant'; -import { getFee } from './fee'; import { messageCreators } from './messages'; import { getSigner } from './signer'; diff --git a/src/app/global/global.ts b/src/app/global/global.ts index baa1ad9d3..9aca48524 100644 --- a/src/app/global/global.ts +++ b/src/app/global/global.ts @@ -23,6 +23,7 @@ export class Globals { aura: 0, btc: 0, }; + listNameTag = []; } export function getAmount(arrayMsg, type, rawRog = '', coinMinimalDenom = '') { @@ -125,6 +126,12 @@ export function getDataInfo(arrayMsg, addressContract, rawLog = '') { case eTransType.ExecuteContract: method = 'mint'; itemMessage.msg = itemMessage.msg || ''; + if (typeof itemMessage.msg === 'string') { + try { + itemMessage.msg = JSON.parse(itemMessage.msg); + } catch (e) {} + } + if (itemMessage.msg) { method = Object.keys(itemMessage.msg)[0]; } @@ -134,6 +141,7 @@ export function getDataInfo(arrayMsg, addressContract, rawLog = '') { itemMessage.msg[Object.keys(itemMessage.msg)[0]]?.recipient || itemMessage.msg[Object.keys(itemMessage.msg)[0]]?.owner || itemMessage.msg[Object.keys(itemMessage.msg)[0]]?.spender || + itemMessage.msg[Object.keys(itemMessage.msg)[0]]?.to || itemMessage.msg[Object.keys(itemMessage.msg)[0]]?.operator; if (arrayMsg?.length > 1 || itemMessage.msg['batch_mint']) { @@ -159,8 +167,9 @@ export function getDataInfo(arrayMsg, addressContract, rawLog = '') { fromAddress = NULL_ADDRESS; modeExecute = ModeExecuteTransaction.Mint; } else if (method === ModeExecuteTransaction.Take) { - fromAddress = itemMessage.msg?.take?.from; + fromAddress = NULL_ADDRESS; toAddress = itemMessage.sender; + modeExecute = ModeExecuteTransaction.Take; try { const data = JSON.parse(rawLog); tokenId = @@ -183,8 +192,6 @@ export function getDataInfo(arrayMsg, addressContract, rawLog = '') { } catch (e) {} } else if (method === ModeExecuteTransaction.Send) { toAddress = itemMessage?.msg?.send?.contract; - } else if (method === ModeExecuteTransaction.ProvideLiquidity) { - toAddress = itemMessage?.contract; } break; case eTransType.Deposit: @@ -212,24 +219,35 @@ export function getDataInfo(arrayMsg, addressContract, rawLog = '') { toAddress = itemMessage.to_address; break; } + toAddress = toAddress || itemMessage?.contract; return [fromAddress, toAddress, value, method, tokenId, modeExecute]; } export function convertDataTransaction(data, coinInfo) { - const txs = _.get(data, 'transactions').map((element) => { - const code = _.get(element, 'tx_response.code'); - const tx_hash = _.get(element, 'tx_response.txhash'); - const messages = _.get(element, 'tx_response.tx.body.messages'); + const txs = _.get(data, 'transaction').map((element) => { + if (!element['data']['body']) { + element['data']['body'] = element['data']['tx']['body']; + element['data']['auth_info'] = element['data']['tx']['auth_info']; + } + + const code = _.get(element, 'code'); + const tx_hash = _.get(element, 'hash'); + const messages = _.get(element, 'data.body.messages'); - let _type = _.get(element, 'tx_response.tx.body.messages[0].@type'); - let lstType = _.get(element, 'tx_response.tx.body.messages'); + let _type = _.get(element, 'data.body.messages[0].@type'); + let lstType = _.get(element, 'data.body.messages'); let denom = coinInfo.coinDenom; - //check send token ibc same chain - if (_type === TRANSACTION_TYPE_ENUM.Send && messages[0].amount[0].denom !== denom) { + // check send token ibc same chain + if (_type === TRANSACTION_TYPE_ENUM.Send && messages[0]?.amount[0]?.denom !== denom) { denom = messages[0].amount[0].denom; } + // check transfer token ibc different chain + if (_type === TRANSACTION_TYPE_ENUM.IBCTransfer && messages[0]?.token?.denom !== denom) { + denom = messages[0].token?.denom; + } + if (lstType?.length > 1) { lstType.forEach((type) => { if (type['@type'] !== TRANSACTION_TYPE_ENUM.IBCUpdateClient && type['@type'].indexOf('ibc') > -1) { @@ -247,25 +265,16 @@ export function convertDataTransaction(data, coinInfo) { } const _amount = getAmount( - _.get(element, 'tx_response.tx.body.messages'), + _.get(element, 'data.body.messages'), _type, - _.get(element, 'tx_response.tx.body.raw_log'), + _.get(element, 'data.body.raw_log'), coinInfo.coinMinimalDenom, ); - const fee = balanceOf( - _.get(element, 'tx_response.tx.auth_info.fee.amount[0].amount') || 0, - coinInfo.coinDecimals, - ).toFixed(coinInfo.coinDecimals); - - const height = _.get(element, 'tx_response.height'); - const timestamp = _.get(element, 'tx_response.timestamp'); - const gas_used = _.get(element, 'tx_response.gas_used'); - const gas_wanted = _.get(element, 'tx_response.gas_wanted'); - + const typeOrigin = _type; let amount = _.isNumber(_amount) && _amount > 0 ? _amount.toFixed(coinInfo.coinDecimals) : _amount; - let type = _.find(TYPE_TRANSACTION, { label: _type })?.value || _type.split('.').pop(); + try { if (lstType[0]['@type'].indexOf('ibc') == -1) { if (lstType[0]['@type'] === TRANSACTION_TYPE_ENUM.GetReward) { @@ -282,24 +291,48 @@ export function convertDataTransaction(data, coinInfo) { } catch (e) {} const status = - _.get(element, 'tx_response.code') == CodeTransaction.Success - ? StatusTransaction.Success - : StatusTransaction.Fail; + _.get(element, 'code') == CodeTransaction.Success ? StatusTransaction.Success : StatusTransaction.Fail; - return { code, tx_hash, type, status, amount, fee, height, timestamp, gas_used, gas_wanted, denom, messages }; + const fee = balanceOf(_.get(element, 'data.auth_info.fee.amount[0].amount') || 0, coinInfo.coinDecimals).toFixed( + coinInfo.coinDecimals, + ); + const height = _.get(element, 'height'); + const timestamp = _.get(element, 'timestamp'); + const gas_used = _.get(element, 'gas_used'); + const gas_wanted = _.get(element, 'gas_wanted'); + let tx = _.get(element, 'data.tx_response'); + if (tx) { + tx['tx'] = _.get(element, 'data.tx'); + } + + return { + code, + tx_hash, + type, + status, + amount, + fee, + height, + timestamp, + gas_used, + gas_wanted, + denom, + messages, + tx, + typeOrigin, + }; }); return txs; } export function convertDataBlock(data) { - const block = _.get(data, 'blocks').map((element) => { - const height = _.get(element, 'block.header.height'); - const block_hash = _.get(element, 'block_id.hash'); - const num_txs = _.get(element, 'block.data.txs.length'); - const proposer = _.get(element, 'validator_name'); - const operator_address = _.get(element, 'operator_address'); - const timestamp = _.get(element, 'block.header.time'); - + const block = _.get(data, 'block').map((element) => { + const height = _.get(element, 'height'); + const block_hash = _.get(element, 'hash'); + const num_txs = _.get(element, 'data.block.data.txs.length'); + const proposer = _.get(element, 'validator.description.moniker'); + const operator_address = _.get(element, 'validator.operator_address'); + const timestamp = _.get(element, 'time'); return { height, block_hash, num_txs, proposer, operator_address, timestamp }; }); return block; diff --git a/src/app/layouts/horizontaltopbar/horizontaltopbar.component.scss b/src/app/layouts/horizontaltopbar/horizontaltopbar.component.scss index dd6ec9e50..8d53d2835 100644 --- a/src/app/layouts/horizontaltopbar/horizontaltopbar.component.scss +++ b/src/app/layouts/horizontaltopbar/horizontaltopbar.component.scss @@ -10,6 +10,7 @@ align-items: center; justify-content: center; font-weight: 600; + white-space: nowrap; @media (min-width: 414.99px) { padding: 0 var(--spacer-2); } diff --git a/src/app/layouts/horizontaltopbar/horizontaltopbar.component.ts b/src/app/layouts/horizontaltopbar/horizontaltopbar.component.ts index 00ffb574b..0aa78f4e3 100644 --- a/src/app/layouts/horizontaltopbar/horizontaltopbar.component.ts +++ b/src/app/layouts/horizontaltopbar/horizontaltopbar.component.ts @@ -2,10 +2,12 @@ import { AfterViewInit, Component, EventEmitter, HostListener, OnInit, Output } import { NavigationEnd, Router } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { CookieService } from 'ngx-cookie-service'; +import { from } from 'rxjs'; +import { delay, mergeMap } from 'rxjs/operators'; import { EnvironmentService } from 'src/app/core/data-services/environment.service'; +import { CommonService } from 'src/app/core/services/common.service'; import { SoulboundService } from 'src/app/core/services/soulbound.service'; import { LENGTH_CHARACTER, NETWORK } from '../../../app/core/constants/common.constant'; -import { ResponseDto } from '../../core/models/common.model'; import { EventService } from '../../core/services/event.service'; import { LanguageService } from '../../core/services/language.service'; import { TransactionService } from '../../core/services/transaction.service'; @@ -13,8 +15,6 @@ import { WalletService } from '../../core/services/wallet.service'; import { LAYOUT_MODE } from '../layouts.model'; import { MENU, MenuName } from './menu'; import { MenuItem } from './menu.model'; -import { from } from 'rxjs'; -import { delay, mergeMap } from 'rxjs/operators'; @Component({ selector: 'app-horizontaltopbar', @@ -34,9 +34,6 @@ export class HorizontaltopbarComponent implements OnInit, AfterViewInit { cookieValue: any; countryName: any; valueset: any; - networks = NETWORK; - currentNetwork = JSON.parse(localStorage.getItem('currentNetwork')) || NETWORK[1]; - currentChanel = JSON.parse(localStorage.getItem('currentChanel')) || null; searchValue = null; env = null; pageTitle = null; @@ -80,6 +77,7 @@ export class HorizontaltopbarComponent implements OnInit, AfterViewInit { private transactionService: TransactionService, private environmentService: EnvironmentService, private soulboundService: SoulboundService, + private commonService: CommonService, ) { router.events.subscribe((event) => { if (event instanceof NavigationEnd) { @@ -162,6 +160,7 @@ export class HorizontaltopbarComponent implements OnInit, AfterViewInit { } checkEnv() { + this.env = this.environmentService.configValue.env; this.innerWidth = window.innerWidth; this.pageTitle = this.innerWidth > 992 @@ -322,6 +321,14 @@ export class HorizontaltopbarComponent implements OnInit, AfterViewInit { const regexRule = VALIDATORS.HASHRULE; if (this.searchValue) { this.searchValue = this.searchValue.trim(); + const addressNameTag = this.commonService.findNameTag(this.searchValue); + if (addressNameTag?.length > 0) { + let urlLink = addressNameTag.length === LENGTH_CHARACTER.CONTRACT ? 'contracts' : 'account'; + this.router.navigateByUrl('/', { skipLocationChange: true }).then(() => { + this.router.navigate([urlLink, addressNameTag]); + }); + } + let isNumber = /^\d+$/.test(this.searchValue); if (regexRule.test(this.searchValue)) { //check is start with 'aura' and length >= normal address @@ -343,16 +350,18 @@ export class HorizontaltopbarComponent implements OnInit, AfterViewInit { this.router.navigate(['blocks', this.searchValue]); }); } - } else { - this.searchValue = ''; } } } getTxhDetail(value): void { - this.transactionService.txsIndexer(1, 0, decodeURI(value)).subscribe( - (res: ResponseDto) => { - if (res.data) { + const payload = { + limit: 1, + hash: decodeURI(value), + }; + this.transactionService.getListTx(payload).subscribe( + (res) => { + if (res?.transaction?.length > 0) { this.router.navigateByUrl('/', { skipLocationChange: true }).then(() => { this.router.navigate(['transaction', this.searchValue]); }); diff --git a/src/app/pages/account/account-detail/account-detail-table/account-detail-table.component.html b/src/app/pages/account/account-detail/account-detail-table/account-detail-table.component.html index dde4b25f2..a1521709d 100644 --- a/src/app/pages/account/account-detail/account-detail-table/account-detail-table.component.html +++ b/src/app/pages/account/account-detail/account-detail-table/account-detail-table.component.html @@ -60,7 +60,7 @@ + [srcImg]="data.image_src_url"> @@ -76,7 +76,7 @@ + [srcImg]="data.image_dst_url"> @@ -185,7 +185,7 @@ + [srcImg]="item['image_src_url']"> @@ -205,7 +205,7 @@ + [srcImg]="item['image_dst_url']"> diff --git a/src/app/pages/account/account-detail/account-detail-table/account-detail-table.component.ts b/src/app/pages/account/account-detail/account-detail-table/account-detail-table.component.ts index 1ba0e314a..ff5a06415 100644 --- a/src/app/pages/account/account-detail/account-detail-table/account-detail-table.component.ts +++ b/src/app/pages/account/account-detail/account-detail-table/account-detail-table.component.ts @@ -1,19 +1,9 @@ import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout'; -import { - AfterViewInit, - ChangeDetectorRef, - Component, - EventEmitter, - Input, - OnChanges, - OnInit, - Output, -} from '@angular/core'; +import { AfterViewInit, Component, EventEmitter, Input, OnChanges, OnInit, Output } from '@angular/core'; import { MatPaginator, PageEvent } from '@angular/material/paginator'; import { MatTableDataSource } from '@angular/material/table'; import { TranslateService } from '@ngx-translate/core'; import { EnvironmentService } from 'src/app/core/data-services/environment.service'; -import { ValidatorService } from 'src/app/core/services/validator.service'; import { PageEventType } from '../../../../../app/core/constants/account.enum'; import { TableTemplate } from '../../../../core/models/common.model'; import { CommonService } from '../../../../core/services/common.service'; @@ -46,8 +36,6 @@ export class AccountDetailTableComponent implements OnInit, OnChanges, AfterView public commonService: CommonService, private layout: BreakpointObserver, private environmentService: EnvironmentService, - private validatorService: ValidatorService, - private cdr: ChangeDetectorRef, ) {} ngOnInit(): void {} @@ -82,29 +70,6 @@ export class AccountDetailTableComponent implements OnInit, OnChanges, AfterView operatorAddArr.push(f.validator_dst_address); } }); - if (operatorAddArr.length > 0 && operatorAddArr[0]) { - // get validator logo - this.validatorService.getValidatorInfoByList(operatorAddArr).subscribe((res) => { - if (res?.data) { - this.validatorImgArr = res?.data; - // push image into validator array - this.dataSource.data.forEach((item) => { - this.validatorImgArr.forEach((imgObj) => { - if (this.pageEventType !== 'Redelegation' && imgObj.operator_address == item.validator_address) { - item['image_url'] = imgObj.image_url; - } - if (this.pageEventType === 'Redelegation' && imgObj.operator_address == item.validator_src_address) { - item['src_image_url'] = imgObj.image_url; - } - if (this.pageEventType === 'Redelegation' && imgObj.operator_address == item.validator_dst_address) { - item['dst_image_url'] = imgObj.image_url; - } - }); - }); - this.cdr.markForCheck(); - } - }); - } } } diff --git a/src/app/pages/account/account-detail/account-detail.component.html b/src/app/pages/account/account-detail/account-detail.component.html index 7ff4a9519..4c899857f 100644 --- a/src/app/pages/account/account-detail/account-detail.component.html +++ b/src/app/pages/account/account-detail/account-detail.component.html @@ -19,20 +19,27 @@ {{ currentAddress }} {{ currentAddress | cutStringPipe : 8 : 8 }} -
- +
+ +
+
+ +
Total Value
@@ -113,7 +120,7 @@

Coins & Tokens ({{ totalAssets || 0 }})

-
+
@@ -150,14 +157,12 @@

Coins & Tokens ({{ totalAssets || 0 }})

-
-
+
+
{{ data[template.matColumnDef] | stringEllipsis : 11 }}
+ +
@@ -177,21 +182,6 @@

Coins & Tokens ({{ totalAssets || 0 }})

{{ denom }}
-
- - {{ +data[template.matColumnDef] | mask : 'separator.6' }} - {{ commonService.mappingNameIBC(data?.denom) }} - - - - - - More - - -
{{ data[template.matColumnDef] }}
diff --git a/src/app/pages/account/account-detail/account-detail.component.scss b/src/app/pages/account/account-detail/account-detail.component.scss index a9e9d5653..b9ce860d8 100644 --- a/src/app/pages/account/account-detail/account-detail.component.scss +++ b/src/app/pages/account/account-detail/account-detail.component.scss @@ -156,4 +156,4 @@ section.account-detail { } app-soulbound-feature-tokens { width: 100%; -} +} \ No newline at end of file diff --git a/src/app/pages/account/account-detail/account-detail.component.ts b/src/app/pages/account/account-detail/account-detail.component.ts index 7d999f957..4bdb1d239 100644 --- a/src/app/pages/account/account-detail/account-detail.component.ts +++ b/src/app/pages/account/account-detail/account-detail.component.ts @@ -28,8 +28,8 @@ import { TableTemplate } from '../../../core/models/common.model'; import { AccountService } from '../../../core/services/account.service'; import { CommonService } from '../../../core/services/common.service'; import { TransactionService } from '../../../core/services/transaction.service'; -import { convertDataTransaction, Globals } from '../../../global/global'; -import { chartCustomOptions, ChartOptions, CHART_OPTION } from './chart-options'; +import { Globals, convertDataTransaction } from '../../../global/global'; +import { CHART_OPTION, ChartOptions, chartCustomOptions } from './chart-options'; @Component({ selector: 'app-account-detail', @@ -59,7 +59,6 @@ export class AccountDetailComponent implements OnInit, AfterViewInit { { matColumnDef: 'tx_hash', headerCellDef: 'Tx Hash' }, { matColumnDef: 'type', headerCellDef: 'Type' }, { matColumnDef: 'status', headerCellDef: 'Result' }, - { matColumnDef: 'amount', headerCellDef: 'Amount' }, { matColumnDef: 'fee', headerCellDef: 'Fee' }, { matColumnDef: 'height', headerCellDef: 'Height' }, { matColumnDef: 'timestamp', headerCellDef: 'Time' }, @@ -264,20 +263,6 @@ export class AccountDetailComponent implements OnInit, AfterViewInit { } } - copyMessage(text: string) { - const dummy = document.createElement('textarea'); - document.body.appendChild(dummy); - dummy.value = text; - dummy.select(); - document.execCommand('copy'); - document.body.removeChild(dummy); - // fake event click out side copy button - // this event for hidden tooltip - setTimeout(function () { - document.getElementById('currentAddress').click(); - }, 800); - } - changePage(page: any): void { switch (page.pageEventType) { case this.pageEventType.Delegation: @@ -301,22 +286,26 @@ export class AccountDetailComponent implements OnInit, AfterViewInit { } getTxsFromHoroscope(nextKey = null): void { - const chainId = this.environmentService.configValue.chainId; const address = this.currentAddress; - - this.transactionService.getAccountTxFromHoroscope(chainId, address, 40, nextKey).subscribe({ - next: (txResponse) => { - const { code, data } = txResponse; - this.nextKey = data.nextKey || null; - - if (code === 200) { + let payload = { + limit: 40, + value: address, + heightLT: nextKey, + }; + this.transactionService.getListTxCondition(payload).subscribe({ + next: (data) => { + if (data?.transaction?.length > 0) { + this.nextKey = null; + if (data?.transaction?.length >= 40) { + this.nextKey = data?.transaction[data?.transaction?.length - 1].height; + } const txs = convertDataTransaction(data, this.coinInfo); txs.forEach((element) => { if (element.type === 'Send') { if (!element.messages.find((k) => k.from_address === this.currentAddress)) { element.type = 'Receive'; } - } else if (element.type === 'Multi Send') { + } else if (element.type === 'Multisend') { if (element.messages[0]?.inputs[0]?.address !== this.currentAddress) { element.type = 'Receive'; } @@ -348,87 +337,90 @@ export class AccountDetailComponent implements OnInit, AfterViewInit { getAccountDetail(): void { this.isNoData = false; const halftime = 15000; - this.accountService.getAccountDetail(this.currentAddress).subscribe((res) => { - this.chartLoading = true; - this.accDetailLoading = true; - if (res.data.code === 200 && !res.data?.data) { - this.isNoData = true; - setTimeout(() => { - this.getAccountDetail(); - }, halftime); - return; - } + this.accountService.getAccountDetail(this.currentAddress).subscribe( + (res) => { + if (res.data.code === 200 && !res.data?.data) { + this.isNoData = true; + setTimeout(() => { + this.getAccountDetail(); + }, halftime); + return; + } + + if (res?.data) { + this.currentAccountDetail = res.data; + this.chartOptions.series = []; + if (+this.currentAccountDetail.commission > 0) { + this.chartOptions.labels.push(ACCOUNT_WALLET_COLOR_ENUM.Commission); + this.chartOptions.colors.push(WalletAcount.Commission); + this.chartCustomOptions.push({ + name: ACCOUNT_WALLET_COLOR_ENUM.Commission, + color: WalletAcount.Commission, + amount: '0.000000', + }); + } else { + this.chartCustomOptions = chartCustomOptions; + } - if (res?.data) { - this.currentAccountDetail = res.data; - this.chartOptions.series = []; - if (+this.currentAccountDetail.commission > 0) { - this.chartOptions.labels.push(ACCOUNT_WALLET_COLOR_ENUM.Commission); - this.chartOptions.colors.push(WalletAcount.Commission); - this.chartCustomOptions.push({ - name: ACCOUNT_WALLET_COLOR_ENUM.Commission, - color: WalletAcount.Commission, - amount: '0.000000', + this.chartCustomOptions.forEach((f) => { + switch (f.name) { + case ACCOUNT_WALLET_COLOR_ENUM.Available: + f.amount = this.currentAccountDetail.available; + break; + case ACCOUNT_WALLET_COLOR_ENUM.Delegated: + f.amount = this.currentAccountDetail.delegated; + break; + case ACCOUNT_WALLET_COLOR_ENUM.StakingReward: + f.amount = this.currentAccountDetail.stake_reward; + break; + case ACCOUNT_WALLET_COLOR_ENUM.Commission: + f.amount = this.currentAccountDetail.commission; + break; + case ACCOUNT_WALLET_COLOR_ENUM.Unbonding: + f.amount = this.currentAccountDetail.unbonding; + break; + case ACCOUNT_WALLET_COLOR_ENUM.DelegableVesting: + f.amount = this.currentAccountDetail?.delegable_vesting; + break; + default: + break; + } + f.amount = f.amount || '0'; + this.chartOptions.series.push(Number(f.amount)); }); - } else { - this.chartCustomOptions = chartCustomOptions; - } + this.dataSourceToken.data = this.currentAccountDetail?.balances; + this.pageDataToken.length = this.currentAccountDetail?.balances?.length; + this.dataSourceTokenBk = this.dataSourceToken; + + this.dataSourceDelegation.data = this.currentAccountDetail?.delegations; + this.pageDataDelegation.length = this.currentAccountDetail?.delegations?.length; - this.chartCustomOptions.forEach((f) => { - switch (f.name) { - case ACCOUNT_WALLET_COLOR_ENUM.Available: - f.amount = this.currentAccountDetail.available; - break; - case ACCOUNT_WALLET_COLOR_ENUM.Delegated: - f.amount = this.currentAccountDetail.delegated; - break; - case ACCOUNT_WALLET_COLOR_ENUM.StakingReward: - f.amount = this.currentAccountDetail.stake_reward; - break; - case ACCOUNT_WALLET_COLOR_ENUM.Commission: - f.amount = this.currentAccountDetail.commission; - break; - case ACCOUNT_WALLET_COLOR_ENUM.Unbonding: - f.amount = this.currentAccountDetail.unbonding; - break; - case ACCOUNT_WALLET_COLOR_ENUM.DelegableVesting: - f.amount = this.currentAccountDetail?.delegable_vesting; - break; - default: - break; + this.dataSourceUnBonding.data = this.currentAccountDetail?.unbonding_delegations; + this.pageDataUnbonding.length = this.currentAccountDetail?.unbonding_delegations?.length; + this.dataSourceReDelegation.data = this.currentAccountDetail?.redelegations; + this.pageDataRedelegation.length = this.currentAccountDetail?.redelegations?.length; + + if (this.currentAccountDetail?.vesting) { + this.dataSourceVesting = new MatTableDataSource([this.currentAccountDetail?.vesting]); + this.pageDataVesting.length = 1; + } + + if (this.userAddress === this.currentAddress) { + local.removeItem('accountDetail'); + //store data wallet info + let accountDetail = {}; + accountDetail['dataAccount'] = JSON.stringify(this.currentAccountDetail); + accountDetail['dataChart'] = JSON.stringify(this.chartOptions); + local.setItem('accountDetail', accountDetail); } - f.amount = f.amount || '0'; - this.chartOptions.series.push(Number(f.amount)); - }); - this.dataSourceToken.data = this.currentAccountDetail?.balances; - this.pageDataToken.length = this.currentAccountDetail?.balances?.length; - this.dataSourceTokenBk = this.dataSourceToken; - - this.dataSourceDelegation.data = this.currentAccountDetail?.delegations; - this.pageDataDelegation.length = this.currentAccountDetail?.delegations?.length; - - this.dataSourceUnBonding.data = this.currentAccountDetail?.unbonding_delegations; - this.pageDataUnbonding.length = this.currentAccountDetail?.unbonding_delegations?.length; - this.dataSourceReDelegation.data = this.currentAccountDetail?.redelegations; - this.pageDataRedelegation.length = this.currentAccountDetail?.redelegations?.length; - - if (this.currentAccountDetail?.vesting) { - this.dataSourceVesting = new MatTableDataSource([this.currentAccountDetail?.vesting]); - this.pageDataVesting.length = 1; } + }, + () => {}, + () => { this.accDetailLoading = false; this.chartLoading = false; - - if (this.userAddress === this.currentAddress) { - local.removeItem('accountDetail'); - //store data wallet info - let accountDetail = {}; - accountDetail['dataAccount'] = JSON.stringify(this.currentAccountDetail); - accountDetail['dataChart'] = JSON.stringify(this.chartOptions); - local.setItem('accountDetail', accountDetail); - } - } - }); + }, + ); } searchToken(): void { @@ -481,10 +473,6 @@ export class AccountDetailComponent implements OnInit, AfterViewInit { }); } - splitDataSource(d: any[]) { - return d.slice(0, 5); - } - closePopup() { this.modalReference.close(); } diff --git a/src/app/pages/account/account-detail/account-detail.module.ts b/src/app/pages/account/account-detail/account-detail.module.ts index 30fff170a..ebb1a9ffb 100644 --- a/src/app/pages/account/account-detail/account-detail.module.ts +++ b/src/app/pages/account/account-detail/account-detail.module.ts @@ -1,3 +1,4 @@ +import { ClipboardModule } from '@angular/cdk/clipboard'; import { CommonModule, DecimalPipe } from '@angular/common'; import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; @@ -7,8 +8,11 @@ import { NgApexchartsModule } from 'ng-apexcharts'; import { NgxMaskModule } from 'ngx-mask'; import { SimplebarAngularModule } from 'simplebar-angular'; import { CommonDirectiveModule } from 'src/app/core/directives/common-directive.module'; +import { APaginatorModule } from 'src/app/shared/components/a-paginator/a-paginator.module'; import { NftCardModule } from 'src/app/shared/components/cards/nft-card/nft-card.module'; +import { NameTagModule } from 'src/app/shared/components/name-tag/name-tag.module'; import { SoulboundFeatureTokensModule } from 'src/app/shared/components/soulbound-feature-tokens/soulbound-feature-tokens.module'; +import { TooltipCustomizeModule } from 'src/app/shared/components/tooltip-customize/tooltip-customize.module'; import { MaterialModule } from '../../../app.module'; import { CommonPipeModule } from '../../../core/pipes/common-pipe.module'; import { AccountService } from '../../../core/services/account.service'; @@ -45,7 +49,11 @@ import { TokenTableComponent } from './token-table/token-table.component'; NftCardModule, NgxMaskModule, SoulboundFeatureTokensModule, - CommonDirectiveModule + CommonDirectiveModule, + APaginatorModule, + NameTagModule, + TooltipCustomizeModule, + ClipboardModule, ], providers: [TransactionService, AccountService, DecimalPipe], }) diff --git a/src/app/pages/account/account-detail/nft-list/nft-list.component.html b/src/app/pages/account/account-detail/nft-list/nft-list.component.html index 42061f5b1..6889f0663 100644 --- a/src/app/pages/account/account-detail/nft-list/nft-list.component.html +++ b/src/app/pages/account/account-detail/nft-list/nft-list.component.html @@ -1,13 +1,13 @@ -

NFTs ({{ pageData.length || 0 }} NFTs and more)

+

NFTs ({{ pageData?.length || 0 }} NFTs)

-
+
- +
@@ -17,8 +17,8 @@

NFTs ({{ pageData.length || 0 }}

+
+
@@ -50,48 +49,42 @@
-
- {{ element.name | stringEllipsis : 23 }} +
+ {{ element.name | stringEllipsis : 19 }}
-
- {{ element.name | stringEllipsis : 16 }} +
+
+ +
+ +
-
+
+ +
+ + +
+ {{ element.name | stringEllipsis : 19 }} +
+
+
-
- -
- - -
- {{ element.name | stringEllipsis : 23 }} -
-
- {{ element.name | stringEllipsis : 16 }} -
-
- + +
@@ -109,15 +102,11 @@
diff --git a/src/app/pages/account/account-detail/token-table/token-table.component.ts b/src/app/pages/account/account-detail/token-table/token-table.component.ts index f2db04783..fe09f196e 100644 --- a/src/app/pages/account/account-detail/token-table/token-table.component.ts +++ b/src/app/pages/account/account-detail/token-table/token-table.component.ts @@ -1,6 +1,5 @@ import { Component, EventEmitter, Input, OnChanges, Output } from '@angular/core'; import { MatPaginator, PageEvent } from '@angular/material/paginator'; -import { Sort } from '@angular/material/sort'; import { MatTableDataSource } from '@angular/material/table'; import * as _ from 'lodash'; import { PAGE_EVENT } from 'src/app/core/constants/common.constant'; @@ -21,8 +20,8 @@ export class TokenTableComponent implements OnChanges { @Output() totalValue = new EventEmitter(); @Output() totalAssets = new EventEmitter(); - math = Math; textSearch = ''; + searchValue = ''; templates: Array = [ { matColumnDef: 'asset', headerCellDef: 'asset' }, { matColumnDef: 'symbol', headerCellDef: 'symbol' }, @@ -46,20 +45,22 @@ export class TokenTableComponent implements OnChanges { total = 0; pageEvent: any; paginator: MatPaginator; + dataTable = []; denom = this.environmentService.configValue.chain_info.currencies[0].coinDenom; coinMiniDenom = this.environmentService.configValue.chain_info.currencies[0].coinMinimalDenom; coinInfo = this.environmentService.configValue.chain_info.currencies[0]; image_s3 = this.environmentService.configValue.image_s3; defaultLogoAura = this.image_s3 + 'images/icons/aura.svg'; - constructor( public global: Globals, private accountService: AccountService, private environmentService: EnvironmentService, ) {} - ngOnInit(): void {} + ngOnInit(): void { + this.getTotalAssets(); + } ngOnChanges(): void { this.getListToken(); @@ -72,86 +73,98 @@ export class TokenTableComponent implements OnChanges { offset: this.pageData.pageSize * this.pageData.pageIndex, keyword: this.textSearch, }; - this.accountService.getAssetCW20ByOwner(payload).subscribe( - (res: ResponseDto) => { - let data: any; - if (res?.data?.length > 0) { - let lstToken = _.get(res, 'data').map((element) => { - data = element; - if (data) { - data.change = data.price_change_percentage_24h; - data.isValueUp = true; - data['balance'] = data['balance'] || 0; - if (data.change !== '-' && data.change < 0) { - data.isValueUp = false; - data.change = Number(data.change.toString().substring(1)); - } - if (data.contract_address === '-') { - this.total = data.price * data.balance + this.total; - } else if (data.verify_status === 'VERIFIED') { - const powValue = Math.pow(10, data.decimals); - let amountValue = data.balance / powValue; - amountValue = amountValue * data.price; - this.total = amountValue + this.total; + if (this.dataTable.length > 0) { + let result = this.dataTable.slice(payload?.offset, payload?.offset + payload?.limit); + // Search with text search + if (this.textSearch) { + const textSearch = this.textSearch.trim(); + result = this.dataTable.filter( + (item) => + item.name?.toLowerCase().includes(textSearch.toLowerCase()) || + item.contract_address == textSearch, + ); + + const data = result?.slice(payload?.offset, payload?.offset + payload?.limit); + this.dataSource = new MatTableDataSource(data); + this.pageData.length = result?.length; + } else { + this.dataSource = new MatTableDataSource(result); + this.pageData.length = this.dataTable?.length; + } + } else { + this.accountService.getAssetCW20ByOwner(payload).subscribe( + (res: ResponseDto) => { + let data: any; + if (res?.data?.length > 0) { + let lstToken = _.get(res, 'data').map((element) => { + data = element; + if (data) { + data.change = data.price_change_percentage_24h; + data.isValueUp = true; + data['balance'] = data['balance'] || 0; + if (data.change !== '-' && data.change < 0) { + data.isValueUp = false; + data.change = Number(data.change.toString().substring(1)); + } } - } - return data; - }); - - lstToken = lstToken.filter((k) => k?.symbol); - this.dataSource = new MatTableDataSource(lstToken); - this.pageData.length = res.meta.count; + return data; + }); + + lstToken = lstToken.filter((k) => k?.symbol); + // store datatable + this.dataTable = lstToken; + // Sort and slice 20 frist record. + const result = lstToken?.slice(payload?.offset, payload?.offset + payload?.limit); + this.dataSource = new MatTableDataSource(result); + this.pageData.length = res.meta.count; + } else { + this.pageData.length = 0; + this.dataSource.data = []; + } this.totalAssets.emit(this.pageData.length); - this.totalValue.emit(this.total); - } else { - this.pageData.length = 0; - this.dataSource.data = []; - } - }, - () => {}, - () => { - this.assetsLoading = false; - }, - ); + }, + () => {}, + () => { + this.assetsLoading = false; + }, + ); + } } convertValue(value: any, decimal: number) { return balanceOf(value, decimal); } - sortData(sort: Sort) {} - paginatorEmit(event): void { this.paginator = event; } handlePageEvent(e: any) { this.pageData.pageIndex = e.pageIndex; - this.getKeySearch(); - } - - getKeySearch() { - this.textSearch = this.textSearch?.trim(); this.getListToken(); } searchToken(): void { + this.searchValue = this.searchValue?.trim(); + this.textSearch = this.searchValue?.trim(); if (this.paginator.pageIndex !== 0) { this.paginator.firstPage(); } else { - this.getKeySearch(); - } - } - - checkSearch(): void { - if (this.textSearch.length === 0) { - this.searchToken(); + this.getListToken(); } } resetSearch(): void { this.textSearch = ''; + this.searchValue = ''; this.pageData.pageIndex = 0; this.searchToken(); } + + getTotalAssets(): void { + this.accountService.getTotalAssets(this.address).subscribe((res: ResponseDto) => { + this.total = res.data || 0; + this.totalValue.emit(this.total); + }); + } } diff --git a/src/app/pages/blocks/block-detail/block-detail.component.html b/src/app/pages/blocks/block-detail/block-detail.component.html index d86490463..6f4d07562 100644 --- a/src/app/pages/blocks/block-detail/block-detail.component.html +++ b/src/app/pages/blocks/block-detail/block-detail.component.html @@ -4,7 +4,7 @@ - +
-
+

{{ !isRawData ? 'Information' : 'Raw Data' }}

- +
+ + +

{{ !isRawData ? 'Information' : 'Raw Data' }}

- +
+ + +
-
+
Chain Id
-
{{ blockDetail?.chainid }}
+
{{ blockDetail?.chainid }}
-
+
Height
{{ blockDetail?.height }}
-
+
Block Time
{{ commonService.getDateValue(blockDetail?.timestamp)[0] }}
@@ -85,15 +87,15 @@

{{ !isRawData ? 'Information' : 'Raw Data' }}

-
+
Block Hash
{{ blockDetail?.block_hash }}
-
+
Number of Tx
{{ blockDetail?.num_txs }}
-
+
Gas
(used / wanted)
@@ -102,11 +104,11 @@

{{ !isRawData ? 'Information' : 'Raw Data' }}

{{ blockDetail?.gas_used | number }} / {{ blockDetail?.gas_wanted | number }}
-
+
Block Round
{{ blockDetail?.round | number }}
-
+ + + +
+

Events

+
+
+
+ + + +
+ {{ item.type }} +
+
+ +
+ +
+ +
+ {{ data.key | decodeData }} + {{ data.value | decodeData }} +
+
+
+
+
+
+
+
diff --git a/src/app/pages/blocks/block-detail/block-detail.component.scss b/src/app/pages/blocks/block-detail/block-detail.component.scss index 4e1d4a6e9..3b3f86560 100644 --- a/src/app/pages/blocks/block-detail/block-detail.component.scss +++ b/src/app/pages/blocks/block-detail/block-detail.component.scss @@ -10,3 +10,79 @@ padding-bottom: 2px !important; } } + +.box-event-log { + border-radius: 8px; + padding-left: calc(var(--bs-gutter-x) * 0.5); + overflow-y: auto; + background-color: transparent; + .item-event-log:not(:last-child) { + margin-bottom: var(--spacer-7); + } + .txt-event-key { + color: var(--aura-gray-4); + } + .mat-expansion-panel { + background: none; + box-shadow: none !important; + } +} + +.content-log { + position: relative; + &::before { + content: ''; + position: absolute; + left: 2.15px; + top: 0; + bottom: 10px; + width: 2px; + border-right: 2.5px dashed gray; + } + &::after { + content: ''; + position: absolute; + left: -5px; + bottom: -1px; + width: 0; + height: 0; + border-left: 8px solid transparent; + border-right: 8px solid transparent; + border-top: 10px solid gray; + border-radius: 3px; + } +} +::ng-deep mat-expansion-panel:last-child .mat-expansion-panel-content .content-log { + &::before { + bottom: 4px; + } + &::after { + content: unset; + } +} + +.mat-expansion-panel { + background: none; + box-shadow: none !important; + mat-expansion-panel-header { + padding: 0 12px; + .mat-expanded { + height: 48px; + } + .txt-header::after { + font-family: 'Font Awesome 5 Free'; + font-weight: 700; + content: '\f078'; + color: var(--aura-gray-1); + font-size: 13px; + } + &[aria-expanded='true'] { + .txt-header::after { + content: '\f077'; + } + } + } + .mat-expansion-panel-header.mat-expanded { + height: 48px; + } +} diff --git a/src/app/pages/blocks/block-detail/block-detail.component.ts b/src/app/pages/blocks/block-detail/block-detail.component.ts index ec0768ade..4e562bae3 100644 --- a/src/app/pages/blocks/block-detail/block-detail.component.ts +++ b/src/app/pages/blocks/block-detail/block-detail.component.ts @@ -1,4 +1,3 @@ -import { Clipboard } from '@angular/cdk/clipboard'; import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout'; import { Component, OnInit } from '@angular/core'; import { PageEvent } from '@angular/material/paginator'; @@ -14,7 +13,7 @@ import { PAGE_EVENT } from '../../../../app/core/constants/common.constant'; import { TableTemplate } from '../../../../app/core/models/common.model'; import { BlockService } from '../../../../app/core/services/block.service'; import { CommonService } from '../../../../app/core/services/common.service'; -import { convertDataBlock, convertDataTransaction, Globals } from '../../../../app/global/global'; +import { Globals, convertDataBlock, convertDataTransaction } from '../../../../app/global/global'; @Component({ selector: 'app-block-detail', @@ -22,8 +21,7 @@ import { convertDataBlock, convertDataTransaction, Globals } from '../../../../a styleUrls: ['./block-detail.component.scss'], }) export class BlockDetailComponent implements OnInit { - id: string | number; - blockId: string | number; + blockHeight: string | number; pageData: PageEvent = { length: PAGE_EVENT.LENGTH, pageSize: 20, @@ -46,7 +44,6 @@ export class BlockDetailComponent implements OnInit { { matColumnDef: 'tx_hash', headerCellDef: 'Tx Hash' }, { matColumnDef: 'type', headerCellDef: 'Type' }, { matColumnDef: 'status', headerCellDef: 'Result' }, - { matColumnDef: 'amount', headerCellDef: 'Amount' }, { matColumnDef: 'fee', headerCellDef: 'Fee' }, { matColumnDef: 'height', headerCellDef: 'Height' }, { matColumnDef: 'timestamp', headerCellDef: 'Time' }, @@ -83,44 +80,55 @@ export class BlockDetailComponent implements OnInit { private layout: BreakpointObserver, private environmentService: EnvironmentService, private transactionService: TransactionService, - private clipboard: Clipboard, ) {} ngOnInit(): void { - this.id = this.route.snapshot.paramMap.get('height'); - this.blockId = this.route.snapshot.paramMap.get('blockId'); - if (this.id === 'null' || this.blockId === 'null') { + this.blockHeight = this.route.snapshot.paramMap.get('height'); + if (this.blockHeight === 'null') { this.router.navigate(['/']); } this.getDetail(); } getDetail(): void { - if (this.id) { + if (this.blockHeight) { this.getDetailByHeight(); } } getDetailByHeight() { - this.blockService.blocksIndexer(1, this.id).subscribe( + let payload = { + limit: 1, + height: this.blockHeight, + }; + this.blockService.getDataBlock(payload).subscribe( async (res) => { - const { code, data } = res; - if (code === 200 && data?.blocks?.length > 0) { - const block = convertDataBlock(data)[0]; - block['round'] = _.get(data.blocks[0], 'block.last_commit.round'); - block['chainid'] = _.get(data.blocks[0], 'block.header.chain_id'); - block['json_data'] = _.get(data.blocks[0], 'block'); + if (res?.block?.length > 0) { + const block = convertDataBlock(res)[0]; + block['round'] = _.get(res.block[0], 'data.block.last_commit.round'); + block['chainid'] = _.get(res.block[0], 'data.block.header.chain_id'); + block['json_data'] = _.get(res.block[0], 'data.block'); block['gas_used'] = block['gas_wanted'] = 0; + block['events'] = _.get(res.block[0], 'data.block_result.begin_block_events'); + const blockEnd = _.get(res.block[0], 'data.block_result.end_block_events'); + if (blockEnd) { + block['events'] = block['events'].concat(blockEnd); + } this.blockDetail = block; //get list tx detail let txs = []; - for (const key in data.blocks[0]?.block?.data?.txs) { - const element = data.blocks[0].block?.data?.txs[key]; + for (const key in res.block[0]?.data?.block?.data?.txs) { + const element = res.block[0]?.data?.block?.data?.txs[key]; const tx = sha256(Buffer.from(element, 'base64')).toUpperCase(); - this.transactionService.txsIndexer(1, 0, tx).subscribe((res) => { - if (res.data.transactions[0]) { - txs.push(res.data.transactions[0]); + + const payload = { + limit: 1, + hash: tx, + }; + this.transactionService.getListTx(payload).subscribe((res) => { + if (res?.transaction[0]) { + txs.push(res?.transaction[0]); } }); } @@ -129,7 +137,7 @@ export class BlockDetailComponent implements OnInit { setTimeout(() => { if (txs?.length > 0) { let dataTempTx = {}; - dataTempTx['transactions'] = txs; + dataTempTx['transaction'] = txs; if (txs.length > 0) { txs = convertDataTransaction(dataTempTx, this.coinInfo); txs.forEach((k) => { @@ -179,18 +187,4 @@ export class BlockDetailComponent implements OnInit { paginatorEmit(event): void { this.dataSource.paginator = event; } - - copyData(text: string): void { - var dummy = document.createElement('textarea'); - document.body.appendChild(dummy); - this.clipboard.copy(JSON.stringify(text, null, 2)); - dummy.select(); - document.execCommand('copy'); - document.body.removeChild(dummy); - // fake event click out side copy button - // this event for hidden tooltip - setTimeout(function () { - document.getElementById('popupCopy').click(); - }, 800); - } } diff --git a/src/app/pages/blocks/blocks.component.ts b/src/app/pages/blocks/blocks.component.ts index 7d6428136..241e3ec09 100644 --- a/src/app/pages/blocks/blocks.component.ts +++ b/src/app/pages/blocks/blocks.component.ts @@ -2,7 +2,7 @@ import { Component, OnInit } from '@angular/core'; import { MatTableDataSource } from '@angular/material/table'; import { EnvironmentService } from 'src/app/core/data-services/environment.service'; import { getInfo } from 'src/app/core/utils/common/info-common'; -import { convertDataBlock, Globals } from 'src/app/global/global'; +import { Globals, convertDataBlock } from 'src/app/global/global'; import { TableTemplate } from '../../../app/core/models/common.model'; import { BlockService } from '../../../app/core/services/block.service'; import { CommonService } from '../../../app/core/services/common.service'; @@ -22,8 +22,6 @@ export class BlocksComponent implements OnInit { ]; displayedColumns: string[] = this.templates.map((dta) => dta.matColumnDef); dataSource: MatTableDataSource; - dataBlock: any[]; - pageSize = 20; loading = true; @@ -42,11 +40,13 @@ export class BlocksComponent implements OnInit { } getList(): void { - this.blockService.blocksIndexer(this.pageSize).subscribe( + const payload = { + limit: 20, + }; + this.blockService.getDataBlock(payload).subscribe( (res) => { - const { code, data } = res; - if (code === 200) { - const blocks = convertDataBlock(data); + if (res?.block?.length > 0) { + const blocks = convertDataBlock(res); this.dataSource = new MatTableDataSource(blocks); } }, @@ -59,7 +59,7 @@ export class BlocksComponent implements OnInit { getInfoCommon(): void { this.commonService.status().subscribe((res) => { - getInfo(this.globals, res.data); + getInfo(this.globals, res); }); } } diff --git a/src/app/pages/blocks/blocks.module.ts b/src/app/pages/blocks/blocks.module.ts index 308fe4307..47b65485d 100644 --- a/src/app/pages/blocks/blocks.module.ts +++ b/src/app/pages/blocks/blocks.module.ts @@ -1,10 +1,13 @@ +import { ClipboardModule } from '@angular/cdk/clipboard'; import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { NgbNavModule } from '@ng-bootstrap/ng-bootstrap'; import { TranslateModule } from '@ngx-translate/core'; -import { NgxMaskModule } from 'ngx-mask'; +import { MaskPipe, NgxMaskModule } from 'ngx-mask'; +import { CommonDirectiveModule } from 'src/app/core/directives/common-directive.module'; import { PaginatorModule } from 'src/app/shared/components/paginator/paginator.module'; +import { TooltipCustomizeModule } from 'src/app/shared/components/tooltip-customize/tooltip-customize.module'; import { MaterialModule } from '../../../app/app.module'; import { CommonPipeModule } from '../../../app/core/pipes/common-pipe.module'; import { BlockService } from '../../../app/core/services/block.service'; @@ -29,7 +32,10 @@ import { BlocksComponent } from './blocks.component'; TableNoDataModule, NgbNavModule, PaginatorModule, + CommonDirectiveModule, + TooltipCustomizeModule, + ClipboardModule, ], - providers: [BlockService], + providers: [BlockService, MaskPipe], }) export class BlocksModule {} diff --git a/src/app/pages/code-ids/code-id-detail/code-id-contracts-tab/code-id-contracts-tab.component.html b/src/app/pages/code-ids/code-id-detail/code-id-contracts-tab/code-id-contracts-tab.component.html index 514696b10..5db0ae977 100644 --- a/src/app/pages/code-ids/code-id-detail/code-id-contracts-tab/code-id-contracts-tab.component.html +++ b/src/app/pages/code-ids/code-id-detail/code-id-contracts-tab/code-id-contracts-tab.component.html @@ -1,8 +1,8 @@
A total of {{ pageData.length }} record{{ pageData.length > 1 ? 's' : '' }} found
-
- +
+
ASSET CONTRACT ADDRESS - - -
- {{ element.contract_address | cutStringPipe : 8 : 8 }} -
-
+ -
@@ -11,12 +11,7 @@ - - -
- - {{ shortenAddress(data[template.matColumnDef]) || '-' }} - + - - {{ shortenAddress(data[template.matColumnDef]) || '-' }} - +
{{ data[template.matColumnDef] }}
@@ -54,20 +46,13 @@
- {{ 'NO DATA' | translate }} -
- - + +
+ +
diff --git a/src/app/pages/code-ids/code-id-detail/code-id-contracts-tab/code-id-contracts-tab.component.ts b/src/app/pages/code-ids/code-id-detail/code-id-contracts-tab/code-id-contracts-tab.component.ts index ef823de5d..b9b6facdc 100644 --- a/src/app/pages/code-ids/code-id-detail/code-id-contracts-tab/code-id-contracts-tab.component.ts +++ b/src/app/pages/code-ids/code-id-detail/code-id-contracts-tab/code-id-contracts-tab.component.ts @@ -2,11 +2,14 @@ import { DatePipe } from '@angular/common'; import { Component, Input, OnInit } from '@angular/core'; import { PageEvent } from '@angular/material/paginator'; import { MatTableDataSource } from '@angular/material/table'; -import { DATEFORMAT, PAGE_EVENT } from 'src/app/core/constants/common.constant'; -import { CONTRACT_RESULT } from 'src/app/core/constants/contract.constant'; +import * as _ from 'lodash'; +import { DATEFORMAT, LENGTH_CHARACTER, PAGE_EVENT } from 'src/app/core/constants/common.constant'; +import { TYPE_CW4973 } from 'src/app/core/constants/contract.constant'; +import { ContractRegisterType } from 'src/app/core/constants/contract.enum'; import { TableTemplate } from 'src/app/core/models/common.model'; import { ContractService } from 'src/app/core/services/contract.service'; import { shortenAddress } from '../../../../core/utils/common/shorten'; +import { CommonService } from 'src/app/core/services/common.service'; @Component({ selector: 'app-code-id-contracts-tab', @@ -18,9 +21,9 @@ export class CodeIdContractsTabComponent implements OnInit { pageData: PageEvent = { length: PAGE_EVENT.LENGTH, pageSize: 20, - pageIndex: PAGE_EVENT.PAGE_INDEX, + pageIndex: 1, }; - dataSource: MatTableDataSource; + dataSource: MatTableDataSource = new MatTableDataSource([]); templates: Array = [ { matColumnDef: 'contract_address', headerCellDef: 'CONTRACT ADDRESS', isUrl: '/contracts' }, { matColumnDef: 'tx_hash', headerCellDef: 'TX HASH', isUrl: '/transaction' }, @@ -30,11 +33,14 @@ export class CodeIdContractsTabComponent implements OnInit { { matColumnDef: 'verified_at', headerCellDef: 'Verified at' }, ]; displayedColumns: string[] = this.templates.map((dta) => dta.matColumnDef); - constructor(private contractService: ContractService, private datePipe: DatePipe) {} + lengthAddress = LENGTH_CHARACTER.ADDRESS; + + constructor(private contractService: ContractService, private datePipe: DatePipe, public commonService: CommonService) {} ngOnInit(): void { - this.getListContract(); + this.getListContractByCode(); } + shortenAddress(address: string): string { if (address) { return shortenAddress(address, 8); @@ -42,35 +48,36 @@ export class CodeIdContractsTabComponent implements OnInit { return ''; } - paginatorEmit(event): void { - this.dataSource.paginator = event; - } - - pageEvent(e: PageEvent): void { - this.pageData.pageIndex = e.pageIndex; - this.getListContract(); + pageEvent(pageIndex: number): void { + // reset page 1 if pageIndex = 0 + if (pageIndex === 0) { + this.pageData.pageIndex = 1; + } + this.getListContractByCode(); } - getListContract() { + getListContractByCode() { let payload = { limit: this.pageData.pageSize, - offset: this.pageData.pageIndex * this.pageData.pageSize, - keyword: this.codeId.toString(), - contractType: [], + offset: (this.pageData.pageIndex - 1) * this.pageData.pageSize, + codeId: this.codeId.toString(), }; - this.contractService.getListContract(payload).subscribe((res) => { - this.pageData.length = res?.meta?.count; - if (res?.data?.length > 0) { - res.data.forEach((item) => { - item.updated_at = this.datePipe.transform(item.updated_at, DATEFORMAT.DATETIME_UTC); - if (item.result === CONTRACT_RESULT.INCORRECT || !item.type) { - item.type = '-'; - } else if (item.result === CONTRACT_RESULT.TBD) { - item.type = CONTRACT_RESULT.TBD; + this.contractService.getListContractByCode(payload).subscribe((res) => { + this.pageData.length = res?.smart_contract_aggregate?.aggregate?.count || 0; + if (res?.smart_contract?.length > 0) { + res?.smart_contract.forEach((item) => { + item.updated_at = this.datePipe.transform(item?.created_at, DATEFORMAT.DATETIME_UTC); + item.contract_address = item?.address; + item.tx_hash = item?.instantiate_hash; + item.creator_address = item?.creator; + item.verified_at = _.get(item, 'code.code_id_verifications[0].verified_at'); + item.type = item.code?.type || '-'; + if (item.type === ContractRegisterType.CW721 && item.smart_contracts?.name === TYPE_CW4973) { + item.type = ContractRegisterType.CW4973; } }); - this.dataSource = res.data; + this.dataSource.data = res.smart_contract; } }); } diff --git a/src/app/pages/code-ids/code-id-detail/code-id-detail.component.html b/src/app/pages/code-ids/code-id-detail/code-id-detail.component.html index 1ee0074ee..bf35ec4a0 100644 --- a/src/app/pages/code-ids/code-id-detail/code-id-detail.component.html +++ b/src/app/pages/code-ids/code-id-detail/code-id-detail.component.html @@ -17,12 +17,10 @@

Information

Creator
@@ -44,13 +42,7 @@

Information

- {{ - codeIdDetail.result === contractResult.CORRECT - ? codeIdDetail.type - : codeIdDetail.result === contractResult.TBD - ? contractResult.TBD - : '-' - }} + {{ codeIdDetail.type || '-' }}
diff --git a/src/app/pages/code-ids/code-id-detail/code-id-detail.component.ts b/src/app/pages/code-ids/code-id-detail/code-id-detail.component.ts index 4f9f9c02d..5f3777298 100644 --- a/src/app/pages/code-ids/code-id-detail/code-id-detail.component.ts +++ b/src/app/pages/code-ids/code-id-detail/code-id-detail.component.ts @@ -1,6 +1,10 @@ import { Component, OnInit } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; -import { CONTRACT_RESULT } from 'src/app/core/constants/contract.constant'; +import * as _ from 'lodash'; +import { LENGTH_CHARACTER } from 'src/app/core/constants/common.constant'; +import { CONTRACT_RESULT, TYPE_CW4973 } from 'src/app/core/constants/contract.constant'; +import { ContractRegisterType } from 'src/app/core/constants/contract.enum'; +import { CommonService } from 'src/app/core/services/common.service'; import { ContractService } from 'src/app/core/services/contract.service'; @Component({ selector: 'app-code-id-detail', @@ -22,8 +26,14 @@ export class CodeIdDetailComponent implements OnInit { ]; codeIdDetail; contractResult = CONTRACT_RESULT; + lengthNormalAddress = LENGTH_CHARACTER.ADDRESS; - constructor(private router: ActivatedRoute, public route: Router, private contractService: ContractService) {} + constructor( + private router: ActivatedRoute, + public route: Router, + private contractService: ContractService, + public commonService: CommonService, + ) {} ngOnInit(): void { this.codeId = this.router.snapshot.paramMap.get('codeId'); @@ -41,7 +51,18 @@ export class CodeIdDetailComponent implements OnInit { getCodeIdDetail() { this.contractService.getCodeIDDetail(this.codeId).subscribe((res) => { - this.codeIdDetail = res.data; + if (res.code?.length > 0) { + let data = res.code[0]; + data.instantiates = data.smart_contracts_aggregate?.aggregate?.count || 0; + data.tx_hash = data.store_hash; + data.verified_at = _.get(data, 'code_id_verifications[0].verified_at'); + data.contract_verification = _.get(data, 'code_id_verifications[0].verification_status'); + if (data.type === ContractRegisterType.CW721 && data.smart_contracts[0]?.name === TYPE_CW4973) { + data.type = ContractRegisterType.CW4973; + } + + this.codeIdDetail = data; + } }); } } diff --git a/src/app/pages/code-ids/code-id-detail/verify-code-id/verify-code-id.component.html b/src/app/pages/code-ids/code-id-detail/verify-code-id/verify-code-id.component.html index 5dc892257..f9562ec09 100644 --- a/src/app/pages/code-ids/code-id-detail/verify-code-id/verify-code-id.component.html +++ b/src/app/pages/code-ids/code-id-detail/verify-code-id/verify-code-id.component.html @@ -4,7 +4,7 @@
- +
- +
- +
- +
Code ID Verified
@@ -84,15 +84,16 @@ class="form-control form-check-input body mt-0 text--gray-1" readonly value="{{ codeIdDetail.url }}" /> - +
+ + +
diff --git a/src/app/pages/code-ids/code-id-detail/verify-code-id/verify-code-id.component.ts b/src/app/pages/code-ids/code-id-detail/verify-code-id/verify-code-id.component.ts index ce17d550a..8e8bdc928 100644 --- a/src/app/pages/code-ids/code-id-detail/verify-code-id/verify-code-id.component.ts +++ b/src/app/pages/code-ids/code-id-detail/verify-code-id/verify-code-id.component.ts @@ -1,6 +1,8 @@ import { Component, Input, OnInit } from '@angular/core'; import { Router } from '@angular/router'; +import * as _ from 'lodash'; import { ContractVerifyType } from 'src/app/core/constants/contract.enum'; +import { CommonService } from 'src/app/core/services/common.service'; import { ContractService } from 'src/app/core/services/contract.service'; @Component({ @@ -12,38 +14,36 @@ export class VerifyCodeIdComponent implements OnInit { @Input() codeId: any; loading = true; codeIdDetail: any; - contractStatus: any = ContractVerifyType.Unverified; contractVerifyType = ContractVerifyType; - constructor(private contractService: ContractService, private router: Router) {} + + constructor(private contractService: ContractService, private router: Router, public commonService: CommonService) {} ngOnInit(): void { this.getCodeIdDetail(); } - copyData(text: string): void { - var dummy = document.createElement('textarea'); - document.body.appendChild(dummy); - dummy.value = text; - dummy.select(); - document.execCommand('copy'); - document.body.removeChild(dummy); - // fake event click out side copy button - // this event for hidden tooltip - setTimeout(function () { - document.getElementById('popupCopy').click(); - }, 800); - } - navigateToVerify() { sessionStorage.setItem('codeIdPrePage', this.router.url); this.router.navigate(['/code-ids/verify', this.codeId]); } getCodeIdDetail() { - this.contractService.getCodeIDDetail(this.codeId).subscribe((res) => { - this.codeIdDetail = res.data; - this.contractStatus = this.codeIdDetail?.contract_verification; - this.loading = false; - }); + this.contractService.getCodeIDDetail(this.codeId).subscribe( + (res) => { + if (res.code?.length > 0) { + let data = res.code[0]; + data.compiler_version = _.get(data, 'code_id_verifications[0].compiler_version'); + data.verified_at = _.get(data, 'code_id_verifications[0].verified_at'); + data.contract_verification = _.get(data, 'code_id_verifications[0].verification_status'); + data.url = _.get(data, 'code_id_verifications[0].github_url'); + + this.codeIdDetail = data; + } + }, + () => {}, + () => { + this.loading = false; + }, + ); } } diff --git a/src/app/pages/code-ids/code-id-list/code-id-list.component.html b/src/app/pages/code-ids/code-id-list/code-id-list.component.html index 5dcb73eef..46309945d 100644 --- a/src/app/pages/code-ids/code-id-list/code-id-list.component.html +++ b/src/app/pages/code-ids/code-id-list/code-id-list.component.html @@ -10,7 +10,7 @@

Code IDs

Code IDs Code IDs
- - {{ shortenAddress(data[template.matColumnDef]) || '-' }} - +
- {{ - data['result'] === contractResult.CORRECT - ? data[template.matColumnDef] - : data['result'] === contractResult.TBD - ? contractResult.TBD - : '-' - }} + {{ data[template.matColumnDef] || '-' }}
@@ -127,8 +116,12 @@

Code IDs

- - {{data['verified_at'] | customDate : 'yyyy-MM-dd HH:mm:ss'}} + + {{ data['verified_at'] | customDate : 'yyyy-MM-dd HH:mm:ss' }} - diff --git a/src/app/pages/code-ids/code-id-list/code-id-list.component.scss b/src/app/pages/code-ids/code-id-list/code-id-list.component.scss index 6a86e4dcd..168cf64d8 100644 --- a/src/app/pages/code-ids/code-id-list/code-id-list.component.scss +++ b/src/app/pages/code-ids/code-id-list/code-id-list.component.scss @@ -2,7 +2,7 @@ width: 100%; @media (min-width: 992px) { - width: 500px; + width: 550px; } .box-search-data { diff --git a/src/app/pages/code-ids/code-id-list/code-id-list.component.ts b/src/app/pages/code-ids/code-id-list/code-id-list.component.ts index 4debe7c82..aac64fbbc 100644 --- a/src/app/pages/code-ids/code-id-list/code-id-list.component.ts +++ b/src/app/pages/code-ids/code-id-list/code-id-list.component.ts @@ -4,13 +4,14 @@ import { MatTableDataSource } from '@angular/material/table'; import { Subject } from 'rxjs'; import { debounceTime, distinctUntilChanged, takeUntil } from 'rxjs/operators'; import { PAGE_EVENT } from 'src/app/core/constants/common.constant'; -import { CONTRACT_RESULT } from 'src/app/core/constants/contract.constant'; -import { ContractVerifyType } from 'src/app/core/constants/contract.enum'; +import { CONTRACT_RESULT, TYPE_CW4973 } from 'src/app/core/constants/contract.constant'; +import { ContractRegisterType, ContractVerifyType } from 'src/app/core/constants/contract.enum'; import { MAX_LENGTH_SEARCH_TOKEN } from 'src/app/core/constants/token.constant'; import { TableTemplate } from 'src/app/core/models/common.model'; import { ContractService } from 'src/app/core/services/contract.service'; import { PaginatorComponent } from 'src/app/shared/components/paginator/paginator.component'; import { shortenAddress } from '../../../core/utils/common/shorten'; +import { CommonService } from 'src/app/core/services/common.service'; @Component({ selector: 'app-code-id-list', @@ -42,7 +43,8 @@ export class CodeIdListComponent implements OnInit, OnDestroy { displayedColumns: string[] = this.templates.map((dta) => dta.matColumnDef); contractResult = CONTRACT_RESULT; contractVerifyType = ContractVerifyType; - constructor(private contractService: ContractService) {} + + constructor(private contractService: ContractService, public commonService: CommonService) {} ngOnInit(): void { this.getListCodeIds(); @@ -69,15 +71,31 @@ export class CodeIdListComponent implements OnInit, OnDestroy { } getListCodeIds() { + this.textSearch = this.textSearch?.trim(); let payload = { limit: this.pageData.pageSize, offset: this.pageData.pageIndex * this.pageData.pageSize, keyword: this.textSearch, }; - this.contractService.getListCodeID(payload).subscribe((res) => { - this.dataSource.data = res.data; - this.pageData.length = res?.meta?.count; + const addressNameTag = this.commonService.findNameTag(this.textSearch); + if (addressNameTag?.length > 0) { + payload['keyword'] = addressNameTag; + } + + this.contractService.getListCodeId(payload).subscribe((res) => { + res?.code?.forEach((k) => { + k.instantiates = k.smart_contracts_aggregate?.aggregate?.count || 0; + k.tx_hash = k.store_hash; + k.verified_at = k.code_id_verifications[0]?.verified_at; + k.contract_verification = k.code_id_verifications[0]?.verification_status; + if (k.type === ContractRegisterType.CW721 && k.smart_contracts[0]?.name === TYPE_CW4973) { + k.type = ContractRegisterType.CW4973; + } + }); + + this.dataSource.data = res.code; + this.pageData.length = res?.code_aggregate?.aggregate?.count || 0; }); } diff --git a/src/app/pages/code-ids/code-ids.module.ts b/src/app/pages/code-ids/code-ids.module.ts index fbd70e3d2..29e761a88 100644 --- a/src/app/pages/code-ids/code-ids.module.ts +++ b/src/app/pages/code-ids/code-ids.module.ts @@ -1,3 +1,4 @@ +import { ClipboardModule } from '@angular/cdk/clipboard'; import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; @@ -6,8 +7,11 @@ import { TranslateModule } from '@ngx-translate/core'; import { MaterialModule } from 'src/app/app.module'; import { CommonPipeModule } from 'src/app/core/pipes/common-pipe.module'; import { ContractService } from 'src/app/core/services/contract.service'; +import { APaginatorModule } from 'src/app/shared/components/a-paginator/a-paginator.module'; +import { NameTagModule } from 'src/app/shared/components/name-tag/name-tag.module'; import { PaginatorModule } from 'src/app/shared/components/paginator/paginator.module'; import { TableNoDataModule } from 'src/app/shared/components/table-no-data/table-no-data.module'; +import { TooltipCustomizeModule } from 'src/app/shared/components/tooltip-customize/tooltip-customize.module'; import { SharedModule } from 'src/app/shared/shared.module'; import { ContractsModule } from '../contracts/contracts.module'; import { CodeIdContractsTabComponent } from './code-id-detail/code-id-contracts-tab/code-id-contracts-tab.component'; @@ -30,6 +34,10 @@ import { CodeIdsRoutingModule } from './code-ids-routing.module'; SharedModule, NgbNavModule, ContractsModule, + APaginatorModule, + NameTagModule, + TooltipCustomizeModule, + ClipboardModule, ], providers: [ContractService], }) diff --git a/src/app/pages/community-pool/asset-list/community-pool-asset.component.html b/src/app/pages/community-pool/asset-list/community-pool-asset.component.html new file mode 100644 index 000000000..1a826edd5 --- /dev/null +++ b/src/app/pages/community-pool/asset-list/community-pool-asset.component.html @@ -0,0 +1,112 @@ +
+ +
+
+ +
+

Asset

+ +
+ + + +
+ +
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Name +
+ +
{{ element.name }}
+
+
Symbol + {{ element.symbol ? element.symbol : 'AURA' }} + Amount + + +
+ {{ 'NO DATA' | translate }} +
+
+ + +
+ + + + + + + + + + + + + +
+
+
+ - +
diff --git a/src/app/pages/community-pool/asset-list/community-pool-asset.component.scss b/src/app/pages/community-pool/asset-list/community-pool-asset.component.scss new file mode 100644 index 000000000..53665edea --- /dev/null +++ b/src/app/pages/community-pool/asset-list/community-pool-asset.component.scss @@ -0,0 +1,15 @@ +.search-form { + min-width: 100%; + + @media (min-width: 992px) { + min-width: 410px; + } +} + +.aura-table.community-pool-assets-table th.mat-header-cell { + width: 33%; +} + +.vertical-align-top { + vertical-align: top; +} diff --git a/src/app/pages/community-pool/asset-list/community-pool-asset.component.ts b/src/app/pages/community-pool/asset-list/community-pool-asset.component.ts new file mode 100644 index 000000000..b806bef6a --- /dev/null +++ b/src/app/pages/community-pool/asset-list/community-pool-asset.component.ts @@ -0,0 +1,177 @@ +import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout'; +import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; +import { MatPaginator, PageEvent } from '@angular/material/paginator'; +import { MatTableDataSource } from '@angular/material/table'; +import { TranslateService } from '@ngx-translate/core'; +import * as _ from 'lodash'; +import { Subject } from 'rxjs'; +import { debounceTime, distinctUntilChanged, takeUntil } from 'rxjs/operators'; +import { NUMBER_CONVERT, PAGE_EVENT } from 'src/app/core/constants/common.constant'; +import { PROPOSAL_STATUS } from 'src/app/core/constants/proposal.constant'; +import { MAX_LENGTH_SEARCH_TOKEN } from 'src/app/core/constants/token.constant'; +import { EnvironmentService } from 'src/app/core/data-services/environment.service'; +import { TableTemplate } from 'src/app/core/models/common.model'; +import { TokenService } from 'src/app/core/services/token.service'; +import { balanceOf } from 'src/app/core/utils/common/parsing'; +import { shortenAddress } from 'src/app/core/utils/common/shorten'; +import { PaginatorComponent } from 'src/app/shared/components/paginator/paginator.component'; + +@Component({ + selector: 'app-community-pool-asset', + templateUrl: './community-pool-asset.component.html', + styleUrls: ['./community-pool-asset.component.scss'], +}) +export class CommunityPoolAssetComponent implements OnInit, OnDestroy { + @ViewChild(PaginatorComponent) pageChange: PaginatorComponent; + @ViewChild(MatPaginator) paginator: MatPaginator; + textSearch = ''; + templates: Array = [ + { matColumnDef: 'name', headerCellDef: 'name' }, + { matColumnDef: 'symbol', headerCellDef: 'symbol' }, + { matColumnDef: 'amount', headerCellDef: 'amount' }, + ]; + + displayedColumns: string[] = this.templates.map((dta) => dta.matColumnDef); + pageData: PageEvent = { + length: PAGE_EVENT.LENGTH, + pageSize: 10, + pageIndex: PAGE_EVENT.PAGE_INDEX, + }; + pageSizeMob = 5; + breakpoint$ = this.layout.observe([Breakpoints.Small, Breakpoints.XSmall]); + dataSource: MatTableDataSource; + dataSourceMob: any[]; + filterSearchData = []; + maxLengthSearch = MAX_LENGTH_SEARCH_TOKEN; + denom = this.environmentService.configValue.chain_info.currencies[0].coinDenom; + image_s3 = this.environmentService.configValue.image_s3; + defaultLogoToken = this.image_s3 + 'images/icons/token-logo.png'; + listCoin = this.environmentService.configValue.coins; + listAssetLcd = []; + searchSubject = new Subject(); + destroy$ = new Subject(); + statusConstant = PROPOSAL_STATUS; + + constructor( + public translate: TranslateService, + public tokenService: TokenService, + private environmentService: EnvironmentService, + private layout: BreakpointObserver, + ) {} + + ngOnDestroy(): void { + // throw new Error('Method not implemented.'); + this.destroy$.next(); + this.destroy$.complete(); + } + + ngOnInit(): void { + this.getListAsset(); + + this.searchSubject + .asObservable() + .pipe(debounceTime(500), distinctUntilChanged(), takeUntil(this.destroy$)) + .subscribe(() => { + if (this.pageData.pageIndex === PAGE_EVENT.PAGE_INDEX) { + this.getListAsset(); + } else { + this.pageChange.selectPage(0); + } + }); + } + + onKeyUp() { + this.searchSubject.next(this.textSearch); + } + + shortenAddress(address: string): string { + if (address) { + return shortenAddress(address, 8); + } + return ''; + } + + async getListAsset() { + let auraAsset; + if (this.textSearch) { + this.filterSearchData = this.listAssetLcd; + this.filterSearchData = this.filterSearchData.filter( + (k) => + k.name.toLowerCase().includes(this.textSearch.toLowerCase()) === true || + k.symbol.toLowerCase().includes(this.textSearch.toLowerCase()) === true, + ); + this.dataSource.data = this.filterSearchData.slice( + this.pageData.pageIndex * this.pageData.pageSize, + this.pageData.pageIndex * this.pageData.pageSize + this.pageData.pageSize, + ); + this.dataSourceMob = this.filterSearchData.slice( + this.pageData.pageIndex * this.pageSizeMob, + this.pageData.pageIndex * this.pageSizeMob + this.pageSizeMob, + ); + this.pageData.length = this.filterSearchData.length; + } else { + const res = await this.tokenService.getListAssetCommunityPool(); + this.listAssetLcd = _.get(res, 'data.pool'); + + this.listAssetLcd.forEach((element) => { + let findItem = this.listCoin.find((i) => i.denom === element.denom); + if (findItem) { + element.decimal = findItem.decimal; + element.symbol = findItem.display; + element.logo = findItem.logo; + element.name = findItem.name; + } else { + element.decimal = 6; + element.symbol = ''; + element.logo = ''; + element.name = 'Aura'; + element.amount = element.amount / NUMBER_CONVERT; + auraAsset = element; + } + }); + this.listAssetLcd = this.listAssetLcd.filter((k) => k.symbol !== ''); + this.listAssetLcd = this.listAssetLcd.sort((a, b) => { + return this.compare(balanceOf(a.amount, a.decimal), balanceOf(b.amount, b.decimal), false); + }); + this.listAssetLcd.unshift(auraAsset); + this.filterSearchData = this.listAssetLcd; + if (!this.dataSource) { + this.dataSource = new MatTableDataSource(this.listAssetLcd); + this.dataSourceMob = this.listAssetLcd.slice( + this.pageData.pageIndex * this.pageSizeMob, + this.pageData.pageIndex * this.pageSizeMob + this.pageSizeMob, + ); + } else { + this.dataSource.data = this.listAssetLcd; + this.dataSourceMob = this.listAssetLcd.slice( + this.pageData.pageIndex * this.pageSizeMob, + this.pageData.pageIndex * this.pageSizeMob + this.pageSizeMob, + ); + } + this.pageData.length = this.listAssetLcd.length; + } + } + + paginatorEmit(event): void { + if (this.dataSource) { + this.dataSource.paginator = event; + } else { + this.dataSource = new MatTableDataSource(); + this.dataSource.paginator = event; + } + } + + compare(a: number | string, b: number | string, isAsc: boolean) { + return (a < b ? -1 : 1) * (isAsc ? 1 : -1); + } + + resetSearch() { + this.textSearch = ''; + this.onKeyUp(); + } + + pageEvent(e: PageEvent): void { + this.pageData.pageIndex = e.pageIndex; + this.getListAsset(); + } +} diff --git a/src/app/pages/community-pool/community-pool.component.html b/src/app/pages/community-pool/community-pool.component.html index 03acc488a..6b4f37bd7 100644 --- a/src/app/pages/community-pool/community-pool.component.html +++ b/src/app/pages/community-pool/community-pool.component.html @@ -1,113 +1,3 @@

Community Pool Details

-
- -
-
- -
-

Asset

-
-
- - - -
-
-
-
- - -
- - - - - - - - - - - - - - - - - - - - - - - - -
Name -
- -
{{ element.name }}
-
-
Symbol - {{ element.symbol ? element.symbol : 'AURA' }} - Amount - - -
- {{ 'NO DATA' | translate }} -
-
- - -
- - - - - - - - - - - - - -
-
-
- - -
+ + diff --git a/src/app/pages/community-pool/community-pool.component.scss b/src/app/pages/community-pool/community-pool.component.scss index 3daeda372..e69de29bb 100644 --- a/src/app/pages/community-pool/community-pool.component.scss +++ b/src/app/pages/community-pool/community-pool.component.scss @@ -1,16 +0,0 @@ -.search-form { - min-width: 100%; - @media (min-width: 992px) { - min-width: 410px; - } -} - -@media (min-width: 991.99px) { - ::ng-deep table.aura-table th.mat-header-cell { - width: 33%; - } -} - -.vertical-align-top { - vertical-align: top; -} \ No newline at end of file diff --git a/src/app/pages/community-pool/community-pool.component.ts b/src/app/pages/community-pool/community-pool.component.ts index be0250ae0..3ef0213e6 100644 --- a/src/app/pages/community-pool/community-pool.component.ts +++ b/src/app/pages/community-pool/community-pool.component.ts @@ -1,165 +1,12 @@ -import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout'; -import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; -import { MatPaginator, PageEvent } from '@angular/material/paginator'; -import { MatTableDataSource } from '@angular/material/table'; -import { TranslateService } from '@ngx-translate/core'; -import * as _ from 'lodash'; -import { Subject } from 'rxjs'; -import { debounceTime, distinctUntilChanged, takeUntil } from 'rxjs/operators'; -import { NUMBER_CONVERT, PAGE_EVENT } from 'src/app/core/constants/common.constant'; -import { MAX_LENGTH_SEARCH_TOKEN } from 'src/app/core/constants/token.constant'; -import { EnvironmentService } from 'src/app/core/data-services/environment.service'; -import { TableTemplate } from 'src/app/core/models/common.model'; -import { TokenService } from 'src/app/core/services/token.service'; -import { balanceOf } from 'src/app/core/utils/common/parsing'; -import { PaginatorComponent } from 'src/app/shared/components/paginator/paginator.component'; +import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-community-pool', templateUrl: './community-pool.component.html', styleUrls: ['./community-pool.component.scss'], }) -export class CommunityPoolComponent implements OnInit, OnDestroy { - @ViewChild(PaginatorComponent) pageChange: PaginatorComponent; - @ViewChild(MatPaginator) paginator: MatPaginator; - textSearch = ''; - templates: Array = [ - { matColumnDef: 'name', headerCellDef: 'name' }, - { matColumnDef: 'symbol', headerCellDef: 'symbol' }, - { matColumnDef: 'amount', headerCellDef: 'amount' }, - ]; - displayedColumns: string[] = this.templates.map((dta) => dta.matColumnDef); - pageData: PageEvent = { - length: PAGE_EVENT.LENGTH, - pageSize: 10, - pageIndex: PAGE_EVENT.PAGE_INDEX, - }; - pageSizeMob = 5; - breakpoint$ = this.layout.observe([Breakpoints.Small, Breakpoints.XSmall]); - dataSource: MatTableDataSource; - dataSourceMob: any[]; - filterSearchData = []; - maxLengthSearch = MAX_LENGTH_SEARCH_TOKEN; - denom = this.environmentService.configValue.chain_info.currencies[0].coinDenom; - image_s3 = this.environmentService.configValue.image_s3; - defaultLogoToken = this.image_s3 + 'images/icons/token-logo.png'; - listCoin = this.environmentService.configValue.coins; - listAssetLcd = []; - searchSubject = new Subject(); - destroy$ = new Subject(); +export class CommunityPoolComponent implements OnInit { + constructor() {} - constructor( - public translate: TranslateService, - public tokenService: TokenService, - private environmentService: EnvironmentService, - private layout: BreakpointObserver, - ) {} - - ngOnDestroy(): void { - // throw new Error('Method not implemented.'); - this.destroy$.next(); - this.destroy$.complete(); - } - - ngOnInit(): void { - this.getListAsset(); - this.searchSubject - .asObservable() - .pipe(debounceTime(500), distinctUntilChanged(), takeUntil(this.destroy$)) - .subscribe(() => { - if (this.pageData.pageIndex === PAGE_EVENT.PAGE_INDEX) { - this.getListAsset(); - } else { - this.pageChange.selectPage(0); - } - }); - } - - onKeyUp() { - this.searchSubject.next(this.textSearch); - } - - async getListAsset() { - let auraAsset; - if (this.textSearch) { - this.filterSearchData = this.listAssetLcd; - this.filterSearchData = this.filterSearchData.filter( - (k) => - k.name.toLowerCase().includes(this.textSearch.toLowerCase()) === true || - k.symbol.toLowerCase().includes(this.textSearch.toLowerCase()) === true, - ); - this.dataSource.data = this.filterSearchData.slice( - this.pageData.pageIndex * this.pageData.pageSize, - this.pageData.pageIndex * this.pageData.pageSize + this.pageData.pageSize, - ); - this.dataSourceMob = this.filterSearchData.slice( - this.pageData.pageIndex * this.pageSizeMob, - this.pageData.pageIndex * this.pageSizeMob + this.pageSizeMob, - ); - this.pageData.length = this.filterSearchData.length; - } else { - const res = await this.tokenService.getListAssetCommunityPool(); - this.listAssetLcd = _.get(res, 'data.pool'); - - this.listAssetLcd.forEach((element) => { - let findItem = this.listCoin.find((i) => i.denom === element.denom); - if (findItem) { - element.decimal = findItem.decimal; - element.symbol = findItem.display; - element.logo = findItem.logo; - element.name = findItem.name; - } else { - element.decimal = 6; - element.symbol = ''; - element.logo = ''; - element.name = 'Aura'; - element.amount = element.amount / NUMBER_CONVERT; - auraAsset = element; - } - }); - this.listAssetLcd = this.listAssetLcd.filter((k) => k.symbol !== ''); - this.listAssetLcd = this.listAssetLcd.sort((a, b) => { - return this.compare(balanceOf(a.amount, a.decimal), balanceOf(b.amount, b.decimal), false); - }); - this.listAssetLcd.unshift(auraAsset); - this.filterSearchData = this.listAssetLcd; - if (!this.dataSource) { - this.dataSource = new MatTableDataSource(this.listAssetLcd); - this.dataSourceMob = this.listAssetLcd.slice( - this.pageData.pageIndex * this.pageSizeMob, - this.pageData.pageIndex * this.pageSizeMob + this.pageSizeMob, - ); - } else { - this.dataSource.data = this.listAssetLcd; - this.dataSourceMob = this.listAssetLcd.slice( - this.pageData.pageIndex * this.pageSizeMob, - this.pageData.pageIndex * this.pageSizeMob + this.pageSizeMob, - ); - } - this.pageData.length = this.listAssetLcd.length; - } - } - - paginatorEmit(event): void { - if (this.dataSource) { - this.dataSource.paginator = event; - } else { - this.dataSource = new MatTableDataSource(); - this.dataSource.paginator = event; - } - } - - compare(a: number | string, b: number | string, isAsc: boolean) { - return (a < b ? -1 : 1) * (isAsc ? 1 : -1); - } - - resetSearch() { - this.textSearch = ''; - this.onKeyUp(); - } - - pageEvent(e: PageEvent): void { - this.pageData.pageIndex = e.pageIndex; - this.getListAsset(); - } + ngOnInit(): void {} } diff --git a/src/app/pages/community-pool/community-pool.module.ts b/src/app/pages/community-pool/community-pool.module.ts index 44d155144..47d8ac174 100644 --- a/src/app/pages/community-pool/community-pool.module.ts +++ b/src/app/pages/community-pool/community-pool.module.ts @@ -6,14 +6,19 @@ import { TranslateModule } from '@ngx-translate/core'; import { NgxMaskModule } from 'ngx-mask'; import { CommonDirectiveModule } from 'src/app/core/directives/common-directive.module'; import { CommonPipeModule } from 'src/app/core/pipes/common-pipe.module'; +import { ProposalService } from 'src/app/core/services/proposal.service'; +import { APaginatorModule } from 'src/app/shared/components/a-paginator/a-paginator.module'; +import { NameTagModule } from 'src/app/shared/components/name-tag/name-tag.module'; import { PaginatorModule } from '../../../app/shared/components/paginator/paginator.module'; import { TableNoDataModule } from '../../../app/shared/components/table-no-data/table-no-data.module'; import { SharedModule } from '../../../app/shared/shared.module'; +import { CommunityPoolAssetComponent } from './asset-list/community-pool-asset.component'; import { CommunityPoolRoutingModule } from './community-pool-routing.module'; import { CommunityPoolComponent } from './community-pool.component'; +import { CommunityPoolProposalComponent } from './proposal-list/community-pool-proposal.component'; @NgModule({ - declarations: [CommunityPoolComponent], + declarations: [CommunityPoolAssetComponent, CommunityPoolProposalComponent, CommunityPoolComponent], imports: [ CommunityPoolRoutingModule, CommonModule, @@ -26,6 +31,9 @@ import { CommunityPoolComponent } from './community-pool.component'; CommonPipeModule, NgxMaskModule, CommonDirectiveModule, + APaginatorModule, + NameTagModule ], + providers: [ProposalService], }) export class CommunityPoolModule {} diff --git a/src/app/pages/community-pool/proposal-list/community-pool-proposal.component.html b/src/app/pages/community-pool/proposal-list/community-pool-proposal.component.html new file mode 100644 index 000000000..835a33631 --- /dev/null +++ b/src/app/pages/community-pool/proposal-list/community-pool-proposal.component.html @@ -0,0 +1,161 @@ + + +
+
+
+

Community Pool Spent Proposals

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#ID#{{ element.proposal_id }}Title + {{ + element.content.title + }} + Status +
+ {{ getStatus(element.status).value }} +
+
Sender + + Recipient + + Amount + + {{ denom }} + Voting End +
+ {{ element.voting_end_time | customDate : 'yyyy-MM-dd' }} +
+ {{ element.voting_end_time | customDate : 'HH:mm:ss' }} +
+
+ - +
+
+ {{ 'NO DATA' | translate }} +
+
+ +
+ + +
+ +
+ +
+ + +
+
+
+
+
+ + + diff --git a/src/app/pages/community-pool/proposal-list/community-pool-proposal.component.scss b/src/app/pages/community-pool/proposal-list/community-pool-proposal.component.scss new file mode 100644 index 000000000..56db06b2b --- /dev/null +++ b/src/app/pages/community-pool/proposal-list/community-pool-proposal.component.scss @@ -0,0 +1,19 @@ +.proposal-title { + max-width: 370px; +} + +.aura-table.proposal-table th.mat-header-cell:nth-child(3), +.aura-table.proposal-table th.mat-header-cell:nth-child(4), +.aura-table.proposal-table th.mat-header-cell:nth-child(5), +.aura-table.proposal-table th.mat-header-cell:nth-child(6), +.aura-table.proposal-table th.mat-header-cell:nth-child(7) { + width: 7%; +} + +.aura-table.proposal-table th.mat-header-cell:nth-child(1) { + width: 4%; +} + +.aura-table.proposal-table th.mat-header-cell:nth-child(2) { + width: 20%; +} \ No newline at end of file diff --git a/src/app/pages/community-pool/proposal-list/community-pool-proposal.component.ts b/src/app/pages/community-pool/proposal-list/community-pool-proposal.component.ts new file mode 100644 index 000000000..73b9bb077 --- /dev/null +++ b/src/app/pages/community-pool/proposal-list/community-pool-proposal.component.ts @@ -0,0 +1,108 @@ +import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout'; +import { Component, OnInit, ViewChild } from '@angular/core'; +import { MatPaginator, PageEvent } from '@angular/material/paginator'; +import { MatTableDataSource } from '@angular/material/table'; +import { TranslateService } from '@ngx-translate/core'; +import { tap } from 'rxjs/operators'; +import { PAGE_EVENT } from 'src/app/core/constants/common.constant'; +import { PROPOSAL_STATUS } from 'src/app/core/constants/proposal.constant'; +import { EnvironmentService } from 'src/app/core/data-services/environment.service'; +import { TableTemplate } from 'src/app/core/models/common.model'; +import { CommonService } from 'src/app/core/services/common.service'; +import { ProposalService } from 'src/app/core/services/proposal.service'; +import { shortenAddress } from 'src/app/core/utils/common/shorten'; +import { PaginatorComponent } from 'src/app/shared/components/paginator/paginator.component'; + +@Component({ + selector: 'app-community-pool-proposal', + templateUrl: './community-pool-proposal.component.html', + styleUrls: ['./community-pool-proposal.component.scss'], +}) +export class CommunityPoolProposalComponent implements OnInit { + @ViewChild(PaginatorComponent) pageChange: PaginatorComponent; + @ViewChild(MatPaginator) paginator: MatPaginator; + + templates: Array = [ + { matColumnDef: 'id', headerCellDef: 'ID' }, + { matColumnDef: 'title', headerCellDef: 'Title' }, + { matColumnDef: 'status', headerCellDef: 'Status' }, + { matColumnDef: 'sender', headerCellDef: 'Sender' }, + { matColumnDef: 'recipient', headerCellDef: 'recipient' }, + { matColumnDef: 'amount', headerCellDef: 'Amount' }, + { matColumnDef: 'voting_end_time', headerCellDef: 'Voting End' }, + ]; + displayedColumns: string[] = this.templates.map((dta) => dta.matColumnDef); + pageData: PageEvent = { + length: PAGE_EVENT.LENGTH, + pageSize: 10, + pageIndex: 1, + }; + breakpoint$ = this.layout.observe([Breakpoints.Small, Breakpoints.XSmall]).pipe( + tap((state) => { + this.pageData = { + length: PAGE_EVENT.LENGTH, + pageSize: state.matches ? 5 : 10, + pageIndex: 1, + }; + + this.getListProposal({ index: 1 }); + }), + ); + length: number; + dataSource: MatTableDataSource; + denom = this.environmentService.configValue.chain_info.currencies[0].coinDenom; + listCoin = this.environmentService.configValue.coins; + statusConstant = PROPOSAL_STATUS; + distributionAcc = ''; + + constructor( + public translate: TranslateService, + private environmentService: EnvironmentService, + private layout: BreakpointObserver, + private proposalService: ProposalService, + public commonService: CommonService, + ) {} + + ngOnInit(): void { + this.getAddressDistribution(); + } + + async getAddressDistribution() { + const res = await this.commonService.getAccountDistribution(); + this.distributionAcc = res.data.account.base_account.address; + } + + shortenAddress(address: string): string { + if (address) { + return shortenAddress(address, 8); + } + return ''; + } + + getStatus(key: string) { + let resObj: { value: string; class: string; key: string } = null; + const statusObj = this.statusConstant.find((s) => s.key === key); + if (statusObj !== undefined) { + resObj = { + value: statusObj.value, + class: statusObj.class, + key: statusObj.key, + }; + } + return resObj; + } + + getListProposal({ index }) { + let payload = { + limit: this.pageData.pageSize, + offset: (index - 1) * this.pageData.pageSize, + type: '/cosmos.distribution.v1beta1.CommunityPoolSpendProposal', + }; + this.proposalService.getProposalData(payload).subscribe((res) => { + if (res?.proposal) { + this.dataSource = new MatTableDataSource(res.proposal); + } + this.length = res.proposal_aggregate.aggregate.count; + }); + } +} diff --git a/src/app/pages/contracts/contracts-detail/contract-info-card/contract-info-card.component.html b/src/app/pages/contracts/contracts-detail/contract-info-card/contract-info-card.component.html index c4419e958..67fb0ebef 100644 --- a/src/app/pages/contracts/contracts-detail/contract-info-card/contract-info-card.component.html +++ b/src/app/pages/contracts/contracts-detail/contract-info-card/contract-info-card.component.html @@ -1,96 +1,105 @@ -
+
- + - - - - - - + - - + + + + + - + diff --git a/src/app/pages/contracts/contracts-detail/contract-info-card/contract-info-card.component.ts b/src/app/pages/contracts/contracts-detail/contract-info-card/contract-info-card.component.ts index e34fed25d..5ee04f4ae 100644 --- a/src/app/pages/contracts/contracts-detail/contract-info-card/contract-info-card.component.ts +++ b/src/app/pages/contracts/contracts-detail/contract-info-card/contract-info-card.component.ts @@ -1,20 +1,29 @@ -import { Component, Input, OnInit } from '@angular/core'; +import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'; +import { LENGTH_CHARACTER } from 'src/app/core/constants/common.constant'; +import { TYPE_CW4973 } from 'src/app/core/constants/contract.constant'; import { ContractRegisterType } from 'src/app/core/constants/contract.enum'; +import { CommonService } from 'src/app/core/services/common.service'; @Component({ selector: 'app-contract-info-card', templateUrl: './contract-info-card.component.html', styleUrls: ['./contract-info-card.component.scss'], }) -export class ContractInfoCardComponent implements OnInit { +export class ContractInfoCardComponent implements OnInit, OnChanges { @Input() contractDetail: any; contractRegisterType = ContractRegisterType; - linkNft = 'token-nft' - constructor() {} + linkNft = 'token-nft'; + lengthNormalAddress = LENGTH_CHARACTER.ADDRESS; - ngOnInit(): void { - if(this.contractDetail?.type === ContractRegisterType.CW4973){ - this.linkNft = 'token-abt'; - } + constructor(public commonService: CommonService) {} + + ngOnInit(): void {} + + ngOnChanges(changes: SimpleChanges): void { + setTimeout(() => { + if (changes?.contractDetail?.currentValue?.name === TYPE_CW4973) { + this.linkNft = 'token-abt'; + } + }, 500); } } diff --git a/src/app/pages/contracts/contracts-detail/contracts-contents/contract-content.component.html b/src/app/pages/contracts/contracts-detail/contracts-contents/contract-content.component.html index 8d955923f..53d7bfafb 100644 --- a/src/app/pages/contracts/contracts-detail/contracts-contents/contract-content.component.html +++ b/src/app/pages/contracts/contracts-detail/contracts-contents/contract-content.component.html @@ -27,16 +27,16 @@
+
diff --git a/src/app/pages/contracts/contracts-detail/contracts-contents/contract-content.component.ts b/src/app/pages/contracts/contracts-detail/contracts-contents/contract-content.component.ts index 790ba2bf4..549015fc6 100644 --- a/src/app/pages/contracts/contracts-detail/contracts-contents/contract-content.component.ts +++ b/src/app/pages/contracts/contracts-detail/contracts-contents/contract-content.component.ts @@ -5,6 +5,7 @@ import { takeUntil } from 'rxjs/operators'; import { EnvironmentService } from 'src/app/core/data-services/environment.service'; import { TableTemplate } from 'src/app/core/models/common.model'; import { ContractService } from 'src/app/core/services/contract.service'; +import { TransactionService } from 'src/app/core/services/transaction.service'; import { isContract } from 'src/app/core/utils/common/validation'; import { convertDataTransaction } from 'src/app/global/global'; import { CONTRACT_TAB, CONTRACT_TABLE_TEMPLATES } from '../../../../core/constants/contract.constant'; @@ -19,24 +20,17 @@ export class ContractContentComponent implements OnInit, OnDestroy { @Input() contractsAddress = ''; @Input() contractTypeData: ContractVerifyType; - TABS = CONTRACT_TAB.filter((tab) => - [ - ContractTab.Transactions, - // ContractTab.Cw20Token, - ContractTab.Contract, - // ContractTab.Events, - // ContractTab.Analytics, - ].includes(tab.key), - ).map((tab) => ({ - ...tab, - value: tab.value, - key: tab.key === ContractTab.Transactions ? '' : tab.key, - })); + TABS = CONTRACT_TAB.filter((tab) => [ContractTab.Transactions, ContractTab.Contract].includes(tab.key)).map( + (tab) => ({ + ...tab, + value: tab.value, + key: tab.key === ContractTab.Transactions ? '' : tab.key, + }), + ); countCurrent: string = ContractTab.Transactions; contractTab = ContractTab; contractVerifyType = ContractVerifyType; - nextKey = null; activeId = 0; limit = 25; contractTransaction = {}; @@ -49,6 +43,7 @@ export class ContractContentComponent implements OnInit, OnDestroy { popover: true, }; dataInstantiate = []; + loadingContract = true; destroyed$ = new Subject(); timerGetUpTime: any; @@ -57,6 +52,7 @@ export class ContractContentComponent implements OnInit, OnDestroy { constructor( private contractService: ContractService, + private transactionService: TransactionService, private router: Router, private aRoute: ActivatedRoute, private environmentService: EnvironmentService, @@ -120,52 +116,34 @@ export class ContractContentComponent implements OnInit, OnDestroy { getTransaction(isInit = true): void { if (isContract(this.contractsAddress)) { - this.contractService - .getTransactionsIndexer(this.limit, this.contractsAddress, 'execute') - .subscribe((dataExecute) => { - const { code, data } = dataExecute; - this.nextKey = dataExecute.data.nextKey; - if (code === 200) { + const payload = { + limit: this.limit, + value: this.contractsAddress, + key: '_contract_address', + }; + this.transactionService.getListTxCondition(payload).subscribe( + (res) => { + const data = res; + if (res) { const txsExecute = convertDataTransaction(data, this.coinInfo); - if (dataExecute?.data?.transactions?.length > 0) { + if (res?.transaction?.length > 0) { this.contractTransaction['data'] = txsExecute; this.contractTransaction['count'] = this.contractTransaction['data'].length || 0; } - if (!isInit) { + if (!isInit && this.dataInstantiate?.length > 0) { this.contractTransaction['data'] = [...this.contractTransaction['data'], this.dataInstantiate[0]]; this.contractTransaction['count'] = this.contractTransaction['count'] + this.dataInstantiate?.length; } - - //check data < 25 record - if (isInit) { - if (this.contractTransaction['data']?.length < this.limit || !this.contractTransaction['data']) { - this.contractService - .getTransactionsIndexer(this.limit, this.contractsAddress, 'instantiate') - .subscribe((dataInstantiate) => { - if (dataInstantiate.data?.transactions?.length > 0) { - const txsInstantiate = convertDataTransaction(dataInstantiate.data, this.coinInfo); - txsInstantiate[0]['type'] = - dataInstantiate.data.transactions[0].tx_response.tx.body.messages[0]['@type']; - txsInstantiate[0]['contract_address'] = this.contractsAddress; - let data = []; - this.dataInstantiate = txsInstantiate; - if (this.contractTransaction['data']?.length >= 1) { - data = [...this.contractTransaction['data'], txsInstantiate[0]]; - } else { - data = txsInstantiate; - } - let count = data.length || 0; - this.contractTransaction = { - data, - count, - }; - } - }); - } - } } - }); + }, + () => {}, + () => { + this.loadingContract = false; + }, + ); + } else { + this.loadingContract = false; } } diff --git a/src/app/pages/contracts/contracts-detail/contracts-contents/contract/contract-code/code-contract.component.html b/src/app/pages/contracts/contracts-detail/contracts-contents/contract/contract-code/code-contract.component.html index a9db6a67a..9f601d405 100644 --- a/src/app/pages/contracts/contracts-detail/contracts-contents/contract/contract-code/code-contract.component.html +++ b/src/app/pages/contracts/contracts-detail/contracts-contents/contract/contract-code/code-contract.component.html @@ -22,18 +22,6 @@
More Info - -
My Name Tag:Public Name Tag: - Not Available - + + + + Not Available
Private Name Tag:
Token Tracker: - +
-
@@ -45,22 +33,21 @@ -
+
+
-
+
File Contract Source Code @@ -69,10 +56,14 @@
- +
+ + +
- +
+ + +
- +
+ + +
+ + + + +
+
+ true +
+
+
+ +
+
+ false +
+
+
+
+
diff --git a/src/app/pages/contracts/contracts-detail/contracts-contents/contract/write-contact/write-contract.component.scss b/src/app/pages/contracts/contracts-detail/contracts-contents/contract/write-contact/write-contract.component.scss index c1198179c..5b484d4ce 100644 --- a/src/app/pages/contracts/contracts-detail/contracts-contents/contract/write-contact/write-contract.component.scss +++ b/src/app/pages/contracts/contracts-detail/contracts-contents/contract/write-contact/write-contract.component.scss @@ -75,4 +75,72 @@ input.form-check-input { textarea { resize: none; -} \ No newline at end of file +} + +::ng-deep { + .mat-form-field[contract] { + background-color: var(--aura-gray-9); + border: 1px solid var(--aura-gray-8); + border-radius: var(--spacer-1); + display: flex; + align-items: center; + @media (min-width: 991.98px) { + width: 100%; + } + + .mat-form-field-wrapper { + width: 100%; + padding-bottom: 0; + } + + .mat-form-field-flex { + padding: 0 0.75em 0 0.75em; + background: transparent; + } + + .mat-form-field-infix { + padding: 0 0 0.75em 0; + } + + .mat-select-value { + color: var(--aura-gray-1); + } + + .mat-form-field-underline { + display: none; + } + + .mat-select-arrow-wrapper { + transform: translateY(-5%); + + .mat-select-arrow { + border: solid #E6E7E8; + border-width: 0 2.3px 2.3px 0; + display: inline-block; + padding: 2.8px; + transform: rotate(45deg); + -webkit-transform: rotate(45deg); + } + } + } + + .contractPanel { + background: #25252c; + min-width: calc(100% + 40px) !important; + transform: translate3D(-5px, 35px, 0) !important; + padding: var(--spacer-3) 0 !important; + border-radius: 8px; + + @media (min-width: 992px) { + padding: var(--spacer-4) 0 !important; + } + } + .mat-option, + .mat-option.mat-active { + color: var(--aura-gray-1); + } + + textarea.mat-input-element{ + padding: 0px 12px !important; + } +} diff --git a/src/app/pages/contracts/contracts-detail/contracts-contents/contract/write-contact/write-contract.component.ts b/src/app/pages/contracts/contracts-detail/contracts-contents/contract/write-contact/write-contract.component.ts index ec9d19324..e62f75891 100644 --- a/src/app/pages/contracts/contracts-detail/contracts-contents/contract/write-contact/write-contract.component.ts +++ b/src/app/pages/contracts/contracts-detail/contracts-contents/contract/write-contact/write-contract.component.ts @@ -1,7 +1,6 @@ import { Component, Input, OnInit } from '@angular/core'; import { MatDialog, MatDialogConfig } from '@angular/material/dialog'; import { TranslateService } from '@ngx-translate/core'; -import BigNumber from 'bignumber.js'; import { Schema, Validator } from 'jsonschema'; import * as _ from 'lodash'; import { MESSAGES_CODE_CONTRACT } from 'src/app/core/constants/messages.constant'; @@ -188,7 +187,7 @@ export class WriteContractComponent implements OnInit { msgError = msgError ? msgError.charAt(0).toUpperCase() + msgError.slice(1) : 'Error'; try { this.walletService - .execute(this.userAddress, this.contractDetailData.contract_address, data) + .execute(this.userAddress, this.contractDetailData.address, data) .then((e) => { msg.isLoading = false; if ((e as any).result?.error) { diff --git a/src/app/pages/contracts/contracts-detail/contracts-contents/contract/write-contact/write-contract.module.ts b/src/app/pages/contracts/contracts-detail/contracts-contents/contract/write-contact/write-contract.module.ts index 7dca3da9c..4ec3b75e2 100644 --- a/src/app/pages/contracts/contracts-detail/contracts-contents/contract/write-contact/write-contract.module.ts +++ b/src/app/pages/contracts/contracts-detail/contracts-contents/contract/write-contact/write-contract.module.ts @@ -8,6 +8,7 @@ import { TableNoDataModule } from 'src/app/shared/components/table-no-data/table import { SharedModule } from 'src/app/shared/shared.module'; import { WriteContractComponent } from './write-contract.component'; import { MatFormFieldModule } from '@angular/material/form-field'; +import { MaterialModule } from '../../../../../../app.module'; @NgModule({ declarations: [WriteContractComponent], @@ -15,6 +16,7 @@ import { MatFormFieldModule } from '@angular/material/form-field'; CommonModule, CommonPipeModule, TableNoDataModule, + MaterialModule, MatExpansionModule, RouterModule, FormsModule, diff --git a/src/app/pages/contracts/contracts-detail/contracts-detail.component.html b/src/app/pages/contracts/contracts-detail/contracts-detail.component.html index b666a9a85..5e69421ab 100644 --- a/src/app/pages/contracts/contracts-detail/contracts-detail.component.html +++ b/src/app/pages/contracts/contracts-detail/contracts-detail.component.html @@ -5,18 +5,17 @@

Contract

{{ contractAddress }}
- - + +
+
diff --git a/src/app/pages/contracts/contracts-detail/contracts-overview-card/contracts-overview-card.component.ts b/src/app/pages/contracts/contracts-detail/contracts-overview-card/contracts-overview-card.component.ts index 9d078872c..3fd9c9dcf 100644 --- a/src/app/pages/contracts/contracts-detail/contracts-overview-card/contracts-overview-card.component.ts +++ b/src/app/pages/contracts/contracts-detail/contracts-overview-card/contracts-overview-card.component.ts @@ -1,20 +1,39 @@ -import { Component, Input, OnInit } from '@angular/core'; +import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'; import { TYPE_ACCOUNT } from 'src/app/core/constants/account.constant'; import { EnvironmentService } from 'src/app/core/data-services/environment.service'; import { Globals } from '../../../../global/global'; +import { ContractService } from 'src/app/core/services/contract.service'; +import { LENGTH_CHARACTER } from 'src/app/core/constants/common.constant'; @Component({ selector: 'app-contracts-overview-card', templateUrl: './contracts-overview-card.component.html', styleUrls: ['./contracts-overview-card.component.scss'], }) -export class ContractsOverviewCardComponent implements OnInit { +export class ContractsOverviewCardComponent implements OnInit, OnChanges { @Input() contractDetail: any; + contractBalance; + contractPrice; + priceToken = 0; selectedToken = '$0.00'; assetsType = TYPE_ACCOUNT; + lengthNormalAddress = LENGTH_CHARACTER.ADDRESS; + denom = this.environmentService.configValue.chain_info.currencies[0].coinDenom; - constructor(public global: Globals, private environmentService: EnvironmentService) {} + constructor( + public global: Globals, + private environmentService: EnvironmentService, + private contractService: ContractService, + ) {} + + ngOnInit() {} - ngOnInit(): void {} + async ngOnChanges(changes: SimpleChanges) { + const balanceReq = await this.contractService.getContractBalance(this.contractDetail.address); + if (balanceReq?.data) { + this.contractBalance = balanceReq.data.balances[0] ? balanceReq.data.balances[0] : 0; + this.contractPrice = this.contractBalance * this.priceToken || 0; + } + } } diff --git a/src/app/pages/contracts/contracts-list/contracts-list.component.html b/src/app/pages/contracts/contracts-list/contracts-list.component.html index 70329130b..1616f0281 100644 --- a/src/app/pages/contracts/contracts-list/contracts-list.component.html +++ b/src/app/pages/contracts/contracts-list/contracts-list.component.html @@ -9,20 +9,20 @@

Contracts

- diff --git a/src/app/pages/contracts/contracts-list/contracts-list.component.scss b/src/app/pages/contracts/contracts-list/contracts-list.component.scss index 11aad175f..87d405f6b 100644 --- a/src/app/pages/contracts/contracts-list/contracts-list.component.scss +++ b/src/app/pages/contracts/contracts-list/contracts-list.component.scss @@ -2,7 +2,7 @@ width: 100%; @media (min-width: 992px) { - width: 500px; + width: 680px; } .box-search-data { diff --git a/src/app/pages/contracts/contracts-list/contracts-list.component.ts b/src/app/pages/contracts/contracts-list/contracts-list.component.ts index 7648e3888..cd9ebecfc 100644 --- a/src/app/pages/contracts/contracts-list/contracts-list.component.ts +++ b/src/app/pages/contracts/contracts-list/contracts-list.component.ts @@ -1,20 +1,18 @@ -import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout'; import { DatePipe } from '@angular/common'; -import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; +import { Component, OnDestroy, OnInit } from '@angular/core'; import { PageEvent } from '@angular/material/paginator'; import { MatTableDataSource } from '@angular/material/table'; import { TranslateService } from '@ngx-translate/core'; import { Subject } from 'rxjs'; -import { debounceTime, distinctUntilChanged, takeUntil } from 'rxjs/operators'; -import { CONTRACT_RESULT } from 'src/app/core/constants/contract.constant'; +import { debounceTime, takeUntil } from 'rxjs/operators'; import { ContractRegisterType, ContractVerifyType } from 'src/app/core/constants/contract.enum'; -import { PaginatorComponent } from 'src/app/shared/components/paginator/paginator.component'; import { DATEFORMAT, PAGE_EVENT } from '../../../core/constants/common.constant'; import { MAX_LENGTH_SEARCH_TOKEN } from '../../../core/constants/token.constant'; import { TableTemplate } from '../../../core/models/common.model'; import { ContractService } from '../../../core/services/contract.service'; import { shortenAddress } from '../../../core/utils/common/shorten'; -import { Globals } from '../../../global/global'; +import { TYPE_CW4973 } from 'src/app/core/constants/contract.constant'; +import { CommonService } from 'src/app/core/services/common.service'; @Component({ selector: 'app-contracts-list', @@ -22,41 +20,41 @@ import { Globals } from '../../../global/global'; styleUrls: ['./contracts-list.component.scss'], }) export class ContractsListComponent implements OnInit, OnDestroy { - @ViewChild(PaginatorComponent) pageChange: PaginatorComponent; - textSearch = ''; templates: Array = [ - { matColumnDef: 'contract_address', headerCellDef: 'Address', isUrl: '/contracts', isShort: true }, - { matColumnDef: 'contract_name', headerCellDef: 'Contract Name' }, + { matColumnDef: 'address', headerCellDef: 'Address', isUrl: '/contracts', isShort: true, isNameTag: true }, + { matColumnDef: 'name', headerCellDef: 'Contract Name' }, { matColumnDef: 'code_id', headerCellDef: 'Code ID' }, - //{ matColumnDef: 'project_name', headerCellDef: 'Project' }, { matColumnDef: 'type', headerCellDef: 'Type Contract' }, { matColumnDef: 'compiler_version', headerCellDef: 'Version' }, { matColumnDef: 'contract_verification', headerCellDef: 'Verified' }, - { matColumnDef: 'creator_address', headerCellDef: 'Creator', isUrl: '/account', isShort: true }, + { matColumnDef: 'creator', headerCellDef: 'Creator', isUrl: '/account', isShort: true, isNameTag: true }, ]; displayedColumns: string[] = this.templates.map((dta) => dta.matColumnDef); - pageData: PageEvent; - pageSize = 20; - pageIndex = 0; - dataSource: MatTableDataSource = new MatTableDataSource([]); - maxLengthSearch = MAX_LENGTH_SEARCH_TOKEN; - contractVerifyType = ContractVerifyType; - breakpoint$ = this.layout.observe([Breakpoints.Small, Breakpoints.XSmall]); + pageData: PageEvent = { + length: PAGE_EVENT.LENGTH, + pageSize: 20, + pageIndex: 1, + }; filterButtons = []; + listContract = []; + textSearch = ''; + + dataSource = new MatTableDataSource(); searchSubject = new Subject(); destroy$ = new Subject(); - contractRegisterType = ContractRegisterType; + + ContractRegisterType = ContractRegisterType; + ContractVerifyType = ContractVerifyType; + MAX_LENGTH_SEARCH_TOKEN = MAX_LENGTH_SEARCH_TOKEN; constructor( public translate: TranslateService, - public global: Globals, private contractService: ContractService, private datePipe: DatePipe, - private layout: BreakpointObserver, + public commonService: CommonService ) {} ngOnDestroy(): void { - // throw new Error('Method not implemented.'); this.destroy$.next(); this.destroy$.complete(); } @@ -66,9 +64,9 @@ export class ContractsListComponent implements OnInit, OnDestroy { this.searchSubject .asObservable() - .pipe(debounceTime(500), distinctUntilChanged(), takeUntil(this.destroy$)) + .pipe(debounceTime(500), takeUntil(this.destroy$)) .subscribe(() => { - this.pageChange.selectPage(0); + this.pageEvent(0); }); } @@ -77,39 +75,43 @@ export class ContractsListComponent implements OnInit, OnDestroy { } getListContract() { + this.textSearch = this.textSearch?.trim(); let payload = { - limit: this.pageSize, - offset: this.pageIndex * this.pageSize, + limit: this.pageData.pageSize, + offset: (this.pageData.pageIndex - 1) * this.pageData.pageSize, keyword: this.textSearch, - contractType: this.filterButtons, + contractType: this.filterButtons?.length > 0 && this.filterButtons?.length < 4 ? this.filterButtons : null, }; this.contractService.getListContract(payload).subscribe((res) => { - this.pageData = { - length: res?.meta?.count, - pageSize: 20, - pageIndex: PAGE_EVENT.PAGE_INDEX, - }; - if (res?.data?.length > 0) { - res.data.forEach((item) => { - item.updated_at = this.datePipe.transform(item.updated_at, DATEFORMAT.DATETIME_UTC); - if (item.result === CONTRACT_RESULT.INCORRECT || !item.type) { - item.type = '-'; - } else if (item.result === CONTRACT_RESULT.TBD) { - item.type = CONTRACT_RESULT.TBD; + if (res?.smart_contract?.length) { + res?.smart_contract.forEach((item) => { + item.verified_at = this.datePipe.transform( + item.code?.code_id_verifications[0]?.verified_at, + DATEFORMAT.DATETIME_UTC, + ); + item.type = item.code.type; + if (item.type === ContractRegisterType.CW721 && item?.name === TYPE_CW4973) { + item.type = ContractRegisterType.CW4973; } + item.compiler_version = item.code?.code_id_verifications[0]?.compiler_version; + item.contract_verification = item.code.code_id_verifications[0]?.verification_status; }); - this.dataSource = res.data; + this.dataSource.data = res.smart_contract; + this.pageData.length = res.smart_contract_aggregate?.aggregate?.count; + } else { + this.dataSource.data = []; + this.listContract = []; + this.pageData.length = 0; } }); } - paginatorEmit(event): void { - this.dataSource.paginator = event; - } - - pageEvent(e: PageEvent): void { - this.pageIndex = e.pageIndex; + pageEvent(pageIndex: number): void { + // reset page 1 if pageIndex = 0 + if (pageIndex === 0) { + this.pageData.pageIndex = 1; + } this.getListContract(); } @@ -122,18 +124,18 @@ export class ContractsListComponent implements OnInit, OnDestroy { resetFilterSearch() { this.textSearch = ''; - this.onKeyUp(); + this.filterButtons = []; + this.pageEvent(0); } filterButton(val: string) { + console.log(val); + const i = this.filterButtons.findIndex((i) => i === val); + switch (val) { case 'All': - if (i >= 0) { - this.filterButtons = this.filterButtons.filter((item) => item !== val); - } else { - this.filterButtons = []; - } + this.filterButtons = []; break; case ContractRegisterType.CW20: case ContractRegisterType.CW721: @@ -146,6 +148,6 @@ export class ContractsListComponent implements OnInit, OnDestroy { this.filterButtons.push(val); } } - this.pageChange.selectPage(0); + this.pageEvent(0); } } diff --git a/src/app/pages/contracts/contracts-register/contracts-register.component.ts b/src/app/pages/contracts/contracts-register/contracts-register.component.ts index 234801090..ea4d404d8 100644 --- a/src/app/pages/contracts/contracts-register/contracts-register.component.ts +++ b/src/app/pages/contracts/contracts-register/contracts-register.component.ts @@ -109,7 +109,7 @@ export class ContractsRegisterComponent implements OnInit { } getListContract() { - this.loading = true; + this.textSearch = this.textSearch?.trim(); let payload = { account_address: this.userAddress, limit: this.pageData.pageSize, diff --git a/src/app/pages/contracts/contracts-routing.module.ts b/src/app/pages/contracts/contracts-routing.module.ts index 8342f1765..e11245aa6 100644 --- a/src/app/pages/contracts/contracts-routing.module.ts +++ b/src/app/pages/contracts/contracts-routing.module.ts @@ -2,7 +2,6 @@ import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { ContractsDetailComponent } from './contracts-detail/contracts-detail.component'; import { ContractsListComponent } from './contracts-list/contracts-list.component'; -import { ContractsRegisterComponent } from './contracts-register/contracts-register.component'; import { ContractsTransactionsComponent } from './contracts-transactions/contracts-transactions.component'; const routes: Routes = [ @@ -10,10 +9,10 @@ const routes: Routes = [ path: '', component: ContractsListComponent, }, - { - path: 'register', - component: ContractsRegisterComponent, - }, + // { + // path: 'register', + // component: ContractsRegisterComponent, + // }, { path: 'transactions/:addressId', component: ContractsTransactionsComponent, diff --git a/src/app/pages/contracts/contracts-transactions/contracts-transactions.component.html b/src/app/pages/contracts/contracts-transactions/contracts-transactions.component.html index 32a99f05f..cdd557c8f 100644 --- a/src/app/pages/contracts/contracts-transactions/contracts-transactions.component.html +++ b/src/app/pages/contracts/contracts-transactions/contracts-transactions.component.html @@ -1,11 +1,16 @@

Transactions

-
diff --git a/src/app/pages/contracts/contracts-transactions/contracts-transactions.component.scss b/src/app/pages/contracts/contracts-transactions/contracts-transactions.component.scss index 17acf974d..6f2b3cbb0 100644 --- a/src/app/pages/contracts/contracts-transactions/contracts-transactions.component.scss +++ b/src/app/pages/contracts/contracts-transactions/contracts-transactions.component.scss @@ -1,3 +1,3 @@ .text-gray { - color: var(--aura-light-gray); + color: var(--aura-light-gray); } \ No newline at end of file diff --git a/src/app/pages/contracts/contracts-transactions/contracts-transactions.component.ts b/src/app/pages/contracts/contracts-transactions/contracts-transactions.component.ts index 7ad85201d..a28418e54 100644 --- a/src/app/pages/contracts/contracts-transactions/contracts-transactions.component.ts +++ b/src/app/pages/contracts/contracts-transactions/contracts-transactions.component.ts @@ -4,11 +4,11 @@ import { ActivatedRoute, Router } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { Subject } from 'rxjs'; import { CONTRACT_TABLE_TEMPLATES } from 'src/app/core/constants/contract.constant'; -import { TRANSACTION_TYPE_ENUM } from 'src/app/core/constants/transaction.enum'; import { EnvironmentService } from 'src/app/core/data-services/environment.service'; import { TableTemplate } from 'src/app/core/models/common.model'; import { ITableContract } from 'src/app/core/models/contract.model'; -import { ContractService } from 'src/app/core/services/contract.service'; +import { CommonService } from 'src/app/core/services/common.service'; +import { TransactionService } from 'src/app/core/services/transaction.service'; import { convertDataTransaction } from 'src/app/global/global'; import { TableData } from 'src/app/shared/components/contract-table/contract-table.component'; @@ -42,10 +42,15 @@ export class ContractsTransactionsComponent implements OnInit { timerGetUpTime: any; isLoadingTX = true; lengthTxsExecute = 0; - isLoadInstantiate = false; txsInstantiate = []; currentPage = 0; destroyed$ = new Subject(); + modeTxType = { Out: 0, In: 1, Instantiate: 2 }; + hashIns = ''; + hasLoadIns = false; + payload = { + limit: 100, + }; breakpoint$ = this.layout.observe([Breakpoints.Small, Breakpoints.XSmall]); coinInfo = this.environmentService.configValue.chain_info.currencies[0]; @@ -53,10 +58,11 @@ export class ContractsTransactionsComponent implements OnInit { constructor( public translate: TranslateService, private router: Router, - private contractService: ContractService, private layout: BreakpointObserver, private environmentService: EnvironmentService, private route: ActivatedRoute, + private transactionService: TransactionService, + public commonService: CommonService, ) { const valueColumn = this.templates.find((item) => item.matColumnDef === 'value'); @@ -71,7 +77,10 @@ export class ContractsTransactionsComponent implements OnInit { ngOnInit(): void { this.contractAddress = this.route.snapshot.paramMap.get('addressId'); + this.contractInfo.contractsAddress = this.contractAddress; + this.payload['value'] = this.contractAddress; this.getData(); + this.getDataInstantiate(); this.timerGetUpTime = setInterval(() => { // reload when page = 0 if (this.currentPage === 0) { @@ -93,31 +102,41 @@ export class ContractsTransactionsComponent implements OnInit { getData(isReload = false) { this.route.queryParams.subscribe((params) => { if (params['label']) { - this.label = params['label'] || 0; + this.label = params['label'] || this.modeTxType.Out; } + this.payload['key'] = null; + this.payload['compositeKey'] = null; switch (+this.label) { case 1: - this.getDataTable(null, isReload); + this.payload['compositeKey'] = 'execute._contract_address'; break; case 2: - this.getDataInstantiate(); + this.payload['compositeKey'] = 'instantiate._contract_address'; break; default: - this.getDataTable(null, isReload); + this.payload['key'] = '_contract_address'; + break; } + this.getDataTable(null, isReload); }); } getDataTable(nextKey = null, isReload = false) { - if (!this.label || +this.label == 1) { - this.contractService.getTransactionsIndexer(100, this.contractAddress, 'execute', nextKey).subscribe( + if (+this.label == this.modeTxType.In && !this.hasLoadIns) { + return; + } + if (!this.label || +this.label == this.modeTxType.In) { + this.payload['heightLT'] = nextKey; + this.transactionService.getListTxCondition(this.payload).subscribe( (dataExecute) => { - const { code, data } = dataExecute; - if (code === 200) { - const txsExecute = convertDataTransaction(data, this.coinInfo); + if (dataExecute) { + const txsExecute = convertDataTransaction(dataExecute, this.coinInfo); this.lengthTxsExecute = txsExecute.length; - if (dataExecute.data.transactions?.length > 0) { - this.nextKey = dataExecute.data.nextKey; + if (dataExecute.transaction?.length > 0) { + this.nextKey = null; + if (txsExecute.length >= 100) { + this.nextKey = dataExecute?.transaction[txsExecute.length - 1].height; + } if (this.contractTransaction['data']?.length > 0 && !isReload) { this.contractTransaction['data'] = [...this.contractTransaction['data'], ...txsExecute]; } else if (txsExecute.length > 0) { @@ -126,15 +145,9 @@ export class ContractsTransactionsComponent implements OnInit { } this.contractTransaction['count'] = this.contractTransaction['data']?.length; - if (this.label != 1) { - if (isReload && txsExecute?.length > 0 && txsExecute?.length < 100) { - this.contractTransaction['data'] = [...this.contractTransaction['data'], this.txsInstantiate[0]]; - this.contractTransaction['count'] = this.contractTransaction['data']?.length; - } - } if (!isReload) { - if (this.nextKey === null) { + if (this.nextKey === null && +this.label == this.modeTxType.Instantiate) { this.getDataInstantiate(); } } @@ -151,35 +164,25 @@ export class ContractsTransactionsComponent implements OnInit { } getDataInstantiate(): void { - this.contractService.getTransactionsIndexer(1, this.contractAddress, 'instantiate').subscribe( + this.transactionService.getListTxCondition(this.payload).subscribe( (dataInstantiate) => { - if (dataInstantiate.data.transactions?.length > 0) { - this.txsInstantiate = convertDataTransaction(dataInstantiate.data, this.coinInfo); - if (this.txsInstantiate.length > 0) { - this.txsInstantiate[0]['type'] = - dataInstantiate.data?.transactions[0]?.tx_response?.tx?.body.messages[0]['@type']; - this.txsInstantiate[0]['contract_address'] = this.contractAddress; - if (+this.label == 2) { - this.contractTransaction['data'] = this.txsInstantiate; - this.contractTransaction['count'] = this.txsInstantiate.length || 0; - return; - } - if (!this.label) { - if (this.contractTransaction['data']?.length >= 1) { - this.contractTransaction['data'].push(this.txsInstantiate[0]); - } else { - this.contractTransaction['data'] = this.txsInstantiate; - } - this.contractTransaction['count'] = this.contractTransaction['data']?.length || 0; - return; - } + this.hasLoadIns = true; + if (dataInstantiate.transaction?.length > 0) { + this.hashIns = dataInstantiate.transaction[0]?.hash; + if (+this.label == this.modeTxType.Instantiate) { + this.txsInstantiate = convertDataTransaction(dataInstantiate, this.coinInfo); + this.contractTransaction['data'] = this.txsInstantiate; + this.contractTransaction['count'] = this.txsInstantiate.length || 0; + } + if (+this.label == this.modeTxType.In) { + this.getDataTable(); + } else { + this.isLoadingTX = false; } } }, () => {}, - () => { - this.isLoadingTX = false; - }, + () => {}, ); } @@ -187,7 +190,7 @@ export class ContractsTransactionsComponent implements OnInit { const { pageIndex, pageSize } = event; this.currentPage = pageIndex; const next = event.length <= (pageIndex + 2) * pageSize; - if (next && this.nextKey && this.currentKey !== this.nextKey ) { + if (next && this.nextKey && this.currentKey !== this.nextKey) { this.getDataTable(this.nextKey); this.currentKey = this.nextKey; } diff --git a/src/app/pages/contracts/contracts-verify/contract-verify-steps/contract-verify-steps.component.html b/src/app/pages/contracts/contracts-verify/contract-verify-steps/contract-verify-steps.component.html index 42239ba37..ae7623cf2 100644 --- a/src/app/pages/contracts/contracts-verify/contract-verify-steps/contract-verify-steps.component.html +++ b/src/app/pages/contracts/contracts-verify/contract-verify-steps/contract-verify-steps.component.html @@ -1,4 +1,11 @@
+
+
+ icon + ERROR: +
+ {{errorMessage}} +
diff --git a/src/app/pages/contracts/contracts-verify/contract-verify-steps/contract-verify-steps.component.ts b/src/app/pages/contracts/contracts-verify/contract-verify-steps/contract-verify-steps.component.ts index 9fb523410..d6d301dfc 100644 --- a/src/app/pages/contracts/contracts-verify/contract-verify-steps/contract-verify-steps.component.ts +++ b/src/app/pages/contracts/contracts-verify/contract-verify-steps/contract-verify-steps.component.ts @@ -13,6 +13,7 @@ export class ContractVerifyStepsComponent implements OnInit { @Output() isCompilerComplete = new EventEmitter(); @Output() isVerifyFail = new EventEmitter(); @Output() isVerifySuccess = new EventEmitter(); + errorMessage = null; currentStep = 0; steps = []; @@ -41,12 +42,12 @@ export class ContractVerifyStepsComponent implements OnInit { getDataVerify() { this.contractService.getVerifyCodeStep(this.currentCode).subscribe((res: IResponsesTemplates) => { + this.errorMessage = res?.error?.Message ?? null; this.steps = res?.data.map((dta) => ({ ...dta, className: this.getClassName(dta.result), })); - let stepTemp = this.steps.find((dta) => dta.result !== 'Success')?.check_id; if (stepTemp) { this.currentStep = stepTemp - 1 > 0 ? stepTemp - 1 : 0; diff --git a/src/app/pages/contracts/contracts.module.ts b/src/app/pages/contracts/contracts.module.ts index 0d0ebf522..7fb22947f 100644 --- a/src/app/pages/contracts/contracts.module.ts +++ b/src/app/pages/contracts/contracts.module.ts @@ -1,3 +1,4 @@ +import { ClipboardModule } from '@angular/cdk/clipboard'; import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; @@ -8,12 +9,15 @@ import { ClickOutsideModule } from 'ng-click-outside'; import { NgxMaskModule } from 'ngx-mask'; import { MaterialModule } from 'src/app/app.module'; import { CommonPipeModule } from 'src/app/core/pipes/common-pipe.module'; +import { APaginatorModule } from 'src/app/shared/components/a-paginator/a-paginator.module'; import { ContractTableModule } from 'src/app/shared/components/contract-table/contract-table.module'; import { DropdownModule } from 'src/app/shared/components/dropdown/dropdown.module'; +import { NameTagModule } from 'src/app/shared/components/name-tag/name-tag.module'; import { PaginatorModule } from 'src/app/shared/components/paginator/paginator.module'; import { PopupAddZeroModule } from 'src/app/shared/components/popup-add-zero/popup-add-zero.module'; import { QrModule } from 'src/app/shared/components/qr/qr.module'; import { TableNoDataModule } from 'src/app/shared/components/table-no-data/table-no-data.module'; +import { TooltipCustomizeModule } from 'src/app/shared/components/tooltip-customize/tooltip-customize.module'; import { SharedModule } from 'src/app/shared/shared.module'; import { ContractService } from '../../core/services/contract.service'; import { ContractInfoCardComponent } from './contracts-detail/contract-info-card/contract-info-card.component'; @@ -43,7 +47,7 @@ import { ContractsVerifyComponent } from './contracts-verify/contracts-verify.co CodeContractComponent, ContractsVerifyComponent, ContractVerifyStepsComponent, - ContractsRegisterComponent + ContractsRegisterComponent, ], imports: [ CommonModule, @@ -65,7 +69,11 @@ import { ContractsVerifyComponent } from './contracts-verify/contracts-verify.co ClickOutsideModule, WriteContractModule, ReadContractModule, - PopupAddZeroModule + PopupAddZeroModule, + APaginatorModule, + NameTagModule, + TooltipCustomizeModule, + ClipboardModule, ], providers: [ContractService], exports: [ContractVerifyStepsComponent], diff --git a/src/app/pages/dashboard/dashboard-chart-options.ts b/src/app/pages/dashboard/dashboard-chart-options.ts index 24d89f0f1..5fb1792e5 100644 --- a/src/app/pages/dashboard/dashboard-chart-options.ts +++ b/src/app/pages/dashboard/dashboard-chart-options.ts @@ -1,65 +1,6 @@ -import { ChartOptions, DeepPartial, ISeriesApi, SeriesPartialOptionsMap } from 'lightweight-charts'; -import { ApexAxisChartSeries, ApexChart, ApexXAxis, ApexStroke, ApexTooltip, ApexDataLabels } from 'ng-apexcharts'; +import { ChartOptions, DeepPartial, SeriesPartialOptionsMap } from 'lightweight-charts'; import { RangeType } from 'src/app/core/models/common.model'; -// export type ChartOptions = { -// series: ApexAxisChartSeries; -// chart: ApexChart; -// xAxis: ApexXAxis; -// stroke: ApexStroke; -// tooltip: ApexTooltip; -// dataLabels: ApexDataLabels; -// }; - -// export const DASHBOARD_CHART_OPTIONS: Partial = { -// series: [ -// { -// name: 'transactions', -// type: 'line', -// data: [], -// color: '#5EE6D0', -// }, -// ], -// chart: { -// height: 333, -// type: 'area', -// toolbar: { -// tools: { -// selection: false, -// download: ``, -// zoom: false, -// zoomin: ``, -// zoomout: ``, -// pan: false, -// reset: false, -// }, -// }, -// }, -// dataLabels: { -// enabled: false, -// }, -// stroke: { -// width: 3, -// curve: 'smooth', -// }, -// xAxis: { -// type: 'datetime', -// categories: [], -// labels: { -// datetimeUTC: false, -// }, -// axisBorder: { -// show: true, -// color: '#FFA741', -// }, -// }, -// tooltip: { -// x: { -// format: 'dd/MM/yy HH:mm', -// }, -// }, -// }; - export const DASHBOARD_CHART_OPTIONS: DeepPartial = { height: 300, crosshair: { diff --git a/src/app/pages/dashboard/dashboard-routing.module.ts b/src/app/pages/dashboard/dashboard-routing.module.ts index 969a5fbcf..7a937f826 100644 --- a/src/app/pages/dashboard/dashboard-routing.module.ts +++ b/src/app/pages/dashboard/dashboard-routing.module.ts @@ -1,6 +1,5 @@ import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; - import { DashboardComponent } from './dashboard.component'; const routes: Routes = [ diff --git a/src/app/pages/dashboard/dashboard.component.html b/src/app/pages/dashboard/dashboard.component.html index 6929b6e3a..e17681277 100644 --- a/src/app/pages/dashboard/dashboard.component.html +++ b/src/app/pages/dashboard/dashboard.component.html @@ -45,15 +45,17 @@
AURA
- - - +
+ + + + + +
@@ -166,8 +168,8 @@
Height
-
- {{ global?.dataHeader?.block_height || 0 | number }} +
+ {{ global?.dataHeader?.total_blocks || 0 | number }}
@@ -193,8 +195,8 @@
Transactions
-
- {{ global?.dataHeader?.total_txs_num | number }} +
+ {{ global?.dataHeader?.total_transactions | number }}
@@ -209,7 +211,7 @@
- {{ global?.dataHeader?.bonded_tokens || 0 }} / {{ global?.dataHeader?.supply || 0 }} + {{ global?.dataHeader?.bonded_tokens || 0 }} / {{ global?.dataHeader?.total_aura || 0 }}
@@ -389,7 +391,7 @@

Blocks

*ngSwitchCase="'proposer'" class="text--primary cursor-pointer text-break" [routerLink]="['/validators', data.operator_address]"> - {{ data[template.matColumnDef] }} + {{ data[template.matColumnDef] | stringEllipsis : 10 }} = DASHBOARD_CHART_OPTIONS; templatesBlock: Array = [ { matColumnDef: 'height', headerCellDef: 'Height' }, @@ -252,21 +251,25 @@ export class DashboardComponent implements OnInit, AfterViewInit, OnDestroy { } getListBlock(): void { - this.blockService.blocksIndexer(this.PAGE_SIZE).subscribe((res) => { - const { code, data } = res; - if (code === 200) { - const blocks = convertDataBlock(data); + const payload = { + limit: this.PAGE_SIZE, + } + this.blockService.getDataBlock(payload).subscribe((res) => { + if (res?.block?.length > 0) { + const blocks = convertDataBlock(res); this.dataSourceBlock = new MatTableDataSource(blocks); } }); } getListTransaction(): void { - this.transactionService.txsIndexer(this.PAGE_SIZE, 0).subscribe((res) => { + const payload = { + limit: this.PAGE_SIZE, + }; + this.transactionService.getListTx(payload).subscribe((res) => { this.dataSourceTx.data = []; - const { code, data } = res; - if (code === 200) { - const txs = convertDataTransaction(data, this.coinInfo); + if (res?.transaction?.length > 0) { + const txs = convertDataTransaction(res, this.coinInfo); if (this.dataSourceTx.data.length > 0) { this.dataSourceTx.data = [...this.dataSourceTx.data, ...txs]; @@ -328,7 +331,7 @@ export class DashboardComponent implements OnInit, AfterViewInit, OnDestroy { getInfoCommon(): void { this.commonService.status().subscribe((res) => { - getInfo(this.global, res.data); + getInfo(this.global, res); }); } @@ -410,9 +413,12 @@ export class DashboardComponent implements OnInit, AfterViewInit, OnDestroy { } getVotingPeriod() { - this.proposalService.getProposalList(20, null).subscribe((res) => { - if (res?.data?.proposals) { - let tempDta = res.data.proposals; + let payload = { + limit: 20, + }; + this.proposalService.getProposalData(payload).subscribe((res) => { + if (res?.proposal) { + let tempDta = res.proposal; this.voting_Period_arr = tempDta.filter((k) => k?.status === VOTING_STATUS.PROPOSAL_STATUS_VOTING_PERIOD); this.voting_Period_arr.forEach((pro, index) => { diff --git a/src/app/pages/dashboard/dashboard.module.ts b/src/app/pages/dashboard/dashboard.module.ts index 09f8274f6..0b9dfa82c 100644 --- a/src/app/pages/dashboard/dashboard.module.ts +++ b/src/app/pages/dashboard/dashboard.module.ts @@ -12,6 +12,7 @@ import { CommonService } from 'src/app/core/services/common.service'; import { ProposalService } from 'src/app/core/services/proposal.service'; import { TransactionService } from 'src/app/core/services/transaction.service'; import { TableNoDataModule } from 'src/app/shared/components/table-no-data/table-no-data.module'; +import { TooltipCustomizeModule } from 'src/app/shared/components/tooltip-customize/tooltip-customize.module'; import { SharedModule } from 'src/app/shared/shared.module'; import { DashboardRoutingModule } from './dashboard-routing.module'; import { DashboardComponent } from './dashboard.component'; @@ -33,6 +34,7 @@ import { DashboardComponent } from './dashboard.component'; TranslateModule, TableNoDataModule, NgbCarouselModule, + TooltipCustomizeModule, ], providers: [DatePipe, BlockService, TransactionService, DecimalPipe, ProposalService, CommonService, MaskPipe], }) diff --git a/src/app/pages/fee-grant/fee-grant.module.ts b/src/app/pages/fee-grant/fee-grant.module.ts index 5a711b92b..abd4ea036 100644 --- a/src/app/pages/fee-grant/fee-grant.module.ts +++ b/src/app/pages/fee-grant/fee-grant.module.ts @@ -12,7 +12,8 @@ import { AccountService } from 'src/app/core/services/account.service'; import { FeeGrantService } from 'src/app/core/services/feegrant.service'; import { MappingErrorService } from 'src/app/core/services/mapping-error.service'; import { TransactionService } from 'src/app/core/services/transaction.service'; -import { PaginatorModule } from 'src/app/shared/components/paginator/paginator.module'; +import { APaginatorModule } from 'src/app/shared/components/a-paginator/a-paginator.module'; +import { NameTagModule } from 'src/app/shared/components/name-tag/name-tag.module'; import { TableNoDataModule } from 'src/app/shared/components/table-no-data/table-no-data.module'; import { SharedModule } from 'src/app/shared/shared.module'; import { FeeGrantRoutingModule } from './fee-grant-routing.module'; @@ -30,7 +31,7 @@ import { PopupRevokeComponent } from './popup-revoke/popup-revoke.component'; MyGrantersComponent, PopupAddGrantComponent, PopupRevokeComponent, - PopupNoticeComponent + PopupNoticeComponent, ], imports: [ CommonModule, @@ -39,7 +40,6 @@ import { PopupRevokeComponent } from './popup-revoke/popup-revoke.component'; FormsModule, CommonPipeModule, MatTableModule, - PaginatorModule, TableNoDataModule, TranslateModule, SharedModule, @@ -47,6 +47,8 @@ import { PopupRevokeComponent } from './popup-revoke/popup-revoke.component'; MatDatepickerModule, ClickOutsideModule, NgxMaskModule, + APaginatorModule, + NameTagModule ], providers: [FormBuilder, FeeGrantService, TransactionService, MappingErrorService, AccountService], }) diff --git a/src/app/pages/fee-grant/my-grantees/my-grantees.component.html b/src/app/pages/fee-grant/my-grantees/my-grantees.component.html index 12b00f66f..efaf4a93b 100644 --- a/src/app/pages/fee-grant/my-grantees/my-grantees.component.html +++ b/src/app/pages/fee-grant/my-grantees/my-grantees.component.html @@ -17,15 +17,12 @@ - - - - - - \ No newline at end of file + +
+ +
Your vote
+
+
#{{ data.id }} {{ data.title }}
+
+ + {{ 'PAGES.PROPOSAL.yes' | translate }} + + {{ 'PAGES.PROPOSAL.no' | translate }} + + {{ + 'PAGES.PROPOSAL.noWithVeto' | translate + }} + {{ + 'PAGES.PROPOSAL.abstain' | translate + }} + +
+ + +
+
+
+ diff --git a/src/app/pages/proposal/proposal-vote/proposal-vote.component.ts b/src/app/pages/proposal/proposal-vote/proposal-vote.component.ts index 57bb78c48..30916fb9a 100644 --- a/src/app/pages/proposal/proposal-vote/proposal-vote.component.ts +++ b/src/app/pages/proposal/proposal-vote/proposal-vote.component.ts @@ -1,14 +1,11 @@ import { Component, Inject, OnInit } from '@angular/core'; -import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { TIME_OUT_CALL_API } from 'src/app/core/constants/common.constant'; -import { TYPE_CODE_SPACE } from 'src/app/core/constants/messages.constant'; -import { CodeTransaction } from 'src/app/core/constants/transaction.enum'; import { ESigningType, SIGNING_MESSAGE_TYPES } from 'src/app/core/constants/wallet.constant'; import { EnvironmentService } from 'src/app/core/data-services/environment.service'; import { IVotingDialog } from 'src/app/core/models/proposal.model'; import { MappingErrorService } from 'src/app/core/services/mapping-error.service'; import { NgxToastrService } from 'src/app/core/services/ngx-toastr.service'; -import { TransactionService } from 'src/app/core/services/transaction.service'; import { WalletService } from 'src/app/core/services/wallet.service'; @Component({ @@ -28,7 +25,6 @@ export class ProposalVoteComponent implements OnInit { private environmentService: EnvironmentService, private toastr: NgxToastrService, private walletService: WalletService, - private transactionService: TransactionService, private mappingErrorService: MappingErrorService, ) { this.keyVote = data.voteValue ?? null; diff --git a/src/app/pages/proposal/proposal.component.html b/src/app/pages/proposal/proposal.component.html index b0d0f076d..b62b625e9 100644 --- a/src/app/pages/proposal/proposal.component.html +++ b/src/app/pages/proposal/proposal.component.html @@ -23,13 +23,14 @@
Voting Start
@@ -66,31 +67,45 @@
    +
  • +
    + + +
  • -
  • + [style.width]="lastedItem.tally?.no + '%'"> +
    + + +
  • + [style.width]="lastedItem.tally?.no_with_veto + '%'"> +
    + + +
  • + [style.width]="lastedItem.tally?.abstain + '%'"> +
    + + +
@@ -189,12 +204,13 @@

@@ -235,31 +251,44 @@

    +
  • +
    + + +
  • -
  • + [style.width]="lastedItem.tally?.no + '%'"> +
    + + +
  • + [style.width]="lastedItem.tally?.no_with_veto + '%'"> +
    + + +
  • + [style.width]="lastedItem.tally.abstain + '%'"> +
    + + +
@@ -322,106 +351,94 @@

-
+

Proposals

- - - - - - + +
#ID#{{ element.proposal_id }}
+ + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - -
#ID#{{ element.proposal_id }}Title - {{ element.content.title }} - Title + {{ element.content.title }} + Status -
- {{ getStatus(element.status).value }} -
-
Status +
+ {{ getStatus(element.status).value }} +
+
Voting Start -
- {{ element.voting_start_time | customDate : 'yyyy-MM-dd' }} -
- {{ element.voting_start_time | customDate : 'HH:mm:ss' }} -
-
- - -
-
Voting Start +
+ {{ element.voting_start_time | customDate : 'yyyy-MM-dd' }} +
+ {{ element.voting_start_time | customDate : 'HH:mm:ss' }} +
+
+ - +
+
Submit Time -
- {{ element.submit_time | customDate : 'yyyy-MM-dd' }} -
- {{ element.submit_time | customDate : 'HH:mm:ss' }} -
-
Submit Time +
+ {{ element.submit_time | customDate : 'yyyy-MM-dd' }} +
+ {{ element.submit_time | customDate : 'HH:mm:ss' }} +
+
Total Deposit - {{ element.total_deposit[0].amount | mask : 'separator.6' }} - {{ denom }} - Total Deposit + {{ element.total_deposit[0].amount | mask : 'separator.6' }} + {{ denom }} +
- {{ 'NO DATA' | translate }} -
- - -
-
-
- -
-
- -
-
-

Proposals

-
-
+ + + + + {{ 'NO DATA' | translate }} + + + + + + Proposals

'' } ]"> -
- - -
- + +
+
+
+ +
diff --git a/src/app/pages/proposal/proposal.component.scss b/src/app/pages/proposal/proposal.component.scss index 8528543de..07733545c 100644 --- a/src/app/pages/proposal/proposal.component.scss +++ b/src/app/pages/proposal/proposal.component.scss @@ -31,7 +31,14 @@ ul { background-color: var(--aura-gray-8); border-radius: 4px; - overflow: hidden; + li:first-child { + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; + } + li:last-child { + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; + } } } diff --git a/src/app/pages/proposal/proposal.component.ts b/src/app/pages/proposal/proposal.component.ts index de805bc7d..46613909c 100644 --- a/src/app/pages/proposal/proposal.component.ts +++ b/src/app/pages/proposal/proposal.component.ts @@ -1,10 +1,11 @@ import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout'; import { ViewportScroller } from '@angular/common'; -import { Component, HostListener, OnInit } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; -import { MatPaginator, PageEvent } from '@angular/material/paginator'; +import { PageEvent } from '@angular/material/paginator'; import { MatTableDataSource } from '@angular/material/table'; import * as moment from 'moment'; +import { tap } from 'rxjs/operators'; import { PAGE_EVENT } from 'src/app/core/constants/common.constant'; import { CommonService } from 'src/app/core/services/common.service'; import { Globals } from '../../../app/global/global'; @@ -12,11 +13,9 @@ import { PROPOSAL_STATUS, PROPOSAL_VOTE, VOTE_OPTION } from '../../core/constant import { EnvironmentService } from '../../core/data-services/environment.service'; import { TableTemplate } from '../../core/models/common.model'; import { IProposal } from '../../core/models/proposal.model'; -import { DialogService } from '../../core/services/dialog.service'; import { ProposalService } from '../../core/services/proposal.service'; import { WalletService } from '../../core/services/wallet.service'; import { balanceOf } from '../../core/utils/common/parsing'; -import { shortenAddressStartEnd } from '../../core/utils/common/shorten'; import { ProposalVoteComponent } from './proposal-vote/proposal-vote.component'; @Component({ @@ -38,30 +37,31 @@ export class ProposalComponent implements OnInit { { matColumnDef: 'submitTime', headerCellDef: 'Submit Time' }, { matColumnDef: 'totalDeposit', headerCellDef: 'Total Deposit' }, ]; - breakpoint$ = this.layout.observe([Breakpoints.Small, Breakpoints.XSmall]); + + breakpoint$ = this.layout.observe([Breakpoints.Small, Breakpoints.XSmall]).pipe( + tap((state) => { + this.pageData = { + length: PAGE_EVENT.LENGTH, + pageSize: state.matches ? 5 : 10, + pageIndex: 1, + }; + + this.getListProposal({ index: 1 }); + }), + ); + displayedColumns: string[] = this.templates.map((dta) => dta.matColumnDef); dataSource: MatTableDataSource = new MatTableDataSource([]); - dataSourceMobile: any[]; proposalData: any; length: number; nextKey = null; - isLoadingAction = false; - pageYOffset = 0; scrolling = false; pageData: PageEvent = { length: PAGE_EVENT.LENGTH, - pageSize: 10, - pageIndex: PAGE_EVENT.PAGE_INDEX, + pageSize: this.layout.isMatched([Breakpoints.Small, Breakpoints.XSmall]) ? 5 : 10, + pageIndex: 1, }; - proposalVotes: { - proId: number; - vote: string | null; - }[] = []; - - @HostListener('window:scroll', ['$event']) onScroll(event) { - this.pageYOffset = window.pageYOffset; - } denom = this.environmentService.configValue.chain_info.currencies[0].coinDenom; constructor( private proposalService: ProposalService, @@ -69,92 +69,72 @@ export class ProposalComponent implements OnInit { public global: Globals, public walletService: WalletService, private environmentService: EnvironmentService, - private dlgService: DialogService, private layout: BreakpointObserver, private scroll: ViewportScroller, public commonService: CommonService, ) {} ngOnInit(): void { - this.getListProposal(); this.walletService.wallet$.subscribe((wallet) => this.getFourLastedProposal()); } getFourLastedProposal() { - this.proposalService.getProposalList(4, null).subscribe((res) => { - if (res?.data?.proposals) { - const addr = this.walletService.wallet?.bech32Address || null; - this.proposalData = res.data.proposals; - if (this.proposalData?.length > 0) { - this.proposalData.forEach((pro, index) => { - if (pro?.tally) { - const { yes, no, no_with_veto, abstain } = pro?.tally; - let totalVote = +yes + +no + +no_with_veto + +abstain; - - if (this.proposalData[index].tally) { - this.proposalData[index].tally.yes = (+yes * 100) / totalVote; - this.proposalData[index].tally.no = (+no * 100) / totalVote; - this.proposalData[index].tally.no_with_veto = (+no_with_veto * 100) / totalVote; - this.proposalData[index].tally.abstain = (+abstain * 100) / totalVote; - } - } else if (pro?.final_tally_result) { - const { yes, no, no_with_veto, abstain } = pro.final_tally_result; - let totalVote = +yes + +no + +no_with_veto + +abstain; - this.proposalData[index]['tally'] = { yes: 0, no: 0, no_with_veto: 0, abstain: 0 }; - this.proposalData[index].tally.yes = (+yes * 100) / totalVote; - this.proposalData[index].tally.no = (+no * 100) / totalVote; - this.proposalData[index].tally.no_with_veto = (+no_with_veto * 100) / totalVote; - this.proposalData[index].tally.abstain = (+abstain * 100) / totalVote; - } - - const getVoted = async () => { - if (addr) { - const payload = { - proposalId: pro.proposal_id, - wallet: addr, - }; - this.proposalService.getVotes(payload).subscribe((res) => { - const optionVote = this.proposalService.getVoteMessageByConstant(res?.data?.transactions[0]?.tx_response?.tx?.body?.messages[0]?.option); - pro.vote_option = this.voteConstant.find( - (s) => s.key === optionVote, - )?.voteOption; - }); + this.proposalService + .getProposalData({ + limit: 4, + }) + .subscribe((res) => { + if (res?.proposal) { + const addr = this.walletService.wallet?.bech32Address || null; + this.proposalData = res.proposal; + if (this.proposalData?.length > 0) { + this.proposalData.forEach((pro, index) => { + if (pro?.tally) { + const { yes, no, no_with_veto, abstain } = pro?.tally; + let totalVote = +yes + +no + +no_with_veto + +abstain; + if (this.proposalData[index].tally && totalVote > 0) { + this.proposalData[index].tally.yes = (+yes * 100) / totalVote; + this.proposalData[index].tally.no = (+no * 100) / totalVote; + this.proposalData[index].tally.no_with_veto = (+no_with_veto * 100) / totalVote; + this.proposalData[index].tally.abstain = (+abstain * 100) / totalVote; + } } - }; - getVoted(); - }); + const getVoted = async () => { + if (addr) { + const payload = { + proposal_id: pro.proposal_id?.toString(), + address: addr, + }; + this.proposalService.getVotedResult(payload).subscribe((res) => { + const optionVote = this.proposalService.getVoteMessageByConstant(res?.vote[0]?.vote_option); + pro.vote_option = this.voteConstant.find((s) => s.key === optionVote)?.voteOption; + }); + } + }; + getVoted(); + }); + } } - } - }); + }); } - getListProposal(nextKey = null) { - this.proposalService.getProposalList(40, nextKey).subscribe((res) => { - this.nextKey = res.data.nextKey ? res.data.nextKey : null; - if (res?.data?.proposals) { - let tempDta = res.data.proposals; - tempDta.forEach((pro, index) => { - pro.total_deposit[0].amount = balanceOf(pro.total_deposit[0].amount); - const { yes, no, no_with_veto, abstain } = pro.final_tally_result; - let totalVote = +yes + +no + +no_with_veto + +abstain; - tempDta[index]['tally'] = { yes: 0, no: 0, no_with_veto: 0, abstain: 0 }; - tempDta[index].tally.yes = (+yes * 100) / totalVote; - tempDta[index].tally.no = (+no * 100) / totalVote; - tempDta[index].tally.no_with_veto = (+no_with_veto * 100) / totalVote; - tempDta[index].tally.abstain = (+abstain * 100) / totalVote; - }); - if (this.dataSource.data.length > 0) { - this.dataSource.data = [...this.dataSource.data, ...tempDta]; - } else { - this.dataSource.data = [...tempDta]; + getListProposal({ index }) { + this.proposalService + .getProposalData({ + limit: this.pageData.pageSize, + offset: (index - 1) * this.pageData.pageSize, + }) + .subscribe((res) => { + if (res?.proposal) { + let tempDta = res.proposal; + tempDta.forEach((pro) => { + pro.total_deposit[0].amount = balanceOf(pro.total_deposit[0].amount); + }); + + this.dataSource.data = tempDta; } - } - this.dataSourceMobile = this.dataSource.data.slice( - this.pageData.pageIndex * this.pageData.pageSize, - this.pageData.pageIndex * this.pageData.pageSize + this.pageData.pageSize, - ); - this.length = this.dataSource.data.length; - }); + this.length = res.proposal_aggregate.aggregate.count; + }); } getStatus(key: string) { @@ -177,16 +157,16 @@ export class ProposalComponent implements OnInit { if (!highest || highest > 100) { highest = 0; - key = VOTE_OPTION.VOTE_OPTION_YES; + key = VOTE_OPTION.YES; } else { if (highest === yes) { - key = VOTE_OPTION.VOTE_OPTION_YES; + key = VOTE_OPTION.YES; } else if (highest === no) { - key = VOTE_OPTION.VOTE_OPTION_NO; + key = VOTE_OPTION.NO; } else if (highest === noWithVeto) { - key = VOTE_OPTION.VOTE_OPTION_NO_WITH_VETO; + key = VOTE_OPTION.NO_WITH_VETO; } else { - key = VOTE_OPTION.VOTE_OPTION_ABSTAIN; + key = VOTE_OPTION.ABSTAIN; } } @@ -242,46 +222,4 @@ export class ProposalComponent implements OnInit { this.scrolling = !this.scrolling; }, 500); } - - parsingStatus(sts) { - return ( - this.voteConstant.find((s) => { - return s.value?.toUpperCase() === sts?.toUpperCase(); - })?.voteOption || sts - ); - } - - shortenAddress(address: string): string { - return shortenAddressStartEnd(address, 6, 10); - } - - dlgServOpen(): void { - this.dlgService.showDialog({ - content: 'Please set up override Keplr in settings of Coin98 wallet', - title: '', - }); - } - - paginatorEmit(e: MatPaginator): void { - if (this.dataSource.paginator) { - e.page.next({ - length: this.dataSource.paginator.length, - pageIndex: 0, - pageSize: this.dataSource.paginator.pageSize, - previousPageIndex: this.dataSource.paginator.pageIndex, - }); - this.dataSource.paginator = e; - } else this.dataSource.paginator = e; - } - - pageEvent(e: PageEvent): void { - const { length, pageIndex, pageSize } = e; - const next = length <= (pageIndex + 2) * pageSize; - this.dataSourceMobile = this.dataSource.data.slice(pageIndex * pageSize, pageIndex * pageSize + pageSize); - - if (next && this.nextKey) { - this.getListProposal(this.nextKey); - } - this.pageData.pageIndex = e.pageIndex; - } } diff --git a/src/app/pages/proposal/proposal.module.ts b/src/app/pages/proposal/proposal.module.ts index 1d4cadecc..b2df5fd21 100644 --- a/src/app/pages/proposal/proposal.module.ts +++ b/src/app/pages/proposal/proposal.module.ts @@ -24,6 +24,9 @@ import { ProposalRoutingModule } from './proposal-routing.module'; import { ProposalTableComponent } from './proposal-table/proposal-table.component'; import { ProposalVoteComponent } from './proposal-vote/proposal-vote.component'; import { ProposalComponent } from './proposal.component'; +import { APaginatorModule } from 'src/app/shared/components/a-paginator/a-paginator.module'; +import { NameTagModule } from 'src/app/shared/components/name-tag/name-tag.module'; +import { TooltipCustomizeModule } from 'src/app/shared/components/tooltip-customize/tooltip-customize.module'; @NgModule({ declarations: [ @@ -52,6 +55,9 @@ import { ProposalComponent } from './proposal.component'; TableNoDataModule, PaginatorModule, LoadingImageModule, + APaginatorModule, + NameTagModule, + TooltipCustomizeModule, ], providers: [ProposalService, MappingErrorService, DecimalPipe, ValidatorService], }) diff --git a/src/app/pages/soulbound-token/abt-reject-popup/abt-reject-popup.component.html b/src/app/pages/soulbound-token/abt-reject-popup/abt-reject-popup.component.html index 367e8de37..ec9e8877e 100644 --- a/src/app/pages/soulbound-token/abt-reject-popup/abt-reject-popup.component.html +++ b/src/app/pages/soulbound-token/abt-reject-popup/abt-reject-popup.component.html @@ -1,7 +1,7 @@
- {{ !abtDetail.rejectAll ? 'Reject new ABTs from creator' : 'Reject all new ABTs from this creator'}} + {{ !abtDetail.rejectAll ? 'Reject new ABTs from creator' : 'Reject all new ABTs from this creator' }}
{{ userAddress }} {{ userAddress | cutStringPipe : 8 : 8 }}
-
- +
+ +
+
+ +
diff --git a/src/app/pages/soulbound-token/soulbound-account-token-list/soulbound-account-token-list.component.ts b/src/app/pages/soulbound-token/soulbound-account-token-list/soulbound-account-token-list.component.ts index 7c81a9a6d..578f9bca6 100644 --- a/src/app/pages/soulbound-token/soulbound-account-token-list/soulbound-account-token-list.component.ts +++ b/src/app/pages/soulbound-token/soulbound-account-token-list/soulbound-account-token-list.component.ts @@ -1,7 +1,8 @@ -import { ChangeDetectorRef, Component, OnInit, SimpleChanges } from '@angular/core'; +import { ChangeDetectorRef, Component, OnInit } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; -import {LIMIT_NUM_SBT, SB_TYPE} from 'src/app/core/constants/soulbound.constant'; +import { LIMIT_NUM_SBT, SB_TYPE } from 'src/app/core/constants/soulbound.constant'; +import { CommonService } from 'src/app/core/services/common.service'; import { SoulboundService } from 'src/app/core/services/soulbound.service'; import { WalletService } from 'src/app/core/services/wallet.service'; @@ -43,6 +44,7 @@ export class SoulboundAccountTokenListComponent implements OnInit { private walletService: WalletService, private cdr: ChangeDetectorRef, private soulboundService: SoulboundService, + public commonService: CommonService ) {} ngOnInit(): void { @@ -83,20 +85,6 @@ export class SoulboundAccountTokenListComponent implements OnInit { this.modalReference.close(); } - copyMessage(text: string) { - const dummy = document.createElement('textarea'); - document.body.appendChild(dummy); - dummy.value = text; - dummy.select(); - document.execCommand('copy'); - document.body.removeChild(dummy); - // fake event click out side copy button - // this event for hidden tooltip - setTimeout(function () { - document.getElementById('tokenAddress').click(); - }, 800); - } - changeTab(key) { this.activeId = key; this.reloadAPI = false; diff --git a/src/app/pages/soulbound-token/soulbound-account-token-list/soulbound-token-equipped/soulbound-token-equipped.component.html b/src/app/pages/soulbound-token/soulbound-account-token-list/soulbound-token-equipped/soulbound-token-equipped.component.html index 30a6a3fc0..34f44a94b 100644 --- a/src/app/pages/soulbound-token/soulbound-account-token-list/soulbound-token-equipped/soulbound-token-equipped.component.html +++ b/src/app/pages/soulbound-token/soulbound-account-token-list/soulbound-token-equipped/soulbound-token-equipped.component.html @@ -92,7 +92,9 @@

Equipped ABT

(pageEvent)="pageEvent($event)"> - +
diff --git a/src/app/pages/soulbound-token/soulbound-account-token-list/soulbound-token-equipped/soulbound-token-equipped.component.scss b/src/app/pages/soulbound-token/soulbound-account-token-list/soulbound-token-equipped/soulbound-token-equipped.component.scss index 797b1cc49..562c3871e 100644 --- a/src/app/pages/soulbound-token/soulbound-account-token-list/soulbound-token-equipped/soulbound-token-equipped.component.scss +++ b/src/app/pages/soulbound-token/soulbound-account-token-list/soulbound-token-equipped/soulbound-token-equipped.component.scss @@ -2,17 +2,6 @@ position: relative; .nft-cards__item { padding: 0; - app-model-view, - app-audio-player, - app-custom-video-player { - height: 100%; - position: absolute; - top: 50%; - left: 0; - right: 0; - bottom: 0; - transform: translateY(-50%); - } .token-cards__img { min-height: unset; height: auto; diff --git a/src/app/pages/soulbound-token/soulbound-account-token-list/soulbound-token-equipped/soulbound-token-equipped.component.ts b/src/app/pages/soulbound-token/soulbound-account-token-list/soulbound-token-equipped/soulbound-token-equipped.component.ts index e7b7d86af..f0ad3ba1e 100644 --- a/src/app/pages/soulbound-token/soulbound-account-token-list/soulbound-token-equipped/soulbound-token-equipped.component.ts +++ b/src/app/pages/soulbound-token/soulbound-account-token-list/soulbound-token-equipped/soulbound-token-equipped.component.ts @@ -25,7 +25,7 @@ export class SoulboundTokenEquippedComponent implements OnInit { textSearch = ''; maxLengthSearch = MAX_LENGTH_SEARCH_TOKEN; countSelected = 0; - loading = false; + loading = true; pageData: PageEvent = { length: PAGE_EVENT.LENGTH, pageSize: 20, @@ -81,22 +81,27 @@ export class SoulboundTokenEquippedComponent implements OnInit { } getListSB() { - this.loading = true; + this.textSearch = this.searchValue = this.textSearch?.trim(); const payload = { limit: this.pageData.pageSize, offset: this.pageData.pageIndex * this.pageData.pageSize, receiverAddress: this.userAddress, isEquipToken: true, - keyword: this.textSearch?.trim(), + keyword: this.textSearch, }; - this.soulboundService.getListSoulboundByAddress(payload).subscribe((res) => { - this.countSelected = res.data.filter((k) => k.picked)?.length || 0; - this.soulboundData.data = res.data; - this.pageData.length = res.meta.count; - this.totalSBT.emit(this.pageData.length); - }); - this.loading = false; + this.soulboundService.getListSoulboundByAddress(payload).subscribe( + (res) => { + this.countSelected = res.data.filter((k) => k.picked)?.length || 0; + this.soulboundData.data = res.data; + this.pageData.length = res.meta.count; + this.totalSBT.emit(this.pageData.length); + }, + () => {}, + () => { + this.loading = false; + }, + ); } paginatorEmit(event): void { @@ -111,7 +116,7 @@ export class SoulboundTokenEquippedComponent implements OnInit { } getSBTDetail(contractAddress, tokenID, pick = true) { - this.contractService.getNFTDetail(contractAddress, tokenID).subscribe((res) => { + this.contractService.getDetailCW4973(contractAddress, tokenID).subscribe((res) => { if (res?.data) { this.updatePick(res.data, pick); } diff --git a/src/app/pages/soulbound-token/soulbound-account-token-list/soulbound-token-unequipped/soulbound-token-unequipped.component.ts b/src/app/pages/soulbound-token/soulbound-account-token-list/soulbound-token-unequipped/soulbound-token-unequipped.component.ts index cdd49e4d9..84f7c91ce 100644 --- a/src/app/pages/soulbound-token/soulbound-account-token-list/soulbound-token-unequipped/soulbound-token-unequipped.component.ts +++ b/src/app/pages/soulbound-token/soulbound-account-token-list/soulbound-token-unequipped/soulbound-token-unequipped.component.ts @@ -88,11 +88,12 @@ export class SoulboundTokenUnequippedComponent implements OnInit, OnChanges { } getListSB() { + this.searchValue = this.textSearch = this.textSearch?.trim(); const payload = { limit: this.pageData.pageSize, offset: this.pageData.pageIndex * this.pageData.pageSize, receiverAddress: this.currentAddress, - keyword: this.textSearch?.trim(), + keyword: this.textSearch, }; this.soulboundService.getListSoulboundByAddress(payload).subscribe((res) => { @@ -118,7 +119,7 @@ export class SoulboundTokenUnequippedComponent implements OnInit, OnChanges { getSBTDetail(contractAddress, tokenID, isNotify) { this.isClick = true; - this.contractService.getNFTDetail(contractAddress, tokenID).subscribe((res) => { + this.contractService.getDetailCW4973(contractAddress, tokenID).subscribe((res) => { if (res?.data) { this.openDialogDetail(res.data); if (isNotify) { diff --git a/src/app/pages/soulbound-token/soulbound-contract-list/soulbound-contract-list.component.html b/src/app/pages/soulbound-token/soulbound-contract-list/soulbound-contract-list.component.html index e79d722df..283509d51 100644 --- a/src/app/pages/soulbound-token/soulbound-contract-list/soulbound-contract-list.component.html +++ b/src/app/pages/soulbound-token/soulbound-contract-list/soulbound-contract-list.component.html @@ -10,7 +10,7 @@

Account Bound Token

Account Bound Token

CONTRACT ADDRESS -
- - {{ - element.contract_address | cutStringPipe : 8 : 8 - }} +
+
@@ -82,7 +82,7 @@

Account Bound Token

diff --git a/src/app/pages/soulbound-token/soulbound-contract-list/soulbound-contract-list.component.ts b/src/app/pages/soulbound-token/soulbound-contract-list/soulbound-contract-list.component.ts index fae7a74fb..58c397cb4 100644 --- a/src/app/pages/soulbound-token/soulbound-contract-list/soulbound-contract-list.component.ts +++ b/src/app/pages/soulbound-token/soulbound-contract-list/soulbound-contract-list.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, ViewChild } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { PageEvent } from '@angular/material/paginator'; import { MatTableDataSource } from '@angular/material/table'; @@ -11,6 +11,8 @@ import { TableTemplate } from 'src/app/core/models/common.model'; import { SoulboundService } from 'src/app/core/services/soulbound.service'; import { WalletService } from 'src/app/core/services/wallet.service'; import { SoulboundTokenCreatePopupComponent } from '../soulbound-token-create-popup/soulbound-token-create-popup.component'; +import { CommonService } from 'src/app/core/services/common.service'; +import { PaginatorComponent } from 'src/app/shared/components/paginator/paginator.component'; @Component({ selector: 'app-soulbound-contract-list', @@ -18,6 +20,7 @@ import { SoulboundTokenCreatePopupComponent } from '../soulbound-token-create-po styleUrls: ['./soulbound-contract-list.component.scss'], }) export class SoulboundContractListComponent implements OnInit { + @ViewChild(PaginatorComponent) pageChange: PaginatorComponent; textSearch = ''; searchValue = ''; maxLengthSearch = MAX_LENGTH_SEARCH_TOKEN; @@ -44,6 +47,7 @@ export class SoulboundContractListComponent implements OnInit { public dialog: MatDialog, private walletService: WalletService, private router: Router, + public commonService: CommonService, ) {} ngOnInit(): void { @@ -73,6 +77,7 @@ export class SoulboundContractListComponent implements OnInit { resetSearch() { this.textSearch = ''; this.searchValue = ''; + this.pageChange.selectPage(0); this.getListSmartContract(); } @@ -86,6 +91,7 @@ export class SoulboundContractListComponent implements OnInit { } getListSmartContract() { + this.textSearch = this.searchValue = this.textSearch?.trim(); const payload = { limit: this.pageData.pageSize, offset: this.pageData.pageIndex * this.pageData.pageSize, @@ -93,6 +99,11 @@ export class SoulboundContractListComponent implements OnInit { keyword: this.textSearch, }; + const addressNameTag = this.commonService.findNameTag(this.textSearch); + if (addressNameTag?.length > 0) { + payload['keyword'] = addressNameTag; + } + this.soulboundService.getListSoulbound(payload).subscribe((res) => { this.dataSource.data = res.data; this.pageData.length = res.meta.count; @@ -112,7 +123,7 @@ export class SoulboundContractListComponent implements OnInit { if (result !== 'canceled') { setTimeout(() => { this.getListSmartContract(); - }, 2000); + }, 4000); } }); } diff --git a/src/app/pages/soulbound-token/soulbound-token-contract/soulbound-token-contract.component.html b/src/app/pages/soulbound-token/soulbound-token-contract/soulbound-token-contract.component.html index 7c519e6fc..337a1bb06 100644 --- a/src/app/pages/soulbound-token/soulbound-token-contract/soulbound-token-contract.component.html +++ b/src/app/pages/soulbound-token/soulbound-token-contract/soulbound-token-contract.component.html @@ -7,8 +7,10 @@

Account Bound Token

Contract
- {{ contractAddress | stringEllipsis : 8 }} - {{ contractAddress }} + {{ + commonService.setNameTag(contractAddress) | stringEllipsis : 8 + }} + {{ commonService.setNameTag(contractAddress) }}
- -
- -
- - - - - - - -
-
diff --git a/src/app/pages/token/token-holding/token-holding-nft/token-holding-nft.component.scss b/src/app/pages/token/token-holding/token-holding-nft/token-holding-nft.component.scss deleted file mode 100644 index 5af62b6a2..000000000 --- a/src/app/pages/token/token-holding/token-holding-nft/token-holding-nft.component.scss +++ /dev/null @@ -1,15 +0,0 @@ -.aura-form.single-input-field { - min-width: 420px; - .input-group { - height: 36px; - padding: 0 16px; - input { - font-size: 1.4rem; - line-height: 1.9rem; - } - button.btn-search img, button.btn-reset img { - width: 18px; - height: 18px; - } - } -} diff --git a/src/app/pages/token/token-holding/token-holding-nft/token-holding-nft.component.ts b/src/app/pages/token/token-holding/token-holding-nft/token-holding-nft.component.ts deleted file mode 100644 index 18227a86f..000000000 --- a/src/app/pages/token/token-holding/token-holding-nft/token-holding-nft.component.ts +++ /dev/null @@ -1,185 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import {PageEvent} from "@angular/material/paginator"; - -@Component({ - selector: 'app-token-holding-nft', - templateUrl: './token-holding-nft.component.html', - styleUrls: ['./token-holding-nft.component.scss'] -}) -export class TokenHoldingNftComponent implements OnInit { - searchValue = null; - loading = true; - pageData: PageEvent; - nftData = []; - showedData = []; - - constructor() { } - - ngOnInit(): void { - this.getNftData(); - this.showedData = this.nftData.slice(0,10); - } - - getNftData() { - this.loading = true; - // call API get nft data -> import data to showedData - this.nftData = [ - { - symbol: 'CW - 721', - name: 'The Picaroons', - tokenID: '443432324234agbki443432324adw453443', - link: '#', - img: 'assets/images/about.png' - }, - { - symbol: 'CW - 721', - name: 'The Picaroons', - tokenID: '443432324234agbki443432324adw453443', - link: '#', - img: 'assets/images/about.png' - }, - { - symbol: 'CW - 721', - name: 'The Picaroons', - tokenID: '443432324234agbki443432324adw453443', - link: '#', - img: 'assets/images/about.png' - }, - { - symbol: 'CW - 721', - name: 'The Picaroons', - tokenID: '443432324234agbki443432324adw453443', - link: '#', - img: 'assets/images/about.png' - }, - { - symbol: 'CW - 721', - name: 'The Picaroons', - tokenID: '443432324234agbki443432324adw453443', - link: '#', - img: 'assets/images/about.png' - }, - { - symbol: 'CW - 721', - name: 'The Picaroons', - tokenID: '443432324234agbki443432324adw453443', - link: '#', - img: 'assets/images/about.png' - }, - { - symbol: 'CW - 721', - name: 'The Picaroons', - tokenID: '443432324234agbki443432324adw453443', - link: '#', - img: 'assets/images/about.png' - }, - { - symbol: 'CW - 721', - name: 'The Picaroons', - tokenID: '443432324234agbki443432324adw453443', - link: '#', - img: 'assets/images/about.png' - }, - { - symbol: 'CW - 721', - name: 'The Picaroons', - tokenID: '443432324234agbki443432324adw453443', - link: '#', - img: 'assets/images/about.png' - }, - { - symbol: 'CW - 721', - name: 'The Picaroons', - tokenID: '443432324234agbki443432324adw453443', - link: '#', - img: 'assets/images/about.png' - }, - { - symbol: 'CW - 721', - name: 'The Picaroons', - tokenID: '443432324234agbki443432324adw453443', - link: '#', - img: 'assets/images/about.png' - }, - { - symbol: 'CW - 721', - name: 'The Picaroons', - tokenID: '443432324234agbki443432324adw453443', - link: '#', - img: 'assets/images/about.png' - }, - { - symbol: 'CW - 721', - name: 'The Picaroons', - tokenID: '443432324234agbki443432324adw453443', - link: '#', - img: 'assets/images/about.png' - }, - { - symbol: 'CW - 721', - name: 'The Picaroons', - tokenID: '443432324234agbki443432324adw453443', - link: '#', - img: 'assets/images/about.png' - }, - { - symbol: 'CW - 721', - name: 'The Picaroons', - tokenID: '443432324234agbki443432324adw453443', - link: '#', - img: 'assets/images/about.png' - }, - { - symbol: 'CW - 721', - name: 'The Picaroons', - tokenID: '443432324234agbki443432324adw453443', - link: '#', - img: 'assets/images/about.png' - }, - { - symbol: 'CW - 721', - name: 'The Picaroons', - tokenID: '443432324234agbki443432324adw453443', - link: '#', - img: 'assets/images/about.png' - }, - { - symbol: 'CW - 721', - name: 'The Picaroons', - tokenID: '443432324234agbki443432324adw453443', - link: '#', - img: 'assets/images/about.png' - }, - { - symbol: 'CW - 721', - name: 'The Picaroons', - tokenID: '443432324234agbki443432324adw453443', - link: '#', - img: 'assets/images/about.png' - }, - ] - this.pageData = { - length: this.nftData.length, - pageSize: 10, - pageIndex: 1, - }; - this.loading = false; - } - - handleSearch() { - // call API filter -> import data to showedData - - // update pagination length again - this.pageData = { - length: this.nftData.length, - pageSize: 10, - pageIndex: 1, - }; - } - - paginatorEmit(event): void { - // handle paginator with API - const pageEvent = event; - this.showedData = this.nftData.slice(10 * pageEvent.pageIndex, 10 * (pageEvent.pageIndex + 1)); - } -} diff --git a/src/app/pages/token/token-holding/token-holding-wallet/token-holding-wallet.component.html b/src/app/pages/token/token-holding/token-holding-wallet/token-holding-wallet.component.html deleted file mode 100644 index b2357f707..000000000 --- a/src/app/pages/token/token-holding/token-holding-wallet/token-holding-wallet.component.html +++ /dev/null @@ -1,154 +0,0 @@ -

Assets in Wallet (142/142)

-
-
-
- -
- -
-
$32.41
-
-
- - - -
-
-
- - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Asset -
- - {{ element.asset.name }} -
-
Symbol - {{ element.symbol ?? '-' }} - Contract Address - - - {{ element.contractAddress?.address }} - - Amount - {{ element.amount ? '$' + (element.amount | number: global.formatNumberOnlyDecimal) : '-'}} - Price -
- ${{ element.price.value }} ({{element.price.auraValue}} AURA) -
- -
- - -
-
Change (24H) -
- {{ element.change.value }} -
-
- - -
-
Value -
- ${{ element.value.value }} ({{element.value.auraValue}} AURA) -
-
- - -
-
- -
- {{ 'NO DATA' | translate }} -
- - -
-
- - - -
-
diff --git a/src/app/pages/token/token-holding/token-holding-wallet/token-holding-wallet.component.scss b/src/app/pages/token/token-holding/token-holding-wallet/token-holding-wallet.component.scss deleted file mode 100644 index f032b599b..000000000 --- a/src/app/pages/token/token-holding/token-holding-wallet/token-holding-wallet.component.scss +++ /dev/null @@ -1,28 +0,0 @@ -.aura-form.single-input-field { - min-width: 420px; - .input-group { - height: 36px; - padding: 0 16px; - input { - font-size: 1.4rem; - line-height: 1.9rem; - } - button.btn-search img, button.btn-reset img { - width: 18px; - height: 18px; - } - } -} -.aura__change { - font-size: 1.4rem; - line-height: 2rem; - font-weight: 400; - &--desc, &--asc { - &::after { - left: 0; - transform: unset; - width: 20px; - height: 20px; - } - } -} diff --git a/src/app/pages/token/token-holding/token-holding-wallet/token-holding-wallet.component.ts b/src/app/pages/token/token-holding/token-holding-wallet/token-holding-wallet.component.ts deleted file mode 100644 index 240759aad..000000000 --- a/src/app/pages/token/token-holding/token-holding-wallet/token-holding-wallet.component.ts +++ /dev/null @@ -1,565 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import {TableTemplate} from "../../../../core/models/common.model"; -import {PageEvent} from "@angular/material/paginator"; -import {MatTableDataSource} from "@angular/material/table"; -import {Globals} from "../../../../global/global"; - -@Component({ - selector: 'app-token-holding-wallet', - templateUrl: './token-holding-wallet.component.html', - styleUrls: ['./token-holding-wallet.component.scss'] -}) -export class TokenHoldingWalletComponent implements OnInit { - searchValue = null; - loading = true; - mockData = [ - { - id: 1, - asset: { - img: 'assets/images/logo/auraTitleLogo.png', - name: 'Aura' - }, - symbol: 'AURA', - contractAddress: { - address: 'auraeudfg77482e45FdE', - txtHash: 'auraeudfg77482e45FdE' - }, - amount: 162772.21382, - price: { - value: 21.199, - auraValue: 0.0054 - }, - change: { - value: 0.01, - growthRate: 1 - }, - value: { - value: 4.12, - auraValue: 0.001 - }, - }, - { - id: 2, - asset: { - img: 'assets/images/logo/auraTitleLogo.png', - name: 'Ethereum' - }, - symbol: 'ETH', - contractAddress: { - address: 'auraeudfg77482e45FdE', - txtHash: 'auraeudfg77482e45FdE' - }, - amount: 162772.21382, - price: { - value: 21.199, - auraValue: 0.0054 - }, - change: { - value: 0.01, - growthRate: -1 - }, - value: { - value: 4.12, - auraValue: 0.001 - }, - }, - { - id: 3, - asset: { - img: 'assets/images/logo/auraTitleLogo.png', - name: 'Gala' - }, - symbol: 'GALA', - contractAddress: { - address: 'auraeudfg77482e45FdE', - txtHash: 'auraeudfg77482e45FdE' - }, - amount: 162772.21382, - price: { - value: 21.199, - auraValue: 0.0054 - }, - change: { - value: 0.01, - growthRate: 1 - }, - value: { - value: 4.12, - auraValue: 0.001 - }, - }, - { - id: 4, - asset: { - img: 'assets/images/logo/auraTitleLogo.png', - name: 'Kishu Inu' - }, - symbol: 'KISHU', - contractAddress: { - address: 'auraeudfg77482e45FdE', - txtHash: 'auraeudfg77482e45FdE' - }, - amount: 162772.21382, - price: { - value: 21.199, - auraValue: 0.0054 - }, - change: { - value: 0.01, - growthRate: -1 - }, - value: { - value: 4.12, - auraValue: 0.001 - }, - }, - { - id: 5, - asset: { - img: 'assets/images/logo/auraTitleLogo.png', - name: 'Bitto' - }, - symbol: 'BITTO', - contractAddress: { - address: 'auraeudfg77482e45FdE', - txtHash: 'auraeudfg77482e45FdE' - }, - amount: 162772.21382, - price: { - value: 21.199, - auraValue: 0.0054 - }, - change: { - value: 0.01, - growthRate: -1 - }, - value: { - value: 4.12, - auraValue: 0.001 - }, - }, - { - id: 6, - asset: { - img: 'assets/images/logo/auraTitleLogo.png', - name: 'PKG Token' - }, - symbol: 'PKG', - contractAddress: { - address: 'auraeudfg77482e45FdE', - txtHash: 'auraeudfg77482e45FdE' - }, - amount: 162772.21382, - price: { - value: 21.199, - auraValue: 0.0054 - }, - change: { - value: 0.01, - growthRate: 1 - }, - value: { - value: 4.12, - auraValue: 0.001 - }, - }, - { - id: 7, - asset: { - img: 'assets/images/logo/auraTitleLogo.png', - name: 'Tether USD' - }, - symbol: 'USDT', - contractAddress: { - address: 'auraeudfg77482e45FdE', - txtHash: 'auraeudfg77482e45FdE' - }, - amount: 162772.21382, - price: { - value: 21.199, - auraValue: 0.0054 - }, - change: { - value: 0.01, - growthRate: 1 - }, - value: { - value: 123.1920, - auraValue: 0.0054 - }, - }, - { - id: 8, - asset: { - img: 'assets/images/logo/auraTitleLogo.png', - name: 'USDC' - }, - symbol: 'USDC', - contractAddress: { - address: 'auraeudfg77482e45FdE', - txtHash: 'auraeudfg77482e45FdE' - }, - amount: 162772.21382, - price: { - value: 21.199, - auraValue: 0.0054 - }, - change: { - value: 0.01, - growthRate: 1 - }, - value: { - value: 123.1920, - auraValue: 0.0054 - }, - }, - { - id: 9, - asset: { - img: 'assets/images/logo/auraTitleLogo.png', - name: 'Cronos Coin' - }, - symbol: 'CRO', - contractAddress: { - address: 'auraeudfg77482e45FdE', - txtHash: 'auraeudfg77482e45FdE' - }, - amount: 162772.21382, - price: { - value: 21.199, - auraValue: 0.0054 - }, - change: { - value: 0.01, - growthRate: 1 - }, - value: { - value: 123.1920, - auraValue: 0.0054 - }, - }, - { - id: 10, - asset: { - img: 'assets/images/logo/auraTitleLogo.png', - name: 'Binance USD' - }, - symbol: 'BNB', - contractAddress: { - address: 'auraeudfg77482e45FdE', - txtHash: 'auraeudfg77482e45FdE' - }, - amount: 162772.21382, - price: { - value: 21.199, - auraValue: 0.0054 - }, - change: { - value: 0.01, - growthRate: 1 - }, - value: { - value: 123.1920, - auraValue: 0.0054 - }, - }, - { - id: 11, - asset: { - img: 'assets/images/logo/auraTitleLogo.png', - name: 'BNB' - }, - symbol: 'BNB', - contractAddress: { - address: 'auraeudfg77482e45FdE', - txtHash: 'auraeudfg77482e45FdE' - }, - amount: 162772.21382, - price: { - value: 21.199, - auraValue: 0.0054 - }, - change: { - value: 0.01, - growthRate: 1 - }, - value: { - value: 4.12, - auraValue: 0.001 - }, - }, - { - id: 12, - asset: { - img: 'assets/images/logo/auraTitleLogo.png', - name: 'Tether USD' - }, - symbol: 'USDT', - contractAddress: { - address: 'auraeudfg77482e45FdE', - txtHash: 'auraeudfg77482e45FdE' - }, - amount: 162772.21382, - price: { - value: 21.199, - auraValue: 0.0054 - }, - change: { - value: 0.01, - growthRate: -1 - }, - value: { - value: 4.12, - auraValue: 0.001 - }, - }, - { - id: 13, - asset: { - img: 'assets/images/logo/auraTitleLogo.png', - name: 'USD Coin' - }, - symbol: 'USDC', - contractAddress: { - address: 'auraeudfg77482e45FdE', - txtHash: 'auraeudfg77482e45FdE' - }, - amount: 162772.21382, - price: { - value: 21.199, - auraValue: 0.0054 - }, - change: { - value: 0.01, - growthRate: 1 - }, - value: { - value: 4.12, - auraValue: 0.001 - }, - }, - { - id: 14, - asset: { - img: 'assets/images/logo/auraTitleLogo.png', - name: 'Binance USD' - }, - symbol: 'BUSD', - contractAddress: { - address: 'auraeudfg77482e45FdE', - txtHash: 'auraeudfg77482e45FdE' - }, - amount: 162772.21382, - price: { - value: 21.199, - auraValue: 0.0054 - }, - change: { - value: 0.01, - growthRate: -1 - }, - value: { - value: 4.12, - auraValue: 0.001 - }, - }, - { - id: 15, - asset: { - img: 'assets/images/logo/auraTitleLogo.png', - name: 'HEX' - }, - symbol: 'HEX', - contractAddress: { - address: 'auraeudfg77482e45FdE', - txtHash: 'auraeudfg77482e45FdE' - }, - amount: 162772.21382, - price: { - value: 21.199, - auraValue: 0.0054 - }, - change: { - value: 0.01, - growthRate: -1 - }, - value: { - value: 4.12, - auraValue: 0.001 - }, - }, - { - id: 16, - asset: { - img: 'assets/images/logo/auraTitleLogo.png', - name: 'Wrapped BTC' - }, - symbol: 'WBTC', - contractAddress: { - address: 'auraeudfg77482e45FdE', - txtHash: 'auraeudfg77482e45FdE' - }, - amount: 162772.21382, - price: { - value: 21.199, - auraValue: 0.0054 - }, - change: { - value: 0.01, - growthRate: 1 - }, - value: { - value: 4.12, - auraValue: 0.001 - }, - }, - { - id: 17, - asset: { - img: 'assets/images/logo/auraTitleLogo.png', - name: 'stETH' - }, - symbol: 'stETH', - contractAddress: { - address: 'auraeudfg77482e45FdE', - txtHash: 'auraeudfg77482e45FdE' - }, - amount: 162772.21382, - price: { - value: 21.199, - auraValue: 0.0054 - }, - change: { - value: 0.01, - growthRate: 1 - }, - value: { - value: 123.1920, - auraValue: 0.0054 - }, - }, - { - id: 18, - asset: { - img: 'assets/images/logo/auraTitleLogo.png', - name: 'Wrapped liquid staked Ether 2.0' - }, - symbol: 'wstETH', - contractAddress: { - address: 'auraeudfg77482e45FdE', - txtHash: 'auraeudfg77482e45FdE' - }, - amount: 162772.21382, - price: { - value: 21.199, - auraValue: 0.0054 - }, - change: { - value: 0.01, - growthRate: 1 - }, - value: { - value: 123.1920, - auraValue: 0.0054 - }, - }, - { - id: 19, - asset: { - img: 'assets/images/logo/auraTitleLogo.png', - name: 'Dai Stablecoin' - }, - symbol: 'DAI', - contractAddress: { - address: 'auraeudfg77482e45FdE', - txtHash: 'auraeudfg77482e45FdE' - }, - amount: 162772.21382, - price: { - value: 21.199, - auraValue: 0.0054 - }, - change: { - value: 0.01, - growthRate: 1 - }, - value: { - value: 123.1920, - auraValue: 0.0054 - }, - }, - { - id: 20, - asset: { - img: 'assets/images/logo/auraTitleLogo.png', - name: 'SHIBA INU' - }, - symbol: 'SHIB', - contractAddress: { - address: 'auraeudfg77482e45FdE', - txtHash: 'auraeudfg77482e45FdE' - }, - amount: 162772.21382, - price: { - value: 21.199, - auraValue: 0.0054 - }, - change: { - value: 0.01, - growthRate: 1 - }, - value: { - value: 123.1920, - auraValue: 0.0054 - }, - }, - ]; - templates: Array = [ - { matColumnDef: 'asset', headerCellDef: 'asset' }, - { matColumnDef: 'symbol', headerCellDef: 'symbol' }, - { matColumnDef: 'contractAddress', headerCellDef: 'contractAddress' }, - { matColumnDef: 'amount', headerCellDef: 'amount' }, - { matColumnDef: 'price', headerCellDef: 'price' }, - { matColumnDef: 'change', headerCellDef: 'change' }, - { matColumnDef: 'value', headerCellDef: 'value' }, - { matColumnDef: 'action', headerCellDef: 'action' }, - ]; - displayedColumns: string[] = this.templates.map((dta) => dta.matColumnDef); - pageData: PageEvent; - dataSource: MatTableDataSource = new MatTableDataSource([]); - - constructor(public global: Globals) { } - - ngOnInit(): void { - this.getTokenData(); - } - - getTokenData() { - this.pageData = { - length: this.mockData.length, - pageSize: 10, - pageIndex: 1, - }; - this.loading = true; - this.dataSource = new MatTableDataSource(this.mockData); - this.loading = false; - } - - handleSearch() { - const filterData = this.mockData.filter( - (data) => data.asset.name.includes(this.searchValue) || data.contractAddress.txtHash.includes(this.searchValue), - ); - if (filterData.length > 0) { - this.pageData = { - length: filterData.length, - pageSize: 10, - pageIndex: 1, - }; - this.dataSource = new MatTableDataSource(filterData); - } - } - - paginatorEmit(event): void { - this.dataSource.paginator = event; - } -} diff --git a/src/app/pages/token/token-holding/token-holding.component.html b/src/app/pages/token/token-holding/token-holding.component.html deleted file mode 100644 index 779a40198..000000000 --- a/src/app/pages/token/token-holding/token-holding.component.html +++ /dev/null @@ -1,63 +0,0 @@ - -
-

Token Holdings

- -
-
- -
-

Overview

-
-
-
Net Worth in USD
-
$32.41
-
-
-
Net Worth in AURA
-
- - 12.25 -
-
-
-
Total Balance Change (24h)
-
1.87%
-
-
-
-
-
-
-
Assets in Wallet (142)
-
$32.41
-
-
-
-
-
-
-
NFT Assets (3)
-
$0.41
-
-
-
-
-
- -
- -
- - -
- -
diff --git a/src/app/pages/token/token-holding/token-holding.component.scss b/src/app/pages/token/token-holding/token-holding.component.scss deleted file mode 100644 index e689645b7..000000000 --- a/src/app/pages/token/token-holding/token-holding.component.scss +++ /dev/null @@ -1,25 +0,0 @@ -.overview { - &-row { - display: flex; - } - &-col { - padding: 12px 24px; - &:not(:last-child) { - border-right: 1px solid #353945; - } - } - &__label { - font-size: 1.6rem; - line-height: 2.4rem; - font-weight: 400; - color: var(--aura-light-gray); - margin-bottom: var(--spacer-1); - } - &__content { - display: inline-flex; - color: var(--aura-white); - font-size: 2rem; - line-height: 2.3rem; - font-weight: 500; - } -} diff --git a/src/app/pages/token/token-holding/token-holding.component.ts b/src/app/pages/token/token-holding/token-holding.component.ts deleted file mode 100644 index e86e8b5a5..000000000 --- a/src/app/pages/token/token-holding/token-holding.component.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import {ActivatedRoute} from "@angular/router"; - -@Component({ - selector: 'app-token-holding', - templateUrl: './token-holding.component.html', - styleUrls: ['./token-holding.component.scss'] -}) -export class TokenHoldingComponent implements OnInit { - tokenId = ''; - constructor(private route:ActivatedRoute) { } - - ngOnInit(): void { - this.tokenId = this.route.snapshot.paramMap.get('tokenId'); - } - - copyData(text: string): void { - const dummy = document.createElement('textarea'); - document.body.appendChild(dummy); - dummy.value = text; - dummy.select(); - document.execCommand('copy'); - document.body.removeChild(dummy); - // fake event click out side copy button - // this event for hidden tooltip - setTimeout(function (){ - document.getElementById('popupCopy').click(); - }, 800) - } -} diff --git a/src/app/pages/token/token-list/token-cw20/token-cw20.component.html b/src/app/pages/token/token-list/token-cw20/token-cw20.component.html index 8141bf872..e21783d65 100644 --- a/src/app/pages/token/token-list/token-cw20/token-cw20.component.html +++ b/src/app/pages/token/token-list/token-cw20/token-cw20.component.html @@ -1,5 +1,6 @@

CW-20 Tokens

-
+ +
@@ -59,23 +60,17 @@

CW-20 Tokens

{{ element.name | stringEllipsis : 16 }} ({{ element.symbol }}) -
+
+ +
- -
@@ -152,9 +147,9 @@

CW-20 Tokens

{{ element.holders | number : global.formatNumberOnlyDecimal }}
- {{ element.isHolderUp ? '+' : '' - }}{{ element.holderChange | number : global.formatNumber2Decimal }}% + {{ element.isHolderUp ? '↑' : '↓' + }}{{ element.holderChange || 0 | number : global.formatNumber2Decimal }}% diff --git a/src/app/pages/token/token-list/token-cw20/token-cw20.component.ts b/src/app/pages/token/token-list/token-cw20/token-cw20.component.ts index 483214d86..990d657d3 100644 --- a/src/app/pages/token/token-list/token-cw20/token-cw20.component.ts +++ b/src/app/pages/token/token-list/token-cw20/token-cw20.component.ts @@ -1,16 +1,18 @@ +import { DatePipe } from '@angular/common'; import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { PageEvent } from '@angular/material/paginator'; import { MatSort, Sort } from '@angular/material/sort'; import { MatTableDataSource } from '@angular/material/table'; import { TranslateService } from '@ngx-translate/core'; -import { Subject } from 'rxjs'; -import { debounceTime, distinctUntilChanged, takeUntil } from 'rxjs/operators'; +import * as _ from 'lodash'; +import { Observable, Subject, of } from 'rxjs'; +import { debounceTime, distinctUntilChanged, map, mergeMap, repeat, takeLast, takeUntil } from 'rxjs/operators'; import { EnvironmentService } from 'src/app/core/data-services/environment.service'; import { TokenService } from 'src/app/core/services/token.service'; import { PaginatorComponent } from 'src/app/shared/components/paginator/paginator.component'; -import { PAGE_EVENT } from '../../../../core/constants/common.constant'; +import { DATEFORMAT, PAGE_EVENT } from '../../../../core/constants/common.constant'; import { MAX_LENGTH_SEARCH_TOKEN } from '../../../../core/constants/token.constant'; -import { ResponseDto, TableTemplate } from '../../../../core/models/common.model'; +import { TableTemplate } from '../../../../core/models/common.model'; import { Globals } from '../../../../global/global'; @Component({ @@ -47,15 +49,18 @@ export class TokenCw20Component implements OnInit, OnDestroy { denom = this.environmentService.configValue.chain_info.currencies[0].coinDenom; image_s3 = this.environmentService.configValue.image_s3; defaultLogoToken = this.image_s3 + 'images/icons/token-logo.png'; + isLoading = true; searchSubject = new Subject(); destroy$ = new Subject(); + dataTable = []; constructor( public translate: TranslateService, public global: Globals, public tokenService: TokenService, private environmentService: EnvironmentService, + private datePipe: DatePipe, ) {} ngOnDestroy(): void { @@ -66,7 +71,6 @@ export class TokenCw20Component implements OnInit, OnDestroy { ngOnInit(): void { this.getListToken(); - this.searchSubject .asObservable() .pipe(debounceTime(500), distinctUntilChanged(), takeUntil(this.destroy$)) @@ -83,32 +87,126 @@ export class TokenCw20Component implements OnInit, OnDestroy { this.searchSubject.next(this.textSearch); } + getAllCW20Token(): Observable { + let now = new Date(); + now.setDate(now.getDate() - 1); + + let payload = { + offset: 0, + date: this.datePipe.transform(now, DATEFORMAT.DATE_ONLY), + }; + let cw20Total = []; + const destroy_cw20$ = new Subject(); + return of(null).pipe( + mergeMap(() => { + return this.tokenService.getListToken(payload); + }), + map((res) => { + const count = _.get(res, `cw20_contract_aggregate`); + const cw20Data = _.get(res, `cw20_contract`); + // Get more data when response data less than total data + if (cw20Total.length < count?.aggregate?.count) { + cw20Total = [...cw20Total, ...cw20Data]; + payload = { + offset: cw20Total.length, + date: this.datePipe.transform(now, DATEFORMAT.DATE_ONLY), + }; + } else { + destroy_cw20$.next(); + destroy_cw20$.complete(); + } + return cw20Total; + }), + repeat(), + takeUntil(destroy_cw20$), + ); + } + getListToken() { + this.textSearch = this.textSearch?.trim(); const payload = { limit: this.pageData.pageSize, offset: this.pageData.pageIndex * this.pageData.pageSize, - keyword: this.textSearch, }; + // Check table exist for search and pagination + if (this.dataTable.length > 0) { + let result = this.dataTable + ?.sort((a, b) => b.circulating_market_cap - a.circulating_market_cap) + .slice(payload?.offset, payload?.offset + payload?.limit); + // Search with text search + if (this.textSearch) { + result = this.dataTable + .filter( + (item) => + item.name.toLowerCase().includes(this.textSearch.toLowerCase()) || + item.contract_address == this.textSearch.toLowerCase(), + ) + ?.sort((a, b) => b.circulating_market_cap - a.circulating_market_cap); - this.tokenService.getListToken(payload).subscribe((res: ResponseDto) => { - res.data.forEach((data) => { - Object.assign(data, { - ...data, - circulating_market_cap: +data.circulating_market_cap || 0, - onChainMarketCap: +data.circulating_market_cap || 0, - volume: +data.volume_24h, - price: +data.price, - isValueUp: data.price_change_percentage_24h < 0 ? false : true, - change: Number(data.price_change_percentage_24h.toString()), - isHolderUp: data.holders_change_percentage_24h < 0 ? false : true, - holders: +data.holders, - holderChange: Number(data.holders_change_percentage_24h.toString()), - }); - }); - - this.dataSource = new MatTableDataSource(res.data); - this.pageData.length = res.meta.count; - }); + const data = result.slice(payload?.offset, payload?.offset + payload?.limit); + this.dataSource = new MatTableDataSource(data); + this.pageData.length = result?.length; + } else { + this.dataSource = new MatTableDataSource(result); + this.pageData.length = this.dataTable?.length; + } + } else { + // Get the frist time data init screen + this.getAllCW20Token() + .pipe(takeLast(1)) + .subscribe( + (res) => { + this.tokenService.getTokenMarketData().subscribe((tokenMarket) => { + // Flat data for mapping response api + const dataFlat = res?.map((item) => { + let changePercent = 0; + const tokenFind = tokenMarket?.find( + (f) => String(f.contract_address) === item?.smart_contract?.address, + ); + if (item.cw20_total_holder_stats?.length > 1) { + changePercent = + (item.cw20_total_holder_stats[1].total_holder * 100) / + item.cw20_total_holder_stats[0].total_holder - + 100; + } + return { + coin_id: tokenFind?.coin_id || '', + contract_address: item.smart_contract.address || '', + name: item.name || '', + symbol: item.symbol || '', + image: item.marketing_info?.logo?.url ? item.marketing_info?.logo?.url : tokenFind?.image || '', + description: tokenFind?.description || '', + verify_status: tokenFind?.verify_status || '', + verify_text: tokenFind?.verify_text || '', + circulating_market_cap: +tokenFind?.circulating_market_cap || 0, + onChainMarketCap: +tokenFind?.circulating_market_cap || 0, + volume: +tokenFind?.total_volume || 0, + price: +tokenFind?.current_price || 0, + isHolderUp: changePercent >= 0 ? true : false, + isValueUp: tokenFind?.price_change_percentage_24h >= 0 ? true : false, + change: tokenFind?.price_change_percentage_24h || 0, + holderChange: Math.abs(changePercent), + holders: item.cw20_holders_aggregate?.aggregate?.count, + max_total_supply: tokenFind?.max_supply || 0, + fully_diluted_market_cap: tokenFind?.fully_diluted_valuation || 0, + }; + }); + // store datatable + this.dataTable = dataFlat; + // Sort and slice 20 frist record. + const result = dataFlat + ?.sort((a, b) => b.circulating_market_cap - a.circulating_market_cap) + .slice(payload?.offset, payload?.offset + payload?.limit); + this.dataSource = new MatTableDataSource(result); + this.pageData.length = res?.length; + }); + }, + (e) => {}, + () => { + this.isLoading = false; + }, + ); + } } paginatorEmit(event): void { diff --git a/src/app/pages/token/token-list/token-cw4973/token-cw4973.component.html b/src/app/pages/token/token-list/token-cw4973/token-cw4973.component.html index 2dcea9e90..461017e57 100644 --- a/src/app/pages/token/token-list/token-cw4973/token-cw4973.component.html +++ b/src/app/pages/token/token-list/token-cw4973/token-cw4973.component.html @@ -12,7 +12,7 @@

Account Bound Tokens (ABT)

Account Bound Tokens (ABT) # - {{ pageData?.pageIndex * 20 + i + 1 }} + {{ (pageData.pageIndex - 1) * pageData.pageSize + i + 1 }} Token Token Contract - {{ - element.contract_address | cutStringPipe : 8 : 8 - }} + Creator - {{ - element.minter_address | cutStringPipe : 8 : 8 - }} + @@ -81,12 +77,10 @@

Account Bound Tokens (ABT)

- - +
+ + +
diff --git a/src/app/pages/token/token-list/token-cw4973/token-cw4973.component.ts b/src/app/pages/token/token-list/token-cw4973/token-cw4973.component.ts index e1eda8daa..37ea58f85 100644 --- a/src/app/pages/token/token-list/token-cw4973/token-cw4973.component.ts +++ b/src/app/pages/token/token-list/token-cw4973/token-cw4973.component.ts @@ -3,13 +3,14 @@ import { PageEvent } from '@angular/material/paginator'; import { MatTableDataSource } from '@angular/material/table'; import { TranslateService } from '@ngx-translate/core'; import { Subject } from 'rxjs'; -import { debounceTime, distinctUntilChanged, takeUntil } from 'rxjs/operators'; +import { debounceTime, takeUntil } from 'rxjs/operators'; import { PAGE_EVENT } from 'src/app/core/constants/common.constant'; import { MAX_LENGTH_SEARCH_TOKEN } from 'src/app/core/constants/token.constant'; +import { CommonService } from 'src/app/core/services/common.service'; import { SoulboundService } from 'src/app/core/services/soulbound.service'; import { TokenService } from 'src/app/core/services/token.service'; import { PaginatorComponent } from 'src/app/shared/components/paginator/paginator.component'; -import { ResponseDto, TableTemplate } from '../../../../core/models/common.model'; +import { TableTemplate } from '../../../../core/models/common.model'; import { Globals } from '../../../../global/global'; @Component({ @@ -32,7 +33,7 @@ export class TokenCw4973Component implements OnInit { pageData: PageEvent = { length: PAGE_EVENT.LENGTH, pageSize: 20, - pageIndex: PAGE_EVENT.PAGE_INDEX, + pageIndex: 1, }; dataSource: MatTableDataSource = new MatTableDataSource([]); maxLengthSearch = MAX_LENGTH_SEARCH_TOKEN; @@ -42,6 +43,7 @@ export class TokenCw4973Component implements OnInit { public global: Globals, public tokenService: TokenService, public soulboundService: SoulboundService, + public commonService: CommonService, ) {} ngOnInit(): void { @@ -49,18 +51,13 @@ export class TokenCw4973Component implements OnInit { this.searchSubject .asObservable() - .pipe(debounceTime(500), distinctUntilChanged(), takeUntil(this.destroy$)) + .pipe(debounceTime(500), takeUntil(this.destroy$)) .subscribe(() => { - if (this.pageData.pageIndex === PAGE_EVENT.PAGE_INDEX) { - this.getTokenData(); - } else { - this.pageChange.selectPage(0); - } + this.pageEvent(0); }); } ngOnDestroy(): void { - // throw new Error('Method not implemented.'); this.destroy$.next(); this.destroy$.complete(); } @@ -70,14 +67,21 @@ export class TokenCw4973Component implements OnInit { } getTokenData() { - const payload = { + this.textSearch = this.textSearch?.trim(); + let payload = { limit: this.pageData.pageSize, - offset: this.pageData.pageIndex * this.pageData.pageSize, + offset: (this.pageData.pageIndex - 1) * this.pageData.pageSize, keyword: this.textSearch, }; - this.soulboundService.getListABT(payload).subscribe((res: ResponseDto) => { - this.dataSource = new MatTableDataSource(res.data); - this.pageData.length = res.meta.count; + + const addressNameTag = this.commonService.findNameTag(this.textSearch); + if (addressNameTag?.length > 0) { + payload['keyword'] = addressNameTag; + } + + this.soulboundService.getListABT(payload).subscribe((res) => { + this.dataSource = new MatTableDataSource(res?.cw721_contract); + this.pageData.length = res?.cw721_contract_aggregate.aggregate.count; }); } @@ -85,13 +89,16 @@ export class TokenCw4973Component implements OnInit { this.dataSource.paginator = event; } - pageEvent(e: PageEvent): void { - this.pageData.pageIndex = e.pageIndex; + pageEvent(pageIndex: number): void { + // reset page 1 if pageIndex = 0 + if (pageIndex === 0) { + this.pageData.pageIndex = 1; + } this.getTokenData(); } resetSearch() { this.textSearch = ''; - this.onKeyUp(); + this.pageEvent(0); } } diff --git a/src/app/pages/token/token-list/token-cw721/token-cw721.component.html b/src/app/pages/token/token-list/token-cw721/token-cw721.component.html index ebc078e62..92c5d602c 100644 --- a/src/app/pages/token/token-list/token-cw721/token-cw721.component.html +++ b/src/app/pages/token/token-list/token-cw721/token-cw721.component.html @@ -13,7 +13,7 @@

Non-Fungible Tokens (NFT)

Non-Fungible Tokens (NFT) # - {{ pageData?.pageIndex * 20 + i + 1 }} + {{ (pageData.pageIndex - 1) * pageData.pageSize + i + 1 }} @@ -51,9 +51,11 @@

Non-Fungible Tokens (NFT)

- - {{ element.name | stringEllipsis : 16 }} - ({{ element.symbol }}) + + {{ element.cw721_contract?.name | stringEllipsis : 16 }} + ({{ element.cw721_contract?.symbol }})
{{ element.description }} @@ -65,22 +67,20 @@

Non-Fungible Tokens (NFT)

Token Contract - {{ - element.contract_address | cutStringPipe : 8 : 8 - }} + - - Total Transactions + + Total Activities - {{ element.total_tx | number }} + {{ element.total_activity | number }} - + Transfers (24H) - - {{ element.transfers_24h | number }} + + {{ element.transfer_24h | number }} @@ -93,12 +93,10 @@

Non-Fungible Tokens (NFT)

- - +
+ + +
diff --git a/src/app/pages/token/token-list/token-cw721/token-cw721.component.ts b/src/app/pages/token/token-list/token-cw721/token-cw721.component.ts index 46d2d2d21..1832001ab 100644 --- a/src/app/pages/token/token-list/token-cw721/token-cw721.component.ts +++ b/src/app/pages/token/token-list/token-cw721/token-cw721.component.ts @@ -4,13 +4,14 @@ import { MatSort, Sort } from '@angular/material/sort'; import { MatTableDataSource } from '@angular/material/table'; import { TranslateService } from '@ngx-translate/core'; import { Subject } from 'rxjs'; -import { debounceTime, distinctUntilChanged, takeUntil } from 'rxjs/operators'; +import { debounceTime, takeUntil } from 'rxjs/operators'; import { PAGE_EVENT } from 'src/app/core/constants/common.constant'; import { MAX_LENGTH_SEARCH_TOKEN } from 'src/app/core/constants/token.constant'; import { EnvironmentService } from 'src/app/core/data-services/environment.service'; +import { CommonService } from 'src/app/core/services/common.service'; import { TokenService } from 'src/app/core/services/token.service'; import { PaginatorComponent } from 'src/app/shared/components/paginator/paginator.component'; -import { ResponseDto, TableTemplate } from '../../../../core/models/common.model'; +import { TableTemplate } from '../../../../core/models/common.model'; import { Globals } from '../../../../global/global'; @Component({ @@ -25,23 +26,19 @@ export class TokenCw721Component implements OnInit { { matColumnDef: 'id', headerCellDef: 'id' }, { matColumnDef: 'token', headerCellDef: 'name' }, { matColumnDef: 'tokenContract', headerCellDef: 'tokenContract' }, - { matColumnDef: 'total_tx', headerCellDef: 'total_tx' }, - { matColumnDef: 'transfers_24h', headerCellDef: 'transfer' }, + { matColumnDef: 'total_activity', headerCellDef: 'total_activity' }, + { matColumnDef: 'transfer_24h', headerCellDef: 'transfer' }, ]; displayedColumns: string[] = this.templates.map((dta) => dta.matColumnDef); pageData: PageEvent = { length: PAGE_EVENT.LENGTH, pageSize: 20, - pageIndex: PAGE_EVENT.PAGE_INDEX, + pageIndex: 1, }; dataSource: MatTableDataSource = new MatTableDataSource([]); maxLengthSearch = MAX_LENGTH_SEARCH_TOKEN; sort: MatSort; - typeSortBy = { - transfers24h: 'transfers_24h', - totalTx: 'total_tx', - }; - sortBy = this.typeSortBy.transfers24h; + sortBy = 'transfer_24h'; sortOrder = 'desc'; isSorting = true; searchSubject = new Subject(); @@ -54,6 +51,7 @@ export class TokenCw721Component implements OnInit { public global: Globals, public tokenService: TokenService, private environmentService: EnvironmentService, + public commonService: CommonService, ) {} ngOnInit(): void { @@ -61,43 +59,35 @@ export class TokenCw721Component implements OnInit { this.searchSubject .asObservable() - .pipe(debounceTime(500), distinctUntilChanged(), takeUntil(this.destroy$)) + .pipe(debounceTime(500), takeUntil(this.destroy$)) .subscribe(() => { - if (this.pageData.pageIndex === PAGE_EVENT.PAGE_INDEX) { - this.getTokenData(); - } else { - this.pageChange.selectPage(0); - } + this.pageEvent(0); }); } ngOnDestroy(): void { - // throw new Error('Method not implemented.'); this.destroy$.next(); this.destroy$.complete(); } getTokenData() { + this.textSearch = this.textSearch?.trim(); const payload = { limit: this.pageData.pageSize, - offset: this.pageData.pageIndex * this.pageData.pageSize, - keyword: this.textSearch, + offset: (this.pageData.pageIndex - 1) * this.pageData.pageSize, sort_column: this.sortBy, sort_order: this.sortOrder, }; - this.tokenService.getListCW721Token(payload).subscribe((res: ResponseDto) => { - this.isSorting = false; - if (res.data.length > 0) { - res.data.forEach((data) => { - data['isValueUp'] = true; - if (data.change < 0) { - data['isValueUp'] = false; - data.change = Number(data.change.toString().substring(1)); - } - }); - } - this.dataSource = new MatTableDataSource(res.data); - this.pageData.length = res.meta.count; + + let keySearch = this.textSearch; + const addressNameTag = this.commonService.findNameTag(keySearch); + if (addressNameTag?.length > 0) { + keySearch = addressNameTag; + } + + this.tokenService.getListCW721Token(payload, keySearch).subscribe((res) => { + this.dataSource = new MatTableDataSource(res.list_token); + this.pageData.length = res.total_token?.aggregate?.count; }); } @@ -105,38 +95,22 @@ export class TokenCw721Component implements OnInit { this.searchSubject.next(this.textSearch); } - paginatorEmit(event): void { - this.dataSource.paginator = event; - } - - pageEvent(e: PageEvent): void { - this.pageData.pageIndex = e.pageIndex; + pageEvent(pageIndex: number): void { + // reset page 1 if pageIndex = 0 + if (pageIndex === 0) { + this.pageData.pageIndex = 1; + } this.getTokenData(); } resetSearch() { this.textSearch = ''; - this.onKeyUp(); + this.pageEvent(0); } sortData(sort: Sort) { - if (!this.isSorting) { - this.dataSource.data.sort((a, b) => { - switch (sort.active) { - case 'transfers_24h': - this.sortBy = this.typeSortBy.transfers24h; - this.sortOrder = sort.direction; - this.getTokenData(); - return 0; - case 'total_tx': - this.sortBy = this.typeSortBy.totalTx; - this.sortOrder = sort.direction; - this.getTokenData(); - return 0; - default: - return 0; - } - }); - } + this.sortBy = sort.active; + this.sortOrder = sort.direction; + this.getTokenData(); } } diff --git a/src/app/pages/token/token-routing.module.ts b/src/app/pages/token/token-routing.module.ts index d0bee27b3..41840198c 100644 --- a/src/app/pages/token/token-routing.module.ts +++ b/src/app/pages/token/token-routing.module.ts @@ -2,7 +2,6 @@ import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { NFTDetailComponent } from './nft-detail/nft-detail.component'; import { TokenDetailComponent } from './token-detail/token-detail.component'; -import { TokenHoldingComponent } from './token-holding/token-holding.component'; import { TokenCw20Component } from './token-list/token-cw20/token-cw20.component'; import { TokenCw4973Component } from './token-list/token-cw4973/token-cw4973.component'; import { TokenCw721Component } from './token-list/token-cw721/token-cw721.component'; @@ -40,10 +39,6 @@ const routes: Routes = [ path: 'address/:contractAddress', component: TokenDetailComponent, }, - { - path: 'token-holding/:contractAddress', - component: TokenHoldingComponent, - }, { path: 'token-nft/:contractAddress/:nftId', component: NFTDetailComponent, diff --git a/src/app/pages/token/token.module.ts b/src/app/pages/token/token.module.ts index 4de078a89..7a7ce5fc4 100644 --- a/src/app/pages/token/token.module.ts +++ b/src/app/pages/token/token.module.ts @@ -1,3 +1,4 @@ +import { ClipboardModule } from '@angular/cdk/clipboard'; import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; @@ -5,12 +6,16 @@ import { MatTableModule } from '@angular/material/table'; import { NgbNavModule, NgbPopoverModule } from '@ng-bootstrap/ng-bootstrap'; import { TranslateModule } from '@ngx-translate/core'; import { NgxMaskModule } from 'ngx-mask'; +import { CommonDirectiveModule } from 'src/app/core/directives/common-directive.module'; import { CommonPipeModule } from 'src/app/core/pipes/common-pipe.module'; import { AccountService } from 'src/app/core/services/account.service'; +import { APaginatorModule } from 'src/app/shared/components/a-paginator/a-paginator.module'; import { AudioPlayerModule } from 'src/app/shared/components/audio-player/audio-player.module'; import { NftCardModule } from 'src/app/shared/components/cards/nft-card/nft-card.module'; import { ContractPopoverModule } from 'src/app/shared/components/contract-popover/contract-popover.module'; import { ModelViewModule } from 'src/app/shared/components/model-view/model-view.module'; +import { NameTagModule } from 'src/app/shared/components/name-tag/name-tag.module'; +import { TooltipCustomizeModule } from 'src/app/shared/components/tooltip-customize/tooltip-customize.module'; import { MaterialModule } from '../../../app/app.module'; import { PaginatorModule } from '../../../app/shared/components/paginator/paginator.module'; import { TableNoDataModule } from '../../../app/shared/components/table-no-data/table-no-data.module'; @@ -30,14 +35,10 @@ import { TokenContentComponent } from './token-detail/token-content/token-conten import { TokenDetailComponent } from './token-detail/token-detail.component'; import { TokenOverviewComponent } from './token-detail/token-overview/token-overview.component'; import { TokenSummaryComponent } from './token-detail/token-summary/token-summary.component'; -import { TokenHoldingNftComponent } from './token-holding/token-holding-nft/token-holding-nft.component'; -import { TokenHoldingWalletComponent } from './token-holding/token-holding-wallet/token-holding-wallet.component'; -import { TokenHoldingComponent } from './token-holding/token-holding.component'; import { TokenCw20Component } from './token-list/token-cw20/token-cw20.component'; import { TokenCw4973Component } from './token-list/token-cw4973/token-cw4973.component'; import { TokenCw721Component } from './token-list/token-cw721/token-cw721.component'; import { TokenRoutingModule } from './token-routing.module'; -import { CommonDirectiveModule } from 'src/app/core/directives/common-directive.module'; @NgModule({ declarations: [ @@ -51,13 +52,10 @@ import { CommonDirectiveModule } from 'src/app/core/directives/common-directive. TokenTransfersTabComponent, TokenInfoTabComponent, TokenContractTabComponent, - TokenHoldingComponent, - TokenHoldingWalletComponent, - TokenHoldingNftComponent, TokenInventoryComponent, NFTDetailComponent, PopupShareComponent, - TokenCw4973Component + TokenCw4973Component, ], imports: [ CommonModule, @@ -80,7 +78,11 @@ import { CommonDirectiveModule } from 'src/app/core/directives/common-directive. NftCardModule, AudioPlayerModule, ContractsModule, - CommonDirectiveModule + CommonDirectiveModule, + APaginatorModule, + NameTagModule, + TooltipCustomizeModule, + ClipboardModule, ], providers: [TokenService, AccountService], }) diff --git a/src/app/pages/transaction/transaction-detail/transaction-detail.component.html b/src/app/pages/transaction/transaction-detail/transaction-detail.component.html index 6954d07de..02306605d 100644 --- a/src/app/pages/transaction/transaction-detail/transaction-detail.component.html +++ b/src/app/pages/transaction/transaction-detail/transaction-detail.component.html @@ -12,50 +12,49 @@

Transaction Details

-
-
- [This is a Serenity Testnet transaction only] -
+
+
+
+
Error:
+ {{ errorMessage }} +
+
+ See more + See less +
-

+

{{ !isRawData ? 'Information' : 'Raw Data' }}

- +
+ + +
-
+
-
- {{ errorMessage }} -
-
+
Chain Id
-
{{ transaction?.chainid }}
+
{{ transaction?.chainid }}
-
+
TxHash
-
+
{{ transaction?.tx_hash }} {{ transaction?.tx_hash | cutStringPipe : 8 : 8 }}
-
+
Status
-
+
Transaction Details }}
-
+
Height
- -
+
Time
-
+
{{ commonService.getDateValue(transaction?.timestamp)[0] }}
( @@ -90,9 +89,9 @@

Transaction Details

-
+
Fee
-
+
{{ +transaction?.fee | mask : 'separator.6' }} {{ denom }}
@@ -101,7 +100,7 @@

Transaction Details

Gas
(used / wanted)
-
+
{{ transaction?.gas_used | number }} / {{ transaction?.gas_wanted | number }}
@@ -111,13 +110,14 @@

Transaction Details

-
+ +

Messages

-
+
Read
diff --git a/src/app/pages/transaction/transaction-detail/transaction-detail.component.scss b/src/app/pages/transaction/transaction-detail/transaction-detail.component.scss index 8a10f0c5e..e726e1e58 100644 --- a/src/app/pages/transaction/transaction-detail/transaction-detail.component.scss +++ b/src/app/pages/transaction/transaction-detail/transaction-detail.component.scss @@ -1,4 +1,4 @@ -@import "../../../../assets/scss/color.scss"; +@import '../../../../assets/scss/color.scss'; .raw-content { white-space: pre-wrap; @@ -10,11 +10,15 @@ } .box-error { - background-color: lightgray; - color: var(--aura-danger); + background-color: var(--aura-gray-9); + color: #e65e5e; border-radius: 10px; padding: 10px 15px; margin-bottom: 1rem; + word-break: break-word; + font-size: 16px; + font-weight: 400; + margin: 0px; } ::ng-deep app-transaction-messages .card-info:not(:last-child) { diff --git a/src/app/pages/transaction/transaction-detail/transaction-detail.component.ts b/src/app/pages/transaction/transaction-detail/transaction-detail.component.ts index 07f70627f..2b6a2fe61 100644 --- a/src/app/pages/transaction/transaction-detail/transaction-detail.component.ts +++ b/src/app/pages/transaction/transaction-detail/transaction-detail.component.ts @@ -1,4 +1,3 @@ -import { Clipboard } from '@angular/cdk/clipboard'; import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout'; import { Component, OnInit } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; @@ -44,6 +43,8 @@ export class TransactionDetailComponent implements OnInit { loading = true; isReload = false; listValidator = []; + seeLess = false; + isDisplayMore = false; constructor( private route: ActivatedRoute, @@ -54,7 +55,6 @@ export class TransactionDetailComponent implements OnInit { private mappingErrorService: MappingErrorService, private environmentService: EnvironmentService, private layout: BreakpointObserver, - private clipboard: Clipboard, private validatorService: ValidatorService, ) {} @@ -68,20 +68,22 @@ export class TransactionDetailComponent implements OnInit { getDetail(): void { if (this.txHash?.length === LENGTH_CHARACTER.TRANSACTION) { - this.transactionService.txsIndexer(1, 0, this.txHash).subscribe( + const payload = { + limit: 1, + hash: this.txHash, + }; + this.transactionService.getListTx(payload).subscribe( (res) => { - const { code, data } = res; - if (code === 200 && data.transactions?.length > 0) { - const txs = convertDataTransaction(data, this.coinInfo); + if (res?.transaction?.length > 0) { + const txs = convertDataTransaction(res, this.coinInfo); this.transaction = txs[0]; this.transaction = { ...this.transaction, chainid: this.chainId, - gas_used: _.get(res?.data.transactions[0], 'tx_response.gas_used'), - gas_wanted: _.get(res?.data.transactions[0], 'tx_response.gas_wanted'), - raw_log: _.get(res?.data.transactions[0], 'tx_response.raw_log'), - type: _.get(res?.data.transactions[0], 'tx_response.tx.body.messages[0].@type'), - tx: _.get(res?.data.transactions[0], 'tx_response'), + gas_used: _.get(res?.transaction[0], 'gas_used'), + gas_wanted: _.get(res?.transaction[0], 'gas_wanted'), + raw_log: _.get(res?.transaction[0], 'data.tx_response.raw_log'), + type: this.transaction.typeOrigin, }; if (this.transaction.raw_log && +this.transaction.code !== CodeTransaction.Success) { @@ -90,6 +92,17 @@ export class TransactionDetailComponent implements OnInit { this.errorMessage, this.transaction.code, ); + + // get height error box + setTimeout(() => { + const lengthChar = document.getElementById('contentError')?.innerText?.length; + const widthContent = document.getElementById('contentError')?.offsetWidth; + + // cal width text/content + if (lengthChar * 6.8 > widthContent * 3) { + this.isDisplayMore = true; + } + }, 500); } this.getListValidator(); @@ -111,9 +124,9 @@ export class TransactionDetailComponent implements OnInit { } getListValidator(): void { - this.validatorService.validators().subscribe((res) => { - if (res.data?.length > 0) { - this.listValidator = res.data; + this.validatorService.getDataValidator(null).subscribe((res) => { + if (res.validator?.length > 0) { + this.listValidator = res.validator; } }); } @@ -121,18 +134,4 @@ export class TransactionDetailComponent implements OnInit { changeType(type: boolean): void { this.isRawData = type; } - - copyData(text: string): void { - var dummy = document.createElement('textarea'); - document.body.appendChild(dummy); - this.clipboard.copy(JSON.stringify(text, null, 2)); - dummy.select(); - document.execCommand('copy'); - document.body.removeChild(dummy); - // fake event click out side copy button - // this event for hidden tooltip - setTimeout(function () { - document.getElementById('popupCopy').click(); - }, 800); - } } diff --git a/src/app/pages/transaction/transaction-detail/transaction-messages/messages-item/messages-item.component.html b/src/app/pages/transaction/transaction-detail/transaction-messages/messages-item/messages-item.component.html index 0d4a6bea8..1fcb7a7ce 100644 --- a/src/app/pages/transaction/transaction-detail/transaction-messages/messages-item/messages-item.component.html +++ b/src/app/pages/transaction/transaction-detail/transaction-messages/messages-item/messages-item.component.html @@ -1,19 +1,30 @@ -
+
{{ label }}
-
+
{{ value }} - - {{ value || dataLink?.data || '-' }} - - - {{ dataLink?.data || value || '-' }} - + + + + + + {{ value || dataLink?.data || '-' }} + + + {{ dataLink?.data || value || '-' }} + + @@ -22,18 +33,17 @@ {{ (value | mask : 'separator.6') || '-' }} - {{ value > 0 ? (value | balanceOf | mask : 'separator.6') : '-' }} + {{ value > 0 ? (value | balanceOf : denom.decimals | mask : 'separator.6') : '-' }} - {{ value | balanceOf | mask : 'separator.6' }}

       
- {{ value | percent : global.formatNumber2Decimal }} + {{ value == '-' ? value : (value | percent : global.formatNumber2Decimal) }} {{ value || '-' }} - {{ denom }}{{ denom?.display }}
diff --git a/src/app/pages/transaction/transaction-detail/transaction-messages/messages-item/messages-item.component.ts b/src/app/pages/transaction/transaction-detail/transaction-messages/messages-item/messages-item.component.ts index 68e1f3796..cc84fba7f 100644 --- a/src/app/pages/transaction/transaction-detail/transaction-messages/messages-item/messages-item.component.ts +++ b/src/app/pages/transaction/transaction-detail/transaction-messages/messages-item/messages-item.component.ts @@ -13,7 +13,7 @@ export class MessagesItemComponent implements OnInit { @Input() label: string; @Input() value: any; @Input() dataLink: any; - @Input() denom: string = ''; + @Input() denom: any = { display: null, decimal: 6 }; @Input() pipeType: string = ''; pipeTypeData = pipeTypeData; diff --git a/src/app/pages/transaction/transaction-detail/transaction-messages/transaction-messages.component.html b/src/app/pages/transaction/transaction-detail/transaction-messages/transaction-messages.component.html index 0369cc71e..e2010c779 100644 --- a/src/app/pages/transaction/transaction-detail/transaction-messages/transaction-messages.component.html +++ b/src/app/pages/transaction/transaction-detail/transaction-messages/transaction-messages.component.html @@ -1,73 +1,77 @@ -

- Messages -
-

-
+
{{ checkTypeMessage() }} - + -
- +
+ - - - - -
-
-
Byte Code
-
-
- {{ item?.value }} -
-
- See More -
-
- See Less + "> + + + + +
+
+
Byte Code
+
+
+ {{ item?.value }} +
+
+ See More +
+
+ See Less +
-
+
+ + +
+ - - -
-
Message
-
-

+              
+                
+
Message
+
+

+                  
-
- + +
@@ -75,36 +79,44 @@

-
- - - -
- - -
-
- - -
-
- - -
-
- - -
-
- - - -
-
- - -
-
+
+
+ + + +
+ + + +
+
+ + + +
+
+ + +
+
+ + +
+
+ + + +
+
+ + +
+
+ + +
@@ -112,10 +124,18 @@

-
-
Message
-
-

+      
+
+
+
Message
+
+

+            
+
+ +
@@ -126,7 +146,7 @@

+ [dataLink]="{ url: '/account', nameTag: true }"> -
+
Amount
{{ transactionDetail?.tx?.tx?.body?.messages[0]?.token?.amount | balanceOf | mask : 'separator.6' }} - {{ commonService.mappingNameIBC(transactionDetail?.tx?.tx?.body?.messages[0]?.token?.denom) }} + {{ + transactionDetail?.tx?.tx?.body?.messages[0]?.token?.denom | convertLogAmount : true + }}
{{ getDataIBC(ibcListMapping.Receive) }} -
+
Amount
{{ ibcData?.amount | balanceOf | mask : 'separator.6' }} @@ -169,19 +191,19 @@

[label]="'Origin Amount'" [value]="ibcData?.amount" [pipeType]="pipeTypeData.Number"> - + + [value]="ibcData?.update_client?.signer || transactionDetail.messages[0].signer" + [dataLink]="{ url: '/account', nameTag: true }"> + [dataLink]="{ url: '/account', nameTag: true }"> @@ -190,9 +212,9 @@

{{ getDataIBC(ibcListMapping.Ack) }} -
+
Amount
{{ ibcData?.acknowledgement?.amount | balanceOf | mask : 'separator.6' }} @@ -208,7 +230,7 @@

+ [dataLink]="{ url: '/account', nameTag: true }"> @@ -216,7 +238,7 @@

+ [dataLink]="{ url: '/account', nameTag: true }"> @@ -224,13 +246,13 @@

{{ getDataIBC(ibcListMapping.TimeOut, index) }} -
+
Data
       [value]="ibcData?.time_out[index - 1]?.proof_height?.revision_height">
     
+      [value]="getLongValue(ibcData?.time_out[index - 1]?.next_sequence_recv)">
     
+      [dataLink]="{ url: '/account', nameTag: true }">
   
 
   
-    
+    
     
     
   
     
   
 
   
     
-
-
+
+
IBC Progress
-
{{ denomIBC ? commonService.mappingNameIBC(denomIBC) : item.denom }}
+
+ {{ (denomIBC ? (denomIBC | convertLogAmount : true) : item.denom) | cutStringPipe : 16 : 16 }} +
@@ -397,36 +424,85 @@

- -
- - - -
-
Amount
-
- {{ item?.coins[0]?.amount | balanceOf | mask : 'separator.6' }} - {{ denom }} + + + + + +
+
Event Log
+
+ Show all events +
+ +
+ {{ element.events.type }} + + + +
+ {{ item.type }} +
+
+ +
+ +
+ +
+ {{ data.key }} + + {{ data.value }} + +
+
+
+
+
+
-
- -
+
@@ -437,7 +513,7 @@

-
+
diff --git a/src/app/pages/transaction/transaction-detail/transaction-messages/transaction-messages.component.scss b/src/app/pages/transaction/transaction-detail/transaction-messages/transaction-messages.component.scss index 9a5a17cfd..f550709a6 100644 --- a/src/app/pages/transaction/transaction-detail/transaction-messages/transaction-messages.component.scss +++ b/src/app/pages/transaction/transaction-detail/transaction-messages/transaction-messages.component.scss @@ -1,5 +1,8 @@ @import '../../../../../assets/scss/color.scss'; +::-webkit-scrollbar { + height: 4px; +} .msg-image { width: auto; height: 24px; @@ -35,7 +38,7 @@ } .divider-lighter { - background-color: var(--aura-gray-5); + background-color: var(--aura-gray-6); max-height: 8px; } @@ -69,3 +72,134 @@ overflow: hidden; text-overflow: ellipsis; } + +.box-multisend { + .card-text { + padding-bottom: var(--spacer-3); + border-bottom: 1px solid var(--aura-gray-8); + } + .body-multisend { + max-height: 440px; + overflow-y: scroll; + .txt-label { + min-width: 75px; + } + .txt-address { + min-width: 365px; + } + .txt-amount { + min-width: 100px; + display: flex; + align-items: center; + text-align: right; + } + ::-webkit-scrollbar { + width: 8px; + } + } + + @media (max-width: 1366px) { + overflow-y: scroll; + } +} + +.card-info { + background-color: var(--aura-gray-10); +} + +.box-event-log { + background-color: var(--aura-gray-9); + border-radius: 8px; + padding-left: calc(var(--bs-gutter-x) * 0.5); + overflow-y: auto; + .item-event-log:not(:last-child) { + margin-bottom: var(--spacer-7); + } + .txt-event-key { + color: var(--aura-gray-4); + } +} + +.content-log { + position: relative; + &::before { + content: ''; + position: absolute; + left: 2.15px; + top: 0; + bottom: 10px; + width: 2px; + border-right: 2.5px dashed gray; + } + &::after { + content: ''; + position: absolute; + left: -5px; + bottom: -1px; + width: 0; + height: 0; + border-left: 8px solid transparent; + border-right: 8px solid transparent; + border-top: 10px solid gray; + border-radius: 3px; + } +} +mat-expansion-panel:last-child .mat-expansion-panel-content .content-log { + &::before { + bottom: 4px; + } + &::after { + content: unset; + } +} +.mat-slide-toggle-bar { + height: 20px !important; + border-radius: 12px !important; +} +.mat-slide-toggle-thumb-container { + width: 14px !important; + height: 14px !important; + top: 3px !important; + transform: translate3d(4px, 0, 0) !important; +} +.mat-slide-toggle.mat-checked .mat-slide-toggle-thumb-container { + transform: translate3d(18px, 0, 0) !important; +} + +.mat-slide-toggle-thumb { + width: 14px !important; + height: 14px !important; +} +.mat-slide-toggle.mat-checked .mat-slide-toggle-bar { + background-color: #2BBBA3; +} + +.mat-slide-toggle.mat-checked .mat-slide-toggle-thumb{ + background-color: var(--aura-white); +} + +.mat-expansion-panel { + background: none; + box-shadow: none !important; + mat-expansion-panel-header { + padding: 0 12px; + .mat-expanded { + height: 48px; + } + .txt-header::after { + font-family: 'Font Awesome 5 Free'; + font-weight: 700; + content: '\f078'; + color: var(--aura-gray-1); + font-size: 13px; + } + &[aria-expanded='true'] { + .txt-header::after { + content: '\f077'; + } + } + } + .mat-expansion-panel-header.mat-expanded { + height: 48px; + } +} diff --git a/src/app/pages/transaction/transaction-detail/transaction-messages/transaction-messages.component.ts b/src/app/pages/transaction/transaction-detail/transaction-messages/transaction-messages.component.ts index 915c59644..9e03b3eda 100644 --- a/src/app/pages/transaction/transaction-detail/transaction-messages/transaction-messages.component.ts +++ b/src/app/pages/transaction/transaction-detail/transaction-messages/transaction-messages.component.ts @@ -1,18 +1,24 @@ +import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout'; import { DatePipe } from '@angular/common'; import { Component, Input, OnInit, ViewEncapsulation } from '@angular/core'; +import * as _ from 'lodash'; +import * as Long from 'long'; import { EnvironmentService } from 'src/app/core/data-services/environment.service'; +import { CommonService } from 'src/app/core/services/common.service'; +import { ProposalService } from 'src/app/core/services/proposal.service'; +import { TransactionService } from 'src/app/core/services/transaction.service'; import { balanceOf } from 'src/app/core/utils/common/parsing'; import { DATEFORMAT } from '../../../../core/constants/common.constant'; import { PROPOSAL_VOTE } from '../../../../core/constants/proposal.constant'; import { TYPE_TRANSACTION } from '../../../../core/constants/transaction.constant'; -import { pipeTypeData, TRANSACTION_TYPE_ENUM, TypeTransaction } from '../../../../core/constants/transaction.enum'; -import { getAmount, Globals } from '../../../../global/global'; -import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout'; -import { CommonService } from 'src/app/core/services/common.service'; -import { TransactionService } from 'src/app/core/services/transaction.service'; -import * as _ from 'lodash'; +import { + CodeTransaction, + TRANSACTION_TYPE_ENUM, + TypeTransaction, + pipeTypeData, +} from '../../../../core/constants/transaction.enum'; import { formatWithSchema } from '../../../../core/helpers/date'; -import { ProposalService } from 'src/app/core/services/proposal.service'; +import { Globals, getAmount } from '../../../../global/global'; @Component({ selector: 'app-transaction-messages', @@ -52,7 +58,6 @@ export class TransactionMessagesComponent implements OnInit { Ack: 'acknowledge_packet', TimeOut: 'timeout_packet', }; - numberListSend = 5; spendLimitAmount = 0; typeGrantAllowance = 'Basic'; denomIBC = ''; @@ -65,9 +70,15 @@ export class TransactionMessagesComponent implements OnInit { specialCase = { ByteCode: 'ByteCode', MultiSend: 'MultiSend', + EventLog: 'EventLog', }; currentIndex = 0; transactionTypeArr = []; + pipeData = pipeTypeData; + eventLogData = []; + idxLog = 0; + codeTransaction = CodeTransaction; + isDisplay = []; denom = this.environmentService.configValue.chain_info.currencies[0].coinDenom; coinMinimalDenom = this.environmentService.configValue.chain_info.currencies[0].coinMinimalDenom; @@ -157,20 +168,28 @@ export class TransactionMessagesComponent implements OnInit { if (this.currentIndex !== index) { return; } - this.currentIndex++; let result = []; const typeTrans = this.typeTransaction.find((f) => f.label.toLowerCase() === data['@type'].toLowerCase()); this.transactionTypeArr.push(typeTrans?.value || data['@type'].split('.').pop()); const denom = data?.amount?.length > 0 ? data?.amount[0]?.denom : this.denom; + let dataDenom = this.commonService.mappingNameIBC(denom); switch (data['@type']) { case this.eTransType.Send: - result.push({ key: 'From Address', value: data?.from_address, link: { url: '/account' } }); - result.push({ key: 'To Address', value: data?.to_address, link: { url: '/account' } }); + result.push({ + key: 'From Address', + value: this.commonService.setNameTag(data?.from_address), + link: { url: '/account', data: data?.from_address, nameTag: true }, + }); + result.push({ + key: 'To Address', + value: this.commonService.setNameTag(data?.to_address), + link: { url: '/account', data: data?.to_address, nameTag: true }, + }); result.push({ key: 'Amount', value: data?.amount[0]?.amount, - denom: this.commonService.mappingNameIBC(denom), + denom: dataDenom, pipeType: pipeTypeData.BalanceOf, }); break; @@ -185,13 +204,13 @@ export class TransactionMessagesComponent implements OnInit { this.checkGetReward(); result.push({ key: 'Delegator Address', - value: data?.delegator_address, - link: { url: '/account' }, + value: this.commonService.setNameTag(data?.delegator_address), + link: { url: '/account', data: data?.delegator_address, nameTag: true }, }); result.push({ key: 'Validator Address', value: `${data?.validator_address} (${this.getNameValidator(data?.validator_address)})`, - link: { url: '/validators', data: data?.validator_address }, + link: { url: '/validators', data: data?.validator_address, nameTag: true }, }); // get amount let amount = data.amount?.amount; @@ -203,7 +222,7 @@ export class TransactionMessagesComponent implements OnInit { result.push({ key: 'Amount', value: amount || '-', - denom: amount ? this.denom : null, + denom: dataDenom, pipeType: pipeType, }); @@ -216,7 +235,7 @@ export class TransactionMessagesComponent implements OnInit { result.push({ key: 'Auto Claim Reward', value: this.listAmountClaim[index], - denom: this.denom, + denom: dataDenom, pipeType: pipeTypeData.Number, }); } @@ -225,117 +244,169 @@ export class TransactionMessagesComponent implements OnInit { case this.eTransType.Redelegate: result.push({ key: 'Delegator Address', - value: data?.delegator_address, - link: { url: '/account' }, + value: this.commonService.setNameTag(data?.delegator_address), + link: { url: '/account', data: data?.delegator_address, nameTag: true }, }); result.push({ key: 'Source Validator Address', value: `${data?.validator_src_address} (${this.getNameValidator(data?.validator_src_address)})`, - link: { url: '/validators', data: data?.validator_src_address }, + link: { url: '/validators', data: data?.validator_src_address, nameTag: true }, }); result.push({ key: 'Destination Validator Address', value: `${data?.validator_dst_address} (${this.getNameValidator(data?.validator_dst_address)})`, - link: { url: '/validators', data: data?.validator_dst_address }, + link: { url: '/validators', data: data?.validator_dst_address, nameTag: true }, }); result.push({ key: 'Amount', value: data.amount?.amount, - denom: this.commonService.mappingNameIBC(denom), + denom: dataDenom, pipeType: pipeTypeData.BalanceOf, }); if (this.amountClaim > 0) { result.push({ key: 'Auto Claim Reward', value: this.amountClaim, - denom: this.commonService.mappingNameIBC(denom), + denom: dataDenom, pipeType: pipeTypeData.Number, }); } break; case this.eTransType.GrantAuthz: - result.push({ key: 'Granter', value: data?.granter, link: { url: '/account' } }); - result.push({ key: 'Grantee', value: data?.grantee, link: { url: '/account' } }); + result.push({ + key: 'Granter', + value: this.commonService.setNameTag(data?.granter), + link: { url: '/account', data: data?.granter, nameTag: true }, + }); + result.push({ + key: 'Grantee', + value: this.commonService.setNameTag(data?.grantee), + link: { url: '/account', data: data?.grantee, nameTag: true }, + }); result.push({ key: 'Authorization Type', value: data?.grant?.authorization?.authorization_type }); result.push({ key: 'Expiration', value: this.getDateValue(data?.grant?.expiration) || '-' }); result.push({ key: 'Limit', value: data?.grant?.authorization?.max_tokens?.amount, - denom: this.denom, + denom: dataDenom, pipeType: pipeTypeData.BalanceOf, }); break; case this.eTransType.ExecuteAuthz: - result.push({ key: 'Grantee', value: data?.grantee, link: { url: '/account' } }); + result.push({ + key: 'Grantee', + value: this.commonService.setNameTag(data?.grantee), + link: { url: '/account', data: data?.grantee, nameTag: true }, + }); result.push({ key: 'Authorization Type', value: data?.msgs[0]['@type'] }); result.push({ key: 'Total Amount Execute', value: this.totalAmountExecute, - denom: this.denom, + denom: dataDenom, pipeType: pipeTypeData.BalanceOf, }); result.push({ key: 'Json', value: data?.msgs, pipeType: pipeTypeData.Json }); break; case this.eTransType.RevokeAuthz: - result.push({ key: 'Granter', value: data?.granter, link: { url: '/account' } }); - result.push({ key: 'Grantee', value: data?.grantee, link: { url: '/account' } }); + result.push({ + key: 'Granter', + value: this.commonService.setNameTag(data?.granter), + link: { url: '/account', data: data?.granter, nameTag: true }, + }); + result.push({ + key: 'Grantee', + value: this.commonService.setNameTag(data?.grantee), + link: { url: '/account', data: data?.grantee, nameTag: true }, + }); result.push({ key: 'Message Type Url', value: data.msg_type_url }); break; case this.eTransType.ExecuteContract: - this.displayMsgRaw(); - result.push({ key: 'Contract', value: data?.contract, link: { url: '/contracts' } }); - result.push({ key: 'Sender', value: data?.sender, link: { url: '/account' } }); + this.displayMsgRaw(index); + result.push({ + key: 'Contract', + value: this.commonService.setNameTag(data?.contract), + link: { url: '/contracts', data: data?.contract, nameTag: true }, + }); + result.push({ + key: 'Sender', + value: this.commonService.setNameTag(data?.sender), + link: { url: '/account', data: data?.sender, nameTag: true }, + }); result.push({ key: 'Messages', value: this.objMsgContract, pipeType: pipeTypeData.Json }); break; case this.eTransType.InstantiateContract: case this.eTransType.InstantiateContract2: - this.displayMsgRaw(); + this.displayMsgRaw(index); result.push({ key: 'Contract', - value: this.getDataJson('_contract_address'), - link: { url: '/contracts' }, + value: this.commonService.setNameTag(this.getDataJson('_contract_address')), + link: { url: '/contracts', data: this.getDataJson('_contract_address'), nameTag: true }, }); result.push({ key: 'Label', value: data?.label }); - result.push({ key: 'Sender', value: data?.sender, link: { url: '/account' } }); + result.push({ + key: 'Sender', + value: this.commonService.setNameTag(data?.sender), + link: { url: '/account', data: data?.sender, nameTag: true }, + }); result.push({ key: 'Messages', value: this.objMsgContract, pipeType: pipeTypeData.Json }); break; case this.eTransType.StoreCode: result.push({ key: 'Sender', - value: data.sender || data.validator_address, - link: { url: '/account' }, + value: this.commonService.setNameTag(data?.sender || data?.validator_address), + link: { url: '/account', data: data?.sender || data?.validator_address, nameTag: true }, }); result.push({ key: 'Code Id', value: this.getStoreCode(index), link: { url: '/code-ids/detail' } }); - result.push({ value: data.wasm_byte_code, specialCase: this.specialCase.ByteCode }); + result.push({ value: data?.wasm_byte_code, specialCase: this.specialCase.ByteCode }); break; case this.eTransType.Vote: - result.push({ key: 'Proposal Id', value: data.proposal_id, link: { url: '/votings' } }); - result.push({ key: 'Voter', value: data.voter, link: { url: '/account' } }); + result.push({ key: 'Proposal Id', value: this.getLongValue(data.proposal_id), link: { url: '/votings' } }); + result.push({ + key: 'Voter', + value: this.commonService.setNameTag(data.voter), + link: { url: '/account', data: data.voter, nameTag: true }, + }); result.push({ key: 'Option', value: this.parsingOptionVote(data?.option) }); break; case this.eTransType.PeriodicVestingAccount: - result.push({ key: 'From Address', value: data.from_address, link: { url: '/account' } }); - result.push({ key: 'To Address', value: data.to_address, link: { url: '/account' } }); + result.push({ + key: 'From Address', + value: this.commonService.setNameTag(data.from_address), + link: { url: '/account', data: data.from_address, nameTag: true }, + }); + result.push({ + key: 'To Address', + value: this.commonService.setNameTag(data.to_address), + link: { url: '/account', data: data.to_address, nameTag: true }, + }); result.push({ key: 'Start Time', value: this.dateVesting }); result.push({ key: 'Vesting Periods', value: data.vesting_periods, pipeType: pipeTypeData.Json }); break; case this.eTransType.Vesting: - result.push({ key: 'From Address', value: data.from_address, link: { url: '/account' } }); - result.push({ key: 'To Address', value: data.to_address, link: { url: '/account' } }); + result.push({ + key: 'From Address', + value: this.commonService.setNameTag(data.from_address), + link: { url: '/account', data: data.from_address, nameTag: true }, + }); + result.push({ + key: 'To Address', + value: this.commonService.setNameTag(data.to_address), + link: { url: '/account', data: data.to_address, nameTag: true }, + }); result.push({ key: 'Vesting Schedule', value: this.dateVesting }); break; case this.eTransType.EditValidator: - result.push({ key: 'Validator Address', value: data.validator_address, link: { url: '/account' } }); + result.push({ key: 'Validator Address', value: data.validator_address, link: { url: '/validators' } }); result.push({ key: 'Details', value: data.description?.details }); result.push({ key: 'Moniker', value: data.description?.moniker }); result.push({ @@ -347,13 +418,13 @@ export class TransactionMessagesComponent implements OnInit { result.push({ key: 'Identity', value: data.description?.identity }); result.push({ key: 'Commission Rate', - value: this.checkRateFloatNumber(data?.commission_rate) || 0, + value: this.checkRateFloatNumber(data?.commission_rate) || '-', pipeType: pipeTypeData.Percent, }); result.push({ key: 'Min Self Delegation', value: data.min_self_delegation, - denom: data.min_self_delegation > 0 ? this.denom : null, + denom: data.min_self_delegation > 0 ? { display: this.denom } : null, pipeType: pipeTypeData.BalanceOf, }); break; @@ -362,15 +433,19 @@ export class TransactionMessagesComponent implements OnInit { result.push({ key: 'Min Self Delegation', value: data.min_self_delegation, - denom: data.min_self_delegation > 0 ? this.denom : null, + denom: data.min_self_delegation > 0 ? { display: this.denom } : null, pipeType: pipeTypeData.BalanceOf, }); - result.push({ key: 'Delegator Address', value: data.delegator_address, link: { url: '/account' } }); - result.push({ key: 'Validator Address', value: data.validator_address, link: { url: '/validators'} }); + result.push({ + key: 'Delegator Address', + value: this.commonService.setNameTag(data.delegator_address), + link: { url: '/account', data: data.delegator_address, nameTag: true }, + }); + result.push({ key: 'Validator Address', value: data.validator_address, link: { url: '/validators' } }); result.push({ key: 'Amount', value: data.value?.amount, - denom: this.denom, + denom: dataDenom, pipeType: pipeTypeData.BalanceOf, }); result.push({ key: 'Details', value: data.description?.details }); @@ -383,17 +458,17 @@ export class TransactionMessagesComponent implements OnInit { result.push({ key: 'Identity', value: data.description?.identity }); result.push({ key: 'Commission Rate', - value: this.checkRateFloatNumber(data?.commission?.rate) || 0, + value: this.checkRateFloatNumber(data?.commission?.rate) || '-', pipeType: pipeTypeData.Percent, }); result.push({ key: 'Commission Max Rate', - value: this.checkRateFloatNumber(data?.commission?.max_rate) || 0, + value: this.checkRateFloatNumber(data?.commission?.max_rate) || '-', pipeType: pipeTypeData.Percent, }); result.push({ key: 'Commission Max Change Rate', - value: this.checkRateFloatNumber(data?.commission?.max_change_rate) || 0, + value: this.checkRateFloatNumber(data?.commission?.max_change_rate) || '-', pipeType: pipeTypeData.Percent, }); result.push({ key: 'Public Key', value: data?.pubkey?.value || data?.pubkey?.key }); @@ -403,7 +478,7 @@ export class TransactionMessagesComponent implements OnInit { result.push({ key: 'Validator Address', value: this.transactionDetail?.tx?.tx?.body?.messages[0]?.validator_addr, - link: { url: '/account' }, + link: { url: '/validators' }, }); break; @@ -412,13 +487,17 @@ export class TransactionMessagesComponent implements OnInit { key: 'Amount', value: data.initial_deposit[0].amount, pipeType: pipeTypeData.BalanceOf, - denom: data.initial_deposit[0].amount > 0 ? this.denom : null, + denom: data.initial_deposit[0].amount > 0 ? { display: this.denom } : null, + }); + result.push({ + key: 'Proposer', + value: this.commonService.setNameTag(data.proposer), + link: { url: '/account', data: data.proposer, nameTag: true }, }); - result.push({ key: 'Proposer', value: data.proposer, link: { url: '/account' } }); if (this.transactionDetail?.tx?.logs?.length > 0) { result.push({ key: 'Proposal Id', - value: this.transactionDetail?.tx?.logs[0].events[4].attributes[0].value, + value: this.getLongValue(this.transactionDetail?.tx?.logs[0].events[4].attributes[0].value), link: { url: '/votings' }, }); result.push({ @@ -430,14 +509,22 @@ export class TransactionMessagesComponent implements OnInit { break; case this.eTransType.MsgGrantAllowance: - result.push({ key: 'Granter', value: data.granter, link: { url: '/account' } }); - result.push({ key: 'Grantee', value: data.grantee, link: { url: '/account' } }); + result.push({ + key: 'Granter', + value: this.commonService.setNameTag(data.granter), + link: { url: '/account', data: data.granter, nameTag: true }, + }); + result.push({ + key: 'Grantee', + value: this.commonService.setNameTag(data.grantee), + link: { url: '/account', data: data.grantee, nameTag: true }, + }); result.push({ key: 'Type', value: this.typeGrantAllowance }); result.push({ key: 'Spend Limit', value: this.spendLimitAmount, pipeType: pipeTypeData.BalanceOf, - denom: this.spendLimitAmount > 0 ? this.denom : null, + denom: this.spendLimitAmount > 0 ? { display: this.denom } : null, }); result.push({ key: 'Expiration', @@ -460,7 +547,7 @@ export class TransactionMessagesComponent implements OnInit { data?.allowance?.period_spend_limit[0].amount || 0, pipeType: pipeTypeData.BalanceOf, - denom: this.denom, + denom: dataDenom, }); result.push({ key: 'Period', @@ -476,41 +563,69 @@ export class TransactionMessagesComponent implements OnInit { break; case this.eTransType.MsgRevokeAllowance: - result.push({ key: 'Granter', value: data.granter, link: { url: '/account' } }); - result.push({ key: 'Grantee', value: data.grantee, link: { url: '/account' } }); + result.push({ + key: 'Granter', + value: this.commonService.setNameTag(data.granter), + link: { url: '/account', data: data.granter, nameTag: true }, + }); + result.push({ + key: 'Grantee', + value: this.commonService.setNameTag(data.grantee), + link: { url: '/account', data: data.grantee, nameTag: true }, + }); break; case this.eTransType.Deposit: - result.push({ key: 'Proposal Id', value: data.proposal_id, link: { url: '/votings' } }); - result.push({ key: 'Depositor', value: data.depositor, link: { url: '/account' } }); + result.push({ key: 'Proposal Id', value: this.getLongValue(data.proposal_id), link: { url: '/votings' } }); + result.push({ + key: 'Depositor', + value: this.commonService.setNameTag(data.depositor), + link: { url: '/account', data: data.depositor, nameTag: true }, + }); result.push({ key: 'Amount', value: data?.amount[0]?.amount, - denom: this.commonService.mappingNameIBC(denom), + denom: dataDenom, pipeType: pipeTypeData.BalanceOf, }); break; case this.eTransType.Deposit: - result.push({ key: 'Proposal Id', value: data.proposal_id, link: { url: '/votings' } }); - result.push({ key: 'Depositor', value: data.depositor, link: { url: '/account' } }); + result.push({ key: 'Proposal Id', value: this.getLongValue(data.proposal_id), link: { url: '/votings' } }); + result.push({ + key: 'Depositor', + value: this.commonService.setNameTag(data.depositor), + link: { url: '/account', data: data.depositor, nameTag: true }, + }); result.push({ key: 'Amount', value: data?.amount[0]?.amount, - denom: this.commonService.mappingNameIBC(denom), + denom: dataDenom, pipeType: pipeTypeData.BalanceOf, }); break; case this.eTransType.MsgMigrateContract: - result.push({ key: 'Sender', value: data.sender, link: { url: '/account' } }); + result.push({ + key: 'Sender', + value: this.commonService.setNameTag(data.sender), + link: { url: '/account', data: data.sender, nameTag: true }, + }); result.push({ key: 'Contract', value: data.contract, link: { url: '/contracts' } }); result.push({ key: 'Code ID', value: data.code_id, link: { url: '/code-ids/detail' } }); break; case this.eTransType.ModifyWithdrawAddress: - result.push({ key: 'Delegator Address', value: data.delegator_address, link: { url: '/account' } }); - result.push({ key: 'Withdraw Address', value: data.withdraw_address, link: { url: '/account' } }); + result.push({ + key: 'Delegator Address', + value: this.commonService.setNameTag(data.delegator_address), + link: { url: '/account', data: data.delegator_address, nameTag: true }, + }); + result.push({ + key: 'Withdraw Address', + value: this.commonService.setNameTag(data.withdraw_address), + link: { url: '/account', data: data.withdraw_address, nameTag: true }, + }); break; case this.eTransType.GetRewardCommission: @@ -524,7 +639,7 @@ export class TransactionMessagesComponent implements OnInit { result.push({ key: 'Amount', value: this.commissionAutoClaim, - denom: this.denom, + denom: dataDenom, pipeType: pipeTypeData.Number, }); } @@ -540,13 +655,23 @@ export class TransactionMessagesComponent implements OnInit { default: break; } + + if (this.transactionDetail.code === CodeTransaction.Success) { + result.push({ + key: 'Event Log', + value: this.transactionDetail?.tx?.logs, + specialCase: this.specialCase.EventLog, + }); + } + this.currentData.push(result); + this.currentIndex++; }); } getNameValidator(address) { const validatorSrcAddress = this.listValidator?.find((f) => f.operator_address === address); - return validatorSrcAddress?.title || ''; + return validatorSrcAddress?.description?.moniker || ''; } checkGetReward(): void { @@ -618,28 +743,42 @@ export class TransactionMessagesComponent implements OnInit { } catch (e) {} } - displayMsgRaw(): void { - this.objMsgContract = _.get(this.transactionDetail.tx.tx.body, 'messages').map((element) => { - let msg = _.get(element, 'msg'); - //get type mint don't type token id - if (!msg && this.transactionDetail?.raw_log.indexOf('mint') >= 0) { + displayMsgRaw(idx = 0): void { + let msgs = _.get( + this.transactionDetail?.tx?.tx?.body || this.transactionDetail?.tx?.body || this.transactionDetail, + 'messages', + ); + msgs?.forEach((element, index) => { + if (idx === index) { + let msg = _.get(element, 'msg'); try { - const jsonData = JSON.parse(this.transactionDetail?.raw_log); - if (jsonData && jsonData[0]) { - const data = jsonData[0]?.events[jsonData[0]?.events?.length - 1]?.attributes; - let tokenId = data.find((k) => k.key === 'token_id')?.value || null; - msg = { mint: { token_id: tokenId || null } }; + if (typeof msg !== 'object' && msg !== null) { + msg = JSON.parse(msg); + } + } catch {} + + //get type mint don't type token id + if (!msg && this.transactionDetail?.raw_log.indexOf('mint') >= 0) { + try { + const jsonData = JSON.parse(this.transactionDetail?.raw_log); + if (jsonData && jsonData[0]) { + const data = jsonData[0]?.events[jsonData[0]?.events?.length - 1]?.attributes; + let tokenId = data.find((k) => k.key === 'token_id')?.value || null; + msg = { mint: { token_id: tokenId || null } }; + } + } catch (e) { + msg = { mint: { token_id: null } }; } - } catch (e) { - msg = { mint: { token_id: null } }; } + const funds = _.get(element, 'funds'); + let result = { msg, funds }; + this.objMsgContract = result; + return; } - const funds = _.get(element, 'funds'); - return { msg, funds }; }); //get first data if array = 1 - if (this.objMsgContract.length === 1) { + if (this.objMsgContract?.length === 1) { this.objMsgContract = this.objMsgContract[0]; } } @@ -690,7 +829,6 @@ export class TransactionMessagesComponent implements OnInit { this.ibcData['time_out'] = this.transactionDetail?.tx?.tx?.body?.messages.filter( (k) => k['@type'] === TRANSACTION_TYPE_ENUM.IBCTimeout, ); - this.ibcData['update_client'] = this.transactionDetail?.tx?.tx?.body?.messages.find( (k) => k['@type'] === TRANSACTION_TYPE_ENUM.IBCUpdateClient, ); @@ -717,17 +855,20 @@ export class TransactionMessagesComponent implements OnInit { } if (this.ibcData['acknowledgement']) { + let data; try { let dataEncode = atob(this.ibcData['acknowledgement']?.packet?.data); - const data = JSON.parse(dataEncode); - this.ibcData['acknowledgement'] = { - ...this.ibcData['acknowledgement'], - amount: data.amount, - denom: data.denom, - receiver: data.receiver, - sender: data.sender, - }; - } catch (e) {} + data = JSON.parse(dataEncode); + } catch (e) { + data = this.ibcData['acknowledgement']?.packet?.data; + } + this.ibcData['acknowledgement'] = { + ...this.ibcData['acknowledgement'], + amount: data.amount, + denom: data.denom, + receiver: data.receiver, + sender: data.sender, + }; } if (this.ibcData['receive']) { @@ -735,8 +876,12 @@ export class TransactionMessagesComponent implements OnInit { this.transactionDetail.tx.logs.forEach((element) => { data = element.events.find((k) => k['type'] === this.typeGetData.Transfer); }); - let temp = data?.attributes.find((j) => j['key'] === 'amount')?.value; - this.ibcData['receive']['denom'] = this.commonService.mappingNameIBC(temp) || ''; + let result = data?.attributes.find((j) => j['key'] === 'amount')?.value; + if (!result.startsWith('ibc')) { + result = result?.replace(result?.match(/\d+/g)[0], ''); + } + this.ibcData['receive']['denomOrigin'] = result; + this.ibcData['receive']['denom'] = this.commonService.mappingNameIBC(result)['display'] || ''; this.ibcData['typeProgress'] = this.eTransType.IBCReceived; } } @@ -748,19 +893,18 @@ export class TransactionMessagesComponent implements OnInit { if (!sequence) { return; } - this.transactionService.getListIBCSequence(sequence).subscribe((res) => { - const { code, data } = res; - if (code === 200) { + this.transactionService.getListIBCSequence(sequence, this.ibcData?.packet_src_channel).subscribe((res) => { + if (res?.transaction?.length > 0) { let typeTx; this.listIBCProgress = []; - let txs = _.get(data, 'transactions').map((element) => { - const code = _.get(element, 'tx_response.code'); - const tx_hash = _.get(element, 'tx_response.txhash'); - const time = _.get(element, 'tx_response.timestamp'); + let txs = _.get(res, 'transaction').map((element) => { + const code = _.get(element, 'data.tx_response.code'); + const tx_hash = _.get(element, 'data.tx_response.txhash'); + const time = _.get(element, 'data.tx_response.timestamp'); const effected = _.get(element, 'indexes.fungible_token_packet_success')?.length > 0 ? 1 : 0; - typeTx = _.get(element, 'tx_response.tx.body.messages[0].@type'); - const lstType = _.get(element, 'tx_response.tx.body.messages'); + typeTx = _.get(element, 'data.tx.body.messages[0].@type'); + const lstType = _.get(element, 'data.tx.body.messages'); if (lstType?.length > 0) { lstType.forEach((type) => { if (type['@type'] !== TRANSACTION_TYPE_ENUM.IBCUpdateClient) { @@ -770,13 +914,13 @@ export class TransactionMessagesComponent implements OnInit { }); } - let temp = _.get(element, 'tx_response.tx.auth_info.fee.amount[0].denom') || this.coinMinimalDenom; + let temp = _.get(element, 'data.tx.auth_info.fee.amount[0].denom') || this.coinMinimalDenom; const denom = temp === this.coinMinimalDenom ? this.denom : temp; return { code, tx_hash, typeTx, denom, time, effected }; }); if (this.ibcData['typeProgress'] === this.eTransType.IBCReceived) { txs = txs.filter((k) => k.typeTx === this.eTransType.IBCReceived); - this.denomIBC = data.transactions[0].indexes.denomination_trace_denom[0]; + this.denomIBC = res.transaction[0]?.event_attributes[0]?.value; } else { txs = txs.filter((k) => k.typeTx !== this.eTransType.IBCReceived); this.denomIBC = this.transactionDetail?.tx?.tx?.body?.messages[0]?.token?.denom; @@ -809,10 +953,6 @@ export class TransactionMessagesComponent implements OnInit { return typeTrans?.value; } - loadMoreSend() { - this.numberListSend += 5; - } - getDataJson(key) { try { const jsonData = JSON.parse(this.transactionDetail?.raw_log); @@ -838,12 +978,29 @@ export class TransactionMessagesComponent implements OnInit { } checkRateFloatNumber(value) { - const temp = value / Math.pow(10, 18); - let tempPercent = temp * 100; - //check is int value - if (Number(tempPercent) === tempPercent && tempPercent % 1 === 0) { - value = temp; + if (!!value) { + const temp = value / Math.pow(10, 18); + let tempPercent = temp * 100; + //check is int value + if (Number(tempPercent) === tempPercent && tempPercent % 1 === 0) { + value = temp; + } + return value; + } + return '-'; + } + + getLongValue(value) { + if (value) { + const longProposalId = Long.fromValue(value); + if (Long.isLong(longProposalId)) { + value = longProposalId.toString(); + } } return value; } + + changeShowData(idx) { + this.isDisplay[idx] = !this.isDisplay[idx]; + } } diff --git a/src/app/pages/transaction/transaction.component.html b/src/app/pages/transaction/transaction.component.html index 733b10362..221182596 100644 --- a/src/app/pages/transaction/transaction.component.html +++ b/src/app/pages/transaction/transaction.component.html @@ -24,7 +24,7 @@ *ngSwitchCase="'tx_hash'" class="text--primary cursor-pointer hash-link" [routerLink]="['/transaction', data['tx_hash']]"> - {{ data[template.matColumnDef] | cutStringPipe: 8:8 }} + {{ data[template.matColumnDef] | cutStringPipe : 8 : 8 }}

- {{ +data[template.matColumnDef] | mask: 'separator.6' }} + {{ +data[template.matColumnDef] | mask : 'separator.6' }} {{ denom }}
-
{{ data[template.matColumnDef] }}
@@ -98,14 +83,6 @@ status: data.code }" [content]="[ - { - label: 'Amount', - class: 'body-01-mob text--gray-1', - info: - data.amount > 0 - ? (+data.amount | mask: 'separator.6') + ' ' + commonService.mappingNameIBC(data?.denom) + '' - : checkAmountValue(data.amount, data.tx_hash) - }, { label: 'Fee', class: 'body-01-mob text--gray-1', diff --git a/src/app/pages/transaction/transaction.component.ts b/src/app/pages/transaction/transaction.component.ts index 90e602489..a0cb59f45 100644 --- a/src/app/pages/transaction/transaction.component.ts +++ b/src/app/pages/transaction/transaction.component.ts @@ -5,7 +5,7 @@ import { TYPE_TRANSACTION } from '../../../app/core/constants/transaction.consta import { TableTemplate } from '../../../app/core/models/common.model'; import { CommonService } from '../../../app/core/services/common.service'; import { TransactionService } from '../../../app/core/services/transaction.service'; -import { convertDataTransaction, Globals } from '../../../app/global/global'; +import { Globals, convertDataTransaction } from '../../../app/global/global'; @Component({ selector: 'app-transaction', @@ -17,7 +17,6 @@ export class TransactionComponent implements OnInit { { matColumnDef: 'tx_hash', headerCellDef: 'Tx Hash' }, { matColumnDef: 'type', headerCellDef: 'Type' }, { matColumnDef: 'status', headerCellDef: 'Result' }, - { matColumnDef: 'amount', headerCellDef: 'Amount' }, { matColumnDef: 'fee', headerCellDef: 'Fee' }, { matColumnDef: 'height', headerCellDef: 'Height' }, { matColumnDef: 'timestamp', headerCellDef: 'Time' }, @@ -41,15 +40,17 @@ export class TransactionComponent implements OnInit { ) {} ngOnInit(): void { - this.getList(); + this.getListTx(); } - getList(): void { - this.transactionService.txsIndexer(this.pageSize, 0).subscribe( + getListTx(): void { + const payload = { + limit: this.pageSize, + } + this.transactionService.getListTx(payload).subscribe( (res) => { - const { code, data } = res; - if (code === 200) { - const txs = convertDataTransaction(data, this.coinInfo); + if (res?.transaction?.length > 0) { + const txs = convertDataTransaction(res, this.coinInfo); if (this.dataSource.data.length > 0) { this.dataSource.data = [...this.dataSource.data, ...txs]; } else { diff --git a/src/app/pages/transaction/transaction.module.ts b/src/app/pages/transaction/transaction.module.ts index c6ad043a4..09c08e222 100644 --- a/src/app/pages/transaction/transaction.module.ts +++ b/src/app/pages/transaction/transaction.module.ts @@ -1,8 +1,14 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { NgbNavModule } from '@ng-bootstrap/ng-bootstrap'; import { TranslateModule } from '@ngx-translate/core'; -import { NgxMaskModule } from 'ngx-mask'; +import { NgxJsonViewerModule } from 'ngx-json-viewer'; +import { MaskPipe, NgxMaskModule } from 'ngx-mask'; +import { CommonDirectiveModule } from 'src/app/core/directives/common-directive.module'; +import { ProposalService } from 'src/app/core/services/proposal.service'; +import { NameTagModule } from 'src/app/shared/components/name-tag/name-tag.module'; +import { TooltipCustomizeModule } from 'src/app/shared/components/tooltip-customize/tooltip-customize.module'; import { MaterialModule } from '../../../app/app.module'; import { CommonPipeModule } from '../../../app/core/pipes/common-pipe.module'; import { MappingErrorService } from '../../../app/core/services/mapping-error.service'; @@ -10,13 +16,11 @@ import { TransactionService } from '../../../app/core/services/transaction.servi import { SharedModule } from '../../../app/shared/shared.module'; import { TableNoDataModule } from '../../shared/components/table-no-data/table-no-data.module'; import { TransactionDetailComponent } from './transaction-detail/transaction-detail.component'; +import { MessagesItemComponent } from './transaction-detail/transaction-messages/messages-item/messages-item.component'; import { TransactionMessagesComponent } from './transaction-detail/transaction-messages/transaction-messages.component'; import { TransactionRoutingModule } from './transaction-routing.module'; import { TransactionComponent } from './transaction.component'; -import { NgbNavModule } from '@ng-bootstrap/ng-bootstrap'; -import { MessagesItemComponent } from './transaction-detail/transaction-messages/messages-item/messages-item.component'; -import {NgxJsonViewerModule} from "ngx-json-viewer"; -import { ProposalService } from 'src/app/core/services/proposal.service'; +import {ClipboardModule} from '@angular/cdk/clipboard'; @NgModule({ declarations: [TransactionComponent, TransactionDetailComponent, TransactionMessagesComponent, MessagesItemComponent], @@ -34,7 +38,11 @@ import { ProposalService } from 'src/app/core/services/proposal.service'; CommonPipeModule, NgbNavModule, NgxJsonViewerModule, + CommonDirectiveModule, + NameTagModule, + TooltipCustomizeModule, + ClipboardModule ], - providers: [TransactionService, MappingErrorService, ProposalService], + providers: [TransactionService, MappingErrorService, ProposalService, MaskPipe], }) export class TransactionModule {} diff --git a/src/app/pages/validators/user-wallet-info/user-wallet-info.component.html b/src/app/pages/validators/user-wallet-info/user-wallet-info.component.html index a9aa42fce..02fea01a5 100644 --- a/src/app/pages/validators/user-wallet-info/user-wallet-info.component.html +++ b/src/app/pages/validators/user-wallet-info/user-wallet-info.component.html @@ -1,5 +1,5 @@ -
+
@@ -7,14 +7,14 @@
Available Balance:
- + {{ denom }}
Total Staked:
- + {{ denom }}
diff --git a/src/app/pages/validators/user-wallet-info/user-wallet-info.component.ts b/src/app/pages/validators/user-wallet-info/user-wallet-info.component.ts index 105eb9cc7..1b1fd6c48 100644 --- a/src/app/pages/validators/user-wallet-info/user-wallet-info.component.ts +++ b/src/app/pages/validators/user-wallet-info/user-wallet-info.component.ts @@ -1,8 +1,7 @@ -import { ChangeDetectorRef, Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core'; +import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core'; import { MatTableDataSource } from '@angular/material/table'; -import { DataDelegateDto, TableTemplate } from 'src/app/core/models/common.model'; +import { TableTemplate } from 'src/app/core/models/common.model'; import { CommonService } from 'src/app/core/services/common.service'; -import { ValidatorService } from 'src/app/core/services/validator.service'; import { Globals } from 'src/app/global/global'; @Component({ @@ -13,9 +12,9 @@ import { Globals } from 'src/app/global/global'; export class UserWalletInfoComponent implements OnChanges { @Input() breakpoint: any; @Input() userAddress: string; - @Input() arrayDelegate: any[] = []; - @Input() dataDelegate: DataDelegateDto; + @Input() dataDelegate: any; @Input() lstUndelegate: any[] = []; + @Input() dataUserDelegate: any; @Input() modalManage: any; @Input() denom: any; @Output() onViewDialog: EventEmitter = new EventEmitter(); @@ -23,6 +22,7 @@ export class UserWalletInfoComponent implements OnChanges { validatorImgArr; dataSourceWallet = new MatTableDataSource(); + dataStakeInfo = {}; templatesWallet: Array = [ { matColumnDef: 'validator_name', headerCellDef: 'Name', desktopOnly: true }, { matColumnDef: 'amount_staked', headerCellDef: 'Amount Staked' }, @@ -33,36 +33,16 @@ export class UserWalletInfoComponent implements OnChanges { clicked = false; isDisableClaim = true; - constructor( - public globals: Globals, - public commonService: CommonService, - private validatorService: ValidatorService, - private cdr: ChangeDetectorRef, - ) {} + constructor(public globals: Globals, public commonService: CommonService) {} ngOnChanges(changes: SimpleChanges): void { - if (changes.arrayDelegate) { - if (changes.arrayDelegate.currentValue?.length !== changes.arrayDelegate.previousValue?.length) { - this.dataSourceWallet = new MatTableDataSource(this.arrayDelegate); - } else { - Object.keys(this.arrayDelegate).forEach((key) => { - if (this.dataSourceWallet.data[key]) { - Object.assign(this.dataSourceWallet.data[key], this.arrayDelegate[key]); - } else { - this.dataSourceWallet.data[key] = this.arrayDelegate[key]; - } - }); - } - if (changes.arrayDelegate.currentValue?.length > 0) { - // get ValidatorAddressArr - this.getValidatorAvatar(changes.arrayDelegate.currentValue); - } - } + this.dataSourceWallet = new MatTableDataSource(this.dataUserDelegate?.delegations); if (changes.dataDelegate) { if (Number(this.dataDelegate?.stakingToken) > 0) { this.isDisableClaim = false; } + this.dataStakeInfo = changes.dataDelegate.currentValue; } if (changes.lstUndelegate) { @@ -75,11 +55,6 @@ export class UserWalletInfoComponent implements OnChanges { } }); this.lstUndelegate = lstUndelegateTemp; - - if (this.lstUndelegate?.length > 0) { - // get ValidatorAddressArr - this.getValidatorAvatar(this.lstUndelegate); - } } } @@ -95,29 +70,4 @@ export class UserWalletInfoComponent implements OnChanges { }; this.onViewDialog.emit(dataModal); } - - getValidatorAvatar(validatorArr) { - if (validatorArr.length > 0) { - const operatorAddArr = []; - // get ValidatorAddressArr - validatorArr.forEach((d) => { - operatorAddArr.push(d.validator_address); - }); - // get validator logo - this.validatorService.getValidatorInfoByList(operatorAddArr).subscribe((res) => { - if (res?.data) { - this.validatorImgArr = res?.data; - // push image into validator array - validatorArr.forEach((item) => { - this.validatorImgArr.forEach((imgObj) => { - if (imgObj.operator_address == item.validator_address) { - item['image_url'] = imgObj.image_url; - } - }); - }); - this.cdr.markForCheck(); - } - }); - } - } } diff --git a/src/app/pages/validators/validators-detail/delegate-item/delegate-item.component.html b/src/app/pages/validators/validators-detail/delegate-item/delegate-item.component.html index 70d2ca375..10639ef36 100644 --- a/src/app/pages/validators/validators-detail/delegate-item/delegate-item.component.html +++ b/src/app/pages/validators/validators-detail/delegate-item/delegate-item.component.html @@ -14,7 +14,7 @@
+ [srcImg]="currentValidatorDetail.image_url">
diff --git a/src/app/pages/validators/validators-detail/delegate-item/delegate-item.component.ts b/src/app/pages/validators/validators-detail/delegate-item/delegate-item.component.ts index fae9acbfe..229865ce2 100644 --- a/src/app/pages/validators/validators-detail/delegate-item/delegate-item.component.ts +++ b/src/app/pages/validators/validators-detail/delegate-item/delegate-item.component.ts @@ -1,8 +1,6 @@ -import { Component, ElementRef, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; -import { forkJoin } from 'rxjs'; import { NUMBER_CONVERT, TIME_OUT_CALL_API } from 'src/app/core/constants/common.constant'; -import { CodeTransaction } from 'src/app/core/constants/transaction.enum'; import { DIALOG_STAKE_MODE } from 'src/app/core/constants/validator.enum'; import { ESigningType, SIGNING_MESSAGE_TYPES } from 'src/app/core/constants/wallet.constant'; import { EnvironmentService } from 'src/app/core/data-services/environment.service'; @@ -10,11 +8,9 @@ import { AccountService } from 'src/app/core/services/account.service'; import { CommonService } from 'src/app/core/services/common.service'; import { MappingErrorService } from 'src/app/core/services/mapping-error.service'; import { NgxToastrService } from 'src/app/core/services/ngx-toastr.service'; -import { TransactionService } from 'src/app/core/services/transaction.service'; import { ValidatorService } from 'src/app/core/services/validator.service'; import { WalletService } from 'src/app/core/services/wallet.service'; import { getFee } from 'src/app/core/utils/signing/fee'; -import { createSignBroadcast } from 'src/app/core/utils/signing/transaction-manager'; import { Globals } from 'src/app/global/global'; @Component({ @@ -83,10 +79,6 @@ export class DelegateItemComponent implements OnInit { } } - getValidatorAvatar(validatorAddress: string): string { - return this.validatorService.getValidatorAvatar(validatorAddress); - } - viewPopupDetail(staticDataModal: any) { if (!this.dialogOpen) { const view = async () => { @@ -112,8 +104,6 @@ export class DelegateItemComponent implements OnInit { if (this.userAddress) { this.accountService.getAccountDetail(this.userAddress).subscribe((res) => { if (res) { - // this.getListDelegators(this.currentValidatorDetail?.operator_address); - this.dataDelegate = { ...this.dataDelegate, delegableVesting: res?.data?.delegable_vesting, @@ -134,11 +124,6 @@ export class DelegateItemComponent implements OnInit { } } - // async getListDelegators(address) { - // const res = await this.validatorService.delegators(5, 0, address); - // this.totalDelegator = res?.data?.pagination?.total || 0; - // } - resetCheck() { this.isExceedAmount = false; this.isValidatorJail = false; diff --git a/src/app/pages/validators/validators-detail/validators-detail.component.html b/src/app/pages/validators/validators-detail/validators-detail.component.html index ad0b6fdc7..2db628c0d 100644 --- a/src/app/pages/validators/validators-detail/validators-detail.component.html +++ b/src/app/pages/validators/validators-detail/validators-detail.component.html @@ -64,24 +64,28 @@
{{ currentValidatorDetail?.title }}
Operator Address
-
+
+
{{ currentValidatorDetail?.operator_address }}
@@ -94,6 +98,7 @@
Address
@@ -104,8 +109,11 @@
Address
@@ -224,7 +232,7 @@

Proposed Blocks

-
+
Proposed Blocks

- - + +
@@ -271,14 +279,13 @@

Proposed Blocks

Uptime

-
+
+
Last {{ numberLastBlock }} Blocks
@@ -288,25 +295,25 @@

Uptime

@@ -327,79 +334,77 @@

Delegators

-->
- - -
- - - - + +
+
-
-
+ + + - - - - - - - - -
+
+
-
- - - {{ data[template.matColumnDef] | cutStringPipe : 8 : 8 }} - -
- {{ data[template.matColumnDef] | mask : 'separator.6' }} - {{ denom }} -
-
{{ data[template.matColumnDef] }}
-
-
-
- + +
+ + +
+ {{ data[template.matColumnDef] | mask : 'separator.6' }} + {{ denom }} +
+
{{ data[template.matColumnDef] }}
+
+
- -
- -
+
- - -
-
- - - -
+ + + + + + + + + +
+ +
+
+ + +
+ + + +

@@ -472,7 +477,7 @@

Power Events

-
+
div { + color: var(--aura-primary) !important; + } + } +} diff --git a/src/app/pages/validators/validators-detail/validators-detail.component.ts b/src/app/pages/validators/validators-detail/validators-detail.component.ts index eb8fd8028..6c4d7f345 100644 --- a/src/app/pages/validators/validators-detail/validators-detail.component.ts +++ b/src/app/pages/validators/validators-detail/validators-detail.component.ts @@ -1,12 +1,11 @@ import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout'; -import { AfterViewChecked, Component, OnInit } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { PageEvent } from '@angular/material/paginator'; import { MatTableDataSource } from '@angular/material/table'; import { ActivatedRoute, Router } from '@angular/router'; import * as _ from 'lodash'; import { NUM_BLOCK } from 'src/app/core/constants/common.constant'; import { LIMIT_NUM_SBT } from 'src/app/core/constants/soulbound.constant'; -import { TRANSACTION_TYPE_ENUM } from 'src/app/core/constants/transaction.enum'; import { STATUS_VALIDATOR } from 'src/app/core/constants/validator.enum'; import { EnvironmentService } from 'src/app/core/data-services/environment.service'; import { TableTemplate } from 'src/app/core/models/common.model'; @@ -15,16 +14,15 @@ import { CommonService } from 'src/app/core/services/common.service'; import { SoulboundService } from 'src/app/core/services/soulbound.service'; import { ValidatorService } from 'src/app/core/services/validator.service'; import { WalletService } from 'src/app/core/services/wallet.service'; -import { convertDataBlock, getAmount, Globals } from 'src/app/global/global'; +import { Globals, convertDataBlock } from 'src/app/global/global'; import { balanceOf } from '../../../core/utils/common/parsing'; const marked = require('marked'); -const encode = require('@cosmjs/encoding'); @Component({ selector: 'app-validators-detail', templateUrl: './validators-detail.component.html', styleUrls: ['./validators-detail.component.scss'], }) -export class ValidatorsDetailComponent implements OnInit, AfterViewChecked { +export class ValidatorsDetailComponent implements OnInit { currentAddress: string; currentValidatorDetail: any; @@ -66,7 +64,7 @@ export class ValidatorsDetailComponent implements OnInit, AfterViewChecked { dataSourceBlockMob: any[]; dataSourceDelegatorMob: any[]; - lengthBlockLoading = true; + isLoadingBlock = true; isLoadingPower = true; lastBlockLoading = true; numberLastBlock = 100; @@ -75,7 +73,6 @@ export class ValidatorsDetailComponent implements OnInit, AfterViewChecked { nextKey = null; currentNextKey = null; nextKeyBlock = null; - currentNextKeyBlock = null; nextKeyDelegator = null; currentNextKeyDelegator = null; @@ -88,8 +85,9 @@ export class ValidatorsDetailComponent implements OnInit, AfterViewChecked { timeInterval = this.environmentService.configValue.timeInterval; soulboundList = []; arrBlockUptime = []; + arrLastBlock = []; isLeftPage = false; - addressBase64 = null; + typeActive = 'BOND_STATUS_BONDED'; constructor( private route: ActivatedRoute, @@ -121,7 +119,6 @@ export class ValidatorsDetailComponent implements OnInit, AfterViewChecked { loadData(isInit = true) { if (!this.isLeftPage) { if (this.pageIndexBlock === 0) { - this.currentNextKeyBlock = null; this.getListBlockWithOperator(null, isInit); } if (this.pageIndexDelegator === 0) { @@ -143,27 +140,42 @@ export class ValidatorsDetailComponent implements OnInit, AfterViewChecked { getDetail(isInit = false): void { if (!this.isLeftPage) { - this.validatorService.validatorsDetail(this.currentAddress).subscribe( + this.validatorService.getDataValidator(null).subscribe( (res) => { - if (res.status === 404) { + if (res.status === 404 || res.validator?.length === 0) { this.router.navigate(['/']); return; } + const arrActive = res.validator.filter((k) => k.status === this.typeActive); + const arrInactive = res.validator.filter((k) => k.status !== this.typeActive && !k.jailed); + const arrJail = res.validator.filter((k) => k.status !== this.typeActive && k.jailed); + const arrRank = [...arrActive, ...arrInactive, ...arrJail]; + + const data = res.validator?.find((k) => k.operator_address === this.currentAddress); this.currentValidatorDetail = { - ...res.data, - self_bonded: balanceOf(res.data.self_bonded), - power: balanceOf(res.data.power), - identity: res?.data?.identity, + ...data, + self_bonded: balanceOf(data?.self_delegation_balance), + power: balanceOf(data?.tokens), + identity: data.description?.identity, + up_time: (NUM_BLOCK - +data?.missed_blocks_counter) / 100, + title: data?.description?.moniker, + acc_address: data?.account_address, + commission: (+data?.commission.commission_rates.rate)?.toFixed(4), + details: data?.description?.details, + percent_power: data?.percent_voting_power?.toFixed(2), + bonded_height: data?.start_height || 1, + jailed: data.jailed ? 1 : 0, + status: data.status === this.typeActive ? this.statusValidator.Active : data?.status, + rank: arrRank?.findIndex((k) => k.operator_address === this.currentAddress) + 1 || 1, }; - this.addressBase64 = encode.toBase64(encode.fromHex(this.currentValidatorDetail.cons_address)); - this.getDetailValidatorIndexer(); - if (isInit) { - if (this.currentValidatorDetail?.status === this.statusValidator.Active) { - this.getLastHeight(); - } else { - this.getListUpTime(); - } + + const percentSelfBonded = + (this.currentValidatorDetail.self_delegation_balance / this.currentValidatorDetail.tokens) * 100; + this.currentValidatorDetail.percent_self_bonded = percentSelfBonded.toFixed(2) + '%'; + + if (this.currentValidatorDetail?.consensus_hex_address && isInit) { + this.getUptime(); } this.getTotalSBT(this.currentValidatorDetail.acc_address); @@ -176,12 +188,19 @@ export class ValidatorsDetailComponent implements OnInit, AfterViewChecked { } getListBlockWithOperator(nextKeyBlock = null, isInit = true): void { - this.blockService.blockWithOperator(100, this.currentAddress, nextKeyBlock).subscribe( + let payload = { + limit: 100, + address: this.currentAddress, + nextHeight: null, + }; + if (nextKeyBlock !== null) { + payload.nextHeight = nextKeyBlock; + } + this.blockService.getDataBlock(payload).subscribe( (res) => { - const { code, data } = res; - this.nextKeyBlock = data.nextKey || null; - if (code === 200) { - const blocks = convertDataBlock(data); + this.nextKeyBlock = res?.block[res?.block?.length - 1]?.height; + if (res.block.length > 0) { + const blocks = convertDataBlock(res); if (this.dataSourceBlock.data.length > 0 && isInit) { this.dataSourceBlock.data = [...this.dataSourceBlock.data, ...blocks]; } else { @@ -198,44 +217,39 @@ export class ValidatorsDetailComponent implements OnInit, AfterViewChecked { }, () => {}, () => { - this.lengthBlockLoading = false; + this.isLoadingBlock = false; }, ); } - async getBlocksMiss(height = null) { - if (this.arrBlockUptime && this.arrBlockUptime?.length >= 100) { - return; + getBlocksMiss(address = null, lastBlock = []) { + //check is query last block + let limit = 100; + let height = null; + if (lastBlock?.length > 0) { + limit = 1; + height = lastBlock[0]?.height; } - - const res = await this.validatorService.getUptimeLCD(height); - const currentHeight = Number(_.get(res, 'data.block.header.height')) || 0; - const temp = this.arrBlockUptime.find((k) => k.height === currentHeight); - if (!temp) { - const listBlock = _.get(res, 'data.block.last_commit.signatures'); - if (listBlock) { - let height = Number(_.get(res, 'data.block.header.height')) || 0; - let isSyncFail = false; - const address = listBlock.find((k) => k.validator_address === this.addressBase64); - if (!address) { - isSyncFail = true; - } - - let element = [{ height, isSyncFail }]; - if (this.arrBlockUptime && this.arrBlockUptime?.length > 0) { - this.arrBlockUptime = [...this.arrBlockUptime, ...element]; + this.validatorService.getUptimeIndexer(address, limit, height).subscribe((res) => { + this.arrBlockUptime = res?.block?.filter((h) => h.block_signatures.length === 0); + if (lastBlock?.length === 0) { + if (this.arrBlockUptime?.length > 0 && lastBlock?.length === 0) { + this.arrLastBlock?.forEach((element) => { + if (this.arrBlockUptime?.find((k) => k.height === element.height)) { + element['isSign'] = false; + } + }); } + } else { + lastBlock[0]['isSign'] = this.arrBlockUptime?.find((k) => k.height === lastBlock[0]?.height) ? false : true; + this.arrLastBlock?.unshift(lastBlock[0]); + this.arrLastBlock?.pop(); } - } - - this.timerGetUpTime = setInterval(() => { - this.getBlocksMiss(height - 1); - clearInterval(this.timerGetUpTime); - }, 500); + }); } async getListDelegator(nextKey = null, isInit = true) { - const res = await this.validatorService.delegators(100, this.currentAddress, nextKey); + const res = await this.validatorService.delegator(100, this.currentAddress, nextKey); if (res.data?.pagination?.next_key) { this.nextKeyDelegator = encodeURIComponent(res.data?.pagination?.next_key); @@ -263,35 +277,26 @@ export class ValidatorsDetailComponent implements OnInit, AfterViewChecked { getListPower(nextKey = null, isInit = true): void { this.validatorService.validatorsDetailListPower(this.currentAddress, 100, nextKey).subscribe( (res) => { - const { code, data } = res; - this.nextKey = data.nextKey || null; - - if (code === 200) { - const txs = _.get(data, 'transactions').map((element) => { + if (res?.power_event?.length > 0) { + if (res?.power_event?.length >= 100) { + this.nextKey = res?.power_event[res?.power_event?.length - 1].id; + } + const txs = _.get(res, 'power_event').map((element) => { let isStakeMode = false; - const tx_hash = _.get(element, 'tx_response.txhash'); - const address = _.get(element, 'tx_response.tx.body.messages[0].validator_dst_address'); - const _type = _.get(element, 'tx_response.tx.body.messages[0].@type'); - if ( - _type === TRANSACTION_TYPE_ENUM.Delegate || - (_type === TRANSACTION_TYPE_ENUM.Redelegate && address === this.currentAddress) || - _type === TRANSACTION_TYPE_ENUM.CreateValidator || - _type === TRANSACTION_TYPE_ENUM.ExecuteAuthz - ) { + const tx_hash = _.get(element, 'transaction.hash'); + const address = _.get(element, 'validatorDst.operator_address'); + const _type = _.get(element, 'type'); + if (_type === 'delegate' || (_type === 'redelegate' && address === this.currentAddress)) { isStakeMode = true; } - let amount = getAmount( - _.get(element, 'tx_response.tx.body.messages'), - _type, - _.get(element, 'tx_response.tx.body.raw_log'), - ); + let amount = balanceOf(element.amount) || '0'; - if (amount === 0 && element?.tx_response?.tx?.body?.messages.length > 0) { + if (amount === 0 && element?.transaction?.data?.length > 0) { amount = 'More'; } - const height = _.get(element, 'tx_response.height'); - const timestamp = _.get(element, 'tx_response.timestamp'); + const height = _.get(element, 'height'); + const timestamp = _.get(element, 'time'); return { tx_hash, amount, isStakeMode, height, timestamp }; }); @@ -340,9 +345,8 @@ export class ValidatorsDetailComponent implements OnInit, AfterViewChecked { page.pageIndex * page.pageSize + page.pageSize, ); const nextBlock = page.length <= (page.pageIndex + 2) * page.pageSize; - if (nextBlock && this.nextKeyBlock && this.currentNextKeyBlock !== this.nextKeyBlock) { + if (nextBlock && this.nextKeyBlock) { this.getListBlockWithOperator(this.nextKeyBlock); - this.currentNextKeyBlock = this.nextKeyBlock; } this.pageIndexBlock = page.pageIndex; break; @@ -376,12 +380,16 @@ export class ValidatorsDetailComponent implements OnInit, AfterViewChecked { } } - ngAfterViewChecked(): void { - const editor = document.getElementById('marked'); - if (editor && this.currentValidatorDetail) { - editor.innerHTML = marked.parse(this.currentValidatorDetail.details); - return; - } + ngAfterViewInit(): void { + setTimeout(() => { + const editor = document.getElementById('marked'); + if (editor && this.currentValidatorDetail) { + editor.innerHTML = marked.parse( + this.currentValidatorDetail.details, + ); + return; + } + }, 1000); } openDialog() { @@ -409,50 +417,15 @@ export class ValidatorsDetailComponent implements OnInit, AfterViewChecked { }); } - async getLastHeight() { - if (!this.isLeftPage) { - const res = await this.validatorService.getUptimeLCD(); - const listBlock = _.get(res, 'data.block.last_commit.signatures'); - if (listBlock) { - let height = Number(_.get(res, 'data.block.header.height')) || 0; - let isSyncFail = false; - const address = listBlock.find((k) => k.validator_address === this.addressBase64); - if (!address) { - isSyncFail = true; - } - let element = [{ height, isSyncFail }]; - if (this.arrBlockUptime && this.arrBlockUptime?.length > 0) { - const temp = this.arrBlockUptime.find((k) => k.height === height); - if (!temp) { - this.arrBlockUptime = [...element, ...this.arrBlockUptime]; - } - } else { - this.arrBlockUptime = [...element]; - this.getBlocksMiss(height); - } - } - this.lastBlockLoading = false; - } - } - - getDetailValidatorIndexer() { - this.validatorService.validatorsFromIndexer(this.currentValidatorDetail.operator_address).subscribe((res) => { - this.currentValidatorDetail['up_time'] = - (NUM_BLOCK - +res.data.validators[0].val_signing_info.missed_blocks_counter) / 100; - }); - } - - getListUpTime(): void { - this.blockService.blocksIndexer(this.numberLastBlock).subscribe( + getUptime() { + const payload = { + limit: 100, + }; + this.blockService.getDataBlock(payload).subscribe( (res) => { - const { code, data } = res; - if (code === 200) { - const block = _.get(data, 'blocks').map((element) => { - const height = _.get(element, 'block.header.height'); - const isSyncFail = true; - return { height, isSyncFail }; - }); - this.arrBlockUptime = block; + if (res?.block?.length > 0) { + this.arrLastBlock = res.block; + this.getBlocksMiss(this.currentValidatorDetail?.consensus_hex_address); } }, () => {}, @@ -461,4 +434,15 @@ export class ValidatorsDetailComponent implements OnInit, AfterViewChecked { }, ); } + + getLastHeight() { + const payload = { + limit: 1, + }; + this.blockService.getDataBlock(payload).subscribe((res) => { + if (res?.block?.length > 0 && res?.block[0].height !== this.arrLastBlock[0].height) { + this.getBlocksMiss(this.currentValidatorDetail?.consensus_hex_address, res?.block); + } + }); + } } diff --git a/src/app/pages/validators/validators.component.html b/src/app/pages/validators/validators.component.html index 13571f980..b43d8682b 100644 --- a/src/app/pages/validators/validators.component.html +++ b/src/app/pages/validators/validators.component.html @@ -3,8 +3,8 @@ Validators

-
+
@@ -112,61 +112,57 @@

Validators

- -
- - - + @@ -174,7 +170,7 @@

Validators

-
-
-
+
-
+
+
+ +
-
+
+
+ + +
-
+
+
+ + +
-
+
+
+ + +
+
@@ -184,15 +180,14 @@

Validators

{{ data[template.matColumnDef] | percent : globals.formatNumber2Decimal }}
-
+
+ +
Validators {{ data['percent_power'] + '%' }} - +
+ + + +
- {{ data[template.matColumnDef] + '/' + data['target_count'] }} + {{ data[template.matColumnDef] + '/' + countProposal }}
-
+
- {{ calculatorUpTime(data['acc_address']) | number : globals.formatNumber2Decimal }}% + {{ calculatorUpTime(data['account_address']) | number : globals.formatNumber2Decimal }}% 0.00%
@@ -352,7 +352,7 @@
- {{ validator[template.matColumnDef] + '/' + validator['target_count'] }} + {{ validator[template.matColumnDef] + '/' + countProposal }}
@@ -398,25 +398,25 @@
+ [appClass]="validatorDetail['jailed'] ? 'jailed' : ''" + [identity]="validatorDetail.identity" + [srcImg]="validatorDetail.image_url">
- {{ dataModal?.title }} + {{ validatorDetail?.title }}
- Commission - {{ dataModal?.commission | percent : globals.formatNumber2Decimal }} + Commission - {{ validatorDetail?.commission | percent : globals.formatNumber2Decimal }}
- Voting power - {{ dataModal?.percent_power }}%  - ({{ dataModal?.power | mask : 'separator.6' }} + Voting power - {{ validatorDetail?.percent_power }}%  + ({{ validatorDetail?.power | mask : 'separator.6' }} {{ denom }})
@@ -571,7 +571,7 @@
+
+
+
+
{{ data.label }}
+
+
+ + {{ denom }} +
+
+
+
diff --git a/src/app/shared/components/cards/card-mob-explain/card-mob-explain.component.scss b/src/app/shared/components/cards/card-mob-explain/card-mob-explain.component.scss new file mode 100644 index 000000000..2abe8bc6e --- /dev/null +++ b/src/app/shared/components/cards/card-mob-explain/card-mob-explain.component.scss @@ -0,0 +1,36 @@ +.card-mob-explain { + background-color: var(--aura-gray-9); + border-radius: var(--spacer-2); + padding: var(--spacer-4); + padding-bottom: 0; + margin-bottom: var(--spacer-4); + overflow: hidden; + &>* { + color: var(--aura-white); + } + .card__content { + max-height: 0; + &.show { + transition: all .35s ease-in-out; + max-height: 900px; + padding-bottom: var(--spacer-4); + } + &-item { + display: flex; + align-items: center; + justify-content: space-between; + font-weight: 400; + font-size: 1.4rem; + line-height: 1.8rem; + &:not(:last-child){ + margin-bottom: 6px; + } + } + } +} +.button-explain:has(.rotate) { + transform: rotate(180deg); +} +.text-gray-3 { + color: #B4B8C0; +} diff --git a/src/app/shared/components/cards/card-mob-explain/card-mob-explain.component.ts b/src/app/shared/components/cards/card-mob-explain/card-mob-explain.component.ts new file mode 100644 index 000000000..555a209f0 --- /dev/null +++ b/src/app/shared/components/cards/card-mob-explain/card-mob-explain.component.ts @@ -0,0 +1,29 @@ +import { Component, Input, OnInit } from '@angular/core'; +import { EnvironmentService } from 'src/app/core/data-services/environment.service'; + +export interface CardMobExplainTitle { + label: string; + labelLink: string; + subLabel: string; +} +export interface CardMobContent { + label: string; + class?: string; + info: any; + isAmount?: boolean; +} +@Component({ + selector: 'app-card-mob-explain', + templateUrl: './card-mob-explain.component.html', + styleUrls: ['./card-mob-explain.component.scss'], +}) +export class CardMobExplainComponent implements OnInit { + denom = this.environmentService.configValue.chain_info.currencies[0].coinDenom; + @Input() title: CardMobExplainTitle; + @Input() status: any; + @Input() content: CardMobContent[]; + @Input() tokenAmount: any; + constructor(private environmentService: EnvironmentService) {} + + ngOnInit(): void {} +} diff --git a/src/app/shared/components/cards/nft-card/nft-card.component.html b/src/app/shared/components/cards/nft-card/nft-card.component.html index 77ca60271..b0aef1745 100644 --- a/src/app/shared/components/cards/nft-card/nft-card.component.html +++ b/src/app/shared/components/cards/nft-card/nft-card.component.html @@ -2,7 +2,9 @@