finish tx detail

This commit is contained in:
liangping 2023-04-06 08:17:40 +08:00
parent 8e3c9eea0c
commit 70351f3833
31 changed files with 303 additions and 252 deletions

View File

@ -1,31 +1,26 @@
<script lang="ts" setup>
import { useFormatter } from '@/stores';
import type { Tally } from '@/types';
import { computed } from '@vue/reactivity';
import { ref, type PropType } from 'vue';
const props = defineProps({
tally: { type: Object as PropType<{
yes: string,
no: string,
noWithVeto: string,
abstain: string
}>},
tally: { type: Object as PropType<Tally>},
pool: {
type: Object as PropType<{
notBondedTokens: string;
bondedTokens: string;
not_bonded_tokens: string;
bonded_tokens: string;
}>,
},
})
const total = computed(() => props.pool?.bonded_tokens)
const format = useFormatter()
const yes = computed(() => (format.calculatePercent(props.tally?.yes, props.pool?.bondedTokens)))
const no = computed(() => ref(format.calculatePercent(props.tally?.no, props.pool?.bondedTokens)))
const abstain = computed(() => (format.calculatePercent(props.tally?.abstain, props.pool?.bondedTokens)))
const veto = computed(() => (format.calculatePercent(props.tally?.noWithVeto, props.pool?.bondedTokens)))
const yes = computed(() => (format.calculatePercent(props.tally?.yes, total.value)))
const no = computed(() => ref(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)))
console.log(yes.value, no.value, abstain.value, veto.value)
</script>
<template>
<div class="progress">

View File

