improve validator and proposal

This commit is contained in:
liangping
2023-04-19 12:05:19 +08:00
parent d3a7c6f176
commit d6d56ba7c0
21 changed files with 1552 additions and 3276 deletions
+317
View File
@@ -0,0 +1,317 @@
<script lang="ts" setup>
import ObjectElement from '@/components/dynamic/ObjectElement.vue';
import { useBaseStore, useFormatter, useGovStore, useStakingStore } from '@/stores';
import type { GovProposal, GovVote, PaginabledAccounts, PaginatedProposalDeposit, PaginatedProposalVotes, Pagination } from '@/types';
import { ref } from 'vue';
import Countdown from '@/components/Countdown.vue';
import { computed } from '@vue/reactivity';
const props = defineProps(["proposal_id", "chain"]);
const proposal = ref({} as GovProposal)
const format = useFormatter()
const store = useGovStore()
store.fetchProposal(props.proposal_id).then((x) => proposal.value = x.proposal)
const color = computed(() => {
if (proposal.value.status==='PROPOSAL_STATUS_PASSED') {
return "success"
}else if (proposal.value.status==='PROPOSAL_STATUS_REJECTED') {
return "error"
}
return ""
})
const status = computed(() => {
if(proposal.value.status) {
return proposal.value.status.replace("PROPOSAL_STATUS_", "")
}
return ""
})
const deposit = ref({} as PaginatedProposalDeposit)
store.fetchProposalDeposits(props.proposal_id).then(x => deposit.value = x)
const votes = ref({} as GovVote[])
const votePage = ref({} as Pagination)
const loading = ref(false)
store.fetchProposalVotes(props.proposal_id).then(x => {
votes.value = x.votes
votePage.value = x.pagination
})
function loadMore() {
if(votePage.value.next_key) {
loading.value = true
store.fetchProposalVotes(props.proposal_id, votePage.value.next_key).then(x => {
votes.value = votes.value.concat(x.votes)
votePage.value = x.pagination
loading.value = false
})
}
}
function shortTime(v: string) {
if(v) {
return format.toDay(v, "from")
}
return ""
}
const votingCountdown = computed((): number => {
const now = new Date();
const end = new Date(proposal.value.voting_end_time)
return end.getTime() - now.getTime()
})
const upgradeCountdown = computed((): number => {
const height = Number(proposal.value.content?.plan?.height || 0)
if(height > 0) {
const base = useBaseStore()
const current = Number(base.latest?.block?.header?.height || 0)
return (height - current) * 6 * 1000
}
const now = new Date();
const end = new Date(proposal.value.content?.plan?.time || "")
return end.getTime() - now.getTime()
})
const total = computed(()=> {
const tally = proposal.value.final_tally_result
let sum = 0
if(tally) {
sum += Number(tally.abstain || 0)
sum += Number(tally.yes || 0)
sum += Number(tally.no || 0)
sum += Number(tally.no_with_veto || 0)
}
return sum
})
const turnout = computed(() => {
const bonded = useStakingStore().pool?.bonded_tokens || "1"
return format.percent(total.value / Number(bonded))
})
const yes = computed(()=> {
if(total.value > 0) {
const yes = proposal.value?.final_tally_result?.yes || 0
return format.percent(Number(yes) / total.value )
}
return 0
})
const no = computed(()=> {
if(total.value > 0) {
const value = proposal.value?.final_tally_result?.no || 0
return format.percent(Number(value) / total.value)
}
return 0
})
const veto = computed(()=> {
if(total.value > 0) {
const value = proposal.value?.final_tally_result?.no_with_veto || 0
return format.percent(Number(value) / total.value)
}
return 0
})
const abstain = computed(()=> {
if(total.value > 0) {
const value = proposal.value?.final_tally_result?.abstain || 0
return format.percent(Number(value) / total.value)
}
return 0
})
</script>
<template>
<div>
<VCard>
<VCardItem>
<VCardTitle>
{{ proposal_id }}. {{ proposal.content?.title }} <VChip label :color="color" class="float-right">{{ status }}</VChip>
</VCardTitle>
<ObjectElement :value="proposal.content"/>
</VCardItem>
</VCard>
<VRow class="my-5">
<VCol cols=12 md="4">
<VCard class="h-100">
<VCardItem>
<VCardTitle>Tally</VCardTitle>
<label>Turnout</label>
<v-progress-linear
:model-value="turnout"
height="25"
color="info"
>
<strong>{{ turnout }}</strong>
</v-progress-linear>
<label>Yes</label>
<v-progress-linear
:model-value="yes"
height="25"
color="success"
>
<strong>{{ yes }}</strong>
</v-progress-linear>
<label>No</label>
<v-progress-linear
:model-value="no"
height="25"
color="error"
>
<strong>{{ no }}</strong>
</v-progress-linear>
<label>No With Veto</label>
<v-progress-linear
:model-value="veto"
height="25"
color="primary"
>
<strong>{{ veto }}</strong>
</v-progress-linear>
<label>Abstain</label>
<v-progress-linear
:model-value="abstain"
height="25"
color="dark"
>
<strong>{{ abstain }}</strong>
</v-progress-linear>
</VCardItem>
</VCard>
</VCol>
<VCol cols=12 md="8">
<VCard>
<VCardItem>
<VCardTitle>
Timeline
</VCardTitle>
<VTimeline
class="mt-2"
side="end"
align="start"
line-inset="8"
truncate-line="both"
density="compact"
>
<VTimelineItem
dot-color="error"
size="x-small"
>
<!-- 👉 Header -->
<div class="d-flex justify-space-between flex-wrap mb-3">
<h6 class="text-base font-weight-medium me-3">
Submited at: {{ format.toDay(proposal.submit_time) }}
</h6>
<small class="text-xs text-disabled my-1">{{ shortTime(proposal.submit_time) }}</small>
</div>
</VTimelineItem>
<VTimelineItem
size="x-small"
dot-color="primary"
>
<!-- 👉 Header -->
<div class="d-flex justify-space-between flex-wrap mb-3">
<h6 class="text-base font-weight-medium me-3">
Deposited at: {{ format.toDay(proposal.status==="PROPOSAL_STATUS_DEPOSIT_PERIOD"?proposal.deposit_end_time: proposal.voting_start_time) }}
</h6>
<small class="text-xs text-disabled text-no-wrap my-1">{{ shortTime(proposal.status==="PROPOSAL_STATUS_DEPOSIT_PERIOD"?proposal.deposit_end_time: proposal.voting_start_time) }}</small>
</div>
<p class="mb-0">
<div v-for="x of deposit.deposits">
{{ x.depositor }} {{ format.formatTokens(x.amount) }}
</div>
</p>
</VTimelineItem>
<VTimelineItem
size="x-small"
dot-color="success"
>
<!-- 👉 Header -->
<div class="d-flex justify-space-between flex-wrap mb-3">
<h6 class="text-base font-weight-medium me-3">
Voting start from {{ format.toDay(proposal.voting_start_time) }}
</h6>
<small class="text-xs text-disabled text-no-wrap my-1">{{ shortTime(proposal.voting_start_time) }}</small>
</div>
<!-- 👉 Content -->
<p class="mb-0">
<Countdown :time="votingCountdown"/>
</p>
</VTimelineItem>
<VTimelineItem
size="x-small"
dot-color="success"
>
<!-- 👉 Header -->
<div class="d-flex justify-space-between flex-wrap mb-3">
<h6 class="text-base font-weight-medium me-3">
Voting end {{ format.toDay(proposal.voting_end_time) }}
</h6>
<small class="text-xs text-disabled text-no-wrap my-1">{{ shortTime(proposal.voting_end_time) }}</small>
</div>
<!-- 👉 Content -->
<p class="mb-0">
Current Status: {{ proposal.status }}
</p>
</VTimelineItem>
<VTimelineItem
v-if="proposal.content && proposal.content['@type'].endsWith('SoftwareUpgradeProposal')"
size="x-small"
dot-color="success"
>
<!-- 👉 Header -->
<div class="d-flex justify-space-between flex-wrap mb-3">
<h6 class="text-base font-weight-medium me-3">
Upgrade Plan:
<span v-if="Number(proposal.content?.plan?.height||'0') > 0"> (EST)</span>
<span v-else>{{ format.toDay(proposal.content?.plan?.time) }}</span>
</h6>
<small class="text-xs text-disabled text-no-wrap my-1">{{ shortTime(proposal.voting_end_time) }}</small>
</div>
<!-- 👉 Content -->
<p class="mb-0">
<Countdown :time="upgradeCountdown"/>
</p>
</VTimelineItem>
</VTimeline>
</VCardItem>
</VCard>
</VCol>
</VRow>
<VCard>
<VCardItem>
<VCardTitle>
Votes
</VCardTitle>
<VTable>
<tbody>
<tr v-for="x in votes">
<td>{{ x.voter }}</td>
<td>{{ x.option }}</td>
</tr>
</tbody>
</VTable>
<VBtn v-if="votePage.next_key" block variant="outlined" @click="loadMore()" :disabled="loading">Load more</VBtn>
</VCardItem>
</VCard>
</div>
</template>
+34 -10
View File
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { useBlockchain, useFormatter, useMintStore, useStakingStore } from '@/stores';
import { useBankStore, useBlockchain, useFormatter, useMintStore, useStakingStore } from '@/stores';
import { onMounted, computed, ref } from 'vue';
import ValidatorCommissionRate from '@/components/ValidatorCommissionRate.vue'
import { consensusPubkeyToHexAddress, operatorAddressToAccount, pubKeyToValcons, valoperToPrefix } from '@/libs';
@@ -18,6 +18,7 @@ const cache = JSON.parse(localStorage.getItem('avatars')||'{}')
const avatars = ref( cache || {} )
const identity = ref("")
const rewards = ref([] as Coin[]|undefined)
const commission = ref([] as Coin[]|undefined)
const addresses = ref({} as {
account: string
operAddress: string
@@ -79,7 +80,20 @@ onMounted(()=> {
addresses.value.valCons = pubKeyToValcons(v.value.consensus_pubkey, prefix)
})
blockchain.rpc.getDistributionValidatorOutstandingRewards(validator).then(res => {
rewards.value = res.rewards?.rewards
rewards.value = res.rewards?.rewards?.sort((a, b) => Number(b.amount) - Number(a.amount))
res.rewards?.rewards?.forEach(x => {
if(x.denom.startsWith("ibc/")) {
format.fetchDenomTrace(x.denom)
}
})
})
blockchain.rpc.getDistributionValidatorCommission(validator).then(res => {
commission.value = res.commission?.commission?.sort((a, b) => Number(b.amount) - Number(a.amount))
res.commission?.commission?.forEach(x => {
if(x.denom.startsWith("ibc/")) {
format.fetchDenomTrace(x.denom)
}
})
})
}
@@ -148,7 +162,7 @@ onMounted(()=> {
<div class="d-flex">
<VAvatar color="secondary" rounded variant="outlined" icon="mdi-flag"></VAvatar>
<div class="ml-3 d-flex flex-column justify-center">
<h4>{{ v.minSelfDelegation }} {{ staking.params.bond_denom }}</h4>
<h4>{{ v.min_self_delegation }} {{ staking.params.bond_denom }}</h4>
<span class="text-sm">Min Self Delegation:</span>
</div>
</div>
@@ -184,16 +198,26 @@ onMounted(()=> {
</VCard>
<VRow class="mt-3">
<VCol md="4" sm="12">
<VCol md="4" sm="12" class="h-100">
<ValidatorCommissionRate :commission="v.commission"></ValidatorCommissionRate>
</VCol>
<VCol md="4" sm="12">
<VCard title="Outstanding Rewards" class="h-100">
<VList>
<VListItem v-for="(i, k) in rewards" :key="`reward-${k}`">
<VAlertTitle>{{ format.formatToken2(i) }}</VAlertTitle>
</VListItem>
</VList>
<VCard class="h-100">
<VCardTitle>Commissions & Rewards</VCardTitle>
<VCardItem class="pt-0 pb-0">
<div class="overflow-auto" style="max-height: 280px;">
<VCardSubtitle>Commissions <VBtn size="small" class="float-right" variant="text">Withdraw</VBtn></VCardSubtitle>
<VDivider class="mb-2"></VDivider>
<VChip v-for="(i, k) in commission" :key="`reward-${k}`" color="info" label variant="outlined" class="mr-1 mb-1">
{{ format.formatToken2(i) }}
</VChip>
<VCardSubtitle class="mt-2">Outstanding Rewards</VCardSubtitle>
<VDivider class="mb-2"></VDivider>
<VChip v-for="(i, k) in rewards" :key="`reward-${k}`" color="success" label variant="outlined" class="mr-1 mb-1">
{{ format.formatToken2(i) }}
</VChip>
</div>
</VCardItem>
</VCard>
</VCol>
<VCol md="4" sm="12">