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
runs-on: mainnet
steps:
- name: print
run: echo ${GITHUB_REF#refs/heads/}
- name: Environment
run: export NODE_OPTIONS="--max_old_space_size=4096"
- name: Git Checkout Latest
uses: actions/checkout@v3
- name: Install
run: yarn install
run: yarn install --ignore-engines
- name: Build
run: yarn run vue-cli-service build

2
.gitignore vendored
View File

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

View File

@ -15,22 +15,24 @@
</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?
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?
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?
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.
- 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.
- 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 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

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 }}
</b-breadcrumb-item>
<b-breadcrumb-item
v-for="item in $route.meta.breadcrumb"
v-for="item in breadcrumb"
:key="item.text"
:active="item.active"
:to="item.to"
@ -75,6 +75,14 @@ export default {
chainname() {
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>

View File

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

View File

@ -22,3 +22,28 @@
.progress {
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",
"api": [
"https://api.agoric.sgtstake.com",
"https://agoric-api.polkachu.com",
"https://api-agoric.nodes.guru",
"https://agoric.stakesystems.io",

View File

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

View File

@ -6,7 +6,7 @@
"snapshot_provider": "29edc55748bc341224f711a05cb0a9f6d73b4da3@bitcanna.rpc.ping.pub:26656",
"sdk_version": "0.45.10",
"coin_type": "118",
"min_tx_fee": "8000",
"min_tx_fee": "420",
"assets": [{
"base": "ubcna",
"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",
"api": "https://lcd.injective.network",
"rpc": ["https://injective-rpc.api.chainlayer.network:443", "https://injective-rpc.api.chainlayer.network:443"],
"api": ["https://lcd.injective.network", "https://injective-api.polkachu.com"],
"rpc": ["https://tm.injective.network", "https://injective-rpc.polkachu.com"],
"snapshot_provider": "",
"sdk_version": "v0.45.5",
"coin_type": "60",
@ -9,6 +9,12 @@
"addr_prefix": "inj",
"excludes": "",
"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": [{
"base": "inj",
"symbol": "INJ",

View File

@ -1,18 +1,28 @@
{
"chain_name": "jackal",
"coingecko": "",
"api": ["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"],
"coingecko": "jackal-protocol",
"api": [
"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": "",
"coin_type": "118",
"sdk_version": "0.45.9",
"sdk_version": "0.45.11",
"addr_prefix": "jkl",
"logo": "/logos/jackal.png",
"assets": [{
"base": "ujkl",
"symbol": "JKL",
"exponent": "6",
"coingecko_id": "jackal",
"logo": "/logos/jackal.png"
}]
"assets": [
{
"base": "ujkl",
"symbol": "JKL",
"exponent": "6",
"coingecko_id": "jackal",
"logo": "/logos/jackal.png"
}
]
}

View File

@ -1,8 +1,8 @@
{
"chain_name": "lumenx",
"coingecko": "",
"api": "https://api.helios-1.lumenex.io",
"rpc": ["https://rpc.helios-1.lumenex.io:443","http://node4.lumenex.io:26657"],
"api": ["https://api.lumenx.chaintools.tech:443","https://api-lumenx.cryptonet.pl:443"],
"rpc": ["https://rpc.lumenx.chaintools.tech:443","https://rpc-lumenx.cryptonet.pl:443"],
"snapshot_provider": "",
"sdk_version": "0.45.5",
"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",
"api": ["https://api.mainnet.rebus.money:1317", "https://rebus.api.kjnodes.com"],
"rpc": ["https://api.mainnet.rebus.money:26657", "https://rebus.rpc.kjnodes.com:443"],
"api": ["https://api.mainnet.rebus.money:1317","https://api.rebus.nodestake.top"],
"rpc": ["https://api.mainnet.rebus.money:26657","https://rpc.rebus.nodestake.top"],
"snapshot_provider": "",
"sdk_version": "0.45.6",
"coin_type": "118",

View File

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

View File

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

View File

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

View File

@ -1,9 +1,9 @@
{
"chain_name": "vidulum",
"coingecko": "vidulum",
"api": ["https://mainnet-lcd.vidulum.app", "https://api-vidulum-ia.cosmosia.notional.ventures", "https://rest.rpc.erialos.me"],
"rpc": ["https://trpc.rpc.erialos.me:443","https://rpc-vidulum-ia.cosmosia.notional.ventures:443", "https://mainnet-rpc.vidulum.app:443"],
"snapshot_provider": "c32903505e9ab811ac46306d2913c98ccf4883ce@rpc.erialos.me:26656",
"api": ["https://mainnet-lcd.vidulum.app", "https://api-vidulum-ia.cosmosia.notional.ventures"],
"rpc": ["https://mainnet-rpc.vidulum.app:443", "https://rpc-vidulum-ia.cosmosia.notional.ventures:443"],
"snapshot_provider": "",
"sdk_version": "0.45.9",
"coin_type": "370",
"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",
"api":"https://vega.api.ping.pub",
"sdk_version": "0.42.9",
"chain_name": "cosmos",
"api": ["https://vega.api.ping.pub", "https://rest.seed-01.theta-testnet.polypore.xyz", "https://rest.seed-02.theta-testnet.polypore.xyz"],
"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",
"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",
"addr_prefix": "evmos",
"logo": "/logos/evmos.jpeg",
"keplr_features": ["ibc-transfer", "ibc-go", "eth-address-gen", "eth-key-sign"],
"assets": [{
"base": "atevmos",
"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",
"coingecko": "jackal",
"api": "https://testnet-api.jackalprotocol.com",
"rpc": "https://testnet-rpc.jackalprotocol.com",
"coingecko": "jackal_protocol",
"api": [
"https://testnet-api.jackalprotocol.com"
],
"rpc": [
"https://testnet-rpc.jackalprotocol.com"
],
"coin_type": "118",
"sdk_version": "0.45.9",
"addr_prefix": "jkl",
"sdk_version": "0.45.11",
"addr_prefix": "jkl",
"logo": "/logos/jackal.png",
"assets": [{
"base": "ujkl",
"symbol": "JKL",
"exponent": "6",
"coingecko_id": "jackal",
"logo": "/logos/jackal.png"
}]
}
"assets": [
{
"base": "ujkl",
"symbol": "JKL",
"exponent": "6",
"coingecko_id": "jackal-protocol",
"logo": "/logos/jackal.png"
}
]
}

View File

@ -1,8 +1,8 @@
{
"chain_name": "osmosis",
"coingecko": "osmosis",
"api": ["https://testnet-rest.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"],
"api": ["https://lcd-test.osmosis.zone", "https://lcd.osmo-test.ccvalidators.com", "https://osmosistest-lcd.quickapi.com"],
"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": "",
"sdk_version": "0.44.5",
"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",
"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"],
"rpc": ["https://rpc.pulsar.scrttestnet.com", "https://rpc.testnet.secretsaturn.net", "https://testnet-rpc.roninventures.io", "https://pulsar-2.api.trivium.network:26657"],
"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://pulsar-2.api.trivium.network:26657"],
"snapshot_provider": "",
"sdk_version": "0.45.4",
"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": {
},
"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)",
"pools": "Pools(WIP)",
"chains": {
"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",
"proposal_type": "Proposal Type",
"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:",
"gravity": "Gravity(WIP)",
"pools": "Pools(WIP)"
},
"btn_vote": "Vote",
"btn_deposit": "Deposit",
"btn_detail": "Detail",
"btn_back_list": "Back To List"
"dashboard": {
"dashboard": "Dashboard",
"staking": "Staking",
"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" /> -->
<!-- Right Col -->
<b-navbar-nav class="nav align-items-center ml-auto">
<dark-Toggler class="d-none d-lg-block" />
<dark-Toggler />
<search-bar />
<locale />
<locale class="d-none" />
<b-dropdown
class="ml-1"
variant="link"

View File

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

View File

@ -16,6 +16,7 @@ export default class Proposal {
this.voting_start_time = '0000-00-00'
this.total_deposit = '-'
this.contents = null
this.metadata = {}
}
init(element, total) {
@ -29,7 +30,7 @@ export default class Proposal {
this.voting_start_time = element.voting_start_time
// eslint-disable-next-line prefer-destructuring
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) {
this.title = this.contents.title
this.description = this.contents.description
@ -38,6 +39,7 @@ export default class Proposal {
this.type = element.content['@type']
}
}
this.metadata = element.metadata
return this
}
@ -51,6 +53,12 @@ export default class Proposal {
versionFixed(ver) {
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) {
this.title = this.element.metadata.title || 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.raw_log = element.tx_response.raw_log
}
self.element = element
return self
}
}

View File

@ -128,8 +128,8 @@ export default class ChainFetch {
// return ret
// })
return Promise.all([
this.get(`/cosmos/distribution/v1beta1/validators/${address}/commission`),
this.get(`/cosmos/distribution/v1beta1/validators/${address}/outstanding_rewards`),
this.get(`/cosmos/distribution/v1beta1/validators/${address}/commission`, null, true),
this.get(`/cosmos/distribution/v1beta1/validators/${address}/outstanding_rewards`, null, true),
]).then(data => {
const ret = ValidatorDistribution.create({
operator_address: address,
@ -145,6 +145,9 @@ export default class ChainFetch {
}
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) {
return this.get(`/supply/total/${denom}`).then(data => ({ amount: commonProcess(data), denom }))
}
@ -159,7 +162,7 @@ export default class ChainFetch {
}
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() {
@ -176,14 +179,14 @@ export default class ChainFetch {
}
async getStakingParameters() {
return this.get('/cosmos/staking/v1beta1/params').then(data => {
return this.get('/cosmos/staking/v1beta1/params', null, true).then(data => {
this.getSelectedConfig()
return StakingParameters.create(commonProcess(data.params), this.config.chain_name)
})
}
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))
try {
localStorage.setItem(`validators-${this.config.chain_name}`, JSON.stringify(vals))
@ -203,7 +206,7 @@ export default class ChainFetch {
}
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 vals = result.validators ? result.validators : result
return vals.map(i => new Validator().init(i))
@ -211,7 +214,7 @@ export default class ChainFetch {
}
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 vals = result.validators ? result.validators : result
return vals.map(i => new Validator().init(i))
@ -223,7 +226,7 @@ export default class ChainFetch {
}
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() {
@ -277,27 +280,39 @@ export default class ChainFetch {
}
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() {
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() {
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() {
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) {
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) {
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)
p.versionFixed(this.config.sdk_version)
return p
@ -305,20 +320,22 @@ export default class ChainFetch {
}
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(`/gov/proposals/${pid}/proposer`).then(data => new Proposer().init(commonProcess(data)))
}
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 => {
const result = commonProcess(data)
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)
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') {
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) {
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 => {
let proposals = commonProcess(data)
if (Array.isArray(proposals.proposals)) {
@ -361,9 +381,10 @@ export default class ChainFetch {
}
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'
? `/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 => {
if (data.code === 3) {
throw new Error('not found')
@ -379,9 +400,10 @@ export default class ChainFetch {
async getGovernanceList(next = '', chain = null) {
const key = next || ''
const ver = compareVersions(this.config.sdk_version, '0.46.5') < 0 ? 'v1beta1' : 'v1'
const url = this.config.chain_name === 'shentu'
? `/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 => {
let proposals = commonProcess(data)
if (Array.isArray(proposals.proposals)) {
@ -415,22 +437,22 @@ export default class ChainFetch {
async getStakingReward(address, config = null) {
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) {
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) {
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) {
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
if (!xh.delegation) {
xh.delegation = {
@ -441,21 +463,21 @@ export default class ChainFetch {
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) {
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) {
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) {
@ -463,7 +485,7 @@ export default class ChainFetch {
}
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) {
@ -589,15 +611,17 @@ export default class ChainFetch {
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) {
this.getSelectedConfig()
}
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
// finalurl = finalurl.replaceAll('v1beta1', this.getEndpointVersion())
const ret = await fetch(finalurl).then(response => response.json())
return ret
return fetch(finalurl).then(response => response.json())
}
getApiIndex(config = null) {

View File

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

View File

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

View File

@ -273,8 +273,9 @@ export default {
return i
}
const txt = text.substring(text.indexOf(':') + 1, text.indexOf(' '))
const sig = text.split(' ')
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"
>
<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>
</b-alert>
@ -90,40 +90,162 @@
</b-row>
<b-card no-body>
<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-body>
<b-media
<b-row
v-for="prop in proprosals2"
:key="prop.id"
no-body
class="mb-1"
>
<b-media-aside
v-b-modal.operation-modal
@click="selectProposal('Vote',prop.id, prop.title)"
<b-col
md="6"
sm="12"
>
<b-avatar
rounded
size="42"
:variant="myVotes[prop.id] ? 'light-primary': 'primary'"
<b-media
no-body
class="mb-1"
>
{{ myVotes[prop.id] || 'Vote' }}
</b-avatar>
</b-media-aside>
<b-link :to="`./${chain}/gov/${prop.id}`">
<b-media-body class="d-flex flex-column justify-content-center">
<h6 class="transaction-title">
{{ prop.id }}. {{ prop.title }}
</h6>
<small>{{ formatType(prop.contents['@type']) }} {{ formatEnding(prop.voting_end_time) }}</small>
</b-media-body>
</b-link>
</b-media>
<b-media-aside
@click="showDetail(prop.id)"
>
<b-avatar
rounded
size="42"
variant="light-primary"
>
{{ prop.id }}
</b-avatar>
</b-media-aside>
<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">
No active proposal!
{{ $t('dashboard.no_active_prop') }}
<b-link :to="`./${chain}/gov`">
Browse all
{{ $t('dashboard.browse') }}
</b-link>
</div>
</b-card-body>
@ -133,20 +255,20 @@
bg-variant="transparent"
class="shadow-none"
>
<b-card-title class="d-flex justify-content-between">
<span>{{ walletName }} Assets </span>
<b-card-title class="d-flex justify-content-between text-capitalize">
<span>{{ walletName }} {{ $t('dashboard.assets') }} </span>
<small>
<b-link
v-if="address"
:to="`./${chain}/account/${address}`"
>
More
{{ $t('dashboard.more') }}
</b-link>
<b-link
v-else
:to="`/wallet/accounts`"
>
Not connected?
{{ $t('dashboard.not_conn') }}
</b-link>
</small>
</b-card-title>
@ -211,6 +333,7 @@
<!-- size -->
<b-button-group
size="sm"
class="d-none"
>
<b-button
v-b-modal.operation-modal
@ -240,18 +363,41 @@
<feather-icon icon="LogOutIcon" />
</b-button>
</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>
</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-col>
</b-row>
@ -260,7 +406,7 @@
<b-col>
<b-card>
<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-body class="pl-0 pr-0">
<b-row
@ -307,7 +453,7 @@
@click="selectSend()"
>
<feather-icon icon="SendIcon" />
Send
{{ $t('dashboard.send') }}
</b-button>
</b-col>
<b-col cols="6">
@ -319,7 +465,7 @@
<feather-icon
icon="PlusCircleIcon"
/>
Receive
{{ $t('dashboard.receive') }}
</b-button>
</b-col>
</b-row>
@ -327,7 +473,7 @@
<router-link to="/wallet/import">
<b-card class="addzone text-center">
<feather-icon icon="PlusIcon" />
Connect Wallet
{{ $t('dashboard.connect_wal') }}
</b-card>
</router-link>
<operation-modal
@ -337,21 +483,24 @@
:proposal-id="selectedProposalId"
:proposal-title="selectedTitle"
/>
<div id="txevent" />
</div>
</template>
<script>
import {
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'
import {
formatNumber, formatTokenAmount, isToken, percent, timeIn, toDay, toDuration, tokenFormatter, getLocalAccounts,
getStakingValidatorOperator,
getStakingValidatorOperator, formatToken,
} from '@/libs/utils'
import OperationModal from '@/views/components/OperationModal/index.vue'
import Ripple from 'vue-ripple-directive'
import dayjs from 'dayjs'
import VueMarkdown from 'vue-markdown'
import ParametersModuleComponent from './components/parameters/ParametersModuleComponent.vue'
import DashboardCardHorizontal from './components/dashboard/DashboardCardHorizontal.vue'
import DashboardCardVertical from './components/dashboard/DashboardCardVertical.vue'
@ -364,6 +513,8 @@ export default {
BButtonGroup,
BTooltip,
BButton,
BDropdown,
BDropdownItem,
BRow,
BCol,
BAlert,
@ -378,6 +529,10 @@ export default {
BCardBody,
BLink,
BCardFooter,
BProgress,
BProgressBar,
VueMarkdown,
BBadge,
OperationModal,
ParametersModuleComponent,
@ -393,6 +548,7 @@ export default {
},
data() {
return {
detailId: 0,
fields: ['validator', 'delegation', 'rewards', 'action'],
delegations: [],
rewards: [],
@ -414,6 +570,8 @@ export default {
selectedProposalId: 0,
selectedTitle: '',
operationModalType: '',
tallyParam: null,
totalPower: 0,
voteColors: {
YES: 'success',
NO: 'warning',
@ -450,10 +608,12 @@ export default {
stakingList() {
return this.delegations.map(x => {
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 {
valAddress: 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) : '',
action: '',
}
@ -461,9 +621,29 @@ export default {
},
},
created() {
this.$http.getGovernanceListByStatus(2).then(res => {
this.proposals = res.proposals
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.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.height = res.block.header.height
if (timeIn(res.block.header.time, 3, 'm')) {
@ -475,19 +655,14 @@ export default {
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.communityPool = this.formatToken(res.pool)
})
this.$http.getGovernanceParameterTallying().then(res => {
this.tallyParam = res
})
const conf = this.$http.getSelectedConfig()
if (conf.excludes && conf.excludes.indexOf('mint') > -1) {
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: {
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) {
this.operationModalType = modal
this.selectedProposalId = Number(pid)
@ -609,6 +816,13 @@ export default {
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'),
convert(v) {
if (typeof v === 'object') {
@ -633,6 +847,13 @@ export default {
}
return v
},
showDetail(id) {
if (this.detailId !== id) {
this.detailId = id
} else {
this.detailId = 0
}
},
},
}
</script>

View File

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

View File

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

View File

@ -5,7 +5,7 @@
:show="syncing"
>
<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>
</b-alert>
<b-row>
@ -38,11 +38,15 @@
<parameters-module-component :data="slashing" />
</b-col>
</b-row>
<b-card title="Application Version">
<object-field-component :tablefield="appVersion" />
<b-card>
<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 title="Node Information">
<object-field-component :tablefield="nodeVersion" />
<b-card>
<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>
</div>
</template>

View File

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

View File

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

View File

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

View File

@ -277,25 +277,20 @@ export default {
})
return Object.values(valCounter).sort((a, b) => b.counter - a.counter)
},
h() {
return this.height
},
},
created() {
const cached = JSON.parse(getCachedValidators(this.$route.params.chain))
if (cached) {
this.validators = cached
}
this.fetchMissingInfo()
this.$http.getValidatorList().then(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()
},
beforeDestroy() {
@ -304,6 +299,18 @@ export default {
clearInterval(this.timer)
},
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() {
localStorage.setItem('pinned', this.pinned)
},
@ -319,13 +326,15 @@ export default {
const blocks = []
// update height
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 })
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)
}))
}
} else {
resolve()
}
}))
}
const sigs = this.initColor()
@ -386,7 +395,10 @@ export default {
res.block.last_commit.signatures.forEach(x => {
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)
if (typeof block === 'undefined') { // mei
// this.$set(block, 0, typeof sigs !== 'undefined')

View File

@ -2,21 +2,21 @@
<div class="px-0">
<b-card>
<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-alert
variant="danger"
:show="syncing"
>
<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>
</b-alert>
<b-row>
<span
v-if="uptime.length===0"
class="text-danger"
> Your node is out of active validator set</span>
> {{$t(uptimeMyChainBlocks.not_active)}}</span>
<b-col
v-for="(x,index) in uptime"
:key="index"

View File

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

View File

@ -23,7 +23,7 @@
style="color: #fff"
class="mb-0"
>
Address: <feather-icon
{{ $t('walletAccountDetail.address') }} <feather-icon
icon="CopyIcon"
size="18"
@click="copy()"
@ -38,7 +38,7 @@
class="d-flex flex-row"
>
<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>
<b-button
v-b-modal.operation-modal
@ -50,7 +50,7 @@
<feather-icon
icon="SendIcon"
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
v-b-modal.operation-modal
@ -61,7 +61,7 @@
icon="SendIcon"
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>
</div>
</b-card-header>
@ -117,7 +117,7 @@
</div>
<!--/ tokens -->
<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>
</b-col>
</b-row>
@ -127,7 +127,7 @@
v-if="unbonding && unbonding.length > 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-body class="pl-0 pr-0">
<b-row
@ -135,7 +135,7 @@
:key="item.validator_address"
>
<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 cols="12">
<b-table
@ -164,7 +164,7 @@
v-if="delegations"
>
<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>
<b-button
v-b-modal.operation-modal
@ -176,7 +176,7 @@
<feather-icon
icon="LogInIcon"
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
v-if="delegations"
@ -188,7 +188,7 @@
<feather-icon
icon="ShareIcon"
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>
</div>
</b-card-header>
@ -197,6 +197,15 @@
:items="deleTable"
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">
<!-- size -->
<b-button-group
@ -275,25 +284,25 @@
<b-tbody v-if="account.type === 'cosmos-sdk/BaseAccount'">
<b-tr>
<b-td>
Account Type
{{ $t('walletAccountDetail.acct_type') }}
</b-td><b-td> {{ account.type }} </b-td>
</b-tr>
<b-tr>
<b-td class="max-width:100px;">
Account Number
{{ $t('walletAccountDetail.acct_num') }}
</b-td><b-td> {{ account.value.account_number }} </b-td>
</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-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-tbody>
<b-tbody v-else-if="account.type === 'cosmos-sdk/PeriodicVestingAccount' && account.value.base_vesting_account">
<b-tr>
<b-td>
Account Type
{{ $t('walletAccountDetail.acct_type') }}
</b-td>
<b-td>
{{ account.type }}
@ -301,32 +310,32 @@
</b-tr>
<b-tr>
<b-td>
Account Number
{{ $t('walletAccountDetail.acct_num') }}
</b-td><b-td> {{ account.value.base_vesting_account.base_account.account_number }} </b-td>
</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-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-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-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-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-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-td> Vesting Periods </b-td>
<b-td> {{ $t('walletAccountDetail.vest_period') }} </b-td>
<b-td>
<b-table-simple>
<th>Length</th><th>Amount</th>
<th>{{ $t('walletAccountDetail.length') }}</th><th>{{ $t('walletAccountDetail.amount') }}</th>
<b-tr
v-for="p, index in account.value.vesting_periods"
:key="index"
@ -340,31 +349,31 @@
<b-tbody v-else-if="account.type === 'cosmos-sdk/DelayedVestingAccount' && account.value.base_vesting_account">
<b-tr>
<b-td>
Account Type
{{ $t('walletAccountDetail.acct_type') }}
</b-td><b-td> {{ account.type }} </b-td>
</b-tr>
<b-tr>
<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-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-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-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-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-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-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-tbody>
<object-field-component
@ -394,10 +403,10 @@
<div class="misc-inner p-2 p-sm-3">
<div class="w-100 text-center">
<h2 class="mb-1">
Account not found 🕵🏻
{{ $t('walletAccountDetail.acct_not_found') }} 🕵🏻
</h2>
<p class="mb-2">
Oops! 😖 {{ error }}.
{{ $t('walletAccountDetail.opps') }} 😖 {{ error }}.
</p>
<b-button
@ -405,7 +414,7 @@
class="mb-2 btn-sm-block"
:to="{path:'../'}"
>
Back to home
{{ $t('walletAccountDetail.back_home') }}
</b-button>
</div>
</div>
@ -621,12 +630,17 @@ export default {
},
deleTable() {
const re = []
const conf = this.$http.getSelectedConfig()
const decimal = conf.assets[0].exponent || '6'
if (this.reward.rewards && this.delegations && this.delegations.length > 0) {
this.delegations.forEach(e => {
const reward = this.reward.rewards.find(r => r.validator_address === e.delegation.validator_address)
re.push({
validator: getStakingValidatorOperator(this.$http.config.chain_name, e.delegation.validator_address, 8),
token: formatToken(e.balance, {}, 2),
validator: {
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),
action: e.delegation.validator_address,
})

View File

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

View File

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

View File

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

View File

@ -63,7 +63,7 @@
/>
</b-progress>
<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="error">FAILED</span>
</div>

View File

@ -235,7 +235,9 @@ export default {
return formatTokenDenom(this.token)
},
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
},
tokenOptions() {
const conf = this.$http.getSelectedConfig()
const decimal = conf.assets[0].exponent || '6'
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() {
return [{

View File

@ -5,29 +5,53 @@
<h4 class="mb-25 font-weight-bolder">
{{ statistic || '-' }}
</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>
<b-avatar
v-b-tooltip.hover
:variant="`light-${color}`"
size="45"
>
<feather-icon
size="21"
:icon="icon"
/>
</b-avatar>
:text="statisticTitle.substring(0,1)"
:title="statisticTitle"
/>
</b-card-body>
</b-card>
</template>
<script>
import { BCard, BCardBody, BAvatar } from 'bootstrap-vue'
import {
BCard, BCardBody, BAvatar, VBTooltip,
} from 'bootstrap-vue'
import { getUserCurrency, getUserCurrencySign } from '@/libs/utils'
export default {
components: {
BCard,
BCardBody,
BAvatar,
VBTooltip,
},
directives: {
'b-tooltip': VBTooltip,
},
props: {
icon: {
@ -47,5 +71,24 @@ export default {
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>

View File

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

View File

@ -98,6 +98,29 @@
<small @click="copy(hexAddress)">{{ hexAddress }}</small>
</b-media-body>
</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>
</template>
@ -138,6 +161,10 @@ export default {
type: String,
default: '-',
},
valconsAddress: {
type: String,
default: '-',
},
},
methods: {
copy(v) {