forked from cerc-io/cosmos-explorer
finished staking list
This commit is contained in:
parent
df6a20ee67
commit
18e0d933b0
@ -5,6 +5,7 @@ export { default as Proposer } from './proposer'
|
||||
export { default as Votes } from './votes'
|
||||
export { default as Deposit } from './deposit'
|
||||
export { default as Validator } from './validator'
|
||||
export { default as StakingParameters } from './staking-parameters'
|
||||
export * from './data'
|
||||
|
||||
export default class Test {}
|
||||
|
24
src/libs/data/staking-parameters.js
Normal file
24
src/libs/data/staking-parameters.js
Normal 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)
|
||||
}
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
export default class ValidatorDescription {
|
||||
constructor() {
|
||||
this.moniker = 'string'
|
||||
this.moniker = 'Ping'
|
||||
this.identity = 'string'
|
||||
this.website = 'string'
|
||||
this.website = 'https://ping.pub'
|
||||
this.security_contact = 'string'
|
||||
this.details = 'string'
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ export default class Validator {
|
||||
this.consensus_pubkey = 'cosmosvalconspub1zcjduepq0vu2zgkgk49efa0nqwzndanq5m4c7pa3u4apz4g2r9gspqg6g9cs3k9cuf'
|
||||
this.jailed = true
|
||||
this.status = 0
|
||||
this.tokens = '-'
|
||||
this.tokens = 0
|
||||
this.delegator_shares = 0
|
||||
this.description = new ValidatorDescription()
|
||||
this.bond_height = 0
|
||||
@ -22,10 +22,10 @@ export default class Validator {
|
||||
this.consensus_pubkey = element.consensus_pubkey
|
||||
this.jailed = element.jailed
|
||||
this.status = element.status
|
||||
this.tokens = element.tokens
|
||||
this.tokens = Number(element.tokens)
|
||||
this.delegator_shares = element.delegator_shares
|
||||
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.unbonding_height = element.unbonding_height
|
||||
this.unbonding_time = element.unbonding_time
|
||||
|
@ -2,7 +2,7 @@ import fetch from 'node-fetch'
|
||||
import store from '@/store'
|
||||
import {
|
||||
Proposal, ProposalTally, Proposer, StakingPool, Votes, Deposit,
|
||||
Validator,
|
||||
Validator, StakingParameters,
|
||||
} from './data'
|
||||
|
||||
function commonProcess(res) {
|
||||
@ -25,6 +25,14 @@ const chainAPI = class ChainFetch {
|
||||
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() {
|
||||
return this.get('/staking/validators').then(data => commonProcess(data).map(i => new Validator().init(i)))
|
||||
}
|
||||
|
@ -11,9 +11,11 @@ export default {
|
||||
state: {
|
||||
config: chains,
|
||||
selected: {},
|
||||
avatars: {},
|
||||
},
|
||||
getters: {
|
||||
getchains: state => state.chains,
|
||||
getAvatarById: state => id => state.avatars[id],
|
||||
},
|
||||
mutations: {
|
||||
setup_sdk_version(state, info) {
|
||||
@ -22,6 +24,9 @@ export default {
|
||||
select(state, args) {
|
||||
state.chains.selected = state.chains.config[args.chain_name]
|
||||
},
|
||||
cacheAvatar(state, args) {
|
||||
state.chains.avatars[args.identity] = args.url
|
||||
},
|
||||
|
||||
},
|
||||
actions: {},
|
||||
|
@ -1,76 +1,115 @@
|
||||
<template>
|
||||
<div>
|
||||
<b-card-code
|
||||
<b-card
|
||||
no-body
|
||||
title="My Delegations"
|
||||
>
|
||||
<b-card-header>
|
||||
<b-card-title>
|
||||
Validators (Max:{{ stakingParameters.max_validators }})
|
||||
<small class="text-muted">
|
||||
<b-badge variant="danger">
|
||||
|
||||
</b-badge>
|
||||
Top 33%
|
||||
<b-badge variant="warning">
|
||||
|
||||
</b-badge>
|
||||
Top 67% of Voting Power
|
||||
</small>
|
||||
</b-card-title>
|
||||
</b-card-header>
|
||||
<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"
|
||||
:fields="validator_fields"
|
||||
:sort-desc="true"
|
||||
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 -->
|
||||
<template #cell(description)="data">
|
||||
<b-media vertical-align="center">
|
||||
<template #aside>
|
||||
<b-avatar
|
||||
v-if="data.item.avatar"
|
||||
v-b-tooltip.hover.v-primary
|
||||
v-b-tooltip.hover.right="data.item.description.details"
|
||||
size="32"
|
||||
icon="ChevronRightIcon"
|
||||
variant="light-primary"
|
||||
: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>
|
||||
<span class="font-weight-bold d-block text-nowrap">
|
||||
<span class="font-weight-bolder d-block text-nowrap">
|
||||
{{ data.item.description.moniker }}
|
||||
</span>
|
||||
<small class="text-muted">{{ data.item.description.website || data.item.description.identity }}</small>
|
||||
</b-media>
|
||||
</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-card-code>
|
||||
</b-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { BTable, BMedia, BAvatar } from 'bootstrap-vue'
|
||||
import BCardCode from '@core/components/b-card-code/BCardCode.vue'
|
||||
import { Validator, percent } from '@/libs/data'
|
||||
import {
|
||||
BTable, BMedia, BAvatar, BBadge, BCard, BCardHeader, BCardTitle, VBTooltip,
|
||||
} from 'bootstrap-vue'
|
||||
import {
|
||||
Validator, percent, StakingParameters, formatToken,
|
||||
} from '@/libs/data'
|
||||
import { keybase } from '@/libs/fetch'
|
||||
// import fetch from 'node-fetch'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
BCardCode,
|
||||
BCard,
|
||||
BTable,
|
||||
BMedia,
|
||||
BAvatar,
|
||||
BBadge,
|
||||
BCardHeader,
|
||||
BCardTitle,
|
||||
},
|
||||
directives: {
|
||||
'b-tooltip': VBTooltip,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
sortBy: 'tokens',
|
||||
sortDesc: true,
|
||||
mintInflation: 0,
|
||||
stakingPool: {},
|
||||
stakingParameters: new StakingParameters(),
|
||||
validators: [new Validator()],
|
||||
delegations: [new Validator()],
|
||||
validator_fields: [
|
||||
{ key: 'index', label: '#' },
|
||||
{ key: 'description', label: 'Validator', sortable: true },
|
||||
{
|
||||
key: 'tokens',
|
||||
label: 'Voting Power',
|
||||
sortable: true,
|
||||
formatter: value => parseInt(value / 100000, 0),
|
||||
tdClass: 'text-right',
|
||||
thClass: 'text-right',
|
||||
sortByFormatted: true,
|
||||
@ -82,25 +121,80 @@ export default {
|
||||
tdClass: '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() {
|
||||
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.validators = res
|
||||
this.validators.forEach(i => {
|
||||
if (i.description.identity) {
|
||||
keybase(i.description.identity).then(d => {
|
||||
if (Array.isArray(d.them) && d.them.length > 0) {
|
||||
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
|
||||
}
|
||||
})
|
||||
}
|
||||
let promise = Promise.resolve()
|
||||
res.forEach((item, index) => {
|
||||
promise = promise.then(() => new Promise(resolve => {
|
||||
this.avatar(item.description.identity, index, resolve)
|
||||
}))
|
||||
})
|
||||
})
|
||||
},
|
||||
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>
|
||||
|
Loading…
Reference in New Issue
Block a user