From 123abf4ed116969250f7700d92c9fde47cf6cd75 Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Thu, 13 Jan 2022 18:36:13 +0100 Subject: [PATCH 01/12] Fix issue #22 #21 #17 #16 #15 #14 #13 #12 #11 #10 #9 Added Chihuahua configuration --- public/icons.svg | 18 ++++++++ src/components/BalanceSummary.vue | 13 ++---- src/components/MenuLink.vue | 33 +++++++++++---- src/components/ValidatorsTable.vue | 9 ++-- src/constants/network.ts | 42 ++++++++++++++++++- src/css/_drawer.scss | 2 +- src/css/_utils.scss | 16 +++++++ src/css/quasar.variables.scss | 5 ++- src/layouts/MainLayout.vue | 26 +++++++----- src/modules/authentication/views/Login.vue | 2 +- .../authentication/views/LoginHome.vue | 32 ++++++++++++-- .../wallet/components/ValidatorDelegation.vue | 8 ++-- .../wallet/components/ValidatorRewards.vue | 4 +- src/modules/wallet/views/Portfolio.vue | 30 ++++--------- src/router/index.ts | 12 +++--- src/store/data/actions.ts | 11 ----- src/store/data/getters.ts | 5 ++- 17 files changed, 184 insertions(+), 84 deletions(-) diff --git a/public/icons.svg b/public/icons.svg index f708c1db..e99b5c83 100644 --- a/public/icons.svg +++ b/public/icons.svg @@ -96,4 +96,22 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/components/BalanceSummary.vue b/src/components/BalanceSummary.vue index c04613d0..ec1c4102 100644 --- a/src/components/BalanceSummary.vue +++ b/src/components/BalanceSummary.vue @@ -7,12 +7,12 @@

- APR + TOTAL ({{ network.stakingDenom }})

