add wasm query

This commit is contained in:
liangping 2025-04-13 07:50:39 +08:00
parent 274a915f32
commit 176422d15d
7 changed files with 148 additions and 85 deletions

View File

@ -5,7 +5,11 @@ import type {
Coin,
ConnectionWithProof,
DenomTrace,
Group,
GroupProposal,
GroupTallyResult,
NodeInfo,
PageResponse,
PaginabledAccounts,
PaginatedIBCChannels,
PaginatedIBCConnections,
@ -126,6 +130,13 @@ export interface RequestRegistry extends AbstractRegistry {
params: Request<{param: any}>;
group_groups: Request<PageResponse<Group>>;
group_groups_by_admin: Request<PageResponse<Group>>;
group_groups_by_member: Request<PageResponse<Group>>;
group_proposal: Request<{ proposal: GroupProposal }>;
group_proposal_tally: Request<{ tally: GroupTallyResult }>;
group_proposals_by_group_policy: Request<PageResponse<GroupProposal>>;
tx_txs: Request<PaginatedTxs>;
tx_txs_block: Request<Tx>;
tx_hash: Request<{ tx: Tx; tx_response: TxResponse }>;

View File

@ -1,4 +1,4 @@
import { fetchData } from '@/libs';
import { fetchData, get } from '@/libs';
import { DEFAULT } from '@/libs';
import {
adapter,
@ -30,6 +30,13 @@ export class BaseRestClient<R extends AbstractRegistry> {
});
return fetchData<T>(url, adapter||request.adapter);
}
async get<T>(request: Request<T>, args: Record<string, any>, query = '' ) {
let url = `${request.url.startsWith("http")?'':this.endpoint}${request.url}${query}`;
Object.keys(args).forEach((k) => {
url = url.replace(`{${k}}`, args[k] || '');
});
return get(url);
}
}
// dynamic all custom request implementations

View File

@ -6,7 +6,7 @@ export async function fetchData<T>(
): Promise<T> {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
throw new Error(`HTTP error: ${response.status}, ${response.statusText}`);
}
const data = await response.json();
return adapter(data);

View File

