Merge branch 'master' into patch-1

This commit is contained in:
ping 2023-02-05 08:47:00 +08:00 committed by GitHub
commit 7b758083d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
70 changed files with 1433 additions and 565 deletions

View File

@ -12,13 +12,14 @@ jobs:
name: Ping deploy name: Ping deploy
runs-on: mainnet runs-on: mainnet
steps: steps:
- name: print - name: Environment
run: echo ${GITHUB_REF#refs/heads/} run: export NODE_OPTIONS="--max_old_space_size=4096"
- name: Git Checkout Latest - name: Git Checkout Latest
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: Install - name: Install
run: yarn install run: yarn install --ignore-engines
- name: Build - name: Build
run: yarn run vue-cli-service build run: yarn run vue-cli-service build

2
.gitignore vendored
View File

@ -32,3 +32,5 @@ yarn-error.log*
.yarn/ .yarn/
.yarnrc.yml .yarnrc.yml
package-lock.json package-lock.json
yarn.lock
pkg/

View File

@ -15,22 +15,24 @@
</div> </div>
Ping Explorer is a light explorer for Cosmos-based Blockchains. https://ping.pub . `Ping Dashboard` is a light explorer for Cosmos-based Blockchains. https://ping.pub .
## What is the difference between Ping explorer and other explorers? ## What is the difference between Ping explorer and other explorers?
Ping Explorer is designed to explore blockchain data as real as possible, therefore there is no cache, no pre-processing. Ping Explorer does not cache/save blockchain data on its server. Ping Explorer only fetch data from Cosmos full node via LCD/RPC endpoints. We call it "Light Explorer". `Ping Dashboard` is designed to explore blockchain data as real as possible, therefore there is no cache, no pre-processing. `Ping Dashboard` only fetch data from Cosmos full node via LCD/RPC endpoints. We call it "Light Explorer".
## Do you want to list your blockchain on ping.pub? ## Do you want to list your blockchain on ping.pub?
Pull your request [here](./src/chains), We will add your chains as soon as possible. It is **FREE** (You must have 10+ independent validators on your chain). Submit your pull request [here](./src/chains), We will add your chains as soon as possible. It is **FREE** (You must have 10+ independent validators on your chain).
We remain neutral to all chains, and we do not comment on their market prospects, technical risks, or investment risks. The only condition we list on ping.pub is if there are ten validators, and we cannot determine if these validators are controlled by the same entity.
## Why Ping explorer use official/trusted third party public LCD/rpc server? ## Why Ping explorer use official/trusted third party public LCD/rpc server?
We have two considerations: There are two main reasons:
- Trust, In decentralize system, everything controlled by one single team/organization could be risks. So we decided to co-build with the community. - Trust, in a decentralized system, anything controlled by one entity cannot be trusted. So we decided to build with the community.
- Limited Resources: ` Ping Dashboard ` will list hundreds cosmos-based blockchains in the future, it's impossible for our team to run validators or fullnodes for all of those chains. - Limited resources: `Ping Dashboard` will list hundreds of cosmos-based blockchains in the future, and it is impossible for our team to run validators or full nodes for all of them.
## Donation ## Donation

BIN
public/logos/c4e.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

BIN
public/logos/cronos.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

BIN
public/logos/mars.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

BIN
public/logos/mars.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 KiB

BIN
public/logos/planq.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
public/logos/quasar.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -31,7 +31,7 @@
{{ chainname }} {{ chainname }}
</b-breadcrumb-item> </b-breadcrumb-item>
<b-breadcrumb-item <b-breadcrumb-item
v-for="item in $route.meta.breadcrumb" v-for="item in breadcrumb"
:key="item.text" :key="item.text"
:active="item.active" :active="item.active"
:to="item.to" :to="item.to"
@ -75,6 +75,14 @@ export default {
chainname() { chainname() {
return this.$store?.state?.chains?.selected?.chain_name return this.$store?.state?.chains?.selected?.chain_name
}, },
/**
* Invoke `route.meta.breadcrumb($route)` if breadcrumb is callable.
*/
breadcrumb() {
const { breadcrumb } = this.$route.meta
const breadcrumbIsCallable = typeof breadcrumb === 'function'
return breadcrumbIsCallable ? breadcrumb(this.$route) : breadcrumb
},
}, },
} }
</script> </script>

View File

@ -1,53 +1,53 @@
export default () => ([ export default () => ([
{ {
scope: 'normal', scope: 'normal',
title: 'dashboard', title: 'dashboard.dashboard',
route: 'dashboard', route: 'dashboard',
}, },
{ {
scope: 'normal', scope: 'normal',
title: 'blocks', title: 'dashboard.blocks',
route: 'blocks', route: 'blocks',
}, },
{ {
scope: 'normal', scope: 'normal',
title: 'staking', title: 'dashboard.staking',
route: 'staking', route: 'staking',
}, },
{ {
scope: 'normal', scope: 'normal',
title: 'governance', title: 'dashboard.governance',
route: 'governance', route: 'governance',
exclude: 'emoney', exclude: 'emoney',
}, },
{ {
scope: 'normal', scope: 'normal',
title: 'uptime', title: 'dashboard.uptime',
route: 'uptime', route: 'uptime',
}, },
{ {
scope: 'normal', scope: 'normal',
title: 'parameters', title: 'dashboard.parameters',
route: 'parameters', route: 'parameters',
}, },
{ {
scope: 'normal', scope: 'normal',
title: 'statesync', title: 'dashboard.statesync',
route: 'statesync', route: 'statesync',
}, },
{ {
scope: 'normal', scope: 'normal',
title: 'consensus', title: 'dashboard.consensus',
route: 'consensus', route: 'consensus',
}, },
{ {
scope: 'cos-mos', scope: 'cos-mos',
title: 'gravity', title: 'dashboard.gravity',
route: 'gravity', route: 'gravity',
}, },
{ {
scope: 'osmosis', scope: 'osmosis',
title: 'trade', title: 'dashboard.trade',
route: 'osmosis-trade', route: 'osmosis-trade',
}, },
]) ])

View File

@ -22,3 +22,28 @@
.progress { .progress {
border-radius: 3px; border-radius: 3px;
} }
.scale {
width: 100%;
height: 3em;
position: relative;
/* margin: 30px; // */
}
.box {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
padding-top: 0.5em;
/* opacity: 0.7; /**/
background: transparent;
}
.overlay {
z-index: 9;
width: 2px;
border-right-color: green;
border-right-width: 2px;
border-right-style: dotted;
}

View File

