Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hooking up bonding/unbonding to wallet #257

Merged
merged 26 commits into from
Dec 30, 2017
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
e7277a7
Hooked up bonding to wallet
mappum Dec 18, 2017
4289045
Merge branch 'develop' into matt/133-bonding
mappum Dec 26, 2017
06d84eb
Fixed delegation data retrieval
mappum Dec 26, 2017
b1b1a2a
Show name and sort by voting power in Delegates page
mappum Dec 26, 2017
c8bded2
Staking UI tweaks
mappum Dec 26, 2017
67d101f
Consolidated logic into 'delegation' vuex module
mappum Dec 27, 2017
eb41ea5
Handle unbonding
mappum Dec 27, 2017
f311d86
Show amount bonded by you in PageDelegates
mappum Dec 27, 2017
8b74c7b
Test fixed
mappum Dec 27, 2017
6932cbd
Updated PageBond UX to address unbonding, etc
mappum Dec 27, 2017
77a596d
Update PageBond snapshot, fix lint
mappum Dec 27, 2017
bfe4c81
Merge branch 'develop' into matt/133-bonding
mappum Dec 27, 2017
375aaf0
Merge remote-tracking branch 'origin/fabo/fix-console-error-catching'…
mappum Dec 27, 2017
abb84de
Merge branch 'develop' into matt/133-bonding
mappum Dec 27, 2017
8937174
Fix lint
mappum Dec 27, 2017
aee6ff0
Addressed comments from @jolesbi
mappum Dec 28, 2017
98fa544
Merge branch 'develop' into matt/133-bonding
faboweb Dec 28, 2017
b27228c
fix staking tx not being build
faboweb Dec 28, 2017
cff1e3f
improved styling of resetAlloc link
faboweb Dec 28, 2017
467b007
slight text improvements
faboweb Dec 28, 2017
c9d32bb
updated snapshot
faboweb Dec 28, 2017
bfba1d3
Merge branch 'develop' into matt/133-bonding
nylira Dec 29, 2017
3ca302e
Merge branch 'develop' into matt/133-bonding
nylira Dec 29, 2017
d27b7c8
Increased PageBond test coverage
mappum Dec 30, 2017
1101f65
PageBond unbonding tests
mappum Dec 30, 2017
c128d74
Merge branch 'develop' into matt/133-bonding
mappum Dec 30, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 22 additions & 14 deletions app/src/renderer/components/staking/LiDelegate.vue
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
<template lang='pug'>
transition(name='ts-li-delegate'): .li-delegate(:class='styles'): .li-delegate__values
.ni-delegate__value
.li-delegate__value.id
.li-delegate__value.name
span
i.fa.fa-check-square-o(v-if='inCart' @click='rm(delegate)')
i.fa.fa-square-o(v-else @click='add(delegate)')
router-link(v-if="config.devMode && delegate.id" :to="{ name: 'delegate', params: { delegate: delegate.id }}") {{ delegate.id }}
a(v-else) {{ delegate.id }}
.li-delegate__value
span {{ delegate.country ? delegate.country : 'n/a' }}
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(v-if="config.devMode" :to="{ name: 'delegate', params: { delegate: delegate.id }}")
| {{ ' ' + delegate.moniker }}
a(v-else) {{ ' ' + delegate.moniker }}
.li-delegate__value.id
span {{ delegate.id }}
.li-delegate__value.delegated
span {{ num.percentInt(bondedPercent) }}
.li-delegate__value.voting_power.num.bar
span {{ num.prettyInt(delegate.voting_power) }}
.bar(:style='vpStyles')
.li-delegate__value.delegated
span {{ num.percentInt(bondedPercent) }}
.li-delegate__value
span {{ delegate.commission ? num.percentInt(delegate.commission) : 'n/a' }}
span {{ num.prettyInt(amountBonded(delegate.id)) }}
</template>

