add power event

This commit is contained in:
liangping 2023-12-25 14:55:47 +08:00
parent 6cccb25964
commit 0e57913204
3 changed files with 133 additions and 0 deletions

View File

@ -14,6 +14,22 @@ export const percent = (num: number) => {
return parseFloat((num * 100).toFixed(2)); 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 = [ const COUNT_ABBRS = [
'', '',
'K', 'K',

View File

@ -17,6 +17,8 @@ import {
} from '@/libs'; } from '@/libs';
import { PageRequest, type Coin, type Delegation, type PaginatedDelegations, type PaginatedTxs, type Validator } from '@/types'; import { PageRequest, type Coin, type Delegation, type PaginatedDelegations, type PaginatedTxs, type Validator } from '@/types';
import PaginationBar from '@/components/PaginationBar.vue'; import PaginationBar from '@/components/PaginationBar.vue';
import { fromBase64, toBase64 } from '@cosmjs/encoding';
import { stringToUint8Array, uint8ArrayToString } from '@/libs/utils';
const props = defineProps(['validator', 'chain']); const props = defineProps(['validator', 'chain']);
@ -189,10 +191,56 @@ const tipMsg = computed(() => {
function pageload(p: number) { function pageload(p: number) {
page.setPage(p); page.setPage(p);
page.limit = 10;
blockchain.rpc.getStakingValidatorsDelegations(validator, page).then(res => { blockchain.rpc.getStakingValidatorsDelegations(validator, page).then(res => {
delegations.value = 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> </script>
<template> <template>
<div> <div>
@ -582,6 +630,72 @@ function pageload(p: number) {
</table> </table>
</div> </div>
</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="toast" v-show="showCopyToast === 1">
<div class="alert alert-success"> <div class="alert alert-success">
<div class="text-xs md:!text-sm"> <div class="text-xs md:!text-sm">

View File

@ -35,6 +35,9 @@ export class PageRequest {
} }
setPage(page: number) { setPage(page: number) {
if(page >= 1) this.offset = (page - 1) * this.limit if(page >= 1) this.offset = (page - 1) * this.limit
}
setPageSize(size: number) {
this.limit = size
} }
} }