@ -13,6 +13,7 @@ import type {
import { toBase64 } from '@cosmjs/encoding';
import { useBlockchain } from '@/stores';
import { PageRequest } from '@/types';
import { get } from '@/libs';
export interface WasmRequestRegistry extends AbstractRegistry {
cosmwasm_code: Request<PaginabledCodeInfos>;
@ -103,11 +104,21 @@ export interface WasmRequestRegistry extends AbstractRegistry {
}
getWasmContractSmartQuery(address: string, query: string) {
const query_data = toBase64(new TextEncoder().encode(query));
return this.request(
return this.get(
this.registry.cosmwasm_contract_address_smart_query_data,
{ address, query_data }
);
}
async getWasmContractQueries(address: string) {
const query_data = toBase64(new TextEncoder().encode('{"":""}'));
const {code, message} = await this.get(
this.registry.cosmwasm_contract_address_smart_query_data,
{ address, query_data }
);
let re = /`(\w+)`/g
let x = String(message).match(re)
return code === 2 ? x?.map(e => e.replaceAll('`', '')) : null
}
getWasmContractStates(address: string, pr: PageRequest) {
if(!pr) pr = new PageRequest()
const query = `?${pr.toQueryString()}`

View File

@ -38,10 +38,10 @@ const contractAddress = String(route.query.contract)
const history = JSON.parse(localStorage.getItem("contract_history") || "{}")
if(history[chainStore.chainName]) {
if(!history[chainStore.chainName].includes(contractAddress)) {
if (history[chainStore.chainName]) {
if (!history[chainStore.chainName].includes(contractAddress)) {
history[chainStore.chainName].push(contractAddress)
if(history[chainStore.chainName].length > 10) {
if (history[chainStore.chainName].length > 10) {
history[chainStore.chainName].shift()
}
}
@ -59,6 +59,14 @@ onMounted(() => {
txs.value = res
})
wasmStore.wasmClient.getWasmContractQueries(contractAddress).then(res => {
console.log("queries: ", res)
queries.value = res
if (res && res.length > 0) {
selectQuery(res[0])
}
})
})
function pageload(pageNum: number) {
@ -97,6 +105,10 @@ function showQuery() {
result.value = '';
}
function selectQuery(method: string) {
query.value = `{"${method}":{}}`
}
function queryContract() {
try {
if (selectedRadio.value === 'raw') {
@ -137,52 +149,68 @@ const radioContent = [
},
];
const selectedRadio = ref('raw');
const selectedRadio = ref('smart');
const query = ref('');
const result = ref({});
const queries = ref<RegExpMatchArray | null>()
const tab = ref('detail')
</script>
<template>
<div>
<div class="bg-base-100 px-4 pt-3 pb-4 rounded mb-4 shadow">
<h2 class="card-title truncate w-full">
{{ $t('cosmwasm.contract_detail') }}
</h2>
<DynamicComponent :value="info" />
<div class="tabs tabs-boxed bg-transparent mb-4">
<a class="tab text-gray-400 uppercase" :class="{ 'tab-active': tab === 'detail' }"
@click="tab = 'detail'">{{ $t('cosmwasm.contract_detail') }}</a>
<a class="tab text-gray-400 uppercase" :class="{ 'tab-active': tab === 'transaction' }"
@click="tab = 'transaction'">Transactions</a>
<a class="tab text-gray-400 uppercase" :class="{ 'tab-active': tab === 'query' }"
@click="tab = 'query'">Query</a>
<a class="tab text-gray-400 uppercase" :class="{ 'tab-active': tab === 'execute' }"
@click="tab = 'execute'">Execute</a>
</div>
<div class="text-center mb-4">
<RouterLink :to="`../${info.code_id}/contracts`"><span class="btn btn-xs text-xs mr-2"> Back </span> </RouterLink>
<label @click="showFunds()" for="modal-contract-funds" class="btn btn-primary btn-xs text-xs mr-2">{{
$t('cosmwasm.btn_funds') }}</label>
<label class="btn btn-primary btn-xs text-xs mr-2" for="modal-contract-states" @click="showState()">
{{ $t('cosmwasm.btn_states') }}
</label>
<label for="modal-contract-query" class="btn btn-primary btn-xs text-xs mr-2" @click="showQuery()">
{{ $t('cosmwasm.btn_query') }}
</label>
<label for="wasm_execute_contract" class="btn btn-primary btn-xs text-xs mr-2"
@click="dialog.open('wasm_execute_contract', { contract: contractAddress })">
{{ $t('cosmwasm.btn_execute') }}
</label>
<div v-show="tab === 'detail'">
<div class="bg-base-100 px-4 pt-3 pb-4 rounded mb-4 shadow">
<h2 class="card-title truncate w-full">
{{ $t('cosmwasm.contract_detail') }}
</h2>
<DynamicComponent :value="info" />
</div>
<label for="wasm_migrate_contract" class="btn btn-primary btn-xs text-xs mr-2"
@click="dialog.open('wasm_migrate_contract', { contract: contractAddress })">
{{ $t('cosmwasm.btn_migrate') }}
</label>
<div class="text-center mb-4">
<RouterLink :to="`../${info.code_id}/contracts`"><span class="btn btn-xs text-xs mr-2"> Back </span>
</RouterLink>
<label @click="showFunds()" for="modal-contract-funds" class="btn btn-primary btn-xs text-xs mr-2">{{
$t('cosmwasm.btn_funds') }}</label>
<label class="btn btn-primary btn-xs text-xs mr-2" for="modal-contract-states" @click="showState()">
{{ $t('cosmwasm.btn_states') }}
</label>
<label for="modal-contract-query" class="btn btn-primary btn-xs text-xs mr-2" @click="showQuery()">
{{ $t('cosmwasm.btn_query') }}
</label>
<label for="wasm_execute_contract" class="btn btn-primary btn-xs text-xs mr-2"
@click="dialog.open('wasm_execute_contract', { contract: contractAddress })">
{{ $t('cosmwasm.btn_execute') }}
</label>
<label for="wasm_update_admin" class="btn btn-primary btn-xs text-xs mr-2"
@click="dialog.open('wasm_update_admin', { contract: contractAddress })">
{{ $t('cosmwasm.btn_update_admin') }}
</label>
<label for="wasm_migrate_contract" class="btn btn-primary btn-xs text-xs mr-2"
@click="dialog.open('wasm_migrate_contract', { contract: contractAddress })">
{{ $t('cosmwasm.btn_migrate') }}
</label>
<label for="wasm_clear_admin" class="btn btn-primary btn-xs text-xs mr-2"
@click="dialog.open('wasm_clear_admin', { contract: contractAddress })">
{{ $t('cosmwasm.btn_clear_admin') }}
</label>
<label for="wasm_update_admin" class="btn btn-primary btn-xs text-xs mr-2"
@click="dialog.open('wasm_update_admin', { contract: contractAddress })">
{{ $t('cosmwasm.btn_update_admin') }}
</label>
<label for="wasm_clear_admin" class="btn btn-primary btn-xs text-xs mr-2"
@click="dialog.open('wasm_clear_admin', { contract: contractAddress })">
{{ $t('cosmwasm.btn_clear_admin') }}
</label>
</div>
</div>
<div class="bg-base-100 px-4 pt-3 pb-4 rounded mb-4 shadow">
<div v-show="tab === 'transaction'" class="bg-base-100 px-4 pt-3 pb-4 rounded mb-4 shadow">
<h2 class="card-title truncate w-full mt-4 mb-2">Transactions</h2>
<table class="table">
<thead class=" bg-base-200">
@ -216,7 +244,38 @@ const result = ref({});
<PaginationBar :limit="page.limit" :total="txs.pagination?.total" :callback="pageload" />
</div>
<WasmVerification :contract="contractAddress"/>
<div v-show="tab === 'query'">
<div class="bg-base-100 px-4 pt-3 pb-4 rounded mb-4 shadow">
<div class="flex items-center justify-between px-3 pt-2 mb-4">
<div class="text-lg font-semibold">{{ $t('cosmwasm.suggested_messages') }}</div>
</div>
<div class="px-3">
<div>
<div>
<span v-for="q in queries" class="btn btn-xs mx-1"
@click="selectQuery(q)">{{ q }}</span>
</div>
<textarea v-model="query" placeholder="Query String, {}" label="Query String"
class="my-2 textarea textarea-bordered w-full" />
<div class="mt-4 mb-4 text-center">
<button class="btn btn-primary btn-sm px-4 text-white" @click="queryContract()">
{{ $t('cosmwasm.query_contract') }}
</button>
</div>
</div>
</div>
</div>
<div class="bg-base-100 px-4 pt-3 pb-4 rounded mb-4 shadow">
<div class="flex items-center justify-between px-3 pt-2 mb-4">
<div class="text-lg font-semibold">{{ $t('cosmwasm.result') }}</div>
</div>
<JsonViewer :value="result" :theme="baseStore.theme" style="background: transparent;" copyable boxed
sort :expand-depth="5" />
</div>
</div>
<!-- WasmVerification :contract="contractAddress"/ -->
<div>
<input type="checkbox" id="modal-contract-funds" class="modal-toggle" />
@ -229,7 +288,8 @@ const result = ref({});
</div>
<ul class="menu mt-5">
<li v-for="b in balances.balances">
<a class="flex justify-between"><span>{{ format.formatToken(b) }}</span> {{ b.amount }} </a>
<a class="flex justify-between"><span>{{ format.formatToken(b) }}</span> {{ b.amount }}
</a>
</li>
<li v-if="balances.pagination?.total === '0'" class="my-10 text-center">{{
$t('cosmwasm.no_escrowed_assets') }}</li>
@ -247,56 +307,16 @@ const result = ref({});
<label for="modal-contract-states" class="btn btn-sm btn-circle"></label>
</div>
<div class="overflow-auto">
<JsonViewer :value="state.models?.map(v => ({key: format.hexToString(v.key), value: JSON.parse(format.base64ToString(v.value))}))||''" :theme="baseStore.theme||'dark'" style="background: transparent;" copyable boxed sort :expand-depth="5"/>
<JsonViewer
:value="state.models?.map(v => ({ key: format.hexToString(v.key), value: JSON.parse(format.base64ToString(v.value)) })) || ''"
:theme="baseStore.theme || 'dark'" style="background: transparent;" copyable boxed sort
:expand-depth="5" />
<PaginationBar :limit="pageRequest.limit" :total="state.pagination?.total"
:callback="pageloadState" />
</div>
</div>
</label>
</label>
<input type="checkbox" id="modal-contract-query" class="modal-toggle" />
<label for="modal-contract-query" class="modal cursor-pointer">
<label class="modal-box !w-11/12 !max-w-5xl" for="">
<div>
<div class="flex items-center justify-between px-3 pt-2 mb-4">
<div class="text-lg font-semibold">{{ $t('cosmwasm.query_contract') }}</div>
<label for="modal-contract-query" class="btn btn-sm btn-circle"></label>
</div>
<div class="px-3">
<div>
<div class="grid grid-cols-2 gap-4 mb-4">
<div class="form-control border rounded px-4" v-for="(item, index) of radioContent"
:key="index" :class="{ 'pt-2': index === 0 }">
<label class="label cursor-pointer justify-start"
@click="selectedRadio = item?.value">
<input type="radio" name="radio-10" class="radio radio-sm radio-primary mr-4"
:checked="item?.value === selectedRadio"
style="border: 1px solid #d2d6dc" />
<div>
<div class="text-base font-semibold">
{{ item?.title }}
</div>
<div class="text-xs">{{ item?.desc }}</div>
</div>
</label>
</div>
</div>
<textarea v-model="query" placeholder="Query String, {}" label="Query String"
class="my-2 textarea textarea-bordered w-full" />
<JsonViewer :value="result" :theme="baseStore.theme" style="background: transparent;" copyable boxed sort :expand-depth="5"/>
</div>
<div class="mt-4 mb-4 text-center">
<button class="btn btn-primary px-4 text-white" @click="queryContract()">
{{ $t('cosmwasm.query_contract') }}
</button>
</div>
</div>
</div>
</label>
</label>
</div>
</div>
</template>

View File

@ -0,0 +1,12 @@
<script lang="ts">
import { fromBech32, fromHex, toBech32 } from '@cosmjs/encoding';
let x = toBech32("neutronvaloper1", fromHex("3363E8F97B02ECC00289E72173D827543047ACDA"))
let add = fromBech32("cosmosvaloper1jxv0u20scum4trha72c7ltfgfqef6nsch7q6cu")
let op = toBech32("neutronvaloper1", add.data)
console.log(x)
console.log(op)
</script>
<template>
<div>address: {{ x }}</div>
</template>

View File

@ -130,6 +130,8 @@
"no_escrowed_assets": "No Escrowed Assets",
"contract_states": "Contract States",
"query_contract": "Query Contract",
"suggested_messages":"Suggested Messages",
"result":"Result",
"tips_description_1": "This feature is available when deploying contracts via WELLDONE Code. For more information, please check the document at the link below."
},
"gov": {