@ -2,50 +2,33 @@
import VueApexCharts from 'vue3-apexcharts'
import { useTheme } from 'vuetify'
import { hexToRgb } from '@/plugins/vuetify/@layouts/utils'
import type { PropType } from 'vue';
import { computed, type PropType } from 'vue';
import { useFormatter } from '@/stores';
import type { CommissionRate } from '@/types'
const props = defineProps({
commission: { type: Object as PropType<{
commissionRates: {
rate: string,
maxRate: string,
maxChangeRate: string,
},
updateTime: string,
}>},
commission: { type: Object as PropType<CommissionRate>},
})
console.log('commission:', props)
const zeros = Math.pow(10, 16)
let rate = Number(props.commission?.commissionRates.rate || 0)
let change = Number(props.commission?.commissionRates.maxChangeRate || 10)
let max = Number(props.commission?.commissionRates.maxRate || 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)
if(rate > 100) {
rate = rate / zeros
}
if(change > 100) {
change = change / zeros
}
if(max > 100) {
max = max / zeros
}
// const rate = 15 // props.commision?.commissionRates.rate
// const change = 15
// const max = 20
const left = rate
const right = max - rate
const right = computed(() => max.value - rate.value)
const s1 = left > change ? left - change : 0
const s2 = left > change ? change: left
const s1 = computed(() => left.value > change.value ? left.value - change.value : 0 )
const s2 = computed(() => left.value > change.value ? change.value: left.value)
const s3 = 2
const s4 = right > change? change: right
const s5 = right > change? right - change: 0
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 = [s1, s2, s3, s4, s5]
const series = computed(() => [s1.value, s2.value, s3, s4.value, s5.value])
const vuetifyTheme = useTheme()
const format = useFormatter()
@ -99,7 +82,7 @@ const chartConfig = computed(() => {
offsetY: -15,
fontWeight: 500,
fontSize: '2.125rem',
formatter: (value: unknown) => `${rate}%`,
formatter: (value: unknown) => `${rate.value}%`,
color: primaryText,
},
total: {
@ -107,7 +90,7 @@ const chartConfig = computed(() => {
label: 'Commission Rate',
fontSize: '1rem',
color: secondaryText,
formatter: ( ) => `${rate}%`,
formatter: ( ) => `${rate.value}%`,
},
},
},
@ -127,7 +110,7 @@ const chartConfig = computed(() => {
</script>
<template>
<VCard title="Commission Rate" :subtitle="`Updated at ${format.toDay(props.commision?.updateTime, 'short')}`">
<VCard title="Commission Rate" :subtitle="`Updated at ${format.toDay(props.commission?.update_time, 'short')}`">
<VCardText>
<VueApexCharts
type="donut"

View File

@ -5,11 +5,11 @@ import { computed } from '@vue/reactivity';
import { hashTx } from '@/libs'
import { useBlockchain, useFormatter } from '@/stores';
const props = defineProps({
value: { type: Array<Uint8Array>},
value: { type: Array<string>},
});
const txs = computed(() => {
return props.value?.map(x => ({ hash: hashTx(x) , tx: decodeTxRaw(x) })) || []
return props.value?.map(x => ({ hash: hashTx(fromBase64(x)) , tx: decodeTxRaw(fromBase64(x)) })) || []
})
const format = useFormatter()
@ -26,7 +26,7 @@ const chain = useBlockchain()
<tbody>
<tr v-for="item in txs">
<td><RouterLink :to="`/${chain.chainName}/tx/${item.hash}`">{{ item.hash }}</RouterLink></td>
<td>{{ format.messages(item.tx.body.messages) }}</td>
<td>{{ format.messages(item.tx.body.messages.map(x => ({"@type": x.typeUrl}))) }}</td>
<td>{{ item.tx.body.memo }}</td>
</tr>
</tbody>

View File

@ -33,8 +33,8 @@ chainStore.initial()
>
<VList>
<!-- 👉 Rest -->
<VListSubheader v-if="chainStore.current?.endpoints?.rpc" title="Rest Endpoint" />
<VListItem v-for="i in chainStore.current?.endpoints?.rpc" link @click="chainStore.setRestEndpoint(i)">
<VListSubheader v-if="chainStore.current?.endpoints?.rest" title="Rest Endpoint" />
<VListItem v-for="i in chainStore.current?.endpoints?.rest" link @click="chainStore.setRestEndpoint(i)">
<VListItemTitle>{{ i.provider }} <VIcon v-if="i.address === chainStore.endpoint?.address" icon="mdi-check" color="success" /></VListItemTitle>
<VListItemSubtitle>{{ i.address }}</VListItemSubtitle>
</VListItem>

View File

@ -41,11 +41,14 @@ export function consensusPubkeyToHexAddress(consensusPubkey?: {"@type": string,
}
export function pubKeyToValcons(consensusPubkey: {"@type": string, key: string}, prefix: string) {
const pubkey = fromBase64(consensusPubkey.key)
if(pubkey) {
const addressData = sha256(pubkey).slice(0, 20)
return toBech32(`${prefix}valcons`, addressData)
if(consensusPubkey && consensusPubkey.key) {
const pubkey = fromBase64(consensusPubkey.key)
if(pubkey) {
const addressData = sha256(pubkey).slice(0, 20)
return toBech32(`${prefix}valcons`, addressData)
}
}
return ''
}
export function toETHAddress(cosmosAddress: string) {

View File

@ -10,6 +10,7 @@ export const DEFAULT: RequestRegistry = {
bank_supply: { url: "/cosmos/bank/v1beta1/supply", adapter },
bank_supply_by_denom: { url: "/cosmos/bank/v1beta1/supply/{denom}", adapter },
distribution_params: { url: "/cosmos/distribution/v1beta1/params", adapter },
distributino_community_pool: {url: "/cosmos/distribution/v1beta1/community_pool", adapter},
distribution_validator_commission: { url: "/cosmos/distribution/v1beta1/validators/{validator_address}/commission", adapter },
distribution_validator_outstanding_rewards: { url: "/cosmos/distribution/v1beta1/validators/{validator_address}/outstanding_rewards", adapter },
distribution_validator_slashes: { url: "/cosmos/distribution/v1beta1/validators/{validator_address}/slashes", adapter },
@ -30,7 +31,7 @@ export const DEFAULT: RequestRegistry = {
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", 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 },

View File

@ -5,9 +5,9 @@ import { adapter, type Request, type RequestRegistry } from './registry';
export class CosmosRestClient {
endpoint: string;
registry: RequestRegistry;
constructor(endpoint: string) {
constructor(endpoint: string, registry?: RequestRegistry) {
this.endpoint = endpoint
this.registry = DEFAULT
this.registry = registry || DEFAULT
}
async request<T>(request: Request<T>, args: Record<string, any>, query="") {
let url = `${this.endpoint}${request.url}${query}`
@ -42,6 +42,9 @@ export class CosmosRestClient {
// Distribution Module
async getDistributionParams() {
return this.request(this.registry.distribution_params, {})
}
async getDistributionCommunityPool() {
return this.request(this.registry.distributino_community_pool, {})
}
async getDistributionValidatorCommission(validator_address: string) {
return this.request(this.registry.distribution_validator_commission, {validator_address})
@ -69,8 +72,9 @@ export class CosmosRestClient {
async getGovParamsTally() {
return this.request(this.registry.gov_params_tally, {})
}
async getGovProposals() {
return this.request(this.registry.gov_proposals, {})
async getGovProposals(status: string, limit = 100) {
const query = "?proposal_status={status}&pagination.limit={limit}&pagination.reverse=true&pagination.key="
return this.request(this.registry.gov_proposals, {status, limit}, query)
}
async getGovProposal(proposal_id: string) {
return this.request(this.registry.gov_proposals_proposal_id, {proposal_id})
@ -106,8 +110,8 @@ export class CosmosRestClient {
async getStakingPool() {
return this.request(this.registry.staking_pool, {})
}
async getStakingValidators() {
return this.request(this.registry.staking_validators, {})
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})
@ -153,4 +157,15 @@ export class CosmosRestClient {
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, {})
}
}

View File

@ -29,6 +29,16 @@ export interface RequestRegistry {
distribution_validator_commission: Request<{commission?: {commission?: Coin[]}}>;
distribution_validator_outstanding_rewards: Request<{rewards?: {rewards?: Coin[]}}>;
distribution_validator_slashes: Request<PaginatedSlashes>;
distributino_community_pool: Request<{pool: Coin[]}>;
mint_inflation: Request<{inflation: string}>;
mint_params: Request<{
params: {
mint_denom: string,
blocks_per_year: string
}
}>;
mint_annual_provisions: Request<{annual_provisions: string}>
slashing_params: Request<any>;
slashing_signing_info: Request<PaginatedSigningInfo>;
@ -39,7 +49,7 @@ export interface RequestRegistry {
gov_proposals: Request<PaginatedProposals>;
gov_proposals_proposal_id: Request<{proposal: GovProposal}>;
gov_proposals_deposits: Request<PaginatedProposalDeposit>;
gov_proposals_tally: Request<Tally>;
gov_proposals_tally: Request<{tally: Tally}>;
gov_proposals_votes: Request<PaginatedProposalVotes>;
gov_proposals_votes_voter: Request<{vote: GovVote}>;

View File

@ -16,7 +16,7 @@ const height = computed(() => {
onBeforeRouteUpdate(async (to, from, next) => {
if (from.path !== to.path) {
store.fetchBlock(Number(to.params.height))
store.fetchBlock(String(to.params.height))
next()
}
})
@ -33,7 +33,7 @@ onBeforeRouteUpdate(async (to, from, next) => {
</span>
</VCardTitle>
<VCardItem class="pt-0">
<DynamicComponent :value="store.current.blockId"/>
<DynamicComponent :value="store.current.block_id"/>
</VCardItem>
</VCard>
@ -51,7 +51,7 @@ onBeforeRouteUpdate(async (to, from, next) => {
<VCard title="Last Commit" class="mt-5">
<VCardItem class="pt-0">
<DynamicComponent :value="store.current.block?.lastCommit"/>
<DynamicComponent :value="store.current.block?.last_commit"/>
</VCardItem>
</VCard>
</div>

View File

@ -22,7 +22,7 @@ export const useBlockModule = defineStore('blockModule', {
},
txsInRecents() {
const txs = [] as {hash:string, tx: DecodedTxRaw}[]
this.recents.forEach((x:GetLatestBlockResponse) => x.block?.data?.txs.forEach((tx:Uint8Array) => txs.push({
this.recents.forEach((x) => x.block?.data?.txs.forEach((tx:Uint8Array) => txs.push({
hash: hashTx(tx),
tx :decodeTxRaw(tx)
})))
@ -47,13 +47,13 @@ export const useBlockModule = defineStore('blockModule', {
})
},
async fetchLatest() {
this.latest = await this.blockchain.rpc.block()
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?: number) {
this.current = await this.blockchain.rpc.block(height)
async fetchBlock(height: string) {
this.current = await this.blockchain.rpc.getBaseBlockAt(height)
return this.current
},
}

View File

@ -1,14 +1,11 @@
<script lang="ts" setup>
import TxsElement from '@/components/dynamic/TxsElement.vue';
import { useBlockModule } from './block'
import DynamicComponent from '@/components/dynamic/DynamicComponent.vue';
import { computed } from '@vue/reactivity';
import { toBase64, toHex } from '@cosmjs/encoding';
import { computed, ref } from '@vue/reactivity';
import { useFormatter } from '@/stores';
const props = defineProps(["height", "chain"]);
const store = useBlockModule()
store.fetchBlock(props.height)
// store.fetchBlock(props.height)
const tab = ref('blocks')
const format = useFormatter()
@ -33,8 +30,8 @@ const format = useFormatter()
<tbody>
<tr v-for="item in store.recents">
<td><RouterLink :to="`/${props.chain}/block/${item.block?.header?.height}`">{{ item.block?.header?.height }}</RouterLink></td>
<td>{{ toBase64(item.blockId?.hash) }}</td>
<td>{{ format.validator(item.block?.header?.proposerAddress) }}</td>
<td>{{ item.block_id?.hash }}</td>
<td>{{ format.validator(item.block?.header?.proposer_address) }}</td>
<td>{{ item.block?.data?.txs.length }}</td>
<td>{{ format.toDay(item.block?.header?.time, 'from') }}</td>
</tr>

View File

@ -146,11 +146,11 @@ function shortName(name: string, id: string) {
<VExpansionPanels variant="accordion">
<VExpansionPanel v-for="(x, i) in store.proposals">
<VExpansionPanelTitle disable-icon-rotate>
<VChip label color="primary" class="mr-2">{{x.proposalId}}</VChip>
<VChip label color="primary" class="mr-2">{{x.proposal_id}}</VChip>
<div class="w-100">{{ x.content?.title }}
<div class="d-flex mt-1">
<small class="text-secondary me-auto"> {{ format.toDay(x.votingEndTime, 'from') }}</small>
<ProposalProcess style="width:300px;" :pool="store.pool" :tally="store.tally[Number(x.proposalId)]"></ProposalProcess>
<small class="text-secondary me-auto"> {{ format.toDay(x.voting_end_time, 'from') }}</small>
<ProposalProcess style="width:300px;" :pool="store.pool" :tally="store.tally[x.proposal_id]"></ProposalProcess>
<span></span>
</div>
</div>

View File

@ -2,6 +2,7 @@ import { useBlockchain, useCoingecko, useBaseStore, useBankStore, useFormatter,
import { useDistributionStore } from "@/stores/useDistributionStore";
import { useMintStore } from "@/stores/useMintStore";
import { useStakingStore } from "@/stores/useStakingStore";
import type { GovProposal, Tally } from "@/types";
import numeral from "numeral";
import { defineStore } from "pinia";
@ -64,13 +65,8 @@ export const useIndexModule = defineStore('module-index', {
total_volumes: [] as number[],
},
communityPool: [] as {amount: string, denom: string}[],
proposals: [] as Proposal[],
tally: {} as Record<number, {
yes: string;
abstain: string;
no: string;
noWithVeto: string;
}>
proposals: [] as GovProposal[],
tally: {} as Record<string, Tally>
}
},
getters: {
@ -144,7 +140,7 @@ export const useIndexModule = defineStore('module-index', {
title: 'Validators',
color: 'error',
icon: 'mdi-human-queue',
stats: String(base.latest.block?.lastCommit?.signatures.length || 0),
stats: String(base.latest.block?.last_commit?.signatures.length || 0),
change: 0,
},
{
@ -158,7 +154,7 @@ export const useIndexModule = defineStore('module-index', {
title: 'Bonded Tokens',
color: 'warning',
icon: 'mdi-lock',
stats: formatter.formatTokenAmount({amount: this.pool.bondedTokens, denom: staking.params.bondDenom }),
stats: formatter.formatTokenAmount({amount: this.pool.bonded_tokens, denom: staking.params.bond_denom }),
change: 0,
},
{
@ -185,18 +181,18 @@ export const useIndexModule = defineStore('module-index', {
this.initCoingecko()
useMintStore().fetchInflation()
useDistributionStore().fetchCommunityPool().then(x => {
this.communityPool = x.pool.filter(t=> t.denom.length < 10).map(t => ({
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(ProposalStatus.PROPOSAL_STATUS_VOTING_PERIOD).then(x => {
gov.fetchProposals(2).then(x => {
this.proposals = x.proposals
x.proposals.forEach(x1 => {
gov.fetchTally(Number(x1.proposalId)).then(t => {
gov.fetchTally(x1.proposal_id).then(t => {
console.log("log: ", t)
if(t.tally) this.tally[Number(x1.proposalId)] = t.tally
if(t.tally) this.tally[x1.proposal_id] = t.tally
})
})
})

View File

@ -1,11 +1,9 @@
<script setup lang="ts">
import { useBlockchain, useFormatter, useMintStore, useStakingStore } from '@/stores';
import { onMounted } from 'vue';
import { onMounted, computed, ref } from 'vue';
import ValidatorCommissionRate from '@/components/ValidatorCommissionRate.vue'
import { consensusPubkeyToHexAddress, operatorAddressToAccount, pubKeyToValcons, valoperToPrefix } from '@/libs';
import { computed } from '@vue/reactivity';
import type { Coin } from '@/types';
import type { Txs } from '@/types/Txs';
import type { Coin, Delegation, PaginatedTxs, Validator } from '@/types';
const props = defineProps(['validator', 'chain'])
@ -15,45 +13,44 @@ const format = useFormatter()
const validator: string = props.validator
const v = ref({})
const v = ref({} as Validator)
const cache = JSON.parse(localStorage.getItem('avatars')||'{}')
const avatars = ref( cache || {} )
const identity = ref("")
const rewards = ref([] as Coin[])
const rewards = ref([] as Coin[]|undefined)
const addresses = ref({} as {
account: string
operAddress: string
hex: string
valCons: string,
})
const selfBonded = ref({} as Coin)
const selfBonded = ref({} as Delegation)
addresses.value.account = operatorAddressToAccount(validator)
// load self bond
staking.fetchValidatorDelegation(validator, addresses.value.account).then(x => {
if(x) {
selfBonded.value = x
selfBonded.value = x.delegation_response
}
})
const txs = ref({} as Txs)
const txs = ref({} as PaginatedTxs)
blockchain.rpc.txs([`message.sender='${addresses.value.account}'`]).then(x => {
blockchain.rpc.getTxsBySender(addresses.value.account).then(x => {
console.log("txs", x)
txs.value = x
})
const apr = computed(()=> {
const rate = v.value.commission?.commissionRates.rate || 0
const rate = v.value.commission?.commission_rates.rate || 0
const inflation = useMintStore().inflation
if(Number(inflation)) {
return format.percent((1 - rate) * Number(inflation))
return format.percent((1 - Number(rate)) * Number(inflation))
}
return "-"
})
const selfRate = computed(()=> {
console.log("self rate", selfBonded.value.balance?.amount, v.value.tokens)
if(selfBonded.value.balance?.amount) {
return format.calculatePercent(selfBonded.value.balance.amount, v.value.tokens)
}
@ -62,9 +59,9 @@ const selfRate = computed(()=> {
onMounted(()=> {
if(validator) {
staking.fetchValidator(validator.toString()).then(res => {
staking.fetchValidator(validator).then(res => {
v.value = res.validator
identity.value = res.validator?.description?.identity
identity.value = res.validator?.description?.identity || ''
if(identity.value && !avatars.value[identity.value]) {
console.log(identity.value, avatars)
staking.keybase(identity.value).then(d => {
@ -77,12 +74,11 @@ onMounted(()=> {
}
})
}
const prefix = valoperToPrefix(v.value.operatorAddress) || '<Invalid>'
addresses.value.hex = consensusPubkeyToHexAddress(v.value.consensusPubkey)
addresses.value.valCons = pubKeyToValcons(v.value.consensusPubkey, prefix)
const prefix = valoperToPrefix(v.value.operator_address) || '<Invalid>'
addresses.value.hex = consensusPubkeyToHexAddress(v.value.consensus_pubkey)
addresses.value.valCons = pubKeyToValcons(v.value.consensus_pubkey, prefix)
})
blockchain.rpc.validatorOutstandingRewards(validator).then(res => {
console.log(res)
blockchain.rpc.getDistributionValidatorOutstandingRewards(validator).then(res => {
rewards.value = res.rewards?.rewards
})
}
@ -114,7 +110,7 @@ onMounted(()=> {
<span>Website: </span><span> {{ v.description?.website || '-' }}</span>
</VListItem>
<VListItem prepend-icon="mdi-phone">
<span>Contact: </span><span> {{ v.description?.securityContact }}</span>
<span>Contact: </span><span> {{ v.description?.security_contact }}</span>
</VListItem>
</VList>
@ -137,7 +133,7 @@ onMounted(()=> {
<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.bondDenom}) }}</h4>
<h4>{{ format.formatToken2({amount: v.tokens, denom: staking.params.bond_denom}) }}</h4>
<span class="text-sm">Bonded Tokens</span>
</div>
</div>
@ -152,7 +148,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.bondDenom }}</h4>
<h4>{{ v.minSelfDelegation }} {{ staking.params.bond_denom }}</h4>
<span class="text-sm">Min Self Delegation:</span>
</div>
</div>
@ -167,7 +163,7 @@ onMounted(()=> {
<div class="d-flex">
<VAvatar color="secondary" rounded variant="outlined" icon="mdi-pound"></VAvatar>
<div class="ml-3 d-flex flex-column justify-center">
<h4>{{ v.unbondingHeight }}</h4>
<h4>{{ v.unbonding_height }}</h4>
<span class="text-sm">Unbonding Height</span>
</div>
</div>
@ -175,7 +171,7 @@ onMounted(()=> {
<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.unbondingTime, 'from') }}</h4>
<h4>{{ format.toDay(v.unbonding_time, 'from') }}</h4>
<span class="text-sm">Unbonding Time</span>
</div>
</div>
@ -209,7 +205,7 @@ onMounted(()=> {
</VListItem>
<VListItem>
<VListItemTitle>Operator Address</VListItemTitle>
<VListItemSubtitle class="text-caption">{{ v.operatorAddress }}</VListItemSubtitle>
<VListItemSubtitle class="text-caption">{{ v.operator_address }}</VListItemSubtitle>
</VListItem>
<VListItem>
<VListItemTitle>Hex Address</VListItemTitle>
@ -233,10 +229,10 @@ onMounted(()=> {
<th class="text-left pl-4">Time</th>
</thead>
<tbody>
<tr v-for="(item, i) in txs.txResponses">
<tr v-for="(item, i) in txs.tx_responses">
<td>{{ item.height }}</td>
<td class="text-truncate" style="max-width: 200px;">{{ item.txhash }}</td>
<td>{{ format.messages(txs.txs[i]?.body.messages) }}</td>
<td>{{ format.messages(item.tx.body.messages) }}</td>
<td width="150">{{ format.toDay(item.timestamp,'from') }}</td>
</tr>
</tbody>

View File

@ -1,10 +1,10 @@
<script lang=ts setup>
import { useBaseStore, useFormatter, useStakingStore } from '@/stores';
import { toBase64, toHex } from '@cosmjs/encoding';
import { pubkeyToAddress } from '@cosmjs/tendermint-rpc';
import { computed } from '@vue/reactivity';
import { onMounted, ref, type DebuggerEvent } from 'vue';
import { consensusPubkeyToHexAddress } from '@/libs'
import type { Key, Validator } from '@/types';
const staking = useStakingStore()
const format = useFormatter()
@ -13,7 +13,7 @@ const avatars = ref( cache || {} )
const latest = ref({} as Record<string, number>)
const yesterday = ref({} as Record<string, number>)
const tab = ref('active')
const unbondList = ref([])
const unbondList = ref([] as Validator[])
const base = useBaseStore()
onMounted(()=> {
fetchChange(0)
@ -25,39 +25,39 @@ onMounted(()=> {
function fetchChange(offset: number) {
const base = useBaseStore()
const diff = 86400000 / base.blocktime
base.fetchAbciInfo().then(h => {
// console.log('block:', h)
base.fetchValidatorByHeight(h.lastBlockHeight, offset).then(x => {
x.validators.forEach(v => {
if(v.pubkey) latest.value[pubkeyToAddress(v.pubkey.algorithm, v.pubkey.data)] = Number(v.votingPower)
})
})
const height = Number(h.lastBlockHeight) - diff
base.fetchValidatorByHeight(height > 0 ? height : 1, offset).then(old => {
old.validators.forEach(v => {
if(v.pubkey) yesterday.value[pubkeyToAddress(v.pubkey.algorithm, v.pubkey.data)] = Number(v.votingPower)
})
// console.log(Object.keys(yesterday.value).map(x => x.toUpperCase()))
})
})
// base.fetchAbciInfo().then(h => {
// // console.log('block:', h)
// base.fetchValidatorByHeight(h.lastBlockHeight, offset).then(x => {
// x.validators.forEach(v => {
// if(v.pubkey) latest.value[pubkeyToAddress(v.pubkey.algorithm, v.pubkey.data)] = Number(v.votingPower)
// })
// })
// const height = Number(h.lastBlockHeight) - diff
// base.fetchValidatorByHeight(height > 0 ? height : 1, offset).then(old => {
// old.validators.forEach(v => {
// if(v.pubkey) yesterday.value[pubkeyToAddress(v.pubkey.algorithm, v.pubkey.data)] = Number(v.votingPower)
// })
// // console.log(Object.keys(yesterday.value).map(x => x.toUpperCase()))
// })
// })
}
const change24 = (key: {typeUrl: string, value: Uint8Array}) => {
const change24 = (key: Key) => {
// console.log('hex key:', consensusPubkeyToHexAddress(key))
const txt = toBase64(key.value)
const txt = key.key
const n : number = latest.value[txt];
const o : number = yesterday.value[txt]
// console.log( txt, n, o)
return n >0 && o > 0 ? n - o : 0
}
const change24Text = (key?: {typeUrl: string, value: Uint8Array}) => {
const change24Text = (key?: Key) => {
if(!key) return ''
const v = change24(key)
return v!==0 ? format.numberAndSign(v) : ''
}
const change24Color = (key?: {typeUrl: string, value: Uint8Array}) => {
const change24Color = (key?: Key) => {
if(!key) return ''
const v = change24(key)
if(v > 0) return 'text-success'
@ -71,8 +71,8 @@ const update = (m: DebuggerEvent) => {
}
const list = computed(() => {
// return tab.value === 'active' ? staking.validators: unbondList.value
return staking.validators
return tab.value === 'active' ? staking.validators: unbondList.value
// return staking.validators
})
const loadAvatars = () => {
@ -116,7 +116,7 @@ const logo = (identity?: string) => {
const rank = function(position: number) {
let sum = 0
for(let i = 0;i < position; i++) {
sum += Number(staking.validators[i]?.delegatorShares)
sum += Number(staking.validators[i]?.delegator_shares)
}
const percent = (sum / staking.totalPower)
@ -135,7 +135,7 @@ const rank = function(position: number) {
<VBtn value="active" variant="outlined" >Active</VBtn>
<VBtn value="inactive" variant="outlined">Inactive</VBtn>
</VBtnToggle>
<span class="mt-2">{{ list.length }}/{{ staking.params.maxValidators }}</span>
<span class="mt-2">{{ list.length }}/{{ staking.params.max_validators }}</span>
</VCardTitle>
<VTable class="text-no-wrap table-header-bg rounded-0">
<thead>
@ -164,7 +164,7 @@ const rank = function(position: number) {
<tbody>
<tr
v-for="(v, i) in list"
:key="v.operatorAddress"
:key="v.operator_address"
>
<!-- 👉 rank -->
<td>
@ -186,7 +186,7 @@ const rank = function(position: number) {
<div class="d-flex flex-column">
<h6 class="text-sm">
<RouterLink
:to="{name: 'chain-staking-validator', params: {validator: v.operatorAddress}}"
:to="{name: 'chain-staking-validator', params: {validator: v.operator_address}}"
class="font-weight-medium user-list-name"
>
{{ v.description?.moniker }}
@ -202,18 +202,18 @@ const rank = function(position: number) {
<td class="text-right">
<div class="d-flex flex-column">
<h6 class="text-sm font-weight-medium">
{{ format.formatToken( {amount: parseInt(v.tokens).toString(), denom: staking.params.bondDenom }, true, "0,0") }}
{{ format.formatToken( {amount: parseInt(v.tokens).toString(), denom: staking.params.bond_denom }, true, "0,0") }}
</h6>
<span class="text-xs">{{ format.calculatePercent(v.delegatorShares, staking.totalPower) }}</span>
<span class="text-xs">{{ format.calculatePercent(v.delegator_shares, staking.totalPower) }}</span>
</div>
</td>
<!-- 👉 24h Changes -->
<td class="text-right text-xs" :class="change24Color(v.consensusPubkey)">
{{ change24Text(v.consensusPubkey) }} <VChip label v-if="v.jailed" color="error">Jailed</VChip>
<td class="text-right text-xs" :class="change24Color(v.consensus_pubkey)">
{{ change24Text(v.consensus_pubkey) }} <VChip label v-if="v.jailed" color="error">Jailed</VChip>
</td>
<!-- 👉 commission -->
<td class="text-right">
{{ format.formatCommissionRate(v.commission?.commissionRates?.rate) }}
{{ format.formatCommissionRate(v.commission?.commission_rates?.rate) }}
</td>
<!-- 👉 Action -->
<td>

View File

@ -1,17 +1,19 @@
<script lang="ts" setup>
import { useBlockchain, useFormatter } from '@/stores';
import type { GetTxResponse } from 'cosmjs-types/cosmos/tx/v1beta1/service';
import DynamicComponent from '@/components/dynamic/DynamicComponent.vue';
import { computed } from '@vue/reactivity';
import { fromBase64, toBase64 } from '@cosmjs/encoding';
import { computed, ref } from '@vue/reactivity';
import type { Tx, TxResponse } from '@/types';
const props = defineProps(['hash', 'chain'])
const blockchain = useBlockchain()
const format = useFormatter()
const tx = ref({} as GetTxResponse)
const tx = ref({} as {
tx: Tx;
tx_response: TxResponse
})
if(props.hash) {
blockchain.rpc.tx(props.hash).then(x => tx.value = x)
blockchain.rpc.getTx(props.hash).then(x => tx.value = x)
}
const messages = computed(() => {
return tx.value.tx?.body?.messages||[]
@ -19,19 +21,19 @@ const messages = computed(() => {
</script>
<template>
<div>
<VCard v-if="tx.txResponse" title="Summary">
<VCard v-if="tx.tx_response" title="Summary">
<VCardItem class="pt-0">
<VTable>
<tbody>
<tr><td>Tx Hash</td><td>{{ tx.txResponse.txhash }}</td></tr>
<tr><td>Height</td><td><RouterLink :to="`/${props.chain}/block/${tx.txResponse.height}`">{{ tx.txResponse.height }}</RouterLink></td></tr>
<tr><td>Tx Hash</td><td>{{ tx.tx_response.txhash }}</td></tr>
<tr><td>Height</td><td><RouterLink :to="`/${props.chain}/block/${tx.tx_response.height}`">{{ tx.tx_response.height }}</RouterLink></td></tr>
<tr><td>Status</td><td>
<VChip v-if="tx.txResponse.code === 0" color="success">Success</VChip>
<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.txResponse.timestamp }} ({{ format.toDay(tx.txResponse.timestamp, "from") }})</td></tr>
<tr><td>Gas</td><td>{{ tx.txResponse.gasUsed }} / {{ tx.txResponse.gasWanted }}</td></tr>
<tr><td>Fee</td><td>{{ format.formatTokens(tx.tx?.authInfo?.fee?.amount, true, '0,0.[00]') }}</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>
@ -39,10 +41,9 @@ const messages = computed(() => {
</VCard>
<VCard title="Messages" class="my-5">
<VCardItem>
<VCardItem style="border-top: 2px dotted gray;">
<div v-for="(msg, i) in messages">
<div><VChip label color="primary">#{{ i+1 }}</VChip>{{ msg.typeUrl }}</div>
<div>{{ toBase64(msg.value) }}</div>
<div><DynamicComponent :value="msg" /></div>
</div>
</VCardItem>
</VCard>
@ -56,7 +57,7 @@ const messages = computed(() => {
</VExpansionPanel>
<VExpansionPanel title="Transaction Response">
<v-expansion-panel-text>
<DynamicComponent :value="tx.txResponse" />
<DynamicComponent :value="tx.tx_response" />
</v-expansion-panel-text>
</VExpansionPanel>
</VExpansionPanels>

View File

@ -5,7 +5,7 @@ async function tt() {
const address = "echelon1uattqtrtv8944qkmh44ll97qjacj6tgrekqzm9"
const validator = "echelonvaloper1uattqtrtv8944qkmh44ll97qjacj6tgr2cupk4"
const client = new CosmosRestClient("https://api.ech.network")
let response = await client.getSlashingSigningInfos();
let response = await client.getBaseBlockLatest();
console.log('response:', response)
}
tt()

View File

@ -1,11 +1,11 @@
import type { RPCClient } from '@/libs/client.rpc'
import type { CosmosRestClient } from '@/libs/client'
import 'pinia'
import type { Ref } from 'vue'
declare module 'pinia' {
export interface PiniaCustomProperties {
// by using a setter we can allow both strings and refs
set rpc(value: RPCClient | Ref<RPCClient>)
get rpc(): RPCClient
set rpc(value: CosmosRestClient | Ref<CosmosRestClient>)
get rpc(): CosmosRestClient
}
}

View File

@ -7,9 +7,9 @@ import type { Coin } from "@/types";
export const useBankStore = defineStore('bankstore', {
state: () => {
return {
supply: {} as Coin[],
supply: {} as Coin,
balances: {} as Record<string, Coin[]>,
totalSupply: {supply: []} ,
totalSupply: {supply: [] as Coin[]} ,
}
},
getters: {
@ -26,7 +26,7 @@ export const useBankStore = defineStore('bankstore', {
this.supply = {} as Coin
const denom = this.staking.params.bondDenom || this.blockchain.current?.assets[0].base
if(denom) {
this.blockchain.rpc.supplyOf(denom).then(res => {
this.blockchain.rpc.getBankSupplyByDenom(denom).then(res => {
if(res.amount) this.supply = res.amount
})
}
@ -38,7 +38,7 @@ export const useBankStore = defineStore('bankstore', {
// return response
// },
async fetchSupply(denom: string) {
return this.blockchain.rpc.supplyOf( denom )
return this.blockchain.rpc.getBankSupplyByDenom( denom )
}
}
})

View File

@ -1,15 +1,14 @@
import { defineStore } from "pinia";
import { useBlockchain } from "@/stores";
import dayjs from "dayjs";
import type { BlockResponse } from "@cosmjs/tendermint-rpc";
import type { Block } from "@/types";
export const useBaseStore = defineStore('baseStore', {
state: () => {
return {
earlest: {} as BlockResponse,
latest: {} as BlockResponse,
recents: [] as BlockResponse[]
earlest: {} as Block,
latest: {} as Block,
recents: [] as Block[]
}
},
getters: {
@ -34,8 +33,8 @@ export const useBaseStore = defineStore('baseStore', {
this.recents = []
},
async fetchLatest() {
this.latest = await this.blockchain.rpc.block()
if(!this.earlest || this.earlest.block?.header?.chainId != this.latest.block?.header?.chainId) {
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 = []
@ -48,16 +47,16 @@ export const useBaseStore = defineStore('baseStore', {
},
async fetchValidatorByHeight(height?: number, offset = 0) {
return this.blockchain.rpc.validatorsAtHeight(height)
return this.blockchain.rpc.getBaseValidatorsetAt(String(height))
},
async fetchLatestValidators(offset = 0) {
return this.blockchain.rpc.validatorsAtHeight()
return this.blockchain.rpc.getBaseValidatorsetLatest()
},
async fetchBlock(height?: number) {
return this.blockchain.rpc.block(height)
return this.blockchain.rpc.getBaseBlockAt(String(height))
},
async fetchAbciInfo() {
return this.blockchain.rpc.abciInfo()
return this.blockchain.rpc.getBaseNodeInfo()
}
// async fetchNodeInfo() {
// return this.blockchain.rpc.no()

View File

@ -2,12 +2,8 @@ import { defineStore } from "pinia";
import { useDashboard, type ChainConfig, type Endpoint, EndpointType } from "./useDashboard";
import type { VerticalNavItems } from '@/@layouts/types'
import { useRouter } from "vue-router";
import { useStakingStore } from "./useStakingStore";
import { useBankStore } from "./useBankStore";
import { useBaseStore } from "./useBaseStore";
import { useGovStore } from "./useGovStore";
import { ref } from "vue";
import { useMintStore } from "./useMintStore";
import { CosmosRestClient } from "@/libs/client";
import { useBankStore, useBaseStore, useGovStore, useMintStore, useStakingStore } from ".";
import { useBlockModule } from "@/modules/[chain]/block/block";
export const useBlockchain = defineStore("blockchain", {
@ -95,16 +91,16 @@ export const useBlockchain = defineStore("blockchain", {
actions: {
async initial() {
await this.randomSetupEndpoint()
// await useStakingStore().init()
// useBankStore().initial()
// useBaseStore().initial()
// useGovStore().initial()
// useMintStore().initial()
// useBlockModule().initial()
await useStakingStore().init()
useBankStore().initial()
useBaseStore().initial()
useGovStore().initial()
useMintStore().initial()
useBlockModule().initial()
},
async randomSetupEndpoint() {
const all = this.current?.endpoints?.rpc
const all = this.current?.endpoints?.rest
if(all) {
const rn = Math.random()
const endpoint = all[Math.floor(rn * all.length)]
@ -115,7 +111,7 @@ export const useBlockchain = defineStore("blockchain", {
async setRestEndpoint(endpoint: Endpoint) {
this.connErr = ''
this.endpoint = endpoint
// this.rpc = new RPCClient(endpoint.address)
this.rpc = new CosmosRestClient(endpoint.address)
// console.log(this.rpc.endpoint)
},
setCurrent(name: string) {

View File

@ -13,7 +13,7 @@ export const useDistributionStore = defineStore('distributionStore', {
},
actions: {
async fetchCommunityPool() {
return this.blockchain.rpc.communityPool()
return this.blockchain.rpc.getDistributionCommunityPool()
}
}
})

View File

@ -8,7 +8,7 @@ import updateLocale from 'dayjs/plugin/updateLocale'
import utc from 'dayjs/plugin/utc'
import localeData from 'dayjs/plugin/localeData'
import { useStakingStore } from "./useStakingStore";
import { toHex } from "@cosmjs/encoding";
import { fromBase64, toHex } from "@cosmjs/encoding";
import { consensusPubkeyToHexAddress } from "@/libs";
dayjs.extend(localeData)
@ -90,9 +90,9 @@ export const useFormatter = defineStore('formatter', {
}
return '-'
},
validator(address: Uint8Array) {
const txt = toHex(address).toUpperCase()
const validator = this.staking.validators.find(x => consensusPubkeyToHexAddress(x.consensusPubkey) === txt)
validator(address: string) {
const txt = toHex(fromBase64(address)).toUpperCase()
const validator = this.staking.validators.find(x => consensusPubkeyToHexAddress(x.consensus_pubkey) === txt)
return validator?.description?.moniker
},
calculatePercent(input?: string, total?: string|number ) {
@ -103,10 +103,8 @@ export const useFormatter = defineStore('formatter', {
formatDecimalToPercent(decimal: string) {
return numeral(decimal).format('0.[00]%')
},
formatCommissionRate(v?: string) {
console.log(v)
if(!v) return '-'
const rate = Number(v) / Number("1000000000000000000")
formatCommissionRate(rate?: string) {
if(!rate) return '-'
return this.percent(rate)
},
percent(decimal?: string|number) {
@ -134,10 +132,10 @@ export const useFormatter = defineStore('formatter', {
}
return dayjs(time).format('YYYY-MM-DD HH:mm:ss')
},
messages(msgs: {typeUrl: string}[]) {
messages(msgs: {"@type": string}[]) {
if(msgs) {
const sum: Record<string, number> = msgs.map(msg => {
return msg.typeUrl.substring(msg.typeUrl.lastIndexOf('.') + 1).replace('Msg', '')
return msg["@type"].substring(msg["@type"].lastIndexOf('.') + 1).replace('Msg', '')
}).reduce((s, c) => {
const sh: Record<string, number> = s
if (sh[c]) {

View File

@ -1,5 +1,6 @@
import { defineStore } from "pinia";
import { useBlockchain } from "./useBlockchain";
import type { PageRequest } from "@/types";
export const useGovStore = defineStore('govStore', {
state: () => {
@ -20,24 +21,17 @@ export const useGovStore = defineStore('govStore', {
initial() {
this.fetchParams()
},
async fetchProposals( proposalStatus: ProposalStatus, pagination?: PageRequest ) {
const param = {
proposalStatus,
voter: '',
depositor: '',
pagination,
}
const proposals = await this.blockchain.rpc.proposals(proposalStatus, '', '')
console.log(proposals)
async fetchProposals( status: string, pagination?: PageRequest ) {
const proposals = await this.blockchain.rpc.getGovProposals(status)
return proposals
},
async fetchParams() {
// this.blockchain.rpc.govParam().then(x => {
// this.blockchain.rpc.getGovParamsDeposit().then(x => {
// this.params.deposit = x.deposit
// })
},
async fetchTally(proposalId: number) {
return this.blockchain.rpc.tally(proposalId)
async fetchTally(proposalId: string) {
return this.blockchain.rpc.getGovProposalTally(proposalId)
}
}
})

View File

@ -17,7 +17,7 @@ export const useMintStore = defineStore('mintStore', {
this.fetchInflation()
},
async fetchInflation() {
this.blockchain.rpc.inflation().then(x => {
this.blockchain.rpc.getMintInflation().then(x => {
this.inflation = x.inflation
}).catch(() => {
this.inflation = "0"

View File

@ -2,18 +2,30 @@ import { defineStore } from "pinia";
import { useBlockchain } from "./useBlockchain";
import { get } from "@/libs/http";
import type { StakingParam, StakingPool, Validator } from "@/types";
export const useStakingStore = defineStore('stakingStore', {
state: () => {
return {
validators: [] as Validator[],
params: {} as QueryParamsResponse,
pool: {} as Pool | undefined,
params: {} as {
"unbonding_time": string,
"max_validators": number,
"max_entries": number,
"historical_entries": number,
"bond_denom": string,
"min_commission_rate": string,
"min_self_delegation": string
},
pool: {} as {
bonded_tokens: string,
not_bonded_tokens: string,
},
}
},
getters: {
totalPower(): number {
const sum = (s:number, e: Validator) => { return s + parseInt(e.delegatorShares) }
const sum = (s:number, e: Validator) => { return s + parseInt(e.delegator_shares) }
return this.validators ? this.validators.reduce(sum, 0): 0
},
blockchain() {
@ -31,12 +43,13 @@ export const useStakingStore = defineStore('stakingStore', {
return get(`https://keybase.io/_/api/1.0/user/lookup.json?key_suffix=${identity}&fields=pictures`)
},
async fetchParams() {
const response = await this.blockchain.rpc.stakingParams()
const response = await this.blockchain.rpc.getStakingParams()
if(response.params) this.params = response.params
return this.params
},
async fetchPool() {
const response = await this.blockchain.rpc.stakingPool()
const response = await this.blockchain.rpc.getStakingPool()
response.pool.bonded_tokens
this.pool = response.pool
},
async fetchAcitveValdiators() {
@ -46,14 +59,14 @@ export const useStakingStore = defineStore('stakingStore', {
return this.fetchValidators('BOND_STATUS_UNBONDED')
},
async fetchValidator(validatorAddr: string) {
return this.blockchain.rpc.validator(validatorAddr)
return this.blockchain.rpc.getStakingValidator(validatorAddr)
},
async fetchValidatorDelegation(validatorAddr: string, delegatorAddr: string) {
return (await this.blockchain.rpc.validatorDelegation(validatorAddr, delegatorAddr)).delegationResponse
return await this.blockchain.rpc.getStakingValidatorsDelegationsDelegator(validatorAddr, delegatorAddr)
},
async fetchValidators(status: string) {
return this.blockchain.rpc.validators(status, undefined).then(res => {
const vals = res.validators.sort((a, b) => (Number(b.delegatorShares) - Number(a.delegatorShares)))
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
}

View File

@ -1,4 +1,5 @@
import type { Key } from "./common"
import type { Tx } from "./tx"
export interface NodeInfo {
"default_node_info": {
@ -35,9 +36,57 @@ export interface NodeInfo {
"cosmos_sdk_version": string,
}
}
export interface BlockId {
"hash": string,
"part_set_header": {
"total": number,
"hash": string
}
}
export interface Signature
{
"block_id_flag": string,
"validator_address": string,
"timestamp": string,
"signature": string,
}
export interface Block {
"block_id": BlockId,
"block": {
"header": {
"version": {
"block": string,
"app": string
},
"chain_id": string,
"height": string,
"time": string,
"last_block_id": BlockId,
"last_commit_hash": string,
"data_hash": string,
"validators_hash": string,
"next_validators_hash": string,
"consensus_hash": string,
"app_hash": string,
"last_results_hash": string,
"evidence_hash": string,
"proposer_address": string,
},
"data": {
"txs": any[]
},
"evidence": {
"evidence": any[]
},
"last_commit": {
"height": string,
"round": number,
"block_id": BlockId,
"signatures": Signature[]
}
}
}
export interface TendermintValidator {

View File

@ -8,6 +8,10 @@ export interface Pagination {
total?: string;
}
export class PageRequest {
limit?: number;
}
export interface PaginatedResponse {
pagination: Pagination;
}
@ -17,6 +21,6 @@ export class Response<T> {
}
export interface Coin {
amount: string|number;
amount: string;
denom: string;
}

View File

@ -44,12 +44,10 @@ export interface GovProposal {
}
export interface Tally {
tally: {
yes: string,
abstain: string,
no: string,
no_with_veto: string
}
yes: string,
abstain: string,
no: string,
no_with_veto: string
}
export interface GovVote {

View File

@ -5,4 +5,5 @@ export * from './bank'
export * from './common'
export * from './distribution'
export * from './gov'
export * from './staking'
export * from './staking'
export * from './tx'

View File

@ -16,17 +16,19 @@ export interface Validator {
},
"unbonding_height": string,
"unbonding_time": string,
"commission": {
"commission_rates": {
"rate": string,
"max_rate": string,
"max_change_rate": string
},
"update_time": string
},
"commission": CommissionRate,
"min_self_delegation": string
}
export interface CommissionRate {
"commission_rates": {
"rate": string,
"max_rate": string,
"max_change_rate": string
},
"update_time": string
}
export interface Delegation {
delegation: {
delegator_address: string,