forked from LaconicNetwork/cosmos-explorer
Merge remote-tracking branch 'upstream/master' into v3-single
This commit is contained in:
@@ -32,7 +32,7 @@ const addFavor = (e: Event) => {
|
||||
<div class="w-8 h-8 rounded-full overflow-hidden">
|
||||
<img :src="conf.logo" />
|
||||
</div>
|
||||
<div class="font-semibold ml-4 text-base flex-1">
|
||||
<div class="font-semibold ml-4 text-base flex-1 truncate">
|
||||
{{ conf?.prettyName || props.name }}
|
||||
</div>
|
||||
<div
|
||||
|
||||
@@ -22,7 +22,7 @@ const header = computed(() => {
|
||||
<VTable
|
||||
v-if="header.length > 0"
|
||||
density="compact"
|
||||
height="300px"
|
||||
:height="value.length > 5? '300px': ''"
|
||||
fixed-header
|
||||
hover
|
||||
>
|
||||
|
||||
@@ -5,10 +5,10 @@ const props = defineProps(['value']);
|
||||
</script>
|
||||
<template>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="table w-full text-sm">
|
||||
<table class="table table-compact w-full text-sm">
|
||||
<tbody>
|
||||
<tr v-for="(v, k) of value">
|
||||
<td class="text-capitalize" style="max-width: 100px">{{ String(k).replaceAll("_", " ") }}</td>
|
||||
<td class="text-capitalize whitespace-break-spaces w-1/5" style="min-width: 180px;">{{ String(k).replaceAll("_", " ") }}</td>
|
||||
<td>
|
||||
<div
|
||||
class="overflow-hidden w-auto whitespace-normal"
|
||||
|
||||
@@ -13,6 +13,7 @@ import { useDashboard } from '@/stores/useDashboard';
|
||||
import NavBarI18n from './NavBarI18n.vue';
|
||||
import NavBarWallet from './NavBarWallet.vue';
|
||||
import { useBlockchain } from '@/stores';
|
||||
import { computed } from 'vue';
|
||||
|
||||
const { appRouteTransition } = useThemeConfig();
|
||||
|
||||
@@ -34,6 +35,7 @@ const changeOpen = (index: Number) => {
|
||||
sidebarOpen.value = !sidebarOpen.value;
|
||||
}
|
||||
};
|
||||
const showDiscord = window.location.host.search("ping.pub") > -1
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -92,7 +94,7 @@ const changeOpen = (index: Number) => {
|
||||
</div>
|
||||
<div
|
||||
v-if="item?.badgeContent"
|
||||
class="mr-6 badge badge-sm badge-primary"
|
||||
class="mr-6 badge badge-sm rounded-none" :class="item?.badgeClass"
|
||||
>
|
||||
{{ item?.badgeContent }}
|
||||
</div>
|
||||
@@ -137,7 +139,7 @@ const changeOpen = (index: Number) => {
|
||||
|
||||
<RouterLink
|
||||
:to="item?.to"
|
||||
v-if="item?.title && !item?.children?.length"
|
||||
v-if="item?.title && !item?.children?.length && item?.to"
|
||||
@click="sidebarShow = false"
|
||||
class="collapse-title px-4 flex items-center py-2 hover:bg-gray-100 dark:hover:bg-[#373f59]"
|
||||
>
|
||||
@@ -162,7 +164,7 @@ const changeOpen = (index: Number) => {
|
||||
</div>
|
||||
<div
|
||||
v-if="item?.badgeContent"
|
||||
class="mr-6 badge badge-sm badge-primary"
|
||||
class="mr-6 badge badge-sm" :class="item?.badgeClass"
|
||||
>
|
||||
{{ item?.badgeContent }}
|
||||
</div>
|
||||
@@ -174,6 +176,45 @@ const changeOpen = (index: Number) => {
|
||||
{{ item?.heading }}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="px-4 text-sm pt-4 text-gray-400 pb-2 uppercase">
|
||||
Sponsors
|
||||
</div>
|
||||
<a href="https://osmosis.zone" class="collapse-title px-4 flex items-center py-2 hover:bg-gray-100 dark:hover:bg-[#373f59]">
|
||||
<img src="https://ping.pub/logos/osmosis.jpg" class="w-6 h-6 rounded-full mr-3"/>
|
||||
<div class="text-base capitalize flex-1 text-gray-700 dark:text-gray-200">
|
||||
Osmosis
|
||||
</div>
|
||||
</a>
|
||||
<a href="https://becole.com" class="collapse-title px-4 flex items-center py-2 hover:bg-gray-100 dark:hover:bg-[#373f59]">
|
||||
<img src="https://becole.com/static/logo/logo_becole.png" class="w-6 h-6 rounded-full mr-3"/>
|
||||
<div class="text-base capitalize flex-1 text-gray-700 dark:text-gray-200">
|
||||
Becole
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<div class="px-4 text-sm pt-4 text-gray-400 pb-2 uppercase">
|
||||
Links
|
||||
</div>
|
||||
<a href="https://twitter.com/ping_pub" class="collapse-title px-4 flex items-center py-2 hover:bg-gray-100 dark:hover:bg-[#373f59]">
|
||||
<Icon icon="mdi:twitter" class="text-xl mr-2"/>
|
||||
<div class="text-base capitalize flex-1 text-gray-700 dark:text-gray-200">
|
||||
Twitter
|
||||
</div>
|
||||
</a>
|
||||
<a v-if="showDiscord" href="https://discord.com/invite/CmjYVSr6GW" class="collapse-title px-4 flex items-center py-2 hover:bg-gray-100 dark:hover:bg-[#373f59]">
|
||||
<Icon icon="mdi:discord" class="text-xl mr-2"/>
|
||||
<div class="text-base capitalize flex-1 text-gray-700 dark:text-gray-200">
|
||||
Discord
|
||||
</div>
|
||||
</a>
|
||||
<a href="https://github.com/ping-pub/explorer/discussions" class="collapse-title px-4 flex items-center py-2 hover:bg-gray-100 dark:hover:bg-[#373f59]">
|
||||
<Icon icon="mdi:frequently-asked-questions" class="text-xl mr-2"/>
|
||||
<div class="text-base capitalize flex-1 text-gray-700 dark:text-gray-200">
|
||||
FAQ
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="xl:ml-64 px-5">
|
||||
<!-- header -->
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import { useWalletStore } from '@/stores';
|
||||
import type { Icon } from '@iconify/vue';
|
||||
import { ref, computed } from 'vue';
|
||||
const walletStore = useWalletStore();
|
||||
walletStore.$subscribe((m, s) => {
|
||||
console.log(m, s);
|
||||
});
|
||||
// walletStore.$subscribe((m, s) => {
|
||||
// console.log(m, s);
|
||||
// });
|
||||
function walletStateChange(res: any) {
|
||||
walletStore.setConnectedWallet(res.detail?.value);
|
||||
}
|
||||
@@ -105,7 +106,7 @@ const addressChange = computed(() => {
|
||||
<ping-connect-wallet
|
||||
:chain-id="'juno-1'"
|
||||
:hd-path="`m/44'/118/0'/0/0`"
|
||||
@change="walletStateChange"
|
||||
@connect="walletStateChange"
|
||||
/>
|
||||
</Teleport>
|
||||
</div>
|
||||
|
||||
@@ -30,7 +30,7 @@ import type {
|
||||
PaginatedProposals,
|
||||
Tally,
|
||||
} from '@/types/gov';
|
||||
import type { PaginatedSigningInfo } from '@/types/slashing';
|
||||
import type { PaginatedSigningInfo, SlashingParam } from '@/types/slashing';
|
||||
import type {
|
||||
Delegation,
|
||||
PaginatedDelegations,
|
||||
@@ -90,7 +90,7 @@ export interface RequestRegistry extends AbstractRegistry {
|
||||
}>;
|
||||
mint_annual_provisions: Request<{ annual_provisions: string }>;
|
||||
|
||||
slashing_params: Request<any>;
|
||||
slashing_params: Request<{params: SlashingParam}>;
|
||||
slashing_signing_info: Request<PaginatedSigningInfo>;
|
||||
|
||||
gov_params_voting: Request<GovParams>;
|
||||
|
||||
+8
-2
@@ -9,7 +9,7 @@ import { loadFonts } from '@/plugins/vuetify/webfontloader';
|
||||
import '@/plugins/vuetify/@core/scss/template/index.scss';
|
||||
import '@/plugins/vuetify/styles/styles.scss';
|
||||
import '@/style.css';
|
||||
import { createApp } from 'vue';
|
||||
import { createApp, ref } from 'vue';
|
||||
import { createPinia } from 'pinia';
|
||||
import LazyLoad from 'lazy-load-vue3';
|
||||
// import router from "@/plugins/vuetify/router";
|
||||
@@ -32,4 +32,10 @@ app.mount('#app');
|
||||
|
||||
// fetch latest block every 6s
|
||||
const blockStore = useBaseStore()
|
||||
setInterval(() => {blockStore.fetchLatest()}, 6000)
|
||||
const requestCounter = ref(0)
|
||||
setInterval(() => {
|
||||
requestCounter.value += 1
|
||||
if(requestCounter.value < 5) { // max allowed request
|
||||
blockStore.fetchLatest().finally(() => requestCounter.value -= 1)
|
||||
}
|
||||
}, 6000)
|
||||
|
||||
@@ -458,8 +458,10 @@ loadAccount(props.address);
|
||||
v.height
|
||||
}}</RouterLink>
|
||||
</td>
|
||||
<td class="text-truncate py-3" style="max-width: 200px">
|
||||
<td class="text-truncate text-primary py-3" style="max-width: 200px">
|
||||
<RouterLink :to="`/${chain}/tx/${v.txhash}`">
|
||||
{{ v.txhash }}
|
||||
</RouterLink>
|
||||
</td>
|
||||
<td class="flex items-center py-3">
|
||||
<div class="mr-2">
|
||||
|
||||
@@ -8,6 +8,12 @@ const tab = ref('blocks');
|
||||
const base = useBaseStore()
|
||||
|
||||
const format = useFormatter();
|
||||
|
||||
const list = computed(() => {
|
||||
// const recents = base.recents
|
||||
// return recents.sort((a, b) => (Number(b.block.header.height) - Number(a.block.header.height)))
|
||||
return base.recents
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
@@ -26,41 +32,35 @@ const format = useFormatter();
|
||||
>
|
||||
</div>
|
||||
|
||||
<div v-show="tab === 'blocks'" class="bg-base-100 rounded overflow-x-auto">
|
||||
<table class="table w-full">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="position: relative; z-index: 2;">Height</th>
|
||||
<th>Hash</th>
|
||||
<th>Proposer</th>
|
||||
<th>Txs</th>
|
||||
<th>Time</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody v-if="base.recents && base.recents.length > 0" >
|
||||
<tr v-for="(item, index) in base.recents" :key="index">
|
||||
<td class="text-sm text-primary">
|
||||
<RouterLink
|
||||
:to="`/${props.chain}/block/${item.block?.header?.height}`"
|
||||
>{{ item.block?.header?.height }}</RouterLink
|
||||
>
|
||||
</td>
|
||||
<td>{{ item.block_id?.hash }}</td>
|
||||
<td>
|
||||
{{ format.validator(item.block?.header?.proposer_address) }}
|
||||
</td>
|
||||
<td>{{ item.block?.data?.txs.length }}</td>
|
||||
<td>{{ format.toDay(item.block?.header?.time, 'from') }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div v-show="tab === 'blocks'" class="grid xl:grid-cols-6 md:grid-cols-4 grid-cols-1">
|
||||
|
||||
<RouterLink
|
||||
v-for="item in list"
|
||||
class="flex flex-col justify-between rounded border border-gray-100 m-2 p-4 shadow-xl bg-base-100"
|
||||
:to="`/${chain}/block/${item.block.header.height}`"
|
||||
>
|
||||
<div class="flex justify-between">
|
||||
<h3 class="text-md font-bold sm:text-lg">
|
||||
{{ item.block.header.height }}
|
||||
</h3>
|
||||
<span class="rounded text-xs whitespace-nowrap font-medium text-green-600">
|
||||
{{ format.toDay(item.block?.header?.time, 'from') }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex justify-between tooltip" data-tip="Block Proposor">
|
||||
<div class="mt-2 hidden text-sm sm:block truncate">
|
||||
<span>{{ format.validator(item.block?.header?.proposer_address) }}</span>
|
||||
</div>
|
||||
<span class="text-right mt-1 whitespace-nowrap"> {{ item.block?.data?.txs.length }} txs </span>
|
||||
</div>
|
||||
</RouterLink>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-show="tab === 'transactions'"
|
||||
class="bg-base-100 rounded overflow-x-auto"
|
||||
>
|
||||
<table class="table w-full">
|
||||
<table class="table w-full table-compact">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="position: relative; z-index: 2;">Height</th>
|
||||
@@ -71,8 +71,12 @@ const format = useFormatter();
|
||||
</thead>
|
||||
<tbody >
|
||||
<tr v-for="(item,index) in base.txsInRecents" :index="index">
|
||||
<td>{{ item.height }}</td>
|
||||
<td class="text-xs truncate" width="50%">
|
||||
<td class="text-sm text-primary">
|
||||
<RouterLink
|
||||
:to="`/${props.chain}/block/${item.height}`"
|
||||
>{{ item.height }}</RouterLink
|
||||
></td>
|
||||
<td class="truncate text-primary" width="50%">
|
||||
<RouterLink :to="`/${props.chain}/tx/${item.hash}`">{{
|
||||
item.hash
|
||||
}}</RouterLink>
|
||||
|
||||
@@ -71,7 +71,7 @@ function color(v: string) {
|
||||
{
|
||||
meta: {
|
||||
i18n: 'ibc',
|
||||
order: 8
|
||||
order: 9
|
||||
}
|
||||
}
|
||||
</route>
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
useTxDialog,
|
||||
useWalletStore,
|
||||
useStakingStore,
|
||||
useParamStore,
|
||||
} from '@/stores';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { useIndexModule } from './indexStore';
|
||||
@@ -16,6 +17,9 @@ import { computed } from '@vue/reactivity';
|
||||
|
||||
import CardStatisticsVertical from '@/components/CardStatisticsVertical.vue';
|
||||
import ProposalListItem from '@/components/ProposalListItem.vue';
|
||||
import ArrayObjectElement from '@/components/dynamic/ArrayObjectElement.vue'
|
||||
|
||||
const props = defineProps(['chain']);
|
||||
|
||||
const blockchain = useBlockchain();
|
||||
const store = useIndexModule();
|
||||
@@ -23,6 +27,7 @@ const walletStore = useWalletStore();
|
||||
const format = useFormatter();
|
||||
const dialog = useTxDialog();
|
||||
const stakingStore = useStakingStore();
|
||||
const paramStore = useParamStore()
|
||||
const coinInfo = computed(() => {
|
||||
return store.coinInfo;
|
||||
});
|
||||
@@ -30,6 +35,9 @@ const coinInfo = computed(() => {
|
||||
onMounted(() => {
|
||||
store.loadDashboard();
|
||||
walletStore.loadMyAsset();
|
||||
paramStore.handleAbciInfo()
|
||||
// if(!(coinInfo.value && coinInfo.value.name)) {
|
||||
// }
|
||||
});
|
||||
const ticker = computed(() => store.coinInfo.tickers[store.tickerIndex]);
|
||||
|
||||
@@ -40,6 +48,7 @@ blockchain.$subscribe((m, s) => {
|
||||
) {
|
||||
store.loadDashboard();
|
||||
walletStore.loadMyAsset();
|
||||
paramStore.handleAbciInfo()
|
||||
}
|
||||
});
|
||||
function shortName(name: string, id: string) {
|
||||
@@ -100,8 +109,7 @@ const color = computed(() => {
|
||||
<div class="text-xl font-semibold text-main">
|
||||
{{ coinInfo.name }} (<span class="uppercase">{{
|
||||
coinInfo.symbol
|
||||
}}</span
|
||||
>)
|
||||
}}</span>)
|
||||
</div>
|
||||
<div class="text-xs mt-2">
|
||||
Rank:
|
||||
@@ -229,7 +237,7 @@ const color = computed(() => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-base-100 rounded mt-4 shadow">
|
||||
<div v-if="blockchain.supportModule('governance')" class="bg-base-100 rounded mt-4 shadow">
|
||||
<div class="px-4 pt-4 pb-2 text-lg font-semibold text-main">
|
||||
Active Proposals
|
||||
</div>
|
||||
@@ -246,8 +254,8 @@ const color = computed(() => {
|
||||
{{ walletStore.currentAddress || 'Not Connected' }}
|
||||
<RouterLink
|
||||
v-if="walletStore.currentAddress"
|
||||
class="float-right font-light text-sm cursor-pointert link link-primary no-underline font-medium"
|
||||
to="/wallet/portfolio"
|
||||
class="float-right text-sm cursor-pointert link link-primary no-underline font-medium"
|
||||
:to="`/${chain}/account/${walletStore.currentAddress}`"
|
||||
>More</RouterLink
|
||||
>
|
||||
</div>
|
||||
@@ -294,7 +302,7 @@ const color = computed(() => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="px-4 pb-4">
|
||||
<div v-if="walletStore.delegations.length > 0" class="px-4 pb-4">
|
||||
<table class="table table-compact w-full table-zebra">
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -316,27 +324,28 @@ const color = computed(() => {
|
||||
<td>{{ format.formatToken(item?.balance) }}</td>
|
||||
<td>
|
||||
{{
|
||||
format.formatToken(
|
||||
format.formatTokens(
|
||||
walletStore?.rewards?.rewards?.find(
|
||||
(el) =>
|
||||
el?.validator_address ===
|
||||
item?.delegation?.validator_address
|
||||
)?.reward?.[0]
|
||||
)
|
||||
)?.reward)
|
||||
}}
|
||||
</td>
|
||||
<td>
|
||||
<div>
|
||||
<button
|
||||
<label for="delegate"
|
||||
class="btn btn-xs btn-primary btn-ghost text-primary rounded-sm mr-2"
|
||||
@click="dialog.open('delegate', { validator_address: item.delegation.validator_address})"
|
||||
>
|
||||
Delegate
|
||||
</button>
|
||||
<button
|
||||
</label>
|
||||
<label for="withdraw"
|
||||
class="btn btn-xs btn-primary btn-ghost text-primary rounded-sm"
|
||||
@click="dialog.open('withdraw', { validator_address: item.delegation.validator_address})"
|
||||
>
|
||||
Withdraw Rewards
|
||||
</button>
|
||||
</label>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -345,13 +354,9 @@ const color = computed(() => {
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-3 gap-4 px-4 pb-6 mt-4">
|
||||
<label for="send" class="btn btn-success text-white">Send</label>
|
||||
<RouterLink to="/wallet/receive" class="btn btn-info text-white"
|
||||
>Receive</RouterLink
|
||||
>
|
||||
<label for="PingTokenConvert" class="btn btn-primary text-white"
|
||||
>Convert</label
|
||||
>
|
||||
<label for="PingTokenConvert" class="btn btn-primary text-white">Convert</label>
|
||||
<label for="send" class="btn btn-success text-white" @click="dialog.open('send', {})">Send</label>
|
||||
<RouterLink to="/wallet/receive" class="btn btn-info text-white">Receive</RouterLink>
|
||||
</div>
|
||||
<Teleport to="body">
|
||||
<ping-token-convert
|
||||
@@ -361,6 +366,21 @@ const color = computed(() => {
|
||||
></ping-token-convert>
|
||||
</Teleport>
|
||||
</div>
|
||||
|
||||
<div class="bg-base-100 rounded mt-4 shadow">
|
||||
<div class="px-4 pt-4 pb-2 text-lg font-semibold text-main">
|
||||
Application
|
||||
</div>
|
||||
<!-- Application Version -->
|
||||
<ArrayObjectElement :value="paramStore.appVersion?.items" :thead="false" />
|
||||
</div>
|
||||
|
||||
<div v-if="!store.coingeckoId" class="bg-base-100 rounded mt-4 shadow">
|
||||
<div class="px-4 pt-4 pb-2 text-lg font-semibold text-main">
|
||||
Node Information
|
||||
</div>
|
||||
<ArrayObjectElement :value="paramStore.nodeVersion?.items" :thead="false" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -87,29 +87,35 @@ export const useIndexModule = defineStore('module-index', {
|
||||
return useBankStore();
|
||||
},
|
||||
twitter(): string {
|
||||
return `https://twitter.com/${this.coinInfo.links.twitter_screen_name}`;
|
||||
if(!this.coinInfo?.links?.twitter_screen_name) return ""
|
||||
return `https://twitter.com/${this.coinInfo?.links.twitter_screen_name}`;
|
||||
},
|
||||
homepage(): string {
|
||||
const [page1, page2, page3] = this.coinInfo.links?.homepage;
|
||||
if(!this.coinInfo?.links?.homepage) return ""
|
||||
const [page1, page2, page3] = this.coinInfo?.links?.homepage;
|
||||
return page1 || page2 || page3;
|
||||
},
|
||||
github(): string {
|
||||
const [page1, page2, page3] = this.coinInfo.links?.repos_url?.github;
|
||||
if(!this.coinInfo?.links?.repos_url) return ""
|
||||
const [page1, page2, page3] = this.coinInfo?.links?.repos_url?.github;
|
||||
return page1 || page2 || page3;
|
||||
},
|
||||
telegram(): string {
|
||||
return `https://t.me/${this.coinInfo.links.telegram_channel_identifier}`;
|
||||
if(!this.coinInfo?.links?.homepage) return ""
|
||||
return `https://t.me/${this.coinInfo?.links.telegram_channel_identifier}`;
|
||||
},
|
||||
|
||||
priceChange(): string {
|
||||
if(!this.coinInfo?.market_data?.price_change_percentage_24h) return ""
|
||||
const change =
|
||||
this.coinInfo.market_data?.price_change_percentage_24h || 0;
|
||||
this.coinInfo?.market_data?.price_change_percentage_24h || 0;
|
||||
return numeral(change).format('+0.[00]');
|
||||
},
|
||||
|
||||
priceColor(): string {
|
||||
if(!this.coinInfo?.market_data?.price_change_percentage_24h) return ""
|
||||
const change =
|
||||
this.coinInfo.market_data?.price_change_percentage_24h || 0;
|
||||
this.coinInfo?.market_data?.price_change_percentage_24h || 0;
|
||||
switch (true) {
|
||||
case change > 0:
|
||||
return 'text-success';
|
||||
@@ -120,7 +126,8 @@ export const useIndexModule = defineStore('module-index', {
|
||||
}
|
||||
},
|
||||
trustColor(): string {
|
||||
const change = this.coinInfo.tickers[this.tickerIndex]?.trust_score;
|
||||
if(!this.coinInfo?.tickers) return ""
|
||||
const change = this.coinInfo?.tickers[this.tickerIndex]?.trust_score;
|
||||
return colorMap(change);
|
||||
},
|
||||
|
||||
@@ -193,6 +200,12 @@ export const useIndexModule = defineStore('module-index', {
|
||||
},
|
||||
];
|
||||
},
|
||||
|
||||
coingeckoId() {
|
||||
this.tickerIndex = 0;
|
||||
const [firstAsset] = this.blockchain?.assets || [];
|
||||
return firstAsset.coingecko_id
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
async loadDashboard() {
|
||||
|
||||
@@ -56,7 +56,7 @@ onMounted(() => {
|
||||
{
|
||||
meta: {
|
||||
i18n: 'parameters',
|
||||
order: 10
|
||||
order: 50
|
||||
}
|
||||
}
|
||||
</route>
|
||||
|
||||
@@ -55,7 +55,6 @@ staking
|
||||
const txs = ref({} as PaginatedTxs);
|
||||
|
||||
blockchain.rpc.getTxsBySender(addresses.value.account).then((x) => {
|
||||
console.log('txs', x);
|
||||
txs.value = x;
|
||||
});
|
||||
|
||||
@@ -77,14 +76,19 @@ const selfRate = computed(() => {
|
||||
}
|
||||
return '-';
|
||||
});
|
||||
|
||||
const logo = (identity?: string) => {
|
||||
if (!identity) return '';
|
||||
const url = avatars.value[identity] || '';
|
||||
return url.startsWith('http')
|
||||
? url
|
||||
: `https://s3.amazonaws.com/keybase_processed_uploads/${url}`;
|
||||
};
|
||||
onMounted(() => {
|
||||
if (validator) {
|
||||
staking.fetchValidator(validator).then((res) => {
|
||||
v.value = res.validator;
|
||||
identity.value = res.validator?.description?.identity || '';
|
||||
if (identity.value && !avatars.value[identity.value]) {
|
||||
console.log(identity.value, avatars);
|
||||
staking.keybase(identity.value).then((d) => {
|
||||
if (Array.isArray(d.them) && d.them.length > 0) {
|
||||
const uri = String(d.them[0]?.pictures?.primary?.url).replace(
|
||||
@@ -143,9 +147,7 @@ onMounted(() => {
|
||||
<div class="w-24 rounded-lg">
|
||||
<img
|
||||
v-if="avatars[identity] !== 'undefined'"
|
||||
v-lazy="
|
||||
`https://s3.amazonaws.com/keybase_processed_uploads/${avatars[identity]}`
|
||||
"
|
||||
v-lazy="logo(identity)"
|
||||
class="object-contain"
|
||||
/>
|
||||
<Icon
|
||||
@@ -394,8 +396,10 @@ onMounted(() => {
|
||||
item.height
|
||||
}}</RouterLink>
|
||||
</td>
|
||||
<td class="text-truncate" style="max-width: 200px">
|
||||
<td class="text-truncate text-primary" style="max-width: 200px">
|
||||
<RouterLink :to="`/${props.chain}/tx/${item.txhash}`">
|
||||
{{ item.txhash }}
|
||||
</RouterLink>
|
||||
</td>
|
||||
<td>
|
||||
<div class="flex items-center">
|
||||
|
||||
@@ -58,8 +58,6 @@ async function fetchChange() {
|
||||
}
|
||||
}
|
||||
|
||||
fetchChange();
|
||||
|
||||
const changes = computed(() => {
|
||||
const changes = {} as Record<string, number>;
|
||||
Object.keys(latest.value).forEach((k) => {
|
||||
@@ -92,12 +90,6 @@ const change24Color = (key?: Key) => {
|
||||
if (v < 0) return 'text-error';
|
||||
};
|
||||
|
||||
const update = (m: DebuggerEvent) => {
|
||||
if (m.key === 'validators') {
|
||||
loadAvatars();
|
||||
}
|
||||
};
|
||||
|
||||
const list = computed(() => {
|
||||
return tab.value === 'active' ? staking.validators : unbondList.value;
|
||||
// return staking.validators
|
||||
@@ -136,15 +128,6 @@ const loadAvatars = () => {
|
||||
});
|
||||
};
|
||||
|
||||
staking.$subscribe((m, s) => {
|
||||
if (Array.isArray(m.events)) {
|
||||
m.events.forEach((x) => {
|
||||
update(x);
|
||||
});
|
||||
} else {
|
||||
update(m.events);
|
||||
}
|
||||
});
|
||||
const logo = (identity?: string) => {
|
||||
if (!identity) return '';
|
||||
const url = avatars.value[identity] || '';
|
||||
@@ -168,6 +151,10 @@ const rank = function (position: number) {
|
||||
return 'primary';
|
||||
}
|
||||
};
|
||||
|
||||
fetchChange();
|
||||
loadAvatars();
|
||||
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
|
||||
@@ -10,6 +10,15 @@ const blockchain = useBlockchain();
|
||||
const base = useBaseStore();
|
||||
const nodeInfo = ref({} as NodeInfo);
|
||||
|
||||
const height = ref(Number(base.latest.block?.header?.height|| 2001))
|
||||
const hash = ref("")
|
||||
|
||||
if(height.value > 2000) {
|
||||
height.value = Math.round((height.value - 2000) / 1000) * 1000
|
||||
base.fetchBlock(height.value).then(res => {
|
||||
hash.value = toHex(fromBase64(res.block_id.hash)).toUpperCase()
|
||||
})
|
||||
}
|
||||
const state = computed(() => {
|
||||
const rpcs = blockchain.current?.endpoints?.rpc
|
||||
?.map((x) => x.address)
|
||||
@@ -17,10 +26,8 @@ const state = computed(() => {
|
||||
return `[statesync]
|
||||
enable = true
|
||||
rpc_servers = "${rpcs}"
|
||||
trust_height = ${base.latest.block?.header?.height || 'loading'}
|
||||
trust_hash = "${
|
||||
base.latest.block_id ? toHex(fromBase64(base.latest.block_id?.hash)) : ''
|
||||
}"
|
||||
trust_height = ${height.value || 'loading'}
|
||||
trust_hash = "${hash.value}"
|
||||
trust_period = "168h" # 2/3 of unbonding time"
|
||||
`;
|
||||
});
|
||||
@@ -31,7 +38,6 @@ const appName = computed(() => {
|
||||
|
||||
onMounted(() => {
|
||||
blockchain.rpc.getBaseNodeInfo().then((x) => {
|
||||
console.log('node info', x);
|
||||
nodeInfo.value = x;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -39,7 +39,7 @@ const messages = computed(() => {
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Height</td>
|
||||
<td>
|
||||
<td class="text-primary">
|
||||
<RouterLink
|
||||
:to="`/${props.chain}/block/${tx.tx_response.height}`"
|
||||
>{{ tx.tx_response.height }}</RouterLink
|
||||
@@ -55,7 +55,7 @@ const messages = computed(() => {
|
||||
tx.tx_response.code === 0 ? 'success' : 'error'
|
||||
}`"
|
||||
>
|
||||
<span
|
||||
<span
|
||||
class="inset-x-0 inset-y-0 opacity-10 absolute"
|
||||
:class="`bg-${
|
||||
tx.tx_response.code === 0 ? 'success' : 'error'
|
||||
|
||||
@@ -155,7 +155,7 @@ function color(v: string) {
|
||||
<tr v-for="v in list">
|
||||
<td class=" capitalize">{{ v.chainName }}</td>
|
||||
<td>{{ v.v.name }}</td>
|
||||
<td><span class="badge " :class="color( v.sigingInfo?.missed_blocks_counter)">{{ v.sigingInfo?.missed_blocks_counter }}</span></td>
|
||||
<td><span v-if="v.sigingInfo" class="badge " :class="color( v.sigingInfo?.missed_blocks_counter)">{{ v.sigingInfo?.missed_blocks_counter }}</span></td>
|
||||
<td><span v-if="v.sigingInfo">{{ Number(v.sigingInfo.index_offset) - Number(v.sigingInfo.start_height) }}</span></td>
|
||||
<td>
|
||||
<div v-if="v.sigingInfo && !v.sigingInfo?.jailed_until.startsWith('1970')" class="text-xs flex flex-col">
|
||||
@@ -1,7 +1,6 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted, computed, watchEffect } from 'vue';
|
||||
import { fromHex, toBase64 } from '@cosmjs/encoding';
|
||||
import { Icon } from '@iconify/vue';
|
||||
import {
|
||||
useFormatter,
|
||||
useStakingStore,
|
||||
@@ -9,9 +8,8 @@ import {
|
||||
useBlockchain,
|
||||
} from '@/stores';
|
||||
import UptimeBar from '@/components/UptimeBar.vue';
|
||||
import type { Block, Commit } from '@/types';
|
||||
import type { Commit, SlashingParam, SigningInfo } from '@/types';
|
||||
import { consensusPubkeyToHexAddress, valconsToBase64 } from '@/libs';
|
||||
import type { SigningInfo } from '@/types/slashing';
|
||||
|
||||
const props = defineProps(['chain']);
|
||||
|
||||
@@ -23,9 +21,11 @@ const latest = ref(0);
|
||||
const commits = ref([] as Commit[]);
|
||||
const keyword = ref('');
|
||||
const live = ref(true);
|
||||
const slashingParam = ref({} as SlashingParam)
|
||||
|
||||
const signingInfo = ref({} as Record<string, SigningInfo>);
|
||||
|
||||
const filterOptout =ref(false)
|
||||
// filter validators by keywords
|
||||
const validators = computed(() => {
|
||||
if (keyword)
|
||||
@@ -36,37 +36,45 @@ const validators = computed(() => {
|
||||
});
|
||||
|
||||
const list = computed(() => {
|
||||
return validators.value.map(v => ({
|
||||
v,
|
||||
signing: signingInfo.value[consensusPubkeyToHexAddress(v.consensus_pubkey)],
|
||||
hex: toBase64(fromHex(consensusPubkeyToHexAddress(v.consensus_pubkey)))
|
||||
}))
|
||||
const window = Number(slashingParam.value.signed_blocks_window|| 0)
|
||||
const vset = validators.value.map(v => {
|
||||
const signing = signingInfo.value[consensusPubkeyToHexAddress(v.consensus_pubkey)]
|
||||
return {
|
||||
v,
|
||||
signing,
|
||||
hex: toBase64(fromHex(consensusPubkeyToHexAddress(v.consensus_pubkey))),
|
||||
uptime: signing && window > 0 ? (window - Number(signing.missed_blocks_counter)) / window: undefined
|
||||
}})
|
||||
return filterOptout.value? vset.filter(x => x.signing) : vset
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
live.value = true;
|
||||
baseStore.fetchLatest().then(b => {
|
||||
|
||||
baseStore.fetchLatest().then(l => {
|
||||
let b = l
|
||||
if(baseStore.recents?.findIndex(x => x.block_id.hash === l.block_id.hash) > -1 ) {
|
||||
b = baseStore.recents?.at(0) || l
|
||||
}
|
||||
latest.value = Number(b.block.header.height);
|
||||
commits.value.unshift(b.block.last_commit);
|
||||
const height = Number(b.block.header?.height || 0);
|
||||
if (height === 0) {
|
||||
if (height > 50) {
|
||||
// constructs sequence for loading blocks
|
||||
let promise = Promise.resolve();
|
||||
for (let i = height - 1; i > height - 50; i -= 1) {
|
||||
if (i > height - 48) {
|
||||
promise = promise.then(
|
||||
() =>
|
||||
new Promise((resolve, reject) => {
|
||||
if (live.value && commits2.value.length < 50) {
|
||||
// continue only if the page is living
|
||||
baseStore.fetchBlock(i).then((x) => {
|
||||
commits.value.unshift(x.block.last_commit);
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
promise = promise.then(
|
||||
() =>
|
||||
new Promise((resolve, reject) => {
|
||||
if (live.value && commits2.value.length < 50) {
|
||||
// continue only if the page is living
|
||||
baseStore.fetchBlock(i).then((x) => {
|
||||
commits.value.unshift(x.block.last_commit);
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -76,6 +84,10 @@ onMounted(() => {
|
||||
signingInfo.value[valconsToBase64(i.address)] = i;
|
||||
});
|
||||
});
|
||||
|
||||
chainStore.rpc.getSlashingParams().then(x => {
|
||||
slashingParam.value = x.params
|
||||
})
|
||||
});
|
||||
|
||||
const commits2 = computed(() => {
|
||||
@@ -91,7 +103,6 @@ const tab = ref("3")
|
||||
function changeTab(v: string) {
|
||||
tab.value = v
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -109,7 +120,7 @@ function changeTab(v: string) {
|
||||
@click="changeTab('2')"
|
||||
>Blocks</a
|
||||
>
|
||||
<RouterLink :to="`/${chain}/uptime/overview`">
|
||||
<RouterLink :to="`/${chain}/uptime/customize`">
|
||||
<a
|
||||
class="tab text-gray-400 capitalize"
|
||||
>Customize</a
|
||||
@@ -117,12 +128,12 @@ function changeTab(v: string) {
|
||||
</div>
|
||||
<div class="bg-base-100 px-5 pt-5">
|
||||
<div class="flex items-center gap-x-4">
|
||||
<label v-if="chainStore.isConsumerChain" class="text-center">
|
||||
<input type="checkbox" v-model="filterOptout" class="checkbox"/>
|
||||
Only Consumer Set
|
||||
</label>
|
||||
<input type="text" v-model="keyword" placeholder="Keywords to filter validators"
|
||||
class="input input-sm w-full flex-1" />
|
||||
<RouterLink class="btn btn-primary btn-sm" :to="`/${chain}/uptime/overview`">
|
||||
<Icon icon="mdi-star" class="mr-2 text-lg" />
|
||||
<span class="">Favorite</span>
|
||||
</RouterLink>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-6 gap-x-4 mt-4" :class="tab === '2'?'':'hidden'">
|
||||
<div v-for="({v, signing, hex}, i) in list" :key="i">
|
||||
@@ -130,10 +141,10 @@ function changeTab(v: string) {
|
||||
<label class="text-truncate text-sm">
|
||||
<span class="ml-1 text-black dark:text-white">{{ i + 1 }}.{{ v.description.moniker }}</span>
|
||||
</label>
|
||||
<div v-if="Number(signing?.missed_blocks_counter || 0) > 10" class="badge badge-error badge-sm text-white">
|
||||
<div v-if="Number(signing?.missed_blocks_counter || 0) > 10" class="badge badge-sm bg-transparent border-0 text-red-500">
|
||||
{{ signing?.missed_blocks_counter }}
|
||||
</div>
|
||||
<div v-else class="mt-1 badge badge-sm text-white bg-yes border-0">
|
||||
<div v-else class="badge badge-sm bg-transparent text-green-600 border-0">
|
||||
{{ signing?.missed_blocks_counter }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -143,35 +154,40 @@ function changeTab(v: string) {
|
||||
|
||||
<div :class="tab === '3'?'':'hidden'">
|
||||
<table class="table table-compact w-full mt-5">
|
||||
<thead>
|
||||
<thead class=" capitalize">
|
||||
<tr>
|
||||
<td rowspan="2">Validator</td>
|
||||
<td rowspan="2">Start Height</td>
|
||||
<td rowspan="2">Signed Blocks</td>
|
||||
<td colspan="2">Missing blocks</td>
|
||||
<td rowspan="2">Last Jailed Time</td>
|
||||
<td rowspan="2">Tombstoned</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>In Window</td>
|
||||
<td>Over All</td>
|
||||
<td>Validator</td>
|
||||
<td class="text-right">Uptime</td>
|
||||
<td>Last Jailed Time</td>
|
||||
<td class="text-right">Signed Precommits</td>
|
||||
<td class="text-right">Start Height</td>
|
||||
<td>Tombstoned</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr v-for="({v, signing}, i) in list">
|
||||
<td>{{ i+1 }}. {{ v.description.moniker }}</td>
|
||||
<td>{{ signing?.start_height }}</td>
|
||||
<td>{{ signing?.index_offset }}</td>
|
||||
<td>
|
||||
<span class="badge badge-sm text-white" :class="Number(signing?.missed_blocks_counter) < 10?'badge-success':'badge-error'">{{ signing?.missed_blocks_counter }}</span>
|
||||
<tr v-for="({v, signing, uptime}, i) in list" class="hover">
|
||||
<td><div class="truncate max-w-sm">{{ i+1 }}. {{ v.description.moniker }}</div></td>
|
||||
<td class="text-right">
|
||||
<span v-if="signing" class="" :class="uptime && uptime > 0.95 ? 'text-green-500':'text-red-500'"><div class="tooltip" :data-tip="`${signing.missed_blocks_counter} missing blocks`"> {{ format.percent(uptime) }} </div> </span>
|
||||
</td>
|
||||
<td><span v-if="signing && signing.jailed_until.startsWith('1970')">{{ format.percent(Number(signing.index_offset)/(latest-Number(signing.start_height))) }}</span></td>
|
||||
<td><span v-if="signing && !signing.jailed_until.startsWith('1970')">
|
||||
<div class="tooltip" :data-tip="format.toDay(signing?.jailed_until, 'long')">
|
||||
<span>{{ format.toDay(signing?.jailed_until, "from") }}</span>
|
||||
</div>
|
||||
</span></td>
|
||||
<td class="text-right text-xs">
|
||||
{{ signing?.index_offset }}<br>
|
||||
<span v-if="signing && signing.jailed_until.startsWith('1970')" class="text-xs">{{ format.percent(Number(signing.index_offset)/(latest-Number(signing.start_height))) }}</span>
|
||||
|
||||
</td>
|
||||
<td class="text-right">{{ signing?.start_height }}</td>
|
||||
<td class=" capitalize">{{ signing?.tombstoned }}</td>
|
||||
</tr>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td colspan="2" class="text-right"> Minimum uptime per window: <span class="lowercase tooltip" :data-tip="`Window size: ${ slashingParam.signed_blocks_window }`"><span class="ml-2 btn btn-error btn-xs">{{ format.percent(slashingParam.min_signed_per_window) }}</span> </span></td>
|
||||
<td colspan="8"></td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
<script lang="ts" setup>
|
||||
import { useBaseStore, useBlockchain, useFormatter } from '@/stores';
|
||||
import type { Connection } from '@/types';
|
||||
import { computed } from 'vue';
|
||||
import { onMounted } from 'vue';
|
||||
import { ref } from 'vue';
|
||||
|
||||
const props = defineProps(['chain']);
|
||||
const chainStore = useBlockchain();
|
||||
const baseStore = useBaseStore()
|
||||
const endpoint = ref(chainStore.current?.endpoints?.rest?.at(0)?.address)
|
||||
|
||||
const chainId = computed(() => baseStore.latest?.block?.header?.chain_id || "")
|
||||
const chainName = computed(() => chainStore?.chainName || "")
|
||||
const hdPath = computed(() => {
|
||||
return `m/44'/${ chainStore.current?.coinType }/0'/0/0`
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<div class="bg-base-100 px-4 pt-3 pb-4 rounded shadow">
|
||||
<h2 class="card-title">Initial Setting</h2>
|
||||
<div class="my-4 grid grid-flow-col auto-cols-max ">
|
||||
<div class="form-control">
|
||||
<div class="input-group">
|
||||
<span>Endpoint</span>
|
||||
<select v-model="endpoint" class="select select-bordered w-fit">
|
||||
<option disabled selected>Select Endpoint</option>
|
||||
<option v-for="v in chainStore.current?.endpoints.rest" :value="v.address">{{ v.address }}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="text-base">Import global script </span>
|
||||
<div class="mockup-code my-2">
|
||||
<pre data-prefix="1"><code class="text-gray-400"><script type="module" src="https://unpkg.com/ping-widget@latest/dist/ping-widget.js"></code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-base-100 my-5 px-4 pt-3 pb-4 rounded shadow">
|
||||
<h2 class="card-title">Widgets</h2>
|
||||
<div class="mt-4">
|
||||
<span class="text-base"> 1. Connect Wallet </span>
|
||||
<div class="mockup-code my-2">
|
||||
<pre data-prefix=">"><code class="text-gray-400"><ping-connect-wallet chain-id="{{ chainId }}" hd-path="{{ hdPath }}"/></code></pre>
|
||||
</div>
|
||||
|
||||
<span class="text-base"> 2. Osmosis Convert </span>
|
||||
<div class="mockup-code my-2">
|
||||
<pre data-prefix=">"><code class="text-gray-400"><ping-token-convert chain-name="{{ chainName }}" endpoint="{{endpoint}}" hd-path="{{hdPath}}"/></code></pre>
|
||||
<pre data-prefix=">"><code class="text-gray-400"><label for="PingTokenConvert" class="btn btn-sm">Buy {{chainName.toUpperCase()}}</label></code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<route>
|
||||
{
|
||||
meta: {
|
||||
i18n: 'widget',
|
||||
order: 300
|
||||
}
|
||||
}
|
||||
</route>
|
||||
@@ -1,13 +1,14 @@
|
||||
{
|
||||
"module": {
|
||||
"dashboard": "Dashboard",
|
||||
"blocks": "Blocks&Transaction",
|
||||
"blocks": "Blocks",
|
||||
"staking": "Staking",
|
||||
"governance": "Governance",
|
||||
"parameters": "Parameters",
|
||||
"uptime": "Uptime",
|
||||
"state-sync": "State Sync",
|
||||
"cosmwasm": "Cosmwasm",
|
||||
"widget": "Widgets",
|
||||
"ibc": "IBC"
|
||||
},
|
||||
"index": {
|
||||
|
||||
@@ -12,6 +12,7 @@ import { filterInputProps, makeVInputProps } from 'vuetify/lib/components/VInput
|
||||
import { filterInputAttrs } from 'vuetify/lib/util/helpers'
|
||||
|
||||
import { useThemeConfig } from '@core/composable/useThemeConfig'
|
||||
import { ref } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
...makeVInputProps({
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { ThemeConfig, UserThemeConfig } from './types'
|
||||
import { RouteTransitions, Skins } from '@core/enums'
|
||||
import type { UserConfig as LayoutConfig } from '@layouts/types'
|
||||
import { ref } from 'vue';
|
||||
|
||||
export const defineThemeConfig = (
|
||||
userConfig: UserThemeConfig,
|
||||
|
||||
@@ -9,6 +9,7 @@ import type { NavGroup, NavLink, NavSectionTitle, VerticalNavItems } from '@layo
|
||||
|
||||
import { themeConfig as config } from '@themeConfig'
|
||||
|
||||
console.log("v nav")
|
||||
interface Props {
|
||||
tag?: string | Component
|
||||
navItems: VerticalNavItems
|
||||
|
||||
@@ -4,6 +4,7 @@ import { TransitionExpand, VerticalNavLink } from '@layouts/components'
|
||||
import { themeConfig as config } from '@themeConfig'
|
||||
import type { NavGroup } from '@layouts/types'
|
||||
import { isNavGroupActive, openGroups } from '@layouts/utils'
|
||||
import { ref } from 'vue'
|
||||
|
||||
const props = defineProps<{
|
||||
item: NavGroup
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import type { MaybeRef } from '@vueuse/shared'
|
||||
import type { Ref } from 'vue'
|
||||
import { computed, unref, type Ref, ref, watch } from 'vue'
|
||||
import { AppContentLayoutNav, NavbarType } from '../enums'
|
||||
import { themeConfig as config } from '@themeConfig'
|
||||
import { injectionKeyIsVerticalNavHovered } from '@layouts'
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
export const useLayouts = () => {
|
||||
const navbarType = computed({
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { Router } from 'vue-router'
|
||||
import type { NavGroup, NavLink, NavLinkProps } from '@layouts/types'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
export const openGroups = ref<string[]>([])
|
||||
|
||||
@@ -8,6 +9,7 @@ export const openGroups = ref<string[]>([])
|
||||
* @param {Object, String} item navigation routeName or route Object provided in navigation data
|
||||
*/
|
||||
export const getComputedNavLinkToProp = computed(() => (link: NavLink) => {
|
||||
console.log(link)
|
||||
const props: NavLinkProps = {
|
||||
target: link.target,
|
||||
rel: link.rel,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { defineStore } from 'pinia';
|
||||
|
||||
export const useStoreName = defineStore('bankstore', {
|
||||
export const useStoreName = defineStore('template', {
|
||||
state: () => {
|
||||
return {};
|
||||
},
|
||||
|
||||
@@ -78,7 +78,7 @@ export const useBaseStore = defineStore('baseStore', {
|
||||
) === -1
|
||||
) {
|
||||
if (this.recents.length >= 50) {
|
||||
this.recents.pop();
|
||||
this.recents.shift();
|
||||
}
|
||||
this.recents.push(this.latest);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import { useTheme } from 'vuetify';
|
||||
import {
|
||||
useDashboard,
|
||||
type ChainConfig,
|
||||
@@ -14,6 +15,7 @@ import {
|
||||
useGovStore,
|
||||
useMintStore,
|
||||
useStakingStore,
|
||||
useWalletStore,
|
||||
} from '.';
|
||||
import { useBlockModule } from '@/modules/[chain]/block/block';
|
||||
import { DEFAULT } from '@/libs';
|
||||
@@ -50,6 +52,10 @@ export const useBlockchain = defineStore('blockchain', {
|
||||
dashboard() {
|
||||
return useDashboard();
|
||||
},
|
||||
isConsumerChain() {
|
||||
// @ts-ignore
|
||||
return this.current && this.current.providerChain
|
||||
},
|
||||
computedChainMenu() {
|
||||
let currNavItem: VerticalNavItems = [];
|
||||
|
||||
@@ -61,8 +67,11 @@ export const useBlockchain = defineStore('blockchain', {
|
||||
title: this.current?.prettyName || this.chainName || '',
|
||||
icon: { image: this.current.logo, size: '22' },
|
||||
i18n: false,
|
||||
badgeContent: this.isConsumerChain? 'Consumer': undefined,
|
||||
badgeClass: 'bg-error',
|
||||
children: routes
|
||||
.filter((x) => x.meta.i18n)
|
||||
.filter((x) => x.meta.i18n) // defined menu name
|
||||
.filter((x) => !this.current?.features || this.current.features.includes(String(x.meta.i18n))) // filter none-custom module
|
||||
.map((x) => ({
|
||||
title: `module.${x.meta.i18n}`,
|
||||
to: { path: x.path.replace(':chain', this.chainName) },
|
||||
@@ -112,6 +121,11 @@ export const useBlockchain = defineStore('blockchain', {
|
||||
},
|
||||
actions: {
|
||||
async initial() {
|
||||
// this.current?.themeColor {
|
||||
// const { global } = useTheme();
|
||||
// global.current
|
||||
// }
|
||||
useWalletStore().$reset()
|
||||
await this.randomSetupEndpoint();
|
||||
await useStakingStore().init();
|
||||
useBankStore().initial();
|
||||
@@ -146,5 +160,8 @@ export const useBlockchain = defineStore('blockchain', {
|
||||
this.chainName = name;
|
||||
}
|
||||
},
|
||||
supportModule(mod: string) {
|
||||
return !this.current?.features || this.current.features.includes(mod)
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -61,6 +61,7 @@ export interface ChainConfig {
|
||||
coinType: string;
|
||||
assets: Asset[];
|
||||
themeColor?: string;
|
||||
features?: string[]
|
||||
endpoints: {
|
||||
rest?: Endpoint[];
|
||||
rpc?: Endpoint[];
|
||||
@@ -74,12 +75,18 @@ export interface ChainConfig {
|
||||
};
|
||||
exponent: string;
|
||||
excludes?: string;
|
||||
providerChain: {
|
||||
api: Endpoint[]
|
||||
};
|
||||
}
|
||||
|
||||
export interface LocalConfig {
|
||||
addr_prefix: string;
|
||||
alias: string;
|
||||
api: string[] | Endpoint[];
|
||||
provider_chain: {
|
||||
api: string[] | Endpoint[]
|
||||
}
|
||||
assets: {
|
||||
base: string;
|
||||
coingecko_id: string;
|
||||
@@ -90,10 +97,12 @@ export interface LocalConfig {
|
||||
chain_name: string;
|
||||
coin_type: string;
|
||||
logo: string;
|
||||
theme_color?: string;
|
||||
min_tx_fee: string;
|
||||
rpc: string[] | Endpoint[];
|
||||
sdk_version: string;
|
||||
registry_name?: string;
|
||||
features?: string[];
|
||||
}
|
||||
|
||||
function apiConverter(api: any[]) {
|
||||
@@ -135,6 +144,12 @@ export function fromLocal(lc: LocalConfig): ChainConfig {
|
||||
rest: apiConverter(lc.api),
|
||||
rpc: apiConverter(lc.rpc),
|
||||
};
|
||||
if(lc.provider_chain) {
|
||||
conf.providerChain = {
|
||||
api: apiConverter(lc.provider_chain.api)
|
||||
}
|
||||
}
|
||||
conf.features = lc.features
|
||||
conf.logo = lc.logo;
|
||||
return conf;
|
||||
}
|
||||
|
||||
@@ -156,7 +156,6 @@ export const useParamStore = defineStore('paramstore', {
|
||||
// this.chain.items[chainIndex].value = `${percent(res)}%`
|
||||
// })
|
||||
const res = await this.getMintParam();
|
||||
console.log(res, 'mint');
|
||||
},
|
||||
async handleSlashingParams() {
|
||||
const res = await this.getSlashingParams();
|
||||
@@ -200,7 +199,6 @@ export const useParamStore = defineStore('paramstore', {
|
||||
this.nodeVersion.items = Object.entries(res.default_node_info).map(
|
||||
([key, value]) => ({ subtitle: key, value: value })
|
||||
);
|
||||
console.log('handleAbciInfo', this.nodeVersion.items);
|
||||
},
|
||||
async getBaseTendermintBlockLatest() {
|
||||
return await this.blockchain.rpc?.getBaseBlockLatest();
|
||||
|
||||
@@ -3,6 +3,9 @@ import { useBlockchain } from './useBlockchain';
|
||||
|
||||
import { get } from '@/libs/http';
|
||||
import type { StakingParam, StakingPool, Validator } from '@/types';
|
||||
import { CosmosRestClient } from '@/libs/client';
|
||||
import { consensusPubkeyToHexAddress, valconsToBase64 } from '@/libs';
|
||||
import { toHex, fromBase64 } from '@cosmjs/encoding';
|
||||
|
||||
export const useStakingStore = defineStore('stakingStore', {
|
||||
state: () => {
|
||||
@@ -77,6 +80,20 @@ export const useStakingStore = defineStore('stakingStore', {
|
||||
);
|
||||
},
|
||||
async fetchValidators(status: string) {
|
||||
if(this.blockchain.isConsumerChain) {
|
||||
if(this.blockchain.current?.providerChain.api && this.blockchain.current.providerChain.api.length > 0) {
|
||||
const client = CosmosRestClient.newDefault(this.blockchain.current.providerChain.api[0].address)
|
||||
// const vals = await client.getBaseValidatorsetLatest(0)
|
||||
const res = await client.getStakingValidators(status)
|
||||
const proVals = res.validators.sort(
|
||||
(a, b) => Number(b.delegator_shares) - Number(a.delegator_shares)
|
||||
)
|
||||
if (status === 'BOND_STATUS_BONDED') {
|
||||
this.validators = proVals;
|
||||
}
|
||||
return proVals
|
||||
}
|
||||
}
|
||||
return this.blockchain.rpc?.getStakingValidators(status).then((res) => {
|
||||
const vals = res.validators.sort(
|
||||
(a, b) => Number(b.delegator_shares) - Number(a.delegator_shares)
|
||||
@@ -89,3 +106,5 @@ export const useStakingStore = defineStore('stakingStore', {
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
|
||||
+2
-1
@@ -7,4 +7,5 @@ export * from './distribution'
|
||||
export * from './gov'
|
||||
export * from './staking'
|
||||
export * from './tx'
|
||||
export * from './ibc'
|
||||
export * from './ibc'
|
||||
export * from './slashing'
|
||||
+14
-6
@@ -1,14 +1,22 @@
|
||||
import type { PaginatedResponse } from "./common";
|
||||
|
||||
export interface SigningInfo {
|
||||
"address": string,
|
||||
"start_height": string,
|
||||
"index_offset": string,
|
||||
"jailed_until": string,
|
||||
"tombstoned": boolean,
|
||||
"missed_blocks_counter": string
|
||||
address: string,
|
||||
start_height: string,
|
||||
index_offset: string,
|
||||
jailed_until: string,
|
||||
tombstoned: boolean,
|
||||
missed_blocks_counter: string
|
||||
}
|
||||
|
||||
export interface SlashingParam{
|
||||
signed_blocks_window: string,
|
||||
min_signed_per_window: string,
|
||||
downtime_jail_duration: string,
|
||||
slash_fraction_double_sign: string,
|
||||
slash_fraction_downtime: string
|
||||
}
|
||||
|
||||
export interface PaginatedSigningInfo extends PaginatedResponse {
|
||||
info: SigningInfo[]
|
||||
}
|
||||
Reference in New Issue
Block a user