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 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 {}
|
||||||
|
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 {
|
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'
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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)))
|
||||||
}
|
}
|
||||||
|
@ -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: {},
|
||||||
|
@ -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">
|
||||||
|
|
||||||
|
</b-badge>
|
||||||
|
Top 33%
|
||||||
|
<b-badge variant="warning">
|
||||||
|
|
||||||
|
</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>
|
||||||
|
Loading…
Reference in New Issue
Block a user