1use crate::error::{Error, Result};
14use crate::proto::qorechain;
15use crate::query::JsonRpcClient;
16use base64::engine::general_purpose::STANDARD as BASE64;
17use base64::Engine;
18use prost::Message;
19use serde_json::json;
20
21#[derive(Debug, Clone)]
23pub struct TypedQueryClient {
24 rpc: JsonRpcClient,
25}
26
27impl TypedQueryClient {
28 pub fn new(rpc_url: impl Into<String>) -> Self {
30 Self {
31 rpc: JsonRpcClient::new(rpc_url),
32 }
33 }
34
35 pub fn with_rpc(rpc: JsonRpcClient) -> Self {
37 Self { rpc }
38 }
39
40 async fn grpc_query<Req: Message, Resp: Message + Default>(
43 &self,
44 path: &str,
45 req: &Req,
46 ) -> Result<Resp> {
47 let data_hex = hex::encode(req.encode_to_vec());
48 let params = json!({
49 "path": path,
50 "data": data_hex,
51 "prove": false,
52 });
53 let result = self.rpc.call("abci_query", params).await?;
54 let response = &result["response"];
55 if let Some(code) = response["code"].as_u64() {
57 if code != 0 {
58 let log = response["log"].as_str().unwrap_or("query failed");
59 return Err(Error::InvalidResponse(format!(
60 "abci_query {path} failed (code {code}): {log}"
61 )));
62 }
63 }
64 let value_b64 = response["value"].as_str().unwrap_or("");
65 let bytes = if value_b64.is_empty() {
66 Vec::new()
67 } else {
68 BASE64
69 .decode(value_b64)
70 .map_err(|e| Error::InvalidResponse(format!("decode abci value: {e}")))?
71 };
72 Resp::decode(bytes.as_slice())
73 .map_err(|e| Error::InvalidResponse(format!("decode {path} response: {e}")))
74 }
75
76 pub async fn pqc_account(
80 &self,
81 address: impl Into<String>,
82 ) -> Result<qorechain::pqc::v1::QueryAccountResponse> {
83 self.grpc_query(
84 "/qorechain.pqc.v1.Query/Account",
85 &qorechain::pqc::v1::QueryAccountRequest {
86 address: address.into(),
87 },
88 )
89 .await
90 }
91
92 pub async fn crossvm_params(&self) -> Result<qorechain::crossvm::v1::QueryParamsResponse> {
96 self.grpc_query(
97 "/qorechain.crossvm.v1.Query/Params",
98 &qorechain::crossvm::v1::QueryParamsRequest {},
99 )
100 .await
101 }
102
103 pub async fn crossvm_pending_messages(
105 &self,
106 ) -> Result<qorechain::crossvm::v1::QueryPendingMessagesResponse> {
107 self.grpc_query(
108 "/qorechain.crossvm.v1.Query/PendingMessages",
109 &qorechain::crossvm::v1::QueryPendingMessagesRequest {},
110 )
111 .await
112 }
113
114 pub async fn crossvm_message(
116 &self,
117 id: impl Into<String>,
118 ) -> Result<qorechain::crossvm::v1::QueryMessageResponse> {
119 self.grpc_query(
120 "/qorechain.crossvm.v1.Query/Message",
121 &qorechain::crossvm::v1::QueryMessageRequest { id: id.into() },
122 )
123 .await
124 }
125
126 pub async fn lightnode(
130 &self,
131 address: impl Into<String>,
132 ) -> Result<qorechain::lightnode::v1::QueryLightNodeResponse> {
133 self.grpc_query(
134 "/qorechain.lightnode.v1.Query/LightNode",
135 &qorechain::lightnode::v1::QueryLightNodeRequest {
136 address: address.into(),
137 },
138 )
139 .await
140 }
141
142 pub async fn lightnodes(&self) -> Result<qorechain::lightnode::v1::QueryLightNodesResponse> {
144 self.grpc_query(
145 "/qorechain.lightnode.v1.Query/LightNodes",
146 &qorechain::lightnode::v1::QueryLightNodesRequest {},
147 )
148 .await
149 }
150
151 pub async fn lightnode_params(&self) -> Result<qorechain::lightnode::v1::QueryParamsResponse> {
153 self.grpc_query(
154 "/qorechain.lightnode.v1.Query/Params",
155 &qorechain::lightnode::v1::QueryParamsRequest {},
156 )
157 .await
158 }
159
160 pub async fn lightnode_rewards(
162 &self,
163 address: impl Into<String>,
164 ) -> Result<qorechain::lightnode::v1::QueryRewardsResponse> {
165 self.grpc_query(
166 "/qorechain.lightnode.v1.Query/Rewards",
167 &qorechain::lightnode::v1::QueryRewardsRequest {
168 address: address.into(),
169 },
170 )
171 .await
172 }
173
174 pub async fn lightnode_stats(&self) -> Result<qorechain::lightnode::v1::QueryStatsResponse> {
176 self.grpc_query(
177 "/qorechain.lightnode.v1.Query/Stats",
178 &qorechain::lightnode::v1::QueryStatsRequest {},
179 )
180 .await
181 }
182
183 pub async fn svm_slot(&self) -> Result<qorechain::svm::v1::QuerySlotResponse> {
187 self.grpc_query(
188 "/qorechain.svm.v1.Query/Slot",
189 &qorechain::svm::v1::QuerySlotRequest {},
190 )
191 .await
192 }
193
194 pub async fn svm_account(
196 &self,
197 address: impl Into<String>,
198 ) -> Result<qorechain::svm::v1::QueryAccountResponse> {
199 self.grpc_query(
200 "/qorechain.svm.v1.Query/Account",
201 &qorechain::svm::v1::QueryAccountRequest {
202 address: address.into(),
203 },
204 )
205 .await
206 }
207
208 pub async fn svm_program(
210 &self,
211 address: impl Into<String>,
212 ) -> Result<qorechain::svm::v1::QueryProgramResponse> {
213 self.grpc_query(
214 "/qorechain.svm.v1.Query/Program",
215 &qorechain::svm::v1::QueryProgramRequest {
216 address: address.into(),
217 },
218 )
219 .await
220 }
221
222 pub async fn reputation_params(
226 &self,
227 ) -> Result<qorechain::reputation::v1::QueryParamsResponse> {
228 self.grpc_query(
229 "/qorechain.reputation.v1.Query/Params",
230 &qorechain::reputation::v1::QueryParamsRequest {},
231 )
232 .await
233 }
234
235 pub async fn qca_config(&self) -> Result<qorechain::qca::v1::QueryConfigResponse> {
239 self.grpc_query(
240 "/qorechain.qca.v1.Query/Config",
241 &qorechain::qca::v1::QueryConfigRequest {},
242 )
243 .await
244 }
245
246 pub async fn rlconsensus_agent_status(
250 &self,
251 ) -> Result<qorechain::rlconsensus::v1::QueryAgentStatusResponse> {
252 self.grpc_query(
253 "/qorechain.rlconsensus.v1.Query/AgentStatus",
254 &qorechain::rlconsensus::v1::QueryAgentStatusRequest {},
255 )
256 .await
257 }
258
259 pub async fn rlconsensus_params(
261 &self,
262 ) -> Result<qorechain::rlconsensus::v1::QueryParamsResponse> {
263 self.grpc_query(
264 "/qorechain.rlconsensus.v1.Query/Params",
265 &qorechain::rlconsensus::v1::QueryParamsRequest {},
266 )
267 .await
268 }
269
270 pub async fn rlconsensus_observation(
272 &self,
273 ) -> Result<qorechain::rlconsensus::v1::QueryObservationResponse> {
274 self.grpc_query(
275 "/qorechain.rlconsensus.v1.Query/Observation",
276 &qorechain::rlconsensus::v1::QueryObservationRequest {},
277 )
278 .await
279 }
280
281 pub async fn rlconsensus_reward(
283 &self,
284 ) -> Result<qorechain::rlconsensus::v1::QueryRewardResponse> {
285 self.grpc_query(
286 "/qorechain.rlconsensus.v1.Query/Reward",
287 &qorechain::rlconsensus::v1::QueryRewardRequest {},
288 )
289 .await
290 }
291
292 pub async fn rlconsensus_policy(
294 &self,
295 ) -> Result<qorechain::rlconsensus::v1::QueryPolicyResponse> {
296 self.grpc_query(
297 "/qorechain.rlconsensus.v1.Query/Policy",
298 &qorechain::rlconsensus::v1::QueryPolicyRequest {},
299 )
300 .await
301 }
302
303 pub async fn multilayer_params(
307 &self,
308 ) -> Result<qorechain::multilayer::v1::QueryParamsResponse> {
309 self.grpc_query(
310 "/qorechain.multilayer.v1.Query/Params",
311 &qorechain::multilayer::v1::QueryParamsRequest {},
312 )
313 .await
314 }
315
316 pub async fn multilayer_layer(
318 &self,
319 layer_id: impl Into<String>,
320 ) -> Result<qorechain::multilayer::v1::QueryLayerResponse> {
321 self.grpc_query(
322 "/qorechain.multilayer.v1.Query/Layer",
323 &qorechain::multilayer::v1::QueryLayerRequest {
324 layer_id: layer_id.into(),
325 },
326 )
327 .await
328 }
329
330 pub async fn multilayer_layers(
332 &self,
333 ) -> Result<qorechain::multilayer::v1::QueryLayersResponse> {
334 self.grpc_query(
335 "/qorechain.multilayer.v1.Query/Layers",
336 &qorechain::multilayer::v1::QueryLayersRequest {},
337 )
338 .await
339 }
340
341 pub async fn multilayer_anchor(
344 &self,
345 layer_id: impl Into<String>,
346 ) -> Result<qorechain::multilayer::v1::QueryAnchorResponse> {
347 self.grpc_query(
348 "/qorechain.multilayer.v1.Query/Anchor",
349 &qorechain::multilayer::v1::QueryAnchorRequest {
350 layer_id: layer_id.into(),
351 },
352 )
353 .await
354 }
355
356 pub async fn multilayer_anchors(
359 &self,
360 layer_id: impl Into<String>,
361 ) -> Result<qorechain::multilayer::v1::QueryAnchorsResponse> {
362 self.grpc_query(
363 "/qorechain.multilayer.v1.Query/Anchors",
364 &qorechain::multilayer::v1::QueryAnchorsRequest {
365 layer_id: layer_id.into(),
366 },
367 )
368 .await
369 }
370
371 pub async fn multilayer_routing_stats(
373 &self,
374 ) -> Result<qorechain::multilayer::v1::QueryRoutingStatsView> {
375 self.grpc_query(
376 "/qorechain.multilayer.v1.Query/RoutingStats",
377 &qorechain::multilayer::v1::QueryRoutingStatsRequest {},
378 )
379 .await
380 }
381
382 pub async fn amm_params(&self) -> Result<qorechain::amm::v1::QueryParamsResponse> {
386 self.grpc_query(
387 "/qorechain.amm.v1.Query/Params",
388 &qorechain::amm::v1::QueryParamsRequest {},
389 )
390 .await
391 }
392
393 pub async fn amm_pool(&self, pool_id: u64) -> Result<qorechain::amm::v1::QueryPoolResponse> {
395 self.grpc_query(
396 "/qorechain.amm.v1.Query/Pool",
397 &qorechain::amm::v1::QueryPoolRequest { pool_id },
398 )
399 .await
400 }
401
402 pub async fn amm_pools(&self) -> Result<qorechain::amm::v1::QueryPoolsResponse> {
404 self.grpc_query(
405 "/qorechain.amm.v1.Query/Pools",
406 &qorechain::amm::v1::QueryPoolsRequest {},
407 )
408 .await
409 }
410
411 pub async fn amm_pool_by_denoms(
413 &self,
414 denom_a: impl Into<String>,
415 denom_b: impl Into<String>,
416 ) -> Result<qorechain::amm::v1::QueryPoolByDenomsResponse> {
417 self.grpc_query(
418 "/qorechain.amm.v1.Query/PoolByDenoms",
419 &qorechain::amm::v1::QueryPoolByDenomsRequest {
420 denom_a: denom_a.into(),
421 denom_b: denom_b.into(),
422 },
423 )
424 .await
425 }
426
427 pub async fn amm_lp_balance(
429 &self,
430 pool_id: u64,
431 address: impl Into<String>,
432 ) -> Result<qorechain::amm::v1::QueryLpBalanceResponse> {
433 self.grpc_query(
434 "/qorechain.amm.v1.Query/LPBalance",
435 &qorechain::amm::v1::QueryLpBalanceRequest {
436 pool_id,
437 address: address.into(),
438 },
439 )
440 .await
441 }
442
443 pub async fn amm_quote_exact_in(
445 &self,
446 pool_id: u64,
447 denom_in: impl Into<String>,
448 amount_in: impl Into<String>,
449 ) -> Result<qorechain::amm::v1::QueryQuoteExactInResponse> {
450 self.grpc_query(
451 "/qorechain.amm.v1.Query/QuoteExactIn",
452 &qorechain::amm::v1::QueryQuoteExactInRequest {
453 pool_id,
454 denom_in: denom_in.into(),
455 amount_in: amount_in.into(),
456 },
457 )
458 .await
459 }
460
461 pub async fn amm_quote_exact_out(
463 &self,
464 pool_id: u64,
465 denom_out: impl Into<String>,
466 amount_out: impl Into<String>,
467 ) -> Result<qorechain::amm::v1::QueryQuoteExactOutResponse> {
468 self.grpc_query(
469 "/qorechain.amm.v1.Query/QuoteExactOut",
470 &qorechain::amm::v1::QueryQuoteExactOutRequest {
471 pool_id,
472 denom_out: denom_out.into(),
473 amount_out: amount_out.into(),
474 },
475 )
476 .await
477 }
478
479 pub async fn license_check(
483 &self,
484 grantee: impl Into<String>,
485 feature_id: impl Into<String>,
486 ) -> Result<qorechain::license::v1::QueryCheckResponse> {
487 self.grpc_query(
488 "/qorechain.license.v1.Query/Check",
489 &qorechain::license::v1::QueryCheckRequest {
490 grantee: grantee.into(),
491 feature_id: feature_id.into(),
492 },
493 )
494 .await
495 }
496
497 pub async fn license_holders(
499 &self,
500 feature_id: impl Into<String>,
501 ) -> Result<qorechain::license::v1::QueryHoldersResponse> {
502 self.grpc_query(
503 "/qorechain.license.v1.Query/Holders",
504 &qorechain::license::v1::QueryHoldersRequest {
505 feature_id: feature_id.into(),
506 },
507 )
508 .await
509 }
510
511 pub async fn license_list(
513 &self,
514 grantee: impl Into<String>,
515 ) -> Result<qorechain::license::v1::QueryListResponse> {
516 self.grpc_query(
517 "/qorechain.license.v1.Query/List",
518 &qorechain::license::v1::QueryListRequest {
519 grantee: grantee.into(),
520 },
521 )
522 .await
523 }
524
525 pub async fn abstractaccount_config(
529 &self,
530 ) -> Result<qorechain::abstractaccount::v1::QueryConfigResponse> {
531 self.grpc_query(
532 "/qorechain.abstractaccount.v1.Query/Config",
533 &qorechain::abstractaccount::v1::QueryConfigRequest {},
534 )
535 .await
536 }
537
538 pub async fn abstractaccount_account(
540 &self,
541 address: impl Into<String>,
542 ) -> Result<qorechain::abstractaccount::v1::QueryAccountResponse> {
543 self.grpc_query(
544 "/qorechain.abstractaccount.v1.Query/Account",
545 &qorechain::abstractaccount::v1::QueryAccountRequest {
546 address: address.into(),
547 },
548 )
549 .await
550 }
551
552 pub async fn abstractaccount_accounts(
554 &self,
555 ) -> Result<qorechain::abstractaccount::v1::QueryAccountsResponse> {
556 self.grpc_query(
557 "/qorechain.abstractaccount.v1.Query/Accounts",
558 &qorechain::abstractaccount::v1::QueryAccountsRequest {},
559 )
560 .await
561 }
562
563 pub async fn abstractaccount_permission_schema(
567 &self,
568 ) -> Result<qorechain::abstractaccount::v1::QueryPermissionSchemaResponse> {
569 self.grpc_query(
570 "/qorechain.abstractaccount.v1.Query/PermissionSchema",
571 &qorechain::abstractaccount::v1::QueryPermissionSchemaRequest {},
572 )
573 .await
574 }
575
576 pub async fn rdk_params(&self) -> Result<qorechain::rdk::v1::QueryParamsResponse> {
580 self.grpc_query(
581 "/qorechain.rdk.v1.Query/Params",
582 &qorechain::rdk::v1::QueryParamsRequest {},
583 )
584 .await
585 }
586
587 pub async fn rdk_rollup(
589 &self,
590 rollup_id: impl Into<String>,
591 ) -> Result<qorechain::rdk::v1::QueryRollupResponse> {
592 self.grpc_query(
593 "/qorechain.rdk.v1.Query/Rollup",
594 &qorechain::rdk::v1::QueryRollupRequest {
595 rollup_id: rollup_id.into(),
596 },
597 )
598 .await
599 }
600
601 pub async fn rdk_rollups(&self) -> Result<qorechain::rdk::v1::QueryRollupsResponse> {
603 self.grpc_query(
604 "/qorechain.rdk.v1.Query/Rollups",
605 &qorechain::rdk::v1::QueryRollupsRequest {},
606 )
607 .await
608 }
609
610 pub async fn rdk_batch(
612 &self,
613 rollup_id: impl Into<String>,
614 batch_index: u64,
615 ) -> Result<qorechain::rdk::v1::QueryBatchResponse> {
616 self.grpc_query(
617 "/qorechain.rdk.v1.Query/Batch",
618 &qorechain::rdk::v1::QueryBatchRequest {
619 rollup_id: rollup_id.into(),
620 batch_index,
621 },
622 )
623 .await
624 }
625
626 pub async fn rdk_latest_batch(
628 &self,
629 rollup_id: impl Into<String>,
630 ) -> Result<qorechain::rdk::v1::QueryLatestBatchResponse> {
631 self.grpc_query(
632 "/qorechain.rdk.v1.Query/LatestBatch",
633 &qorechain::rdk::v1::QueryLatestBatchRequest {
634 rollup_id: rollup_id.into(),
635 },
636 )
637 .await
638 }
639
640 pub async fn bridge_config(&self) -> Result<qorechain::bridge::v1::QueryConfigResponse> {
644 self.grpc_query(
645 "/qorechain.bridge.v1.Query/Config",
646 &qorechain::bridge::v1::QueryConfigRequest {},
647 )
648 .await
649 }
650
651 pub async fn bridge_chain_config(
653 &self,
654 chain_id: impl Into<String>,
655 ) -> Result<qorechain::bridge::v1::QueryChainConfigResponse> {
656 self.grpc_query(
657 "/qorechain.bridge.v1.Query/ChainConfig",
658 &qorechain::bridge::v1::QueryChainConfigRequest {
659 chain_id: chain_id.into(),
660 },
661 )
662 .await
663 }
664
665 pub async fn bridge_chain_configs(
667 &self,
668 ) -> Result<qorechain::bridge::v1::QueryChainConfigsResponse> {
669 self.grpc_query(
670 "/qorechain.bridge.v1.Query/ChainConfigs",
671 &qorechain::bridge::v1::QueryChainConfigsRequest {},
672 )
673 .await
674 }
675
676 pub async fn bridge_validator(
678 &self,
679 address: impl Into<String>,
680 ) -> Result<qorechain::bridge::v1::QueryValidatorResponse> {
681 self.grpc_query(
682 "/qorechain.bridge.v1.Query/Validator",
683 &qorechain::bridge::v1::QueryValidatorRequest {
684 address: address.into(),
685 },
686 )
687 .await
688 }
689
690 pub async fn bridge_validators(
692 &self,
693 ) -> Result<qorechain::bridge::v1::QueryValidatorsResponse> {
694 self.grpc_query(
695 "/qorechain.bridge.v1.Query/Validators",
696 &qorechain::bridge::v1::QueryValidatorsRequest {},
697 )
698 .await
699 }
700
701 pub async fn bridge_operation(
703 &self,
704 id: impl Into<String>,
705 ) -> Result<qorechain::bridge::v1::QueryOperationResponse> {
706 self.grpc_query(
707 "/qorechain.bridge.v1.Query/Operation",
708 &qorechain::bridge::v1::QueryOperationRequest { id: id.into() },
709 )
710 .await
711 }
712
713 pub async fn bridge_operations(
715 &self,
716 ) -> Result<qorechain::bridge::v1::QueryOperationsResponse> {
717 self.grpc_query(
718 "/qorechain.bridge.v1.Query/Operations",
719 &qorechain::bridge::v1::QueryOperationsRequest {},
720 )
721 .await
722 }
723}