finished staking list

This commit is contained in:
liangping 2021-08-01 07:13:47 +08:00
parent df6a20ee67
commit 18e0d933b0
7 changed files with 175 additions and 43 deletions

View File

@ -5,6 +5,7 @@ export { default as Proposer } from './proposer'
export { default as Votes } from './votes' export { default as Votes } from './votes'
export { default as Deposit } from './deposit' export { default as Deposit } from './deposit'
export { default as Validator } from './validator' export { default as Validator } from './validator'
export { default as StakingParameters } from './staking-parameters'
export * from './data' export * from './data'
export default class Test {} export default class Test {}

View File

@ -0,0 +1,24 @@
export default class StakingParameters {
constructor() {
this.max_entries = 0
this.historical_entries = 0
this.unbonding_time = ''
this.max_validators = 0
this.bond_denom = ''
}
init(element) {
if (element != null) {
this.max_entries = Number(element.max_entries)
this.historical_entries = Number(element.historical_entries)
this.unbonding_time = element.unbonding_time
this.max_validators = Number(element.max_validators)
this.bond_denom = element.bond_denom
}
return this
}
debug() {
return console.log(this)
}
}

View File

@ -1,8 +1,8 @@
export default class ValidatorDescription { export default class ValidatorDescription {
constructor() { constructor() {
this.moniker = 'string' this.moniker = 'Ping'
this.identity = 'string' this.identity = 'string'
this.website = 'string' this.website = 'https://ping.pub'
this.security_contact = 'string' this.security_contact = 'string'
this.details = 'string' this.details = 'string'
} }

View File

@ -7,7 +7,7 @@ export default class Validator {
this.consensus_pubkey = 'cosmosvalconspub1zcjduepq0vu2zgkgk49efa0nqwzndanq5m4c7pa3u4apz4g2r9gspqg6g9cs3k9cuf' this.consensus_pubkey = 'cosmosvalconspub1zcjduepq0vu2zgkgk49efa0nqwzndanq5m4c7pa3u4apz4g2r9gspqg6g9cs3k9cuf'
this.jailed = true this.jailed = true
this.status = 0 this.status = 0
this.tokens = '-' this.tokens = 0
this.delegator_shares = 0 this.delegator_shares = 0
this.description = new ValidatorDescription() this.description = new ValidatorDescription()
this.bond_height = 0 this.bond_height = 0
@ -22,10 +22,10 @@ export default class Validator {
this.consensus_pubkey = element.consensus_pubkey this.consensus_pubkey = element.consensus_pubkey
this.jailed = element.jailed this.jailed = element.jailed
this.status = element.status this.status = element.status
this.tokens = element.tokens this.tokens = Number(element.tokens)
this.delegator_shares = element.delegator_shares this.delegator_shares = element.delegator_shares
this.description = new ValidatorDescription().init(element.description) this.description = new ValidatorDescription().init(element.description)
this.bond_height = element.bond_height this.bond_height = Number(element.bond_height)
this.bond_intra_tx_counter = element.bond_intra_tx_counter this.bond_intra_tx_counter = element.bond_intra_tx_counter
this.unbonding_height = element.unbonding_height this.unbonding_height = element.unbonding_height
this.unbonding_time = element.unbonding_time this.unbonding_time = element.unbonding_time

View File

@ -2,7 +2,7 @@ import fetch from 'node-fetch'
import store from '@/store' import store from '@/store'
import { import {
Proposal, ProposalTally, Proposer, StakingPool, Votes, Deposit, Proposal, ProposalTally, Proposer, StakingPool, Votes, Deposit,
Validator, Validator, StakingParameters,
} from './data' } from './data'
function commonProcess(res) { function commonProcess(res) {
@ -25,6 +25,14 @@ const chainAPI = class ChainFetch {
return this.get('/staking/pool').then(data => new StakingPool().init(commonProcess(data))) return this.get('/staking/pool').then(data => new StakingPool().init(commonProcess(data)))
} }
async getMintingInflation() {
return this.get('/minting/inflation').then(data => Number(commonProcess(data)))
}
async getStakingParameters() {
return this.get('/staking/parameters').then(data => new StakingParameters().init(commonProcess(data)))
}
async getValidatorList() { async getValidatorList() {
return this.get('/staking/validators').then(data => commonProcess(data).map(i => new Validator().init(i))) return this.get('/staking/validators').then(data => commonProcess(data).map(i => new Validator().init(i)))
} }

View File

@ -11,9 +11,11 @@ export default {
state: { state: {
config: chains, config: chains,
selected: {}, selected: {},
avatars: {},
}, },
getters: { getters: {
getchains: state => state.chains, getchains: state => state.chains,
getAvatarById: state => id => state.avatars[id],
}, },
mutations: { mutations: {
setup_sdk_version(state, info) { setup_sdk_version(state, info) {
@ -22,6 +24,9 @@ export default {
select(state, args) { select(state, args) {
state.chains.selected = state.chains.config[args.chain_name] state.chains.selected = state.chains.config[args.chain_name]
}, },
cacheAvatar(state, args) {
state.chains.avatars[args.identity] = args.url
},
}, },
actions: {}, actions: {},

View File

@ -1,76 +1,115 @@
<template> <template>
<div> <div>
<b-card-code <b-card
no-body no-body
title="My Delegations"
> >
<b-card-header>
<b-card-title>
Validators (Max:{{ stakingParameters.max_validators }})
<small class="text-muted">
<b-badge variant="danger">
&nbsp;
</b-badge>
Top 33%
<b-badge variant="warning">
&nbsp;
</b-badge>
Top 67% of Voting Power
</small>
</b-card-title>
</b-card-header>
<b-table <b-table
responsive="sm"
:items="delegations"
:fields="validator_fields"
/>
</b-card-code>
<b-card-code
no-body
title="Validators"
>
<b-table
responsive="sm"
striped
:items="validators" :items="validators"
:fields="validator_fields" :fields="validator_fields"
:sort-desc="true" :sort-desc="true"
sort-by="tokens" sort-by="tokens"
striped
hover
responsive="sm"
> >
<!-- A virtual column -->
<template #cell(index)="data">
<b-badge
:variant="rankBadge(data)"
>
{{ data.index + 1 }}
</b-badge>
</template>
<!-- Column: Validator --> <!-- Column: Validator -->
<template #cell(description)="data"> <template #cell(description)="data">
<b-media vertical-align="center"> <b-media vertical-align="center">
<template #aside> <template #aside>
<b-avatar <b-avatar
v-if="data.item.avatar"
v-b-tooltip.hover.v-primary
v-b-tooltip.hover.right="data.item.description.details"
size="32" size="32"
icon="ChevronRightIcon"
variant="light-primary" variant="light-primary"
:src="data.item.avatar" :src="data.item.avatar"
/> />
<b-avatar
v-if="!data.item.avatar"
v-b-tooltip.hover.v-primary
v-b-tooltip.hover.right="data.item.description.details"
>
<feather-icon icon="ServerIcon" />
</b-avatar>
</template> </template>
<span class="font-weight-bold d-block text-nowrap"> <span class="font-weight-bolder d-block text-nowrap">
{{ data.item.description.moniker }} {{ data.item.description.moniker }}
</span> </span>
<small class="text-muted">{{ data.item.description.website || data.item.description.identity }}</small> <small class="text-muted">{{ data.item.description.website || data.item.description.identity }}</small>
</b-media> </b-media>
</template> </template>
<!-- Token -->
<template #cell(tokens)="data">
<div class="d-flex flex-column">
<span class="font-weight-bold mb-0">{{ tokenFormatter(data.item.tokens, stakingParameters.bond_denom) }}</span>
<span class="font-small-2 text-muted text-nowrap">{{ percent(data.item.tokens/stakingPool.bondedToken) }}%</span>
</div>
</template>
</b-table> </b-table>
</b-card-code> </b-card>
</div> </div>
</template> </template>
<script> <script>
import { BTable, BMedia, BAvatar } from 'bootstrap-vue' import {
import BCardCode from '@core/components/b-card-code/BCardCode.vue' BTable, BMedia, BAvatar, BBadge, BCard, BCardHeader, BCardTitle, VBTooltip,
import { Validator, percent } from '@/libs/data' } from 'bootstrap-vue'
import {
Validator, percent, StakingParameters, formatToken,
} from '@/libs/data'
import { keybase } from '@/libs/fetch' import { keybase } from '@/libs/fetch'
// import fetch from 'node-fetch'
export default { export default {
components: { components: {
BCardCode, BCard,
BTable, BTable,
BMedia, BMedia,
BAvatar, BAvatar,
BBadge,
BCardHeader,
BCardTitle,
},
directives: {
'b-tooltip': VBTooltip,
}, },
data() { data() {
return { return {
mintInflation: 0,
sortBy: 'tokens', stakingPool: {},
sortDesc: true, stakingParameters: new StakingParameters(),
validators: [new Validator()], validators: [new Validator()],
delegations: [new Validator()], delegations: [new Validator()],
validator_fields: [ validator_fields: [
{ key: 'index', label: '#' },
{ key: 'description', label: 'Validator', sortable: true }, { key: 'description', label: 'Validator', sortable: true },
{ {
key: 'tokens', key: 'tokens',
label: 'Voting Power',
sortable: true, sortable: true,
formatter: value => parseInt(value / 100000, 0),
tdClass: 'text-right', tdClass: 'text-right',
thClass: 'text-right', thClass: 'text-right',
sortByFormatted: true, sortByFormatted: true,
@ -82,25 +121,80 @@ export default {
tdClass: 'text-right', tdClass: 'text-right',
thClass: 'text-right', thClass: 'text-right',
}, },
{ key: 'delegator_shares', sortable: true }, {
key: 'apr',
formatter: (value, i, data) => this.apr(value, i, data),
tdClass: 'text-right',
thClass: 'text-right',
},
{ key: 'operation' },
], ],
} }
}, },
created() { created() {
this.$http.getStakingPool().then(res => {
this.stakingPool = res
})
this.$http.getMintingInflation().then(res => {
this.mintInflation = res
})
this.$http.getStakingParameters().then(res => {
this.stakingParameters = res
})
this.$http.getValidatorList().then(res => { this.$http.getValidatorList().then(res => {
this.validators = res this.validators = res
this.validators.forEach(i => { let promise = Promise.resolve()
if (i.description.identity) { res.forEach((item, index) => {
keybase(i.description.identity).then(d => { promise = promise.then(() => new Promise(resolve => {
if (Array.isArray(d.them) && d.them.length > 0) { this.avatar(item.description.identity, index, resolve)
console.log(d.them[0].pictures.primary.url) }))
const validator = this.validators.find(u => u.description.identity === i.description.identity)
validator.avatar = d.them[0].pictures.primary.url
}
})
}
}) })
}) })
}, },
methods: {
percent,
tokenFormatter(amount, denom) {
return formatToken({ amount, denom })
},
apr(value, i, data) {
return `${percent((1 - data.commission.rate) * this.mintInflation)} %`
},
rankBadge(data) {
const { index, item } = data
if (index === 0) {
window.sum = item.tokens
} else {
window.sum += item.tokens
}
const rank = window.sum / this.stakingPool.bondedToken
if (rank < 0.333) {
return 'danger'
}
if (rank < 0.67) {
return 'warning'
}
return 'primary'
},
avatar(identity, index, resolve) {
const url = this.$store.getters['chains/getAvatarById'](identity)
if (url !== undefined) {
resolve()
const validator = this.validators.find(u => u.description.identity === identity)
this.$set(validator, 'avatar', url)
} else if (identity) {
keybase(identity).then(d => {
resolve()
if (Array.isArray(d.them) && d.them.length > 0) {
const validator = this.validators.find(u => u.description.identity === identity)
this.$set(validator, 'avatar', d.them[0].pictures.primary.url)
this.$store.commit('cacheAvatar', { identity, url: d.them[0].pictures.primary.url })
}
})
} else {
resolve()
}
},
},
} }
</script> </script>