<script>
Expand All @@ -30,7 +32,7 @@ export default {
Btn
},
computed: {
...mapGetters(['shoppingCart', 'delegates', 'config']),
...mapGetters(['shoppingCart', 'delegates', 'config', 'committedDelegations']),
styles () {
let value = ''
if (this.inCart) value += 'li-delegate-active '
Expand All @@ -42,13 +44,16 @@ export default {
return richestDelegate.voting_power
} else { return 0 }
},
vpTotal () {
return this.delegates.reduce((a, b) => a.voting_power + b.voting_power, 0)
},
vpStyles () {
let percentage =
Math.round((this.delegate.voting_power / this.vpMax) * 100)
return { width: percentage + '%' }
},
bondedPercent () {
return this.delegate.shares / this.delegate.voting_power
return this.delegate.voting_power / this.vpTotal
},
inCart () {
return this.shoppingCart.find(c => c.id === this.delegate.id)
Expand All @@ -59,7 +64,10 @@ export default {
}),
methods: {
add (delegate) { this.$store.commit('addToCart', delegate) },
rm (delegate) { this.$store.commit('removeFromCart', delegate.id) }
rm (delegate) { this.$store.commit('removeFromCart', delegate.id) },
amountBonded (delegateId) {
return this.committedDelegations[delegateId]
}
}
}
</script>
Expand All @@ -70,7 +78,7 @@ export default {
.li-delegate
&:nth-of-type(2n-1)
background app-fg
&.li-delegate-active
&.li-delegate-active
.li-delegate__value i.fa
color accent

Expand Down
103 changes: 40 additions & 63 deletions app/src/renderer/components/staking/PageBond.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,30 @@ page.page-bond(title="Bond Atoms")
i.material-icons arrow_back
.label Back

.reserved-atoms(v-if="unbondedAtoms == this.user.atoms")
| You have #[.reserved-atoms__number {{ unbondedAtoms }}] unbonded atoms. Start by bonding some of your atoms to these delegates.
.reserved-atoms(v-else-if="unbondedAtoms === 0")
| You are bonding #[.reserved-atoms__number ALL {{ bondedAtoms }}] atoms to these delegates. We suggest reserving some atoms for personal use&mdash;are you sure you wish to proceed? #[a(@click="resetAlloc") (start over?)]
.reserved-atoms(v-else-if="unbondedAtoms < 0")
| #[.reserved-atoms__number.reserved-atoms__number--error You are bonding {{ unbondedAtoms * -1 }} more atoms than exist in your balance.] Please reduce the number of atoms you are bonding to these delegates. #[a(@click="resetAlloc") (start over?)]
.reserved-atoms(v-else)
| You are reserving #[.reserved-atoms__number {{ unbondedAtoms }}] ({{ unbondedAtomsPct }}) atoms. You are bonding #[.reserved-atoms__number {{ bondedAtoms }}] ({{ bondedAtomsPct }}) atoms to these delegates. #[a(@click="resetAlloc") (start over?)]
.reserved-atoms
span(v-if="unbondedAtoms == totalAtoms")
span(v-else-if="unbondedAtoms === 0")
| You are bonding #[.reserved-atoms__number ALL {{ bondedAtoms }}] atoms to these delegates. We suggest reserving some atoms for personal use&mdash;are you sure you wish to proceed?
span(v-else-if="unbondedAtoms < 0")
| #[.reserved-atoms__number.reserved-atoms__number--error You've tried to bond {{ unbondedAtoms * -1 }} more atoms than you have.]
span(v-else)
| You will keep #[.reserved-atoms__number {{ unbondedAtoms }}] ({{ unbondedAtomsPct }}) atoms in your wallet. You are bonding #[.reserved-atoms__number {{ bondedAtoms }}] ({{ bondedAtomsPct }}) atoms to these delegates.
span(v-if="willUnbondAtoms > 0")
| You will begin unbonding #[.reserved-atoms__number {{ willUnbondAtoms }}] atoms, which will be available in 30 days.
span
| #[a(@click="resetAlloc") (start over?)]

form-struct(:submit="onSubmit")
form-group(v-for='(delegate, index) in fields.delegates' key='delegate.id'
:error="$v.fields.delegates.$each[index].$error")
Label {{ shortenLabel(delegate.delegate.id, 20) }} ({{ percentAtoms(delegate.atoms) }})
Label {{ shortenLabel(delegate.delegate.description.moniker, 10) }} - {{ shortenLabel(delegate.delegate.id, 20) }} ({{ percentAtoms(delegate.atoms) }})
field-group
field(
type="number"
step="any"
placeholder="Atoms"
v-model.number="delegate.atoms")
field-addon Atoms
// btn(type="button" value="Max"
@click.native="fillAtoms(delegate.id)")
field-addon Atoms
btn(type="button" icon="clear" @click.native="rm(delegate.id)")
form-msg(name="Atoms" type="required"
v-if="!$v.fields.delegates.$each[index].atoms.required")
Expand Down Expand Up @@ -66,65 +68,51 @@ export default {
ToolBar
},
computed: {
...mapGetters(['shoppingCart', 'user']),
reservedAtoms () {
return this.shoppingCart.reduce((sum, d) => sum + (d.reservedAtoms || 0), 0)
...mapGetters(['shoppingCart', 'user', 'committedDelegations']),
previouslyBondedAtoms () {
return Object.values(this.committedDelegations).reduce((sum, d) => sum + d, 0)
},
unreservedAtoms () {
return this.user.atoms - this.reservedAtoms
willUnbondAtoms () {
let sum = 0
for (let id of Object.keys(this.committedDelegations)) {
let committed = this.committedDelegations[id]
let delegate = this.fields.delegates.find(c => c.id === id)
let willBond = delegate ? delegate.atoms : 0
let unbondAmount = Math.max(committed - willBond, 0)
sum += unbondAmount
}
return sum
},
unbondedAtoms () {
let value = this.unreservedAtoms

// reduce unreserved atoms by bonded atoms
this.fields.delegates.forEach(f => (value -= f.atoms))

return value
let willBondSum = this.bondedAtoms
let bondedSum = this.previouslyBondedAtoms
return this.user.atoms - willBondSum + bondedSum - this.willUnbondAtoms
},
unbondedAtomsPct () {
return Math.round(this.unbondedAtoms / this.user.atoms * 100 * 100) / 100 + '%'
return Math.round(this.unbondedAtoms / this.totalAtoms * 100 * 10) / 10 + '%'
},
bondedAtoms () {
let value = 0
this.fields.delegates.forEach(f => (value += f.atoms))
return value
return this.fields.delegates.reduce((sum, d) => sum + (d.atoms || 0), 0)
},
bondedAtomsPct () {
return Math.round(this.bondedAtoms / this.user.atoms * 100 * 100) / 100 + '%'
return Math.round(this.bondedAtoms / this.totalAtoms * 100 * 10) / 10 + '%'
},
totalAtoms () {
return this.bondedAtoms + this.unbondedAtoms
}
},
data: () => ({
equalize: false,
atomsMin: 1,
reservedAtomsMin: 0,
atomsMin: 0,
fields: {
reservedAtoms: 0,
delegates: []
}
}),
methods: {
fillAtoms (delegateId) {
if (delegateId === 'unreserved') {
this.fields.reservedAtoms += this.unbondedAtoms
} else {
let delegate = this.fields.delegates.find(c => c.id === delegateId)
delegate.atoms += this.unbondedAtoms
}
},
clearAtoms (delegateId) {
if (delegateId === 'unreserved') {
console.log('clearing reserved atoms')
this.fields.reservedAtoms = 0
} else {
console.log('clearing atoms for', delegateId)
let delegate = this.fields.delegates.find(c => c.delegateId === delegateId)
delegate.atoms = 0
}
},
equalAlloc () {
this.equalize = true
this.resetAlloc()
let atoms = this.unreservedAtoms
let atoms = this.unbondedAtoms
let delegates = this.fields.delegates.length
let remainderAtoms = atoms % delegates

Expand All @@ -144,11 +132,7 @@ export default {
return Math.round(bondedAtoms / this.user.atoms * 100 * 100) / 100 + '%'
},
async onSubmit () {
if (this.unbondedAtoms === this.user.atoms) {
this.$store.commit('notifyError', { title: 'Unbonded Delegates',
body: 'You either haven\'t bonded any atoms yet, or some delegates have 0 atoms bonded.' })
return
} else if (this.unbondedAtoms < 0) {
if (this.unbondedAtoms < 0) {
this.$store.commit('notifyError', { title: 'Too Many Allocated Atoms',
body: `You've bonded ${this.unbondedAtoms * -1} more atoms than you have.`})
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"You've tried to bond {x} more atoms than you have"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

return
Expand All @@ -159,7 +143,7 @@ export default {
try {
await this.$store.dispatch('submitDelegation', this.fields)
this.$store.commit('notify', { title: 'Atoms Bonded',
body: 'You have successfully bonded your atoms. You can rebond after the 30 day unbonding period.' })
body: 'You have successfully updated your delegations.' })
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"delegated your atoms"?
"bonded your atoms"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I figured it might be weird if you only unbond and then see "you have bonded your atoms". What do you think?

Copy link
Collaborator

@jbibla jbibla Dec 28, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh i see! ok. makes sense. forget what i recommended.

} catch (err) {
this.$store.commit('notifyError', { title: 'Error While Bonding Atoms',
body: err.message })
Expand Down Expand Up @@ -205,13 +189,6 @@ export default {
},
validations: () => ({
fields: {
reservedAtoms: {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i like that we're getting rid of the concept of "reserved" 👍

required,
numeric,
between (atoms) {
return between(this.reservedAtomsMin, this.user.atoms)(atoms)
}
},
delegates: {
$each: {
atoms: {
Expand Down
18 changes: 9 additions & 9 deletions app/src/renderer/components/staking/PageDelegates.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ page(:title='pageTitle')
a(@click='setSearch(true)')
i.material-icons search
.label Search
a(@click='updateDelegates()')
a(@click='updateDelegates(address)')
i.material-icons refresh
.label Refresh
router-link(v-if="config.devMode" to='/staking/bond')
Expand Down Expand Up @@ -69,15 +69,14 @@ export default {
data: () => ({
query: '',
sort: {
property: 'id',
order: 'asc',
property: 'shares',
order: 'desc',
properties: [
// { 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: 'Bonded Power', value: 'shares' },
{ id: 5, title: 'Commission', value: 'commission' }
{ id: 1, title: 'Name', value: 'description.moniker' },
{ id: 2, title: 'Public Key', value: 'id' },
{ id: 3, title: 'Voting Power', value: 'shares', initial: true },
{ id: 4, title: 'Bonded Atoms', value: 'voting_power' },
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not...?

{ id: 3, title: 'Voting Power', value: 'voting_power', initial: true },
{ id: 4, title: 'Bonded Atoms', value: 'bonded_atoms' },

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It makes more sense to call the percentage of power "Voting Power", since that's how it's been referred to outside of the code. And what's called 'voting_power' in the code isn't necessarily voting power, it's more accurate to refer to it as the number of bonded tokens.

Copy link
Collaborator

@jbibla jbibla Dec 28, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

percentage of power "Voting Power"

is percentage of power === voting power OR bonded atoms?

'voting_power' in the code isn't necessarily voting power

😕 why not?

i'm probably just misunderstanding something...

{ id: 5, title: 'Bonded by You', value: 'bonded' }
]
}
}),
Expand All @@ -96,6 +95,7 @@ export default {
mounted () {
Mousetrap.bind(['command+f', 'ctrl+f'], () => this.setSearch(true))
Mousetrap.bind('esc', () => this.setSearch(false))
this.updateDelegates(this.user.address)
}
}
</script>
3 changes: 2 additions & 1 deletion app/src/renderer/vuex/getters.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ export const connected = state => state.node.connected
export const lastHeader = state => state.node.lastHeader

export const delegates = state => state.delegates
export const shoppingCart = state => state.shoppingCart.delegates
export const shoppingCart = state => state.delegation.delegates
export const committedDelegations = state => state.delegation.committedDelegates
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how does committedDelegations differ from bondedAtoms? also, should this be...

export const committedDelegations = state => state.delegation.committedDelegations

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

committedDelegations are our delegations which have been finalized on chain, the other values are just our local values before we have submitted.

That's actually the right name, called it ...Delegates to match the delegates array inside the module

export const user = state => state.user
export const config = state => state.config

Expand Down
2 changes: 2 additions & 0 deletions app/src/renderer/vuex/modules/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ export default ({ commit, basecoin }) => {
activeMenu: '',
desktop: false,
devMode: process.env.PREVIEW !== undefined ? JSON.parse(process.env.PREVIEW) : process.env.NODE_ENV === 'development',
// TODO: change to atom
bondingDenom: 'fermion',
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we check which network we're using to determine this instead of using a TODO?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would be ideal, but I'm not sure of a good heuristic for checking if a network is a testnet (and I'm not sure what the mainnet will be called in the code). We can do this once we have our first mainnet and need the bonding denom to be 'atom'

modals: {
help: {
active: false
Expand Down
Loading