add account details

This commit is contained in:
liangping 2023-04-20 18:44:25 +08:00
parent d6d56ba7c0
commit fc8aab6ce0
8 changed files with 246 additions and 11 deletions

View File

@ -1,7 +1,7 @@
{
"chain_name": "osmosis",
"coingecko": "osmosis",
"api": ["https://api-osmosis-ia.cosmosia.notional.ventures", "https://osmosis-api.polkachu.com", "https://osmo.api.ping.pub", "https://lcd-osmosis.blockapsis.com"],
"api": ["https://api-osmosis-ia.cosmosia.notional.ventures", "https://osmosis-api.polkachu.com", "https://lcd-osmosis.blockapsis.com"],
"rpc": ["https://rpc-osmosis-ia.cosmosia.notional.ventures:443", "https://osmosis-rpc.polkachu.com:443", "https://osmosis.validator.network:443", "https://rpc-osmosis.blockapsis.com:443"],
"snapshot_provider": "",
"sdk_version": "0.46.1",

View File

@ -10,10 +10,11 @@ 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_community_pool: { url: "/cosmos/distribution/v1beta1/community_pool", adapter },
distribution_validator_commission: { url: "/cosmos/distribution/v1beta1/validators/{validator_address}/commission", adapter },
distribution_validator_outstanding_rewards: { url: "/cosmos/distribution/v1beta1/validators/{validator_address}/outstanding_rewards", adapter },
distribution_validator_slashes: { url: "/cosmos/distribution/v1beta1/validators/{validator_address}/slashes", adapter },
distribution_delegator_rewards: { url: "/cosmos/distribution/v1beta1/delegators/{delegator_addr}/rewards", adapter },
slashing_params: { url: "/cosmos/slashing/v1beta1/params", adapter },
slashing_signing_info: { url: "/cosmos/slashing/v1beta1/signing_infos", adapter },
gov_params_voting: { url: "/cosmos/gov/v1beta1/params/voting", adapter },

View File

@ -44,7 +44,10 @@ export class CosmosRestClient {
return this.request(this.registry.distribution_params, {})
}
async getDistributionCommunityPool() {
return this.request(this.registry.distributino_community_pool, {})
return this.request(this.registry.distribution_community_pool, {})
}
async getDistributionDelegatorRewards(delegator_addr: string) {
return this.request(this.registry.distribution_delegator_rewards, {delegator_addr})
}
async getDistributionValidatorCommission(validator_address: string) {
return this.request(this.registry.distribution_validator_commission, {validator_address})

View File

@ -29,7 +29,8 @@ 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[]}>;
distribution_community_pool: Request<{pool: Coin[]}>;
distribution_delegator_rewards: Request<any>;
mint_inflation: Request<{inflation: string}>;
mint_params: Request<{

View File

@ -0,0 +1,216 @@
<script lang="ts" setup>
import { useBlockchain, useFormatter } from '@/stores';
import DynamicComponent from '@/components/dynamic/DynamicComponent.vue';
import { computed, ref } from '@vue/reactivity';
import 'vue-json-pretty/lib/styles.css';
import type { AuthAccount, Delegation, TxResponse, DelegatorRewards } from '@/types';
import type { Coin } from '@cosmjs/amino';
const props = defineProps(['address', 'chain'])
const blockchain = useBlockchain()
const format = useFormatter()
const account = ref({} as AuthAccount)
const txs = ref({} as TxResponse[])
const delegations = ref([] as Delegation[])
const rewards = ref({} as DelegatorRewards)
const balances = ref([] as Coin[])
const totalAmount = computed(()=> {
let total = 0;
delegations.value?.forEach(x => {
total += Number(x.balance.amount)
})
rewards.value?.total?.forEach(x => {
total += Number(x.amount)
})
balances.value?.forEach(x => {
total += Number(x.amount)
})
return total
})
function loadAccount(address: string) {
blockchain.rpc.getAuthAccount(address).then(x => {
account.value = x.account
})
blockchain.rpc.getTxsBySender(address).then(x => {
txs.value = x.tx_responses
})
blockchain.rpc.getDistributionDelegatorRewards(address).then(x => {
rewards.value = x
})
blockchain.rpc.getStakingDelegations(address).then(x => {
delegations.value = x.delegation_responses
})
blockchain.rpc.getBankBalances(address).then(x => {
balances.value = x.balances
})
}
loadAccount(props.address)
</script>
<template>
<div v-if="account">
<VCard>
<VList>
<VListItem>
<template #prepend>
<VAvatar
rounded
variant="tonal"
size="45"
color="primary"
>
<VIcon icon="mdi-qrcode" />
</VAvatar>
</template>
<VListItemTitle class="text-sm font-weight-semibold">
Address:
</VListItemTitle>
<VListItemSubtitle class="text-xs">
{{ address }}
</VListItemSubtitle>
</VListItem>
</VList>
</VCard>
<VCard class="mt-5">
<VCardTitle>Assets</VCardTitle>
<VCardItem>
<VRow>
<VCol cols="12" md="4">
xx
</VCol>
<VCol cols="12" md="8">
<VList class="card-list">
<VListItem v-for="v in balances">
<template #prepend>
<VAvatar
rounded
variant="tonal"
size="45"
color="success"
>
<VIcon icon="mdi-card" />
</VAvatar>
</template>
<VListItemTitle class="text-sm font-weight-semibold">
{{ format.formatToken(v) }}
</VListItemTitle>
<VListItemSubtitle class="text-xs">
${{ 0 }}
</VListItemSubtitle>
<template #append>
<VChip color="primary">{{ format.calculatePercent(v.amount, totalAmount) }}</VChip>
</template>
</VListItem>
<VListItem v-for="v in delegations">
<template #prepend>
<VAvatar
rounded
variant="tonal"
size="45"
color="info"
>
<VIcon icon="mdi-lock" />
</VAvatar>
</template>
<VListItemTitle class="text-sm font-weight-semibold">
{{ format.formatToken(v.balance) }}
</VListItemTitle>
<VListItemSubtitle class="text-xs">
${{ 0 }}
</VListItemSubtitle>
<template #append>
<VChip color="primary">{{ format.calculatePercent(v.balance.amount, totalAmount) }}</VChip>
</template>
</VListItem>
<VListItem v-for="v in rewards.total">
<template #prepend>
<VAvatar
rounded
variant="tonal"
size="45"
color="warning"
>
<VIcon icon="mdi-up" />
</VAvatar>
</template>
<VListItemTitle class="text-sm font-weight-semibold">
{{ format.formatToken(v) }}
</VListItemTitle>
<VListItemSubtitle class="text-xs">
${{ 0 }}
</VListItemSubtitle>
<template #append>
<VChip color="primary">{{ format.calculatePercent(v.amount, totalAmount) }}</VChip>
</template>
</VListItem>
</VList>
<VDivider class="my-2"></VDivider>
{{ totalAmount }}
</VCol>
</VRow>
</VCardItem>
</VCard>
<VCard class="my-5">
<VCardItem>
<VCardTitle>Delegations</VCardTitle>
<VTable>
<thead>
<tr><th>Validator</th><th>Delegation</th><th>Rewards</th><th>Action</th></tr>
</thead>
<tbody>
<tr v-for="v in delegations">
<td>{{ format.validatorFromBech32(v.delegation.validator_address) }} </td>
<td>{{ format.formatToken(v.balance, true, "0,0.[00]") }} </td>
<td>{{ format.formatTokens(rewards?.rewards?.find(x => x.validator_address ===v.delegation.validator_address)?.reward) }} </td>
<td>
action
</td>
</tr>
</tbody>
</VTable>
</VCardItem>
</VCard>
<VCard class="my-5">
<VCardItem>
<VCardTitle>Transactions</VCardTitle>
<VTable>
<thead>
<tr><th>Height</th><th>Hash</th><th>Messages</th><th>Time</th></tr>
</thead>
<tbody>
<tr v-for="v in txs">
<td>{{ v.height }} </td>
<td class="text-truncate" style="max-width: 200px;">{{ v.txhash }} </td>
<td>
{{ format.messages(v.tx.body.messages) }}
<VIcon v-if="v.code === 0" icon="mdi-check" color="success"></VIcon>
<VIcon v-else icon="mdi-multiply" color="error"></VIcon> </td>
<td>{{ format.toDay(v.timestamp, "from") }}</td>
</tr>
</tbody>
</VTable>
</VCardItem>
</VCard>
<VCard>
<VCardItem>
<VCardTitle>Account</VCardTitle>
<DynamicComponent :value="account"/>
</VCardItem>
</VCard>
</div>
<div v-else>
Account does not exists on chain
</div>
</template>
<style lang="scss" scoped>
.card-list {
--v-card-list-gap: 5px;
}
</style>

View File

@ -225,7 +225,7 @@ onMounted(()=> {
<VList class="pt-0">
<VListItem>
<VListItemTitle>Account</VListItemTitle>
<VListItemSubtitle class="text-caption">{{ addresses.account }}</VListItemSubtitle>
<VListItemSubtitle class="text-caption"><RouterLink :to="`/${chain}/account/${addresses.account}`">{{ addresses.account }}</RouterLink></VListItemSubtitle>
</VListItem>
<VListItem>
<VListItemTitle>Operator Address</VListItemTitle>

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 { fromBase64, toHex } from "@cosmjs/encoding";
import { fromBase64, fromBech32, toHex } from "@cosmjs/encoding";
import { consensusPubkeyToHexAddress } from "@/libs";
import { useBankStore } from "./useBankStore";
import type { DenomTrace } from "@/types";
@ -75,7 +75,6 @@ export const useFormatter = defineStore('formatter', {
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
@ -96,7 +95,7 @@ export const useFormatter = defineStore('formatter', {
denom = unit.denom.toUpperCase()
}
}
return `${numeral(amount).format(fmt)} ${withDenom ? denom: ''}`
return `${numeral(amount).format(fmt)} ${withDenom ? denom.substring(0, 10): ''}`
}
return '-'
},
@ -109,20 +108,27 @@ export const useFormatter = defineStore('formatter', {
const b = Number(pool.bonded_tokens)
const nb = Number(pool.not_bonded_tokens)
const p = b/(b+nb)
console.log(b, nb, p, pool)
return numeral(p).format('0.[00]%')
}
return '-'
},
validator(address: string) {
if(!address) return address
const txt = toHex(fromBase64(address)).toUpperCase()
const validator = this.staking.validators.find(x => consensusPubkeyToHexAddress(x.consensus_pubkey) === txt)
return validator?.description?.moniker
},
validatorFromBech32(address: string) {
if(!address) return address
const validator = this.staking.validators.find(x => x.operator_address === address)
return validator?.description?.moniker
},
calculatePercent(input?: string, total?: string|number ) {
if(!input || !total) return '0'
const percent = Number(input)/Number(total)
return numeral(percent).format("0.[00]%")
console.log(input, total, percent);
return numeral(percent>0.0001?percent: 0).format("0.[00]%")
},
formatDecimalToPercent(decimal: string) {
return numeral(decimal).format('0.[00]%')

View File

@ -1,4 +1,4 @@
import type { PaginatedResponse } from "./common"
import type { Coin, PaginatedResponse } from "./common"
export interface DistributionParams {
params: {
@ -9,6 +9,14 @@ export interface DistributionParams {
}
}
export interface DelegatorRewards {
rewards: {
validator_address: string,
reward: Coin[],
}[],
total: Coin[],
}
export interface PaginatedSlashes extends PaginatedResponse {
slashes: any[]
}