using extra to have reverse option
This commit is contained in:
parent
52e0d8f660
commit
ce22688b4e
@ -76,5 +76,8 @@
|
||||
"vite-plugin-pages": "^0.28.0",
|
||||
"vue-json-viewer": "3",
|
||||
"vue-tsc": "^1.0.12"
|
||||
},
|
||||
"resolutions": {
|
||||
"cosmjs-types": "^0.9.0"
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,7 +10,6 @@ import type { PaginatedProposals } from '@/types';
|
||||
import ProposalProcess from './ProposalProcess.vue';
|
||||
import type { PropType } from 'vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import { fromTimestamp } from 'cosmjs-types/helpers';
|
||||
import type { QueryProposalsResponse } from 'cosmjs-types/cosmos/gov/v1beta1/query';
|
||||
const dialog = useTxDialog();
|
||||
defineProps({
|
||||
@ -117,7 +116,7 @@ function metaItem(metadata: string | undefined): {
|
||||
<div
|
||||
class="truncate col-span-2 md:!col-span-1 text-xs text-gray-500 dark:text-gray-400 text-right md:!flex md:!justify-start"
|
||||
>
|
||||
{{ format.toDay(fromTimestamp(item.votingEndTime), 'from') }}
|
||||
{{ format.toDay(item.votingEndTime, 'from') }}
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
@ -185,7 +184,7 @@ function metaItem(metadata: string | undefined): {
|
||||
<div
|
||||
class="truncate text-xs text-gray-500 dark:text-gray-400 flex items-center justify-end"
|
||||
>
|
||||
{{ format.toDay(fromTimestamp(item.votingEndTime), 'from') }}
|
||||
{{ format.toDay(item.votingEndTime, 'from') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -2,8 +2,6 @@
|
||||
import ApexCharts from 'vue3-apexcharts';
|
||||
import { computed, type PropType } from 'vue';
|
||||
import { useFormatter } from '@/stores';
|
||||
import { fromTimestamp } from 'cosmjs-types/helpers';
|
||||
import type { CommissionRate } from '@/types';
|
||||
import type { Commission } from 'cosmjs-types/cosmos/staking/v1beta1/staking';
|
||||
|
||||
const props = defineProps({
|
||||
@ -128,12 +126,7 @@ const chartConfig = computed(() => {
|
||||
<div class="bg-base-100 rounded shadow p-4">
|
||||
<div class="text-lg text-main font-semibold mb-1">Commission Rate</div>
|
||||
<div class="text-sm text-gray-500 dark:text-gray-400">
|
||||
{{
|
||||
`Updated at ${format.toDay(
|
||||
fromTimestamp(props.commission?.updateTime!),
|
||||
'short'
|
||||
)}`
|
||||
}}
|
||||
{{ `Updated at ${format.toDay(props.commission?.updateTime, 'short')}` }}
|
||||
</div>
|
||||
<div class="w-80 m-auto">
|
||||
<ApexCharts type="donut" :options="chartConfig" :series="series" />
|
||||
|
||||
@ -51,7 +51,9 @@ const typeMap = Object.fromEntries(
|
||||
Object.entries(MsgType).map(([k, v]) => ['/' + v, k])
|
||||
);
|
||||
|
||||
type TxType = keyof typeof MsgType;
|
||||
Object.assign(typeMap, {
|
||||
'/cosmos.params.v1beta1.ParameterChangeProposal': 'ParameterChangeProposal',
|
||||
});
|
||||
|
||||
const findType = (obj: any, type: string): any => {
|
||||
if (typeof obj !== 'object') return;
|
||||
|
||||
@ -13,10 +13,13 @@ import {
|
||||
setupGovExtension,
|
||||
type GovProposalId,
|
||||
type IbcExtension,
|
||||
type AuthExtension,
|
||||
type DistributionExtension,
|
||||
setupIbcExtension,
|
||||
setupSlashingExtension,
|
||||
setupDistributionExtension,
|
||||
createProtobufRpcClient,
|
||||
setupAuthExtension,
|
||||
} from '@cosmjs/stargate';
|
||||
import {
|
||||
HttpClient,
|
||||
@ -40,38 +43,72 @@ import {
|
||||
withCustomRequest,
|
||||
} from './registry';
|
||||
import { buildQuery } from '@cosmjs/tendermint-rpc/build/tendermint37/requests';
|
||||
import { PageRequest, type Coin } from '@/types';
|
||||
import type {
|
||||
DistributionExtension,
|
||||
SlashingExtension,
|
||||
} from '@cosmjs/stargate/build/modules';
|
||||
import { PageRequest } from '@/types';
|
||||
import { PageRequest as CosmosPageRequest } from 'cosmjs-types/cosmos/base/query/v1beta1/pagination';
|
||||
import type { BondStatusString } from '@cosmjs/stargate/build/modules/staking/queries';
|
||||
import type { ProposalStatus } from 'cosmjs-types/cosmos/gov/v1beta1/gov';
|
||||
import { fromBase64 } from '@cosmjs/encoding';
|
||||
import {
|
||||
QueryAccountsResponse,
|
||||
QueryClientImpl,
|
||||
QueryClientImpl as AuthQueryClientImpl,
|
||||
} from 'cosmjs-types/cosmos/auth/v1beta1/query';
|
||||
import {
|
||||
QueryVotesResponse,
|
||||
QueryClientImpl as GovQueryClientImpl,
|
||||
QueryProposalsResponse,
|
||||
} from 'cosmjs-types/cosmos/gov/v1beta1/query';
|
||||
|
||||
import type { Any } from 'cosmjs-types/google/protobuf/any';
|
||||
import { BaseAccount } from 'cosmjs-types/cosmos/auth/v1beta1/auth';
|
||||
import type { SlashingExtension } from '@cosmjs/stargate/build/modules';
|
||||
import { longify } from '@cosmjs/stargate/build/queryclient';
|
||||
|
||||
export interface AuthExtension {
|
||||
readonly auth: {
|
||||
readonly account: (address: string) => Promise<BaseAccount | undefined>;
|
||||
readonly accounts: () => Promise<QueryAccountsResponse>;
|
||||
export interface ExtraExtension {
|
||||
readonly extra: {
|
||||
readonly accounts: (page?: PageRequest) => Promise<QueryAccountsResponse>;
|
||||
readonly votes: (
|
||||
proposalId: GovProposalId,
|
||||
page?: PageRequest
|
||||
) => Promise<QueryVotesResponse>;
|
||||
readonly proposals: (
|
||||
proposalStatus: ProposalStatus,
|
||||
page?: PageRequest
|
||||
) => Promise<QueryProposalsResponse>;
|
||||
};
|
||||
}
|
||||
function setupAuthExtension(base: QueryClient) {
|
||||
function setupExtraExtension(base: QueryClient) {
|
||||
const rpc = createProtobufRpcClient(base);
|
||||
const queryService = new QueryClientImpl(rpc);
|
||||
const authQueryService = new AuthQueryClientImpl(rpc);
|
||||
const govQueryService = new GovQueryClientImpl(rpc);
|
||||
return {
|
||||
auth: {
|
||||
account: async (address: string) => {
|
||||
const { account } = await queryService.Account({ address: address });
|
||||
return account?.value ? BaseAccount.decode(account.value) : undefined;
|
||||
extra: {
|
||||
accounts: async (page?: PageRequest) => {
|
||||
return await authQueryService.Accounts({
|
||||
pagination: CosmosPageRequest.fromPartial({
|
||||
key: page?.key ? fromBase64(page.key) : undefined,
|
||||
reverse: page?.reverse ?? true,
|
||||
}),
|
||||
});
|
||||
},
|
||||
accounts: async () => {
|
||||
return await queryService.Accounts();
|
||||
votes: async (proposalId: GovProposalId, page?: PageRequest) => {
|
||||
return await govQueryService.Votes({
|
||||
proposalId: longify(proposalId),
|
||||
pagination: CosmosPageRequest.fromPartial({
|
||||
key: page?.key ? fromBase64(page.key) : undefined,
|
||||
reverse: page?.reverse ?? true,
|
||||
}),
|
||||
});
|
||||
},
|
||||
proposals: async (proposalStatus: ProposalStatus, page?: PageRequest) => {
|
||||
return await govQueryService.Proposals({
|
||||
proposalStatus,
|
||||
voter: '',
|
||||
depositor: '',
|
||||
pagination: CosmosPageRequest.fromPartial({
|
||||
key: page?.key ? fromBase64(page.key) : undefined,
|
||||
reverse: page?.reverse ?? true,
|
||||
}),
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
@ -91,7 +128,8 @@ export class BaseRestClient<R extends AbstractRegistry> {
|
||||
IbcExtension &
|
||||
SlashingExtension &
|
||||
DistributionExtension &
|
||||
TxExtension;
|
||||
TxExtension &
|
||||
ExtraExtension;
|
||||
|
||||
constructor(endpoint: string, registry: R) {
|
||||
this.endpoint = endpoint;
|
||||
@ -116,7 +154,8 @@ export class BaseRestClient<R extends AbstractRegistry> {
|
||||
setupIbcExtension,
|
||||
setupSlashingExtension,
|
||||
setupDistributionExtension,
|
||||
setupTxExtension
|
||||
setupTxExtension,
|
||||
setupExtraExtension
|
||||
);
|
||||
}
|
||||
|
||||
@ -178,7 +217,7 @@ export class CosmosRestClient extends BaseRestClient<RequestRegistry> {
|
||||
// if (!page) page = new PageRequest();
|
||||
// const query = `?${page.toQueryString()}`;
|
||||
// return this.request(this.registry.auth_accounts, {}, query);
|
||||
const res = await this.queryClient.auth.accounts();
|
||||
const res = await this.queryClient.extra.accounts(page);
|
||||
console.log(res);
|
||||
return res;
|
||||
}
|
||||
@ -301,8 +340,12 @@ export class CosmosRestClient extends BaseRestClient<RequestRegistry> {
|
||||
}
|
||||
// Gov
|
||||
async getParams(subspace: string, key: string) {
|
||||
console.log(this.registry.params, subspace, key);
|
||||
return this.request(this.registry.params, { subspace, key });
|
||||
// console.log(this.registry.params, subspace, key);
|
||||
// return this.request(this.registry.params, { subspace, key });
|
||||
switch (subspace) {
|
||||
case 'distribution':
|
||||
return await this.getDistributionParams();
|
||||
}
|
||||
}
|
||||
async getGovParamsVoting() {
|
||||
// return this.request(this.registry.gov_params_voting, {});
|
||||
@ -325,11 +368,7 @@ export class CosmosRestClient extends BaseRestClient<RequestRegistry> {
|
||||
async getGovProposals(status: ProposalStatus, page?: PageRequest) {
|
||||
if (!page) page = new PageRequest();
|
||||
page.reverse = true;
|
||||
// const query = `?proposal_status={status}&${page.toQueryString()}`;
|
||||
// return this.request(this.registry.gov_proposals, { status }, query);
|
||||
const paginationKey = page?.key ? fromBase64(page.key) : undefined;
|
||||
|
||||
const res = this.queryClient.gov.proposals(status, '', '', paginationKey);
|
||||
const res = this.queryClient.extra.proposals(status, page);
|
||||
console.log(res);
|
||||
return res;
|
||||
}
|
||||
@ -361,7 +400,7 @@ export class CosmosRestClient extends BaseRestClient<RequestRegistry> {
|
||||
// }
|
||||
// );
|
||||
}
|
||||
async getGovProposalVotes(proposal_id: string, page?: PageRequest) {
|
||||
async getGovProposalVotes(proposal_id: GovProposalId, page?: PageRequest) {
|
||||
// if (!page) page = new PageRequest();
|
||||
// page.reverse = true;
|
||||
// const query = `?proposal_status={status}&${page.toQueryString()}`;
|
||||
@ -371,9 +410,9 @@ export class CosmosRestClient extends BaseRestClient<RequestRegistry> {
|
||||
// query
|
||||
// );
|
||||
|
||||
const paginationKey = page?.key ? fromBase64(page.key) : undefined;
|
||||
const res = await this.queryClient.gov.votes(proposal_id, paginationKey);
|
||||
console.log(res);
|
||||
// const paginationKey = page?.key ? fromBase64(page.key) : undefined;
|
||||
const res = await this.queryClient.extra.votes(proposal_id, page);
|
||||
console.log('vote', proposal_id, res);
|
||||
return res;
|
||||
}
|
||||
async getGovProposalVotesVoter(proposal_id: string, voter: string) {
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
<script lang="ts" setup>
|
||||
import { computed } from '@vue/reactivity';
|
||||
import { fromTimestamp } from 'cosmjs-types/helpers';
|
||||
import MdEditor from 'md-editor-v3';
|
||||
import ObjectElement from '@/components/dynamic/ObjectElement.vue';
|
||||
import {
|
||||
@ -21,15 +22,25 @@ import { ref, reactive } from 'vue';
|
||||
import Countdown from '@/components/Countdown.vue';
|
||||
import PaginationBar from '@/components/PaginationBar.vue';
|
||||
import { fromBech32, toHex } from '@cosmjs/encoding';
|
||||
import type { Vote } from 'cosmjs-types/cosmos/gov/v1beta1/gov';
|
||||
import {
|
||||
ProposalStatus,
|
||||
proposalStatusToJSON,
|
||||
VoteOption,
|
||||
voteOptionToJSON,
|
||||
} from 'cosmjs-types/cosmos/gov/v1beta1/gov';
|
||||
import type { MsgSoftwareUpgrade } from 'cosmjs-types/cosmos/upgrade/v1beta1/tx';
|
||||
import type { Proposal, Vote } from 'cosmjs-types/cosmos/gov/v1beta1/gov';
|
||||
import type { PageResponse } from 'cosmjs-types/cosmos/base/query/v1beta1/pagination';
|
||||
import type { ParameterChangeProposal } from 'cosmjs-types/cosmos/params/v1beta1/params';
|
||||
import type {
|
||||
QueryDepositResponse,
|
||||
QueryDepositsResponse,
|
||||
} from 'cosmjs-types/cosmos/gov/v1beta1/query';
|
||||
import { decodeProto } from '@/components/dynamic';
|
||||
import type { Timestamp } from 'cosmjs-types/google/protobuf/timestamp';
|
||||
|
||||
const props = defineProps(['proposal_id', 'chain']);
|
||||
const proposal = ref({} as GovProposal);
|
||||
const proposal = ref({} as Proposal);
|
||||
const format = useFormatter();
|
||||
const store = useGovStore();
|
||||
const dialog = useTxDialog();
|
||||
@ -38,22 +49,29 @@ const chainStore = useBlockchain();
|
||||
|
||||
store.fetchProposal(props.proposal_id).then((res) => {
|
||||
const proposalDetail = reactive(res.proposal);
|
||||
const changeProposal = decodeProto(
|
||||
proposalDetail.content!
|
||||
) as ParameterChangeProposal;
|
||||
Object.assign(proposalDetail.content!, changeProposal);
|
||||
// when status under the voting, final_tally_result are no data, should request fetchTally
|
||||
if (res.proposal?.voterStatus === 'PROPOSAL_STATUS_VOTING_PERIOD') {
|
||||
if (proposalDetail.status === ProposalStatus.PROPOSAL_STATUS_VOTING_PERIOD) {
|
||||
// 'PROPOSAL_STATUS_VOTING_PERIOD') {
|
||||
store.fetchTally(props.proposal_id).then((tallRes) => {
|
||||
proposalDetail.finalTallyResult = tallRes.tally;
|
||||
});
|
||||
}
|
||||
|
||||
proposal.value = proposalDetail;
|
||||
console.log('fetchProposal', proposal.value);
|
||||
// load origin params if the proposal is param change
|
||||
if (proposalDetail.content?.changes) {
|
||||
proposalDetail.content?.changes.forEach((item) => {
|
||||
if (changeProposal?.changes) {
|
||||
changeProposal.changes.forEach((item) => {
|
||||
chainStore.rpc.getParams(item.subspace, item.key).then((res) => {
|
||||
if (proposal.value.content && res.param) {
|
||||
if (proposal.value.content && res?.params) {
|
||||
if (proposal.value.content.current) {
|
||||
proposal.value.content.current.push(res.param);
|
||||
proposal.value.content.current.push(res.params);
|
||||
} else {
|
||||
proposal.value.content.current = [res.param];
|
||||
proposal.value.content.current = [res.params];
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -62,16 +80,22 @@ store.fetchProposal(props.proposal_id).then((res) => {
|
||||
});
|
||||
|
||||
const color = computed(() => {
|
||||
if (proposal.value.status === 'PROPOSAL_STATUS_PASSED') {
|
||||
if (proposal.value.status === ProposalStatus.PROPOSAL_STATUS_PASSED) {
|
||||
// 'PROPOSAL_STATUS_PASSED') {
|
||||
return 'success';
|
||||
} else if (proposal.value.status === 'PROPOSAL_STATUS_REJECTED') {
|
||||
} else if (
|
||||
proposal.value.status === ProposalStatus.PROPOSAL_STATUS_REJECTED
|
||||
) {
|
||||
return 'error';
|
||||
}
|
||||
return '';
|
||||
});
|
||||
const status = computed(() => {
|
||||
if (proposal.value.status) {
|
||||
return proposal.value.status.replace('PROPOSAL_STATUS_', '');
|
||||
return proposalStatusToJSON(proposal.value.status).replace(
|
||||
'PROPOSAL_STATUS_',
|
||||
''
|
||||
);
|
||||
}
|
||||
return '';
|
||||
});
|
||||
@ -88,7 +112,7 @@ store.fetchProposalVotes(props.proposal_id).then((x) => {
|
||||
pageResponse.value = x.pagination;
|
||||
});
|
||||
|
||||
function shortTime(v: string) {
|
||||
function shortTime(v: string | Date | Timestamp) {
|
||||
if (v) {
|
||||
return format.toDay(v, 'from');
|
||||
}
|
||||
@ -97,30 +121,36 @@ function shortTime(v: string) {
|
||||
|
||||
const votingCountdown = computed((): number => {
|
||||
const now = new Date();
|
||||
const end = new Date(proposal.value.voting_end_time);
|
||||
const end = proposal.value.votingEndTime
|
||||
? fromTimestamp(proposal.value.votingEndTime)
|
||||
: new Date();
|
||||
return end.getTime() - now.getTime();
|
||||
});
|
||||
|
||||
const upgradeCountdown = computed((): number => {
|
||||
const height = Number(proposal.value.content?.plan?.height || 0);
|
||||
// @ts-ignore
|
||||
const upgradeSoftware = proposal.value.content as MsgSoftwareUpgrade;
|
||||
const height = Number(upgradeSoftware.plan?.height || 0);
|
||||
if (height > 0) {
|
||||
const base = useBaseStore();
|
||||
const current = Number(base.latest?.block?.header?.height || 0);
|
||||
return (height - current) * 6 * 1000;
|
||||
}
|
||||
const now = new Date();
|
||||
const end = new Date(proposal.value.content?.plan?.time || '');
|
||||
const end = upgradeSoftware.plan?.time
|
||||
? fromTimestamp(upgradeSoftware.plan?.time || '')
|
||||
: new Date();
|
||||
return end.getTime() - now.getTime();
|
||||
});
|
||||
|
||||
const total = computed(() => {
|
||||
const tally = proposal.value.final_tally_result;
|
||||
const tally = proposal.value.finalTallyResult;
|
||||
let sum = 0;
|
||||
if (tally) {
|
||||
sum += Number(tally.abstain || 0);
|
||||
sum += Number(tally.yes || 0);
|
||||
sum += Number(tally.no || 0);
|
||||
sum += Number(tally.no_with_veto || 0);
|
||||
sum += Number(tally.noWithVeto || 0);
|
||||
}
|
||||
return sum;
|
||||
});
|
||||
@ -135,7 +165,7 @@ const turnout = computed(() => {
|
||||
|
||||
const yes = computed(() => {
|
||||
if (total.value > 0) {
|
||||
const yes = proposal.value?.final_tally_result?.yes || 0;
|
||||
const yes = proposal.value?.finalTallyResult?.yes || 0;
|
||||
return format.percent(Number(yes) / total.value);
|
||||
}
|
||||
return 0;
|
||||
@ -143,7 +173,7 @@ const yes = computed(() => {
|
||||
|
||||
const no = computed(() => {
|
||||
if (total.value > 0) {
|
||||
const value = proposal.value?.final_tally_result?.no || 0;
|
||||
const value = proposal.value?.finalTallyResult?.no || 0;
|
||||
return format.percent(Number(value) / total.value);
|
||||
}
|
||||
return 0;
|
||||
@ -151,7 +181,7 @@ const no = computed(() => {
|
||||
|
||||
const veto = computed(() => {
|
||||
if (total.value > 0) {
|
||||
const value = proposal.value?.final_tally_result?.no_with_veto || 0;
|
||||
const value = proposal.value?.finalTallyResult?.noWithVeto || 0;
|
||||
return format.percent(Number(value) / total.value);
|
||||
}
|
||||
return 0;
|
||||
@ -159,7 +189,7 @@ const veto = computed(() => {
|
||||
|
||||
const abstain = computed(() => {
|
||||
if (total.value > 0) {
|
||||
const value = proposal.value?.final_tally_result?.abstain || 0;
|
||||
const value = proposal.value?.finalTallyResult?.abstain || 0;
|
||||
return format.percent(Number(value) / total.value);
|
||||
}
|
||||
return 0;
|
||||
@ -187,6 +217,7 @@ function pageload(p: number) {
|
||||
pageRequest.value.setPage(p);
|
||||
store.fetchProposalVotes(props.proposal_id, pageRequest.value).then((x) => {
|
||||
votes.value = x.votes;
|
||||
console.log('vote', votes.value);
|
||||
pageResponse.value = x.pagination;
|
||||
});
|
||||
}
|
||||
@ -297,9 +328,11 @@ function metaItem(metadata: string | undefined): {
|
||||
<div class="w-2 h-2 rounded-full bg-error mr-3"></div>
|
||||
<div class="text-base flex-1 text-main">
|
||||
{{ $t('gov.submit_at') }}:
|
||||
{{ format.toDay(proposal.submit_time) }}
|
||||
{{ format.toDay(proposal.submitTime) }}
|
||||
</div>
|
||||
<div class="text-sm">
|
||||
{{ shortTime(proposal.submitTime) }}
|
||||
</div>
|
||||
<div class="text-sm">{{ shortTime(proposal.submit_time) }}</div>
|
||||
</div>
|
||||
<div class="flex items-center mb-4">
|
||||
<div class="w-2 h-2 rounded-full bg-primary mr-3"></div>
|
||||
@ -307,18 +340,20 @@ function metaItem(metadata: string | undefined): {
|
||||
{{ $t('gov.deposited_at') }}:
|
||||
{{
|
||||
format.toDay(
|
||||
proposal.status === 'PROPOSAL_STATUS_DEPOSIT_PERIOD'
|
||||
? proposal.deposit_end_time
|
||||
: proposal.voting_start_time
|
||||
proposal.status ===
|
||||
ProposalStatus.PROPOSAL_STATUS_DEPOSIT_PERIOD
|
||||
? proposal.depositEndTime
|
||||
: proposal.votingStartTime
|
||||
)
|
||||
}}
|
||||
</div>
|
||||
<div class="text-sm">
|
||||
{{
|
||||
shortTime(
|
||||
proposal.status === 'PROPOSAL_STATUS_DEPOSIT_PERIOD'
|
||||
? proposal.deposit_end_time
|
||||
: proposal.voting_start_time
|
||||
proposal.status ===
|
||||
ProposalStatus.PROPOSAL_STATUS_DEPOSIT_PERIOD
|
||||
? proposal.depositEndTime
|
||||
: proposal.votingStartTime
|
||||
)
|
||||
}}
|
||||
</div>
|
||||
@ -328,10 +363,10 @@ function metaItem(metadata: string | undefined): {
|
||||
<div class="w-2 h-2 rounded-full bg-yes mr-3"></div>
|
||||
<div class="text-base flex-1 text-main">
|
||||
{{ $t('gov.vote_start_from') }}
|
||||
{{ format.toDay(proposal.voting_start_time) }}
|
||||
{{ format.toDay(proposal.votingStartTime) }}
|
||||
</div>
|
||||
<div class="text-sm">
|
||||
{{ shortTime(proposal.voting_start_time) }}
|
||||
{{ shortTime(proposal.votingStartTime) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="pl-5 text-sm mt-2">
|
||||
@ -343,10 +378,10 @@ function metaItem(metadata: string | undefined): {
|
||||
<div class="w-2 h-2 rounded-full bg-success mr-3"></div>
|
||||
<div class="text-base flex-1 text-main">
|
||||
{{ $t('gov.vote_end') }}
|
||||
{{ format.toDay(proposal.voting_end_time) }}
|
||||
{{ format.toDay(proposal.votingEndTime) }}
|
||||
</div>
|
||||
<div class="text-sm">
|
||||
{{ shortTime(proposal.voting_end_time) }}
|
||||
{{ shortTime(proposal.votingEndTime) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="pl-5 text-sm">
|
||||
@ -358,7 +393,7 @@ function metaItem(metadata: string | undefined): {
|
||||
<div
|
||||
class="mt-4"
|
||||
v-if="
|
||||
proposal?.content?.['@type']?.endsWith('SoftwareUpgradeProposal')
|
||||
proposal?.content?.typeUrl.endsWith('SoftwareUpgradeProposal')
|
||||
"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
@ -373,7 +408,7 @@ function metaItem(metadata: string | undefined): {
|
||||
}}</span>
|
||||
</div>
|
||||
<div class="text-sm">
|
||||
{{ shortTime(proposal.voting_end_time) }}
|
||||
{{ shortTime(proposal.votingEndTime) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="pl-5 text-sm mt-2">
|
||||
@ -395,8 +430,9 @@ function metaItem(metadata: string | undefined): {
|
||||
v-if="item.option"
|
||||
class="py-2 text-sm"
|
||||
:class="{
|
||||
'text-yes': item.option === 'VOTE_OPTION_YES',
|
||||
'text-gray-400': item.option === 'VOTE_OPTION_ABSTAIN',
|
||||
'text-yes': item.option === VoteOption.VOTE_OPTION_YES,
|
||||
'text-gray-400':
|
||||
item.option === VoteOption.VOTE_OPTION_ABSTAIN,
|
||||
}"
|
||||
>
|
||||
{{ String(item.option).replace('VOTE_OPTION_', '') }}
|
||||
@ -406,7 +442,7 @@ function metaItem(metadata: string | undefined): {
|
||||
item.options
|
||||
.map(
|
||||
(x) =>
|
||||
`${x.option.replace(
|
||||
`${voteOptionToJSON(x.option).replace(
|
||||
'VOTE_OPTION_',
|
||||
''
|
||||
)}:${format.percent(x.weight)}`
|
||||
@ -419,7 +455,7 @@ function metaItem(metadata: string | undefined): {
|
||||
</table>
|
||||
<PaginationBar
|
||||
:limit="pageRequest.limit"
|
||||
:total="pageResponse?.total.toString()"
|
||||
:total="pageResponse?.total?.toString()"
|
||||
:callback="pageload"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -9,53 +9,81 @@ import ChainRegistryClient from '@ping-pub/chain-registry-client';
|
||||
import type { IBCPath } from '@ping-pub/chain-registry-client/dist/types';
|
||||
import router from '@/router';
|
||||
import { useIBCModule } from './connStore';
|
||||
import type { PageResponse } from 'cosmjs-types/cosmos/base/query/v1beta1/pagination';
|
||||
import type { IdentifiedConnection } from 'cosmjs-types/ibc/core/connection/v1/connection';
|
||||
|
||||
const props = defineProps(['chain']);
|
||||
const chainStore = useBlockchain();
|
||||
const ibcStore = useIBCModule()
|
||||
const list = ref([] as Connection[]);
|
||||
const pageRequest = ref(new PageRequest())
|
||||
const pageResponse = ref({} as Pagination)
|
||||
const ibcStore = useIBCModule();
|
||||
const list = ref([] as IdentifiedConnection[]);
|
||||
const pageRequest = ref(new PageRequest());
|
||||
const pageResponse = ref({} as PageResponse | undefined);
|
||||
const tab = ref('registry');
|
||||
|
||||
onMounted(() => {
|
||||
pageload(1)
|
||||
ibcStore.load()
|
||||
pageload(1);
|
||||
ibcStore.load();
|
||||
});
|
||||
|
||||
function pageload(p: number) {
|
||||
pageRequest.value.setPage(p)
|
||||
pageRequest.value.setPage(p);
|
||||
chainStore.rpc.getIBCConnections(pageRequest.value).then((x) => {
|
||||
list.value = x.connections;
|
||||
pageResponse.value = x.pagination
|
||||
if(x.pagination.total && Number(x.pagination.total) > 0) {
|
||||
ibcStore.showConnection(0)
|
||||
pageResponse.value = x.pagination;
|
||||
if (x.pagination?.total && Number(x.pagination.total) > 0) {
|
||||
ibcStore.showConnection(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<div class="bg-base-100 px-4 pt-3 pb-4 rounded shadow">
|
||||
<div class="flex flex-wrap gap-4 items-center">
|
||||
<div class="flex flex-wrap gap-4 items-center">
|
||||
<h2 class="card-title py-4">{{ $t('ibc.title') }}</h2>
|
||||
<div class="tabs tabs-boxed">
|
||||
<a class="tab" :class="{ 'tab-active': tab === 'registry' }" @click="tab = 'registry'">{{ $t('ibc.registry') }}</a>
|
||||
<a class="tab" :class="{ 'tab-active': tab === 'favorite' }" @click="tab = 'favorite'">{{ $t('module.favorite') }}</a>
|
||||
<a
|
||||
class="tab"
|
||||
:class="{ 'tab-active': tab === 'registry' }"
|
||||
@click="tab = 'registry'"
|
||||
>{{ $t('ibc.registry') }}</a
|
||||
>
|
||||
<a
|
||||
class="tab"
|
||||
:class="{ 'tab-active': tab === 'favorite' }"
|
||||
@click="tab = 'favorite'"
|
||||
>{{ $t('module.favorite') }}</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div v-show="tab === 'registry'" class="flex flex-wrap gap-1 p-4 ">
|
||||
<span v-for="s in ibcStore.commonIBCs" class="btn btn-xs btn-link mr-1" @click="ibcStore.fetchConnection(s.path)">{{ s.from }}
|
||||
⇌ {{ s.to }}</span>
|
||||
<div v-show="tab === 'registry'" class="flex flex-wrap gap-1 p-4">
|
||||
<span
|
||||
v-for="s in ibcStore.commonIBCs"
|
||||
class="btn btn-xs btn-link mr-1"
|
||||
@click="ibcStore.fetchConnection(s.path)"
|
||||
>{{ s.from }} ⇌ {{ s.to }}</span
|
||||
>
|
||||
</div>
|
||||
<div v-show="tab === 'favorite'" class="flex flex-wrap gap-1 p-4 ">
|
||||
<div v-show="tab === 'favorite'" class="flex flex-wrap gap-1 p-4">
|
||||
<div class="join border border-primary">
|
||||
<button class="join-item px-2">{{ $t('ibc.connection_id') }}:</button>
|
||||
<input v-model="ibcStore.connectionId" type=number class="input input-bordered w-40 join-item" min="0"
|
||||
:max="pageResponse.total || 0" :placeholder="`0~${pageResponse.total}`" />
|
||||
<button class="join-item btn btn-primary" @click="ibcStore.showConnection()">{{ $t('ibc.btn_apply') }}</button>
|
||||
<button class="join-item px-2">
|
||||
{{ $t('ibc.connection_id') }}:
|
||||
</button>
|
||||
<input
|
||||
v-model="ibcStore.connectionId"
|
||||
type="number"
|
||||
class="input input-bordered w-40 join-item"
|
||||
min="0"
|
||||
:max="pageResponse?.total.toString()"
|
||||
:placeholder="`0~${pageResponse?.total.toString()}`"
|
||||
/>
|
||||
<button
|
||||
class="join-item btn btn-primary"
|
||||
@click="ibcStore.showConnection()"
|
||||
>
|
||||
{{ $t('ibc.btn_apply') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -57,7 +57,7 @@ onMounted(() => {
|
||||
clientState.value = x.identifiedClientState;
|
||||
if (x.identifiedClientState?.clientState) {
|
||||
Object.assign(
|
||||
clientState.value?.clientState!,
|
||||
clientState.value!,
|
||||
TendermintClientState.decode(
|
||||
x.identifiedClientState?.clientState.value
|
||||
)
|
||||
@ -174,7 +174,7 @@ function color(v: string) {
|
||||
<div
|
||||
class="order-first text-3xl font-semibold tracking-tight text-main mb-2"
|
||||
>
|
||||
{{ clientState?.clientState?.chainId }}
|
||||
{{ clientState?.chainId }}
|
||||
</div>
|
||||
<div class="text-sm text-gray-500 dark:text-gray-400">
|
||||
{{ conn?.counterparty?.connectionId }} {{ clientState?.clientId }}
|
||||
@ -202,8 +202,8 @@ function color(v: string) {
|
||||
<tr>
|
||||
<td class="w-52">{{ $t('ibc.trust_level') }}:</td>
|
||||
<td>
|
||||
{{ clientState?.clientState?.trustLevel.numerator }}/{{
|
||||
clientState.clientState?.trustLevel.denominator
|
||||
{{ clientState?.trustLevel.numerator }}/{{
|
||||
clientState?.trustLevel.denominator
|
||||
}}
|
||||
</td>
|
||||
</tr>
|
||||
@ -211,9 +211,7 @@ function color(v: string) {
|
||||
<td class="w-52">{{ $t('ibc.trusting_period') }}:</td>
|
||||
<td>
|
||||
{{
|
||||
formatSeconds(
|
||||
clientState.clientState?.trustingPeriod.seconds.toString()
|
||||
)
|
||||
formatSeconds(clientState?.trustingPeriod.seconds.toString())
|
||||
}}
|
||||
</td>
|
||||
</tr>
|
||||
@ -221,9 +219,7 @@ function color(v: string) {
|
||||
<td class="w-52">{{ $t('ibc.unbonding_period') }}:</td>
|
||||
<td>
|
||||
{{
|
||||
formatSeconds(
|
||||
clientState.clientState?.unbondingPeriod.seconds.toString()
|
||||
)
|
||||
formatSeconds(clientState?.unbondingPeriod.seconds.toString())
|
||||
}}
|
||||
</td>
|
||||
</tr>
|
||||
@ -231,26 +227,20 @@ function color(v: string) {
|
||||
<td class="w-52">{{ $t('ibc.max_clock_drift') }}:</td>
|
||||
<td>
|
||||
{{
|
||||
formatSeconds(
|
||||
clientState.clientState?.maxClockDrift.seconds.toString()
|
||||
)
|
||||
formatSeconds(clientState?.maxClockDrift.seconds.toString())
|
||||
}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="w-52">{{ $t('ibc.frozen_height') }}:</td>
|
||||
<td>
|
||||
{{
|
||||
clientState.clientState?.frozenHeight.revisionHeight.toString()
|
||||
}}
|
||||
{{ clientState?.frozenHeight.revisionHeight.toString() }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="w-52">{{ $t('ibc.latest_height') }}:</td>
|
||||
<td>
|
||||
{{
|
||||
clientState.clientState?.latestHeight.revisionHeight.toString()
|
||||
}}
|
||||
{{ clientState?.latestHeight.revisionHeight.toString() }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@ -266,9 +256,7 @@ function color(v: string) {
|
||||
<td colspan="2">
|
||||
<div class="flex justify-between">
|
||||
<span>{{ $t('ibc.allow_update_after_expiry') }}:</span>
|
||||
<span>{{
|
||||
clientState.clientState?.allowUpdateAfterExpiry
|
||||
}}</span>
|
||||
<span>{{ clientState?.allowUpdateAfterExpiry }}</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@ -276,16 +264,14 @@ function color(v: string) {
|
||||
<td colspan="2">
|
||||
<div class="flex justify-between">
|
||||
<span>{{ $t('ibc.allow_update_after_misbehaviour') }}: </span>
|
||||
<span>{{
|
||||
clientState.clientState?.allowUpdateAfterMisbehaviour
|
||||
}}</span>
|
||||
<span>{{ clientState?.allowUpdateAfterMisbehaviour }}</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="w-52">{{ $t('ibc.upgrade_path') }}:</td>
|
||||
<td class="text-right">
|
||||
{{ clientState.clientState?.upgradePath.join(', ') }}
|
||||
{{ clientState?.upgradePath.join(', ') }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@ -389,11 +375,11 @@ function color(v: string) {
|
||||
<td>
|
||||
<div
|
||||
class="text-xs truncate relative py-2 px-4 rounded-full w-fit"
|
||||
:class="`text-${color(v.state)}`"
|
||||
:class="`text-${color(v.state.toString())}`"
|
||||
>
|
||||
<span
|
||||
class="inset-x-0 inset-y-0 opacity-10 absolute"
|
||||
:class="`bg-${color(v.state)}`"
|
||||
:class="`bg-${color(v.state.toString())}`"
|
||||
></span>
|
||||
{{ v.state }}
|
||||
</div>
|
||||
|
||||
@ -17,7 +17,7 @@ import { computed } from '@vue/reactivity';
|
||||
|
||||
import CardStatisticsVertical from '@/components/CardStatisticsVertical.vue';
|
||||
import ProposalListItem from '@/components/ProposalListItem.vue';
|
||||
import ArrayObjectElement from '@/components/dynamic/ArrayObjectElement.vue'
|
||||
import ArrayObjectElement from '@/components/dynamic/ArrayObjectElement.vue';
|
||||
|
||||
const props = defineProps(['chain']);
|
||||
|
||||
@ -27,7 +27,7 @@ const walletStore = useWalletStore();
|
||||
const format = useFormatter();
|
||||
const dialog = useTxDialog();
|
||||
const stakingStore = useStakingStore();
|
||||
const paramStore = useParamStore()
|
||||
const paramStore = useParamStore();
|
||||
const coinInfo = computed(() => {
|
||||
return store.coinInfo;
|
||||
});
|
||||
@ -35,19 +35,19 @@ const coinInfo = computed(() => {
|
||||
onMounted(() => {
|
||||
store.loadDashboard();
|
||||
walletStore.loadMyAsset();
|
||||
paramStore.handleAbciInfo()
|
||||
paramStore.handleAbciInfo();
|
||||
// if(!(coinInfo.value && coinInfo.value.name)) {
|
||||
// }
|
||||
});
|
||||
const ticker = computed(() => store.coinInfo.tickers[store.tickerIndex]);
|
||||
|
||||
const currName = ref("")
|
||||
const currName = ref('');
|
||||
blockchain.$subscribe((m, s) => {
|
||||
if (s.chainName !== currName.value) {
|
||||
currName.value = s.chainName
|
||||
currName.value = s.chainName;
|
||||
store.loadDashboard();
|
||||
walletStore.loadMyAsset();
|
||||
paramStore.handleAbciInfo()
|
||||
paramStore.handleAbciInfo();
|
||||
}
|
||||
});
|
||||
function shortName(name: string, id: string) {
|
||||
@ -97,53 +97,62 @@ const color = computed(() => {
|
||||
});
|
||||
|
||||
function updateState() {
|
||||
walletStore.loadMyAsset()
|
||||
walletStore.loadMyAsset();
|
||||
}
|
||||
|
||||
function trustColor(v: string) {
|
||||
return `text-${colorMap(v)}`
|
||||
return `text-${colorMap(v)}`;
|
||||
}
|
||||
|
||||
const quantity = ref(100)
|
||||
const quantity = ref(100);
|
||||
const qty = computed({
|
||||
get: () => {
|
||||
return parseFloat(quantity.value.toFixed(6))
|
||||
return parseFloat(quantity.value.toFixed(6));
|
||||
},
|
||||
set: val => {
|
||||
quantity.value = val
|
||||
}
|
||||
})
|
||||
set: (val) => {
|
||||
quantity.value = val;
|
||||
},
|
||||
});
|
||||
const amount = computed({
|
||||
get: () => {
|
||||
return quantity.value * ticker.value.converted_last.usd || 0
|
||||
return quantity.value * ticker.value.converted_last.usd || 0;
|
||||
},
|
||||
set: val => {
|
||||
quantity.value = val / ticker.value.converted_last.usd || 0
|
||||
}
|
||||
})
|
||||
|
||||
set: (val) => {
|
||||
quantity.value = val / ticker.value.converted_last.usd || 0;
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="coinInfo && coinInfo.name" class="bg-base-100 rounded shadow mb-4">
|
||||
<div
|
||||
v-if="coinInfo && coinInfo.name"
|
||||
class="bg-base-100 rounded shadow mb-4"
|
||||
>
|
||||
<div class="grid grid-cols-2 md:grid-cols-3 p-4">
|
||||
<div class="col-span-2 md:col-span-1">
|
||||
<div class="text-xl font-semibold text-main">
|
||||
{{ coinInfo.name }} (<span class="uppercase">{{
|
||||
coinInfo.symbol
|
||||
}}</span>)
|
||||
}}</span
|
||||
>)
|
||||
</div>
|
||||
<div class="text-xs mt-2">
|
||||
{{ $t('index.rank') }}:
|
||||
<div class="badge text-xs badge-error bg-[#fcebea] dark:bg-[#41384d] text-red-400">
|
||||
<div
|
||||
class="badge text-xs badge-error bg-[#fcebea] dark:bg-[#41384d] text-red-400"
|
||||
>
|
||||
#{{ coinInfo.market_cap_rank }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="my-4 flex flex-wrap items-center">
|
||||
<a v-for="(item, index) of comLinks" :key="index" :href="item.href"
|
||||
class="link link-primary px-2 py-1 rounded-sm no-underline hover:text-primary hover:bg-gray-100 dark:hover:bg-slate-800 flex items-center">
|
||||
<a
|
||||
v-for="(item, index) of comLinks"
|
||||
:key="index"
|
||||
:href="item.href"
|
||||
class="link link-primary px-2 py-1 rounded-sm no-underline hover:text-primary hover:bg-gray-100 dark:hover:bg-slate-800 flex items-center"
|
||||
>
|
||||
<Icon :icon="item?.icon" />
|
||||
<span class="ml-1 text-sm uppercase">{{ item?.name }}</span>
|
||||
</a>
|
||||
@ -153,9 +162,12 @@ const amount = computed({
|
||||
<div class="dropdown dropdown-hover w-full">
|
||||
<label>
|
||||
<div
|
||||
class="bg-gray-100 dark:bg-[#384059] flex items-center justify-between px-4 py-2 cursor-pointer rounded">
|
||||
class="bg-gray-100 dark:bg-[#384059] flex items-center justify-between px-4 py-2 cursor-pointer rounded"
|
||||
>
|
||||
<div>
|
||||
<div class="font-semibold text-xl text-[#666] dark:text-white">
|
||||
<div
|
||||
class="font-semibold text-xl text-[#666] dark:text-white"
|
||||
>
|
||||
{{ ticker?.market?.name || '' }}
|
||||
</div>
|
||||
<div class="text-info text-sm">
|
||||
@ -166,7 +178,9 @@ const amount = computed({
|
||||
</div>
|
||||
|
||||
<div class="text-right">
|
||||
<div class="text-xl font-semibold text-[#666] dark:text-white">
|
||||
<div
|
||||
class="text-xl font-semibold text-[#666] dark:text-white"
|
||||
>
|
||||
${{ ticker?.converted_last?.usd }}
|
||||
</div>
|
||||
<div class="text-sm" :class="store.priceColor">
|
||||
@ -178,10 +192,19 @@ const amount = computed({
|
||||
<div class="dropdown-content pt-1">
|
||||
<div class="h-64 overflow-auto w-full shadow rounded">
|
||||
<ul class="menu w-full bg-gray-100 rounded dark:bg-[#384059]">
|
||||
<li v-for="(item, index) in store.coinInfo.tickers" :key="index" @click="store.selectTicker(index)">
|
||||
<div class="flex items-center justify-between hover:bg-base-100">
|
||||
<li
|
||||
v-for="(item, index) in store.coinInfo.tickers"
|
||||
:key="index"
|
||||
@click="store.selectTicker(index)"
|
||||
>
|
||||
<div
|
||||
class="flex items-center justify-between hover:bg-base-100"
|
||||
>
|
||||
<div class="flex-1">
|
||||
<div class="text-main text-sm" :class="trustColor(item.trust_score)">
|
||||
<div
|
||||
class="text-main text-sm"
|
||||
:class="trustColor(item.trust_score)"
|
||||
>
|
||||
{{ item?.market?.name }}
|
||||
</div>
|
||||
<div class="text-sm text-gray-500 dark:text-gray-400">
|
||||
@ -192,7 +215,7 @@ const amount = computed({
|
||||
</div>
|
||||
|
||||
<div class="text-base text-main">
|
||||
${{ item?.converted_last?.usd }}
|
||||
${{ item?.converted_last?.usd }}
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
@ -203,37 +226,92 @@ const amount = computed({
|
||||
|
||||
<div class="flex">
|
||||
<label class="btn btn-primary !px-1 my-5 mr-2" for="calculator">
|
||||
<svg class="w-8 h-8" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <rect x="4" y="2" width="16" height="20" rx="2"></rect> <line x1="8" x2="16" y1="6" y2="6"></line> <line x1="16" x2="16" y1="14" y2="18"></line> <path d="M16 10h.01"></path> <path d="M12 10h.01"></path> <path d="M8 10h.01"></path> <path d="M12 14h.01"></path> <path d="M8 14h.01"></path> <path d="M12 18h.01"></path> <path d="M8 18h.01"></path> </g></svg>
|
||||
<svg
|
||||
class="w-8 h-8"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="#ffffff"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
|
||||
<g
|
||||
id="SVGRepo_tracerCarrier"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
></g>
|
||||
<g id="SVGRepo_iconCarrier">
|
||||
<rect x="4" y="2" width="16" height="20" rx="2"></rect>
|
||||
<line x1="8" x2="16" y1="6" y2="6"></line>
|
||||
<line x1="16" x2="16" y1="14" y2="18"></line>
|
||||
<path d="M16 10h.01"></path>
|
||||
<path d="M12 10h.01"></path>
|
||||
<path d="M8 10h.01"></path>
|
||||
<path d="M12 14h.01"></path>
|
||||
<path d="M8 14h.01"></path>
|
||||
<path d="M12 18h.01"></path>
|
||||
<path d="M8 18h.01"></path>
|
||||
</g>
|
||||
</svg>
|
||||
</label>
|
||||
<!-- Put this part before </body> tag -->
|
||||
<input type="checkbox" id="calculator" class="modal-toggle" />
|
||||
<div class="modal">
|
||||
<div class="modal-box">
|
||||
<h3 class="text-lg font-bold">{{ $t('index.price_calculator') }}</h3>
|
||||
<h3 class="text-lg font-bold">
|
||||
{{ $t('index.price_calculator') }}
|
||||
</h3>
|
||||
<div class="flex flex-col w-full mt-5">
|
||||
<div class="grid h-20 flex-grow card rounded-box place-items-center">
|
||||
<div
|
||||
class="grid h-20 flex-grow card rounded-box place-items-center"
|
||||
>
|
||||
<div class="join w-full">
|
||||
<label class="join-item btn">
|
||||
<span class="uppercase">{{ coinInfo.symbol }}</span>
|
||||
</label>
|
||||
<input type="number" v-model="qty" min="0" placeholder="Input a number" class="input grow input-bordered join-item" />
|
||||
<input
|
||||
type="number"
|
||||
v-model="qty"
|
||||
min="0"
|
||||
placeholder="Input a number"
|
||||
class="input grow input-bordered join-item"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="divider">=</div>
|
||||
<div class="grid h-20 flex-grow card rounded-box place-items-center">
|
||||
<div
|
||||
class="grid h-20 flex-grow card rounded-box place-items-center"
|
||||
>
|
||||
<div class="join w-full">
|
||||
<label class="join-item btn">
|
||||
<span>USD</span>
|
||||
</label>
|
||||
<input type="number" v-model="amount" min="0" placeholder="Input amount" class="join-item grow input input-bordered" />
|
||||
<input
|
||||
type="number"
|
||||
v-model="amount"
|
||||
min="0"
|
||||
placeholder="Input amount"
|
||||
class="join-item grow input input-bordered"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<label class="modal-backdrop" for="calculator">{{ $t('index.close') }}</label>
|
||||
<label class="modal-backdrop" for="calculator">{{
|
||||
$t('index.close')
|
||||
}}</label>
|
||||
</div>
|
||||
<a class="my-5 !text-white btn grow" :class="{'!btn-success': store.trustColor === 'green', '!btn-warning': store.trustColor === 'yellow'}" :href="ticker.trade_url"
|
||||
target="_blank">
|
||||
<a
|
||||
class="my-5 !text-white btn grow"
|
||||
:class="{
|
||||
'!btn-success': store.trustColor === 'green',
|
||||
'!btn-warning': store.trustColor === 'yellow',
|
||||
}"
|
||||
:href="ticker.trade_url"
|
||||
target="_blank"
|
||||
>
|
||||
{{ $t('index.buy') }} {{ coinInfo.symbol || '' }}
|
||||
</a>
|
||||
</div>
|
||||
@ -246,11 +324,16 @@ const amount = computed({
|
||||
</div>
|
||||
<div class="h-[1px] w-full bg-gray-100 dark:bg-[#384059]"></div>
|
||||
<div class="max-h-[250px] overflow-auto p-4 text-sm">
|
||||
<MdEditor :model-value="coinInfo.description?.en" previewOnly></MdEditor>
|
||||
<MdEditor
|
||||
:model-value="coinInfo.description?.en"
|
||||
previewOnly
|
||||
></MdEditor>
|
||||
</div>
|
||||
<div class="mx-4 flex flex-wrap items-center">
|
||||
<div v-for="tag in coinInfo.categories"
|
||||
class="mr-2 mb-4 text-xs bg-gray-100 dark:bg-[#384059] px-3 rounded-full py-1">
|
||||
<div
|
||||
v-for="tag in coinInfo.categories"
|
||||
class="mr-2 mb-4 text-xs bg-gray-100 dark:bg-[#384059] px-3 rounded-full py-1"
|
||||
>
|
||||
{{ tag }}
|
||||
</div>
|
||||
</div>
|
||||
@ -262,26 +345,41 @@ const amount = computed({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="blockchain.supportModule('governance')" class="bg-base-100 rounded mt-4 shadow">
|
||||
<div
|
||||
v-if="blockchain.supportModule('governance')"
|
||||
class="bg-base-100 rounded mt-4 shadow"
|
||||
>
|
||||
<div class="px-4 pt-4 pb-2 text-lg font-semibold text-main">
|
||||
{{ $t('index.active_proposals') }}
|
||||
</div>
|
||||
<div class="px-4 pb-4">
|
||||
<ProposalListItem :proposals="store?.proposals" />
|
||||
</div>
|
||||
<div class="pb-8 text-center" v-if="store.proposals?.proposals?.length === 0">
|
||||
<div
|
||||
class="pb-8 text-center"
|
||||
v-if="store.proposals?.proposals?.length === 0"
|
||||
>
|
||||
{{ $t('index.no_active_proposals') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-base-100 rounded mt-4 shadow">
|
||||
<div class="flex justify-between px-4 pt-4 pb-2 text-lg font-semibold text-main">
|
||||
<span class="truncate" >{{ walletStore.currentAddress || 'Not Connected' }}</span>
|
||||
<RouterLink v-if="walletStore.currentAddress"
|
||||
<div
|
||||
class="flex justify-between px-4 pt-4 pb-2 text-lg font-semibold text-main"
|
||||
>
|
||||
<span class="truncate">{{
|
||||
walletStore.currentAddress || 'Not Connected'
|
||||
}}</span>
|
||||
<RouterLink
|
||||
v-if="walletStore.currentAddress"
|
||||
class="float-right text-sm cursor-pointert link link-primary no-underline font-medium"
|
||||
:to="`/${chain}/account/${walletStore.currentAddress}`">{{ $t('index.more') }}</RouterLink>
|
||||
:to="`/${chain}/account/${walletStore.currentAddress}`"
|
||||
>{{ $t('index.more') }}</RouterLink
|
||||
>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 md:!grid-cols-4 auto-cols-auto gap-4 px-4 pb-6">
|
||||
<div
|
||||
class="grid grid-cols-1 md:!grid-cols-4 auto-cols-auto gap-4 px-4 pb-6"
|
||||
>
|
||||
<div class="bg-gray-100 dark:bg-[#373f59] rounded-sm px-4 py-3">
|
||||
<div class="text-sm mb-1">{{ $t('account.balance') }}</div>
|
||||
<div class="text-lg font-semibold text-main">
|
||||
@ -320,7 +418,10 @@ const amount = computed({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="walletStore.delegations.length > 0" class="px-4 pb-4 overflow-auto">
|
||||
<div
|
||||
v-if="walletStore.delegations.length > 0"
|
||||
class="px-4 pb-4 overflow-auto"
|
||||
>
|
||||
<table class="table table-compact w-full table-zebra">
|
||||
<thead>
|
||||
<tr>
|
||||
@ -333,12 +434,15 @@ const amount = computed({
|
||||
<tbody>
|
||||
<tr v-for="(item, index) in walletStore.delegations" :key="index">
|
||||
<td>
|
||||
<RouterLink class="link link-primary no-underline" :to="`/${chain}/staking/${item?.delegation?.validator_address}`">
|
||||
{{
|
||||
format.validatorFromBech32(
|
||||
item?.delegation?.validator_address
|
||||
)
|
||||
}}
|
||||
<RouterLink
|
||||
class="link link-primary no-underline"
|
||||
:to="`/${chain}/staking/${item?.delegation?.validatorAddress}`"
|
||||
>
|
||||
{{
|
||||
format.validatorFromBech32(
|
||||
item?.delegation?.validatorAddress
|
||||
)
|
||||
}}
|
||||
</RouterLink>
|
||||
</td>
|
||||
<td>{{ format.formatToken(item?.balance) }}</td>
|
||||
@ -347,19 +451,38 @@ const amount = computed({
|
||||
format.formatTokens(
|
||||
walletStore?.rewards?.rewards?.find(
|
||||
(el) =>
|
||||
el?.validator_address ===
|
||||
item?.delegation?.validator_address
|
||||
)?.reward)
|
||||
el?.validatorAddress ===
|
||||
item?.delegation?.validatorAddress
|
||||
)?.reward
|
||||
)
|
||||
}}
|
||||
</td>
|
||||
<td>
|
||||
<div>
|
||||
<label for="delegate" class="btn !btn-xs !btn-primary btn-ghost rounded-sm mr-2"
|
||||
@click="dialog.open('delegate', { validator_address: item.delegation.validator_address }, updateState)">
|
||||
<label
|
||||
for="delegate"
|
||||
class="btn !btn-xs !btn-primary btn-ghost rounded-sm mr-2"
|
||||
@click="
|
||||
dialog.open(
|
||||
'delegate',
|
||||
{ validator_address: item.delegation.validatorAddress },
|
||||
updateState
|
||||
)
|
||||
"
|
||||
>
|
||||
{{ $t('account.btn_delegate') }}
|
||||
</label>
|
||||
<label for="withdraw" class="btn !btn-xs !btn-primary btn-ghost rounded-sm"
|
||||
@click="dialog.open('withdraw', { validator_address: item.delegation.validator_address }, updateState)">
|
||||
<label
|
||||
for="withdraw"
|
||||
class="btn !btn-xs !btn-primary btn-ghost rounded-sm"
|
||||
@click="
|
||||
dialog.open(
|
||||
'withdraw',
|
||||
{ validator_address: item.delegation.validatorAddress },
|
||||
updateState
|
||||
)
|
||||
"
|
||||
>
|
||||
{{ $t('index.btn_withdraw_reward') }}
|
||||
</label>
|
||||
</div>
|
||||
@ -370,15 +493,33 @@ const amount = computed({
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-3 gap-4 px-4 pb-6 mt-4">
|
||||
<label for="PingTokenConvert" class="btn btn-primary text-white">{{ $t('index.btn_swap') }}</label>
|
||||
<label for="send" class="btn !bg-yes !border-yes text-white" @click="dialog.open('send', {}, updateState)">{{ $t('account.btn_send') }}</label>
|
||||
<label for="delegate" class="btn !bg-info !border-info text-white"
|
||||
@click="dialog.open('delegate', {}, updateState)">{{ $t('account.btn_delegate') }}</label>
|
||||
<RouterLink to="/wallet/receive" class="btn !bg-info !border-info text-white hidden">{{ $t('index.receive') }}</RouterLink>
|
||||
<label for="PingTokenConvert" class="btn btn-primary text-white">{{
|
||||
$t('index.btn_swap')
|
||||
}}</label>
|
||||
<label
|
||||
for="send"
|
||||
class="btn !bg-yes !border-yes text-white"
|
||||
@click="dialog.open('send', {}, updateState)"
|
||||
>{{ $t('account.btn_send') }}</label
|
||||
>
|
||||
<label
|
||||
for="delegate"
|
||||
class="btn !bg-info !border-info text-white"
|
||||
@click="dialog.open('delegate', {}, updateState)"
|
||||
>{{ $t('account.btn_delegate') }}</label
|
||||
>
|
||||
<RouterLink
|
||||
to="/wallet/receive"
|
||||
class="btn !bg-info !border-info text-white hidden"
|
||||
>{{ $t('index.receive') }}</RouterLink
|
||||
>
|
||||
</div>
|
||||
<Teleport to="body">
|
||||
<ping-token-convert :chain-name="blockchain?.current?.prettyName" :endpoint="blockchain?.endpoint?.address"
|
||||
:hd-path="walletStore?.connectedWallet?.hdPath"></ping-token-convert>
|
||||
<ping-token-convert
|
||||
:chain-name="blockchain?.current?.prettyName"
|
||||
:endpoint="blockchain?.endpoint?.address"
|
||||
:hd-path="walletStore?.connectedWallet?.hdPath"
|
||||
></ping-token-convert>
|
||||
</Teleport>
|
||||
</div>
|
||||
|
||||
@ -387,7 +528,10 @@ const amount = computed({
|
||||
{{ $t('index.app_versions') }}
|
||||
</div>
|
||||
<!-- Application Version -->
|
||||
<ArrayObjectElement :value="paramStore.appVersion?.items" :thead="false" />
|
||||
<ArrayObjectElement
|
||||
:value="paramStore.appVersion?.items"
|
||||
:thead="false"
|
||||
/>
|
||||
<div class="h-4"></div>
|
||||
</div>
|
||||
|
||||
@ -395,7 +539,10 @@ const amount = computed({
|
||||
<div class="px-4 pt-4 pb-2 text-lg font-semibold text-main">
|
||||
{{ $t('index.node_info') }}
|
||||
</div>
|
||||
<ArrayObjectElement :value="paramStore.nodeVersion?.items" :thead="false" />
|
||||
<ArrayObjectElement
|
||||
:value="paramStore.nodeVersion?.items"
|
||||
:thead="false"
|
||||
/>
|
||||
<div class="h-4"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -519,7 +519,7 @@ function mapDelegators(messages: any[]) {
|
||||
.startsWith('1970')
|
||||
"
|
||||
>
|
||||
{{ format.toDay(fromTimestamp(v.unbondingTime), 'from') }}
|
||||
{{ format.toDay(v.unbondingTime, 'from') }}
|
||||
</h4>
|
||||
<h4 v-else>-</h4>
|
||||
<span class="text-sm">{{ $t('staking.unbonding_time') }}</span>
|
||||
|
||||
@ -11,9 +11,13 @@ import { useStakingStore } from './useStakingStore';
|
||||
import { fromBase64, fromBech32, fromHex, toHex } from '@cosmjs/encoding';
|
||||
import { consensusPubkeyToHexAddress, get } from '@/libs';
|
||||
import { useBankStore } from './useBankStore';
|
||||
import type { Coin, DenomTrace } from '@/types';
|
||||
// import type { Coin, DenomTrace } from '@/types';
|
||||
import { useDashboard } from './useDashboard';
|
||||
import type { Asset } from '@ping-pub/chain-registry-client/dist/types'
|
||||
import type { Asset } from '@ping-pub/chain-registry-client/dist/types';
|
||||
import type { DenomTrace } from 'cosmjs-types/ibc/applications/transfer/v1/transfer';
|
||||
import type { Coin } from '@cosmjs/stargate';
|
||||
import type { Timestamp } from 'cosmjs-types/google/protobuf/timestamp';
|
||||
import { fromTimestamp } from 'cosmjs-types/helpers';
|
||||
|
||||
dayjs.extend(localeData);
|
||||
dayjs.extend(duration);
|
||||
@ -66,39 +70,41 @@ export const useFormatter = defineStore('formatter', {
|
||||
let trace = this.ibcDenoms[hash];
|
||||
if (!trace) {
|
||||
trace = (await this.blockchain.rpc.getIBCAppTransferDenom(hash))
|
||||
.denom_trace;
|
||||
.denomTrace!;
|
||||
this.ibcDenoms[hash] = trace;
|
||||
}
|
||||
return trace;
|
||||
},
|
||||
async fetchDenomMetadata(denom: string) {
|
||||
if(this.loading.includes(denom)) return
|
||||
this.loading.push(denom)
|
||||
const asset = await get(`https://metadata.ping.pub/metadata/${denom}`) as Asset
|
||||
this.ibcMetadata[denom] = asset
|
||||
if (this.loading.includes(denom)) return;
|
||||
this.loading.push(denom);
|
||||
const asset = (await get(
|
||||
`https://metadata.ping.pub/metadata/${denom}`
|
||||
)) as Asset;
|
||||
this.ibcMetadata[denom] = asset;
|
||||
},
|
||||
priceInfo(denom: string) {
|
||||
const id = this.dashboard.coingecko[denom]?.coinId || "";
|
||||
const id = this.dashboard.coingecko[denom]?.coinId || '';
|
||||
const prices = this.dashboard.prices[id];
|
||||
return prices;
|
||||
},
|
||||
color(change?: number) {
|
||||
if(!change) return ""
|
||||
if (!change) return '';
|
||||
switch (true) {
|
||||
case change > 0:
|
||||
return "text-success"
|
||||
return 'text-success';
|
||||
case change < 0:
|
||||
return "text-error"
|
||||
return 'text-error';
|
||||
default:
|
||||
return ""
|
||||
return '';
|
||||
}
|
||||
},
|
||||
priceColor(denom: string, currency = "usd") {
|
||||
const change = this.priceChanges(denom, currency)
|
||||
return this.color(change)
|
||||
priceColor(denom: string, currency = 'usd') {
|
||||
const change = this.priceChanges(denom, currency);
|
||||
return this.color(change);
|
||||
},
|
||||
price(denom: string, currency = "usd") {
|
||||
if(!denom || denom.length < 2) return 0
|
||||
price(denom: string, currency = 'usd') {
|
||||
if (!denom || denom.length < 2) return 0;
|
||||
const info = this.priceInfo(denom);
|
||||
return info ? info[currency] || 0 : 0;
|
||||
},
|
||||
@ -107,33 +113,38 @@ export const useFormatter = defineStore('formatter', {
|
||||
return info ? info[`${currency}_24h_change`] || 0 : 0;
|
||||
},
|
||||
showChanges(v?: number) {
|
||||
return v!==0 ? numeral(v).format("+0,0.[00]"): ""
|
||||
return v !== 0 ? numeral(v).format('+0,0.[00]') : '';
|
||||
},
|
||||
tokenValue(token?: Coin) {
|
||||
if(token) {
|
||||
return numeral(this.tokenValueNumber(token)).format("0,0.[00]")
|
||||
if (token) {
|
||||
return numeral(this.tokenValueNumber(token)).format('0,0.[00]');
|
||||
}
|
||||
return ""
|
||||
return '';
|
||||
},
|
||||
specialDenom(denom: string) {
|
||||
switch(true) {
|
||||
case denom.startsWith('u'): return 6
|
||||
case denom.startsWith("a"): return 18
|
||||
case denom==='inj': return 18
|
||||
switch (true) {
|
||||
case denom.startsWith('u'):
|
||||
return 6;
|
||||
case denom.startsWith('a'):
|
||||
return 18;
|
||||
case denom === 'inj':
|
||||
return 18;
|
||||
}
|
||||
return 0
|
||||
return 0;
|
||||
},
|
||||
tokenValueNumber(token?: Coin) {
|
||||
if(!token || !token.denom) return 0
|
||||
// find the symbol,
|
||||
const symbol = this.dashboard.coingecko[token.denom]?.symbol || token.denom
|
||||
if (!token || !token.denom) return 0;
|
||||
// find the symbol,
|
||||
const symbol =
|
||||
this.dashboard.coingecko[token.denom]?.symbol || token.denom;
|
||||
// convert denomation to to symbol
|
||||
const exponent =
|
||||
this.dashboard.coingecko[symbol?.toLowerCase()]?.exponent || this.specialDenom(token.denom);
|
||||
this.dashboard.coingecko[symbol?.toLowerCase()]?.exponent ||
|
||||
this.specialDenom(token.denom);
|
||||
// cacualte amount of symbol
|
||||
const amount = Number(token.amount) / (10 ** exponent)
|
||||
const value = amount * this.price(token.denom)
|
||||
return value
|
||||
const amount = Number(token.amount) / 10 ** exponent;
|
||||
const value = amount * this.price(token.denom);
|
||||
return value;
|
||||
},
|
||||
formatTokenAmount(token: { denom: string; amount: string }) {
|
||||
return this.formatToken(token, false);
|
||||
@ -141,34 +152,33 @@ export const useFormatter = defineStore('formatter', {
|
||||
formatToken2(token: { denom: string; amount: string }, withDenom = true) {
|
||||
return this.formatToken(token, true, '0,0.[00]');
|
||||
},
|
||||
|
||||
|
||||
findGlobalAssetConfig(denom: string) {
|
||||
const chains = Object.values(this.dashboard.chains)
|
||||
for ( let i =0; i < chains.length; i++ ) {
|
||||
const assets = chains[i].assets
|
||||
const conf = assets.find(a => a.base === denom)
|
||||
if(conf) {
|
||||
return conf
|
||||
const chains = Object.values(this.dashboard.chains);
|
||||
for (let i = 0; i < chains.length; i++) {
|
||||
const assets = chains[i].assets;
|
||||
const conf = assets.find((a) => a.base === denom);
|
||||
if (conf) {
|
||||
return conf;
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
return undefined;
|
||||
},
|
||||
|
||||
tokenDisplayDenom(denom?: string) {
|
||||
if (denom) {
|
||||
let asset: Asset | undefined;
|
||||
if (denom && denom.startsWith('ibc/')) {
|
||||
const ibcDenom = denom.replace('ibc/', '')
|
||||
asset = this.ibcMetadata[ibcDenom];
|
||||
if(!asset) {
|
||||
const ibcDenom = denom.replace('ibc/', '');
|
||||
asset = this.ibcMetadata[ibcDenom];
|
||||
if (!asset) {
|
||||
// update ibc metadata if not exits in local cache
|
||||
this.fetchDenomMetadata(ibcDenom)
|
||||
this.fetchDenomMetadata(ibcDenom);
|
||||
} else {
|
||||
console.log("ibc metadata", asset)
|
||||
console.log('ibc metadata', asset);
|
||||
}
|
||||
|
||||
} else {
|
||||
asset = this.findGlobalAssetConfig(denom)
|
||||
asset = this.findGlobalAssetConfig(denom);
|
||||
}
|
||||
|
||||
if (asset) {
|
||||
@ -178,7 +188,7 @@ export const useFormatter = defineStore('formatter', {
|
||||
if (x.exponent >= unit.exponent) {
|
||||
unit = x;
|
||||
}
|
||||
});
|
||||
});
|
||||
return unit.denom;
|
||||
}
|
||||
return denom;
|
||||
@ -192,15 +202,18 @@ export const useFormatter = defineStore('formatter', {
|
||||
let amount = Number(token.amount);
|
||||
let denom = token.denom;
|
||||
|
||||
let conf = mode === 'local'? this.blockchain.current?.assets?.find(
|
||||
// @ts-ignore
|
||||
(x) => x.base === token.denom || x.base.denom === token.denom
|
||||
): this.findGlobalAssetConfig(token.denom)
|
||||
let conf =
|
||||
mode === 'local'
|
||||
? this.blockchain.current?.assets?.find(
|
||||
// @ts-ignore
|
||||
(x) => x.base === token.denom || x.base.denom === token.denom
|
||||
)
|
||||
: this.findGlobalAssetConfig(token.denom);
|
||||
|
||||
if (denom && denom.startsWith('ibc/')) {
|
||||
conf = this.ibcMetadata[denom.replace('ibc/', '')];
|
||||
if (!conf) {
|
||||
this.fetchDenomMetadata(denom.replace('ibc/', ''))
|
||||
this.fetchDenomMetadata(denom.replace('ibc/', ''));
|
||||
}
|
||||
}
|
||||
|
||||
@ -230,15 +243,18 @@ export const useFormatter = defineStore('formatter', {
|
||||
let amount = Number(token.amount);
|
||||
let denom = token.denom;
|
||||
|
||||
let conf = mode === 'local'? this.blockchain.current?.assets?.find(
|
||||
// @ts-ignore
|
||||
(x) => x.base === token.denom || x.base.denom === token.denom
|
||||
): this.findGlobalAssetConfig(token.denom)
|
||||
let conf =
|
||||
mode === 'local'
|
||||
? this.blockchain.current?.assets?.find(
|
||||
// @ts-ignore
|
||||
(x) => x.base === token.denom || x.base.denom === token.denom
|
||||
)
|
||||
: this.findGlobalAssetConfig(token.denom);
|
||||
|
||||
if (denom && denom.startsWith('ibc/')) {
|
||||
conf = this.ibcMetadata[denom.replace('ibc/', '')];
|
||||
if (!conf) {
|
||||
this.fetchDenomMetadata(denom.replace('ibc/', ''))
|
||||
this.fetchDenomMetadata(denom.replace('ibc/', ''));
|
||||
}
|
||||
}
|
||||
|
||||
@ -255,11 +271,11 @@ export const useFormatter = defineStore('formatter', {
|
||||
denom = unit.denom.toUpperCase();
|
||||
}
|
||||
}
|
||||
if(amount < 0.000001) {
|
||||
if (amount < 0.000001) {
|
||||
return `0 ${denom.substring(0, 10)}`;
|
||||
}
|
||||
if(amount < 0.01) {
|
||||
fmt = '0.[000000]'
|
||||
if (amount < 0.01) {
|
||||
fmt = '0.[000000]';
|
||||
}
|
||||
return `${numeral(amount).format(fmt)} ${
|
||||
withDenom ? denom.substring(0, 10) : ''
|
||||
@ -291,7 +307,7 @@ export const useFormatter = defineStore('formatter', {
|
||||
|
||||
const txt = toHex(fromBase64(address)).toUpperCase();
|
||||
const validator = this.staking.validators.find(
|
||||
(x) => consensusPubkeyToHexAddress(x.consensus_pubkey) === txt
|
||||
(x) => consensusPubkeyToHexAddress(x.consensusPubkey) === txt
|
||||
);
|
||||
return validator?.description?.moniker;
|
||||
},
|
||||
@ -299,7 +315,7 @@ export const useFormatter = defineStore('formatter', {
|
||||
validatorFromBech32(address: string) {
|
||||
if (!address) return address;
|
||||
const validator = this.staking.validators.find(
|
||||
(x) => x.operator_address === address
|
||||
(x) => x.operatorAddress === address
|
||||
);
|
||||
return validator?.description?.moniker;
|
||||
},
|
||||
@ -319,34 +335,39 @@ export const useFormatter = defineStore('formatter', {
|
||||
return decimal ? numeral(decimal).format('0.[00]%') : '-';
|
||||
},
|
||||
formatNumber(input?: number, fmt = '0.[00]') {
|
||||
if(!input) return ""
|
||||
return numeral(input).format(fmt)
|
||||
if (!input) return '';
|
||||
return numeral(input).format(fmt);
|
||||
},
|
||||
numberAndSign(input: number, fmt = '+0,0') {
|
||||
return numeral(input).format(fmt);
|
||||
},
|
||||
toLocaleDate(time?: string | number | Date) {
|
||||
if(!time) return ""
|
||||
return new Date(time).toLocaleString(navigator.language)
|
||||
},
|
||||
toDay(time?: string | number| Date, format = 'long') {
|
||||
if (!time) return '';
|
||||
return new Date(time).toLocaleString(navigator.language);
|
||||
},
|
||||
toDay(time?: string | number | Date | Timestamp, format = 'long') {
|
||||
if (!time) return '';
|
||||
const timeValue =
|
||||
typeof time === 'object' && 'seconds' in time
|
||||
? fromTimestamp(time)
|
||||
: time;
|
||||
|
||||
if (format === 'long') {
|
||||
return dayjs(time).format('YYYY-MM-DD HH:mm');
|
||||
return dayjs(timeValue).format('YYYY-MM-DD HH:mm');
|
||||
}
|
||||
if (format === 'date') {
|
||||
return dayjs(time).format('YYYY-MM-DD');
|
||||
return dayjs(timeValue).format('YYYY-MM-DD');
|
||||
}
|
||||
if (format === 'time') {
|
||||
return dayjs(time).format('HH:mm:ss');
|
||||
return dayjs(timeValue).format('HH:mm:ss');
|
||||
}
|
||||
if (format === 'from') {
|
||||
return dayjs(time).fromNow();
|
||||
return dayjs(timeValue).fromNow();
|
||||
}
|
||||
if (format === 'to') {
|
||||
return dayjs(time).toNow();
|
||||
return dayjs(timeValue).toNow();
|
||||
}
|
||||
return dayjs(time).format('YYYY-MM-DD HH:mm:ss');
|
||||
return dayjs(timeValue).format('YYYY-MM-DD HH:mm:ss');
|
||||
},
|
||||
messages(msgs: { '@type'?: string; typeUrl?: string }[]) {
|
||||
if (msgs) {
|
||||
|
||||
@ -11,6 +11,7 @@ import {
|
||||
TextProposal,
|
||||
} from 'cosmjs-types/cosmos/gov/v1beta1/gov';
|
||||
import type { QueryProposalsResponse } from 'cosmjs-types/cosmos/gov/v1beta1/query';
|
||||
import type { GovProposalId } from '@cosmjs/stargate';
|
||||
|
||||
export const useGovStore = defineStore('govStore', {
|
||||
state: () => {
|
||||
@ -105,7 +106,7 @@ export const useGovStore = defineStore('govStore', {
|
||||
async fetchProposalDeposits(proposalId: string) {
|
||||
return await this.blockchain.rpc.getGovProposalDeposits(proposalId);
|
||||
},
|
||||
async fetchProposalVotes(proposalId: string, page?: PageRequest) {
|
||||
async fetchProposalVotes(proposalId: GovProposalId, page?: PageRequest) {
|
||||
return await this.blockchain.rpc.getGovProposalVotes(proposalId, page);
|
||||
},
|
||||
async fetchProposalVotesVoter(proposalId: string, voter: string) {
|
||||
|
||||
@ -3,22 +3,30 @@ import { useBlockchain } from './useBlockchain';
|
||||
import { fromBech32, toBech32 } from '@cosmjs/encoding';
|
||||
import type {
|
||||
Delegation,
|
||||
Coin,
|
||||
UnbondingResponses,
|
||||
DelegatorRewards,
|
||||
WalletConnected,
|
||||
} from '@/types';
|
||||
import { useStakingStore } from './useStakingStore';
|
||||
import router from '@/router'
|
||||
import router from '@/router';
|
||||
import type {
|
||||
DelegationResponse,
|
||||
UnbondingDelegation,
|
||||
} from 'cosmjs-types/cosmos/staking/v1beta1/staking';
|
||||
import type { Coin } from 'cosmjs-types/cosmos/base/v1beta1/coin';
|
||||
import type {
|
||||
QueryDelegationTotalRewardsRequest,
|
||||
QueryDelegationTotalRewardsResponse,
|
||||
} from 'cosmjs-types/cosmos/distribution/v1beta1/query';
|
||||
|
||||
export const useWalletStore = defineStore('walletStore', {
|
||||
state: () => {
|
||||
return {
|
||||
balances: [] as Coin[],
|
||||
delegations: [] as Delegation[],
|
||||
unbonding: [] as UnbondingResponses[],
|
||||
rewards: {total: [], rewards: []} as DelegatorRewards,
|
||||
wallet: {} as WalletConnected
|
||||
delegations: [] as DelegationResponse[],
|
||||
unbonding: [] as UnbondingDelegation[],
|
||||
rewards: {} as QueryDelegationTotalRewardsResponse,
|
||||
wallet: {} as WalletConnected,
|
||||
};
|
||||
},
|
||||
getters: {
|
||||
@ -27,24 +35,24 @@ export const useWalletStore = defineStore('walletStore', {
|
||||
},
|
||||
connectedWallet() {
|
||||
// @ts-ignore
|
||||
if(this.wallet.cosmosAddress) return this.wallet
|
||||
if (this.wallet.cosmosAddress) return this.wallet;
|
||||
const chainStore = useBlockchain();
|
||||
const key = chainStore.defaultHDPath;
|
||||
const connected = JSON.parse(localStorage.getItem(key) || '{}');
|
||||
return connected
|
||||
return connected;
|
||||
},
|
||||
balanceOfStakingToken(): Coin {
|
||||
const stakingStore = useStakingStore();
|
||||
return (
|
||||
this.balances.find(
|
||||
(x) => x.denom === stakingStore.params.bond_denom
|
||||
) || { amount: '0', denom: stakingStore.params.bond_denom }
|
||||
(x) => x.denom === stakingStore.params.bondDenom
|
||||
) || { amount: '0', denom: stakingStore.params.bondDenom }
|
||||
);
|
||||
},
|
||||
stakingAmount() {
|
||||
const stakingStore = useStakingStore();
|
||||
let amt = 0;
|
||||
let denom = stakingStore.params.bond_denom;
|
||||
let denom = stakingStore.params.bondDenom;
|
||||
this.delegations.forEach((i) => {
|
||||
amt += Number(i.balance.amount);
|
||||
denom = i.balance.denom;
|
||||
@ -55,20 +63,20 @@ export const useWalletStore = defineStore('walletStore', {
|
||||
const stakingStore = useStakingStore();
|
||||
// @ts-ignore
|
||||
const reward = this.rewards.total?.find(
|
||||
(x: Coin) => x.denom === stakingStore.params.bond_denom
|
||||
(x: Coin) => x.denom === stakingStore.params.bondDenom
|
||||
);
|
||||
return reward || { amount: '0', denom: stakingStore.params.bond_denom };
|
||||
return reward || { amount: '0', denom: stakingStore.params.bondDenom };
|
||||
},
|
||||
unbondingAmount() {
|
||||
let amt = 0;
|
||||
this.unbonding.forEach((i) => {
|
||||
this.unbonding?.forEach((i) => {
|
||||
i.entries.forEach((e) => {
|
||||
amt += Number(e.balance);
|
||||
});
|
||||
});
|
||||
|
||||
const stakingStore = useStakingStore();
|
||||
return { amount: String(amt), denom: stakingStore.params.bond_denom };
|
||||
return { amount: String(amt), denom: stakingStore.params.bondDenom };
|
||||
},
|
||||
currentAddress() {
|
||||
if (!this.connectedWallet?.cosmosAddress) return '';
|
||||
@ -77,29 +85,28 @@ export const useWalletStore = defineStore('walletStore', {
|
||||
return toBech32(chainStore.current?.bech32Prefix || prefix, data);
|
||||
},
|
||||
shortAddress() {
|
||||
const address: string = this.currentAddress
|
||||
if(address.length > 4) {
|
||||
return `${address.substring(address.length -4)}`
|
||||
const address: string = this.currentAddress;
|
||||
if (address.length > 4) {
|
||||
return `${address.substring(address.length - 4)}`;
|
||||
}
|
||||
return ""
|
||||
}
|
||||
return '';
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
|
||||
async loadMyAsset() {
|
||||
if (!this.currentAddress) return;
|
||||
this.blockchain.rpc.getBankBalances(this.currentAddress).then((x) => {
|
||||
this.balances = x.balances;
|
||||
this.balances = x;
|
||||
});
|
||||
this.blockchain.rpc
|
||||
.getStakingDelegations(this.currentAddress)
|
||||
.then((x) => {
|
||||
this.delegations = x.delegation_responses;
|
||||
this.delegations = x.delegationResponses;
|
||||
});
|
||||
this.blockchain.rpc
|
||||
.getStakingDelegatorUnbonding(this.currentAddress)
|
||||
.then((x) => {
|
||||
this.unbonding = x.unbonding_responses;
|
||||
this.unbonding = x.unbondingResponses;
|
||||
});
|
||||
this.blockchain.rpc
|
||||
.getDistributionDelegatorRewards(this.currentAddress)
|
||||
@ -122,14 +129,14 @@ export const useWalletStore = defineStore('walletStore', {
|
||||
const chainStore = useBlockchain();
|
||||
const key = chainStore.defaultHDPath;
|
||||
localStorage.removeItem(key);
|
||||
this.$reset()
|
||||
this.$reset();
|
||||
},
|
||||
setConnectedWallet(value: WalletConnected) {
|
||||
if(value) this.wallet = value
|
||||
if (value) this.wallet = value;
|
||||
},
|
||||
suggestChain() {
|
||||
// const router = useRouter()
|
||||
router.push({path: '/wallet/keplr'})
|
||||
}
|
||||
router.push({ path: '/wallet/keplr' });
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
28
yarn.lock
28
yarn.lock
@ -3360,31 +3360,7 @@ core-util-is@~1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85"
|
||||
integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==
|
||||
|
||||
cosmjs-types@^0.5.2:
|
||||
version "0.5.2"
|
||||
resolved "https://registry.yarnpkg.com/cosmjs-types/-/cosmjs-types-0.5.2.tgz#2d42b354946f330dfb5c90a87fdc2a36f97b965d"
|
||||
integrity sha512-zxCtIJj8v3Di7s39uN4LNcN3HIE1z0B9Z0SPE8ZNQR0oSzsuSe1ACgxoFkvhkS7WBasCAFcglS11G2hyfd5tPg==
|
||||
dependencies:
|
||||
long "^4.0.0"
|
||||
protobufjs "~6.11.2"
|
||||
|
||||
cosmjs-types@^0.7.1:
|
||||
version "0.7.2"
|
||||
resolved "https://registry.yarnpkg.com/cosmjs-types/-/cosmjs-types-0.7.2.tgz#a757371abd340949c5bd5d49c6f8379ae1ffd7e2"
|
||||
integrity sha512-vf2uLyktjr/XVAgEq0DjMxeAWh1yYREe7AMHDKd7EiHVqxBPCaBS+qEEQUkXbR9ndnckqr1sUG8BQhazh4X5lA==
|
||||
dependencies:
|
||||
long "^4.0.0"
|
||||
protobufjs "~6.11.2"
|
||||
|
||||
cosmjs-types@^0.8.0:
|
||||
version "0.8.0"
|
||||
resolved "https://registry.yarnpkg.com/cosmjs-types/-/cosmjs-types-0.8.0.tgz#2ed78f3e990f770229726f95f3ef5bf9e2b6859b"
|
||||
integrity sha512-Q2Mj95Fl0PYMWEhA2LuGEIhipF7mQwd9gTQ85DdP9jjjopeoGaDxvmPa5nakNzsq7FnO1DMTatXTAx6bxMH7Lg==
|
||||
dependencies:
|
||||
long "^4.0.0"
|
||||
protobufjs "~6.11.2"
|
||||
|
||||
cosmjs-types@^0.9.0:
|
||||
cosmjs-types@^0.5.2, cosmjs-types@^0.7.1, cosmjs-types@^0.8.0, cosmjs-types@^0.9.0:
|
||||
version "0.9.0"
|
||||
resolved "https://registry.yarnpkg.com/cosmjs-types/-/cosmjs-types-0.9.0.tgz#c3bc482d28c7dfa25d1445093fdb2d9da1f6cfcc"
|
||||
integrity sha512-MN/yUe6mkJwHnCFfsNPeCfXVhyxHYW6c/xDUzrSbBycYzw++XvWDMJArXp2pLdgD6FQ8DW79vkPjeNKVrXaHeQ==
|
||||
@ -5832,7 +5808,7 @@ promised-io@*:
|
||||
resolved "https://registry.yarnpkg.com/promised-io/-/promised-io-0.3.6.tgz#04c0fea80772f7091dca0f114e30b3e3f7650126"
|
||||
integrity sha512-bNwZusuNIW4m0SPR8jooSyndD35ggirHlxVl/UhIaZD/F0OBv9ebfc6tNmbpZts3QXHggkjIBH8lvtnzhtcz0A==
|
||||
|
||||
protobufjs@^6.11.3, protobufjs@^6.8.8, protobufjs@~6.11.2, protobufjs@~6.11.3:
|
||||
protobufjs@^6.11.3, protobufjs@^6.8.8, protobufjs@~6.11.3:
|
||||
version "6.11.4"
|
||||
resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.11.4.tgz#29a412c38bf70d89e537b6d02d904a6f448173aa"
|
||||
integrity sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw==
|
||||
|
||||
Loading…
Reference in New Issue
Block a user