diff --git a/.eslintrc.js b/.eslintrc.js index 939e133083..56d77c8100 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -6,7 +6,7 @@ module.exports = { extends: ["plugin:vue/recommended", "@vue/prettier"], rules: { "vue/component-name-in-template-casing": ["error", "PascalCase"], - "no-console": process.env.NODE_ENV === "production" ? "error" : "off", + "no-console": "off", "no-debugger": process.env.NODE_ENV === "production" ? "error" : "off" }, parserOptions: { diff --git a/CHANGELOG.md b/CHANGELOG.md index fef2748b76..1d93abb271 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,57 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. +## [1.0.157] - 2020-01-10 + +### Added + +- [#3362](https://github.com/cosmos/lunie/pull/3362) Adds "Back to Validators" button in PageValidator @Bitcoinera +- [#3358](https://github.com/cosmos/lunie/pull/3358) Adds the e-Money network icon @Bitcoinera +- [#3314](https://github.com/cosmos/lunie/issues/3314) Keep sessions per network @faboweb +- Allow address creation in all cosmos networks @faboweb +- [#3364](https://github.com/cosmos/lunie/pull/3364) Track failing transactions clientside in Sentry @faboweb +- Retry graphql fetches on failed attempts @faboweb +- [#3375](https://github.com/cosmos/lunie/pull/3375) Allow user to show address on Ledger Nano @faboweb +- added little x back to action modal @jbibla +- [#3345](https://github.com/cosmos/lunie/issues/3345) New tutorial component @mariopino + +### Changed + +- [#3313](https://github.com/cosmos/lunie/issues/3313) Now when Linux users go to sign in with Ledger they get a warning message with a link to the Ledger documentation to fix connection issues @Bitcoinera +- [#3289](https://github.com/cosmos/lunie/pull/3289) Now PageValidator handles empty fields more uniformly, always displaying `--` @Bitcoinera +- [#3398](https://github.com/cosmos/lunie/pull/3398) Replaces a phantom div in the "Back to Validators" button for padding, as it should have been from the beginning @Bitcoinera +- [#3366](https://github.com/cosmos/lunie/pull/3366) Fix link in ActionModal for lunie browser extension @Bitcoinera +- [#3371](https://github.com/cosmos/lunie/pull/3371) Strengthen the validation for cosmos addresses signin @Bitcoinera +- [#3349](https://github.com/cosmos/lunie/pull/3349) Now it is possible to also sign in with an Ethereum address @Bitcoinera +- [#3349](https://github.com/cosmos/lunie/pull/3349) Now the Undelegations component filters for only pending undelegations @Bitcoinera +- success screen icon is green instead of orange @jbibla +- delegation and undelegation are now "stake" and "unstake" @jbibla + +### Fixed + +- [#3384](https://github.com/cosmos/lunie/pull/3384) Now fees in action modals for all enabled networks work. Micro denoms are properly set @Bitcoinera +- [#3354](https://github.com/cosmos/lunie/pull/3354) Fix session per network so it signs in to the current network @Bitcoinera +- [#3323](https://github.com/cosmos/lunie/pull/3323) Fixes the userTransactionAdded subscription and deletes the double TmLoadingComponent @Bitcoinera +- [#3359](https://github.com/cosmos/lunie/pull/3359) Fixes address undefined for the "To address" in multisends @Bitcoinera +- [#3350](https://github.com/cosmos/lunie/pull/3350) Remove field not present in API schema @colw +- [#3351](https://github.com/cosmos/lunie/pull/3351) A typo @colw +- [#3390](https://github.com/cosmos/lunie/pull/3390) Fix ActionModal data being out of date if a live update of data happened @faboweb +- [#3364](https://github.com/cosmos/lunie/pull/3364) Improve handling of sequence querying in ActionModal @faboweb +- Show failing txs in action modal @faboweb +- there was a styling issue with the "show on ledger" button and it was being displayed for all signed in sessions, not just ledger sessions @jbibla +- [#3096](https://github.com/cosmos/lunie/issues/3096) Fix redelegation to and from fields @mariopino +- [#3277](https://github.com/cosmos/lunie/issues/3277) Update proposals every 10 blocks @mariopino +- [#3280](https://github.com/cosmos/lunie/issues/3280) Replace toggles in all and active buttons in validators page. @mariopino +- [#3328](https://github.com/cosmos/lunie/issues/3328) Fix error 404 in validator links from transactions in page block @mariopino +- [#3339](https://github.com/cosmos/lunie/issues/3339) Fix session modal validation triggers on closing @mariopino +- [#3376](https://github.com/cosmos/lunie/issues/3376) Round total rewards to 6 decimal places @mariopino + +### Repository + +- Merge back master into develop before releasing @faboweb +- Cleaned packages @faboweb +- Lint before push @faboweb + ## [1.0.156] - 2020-01-08 ### Added diff --git a/package.json b/package.json index add375fe66..ac20cac438 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lunie", - "version": "1.0.156", + "version": "1.0.157", "description": "Lunie is the staking and governance platform for proof-of-stake blockchains.", "author": "Lunie International Software Systems Inc. ", "scripts": { @@ -29,13 +29,16 @@ "@dicebear/avatars-jdenticon-sprites": "1.1.4", "@lunie/cosmos-api": "0.2.5", "@lunie/cosmos-keys": "0.0.12", - "@lunie/cosmos-ledger": "0.1.4", + "@lunie/cosmos-ledger": "0.1.5", "@sentry/browser": "5.7.1", "@sentry/integrations": "5.7.1", "apollo-boost": "^0.4.3", "apollo-cache-inmemory": "^1.6.2", + "apollo-client": "2.6.8", + "apollo-link": "1.2.13", "apollo-link-batch-http": "1.2.13", "apollo-link-persisted-queries": "0.2.2", + "apollo-link-retry": "2.2.15", "apollo-link-ws": "1.0.19", "apollo-utilities": "1.3.2", "autosize": "^4.0.2", @@ -49,6 +52,7 @@ "cross-spawn": "7.0.1", "crypto-js": "^3.1.9-1", "graphql": "14.4.2", + "graphql-tag": "2.10.1", "https-proxy-agent": ">=3.0.0", "jdenticon": "2.2.0", "lodash.groupby": "4.6.0", @@ -60,10 +64,11 @@ "moment": "^2.24.0", "no-scroll": "^2.1.1", "register-service-worker": "^1.6.2", + "serialize-javascript": ">=2.1.1", "subscriptions-transport-ws": "0.9.16", "timezone-mock": "^1.0.8", "vue": "^2.6.10", - "vue-apollo": "3.0.0-rc.2", + "vue-apollo": "3.0.2", "vue-clipboard2": "^0.3.0", "vue-directive-tooltip": "^1.4.5", "vue-infinite-scroll": "^2.0.2", @@ -73,7 +78,8 @@ "web3-utils": "1.2.4" }, "devDependencies": { - "@ascendancyy/vue-cli-plugin-stylelint": "^1.1.2", + "@ascendancyy/vue-cli-plugin-stylelint": "1.1.2", + "@babel/core": "7.7.7", "@babel/plugin-transform-runtime": "^7.5.5", "@capacitor/android": "1.3.0", "@capacitor/cli": "1.3.0", @@ -82,19 +88,17 @@ "@vue/cli-plugin-babel": "^3.10.0", "@vue/cli-plugin-eslint": "^3.10.0", "@vue/cli-plugin-pwa": "^3.10.0", - "@vue/cli-plugin-unit-jest": "^3.10.0", - "@vue/cli-service": "^3.10.0", + "@vue/cli-plugin-unit-jest": "4.1.2", + "@vue/cli-service": "4.1.2", "@vue/eslint-config-prettier": "^5.0.0", "@vue/test-utils": "1.0.0-beta.29", - "babel-cli": "6.26.0", - "babel-core": "7.0.0-bridge.0", "babel-eslint": "^10.0.1", - "babel-jest": "^23.6.0", + "babel-jest": "24.9.0", "browserstack-local": "1.4.2", "chai": "^4.2.0", "chai-string": "^1.5.0", "chromedriver": "78.0.1", - "copy-webpack-plugin": "5.0.4", + "copy-webpack-plugin": "5.1.1", "cross-env": "^5.2.0", "csp-webpack-plugin": "^2.0.2", "eslint": "^5.16.0", @@ -110,10 +114,21 @@ "numeral": "^2.0.6", "prettier": "^1.18.2", "sass": "^1.18.0", - "sass-loader": "^7.1.0", + "sass-loader": "8.0.0", "simsala": "0.0.18", - "stylelint-config-standard": "^18.2.0", - "vue-template-compiler": "^2.6.10" + "stylelint": "12.0.1", + "stylelint-config-standard": "19.0.0", + "stylelint-webpack-plugin": "1.1.2", + "vue-template-compiler": "^2.6.10", + "webpack": "4.41.5" + }, + "husky": { + "hooks": { + "pre-push": "yarn lint --no-fix" + } + }, + "resolutions": { + "stylelint-webpack-plugin": "1.1.2" }, "engines": { "node": ">=10.13.0" @@ -124,11 +139,5 @@ "repository": { "type": "git", "url": "git+https://github.com/luniehq/lunie.git" - }, - "resolutions": { - "braces": ">=2.3.1", - "https-proxy-agent": ">=3.0.0", - "handlebars": ">=4.5.3", - "serialize-javascript": ">=2.1.1" } } diff --git a/src/ActionModal/components/ActionModal.vue b/src/ActionModal/components/ActionModal.vue index de89b0ee53..cdf44a7cf7 100644 --- a/src/ActionModal/components/ActionModal.vue +++ b/src/ActionModal/components/ActionModal.vue @@ -17,9 +17,9 @@ close
- {{ - requiresSignIn ? `Sign in required` : title - }} + + {{ requiresSignIn ? `Sign in required` : title }} + - {{ - network.stakingDenom | viewDenom - }} + + {{ network.stakingDenom | viewDenom }} + @@ -138,7 +138,7 @@
@@ -294,6 +294,7 @@ import { between, requiredIf } from "vuelidate/lib/validators" import { track } from "scripts/google-analytics" import { UserTransactionAdded } from "src/gql" import config from "src/../config" +import * as Sentry from "@sentry/browser" import ActionManager from "../utils/ActionManager" @@ -469,6 +470,21 @@ export default { }, prettyIncludedHeight() { return prettyInt(this.includedHeight) + }, + // TODO lets slice this monstrocity + context() { + return { + url: this.network.api_url, + networkId: this.network.id, + chainId: this.network.chain_id, + connected: this.connected, + userAddress: this.session.address, + rewards: this.rewards, + totalRewards: this.overview.totalRewards, + bondDenom: this.network.stakingDenom, + isExtensionAccount: this.isExtensionAccount, + account: this.overview.accountInformation + } } }, watch: { @@ -480,15 +496,18 @@ export default { this.selectedSignMethod = signMethods[0].value } } + }, + context: { + immediate: true, + handler(context) { + this.actionManager.setContext(context) + } } }, created() { this.$apollo.skipAll = true }, updated: function() { - // TODO do we need to set the context on every update of the component? - const context = this.createContext() - this.actionManager.setContext(context) if ( (this.title === "Withdraw" || this.step === "fees") && this.$refs.next @@ -497,21 +516,6 @@ export default { } }, methods: { - createContext() { - return { - url: this.network.api_url, // state.connection.externals.node.url, - networkId: this.network.id, // state.connection.lastHeader.chain_id, - chainId: this.network.chain_id, // state.connection.lastHeader.chain_id, - connected: this.connected, - userAddress: this.session.address, - rewards: this.rewards, // state.distribution.rewards, - totalRewards: this.overview.totalRewards, // getters.totalRewards, - delegations: this.delegations, // state.delegates.delegates, - bondDenom: this.network.stakingDenom, // getters.bondDenom, - isExtensionAccount: this.isExtensionAccount, - account: this.overview.accountInformation - } - }, confirmModalOpen() { let confirmResult = false if (this.session.currrentModalOpen) { @@ -618,7 +622,7 @@ export default { this.gasEstimate = await this.actionManager.simulate(memo) } else { this.gasEstimate = await this.actionManager.simulateTxAPI( - this.createContext(), + this.context, type, properties, memo @@ -656,8 +660,9 @@ export default { if (!this.useTxService) { hashResult = await this.actionManager.send(memo, feeProperties) } else { + await this.$apollo.queries.overview.refetch() hashResult = await this.actionManager.sendTxAPI( - this.createContext(), + this.context, type, memo, properties, @@ -668,8 +673,8 @@ export default { const { hash } = hashResult this.txHash = hash this.step = inclusionStep - } catch ({ message }) { - this.onSendingFailed(message) + } catch (error) { + this.onSendingFailed(error) } }, onTxIncluded() { @@ -683,10 +688,17 @@ export default { this.$emit(`txIncluded`) this.$apollo.queries.overview.refetch() }, - onSendingFailed(message) { + onSendingFailed(error) { + Sentry.withScope(scope => { + scope.setExtra("signMethod", this.selectedSignMethod) + scope.setExtra("transactionData", this.transactionData) + scope.setExtra("gasEstimate", this.gasEstimate) + scope.setExtra("gasPrice", this.gasPrice) + Sentry.captureException(error) + }) this.step = signStep - this.submissionError = `${this.submissionErrorPrefix}: ${message}.` - this.trackEvent(`event`, `failed-submit`, this.title, message) + this.submissionError = `${this.submissionErrorPrefix}: ${error.message}.` + this.trackEvent(`event`, `failed-submit`, this.title, error.message) this.$apollo.queries.overview.refetch() }, async connectLedger() { @@ -722,7 +734,6 @@ export default { overview(networkId: $networkId, address: $address) { totalRewards liquidStake - totalStake accountInformation { accountNumber sequence @@ -754,11 +765,8 @@ export default { query NetworkActionModal($networkId: String!) { network(id: $networkId) { id - testnet stakingDenom chain_id - rpc_url - api_url action_send action_claim_rewards action_delegate @@ -782,39 +790,6 @@ export default { return data.network } }, - delegations: { - query: gql` - query DelegationsActionModal( - $networkId: String! - $delegatorAddress: String! - ) { - delegations( - networkId: $networkId - delegatorAddress: $delegatorAddress - ) { - amount - validator { - operatorAddress - } - } - } - `, - skip() { - /* istanbul ignore next */ - return !this.session.address - }, - variables() { - /* istanbul ignore next */ - return { - networkId: this.networkId, - delegatorAddress: this.session.address - } - }, - update(data) { - /* istanbul ignore next */ - return data.delegations - } - }, $subscribe: { userTransactionAdded: { variables() { @@ -842,7 +817,7 @@ export default { this.onTxIncluded() } else { /* istanbul ignore next */ - this.onSendingFailed(log) + this.onSendingFailed(new Error(log)) } } this.txHash = null diff --git a/src/ActionModal/components/DelegationModal.vue b/src/ActionModal/components/DelegationModal.vue index 68181799e6..dea82f7a47 100644 --- a/src/ActionModal/components/DelegationModal.vue +++ b/src/ActionModal/components/DelegationModal.vue @@ -269,13 +269,11 @@ export default { return this.fromSelectedIndex !== `0` } }, - mounted() { - this.$apollo.queries.balance.refetch() - this.$apollo.queries.delegations.refetch() - }, methods: { open() { this.$refs.actionModal.open() + this.$apollo.queries.balance.refetch() + this.$apollo.queries.delegations.refetch() }, validateForm() { this.$v.$touch() @@ -398,6 +396,7 @@ export default { } } `, + fetchPolicy: "cache-first", variables() { /* istanbul ignore next */ return { @@ -424,11 +423,11 @@ export default { return !this.address }, query: UserTransactionAdded, - result({ data }) { + result() { /* istanbul ignore next */ - if (data.userTransactionAdded.success) { - this.$apollo.queries.delegations.refetch() - } + this.$apollo.queries.balance.refetch() + /* istanbul ignore next */ + this.$apollo.queries.delegations.refetch() } } } diff --git a/src/ActionModal/components/ModalWithdrawRewards.vue b/src/ActionModal/components/ModalWithdrawRewards.vue index fc033e335e..6a1be96f12 100644 --- a/src/ActionModal/components/ModalWithdrawRewards.vue +++ b/src/ActionModal/components/ModalWithdrawRewards.vue @@ -63,7 +63,9 @@ export default { } }, totalRewards() { - return this.rewards.reduce((sum, { amount }) => sum + Number(amount), 0) + return this.rewards + .reduce((sum, { amount }) => sum + Number(amount), 0) + .toFixed(6) }, notifyMessage() { return { @@ -116,6 +118,7 @@ export default { } } `, + fetchPolicy: "cache-first", variables() { return { networkId: this.network diff --git a/src/ActionModal/components/SendModal.vue b/src/ActionModal/components/SendModal.vue index 8019ca101a..d66e73f304 100644 --- a/src/ActionModal/components/SendModal.vue +++ b/src/ActionModal/components/SendModal.vue @@ -134,6 +134,7 @@ import ActionModal from "./ActionModal" import transaction from "../utils/transactionTypes" import { toMicroDenom } from "src/scripts/common" import config from "src/../config" +import { UserTransactionAdded } from "src/gql" const defaultMemo = "(Sent via Lunie)" @@ -189,6 +190,9 @@ export default { } } }, + mounted() { + this.$apollo.queries.balance.refetch() + }, methods: { open() { this.$refs.actionModal.open() @@ -280,6 +284,26 @@ export default { denom: this.denom } } + }, + $subscribe: { + userTransactionAdded: { + variables() { + /* istanbul ignore next */ + return { + networkId: this.network, + address: this.userAddress + } + }, + skip() { + /* istanbul ignore next */ + return !this.userAddress + }, + query: UserTransactionAdded, + result() { + /* istanbul ignore next */ + this.$apollo.queries.balance.refetch() + } + } } } } diff --git a/src/ActionModal/components/UndelegationModal.vue b/src/ActionModal/components/UndelegationModal.vue index 7812ece1c6..d82c74fd07 100644 --- a/src/ActionModal/components/UndelegationModal.vue +++ b/src/ActionModal/components/UndelegationModal.vue @@ -124,6 +124,7 @@ import TmFormMsg from "src/components/common/TmFormMsg" import transaction from "../utils/transactionTypes" import { toMicroDenom } from "src/scripts/common" import { formatBech32, validatorEntry } from "src/filters" +import { UserTransactionAdded } from "src/gql" export default { name: `undelegation-modal`, @@ -266,6 +267,7 @@ export default { methods: { open() { this.$refs.actionModal.open() + this.$apollo.queries.delegations.refetch() }, validateForm() { this.$v.$touch() @@ -331,6 +333,7 @@ export default { } } `, + fetchPolicy: "cache-first", variables() { /* istanbul ignore next */ return { @@ -363,6 +366,27 @@ export default { /* istanbul ignore next */ return data.validators } + }, + + $subscribe: { + userTransactionAdded: { + variables() { + /* istanbul ignore next */ + return { + networkId: this.network, + address: this.userAddress + } + }, + skip() { + /* istanbul ignore next */ + return !this.userAddress + }, + query: UserTransactionAdded, + result() { + /* istanbul ignore next */ + this.$apollo.queries.delegations.refetch() + } + } } } } diff --git a/src/ActionModal/utils/ActionManager.js b/src/ActionModal/utils/ActionManager.js index b31926890e..65bb1d870a 100644 --- a/src/ActionModal/utils/ActionManager.js +++ b/src/ActionModal/utils/ActionManager.js @@ -200,7 +200,7 @@ export default class ActionManager { if (result.success) { return { hash: result.hash } } else { - throw Error("Broadcast was not successfull: " + result.error) + throw Error("Broadcast was not successful: " + result.error) } } diff --git a/src/components/common/AppMenu.vue b/src/components/common/AppMenu.vue index e8d58e7e58..12cae081a5 100644 --- a/src/components/common/AppMenu.vue +++ b/src/components/common/AppMenu.vue @@ -1,13 +1,27 @@ - diff --git a/src/components/staking/PageValidators.vue b/src/components/staking/PageValidators.vue index db686a6960..47b0286ab1 100644 --- a/src/components/staking/PageValidators.vue +++ b/src/components/staking/PageValidators.vue @@ -12,13 +12,13 @@ value="All" class="btn-radio secondary" :type="!activeOnly ? `active` : `secondary`" - @click.native="activeOnly = !activeOnly" + @click.native="activeOnly = false" /> diff --git a/src/components/staking/TableValidators.vue b/src/components/staking/TableValidators.vue index 5f8bb227f6..abb36d3895 100644 --- a/src/components/staking/TableValidators.vue +++ b/src/components/staking/TableValidators.vue @@ -29,7 +29,6 @@