diff --git a/.aws/first.sh b/.aws/first.sh new file mode 100644 index 0000000000..c2d78fbbd5 --- /dev/null +++ b/.aws/first.sh @@ -0,0 +1,67 @@ +#!/bin/bash + +PASSWORD=1234567890 +ACCOUNT=main_account +PORT=26657 +API_PORT=8080 +NETWORK=testnet +AMOUNT=100stake + +# first of all remove old genesis, we do not want other node to boot with the wrong stuff +aws s3 rm s3://cosmos-gaia/genesis.json + +# Initialize local node with an account name and a chain +./gaiad init --home . --moniker ${ACCOUNT} --chain-id ${NETWORK} +NODEID=$(./gaiad tendermint show-node-id --home .) + +# Create our main account and add it to the genesis with a lot of money +echo ${PASSWORD} | ./gaiacli keys add ${ACCOUNT} --home . > main_node.log +./gaiad add-genesis-account $(./gaiacli keys show ${ACCOUNT} --home . --address) 150000stake,100000photino,123cococoin --home . + +echo ${PASSWORD} | ./gaiad gentx --name ${ACCOUNT} --home . --home-client . +./gaiad collect-gentxs --home . + +# Make our genesis avaialable to the secondary nodes +aws s3 cp config/genesis.json s3://cosmos-gaia/genesis.json + +# boot proper nodes in reachable detached sessions +screen -dmS gaia ./gaiad start --home . +screen -dmS rest ./gaiacli rest-server --laddr tcp://0.0.0.0:${API_PORT} --home . --node http://localhost:${PORT} --chain-id ${NETWORK} --trust-node true + +# get my address to use it as source of richness for others +ADDRESS=$(./gaiacli keys show ${ACCOUNT} --home . --address) + +while true +do + # Is anyone asking for money + LIST=$(aws s3 ls s3://cosmos-gaia/addresses/) + if [[ -n "${LIST}" ]]; + then + # TODO: SRE team is working on a clean solution. + # This hacky version is temporary and will be replaced by a stargate running on a separate machine + # Remove this logic as soon as we put back the deploy-gaia automation + + # Check if a stargate is locally running + PID=$(lsof -ti tcp:${API_PORT}) + if [[ -n "${PID}" ]]; + then + # we cannot use gaiacli while the rest server is running, it locks the resources + kill -9 ${PID} + fi + + echo ${LIST} | while IFS= read -r row || [[ -n "$row" ]]; do + # for every file in the list pick the address and give money to it, then delete the file + DESTINATION=$(echo $row | awk '{print $4}') + + # Just in case we were running this command with rest-server switched on, get again the address + ADDRESS=$(./gaiacli keys show ${ACCOUNT} --home . --address) + echo ${PASSWORD} | ./gaiacli tx send --home . --from ${ADDRESS} --amount=${AMOUNT} --to=${DESTINATION} --chain-id=${NETWORK} + + # Remove this address from the ones that needs money + aws s3 rm s3://cosmos-gaia/addresses/${DESTINATION} + done + + #restore the rest server + screen -dmS rest ./gaiacli rest-server --laddr tcp://0.0.0.0:${API_PORT} --home . --node http://localhost:${PORT} --chain-id ${NETWORK} --trust-node true + fi +done diff --git a/.aws/others.sh b/.aws/others.sh new file mode 100644 index 0000000000..3aaba423ea --- /dev/null +++ b/.aws/others.sh @@ -0,0 +1,50 @@ +#!/bin/bash + +PASSWORD=1234567890 +ACCOUNT=operator_account +PORT=26656 +# TODO: hardcoded temporary, this will become a parameter coming from the first ECS instance +MAINNODEID=d08c69fa85969f3d0173f23aadc40268559d0f66 +MAINNODEIP=172.31.35.89 +MAINACCOUNT=main_account +NETWORK=testnet +VALIDATOR_AMOUNT=10stake + +# Initialize local node with a secondary account +./gaiad init --home . --moniker ${ACCOUNT} --chain-id ${NETWORK} + +GENESIS=`aws s3 ls s3://cosmos-gaia/genesis.json | grep genesis.json` +while [[ -z "$GENESIS" ]]; do + sleep 3s + ISTHERE=`aws s3 ls s3://cosmos-gaia/genesis.json | grep genesis.json` +done +aws s3 cp s3://cosmos-gaia/genesis.json config/genesis.json + +# GET Genesis file into config/genesis.json +NODEID=$(./gaiad tendermint show-node-id --home .) + +# boot referring to the remote node +screen -dmS gaia ./gaiad start --home . --p2p.laddr=tcp://0.0.0.0:$((PORT)) --address=tcp://0.0.0.0:$((PORT+1)) --rpc.laddr=tcp://0.0.0.0:$((PORT+2)) --p2p.persistent_peers="$MAINNODEID@$MAINNODEIP:$((PORT))" + +# get the key to make my node validator +PUBKEY=$(./gaiad tendermint show-validator --home .) +echo ${PASSWORD} | ./gaiacli keys add ${ACCOUNT} --home . > secondary_node.log +ADDRESS=$(./gaiacli keys show ${ACCOUNT} --home . --address) +echo ${PUBKEY} > ./${ADDRESS} + +# ask money by declaring my node +aws s3 cp ${ADDRESS} s3://cosmos-gaia/addresses/${ADDRESS} + +poor=true +while ${poor} +do + # query my account to check if I'm still poor + ACCOUNT_INFO=$(./gaiacli query account ${ADDRESS} --chain-id ${NETWORK} --trust-node --home .) + if [[ ${ACCOUNT_INFO} == *"auth/Account"* ]]; then + echo "Address funded, thanks main node!" + poor=false + fi + sleep 3s +done + +echo ${PASSWORD} | ./gaiacli tx staking create-validator --home . --from ${ACCOUNT} --amount=${VALIDATOR_AMOUNT} --pubkey=${PUBKEY} --address-delegator=${ADDRESS} --moniker=${ACCOUNT} --chain-id=${NETWORK} --commission-max-change-rate=0 --commission-max-rate=0 --commission-rate=0 --min-self-delegation=1 -json diff --git a/.circleci/config.yml b/.circleci/config.yml index de87fb03df..1a7935da67 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,138 +1,237 @@ -version: 2 +version: 2.1 + +# Here we define all the paths and versions of images we want to play with +aliases: + # Define paths and never think about them again + - &GAIA /tmp/gaia + - &WORKSPACE /tmp/voyager + - &DIST /tmp/voyager/app/dist + # Pick docker versions here only, then use the aliases in the executors definition + - &docker-node tendermintdev/voyager_node + - &docker-browsers tendermintdev/voyager_node_browser + - &docker-go circleci/golang:1.11 + - &docker-deploy tendermintdev/website_deployment + +# reusable commands +commands: + yarn-install: + description: "[YARN] update and install" + steps: + - restore_cache: + keys: + - v3-dependencies-root-{{ checksum "package.json" }} + - v3-dependencies-root- -jobs: - # Build Gaia from the SDK source code specified by tasks/build/Gaia/COMMIT.sh. - buildGaia: + - run: yarn install + - save_cache: + paths: + - yarn.lock + - node_modules + key: v3-dependencies-root-{{ checksum "package.json" }} + + sync: + parameters: + dist_path: + type: string + steps: + - run: + name: Set default environment variables + command: | + cd && touch $BASH_ENV + + if [ "${CIRCLE_BRANCH}" == "master" ]; then + echo 'export INFRA_PATH=iac/conf/websites/prod/${CIRCLE_PROJECT_REPONAME}' >> $BASH_ENV + echo 'export DEPLOYMENT_ENV=${CIRCLE_PROJECT_REPONAME}' >> $BASH_ENV + echo 'export GIT_BRANCH=${CIRCLE_BRANCH}' >> $BASH_ENV + else + echo 'export INFRA_PATH=iac/conf/websites/dev/${CIRCLE_PROJECT_REPONAME}-staging.interblock.io' >> $BASH_ENV + echo 'export DEPLOYMENT_ENV=${CIRCLE_PROJECT_REPONAME}-staging.interblock.io' >> $BASH_ENV + echo 'export GIT_BRANCH=${CIRCLE_BRANCH}' >> $BASH_ENV + fi + - run: + name: Set the terragrunt iam role + command: | + source $BASH_ENV + echo "role_arn = `chamber read $DEPLOYMENT_ENV terragrunt_iam_role -q`" >> /root/.aws/config + - run: + name: Run terraform plan + command: | + source $BASH_ENV + git clone git@github.com:tendermint/devops.git && cd devops + git checkout $GIT_BRANCH + cd $INFRA_PATH + terragrunt plan + terragrunt output -json > ~/project/terraform_output + - run: + name: Sync dist folder to s3 bucket + command: | + export BUCKET_NAME=`cat terraform_output | jq --raw-output '.website_s3_bucket.value'` + cd << parameters.dist_path >> + echo "deployment job ID = $CIRCLE_BUILD_NUM
" >> version.html + echo "deployment job URL = $CIRCLE_BUILD_URL
" >> version.html + chamber exec $DEPLOYMENT_ENV -- aws s3 sync . s3://$BUCKET_NAME --profile terraform --delete + - run: + name: Invalidate the cloudfront distribution + command: | + export DISTRIBUTION_ID=`cat terraform_output | jq --raw-output '.distribution_id.value'` + chamber exec $DEPLOYMENT_ENV -- aws cloudfront create-invalidation --distribution-id $DISTRIBUTION_ID \ + --profile terraform \ + --path "/*" + +# a reusable executor +executors: + web: + docker: + - image: *docker-browsers + working_directory: *WORKSPACE + + node: + docker: + - image: *docker-node + working_directory: *WORKSPACE + + go: + docker: + - image: *docker-go + working_directory: *GAIA + + web_deploy: docker: - - image: circleci/golang + - image: *docker-deploy + environment: + BASH_ENV: /root/.bashrc + AWS_REGION: us-east-1 +jobs: + build: + executor: web steps: - checkout + - yarn-install + - run: | + mkdir -p app/dist + CIRCLECI=true yarn build:ui + - store_artifacts: + path: *DIST + - persist_to_workspace: + root: *WORKSPACE + paths: + - app/dist + # Build Gaia from the SDK source code specified by tasks/build/Gaia/COMMIT.sh. + buildGaia: + executor: go + steps: + - checkout - restore_cache: key: v7-Gaia-{{ checksum "tasks/build/Gaia/COMMIT.sh" }} # If Gaia isn't in the cache then build it. - run: | - if [ ! -d ~/target ]; then + if [ ! -d /tmp/gaia ]; then cd tasks/build/Gaia . COMMIT.sh - TARGET=~/target ./build.sh + TARGET=/tmp/gaia ./build.sh fi - - save_cache: key: v7-Gaia-{{ checksum "tasks/build/Gaia/COMMIT.sh" }} paths: - - ~/target - + - *GAIA - persist_to_workspace: - root: ~/target + root: . paths: - "*" + - store_artifacts: + path: builds/Gaia/linux_amd64/* changelogUpdated: - docker: - - image: circleci/node:10.13.0-browsers - + executor: node steps: - checkout - - run: tasks/changelog-changed-check.sh - testUnit: - docker: - - image: circleci/node:10.13.0-browsers - + lint: + executor: node steps: - checkout - - - restore_cache: - keys: - - v3-dependencies-root-{{ checksum "package.json" }} - - v3-dependencies-root- - - - run: yarn install - - - save_cache: - paths: - - yarn.lock - - node_modules - key: v3-dependencies-root-{{ checksum "package.json" }} - + - yarn-install - run: yarn run lint + testUnit: + executor: web + steps: + - checkout + - yarn-install - run: name: Test command: yarn run test:unit no_output_timeout: 120 - - run: command: bash <(curl -s https://codecov.io/bash) -t $CODECOV_TOKEN when: on_success - testE2e: - docker: - - image: circleci/node:10.13.0-browsers - - environment: - - BINARY_PATH: "/home/circleci/project/builds/Gaia/linux_amd64/gaiacli" - - NODE_BINARY_PATH: "/home/circleci/project/builds/Gaia/linux_amd64/gaiad" - + security: + executor: web steps: - checkout - - - attach_workspace: - at: builds/Gaia - - - restore_cache: - keys: - - v2-dependencies-root-{{ checksum "package.json" }} - - v2-dependencies-root- - - - run: yarn install - - - save_cache: - paths: - - yarn.lock - - node_modules - key: v2-dependencies-root-{{ checksum "package.json" }} - - run: - name: Test - command: yarn run test:e2e - no_output_timeout: 120 + name: Audit + command: | + set +e - - store_artifacts: - path: testArtifacts - when: on_fail + SUMMARY="$(yarn audit | grep Severity)" + VULNERABILITIES=".*(High|Critical).*" + + if [[ $SUMMARY =~ $VULNERABILITIES ]]; then + echo "Unsafe dependencies found: $SUMMARY" >&2 + exit 1 + fi + echo "Your dependencies are secure enough: $SUMMARY" + exit 0 + + # testE2e: + # executor: web + # environment: + # - BINARY_PATH: "/tmp/gaia/builds/Gaia/linux_amd64/gaiacli" + # - NODE_BINARY_PATH: "/tmp/gaia/builds/Gaia/linux_amd64/gaiad" + # steps: + # - checkout + # - attach_workspace: + # at: *GAIA + # - yarn-install + # - run: + # name: Test + # command: yarn run test:e2e + # no_output_timeout: 120 + # - store_artifacts: + # path: testArtifacts + # when: on_fail + + deploy2s3: + executor: web_deploy + steps: + - attach_workspace: + at: *WORKSPACE + - sync: + dist_path: *DIST # Create release. release: docker: - - image: circleci/node:10.13.0 - + - image: *docker-node steps: - checkout - - - restore_cache: - keys: - - v2-dependencies-root-{{ checksum "package.json" }} - - v2-dependencies-root- - - - run: yarn install + - yarn-install - run: node tasks/createReleasePR.js # Publish the release to GitHub. publish: docker: - - image: circleci/node:10.13.0 - + - image: *docker-node steps: - checkout - - attach_workspace: at: builds/Gaia - - run: command: | mostRecentTag=$(git describe --abbrev=0 --tags) @@ -145,34 +244,28 @@ jobs: git tag -d release-candidate git push --delete bot release-candidate - sudo tasks/build/installWine.sh + npm -g uninstall yarn ; npm -g install yarn@1.13.0 yarn install - # download network configs - # skip as this will overwrite game of stakes - # tasks/build/testnets/build.sh - - # build Voyager - node tasks/build/build.js - - # test linux build - tar -zxvf ./builds/Voyager/Cosmos_Voyager-*-Linux.tar.gz - yarn test:exe "./Cosmos Voyager" - node tasks/publish.js fi workflows: version: 2 - - gaia-test-and-publish: + build-and-deploy: jobs: + # Static checks before - changelogUpdated: filters: branches: ignore: release - - buildGaia: + - security: + filters: + branches: + ignore: release + + - lint: filters: branches: ignore: release @@ -182,26 +275,49 @@ workflows: branches: ignore: release - - testE2e: + - build: + # no heavy lifting if other portion fails requires: - - buildGaia + - security + - lint + + - buildGaia + - deploy2s3: + requires: + - testUnit + - build filters: branches: - ignore: release + only: + - develop + - master + + # - testE2e: + # requires: + # - buildGaia + # filters: + # branches: + # ignore: release - publish: requires: - changelogUpdated - - buildGaia + - build - testUnit - - testE2e + # - testE2e filters: branches: only: develop + # Every UTC midnight we go on develop and release release: - jobs: - - release: + triggers: + - schedule: + cron: "15 10 * * *" filters: branches: - only: release + only: + - develop + - sabau/auto-release-PR-first-step + jobs: + - release diff --git a/.eslintignore b/.eslintignore index da35ca818b..72fb8925d3 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,9 +1,8 @@ /archive /app/dist/ /app/networks/ -/builds/ -/tasks/builds/* +/**/builds/* /testArtifacts /test/unit/coverage/ -/.vscode/settings.json +/.vscode/* /docs/cosmos-voyager/ diff --git a/.eslintrc.js b/.eslintrc.js index ae81735a9a..dbd8e9f51b 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -21,6 +21,13 @@ module.exports = { "no-unused-vars": "error", quotes: ["error", "backtick"], "no-var": "error", - "prettier/prettier": "error" + "prettier/prettier": "error", + "prefer-const": [ + "error", + { + destructuring: "all", + ignoreReadBeforeAssign: false + } + ] } } diff --git a/.gitignore b/.gitignore index bb0bb489ea..d02d6b6349 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ .DS_Store app/dist builds/* -task/builds +tasks/builds coverage node_modules npm-debug.log @@ -15,8 +15,5 @@ testArtifacts/* app/networks/local-testnet/* docs/cosmos-voyager .idea/* -server_dev.key -server_dev.crt -Cosmos_* -app/networks/* -app/package.json \ No newline at end of file +*.crt +*.key diff --git a/.prettierignore b/.prettierignore index 3d0ef18b46..3cb326f6e1 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,6 +1,7 @@ /app/dist/ -/builds/ /package.json /test/unit/coverage/ /test/unit/tmp/ -/docs/cosmos-voyager/ \ No newline at end of file +/docs/cosmos-voyager/ +/**/builds/* +/.vscode/* \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f71a075c8..caff292a0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,9 +7,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] -## [0.10003.3] - 2019-01-16 - -## [0.10003.2] - 2019-01-16 +## [0.10003.4] - 2019-02-14 ### Added @@ -60,6 +58,18 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - [\#1660](https://github.com/cosmos/voyager/issues/1660) Add parameters and pool to store @fedekunze - [\#1739](https://github.com/cosmos/voyager/issues/1739) Init jsDoc into project @sabau - [\#1674](https://github.com/cosmos/voyager/issues/1674) Add PageProfile component with shared styles for validator and proposal profiles @jbibla +- [\#1806](https://github.com/cosmos/voyager/issues/1806) CircleCI security check in dependencies with yarn audit @sabau +- [\#1804](https://github.com/cosmos/voyager/issues/1804) Moved Voyager to the web @faboweb +- [\#1835](https://github.com/cosmos/voyager/issues/1835) allow user to use different signing methods @faboweb +- [\#1833](https://github.com/cosmos/voyager/issues/1833) Prerequisites to allow continuous integration @sabau +- [\#1338](https://github.com/cosmos/voyager/issues/1338) Add Ledger Nano S support for signing transactions @fedekunze +- [\#1869](https://github.com/cosmos/voyager/issues/1869) Added PageNetwork @jbibla +- [\#1894](https://github.com/cosmos/voyager/issues/1894) Added favicons for all the browsers and devices @jbibla +- [\#1865](https://github.com/cosmos/voyager/issues/1865) Added Vuex blocks module @sabau +- [\#1928](https://github.com/cosmos/voyager/issues/1928) Added Browserstack reference to README @sabau +- [\#1918](https://github.com/cosmos/voyager/issues/1918) added message to log in when sending transactions and the user is not authenticated @fedekunze +- [\#1866](https://github.com/cosmos/voyager/issues/1866) Added blocks to network page and a page for viewing individual blocks @jbibla +- Added development mode warning @faboweb ### Changed @@ -102,6 +112,19 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - [\#1379](https://github.com/cosmos/voyager/issues/1379) Changed some tests so they don't display errors on the console to better identify real errors @faboweb - [\#1792](https://github.com/cosmos/voyager/pull/1792) removed mocked demo mode @fedekunze - [\#1720](https://github.com/cosmos/voyager/issues/1720) Time format from 12 to 24h @sabau +- [\#1802](https://github.com/cosmos/voyager/issues/1802) Enable prefer-const eslint rule @sabau +- [\#1688](https://github.com/cosmos/voyager/issues/1688) Moved from every page to TmPage the connected, loading, empty data and search features @sabau +- [\#1588](https://github.com/cosmos/voyager/issues/1588) 404 page updates @jbibla +- [\#1737](https://github.com/cosmos/voyager/issues/1737) Updates to validator and proposal pages @jbibla +- [\#1846](https://github.com/cosmos/voyager/issues/1846) Allow node endpoints to be set from the URL @faboweb +- [\#1221](https://github.com/cosmos/voyager/issues/1221) individual linter check on GitHub @faboweb +- [\#1855](https://github.com/cosmos/voyager/issues/1855) skip gaia build if already built that hash @sabau +- [\#1922](https://github.com/cosmos/voyager/issues/1922) removed font awesome @jbibla +- [\#1916](https://github.com/cosmos/voyager/pull/1916) redirect to session modal when user hasn't logged in @fedekunze +- [\#1836](https://github.com/cosmos/voyager/issues/1836) remove back button @fedekunze +- [\#1948](https://github.com/cosmos/voyager/pull/1948) changed PR template @fedekunze +- [\#1946](https://github.com/cosmos/voyager/pull/1946) removed proposer_address raw hex @jbibla +- [\#1967](https://github.com/cosmos/voyager/pull/1967) bundle analyzer changed from dynamic to static report @sabau ### Fixed @@ -131,8 +154,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - [\#1617](https://github.com/cosmos/voyager/pull/1617) Fixed send buttons not clickable @faboweb - [\#1303](https://github.com/cosmos/voyager/issues/1303) Fixed spamming of setSubscription @faboweb - [\#1603](https://github.com/cosmos/voyager/issues/1603) Fixed inactive sidebar links @jbibla -- [\#1614](https://github.com/cosmos/voyager/issues/1614) Fixed an error that prevented a proposal to be updated optimisticaly after a successful deposit or vote @fedekunze -- [\#1386](https://github.com/cosmos/voyager/issues/1386) Cleaned up onboarding @jbibla +- [\#1614](https://github.com/cosmos/voyager/issues/1614) Fixed an error that prevented a proposal to be updated optimistically after a successful deposit or vote @fedekunze +- [\#1386](https://github.com/cosmos/voyager/issues/1386) Cleaned up on-boarding @jbibla - [\#1640](https://github.com/cosmos/voyager/issues/1640) Hide the table proposals when there are no available ones @fedekunze - [\#1640](https://github.com/cosmos/voyager/issues/1640) Fixed an error that prevented the search bar to be displayed using `Ctrl+F` @fedekunze - Fixed testnet config build script @faboweb @@ -140,7 +163,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - [\#1687](https://github.com/cosmos/voyager/issues/1687) Removing cached state if decrypting fails. @faboweb - [\#1662](https://github.com/cosmos/voyager/issues/1662) Fixed wrong node version in readme @faboweb [\#1642](https://github.com/cosmos/voyager/issues/1642) Refactor table styles and fixed bad aligned headers @faboweb -- [\#1677](https://github.com/cosmos/voyager/issues/1677) Fixed inconstistent status colors on proposals @fedekunze +- [\#1677](https://github.com/cosmos/voyager/issues/1677) Fixed inconsistent status colors on proposals @fedekunze - [\#1696](https://github.com/cosmos/voyager/issues/1696) Fixed broken css variables @jbibla - [\#1687](https://github.com/cosmos/voyager/issues/1687) Removing cached state if decrypting fails. @faboweb - [\#1662](https://github.com/cosmos/voyager/issues/1662) Fixed wrong node version in readme @faboweb @@ -151,10 +174,32 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - [\#1572](https://github.com/cosmos/voyager/issues/1572) Fixed scroll bug when switching between tabs @jbibla - [\#1749](https://github.com/cosmos/voyager/issues/1749) Fixed proposal tally update after voting @fedekunze - [\#1765](https://github.com/cosmos/voyager/pull/1765) Fixed proposal deposit update after submitting a deposit @fedekunze +- [\#1791](https://github.com/cosmos/voyager/issue/1791) Fixed a problem with initializing the Voyager config dir @faboweb +- [\#1815](https://github.com/cosmos/voyager/issue/1815) Fixed getters for proposals denominator, reverted to 945803d586b83d65547cd16f4cd5994eac2957ea until interfaces are ready @sabau +- [\#1809](https://github.com/cosmos/voyager/issue/1809) Fixed optimistically updating the header on sending @faboweb - [\#1791](https://github.com/cosmos/voyager/pull/1791) Fixed a problem with initializing the Voyager config dir @faboweb +- [\#1754](https://github.com/cosmos/voyager/pull/1754) Fixed form UX, UI and other miscellaneous styling issues @jbibla - [\#1707](https://github.com/cosmos/voyager/issues/1707) Governance txs are now disabled if the user doesn't hold any min_deposit token @fedekunze - [\#1815](https://github.com/cosmos/voyager/pull/1815) Fixed getters for proposals denominator, reverted to 945803d586b83d65547cd16f4cd5994eac2957ea until interfaces are ready @sabau - Fixed build process @ƒaboweb +- [\#1818](https://github.com/cosmos/voyager/issues/1818) Fixed error on validator loading showing as no validators @faboweb +- Fixed error locations sucked up by Sentry @faboweb +- [\#1815](https://github.com/cosmos/voyager/pull/1785) Fixed small bug on preferences page @jbibla +- [\#1831](https://github.com/cosmos/voyager/issues/1831) Fixed websocket reconnection @faboweb +- [\#1850](https://github.com/cosmos/voyager/pull/1850) Snapshots aligned for unit tests @sabau +- [\#1859](https://github.com/cosmos/voyager/pull/1859) Fix security check in circleci @sabau +- [\#1892](https://github.com/cosmos/voyager/issues/1892) Fix TmSessionImport form validation @faboweb +- Fixed signing issues related to https://github.com/cosmos/cosmos-sdk/issues/3336 @faboweb +- [\#1896](https://github.com/cosmos/voyager/issues/1896) Correctly update balances if account is empty @faboweb +- Fix actionmodal validation @faboweb +- [\#1934](https://github.com/cosmos/voyager/pull/1934) Fix boot process @sabau +- [\#961](https://github.com/cosmos/voyager/issues/961) Mock timezone and keep moment as it is @sabau +- [\#961](https://github.com/cosmos/voyager/issues/961) Mock only the `now` function from Date module @sabau +- Fixed `yarn start` @ƒaboweb +- [\#1955](https://github.com/cosmos/voyager/issues/1955) Fixed local testnet setup @faboweb +- HOT FIX: unit tests failed due to merge @faboweb +- HOT FIX: we fixed develop (replaced contenthash with hash) @jbibla +- Bring back devMode @faboweb ## [0.10.7] - 2018-10-10 diff --git a/Caddyfile b/Caddyfile new file mode 100644 index 0000000000..7c28924dd0 --- /dev/null +++ b/Caddyfile @@ -0,0 +1,13 @@ +localhost:8080 { + cors + + header / { + Access-Control-Allow-Origin "*" + Access-Control-Allow-Methods "OPTIONS, HEAD, GET, POST, PUT, DELETE" + Access-Control-Allow-Headers "*" + } + + proxy / http://localhost:9070/ { + insecure_skip_verify + } +} \ No newline at end of file diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md index d6005d7968..0e9cf7f2d4 100644 --- a/PULL_REQUEST_TEMPLATE.md +++ b/PULL_REQUEST_TEMPLATE.md @@ -1,17 +1,20 @@ Closes #ISSUE -_Description:_ +**Description:** -❤️ Thank you! +Thank you! 🚀 --- - +For contributor: - [ ] Added entries in `CHANGELOG.md` with issue # and GitHub username - [ ] Reviewed `Files changed` in the github PR explorer +- [ ] Attach screenshots of the UI components on the PR description (if applicable) +- [ ] Scope of work approved for big PRs + +For reviewer: + +- [ ] Manually tested the changes on the UI diff --git a/README.md b/README.md index e5fbde647e..bfd1c319eb 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![Cosmos Voyager logo — spaceship blasting off](/app/icons/png/128x128.png) +![Cosmos Voyager logo — spaceship blasting off](/app/static/icons/png/128x128.png) # Cosmos Voyager @@ -43,6 +43,10 @@ cd voyager yarn install ``` +--- + +## Voyager Development + ### Gaia (Cosmos SDK) Since Voyager runs on top of the Cosmos Hub blockchain, we also need to install Gaia (the Cosmos Hub application) and download the supported testnets. @@ -63,7 +67,13 @@ To connect to a testnet, Voyager needs the configuration files of those networks yarn build:testnets ``` -## Voyager Development +### Caddy Proxy + +Currently we need a proxy to enable easy local development. We use [Caddy](https://caddyserver.com). To download run: + +```bash +curl https://getcaddy.com | bash -s personal http.cors +``` ### Active testnets @@ -73,15 +83,40 @@ To run Voyager on the default testnet (if active): yarn start ``` -To run Voyager on a specific testnet you can use the following command. Click [here](https://github.com/cosmos/testnets) for a complete list of the supported official and community testnets. +## Local testnet + +Sometimes you may want to run a local node, i.e. in the case there is no available network. To do so first [Build Gaia](#gaia-cosmos-sdk), then use our automatic script or the manual process to set up your node. + +### Generate SSL certificates + +If you want to have a predictable environment for Voyager please generate some ssl certificates: ```bash -yarn start +openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ + -keyout server_dev.key -out server_dev.crt \ + -subj "/C=US/ST=CA/L=Irvine/O=Acme Inc./CN=localhost" \ + -reqexts v3_req -reqexts SAN -extensions SAN \ + -config \ + <(echo -e ' + [req]\n + distinguished_name=req_distinguished_name\n + [req_distinguished_name]\n + [SAN]\n + subjectKeyIdentifier=hash\n + authorityKeyIdentifier=keyid:always,issuer:always\n + basicConstraints=CA:TRUE\n + subjectAltName=@alt_names + [alt_names] + DNS.1 = localhost + ') ``` -## Local testnet +Afterwards you can use: -Sometimes you may want to run a local node, i.e. in the case there is no available network. To do so first [Build Gaia](#gaia-cosmos-sdk), then use our automatic script or the manual process to set up your node. +```bash +yarn backend:fixed-https +yarn frontend:fixed-https +``` ### Build @@ -136,6 +171,20 @@ Store the gaia version used in your local testnet: ### Deploy +Create the bundle to deploy Voyager you can run: + +```bash +yarn build:ui +``` + +If you want to set a particular Stargate or RPC endpoints + +```bash +STARGATE= RPC= yarn build:ui +``` + +### Local network + Run Voyager for your local testnet: ```bash @@ -152,6 +201,14 @@ This command will build and run several nodes at once on the local testnet. All yarn start local-testnet ``` +### Using Voyager with a custom SDK REST API instance (Stargate) + +A deployed Voyager can be retargeted against a Stargate and Full Node of your choice. Just add the URLs of those to the Voyager URL: + +``` +https://localhost:9080?stargate=https://stargate.com:1234&rpc=https://cool-node.com:6789 +``` + ## Testing If you would like to run all the tests you can run: @@ -176,7 +233,8 @@ yarn watch PageValidator ### End to end tests -End to end (e2e) testing is performed via [`tape`](https://github.com/substack/tape), you can run all of them using: +End to end testing will be soon restored thanks to: [Browserstack](https://www.browserstack.com/) +You can run all of them using: ```bash yarn test:e2e @@ -286,3 +344,7 @@ rm -rf package-lock.json - You get `The network configuration for the network you want to connect to doesn't exist. Have you run "yarn build:testnets" to download the latest configurations?` but you have run `yarn build:testnets`. The symlink between `app/networks` and `builds/testnets` is broken. Try readding the symlink with `cd app && ln -s ../builds/testnets networks`. + +## Thanks + +[![Browserstack](/test/browserstack-logo-600x315.png)](https://www.browserstack.com) diff --git a/app/config.toml b/app/config.toml deleted file mode 100644 index 223ff6c8d9..0000000000 --- a/app/config.toml +++ /dev/null @@ -1,21 +0,0 @@ -# Name of electron app -# Will be used in production builds -name = "Cosmos Voyager" - -# webpack-dev-server port -wds_port = 9080 -lcd_port = 9070 -lcd_port_prod = 9071 -relay_port = 9060 -relay_port_prod = 9061 -default_tendermint_port = 26657 - -default_network = "game_of_stakes_3" -node_lcd = "https://fabo.interblock.io:1317" -node_rpc = "https://fabo.interblock.io:26657" - -google_analytics_uid = "UA-51029217-3" -sentry_dsn = "https://4dee9f70a7d94cc0959a265c45902d84:cbf160384aab4cdeafbe9a08dee3b961@sentry.io/288169" - -# time to wait for a block until node is declared halted -node_halted_timeout = 120000 diff --git a/app/icons/icon.icns b/app/icons/icon.icns deleted file mode 100644 index 4de24e4790..0000000000 Binary files a/app/icons/icon.icns and /dev/null differ diff --git a/app/icons/icon.ico b/app/icons/icon.ico deleted file mode 100644 index b37e5f6668..0000000000 Binary files a/app/icons/icon.ico and /dev/null differ diff --git a/app/index.ejs b/app/index.ejs index 98861f9afd..a9115aea84 100644 --- a/app/index.ejs +++ b/app/index.ejs @@ -1,19 +1,25 @@ + + + + + + Cosmos Voyager - - - - Cosmos Voyager - <% if (htmlWebpackPlugin.options.appModules) { %> - - - <% } %> + + + + + - -
- + <% if (htmlWebpackPlugin.options.appModules) { %> + <% } %> + + + + +
+ \ No newline at end of file diff --git a/app/src/config.js b/app/src/config.js index 7d28535f0e..cbc1dc1d8f 100644 --- a/app/src/config.js +++ b/app/src/config.js @@ -1,11 +1,26 @@ -"use strict" +const dev = process.env.NODE_ENV === `develop` +const stargate = + process.env.STARGATE || + (dev + ? `localhost:8080` + : `https://sntajlxzsg.execute-api.eu-central-1.amazonaws.com/dev/`) -const fs = require(`fs`) -const path = require(`path`) -const toml = require(`toml`) +const rpc = + process.env.RPC || + (dev ? `localhost:26657` : `https://test.voyager.ninja:26657/`) -module.exports = toml.parse( - fs.readFileSync(path.join(__dirname, `../config.toml`), { - encoding: `utf8` - }) -) +const faucet = process.env.FAUCET || `https://faucet.voyager.ninja` + +export default { + name: `Cosmos Voyager`, + default_network: `${dev ? `local-` : ``}testnet`, + denoms: [`stake`, `photino`], + stargate, + rpc, + google_analytics_uid: `UA-51029217-3`, + sentry_dsn: `https://4dee9f70a7d94cc0959a265c45902d84:cbf160384aab4cdeafbe9a08dee3b961@sentry.io/288169`, + node_halted_timeout: 120000, + block_timeout: 10000, + default_gas: 500000, + faucet +} diff --git a/app/src/helpers/url.js b/app/src/helpers/url.js new file mode 100644 index 0000000000..ce01cb10ac --- /dev/null +++ b/app/src/helpers/url.js @@ -0,0 +1,13 @@ +export function getURLParams(window) { + const queries = window.location.search.slice(1).split(`&`) + return queries.reduce((config, current) => { + const [name, value] = current.split(`=`) + if ([`stargate`, `rpc`].includes(name)) { + return { + ...config, + [name]: value + } + } + return config + }, {}) +} diff --git a/app/src/main/addressbook.js b/app/src/main/addressbook.js deleted file mode 100644 index e427ee2a39..0000000000 --- a/app/src/main/addressbook.js +++ /dev/null @@ -1,171 +0,0 @@ -"use strict" - -const fs = require(`fs-extra`) -const { join } = require(`path`) -const axios = require(`axios`) - -const LOGGING = JSON.parse(process.env.LOGGING || `true`) !== false -const FIXED_NODE = process.env.COSMOS_NODE - -module.exports = class Addressbook { - constructor( - config, - configPath, - { persistent_peers = [], onConnectionMessage = () => {} } = {} - ) { - this.peers = [] - this.config = config - this.onConnectionMessage = onConnectionMessage - - // if we define a fixed node, we skip persistence - if (FIXED_NODE) { - this.addPeer(FIXED_NODE) - return - } - - this.addressbookPath = join(configPath, `addressbook.json`) - this.loadFromDisc() - - // add persistent peers to already stored peers - persistent_peers.forEach(peer => this.addPeer(peer)) - - if (persistent_peers.length > 0) { - this.persistToDisc() - } - } - - // adds the new peer to the list of peers - addPeer(peerHost) { - const peerIsKnown = this.peers.find( - peer => peer.host.indexOf(peerHost) !== -1 - ) - - if (!peerIsKnown) { - LOGGING && console.log(`Adding new peer:`, peerHost) - this.peers.push({ - host: peerHost, - // assume that new peers are available - state: `available` - }) - } - } - - loadFromDisc() { - // if there is no address book file yet, there are no peers stored yet - // the file will be created when persisting any peers to disc - let exists = fs.existsSync(this.addressbookPath) - if (!exists) { - this.peers = [] - return - } - let content = fs.readFileSync(this.addressbookPath, `utf8`) - let peers = JSON.parse(content) - this.peers = peers.map(host => ({ - host, - state: `available` - })) - } - - persistToDisc() { - let peers = this.peers - // only remember available nodes - .filter(p => p.state === `available`) - .map(p => p.host) - fs.ensureFileSync(this.addressbookPath) - fs.writeFileSync(this.addressbookPath, JSON.stringify(peers), `utf8`) - } - - // returns an available node or throws if it can't find any - async pickNode() { - let curNode - - if (FIXED_NODE) { - // we skip discovery for fixed nodes as we want to always return the same - // node - curNode = { host: FIXED_NODE } - - // ping fixed node - let alive = await axios - .get( - `http://${FIXED_NODE}:${ - this.config.default_tendermint_port - }/net_info`, - { timeout: 3000 } - ) - .then(() => true, () => false) - if (!alive) - throw Error(`The fixed node you tried to connect to is not reachable.`) - } else { - let availableNodes = this.peers.filter(node => node.state === `available`) - if (availableNodes.length === 0) { - throw Error(`No nodes available to connect to`) - } - // pick a random node - curNode = - availableNodes[Math.floor(Math.random() * availableNodes.length)] - - try { - let peerIP = curNode.host.split(`:`)[0] - await this.discoverPeers(peerIP) - } catch (exception) { - console.log( - `Unable to discover peers from node ${require(`util`).inspect( - curNode - )}: ${exception}` - ) - - this.flagNodeOffline(curNode.host) - return this.pickNode() - } - - // remember the peers of the node and store them in the addressbook - this.persistToDisc() - } - - this.onConnectionMessage(`Picked node: ` + curNode.host) - return `${curNode.host.split(`:`)[0]}:${ - this.config.default_tendermint_port - }` // export the picked node with the correct tendermint port - } - - flagNodeOffline(host) { - let peer = this.peers.find(p => p.host === host) - if (peer) peer.state = `down` - } - - flagNodeIncompatible(host) { - let peer = this.peers.find(p => p.host === host) - if (peer) peer.state = `incompatible` - } - - resetNodes() { - this.peers = this.peers.map(peer => - Object.assign({}, peer, { - state: `available` - }) - ) - } - - async discoverPeers(peerIP) { - this.onConnectionMessage(`Querying node: ${peerIP}`) - - let subPeers = (await axios.get( - `http://${peerIP}:${this.config.default_tendermint_port}/net_info`, - { timeout: 3000 } - )).data.result.peers - - this.onConnectionMessage(`Node ${peerIP} is alive.`) - - let subPeersHostnames = subPeers.map(peer => peer.node_info.listen_addr) - - subPeersHostnames - // add new peers to state - .forEach(subPeerHostname => { - this.addPeer(subPeerHostname) - }) - - if (subPeersHostnames.length > 0) { - this.persistToDisc() - } - } -} diff --git a/app/src/main/index.dev.js b/app/src/main/index.dev.js deleted file mode 100644 index 374b59ba07..0000000000 --- a/app/src/main/index.dev.js +++ /dev/null @@ -1,29 +0,0 @@ -"use strict" - -/** - * This file is used specifically and only for development. It enables the use of ES6+ - * features for the main process and installs `electron-debug` & `vue-devtools`. There - * shouldn't be any need to modify this file, but it can be used to extend your - * development environment. - */ - -/* eslint-disable no-console */ - -// Set babel `env` and install `babel-register` -process.env.BABEL_ENV = `main` - -require(`babel-register`)({ ignore: /node_modules/ }) - -// Install `vue-devtools` -require(`electron`).app.on(`ready`, () => { - let installExtension = require(`electron-devtools-installer`) - installExtension - .default(installExtension.VUEJS_DEVTOOLS) - .then(() => {}) - .catch(err => { - console.log(`Unable to install \`vue-devtools\`: \n`, err) - }) -}) - -// Require `main` process to boot app -require(`./index`) diff --git a/app/src/main/index.js b/app/src/main/index.js deleted file mode 100644 index 94e85d998e..0000000000 --- a/app/src/main/index.js +++ /dev/null @@ -1,699 +0,0 @@ -"use strict" - -const assert = require(`assert`) -let { app, BrowserWindow, ipcMain } = require(`electron`) -let fs = require(`fs-extra`) -const https = require(`https`) -let { join, relative } = require(`path`) -let childProcess = require(`child_process`) -let semver = require(`semver`) -const Sentry = require(`@sentry/node`) -const readline = require(`readline`) -let axios = require(`axios`) - -let { version: pkgVersion } = require(`../../../package.json`) -let addMenu = require(`./menu.js`) -let config = require(`../config.js`) -config.node_lcd = process.env.LCD_URL || config.node_lcd -config.node_rpc = process.env.RPC_URL || config.node_rpc -let LcdClient = require(`../renderer/connectors/lcdClient.js`) -global.config = config // to make the config accessable from renderer -global.config.version = pkgVersion - -require(`electron-debug`)() - -let shuttingDown = false -let mainWindow -let gaiaLiteProcess -let streams = [] -let connecting = true -let chainId -let booted = false -let expectedGaiaCliVersion - -const root = require(`../root.js`) -global.root = root // to make the root accessable from renderer -const networkPath = require(`../network.js`).path - -const lcdHome = join(root, `lcd`) -const WIN = /^win/.test(process.platform) -const DEV = process.env.NODE_ENV === `development` -const TEST = process.env.NODE_ENV === `testing` -global.config.development = DEV || TEST -// TODO default logging or default disable logging? -const LOGGING = JSON.parse(process.env.LOGGING || `true`) !== false -const winURL = DEV - ? `http://localhost:${config.wds_port}` - : `file://${__dirname}/index.html` -const LCD_PORT = DEV ? config.lcd_port : config.lcd_port_prod -const MOCK = - process.env.COSMOS_MOCKED !== undefined - ? JSON.parse(process.env.COSMOS_MOCKED) - : false -global.config.mocked = MOCK // persist resolved mock setting also in config used by view thread -const gaiaVersion = fs - .readFileSync(networkPath + `/gaiaversion.txt`) - .toString() - .split(`-`)[0] -process.env.GAIA_VERSION = gaiaVersion - -let LCD_BINARY_NAME = `gaiacli` + (WIN ? `.exe` : ``) - -function log(...args) { - if (LOGGING) { - console.log(...args) - } -} -function logError(...args) { - if (LOGGING) { - console.log(...args) - } -} - -function logProcess(process, logPath) { - fs.ensureFileSync(logPath) - // Writestreams are blocking fs cleanup in tests, if you get errors, disable logging - if (LOGGING) { - let logStream = fs.createWriteStream(logPath, { flags: `a` }) // 'a' means appending (old data will be preserved) - streams.push(logStream) - process.stdout.pipe(logStream) - process.stderr.pipe(logStream) - } -} - -function handleCrash(error) { - afterBooted(() => { - if (mainWindow) { - mainWindow.webContents.send(`error`, { - message: error - ? error.message - ? error.message - : error - : `An unspecified error occurred` - }) - } - }) -} - -async function shutdown() { - if (shuttingDown) return - - mainWindow = null - shuttingDown = true - - if (gaiaLiteProcess) { - await stopLCD() - } - - return Promise.all( - streams.map(stream => new Promise(resolve => stream.close(resolve))) - ).then(() => { - log(`[SHUTDOWN] Voyager has shutdown`) - }) -} - -function createWindow() { - mainWindow = new BrowserWindow({ - show: false, - minWidth: 320, - minHeight: 480, - width: 1024, - height: 768, - center: true, - title: `Cosmos Voyager`, - darkTheme: true, - titleBarStyle: `hidden`, - backgroundColor: `#15182d`, - webPreferences: { webSecurity: false } - }) - mainWindow.once(`ready-to-show`, () => { - setTimeout(() => { - mainWindow.show() - if (DEV || JSON.parse(process.env.COSMOS_DEVTOOLS || `false`)) { - mainWindow.webContents.openDevTools() - // we need to reload at this point to make sure sourcemaps are loaded correctly - mainWindow.reload() - } - if (DEV) { - mainWindow.maximize() - } - }, 300) - }) - - // start vue app - mainWindow.loadURL(winURL) - - mainWindow.on(`closed`, shutdown) - - // eslint-disable-next-line no-console - log(`mainWindow opened`) - - // handle opening external links in OS's browser - let webContents = mainWindow.webContents - let handleRedirect = (e, url) => { - if (url !== webContents.getURL()) { - e.preventDefault() - require(`electron`).shell.openExternal(url) - } - } - webContents.on(`will-navigate`, handleRedirect) - webContents.on(`new-window`, handleRedirect) - - addMenu(mainWindow) -} - -function startProcess(name, args, env) { - let binPath - if (process.env.BINARY_PATH) { - binPath = process.env.BINARY_PATH - } else if (DEV) { - // in development use the build gaia files from running `yarn build:gaia` - const osFolderName = (function() { - switch (process.platform) { - case `win32`: - return `windows_amd64` - case `darwin`: - return `darwin_amd64` - case `linux`: - return `linux_amd64` - } - })() - binPath = join(__dirname, `../../../builds/Gaia`, osFolderName, name) - } else { - // in production mode, use binaries packaged with app - binPath = join(__dirname, `..`, `bin`, name) - } - - let argString = args.map(arg => JSON.stringify(arg)).join(` `) - log(`spawning ${binPath} with args "${argString}"`) - let child - try { - child = childProcess.spawn(binPath, args, env) - } catch (error) { - log(`Err: Spawning ${name} failed`, error) - throw error - } - child.stdout.on(`data`, data => !shuttingDown && log(`${name}: ${data}`)) - child.stderr.on(`data`, data => !shuttingDown && log(`${name}: ${data}`)) - - // Make stdout more useful by emitting a line at a time. - readline.createInterface({ input: child.stdout }).on(`line`, line => { - child.stdout.emit(`line`, line) - }) - - // Make stderr more useful by emitting a line at a time. - readline.createInterface({ input: child.stderr }).on(`line`, line => { - child.stderr.emit(`line`, line) - }) - - child.on( - `exit`, - code => !shuttingDown && log(`${name} exited with code ${code}`) - ) - child.on(`error`, async function(error) { - if (!(shuttingDown && error.code === `ECONNRESET`)) { - // if we throw errors here, they are not handled by the main process - let errorMessage = [ - `[Uncaught Exception] Child`, - name, - `produced an unhandled exception:`, - error - ] - logError(...errorMessage) - console.error(...errorMessage) // also output to console for easier debugging - handleCrash(error) - - Sentry.captureException(error) - } - }) - - // need to kill child processes if main process dies - process.on(`exit`, () => { - child.kill() - }) - return child -} - -app.on(`window-all-closed`, () => { - app.quit() -}) - -app.on(`activate`, () => { - if (mainWindow === null) { - createWindow() - } -}) - -app.on(`ready`, () => createWindow()) - -// start lcd REST API -async function startLCD(home, nodeURL) { - assert.equal( - gaiaLiteProcess, - null, - `Can't start Gaia Lite because it's already running. Call StopLCD first.` - ) - - let lcdStarted = false // remember if the lcd has started to toggle the right error handling if it crashes async - return new Promise(async (resolve, reject) => { - log(`startLCD`, home) - let child = startProcess(LCD_BINARY_NAME, [ - `rest-server`, - `--laddr`, - `tcp://localhost:${LCD_PORT}`, - `--home`, - home, - `--node`, - nodeURL, - `--chain-id`, - chainId, - `--trust-node`, - true - ]) - logProcess(child, join(home, `lcd.log`)) - - child.stdout.on(`line`, line => { - if (/\(cert: "(.+?)"/.test(line)) { - const certPath = /\(cert: "(.+?)"/.exec(line)[1] - resolve({ ca: fs.readFileSync(certPath, `utf8`), process: child }) - lcdStarted = true - child.stdout.removeAllListeners(`line`) - } - }) - - child.stderr.on(`line`, error => { - let errorMessage = `The gaiacli rest-server (LCD) experienced an error:\n${error.toString( - `utf8` - )}`.substr(0, 1000) - lcdStarted - ? handleCrash(errorMessage) // if fails later - : reject(errorMessage) // if fails immediatly - }) - }) -} - -function stopLCD() { - return new Promise((resolve, reject) => { - if (!gaiaLiteProcess) { - resolve() - return - } - log(`Stopping the LCD server`) - try { - // prevent the exit to signal bad termination warnings - gaiaLiteProcess.removeAllListeners(`exit`) - gaiaLiteProcess.on(`exit`, () => { - gaiaLiteProcess = null - resolve() - }) - gaiaLiteProcess.kill(`SIGKILL`) - } catch (error) { - handleCrash(error) - reject(`Stopping the LCD resulted in an error: ${error.message}`) - } - }) -} - -async function getGaiacliVersion() { - let child = startProcess(LCD_BINARY_NAME, [`version`]) - let data = await new Promise(resolve => { - child.stdout.on(`data`, resolve) - }) - return data.toString(`utf8`).trim() -} - -function exists(path) { - try { - fs.accessSync(path) - return true - } catch (error) { - if (error.code !== `ENOENT`) throw error - return false - } -} - -// this function will call the passed in callback when the view is booted -// the purpose is to send events to the view thread only after it is ready to receive those events -// if we don't do this, the view thread misses out on those (i.e. an error that occures before the view is ready) -function afterBooted(cb) { - // in tests we trigger the booted callback always, this causes those events to be sent twice - // this is why we skip the callback if the message was sent already - let sent = false - ipcMain.on(`booted`, () => { - cb() - sent = true - }) - if (booted && !sent) { - cb() - } -} - -/* - * log to file - */ -function setupLogging(root) { - if (!LOGGING) return - - // initialize log file - let logFilePath = join(root, `main.log`) - fs.ensureFileSync(logFilePath) - let mainLog = fs.createWriteStream(logFilePath, { flags: `a` }) // 'a' means appending (old data will be preserved) - mainLog.write(`${new Date()} Running Cosmos-UI\r\n`) - // mainLog.write(`${new Date()} Environment: ${JSON.stringify(process.env)}\r\n`) // TODO should be filtered before adding it to the log - streams.push(mainLog) - - log(`Redirecting console output to logfile`, logFilePath) - // redirect stdout/err to logfile - // TODO overwriting console.log sounds like a bad idea, can we find an alternative? - // eslint-disable-next-line no-func-assign - log = function(...args) { - if (DEV) { - console.log(...args) - } - mainLog.write(`main-process: ${args.join(` `)}\r\n`) - } - // eslint-disable-next-line no-func-assign - logError = function(...args) { - if (DEV) { - console.error(...args) - } - mainLog.write(`main-process: ${args.join(` `)}\r\n`) - } -} - -if (!TEST) { - process.on(`exit`, shutdown) - // on uncaught exceptions we wait so the sentry event can be sent - process.on(`uncaughtException`, async function(error) { - logError(`[Uncaught Exception]`, error) - Sentry.captureException(error) - handleCrash(error) - }) - process.on(`unhandledRejection`, async function(error) { - logError(`[Unhandled Promise Rejection]`, error) - Sentry.captureException(error) - handleCrash(error) - }) -} - -const eventHandlers = { - booted: () => { - log(`View has booted`) - booted = true - }, - - "error-collection": (event, optin) => { - if (optin) { - Sentry.init({ - dsn: config.sentry_dsn, - release: `voyager@${pkgVersion}` - }) - } else { - Sentry.init({}) - } - }, - - mocked: value => { - global.config.mocked = value - }, - - reconnect: () => reconnect(), - - "stop-lcd": () => stopLCD(), - - "successful-launch": () => { - console.log(`[START SUCCESS] Vue app successfuly started`) - } -} - -// handle ipc messages from the renderer process -Object.entries(eventHandlers).forEach(([event, handler]) => { - ipcMain.on(event, handler) -}) - -// test an actual node version against the expected one and flag the node if incompatible -async function testNodeVersion(client, expectedGaiaVersion) { - let result = await client.nodeVersion() - let nodeVersion = result.split(`-`)[0] - let semverDiff = semver.diff(nodeVersion, expectedGaiaVersion) - if (semverDiff === `patch` || semverDiff === null) { - return { compatible: true, nodeVersion } - } - - return { compatible: false, nodeVersion } -} - -// Proxy requests to Axios through the main process because we need -// Node.js in order to support self-signed TLS certificates. -const AxiosListener = axios => { - return async (event, id, options) => { - let response - - try { - response = { - value: await axios(options) - } - } catch (exception) { - response = { exception } - } - - event.sender.send(`Axios/${id}`, response) - } -} - -// check if our node is reachable and the SDK version is compatible with the local one -async function pickAndConnect() { - let nodeURL = config.node_lcd - connecting = true - let certificate - - try { - certificate = (await connect(nodeURL)).ca - } catch (error) { - handleCrash(error) - return - } - - // make the tls certificate available to the view process - // https://en.wikipedia.org/wiki/Certificate_authority - global.config.ca = certificate - // TODO reenable certificate - const axiosInstance = axios.create({ - httpsAgent: new https.Agent({ - // ca: certificate - rejectUnauthorized: false - }) - }) - - let compatible, nodeVersion - try { - const client = LcdClient(axiosInstance, config.node_lcd) - const out = await testNodeVersion(client, expectedGaiaCliVersion) - - compatible = out.compatible - nodeVersion = out.nodeVersion - } catch (error) { - logError( - `Error in getting node SDK version, assuming node is incompatible. Error:`, - error - ) - await stopLCD() - - // retry - setTimeout(pickAndConnect, 2000) - return - } - - if (!compatible) { - let message = `Node ${nodeURL} uses SDK version ${nodeVersion} which is incompatible to the version used in Voyager ${expectedGaiaCliVersion}` - log(message) - await stopLCD() - - // retry - setTimeout(pickAndConnect, 2000) - return - } - - ipcMain.removeAllListeners(`Axios`) - ipcMain.on(`Axios`, AxiosListener(axiosInstance)) - - afterBooted(() => { - log(`Signaling connected node`) - mainWindow.webContents.send(`connected`, { - lcdURL: config.node_lcd, - rpcURL: config.node_rpc - }) - }) -} - -async function connect() { - log(`starting gaia rest server with nodeURL ${config.node_rpc}`) - - const { ca, process } = await startLCD(lcdHome, config.node_rpc) - gaiaLiteProcess = process - log(`gaia rest server ready`) - - connecting = false - return { ca, process } -} - -async function reconnect() { - if (connecting) return - log(`Starting reconnect`) - connecting = true - - await stopLCD() - - await pickAndConnect() -} - -function checkConsistentConfigDir( - appVersionPath, - genesisPath, - configPath, - gaiacliVersionPath -) { - let missingFile = - (!exists(genesisPath) && genesisPath) || - (!exists(appVersionPath) && appVersionPath) || - (!exists(configPath) && configPath) || - (!exists(gaiacliVersionPath) && gaiacliVersionPath) - if (missingFile) { - throw Error( - `The data directory (${root}) is missing ${relative(root, missingFile)}` - ) - } else { - let existingVersion = fs.readFileSync(appVersionPath, `utf8`).trim() - let semverDiff = semver.diff(existingVersion, pkgVersion) - let compatible = semverDiff !== `major` && semverDiff !== `minor` - if (compatible) { - log(`configs are compatible with current app version`) - } else { - // TODO: versions of the app with different data formats will need to learn how to - // migrate old data - throw Error(`Data was created with an incompatible app version - data=${existingVersion} app=${pkgVersion}`) - } - } -} - -const checkGaiaCompatibility = async gaiacliVersionPath => { - // XXX: currently ignores commit hash - let gaiacliVersion = (await getGaiacliVersion()).split(`-`)[0] - - expectedGaiaCliVersion = fs - .readFileSync(gaiacliVersionPath, `utf8`) - .trim() - .split(`-`)[0] - - log( - `gaiacli version: "${gaiacliVersion}", expected: "${expectedGaiaCliVersion}"` - ) - - let compatible = - semver.major(gaiacliVersion) == semver.major(expectedGaiaCliVersion) && - semver.minor(gaiacliVersion) == semver.minor(expectedGaiaCliVersion) - - if (!compatible) { - throw Error( - `The network you are trying to connect to requires gaia ${expectedGaiaCliVersion}, but the version Voyager is using is ${gaiacliVersion}.${ - DEV - ? ` Please update "tasks/build/Gaia/COMMIT.sh" with the required version and run "yarn build:gaia".` - : `` - }` - ) - } -} - -async function main() { - // Sentry is used for automatic error reporting. It is turned off by default. - Sentry.init({}) - - let appVersionPath = join(root, `app_version`) - let genesisPath = join(root, `genesis.json`) - let configPath = join(root, `config.toml`) - let gaiacliVersionPath = join(root, `gaiaversion.txt`) - - let rootExists = exists(root) - await fs.ensureDir(root) - - setupLogging(root) - - if (rootExists) { - log(`root exists (${root})`) - - // NOTE: when changing this code, always make sure the app can never - // overwrite/delete existing data without at least backing it up, - // since it may contain the user's private keys and they might not - // have written down their seed words. - // they might get pretty mad if the app deletes their money! - - // check if the existing data came from a compatible app version - // if not, fail with an error - checkConsistentConfigDir( - appVersionPath, - genesisPath, - configPath, - gaiacliVersionPath - ) - - // check to make sure the genesis.json we want to use matches the one - // we already have. if it has changed, replace it with the new one - let existingGenesis = fs.readFileSync(genesisPath, `utf8`) - let genesisJSON = JSON.parse(existingGenesis) - // skip this check for local testnet - if (genesisJSON.chain_id !== `local`) { - let specifiedGenesis = fs.readFileSync( - join(networkPath, `genesis.json`), - `utf8` - ) - if (existingGenesis.trim() !== specifiedGenesis.trim()) { - fs.copySync(networkPath, root) - log( - `genesis.json at "${genesisPath}" was overridden by genesis.json from "${networkPath}"` - ) - } - } - } else { - log(`initializing data directory (${root})`) - await fs.ensureDir(root) - - // copy predefined genesis.json and config.toml into root - fs.accessSync(networkPath) // crash if invalid path - await fs.copyFile( - join(networkPath, `config.toml`), - join(root, `config.toml`) - ) - await fs.copyFile( - join(networkPath, `gaiaversion.txt`), - join(root, `gaiaversion.txt`) - ) - await fs.copyFile( - join(networkPath, `genesis.json`), - join(root, `genesis.json`) - ) - - fs.writeFileSync(appVersionPath, pkgVersion) - } - - await checkGaiaCompatibility(gaiacliVersionPath) - - // read chainId from genesis.json - let genesisText = fs.readFileSync(genesisPath, `utf8`) - let genesis = JSON.parse(genesisText) - chainId = genesis.chain_id // is set globaly - - // choose one random node to start from - await pickAndConnect() -} -module.exports = main() - .catch(error => { - logError(error) - handleCrash(error) - }) - .then(() => ({ - shutdown, - processes: { gaiaLiteProcess }, - eventHandlers, - getGaiaLiteProcess: () => gaiaLiteProcess - })) diff --git a/app/src/main/menu.js b/app/src/main/menu.js deleted file mode 100644 index 34d20acb25..0000000000 --- a/app/src/main/menu.js +++ /dev/null @@ -1,83 +0,0 @@ -"use strict" - -const { app, Menu, shell, dialog } = require(`electron`) -const { join } = require(`path`) - -module.exports = function() { - let template = [ - { - label: `Cosmos Voyager`, - submenu: [ - { - label: `About Cosmos Voyager`, - selector: `orderFrontStandardAboutPanel:`, - click: () => openAboutMenu() - }, - { type: `separator` }, - { - label: `Quit`, - accelerator: `Command+Q`, - click: () => app.quit() - } - ] - }, - { - label: `Edit`, - submenu: [ - { - label: `Cut`, - accelerator: `CmdOrCtrl+X`, - selector: `cut:` - }, - { - label: `Copy`, - accelerator: `CmdOrCtrl+C`, - selector: `copy:` - }, - { - label: `Paste`, - accelerator: `CmdOrCtrl+V`, - selector: `paste:` - } - ] - }, - { - label: `Help`, - submenu: [ - { - label: `Report An Issue`, - click() { - shell.openExternal(`https://github.com/cosmos/voyager/issues/new`) - } - }, - { - label: `View Application Log`, - click() { - shell.openItem(global.root + `/main.log`) - } - } - ] - } - ] - - let menu = Menu.buildFromTemplate(template) - Menu.setApplicationMenu(menu) -} - -function openAboutMenu() { - const voyagerVersion = require(`../../../package.json`).version - const gaiaVersion = process.env.GAIA_VERSION - const electronVersion = app.getVersion() - - const imageLocation = - process.env.NODE_ENV === `development` - ? join(__dirname, `../renderer/assets/images`) - : join(__dirname, `./imgs`) - - dialog.showMessageBox({ - type: `info`, - title: `About Voyager`, - message: `Versions\n\nVoyager ${voyagerVersion}\nCosmos SDK ${gaiaVersion}\nElectron ${electronVersion}`, - icon: join(imageLocation, `cosmos-logo.png`) - }) -} diff --git a/app/src/network.js b/app/src/network.js index 18e89302a5..ccb93d0b38 100644 --- a/app/src/network.js +++ b/app/src/network.js @@ -1,19 +1,16 @@ -"use strict" +/* istanbul ignore file */ +import axios from "axios" +import config from "./config" -let { join } = require(`path`) -let { readFileSync } = require(`fs-extra`) -let config = require(`./config.js`) +const networkPath = `../networks/${config.default_network}` -// this network gets used if none is specified via the -// COSMOS_NETWORK env var -let DEFAULT_NETWORK = join(__dirname, `../networks/` + config.default_network) -let networkPath = process.env.COSMOS_NETWORK || DEFAULT_NETWORK +export default async function() { + const genesis = (await axios(`${networkPath}/genesis.json`)).data + const networkName = genesis.chain_id -let genesisText = readFileSync(join(networkPath, `genesis.json`), `utf8`) -let genesis = JSON.parse(genesisText) -let networkName = genesis.chain_id - -module.exports = { - path: networkPath, - name: networkName + return { + genesis, + path: networkPath, + name: networkName + } } diff --git a/app/src/renderer/App.vue b/app/src/renderer/App.vue index db6d293d23..55303be1e8 100644 --- a/app/src/renderer/App.vue +++ b/app/src/renderer/App.vue @@ -1,20 +1,18 @@ @@ -24,9 +22,6 @@ import AppHeader from "common/AppHeader" import TmNotifications from "common/TmNotifications" import ModalError from "common/TmModalError" import ModalHelp from "common/TmModalHelp" -import ModalLcdApproval from "common/TmModalLCDApproval" -import ModalNodeHalted from "common/TmModalNodeHalted" -import ModalReceive from "common/TmModalReceive" import Onboarding from "common/TmOnboarding" import Session from "common/TmSession" import store from "./vuex/store" @@ -38,9 +33,6 @@ import store from "./vuex/store" * @vue-data {Object} nothing * @vue-computed {function} notifications mapGetter * @vue-computed {function} config mapGetter - * @vue-computed {function} themes mapGetter - * @vue-computed {function} approval mapGetter - * @vue-computed {function} required mapGetter * @vue-computed {function} onboarding mapGetter */ export default { @@ -49,25 +41,15 @@ export default { AppHeader, ModalError, ModalHelp, - ModalLcdApproval, - ModalReceive, TmNotifications, - ModalNodeHalted, Onboarding, Session }, computed: { - ...mapGetters([ - `notifications`, - `config`, - `themes`, - `approvalRequired`, - `onboarding` - ]) + ...mapGetters([`notifications`, `config`, `onboarding`]) }, mounted() { this.$store.commit(`loadOnboarding`) - this.$store.commit(`setTheme`, `dark`) }, store } diff --git a/app/src/renderer/assets/fonts/FontAwesome.otf b/app/src/renderer/assets/fonts/FontAwesome.otf deleted file mode 100644 index 401ec0f36e..0000000000 Binary files a/app/src/renderer/assets/fonts/FontAwesome.otf and /dev/null differ diff --git a/app/src/renderer/assets/fonts/fontawesome-webfont.eot b/app/src/renderer/assets/fonts/fontawesome-webfont.eot deleted file mode 100644 index e9f60ca953..0000000000 Binary files a/app/src/renderer/assets/fonts/fontawesome-webfont.eot and /dev/null differ diff --git a/app/src/renderer/assets/fonts/fontawesome-webfont.svg b/app/src/renderer/assets/fonts/fontawesome-webfont.svg deleted file mode 100644 index 855c845e53..0000000000 --- a/app/src/renderer/assets/fonts/fontawesome-webfont.svg +++ /dev/null @@ -1,2671 +0,0 @@ - - - - -Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 - By ,,, -Copyright Dave Gandy 2016. All rights reserved. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/renderer/assets/fonts/fontawesome-webfont.ttf b/app/src/renderer/assets/fonts/fontawesome-webfont.ttf deleted file mode 100644 index 35acda2fa1..0000000000 Binary files a/app/src/renderer/assets/fonts/fontawesome-webfont.ttf and /dev/null differ diff --git a/app/src/renderer/assets/fonts/fontawesome-webfont.woff b/app/src/renderer/assets/fonts/fontawesome-webfont.woff deleted file mode 100644 index 400014a4b0..0000000000 Binary files a/app/src/renderer/assets/fonts/fontawesome-webfont.woff and /dev/null differ diff --git a/app/src/renderer/assets/fonts/fontawesome-webfont.woff2 b/app/src/renderer/assets/fonts/fontawesome-webfont.woff2 deleted file mode 100644 index 4d13fc6040..0000000000 Binary files a/app/src/renderer/assets/fonts/fontawesome-webfont.woff2 and /dev/null differ diff --git a/app/src/renderer/components/common/ActionModal.vue b/app/src/renderer/components/common/ActionModal.vue new file mode 100644 index 0000000000..8d88657fe0 --- /dev/null +++ b/app/src/renderer/components/common/ActionModal.vue @@ -0,0 +1,345 @@ + + + + + diff --git a/app/src/renderer/components/common/AnchorCopy.vue b/app/src/renderer/components/common/AnchorCopy.vue index 93df2a77f7..db3b24cddc 100644 --- a/app/src/renderer/components/common/AnchorCopy.vue +++ b/app/src/renderer/components/common/AnchorCopy.vue @@ -6,7 +6,6 @@ + + diff --git a/app/src/renderer/components/common/PagePreferences.vue b/app/src/renderer/components/common/PagePreferences.vue index a3fb670167..6a5fda45b1 100644 --- a/app/src/renderer/components/common/PagePreferences.vue +++ b/app/src/renderer/components/common/PagePreferences.vue @@ -1,18 +1,15 @@ + diff --git a/app/src/renderer/components/common/TextBlock.vue b/app/src/renderer/components/common/TextBlock.vue index 0b72a6bb2a..d453929480 100644 --- a/app/src/renderer/components/common/TextBlock.vue +++ b/app/src/renderer/components/common/TextBlock.vue @@ -14,7 +14,7 @@ export default { }, computed: { htmlContent() { - let md = new MarkdownIt() + const md = new MarkdownIt() return md.render(this.content) } } @@ -22,10 +22,6 @@ export default { diff --git a/app/src/renderer/components/common/TmBtn.vue b/app/src/renderer/components/common/TmBtn.vue index cc394f626a..52ffd3b255 100644 --- a/app/src/renderer/components/common/TmBtn.vue +++ b/app/src/renderer/components/common/TmBtn.vue @@ -115,10 +115,10 @@ export default { height: 2em; line-height: 1; color: var(--bright, #333) !important; - padding: 0 0.75em; + padding: 0.5rem 2rem; margin: 0; background: var(--app-bg, #fff); - border: 2px solid var(--bc, #ddd); + border: 1px solid var(--bc, #ddd); border-radius: 0.25rem; cursor: pointer; user-select: none; diff --git a/app/src/renderer/components/common/TmBtnCopy.vue b/app/src/renderer/components/common/TmBtnCopy.vue index ce8bedeaab..d132188743 100644 --- a/app/src/renderer/components/common/TmBtnCopy.vue +++ b/app/src/renderer/components/common/TmBtnCopy.vue @@ -8,7 +8,6 @@ diff --git a/app/src/renderer/components/common/TmModalLCDApproval.vue b/app/src/renderer/components/common/TmModalLCDApproval.vue deleted file mode 100644 index b02bce3dba..0000000000 --- a/app/src/renderer/components/common/TmModalLCDApproval.vue +++ /dev/null @@ -1,131 +0,0 @@ - - - - - diff --git a/app/src/renderer/components/common/TmModalNodeHalted.vue b/app/src/renderer/components/common/TmModalNodeHalted.vue deleted file mode 100644 index 78ed330bd4..0000000000 --- a/app/src/renderer/components/common/TmModalNodeHalted.vue +++ /dev/null @@ -1,98 +0,0 @@ - - - - - diff --git a/app/src/renderer/components/common/TmModalSearch.vue b/app/src/renderer/components/common/TmModalSearch.vue index 8a33cfa93e..d70cbf5eed 100644 --- a/app/src/renderer/components/common/TmModalSearch.vue +++ b/app/src/renderer/components/common/TmModalSearch.vue @@ -55,7 +55,7 @@ export default { open(open) { if (open) { setTimeout(() => { - let el = this.$el.querySelector(`.tm-field`) + const el = this.$el.querySelector(`.tm-field`) el.focus() }) } diff --git a/app/src/renderer/components/common/TmNotification.vue b/app/src/renderer/components/common/TmNotification.vue index a03ff08086..4347bdf005 100644 --- a/app/src/renderer/components/common/TmNotification.vue +++ b/app/src/renderer/components/common/TmNotification.vue @@ -68,7 +68,7 @@ export default { setDeactivation() { if (!this.layout || this.layout === `banner`) { // notification active duration is 5 seconds - (time since creation) - let activeDuration = this.duration - (Date.now() - this.time) + const activeDuration = this.duration - (Date.now() - this.time) // disable visibility if it's an old notification if (activeDuration < 0) { @@ -86,12 +86,13 @@ export default { diff --git a/app/src/renderer/components/common/TmSessionAccountDelete.vue b/app/src/renderer/components/common/TmSessionAccountDelete.vue index 86583e9af9..29fa7945f7 100644 --- a/app/src/renderer/components/common/TmSessionAccountDelete.vue +++ b/app/src/renderer/components/common/TmSessionAccountDelete.vue @@ -69,7 +69,7 @@ diff --git a/app/src/renderer/components/common/TmUserPane.vue b/app/src/renderer/components/common/TmUserPane.vue index 8fe3791466..73db9f9604 100644 --- a/app/src/renderer/components/common/TmUserPane.vue +++ b/app/src/renderer/components/common/TmUserPane.vue @@ -17,7 +17,7 @@ import TmListItem from "common/TmListItem" export default { name: `tm-user-pane`, components: { TmListItem }, - computed: { ...mapGetters([`user`, `config`]) }, + computed: { ...mapGetters([`user`]) }, methods: { close() { this.$store.commit(`setActiveMenu`, ``) diff --git a/app/src/renderer/components/common/ToolBar.vue b/app/src/renderer/components/common/ToolBar.vue index aa4af2a2f4..2276bdfa48 100644 --- a/app/src/renderer/components/common/ToolBar.vue +++ b/app/src/renderer/components/common/ToolBar.vue @@ -1,44 +1,68 @@ diff --git a/app/src/renderer/components/governance/LiProposal.vue b/app/src/renderer/components/governance/LiProposal.vue index 9fa96009cb..b684c37eba 100644 --- a/app/src/renderer/components/governance/LiProposal.vue +++ b/app/src/renderer/components/governance/LiProposal.vue @@ -48,8 +48,8 @@ export default { computed: { ...mapGetters([`proposals`]), tally() { - let proposalTally - proposalTally = this.proposals.tallies[this.proposal.proposal_id] || {} + const proposalTally = + this.proposals.tallies[this.proposal.proposal_id] || {} proposalTally.yes = Math.round(parseFloat(proposalTally.yes)) proposalTally.no = Math.round(parseFloat(proposalTally.no)) proposalTally.no_with_veto = Math.round( @@ -95,9 +95,6 @@ export default { diff --git a/app/src/renderer/components/governance/ModalPropose.vue b/app/src/renderer/components/governance/ModalPropose.vue index ed5c786146..ed17df4953 100644 --- a/app/src/renderer/components/governance/ModalPropose.vue +++ b/app/src/renderer/components/governance/ModalPropose.vue @@ -1,19 +1,18 @@ - diff --git a/app/src/renderer/components/governance/ModalVote.vue b/app/src/renderer/components/governance/ModalVote.vue index 50e2933000..fc476050de 100644 --- a/app/src/renderer/components/governance/ModalVote.vue +++ b/app/src/renderer/components/governance/ModalVote.vue @@ -1,93 +1,62 @@ diff --git a/app/src/renderer/components/governance/PageGovernance.vue b/app/src/renderer/components/governance/PageGovernance.vue index 2f013de24e..c569382e7c 100644 --- a/app/src/renderer/components/governance/PageGovernance.vue +++ b/app/src/renderer/components/governance/PageGovernance.vue @@ -1,52 +1,37 @@ diff --git a/app/src/renderer/components/governance/TabParameters.vue b/app/src/renderer/components/governance/TabParameters.vue index ce9ca9fec6..bff6ab3334 100644 --- a/app/src/renderer/components/governance/TabParameters.vue +++ b/app/src/renderer/components/governance/TabParameters.vue @@ -1,163 +1,153 @@