add power event
This commit is contained in:
parent
6cccb25964
commit
0e57913204
@ -14,6 +14,22 @@ export const percent = (num: number) => {
|
||||
return parseFloat((num * 100).toFixed(2));
|
||||
};
|
||||
|
||||
export function stringToUint8Array(str: string) {
|
||||
const arr = [];
|
||||
for (let i = 0, j = str.length; i < j; ++i) {
|
||||
arr.push(str.charCodeAt(i));
|
||||
}
|
||||
return new Uint8Array(arr);
|
||||
}
|
||||
|
||||
export function uint8ArrayToString(arr: Uint8Array) {
|
||||
let str = '';
|
||||
for (let i = 0, j = arr.length; i < j; ++i) {
|
||||
str += String.fromCharCode(arr[i]);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
const COUNT_ABBRS = [
|
||||
'',
|
||||
'K',
|
||||
|
@ -17,6 +17,8 @@ import {
|
||||
} from '@/libs';
|
||||
import { PageRequest, type Coin, type Delegation, type PaginatedDelegations, type PaginatedTxs, type Validator } from '@/types';
|
||||
import PaginationBar from '@/components/PaginationBar.vue';
|
||||
import { fromBase64, toBase64 } from '@cosmjs/encoding';
|
||||
import { stringToUint8Array, uint8ArrayToString } from '@/libs/utils';
|
||||
|
||||
const props = defineProps(['validator', 'chain']);
|
||||
|
||||
@ -189,10 +191,56 @@ const tipMsg = computed(() => {
|
||||
|
||||
function pageload(p: number) {
|
||||
page.setPage(p);
|
||||
page.limit = 10;
|
||||
|
||||
blockchain.rpc.getStakingValidatorsDelegations(validator, page).then(res => {
|
||||
delegations.value = res
|
||||
})
|
||||
}
|
||||
|
||||
const events = ref({} as PaginatedTxs)
|
||||
|
||||
enum EventType {
|
||||
Delegate = 'delegate',
|
||||
Unbond = 'unbond',
|
||||
}
|
||||
|
||||
const selectedEventType = ref(EventType.Unbond)
|
||||
|
||||
function loadPowerEvents(p: number, type: EventType) {
|
||||
selectedEventType.value = type
|
||||
page.setPage(p);
|
||||
page.setPageSize(5);
|
||||
blockchain.rpc.getTxs("?order_by=2&events={type}.validator='{validator}'", { type: selectedEventType.value, validator }, page).then(res => {
|
||||
events.value = res
|
||||
})
|
||||
}
|
||||
|
||||
function pagePowerEvents(page: number) {
|
||||
loadPowerEvents(page, selectedEventType.value)
|
||||
}
|
||||
|
||||
|
||||
function mapEvents(events: {type: string, attributes: {key: string, value: string}[]}[]) {
|
||||
const attributes = events.filter(x => x.type=== selectedEventType.value).filter(x => x.attributes.findIndex(attr => attr.value === toBase64(stringToUint8Array(validator))) > -1).map(x => {
|
||||
// check if attributes need to decode
|
||||
if(x.attributes.findIndex(a => a.value === `amount` || a.value === 'delegator_address') > -1) return x.attributes
|
||||
const output = {} as {[key: string]: string }
|
||||
x.attributes.forEach(attr => {
|
||||
output[uint8ArrayToString(fromBase64(attr.key))] = uint8ArrayToString(fromBase64(attr.value))
|
||||
})
|
||||
return output
|
||||
})
|
||||
|
||||
return attributes
|
||||
|
||||
}
|
||||
|
||||
function mapDelegators(messages: any[]) {
|
||||
if(!messages) return []
|
||||
return Array.from(new Set(messages.map(x => x.delegator_address || x.grantee)))
|
||||
}
|
||||
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
@ -582,6 +630,72 @@ function pageload(p: number) {
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-5 bg-base-100 shadow rounded p-4">
|
||||
<div class="text-lg mb-4 font-semibold">
|
||||
<div class="tabs tabs-boxed bg-transparent">
|
||||
|
||||
<span class="mr-10">Power Events: </span>
|
||||
<a
|
||||
class="tab text-gray-400"
|
||||
:class="{ 'tab-active': selectedEventType === EventType.Delegate }"
|
||||
@click="loadPowerEvents(1, EventType.Delegate)"
|
||||
>{{ $t('account.btn_delegate') }}</a
|
||||
>
|
||||
<a
|
||||
class="tab text-gray-400"
|
||||
:class="{ 'tab-active': selectedEventType === EventType.Unbond }"
|
||||
@click="loadPowerEvents(1, EventType.Unbond)"
|
||||
>{{ $t('account.btn_unbond') }}</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rounded overflow-auto">
|
||||
<table class="table validatore-table w-full">
|
||||
<thead>
|
||||
<th class="text-left pl-4">{{ $t('account.delegator') }}</th>
|
||||
<th class="text-left pl-4">{{ $t('account.amount') }}</th>
|
||||
<th class="text-left pl-4">{{ $t('account.height') }} / {{ $t('account.time') }}</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(item, i) in events.tx_responses">
|
||||
<td class="pr-2 text-primary" style="max-width: 250px">
|
||||
<RouterLink v-for="d in mapDelegators(item.tx?.body?.messages)" :to="`/${props.chain}/account/${d}`">
|
||||
{{ d }}
|
||||
</RouterLink>
|
||||
</td>
|
||||
<td>
|
||||
<div class="flex items-center" :class="{
|
||||
'text-yes' : selectedEventType === EventType.Delegate,
|
||||
'text-no' : selectedEventType === EventType.Unbond,
|
||||
}">
|
||||
<RouterLink :to="`/${props.chain}/tx/${item.txhash}`">
|
||||
<span class="mr-2">
|
||||
{{ (selectedEventType === EventType.Delegate ? '+' : '-')}} {{
|
||||
mapEvents(item.events).map(x => x.amount).join(", ")
|
||||
}}</span>
|
||||
</RouterLink>
|
||||
<Icon
|
||||
v-if="item.code === 0"
|
||||
icon="mdi-check"
|
||||
class="text-yes"
|
||||
/>
|
||||
<Icon v-else icon="mdi-multiply" class="text-no" />
|
||||
</div>
|
||||
</td>
|
||||
<td width="150">
|
||||
<RouterLink class="text-primary mb-0" :to="`/${props.chain}/block/${item.height}`">{{
|
||||
item.height
|
||||
}}</RouterLink><br>
|
||||
<span class="text-xs pt-0 mt-0">{{ format.toDay(item.timestamp, 'from') }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<PaginationBar :total="events.pagination?.total" :limit="page.limit" :callback="pagePowerEvents"/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end -->
|
||||
<div class="toast" v-show="showCopyToast === 1">
|
||||
<div class="alert alert-success">
|
||||
<div class="text-xs md:!text-sm">
|
||||
|
@ -36,6 +36,9 @@ export class PageRequest {
|
||||
setPage(page: number) {
|
||||
if(page >= 1) this.offset = (page - 1) * this.limit
|
||||
}
|
||||
setPageSize(size: number) {
|
||||
this.limit = size
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user