Skip to content

Commit

Permalink
Merge pull request #250 from cosmos/fabo/133-hook-up-staking
Browse files Browse the repository at this point in the history
Show Candidates
  • Loading branch information
faboweb authored Dec 18, 2017
2 parents 1cefea7 + 983965f commit c45301c
Show file tree
Hide file tree
Showing 9 changed files with 460 additions and 127 deletions.
60 changes: 2 additions & 58 deletions app/src/main/mockServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,6 @@ let proxy = require('express-http-proxy')
let randomBytes = require('crypto').pseudoRandomBytes
let casual = require('casual')

let randomPubkey = () => ({
type: 'ed25519',
data: randomBytes(32).toString('hex')
})

let randomAddress = () => randomBytes(20).toString('hex')

let randomTime = () => Date.now() - casual.integer(0, 32e7)
Expand All @@ -23,24 +18,6 @@ let randomBondTx = (address, delegator) => ({
height: 1000
})

let randomCandidate = () => ({
address: randomAddress(),
owner: randomAddress(), // address
shares: casual.integer(1000, 1e7),
votingPower: casual.integer(10, 1e5),
since: casual.date('YYYY-MM-DD'),
description: {
name: casual.username,
website: casual.url,
details: casual.sentences(3)
},
commissionRate: casual.double(0.005, 0.05),
commissionMax: casual.double(0.05, 0.25),
status: [ 'active', 'bonding', 'unbonding' ][Math.floor(Math.random() * 3)],
slashRatio: Math.random() < 0.9 ? casual.double(0.01, 0.5) : 0,
reDelegatingShares: casual.integer(1000, 1e7)
})

