forked from cerc-io/cosmos-explorer
commit
852a8e6c1b
@ -47,19 +47,23 @@ export const DEFAULT: RequestRegistry = {
|
|||||||
tx_txs_block: { url: "/cosmos/tx/v1beta1/txs/block/{height}", adapter },
|
tx_txs_block: { url: "/cosmos/tx/v1beta1/txs/block/{height}", adapter },
|
||||||
tx_hash: { url: "/cosmos/tx/v1beta1/txs/{hash}", adapter },
|
tx_hash: { url: "/cosmos/tx/v1beta1/txs/{hash}", adapter },
|
||||||
|
|
||||||
mint_inflation: { url: "/cosmos/mint/v1beta1/inflation", adapter},
|
mint_inflation: { url: "/cosmos/mint/v1beta1/inflation", adapter },
|
||||||
mint_params: { url: "/cosmos/mint/v1beta1/params", adapter},
|
mint_params: { url: "/cosmos/mint/v1beta1/params", adapter },
|
||||||
mint_annual_provisions: { url: "/cosmos/mint/v1beta1/annual_provisions", adapter},
|
mint_annual_provisions: { url: "/cosmos/mint/v1beta1/annual_provisions", adapter },
|
||||||
|
|
||||||
// ibc
|
// ibc
|
||||||
ibc_app_ica_controller_params: { url: "/ibc/apps/interchain_accounts/controller/v1/params", adapter },
|
ibc_app_ica_controller_params: { url: "/ibc/apps/interchain_accounts/controller/v1/params", adapter },
|
||||||
ibc_app_ica_host_params: { url: "/ibc/apps/interchain_accounts/host/v1/params", adapter},
|
ibc_app_ica_host_params: { url: "/ibc/apps/interchain_accounts/host/v1/params", adapter },
|
||||||
ibc_app_transfer_escrow_address: { url: "/ibc/apps/transfer/v1/channels/{channel_id}/ports/{port_id}/escrow_address", adapter},
|
ibc_app_transfer_escrow_address: { url: "/ibc/apps/transfer/v1/channels/{channel_id}/ports/{port_id}/escrow_address", adapter },
|
||||||
ibc_app_transfer_denom_traces: { url: "/ibc/apps/transfer/v1/denom_traces", adapter},
|
ibc_app_transfer_denom_traces: { url: "/ibc/apps/transfer/v1/denom_traces", adapter },
|
||||||
ibc_app_transfer_denom_traces_hash: { url: "/ibc/apps/transfer/v1/denom_traces/{hash}", adapter},
|
ibc_app_transfer_denom_traces_hash: { url: "/ibc/apps/transfer/v1/denom_traces/{hash}", adapter },
|
||||||
ibc_core_channel_channels: { url: "/ibc/core/channel/v1/channels", adapter},
|
ibc_core_channel_channels: { url: "/ibc/core/channel/v1/channels", adapter },
|
||||||
ibc_core_channel_channels_next_sequence: { url: "/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/next_sequence", adapter},
|
ibc_core_channel_channels_next_sequence: { url: "/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/next_sequence", adapter },
|
||||||
ibc_core_channel_channels_acknowledgements: { url: "/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/packet_acknowledgements", adapter}
|
ibc_core_channel_channels_acknowledgements: { url: "/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/packet_acknowledgements", adapter },
|
||||||
|
ibc_core_channel_connections_channels: { url: "/ibc/core/channel/v1/connections/{connection_id}/channels", adapter },
|
||||||
|
ibc_core_connection_connections: { url: "/ibc/core/connection/v1/connections", adapter },
|
||||||
|
ibc_core_connection_connections_connection_id: { url: "/ibc/core/connection/v1/connections/{connection_id}", adapter },
|
||||||
|
ibc_core_connection_connections_connection_id_client_state: { url: "/ibc/core/connection/v1/connections/{connection_id}/client_state", adapter }
|
||||||
};
|
};
|
||||||
|
|
||||||
export const VERSION_REGISTRY: Registry = {
|
export const VERSION_REGISTRY: Registry = {
|
||||||
|
@ -179,6 +179,27 @@ export class CosmosRestClient extends BaseRestClient<RequestRegistry> {
|
|||||||
async getIBCAppTransferDenom(hash: string) {
|
async getIBCAppTransferDenom(hash: string) {
|
||||||
return this.request(this.registry.ibc_app_transfer_denom_traces_hash, {hash})
|
return this.request(this.registry.ibc_app_transfer_denom_traces_hash, {hash})
|
||||||
}
|
}
|
||||||
|
async getIBCConnections() {
|
||||||
|
return this.request(this.registry.ibc_core_connection_connections, {})
|
||||||
|
}
|
||||||
|
async getIBCConnectionsById(connection_id: string) {
|
||||||
|
return this.request(this.registry.ibc_core_connection_connections_connection_id, {connection_id})
|
||||||
|
}
|
||||||
|
async getIBCConnectionsClientState(connection_id: string) {
|
||||||
|
return this.request(this.registry.ibc_core_connection_connections_connection_id_client_state, {connection_id})
|
||||||
|
}
|
||||||
|
async getIBCConnectionsChannels(connection_id: string) {
|
||||||
|
return this.request(this.registry.ibc_core_channel_connections_channels, {connection_id})
|
||||||
|
}
|
||||||
|
async getIBCChannels() {
|
||||||
|
return this.request(this.registry.ibc_core_channel_channels, {})
|
||||||
|
}
|
||||||
|
async getIBCChannelAcknowledgements(channel_id: string, port_id: string) {
|
||||||
|
return this.request(this.registry.ibc_core_channel_channels_acknowledgements, {channel_id, port_id})
|
||||||
|
}
|
||||||
|
async getIBCChannelNextSequence(channel_id: string, port_id: string) {
|
||||||
|
return this.request(this.registry.ibc_core_channel_channels_next_sequence, {channel_id, port_id})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import type { AuthAccount, Block, Coin, NodeInfo, PaginabledAccounts, PaginatedTendermintValidator,} from "@/types";
|
import type { AuthAccount, Block, ClientStateWithProof, Coin, ConnectionWithProof, DenomTrace, NodeInfo, PaginabledAccounts, PaginatedIBCChannels, PaginatedIBCConnections, PaginatedTendermintValidator,} from "@/types";
|
||||||
import type { BankParams, PaginatedBalances, PaginatedDenomMetadata, PaginatedSupply } from "@/types/bank";
|
import type { BankParams, PaginatedBalances, PaginatedDenomMetadata, PaginatedSupply } from "@/types/bank";
|
||||||
import type { DistributionParams, PaginatedSlashes } from "@/types/distribution";
|
import type { DistributionParams, PaginatedSlashes } from "@/types/distribution";
|
||||||
import type { GovParams, GovProposal, GovVote, PaginatedProposalDeposit, PaginatedProposalVotes, PaginatedProposals, Tally } from "@/types/gov";
|
import type { GovParams, GovProposal, GovVote, PaginatedProposalDeposit, PaginatedProposalVotes, PaginatedProposals, Tally } from "@/types/gov";
|
||||||
import type { PaginatedSigningInfo } from "@/types/slashing";
|
import type { PaginatedSigningInfo } from "@/types/slashing";
|
||||||
import type { Delegation, PaginatedDelegations, PaginatedRedelegations, PaginatedUnbonding, PaginatedValdiators, StakingParam, StakingPool, Validator } from "@/types/staking";
|
import type { Delegation, PaginatedDelegations, PaginatedRedelegations, PaginatedUnbonding, PaginatedValdiators, StakingParam, StakingPool, Validator } from "@/types/staking";
|
||||||
import type { PaginatedTxs, Tx, TxResponse } from "@/types/tx";
|
import type { PaginatedTxs, Tx, TxResponse } from "@/types/tx";
|
||||||
import semver from "semver";
|
|
||||||
|
|
||||||
|
|
||||||
export interface Request<T> {
|
export interface Request<T> {
|
||||||
@ -86,15 +85,22 @@ export interface RequestRegistry extends AbstractRegistry {
|
|||||||
ibc_app_transfer_escrow_address: Request<any>;
|
ibc_app_transfer_escrow_address: Request<any>;
|
||||||
ibc_app_transfer_denom_traces: Request<any>;
|
ibc_app_transfer_denom_traces: Request<any>;
|
||||||
ibc_app_transfer_denom_traces_hash: Request<{
|
ibc_app_transfer_denom_traces_hash: Request<{
|
||||||
"denom_trace": {
|
denom_trace: DenomTrace
|
||||||
"path": "string",
|
}>;
|
||||||
"base_denom": "string"
|
ibc_core_channel_channels: Request<PaginatedIBCChannels>;
|
||||||
|
ibc_core_channel_channels_next_sequence: Request<{
|
||||||
|
next_sequence_receive: string,
|
||||||
|
proof: string,
|
||||||
|
proof_height: {
|
||||||
|
revision_number: string,
|
||||||
|
revision_height: string
|
||||||
}
|
}
|
||||||
}>;
|
}>;
|
||||||
ibc_core_channel_channels: Request<any>;
|
|
||||||
ibc_core_channel_channels_next_sequence: Request<any>;
|
|
||||||
ibc_core_channel_channels_acknowledgements: Request<any>;
|
ibc_core_channel_channels_acknowledgements: Request<any>;
|
||||||
|
ibc_core_channel_connections_channels: Request<PaginatedIBCChannels>;
|
||||||
|
ibc_core_connection_connections: Request<PaginatedIBCConnections>;
|
||||||
|
ibc_core_connection_connections_connection_id: Request<ConnectionWithProof>;
|
||||||
|
ibc_core_connection_connections_connection_id_client_state: Request<ClientStateWithProof>;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { BaseRestClient } from "@/libs/client";
|
import { BaseRestClient } from "@/libs/client";
|
||||||
import { adapter, type AbstractRegistry, type Request } from "@/libs/registry";
|
import { adapter, type AbstractRegistry, type Request } from "@/libs/registry";
|
||||||
import type { PaginabledAccounts } from "@/types";
|
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
import type { CodeInfo, ContractInfo, PaginabledCodeInfos, PaginabledContractHistory, PaginabledContracts, PaginabledContractStates, WasmParam } from "./types";
|
import type { CodeInfo, ContractInfo, PaginabledCodeInfos, PaginabledContractHistory, PaginabledContracts, PaginabledContractStates, WasmParam } from "./types";
|
||||||
import { toBase64 } from "@cosmjs/encoding";
|
import { toBase64 } from "@cosmjs/encoding";
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useBlockchain, useFormatter } from '@/stores';
|
import { fromHex } from "@cosmjs/encoding";
|
||||||
import { useWasmStore } from '../WasmStore';
|
import { useWasmStore } from '../WasmStore';
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import type { ContractInfo, PaginabledContractStates, PaginabledContracts } from '../types';
|
import type { ContractInfo, PaginabledContractStates, PaginabledContracts } from '../types';
|
||||||
import DynamicComponent from '@/components/dynamic/DynamicComponent.vue';
|
import DynamicComponent from '@/components/dynamic/DynamicComponent.vue';
|
||||||
import type CustomRadiosVue from '@/plugins/vuetify/@core/components/CustomRadios.vue';
|
import type CustomRadiosVue from '@/plugins/vuetify/@core/components/CustomRadios.vue';
|
||||||
import type { CustomInputContent } from '@/plugins/vuetify/@core/types';
|
import type { CustomInputContent } from '@/plugins/vuetify/@core/types';
|
||||||
|
import { useFormatter } from "@/stores";
|
||||||
|
|
||||||
const props = defineProps(['code_id', 'chain', ])
|
const props = defineProps(['code_id', 'chain', ])
|
||||||
|
|
||||||
@ -15,6 +16,7 @@ const wasmStore = useWasmStore()
|
|||||||
wasmStore.wasmClient.getWasmCodeContracts(props.code_id).then(x =>{
|
wasmStore.wasmClient.getWasmCodeContracts(props.code_id).then(x =>{
|
||||||
response.value = x
|
response.value = x
|
||||||
})
|
})
|
||||||
|
const format = useFormatter()
|
||||||
const infoDialog = ref(false)
|
const infoDialog = ref(false)
|
||||||
const stateDialog = ref(false)
|
const stateDialog = ref(false)
|
||||||
const queryDialog = ref(false)
|
const queryDialog = ref(false)
|
||||||
@ -80,6 +82,7 @@ const radioContent: CustomInputContent[] = [
|
|||||||
const selectedRadio = ref('raw')
|
const selectedRadio = ref('raw')
|
||||||
const query = ref("")
|
const query = ref("")
|
||||||
const result = ref("")
|
const result = ref("")
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
@ -116,10 +119,10 @@ const result = ref("")
|
|||||||
<VList>
|
<VList>
|
||||||
<VListItem v-for="v in state.models">
|
<VListItem v-for="v in state.models">
|
||||||
<VListItemTitle>
|
<VListItemTitle>
|
||||||
{{ v.value }}
|
{{ format.hexToString(v.key) }}
|
||||||
</VListItemTitle>
|
</VListItemTitle>
|
||||||
<VListItemSubtitle>
|
<VListItemSubtitle :title="format.base64ToString(v.value)">
|
||||||
{{ v.key }}
|
{{ format.base64ToString(v.value) }}
|
||||||
</VListItemSubtitle>
|
</VListItemSubtitle>
|
||||||
</VListItem>
|
</VListItem>
|
||||||
</VList>
|
</VList>
|
||||||
|
@ -16,17 +16,21 @@ wasmStore.wasmClient.getWasmCodeList().then(x =>{
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<VCard>
|
<VCard>
|
||||||
<VCardTitle>Cosmos Wasm</VCardTitle>
|
<VCardTitle>Cosmos Wasm Smart Contracts</VCardTitle>
|
||||||
<VTable>
|
<VTable>
|
||||||
<thead>
|
<thead>
|
||||||
<tr><th>Code Id</th><th>Creator</th><th>Code Hash</th><th>Permissions</th></tr>
|
<tr><th>Code Id</th><th>Code Hash</th><th>Creator</th><th>Permissions</th></tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="v in codes.code_infos">
|
<tr v-for="v in codes.code_infos">
|
||||||
<td>{{ v.code_id }}</td>
|
<td>{{ v.code_id }}</td>
|
||||||
<td>{{ v.creator }}</td>
|
|
||||||
<td><RouterLink :to="`/${props.chain}/cosmwasm/${v.code_id}/contracts`"><div class="text-truncate" style="max-width: 200px;">{{ v.data_hash }}</div></RouterLink></td>
|
<td><RouterLink :to="`/${props.chain}/cosmwasm/${v.code_id}/contracts`"><div class="text-truncate" style="max-width: 200px;">{{ v.data_hash }}</div></RouterLink></td>
|
||||||
<td>{{ v.instantiate_permission }}</td>
|
<td>{{ v.creator }}</td>
|
||||||
|
<td>
|
||||||
|
{{ v.instantiate_permission?.permission }}
|
||||||
|
<span>{{ v.instantiate_permission?.address }} {{ v.instantiate_permission.addresses.join(", ") }}</span>
|
||||||
|
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</VTable>
|
</VTable>
|
||||||
|
@ -6,7 +6,12 @@ const tab = ref('2');
|
|||||||
const store = useGovStore();
|
const store = useGovStore();
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
store.fetchProposals('2');
|
store.fetchProposals('2').then(x => {
|
||||||
|
if(x.proposals.length ===0 ) {
|
||||||
|
tab.value = "3"
|
||||||
|
store.fetchProposals('3')
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const changeTab = (val: '2' | '3' | '4') => {
|
const changeTab = (val: '2' | '3' | '4') => {
|
||||||
|
99
src/modules/[chain]/ibc/[connection_id].vue
Normal file
99
src/modules/[chain]/ibc/[connection_id].vue
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import DynamicComponent from '@/components/dynamic/DynamicComponent.vue';
|
||||||
|
import { useBaseStore, useBlockchain, useFormatter } from '@/stores';
|
||||||
|
import type { ClientStateWithProof, Connection, ClientState, Channel } from '@/types';
|
||||||
|
import { onMounted } from 'vue';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
const props = defineProps(['chain', 'connection_id'])
|
||||||
|
const chainStore = useBlockchain()
|
||||||
|
const baseStore = useBaseStore()
|
||||||
|
const conn = ref({} as Connection)
|
||||||
|
const clientState = ref({} as {client_id: string, client_state: ClientState})
|
||||||
|
const channels = ref([] as Channel[])
|
||||||
|
onMounted(() => {
|
||||||
|
if(props.connection_id) {
|
||||||
|
chainStore.rpc.getIBCConnectionsById(props.connection_id).then(x => {
|
||||||
|
conn.value = x.connection
|
||||||
|
})
|
||||||
|
chainStore.rpc.getIBCConnectionsClientState(props.connection_id).then(x => {
|
||||||
|
clientState.value = x.identified_client_state
|
||||||
|
})
|
||||||
|
chainStore.rpc.getIBCConnectionsChannels(props.connection_id).then(x => {
|
||||||
|
channels.value = x.channels
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
function loadChannel(channel: string, port: string) {
|
||||||
|
chainStore.rpc.getIBCChannelNextSequence(channel, port).then(x => {
|
||||||
|
console.log(x)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function color(v: string) {
|
||||||
|
if(v && v.indexOf("_OPEN") > -1) {
|
||||||
|
return "success"
|
||||||
|
}
|
||||||
|
return "warning"
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="bg-white py-24 sm:py-32">
|
||||||
|
<div class="mx-auto max-w-7xl px-6 lg:px-8">
|
||||||
|
<dl class="grid grid-cols-1 gap-x-8 gap-y-16 text-center lg:grid-cols-3">
|
||||||
|
<div class="mx-auto flex max-w-xs flex-col gap-y-4">
|
||||||
|
<dt class="text-base leading-7 text-gray-600">{{ conn.client_id }} {{props.connection_id}}</dt>
|
||||||
|
<dd class="order-first text-3xl font-semibold tracking-tight text-gray-900 sm:text-5xl">{{ baseStore.latest?.block?.header?.chain_id }}</dd>
|
||||||
|
</div>
|
||||||
|
<div class="mx-auto flex max-w-xs flex-col gap-y-4">
|
||||||
|
<dt class="text-base leading-7 text-gray-600">{{ conn.state }}</dt>
|
||||||
|
<dd class="order-first text-3xl font-semibold tracking-tight text-gray-900 sm:text-5xl"> <><VProgressLinear class="w-100" color="success" /></dd>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="mx-auto flex max-w-xs flex-col gap-y-4">
|
||||||
|
<dt class="text-base leading-7 text-gray-600">{{ conn.counterparty?.connection_id }} {{ clientState.client_id }}</dt>
|
||||||
|
<dd class="order-first text-3xl font-semibold tracking-tight text-gray-900 sm:text-5xl">{{clientState.client_state?.chain_id}}</dd>
|
||||||
|
</div>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<VCard class="my-2">
|
||||||
|
<VCardTitle>IBC Client State</VCardTitle>
|
||||||
|
<VCardText>
|
||||||
|
<br>update after expiry: {{ clientState.client_state?.allow_update_after_expiry }}
|
||||||
|
<br>allow_update_after_misbehaviour: {{ clientState.client_state?.allow_update_after_misbehaviour }}
|
||||||
|
<br>trust_level: {{ clientState.client_state?.trust_level?.numerator }}/{{ clientState.client_state?.trust_level?.denominator }}
|
||||||
|
<br>trusting_period: {{ clientState.client_state?.trusting_period }}
|
||||||
|
<br>unbonding_period: {{ clientState.client_state?.unbonding_period }}
|
||||||
|
<br>frozen_height: {{ clientState.client_state?.frozen_height }}
|
||||||
|
<br>latest_height: {{ clientState.client_state?.latest_height }}
|
||||||
|
<br>type: {{ clientState.client_state?.['@type'] }}
|
||||||
|
<br>upgrade_path: {{ clientState.client_state?.upgrade_path }}
|
||||||
|
<br> {{ clientState.client_state?.max_clock_drift }}
|
||||||
|
</VCardText>
|
||||||
|
</VCard>
|
||||||
|
|
||||||
|
<VCard class="my-2">
|
||||||
|
<VCardTitle>Channels</VCardTitle>
|
||||||
|
<VTable>
|
||||||
|
<thead>
|
||||||
|
<tr><th>Channel Id</th><th>Port Id</th><th>Counterparty</th><th>Hops</th><th>Version</th><th>Ordering</th><th>State</th></tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr v-for="v in channels">
|
||||||
|
<td><a href="#" @click="loadChannel(v.channel_id, v.port_id)">{{ v.channel_id }}</a></td>
|
||||||
|
<td>{{ v.port_id }}</td>
|
||||||
|
<td>{{ v.counterparty?.port_id }}/{{ v.counterparty?.channel_id }}</td>
|
||||||
|
<td>{{ v.connection_hops.join(", ") }} </td>
|
||||||
|
<td>{{ v.version }} </td>
|
||||||
|
<td>{{ v.ordering }}</td>
|
||||||
|
<td><VChip :color="color(v.state)">{{ v.state }}</VChip></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</VTable>
|
||||||
|
</VCard>
|
||||||
|
</div>
|
||||||
|
</template>
|
51
src/modules/[chain]/ibc/index.vue
Normal file
51
src/modules/[chain]/ibc/index.vue
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { useBlockchain, useFormatter } from '@/stores';
|
||||||
|
import type { Connection } from '@/types';
|
||||||
|
import { onMounted } from 'vue';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
const props = defineProps(['chain'])
|
||||||
|
const chainStore = useBlockchain()
|
||||||
|
const list = ref([] as Connection[])
|
||||||
|
onMounted(() => {
|
||||||
|
chainStore.rpc.getIBCConnections().then(x => {
|
||||||
|
list.value = x.connections
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
function color(v: string) {
|
||||||
|
if(v && v.indexOf("_OPEN") > -1) {
|
||||||
|
return "success"
|
||||||
|
}
|
||||||
|
return "warning"
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<VCard>
|
||||||
|
<VCardTitle>IBC Connections</VCardTitle>
|
||||||
|
<VTable>
|
||||||
|
<thead>
|
||||||
|
<tr><th>Connection Id</th><th>Connection</th><th>Delay Period</th><th>State</th></tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr v-for="v in list">
|
||||||
|
<td><RouterLink :to="`/${chain}/ibc/${v.id}`">{{ v.id }}</RouterLink></td>
|
||||||
|
<td>{{ v.client_id }} {{ v.id }} <br> {{v.counterparty.client_id }} {{ v.counterparty.connection_id }} </td>
|
||||||
|
<td>{{ v.delay_period }}</td>
|
||||||
|
<td><VChip :color="color(v.state)">{{ v.state }}</VChip></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</VTable>
|
||||||
|
</VCard>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<route>
|
||||||
|
{
|
||||||
|
meta: {
|
||||||
|
i18n: 'ibc'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</route>
|
@ -168,7 +168,7 @@ export const useIndexModule = defineStore('module-index', {
|
|||||||
title: 'Community Pool',
|
title: 'Community Pool',
|
||||||
color: 'primary',
|
color: 'primary',
|
||||||
icon: 'mdi-bank',
|
icon: 'mdi-bank',
|
||||||
stats: formatter.formatTokens(this.communityPool),
|
stats: formatter.formatTokens(this.communityPool?.filter(x => x.denom === staking.params.bond_denom)),
|
||||||
change: 0,
|
change: 0,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
@ -1,24 +1,29 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, onMounted } from 'vue';
|
import { ref, onMounted, computed, watchEffect } from 'vue';
|
||||||
import {fromBase64, fromBech32, fromHex, toBase64, toBech32, toHex} from '@cosmjs/encoding'
|
import { fromHex, toBase64 } from '@cosmjs/encoding'
|
||||||
import { useFormatter, useStakingStore, useBaseStore, useBlockchain } from '@/stores';
|
import { useFormatter, useStakingStore, useBaseStore, useBlockchain } from '@/stores';
|
||||||
import UptimeBar from '@/components/UptimeBar.vue';
|
import UptimeBar from '@/components/UptimeBar.vue';
|
||||||
import type { Commit } from '@/types'
|
import type { Block, Commit } from '@/types'
|
||||||
import { consensusPubkeyToHexAddress, valconsToBase64 } from "@/libs";
|
import { consensusPubkeyToHexAddress, valconsToBase64 } from "@/libs";
|
||||||
|
import type { SigningInfo } from '@/types/slashing';
|
||||||
|
|
||||||
const props = defineProps(['chain'])
|
const props = defineProps(['chain'])
|
||||||
|
|
||||||
const stakingStore = useStakingStore();
|
const stakingStore = useStakingStore();
|
||||||
const baseStore = useBaseStore();
|
const baseStore = useBaseStore();
|
||||||
const chainStore = useBlockchain()
|
const chainStore = useBlockchain()
|
||||||
const format = useFormatter();
|
const latest = ref({} as Block)
|
||||||
const latest = ref({})
|
|
||||||
const commits = ref([] as Commit[]);
|
const commits = ref([] as Commit[]);
|
||||||
const keyword = ref("")
|
const keyword = ref("")
|
||||||
const live = ref(true);
|
const live = ref(true);
|
||||||
|
|
||||||
const signingInfo = ref({})
|
// storage local favorite validator ids
|
||||||
|
const local = ref((JSON.parse(localStorage.getItem("uptime-validators") || "{}")) as Record<string, string[]>)
|
||||||
|
const selected = ref(local.value[chainStore.chainName] as string[]) // favorite validators on selected blockchain
|
||||||
|
|
||||||
|
const signingInfo = ref({} as Record<string, SigningInfo>)
|
||||||
|
|
||||||
|
// filter validators by keywords
|
||||||
const validators = computed(()=> {
|
const validators = computed(()=> {
|
||||||
if(keyword) return stakingStore.validators.filter(x => x.description.moniker.indexOf(keyword.value) > -1)
|
if(keyword) return stakingStore.validators.filter(x => x.description.moniker.indexOf(keyword.value) > -1)
|
||||||
return stakingStore.validators
|
return stakingStore.validators
|
||||||
@ -36,14 +41,12 @@ onMounted(() => {
|
|||||||
for (let i = height - 1; i > height - 50; i -= 1) {
|
for (let i = height - 1; i > height - 50; i -= 1) {
|
||||||
if (i > height - 48) {
|
if (i > height - 48) {
|
||||||
promise = promise.then(() => new Promise((resolve, reject) => {
|
promise = promise.then(() => new Promise((resolve, reject) => {
|
||||||
baseStore.fetchBlock(i).then((x) => {
|
if(live.value) { // continue only if the page is living
|
||||||
commits.value.unshift(x.block.last_commit)
|
baseStore.fetchBlock(i).then((x) => {
|
||||||
if(live.value) {
|
commits.value.unshift(x.block.last_commit)
|
||||||
resolve()
|
resolve()
|
||||||
} else {
|
})
|
||||||
reject()
|
}
|
||||||
}
|
|
||||||
})
|
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -61,6 +64,11 @@ onUnmounted(() => {
|
|||||||
live.value = false
|
live.value = false
|
||||||
})
|
})
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
local.value[chainStore.chainName] = selected.value
|
||||||
|
localStorage.setItem("uptime-validators", JSON.stringify(local.value))
|
||||||
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -72,17 +80,24 @@ onUnmounted(() => {
|
|||||||
</VCard>
|
</VCard>
|
||||||
</VCol>
|
</VCol>
|
||||||
<VCol cols="12" md="8" class="">
|
<VCol cols="12" md="8" class="">
|
||||||
<VTextField v-model="keyword" label="Keywords to filter validators" variant="outlined"/>
|
<VTextField v-model="keyword" label="Keywords to filter validators" variant="outlined">
|
||||||
|
<template v-slot:append>
|
||||||
|
<VBtn><VIcon icon="mdi-star"/><span class="d-none d-md-block">Favorite</span></VBtn>
|
||||||
|
</template>
|
||||||
|
</VTextField>
|
||||||
</VCol>
|
</VCol>
|
||||||
</VRow>
|
</VRow>
|
||||||
|
|
||||||
<VRow>
|
<VRow>
|
||||||
<VCol v-for="(v, i) in validators" cols="12" md="3" xl="2" class="py-1">
|
<VCol v-for="(v, i) in validators" cols="12" md="3" xl="2" class="py-0">
|
||||||
<div class="d-flex justify-between">
|
<div class="d-flex justify-between">
|
||||||
<span class="text-truncate"> {{i + 1}}. <RouterLink class="" :to="`/${props.chain}/staking/${v.operator_address}`"> {{v.description.moniker}} </RouterLink></span>
|
<VCheckbox v-model="selected" color="warning" :value="v.operator_address">
|
||||||
<VChip v-if="Number(signingInfo[consensusPubkeyToHexAddress(v.consensus_pubkey)]?.missed_blocks_counter || 0) > 0" size="small" class="mb-1" label color="error">{{ signingInfo[consensusPubkeyToHexAddress(v.consensus_pubkey)]?.missed_blocks_counter }}</VChip>
|
<template v-slot:label>
|
||||||
<VChip v-else size="small" class="mb-1" label color="success">{{ signingInfo[consensusPubkeyToHexAddress(v.consensus_pubkey)]?.missed_blocks_counter }}</VChip>
|
<span class="text-truncate">{{i + 1}}. {{v.description.moniker}}</span>
|
||||||
|
</template>
|
||||||
|
</VCheckbox>
|
||||||
|
<VChip v-if="Number(signingInfo[consensusPubkeyToHexAddress(v.consensus_pubkey)]?.missed_blocks_counter || 0) > 0" size="small" class="mt-1" label color="error">{{ signingInfo[consensusPubkeyToHexAddress(v.consensus_pubkey)]?.missed_blocks_counter }}</VChip>
|
||||||
|
<VChip v-else size="small" class="mt-1" label color="success">{{ signingInfo[consensusPubkeyToHexAddress(v.consensus_pubkey)]?.missed_blocks_counter }}</VChip>
|
||||||
</div>
|
</div>
|
||||||
<UptimeBar :blocks="commits" :validator="toBase64(fromHex(consensusPubkeyToHexAddress(v.consensus_pubkey)))" />
|
<UptimeBar :blocks="commits" :validator="toBase64(fromHex(consensusPubkeyToHexAddress(v.consensus_pubkey)))" />
|
||||||
</VCol>
|
</VCol>
|
||||||
|
@ -7,7 +7,8 @@
|
|||||||
"parameters": "Parameters",
|
"parameters": "Parameters",
|
||||||
"uptime": "Uptime",
|
"uptime": "Uptime",
|
||||||
"state-sync": "State Sync",
|
"state-sync": "State Sync",
|
||||||
"cosmwasm": "Cosmwasm"
|
"cosmwasm": "Cosmwasm",
|
||||||
|
"ibc": "IBC"
|
||||||
},
|
},
|
||||||
"index": {
|
"index": {
|
||||||
"slogan": "Ping Dashboard is not just an explorer but also a wallet and more ... 🛠",
|
"slogan": "Ping Dashboard is not just an explorer but also a wallet and more ... 🛠",
|
||||||
|
@ -8,7 +8,7 @@ import updateLocale from 'dayjs/plugin/updateLocale'
|
|||||||
import utc from 'dayjs/plugin/utc'
|
import utc from 'dayjs/plugin/utc'
|
||||||
import localeData from 'dayjs/plugin/localeData'
|
import localeData from 'dayjs/plugin/localeData'
|
||||||
import { useStakingStore } from "./useStakingStore";
|
import { useStakingStore } from "./useStakingStore";
|
||||||
import { fromBase64, fromBech32, toHex } from "@cosmjs/encoding";
|
import { fromBase64, fromBech32, fromHex, toHex } from "@cosmjs/encoding";
|
||||||
import { consensusPubkeyToHexAddress } from "@/libs";
|
import { consensusPubkeyToHexAddress } from "@/libs";
|
||||||
import { useBankStore } from "./useBankStore";
|
import { useBankStore } from "./useBankStore";
|
||||||
import type { DenomTrace } from "@/types";
|
import type { DenomTrace } from "@/types";
|
||||||
@ -183,7 +183,19 @@ export const useFormatter = defineStore('formatter', {
|
|||||||
},
|
},
|
||||||
multiLine(v: string) {
|
multiLine(v: string) {
|
||||||
return v? v.replaceAll("\\n","\n"): ""
|
return v? v.replaceAll("\\n","\n"): ""
|
||||||
}
|
},
|
||||||
|
hexToString(hex: string) {
|
||||||
|
if(hex) {
|
||||||
|
return new TextDecoder().decode(fromHex(hex))
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
},
|
||||||
|
base64ToString(hex: string) {
|
||||||
|
if(hex) {
|
||||||
|
return new TextDecoder().decode(fromBase64(hex))
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
109
src/types/ibc.ts
109
src/types/ibc.ts
@ -1,4 +1,107 @@
|
|||||||
export interface DenomTrace {
|
import type { PaginatedResponse } from "."
|
||||||
"path": "string",
|
|
||||||
"base_denom": "string"
|
export interface DenomTrace {
|
||||||
|
path: string,
|
||||||
|
base_denom: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Connection {
|
||||||
|
id: string,
|
||||||
|
client_id: string,
|
||||||
|
versions: {
|
||||||
|
identifier: string,
|
||||||
|
features: string[]
|
||||||
|
}[],
|
||||||
|
state: string,
|
||||||
|
counterparty: {
|
||||||
|
client_id: string,
|
||||||
|
connection_id: string,
|
||||||
|
prefix: {
|
||||||
|
key_prefix: string
|
||||||
|
}
|
||||||
|
},
|
||||||
|
delay_period: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Channel {
|
||||||
|
state: string,
|
||||||
|
ordering: string,
|
||||||
|
counterparty: {
|
||||||
|
port_id: string,
|
||||||
|
channel_id: string
|
||||||
|
},
|
||||||
|
connection_hops: string[],
|
||||||
|
version: string,
|
||||||
|
port_id: string,
|
||||||
|
channel_id: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ClientState {
|
||||||
|
"@type": string,
|
||||||
|
chain_id: string,
|
||||||
|
trust_level: {
|
||||||
|
numerator: string,
|
||||||
|
denominator: string
|
||||||
|
},
|
||||||
|
trusting_period: string,
|
||||||
|
unbonding_period: string,
|
||||||
|
max_clock_drift: string,
|
||||||
|
frozen_height: {
|
||||||
|
revision_number: string,
|
||||||
|
revision_height: string
|
||||||
|
},
|
||||||
|
latest_height: {
|
||||||
|
revision_number: string,
|
||||||
|
revision_height: string
|
||||||
|
},
|
||||||
|
proof_specs: {
|
||||||
|
leaf_spec: {
|
||||||
|
hash: string,
|
||||||
|
prehash_key: string,
|
||||||
|
prehash_value: string,
|
||||||
|
length: string,
|
||||||
|
prefix: string
|
||||||
|
},
|
||||||
|
inner_spec: {
|
||||||
|
child_order: number[],
|
||||||
|
child_size: number,
|
||||||
|
min_prefix_length: number,
|
||||||
|
max_prefix_length: number,
|
||||||
|
empty_child: string,
|
||||||
|
hash: string
|
||||||
|
},
|
||||||
|
max_depth: number,
|
||||||
|
min_depth: number
|
||||||
|
}[],
|
||||||
|
upgrade_path: string[],
|
||||||
|
allow_update_after_expiry: boolean,
|
||||||
|
allow_update_after_misbehaviour: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ClientStateWithProof {
|
||||||
|
identified_client_state: {
|
||||||
|
client_id: string,
|
||||||
|
client_state: ClientState
|
||||||
|
},
|
||||||
|
proof: string,
|
||||||
|
proof_height: {
|
||||||
|
revision_number: string,
|
||||||
|
revision_height: string
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
export interface ConnectionWithProof {
|
||||||
|
connection: Connection,
|
||||||
|
proof: string,
|
||||||
|
proof_height: {
|
||||||
|
revision_number: string,
|
||||||
|
revision_height: string
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
export interface PaginatedIBCChannels extends PaginatedResponse {
|
||||||
|
channels: Channel[]
|
||||||
|
}
|
||||||
|
export interface PaginatedIBCConnections extends PaginatedResponse {
|
||||||
|
connections: Connection[]
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user