From ceb680471a75bda37d8c71be1b9f12825ea1ed7d Mon Sep 17 00:00:00 2001 From: Fabian Date: Mon, 13 Aug 2018 09:34:15 +0200 Subject: [PATCH 1/4] Revert "Merge pull request #1120 from cosmos/revert-1068-fedekunze/1010-lcd-stake" This reverts commit 028832ae3697b650f799e21591f6a26198132783. --- CHANGELOG.md | 2 + README.md | 2 +- .../renderer/components/common/AppHeader.vue | 5 +- .../renderer/components/staking/PageBond.vue | 20 +- .../components/wallet/PageTransactions.vue | 57 ++++- .../wallet/TmLiStakingTransaction.vue | 160 +++++++++++++ .../components/wallet/TmLiTransaction.vue | 219 ++++++++++++++++++ app/src/renderer/connectors/lcdClient.js | 64 ++++- app/src/renderer/connectors/lcdClientMock.js | 139 +++++++---- app/src/renderer/vuex/getters.js | 1 + app/src/renderer/vuex/modules/delegates.js | 8 +- app/src/renderer/vuex/modules/delegation.js | 71 ++++-- app/src/renderer/vuex/modules/node.js | 4 +- app/src/renderer/vuex/modules/user.js | 2 +- app/src/renderer/vuex/modules/validators.js | 25 +- app/src/renderer/vuex/modules/wallet.js | 2 +- app/src/renderer/vuex/store.js | 6 +- tasks/build/Gaia/COMMIT.sh | 2 +- test/e2e/launch.js | 3 + test/unit/helpers/vuex-setup.js | 11 +- .../__snapshots__/lcdClient.spec.js.snap | 46 +++- .../__snapshots__/lcdClientMock.spec.js.snap | 4 +- .../specs/components/common/AppHeader.spec.js | 3 +- .../specs/components/staking/PageBond.spec.js | 24 +- .../__snapshots__/PageBond.spec.js.snap | 12 +- .../__snapshots__/PageStaking.spec.js.snap | 4 +- .../wallet/PageTransactions.spec.js | 80 +++++-- .../PageTransactions.spec.js.snap | 14 ++ test/unit/specs/lcdClient.spec.js | 26 +++ test/unit/specs/lcdClientMock.spec.js | 104 +++++++-- .../__snapshots__/delegation.spec.js.snap | 50 +++- test/unit/specs/store/delegation.spec.js | 68 +++--- test/unit/specs/store/json/txs.js | 6 +- test/unit/specs/store/node.spec.js | 2 +- test/unit/specs/store/store.spec.js | 5 +- test/unit/specs/store/validators.spec.js | 8 +- 36 files changed, 1040 insertions(+), 219 deletions(-) create mode 100644 app/src/renderer/components/wallet/TmLiStakingTransaction.vue create mode 100644 app/src/renderer/components/wallet/TmLiTransaction.vue diff --git a/CHANGELOG.md b/CHANGELOG.md index 4410a9744c..1d4d0bc999 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,11 +14,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. * removed light theme option from preferences page @jbibla * enabled staked balance on PageWallet in production @faboweb * removed unused xmlhttprequest dependency @faboweb +* LCD staking endpoints @fedekunze @faboweb ### Added * storing balance, tx history and delegations locally to serve an old state faster @faboweb * added error message for missing network config @faboweb +* showing staking txs in history @faboweb ### Fixed diff --git a/README.md b/README.md index 5309ac70d6..177f200e7d 100644 --- a/README.md +++ b/README.md @@ -182,7 +182,7 @@ $ sed -i.bak 's/seeds = ""/seeds = "localhost"/g' ./builds/testnets/local-testne Activate TX indexing in your local node: ```bash -$ sed -i.bak 's/index_all_tags = true/index_all_tags = false/g' ./builds/testnets/local-testnet/config.toml +$ sed -i.bak 's/index_all_tags = false/index_all_tags = true/g' ~/.gaiad-testnet/config/config.toml ``` Store the gaia version used in your local testnet: diff --git a/app/src/renderer/components/common/AppHeader.vue b/app/src/renderer/components/common/AppHeader.vue index 0e189ce8dc..7c0a630be4 100644 --- a/app/src/renderer/components/common/AppHeader.vue +++ b/app/src/renderer/components/common/AppHeader.vue @@ -44,6 +44,7 @@ export default { document.documentElement.clientWidth, window.innerWidth || 0 ) + if (w >= 1024) { this.close() this.$store.commit("setConfigDesktop", true) @@ -65,6 +66,7 @@ export default { #app-header z-index z(appHeader) + .container -webkit-app-region drag @@ -85,7 +87,6 @@ export default { top 0 left 0 width 100% - background var(--app-bg) > .container @@ -103,7 +104,6 @@ export default { align-items center justify-content center padding 0 1rem - color var(--link) cursor pointer @@ -131,6 +131,7 @@ export default { border-bottom px solid var(--bc) padding 2.5rem 1rem 1rem 1rem line-height normal + img height 1.75rem diff --git a/app/src/renderer/components/staking/PageBond.vue b/app/src/renderer/components/staking/PageBond.vue index 92c99c1970..60fda33780 100644 --- a/app/src/renderer/components/staking/PageBond.vue +++ b/app/src/renderer/components/staking/PageBond.vue @@ -152,15 +152,17 @@ export default { ToolBar }, computed: { - ...mapGetters(["shoppingCart", "user", "committedDelegations", "config"]), + ...mapGetters(["shoppingCart", "user", "delegation", "config"]), denom() { return this.config.bondingDenom.toUpperCase() }, totalAtoms() { - return parseInt(this.user.atoms) + this.oldBondedAtoms + return ( + parseInt(this.user.atoms) + this.oldBondedAtoms + this.oldUnbondingAtoms + ) }, oldBondedAtoms() { - return Object.values(this.committedDelegations).reduce( + return Object.values(this.delegation.committedDelegates).reduce( (sum, d) => sum + parseInt(d), 0 ) @@ -177,6 +179,14 @@ export default { return atoms }, this.oldUnbondedAtoms) }, + oldUnbondingAtoms() { + return Object.values(this.delegation.unbondingDelegations).reduce( + (atoms, value) => { + return atoms + value + }, + 0 + ) + }, newUnbondingAtoms() { return this.fields.delegates.reduce((atoms, d) => { let delta = d.oldAtoms - d.atoms @@ -184,7 +194,7 @@ export default { return atoms + delta } return atoms - }, 0) + }, this.oldUnbondingAtoms) }, newUnbondingAtomsDelta() { return this.delta(this.newUnbondingAtoms, 0) @@ -247,7 +257,7 @@ export default { } }, resetFields() { - let committedDelegations = this.committedDelegations + let committedDelegations = this.delegation.committedDelegates let totalAtoms = this.totalAtoms this.fields.bondConfirm = false this.fields.delegates = this.shoppingCart.map(c => diff --git a/app/src/renderer/components/wallet/PageTransactions.vue b/app/src/renderer/components/wallet/PageTransactions.vue index 8bd0958c92..546fbc1d1a 100644 --- a/app/src/renderer/components/wallet/PageTransactions.vue +++ b/app/src/renderer/components/wallet/PageTransactions.vue @@ -9,14 +9,19 @@ tm-page(title='Transactions') modal-search(type="transactions" v-if="somethingToSearch") tm-data-loading(v-if="wallet.historyLoading") - data-empty-tx(v-else-if='transactions.length === 0') + data-empty-tx(v-else-if='allTransactions.length === 0') data-empty-search(v-else-if="filteredTransactions.length === 0") - tm-li-transaction( - v-else - v-for="i in filteredTransactions" - :key="shortid.generate()" - :transaction="i" - :address="wallet.address") + template(v-else v-for="i in filteredTransactions") + tm-li-transaction( + v-if="i.type === 'wallet'" + :key="shortid.generate()" + :transaction="i" + :address="wallet.address") + tm-li-staking-transaction( + v-if="i.type === 'staking'" + :key="shortid.generate()" + :transaction="i" + :address="wallet.address") diff --git a/app/src/renderer/components/wallet/TmLiStakingTransaction.vue b/app/src/renderer/components/wallet/TmLiStakingTransaction.vue new file mode 100644 index 0000000000..e557cb4ddc --- /dev/null +++ b/app/src/renderer/components/wallet/TmLiStakingTransaction.vue @@ -0,0 +1,160 @@ + + + + + diff --git a/app/src/renderer/components/wallet/TmLiTransaction.vue b/app/src/renderer/components/wallet/TmLiTransaction.vue new file mode 100644 index 0000000000..57e8f15a0a --- /dev/null +++ b/app/src/renderer/components/wallet/TmLiTransaction.vue @@ -0,0 +1,219 @@ + + + + + diff --git a/app/src/renderer/connectors/lcdClient.js b/app/src/renderer/connectors/lcdClient.js index 79d470fbd0..75974d5ec1 100644 --- a/app/src/renderer/connectors/lcdClient.js +++ b/app/src/renderer/connectors/lcdClient.js @@ -90,12 +90,64 @@ Object.assign(Client.prototype, { }, tx: argReq("GET", "/txs"), - // staking - updateDelegations: req("POST", "/stake/delegations"), - candidates: req("GET", "/stake/validators"), - getValidators: req("GET", "/validatorsets/latest"), - queryDelegation: function(delegator, validator) { - return req("GET", `/stake/${delegator}/delegation/${validator}`).call(this) + /* ============ STAKE ============ */ + + // Get all delegations information from a delegator + getDelegator: function(addr) { + return req("GET", `/stake/delegators/${addr}`).call(this) + }, + // Get all txs from a delegator + getDelegatorTxs: function(addr, types) { + if (!types) { + return req("GET", `/stake/delegators/${addr}/txs`).call(this) + } else { + return req("GET", `/stake/delegators/${addr}/txs?type=${types}`).call( + this + ) + } + }, + // // Query all validators that a delegator is bonded to + // getDelegatorValidators: function(delegatorAddr) { + // return req("GET", `/stake/delegators/${delegatorAddr}/validators`).call(this) + // }, + // // Query a validator info that a delegator is bonded to + // getDelegatorValidator: function(delegatorAddr, validatorAddr) { + // return req("GET", `/stake/delegators/${delegatorAddr}/validators/${validatorAddr}`).call(this) + // }, + + // Get a list containing all the validator candidates + getCandidates: req("GET", "/stake/validators"), + // Get information from a validator + getCandidate: function(addr) { + return req("GET", `/stake/validators/${addr}`).call(this) + }, + // // Get all of the validator bonded delegators + // getValidatorDelegators: function(addr) { + // return req("GET", `/stake/validator/${addr}/delegators`).call(this) + // }, + + // Get the list of the validators in the latest validator set + getValidatorSet: req("GET", "/validatorsets/latest"), + + updateDelegations: function(delegatorAddr, data) { + return req("POST", `/stake/delegators/${delegatorAddr}/delegations`).call( + this, + data + ) + }, + + // Query a delegation between a delegator and a validator + queryDelegation: function(delegatorAddr, validatorAddr) { + return req( + "GET", + `/stake/delegators/${delegatorAddr}/delegations/${validatorAddr}` + ).call(this) + }, + queryUnbonding: function(delegatorAddr, validatorAddr) { + return req( + "GET", + `/stake/delegators/${delegatorAddr}/unbonding_delegations/${validatorAddr}` + ).call(this) } }) diff --git a/app/src/renderer/connectors/lcdClientMock.js b/app/src/renderer/connectors/lcdClientMock.js index a995f0ceb8..d5ccf0dcd7 100644 --- a/app/src/renderer/connectors/lcdClientMock.js +++ b/app/src/renderer/connectors/lcdClientMock.js @@ -48,6 +48,7 @@ let state = { value: { msg: [ { + type: "cosmos-sdk/Send", value: { inputs: [ { @@ -84,6 +85,7 @@ let state = { value: { msg: [ { + type: "cosmos-sdk/Send", value: { inputs: [ { @@ -118,12 +120,15 @@ let state = { ], stake: { [addresses[0]]: { - [validators[0]]: { - delegator_addr: addresses[0], - validator_addr: validators[0], - shares: "130", - height: 123 - } + delegations: [ + { + delegator_addr: addresses[0], + validator_addr: validators[0], + shares: "14", + height: 123 + } + ], + unbonding_delegations: [] } }, candidates: [ @@ -236,8 +241,8 @@ module.exports = { ) }) }, - async tx() { - return {} + async tx(hash) { + return state.txs.find(tx => tx.hash === hash) }, async send(to, req) { let fromKey = state.keys.find(a => a.name === req.name) @@ -254,7 +259,10 @@ module.exports = { }, // staking - async updateDelegations({ name, sequence, delegations, begin_unbondings }) { + async updateDelegations( + delegatorAddr, + { name, sequence, delegations, begin_unbondings } + ) { let results = [] let fromKey = state.keys.find(a => a.name === name) @@ -294,10 +302,15 @@ module.exports = { // update stake let delegator = state.stake[fromKey.address] if (!delegator) { - state.stake[fromKey.address] = {} + state.stake[fromKey.address] = { + delegations: [], + unbonding_delegations: [] + } delegator = state.stake[fromKey.address] } - let delegation = delegator[tx.validator_addr] + let delegation = delegator.delegations.find( + d => d.validator_addr === tx.validator_addr + ) if (!delegation) { delegation = { delegator_addr: fromKey.address, @@ -305,8 +318,9 @@ module.exports = { shares: "0", height: 0 } - delegator[tx.validator_addr] = delegation + delegator.delegations.push(delegation) } + let shares = parseInt(delegation.shares) delegation.shares = (shares + amount).toString() @@ -316,6 +330,7 @@ module.exports = { parseInt(candidate.delegator_shares) + amount ).toString() + storeTx("cosmos-sdk/MsgDelegate", tx) results.push(txResult(0)) } @@ -334,7 +349,9 @@ module.exports = { results.push(txResult(2, "Nonexistent delegator")) return results } - let delegation = delegator[tx.validator_addr] + let delegation = delegator.delegations.find( + d => d.validator_addr === tx.validator_addr + ) if (!delegation) { results.push(txResult(2, "Nonexistent delegation")) return results @@ -345,26 +362,59 @@ module.exports = { let candidate = state.candidates.find(c => c.owner === tx.validator_addr) shares = parseInt(candidate.tokens) candidate.tokens = (+shares - amount).toString() + delegator.unbonding_delegations.push( + Object.assign({}, tx, { + balance: { + amount: tx.shares + } + }) + ) + storeTx("cosmos-sdk/BeginUnbonding", tx) results.push(txResult(0)) } return results }, async queryDelegation(delegatorAddress, validatorAddress) { + let delegator = state.stake[delegatorAddress] + if (!delegator) return {} + return delegator.delegations.find( + ({ validator_addr }) => validator_addr === validatorAddress + ) + }, + async queryUnbonding(delegatorAddress, validatorAddress) { let delegator = state.stake[delegatorAddress] if (!delegator) return - return delegator[validatorAddress] + return delegator.unbonding_delegations.find( + d => d.validator_addr === validatorAddress + ) + }, + // Get all delegations information from a delegator + getDelegator(delegatorAddress) { + let delegator = state.stake[delegatorAddress] || {} + return delegator + }, + getDelegatorTxs(addr, types = []) { + if (types.length === 0) types = ["bonding", "unbonding"] + types = types.map(type => { + if (type === "bonding") return "cosmos-sdk/MsgDelegate" + if (type === "unbonding") return "cosmos-sdk/BeginUnbonding" + }) + return getTxs(types) }, - async candidates() { + async getCandidates() { return state.candidates }, - async getValidators() { + async getValidatorSet() { return { block_height: 1, validators: state.candidates } }, + async getCandidate(addr) { + return state.candidates.find(c => c.owner === addr) + }, // exports to be used in tests state, addresses, @@ -435,43 +485,52 @@ function send(to, from, req) { } // log tx + storeTx("cosmos-sdk/Send", { + inputs: [ + { + coins: req.amount, + address: from + } + ], + outputs: [ + { + coins: req.amount, + address: to + } + ] + }) + + // if receiver is bot address, send money back + if (to === botAddress) { + send(from, botAddress, { + amount: req.amount, + sequence: state.accounts[botAddress].sequence + }) + } + + return txResult(0) +} + +function storeTx(type, body) { state.txs.push({ tx: { value: { msg: [ { - value: { - inputs: [ - { - coins: req.amount, - address: from - } - ], - outputs: [ - { - coins: req.amount, - address: to - } - ] - } + type, + value: body } ] } }, hash: makeHash(), - height: getHeight() + (from === botAddress ? 1 : 0), + height: getHeight(), time: Date.now() }) +} - // if receiver is bot address, send money back - if (to === botAddress) { - send(from, botAddress, { - amount: req.amount, - sequence: state.accounts[botAddress].sequence - }) - } - - return txResult(0) +function getTxs(types) { + return state.txs.filter(tx => types.indexOf(tx.tx.value.msg[0].type) !== -1) } // function delegate (sender, { pub_key: { data: pubKey }, amount: delegation }) { diff --git a/app/src/renderer/vuex/getters.js b/app/src/renderer/vuex/getters.js index a310805974..78a1832cdf 100644 --- a/app/src/renderer/vuex/getters.js +++ b/app/src/renderer/vuex/getters.js @@ -17,6 +17,7 @@ export const transactions = state => state.wallet.history export const wallet = state => state.wallet // staking +export const delegation = state => state.delegation export const committedDelegations = state => state.delegation.committedDelegates export const delegates = state => state.delegates export const shoppingCart = state => state.delegation.delegates diff --git a/app/src/renderer/vuex/modules/delegates.js b/app/src/renderer/vuex/modules/delegates.js index ab16ae8a83..2ef8eca4a5 100644 --- a/app/src/renderer/vuex/modules/delegates.js +++ b/app/src/renderer/vuex/modules/delegates.js @@ -38,16 +38,16 @@ export default ({ node }) => { }, async getDelegates({ state, commit }) { commit("setDelegateLoading", true) - let delegates = await node.candidates() - let { validators } = await node.getValidators() - for (let delegate of delegates) { + let candidates = await node.getCandidates() + let { validators } = await node.getValidatorSet() + for (let delegate of candidates) { if (validators.find(v => v.pub_key === delegate.pub_key)) { delegate.isValidator = true } commit("addDelegate", delegate) } - commit("setDelegates", delegates) + commit("setDelegates", candidates) commit("setDelegateLoading", false) return state.delegates diff --git a/app/src/renderer/vuex/modules/delegation.js b/app/src/renderer/vuex/modules/delegation.js index 6e51c627b6..404d90eb16 100644 --- a/app/src/renderer/vuex/modules/delegation.js +++ b/app/src/renderer/vuex/modules/delegation.js @@ -6,7 +6,9 @@ export default ({ node }) => { delegates: [], // our delegations which are already on the blockchain - committedDelegates: {} + committedDelegates: {}, + unbondingDelegations: {}, + delegationTxs: [] } const mutations = { @@ -36,6 +38,18 @@ export default ({ node }) => { committedDelegates[candidateId] = value } state.committedDelegates = committedDelegates + }, + setUnbondingDelegations(state, { candidateId, value }) { + let unbondingDelegations = Object.assign({}, state.unbondingDelegations) + if (value === 0) { + delete unbondingDelegations[candidateId] + } else { + unbondingDelegations[candidateId] = value + } + state.unbondingDelegations = unbondingDelegations + }, + setDelegationTxs(state, txs) { + state.delegationTxs = txs } } @@ -46,36 +60,44 @@ export default ({ node }) => { } }, // load committed delegations from LCD - async getBondedDelegates({ state, rootState, dispatch }, candidates) { + async getBondedDelegates( + { state, rootState, commit, dispatch }, + candidates + ) { state.loading = true let address = rootState.user.address candidates = candidates || (await dispatch("getDelegates")) - await Promise.all( - candidates.map(candidate => - dispatch("getBondedDelegate", { - delegator: address, - validator: candidate.owner + let delegator = await node.getDelegator(address) + if (delegator.delegations) { + delegator.delegations.forEach(({ validator_addr, shares }) => { + commit("setCommittedDelegation", { + candidateId: validator_addr, + value: parseFloat(shares) }) + if (shares > 0) { + const delegate = candidates.find( + ({ owner }) => owner === validator_addr // this should change to address instead of owner + ) + commit("addToCart", delegate) + } + }) + } + if (delegator.unbonding_delegations) { + delegator.unbonding_delegations.forEach( + ({ validator_addr, balance: { amount } }) => { + commit("setUnbondingDelegations", { + candidateId: validator_addr, + value: parseFloat(amount) + }) + } ) - ) + } state.loading = false }, - // load committed delegation from LCD - async getBondedDelegate({ commit, rootState }, { delegator, validator }) { - let bond = await node.queryDelegation(delegator, validator) - - let shares = bond ? bond.shares : 0 - let delegate = rootState.delegates.delegates.find( - d => d.owner === validator - ) - - commit("setCommittedDelegation", { - candidateId: validator, - value: shares - }) - if (shares > 0) { - commit("addToCart", delegate) - } + async getDelegationTxs({ commit, rootState }) { + let address = rootState.user.address + let txs = await node.getDelegatorTxs(address) + commit("setDelegationTxs", txs) }, async updateDelegates({ dispatch }) { let candidates = await dispatch("getDelegates") @@ -117,6 +139,7 @@ export default ({ node }) => { await dispatch("sendTx", { type: "updateDelegations", + to: rootState.wallet.address, // TODO strange syntax delegations: delegate, begin_unbondings: unbond }) diff --git a/app/src/renderer/vuex/modules/node.js b/app/src/renderer/vuex/modules/node.js index 39f0b781b0..ea585e6370 100644 --- a/app/src/renderer/vuex/modules/node.js +++ b/app/src/renderer/vuex/modules/node.js @@ -36,7 +36,7 @@ export default function({ node }) { } const actions = { - setLastHeader({ state, rootState, dispatch }, header) { + async setLastHeader({ state, rootState, dispatch }, header) { state.lastHeader = header // TODO do this somewhere else probably @@ -44,7 +44,7 @@ export default function({ node }) { rootState.wallet.zoneIds.unshift(header.chain_id) } - dispatch("maybeUpdateValidators", header) + await dispatch("maybeUpdateValidators", header) }, async reconnect({ commit }) { if (state.stopConnecting) return diff --git a/app/src/renderer/vuex/modules/user.js b/app/src/renderer/vuex/modules/user.js index 391643beca..60a37e9b63 100644 --- a/app/src/renderer/vuex/modules/user.js +++ b/app/src/renderer/vuex/modules/user.js @@ -109,7 +109,7 @@ export default ({ node }) => { let { address } = await node.getKey(account) state.address = address - commit("loadPersistedState", { account, password }) + commit("loadPersistedState", { address, password }) commit("setModalSession", false) dispatch("initializeWallet", address) dispatch("loadErrorCollection", account) diff --git a/app/src/renderer/vuex/modules/validators.js b/app/src/renderer/vuex/modules/validators.js index 198e8de8ce..f74bfa7dfd 100644 --- a/app/src/renderer/vuex/modules/validators.js +++ b/app/src/renderer/vuex/modules/validators.js @@ -20,25 +20,24 @@ export default ({ node }) => { dispatch("getValidators") } }, - getValidators({ state, commit }) { + async getValidators({ state, commit }) { state.loading = true - node.rpc.validators((err, { validators } = {}) => { - if (err) { - commit("notifyError", { - title: "Error fetching validator set", - body: err.message - }) - return - } + try { + let validators = (await node.getValidatorSet()).validators commit("setValidators", validators) - state.loading = false - }) + } catch (err) { + commit("notifyError", { + title: "Error fetching validator set", + body: err.message + }) + } + state.loading = false }, - maybeUpdateValidators({ state, commit, dispatch }, header) { + async maybeUpdateValidators({ state, commit, dispatch }, header) { let validatorHash = header.validators_hash if (validatorHash === state.validatorHash) return commit("setValidatorHash", validatorHash) - dispatch("getValidators") + await dispatch("getValidators") } } diff --git a/app/src/renderer/vuex/modules/wallet.js b/app/src/renderer/vuex/modules/wallet.js index b6e513a852..e7ceb8624e 100644 --- a/app/src/renderer/vuex/modules/wallet.js +++ b/app/src/renderer/vuex/modules/wallet.js @@ -69,7 +69,7 @@ export default ({ node }) => { }, queryWalletState({ dispatch }) { dispatch("queryWalletBalances") - dispatch("queryWalletHistory") + // dispatch("queryWalletHistory") // is done on mounting transactions }, async queryWalletBalances({ state, rootState, commit }) { let res = await node.queryAccount(state.address) diff --git a/app/src/renderer/vuex/store.js b/app/src/renderer/vuex/store.js index 6c6fa9a9ce..1ca4037985 100644 --- a/app/src/renderer/vuex/store.js +++ b/app/src/renderer/vuex/store.js @@ -47,11 +47,11 @@ function persistState(state) { state.user.password ) // Store the state object as a JSON string - localStorage.setItem("store_" + state.user.account, encryptedState) + localStorage.setItem("store_" + state.user.address, encryptedState) } -function loadPersistedState(state, { account, password }) { - const cachedState = localStorage.getItem("store_" + account) +function loadPersistedState(state, { address, password }) { + const cachedState = localStorage.getItem("store_" + address) if (cachedState) { const bytes = CryptoJS.AES.decrypt(cachedState, password) const plaintext = bytes.toString(CryptoJS.enc.Utf8) diff --git a/tasks/build/Gaia/COMMIT.sh b/tasks/build/Gaia/COMMIT.sh index 61800138c4..f097f53326 100755 --- a/tasks/build/Gaia/COMMIT.sh +++ b/tasks/build/Gaia/COMMIT.sh @@ -2,4 +2,4 @@ # This is the commit of the SDK version to use for building Gaia. We use an # explicit hash instead of a tag so we don't have to trust GitHub. -export COMMIT=23e3d5ac12145c02fcb4b4767d7dfccad782aee5 +export COMMIT=6d95d1cef47ec6806fba26e17ac63c7d387bb771 diff --git a/test/e2e/launch.js b/test/e2e/launch.js index 1683776d15..41e9524a91 100644 --- a/test/e2e/launch.js +++ b/test/e2e/launch.js @@ -253,6 +253,9 @@ function initLocalNode() { const localnodeProcess = spawn(command, { shell: true }) localnodeProcess.stderr.pipe(process.stderr) + // the init command now asks for a password for some default account we don't need + localnodeProcess.stdin.write("\n") + localnodeProcess.stdout.once("data", data => { let msg = data.toString() diff --git a/test/unit/helpers/vuex-setup.js b/test/unit/helpers/vuex-setup.js index 7fe8d0ae87..b6c971a5e7 100644 --- a/test/unit/helpers/vuex-setup.js +++ b/test/unit/helpers/vuex-setup.js @@ -16,7 +16,7 @@ export default function vuexSetup() { function init( componentConstructor, testType = shallow, - { stubs, getters = {}, propsData, doBefore = () => {} } // doBefore receives router and store + { stubs, getters = {}, propsData, methods, doBefore = () => {} } // doBefore receives router and store ) { const node = Object.assign({}, require("../helpers/node_mock")) const modules = Modules({ node }) @@ -58,7 +58,8 @@ export default function vuexSetup() { store, router, stubs, - propsData + propsData, + methods }) } } @@ -67,22 +68,24 @@ export default function vuexSetup() { localVue, shallow: ( componentConstructor, - { stubs, getters, propsData, doBefore } = {} + { stubs, getters, propsData, methods, doBefore } = {} ) => init(componentConstructor, shallow, { stubs, getters, propsData, + methods, doBefore }), mount: ( componentConstructor, - { stubs, getters, propsData, doBefore } = {} + { stubs, getters, propsData, methods, doBefore } = {} ) => init(componentConstructor, mount, { stubs, getters, propsData, + methods, doBefore }) } diff --git a/test/unit/specs/__snapshots__/lcdClient.spec.js.snap b/test/unit/specs/__snapshots__/lcdClient.spec.js.snap index 72925727b2..767113f074 100644 --- a/test/unit/specs/__snapshots__/lcdClient.spec.js.snap +++ b/test/unit/specs/__snapshots__/lcdClient.spec.js.snap @@ -1,9 +1,53 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`LCD Client queries for a candidate 1`] = ` +Array [ + Array [ + "http://localhost:8998/stake/validators/abc", + undefined, + ], +] +`; + +exports[`LCD Client queries for a delegation summary for a delegator 1`] = ` +Array [ + Array [ + "http://localhost:8998/stake/delegators/abc", + undefined, + ], +] +`; + +exports[`LCD Client queries for a delegation txs 1`] = ` +Array [ + Array [ + "http://localhost:8998/stake/delegators/abc/txs", + undefined, + ], + Array [ + "http://localhost:8998/stake/delegators/abc/txs?type=bonding", + undefined, + ], + Array [ + "http://localhost:8998/stake/delegators/abc/txs?type=unbonding", + undefined, + ], +] +`; + exports[`LCD Client queries for shares for a validator and delegate 1`] = ` Array [ Array [ - "http://localhost:8998/stake/abc/delegation/efg", + "http://localhost:8998/stake/delegators/abc/delegations/efg", + undefined, + ], +] +`; + +exports[`LCD Client queries for undelegations between a delegator and a validator 1`] = ` +Array [ + Array [ + "http://localhost:8998/stake/delegators/abc/unbonding_delegations/def", undefined, ], ] diff --git a/test/unit/specs/__snapshots__/lcdClientMock.spec.js.snap b/test/unit/specs/__snapshots__/lcdClientMock.spec.js.snap index cd6a39cd30..3028ce00dc 100644 --- a/test/unit/specs/__snapshots__/lcdClientMock.spec.js.snap +++ b/test/unit/specs/__snapshots__/lcdClientMock.spec.js.snap @@ -2,10 +2,10 @@ exports[`LCD Client Mock delegates to multiple validators at once 1`] = `"10"`; -exports[`LCD Client Mock delegates to multiple validators at once 2`] = `"140"`; +exports[`LCD Client Mock delegates to multiple validators at once 2`] = `"24"`; exports[`LCD Client Mock deletes keys 1`] = `[Error: Passwords do not match]`; -exports[`LCD Client Mock queries bondings per delegator 1`] = `"130"`; +exports[`LCD Client Mock queries bondings per delegator 1`] = `"14"`; exports[`LCD Client Mock updates keys 1`] = `[Error: Passwords do not match]`; diff --git a/test/unit/specs/components/common/AppHeader.spec.js b/test/unit/specs/components/common/AppHeader.spec.js index d03615efe3..0da3326809 100644 --- a/test/unit/specs/components/common/AppHeader.spec.js +++ b/test/unit/specs/components/common/AppHeader.spec.js @@ -8,8 +8,7 @@ describe("AppHeader", () => { beforeEach(() => { instance = mount(AppHeader, { - stubs: { "app-menu": "" }, - methods: { watchWindowSize: () => {} } + stubs: { "app-menu": "" } }) wrapper = instance.wrapper store = instance.store diff --git a/test/unit/specs/components/staking/PageBond.spec.js b/test/unit/specs/components/staking/PageBond.spec.js index c467e4972e..308ef74979 100644 --- a/test/unit/specs/components/staking/PageBond.spec.js +++ b/test/unit/specs/components/staking/PageBond.spec.js @@ -37,6 +37,10 @@ describe("PageBond", () => { country: "Canada", moniker: "someOtherValidator" }) + store.commit("setUnbondingDelegations", { + candidateId: "pubkeyY", + value: 100 + }) } }) store = test.store @@ -58,7 +62,7 @@ describe("PageBond", () => { it("shows number of total atoms", () => { store.commit("setAtoms", 1337) - expect(wrapper.vm.totalAtoms).toBe(1337) + expect(wrapper.vm.totalAtoms).toBe(1437) // plus unbonding atoms }) it("shows old bonded atoms ", () => { @@ -75,14 +79,14 @@ describe("PageBond", () => { it("shows bond bar percent", () => { store.commit("setAtoms", 120) - expect(wrapper.vm.bondBarPercent(30)).toBe("25%") + expect(wrapper.vm.bondBarPercent(30)).toBe("14%") }) it("sets bond bar inner width and style", () => { store.commit("setAtoms", 120) wrapper.setData({ bondBarOuterWidth: 128 }) - expect(wrapper.vm.bondBarInnerWidth(80)).toBe("95px") - expect(wrapper.vm.styleBondBarInner(80)).toEqual({ width: "95px" }) + expect(wrapper.vm.bondBarInnerWidth(80)).toBe("64px") + expect(wrapper.vm.styleBondBarInner(80)).toEqual({ width: "64px" }) }) it("sets bond group class", () => { @@ -180,9 +184,9 @@ describe("PageBond", () => { ] } }) - expect(wrapper.find("#new-unbonded-atoms").element.value).toBe("81") + expect(wrapper.find("#new-unbonded-atoms").element.value).toBe("181") // plus unbonding atoms wrapper.find("#btn-reset").trigger("click") - expect(wrapper.find("#new-unbonded-atoms").element.value).toBe("101") + expect(wrapper.find("#new-unbonded-atoms").element.value).toBe("201") }) it("shows an error when bonding too many atoms", () => { @@ -227,8 +231,8 @@ describe("PageBond", () => { ] } }) - expect(wrapper.vm.newUnbondedAtoms).toBe(81) - expect(wrapper.find("#new-unbonded-atoms").vnode.elm._value).toBe(81) + expect(wrapper.vm.newUnbondedAtoms).toBe(181) // plus unbonding atoms + expect(wrapper.find("#new-unbonded-atoms").vnode.elm._value).toBe(181) }) it("shows an appropriate amount of unbonding atoms", () => { @@ -255,8 +259,8 @@ describe("PageBond", () => { ] } }) - expect(wrapper.vm.newUnbondingAtoms).toBe(20) - expect(wrapper.find("#new-unbonding-atoms").vnode.elm._value).toBe(20) + expect(wrapper.vm.newUnbondingAtoms).toBe(120) // plus old unbonding atoms + expect(wrapper.find("#new-unbonding-atoms").vnode.elm._value).toBe(120) }) it("shows an error if confirmation is not checked", () => { diff --git a/test/unit/specs/components/staking/__snapshots__/PageBond.spec.js.snap b/test/unit/specs/components/staking/__snapshots__/PageBond.spec.js.snap index 17d00ca27e..c63efed253 100644 --- a/test/unit/specs/components/staking/__snapshots__/PageBond.spec.js.snap +++ b/test/unit/specs/components/staking/__snapshots__/PageBond.spec.js.snap @@ -96,7 +96,7 @@ exports[`PageBond has the expected html structure 1`] = `
- Start bonding your 101 STEAK + Start bonding your 201 STEAK
- Start bonding your 101 STEAK + Start bonding your 201 STEAK
- 130 + 14
Validator @@ -392,7 +392,7 @@ exports[`PageStaking should filter the delegates 1`] = ` class="li-delegate__value your-votes" > - 130 + 14
{ let wrapper, store let { mount } = setup() - beforeEach(() => { + beforeEach(async () => { let instance = mount(PageTransactions, { stubs: { "tm-li-transaction": "", + "tm-li-staking-transaction": "", "data-empty-tx": "" + }, + methods: { + refreshTransactions: jest.fn() } }) wrapper = instance.wrapper @@ -17,6 +64,7 @@ describe("PageTransactions", () => { store.commit("setWalletAddress", "tb1d4u5zerywfjhxuc9nudvw") store.commit("setWalletHistory", mockTransactions) + store.commit("setDelegationTxs", delegationTxs) wrapper.update() }) @@ -41,11 +89,12 @@ describe("PageTransactions", () => { }) it("should refresh the transaction history", () => { + wrapper.vm.refreshTransactions = jest.fn() wrapper .findAll(".tm-tool-bar i") .at(0) .trigger("click") - expect(store.dispatch).toHaveBeenCalledWith("queryWalletHistory") + expect(wrapper.vm.refreshTransactions).toHaveBeenCalled() }) it("should show transactions", () => { @@ -54,9 +103,11 @@ describe("PageTransactions", () => { it("should sort the transaction by time", () => { expect(wrapper.vm.filteredTransactions.map(x => x.height)).toEqual([ - "3466", - "3438", - "3436" + 3438, + 3436, + 466, + 170, + 160 ]) }) @@ -64,25 +115,17 @@ describe("PageTransactions", () => { store.commit("setSearchVisible", ["transactions", true]) store.commit("setSearchQuery", ["transactions", "fabo"]) wrapper.update() - expect(wrapper.vm.filteredTransactions.map(x => x.height)).toEqual(["3466"]) + expect(wrapper.vm.filteredTransactions.map(x => x.height)).toEqual([466]) // reflects the filter in the view expect(wrapper.vm.$el).toMatchSnapshot() store.commit("setSearchQuery", ["transactions", "mattc"]) - expect(wrapper.vm.filteredTransactions.map(x => x.height)).toEqual(["3466"]) - }) - - it("should refresh the transactions on click", () => { - wrapper - .findAll(".tm-tool-bar i") - .at(0) - .trigger("click") - - expect(store.dispatch).toHaveBeenCalledWith("queryWalletHistory") + expect(wrapper.vm.filteredTransactions.map(x => x.height)).toEqual([466]) }) it("should update 'somethingToSearch' when there's nothing to search", () => { expect(wrapper.vm.somethingToSearch).toBe(true) store.commit("setWalletHistory", []) + store.commit("setDelegationTxs", []) expect(wrapper.vm.somethingToSearch).toBe(false) store.commit("setWalletHistory", mockTransactions) expect(wrapper.vm.somethingToSearch).toBe(true) @@ -92,19 +135,20 @@ describe("PageTransactions", () => { it("should show an error if there are no transactions", () => { store.commit("setWalletHistory", []) + store.commit("setDelegationTxs", []) wrapper.update() expect(wrapper.contains("data-empty-tx")).toBe(true) }) it("should not show search when there is nothing to search", () => { - let transactions = [] mount(PageTransactions, { stubs: { "tm-li-transaction": "", "data-empty-tx": "" } }) - store.commit("setWalletHistory", transactions) + store.commit("setWalletHistory", []) + store.commit("setDelegationTxs", []) wrapper.update() expect(wrapper.vm.setSearch()).toEqual(false) }) diff --git a/test/unit/specs/components/wallet/__snapshots__/PageTransactions.spec.js.snap b/test/unit/specs/components/wallet/__snapshots__/PageTransactions.spec.js.snap index 21d30ab532..592cfdcfe5 100644 --- a/test/unit/specs/components/wallet/__snapshots__/PageTransactions.spec.js.snap +++ b/test/unit/specs/components/wallet/__snapshots__/PageTransactions.spec.js.snap @@ -100,14 +100,27 @@ exports[`PageTransactions has the expected html structure 1`] = ` address="tb1d4u5zerywfjhxuc9nudvw" transaction="[object Object]" /> + + + + + + +
+
`; diff --git a/test/unit/specs/lcdClient.spec.js b/test/unit/specs/lcdClient.spec.js index 458caf6b90..8ba59c1bc0 100644 --- a/test/unit/specs/lcdClient.spec.js +++ b/test/unit/specs/lcdClient.spec.js @@ -158,4 +158,30 @@ describe("LCD Client", () => { client.listKeys = () => Promise.resolve() expect(result).toEqual(["abc"]) }) + + it("queries for a delegation summary for a delegator", async () => { + axios.get = jest.fn().mockReturnValue({}) + client.getDelegator("abc") + expect(axios.get.mock.calls).toMatchSnapshot() + }) + + it("queries for a delegation txs", async () => { + axios.get = jest.fn().mockReturnValue({}) + client.getDelegatorTxs("abc") + client.getDelegatorTxs("abc", ["bonding"]) + client.getDelegatorTxs("abc", ["unbonding"]) + expect(axios.get.mock.calls).toMatchSnapshot() + }) + + it("queries for undelegations between a delegator and a validator", async () => { + axios.get = jest.fn().mockReturnValue({}) + client.queryUnbonding("abc", "def") + expect(axios.get.mock.calls).toMatchSnapshot() + }) + + it("queries for a candidate", async () => { + axios.get = jest.fn().mockReturnValue({}) + client.getCandidate("abc") + expect(axios.get.mock.calls).toMatchSnapshot() + }) }) diff --git a/test/unit/specs/lcdClientMock.spec.js b/test/unit/specs/lcdClientMock.spec.js index 3c315d7716..7e5fc4ad30 100644 --- a/test/unit/specs/lcdClientMock.spec.js +++ b/test/unit/specs/lcdClientMock.spec.js @@ -74,8 +74,8 @@ describe("LCD Client Mock", () => { expect(res).toBeUndefined() }) - xit("persists a sent tx", async () => { - let res = await client.coinTxs(lcdClientMock.addresses[0]) + it("persists a sent tx", async () => { + let res = await client.txs(lcdClientMock.addresses[0]) expect(res.length).toBe(2) // predefined txs let { address: toAddr } = await client.storeKey({ @@ -96,10 +96,15 @@ describe("LCD Client Mock", () => { }) expect(res.height).toBeDefined() - res = await client.coinTxs(lcdClientMock.addresses[0]) + res = await client.txs(lcdClientMock.addresses[0]) expect(res.length).toBe(3) }) + it("queries a tx by it's hash", async () => { + let tx = await client.tx(lcdClientMock.state.txs[0].hash) + expect(tx.height).toBe(1) + }) + it("query and update the nonce", async () => { let { sequence } = await client.queryAccount(lcdClientMock.addresses[0]) expect(sequence).toBe("1") @@ -255,10 +260,19 @@ describe("LCD Client Mock", () => { }) it("queries for all candidates", async () => { - let data = await client.candidates() + let data = await client.getCandidates() expect(data.length).toBeGreaterThan(0) }) + it("queries for one candidate", async () => { + let validator = await client.getCandidate(lcdClientMock.validators[0]) + expect(validator).toBe( + lcdClientMock.state.candidates.find( + v => v.owner === lcdClientMock.validators[0] + ) + ) + }) + it("queries bondings per delegator", async () => { let res = await client.queryDelegation( lcdClientMock.addresses[0], @@ -274,7 +288,7 @@ describe("LCD Client Mock", () => { ) expect(stake).toBeUndefined() - let res = await client.updateDelegations({ + let res = await client.updateDelegations(lcdClientMock.addresses[0], { sequence: 1, name: "default", delegations: [ @@ -298,7 +312,7 @@ describe("LCD Client Mock", () => { }) it("executes an unbond tx", async () => { - let res = await client.updateDelegations({ + let res = await client.updateDelegations(lcdClientMock.addresses[0], { sequence: 1, name: "default", delegations: [ @@ -320,7 +334,7 @@ describe("LCD Client Mock", () => { ) expect(initialStake.shares).toBe("10") - res = await client.updateDelegations({ + res = await client.updateDelegations(lcdClientMock.addresses[0], { sequence: 2, name: "default", delegations: [], @@ -344,7 +358,7 @@ describe("LCD Client Mock", () => { }) it("can not stake fermions you dont have", async () => { - let res = await client.updateDelegations({ + let res = await client.updateDelegations(lcdClientMock.addresses[0], { sequence: 1, name: "default", delegations: [ @@ -362,7 +376,7 @@ describe("LCD Client Mock", () => { }) it("errors when delegating with incorrect nonce", async () => { - let res = await client.updateDelegations({ + let res = await client.updateDelegations(lcdClientMock.addresses[0], { sequence: 1, name: "default", delegations: [ @@ -378,7 +392,7 @@ describe("LCD Client Mock", () => { expect(res[0].check_tx.log).toBe("") expect(res[0].check_tx.code).toBe(0) - res = await client.updateDelegations({ + res = await client.updateDelegations(lcdClientMock.addresses[0], { sequence: 1, name: "default", delegations: [ @@ -401,7 +415,7 @@ describe("LCD Client Mock", () => { password: "1234567890", address: lcdClientMock.addresses[1] }) - let res = await client.updateDelegations({ + let res = await client.updateDelegations(lcdClientMock.addresses[0], { sequence: 1, name: "nonexistent_account", delegations: [ @@ -419,7 +433,7 @@ describe("LCD Client Mock", () => { }) it("delegates to multiple validators at once", async () => { - let res = await client.updateDelegations({ + let res = await client.updateDelegations(lcdClientMock.addresses[0], { sequence: 1, name: "default", delegations: [ @@ -456,7 +470,7 @@ describe("LCD Client Mock", () => { }) it("errors when delegating negative amount", async () => { - let res = await client.updateDelegations({ + let res = await client.updateDelegations(lcdClientMock.addresses[0], { sequence: 1, name: "default", delegations: [ @@ -474,7 +488,7 @@ describe("LCD Client Mock", () => { }) it("errors when unbonding with no delegation", async () => { - let res = await client.updateDelegations({ + let res = await client.updateDelegations(lcdClientMock.addresses[0], { sequence: 1, name: "default", delegations: [], @@ -490,4 +504,66 @@ describe("LCD Client Mock", () => { expect(res[0].check_tx.log).toBe("Nonexistent delegation") expect(res[0].check_tx.code).toBe(2) }) + + it("queries for summary of delegation information for a delegator", async () => { + let delegation = await client.getDelegator(lcdClientMock.addresses[0]) + expect(Object.keys(delegation)).toEqual([ + "delegations", + "unbonding_delegations" + ]) + }) + + it("queries for an unbonding delegation between a validator and a delegator", async () => { + await client.updateDelegations(lcdClientMock.addresses[0], { + sequence: 1, + name: "default", + delegations: [], + begin_unbondings: [ + { + delegator_addr: lcdClientMock.addresses[0], + validator_addr: lcdClientMock.validators[0], + shares: "10" + } + ] + }) + let undelegations = await client.queryUnbonding( + lcdClientMock.addresses[0], + lcdClientMock.validators[0] + ) + + expect(undelegations.shares).toBe("10") + }) + + it("queries for staking txs", async () => { + await client.updateDelegations(lcdClientMock.addresses[0], { + sequence: 1, + name: "default", + delegations: [ + { + delegator_addr: lcdClientMock.addresses[0], + validator_addr: lcdClientMock.validators[2], + delegation: { denom: "mycoin", amount: "10" } + } + ], + begin_unbondings: [ + { + delegator_addr: lcdClientMock.addresses[0], + validator_addr: lcdClientMock.validators[0], + shares: "10" + } + ] + }) + let txs = await client.getDelegatorTxs(lcdClientMock.addresses[0]) + expect(txs).toHaveLength(2) + + txs = await client.getDelegatorTxs(lcdClientMock.addresses[0], ["bonding"]) + expect(txs).toHaveLength(1) + expect(txs[0].tx.value.msg[0].type).toBe("cosmos-sdk/MsgDelegate") + + txs = await client.getDelegatorTxs(lcdClientMock.addresses[0], [ + "unbonding" + ]) + expect(txs).toHaveLength(1) + expect(txs[0].tx.value.msg[0].type).toBe("cosmos-sdk/BeginUnbonding") + }) }) diff --git a/test/unit/specs/store/__snapshots__/delegation.spec.js.snap b/test/unit/specs/store/__snapshots__/delegation.spec.js.snap index 7d64413859..3c0544b738 100644 --- a/test/unit/specs/store/__snapshots__/delegation.spec.js.snap +++ b/test/unit/specs/store/__snapshots__/delegation.spec.js.snap @@ -2,8 +2,14 @@ exports[`Module: Delegations fetches bonded delegates 1`] = ` Object { - "cosmosvaladdr15ky9du8a2wlstz6fpx3p4mqpjyrm5ctplpn3au": "15", - "cosmosvaladdr15ky9du8a2wlstz6fpx3p4mqpjyrm5ctqzh8yqw": "10", + "cosmosvaladdr15ky9du8a2wlstz6fpx3p4mqpjyrm5ctqzh8yqw": 14, +} +`; + +exports[`Module: Delegations fetches current undelegations 1`] = ` +Object { + "cosmosvaladdr15ky9du8a2wlstz6fpx3p4mqpjyrm5ctplpn3au": 356, + "cosmosvaladdr15ky9du8a2wlstz6fpx3p4mqpjyrm5ctqzh8yqw": 73, } `; @@ -14,15 +20,17 @@ Array [ Array [ Object { "account_number": "1", - "begin_unbondings": Array [ + "begin_unbondings": Array [], + "chain_id": "test-chain", + "delegations": Array [ Object { + "delegation": Object { + "amount": "109", + "denom": "steak", + }, "delegator_addr": "cosmosaccaddr15ky9du8a2wlstz6fpx3p4mqpjyrm5ctpesxxn9", - "shares": "7", "validator_addr": "cosmosvaladdr15ky9du8a2wlstz6fpx3p4mqpjyrm5ctqzh8yqw", }, - ], - "chain_id": "test-chain", - "delegations": Array [ Object { "delegation": Object { "amount": "456", @@ -40,3 +48,31 @@ Array [ ], ] `; + +exports[`Module: Delegations submits undelegation transaction 1`] = ` +Array [ + Array [ + Object { + "account_number": "1", + "begin_unbondings": Array [ + Object { + "delegator_addr": "cosmosaccaddr15ky9du8a2wlstz6fpx3p4mqpjyrm5ctpesxxn9", + "shares": "73", + "validator_addr": "cosmosvaladdr15ky9du8a2wlstz6fpx3p4mqpjyrm5ctqzh8yqw", + }, + Object { + "delegator_addr": "cosmosaccaddr15ky9du8a2wlstz6fpx3p4mqpjyrm5ctpesxxn9", + "shares": "356", + "validator_addr": "cosmosvaladdr15ky9du8a2wlstz6fpx3p4mqpjyrm5ctplpn3au", + }, + ], + "chain_id": "test-chain", + "delegations": Array [], + "gas": "50000000", + "name": "default", + "password": "bar", + "sequence": "3", + }, + ], +] +`; diff --git a/test/unit/specs/store/delegation.spec.js b/test/unit/specs/store/delegation.spec.js index 63803270c6..9f41a54caa 100644 --- a/test/unit/specs/store/delegation.spec.js +++ b/test/unit/specs/store/delegation.spec.js @@ -3,12 +3,11 @@ import setup from "../../helpers/vuex-setup" let instance = setup() describe("Module: Delegations", () => { - let store, node + let store beforeEach(async () => { let test = instance.shallow() store = test.store - node = test.node store.dispatch("signIn", { password: "bar", account: "default" }) await store.dispatch("getDelegates") @@ -64,35 +63,7 @@ describe("Module: Delegations", () => { }) it("fetches bonded delegates", async () => { - node.queryDelegation = jest - .fn() - .mockReturnValueOnce({ - shares: "10" - }) - .mockReturnValueOnce({ - shares: "15" - }) - // no delegation for a delegate - .mockReturnValueOnce(null) - await store.dispatch("getBondedDelegates", store.state.delegates.delegates) - - // each is user account + validator owner - expect(node.queryDelegation.mock.calls).toEqual([ - [ - "cosmosaccaddr15ky9du8a2wlstz6fpx3p4mqpjyrm5ctpesxxn9", - "cosmosvaladdr15ky9du8a2wlstz6fpx3p4mqpjyrm5ctqzh8yqw" - ], - [ - "cosmosaccaddr15ky9du8a2wlstz6fpx3p4mqpjyrm5ctpesxxn9", - "cosmosvaladdr15ky9du8a2wlstz6fpx3p4mqpjyrm5ctplpn3au" - ], - [ - "cosmosaccaddr15ky9du8a2wlstz6fpx3p4mqpjyrm5ctpesxxn9", - "cosmosvaladdr15ky9du8a2wlstz6fpx3p4mqpjyrm5ctgurrg7n" - ] - ]) - expect(store.state.delegation.committedDelegates).toMatchSnapshot() }) @@ -116,6 +87,43 @@ describe("Module: Delegations", () => { expect(store._actions.sendTx[0].mock.calls).toMatchSnapshot() }) + it("submits undelegation transaction", async () => { + store.dispatch("setLastHeader", { + height: 42, + chain_id: "test-chain" + }) + await store.dispatch("getBondedDelegates") + + jest.spyOn(store._actions.sendTx, "0") + + let bondings = [50, 100, 0] + const delegations = store.state.delegates.delegates.map((delegate, i) => ({ + delegate, + atoms: bondings[i] + })) + + await store.dispatch("submitDelegation", delegations) + + expect(store._actions.sendTx[0].mock.calls).toMatchSnapshot() + }) + + it("fetches current undelegations", async () => { + await store.dispatch("getBondedDelegates", store.state.delegates.delegates) + expect(store.state.delegation.unbondingDelegations).toMatchSnapshot() + }) + + it("deletes undelegations that are 0", async () => { + await store.dispatch("getBondedDelegates", store.state.delegates.delegates) + store.commit("setUnbondingDelegations", { + candidateId: "cosmosvaladdr15ky9du8a2wlstz6fpx3p4mqpjyrm5ctqzh8yqw", + value: 0 + }) + expect( + store.state.delegation.unbondingDelegations + .cosmosvaladdr15ky9du8a2wlstz6fpx3p4mqpjyrm5ctqzh8yqw + ).toBeUndefined() + }) + it("should query delegated atoms on reconnection", () => { jest.resetModules() let axios = require("axios") diff --git a/test/unit/specs/store/json/txs.js b/test/unit/specs/store/json/txs.js index 2d320b23c6..44e06c1a7d 100644 --- a/test/unit/specs/store/json/txs.js +++ b/test/unit/specs/store/json/txs.js @@ -1,7 +1,7 @@ module.exports = [ { hash: "not a real hash", - time: Date.now(), // set by Voyager + time: Date.now() + 1000, // set by Voyager height: "3436", tx: { type: "8EFE47F0625DE8", @@ -79,7 +79,7 @@ module.exports = [ }, { hash: "not a real hash2", - time: Date.now() + 10, // set by Voyager + time: Date.now() + 1010, // set by Voyager height: "3438", tx: { type: "8EFE47F0625DE8", @@ -160,7 +160,7 @@ module.exports = [ hash: "not a real hash3", time: Date.now() + 100, // set by Voyager - height: "3466", + height: "466", tx: { type: "8EFE47F0625DE8", value: { diff --git a/test/unit/specs/store/node.spec.js b/test/unit/specs/store/node.spec.js index 6dc96e2003..1ebbba4c5b 100644 --- a/test/unit/specs/store/node.spec.js +++ b/test/unit/specs/store/node.spec.js @@ -35,7 +35,7 @@ describe("Module: Node", () => { }) it("checks for new validators", done => { - node.rpc.validators = () => done() + node.getValidatorSet = () => done() store.dispatch("setLastHeader", { height: 5, chain_id: "test-chain", diff --git a/test/unit/specs/store/store.spec.js b/test/unit/specs/store/store.spec.js index fc47236755..63c5c0d039 100644 --- a/test/unit/specs/store/store.spec.js +++ b/test/unit/specs/store/store.spec.js @@ -1,5 +1,6 @@ import Store from "renderer/vuex/store" import node from "../../helpers/node_mock" +import lcdClientMock from "renderer/connectors/lcdClientMock.js" describe("Store", () => { let store @@ -18,7 +19,9 @@ describe("Store", () => { password: "1234567890" }) store.commit("setWalletBalances", [{ denom: "fabocoin", amount: 42 }]) - expect(localStorage.getItem("store_default")).toBeTruthy() + expect( + localStorage.getItem("store_" + lcdClientMock.addresses[0]) + ).toBeTruthy() }) it("should restore balances et al after logging in", async () => { diff --git a/test/unit/specs/store/validators.spec.js b/test/unit/specs/store/validators.spec.js index 946f8993f4..3be4d6f714 100644 --- a/test/unit/specs/store/validators.spec.js +++ b/test/unit/specs/store/validators.spec.js @@ -34,8 +34,8 @@ describe("Module: Validators", () => { }) it("should query validators", async () => { - store.dispatch("getValidators") - expect(store.state.validators.validators).toHaveLength(6) + await store.dispatch("getValidators") + expect(store.state.validators.validators).toHaveLength(3) }) it("should survive errors in querying validators", async () => { @@ -69,9 +69,9 @@ describe("Module: Validators", () => { jest.resetModules() store.state.node.stopConnecting = true store.state.validators.loading = true - jest.spyOn(node.rpc, "validators") + jest.spyOn(node, "getValidatorSet") store.dispatch("reconnected") - expect(node.rpc.validators).toHaveBeenCalled() + expect(node.getValidatorSet).toHaveBeenCalled() }) it("should not query validators on reconnection if not stuck in loading", () => { From 57ad7df0123f9dc498801fb9d342935b61b07e19 Mon Sep 17 00:00:00 2001 From: Fabian Date: Mon, 13 Aug 2018 18:28:38 +0200 Subject: [PATCH 2/4] trigger CI --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d4d0bc999..0a99ca15d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,7 +20,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. * storing balance, tx history and delegations locally to serve an old state faster @faboweb * added error message for missing network config @faboweb -* showing staking txs in history @faboweb +* showing staking transactions in history @faboweb ### Fixed From ff0047cc3c66d990cfe16bfcee116ac59177cfd4 Mon Sep 17 00:00:00 2001 From: Fabian Date: Mon, 13 Aug 2018 18:42:37 +0200 Subject: [PATCH 3/4] using latest release candidate --- tasks/build/Gaia/COMMIT.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasks/build/Gaia/COMMIT.sh b/tasks/build/Gaia/COMMIT.sh index f097f53326..b1d3263bc0 100755 --- a/tasks/build/Gaia/COMMIT.sh +++ b/tasks/build/Gaia/COMMIT.sh @@ -2,4 +2,4 @@ # This is the commit of the SDK version to use for building Gaia. We use an # explicit hash instead of a tag so we don't have to trust GitHub. -export COMMIT=6d95d1cef47ec6806fba26e17ac63c7d387bb771 +export COMMIT=0b2bf8f3a0e02844fb959099a27969186ab6fead From 4b67f3061b0046da5ed96c5d07f9da1e46cae743 Mon Sep 17 00:00:00 2001 From: Voyager Bot Date: Mon, 13 Aug 2018 20:20:03 +0200 Subject: [PATCH 4/4] cachebust gaia --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index d9c0c8372d..fdd85c27b8 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -10,7 +10,7 @@ jobs: - checkout - restore_cache: - key: v6-Gaia-{{ checksum "tasks/build/Gaia/COMMIT.sh" }} + key: v7-Gaia-{{ checksum "tasks/build/Gaia/COMMIT.sh" }} # If Gaia isn't in the cache then build it. - run: | @@ -21,7 +21,7 @@ jobs: fi - save_cache: - key: v6-Gaia-{{ checksum "tasks/build/Gaia/COMMIT.sh" }} + key: v7-Gaia-{{ checksum "tasks/build/Gaia/COMMIT.sh" }} paths: - ~/target