forked from cerc-io/cosmos-explorer
improve validator and proposal
This commit is contained in:
parent
d3a7c6f176
commit
d6d56ba7c0
@ -15,6 +15,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@casl/ability": "^6.3.3",
|
"@casl/ability": "^6.3.3",
|
||||||
"@casl/vue": "^2.2.1",
|
"@casl/vue": "^2.2.1",
|
||||||
|
"@chenfengyuan/vue-countdown": "2",
|
||||||
"@cosmjs/crypto": "^0.29.5",
|
"@cosmjs/crypto": "^0.29.5",
|
||||||
"@cosmjs/encoding": "^0.29.5",
|
"@cosmjs/encoding": "^0.29.5",
|
||||||
"@floating-ui/dom": "^1.2.0",
|
"@floating-ui/dom": "^1.2.0",
|
||||||
@ -22,6 +23,7 @@
|
|||||||
"@intlify/unplugin-vue-i18n": "^0.8.2",
|
"@intlify/unplugin-vue-i18n": "^0.8.2",
|
||||||
"@osmonauts/lcd": "^0.8.0",
|
"@osmonauts/lcd": "^0.8.0",
|
||||||
"@ping-pub/chain-registry-client": "^0.0.25",
|
"@ping-pub/chain-registry-client": "^0.0.25",
|
||||||
|
"@tomieric/vue-flip-countdown": "^0.0.5",
|
||||||
"@vitejs/plugin-vue-jsx": "^3.0.0",
|
"@vitejs/plugin-vue-jsx": "^3.0.0",
|
||||||
"@vueuse/core": "^9.12.0",
|
"@vueuse/core": "^9.12.0",
|
||||||
"@vueuse/math": "^9.12.0",
|
"@vueuse/math": "^9.12.0",
|
||||||
@ -41,6 +43,7 @@
|
|||||||
"vue-json-pretty": "^2.2.4",
|
"vue-json-pretty": "^2.2.4",
|
||||||
"vue-router": "^4.1.6",
|
"vue-router": "^4.1.6",
|
||||||
"vue3-apexcharts": "^1.4.1",
|
"vue3-apexcharts": "^1.4.1",
|
||||||
|
"vue3-flip-countdown": "^0.1.6",
|
||||||
"vue3-perfect-scrollbar": "^1.6.1",
|
"vue3-perfect-scrollbar": "^1.6.1",
|
||||||
"vuetify": "3.0.6",
|
"vuetify": "3.0.6",
|
||||||
"webfontloader": "^1.6.28"
|
"webfontloader": "^1.6.28"
|
||||||
|
12
src/components/Countdown.vue
Normal file
12
src/components/Countdown.vue
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<script lang="ts" setup >
|
||||||
|
import VueCountdown from '@chenfengyuan/vue-countdown';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
time: { type: Number},
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<vue-countdown v-if="time" :time="time > 0? time: 0" v-slot="{ days, hours, minutes, seconds }">
|
||||||
|
Time Remaining:{{ days }} days, {{ hours }} hours, {{ minutes }} minutes, {{ seconds }} seconds.
|
||||||
|
</vue-countdown>
|
||||||
|
</template>
|
@ -1,6 +1,6 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import MdEditor from 'md-editor-v3';
|
import MdEditor from 'md-editor-v3';
|
||||||
import { useFormatter, useStakingStore } from '@/stores';
|
import { useBlockchain, useFormatter, useStakingStore } from '@/stores';
|
||||||
import type { GovProposal, PaginatedProposals } from '@/types';
|
import type { GovProposal, PaginatedProposals } from '@/types';
|
||||||
import ProposalProcess from './ProposalProcess.vue';
|
import ProposalProcess from './ProposalProcess.vue';
|
||||||
import type { PropType } from 'vue';
|
import type { PropType } from 'vue';
|
||||||
@ -11,13 +11,20 @@ const props = defineProps({
|
|||||||
// const list = computed(()=> proposl)
|
// const list = computed(()=> proposl)
|
||||||
const format = useFormatter()
|
const format = useFormatter()
|
||||||
const staking = useStakingStore()
|
const staking = useStakingStore()
|
||||||
|
const chain = useBlockchain()
|
||||||
|
function showType(v: string){
|
||||||
|
if(v) {
|
||||||
|
return v.substring(v.lastIndexOf('.')+1)
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<VExpansionPanels variant="accordion">
|
<VExpansionPanels variant="accordion">
|
||||||
<VExpansionPanel v-for="(x, i) in proposals?.proposals">
|
<VExpansionPanel v-for="(x, i) in proposals?.proposals">
|
||||||
<VExpansionPanelTitle disable-icon-rotate>
|
<VExpansionPanelTitle disable-icon-rotate>
|
||||||
<VChip label color="primary" class="mr-2">{{x.proposal_id}}</VChip>
|
<VChip label color="primary" class="mr-2">{{x.proposal_id}}</VChip>
|
||||||
<div class="w-100">{{ x.content?.title }}
|
<div class="w-100"><VChip label>{{ showType(x.content['@type']) }}</VChip> {{ x.content?.title }}
|
||||||
<div class="d-flex mt-1">
|
<div class="d-flex mt-1">
|
||||||
<small class="text-secondary me-auto"> {{ format.toDay(x.voting_end_time, 'from') }}</small>
|
<small class="text-secondary me-auto"> {{ format.toDay(x.voting_end_time, 'from') }}</small>
|
||||||
<ProposalProcess style="width:300px;" :pool="staking.pool" :tally="x.final_tally_result"></ProposalProcess>
|
<ProposalProcess style="width:300px;" :pool="staking.pool" :tally="x.final_tally_result"></ProposalProcess>
|
||||||
@ -42,11 +49,11 @@ const staking = useStakingStore()
|
|||||||
<VExpansionPanelText>
|
<VExpansionPanelText>
|
||||||
<VCard class="card-box">
|
<VCard class="card-box">
|
||||||
<VCardText>
|
<VCardText>
|
||||||
{{ x.final_tally_result }}
|
|
||||||
<MdEditor :model-value="format.multiLine(x.content?.description)" previewOnly></MdEditor>
|
<MdEditor :model-value="format.multiLine(x.content?.description)" previewOnly></MdEditor>
|
||||||
</VCardText>
|
</VCardText>
|
||||||
<div class="text-center w-100 my-2">
|
<div class="text-center w-100 my-2">
|
||||||
<VBtn color="primary" variant="flat">Vote</VBtn>
|
<VBtn :to="`/${chain.chainName}/gov/${x.proposal_id}`" color="primary" variant="flat" size="small">Detail</VBtn>
|
||||||
|
<VBtn color="primary" variant="flat" class="ml-2" size="small">Vote</VBtn>
|
||||||
</div>
|
</div>
|
||||||
</VCard>
|
</VCard>
|
||||||
</VExpansionPanelText>
|
</VExpansionPanelText>
|
||||||
|
21
src/components/dynamic/ArrayCoinElement.vue
Normal file
21
src/components/dynamic/ArrayCoinElement.vue
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { useFormatter } from '@/stores';
|
||||||
|
import type { Coin } from '@/types';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
value: { type: Array<Coin>},
|
||||||
|
})
|
||||||
|
|
||||||
|
const format = useFormatter()
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
{{ format.formatTokens(value, true, "0,0.[000000]") }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
export default {
|
||||||
|
name: 'ArrayCoinElement'
|
||||||
|
}
|
||||||
|
</script>
|
@ -7,6 +7,7 @@ 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';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
value: { type: Array<Object>},
|
value: { type: Array<Object>},
|
||||||
@ -18,6 +19,8 @@ function selectByElement() {
|
|||||||
switch(true) {
|
switch(true) {
|
||||||
case first instanceof Uint8Array:
|
case first instanceof Uint8Array:
|
||||||
return ArrayBytesElement
|
return ArrayBytesElement
|
||||||
|
case Object.keys(first).includes('denom'):
|
||||||
|
return ArrayCoinElement
|
||||||
default:
|
default:
|
||||||
return ArrayObjectElement
|
return ArrayObjectElement
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import TextElement from './TextElement.vue'
|
|
||||||
import ObjectElement from './ObjectElement.vue'
|
|
||||||
import { select } from './index'
|
import { select } from './index'
|
||||||
|
|
||||||
const props = defineProps(["value", "direct"]);
|
const props = defineProps(["value", "direct"]);
|
||||||
|
@ -1,6 +1,17 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { useFormatter } from '@/stores';
|
||||||
|
import MdEditor from 'md-editor-v3';
|
||||||
|
|
||||||
const props = defineProps(["value"]);
|
const props = defineProps(["value"]);
|
||||||
|
const format = useFormatter()
|
||||||
|
function isMD() {
|
||||||
|
if(props.value && (props.value.indexOf("\n") > -1 || props.value.indexOf("\\n") > -1)){
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<span>{{ props.value }}</span>
|
<MdEditor v-if="isMD()" :model-value="format.multiLine(value)" previewOnly></MdEditor>
|
||||||
|
<span v-else>{{ value }}</span>
|
||||||
</template>
|
</template>
|
@ -10,7 +10,7 @@ export const DEFAULT: RequestRegistry = {
|
|||||||
bank_supply: { url: "/cosmos/bank/v1beta1/supply", adapter },
|
bank_supply: { url: "/cosmos/bank/v1beta1/supply", adapter },
|
||||||
bank_supply_by_denom: { url: "/cosmos/bank/v1beta1/supply/{denom}", adapter },
|
bank_supply_by_denom: { url: "/cosmos/bank/v1beta1/supply/{denom}", adapter },
|
||||||
distribution_params: { url: "/cosmos/distribution/v1beta1/params", adapter },
|
distribution_params: { url: "/cosmos/distribution/v1beta1/params", adapter },
|
||||||
distributino_community_pool: {url: "/cosmos/distribution/v1beta1/community_pool", adapter},
|
distributino_community_pool: { url: "/cosmos/distribution/v1beta1/community_pool", adapter },
|
||||||
distribution_validator_commission: { url: "/cosmos/distribution/v1beta1/validators/{validator_address}/commission", adapter },
|
distribution_validator_commission: { url: "/cosmos/distribution/v1beta1/validators/{validator_address}/commission", adapter },
|
||||||
distribution_validator_outstanding_rewards: { url: "/cosmos/distribution/v1beta1/validators/{validator_address}/outstanding_rewards", adapter },
|
distribution_validator_outstanding_rewards: { url: "/cosmos/distribution/v1beta1/validators/{validator_address}/outstanding_rewards", adapter },
|
||||||
distribution_validator_slashes: { url: "/cosmos/distribution/v1beta1/validators/{validator_address}/slashes", adapter },
|
distribution_validator_slashes: { url: "/cosmos/distribution/v1beta1/validators/{validator_address}/slashes", adapter },
|
||||||
@ -20,10 +20,10 @@ export const DEFAULT: RequestRegistry = {
|
|||||||
gov_params_tally: { url: "/cosmos/gov/v1beta1/params/tallying", adapter },
|
gov_params_tally: { url: "/cosmos/gov/v1beta1/params/tallying", adapter },
|
||||||
gov_params_deposit: { url: "/cosmos/gov/v1beta1/params/deposit", adapter },
|
gov_params_deposit: { url: "/cosmos/gov/v1beta1/params/deposit", adapter },
|
||||||
gov_proposals: { url: "/cosmos/gov/v1beta1/proposals", adapter },
|
gov_proposals: { url: "/cosmos/gov/v1beta1/proposals", adapter },
|
||||||
gov_proposals_proposal_id: {url: "/cosmos/gov/v1beta1/proposals/{proposal_id}", 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_deposits: { url: "/cosmos/gov/v1beta1/proposals/{proposal_id}/deposits", adapter },
|
||||||
gov_proposals_tally: { url: "/cosmos/gov/v1beta1/proposals/{proposal_id}/tally", adapter },
|
gov_proposals_tally: { url: "/cosmos/gov/v1beta1/proposals/{proposal_id}/tally", adapter },
|
||||||
gov_proposals_votes: { url: "/cosmos/gov/v1beta1/proposals/{proposal_id}/votes", 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 },
|
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_deletations: { url: "/cosmos/staking/v1beta1/delegations/{delegator_addr}", adapter },
|
||||||
staking_delegator_redelegations: { url: "/cosmos/staking/v1beta1/delegators/{delegator_addr}/redelegations", adapter },
|
staking_delegator_redelegations: { url: "/cosmos/staking/v1beta1/delegators/{delegator_addr}/redelegations", adapter },
|
||||||
@ -45,6 +45,20 @@ export const DEFAULT: RequestRegistry = {
|
|||||||
tx_txs: { url: "/cosmos/tx/v1beta1/txs", adapter },
|
tx_txs: { url: "/cosmos/tx/v1beta1/txs", adapter },
|
||||||
tx_txs_block: { url: "/cosmos/tx/v1beta1/txs/block/{height}", adapter },
|
tx_txs_block: { url: "/cosmos/tx/v1beta1/txs/block/{height}", adapter },
|
||||||
tx_hash: { url: "/cosmos/tx/v1beta1/txs/{hash}", adapter },
|
tx_hash: { url: "/cosmos/tx/v1beta1/txs/{hash}", adapter },
|
||||||
|
|
||||||
|
mint_inflation: { url: "/cosmos/mint/v1beta1/inflation", adapter},
|
||||||
|
mint_params: { url: "/cosmos/mint/v1beta1/params", adapter},
|
||||||
|
mint_annual_provisions: { url: "/cosmos/mint/v1beta1/annual_provisions", adapter},
|
||||||
|
|
||||||
|
// ibc
|
||||||
|
ibc_app_ica_controller_params: { url: "/ibc/apps/interchain_accounts/controller/v1/params", adapter },
|
||||||
|
ibc_app_ica_host_params: { url: "/ibc/apps/interchain_accounts/host/v1/params", adapter},
|
||||||
|
ibc_app_transfer_escrow_address: { url: "/ibc/apps/transfer/v1/channels/{channel_id}/ports/{port_id}/escrow_address", adapter},
|
||||||
|
ibc_app_transfer_denom_traces: { url: "/ibc/apps/transfer/v1/denom_traces", adapter},
|
||||||
|
ibc_app_transfer_denom_traces_hash: { url: "/ibc/apps/transfer/v1/denom_traces/{hash}", adapter},
|
||||||
|
ibc_core_channel_channels: { url: "/ibc/core/channel/v1/channels", adapter},
|
||||||
|
ibc_core_channel_channels_next_sequence: { url: "/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/next_sequence", adapter},
|
||||||
|
ibc_core_channel_channels_acknowledgements: { url: "/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/packet_acknowledgements", adapter}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const VERSION_REGISTRY: Registry = {
|
export const VERSION_REGISTRY: Registry = {
|
||||||
|
@ -12,7 +12,7 @@ export class CosmosRestClient {
|
|||||||
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)
|
||||||
}
|
}
|
||||||
@ -72,7 +72,7 @@ export class CosmosRestClient {
|
|||||||
async getGovParamsTally() {
|
async getGovParamsTally() {
|
||||||
return this.request(this.registry.gov_params_tally, {})
|
return this.request(this.registry.gov_params_tally, {})
|
||||||
}
|
}
|
||||||
async getGovProposals(status: string, limit = 100) {
|
async getGovProposals(status: string, limit = 50) {
|
||||||
const query = "?proposal_status={status}&pagination.limit={limit}&pagination.reverse=true&pagination.key="
|
const query = "?proposal_status={status}&pagination.limit={limit}&pagination.reverse=true&pagination.key="
|
||||||
return this.request(this.registry.gov_proposals, {status, limit}, query)
|
return this.request(this.registry.gov_proposals, {status, limit}, query)
|
||||||
}
|
}
|
||||||
@ -85,8 +85,8 @@ export class CosmosRestClient {
|
|||||||
async getGovProposalTally(proposal_id: string) {
|
async getGovProposalTally(proposal_id: string) {
|
||||||
return this.request(this.registry.gov_proposals_tally, {proposal_id})
|
return this.request(this.registry.gov_proposals_tally, {proposal_id})
|
||||||
}
|
}
|
||||||
async getGovProposalVotes(proposal_id: string) {
|
async getGovProposalVotes(proposal_id: string, next_key?: string) {
|
||||||
return this.request(this.registry.gov_proposals_votes, {proposal_id})
|
return this.request(this.registry.gov_proposals_votes, {proposal_id, next_key})
|
||||||
}
|
}
|
||||||
async getGovProposalVotesVoter(proposal_id: string, voter: string ) {
|
async getGovProposalVotesVoter(proposal_id: string, voter: string ) {
|
||||||
return this.request(this.registry.gov_proposals_votes_voter, {proposal_id, voter})
|
return this.request(this.registry.gov_proposals_votes_voter, {proposal_id, voter})
|
||||||
@ -147,7 +147,7 @@ export class CosmosRestClient {
|
|||||||
}
|
}
|
||||||
// tx
|
// tx
|
||||||
async getTxsBySender(sender: string) {
|
async getTxsBySender(sender: string) {
|
||||||
const query = `?events=message.sender='${sender}'&pagination.reverse=true`
|
const query = `?pagination.reverse=true&events=message.sender='${sender}'`
|
||||||
return this.request(this.registry.tx_txs, {}, query)
|
return this.request(this.registry.tx_txs, {}, query)
|
||||||
}
|
}
|
||||||
async getTxsAt(height: string|number) {
|
async getTxsAt(height: string|number) {
|
||||||
@ -168,4 +168,10 @@ export class CosmosRestClient {
|
|||||||
return this.request(this.registry.mint_annual_provisions, {})
|
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})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -76,6 +76,21 @@ export interface RequestRegistry {
|
|||||||
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_host_params: Request<any>
|
||||||
|
ibc_app_transfer_escrow_address: Request<any>;
|
||||||
|
ibc_app_transfer_denom_traces: Request<any>;
|
||||||
|
ibc_app_transfer_denom_traces_hash: Request<{
|
||||||
|
"denom_trace": {
|
||||||
|
"path": "string",
|
||||||
|
"base_denom": "string"
|
||||||
|
}
|
||||||
|
}>;
|
||||||
|
ibc_core_channel_channels: Request<any>;
|
||||||
|
ibc_core_channel_channels_next_sequence: Request<any>;
|
||||||
|
ibc_core_channel_channels_acknowledgements: Request<any>;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function adapter<T>(source: any): T {
|
export function adapter<T>(source: any): T {
|
||||||
|
317
src/modules/[chain]/gov/[proposal_id].vue
Normal file
317
src/modules/[chain]/gov/[proposal_id].vue
Normal 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>
|
@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<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 { 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';
|
||||||
@ -18,6 +18,7 @@ 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 addresses = ref({} as {
|
const addresses = ref({} as {
|
||||||
account: string
|
account: string
|
||||||
operAddress: string
|
operAddress: string
|
||||||
@ -79,7 +80,20 @@ onMounted(()=> {
|
|||||||
addresses.value.valCons = pubKeyToValcons(v.value.consensus_pubkey, prefix)
|
addresses.value.valCons = pubKeyToValcons(v.value.consensus_pubkey, prefix)
|
||||||
})
|
})
|
||||||
blockchain.rpc.getDistributionValidatorOutstandingRewards(validator).then(res => {
|
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">
|
<div class="d-flex">
|
||||||
<VAvatar color="secondary" rounded variant="outlined" icon="mdi-flag"></VAvatar>
|
<VAvatar color="secondary" rounded variant="outlined" icon="mdi-flag"></VAvatar>
|
||||||
<div class="ml-3 d-flex flex-column justify-center">
|
<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>
|
<span class="text-sm">Min Self Delegation:</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -184,16 +198,26 @@ onMounted(()=> {
|
|||||||
</VCard>
|
</VCard>
|
||||||
|
|
||||||
<VRow class="mt-3">
|
<VRow class="mt-3">
|
||||||
<VCol md="4" sm="12">
|
<VCol md="4" sm="12" class="h-100">
|
||||||
<ValidatorCommissionRate :commission="v.commission"></ValidatorCommissionRate>
|
<ValidatorCommissionRate :commission="v.commission"></ValidatorCommissionRate>
|
||||||
</VCol>
|
</VCol>
|
||||||
<VCol md="4" sm="12">
|
<VCol md="4" sm="12">
|
||||||
<VCard title="Outstanding Rewards" class="h-100">
|
<VCard class="h-100">
|
||||||
<VList>
|
<VCardTitle>Commissions & Rewards</VCardTitle>
|
||||||
<VListItem v-for="(i, k) in rewards" :key="`reward-${k}`">
|
<VCardItem class="pt-0 pb-0">
|
||||||
<VAlertTitle>{{ format.formatToken2(i) }}</VAlertTitle>
|
<div class="overflow-auto" style="max-height: 280px;">
|
||||||
</VListItem>
|
<VCardSubtitle>Commissions <VBtn size="small" class="float-right" variant="text">Withdraw</VBtn></VCardSubtitle>
|
||||||
</VList>
|
<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>
|
</VCard>
|
||||||
</VCol>
|
</VCol>
|
||||||
<VCol md="4" sm="12">
|
<VCol md="4" sm="12">
|
||||||
|
@ -2,7 +2,7 @@ import { defineStore } from "pinia";
|
|||||||
|
|
||||||
import { useBlockchain } from "./useBlockchain";
|
import { useBlockchain } from "./useBlockchain";
|
||||||
import { useStakingStore } from "./useStakingStore";
|
import { useStakingStore } from "./useStakingStore";
|
||||||
import type { Coin } from "@/types";
|
import type { Coin, DenomTrace } from "@/types";
|
||||||
|
|
||||||
export const useBankStore = defineStore('bankstore', {
|
export const useBankStore = defineStore('bankstore', {
|
||||||
state: () => {
|
state: () => {
|
||||||
@ -31,14 +31,17 @@ export const useBankStore = defineStore('bankstore', {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// async fetchTotalSupply(param: QueryTotalSupplyRequest): Promise<QueryTotalSupplyResponse> {
|
|
||||||
// const response = await this.blockchain.rpc.(param)
|
|
||||||
// this.totalSupply.supply = [...this.totalSupply.supply, ...response.supply]
|
|
||||||
// this.totalSupply.pagination = response.pagination
|
|
||||||
// return response
|
|
||||||
// },
|
|
||||||
async fetchSupply(denom: string) {
|
async fetchSupply(denom: string) {
|
||||||
return this.blockchain.rpc.getBankSupplyByDenom( denom )
|
return this.blockchain.rpc.getBankSupplyByDenom( denom )
|
||||||
|
},
|
||||||
|
async fetchDenomTrace(denom: string) {
|
||||||
|
const hash = denom.replace("ibc/", "")
|
||||||
|
let trace = this.ibcDenoms[hash]
|
||||||
|
if(!trace) {
|
||||||
|
trace = (await this.blockchain.rpc.getIBCAppTransferDenom( hash )).denom_trace
|
||||||
|
this.ibcDenoms[hash] = trace
|
||||||
|
}
|
||||||
|
return trace
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -10,6 +10,8 @@ import localeData from 'dayjs/plugin/localeData'
|
|||||||
import { useStakingStore } from "./useStakingStore";
|
import { useStakingStore } from "./useStakingStore";
|
||||||
import { fromBase64, toHex } from "@cosmjs/encoding";
|
import { fromBase64, toHex } from "@cosmjs/encoding";
|
||||||
import { consensusPubkeyToHexAddress } from "@/libs";
|
import { consensusPubkeyToHexAddress } from "@/libs";
|
||||||
|
import { useBankStore } from "./useBankStore";
|
||||||
|
import type { DenomTrace } from "@/types";
|
||||||
|
|
||||||
dayjs.extend(localeData)
|
dayjs.extend(localeData)
|
||||||
dayjs.extend(duration)
|
dayjs.extend(duration)
|
||||||
@ -37,6 +39,7 @@ dayjs.updateLocale('en', {
|
|||||||
export const useFormatter = defineStore('formatter', {
|
export const useFormatter = defineStore('formatter', {
|
||||||
state: () => {
|
state: () => {
|
||||||
return {
|
return {
|
||||||
|
ibcDenoms: {} as Record<string, DenomTrace>
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getters: {
|
getters: {
|
||||||
@ -45,9 +48,21 @@ export const useFormatter = defineStore('formatter', {
|
|||||||
},
|
},
|
||||||
staking() {
|
staking() {
|
||||||
return useStakingStore()
|
return useStakingStore()
|
||||||
|
},
|
||||||
|
useBank() {
|
||||||
|
return useBankStore()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
|
async fetchDenomTrace(denom: string) {
|
||||||
|
const hash = denom.replace("ibc/", "")
|
||||||
|
let trace = this.ibcDenoms[hash]
|
||||||
|
if(!trace) {
|
||||||
|
trace = (await this.blockchain.rpc.getIBCAppTransferDenom( hash )).denom_trace
|
||||||
|
this.ibcDenoms[hash] = trace
|
||||||
|
}
|
||||||
|
return trace
|
||||||
|
},
|
||||||
formatTokenAmount(token: {denom: string, amount: string;}) {
|
formatTokenAmount(token: {denom: string, amount: string;}) {
|
||||||
return this.formatToken(token, false)
|
return this.formatToken(token, false)
|
||||||
},
|
},
|
||||||
@ -58,6 +73,15 @@ export const useFormatter = defineStore('formatter', {
|
|||||||
if(token && token.amount) {
|
if(token && token.amount) {
|
||||||
let amount = Number(token.amount)
|
let amount = Number(token.amount)
|
||||||
let denom = token.denom
|
let denom = token.denom
|
||||||
|
|
||||||
|
if( denom && denom.startsWith("ibc/")) {
|
||||||
|
console.log(denom)
|
||||||
|
let ibcDenom = this.ibcDenoms[denom.replace("ibc/", "")]
|
||||||
|
if(ibcDenom) {
|
||||||
|
denom = ibcDenom.base_denom
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const conf = this.blockchain.current?.assets?.find(x => x.base === token.denom || x.base.denom === token.denom)
|
const conf = this.blockchain.current?.assets?.find(x => x.base === token.denom || x.base.denom === token.denom)
|
||||||
if(conf) {
|
if(conf) {
|
||||||
let unit = {exponent: 6, denom: ''}
|
let unit = {exponent: 6, denom: ''}
|
||||||
|
@ -49,6 +49,15 @@ export const useGovStore = defineStore('govStore', {
|
|||||||
},
|
},
|
||||||
async fetchTally(proposalId: string) {
|
async fetchTally(proposalId: string) {
|
||||||
return this.blockchain.rpc.getGovProposalTally(proposalId)
|
return 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -10,7 +10,7 @@ export enum LoadingStatus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface Pagination {
|
export interface Pagination {
|
||||||
key?: string;
|
next_key?: string;
|
||||||
total?: string;
|
total?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +62,11 @@ export interface PaginatedProposals extends PaginatedResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface PaginatedProposalDeposit extends PaginatedResponse {
|
export interface PaginatedProposalDeposit extends PaginatedResponse {
|
||||||
deposits: Coin[]
|
deposits: {
|
||||||
|
amount: Coin[],
|
||||||
|
proposal_id: string,
|
||||||
|
depositor: string
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PaginatedProposalVotes extends PaginatedResponse {
|
export interface PaginatedProposalVotes extends PaginatedResponse {
|
||||||
|
4
src/types/ibc.ts
Normal file
4
src/types/ibc.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export interface DenomTrace {
|
||||||
|
"path": "string",
|
||||||
|
"base_denom": "string"
|
||||||
|
}
|
@ -7,3 +7,4 @@ export * from './distribution'
|
|||||||
export * from './gov'
|
export * from './gov'
|
||||||
export * from './staking'
|
export * from './staking'
|
||||||
export * from './tx'
|
export * from './tx'
|
||||||
|
export * from './ibc'
|
4259
yarn-error.log
4259
yarn-error.log
File diff suppressed because it is too large
Load Diff
21
yarn.lock
21
yarn.lock
@ -1435,6 +1435,11 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime" "^7.19.4"
|
"@babel/runtime" "^7.19.4"
|
||||||
|
|
||||||
|
"@chenfengyuan/vue-countdown@2":
|
||||||
|
version "2.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@chenfengyuan/vue-countdown/-/vue-countdown-2.1.1.tgz#0e19b59b46eecab54b3a569d6a2dba78f7b6996f"
|
||||||
|
integrity sha512-HARJ62AFyxrBH/nMzwuaHUd20waKLN07mjyo2+8YfVouALkFERNRabqt5i3lfp3OISHb2054lWgyaX9L60hdPw==
|
||||||
|
|
||||||
"@confio/ics23@^0.6.8":
|
"@confio/ics23@^0.6.8":
|
||||||
version "0.6.8"
|
version "0.6.8"
|
||||||
resolved "https://registry.yarnpkg.com/@confio/ics23/-/ics23-0.6.8.tgz#2a6b4f1f2b7b20a35d9a0745bb5a446e72930b3d"
|
resolved "https://registry.yarnpkg.com/@confio/ics23/-/ics23-0.6.8.tgz#2a6b4f1f2b7b20a35d9a0745bb5a446e72930b3d"
|
||||||
@ -2469,6 +2474,13 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@sinonjs/commons" "^2.0.0"
|
"@sinonjs/commons" "^2.0.0"
|
||||||
|
|
||||||
|
"@tomieric/vue-flip-countdown@^0.0.5":
|
||||||
|
version "0.0.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tomieric/vue-flip-countdown/-/vue-flip-countdown-0.0.5.tgz#ecf832ebad03aef7cfefad76ca3988af2d66e427"
|
||||||
|
integrity sha512-V2Y37zFiing2cSTD1xLOs9S+ZLLwKvcOEMoCRpzElyWLxEyY9Q2lydU7jwRpA+8QRzhJ9P7JKCHGdd8Aukt7LQ==
|
||||||
|
dependencies:
|
||||||
|
vue "^3.0.2"
|
||||||
|
|
||||||
"@trysound/sax@0.2.0":
|
"@trysound/sax@0.2.0":
|
||||||
version "0.2.0"
|
version "0.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad"
|
resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad"
|
||||||
@ -7847,6 +7859,13 @@ vue3-apexcharts@^1.4.1:
|
|||||||
resolved "https://registry.yarnpkg.com/vue3-apexcharts/-/vue3-apexcharts-1.4.1.tgz#ea561308430a1c5213b7f17c44ba3c845f6c490d"
|
resolved "https://registry.yarnpkg.com/vue3-apexcharts/-/vue3-apexcharts-1.4.1.tgz#ea561308430a1c5213b7f17c44ba3c845f6c490d"
|
||||||
integrity sha512-96qP8JDqB9vwU7bkG5nVU+E0UGQn7yYQVqUUCLQMYWDuQyu2vE77H/UFZ1yI+hwzlSTBKT9BqnNG8JsFegB3eg==
|
integrity sha512-96qP8JDqB9vwU7bkG5nVU+E0UGQn7yYQVqUUCLQMYWDuQyu2vE77H/UFZ1yI+hwzlSTBKT9BqnNG8JsFegB3eg==
|
||||||
|
|
||||||
|
vue3-flip-countdown@^0.1.6:
|
||||||
|
version "0.1.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/vue3-flip-countdown/-/vue3-flip-countdown-0.1.6.tgz#995255932223a2cf6d58ae6ee1c1c78364157684"
|
||||||
|
integrity sha512-RRz+iZ7Zvr1U9mrZRya7I5815jboDyRJz9vzgILq8ZCc2fQ6SxZPYwOr3pD5oWCDBprAEsPF9x4fsTtEitSmXw==
|
||||||
|
dependencies:
|
||||||
|
vue "^3.0.0"
|
||||||
|
|
||||||
vue3-perfect-scrollbar@^1.6.1:
|
vue3-perfect-scrollbar@^1.6.1:
|
||||||
version "1.6.1"
|
version "1.6.1"
|
||||||
resolved "https://registry.yarnpkg.com/vue3-perfect-scrollbar/-/vue3-perfect-scrollbar-1.6.1.tgz#296e0e0c61a8f6278184f5b09bb45d137af92327"
|
resolved "https://registry.yarnpkg.com/vue3-perfect-scrollbar/-/vue3-perfect-scrollbar-1.6.1.tgz#296e0e0c61a8f6278184f5b09bb45d137af92327"
|
||||||
@ -7856,7 +7875,7 @@ vue3-perfect-scrollbar@^1.6.1:
|
|||||||
perfect-scrollbar "^1.5.5"
|
perfect-scrollbar "^1.5.5"
|
||||||
postcss-import "^12.0.0"
|
postcss-import "^12.0.0"
|
||||||
|
|
||||||
vue@^3.2.45:
|
vue@^3.0.0, vue@^3.0.2, vue@^3.2.45:
|
||||||
version "3.2.47"
|
version "3.2.47"
|
||||||
resolved "https://registry.yarnpkg.com/vue/-/vue-3.2.47.tgz#3eb736cbc606fc87038dbba6a154707c8a34cff0"
|
resolved "https://registry.yarnpkg.com/vue/-/vue-3.2.47.tgz#3eb736cbc606fc87038dbba6a154707c8a34cff0"
|
||||||
integrity sha512-60188y/9Dc9WVrAZeUVSDxRQOZ+z+y5nO2ts9jWXSTkMvayiWxCWOWtBQoYjLeccfXkiiPZWAHcV+WTPhkqJHQ==
|
integrity sha512-60188y/9Dc9WVrAZeUVSDxRQOZ+z+y5nO2ts9jWXSTkMvayiWxCWOWtBQoYjLeccfXkiiPZWAHcV+WTPhkqJHQ==
|
||||||
|
Loading…
Reference in New Issue
Block a user