feat: format code
This commit is contained in:
parent
b17d6fd6bf
commit
5c3118116f
6
.idea/vcs.xml
generated
6
.idea/vcs.xml
generated
@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
106
.idea/workspace.xml
generated
106
.idea/workspace.xml
generated
@ -1,106 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="AutoImportSettings">
|
||||
<option name="autoReloadType" value="SELECTIVE" />
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="863a12bf-d142-4126-a636-76cbfb7ec337" name="Changes" comment="" />
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
</component>
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="MacroExpansionManager">
|
||||
<option name="directoryName" value="scny7heo" />
|
||||
</component>
|
||||
<component name="MarkdownSettingsMigration">
|
||||
<option name="stateVersion" value="1" />
|
||||
</component>
|
||||
<component name="MavenImportPreferences">
|
||||
<option name="generalSettings">
|
||||
<MavenGeneralSettings>
|
||||
<option name="mavenHome" value="$APPLICATION_HOME_DIR$/plugins/maven/lib/maven3" />
|
||||
</MavenGeneralSettings>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectId" id="2MyxeMOFrRrG7rSZlmfjzrCBu0L" />
|
||||
<component name="ProjectViewState">
|
||||
<option name="showLibraryContents" value="true" />
|
||||
</component>
|
||||
<component name="PropertiesComponent">{
|
||||
"keyToString": {
|
||||
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"last_opened_file_path": "/Users/ping/workspace/dashboard"
|
||||
}
|
||||
}</component>
|
||||
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
|
||||
<component name="SvnConfiguration">
|
||||
<configuration>$USER_HOME$/.subversion</configuration>
|
||||
</component>
|
||||
<component name="TaskManager">
|
||||
<task active="true" id="Default" summary="Default task">
|
||||
<changelist id="863a12bf-d142-4126-a636-76cbfb7ec337" name="Changes" comment="" />
|
||||
<created>1678753718354</created>
|
||||
<option name="number" value="Default" />
|
||||
<option name="presentableId" value="Default" />
|
||||
<updated>1678753718354</updated>
|
||||
</task>
|
||||
<servers />
|
||||
</component>
|
||||
<component name="Vcs.Log.History.Properties">
|
||||
<option name="COLUMN_ID_ORDER">
|
||||
<list>
|
||||
<option value="Default.Root" />
|
||||
<option value="Default.Author" />
|
||||
<option value="Default.Date" />
|
||||
<option value="Default.Subject" />
|
||||
<option value="Space.CommitStatus" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="Vcs.Log.Tabs.Properties">
|
||||
<option name="TAB_STATES">
|
||||
<map>
|
||||
<entry key="9c0ade11-225d-412a-bada-509908951784">
|
||||
<value>
|
||||
<State>
|
||||
<option name="SHOW_ONLY_AFFECTED_CHANGES" value="true" />
|
||||
<option name="FILTERS">
|
||||
<map>
|
||||
<entry key="branch">
|
||||
<value>
|
||||
<list>
|
||||
<option value="HEAD" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="roots">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
</map>
|
||||
</option>
|
||||
</State>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="MAIN">
|
||||
<value>
|
||||
<State />
|
||||
</value>
|
||||
</entry>
|
||||
</map>
|
||||
</option>
|
||||
<option name="OPEN_GENERIC_TABS">
|
||||
<map>
|
||||
<entry key="9c0ade11-225d-412a-bada-509908951784" value="TOOL_WINDOW" />
|
||||
</map>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
34
src/App.vue
34
src/App.vue
@ -1,26 +1,34 @@
|
||||
<script setup lang="ts">
|
||||
import { useTheme } from 'vuetify'
|
||||
import { useThemeConfig } from '@/plugins/vuetify/@core/composable/useThemeConfig'
|
||||
import { hexToRgb } from '@/plugins/vuetify/@layouts/utils'
|
||||
import { themeChange } from 'theme-change'
|
||||
import { onMounted } from 'vue'
|
||||
const { syncInitialLoaderTheme, syncVuetifyThemeWithTheme: syncConfigThemeWithVuetifyTheme, isAppRtl } = useThemeConfig()
|
||||
import { useTheme } from 'vuetify';
|
||||
import { useThemeConfig } from '@/plugins/vuetify/@core/composable/useThemeConfig';
|
||||
import { hexToRgb } from '@/plugins/vuetify/@layouts/utils';
|
||||
import { themeChange } from 'theme-change';
|
||||
import { onMounted } from 'vue';
|
||||
const {
|
||||
syncInitialLoaderTheme,
|
||||
syncVuetifyThemeWithTheme: syncConfigThemeWithVuetifyTheme,
|
||||
isAppRtl,
|
||||
} = useThemeConfig();
|
||||
|
||||
const { global } = useTheme()
|
||||
const { global } = useTheme();
|
||||
|
||||
// ℹ️ Sync current theme with initial loader theme
|
||||
syncInitialLoaderTheme()
|
||||
syncConfigThemeWithVuetifyTheme()
|
||||
syncInitialLoaderTheme();
|
||||
syncConfigThemeWithVuetifyTheme();
|
||||
|
||||
onMounted(()=> {
|
||||
themeChange(false)
|
||||
})
|
||||
onMounted(() => {
|
||||
themeChange(false);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VLocaleProvider :rtl="isAppRtl">
|
||||
<!-- ℹ️ This is required to set the background color of active nav link based on currently active global theme's primary -->
|
||||
<VApp :style="`--v-global-theme-primary: ${hexToRgb(global.current.value.colors.primary)}`">
|
||||
<VApp
|
||||
:style="`--v-global-theme-primary: ${hexToRgb(
|
||||
global.current.value.colors.primary
|
||||
)}`"
|
||||
>
|
||||
<RouterView />
|
||||
</VApp>
|
||||
</VLocaleProvider>
|
||||
|
@ -1,26 +1,26 @@
|
||||
<script lang="ts" setup>
|
||||
import type { PropType } from 'vue';
|
||||
import { useFormatter } from "@/stores";
|
||||
import { useFormatter } from '@/stores';
|
||||
const props = defineProps({
|
||||
cardItem: {
|
||||
type: Object as PropType<{ title: string; items: Array<any> }>,
|
||||
},
|
||||
});
|
||||
|
||||
const formatter = useFormatter()
|
||||
function calculateValue(value: any){
|
||||
if (Array.isArray(value) ){
|
||||
return (value[0] && value[0].amount)|| '-'
|
||||
const formatter = useFormatter();
|
||||
function calculateValue(value: any) {
|
||||
if (Array.isArray(value)) {
|
||||
return (value[0] && value[0].amount) || '-';
|
||||
}
|
||||
const newValue = Number(value)
|
||||
if(`${newValue}` === 'NaN' || typeof(value) === 'boolean'){
|
||||
return value
|
||||
const newValue = Number(value);
|
||||
if (`${newValue}` === 'NaN' || typeof value === 'boolean') {
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
if (newValue < 1 && newValue > 0) {
|
||||
return formatter.formatDecimalToPercent(value)
|
||||
return formatter.formatDecimalToPercent(value);
|
||||
}
|
||||
return newValue
|
||||
return newValue;
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
|
@ -2,18 +2,21 @@
|
||||
import { controlledComputed } from '@vueuse/shared';
|
||||
|
||||
interface Props {
|
||||
title: string
|
||||
color?: string
|
||||
icon: string
|
||||
stats: number
|
||||
change?: number
|
||||
title: string;
|
||||
color?: string;
|
||||
icon: string;
|
||||
stats: number;
|
||||
change?: number;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
color: 'primary',
|
||||
})
|
||||
});
|
||||
|
||||
const isPositive = controlledComputed(() => props.change, () => Math.sign(props.change||0) === 1)
|
||||
const isPositive = controlledComputed(
|
||||
() => props.change,
|
||||
() => Math.sign(props.change || 0) === 1
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -26,16 +29,13 @@ const isPositive = controlledComputed(() => props.change, () => Math.sign(props.
|
||||
variant="tonal"
|
||||
class="me-4"
|
||||
>
|
||||
<VIcon
|
||||
:icon="props.icon"
|
||||
size="24"
|
||||
/>
|
||||
<VIcon :icon="props.icon" size="24" />
|
||||
</VAvatar>
|
||||
|
||||
<div class="d-flex flex-column">
|
||||
<div class="d-flex align-center flex-wrap">
|
||||
<h6 class="text-h6">
|
||||
{{ (props.stats) }}
|
||||
{{ props.stats }}
|
||||
</h6>
|
||||
<div
|
||||
v-if="props.change"
|
||||
|
@ -21,7 +21,13 @@ const isPositive = controlledComputed(
|
||||
<template>
|
||||
<VCard class="h-full flex-col content-between">
|
||||
<VCardText class="d-flex align-center justify-between">
|
||||
<VAvatar v-if="props.icon" rounded size="38" variant="tonal" :color="props.color">
|
||||
<VAvatar
|
||||
v-if="props.icon"
|
||||
rounded
|
||||
size="38"
|
||||
variant="tonal"
|
||||
:color="props.color"
|
||||
>
|
||||
<VIcon :icon="props.icon" size="24" />
|
||||
</VAvatar>
|
||||
|
||||
|
@ -1,19 +1,22 @@
|
||||
<script setup lang="ts">
|
||||
interface Props {
|
||||
title: string
|
||||
subtitle: string
|
||||
stats: string
|
||||
change: number
|
||||
image: string
|
||||
imgWidth: number
|
||||
color?: string
|
||||
title: string;
|
||||
subtitle: string;
|
||||
stats: string;
|
||||
change: number;
|
||||
image: string;
|
||||
imgWidth: number;
|
||||
color?: string;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
color: 'primary',
|
||||
})
|
||||
});
|
||||
|
||||
const isPositive = controlledComputed(() => props.change, () => Math.sign(props.change) === 1)
|
||||
const isPositive = controlledComputed(
|
||||
() => props.change,
|
||||
() => Math.sign(props.change) === 1
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -47,11 +50,7 @@ const isPositive = controlledComputed(() => props.change, () => Math.sign(props.
|
||||
<VSpacer />
|
||||
|
||||
<div class="illustrator-img">
|
||||
<VImg
|
||||
v-if="props.image"
|
||||
:src="props.image"
|
||||
:width="props.imgWidth"
|
||||
/>
|
||||
<VImg v-if="props.image" :src="props.image" :width="props.imgWidth" />
|
||||
</div>
|
||||
</VCard>
|
||||
</template>
|
||||
|
@ -1,12 +1,17 @@
|
||||
<script lang="ts" setup >
|
||||
<script lang="ts" setup>
|
||||
import VueCountdown from '@chenfengyuan/vue-countdown';
|
||||
|
||||
const props = defineProps({
|
||||
time: { type: Number},
|
||||
})
|
||||
time: { type: Number },
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<vue-countdown v-if="time" :time="time > 0? time: 0" v-slot="{ days, hours, minutes, seconds }">
|
||||
Time Remaining:{{ days }} days, {{ hours }} hours, {{ minutes }} minutes, {{ seconds }} seconds.
|
||||
</vue-countdown>
|
||||
<vue-countdown
|
||||
v-if="time"
|
||||
:time="time > 0 ? time : 0"
|
||||
v-slot="{ days, hours, minutes, seconds }"
|
||||
>
|
||||
Time Remaining:{{ days }} days, {{ hours }} hours, {{ minutes }} minutes,
|
||||
{{ seconds }} seconds.
|
||||
</vue-countdown>
|
||||
</template>
|
||||
|
@ -15,17 +15,28 @@ const props = defineProps({
|
||||
});
|
||||
const total = computed(() => props.pool?.bonded_tokens);
|
||||
const format = useFormatter();
|
||||
const yes = computed(() => format.calculatePercent(props.tally?.yes, total.value));
|
||||
const no = computed(() => format.calculatePercent(props.tally?.no, total.value));
|
||||
const abstain = computed(() => format.calculatePercent(props.tally?.abstain, total.value));
|
||||
const veto = computed(() => format.calculatePercent(props.tally?.no_with_veto, total.value));
|
||||
const yes = computed(() =>
|
||||
format.calculatePercent(props.tally?.yes, total.value)
|
||||
);
|
||||
const no = computed(() =>
|
||||
format.calculatePercent(props.tally?.no, total.value)
|
||||
);
|
||||
const abstain = computed(() =>
|
||||
format.calculatePercent(props.tally?.abstain, total.value)
|
||||
);
|
||||
const veto = computed(() =>
|
||||
format.calculatePercent(props.tally?.no_with_veto, total.value)
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="progress rounded-full h-1 text-xs flex items-center">
|
||||
<div class="h-1 bg-yes" :style="`width: ${yes}`"></div>
|
||||
<div class="h-1 bg-no" :style="`width: ${no}`"></div>
|
||||
<div class="h-1" :style="`width: ${veto}; background-color: #B71C1C;`"></div>
|
||||
<div
|
||||
class="h-1"
|
||||
:style="`width: ${veto}; background-color: #B71C1C;`"
|
||||
></div>
|
||||
<div class="h-1 bg-secondary" :style="`width: ${abstain}`"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -14,28 +14,30 @@ const {
|
||||
next: getNextThemeName,
|
||||
index: currentThemeIndex,
|
||||
} = useCycleList(
|
||||
props.themes.map(t => t.name),
|
||||
props.themes.map((t) => t.name),
|
||||
{ initialValue: theme.value }
|
||||
);
|
||||
|
||||
const changeTheme = () => {
|
||||
theme.value = getNextThemeName();
|
||||
theme.value = getNextThemeName();
|
||||
};
|
||||
|
||||
const changeMode = (val: 'dark' | 'light' | 'system') => {
|
||||
let value = val;
|
||||
if (theme.value === 'system' && window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
||||
if (
|
||||
theme.value === 'system' &&
|
||||
window.matchMedia('(prefers-color-scheme: dark)').matches
|
||||
) {
|
||||
value = 'dark';
|
||||
}
|
||||
if (value === 'dark') {
|
||||
document.documentElement.classList.add('dark');
|
||||
document.documentElement.classList.remove('light');
|
||||
|
||||
} else {
|
||||
document.documentElement.classList.add('light');
|
||||
document.documentElement.classList.remove('dark');
|
||||
}
|
||||
document.documentElement.setAttribute("data-theme", value);
|
||||
document.documentElement.setAttribute('data-theme', value);
|
||||
};
|
||||
// Update icon if theme is changed from other sources
|
||||
watch(theme, (val: 'dark' | 'light' | 'system') => {
|
||||
@ -52,10 +54,7 @@ onMounted(() => {
|
||||
|
||||
<template>
|
||||
<div class="tooltip tooltip-bottom delay-1000" :data-tip="currentThemeName">
|
||||
<button
|
||||
class="btn btn-ghost btn-circle btn-sm mx-1"
|
||||
@click="changeTheme"
|
||||
>
|
||||
<button class="btn btn-ghost btn-circle btn-sm mx-1" @click="changeTheme">
|
||||
<Icon :icon="props.themes[currentThemeIndex].icon" class="text-2xl" />
|
||||
</button>
|
||||
</div>
|
||||
|
@ -1,32 +1,37 @@
|
||||
<script lang=ts setup>
|
||||
import type { Commit } from "@/types";
|
||||
<script lang="ts" setup>
|
||||
import type { Commit } from '@/types';
|
||||
|
||||
const props = defineProps({
|
||||
blocks: { type: Array as PropType<Commit[]>},
|
||||
blocks: { type: Array as PropType<Commit[]> },
|
||||
validator: { type: String },
|
||||
})
|
||||
});
|
||||
|
||||
const bars = computed(() => {
|
||||
const uptime = Array(50).fill({height:0, color: 'bg-secondary'})
|
||||
props.blocks.forEach(element => {
|
||||
const has = element.signatures?.findIndex(sig => sig.validator_address === props.validator )
|
||||
// console.log(has, props.validato, element)
|
||||
uptime.push({
|
||||
height: element.height,
|
||||
color: has > -1 ? 'bg-success' : 'bg-error'
|
||||
})
|
||||
uptime.shift()
|
||||
const uptime = Array(50).fill({ height: 0, color: 'bg-secondary' });
|
||||
props.blocks.forEach((element) => {
|
||||
const has = element.signatures?.findIndex(
|
||||
(sig) => sig.validator_address === props.validator
|
||||
);
|
||||
// console.log(has, props.validato, element)
|
||||
uptime.push({
|
||||
height: element.height,
|
||||
color: has > -1 ? 'bg-success' : 'bg-error',
|
||||
});
|
||||
return uptime
|
||||
})
|
||||
uptime.shift();
|
||||
});
|
||||
return uptime;
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<div class="d-flex justify-evenly">
|
||||
<span v-for="(b,i) in bars"
|
||||
:key="i"
|
||||
:class="b.color"
|
||||
style="width:1.5%">
|
||||
<v-tooltip v-if="Number(b.height) > 0" activator="parent" location="top">{{ b.height }}</v-tooltip>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<div class="d-flex justify-evenly">
|
||||
<span v-for="(b, i) in bars" :key="i" :class="b.color" style="width: 1.5%"
|
||||
>
|
||||
<v-tooltip
|
||||
v-if="Number(b.height) > 0"
|
||||
activator="parent"
|
||||
location="top"
|
||||
>{{ b.height }}</v-tooltip
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -1,44 +1,61 @@
|
||||
<script setup lang="ts">
|
||||
import VueApexCharts from 'vue3-apexcharts'
|
||||
import { useTheme } from 'vuetify'
|
||||
import { hexToRgb } from '@/plugins/vuetify/@layouts/utils'
|
||||
import VueApexCharts from 'vue3-apexcharts';
|
||||
import { useTheme } from 'vuetify';
|
||||
import { hexToRgb } from '@/plugins/vuetify/@layouts/utils';
|
||||
import { computed, type PropType } from 'vue';
|
||||
import { useFormatter } from '@/stores';
|
||||
import type { CommissionRate } from '@/types'
|
||||
import type { CommissionRate } from '@/types';
|
||||
|
||||
const props = defineProps({
|
||||
commission: { type: Object as PropType<CommissionRate>},
|
||||
})
|
||||
|
||||
let rate = computed(() => Number(props.commission?.commission_rates.rate || 0) * 100)
|
||||
let change = computed(() => Number(props.commission?.commission_rates.max_change_rate || 0) * 100)
|
||||
let max = computed(() => Number(props.commission?.commission_rates.max_rate || 1) * 100)
|
||||
commission: { type: Object as PropType<CommissionRate> },
|
||||
});
|
||||
|
||||
let rate = computed(
|
||||
() => Number(props.commission?.commission_rates.rate || 0) * 100
|
||||
);
|
||||
let change = computed(
|
||||
() => Number(props.commission?.commission_rates.max_change_rate || 0) * 100
|
||||
);
|
||||
let max = computed(
|
||||
() => Number(props.commission?.commission_rates.max_rate || 1) * 100
|
||||
);
|
||||
|
||||
// const rate = 15 // props.commision?.commissionRates.rate
|
||||
// const change = 15
|
||||
// const max = 20
|
||||
|
||||
const left = rate
|
||||
const right = computed(() => max.value - rate.value)
|
||||
const left = rate;
|
||||
const right = computed(() => max.value - rate.value);
|
||||
|
||||
const s1 = computed(() => left.value > change.value ? left.value - change.value : 0 )
|
||||
const s2 = computed(() => left.value > change.value ? change.value: left.value)
|
||||
const s3 = 2
|
||||
const s4 = computed(() => right.value > change.value? change.value: right.value)
|
||||
const s5 = computed(() => right.value > change.value? right.value - change.value: 0)
|
||||
const s1 = computed(() =>
|
||||
left.value > change.value ? left.value - change.value : 0
|
||||
);
|
||||
const s2 = computed(() =>
|
||||
left.value > change.value ? change.value : left.value
|
||||
);
|
||||
const s3 = 2;
|
||||
const s4 = computed(() =>
|
||||
right.value > change.value ? change.value : right.value
|
||||
);
|
||||
const s5 = computed(() =>
|
||||
right.value > change.value ? right.value - change.value : 0
|
||||
);
|
||||
|
||||
const series = computed(() => [s1.value, s2.value, s3, s4.value, s5.value])
|
||||
const series = computed(() => [s1.value, s2.value, s3, s4.value, s5.value]);
|
||||
|
||||
const vuetifyTheme = useTheme()
|
||||
const format = useFormatter()
|
||||
const vuetifyTheme = useTheme();
|
||||
const format = useFormatter();
|
||||
|
||||
const chartConfig = computed(() => {
|
||||
const themeColors = vuetifyTheme.current.value.colors
|
||||
const variableTheme = vuetifyTheme.current.value.variables
|
||||
const themeColors = vuetifyTheme.current.value.colors;
|
||||
const variableTheme = vuetifyTheme.current.value.variables;
|
||||
|
||||
const secondaryText = `rgba(${hexToRgb(String(themeColors['on-background']))},${variableTheme['medium-emphasis-opacity']})`
|
||||
const primaryText = `rgba(${hexToRgb(String(themeColors['on-background']))},${variableTheme['high-emphasis-opacity']})`
|
||||
const secondaryText = `rgba(${hexToRgb(
|
||||
String(themeColors['on-background'])
|
||||
)},${variableTheme['medium-emphasis-opacity']})`;
|
||||
const primaryText = `rgba(${hexToRgb(String(themeColors['on-background']))},${
|
||||
variableTheme['high-emphasis-opacity']
|
||||
})`;
|
||||
|
||||
return {
|
||||
chart: {
|
||||
@ -54,8 +71,18 @@ const chartConfig = computed(() => {
|
||||
legend: { show: false },
|
||||
tooltip: { enabled: false },
|
||||
dataLabels: { enabled: false },
|
||||
stroke: { width: 3, lineCap: 'round', colors: ['rgba(var(--v-theme-surface), 1)'] },
|
||||
labels: ['Available', 'Daily Change', 'Commission Rate', 'Daily Change', 'Available'],
|
||||
stroke: {
|
||||
width: 3,
|
||||
lineCap: 'round',
|
||||
colors: ['rgba(var(--v-theme-surface), 1)'],
|
||||
},
|
||||
labels: [
|
||||
'Available',
|
||||
'Daily Change',
|
||||
'Commission Rate',
|
||||
'Daily Change',
|
||||
'Available',
|
||||
],
|
||||
states: {
|
||||
hover: {
|
||||
filter: { type: 'none' },
|
||||
@ -90,7 +117,7 @@ const chartConfig = computed(() => {
|
||||
label: 'Commission Rate',
|
||||
fontSize: '1rem',
|
||||
color: secondaryText,
|
||||
formatter: ( ) => `${rate.value}%`,
|
||||
formatter: () => `${rate.value}%`,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -104,13 +131,18 @@ const chartConfig = computed(() => {
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
})
|
||||
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VCard title="Commission Rate" :subtitle="`Updated at ${format.toDay(props.commission?.update_time, 'short')}`">
|
||||
<VCard
|
||||
title="Commission Rate"
|
||||
:subtitle="`Updated at ${format.toDay(
|
||||
props.commission?.update_time,
|
||||
'short'
|
||||
)}`"
|
||||
>
|
||||
<VCardText>
|
||||
<VueApexCharts
|
||||
type="donut"
|
||||
@ -121,15 +153,15 @@ const chartConfig = computed(() => {
|
||||
|
||||
<div class="d-flex align-center justify-center flex-wrap mx-2 gap-x-6">
|
||||
<div class="d-flex align-center gap-2">
|
||||
<VBadge dot color="success"/>
|
||||
<VBadge dot color="success" />
|
||||
<span class="mt-1 text-caption">Rate:{{ rate }}%</span>
|
||||
</div>
|
||||
<div class="d-flex align-center gap-2">
|
||||
<VBadge dot color="success" style="opacity:0.2"/>
|
||||
<VBadge dot color="success" style="opacity: 0.2" />
|
||||
<span class="mt-1 text-caption">24h: ±{{ change }}%</span>
|
||||
</div>
|
||||
<div class="d-flex align-center gap-2">
|
||||
<VBadge dot color="secondary"/>
|
||||
<VBadge dot color="secondary" />
|
||||
<span class="mt-1 text-caption">Max:{{ max }}%</span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,15 +1,15 @@
|
||||
<script lang="ts" setup>
|
||||
import VueApexCharts from 'vue3-apexcharts'
|
||||
import { useTheme } from 'vuetify'
|
||||
import { getDonutChartConfig } from './apexChartConfig'
|
||||
import VueApexCharts from 'vue3-apexcharts';
|
||||
import { useTheme } from 'vuetify';
|
||||
import { getDonutChartConfig } from './apexChartConfig';
|
||||
|
||||
const props = defineProps(["series", "labels"])
|
||||
|
||||
const vuetifyTheme = useTheme()
|
||||
|
||||
const expenseRationChartConfig = computed(() => getDonutChartConfig(vuetifyTheme.current.value, props.labels))
|
||||
const props = defineProps(['series', 'labels']);
|
||||
|
||||
const vuetifyTheme = useTheme();
|
||||
|
||||
const expenseRationChartConfig = computed(() =>
|
||||
getDonutChartConfig(vuetifyTheme.current.value, props.labels)
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -1,30 +1,41 @@
|
||||
<script lang="ts" setup>
|
||||
import VueApexCharts from 'vue3-apexcharts'
|
||||
import { useTheme } from 'vuetify'
|
||||
import { getAreaChartSplineConfig, getMarketPriceChartConfig } from './apexChartConfig'
|
||||
import VueApexCharts from 'vue3-apexcharts';
|
||||
import { useTheme } from 'vuetify';
|
||||
import {
|
||||
getAreaChartSplineConfig,
|
||||
getMarketPriceChartConfig,
|
||||
} from './apexChartConfig';
|
||||
import { useIndexModule } from '@/modules/[chain]/indexStore';
|
||||
import { computed, ref } from '@vue/reactivity';
|
||||
|
||||
const store = useIndexModule()
|
||||
const vuetifyTheme = useTheme()
|
||||
const store = useIndexModule();
|
||||
const vuetifyTheme = useTheme();
|
||||
const chartConfig = computed(() => {
|
||||
const labels = store.marketData.prices.map(x => x[0])
|
||||
return getMarketPriceChartConfig(vuetifyTheme.current.value, labels)
|
||||
})
|
||||
const kind = ref('price')
|
||||
const labels = store.marketData.prices.map((x) => x[0]);
|
||||
return getMarketPriceChartConfig(vuetifyTheme.current.value, labels);
|
||||
});
|
||||
const kind = ref('price');
|
||||
const series = computed(() => {
|
||||
return [{
|
||||
name: 'Price',
|
||||
data: kind.value ==='price'?store.marketData.prices.map(x => x[1]) : store.marketData.total_volumes.map(x => x[1])}]
|
||||
})
|
||||
return [
|
||||
{
|
||||
name: 'Price',
|
||||
data:
|
||||
kind.value === 'price'
|
||||
? store.marketData.prices.map((x) => x[1])
|
||||
: store.marketData.total_volumes.map((x) => x[1]),
|
||||
},
|
||||
];
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VTabs v-model="kind" align-tabs="end"><VTab value="price">Price</VTab><VTab value="volume">Volume</VTab></VTabs>
|
||||
<VTabs v-model="kind" align-tabs="end"
|
||||
><VTab value="price">Price</VTab><VTab value="volume">Volume</VTab></VTabs
|
||||
>
|
||||
<VueApexCharts
|
||||
type="area"
|
||||
height="261"
|
||||
:options="chartConfig"
|
||||
:series="series"
|
||||
/>
|
||||
</template>
|
||||
</template>
|
||||
|
@ -1,20 +1,38 @@
|
||||
import type { ThemeInstance } from 'vuetify'
|
||||
import { hexToRgb } from '@/plugins/vuetify/@layouts/utils'
|
||||
import numeral from 'numeral'
|
||||
import type { ThemeInstance } from 'vuetify';
|
||||
import { hexToRgb } from '@/plugins/vuetify/@layouts/utils';
|
||||
import numeral from 'numeral';
|
||||
|
||||
// 👉 Colors variables
|
||||
const colorVariables = (themeColors: ThemeInstance['themes']['value']['colors']) => {
|
||||
const themeSecondaryTextColor = `rgba(${hexToRgb(themeColors.colors['on-surface'])},${themeColors.variables['medium-emphasis-opacity']})`
|
||||
const themeDisabledTextColor = `rgba(${hexToRgb(themeColors.colors['on-surface'])},${themeColors.variables['disabled-opacity']})`
|
||||
const themeBorderColor = `rgba(${hexToRgb(String(themeColors.variables['border-color']))},${themeColors.variables['border-opacity']})`
|
||||
const themePrimaryTextColor = `rgba(${hexToRgb(themeColors.colors['on-surface'])},${themeColors.variables['high-emphasis-opacity']})`
|
||||
const colorVariables = (
|
||||
themeColors: ThemeInstance['themes']['value']['colors']
|
||||
) => {
|
||||
const themeSecondaryTextColor = `rgba(${hexToRgb(
|
||||
themeColors.colors['on-surface']
|
||||
)},${themeColors.variables['medium-emphasis-opacity']})`;
|
||||
const themeDisabledTextColor = `rgba(${hexToRgb(
|
||||
themeColors.colors['on-surface']
|
||||
)},${themeColors.variables['disabled-opacity']})`;
|
||||
const themeBorderColor = `rgba(${hexToRgb(
|
||||
String(themeColors.variables['border-color'])
|
||||
)},${themeColors.variables['border-opacity']})`;
|
||||
const themePrimaryTextColor = `rgba(${hexToRgb(
|
||||
themeColors.colors['on-surface']
|
||||
)},${themeColors.variables['high-emphasis-opacity']})`;
|
||||
|
||||
return { themeSecondaryTextColor, themeDisabledTextColor, themeBorderColor, themePrimaryTextColor }
|
||||
}
|
||||
return {
|
||||
themeSecondaryTextColor,
|
||||
themeDisabledTextColor,
|
||||
themeBorderColor,
|
||||
themePrimaryTextColor,
|
||||
};
|
||||
};
|
||||
/// Price Chart config
|
||||
export const getMarketPriceChartConfig = (themeColors: ThemeInstance['themes']['value']['colors'], categories: string[]) => {
|
||||
|
||||
const { themeSecondaryTextColor, themeBorderColor, themeDisabledTextColor } = colorVariables(themeColors)
|
||||
export const getMarketPriceChartConfig = (
|
||||
themeColors: ThemeInstance['themes']['value']['colors'],
|
||||
categories: string[]
|
||||
) => {
|
||||
const { themeSecondaryTextColor, themeBorderColor, themeDisabledTextColor } =
|
||||
colorVariables(themeColors);
|
||||
|
||||
return {
|
||||
chart: {
|
||||
@ -25,7 +43,7 @@ export const getMarketPriceChartConfig = (themeColors: ThemeInstance['themes']['
|
||||
},
|
||||
tooltip: {
|
||||
theme: 'dark',
|
||||
shared: false
|
||||
shared: false,
|
||||
},
|
||||
dataLabels: { enabled: false },
|
||||
stroke: {
|
||||
@ -64,9 +82,9 @@ export const getMarketPriceChartConfig = (themeColors: ThemeInstance['themes']['
|
||||
labels: {
|
||||
style: { colors: themeDisabledTextColor },
|
||||
formatter: function (value: string) {
|
||||
const pattern = (Number(value) > 0.01 ? '0.0[0]a': '0.00[000]')
|
||||
const pattern = Number(value) > 0.01 ? '0.0[0]a' : '0.00[000]';
|
||||
return numeral(value).format(pattern);
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
xaxis: {
|
||||
@ -82,19 +100,22 @@ export const getMarketPriceChartConfig = (themeColors: ThemeInstance['themes']['
|
||||
},
|
||||
categories,
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/// default config
|
||||
|
||||
export const getScatterChartConfig = (themeColors: ThemeInstance['themes']['value']['colors']) => {
|
||||
export const getScatterChartConfig = (
|
||||
themeColors: ThemeInstance['themes']['value']['colors']
|
||||
) => {
|
||||
const scatterColors = {
|
||||
series1: '#ff9f43',
|
||||
series2: '#7367f0',
|
||||
series3: '#28c76f',
|
||||
}
|
||||
};
|
||||
|
||||
const { themeSecondaryTextColor, themeBorderColor, themeDisabledTextColor } = colorVariables(themeColors)
|
||||
const { themeSecondaryTextColor, themeBorderColor, themeDisabledTextColor } =
|
||||
colorVariables(themeColors);
|
||||
|
||||
return {
|
||||
chart: {
|
||||
@ -116,7 +137,11 @@ export const getScatterChartConfig = (themeColors: ThemeInstance['themes']['valu
|
||||
horizontal: 10,
|
||||
},
|
||||
},
|
||||
colors: [scatterColors.series1, scatterColors.series2, scatterColors.series3],
|
||||
colors: [
|
||||
scatterColors.series1,
|
||||
scatterColors.series2,
|
||||
scatterColors.series3,
|
||||
],
|
||||
grid: {
|
||||
borderColor: themeBorderColor,
|
||||
xaxis: {
|
||||
@ -141,10 +166,13 @@ export const getScatterChartConfig = (themeColors: ThemeInstance['themes']['valu
|
||||
formatter: (val: string) => parseFloat(val).toFixed(1),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
export const getLineChartSimpleConfig = (themeColors: ThemeInstance['themes']['value']['colors']) => {
|
||||
const { themeBorderColor, themeDisabledTextColor } = colorVariables(themeColors)
|
||||
};
|
||||
};
|
||||
export const getLineChartSimpleConfig = (
|
||||
themeColors: ThemeInstance['themes']['value']['colors']
|
||||
) => {
|
||||
const { themeBorderColor, themeDisabledTextColor } =
|
||||
colorVariables(themeColors);
|
||||
|
||||
return {
|
||||
chart: {
|
||||
@ -174,7 +202,7 @@ export const getLineChartSimpleConfig = (themeColors: ThemeInstance['themes']['v
|
||||
custom(data: any) {
|
||||
return `<div class='bar-chart pa-2'>
|
||||
<span>${data.series[data.seriesIndex][data.dataPointIndex]}%</span>
|
||||
</div>`
|
||||
</div>`;
|
||||
},
|
||||
},
|
||||
yaxis: {
|
||||
@ -210,11 +238,14 @@ export const getLineChartSimpleConfig = (themeColors: ThemeInstance['themes']['v
|
||||
'21/12',
|
||||
],
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export const getBarChartConfig = (themeColors: ThemeInstance['themes']['value']['colors']) => {
|
||||
const { themeBorderColor, themeDisabledTextColor } = colorVariables(themeColors)
|
||||
export const getBarChartConfig = (
|
||||
themeColors: ThemeInstance['themes']['value']['colors']
|
||||
) => {
|
||||
const { themeBorderColor, themeDisabledTextColor } =
|
||||
colorVariables(themeColors);
|
||||
|
||||
return {
|
||||
chart: {
|
||||
@ -248,21 +279,32 @@ export const getBarChartConfig = (themeColors: ThemeInstance['themes']['value'][
|
||||
xaxis: {
|
||||
axisBorder: { show: false },
|
||||
axisTicks: { color: themeBorderColor },
|
||||
categories: ['MON, 11', 'THU, 14', 'FRI, 15', 'MON, 18', 'WED, 20', 'FRI, 21', 'MON, 23'],
|
||||
categories: [
|
||||
'MON, 11',
|
||||
'THU, 14',
|
||||
'FRI, 15',
|
||||
'MON, 18',
|
||||
'WED, 20',
|
||||
'FRI, 21',
|
||||
'MON, 23',
|
||||
],
|
||||
labels: {
|
||||
style: { colors: themeDisabledTextColor },
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export const getCandlestickChartConfig = (themeColors: ThemeInstance['themes']['value']['colors']) => {
|
||||
export const getCandlestickChartConfig = (
|
||||
themeColors: ThemeInstance['themes']['value']['colors']
|
||||
) => {
|
||||
const candlestickColors = {
|
||||
series1: '#28c76f',
|
||||
series2: '#ea5455',
|
||||
}
|
||||
};
|
||||
|
||||
const { themeBorderColor, themeDisabledTextColor } = colorVariables(themeColors)
|
||||
const { themeBorderColor, themeDisabledTextColor } =
|
||||
colorVariables(themeColors);
|
||||
|
||||
return {
|
||||
chart: {
|
||||
@ -305,18 +347,21 @@ export const getCandlestickChartConfig = (themeColors: ThemeInstance['themes']['
|
||||
style: { colors: themeDisabledTextColor },
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
export const getRadialBarChartConfig = (themeColors: ThemeInstance['themes']['value']['colors']) => {
|
||||
};
|
||||
};
|
||||
export const getRadialBarChartConfig = (
|
||||
themeColors: ThemeInstance['themes']['value']['colors']
|
||||
) => {
|
||||
const radialBarColors = {
|
||||
series1: '#fdd835',
|
||||
series2: '#32baff',
|
||||
series3: '#00d4bd',
|
||||
series4: '#7367f0',
|
||||
series5: '#FFA1A1',
|
||||
}
|
||||
};
|
||||
|
||||
const { themeSecondaryTextColor, themePrimaryTextColor } = colorVariables(themeColors)
|
||||
const { themeSecondaryTextColor, themePrimaryTextColor } =
|
||||
colorVariables(themeColors);
|
||||
|
||||
return {
|
||||
stroke: { lineCap: 'round' },
|
||||
@ -335,7 +380,11 @@ export const getRadialBarChartConfig = (themeColors: ThemeInstance['themes']['va
|
||||
horizontal: 10,
|
||||
},
|
||||
},
|
||||
colors: [radialBarColors.series1, radialBarColors.series2, radialBarColors.series4],
|
||||
colors: [
|
||||
radialBarColors.series1,
|
||||
radialBarColors.series2,
|
||||
radialBarColors.series4,
|
||||
],
|
||||
plotOptions: {
|
||||
radialBar: {
|
||||
hollow: { size: '30%' },
|
||||
@ -359,16 +408,16 @@ export const getRadialBarChartConfig = (themeColors: ThemeInstance['themes']['va
|
||||
|
||||
color: themePrimaryTextColor,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
formatter(w: { globals: { seriesTotals: any[]; series: string | any[] } }) {
|
||||
const totalValue
|
||||
= w.globals.seriesTotals.reduce((a: number, b: number) => {
|
||||
return a + b
|
||||
}, 0) / w.globals.series.length
|
||||
formatter(w: {
|
||||
globals: { seriesTotals: any[]; series: string | any[] };
|
||||
}) {
|
||||
const totalValue =
|
||||
w.globals.seriesTotals.reduce((a: number, b: number) => {
|
||||
return a + b;
|
||||
}, 0) / w.globals.series.length;
|
||||
|
||||
if (totalValue % 1 === 0)
|
||||
return `${totalValue}%`
|
||||
else
|
||||
return `${totalValue.toFixed(2)}%`
|
||||
if (totalValue % 1 === 0) return `${totalValue}%`;
|
||||
else return `${totalValue.toFixed(2)}%`;
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -380,24 +429,33 @@ export const getRadialBarChartConfig = (themeColors: ThemeInstance['themes']['va
|
||||
bottom: -30,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export const getDonutChartConfig = (themeColors: ThemeInstance['themes']['value']['colors'], labels: string[]) => {
|
||||
export const getDonutChartConfig = (
|
||||
themeColors: ThemeInstance['themes']['value']['colors'],
|
||||
labels: string[]
|
||||
) => {
|
||||
const donutColors = {
|
||||
series1: '#fdd835',
|
||||
series2: '#00d4bd',
|
||||
series3: '#826bf8',
|
||||
series4: '#32baff',
|
||||
series5: '#ffa1a1',
|
||||
}
|
||||
};
|
||||
|
||||
const { themeSecondaryTextColor, themePrimaryTextColor } = colorVariables(themeColors)
|
||||
const { themeSecondaryTextColor, themePrimaryTextColor } =
|
||||
colorVariables(themeColors);
|
||||
|
||||
return {
|
||||
stroke: { width: 0 },
|
||||
labels,
|
||||
colors: [donutColors.series1, donutColors.series5, donutColors.series3, donutColors.series2],
|
||||
colors: [
|
||||
donutColors.series1,
|
||||
donutColors.series5,
|
||||
donutColors.series3,
|
||||
donutColors.series2,
|
||||
],
|
||||
dataLabels: {
|
||||
enabled: true,
|
||||
formatter: (val: string) => `${parseInt(val, 10)}%`,
|
||||
@ -474,17 +532,20 @@ export const getDonutChartConfig = (themeColors: ThemeInstance['themes']['value'
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export const getAreaChartSplineConfig = (themeColors: ThemeInstance['themes']['value']['colors']) => {
|
||||
export const getAreaChartSplineConfig = (
|
||||
themeColors: ThemeInstance['themes']['value']['colors']
|
||||
) => {
|
||||
const areaColors = {
|
||||
series3: '#e0cffe',
|
||||
series2: '#b992fe',
|
||||
series1: '#ab7efd',
|
||||
}
|
||||
};
|
||||
|
||||
const { themeSecondaryTextColor, themeBorderColor, themeDisabledTextColor } = colorVariables(themeColors)
|
||||
const { themeSecondaryTextColor, themeBorderColor, themeDisabledTextColor } =
|
||||
colorVariables(themeColors);
|
||||
|
||||
return {
|
||||
chart: {
|
||||
@ -555,17 +616,20 @@ export const getAreaChartSplineConfig = (themeColors: ThemeInstance['themes']['v
|
||||
'19/12',
|
||||
],
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export const getColumnChartConfig = (themeColors: ThemeInstance['themes']['value']['colors']) => {
|
||||
export const getColumnChartConfig = (
|
||||
themeColors: ThemeInstance['themes']['value']['colors']
|
||||
) => {
|
||||
const columnColors = {
|
||||
series1: '#826af9',
|
||||
series2: '#d2b0ff',
|
||||
bg: '#f8d3ff',
|
||||
}
|
||||
};
|
||||
|
||||
const { themeSecondaryTextColor, themeBorderColor, themeDisabledTextColor } = colorVariables(themeColors)
|
||||
const { themeSecondaryTextColor, themeBorderColor, themeDisabledTextColor } =
|
||||
colorVariables(themeColors);
|
||||
|
||||
return {
|
||||
chart: {
|
||||
@ -602,7 +666,13 @@ export const getColumnChartConfig = (themeColors: ThemeInstance['themes']['value
|
||||
colors: {
|
||||
backgroundBarRadius: 10,
|
||||
|
||||
backgroundBarColors: [columnColors.bg, columnColors.bg, columnColors.bg, columnColors.bg, columnColors.bg],
|
||||
backgroundBarColors: [
|
||||
columnColors.bg,
|
||||
columnColors.bg,
|
||||
columnColors.bg,
|
||||
columnColors.bg,
|
||||
columnColors.bg,
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -621,7 +691,17 @@ export const getColumnChartConfig = (themeColors: ThemeInstance['themes']['value
|
||||
axisBorder: { show: false },
|
||||
|
||||
axisTicks: { color: themeBorderColor },
|
||||
categories: ['7/12', '8/12', '9/12', '10/12', '11/12', '12/12', '13/12', '14/12', '15/12'],
|
||||
categories: [
|
||||
'7/12',
|
||||
'8/12',
|
||||
'9/12',
|
||||
'10/12',
|
||||
'11/12',
|
||||
'12/12',
|
||||
'13/12',
|
||||
'14/12',
|
||||
'15/12',
|
||||
],
|
||||
crosshairs: {
|
||||
stroke: { color: themeBorderColor },
|
||||
},
|
||||
@ -641,11 +721,14 @@ export const getColumnChartConfig = (themeColors: ThemeInstance['themes']['value
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export const getHeatMapChartConfig = (themeColors: ThemeInstance['themes']['value']['colors']) => {
|
||||
const { themeSecondaryTextColor, themeDisabledTextColor } = colorVariables(themeColors)
|
||||
export const getHeatMapChartConfig = (
|
||||
themeColors: ThemeInstance['themes']['value']['colors']
|
||||
) => {
|
||||
const { themeSecondaryTextColor, themeDisabledTextColor } =
|
||||
colorVariables(themeColors);
|
||||
|
||||
return {
|
||||
chart: {
|
||||
@ -700,16 +783,19 @@ export const getHeatMapChartConfig = (themeColors: ThemeInstance['themes']['valu
|
||||
axisTicks: { show: false },
|
||||
axisBorder: { show: false },
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export const getRadarChartConfig = (themeColors: ThemeInstance['themes']['value']['colors']) => {
|
||||
export const getRadarChartConfig = (
|
||||
themeColors: ThemeInstance['themes']['value']['colors']
|
||||
) => {
|
||||
const radarColors = {
|
||||
series1: '#9b88fa',
|
||||
series2: '#ffa1a1',
|
||||
}
|
||||
};
|
||||
|
||||
const { themeSecondaryTextColor, themeBorderColor, themeDisabledTextColor } = colorVariables(themeColors)
|
||||
const { themeSecondaryTextColor, themeBorderColor, themeDisabledTextColor } =
|
||||
colorVariables(themeColors);
|
||||
|
||||
return {
|
||||
chart: {
|
||||
@ -759,7 +845,16 @@ export const getRadarChartConfig = (themeColors: ThemeInstance['themes']['value'
|
||||
},
|
||||
yaxis: { show: false },
|
||||
xaxis: {
|
||||
categories: ['Battery', 'Brand', 'Camera', 'Memory', 'Storage', 'Display', 'OS', 'Price'],
|
||||
categories: [
|
||||
'Battery',
|
||||
'Brand',
|
||||
'Camera',
|
||||
'Memory',
|
||||
'Storage',
|
||||
'Display',
|
||||
'OS',
|
||||
'Price',
|
||||
],
|
||||
labels: {
|
||||
style: {
|
||||
colors: [
|
||||
@ -775,5 +870,5 @@ export const getRadarChartConfig = (themeColors: ThemeInstance['themes']['value'
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
@ -2,9 +2,8 @@
|
||||
import { fromBase64, toBase64 } from '@cosmjs/encoding';
|
||||
|
||||
const props = defineProps({
|
||||
value: { type: Array<Uint8Array>},
|
||||
})
|
||||
|
||||
value: { type: Array<Uint8Array> },
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
@ -12,4 +11,4 @@ const props = defineProps({
|
||||
{{ toBase64(v) }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
|
@ -3,19 +3,18 @@ import { useFormatter } from '@/stores';
|
||||
import type { Coin } from '@/types';
|
||||
|
||||
const props = defineProps({
|
||||
value: { type: Array<Coin>},
|
||||
})
|
||||
|
||||
const format = useFormatter()
|
||||
value: { type: Array<Coin> },
|
||||
});
|
||||
|
||||
const format = useFormatter();
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
{{ format.formatTokens(value, true, "0,0.[000000]") }}
|
||||
{{ format.formatTokens(value, true, '0,0.[000000]') }}
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'ArrayCoinElement'
|
||||
}
|
||||
name: 'ArrayCoinElement',
|
||||
};
|
||||
</script>
|
||||
|
@ -3,32 +3,31 @@ import { toBase64 } from '@cosmjs/encoding';
|
||||
import type { PropType } from 'vue';
|
||||
import { computed } from '@vue/reactivity';
|
||||
import DynamicComponentVue from './DynamicComponent.vue';
|
||||
import {select} from './index'
|
||||
import { select } from './index';
|
||||
import ArrayBytesElement from './ArrayBytesElement.vue';
|
||||
import ArrayObjectElement from './ArrayObjectElement.vue';
|
||||
import TextElement from './TextElement.vue';
|
||||
import ArrayCoinElement from './ArrayCoinElement.vue';
|
||||
|
||||
const props = defineProps({
|
||||
value: { type: Array<Object>},
|
||||
})
|
||||
value: { type: Array<Object> },
|
||||
});
|
||||
|
||||
function selectByElement() {
|
||||
if(props.value && props.value.length > 0) {
|
||||
const [first] = props.value
|
||||
switch(true) {
|
||||
case first instanceof Uint8Array:
|
||||
return ArrayBytesElement
|
||||
if (props.value && props.value.length > 0) {
|
||||
const [first] = props.value;
|
||||
switch (true) {
|
||||
case first instanceof Uint8Array:
|
||||
return ArrayBytesElement;
|
||||
case Object.keys(first).includes('denom'):
|
||||
return ArrayCoinElement
|
||||
return ArrayCoinElement;
|
||||
default:
|
||||
return ArrayObjectElement
|
||||
return ArrayObjectElement;
|
||||
}
|
||||
}
|
||||
return TextElement
|
||||
return TextElement;
|
||||
}
|
||||
|
||||
</script>
|
||||
<template>
|
||||
<Component :is="selectByElement()" :value="props.value"></Component>
|
||||
</template>
|
||||
</template>
|
||||
|
@ -6,33 +6,44 @@ const props = defineProps({
|
||||
value: { type: null as any },
|
||||
thead: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
})
|
||||
default: true,
|
||||
},
|
||||
});
|
||||
|
||||
const header = computed(() => {
|
||||
if(props.value && props.value.length > 0) {
|
||||
return Object.keys(props.value[0])
|
||||
if (props.value && props.value.length > 0) {
|
||||
return Object.keys(props.value[0]);
|
||||
}
|
||||
return []
|
||||
})
|
||||
|
||||
return [];
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<VTable v-if="header.length > 0" density="compact" height="300px" fixed-header hover>
|
||||
<VTable
|
||||
v-if="header.length > 0"
|
||||
density="compact"
|
||||
height="300px"
|
||||
fixed-header
|
||||
hover
|
||||
>
|
||||
<thead v-if="thead">
|
||||
<tr>
|
||||
<th v-for="(item, index) in header" :key="index" class="text-left text-capitalize">{{ item }}</th>
|
||||
<th
|
||||
v-for="(item, index) in header"
|
||||
:key="index"
|
||||
class="text-left text-capitalize"
|
||||
>
|
||||
{{ item }}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(item, index) in value" :key="index">
|
||||
<td v-for="(el, key) in header" :key="key"> <DynamicComponent :value="item[el]" /></td>
|
||||
<td v-for="(el, key) in header" :key="key">
|
||||
<DynamicComponent :value="item[el]" />
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</VTable>
|
||||
|
||||
<div v-else class="h-[300px]">
|
||||
|
||||
</div>
|
||||
</template>
|
||||
<div v-else class="h-[300px]"></div>
|
||||
</template>
|
||||
|
@ -1,9 +1,8 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { select } from './index'
|
||||
import { select } from './index';
|
||||
|
||||
const props = defineProps(["value", "direct"]);
|
||||
const props = defineProps(['value', 'direct']);
|
||||
</script>
|
||||
<template>
|
||||
<Component :is="select(value, direct)" :value="value"></Component>
|
||||
</template>
|
||||
<Component :is="select(value, direct)" :value="value"></Component>
|
||||
</template>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script lang="ts" setup>
|
||||
const props = defineProps(["value"]);
|
||||
const props = defineProps(['value']);
|
||||
</script>
|
||||
<template>
|
||||
<span>{{ Number(props.value) }}</span>
|
||||
</template>
|
||||
<span>{{ Number(props.value) }}</span>
|
||||
</template>
|
||||
|
@ -1,23 +1,29 @@
|
||||
<script lang="ts" setup>
|
||||
import DynamicComponent from './DynamicComponent.vue';
|
||||
import {select} from './index'
|
||||
|
||||
const props = defineProps(["value"]);
|
||||
import { select } from './index';
|
||||
|
||||
const props = defineProps(['value']);
|
||||
</script>
|
||||
<template>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="table w-full text-sm">
|
||||
<tbody>
|
||||
<tr v-for="(v, k) of value">
|
||||
<td class="text-capitalize" style="max-width: 200px;">{{ k }}</td>
|
||||
<td>
|
||||
<div class="overflow-hidden w-auto whitespace-normal" style="max-width: 1000px;">
|
||||
<Component v-if="v" :is="select(v, 'horizontal')" :value="v"></Component>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</template>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="table w-full text-sm">
|
||||
<tbody>
|
||||
<tr v-for="(v, k) of value">
|
||||
<td class="text-capitalize" style="max-width: 200px">{{ k }}</td>
|
||||
<td>
|
||||
<div
|
||||
class="overflow-hidden w-auto whitespace-normal"
|
||||
style="max-width: 1000px"
|
||||
>
|
||||
<Component
|
||||
v-if="v"
|
||||
:is="select(v, 'horizontal')"
|
||||
:value="v"
|
||||
></Component>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -1,17 +1,19 @@
|
||||
<script lang="ts" setup>
|
||||
import DynamicComponent from './DynamicComponent.vue';
|
||||
import {select} from './index'
|
||||
import { select } from './index';
|
||||
|
||||
const props = defineProps(["value"]);
|
||||
const tab = ref("")
|
||||
const props = defineProps(['value']);
|
||||
const tab = ref('');
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<VTabs v-model="tab">
|
||||
<VTab v-for="(v, k) of value" :value="k">{{ k }}</VTab>
|
||||
</VTabs>
|
||||
<VWindow v-model="tab" style="min-height: 25px;">
|
||||
<VWindowItem v-for="(v, k) of value" :value="k"><DynamicComponent :value="v"/></VWindowItem>
|
||||
</VWindow>
|
||||
</div>
|
||||
</template>
|
||||
<div>
|
||||
<VTabs v-model="tab">
|
||||
<VTab v-for="(v, k) of value" :value="k">{{ k }}</VTab>
|
||||
</VTabs>
|
||||
<VWindow v-model="tab" style="min-height: 25px">
|
||||
<VWindowItem v-for="(v, k) of value" :value="k"
|
||||
><DynamicComponent :value="v"
|
||||
/></VWindowItem>
|
||||
</VWindow>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -2,16 +2,23 @@
|
||||
import { useFormatter } from '@/stores';
|
||||
import MdEditor from 'md-editor-v3';
|
||||
|
||||
const props = defineProps(["value"]);
|
||||
const format = useFormatter()
|
||||
const props = defineProps(['value']);
|
||||
const format = useFormatter();
|
||||
function isMD() {
|
||||
if(props.value && (props.value.indexOf("\n") > -1 || props.value.indexOf("\\n") > -1)){
|
||||
return true
|
||||
}
|
||||
return false
|
||||
if (
|
||||
props.value &&
|
||||
(props.value.indexOf('\n') > -1 || props.value.indexOf('\\n') > -1)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<MdEditor v-if="isMD()" :model-value="format.multiLine(value)" previewOnly></MdEditor>
|
||||
<span v-else>{{ value }}</span>
|
||||
</template>
|
||||
<template>
|
||||
<MdEditor
|
||||
v-if="isMD()"
|
||||
:model-value="format.multiLine(value)"
|
||||
previewOnly
|
||||
></MdEditor>
|
||||
<span v-else>{{ value }}</span>
|
||||
</template>
|
||||
|
@ -1,35 +1,51 @@
|
||||
<script lang="ts" setup>
|
||||
import { fromBase64, toBase64 } from '@cosmjs/encoding';
|
||||
import { decodeTxRaw } from '@cosmjs/proto-signing'
|
||||
import { decodeTxRaw } from '@cosmjs/proto-signing';
|
||||
import { computed } from '@vue/reactivity';
|
||||
import { hashTx } from '@/libs'
|
||||
import { hashTx } from '@/libs';
|
||||
import { useBlockchain, useFormatter } from '@/stores';
|
||||
const props = defineProps({
|
||||
value: { type: Array<string>},
|
||||
value: { type: Array<string> },
|
||||
});
|
||||
|
||||
const txs = computed(() => {
|
||||
return props.value?.map(x => ({ hash: hashTx(fromBase64(x)) , tx: decodeTxRaw(fromBase64(x)) })) || []
|
||||
})
|
||||
|
||||
const format = useFormatter()
|
||||
const chain = useBlockchain()
|
||||
return (
|
||||
props.value?.map((x) => ({
|
||||
hash: hashTx(fromBase64(x)),
|
||||
tx: decodeTxRaw(fromBase64(x)),
|
||||
})) || []
|
||||
);
|
||||
});
|
||||
|
||||
const format = useFormatter();
|
||||
const chain = useBlockchain();
|
||||
</script>
|
||||
<template>
|
||||
<VTable density="compact" v-if="txs.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Hash</th><th>Msgs</th><th>Memo</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="item in txs">
|
||||
<td><RouterLink :to="`/${chain.chainName}/tx/${item.hash}`">{{ item.hash }}</RouterLink></td>
|
||||
<td>{{ format.messages(item.tx.body.messages.map(x => ({"@type": x.typeUrl}))) }}</td>
|
||||
<td>{{ item.tx.body.memo }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</VTable>
|
||||
<div v-else>[]</div>
|
||||
</template>
|
||||
<VTable density="compact" v-if="txs.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Hash</th>
|
||||
<th>Msgs</th>
|
||||
<th>Memo</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="item in txs">
|
||||
<td>
|
||||
<RouterLink :to="`/${chain.chainName}/tx/${item.hash}`">{{
|
||||
item.hash
|
||||
}}</RouterLink>
|
||||
</td>
|
||||
<td>
|
||||
{{
|
||||
format.messages(
|
||||
item.tx.body.messages.map((x) => ({ '@type': x.typeUrl }))
|
||||
)
|
||||
}}
|
||||
</td>
|
||||
<td>{{ item.tx.body.memo }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</VTable>
|
||||
<div v-else>[]</div>
|
||||
</template>
|
||||
|
@ -2,15 +2,17 @@
|
||||
import { toBase64, toHex } from '@cosmjs/encoding';
|
||||
import { computed } from '@vue/reactivity';
|
||||
|
||||
const props = defineProps(["value"]);
|
||||
const format = ref('base64')
|
||||
const text = computed(()=> {
|
||||
return format.value === 'hex'? toHex(props.value) : toBase64(props.value)
|
||||
})
|
||||
const props = defineProps(['value']);
|
||||
const format = ref('base64');
|
||||
const text = computed(() => {
|
||||
return format.value === 'hex' ? toHex(props.value) : toBase64(props.value);
|
||||
});
|
||||
function change() {
|
||||
format.value = format.value === 'hex'? 'base64': 'hex'
|
||||
format.value = format.value === 'hex' ? 'base64' : 'hex';
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<span>{{ text }} <VIcon size="12" icon="mdi-cached" @click="change()"/></span>
|
||||
</template>
|
||||
<span
|
||||
>{{ text }} <VIcon size="12" icon="mdi-cached" @click="change()"
|
||||
/></span>
|
||||
</template>
|
||||
|
@ -1,39 +1,39 @@
|
||||
import ObjectElement from './ObjectElement.vue'
|
||||
import TextElement from './TextElement.vue'
|
||||
import ArrayElement from './ArrayElement.vue'
|
||||
import UInt8Array from './UInt8Array.vue'
|
||||
import NumberElement from './NumberElement.vue'
|
||||
import TxsElement from './TxsElement.vue'
|
||||
import ObjectHorizontalElement from './ObjectHorizontalElement.vue'
|
||||
import Long from 'long'
|
||||
import ObjectElement from './ObjectElement.vue';
|
||||
import TextElement from './TextElement.vue';
|
||||
import ArrayElement from './ArrayElement.vue';
|
||||
import UInt8Array from './UInt8Array.vue';
|
||||
import NumberElement from './NumberElement.vue';
|
||||
import TxsElement from './TxsElement.vue';
|
||||
import ObjectHorizontalElement from './ObjectHorizontalElement.vue';
|
||||
import Long from 'long';
|
||||
|
||||
export function select(v: any, direct?: string) {
|
||||
// if(k === 'txs' && v) {
|
||||
// return TxsElement
|
||||
// } else {
|
||||
const type = typeof v
|
||||
switch(type) {
|
||||
case 'object':
|
||||
return selectObject(v, direct)
|
||||
case 'number':
|
||||
return NumberElement
|
||||
default:
|
||||
return TextElement
|
||||
}
|
||||
// }
|
||||
// if(k === 'txs' && v) {
|
||||
// return TxsElement
|
||||
// } else {
|
||||
const type = typeof v;
|
||||
switch (type) {
|
||||
case 'object':
|
||||
return selectObject(v, direct);
|
||||
case 'number':
|
||||
return NumberElement;
|
||||
default:
|
||||
return TextElement;
|
||||
}
|
||||
// }
|
||||
}
|
||||
|
||||
function selectObject(v: Object, direct?: string) {
|
||||
switch(true) {
|
||||
case v instanceof Long:
|
||||
return NumberElement
|
||||
case v instanceof Uint8Array:
|
||||
return UInt8Array
|
||||
case Array.isArray(v):
|
||||
return ArrayElement
|
||||
case direct === 'horizontal':
|
||||
return ObjectHorizontalElement
|
||||
default:
|
||||
return ObjectElement
|
||||
}
|
||||
}
|
||||
switch (true) {
|
||||
case v instanceof Long:
|
||||
return NumberElement;
|
||||
case v instanceof Uint8Array:
|
||||
return UInt8Array;
|
||||
case Array.isArray(v):
|
||||
return ArrayElement;
|
||||
case direct === 'horizontal':
|
||||
return ObjectHorizontalElement;
|
||||
default:
|
||||
return ObjectElement;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,10 @@
|
||||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="20"
|
||||
height="20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
d="M15 4a1 1 0 1 0 0 2V4zm0 11v-1a1 1 0 0 0-1 1h1zm0 4l-.707.707A1 1 0 0 0 16 19h-1zm-4-4l.707-.707A1 1 0 0 0 11 14v1zm-4.707-1.293a1 1 0 0 0-1.414 1.414l1.414-1.414zm-.707.707l-.707-.707.707.707zM9 11v-1a1 1 0 0 0-.707.293L9 11zm-4 0h1a1 1 0 0 0-1-1v1zm0 4H4a1 1 0 0 0 1.707.707L5 15zm10-9h2V4h-2v2zm2 0a1 1 0 0 1 1 1h2a3 3 0 0 0-3-3v2zm1 1v6h2V7h-2zm0 6a1 1 0 0 1-1 1v2a3 3 0 0 0 3-3h-2zm-1 1h-2v2h2v-2zm-3 1v4h2v-4h-2zm1.707 3.293l-4-4-1.414 1.414 4 4 1.414-1.414zM11 14H7v2h4v-2zm-4 0c-.276 0-.525-.111-.707-.293l-1.414 1.414C5.42 15.663 6.172 16 7 16v-2zm-.707 1.121l3.414-3.414-1.414-1.414-3.414 3.414 1.414 1.414zM9 12h4v-2H9v2zm4 0a3 3 0 0 0 3-3h-2a1 1 0 0 1-1 1v2zm3-3V3h-2v6h2zm0-6a3 3 0 0 0-3-3v2a1 1 0 0 1 1 1h2zm-3-3H3v2h10V0zM3 0a3 3 0 0 0-3 3h2a1 1 0 0 1 1-1V0zM0 3v6h2V3H0zm0 6a3 3 0 0 0 3 3v-2a1 1 0 0 1-1-1H0zm3 3h2v-2H3v2zm1-1v4h2v-4H4zm1.707 4.707l.586-.586-1.414-1.414-.586.586 1.414 1.414z"
|
||||
/>
|
||||
|
@ -1,5 +1,10 @@
|
||||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="17" fill="currentColor">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="20"
|
||||
height="17"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
d="M11 2.253a1 1 0 1 0-2 0h2zm-2 13a1 1 0 1 0 2 0H9zm.447-12.167a1 1 0 1 0 1.107-1.666L9.447 3.086zM1 2.253L.447 1.42A1 1 0 0 0 0 2.253h1zm0 13H0a1 1 0 0 0 1.553.833L1 15.253zm8.447.833a1 1 0 1 0 1.107-1.666l-1.107 1.666zm0-14.666a1 1 0 1 0 1.107 1.666L9.447 1.42zM19 2.253h1a1 1 0 0 0-.447-.833L19 2.253zm0 13l-.553.833A1 1 0 0 0 20 15.253h-1zm-9.553-.833a1 1 0 1 0 1.107 1.666L9.447 14.42zM9 2.253v13h2v-13H9zm1.553-.833C9.203.523 7.42 0 5.5 0v2c1.572 0 2.961.431 3.947 1.086l1.107-1.666zM5.5 0C3.58 0 1.797.523.447 1.42l1.107 1.666C2.539 2.431 3.928 2 5.5 2V0zM0 2.253v13h2v-13H0zm1.553 13.833C2.539 15.431 3.928 15 5.5 15v-2c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM5.5 15c1.572 0 2.961.431 3.947 1.086l1.107-1.666C9.203 13.523 7.42 13 5.5 13v2zm5.053-11.914C11.539 2.431 12.928 2 14.5 2V0c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM14.5 2c1.573 0 2.961.431 3.947 1.086l1.107-1.666C18.203.523 16.421 0 14.5 0v2zm3.5.253v13h2v-13h-2zm1.553 12.167C18.203 13.523 16.421 13 14.5 13v2c1.573 0 2.961.431 3.947 1.086l1.107-1.666zM14.5 13c-1.92 0-3.703.523-5.053 1.42l1.107 1.666C11.539 15.431 12.928 15 14.5 15v-2z"
|
||||
/>
|
||||
|
@ -1,5 +1,10 @@
|
||||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="20" fill="currentColor">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="18"
|
||||
height="20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
d="M11.447 8.894a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm0 1.789a1 1 0 1 0 .894-1.789l-.894 1.789zM7.447 7.106a1 1 0 1 0-.894 1.789l.894-1.789zM10 9a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0H8zm9.447-5.606a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm2 .789a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zM18 5a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0h-2zm-5.447-4.606a1 1 0 1 0 .894-1.789l-.894 1.789zM9 1l.447-.894a1 1 0 0 0-.894 0L9 1zm-2.447.106a1 1 0 1 0 .894 1.789l-.894-1.789zm-6 3a1 1 0 1 0 .894 1.789L.553 4.106zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zm-2-.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 2.789a1 1 0 1 0 .894-1.789l-.894 1.789zM2 5a1 1 0 1 0-2 0h2zM0 7.5a1 1 0 1 0 2 0H0zm8.553 12.394a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 1a1 1 0 1 0 .894 1.789l-.894-1.789zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zM8 19a1 1 0 1 0 2 0H8zm2-2.5a1 1 0 1 0-2 0h2zm-7.447.394a1 1 0 1 0 .894-1.789l-.894 1.789zM1 15H0a1 1 0 0 0 .553.894L1 15zm1-2.5a1 1 0 1 0-2 0h2zm12.553 2.606a1 1 0 1 0 .894 1.789l-.894-1.789zM17 15l.447.894A1 1 0 0 0 18 15h-1zm1-2.5a1 1 0 1 0-2 0h2zm-7.447-5.394l-2 1 .894 1.789 2-1-.894-1.789zm-1.106 1l-2-1-.894 1.789 2 1 .894-1.789zM8 9v2.5h2V9H8zm8.553-4.894l-2 1 .894 1.789 2-1-.894-1.789zm.894 0l-2-1-.894 1.789 2 1 .894-1.789zM16 5v2.5h2V5h-2zm-4.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zm-2.894-1l-2 1 .894 1.789 2-1L8.553.106zM1.447 5.894l2-1-.894-1.789-2 1 .894 1.789zm-.894 0l2 1 .894-1.789-2-1-.894 1.789zM0 5v2.5h2V5H0zm9.447 13.106l-2-1-.894 1.789 2 1 .894-1.789zm0 1.789l2-1-.894-1.789-2 1 .894 1.789zM10 19v-2.5H8V19h2zm-6.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zM2 15v-2.5H0V15h2zm13.447 1.894l2-1-.894-1.789-2 1 .894 1.789zM18 15v-2.5h-2V15h2z"
|
||||
/>
|
||||
|
@ -1,5 +1,10 @@
|
||||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="20"
|
||||
height="20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
d="M10 3.22l-.61-.6a5.5 5.5 0 0 0-7.666.105 5.5 5.5 0 0 0-.114 7.665L10 18.78l8.39-8.4a5.5 5.5 0 0 0-.114-7.665 5.5 5.5 0 0 0-7.666-.105l-.61.61z"
|
||||
/>
|
||||
|
@ -1,17 +1,18 @@
|
||||
<script lang="ts">
|
||||
import { useSkins } from '@core/composable/useSkins'
|
||||
import { useSkins } from '@core/composable/useSkins';
|
||||
|
||||
export default defineComponent({
|
||||
setup() {
|
||||
const routerView = resolveComponent('router-view')
|
||||
const { injectSkinClasses } = useSkins()
|
||||
const routerView = resolveComponent('router-view');
|
||||
const { injectSkinClasses } = useSkins();
|
||||
|
||||
// ℹ️ This will inject classes in body tag for accurate styling
|
||||
injectSkinClasses()
|
||||
injectSkinClasses();
|
||||
|
||||
return () => h('div', { class: 'layout-wrapper layout-blank' }, h(routerView))
|
||||
return () =>
|
||||
h('div', { class: 'layout-wrapper layout-blank' }, h(routerView));
|
||||
},
|
||||
})
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
@ -4,22 +4,27 @@ import { computed } from '@vue/reactivity';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
const chain = useBlockchain()
|
||||
const route = useRoute()
|
||||
const i18n = useI18n()
|
||||
/// To display human readable module name, we have to set the prefix("module.") + route name to the key in i18n.
|
||||
const chain = useBlockchain();
|
||||
const route = useRoute();
|
||||
const i18n = useI18n();
|
||||
/// To display human readable module name, we have to set the prefix("module.") + route name to the key in i18n.
|
||||
/// such as `module.chain` = 'Dashboard'
|
||||
const moduleName = computed(() => i18n.t(`module.${route.name?.toString()||''}`))
|
||||
const items = computed(() => [{title: String(chain.name).toUpperCase(), href: `/${chain.name}`}, moduleName.value])
|
||||
const moduleName = computed(() =>
|
||||
i18n.t(`module.${route.name?.toString() || ''}`)
|
||||
);
|
||||
const items = computed(() => [
|
||||
{ title: String(chain.name).toUpperCase(), href: `/${chain.name}` },
|
||||
moduleName.value,
|
||||
]);
|
||||
</script>
|
||||
<template>
|
||||
<div class="d-flex flex-rows align-center">
|
||||
<span class="text-h5 mr-3">{{ moduleName }}</span>
|
||||
<v-icon icon="mdi-dots-vertical" />
|
||||
<v-icon icon="mdi-dots-vertical" />
|
||||
<VBreadcrumbs :items="items">
|
||||
<template v-slot:divider>
|
||||
<v-icon icon="mdi-chevron-right"></v-icon>
|
||||
</template>
|
||||
<template v-slot:divider>
|
||||
<v-icon icon="mdi-chevron-right"></v-icon>
|
||||
</template>
|
||||
</VBreadcrumbs>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
|
@ -1,61 +1,72 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import { useBlockchain, useBaseStore } from '@/stores';
|
||||
const chainStore = useBlockchain()
|
||||
const baseStore = useBaseStore()
|
||||
chainStore.initial()
|
||||
const chainStore = useBlockchain();
|
||||
const baseStore = useBaseStore();
|
||||
chainStore.initial();
|
||||
chainStore.$subscribe((m, s) => {
|
||||
if(!Array.isArray(m.events) && m.events.key === 'endpoint') {
|
||||
chainStore.initial()
|
||||
if (!Array.isArray(m.events) && m.events.key === 'endpoint') {
|
||||
chainStore.initial();
|
||||
}
|
||||
})
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VListItem class="m-0 p-0">
|
||||
<template #prepend>
|
||||
<VBadge
|
||||
dot
|
||||
location="bottom right"
|
||||
offset-x="3"
|
||||
offset-y="3"
|
||||
bordered
|
||||
color="success"
|
||||
class="mr-2"
|
||||
>
|
||||
<VAvatar
|
||||
class="cursor-pointer"
|
||||
color="primary"
|
||||
variant="tonal"
|
||||
<VBadge
|
||||
dot
|
||||
location="bottom right"
|
||||
offset-x="3"
|
||||
offset-y="3"
|
||||
bordered
|
||||
color="success"
|
||||
class="mr-2"
|
||||
>
|
||||
<VImg :src="chainStore.logo" />
|
||||
<VAvatar class="cursor-pointer" color="primary" variant="tonal">
|
||||
<VImg :src="chainStore.logo" />
|
||||
|
||||
<!-- SECTION Menu -->
|
||||
<VMenu
|
||||
activator="parent"
|
||||
location="bottom start"
|
||||
offset="14px"
|
||||
>
|
||||
<VList>
|
||||
<!-- 👉 Rest -->
|
||||
<VListSubheader v-if="chainStore.current?.endpoints?.rest" title="Rest Endpoint" />
|
||||
<VListItem v-for="i in chainStore.current?.endpoints?.rest" link @click="chainStore.setRestEndpoint(i)">
|
||||
<VListItemTitle>{{ i.provider }} <VIcon v-if="i.address === chainStore.endpoint?.address" icon="mdi-check" color="success" /></VListItemTitle>
|
||||
<VListItemSubtitle>{{ i.address }}</VListItemSubtitle>
|
||||
</VListItem>
|
||||
<!-- SECTION Menu -->
|
||||
<VMenu activator="parent" location="bottom start" offset="14px">
|
||||
<VList>
|
||||
<!-- 👉 Rest -->
|
||||
<VListSubheader
|
||||
v-if="chainStore.current?.endpoints?.rest"
|
||||
title="Rest Endpoint"
|
||||
/>
|
||||
<VListItem
|
||||
v-for="i in chainStore.current?.endpoints?.rest"
|
||||
link
|
||||
@click="chainStore.setRestEndpoint(i)"
|
||||
>
|
||||
<VListItemTitle
|
||||
>{{ i.provider }}
|
||||
<VIcon
|
||||
v-if="i.address === chainStore.endpoint?.address"
|
||||
icon="mdi-check"
|
||||
color="success"
|
||||
/></VListItemTitle>
|
||||
<VListItemSubtitle>{{ i.address }}</VListItemSubtitle>
|
||||
</VListItem>
|
||||
|
||||
<VListSubheader v-if="chainStore.current?.endpoints?.grpc" title="gRPC Endpoint" />
|
||||
<VListItem v-for="i in chainStore.current?.endpoints?.grpc" link>
|
||||
<VListItemTitle>{{ i.provider }}</VListItemTitle>
|
||||
<VListItemSubtitle>{{ i.address }}</VListItemSubtitle>
|
||||
</VListItem>
|
||||
</VList>
|
||||
</VMenu>
|
||||
<!-- !SECTION -->
|
||||
</VAvatar>
|
||||
</VBadge>
|
||||
</template>
|
||||
<VListItemTitle>{{ baseStore.latest.block?.header?.chain_id || chainStore.chainName || '' }}</VListItemTitle>
|
||||
<VListItemSubtitle> {{ chainStore.connErr|| chainStore.endpoint.address }}</VListItemSubtitle>
|
||||
<VListSubheader
|
||||
v-if="chainStore.current?.endpoints?.grpc"
|
||||
title="gRPC Endpoint"
|
||||
/>
|
||||
<VListItem v-for="i in chainStore.current?.endpoints?.grpc" link>
|
||||
<VListItemTitle>{{ i.provider }}</VListItemTitle>
|
||||
<VListItemSubtitle>{{ i.address }}</VListItemSubtitle>
|
||||
</VListItem>
|
||||
</VList>
|
||||
</VMenu>
|
||||
<!-- !SECTION -->
|
||||
</VAvatar>
|
||||
</VBadge>
|
||||
</template>
|
||||
<VListItemTitle>{{
|
||||
baseStore.latest.block?.header?.chain_id || chainStore.chainName || ''
|
||||
}}</VListItemTitle>
|
||||
<VListItemSubtitle>
|
||||
{{ chainStore.connErr || chainStore.endpoint.address }}</VListItemSubtitle
|
||||
>
|
||||
</VListItem>
|
||||
</template>
|
||||
|
@ -67,7 +67,7 @@ blockchain.$subscribe((m, s) => {
|
||||
<NavBarNotifications class="hidden md:inline-block" />
|
||||
<NavBarI18n class="hidden md:inline-block" />
|
||||
<NavbarThemeSwitcher class="hidden md:inline-block" />
|
||||
<ConnectWallet class="md:inline-block"/>
|
||||
<ConnectWallet class="md:inline-block" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
<script lang="ts" setup>
|
||||
import NavBarI18n from '@core/components/I18n.vue'
|
||||
import { useThemeConfig } from '@core/composable/useThemeConfig'
|
||||
import type { I18nLanguage } from '@layouts/types'
|
||||
import NavBarI18n from '@core/components/I18n.vue';
|
||||
import { useThemeConfig } from '@core/composable/useThemeConfig';
|
||||
import type { I18nLanguage } from '@layouts/types';
|
||||
|
||||
const { isAppRtl } = useThemeConfig()
|
||||
const { isAppRtl } = useThemeConfig();
|
||||
|
||||
const i18nCompLanguages: I18nLanguage[] = [
|
||||
{
|
||||
@ -18,17 +18,14 @@ const i18nCompLanguages: I18nLanguage[] = [
|
||||
label: 'Arabic',
|
||||
i18nLang: 'ar',
|
||||
},
|
||||
]
|
||||
];
|
||||
|
||||
const handleLangChange = (lang: string) => {
|
||||
isAppRtl.value = lang === 'ar'
|
||||
localStorage.setItem('lang', lang)
|
||||
}
|
||||
isAppRtl.value = lang === 'ar';
|
||||
localStorage.setItem('lang', lang);
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NavBarI18n
|
||||
:languages="i18nCompLanguages"
|
||||
@change="handleLangChange"
|
||||
/>
|
||||
<NavBarI18n :languages="i18nCompLanguages" @change="handleLangChange" />
|
||||
</template>
|
||||
|
@ -1,12 +1,12 @@
|
||||
<script lang="ts" setup>
|
||||
import Notifications from '@core/components/Notifications.vue'
|
||||
import type { Notification } from '@layouts/types'
|
||||
import Notifications from '@core/components/Notifications.vue';
|
||||
import type { Notification } from '@layouts/types';
|
||||
|
||||
// Images
|
||||
import avatar3 from '@images/avatars/avatar-3.png'
|
||||
import avatar4 from '@images/avatars/avatar-4.png'
|
||||
import avatar5 from '@images/avatars/avatar-5.png'
|
||||
import paypal from '@images/svg/paypal.svg'
|
||||
import avatar3 from '@images/avatars/avatar-3.png';
|
||||
import avatar4 from '@images/avatars/avatar-4.png';
|
||||
import avatar5 from '@images/avatars/avatar-5.png';
|
||||
import paypal from '@images/svg/paypal.svg';
|
||||
|
||||
const notifications = ref<Notification[]>([
|
||||
{
|
||||
@ -50,32 +50,29 @@ const notifications = ref<Notification[]>([
|
||||
time: '19 Mar',
|
||||
isRead: false,
|
||||
},
|
||||
])
|
||||
]);
|
||||
|
||||
const removeNotification = (notificationId: number) => {
|
||||
notifications.value.forEach((item, index) => {
|
||||
if (notificationId === item.id)
|
||||
notifications.value.splice(index, 1)
|
||||
})
|
||||
}
|
||||
if (notificationId === item.id) notifications.value.splice(index, 1);
|
||||
});
|
||||
};
|
||||
|
||||
const markRead = (notificationId: number[]) => {
|
||||
notifications.value.forEach(item => {
|
||||
notificationId.forEach(id => {
|
||||
if (id === item.id)
|
||||
item.isRead = true
|
||||
})
|
||||
})
|
||||
}
|
||||
notifications.value.forEach((item) => {
|
||||
notificationId.forEach((id) => {
|
||||
if (id === item.id) item.isRead = true;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const markUnRead = (notificationId: number[]) => {
|
||||
notifications.value.forEach(item => {
|
||||
notificationId.forEach(id => {
|
||||
if (id === item.id)
|
||||
item.isRead = false
|
||||
})
|
||||
})
|
||||
}
|
||||
notifications.value.forEach((item) => {
|
||||
notificationId.forEach((id) => {
|
||||
if (id === item.id) item.isRead = false;
|
||||
});
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -36,7 +36,7 @@ const shortcuts = [
|
||||
subtitle: 'FAQs & Articles',
|
||||
to: { name: 'pages-help-center' },
|
||||
},
|
||||
]
|
||||
];
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { ThemeSwitcherTheme } from '@layouts/types'
|
||||
import NewThemeSwitcher from '@/components/ThemeSwitcher.vue'
|
||||
import type { ThemeSwitcherTheme } from '@layouts/types';
|
||||
import NewThemeSwitcher from '@/components/ThemeSwitcher.vue';
|
||||
const themes: ThemeSwitcherTheme[] = [
|
||||
{
|
||||
name: 'system',
|
||||
@ -14,11 +14,11 @@ const themes: ThemeSwitcherTheme[] = [
|
||||
name: 'dark',
|
||||
icon: 'mdi-weather-night',
|
||||
},
|
||||
]
|
||||
];
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<NewThemeSwitcher :themes="themes"/>
|
||||
<NewThemeSwitcher :themes="themes" />
|
||||
</div>
|
||||
</template>
|
||||
|
@ -1,26 +1,34 @@
|
||||
<template>
|
||||
<footer class="footer items-center p-4 text-base">
|
||||
<div class="items-center grid-flow-col">
|
||||
©
|
||||
{{ new Date().getFullYear() }}
|
||||
Made With
|
||||
<img src="../../assets/images/heart.svg"/>
|
||||
By
|
||||
<a class="link link-info no-underline"
|
||||
href="https://ping.pub"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>Ping.pub</a>
|
||||
</div>
|
||||
<div class="grid-flow-col gap-4 md:place-self-center md:justify-self-end hidden md:grid">
|
||||
<a class="link link-info no-underline"
|
||||
href="https://github.com/ping-pub/explorer/blob/master/LICENSE"
|
||||
target="noopener noreferrer"
|
||||
>License</a>
|
||||
<a class="link link-info no-underline"
|
||||
href="https://github.com/ping-pub/explorer"
|
||||
target="noopener noreferrer"
|
||||
>Github</a>
|
||||
</div>
|
||||
</footer>
|
||||
</template>
|
||||
<footer class="footer items-center p-4 text-base">
|
||||
<div class="items-center grid-flow-col">
|
||||
©
|
||||
{{ new Date().getFullYear() }}
|
||||
Made With
|
||||
<img src="../../assets/images/heart.svg" />
|
||||
By
|
||||
<a
|
||||
class="link link-info no-underline"
|
||||
href="https://ping.pub"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>Ping.pub</a
|
||||
>
|
||||
</div>
|
||||
<div
|
||||
class="grid-flow-col gap-4 md:place-self-center md:justify-self-end hidden md:grid"
|
||||
>
|
||||
<a
|
||||
class="link link-info no-underline"
|
||||
href="https://github.com/ping-pub/explorer/blob/master/LICENSE"
|
||||
target="noopener noreferrer"
|
||||
>License</a
|
||||
>
|
||||
<a
|
||||
class="link link-info no-underline"
|
||||
href="https://github.com/ping-pub/explorer"
|
||||
target="noopener noreferrer"
|
||||
>Github</a
|
||||
>
|
||||
</div>
|
||||
</footer>
|
||||
</template>
|
||||
|
@ -1,65 +1,79 @@
|
||||
import {fromBase64, fromBech32, fromHex, toBase64, toBech32, toHex} from '@cosmjs/encoding'
|
||||
import { Ripemd160, sha256 } from '@cosmjs/crypto'
|
||||
import {
|
||||
fromBase64,
|
||||
fromBech32,
|
||||
fromHex,
|
||||
toBase64,
|
||||
toBech32,
|
||||
toHex,
|
||||
} from '@cosmjs/encoding';
|
||||
import { Ripemd160, sha256 } from '@cosmjs/crypto';
|
||||
|
||||
export function decodeAddress(address: string) {
|
||||
return fromBech32(address)
|
||||
return fromBech32(address);
|
||||
}
|
||||
|
||||
export function valoperToPrefix(valoper?: string) {
|
||||
if(!valoper) return ''
|
||||
const prefixIndex = valoper.indexOf('valoper')
|
||||
if (prefixIndex === -1) return null
|
||||
return valoper.slice(0, prefixIndex)
|
||||
}
|
||||
|
||||
export function operatorAddressToAccount(operAddress?: string) {
|
||||
if(!operAddress) return ''
|
||||
const { prefix, data } = fromBech32(operAddress)
|
||||
if (prefix === 'iva') { // handle special cases
|
||||
return toBech32('iaa', data)
|
||||
}
|
||||
if (prefix === 'crocncl') { // handle special cases
|
||||
return toBech32('cro', data)
|
||||
}
|
||||
return toBech32(prefix.replace('valoper', ''), data)
|
||||
}
|
||||
if (!valoper) return '';
|
||||
const prefixIndex = valoper.indexOf('valoper');
|
||||
if (prefixIndex === -1) return null;
|
||||
return valoper.slice(0, prefixIndex);
|
||||
}
|
||||
|
||||
export function consensusPubkeyToHexAddress(consensusPubkey?: {"@type": string, key: string}) {
|
||||
if(!consensusPubkey) return ""
|
||||
let raw = ""
|
||||
export function operatorAddressToAccount(operAddress?: string) {
|
||||
if (!operAddress) return '';
|
||||
const { prefix, data } = fromBech32(operAddress);
|
||||
if (prefix === 'iva') {
|
||||
// handle special cases
|
||||
return toBech32('iaa', data);
|
||||
}
|
||||
if (prefix === 'crocncl') {
|
||||
// handle special cases
|
||||
return toBech32('cro', data);
|
||||
}
|
||||
return toBech32(prefix.replace('valoper', ''), data);
|
||||
}
|
||||
|
||||
export function consensusPubkeyToHexAddress(consensusPubkey?: {
|
||||
'@type': string;
|
||||
key: string;
|
||||
}) {
|
||||
if (!consensusPubkey) return '';
|
||||
let raw = '';
|
||||
if (consensusPubkey['@type'] === '/cosmos.crypto.ed25519.PubKey') {
|
||||
const pubkey = fromBase64(consensusPubkey.key)
|
||||
if(pubkey) return toHex(sha256(pubkey)).slice(0, 40).toUpperCase()
|
||||
const pubkey = fromBase64(consensusPubkey.key);
|
||||
if (pubkey) return toHex(sha256(pubkey)).slice(0, 40).toUpperCase();
|
||||
}
|
||||
|
||||
if (consensusPubkey['@type'] === '/cosmos.crypto.secp256k1.PubKey') {
|
||||
const pubkey = fromBase64(consensusPubkey.key)
|
||||
if(pubkey) return toHex(new Ripemd160().update(sha256(pubkey)).digest())
|
||||
const pubkey = fromBase64(consensusPubkey.key);
|
||||
if (pubkey) return toHex(new Ripemd160().update(sha256(pubkey)).digest());
|
||||
}
|
||||
return raw
|
||||
|
||||
return raw;
|
||||
}
|
||||
|
||||
export function pubKeyToValcons(consensusPubkey: {"@type": string, key: string}, prefix: string) {
|
||||
if(consensusPubkey && consensusPubkey.key) {
|
||||
const pubkey = fromBase64(consensusPubkey.key)
|
||||
if(pubkey) {
|
||||
const addressData = sha256(pubkey).slice(0, 20)
|
||||
return toBech32(`${prefix}valcons`, addressData)
|
||||
}
|
||||
export function pubKeyToValcons(
|
||||
consensusPubkey: { '@type': string; key: string },
|
||||
prefix: string
|
||||
) {
|
||||
if (consensusPubkey && consensusPubkey.key) {
|
||||
const pubkey = fromBase64(consensusPubkey.key);
|
||||
if (pubkey) {
|
||||
const addressData = sha256(pubkey).slice(0, 20);
|
||||
return toBech32(`${prefix}valcons`, addressData);
|
||||
}
|
||||
return ''
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
export function valconsToBase64(address: string) {
|
||||
if(address) return toHex(fromBech32(address).data).toUpperCase()
|
||||
return ''
|
||||
}
|
||||
|
||||
export function toETHAddress(cosmosAddress: string) {
|
||||
return `0x${toHex(fromBech32(cosmosAddress).data)}`
|
||||
}
|
||||
|
||||
export function addressEnCode(prefix: string, pubkey: Uint8Array) {
|
||||
return toBech32(prefix, pubkey)
|
||||
}
|
||||
export function valconsToBase64(address: string) {
|
||||
if (address) return toHex(fromBech32(address).data).toUpperCase();
|
||||
return '';
|
||||
}
|
||||
|
||||
export function toETHAddress(cosmosAddress: string) {
|
||||
return `0x${toHex(fromBech32(cosmosAddress).data)}`;
|
||||
}
|
||||
|
||||
export function addressEnCode(prefix: string, pubkey: Uint8Array) {
|
||||
return toBech32(prefix, pubkey);
|
||||
}
|
||||
|
262
src/libs/api.ts
262
src/libs/api.ts
@ -1,77 +1,203 @@
|
||||
import { type RequestRegistry, type Registry, adapter, withCustomAdapter } from "./registry";
|
||||
import {
|
||||
type RequestRegistry,
|
||||
type Registry,
|
||||
adapter,
|
||||
withCustomAdapter,
|
||||
} from './registry';
|
||||
|
||||
export const DEFAULT: RequestRegistry = {
|
||||
auth_params: { url: "/cosmos/auth/v1beta1/params", adapter },
|
||||
auth_accounts: { url: "/cosmos/auth/v1beta1/accounts", adapter },
|
||||
auth_account_address: { url: "/cosmos/auth/v1beta1/accounts/{address}", adapter },
|
||||
bank_params: { url: "/cosmos/bank/v1beta1/params", adapter },
|
||||
bank_balances_address: { url: "/cosmos/bank/v1beta1/balances/{address}", adapter },
|
||||
bank_denoms_metadata: { url: "/cosmos/bank/v1beta1/denoms_metadata", adapter },
|
||||
bank_supply: { url: "/cosmos/bank/v1beta1/supply", adapter },
|
||||
bank_supply_by_denom: { url: "/cosmos/bank/v1beta1/supply/{denom}", adapter },
|
||||
distribution_params: { url: "/cosmos/distribution/v1beta1/params", adapter },
|
||||
distribution_community_pool: { url: "/cosmos/distribution/v1beta1/community_pool", adapter },
|
||||
distribution_validator_commission: { url: "/cosmos/distribution/v1beta1/validators/{validator_address}/commission", adapter },
|
||||
distribution_validator_outstanding_rewards: { url: "/cosmos/distribution/v1beta1/validators/{validator_address}/outstanding_rewards", adapter },
|
||||
distribution_validator_slashes: { url: "/cosmos/distribution/v1beta1/validators/{validator_address}/slashes", adapter },
|
||||
distribution_delegator_rewards: { url: "/cosmos/distribution/v1beta1/delegators/{delegator_addr}/rewards", adapter },
|
||||
slashing_params: { url: "/cosmos/slashing/v1beta1/params", adapter },
|
||||
slashing_signing_info: { url: "/cosmos/slashing/v1beta1/signing_infos", adapter },
|
||||
gov_params_voting: { url: "/cosmos/gov/v1beta1/params/voting", adapter },
|
||||
gov_params_tally: { url: "/cosmos/gov/v1beta1/params/tallying", adapter },
|
||||
gov_params_deposit: { url: "/cosmos/gov/v1beta1/params/deposit", adapter },
|
||||
gov_proposals: { url: "/cosmos/gov/v1beta1/proposals", adapter },
|
||||
gov_proposals_proposal_id: { url: "/cosmos/gov/v1beta1/proposals/{proposal_id}", adapter },
|
||||
gov_proposals_deposits: { url: "/cosmos/gov/v1beta1/proposals/{proposal_id}/deposits", adapter },
|
||||
gov_proposals_tally: { url: "/cosmos/gov/v1beta1/proposals/{proposal_id}/tally", adapter },
|
||||
gov_proposals_votes: { url: "/cosmos/gov/v1beta1/proposals/{proposal_id}/votes?pagination.key={next_key}", adapter },
|
||||
gov_proposals_votes_voter: { url: "/cosmos/gov/v1beta1/proposals/{proposal_id}/votes/{voter}", adapter },
|
||||
staking_deletations: { url: "/cosmos/staking/v1beta1/delegations/{delegator_addr}", adapter },
|
||||
staking_delegator_redelegations: { url: "/cosmos/staking/v1beta1/delegators/{delegator_addr}/redelegations", adapter },
|
||||
staking_delegator_unbonding_delegations: { url: "/cosmos/staking/v1beta1/delegators/{delegator_addr}/unbonding_delegations", adapter },
|
||||
staking_delegator_validators: { url: "/cosmos/staking/v1beta1/delegators/{delegator_addr}/validators", adapter },
|
||||
staking_params: { url: "/cosmos/staking/v1beta1/params", adapter },
|
||||
staking_pool: { url: "/cosmos/staking/v1beta1/pool", adapter },
|
||||
staking_validators: { url: "/cosmos/staking/v1beta1/validators?pagination.limit={limit}&status={status}", adapter },
|
||||
staking_validators_address: { url: "/cosmos/staking/v1beta1/validators/{validator_addr}", adapter },
|
||||
staking_validators_delegations: { url: "/cosmos/staking/v1beta1/validators/{validator_addr}/delegations", adapter },
|
||||
staking_validators_delegations_delegator: { url: "/cosmos/staking/v1beta1/validators/{validator_addr}/delegations/{delegator_addr}", adapter },
|
||||
staking_validators_delegations_unbonding_delegations: { url: "/cosmos/staking/v1beta1/validators/{validator_addr}/delegations/{delegator_addr}/unbonding_delegation", adapter },
|
||||
base_tendermint_abci_query: { url: "/cosmos/base/tendermint/v1beta1/abci_query", adapter },
|
||||
base_tendermint_block_latest: { url: "/cosmos/base/tendermint/v1beta1/blocks/latest", adapter },
|
||||
base_tendermint_block_height: { url: "/cosmos/base/tendermint/v1beta1/blocks/{height}", adapter },
|
||||
base_tendermint_node_info: { url: "/cosmos/base/tendermint/v1beta1/node_info", adapter },
|
||||
base_tendermint_validatorsets_latest: { url: "/cosmos/base/tendermint/v1beta1/validatorsets/latest", adapter },
|
||||
base_tendermint_validatorsets_height: { url: "/cosmos/base/tendermint/v1beta1/validatorsets/{height}", adapter },
|
||||
tx_txs: { url: "/cosmos/tx/v1beta1/txs", adapter },
|
||||
tx_txs_block: { url: "/cosmos/tx/v1beta1/txs/block/{height}", adapter },
|
||||
tx_hash: { url: "/cosmos/tx/v1beta1/txs/{hash}", adapter },
|
||||
auth_params: { url: '/cosmos/auth/v1beta1/params', adapter },
|
||||
auth_accounts: { url: '/cosmos/auth/v1beta1/accounts', adapter },
|
||||
auth_account_address: {
|
||||
url: '/cosmos/auth/v1beta1/accounts/{address}',
|
||||
adapter,
|
||||
},
|
||||
bank_params: { url: '/cosmos/bank/v1beta1/params', adapter },
|
||||
bank_balances_address: {
|
||||
url: '/cosmos/bank/v1beta1/balances/{address}',
|
||||
adapter,
|
||||
},
|
||||
bank_denoms_metadata: {
|
||||
url: '/cosmos/bank/v1beta1/denoms_metadata',
|
||||
adapter,
|
||||
},
|
||||
bank_supply: { url: '/cosmos/bank/v1beta1/supply', adapter },
|
||||
bank_supply_by_denom: { url: '/cosmos/bank/v1beta1/supply/{denom}', adapter },
|
||||
distribution_params: { url: '/cosmos/distribution/v1beta1/params', adapter },
|
||||
distribution_community_pool: {
|
||||
url: '/cosmos/distribution/v1beta1/community_pool',
|
||||
adapter,
|
||||
},
|
||||
distribution_validator_commission: {
|
||||
url: '/cosmos/distribution/v1beta1/validators/{validator_address}/commission',
|
||||
adapter,
|
||||
},
|
||||
distribution_validator_outstanding_rewards: {
|
||||
url: '/cosmos/distribution/v1beta1/validators/{validator_address}/outstanding_rewards',
|
||||
adapter,
|
||||
},
|
||||
distribution_validator_slashes: {
|
||||
url: '/cosmos/distribution/v1beta1/validators/{validator_address}/slashes',
|
||||
adapter,
|
||||
},
|
||||
distribution_delegator_rewards: {
|
||||
url: '/cosmos/distribution/v1beta1/delegators/{delegator_addr}/rewards',
|
||||
adapter,
|
||||
},
|
||||
slashing_params: { url: '/cosmos/slashing/v1beta1/params', adapter },
|
||||
slashing_signing_info: {
|
||||
url: '/cosmos/slashing/v1beta1/signing_infos',
|
||||
adapter,
|
||||
},
|
||||
gov_params_voting: { url: '/cosmos/gov/v1beta1/params/voting', adapter },
|
||||
gov_params_tally: { url: '/cosmos/gov/v1beta1/params/tallying', adapter },
|
||||
gov_params_deposit: { url: '/cosmos/gov/v1beta1/params/deposit', adapter },
|
||||
gov_proposals: { url: '/cosmos/gov/v1beta1/proposals', adapter },
|
||||
gov_proposals_proposal_id: {
|
||||
url: '/cosmos/gov/v1beta1/proposals/{proposal_id}',
|
||||
adapter,
|
||||
},
|
||||
gov_proposals_deposits: {
|
||||
url: '/cosmos/gov/v1beta1/proposals/{proposal_id}/deposits',
|
||||
adapter,
|
||||
},
|
||||
gov_proposals_tally: {
|
||||
url: '/cosmos/gov/v1beta1/proposals/{proposal_id}/tally',
|
||||
adapter,
|
||||
},
|
||||
gov_proposals_votes: {
|
||||
url: '/cosmos/gov/v1beta1/proposals/{proposal_id}/votes?pagination.key={next_key}',
|
||||
adapter,
|
||||
},
|
||||
gov_proposals_votes_voter: {
|
||||
url: '/cosmos/gov/v1beta1/proposals/{proposal_id}/votes/{voter}',
|
||||
adapter,
|
||||
},
|
||||
staking_deletations: {
|
||||
url: '/cosmos/staking/v1beta1/delegations/{delegator_addr}',
|
||||
adapter,
|
||||
},
|
||||
staking_delegator_redelegations: {
|
||||
url: '/cosmos/staking/v1beta1/delegators/{delegator_addr}/redelegations',
|
||||
adapter,
|
||||
},
|
||||
staking_delegator_unbonding_delegations: {
|
||||
url: '/cosmos/staking/v1beta1/delegators/{delegator_addr}/unbonding_delegations',
|
||||
adapter,
|
||||
},
|
||||
staking_delegator_validators: {
|
||||
url: '/cosmos/staking/v1beta1/delegators/{delegator_addr}/validators',
|
||||
adapter,
|
||||
},
|
||||
staking_params: { url: '/cosmos/staking/v1beta1/params', adapter },
|
||||
staking_pool: { url: '/cosmos/staking/v1beta1/pool', adapter },
|
||||
staking_validators: {
|
||||
url: '/cosmos/staking/v1beta1/validators?pagination.limit={limit}&status={status}',
|
||||
adapter,
|
||||
},
|
||||
staking_validators_address: {
|
||||
url: '/cosmos/staking/v1beta1/validators/{validator_addr}',
|
||||
adapter,
|
||||
},
|
||||
staking_validators_delegations: {
|
||||
url: '/cosmos/staking/v1beta1/validators/{validator_addr}/delegations',
|
||||
adapter,
|
||||
},
|
||||
staking_validators_delegations_delegator: {
|
||||
url: '/cosmos/staking/v1beta1/validators/{validator_addr}/delegations/{delegator_addr}',
|
||||
adapter,
|
||||
},
|
||||
staking_validators_delegations_unbonding_delegations: {
|
||||
url: '/cosmos/staking/v1beta1/validators/{validator_addr}/delegations/{delegator_addr}/unbonding_delegation',
|
||||
adapter,
|
||||
},
|
||||
base_tendermint_abci_query: {
|
||||
url: '/cosmos/base/tendermint/v1beta1/abci_query',
|
||||
adapter,
|
||||
},
|
||||
base_tendermint_block_latest: {
|
||||
url: '/cosmos/base/tendermint/v1beta1/blocks/latest',
|
||||
adapter,
|
||||
},
|
||||
base_tendermint_block_height: {
|
||||
url: '/cosmos/base/tendermint/v1beta1/blocks/{height}',
|
||||
adapter,
|
||||
},
|
||||
base_tendermint_node_info: {
|
||||
url: '/cosmos/base/tendermint/v1beta1/node_info',
|
||||
adapter,
|
||||
},
|
||||
base_tendermint_validatorsets_latest: {
|
||||
url: '/cosmos/base/tendermint/v1beta1/validatorsets/latest',
|
||||
adapter,
|
||||
},
|
||||
base_tendermint_validatorsets_height: {
|
||||
url: '/cosmos/base/tendermint/v1beta1/validatorsets/{height}',
|
||||
adapter,
|
||||
},
|
||||
tx_txs: { url: '/cosmos/tx/v1beta1/txs', adapter },
|
||||
tx_txs_block: { url: '/cosmos/tx/v1beta1/txs/block/{height}', adapter },
|
||||
tx_hash: { url: '/cosmos/tx/v1beta1/txs/{hash}', adapter },
|
||||
|
||||
mint_inflation: { url: "/cosmos/mint/v1beta1/inflation", adapter },
|
||||
mint_params: { url: "/cosmos/mint/v1beta1/params", adapter },
|
||||
mint_annual_provisions: { url: "/cosmos/mint/v1beta1/annual_provisions", adapter },
|
||||
mint_inflation: { url: '/cosmos/mint/v1beta1/inflation', adapter },
|
||||
mint_params: { url: '/cosmos/mint/v1beta1/params', adapter },
|
||||
mint_annual_provisions: {
|
||||
url: '/cosmos/mint/v1beta1/annual_provisions',
|
||||
adapter,
|
||||
},
|
||||
|
||||
// ibc
|
||||
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_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_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_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_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 }
|
||||
// ibc
|
||||
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_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_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_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_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 = {
|
||||
"0.46.1": DEFAULT
|
||||
}
|
||||
'0.46.1': DEFAULT,
|
||||
};
|
||||
|
||||
export const NAME_REGISTRY: Registry = {
|
||||
"evmos": withCustomAdapter(DEFAULT, {})
|
||||
}
|
||||
|
||||
|
||||
evmos: withCustomAdapter(DEFAULT, {}),
|
||||
};
|
||||
|
@ -1,205 +1,268 @@
|
||||
import { fetchData } from '@/libs';
|
||||
import { DEFAULT } from '@/libs'
|
||||
import { adapter, withCustomAdapter, type Request, type RequestRegistry, type Registry, type AbstractRegistry } from './registry';
|
||||
import { DEFAULT } from '@/libs';
|
||||
import {
|
||||
adapter,
|
||||
withCustomAdapter,
|
||||
type Request,
|
||||
type RequestRegistry,
|
||||
type Registry,
|
||||
type AbstractRegistry,
|
||||
} from './registry';
|
||||
|
||||
export class BaseRestClient<R extends AbstractRegistry> {
|
||||
endpoint: string;
|
||||
registry: R;
|
||||
constructor(endpoint: string, registry: R) {
|
||||
this.endpoint = endpoint
|
||||
this.registry = registry
|
||||
}
|
||||
async request<T>(request: Request<T>, args: Record<string, any>, query="") {
|
||||
let url = `${this.endpoint}${request.url}${query}`
|
||||
Object.keys(args).forEach(k => {
|
||||
url = url.replace(`{${k}}`, args[k] || "")
|
||||
})
|
||||
return fetchData<T>(url, adapter)
|
||||
}
|
||||
endpoint: string;
|
||||
registry: R;
|
||||
constructor(endpoint: string, registry: R) {
|
||||
this.endpoint = endpoint;
|
||||
this.registry = registry;
|
||||
}
|
||||
async request<T>(request: Request<T>, args: Record<string, any>, query = '') {
|
||||
let url = `${this.endpoint}${request.url}${query}`;
|
||||
Object.keys(args).forEach((k) => {
|
||||
url = url.replace(`{${k}}`, args[k] || '');
|
||||
});
|
||||
return fetchData<T>(url, adapter);
|
||||
}
|
||||
}
|
||||
|
||||
export class CosmosRestClient extends BaseRestClient<RequestRegistry> {
|
||||
// Auth Module
|
||||
async getAuthAccounts() {
|
||||
return this.request(this.registry.auth_accounts, {})
|
||||
}
|
||||
async getAuthAccount(address: string) {
|
||||
return this.request(this.registry.auth_account_address, {address})
|
||||
}
|
||||
// Bank Module
|
||||
async getBankParams() {
|
||||
return this.request(this.registry.bank_params, {})
|
||||
}
|
||||
async getBankBalances(address: string) {
|
||||
return this.request(this.registry.bank_balances_address, {address})
|
||||
}
|
||||
async getBankDenomMetadata() {
|
||||
return this.request(this.registry.bank_denoms_metadata, {})
|
||||
}
|
||||
async getBankSupply() {
|
||||
return this.request(this.registry.bank_supply, {})
|
||||
}
|
||||
async getBankSupplyByDenom(denom: string) {
|
||||
return this.request(this.registry.bank_supply_by_denom, {denom})
|
||||
}
|
||||
// Distribution Module
|
||||
async getDistributionParams() {
|
||||
return this.request(this.registry.distribution_params, {})
|
||||
}
|
||||
async getDistributionCommunityPool() {
|
||||
return this.request(this.registry.distribution_community_pool, {})
|
||||
}
|
||||
async getDistributionDelegatorRewards(delegator_addr: string) {
|
||||
return this.request(this.registry.distribution_delegator_rewards, {delegator_addr})
|
||||
}
|
||||
async getDistributionValidatorCommission(validator_address: string) {
|
||||
return this.request(this.registry.distribution_validator_commission, {validator_address})
|
||||
}
|
||||
async getDistributionValidatorOutstandingRewards(validator_address: string) {
|
||||
return this.request(this.registry.distribution_validator_outstanding_rewards, {validator_address})
|
||||
}
|
||||
async getDistributionValidatorSlashes(validator_address: string) {
|
||||
return this.request(this.registry.distribution_validator_slashes, {validator_address})
|
||||
}
|
||||
// Slashing
|
||||
async getSlashingParams() {
|
||||
return this.request(this.registry.slashing_params, {})
|
||||
}
|
||||
async getSlashingSigningInfos() {
|
||||
const query = "?pagination.limit=300"
|
||||
return this.request(this.registry.slashing_signing_info, {}, query)
|
||||
}
|
||||
// Gov
|
||||
async getGovParamsVoting() {
|
||||
return this.request(this.registry.gov_params_voting, {})
|
||||
}
|
||||
async getGovParamsDeposit() {
|
||||
return this.request(this.registry.gov_params_deposit, {})
|
||||
}
|
||||
async getGovParamsTally() {
|
||||
return this.request(this.registry.gov_params_tally, {})
|
||||
}
|
||||
async getGovProposals(status: string, limit = 50) {
|
||||
const query = "?proposal_status={status}&pagination.limit={limit}&pagination.reverse=true&pagination.key="
|
||||
return this.request(this.registry.gov_proposals, {status, limit}, query)
|
||||
}
|
||||
async getGovProposal(proposal_id: string) {
|
||||
return this.request(this.registry.gov_proposals_proposal_id, {proposal_id})
|
||||
}
|
||||
async getGovProposalDeposits(proposal_id: string) {
|
||||
return this.request(this.registry.gov_proposals_deposits, {proposal_id})
|
||||
}
|
||||
async getGovProposalTally(proposal_id: string) {
|
||||
return this.request(this.registry.gov_proposals_tally, {proposal_id})
|
||||
}
|
||||
async getGovProposalVotes(proposal_id: string, next_key?: string) {
|
||||
return this.request(this.registry.gov_proposals_votes, {proposal_id, next_key})
|
||||
}
|
||||
async getGovProposalVotesVoter(proposal_id: string, voter: string ) {
|
||||
return this.request(this.registry.gov_proposals_votes_voter, {proposal_id, voter})
|
||||
}
|
||||
// staking
|
||||
async getStakingDelegations(delegator_addr: string) {
|
||||
return this.request(this.registry.staking_deletations, {delegator_addr})
|
||||
}
|
||||
async getStakingDelegatorRedelegations(delegator_addr: string) {
|
||||
return this.request(this.registry.staking_delegator_redelegations, {delegator_addr})
|
||||
}
|
||||
async getStakingDelegatorUnbonding(delegator_addr: string) {
|
||||
return this.request(this.registry.staking_delegator_unbonding_delegations, {delegator_addr})
|
||||
}
|
||||
async getStakingDelegatorValidators(delegator_addr: string) {
|
||||
return this.request(this.registry.staking_delegator_validators, {delegator_addr})
|
||||
}
|
||||
async getStakingParams() {
|
||||
return this.request(this.registry.staking_params, {})
|
||||
}
|
||||
async getStakingPool() {
|
||||
return this.request(this.registry.staking_pool, {})
|
||||
}
|
||||
async getStakingValidators(status: string, limit = 200) {
|
||||
return this.request(this.registry.staking_validators, {status, limit})
|
||||
}
|
||||
async getStakingValidator(validator_addr: string) {
|
||||
return this.request(this.registry.staking_validators_address, {validator_addr})
|
||||
}
|
||||
async getStakingValidatorsDelegations(validator_addr: string) {
|
||||
return this.request(this.registry.staking_validators_delegations, {validator_addr})
|
||||
}
|
||||
async getStakingValidatorsDelegationsDelegator(validator_addr: string, delegator_addr: string) {
|
||||
return this.request(this.registry.staking_validators_delegations_delegator, {validator_addr, delegator_addr})
|
||||
}
|
||||
async getStakingValidatorsDelegationsUnbonding(validator_addr: string, delegator_addr: string) {
|
||||
return this.request(this.registry.staking_validators_delegations_unbonding_delegations, {validator_addr, delegator_addr})
|
||||
}
|
||||
// Auth Module
|
||||
async getAuthAccounts() {
|
||||
return this.request(this.registry.auth_accounts, {});
|
||||
}
|
||||
async getAuthAccount(address: string) {
|
||||
return this.request(this.registry.auth_account_address, { address });
|
||||
}
|
||||
// Bank Module
|
||||
async getBankParams() {
|
||||
return this.request(this.registry.bank_params, {});
|
||||
}
|
||||
async getBankBalances(address: string) {
|
||||
return this.request(this.registry.bank_balances_address, { address });
|
||||
}
|
||||
async getBankDenomMetadata() {
|
||||
return this.request(this.registry.bank_denoms_metadata, {});
|
||||
}
|
||||
async getBankSupply() {
|
||||
return this.request(this.registry.bank_supply, {});
|
||||
}
|
||||
async getBankSupplyByDenom(denom: string) {
|
||||
return this.request(this.registry.bank_supply_by_denom, { denom });
|
||||
}
|
||||
// Distribution Module
|
||||
async getDistributionParams() {
|
||||
return this.request(this.registry.distribution_params, {});
|
||||
}
|
||||
async getDistributionCommunityPool() {
|
||||
return this.request(this.registry.distribution_community_pool, {});
|
||||
}
|
||||
async getDistributionDelegatorRewards(delegator_addr: string) {
|
||||
return this.request(this.registry.distribution_delegator_rewards, {
|
||||
delegator_addr,
|
||||
});
|
||||
}
|
||||
async getDistributionValidatorCommission(validator_address: string) {
|
||||
return this.request(this.registry.distribution_validator_commission, {
|
||||
validator_address,
|
||||
});
|
||||
}
|
||||
async getDistributionValidatorOutstandingRewards(validator_address: string) {
|
||||
return this.request(
|
||||
this.registry.distribution_validator_outstanding_rewards,
|
||||
{ validator_address }
|
||||
);
|
||||
}
|
||||
async getDistributionValidatorSlashes(validator_address: string) {
|
||||
return this.request(this.registry.distribution_validator_slashes, {
|
||||
validator_address,
|
||||
});
|
||||
}
|
||||
// Slashing
|
||||
async getSlashingParams() {
|
||||
return this.request(this.registry.slashing_params, {});
|
||||
}
|
||||
async getSlashingSigningInfos() {
|
||||
const query = '?pagination.limit=300';
|
||||
return this.request(this.registry.slashing_signing_info, {}, query);
|
||||
}
|
||||
// Gov
|
||||
async getGovParamsVoting() {
|
||||
return this.request(this.registry.gov_params_voting, {});
|
||||
}
|
||||
async getGovParamsDeposit() {
|
||||
return this.request(this.registry.gov_params_deposit, {});
|
||||
}
|
||||
async getGovParamsTally() {
|
||||
return this.request(this.registry.gov_params_tally, {});
|
||||
}
|
||||
async getGovProposals(status: string, limit = 50) {
|
||||
const query =
|
||||
'?proposal_status={status}&pagination.limit={limit}&pagination.reverse=true&pagination.key=';
|
||||
return this.request(this.registry.gov_proposals, { status, limit }, query);
|
||||
}
|
||||
async getGovProposal(proposal_id: string) {
|
||||
return this.request(this.registry.gov_proposals_proposal_id, {
|
||||
proposal_id,
|
||||
});
|
||||
}
|
||||
async getGovProposalDeposits(proposal_id: string) {
|
||||
return this.request(this.registry.gov_proposals_deposits, { proposal_id });
|
||||
}
|
||||
async getGovProposalTally(proposal_id: string) {
|
||||
return this.request(this.registry.gov_proposals_tally, { proposal_id });
|
||||
}
|
||||
async getGovProposalVotes(proposal_id: string, next_key?: string) {
|
||||
return this.request(this.registry.gov_proposals_votes, {
|
||||
proposal_id,
|
||||
next_key,
|
||||
});
|
||||
}
|
||||
async getGovProposalVotesVoter(proposal_id: string, voter: string) {
|
||||
return this.request(this.registry.gov_proposals_votes_voter, {
|
||||
proposal_id,
|
||||
voter,
|
||||
});
|
||||
}
|
||||
// staking
|
||||
async getStakingDelegations(delegator_addr: string) {
|
||||
return this.request(this.registry.staking_deletations, { delegator_addr });
|
||||
}
|
||||
async getStakingDelegatorRedelegations(delegator_addr: string) {
|
||||
return this.request(this.registry.staking_delegator_redelegations, {
|
||||
delegator_addr,
|
||||
});
|
||||
}
|
||||
async getStakingDelegatorUnbonding(delegator_addr: string) {
|
||||
return this.request(this.registry.staking_delegator_unbonding_delegations, {
|
||||
delegator_addr,
|
||||
});
|
||||
}
|
||||
async getStakingDelegatorValidators(delegator_addr: string) {
|
||||
return this.request(this.registry.staking_delegator_validators, {
|
||||
delegator_addr,
|
||||
});
|
||||
}
|
||||
async getStakingParams() {
|
||||
return this.request(this.registry.staking_params, {});
|
||||
}
|
||||
async getStakingPool() {
|
||||
return this.request(this.registry.staking_pool, {});
|
||||
}
|
||||
async getStakingValidators(status: string, limit = 200) {
|
||||
return this.request(this.registry.staking_validators, { status, limit });
|
||||
}
|
||||
async getStakingValidator(validator_addr: string) {
|
||||
return this.request(this.registry.staking_validators_address, {
|
||||
validator_addr,
|
||||
});
|
||||
}
|
||||
async getStakingValidatorsDelegations(validator_addr: string) {
|
||||
return this.request(this.registry.staking_validators_delegations, {
|
||||
validator_addr,
|
||||
});
|
||||
}
|
||||
async getStakingValidatorsDelegationsDelegator(
|
||||
validator_addr: string,
|
||||
delegator_addr: string
|
||||
) {
|
||||
return this.request(
|
||||
this.registry.staking_validators_delegations_delegator,
|
||||
{ validator_addr, delegator_addr }
|
||||
);
|
||||
}
|
||||
async getStakingValidatorsDelegationsUnbonding(
|
||||
validator_addr: string,
|
||||
delegator_addr: string
|
||||
) {
|
||||
return this.request(
|
||||
this.registry.staking_validators_delegations_unbonding_delegations,
|
||||
{ validator_addr, delegator_addr }
|
||||
);
|
||||
}
|
||||
|
||||
//tendermint
|
||||
async getBaseAbciQuery() {
|
||||
return this.request(this.registry.base_tendermint_abci_query, {})
|
||||
}
|
||||
async getBaseBlockLatest() {
|
||||
return this.request(this.registry.base_tendermint_block_latest, {})
|
||||
}
|
||||
async getBaseBlockAt(height: string|number) {
|
||||
return this.request(this.registry.base_tendermint_block_height, {height})
|
||||
}
|
||||
async getBaseNodeInfo() {
|
||||
return this.request(this.registry.base_tendermint_node_info, {})
|
||||
}
|
||||
async getBaseValidatorsetAt(height: string|number) {
|
||||
return this.request(this.registry.base_tendermint_validatorsets_height, {height})
|
||||
}
|
||||
async getBaseValidatorsetLatest() {
|
||||
return this.request(this.registry.base_tendermint_validatorsets_latest, {})
|
||||
}
|
||||
// tx
|
||||
async getTxsBySender(sender: string) {
|
||||
const query = `?pagination.reverse=true&events=message.sender='${sender}'`
|
||||
return this.request(this.registry.tx_txs, {}, query)
|
||||
}
|
||||
async getTxsAt(height: string|number) {
|
||||
return this.request(this.registry.tx_txs_block, {height})
|
||||
}
|
||||
async getTx(hash: string) {
|
||||
return this.request(this.registry.tx_hash, {hash})
|
||||
}
|
||||
|
||||
// mint
|
||||
async getMintParam() {
|
||||
return this.request(this.registry.mint_params, {})
|
||||
}
|
||||
async getMintInflation() {
|
||||
return this.request(this.registry.mint_inflation, {})
|
||||
}
|
||||
async getMintAnnualProvisions() {
|
||||
return this.request(this.registry.mint_annual_provisions, {})
|
||||
}
|
||||
|
||||
// ibc
|
||||
async getIBCAppTransferDenom(hash: string) {
|
||||
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})
|
||||
}
|
||||
//tendermint
|
||||
async getBaseAbciQuery() {
|
||||
return this.request(this.registry.base_tendermint_abci_query, {});
|
||||
}
|
||||
async getBaseBlockLatest() {
|
||||
return this.request(this.registry.base_tendermint_block_latest, {});
|
||||
}
|
||||
async getBaseBlockAt(height: string | number) {
|
||||
return this.request(this.registry.base_tendermint_block_height, { height });
|
||||
}
|
||||
async getBaseNodeInfo() {
|
||||
return this.request(this.registry.base_tendermint_node_info, {});
|
||||
}
|
||||
async getBaseValidatorsetAt(height: string | number) {
|
||||
return this.request(this.registry.base_tendermint_validatorsets_height, {
|
||||
height,
|
||||
});
|
||||
}
|
||||
async getBaseValidatorsetLatest() {
|
||||
return this.request(this.registry.base_tendermint_validatorsets_latest, {});
|
||||
}
|
||||
// tx
|
||||
async getTxsBySender(sender: string) {
|
||||
const query = `?pagination.reverse=true&events=message.sender='${sender}'`;
|
||||
return this.request(this.registry.tx_txs, {}, query);
|
||||
}
|
||||
async getTxsAt(height: string | number) {
|
||||
return this.request(this.registry.tx_txs_block, { height });
|
||||
}
|
||||
async getTx(hash: string) {
|
||||
return this.request(this.registry.tx_hash, { hash });
|
||||
}
|
||||
|
||||
// mint
|
||||
async getMintParam() {
|
||||
return this.request(this.registry.mint_params, {});
|
||||
}
|
||||
async getMintInflation() {
|
||||
return this.request(this.registry.mint_inflation, {});
|
||||
}
|
||||
async getMintAnnualProvisions() {
|
||||
return this.request(this.registry.mint_annual_provisions, {});
|
||||
}
|
||||
|
||||
// ibc
|
||||
async getIBCAppTransferDenom(hash: string) {
|
||||
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,6 +1,9 @@
|
||||
import fetch from 'cross-fetch'
|
||||
import fetch from 'cross-fetch';
|
||||
|
||||
export async function fetchData<T>(url: string, adapter: (source: any) => T): Promise<T> {
|
||||
export async function fetchData<T>(
|
||||
url: string,
|
||||
adapter: (source: any) => T
|
||||
): Promise<T> {
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error: ${response.status}`);
|
||||
@ -27,22 +30,22 @@ try {
|
||||
// */
|
||||
|
||||
export async function get(url: string) {
|
||||
return (await fetch(url)).json()
|
||||
return (await fetch(url)).json();
|
||||
}
|
||||
|
||||
export async function post(url: string, data: any) {
|
||||
const response = await fetch(url, {
|
||||
method: 'POST', // *GET, POST, PUT, DELETE, etc.
|
||||
// mode: 'cors', // no-cors, *cors, same-origin
|
||||
// credentials: 'same-origin', // redirect: 'follow', // manual, *follow, error
|
||||
// referrerPolicy: 'origin', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
|
||||
headers: {
|
||||
'Content-Type': 'text/plain',
|
||||
Accept: '*/*',
|
||||
'Accept-Encoding': 'gzip, deflate, br',
|
||||
},
|
||||
body: JSON.stringify(data), // body data type must match "Content-Type" header
|
||||
})
|
||||
// const response = axios.post((config ? config.api : this.config.api) + url, data)
|
||||
return response.json() // parses JSON response into native JavaScript objects
|
||||
}
|
||||
const response = await fetch(url, {
|
||||
method: 'POST', // *GET, POST, PUT, DELETE, etc.
|
||||
// mode: 'cors', // no-cors, *cors, same-origin
|
||||
// credentials: 'same-origin', // redirect: 'follow', // manual, *follow, error
|
||||
// referrerPolicy: 'origin', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
|
||||
headers: {
|
||||
'Content-Type': 'text/plain',
|
||||
Accept: '*/*',
|
||||
'Accept-Encoding': 'gzip, deflate, br',
|
||||
},
|
||||
body: JSON.stringify(data), // body data type must match "Content-Type" header
|
||||
});
|
||||
// const response = axios.post((config ? config.api : this.config.api) + url, data)
|
||||
return response.json(); // parses JSON response into native JavaScript objects
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
export * from './address'
|
||||
export * from './http'
|
||||
export * from './misc'
|
||||
export * from './api'
|
||||
export * from './address';
|
||||
export * from './http';
|
||||
export * from './misc';
|
||||
export * from './api';
|
||||
|
@ -1,16 +1,16 @@
|
||||
import { sha256 } from "@cosmjs/crypto";
|
||||
import { toHex } from "@cosmjs/encoding";
|
||||
import { sha256 } from '@cosmjs/crypto';
|
||||
import { toHex } from '@cosmjs/encoding';
|
||||
|
||||
export function newPageRequest(param: {
|
||||
key?: Uint8Array,
|
||||
limit?: number,
|
||||
offset?: number,
|
||||
countTotal?: boolean,
|
||||
reverse?: boolean
|
||||
key?: Uint8Array;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
countTotal?: boolean;
|
||||
reverse?: boolean;
|
||||
}) {
|
||||
return param
|
||||
return param;
|
||||
}
|
||||
|
||||
export function hashTx(raw: Uint8Array) {
|
||||
return toHex(sha256(raw)).toUpperCase()
|
||||
}
|
||||
return toHex(sha256(raw)).toUpperCase();
|
||||
}
|
||||
|
@ -1,61 +1,101 @@
|
||||
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 { DistributionParams, PaginatedSlashes } from "@/types/distribution";
|
||||
import type { GovParams, GovProposal, GovVote, PaginatedProposalDeposit, PaginatedProposalVotes, PaginatedProposals, Tally } from "@/types/gov";
|
||||
import type { PaginatedSigningInfo } from "@/types/slashing";
|
||||
import type { Delegation, PaginatedDelegations, PaginatedRedelegations, PaginatedUnbonding, PaginatedValdiators, StakingParam, StakingPool, Validator } from "@/types/staking";
|
||||
import type { PaginatedTxs, Tx, TxResponse } from "@/types/tx";
|
||||
|
||||
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 {
|
||||
DistributionParams,
|
||||
PaginatedSlashes,
|
||||
} from '@/types/distribution';
|
||||
import type {
|
||||
GovParams,
|
||||
GovProposal,
|
||||
GovVote,
|
||||
PaginatedProposalDeposit,
|
||||
PaginatedProposalVotes,
|
||||
PaginatedProposals,
|
||||
Tally,
|
||||
} from '@/types/gov';
|
||||
import type { PaginatedSigningInfo } from '@/types/slashing';
|
||||
import type {
|
||||
Delegation,
|
||||
PaginatedDelegations,
|
||||
PaginatedRedelegations,
|
||||
PaginatedUnbonding,
|
||||
PaginatedValdiators,
|
||||
StakingParam,
|
||||
StakingPool,
|
||||
Validator,
|
||||
} from '@/types/staking';
|
||||
import type { PaginatedTxs, Tx, TxResponse } from '@/types/tx';
|
||||
|
||||
export interface Request<T> {
|
||||
url: string,
|
||||
adapter: (source: any) => T
|
||||
url: string;
|
||||
adapter: (source: any) => T;
|
||||
}
|
||||
|
||||
export interface AbstractRegistry {
|
||||
[key: string]: Request<any>
|
||||
[key: string]: Request<any>;
|
||||
}
|
||||
|
||||
// use snake style, since the all return object use snake style.
|
||||
export interface RequestRegistry extends AbstractRegistry {
|
||||
auth_params: Request<any>
|
||||
auth_params: Request<any>;
|
||||
auth_accounts: Request<PaginabledAccounts>;
|
||||
auth_account_address: Request<{account: AuthAccount}>;
|
||||
auth_account_address: Request<{ account: AuthAccount }>;
|
||||
|
||||
bank_params: Request<BankParams>;
|
||||
bank_balances_address: Request<PaginatedBalances>;
|
||||
bank_denoms_metadata: Request<PaginatedDenomMetadata>;
|
||||
bank_supply: Request<PaginatedSupply>;
|
||||
bank_supply_by_denom: Request<{amount: Coin}>;
|
||||
bank_supply_by_denom: Request<{ amount: Coin }>;
|
||||
|
||||
distribution_params: Request<DistributionParams>;
|
||||
distribution_validator_commission: Request<{commission?: {commission?: Coin[]}}>;
|
||||
distribution_validator_outstanding_rewards: Request<{rewards?: {rewards?: Coin[]}}>;
|
||||
distribution_validator_commission: Request<{
|
||||
commission?: { commission?: Coin[] };
|
||||
}>;
|
||||
distribution_validator_outstanding_rewards: Request<{
|
||||
rewards?: { rewards?: Coin[] };
|
||||
}>;
|
||||
distribution_validator_slashes: Request<PaginatedSlashes>;
|
||||
distribution_community_pool: Request<{pool: Coin[]}>;
|
||||
distribution_community_pool: Request<{ pool: Coin[] }>;
|
||||
distribution_delegator_rewards: Request<any>;
|
||||
|
||||
mint_inflation: Request<{inflation: string}>;
|
||||
mint_inflation: Request<{ inflation: string }>;
|
||||
mint_params: Request<{
|
||||
params: {
|
||||
mint_denom: string,
|
||||
blocks_per_year: string
|
||||
}
|
||||
mint_denom: string;
|
||||
blocks_per_year: string;
|
||||
};
|
||||
}>;
|
||||
mint_annual_provisions: Request<{annual_provisions: string}>
|
||||
mint_annual_provisions: Request<{ annual_provisions: string }>;
|
||||
|
||||
slashing_params: Request<any>;
|
||||
slashing_signing_info: Request<PaginatedSigningInfo>;
|
||||
|
||||
|
||||
gov_params_voting: Request<GovParams>;
|
||||
gov_params_tally: Request<GovParams>;
|
||||
gov_params_deposit: Request<GovParams>;
|
||||
gov_proposals: Request<PaginatedProposals>;
|
||||
gov_proposals_proposal_id: Request<{proposal: GovProposal}>;
|
||||
gov_proposals_proposal_id: Request<{ proposal: GovProposal }>;
|
||||
gov_proposals_deposits: Request<PaginatedProposalDeposit>;
|
||||
gov_proposals_tally: Request<{tally: Tally}>;
|
||||
gov_proposals_tally: Request<{ tally: Tally }>;
|
||||
gov_proposals_votes: Request<PaginatedProposalVotes>;
|
||||
gov_proposals_votes_voter: Request<{vote: GovVote}>;
|
||||
gov_proposals_votes_voter: Request<{ vote: GovVote }>;
|
||||
|
||||
staking_deletations: Request<PaginatedDelegations>;
|
||||
staking_delegator_redelegations: Request<PaginatedRedelegations>;
|
||||
@ -64,9 +104,11 @@ export interface RequestRegistry extends AbstractRegistry {
|
||||
staking_params: Request<StakingParam>;
|
||||
staking_pool: Request<StakingPool>;
|
||||
staking_validators: Request<PaginatedValdiators>;
|
||||
staking_validators_address: Request<{validator: Validator}>;
|
||||
staking_validators_address: Request<{ validator: Validator }>;
|
||||
staking_validators_delegations: Request<PaginatedDelegations>;
|
||||
staking_validators_delegations_delegator: Request<{delegation_response: Delegation}>;
|
||||
staking_validators_delegations_delegator: Request<{
|
||||
delegation_response: Delegation;
|
||||
}>;
|
||||
staking_validators_delegations_unbonding_delegations: Request<PaginatedUnbonding>;
|
||||
|
||||
base_tendermint_abci_query: Request<any>;
|
||||
@ -78,45 +120,50 @@ export interface RequestRegistry extends AbstractRegistry {
|
||||
|
||||
tx_txs: Request<PaginatedTxs>;
|
||||
tx_txs_block: Request<Tx>;
|
||||
tx_hash: Request<{tx: Tx, tx_response: TxResponse}>;
|
||||
tx_hash: Request<{ tx: Tx; tx_response: TxResponse }>;
|
||||
|
||||
ibc_app_ica_controller_params: Request<any>;
|
||||
ibc_app_ica_host_params: Request<any>
|
||||
ibc_app_ica_host_params: Request<any>;
|
||||
ibc_app_transfer_escrow_address: Request<any>;
|
||||
ibc_app_transfer_denom_traces: Request<any>;
|
||||
ibc_app_transfer_denom_traces_hash: Request<{
|
||||
denom_trace: DenomTrace
|
||||
denom_trace: DenomTrace;
|
||||
}>;
|
||||
ibc_core_channel_channels: Request<PaginatedIBCChannels>;
|
||||
ibc_core_channel_channels_next_sequence: Request<{
|
||||
next_sequence_receive: string,
|
||||
proof: string,
|
||||
next_sequence_receive: string;
|
||||
proof: string;
|
||||
proof_height: {
|
||||
revision_number: string,
|
||||
revision_height: string
|
||||
}
|
||||
revision_number: string;
|
||||
revision_height: string;
|
||||
};
|
||||
}>;
|
||||
ibc_core_channel_channels_acknowledgements: Request<any>;
|
||||
ibc_core_channel_connections_channels: Request<PaginatedIBCChannels>;
|
||||
ibc_core_connection_connections: Request<PaginatedIBCConnections>;
|
||||
ibc_core_connection_connections: Request<PaginatedIBCConnections>;
|
||||
ibc_core_connection_connections_connection_id: Request<ConnectionWithProof>;
|
||||
ibc_core_connection_connections_connection_id_client_state: Request<ClientStateWithProof>;
|
||||
|
||||
}
|
||||
|
||||
export function adapter<T>(source: any): T {
|
||||
return source
|
||||
return source;
|
||||
}
|
||||
|
||||
export interface Registry {
|
||||
[key: string]: RequestRegistry;
|
||||
}
|
||||
|
||||
export function withCustomAdapter<T extends RequestRegistry>(target: T, source?: Partial<T>): T {
|
||||
return source ? Object.assign({}, target, source): target;
|
||||
export function withCustomAdapter<T extends RequestRegistry>(
|
||||
target: T,
|
||||
source?: Partial<T>
|
||||
): T {
|
||||
return source ? Object.assign({}, target, source) : target;
|
||||
}
|
||||
|
||||
export function findConfigByName(name: string, registry: Registry): RequestRegistry {
|
||||
export function findConfigByName(
|
||||
name: string,
|
||||
registry: Registry
|
||||
): RequestRegistry {
|
||||
const url = registry[name];
|
||||
if (!url) {
|
||||
throw new Error(`Unsupported version or name: ${name}`);
|
||||
@ -125,7 +172,10 @@ export function findConfigByName(name: string, registry: Registry): RequestRegis
|
||||
return url;
|
||||
}
|
||||
|
||||
export function findConfigByVersion(version: string, registry: Registry): RequestRegistry {
|
||||
export function findConfigByVersion(
|
||||
version: string,
|
||||
registry: Registry
|
||||
): RequestRegistry {
|
||||
let closestVersion: string | null = null;
|
||||
|
||||
for (const key in registry) {
|
||||
|
@ -1,110 +1,157 @@
|
||||
export function getLocalObject(name: string) {
|
||||
const text = localStorage.getItem(name)
|
||||
if (text) {
|
||||
return JSON.parse(text)
|
||||
}
|
||||
return null
|
||||
const text = localStorage.getItem(name);
|
||||
if (text) {
|
||||
return JSON.parse(text);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function getLocalChains() {
|
||||
return 'osmosis'
|
||||
return 'osmosis';
|
||||
}
|
||||
|
||||
export const percent = (num: number) => {
|
||||
return parseFloat((num * 100).toFixed(2))
|
||||
return parseFloat((num * 100).toFixed(2));
|
||||
};
|
||||
|
||||
const COUNT_ABBRS = [
|
||||
'',
|
||||
'K',
|
||||
'M',
|
||||
'B',
|
||||
't',
|
||||
'q',
|
||||
's',
|
||||
'S',
|
||||
'o',
|
||||
'n',
|
||||
'd',
|
||||
'U',
|
||||
'D',
|
||||
'T',
|
||||
'Qt',
|
||||
'Qd',
|
||||
'Sd',
|
||||
'St',
|
||||
];
|
||||
|
||||
export function formatNumber(count: number, withAbbr = false, decimals = 2) {
|
||||
const i = count === 0 ? count : Math.floor(Math.log(count) / Math.log(1000));
|
||||
let result: any = parseFloat((count / 1000 ** i).toFixed(decimals));
|
||||
if (withAbbr && COUNT_ABBRS[i]) {
|
||||
result += `${COUNT_ABBRS[i]}`;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const COUNT_ABBRS = ['', 'K', 'M', 'B', 't', 'q', 's', 'S', 'o', 'n', 'd', 'U', 'D', 'T', 'Qt', 'Qd', 'Sd', 'St']
|
||||
export function formatTokenAmount(
|
||||
assets: any,
|
||||
tokenAmount: any,
|
||||
decimals = 2,
|
||||
tokenDenom = 'uatom',
|
||||
format = true
|
||||
) {
|
||||
const denom = tokenDenom?.denom_trace
|
||||
? tokenDenom?.denom_trace?.base_denom
|
||||
: tokenDenom;
|
||||
let amount = 0;
|
||||
const asset = assets.find((a: any) => a.base === denom);
|
||||
let exp = asset
|
||||
? asset.exponent
|
||||
: String(denom).startsWith('gravity')
|
||||
? 18
|
||||
: 6;
|
||||
const config = Object.values(getLocalChains());
|
||||
|
||||
export function formatNumber(count:number, withAbbr = false, decimals = 2) {
|
||||
const i = count === 0 ? count : Math.floor(Math.log(count) / Math.log(1000))
|
||||
let result: any = parseFloat((count / (1000 ** i)).toFixed(decimals))
|
||||
if (withAbbr && COUNT_ABBRS[i]) {
|
||||
result += `${COUNT_ABBRS[i]}`
|
||||
amount = Number(Number(tokenAmount)) / 10 ** exp;
|
||||
if (amount > 10) {
|
||||
if (format) {
|
||||
return numberWithCommas(parseFloat(amount.toFixed(decimals)));
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
export function formatTokenAmount(assets: any ,tokenAmount: any, decimals = 2, tokenDenom = 'uatom', format = true) {
|
||||
const denom = tokenDenom?.denom_trace ? tokenDenom?.denom_trace?.base_denom : tokenDenom
|
||||
let amount = 0
|
||||
const asset = assets.find((a:any) => (a.base === denom))
|
||||
let exp = asset? asset.exponent: String(denom).startsWith('gravity') ? 18 : 6
|
||||
const config = Object.values(getLocalChains())
|
||||
|
||||
amount = Number(Number(tokenAmount)) / (10 ** exp)
|
||||
if (amount > 10) {
|
||||
if (format) { return numberWithCommas(parseFloat(amount.toFixed(decimals))) }
|
||||
return parseFloat(amount.toFixed(decimals))
|
||||
}
|
||||
return parseFloat(amount.toFixed(exp))
|
||||
return parseFloat(amount.toFixed(decimals));
|
||||
}
|
||||
return parseFloat(amount.toFixed(exp));
|
||||
}
|
||||
|
||||
export function numberWithCommas(x: any) {
|
||||
const parts = x.toString().split('.')
|
||||
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',')
|
||||
return parts.join('.')
|
||||
const parts = x.toString().split('.');
|
||||
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
||||
return parts.join('.');
|
||||
}
|
||||
|
||||
export function tokenFormatter(tokens:any, denoms = {}, decimal = 2) {
|
||||
if (Array.isArray(tokens)) {
|
||||
return tokens.map(t => formatToken(t, denoms, decimal)).join(', ')
|
||||
}
|
||||
return formatToken(tokens, denoms, 2)
|
||||
}
|
||||
export function formatToken(token:any, IBCDenom = {}, decimals = 2, withDenom = true) {
|
||||
if (token) {
|
||||
const denom = IBCDenom[token.denom] || token.denom
|
||||
if (withDenom) {
|
||||
return `${formatTokenAmount(token.amount, decimals, denom)} ${formatTokenDenom(denom)}`
|
||||
}
|
||||
return formatTokenAmount(token.amount, decimals, denom)
|
||||
}
|
||||
return token
|
||||
export function tokenFormatter(tokens: any, denoms = {}, decimal = 2) {
|
||||
if (Array.isArray(tokens)) {
|
||||
return tokens.map((t) => formatToken(t, denoms, decimal)).join(', ');
|
||||
}
|
||||
export function formatTokenDenom(tokenDenom:any) {
|
||||
if (tokenDenom && tokenDenom.code === undefined) {
|
||||
let denom = tokenDenom.denom_trace ? tokenDenom.denom_trace.base_denom : tokenDenom
|
||||
const chains = getLocalChains()
|
||||
const selected = localStorage.getItem('selected_chain')
|
||||
const selChain = chains[selected]
|
||||
const nativeAsset = selChain.assets.find(a => (a.base === denom))
|
||||
if (nativeAsset) {
|
||||
denom = nativeAsset.symbol
|
||||
} else {
|
||||
const config = Object.values(chains)
|
||||
config.forEach(x => {
|
||||
if (x.assets) {
|
||||
const asset = x.assets.find(a => (a.base === denom))
|
||||
if (asset) denom = asset.symbol
|
||||
}
|
||||
})
|
||||
}
|
||||
return denom.length > 10 ? `${denom.substring(0, 7).toUpperCase()}..${denom.substring(denom.length - 3)}` : denom.toUpperCase()
|
||||
return formatToken(tokens, denoms, 2);
|
||||
}
|
||||
export function formatToken(
|
||||
token: any,
|
||||
IBCDenom = {},
|
||||
decimals = 2,
|
||||
withDenom = true
|
||||
) {
|
||||
if (token) {
|
||||
const denom = IBCDenom[token.denom] || token.denom;
|
||||
if (withDenom) {
|
||||
return `${formatTokenAmount(
|
||||
token.amount,
|
||||
decimals,
|
||||
denom
|
||||
)} ${formatTokenDenom(denom)}`;
|
||||
}
|
||||
return ''
|
||||
return formatTokenAmount(token.amount, decimals, denom);
|
||||
}
|
||||
return token;
|
||||
}
|
||||
export function formatTokenDenom(tokenDenom: any) {
|
||||
if (tokenDenom && tokenDenom.code === undefined) {
|
||||
let denom = tokenDenom.denom_trace
|
||||
? tokenDenom.denom_trace.base_denom
|
||||
: tokenDenom;
|
||||
const chains = getLocalChains();
|
||||
const selected = localStorage.getItem('selected_chain');
|
||||
const selChain = chains[selected];
|
||||
const nativeAsset = selChain.assets.find((a) => a.base === denom);
|
||||
if (nativeAsset) {
|
||||
denom = nativeAsset.symbol;
|
||||
} else {
|
||||
const config = Object.values(chains);
|
||||
config.forEach((x) => {
|
||||
if (x.assets) {
|
||||
const asset = x.assets.find((a) => a.base === denom);
|
||||
if (asset) denom = asset.symbol;
|
||||
}
|
||||
});
|
||||
}
|
||||
return denom.length > 10
|
||||
? `${denom.substring(0, 7).toUpperCase()}..${denom.substring(
|
||||
denom.length - 3
|
||||
)}`
|
||||
: denom.toUpperCase();
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
export function isToken(value: string) {
|
||||
let is = false
|
||||
if (Array.isArray(value)) {
|
||||
is = value.findIndex(x => Object.keys(x).includes('denom')) > -1
|
||||
} else {
|
||||
is = Object.keys(value).includes('denom')
|
||||
}
|
||||
return is
|
||||
let is = false;
|
||||
if (Array.isArray(value)) {
|
||||
is = value.findIndex((x) => Object.keys(x).includes('denom')) > -1;
|
||||
} else {
|
||||
is = Object.keys(value).includes('denom');
|
||||
}
|
||||
export function isStringArray(value: any) {
|
||||
let is = false
|
||||
if (Array.isArray(value)) {
|
||||
is = value.findIndex(x => typeof x === 'string') > -1
|
||||
}
|
||||
return is
|
||||
return is;
|
||||
}
|
||||
export function isStringArray(value: any) {
|
||||
let is = false;
|
||||
if (Array.isArray(value)) {
|
||||
is = value.findIndex((x) => typeof x === 'string') > -1;
|
||||
}
|
||||
return is;
|
||||
}
|
||||
|
||||
export function isHexAddress(v: any) {
|
||||
// const re = /^[A-Z\d]{40}$/
|
||||
// return re.test(v)
|
||||
return v.length === 28
|
||||
}
|
||||
|
||||
export function isHexAddress(v: any) {
|
||||
// const re = /^[A-Z\d]{40}$/
|
||||
// return re.test(v)
|
||||
return v.length === 28;
|
||||
}
|
||||
|
@ -1,290 +1,350 @@
|
||||
<script lang="ts" setup>
|
||||
import { useBlockchain, useFormatter, useStakingStore } from '@/stores';
|
||||
import DynamicComponent from '@/components/dynamic/DynamicComponent.vue';
|
||||
import DonutChart from '@/components/charts/DonutChart.vue'
|
||||
import DonutChart from '@/components/charts/DonutChart.vue';
|
||||
import { computed, ref } from '@vue/reactivity';
|
||||
import 'vue-json-pretty/lib/styles.css';
|
||||
import type { AuthAccount, Delegation, TxResponse, DelegatorRewards, UnbondingResponses } from '@/types';
|
||||
import type {
|
||||
AuthAccount,
|
||||
Delegation,
|
||||
TxResponse,
|
||||
DelegatorRewards,
|
||||
UnbondingResponses,
|
||||
} from '@/types';
|
||||
import type { Coin } from '@cosmjs/amino';
|
||||
|
||||
const props = defineProps(['address', 'chain'])
|
||||
const props = defineProps(['address', 'chain']);
|
||||
|
||||
const blockchain = useBlockchain()
|
||||
const stakingStore = useStakingStore()
|
||||
const format = useFormatter()
|
||||
const account = ref({} as AuthAccount)
|
||||
const txs = ref({} as TxResponse[])
|
||||
const delegations = ref([] as Delegation[])
|
||||
const rewards = ref({} as DelegatorRewards)
|
||||
const balances = ref([] as Coin[])
|
||||
const unbonding = ref([] as UnbondingResponses[])
|
||||
const unbondingTotal = ref(0)
|
||||
const chart = {}
|
||||
const blockchain = useBlockchain();
|
||||
const stakingStore = useStakingStore();
|
||||
const format = useFormatter();
|
||||
const account = ref({} as AuthAccount);
|
||||
const txs = ref({} as TxResponse[]);
|
||||
const delegations = ref([] as Delegation[]);
|
||||
const rewards = ref({} as DelegatorRewards);
|
||||
const balances = ref([] as Coin[]);
|
||||
const unbonding = ref([] as UnbondingResponses[]);
|
||||
const unbondingTotal = ref(0);
|
||||
const chart = {};
|
||||
|
||||
const totalAmountByCategory = computed(()=> {
|
||||
let sumDel = 0;
|
||||
delegations.value?.forEach(x => {
|
||||
sumDel += Number(x.balance.amount)
|
||||
})
|
||||
let sumRew = 0
|
||||
rewards.value?.total?.forEach(x => {
|
||||
sumRew += Number(x.amount)
|
||||
})
|
||||
let sumBal = 0
|
||||
balances.value?.forEach(x => {
|
||||
sumBal += Number(x.amount)
|
||||
})
|
||||
let sumUn = 0
|
||||
unbonding.value?.forEach(x => {
|
||||
x.entries?.forEach(y => {
|
||||
sumUn += Number(y.balance)
|
||||
})
|
||||
})
|
||||
return [sumBal, sumDel, sumRew, sumUn]
|
||||
})
|
||||
const totalAmountByCategory = computed(() => {
|
||||
let sumDel = 0;
|
||||
delegations.value?.forEach((x) => {
|
||||
sumDel += Number(x.balance.amount);
|
||||
});
|
||||
let sumRew = 0;
|
||||
rewards.value?.total?.forEach((x) => {
|
||||
sumRew += Number(x.amount);
|
||||
});
|
||||
let sumBal = 0;
|
||||
balances.value?.forEach((x) => {
|
||||
sumBal += Number(x.amount);
|
||||
});
|
||||
let sumUn = 0;
|
||||
unbonding.value?.forEach((x) => {
|
||||
x.entries?.forEach((y) => {
|
||||
sumUn += Number(y.balance);
|
||||
});
|
||||
});
|
||||
return [sumBal, sumDel, sumRew, sumUn];
|
||||
});
|
||||
|
||||
const labels = ['Balance', 'Delegation', 'Reward', 'Unbonding']
|
||||
|
||||
const totalAmount= computed(()=> {
|
||||
return totalAmountByCategory.value.reduce((p, c)=> c + p, 0)
|
||||
})
|
||||
const labels = ['Balance', 'Delegation', 'Reward', 'Unbonding'];
|
||||
|
||||
const totalAmount = computed(() => {
|
||||
return totalAmountByCategory.value.reduce((p, c) => c + p, 0);
|
||||
});
|
||||
|
||||
function loadAccount(address: string) {
|
||||
blockchain.rpc.getAuthAccount(address).then(x => {
|
||||
account.value = x.account
|
||||
})
|
||||
blockchain.rpc.getTxsBySender(address).then(x => {
|
||||
txs.value = x.tx_responses
|
||||
})
|
||||
blockchain.rpc.getDistributionDelegatorRewards(address).then(x => {
|
||||
rewards.value = x
|
||||
})
|
||||
blockchain.rpc.getStakingDelegations(address).then(x => {
|
||||
delegations.value = x.delegation_responses
|
||||
})
|
||||
blockchain.rpc.getBankBalances(address).then(x => {
|
||||
balances.value = x.balances
|
||||
})
|
||||
blockchain.rpc.getStakingDelegatorUnbonding(address).then(x => {
|
||||
unbonding.value = x.unbonding_responses
|
||||
x.unbonding_responses?.forEach(y => {
|
||||
y.entries.forEach(z => {
|
||||
unbondingTotal.value += Number(z.balance)
|
||||
})
|
||||
})
|
||||
})
|
||||
blockchain.rpc.getAuthAccount(address).then((x) => {
|
||||
account.value = x.account;
|
||||
});
|
||||
blockchain.rpc.getTxsBySender(address).then((x) => {
|
||||
txs.value = x.tx_responses;
|
||||
});
|
||||
blockchain.rpc.getDistributionDelegatorRewards(address).then((x) => {
|
||||
rewards.value = x;
|
||||
});
|
||||
blockchain.rpc.getStakingDelegations(address).then((x) => {
|
||||
delegations.value = x.delegation_responses;
|
||||
});
|
||||
blockchain.rpc.getBankBalances(address).then((x) => {
|
||||
balances.value = x.balances;
|
||||
});
|
||||
blockchain.rpc.getStakingDelegatorUnbonding(address).then((x) => {
|
||||
unbonding.value = x.unbonding_responses;
|
||||
x.unbonding_responses?.forEach((y) => {
|
||||
y.entries.forEach((z) => {
|
||||
unbondingTotal.value += Number(z.balance);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
loadAccount(props.address)
|
||||
loadAccount(props.address);
|
||||
</script>
|
||||
<template>
|
||||
<div v-if="account">
|
||||
<VCard>
|
||||
<VList>
|
||||
<VListItem>
|
||||
<div v-if="account">
|
||||
<VCard>
|
||||
<VList>
|
||||
<VListItem>
|
||||
<template #prepend>
|
||||
<VAvatar rounded variant="tonal" size="45" color="primary">
|
||||
<VIcon icon="mdi-qrcode" />
|
||||
</VAvatar>
|
||||
</template>
|
||||
|
||||
<VListItemTitle class="text-sm font-weight-semibold">
|
||||
Address:
|
||||
</VListItemTitle>
|
||||
<VListItemSubtitle class="text-xs">
|
||||
{{ address }}
|
||||
</VListItemSubtitle>
|
||||
</VListItem>
|
||||
</VList>
|
||||
</VCard>
|
||||
|
||||
<VCard class="mt-5">
|
||||
<VCardTitle>Assets</VCardTitle>
|
||||
<VCardItem>
|
||||
<VRow>
|
||||
<VCol cols="12" md="4">
|
||||
<DonutChart :series="totalAmountByCategory" :labels="labels" />
|
||||
</VCol>
|
||||
<VCol cols="12" md="8">
|
||||
<VList class="card-list">
|
||||
<VListItem v-for="v in balances">
|
||||
<template #prepend>
|
||||
<VAvatar
|
||||
rounded
|
||||
variant="tonal"
|
||||
size="45"
|
||||
color="primary"
|
||||
>
|
||||
<VIcon icon="mdi-qrcode" />
|
||||
</VAvatar>
|
||||
<VAvatar rounded variant="tonal" size="35" color="info">
|
||||
<VIcon icon="mdi-account-cash" size="20" />
|
||||
</VAvatar>
|
||||
</template>
|
||||
<VListItemTitle class="text-sm font-weight-semibold">
|
||||
{{ format.formatToken(v) }}
|
||||
</VListItemTitle>
|
||||
<VListItemSubtitle class="text-xs">
|
||||
≈${{ 0 }}
|
||||
</VListItemSubtitle>
|
||||
<template #append>
|
||||
<VChip color="primary">{{
|
||||
format.calculatePercent(v.amount, totalAmount)
|
||||
}}</VChip>
|
||||
</template>
|
||||
</VListItem>
|
||||
<VListItem v-for="v in delegations">
|
||||
<template #prepend>
|
||||
<VAvatar rounded variant="tonal" size="35" color="warning">
|
||||
<VIcon icon="mdi-user-clock" size="20" />
|
||||
</VAvatar>
|
||||
</template>
|
||||
|
||||
<VListItemTitle class="text-sm font-weight-semibold">
|
||||
Address:
|
||||
{{ format.formatToken(v.balance) }}
|
||||
</VListItemTitle>
|
||||
<VListItemSubtitle class="text-xs">
|
||||
{{ address }}
|
||||
≈${{ 0 }}
|
||||
</VListItemSubtitle>
|
||||
</VListItem>
|
||||
<template #append>
|
||||
<VChip color="primary">{{
|
||||
format.calculatePercent(v.balance.amount, totalAmount)
|
||||
}}</VChip>
|
||||
</template>
|
||||
</VListItem>
|
||||
<VListItem v-for="v in rewards.total">
|
||||
<template #prepend>
|
||||
<VAvatar rounded variant="tonal" size="35" color="success">
|
||||
<VIcon icon="mdi-account-arrow-up" size="20" />
|
||||
</VAvatar>
|
||||
</template>
|
||||
|
||||
<VListItemTitle class="text-sm font-weight-semibold">
|
||||
{{ format.formatToken(v) }}
|
||||
</VListItemTitle>
|
||||
<VListItemSubtitle class="text-xs">
|
||||
≈${{ 0 }}
|
||||
</VListItemSubtitle>
|
||||
<template #append>
|
||||
<VChip color="primary">{{
|
||||
format.calculatePercent(v.amount, totalAmount)
|
||||
}}</VChip>
|
||||
</template>
|
||||
</VListItem>
|
||||
|
||||
<VListItem>
|
||||
<template #prepend>
|
||||
<VAvatar rounded variant="tonal" size="35" color="error">
|
||||
<VIcon icon="mdi-account-arrow-right" size="20" />
|
||||
</VAvatar>
|
||||
</template>
|
||||
|
||||
<VListItemTitle class="text-sm font-weight-semibold">
|
||||
{{
|
||||
format.formatToken({
|
||||
amount: String(unbondingTotal),
|
||||
denom: stakingStore.params.bond_denom,
|
||||
})
|
||||
}}
|
||||
</VListItemTitle>
|
||||
<VListItemSubtitle class="text-xs">
|
||||
≈${{ 0 }}
|
||||
</VListItemSubtitle>
|
||||
<template #append>
|
||||
<VChip color="primary">{{
|
||||
format.calculatePercent(unbondingTotal, totalAmount)
|
||||
}}</VChip>
|
||||
</template>
|
||||
</VListItem>
|
||||
</VList>
|
||||
</VCard>
|
||||
<VDivider class="my-2"></VDivider>
|
||||
{{ totalAmount }}
|
||||
</VCol>
|
||||
</VRow>
|
||||
</VCardItem>
|
||||
</VCard>
|
||||
|
||||
<VCard class="mt-5">
|
||||
<VCardTitle>Assets</VCardTitle>
|
||||
<VCardItem>
|
||||
<VRow>
|
||||
<VCol cols="12" md="4">
|
||||
<DonutChart :series="totalAmountByCategory" :labels="labels"/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="8">
|
||||
<VList class="card-list">
|
||||
<VListItem v-for="v in balances">
|
||||
<template #prepend>
|
||||
<VAvatar
|
||||
rounded
|
||||
variant="tonal"
|
||||
size="35"
|
||||
color="info"
|
||||
>
|
||||
<VIcon icon="mdi-account-cash" size="20"/>
|
||||
</VAvatar>
|
||||
</template>
|
||||
<VListItemTitle class="text-sm font-weight-semibold">
|
||||
{{ format.formatToken(v) }}
|
||||
</VListItemTitle>
|
||||
<VListItemSubtitle class="text-xs">
|
||||
≈${{ 0 }}
|
||||
</VListItemSubtitle>
|
||||
<template #append>
|
||||
<VChip color="primary">{{ format.calculatePercent(v.amount, totalAmount) }}</VChip>
|
||||
</template>
|
||||
</VListItem>
|
||||
<VListItem v-for="v in delegations">
|
||||
<template #prepend>
|
||||
<VAvatar
|
||||
rounded
|
||||
variant="tonal"
|
||||
size="35"
|
||||
color="warning"
|
||||
>
|
||||
<VIcon icon="mdi-user-clock" size="20" />
|
||||
</VAvatar>
|
||||
</template>
|
||||
|
||||
<VListItemTitle class="text-sm font-weight-semibold">
|
||||
{{ format.formatToken(v.balance) }}
|
||||
</VListItemTitle>
|
||||
<VListItemSubtitle class="text-xs">
|
||||
≈${{ 0 }}
|
||||
</VListItemSubtitle>
|
||||
<template #append>
|
||||
<VChip color="primary">{{ format.calculatePercent(v.balance.amount, totalAmount) }}</VChip>
|
||||
</template>
|
||||
</VListItem>
|
||||
<VListItem v-for="v in rewards.total">
|
||||
<template #prepend>
|
||||
<VAvatar
|
||||
rounded
|
||||
variant="tonal"
|
||||
size="35"
|
||||
color="success"
|
||||
>
|
||||
<VIcon icon="mdi-account-arrow-up" size="20" />
|
||||
</VAvatar>
|
||||
</template>
|
||||
|
||||
<VListItemTitle class="text-sm font-weight-semibold">
|
||||
{{ format.formatToken(v) }}
|
||||
</VListItemTitle>
|
||||
<VListItemSubtitle class="text-xs">
|
||||
≈${{ 0 }}
|
||||
</VListItemSubtitle>
|
||||
<template #append>
|
||||
<VChip color="primary">{{ format.calculatePercent(v.amount, totalAmount) }}</VChip>
|
||||
</template>
|
||||
</VListItem>
|
||||
|
||||
<VListItem>
|
||||
<template #prepend>
|
||||
<VAvatar
|
||||
rounded
|
||||
variant="tonal"
|
||||
size="35"
|
||||
color="error"
|
||||
>
|
||||
<VIcon icon="mdi-account-arrow-right" size="20" />
|
||||
</VAvatar>
|
||||
</template>
|
||||
|
||||
<VListItemTitle class="text-sm font-weight-semibold">
|
||||
{{ format.formatToken({amount: String(unbondingTotal), denom: stakingStore.params.bond_denom}) }}
|
||||
</VListItemTitle>
|
||||
<VListItemSubtitle class="text-xs">
|
||||
≈${{ 0 }}
|
||||
</VListItemSubtitle>
|
||||
<template #append>
|
||||
<VChip color="primary">{{ format.calculatePercent(unbondingTotal, totalAmount) }}</VChip>
|
||||
</template>
|
||||
</VListItem>
|
||||
</VList>
|
||||
<VDivider class="my-2"></VDivider>
|
||||
{{ totalAmount }}
|
||||
</VCol>
|
||||
</VRow>
|
||||
</VCardItem>
|
||||
</VCard>
|
||||
|
||||
<VCard class="my-5">
|
||||
<VCardItem>
|
||||
<VCardTitle>Delegations</VCardTitle>
|
||||
<VTable>
|
||||
<thead>
|
||||
<tr><th>Validator</th><th>Delegation</th><th>Rewards</th><th>Action</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="v in delegations">
|
||||
<td class="text-caption text-primary"><RouterLink :to="`/${chain}/staking/${v.delegation.validator_address}`">{{ format.validatorFromBech32(v.delegation.validator_address) }}</RouterLink></td>
|
||||
<td>{{ format.formatToken(v.balance, true, "0,0.[00]") }} </td>
|
||||
<td>{{ format.formatTokens(rewards?.rewards?.find(x => x.validator_address ===v.delegation.validator_address)?.reward) }} </td>
|
||||
<td>
|
||||
action
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</VTable>
|
||||
</VCardItem>
|
||||
</VCard>
|
||||
<VCard class="my-5" v-if="unbonding && unbonding.length > 0">
|
||||
<VCardItem>
|
||||
<VCardTitle>Unbonding Delegations</VCardTitle>
|
||||
<VTable>
|
||||
<thead>
|
||||
<tr><th>Creation Height</th><th>Initial Balance</th><th>Balance</th><th>Completion Time</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<div v-for="v in unbonding">
|
||||
<tr>
|
||||
<td class="text-caption text-primary"><RouterLink :to="`/${chain}/staking/${v.validator_address}`">{{ format.validatorFromBech32(v.validator_address) }}</RouterLink></td>
|
||||
</tr>
|
||||
<tr v-for="entry in v.entries">
|
||||
<td>{{ entry.creation_height }}</td>
|
||||
<td>{{ format.formatToken({ amount: entry.initial_balance, denom: stakingStore.params.bond_denom }, true, "0,0.[00]") }}</td>
|
||||
<td>{{ format.formatToken({ amount: entry.balance, denom: stakingStore.params.bond_denom }, true, "0,0.[00]") }}</td>
|
||||
<td>{{ format.toDay(entry.completion_time, "to") }} </td>
|
||||
</tr>
|
||||
</div>
|
||||
</tbody>
|
||||
</VTable>
|
||||
</VCardItem>
|
||||
</VCard>
|
||||
<VCard class="my-5">
|
||||
<VCardItem>
|
||||
<VCardTitle>Transactions</VCardTitle>
|
||||
<VTable>
|
||||
<thead>
|
||||
<tr><th>Height</th><th>Hash</th><th>Messages</th><th>Time</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="v in txs">
|
||||
<td class="text-sm text-primary"><RouterLink :to="`/${chain}/block/${v.height}`">{{ v.height }}</RouterLink></td>
|
||||
<td class="text-truncate" style="max-width: 200px;">{{ v.txhash }} </td>
|
||||
<td>
|
||||
{{ format.messages(v.tx.body.messages) }}
|
||||
<VIcon v-if="v.code === 0" icon="mdi-check" color="success"></VIcon>
|
||||
<VIcon v-else icon="mdi-multiply" color="error"></VIcon> </td>
|
||||
<td>{{ format.toDay(v.timestamp, "from") }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</VTable>
|
||||
</VCardItem>
|
||||
</VCard>
|
||||
<VCard>
|
||||
<VCardItem>
|
||||
<VCardTitle>Account</VCardTitle>
|
||||
<DynamicComponent :value="account"/>
|
||||
</VCardItem>
|
||||
</VCard>
|
||||
</div>
|
||||
<div v-else>
|
||||
Account does not exists on chain
|
||||
</div>
|
||||
<VCard class="my-5">
|
||||
<VCardItem>
|
||||
<VCardTitle>Delegations</VCardTitle>
|
||||
<VTable>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Validator</th>
|
||||
<th>Delegation</th>
|
||||
<th>Rewards</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="v in delegations">
|
||||
<td class="text-caption text-primary">
|
||||
<RouterLink
|
||||
:to="`/${chain}/staking/${v.delegation.validator_address}`"
|
||||
>{{
|
||||
format.validatorFromBech32(v.delegation.validator_address)
|
||||
}}</RouterLink
|
||||
>
|
||||
</td>
|
||||
<td>{{ format.formatToken(v.balance, true, '0,0.[00]') }}</td>
|
||||
<td>
|
||||
{{
|
||||
format.formatTokens(
|
||||
rewards?.rewards?.find(
|
||||
(x) =>
|
||||
x.validator_address === v.delegation.validator_address
|
||||
)?.reward
|
||||
)
|
||||
}}
|
||||
</td>
|
||||
<td>action</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</VTable>
|
||||
</VCardItem>
|
||||
</VCard>
|
||||
<VCard class="my-5" v-if="unbonding && unbonding.length > 0">
|
||||
<VCardItem>
|
||||
<VCardTitle>Unbonding Delegations</VCardTitle>
|
||||
<VTable>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Creation Height</th>
|
||||
<th>Initial Balance</th>
|
||||
<th>Balance</th>
|
||||
<th>Completion Time</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<div v-for="v in unbonding">
|
||||
<tr>
|
||||
<td class="text-caption text-primary">
|
||||
<RouterLink
|
||||
:to="`/${chain}/staking/${v.validator_address}`"
|
||||
>{{
|
||||
format.validatorFromBech32(v.validator_address)
|
||||
}}</RouterLink
|
||||
>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-for="entry in v.entries">
|
||||
<td>{{ entry.creation_height }}</td>
|
||||
<td>
|
||||
{{
|
||||
format.formatToken(
|
||||
{
|
||||
amount: entry.initial_balance,
|
||||
denom: stakingStore.params.bond_denom,
|
||||
},
|
||||
true,
|
||||
'0,0.[00]'
|
||||
)
|
||||
}}
|
||||
</td>
|
||||
<td>
|
||||
{{
|
||||
format.formatToken(
|
||||
{
|
||||
amount: entry.balance,
|
||||
denom: stakingStore.params.bond_denom,
|
||||
},
|
||||
true,
|
||||
'0,0.[00]'
|
||||
)
|
||||
}}
|
||||
</td>
|
||||
<td>{{ format.toDay(entry.completion_time, 'to') }}</td>
|
||||
</tr>
|
||||
</div>
|
||||
</tbody>
|
||||
</VTable>
|
||||
</VCardItem>
|
||||
</VCard>
|
||||
<VCard class="my-5">
|
||||
<VCardItem>
|
||||
<VCardTitle>Transactions</VCardTitle>
|
||||
<VTable>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Height</th>
|
||||
<th>Hash</th>
|
||||
<th>Messages</th>
|
||||
<th>Time</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="v in txs">
|
||||
<td class="text-sm text-primary">
|
||||
<RouterLink :to="`/${chain}/block/${v.height}`">{{
|
||||
v.height
|
||||
}}</RouterLink>
|
||||
</td>
|
||||
<td class="text-truncate" style="max-width: 200px">
|
||||
{{ v.txhash }}
|
||||
</td>
|
||||
<td>
|
||||
{{ format.messages(v.tx.body.messages) }}
|
||||
<VIcon
|
||||
v-if="v.code === 0"
|
||||
icon="mdi-check"
|
||||
color="success"
|
||||
></VIcon>
|
||||
<VIcon v-else icon="mdi-multiply" color="error"></VIcon>
|
||||
</td>
|
||||
<td>{{ format.toDay(v.timestamp, 'from') }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</VTable>
|
||||
</VCardItem>
|
||||
</VCard>
|
||||
<VCard>
|
||||
<VCardItem>
|
||||
<VCardTitle>Account</VCardTitle>
|
||||
<DynamicComponent :value="account" />
|
||||
</VCardItem>
|
||||
</VCard>
|
||||
</div>
|
||||
<div v-else>Account does not exists on chain</div>
|
||||
</template>
|
||||
<style lang="scss" scoped>
|
||||
.card-list {
|
||||
--v-card-list-gap: 5px;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
@ -21,21 +21,24 @@ onBeforeRouteUpdate(async (to, from, next) => {
|
||||
next();
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<div class="bg-base-100 px-4 pt-3 pb-4 rounded mb-4 shadow">
|
||||
<h2 class="card-title flex flex-row justify-between">
|
||||
<p class="">#{{ store.current.block?.header?.height }}</p>
|
||||
<div class="" v-if="props.height">
|
||||
<RouterLink :to="`/${store.blockchain.chainName}/block/${height - 1}`"
|
||||
class="btn btn-primary btn-sm p-1 text-2xl mr-2">
|
||||
<Icon icon="mdi-arrow-left" class="w-full h-full"/>
|
||||
<div class="" v-if="props.height">
|
||||
<RouterLink
|
||||
:to="`/${store.blockchain.chainName}/block/${height - 1}`"
|
||||
class="btn btn-primary btn-sm p-1 text-2xl mr-2"
|
||||
>
|
||||
<Icon icon="mdi-arrow-left" class="w-full h-full" />
|
||||
</RouterLink>
|
||||
<RouterLink :to="`/${store.blockchain.chainName}/block/${height + 1}`"
|
||||
class="btn btn-primary btn-sm p-1 text-2xl">
|
||||
<Icon icon="mdi-arrow-right"/>
|
||||
<RouterLink
|
||||
:to="`/${store.blockchain.chainName}/block/${height + 1}`"
|
||||
class="btn btn-primary btn-sm p-1 text-2xl"
|
||||
>
|
||||
<Icon icon="mdi-arrow-right" />
|
||||
</RouterLink>
|
||||
</div>
|
||||
</h2>
|
||||
@ -45,25 +48,17 @@ onBeforeRouteUpdate(async (to, from, next) => {
|
||||
</div>
|
||||
|
||||
<div class="bg-base-100 px-4 pt-3 pb-4 rounded mb-4 shadow">
|
||||
<h2 class="card-title flex flex-row justify-between">
|
||||
Block Header
|
||||
</h2>
|
||||
<h2 class="card-title flex flex-row justify-between">Block Header</h2>
|
||||
<DynamicComponent :value="store.current.block?.header" />
|
||||
</div>
|
||||
|
||||
|
||||
<div class="bg-base-100 px-4 pt-3 pb-4 rounded mb-4 shadow">
|
||||
<h2 class="card-title flex flex-row justify-between">
|
||||
Transactions
|
||||
</h2>
|
||||
<h2 class="card-title flex flex-row justify-between">Transactions</h2>
|
||||
<TxsElement :value="store.current.block?.data?.txs" />
|
||||
</div>
|
||||
|
||||
|
||||
<div class="bg-base-100 px-4 pt-3 pb-4 rounded shadow">
|
||||
<h2 class="card-title flex flex-row justify-between">
|
||||
Last Commit
|
||||
</h2>
|
||||
<h2 class="card-title flex flex-row justify-between">Last Commit</h2>
|
||||
<DynamicComponent :value="store.current.block?.last_commit" />
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,61 +1,64 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { decodeTxRaw, type DecodedTxRaw } from '@cosmjs/proto-signing'
|
||||
import { useBlockchain } from "@/stores";
|
||||
import { hashTx } from "@/libs";
|
||||
import type { Block } from "@/types";
|
||||
import { defineStore } from 'pinia';
|
||||
import { decodeTxRaw, type DecodedTxRaw } from '@cosmjs/proto-signing';
|
||||
import { useBlockchain } from '@/stores';
|
||||
import { hashTx } from '@/libs';
|
||||
import type { Block } from '@/types';
|
||||
|
||||
export const useBlockModule = defineStore('blockModule', {
|
||||
state: () => {
|
||||
return {
|
||||
latest: {} as Block,
|
||||
current: {} as Block,
|
||||
recents: [] as Block[]
|
||||
}
|
||||
state: () => {
|
||||
return {
|
||||
latest: {} as Block,
|
||||
current: {} as Block,
|
||||
recents: [] as Block[],
|
||||
};
|
||||
},
|
||||
getters: {
|
||||
blockchain() {
|
||||
return useBlockchain();
|
||||
},
|
||||
getters: {
|
||||
blockchain() {
|
||||
return useBlockchain()
|
||||
},
|
||||
blocktime() {
|
||||
if(this.recents.length<2) return 6000
|
||||
return 6000 // todo later
|
||||
},
|
||||
txsInRecents() {
|
||||
const txs = [] as {hash:string, tx: DecodedTxRaw}[]
|
||||
this.recents.forEach((x) => x.block?.data?.txs.forEach((tx:Uint8Array) => txs.push({
|
||||
hash: hashTx(tx),
|
||||
tx :decodeTxRaw(tx)
|
||||
})))
|
||||
return txs
|
||||
}
|
||||
blocktime() {
|
||||
if (this.recents.length < 2) return 6000;
|
||||
return 6000; // todo later
|
||||
},
|
||||
actions: {
|
||||
initial() {
|
||||
this.clearRecentBlocks()
|
||||
this.autoFetch()
|
||||
},
|
||||
async clearRecentBlocks() {
|
||||
this.recents = []
|
||||
},
|
||||
autoFetch() {
|
||||
this.fetchLatest().then(x => {
|
||||
const timer = this.autoFetch
|
||||
this.latest = x;
|
||||
// if(this.recents.length >= 50) this.recents.pop()
|
||||
// this.recents.push(x)
|
||||
// setTimeout(timer, 6000)
|
||||
})
|
||||
},
|
||||
async fetchLatest() {
|
||||
this.latest = await this.blockchain.rpc.getBaseBlockLatest()
|
||||
if(this.recents.length >= 50) this.recents.shift()
|
||||
this.recents.push(this.latest)
|
||||
return this.latest
|
||||
},
|
||||
async fetchBlock(height: string) {
|
||||
this.current = await this.blockchain.rpc.getBaseBlockAt(height)
|
||||
return this.current
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
txsInRecents() {
|
||||
const txs = [] as { hash: string; tx: DecodedTxRaw }[];
|
||||
this.recents.forEach((x) =>
|
||||
x.block?.data?.txs.forEach((tx: Uint8Array) =>
|
||||
txs.push({
|
||||
hash: hashTx(tx),
|
||||
tx: decodeTxRaw(tx),
|
||||
})
|
||||
)
|
||||
);
|
||||
return txs;
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
initial() {
|
||||
this.clearRecentBlocks();
|
||||
this.autoFetch();
|
||||
},
|
||||
async clearRecentBlocks() {
|
||||
this.recents = [];
|
||||
},
|
||||
autoFetch() {
|
||||
this.fetchLatest().then((x) => {
|
||||
const timer = this.autoFetch;
|
||||
this.latest = x;
|
||||
// if(this.recents.length >= 50) this.recents.pop()
|
||||
// this.recents.push(x)
|
||||
// setTimeout(timer, 6000)
|
||||
});
|
||||
},
|
||||
async fetchLatest() {
|
||||
this.latest = await this.blockchain.rpc.getBaseBlockLatest();
|
||||
if (this.recents.length >= 50) this.recents.shift();
|
||||
this.recents.push(this.latest);
|
||||
return this.latest;
|
||||
},
|
||||
async fetchBlock(height: string) {
|
||||
this.current = await this.blockchain.rpc.getBaseBlockAt(height);
|
||||
return this.current;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -31,7 +31,7 @@ const format = useFormatter();
|
||||
<table class="table w-full">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="position: relative;">Height</th>
|
||||
<th style="position: relative">Height</th>
|
||||
<th>Hash</th>
|
||||
<th>Proposer</th>
|
||||
<th>Txs</th>
|
||||
@ -57,11 +57,14 @@ const format = useFormatter();
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div v-show="tab === 'transactions'" class="bg-base-100 rounded overflow-x-auto">
|
||||
<div
|
||||
v-show="tab === 'transactions'"
|
||||
class="bg-base-100 rounded overflow-x-auto"
|
||||
>
|
||||
<table class="table w-full">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="position: relative;">Hash</th>
|
||||
<th style="position: relative">Hash</th>
|
||||
<th>Messages</th>
|
||||
<th>Fees</th>
|
||||
</tr>
|
||||
@ -73,7 +76,7 @@ const format = useFormatter();
|
||||
item.hash
|
||||
}}</RouterLink>
|
||||
</td>
|
||||
<td>{{ format.messages(item.tx.body.messages) }}</td>
|
||||
<td>{{ format.messages(item.tx.body.messages as any) }}</td>
|
||||
<td>{{ format.formatTokens(item.tx.authInfo.fee?.amount) }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
@ -1,75 +1,113 @@
|
||||
import { BaseRestClient } from "@/libs/client";
|
||||
import { adapter, type AbstractRegistry, type Request } from "@/libs/registry";
|
||||
import { defineStore } from "pinia";
|
||||
import type { CodeInfo, ContractInfo, PaginabledCodeInfos, PaginabledContractHistory, PaginabledContracts, PaginabledContractStates, WasmParam } from "./types";
|
||||
import { toBase64 } from "@cosmjs/encoding";
|
||||
import { useBlockchain } from "@/stores";
|
||||
import { BaseRestClient } from '@/libs/client';
|
||||
import { adapter, type AbstractRegistry, type Request } from '@/libs/registry';
|
||||
import { defineStore } from 'pinia';
|
||||
import type {
|
||||
CodeInfo,
|
||||
ContractInfo,
|
||||
PaginabledCodeInfos,
|
||||
PaginabledContractHistory,
|
||||
PaginabledContracts,
|
||||
PaginabledContractStates,
|
||||
WasmParam,
|
||||
} from './types';
|
||||
import { toBase64 } from '@cosmjs/encoding';
|
||||
import { useBlockchain } from '@/stores';
|
||||
|
||||
export interface WasmRequestRegistry extends AbstractRegistry {
|
||||
cosmwasm_code: Request<PaginabledCodeInfos>;
|
||||
cosmwasm_code_id: Request<CodeInfo>;
|
||||
cosmwasm_code_id_contracts: Request<PaginabledContracts>;
|
||||
cosmwasm_param: Request<WasmParam>;
|
||||
cosmwasm_contract_address: Request<{address: string, contract_info: ContractInfo}>;
|
||||
cosmwasm_contract_address_history: Request<PaginabledContractHistory>;
|
||||
cosmwasm_contract_address_raw_query_data: Request<any>;
|
||||
cosmwasm_contract_address_smart_query_data: Request<any>;
|
||||
cosmwasm_contract_address_state: Request<PaginabledContractStates>;
|
||||
cosmwasm_code: Request<PaginabledCodeInfos>;
|
||||
cosmwasm_code_id: Request<CodeInfo>;
|
||||
cosmwasm_code_id_contracts: Request<PaginabledContracts>;
|
||||
cosmwasm_param: Request<WasmParam>;
|
||||
cosmwasm_contract_address: Request<{
|
||||
address: string;
|
||||
contract_info: ContractInfo;
|
||||
}>;
|
||||
cosmwasm_contract_address_history: Request<PaginabledContractHistory>;
|
||||
cosmwasm_contract_address_raw_query_data: Request<any>;
|
||||
cosmwasm_contract_address_smart_query_data: Request<any>;
|
||||
cosmwasm_contract_address_state: Request<PaginabledContractStates>;
|
||||
}
|
||||
|
||||
export const DEFAULT: WasmRequestRegistry = {
|
||||
cosmwasm_code: { url: "/cosmwasm/wasm/v1/code", adapter },
|
||||
cosmwasm_code_id: { url: "/cosmwasm/wasm/v1/code/{code_id}", adapter },
|
||||
cosmwasm_code_id_contracts: { url: "/cosmwasm/wasm/v1/code/{code_id}/contracts", adapter },
|
||||
cosmwasm_param: { url: "/cosmwasm/wasm/v1/codes/params", adapter },
|
||||
cosmwasm_contract_address: { url: "/cosmwasm/wasm/v1/contract/{address}", adapter },
|
||||
cosmwasm_contract_address_history: { url: "/cosmwasm/wasm/v1/contract/{address}/history", adapter },
|
||||
cosmwasm_contract_address_raw_query_data: { url: "/cosmwasm/wasm/v1/contract/{address}/raw/{query_data}", adapter },
|
||||
cosmwasm_contract_address_smart_query_data: { url: "/cosmwasm/wasm/v1/contract/{address}/smart/{query_data}", adapter },
|
||||
cosmwasm_contract_address_state: { url: "/cosmwasm/wasm/v1/contract/{address}/state", adapter }
|
||||
}
|
||||
cosmwasm_code: { url: '/cosmwasm/wasm/v1/code', adapter },
|
||||
cosmwasm_code_id: { url: '/cosmwasm/wasm/v1/code/{code_id}', adapter },
|
||||
cosmwasm_code_id_contracts: {
|
||||
url: '/cosmwasm/wasm/v1/code/{code_id}/contracts',
|
||||
adapter,
|
||||
},
|
||||
cosmwasm_param: { url: '/cosmwasm/wasm/v1/codes/params', adapter },
|
||||
cosmwasm_contract_address: {
|
||||
url: '/cosmwasm/wasm/v1/contract/{address}',
|
||||
adapter,
|
||||
},
|
||||
cosmwasm_contract_address_history: {
|
||||
url: '/cosmwasm/wasm/v1/contract/{address}/history',
|
||||
adapter,
|
||||
},
|
||||
cosmwasm_contract_address_raw_query_data: {
|
||||
url: '/cosmwasm/wasm/v1/contract/{address}/raw/{query_data}',
|
||||
adapter,
|
||||
},
|
||||
cosmwasm_contract_address_smart_query_data: {
|
||||
url: '/cosmwasm/wasm/v1/contract/{address}/smart/{query_data}',
|
||||
adapter,
|
||||
},
|
||||
cosmwasm_contract_address_state: {
|
||||
url: '/cosmwasm/wasm/v1/contract/{address}/state',
|
||||
adapter,
|
||||
},
|
||||
};
|
||||
|
||||
class WasmRestClient extends BaseRestClient<WasmRequestRegistry> {
|
||||
getWasmCodeList() {
|
||||
return this.request(this.registry.cosmwasm_code, {})
|
||||
}
|
||||
getWasmCodeById(code_id: string) {
|
||||
return this.request(this.registry.cosmwasm_code, {code_id}) // `code_id` is a param in above url
|
||||
}
|
||||
getWasmCodeContracts(code_id: string) {
|
||||
return this.request(this.registry.cosmwasm_code_id_contracts, {code_id})
|
||||
}
|
||||
getWasmParams() {
|
||||
return this.request(this.registry.cosmwasm_param, {})
|
||||
}
|
||||
getWasmContracts(address: string) {
|
||||
return this.request(this.registry.cosmwasm_contract_address, {address})
|
||||
}
|
||||
getWasmContractHistory(address: string) {
|
||||
return this.request(this.registry.cosmwasm_contract_address_history, {address})
|
||||
}
|
||||
getWasmContractRawQuery(address: string, query: string) {
|
||||
const query_data = toBase64(new TextEncoder().encode(query))
|
||||
return this.request(this.registry.cosmwasm_contract_address_raw_query_data, {address, query_data})
|
||||
}
|
||||
getWasmContractSmartQuery(address: string, query: string) {
|
||||
const query_data = toBase64(new TextEncoder().encode(query))
|
||||
return this.request(this.registry.cosmwasm_contract_address_smart_query_data, {address, query_data})
|
||||
}
|
||||
getWasmContractStates(address: string) {
|
||||
return this.request(this.registry.cosmwasm_contract_address_state, {address})
|
||||
}
|
||||
|
||||
getWasmCodeList() {
|
||||
return this.request(this.registry.cosmwasm_code, {});
|
||||
}
|
||||
getWasmCodeById(code_id: string) {
|
||||
return this.request(this.registry.cosmwasm_code, { code_id }); // `code_id` is a param in above url
|
||||
}
|
||||
getWasmCodeContracts(code_id: string) {
|
||||
return this.request(this.registry.cosmwasm_code_id_contracts, { code_id });
|
||||
}
|
||||
getWasmParams() {
|
||||
return this.request(this.registry.cosmwasm_param, {});
|
||||
}
|
||||
getWasmContracts(address: string) {
|
||||
return this.request(this.registry.cosmwasm_contract_address, { address });
|
||||
}
|
||||
getWasmContractHistory(address: string) {
|
||||
return this.request(this.registry.cosmwasm_contract_address_history, {
|
||||
address,
|
||||
});
|
||||
}
|
||||
getWasmContractRawQuery(address: string, query: string) {
|
||||
const query_data = toBase64(new TextEncoder().encode(query));
|
||||
return this.request(
|
||||
this.registry.cosmwasm_contract_address_raw_query_data,
|
||||
{ address, query_data }
|
||||
);
|
||||
}
|
||||
getWasmContractSmartQuery(address: string, query: string) {
|
||||
const query_data = toBase64(new TextEncoder().encode(query));
|
||||
return this.request(
|
||||
this.registry.cosmwasm_contract_address_smart_query_data,
|
||||
{ address, query_data }
|
||||
);
|
||||
}
|
||||
getWasmContractStates(address: string) {
|
||||
return this.request(this.registry.cosmwasm_contract_address_state, {
|
||||
address,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export const useWasmStore = defineStore('module-wasm', {
|
||||
state: () => {
|
||||
return {}
|
||||
state: () => {
|
||||
return {};
|
||||
},
|
||||
getters: {
|
||||
wasmClient() {
|
||||
const blockchain = useBlockchain();
|
||||
return new WasmRestClient(blockchain.endpoint.address, DEFAULT);
|
||||
},
|
||||
getters: {
|
||||
wasmClient() {
|
||||
const blockchain = useBlockchain()
|
||||
return new WasmRestClient(blockchain.endpoint.address, DEFAULT)
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
});
|
||||
|
@ -1,69 +1,77 @@
|
||||
<script lang="ts" setup>
|
||||
import { fromHex } from "@cosmjs/encoding";
|
||||
import { fromHex } from '@cosmjs/encoding';
|
||||
import { useWasmStore } from '../WasmStore';
|
||||
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 type CustomRadiosVue from '@/plugins/vuetify/@core/components/CustomRadios.vue';
|
||||
import type { CustomInputContent } from '@/plugins/vuetify/@core/types';
|
||||
import { useFormatter } from "@/stores";
|
||||
import { useFormatter } from '@/stores';
|
||||
|
||||
const props = defineProps(['code_id', 'chain', ])
|
||||
const props = defineProps(['code_id', 'chain']);
|
||||
|
||||
const response = ref({} as PaginabledContracts)
|
||||
const response = ref({} as PaginabledContracts);
|
||||
|
||||
const wasmStore = useWasmStore()
|
||||
wasmStore.wasmClient.getWasmCodeContracts(props.code_id).then(x =>{
|
||||
response.value = x
|
||||
})
|
||||
const format = useFormatter()
|
||||
const infoDialog = ref(false)
|
||||
const stateDialog = ref(false)
|
||||
const queryDialog = ref(false)
|
||||
const info = ref({} as ContractInfo)
|
||||
const state = ref( {} as PaginabledContractStates)
|
||||
const selected = ref("")
|
||||
const wasmStore = useWasmStore();
|
||||
wasmStore.wasmClient.getWasmCodeContracts(props.code_id).then((x) => {
|
||||
response.value = x;
|
||||
});
|
||||
const format = useFormatter();
|
||||
const infoDialog = ref(false);
|
||||
const stateDialog = ref(false);
|
||||
const queryDialog = ref(false);
|
||||
const info = ref({} as ContractInfo);
|
||||
const state = ref({} as PaginabledContractStates);
|
||||
const selected = ref('');
|
||||
|
||||
function showInfo(address: string) {
|
||||
wasmStore.wasmClient.getWasmContracts(address).then(x => {
|
||||
info.value = x.contract_info
|
||||
infoDialog.value = true
|
||||
})
|
||||
wasmStore.wasmClient.getWasmContracts(address).then((x) => {
|
||||
info.value = x.contract_info;
|
||||
infoDialog.value = true;
|
||||
});
|
||||
}
|
||||
function showState(address: string) {
|
||||
wasmStore.wasmClient.getWasmContractStates(address).then(x => {
|
||||
state.value = x
|
||||
stateDialog.value = true
|
||||
})
|
||||
wasmStore.wasmClient.getWasmContractStates(address).then((x) => {
|
||||
state.value = x;
|
||||
stateDialog.value = true;
|
||||
});
|
||||
}
|
||||
function showQuery(address: string) {
|
||||
queryDialog.value = true
|
||||
selected.value = address
|
||||
query.value = ""
|
||||
result.value = ""
|
||||
queryDialog.value = true;
|
||||
selected.value = address;
|
||||
query.value = '';
|
||||
result.value = '';
|
||||
}
|
||||
|
||||
function queryContract() {
|
||||
try{
|
||||
|
||||
if(selectedRadio.value === 'raw') {
|
||||
wasmStore.wasmClient.getWasmContractRawQuery(selected.value, query.value).then(x => {
|
||||
result.value = JSON.stringify(x)
|
||||
}).catch(err => {
|
||||
result.value = JSON.stringify(err)
|
||||
})
|
||||
} else {
|
||||
wasmStore.wasmClient.getWasmContractSmartQuery(selected.value, query.value).then(x => {
|
||||
result.value = JSON.stringify(x)
|
||||
}).catch(err => {
|
||||
result.value = JSON.stringify(err)
|
||||
})
|
||||
}
|
||||
|
||||
} catch(err) {
|
||||
result.value = JSON.stringify(err) // not works for now
|
||||
try {
|
||||
if (selectedRadio.value === 'raw') {
|
||||
wasmStore.wasmClient
|
||||
.getWasmContractRawQuery(selected.value, query.value)
|
||||
.then((x) => {
|
||||
result.value = JSON.stringify(x);
|
||||
})
|
||||
.catch((err) => {
|
||||
result.value = JSON.stringify(err);
|
||||
});
|
||||
} else {
|
||||
wasmStore.wasmClient
|
||||
.getWasmContractSmartQuery(selected.value, query.value)
|
||||
.then((x) => {
|
||||
result.value = JSON.stringify(x);
|
||||
})
|
||||
.catch((err) => {
|
||||
result.value = JSON.stringify(err);
|
||||
});
|
||||
}
|
||||
// TODO, show error in the result.
|
||||
} catch (err) {
|
||||
result.value = JSON.stringify(err); // not works for now
|
||||
}
|
||||
// TODO, show error in the result.
|
||||
}
|
||||
|
||||
const radioContent: CustomInputContent[] = [
|
||||
@ -77,78 +85,90 @@ const radioContent: CustomInputContent[] = [
|
||||
desc: 'Return structure result if possible',
|
||||
value: 'smart',
|
||||
},
|
||||
]
|
||||
|
||||
const selectedRadio = ref('raw')
|
||||
const query = ref("")
|
||||
const result = ref("")
|
||||
];
|
||||
|
||||
const selectedRadio = ref('raw');
|
||||
const query = ref('');
|
||||
const result = ref('');
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<VCard>
|
||||
<VCardTitle>Contract List of Code: {{ props.code_id }}</VCardTitle>
|
||||
<VTable>
|
||||
<thead>
|
||||
<tr><th>Contract List</th><th>Actions</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="v in response.contracts">
|
||||
<td>{{ v }}</td><td>
|
||||
<VBtn size="small" @click="showInfo(v)">contract</VBtn>
|
||||
<VBtn size="small" @click="showState(v)" class="ml-2">States</VBtn>
|
||||
<VBtn size="small" @click="showQuery(v)" class="ml-2">Query</VBtn></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</VTable>
|
||||
</VCard>
|
||||
<v-dialog v-model="infoDialog" width="auto">
|
||||
<v-card>
|
||||
<VCardTitle>Contract Detail</VCardTitle>
|
||||
<v-card-text>
|
||||
<DynamicComponent :value="info"/>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-btn color="primary" block @click="infoDialog = false">Close Dialog</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
<v-dialog v-model="stateDialog" width="auto">
|
||||
<v-card>
|
||||
<VCardTitle>Contract States</VCardTitle>
|
||||
<VList>
|
||||
<VListItem v-for="v in state.models">
|
||||
<VListItemTitle>
|
||||
{{ format.hexToString(v.key) }}
|
||||
</VListItemTitle>
|
||||
<VListItemSubtitle :title="format.base64ToString(v.value)">
|
||||
{{ format.base64ToString(v.value) }}
|
||||
</VListItemSubtitle>
|
||||
</VListItem>
|
||||
</VList>
|
||||
<v-card-actions>
|
||||
<v-btn color="primary" block @click="stateDialog = false">Close Dialog</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
<v-dialog v-model="queryDialog" width="auto">
|
||||
<v-card>
|
||||
<VCardTitle>Query Contract</VCardTitle>
|
||||
<v-card-text>
|
||||
<CustomRadios
|
||||
v-model:selected-radio="selectedRadio"
|
||||
:radio-content="radioContent"
|
||||
:grid-column="{ sm: '6', cols: '12' }"
|
||||
/>
|
||||
|
||||
<VTextarea v-model="query" label="Query String" class="my-2"/>
|
||||
<VTextarea v-model="result" label="Result"/>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-btn color="primary" @click="queryDialog = false">Close Dialog</v-btn>
|
||||
<v-btn color="success" @click="queryContract()">Query Contract</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</div>
|
||||
<div>
|
||||
<VCard>
|
||||
<VCardTitle>Contract List of Code: {{ props.code_id }}</VCardTitle>
|
||||
<VTable>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Contract List</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="v in response.contracts">
|
||||
<td>{{ v }}</td>
|
||||
<td>
|
||||
<VBtn size="small" @click="showInfo(v)">contract</VBtn>
|
||||
<VBtn size="small" @click="showState(v)" class="ml-2"
|
||||
>States</VBtn
|
||||
>
|
||||
<VBtn size="small" @click="showQuery(v)" class="ml-2">Query</VBtn>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</VTable>
|
||||
</VCard>
|
||||
<v-dialog v-model="infoDialog" width="auto">
|
||||
<v-card>
|
||||
<VCardTitle>Contract Detail</VCardTitle>
|
||||
<v-card-text>
|
||||
<DynamicComponent :value="info" />
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-btn color="primary" block @click="infoDialog = false"
|
||||
>Close Dialog</v-btn
|
||||
>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
<v-dialog v-model="stateDialog" width="auto">
|
||||
<v-card>
|
||||
<VCardTitle>Contract States</VCardTitle>
|
||||
<VList>
|
||||
<VListItem v-for="v in state.models">
|
||||
<VListItemTitle>
|
||||
{{ format.hexToString(v.key) }}
|
||||
</VListItemTitle>
|
||||
<VListItemSubtitle :title="format.base64ToString(v.value)">
|
||||
{{ format.base64ToString(v.value) }}
|
||||
</VListItemSubtitle>
|
||||
</VListItem>
|
||||
</VList>
|
||||
<v-card-actions>
|
||||
<v-btn color="primary" block @click="stateDialog = false"
|
||||
>Close Dialog</v-btn
|
||||
>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
<v-dialog v-model="queryDialog" width="auto">
|
||||
<v-card>
|
||||
<VCardTitle>Query Contract</VCardTitle>
|
||||
<v-card-text>
|
||||
<CustomRadios
|
||||
v-model:selected-radio="selectedRadio"
|
||||
:radio-content="radioContent"
|
||||
:grid-column="{ sm: '6', cols: '12' }"
|
||||
/>
|
||||
|
||||
<VTextarea v-model="query" label="Query String" class="my-2" />
|
||||
<VTextarea v-model="result" label="Result" />
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-btn color="primary" @click="queryDialog = false"
|
||||
>Close Dialog</v-btn
|
||||
>
|
||||
<v-btn color="success" @click="queryContract()">Query Contract</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -4,38 +4,52 @@ import { useWasmStore } from './WasmStore';
|
||||
import { ref } from 'vue';
|
||||
import type { PaginabledCodeInfos } from './types';
|
||||
|
||||
const props = defineProps(['chain'])
|
||||
const props = defineProps(['chain']);
|
||||
|
||||
const codes = ref({} as PaginabledCodeInfos)
|
||||
const codes = ref({} as PaginabledCodeInfos);
|
||||
|
||||
const wasmStore = useWasmStore()
|
||||
wasmStore.wasmClient.getWasmCodeList().then(x =>{
|
||||
codes.value = x
|
||||
})
|
||||
const wasmStore = useWasmStore();
|
||||
wasmStore.wasmClient.getWasmCodeList().then((x) => {
|
||||
codes.value = x;
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<VCard>
|
||||
<VCardTitle>Cosmos Wasm Smart Contracts</VCardTitle>
|
||||
<VTable>
|
||||
<thead>
|
||||
<tr><th>Code Id</th><th>Code Hash</th><th>Creator</th><th>Permissions</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="v in codes.code_infos">
|
||||
<td>{{ v.code_id }}</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.creator }}</td>
|
||||
<td>
|
||||
{{ v.instantiate_permission?.permission }}
|
||||
<span>{{ v.instantiate_permission?.address }} {{ v.instantiate_permission.addresses.join(", ") }}</span>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</VTable>
|
||||
</VCard>
|
||||
</div>
|
||||
<div>
|
||||
<VCard>
|
||||
<VCardTitle>Cosmos Wasm Smart Contracts</VCardTitle>
|
||||
<VTable>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Code Id</th>
|
||||
<th>Code Hash</th>
|
||||
<th>Creator</th>
|
||||
<th>Permissions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="v in codes.code_infos">
|
||||
<td>{{ v.code_id }}</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.creator }}</td>
|
||||
<td>
|
||||
{{ v.instantiate_permission?.permission }}
|
||||
<span
|
||||
>{{ v.instantiate_permission?.address }}
|
||||
{{ v.instantiate_permission.addresses.join(', ') }}</span
|
||||
>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</VTable>
|
||||
</VCard>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<route>
|
||||
@ -44,4 +58,4 @@ wasmStore.wasmClient.getWasmCodeList().then(x =>{
|
||||
i18n: 'cosmwasm'
|
||||
}
|
||||
}
|
||||
</route>
|
||||
</route>
|
||||
|
@ -1,69 +1,69 @@
|
||||
import type { PaginatedResponse } from "@/types"
|
||||
import type { PaginatedResponse } from '@/types';
|
||||
|
||||
export interface CodeInfo {
|
||||
code_id: string,
|
||||
creator: string,
|
||||
data_hash: string,
|
||||
instantiate_permission: {
|
||||
permission: string,
|
||||
address: string,
|
||||
addresses: string[]
|
||||
}
|
||||
code_id: string;
|
||||
creator: string;
|
||||
data_hash: string;
|
||||
instantiate_permission: {
|
||||
permission: string;
|
||||
address: string;
|
||||
addresses: string[];
|
||||
};
|
||||
}
|
||||
|
||||
export interface ContractInfo {
|
||||
code_id: string,
|
||||
creator: string,
|
||||
admin: string,
|
||||
label: string,
|
||||
created: {
|
||||
block_height: string,
|
||||
tx_index: string
|
||||
},
|
||||
ibc_port_id: string,
|
||||
extension: {
|
||||
type_url: string,
|
||||
value: string
|
||||
}
|
||||
}
|
||||
code_id: string;
|
||||
creator: string;
|
||||
admin: string;
|
||||
label: string;
|
||||
created: {
|
||||
block_height: string;
|
||||
tx_index: string;
|
||||
};
|
||||
ibc_port_id: string;
|
||||
extension: {
|
||||
type_url: string;
|
||||
value: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface WasmParam {
|
||||
params: {
|
||||
code_upload_access: {
|
||||
permission: string,
|
||||
address: string,
|
||||
addresses: string[]
|
||||
},
|
||||
instantiate_default_permission: string
|
||||
}
|
||||
params: {
|
||||
code_upload_access: {
|
||||
permission: string;
|
||||
address: string;
|
||||
addresses: string[];
|
||||
};
|
||||
instantiate_default_permission: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface HistoryEntry {
|
||||
operation: string,
|
||||
code_id: string,
|
||||
updated: {
|
||||
block_height: string,
|
||||
tx_index: string
|
||||
},
|
||||
msg: string
|
||||
operation: string;
|
||||
code_id: string;
|
||||
updated: {
|
||||
block_height: string;
|
||||
tx_index: string;
|
||||
};
|
||||
msg: string;
|
||||
}
|
||||
|
||||
export interface Models {
|
||||
key: string,
|
||||
value: string
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface PaginabledContractHistory extends PaginatedResponse {
|
||||
entries: HistoryEntry[]
|
||||
entries: HistoryEntry[];
|
||||
}
|
||||
|
||||
export interface PaginabledContractStates extends PaginatedResponse {
|
||||
models: Models[]
|
||||
models: Models[];
|
||||
}
|
||||
|
||||
export interface PaginabledCodeInfos extends PaginatedResponse {
|
||||
code_infos: CodeInfo[]
|
||||
code_infos: CodeInfo[];
|
||||
}
|
||||
export interface PaginabledContracts extends PaginatedResponse {
|
||||
contracts: string[]
|
||||
}
|
||||
contracts: string[];
|
||||
}
|
||||
|
@ -6,8 +6,6 @@ import { ref , reactive} from 'vue';
|
||||
import Countdown from '@/components/Countdown.vue';
|
||||
import { computed } from '@vue/reactivity';
|
||||
|
||||
|
||||
|
||||
const props = defineProps(["proposal_id", "chain"]);
|
||||
const proposal = ref({} as GovProposal)
|
||||
const format = useFormatter()
|
||||
@ -147,7 +145,6 @@ const processList = computed(()=>{
|
||||
{name: 'Abstain', value : abstain.value, class: 'bg-warning' }
|
||||
]
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -6,10 +6,10 @@ const tab = ref('2');
|
||||
const store = useGovStore();
|
||||
|
||||
onMounted(() => {
|
||||
store.fetchProposals('2').then(x => {
|
||||
if(x.proposals.length ===0 ) {
|
||||
tab.value = "3"
|
||||
store.fetchProposals('3')
|
||||
store.fetchProposals('2').then((x) => {
|
||||
if (x.proposals.length === 0) {
|
||||
tab.value = '3';
|
||||
store.fetchProposals('3');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -1,108 +1,146 @@
|
||||
<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 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[])
|
||||
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
|
||||
})
|
||||
}
|
||||
})
|
||||
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)
|
||||
})
|
||||
chainStore.rpc.getIBCChannelNextSequence(channel, port).then((x) => {
|
||||
console.log(x);
|
||||
});
|
||||
}
|
||||
|
||||
function color(v: string) {
|
||||
if(v && v.indexOf("_OPEN") > -1) {
|
||||
return "success"
|
||||
}
|
||||
return "warning"
|
||||
if (v && v.indexOf('_OPEN') > -1) {
|
||||
return 'success';
|
||||
}
|
||||
return 'warning';
|
||||
}
|
||||
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<div class="px-4 pt-3 pb-4 bg-base-100 rounded mb-4 shadow 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>
|
||||
|
||||
<div class="bg-base-100 px-4 pt-3 pb-4 rounded mb-4 shadow">
|
||||
<h2 class="card-title">IBC Client State </h2>
|
||||
<div class="text-sm">
|
||||
<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 }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-base-100 px-4 pt-3 pb-4 rounded mb-4 shadow">
|
||||
<h2 class="card-title">Channels </h2>
|
||||
<div class="overflow-x-auto"></div>
|
||||
<table class="table w-full mt-4">
|
||||
<thead>
|
||||
<tr><th style="position: relative;">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>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="px-4 pt-3 pb-4 bg-base-100 rounded mb-4 shadow 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>
|
||||
|
||||
<div class="bg-base-100 px-4 pt-3 pb-4 rounded mb-4 shadow">
|
||||
<h2 class="card-title">IBC Client State</h2>
|
||||
<div class="text-sm">
|
||||
<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 }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-base-100 px-4 pt-3 pb-4 rounded mb-4 shadow">
|
||||
<h2 class="card-title">Channels</h2>
|
||||
<div class="overflow-x-auto"></div>
|
||||
<table class="table w-full mt-4">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="position: relative">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>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -4,44 +4,58 @@ 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[])
|
||||
const props = defineProps(['chain']);
|
||||
const chainStore = useBlockchain();
|
||||
const list = ref([] as Connection[]);
|
||||
onMounted(() => {
|
||||
chainStore.rpc.getIBCConnections().then(x => {
|
||||
list.value = x.connections
|
||||
})
|
||||
})
|
||||
chainStore.rpc.getIBCConnections().then((x) => {
|
||||
list.value = x.connections;
|
||||
});
|
||||
});
|
||||
|
||||
function color(v: string) {
|
||||
if(v && v.indexOf("_OPEN") > -1) {
|
||||
return "success"
|
||||
}
|
||||
return "warning"
|
||||
if (v && v.indexOf('_OPEN') > -1) {
|
||||
return 'success';
|
||||
}
|
||||
return 'warning';
|
||||
}
|
||||
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<div class="bg-base-100 px-4 pt-3 pb-4 rounded shadow">
|
||||
<h2 class="card-title">IBC Connections</h2>
|
||||
<div class="overflow-x-auto mt-4">
|
||||
<table class="table w-full">
|
||||
<thead>
|
||||
<tr><th style="position: relative;">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>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="bg-base-100 px-4 pt-3 pb-4 rounded shadow">
|
||||
<h2 class="card-title">IBC Connections</h2>
|
||||
<div class="overflow-x-auto mt-4">
|
||||
<table class="table w-full">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="position: relative">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>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<route>
|
||||
@ -50,4 +64,4 @@ function color(v: string) {
|
||||
i18n: 'ibc'
|
||||
}
|
||||
}
|
||||
</route>
|
||||
</route>
|
||||
|
@ -25,12 +25,18 @@ const format = useFormatter();
|
||||
const ticker = computed(() => store.coinInfo.tickers[store.tickerIndex]);
|
||||
|
||||
blockchain.$subscribe((m, s) => {
|
||||
if (!Array.isArray(m.events) && ['chainName', 'endpoint'].includes(m.events.key)) {
|
||||
if (
|
||||
!Array.isArray(m.events) &&
|
||||
['chainName', 'endpoint'].includes(m.events.key)
|
||||
) {
|
||||
store.loadDashboard();
|
||||
}
|
||||
});
|
||||
function shortName(name: string, id: string) {
|
||||
return name.toLowerCase().startsWith('ibc/') || name.toLowerCase().startsWith('0x') ? id : name;
|
||||
return name.toLowerCase().startsWith('ibc/') ||
|
||||
name.toLowerCase().startsWith('0x')
|
||||
? id
|
||||
: name;
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -47,27 +53,51 @@ function shortName(name: string, id: string) {
|
||||
</VCardTitle>
|
||||
<VCardSubtitle>
|
||||
Rank:
|
||||
<VChip color="error" size="x-small">#{{ coinInfo.market_cap_rank }}</VChip>
|
||||
<VChip color="error" size="x-small"
|
||||
>#{{ coinInfo.market_cap_rank }}</VChip
|
||||
>
|
||||
</VCardSubtitle>
|
||||
</VCardItem>
|
||||
<VDivider />
|
||||
<VCardItem>
|
||||
<VBtn variant="text" size="small" :href="store.homepage" prependIcon="mdi-web">
|
||||
<VBtn
|
||||
variant="text"
|
||||
size="small"
|
||||
:href="store.homepage"
|
||||
prependIcon="mdi-web"
|
||||
>
|
||||
Website
|
||||
</VBtn>
|
||||
<VBtn variant="text" size="small" :href="store.twitter" prependIcon="mdi-twitter">
|
||||
<VBtn
|
||||
variant="text"
|
||||
size="small"
|
||||
:href="store.twitter"
|
||||
prependIcon="mdi-twitter"
|
||||
>
|
||||
Twitter
|
||||
</VBtn>
|
||||
<VBtn variant="text" size="small" :href="store.telegram" prependIcon="mdi-telegram">
|
||||
<VBtn
|
||||
variant="text"
|
||||
size="small"
|
||||
:href="store.telegram"
|
||||
prependIcon="mdi-telegram"
|
||||
>
|
||||
Telegram
|
||||
</VBtn>
|
||||
<VBtn variant="text" size="small" :href="store.github" prependIcon="mdi-github">
|
||||
<VBtn
|
||||
variant="text"
|
||||
size="small"
|
||||
:href="store.github"
|
||||
prependIcon="mdi-github"
|
||||
>
|
||||
Github
|
||||
</VBtn>
|
||||
</VCardItem>
|
||||
<VCardItem>
|
||||
<!-- SECTION upgrade plan banner -->
|
||||
<div class="plan-upgrade-banner d-flex bg-light-secondary rounded align-center pa-3">
|
||||
<div
|
||||
class="plan-upgrade-banner d-flex bg-light-secondary rounded align-center pa-3"
|
||||
>
|
||||
<h3 class="plan-details me-3" :class="store.priceColor">
|
||||
{{ store.priceChange }}
|
||||
<small>%</small>
|
||||
@ -102,7 +132,10 @@ function shortName(name: string, id: string) {
|
||||
}}
|
||||
</VListItemSubtitle>
|
||||
<template #append>
|
||||
<span class="ml-3" :class="`text-${store.tickerColor(item.trust_score)}`">
|
||||
<span
|
||||
class="ml-3"
|
||||
:class="`text-${store.tickerColor(item.trust_score)}`"
|
||||
>
|
||||
{{ item.converted_last.usd }}
|
||||
</span>
|
||||
</template>
|
||||
@ -119,9 +152,13 @@ function shortName(name: string, id: string) {
|
||||
<span class="text-h5">{{ ticker.converted_last.usd }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- !SECTION -->
|
||||
<VSpacer />
|
||||
<VBtn block :color="store.trustColor" class="mt-3" :href="ticker.trade_url">
|
||||
<VBtn
|
||||
block
|
||||
:color="store.trustColor"
|
||||
class="mt-3"
|
||||
:href="ticker.trade_url"
|
||||
>
|
||||
Buy {{ coinInfo.symbol || '' }}
|
||||
</VBtn>
|
||||
</VCardItem>
|
||||
@ -134,10 +171,15 @@ function shortName(name: string, id: string) {
|
||||
</VRow>
|
||||
<VDivider />
|
||||
<VCardText style="max-height: 250px; overflow: auto">
|
||||
<MdEditor :model-value="coinInfo.description?.en" previewOnly></MdEditor>
|
||||
<MdEditor
|
||||
:model-value="coinInfo.description?.en"
|
||||
previewOnly
|
||||
></MdEditor>
|
||||
</VCardText>
|
||||
<VCardItem>
|
||||
<VChip v-for="tag in coinInfo.categories" size="x-small" class="mr-2">{{ tag }}</VChip>
|
||||
<VChip v-for="tag in coinInfo.categories" size="x-small" class="mr-2">{{
|
||||
tag
|
||||
}}</VChip>
|
||||
</VCardItem>
|
||||
</VCard>
|
||||
|
||||
@ -154,10 +196,14 @@ function shortName(name: string, id: string) {
|
||||
<VCardItem>
|
||||
<ProposalListItem :proposals="store?.proposals" />
|
||||
</VCardItem>
|
||||
<VCardText v-if="store.proposals.length === 0">No active proposals</VCardText>
|
||||
<VCardText v-if="store.proposals.length === 0"
|
||||
>No active proposals</VCardText
|
||||
>
|
||||
</VCard>
|
||||
|
||||
<VBtn block color="secondary" variant="outlined" class="mt-5">Connect Wallet</VBtn>
|
||||
<VBtn block color="secondary" variant="outlined" class="mt-5"
|
||||
>Connect Wallet</VBtn
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -1,212 +1,234 @@
|
||||
import { useBlockchain, useCoingecko, useBaseStore, useBankStore, useFormatter, useGovStore } from "@/stores";
|
||||
import { useDistributionStore } from "@/stores/useDistributionStore";
|
||||
import { useMintStore } from "@/stores/useMintStore";
|
||||
import { useStakingStore } from "@/stores/useStakingStore";
|
||||
import type { GovProposal, PaginatedProposals, Tally } from "@/types";
|
||||
import numeral from "numeral";
|
||||
import { defineStore } from "pinia";
|
||||
import {
|
||||
useBlockchain,
|
||||
useCoingecko,
|
||||
useBaseStore,
|
||||
useBankStore,
|
||||
useFormatter,
|
||||
useGovStore,
|
||||
} from '@/stores';
|
||||
import { useDistributionStore } from '@/stores/useDistributionStore';
|
||||
import { useMintStore } from '@/stores/useMintStore';
|
||||
import { useStakingStore } from '@/stores/useStakingStore';
|
||||
import type { GovProposal, PaginatedProposals, Tally } from '@/types';
|
||||
import numeral from 'numeral';
|
||||
import { defineStore } from 'pinia';
|
||||
|
||||
function colorMap(color: string) {
|
||||
switch (color) {
|
||||
case 'yellow':
|
||||
return 'warning'
|
||||
case 'green':
|
||||
return 'success'
|
||||
default:
|
||||
return 'secondary'
|
||||
}
|
||||
switch (color) {
|
||||
case 'yellow':
|
||||
return 'warning';
|
||||
case 'green':
|
||||
return 'success';
|
||||
default:
|
||||
return 'secondary';
|
||||
}
|
||||
}
|
||||
|
||||
export const useIndexModule = defineStore('module-index', {
|
||||
state: () => {
|
||||
return {
|
||||
days: 14,
|
||||
tickerIndex: 0,
|
||||
coinInfo: {
|
||||
name: '',
|
||||
symbol: '',
|
||||
description: {
|
||||
en: ''
|
||||
},
|
||||
categories: [] as string[],
|
||||
market_cap_rank: 0,
|
||||
links: {
|
||||
twitter_screen_name: '',
|
||||
homepage: [] as string[],
|
||||
repos_url: {
|
||||
github: []
|
||||
},
|
||||
telegram_channel_identifier: ''
|
||||
},
|
||||
market_data: {
|
||||
price_change_percentage_24h: 0
|
||||
},
|
||||
tickers: [] as {
|
||||
market: {
|
||||
name: string,
|
||||
identifier: string,
|
||||
},
|
||||
coin_id: string,
|
||||
target_coin_id: string,
|
||||
trust_score: string,
|
||||
trade_url: string,
|
||||
converted_last: {
|
||||
btc: number,
|
||||
eth: number,
|
||||
usd: number,
|
||||
},
|
||||
base: string,
|
||||
target: string,
|
||||
}[]
|
||||
},
|
||||
marketData: {
|
||||
market_caps: [],
|
||||
prices: [] as number[],
|
||||
total_volumes: [] as number[],
|
||||
},
|
||||
communityPool: [] as {amount: string, denom: string}[],
|
||||
proposals: {} as PaginatedProposals,
|
||||
tally: {} as Record<string, Tally>
|
||||
}
|
||||
state: () => {
|
||||
return {
|
||||
days: 14,
|
||||
tickerIndex: 0,
|
||||
coinInfo: {
|
||||
name: '',
|
||||
symbol: '',
|
||||
description: {
|
||||
en: '',
|
||||
},
|
||||
categories: [] as string[],
|
||||
market_cap_rank: 0,
|
||||
links: {
|
||||
twitter_screen_name: '',
|
||||
homepage: [] as string[],
|
||||
repos_url: {
|
||||
github: [],
|
||||
},
|
||||
telegram_channel_identifier: '',
|
||||
},
|
||||
market_data: {
|
||||
price_change_percentage_24h: 0,
|
||||
},
|
||||
tickers: [] as {
|
||||
market: {
|
||||
name: string;
|
||||
identifier: string;
|
||||
};
|
||||
coin_id: string;
|
||||
target_coin_id: string;
|
||||
trust_score: string;
|
||||
trade_url: string;
|
||||
converted_last: {
|
||||
btc: number;
|
||||
eth: number;
|
||||
usd: number;
|
||||
};
|
||||
base: string;
|
||||
target: string;
|
||||
}[],
|
||||
},
|
||||
marketData: {
|
||||
market_caps: [],
|
||||
prices: [] as number[],
|
||||
total_volumes: [] as number[],
|
||||
},
|
||||
communityPool: [] as { amount: string; denom: string }[],
|
||||
proposals: {} as PaginatedProposals,
|
||||
tally: {} as Record<string, Tally>,
|
||||
};
|
||||
},
|
||||
getters: {
|
||||
blockchain() {
|
||||
const chain = useBlockchain();
|
||||
return chain.current;
|
||||
},
|
||||
getters: {
|
||||
blockchain() {
|
||||
const chain = useBlockchain()
|
||||
return chain.current
|
||||
},
|
||||
coingecko() {
|
||||
return useCoingecko()
|
||||
},
|
||||
bankStore() {
|
||||
return useBankStore()
|
||||
},
|
||||
twitter() : string {
|
||||
return `https://twitter.com/${this.coinInfo.links.twitter_screen_name}`
|
||||
},
|
||||
homepage(): string {
|
||||
const [page1, page2, page3] = this.coinInfo.links?.homepage
|
||||
return page1 || page2 || page3
|
||||
},
|
||||
github(): string {
|
||||
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}`
|
||||
},
|
||||
|
||||
priceChange(): string {
|
||||
const change = this.coinInfo.market_data?.price_change_percentage_24h || 0
|
||||
return numeral(change).format('+0.[00]')
|
||||
},
|
||||
|
||||
priceColor() : string {
|
||||
const change = this.coinInfo.market_data?.price_change_percentage_24h || 0
|
||||
switch (true) {
|
||||
case change > 0:
|
||||
return 'text-success'
|
||||
case change < 0:
|
||||
return 'text-error'
|
||||
default:
|
||||
return ''
|
||||
}
|
||||
},
|
||||
trustColor() : string {
|
||||
const change = this.coinInfo.tickers[this.tickerIndex]?.trust_score
|
||||
return colorMap(change)
|
||||
},
|
||||
|
||||
pool() {
|
||||
const staking = useStakingStore()
|
||||
return staking.pool
|
||||
},
|
||||
|
||||
stats () {
|
||||
const base = useBaseStore()
|
||||
const bank = useBankStore()
|
||||
const staking = useStakingStore()
|
||||
const mintStore = useMintStore()
|
||||
const formatter = useFormatter()
|
||||
|
||||
return [
|
||||
{
|
||||
title: 'Height',
|
||||
color: 'primary',
|
||||
icon: 'mdi-pound',
|
||||
stats: String(base.latest.block?.header?.height || 0),
|
||||
change: 0,
|
||||
},
|
||||
{
|
||||
title: 'Validators',
|
||||
color: 'error',
|
||||
icon: 'mdi-human-queue',
|
||||
stats: String(base.latest.block?.last_commit?.signatures.length || 0),
|
||||
change: 0,
|
||||
},
|
||||
{
|
||||
title: 'Supply',
|
||||
color: 'success',
|
||||
icon: 'mdi-currency-usd',
|
||||
stats: formatter.formatTokenAmount(bank.supply),
|
||||
change: 0,
|
||||
},
|
||||
{
|
||||
title: 'Bonded Tokens',
|
||||
color: 'warning',
|
||||
icon: 'mdi-lock',
|
||||
stats: formatter.formatTokenAmount({amount: this.pool.bonded_tokens, denom: staking.params.bond_denom }),
|
||||
change: 0,
|
||||
},
|
||||
{
|
||||
title: 'Inflation',
|
||||
color: 'success',
|
||||
icon: 'mdi-chart-multiple',
|
||||
stats: formatter.formatDecimalToPercent(mintStore.inflation),
|
||||
change: 0,
|
||||
},
|
||||
{
|
||||
title: 'Community Pool',
|
||||
color: 'primary',
|
||||
icon: 'mdi-bank',
|
||||
stats: formatter.formatTokens(this.communityPool?.filter(x => x.denom === staking.params.bond_denom)),
|
||||
change: 0,
|
||||
},
|
||||
]
|
||||
},
|
||||
coingecko() {
|
||||
return useCoingecko();
|
||||
},
|
||||
actions: {
|
||||
async loadDashboard() {
|
||||
this.$reset()
|
||||
this.initCoingecko()
|
||||
useMintStore().fetchInflation()
|
||||
useDistributionStore().fetchCommunityPool().then(x => {
|
||||
this.communityPool = x.pool.filter(t => t.denom.length < 10).map(t => ({
|
||||
amount: String(parseInt(t.amount)),
|
||||
denom: t.denom
|
||||
}))
|
||||
})
|
||||
const gov = useGovStore()
|
||||
gov.fetchProposals("2").then(x => {
|
||||
this.proposals = x
|
||||
})
|
||||
bankStore() {
|
||||
return useBankStore();
|
||||
},
|
||||
twitter(): string {
|
||||
return `https://twitter.com/${this.coinInfo.links.twitter_screen_name}`;
|
||||
},
|
||||
homepage(): string {
|
||||
const [page1, page2, page3] = this.coinInfo.links?.homepage;
|
||||
return page1 || page2 || page3;
|
||||
},
|
||||
github(): string {
|
||||
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}`;
|
||||
},
|
||||
|
||||
priceChange(): string {
|
||||
const change =
|
||||
this.coinInfo.market_data?.price_change_percentage_24h || 0;
|
||||
return numeral(change).format('+0.[00]');
|
||||
},
|
||||
|
||||
priceColor(): string {
|
||||
const change =
|
||||
this.coinInfo.market_data?.price_change_percentage_24h || 0;
|
||||
switch (true) {
|
||||
case change > 0:
|
||||
return 'text-success';
|
||||
case change < 0:
|
||||
return 'text-error';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
},
|
||||
trustColor(): string {
|
||||
const change = this.coinInfo.tickers[this.tickerIndex]?.trust_score;
|
||||
return colorMap(change);
|
||||
},
|
||||
|
||||
pool() {
|
||||
const staking = useStakingStore();
|
||||
return staking.pool;
|
||||
},
|
||||
|
||||
stats() {
|
||||
const base = useBaseStore();
|
||||
const bank = useBankStore();
|
||||
const staking = useStakingStore();
|
||||
const mintStore = useMintStore();
|
||||
const formatter = useFormatter();
|
||||
|
||||
return [
|
||||
{
|
||||
title: 'Height',
|
||||
color: 'primary',
|
||||
icon: 'mdi-pound',
|
||||
stats: String(base.latest.block?.header?.height || 0),
|
||||
change: 0,
|
||||
},
|
||||
tickerColor(color: string) {
|
||||
return colorMap(color)
|
||||
},
|
||||
initCoingecko() {
|
||||
this.tickerIndex = 0
|
||||
const [firstAsset] = this.blockchain?.assets || []
|
||||
if (firstAsset && firstAsset.coingecko_id) {
|
||||
this.coingecko.getCoinInfo(firstAsset.coingecko_id).then(x => {
|
||||
this.coinInfo = x
|
||||
})
|
||||
this.coingecko.getMarketChart(this.days, firstAsset.coingecko_id).then(x => {
|
||||
this.marketData = x
|
||||
})
|
||||
}
|
||||
{
|
||||
title: 'Validators',
|
||||
color: 'error',
|
||||
icon: 'mdi-human-queue',
|
||||
stats: String(base.latest.block?.last_commit?.signatures.length || 0),
|
||||
change: 0,
|
||||
},
|
||||
selectTicker(i: number) {
|
||||
this.tickerIndex = i
|
||||
}
|
||||
}
|
||||
})
|
||||
{
|
||||
title: 'Supply',
|
||||
color: 'success',
|
||||
icon: 'mdi-currency-usd',
|
||||
stats: formatter.formatTokenAmount(bank.supply),
|
||||
change: 0,
|
||||
},
|
||||
{
|
||||
title: 'Bonded Tokens',
|
||||
color: 'warning',
|
||||
icon: 'mdi-lock',
|
||||
stats: formatter.formatTokenAmount({
|
||||
amount: this.pool.bonded_tokens,
|
||||
denom: staking.params.bond_denom,
|
||||
}),
|
||||
change: 0,
|
||||
},
|
||||
{
|
||||
title: 'Inflation',
|
||||
color: 'success',
|
||||
icon: 'mdi-chart-multiple',
|
||||
stats: formatter.formatDecimalToPercent(mintStore.inflation),
|
||||
change: 0,
|
||||
},
|
||||
{
|
||||
title: 'Community Pool',
|
||||
color: 'primary',
|
||||
icon: 'mdi-bank',
|
||||
stats: formatter.formatTokens(
|
||||
this.communityPool?.filter(
|
||||
(x) => x.denom === staking.params.bond_denom
|
||||
)
|
||||
),
|
||||
change: 0,
|
||||
},
|
||||
];
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
async loadDashboard() {
|
||||
this.$reset();
|
||||
this.initCoingecko();
|
||||
useMintStore().fetchInflation();
|
||||
useDistributionStore()
|
||||
.fetchCommunityPool()
|
||||
.then((x) => {
|
||||
this.communityPool = x.pool
|
||||
.filter((t) => t.denom.length < 10)
|
||||
.map((t) => ({
|
||||
amount: String(parseInt(t.amount)),
|
||||
denom: t.denom,
|
||||
}));
|
||||
});
|
||||
const gov = useGovStore();
|
||||
gov.fetchProposals('2').then((x) => {
|
||||
this.proposals = x;
|
||||
});
|
||||
},
|
||||
tickerColor(color: string) {
|
||||
return colorMap(color);
|
||||
},
|
||||
initCoingecko() {
|
||||
this.tickerIndex = 0;
|
||||
const [firstAsset] = this.blockchain?.assets || [];
|
||||
if (firstAsset && firstAsset.coingecko_id) {
|
||||
this.coingecko.getCoinInfo(firstAsset.coingecko_id).then((x) => {
|
||||
this.coinInfo = x;
|
||||
});
|
||||
this.coingecko
|
||||
.getMarketChart(this.days, firstAsset.coingecko_id)
|
||||
.then((x) => {
|
||||
this.marketData = x;
|
||||
});
|
||||
}
|
||||
},
|
||||
selectTicker(i: number) {
|
||||
this.tickerIndex = i;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -1,15 +1,14 @@
|
||||
<script lang="ts" setup>
|
||||
import { useParamStore } from '@/stores';
|
||||
import { ref, onMounted } from 'vue'
|
||||
import CardParameter from '@/components/CardParameter.vue'
|
||||
import { ref, onMounted } from 'vue';
|
||||
import CardParameter from '@/components/CardParameter.vue';
|
||||
import ArrayObjectElement from '@/components/dynamic/ArrayObjectElement.vue';
|
||||
const store = useParamStore()
|
||||
const chain = ref(store.chain)
|
||||
const store = useParamStore();
|
||||
const chain = ref(store.chain);
|
||||
onMounted(() => {
|
||||
// fetch the data
|
||||
store.initial()
|
||||
})
|
||||
|
||||
// fetch the data
|
||||
store.initial();
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<div class="overflow-hidden">
|
||||
@ -29,28 +28,27 @@ onMounted(() => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- minting Parameters -->
|
||||
<CardParameter :cardItem="store.mint"/>
|
||||
<!-- Staking Parameters -->
|
||||
<CardParameter :cardItem="store.staking"/>
|
||||
<!-- Governance Parameters -->
|
||||
<CardParameter :cardItem="store.gov"/>
|
||||
<!-- Distribution Parameters -->
|
||||
<CardParameter :cardItem="store.distribution"/>
|
||||
<!-- Slashing Parameters -->
|
||||
<CardParameter :cardItem="store.slashing"/>
|
||||
<!-- Application Version -->
|
||||
<div class="bg-base-100 px-4 pt-3 pb-4 rounded-sm mt-6">
|
||||
<div class="text-base mb-3 text-main">{{ store.appVersion?.title }}</div>
|
||||
<ArrayObjectElement :value="store.appVersion?.items" :thead="false"/>
|
||||
</div>
|
||||
|
||||
<!-- Node Information -->
|
||||
<div class="bg-base-100 px-4 pt-3 pb-4ß rounded-sm mt-6">
|
||||
<div class="text-base mb-3 text-main">{{ store.nodeVersion?.title }}</div>
|
||||
<ArrayObjectElement :value="store.nodeVersion?.items" :thead="false"/>
|
||||
</div>
|
||||
|
||||
<!-- minting Parameters -->
|
||||
<CardParameter :cardItem="store.mint" />
|
||||
<!-- Staking Parameters -->
|
||||
<CardParameter :cardItem="store.staking" />
|
||||
<!-- Governance Parameters -->
|
||||
<CardParameter :cardItem="store.gov" />
|
||||
<!-- Distribution Parameters -->
|
||||
<CardParameter :cardItem="store.distribution" />
|
||||
<!-- Slashing Parameters -->
|
||||
<CardParameter :cardItem="store.slashing" />
|
||||
<!-- Application Version -->
|
||||
<div class="bg-base-100 px-4 pt-3 pb-4 rounded-sm mt-6">
|
||||
<div class="text-base mb-3 text-main">{{ store.appVersion?.title }}</div>
|
||||
<ArrayObjectElement :value="store.appVersion?.items" :thead="false" />
|
||||
</div>
|
||||
|
||||
<!-- Node Information -->
|
||||
<div class="bg-base-100 px-4 pt-3 pb-4ß rounded-sm mt-6">
|
||||
<div class="text-base mb-3 text-main">{{ store.nodeVersion?.title }}</div>
|
||||
<ArrayObjectElement :value="store.nodeVersion?.items" :thead="false" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -1,275 +1,399 @@
|
||||
<script setup lang="ts">
|
||||
import { useBankStore, useBlockchain, useFormatter, useMintStore, useStakingStore } from '@/stores';
|
||||
import {
|
||||
useBankStore,
|
||||
useBlockchain,
|
||||
useFormatter,
|
||||
useMintStore,
|
||||
useStakingStore,
|
||||
} from '@/stores';
|
||||
import { onMounted, computed, ref } from 'vue';
|
||||
import ValidatorCommissionRate from '@/components/ValidatorCommissionRate.vue'
|
||||
import { consensusPubkeyToHexAddress, operatorAddressToAccount, pubKeyToValcons, valoperToPrefix } from '@/libs';
|
||||
import ValidatorCommissionRate from '@/components/ValidatorCommissionRate.vue';
|
||||
import {
|
||||
consensusPubkeyToHexAddress,
|
||||
operatorAddressToAccount,
|
||||
pubKeyToValcons,
|
||||
valoperToPrefix,
|
||||
} from '@/libs';
|
||||
import type { Coin, Delegation, PaginatedTxs, Validator } from '@/types';
|
||||
|
||||
const props = defineProps(['validator', 'chain'])
|
||||
const props = defineProps(['validator', 'chain']);
|
||||
|
||||
const staking = useStakingStore()
|
||||
const blockchain = useBlockchain()
|
||||
const format = useFormatter()
|
||||
const staking = useStakingStore();
|
||||
const blockchain = useBlockchain();
|
||||
const format = useFormatter();
|
||||
|
||||
const validator: string = props.validator
|
||||
const validator: string = props.validator;
|
||||
|
||||
const v = ref({} as Validator)
|
||||
const cache = JSON.parse(localStorage.getItem('avatars')||'{}')
|
||||
const avatars = ref( cache || {} )
|
||||
const identity = ref("")
|
||||
const rewards = ref([] as Coin[]|undefined)
|
||||
const commission = ref([] as Coin[]|undefined)
|
||||
const addresses = ref({} as {
|
||||
account: string
|
||||
operAddress: string
|
||||
hex: string
|
||||
valCons: string,
|
||||
})
|
||||
const selfBonded = ref({} as Delegation)
|
||||
const v = ref({} as Validator);
|
||||
const cache = JSON.parse(localStorage.getItem('avatars') || '{}');
|
||||
const avatars = ref(cache || {});
|
||||
const identity = ref('');
|
||||
const rewards = ref([] as Coin[] | undefined);
|
||||
const commission = ref([] as Coin[] | undefined);
|
||||
const addresses = ref(
|
||||
{} as {
|
||||
account: string;
|
||||
operAddress: string;
|
||||
hex: string;
|
||||
valCons: string;
|
||||
}
|
||||
);
|
||||
const selfBonded = ref({} as Delegation);
|
||||
|
||||
addresses.value.account = operatorAddressToAccount(validator)
|
||||
addresses.value.account = operatorAddressToAccount(validator);
|
||||
// load self bond
|
||||
staking.fetchValidatorDelegation(validator, addresses.value.account).then(x => {
|
||||
if(x) {
|
||||
selfBonded.value = x.delegation_response
|
||||
staking
|
||||
.fetchValidatorDelegation(validator, addresses.value.account)
|
||||
.then((x) => {
|
||||
if (x) {
|
||||
selfBonded.value = x.delegation_response;
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
const txs = ref({} as PaginatedTxs)
|
||||
const txs = ref({} as PaginatedTxs);
|
||||
|
||||
blockchain.rpc.getTxsBySender(addresses.value.account).then(x => {
|
||||
console.log("txs", x)
|
||||
txs.value = x
|
||||
})
|
||||
blockchain.rpc.getTxsBySender(addresses.value.account).then((x) => {
|
||||
console.log('txs', x);
|
||||
txs.value = x;
|
||||
});
|
||||
|
||||
const apr = computed(()=> {
|
||||
const rate = v.value.commission?.commission_rates.rate || 0
|
||||
const inflation = useMintStore().inflation
|
||||
if(Number(inflation)) {
|
||||
return format.percent((1 - Number(rate)) * Number(inflation))
|
||||
}
|
||||
return "-"
|
||||
})
|
||||
const apr = computed(() => {
|
||||
const rate = v.value.commission?.commission_rates.rate || 0;
|
||||
const inflation = useMintStore().inflation;
|
||||
if (Number(inflation)) {
|
||||
return format.percent((1 - Number(rate)) * Number(inflation));
|
||||
}
|
||||
return '-';
|
||||
});
|
||||
|
||||
const selfRate = computed(()=> {
|
||||
if(selfBonded.value.balance?.amount) {
|
||||
return format.calculatePercent(selfBonded.value.balance.amount, v.value.tokens)
|
||||
}
|
||||
return "-"
|
||||
})
|
||||
const selfRate = computed(() => {
|
||||
if (selfBonded.value.balance?.amount) {
|
||||
return format.calculatePercent(
|
||||
selfBonded.value.balance.amount,
|
||||
v.value.tokens
|
||||
);
|
||||
}
|
||||
return '-';
|
||||
});
|
||||
|
||||
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("https://s3.amazonaws.com/keybase_processed_uploads/", "")
|
||||
if(uri) {
|
||||
avatars.value[identity.value] = uri
|
||||
localStorage.setItem('avatars', JSON.stringify(avatars.value))
|
||||
}
|
||||
}
|
||||
})
|
||||
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(
|
||||
'https://s3.amazonaws.com/keybase_processed_uploads/',
|
||||
''
|
||||
);
|
||||
if (uri) {
|
||||
avatars.value[identity.value] = uri;
|
||||
localStorage.setItem('avatars', JSON.stringify(avatars.value));
|
||||
}
|
||||
const prefix = valoperToPrefix(v.value.operator_address) || '<Invalid>'
|
||||
addresses.value.hex = consensusPubkeyToHexAddress(v.value.consensus_pubkey)
|
||||
addresses.value.valCons = pubKeyToValcons(v.value.consensus_pubkey, prefix)
|
||||
})
|
||||
blockchain.rpc.getDistributionValidatorOutstandingRewards(validator).then(res => {
|
||||
rewards.value = res.rewards?.rewards?.sort((a, b) => Number(b.amount) - Number(a.amount))
|
||||
res.rewards?.rewards?.forEach(x => {
|
||||
if(x.denom.startsWith("ibc/")) {
|
||||
format.fetchDenomTrace(x.denom)
|
||||
}
|
||||
})
|
||||
})
|
||||
blockchain.rpc.getDistributionValidatorCommission(validator).then(res => {
|
||||
commission.value = res.commission?.commission?.sort((a, b) => Number(b.amount) - Number(a.amount))
|
||||
res.commission?.commission?.forEach(x => {
|
||||
if(x.denom.startsWith("ibc/")) {
|
||||
format.fetchDenomTrace(x.denom)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
const prefix = valoperToPrefix(v.value.operator_address) || '<Invalid>';
|
||||
addresses.value.hex = consensusPubkeyToHexAddress(
|
||||
v.value.consensus_pubkey
|
||||
);
|
||||
addresses.value.valCons = pubKeyToValcons(
|
||||
v.value.consensus_pubkey,
|
||||
prefix
|
||||
);
|
||||
});
|
||||
blockchain.rpc
|
||||
.getDistributionValidatorOutstandingRewards(validator)
|
||||
.then((res) => {
|
||||
rewards.value = res.rewards?.rewards?.sort(
|
||||
(a, b) => Number(b.amount) - Number(a.amount)
|
||||
);
|
||||
res.rewards?.rewards?.forEach((x) => {
|
||||
if (x.denom.startsWith('ibc/')) {
|
||||
format.fetchDenomTrace(x.denom);
|
||||
}
|
||||
});
|
||||
});
|
||||
blockchain.rpc.getDistributionValidatorCommission(validator).then((res) => {
|
||||
commission.value = res.commission?.commission?.sort(
|
||||
(a, b) => Number(b.amount) - Number(a.amount)
|
||||
);
|
||||
res.commission?.commission?.forEach((x) => {
|
||||
if (x.denom.startsWith('ibc/')) {
|
||||
format.fetchDenomTrace(x.denom);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<div>
|
||||
<VCard class="card-box">
|
||||
<VCardItem>
|
||||
<VRow>
|
||||
<VCol cols="12" md="6">
|
||||
<div class="d-flex pl-2">
|
||||
<VAvatar icon="mdi-help-circle-outline" :image="avatars[identity]" size="90" rounded variant="outlined" color="secondary"/>
|
||||
<div class="mx-2">
|
||||
<h4>{{ v.description?.moniker }}</h4>
|
||||
<div class="text-sm mb-2">{{ v.description?.identity || '-'}}</div>
|
||||
<VBtn>Delegate</VBtn>
|
||||
</div>
|
||||
</div>
|
||||
<VSpacer/>
|
||||
<VCardText>
|
||||
<p class="text-md">
|
||||
About Us
|
||||
</p>
|
||||
<VList class="card-list">
|
||||
<VListItem prepend-icon="mdi-web">
|
||||
<span>Website: </span><span> {{ v.description?.website || '-' }}</span>
|
||||
</VListItem>
|
||||
<VListItem prepend-icon="mdi-email-outline">
|
||||
<span>Contact: </span><span> {{ v.description?.security_contact }}</span>
|
||||
</VListItem>
|
||||
</VList>
|
||||
|
||||
<p class="text-md mt-3">
|
||||
Validator Status
|
||||
</p>
|
||||
<VList class="card-list">
|
||||
<VListItem prepend-icon="mdi-shield-account-outline">
|
||||
<span>Status: </span><span> {{ String(v.status).replace('BOND_STATUS_', '') }} </span>
|
||||
</VListItem>
|
||||
<VListItem prepend-icon="mdi-shield-alert-outline">
|
||||
<span>Jailed: </span><span> {{ v.jailed || '-' }} </span>
|
||||
</VListItem>
|
||||
</VList>
|
||||
</VCardText>
|
||||
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
<div class="d-flex flex-column py-3 justify-space-between">
|
||||
<div class="d-flex">
|
||||
<VAvatar color="secondary" rounded variant="outlined" icon="mdi-coin"></VAvatar>
|
||||
<div class="ml-3 d-flex flex-column justify-center">
|
||||
<h4>{{ format.formatToken2({amount: v.tokens, denom: staking.params.bond_denom}) }}</h4>
|
||||
<span class="text-sm">Total Bonded Tokens</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex">
|
||||
<VAvatar color="secondary" rounded variant="outlined" icon="mdi-percent"></VAvatar>
|
||||
<div class="ml-3 d-flex flex-column justify-center">
|
||||
<h4>{{ format.formatToken(selfBonded.balance) }} ({{ selfRate }})</h4>
|
||||
<span class="text-sm">Self Bonded</span>
|
||||
</div>
|
||||
</div>
|
||||
<VCardItem>
|
||||
<VRow>
|
||||
<VCol cols="12" md="6">
|
||||
<div class="d-flex pl-2">
|
||||
<VAvatar
|
||||
icon="mdi-help-circle-outline"
|
||||
:image="avatars[identity]"
|
||||
size="90"
|
||||
rounded
|
||||
variant="outlined"
|
||||
color="secondary"
|
||||
/>
|
||||
<div class="mx-2">
|
||||
<h4>{{ v.description?.moniker }}</h4>
|
||||
<div class="text-sm mb-2">
|
||||
{{ v.description?.identity || '-' }}
|
||||
</div>
|
||||
<VBtn>Delegate</VBtn>
|
||||
</div>
|
||||
</div>
|
||||
<VSpacer />
|
||||
<VCardText>
|
||||
<p class="text-md">About Us</p>
|
||||
<VList class="card-list">
|
||||
<VListItem prepend-icon="mdi-web">
|
||||
<span>Website: </span
|
||||
><span> {{ v.description?.website || '-' }}</span>
|
||||
</VListItem>
|
||||
<VListItem prepend-icon="mdi-email-outline">
|
||||
<span>Contact: </span
|
||||
><span> {{ v.description?.security_contact }}</span>
|
||||
</VListItem>
|
||||
</VList>
|
||||
|
||||
<div class="d-flex">
|
||||
<VAvatar color="secondary" rounded variant="outlined" icon="mdi-account-tie"></VAvatar>
|
||||
<div class="ml-3 d-flex flex-column justify-center">
|
||||
<h4>{{ v.min_self_delegation }} {{ staking.params.bond_denom }}</h4>
|
||||
<span class="text-sm">Min Self Delegation:</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex">
|
||||
<VAvatar color="secondary" rounded variant="outlined" icon="mdi-finance"></VAvatar>
|
||||
<div class="ml-3 d-flex flex-column justify-center">
|
||||
<h4>{{ apr }}</h4>
|
||||
<span class="text-sm">Annual Profit</span>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-md mt-3">Validator Status</p>
|
||||
<VList class="card-list">
|
||||
<VListItem prepend-icon="mdi-shield-account-outline">
|
||||
<span>Status: </span
|
||||
><span>
|
||||
{{ String(v.status).replace('BOND_STATUS_', '') }}
|
||||
</span>
|
||||
</VListItem>
|
||||
<VListItem prepend-icon="mdi-shield-alert-outline">
|
||||
<span>Jailed: </span><span> {{ v.jailed || '-' }} </span>
|
||||
</VListItem>
|
||||
</VList>
|
||||
</VCardText>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
<div class="d-flex flex-column py-3 justify-space-between">
|
||||
<div class="d-flex">
|
||||
<VAvatar
|
||||
color="secondary"
|
||||
rounded
|
||||
variant="outlined"
|
||||
icon="mdi-coin"
|
||||
></VAvatar>
|
||||
<div class="ml-3 d-flex flex-column justify-center">
|
||||
<h4>
|
||||
{{
|
||||
format.formatToken2({
|
||||
amount: v.tokens,
|
||||
denom: staking.params.bond_denom,
|
||||
})
|
||||
}}
|
||||
</h4>
|
||||
<span class="text-sm">Total Bonded Tokens</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex">
|
||||
<VAvatar
|
||||
color="secondary"
|
||||
rounded
|
||||
variant="outlined"
|
||||
icon="mdi-percent"
|
||||
></VAvatar>
|
||||
<div class="ml-3 d-flex flex-column justify-center">
|
||||
<h4>
|
||||
{{ format.formatToken(selfBonded.balance) }} ({{
|
||||
selfRate
|
||||
}})
|
||||
</h4>
|
||||
<span class="text-sm">Self Bonded</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex">
|
||||
<VAvatar color="secondary" rounded variant="outlined" icon="mdi-stairs-up"></VAvatar>
|
||||
<div class="ml-3 d-flex flex-column justify-center">
|
||||
<h4>{{ v.unbonding_height }}</h4>
|
||||
<span class="text-sm">Unbonding Height</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex">
|
||||
<VAvatar
|
||||
color="secondary"
|
||||
rounded
|
||||
variant="outlined"
|
||||
icon="mdi-account-tie"
|
||||
></VAvatar>
|
||||
<div class="ml-3 d-flex flex-column justify-center">
|
||||
<h4>
|
||||
{{ v.min_self_delegation }} {{ staking.params.bond_denom }}
|
||||
</h4>
|
||||
<span class="text-sm">Min Self Delegation:</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex">
|
||||
<VAvatar
|
||||
color="secondary"
|
||||
rounded
|
||||
variant="outlined"
|
||||
icon="mdi-finance"
|
||||
></VAvatar>
|
||||
<div class="ml-3 d-flex flex-column justify-center">
|
||||
<h4>{{ apr }}</h4>
|
||||
<span class="text-sm">Annual Profit</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex">
|
||||
<VAvatar color="secondary" rounded variant="outlined" icon="mdi-clock"></VAvatar>
|
||||
<div class="ml-3 d-flex flex-column justify-center">
|
||||
<h4>{{ format.toDay(v.unbonding_time, 'from') }}</h4>
|
||||
<span class="text-sm">Unbonding Time</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</VCol>
|
||||
</VRow>
|
||||
<VDivider />
|
||||
<VCardText>{{ v.description?.details }}</VCardText>
|
||||
</VCardItem>
|
||||
<div class="d-flex">
|
||||
<VAvatar
|
||||
color="secondary"
|
||||
rounded
|
||||
variant="outlined"
|
||||
icon="mdi-stairs-up"
|
||||
></VAvatar>
|
||||
<div class="ml-3 d-flex flex-column justify-center">
|
||||
<h4>{{ v.unbonding_height }}</h4>
|
||||
<span class="text-sm">Unbonding Height</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex">
|
||||
<VAvatar
|
||||
color="secondary"
|
||||
rounded
|
||||
variant="outlined"
|
||||
icon="mdi-clock"
|
||||
></VAvatar>
|
||||
<div class="ml-3 d-flex flex-column justify-center">
|
||||
<h4>{{ format.toDay(v.unbonding_time, 'from') }}</h4>
|
||||
<span class="text-sm">Unbonding Time</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</VCol>
|
||||
</VRow>
|
||||
<VDivider />
|
||||
<VCardText>{{ v.description?.details }}</VCardText>
|
||||
</VCardItem>
|
||||
</VCard>
|
||||
|
||||
<VRow class="mt-3">
|
||||
<VCol md="4" sm="12" class="h-100">
|
||||
<ValidatorCommissionRate :commission="v.commission"></ValidatorCommissionRate>
|
||||
</VCol>
|
||||
<VCol md="4" sm="12">
|
||||
<VCard class="h-100">
|
||||
<VCardTitle>Commissions & Rewards</VCardTitle>
|
||||
<VCardItem class="pt-0 pb-0">
|
||||
<div class="overflow-auto" style="max-height: 280px;">
|
||||
<VCardSubtitle>Commissions <VBtn size="small" class="float-right" variant="text">Withdraw</VBtn></VCardSubtitle>
|
||||
<VDivider class="mb-2"></VDivider>
|
||||
<VChip v-for="(i, k) in commission" :key="`reward-${k}`" color="info" label variant="outlined" class="mr-1 mb-1">
|
||||
{{ format.formatToken2(i) }}
|
||||
</VChip>
|
||||
<VCardSubtitle class="mt-2">Outstanding Rewards</VCardSubtitle>
|
||||
<VDivider class="mb-2"></VDivider>
|
||||
<VChip v-for="(i, k) in rewards" :key="`reward-${k}`" color="success" label variant="outlined" class="mr-1 mb-1">
|
||||
{{ format.formatToken2(i) }}
|
||||
</VChip>
|
||||
</div>
|
||||
</VCardItem>
|
||||
</VCard>
|
||||
</VCol>
|
||||
<VCol md="4" sm="12">
|
||||
<VCard title="Addresses" class="h-100">
|
||||
<VList class="pt-0">
|
||||
<VListItem>
|
||||
<VListItemTitle>Account</VListItemTitle>
|
||||
<VListItemSubtitle class="text-caption text-primary"><RouterLink :to="`/${chain}/account/${addresses.account}`">{{ addresses.account }}</RouterLink></VListItemSubtitle>
|
||||
</VListItem>
|
||||
<VListItem>
|
||||
<VListItemTitle>Operator Address</VListItemTitle>
|
||||
<VListItemSubtitle class="text-caption">{{ v.operator_address }}</VListItemSubtitle>
|
||||
</VListItem>
|
||||
<VListItem>
|
||||
<VListItemTitle>Hex Address</VListItemTitle>
|
||||
<VListItemSubtitle class="text-caption">{{ addresses.hex }}</VListItemSubtitle>
|
||||
</VListItem>
|
||||
<VListItem>
|
||||
<VListItemTitle>Signer Address</VListItemTitle>
|
||||
<VListItemSubtitle class="text-caption">{{ addresses.valCons }}</VListItemSubtitle>
|
||||
</VListItem>
|
||||
</VList>
|
||||
</VCard>
|
||||
</VCol>
|
||||
<VCol md="4" sm="12" class="h-100">
|
||||
<ValidatorCommissionRate
|
||||
:commission="v.commission"
|
||||
></ValidatorCommissionRate>
|
||||
</VCol>
|
||||
<VCol md="4" sm="12">
|
||||
<VCard class="h-100">
|
||||
<VCardTitle>Commissions & Rewards</VCardTitle>
|
||||
<VCardItem class="pt-0 pb-0">
|
||||
<div class="overflow-auto" style="max-height: 280px">
|
||||
<VCardSubtitle
|
||||
>Commissions
|
||||
<VBtn size="small" class="float-right" variant="text"
|
||||
>Withdraw</VBtn
|
||||
></VCardSubtitle
|
||||
>
|
||||
<VDivider class="mb-2"></VDivider>
|
||||
<VChip
|
||||
v-for="(i, k) in commission"
|
||||
:key="`reward-${k}`"
|
||||
color="info"
|
||||
label
|
||||
variant="outlined"
|
||||
class="mr-1 mb-1"
|
||||
>
|
||||
{{ format.formatToken2(i) }}
|
||||
</VChip>
|
||||
<VCardSubtitle class="mt-2">Outstanding Rewards</VCardSubtitle>
|
||||
<VDivider class="mb-2"></VDivider>
|
||||
<VChip
|
||||
v-for="(i, k) in rewards"
|
||||
:key="`reward-${k}`"
|
||||
color="success"
|
||||
label
|
||||
variant="outlined"
|
||||
class="mr-1 mb-1"
|
||||
>
|
||||
{{ format.formatToken2(i) }}
|
||||
</VChip>
|
||||
</div>
|
||||
</VCardItem>
|
||||
</VCard>
|
||||
</VCol>
|
||||
<VCol md="4" sm="12">
|
||||
<VCard title="Addresses" class="h-100">
|
||||
<VList class="pt-0">
|
||||
<VListItem>
|
||||
<VListItemTitle>Account</VListItemTitle>
|
||||
<VListItemSubtitle class="text-caption text-primary"
|
||||
><RouterLink :to="`/${chain}/account/${addresses.account}`">{{
|
||||
addresses.account
|
||||
}}</RouterLink></VListItemSubtitle
|
||||
>
|
||||
</VListItem>
|
||||
<VListItem>
|
||||
<VListItemTitle>Operator Address</VListItemTitle>
|
||||
<VListItemSubtitle class="text-caption">{{
|
||||
v.operator_address
|
||||
}}</VListItemSubtitle>
|
||||
</VListItem>
|
||||
<VListItem>
|
||||
<VListItemTitle>Hex Address</VListItemTitle>
|
||||
<VListItemSubtitle class="text-caption">{{
|
||||
addresses.hex
|
||||
}}</VListItemSubtitle>
|
||||
</VListItem>
|
||||
<VListItem>
|
||||
<VListItemTitle>Signer Address</VListItemTitle>
|
||||
<VListItemSubtitle class="text-caption">{{
|
||||
addresses.valCons
|
||||
}}</VListItemSubtitle>
|
||||
</VListItem>
|
||||
</VList>
|
||||
</VCard>
|
||||
</VCol>
|
||||
</VRow>
|
||||
<VCard title="Transactions" class="mt-5">
|
||||
<VCardItem class="pt-0">
|
||||
<VTable>
|
||||
<thead>
|
||||
<th class="text-left pl-4">Height</th>
|
||||
<th class="text-left pl-4">Hash</th>
|
||||
<th class="text-left pl-4" width="40%">Messages</th>
|
||||
<th class="text-left pl-4">Time</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(item, i) in txs.tx_responses">
|
||||
<td class="text-sm text-primary"><RouterLink :to="`/${props.chain}/block/${item.height}`">{{ item.height }}</RouterLink></td>
|
||||
<td class="text-truncate" style="max-width: 200px;">{{ item.txhash }}</td>
|
||||
<td>
|
||||
{{ format.messages(item.tx.body.messages) }}
|
||||
<VIcon v-if="item.code === 0" icon="mdi-check" color="success"></VIcon>
|
||||
<VIcon v-else icon="mdi-multiply" color="error"></VIcon> </td>
|
||||
<td width="150">{{ format.toDay(item.timestamp,'from') }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</VTable>
|
||||
</VCardItem>
|
||||
<VCardItem class="pt-0">
|
||||
<VTable>
|
||||
<thead>
|
||||
<th class="text-left pl-4">Height</th>
|
||||
<th class="text-left pl-4">Hash</th>
|
||||
<th class="text-left pl-4" width="40%">Messages</th>
|
||||
<th class="text-left pl-4">Time</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(item, i) in txs.tx_responses">
|
||||
<td class="text-sm text-primary">
|
||||
<RouterLink :to="`/${props.chain}/block/${item.height}`">{{
|
||||
item.height
|
||||
}}</RouterLink>
|
||||
</td>
|
||||
<td class="text-truncate" style="max-width: 200px">
|
||||
{{ item.txhash }}
|
||||
</td>
|
||||
<td>
|
||||
{{ format.messages(item.tx.body.messages) }}
|
||||
<VIcon
|
||||
v-if="item.code === 0"
|
||||
icon="mdi-check"
|
||||
color="success"
|
||||
></VIcon>
|
||||
<VIcon v-else icon="mdi-multiply" color="error"></VIcon>
|
||||
</td>
|
||||
<td width="150">{{ format.toDay(item.timestamp, 'from') }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</VTable>
|
||||
</VCardItem>
|
||||
</VCard>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<style>
|
||||
.card-list {
|
||||
--v-card-list-gap: 10px;
|
||||
--v-card-list-gap: 10px;
|
||||
}
|
||||
</style>
|
||||
|
@ -5,76 +5,97 @@ import { fromBase64, toHex } from '@cosmjs/encoding';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { computed } from 'vue';
|
||||
|
||||
const props = defineProps(['hash', 'chain'])
|
||||
const blockchain = useBlockchain()
|
||||
const base = useBaseStore()
|
||||
const nodeInfo = ref({} as NodeInfo)
|
||||
const props = defineProps(['hash', 'chain']);
|
||||
const blockchain = useBlockchain();
|
||||
const base = useBaseStore();
|
||||
const nodeInfo = ref({} as NodeInfo);
|
||||
|
||||
const state = computed(()=> {
|
||||
const rpcs = blockchain.current?.endpoints?.rpc?.map(x => x.address).join(',')
|
||||
return `[statesync]
|
||||
const state = computed(() => {
|
||||
const rpcs = blockchain.current?.endpoints?.rpc
|
||||
?.map((x) => x.address)
|
||||
.join(',');
|
||||
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_hash = "${
|
||||
base.latest.block_id ? toHex(fromBase64(base.latest.block_id?.hash)) : ''
|
||||
}"
|
||||
trust_period = "168h" # 2/3 of unbonding time"
|
||||
`
|
||||
})
|
||||
`;
|
||||
});
|
||||
|
||||
const appName = computed(()=> {
|
||||
return nodeInfo.value.application_version?.app_name || "gaiad"
|
||||
})
|
||||
const appName = computed(() => {
|
||||
return nodeInfo.value.application_version?.app_name || 'gaiad';
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
blockchain.rpc.getBaseNodeInfo().then(x => {
|
||||
console.log('node info', x)
|
||||
nodeInfo.value = x
|
||||
})
|
||||
})
|
||||
|
||||
blockchain.rpc.getBaseNodeInfo().then((x) => {
|
||||
console.log('node info', x);
|
||||
nodeInfo.value = x;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<VCard>
|
||||
<VCardTitle>What's State Sync?</VCardTitle>
|
||||
<VCardText>
|
||||
The Tendermint Core 0.34 release includes support for state sync, which allows a new node to join a network by fetching a snapshot of the application state at a recent height instead of fetching and replaying all historical blocks. This can reduce the time needed to sync with the network from days to minutes. Click <a class="text-primary" href="https://blog.cosmos.network/cosmos-sdk-state-sync-guide-99e4cf43be2f">here</a> for more infomation.
|
||||
</VCardText>
|
||||
</VCard>
|
||||
<div>
|
||||
<VCard>
|
||||
<VCardTitle>What's State Sync?</VCardTitle>
|
||||
<VCardText>
|
||||
The Tendermint Core 0.34 release includes support for state sync, which
|
||||
allows a new node to join a network by fetching a snapshot of the
|
||||
application state at a recent height instead of fetching and replaying
|
||||
all historical blocks. This can reduce the time needed to sync with the
|
||||
network from days to minutes. Click
|
||||
<a
|
||||
class="text-primary"
|
||||
href="https://blog.cosmos.network/cosmos-sdk-state-sync-guide-99e4cf43be2f"
|
||||
>here</a
|
||||
>
|
||||
for more infomation.
|
||||
</VCardText>
|
||||
</VCard>
|
||||
|
||||
<VCard class="my-5">
|
||||
<VCardTitle>Starting New Node From State Sync</VCardTitle>
|
||||
<VCardItem>
|
||||
1. Install Binary ({{ appName }} Version: {{ nodeInfo.application_version?.version || "" }})
|
||||
<br>
|
||||
We need to install the binary first and make sure that the version is the one currently in use on mainnet.
|
||||
<br>
|
||||
2. Enable State Sync<br>
|
||||
We can configure Tendermint to use state sync in $DAEMON_HOME/config/config.toml.
|
||||
<VTextarea auto-grow :model-value="state"></VTextarea>
|
||||
3. Start the daemon: <code>{{ appName }} start</code>
|
||||
<br/>
|
||||
If you are resetting node, run <code>{{ appName }} unsafe-reset-all</code> or <code>{{ appName }} tendermint unsafe-reset-all --home ~/.HOME</code> before you start the daemon.
|
||||
</VCardItem>
|
||||
</VCard>
|
||||
<VCard class="my-5">
|
||||
<VCardTitle>Starting New Node From State Sync</VCardTitle>
|
||||
<VCardItem>
|
||||
1. Install Binary ({{ appName }} Version:
|
||||
{{ nodeInfo.application_version?.version || '' }})
|
||||
<br />
|
||||
We need to install the binary first and make sure that the version is
|
||||
the one currently in use on mainnet.
|
||||
<br />
|
||||
2. Enable State Sync<br />
|
||||
We can configure Tendermint to use state sync in
|
||||
$DAEMON_HOME/config/config.toml.
|
||||
<VTextarea auto-grow :model-value="state"></VTextarea>
|
||||
3. Start the daemon: <code>{{ appName }} start</code>
|
||||
<br />
|
||||
If you are resetting node, run
|
||||
<code>{{ appName }} unsafe-reset-all</code> or
|
||||
<code>{{ appName }} tendermint unsafe-reset-all --home ~/.HOME</code>
|
||||
before you start the daemon.
|
||||
</VCardItem>
|
||||
</VCard>
|
||||
|
||||
<VCard>
|
||||
<VCardTitle>Enable Snapshot For State Sync</VCardTitle>
|
||||
<VCardItem>
|
||||
To make state sync works, we can enable snapshot in $DAEMON_HOME/config/app.toml
|
||||
<VTextarea auto-grow model-value="[state-sync]
|
||||
<VCard>
|
||||
<VCardTitle>Enable Snapshot For State Sync</VCardTitle>
|
||||
<VCardItem>
|
||||
To make state sync works, we can enable snapshot in
|
||||
$DAEMON_HOME/config/app.toml
|
||||
<VTextarea
|
||||
auto-grow
|
||||
model-value="[state-sync]
|
||||
# snapshot-interval specifies the block interval at which local state sync snapshots are
|
||||
# taken (0 to disable). Must be a multiple of pruning-keep-every.
|
||||
snapshot-interval = 1000
|
||||
|
||||
# snapshot-keep-recent specifies the number of recent snapshots to keep and serve (0 to keep all). Each snapshot is about 500MiB
|
||||
snapshot-keep-recent = 2">
|
||||
|
||||
</VTextarea>
|
||||
</VCardItem>
|
||||
</VCard>
|
||||
|
||||
</div>
|
||||
snapshot-keep-recent = 2"
|
||||
>
|
||||
</VTextarea>
|
||||
</VCardItem>
|
||||
</VCard>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<route>
|
||||
@ -83,4 +104,4 @@ snapshot-keep-recent = 2">
|
||||
i18n: 'state-sync'
|
||||
}
|
||||
}
|
||||
</route>
|
||||
</route>
|
||||
|
@ -6,58 +6,99 @@ import type { Tx, TxResponse } from '@/types';
|
||||
import VueJsonPretty from 'vue-json-pretty';
|
||||
import 'vue-json-pretty/lib/styles.css';
|
||||
|
||||
const props = defineProps(['hash', 'chain'])
|
||||
const props = defineProps(['hash', 'chain']);
|
||||
|
||||
const blockchain = useBlockchain()
|
||||
const format = useFormatter()
|
||||
const tx = ref({} as {
|
||||
const blockchain = useBlockchain();
|
||||
const format = useFormatter();
|
||||
const tx = ref(
|
||||
{} as {
|
||||
tx: Tx;
|
||||
tx_response: TxResponse
|
||||
})
|
||||
if(props.hash) {
|
||||
blockchain.rpc.getTx(props.hash).then(x => tx.value = x)
|
||||
tx_response: TxResponse;
|
||||
}
|
||||
);
|
||||
if (props.hash) {
|
||||
blockchain.rpc.getTx(props.hash).then((x) => (tx.value = x));
|
||||
}
|
||||
const messages = computed(() => {
|
||||
return tx.value.tx?.body?.messages||[]
|
||||
})
|
||||
return tx.value.tx?.body?.messages || [];
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<VCard v-if="tx.tx_response" title="Summary">
|
||||
<VCardItem class="pt-0">
|
||||
<VTable>
|
||||
<tbody>
|
||||
<tr><td>Tx Hash</td><td>{{ tx.tx_response.txhash }}</td></tr>
|
||||
<tr><td>Height</td><td><RouterLink :to="`/${props.chain}/block/${tx.tx_response.height}`">{{ tx.tx_response.height }}</RouterLink></td></tr>
|
||||
<tr><td>Status</td><td>
|
||||
<VChip v-if="tx.tx_response.code === 0" color="success">Success</VChip>
|
||||
<span v-else><VChip color="error">Failded</VChip></span>
|
||||
</td></tr>
|
||||
<tr><td>Time</td><td>{{ tx.tx_response.timestamp }} ({{ format.toDay(tx.tx_response.timestamp, "from") }})</td></tr>
|
||||
<tr><td>Gas</td><td>{{ tx.tx_response.gas_used }} / {{ tx.tx_response.gas_wanted }}</td></tr>
|
||||
<tr><td>Fee</td><td>{{ format.formatTokens(tx.tx?.auth_info?.fee?.amount, true, '0,0.[00]') }}</td></tr>
|
||||
<tr><td>Memo</td><td>{{ tx.tx.body.memo }}</td></tr>
|
||||
</tbody>
|
||||
</VTable>
|
||||
</VCardItem>
|
||||
</VCard>
|
||||
<div>
|
||||
<VCard v-if="tx.tx_response" title="Summary">
|
||||
<VCardItem class="pt-0">
|
||||
<VTable>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Tx Hash</td>
|
||||
<td>{{ tx.tx_response.txhash }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Height</td>
|
||||
<td>
|
||||
<RouterLink
|
||||
:to="`/${props.chain}/block/${tx.tx_response.height}`"
|
||||
>{{ tx.tx_response.height }}</RouterLink
|
||||
>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Status</td>
|
||||
<td>
|
||||
<VChip v-if="tx.tx_response.code === 0" color="success"
|
||||
>Success</VChip
|
||||
>
|
||||
<span v-else><VChip color="error">Failded</VChip></span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Time</td>
|
||||
<td>
|
||||
{{ tx.tx_response.timestamp }} ({{
|
||||
format.toDay(tx.tx_response.timestamp, 'from')
|
||||
}})
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Gas</td>
|
||||
<td>
|
||||
{{ tx.tx_response.gas_used }} / {{ tx.tx_response.gas_wanted }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Fee</td>
|
||||
<td>
|
||||
{{
|
||||
format.formatTokens(
|
||||
tx.tx?.auth_info?.fee?.amount,
|
||||
true,
|
||||
'0,0.[00]'
|
||||
)
|
||||
}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Memo</td>
|
||||
<td>{{ tx.tx.body.memo }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</VTable>
|
||||
</VCardItem>
|
||||
</VCard>
|
||||
|
||||
<VCard :title="`Messages: (${messages.length})`" class="my-5">
|
||||
<VCardItem class="pt-0" style="border-top: 2px dotted gray;">
|
||||
<div v-for="(msg, i) in messages">
|
||||
<div><DynamicComponent :value="msg" /></div>
|
||||
</div>
|
||||
<div v-if="messages.length === 0">
|
||||
No messages
|
||||
</div>
|
||||
</VCardItem>
|
||||
</VCard>
|
||||
<VCard :title="`Messages: (${messages.length})`" class="my-5">
|
||||
<VCardItem class="pt-0" style="border-top: 2px dotted gray">
|
||||
<div v-for="(msg, i) in messages">
|
||||
<div><DynamicComponent :value="msg" /></div>
|
||||
</div>
|
||||
<div v-if="messages.length === 0">No messages</div>
|
||||
</VCardItem>
|
||||
</VCard>
|
||||
|
||||
<VCard title="JSON">
|
||||
<VCardItem class="pt-0">
|
||||
<vue-json-pretty :data="tx" :deep="3"/>
|
||||
</VCardItem>
|
||||
</VCard>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
<VCard title="JSON">
|
||||
<VCardItem class="pt-0">
|
||||
<vue-json-pretty :data="tx" :deep="3" />
|
||||
</VCardItem>
|
||||
</VCard>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -1,107 +1,162 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted, computed, watchEffect } from 'vue';
|
||||
import { fromHex, toBase64 } from '@cosmjs/encoding'
|
||||
import { useFormatter, useStakingStore, useBaseStore, useBlockchain } from '@/stores';
|
||||
import { fromHex, toBase64 } from '@cosmjs/encoding';
|
||||
import {
|
||||
useFormatter,
|
||||
useStakingStore,
|
||||
useBaseStore,
|
||||
useBlockchain,
|
||||
} from '@/stores';
|
||||
import UptimeBar from '@/components/UptimeBar.vue';
|
||||
import type { Block, Commit } from '@/types'
|
||||
import { consensusPubkeyToHexAddress, valconsToBase64 } from "@/libs";
|
||||
import type { Block, Commit } from '@/types';
|
||||
import { consensusPubkeyToHexAddress, valconsToBase64 } from '@/libs';
|
||||
import type { SigningInfo } from '@/types/slashing';
|
||||
|
||||
const props = defineProps(['chain'])
|
||||
const props = defineProps(['chain']);
|
||||
|
||||
const stakingStore = useStakingStore();
|
||||
const baseStore = useBaseStore();
|
||||
const chainStore = useBlockchain()
|
||||
const latest = ref({} as Block)
|
||||
const chainStore = useBlockchain();
|
||||
const latest = ref({} as Block);
|
||||
const commits = ref([] as Commit[]);
|
||||
const keyword = ref("")
|
||||
const keyword = ref('');
|
||||
const live = ref(true);
|
||||
|
||||
// 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 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>)
|
||||
const signingInfo = ref({} as Record<string, SigningInfo>);
|
||||
|
||||
// filter validators by keywords
|
||||
const validators = computed(()=> {
|
||||
if(keyword) return stakingStore.validators.filter(x => x.description.moniker.indexOf(keyword.value) > -1)
|
||||
return stakingStore.validators
|
||||
})
|
||||
const validators = computed(() => {
|
||||
if (keyword)
|
||||
return stakingStore.validators.filter(
|
||||
(x) => x.description.moniker.indexOf(keyword.value) > -1
|
||||
);
|
||||
return stakingStore.validators;
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
live.value = true
|
||||
baseStore.fetchLatest().then(block => {
|
||||
latest.value = block
|
||||
commits.value.unshift(block.block.last_commit)
|
||||
const height = Number(block.block.header?.height|| 0)
|
||||
if(height > 0) {
|
||||
live.value = true;
|
||||
baseStore.fetchLatest().then((block) => {
|
||||
latest.value = block;
|
||||
commits.value.unshift(block.block.last_commit);
|
||||
const height = Number(block.block.header?.height || 0);
|
||||
if (height > 0) {
|
||||
// constructs sequence for loading blocks
|
||||
let promise = Promise.resolve()
|
||||
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) { // 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) {
|
||||
// continue only if the page is living
|
||||
baseStore.fetchBlock(i).then((x) => {
|
||||
commits.value.unshift(x.block.last_commit);
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
}))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
chainStore.rpc.getSlashingSigningInfos().then((x)=> {
|
||||
x.info?.forEach(i => {
|
||||
signingInfo.value[valconsToBase64(i.address)] = i
|
||||
})
|
||||
})
|
||||
})
|
||||
chainStore.rpc.getSlashingSigningInfos().then((x) => {
|
||||
x.info?.forEach((i) => {
|
||||
signingInfo.value[valconsToBase64(i.address)] = i;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
live.value = false
|
||||
})
|
||||
live.value = false;
|
||||
});
|
||||
|
||||
watchEffect(() => {
|
||||
local.value[chainStore.chainName] = selected.value
|
||||
localStorage.setItem("uptime-validators", JSON.stringify(local.value))
|
||||
})
|
||||
|
||||
local.value[chainStore.chainName] = selected.value;
|
||||
localStorage.setItem('uptime-validators', JSON.stringify(local.value));
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<VRow>
|
||||
<VCol cols="12" md="4" >
|
||||
<VCol cols="12" md="4">
|
||||
<VCard class="h-full self-center d-flex p-4">
|
||||
<div class="self-center">Current Height: {{latest.block?.header?.height}} </div>
|
||||
<div class="self-center">
|
||||
Current Height: {{ latest.block?.header?.height }}
|
||||
</div>
|
||||
</VCard>
|
||||
</VCol>
|
||||
<VCol cols="12" md="8" class="">
|
||||
<VTextField v-model="keyword" label="Keywords to filter validators" variant="outlined">
|
||||
<VCol cols="12" md="8" class="">
|
||||
<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>
|
||||
<VBtn
|
||||
><VIcon icon="mdi-star" /><span class="d-none d-md-block"
|
||||
>Favorite</span
|
||||
></VBtn
|
||||
>
|
||||
</template>
|
||||
</VTextField>
|
||||
</VTextField>
|
||||
</VCol>
|
||||
</VRow>
|
||||
|
||||
|
||||
<VRow>
|
||||
<VCol v-for="(v, i) in validators" cols="12" md="3" xl="2" class="py-0">
|
||||
<div class="d-flex justify-between">
|
||||
<VCheckbox v-model="selected" color="warning" :value="v.operator_address">
|
||||
<template v-slot:label>
|
||||
<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>
|
||||
<VCheckbox
|
||||
v-model="selected"
|
||||
color="warning"
|
||||
:value="v.operator_address"
|
||||
>
|
||||
<template v-slot:label>
|
||||
<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>
|
||||
<UptimeBar :blocks="commits" :validator="toBase64(fromHex(consensusPubkeyToHexAddress(v.consensus_pubkey)))" />
|
||||
<UptimeBar
|
||||
:blocks="commits"
|
||||
:validator="
|
||||
toBase64(fromHex(consensusPubkeyToHexAddress(v.consensus_pubkey)))
|
||||
"
|
||||
/>
|
||||
</VCol>
|
||||
</VRow>
|
||||
</VRow>
|
||||
</div>
|
||||
</template>
|
||||
<route>
|
||||
@ -113,7 +168,7 @@ watchEffect(() => {
|
||||
</route>
|
||||
|
||||
<style lang="scss">
|
||||
.v-field--variant-outlined .v-field__outline__notch{
|
||||
.v-field--variant-outlined .v-field__outline__notch {
|
||||
border-width: 0 !important;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
@ -2,14 +2,14 @@
|
||||
import { CosmosRestClient } from '@/libs/client';
|
||||
|
||||
async function tt() {
|
||||
const address = "echelon1uattqtrtv8944qkmh44ll97qjacj6tgrekqzm9"
|
||||
const validator = "echelonvaloper1uattqtrtv8944qkmh44ll97qjacj6tgr2cupk4"
|
||||
const client = new CosmosRestClient("https://api.ech.network")
|
||||
const address = 'echelon1uattqtrtv8944qkmh44ll97qjacj6tgrekqzm9';
|
||||
const validator = 'echelonvaloper1uattqtrtv8944qkmh44ll97qjacj6tgr2cupk4';
|
||||
const client = new CosmosRestClient('https://api.ech.network');
|
||||
let response = await client.getBaseBlockLatest();
|
||||
console.log('response:', response)
|
||||
console.log('response:', response);
|
||||
}
|
||||
tt()
|
||||
tt();
|
||||
</script>
|
||||
<template>
|
||||
<div>Hello wallet</div>
|
||||
</template>
|
||||
</template>
|
||||
|
@ -1,35 +1,50 @@
|
||||
<script setup lang="ts">
|
||||
import misc404 from '@images/pages/404.png'
|
||||
import misc404 from '@images/pages/404.png';
|
||||
|
||||
import miscObj from '@images/pages/misc-404-object.png'
|
||||
import miscMaskDark from '@images/pages/misc-mask-dark.png'
|
||||
import miscMaskLight from '@images/pages/misc-mask-light.png'
|
||||
import miscObj from '@images/pages/misc-404-object.png';
|
||||
import miscMaskDark from '@images/pages/misc-mask-dark.png';
|
||||
import miscMaskLight from '@images/pages/misc-mask-light.png';
|
||||
|
||||
import { useGenerateImageVariant } from '@/plugins/vuetify/@core/composable/useGenerateImageVariant'
|
||||
import { useGenerateImageVariant } from '@/plugins/vuetify/@core/composable/useGenerateImageVariant';
|
||||
|
||||
const miscThemeMask = useGenerateImageVariant(miscMaskLight, miscMaskDark)
|
||||
const miscThemeMask = useGenerateImageVariant(miscMaskLight, miscMaskDark);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="misc-wrapper">
|
||||
<ErrorHeader error-code="404" error-title="Page Not Found ⚠️"
|
||||
error-description="We couldn't find the page you are looking for." />
|
||||
<ErrorHeader
|
||||
error-code="404"
|
||||
error-title="Page Not Found ⚠️"
|
||||
error-description="We couldn't find the page you are looking for."
|
||||
/>
|
||||
|
||||
<!-- 👉 Image -->
|
||||
<div class="misc-avatar w-100 text-center">
|
||||
<VImg :src="misc404" alt="Coming Soon" :height="$vuetify.display.xs ? 400 : 500" class="my-sm-4" />
|
||||
<VBtn to="/" class="mt-10">
|
||||
Back to Home
|
||||
</VBtn>
|
||||
<VImg :src="miscThemeMask" class="d-none d-md-block footer-coming-soon" cover />
|
||||
<VImg
|
||||
:src="misc404"
|
||||
alt="Coming Soon"
|
||||
:height="$vuetify.display.xs ? 400 : 500"
|
||||
class="my-sm-4"
|
||||
/>
|
||||
<VBtn to="/" class="mt-10"> Back to Home </VBtn>
|
||||
<VImg
|
||||
:src="miscThemeMask"
|
||||
class="d-none d-md-block footer-coming-soon"
|
||||
cover
|
||||
/>
|
||||
|
||||
<VImg :src="miscObj" class="d-none d-md-block footer-coming-soon-obj" :max-width="174" height="158" />
|
||||
<VImg
|
||||
:src="miscObj"
|
||||
class="d-none d-md-block footer-coming-soon-obj"
|
||||
:max-width="174"
|
||||
height="158"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@use "@core/scss/template/pages/misc.scss";
|
||||
@use '@core/scss/template/pages/misc.scss';
|
||||
</style>
|
||||
|
||||
<route lang="yaml">
|
||||
|
@ -4,15 +4,14 @@
|
||||
<VCardText>This is your second page.</VCardText>
|
||||
<VCardText>
|
||||
Chocolate sesame snaps pie carrot cake pastry pie lollipop muffin.
|
||||
Carrot cake dragée chupa chups jujubes. Macaroon liquorice cookie
|
||||
wafer tart marzipan bonbon. Gingerbread jelly-o dragée
|
||||
chocolate.
|
||||
Carrot cake dragée chupa chups jujubes. Macaroon liquorice cookie wafer
|
||||
tart marzipan bonbon. Gingerbread jelly-o dragée chocolate.
|
||||
</VCardText>
|
||||
</VCard>
|
||||
</div>
|
||||
</template>
|
||||
<route lang="yaml">
|
||||
meta:
|
||||
layout: blank
|
||||
bgColor: yellow
|
||||
</route>
|
||||
meta:
|
||||
layout: blank
|
||||
bgColor: yellow
|
||||
</route>
|
||||
|
@ -1,15 +1,15 @@
|
||||
import { createI18n } from 'vue-i18n'
|
||||
import { createI18n } from 'vue-i18n';
|
||||
|
||||
const messages = Object.fromEntries(
|
||||
Object.entries(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
import.meta.glob<{ default: any }>('./locales/*.json', { eager: true }))
|
||||
.map(([key, value]) => [key.slice(10, -5), value.default]),
|
||||
)
|
||||
import.meta.glob<{ default: any }>('./locales/*.json', { eager: true })
|
||||
).map(([key, value]) => [key.slice(10, -5), value.default])
|
||||
);
|
||||
|
||||
export default createI18n({
|
||||
legacy: false,
|
||||
locale: localStorage.getItem('lang') || 'en',
|
||||
fallbackLocale: 'en',
|
||||
messages,
|
||||
})
|
||||
});
|
||||
|
@ -1,11 +1,11 @@
|
||||
import type { CosmosRestClient } from '@/libs/client'
|
||||
import 'pinia'
|
||||
import type { Ref } from 'vue'
|
||||
import type { CosmosRestClient } from '@/libs/client';
|
||||
import 'pinia';
|
||||
import type { Ref } from 'vue';
|
||||
|
||||
declare module 'pinia' {
|
||||
export interface PiniaCustomProperties {
|
||||
// by using a setter we can allow both strings and refs
|
||||
set rpc(value: CosmosRestClient | Ref<CosmosRestClient>)
|
||||
get rpc(): CosmosRestClient
|
||||
set rpc(value: CosmosRestClient | Ref<CosmosRestClient>);
|
||||
get rpc(): CosmosRestClient;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
export * from './useBankStore'
|
||||
export * from './useBlockchain'
|
||||
export * from './useCoinGecko'
|
||||
export * from './useDashboard'
|
||||
export * from './useBaseStore'
|
||||
export * from './useFormatter'
|
||||
export * from './useGovStore'
|
||||
export * from './useMintStore'
|
||||
export * from './useStakingStore'
|
||||
export * from './useDistributionStore'
|
||||
export * from './useParamsStore'
|
||||
export * from './useWalletStore'
|
||||
export * from './useBankStore';
|
||||
export * from './useBlockchain';
|
||||
export * from './useCoinGecko';
|
||||
export * from './useDashboard';
|
||||
export * from './useBaseStore';
|
||||
export * from './useFormatter';
|
||||
export * from './useGovStore';
|
||||
export * from './useMintStore';
|
||||
export * from './useStakingStore';
|
||||
export * from './useDistributionStore';
|
||||
export * from './useParamsStore';
|
||||
export * from './useWalletStore';
|
||||
|
@ -1,13 +1,9 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { defineStore } from 'pinia';
|
||||
|
||||
export const useStoreName = defineStore('bankstore', {
|
||||
state: () => {
|
||||
return {
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
|
||||
},
|
||||
actions: {
|
||||
}
|
||||
})
|
||||
state: () => {
|
||||
return {};
|
||||
},
|
||||
getters: {},
|
||||
actions: {},
|
||||
});
|
||||
|
@ -1,48 +1,50 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { defineStore } from 'pinia';
|
||||
|
||||
import { useBlockchain } from "./useBlockchain";
|
||||
import { useStakingStore } from "./useStakingStore";
|
||||
import type { Coin, DenomTrace } from "@/types";
|
||||
import { useBlockchain } from './useBlockchain';
|
||||
import { useStakingStore } from './useStakingStore';
|
||||
import type { Coin, DenomTrace } from '@/types';
|
||||
|
||||
export const useBankStore = defineStore('bankstore', {
|
||||
state: () => {
|
||||
return {
|
||||
supply: {} as Coin,
|
||||
balances: {} as Record<string, Coin[]>,
|
||||
totalSupply: {supply: [] as Coin[]} ,
|
||||
}
|
||||
state: () => {
|
||||
return {
|
||||
supply: {} as Coin,
|
||||
balances: {} as Record<string, Coin[]>,
|
||||
totalSupply: { supply: [] as Coin[] },
|
||||
};
|
||||
},
|
||||
getters: {
|
||||
blockchain() {
|
||||
return useBlockchain();
|
||||
},
|
||||
getters: {
|
||||
blockchain() {
|
||||
return useBlockchain()
|
||||
},
|
||||
staking() {
|
||||
return useStakingStore()
|
||||
}
|
||||
staking() {
|
||||
return useStakingStore();
|
||||
},
|
||||
actions: {
|
||||
initial() {
|
||||
this.$reset()
|
||||
this.supply = {} as Coin
|
||||
const denom = this.staking.params.bond_denom || this.blockchain.current?.assets[0].base
|
||||
if(denom) {
|
||||
this.blockchain.rpc.getBankSupplyByDenom(denom).then(res => {
|
||||
if(res.amount) this.supply = res.amount
|
||||
})
|
||||
}
|
||||
},
|
||||
async fetchSupply(denom: string) {
|
||||
return this.blockchain.rpc.getBankSupplyByDenom( denom )
|
||||
},
|
||||
async fetchDenomTrace(denom: string) {
|
||||
const hash = denom.replace("ibc/", "")
|
||||
let trace = this.ibcDenoms[hash]
|
||||
if(!trace) {
|
||||
trace = (await this.blockchain.rpc.getIBCAppTransferDenom( hash )).denom_trace
|
||||
this.ibcDenoms[hash] = trace
|
||||
}
|
||||
return trace
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
},
|
||||
actions: {
|
||||
initial() {
|
||||
this.$reset();
|
||||
this.supply = {} as Coin;
|
||||
const denom =
|
||||
this.staking.params.bond_denom ||
|
||||
this.blockchain.current?.assets[0].base;
|
||||
if (denom) {
|
||||
this.blockchain.rpc.getBankSupplyByDenom(denom).then((res) => {
|
||||
if (res.amount) this.supply = res.amount;
|
||||
});
|
||||
}
|
||||
},
|
||||
async fetchSupply(denom: string) {
|
||||
return this.blockchain.rpc.getBankSupplyByDenom(denom);
|
||||
},
|
||||
async fetchDenomTrace(denom: string) {
|
||||
const hash = denom.replace('ibc/', '');
|
||||
let trace = this.ibcDenoms[hash];
|
||||
if (!trace) {
|
||||
trace = (await this.blockchain.rpc.getIBCAppTransferDenom(hash))
|
||||
.denom_trace;
|
||||
this.ibcDenoms[hash] = trace;
|
||||
}
|
||||
return trace;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -1,65 +1,74 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { useBlockchain } from "@/stores";
|
||||
import dayjs from "dayjs";
|
||||
import type { Block } from "@/types";
|
||||
import { defineStore } from 'pinia';
|
||||
import { useBlockchain } from '@/stores';
|
||||
import dayjs from 'dayjs';
|
||||
import type { Block } from '@/types';
|
||||
|
||||
export const useBaseStore = defineStore('baseStore', {
|
||||
state: () => {
|
||||
return {
|
||||
earlest: {} as Block,
|
||||
latest: {} as Block,
|
||||
recents: [] as Block[]
|
||||
state: () => {
|
||||
return {
|
||||
earlest: {} as Block,
|
||||
latest: {} as Block,
|
||||
recents: [] as Block[],
|
||||
};
|
||||
},
|
||||
getters: {
|
||||
blocktime(): number {
|
||||
if (this.earlest && this.latest) {
|
||||
if (
|
||||
this.latest.block?.header?.height !==
|
||||
this.earlest.block?.header?.height
|
||||
) {
|
||||
const diff = dayjs(this.latest.block?.header?.time).diff(
|
||||
this.earlest.block?.header?.time
|
||||
);
|
||||
return diff;
|
||||
}
|
||||
}
|
||||
return 6000;
|
||||
},
|
||||
getters: {
|
||||
blocktime(): number {
|
||||
if(this.earlest && this.latest) {
|
||||
if(this.latest.block?.header?.height !== this.earlest.block?.header?.height) {
|
||||
const diff = dayjs(this.latest.block?.header?.time).diff(this.earlest.block?.header?.time)
|
||||
return diff
|
||||
}
|
||||
}
|
||||
return 6000
|
||||
},
|
||||
blockchain() {
|
||||
return useBlockchain()
|
||||
}
|
||||
blockchain() {
|
||||
return useBlockchain();
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
async initial() {
|
||||
this.fetchLatest();
|
||||
},
|
||||
async clearRecentBlocks() {
|
||||
this.recents = [];
|
||||
},
|
||||
async fetchLatest() {
|
||||
this.latest = await this.blockchain.rpc.getBaseBlockLatest();
|
||||
if (
|
||||
!this.earlest ||
|
||||
this.earlest.block?.header?.chain_id !=
|
||||
this.latest.block?.header?.chain_id
|
||||
) {
|
||||
//reset earlest and recents
|
||||
this.earlest = this.latest;
|
||||
this.recents = [];
|
||||
}
|
||||
if (this.recents.length >= 50) {
|
||||
this.recents.pop();
|
||||
}
|
||||
this.recents.push(this.latest);
|
||||
return this.latest;
|
||||
},
|
||||
actions: {
|
||||
async initial() {
|
||||
this.fetchLatest()
|
||||
},
|
||||
async clearRecentBlocks() {
|
||||
this.recents = []
|
||||
},
|
||||
async fetchLatest() {
|
||||
this.latest = await this.blockchain.rpc.getBaseBlockLatest()
|
||||
if(!this.earlest || this.earlest.block?.header?.chain_id != this.latest.block?.header?.chain_id) {
|
||||
//reset earlest and recents
|
||||
this.earlest = this.latest
|
||||
this.recents = []
|
||||
}
|
||||
if(this.recents.length>= 50) {
|
||||
this.recents.pop()
|
||||
}
|
||||
this.recents.push(this.latest)
|
||||
return this.latest
|
||||
},
|
||||
|
||||
async fetchValidatorByHeight(height?: number, offset = 0) {
|
||||
return this.blockchain.rpc.getBaseValidatorsetAt(String(height))
|
||||
},
|
||||
async fetchLatestValidators(offset = 0) {
|
||||
return this.blockchain.rpc.getBaseValidatorsetLatest()
|
||||
},
|
||||
async fetchBlock(height?: number) {
|
||||
return this.blockchain.rpc.getBaseBlockAt(String(height))
|
||||
},
|
||||
async fetchAbciInfo() {
|
||||
return this.blockchain.rpc.getBaseNodeInfo()
|
||||
}
|
||||
// async fetchNodeInfo() {
|
||||
// return this.blockchain.rpc.no()
|
||||
// }
|
||||
}
|
||||
})
|
||||
async fetchValidatorByHeight(height?: number, offset = 0) {
|
||||
return this.blockchain.rpc.getBaseValidatorsetAt(String(height));
|
||||
},
|
||||
async fetchLatestValidators(offset = 0) {
|
||||
return this.blockchain.rpc.getBaseValidatorsetLatest();
|
||||
},
|
||||
async fetchBlock(height?: number) {
|
||||
return this.blockchain.rpc.getBaseBlockAt(String(height));
|
||||
},
|
||||
async fetchAbciInfo() {
|
||||
return this.blockchain.rpc.getBaseNodeInfo();
|
||||
},
|
||||
// async fetchNodeInfo() {
|
||||
// return this.blockchain.rpc.no()
|
||||
// }
|
||||
},
|
||||
});
|
||||
|
@ -1,51 +1,54 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { get } from '../libs/http'
|
||||
import type { LoadingStatus } from "./useDashboard";
|
||||
import { defineStore } from 'pinia';
|
||||
import { get } from '../libs/http';
|
||||
import type { LoadingStatus } from './useDashboard';
|
||||
|
||||
export interface PriceMeta {
|
||||
usd?: string,
|
||||
usd_24h_change?: string,
|
||||
cny?: string,
|
||||
cny_24h_change? : string,
|
||||
eur?: string,
|
||||
eur_24h_change?: string,
|
||||
usd?: string;
|
||||
usd_24h_change?: string;
|
||||
cny?: string;
|
||||
cny_24h_change?: string;
|
||||
eur?: string;
|
||||
eur_24h_change?: string;
|
||||
}
|
||||
|
||||
const LocalStoreKey = 'currency'
|
||||
const LocalStoreKey = 'currency';
|
||||
|
||||
export const useCoingecko = defineStore('coingecko', {
|
||||
state: () => {
|
||||
const currency = localStorage.getItem(LocalStoreKey)
|
||||
return {
|
||||
currency, // secondary currency
|
||||
loadStatus: {} as Record<string, LoadingStatus | undefined>,
|
||||
prices: {} as Record<string, PriceMeta>,
|
||||
marketChart: {}
|
||||
}
|
||||
state: () => {
|
||||
const currency = localStorage.getItem(LocalStoreKey);
|
||||
return {
|
||||
currency, // secondary currency
|
||||
loadStatus: {} as Record<string, LoadingStatus | undefined>,
|
||||
prices: {} as Record<string, PriceMeta>,
|
||||
marketChart: {},
|
||||
};
|
||||
},
|
||||
getters: {},
|
||||
|
||||
actions: {
|
||||
getMarketChart(days = 30, coinId = 'cosmos') {
|
||||
return get(
|
||||
`https://api.coingecko.com/api/v3/coins/${coinId}/market_chart?vs_currency=usd&days=${days}`
|
||||
);
|
||||
},
|
||||
getters: {
|
||||
|
||||
|
||||
fetchCoinPrice(ids: string[]) {
|
||||
const url = `https://api.coingecko.com/api/v3/simple/price?include_24hr_change=true&vs_currencies=${[
|
||||
'usd',
|
||||
this.currency,
|
||||
].join(',')}&ids=${ids.join(',')}`;
|
||||
get(url).then((data) => {
|
||||
this.prices = { ...this.prices, ...data };
|
||||
});
|
||||
},
|
||||
|
||||
actions: {
|
||||
getMarketChart(days = 30, coinId = 'cosmos') {
|
||||
return get(`https://api.coingecko.com/api/v3/coins/${coinId}/market_chart?vs_currency=usd&days=${days}`)
|
||||
},
|
||||
|
||||
fetchCoinPrice(ids: string[]) {
|
||||
const url = `https://api.coingecko.com/api/v3/simple/price?include_24hr_change=true&vs_currencies=${['usd', this.currency].join(',')}&ids=${ids.join(',')}`
|
||||
get(url).then(data => {
|
||||
this.prices = {...this.prices, ...data}
|
||||
})
|
||||
},
|
||||
getCoinInfo(coinId: string) {
|
||||
return get(`https://api.coingecko.com/api/v3/coins/${coinId}`)
|
||||
},
|
||||
setSecondaryCurrency(currency: string) {
|
||||
if(currency !== 'usd') {
|
||||
localStorage.setItem(LocalStoreKey, currency)
|
||||
this.currency = currency
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
getCoinInfo(coinId: string) {
|
||||
return get(`https://api.coingecko.com/api/v3/coins/${coinId}`);
|
||||
},
|
||||
setSecondaryCurrency(currency: string) {
|
||||
if (currency !== 'usd') {
|
||||
localStorage.setItem(LocalStoreKey, currency);
|
||||
this.currency = currency;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -1,19 +1,18 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { useBlockchain } from "./useBlockchain";
|
||||
import { defineStore } from 'pinia';
|
||||
import { useBlockchain } from './useBlockchain';
|
||||
|
||||
export const useDistributionStore = defineStore('distributionStore', {
|
||||
state: () => {
|
||||
return {
|
||||
}
|
||||
state: () => {
|
||||
return {};
|
||||
},
|
||||
getters: {
|
||||
blockchain() {
|
||||
return useBlockchain();
|
||||
},
|
||||
getters: {
|
||||
blockchain() {
|
||||
return useBlockchain()
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
async fetchCommunityPool() {
|
||||
return this.blockchain.rpc.getDistributionCommunityPool();
|
||||
},
|
||||
actions: {
|
||||
async fetchCommunityPool() {
|
||||
return this.blockchain.rpc.getDistributionCommunityPool()
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
});
|
||||
|
@ -1,23 +1,23 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { useBlockchain } from "./useBlockchain";
|
||||
import numeral from "numeral";
|
||||
import { defineStore } from 'pinia';
|
||||
import { useBlockchain } from './useBlockchain';
|
||||
import numeral from 'numeral';
|
||||
import dayjs from 'dayjs';
|
||||
import duration from 'dayjs/plugin/duration'
|
||||
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||
import updateLocale from 'dayjs/plugin/updateLocale'
|
||||
import utc from 'dayjs/plugin/utc'
|
||||
import localeData from 'dayjs/plugin/localeData'
|
||||
import { useStakingStore } from "./useStakingStore";
|
||||
import { fromBase64, fromBech32, fromHex, toHex } from "@cosmjs/encoding";
|
||||
import { consensusPubkeyToHexAddress } from "@/libs";
|
||||
import { useBankStore } from "./useBankStore";
|
||||
import type { DenomTrace } from "@/types";
|
||||
import duration from 'dayjs/plugin/duration';
|
||||
import relativeTime from 'dayjs/plugin/relativeTime';
|
||||
import updateLocale from 'dayjs/plugin/updateLocale';
|
||||
import utc from 'dayjs/plugin/utc';
|
||||
import localeData from 'dayjs/plugin/localeData';
|
||||
import { useStakingStore } from './useStakingStore';
|
||||
import { fromBase64, fromBech32, fromHex, toHex } from '@cosmjs/encoding';
|
||||
import { consensusPubkeyToHexAddress } from '@/libs';
|
||||
import { useBankStore } from './useBankStore';
|
||||
import type { DenomTrace } from '@/types';
|
||||
|
||||
dayjs.extend(localeData)
|
||||
dayjs.extend(duration)
|
||||
dayjs.extend(relativeTime)
|
||||
dayjs.extend(updateLocale)
|
||||
dayjs.extend(utc)
|
||||
dayjs.extend(localeData);
|
||||
dayjs.extend(duration);
|
||||
dayjs.extend(relativeTime);
|
||||
dayjs.extend(updateLocale);
|
||||
dayjs.extend(utc);
|
||||
dayjs.updateLocale('en', {
|
||||
relativeTime: {
|
||||
future: 'in %s',
|
||||
@ -34,168 +34,190 @@ dayjs.updateLocale('en', {
|
||||
y: 'a year',
|
||||
yy: '%d years',
|
||||
},
|
||||
})
|
||||
});
|
||||
|
||||
export const useFormatter = defineStore('formatter', {
|
||||
state: () => {
|
||||
return {
|
||||
ibcDenoms: {} as Record<string, DenomTrace>
|
||||
}
|
||||
state: () => {
|
||||
return {
|
||||
ibcDenoms: {} as Record<string, DenomTrace>,
|
||||
};
|
||||
},
|
||||
getters: {
|
||||
blockchain() {
|
||||
return useBlockchain();
|
||||
},
|
||||
getters: {
|
||||
blockchain() {
|
||||
return useBlockchain()
|
||||
},
|
||||
staking() {
|
||||
return useStakingStore()
|
||||
},
|
||||
useBank() {
|
||||
return useBankStore()
|
||||
}
|
||||
staking() {
|
||||
return useStakingStore();
|
||||
},
|
||||
actions: {
|
||||
async fetchDenomTrace(denom: string) {
|
||||
const hash = denom.replace("ibc/", "")
|
||||
let trace = this.ibcDenoms[hash]
|
||||
if(!trace) {
|
||||
trace = (await this.blockchain.rpc.getIBCAppTransferDenom( hash )).denom_trace
|
||||
this.ibcDenoms[hash] = trace
|
||||
}
|
||||
return trace
|
||||
},
|
||||
formatTokenAmount(token: {denom: string, amount: string;}) {
|
||||
return this.formatToken(token, false)
|
||||
},
|
||||
formatToken2(token: { denom: string, amount: string;}, withDenom = true) {
|
||||
return this.formatToken(token, true, '0,0.[00]')
|
||||
},
|
||||
formatToken(token: { denom: string, amount: string;}, withDenom = true, fmt='0.0a') : string {
|
||||
if(token && token.amount) {
|
||||
let amount = Number(token.amount)
|
||||
let denom = token.denom
|
||||
useBank() {
|
||||
return useBankStore();
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
async fetchDenomTrace(denom: string) {
|
||||
const hash = denom.replace('ibc/', '');
|
||||
let trace = this.ibcDenoms[hash];
|
||||
if (!trace) {
|
||||
trace = (await this.blockchain.rpc.getIBCAppTransferDenom(hash))
|
||||
.denom_trace;
|
||||
this.ibcDenoms[hash] = trace;
|
||||
}
|
||||
return trace;
|
||||
},
|
||||
formatTokenAmount(token: { denom: string; amount: string }) {
|
||||
return this.formatToken(token, false);
|
||||
},
|
||||
formatToken2(token: { denom: string; amount: string }, withDenom = true) {
|
||||
return this.formatToken(token, true, '0,0.[00]');
|
||||
},
|
||||
formatToken(
|
||||
token: { denom: string; amount: string },
|
||||
withDenom = true,
|
||||
fmt = '0.0a'
|
||||
): string {
|
||||
if (token && token.amount) {
|
||||
let amount = Number(token.amount);
|
||||
let denom = token.denom;
|
||||
|
||||
if( denom && denom.startsWith("ibc/")) {
|
||||
let ibcDenom = this.ibcDenoms[denom.replace("ibc/", "")]
|
||||
if(ibcDenom) {
|
||||
denom = ibcDenom.base_denom
|
||||
}
|
||||
}
|
||||
if (denom && denom.startsWith('ibc/')) {
|
||||
let ibcDenom = this.ibcDenoms[denom.replace('ibc/', '')];
|
||||
if (ibcDenom) {
|
||||
denom = ibcDenom.base_denom;
|
||||
}
|
||||
}
|
||||
|
||||
const conf = this.blockchain.current?.assets?.find(x => x.base === token.denom || x.base.denom === token.denom)
|
||||
if(conf) {
|
||||
let unit = {exponent: 6, denom: ''}
|
||||
// find the max exponent for display
|
||||
conf.denom_units.forEach(x => {
|
||||
if(x.exponent >= unit.exponent) {
|
||||
unit = x
|
||||
}
|
||||
})
|
||||
if(unit && unit.exponent > 0) {
|
||||
amount = amount / Math.pow(10, unit.exponent || 6)
|
||||
denom = unit.denom.toUpperCase()
|
||||
}
|
||||
}
|
||||
return `${numeral(amount).format(fmt)} ${withDenom ? denom.substring(0, 10): ''}`
|
||||
}
|
||||
return '-'
|
||||
},
|
||||
formatTokens(tokens?: { denom: string, amount: string;}[], withDenom = true, fmt='0.0a') : string {
|
||||
if(!tokens) return ''
|
||||
return tokens.map(x => this.formatToken(x, withDenom, fmt)).join(', ')
|
||||
},
|
||||
calculateBondedRatio(pool: {bonded_tokens: string, not_bonded_tokens: string}|undefined) {
|
||||
if(pool && pool.bonded_tokens) {
|
||||
const b = Number(pool.bonded_tokens)
|
||||
const nb = Number(pool.not_bonded_tokens)
|
||||
const p = b/(b+nb)
|
||||
return numeral(p).format('0.[00]%')
|
||||
const conf = this.blockchain.current?.assets?.find(
|
||||
(x) => x.base === token.denom || x.base.denom === token.denom
|
||||
);
|
||||
if (conf) {
|
||||
let unit = { exponent: 6, denom: '' };
|
||||
// find the max exponent for display
|
||||
conf.denom_units.forEach((x) => {
|
||||
if (x.exponent >= unit.exponent) {
|
||||
unit = x;
|
||||
}
|
||||
return '-'
|
||||
},
|
||||
validator(address: string) {
|
||||
if(!address) return address
|
||||
|
||||
const txt = toHex(fromBase64(address)).toUpperCase()
|
||||
const validator = this.staking.validators.find(x => consensusPubkeyToHexAddress(x.consensus_pubkey) === txt)
|
||||
return validator?.description?.moniker
|
||||
},
|
||||
validatorFromBech32(address: string) {
|
||||
if(!address) return address
|
||||
const validator = this.staking.validators.find(x => x.operator_address === address)
|
||||
return validator?.description?.moniker
|
||||
},
|
||||
calculatePercent(input?: string|number, total?: string|number ) {
|
||||
if(!input || !total) return '0'
|
||||
const percent = Number(input)/Number(total)
|
||||
return numeral(percent>0.0001?percent: 0).format("0.[00]%")
|
||||
},
|
||||
formatDecimalToPercent(decimal: string) {
|
||||
return numeral(decimal).format('0.[00]%')
|
||||
},
|
||||
formatCommissionRate(rate?: string) {
|
||||
if(!rate) return '-'
|
||||
return this.percent(rate)
|
||||
},
|
||||
percent(decimal?: string|number) {
|
||||
return decimal ? numeral(decimal).format('0.[00]%') : '-'
|
||||
},
|
||||
numberAndSign(input: number, fmt="+0,0") {
|
||||
return numeral(input).format(fmt)
|
||||
},
|
||||
toDay(time?: string, format = 'long') {
|
||||
if(!time) return ''
|
||||
if (format === 'long') {
|
||||
return dayjs(time).format('YYYY-MM-DD HH:mm')
|
||||
}
|
||||
if (format === 'date') {
|
||||
return dayjs(time).format('YYYY-MM-DD')
|
||||
}
|
||||
if (format === 'time') {
|
||||
return dayjs(time).format('HH:mm:ss')
|
||||
}
|
||||
if (format === 'from') {
|
||||
return dayjs(time).fromNow()
|
||||
}
|
||||
if (format === 'to') {
|
||||
return dayjs(time).toNow()
|
||||
}
|
||||
return dayjs(time).format('YYYY-MM-DD HH:mm:ss')
|
||||
},
|
||||
messages(msgs: {"@type": string}[]) {
|
||||
if(msgs) {
|
||||
const sum: Record<string, number> = msgs.map(msg => {
|
||||
return msg["@type"].substring(msg["@type"].lastIndexOf('.') + 1).replace('Msg', '')
|
||||
}).reduce((s, c) => {
|
||||
const sh: Record<string, number> = s
|
||||
if (sh[c]) {
|
||||
sh[c] += 1
|
||||
} else {
|
||||
sh[c] = 1
|
||||
}
|
||||
return sh
|
||||
}, {})
|
||||
const output: string[] = []
|
||||
Object.keys(sum).forEach(k => {
|
||||
output.push(sum[k] > 1 ? `${k}×${sum[k]}` : k)
|
||||
})
|
||||
return output.join(', ')
|
||||
}
|
||||
},
|
||||
multiLine(v: string) {
|
||||
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 ""
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
if (unit && unit.exponent > 0) {
|
||||
amount = amount / Math.pow(10, unit.exponent || 6);
|
||||
denom = unit.denom.toUpperCase();
|
||||
}
|
||||
}
|
||||
return `${numeral(amount).format(fmt)} ${
|
||||
withDenom ? denom.substring(0, 10) : ''
|
||||
}`;
|
||||
}
|
||||
return '-';
|
||||
},
|
||||
formatTokens(
|
||||
tokens?: { denom: string; amount: string }[],
|
||||
withDenom = true,
|
||||
fmt = '0.0a'
|
||||
): string {
|
||||
if (!tokens) return '';
|
||||
return tokens.map((x) => this.formatToken(x, withDenom, fmt)).join(', ');
|
||||
},
|
||||
calculateBondedRatio(
|
||||
pool: { bonded_tokens: string; not_bonded_tokens: string } | undefined
|
||||
) {
|
||||
if (pool && pool.bonded_tokens) {
|
||||
const b = Number(pool.bonded_tokens);
|
||||
const nb = Number(pool.not_bonded_tokens);
|
||||
const p = b / (b + nb);
|
||||
return numeral(p).format('0.[00]%');
|
||||
}
|
||||
return '-';
|
||||
},
|
||||
validator(address: string) {
|
||||
if (!address) return address;
|
||||
|
||||
const txt = toHex(fromBase64(address)).toUpperCase();
|
||||
const validator = this.staking.validators.find(
|
||||
(x) => consensusPubkeyToHexAddress(x.consensus_pubkey) === txt
|
||||
);
|
||||
return validator?.description?.moniker;
|
||||
},
|
||||
validatorFromBech32(address: string) {
|
||||
if (!address) return address;
|
||||
const validator = this.staking.validators.find(
|
||||
(x) => x.operator_address === address
|
||||
);
|
||||
return validator?.description?.moniker;
|
||||
},
|
||||
calculatePercent(input?: string | number, total?: string | number) {
|
||||
if (!input || !total) return '0';
|
||||
const percent = Number(input) / Number(total);
|
||||
return numeral(percent > 0.0001 ? percent : 0).format('0.[00]%');
|
||||
},
|
||||
formatDecimalToPercent(decimal: string) {
|
||||
return numeral(decimal).format('0.[00]%');
|
||||
},
|
||||
formatCommissionRate(rate?: string) {
|
||||
if (!rate) return '-';
|
||||
return this.percent(rate);
|
||||
},
|
||||
percent(decimal?: string | number) {
|
||||
return decimal ? numeral(decimal).format('0.[00]%') : '-';
|
||||
},
|
||||
numberAndSign(input: number, fmt = '+0,0') {
|
||||
return numeral(input).format(fmt);
|
||||
},
|
||||
toDay(time?: string, format = 'long') {
|
||||
if (!time) return '';
|
||||
if (format === 'long') {
|
||||
return dayjs(time).format('YYYY-MM-DD HH:mm');
|
||||
}
|
||||
if (format === 'date') {
|
||||
return dayjs(time).format('YYYY-MM-DD');
|
||||
}
|
||||
if (format === 'time') {
|
||||
return dayjs(time).format('HH:mm:ss');
|
||||
}
|
||||
if (format === 'from') {
|
||||
return dayjs(time).fromNow();
|
||||
}
|
||||
if (format === 'to') {
|
||||
return dayjs(time).toNow();
|
||||
}
|
||||
return dayjs(time).format('YYYY-MM-DD HH:mm:ss');
|
||||
},
|
||||
messages(msgs: { '@type': string }[]) {
|
||||
if (msgs) {
|
||||
const sum: Record<string, number> = msgs
|
||||
.map((msg) => {
|
||||
return msg['@type']
|
||||
.substring(msg['@type'].lastIndexOf('.') + 1)
|
||||
.replace('Msg', '');
|
||||
})
|
||||
.reduce((s, c) => {
|
||||
const sh: Record<string, number> = s;
|
||||
if (sh[c]) {
|
||||
sh[c] += 1;
|
||||
} else {
|
||||
sh[c] = 1;
|
||||
}
|
||||
return sh;
|
||||
}, {});
|
||||
const output: string[] = [];
|
||||
Object.keys(sum).forEach((k) => {
|
||||
output.push(sum[k] > 1 ? `${k}×${sum[k]}` : k);
|
||||
});
|
||||
return output.join(', ');
|
||||
}
|
||||
},
|
||||
multiLine(v: string) {
|
||||
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 '';
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -1,63 +1,64 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { useBlockchain } from "./useBlockchain";
|
||||
import type { PageRequest, PaginatedProposals } from "@/types";
|
||||
import { LoadingStatus } from "./useDashboard";
|
||||
import {reactive} from 'vue'
|
||||
import { defineStore } from 'pinia';
|
||||
import { useBlockchain } from './useBlockchain';
|
||||
import type { PageRequest, PaginatedProposals } from '@/types';
|
||||
import { LoadingStatus } from './useDashboard';
|
||||
import { reactive } from 'vue';
|
||||
|
||||
export const useGovStore = defineStore('govStore', {
|
||||
state: () => {
|
||||
return {
|
||||
params: {
|
||||
deposit: {},
|
||||
voting: {},
|
||||
tally: {},
|
||||
},
|
||||
proposals: {} as Record<string, PaginatedProposals>,
|
||||
loading: {} as Record<string, LoadingStatus>
|
||||
}
|
||||
state: () => {
|
||||
return {
|
||||
params: {
|
||||
deposit: {},
|
||||
voting: {},
|
||||
tally: {},
|
||||
},
|
||||
proposals: {} as Record<string, PaginatedProposals>,
|
||||
loading: {} as Record<string, LoadingStatus>,
|
||||
};
|
||||
},
|
||||
getters: {
|
||||
blockchain() {
|
||||
return useBlockchain();
|
||||
},
|
||||
getters: {
|
||||
blockchain() {
|
||||
return useBlockchain()
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
initial() {
|
||||
this.fetchParams();
|
||||
},
|
||||
actions: {
|
||||
initial() {
|
||||
this.fetchParams()
|
||||
},
|
||||
async fetchProposals( status: string, pagination?: PageRequest ) {
|
||||
if(!this.loading[status]) {
|
||||
this.loading[status] = LoadingStatus.Loading
|
||||
const proposals = reactive(await this.blockchain.rpc.getGovProposals(status))
|
||||
if(status === '2') {
|
||||
proposals.proposals.forEach(async(x1) => {
|
||||
await this.fetchTally(x1.proposal_id).then(res => {
|
||||
x1.final_tally_result = res?.tally
|
||||
})
|
||||
})
|
||||
}
|
||||
this.loading[status] = LoadingStatus.Loaded
|
||||
this.proposals[status] = proposals
|
||||
}
|
||||
return this.proposals[status]
|
||||
},
|
||||
async fetchParams() {
|
||||
// this.blockchain.rpc.getGovParamsDeposit().then(x => {
|
||||
// this.params.deposit = x.deposit
|
||||
// })
|
||||
},
|
||||
async fetchTally(proposalId: string) {
|
||||
return await this.blockchain.rpc.getGovProposalTally(proposalId)
|
||||
},
|
||||
async fetchProposal(proposalId: string) {
|
||||
return this.blockchain.rpc.getGovProposal(proposalId)
|
||||
},
|
||||
async fetchProposalDeposits(proposalId: string) {
|
||||
return this.blockchain.rpc.getGovProposalDeposits(proposalId)
|
||||
},
|
||||
async fetchProposalVotes(proposalId: string, next_key?: string) {
|
||||
return this.blockchain.rpc.getGovProposalVotes(proposalId, next_key)
|
||||
async fetchProposals(status: string, pagination?: PageRequest) {
|
||||
if (!this.loading[status]) {
|
||||
this.loading[status] = LoadingStatus.Loading;
|
||||
const proposals = reactive(
|
||||
await this.blockchain.rpc.getGovProposals(status)
|
||||
);
|
||||
if (status === '2') {
|
||||
proposals.proposals.forEach(async (x1) => {
|
||||
await this.fetchTally(x1.proposal_id).then((res) => {
|
||||
x1.final_tally_result = res?.tally;
|
||||
});
|
||||
});
|
||||
}
|
||||
this.loading[status] = LoadingStatus.Loaded;
|
||||
this.proposals[status] = proposals;
|
||||
}
|
||||
return this.proposals[status];
|
||||
},
|
||||
|
||||
})
|
||||
async fetchParams() {
|
||||
// this.blockchain.rpc.getGovParamsDeposit().then(x => {
|
||||
// this.params.deposit = x.deposit
|
||||
// })
|
||||
},
|
||||
async fetchTally(proposalId: string) {
|
||||
return await this.blockchain.rpc.getGovProposalTally(proposalId);
|
||||
},
|
||||
async fetchProposal(proposalId: string) {
|
||||
return this.blockchain.rpc.getGovProposal(proposalId);
|
||||
},
|
||||
async fetchProposalDeposits(proposalId: string) {
|
||||
return this.blockchain.rpc.getGovProposalDeposits(proposalId);
|
||||
},
|
||||
async fetchProposalVotes(proposalId: string, next_key?: string) {
|
||||
return this.blockchain.rpc.getGovProposalVotes(proposalId, next_key);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -1,27 +1,30 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { useBlockchain } from "./useBlockchain";
|
||||
import { defineStore } from 'pinia';
|
||||
import { useBlockchain } from './useBlockchain';
|
||||
|
||||
export const useMintStore = defineStore('mintStore', {
|
||||
state: () => {
|
||||
return {
|
||||
inflation: "0",
|
||||
}
|
||||
state: () => {
|
||||
return {
|
||||
inflation: '0',
|
||||
};
|
||||
},
|
||||
getters: {
|
||||
blockchain() {
|
||||
return useBlockchain();
|
||||
},
|
||||
getters: {
|
||||
blockchain() {
|
||||
return useBlockchain()
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
initial() {
|
||||
this.fetchInflation();
|
||||
},
|
||||
actions: {
|
||||
initial() {
|
||||
this.fetchInflation()
|
||||
},
|
||||
async fetchInflation() {
|
||||
this.blockchain.rpc.getMintInflation().then(x => {
|
||||
this.inflation = x.inflation
|
||||
}).catch(() => {
|
||||
this.inflation = "0"
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
async fetchInflation() {
|
||||
this.blockchain.rpc
|
||||
.getMintInflation()
|
||||
.then((x) => {
|
||||
this.inflation = x.inflation;
|
||||
})
|
||||
.catch(() => {
|
||||
this.inflation = '0';
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -1,195 +1,246 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { useBlockchain } from "./useBlockchain";
|
||||
import { percent,formatNumber,formatTokenAmount } from '@/libs/utils'
|
||||
import { defineStore } from 'pinia';
|
||||
import { useBlockchain } from './useBlockchain';
|
||||
import { percent, formatNumber, formatTokenAmount } from '@/libs/utils';
|
||||
export interface stakingItem {
|
||||
unbonding_time: string
|
||||
max_validators: number
|
||||
max_entries:number
|
||||
historical_entries:number
|
||||
bond_denom: string
|
||||
min_commission_rate: string
|
||||
min_self_delegation:string
|
||||
unbonding_time: string;
|
||||
max_validators: number;
|
||||
max_entries: number;
|
||||
historical_entries: number;
|
||||
bond_denom: string;
|
||||
min_commission_rate: string;
|
||||
min_self_delegation: string;
|
||||
}
|
||||
|
||||
export const useParamStore = defineStore("paramstore", {
|
||||
state: () => ({
|
||||
latestTime: '',
|
||||
chain: {
|
||||
title: '',
|
||||
class: 'border-primary',
|
||||
items: [
|
||||
{ subtitle: 'height', icon: 'BoxIcon', color: 'light-success', value: '-' },
|
||||
{ subtitle: 'bonded_and_supply', icon: 'DollarSignIcon', color: 'light-danger', value: '-' },
|
||||
{ subtitle: 'bonded_ratio', icon: 'PercentIcon', color: 'light-warning', value: '-' },
|
||||
{ subtitle: 'inflation', icon: 'TrendingUpIcon', color: 'light-primary', value: '-' },
|
||||
],
|
||||
export const useParamStore = defineStore('paramstore', {
|
||||
state: () => ({
|
||||
latestTime: '',
|
||||
chain: {
|
||||
title: '',
|
||||
class: 'border-primary',
|
||||
items: [
|
||||
{
|
||||
subtitle: 'height',
|
||||
icon: 'BoxIcon',
|
||||
color: 'light-success',
|
||||
value: '-',
|
||||
},
|
||||
mint: {
|
||||
title: 'Mint Parameters',
|
||||
items: [] as Array<any>,
|
||||
{
|
||||
subtitle: 'bonded_and_supply',
|
||||
icon: 'DollarSignIcon',
|
||||
color: 'light-danger',
|
||||
value: '-',
|
||||
},
|
||||
staking: {
|
||||
title: 'Staking Parameters',
|
||||
items: [] as Array<any>,
|
||||
{
|
||||
subtitle: 'bonded_ratio',
|
||||
icon: 'PercentIcon',
|
||||
color: 'light-warning',
|
||||
value: '-',
|
||||
},
|
||||
distribution: {
|
||||
title: 'Distribution Parameters',
|
||||
items: [] as Array<any>,
|
||||
},
|
||||
slashing: {
|
||||
title: 'Slashing Parameters',
|
||||
items: [] as Array<any>,
|
||||
},
|
||||
gov: {
|
||||
title: 'Governance Parameters',
|
||||
items: [] as Array<any>,
|
||||
},
|
||||
appVersion: {
|
||||
title: 'Application Version',
|
||||
items: {},
|
||||
},
|
||||
nodeVersion: {
|
||||
title: 'Node Information',
|
||||
items: {},
|
||||
},
|
||||
}),
|
||||
getters: {
|
||||
blockchain() {
|
||||
return useBlockchain()
|
||||
{
|
||||
subtitle: 'inflation',
|
||||
icon: 'TrendingUpIcon',
|
||||
color: 'light-primary',
|
||||
value: '-',
|
||||
},
|
||||
],
|
||||
},
|
||||
actions: {
|
||||
initial() {
|
||||
this.handleBaseBlockLatest()
|
||||
// this.handleMintParam()
|
||||
this.handleStakingParams()
|
||||
this.handleSlashingParams()
|
||||
this.handleDistributionParams()
|
||||
this.handleGovernanceParams()
|
||||
this.handleAbciInfo()
|
||||
},
|
||||
async handleBaseBlockLatest() {
|
||||
try {
|
||||
const res = await this.getBaseTendermintBlockLatest()
|
||||
const height = this.chain.items.findIndex(x => x.subtitle === 'height')
|
||||
this.chain.title = `Chain ID: ${res.block.header.chain_id}`
|
||||
this.chain.items[height].value = res.block.header.height
|
||||
// if (timeIn(res.block.header.time, 3, 'm')) {
|
||||
// this.syncing = true
|
||||
// } else {
|
||||
// this.syncing = false
|
||||
// }
|
||||
// this.latestTime = toDay(res.block.header.time, 'long')
|
||||
this.latestTime = res.block.header.time
|
||||
} catch (error) {
|
||||
console.warn(error)
|
||||
}
|
||||
},
|
||||
async handleStakingParams() {
|
||||
const res = await this.getStakingParams()
|
||||
const bond_denom = res?.params.bond_denom
|
||||
this.staking.items = Object.entries(res.params).map(([key, value]) => ({ subtitle:key,
|
||||
value: value })).filter((item: any) => {
|
||||
if (!['min_commission_rate','min_self_delegation'].includes(item.subtitle)) return item
|
||||
})
|
||||
Promise.all([this.getStakingPool(), this.getBankTotal(bond_denom)])
|
||||
.then(resArr => {
|
||||
const pool = resArr[0]?.pool
|
||||
const amount =resArr[1]?.amount?.amount
|
||||
const assets = this.blockchain.current?.assets
|
||||
const bondedAndSupply = this.chain.items.findIndex(x => x.subtitle === 'bonded_and_supply')
|
||||
this.chain.items[bondedAndSupply].value = `${formatNumber(formatTokenAmount(assets,pool.bonded_tokens, 2, bond_denom, false), true, 0)}/${formatNumber(formatTokenAmount(assets,amount, 2, bond_denom, false), true, 0)}`
|
||||
const bondedRatio = this.chain.items.findIndex(x => x.subtitle === 'bonded_ratio')
|
||||
this.chain.items[bondedRatio].value = `${percent(Number(pool.bonded_tokens) /Number(amount)) }%`
|
||||
})
|
||||
},
|
||||
async handleMintParam() {
|
||||
const excludes = this.blockchain.current?.excludes
|
||||
if(excludes && excludes.indexOf('mint') > -1){
|
||||
return
|
||||
}
|
||||
// this.getMintingInflation().then(res => {
|
||||
// const chainIndex = this.chain.items.findIndex(x => x.subtitle === 'inflation')
|
||||
// this.chain.items[chainIndex].value = `${percent(res)}%`
|
||||
// })
|
||||
const res = await this.getMintParam()
|
||||
console.log(res, 'mint')
|
||||
},
|
||||
async handleSlashingParams(){
|
||||
const res = await this.getSlashingParams()
|
||||
this.slashing.items = Object.entries(res.params).map(([key, value]) => ({ subtitle:key,
|
||||
value: value }))
|
||||
},
|
||||
async handleDistributionParams(){
|
||||
const res = await this.getDistributionParams()
|
||||
this.distribution.items = Object.entries(res.params).map(([key, value]) => ({ subtitle: key,
|
||||
value: value }))
|
||||
},
|
||||
async handleGovernanceParams() {
|
||||
const excludes = this.blockchain.current?.excludes
|
||||
if(excludes && excludes.indexOf('governance') > -1){
|
||||
return
|
||||
}
|
||||
Promise.all([this.getGovParamsVoting(),this.getGovParamsDeposit(),this.getGovParamsTally()]).then((resArr) => {
|
||||
const govParams = {...resArr[0]?.voting_params,...resArr[1]?.deposit_params,...resArr[2]?.tally_params}
|
||||
this.gov.items = Object.entries(govParams).map(([key, value]) => ({ subtitle:key,
|
||||
value: value }))
|
||||
})
|
||||
|
||||
},
|
||||
async handleAbciInfo(){
|
||||
const res = await this.fetchAbciInfo()
|
||||
this.appVersion.items = Object.entries(res.application_version).map(([key, value]) => ({ subtitle:key,
|
||||
value: value }))
|
||||
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()
|
||||
},
|
||||
async getMintParam() {
|
||||
return await this.blockchain.rpc.getMintParam()
|
||||
},
|
||||
async getStakingParams() {
|
||||
return await this.blockchain.rpc.getStakingParams()
|
||||
},
|
||||
async getStakingPool(){
|
||||
return await this.blockchain.rpc.getStakingPool()
|
||||
},
|
||||
async getBankTotal(denom: string){
|
||||
return await this.blockchain.rpc.getBankSupplyByDenom(denom)
|
||||
// if (compareVersions(this.config.sdk_version, '0.46.2') > 0) {
|
||||
// return this.get(`/cosmos/bank/v1beta1/supply/by_denom?denom=${denom}`).then(data => commonProcess(data).amount)
|
||||
// }
|
||||
// if (compareVersions(this.config.sdk_version, '0.40') < 0) {
|
||||
// return this.get(`/supply/total/${denom}`).then(data => ({ amount: commonProcess(data), denom }))
|
||||
// }
|
||||
// return this.get(`/cosmos/bank/v1beta1/supply/${denom}`).then(data => commonProcess(data).amount)
|
||||
},
|
||||
async getSlashingParams() {
|
||||
return await this.blockchain.rpc.getSlashingParams()
|
||||
},
|
||||
async getDistributionParams() {
|
||||
return await this.blockchain.rpc.getDistributionParams()
|
||||
},
|
||||
async getGovParamsVoting() {
|
||||
return await this.blockchain.rpc.getGovParamsVoting()
|
||||
},
|
||||
async getGovParamsDeposit() {
|
||||
return await this.blockchain.rpc.getGovParamsDeposit()
|
||||
},
|
||||
async getGovParamsTally() {
|
||||
return await this.blockchain.rpc.getGovParamsTally()
|
||||
},
|
||||
async fetchAbciInfo() {
|
||||
return this.blockchain.rpc.getBaseNodeInfo()
|
||||
mint: {
|
||||
title: 'Mint Parameters',
|
||||
items: [] as Array<any>,
|
||||
},
|
||||
staking: {
|
||||
title: 'Staking Parameters',
|
||||
items: [] as Array<any>,
|
||||
},
|
||||
distribution: {
|
||||
title: 'Distribution Parameters',
|
||||
items: [] as Array<any>,
|
||||
},
|
||||
slashing: {
|
||||
title: 'Slashing Parameters',
|
||||
items: [] as Array<any>,
|
||||
},
|
||||
gov: {
|
||||
title: 'Governance Parameters',
|
||||
items: [] as Array<any>,
|
||||
},
|
||||
appVersion: {
|
||||
title: 'Application Version',
|
||||
items: {},
|
||||
},
|
||||
nodeVersion: {
|
||||
title: 'Node Information',
|
||||
items: {},
|
||||
},
|
||||
}),
|
||||
getters: {
|
||||
blockchain() {
|
||||
return useBlockchain();
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
initial() {
|
||||
this.handleBaseBlockLatest();
|
||||
// this.handleMintParam()
|
||||
this.handleStakingParams();
|
||||
this.handleSlashingParams();
|
||||
this.handleDistributionParams();
|
||||
this.handleGovernanceParams();
|
||||
this.handleAbciInfo();
|
||||
},
|
||||
async handleBaseBlockLatest() {
|
||||
try {
|
||||
const res = await this.getBaseTendermintBlockLatest();
|
||||
const height = this.chain.items.findIndex(
|
||||
(x) => x.subtitle === 'height'
|
||||
);
|
||||
this.chain.title = `Chain ID: ${res.block.header.chain_id}`;
|
||||
this.chain.items[height].value = res.block.header.height;
|
||||
// if (timeIn(res.block.header.time, 3, 'm')) {
|
||||
// this.syncing = true
|
||||
// } else {
|
||||
// this.syncing = false
|
||||
// }
|
||||
// this.latestTime = toDay(res.block.header.time, 'long')
|
||||
this.latestTime = res.block.header.time;
|
||||
} catch (error) {
|
||||
console.warn(error);
|
||||
}
|
||||
},
|
||||
async handleStakingParams() {
|
||||
const res = await this.getStakingParams();
|
||||
const bond_denom = res?.params.bond_denom;
|
||||
this.staking.items = Object.entries(res.params)
|
||||
.map(([key, value]) => ({ subtitle: key, value: value }))
|
||||
.filter((item: any) => {
|
||||
if (
|
||||
!['min_commission_rate', 'min_self_delegation'].includes(
|
||||
item.subtitle
|
||||
)
|
||||
)
|
||||
return item;
|
||||
});
|
||||
Promise.all([this.getStakingPool(), this.getBankTotal(bond_denom)]).then(
|
||||
(resArr) => {
|
||||
const pool = resArr[0]?.pool;
|
||||
const amount = resArr[1]?.amount?.amount;
|
||||
const assets = this.blockchain.current?.assets;
|
||||
const bondedAndSupply = this.chain.items.findIndex(
|
||||
(x) => x.subtitle === 'bonded_and_supply'
|
||||
);
|
||||
this.chain.items[bondedAndSupply].value = `${formatNumber(
|
||||
formatTokenAmount(assets, pool.bonded_tokens, 2, bond_denom, false),
|
||||
true,
|
||||
0
|
||||
)}/${formatNumber(
|
||||
formatTokenAmount(assets, amount, 2, bond_denom, false),
|
||||
true,
|
||||
0
|
||||
)}`;
|
||||
const bondedRatio = this.chain.items.findIndex(
|
||||
(x) => x.subtitle === 'bonded_ratio'
|
||||
);
|
||||
this.chain.items[bondedRatio].value = `${percent(
|
||||
Number(pool.bonded_tokens) / Number(amount)
|
||||
)}%`;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
})
|
||||
);
|
||||
},
|
||||
async handleMintParam() {
|
||||
const excludes = this.blockchain.current?.excludes;
|
||||
if (excludes && excludes.indexOf('mint') > -1) {
|
||||
return;
|
||||
}
|
||||
// this.getMintingInflation().then(res => {
|
||||
// const chainIndex = this.chain.items.findIndex(x => x.subtitle === 'inflation')
|
||||
// this.chain.items[chainIndex].value = `${percent(res)}%`
|
||||
// })
|
||||
const res = await this.getMintParam();
|
||||
console.log(res, 'mint');
|
||||
},
|
||||
async handleSlashingParams() {
|
||||
const res = await this.getSlashingParams();
|
||||
this.slashing.items = Object.entries(res.params).map(([key, value]) => ({
|
||||
subtitle: key,
|
||||
value: value,
|
||||
}));
|
||||
},
|
||||
async handleDistributionParams() {
|
||||
const res = await this.getDistributionParams();
|
||||
this.distribution.items = Object.entries(res.params).map(
|
||||
([key, value]) => ({ subtitle: key, value: value })
|
||||
);
|
||||
},
|
||||
async handleGovernanceParams() {
|
||||
const excludes = this.blockchain.current?.excludes;
|
||||
if (excludes && excludes.indexOf('governance') > -1) {
|
||||
return;
|
||||
}
|
||||
Promise.all([
|
||||
this.getGovParamsVoting(),
|
||||
this.getGovParamsDeposit(),
|
||||
this.getGovParamsTally(),
|
||||
]).then((resArr) => {
|
||||
const govParams = {
|
||||
...resArr[0]?.voting_params,
|
||||
...resArr[1]?.deposit_params,
|
||||
...resArr[2]?.tally_params,
|
||||
};
|
||||
this.gov.items = Object.entries(govParams).map(([key, value]) => ({
|
||||
subtitle: key,
|
||||
value: value,
|
||||
}));
|
||||
});
|
||||
},
|
||||
async handleAbciInfo() {
|
||||
const res = await this.fetchAbciInfo();
|
||||
this.appVersion.items = Object.entries(res.application_version).map(
|
||||
([key, value]) => ({ subtitle: key, value: value })
|
||||
);
|
||||
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();
|
||||
},
|
||||
async getMintParam() {
|
||||
return await this.blockchain.rpc.getMintParam();
|
||||
},
|
||||
async getStakingParams() {
|
||||
return await this.blockchain.rpc.getStakingParams();
|
||||
},
|
||||
async getStakingPool() {
|
||||
return await this.blockchain.rpc.getStakingPool();
|
||||
},
|
||||
async getBankTotal(denom: string) {
|
||||
return await this.blockchain.rpc.getBankSupplyByDenom(denom);
|
||||
// if (compareVersions(this.config.sdk_version, '0.46.2') > 0) {
|
||||
// return this.get(`/cosmos/bank/v1beta1/supply/by_denom?denom=${denom}`).then(data => commonProcess(data).amount)
|
||||
// }
|
||||
// if (compareVersions(this.config.sdk_version, '0.40') < 0) {
|
||||
// return this.get(`/supply/total/${denom}`).then(data => ({ amount: commonProcess(data), denom }))
|
||||
// }
|
||||
// return this.get(`/cosmos/bank/v1beta1/supply/${denom}`).then(data => commonProcess(data).amount)
|
||||
},
|
||||
async getSlashingParams() {
|
||||
return await this.blockchain.rpc.getSlashingParams();
|
||||
},
|
||||
async getDistributionParams() {
|
||||
return await this.blockchain.rpc.getDistributionParams();
|
||||
},
|
||||
async getGovParamsVoting() {
|
||||
return await this.blockchain.rpc.getGovParamsVoting();
|
||||
},
|
||||
async getGovParamsDeposit() {
|
||||
return await this.blockchain.rpc.getGovParamsDeposit();
|
||||
},
|
||||
async getGovParamsTally() {
|
||||
return await this.blockchain.rpc.getGovParamsTally();
|
||||
},
|
||||
async fetchAbciInfo() {
|
||||
return this.blockchain.rpc.getBaseNodeInfo();
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -1,77 +1,89 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { useBlockchain } from "./useBlockchain";
|
||||
import { defineStore } from 'pinia';
|
||||
import { useBlockchain } from './useBlockchain';
|
||||
|
||||
import { get } from "@/libs/http";
|
||||
import type { StakingParam, StakingPool, Validator } from "@/types";
|
||||
import { get } from '@/libs/http';
|
||||
import type { StakingParam, StakingPool, Validator } from '@/types';
|
||||
|
||||
export const useStakingStore = defineStore('stakingStore', {
|
||||
state: () => {
|
||||
return {
|
||||
validators: [] as Validator[],
|
||||
params: {} as {
|
||||
"unbonding_time": string,
|
||||
"max_validators": number,
|
||||
"max_entries": number,
|
||||
"historical_entries": number,
|
||||
"bond_denom": string,
|
||||
"min_commission_rate": string,
|
||||
"min_self_delegation": string
|
||||
},
|
||||
pool: {} as {
|
||||
bonded_tokens: string,
|
||||
not_bonded_tokens: string,
|
||||
},
|
||||
}
|
||||
state: () => {
|
||||
return {
|
||||
validators: [] as Validator[],
|
||||
params: {} as {
|
||||
unbonding_time: string;
|
||||
max_validators: number;
|
||||
max_entries: number;
|
||||
historical_entries: number;
|
||||
bond_denom: string;
|
||||
min_commission_rate: string;
|
||||
min_self_delegation: string;
|
||||
},
|
||||
pool: {} as {
|
||||
bonded_tokens: string;
|
||||
not_bonded_tokens: string;
|
||||
},
|
||||
};
|
||||
},
|
||||
getters: {
|
||||
totalPower(): number {
|
||||
const sum = (s: number, e: Validator) => {
|
||||
return s + parseInt(e.delegator_shares);
|
||||
};
|
||||
return this.validators ? this.validators.reduce(sum, 0) : 0;
|
||||
},
|
||||
getters: {
|
||||
totalPower(): number {
|
||||
const sum = (s:number, e: Validator) => { return s + parseInt(e.delegator_shares) }
|
||||
return this.validators ? this.validators.reduce(sum, 0): 0
|
||||
},
|
||||
blockchain() {
|
||||
return useBlockchain()
|
||||
}
|
||||
blockchain() {
|
||||
return useBlockchain();
|
||||
},
|
||||
actions: {
|
||||
async init() {
|
||||
this.$reset()
|
||||
this.fetchPool()
|
||||
this.fetchAcitveValdiators()
|
||||
return await this.fetchParams()
|
||||
},
|
||||
async keybase(identity: string) {
|
||||
return get(`https://keybase.io/_/api/1.0/user/lookup.json?key_suffix=${identity}&fields=pictures`)
|
||||
},
|
||||
async fetchParams() {
|
||||
const response = await this.blockchain.rpc.getStakingParams()
|
||||
if(response.params) this.params = response.params
|
||||
return this.params
|
||||
},
|
||||
async fetchPool() {
|
||||
const response = await this.blockchain.rpc.getStakingPool()
|
||||
response.pool.bonded_tokens
|
||||
this.pool = response.pool
|
||||
},
|
||||
async fetchAcitveValdiators() {
|
||||
return this.fetchValidators('BOND_STATUS_BONDED')
|
||||
},
|
||||
async fetchInacitveValdiators() {
|
||||
return this.fetchValidators('BOND_STATUS_UNBONDED')
|
||||
},
|
||||
async fetchValidator(validatorAddr: string) {
|
||||
return this.blockchain.rpc.getStakingValidator(validatorAddr)
|
||||
},
|
||||
async fetchValidatorDelegation(validatorAddr: string, delegatorAddr: string) {
|
||||
return await this.blockchain.rpc.getStakingValidatorsDelegationsDelegator(validatorAddr, delegatorAddr)
|
||||
},
|
||||
async fetchValidators(status: string) {
|
||||
return this.blockchain.rpc.getStakingValidators(status).then(res => {
|
||||
const vals = res.validators.sort((a, b) => (Number(b.delegator_shares) - Number(a.delegator_shares)))
|
||||
if(status==='BOND_STATUS_BONDED') {
|
||||
this.validators = vals
|
||||
}
|
||||
return vals
|
||||
})
|
||||
},
|
||||
actions: {
|
||||
async init() {
|
||||
this.$reset();
|
||||
this.fetchPool();
|
||||
this.fetchAcitveValdiators();
|
||||
return await this.fetchParams();
|
||||
},
|
||||
async keybase(identity: string) {
|
||||
return get(
|
||||
`https://keybase.io/_/api/1.0/user/lookup.json?key_suffix=${identity}&fields=pictures`
|
||||
);
|
||||
},
|
||||
async fetchParams() {
|
||||
const response = await this.blockchain.rpc.getStakingParams();
|
||||
if (response.params) this.params = response.params;
|
||||
return this.params;
|
||||
},
|
||||
async fetchPool() {
|
||||
const response = await this.blockchain.rpc.getStakingPool();
|
||||
response.pool.bonded_tokens;
|
||||
this.pool = response.pool;
|
||||
},
|
||||
async fetchAcitveValdiators() {
|
||||
return this.fetchValidators('BOND_STATUS_BONDED');
|
||||
},
|
||||
async fetchInacitveValdiators() {
|
||||
return this.fetchValidators('BOND_STATUS_UNBONDED');
|
||||
},
|
||||
async fetchValidator(validatorAddr: string) {
|
||||
return this.blockchain.rpc.getStakingValidator(validatorAddr);
|
||||
},
|
||||
async fetchValidatorDelegation(
|
||||
validatorAddr: string,
|
||||
delegatorAddr: string
|
||||
) {
|
||||
return await this.blockchain.rpc.getStakingValidatorsDelegationsDelegator(
|
||||
validatorAddr,
|
||||
delegatorAddr
|
||||
);
|
||||
},
|
||||
async fetchValidators(status: string) {
|
||||
return this.blockchain.rpc.getStakingValidators(status).then((res) => {
|
||||
const vals = res.validators.sort(
|
||||
(a, b) => Number(b.delegator_shares) - Number(a.delegator_shares)
|
||||
);
|
||||
if (status === 'BOND_STATUS_BONDED') {
|
||||
this.validators = vals;
|
||||
}
|
||||
}
|
||||
})
|
||||
return vals;
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -1,13 +1,9 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { defineStore } from 'pinia';
|
||||
|
||||
export const useWalletStore = defineStore('walletStore', {
|
||||
state: () => {
|
||||
return {
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
|
||||
},
|
||||
actions: {
|
||||
}
|
||||
})
|
||||
state: () => {
|
||||
return {};
|
||||
},
|
||||
getters: {},
|
||||
actions: {},
|
||||
});
|
||||
|
@ -1,16 +1,16 @@
|
||||
import { fileURLToPath, URL } from "node:url";
|
||||
import { fileURLToPath, URL } from 'node:url';
|
||||
|
||||
import { defineConfig } from "vite";
|
||||
import vue from "@vitejs/plugin-vue";
|
||||
import vueJsx from "@vitejs/plugin-vue-jsx";
|
||||
import vuetify from "vite-plugin-vuetify";
|
||||
import Layouts from "vite-plugin-vue-layouts";
|
||||
import DefineOptions from "unplugin-vue-define-options/vite";
|
||||
import Components from "unplugin-vue-components/vite";
|
||||
import AutoImport from "unplugin-auto-import/vite";
|
||||
import Pages from "vite-plugin-pages";
|
||||
import { defineConfig } from 'vite';
|
||||
import vue from '@vitejs/plugin-vue';
|
||||
import vueJsx from '@vitejs/plugin-vue-jsx';
|
||||
import vuetify from 'vite-plugin-vuetify';
|
||||
import Layouts from 'vite-plugin-vue-layouts';
|
||||
import DefineOptions from 'unplugin-vue-define-options/vite';
|
||||
import Components from 'unplugin-vue-components/vite';
|
||||
import AutoImport from 'unplugin-auto-import/vite';
|
||||
import Pages from 'vite-plugin-pages';
|
||||
|
||||
import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite'
|
||||
import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite';
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
@ -19,61 +19,70 @@ export default defineConfig({
|
||||
vueJsx(),
|
||||
vuetify({
|
||||
styles: {
|
||||
configFile: "src/plugins/vuetify/styles/variables/_vuetify.scss",
|
||||
configFile: 'src/plugins/vuetify/styles/variables/_vuetify.scss',
|
||||
},
|
||||
}),
|
||||
Pages({
|
||||
dirs: ["./src/modules", "./src/pages", ],
|
||||
dirs: ['./src/modules', './src/pages'],
|
||||
exclude: ['**/*.ts'], // only load .vue as modules
|
||||
}),
|
||||
Layouts({
|
||||
layoutsDirs: "./src/layouts/",
|
||||
layoutsDirs: './src/layouts/',
|
||||
}),
|
||||
Components({
|
||||
dirs: ["src/plugins/vuetify/@core/components"],
|
||||
dirs: ['src/plugins/vuetify/@core/components'],
|
||||
dts: true,
|
||||
}),
|
||||
AutoImport({
|
||||
imports: ["vue", "vue-router", "@vueuse/core", "@vueuse/math", "vue-i18n", "pinia"],
|
||||
imports: [
|
||||
'vue',
|
||||
'vue-router',
|
||||
'@vueuse/core',
|
||||
'@vueuse/math',
|
||||
'vue-i18n',
|
||||
'pinia',
|
||||
],
|
||||
vueTemplate: true,
|
||||
}),
|
||||
VueI18nPlugin({
|
||||
runtimeOnly: true,
|
||||
compositionOnly: true,
|
||||
include: [
|
||||
fileURLToPath(new URL('./src/plugins/i18n/locales/**', import.meta.url)),
|
||||
fileURLToPath(
|
||||
new URL('./src/plugins/i18n/locales/**', import.meta.url)
|
||||
),
|
||||
],
|
||||
}),
|
||||
DefineOptions(),
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": fileURLToPath(new URL("./src", import.meta.url)),
|
||||
"@themeConfig": fileURLToPath(
|
||||
new URL("./themeConfig.ts", import.meta.url)
|
||||
'@': fileURLToPath(new URL('./src', import.meta.url)),
|
||||
'@themeConfig': fileURLToPath(
|
||||
new URL('./themeConfig.ts', import.meta.url)
|
||||
),
|
||||
"@configured-variables": fileURLToPath(
|
||||
'@configured-variables': fileURLToPath(
|
||||
new URL(
|
||||
"./src/plugins/vuetify/styles/variables/_template.scss",
|
||||
'./src/plugins/vuetify/styles/variables/_template.scss',
|
||||
import.meta.url
|
||||
)
|
||||
),
|
||||
"@core": fileURLToPath(
|
||||
new URL("./src/plugins/vuetify/@core", import.meta.url)
|
||||
'@core': fileURLToPath(
|
||||
new URL('./src/plugins/vuetify/@core', import.meta.url)
|
||||
),
|
||||
"@layouts": fileURLToPath(
|
||||
new URL("./src/plugins/vuetify/@layouts", import.meta.url)
|
||||
'@layouts': fileURLToPath(
|
||||
new URL('./src/plugins/vuetify/@layouts', import.meta.url)
|
||||
),
|
||||
"@images": fileURLToPath(
|
||||
new URL("./src/plugins/vuetify/images/", import.meta.url)
|
||||
'@images': fileURLToPath(
|
||||
new URL('./src/plugins/vuetify/images/', import.meta.url)
|
||||
),
|
||||
"@styles": fileURLToPath(
|
||||
new URL("./src/plugins/vuetify/styles/", import.meta.url)
|
||||
'@styles': fileURLToPath(
|
||||
new URL('./src/plugins/vuetify/styles/', import.meta.url)
|
||||
),
|
||||
},
|
||||
},
|
||||
optimizeDeps: {
|
||||
exclude: ["vuetify"],
|
||||
entries: ["./src/**/*.vue"],
|
||||
exclude: ['vuetify'],
|
||||
entries: ['./src/**/*.vue'],
|
||||
},
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user