Merge branch 'ping-pub:master' into master
This commit is contained in:
commit
e81a458fb9
@ -41,7 +41,7 @@
|
|||||||
"md-editor-v3": "^2.8.1",
|
"md-editor-v3": "^2.8.1",
|
||||||
"numeral": "^2.0.6",
|
"numeral": "^2.0.6",
|
||||||
"osmojs": "^14.0.0-rc.0",
|
"osmojs": "^14.0.0-rc.0",
|
||||||
"ping-widget": "^0.0.21",
|
"ping-widget": "^0.0.24",
|
||||||
"pinia": "^2.0.28",
|
"pinia": "^2.0.28",
|
||||||
"postcss": "^8.4.23",
|
"postcss": "^8.4.23",
|
||||||
"prismjs": "^1.29.0",
|
"prismjs": "^1.29.0",
|
||||||
|
10
public/logos/keplr-logo.svg
Normal file
10
public/logos/keplr-logo.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 148 KiB |
BIN
public/logos/ledger.png
Normal file
BIN
public/logos/ledger.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 41 KiB |
@ -32,7 +32,7 @@ const addFavor = (e: Event) => {
|
|||||||
<div class="w-8 h-8 rounded-full overflow-hidden">
|
<div class="w-8 h-8 rounded-full overflow-hidden">
|
||||||
<img :src="conf.logo" />
|
<img :src="conf.logo" />
|
||||||
</div>
|
</div>
|
||||||
<div class="font-semibold ml-4 text-base flex-1 truncate">
|
<div class="font-semibold ml-4 text-base flex-1 truncate capitalize">
|
||||||
{{ conf?.prettyName || props.name }}
|
{{ conf?.prettyName || props.name }}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
@ -110,24 +110,16 @@ const proposalInfo = ref();
|
|||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td v-if="statusMap?.[item?.status] === 'VOTING'" class="w-40">
|
<td v-if="statusMap?.[item?.status] === 'VOTING'" class="w-40">
|
||||||
<div class="" v-show="item?.voterStatus === 'No With Veto'">
|
<div class="">
|
||||||
<label
|
<label
|
||||||
for="vote"
|
for="vote"
|
||||||
class="btn btn-xs btn-primary rounded-sm"
|
class="btn btn-xs btn-primary rounded-sm"
|
||||||
@click="dialog.open('vote', { proposal_id: item?.proposal_id })"
|
@click="dialog.open('vote', { proposal_id: item?.proposal_id })"
|
||||||
>Vote</label
|
|
||||||
>
|
>
|
||||||
<div
|
<span v-if="item?.voterStatus">{{ item?.voterStatus.replace("VOTE_OPTION_", "")}}</span>
|
||||||
class="text-xs truncate relative py-1 px-3 rounded-full w-fit"
|
<span v-else>Vote</span>
|
||||||
:class="`text-${voterStatusMap?.[item?.voterStatus]}`"
|
</label
|
||||||
v-show="item?.voterStatus !== 'No With Veto'"
|
|
||||||
>
|
>
|
||||||
<span
|
|
||||||
class="inset-x-0 inset-y-0 opacity-10 absolute"
|
|
||||||
:class="`bg-${voterStatusMap?.[item?.voterStatus]}`"
|
|
||||||
></span>
|
|
||||||
{{ item?.voterStatus }}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -44,7 +44,7 @@ function changeEndpoint(item: Endpoint) {
|
|||||||
</label>
|
</label>
|
||||||
<div
|
<div
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
class="dropdown-content w-80 menu shadow bg-base-200 rounded-box max-h-[300px] overflow-auto"
|
class="dropdown-content w-80 menu shadow bg-base-200 rounded-box overflow-auto"
|
||||||
>
|
>
|
||||||
<!-- rest -->
|
<!-- rest -->
|
||||||
<div
|
<div
|
||||||
|
@ -128,7 +128,7 @@ const showDiscord = window.location.host.search('ping.pub') > -1;
|
|||||||
class="w-6 h-6 rounded-full mr-3 ml-4"
|
class="w-6 h-6 rounded-full mr-3 ml-4"
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
class="text-base text-gray-500 dark:text-gray-300"
|
class="text-base capitalize text-gray-500 dark:text-gray-300"
|
||||||
:class="{
|
:class="{
|
||||||
'text-white':
|
'text-white':
|
||||||
$route.path === el?.to?.path &&
|
$route.path === el?.to?.path &&
|
||||||
|
@ -84,7 +84,7 @@ const tipMsg = computed(() => {
|
|||||||
v-if="walletStore.currentAddress"
|
v-if="walletStore.currentAddress"
|
||||||
class="block py-2 px-2 hover:bg-gray-100 dark:hover:bg-[#353f5a] rounded cursor-pointer"
|
class="block py-2 px-2 hover:bg-gray-100 dark:hover:bg-[#353f5a] rounded cursor-pointer"
|
||||||
@click="walletStore.disconnect()"
|
@click="walletStore.disconnect()"
|
||||||
>Disconnected</a
|
>Disconnect</a
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -66,7 +66,7 @@ export const DEFAULT: RequestRegistry = {
|
|||||||
adapter,
|
adapter,
|
||||||
},
|
},
|
||||||
gov_proposals_votes: {
|
gov_proposals_votes: {
|
||||||
url: '/cosmos/gov/v1beta1/proposals/{proposal_id}/votes?pagination.key={next_key}',
|
url: '/cosmos/gov/v1beta1/proposals/{proposal_id}/votes',
|
||||||
adapter,
|
adapter,
|
||||||
},
|
},
|
||||||
gov_proposals_votes_voter: {
|
gov_proposals_votes_voter: {
|
||||||
|
@ -116,11 +116,11 @@ export class CosmosRestClient extends BaseRestClient<RequestRegistry> {
|
|||||||
async getGovProposalTally(proposal_id: string) {
|
async getGovProposalTally(proposal_id: string) {
|
||||||
return this.request(this.registry.gov_proposals_tally, { proposal_id });
|
return this.request(this.registry.gov_proposals_tally, { proposal_id });
|
||||||
}
|
}
|
||||||
async getGovProposalVotes(proposal_id: string, next_key?: string) {
|
async getGovProposalVotes(proposal_id: string, page?: PageRequest) {
|
||||||
return this.request(this.registry.gov_proposals_votes, {
|
if(!page) page = new PageRequest()
|
||||||
proposal_id,
|
page.reverse = true
|
||||||
next_key,
|
const query =`?proposal_status={status}&${page.toQueryString()}`;
|
||||||
});
|
return this.request(this.registry.gov_proposals_votes, { proposal_id }, query);
|
||||||
}
|
}
|
||||||
async getGovProposalVotesVoter(proposal_id: string, voter: string) {
|
async getGovProposalVotesVoter(proposal_id: string, voter: string) {
|
||||||
return this.request(this.registry.gov_proposals_votes_voter, {
|
return this.request(this.registry.gov_proposals_votes_voter, {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { computed } from '@vue/reactivity';
|
||||||
import ObjectElement from '@/components/dynamic/ObjectElement.vue';
|
import ObjectElement from '@/components/dynamic/ObjectElement.vue';
|
||||||
import {
|
import {
|
||||||
useBaseStore,
|
useBaseStore,
|
||||||
@ -7,21 +8,24 @@ import {
|
|||||||
useStakingStore,
|
useStakingStore,
|
||||||
useTxDialog,
|
useTxDialog,
|
||||||
} from '@/stores';
|
} from '@/stores';
|
||||||
import type {
|
import {
|
||||||
GovProposal,
|
PageRequest,
|
||||||
GovVote,
|
type GovProposal,
|
||||||
PaginatedProposalDeposit,
|
type GovVote,
|
||||||
Pagination,
|
type PaginatedProposalDeposit,
|
||||||
|
type Pagination,
|
||||||
} from '@/types';
|
} from '@/types';
|
||||||
import { ref, reactive } from 'vue';
|
import { ref, reactive } from 'vue';
|
||||||
import Countdown from '@/components/Countdown.vue';
|
import Countdown from '@/components/Countdown.vue';
|
||||||
import { computed } from '@vue/reactivity';
|
import PaginationBar from '@/components/PaginationBar.vue'
|
||||||
|
import { fromBech32, toHex } from '@cosmjs/encoding';
|
||||||
|
|
||||||
const props = defineProps(['proposal_id', 'chain']);
|
const props = defineProps(['proposal_id', 'chain']);
|
||||||
const proposal = ref({} as GovProposal);
|
const proposal = ref({} as GovProposal);
|
||||||
const format = useFormatter();
|
const format = useFormatter();
|
||||||
const store = useGovStore();
|
const store = useGovStore();
|
||||||
const dialog = useTxDialog();
|
const dialog = useTxDialog();
|
||||||
|
const stakingStore = useStakingStore();
|
||||||
|
|
||||||
store.fetchProposal(props.proposal_id).then((res) => {
|
store.fetchProposal(props.proposal_id).then((res) => {
|
||||||
const proposalDetail = reactive(res.proposal);
|
const proposalDetail = reactive(res.proposal);
|
||||||
@ -53,27 +57,14 @@ const deposit = ref({} as PaginatedProposalDeposit);
|
|||||||
store.fetchProposalDeposits(props.proposal_id).then((x) => (deposit.value = x));
|
store.fetchProposalDeposits(props.proposal_id).then((x) => (deposit.value = x));
|
||||||
|
|
||||||
const votes = ref({} as GovVote[]);
|
const votes = ref({} as GovVote[]);
|
||||||
const votePage = ref({} as Pagination);
|
const pageRequest = ref(new PageRequest())
|
||||||
const loading = ref(false);
|
const pageResponse = ref({} as Pagination)
|
||||||
|
|
||||||
store.fetchProposalVotes(props.proposal_id).then((x) => {
|
store.fetchProposalVotes(props.proposal_id).then((x) => {
|
||||||
votes.value = x.votes;
|
votes.value = x.votes;
|
||||||
votePage.value = x.pagination;
|
pageResponse.value = x.pagination;
|
||||||
});
|
});
|
||||||
|
|
||||||
function loadMore() {
|
|
||||||
if (votePage.value.next_key) {
|
|
||||||
loading.value = true;
|
|
||||||
store
|
|
||||||
.fetchProposalVotes(props.proposal_id, votePage.value.next_key)
|
|
||||||
.then((x) => {
|
|
||||||
votes.value = votes.value.concat(x.votes);
|
|
||||||
votePage.value = x.pagination;
|
|
||||||
loading.value = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function shortTime(v: string) {
|
function shortTime(v: string) {
|
||||||
if (v) {
|
if (v) {
|
||||||
return format.toDay(v, 'from');
|
return format.toDay(v, 'from');
|
||||||
@ -113,7 +104,7 @@ const total = computed(() => {
|
|||||||
|
|
||||||
const turnout = computed(() => {
|
const turnout = computed(() => {
|
||||||
if (total.value > 0) {
|
if (total.value > 0) {
|
||||||
const bonded = useStakingStore().pool?.bonded_tokens || '1';
|
const bonded = stakingStore.pool?.bonded_tokens || '1';
|
||||||
return format.percent(total.value / Number(bonded));
|
return format.percent(total.value / Number(bonded));
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -159,6 +150,23 @@ const processList = computed(() => {
|
|||||||
{ name: 'Abstain', value: abstain.value, class: 'bg-warning' },
|
{ name: 'Abstain', value: abstain.value, class: 'bg-warning' },
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function showValidatorName(voter: string) {
|
||||||
|
const {data} = fromBech32(voter)
|
||||||
|
const hex = toHex(data)
|
||||||
|
const v = stakingStore.validators.find( x => toHex(fromBech32(x.operator_address).data) === hex)
|
||||||
|
return v? v.description.moniker : voter
|
||||||
|
}
|
||||||
|
|
||||||
|
function pageload(p: number) {
|
||||||
|
pageRequest.value.setPage(p)
|
||||||
|
store
|
||||||
|
.fetchProposalVotes(props.proposal_id, pageRequest.value)
|
||||||
|
.then((x) => {
|
||||||
|
votes.value = x.votes;
|
||||||
|
pageResponse.value = x.pagination;
|
||||||
|
});
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -325,7 +333,7 @@ const processList = computed(() => {
|
|||||||
<table class="table w-full table-zebra">
|
<table class="table w-full table-zebra">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="(item, index) of votes" :key="index">
|
<tr v-for="(item, index) of votes" :key="index">
|
||||||
<td class="py-2 text-sm">{{ item.voter }}</td>
|
<td class="py-2 text-sm">{{ showValidatorName(item.voter) }}</td>
|
||||||
<td
|
<td
|
||||||
class="py-2 text-sm"
|
class="py-2 text-sm"
|
||||||
:class="{
|
:class="{
|
||||||
@ -333,20 +341,12 @@ const processList = computed(() => {
|
|||||||
'text-gray-400': item.option === 'VOTE_OPTION_ABSTAIN',
|
'text-gray-400': item.option === 'VOTE_OPTION_ABSTAIN',
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
{{ item.option }}
|
{{ String(item.option).replace("VOTE_OPTION_", "") }}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
<PaginationBar :limit="pageRequest.limit" :total="pageResponse.total" :callback="pageload"/>
|
||||||
<button
|
|
||||||
@click="loadMore()"
|
|
||||||
v-if="votePage.next_key"
|
|
||||||
:disabled="loading"
|
|
||||||
class="btn btn-outline btn-primary w-full mt-4"
|
|
||||||
>
|
|
||||||
Load more
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -267,9 +267,7 @@ const color = computed(() => {
|
|||||||
{{ format.formatToken(walletStore.balanceOfStakingToken) }}
|
{{ format.formatToken(walletStore.balanceOfStakingToken) }}
|
||||||
</div>
|
</div>
|
||||||
<div class="text-sm" :class="color">
|
<div class="text-sm" :class="color">
|
||||||
<span class="ml-1">
|
|
||||||
${{ format.tokenValue(walletStore.balanceOfStakingToken) }}
|
${{ format.tokenValue(walletStore.balanceOfStakingToken) }}
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="bg-gray-100 dark:bg-[#373f59] rounded-sm px-4 py-3">
|
<div class="bg-gray-100 dark:bg-[#373f59] rounded-sm px-4 py-3">
|
||||||
@ -355,7 +353,8 @@ const color = computed(() => {
|
|||||||
<div class="grid grid-cols-3 gap-4 px-4 pb-6 mt-4">
|
<div class="grid grid-cols-3 gap-4 px-4 pb-6 mt-4">
|
||||||
<label for="PingTokenConvert" class="btn btn-primary text-white">Swap</label>
|
<label for="PingTokenConvert" class="btn btn-primary text-white">Swap</label>
|
||||||
<label for="send" class="btn !bg-yes !border-yes text-white" @click="dialog.open('send', {})">Send</label>
|
<label for="send" class="btn !bg-yes !border-yes text-white" @click="dialog.open('send', {})">Send</label>
|
||||||
<RouterLink to="/wallet/receive" class="btn !bg-info !border-info text-white">Receive</RouterLink>
|
<label for="delegate" class="btn !bg-info !border-info text-white" @click="dialog.open('delegate', {})">Delegate</label>
|
||||||
|
<RouterLink to="/wallet/receive" class="btn !bg-info !border-info text-white hidden">Receive</RouterLink>
|
||||||
</div>
|
</div>
|
||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<ping-token-convert
|
<ping-token-convert
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, onMounted, computed, watchEffect } from 'vue';
|
import { ref, onMounted, computed, onUnmounted } from 'vue';
|
||||||
import { fromHex, toBase64 } from '@cosmjs/encoding';
|
import { fromHex, toBase64 } from '@cosmjs/encoding';
|
||||||
import {
|
import {
|
||||||
useFormatter,
|
useFormatter,
|
||||||
|
@ -265,7 +265,7 @@ export const useDashboard = defineStore('dashboard', {
|
|||||||
favorite: fav as string[],
|
favorite: fav as string[],
|
||||||
favoriteMap: favMap as Record<string, boolean>,
|
favoriteMap: favMap as Record<string, boolean>,
|
||||||
chains: {} as Record<string, ChainConfig>,
|
chains: {} as Record<string, ChainConfig>,
|
||||||
prices: {},
|
prices: {} as Record<string, any>,
|
||||||
coingecko: {} as Record<string, {coinId: string, exponent: number, symbol: string}>,
|
coingecko: {} as Record<string, {coinId: string, exponent: number, symbol: string}>,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -69,7 +69,7 @@ export const useFormatter = defineStore('formatter', {
|
|||||||
return trace;
|
return trace;
|
||||||
},
|
},
|
||||||
priceInfo(denom: string) {
|
priceInfo(denom: string) {
|
||||||
const id = this.dashboard.coingecko[denom]?.coinId;
|
const id = this.dashboard.coingecko[denom]?.coinId || "";
|
||||||
const prices = this.dashboard.prices[id];
|
const prices = this.dashboard.prices[id];
|
||||||
return prices;
|
return prices;
|
||||||
},
|
},
|
||||||
@ -96,7 +96,10 @@ export const useFormatter = defineStore('formatter', {
|
|||||||
return v!==0 ? numeral(v).format("+0,0.[00]"): ""
|
return v!==0 ? numeral(v).format("+0,0.[00]"): ""
|
||||||
},
|
},
|
||||||
tokenValue(token?: Coin) {
|
tokenValue(token?: Coin) {
|
||||||
return token ? numeral(this.formatTokenAmount(token)).format('0,0.[00]') : ""
|
if(token) {
|
||||||
|
return numeral(this.tokenValueNumber(token)).format("0,0.[00]")
|
||||||
|
}
|
||||||
|
return ""
|
||||||
},
|
},
|
||||||
tokenValueNumber(token?: Coin) {
|
tokenValueNumber(token?: Coin) {
|
||||||
if(!token) return 0
|
if(!token) return 0
|
||||||
@ -129,7 +132,7 @@ export const useFormatter = defineStore('formatter', {
|
|||||||
formatToken(
|
formatToken(
|
||||||
token?: { denom: string; amount: string },
|
token?: { denom: string; amount: string },
|
||||||
withDenom = true,
|
withDenom = true,
|
||||||
fmt = '0.0a',
|
fmt = '0,0.[0]',
|
||||||
mode = 'local'
|
mode = 'local'
|
||||||
): string {
|
): string {
|
||||||
if (token && token.amount && token?.denom) {
|
if (token && token.amount && token?.denom) {
|
||||||
|
@ -75,8 +75,8 @@ export const useGovStore = defineStore('govStore', {
|
|||||||
async fetchProposalDeposits(proposalId: string) {
|
async fetchProposalDeposits(proposalId: string) {
|
||||||
return this.blockchain.rpc.getGovProposalDeposits(proposalId);
|
return this.blockchain.rpc.getGovProposalDeposits(proposalId);
|
||||||
},
|
},
|
||||||
async fetchProposalVotes(proposalId: string, next_key?: string) {
|
async fetchProposalVotes(proposalId: string, page?: PageRequest) {
|
||||||
return this.blockchain.rpc.getGovProposalVotes(proposalId, next_key);
|
return this.blockchain.rpc.getGovProposalVotes(proposalId, page);
|
||||||
},
|
},
|
||||||
async fetchProposalVotesVoter(proposalId: string, voter: string) {
|
async fetchProposalVotesVoter(proposalId: string, voter: string) {
|
||||||
return this.blockchain.rpc.getGovProposalVotesVoter(proposalId, voter);
|
return this.blockchain.rpc.getGovProposalVotesVoter(proposalId, voter);
|
||||||
|
@ -42,8 +42,9 @@ export const useWalletStore = defineStore('walletStore', {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
stakingAmount() {
|
stakingAmount() {
|
||||||
|
const stakingStore = useStakingStore();
|
||||||
let amt = 0;
|
let amt = 0;
|
||||||
let denom = '';
|
let denom = stakingStore.params.bond_denom;
|
||||||
this.delegations.forEach((i) => {
|
this.delegations.forEach((i) => {
|
||||||
amt += Number(i.balance.amount);
|
amt += Number(i.balance.amount);
|
||||||
denom = i.balance.denom;
|
denom = i.balance.denom;
|
||||||
|
@ -6955,10 +6955,10 @@ pify@^3.0.0:
|
|||||||
resolved "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz"
|
resolved "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz"
|
||||||
integrity sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==
|
integrity sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==
|
||||||
|
|
||||||
ping-widget@^0.0.21:
|
ping-widget@^0.0.24:
|
||||||
version "0.0.21"
|
version "0.0.24"
|
||||||
resolved "https://registry.yarnpkg.com/ping-widget/-/ping-widget-0.0.21.tgz#7143c9702a1ad0cfaf2efccfbfe773c9e0ed940a"
|
resolved "https://registry.yarnpkg.com/ping-widget/-/ping-widget-0.0.24.tgz#fc17532d486af65836a1765918569dba99e615f0"
|
||||||
integrity sha512-4+Xprk1wYn9ww9FsbFY4j4HEpD9CUFlrlWl8AP5iO02RTiUMCpOHSvyKALUlDYL1LYC6bhuRUFepJ5KpMZIO8Q==
|
integrity sha512-TVRj1FctAaZRy3kWlttVa3KUmqjBwb9kh2u6zpSvVIaKAp3M+B+hyGf0lARVeSyNd3pbYPJKo3vZL1tu4DHqCw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@cosmjs/amino" "^0.30.1"
|
"@cosmjs/amino" "^0.30.1"
|
||||||
"@cosmjs/cosmwasm-stargate" "^0.30.1"
|
"@cosmjs/cosmwasm-stargate" "^0.30.1"
|
||||||
|
Loading…
Reference in New Issue
Block a user