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">
|
<script setup lang="ts">
|
||||||
import { useTheme } from 'vuetify'
|
import { useTheme } from 'vuetify';
|
||||||
import { useThemeConfig } from '@/plugins/vuetify/@core/composable/useThemeConfig'
|
import { useThemeConfig } from '@/plugins/vuetify/@core/composable/useThemeConfig';
|
||||||
import { hexToRgb } from '@/plugins/vuetify/@layouts/utils'
|
import { hexToRgb } from '@/plugins/vuetify/@layouts/utils';
|
||||||
import { themeChange } from 'theme-change'
|
import { themeChange } from 'theme-change';
|
||||||
import { onMounted } from 'vue'
|
import { onMounted } from 'vue';
|
||||||
const { syncInitialLoaderTheme, syncVuetifyThemeWithTheme: syncConfigThemeWithVuetifyTheme, isAppRtl } = useThemeConfig()
|
const {
|
||||||
|
syncInitialLoaderTheme,
|
||||||
|
syncVuetifyThemeWithTheme: syncConfigThemeWithVuetifyTheme,
|
||||||
|
isAppRtl,
|
||||||
|
} = useThemeConfig();
|
||||||
|
|
||||||
const { global } = useTheme()
|
const { global } = useTheme();
|
||||||
|
|
||||||
// ℹ️ Sync current theme with initial loader theme
|
// ℹ️ Sync current theme with initial loader theme
|
||||||
syncInitialLoaderTheme()
|
syncInitialLoaderTheme();
|
||||||
syncConfigThemeWithVuetifyTheme()
|
syncConfigThemeWithVuetifyTheme();
|
||||||
|
|
||||||
onMounted(()=> {
|
onMounted(() => {
|
||||||
themeChange(false)
|
themeChange(false);
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<VLocaleProvider :rtl="isAppRtl">
|
<VLocaleProvider :rtl="isAppRtl">
|
||||||
<!-- ℹ️ This is required to set the background color of active nav link based on currently active global theme's primary -->
|
<!-- ℹ️ 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 />
|
<RouterView />
|
||||||
</VApp>
|
</VApp>
|
||||||
</VLocaleProvider>
|
</VLocaleProvider>
|
||||||
|
@ -1,26 +1,26 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { PropType } from 'vue';
|
import type { PropType } from 'vue';
|
||||||
import { useFormatter } from "@/stores";
|
import { useFormatter } from '@/stores';
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
cardItem: {
|
cardItem: {
|
||||||
type: Object as PropType<{ title: string; items: Array<any> }>,
|
type: Object as PropType<{ title: string; items: Array<any> }>,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const formatter = useFormatter()
|
const formatter = useFormatter();
|
||||||
function calculateValue(value: any){
|
function calculateValue(value: any) {
|
||||||
if (Array.isArray(value) ){
|
if (Array.isArray(value)) {
|
||||||
return (value[0] && value[0].amount)|| '-'
|
return (value[0] && value[0].amount) || '-';
|
||||||
}
|
}
|
||||||
const newValue = Number(value)
|
const newValue = Number(value);
|
||||||
if(`${newValue}` === 'NaN' || typeof(value) === 'boolean'){
|
if (`${newValue}` === 'NaN' || typeof value === 'boolean') {
|
||||||
return value
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newValue < 1 && newValue > 0) {
|
if (newValue < 1 && newValue > 0) {
|
||||||
return formatter.formatDecimalToPercent(value)
|
return formatter.formatDecimalToPercent(value);
|
||||||
}
|
}
|
||||||
return newValue
|
return newValue;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
|
@ -2,18 +2,21 @@
|
|||||||
import { controlledComputed } from '@vueuse/shared';
|
import { controlledComputed } from '@vueuse/shared';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
title: string
|
title: string;
|
||||||
color?: string
|
color?: string;
|
||||||
icon: string
|
icon: string;
|
||||||
stats: number
|
stats: number;
|
||||||
change?: number
|
change?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
color: 'primary',
|
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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -26,16 +29,13 @@ const isPositive = controlledComputed(() => props.change, () => Math.sign(props.
|
|||||||
variant="tonal"
|
variant="tonal"
|
||||||
class="me-4"
|
class="me-4"
|
||||||
>
|
>
|
||||||
<VIcon
|
<VIcon :icon="props.icon" size="24" />
|
||||||
:icon="props.icon"
|
|
||||||
size="24"
|
|
||||||
/>
|
|
||||||
</VAvatar>
|
</VAvatar>
|
||||||
|
|
||||||
<div class="d-flex flex-column">
|
<div class="d-flex flex-column">
|
||||||
<div class="d-flex align-center flex-wrap">
|
<div class="d-flex align-center flex-wrap">
|
||||||
<h6 class="text-h6">
|
<h6 class="text-h6">
|
||||||
{{ (props.stats) }}
|
{{ props.stats }}
|
||||||
</h6>
|
</h6>
|
||||||
<div
|
<div
|
||||||
v-if="props.change"
|
v-if="props.change"
|
||||||
|
@ -21,7 +21,13 @@ const isPositive = controlledComputed(
|
|||||||
<template>
|
<template>
|
||||||
<VCard class="h-full flex-col content-between">
|
<VCard class="h-full flex-col content-between">
|
||||||
<VCardText class="d-flex align-center justify-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" />
|
<VIcon :icon="props.icon" size="24" />
|
||||||
</VAvatar>
|
</VAvatar>
|
||||||
|
|
||||||
|
@ -1,19 +1,22 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
interface Props {
|
interface Props {
|
||||||
title: string
|
title: string;
|
||||||
subtitle: string
|
subtitle: string;
|
||||||
stats: string
|
stats: string;
|
||||||
change: number
|
change: number;
|
||||||
image: string
|
image: string;
|
||||||
imgWidth: number
|
imgWidth: number;
|
||||||
color?: string
|
color?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
color: 'primary',
|
color: 'primary',
|
||||||
})
|
});
|
||||||
|
|
||||||
const isPositive = controlledComputed(() => props.change, () => Math.sign(props.change) === 1)
|
const isPositive = controlledComputed(
|
||||||
|
() => props.change,
|
||||||
|
() => Math.sign(props.change) === 1
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -47,11 +50,7 @@ const isPositive = controlledComputed(() => props.change, () => Math.sign(props.
|
|||||||
<VSpacer />
|
<VSpacer />
|
||||||
|
|
||||||
<div class="illustrator-img">
|
<div class="illustrator-img">
|
||||||
<VImg
|
<VImg v-if="props.image" :src="props.image" :width="props.imgWidth" />
|
||||||
v-if="props.image"
|
|
||||||
:src="props.image"
|
|
||||||
:width="props.imgWidth"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</VCard>
|
</VCard>
|
||||||
</template>
|
</template>
|
||||||
|
@ -1,12 +1,17 @@
|
|||||||
<script lang="ts" setup >
|
<script lang="ts" setup>
|
||||||
import VueCountdown from '@chenfengyuan/vue-countdown';
|
import VueCountdown from '@chenfengyuan/vue-countdown';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
time: { type: Number},
|
time: { type: Number },
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<vue-countdown v-if="time" :time="time > 0? time: 0" v-slot="{ days, hours, minutes, seconds }">
|
<vue-countdown
|
||||||
Time Remaining:{{ days }} days, {{ hours }} hours, {{ minutes }} minutes, {{ seconds }} seconds.
|
v-if="time"
|
||||||
</vue-countdown>
|
:time="time > 0 ? time : 0"
|
||||||
|
v-slot="{ days, hours, minutes, seconds }"
|
||||||
|
>
|
||||||
|
Time Remaining:{{ days }} days, {{ hours }} hours, {{ minutes }} minutes,
|
||||||
|
{{ seconds }} seconds.
|
||||||
|
</vue-countdown>
|
||||||
</template>
|
</template>
|
||||||
|
@ -15,17 +15,28 @@ const props = defineProps({
|
|||||||
});
|
});
|
||||||
const total = computed(() => props.pool?.bonded_tokens);
|
const total = computed(() => props.pool?.bonded_tokens);
|
||||||
const format = useFormatter();
|
const format = useFormatter();
|
||||||
const yes = computed(() => format.calculatePercent(props.tally?.yes, total.value));
|
const yes = computed(() =>
|
||||||
const no = computed(() => format.calculatePercent(props.tally?.no, total.value));
|
format.calculatePercent(props.tally?.yes, 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 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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="progress rounded-full h-1 text-xs flex items-center">
|
<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-yes" :style="`width: ${yes}`"></div>
|
||||||
<div class="h-1 bg-no" :style="`width: ${no}`"></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 class="h-1 bg-secondary" :style="`width: ${abstain}`"></div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -14,28 +14,30 @@ const {
|
|||||||
next: getNextThemeName,
|
next: getNextThemeName,
|
||||||
index: currentThemeIndex,
|
index: currentThemeIndex,
|
||||||
} = useCycleList(
|
} = useCycleList(
|
||||||
props.themes.map(t => t.name),
|
props.themes.map((t) => t.name),
|
||||||
{ initialValue: theme.value }
|
{ initialValue: theme.value }
|
||||||
);
|
);
|
||||||
|
|
||||||
const changeTheme = () => {
|
const changeTheme = () => {
|
||||||
theme.value = getNextThemeName();
|
theme.value = getNextThemeName();
|
||||||
};
|
};
|
||||||
|
|
||||||
const changeMode = (val: 'dark' | 'light' | 'system') => {
|
const changeMode = (val: 'dark' | 'light' | 'system') => {
|
||||||
let value = val;
|
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';
|
value = 'dark';
|
||||||
}
|
}
|
||||||
if (value === 'dark') {
|
if (value === 'dark') {
|
||||||
document.documentElement.classList.add('dark');
|
document.documentElement.classList.add('dark');
|
||||||
document.documentElement.classList.remove('light');
|
document.documentElement.classList.remove('light');
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
document.documentElement.classList.add('light');
|
document.documentElement.classList.add('light');
|
||||||
document.documentElement.classList.remove('dark');
|
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
|
// Update icon if theme is changed from other sources
|
||||||
watch(theme, (val: 'dark' | 'light' | 'system') => {
|
watch(theme, (val: 'dark' | 'light' | 'system') => {
|
||||||
@ -52,10 +54,7 @@ onMounted(() => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="tooltip tooltip-bottom delay-1000" :data-tip="currentThemeName">
|
<div class="tooltip tooltip-bottom delay-1000" :data-tip="currentThemeName">
|
||||||
<button
|
<button class="btn btn-ghost btn-circle btn-sm mx-1" @click="changeTheme">
|
||||||
class="btn btn-ghost btn-circle btn-sm mx-1"
|
|
||||||
@click="changeTheme"
|
|
||||||
>
|
|
||||||
<Icon :icon="props.themes[currentThemeIndex].icon" class="text-2xl" />
|
<Icon :icon="props.themes[currentThemeIndex].icon" class="text-2xl" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,32 +1,37 @@
|
|||||||
<script lang=ts setup>
|
<script lang="ts" setup>
|
||||||
import type { Commit } from "@/types";
|
import type { Commit } from '@/types';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
blocks: { type: Array as PropType<Commit[]>},
|
blocks: { type: Array as PropType<Commit[]> },
|
||||||
validator: { type: String },
|
validator: { type: String },
|
||||||
})
|
});
|
||||||
|
|
||||||
const bars = computed(() => {
|
const bars = computed(() => {
|
||||||
const uptime = Array(50).fill({height:0, color: 'bg-secondary'})
|
const uptime = Array(50).fill({ height: 0, color: 'bg-secondary' });
|
||||||
props.blocks.forEach(element => {
|
props.blocks.forEach((element) => {
|
||||||
const has = element.signatures?.findIndex(sig => sig.validator_address === props.validator )
|
const has = element.signatures?.findIndex(
|
||||||
// console.log(has, props.validato, element)
|
(sig) => sig.validator_address === props.validator
|
||||||
uptime.push({
|
);
|
||||||
height: element.height,
|
// console.log(has, props.validato, element)
|
||||||
color: has > -1 ? 'bg-success' : 'bg-error'
|
uptime.push({
|
||||||
})
|
height: element.height,
|
||||||
uptime.shift()
|
color: has > -1 ? 'bg-success' : 'bg-error',
|
||||||
});
|
});
|
||||||
return uptime
|
uptime.shift();
|
||||||
})
|
});
|
||||||
|
return uptime;
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="d-flex justify-evenly">
|
<div class="d-flex justify-evenly">
|
||||||
<span v-for="(b,i) in bars"
|
<span v-for="(b, i) in bars" :key="i" :class="b.color" style="width: 1.5%"
|
||||||
:key="i"
|
>
|
||||||
:class="b.color"
|
<v-tooltip
|
||||||
style="width:1.5%">
|
v-if="Number(b.height) > 0"
|
||||||
<v-tooltip v-if="Number(b.height) > 0" activator="parent" location="top">{{ b.height }}</v-tooltip>
|
activator="parent"
|
||||||
</span>
|
location="top"
|
||||||
</div>
|
>{{ b.height }}</v-tooltip
|
||||||
</template>
|
>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
@ -1,44 +1,61 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import VueApexCharts from 'vue3-apexcharts'
|
import VueApexCharts from 'vue3-apexcharts';
|
||||||
import { useTheme } from 'vuetify'
|
import { useTheme } from 'vuetify';
|
||||||
import { hexToRgb } from '@/plugins/vuetify/@layouts/utils'
|
import { hexToRgb } from '@/plugins/vuetify/@layouts/utils';
|
||||||
import { computed, type PropType } from 'vue';
|
import { computed, type PropType } from 'vue';
|
||||||
import { useFormatter } from '@/stores';
|
import { useFormatter } from '@/stores';
|
||||||
import type { CommissionRate } from '@/types'
|
import type { CommissionRate } from '@/types';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
commission: { type: Object as PropType<CommissionRate>},
|
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)
|
|
||||||
|
|
||||||
|
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 rate = 15 // props.commision?.commissionRates.rate
|
||||||
// const change = 15
|
// const change = 15
|
||||||
// const max = 20
|
// const max = 20
|
||||||
|
|
||||||
const left = rate
|
const left = rate;
|
||||||
const right = computed(() => max.value - rate.value)
|
const right = computed(() => max.value - rate.value);
|
||||||
|
|
||||||
const s1 = computed(() => left.value > change.value ? left.value - change.value : 0 )
|
const s1 = computed(() =>
|
||||||
const s2 = computed(() => left.value > change.value ? change.value: left.value)
|
left.value > change.value ? left.value - change.value : 0
|
||||||
const s3 = 2
|
);
|
||||||
const s4 = computed(() => right.value > change.value? change.value: right.value)
|
const s2 = computed(() =>
|
||||||
const s5 = computed(() => right.value > change.value? right.value - change.value: 0)
|
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 vuetifyTheme = useTheme();
|
||||||
const format = useFormatter()
|
const format = useFormatter();
|
||||||
|
|
||||||
const chartConfig = computed(() => {
|
const chartConfig = computed(() => {
|
||||||
const themeColors = vuetifyTheme.current.value.colors
|
const themeColors = vuetifyTheme.current.value.colors;
|
||||||
const variableTheme = vuetifyTheme.current.value.variables
|
const variableTheme = vuetifyTheme.current.value.variables;
|
||||||
|
|
||||||
const secondaryText = `rgba(${hexToRgb(String(themeColors['on-background']))},${variableTheme['medium-emphasis-opacity']})`
|
const secondaryText = `rgba(${hexToRgb(
|
||||||
const primaryText = `rgba(${hexToRgb(String(themeColors['on-background']))},${variableTheme['high-emphasis-opacity']})`
|
String(themeColors['on-background'])
|
||||||
|
)},${variableTheme['medium-emphasis-opacity']})`;
|
||||||
|
const primaryText = `rgba(${hexToRgb(String(themeColors['on-background']))},${
|
||||||
|
variableTheme['high-emphasis-opacity']
|
||||||
|
})`;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
chart: {
|
chart: {
|
||||||
@ -54,8 +71,18 @@ const chartConfig = computed(() => {
|
|||||||
legend: { show: false },
|
legend: { show: false },
|
||||||
tooltip: { enabled: false },
|
tooltip: { enabled: false },
|
||||||
dataLabels: { enabled: false },
|
dataLabels: { enabled: false },
|
||||||
stroke: { width: 3, lineCap: 'round', colors: ['rgba(var(--v-theme-surface), 1)'] },
|
stroke: {
|
||||||
labels: ['Available', 'Daily Change', 'Commission Rate', 'Daily Change', 'Available'],
|
width: 3,
|
||||||
|
lineCap: 'round',
|
||||||
|
colors: ['rgba(var(--v-theme-surface), 1)'],
|
||||||
|
},
|
||||||
|
labels: [
|
||||||
|
'Available',
|
||||||
|
'Daily Change',
|
||||||
|
'Commission Rate',
|
||||||
|
'Daily Change',
|
||||||
|
'Available',
|
||||||
|
],
|
||||||
states: {
|
states: {
|
||||||
hover: {
|
hover: {
|
||||||
filter: { type: 'none' },
|
filter: { type: 'none' },
|
||||||
@ -90,7 +117,7 @@ const chartConfig = computed(() => {
|
|||||||
label: 'Commission Rate',
|
label: 'Commission Rate',
|
||||||
fontSize: '1rem',
|
fontSize: '1rem',
|
||||||
color: secondaryText,
|
color: secondaryText,
|
||||||
formatter: ( ) => `${rate.value}%`,
|
formatter: () => `${rate.value}%`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -104,13 +131,18 @@ const chartConfig = computed(() => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
};
|
||||||
})
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<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>
|
<VCardText>
|
||||||
<VueApexCharts
|
<VueApexCharts
|
||||||
type="donut"
|
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 justify-center flex-wrap mx-2 gap-x-6">
|
||||||
<div class="d-flex align-center gap-2">
|
<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>
|
<span class="mt-1 text-caption">Rate:{{ rate }}%</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex align-center gap-2">
|
<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>
|
<span class="mt-1 text-caption">24h: ±{{ change }}%</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex align-center gap-2">
|
<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>
|
<span class="mt-1 text-caption">Max:{{ max }}%</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import VueApexCharts from 'vue3-apexcharts'
|
import VueApexCharts from 'vue3-apexcharts';
|
||||||
import { useTheme } from 'vuetify'
|
import { useTheme } from 'vuetify';
|
||||||
import { getDonutChartConfig } from './apexChartConfig'
|
import { getDonutChartConfig } from './apexChartConfig';
|
||||||
|
|
||||||
const props = defineProps(["series", "labels"])
|
const props = defineProps(['series', 'labels']);
|
||||||
|
|
||||||
const vuetifyTheme = useTheme()
|
|
||||||
|
|
||||||
const expenseRationChartConfig = computed(() => getDonutChartConfig(vuetifyTheme.current.value, props.labels))
|
|
||||||
|
|
||||||
|
const vuetifyTheme = useTheme();
|
||||||
|
|
||||||
|
const expenseRationChartConfig = computed(() =>
|
||||||
|
getDonutChartConfig(vuetifyTheme.current.value, props.labels)
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -1,30 +1,41 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import VueApexCharts from 'vue3-apexcharts'
|
import VueApexCharts from 'vue3-apexcharts';
|
||||||
import { useTheme } from 'vuetify'
|
import { useTheme } from 'vuetify';
|
||||||
import { getAreaChartSplineConfig, getMarketPriceChartConfig } from './apexChartConfig'
|
import {
|
||||||
|
getAreaChartSplineConfig,
|
||||||
|
getMarketPriceChartConfig,
|
||||||
|
} from './apexChartConfig';
|
||||||
import { useIndexModule } from '@/modules/[chain]/indexStore';
|
import { useIndexModule } from '@/modules/[chain]/indexStore';
|
||||||
import { computed, ref } from '@vue/reactivity';
|
import { computed, ref } from '@vue/reactivity';
|
||||||
|
|
||||||
const store = useIndexModule()
|
const store = useIndexModule();
|
||||||
const vuetifyTheme = useTheme()
|
const vuetifyTheme = useTheme();
|
||||||
const chartConfig = computed(() => {
|
const chartConfig = computed(() => {
|
||||||
const labels = store.marketData.prices.map(x => x[0])
|
const labels = store.marketData.prices.map((x) => x[0]);
|
||||||
return getMarketPriceChartConfig(vuetifyTheme.current.value, labels)
|
return getMarketPriceChartConfig(vuetifyTheme.current.value, labels);
|
||||||
})
|
});
|
||||||
const kind = ref('price')
|
const kind = ref('price');
|
||||||
const series = computed(() => {
|
const series = computed(() => {
|
||||||
return [{
|
return [
|
||||||
name: 'Price',
|
{
|
||||||
data: kind.value ==='price'?store.marketData.prices.map(x => x[1]) : store.marketData.total_volumes.map(x => x[1])}]
|
name: 'Price',
|
||||||
})
|
data:
|
||||||
|
kind.value === 'price'
|
||||||
|
? store.marketData.prices.map((x) => x[1])
|
||||||
|
: store.marketData.total_volumes.map((x) => x[1]),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<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
|
<VueApexCharts
|
||||||
type="area"
|
type="area"
|
||||||
height="261"
|
height="261"
|
||||||
:options="chartConfig"
|
:options="chartConfig"
|
||||||
:series="series"
|
:series="series"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
@ -1,20 +1,38 @@
|
|||||||
import type { ThemeInstance } from 'vuetify'
|
import type { ThemeInstance } from 'vuetify';
|
||||||
import { hexToRgb } from '@/plugins/vuetify/@layouts/utils'
|
import { hexToRgb } from '@/plugins/vuetify/@layouts/utils';
|
||||||
import numeral from 'numeral'
|
import numeral from 'numeral';
|
||||||
|
|
||||||
// 👉 Colors variables
|
// 👉 Colors variables
|
||||||
const colorVariables = (themeColors: ThemeInstance['themes']['value']['colors']) => {
|
const colorVariables = (
|
||||||
const themeSecondaryTextColor = `rgba(${hexToRgb(themeColors.colors['on-surface'])},${themeColors.variables['medium-emphasis-opacity']})`
|
themeColors: ThemeInstance['themes']['value']['colors']
|
||||||
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 themeSecondaryTextColor = `rgba(${hexToRgb(
|
||||||
const themePrimaryTextColor = `rgba(${hexToRgb(themeColors.colors['on-surface'])},${themeColors.variables['high-emphasis-opacity']})`
|
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
|
/// Price Chart config
|
||||||
export const getMarketPriceChartConfig = (themeColors: ThemeInstance['themes']['value']['colors'], categories: string[]) => {
|
export const getMarketPriceChartConfig = (
|
||||||
|
themeColors: ThemeInstance['themes']['value']['colors'],
|
||||||
const { themeSecondaryTextColor, themeBorderColor, themeDisabledTextColor } = colorVariables(themeColors)
|
categories: string[]
|
||||||
|
) => {
|
||||||
|
const { themeSecondaryTextColor, themeBorderColor, themeDisabledTextColor } =
|
||||||
|
colorVariables(themeColors);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
chart: {
|
chart: {
|
||||||
@ -25,7 +43,7 @@ export const getMarketPriceChartConfig = (themeColors: ThemeInstance['themes']['
|
|||||||
},
|
},
|
||||||
tooltip: {
|
tooltip: {
|
||||||
theme: 'dark',
|
theme: 'dark',
|
||||||
shared: false
|
shared: false,
|
||||||
},
|
},
|
||||||
dataLabels: { enabled: false },
|
dataLabels: { enabled: false },
|
||||||
stroke: {
|
stroke: {
|
||||||
@ -64,9 +82,9 @@ export const getMarketPriceChartConfig = (themeColors: ThemeInstance['themes']['
|
|||||||
labels: {
|
labels: {
|
||||||
style: { colors: themeDisabledTextColor },
|
style: { colors: themeDisabledTextColor },
|
||||||
formatter: function (value: string) {
|
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);
|
return numeral(value).format(pattern);
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
xaxis: {
|
xaxis: {
|
||||||
@ -82,19 +100,22 @@ export const getMarketPriceChartConfig = (themeColors: ThemeInstance['themes']['
|
|||||||
},
|
},
|
||||||
categories,
|
categories,
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
/// default config
|
/// default config
|
||||||
|
|
||||||
export const getScatterChartConfig = (themeColors: ThemeInstance['themes']['value']['colors']) => {
|
export const getScatterChartConfig = (
|
||||||
|
themeColors: ThemeInstance['themes']['value']['colors']
|
||||||
|
) => {
|
||||||
const scatterColors = {
|
const scatterColors = {
|
||||||
series1: '#ff9f43',
|
series1: '#ff9f43',
|
||||||
series2: '#7367f0',
|
series2: '#7367f0',
|
||||||
series3: '#28c76f',
|
series3: '#28c76f',
|
||||||
}
|
};
|
||||||
|
|
||||||
const { themeSecondaryTextColor, themeBorderColor, themeDisabledTextColor } = colorVariables(themeColors)
|
const { themeSecondaryTextColor, themeBorderColor, themeDisabledTextColor } =
|
||||||
|
colorVariables(themeColors);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
chart: {
|
chart: {
|
||||||
@ -116,7 +137,11 @@ export const getScatterChartConfig = (themeColors: ThemeInstance['themes']['valu
|
|||||||
horizontal: 10,
|
horizontal: 10,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
colors: [scatterColors.series1, scatterColors.series2, scatterColors.series3],
|
colors: [
|
||||||
|
scatterColors.series1,
|
||||||
|
scatterColors.series2,
|
||||||
|
scatterColors.series3,
|
||||||
|
],
|
||||||
grid: {
|
grid: {
|
||||||
borderColor: themeBorderColor,
|
borderColor: themeBorderColor,
|
||||||
xaxis: {
|
xaxis: {
|
||||||
@ -141,10 +166,13 @@ export const getScatterChartConfig = (themeColors: ThemeInstance['themes']['valu
|
|||||||
formatter: (val: string) => parseFloat(val).toFixed(1),
|
formatter: (val: string) => parseFloat(val).toFixed(1),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
export const getLineChartSimpleConfig = (themeColors: ThemeInstance['themes']['value']['colors']) => {
|
export const getLineChartSimpleConfig = (
|
||||||
const { themeBorderColor, themeDisabledTextColor } = colorVariables(themeColors)
|
themeColors: ThemeInstance['themes']['value']['colors']
|
||||||
|
) => {
|
||||||
|
const { themeBorderColor, themeDisabledTextColor } =
|
||||||
|
colorVariables(themeColors);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
chart: {
|
chart: {
|
||||||
@ -174,7 +202,7 @@ export const getLineChartSimpleConfig = (themeColors: ThemeInstance['themes']['v
|
|||||||
custom(data: any) {
|
custom(data: any) {
|
||||||
return `<div class='bar-chart pa-2'>
|
return `<div class='bar-chart pa-2'>
|
||||||
<span>${data.series[data.seriesIndex][data.dataPointIndex]}%</span>
|
<span>${data.series[data.seriesIndex][data.dataPointIndex]}%</span>
|
||||||
</div>`
|
</div>`;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
yaxis: {
|
yaxis: {
|
||||||
@ -210,11 +238,14 @@ export const getLineChartSimpleConfig = (themeColors: ThemeInstance['themes']['v
|
|||||||
'21/12',
|
'21/12',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export const getBarChartConfig = (themeColors: ThemeInstance['themes']['value']['colors']) => {
|
export const getBarChartConfig = (
|
||||||
const { themeBorderColor, themeDisabledTextColor } = colorVariables(themeColors)
|
themeColors: ThemeInstance['themes']['value']['colors']
|
||||||
|
) => {
|
||||||
|
const { themeBorderColor, themeDisabledTextColor } =
|
||||||
|
colorVariables(themeColors);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
chart: {
|
chart: {
|
||||||
@ -248,21 +279,32 @@ export const getBarChartConfig = (themeColors: ThemeInstance['themes']['value'][
|
|||||||
xaxis: {
|
xaxis: {
|
||||||
axisBorder: { show: false },
|
axisBorder: { show: false },
|
||||||
axisTicks: { color: themeBorderColor },
|
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: {
|
labels: {
|
||||||
style: { colors: themeDisabledTextColor },
|
style: { colors: themeDisabledTextColor },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export const getCandlestickChartConfig = (themeColors: ThemeInstance['themes']['value']['colors']) => {
|
export const getCandlestickChartConfig = (
|
||||||
|
themeColors: ThemeInstance['themes']['value']['colors']
|
||||||
|
) => {
|
||||||
const candlestickColors = {
|
const candlestickColors = {
|
||||||
series1: '#28c76f',
|
series1: '#28c76f',
|
||||||
series2: '#ea5455',
|
series2: '#ea5455',
|
||||||
}
|
};
|
||||||
|
|
||||||
const { themeBorderColor, themeDisabledTextColor } = colorVariables(themeColors)
|
const { themeBorderColor, themeDisabledTextColor } =
|
||||||
|
colorVariables(themeColors);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
chart: {
|
chart: {
|
||||||
@ -305,18 +347,21 @@ export const getCandlestickChartConfig = (themeColors: ThemeInstance['themes']['
|
|||||||
style: { colors: themeDisabledTextColor },
|
style: { colors: themeDisabledTextColor },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
export const getRadialBarChartConfig = (themeColors: ThemeInstance['themes']['value']['colors']) => {
|
export const getRadialBarChartConfig = (
|
||||||
|
themeColors: ThemeInstance['themes']['value']['colors']
|
||||||
|
) => {
|
||||||
const radialBarColors = {
|
const radialBarColors = {
|
||||||
series1: '#fdd835',
|
series1: '#fdd835',
|
||||||
series2: '#32baff',
|
series2: '#32baff',
|
||||||
series3: '#00d4bd',
|
series3: '#00d4bd',
|
||||||
series4: '#7367f0',
|
series4: '#7367f0',
|
||||||
series5: '#FFA1A1',
|
series5: '#FFA1A1',
|
||||||
}
|
};
|
||||||
|
|
||||||
const { themeSecondaryTextColor, themePrimaryTextColor } = colorVariables(themeColors)
|
const { themeSecondaryTextColor, themePrimaryTextColor } =
|
||||||
|
colorVariables(themeColors);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
stroke: { lineCap: 'round' },
|
stroke: { lineCap: 'round' },
|
||||||
@ -335,7 +380,11 @@ export const getRadialBarChartConfig = (themeColors: ThemeInstance['themes']['va
|
|||||||
horizontal: 10,
|
horizontal: 10,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
colors: [radialBarColors.series1, radialBarColors.series2, radialBarColors.series4],
|
colors: [
|
||||||
|
radialBarColors.series1,
|
||||||
|
radialBarColors.series2,
|
||||||
|
radialBarColors.series4,
|
||||||
|
],
|
||||||
plotOptions: {
|
plotOptions: {
|
||||||
radialBar: {
|
radialBar: {
|
||||||
hollow: { size: '30%' },
|
hollow: { size: '30%' },
|
||||||
@ -359,16 +408,16 @@ export const getRadialBarChartConfig = (themeColors: ThemeInstance['themes']['va
|
|||||||
|
|
||||||
color: themePrimaryTextColor,
|
color: themePrimaryTextColor,
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
formatter(w: { globals: { seriesTotals: any[]; series: string | any[] } }) {
|
formatter(w: {
|
||||||
const totalValue
|
globals: { seriesTotals: any[]; series: string | any[] };
|
||||||
= w.globals.seriesTotals.reduce((a: number, b: number) => {
|
}) {
|
||||||
return a + b
|
const totalValue =
|
||||||
}, 0) / w.globals.series.length
|
w.globals.seriesTotals.reduce((a: number, b: number) => {
|
||||||
|
return a + b;
|
||||||
|
}, 0) / w.globals.series.length;
|
||||||
|
|
||||||
if (totalValue % 1 === 0)
|
if (totalValue % 1 === 0) return `${totalValue}%`;
|
||||||
return `${totalValue}%`
|
else return `${totalValue.toFixed(2)}%`;
|
||||||
else
|
|
||||||
return `${totalValue.toFixed(2)}%`
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -380,24 +429,33 @@ export const getRadialBarChartConfig = (themeColors: ThemeInstance['themes']['va
|
|||||||
bottom: -30,
|
bottom: -30,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export const getDonutChartConfig = (themeColors: ThemeInstance['themes']['value']['colors'], labels: string[]) => {
|
export const getDonutChartConfig = (
|
||||||
|
themeColors: ThemeInstance['themes']['value']['colors'],
|
||||||
|
labels: string[]
|
||||||
|
) => {
|
||||||
const donutColors = {
|
const donutColors = {
|
||||||
series1: '#fdd835',
|
series1: '#fdd835',
|
||||||
series2: '#00d4bd',
|
series2: '#00d4bd',
|
||||||
series3: '#826bf8',
|
series3: '#826bf8',
|
||||||
series4: '#32baff',
|
series4: '#32baff',
|
||||||
series5: '#ffa1a1',
|
series5: '#ffa1a1',
|
||||||
}
|
};
|
||||||
|
|
||||||
const { themeSecondaryTextColor, themePrimaryTextColor } = colorVariables(themeColors)
|
const { themeSecondaryTextColor, themePrimaryTextColor } =
|
||||||
|
colorVariables(themeColors);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
stroke: { width: 0 },
|
stroke: { width: 0 },
|
||||||
labels,
|
labels,
|
||||||
colors: [donutColors.series1, donutColors.series5, donutColors.series3, donutColors.series2],
|
colors: [
|
||||||
|
donutColors.series1,
|
||||||
|
donutColors.series5,
|
||||||
|
donutColors.series3,
|
||||||
|
donutColors.series2,
|
||||||
|
],
|
||||||
dataLabels: {
|
dataLabels: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
formatter: (val: string) => `${parseInt(val, 10)}%`,
|
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 = {
|
const areaColors = {
|
||||||
series3: '#e0cffe',
|
series3: '#e0cffe',
|
||||||
series2: '#b992fe',
|
series2: '#b992fe',
|
||||||
series1: '#ab7efd',
|
series1: '#ab7efd',
|
||||||
}
|
};
|
||||||
|
|
||||||
const { themeSecondaryTextColor, themeBorderColor, themeDisabledTextColor } = colorVariables(themeColors)
|
const { themeSecondaryTextColor, themeBorderColor, themeDisabledTextColor } =
|
||||||
|
colorVariables(themeColors);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
chart: {
|
chart: {
|
||||||
@ -555,17 +616,20 @@ export const getAreaChartSplineConfig = (themeColors: ThemeInstance['themes']['v
|
|||||||
'19/12',
|
'19/12',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export const getColumnChartConfig = (themeColors: ThemeInstance['themes']['value']['colors']) => {
|
export const getColumnChartConfig = (
|
||||||
|
themeColors: ThemeInstance['themes']['value']['colors']
|
||||||
|
) => {
|
||||||
const columnColors = {
|
const columnColors = {
|
||||||
series1: '#826af9',
|
series1: '#826af9',
|
||||||
series2: '#d2b0ff',
|
series2: '#d2b0ff',
|
||||||
bg: '#f8d3ff',
|
bg: '#f8d3ff',
|
||||||
}
|
};
|
||||||
|
|
||||||
const { themeSecondaryTextColor, themeBorderColor, themeDisabledTextColor } = colorVariables(themeColors)
|
const { themeSecondaryTextColor, themeBorderColor, themeDisabledTextColor } =
|
||||||
|
colorVariables(themeColors);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
chart: {
|
chart: {
|
||||||
@ -602,7 +666,13 @@ export const getColumnChartConfig = (themeColors: ThemeInstance['themes']['value
|
|||||||
colors: {
|
colors: {
|
||||||
backgroundBarRadius: 10,
|
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 },
|
axisBorder: { show: false },
|
||||||
|
|
||||||
axisTicks: { color: themeBorderColor },
|
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: {
|
crosshairs: {
|
||||||
stroke: { color: themeBorderColor },
|
stroke: { color: themeBorderColor },
|
||||||
},
|
},
|
||||||
@ -641,11 +721,14 @@ export const getColumnChartConfig = (themeColors: ThemeInstance['themes']['value
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export const getHeatMapChartConfig = (themeColors: ThemeInstance['themes']['value']['colors']) => {
|
export const getHeatMapChartConfig = (
|
||||||
const { themeSecondaryTextColor, themeDisabledTextColor } = colorVariables(themeColors)
|
themeColors: ThemeInstance['themes']['value']['colors']
|
||||||
|
) => {
|
||||||
|
const { themeSecondaryTextColor, themeDisabledTextColor } =
|
||||||
|
colorVariables(themeColors);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
chart: {
|
chart: {
|
||||||
@ -700,16 +783,19 @@ export const getHeatMapChartConfig = (themeColors: ThemeInstance['themes']['valu
|
|||||||
axisTicks: { show: false },
|
axisTicks: { show: false },
|
||||||
axisBorder: { show: false },
|
axisBorder: { show: false },
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export const getRadarChartConfig = (themeColors: ThemeInstance['themes']['value']['colors']) => {
|
export const getRadarChartConfig = (
|
||||||
|
themeColors: ThemeInstance['themes']['value']['colors']
|
||||||
|
) => {
|
||||||
const radarColors = {
|
const radarColors = {
|
||||||
series1: '#9b88fa',
|
series1: '#9b88fa',
|
||||||
series2: '#ffa1a1',
|
series2: '#ffa1a1',
|
||||||
}
|
};
|
||||||
|
|
||||||
const { themeSecondaryTextColor, themeBorderColor, themeDisabledTextColor } = colorVariables(themeColors)
|
const { themeSecondaryTextColor, themeBorderColor, themeDisabledTextColor } =
|
||||||
|
colorVariables(themeColors);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
chart: {
|
chart: {
|
||||||
@ -759,7 +845,16 @@ export const getRadarChartConfig = (themeColors: ThemeInstance['themes']['value'
|
|||||||
},
|
},
|
||||||
yaxis: { show: false },
|
yaxis: { show: false },
|
||||||
xaxis: {
|
xaxis: {
|
||||||
categories: ['Battery', 'Brand', 'Camera', 'Memory', 'Storage', 'Display', 'OS', 'Price'],
|
categories: [
|
||||||
|
'Battery',
|
||||||
|
'Brand',
|
||||||
|
'Camera',
|
||||||
|
'Memory',
|
||||||
|
'Storage',
|
||||||
|
'Display',
|
||||||
|
'OS',
|
||||||
|
'Price',
|
||||||
|
],
|
||||||
labels: {
|
labels: {
|
||||||
style: {
|
style: {
|
||||||
colors: [
|
colors: [
|
||||||
@ -775,5 +870,5 @@ export const getRadarChartConfig = (themeColors: ThemeInstance['themes']['value'
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
@ -2,9 +2,8 @@
|
|||||||
import { fromBase64, toBase64 } from '@cosmjs/encoding';
|
import { fromBase64, toBase64 } from '@cosmjs/encoding';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
value: { type: Array<Uint8Array>},
|
value: { type: Array<Uint8Array> },
|
||||||
})
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
@ -12,4 +11,4 @@ const props = defineProps({
|
|||||||
{{ toBase64(v) }}
|
{{ toBase64(v) }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -3,19 +3,18 @@ import { useFormatter } from '@/stores';
|
|||||||
import type { Coin } from '@/types';
|
import type { Coin } from '@/types';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
value: { type: Array<Coin>},
|
value: { type: Array<Coin> },
|
||||||
})
|
});
|
||||||
|
|
||||||
const format = useFormatter()
|
|
||||||
|
|
||||||
|
const format = useFormatter();
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
{{ format.formatTokens(value, true, "0,0.[000000]") }}
|
{{ format.formatTokens(value, true, '0,0.[000000]') }}
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
export default {
|
export default {
|
||||||
name: 'ArrayCoinElement'
|
name: 'ArrayCoinElement',
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -3,32 +3,31 @@ import { toBase64 } from '@cosmjs/encoding';
|
|||||||
import type { PropType } from 'vue';
|
import type { PropType } from 'vue';
|
||||||
import { computed } from '@vue/reactivity';
|
import { computed } from '@vue/reactivity';
|
||||||
import DynamicComponentVue from './DynamicComponent.vue';
|
import DynamicComponentVue from './DynamicComponent.vue';
|
||||||
import {select} from './index'
|
import { select } from './index';
|
||||||
import ArrayBytesElement from './ArrayBytesElement.vue';
|
import ArrayBytesElement from './ArrayBytesElement.vue';
|
||||||
import ArrayObjectElement from './ArrayObjectElement.vue';
|
import ArrayObjectElement from './ArrayObjectElement.vue';
|
||||||
import TextElement from './TextElement.vue';
|
import TextElement from './TextElement.vue';
|
||||||
import ArrayCoinElement from './ArrayCoinElement.vue';
|
import ArrayCoinElement from './ArrayCoinElement.vue';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
value: { type: Array<Object>},
|
value: { type: Array<Object> },
|
||||||
})
|
});
|
||||||
|
|
||||||
function selectByElement() {
|
function selectByElement() {
|
||||||
if(props.value && props.value.length > 0) {
|
if (props.value && props.value.length > 0) {
|
||||||
const [first] = props.value
|
const [first] = props.value;
|
||||||
switch(true) {
|
switch (true) {
|
||||||
case first instanceof Uint8Array:
|
case first instanceof Uint8Array:
|
||||||
return ArrayBytesElement
|
return ArrayBytesElement;
|
||||||
case Object.keys(first).includes('denom'):
|
case Object.keys(first).includes('denom'):
|
||||||
return ArrayCoinElement
|
return ArrayCoinElement;
|
||||||
default:
|
default:
|
||||||
return ArrayObjectElement
|
return ArrayObjectElement;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return TextElement
|
return TextElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<Component :is="selectByElement()" :value="props.value"></Component>
|
<Component :is="selectByElement()" :value="props.value"></Component>
|
||||||
</template>
|
</template>
|
||||||
|
@ -6,33 +6,44 @@ const props = defineProps({
|
|||||||
value: { type: null as any },
|
value: { type: null as any },
|
||||||
thead: {
|
thead: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true,
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
const header = computed(() => {
|
const header = computed(() => {
|
||||||
if(props.value && props.value.length > 0) {
|
if (props.value && props.value.length > 0) {
|
||||||
return Object.keys(props.value[0])
|
return Object.keys(props.value[0]);
|
||||||
}
|
}
|
||||||
return []
|
return [];
|
||||||
})
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<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">
|
<thead v-if="thead">
|
||||||
<tr>
|
<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>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="(item, index) in value" :key="index">
|
<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>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</VTable>
|
</VTable>
|
||||||
|
|
||||||
<div v-else class="h-[300px]">
|
<div v-else class="h-[300px]"></div>
|
||||||
|
</template>
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { select } from './index'
|
import { select } from './index';
|
||||||
|
|
||||||
const props = defineProps(["value", "direct"]);
|
const props = defineProps(['value', 'direct']);
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<Component :is="select(value, direct)" :value="value"></Component>
|
<Component :is="select(value, direct)" :value="value"></Component>
|
||||||
</template>
|
</template>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
const props = defineProps(["value"]);
|
const props = defineProps(['value']);
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<span>{{ Number(props.value) }}</span>
|
<span>{{ Number(props.value) }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
@ -1,23 +1,29 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import DynamicComponent from './DynamicComponent.vue';
|
import DynamicComponent from './DynamicComponent.vue';
|
||||||
import {select} from './index'
|
import { select } from './index';
|
||||||
|
|
||||||
const props = defineProps(["value"]);
|
|
||||||
|
|
||||||
|
const props = defineProps(['value']);
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="overflow-x-auto">
|
<div class="overflow-x-auto">
|
||||||
<table class="table w-full text-sm">
|
<table class="table w-full text-sm">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="(v, k) of value">
|
<tr v-for="(v, k) of value">
|
||||||
<td class="text-capitalize" style="max-width: 200px;">{{ k }}</td>
|
<td class="text-capitalize" style="max-width: 200px">{{ k }}</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="overflow-hidden w-auto whitespace-normal" style="max-width: 1000px;">
|
<div
|
||||||
<Component v-if="v" :is="select(v, 'horizontal')" :value="v"></Component>
|
class="overflow-hidden w-auto whitespace-normal"
|
||||||
</div>
|
style="max-width: 1000px"
|
||||||
</td>
|
>
|
||||||
</tr>
|
<Component
|
||||||
</tbody>
|
v-if="v"
|
||||||
</table>
|
:is="select(v, 'horizontal')"
|
||||||
</div>
|
:value="v"
|
||||||
</template>
|
></Component>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
@ -1,17 +1,19 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import DynamicComponent from './DynamicComponent.vue';
|
import DynamicComponent from './DynamicComponent.vue';
|
||||||
import {select} from './index'
|
import { select } from './index';
|
||||||
|
|
||||||
const props = defineProps(["value"]);
|
const props = defineProps(['value']);
|
||||||
const tab = ref("")
|
const tab = ref('');
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<VTabs v-model="tab">
|
<VTabs v-model="tab">
|
||||||
<VTab v-for="(v, k) of value" :value="k">{{ k }}</VTab>
|
<VTab v-for="(v, k) of value" :value="k">{{ k }}</VTab>
|
||||||
</VTabs>
|
</VTabs>
|
||||||
<VWindow v-model="tab" style="min-height: 25px;">
|
<VWindow v-model="tab" style="min-height: 25px">
|
||||||
<VWindowItem v-for="(v, k) of value" :value="k"><DynamicComponent :value="v"/></VWindowItem>
|
<VWindowItem v-for="(v, k) of value" :value="k"
|
||||||
</VWindow>
|
><DynamicComponent :value="v"
|
||||||
</div>
|
/></VWindowItem>
|
||||||
</template>
|
</VWindow>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
@ -2,16 +2,23 @@
|
|||||||
import { useFormatter } from '@/stores';
|
import { useFormatter } from '@/stores';
|
||||||
import MdEditor from 'md-editor-v3';
|
import MdEditor from 'md-editor-v3';
|
||||||
|
|
||||||
const props = defineProps(["value"]);
|
const props = defineProps(['value']);
|
||||||
const format = useFormatter()
|
const format = useFormatter();
|
||||||
function isMD() {
|
function isMD() {
|
||||||
if(props.value && (props.value.indexOf("\n") > -1 || props.value.indexOf("\\n") > -1)){
|
if (
|
||||||
return true
|
props.value &&
|
||||||
}
|
(props.value.indexOf('\n') > -1 || props.value.indexOf('\\n') > -1)
|
||||||
return false
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<MdEditor v-if="isMD()" :model-value="format.multiLine(value)" previewOnly></MdEditor>
|
<MdEditor
|
||||||
<span v-else>{{ value }}</span>
|
v-if="isMD()"
|
||||||
</template>
|
:model-value="format.multiLine(value)"
|
||||||
|
previewOnly
|
||||||
|
></MdEditor>
|
||||||
|
<span v-else>{{ value }}</span>
|
||||||
|
</template>
|
||||||
|
@ -1,35 +1,51 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { fromBase64, toBase64 } from '@cosmjs/encoding';
|
import { fromBase64, toBase64 } from '@cosmjs/encoding';
|
||||||
import { decodeTxRaw } from '@cosmjs/proto-signing'
|
import { decodeTxRaw } from '@cosmjs/proto-signing';
|
||||||
import { computed } from '@vue/reactivity';
|
import { computed } from '@vue/reactivity';
|
||||||
import { hashTx } from '@/libs'
|
import { hashTx } from '@/libs';
|
||||||
import { useBlockchain, useFormatter } from '@/stores';
|
import { useBlockchain, useFormatter } from '@/stores';
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
value: { type: Array<string>},
|
value: { type: Array<string> },
|
||||||
});
|
});
|
||||||
|
|
||||||
const txs = computed(() => {
|
const txs = computed(() => {
|
||||||
return props.value?.map(x => ({ hash: hashTx(fromBase64(x)) , tx: decodeTxRaw(fromBase64(x)) })) || []
|
return (
|
||||||
})
|
props.value?.map((x) => ({
|
||||||
|
hash: hashTx(fromBase64(x)),
|
||||||
const format = useFormatter()
|
tx: decodeTxRaw(fromBase64(x)),
|
||||||
const chain = useBlockchain()
|
})) || []
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const format = useFormatter();
|
||||||
|
const chain = useBlockchain();
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<VTable density="compact" v-if="txs.length > 0">
|
<VTable density="compact" v-if="txs.length > 0">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Hash</th><th>Msgs</th><th>Memo</th>
|
<th>Hash</th>
|
||||||
</tr>
|
<th>Msgs</th>
|
||||||
</thead>
|
<th>Memo</th>
|
||||||
<tbody>
|
</tr>
|
||||||
<tr v-for="item in txs">
|
</thead>
|
||||||
<td><RouterLink :to="`/${chain.chainName}/tx/${item.hash}`">{{ item.hash }}</RouterLink></td>
|
<tbody>
|
||||||
<td>{{ format.messages(item.tx.body.messages.map(x => ({"@type": x.typeUrl}))) }}</td>
|
<tr v-for="item in txs">
|
||||||
<td>{{ item.tx.body.memo }}</td>
|
<td>
|
||||||
</tr>
|
<RouterLink :to="`/${chain.chainName}/tx/${item.hash}`">{{
|
||||||
</tbody>
|
item.hash
|
||||||
</VTable>
|
}}</RouterLink>
|
||||||
<div v-else>[]</div>
|
</td>
|
||||||
</template>
|
<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 { toBase64, toHex } from '@cosmjs/encoding';
|
||||||
import { computed } from '@vue/reactivity';
|
import { computed } from '@vue/reactivity';
|
||||||
|
|
||||||
const props = defineProps(["value"]);
|
const props = defineProps(['value']);
|
||||||
const format = ref('base64')
|
const format = ref('base64');
|
||||||
const text = computed(()=> {
|
const text = computed(() => {
|
||||||
return format.value === 'hex'? toHex(props.value) : toBase64(props.value)
|
return format.value === 'hex' ? toHex(props.value) : toBase64(props.value);
|
||||||
})
|
});
|
||||||
function change() {
|
function change() {
|
||||||
format.value = format.value === 'hex'? 'base64': 'hex'
|
format.value = format.value === 'hex' ? 'base64' : 'hex';
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<span>{{ text }} <VIcon size="12" icon="mdi-cached" @click="change()"/></span>
|
<span
|
||||||
</template>
|
>{{ text }} <VIcon size="12" icon="mdi-cached" @click="change()"
|
||||||
|
/></span>
|
||||||
|
</template>
|
||||||
|
@ -1,39 +1,39 @@
|
|||||||
import ObjectElement from './ObjectElement.vue'
|
import ObjectElement from './ObjectElement.vue';
|
||||||
import TextElement from './TextElement.vue'
|
import TextElement from './TextElement.vue';
|
||||||
import ArrayElement from './ArrayElement.vue'
|
import ArrayElement from './ArrayElement.vue';
|
||||||
import UInt8Array from './UInt8Array.vue'
|
import UInt8Array from './UInt8Array.vue';
|
||||||
import NumberElement from './NumberElement.vue'
|
import NumberElement from './NumberElement.vue';
|
||||||
import TxsElement from './TxsElement.vue'
|
import TxsElement from './TxsElement.vue';
|
||||||
import ObjectHorizontalElement from './ObjectHorizontalElement.vue'
|
import ObjectHorizontalElement from './ObjectHorizontalElement.vue';
|
||||||
import Long from 'long'
|
import Long from 'long';
|
||||||
|
|
||||||
export function select(v: any, direct?: string) {
|
export function select(v: any, direct?: string) {
|
||||||
// if(k === 'txs' && v) {
|
// if(k === 'txs' && v) {
|
||||||
// return TxsElement
|
// return TxsElement
|
||||||
// } else {
|
// } else {
|
||||||
const type = typeof v
|
const type = typeof v;
|
||||||
switch(type) {
|
switch (type) {
|
||||||
case 'object':
|
case 'object':
|
||||||
return selectObject(v, direct)
|
return selectObject(v, direct);
|
||||||
case 'number':
|
case 'number':
|
||||||
return NumberElement
|
return NumberElement;
|
||||||
default:
|
default:
|
||||||
return TextElement
|
return TextElement;
|
||||||
}
|
}
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectObject(v: Object, direct?: string) {
|
function selectObject(v: Object, direct?: string) {
|
||||||
switch(true) {
|
switch (true) {
|
||||||
case v instanceof Long:
|
case v instanceof Long:
|
||||||
return NumberElement
|
return NumberElement;
|
||||||
case v instanceof Uint8Array:
|
case v instanceof Uint8Array:
|
||||||
return UInt8Array
|
return UInt8Array;
|
||||||
case Array.isArray(v):
|
case Array.isArray(v):
|
||||||
return ArrayElement
|
return ArrayElement;
|
||||||
case direct === 'horizontal':
|
case direct === 'horizontal':
|
||||||
return ObjectHorizontalElement
|
return ObjectHorizontalElement;
|
||||||
default:
|
default:
|
||||||
return ObjectElement
|
return ObjectElement;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
<template>
|
<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
|
<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"
|
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>
|
<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
|
<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"
|
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>
|
<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
|
<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"
|
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>
|
<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
|
<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"
|
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">
|
<script lang="ts">
|
||||||
import { useSkins } from '@core/composable/useSkins'
|
import { useSkins } from '@core/composable/useSkins';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
setup() {
|
setup() {
|
||||||
const routerView = resolveComponent('router-view')
|
const routerView = resolveComponent('router-view');
|
||||||
const { injectSkinClasses } = useSkins()
|
const { injectSkinClasses } = useSkins();
|
||||||
|
|
||||||
// ℹ️ This will inject classes in body tag for accurate styling
|
// ℹ️ 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>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
@ -4,22 +4,27 @@ import { computed } from '@vue/reactivity';
|
|||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
const chain = useBlockchain()
|
const chain = useBlockchain();
|
||||||
const route = useRoute()
|
const route = useRoute();
|
||||||
const i18n = useI18n()
|
const i18n = useI18n();
|
||||||
/// To display human readable module name, we have to set the prefix("module.") + route name to the key in i18n.
|
/// 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'
|
/// such as `module.chain` = 'Dashboard'
|
||||||
const moduleName = computed(() => i18n.t(`module.${route.name?.toString()||''}`))
|
const moduleName = computed(() =>
|
||||||
const items = computed(() => [{title: String(chain.name).toUpperCase(), href: `/${chain.name}`}, moduleName.value])
|
i18n.t(`module.${route.name?.toString() || ''}`)
|
||||||
|
);
|
||||||
|
const items = computed(() => [
|
||||||
|
{ title: String(chain.name).toUpperCase(), href: `/${chain.name}` },
|
||||||
|
moduleName.value,
|
||||||
|
]);
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="d-flex flex-rows align-center">
|
<div class="d-flex flex-rows align-center">
|
||||||
<span class="text-h5 mr-3">{{ moduleName }}</span>
|
<span class="text-h5 mr-3">{{ moduleName }}</span>
|
||||||
<v-icon icon="mdi-dots-vertical" />
|
<v-icon icon="mdi-dots-vertical" />
|
||||||
<VBreadcrumbs :items="items">
|
<VBreadcrumbs :items="items">
|
||||||
<template v-slot:divider>
|
<template v-slot:divider>
|
||||||
<v-icon icon="mdi-chevron-right"></v-icon>
|
<v-icon icon="mdi-chevron-right"></v-icon>
|
||||||
</template>
|
</template>
|
||||||
</VBreadcrumbs>
|
</VBreadcrumbs>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -1,61 +1,72 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|
||||||
import { useBlockchain, useBaseStore } from '@/stores';
|
import { useBlockchain, useBaseStore } from '@/stores';
|
||||||
const chainStore = useBlockchain()
|
const chainStore = useBlockchain();
|
||||||
const baseStore = useBaseStore()
|
const baseStore = useBaseStore();
|
||||||
chainStore.initial()
|
chainStore.initial();
|
||||||
chainStore.$subscribe((m, s) => {
|
chainStore.$subscribe((m, s) => {
|
||||||
if(!Array.isArray(m.events) && m.events.key === 'endpoint') {
|
if (!Array.isArray(m.events) && m.events.key === 'endpoint') {
|
||||||
chainStore.initial()
|
chainStore.initial();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<VListItem class="m-0 p-0">
|
<VListItem class="m-0 p-0">
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<VBadge
|
<VBadge
|
||||||
dot
|
dot
|
||||||
location="bottom right"
|
location="bottom right"
|
||||||
offset-x="3"
|
offset-x="3"
|
||||||
offset-y="3"
|
offset-y="3"
|
||||||
bordered
|
bordered
|
||||||
color="success"
|
color="success"
|
||||||
class="mr-2"
|
class="mr-2"
|
||||||
>
|
|
||||||
<VAvatar
|
|
||||||
class="cursor-pointer"
|
|
||||||
color="primary"
|
|
||||||
variant="tonal"
|
|
||||||
>
|
>
|
||||||
<VImg :src="chainStore.logo" />
|
<VAvatar class="cursor-pointer" color="primary" variant="tonal">
|
||||||
|
<VImg :src="chainStore.logo" />
|
||||||
|
|
||||||
<!-- SECTION Menu -->
|
<!-- SECTION Menu -->
|
||||||
<VMenu
|
<VMenu activator="parent" location="bottom start" offset="14px">
|
||||||
activator="parent"
|
<VList>
|
||||||
location="bottom start"
|
<!-- 👉 Rest -->
|
||||||
offset="14px"
|
<VListSubheader
|
||||||
>
|
v-if="chainStore.current?.endpoints?.rest"
|
||||||
<VList>
|
title="Rest Endpoint"
|
||||||
<!-- 👉 Rest -->
|
/>
|
||||||
<VListSubheader v-if="chainStore.current?.endpoints?.rest" title="Rest Endpoint" />
|
<VListItem
|
||||||
<VListItem v-for="i in chainStore.current?.endpoints?.rest" link @click="chainStore.setRestEndpoint(i)">
|
v-for="i in chainStore.current?.endpoints?.rest"
|
||||||
<VListItemTitle>{{ i.provider }} <VIcon v-if="i.address === chainStore.endpoint?.address" icon="mdi-check" color="success" /></VListItemTitle>
|
link
|
||||||
<VListItemSubtitle>{{ i.address }}</VListItemSubtitle>
|
@click="chainStore.setRestEndpoint(i)"
|
||||||
</VListItem>
|
>
|
||||||
|
<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" />
|
<VListSubheader
|
||||||
<VListItem v-for="i in chainStore.current?.endpoints?.grpc" link>
|
v-if="chainStore.current?.endpoints?.grpc"
|
||||||
<VListItemTitle>{{ i.provider }}</VListItemTitle>
|
title="gRPC Endpoint"
|
||||||
<VListItemSubtitle>{{ i.address }}</VListItemSubtitle>
|
/>
|
||||||
</VListItem>
|
<VListItem v-for="i in chainStore.current?.endpoints?.grpc" link>
|
||||||
</VList>
|
<VListItemTitle>{{ i.provider }}</VListItemTitle>
|
||||||
</VMenu>
|
<VListItemSubtitle>{{ i.address }}</VListItemSubtitle>
|
||||||
<!-- !SECTION -->
|
</VListItem>
|
||||||
</VAvatar>
|
</VList>
|
||||||
</VBadge>
|
</VMenu>
|
||||||
</template>
|
<!-- !SECTION -->
|
||||||
<VListItemTitle>{{ baseStore.latest.block?.header?.chain_id || chainStore.chainName || '' }}</VListItemTitle>
|
</VAvatar>
|
||||||
<VListItemSubtitle> {{ chainStore.connErr|| chainStore.endpoint.address }}</VListItemSubtitle>
|
</VBadge>
|
||||||
|
</template>
|
||||||
|
<VListItemTitle>{{
|
||||||
|
baseStore.latest.block?.header?.chain_id || chainStore.chainName || ''
|
||||||
|
}}</VListItemTitle>
|
||||||
|
<VListItemSubtitle>
|
||||||
|
{{ chainStore.connErr || chainStore.endpoint.address }}</VListItemSubtitle
|
||||||
|
>
|
||||||
</VListItem>
|
</VListItem>
|
||||||
</template>
|
</template>
|
||||||
|
@ -67,7 +67,7 @@ blockchain.$subscribe((m, s) => {
|
|||||||
<NavBarNotifications class="hidden md:inline-block" />
|
<NavBarNotifications class="hidden md:inline-block" />
|
||||||
<NavBarI18n class="hidden md:inline-block" />
|
<NavBarI18n class="hidden md:inline-block" />
|
||||||
<NavbarThemeSwitcher class="hidden md:inline-block" />
|
<NavbarThemeSwitcher class="hidden md:inline-block" />
|
||||||
<ConnectWallet class="md:inline-block"/>
|
<ConnectWallet class="md:inline-block" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import NavBarI18n from '@core/components/I18n.vue'
|
import NavBarI18n from '@core/components/I18n.vue';
|
||||||
import { useThemeConfig } from '@core/composable/useThemeConfig'
|
import { useThemeConfig } from '@core/composable/useThemeConfig';
|
||||||
import type { I18nLanguage } from '@layouts/types'
|
import type { I18nLanguage } from '@layouts/types';
|
||||||
|
|
||||||
const { isAppRtl } = useThemeConfig()
|
const { isAppRtl } = useThemeConfig();
|
||||||
|
|
||||||
const i18nCompLanguages: I18nLanguage[] = [
|
const i18nCompLanguages: I18nLanguage[] = [
|
||||||
{
|
{
|
||||||
@ -18,17 +18,14 @@ const i18nCompLanguages: I18nLanguage[] = [
|
|||||||
label: 'Arabic',
|
label: 'Arabic',
|
||||||
i18nLang: 'ar',
|
i18nLang: 'ar',
|
||||||
},
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
const handleLangChange = (lang: string) => {
|
const handleLangChange = (lang: string) => {
|
||||||
isAppRtl.value = lang === 'ar'
|
isAppRtl.value = lang === 'ar';
|
||||||
localStorage.setItem('lang', lang)
|
localStorage.setItem('lang', lang);
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<NavBarI18n
|
<NavBarI18n :languages="i18nCompLanguages" @change="handleLangChange" />
|
||||||
:languages="i18nCompLanguages"
|
|
||||||
@change="handleLangChange"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import Notifications from '@core/components/Notifications.vue'
|
import Notifications from '@core/components/Notifications.vue';
|
||||||
import type { Notification } from '@layouts/types'
|
import type { Notification } from '@layouts/types';
|
||||||
|
|
||||||
// Images
|
// Images
|
||||||
import avatar3 from '@images/avatars/avatar-3.png'
|
import avatar3 from '@images/avatars/avatar-3.png';
|
||||||
import avatar4 from '@images/avatars/avatar-4.png'
|
import avatar4 from '@images/avatars/avatar-4.png';
|
||||||
import avatar5 from '@images/avatars/avatar-5.png'
|
import avatar5 from '@images/avatars/avatar-5.png';
|
||||||
import paypal from '@images/svg/paypal.svg'
|
import paypal from '@images/svg/paypal.svg';
|
||||||
|
|
||||||
const notifications = ref<Notification[]>([
|
const notifications = ref<Notification[]>([
|
||||||
{
|
{
|
||||||
@ -50,32 +50,29 @@ const notifications = ref<Notification[]>([
|
|||||||
time: '19 Mar',
|
time: '19 Mar',
|
||||||
isRead: false,
|
isRead: false,
|
||||||
},
|
},
|
||||||
])
|
]);
|
||||||
|
|
||||||
const removeNotification = (notificationId: number) => {
|
const removeNotification = (notificationId: number) => {
|
||||||
notifications.value.forEach((item, index) => {
|
notifications.value.forEach((item, index) => {
|
||||||
if (notificationId === item.id)
|
if (notificationId === item.id) notifications.value.splice(index, 1);
|
||||||
notifications.value.splice(index, 1)
|
});
|
||||||
})
|
};
|
||||||
}
|
|
||||||
|
|
||||||
const markRead = (notificationId: number[]) => {
|
const markRead = (notificationId: number[]) => {
|
||||||
notifications.value.forEach(item => {
|
notifications.value.forEach((item) => {
|
||||||
notificationId.forEach(id => {
|
notificationId.forEach((id) => {
|
||||||
if (id === item.id)
|
if (id === item.id) item.isRead = true;
|
||||||
item.isRead = true
|
});
|
||||||
})
|
});
|
||||||
})
|
};
|
||||||
}
|
|
||||||
|
|
||||||
const markUnRead = (notificationId: number[]) => {
|
const markUnRead = (notificationId: number[]) => {
|
||||||
notifications.value.forEach(item => {
|
notifications.value.forEach((item) => {
|
||||||
notificationId.forEach(id => {
|
notificationId.forEach((id) => {
|
||||||
if (id === item.id)
|
if (id === item.id) item.isRead = false;
|
||||||
item.isRead = false
|
});
|
||||||
})
|
});
|
||||||
})
|
};
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -36,7 +36,7 @@ const shortcuts = [
|
|||||||
subtitle: 'FAQs & Articles',
|
subtitle: 'FAQs & Articles',
|
||||||
to: { name: 'pages-help-center' },
|
to: { name: 'pages-help-center' },
|
||||||
},
|
},
|
||||||
]
|
];
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { ThemeSwitcherTheme } from '@layouts/types'
|
import type { ThemeSwitcherTheme } from '@layouts/types';
|
||||||
import NewThemeSwitcher from '@/components/ThemeSwitcher.vue'
|
import NewThemeSwitcher from '@/components/ThemeSwitcher.vue';
|
||||||
const themes: ThemeSwitcherTheme[] = [
|
const themes: ThemeSwitcherTheme[] = [
|
||||||
{
|
{
|
||||||
name: 'system',
|
name: 'system',
|
||||||
@ -14,11 +14,11 @@ const themes: ThemeSwitcherTheme[] = [
|
|||||||
name: 'dark',
|
name: 'dark',
|
||||||
icon: 'mdi-weather-night',
|
icon: 'mdi-weather-night',
|
||||||
},
|
},
|
||||||
]
|
];
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<NewThemeSwitcher :themes="themes"/>
|
<NewThemeSwitcher :themes="themes" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -1,26 +1,34 @@
|
|||||||
<template>
|
<template>
|
||||||
<footer class="footer items-center p-4 text-base">
|
<footer class="footer items-center p-4 text-base">
|
||||||
<div class="items-center grid-flow-col">
|
<div class="items-center grid-flow-col">
|
||||||
©
|
©
|
||||||
{{ new Date().getFullYear() }}
|
{{ new Date().getFullYear() }}
|
||||||
Made With
|
Made With
|
||||||
<img src="../../assets/images/heart.svg"/>
|
<img src="../../assets/images/heart.svg" />
|
||||||
By
|
By
|
||||||
<a class="link link-info no-underline"
|
<a
|
||||||
href="https://ping.pub"
|
class="link link-info no-underline"
|
||||||
target="_blank"
|
href="https://ping.pub"
|
||||||
rel="noopener noreferrer"
|
target="_blank"
|
||||||
>Ping.pub</a>
|
rel="noopener noreferrer"
|
||||||
</div>
|
>Ping.pub</a
|
||||||
<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"
|
</div>
|
||||||
href="https://github.com/ping-pub/explorer/blob/master/LICENSE"
|
<div
|
||||||
target="noopener noreferrer"
|
class="grid-flow-col gap-4 md:place-self-center md:justify-self-end hidden md:grid"
|
||||||
>License</a>
|
>
|
||||||
<a class="link link-info no-underline"
|
<a
|
||||||
href="https://github.com/ping-pub/explorer"
|
class="link link-info no-underline"
|
||||||
target="noopener noreferrer"
|
href="https://github.com/ping-pub/explorer/blob/master/LICENSE"
|
||||||
>Github</a>
|
target="noopener noreferrer"
|
||||||
</div>
|
>License</a
|
||||||
</footer>
|
>
|
||||||
</template>
|
<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 {
|
||||||
import { Ripemd160, sha256 } from '@cosmjs/crypto'
|
fromBase64,
|
||||||
|
fromBech32,
|
||||||
|
fromHex,
|
||||||
|
toBase64,
|
||||||
|
toBech32,
|
||||||
|
toHex,
|
||||||
|
} from '@cosmjs/encoding';
|
||||||
|
import { Ripemd160, sha256 } from '@cosmjs/crypto';
|
||||||
|
|
||||||
export function decodeAddress(address: string) {
|
export function decodeAddress(address: string) {
|
||||||
return fromBech32(address)
|
return fromBech32(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function valoperToPrefix(valoper?: string) {
|
export function valoperToPrefix(valoper?: string) {
|
||||||
if(!valoper) return ''
|
if (!valoper) return '';
|
||||||
const prefixIndex = valoper.indexOf('valoper')
|
const prefixIndex = valoper.indexOf('valoper');
|
||||||
if (prefixIndex === -1) return null
|
if (prefixIndex === -1) return null;
|
||||||
return valoper.slice(0, prefixIndex)
|
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function consensusPubkeyToHexAddress(consensusPubkey?: {"@type": string, key: string}) {
|
export function operatorAddressToAccount(operAddress?: string) {
|
||||||
if(!consensusPubkey) return ""
|
if (!operAddress) return '';
|
||||||
let raw = ""
|
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') {
|
if (consensusPubkey['@type'] === '/cosmos.crypto.ed25519.PubKey') {
|
||||||
const pubkey = fromBase64(consensusPubkey.key)
|
const pubkey = fromBase64(consensusPubkey.key);
|
||||||
if(pubkey) return toHex(sha256(pubkey)).slice(0, 40).toUpperCase()
|
if (pubkey) return toHex(sha256(pubkey)).slice(0, 40).toUpperCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (consensusPubkey['@type'] === '/cosmos.crypto.secp256k1.PubKey') {
|
if (consensusPubkey['@type'] === '/cosmos.crypto.secp256k1.PubKey') {
|
||||||
const pubkey = fromBase64(consensusPubkey.key)
|
const pubkey = fromBase64(consensusPubkey.key);
|
||||||
if(pubkey) return toHex(new Ripemd160().update(sha256(pubkey)).digest())
|
if (pubkey) return toHex(new Ripemd160().update(sha256(pubkey)).digest());
|
||||||
}
|
}
|
||||||
return raw
|
return raw;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function pubKeyToValcons(consensusPubkey: {"@type": string, key: string}, prefix: string) {
|
export function pubKeyToValcons(
|
||||||
if(consensusPubkey && consensusPubkey.key) {
|
consensusPubkey: { '@type': string; key: string },
|
||||||
const pubkey = fromBase64(consensusPubkey.key)
|
prefix: string
|
||||||
if(pubkey) {
|
) {
|
||||||
const addressData = sha256(pubkey).slice(0, 20)
|
if (consensusPubkey && consensusPubkey.key) {
|
||||||
return toBech32(`${prefix}valcons`, addressData)
|
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) {
|
export function valconsToBase64(address: string) {
|
||||||
if(address) return toHex(fromBech32(address).data).toUpperCase()
|
if (address) return toHex(fromBech32(address).data).toUpperCase();
|
||||||
return ''
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function toETHAddress(cosmosAddress: string) {
|
export function toETHAddress(cosmosAddress: string) {
|
||||||
return `0x${toHex(fromBech32(cosmosAddress).data)}`
|
return `0x${toHex(fromBech32(cosmosAddress).data)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function addressEnCode(prefix: string, pubkey: Uint8Array) {
|
export function addressEnCode(prefix: string, pubkey: Uint8Array) {
|
||||||
return toBech32(prefix, pubkey)
|
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 = {
|
export const DEFAULT: RequestRegistry = {
|
||||||
auth_params: { url: "/cosmos/auth/v1beta1/params", adapter },
|
auth_params: { url: '/cosmos/auth/v1beta1/params', adapter },
|
||||||
auth_accounts: { url: "/cosmos/auth/v1beta1/accounts", adapter },
|
auth_accounts: { url: '/cosmos/auth/v1beta1/accounts', adapter },
|
||||||
auth_account_address: { url: "/cosmos/auth/v1beta1/accounts/{address}", adapter },
|
auth_account_address: {
|
||||||
bank_params: { url: "/cosmos/bank/v1beta1/params", adapter },
|
url: '/cosmos/auth/v1beta1/accounts/{address}',
|
||||||
bank_balances_address: { url: "/cosmos/bank/v1beta1/balances/{address}", adapter },
|
adapter,
|
||||||
bank_denoms_metadata: { url: "/cosmos/bank/v1beta1/denoms_metadata", adapter },
|
},
|
||||||
bank_supply: { url: "/cosmos/bank/v1beta1/supply", adapter },
|
bank_params: { url: '/cosmos/bank/v1beta1/params', adapter },
|
||||||
bank_supply_by_denom: { url: "/cosmos/bank/v1beta1/supply/{denom}", adapter },
|
bank_balances_address: {
|
||||||
distribution_params: { url: "/cosmos/distribution/v1beta1/params", adapter },
|
url: '/cosmos/bank/v1beta1/balances/{address}',
|
||||||
distribution_community_pool: { url: "/cosmos/distribution/v1beta1/community_pool", adapter },
|
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 },
|
bank_denoms_metadata: {
|
||||||
distribution_validator_slashes: { url: "/cosmos/distribution/v1beta1/validators/{validator_address}/slashes", adapter },
|
url: '/cosmos/bank/v1beta1/denoms_metadata',
|
||||||
distribution_delegator_rewards: { url: "/cosmos/distribution/v1beta1/delegators/{delegator_addr}/rewards", adapter },
|
adapter,
|
||||||
slashing_params: { url: "/cosmos/slashing/v1beta1/params", adapter },
|
},
|
||||||
slashing_signing_info: { url: "/cosmos/slashing/v1beta1/signing_infos", adapter },
|
bank_supply: { url: '/cosmos/bank/v1beta1/supply', adapter },
|
||||||
gov_params_voting: { url: "/cosmos/gov/v1beta1/params/voting", adapter },
|
bank_supply_by_denom: { url: '/cosmos/bank/v1beta1/supply/{denom}', adapter },
|
||||||
gov_params_tally: { url: "/cosmos/gov/v1beta1/params/tallying", adapter },
|
distribution_params: { url: '/cosmos/distribution/v1beta1/params', adapter },
|
||||||
gov_params_deposit: { url: "/cosmos/gov/v1beta1/params/deposit", adapter },
|
distribution_community_pool: {
|
||||||
gov_proposals: { url: "/cosmos/gov/v1beta1/proposals", adapter },
|
url: '/cosmos/distribution/v1beta1/community_pool',
|
||||||
gov_proposals_proposal_id: { url: "/cosmos/gov/v1beta1/proposals/{proposal_id}", adapter },
|
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 },
|
distribution_validator_commission: {
|
||||||
gov_proposals_votes: { url: "/cosmos/gov/v1beta1/proposals/{proposal_id}/votes?pagination.key={next_key}", adapter },
|
url: '/cosmos/distribution/v1beta1/validators/{validator_address}/commission',
|
||||||
gov_proposals_votes_voter: { url: "/cosmos/gov/v1beta1/proposals/{proposal_id}/votes/{voter}", adapter },
|
adapter,
|
||||||
staking_deletations: { url: "/cosmos/staking/v1beta1/delegations/{delegator_addr}", adapter },
|
},
|
||||||
staking_delegator_redelegations: { url: "/cosmos/staking/v1beta1/delegators/{delegator_addr}/redelegations", adapter },
|
distribution_validator_outstanding_rewards: {
|
||||||
staking_delegator_unbonding_delegations: { url: "/cosmos/staking/v1beta1/delegators/{delegator_addr}/unbonding_delegations", adapter },
|
url: '/cosmos/distribution/v1beta1/validators/{validator_address}/outstanding_rewards',
|
||||||
staking_delegator_validators: { url: "/cosmos/staking/v1beta1/delegators/{delegator_addr}/validators", adapter },
|
adapter,
|
||||||
staking_params: { url: "/cosmos/staking/v1beta1/params", adapter },
|
},
|
||||||
staking_pool: { url: "/cosmos/staking/v1beta1/pool", adapter },
|
distribution_validator_slashes: {
|
||||||
staking_validators: { url: "/cosmos/staking/v1beta1/validators?pagination.limit={limit}&status={status}", adapter },
|
url: '/cosmos/distribution/v1beta1/validators/{validator_address}/slashes',
|
||||||
staking_validators_address: { url: "/cosmos/staking/v1beta1/validators/{validator_addr}", adapter },
|
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 },
|
distribution_delegator_rewards: {
|
||||||
staking_validators_delegations_unbonding_delegations: { url: "/cosmos/staking/v1beta1/validators/{validator_addr}/delegations/{delegator_addr}/unbonding_delegation", adapter },
|
url: '/cosmos/distribution/v1beta1/delegators/{delegator_addr}/rewards',
|
||||||
base_tendermint_abci_query: { url: "/cosmos/base/tendermint/v1beta1/abci_query", adapter },
|
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 },
|
slashing_params: { url: '/cosmos/slashing/v1beta1/params', adapter },
|
||||||
base_tendermint_node_info: { url: "/cosmos/base/tendermint/v1beta1/node_info", adapter },
|
slashing_signing_info: {
|
||||||
base_tendermint_validatorsets_latest: { url: "/cosmos/base/tendermint/v1beta1/validatorsets/latest", adapter },
|
url: '/cosmos/slashing/v1beta1/signing_infos',
|
||||||
base_tendermint_validatorsets_height: { url: "/cosmos/base/tendermint/v1beta1/validatorsets/{height}", adapter },
|
adapter,
|
||||||
tx_txs: { url: "/cosmos/tx/v1beta1/txs", adapter },
|
},
|
||||||
tx_txs_block: { url: "/cosmos/tx/v1beta1/txs/block/{height}", adapter },
|
gov_params_voting: { url: '/cosmos/gov/v1beta1/params/voting', adapter },
|
||||||
tx_hash: { url: "/cosmos/tx/v1beta1/txs/{hash}", 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_inflation: { url: '/cosmos/mint/v1beta1/inflation', adapter },
|
||||||
mint_params: { url: "/cosmos/mint/v1beta1/params", adapter },
|
mint_params: { url: '/cosmos/mint/v1beta1/params', adapter },
|
||||||
mint_annual_provisions: { url: "/cosmos/mint/v1beta1/annual_provisions", adapter },
|
mint_annual_provisions: {
|
||||||
|
url: '/cosmos/mint/v1beta1/annual_provisions',
|
||||||
|
adapter,
|
||||||
|
},
|
||||||
|
|
||||||
// ibc
|
// ibc
|
||||||
ibc_app_ica_controller_params: { url: "/ibc/apps/interchain_accounts/controller/v1/params", adapter },
|
ibc_app_ica_controller_params: {
|
||||||
ibc_app_ica_host_params: { url: "/ibc/apps/interchain_accounts/host/v1/params", adapter },
|
url: '/ibc/apps/interchain_accounts/controller/v1/params',
|
||||||
ibc_app_transfer_escrow_address: { url: "/ibc/apps/transfer/v1/channels/{channel_id}/ports/{port_id}/escrow_address", adapter },
|
adapter,
|
||||||
ibc_app_transfer_denom_traces: { url: "/ibc/apps/transfer/v1/denom_traces", adapter },
|
},
|
||||||
ibc_app_transfer_denom_traces_hash: { url: "/ibc/apps/transfer/v1/denom_traces/{hash}", adapter },
|
ibc_app_ica_host_params: {
|
||||||
ibc_core_channel_channels: { url: "/ibc/core/channel/v1/channels", adapter },
|
url: '/ibc/apps/interchain_accounts/host/v1/params',
|
||||||
ibc_core_channel_channels_next_sequence: { url: "/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/next_sequence", adapter },
|
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_app_transfer_escrow_address: {
|
||||||
ibc_core_connection_connections: { url: "/ibc/core/connection/v1/connections", adapter },
|
url: '/ibc/apps/transfer/v1/channels/{channel_id}/ports/{port_id}/escrow_address',
|
||||||
ibc_core_connection_connections_connection_id: { url: "/ibc/core/connection/v1/connections/{connection_id}", adapter },
|
adapter,
|
||||||
ibc_core_connection_connections_connection_id_client_state: { url: "/ibc/core/connection/v1/connections/{connection_id}/client_state", 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 = {
|
export const VERSION_REGISTRY: Registry = {
|
||||||
"0.46.1": DEFAULT
|
'0.46.1': DEFAULT,
|
||||||
}
|
};
|
||||||
|
|
||||||
export const NAME_REGISTRY: Registry = {
|
export const NAME_REGISTRY: Registry = {
|
||||||
"evmos": withCustomAdapter(DEFAULT, {})
|
evmos: withCustomAdapter(DEFAULT, {}),
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,205 +1,268 @@
|
|||||||
import { fetchData } from '@/libs';
|
import { fetchData } from '@/libs';
|
||||||
import { DEFAULT } from '@/libs'
|
import { DEFAULT } from '@/libs';
|
||||||
import { adapter, withCustomAdapter, type Request, type RequestRegistry, type Registry, type AbstractRegistry } from './registry';
|
import {
|
||||||
|
adapter,
|
||||||
|
withCustomAdapter,
|
||||||
|
type Request,
|
||||||
|
type RequestRegistry,
|
||||||
|
type Registry,
|
||||||
|
type AbstractRegistry,
|
||||||
|
} from './registry';
|
||||||
|
|
||||||
export class BaseRestClient<R extends AbstractRegistry> {
|
export class BaseRestClient<R extends AbstractRegistry> {
|
||||||
endpoint: string;
|
endpoint: string;
|
||||||
registry: R;
|
registry: R;
|
||||||
constructor(endpoint: string, registry: R) {
|
constructor(endpoint: string, registry: R) {
|
||||||
this.endpoint = endpoint
|
this.endpoint = endpoint;
|
||||||
this.registry = registry
|
this.registry = registry;
|
||||||
}
|
}
|
||||||
async request<T>(request: Request<T>, args: Record<string, any>, query="") {
|
async request<T>(request: Request<T>, args: Record<string, any>, query = '') {
|
||||||
let url = `${this.endpoint}${request.url}${query}`
|
let url = `${this.endpoint}${request.url}${query}`;
|
||||||
Object.keys(args).forEach(k => {
|
Object.keys(args).forEach((k) => {
|
||||||
url = url.replace(`{${k}}`, args[k] || "")
|
url = url.replace(`{${k}}`, args[k] || '');
|
||||||
})
|
});
|
||||||
return fetchData<T>(url, adapter)
|
return fetchData<T>(url, adapter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CosmosRestClient extends BaseRestClient<RequestRegistry> {
|
export class CosmosRestClient extends BaseRestClient<RequestRegistry> {
|
||||||
// Auth Module
|
// Auth Module
|
||||||
async getAuthAccounts() {
|
async getAuthAccounts() {
|
||||||
return this.request(this.registry.auth_accounts, {})
|
return this.request(this.registry.auth_accounts, {});
|
||||||
}
|
}
|
||||||
async getAuthAccount(address: string) {
|
async getAuthAccount(address: string) {
|
||||||
return this.request(this.registry.auth_account_address, {address})
|
return this.request(this.registry.auth_account_address, { address });
|
||||||
}
|
}
|
||||||
// Bank Module
|
// Bank Module
|
||||||
async getBankParams() {
|
async getBankParams() {
|
||||||
return this.request(this.registry.bank_params, {})
|
return this.request(this.registry.bank_params, {});
|
||||||
}
|
}
|
||||||
async getBankBalances(address: string) {
|
async getBankBalances(address: string) {
|
||||||
return this.request(this.registry.bank_balances_address, {address})
|
return this.request(this.registry.bank_balances_address, { address });
|
||||||
}
|
}
|
||||||
async getBankDenomMetadata() {
|
async getBankDenomMetadata() {
|
||||||
return this.request(this.registry.bank_denoms_metadata, {})
|
return this.request(this.registry.bank_denoms_metadata, {});
|
||||||
}
|
}
|
||||||
async getBankSupply() {
|
async getBankSupply() {
|
||||||
return this.request(this.registry.bank_supply, {})
|
return this.request(this.registry.bank_supply, {});
|
||||||
}
|
}
|
||||||
async getBankSupplyByDenom(denom: string) {
|
async getBankSupplyByDenom(denom: string) {
|
||||||
return this.request(this.registry.bank_supply_by_denom, {denom})
|
return this.request(this.registry.bank_supply_by_denom, { denom });
|
||||||
}
|
}
|
||||||
// Distribution Module
|
// Distribution Module
|
||||||
async getDistributionParams() {
|
async getDistributionParams() {
|
||||||
return this.request(this.registry.distribution_params, {})
|
return this.request(this.registry.distribution_params, {});
|
||||||
}
|
}
|
||||||
async getDistributionCommunityPool() {
|
async getDistributionCommunityPool() {
|
||||||
return this.request(this.registry.distribution_community_pool, {})
|
return this.request(this.registry.distribution_community_pool, {});
|
||||||
}
|
}
|
||||||
async getDistributionDelegatorRewards(delegator_addr: string) {
|
async getDistributionDelegatorRewards(delegator_addr: string) {
|
||||||
return this.request(this.registry.distribution_delegator_rewards, {delegator_addr})
|
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 getDistributionValidatorCommission(validator_address: string) {
|
||||||
async getDistributionValidatorOutstandingRewards(validator_address: string) {
|
return this.request(this.registry.distribution_validator_commission, {
|
||||||
return this.request(this.registry.distribution_validator_outstanding_rewards, {validator_address})
|
validator_address,
|
||||||
}
|
});
|
||||||
async getDistributionValidatorSlashes(validator_address: string) {
|
}
|
||||||
return this.request(this.registry.distribution_validator_slashes, {validator_address})
|
async getDistributionValidatorOutstandingRewards(validator_address: string) {
|
||||||
}
|
return this.request(
|
||||||
// Slashing
|
this.registry.distribution_validator_outstanding_rewards,
|
||||||
async getSlashingParams() {
|
{ validator_address }
|
||||||
return this.request(this.registry.slashing_params, {})
|
);
|
||||||
}
|
}
|
||||||
async getSlashingSigningInfos() {
|
async getDistributionValidatorSlashes(validator_address: string) {
|
||||||
const query = "?pagination.limit=300"
|
return this.request(this.registry.distribution_validator_slashes, {
|
||||||
return this.request(this.registry.slashing_signing_info, {}, query)
|
validator_address,
|
||||||
}
|
});
|
||||||
// Gov
|
}
|
||||||
async getGovParamsVoting() {
|
// Slashing
|
||||||
return this.request(this.registry.gov_params_voting, {})
|
async getSlashingParams() {
|
||||||
}
|
return this.request(this.registry.slashing_params, {});
|
||||||
async getGovParamsDeposit() {
|
}
|
||||||
return this.request(this.registry.gov_params_deposit, {})
|
async getSlashingSigningInfos() {
|
||||||
}
|
const query = '?pagination.limit=300';
|
||||||
async getGovParamsTally() {
|
return this.request(this.registry.slashing_signing_info, {}, query);
|
||||||
return this.request(this.registry.gov_params_tally, {})
|
}
|
||||||
}
|
// Gov
|
||||||
async getGovProposals(status: string, limit = 50) {
|
async getGovParamsVoting() {
|
||||||
const query = "?proposal_status={status}&pagination.limit={limit}&pagination.reverse=true&pagination.key="
|
return this.request(this.registry.gov_params_voting, {});
|
||||||
return this.request(this.registry.gov_proposals, {status, limit}, query)
|
}
|
||||||
}
|
async getGovParamsDeposit() {
|
||||||
async getGovProposal(proposal_id: string) {
|
return this.request(this.registry.gov_params_deposit, {});
|
||||||
return this.request(this.registry.gov_proposals_proposal_id, {proposal_id})
|
}
|
||||||
}
|
async getGovParamsTally() {
|
||||||
async getGovProposalDeposits(proposal_id: string) {
|
return this.request(this.registry.gov_params_tally, {});
|
||||||
return this.request(this.registry.gov_proposals_deposits, {proposal_id})
|
}
|
||||||
}
|
async getGovProposals(status: string, limit = 50) {
|
||||||
async getGovProposalTally(proposal_id: string) {
|
const query =
|
||||||
return this.request(this.registry.gov_proposals_tally, {proposal_id})
|
'?proposal_status={status}&pagination.limit={limit}&pagination.reverse=true&pagination.key=';
|
||||||
}
|
return this.request(this.registry.gov_proposals, { status, limit }, query);
|
||||||
async getGovProposalVotes(proposal_id: string, next_key?: string) {
|
}
|
||||||
return this.request(this.registry.gov_proposals_votes, {proposal_id, next_key})
|
async getGovProposal(proposal_id: string) {
|
||||||
}
|
return this.request(this.registry.gov_proposals_proposal_id, {
|
||||||
async getGovProposalVotesVoter(proposal_id: string, voter: string ) {
|
proposal_id,
|
||||||
return this.request(this.registry.gov_proposals_votes_voter, {proposal_id, voter})
|
});
|
||||||
}
|
}
|
||||||
// staking
|
async getGovProposalDeposits(proposal_id: string) {
|
||||||
async getStakingDelegations(delegator_addr: string) {
|
return this.request(this.registry.gov_proposals_deposits, { proposal_id });
|
||||||
return this.request(this.registry.staking_deletations, {delegator_addr})
|
}
|
||||||
}
|
async getGovProposalTally(proposal_id: string) {
|
||||||
async getStakingDelegatorRedelegations(delegator_addr: string) {
|
return this.request(this.registry.gov_proposals_tally, { proposal_id });
|
||||||
return this.request(this.registry.staking_delegator_redelegations, {delegator_addr})
|
}
|
||||||
}
|
async getGovProposalVotes(proposal_id: string, next_key?: string) {
|
||||||
async getStakingDelegatorUnbonding(delegator_addr: string) {
|
return this.request(this.registry.gov_proposals_votes, {
|
||||||
return this.request(this.registry.staking_delegator_unbonding_delegations, {delegator_addr})
|
proposal_id,
|
||||||
}
|
next_key,
|
||||||
async getStakingDelegatorValidators(delegator_addr: string) {
|
});
|
||||||
return this.request(this.registry.staking_delegator_validators, {delegator_addr})
|
}
|
||||||
}
|
async getGovProposalVotesVoter(proposal_id: string, voter: string) {
|
||||||
async getStakingParams() {
|
return this.request(this.registry.gov_proposals_votes_voter, {
|
||||||
return this.request(this.registry.staking_params, {})
|
proposal_id,
|
||||||
}
|
voter,
|
||||||
async getStakingPool() {
|
});
|
||||||
return this.request(this.registry.staking_pool, {})
|
}
|
||||||
}
|
// staking
|
||||||
async getStakingValidators(status: string, limit = 200) {
|
async getStakingDelegations(delegator_addr: string) {
|
||||||
return this.request(this.registry.staking_validators, {status, limit})
|
return this.request(this.registry.staking_deletations, { delegator_addr });
|
||||||
}
|
}
|
||||||
async getStakingValidator(validator_addr: string) {
|
async getStakingDelegatorRedelegations(delegator_addr: string) {
|
||||||
return this.request(this.registry.staking_validators_address, {validator_addr})
|
return this.request(this.registry.staking_delegator_redelegations, {
|
||||||
}
|
delegator_addr,
|
||||||
async getStakingValidatorsDelegations(validator_addr: string) {
|
});
|
||||||
return this.request(this.registry.staking_validators_delegations, {validator_addr})
|
}
|
||||||
}
|
async getStakingDelegatorUnbonding(delegator_addr: string) {
|
||||||
async getStakingValidatorsDelegationsDelegator(validator_addr: string, delegator_addr: string) {
|
return this.request(this.registry.staking_delegator_unbonding_delegations, {
|
||||||
return this.request(this.registry.staking_validators_delegations_delegator, {validator_addr, delegator_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})
|
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
|
//tendermint
|
||||||
async getBaseAbciQuery() {
|
async getBaseAbciQuery() {
|
||||||
return this.request(this.registry.base_tendermint_abci_query, {})
|
return this.request(this.registry.base_tendermint_abci_query, {});
|
||||||
}
|
}
|
||||||
async getBaseBlockLatest() {
|
async getBaseBlockLatest() {
|
||||||
return this.request(this.registry.base_tendermint_block_latest, {})
|
return this.request(this.registry.base_tendermint_block_latest, {});
|
||||||
}
|
}
|
||||||
async getBaseBlockAt(height: string|number) {
|
async getBaseBlockAt(height: string | number) {
|
||||||
return this.request(this.registry.base_tendermint_block_height, {height})
|
return this.request(this.registry.base_tendermint_block_height, { height });
|
||||||
}
|
}
|
||||||
async getBaseNodeInfo() {
|
async getBaseNodeInfo() {
|
||||||
return this.request(this.registry.base_tendermint_node_info, {})
|
return this.request(this.registry.base_tendermint_node_info, {});
|
||||||
}
|
}
|
||||||
async getBaseValidatorsetAt(height: string|number) {
|
async getBaseValidatorsetAt(height: string | number) {
|
||||||
return this.request(this.registry.base_tendermint_validatorsets_height, {height})
|
return this.request(this.registry.base_tendermint_validatorsets_height, {
|
||||||
}
|
height,
|
||||||
async getBaseValidatorsetLatest() {
|
});
|
||||||
return this.request(this.registry.base_tendermint_validatorsets_latest, {})
|
}
|
||||||
}
|
async getBaseValidatorsetLatest() {
|
||||||
// tx
|
return this.request(this.registry.base_tendermint_validatorsets_latest, {});
|
||||||
async getTxsBySender(sender: string) {
|
}
|
||||||
const query = `?pagination.reverse=true&events=message.sender='${sender}'`
|
// tx
|
||||||
return this.request(this.registry.tx_txs, {}, query)
|
async getTxsBySender(sender: string) {
|
||||||
}
|
const query = `?pagination.reverse=true&events=message.sender='${sender}'`;
|
||||||
async getTxsAt(height: string|number) {
|
return this.request(this.registry.tx_txs, {}, query);
|
||||||
return this.request(this.registry.tx_txs_block, {height})
|
}
|
||||||
}
|
async getTxsAt(height: string | number) {
|
||||||
async getTx(hash: string) {
|
return this.request(this.registry.tx_txs_block, { height });
|
||||||
return this.request(this.registry.tx_hash, {hash})
|
}
|
||||||
}
|
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})
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// 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);
|
const response = await fetch(url);
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`HTTP error: ${response.status}`);
|
throw new Error(`HTTP error: ${response.status}`);
|
||||||
@ -27,22 +30,22 @@ try {
|
|||||||
// */
|
// */
|
||||||
|
|
||||||
export async function get(url: string) {
|
export async function get(url: string) {
|
||||||
return (await fetch(url)).json()
|
return (await fetch(url)).json();
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function post(url: string, data: any) {
|
export async function post(url: string, data: any) {
|
||||||
const response = await fetch(url, {
|
const response = await fetch(url, {
|
||||||
method: 'POST', // *GET, POST, PUT, DELETE, etc.
|
method: 'POST', // *GET, POST, PUT, DELETE, etc.
|
||||||
// mode: 'cors', // no-cors, *cors, same-origin
|
// mode: 'cors', // no-cors, *cors, same-origin
|
||||||
// credentials: 'same-origin', // redirect: 'follow', // manual, *follow, error
|
// 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
|
// 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: {
|
headers: {
|
||||||
'Content-Type': 'text/plain',
|
'Content-Type': 'text/plain',
|
||||||
Accept: '*/*',
|
Accept: '*/*',
|
||||||
'Accept-Encoding': 'gzip, deflate, br',
|
'Accept-Encoding': 'gzip, deflate, br',
|
||||||
},
|
},
|
||||||
body: JSON.stringify(data), // body data type must match "Content-Type" header
|
body: JSON.stringify(data), // body data type must match "Content-Type" header
|
||||||
})
|
});
|
||||||
// const response = axios.post((config ? config.api : this.config.api) + url, data)
|
// const response = axios.post((config ? config.api : this.config.api) + url, data)
|
||||||
return response.json() // parses JSON response into native JavaScript objects
|
return response.json(); // parses JSON response into native JavaScript objects
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
export * from './address'
|
export * from './address';
|
||||||
export * from './http'
|
export * from './http';
|
||||||
export * from './misc'
|
export * from './misc';
|
||||||
export * from './api'
|
export * from './api';
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
import { sha256 } from "@cosmjs/crypto";
|
import { sha256 } from '@cosmjs/crypto';
|
||||||
import { toHex } from "@cosmjs/encoding";
|
import { toHex } from '@cosmjs/encoding';
|
||||||
|
|
||||||
export function newPageRequest(param: {
|
export function newPageRequest(param: {
|
||||||
key?: Uint8Array,
|
key?: Uint8Array;
|
||||||
limit?: number,
|
limit?: number;
|
||||||
offset?: number,
|
offset?: number;
|
||||||
countTotal?: boolean,
|
countTotal?: boolean;
|
||||||
reverse?: boolean
|
reverse?: boolean;
|
||||||
}) {
|
}) {
|
||||||
return param
|
return param;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function hashTx(raw: Uint8Array) {
|
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 {
|
||||||
import type { BankParams, PaginatedBalances, PaginatedDenomMetadata, PaginatedSupply } from "@/types/bank";
|
AuthAccount,
|
||||||
import type { DistributionParams, PaginatedSlashes } from "@/types/distribution";
|
Block,
|
||||||
import type { GovParams, GovProposal, GovVote, PaginatedProposalDeposit, PaginatedProposalVotes, PaginatedProposals, Tally } from "@/types/gov";
|
ClientStateWithProof,
|
||||||
import type { PaginatedSigningInfo } from "@/types/slashing";
|
Coin,
|
||||||
import type { Delegation, PaginatedDelegations, PaginatedRedelegations, PaginatedUnbonding, PaginatedValdiators, StakingParam, StakingPool, Validator } from "@/types/staking";
|
ConnectionWithProof,
|
||||||
import type { PaginatedTxs, Tx, TxResponse } from "@/types/tx";
|
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> {
|
export interface Request<T> {
|
||||||
url: string,
|
url: string;
|
||||||
adapter: (source: any) => T
|
adapter: (source: any) => T;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AbstractRegistry {
|
export interface AbstractRegistry {
|
||||||
[key: string]: Request<any>
|
[key: string]: Request<any>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// use snake style, since the all return object use snake style.
|
// use snake style, since the all return object use snake style.
|
||||||
export interface RequestRegistry extends AbstractRegistry {
|
export interface RequestRegistry extends AbstractRegistry {
|
||||||
auth_params: Request<any>
|
auth_params: Request<any>;
|
||||||
auth_accounts: Request<PaginabledAccounts>;
|
auth_accounts: Request<PaginabledAccounts>;
|
||||||
auth_account_address: Request<{account: AuthAccount}>;
|
auth_account_address: Request<{ account: AuthAccount }>;
|
||||||
|
|
||||||
bank_params: Request<BankParams>;
|
bank_params: Request<BankParams>;
|
||||||
bank_balances_address: Request<PaginatedBalances>;
|
bank_balances_address: Request<PaginatedBalances>;
|
||||||
bank_denoms_metadata: Request<PaginatedDenomMetadata>;
|
bank_denoms_metadata: Request<PaginatedDenomMetadata>;
|
||||||
bank_supply: Request<PaginatedSupply>;
|
bank_supply: Request<PaginatedSupply>;
|
||||||
bank_supply_by_denom: Request<{amount: Coin}>;
|
bank_supply_by_denom: Request<{ amount: Coin }>;
|
||||||
|
|
||||||
distribution_params: Request<DistributionParams>;
|
distribution_params: Request<DistributionParams>;
|
||||||
distribution_validator_commission: Request<{commission?: {commission?: Coin[]}}>;
|
distribution_validator_commission: Request<{
|
||||||
distribution_validator_outstanding_rewards: Request<{rewards?: {rewards?: Coin[]}}>;
|
commission?: { commission?: Coin[] };
|
||||||
|
}>;
|
||||||
|
distribution_validator_outstanding_rewards: Request<{
|
||||||
|
rewards?: { rewards?: Coin[] };
|
||||||
|
}>;
|
||||||
distribution_validator_slashes: Request<PaginatedSlashes>;
|
distribution_validator_slashes: Request<PaginatedSlashes>;
|
||||||
distribution_community_pool: Request<{pool: Coin[]}>;
|
distribution_community_pool: Request<{ pool: Coin[] }>;
|
||||||
distribution_delegator_rewards: Request<any>;
|
distribution_delegator_rewards: Request<any>;
|
||||||
|
|
||||||
mint_inflation: Request<{inflation: string}>;
|
mint_inflation: Request<{ inflation: string }>;
|
||||||
mint_params: Request<{
|
mint_params: Request<{
|
||||||
params: {
|
params: {
|
||||||
mint_denom: string,
|
mint_denom: string;
|
||||||
blocks_per_year: string
|
blocks_per_year: string;
|
||||||
}
|
};
|
||||||
}>;
|
}>;
|
||||||
mint_annual_provisions: Request<{annual_provisions: string}>
|
mint_annual_provisions: Request<{ annual_provisions: string }>;
|
||||||
|
|
||||||
slashing_params: Request<any>;
|
slashing_params: Request<any>;
|
||||||
slashing_signing_info: Request<PaginatedSigningInfo>;
|
slashing_signing_info: Request<PaginatedSigningInfo>;
|
||||||
|
|
||||||
gov_params_voting: Request<GovParams>;
|
gov_params_voting: Request<GovParams>;
|
||||||
gov_params_tally: Request<GovParams>;
|
gov_params_tally: Request<GovParams>;
|
||||||
gov_params_deposit: Request<GovParams>;
|
gov_params_deposit: Request<GovParams>;
|
||||||
gov_proposals: Request<PaginatedProposals>;
|
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_deposits: Request<PaginatedProposalDeposit>;
|
||||||
gov_proposals_tally: Request<{tally: Tally}>;
|
gov_proposals_tally: Request<{ tally: Tally }>;
|
||||||
gov_proposals_votes: Request<PaginatedProposalVotes>;
|
gov_proposals_votes: Request<PaginatedProposalVotes>;
|
||||||
gov_proposals_votes_voter: Request<{vote: GovVote}>;
|
gov_proposals_votes_voter: Request<{ vote: GovVote }>;
|
||||||
|
|
||||||
staking_deletations: Request<PaginatedDelegations>;
|
staking_deletations: Request<PaginatedDelegations>;
|
||||||
staking_delegator_redelegations: Request<PaginatedRedelegations>;
|
staking_delegator_redelegations: Request<PaginatedRedelegations>;
|
||||||
@ -64,9 +104,11 @@ export interface RequestRegistry extends AbstractRegistry {
|
|||||||
staking_params: Request<StakingParam>;
|
staking_params: Request<StakingParam>;
|
||||||
staking_pool: Request<StakingPool>;
|
staking_pool: Request<StakingPool>;
|
||||||
staking_validators: Request<PaginatedValdiators>;
|
staking_validators: Request<PaginatedValdiators>;
|
||||||
staking_validators_address: Request<{validator: Validator}>;
|
staking_validators_address: Request<{ validator: Validator }>;
|
||||||
staking_validators_delegations: Request<PaginatedDelegations>;
|
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>;
|
staking_validators_delegations_unbonding_delegations: Request<PaginatedUnbonding>;
|
||||||
|
|
||||||
base_tendermint_abci_query: Request<any>;
|
base_tendermint_abci_query: Request<any>;
|
||||||
@ -78,45 +120,50 @@ export interface RequestRegistry extends AbstractRegistry {
|
|||||||
|
|
||||||
tx_txs: Request<PaginatedTxs>;
|
tx_txs: Request<PaginatedTxs>;
|
||||||
tx_txs_block: Request<Tx>;
|
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_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_escrow_address: Request<any>;
|
||||||
ibc_app_transfer_denom_traces: Request<any>;
|
ibc_app_transfer_denom_traces: Request<any>;
|
||||||
ibc_app_transfer_denom_traces_hash: Request<{
|
ibc_app_transfer_denom_traces_hash: Request<{
|
||||||
denom_trace: DenomTrace
|
denom_trace: DenomTrace;
|
||||||
}>;
|
}>;
|
||||||
ibc_core_channel_channels: Request<PaginatedIBCChannels>;
|
ibc_core_channel_channels: Request<PaginatedIBCChannels>;
|
||||||
ibc_core_channel_channels_next_sequence: Request<{
|
ibc_core_channel_channels_next_sequence: Request<{
|
||||||
next_sequence_receive: string,
|
next_sequence_receive: string;
|
||||||
proof: string,
|
proof: string;
|
||||||
proof_height: {
|
proof_height: {
|
||||||
revision_number: string,
|
revision_number: string;
|
||||||
revision_height: string
|
revision_height: string;
|
||||||
}
|
};
|
||||||
}>;
|
}>;
|
||||||
ibc_core_channel_channels_acknowledgements: Request<any>;
|
ibc_core_channel_channels_acknowledgements: Request<any>;
|
||||||
ibc_core_channel_connections_channels: Request<PaginatedIBCChannels>;
|
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: Request<ConnectionWithProof>;
|
||||||
ibc_core_connection_connections_connection_id_client_state: Request<ClientStateWithProof>;
|
ibc_core_connection_connections_connection_id_client_state: Request<ClientStateWithProof>;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function adapter<T>(source: any): T {
|
export function adapter<T>(source: any): T {
|
||||||
return source
|
return source;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Registry {
|
export interface Registry {
|
||||||
[key: string]: RequestRegistry;
|
[key: string]: RequestRegistry;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function withCustomAdapter<T extends RequestRegistry>(target: T, source?: Partial<T>): T {
|
export function withCustomAdapter<T extends RequestRegistry>(
|
||||||
return source ? Object.assign({}, target, source): target;
|
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];
|
const url = registry[name];
|
||||||
if (!url) {
|
if (!url) {
|
||||||
throw new Error(`Unsupported version or name: ${name}`);
|
throw new Error(`Unsupported version or name: ${name}`);
|
||||||
@ -125,7 +172,10 @@ export function findConfigByName(name: string, registry: Registry): RequestRegis
|
|||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function findConfigByVersion(version: string, registry: Registry): RequestRegistry {
|
export function findConfigByVersion(
|
||||||
|
version: string,
|
||||||
|
registry: Registry
|
||||||
|
): RequestRegistry {
|
||||||
let closestVersion: string | null = null;
|
let closestVersion: string | null = null;
|
||||||
|
|
||||||
for (const key in registry) {
|
for (const key in registry) {
|
||||||
|
@ -1,110 +1,157 @@
|
|||||||
export function getLocalObject(name: string) {
|
export function getLocalObject(name: string) {
|
||||||
const text = localStorage.getItem(name)
|
const text = localStorage.getItem(name);
|
||||||
if (text) {
|
if (text) {
|
||||||
return JSON.parse(text)
|
return JSON.parse(text);
|
||||||
}
|
}
|
||||||
return null
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getLocalChains() {
|
export function getLocalChains() {
|
||||||
return 'osmosis'
|
return 'osmosis';
|
||||||
}
|
}
|
||||||
|
|
||||||
export const percent = (num: number) => {
|
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) {
|
amount = Number(Number(tokenAmount)) / 10 ** exp;
|
||||||
const i = count === 0 ? count : Math.floor(Math.log(count) / Math.log(1000))
|
if (amount > 10) {
|
||||||
let result: any = parseFloat((count / (1000 ** i)).toFixed(decimals))
|
if (format) {
|
||||||
if (withAbbr && COUNT_ABBRS[i]) {
|
return numberWithCommas(parseFloat(amount.toFixed(decimals)));
|
||||||
result += `${COUNT_ABBRS[i]}`
|
|
||||||
}
|
}
|
||||||
return result
|
return parseFloat(amount.toFixed(decimals));
|
||||||
}
|
}
|
||||||
|
return parseFloat(amount.toFixed(exp));
|
||||||
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))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function numberWithCommas(x: any) {
|
export function numberWithCommas(x: any) {
|
||||||
const parts = x.toString().split('.')
|
const parts = x.toString().split('.');
|
||||||
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',')
|
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
||||||
return parts.join('.')
|
return parts.join('.');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function tokenFormatter(tokens:any, denoms = {}, decimal = 2) {
|
export function tokenFormatter(tokens: any, denoms = {}, decimal = 2) {
|
||||||
if (Array.isArray(tokens)) {
|
if (Array.isArray(tokens)) {
|
||||||
return tokens.map(t => formatToken(t, denoms, decimal)).join(', ')
|
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 formatTokenDenom(tokenDenom:any) {
|
return formatToken(tokens, denoms, 2);
|
||||||
if (tokenDenom && tokenDenom.code === undefined) {
|
}
|
||||||
let denom = tokenDenom.denom_trace ? tokenDenom.denom_trace.base_denom : tokenDenom
|
export function formatToken(
|
||||||
const chains = getLocalChains()
|
token: any,
|
||||||
const selected = localStorage.getItem('selected_chain')
|
IBCDenom = {},
|
||||||
const selChain = chains[selected]
|
decimals = 2,
|
||||||
const nativeAsset = selChain.assets.find(a => (a.base === denom))
|
withDenom = true
|
||||||
if (nativeAsset) {
|
) {
|
||||||
denom = nativeAsset.symbol
|
if (token) {
|
||||||
} else {
|
const denom = IBCDenom[token.denom] || token.denom;
|
||||||
const config = Object.values(chains)
|
if (withDenom) {
|
||||||
config.forEach(x => {
|
return `${formatTokenAmount(
|
||||||
if (x.assets) {
|
token.amount,
|
||||||
const asset = x.assets.find(a => (a.base === denom))
|
decimals,
|
||||||
if (asset) denom = asset.symbol
|
denom
|
||||||
}
|
)} ${formatTokenDenom(denom)}`;
|
||||||
})
|
|
||||||
}
|
|
||||||
return denom.length > 10 ? `${denom.substring(0, 7).toUpperCase()}..${denom.substring(denom.length - 3)}` : denom.toUpperCase()
|
|
||||||
}
|
}
|
||||||
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) {
|
export function isToken(value: string) {
|
||||||
let is = false
|
let is = false;
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
is = value.findIndex(x => Object.keys(x).includes('denom')) > -1
|
is = value.findIndex((x) => Object.keys(x).includes('denom')) > -1;
|
||||||
} else {
|
} else {
|
||||||
is = Object.keys(value).includes('denom')
|
is = Object.keys(value).includes('denom');
|
||||||
}
|
|
||||||
return is
|
|
||||||
}
|
}
|
||||||
export function isStringArray(value: any) {
|
return is;
|
||||||
let is = false
|
}
|
||||||
if (Array.isArray(value)) {
|
export function isStringArray(value: any) {
|
||||||
is = value.findIndex(x => typeof x === 'string') > -1
|
let is = false;
|
||||||
}
|
if (Array.isArray(value)) {
|
||||||
return is
|
is = value.findIndex((x) => typeof x === 'string') > -1;
|
||||||
}
|
}
|
||||||
|
return is;
|
||||||
|
}
|
||||||
|
|
||||||
export function isHexAddress(v: any) {
|
export function isHexAddress(v: any) {
|
||||||
// const re = /^[A-Z\d]{40}$/
|
// const re = /^[A-Z\d]{40}$/
|
||||||
// return re.test(v)
|
// return re.test(v)
|
||||||
return v.length === 28
|
return v.length === 28;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,290 +1,350 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useBlockchain, useFormatter, useStakingStore } from '@/stores';
|
import { useBlockchain, useFormatter, useStakingStore } from '@/stores';
|
||||||
import DynamicComponent from '@/components/dynamic/DynamicComponent.vue';
|
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 { computed, ref } from '@vue/reactivity';
|
||||||
import 'vue-json-pretty/lib/styles.css';
|
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';
|
import type { Coin } from '@cosmjs/amino';
|
||||||
|
|
||||||
const props = defineProps(['address', 'chain'])
|
const props = defineProps(['address', 'chain']);
|
||||||
|
|
||||||
const blockchain = useBlockchain()
|
const blockchain = useBlockchain();
|
||||||
const stakingStore = useStakingStore()
|
const stakingStore = useStakingStore();
|
||||||
const format = useFormatter()
|
const format = useFormatter();
|
||||||
const account = ref({} as AuthAccount)
|
const account = ref({} as AuthAccount);
|
||||||
const txs = ref({} as TxResponse[])
|
const txs = ref({} as TxResponse[]);
|
||||||
const delegations = ref([] as Delegation[])
|
const delegations = ref([] as Delegation[]);
|
||||||
const rewards = ref({} as DelegatorRewards)
|
const rewards = ref({} as DelegatorRewards);
|
||||||
const balances = ref([] as Coin[])
|
const balances = ref([] as Coin[]);
|
||||||
const unbonding = ref([] as UnbondingResponses[])
|
const unbonding = ref([] as UnbondingResponses[]);
|
||||||
const unbondingTotal = ref(0)
|
const unbondingTotal = ref(0);
|
||||||
const chart = {}
|
const chart = {};
|
||||||
|
|
||||||
const totalAmountByCategory = computed(()=> {
|
const totalAmountByCategory = computed(() => {
|
||||||
let sumDel = 0;
|
let sumDel = 0;
|
||||||
delegations.value?.forEach(x => {
|
delegations.value?.forEach((x) => {
|
||||||
sumDel += Number(x.balance.amount)
|
sumDel += Number(x.balance.amount);
|
||||||
})
|
});
|
||||||
let sumRew = 0
|
let sumRew = 0;
|
||||||
rewards.value?.total?.forEach(x => {
|
rewards.value?.total?.forEach((x) => {
|
||||||
sumRew += Number(x.amount)
|
sumRew += Number(x.amount);
|
||||||
})
|
});
|
||||||
let sumBal = 0
|
let sumBal = 0;
|
||||||
balances.value?.forEach(x => {
|
balances.value?.forEach((x) => {
|
||||||
sumBal += Number(x.amount)
|
sumBal += Number(x.amount);
|
||||||
})
|
});
|
||||||
let sumUn = 0
|
let sumUn = 0;
|
||||||
unbonding.value?.forEach(x => {
|
unbonding.value?.forEach((x) => {
|
||||||
x.entries?.forEach(y => {
|
x.entries?.forEach((y) => {
|
||||||
sumUn += Number(y.balance)
|
sumUn += Number(y.balance);
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
return [sumBal, sumDel, sumRew, sumUn]
|
return [sumBal, sumDel, sumRew, sumUn];
|
||||||
})
|
});
|
||||||
|
|
||||||
const labels = ['Balance', 'Delegation', 'Reward', 'Unbonding']
|
const labels = ['Balance', 'Delegation', 'Reward', 'Unbonding'];
|
||||||
|
|
||||||
const totalAmount= computed(()=> {
|
|
||||||
return totalAmountByCategory.value.reduce((p, c)=> c + p, 0)
|
|
||||||
})
|
|
||||||
|
|
||||||
|
const totalAmount = computed(() => {
|
||||||
|
return totalAmountByCategory.value.reduce((p, c) => c + p, 0);
|
||||||
|
});
|
||||||
|
|
||||||
function loadAccount(address: string) {
|
function loadAccount(address: string) {
|
||||||
blockchain.rpc.getAuthAccount(address).then(x => {
|
blockchain.rpc.getAuthAccount(address).then((x) => {
|
||||||
account.value = x.account
|
account.value = x.account;
|
||||||
})
|
});
|
||||||
blockchain.rpc.getTxsBySender(address).then(x => {
|
blockchain.rpc.getTxsBySender(address).then((x) => {
|
||||||
txs.value = x.tx_responses
|
txs.value = x.tx_responses;
|
||||||
})
|
});
|
||||||
blockchain.rpc.getDistributionDelegatorRewards(address).then(x => {
|
blockchain.rpc.getDistributionDelegatorRewards(address).then((x) => {
|
||||||
rewards.value = x
|
rewards.value = x;
|
||||||
})
|
});
|
||||||
blockchain.rpc.getStakingDelegations(address).then(x => {
|
blockchain.rpc.getStakingDelegations(address).then((x) => {
|
||||||
delegations.value = x.delegation_responses
|
delegations.value = x.delegation_responses;
|
||||||
})
|
});
|
||||||
blockchain.rpc.getBankBalances(address).then(x => {
|
blockchain.rpc.getBankBalances(address).then((x) => {
|
||||||
balances.value = x.balances
|
balances.value = x.balances;
|
||||||
})
|
});
|
||||||
blockchain.rpc.getStakingDelegatorUnbonding(address).then(x => {
|
blockchain.rpc.getStakingDelegatorUnbonding(address).then((x) => {
|
||||||
unbonding.value = x.unbonding_responses
|
unbonding.value = x.unbonding_responses;
|
||||||
x.unbonding_responses?.forEach(y => {
|
x.unbonding_responses?.forEach((y) => {
|
||||||
y.entries.forEach(z => {
|
y.entries.forEach((z) => {
|
||||||
unbondingTotal.value += Number(z.balance)
|
unbondingTotal.value += Number(z.balance);
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
loadAccount(props.address)
|
loadAccount(props.address);
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div v-if="account">
|
<div v-if="account">
|
||||||
<VCard>
|
<VCard>
|
||||||
<VList>
|
<VList>
|
||||||
<VListItem>
|
<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>
|
<template #prepend>
|
||||||
<VAvatar
|
<VAvatar rounded variant="tonal" size="35" color="info">
|
||||||
rounded
|
<VIcon icon="mdi-account-cash" size="20" />
|
||||||
variant="tonal"
|
</VAvatar>
|
||||||
size="45"
|
</template>
|
||||||
color="primary"
|
<VListItemTitle class="text-sm font-weight-semibold">
|
||||||
>
|
{{ format.formatToken(v) }}
|
||||||
<VIcon icon="mdi-qrcode" />
|
</VListItemTitle>
|
||||||
</VAvatar>
|
<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>
|
</template>
|
||||||
|
|
||||||
<VListItemTitle class="text-sm font-weight-semibold">
|
<VListItemTitle class="text-sm font-weight-semibold">
|
||||||
Address:
|
{{ format.formatToken(v.balance) }}
|
||||||
</VListItemTitle>
|
</VListItemTitle>
|
||||||
<VListItemSubtitle class="text-xs">
|
<VListItemSubtitle class="text-xs">
|
||||||
{{ address }}
|
≈${{ 0 }}
|
||||||
</VListItemSubtitle>
|
</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>
|
</VList>
|
||||||
</VCard>
|
<VDivider class="my-2"></VDivider>
|
||||||
|
{{ totalAmount }}
|
||||||
|
</VCol>
|
||||||
|
</VRow>
|
||||||
|
</VCardItem>
|
||||||
|
</VCard>
|
||||||
|
|
||||||
<VCard class="mt-5">
|
<VCard class="my-5">
|
||||||
<VCardTitle>Assets</VCardTitle>
|
<VCardItem>
|
||||||
<VCardItem>
|
<VCardTitle>Delegations</VCardTitle>
|
||||||
<VRow>
|
<VTable>
|
||||||
<VCol cols="12" md="4">
|
<thead>
|
||||||
<DonutChart :series="totalAmountByCategory" :labels="labels"/>
|
<tr>
|
||||||
</VCol>
|
<th>Validator</th>
|
||||||
<VCol cols="12" md="8">
|
<th>Delegation</th>
|
||||||
<VList class="card-list">
|
<th>Rewards</th>
|
||||||
<VListItem v-for="v in balances">
|
<th>Action</th>
|
||||||
<template #prepend>
|
</tr>
|
||||||
<VAvatar
|
</thead>
|
||||||
rounded
|
<tbody>
|
||||||
variant="tonal"
|
<tr v-for="v in delegations">
|
||||||
size="35"
|
<td class="text-caption text-primary">
|
||||||
color="info"
|
<RouterLink
|
||||||
>
|
:to="`/${chain}/staking/${v.delegation.validator_address}`"
|
||||||
<VIcon icon="mdi-account-cash" size="20"/>
|
>{{
|
||||||
</VAvatar>
|
format.validatorFromBech32(v.delegation.validator_address)
|
||||||
</template>
|
}}</RouterLink
|
||||||
<VListItemTitle class="text-sm font-weight-semibold">
|
>
|
||||||
{{ format.formatToken(v) }}
|
</td>
|
||||||
</VListItemTitle>
|
<td>{{ format.formatToken(v.balance, true, '0,0.[00]') }}</td>
|
||||||
<VListItemSubtitle class="text-xs">
|
<td>
|
||||||
≈${{ 0 }}
|
{{
|
||||||
</VListItemSubtitle>
|
format.formatTokens(
|
||||||
<template #append>
|
rewards?.rewards?.find(
|
||||||
<VChip color="primary">{{ format.calculatePercent(v.amount, totalAmount) }}</VChip>
|
(x) =>
|
||||||
</template>
|
x.validator_address === v.delegation.validator_address
|
||||||
</VListItem>
|
)?.reward
|
||||||
<VListItem v-for="v in delegations">
|
)
|
||||||
<template #prepend>
|
}}
|
||||||
<VAvatar
|
</td>
|
||||||
rounded
|
<td>action</td>
|
||||||
variant="tonal"
|
</tr>
|
||||||
size="35"
|
</tbody>
|
||||||
color="warning"
|
</VTable>
|
||||||
>
|
</VCardItem>
|
||||||
<VIcon icon="mdi-user-clock" size="20" />
|
</VCard>
|
||||||
</VAvatar>
|
<VCard class="my-5" v-if="unbonding && unbonding.length > 0">
|
||||||
</template>
|
<VCardItem>
|
||||||
|
<VCardTitle>Unbonding Delegations</VCardTitle>
|
||||||
<VListItemTitle class="text-sm font-weight-semibold">
|
<VTable>
|
||||||
{{ format.formatToken(v.balance) }}
|
<thead>
|
||||||
</VListItemTitle>
|
<tr>
|
||||||
<VListItemSubtitle class="text-xs">
|
<th>Creation Height</th>
|
||||||
≈${{ 0 }}
|
<th>Initial Balance</th>
|
||||||
</VListItemSubtitle>
|
<th>Balance</th>
|
||||||
<template #append>
|
<th>Completion Time</th>
|
||||||
<VChip color="primary">{{ format.calculatePercent(v.balance.amount, totalAmount) }}</VChip>
|
</tr>
|
||||||
</template>
|
</thead>
|
||||||
</VListItem>
|
<tbody>
|
||||||
<VListItem v-for="v in rewards.total">
|
<div v-for="v in unbonding">
|
||||||
<template #prepend>
|
<tr>
|
||||||
<VAvatar
|
<td class="text-caption text-primary">
|
||||||
rounded
|
<RouterLink
|
||||||
variant="tonal"
|
:to="`/${chain}/staking/${v.validator_address}`"
|
||||||
size="35"
|
>{{
|
||||||
color="success"
|
format.validatorFromBech32(v.validator_address)
|
||||||
>
|
}}</RouterLink
|
||||||
<VIcon icon="mdi-account-arrow-up" size="20" />
|
>
|
||||||
</VAvatar>
|
</td>
|
||||||
</template>
|
</tr>
|
||||||
|
<tr v-for="entry in v.entries">
|
||||||
<VListItemTitle class="text-sm font-weight-semibold">
|
<td>{{ entry.creation_height }}</td>
|
||||||
{{ format.formatToken(v) }}
|
<td>
|
||||||
</VListItemTitle>
|
{{
|
||||||
<VListItemSubtitle class="text-xs">
|
format.formatToken(
|
||||||
≈${{ 0 }}
|
{
|
||||||
</VListItemSubtitle>
|
amount: entry.initial_balance,
|
||||||
<template #append>
|
denom: stakingStore.params.bond_denom,
|
||||||
<VChip color="primary">{{ format.calculatePercent(v.amount, totalAmount) }}</VChip>
|
},
|
||||||
</template>
|
true,
|
||||||
</VListItem>
|
'0,0.[00]'
|
||||||
|
)
|
||||||
<VListItem>
|
}}
|
||||||
<template #prepend>
|
</td>
|
||||||
<VAvatar
|
<td>
|
||||||
rounded
|
{{
|
||||||
variant="tonal"
|
format.formatToken(
|
||||||
size="35"
|
{
|
||||||
color="error"
|
amount: entry.balance,
|
||||||
>
|
denom: stakingStore.params.bond_denom,
|
||||||
<VIcon icon="mdi-account-arrow-right" size="20" />
|
},
|
||||||
</VAvatar>
|
true,
|
||||||
</template>
|
'0,0.[00]'
|
||||||
|
)
|
||||||
<VListItemTitle class="text-sm font-weight-semibold">
|
}}
|
||||||
{{ format.formatToken({amount: String(unbondingTotal), denom: stakingStore.params.bond_denom}) }}
|
</td>
|
||||||
</VListItemTitle>
|
<td>{{ format.toDay(entry.completion_time, 'to') }}</td>
|
||||||
<VListItemSubtitle class="text-xs">
|
</tr>
|
||||||
≈${{ 0 }}
|
</div>
|
||||||
</VListItemSubtitle>
|
</tbody>
|
||||||
<template #append>
|
</VTable>
|
||||||
<VChip color="primary">{{ format.calculatePercent(unbondingTotal, totalAmount) }}</VChip>
|
</VCardItem>
|
||||||
</template>
|
</VCard>
|
||||||
</VListItem>
|
<VCard class="my-5">
|
||||||
</VList>
|
<VCardItem>
|
||||||
<VDivider class="my-2"></VDivider>
|
<VCardTitle>Transactions</VCardTitle>
|
||||||
{{ totalAmount }}
|
<VTable>
|
||||||
</VCol>
|
<thead>
|
||||||
</VRow>
|
<tr>
|
||||||
</VCardItem>
|
<th>Height</th>
|
||||||
</VCard>
|
<th>Hash</th>
|
||||||
|
<th>Messages</th>
|
||||||
<VCard class="my-5">
|
<th>Time</th>
|
||||||
<VCardItem>
|
</tr>
|
||||||
<VCardTitle>Delegations</VCardTitle>
|
</thead>
|
||||||
<VTable>
|
<tbody>
|
||||||
<thead>
|
<tr v-for="v in txs">
|
||||||
<tr><th>Validator</th><th>Delegation</th><th>Rewards</th><th>Action</th></tr>
|
<td class="text-sm text-primary">
|
||||||
</thead>
|
<RouterLink :to="`/${chain}/block/${v.height}`">{{
|
||||||
<tbody>
|
v.height
|
||||||
<tr v-for="v in delegations">
|
}}</RouterLink>
|
||||||
<td class="text-caption text-primary"><RouterLink :to="`/${chain}/staking/${v.delegation.validator_address}`">{{ format.validatorFromBech32(v.delegation.validator_address) }}</RouterLink></td>
|
</td>
|
||||||
<td>{{ format.formatToken(v.balance, true, "0,0.[00]") }} </td>
|
<td class="text-truncate" style="max-width: 200px">
|
||||||
<td>{{ format.formatTokens(rewards?.rewards?.find(x => x.validator_address ===v.delegation.validator_address)?.reward) }} </td>
|
{{ v.txhash }}
|
||||||
<td>
|
</td>
|
||||||
action
|
<td>
|
||||||
</td>
|
{{ format.messages(v.tx.body.messages) }}
|
||||||
</tr>
|
<VIcon
|
||||||
</tbody>
|
v-if="v.code === 0"
|
||||||
</VTable>
|
icon="mdi-check"
|
||||||
</VCardItem>
|
color="success"
|
||||||
</VCard>
|
></VIcon>
|
||||||
<VCard class="my-5" v-if="unbonding && unbonding.length > 0">
|
<VIcon v-else icon="mdi-multiply" color="error"></VIcon>
|
||||||
<VCardItem>
|
</td>
|
||||||
<VCardTitle>Unbonding Delegations</VCardTitle>
|
<td>{{ format.toDay(v.timestamp, 'from') }}</td>
|
||||||
<VTable>
|
</tr>
|
||||||
<thead>
|
</tbody>
|
||||||
<tr><th>Creation Height</th><th>Initial Balance</th><th>Balance</th><th>Completion Time</th></tr>
|
</VTable>
|
||||||
</thead>
|
</VCardItem>
|
||||||
<tbody>
|
</VCard>
|
||||||
<div v-for="v in unbonding">
|
<VCard>
|
||||||
<tr>
|
<VCardItem>
|
||||||
<td class="text-caption text-primary"><RouterLink :to="`/${chain}/staking/${v.validator_address}`">{{ format.validatorFromBech32(v.validator_address) }}</RouterLink></td>
|
<VCardTitle>Account</VCardTitle>
|
||||||
</tr>
|
<DynamicComponent :value="account" />
|
||||||
<tr v-for="entry in v.entries">
|
</VCardItem>
|
||||||
<td>{{ entry.creation_height }}</td>
|
</VCard>
|
||||||
<td>{{ format.formatToken({ amount: entry.initial_balance, denom: stakingStore.params.bond_denom }, true, "0,0.[00]") }}</td>
|
</div>
|
||||||
<td>{{ format.formatToken({ amount: entry.balance, denom: stakingStore.params.bond_denom }, true, "0,0.[00]") }}</td>
|
<div v-else>Account does not exists on chain</div>
|
||||||
<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>
|
</template>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.card-list {
|
.card-list {
|
||||||
--v-card-list-gap: 5px;
|
--v-card-list-gap: 5px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -21,21 +21,24 @@ onBeforeRouteUpdate(async (to, from, next) => {
|
|||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="bg-base-100 px-4 pt-3 pb-4 rounded mb-4 shadow">
|
<div class="bg-base-100 px-4 pt-3 pb-4 rounded mb-4 shadow">
|
||||||
<h2 class="card-title flex flex-row justify-between">
|
<h2 class="card-title flex flex-row justify-between">
|
||||||
<p class="">#{{ store.current.block?.header?.height }}</p>
|
<p class="">#{{ store.current.block?.header?.height }}</p>
|
||||||
<div class="" v-if="props.height">
|
<div class="" v-if="props.height">
|
||||||
<RouterLink :to="`/${store.blockchain.chainName}/block/${height - 1}`"
|
<RouterLink
|
||||||
class="btn btn-primary btn-sm p-1 text-2xl mr-2">
|
:to="`/${store.blockchain.chainName}/block/${height - 1}`"
|
||||||
<Icon icon="mdi-arrow-left" class="w-full h-full"/>
|
class="btn btn-primary btn-sm p-1 text-2xl mr-2"
|
||||||
|
>
|
||||||
|
<Icon icon="mdi-arrow-left" class="w-full h-full" />
|
||||||
</RouterLink>
|
</RouterLink>
|
||||||
<RouterLink :to="`/${store.blockchain.chainName}/block/${height + 1}`"
|
<RouterLink
|
||||||
class="btn btn-primary btn-sm p-1 text-2xl">
|
:to="`/${store.blockchain.chainName}/block/${height + 1}`"
|
||||||
<Icon icon="mdi-arrow-right"/>
|
class="btn btn-primary btn-sm p-1 text-2xl"
|
||||||
|
>
|
||||||
|
<Icon icon="mdi-arrow-right" />
|
||||||
</RouterLink>
|
</RouterLink>
|
||||||
</div>
|
</div>
|
||||||
</h2>
|
</h2>
|
||||||
@ -45,25 +48,17 @@ onBeforeRouteUpdate(async (to, from, next) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bg-base-100 px-4 pt-3 pb-4 rounded mb-4 shadow">
|
<div class="bg-base-100 px-4 pt-3 pb-4 rounded mb-4 shadow">
|
||||||
<h2 class="card-title flex flex-row justify-between">
|
<h2 class="card-title flex flex-row justify-between">Block Header</h2>
|
||||||
Block Header
|
|
||||||
</h2>
|
|
||||||
<DynamicComponent :value="store.current.block?.header" />
|
<DynamicComponent :value="store.current.block?.header" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="bg-base-100 px-4 pt-3 pb-4 rounded mb-4 shadow">
|
<div class="bg-base-100 px-4 pt-3 pb-4 rounded mb-4 shadow">
|
||||||
<h2 class="card-title flex flex-row justify-between">
|
<h2 class="card-title flex flex-row justify-between">Transactions</h2>
|
||||||
Transactions
|
|
||||||
</h2>
|
|
||||||
<TxsElement :value="store.current.block?.data?.txs" />
|
<TxsElement :value="store.current.block?.data?.txs" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="bg-base-100 px-4 pt-3 pb-4 rounded shadow">
|
<div class="bg-base-100 px-4 pt-3 pb-4 rounded shadow">
|
||||||
<h2 class="card-title flex flex-row justify-between">
|
<h2 class="card-title flex flex-row justify-between">Last Commit</h2>
|
||||||
Last Commit
|
|
||||||
</h2>
|
|
||||||
<DynamicComponent :value="store.current.block?.last_commit" />
|
<DynamicComponent :value="store.current.block?.last_commit" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,61 +1,64 @@
|
|||||||
import { defineStore } from "pinia";
|
import { defineStore } from 'pinia';
|
||||||
import { decodeTxRaw, type DecodedTxRaw } from '@cosmjs/proto-signing'
|
import { decodeTxRaw, type DecodedTxRaw } from '@cosmjs/proto-signing';
|
||||||
import { useBlockchain } from "@/stores";
|
import { useBlockchain } from '@/stores';
|
||||||
import { hashTx } from "@/libs";
|
import { hashTx } from '@/libs';
|
||||||
import type { Block } from "@/types";
|
import type { Block } from '@/types';
|
||||||
|
|
||||||
export const useBlockModule = defineStore('blockModule', {
|
export const useBlockModule = defineStore('blockModule', {
|
||||||
state: () => {
|
state: () => {
|
||||||
return {
|
return {
|
||||||
latest: {} as Block,
|
latest: {} as Block,
|
||||||
current: {} as Block,
|
current: {} as Block,
|
||||||
recents: [] as Block[]
|
recents: [] as Block[],
|
||||||
}
|
};
|
||||||
|
},
|
||||||
|
getters: {
|
||||||
|
blockchain() {
|
||||||
|
return useBlockchain();
|
||||||
},
|
},
|
||||||
getters: {
|
blocktime() {
|
||||||
blockchain() {
|
if (this.recents.length < 2) return 6000;
|
||||||
return useBlockchain()
|
return 6000; // todo later
|
||||||
},
|
|
||||||
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
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
actions: {
|
txsInRecents() {
|
||||||
initial() {
|
const txs = [] as { hash: string; tx: DecodedTxRaw }[];
|
||||||
this.clearRecentBlocks()
|
this.recents.forEach((x) =>
|
||||||
this.autoFetch()
|
x.block?.data?.txs.forEach((tx: Uint8Array) =>
|
||||||
},
|
txs.push({
|
||||||
async clearRecentBlocks() {
|
hash: hashTx(tx),
|
||||||
this.recents = []
|
tx: decodeTxRaw(tx),
|
||||||
},
|
})
|
||||||
autoFetch() {
|
)
|
||||||
this.fetchLatest().then(x => {
|
);
|
||||||
const timer = this.autoFetch
|
return txs;
|
||||||
this.latest = x;
|
},
|
||||||
// if(this.recents.length >= 50) this.recents.pop()
|
},
|
||||||
// this.recents.push(x)
|
actions: {
|
||||||
// setTimeout(timer, 6000)
|
initial() {
|
||||||
})
|
this.clearRecentBlocks();
|
||||||
},
|
this.autoFetch();
|
||||||
async fetchLatest() {
|
},
|
||||||
this.latest = await this.blockchain.rpc.getBaseBlockLatest()
|
async clearRecentBlocks() {
|
||||||
if(this.recents.length >= 50) this.recents.shift()
|
this.recents = [];
|
||||||
this.recents.push(this.latest)
|
},
|
||||||
return this.latest
|
autoFetch() {
|
||||||
},
|
this.fetchLatest().then((x) => {
|
||||||
async fetchBlock(height: string) {
|
const timer = this.autoFetch;
|
||||||
this.current = await this.blockchain.rpc.getBaseBlockAt(height)
|
this.latest = x;
|
||||||
return this.current
|
// 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">
|
<table class="table w-full">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th style="position: relative;">Height</th>
|
<th style="position: relative">Height</th>
|
||||||
<th>Hash</th>
|
<th>Hash</th>
|
||||||
<th>Proposer</th>
|
<th>Proposer</th>
|
||||||
<th>Txs</th>
|
<th>Txs</th>
|
||||||
@ -57,11 +57,14 @@ const format = useFormatter();
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</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">
|
<table class="table w-full">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th style="position: relative;">Hash</th>
|
<th style="position: relative">Hash</th>
|
||||||
<th>Messages</th>
|
<th>Messages</th>
|
||||||
<th>Fees</th>
|
<th>Fees</th>
|
||||||
</tr>
|
</tr>
|
||||||
@ -73,7 +76,7 @@ const format = useFormatter();
|
|||||||
item.hash
|
item.hash
|
||||||
}}</RouterLink>
|
}}</RouterLink>
|
||||||
</td>
|
</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>
|
<td>{{ format.formatTokens(item.tx.authInfo.fee?.amount) }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
@ -1,75 +1,113 @@
|
|||||||
import { BaseRestClient } from "@/libs/client";
|
import { BaseRestClient } from '@/libs/client';
|
||||||
import { adapter, type AbstractRegistry, type Request } from "@/libs/registry";
|
import { adapter, type AbstractRegistry, type Request } from '@/libs/registry';
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from 'pinia';
|
||||||
import type { CodeInfo, ContractInfo, PaginabledCodeInfos, PaginabledContractHistory, PaginabledContracts, PaginabledContractStates, WasmParam } from "./types";
|
import type {
|
||||||
import { toBase64 } from "@cosmjs/encoding";
|
CodeInfo,
|
||||||
import { useBlockchain } from "@/stores";
|
ContractInfo,
|
||||||
|
PaginabledCodeInfos,
|
||||||
|
PaginabledContractHistory,
|
||||||
|
PaginabledContracts,
|
||||||
|
PaginabledContractStates,
|
||||||
|
WasmParam,
|
||||||
|
} from './types';
|
||||||
|
import { toBase64 } from '@cosmjs/encoding';
|
||||||
|
import { useBlockchain } from '@/stores';
|
||||||
|
|
||||||
export interface WasmRequestRegistry extends AbstractRegistry {
|
export interface WasmRequestRegistry extends AbstractRegistry {
|
||||||
cosmwasm_code: Request<PaginabledCodeInfos>;
|
cosmwasm_code: Request<PaginabledCodeInfos>;
|
||||||
cosmwasm_code_id: Request<CodeInfo>;
|
cosmwasm_code_id: Request<CodeInfo>;
|
||||||
cosmwasm_code_id_contracts: Request<PaginabledContracts>;
|
cosmwasm_code_id_contracts: Request<PaginabledContracts>;
|
||||||
cosmwasm_param: Request<WasmParam>;
|
cosmwasm_param: Request<WasmParam>;
|
||||||
cosmwasm_contract_address: Request<{address: string, contract_info: ContractInfo}>;
|
cosmwasm_contract_address: Request<{
|
||||||
cosmwasm_contract_address_history: Request<PaginabledContractHistory>;
|
address: string;
|
||||||
cosmwasm_contract_address_raw_query_data: Request<any>;
|
contract_info: ContractInfo;
|
||||||
cosmwasm_contract_address_smart_query_data: Request<any>;
|
}>;
|
||||||
cosmwasm_contract_address_state: Request<PaginabledContractStates>;
|
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 = {
|
export const DEFAULT: WasmRequestRegistry = {
|
||||||
cosmwasm_code: { url: "/cosmwasm/wasm/v1/code", adapter },
|
cosmwasm_code: { url: '/cosmwasm/wasm/v1/code', adapter },
|
||||||
cosmwasm_code_id: { url: "/cosmwasm/wasm/v1/code/{code_id}", 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_code_id_contracts: {
|
||||||
cosmwasm_param: { url: "/cosmwasm/wasm/v1/codes/params", adapter },
|
url: '/cosmwasm/wasm/v1/code/{code_id}/contracts',
|
||||||
cosmwasm_contract_address: { url: "/cosmwasm/wasm/v1/contract/{address}", adapter },
|
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_param: { url: '/cosmwasm/wasm/v1/codes/params', adapter },
|
||||||
cosmwasm_contract_address_smart_query_data: { url: "/cosmwasm/wasm/v1/contract/{address}/smart/{query_data}", adapter },
|
cosmwasm_contract_address: {
|
||||||
cosmwasm_contract_address_state: { url: "/cosmwasm/wasm/v1/contract/{address}/state", adapter }
|
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> {
|
class WasmRestClient extends BaseRestClient<WasmRequestRegistry> {
|
||||||
getWasmCodeList() {
|
getWasmCodeList() {
|
||||||
return this.request(this.registry.cosmwasm_code, {})
|
return this.request(this.registry.cosmwasm_code, {});
|
||||||
}
|
}
|
||||||
getWasmCodeById(code_id: string) {
|
getWasmCodeById(code_id: string) {
|
||||||
return this.request(this.registry.cosmwasm_code, {code_id}) // `code_id` is a param in above url
|
return this.request(this.registry.cosmwasm_code, { code_id }); // `code_id` is a param in above url
|
||||||
}
|
}
|
||||||
getWasmCodeContracts(code_id: string) {
|
getWasmCodeContracts(code_id: string) {
|
||||||
return this.request(this.registry.cosmwasm_code_id_contracts, {code_id})
|
return this.request(this.registry.cosmwasm_code_id_contracts, { code_id });
|
||||||
}
|
}
|
||||||
getWasmParams() {
|
getWasmParams() {
|
||||||
return this.request(this.registry.cosmwasm_param, {})
|
return this.request(this.registry.cosmwasm_param, {});
|
||||||
}
|
}
|
||||||
getWasmContracts(address: string) {
|
getWasmContracts(address: string) {
|
||||||
return this.request(this.registry.cosmwasm_contract_address, {address})
|
return this.request(this.registry.cosmwasm_contract_address, { address });
|
||||||
}
|
}
|
||||||
getWasmContractHistory(address: string) {
|
getWasmContractHistory(address: string) {
|
||||||
return this.request(this.registry.cosmwasm_contract_address_history, {address})
|
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})
|
getWasmContractRawQuery(address: string, query: string) {
|
||||||
}
|
const query_data = toBase64(new TextEncoder().encode(query));
|
||||||
getWasmContractSmartQuery(address: string, query: string) {
|
return this.request(
|
||||||
const query_data = toBase64(new TextEncoder().encode(query))
|
this.registry.cosmwasm_contract_address_raw_query_data,
|
||||||
return this.request(this.registry.cosmwasm_contract_address_smart_query_data, {address, query_data})
|
{ address, query_data }
|
||||||
}
|
);
|
||||||
getWasmContractStates(address: string) {
|
}
|
||||||
return this.request(this.registry.cosmwasm_contract_address_state, {address})
|
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', {
|
export const useWasmStore = defineStore('module-wasm', {
|
||||||
state: () => {
|
state: () => {
|
||||||
return {}
|
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>
|
<script lang="ts" setup>
|
||||||
import { fromHex } from "@cosmjs/encoding";
|
import { fromHex } from '@cosmjs/encoding';
|
||||||
import { useWasmStore } from '../WasmStore';
|
import { useWasmStore } from '../WasmStore';
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import type { ContractInfo, PaginabledContractStates, PaginabledContracts } from '../types';
|
import type {
|
||||||
|
ContractInfo,
|
||||||
|
PaginabledContractStates,
|
||||||
|
PaginabledContracts,
|
||||||
|
} from '../types';
|
||||||
import DynamicComponent from '@/components/dynamic/DynamicComponent.vue';
|
import DynamicComponent from '@/components/dynamic/DynamicComponent.vue';
|
||||||
import type CustomRadiosVue from '@/plugins/vuetify/@core/components/CustomRadios.vue';
|
import type CustomRadiosVue from '@/plugins/vuetify/@core/components/CustomRadios.vue';
|
||||||
import type { CustomInputContent } from '@/plugins/vuetify/@core/types';
|
import type { CustomInputContent } from '@/plugins/vuetify/@core/types';
|
||||||
import { useFormatter } from "@/stores";
|
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()
|
const wasmStore = useWasmStore();
|
||||||
wasmStore.wasmClient.getWasmCodeContracts(props.code_id).then(x =>{
|
wasmStore.wasmClient.getWasmCodeContracts(props.code_id).then((x) => {
|
||||||
response.value = x
|
response.value = x;
|
||||||
})
|
});
|
||||||
const format = useFormatter()
|
const format = useFormatter();
|
||||||
const infoDialog = ref(false)
|
const infoDialog = ref(false);
|
||||||
const stateDialog = ref(false)
|
const stateDialog = ref(false);
|
||||||
const queryDialog = ref(false)
|
const queryDialog = ref(false);
|
||||||
const info = ref({} as ContractInfo)
|
const info = ref({} as ContractInfo);
|
||||||
const state = ref( {} as PaginabledContractStates)
|
const state = ref({} as PaginabledContractStates);
|
||||||
const selected = ref("")
|
const selected = ref('');
|
||||||
|
|
||||||
function showInfo(address: string) {
|
function showInfo(address: string) {
|
||||||
wasmStore.wasmClient.getWasmContracts(address).then(x => {
|
wasmStore.wasmClient.getWasmContracts(address).then((x) => {
|
||||||
info.value = x.contract_info
|
info.value = x.contract_info;
|
||||||
infoDialog.value = true
|
infoDialog.value = true;
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
function showState(address: string) {
|
function showState(address: string) {
|
||||||
wasmStore.wasmClient.getWasmContractStates(address).then(x => {
|
wasmStore.wasmClient.getWasmContractStates(address).then((x) => {
|
||||||
state.value = x
|
state.value = x;
|
||||||
stateDialog.value = true
|
stateDialog.value = true;
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
function showQuery(address: string) {
|
function showQuery(address: string) {
|
||||||
queryDialog.value = true
|
queryDialog.value = true;
|
||||||
selected.value = address
|
selected.value = address;
|
||||||
query.value = ""
|
query.value = '';
|
||||||
result.value = ""
|
result.value = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
function queryContract() {
|
function queryContract() {
|
||||||
try{
|
try {
|
||||||
|
if (selectedRadio.value === 'raw') {
|
||||||
if(selectedRadio.value === 'raw') {
|
wasmStore.wasmClient
|
||||||
wasmStore.wasmClient.getWasmContractRawQuery(selected.value, query.value).then(x => {
|
.getWasmContractRawQuery(selected.value, query.value)
|
||||||
result.value = JSON.stringify(x)
|
.then((x) => {
|
||||||
}).catch(err => {
|
result.value = JSON.stringify(x);
|
||||||
result.value = JSON.stringify(err)
|
})
|
||||||
})
|
.catch((err) => {
|
||||||
} else {
|
result.value = JSON.stringify(err);
|
||||||
wasmStore.wasmClient.getWasmContractSmartQuery(selected.value, query.value).then(x => {
|
});
|
||||||
result.value = JSON.stringify(x)
|
} else {
|
||||||
}).catch(err => {
|
wasmStore.wasmClient
|
||||||
result.value = JSON.stringify(err)
|
.getWasmContractSmartQuery(selected.value, query.value)
|
||||||
})
|
.then((x) => {
|
||||||
}
|
result.value = JSON.stringify(x);
|
||||||
|
})
|
||||||
} catch(err) {
|
.catch((err) => {
|
||||||
result.value = JSON.stringify(err) // not works for now
|
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[] = [
|
const radioContent: CustomInputContent[] = [
|
||||||
@ -77,78 +85,90 @@ const radioContent: CustomInputContent[] = [
|
|||||||
desc: 'Return structure result if possible',
|
desc: 'Return structure result if possible',
|
||||||
value: 'smart',
|
value: 'smart',
|
||||||
},
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
const selectedRadio = ref('raw')
|
|
||||||
const query = ref("")
|
|
||||||
const result = ref("")
|
|
||||||
|
|
||||||
|
const selectedRadio = ref('raw');
|
||||||
|
const query = ref('');
|
||||||
|
const result = ref('');
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<VCard>
|
<VCard>
|
||||||
<VCardTitle>Contract List of Code: {{ props.code_id }}</VCardTitle>
|
<VCardTitle>Contract List of Code: {{ props.code_id }}</VCardTitle>
|
||||||
<VTable>
|
<VTable>
|
||||||
<thead>
|
<thead>
|
||||||
<tr><th>Contract List</th><th>Actions</th></tr>
|
<tr>
|
||||||
</thead>
|
<th>Contract List</th>
|
||||||
<tbody>
|
<th>Actions</th>
|
||||||
<tr v-for="v in response.contracts">
|
</tr>
|
||||||
<td>{{ v }}</td><td>
|
</thead>
|
||||||
<VBtn size="small" @click="showInfo(v)">contract</VBtn>
|
<tbody>
|
||||||
<VBtn size="small" @click="showState(v)" class="ml-2">States</VBtn>
|
<tr v-for="v in response.contracts">
|
||||||
<VBtn size="small" @click="showQuery(v)" class="ml-2">Query</VBtn></td>
|
<td>{{ v }}</td>
|
||||||
</tr>
|
<td>
|
||||||
</tbody>
|
<VBtn size="small" @click="showInfo(v)">contract</VBtn>
|
||||||
</VTable>
|
<VBtn size="small" @click="showState(v)" class="ml-2"
|
||||||
</VCard>
|
>States</VBtn
|
||||||
<v-dialog v-model="infoDialog" width="auto">
|
>
|
||||||
<v-card>
|
<VBtn size="small" @click="showQuery(v)" class="ml-2">Query</VBtn>
|
||||||
<VCardTitle>Contract Detail</VCardTitle>
|
</td>
|
||||||
<v-card-text>
|
</tr>
|
||||||
<DynamicComponent :value="info"/>
|
</tbody>
|
||||||
</v-card-text>
|
</VTable>
|
||||||
<v-card-actions>
|
</VCard>
|
||||||
<v-btn color="primary" block @click="infoDialog = false">Close Dialog</v-btn>
|
<v-dialog v-model="infoDialog" width="auto">
|
||||||
</v-card-actions>
|
<v-card>
|
||||||
</v-card>
|
<VCardTitle>Contract Detail</VCardTitle>
|
||||||
</v-dialog>
|
<v-card-text>
|
||||||
<v-dialog v-model="stateDialog" width="auto">
|
<DynamicComponent :value="info" />
|
||||||
<v-card>
|
</v-card-text>
|
||||||
<VCardTitle>Contract States</VCardTitle>
|
<v-card-actions>
|
||||||
<VList>
|
<v-btn color="primary" block @click="infoDialog = false"
|
||||||
<VListItem v-for="v in state.models">
|
>Close Dialog</v-btn
|
||||||
<VListItemTitle>
|
>
|
||||||
{{ format.hexToString(v.key) }}
|
</v-card-actions>
|
||||||
</VListItemTitle>
|
</v-card>
|
||||||
<VListItemSubtitle :title="format.base64ToString(v.value)">
|
</v-dialog>
|
||||||
{{ format.base64ToString(v.value) }}
|
<v-dialog v-model="stateDialog" width="auto">
|
||||||
</VListItemSubtitle>
|
<v-card>
|
||||||
</VListItem>
|
<VCardTitle>Contract States</VCardTitle>
|
||||||
</VList>
|
<VList>
|
||||||
<v-card-actions>
|
<VListItem v-for="v in state.models">
|
||||||
<v-btn color="primary" block @click="stateDialog = false">Close Dialog</v-btn>
|
<VListItemTitle>
|
||||||
</v-card-actions>
|
{{ format.hexToString(v.key) }}
|
||||||
</v-card>
|
</VListItemTitle>
|
||||||
</v-dialog>
|
<VListItemSubtitle :title="format.base64ToString(v.value)">
|
||||||
<v-dialog v-model="queryDialog" width="auto">
|
{{ format.base64ToString(v.value) }}
|
||||||
<v-card>
|
</VListItemSubtitle>
|
||||||
<VCardTitle>Query Contract</VCardTitle>
|
</VListItem>
|
||||||
<v-card-text>
|
</VList>
|
||||||
<CustomRadios
|
<v-card-actions>
|
||||||
v-model:selected-radio="selectedRadio"
|
<v-btn color="primary" block @click="stateDialog = false"
|
||||||
:radio-content="radioContent"
|
>Close Dialog</v-btn
|
||||||
:grid-column="{ sm: '6', cols: '12' }"
|
>
|
||||||
/>
|
</v-card-actions>
|
||||||
|
</v-card>
|
||||||
<VTextarea v-model="query" label="Query String" class="my-2"/>
|
</v-dialog>
|
||||||
<VTextarea v-model="result" label="Result"/>
|
<v-dialog v-model="queryDialog" width="auto">
|
||||||
</v-card-text>
|
<v-card>
|
||||||
<v-card-actions>
|
<VCardTitle>Query Contract</VCardTitle>
|
||||||
<v-btn color="primary" @click="queryDialog = false">Close Dialog</v-btn>
|
<v-card-text>
|
||||||
<v-btn color="success" @click="queryContract()">Query Contract</v-btn>
|
<CustomRadios
|
||||||
</v-card-actions>
|
v-model:selected-radio="selectedRadio"
|
||||||
</v-card>
|
:radio-content="radioContent"
|
||||||
</v-dialog>
|
:grid-column="{ sm: '6', cols: '12' }"
|
||||||
</div>
|
/>
|
||||||
|
|
||||||
|
<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>
|
</template>
|
||||||
|
@ -4,38 +4,52 @@ import { useWasmStore } from './WasmStore';
|
|||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import type { PaginabledCodeInfos } from './types';
|
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()
|
const wasmStore = useWasmStore();
|
||||||
wasmStore.wasmClient.getWasmCodeList().then(x =>{
|
wasmStore.wasmClient.getWasmCodeList().then((x) => {
|
||||||
codes.value = x
|
codes.value = x;
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<VCard>
|
<VCard>
|
||||||
<VCardTitle>Cosmos Wasm Smart Contracts</VCardTitle>
|
<VCardTitle>Cosmos Wasm Smart Contracts</VCardTitle>
|
||||||
<VTable>
|
<VTable>
|
||||||
<thead>
|
<thead>
|
||||||
<tr><th>Code Id</th><th>Code Hash</th><th>Creator</th><th>Permissions</th></tr>
|
<tr>
|
||||||
</thead>
|
<th>Code Id</th>
|
||||||
<tbody>
|
<th>Code Hash</th>
|
||||||
<tr v-for="v in codes.code_infos">
|
<th>Creator</th>
|
||||||
<td>{{ v.code_id }}</td>
|
<th>Permissions</th>
|
||||||
<td><RouterLink :to="`/${props.chain}/cosmwasm/${v.code_id}/contracts`"><div class="text-truncate" style="max-width: 200px;">{{ v.data_hash }}</div></RouterLink></td>
|
</tr>
|
||||||
<td>{{ v.creator }}</td>
|
</thead>
|
||||||
<td>
|
<tbody>
|
||||||
{{ v.instantiate_permission?.permission }}
|
<tr v-for="v in codes.code_infos">
|
||||||
<span>{{ v.instantiate_permission?.address }} {{ v.instantiate_permission.addresses.join(", ") }}</span>
|
<td>{{ v.code_id }}</td>
|
||||||
|
<td>
|
||||||
</td>
|
<RouterLink
|
||||||
</tr>
|
:to="`/${props.chain}/cosmwasm/${v.code_id}/contracts`"
|
||||||
</tbody>
|
><div class="text-truncate" style="max-width: 200px">
|
||||||
</VTable>
|
{{ v.data_hash }}
|
||||||
</VCard>
|
</div></RouterLink
|
||||||
</div>
|
>
|
||||||
|
</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>
|
</template>
|
||||||
|
|
||||||
<route>
|
<route>
|
||||||
@ -44,4 +58,4 @@ wasmStore.wasmClient.getWasmCodeList().then(x =>{
|
|||||||
i18n: 'cosmwasm'
|
i18n: 'cosmwasm'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</route>
|
</route>
|
||||||
|
@ -1,69 +1,69 @@
|
|||||||
import type { PaginatedResponse } from "@/types"
|
import type { PaginatedResponse } from '@/types';
|
||||||
|
|
||||||
export interface CodeInfo {
|
export interface CodeInfo {
|
||||||
code_id: string,
|
code_id: string;
|
||||||
creator: string,
|
creator: string;
|
||||||
data_hash: string,
|
data_hash: string;
|
||||||
instantiate_permission: {
|
instantiate_permission: {
|
||||||
permission: string,
|
permission: string;
|
||||||
address: string,
|
address: string;
|
||||||
addresses: string[]
|
addresses: string[];
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ContractInfo {
|
export interface ContractInfo {
|
||||||
code_id: string,
|
code_id: string;
|
||||||
creator: string,
|
creator: string;
|
||||||
admin: string,
|
admin: string;
|
||||||
label: string,
|
label: string;
|
||||||
created: {
|
created: {
|
||||||
block_height: string,
|
block_height: string;
|
||||||
tx_index: string
|
tx_index: string;
|
||||||
},
|
};
|
||||||
ibc_port_id: string,
|
ibc_port_id: string;
|
||||||
extension: {
|
extension: {
|
||||||
type_url: string,
|
type_url: string;
|
||||||
value: string
|
value: string;
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WasmParam {
|
export interface WasmParam {
|
||||||
params: {
|
params: {
|
||||||
code_upload_access: {
|
code_upload_access: {
|
||||||
permission: string,
|
permission: string;
|
||||||
address: string,
|
address: string;
|
||||||
addresses: string[]
|
addresses: string[];
|
||||||
},
|
};
|
||||||
instantiate_default_permission: string
|
instantiate_default_permission: string;
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface HistoryEntry {
|
export interface HistoryEntry {
|
||||||
operation: string,
|
operation: string;
|
||||||
code_id: string,
|
code_id: string;
|
||||||
updated: {
|
updated: {
|
||||||
block_height: string,
|
block_height: string;
|
||||||
tx_index: string
|
tx_index: string;
|
||||||
},
|
};
|
||||||
msg: string
|
msg: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Models {
|
export interface Models {
|
||||||
key: string,
|
key: string;
|
||||||
value: string
|
value: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PaginabledContractHistory extends PaginatedResponse {
|
export interface PaginabledContractHistory extends PaginatedResponse {
|
||||||
entries: HistoryEntry[]
|
entries: HistoryEntry[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PaginabledContractStates extends PaginatedResponse {
|
export interface PaginabledContractStates extends PaginatedResponse {
|
||||||
models: Models[]
|
models: Models[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PaginabledCodeInfos extends PaginatedResponse {
|
export interface PaginabledCodeInfos extends PaginatedResponse {
|
||||||
code_infos: CodeInfo[]
|
code_infos: CodeInfo[];
|
||||||
}
|
}
|
||||||
export interface PaginabledContracts extends PaginatedResponse {
|
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 Countdown from '@/components/Countdown.vue';
|
||||||
import { computed } from '@vue/reactivity';
|
import { computed } from '@vue/reactivity';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const props = defineProps(["proposal_id", "chain"]);
|
const props = defineProps(["proposal_id", "chain"]);
|
||||||
const proposal = ref({} as GovProposal)
|
const proposal = ref({} as GovProposal)
|
||||||
const format = useFormatter()
|
const format = useFormatter()
|
||||||
@ -147,7 +145,6 @@ const processList = computed(()=>{
|
|||||||
{name: 'Abstain', value : abstain.value, class: 'bg-warning' }
|
{name: 'Abstain', value : abstain.value, class: 'bg-warning' }
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -6,10 +6,10 @@ const tab = ref('2');
|
|||||||
const store = useGovStore();
|
const store = useGovStore();
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
store.fetchProposals('2').then(x => {
|
store.fetchProposals('2').then((x) => {
|
||||||
if(x.proposals.length ===0 ) {
|
if (x.proposals.length === 0) {
|
||||||
tab.value = "3"
|
tab.value = '3';
|
||||||
store.fetchProposals('3')
|
store.fetchProposals('3');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,108 +1,146 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import DynamicComponent from '@/components/dynamic/DynamicComponent.vue';
|
import DynamicComponent from '@/components/dynamic/DynamicComponent.vue';
|
||||||
import { useBaseStore, useBlockchain, useFormatter } from '@/stores';
|
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 { onMounted } from 'vue';
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
|
|
||||||
const props = defineProps(['chain', 'connection_id'])
|
const props = defineProps(['chain', 'connection_id']);
|
||||||
const chainStore = useBlockchain()
|
const chainStore = useBlockchain();
|
||||||
const baseStore = useBaseStore()
|
const baseStore = useBaseStore();
|
||||||
const conn = ref({} as Connection)
|
const conn = ref({} as Connection);
|
||||||
const clientState = ref({} as {client_id: string, client_state: ClientState})
|
const clientState = ref({} as { client_id: string; client_state: ClientState });
|
||||||
const channels = ref([] as Channel[])
|
const channels = ref([] as Channel[]);
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if(props.connection_id) {
|
if (props.connection_id) {
|
||||||
chainStore.rpc.getIBCConnectionsById(props.connection_id).then(x => {
|
chainStore.rpc.getIBCConnectionsById(props.connection_id).then((x) => {
|
||||||
conn.value = x.connection
|
conn.value = x.connection;
|
||||||
})
|
});
|
||||||
chainStore.rpc.getIBCConnectionsClientState(props.connection_id).then(x => {
|
chainStore.rpc
|
||||||
clientState.value = x.identified_client_state
|
.getIBCConnectionsClientState(props.connection_id)
|
||||||
})
|
.then((x) => {
|
||||||
chainStore.rpc.getIBCConnectionsChannels(props.connection_id).then(x => {
|
clientState.value = x.identified_client_state;
|
||||||
channels.value = x.channels
|
});
|
||||||
})
|
chainStore.rpc.getIBCConnectionsChannels(props.connection_id).then((x) => {
|
||||||
}
|
channels.value = x.channels;
|
||||||
})
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
function loadChannel(channel: string, port: string) {
|
function loadChannel(channel: string, port: string) {
|
||||||
chainStore.rpc.getIBCChannelNextSequence(channel, port).then(x => {
|
chainStore.rpc.getIBCChannelNextSequence(channel, port).then((x) => {
|
||||||
console.log(x)
|
console.log(x);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function color(v: string) {
|
function color(v: string) {
|
||||||
if(v && v.indexOf("_OPEN") > -1) {
|
if (v && v.indexOf('_OPEN') > -1) {
|
||||||
return "success"
|
return 'success';
|
||||||
}
|
}
|
||||||
return "warning"
|
return 'warning';
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="px-4 pt-3 pb-4 bg-base-100 rounded mb-4 shadow py-24 sm:py-32">
|
<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">
|
<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">
|
<dl
|
||||||
<div class="mx-auto flex max-w-xs flex-col gap-y-4">
|
class="grid grid-cols-1 gap-x-8 gap-y-16 text-center lg:grid-cols-3"
|
||||||
<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 class="mx-auto flex max-w-xs flex-col gap-y-4">
|
||||||
</div>
|
<dt class="text-base leading-7 text-gray-600">
|
||||||
<div class="mx-auto flex max-w-xs flex-col gap-y-4">
|
{{ conn.client_id }} {{ props.connection_id }}
|
||||||
<dt class="text-base leading-7 text-gray-600">{{ conn.state }}</dt>
|
</dt>
|
||||||
<dd class="order-first text-3xl font-semibold tracking-tight text-gray-900 sm:text-5xl"> <><VProgressLinear class="w-100" color="success" /></dd>
|
<dd
|
||||||
|
class="order-first text-3xl font-semibold tracking-tight text-gray-900 sm:text-5xl"
|
||||||
</div>
|
>
|
||||||
<div class="mx-auto flex max-w-xs flex-col gap-y-4">
|
{{ baseStore.latest?.block?.header?.chain_id }}
|
||||||
<dt class="text-base leading-7 text-gray-600">{{ conn.counterparty?.connection_id }} {{ clientState.client_id }}</dt>
|
</dd>
|
||||||
<dd class="order-first text-3xl font-semibold tracking-tight text-gray-900 sm:text-5xl">{{clientState.client_state?.chain_id}}</dd>
|
</div>
|
||||||
</div>
|
<div class="mx-auto flex max-w-xs flex-col gap-y-4">
|
||||||
</dl>
|
<dt class="text-base leading-7 text-gray-600">{{ conn.state }}</dt>
|
||||||
</div>
|
<dd
|
||||||
</div>
|
class="order-first text-3xl font-semibold tracking-tight text-gray-900 sm:text-5xl"
|
||||||
|
>
|
||||||
<div class="bg-base-100 px-4 pt-3 pb-4 rounded mb-4 shadow">
|
<><VProgressLinear class="w-100" color="success" />
|
||||||
<h2 class="card-title">IBC Client State </h2>
|
</dd>
|
||||||
<div class="text-sm">
|
</div>
|
||||||
<br>update after expiry: {{ clientState.client_state?.allow_update_after_expiry }}
|
<div class="mx-auto flex max-w-xs flex-col gap-y-4">
|
||||||
<br>allow_update_after_misbehaviour: {{ clientState.client_state?.allow_update_after_misbehaviour }}
|
<dt class="text-base leading-7 text-gray-600">
|
||||||
<br>trust_level: {{ clientState.client_state?.trust_level?.numerator }}/{{ clientState.client_state?.trust_level?.denominator }}
|
{{ conn.counterparty?.connection_id }} {{ clientState.client_id }}
|
||||||
<br>trusting_period: {{ clientState.client_state?.trusting_period }}
|
</dt>
|
||||||
<br>unbonding_period: {{ clientState.client_state?.unbonding_period }}
|
<dd
|
||||||
<br>frozen_height: {{ clientState.client_state?.frozen_height }}
|
class="order-first text-3xl font-semibold tracking-tight text-gray-900 sm:text-5xl"
|
||||||
<br>latest_height: {{ clientState.client_state?.latest_height }}
|
>
|
||||||
<br>type: {{ clientState.client_state?.['@type'] }}
|
{{ clientState.client_state?.chain_id }}
|
||||||
<br>upgrade_path: {{ clientState.client_state?.upgrade_path }}
|
</dd>
|
||||||
<br> {{ clientState.client_state?.max_clock_drift }}
|
</div>
|
||||||
</div>
|
</dl>
|
||||||
</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>
|
||||||
|
|
||||||
|
<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>
|
</template>
|
||||||
|
@ -4,44 +4,58 @@ import type { Connection } from '@/types';
|
|||||||
import { onMounted } from 'vue';
|
import { onMounted } from 'vue';
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
|
|
||||||
const props = defineProps(['chain'])
|
const props = defineProps(['chain']);
|
||||||
const chainStore = useBlockchain()
|
const chainStore = useBlockchain();
|
||||||
const list = ref([] as Connection[])
|
const list = ref([] as Connection[]);
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
chainStore.rpc.getIBCConnections().then(x => {
|
chainStore.rpc.getIBCConnections().then((x) => {
|
||||||
list.value = x.connections
|
list.value = x.connections;
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
function color(v: string) {
|
function color(v: string) {
|
||||||
if(v && v.indexOf("_OPEN") > -1) {
|
if (v && v.indexOf('_OPEN') > -1) {
|
||||||
return "success"
|
return 'success';
|
||||||
}
|
}
|
||||||
return "warning"
|
return 'warning';
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="bg-base-100 px-4 pt-3 pb-4 rounded shadow">
|
<div class="bg-base-100 px-4 pt-3 pb-4 rounded shadow">
|
||||||
<h2 class="card-title">IBC Connections</h2>
|
<h2 class="card-title">IBC Connections</h2>
|
||||||
<div class="overflow-x-auto mt-4">
|
<div class="overflow-x-auto mt-4">
|
||||||
<table class="table w-full">
|
<table class="table w-full">
|
||||||
<thead>
|
<thead>
|
||||||
<tr><th style="position: relative;">Connection Id</th><th>Connection</th><th>Delay Period</th><th>State</th></tr>
|
<tr>
|
||||||
</thead>
|
<th style="position: relative">Connection Id</th>
|
||||||
<tbody>
|
<th>Connection</th>
|
||||||
<tr v-for="v in list">
|
<th>Delay Period</th>
|
||||||
<td><RouterLink :to="`/${chain}/ibc/${v.id}`">{{ v.id }}</RouterLink></td>
|
<th>State</th>
|
||||||
<td>{{ v.client_id }} {{ v.id }} <br> {{v.counterparty.client_id }} {{ v.counterparty.connection_id }} </td>
|
</tr>
|
||||||
<td>{{ v.delay_period }}</td>
|
</thead>
|
||||||
<td><VChip :color="color(v.state)">{{ v.state }}</VChip></td>
|
<tbody>
|
||||||
</tr>
|
<tr v-for="v in list">
|
||||||
</tbody>
|
<td>
|
||||||
</table>
|
<RouterLink :to="`/${chain}/ibc/${v.id}`">{{
|
||||||
</div>
|
v.id
|
||||||
</div>
|
}}</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>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<route>
|
<route>
|
||||||
@ -50,4 +64,4 @@ function color(v: string) {
|
|||||||
i18n: 'ibc'
|
i18n: 'ibc'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</route>
|
</route>
|
||||||
|
@ -25,12 +25,18 @@ const format = useFormatter();
|
|||||||
const ticker = computed(() => store.coinInfo.tickers[store.tickerIndex]);
|
const ticker = computed(() => store.coinInfo.tickers[store.tickerIndex]);
|
||||||
|
|
||||||
blockchain.$subscribe((m, s) => {
|
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();
|
store.loadDashboard();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
function shortName(name: string, id: string) {
|
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>
|
</script>
|
||||||
|
|
||||||
@ -47,27 +53,51 @@ function shortName(name: string, id: string) {
|
|||||||
</VCardTitle>
|
</VCardTitle>
|
||||||
<VCardSubtitle>
|
<VCardSubtitle>
|
||||||
Rank:
|
Rank:
|
||||||
<VChip color="error" size="x-small">#{{ coinInfo.market_cap_rank }}</VChip>
|
<VChip color="error" size="x-small"
|
||||||
|
>#{{ coinInfo.market_cap_rank }}</VChip
|
||||||
|
>
|
||||||
</VCardSubtitle>
|
</VCardSubtitle>
|
||||||
</VCardItem>
|
</VCardItem>
|
||||||
<VDivider />
|
<VDivider />
|
||||||
<VCardItem>
|
<VCardItem>
|
||||||
<VBtn variant="text" size="small" :href="store.homepage" prependIcon="mdi-web">
|
<VBtn
|
||||||
|
variant="text"
|
||||||
|
size="small"
|
||||||
|
:href="store.homepage"
|
||||||
|
prependIcon="mdi-web"
|
||||||
|
>
|
||||||
Website
|
Website
|
||||||
</VBtn>
|
</VBtn>
|
||||||
<VBtn variant="text" size="small" :href="store.twitter" prependIcon="mdi-twitter">
|
<VBtn
|
||||||
|
variant="text"
|
||||||
|
size="small"
|
||||||
|
:href="store.twitter"
|
||||||
|
prependIcon="mdi-twitter"
|
||||||
|
>
|
||||||
Twitter
|
Twitter
|
||||||
</VBtn>
|
</VBtn>
|
||||||
<VBtn variant="text" size="small" :href="store.telegram" prependIcon="mdi-telegram">
|
<VBtn
|
||||||
|
variant="text"
|
||||||
|
size="small"
|
||||||
|
:href="store.telegram"
|
||||||
|
prependIcon="mdi-telegram"
|
||||||
|
>
|
||||||
Telegram
|
Telegram
|
||||||
</VBtn>
|
</VBtn>
|
||||||
<VBtn variant="text" size="small" :href="store.github" prependIcon="mdi-github">
|
<VBtn
|
||||||
|
variant="text"
|
||||||
|
size="small"
|
||||||
|
:href="store.github"
|
||||||
|
prependIcon="mdi-github"
|
||||||
|
>
|
||||||
Github
|
Github
|
||||||
</VBtn>
|
</VBtn>
|
||||||
</VCardItem>
|
</VCardItem>
|
||||||
<VCardItem>
|
<VCardItem>
|
||||||
<!-- SECTION upgrade plan banner -->
|
<!-- 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">
|
<h3 class="plan-details me-3" :class="store.priceColor">
|
||||||
{{ store.priceChange }}
|
{{ store.priceChange }}
|
||||||
<small>%</small>
|
<small>%</small>
|
||||||
@ -102,7 +132,10 @@ function shortName(name: string, id: string) {
|
|||||||
}}
|
}}
|
||||||
</VListItemSubtitle>
|
</VListItemSubtitle>
|
||||||
<template #append>
|
<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 }}
|
{{ item.converted_last.usd }}
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
@ -119,9 +152,13 @@ function shortName(name: string, id: string) {
|
|||||||
<span class="text-h5">{{ ticker.converted_last.usd }}</span>
|
<span class="text-h5">{{ ticker.converted_last.usd }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- !SECTION -->
|
|
||||||
<VSpacer />
|
<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 || '' }}
|
Buy {{ coinInfo.symbol || '' }}
|
||||||
</VBtn>
|
</VBtn>
|
||||||
</VCardItem>
|
</VCardItem>
|
||||||
@ -134,10 +171,15 @@ function shortName(name: string, id: string) {
|
|||||||
</VRow>
|
</VRow>
|
||||||
<VDivider />
|
<VDivider />
|
||||||
<VCardText style="max-height: 250px; overflow: auto">
|
<VCardText style="max-height: 250px; overflow: auto">
|
||||||
<MdEditor :model-value="coinInfo.description?.en" previewOnly></MdEditor>
|
<MdEditor
|
||||||
|
:model-value="coinInfo.description?.en"
|
||||||
|
previewOnly
|
||||||
|
></MdEditor>
|
||||||
</VCardText>
|
</VCardText>
|
||||||
<VCardItem>
|
<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>
|
</VCardItem>
|
||||||
</VCard>
|
</VCard>
|
||||||
|
|
||||||
@ -154,10 +196,14 @@ function shortName(name: string, id: string) {
|
|||||||
<VCardItem>
|
<VCardItem>
|
||||||
<ProposalListItem :proposals="store?.proposals" />
|
<ProposalListItem :proposals="store?.proposals" />
|
||||||
</VCardItem>
|
</VCardItem>
|
||||||
<VCardText v-if="store.proposals.length === 0">No active proposals</VCardText>
|
<VCardText v-if="store.proposals.length === 0"
|
||||||
|
>No active proposals</VCardText
|
||||||
|
>
|
||||||
</VCard>
|
</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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -1,212 +1,234 @@
|
|||||||
import { useBlockchain, useCoingecko, useBaseStore, useBankStore, useFormatter, useGovStore } from "@/stores";
|
import {
|
||||||
import { useDistributionStore } from "@/stores/useDistributionStore";
|
useBlockchain,
|
||||||
import { useMintStore } from "@/stores/useMintStore";
|
useCoingecko,
|
||||||
import { useStakingStore } from "@/stores/useStakingStore";
|
useBaseStore,
|
||||||
import type { GovProposal, PaginatedProposals, Tally } from "@/types";
|
useBankStore,
|
||||||
import numeral from "numeral";
|
useFormatter,
|
||||||
import { defineStore } from "pinia";
|
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) {
|
function colorMap(color: string) {
|
||||||
switch (color) {
|
switch (color) {
|
||||||
case 'yellow':
|
case 'yellow':
|
||||||
return 'warning'
|
return 'warning';
|
||||||
case 'green':
|
case 'green':
|
||||||
return 'success'
|
return 'success';
|
||||||
default:
|
default:
|
||||||
return 'secondary'
|
return 'secondary';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useIndexModule = defineStore('module-index', {
|
export const useIndexModule = defineStore('module-index', {
|
||||||
state: () => {
|
state: () => {
|
||||||
return {
|
return {
|
||||||
days: 14,
|
days: 14,
|
||||||
tickerIndex: 0,
|
tickerIndex: 0,
|
||||||
coinInfo: {
|
coinInfo: {
|
||||||
name: '',
|
name: '',
|
||||||
symbol: '',
|
symbol: '',
|
||||||
description: {
|
description: {
|
||||||
en: ''
|
en: '',
|
||||||
},
|
},
|
||||||
categories: [] as string[],
|
categories: [] as string[],
|
||||||
market_cap_rank: 0,
|
market_cap_rank: 0,
|
||||||
links: {
|
links: {
|
||||||
twitter_screen_name: '',
|
twitter_screen_name: '',
|
||||||
homepage: [] as string[],
|
homepage: [] as string[],
|
||||||
repos_url: {
|
repos_url: {
|
||||||
github: []
|
github: [],
|
||||||
},
|
},
|
||||||
telegram_channel_identifier: ''
|
telegram_channel_identifier: '',
|
||||||
},
|
},
|
||||||
market_data: {
|
market_data: {
|
||||||
price_change_percentage_24h: 0
|
price_change_percentage_24h: 0,
|
||||||
},
|
},
|
||||||
tickers: [] as {
|
tickers: [] as {
|
||||||
market: {
|
market: {
|
||||||
name: string,
|
name: string;
|
||||||
identifier: string,
|
identifier: string;
|
||||||
},
|
};
|
||||||
coin_id: string,
|
coin_id: string;
|
||||||
target_coin_id: string,
|
target_coin_id: string;
|
||||||
trust_score: string,
|
trust_score: string;
|
||||||
trade_url: string,
|
trade_url: string;
|
||||||
converted_last: {
|
converted_last: {
|
||||||
btc: number,
|
btc: number;
|
||||||
eth: number,
|
eth: number;
|
||||||
usd: number,
|
usd: number;
|
||||||
},
|
};
|
||||||
base: string,
|
base: string;
|
||||||
target: string,
|
target: string;
|
||||||
}[]
|
}[],
|
||||||
},
|
},
|
||||||
marketData: {
|
marketData: {
|
||||||
market_caps: [],
|
market_caps: [],
|
||||||
prices: [] as number[],
|
prices: [] as number[],
|
||||||
total_volumes: [] as number[],
|
total_volumes: [] as number[],
|
||||||
},
|
},
|
||||||
communityPool: [] as {amount: string, denom: string}[],
|
communityPool: [] as { amount: string; denom: string }[],
|
||||||
proposals: {} as PaginatedProposals,
|
proposals: {} as PaginatedProposals,
|
||||||
tally: {} as Record<string, Tally>
|
tally: {} as Record<string, Tally>,
|
||||||
}
|
};
|
||||||
|
},
|
||||||
|
getters: {
|
||||||
|
blockchain() {
|
||||||
|
const chain = useBlockchain();
|
||||||
|
return chain.current;
|
||||||
},
|
},
|
||||||
getters: {
|
coingecko() {
|
||||||
blockchain() {
|
return useCoingecko();
|
||||||
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,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
actions: {
|
bankStore() {
|
||||||
async loadDashboard() {
|
return useBankStore();
|
||||||
this.$reset()
|
},
|
||||||
this.initCoingecko()
|
twitter(): string {
|
||||||
useMintStore().fetchInflation()
|
return `https://twitter.com/${this.coinInfo.links.twitter_screen_name}`;
|
||||||
useDistributionStore().fetchCommunityPool().then(x => {
|
},
|
||||||
this.communityPool = x.pool.filter(t => t.denom.length < 10).map(t => ({
|
homepage(): string {
|
||||||
amount: String(parseInt(t.amount)),
|
const [page1, page2, page3] = this.coinInfo.links?.homepage;
|
||||||
denom: t.denom
|
return page1 || page2 || page3;
|
||||||
}))
|
},
|
||||||
})
|
github(): string {
|
||||||
const gov = useGovStore()
|
const [page1, page2, page3] = this.coinInfo.links?.repos_url?.github;
|
||||||
gov.fetchProposals("2").then(x => {
|
return page1 || page2 || page3;
|
||||||
this.proposals = x
|
},
|
||||||
})
|
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)
|
title: 'Validators',
|
||||||
},
|
color: 'error',
|
||||||
initCoingecko() {
|
icon: 'mdi-human-queue',
|
||||||
this.tickerIndex = 0
|
stats: String(base.latest.block?.last_commit?.signatures.length || 0),
|
||||||
const [firstAsset] = this.blockchain?.assets || []
|
change: 0,
|
||||||
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
|
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>
|
<script lang="ts" setup>
|
||||||
import { useParamStore } from '@/stores';
|
import { useParamStore } from '@/stores';
|
||||||
import { ref, onMounted } from 'vue'
|
import { ref, onMounted } from 'vue';
|
||||||
import CardParameter from '@/components/CardParameter.vue'
|
import CardParameter from '@/components/CardParameter.vue';
|
||||||
import ArrayObjectElement from '@/components/dynamic/ArrayObjectElement.vue';
|
import ArrayObjectElement from '@/components/dynamic/ArrayObjectElement.vue';
|
||||||
const store = useParamStore()
|
const store = useParamStore();
|
||||||
const chain = ref(store.chain)
|
const chain = ref(store.chain);
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// fetch the data
|
// fetch the data
|
||||||
store.initial()
|
store.initial();
|
||||||
})
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="overflow-hidden">
|
<div class="overflow-hidden">
|
||||||
@ -29,28 +28,27 @@ onMounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- minting Parameters -->
|
<!-- minting Parameters -->
|
||||||
<CardParameter :cardItem="store.mint"/>
|
<CardParameter :cardItem="store.mint" />
|
||||||
<!-- Staking Parameters -->
|
<!-- Staking Parameters -->
|
||||||
<CardParameter :cardItem="store.staking"/>
|
<CardParameter :cardItem="store.staking" />
|
||||||
<!-- Governance Parameters -->
|
<!-- Governance Parameters -->
|
||||||
<CardParameter :cardItem="store.gov"/>
|
<CardParameter :cardItem="store.gov" />
|
||||||
<!-- Distribution Parameters -->
|
<!-- Distribution Parameters -->
|
||||||
<CardParameter :cardItem="store.distribution"/>
|
<CardParameter :cardItem="store.distribution" />
|
||||||
<!-- Slashing Parameters -->
|
<!-- Slashing Parameters -->
|
||||||
<CardParameter :cardItem="store.slashing"/>
|
<CardParameter :cardItem="store.slashing" />
|
||||||
<!-- Application Version -->
|
<!-- Application Version -->
|
||||||
<div class="bg-base-100 px-4 pt-3 pb-4 rounded-sm mt-6">
|
<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>
|
<div class="text-base mb-3 text-main">{{ store.appVersion?.title }}</div>
|
||||||
<ArrayObjectElement :value="store.appVersion?.items" :thead="false"/>
|
<ArrayObjectElement :value="store.appVersion?.items" :thead="false" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Node Information -->
|
<!-- Node Information -->
|
||||||
<div class="bg-base-100 px-4 pt-3 pb-4ß rounded-sm mt-6">
|
<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>
|
<div class="text-base mb-3 text-main">{{ store.nodeVersion?.title }}</div>
|
||||||
<ArrayObjectElement :value="store.nodeVersion?.items" :thead="false"/>
|
<ArrayObjectElement :value="store.nodeVersion?.items" :thead="false" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -1,275 +1,399 @@
|
|||||||
<script setup lang="ts">
|
<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 { onMounted, computed, ref } from 'vue';
|
||||||
import ValidatorCommissionRate from '@/components/ValidatorCommissionRate.vue'
|
import ValidatorCommissionRate from '@/components/ValidatorCommissionRate.vue';
|
||||||
import { consensusPubkeyToHexAddress, operatorAddressToAccount, pubKeyToValcons, valoperToPrefix } from '@/libs';
|
import {
|
||||||
|
consensusPubkeyToHexAddress,
|
||||||
|
operatorAddressToAccount,
|
||||||
|
pubKeyToValcons,
|
||||||
|
valoperToPrefix,
|
||||||
|
} from '@/libs';
|
||||||
import type { Coin, Delegation, PaginatedTxs, Validator } from '@/types';
|
import type { Coin, Delegation, PaginatedTxs, Validator } from '@/types';
|
||||||
|
|
||||||
const props = defineProps(['validator', 'chain'])
|
const props = defineProps(['validator', 'chain']);
|
||||||
|
|
||||||
const staking = useStakingStore()
|
const staking = useStakingStore();
|
||||||
const blockchain = useBlockchain()
|
const blockchain = useBlockchain();
|
||||||
const format = useFormatter()
|
const format = useFormatter();
|
||||||
|
|
||||||
const validator: string = props.validator
|
const validator: string = props.validator;
|
||||||
|
|
||||||
const v = ref({} as Validator)
|
const v = ref({} as Validator);
|
||||||
const cache = JSON.parse(localStorage.getItem('avatars')||'{}')
|
const cache = JSON.parse(localStorage.getItem('avatars') || '{}');
|
||||||
const avatars = ref( cache || {} )
|
const avatars = ref(cache || {});
|
||||||
const identity = ref("")
|
const identity = ref('');
|
||||||
const rewards = ref([] as Coin[]|undefined)
|
const rewards = ref([] as Coin[] | undefined);
|
||||||
const commission = ref([] as Coin[]|undefined)
|
const commission = ref([] as Coin[] | undefined);
|
||||||
const addresses = ref({} as {
|
const addresses = ref(
|
||||||
account: string
|
{} as {
|
||||||
operAddress: string
|
account: string;
|
||||||
hex: string
|
operAddress: string;
|
||||||
valCons: string,
|
hex: string;
|
||||||
})
|
valCons: string;
|
||||||
const selfBonded = ref({} as Delegation)
|
}
|
||||||
|
);
|
||||||
|
const selfBonded = ref({} as Delegation);
|
||||||
|
|
||||||
addresses.value.account = operatorAddressToAccount(validator)
|
addresses.value.account = operatorAddressToAccount(validator);
|
||||||
// load self bond
|
// load self bond
|
||||||
staking.fetchValidatorDelegation(validator, addresses.value.account).then(x => {
|
staking
|
||||||
if(x) {
|
.fetchValidatorDelegation(validator, addresses.value.account)
|
||||||
selfBonded.value = x.delegation_response
|
.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 => {
|
blockchain.rpc.getTxsBySender(addresses.value.account).then((x) => {
|
||||||
console.log("txs", x)
|
console.log('txs', x);
|
||||||
txs.value = x
|
txs.value = x;
|
||||||
})
|
});
|
||||||
|
|
||||||
const apr = computed(()=> {
|
const apr = computed(() => {
|
||||||
const rate = v.value.commission?.commission_rates.rate || 0
|
const rate = v.value.commission?.commission_rates.rate || 0;
|
||||||
const inflation = useMintStore().inflation
|
const inflation = useMintStore().inflation;
|
||||||
if(Number(inflation)) {
|
if (Number(inflation)) {
|
||||||
return format.percent((1 - Number(rate)) * Number(inflation))
|
return format.percent((1 - Number(rate)) * Number(inflation));
|
||||||
}
|
}
|
||||||
return "-"
|
return '-';
|
||||||
})
|
});
|
||||||
|
|
||||||
const selfRate = computed(()=> {
|
const selfRate = computed(() => {
|
||||||
if(selfBonded.value.balance?.amount) {
|
if (selfBonded.value.balance?.amount) {
|
||||||
return format.calculatePercent(selfBonded.value.balance.amount, v.value.tokens)
|
return format.calculatePercent(
|
||||||
}
|
selfBonded.value.balance.amount,
|
||||||
return "-"
|
v.value.tokens
|
||||||
})
|
);
|
||||||
|
}
|
||||||
|
return '-';
|
||||||
|
});
|
||||||
|
|
||||||
onMounted(()=> {
|
onMounted(() => {
|
||||||
if(validator) {
|
if (validator) {
|
||||||
staking.fetchValidator(validator).then(res => {
|
staking.fetchValidator(validator).then((res) => {
|
||||||
v.value = res.validator
|
v.value = res.validator;
|
||||||
identity.value = res.validator?.description?.identity || ''
|
identity.value = res.validator?.description?.identity || '';
|
||||||
if(identity.value && !avatars.value[identity.value]) {
|
if (identity.value && !avatars.value[identity.value]) {
|
||||||
console.log(identity.value, avatars)
|
console.log(identity.value, avatars);
|
||||||
staking.keybase(identity.value).then(d => {
|
staking.keybase(identity.value).then((d) => {
|
||||||
if (Array.isArray(d.them) && d.them.length > 0) {
|
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/", "")
|
const uri = String(d.them[0]?.pictures?.primary?.url).replace(
|
||||||
if(uri) {
|
'https://s3.amazonaws.com/keybase_processed_uploads/',
|
||||||
avatars.value[identity.value] = uri
|
''
|
||||||
localStorage.setItem('avatars', JSON.stringify(avatars.value))
|
);
|
||||||
}
|
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)
|
}
|
||||||
})
|
const prefix = valoperToPrefix(v.value.operator_address) || '<Invalid>';
|
||||||
blockchain.rpc.getDistributionValidatorOutstandingRewards(validator).then(res => {
|
addresses.value.hex = consensusPubkeyToHexAddress(
|
||||||
rewards.value = res.rewards?.rewards?.sort((a, b) => Number(b.amount) - Number(a.amount))
|
v.value.consensus_pubkey
|
||||||
res.rewards?.rewards?.forEach(x => {
|
);
|
||||||
if(x.denom.startsWith("ibc/")) {
|
addresses.value.valCons = pubKeyToValcons(
|
||||||
format.fetchDenomTrace(x.denom)
|
v.value.consensus_pubkey,
|
||||||
}
|
prefix
|
||||||
})
|
);
|
||||||
})
|
});
|
||||||
blockchain.rpc.getDistributionValidatorCommission(validator).then(res => {
|
blockchain.rpc
|
||||||
commission.value = res.commission?.commission?.sort((a, b) => Number(b.amount) - Number(a.amount))
|
.getDistributionValidatorOutstandingRewards(validator)
|
||||||
res.commission?.commission?.forEach(x => {
|
.then((res) => {
|
||||||
if(x.denom.startsWith("ibc/")) {
|
rewards.value = res.rewards?.rewards?.sort(
|
||||||
format.fetchDenomTrace(x.denom)
|
(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>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<VCard class="card-box">
|
<VCard class="card-box">
|
||||||
<VCardItem>
|
<VCardItem>
|
||||||
<VRow>
|
<VRow>
|
||||||
<VCol cols="12" md="6">
|
<VCol cols="12" md="6">
|
||||||
<div class="d-flex pl-2">
|
<div class="d-flex pl-2">
|
||||||
<VAvatar icon="mdi-help-circle-outline" :image="avatars[identity]" size="90" rounded variant="outlined" color="secondary"/>
|
<VAvatar
|
||||||
<div class="mx-2">
|
icon="mdi-help-circle-outline"
|
||||||
<h4>{{ v.description?.moniker }}</h4>
|
:image="avatars[identity]"
|
||||||
<div class="text-sm mb-2">{{ v.description?.identity || '-'}}</div>
|
size="90"
|
||||||
<VBtn>Delegate</VBtn>
|
rounded
|
||||||
</div>
|
variant="outlined"
|
||||||
</div>
|
color="secondary"
|
||||||
<VSpacer/>
|
/>
|
||||||
<VCardText>
|
<div class="mx-2">
|
||||||
<p class="text-md">
|
<h4>{{ v.description?.moniker }}</h4>
|
||||||
About Us
|
<div class="text-sm mb-2">
|
||||||
</p>
|
{{ v.description?.identity || '-' }}
|
||||||
<VList class="card-list">
|
</div>
|
||||||
<VListItem prepend-icon="mdi-web">
|
<VBtn>Delegate</VBtn>
|
||||||
<span>Website: </span><span> {{ v.description?.website || '-' }}</span>
|
</div>
|
||||||
</VListItem>
|
</div>
|
||||||
<VListItem prepend-icon="mdi-email-outline">
|
<VSpacer />
|
||||||
<span>Contact: </span><span> {{ v.description?.security_contact }}</span>
|
<VCardText>
|
||||||
</VListItem>
|
<p class="text-md">About Us</p>
|
||||||
</VList>
|
<VList class="card-list">
|
||||||
|
<VListItem prepend-icon="mdi-web">
|
||||||
<p class="text-md mt-3">
|
<span>Website: </span
|
||||||
Validator Status
|
><span> {{ v.description?.website || '-' }}</span>
|
||||||
</p>
|
</VListItem>
|
||||||
<VList class="card-list">
|
<VListItem prepend-icon="mdi-email-outline">
|
||||||
<VListItem prepend-icon="mdi-shield-account-outline">
|
<span>Contact: </span
|
||||||
<span>Status: </span><span> {{ String(v.status).replace('BOND_STATUS_', '') }} </span>
|
><span> {{ v.description?.security_contact }}</span>
|
||||||
</VListItem>
|
</VListItem>
|
||||||
<VListItem prepend-icon="mdi-shield-alert-outline">
|
</VList>
|
||||||
<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">
|
<p class="text-md mt-3">Validator Status</p>
|
||||||
<VAvatar color="secondary" rounded variant="outlined" icon="mdi-account-tie"></VAvatar>
|
<VList class="card-list">
|
||||||
<div class="ml-3 d-flex flex-column justify-center">
|
<VListItem prepend-icon="mdi-shield-account-outline">
|
||||||
<h4>{{ v.min_self_delegation }} {{ staking.params.bond_denom }}</h4>
|
<span>Status: </span
|
||||||
<span class="text-sm">Min Self Delegation:</span>
|
><span>
|
||||||
</div>
|
{{ String(v.status).replace('BOND_STATUS_', '') }}
|
||||||
</div>
|
</span>
|
||||||
<div class="d-flex">
|
</VListItem>
|
||||||
<VAvatar color="secondary" rounded variant="outlined" icon="mdi-finance"></VAvatar>
|
<VListItem prepend-icon="mdi-shield-alert-outline">
|
||||||
<div class="ml-3 d-flex flex-column justify-center">
|
<span>Jailed: </span><span> {{ v.jailed || '-' }} </span>
|
||||||
<h4>{{ apr }}</h4>
|
</VListItem>
|
||||||
<span class="text-sm">Annual Profit</span>
|
</VList>
|
||||||
</div>
|
</VCardText>
|
||||||
</div>
|
</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">
|
<div class="d-flex">
|
||||||
<VAvatar color="secondary" rounded variant="outlined" icon="mdi-stairs-up"></VAvatar>
|
<VAvatar
|
||||||
<div class="ml-3 d-flex flex-column justify-center">
|
color="secondary"
|
||||||
<h4>{{ v.unbonding_height }}</h4>
|
rounded
|
||||||
<span class="text-sm">Unbonding Height</span>
|
variant="outlined"
|
||||||
</div>
|
icon="mdi-account-tie"
|
||||||
</div>
|
></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">
|
<div class="d-flex">
|
||||||
<VAvatar color="secondary" rounded variant="outlined" icon="mdi-clock"></VAvatar>
|
<VAvatar
|
||||||
<div class="ml-3 d-flex flex-column justify-center">
|
color="secondary"
|
||||||
<h4>{{ format.toDay(v.unbonding_time, 'from') }}</h4>
|
rounded
|
||||||
<span class="text-sm">Unbonding Time</span>
|
variant="outlined"
|
||||||
</div>
|
icon="mdi-stairs-up"
|
||||||
</div>
|
></VAvatar>
|
||||||
</div>
|
<div class="ml-3 d-flex flex-column justify-center">
|
||||||
</VCol>
|
<h4>{{ v.unbonding_height }}</h4>
|
||||||
</VRow>
|
<span class="text-sm">Unbonding Height</span>
|
||||||
<VDivider />
|
</div>
|
||||||
<VCardText>{{ v.description?.details }}</VCardText>
|
</div>
|
||||||
</VCardItem>
|
|
||||||
|
<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>
|
</VCard>
|
||||||
|
|
||||||
<VRow class="mt-3">
|
<VRow class="mt-3">
|
||||||
<VCol md="4" sm="12" class="h-100">
|
<VCol md="4" sm="12" class="h-100">
|
||||||
<ValidatorCommissionRate :commission="v.commission"></ValidatorCommissionRate>
|
<ValidatorCommissionRate
|
||||||
</VCol>
|
:commission="v.commission"
|
||||||
<VCol md="4" sm="12">
|
></ValidatorCommissionRate>
|
||||||
<VCard class="h-100">
|
</VCol>
|
||||||
<VCardTitle>Commissions & Rewards</VCardTitle>
|
<VCol md="4" sm="12">
|
||||||
<VCardItem class="pt-0 pb-0">
|
<VCard class="h-100">
|
||||||
<div class="overflow-auto" style="max-height: 280px;">
|
<VCardTitle>Commissions & Rewards</VCardTitle>
|
||||||
<VCardSubtitle>Commissions <VBtn size="small" class="float-right" variant="text">Withdraw</VBtn></VCardSubtitle>
|
<VCardItem class="pt-0 pb-0">
|
||||||
<VDivider class="mb-2"></VDivider>
|
<div class="overflow-auto" style="max-height: 280px">
|
||||||
<VChip v-for="(i, k) in commission" :key="`reward-${k}`" color="info" label variant="outlined" class="mr-1 mb-1">
|
<VCardSubtitle
|
||||||
{{ format.formatToken2(i) }}
|
>Commissions
|
||||||
</VChip>
|
<VBtn size="small" class="float-right" variant="text"
|
||||||
<VCardSubtitle class="mt-2">Outstanding Rewards</VCardSubtitle>
|
>Withdraw</VBtn
|
||||||
<VDivider class="mb-2"></VDivider>
|
></VCardSubtitle
|
||||||
<VChip v-for="(i, k) in rewards" :key="`reward-${k}`" color="success" label variant="outlined" class="mr-1 mb-1">
|
>
|
||||||
{{ format.formatToken2(i) }}
|
<VDivider class="mb-2"></VDivider>
|
||||||
</VChip>
|
<VChip
|
||||||
</div>
|
v-for="(i, k) in commission"
|
||||||
</VCardItem>
|
:key="`reward-${k}`"
|
||||||
</VCard>
|
color="info"
|
||||||
</VCol>
|
label
|
||||||
<VCol md="4" sm="12">
|
variant="outlined"
|
||||||
<VCard title="Addresses" class="h-100">
|
class="mr-1 mb-1"
|
||||||
<VList class="pt-0">
|
>
|
||||||
<VListItem>
|
{{ format.formatToken2(i) }}
|
||||||
<VListItemTitle>Account</VListItemTitle>
|
</VChip>
|
||||||
<VListItemSubtitle class="text-caption text-primary"><RouterLink :to="`/${chain}/account/${addresses.account}`">{{ addresses.account }}</RouterLink></VListItemSubtitle>
|
<VCardSubtitle class="mt-2">Outstanding Rewards</VCardSubtitle>
|
||||||
</VListItem>
|
<VDivider class="mb-2"></VDivider>
|
||||||
<VListItem>
|
<VChip
|
||||||
<VListItemTitle>Operator Address</VListItemTitle>
|
v-for="(i, k) in rewards"
|
||||||
<VListItemSubtitle class="text-caption">{{ v.operator_address }}</VListItemSubtitle>
|
:key="`reward-${k}`"
|
||||||
</VListItem>
|
color="success"
|
||||||
<VListItem>
|
label
|
||||||
<VListItemTitle>Hex Address</VListItemTitle>
|
variant="outlined"
|
||||||
<VListItemSubtitle class="text-caption">{{ addresses.hex }}</VListItemSubtitle>
|
class="mr-1 mb-1"
|
||||||
</VListItem>
|
>
|
||||||
<VListItem>
|
{{ format.formatToken2(i) }}
|
||||||
<VListItemTitle>Signer Address</VListItemTitle>
|
</VChip>
|
||||||
<VListItemSubtitle class="text-caption">{{ addresses.valCons }}</VListItemSubtitle>
|
</div>
|
||||||
</VListItem>
|
</VCardItem>
|
||||||
</VList>
|
</VCard>
|
||||||
</VCard>
|
</VCol>
|
||||||
</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>
|
</VRow>
|
||||||
<VCard title="Transactions" class="mt-5">
|
<VCard title="Transactions" class="mt-5">
|
||||||
<VCardItem class="pt-0">
|
<VCardItem class="pt-0">
|
||||||
<VTable>
|
<VTable>
|
||||||
<thead>
|
<thead>
|
||||||
<th class="text-left pl-4">Height</th>
|
<th class="text-left pl-4">Height</th>
|
||||||
<th class="text-left pl-4">Hash</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" width="40%">Messages</th>
|
||||||
<th class="text-left pl-4">Time</th>
|
<th class="text-left pl-4">Time</th>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="(item, i) in txs.tx_responses">
|
<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-sm text-primary">
|
||||||
<td class="text-truncate" style="max-width: 200px;">{{ item.txhash }}</td>
|
<RouterLink :to="`/${props.chain}/block/${item.height}`">{{
|
||||||
<td>
|
item.height
|
||||||
{{ format.messages(item.tx.body.messages) }}
|
}}</RouterLink>
|
||||||
<VIcon v-if="item.code === 0" icon="mdi-check" color="success"></VIcon>
|
</td>
|
||||||
<VIcon v-else icon="mdi-multiply" color="error"></VIcon> </td>
|
<td class="text-truncate" style="max-width: 200px">
|
||||||
<td width="150">{{ format.toDay(item.timestamp,'from') }}</td>
|
{{ item.txhash }}
|
||||||
</tr>
|
</td>
|
||||||
</tbody>
|
<td>
|
||||||
</VTable>
|
{{ format.messages(item.tx.body.messages) }}
|
||||||
</VCardItem>
|
<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>
|
</VCard>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<style>
|
<style>
|
||||||
.card-list {
|
.card-list {
|
||||||
--v-card-list-gap: 10px;
|
--v-card-list-gap: 10px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -5,76 +5,97 @@ import { fromBase64, toHex } from '@cosmjs/encoding';
|
|||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
|
|
||||||
const props = defineProps(['hash', 'chain'])
|
const props = defineProps(['hash', 'chain']);
|
||||||
const blockchain = useBlockchain()
|
const blockchain = useBlockchain();
|
||||||
const base = useBaseStore()
|
const base = useBaseStore();
|
||||||
const nodeInfo = ref({} as NodeInfo)
|
const nodeInfo = ref({} as NodeInfo);
|
||||||
|
|
||||||
const state = computed(()=> {
|
const state = computed(() => {
|
||||||
const rpcs = blockchain.current?.endpoints?.rpc?.map(x => x.address).join(',')
|
const rpcs = blockchain.current?.endpoints?.rpc
|
||||||
return `[statesync]
|
?.map((x) => x.address)
|
||||||
|
.join(',');
|
||||||
|
return `[statesync]
|
||||||
enable = true
|
enable = true
|
||||||
rpc_servers = "${rpcs}"
|
rpc_servers = "${rpcs}"
|
||||||
trust_height = ${base.latest.block?.header?.height || 'loading'}
|
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"
|
trust_period = "168h" # 2/3 of unbonding time"
|
||||||
`
|
`;
|
||||||
})
|
});
|
||||||
|
|
||||||
const appName = computed(()=> {
|
const appName = computed(() => {
|
||||||
return nodeInfo.value.application_version?.app_name || "gaiad"
|
return nodeInfo.value.application_version?.app_name || 'gaiad';
|
||||||
})
|
});
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
blockchain.rpc.getBaseNodeInfo().then(x => {
|
blockchain.rpc.getBaseNodeInfo().then((x) => {
|
||||||
console.log('node info', x)
|
console.log('node info', x);
|
||||||
nodeInfo.value = x
|
nodeInfo.value = x;
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<VCard>
|
<VCard>
|
||||||
<VCardTitle>What's State Sync?</VCardTitle>
|
<VCardTitle>What's State Sync?</VCardTitle>
|
||||||
<VCardText>
|
<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.
|
The Tendermint Core 0.34 release includes support for state sync, which
|
||||||
</VCardText>
|
allows a new node to join a network by fetching a snapshot of the
|
||||||
</VCard>
|
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">
|
<VCard class="my-5">
|
||||||
<VCardTitle>Starting New Node From State Sync</VCardTitle>
|
<VCardTitle>Starting New Node From State Sync</VCardTitle>
|
||||||
<VCardItem>
|
<VCardItem>
|
||||||
1. Install Binary ({{ appName }} Version: {{ nodeInfo.application_version?.version || "" }})
|
1. Install Binary ({{ appName }} Version:
|
||||||
<br>
|
{{ nodeInfo.application_version?.version || '' }})
|
||||||
We need to install the binary first and make sure that the version is the one currently in use on mainnet.
|
<br />
|
||||||
<br>
|
We need to install the binary first and make sure that the version is
|
||||||
2. Enable State Sync<br>
|
the one currently in use on mainnet.
|
||||||
We can configure Tendermint to use state sync in $DAEMON_HOME/config/config.toml.
|
<br />
|
||||||
<VTextarea auto-grow :model-value="state"></VTextarea>
|
2. Enable State Sync<br />
|
||||||
3. Start the daemon: <code>{{ appName }} start</code>
|
We can configure Tendermint to use state sync in
|
||||||
<br/>
|
$DAEMON_HOME/config/config.toml.
|
||||||
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.
|
<VTextarea auto-grow :model-value="state"></VTextarea>
|
||||||
</VCardItem>
|
3. Start the daemon: <code>{{ appName }} start</code>
|
||||||
</VCard>
|
<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>
|
<VCard>
|
||||||
<VCardTitle>Enable Snapshot For State Sync</VCardTitle>
|
<VCardTitle>Enable Snapshot For State Sync</VCardTitle>
|
||||||
<VCardItem>
|
<VCardItem>
|
||||||
To make state sync works, we can enable snapshot in $DAEMON_HOME/config/app.toml
|
To make state sync works, we can enable snapshot in
|
||||||
<VTextarea auto-grow model-value="[state-sync]
|
$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
|
# 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.
|
# taken (0 to disable). Must be a multiple of pruning-keep-every.
|
||||||
snapshot-interval = 1000
|
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 specifies the number of recent snapshots to keep and serve (0 to keep all). Each snapshot is about 500MiB
|
||||||
snapshot-keep-recent = 2">
|
snapshot-keep-recent = 2"
|
||||||
|
>
|
||||||
</VTextarea>
|
</VTextarea>
|
||||||
</VCardItem>
|
</VCardItem>
|
||||||
</VCard>
|
</VCard>
|
||||||
|
</div>
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<route>
|
<route>
|
||||||
@ -83,4 +104,4 @@ snapshot-keep-recent = 2">
|
|||||||
i18n: 'state-sync'
|
i18n: 'state-sync'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</route>
|
</route>
|
||||||
|
@ -6,58 +6,99 @@ import type { Tx, TxResponse } from '@/types';
|
|||||||
import VueJsonPretty from 'vue-json-pretty';
|
import VueJsonPretty from 'vue-json-pretty';
|
||||||
import 'vue-json-pretty/lib/styles.css';
|
import 'vue-json-pretty/lib/styles.css';
|
||||||
|
|
||||||
const props = defineProps(['hash', 'chain'])
|
const props = defineProps(['hash', 'chain']);
|
||||||
|
|
||||||
const blockchain = useBlockchain()
|
const blockchain = useBlockchain();
|
||||||
const format = useFormatter()
|
const format = useFormatter();
|
||||||
const tx = ref({} as {
|
const tx = ref(
|
||||||
|
{} as {
|
||||||
tx: Tx;
|
tx: Tx;
|
||||||
tx_response: TxResponse
|
tx_response: TxResponse;
|
||||||
})
|
}
|
||||||
if(props.hash) {
|
);
|
||||||
blockchain.rpc.getTx(props.hash).then(x => tx.value = x)
|
if (props.hash) {
|
||||||
|
blockchain.rpc.getTx(props.hash).then((x) => (tx.value = x));
|
||||||
}
|
}
|
||||||
const messages = computed(() => {
|
const messages = computed(() => {
|
||||||
return tx.value.tx?.body?.messages||[]
|
return tx.value.tx?.body?.messages || [];
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<VCard v-if="tx.tx_response" title="Summary">
|
<VCard v-if="tx.tx_response" title="Summary">
|
||||||
<VCardItem class="pt-0">
|
<VCardItem class="pt-0">
|
||||||
<VTable>
|
<VTable>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr><td>Tx Hash</td><td>{{ tx.tx_response.txhash }}</td></tr>
|
<tr>
|
||||||
<tr><td>Height</td><td><RouterLink :to="`/${props.chain}/block/${tx.tx_response.height}`">{{ tx.tx_response.height }}</RouterLink></td></tr>
|
<td>Tx Hash</td>
|
||||||
<tr><td>Status</td><td>
|
<td>{{ tx.tx_response.txhash }}</td>
|
||||||
<VChip v-if="tx.tx_response.code === 0" color="success">Success</VChip>
|
</tr>
|
||||||
<span v-else><VChip color="error">Failded</VChip></span>
|
<tr>
|
||||||
</td></tr>
|
<td>Height</td>
|
||||||
<tr><td>Time</td><td>{{ tx.tx_response.timestamp }} ({{ format.toDay(tx.tx_response.timestamp, "from") }})</td></tr>
|
<td>
|
||||||
<tr><td>Gas</td><td>{{ tx.tx_response.gas_used }} / {{ tx.tx_response.gas_wanted }}</td></tr>
|
<RouterLink
|
||||||
<tr><td>Fee</td><td>{{ format.formatTokens(tx.tx?.auth_info?.fee?.amount, true, '0,0.[00]') }}</td></tr>
|
:to="`/${props.chain}/block/${tx.tx_response.height}`"
|
||||||
<tr><td>Memo</td><td>{{ tx.tx.body.memo }}</td></tr>
|
>{{ tx.tx_response.height }}</RouterLink
|
||||||
</tbody>
|
>
|
||||||
</VTable>
|
</td>
|
||||||
</VCardItem>
|
</tr>
|
||||||
</VCard>
|
<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">
|
<VCard :title="`Messages: (${messages.length})`" class="my-5">
|
||||||
<VCardItem class="pt-0" style="border-top: 2px dotted gray;">
|
<VCardItem class="pt-0" style="border-top: 2px dotted gray">
|
||||||
<div v-for="(msg, i) in messages">
|
<div v-for="(msg, i) in messages">
|
||||||
<div><DynamicComponent :value="msg" /></div>
|
<div><DynamicComponent :value="msg" /></div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="messages.length === 0">
|
<div v-if="messages.length === 0">No messages</div>
|
||||||
No messages
|
</VCardItem>
|
||||||
</div>
|
</VCard>
|
||||||
</VCardItem>
|
|
||||||
</VCard>
|
|
||||||
|
|
||||||
<VCard title="JSON">
|
<VCard title="JSON">
|
||||||
<VCardItem class="pt-0">
|
<VCardItem class="pt-0">
|
||||||
<vue-json-pretty :data="tx" :deep="3"/>
|
<vue-json-pretty :data="tx" :deep="3" />
|
||||||
</VCardItem>
|
</VCardItem>
|
||||||
</VCard>
|
</VCard>
|
||||||
|
</div>
|
||||||
</div>
|
</template>
|
||||||
</template>
|
|
||||||
|
@ -1,107 +1,162 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, onMounted, computed, watchEffect } from 'vue';
|
import { ref, onMounted, computed, watchEffect } from 'vue';
|
||||||
import { fromHex, toBase64 } from '@cosmjs/encoding'
|
import { fromHex, toBase64 } from '@cosmjs/encoding';
|
||||||
import { useFormatter, useStakingStore, useBaseStore, useBlockchain } from '@/stores';
|
import {
|
||||||
|
useFormatter,
|
||||||
|
useStakingStore,
|
||||||
|
useBaseStore,
|
||||||
|
useBlockchain,
|
||||||
|
} from '@/stores';
|
||||||
import UptimeBar from '@/components/UptimeBar.vue';
|
import UptimeBar from '@/components/UptimeBar.vue';
|
||||||
import type { Block, Commit } from '@/types'
|
import type { Block, Commit } from '@/types';
|
||||||
import { consensusPubkeyToHexAddress, valconsToBase64 } from "@/libs";
|
import { consensusPubkeyToHexAddress, valconsToBase64 } from '@/libs';
|
||||||
import type { SigningInfo } from '@/types/slashing';
|
import type { SigningInfo } from '@/types/slashing';
|
||||||
|
|
||||||
const props = defineProps(['chain'])
|
const props = defineProps(['chain']);
|
||||||
|
|
||||||
const stakingStore = useStakingStore();
|
const stakingStore = useStakingStore();
|
||||||
const baseStore = useBaseStore();
|
const baseStore = useBaseStore();
|
||||||
const chainStore = useBlockchain()
|
const chainStore = useBlockchain();
|
||||||
const latest = ref({} as Block)
|
const latest = ref({} as Block);
|
||||||
const commits = ref([] as Commit[]);
|
const commits = ref([] as Commit[]);
|
||||||
const keyword = ref("")
|
const keyword = ref('');
|
||||||
const live = ref(true);
|
const live = ref(true);
|
||||||
|
|
||||||
// storage local favorite validator ids
|
// storage local favorite validator ids
|
||||||
const local = ref((JSON.parse(localStorage.getItem("uptime-validators") || "{}")) as Record<string, string[]>)
|
const local = ref(
|
||||||
const selected = ref(local.value[chainStore.chainName] as string[]) // favorite validators on selected blockchain
|
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
|
// filter validators by keywords
|
||||||
const validators = computed(()=> {
|
const validators = computed(() => {
|
||||||
if(keyword) return stakingStore.validators.filter(x => x.description.moniker.indexOf(keyword.value) > -1)
|
if (keyword)
|
||||||
return stakingStore.validators
|
return stakingStore.validators.filter(
|
||||||
})
|
(x) => x.description.moniker.indexOf(keyword.value) > -1
|
||||||
|
);
|
||||||
|
return stakingStore.validators;
|
||||||
|
});
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
live.value = true
|
live.value = true;
|
||||||
baseStore.fetchLatest().then(block => {
|
baseStore.fetchLatest().then((block) => {
|
||||||
latest.value = block
|
latest.value = block;
|
||||||
commits.value.unshift(block.block.last_commit)
|
commits.value.unshift(block.block.last_commit);
|
||||||
const height = Number(block.block.header?.height|| 0)
|
const height = Number(block.block.header?.height || 0);
|
||||||
if(height > 0) {
|
if (height > 0) {
|
||||||
// constructs sequence for loading blocks
|
// constructs sequence for loading blocks
|
||||||
let promise = Promise.resolve()
|
let promise = Promise.resolve();
|
||||||
for (let i = height - 1; i > height - 50; i -= 1) {
|
for (let i = height - 1; i > height - 50; i -= 1) {
|
||||||
if (i > height - 48) {
|
if (i > height - 48) {
|
||||||
promise = promise.then(() => new Promise((resolve, reject) => {
|
promise = promise.then(
|
||||||
if(live.value) { // continue only if the page is living
|
() =>
|
||||||
baseStore.fetchBlock(i).then((x) => {
|
new Promise((resolve, reject) => {
|
||||||
commits.value.unshift(x.block.last_commit)
|
if (live.value) {
|
||||||
resolve()
|
// 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)=> {
|
chainStore.rpc.getSlashingSigningInfos().then((x) => {
|
||||||
x.info?.forEach(i => {
|
x.info?.forEach((i) => {
|
||||||
signingInfo.value[valconsToBase64(i.address)] = i
|
signingInfo.value[valconsToBase64(i.address)] = i;
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
live.value = false
|
live.value = false;
|
||||||
})
|
});
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
local.value[chainStore.chainName] = selected.value
|
local.value[chainStore.chainName] = selected.value;
|
||||||
localStorage.setItem("uptime-validators", JSON.stringify(local.value))
|
localStorage.setItem('uptime-validators', JSON.stringify(local.value));
|
||||||
})
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<VRow>
|
<VRow>
|
||||||
<VCol cols="12" md="4" >
|
<VCol cols="12" md="4">
|
||||||
<VCard class="h-full self-center d-flex p-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>
|
</VCard>
|
||||||
</VCol>
|
</VCol>
|
||||||
<VCol cols="12" md="8" class="">
|
<VCol cols="12" md="8" class="">
|
||||||
<VTextField v-model="keyword" label="Keywords to filter validators" variant="outlined">
|
<VTextField
|
||||||
|
v-model="keyword"
|
||||||
|
label="Keywords to filter validators"
|
||||||
|
variant="outlined"
|
||||||
|
>
|
||||||
<template v-slot:append>
|
<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>
|
</template>
|
||||||
</VTextField>
|
</VTextField>
|
||||||
</VCol>
|
</VCol>
|
||||||
</VRow>
|
</VRow>
|
||||||
|
|
||||||
<VRow>
|
<VRow>
|
||||||
<VCol v-for="(v, i) in validators" cols="12" md="3" xl="2" class="py-0">
|
<VCol v-for="(v, i) in validators" cols="12" md="3" xl="2" class="py-0">
|
||||||
<div class="d-flex justify-between">
|
<div class="d-flex justify-between">
|
||||||
<VCheckbox v-model="selected" color="warning" :value="v.operator_address">
|
<VCheckbox
|
||||||
<template v-slot:label>
|
v-model="selected"
|
||||||
<span class="text-truncate">{{i + 1}}. {{v.description.moniker}}</span>
|
color="warning"
|
||||||
</template>
|
:value="v.operator_address"
|
||||||
</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>
|
<template v-slot:label>
|
||||||
<VChip v-else size="small" class="mt-1" label color="success">{{ signingInfo[consensusPubkeyToHexAddress(v.consensus_pubkey)]?.missed_blocks_counter }}</VChip>
|
<span class="text-truncate"
|
||||||
|
>{{ i + 1 }}. {{ v.description.moniker }}</span
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
</VCheckbox>
|
||||||
|
<VChip
|
||||||
|
v-if="
|
||||||
|
Number(
|
||||||
|
signingInfo[consensusPubkeyToHexAddress(v.consensus_pubkey)]
|
||||||
|
?.missed_blocks_counter || 0
|
||||||
|
) > 0
|
||||||
|
"
|
||||||
|
size="small"
|
||||||
|
class="mt-1"
|
||||||
|
label
|
||||||
|
color="error"
|
||||||
|
>{{
|
||||||
|
signingInfo[consensusPubkeyToHexAddress(v.consensus_pubkey)]
|
||||||
|
?.missed_blocks_counter
|
||||||
|
}}</VChip
|
||||||
|
>
|
||||||
|
<VChip v-else size="small" class="mt-1" label color="success">{{
|
||||||
|
signingInfo[consensusPubkeyToHexAddress(v.consensus_pubkey)]
|
||||||
|
?.missed_blocks_counter
|
||||||
|
}}</VChip>
|
||||||
</div>
|
</div>
|
||||||
<UptimeBar :blocks="commits" :validator="toBase64(fromHex(consensusPubkeyToHexAddress(v.consensus_pubkey)))" />
|
<UptimeBar
|
||||||
|
:blocks="commits"
|
||||||
|
:validator="
|
||||||
|
toBase64(fromHex(consensusPubkeyToHexAddress(v.consensus_pubkey)))
|
||||||
|
"
|
||||||
|
/>
|
||||||
</VCol>
|
</VCol>
|
||||||
</VRow>
|
</VRow>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<route>
|
<route>
|
||||||
@ -113,7 +168,7 @@ watchEffect(() => {
|
|||||||
</route>
|
</route>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.v-field--variant-outlined .v-field__outline__notch{
|
.v-field--variant-outlined .v-field__outline__notch {
|
||||||
border-width: 0 !important;
|
border-width: 0 !important;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -2,14 +2,14 @@
|
|||||||
import { CosmosRestClient } from '@/libs/client';
|
import { CosmosRestClient } from '@/libs/client';
|
||||||
|
|
||||||
async function tt() {
|
async function tt() {
|
||||||
const address = "echelon1uattqtrtv8944qkmh44ll97qjacj6tgrekqzm9"
|
const address = 'echelon1uattqtrtv8944qkmh44ll97qjacj6tgrekqzm9';
|
||||||
const validator = "echelonvaloper1uattqtrtv8944qkmh44ll97qjacj6tgr2cupk4"
|
const validator = 'echelonvaloper1uattqtrtv8944qkmh44ll97qjacj6tgr2cupk4';
|
||||||
const client = new CosmosRestClient("https://api.ech.network")
|
const client = new CosmosRestClient('https://api.ech.network');
|
||||||
let response = await client.getBaseBlockLatest();
|
let response = await client.getBaseBlockLatest();
|
||||||
console.log('response:', response)
|
console.log('response:', response);
|
||||||
}
|
}
|
||||||
tt()
|
tt();
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div>Hello wallet</div>
|
<div>Hello wallet</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -1,35 +1,50 @@
|
|||||||
<script setup lang="ts">
|
<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 miscObj from '@images/pages/misc-404-object.png';
|
||||||
import miscMaskDark from '@images/pages/misc-mask-dark.png'
|
import miscMaskDark from '@images/pages/misc-mask-dark.png';
|
||||||
import miscMaskLight from '@images/pages/misc-mask-light.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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="misc-wrapper">
|
<div class="misc-wrapper">
|
||||||
<ErrorHeader error-code="404" error-title="Page Not Found ⚠️"
|
<ErrorHeader
|
||||||
error-description="We couldn't find the page you are looking for." />
|
error-code="404"
|
||||||
|
error-title="Page Not Found ⚠️"
|
||||||
|
error-description="We couldn't find the page you are looking for."
|
||||||
|
/>
|
||||||
|
|
||||||
<!-- 👉 Image -->
|
<!-- 👉 Image -->
|
||||||
<div class="misc-avatar w-100 text-center">
|
<div class="misc-avatar w-100 text-center">
|
||||||
<VImg :src="misc404" alt="Coming Soon" :height="$vuetify.display.xs ? 400 : 500" class="my-sm-4" />
|
<VImg
|
||||||
<VBtn to="/" class="mt-10">
|
:src="misc404"
|
||||||
Back to Home
|
alt="Coming Soon"
|
||||||
</VBtn>
|
:height="$vuetify.display.xs ? 400 : 500"
|
||||||
<VImg :src="miscThemeMask" class="d-none d-md-block footer-coming-soon" cover />
|
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>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@use "@core/scss/template/pages/misc.scss";
|
@use '@core/scss/template/pages/misc.scss';
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<route lang="yaml">
|
<route lang="yaml">
|
||||||
|
@ -4,15 +4,14 @@
|
|||||||
<VCardText>This is your second page.</VCardText>
|
<VCardText>This is your second page.</VCardText>
|
||||||
<VCardText>
|
<VCardText>
|
||||||
Chocolate sesame snaps pie carrot cake pastry pie lollipop muffin.
|
Chocolate sesame snaps pie carrot cake pastry pie lollipop muffin.
|
||||||
Carrot cake dragée chupa chups jujubes. Macaroon liquorice cookie
|
Carrot cake dragée chupa chups jujubes. Macaroon liquorice cookie wafer
|
||||||
wafer tart marzipan bonbon. Gingerbread jelly-o dragée
|
tart marzipan bonbon. Gingerbread jelly-o dragée chocolate.
|
||||||
chocolate.
|
|
||||||
</VCardText>
|
</VCardText>
|
||||||
</VCard>
|
</VCard>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<route lang="yaml">
|
<route lang="yaml">
|
||||||
meta:
|
meta:
|
||||||
layout: blank
|
layout: blank
|
||||||
bgColor: yellow
|
bgColor: yellow
|
||||||
</route>
|
</route>
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
import { createI18n } from 'vue-i18n'
|
import { createI18n } from 'vue-i18n';
|
||||||
|
|
||||||
const messages = Object.fromEntries(
|
const messages = Object.fromEntries(
|
||||||
Object.entries(
|
Object.entries(
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
import.meta.glob<{ default: any }>('./locales/*.json', { eager: true }))
|
import.meta.glob<{ default: any }>('./locales/*.json', { eager: true })
|
||||||
.map(([key, value]) => [key.slice(10, -5), value.default]),
|
).map(([key, value]) => [key.slice(10, -5), value.default])
|
||||||
)
|
);
|
||||||
|
|
||||||
export default createI18n({
|
export default createI18n({
|
||||||
legacy: false,
|
legacy: false,
|
||||||
locale: localStorage.getItem('lang') || 'en',
|
locale: localStorage.getItem('lang') || 'en',
|
||||||
fallbackLocale: 'en',
|
fallbackLocale: 'en',
|
||||||
messages,
|
messages,
|
||||||
})
|
});
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import type { CosmosRestClient } from '@/libs/client'
|
import type { CosmosRestClient } from '@/libs/client';
|
||||||
import 'pinia'
|
import 'pinia';
|
||||||
import type { Ref } from 'vue'
|
import type { Ref } from 'vue';
|
||||||
|
|
||||||
declare module 'pinia' {
|
declare module 'pinia' {
|
||||||
export interface PiniaCustomProperties {
|
export interface PiniaCustomProperties {
|
||||||
// by using a setter we can allow both strings and refs
|
// by using a setter we can allow both strings and refs
|
||||||
set rpc(value: CosmosRestClient | Ref<CosmosRestClient>)
|
set rpc(value: CosmosRestClient | Ref<CosmosRestClient>);
|
||||||
get rpc(): CosmosRestClient
|
get rpc(): CosmosRestClient;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
export * from './useBankStore'
|
export * from './useBankStore';
|
||||||
export * from './useBlockchain'
|
export * from './useBlockchain';
|
||||||
export * from './useCoinGecko'
|
export * from './useCoinGecko';
|
||||||
export * from './useDashboard'
|
export * from './useDashboard';
|
||||||
export * from './useBaseStore'
|
export * from './useBaseStore';
|
||||||
export * from './useFormatter'
|
export * from './useFormatter';
|
||||||
export * from './useGovStore'
|
export * from './useGovStore';
|
||||||
export * from './useMintStore'
|
export * from './useMintStore';
|
||||||
export * from './useStakingStore'
|
export * from './useStakingStore';
|
||||||
export * from './useDistributionStore'
|
export * from './useDistributionStore';
|
||||||
export * from './useParamsStore'
|
export * from './useParamsStore';
|
||||||
export * from './useWalletStore'
|
export * from './useWalletStore';
|
||||||
|
@ -1,13 +1,9 @@
|
|||||||
import { defineStore } from "pinia";
|
import { defineStore } from 'pinia';
|
||||||
|
|
||||||
export const useStoreName = defineStore('bankstore', {
|
export const useStoreName = defineStore('bankstore', {
|
||||||
state: () => {
|
state: () => {
|
||||||
return {
|
return {};
|
||||||
}
|
},
|
||||||
},
|
getters: {},
|
||||||
getters: {
|
actions: {},
|
||||||
|
});
|
||||||
},
|
|
||||||
actions: {
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
@ -1,48 +1,50 @@
|
|||||||
import { defineStore } from "pinia";
|
import { defineStore } from 'pinia';
|
||||||
|
|
||||||
import { useBlockchain } from "./useBlockchain";
|
import { useBlockchain } from './useBlockchain';
|
||||||
import { useStakingStore } from "./useStakingStore";
|
import { useStakingStore } from './useStakingStore';
|
||||||
import type { Coin, DenomTrace } from "@/types";
|
import type { Coin, DenomTrace } from '@/types';
|
||||||
|
|
||||||
export const useBankStore = defineStore('bankstore', {
|
export const useBankStore = defineStore('bankstore', {
|
||||||
state: () => {
|
state: () => {
|
||||||
return {
|
return {
|
||||||
supply: {} as Coin,
|
supply: {} as Coin,
|
||||||
balances: {} as Record<string, Coin[]>,
|
balances: {} as Record<string, Coin[]>,
|
||||||
totalSupply: {supply: [] as Coin[]} ,
|
totalSupply: { supply: [] as Coin[] },
|
||||||
}
|
};
|
||||||
|
},
|
||||||
|
getters: {
|
||||||
|
blockchain() {
|
||||||
|
return useBlockchain();
|
||||||
},
|
},
|
||||||
getters: {
|
staking() {
|
||||||
blockchain() {
|
return useStakingStore();
|
||||||
return useBlockchain()
|
|
||||||
},
|
|
||||||
staking() {
|
|
||||||
return useStakingStore()
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
actions: {
|
},
|
||||||
initial() {
|
actions: {
|
||||||
this.$reset()
|
initial() {
|
||||||
this.supply = {} as Coin
|
this.$reset();
|
||||||
const denom = this.staking.params.bond_denom || this.blockchain.current?.assets[0].base
|
this.supply = {} as Coin;
|
||||||
if(denom) {
|
const denom =
|
||||||
this.blockchain.rpc.getBankSupplyByDenom(denom).then(res => {
|
this.staking.params.bond_denom ||
|
||||||
if(res.amount) this.supply = res.amount
|
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) {
|
async fetchSupply(denom: string) {
|
||||||
const hash = denom.replace("ibc/", "")
|
return this.blockchain.rpc.getBankSupplyByDenom(denom);
|
||||||
let trace = this.ibcDenoms[hash]
|
},
|
||||||
if(!trace) {
|
async fetchDenomTrace(denom: string) {
|
||||||
trace = (await this.blockchain.rpc.getIBCAppTransferDenom( hash )).denom_trace
|
const hash = denom.replace('ibc/', '');
|
||||||
this.ibcDenoms[hash] = trace
|
let trace = this.ibcDenoms[hash];
|
||||||
}
|
if (!trace) {
|
||||||
return 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 { defineStore } from 'pinia';
|
||||||
import { useBlockchain } from "@/stores";
|
import { useBlockchain } from '@/stores';
|
||||||
import dayjs from "dayjs";
|
import dayjs from 'dayjs';
|
||||||
import type { Block } from "@/types";
|
import type { Block } from '@/types';
|
||||||
|
|
||||||
export const useBaseStore = defineStore('baseStore', {
|
export const useBaseStore = defineStore('baseStore', {
|
||||||
state: () => {
|
state: () => {
|
||||||
return {
|
return {
|
||||||
earlest: {} as Block,
|
earlest: {} as Block,
|
||||||
latest: {} as Block,
|
latest: {} as Block,
|
||||||
recents: [] 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: {
|
blockchain() {
|
||||||
blocktime(): number {
|
return useBlockchain();
|
||||||
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)
|
actions: {
|
||||||
return diff
|
async initial() {
|
||||||
}
|
this.fetchLatest();
|
||||||
}
|
},
|
||||||
return 6000
|
async clearRecentBlocks() {
|
||||||
},
|
this.recents = [];
|
||||||
blockchain() {
|
},
|
||||||
return useBlockchain()
|
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) {
|
async fetchValidatorByHeight(height?: number, offset = 0) {
|
||||||
return this.blockchain.rpc.getBaseValidatorsetAt(String(height))
|
return this.blockchain.rpc.getBaseValidatorsetAt(String(height));
|
||||||
},
|
},
|
||||||
async fetchLatestValidators(offset = 0) {
|
async fetchLatestValidators(offset = 0) {
|
||||||
return this.blockchain.rpc.getBaseValidatorsetLatest()
|
return this.blockchain.rpc.getBaseValidatorsetLatest();
|
||||||
},
|
},
|
||||||
async fetchBlock(height?: number) {
|
async fetchBlock(height?: number) {
|
||||||
return this.blockchain.rpc.getBaseBlockAt(String(height))
|
return this.blockchain.rpc.getBaseBlockAt(String(height));
|
||||||
},
|
},
|
||||||
async fetchAbciInfo() {
|
async fetchAbciInfo() {
|
||||||
return this.blockchain.rpc.getBaseNodeInfo()
|
return this.blockchain.rpc.getBaseNodeInfo();
|
||||||
}
|
},
|
||||||
// async fetchNodeInfo() {
|
// async fetchNodeInfo() {
|
||||||
// return this.blockchain.rpc.no()
|
// return this.blockchain.rpc.no()
|
||||||
// }
|
// }
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
@ -1,51 +1,54 @@
|
|||||||
import { defineStore } from "pinia";
|
import { defineStore } from 'pinia';
|
||||||
import { get } from '../libs/http'
|
import { get } from '../libs/http';
|
||||||
import type { LoadingStatus } from "./useDashboard";
|
import type { LoadingStatus } from './useDashboard';
|
||||||
|
|
||||||
export interface PriceMeta {
|
export interface PriceMeta {
|
||||||
usd?: string,
|
usd?: string;
|
||||||
usd_24h_change?: string,
|
usd_24h_change?: string;
|
||||||
cny?: string,
|
cny?: string;
|
||||||
cny_24h_change? : string,
|
cny_24h_change?: string;
|
||||||
eur?: string,
|
eur?: string;
|
||||||
eur_24h_change?: string,
|
eur_24h_change?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const LocalStoreKey = 'currency'
|
const LocalStoreKey = 'currency';
|
||||||
|
|
||||||
export const useCoingecko = defineStore('coingecko', {
|
export const useCoingecko = defineStore('coingecko', {
|
||||||
state: () => {
|
state: () => {
|
||||||
const currency = localStorage.getItem(LocalStoreKey)
|
const currency = localStorage.getItem(LocalStoreKey);
|
||||||
return {
|
return {
|
||||||
currency, // secondary currency
|
currency, // secondary currency
|
||||||
loadStatus: {} as Record<string, LoadingStatus | undefined>,
|
loadStatus: {} as Record<string, LoadingStatus | undefined>,
|
||||||
prices: {} as Record<string, PriceMeta>,
|
prices: {} as Record<string, PriceMeta>,
|
||||||
marketChart: {}
|
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 };
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
getCoinInfo(coinId: string) {
|
||||||
actions: {
|
return get(`https://api.coingecko.com/api/v3/coins/${coinId}`);
|
||||||
getMarketChart(days = 30, coinId = 'cosmos') {
|
},
|
||||||
return get(`https://api.coingecko.com/api/v3/coins/${coinId}/market_chart?vs_currency=usd&days=${days}`)
|
setSecondaryCurrency(currency: string) {
|
||||||
},
|
if (currency !== 'usd') {
|
||||||
|
localStorage.setItem(LocalStoreKey, currency);
|
||||||
fetchCoinPrice(ids: string[]) {
|
this.currency = currency;
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
@ -1,19 +1,18 @@
|
|||||||
import { defineStore } from "pinia";
|
import { defineStore } from 'pinia';
|
||||||
import { useBlockchain } from "./useBlockchain";
|
import { useBlockchain } from './useBlockchain';
|
||||||
|
|
||||||
export const useDistributionStore = defineStore('distributionStore', {
|
export const useDistributionStore = defineStore('distributionStore', {
|
||||||
state: () => {
|
state: () => {
|
||||||
return {
|
return {};
|
||||||
}
|
},
|
||||||
|
getters: {
|
||||||
|
blockchain() {
|
||||||
|
return useBlockchain();
|
||||||
},
|
},
|
||||||
getters: {
|
},
|
||||||
blockchain() {
|
actions: {
|
||||||
return useBlockchain()
|
async fetchCommunityPool() {
|
||||||
}
|
return this.blockchain.rpc.getDistributionCommunityPool();
|
||||||
},
|
},
|
||||||
actions: {
|
},
|
||||||
async fetchCommunityPool() {
|
});
|
||||||
return this.blockchain.rpc.getDistributionCommunityPool()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
@ -1,23 +1,23 @@
|
|||||||
import { defineStore } from "pinia";
|
import { defineStore } from 'pinia';
|
||||||
import { useBlockchain } from "./useBlockchain";
|
import { useBlockchain } from './useBlockchain';
|
||||||
import numeral from "numeral";
|
import numeral from 'numeral';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import duration from 'dayjs/plugin/duration'
|
import duration from 'dayjs/plugin/duration';
|
||||||
import relativeTime from 'dayjs/plugin/relativeTime'
|
import relativeTime from 'dayjs/plugin/relativeTime';
|
||||||
import updateLocale from 'dayjs/plugin/updateLocale'
|
import updateLocale from 'dayjs/plugin/updateLocale';
|
||||||
import utc from 'dayjs/plugin/utc'
|
import utc from 'dayjs/plugin/utc';
|
||||||
import localeData from 'dayjs/plugin/localeData'
|
import localeData from 'dayjs/plugin/localeData';
|
||||||
import { useStakingStore } from "./useStakingStore";
|
import { useStakingStore } from './useStakingStore';
|
||||||
import { fromBase64, fromBech32, fromHex, toHex } from "@cosmjs/encoding";
|
import { fromBase64, fromBech32, fromHex, toHex } from '@cosmjs/encoding';
|
||||||
import { consensusPubkeyToHexAddress } from "@/libs";
|
import { consensusPubkeyToHexAddress } from '@/libs';
|
||||||
import { useBankStore } from "./useBankStore";
|
import { useBankStore } from './useBankStore';
|
||||||
import type { DenomTrace } from "@/types";
|
import type { DenomTrace } from '@/types';
|
||||||
|
|
||||||
dayjs.extend(localeData)
|
dayjs.extend(localeData);
|
||||||
dayjs.extend(duration)
|
dayjs.extend(duration);
|
||||||
dayjs.extend(relativeTime)
|
dayjs.extend(relativeTime);
|
||||||
dayjs.extend(updateLocale)
|
dayjs.extend(updateLocale);
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc);
|
||||||
dayjs.updateLocale('en', {
|
dayjs.updateLocale('en', {
|
||||||
relativeTime: {
|
relativeTime: {
|
||||||
future: 'in %s',
|
future: 'in %s',
|
||||||
@ -34,168 +34,190 @@ dayjs.updateLocale('en', {
|
|||||||
y: 'a year',
|
y: 'a year',
|
||||||
yy: '%d years',
|
yy: '%d years',
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
export const useFormatter = defineStore('formatter', {
|
export const useFormatter = defineStore('formatter', {
|
||||||
state: () => {
|
state: () => {
|
||||||
return {
|
return {
|
||||||
ibcDenoms: {} as Record<string, DenomTrace>
|
ibcDenoms: {} as Record<string, DenomTrace>,
|
||||||
}
|
};
|
||||||
|
},
|
||||||
|
getters: {
|
||||||
|
blockchain() {
|
||||||
|
return useBlockchain();
|
||||||
},
|
},
|
||||||
getters: {
|
staking() {
|
||||||
blockchain() {
|
return useStakingStore();
|
||||||
return useBlockchain()
|
|
||||||
},
|
|
||||||
staking() {
|
|
||||||
return useStakingStore()
|
|
||||||
},
|
|
||||||
useBank() {
|
|
||||||
return useBankStore()
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
actions: {
|
useBank() {
|
||||||
async fetchDenomTrace(denom: string) {
|
return useBankStore();
|
||||||
const hash = denom.replace("ibc/", "")
|
},
|
||||||
let trace = this.ibcDenoms[hash]
|
},
|
||||||
if(!trace) {
|
actions: {
|
||||||
trace = (await this.blockchain.rpc.getIBCAppTransferDenom( hash )).denom_trace
|
async fetchDenomTrace(denom: string) {
|
||||||
this.ibcDenoms[hash] = trace
|
const hash = denom.replace('ibc/', '');
|
||||||
}
|
let trace = this.ibcDenoms[hash];
|
||||||
return trace
|
if (!trace) {
|
||||||
},
|
trace = (await this.blockchain.rpc.getIBCAppTransferDenom(hash))
|
||||||
formatTokenAmount(token: {denom: string, amount: string;}) {
|
.denom_trace;
|
||||||
return this.formatToken(token, false)
|
this.ibcDenoms[hash] = trace;
|
||||||
},
|
}
|
||||||
formatToken2(token: { denom: string, amount: string;}, withDenom = true) {
|
return trace;
|
||||||
return this.formatToken(token, true, '0,0.[00]')
|
},
|
||||||
},
|
formatTokenAmount(token: { denom: string; amount: string }) {
|
||||||
formatToken(token: { denom: string, amount: string;}, withDenom = true, fmt='0.0a') : string {
|
return this.formatToken(token, false);
|
||||||
if(token && token.amount) {
|
},
|
||||||
let amount = Number(token.amount)
|
formatToken2(token: { denom: string; amount: string }, withDenom = true) {
|
||||||
let denom = token.denom
|
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/")) {
|
if (denom && denom.startsWith('ibc/')) {
|
||||||
let ibcDenom = this.ibcDenoms[denom.replace("ibc/", "")]
|
let ibcDenom = this.ibcDenoms[denom.replace('ibc/', '')];
|
||||||
if(ibcDenom) {
|
if (ibcDenom) {
|
||||||
denom = ibcDenom.base_denom
|
denom = ibcDenom.base_denom;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const conf = this.blockchain.current?.assets?.find(x => x.base === token.denom || x.base.denom === token.denom)
|
const conf = this.blockchain.current?.assets?.find(
|
||||||
if(conf) {
|
(x) => x.base === token.denom || x.base.denom === token.denom
|
||||||
let unit = {exponent: 6, denom: ''}
|
);
|
||||||
// find the max exponent for display
|
if (conf) {
|
||||||
conf.denom_units.forEach(x => {
|
let unit = { exponent: 6, denom: '' };
|
||||||
if(x.exponent >= unit.exponent) {
|
// find the max exponent for display
|
||||||
unit = x
|
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]%')
|
|
||||||
}
|
}
|
||||||
return '-'
|
});
|
||||||
},
|
if (unit && unit.exponent > 0) {
|
||||||
validator(address: string) {
|
amount = amount / Math.pow(10, unit.exponent || 6);
|
||||||
if(!address) return address
|
denom = unit.denom.toUpperCase();
|
||||||
|
}
|
||||||
const txt = toHex(fromBase64(address)).toUpperCase()
|
}
|
||||||
const validator = this.staking.validators.find(x => consensusPubkeyToHexAddress(x.consensus_pubkey) === txt)
|
return `${numeral(amount).format(fmt)} ${
|
||||||
return validator?.description?.moniker
|
withDenom ? denom.substring(0, 10) : ''
|
||||||
},
|
}`;
|
||||||
validatorFromBech32(address: string) {
|
}
|
||||||
if(!address) return address
|
return '-';
|
||||||
const validator = this.staking.validators.find(x => x.operator_address === address)
|
},
|
||||||
return validator?.description?.moniker
|
formatTokens(
|
||||||
},
|
tokens?: { denom: string; amount: string }[],
|
||||||
calculatePercent(input?: string|number, total?: string|number ) {
|
withDenom = true,
|
||||||
if(!input || !total) return '0'
|
fmt = '0.0a'
|
||||||
const percent = Number(input)/Number(total)
|
): string {
|
||||||
return numeral(percent>0.0001?percent: 0).format("0.[00]%")
|
if (!tokens) return '';
|
||||||
},
|
return tokens.map((x) => this.formatToken(x, withDenom, fmt)).join(', ');
|
||||||
formatDecimalToPercent(decimal: string) {
|
},
|
||||||
return numeral(decimal).format('0.[00]%')
|
calculateBondedRatio(
|
||||||
},
|
pool: { bonded_tokens: string; not_bonded_tokens: string } | undefined
|
||||||
formatCommissionRate(rate?: string) {
|
) {
|
||||||
if(!rate) return '-'
|
if (pool && pool.bonded_tokens) {
|
||||||
return this.percent(rate)
|
const b = Number(pool.bonded_tokens);
|
||||||
},
|
const nb = Number(pool.not_bonded_tokens);
|
||||||
percent(decimal?: string|number) {
|
const p = b / (b + nb);
|
||||||
return decimal ? numeral(decimal).format('0.[00]%') : '-'
|
return numeral(p).format('0.[00]%');
|
||||||
},
|
}
|
||||||
numberAndSign(input: number, fmt="+0,0") {
|
return '-';
|
||||||
return numeral(input).format(fmt)
|
},
|
||||||
},
|
validator(address: string) {
|
||||||
toDay(time?: string, format = 'long') {
|
if (!address) return address;
|
||||||
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 ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
|
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 { defineStore } from 'pinia';
|
||||||
import { useBlockchain } from "./useBlockchain";
|
import { useBlockchain } from './useBlockchain';
|
||||||
import type { PageRequest, PaginatedProposals } from "@/types";
|
import type { PageRequest, PaginatedProposals } from '@/types';
|
||||||
import { LoadingStatus } from "./useDashboard";
|
import { LoadingStatus } from './useDashboard';
|
||||||
import {reactive} from 'vue'
|
import { reactive } from 'vue';
|
||||||
|
|
||||||
export const useGovStore = defineStore('govStore', {
|
export const useGovStore = defineStore('govStore', {
|
||||||
state: () => {
|
state: () => {
|
||||||
return {
|
return {
|
||||||
params: {
|
params: {
|
||||||
deposit: {},
|
deposit: {},
|
||||||
voting: {},
|
voting: {},
|
||||||
tally: {},
|
tally: {},
|
||||||
},
|
},
|
||||||
proposals: {} as Record<string, PaginatedProposals>,
|
proposals: {} as Record<string, PaginatedProposals>,
|
||||||
loading: {} as Record<string, LoadingStatus>
|
loading: {} as Record<string, LoadingStatus>,
|
||||||
}
|
};
|
||||||
|
},
|
||||||
|
getters: {
|
||||||
|
blockchain() {
|
||||||
|
return useBlockchain();
|
||||||
},
|
},
|
||||||
getters: {
|
},
|
||||||
blockchain() {
|
actions: {
|
||||||
return useBlockchain()
|
initial() {
|
||||||
}
|
this.fetchParams();
|
||||||
},
|
},
|
||||||
actions: {
|
async fetchProposals(status: string, pagination?: PageRequest) {
|
||||||
initial() {
|
if (!this.loading[status]) {
|
||||||
this.fetchParams()
|
this.loading[status] = LoadingStatus.Loading;
|
||||||
},
|
const proposals = reactive(
|
||||||
async fetchProposals( status: string, pagination?: PageRequest ) {
|
await this.blockchain.rpc.getGovProposals(status)
|
||||||
if(!this.loading[status]) {
|
);
|
||||||
this.loading[status] = LoadingStatus.Loading
|
if (status === '2') {
|
||||||
const proposals = reactive(await this.blockchain.rpc.getGovProposals(status))
|
proposals.proposals.forEach(async (x1) => {
|
||||||
if(status === '2') {
|
await this.fetchTally(x1.proposal_id).then((res) => {
|
||||||
proposals.proposals.forEach(async(x1) => {
|
x1.final_tally_result = res?.tally;
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
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 { defineStore } from 'pinia';
|
||||||
import { useBlockchain } from "./useBlockchain";
|
import { useBlockchain } from './useBlockchain';
|
||||||
|
|
||||||
export const useMintStore = defineStore('mintStore', {
|
export const useMintStore = defineStore('mintStore', {
|
||||||
state: () => {
|
state: () => {
|
||||||
return {
|
return {
|
||||||
inflation: "0",
|
inflation: '0',
|
||||||
}
|
};
|
||||||
|
},
|
||||||
|
getters: {
|
||||||
|
blockchain() {
|
||||||
|
return useBlockchain();
|
||||||
},
|
},
|
||||||
getters: {
|
},
|
||||||
blockchain() {
|
actions: {
|
||||||
return useBlockchain()
|
initial() {
|
||||||
}
|
this.fetchInflation();
|
||||||
},
|
},
|
||||||
actions: {
|
async fetchInflation() {
|
||||||
initial() {
|
this.blockchain.rpc
|
||||||
this.fetchInflation()
|
.getMintInflation()
|
||||||
},
|
.then((x) => {
|
||||||
async fetchInflation() {
|
this.inflation = x.inflation;
|
||||||
this.blockchain.rpc.getMintInflation().then(x => {
|
})
|
||||||
this.inflation = x.inflation
|
.catch(() => {
|
||||||
}).catch(() => {
|
this.inflation = '0';
|
||||||
this.inflation = "0"
|
});
|
||||||
})
|
},
|
||||||
}
|
},
|
||||||
}
|
});
|
||||||
})
|
|
||||||
|
@ -1,195 +1,246 @@
|
|||||||
import { defineStore } from "pinia";
|
import { defineStore } from 'pinia';
|
||||||
import { useBlockchain } from "./useBlockchain";
|
import { useBlockchain } from './useBlockchain';
|
||||||
import { percent,formatNumber,formatTokenAmount } from '@/libs/utils'
|
import { percent, formatNumber, formatTokenAmount } from '@/libs/utils';
|
||||||
export interface stakingItem {
|
export interface stakingItem {
|
||||||
unbonding_time: string
|
unbonding_time: string;
|
||||||
max_validators: number
|
max_validators: number;
|
||||||
max_entries:number
|
max_entries: number;
|
||||||
historical_entries:number
|
historical_entries: number;
|
||||||
bond_denom: string
|
bond_denom: string;
|
||||||
min_commission_rate: string
|
min_commission_rate: string;
|
||||||
min_self_delegation:string
|
min_self_delegation: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useParamStore = defineStore("paramstore", {
|
export const useParamStore = defineStore('paramstore', {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
latestTime: '',
|
latestTime: '',
|
||||||
chain: {
|
chain: {
|
||||||
title: '',
|
title: '',
|
||||||
class: 'border-primary',
|
class: 'border-primary',
|
||||||
items: [
|
items: [
|
||||||
{ subtitle: 'height', icon: 'BoxIcon', color: 'light-success', value: '-' },
|
{
|
||||||
{ subtitle: 'bonded_and_supply', icon: 'DollarSignIcon', color: 'light-danger', value: '-' },
|
subtitle: 'height',
|
||||||
{ subtitle: 'bonded_ratio', icon: 'PercentIcon', color: 'light-warning', value: '-' },
|
icon: 'BoxIcon',
|
||||||
{ subtitle: 'inflation', icon: 'TrendingUpIcon', color: 'light-primary', value: '-' },
|
color: 'light-success',
|
||||||
],
|
value: '-',
|
||||||
},
|
},
|
||||||
mint: {
|
{
|
||||||
title: 'Mint Parameters',
|
subtitle: 'bonded_and_supply',
|
||||||
items: [] as Array<any>,
|
icon: 'DollarSignIcon',
|
||||||
|
color: 'light-danger',
|
||||||
|
value: '-',
|
||||||
},
|
},
|
||||||
staking: {
|
{
|
||||||
title: 'Staking Parameters',
|
subtitle: 'bonded_ratio',
|
||||||
items: [] as Array<any>,
|
icon: 'PercentIcon',
|
||||||
|
color: 'light-warning',
|
||||||
|
value: '-',
|
||||||
},
|
},
|
||||||
distribution: {
|
{
|
||||||
title: 'Distribution Parameters',
|
subtitle: 'inflation',
|
||||||
items: [] as Array<any>,
|
icon: 'TrendingUpIcon',
|
||||||
},
|
color: 'light-primary',
|
||||||
slashing: {
|
value: '-',
|
||||||
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: {
|
mint: {
|
||||||
initial() {
|
title: 'Mint Parameters',
|
||||||
this.handleBaseBlockLatest()
|
items: [] as Array<any>,
|
||||||
// this.handleMintParam()
|
},
|
||||||
this.handleStakingParams()
|
staking: {
|
||||||
this.handleSlashingParams()
|
title: 'Staking Parameters',
|
||||||
this.handleDistributionParams()
|
items: [] as Array<any>,
|
||||||
this.handleGovernanceParams()
|
},
|
||||||
this.handleAbciInfo()
|
distribution: {
|
||||||
},
|
title: 'Distribution Parameters',
|
||||||
async handleBaseBlockLatest() {
|
items: [] as Array<any>,
|
||||||
try {
|
},
|
||||||
const res = await this.getBaseTendermintBlockLatest()
|
slashing: {
|
||||||
const height = this.chain.items.findIndex(x => x.subtitle === 'height')
|
title: 'Slashing Parameters',
|
||||||
this.chain.title = `Chain ID: ${res.block.header.chain_id}`
|
items: [] as Array<any>,
|
||||||
this.chain.items[height].value = res.block.header.height
|
},
|
||||||
// if (timeIn(res.block.header.time, 3, 'm')) {
|
gov: {
|
||||||
// this.syncing = true
|
title: 'Governance Parameters',
|
||||||
// } else {
|
items: [] as Array<any>,
|
||||||
// this.syncing = false
|
},
|
||||||
// }
|
appVersion: {
|
||||||
// this.latestTime = toDay(res.block.header.time, 'long')
|
title: 'Application Version',
|
||||||
this.latestTime = res.block.header.time
|
items: {},
|
||||||
} catch (error) {
|
},
|
||||||
console.warn(error)
|
nodeVersion: {
|
||||||
}
|
title: 'Node Information',
|
||||||
},
|
items: {},
|
||||||
async handleStakingParams() {
|
},
|
||||||
const res = await this.getStakingParams()
|
}),
|
||||||
const bond_denom = res?.params.bond_denom
|
getters: {
|
||||||
this.staking.items = Object.entries(res.params).map(([key, value]) => ({ subtitle:key,
|
blockchain() {
|
||||||
value: value })).filter((item: any) => {
|
return useBlockchain();
|
||||||
if (!['min_commission_rate','min_self_delegation'].includes(item.subtitle)) return item
|
},
|
||||||
})
|
},
|
||||||
Promise.all([this.getStakingPool(), this.getBankTotal(bond_denom)])
|
actions: {
|
||||||
.then(resArr => {
|
initial() {
|
||||||
const pool = resArr[0]?.pool
|
this.handleBaseBlockLatest();
|
||||||
const amount =resArr[1]?.amount?.amount
|
// this.handleMintParam()
|
||||||
const assets = this.blockchain.current?.assets
|
this.handleStakingParams();
|
||||||
const bondedAndSupply = this.chain.items.findIndex(x => x.subtitle === 'bonded_and_supply')
|
this.handleSlashingParams();
|
||||||
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)}`
|
this.handleDistributionParams();
|
||||||
const bondedRatio = this.chain.items.findIndex(x => x.subtitle === 'bonded_ratio')
|
this.handleGovernanceParams();
|
||||||
this.chain.items[bondedRatio].value = `${percent(Number(pool.bonded_tokens) /Number(amount)) }%`
|
this.handleAbciInfo();
|
||||||
})
|
},
|
||||||
},
|
async handleBaseBlockLatest() {
|
||||||
async handleMintParam() {
|
try {
|
||||||
const excludes = this.blockchain.current?.excludes
|
const res = await this.getBaseTendermintBlockLatest();
|
||||||
if(excludes && excludes.indexOf('mint') > -1){
|
const height = this.chain.items.findIndex(
|
||||||
return
|
(x) => x.subtitle === 'height'
|
||||||
}
|
);
|
||||||
// this.getMintingInflation().then(res => {
|
this.chain.title = `Chain ID: ${res.block.header.chain_id}`;
|
||||||
// const chainIndex = this.chain.items.findIndex(x => x.subtitle === 'inflation')
|
this.chain.items[height].value = res.block.header.height;
|
||||||
// this.chain.items[chainIndex].value = `${percent(res)}%`
|
// if (timeIn(res.block.header.time, 3, 'm')) {
|
||||||
// })
|
// this.syncing = true
|
||||||
const res = await this.getMintParam()
|
// } else {
|
||||||
console.log(res, 'mint')
|
// this.syncing = false
|
||||||
},
|
// }
|
||||||
async handleSlashingParams(){
|
// this.latestTime = toDay(res.block.header.time, 'long')
|
||||||
const res = await this.getSlashingParams()
|
this.latestTime = res.block.header.time;
|
||||||
this.slashing.items = Object.entries(res.params).map(([key, value]) => ({ subtitle:key,
|
} catch (error) {
|
||||||
value: value }))
|
console.warn(error);
|
||||||
},
|
}
|
||||||
async handleDistributionParams(){
|
},
|
||||||
const res = await this.getDistributionParams()
|
async handleStakingParams() {
|
||||||
this.distribution.items = Object.entries(res.params).map(([key, value]) => ({ subtitle: key,
|
const res = await this.getStakingParams();
|
||||||
value: value }))
|
const bond_denom = res?.params.bond_denom;
|
||||||
},
|
this.staking.items = Object.entries(res.params)
|
||||||
async handleGovernanceParams() {
|
.map(([key, value]) => ({ subtitle: key, value: value }))
|
||||||
const excludes = this.blockchain.current?.excludes
|
.filter((item: any) => {
|
||||||
if(excludes && excludes.indexOf('governance') > -1){
|
if (
|
||||||
return
|
!['min_commission_rate', 'min_self_delegation'].includes(
|
||||||
}
|
item.subtitle
|
||||||
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,
|
return item;
|
||||||
value: value }))
|
});
|
||||||
})
|
Promise.all([this.getStakingPool(), this.getBankTotal(bond_denom)]).then(
|
||||||
|
(resArr) => {
|
||||||
},
|
const pool = resArr[0]?.pool;
|
||||||
async handleAbciInfo(){
|
const amount = resArr[1]?.amount?.amount;
|
||||||
const res = await this.fetchAbciInfo()
|
const assets = this.blockchain.current?.assets;
|
||||||
this.appVersion.items = Object.entries(res.application_version).map(([key, value]) => ({ subtitle:key,
|
const bondedAndSupply = this.chain.items.findIndex(
|
||||||
value: value }))
|
(x) => x.subtitle === 'bonded_and_supply'
|
||||||
this.nodeVersion.items = Object.entries(res.default_node_info).map(([key, value]) => ({ subtitle:key,
|
);
|
||||||
value: value }))
|
this.chain.items[bondedAndSupply].value = `${formatNumber(
|
||||||
console.log('handleAbciInfo', this.nodeVersion.items)
|
formatTokenAmount(assets, pool.bonded_tokens, 2, bond_denom, false),
|
||||||
},
|
true,
|
||||||
async getBaseTendermintBlockLatest() {
|
0
|
||||||
return await this.blockchain.rpc.getBaseBlockLatest()
|
)}/${formatNumber(
|
||||||
},
|
formatTokenAmount(assets, amount, 2, bond_denom, false),
|
||||||
async getMintParam() {
|
true,
|
||||||
return await this.blockchain.rpc.getMintParam()
|
0
|
||||||
},
|
)}`;
|
||||||
async getStakingParams() {
|
const bondedRatio = this.chain.items.findIndex(
|
||||||
return await this.blockchain.rpc.getStakingParams()
|
(x) => x.subtitle === 'bonded_ratio'
|
||||||
},
|
);
|
||||||
async getStakingPool(){
|
this.chain.items[bondedRatio].value = `${percent(
|
||||||
return await this.blockchain.rpc.getStakingPool()
|
Number(pool.bonded_tokens) / Number(amount)
|
||||||
},
|
)}%`;
|
||||||
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()
|
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
}
|
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 { defineStore } from 'pinia';
|
||||||
import { useBlockchain } from "./useBlockchain";
|
import { useBlockchain } from './useBlockchain';
|
||||||
|
|
||||||
import { get } from "@/libs/http";
|
import { get } from '@/libs/http';
|
||||||
import type { StakingParam, StakingPool, Validator } from "@/types";
|
import type { StakingParam, StakingPool, Validator } from '@/types';
|
||||||
|
|
||||||
export const useStakingStore = defineStore('stakingStore', {
|
export const useStakingStore = defineStore('stakingStore', {
|
||||||
state: () => {
|
state: () => {
|
||||||
return {
|
return {
|
||||||
validators: [] as Validator[],
|
validators: [] as Validator[],
|
||||||
params: {} as {
|
params: {} as {
|
||||||
"unbonding_time": string,
|
unbonding_time: string;
|
||||||
"max_validators": number,
|
max_validators: number;
|
||||||
"max_entries": number,
|
max_entries: number;
|
||||||
"historical_entries": number,
|
historical_entries: number;
|
||||||
"bond_denom": string,
|
bond_denom: string;
|
||||||
"min_commission_rate": string,
|
min_commission_rate: string;
|
||||||
"min_self_delegation": string
|
min_self_delegation: string;
|
||||||
},
|
},
|
||||||
pool: {} as {
|
pool: {} as {
|
||||||
bonded_tokens: string,
|
bonded_tokens: string;
|
||||||
not_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: {
|
blockchain() {
|
||||||
totalPower(): number {
|
return useBlockchain();
|
||||||
const sum = (s:number, e: Validator) => { return s + parseInt(e.delegator_shares) }
|
|
||||||
return this.validators ? this.validators.reduce(sum, 0): 0
|
|
||||||
},
|
|
||||||
blockchain() {
|
|
||||||
return useBlockchain()
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
actions: {
|
},
|
||||||
async init() {
|
actions: {
|
||||||
this.$reset()
|
async init() {
|
||||||
this.fetchPool()
|
this.$reset();
|
||||||
this.fetchAcitveValdiators()
|
this.fetchPool();
|
||||||
return await this.fetchParams()
|
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 keybase(identity: string) {
|
||||||
},
|
return get(
|
||||||
async fetchParams() {
|
`https://keybase.io/_/api/1.0/user/lookup.json?key_suffix=${identity}&fields=pictures`
|
||||||
const response = await this.blockchain.rpc.getStakingParams()
|
);
|
||||||
if(response.params) this.params = response.params
|
},
|
||||||
return this.params
|
async fetchParams() {
|
||||||
},
|
const response = await this.blockchain.rpc.getStakingParams();
|
||||||
async fetchPool() {
|
if (response.params) this.params = response.params;
|
||||||
const response = await this.blockchain.rpc.getStakingPool()
|
return this.params;
|
||||||
response.pool.bonded_tokens
|
},
|
||||||
this.pool = response.pool
|
async fetchPool() {
|
||||||
},
|
const response = await this.blockchain.rpc.getStakingPool();
|
||||||
async fetchAcitveValdiators() {
|
response.pool.bonded_tokens;
|
||||||
return this.fetchValidators('BOND_STATUS_BONDED')
|
this.pool = response.pool;
|
||||||
},
|
},
|
||||||
async fetchInacitveValdiators() {
|
async fetchAcitveValdiators() {
|
||||||
return this.fetchValidators('BOND_STATUS_UNBONDED')
|
return this.fetchValidators('BOND_STATUS_BONDED');
|
||||||
},
|
},
|
||||||
async fetchValidator(validatorAddr: string) {
|
async fetchInacitveValdiators() {
|
||||||
return this.blockchain.rpc.getStakingValidator(validatorAddr)
|
return this.fetchValidators('BOND_STATUS_UNBONDED');
|
||||||
},
|
},
|
||||||
async fetchValidatorDelegation(validatorAddr: string, delegatorAddr: string) {
|
async fetchValidator(validatorAddr: string) {
|
||||||
return await this.blockchain.rpc.getStakingValidatorsDelegationsDelegator(validatorAddr, delegatorAddr)
|
return this.blockchain.rpc.getStakingValidator(validatorAddr);
|
||||||
},
|
},
|
||||||
async fetchValidators(status: string) {
|
async fetchValidatorDelegation(
|
||||||
return this.blockchain.rpc.getStakingValidators(status).then(res => {
|
validatorAddr: string,
|
||||||
const vals = res.validators.sort((a, b) => (Number(b.delegator_shares) - Number(a.delegator_shares)))
|
delegatorAddr: string
|
||||||
if(status==='BOND_STATUS_BONDED') {
|
) {
|
||||||
this.validators = vals
|
return await this.blockchain.rpc.getStakingValidatorsDelegationsDelegator(
|
||||||
}
|
validatorAddr,
|
||||||
return vals
|
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', {
|
export const useWalletStore = defineStore('walletStore', {
|
||||||
state: () => {
|
state: () => {
|
||||||
return {
|
return {};
|
||||||
}
|
},
|
||||||
},
|
getters: {},
|
||||||
getters: {
|
actions: {},
|
||||||
|
});
|
||||||
},
|
|
||||||
actions: {
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
import { fileURLToPath, URL } from "node:url";
|
import { fileURLToPath, URL } from 'node:url';
|
||||||
|
|
||||||
import { defineConfig } from "vite";
|
import { defineConfig } from 'vite';
|
||||||
import vue from "@vitejs/plugin-vue";
|
import vue from '@vitejs/plugin-vue';
|
||||||
import vueJsx from "@vitejs/plugin-vue-jsx";
|
import vueJsx from '@vitejs/plugin-vue-jsx';
|
||||||
import vuetify from "vite-plugin-vuetify";
|
import vuetify from 'vite-plugin-vuetify';
|
||||||
import Layouts from "vite-plugin-vue-layouts";
|
import Layouts from 'vite-plugin-vue-layouts';
|
||||||
import DefineOptions from "unplugin-vue-define-options/vite";
|
import DefineOptions from 'unplugin-vue-define-options/vite';
|
||||||
import Components from "unplugin-vue-components/vite";
|
import Components from 'unplugin-vue-components/vite';
|
||||||
import AutoImport from "unplugin-auto-import/vite";
|
import AutoImport from 'unplugin-auto-import/vite';
|
||||||
import Pages from "vite-plugin-pages";
|
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/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
@ -19,61 +19,70 @@ export default defineConfig({
|
|||||||
vueJsx(),
|
vueJsx(),
|
||||||
vuetify({
|
vuetify({
|
||||||
styles: {
|
styles: {
|
||||||
configFile: "src/plugins/vuetify/styles/variables/_vuetify.scss",
|
configFile: 'src/plugins/vuetify/styles/variables/_vuetify.scss',
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
Pages({
|
Pages({
|
||||||
dirs: ["./src/modules", "./src/pages", ],
|
dirs: ['./src/modules', './src/pages'],
|
||||||
exclude: ['**/*.ts'], // only load .vue as modules
|
exclude: ['**/*.ts'], // only load .vue as modules
|
||||||
}),
|
}),
|
||||||
Layouts({
|
Layouts({
|
||||||
layoutsDirs: "./src/layouts/",
|
layoutsDirs: './src/layouts/',
|
||||||
}),
|
}),
|
||||||
Components({
|
Components({
|
||||||
dirs: ["src/plugins/vuetify/@core/components"],
|
dirs: ['src/plugins/vuetify/@core/components'],
|
||||||
dts: true,
|
dts: true,
|
||||||
}),
|
}),
|
||||||
AutoImport({
|
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,
|
vueTemplate: true,
|
||||||
}),
|
}),
|
||||||
VueI18nPlugin({
|
VueI18nPlugin({
|
||||||
runtimeOnly: true,
|
runtimeOnly: true,
|
||||||
compositionOnly: true,
|
compositionOnly: true,
|
||||||
include: [
|
include: [
|
||||||
fileURLToPath(new URL('./src/plugins/i18n/locales/**', import.meta.url)),
|
fileURLToPath(
|
||||||
|
new URL('./src/plugins/i18n/locales/**', import.meta.url)
|
||||||
|
),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
DefineOptions(),
|
DefineOptions(),
|
||||||
],
|
],
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
"@": fileURLToPath(new URL("./src", import.meta.url)),
|
'@': fileURLToPath(new URL('./src', import.meta.url)),
|
||||||
"@themeConfig": fileURLToPath(
|
'@themeConfig': fileURLToPath(
|
||||||
new URL("./themeConfig.ts", import.meta.url)
|
new URL('./themeConfig.ts', import.meta.url)
|
||||||
),
|
),
|
||||||
"@configured-variables": fileURLToPath(
|
'@configured-variables': fileURLToPath(
|
||||||
new URL(
|
new URL(
|
||||||
"./src/plugins/vuetify/styles/variables/_template.scss",
|
'./src/plugins/vuetify/styles/variables/_template.scss',
|
||||||
import.meta.url
|
import.meta.url
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
"@core": fileURLToPath(
|
'@core': fileURLToPath(
|
||||||
new URL("./src/plugins/vuetify/@core", import.meta.url)
|
new URL('./src/plugins/vuetify/@core', import.meta.url)
|
||||||
),
|
),
|
||||||
"@layouts": fileURLToPath(
|
'@layouts': fileURLToPath(
|
||||||
new URL("./src/plugins/vuetify/@layouts", import.meta.url)
|
new URL('./src/plugins/vuetify/@layouts', import.meta.url)
|
||||||
),
|
),
|
||||||
"@images": fileURLToPath(
|
'@images': fileURLToPath(
|
||||||
new URL("./src/plugins/vuetify/images/", import.meta.url)
|
new URL('./src/plugins/vuetify/images/', import.meta.url)
|
||||||
),
|
),
|
||||||
"@styles": fileURLToPath(
|
'@styles': fileURLToPath(
|
||||||
new URL("./src/plugins/vuetify/styles/", import.meta.url)
|
new URL('./src/plugins/vuetify/styles/', import.meta.url)
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
optimizeDeps: {
|
optimizeDeps: {
|
||||||
exclude: ["vuetify"],
|
exclude: ['vuetify'],
|
||||||
entries: ["./src/**/*.vue"],
|
entries: ['./src/**/*.vue'],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user