module.exports = function (port = 8999) {
let app = express()

Expand All @@ -52,38 +29,6 @@ module.exports = function (port = 8999) {
// })

// delegation mock API
let candidates = new Array(50).fill(0).map(randomPubkey)
app.get('/query/stake/candidates', (req, res) => {
res.json({
height: 10000,
data: candidates
})
})
app.get('/query/stake/candidates/:pubkey', (req, res) => {
res.json({
height: 10000,
data: {
pubkey: randomPubkey(),
owner: {
chain: 'gaia-1',
app: 'sig',
address: randomBytes(20).toString('hex')
},
shares: Math.floor(Math.random() * 1e7),
voting_power: Math.floor(Math.random() * 1e5),
description: JSON.stringify({
description: casual.sentences(3),
commission: casual.double(0.005, 0.05),
commissionMax: casual.double(0.05, 0.25),
commissionMaxRate: casual.double(0.005, 0.05),
url: casual.url,
keybaseID: casual.username,
country: casual.country,
startDate: casual.date('YYYY-MM-DD')
})
}
})
})
app.post('/tx/stake/delegate/:pubkey/:amount', (req, res) => {
res.json({
'type': 'sigs/one',
Expand Down Expand Up @@ -150,9 +95,8 @@ module.exports = function (port = 8999) {
}
})
})
app.get('/candidates', (req, res) => {
res.json(new Array(200).fill(0).map(randomCandidate))
})

// tx history
app.get('/tx/bondings/delegator/:address', (req, res) => {
let { address } = req.params
let txs = new Array(100).fill(0)
Expand Down
2 changes: 1 addition & 1 deletion app/src/renderer/components/common/AppMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ menu.app-menu
list-item(to="/wallet/transactions" exact @click.native="close" title="Transactions")
part(title='Governance' v-if="config.devMode")
list-item(to="/proposals" exact @click.native="close" title="Proposals")
part(title='Stake' v-if="config.devMode")
part(title='Stake')
list-item(to="/staking" exact @click.native="close" title="Delegates")
part(title='Monitor' v-if="config.devMode")
list-item(to="/blockchain" exact @click.native="close" title="Blockchain")
Expand Down
12 changes: 7 additions & 5 deletions app/src/renderer/components/staking/LiDelegate.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,18 @@ transition(name='ts-li-delegate'): div(:class='styles')
template
i.fa.fa-check-square-o(v-if='inCart' @click='rm(delegate)')
i.fa.fa-square-o(v-else @click='add(delegate)')
router-link(:to="{ name: 'delegate', params: { delegate: delegate.id }}")
| {{ delegate.keybaseID}}
.value {{ delegate.country }}
router-link(v-if="config.devMode" :to="{ name: 'delegate', params: { delegate: delegate.id }}")
//- | {{ delegate.keybaseID ? delegate.keybaseID : 'n/a'}}
| {{ delegate.id }}
a(v-else) {{ delegate.id }}
.value {{ delegate.country ? delegate.country : 'n/a' }}
.value.voting_power.num.bar
span {{ num.prettyInt(delegate.voting_power) }}
.bar(:style='vpStyles')
.value.delegated.num.bar.delegated
span {{ num.prettyInt(delegate.shares) }}
.bar(:style='sharesStyles')
.value {{ (delegate.commission * 100).toFixed(2) }}%
.value {{ delegate.commission ? (delegate.commission * 100).toFixed(2) + '%' : 'n/a' }}
menu
btn(theme='cosmos' v-if='inCart'
icon='delete' value='Remove' size='sm' @click.native='rm(delegate)')
Expand All @@ -36,7 +38,7 @@ export default {
Btn
},
computed: {
...mapGetters(['shoppingCart', 'delegates']),
...mapGetters(['shoppingCart', 'delegates', 'config']),
styles () {
let value = 'li-delegate'
if (this.inCart) value += ' li-delegate-active '
Expand Down
17 changes: 11 additions & 6 deletions app/src/renderer/components/staking/PageDelegates.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@ page(:title='pageTitle')
a(@click='setSearch(true)')
i.material-icons search
.label Search
router-link(to='/staking/bond')
a(@click='updateDelegates()')
i.material-icons refresh
.label Refresh
router-link(v-if="config.devMode" to='/staking/bond')
i.material-icons check_circle
.label Bond Atoms
modal-search(v-if="filters.delegates.search.visible" type="delegates")
template(v-if="filteredDelegates.length > 0")
template(v-if="delegates.length > 0")
panel-sort(:sort='sort')
li-delegate(
v-for='i in filteredDelegates'
Expand Down Expand Up @@ -42,7 +45,7 @@ export default {
ToolBar
},
computed: {
...mapGetters(['delegates', 'filters', 'shoppingCart']),
...mapGetters(['delegates', 'filters', 'shoppingCart', 'config']),
pageTitle () {
if (this.shoppingCart.length > 0) {
return `Delegates (${this.shoppingCart.length} Selected)`
Expand All @@ -54,7 +57,7 @@ export default {
let query = this.filters.delegates.search.query
let list = orderBy(this.delegates, [this.sort.property], [this.sort.order])
if (this.filters.delegates.search.visible) {
return list.filter(i => includes(i.keybaseID.toLowerCase(), query.toLowerCase()))
return list.filter(i => includes(JSON.stringify(i).toLowerCase(), query.toLowerCase()))
} else {
return list
}
Expand All @@ -63,10 +66,11 @@ export default {
data: () => ({
query: '',
sort: {
property: 'keybaseID',
property: 'id',
order: 'asc',
properties: [
{ id: 1, title: 'Keybase ID', value: 'keybaseID', initial: true },
// { id: 1, title: 'Keybase ID', value: 'keybaseID', initial: true },
{ id: 1, title: 'Public Key', value: 'id', initial: true },
{ id: 2, title: 'Country', value: 'country' },
{ id: 3, title: 'Voting Power', value: 'voting_power' },
{ id: 4, title: 'Delegated Power', value: 'shares' },
Expand All @@ -75,6 +79,7 @@ export default {
}
}),
methods: {
updateDelegates () { this.$store.dispatch('getDelegates') },
setSearch (bool) { this.$store.commit('setSearchVisible', ['delegates', bool]) }
},
mounted () {
Expand Down
15 changes: 6 additions & 9 deletions app/src/renderer/vuex/modules/delegates.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
function pubkeyToString (pubkey) {
// go-wire key encoding,
// ed25519 keys prefixed w/ 01, secp256k1 w/ 02
let type = pubkey.type === 'ed25519' ? '01' : '02'
return type + pubkey.data
}
import axios from 'axios'

export default ({ dispatch, node }) => {
const state = []

const mutations = {
addDelegate (state, delegate) {
delegate.id = pubkeyToString(delegate.pubkey)
Object.assign(delegate, JSON.parse(delegate.description))
delegate.id = delegate.pub_key.data
Object.assign(delegate, delegate.description)

// return if we already have this delegate
for (let existingDelegate of state) {
Expand All @@ -30,7 +25,9 @@ export default ({ dispatch, node }) => {
}
},
async getDelegate ({ commit }, pubkey) {
let delegate = (await node.candidate(pubkeyToString(pubkey))).data
let delegate = (await axios.get('http://localhost:8998/query/stake/candidate/' + pubkey.data)).data.data
// TODO move into cosmos-sdk
// let delegate = (await node.candidate(pubkeyToString(pubkey))).data
commit('addDelegate', delegate)
}
}
Expand Down
33 changes: 20 additions & 13 deletions test/unit/specs/LiDelegate.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ describe('LiDelegate', () => {
store = new Vuex.Store({
getters: {
shoppingCart: () => shoppingCart.state.delegates,
delegates: () => delegates.state
delegates: () => delegates.state,
config: () => ({
devMode: true
})
},
modules: {
shoppingCart,
Expand All @@ -24,26 +27,30 @@ describe('LiDelegate', () => {
})

store.commit('addDelegate', {
pubkey: 'pubkeyX',
description: JSON.stringify({
id: 'idX',
pub_key: {
type: 'ed25519',
data: 'pubkeyX'
},
voting_power: 10000,
shares: 5000,
description: {
description: 'descriptionX',
voting_power: 10000,
shares: 5000,
keybaseID: 'keybaseX',
country: 'USA'
})
}
})
store.commit('addDelegate', {
pubkey: 'pubkeyY',
description: JSON.stringify({
id: 'idY',
pub_key: {
type: 'ed25519',
data: 'pubkeyY'
},
voting_power: 30000,
shares: 10000,
description: {
description: 'descriptionY',
voting_power: 30000,
shares: 10000,
keybaseID: 'keybaseY',
country: 'Canada'
})
}
})

delegate = store.state.delegates[0]
Expand Down
68 changes: 43 additions & 25 deletions test/unit/specs/PageDelegates.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ describe('PageDelegates', () => {
getters: {
shoppingCart: () => shoppingCart.state.delegates,
delegates: () => delegates.state,
filters: () => filters.state
filters: () => filters.state,
config: () => ({
devMode: true
})
},
modules: {
shoppingCart,
Expand All @@ -27,26 +30,30 @@ describe('PageDelegates', () => {
})

store.commit('addDelegate', {
pubkey: 'pubkeyY',
description: JSON.stringify({
id: 'idY',
description: 'descriptionY',
voting_power: 30000,
shares: 10000,
keybaseID: 'keybaseY',
country: 'Canada'
})
})
store.commit('addDelegate', {
pubkey: 'pubkeyX',
description: JSON.stringify({
id: 'idX',
pub_key: {
type: 'ed25519',
data: 'pubkeyX'
},
voting_power: 10000,
shares: 5000,
description: {
description: 'descriptionX',
voting_power: 2000,
shares: 5000,
keybaseID: 'keybaseX',
country: 'USA'
})
}
})
store.commit('addDelegate', {
pub_key: {
type: 'ed25519',
data: 'pubkeyY'
},
voting_power: 30000,
shares: 10000,
description: {
description: 'descriptionY',
keybaseID: 'keybaseY',
country: 'Canada'
}
})

wrapper = mount(PageDelegates, {
Expand All @@ -58,6 +65,7 @@ describe('PageDelegates', () => {
})

jest.spyOn(store, 'commit')
jest.spyOn(store, 'dispatch')
})

it('has the expected html structure', () => {
Expand All @@ -69,19 +77,26 @@ describe('PageDelegates', () => {
expect(wrapper.contains('.ni-modal-search')).toBe(true)
})

it('should refresh candidates on click', () => {
wrapper.findAll('.ni-tool-bar i').at(1).trigger('click')
expect(store.dispatch).toHaveBeenCalledWith('getDelegates')
})

it('should sort the delegates by selected property', () => {
expect(wrapper.vm.filteredDelegates.map(x => x.id)).toEqual(['idX', 'idY'])
wrapper.vm.sort = 'voting_power'
expect(wrapper.vm.filteredDelegates.map(x => x.id)).toEqual(['idY', 'idX'])
expect(wrapper.vm.filteredDelegates.map(x => x.id)).toEqual(['pubkeyX', 'pubkeyY'])

wrapper.vm.sort.property = 'voting_power'
wrapper.vm.sort.order = 'desc'
expect(wrapper.vm.filteredDelegates.map(x => x.id)).toEqual(['pubkeyY', 'pubkeyX'])
})

it('should filter the delegates', () => {
store.commit('setSearchVisible', ['delegates', true])
store.commit('setSearchQuery', ['delegates', 'baseX'])
expect(wrapper.vm.filteredDelegates.map(x => x.id)).toEqual(['idX'])
expect(wrapper.html()).toMatchSnapshot()
expect(wrapper.vm.filteredDelegates.map(x => x.id)).toEqual(['pubkeyX'])
expect(wrapper.vm.$el).toMatchSnapshot()
store.commit('setSearchQuery', ['delegates', 'baseY'])
expect(wrapper.vm.filteredDelegates.map(x => x.id)).toEqual(['idY'])
expect(wrapper.vm.filteredDelegates.map(x => x.id)).toEqual(['pubkeyY'])
})

it('should show the amount of selected delegates', () => {
Expand All @@ -96,7 +111,10 @@ describe('PageDelegates', () => {
getters: {
shoppingCart: () => shoppingCart.state,
delegates: () => [],
filters: () => filters.state
filters: () => filters.state,
config: () => ({
devMode: true
})
},
modules: {
shoppingCart,
Expand Down
Loading

0 comments on commit c45301c

Please sign in to comment.