@ -1,7 +1,6 @@
{ {
"chain_name": "agoric", "chain_name": "agoric",
"api": [ "api": [
"https://api.agoric.sgtstake.com",
"https://agoric-api.polkachu.com", "https://agoric-api.polkachu.com",
"https://api-agoric.nodes.guru", "https://api-agoric.nodes.guru",
"https://agoric.stakesystems.io", "https://agoric.stakesystems.io",

View File

@ -4,7 +4,7 @@
"api": ["https://rest.getbze.com"], "api": ["https://rest.getbze.com"],
"rpc": ["https://rpc-1.getbze.com:443","https://rpc-2.getbze.com:443"], "rpc": ["https://rpc-1.getbze.com:443","https://rpc-2.getbze.com:443"],
"snapshot_provider": ["a9fac0534bd6853f5810fdc692564967bd01b1fe@rpc-1.getbze.com:26656"], "snapshot_provider": ["a9fac0534bd6853f5810fdc692564967bd01b1fe@rpc-1.getbze.com:26656"],
"sdk_version": "0.44.3", "sdk_version": "0.45.9",
"coin_type": "370", "coin_type": "370",
"min_tx_fee": "8000", "min_tx_fee": "8000",
"addr_prefix": "bze", "addr_prefix": "bze",

View File

@ -6,7 +6,7 @@
"snapshot_provider": "29edc55748bc341224f711a05cb0a9f6d73b4da3@bitcanna.rpc.ping.pub:26656", "snapshot_provider": "29edc55748bc341224f711a05cb0a9f6d73b4da3@bitcanna.rpc.ping.pub:26656",
"sdk_version": "0.45.10", "sdk_version": "0.45.10",
"coin_type": "118", "coin_type": "118",
"min_tx_fee": "8000", "min_tx_fee": "420",
"assets": [{ "assets": [{
"base": "ubcna", "base": "ubcna",
"symbol": "BCNA", "symbol": "BCNA",

View File

@ -0,0 +1,16 @@
{
"chain_name": "chain4energy",
"api": ["https://lcd.c4e.io"],
"rpc": ["https://rpc.c4e.io:443", "https://rpc.c4e.io:443"],
"sdk_version": "0.45.5",
"coin_type": "4444",
"min_tx_fee": "3000",
"addr_prefix": "c4e",
"logo": "/logos/c4e.png",
"assets": [{
"base": "uc4e",
"symbol": "C4E",
"exponent": "6",
"logo": "/logos/c4e.png"
}]
}

View File

@ -0,0 +1,17 @@
{
"chain_name": "cronos",
"api": ["https://rest.cronos.org"],
"rpc": ["https://rpc.cronos.org:443"],
"snapshot_provider": "",
"sdk_version": "0.45.11",
"coin_type": "60",
"min_tx_fee": "5000000000000000",
"addr_prefix": "crc",
"logo": "/logos/cronos.png",
"assets": [{
"base": "basecro",
"symbol": "CRO",
"exponent": "18"
}]
}

View File

@ -1,7 +1,7 @@
{ {
"chain_name": "injective", "chain_name": "injective",
"api": "https://lcd.injective.network", "api": ["https://lcd.injective.network", "https://injective-api.polkachu.com"],
"rpc": ["https://injective-rpc.api.chainlayer.network:443", "https://injective-rpc.api.chainlayer.network:443"], "rpc": ["https://tm.injective.network", "https://injective-rpc.polkachu.com"],
"snapshot_provider": "", "snapshot_provider": "",
"sdk_version": "v0.45.5", "sdk_version": "v0.45.5",
"coin_type": "60", "coin_type": "60",
@ -9,6 +9,12 @@
"addr_prefix": "inj", "addr_prefix": "inj",
"excludes": "", "excludes": "",
"logo": "/logos/injective.jpg", "logo": "/logos/injective.jpg",
"keplr_features": ["ibc-transfer", "ibc-go", "eth-address-gen", "eth-key-sign"],
"keplr_price_step": {
"low": 100000000000,
"average": 200000000000,
"high": 30000000000000
},
"assets": [{ "assets": [{
"base": "inj", "base": "inj",
"symbol": "INJ", "symbol": "INJ",

View File

@ -1,18 +1,28 @@
{ {
"chain_name": "jackal", "chain_name": "jackal",
"coingecko": "", "coingecko": "jackal-protocol",
"api": ["https://api.jackalprotocol.com", "https://jackal-api.polkachu.com","https://api.jackal.nodestake.top"], "api": [
"rpc": ["https://rpc.jackalprotocol.com", "https://jackal-rpc.polkachu.com","https://rpc.jackal.nodestake.top"], "https://api.jackalprotocol.com",
"https://jackal-api.polkachu.com",
"https://api.jackal.nodestake.top"
],
"rpc": [
"https://rpc.jackalprotocol.com",
"https://jackal-rpc.polkachu.com",
"https://rpc.jackal.nodestake.top"
],
"snapshot_provider": "", "snapshot_provider": "",
"coin_type": "118", "coin_type": "118",
"sdk_version": "0.45.9", "sdk_version": "0.45.11",
"addr_prefix": "jkl", "addr_prefix": "jkl",
"logo": "/logos/jackal.png", "logo": "/logos/jackal.png",
"assets": [{ "assets": [
"base": "ujkl", {
"symbol": "JKL", "base": "ujkl",
"exponent": "6", "symbol": "JKL",
"coingecko_id": "jackal", "exponent": "6",
"logo": "/logos/jackal.png" "coingecko_id": "jackal",
}] "logo": "/logos/jackal.png"
}
]
} }

View File

@ -1,8 +1,8 @@
{ {
"chain_name": "lumenx", "chain_name": "lumenx",
"coingecko": "", "coingecko": "",
"api": "https://api.helios-1.lumenex.io", "api": ["https://api.lumenx.chaintools.tech:443","https://api-lumenx.cryptonet.pl:443"],
"rpc": ["https://rpc.helios-1.lumenex.io:443","http://node4.lumenex.io:26657"], "rpc": ["https://rpc.lumenx.chaintools.tech:443","https://rpc-lumenx.cryptonet.pl:443"],
"snapshot_provider": "", "snapshot_provider": "",
"sdk_version": "0.45.5", "sdk_version": "0.45.5",
"coin_type": "118", "coin_type": "118",

View File

@ -0,0 +1,29 @@
{
"chain_name": "mars",
"coingecko": "",
"api": [
"https://rest.marsprotocol.io",
"https://mars-api.polkachu.com",
"https://rest.cosmos.directory/mars"
],
"rpc": [
"https://rpc.marsprotocol.io",
"https://mars-rpc.polkachu.com",
"https://rpc.marsprotocol.io",
"https://rpc.cosmos.directory/mars"
],
"snapshot_provider": "",
"coin_type": "118",
"sdk_version": "0.46.8",
"addr_prefix": "mars",
"logo": "/logos/mars.png",
"assets": [
{
"base": "umars",
"symbol": "MARS",
"exponent": "6",
"coingecko_id": "",
"logo": "/logos/mars.png"
}
]
}

View File

@ -0,0 +1,19 @@
{
"chain_name": "planq",
"api": ["https://rest.planq.network"],
"rpc": ["https://rpc.planq.network"],
"snapshot_provider": "",
"sdk_version": "0.46.3",
"coin_type": "60",
"min_tx_fee": "5000000000000000",
"addr_prefix": "plq",
"logo": "/logos/planq.png",
"keplr_features": ["ibc-transfer", "ibc-go", "eth-address-gen", "eth-key-sign"],
"assets": [{
"base": "aplanq",
"symbol": "planq",
"exponent": "18",
"coingecko_id": "",
"logo": "/logos/planq.png"
}]
}

View File

@ -0,0 +1,20 @@
{
"chain_name": "quicksilver",
"coingecko": "",
"api": ["https://quicksilver-api.polkachu.com", "https://api-quicksilver.nodeist.net"],
"rpc": ["https://quicksilver-rpc.polkachu.com", "https://rpc-quicksilver.nodeist.net"],
"sdk_version": "0.46.7",
"coin_type": "118",
"min_tx_fee": "8000",
"addr_prefix": "quick",
"logo": "/logos/quicksilver.png",
"assets": [
{
"base": "uqck",
"symbol": "QCK",
"exponent": "6",
"coingecko_id": "",
"logo": "/logos/quicksilver.png"
}
]
}

View File

@ -1,7 +1,7 @@
{ {
"chain_name": "rebus", "chain_name": "rebus",
"api": ["https://api.mainnet.rebus.money:1317", "https://rebus.api.kjnodes.com"], "api": ["https://api.mainnet.rebus.money:1317","https://api.rebus.nodestake.top"],
"rpc": ["https://api.mainnet.rebus.money:26657", "https://rebus.rpc.kjnodes.com:443"], "rpc": ["https://api.mainnet.rebus.money:26657","https://rpc.rebus.nodestake.top"],
"snapshot_provider": "", "snapshot_provider": "",
"sdk_version": "0.45.6", "sdk_version": "0.45.6",
"coin_type": "118", "coin_type": "118",

View File

@ -1,8 +1,8 @@
{ {
"chain_name": "secret", "chain_name": "secret",
"coingecko": "secret", "coingecko": "secret",
"api": ["https://api.roninventures.io","https://api.scrt.network"], "api": ["https://lcd.spartanapi.dev", "https://secretnetwork-lcd.stakely.io"],
"rpc": ["http://beta-api.scrt.network:26657", "https://api.scrt.network:443"], "rpc": ["https://rpc.spartanapi.dev", "https://secretnetwork-rpc.stakely.io"],
"snapshot_provider": "", "snapshot_provider": "",
"sdk_version": "0.45.4", "sdk_version": "0.45.4",
"coin_type": "529", "coin_type": "529",

View File

@ -2,10 +2,10 @@
{ {
"chain_name": "shentu", "chain_name": "shentu",
"coingecko": "certik", "coingecko": "certik",
"api": ["https://certik-api.polkachu.com/", "https://shentu-api.panthea.eu", "https://chainfull.noopsbycertik.com"], "api": ["https://certik-api.polkachu.com", "https://chainfull.noopsbycertik.com"],
"rpc": ["https://certik-rpc.polkachu.com:443", "https://shentu-rpc.panthea.eu:443"], "rpc": ["https://certik-rpc.polkachu.com:443"],
"snapshot_provider": "", "snapshot_provider": "",
"sdk_version": "0.45.4", "sdk_version": "0.45.9",
"coin_type": "118", "coin_type": "118",
"min_tx_fee": "8000", "min_tx_fee": "8000",
"addr_prefix": "certik", "addr_prefix": "certik",

View File

@ -1,7 +1,7 @@
{ {
"chain_name": "teritori", "chain_name": "teritori",
"api": ["https://rest.mainnet.teritori.com", "https://teritori.api.kjnodes.com"], "api": ["https://rest.mainnet.teritori.com","https://api.teritori.nodestake.top"],
"rpc": ["https://rpc.mainnet.teritori.com", "https://teritori.rpc.kjnodes.com:443"], "rpc": ["https://rpc.mainnet.teritori.com","https://rpc.teritori.nodestake.top"],
"snapshot_provider": "", "snapshot_provider": "",
"sdk_version": "0.45.4", "sdk_version": "0.45.4",
"coin_type": "118", "coin_type": "118",

View File

@ -1,9 +1,9 @@
{ {
"chain_name": "vidulum", "chain_name": "vidulum",
"coingecko": "vidulum", "coingecko": "vidulum",
"api": ["https://mainnet-lcd.vidulum.app", "https://api-vidulum-ia.cosmosia.notional.ventures", "https://rest.rpc.erialos.me"], "api": ["https://mainnet-lcd.vidulum.app", "https://api-vidulum-ia.cosmosia.notional.ventures"],
"rpc": ["https://trpc.rpc.erialos.me:443","https://rpc-vidulum-ia.cosmosia.notional.ventures:443", "https://mainnet-rpc.vidulum.app:443"], "rpc": ["https://mainnet-rpc.vidulum.app:443", "https://rpc-vidulum-ia.cosmosia.notional.ventures:443"],
"snapshot_provider": "c32903505e9ab811ac46306d2913c98ccf4883ce@rpc.erialos.me:26656", "snapshot_provider": "",
"sdk_version": "0.45.9", "sdk_version": "0.45.9",
"coin_type": "370", "coin_type": "370",
"min_tx_fee": "8000", "min_tx_fee": "8000",

View File

@ -0,0 +1,20 @@
{
"chain_name": "apollo",
"provider_chain": {
"api": "https://rest.provider-sentry-01.goc.earthball.xyz"
},
"api": ["https://apollo.api.ping.pub"],
"rpc": [],
"sdk_version": "0.45.7",
"coin_type": 118,
"min_tx_fee": "0",
"addr_prefix": "cosmos",
"logo": "/logos/game_of_chain.jpeg",
"assets": [{
"base": "upol",
"symbol": "POL",
"exponent": "6",
"coingecko_id": "",
"logo": "/logos/game_of_chain.jpeg"
}]
}

View File

@ -0,0 +1,19 @@
{
"chain_name": "canto",
"api": ["https://canto-testnet.ansybl.io/api"],
"rpc": ["https://canto-testnet.ansybl.io/rpc"],
"snapshot_provider": "",
"sdk_version": "0.45.6",
"coin_type": "60",
"min_tx_fee": "800",
"addr_prefix": "canto",
"logo": "/logos/canto.png",
"assets": [
{
"base": "acanto",
"symbol": "CANTO",
"exponent": "18"
}
]
}

View File

@ -0,0 +1,19 @@
{
"chain_name": "celestia",
"coingecko": "",
"api": ["https://celestia-testnet-api.polkachu.com"],
"rpc": ["https://celestia-testnet-rpc.polkachu.com"],
"snapshot_provider": "",
"sdk_version": "0.46.0",
"coin_type": "118",
"min_tx_fee": "800",
"addr_prefix": "celestia",
"logo": "/logos/celestia.png",
"assets": [{
"base": "utia",
"symbol": "TIA",
"exponent": "6",
"coingecko_id": "",
"logo": "/logos/celestia.png"
}]
}

View File

@ -1,7 +1,17 @@
{ {
"chain_name": "cosmos-vega", "chain_name": "cosmos",
"api":"https://vega.api.ping.pub", "api": ["https://vega.api.ping.pub", "https://rest.seed-01.theta-testnet.polypore.xyz", "https://rest.seed-02.theta-testnet.polypore.xyz"],
"sdk_version": "0.42.9", "rpc": ["https://rpc.seed-01.theta-testnet.polypore.xyz", "https://rpc.seed-02.theta-testnet.polypore.xyz"],
"sdk_version": "0.45.1",
"coin_type": "118",
"min_tx_fee": "800",
"addr_prefix": "cosmos", "addr_prefix": "cosmos",
"logo": "https://dl.airtable.com/.attachments/e54f814bba8c0f9af8a3056020210de0/2d1155fb/cosmos-hub.svg" "logo": "/logos/cosmos.svg",
} "assets": [{
"base": "uatom",
"symbol": "ATOM",
"exponent": "6",
"coingecko_id": "cosmos",
"logo": "/logos/cosmos.svg"
}]
}

View File

@ -9,6 +9,7 @@
"min_tx_fee": "3000000000000000", "min_tx_fee": "3000000000000000",
"addr_prefix": "evmos", "addr_prefix": "evmos",
"logo": "/logos/evmos.jpeg", "logo": "/logos/evmos.jpeg",
"keplr_features": ["ibc-transfer", "ibc-go", "eth-address-gen", "eth-key-sign"],
"assets": [{ "assets": [{
"base": "atevmos", "base": "atevmos",
"symbol": "TEVMOS", "symbol": "TEVMOS",

View File

@ -0,0 +1,20 @@
{
"chain_name": "hero",
"provider_chain": {
"api": "https://rest.provider-sentry-01.goc.earthball.xyz"
},
"api": ["https://api-c.hero.nodestake.top"],
"rpc": ["https://rpc-c.hero.nodestake.top"],
"sdk_version": "0.45.7",
"coin_type": 118,
"min_tx_fee": "0",
"addr_prefix": "cosmos",
"logo": "/logos/game_of_chain.jpeg",
"assets": [{
"base": "uhero",
"symbol": "HERO",
"exponent": "6",
"coingecko_id": "",
"logo": "/logos/game_of_chain.jpeg"
}]
}

View File

@ -1,17 +1,23 @@
{ {
"chain_name": "jackal", "chain_name": "jackal",
"coingecko": "jackal", "coingecko": "jackal_protocol",
"api": "https://testnet-api.jackalprotocol.com", "api": [
"rpc": "https://testnet-rpc.jackalprotocol.com", "https://testnet-api.jackalprotocol.com"
],
"rpc": [
"https://testnet-rpc.jackalprotocol.com"
],
"coin_type": "118", "coin_type": "118",
"sdk_version": "0.45.9", "sdk_version": "0.45.11",
"addr_prefix": "jkl", "addr_prefix": "jkl",
"logo": "/logos/jackal.png", "logo": "/logos/jackal.png",
"assets": [{ "assets": [
"base": "ujkl", {
"symbol": "JKL", "base": "ujkl",
"exponent": "6", "symbol": "JKL",
"coingecko_id": "jackal", "exponent": "6",
"logo": "/logos/jackal.png" "coingecko_id": "jackal-protocol",
}] "logo": "/logos/jackal.png"
} }
]
}

View File

@ -1,8 +1,8 @@
{ {
"chain_name": "osmosis", "chain_name": "osmosis",
"coingecko": "osmosis", "coingecko": "osmosis",
"api": ["https://testnet-rest.osmosis.zone", "https://lcd.osmo-test.ccvalidators.com", "https://osmosistest-lcd.quickapi.com"], "api": ["https://lcd-test.osmosis.zone", "https://lcd.osmo-test.ccvalidators.com", "https://osmosistest-lcd.quickapi.com"],
"rpc": ["https://testnet-rpc.osmosis.zone:443", "https://rpc.osmo-test.ccvalidators.com:443"," https://osmosistest-rpc.quickapi.com:443"], "rpc": ["https://rpc-test.osmosis.zone", "https://testnet-rpc.osmosis.zone:443", "https://rpc.osmo-test.ccvalidators.com:443"," https://osmosistest-rpc.quickapi.com:443"],
"snapshot_provider": "", "snapshot_provider": "",
"sdk_version": "0.44.5", "sdk_version": "0.44.5",
"coin_type": "118", "coin_type": "118",

View File

@ -0,0 +1,17 @@
{
"chain_name": "provider",
"api": ["https://rest.provider-sentry-01.goc.earthball.xyz","https://rest.provider-sentry-02.goc.earthball.xyz"],
"rpc": ["https://rpc.provider-sentry-01.goc.earthball.xyz"],
"sdk_version": "0.45.7",
"coin_type": 118,
"min_tx_fee": "0",
"addr_prefix": "cosmos",
"logo": "/logos/game_of_chain.jpeg",
"assets": [{
"base": "uprov",
"symbol": "PROV",
"exponent": "6",
"coingecko_id": "",
"logo": "/logos/game_of_chain.jpeg"
}]
}

View File

@ -0,0 +1,20 @@
{
"chain_name": "quasar",
"coingecko": "",
"api": ["https://quasar-testnet-api.polkachu.com", "https://lcd-office.cosmostation.io/quasar-testnet"],
"rpc": ["https://quasar-testnet-rpc.polkachu.com", "https://rpc-office.cosmostation.io/quasar-testnet", "https://questnet.quasar-finance.rhinostake.com"],
"sdk_version": "0.45.6",
"coin_type": 118,
"min_tx_fee": "8000",
"addr_prefix": "quasar",
"logo": "/logos/quasar.png",
"assets": [
{
"base": "uqsr",
"symbol": "QSR",
"exponent": 6,
"coingecko_id": "",
"logo": "/logos/quasar.png"
}
]
}

View File

@ -1,8 +1,8 @@
{ {
"chain_name": "secret", "chain_name": "secret",
"coingecko": "secret", "coingecko": "secret",
"api": ["https://api.pulsar.scrttestnet.com","https://lcd.testnet.secretsaturn.net", "https://testnet-api.roninventures.io", "https://pulsar-2.api.trivium.network:1317"], "api": ["https://api.pulsar.scrttestnet.com","https://lcd.testnet.secretsaturn.net", "https://pulsar-2.api.trivium.network:1317"],
"rpc": ["https://rpc.pulsar.scrttestnet.com", "https://rpc.testnet.secretsaturn.net", "https://testnet-rpc.roninventures.io", "https://pulsar-2.api.trivium.network:26657"], "rpc": ["https://rpc.pulsar.scrttestnet.com", "https://rpc.testnet.secretsaturn.net", "https://pulsar-2.api.trivium.network:26657"],
"snapshot_provider": "", "snapshot_provider": "",
"sdk_version": "0.45.4", "sdk_version": "0.45.4",
"coin_type": "529", "coin_type": "529",

View File

@ -0,0 +1,20 @@
{
"chain_name": "sputnik",
"provider_chain": {
"api": "https://rest.provider-sentry-01.goc.earthball.xyz"
},
"api": ["https://sputnik.api.ping.pub"],
"rpc": [],
"sdk_version": "0.45.7",
"coin_type": 118,
"min_tx_fee": "0",
"addr_prefix": "cosmos",
"logo": "/logos/game_of_chain.jpeg",
"assets": [{
"base": "unik",
"symbol": "NIK",
"exponent": "6",
"coingecko_id": "",
"logo": "/logos/game_of_chain.jpeg"
}]
}

View File

@ -2,64 +2,150 @@
"message": { "message": {
}, },
"cosmos": "Cosmos Hub",
"kava": "Kava",
"akash-network": "Akash Decloud",
"iris-network": "IRIS Hub",
"crypto-com-chain": "Crypto.org",
"osmosis": "Osmosis",
"okexchain": "OKEX Chain",
"band-protocol": "Band Protocol",
"terra-luna": "Terra",
"persistence": "Persistence",
"regen": "Regen Network",
"secret": "Secret Network",
"desmos": "Desmos",
"juno": "Juno",
"certik": "Certik",
"sentinel": "Sentinel",
"sifchain": "Sifchain",
"starname": "Starname",
"bitsong": "BitSong",
"e-money": "E-Money",
"omniflix": "OmniFlix",
"likecoin": "LikeCoin",
"stargaze": "Stargaze",
"injective": "Injective Protocal",
"vidulum": "Vidulum",
"kichain": "KI Chain",
"genesisL1": "Genesis L1",
"microtick": "Microtick",
"odin": "ODIN",
"chihuahua": "CHIHUAHUA",
"staking": "Staking",
"governance": "Governance",
"summary": "Summary",
"blocks": "Blocks / Transactions",
"blockchains": "Blockchains",
"uptime": "Uptime",
"statesync": "State Sync",
"trade": "Trade",
"gravity": "Gravity(WIP)", "chains": {
"pools": "Pools(WIP)", "cosmos": "Cosmos Hub",
"kava": "Kava",
"akash-network": "Akash Decloud",
"iris-network": "IRIS Hub",
"crypto-com-chain": "Crypto.org",
"osmosis": "Osmosis",
"okexchain": "OKEX Chain",
"band-protocol": "Band Protocol",
"terra-luna": "Terra",
"persistence": "Persistence",
"regen": "Regen Network",
"secret": "Secret Network",
"desmos": "Desmos",
"juno": "Juno",
"certik": "Certik",
"sentinel": "Sentinel",
"sifchain": "Sifchain",
"starname": "Starname",
"bitsong": "BitSong",
"e-money": "E-Money",
"omniflix": "OmniFlix",
"likecoin": "LikeCoin",
"stargaze": "Stargaze",
"injective": "Injective Protocal",
"vidulum": "Vidulum",
"kichain": "KI Chain",
"genesisL1": "Genesis L1",
"microtick": "Microtick",
"odin": "ODIN",
"chihuahua": "CHIHUAHUA",
"proposal_id": "Proposal ID", "gravity": "Gravity(WIP)",
"proposal_type": "Proposal Type", "pools": "Pools(WIP)"
"proposal_proposer": "Proposer", },
"proposal_submit_time": "Submited Time",
"proposal_voting_start_time": "Voting Begin Time",
"proposal_voting_end_time": "Voting End Time",
"proposal_description": "Description",
"proposal_content": "Content",
"proposal_total_deposit": "Total Deposit",
"voting_time": "Voting Time",
"upgrade_time": "Estimated Upgrade Time:",
"btn_vote": "Vote", "dashboard": {
"btn_deposit": "Deposit", "dashboard": "Dashboard",
"btn_detail": "Detail", "staking": "Staking",
"btn_back_list": "Back To List" "governance": "Governance",
"summary": "Summary",
"blocks": "Blocks / Transactions",
"blockchains": "Blockchains",
"uptime": "Uptime",
"statesync": "State Sync",
"trade": "Trade",
"parameters": "Parameters",
"consensus": "consensus",
"no_new_blocks": "No new blocks have been produced since ",
"active_props": "Active Proposals",
"proposal_votes_yes": "voters voted Yes",
"proposal_votes_no": "voters voted No",
"proposal_votes_nwv": "voters voted No With Veto",
"proposal_votes_abstain": "voters voted Abstain",
"no_active_prop": "No active proposal!",
"browse": "Browse all",
"assets": "Assets",
"more": "More",
"not_conn": "Not Connected?",
"delegate": "Delegate",
"redelegate": "Redelegate",
"unbond": "Unbond",
"withdraw_reward": "Withdraw Rewards",
"unbonding_token": "Unbonding Tokens",
"send": "Send",
"receive": "Receive",
"connect_wal": "Connect Wallet"
},
"governanceProposal": {
"proposal_id": "Proposal ID",
"proposal_type": "Proposal Type",
"proposal_proposer": "Proposer",
"proposal_submit_time": "Submitted Time",
"proposal_voting_start_time": "Voting Begin Time",
"proposal_voting_end_time": "Voting End Time",
"proposal_description": "Description",
"proposal_content": "Content",
"proposal_total_deposit": "Total Deposit",
"proposal_deposits": "Deposits",
"voting_time": "Voting Time",
"upgrade_time": "Estimated Upgrade Time:",
"btn_vote": "Vote",
"btn_deposit": "Deposit",
"btn_detail": "Detail",
"btn_back_list": "Back To List",
"proposal_status": "Status",
"proposal_status_deposit": "Deposit",
"proposal_status_voting": "Voting",
"proposal_status_passed": "Passed",
"proposal_status_rejected": "Rejected",
"proposal_status_start_date": "Start Date",
"proposal_status_end_date": "End Date",
"proposal_votes": "Votes",
"proposal_votes_yes": "voted Yes",
"proposal_votes_no": "voted No",
"proposal_votes_nwv": "voted No With Veto",
"proposal_votes_abstain": "voted Abstain",
"proposal_votes_load": "Load More Votes"
},
"parameters" : {
"no_blocks_produced" : "No new blocks have been produced since ",
"app_ver": "Application Version",
"node_info": "Node Information"
},
"uptimeMyChainBlocks" : {
"height": "Height:",
"no_blocks_produced" : "No new blocks have been produced since ",
"not_active": "Your node is out of active validator set"
},
"walletAccountDetail": {
"address": "Address:",
"assets": "Assets",
"transfer": "Transfer",
"ibc_transfer": "IBC Transfer",
"total": "Total: ",
"unbonding": "Unbonding Tokens",
"from": "From: ",
"delegation": "Delegation",
"delegate": "Delegate",
"withdraw": " Withdraw Rewards",
"acct_type": "Account Type",
"acct_num": "Account Number",
"seq": "Sequence",
"pub_key": "Public Key",
"orig_vest": "Original Vesting",
"delegated_free": "Delegated Free",
"delegated_vest": "Delegated Vesting",
"vest_time": "Vesting Time",
"vest_period": "Vesting Periods",
"length": "Length",
"amount": "Amount",
"end_time": "End Time",
"acct_not_found": "Account not found",
"opps": "Oops!",
"back_home": "Back to home"
},
"uptimeMyValidators": {
"tips": "Tips",
"two_ways": "There are two ways to monitor your validators:",
"pin": "Pin a validator on Uptime pages.",
"link": "Specify parameters like following:"
}
} }

View File

@ -84,9 +84,9 @@
<!-- <dark-Toggler class="d-none d-lg-block" /> --> <!-- <dark-Toggler class="d-none d-lg-block" /> -->
<!-- Right Col --> <!-- Right Col -->
<b-navbar-nav class="nav align-items-center ml-auto"> <b-navbar-nav class="nav align-items-center ml-auto">
<dark-Toggler class="d-none d-lg-block" /> <dark-Toggler />
<search-bar /> <search-bar />
<locale /> <locale class="d-none" />
<b-dropdown <b-dropdown
class="ml-1" class="ml-1"
variant="link" variant="link"

View File

@ -9,16 +9,16 @@ export default class ProposalTally {
} }
init(element, total) { init(element, total) {
const subtotal = Number(element.yes) + Number(element.no) + Number(element.abstain) + Number(element.no_with_veto) const subtotal = Number(element.yes || element.yes_count) + Number(element.no || element.no_count) + Number(element.abstain || element.abstain_count) + Number(element.no_with_veto || element.no_with_veto_count)
if (total < 1) { if (total < 1) {
this.total = subtotal + 1 this.total = subtotal + 1
} else { } else {
this.total = total this.total = total
} }
this.yes = Number(element.yes) / this.total this.yes = Number(element.yes || element.yes_count) / this.total
this.no = Number(element.no) / this.total this.no = Number(element.no || element.no_count) / this.total
this.veto = Number(element.no_with_veto) / this.total this.veto = Number(element.no_with_veto || element.no_with_veto_count) / this.total
this.abstain = Number(element.abstain) / this.total this.abstain = Number(element.abstain || element.abstain_count) / this.total
this.turnout = subtotal / this.total this.turnout = subtotal / this.total
return this return this
} }

View File

@ -16,6 +16,7 @@ export default class Proposal {
this.voting_start_time = '0000-00-00' this.voting_start_time = '0000-00-00'
this.total_deposit = '-' this.total_deposit = '-'
this.contents = null this.contents = null
this.metadata = {}
} }
init(element, total) { init(element, total) {
@ -29,7 +30,7 @@ export default class Proposal {
this.voting_start_time = element.voting_start_time this.voting_start_time = element.voting_start_time
// eslint-disable-next-line prefer-destructuring // eslint-disable-next-line prefer-destructuring
this.total_deposit = element.total_deposit[0] this.total_deposit = element.total_deposit[0]
this.contents = element.content.value || element.content if (element.content) this.contents = element.content.value || element.content
if (this.contents) { if (this.contents) {
this.title = this.contents.title this.title = this.contents.title
this.description = this.contents.description this.description = this.contents.description
@ -38,6 +39,7 @@ export default class Proposal {
this.type = element.content['@type'] this.type = element.content['@type']
} }
} }
this.metadata = element.metadata
return this return this
} }
@ -51,6 +53,12 @@ export default class Proposal {
versionFixed(ver) { versionFixed(ver) {
if (compareVersions(ver, '0.46') >= 0) { if (compareVersions(ver, '0.46') >= 0) {
if (this.element.messages) [this.contents] = this.element.messages
if (this.contents) this.type = this.contents['@type']
if (this.contents['@type'] === '/cosmos.gov.v1.MsgExecLegacyContent') {
this.title = this.contents.content.title
this.description = this.contents.content.description
}
if (this.element.metadata) { if (this.element.metadata) {
this.title = this.element.metadata.title || this.element.metadata this.title = this.element.metadata.title || this.element.metadata
this.description = this.element.metadata.description || this.element.metadata this.description = this.element.metadata.description || this.element.metadata

View File

@ -46,6 +46,7 @@ export default class WrapStdTx {
self.tx = StdTx.create(element.tx, version) self.tx = StdTx.create(element.tx, version)
self.raw_log = element.tx_response.raw_log self.raw_log = element.tx_response.raw_log
} }
self.element = element
return self return self
} }
} }

View File

@ -128,8 +128,8 @@ export default class ChainFetch {
// return ret // return ret
// }) // })
return Promise.all([ return Promise.all([
this.get(`/cosmos/distribution/v1beta1/validators/${address}/commission`), this.get(`/cosmos/distribution/v1beta1/validators/${address}/commission`, null, true),
this.get(`/cosmos/distribution/v1beta1/validators/${address}/outstanding_rewards`), this.get(`/cosmos/distribution/v1beta1/validators/${address}/outstanding_rewards`, null, true),
]).then(data => { ]).then(data => {
const ret = ValidatorDistribution.create({ const ret = ValidatorDistribution.create({
operator_address: address, operator_address: address,
@ -145,6 +145,9 @@ export default class ChainFetch {
} }
async getBankTotal(denom) { async getBankTotal(denom) {
if (compareVersions(this.config.sdk_version, '0.46.2') > 0) {
return this.get(`/cosmos/bank/v1beta1/supply/by_denom?denom=${denom}`).then(data => commonProcess(data).amount)
}
if (compareVersions(this.config.sdk_version, '0.40') < 0) { if (compareVersions(this.config.sdk_version, '0.40') < 0) {
return this.get(`/supply/total/${denom}`).then(data => ({ amount: commonProcess(data), denom })) return this.get(`/supply/total/${denom}`).then(data => ({ amount: commonProcess(data), denom }))
} }
@ -159,7 +162,7 @@ export default class ChainFetch {
} }
async getStakingPool() { async getStakingPool() {
return this.get('/cosmos/staking/v1beta1/pool').then(data => new StakingPool().init(commonProcess(data.pool))) return this.get('/cosmos/staking/v1beta1/pool', null, true).then(data => new StakingPool().init(commonProcess(data.pool)))
} }
async getMintingInflation() { async getMintingInflation() {
@ -176,14 +179,14 @@ export default class ChainFetch {
} }
async getStakingParameters() { async getStakingParameters() {
return this.get('/cosmos/staking/v1beta1/params').then(data => { return this.get('/cosmos/staking/v1beta1/params', null, true).then(data => {
this.getSelectedConfig() this.getSelectedConfig()
return StakingParameters.create(commonProcess(data.params), this.config.chain_name) return StakingParameters.create(commonProcess(data.params), this.config.chain_name)
}) })
} }
async getValidatorList(config = null) { async getValidatorList(config = null) {
return this.get('/cosmos/staking/v1beta1/validators?pagination.limit=200&status=BOND_STATUS_BONDED', config).then(data => { return this.get('/cosmos/staking/v1beta1/validators?pagination.limit=200&status=BOND_STATUS_BONDED', config, true).then(data => {
const vals = commonProcess(data.validators).map(i => new Validator().init(i)) const vals = commonProcess(data.validators).map(i => new Validator().init(i))
try { try {
localStorage.setItem(`validators-${this.config.chain_name}`, JSON.stringify(vals)) localStorage.setItem(`validators-${this.config.chain_name}`, JSON.stringify(vals))
@ -203,7 +206,7 @@ export default class ChainFetch {
} }
async getValidatorUnbondedList() { async getValidatorUnbondedList() {
return this.get('/cosmos/staking/v1beta1/validators?pagination.limit=100&status=BOND_STATUS_UNBONDED').then(data => { return this.get('/cosmos/staking/v1beta1/validators?pagination.limit=100&status=BOND_STATUS_UNBONDED', null, true).then(data => {
const result = commonProcess(data.validators) const result = commonProcess(data.validators)
const vals = result.validators ? result.validators : result const vals = result.validators ? result.validators : result
return vals.map(i => new Validator().init(i)) return vals.map(i => new Validator().init(i))
@ -211,7 +214,7 @@ export default class ChainFetch {
} }
async getValidatorListByStatus(status) { async getValidatorListByStatus(status) {
return this.get(`/cosmos/staking/v1beta1/validators?status=${status}&pagination.limit=500`).then(data => { return this.get(`/cosmos/staking/v1beta1/validators?status=${status}&pagination.limit=500`, null, true).then(data => {
const result = commonProcess(data) const result = commonProcess(data)
const vals = result.validators ? result.validators : result const vals = result.validators ? result.validators : result
return vals.map(i => new Validator().init(i)) return vals.map(i => new Validator().init(i))
@ -223,7 +226,7 @@ export default class ChainFetch {
} }
async getStakingValidator(address) { async getStakingValidator(address) {
return this.get(`/cosmos/staking/v1beta1/validators/${address}`).then(data => new Validator().init(commonProcess(data).validator)) return this.get(`/cosmos/staking/v1beta1/validators/${address}`, null, true).then(data => new Validator().init(commonProcess(data).validator))
} }
async getSlashingParameters() { async getSlashingParameters() {
@ -277,27 +280,39 @@ export default class ChainFetch {
} }
async getDistributionParameters() { async getDistributionParameters() {
return this.get('/cosmos/distribution/v1beta1/params').then(data => commonProcess(data.params)) return this.get('/cosmos/distribution/v1beta1/params', null, true).then(data => commonProcess(data.params))
} }
async getGovernanceParameterDeposit() { async getGovernanceParameterDeposit() {
return this.get('/cosmos/gov/v1beta1/params/deposit').then(data => commonProcess(data.deposit_params)) const ver = compareVersions(this.config.sdk_version, '0.46.5') < 0 ? 'v1beta1' : 'v1'
return this.get(`/cosmos/gov/${ver}/params/deposit`).then(data => commonProcess(data.deposit_params))
} }
async getGovernanceParameterTallying() { async getGovernanceParameterTallying() {
return this.get('/cosmos/gov/v1beta1/params/tallying').then(data => commonProcess(data.tally_params)) const ver = compareVersions(this.config.sdk_version, '0.46.5') < 0 ? 'v1beta1' : 'v1'
return this.get(`/cosmos/gov/${ver}/params/tallying`).then(data => commonProcess(data.tally_params))
} }
async getGovernanceParameterVoting() { async getGovernanceParameterVoting() {
return this.get('/cosmos/gov/v1beta1/params/voting').then(data => commonProcess(data.voting_params)) const ver = compareVersions(this.config.sdk_version, '0.46.5') < 0 ? 'v1beta1' : 'v1'
return this.get(`/cosmos/gov/${ver}/params/voting`).then(data => commonProcess(data.voting_params))
} }
async getGovernanceTally(pid, total, conf) { async getGovernanceTally(pid, total, conf) {
return this.get(`/cosmos/gov/v1beta1/proposals/${pid}/tally`, conf).then(data => new ProposalTally().init(commonProcess(data).tally, total)) const ver = compareVersions(this.config.sdk_version, '0.46.5') < 0 ? 'v1beta1' : 'v1'
return this.get(`/cosmos/gov/${ver}/proposals/${pid}/tally`, conf).then(data => new ProposalTally().init(commonProcess(data).tally, total))
} }
getGovernance(pid) { getGovernance(pid) {
return this.get(`/cosmos/gov/v1beta1/proposals/${pid}`).then(data => { if (this.config.chain_name === 'shentu') {
return this.get(`/shentu/gov/v1alpha1/proposals/${pid}`).then(data => {
const p = new Proposal().init(commonProcess(data).proposal, 0)
return p
})
}
const ver = compareVersions(this.config.sdk_version, '0.46.5') < 0 ? 'v1beta1' : 'v1'
return this.get(`/cosmos/gov/${ver}/proposals/${pid}`).then(data => {
const p = new Proposal().init(commonProcess(data).proposal, 0) const p = new Proposal().init(commonProcess(data).proposal, 0)
p.versionFixed(this.config.sdk_version) p.versionFixed(this.config.sdk_version)
return p return p
@ -305,20 +320,22 @@ export default class ChainFetch {
} }
async getGovernanceProposer(pid) { async getGovernanceProposer(pid) {
if (this.config.chain_name === 'certik') { if (this.config.chain_name === 'shentu') {
return this.get(`/shentu/gov/v1alpha1/${pid}/proposer`).then(data => new Proposer().init(commonProcess(data))) return this.get(`/shentu/gov/v1alpha1/${pid}/proposer`).then(data => new Proposer().init(commonProcess(data)))
} }
return this.get(`/gov/proposals/${pid}/proposer`).then(data => new Proposer().init(commonProcess(data))) return this.get(`/gov/proposals/${pid}/proposer`).then(data => new Proposer().init(commonProcess(data)))
} }
async getGovernanceDeposits(pid) { async getGovernanceDeposits(pid) {
if (this.config.chain_name === 'certik') { if (this.config.chain_name === 'shentu') {
return this.get(`/shentu/gov/v1alpha1/proposals/${pid}/deposits`).then(data => { return this.get(`/shentu/gov/v1alpha1/proposals/${pid}/deposits`).then(data => {
const result = commonProcess(data) const result = commonProcess(data)
return Array.isArray(result) ? result.reverse().map(d => new Deposit().init(d)) : result return Array.isArray(result) ? result.reverse().map(d => new Deposit().init(d)) : result
}) })
} }
return this.get(`/cosmos/gov/v1beta1/proposals/${pid}/deposits`).then(data => {
const ver = compareVersions(this.config.sdk_version, '0.46.5') < 0 ? 'v1beta1' : 'v1'
return this.get(`/cosmos/gov/${ver}/proposals/${pid}/deposits`).then(data => {
const result = commonProcess(data) const result = commonProcess(data)
return Array.isArray(result) ? result.reverse().map(d => new Deposit().init(d)) : result return Array.isArray(result) ? result.reverse().map(d => new Deposit().init(d)) : result
}) })
@ -334,12 +351,15 @@ export default class ChainFetch {
if (this.config.chain_name === 'shentu') { if (this.config.chain_name === 'shentu') {
return this.get(`/shentu/gov/v1alpha1/proposals/${pid}/votes?pagination.key=${encodeURIComponent(next)}&pagination.limit=${limit}&pagination.reverse=true`) return this.get(`/shentu/gov/v1alpha1/proposals/${pid}/votes?pagination.key=${encodeURIComponent(next)}&pagination.limit=${limit}&pagination.reverse=true`)
} }
return this.get(`/cosmos/gov/v1beta1/proposals/${pid}/votes?pagination.key=${encodeURIComponent(next)}&pagination.limit=${limit}&pagination.reverse=true`) const ver = compareVersions(this.config.sdk_version, '0.46.5') < 0 ? 'v1beta1' : 'v1'
return this.get(`/cosmos/gov/${ver}/proposals/${pid}/votes?pagination.key=${encodeURIComponent(next)}&pagination.limit=${limit}&pagination.reverse=true`)
} }
async getGovernanceListByStatus(status, chain = null) { async getGovernanceListByStatus(status, chain = null) {
const conf = chain || this.config const conf = chain || this.config
const url = conf.chain_name === 'shentu' ? `/shentu/gov/v1alpha1/proposals?pagination.limit=100&proposal_status=${status}` : `/cosmos/gov/v1beta1/proposals?pagination.limit=100&proposal_status=${status}`
const ver = compareVersions(this.config.sdk_version, '0.46.5') < 0 ? 'v1beta1' : 'v1'
const url = conf.chain_name === 'shentu' ? `/shentu/gov/v1alpha1/proposals?pagination.limit=100&proposal_status=${status}` : `/cosmos/gov/${ver}/proposals?pagination.limit=100&proposal_status=${status}`
return this.get(url, conf).then(data => { return this.get(url, conf).then(data => {
let proposals = commonProcess(data) let proposals = commonProcess(data)
if (Array.isArray(proposals.proposals)) { if (Array.isArray(proposals.proposals)) {
@ -361,9 +381,10 @@ export default class ChainFetch {
} }
async getGovernanceProposalVote(pid, voter, chain) { async getGovernanceProposalVote(pid, voter, chain) {
const ver = compareVersions(this.config.sdk_version, '0.46.5') < 0 ? 'v1beta1' : 'v1'
const url = this.config.chain_name === 'shentu' const url = this.config.chain_name === 'shentu'
? `/shentu/gov/v1alpha1/proposals/${pid}/votes/${voter}` ? `/shentu/gov/v1alpha1/proposals/${pid}/votes/${voter}`
: `/cosmos/gov/v1beta1/proposals/${pid}/votes/${voter}` : `/cosmos/gov/${ver}/proposals/${pid}/votes/${voter}`
return this.get(url, chain).then(data => { return this.get(url, chain).then(data => {
if (data.code === 3) { if (data.code === 3) {
throw new Error('not found') throw new Error('not found')
@ -379,9 +400,10 @@ export default class ChainFetch {
async getGovernanceList(next = '', chain = null) { async getGovernanceList(next = '', chain = null) {
const key = next || '' const key = next || ''
const ver = compareVersions(this.config.sdk_version, '0.46.5') < 0 ? 'v1beta1' : 'v1'
const url = this.config.chain_name === 'shentu' const url = this.config.chain_name === 'shentu'
? `/shentu/gov/v1alpha1/proposals?pagination.limit=20&pagination.reverse=true&pagination.key=${key}` ? `/shentu/gov/v1alpha1/proposals?pagination.limit=20&pagination.reverse=true&pagination.key=${key}`
: `/cosmos/gov/v1beta1/proposals?pagination.limit=20&pagination.reverse=true&pagination.key=${key}` : `/cosmos/gov/${ver}/proposals?pagination.limit=20&pagination.reverse=true&pagination.key=${key}`
return this.get(url, chain).then(data => { return this.get(url, chain).then(data => {
let proposals = commonProcess(data) let proposals = commonProcess(data)
if (Array.isArray(proposals.proposals)) { if (Array.isArray(proposals.proposals)) {
@ -415,22 +437,22 @@ export default class ChainFetch {
async getStakingReward(address, config = null) { async getStakingReward(address, config = null) {
if (compareVersions(config ? config.sdk_version : this.config.sdk_version, '0.40') < 0) { if (compareVersions(config ? config.sdk_version : this.config.sdk_version, '0.40') < 0) {
return this.get(`/distribution/delegators/${address}/rewards`, config).then(data => commonProcess(data)) return this.get(`/distribution/delegators/${address}/rewards`, config, true).then(data => commonProcess(data))
} }
return this.get(`/cosmos/distribution/v1beta1/delegators/${address}/rewards`, config).then(data => commonProcess(data)) return this.get(`/cosmos/distribution/v1beta1/delegators/${address}/rewards`, config, true).then(data => commonProcess(data))
} }
async getValidatorSlashs(address, config = null) { async getValidatorSlashs(address, config = null) {
return this.get(`/cosmos/distribution/v1beta1/validators//${address}/slashes`, config).then(data => commonProcess(data)) return this.get(`/cosmos/distribution/v1beta1/validators/${address}/slashes`, config, true).then(data => commonProcess(data))
} }
async getStakingValidators(address) { async getStakingValidators(address) {
return this.get(`/cosmos/distribution/v1beta1/delegators/${address}/validators?pagination.size=200`).then(data => commonProcess(data.validators)) return this.get(`/cosmos/distribution/v1beta1/delegators/${address}/validators?pagination.size=200`, null, true).then(data => commonProcess(data.validators))
} }
async getStakingDelegations(address, config = null) { async getStakingDelegations(address, config = null) {
if (compareVersions(config ? config.sdk_version : this.config.sdk_version, '0.40') < 0) { if (compareVersions(config ? config.sdk_version : this.config.sdk_version, '0.40') < 0) {
return this.get(`/staking/delegators/${address}/delegations`, config).then(data => commonProcess(data).map(x => { return this.get(`/staking/delegators/${address}/delegations`, config, true).then(data => commonProcess(data).map(x => {
const xh = x const xh = x
if (!xh.delegation) { if (!xh.delegation) {
xh.delegation = { xh.delegation = {
@ -441,21 +463,21 @@ export default class ChainFetch {
return xh return xh
})) }))
} }
return this.get(`/cosmos/staking/v1beta1/delegations/${address}`, config).then(data => commonProcess(data)) return this.get(`/cosmos/staking/v1beta1/delegations/${address}`, config, true).then(data => commonProcess(data))
} }
async getStakingRedelegations(address, config = null) { async getStakingRedelegations(address, config = null) {
if (compareVersions(config ? config.sdk_version : this.config.sdk_version, '0.40') < 0) { if (compareVersions(config ? config.sdk_version : this.config.sdk_version, '0.40') < 0) {
return this.get(`/staking/redelegations?delegator=${address}`, config).then(data => commonProcess(data)) return this.get(`/staking/redelegations?delegator=${address}`, config, true).then(data => commonProcess(data))
} }
return this.get(`/cosmos/staking/v1beta1/delegators/${address}/redelegations`, config).then(data => commonProcess(data)) return this.get(`/cosmos/staking/v1beta1/delegators/${address}/redelegations`, config, true).then(data => commonProcess(data))
} }
async getStakingUnbonding(address, config = null) { async getStakingUnbonding(address, config = null) {
if (compareVersions(config ? config.sdk_version : this.config.sdk_version, '0.40') < 0) { if (compareVersions(config ? config.sdk_version : this.config.sdk_version, '0.40') < 0) {
return this.get(`/staking/delegators/${address}/unbonding_delegations`, config).then(data => commonProcess(data)) return this.get(`/staking/delegators/${address}/unbonding_delegations`, config, true).then(data => commonProcess(data))
} }
return this.get(`/cosmos/staking/v1beta1/delegators/${address}/unbonding_delegations`, config).then(data => commonProcess(data)) return this.get(`/cosmos/staking/v1beta1/delegators/${address}/unbonding_delegations`, config, true).then(data => commonProcess(data))
} }
async getBankBalances(address, config = null) { async getBankBalances(address, config = null) {
@ -463,7 +485,7 @@ export default class ChainFetch {
} }
async getCommunityPool(config = null) { async getCommunityPool(config = null) {
return this.get('/cosmos/distribution/v1beta1/community_pool', config).then(data => commonProcess(data)) return this.get('/cosmos/distribution/v1beta1/community_pool', config, true).then(data => commonProcess(data))
} }
async getAllIBCDenoms(config = null) { async getAllIBCDenoms(config = null) {
@ -589,15 +611,17 @@ export default class ChainFetch {
return response.json() // parses JSON response into native JavaScript objects return response.json() // parses JSON response into native JavaScript objects
} }
async get(url, config = null) { async get(url, config = null, fetch_on_provider = false) {
if (!config) { if (!config) {
this.getSelectedConfig() this.getSelectedConfig()
} }
const conf = config || this.config const conf = config || this.config
if (fetch_on_provider && conf.provider_chain) {
return fetch(`${conf.provider_chain.api}${url}`).then(response => response.json())
}
const finalurl = (Array.isArray(conf.api) ? conf.api[this.getApiIndex(config)] : conf.api) + url const finalurl = (Array.isArray(conf.api) ? conf.api[this.getApiIndex(config)] : conf.api) + url
// finalurl = finalurl.replaceAll('v1beta1', this.getEndpointVersion()) // finalurl = finalurl.replaceAll('v1beta1', this.getEndpointVersion())
const ret = await fetch(finalurl).then(response => response.json()) return fetch(finalurl).then(response => response.json())
return ret
} }
getApiIndex(config = null) { getApiIndex(config = null) {

View File

@ -1,5 +1,5 @@
import { import {
Bech32, fromBase64, fromBech32, fromHex, toBase64, toBech32, toHex, fromBase64, fromBech32, fromHex, toBase64, toBech32, toHex,
} from '@cosmjs/encoding' } from '@cosmjs/encoding'
import { sha256, stringToPath } from '@cosmjs/crypto' import { sha256, stringToPath } from '@cosmjs/crypto'
// ledger // ledger
@ -82,20 +82,26 @@ export async function connectLedger(transport = 'usb') {
return new CosmosApp(trans) return new CosmosApp(trans)
} }
export function operatorAddressToAccount(operAddress) { export function valoperToPrefix(valoper) {
const { prefix, data } = Bech32.decode(operAddress) const prefixIndex = valoper.indexOf('valoper')
if (prefix === 'iva') { // handle special cases if (prefixIndex === -1) return null
return Bech32.encode('iaa', data) return valoper.slice(0, prefixIndex)
}
if (prefix === 'crocncl') { // handle special cases
return Bech32.encode('cro', data)
}
return Bech32.encode(prefix.replace('valoper', ''), data)
} }
// TODO, not tested export function operatorAddressToAccount(operAddress) {
export function pubkeyToAccountAddress(pubkey, prefix) { const { prefix, data } = fromBech32(operAddress)
return Bech32.encode(prefix, pubkey, 40) if (prefix === 'iva') { // handle special cases
return toBech32('iaa', data)
}
if (prefix === 'crocncl') { // handle special cases
return toBech32('cro', data)
}
return toBech32(prefix.replace('valoper', ''), data)
}
export function pubKeyToValcons(pubkey, prefix) {
const addressData = sha256(fromBase64(pubkey.key)).slice(0, 20)
return toBech32(`${prefix}valcons`, addressData)
} }
export function toETHAddress(cosmosAddress) { export function toETHAddress(cosmosAddress) {

View File

@ -249,16 +249,16 @@ const router = new VueRouter({
component: () => import('@/views/StakingValidator.vue'), component: () => import('@/views/StakingValidator.vue'),
meta: { meta: {
pageTitle: 'Staking Validator', pageTitle: 'Staking Validator',
breadcrumb: [ breadcrumb: route => ([
{ {
text: 'Staking', text: 'Staking',
active: true, to: `/${route.params.chain}/staking`,
}, },
{ {
text: 'Validator', text: 'Validator',
active: true, active: true,
}, },
], ]),
}, },
}, },
{ {
@ -317,16 +317,16 @@ const router = new VueRouter({
component: () => import('@/views/Block.vue'), component: () => import('@/views/Block.vue'),
meta: { meta: {
pageTitle: 'Block', pageTitle: 'Block',
breadcrumb: [ breadcrumb: route => ([
{ {
text: 'Blocks', text: 'Blocks',
active: true, to: `/${route.params.chain}/blocks`,
}, },
{ {
text: 'Block', text: 'Block',
active: true, active: true,
}, },
], ]),
}, },
}, },
{ {

View File

@ -273,8 +273,9 @@ export default {
return i return i
} }
const txt = text.substring(text.indexOf(':') + 1, text.indexOf(' ')) const txt = text.substring(text.indexOf(':') + 1, text.indexOf(' '))
const sig = text.split(' ')
const val = this.vals.find(x => x.hex.startsWith(txt)) const val = this.vals.find(x => x.hex.startsWith(txt))
return val?.description?.moniker || txt return `${val?.description?.moniker || txt} - ${sig[2]}`
}, },
}, },

View File

@ -5,7 +5,7 @@
:show="syncing" :show="syncing"
> >
<div class="alert-body"> <div class="alert-body">
<span>No new blocks have been produced since <strong>{{ latestTime }}</strong> </span> <span>{{ $t('dashboard.no_new_blocks') }}<strong>{{ latestTime }}</strong> </span>
</div> </div>
</b-alert> </b-alert>
@ -90,40 +90,162 @@
</b-row> </b-row>
<b-card no-body> <b-card no-body>
<b-card-header> <b-card-header>
<b-card-title>Active Proposals</b-card-title> <b-card-title>{{ $t('dashboard.active_props') }}</b-card-title>
</b-card-header> </b-card-header>
<b-card-body> <b-card-body>
<b-media <b-row
v-for="prop in proprosals2" v-for="prop in proprosals2"
:key="prop.id" :key="prop.id"
no-body
class="mb-1"
> >
<b-media-aside <b-col
v-b-modal.operation-modal md="6"
@click="selectProposal('Vote',prop.id, prop.title)" sm="12"
> >
<b-avatar <b-media
rounded no-body
size="42" class="mb-1"
:variant="myVotes[prop.id] ? 'light-primary': 'primary'"
> >
{{ myVotes[prop.id] || 'Vote' }} <b-media-aside
</b-avatar> @click="showDetail(prop.id)"
</b-media-aside> >
<b-link :to="`./${chain}/gov/${prop.id}`"> <b-avatar
<b-media-body class="d-flex flex-column justify-content-center"> rounded
<h6 class="transaction-title"> size="42"
{{ prop.id }}. {{ prop.title }} variant="light-primary"
</h6> >
<small>{{ formatType(prop.contents['@type']) }} {{ formatEnding(prop.voting_end_time) }}</small> {{ prop.id }}
</b-media-body> </b-avatar>
</b-link> </b-media-aside>
</b-media> <b-link :to="`./${chain}/gov/${prop.id}`">
<b-media-body class="d-flex flex-column justify-content-center">
<h6 class="transaction-title">
<b-badge
pill
variant="light-primary"
>
{{ formatType(prop.contents['@type']) }}
</b-badge>{{ prop.title }}
</h6>
<small>will {{ caculateTallyResult(prop.tally) }} {{ formatEnding(prop.voting_end_time) }}</small>
</b-media-body>
</b-link>
</b-media>
</b-col>
<b-col
md="6"
sm="12"
>
<b-row>
<b-col cols="8">
<div class="scale">
<div class="box">
<b-progress
:max="totalPower? 100 * (totalPower/prop.tally.total) :100"
height="2rem"
show-progress
class="font-small-1"
>
<b-progress-bar
:id="'vote-yes'+prop.id"
variant="success"
:value="percent(prop.tally.yes)"
show-progress
:label="`${percent(prop.tally.yes).toFixed()}%`"
/>
<b-progress-bar
:id="'vote-no'+prop.id"
variant="danger"
:value="percent(prop.tally.no)"
:label="`${percent(prop.tally.no).toFixed()}%`"
show-progress
/>
<b-progress-bar
:id="'vote-veto'+prop.id"
class="bg-danger bg-darken-4"
:value="percent(prop.tally.veto)"
:label="`${percent(prop.tally.veto).toFixed()}%`"
show-progress
/>
<b-progress-bar
:id="'vote-abstain'+prop.id"
variant="secondary"
:value="percent(prop.tally.abstain)"
:label="`${percent(prop.tally.abstain).toFixed()}%`"
show-progress
/>
</b-progress>
</div>
<div
v-b-tooltip.hover
title="Threshold"
class="box overlay"
:style="`left:${scaleWidth(prop)}%;`"
/>
<div
v-if="tallyParam"
v-b-tooltip.hover
title="Quorum"
class="box overlay"
:style="`left:${Number(tallyParam.quorum) * 100}%; border-color:black`"
/>
</div>
<b-tooltip
:target="'vote-yes'+prop.id"
>
{{ percent(prop.tally.yes) }}% {{ $t('dashboard.proposal_votes_yes') }}
</b-tooltip>
<b-tooltip
:target="'vote-no'+prop.id"
>
{{ percent(prop.tally.no) }}% {{ $t('dashboard.proposal_votes_no') }}
</b-tooltip>
<b-tooltip
:target="'vote-veto'+prop.id"
>
{{ percent(prop.tally.veto) }}% {{ $t('dashboard.proposal_votes_nwv') }}
</b-tooltip>
<b-tooltip
:target="'vote-abstain'+prop.id"
>
{{ percent(prop.tally.abstain) }}% {{ $t('dashboard.proposal_votes_abstain') }}
</b-tooltip>
</b-col>
<b-col
cols="4"
style="padding-top: 0.5em"
>
<b-button
v-b-modal.operation-modal
variant="primary"
size="sm"
class="mb-2"
@click="selectProposal('Vote',prop.id, prop.title)"
>
{{ myVotes[prop.id] ? `${myVotes[prop.id]}`: 'Vote' }}
</b-button>
</b-col>
</b-row>
</b-col>
<b-col
cols="12"
:class="detailId === prop.id? 'd-block': 'd-none'"
>
<b-card
border-variant="primary"
bg-variant="transparent"
class="shadow-none"
style="max-height:350px;overflow: auto;"
>
<VueMarkdown class="pb-1">
{{ addNewLine(prop.description) }}
</VueMarkdown>
</b-card>
</b-col>
</b-row>
<div v-if="proprosals2.length === 0"> <div v-if="proprosals2.length === 0">
No active proposal! {{ $t('dashboard.no_active_prop') }}
<b-link :to="`./${chain}/gov`"> <b-link :to="`./${chain}/gov`">
Browse all {{ $t('dashboard.browse') }}
</b-link> </b-link>
</div> </div>
</b-card-body> </b-card-body>
@ -133,20 +255,20 @@
bg-variant="transparent" bg-variant="transparent"
class="shadow-none" class="shadow-none"
> >
<b-card-title class="d-flex justify-content-between"> <b-card-title class="d-flex justify-content-between text-capitalize">
<span>{{ walletName }} Assets </span> <span>{{ walletName }} {{ $t('dashboard.assets') }} </span>
<small> <small>
<b-link <b-link
v-if="address" v-if="address"
:to="`./${chain}/account/${address}`" :to="`./${chain}/account/${address}`"
> >
More {{ $t('dashboard.more') }}
</b-link> </b-link>
<b-link <b-link
v-else v-else
:to="`/wallet/accounts`" :to="`/wallet/accounts`"
> >
Not connected? {{ $t('dashboard.not_conn') }}
</b-link> </b-link>
</small> </small>
</b-card-title> </b-card-title>
@ -211,6 +333,7 @@
<!-- size --> <!-- size -->
<b-button-group <b-button-group
size="sm" size="sm"
class="d-none"
> >
<b-button <b-button
v-b-modal.operation-modal v-b-modal.operation-modal
@ -240,18 +363,41 @@
<feather-icon icon="LogOutIcon" /> <feather-icon icon="LogOutIcon" />
</b-button> </b-button>
</b-button-group> </b-button-group>
<b-dropdown
v-b-modal.operation-modal
split
variant="outline-primary"
text="Delegate"
class="mr-1"
size="sm"
@click="selectDelegation(data,'Delegate')"
>
<template #button-content>
{{ $t('dashboard.delegate') }}
</template>
<b-dropdown-item
v-b-modal.operation-modal
@click="selectDelegation(data,'Redelegate')"
>
{{ $t('dashboard.redelegate') }}
</b-dropdown-item>
<b-dropdown-item
v-b-modal.operation-modal
@click="selectDelegation(data,'Unbond')"
>
{{ $t('dashboard.unbond') }}
</b-dropdown-item>
</b-dropdown>
<b-button
v-b-modal.operation-modal
variant="outline-primary"
size="sm"
@click="selectWithdraw()"
>
{{ $t('dashboard.withdraw_reward') }}
</b-button>
</template> </template>
</b-table> </b-table>
<b-card-footer class="text-right">
<b-button
v-b-modal.operation-modal
variant="outline-primary"
@click="selectWithdraw()"
>
<feather-icon icon="AwardIcon" />
Widthdraw Rewards
</b-button>
</b-card-footer>
</b-card> </b-card>
</b-col> </b-col>
</b-row> </b-row>
@ -260,7 +406,7 @@
<b-col> <b-col>
<b-card> <b-card>
<b-card-header class="pt-0 pl-0 pr-0"> <b-card-header class="pt-0 pl-0 pr-0">
<b-card-title>Unbonding Tokens</b-card-title> <b-card-title>{{ $t('dashboard.unbonding_token') }}</b-card-title>
</b-card-header> </b-card-header>
<b-card-body class="pl-0 pr-0"> <b-card-body class="pl-0 pr-0">
<b-row <b-row
@ -307,7 +453,7 @@
@click="selectSend()" @click="selectSend()"
> >
<feather-icon icon="SendIcon" /> <feather-icon icon="SendIcon" />
Send {{ $t('dashboard.send') }}
</b-button> </b-button>
</b-col> </b-col>
<b-col cols="6"> <b-col cols="6">
@ -319,7 +465,7 @@
<feather-icon <feather-icon
icon="PlusCircleIcon" icon="PlusCircleIcon"
/> />
Receive {{ $t('dashboard.receive') }}
</b-button> </b-button>
</b-col> </b-col>
</b-row> </b-row>
@ -327,7 +473,7 @@
<router-link to="/wallet/import"> <router-link to="/wallet/import">
<b-card class="addzone text-center"> <b-card class="addzone text-center">
<feather-icon icon="PlusIcon" /> <feather-icon icon="PlusIcon" />
Connect Wallet {{ $t('dashboard.connect_wal') }}
</b-card> </b-card>
</router-link> </router-link>
<operation-modal <operation-modal
@ -337,21 +483,24 @@
:proposal-id="selectedProposalId" :proposal-id="selectedProposalId"
:proposal-title="selectedTitle" :proposal-title="selectedTitle"
/> />
<div id="txevent" />
</div> </div>
</template> </template>
<script> <script>
import { import {
BRow, BCol, BAlert, BCard, BTable, BFormCheckbox, BCardHeader, BCardTitle, BMedia, BMediaAside, BMediaBody, BAvatar, BRow, BCol, BAlert, BCard, BTable, BFormCheckbox, BCardHeader, BCardTitle, BMedia, BMediaAside, BMediaBody, BAvatar,
BCardBody, BLink, BButtonGroup, BButton, BTooltip, VBModal, VBTooltip, BCardFooter, BCardBody, BLink, BButtonGroup, BButton, BTooltip, VBModal, VBTooltip, BCardFooter, BProgress, BProgressBar, BBadge,
BDropdown, BDropdownItem,
} from 'bootstrap-vue' } from 'bootstrap-vue'
import { import {
formatNumber, formatTokenAmount, isToken, percent, timeIn, toDay, toDuration, tokenFormatter, getLocalAccounts, formatNumber, formatTokenAmount, isToken, percent, timeIn, toDay, toDuration, tokenFormatter, getLocalAccounts,
getStakingValidatorOperator, getStakingValidatorOperator, formatToken,
} from '@/libs/utils' } from '@/libs/utils'
import OperationModal from '@/views/components/OperationModal/index.vue' import OperationModal from '@/views/components/OperationModal/index.vue'
import Ripple from 'vue-ripple-directive' import Ripple from 'vue-ripple-directive'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import VueMarkdown from 'vue-markdown'
import ParametersModuleComponent from './components/parameters/ParametersModuleComponent.vue' import ParametersModuleComponent from './components/parameters/ParametersModuleComponent.vue'
import DashboardCardHorizontal from './components/dashboard/DashboardCardHorizontal.vue' import DashboardCardHorizontal from './components/dashboard/DashboardCardHorizontal.vue'
import DashboardCardVertical from './components/dashboard/DashboardCardVertical.vue' import DashboardCardVertical from './components/dashboard/DashboardCardVertical.vue'
@ -364,6 +513,8 @@ export default {
BButtonGroup, BButtonGroup,
BTooltip, BTooltip,
BButton, BButton,
BDropdown,
BDropdownItem,
BRow, BRow,
BCol, BCol,
BAlert, BAlert,
@ -378,6 +529,10 @@ export default {
BCardBody, BCardBody,
BLink, BLink,
BCardFooter, BCardFooter,
BProgress,
BProgressBar,
VueMarkdown,
BBadge,
OperationModal, OperationModal,
ParametersModuleComponent, ParametersModuleComponent,
@ -393,6 +548,7 @@ export default {
}, },
data() { data() {
return { return {
detailId: 0,
fields: ['validator', 'delegation', 'rewards', 'action'], fields: ['validator', 'delegation', 'rewards', 'action'],
delegations: [], delegations: [],
rewards: [], rewards: [],
@ -414,6 +570,8 @@ export default {
selectedProposalId: 0, selectedProposalId: 0,
selectedTitle: '', selectedTitle: '',
operationModalType: '', operationModalType: '',
tallyParam: null,
totalPower: 0,
voteColors: { voteColors: {
YES: 'success', YES: 'success',
NO: 'warning', NO: 'warning',
@ -450,10 +608,12 @@ export default {
stakingList() { stakingList() {
return this.delegations.map(x => { return this.delegations.map(x => {
const rewards = this.rewards.find(r => r.validator_address === x.delegation.validator_address) const rewards = this.rewards.find(r => r.validator_address === x.delegation.validator_address)
const conf = this.$http.getSelectedConfig()
const decimal = conf.assets[0].exponent || '6'
return { return {
valAddress: x.delegation.validator_address, valAddress: x.delegation.validator_address,
validator: getStakingValidatorOperator(this.$store.state.chains.selected.chain_name, x.delegation.validator_address), validator: getStakingValidatorOperator(this.$store.state.chains.selected.chain_name, x.delegation.validator_address),
delegation: this.formatToken([x.balance]), delegation: formatToken(x.balance, {}, decimal),
rewards: rewards ? this.formatToken(rewards.reward) : '', rewards: rewards ? this.formatToken(rewards.reward) : '',
action: '', action: '',
} }
@ -461,9 +621,29 @@ export default {
}, },
}, },
created() { created() {
this.$http.getGovernanceListByStatus(2).then(res => { this.$http.getStakingParameters().then(res => {
this.proposals = res.proposals Promise.all([this.$http.getStakingPool(), this.$http.getBankTotal(res.bond_denom)])
.then(pool => {
this.supply = `${formatNumber(formatTokenAmount(pool[1].amount, 2, res.bond_denom, false), true, 2)}`
this.bonded = `${formatNumber(formatTokenAmount(pool[0].bondedToken, 2, res.bond_denom, false), true, 2)}`
this.ratio = `${percent(pool[0].bondedToken / pool[1].amount)}%`
this.totalPower = pool[0].bondedToken
})
}) })
this.$http.getGovernanceListByStatus(2).then(gov => {
this.proposals = gov.proposals
this.proposals.forEach(p => {
this.$http.getGovernanceTally(p.id, 0).then(update => {
// const p2 = p
// p2.tally = update
// this.proposals.push(p2)
// this.proposals.sort((a, b) => a.id - b.id)
this.$set(p, 'tally', update)
})
})
})
this.$http.getLatestBlock().then(res => { this.$http.getLatestBlock().then(res => {
this.height = res.block.header.height this.height = res.block.header.height
if (timeIn(res.block.header.time, 3, 'm')) { if (timeIn(res.block.header.time, 3, 'm')) {
@ -475,19 +655,14 @@ export default {
this.validators = res.block.last_commit.signatures.length this.validators = res.block.last_commit.signatures.length
}) })
this.$http.getStakingParameters().then(res => {
Promise.all([this.$http.getStakingPool(), this.$http.getBankTotal(res.bond_denom)])
.then(pool => {
this.supply = `${formatNumber(formatTokenAmount(pool[1].amount, 2, res.bond_denom, false), true, 2)}`
this.bonded = `${formatNumber(formatTokenAmount(pool[0].bondedToken, 2, res.bond_denom, false), true, 2)}`
this.ratio = `${percent(pool[0].bondedToken / pool[1].amount)}%`
})
})
this.$http.getCommunityPool().then(res => { this.$http.getCommunityPool().then(res => {
this.communityPool = this.formatToken(res.pool) this.communityPool = this.formatToken(res.pool)
}) })
this.$http.getGovernanceParameterTallying().then(res => {
this.tallyParam = res
})
const conf = this.$http.getSelectedConfig() const conf = this.$http.getSelectedConfig()
if (conf.excludes && conf.excludes.indexOf('mint') > -1) { if (conf.excludes && conf.excludes.indexOf('mint') > -1) {
this.inflation = '-' this.inflation = '-'
@ -499,7 +674,39 @@ export default {
}) })
} }
}, },
mounted() {
const elem = document.getElementById('txevent')
elem.addEventListener('txcompleted', () => {
const key = this.$store?.state?.chains?.defaultWallet
if (key) {
const accounts = getLocalAccounts() || {}
const account = Object.entries(accounts)
.map(v => ({ wallet: v[0], address: v[1].address.find(x => x.chain === this.$store.state.chains.selected.chain_name) }))
.filter(v => v.address)
.find(x => x.wallet === key)
if (account) {
this.fetchAccount(account.address.addr)
}
}
})
},
methods: { methods: {
caculateTallyResult(tally) {
if (this.tallyParam && tally && this.totalPower > 0) {
if (tally.veto < Number(this.tallyParam.veto_threshold)
&& tally.yes > Number(this.tallyParam.threshold)
&& tally.total / this.totalPower > Number(this.tallyParam.quorum)) {
return 'pass'
}
}
return 'be rejected'
},
scaleWidth(p) {
if (this.tallyParam) {
return Number(this.tallyParam.quorum) * Number(this.tallyParam.threshold) * (1 - p.tally.abstain) * 100
}
return 50
},
selectProposal(modal, pid, title) { selectProposal(modal, pid, title) {
this.operationModalType = modal this.operationModalType = modal
this.selectedProposalId = Number(pid) this.selectedProposalId = Number(pid)
@ -609,6 +816,13 @@ export default {
return { title: this.convert(data[k]), subtitle: k } return { title: this.convert(data[k]), subtitle: k }
}) })
}, },
addNewLine(value) {
return value ? value.replace(/(?:\\[rn])+/g, '\n') : '-'
},
percent: v => percent(v),
processBarLength(v) {
return percent(v)
},
formatDate: v => dayjs(v).format('YYYY-MM-DD HH:mm:ss'), formatDate: v => dayjs(v).format('YYYY-MM-DD HH:mm:ss'),
convert(v) { convert(v) {
if (typeof v === 'object') { if (typeof v === 'object') {
@ -633,6 +847,13 @@ export default {
} }
return v return v
}, },
showDetail(id) {
if (this.detailId !== id) {
this.detailId = id
} else {
this.detailId = 0
}
},
}, },
} }
</script> </script>

View File

@ -7,7 +7,11 @@
lg="6" lg="6"
md="12" md="12"
> >
<proposal-summary-component :p="p" /> <proposal-summary-component
:p="p"
:total-power="totalPower"
:tally-param="tallyParam"
/>
</b-col> </b-col>
</b-row> </b-row>
<b-row v-if="next"> <b-row v-if="next">
@ -64,9 +68,14 @@ export default {
max: 1, max: 1,
operationModalType: '', operationModalType: '',
next: '', next: '',
totalPower: 0,
tallyParam: null,
} }
}, },
mounted() { mounted() {
this.$http.getGovernanceParameterTallying().then(res => {
this.tallyParam = res
})
this.getList() this.getList()
}, },
methods: { methods: {
@ -81,9 +90,10 @@ export default {
}, },
updateTally(res) { updateTally(res) {
this.$http.getStakingPool().then(pool => { this.$http.getStakingPool().then(pool => {
this.totalPower = pool.bondedToken
const voting = res.filter(i => i.status === 2) const voting = res.filter(i => i.status === 2)
if (voting.length > 0) { if (voting.length > 0) {
voting.forEach(p => this.$http.getGovernanceTally(p.id, pool.bondedToken).then(update => { voting.forEach(p => this.$http.getGovernanceTally(p.id, 0).then(update => {
this.$set(p, 'tally', update) this.$set(p, 'tally', update)
})) }))
} }

View File

@ -12,7 +12,7 @@
variant="light-info" variant="light-info"
class="text-right" class="text-right"
> >
Deposit {{$t('governanceProposal.proposal_status_deposit')}}
</b-badge> </b-badge>
<b-badge <b-badge
v-if="proposal.status == 2" v-if="proposal.status == 2"
@ -20,7 +20,7 @@
variant="light-primary" variant="light-primary"
class="text-right" class="text-right"
> >
Voting {{$t('governanceProposal.proposal_status_voting')}}
</b-badge> </b-badge>
<b-badge <b-badge
v-if="proposal.status == 3" v-if="proposal.status == 3"
@ -28,7 +28,7 @@
variant="light-success" variant="light-success"
class="text-right" class="text-right"
> >
Passed {{$t('governanceProposal.proposal_status_passed')}}
</b-badge> </b-badge>
<b-badge <b-badge
v-if="proposal.status == 4" v-if="proposal.status == 4"
@ -36,12 +36,17 @@
variant="light-danger" variant="light-danger"
class="text-right" class="text-right"
> >
Rejected {{$t('governanceProposal.proposal_status_rejected')}}
</b-badge> </b-badge>
{{ proposal.title }} {{ proposal.title }}
</b-card-title> </b-card-title>
</b-card-header> </b-card-header>
<b-card-body> <b-card-body>
<div>
<object-field-component
:tablefield="proposal.contents"
:small="false"
/></div>
<b-table-simple <b-table-simple
stacked="sm" stacked="sm"
hover hover
@ -50,38 +55,46 @@
<tbody> <tbody>
<b-tr> <b-tr>
<b-td style="text-transform: capitalize; vertical-align: top; width:200px"> <b-td style="text-transform: capitalize; vertical-align: top; width:200px">
{{ $t('proposal_proposer') }} {{ $t('governanceProposal.proposal_total_deposit') }}
</b-td><b-td><router-link :to="`../account/${proposer.proposer}`">
{{ formatAddress(proposer.proposer) }}
</router-link> </b-td>
</b-tr>
<b-tr>
<b-td>
{{ $t('proposal_total_deposit') }}
</b-td><b-td>{{ formatToken(proposal.total_deposit) }} </b-td> </b-td><b-td>{{ formatToken(proposal.total_deposit) }} </b-td>
</b-tr> </b-tr>
<b-tr> <b-tr>
<b-td> <b-td>
{{ $t('proposal_submit_time') }} {{ $t('governanceProposal.proposal_submit_time') }}
</b-td><b-td>{{ formatDate(proposal.submit_time) }}</b-td> </b-td><b-td>{{ formatDate(proposal.submit_time) }}</b-td>
</b-tr> </b-tr>
<b-tr> <b-tr>
<b-td> <b-td>
{{ $t('voting_time') }} {{ $t('governanceProposal.voting_time') }}
</b-td><b-td>{{ formatDate(proposal.voting_start_time) }} - {{ formatDate(proposal.voting_end_time) }}</b-td> </b-td><b-td>{{ formatDate(proposal.voting_start_time) }} - {{ formatDate(proposal.voting_end_time) }}</b-td>
</b-tr> </b-tr>
<b-tr v-if="proposal.metadata">
<b-td>
Metadata
</b-td><b-td>{{ proposal.metadata }}</b-td>
</b-tr>
</tbody> </tbody>
</b-table-simple> </b-table-simple>
<div>
<object-field-component
:tablefield="proposal.contents"
:small="false"
/></div>
<b-table-simple v-if="proposal.type.indexOf('SoftwareUpgrade') > 0"> <b-table-simple v-if="proposal.type.indexOf('SoftwareUpgrade') > 0">
<b-tr> <b-tr>
<b-td class="text-center"> <b-td class="text-center">
{{ $t('upgrade_time') }} {{ upgradeTime }} {{ $t('governanceProposal.upgrade_time') }} {{ upgradeTime }}
<flip-countdown :deadline="upgradeTime" /> <flip-countdown :deadline="upgradeTime" />
<b-input-group prepend="Estimated by block time: ">
<b-form-select v-model="blocktime">
<b-form-select-option value="7">
7s
</b-form-select-option>
<b-form-select-option value="6">
6s
</b-form-select-option>
<b-form-select-option value="2">
2s
</b-form-select-option>
<b-form-select-option value="1">
1s
</b-form-select-option>
</b-form-select></b-input-group>
</b-td> </b-td>
</b-tr> </b-tr>
</b-table-simple> </b-table-simple>
@ -91,7 +104,7 @@
<b-button <b-button
variant="outline-primary" variant="outline-primary"
> >
{{ $t('btn_back_list') }} {{ $t('governanceProposal.btn_back_list') }}
</b-button> </b-button>
</router-link> </router-link>
<b-button <b-button
@ -101,94 +114,106 @@
class="btn float-right mg-2" class="btn float-right mg-2"
@click="openModal('Vote')" @click="openModal('Vote')"
> >
{{ $t('btn_vote') }} {{ $t('governanceProposal.btn_vote') }}
</b-button> </b-button>
</b-card-footer> </b-card-footer>
</b-card> </b-card>
<b-card no-body> <b-card no-body>
<b-card-header> <b-card-header>
<b-card-title> <b-card-title>
Votes {{ $t('governanceProposal.proposal_votes') }}
</b-card-title> </b-card-title>
</b-card-header> </b-card-header>
<b-card-body> <b-card-body>
<b-progress <div>
:max="100" <div class="scale">
height="2rem" <div class="box">
class="mb-2" <b-progress
show-progress :max="totalPower && proposal.status ===2? 100 * (totalPower/proposal.tally.total) :100"
> height="2rem"
<b-progress-bar class="mb-2"
:id="'vote-yes'+proposal.id" show-progress
variant="success" >
:value="percent(proposal.tally.yes)" <b-progress-bar
:label="`${percent(proposal.tally.yes).toFixed()}%`" :id="'vote-yes'+proposal.id"
show-progress variant="success"
/> :value="percent(proposal.tally.yes)"
<b-progress-bar :label="`${percent(proposal.tally.yes).toFixed()}%`"
:id="'vote-no'+proposal.id" show-progress
variant="warning" />
:value="percent(proposal.tally.no)" <b-progress-bar
:label="`${percent(proposal.tally.no).toFixed()}%`" :id="'vote-no'+proposal.id"
show-progress variant="danger"
/> :value="percent(proposal.tally.no)"
<b-progress-bar :label="`${percent(proposal.tally.no).toFixed()}%`"
:id="'vote-veto'+proposal.id" show-progress
variant="danger" />
:value="percent(proposal.tally.veto)" <b-progress-bar
:label="`${percent(proposal.tally.veto).toFixed()}%`" :id="'vote-veto'+proposal.id"
show-progress class="bg-danger bg-darken-4"
/> :value="percent(proposal.tally.veto)"
<b-progress-bar :label="`${percent(proposal.tally.veto).toFixed()}%`"
:id="'vote-abstain'+proposal.id" show-progress
variant="secondary" />
:value="percent(proposal.tally.abstain)" <b-progress-bar
:label="`${percent(proposal.tally.abstain).toFixed()}%`" :id="'vote-abstain'+proposal.id"
show-progress variant="secondary"
/> :value="percent(proposal.tally.abstain)"
</b-progress> :label="`${percent(proposal.tally.abstain).toFixed()}%`"
<b-tooltip show-progress
:target="'vote-yes'+proposal.id" />
> </b-progress>
{{ percent(proposal.tally.yes) }}% voted Yes <b-tooltip
</b-tooltip> :target="'vote-yes'+proposal.id"
<b-tooltip >
:target="'vote-no'+proposal.id" {{ percent(proposal.tally.yes) }}% {{ $t('governanceProposal.proposal_votes_yes') }}
> </b-tooltip>
{{ percent(proposal.tally.no) }}% voted No <b-tooltip
</b-tooltip> :target="'vote-no'+proposal.id"
<b-tooltip >
:target="'vote-veto'+proposal.id" {{ percent(proposal.tally.no) }}% {{ $t('governanceProposal.proposal_votes_no') }}
> </b-tooltip>
{{ percent(proposal.tally.veto) }}% voted No With Veto <b-tooltip
</b-tooltip> :target="'vote-veto'+proposal.id"
<b-tooltip >
:target="'vote-abstain'+proposal.id" {{ percent(proposal.tally.veto) }}% voted {{ $t('governanceProposal.proposal_votes_nwv') }}
> </b-tooltip>
{{ percent(proposal.tally.abstain) }}% voted Abstain <b-tooltip
</b-tooltip> :target="'vote-abstain'+proposal.id"
<b-table >
v-if="votes.votes && votes.votes.length > 0" {{ percent(proposal.tally.abstain) }}% {{ $t('governanceProposal.proposal_votes_abstain') }}
stacked="sm" </b-tooltip>
:fields="votes_fields"
:items="votes.votes" <div
striped v-if="tallyParam"
> title="Threshold"
<template #cell(voter)="data"> class="box overlay"
<router-link :to="`../account/${data.item.voter}`"> :style="`left:${scaleWidth(proposal)}%;`"
{{ formatAddress(data.item.voter) }} />
</router-link> </div>
</template> </div>
</b-table> <b-table
<div v-if="votes.votes && votes.votes.length > 0"
v-if="next" stacked="sm"
class="addzone text-center pt-50 pb-50 bg-transparent text-primary" :fields="votes_fields"
@click="loadVotes()" :items="votes.votes"
> striped
<feather-icon icon="PlusIcon" /> >
Load More Votes <template #cell(voter)="data">
</div> <router-link :to="`../account/${data.item.voter}`">
</b-card-body> {{ formatAddress(data.item.voter) }}
</router-link>
</template>
</b-table>
<div
v-if="next"
class="addzone text-center pt-50 pb-50 bg-transparent text-primary"
@click="loadVotes()"
>
<feather-icon icon="PlusIcon" />
{{ $t('governanceProposal.proposal_votes_load') }}
</div>
</div></b-card-body>
</b-card> </b-card>
<b-card <b-card
v-if="proposal.total_deposit" v-if="proposal.total_deposit"
@ -196,7 +221,7 @@
> >
<b-card-header> <b-card-header>
<b-card-title> <b-card-title>
Deposits ({{ formatToken(proposal.total_deposit) }}) {{ $t('governanceProposal.proposal_deposits') }} ({{ formatToken(proposal.total_deposit) }})
</b-card-title> </b-card-title>
</b-card-header> </b-card-header>
<b-card-body> <b-card-body>
@ -219,7 +244,7 @@
<b-button <b-button
variant="outline-primary" variant="outline-primary"
> >
{{ $t('btn_back_list') }} {{ $t('governanceProposal.btn_back_list') }}
</b-button> </b-button>
</router-link> </router-link>
<b-button <b-button
@ -229,7 +254,7 @@
class="btn float-right mg-2" class="btn float-right mg-2"
@click="openModal('GovDeposit')" @click="openModal('GovDeposit')"
> >
{{ $t('btn_deposit') }} {{ $t('governanceProposal.btn_deposit') }}
</b-button> </b-button>
<b-button <b-button
v-b-modal.operation-modal v-b-modal.operation-modal
@ -238,7 +263,7 @@
class="btn float-right mg-2 mr-1" class="btn float-right mg-2 mr-1"
@click="openModal('Vote')" @click="openModal('Vote')"
> >
{{ $t('btn_vote') }} {{ $t('governanceProposal.btn_vote') }}
</b-button> </b-button>
</b-card-footer> </b-card-footer>
</b-card> </b-card>
@ -253,7 +278,7 @@
<script> <script>
import { import {
BCard, BCardBody, BCardFooter, BButton, BTable, BTableSimple, BTr, BTd, BCardTitle, BCardHeader, BCard, BCardBody, BCardFooter, BButton, BTable, BTableSimple, BTr, BTd, BCardTitle, BCardHeader,
BProgressBar, BProgress, BTooltip, BBadge, BProgressBar, BProgress, BTooltip, BBadge, BFormSelect, BFormSelectOption, BInputGroup, BInputGroupPrepend,
} from 'bootstrap-vue' } from 'bootstrap-vue'
import FlipCountdown from 'vue2-flip-countdown' import FlipCountdown from 'vue2-flip-countdown'
// import fetch from 'node-fetch' // import fetch from 'node-fetch'
@ -284,16 +309,23 @@ export default {
BProgress, BProgress,
BTooltip, BTooltip,
BBadge, BBadge,
BFormSelect,
BFormSelectOption,
BInputGroup,
BInputGroupPrepend,
ObjectFieldComponent, ObjectFieldComponent,
FlipCountdown, FlipCountdown,
OperationModal, OperationModal,
}, },
data() { data() {
return { return {
blocktime: 6,
tallyParam: null,
latest: {}, latest: {},
next: null, next: null,
proposal: new Proposal(), proposal: new Proposal(),
proposer: new Proposer(), proposer: new Proposer(),
totalPower: 0,
deposits: [], deposits: [],
votes: [], votes: [],
operationModalType: '', operationModalType: '',
@ -346,7 +378,7 @@ export default {
if (Number(this.proposal?.contents.plan.height || 0) > 0 && this.latest?.block) { if (Number(this.proposal?.contents.plan.height || 0) > 0 && this.latest?.block) {
const blocks = Number(this.proposal.contents.plan.height) - Number(this.latest.block?.header?.height || 0) const blocks = Number(this.proposal.contents.plan.height) - Number(this.latest.block?.header?.height || 0)
if (blocks > 0) { if (blocks > 0) {
const endtime = dayjs().add(blocks * 6, 'second').format('YYYY-MM-DD HH:mm:ss') const endtime = dayjs().add(blocks * this.blocktime, 'second').format('YYYY-MM-DD HH:mm:ss')
return endtime return endtime
} }
} }
@ -356,6 +388,9 @@ export default {
}, },
}, },
created() { created() {
this.$http.getGovernanceParameterTallying().then(res => {
this.tallyParam = res
})
const pid = this.$route.params.proposalid const pid = this.$route.params.proposalid
if (this.$route.query.from) { if (this.$route.query.from) {
this.from = this.$route.query.from this.from = this.$route.query.from
@ -368,7 +403,8 @@ export default {
this.$http.getGovernance(pid).then(p => { this.$http.getGovernance(pid).then(p => {
if (p.status === 2) { if (p.status === 2) {
this.$http.getStakingPool().then(pool => { this.$http.getStakingPool().then(pool => {
this.$http.getGovernanceTally(pid, pool.bondedToken).then(t => p.updateTally(t)) this.totalPower = pool.bondedToken
this.$http.getGovernanceTally(pid, 0).then(t => p.updateTally(t))
}) })
} }
this.proposal = p this.proposal = p
@ -377,10 +413,9 @@ export default {
if (!getCachedValidators()) { if (!getCachedValidators()) {
this.$http.getValidatorList() this.$http.getValidatorList()
} }
// this.$http.getGovernanceProposer(pid).then(res => {
this.$http.getGovernanceProposer(pid).then(res => { // this.proposer = res
this.proposer = res // })
})
this.$http.getGovernanceDeposits(pid).then(res => { this.$http.getGovernanceDeposits(pid).then(res => {
this.deposits = res this.deposits = res
}).catch(() => {}) }).catch(() => {})
@ -390,6 +425,15 @@ export default {
}) })
}, },
methods: { methods: {
scaleWidth(p) {
if (this.tallyParam) {
if (p.status === 2) {
return Number(this.tallyParam.quorum) * Number(this.tallyParam.threshold) * (1 - p.tally.abstain) * 100
}
return Number(this.tallyParam.threshold) * (1 - p.tally.abstain) * 100
}
return 50
},
percent: v => percent(v), percent: v => percent(v),
formatDate: v => dayjs(v).format('YYYY-MM-DD HH:mm'), formatDate: v => dayjs(v).format('YYYY-MM-DD HH:mm'),
formatToken: v => tokenFormatter(v, {}), formatToken: v => tokenFormatter(v, {}),

View File

@ -5,7 +5,7 @@
:show="syncing" :show="syncing"
> >
<div class="alert-body"> <div class="alert-body">
<span>No new blocks have been produced since <strong>{{ latestTime }}</strong> </span> <span>{{$t('parameters.no_blocks_produced')}}<strong>{{ latestTime }}</strong> </span>
</div> </div>
</b-alert> </b-alert>
<b-row> <b-row>
@ -38,11 +38,15 @@
<parameters-module-component :data="slashing" /> <parameters-module-component :data="slashing" />
</b-col> </b-col>
</b-row> </b-row>
<b-card title="Application Version"> <b-card>
<object-field-component :tablefield="appVersion" /> <b-card-title class="card-title"><h4>{{$t('parameters.app_ver')}}</h4></b-card-title>
<b-card><object-field-component :tablefield="appVersion" /></b-card>
</b-card> </b-card>
<b-card title="Node Information"> <b-card>
<object-field-component :tablefield="nodeVersion" /> <b-card-title class="card-title">
<h4>{{$t('parameters.node_info')}}</h4>
</b-card-title>
<b-card><object-field-component :tablefield="nodeVersion" /></b-card>
</b-card> </b-card>
</div> </div>
</template> </template>

View File

@ -468,11 +468,10 @@ export default {
if (this.selectedStatus === 'inactive') return 'primary' if (this.selectedStatus === 'inactive') return 'primary'
const { index, item } = data const { index, item } = data
if (index === 0) { if (index === 0) {
window.sum = item.tokens window.sum = 0
} else {
window.sum += item.tokens
} }
const rank = window.sum / this.stakingPool const rank = window.sum / this.stakingPool
window.sum += item.tokens // sum up after the calculating.
if (rank < 0.333) { if (rank < 0.333) {
return 'danger' return 'danger'
} }

View File

@ -224,6 +224,7 @@
:operator-address="validator.operator_address" :operator-address="validator.operator_address"
:consensus-pubkey="validator.consensus_pubkey" :consensus-pubkey="validator.consensus_pubkey"
:account-address="accountAddress" :account-address="accountAddress"
:valcons-address="valconsAddress"
/> />
</b-col> </b-col>
</b-row> </b-row>
@ -273,7 +274,7 @@ import {
} from 'bootstrap-vue' } from 'bootstrap-vue'
import { import {
percent, formatToken, StakingParameters, Validator, operatorAddressToAccount, consensusPubkeyToHexAddress, toDay, abbrMessage, abbrAddress, percent, formatToken, StakingParameters, Validator, operatorAddressToAccount, consensusPubkeyToHexAddress, toDay, abbrMessage, abbrAddress, valoperToPrefix, pubKeyToValcons,
} from '@/libs/utils' } from '@/libs/utils'
import { keybase } from '@/libs/fetch' import { keybase } from '@/libs/fetch'
import OperationModal from '@/views/components/OperationModal/index.vue' import OperationModal from '@/views/components/OperationModal/index.vue'
@ -314,6 +315,7 @@ export default {
latestHeight: 0, latestHeight: 0,
accountAddress: '-', accountAddress: '-',
hexAddress: '-', hexAddress: '-',
valconsAddress: '-',
stakingPool: {}, stakingPool: {},
mintInflation: 0, mintInflation: 0,
stakingParameter: new StakingParameters(), stakingParameter: new StakingParameters(),
@ -384,8 +386,10 @@ export default {
return percent(value) return percent(value)
}, },
processAddress(operAddress, consensusPubkey) { processAddress(operAddress, consensusPubkey) {
const prefix = valoperToPrefix(operAddress)
this.accountAddress = operatorAddressToAccount(operAddress) this.accountAddress = operatorAddressToAccount(operAddress)
this.hexAddress = consensusPubkeyToHexAddress(consensusPubkey) this.hexAddress = consensusPubkeyToHexAddress(consensusPubkey)
this.valconsAddress = pubKeyToValcons(consensusPubkey, prefix)
this.$http.getStakingDelegatorDelegation(this.accountAddress, operAddress).then(d => { this.$http.getStakingDelegatorDelegation(this.accountAddress, operAddress).then(d => {
this.selfDelegation = d this.selfDelegation = d
}) })

View File

@ -13,7 +13,7 @@
</b-alert> </b-alert>
<b-card <b-card
v-if="error===null" v-if="error===null"
title="Basic" title="Summary"
class="text-truncate" class="text-truncate"
> >
<object-field-component <object-field-component
@ -46,7 +46,8 @@
variant="light-danger" variant="light-danger"
> >
Failed Failed
</b-badge><b v-if="tx.code > 0"> {{ tx.raw_log }}</b> </b-td> </b-badge>
</b-td>
</b-tr> </b-tr>
<b-tr> <b-tr>
<b-td> <b-td>
@ -85,26 +86,30 @@
</b-table-simple> </b-table-simple>
</b-card> </b-card>
<b-card <b-card v-if="tx.tx.messages">
v-if="tx.tx.messages" <b-card-title>Messages (total: {{ tx.tx.messages.length }})</b-card-title>
:title="`Messages (total: ${tx.tx.messages.length})`"
no-body
>
<b-card-body <b-card-body
v-for="(item, i) in tx.tx.messages " v-for="(item, i) in tx.tx.messages "
id="message" id="message"
:key="i" :key="i"
class="message" class="message px-0"
> >
<object-field-component :tablefield="item" /> <object-field-component :tablefield="item" />
</b-card-body> </b-card-body>
</b-card> </b-card>
<b-card
v-if="tx.element"
title="Details"
>
<object-field-component :tablefield="tx.element.tx_response" />
</b-card>
</div> </div>
</template> </template>
<script> <script>
import { import {
BCard, BTableSimple, BTr, BTd, BBadge, BCardBody, BAlert, BCard, BTableSimple, BTr, BTd, BBadge, BCardBody, BAlert, BCardTitle,
} from 'bootstrap-vue' } from 'bootstrap-vue'
import { toDay, tokenFormatter } from '@/libs/utils' import { toDay, tokenFormatter } from '@/libs/utils'
import ObjectFieldComponent from './components/ObjectFieldComponent.vue' import ObjectFieldComponent from './components/ObjectFieldComponent.vue'
@ -113,6 +118,7 @@ export default {
components: { components: {
BAlert, BAlert,
BCard, BCard,
BCardTitle,
BCardBody, BCardBody,
BTableSimple, BTableSimple,
BTr, BTr,

View File

@ -277,25 +277,20 @@ export default {
}) })
return Object.values(valCounter).sort((a, b) => b.counter - a.counter) return Object.values(valCounter).sort((a, b) => b.counter - a.counter)
}, },
h() {
return this.height
},
}, },
created() { created() {
const cached = JSON.parse(getCachedValidators(this.$route.params.chain)) const cached = JSON.parse(getCachedValidators(this.$route.params.chain))
if (cached) { if (cached) {
this.validators = cached this.validators = cached
} }
this.fetchMissingInfo()
this.$http.getValidatorList().then(res => { this.$http.getValidatorList().then(res => {
this.validators = res this.validators = res
}) })
this.$http.getSlashingSigningInfo().then(res => {
if (res.info) {
res.info.forEach(x => {
if (x.address) {
const hex = toBase64(fromBech32(x.address).data)
this.missing[hex] = x
}
})
}
})
this.initBlocks() this.initBlocks()
}, },
beforeDestroy() { beforeDestroy() {
@ -304,6 +299,18 @@ export default {
clearInterval(this.timer) clearInterval(this.timer)
}, },
methods: { methods: {
fetchMissingInfo() {
this.$http.getSlashingSigningInfo().then(res => {
if (res.info) {
res.info.forEach(x => {
if (x.address) {
const hex = toBase64(fromBech32(x.address).data)
this.missing[hex] = x
}
})
}
})
},
pinValidator() { pinValidator() {
localStorage.setItem('pinned', this.pinned) localStorage.setItem('pinned', this.pinned)
}, },
@ -319,13 +326,15 @@ export default {
const blocks = [] const blocks = []
// update height // update height
let promise = Promise.resolve() let promise = Promise.resolve()
for (let i = height - 1; i > height - 50; i -= 1) { for (let i = height - 1; i > height - 48; i -= 1) {
blocks.unshift({ sigs: {}, height: i > 0 ? i : 0 }) blocks.unshift({ sigs: {}, height: i > 0 ? i : 0 })
if (i > height - 48 && i > 0) { promise = promise.then(() => new Promise(resolve => {
promise = promise.then(() => new Promise(resolve => { if (i > this.blocks[0].height && i > 0) { // filter useless loading
this.fetch_status(i, resolve) this.fetch_status(i, resolve)
})) } else {
} resolve()
}
}))
} }
const sigs = this.initColor() const sigs = this.initColor()
@ -386,7 +395,10 @@ export default {
res.block.last_commit.signatures.forEach(x => { res.block.last_commit.signatures.forEach(x => {
if (x.validator_address) sigs[x.validator_address] = 'bg-success' if (x.validator_address) sigs[x.validator_address] = 'bg-success'
}) })
this.height = res.block.header.height this.height = Number(res.block.header.height)
if (this.height % 100 === 0) { // update the missing number each 100
this.fetchMissingInfo()
}
const block = this.blocks.find(b => b.height === res.block.last_commit.height) const block = this.blocks.find(b => b.height === res.block.last_commit.height)
if (typeof block === 'undefined') { // mei if (typeof block === 'undefined') { // mei
// this.$set(block, 0, typeof sigs !== 'undefined') // this.$set(block, 0, typeof sigs !== 'undefined')

View File

@ -2,21 +2,21 @@
<div class="px-0"> <div class="px-0">
<b-card> <b-card>
<b-card-title class="d-flex justify-content-between"> <b-card-title class="d-flex justify-content-between">
<span class="text-uppercase"> {{ chain }} </span><small class="text-right"> Height: {{ height }} </small> <span class="text-uppercase"> {{ chain }} </span><small class="text-right"> {{$t('uptimeMyChainBlocks.height')}} {{ height }} </small>
</b-card-title> </b-card-title>
<b-alert <b-alert
variant="danger" variant="danger"
:show="syncing" :show="syncing"
> >
<div class="alert-body"> <div class="alert-body">
<span>No new blocks have been produced since <strong>{{ latestTime }}</strong> </span> <span>{{$t('uptimeMyChainBlocks.no_blocks_produced')}}<strong>{{ latestTime }}</strong> </span>
</div> </div>
</b-alert> </b-alert>
<b-row> <b-row>
<span <span
v-if="uptime.length===0" v-if="uptime.length===0"
class="text-danger" class="text-danger"
> Your node is out of active validator set</span> > {{$t(uptimeMyChainBlocks.not_active)}}</span>
<b-col <b-col
v-for="(x,index) in uptime" v-for="(x,index) in uptime"
:key="index" :key="index"

View File

@ -21,12 +21,12 @@
show show
> >
<div class="alert-heading"> <div class="alert-heading">
Tips {{ $t('uptimeMyValidators.tips') }}
</div> </div>
<div class="alert-body"> <div class="alert-body">
There are two ways to monitor your validators: {{ $t('uptimeMyValidators.two_ways') }}
<li> Pin a validator on Uptime pages.</li> <li> {{ $t('uptimeMyValidators.pin') }}</li>
<li> Specify parameters like following: <pre>https://ping.pub/cosmos/uptime/my?validators={"sifchain":["FBADE9A30473BB9ED6DFA16BFB3838E028F33650"],"chain_name":["hexAddress"]}</pre></li> <li> {{ $t('uptimeMyValidators.link') }} <pre>https://ping.pub/cosmos/uptime/my?validators={"sifchain":["FBADE9A30473BB9ED6DFA16BFB3838E028F33650"],"chain_name":["hexAddress"]}</pre></li>
</div> </div>
</b-alert> </b-alert>
</div> </div>

View File

@ -23,7 +23,7 @@
style="color: #fff" style="color: #fff"
class="mb-0" class="mb-0"
> >
Address: <feather-icon {{ $t('walletAccountDetail.address') }} <feather-icon
icon="CopyIcon" icon="CopyIcon"
size="18" size="18"
@click="copy()" @click="copy()"
@ -38,7 +38,7 @@
class="d-flex flex-row" class="d-flex flex-row"
> >
<b-card-header class="pt-0 pl-0 pr-0"> <b-card-header class="pt-0 pl-0 pr-0">
<b-card-title>Assets</b-card-title> <b-card-title>{{ $t('walletAccountDetail.assets') }}</b-card-title>
<div> <div>
<b-button <b-button
v-b-modal.operation-modal v-b-modal.operation-modal
@ -50,7 +50,7 @@
<feather-icon <feather-icon
icon="SendIcon" icon="SendIcon"
class="d-md-none" class="d-md-none"
/><small class="d-none d-md-block">Transfer</small> /><small class="d-none d-md-block">{{ $t('walletAccountDetail.transfer') }}</small>
</b-button> </b-button>
<b-button <b-button
v-b-modal.operation-modal v-b-modal.operation-modal
@ -61,7 +61,7 @@
icon="SendIcon" icon="SendIcon"
class="d-md-none" class="d-md-none"
/> />
<span class="d-none d-md-block">IBC Transfer</span> <span class="d-none d-md-block">{{ $t('walletAccountDetail.ibc_transfer') }}</span>
</b-button> </b-button>
</div> </div>
</b-card-header> </b-card-header>
@ -117,7 +117,7 @@
</div> </div>
<!--/ tokens --> <!--/ tokens -->
<div class="text-right border-top pt-1"> <div class="text-right border-top pt-1">
<h2>Total: {{ currency }}{{ formatNumber(assetTable.currency) }}</h2> <h2>{{ $t('walletAccountDetail.total') }}{{ currency }}{{ formatNumber(assetTable.currency) }}</h2>
</div> </div>
</b-col> </b-col>
</b-row> </b-row>
@ -127,7 +127,7 @@
v-if="unbonding && unbonding.length > 0" v-if="unbonding && unbonding.length > 0"
> >
<b-card-header class="pt-0 pl-0 pr-0"> <b-card-header class="pt-0 pl-0 pr-0">
<b-card-title>Unbonding Tokens</b-card-title> <b-card-title>{{ $t('walletAccountDetail.unbonding') }}</b-card-title>
</b-card-header> </b-card-header>
<b-card-body class="pl-0 pr-0"> <b-card-body class="pl-0 pr-0">
<b-row <b-row
@ -135,7 +135,7 @@
:key="item.validator_address" :key="item.validator_address"
> >
<b-col cols="12"> <b-col cols="12">
<span class="font-weight-bolder">From: <router-link :to="`../staking/${item.validator_address}`">{{ item.validator_address }}</router-link></span> <span class="font-weight-bolder">{{ $t('walletAccountDetail.from') }}<router-link :to="`../staking/${item.validator_address}`">{{ item.validator_address }}</router-link></span>
</b-col> </b-col>
<b-col cols="12"> <b-col cols="12">
<b-table <b-table
@ -164,7 +164,7 @@
v-if="delegations" v-if="delegations"
> >
<b-card-header class="pt-0 pl-0 pr-0"> <b-card-header class="pt-0 pl-0 pr-0">
<b-card-title>Delegation</b-card-title> <b-card-title>{{ $t('walletAccountDetail.delegation') }}</b-card-title>
<div> <div>
<b-button <b-button
v-b-modal.operation-modal v-b-modal.operation-modal
@ -176,7 +176,7 @@
<feather-icon <feather-icon
icon="LogInIcon" icon="LogInIcon"
class="d-md-none" class="d-md-none"
/><small class="d-none d-md-block">Delegate</small> /><small class="d-none d-md-block">{{ $t('walletAccountDetail.delegate') }}</small>
</b-button> </b-button>
<b-button <b-button
v-if="delegations" v-if="delegations"
@ -188,7 +188,7 @@
<feather-icon <feather-icon
icon="ShareIcon" icon="ShareIcon"
class="d-md-none" class="d-md-none"
/><small class="d-none d-md-block"> Withdraw Rewards</small> /><small class="d-none d-md-block">{{ $t('walletAccountDetail.withdraw') }}</small>
</b-button> </b-button>
</div> </div>
</b-card-header> </b-card-header>
@ -197,6 +197,15 @@
:items="deleTable" :items="deleTable"
stacked="sm" stacked="sm"
> >
<template #cell(validator)="data">
<span>
<router-link
:to="`../staking/${data.value.address}`"
>
{{ data.value.moniker }}
</router-link>
</span>
</template>
<template #cell(action)="data"> <template #cell(action)="data">
<!-- size --> <!-- size -->
<b-button-group <b-button-group
@ -275,25 +284,25 @@
<b-tbody v-if="account.type === 'cosmos-sdk/BaseAccount'"> <b-tbody v-if="account.type === 'cosmos-sdk/BaseAccount'">
<b-tr> <b-tr>
<b-td> <b-td>
Account Type {{ $t('walletAccountDetail.acct_type') }}
</b-td><b-td> {{ account.type }} </b-td> </b-td><b-td> {{ account.type }} </b-td>
</b-tr> </b-tr>
<b-tr> <b-tr>
<b-td class="max-width:100px;"> <b-td class="max-width:100px;">
Account Number {{ $t('walletAccountDetail.acct_num') }}
</b-td><b-td> {{ account.value.account_number }} </b-td> </b-td><b-td> {{ account.value.account_number }} </b-td>
</b-tr> </b-tr>
<b-tr> <b-tr>
<b-td> Sequence </b-td><b-td> {{ account.value.sequence }} </b-td> <b-td> {{ $t('walletAccountDetail.seq') }} </b-td><b-td> {{ account.value.sequence }} </b-td>
</b-tr> </b-tr>
<b-tr> <b-tr>
<b-td> Public Key </b-td><b-td> <object-field-component :tablefield="account.value.public_key" /> </b-td> <b-td> {{ $t('walletAccountDetail.pub_key') }} </b-td><b-td> <object-field-component :tablefield="account.value.public_key" /> </b-td>
</b-tr> </b-tr>
</b-tbody> </b-tbody>
<b-tbody v-else-if="account.type === 'cosmos-sdk/PeriodicVestingAccount' && account.value.base_vesting_account"> <b-tbody v-else-if="account.type === 'cosmos-sdk/PeriodicVestingAccount' && account.value.base_vesting_account">
<b-tr> <b-tr>
<b-td> <b-td>
Account Type {{ $t('walletAccountDetail.acct_type') }}
</b-td> </b-td>
<b-td> <b-td>
{{ account.type }} {{ account.type }}
@ -301,32 +310,32 @@
</b-tr> </b-tr>
<b-tr> <b-tr>
<b-td> <b-td>
Account Number {{ $t('walletAccountDetail.acct_num') }}
</b-td><b-td> {{ account.value.base_vesting_account.base_account.account_number }} </b-td> </b-td><b-td> {{ account.value.base_vesting_account.base_account.account_number }} </b-td>
</b-tr> </b-tr>
<b-tr> <b-tr>
<b-td> Sequence </b-td><b-td> {{ account.value.base_vesting_account.base_account.sequence }} </b-td> <b-td> {{ $t('walletAccountDetail.seq') }} </b-td><b-td> {{ account.value.base_vesting_account.base_account.sequence }} </b-td>
</b-tr> </b-tr>
<b-tr> <b-tr>
<b-td> Public Key </b-td><b-td> <object-field-component :tablefield="account.value.base_vesting_account.base_account.public_key" /> </b-td> <b-td> {{ $t('walletAccountDetail.pub_key') }} </b-td><b-td> <object-field-component :tablefield="account.value.base_vesting_account.base_account.public_key" /> </b-td>
</b-tr> </b-tr>
<b-tr> <b-tr>
<b-td> Original Vesting </b-td><b-td> {{ formatToken(account.value.base_vesting_account.original_vesting) }} </b-td> <b-td> {{ $t('walletAccountDetail.orig_vest') }} </b-td><b-td> {{ formatToken(account.value.base_vesting_account.original_vesting) }} </b-td>
</b-tr> </b-tr>
<b-tr> <b-tr>
<b-td> Delegated Free </b-td><b-td> {{ formatToken(account.value.base_vesting_account.delegated_free) }} </b-td> <b-td> {{ $t('walletAccountDetail.delegated_free') }} </b-td><b-td> {{ formatToken(account.value.base_vesting_account.delegated_free) }} </b-td>
</b-tr> </b-tr>
<b-tr> <b-tr>
<b-td> Delegated Vesting </b-td><b-td> {{ formatToken(account.value.base_vesting_account.delegated_vesting) }} </b-td> <b-td> {{ $t('walletAccountDetail.delegated_vest') }} </b-td><b-td> {{ formatToken(account.value.base_vesting_account.delegated_vesting) }} </b-td>
</b-tr> </b-tr>
<b-tr> <b-tr>
<b-td> Vesting Time </b-td><b-td> {{ formatTime(account.value.start_time) }} - {{ formatTime(account.value.base_vesting_account.end_time) }}</b-td> <b-td> {{ $t('walletAccountDetail.vest_time') }} </b-td><b-td> {{ formatTime(account.value.start_time) }} - {{ formatTime(account.value.base_vesting_account.end_time) }}</b-td>
</b-tr> </b-tr>
<b-tr> <b-tr>
<b-td> Vesting Periods </b-td> <b-td> {{ $t('walletAccountDetail.vest_period') }} </b-td>
<b-td> <b-td>
<b-table-simple> <b-table-simple>
<th>Length</th><th>Amount</th> <th>{{ $t('walletAccountDetail.length') }}</th><th>{{ $t('walletAccountDetail.amount') }}</th>
<b-tr <b-tr
v-for="p, index in account.value.vesting_periods" v-for="p, index in account.value.vesting_periods"
:key="index" :key="index"
@ -340,31 +349,31 @@
<b-tbody v-else-if="account.type === 'cosmos-sdk/DelayedVestingAccount' && account.value.base_vesting_account"> <b-tbody v-else-if="account.type === 'cosmos-sdk/DelayedVestingAccount' && account.value.base_vesting_account">
<b-tr> <b-tr>
<b-td> <b-td>
Account Type {{ $t('walletAccountDetail.acct_type') }}
</b-td><b-td> {{ account.type }} </b-td> </b-td><b-td> {{ account.type }} </b-td>
</b-tr> </b-tr>
<b-tr> <b-tr>
<b-td style="max-width:100px;"> <b-td style="max-width:100px;">
Account Number {{ $t('walletAccountDetail.acct_num') }}
</b-td><b-td> {{ account.value.base_vesting_account.base_account.account_number }} </b-td> </b-td><b-td> {{ account.value.base_vesting_account.base_account.account_number }} </b-td>
</b-tr> </b-tr>
<b-tr> <b-tr>
<b-td> Sequence </b-td><b-td> {{ account.value.base_vesting_account.base_account.sequence }} </b-td> <b-td> {{ $t('walletAccountDetail.seq') }} </b-td><b-td> {{ account.value.base_vesting_account.base_account.sequence }} </b-td>
</b-tr> </b-tr>
<b-tr> <b-tr>
<b-td> Public Key </b-td><b-td> <object-field-component :tablefield="account.value.base_vesting_account.base_account.public_key" /> </b-td> <b-td> {{ $t('walletAccountDetail.pub_key') }} </b-td><b-td> <object-field-component :tablefield="account.value.base_vesting_account.base_account.public_key" /> </b-td>
</b-tr> </b-tr>
<b-tr> <b-tr>
<b-td> Original Vesting </b-td><b-td> {{ formatToken(account.value.base_vesting_account.original_vesting) }} </b-td> <b-td> {{ $t('walletAccountDetail.orig_vest') }} </b-td><b-td> {{ formatToken(account.value.base_vesting_account.original_vesting) }} </b-td>
</b-tr> </b-tr>
<b-tr> <b-tr>
<b-td> Delegated Free </b-td><b-td> {{ formatToken(account.value.base_vesting_account.delegated_free) }} </b-td> <b-td> {{ $t('walletAccountDetail.delegated_free') }} </b-td><b-td> {{ formatToken(account.value.base_vesting_account.delegated_free) }} </b-td>
</b-tr> </b-tr>
<b-tr> <b-tr>
<b-td> Delegated Vesting </b-td><b-td> {{ formatToken(account.value.base_vesting_account.delegated_vesting) }} </b-td> <b-td> {{ $t('walletAccountDetail.delegated_vest') }} </b-td><b-td> {{ formatToken(account.value.base_vesting_account.delegated_vesting) }} </b-td>
</b-tr> </b-tr>
<b-tr> <b-tr>
<b-td> End Time </b-td><b-td> {{ formatTime(account.value.base_vesting_account.end_time) }}</b-td> <b-td> {{ $t('walletAccountDetail.end_time') }} </b-td><b-td> {{ formatTime(account.value.base_vesting_account.end_time) }}</b-td>
</b-tr> </b-tr>
</b-tbody> </b-tbody>
<object-field-component <object-field-component
@ -394,10 +403,10 @@
<div class="misc-inner p-2 p-sm-3"> <div class="misc-inner p-2 p-sm-3">
<div class="w-100 text-center"> <div class="w-100 text-center">
<h2 class="mb-1"> <h2 class="mb-1">
Account not found 🕵🏻 {{ $t('walletAccountDetail.acct_not_found') }} 🕵🏻
</h2> </h2>
<p class="mb-2"> <p class="mb-2">
Oops! 😖 {{ error }}. {{ $t('walletAccountDetail.opps') }} 😖 {{ error }}.
</p> </p>
<b-button <b-button
@ -405,7 +414,7 @@
class="mb-2 btn-sm-block" class="mb-2 btn-sm-block"
:to="{path:'../'}" :to="{path:'../'}"
> >
Back to home {{ $t('walletAccountDetail.back_home') }}
</b-button> </b-button>
</div> </div>
</div> </div>
@ -621,12 +630,17 @@ export default {
}, },
deleTable() { deleTable() {
const re = [] const re = []
const conf = this.$http.getSelectedConfig()
const decimal = conf.assets[0].exponent || '6'
if (this.reward.rewards && this.delegations && this.delegations.length > 0) { if (this.reward.rewards && this.delegations && this.delegations.length > 0) {
this.delegations.forEach(e => { this.delegations.forEach(e => {
const reward = this.reward.rewards.find(r => r.validator_address === e.delegation.validator_address) const reward = this.reward.rewards.find(r => r.validator_address === e.delegation.validator_address)
re.push({ re.push({
validator: getStakingValidatorOperator(this.$http.config.chain_name, e.delegation.validator_address, 8), validator: {
token: formatToken(e.balance, {}, 2), moniker: getStakingValidatorOperator(this.$http.config.chain_name, e.delegation.validator_address, 8),
address: e.delegation.validator_address,
},
token: formatToken(e.balance, {}, decimal),
reward: tokenFormatter(reward.reward, this.denoms), reward: tokenFormatter(reward.reward, this.denoms),
action: e.delegation.validator_address, action: e.delegation.validator_address,
}) })

View File

@ -464,15 +464,20 @@ export default {
} }
}, },
initParamsForKeplr(chainid, chain) { initParamsForKeplr(chainid, chain) {
const gasPriceStep = chain.keplr_price_step || {
low: 0.01,
average: 0.025,
high: 0.03,
}
return JSON.stringify({ return JSON.stringify({
chainId: chainid, chainId: chainid,
chainName: chain.chain_name, chainName: chain.chain_name,
rpc: Array.isArray(chain.rpc) ? chain.rpc[0] : chain.rpc, rpc: Array.isArray(chain.rpc) ? chain.rpc[0] : chain.rpc,
rest: Array.isArray(chain.api) ? chain.api[0] : chain.api, rest: Array.isArray(chain.api) ? chain.api[0] : chain.api,
bip44: { bip44: {
coinType: chain.coin_type, coinType: Number(chain.coin_type),
}, },
coinType: chain.coin_type, coinType: Number(chain.coin_type),
bech32Config: { bech32Config: {
bech32PrefixAccAddr: chain.addr_prefix, bech32PrefixAccAddr: chain.addr_prefix,
bech32PrefixAccPub: `${chain.addr_prefix}pub`, bech32PrefixAccPub: `${chain.addr_prefix}pub`,
@ -485,7 +490,7 @@ export default {
{ {
coinDenom: chain.assets[0].symbol, coinDenom: chain.assets[0].symbol,
coinMinimalDenom: chain.assets[0].base, coinMinimalDenom: chain.assets[0].base,
coinDecimals: chain.assets[0].exponent, coinDecimals: Number(chain.assets[0].exponent),
coinGeckoId: chain.assets[0].coingecko_id || 'unknown', coinGeckoId: chain.assets[0].coingecko_id || 'unknown',
}, },
], ],
@ -493,21 +498,18 @@ export default {
{ {
coinDenom: chain.assets[0].symbol, coinDenom: chain.assets[0].symbol,
coinMinimalDenom: chain.assets[0].base, coinMinimalDenom: chain.assets[0].base,
coinDecimals: chain.assets[0].exponent, coinDecimals: Number(chain.assets[0].exponent),
coinGeckoId: chain.assets[0].coingecko_id || 'unknown', coinGeckoId: chain.assets[0].coingecko_id || 'unknown',
gasPriceStep,
}, },
], ],
gasPriceStep,
stakeCurrency: { stakeCurrency: {
coinDenom: chain.assets[0].symbol, coinDenom: chain.assets[0].symbol,
coinMinimalDenom: chain.assets[0].base, coinMinimalDenom: chain.assets[0].base,
coinDecimals: chain.assets[0].exponent, coinDecimals: Number(chain.assets[0].exponent),
coinGeckoId: chain.assets[0].coingecko_id || 'unknown', coinGeckoId: chain.assets[0].coingecko_id || 'unknown',
}, },
gasPriceStep: {
low: 0.01,
average: 0.025,
high: 0.03,
},
features: chain.keplr_features || [], features: chain.keplr_features || [],
}, null, '\t') }, null, '\t')
}, },

View File

@ -119,6 +119,8 @@ export default {
}, },
computed: { computed: {
formatedDelegations() { formatedDelegations() {
const conf = this.$http.getSelectedConfig()
const decimal = conf.assets[0].exponent || '6'
return this.delegations.map(x => ({ return this.delegations.map(x => ({
validator: { validator: {
logo: x.chain.logo, logo: x.chain.logo,
@ -128,13 +130,15 @@ export default {
}, },
delegator: x.keyname, delegator: x.keyname,
delegator_address: x.delegation.delegator_address, delegator_address: x.delegation.delegator_address,
delegation: formatToken(x.balance), delegation: formatToken(x.balance, {}, decimal),
reward: this.findReward(x.delegation.delegator_address, x.delegation.validator_address), reward: this.findReward(x.delegation.delegator_address, x.delegation.validator_address),
// action: '', // action: '',
})) }))
}, },
groupedDelegations() { groupedDelegations() {
const group = {} const group = {}
const conf = this.$http.getSelectedConfig()
const decimal = conf.assets[0].exponent || '6'
this.delegations.forEach(x => { this.delegations.forEach(x => {
const d = { const d = {
validator: { validator: {
@ -145,7 +149,7 @@ export default {
}, },
delegator: x.keyname, delegator: x.keyname,
delegator_address: x.delegation.delegator_address, delegator_address: x.delegation.delegator_address,
delegation: formatToken(x.balance), delegation: formatToken(x.balance, {}, decimal),
reward: this.findReward(x.delegation.delegator_address, x.delegation.validator_address), reward: this.findReward(x.delegation.delegator_address, x.delegation.validator_address),
// action: '', // action: '',
} }

View File

@ -69,7 +69,6 @@
</h6> </h6>
</div> </div>
</div> </div>
<b-progress <b-progress
:max="100" :max="100"
height="2rem" height="2rem"
@ -85,21 +84,21 @@
/> />
<b-progress-bar <b-progress-bar
:id="'vote-no'+p.id" :id="'vote-no'+p.id"
variant="warning" variant="danger"
:value="percent(p.tally.no)" :value="percent(p.tally.no)"
:label="`${percent(p.tally.no).toFixed()}%`" :label="`${percent(p.tally.no).toFixed()}%`"
show-progress show-progress
/> />
<b-progress-bar <b-progress-bar
:id="'vote-veto'+p.id" :id="'vote-veto'+p.id"
variant="danger" class="bg-danger bg-darken-4"
:value="percent(p.tally.veto)" :value="percent(p.tally.veto)"
:label="`${percent(p.tally.veto).toFixed()}%`" :label="`${percent(p.tally.veto).toFixed()}%`"
show-progress show-progress
/> />
<b-progress-bar <b-progress-bar
:id="'vote-abstain'+p.id" :id="'vote-abstain'+p.id"
variant="info" variant="secondary"
:value="percent(p.tally.abstain)" :value="percent(p.tally.abstain)"
:label="`${percent(p.tally.abstain).toFixed()}%`" :label="`${percent(p.tally.abstain).toFixed()}%`"
show-progress show-progress
@ -129,7 +128,7 @@
<span <span
v-for="(v,k) in p.votes" v-for="(v,k) in p.votes"
:key="k" :key="k"
> <b-badge :variant="color(v.vote.option)">{{ v.keyname }} : {{ v.vote.option }}</b-badge></span> > <b-badge :variant="color(v.vote.option)">{{ v.keyname }} : {{ formatOption(v.vote.option) }}</b-badge></span>
</b-card-footer> </b-card-footer>
</b-card> </b-card>
</b-col> </b-col>
@ -237,6 +236,13 @@ export default {
percent: v => percent(v), percent: v => percent(v),
formatDate: v => dayjs(v).format('YYYY-MM-DD'), formatDate: v => dayjs(v).format('YYYY-MM-DD'),
formatToken: v => tokenFormatter(v, {}), formatToken: v => tokenFormatter(v, {}),
formatOption: v => {
const start = String(v).lastIndexOf('_')
if (start > 0) {
return String(v).substring(start + 1)
}
return v
},
init() { init() {
this.accounts = getLocalAccounts() this.accounts = getLocalAccounts()
if (this.accounts) { if (this.accounts) {

View File

@ -63,7 +63,7 @@
/> />
</b-progress> </b-progress>
<div class="status-text"> <div class="status-text">
<span v-if="hash">SUBMITED</span> <span v-if="hash">SUBMITTED</span>
<span v-if="succeed">COMPLETED</span> <span v-if="succeed">COMPLETED</span>
<span v-if="error">FAILED</span> <span v-if="error">FAILED</span>
</div> </div>

View File

@ -235,7 +235,9 @@ export default {
return formatTokenDenom(this.token) return formatTokenDenom(this.token)
}, },
format(v) { format(v) {
return formatToken(v, this.IBCDenom, 6) const conf = this.$http.getSelectedConfig()
const decimal = conf.assets[0].exponent || '6'
return formatToken(v, this.IBCDenom, decimal)
}, },
}, },
} }

View File

@ -179,8 +179,10 @@ export default {
return options return options
}, },
tokenOptions() { tokenOptions() {
const conf = this.$http.getSelectedConfig()
const decimal = conf.assets[0].exponent || '6'
if (!this.delegations) return [] if (!this.delegations) return []
return this.delegations.filter(x => x.delegation.validator_address === this.validatorAddress).map(x => ({ value: x.balance.denom, label: formatToken(x.balance) })) return this.delegations.filter(x => x.delegation.validator_address === this.validatorAddress).map(x => ({ value: x.balance.denom, label: formatToken(x.balance, {}, decimal) }))
}, },
msg() { msg() {
return [{ return [{

View File

@ -5,29 +5,53 @@
<h4 class="mb-25 font-weight-bolder"> <h4 class="mb-25 font-weight-bolder">
{{ statistic || '-' }} {{ statistic || '-' }}
</h4> </h4>
<span>{{ statisticTitle }}</span> <span v-if="!statistic || statistic === '-'">{{ statisticTitle }}</span>
<span v-else-if="changes === 0">
{{ showPrice(statistic, statisticTitle) }}
</span>
<span
v-else-if="changes < 0"
v-b-tooltip.hover.v-danger
:title="`${changes.toFixed(1)}%`"
class="text-danger"
>
{{ showPrice(statistic, statisticTitle) }}
</span>
<span
v-else
v-b-tooltip.hover.v-success
:title="`+${changes.toFixed(1)}%`"
class="text-success"
>
{{ showPrice(statistic, statisticTitle) }}
</span>
</div> </div>
<b-avatar <b-avatar
v-b-tooltip.hover
:variant="`light-${color}`" :variant="`light-${color}`"
size="45" size="45"
> :text="statisticTitle.substring(0,1)"
<feather-icon :title="statisticTitle"
size="21" />
:icon="icon"
/>
</b-avatar>
</b-card-body> </b-card-body>
</b-card> </b-card>
</template> </template>
<script> <script>
import { BCard, BCardBody, BAvatar } from 'bootstrap-vue' import {
BCard, BCardBody, BAvatar, VBTooltip,
} from 'bootstrap-vue'
import { getUserCurrency, getUserCurrencySign } from '@/libs/utils'
export default { export default {
components: { components: {
BCard, BCard,
BCardBody, BCardBody,
BAvatar, BAvatar,
VBTooltip,
},
directives: {
'b-tooltip': VBTooltip,
}, },
props: { props: {
icon: { icon: {
@ -47,5 +71,24 @@ export default {
default: 'primary', default: 'primary',
}, },
}, },
data() {
return {
changes: 0,
}
},
methods: {
showPrice(v, statisticTitle) {
const token = String(v).split(' ')
if (token.length >= 2) {
const quote = this.$store.state.chains.quotes[token[1]]
if (quote) {
const price = quote[getUserCurrency()]
this.changes = quote[`${getUserCurrency()}_24h_change`]
return `${getUserCurrencySign()}${(Number(token[0].replaceAll(',', '')) * price).toFixed(2)}`
}
}
return statisticTitle
},
},
} }
</script> </script>

View File

@ -20,27 +20,27 @@
<div class="gov-wrapper flex-wrap my-1"> <div class="gov-wrapper flex-wrap my-1">
<div class="gov"> <div class="gov">
<p class="card-text mb-25"> <p class="card-text mb-25">
Status {{$t('governanceProposal.proposal_status')}}
</p> </p>
<h6 class="mb-0"> <h6 class="mb-0">
<span v-if="p.status == 1"> <span v-if="p.status == 1">
Deposit {{$t('governanceProposal.proposal_status_deposit')}}
</span> </span>
<span v-else-if="p.status == 2"> <span v-else-if="p.status == 2">
Voting {{$t('governanceProposal.proposal_status_voting')}}
</span> </span>
<span v-else-if="p.status == 3"> <span v-else-if="p.status == 3">
Passed {{$t('governanceProposal.proposal_status_passed')}}
</span> </span>
<span v-else-if="p.status == 4"> <span v-else-if="p.status == 4">
Rejected {{$t('governanceProposal.proposal_status_rejected')}}
</span> </span>
<span v-else>{{ p.status }}</span> <span v-else>{{ p.status }}</span>
</h6> </h6>
</div> </div>
<div class="gov"> <div class="gov">
<p class="card-text mb-25"> <p class="card-text mb-25">
Start Date {{$t('governanceProposal.proposal_status_start_date')}}
</p> </p>
<h6 class="mb-0"> <h6 class="mb-0">
{{ formatDate(p.voting_start_time) }} {{ formatDate(p.voting_start_time) }}
@ -48,7 +48,7 @@
</div> </div>
<div class="gov"> <div class="gov">
<p class="card-text mb-25"> <p class="card-text mb-25">
End Date {{$t('governanceProposal.proposal_status_end_date')}}
</p> </p>
<h6 class="mb-0"> <h6 class="mb-0">
{{ formatDate(p.voting_end_time) }} {{ formatDate(p.voting_end_time) }}
@ -56,108 +56,126 @@
</div> </div>
<div class="gov"> <div class="gov">
<p class="card-text mb-25"> <p class="card-text mb-25">
Deposit {{$t('governanceProposal.proposal_status_deposit')}}
</p> </p>
<h6 class="mb-0"> <h6 class="mb-0">
{{ formatToken(p.total_deposit) || '-' }} {{ formatToken(p.total_deposit) || '-' }}
</h6> </h6>
</div> </div>
</div> </div>
<div>
<b-progress <div class="scale">
:max="100" <div class="box">
height="2rem" <b-progress
class="mb-2" :max="totalPower && p.status === 2? 100 * (totalPower/p.tally.total) :100"
show-progress height="2rem"
> class="mb-2"
<b-progress-bar show-progress
:id="'vote-yes'+p.id" >
variant="success" <b-progress-bar
:value="percent(p.tally.yes)" :id="'vote-yes'+p.id"
show-progress variant="success"
:label="`${percent(p.tally.yes).toFixed()}%`" :value="percent(p.tally.yes)"
/> show-progress
<b-progress-bar :label="`${percent(p.tally.yes).toFixed()}%`"
:id="'vote-no'+p.id" />
variant="warning" <b-progress-bar
:value="percent(p.tally.no)" :id="'vote-no'+p.id"
:label="`${percent(p.tally.no).toFixed()}%`" variant="danger"
show-progress :value="percent(p.tally.no)"
/> :label="`${percent(p.tally.no).toFixed()}%`"
<b-progress-bar show-progress
:id="'vote-veto'+p.id" />
variant="danger" <b-progress-bar
:value="percent(p.tally.veto)" :id="'vote-veto'+p.id"
:label="`${percent(p.tally.veto).toFixed()}%`" class="bg-danger bg-darken-4"
show-progress :value="percent(p.tally.veto)"
/> :label="`${percent(p.tally.veto).toFixed()}%`"
<b-progress-bar show-progress
:id="'vote-abstain'+p.id" />
variant="secondary" <b-progress-bar
:value="percent(p.tally.abstain)" :id="'vote-abstain'+p.id"
:label="`${percent(p.tally.abstain).toFixed()}%`" variant="secondary"
show-progress :value="percent(p.tally.abstain)"
/> :label="`${percent(p.tally.abstain).toFixed()}%`"
</b-progress> show-progress
<b-tooltip />
:target="'vote-yes'+p.id" </b-progress>
> <div
{{ percent(p.tally.yes) }}% voted Yes v-if="tallyParam"
</b-tooltip> v-b-tooltip.hover
<b-tooltip title="Threshold"
:target="'vote-no'+p.id" class="box overlay"
> :style="`left:${scaleWidth(p)}%;`"
{{ percent(p.tally.no) }}% voted No />
</b-tooltip> <div
<b-tooltip v-if="tallyParam && p.status === 2"
:target="'vote-veto'+p.id" v-b-tooltip.hover
> title="Quorum"
{{ percent(p.tally.veto) }}% voted No With Veto class="box overlay"
</b-tooltip> :style="`left:${Number(tallyParam.quorum) * 100}%; border-color:black`"
<b-tooltip />
:target="'vote-abstain'+p.id" </div>
> <b-tooltip
{{ percent(p.tally.abstain) }}% voted Abstain :target="'vote-yes'+p.id"
</b-tooltip> >
<b-card-footer class="pb-0"> {{ percent(p.tally.yes) }}% {{ $t('governanceProposal.proposal_votes_yes') }}
<router-link </b-tooltip>
v-ripple.400="'rgba(113, 102, 240, 0.15)'" <b-tooltip
:to="`./gov/${p.id}`" :target="'vote-no'+p.id"
variant="outline-primary" >
> {{ percent(p.tally.no) }}% {{ $t('governanceProposal.proposal_votes_no') }}
<b-button </b-tooltip>
<b-tooltip
:target="'vote-veto'+p.id"
>
{{ percent(p.tally.veto) }}% {{ $t('governanceProposal.proposal_votes_nwv') }}
</b-tooltip>
<b-tooltip
:target="'vote-abstain'+p.id"
>
{{ percent(p.tally.abstain) }}% {{ $t('governanceProposal.proposal_votes_abstain') }}
</b-tooltip>
</div>
<b-card-footer class="pb-0">
<router-link
v-ripple.400="'rgba(113, 102, 240, 0.15)'" v-ripple.400="'rgba(113, 102, 240, 0.15)'"
:href="`./gov/${p.id}`" :to="`./gov/${p.id}`"
variant="outline-primary" variant="outline-primary"
> >
{{ $t('btn_detail') }} <b-button
v-ripple.400="'rgba(113, 102, 240, 0.15)'"
:href="`./gov/${p.id}`"
variant="outline-primary"
>
{{ $t('governanceProposal.btn_detail') }}
</b-button>
</router-link>
<b-button
v-if="p.status===1"
v-b-modal.operation-modal
variant="primary"
class="btn float-right mg-2"
@click="selectProposal('GovDeposit',p.id, p.title)"
>
{{ $t('governanceProposal.btn_deposit') }}
</b-button> </b-button>
</router-link> <b-button
<b-button v-if="p.status===2"
v-if="p.status===1" v-b-modal.operation-modal
v-b-modal.operation-modal variant="primary"
variant="primary" class="btn float-right mg-2"
class="btn float-right mg-2" @click="selectProposal('Vote',p.id, p.title)"
@click="selectProposal('GovDeposit',p.id, p.title)" >
> {{ $t('governanceProposal.btn_vote') }}
{{ $t('btn_deposit') }} </b-button>
</b-button> </b-card-footer>
<b-button </div></b-card>
v-if="p.status===2"
v-b-modal.operation-modal
variant="primary"
class="btn float-right mg-2"
@click="selectProposal('Vote',p.id, p.title)"
>
{{ $t('btn_vote') }}
</b-button>
</b-card-footer>
</b-card>
</template> </template>
<script> <script>
import { import {
BCard, BCardTitle, BCardFooter, BButton, BProgressBar, BProgress, BBadge, BTooltip, BRow, BCol, VBModal, BCard, BCardTitle, BCardFooter, BButton, BProgressBar, BProgress, BBadge, BTooltip, BRow, BCol, VBModal, VBTooltip,
} from 'bootstrap-vue' } from 'bootstrap-vue'
import Ripple from 'vue-ripple-directive' import Ripple from 'vue-ripple-directive'
import { percent, tokenFormatter } from '@/libs/utils' import { percent, tokenFormatter } from '@/libs/utils'
@ -180,6 +198,7 @@ export default {
}, },
directives: { directives: {
'b-modal': VBModal, 'b-modal': VBModal,
'b-tooltip': VBTooltip,
Ripple, Ripple,
}, },
props: { props: {
@ -187,8 +206,25 @@ export default {
type: Object, type: Object,
default: () => ({}), default: () => ({}),
}, },
totalPower: {
type: Number,
default: 0,
},
tallyParam: {
type: Object,
default: null,
},
}, },
methods: { methods: {
scaleWidth(p) {
if (this.tallyParam) {
if (p.status === 2) {
return Number(this.tallyParam.quorum) * Number(this.tallyParam.threshold) * (1 - p.tally.abstain) * 100
}
return Number(this.tallyParam.threshold) * (1 - p.tally.abstain) * 100
}
return 50
},
selectProposal(modal, pid, title) { selectProposal(modal, pid, title) {
this.$parent.operationModalType = modal this.$parent.operationModalType = modal
this.$parent.selectedProposalId = Number(pid) this.$parent.selectedProposalId = Number(pid)
@ -206,7 +242,7 @@ export default {
} }
</script> </script>
<style scoped> <style scoped>
section { section {
display: flex; display: flex;
/* flex-wrap: nowrap; */ /* flex-wrap: nowrap; */

View File

@ -98,6 +98,29 @@
<small @click="copy(hexAddress)">{{ hexAddress }}</small> <small @click="copy(hexAddress)">{{ hexAddress }}</small>
</b-media-body> </b-media-body>
</b-media> </b-media>
<b-media
class="mb-1"
no-body
>
<b-media-aside class="mr-1">
<b-avatar
rounded
variant="light-primary"
size="34"
>
<feather-icon
icon="HashIcon"
size="18"
/>
</b-avatar>
</b-media-aside>
<b-media-body class="text-truncate">
<h6 class="mb-0">
Signer Address
</h6>
<small @click="copy(valconsAddress)">{{ valconsAddress }}</small>
</b-media-body>
</b-media>
</b-card> </b-card>
</template> </template>
@ -138,6 +161,10 @@ export default {
type: String, type: String,
default: '-', default: '-',
}, },
valconsAddress: {
type: String,
default: '-',
},
}, },
methods: { methods: {
copy(v) { copy(v) {