polyfill tx event

This commit is contained in:
Pham Tu 2024-01-31 18:39:08 +07:00
parent dbb95626b2
commit 8d25fd702c
No known key found for this signature in database
GPG Key ID: 7460FD99133ADA1C
4 changed files with 64 additions and 49 deletions

View File

@ -39,6 +39,7 @@ import {
type AbciQueryParams,
type CometClient,
type QueryTag,
type TxData,
type TxResponse,
} from '@cosmjs/tendermint-rpc';
import { buildQuery } from '@cosmjs/tendermint-rpc/build/tendermint37/requests';
@ -104,13 +105,17 @@ import {
type RequestRegistry,
} from './registry';
import { decodeProto } from '@/components/dynamic';
import { convertStr } from './utils';
export const DEFAULT_SDK_VERSION = '0.45.16';
export const LCD_FALLBACK_CHAINS = ['OraiBtcMainnet'];
export type ExtraTxResponse = TxResponse & {
export type ExtraTxResponse = Omit<TxResponse, 'result'> & {
txRaw: DecodedTxRaw;
timestamp?: string;
result: Omit<TxData, 'events'> & {
readonly events: readonly Event[];
};
};
export interface ExtraTxSearchResponse {
readonly txs: ExtraTxResponse[];
@ -965,6 +970,13 @@ export class CosmosRestClient extends BaseRestClient<RequestRegistry> {
if (decodeRaw) {
res.txs.forEach((tx, i) => {
const txRaw = decodeTxRaw(tx.tx);
tx.result.events.forEach((event) => {
event.attributes.forEach((attr) => {
const key = convertStr(attr.key);
const value = convertStr(attr.value);
Object.assign(attr, { key, value });
});
});
// txRaw.body.messages = txRaw.body.messages.map(decodeProto);
// @ts-ignore
@ -1062,7 +1074,6 @@ export class CosmosRestClient extends BaseRestClient<RequestRegistry> {
// hash,
// });
const res = await this.queryClient.ibc.transfer.denomTrace(hash);
console.log(res);
return res;
}
async getIBCConnections(page?: PageRequest) {

View File

@ -1,5 +1,5 @@
import { fromBinary, type JsonObject } from '@cosmjs/cosmwasm-stargate';
import { fromAscii, toBase64 } from '@cosmjs/encoding';
import { fromAscii, fromBase64, toBase64 } from '@cosmjs/encoding';
import type { Timestamp } from 'cosmjs-types/google/protobuf/timestamp';
export const formatTitle = (title: string) => {
@ -26,6 +26,26 @@ export const percent = (num: number) => {
return parseFloat((num * 100).toFixed(2));
};
export const convertStr = (value: Uint8Array | string) => {
let valueArr;
if (typeof value === 'string') {
try {
valueArr = fromBase64(value);
} catch {
// pure string
return value;
}
} else {
valueArr = value;
}
try {
return fromAscii(valueArr);
} catch {
return typeof value === 'string' ? value : toBase64(valueArr);
}
};
export const decodeBuffer = (value: Uint8Array) => {
try {
const str = fromAscii(value);
@ -56,14 +76,6 @@ export const parseJSONRecursive = (value: JsonObject) => {
return value;
};
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) {

View File

@ -19,7 +19,7 @@ import {
type UnbondingResponses,
PageRequest,
} from '@/types';
import type { Event } from '@cosmjs/tendermint-rpc';
import type { Coin } from '@cosmjs/amino';
import Countdown from '@/components/Countdown.vue';
import { fromAscii, fromBase64, toBase64, toHex } from '@cosmjs/encoding';
@ -31,6 +31,7 @@ import { BaseAccount } from 'cosmjs-types/cosmos/auth/v1beta1/auth';
import type { ExtraTxResponse } from '@/libs/client';
import type { QueryDelegationTotalRewardsResponse } from 'cosmjs-types/cosmos/distribution/v1beta1/query';
import { fromTimestamp } from 'cosmjs-types/helpers';
import type { Event } from 'cosmjs-types/tendermint/abci/types';
const props = defineProps(['address', 'chain']);
@ -151,9 +152,7 @@ function mapAmount(events: readonly Event[]) {
if (!events) return [];
return events
.find((x) => x.type === 'coin_received')
?.attributes.filter(
(x) => (typeof x.key === 'string' ? x.key : fromAscii(x.key)) === 'amount'
)
?.attributes.filter((x) => x.key === 'amount')
.map((x) => x.value);
}
</script>

View File

@ -10,7 +10,6 @@ import {
decodeKey,
} from '@/libs';
import type { ExtraTxResponse, ExtraTxSearchResponse } from '@/libs/client';
import { stringToUint8Array } from '@/libs/utils';
import {
useBlockchain,
useFormatter,
@ -21,7 +20,7 @@ import {
import { PageRequest } from '@/types';
import { fromAscii, fromBech32, toBase64, toHex } from '@cosmjs/encoding';
import type { Coin } from '@cosmjs/stargate';
import type { Event } from '@cosmjs/tendermint-rpc';
import type { Event, EventAttribute } from 'cosmjs-types/tendermint/abci/types';
import { Icon } from '@iconify/vue';
import type { QueryValidatorDelegationsResponse } from 'cosmjs-types/cosmos/staking/v1beta1/query';
import {
@ -286,45 +285,39 @@ function mapAmounts(tx: ExtraTxResponse) {
})
.filter(Boolean);
if (amounts.length) return amounts;
return mapEvents(tx.result.events);
// fallback from event
return filterEvents(tx.result.events).map((x) =>
x.attributes.find((a) => a.key === 'amount')?.value.replace(/[^\d]+/g, '')
);
}
function mapEvents(events: readonly Event[]) {
function filterEvents(events: readonly Event[]) {
const attributes = events
.filter((x) => x.type === selectedEventType.value)
.filter(
(x) =>
x.attributes.findIndex((attr) => {
const base64Validator = toBase64(stringToUint8Array(validator));
return (
toBase64(attr.value) === base64Validator ||
toBase64(attr.value) === base64Validator
);
}) > -1
)
.map((x) => {
// check if attributes need to decode
const output = {} as { [key: string]: string };
if (x.attributes.findIndex((a) => fromAscii(a.key) === `amount`) > -1) {
x.attributes.forEach((attr) => {
output[fromAscii(attr.key)] = fromAscii(attr.value);
});
} else
x.attributes.forEach((attr) => {
output[fromAscii(attr.key)] = fromAscii(attr.value);
});
return output;
});
.filter((x) =>
x.attributes.some((attr) => {
return attr.value === validator;
})
);
return attributes;
}
function mapDelegators(messages: any[]) {
function mapDelegators(tx: ExtraTxResponse) {
const { messages } = tx.txRaw.body;
if (!messages) return [];
return Array.from(
new Set(messages.map((x) => x.delegatorAddress || x.grantee || x.contract))
);
const delegators = Array.from(
new Set(
messages.map((x: any) => x.delegatorAddress || x.grantee || x.contract)
)
).filter(Boolean);
if (delegators.length) return delegators;
// fallback from event
return filterEvents(tx.result.events)
.map((x) => x.attributes.find((a) => a.key === 'validator')?.value)
.filter(Boolean);
}
</script>
<template>
@ -410,7 +403,7 @@ function mapDelegators(messages: any[]) {
<div class="flex items-center mb-2">
<Icon icon="mdi-shield-account-outline" class="text-xl mr-1" />
<span class="font-bold mr-2">{{ $t('staking.status') }}: </span
><span>
><span class="capitalize">
{{
bondStatusToJSON(v.status)
.toLowerCase()
@ -828,7 +821,7 @@ function mapDelegators(messages: any[]) {
<tr v-for="(item, i) in events.txs">
<td class="pr-2 truncate text-primary" style="max-width: 250px">
<RouterLink
v-for="d in mapDelegators(item.txRaw.body?.messages)"
v-for="d in mapDelegators(item)"
:to="`/${props.chain}/account/${d}`"
>
{{ d }}