- @@ -73,7 +73,10 @@ export default defineComponent({ newLink: { type: Boolean, default: false, - } + }, + count: { + type: Number, + }, }, setup() { const router = useRouter(); @@ -125,4 +128,20 @@ export default defineComponent({ min-height: 24px; border-radius: 25px; } + +.status-count { + margin-left: 14px; + width: 24px; + height: 24px; + padding: 0; + border-radius: 25px; + justify-content: center; + align-items: center; +} + +.external-icon { + margin-left: 12px; + margin-top: auto; + margin-bottom: auto; +} diff --git a/src/components/ValidatorsTable.vue b/src/components/ValidatorsTable.vue index 37f9f336..6314e768 100644 --- a/src/components/ValidatorsTable.vue +++ b/src/components/ValidatorsTable.vue @@ -147,6 +147,7 @@ export default defineComponent({ const router = useRouter(); const rewards = computed(() => store.state.data.rewards); const network = computed(() => store.state.authentication.network); + const session = computed(() => store.state.authentication.session); const pagination = { sortBy: 'votingPower', @@ -199,7 +200,7 @@ export default defineComponent({ }, { name: 'time', - label: 'Time', + label: 'Remaining Time', align: 'center', field: 'time', }, @@ -210,15 +211,17 @@ export default defineComponent({ ]); const visibleColumns = computed(() => { + const extra = !session.value || (session.value && session.value.sessionType !== 'keplr') ? [] : ['actions']; + if (props.unstaking) { return ['id', 'name', 'unstaked', 'time']; } if (props.staking) { - return ['id', 'name', 'status', 'staked', 'rewards', 'votingPower', 'actions']; + return ['id', 'name', 'status', 'staked', 'rewards', 'votingPower', ...extra]; } - return ['id', 'name', 'status', 'rewards', 'votingPower', 'actions']; + return ['id', 'name', 'status', 'rewards', 'votingPower', ...extra]; }); const rowClick = async (row: LooseDictionary) => { diff --git a/src/constants/network.ts b/src/constants/network.ts index 74dc27fb..b4486bd4 100644 --- a/src/constants/network.ts +++ b/src/constants/network.ts @@ -176,7 +176,7 @@ export const networks: NetworkConfig[] = [ apiURL: 'https://lcd-cosmoshub.keplr.app', rpcURL: 'https://rpc-cosmoshub.keplr.app', explorerURL: 'https://www.mintscan.io/cosmos/', - minBlockHeight: 1, + minBlockHeight: 9054000, stakingDenom: 'ATOM', coinLookup: [ { @@ -206,5 +206,45 @@ export const networks: NetworkConfig[] = [ }, icon: 'https://assets.coingecko.com/coins/images/5041/small/logo_-_2021-01-10T210801.390.png', localSigning: false, // this is only to be used as a developer tool - never deployed in production or for mainnet chains + }, + { + id: 'chihuahua-1', + name: 'Chihuahua', + description: 'Chihuahua Mainnet', + logo: 'logo.svg', + website: 'https://chihuahua.wtf', + apiURL: 'https://api.chihuahua.wtf', + rpcURL: 'https://rpc.chihuahua.wtf', + explorerURL: 'https://www.mintscan.io/chihuahua/', + minBlockHeight: 1, + stakingDenom: 'HUAHUA', + coinLookup: [ + { + viewDenom: 'HUAHUA', + chainDenom: 'uhuahua', + chainToViewConversionFactor: 1e-6, + icon: 'currencies/bitsong.png', + }, + ], + addressPrefix: 'chihuahua', + validatorAddressPrefix: 'chihuahuavaloper', + validatorConsensusaddressPrefix: 'chihuahuavalcons', // needed to map validators from staking queries to the validator set + HDPath: 'm/44\'/118\'/0\'/0/0', + coinType: 118, + coinGeckoId: 'chihuahua-token', + lockUpPeriod: '3 days', + fees: { + default: { + gasEstimate: 350000, + feeOptions: [ + { + denom: 'HUAHUA', + amount: 0.001, + }, + ], + }, + }, + icon: 'https://assets.coingecko.com/coins/images/22485/small/logo_transparent_notext.png', + localSigning: false, // this is only to be used as a developer tool - never deployed in production or for mainnet chains } ]; diff --git a/src/css/_drawer.scss b/src/css/_drawer.scss index 05e03217..fda715a8 100644 --- a/src/css/_drawer.scss +++ b/src/css/_drawer.scss @@ -25,7 +25,7 @@ @media screen and (min-width: $breakpoint-md-min) { padding-top: 190px; - padding-right: 46px; + padding-right: 38px; padding-left: 0; } diff --git a/src/css/_utils.scss b/src/css/_utils.scss index 4c2a21bb..d4793172 100644 --- a/src/css/_utils.scss +++ b/src/css/_utils.scss @@ -47,6 +47,18 @@ background: $accent-2 !important; } +.bg-accent-3 { + background: $accent-3 !important; +} + +.bg-alternative-4 { + background: $alternative-4 !important; +} + +.bg-transparent-accent-3 { + background: $transparent-accent-3 !important; +} + .bg-alternative-linear-gradient { background: $alternative-linear-gradient !important; } @@ -79,6 +91,10 @@ color: $gray3 !important; } +.text-alternative-4 { + color: $alternative-4 !important; +} + .text-transparent-accent { color: $transparent-accent !important; } diff --git a/src/css/quasar.variables.scss b/src/css/quasar.variables.scss index 1c333569..332d8ac0 100644 --- a/src/css/quasar.variables.scss +++ b/src/css/quasar.variables.scss @@ -23,6 +23,7 @@ $accent-5: #9494B9; $alternative: #313150; $alternative-2: #23223B; $alternative-3: #303046; +$alternative-4: #27273E; $white: #fff; $transparent-white: transparentize($white, 0.85); @@ -36,6 +37,7 @@ $dark: #1D1D1D; $transparent-secondary: transparentize($secondary, 0.3); $transparent-accent: transparentize($accent, 0.5); +$transparent-accent-3: transparentize($accent-3, 0.5); $accent-linear-gradient: linear-gradient(0deg, $accent, $accent), rgba(255, 255, 255, 0.2); $alternative-linear-gradient: linear-gradient(0deg, $alternative, $alternative), $white; @@ -117,7 +119,8 @@ $subtitle2: (size: 16px, line-height: 20px, letter-spacing: normal, weight: 400) $overline: (size: 13px, line-height: 16px, letter-spacing: normal, weight: 400) !default; $overline-2: (size: 13px, line-height: 24px, letter-spacing: normal, weight: 400) !default; $caption: (size: 11px, line-height: 12px, letter-spacing: normal, weight: 400) !default; +$caption-2: (size: 10px, line-height: 12px, letter-spacing: normal, weight: 400) !default; -$headings: ('h1': $h1, 'h2': $h2, 'h3': $h3, 'h4': $h4, 'h5': $h5, 'h6': $h6, 'subtitle1': $subtitle1, 'subtitle2': $subtitle2, 'body1': $body1, 'body2': $body2, 'body3': $body3, 'body4': $body4, 'body5': $body5, 'body6': $body6, 'body-large': $body-large, 'body-extra-large': $body-extra-large, 'body-extra-large2': $body-extra-large2, 'body-extra-large3': $body-extra-large3, 'overline': $overline,'overline-2': $overline-2, 'caption': $caption) !default; +$headings: ('h1': $h1, 'h2': $h2, 'h3': $h3, 'h4': $h4, 'h5': $h5, 'h6': $h6, 'subtitle1': $subtitle1, 'subtitle2': $subtitle2, 'body1': $body1, 'body2': $body2, 'body3': $body3, 'body4': $body4, 'body5': $body5, 'body6': $body6, 'body-large': $body-large, 'body-extra-large': $body-extra-large, 'body-extra-large2': $body-extra-large2, 'body-extra-large3': $body-extra-large3, 'overline': $overline,'overline-2': $overline-2, 'caption': $caption, 'caption-2': $caption-2) !default; $typography-font-family: Circular Std, 'Roboto', '-apple-system', 'Helvetica Neue', Helvetica, Arial, sans-serif !default diff --git a/src/layouts/MainLayout.vue b/src/layouts/MainLayout.vue index dec2ff6d..9f08a471 100644 --- a/src/layouts/MainLayout.vue +++ b/src/layouts/MainLayout.vue @@ -7,11 +7,13 @@ - - - + + + + -

wallet

+

wallet

+
@@ -22,13 +24,13 @@ - - + + - - + + @@ -46,7 +48,7 @@ - + @@ -68,12 +70,12 @@ > @@ -122,6 +124,7 @@ export default defineComponent({ const session = computed(() => store.state.authentication.session); const address = computed(() => formatAddress(store.state.authentication.session?.address)); const loading = computed(() => store.state.authentication.loading); + const votingProposalsCount = computed(() => store.getters['data/votingProposalsCount'] as number); const explorerURL = computed(() => { const session = store.state.authentication.session; @@ -159,6 +162,7 @@ export default defineComponent({ } return { + votingProposalsCount, bridgeURL, loadingNetwork, network, diff --git a/src/modules/authentication/views/Login.vue b/src/modules/authentication/views/Login.vue index 830581a9..0d015eaf 100644 --- a/src/modules/authentication/views/Login.vue +++ b/src/modules/authentication/views/Login.vue @@ -31,7 +31,7 @@ export default defineComponent({ name: 'Login', setup() { const router = useRouter(); - const canGoBack = computed(() => router.currentRoute.value.name !== 'choose'); + const canGoBack = computed(() => router.currentRoute.value.name !== 'login-home'); return { canGoBack, diff --git a/src/modules/authentication/views/LoginHome.vue b/src/modules/authentication/views/LoginHome.vue index 5bc79665..31051598 100644 --- a/src/modules/authentication/views/LoginHome.vue +++ b/src/modules/authentication/views/LoginHome.vue @@ -19,21 +19,37 @@ > - + + + - + + +
@@ -99,4 +115,12 @@ export default defineComponent({ .subtitle { margin-bottom: 48px; } + +.soon-chip { + min-width: 70px; + min-height: 36px; + border-radius: 25px; + align-items: center; + justify-content: center; +} diff --git a/src/modules/wallet/components/ValidatorDelegation.vue b/src/modules/wallet/components/ValidatorDelegation.vue index 7441235f..4c44b986 100644 --- a/src/modules/wallet/components/ValidatorDelegation.vue +++ b/src/modules/wallet/components/ValidatorDelegation.vue @@ -7,13 +7,13 @@
- + delegate - + undelegate - + redelegate
@@ -39,6 +39,7 @@ export default defineComponent({ setup(props) { const store = useStore(); const delegations = computed(() => store.state.data.delegations); + const session = computed(() => store.state.authentication.session); const hasDelegations = computed(() => { return delegations.value.filter(({ validator }) => validator.operatorAddress === props.validator.operatorAddress).length > 0; @@ -55,6 +56,7 @@ export default defineComponent({ }); return { + session, delegated, hasDelegations, ...useDelegatorActions(), diff --git a/src/modules/wallet/components/ValidatorRewards.vue b/src/modules/wallet/components/ValidatorRewards.vue index f56d9a62..0c8c61db 100644 --- a/src/modules/wallet/components/ValidatorRewards.vue +++ b/src/modules/wallet/components/ValidatorRewards.vue @@ -7,7 +7,7 @@
- + CLAIM
@@ -34,6 +34,7 @@ export default defineComponent({ const store = useStore(); const rewards = computed(() => store.state.data.rewards); const network = computed(() => store.state.authentication.network); + const session = computed(() => store.state.authentication.session); const validatorReward = computed(() => rewards.value.filter( ({ validator }) => validator.operatorAddress === props.validator.operatorAddress) @@ -61,6 +62,7 @@ export default defineComponent({ } return { + session, validatorReward, stakingDenomReward, openClaimDialog diff --git a/src/modules/wallet/views/Portfolio.vue b/src/modules/wallet/views/Portfolio.vue index ed30506c..cce4a2c6 100644 --- a/src/modules/wallet/views/Portfolio.vue +++ b/src/modules/wallet/views/Portfolio.vue @@ -5,19 +5,9 @@ Your Balances - + {{ !quasar.screen.lt.md ? 'CLAIM REWARDS' : 'CLAIM' }} - -
-

- TOTAL ({{ network.stakingDenom }}) -

-

- {{ balance ? balance.total : 0 }} -

- -
@@ -74,9 +64,9 @@ appear >
- - - + + +
@@ -86,7 +76,7 @@ import { defineComponent, computed } from 'vue'; import { useQuasar } from 'quasar'; import { useStore } from 'src/store'; -import { SupplyResponse, Validator, Balance } from 'src/models'; +import { SupplyResponse, Validator } from 'src/models'; import BalanceSummary from 'src/components/BalanceSummary.vue'; import ValidatorsSummary from 'src/components/ValidatorsSummary.vue'; @@ -106,9 +96,8 @@ export default defineComponent({ const store = useStore(); const quasar = useQuasar(); - const network = computed(() => store.state.authentication.network); - const rewards = computed(() => store.state.data.rewards); + const session = computed(() => store.state.authentication.session); const validatorsOfDelegations = computed(() => store.getters['data/validatorsOfDelegations'] as Validator[]); const delegationsLoaded = computed(() => store.state.data.delegationsLoaded); @@ -119,9 +108,6 @@ export default defineComponent({ const supplyInfo = computed(() => store.getters['data/supplyInfo'] as SupplyResponse | null); const loadingSupplyInfo = computed(() => store.state.data.loadingSupplyInfo); - const balance = computed(() => store.getters['data/currentBalance'] as Balance | undefined); - const loadingBalance = computed(() => !store.state.data.balancesLoaded || store.state.data.loading); - const openClaimDialog = () => { quasar.dialog({ component: ClaimDialog, @@ -131,9 +117,7 @@ export default defineComponent({ } return { - network, - balance, - loadingBalance, + session, supplyInfo, loadingSupplyInfo, rewards, diff --git a/src/router/index.ts b/src/router/index.ts index 0c132af9..117972a8 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -1,4 +1,4 @@ -/* import Store from 'src/store'; */ +import Store from 'src/store'; import { createMemoryHistory, createRouter, @@ -23,12 +23,10 @@ const Router = createRouter({ ) }); -/* Router.beforeEach((to, _, next) => { +Router.beforeEach((to, _, next) => { const logged = Store.state.authentication.session !== undefined; const match = to.matched.find(el => el.name === 'login'); - console.log(to); - if (!logged && !match) { if (to.fullPath !== '/') { return next({ name: 'authentication', query: { r: to.fullPath } }); @@ -37,14 +35,14 @@ const Router = createRouter({ return next({ name: 'authentication' }); } - const defaultRoute = { name: 'wallet' }; + /* const defaultRoute = { name: 'wallet' }; if (logged && (match || to.path === '/')) { return next(defaultRoute); - } + } */ return next(); -}); */ +}); Router.afterEach(to => { const title = Array.isArray(to.meta.title) ? to.meta.title.join(' - ') : to.meta.title as string; diff --git a/src/store/data/actions.ts b/src/store/data/actions.ts index 7d9ee9b9..53125bfb 100644 --- a/src/store/data/actions.ts +++ b/src/store/data/actions.ts @@ -442,17 +442,6 @@ const actions: ActionTree = { return hash; } } catch (err) { - if (err instanceof Error) { - commit( - 'notifications/add', - { - type: 'danger', - message: 'Getting validator self stake failed:' + err.message, - }, - { root: true } - ); - } - throw err; } finally { commit('setLoadingSignTransaction', false); diff --git a/src/store/data/getters.ts b/src/store/data/getters.ts index df2409bc..a2f7788f 100644 --- a/src/store/data/getters.ts +++ b/src/store/data/getters.ts @@ -4,7 +4,7 @@ import { StateInterface } from '../index'; import { DataStateInterface } from './state'; import { bigFigureOrShortDecimals, percent } from 'src/common/numbers'; import { Dictionary, keyBy, reduce, reverse, sortBy, take } from 'lodash'; -import { Validator, ValidatorMap, Reward, ValidatorStatus } from 'src/models'; +import { Validator, ValidatorMap, Reward, ValidatorStatus, ProposalStatus } from 'src/models'; const getters: GetterTree = { totalRewardsPerDenom({ rewards }) { @@ -77,6 +77,9 @@ const getters: GetterTree = { activeValidators({ validators }) { return validators.filter(el => el.status === ValidatorStatus.ACTIVE); }, + votingProposalsCount({ proposals }) { + return proposals.filter(el => el.status === ProposalStatus.VOTING).length; + }, supplyInfo({ supplyInfo }) { if (supplyInfo) { return { From 58dcbda3443b249dd709151010850635232999f6 Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Thu, 13 Jan 2022 20:40:16 +0100 Subject: [PATCH 02/12] Fix issue #23 #19 #18 --- src/components/BalancesTable.vue | 205 +++++++++++++++++++++++++ src/components/ProposalsSummary.vue | 58 +++++++ src/layouts/MainLayout.vue | 1 + src/models/supply.ts | 7 + src/modules/wallet/routes.ts | 8 + src/modules/wallet/views/Portfolio.vue | 52 +++---- src/modules/wallet/views/Proposals.vue | 7 +- src/modules/wallet/views/Stats.vue | 99 ++++++++++++ src/services/cosmos.ts | 9 +- src/store/authentication/actions.ts | 2 + src/store/authentication/mutations.ts | 2 +- src/store/data/actions.ts | 37 ++++- src/store/data/getters.ts | 74 ++++++++- src/store/data/mutations.ts | 19 ++- src/store/data/state.ts | 13 +- 15 files changed, 548 insertions(+), 45 deletions(-) create mode 100644 src/components/BalancesTable.vue create mode 100644 src/components/ProposalsSummary.vue create mode 100644 src/modules/wallet/views/Stats.vue diff --git a/src/components/BalancesTable.vue b/src/components/BalancesTable.vue new file mode 100644 index 00000000..b905ac42 --- /dev/null +++ b/src/components/BalancesTable.vue @@ -0,0 +1,205 @@ + + + + + diff --git a/src/components/ProposalsSummary.vue b/src/components/ProposalsSummary.vue new file mode 100644 index 00000000..8ac7955f --- /dev/null +++ b/src/components/ProposalsSummary.vue @@ -0,0 +1,58 @@ + + + + + diff --git a/src/layouts/MainLayout.vue b/src/layouts/MainLayout.vue index 9f08a471..2976fbdf 100644 --- a/src/layouts/MainLayout.vue +++ b/src/layouts/MainLayout.vue @@ -47,6 +47,7 @@ + diff --git a/src/models/supply.ts b/src/models/supply.ts index 0623f54f..fcfdda88 100644 --- a/src/models/supply.ts +++ b/src/models/supply.ts @@ -1,3 +1,6 @@ +import { Coin } from '@cosmjs/stargate'; +import { PaginationResponse } from './balances'; + export interface SupplyResponse { circulatingSupply: string; communityPool: string; @@ -6,3 +9,7 @@ export interface SupplyResponse { ethSupply: string; totalSupply: string; } + +export interface BankSupplyResponse extends PaginationResponse { + supply: Coin[]; +} diff --git a/src/modules/wallet/routes.ts b/src/modules/wallet/routes.ts index 7346c9c2..98f11e81 100644 --- a/src/modules/wallet/routes.ts +++ b/src/modules/wallet/routes.ts @@ -15,6 +15,14 @@ export default [ title: 'Portfolio' }, }, + { + path: 'Stats', + name: 'stats', + component: () => import('./views/Stats.vue'), + meta: { + title: 'Stats' + }, + }, { path: 'validators', name: 'validators', diff --git a/src/modules/wallet/views/Portfolio.vue b/src/modules/wallet/views/Portfolio.vue index cce4a2c6..f246f5bb 100644 --- a/src/modules/wallet/views/Portfolio.vue +++ b/src/modules/wallet/views/Portfolio.vue @@ -12,6 +12,23 @@ + +
+
+

+ Your Assets +

+
+ + +
+
+ - -
-

- Chain Stats -

-
- - -
- - - -
-
@@ -76,13 +74,13 @@ import { defineComponent, computed } from 'vue'; import { useQuasar } from 'quasar'; import { useStore } from 'src/store'; -import { SupplyResponse, Validator } from 'src/models'; +import { Balance, Validator } from 'src/models'; import BalanceSummary from 'src/components/BalanceSummary.vue'; import ValidatorsSummary from 'src/components/ValidatorsSummary.vue'; +import BalancesTable from 'src/components/BalancesTable.vue'; import ValidatorsTable from 'src/components/ValidatorsTable.vue'; import ClaimDialog from 'src/components/ClaimDialog.vue'; -import ChainStats from 'src/components/ChainStats.vue'; export default defineComponent({ name: 'Portfolio', @@ -90,7 +88,7 @@ export default defineComponent({ BalanceSummary, ValidatorsSummary, ValidatorsTable, - ChainStats + BalancesTable }, setup() { const store = useStore(); @@ -99,15 +97,15 @@ export default defineComponent({ const rewards = computed(() => store.state.data.rewards); const session = computed(() => store.state.authentication.session); + const balances = computed(() => store.getters['data/balances'] as Balance[]); + const balancesLoaded = computed(() => store.state.data.balancesLoaded); + const validatorsOfDelegations = computed(() => store.getters['data/validatorsOfDelegations'] as Validator[]); const delegationsLoaded = computed(() => store.state.data.delegationsLoaded); const validatorsOfUndelegations = computed(() => store.getters['data/validatorsOfUndelegations'] as Validator[]); const undelegationsLoaded = computed(() => store.state.data.undelegationsLoaded); - const supplyInfo = computed(() => store.getters['data/supplyInfo'] as SupplyResponse | null); - const loadingSupplyInfo = computed(() => store.state.data.loadingSupplyInfo); - const openClaimDialog = () => { quasar.dialog({ component: ClaimDialog, @@ -118,8 +116,8 @@ export default defineComponent({ return { session, - supplyInfo, - loadingSupplyInfo, + balances, + balancesLoaded, rewards, validatorsOfDelegations, delegationsLoaded, diff --git a/src/modules/wallet/views/Proposals.vue b/src/modules/wallet/views/Proposals.vue index e7b31d61..e9914c7c 100644 --- a/src/modules/wallet/views/Proposals.vue +++ b/src/modules/wallet/views/Proposals.vue @@ -24,7 +24,10 @@ @@ -38,11 +41,13 @@ import { useStore } from 'src/store'; import { ProposalStatus } from 'src/models'; import ProposalItem from 'src/components/ProposalItem.vue'; +import ProposalsSummary from 'src/components/ProposalsSummary.vue'; export default defineComponent({ name: 'Proposals', components: { ProposalItem, + ProposalsSummary }, setup() { const store = useStore(); diff --git a/src/modules/wallet/views/Stats.vue b/src/modules/wallet/views/Stats.vue new file mode 100644 index 00000000..b34dd6ef --- /dev/null +++ b/src/modules/wallet/views/Stats.vue @@ -0,0 +1,99 @@ + + + + + diff --git a/src/services/cosmos.ts b/src/services/cosmos.ts index a5c1bea5..4208d09d 100644 --- a/src/services/cosmos.ts +++ b/src/services/cosmos.ts @@ -39,7 +39,8 @@ import { ValidatorsDelegationResponse, AccountResponse, AccountInfo, - InflationResponse + InflationResponse, + BankSupplyResponse } from 'src/models'; import { chunk, compact, orderBy, reduce } from 'lodash'; import Store from 'src/store'; @@ -164,6 +165,12 @@ export const getAnnualProvision = async () => { return response.data.annual_provisions; } +export const getSupply = async () => { + const response = await api.get('cosmos/bank/v1beta1/supply'); + + return response.data; +} + export const getPool = async () => { const response = await api.get('cosmos/staking/v1beta1/pool'); diff --git a/src/store/authentication/actions.ts b/src/store/authentication/actions.ts index 52fe668d..f6d6dcb6 100644 --- a/src/store/authentication/actions.ts +++ b/src/store/authentication/actions.ts @@ -36,6 +36,8 @@ const actions: ActionTree = { }, async init({ dispatch, commit, state, rootState }) { try { + await dispatch('data/resetSessionData', undefined, { root: true }); + if (state.session && state.session.sessionType === SessionType.KEPLR) { await dispatch('keplr/init', 0, { root: true }); await dispatch('signIn', { diff --git a/src/store/authentication/mutations.ts b/src/store/authentication/mutations.ts index 8e531a4a..1677c563 100644 --- a/src/store/authentication/mutations.ts +++ b/src/store/authentication/mutations.ts @@ -7,7 +7,7 @@ const mutation: MutationTree = { state.session = session; }, setNetwork(state, network: NetworkConfig) { - state.network = network; + state.network = Object.assign({ supplyURL: undefined } , network); }, setLoading(state, loading: boolean) { state.loading = loading; diff --git a/src/store/data/actions.ts b/src/store/data/actions.ts index 53125bfb..76817541 100644 --- a/src/store/data/actions.ts +++ b/src/store/data/actions.ts @@ -15,13 +15,17 @@ import { getAccountInfo, getSupplyInfo, getPool, - getInflation + getInflation, + getSupply, + getCommunityPool } from 'src/services'; import { keyBy } from 'lodash'; import { updateValidatorImages } from 'src/common/keybase'; import { AccountInfo, BlockReduced, TransactionRequest, Validator } from 'src/models'; import { createSignBroadcast, pollTxInclusion } from 'src/signing/transaction-manager'; import { getAPR } from 'src/common/numbers'; +import { getCoinLookup } from 'src/common/network'; +import { getStakingCoinViewAmount } from 'src/common/cosmos-reducer'; const actions: ActionTree = { resetSessionData({ commit }) { @@ -125,17 +129,34 @@ const actions: ActionTree = { await dispatch('getAPR'); } }, - async getAPR({ commit, state }) { + async getAPR({ commit, rootState }) { try { commit('setLoadingAPR', true); - if (state.supplyInfo) { - const pool = await getPool(); - const inflation = await getInflation(); - const apr = getAPR(state.supplyInfo.chainSupply, inflation.inflation, pool.pool.bonded_tokens); + const totalSupply = await getSupply(); + const communityPool = await getCommunityPool(); - commit('setApr', apr.toString()); - } + commit('setSupply', totalSupply.supply); + commit('setCommunityPool', communityPool.pool); + + const supplyCoin = getCoinLookup( + rootState.authentication.network.stakingDenom, + 'viewDenom' + ); + + const supplyChainDenom = supplyCoin?.chainDenom; + const chainSupplyTotal = totalSupply.supply.find(el => el.denom === supplyChainDenom); + const chainSupplyCoin = getStakingCoinViewAmount(chainSupplyTotal ? chainSupplyTotal.amount : '0') + + const chainSupply = chainSupplyCoin.toString(); + + const pool = await getPool(); + const inflation = await getInflation(); + const apr = getAPR(chainSupply, inflation.inflation, pool.pool.bonded_tokens); + + commit('setApr', apr.toString()); + commit('setPool', pool.pool); + commit('setInflation', inflation.inflation); } catch (err) { if (err instanceof Error) { commit( diff --git a/src/store/data/getters.ts b/src/store/data/getters.ts index a2f7788f..326c5818 100644 --- a/src/store/data/getters.ts +++ b/src/store/data/getters.ts @@ -5,6 +5,7 @@ import { DataStateInterface } from './state'; import { bigFigureOrShortDecimals, percent } from 'src/common/numbers'; import { Dictionary, keyBy, reduce, reverse, sortBy, take } from 'lodash'; import { Validator, ValidatorMap, Reward, ValidatorStatus, ProposalStatus } from 'src/models'; +import { getStakingCoinViewAmount } from 'src/common/cosmos-reducer'; const getters: GetterTree = { totalRewardsPerDenom({ rewards }) { @@ -31,6 +32,22 @@ const getters: GetterTree = { }, {}); }; }, + balances({ balances }, _getters, { authentication }) { + return balances.filter( + balance => balance.denom !== authentication.network.stakingDenom + ).map( + balance => { + const total = getStakingCoinViewAmount(new BigNumber(balance.total).toString()); + const available = getStakingCoinViewAmount(new BigNumber(balance.available).toString()); + + return ({ + ...balance, + total: bigFigureOrShortDecimals(total), + available: bigFigureOrShortDecimals(available), + }); + } + ); + }, currentBalance({ balances }) { const balance = [...balances].pop(); @@ -80,7 +97,35 @@ const getters: GetterTree = { votingProposalsCount({ proposals }) { return proposals.filter(el => el.status === ProposalStatus.VOTING).length; }, - supplyInfo({ supplyInfo }) { + getTotalSupply({ supply }) { + if (supply.length > 0) { + let total = new BigNumber('0'); + + supply.forEach(coin => { + const amount = getStakingCoinViewAmount(coin ? coin.amount : '0'); + total = total.plus(new BigNumber(amount)); + }); + + return total.toString(); + } + + return null; + }, + getCommunityPool({ communityPool }) { + if (communityPool.length > 0) { + let total = new BigNumber('0'); + + communityPool.forEach(coin => { + const amount = getStakingCoinViewAmount(coin ? coin.amount : '0'); + total = total.plus(new BigNumber(amount)); + }); + + return total.toString(); + } + + return null; + }, + supplyInfo({ supplyInfo }, getters, { authentication }) { if (supplyInfo) { return { ...supplyInfo, @@ -88,13 +133,34 @@ const getters: GetterTree = { communityPool: `${bigFigureOrShortDecimals(new BigNumber(supplyInfo.communityPool).toString()) ?? ''} ${supplyInfo.denom}`, totalSupply: `${bigFigureOrShortDecimals(new BigNumber(supplyInfo.totalSupply).toString()) ?? ''} ${supplyInfo.denom}` }; - } + } else { + const totalSupply = getters['getTotalSupply'] as string | null; + const communityPool = getters['getCommunityPool'] as string | null; - return null; + return { + totalSupply: totalSupply ? `${bigFigureOrShortDecimals(totalSupply) ?? ''} ${authentication.network.stakingDenom}` : null, + communityPool: communityPool ? `${bigFigureOrShortDecimals(communityPool) ?? ''} ${authentication.network.stakingDenom}` : null, + } + } }, getAprInfo({ apr }) { return percent(new BigNumber(apr).toFixed(4)); - } + }, + getInflation({ inflation }) { + if (inflation) { + return percent(new BigNumber(inflation).toFixed(4)); + } + + return null; + }, + getBondedTokens({ pool }, _getters, { authentication }) { + if (pool) { + const bondedTokensNumber = new BigNumber(getStakingCoinViewAmount(pool.bonded_tokens)); + return `${bigFigureOrShortDecimals(bondedTokensNumber.toString()) ?? ''} ${authentication.network.stakingDenom}`; + } + + return null; + }, } export default getters diff --git a/src/store/data/mutations.ts b/src/store/data/mutations.ts index 52da13e5..6d57ab06 100644 --- a/src/store/data/mutations.ts +++ b/src/store/data/mutations.ts @@ -1,4 +1,5 @@ -import { Balance, BlockReduced, Delegation, GovernanceOverview, Proposal, Reward, SupplyResponse, UnbondingDelegation, Validator } from 'src/models'; +import { Coin } from '@cosmjs/stargate'; +import { Balance, BlockReduced, Delegation, GovernanceOverview, Pool, Proposal, Reward, SupplyResponse, UnbondingDelegation, Validator } from 'src/models'; import { MutationTree } from 'vuex'; import { DataStateInterface } from './state'; @@ -81,8 +82,24 @@ const mutation: MutationTree = { setApr(state, apr: string) { state.apr = apr; }, + setPool(state, pool: Pool) { + state.pool = pool; + }, + setInflation(state, inflation: string) { + state.inflation = inflation; + }, + setSupply(state, supply: Coin[]) { + state.supply = supply; + }, + setCommunityPool(state, communityPool: Coin[]) { + state.communityPool = communityPool; + }, resetSessionData(state) { state.supplyInfo = null; + state.inflation = null; + state.supply = []; + state.communityPool = []; + state.pool = null; state.apr = '0'; state.balances = []; state.rewards = []; diff --git a/src/store/data/state.ts b/src/store/data/state.ts index cb115e00..cdd59418 100644 --- a/src/store/data/state.ts +++ b/src/store/data/state.ts @@ -1,4 +1,5 @@ -import { Balance, BlockReduced, Delegation, GovernanceOverview, Proposal, Reward, SupplyResponse, UnbondingDelegation, Validator } from 'src/models'; +import { Coin } from '@cosmjs/stargate'; +import { Balance, BlockReduced, Delegation, GovernanceOverview, Pool, Proposal, Reward, SupplyResponse, UnbondingDelegation, Validator } from 'src/models'; export interface DataStateInterface { block: BlockReduced | undefined; @@ -26,8 +27,12 @@ export interface DataStateInterface { loadingSignTransaction: boolean; loading: boolean; loadingDataDetails: boolean; + supply: Coin[]; + communityPool: Coin[]; apr: string; loadingApr: boolean; + inflation: string | null; + pool: Pool | null; } function state (): DataStateInterface { @@ -57,8 +62,12 @@ function state (): DataStateInterface { loadingDataDetails: false, supplyInfo: null, loadingSupplyInfo: false, + supply: [], + communityPool: [], apr: '0', - loadingApr: false + loadingApr: false, + inflation: null, + pool: null } } From 3c1542b82d8592258b41ecc206722c7a175e8900 Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Thu, 13 Jan 2022 22:47:31 +0100 Subject: [PATCH 03/12] Minor fix for loading state Fix supplyURL --- src/constants/network.ts | 3 +++ src/hooks/useChangeNetwork.ts | 2 +- src/layouts/MainLayout.vue | 1 + src/modules/authentication/views/LoginHome.vue | 3 ++- src/store/authentication/actions.ts | 1 + src/store/authentication/mutations.ts | 3 ++- src/store/data/actions.ts | 11 ----------- 7 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/constants/network.ts b/src/constants/network.ts index b4486bd4..847726a0 100644 --- a/src/constants/network.ts +++ b/src/constants/network.ts @@ -136,6 +136,7 @@ export const networks: NetworkConfig[] = [ apiURL: 'https://lcd-osmosis.keplr.app', rpcURL: 'https://rpc-osmosis.itastakers.com', explorerURL: 'https://www.mintscan.io/osmosis/', + supplyURL: undefined, minBlockHeight: 2742000, stakingDenom: 'OSMO', coinLookup: [ @@ -176,6 +177,7 @@ export const networks: NetworkConfig[] = [ apiURL: 'https://lcd-cosmoshub.keplr.app', rpcURL: 'https://rpc-cosmoshub.keplr.app', explorerURL: 'https://www.mintscan.io/cosmos/', + supplyURL: undefined, minBlockHeight: 9054000, stakingDenom: 'ATOM', coinLookup: [ @@ -217,6 +219,7 @@ export const networks: NetworkConfig[] = [ rpcURL: 'https://rpc.chihuahua.wtf', explorerURL: 'https://www.mintscan.io/chihuahua/', minBlockHeight: 1, + supplyURL: undefined, stakingDenom: 'HUAHUA', coinLookup: [ { diff --git a/src/hooks/useChangeNetwork.ts b/src/hooks/useChangeNetwork.ts index bb3cdad3..379bfd5c 100644 --- a/src/hooks/useChangeNetwork.ts +++ b/src/hooks/useChangeNetwork.ts @@ -6,7 +6,7 @@ import { networks } from 'src/constants'; export const useChangeNetwork = (onChange?: () => Promise) => { const store = useStore(); const router = useRouter(); - const loadingNetwork = computed(() => store.state.authentication.changing); + const loadingNetwork = computed(() => store.state.authentication.changing || store.state.authentication.loading); const network = computed({ get: () => store.state.authentication.network, diff --git a/src/layouts/MainLayout.vue b/src/layouts/MainLayout.vue index 2976fbdf..737372c1 100644 --- a/src/layouts/MainLayout.vue +++ b/src/layouts/MainLayout.vue @@ -67,6 +67,7 @@ no-error-icon hide-bottom-space :loading="loadingNetwork" + :disable="loadingNetwork" :options-cover="false" >