From 4ed7b775166dabe3465c24acbe366b19c55721b0 Mon Sep 17 00:00:00 2001 From: Saeed Dadkhah Date: Thu, 20 Jun 2024 11:50:16 +0330 Subject: [PATCH] Add more query functions --- Cargo.toml | 1 + crates/sdk/libs/near/Cargo.toml | 1 + crates/sdk/libs/near/src/jsonrpc.rs | 27 +++++--- crates/sdk/libs/near/src/lib.rs | 95 ++++++++++++++++++++++++----- crates/sdk/libs/near/src/query.rs | 7 ++- crates/sdk/libs/near/src/types.rs | 14 +++++ crates/sdk/libs/near/src/views.rs | 75 +++++++++++++++++++++-- 7 files changed, 192 insertions(+), 28 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5acd8b2e2..6c466d82b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -70,6 +70,7 @@ sha3 = "0.10.8" semver = "1.0.22" serde = "1.0.196" serde_json = "1.0.113" +serde_with = "3.8.1" syn = "2.0" thiserror = "1.0.56" tokio = "1.35.1" diff --git a/crates/sdk/libs/near/Cargo.toml b/crates/sdk/libs/near/Cargo.toml index f1260ce4b..91bb0ed13 100644 --- a/crates/sdk/libs/near/Cargo.toml +++ b/crates/sdk/libs/near/Cargo.toml @@ -9,6 +9,7 @@ license.workspace = true [dependencies] serde = { workspace = true, features = ["derive"] } serde_json.workspace = true +serde_with = {workspace = true, features = ["base64"]} calimero-sdk = { path = "../../" } calimero-primitives = { path = "../../../primitives" } diff --git a/crates/sdk/libs/near/src/jsonrpc.rs b/crates/sdk/libs/near/src/jsonrpc.rs index dfbe3d22b..bc2f80f11 100644 --- a/crates/sdk/libs/near/src/jsonrpc.rs +++ b/crates/sdk/libs/near/src/jsonrpc.rs @@ -1,6 +1,6 @@ use calimero_sdk::env; use serde::de::DeserializeOwned; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; pub(crate) struct Client { url: String, @@ -15,20 +15,20 @@ impl Client { } } - pub fn call( + pub fn call( &self, method: &str, - params: serde_json::Value, + params: P, ) -> Result, String> { let headers = [("Content-Type", "application/json")]; *self.id.borrow_mut() += 1; - let body = serde_json::to_vec(&serde_json::json!({ - "jsonrpc": "2.0", - "id": self.id.borrow().to_string(), - "method": method, - "params": params, - })) + let body = serde_json::to_vec(&Request { + jsonrpc: "2.0", + id: self.id.borrow().to_string(), + method: method.to_string(), + params, + }) .map_err(|err| format!("Cannot serialize request: {:?}", err))?; let response = unsafe { env::ext::fetch(&self.url, "POST", &headers, &body) }?; @@ -37,6 +37,15 @@ impl Client { } } +#[derive(Debug, Clone, Serialize)] +pub struct Request { + pub jsonrpc: &'static str, + pub id: String, + pub method: String, + + pub params: P, +} + #[derive(Debug, Clone, Deserialize)] pub struct Response { pub jsonrpc: Option, diff --git a/crates/sdk/libs/near/src/lib.rs b/crates/sdk/libs/near/src/lib.rs index eee4008c0..ff0e6b348 100644 --- a/crates/sdk/libs/near/src/lib.rs +++ b/crates/sdk/libs/near/src/lib.rs @@ -1,6 +1,6 @@ use jsonrpc::Response; use query::{QueryResponseKind, RpcQueryRequest}; -use types::BlockId; +use types::{BlockId, StoreKey}; use views::QueryRequest; mod jsonrpc; @@ -36,9 +36,8 @@ impl Client { account_id: account_id.to_string(), }, }; - let response: Response = self - .client - .call("query", serde_json::to_value(&request).unwrap())?; + let response: Response = + self.client.call("query", request)?; match response.data { Ok(r) => { @@ -51,18 +50,86 @@ impl Client { } } - pub fn view_code(&self, account_id: &str) -> Result { - let response: Response = self.client.call( - "query", - serde_json::json!({ - "request_type": "view_code", - "finality": "final", - "account_id": account_id, - }), - )?; + pub fn view_code( + &self, + account_id: &str, + block_id: BlockId, + ) -> Result { + let request = RpcQueryRequest { + block_id, + request: QueryRequest::ViewCode { + account_id: account_id.to_string(), + }, + }; + + let response: Response = + self.client.call("query", request)?; match response.data { - Ok(r) => Ok(r), + Ok(r) => { + if let QueryResponseKind::ViewCode(vc) = r.kind { + return Ok(vc); + } + return Err("Unexpected response returned.".to_string()); + } + Err(e) => Err(format!("Error: {}, Code: {}", e.message, e.code,)), + } + } + + pub fn view_state( + &self, + account_id: &str, + prefix: StoreKey, + include_proof: bool, + block_id: BlockId, + ) -> Result { + let request = RpcQueryRequest { + block_id, + request: QueryRequest::ViewState { + account_id: account_id.to_string(), + prefix, + include_proof, + }, + }; + + let response: Response = + self.client.call("query", request)?; + + match response.data { + Ok(r) => { + if let QueryResponseKind::ViewState(vs) = r.kind { + return Ok(vs); + } + return Err("Unexpected response returned.".to_string()); + } + Err(e) => Err(format!("Error: {}, Code: {}", e.message, e.code,)), + } + } + + pub fn view_access_key( + &self, + account_id: &str, + public_key: &str, + block_id: BlockId, + ) -> Result { + let request = RpcQueryRequest { + block_id, + request: QueryRequest::ViewAccessKey { + account_id: account_id.to_string(), + public_key: public_key.to_string(), + }, + }; + + let response: Response = + self.client.call("query", request)?; + + match response.data { + Ok(r) => { + if let QueryResponseKind::ViewState(vs) = r.kind { + return Ok(vs); + } + return Err("Unexpected response returned.".to_string()); + } Err(e) => Err(format!("Error: {}, Code: {}", e.message, e.code,)), } } diff --git a/crates/sdk/libs/near/src/query.rs b/crates/sdk/libs/near/src/query.rs index 7668e45a1..36f9dc4d5 100644 --- a/crates/sdk/libs/near/src/query.rs +++ b/crates/sdk/libs/near/src/query.rs @@ -1,6 +1,8 @@ use crate::{ types::{BlockHash, BlockHeight, BlockId}, - views::{AccountView, ContractCodeView, QueryRequest}, + views::{ + AccessKeyList, AccessKeyView, AccountView, ContractCodeView, QueryRequest, ViewStateResult, + }, }; #[derive(serde::Serialize, Debug)] @@ -23,4 +25,7 @@ pub struct RpcQueryResponse { pub enum QueryResponseKind { ViewAccount(AccountView), ViewCode(ContractCodeView), + ViewState(ViewStateResult), + AccessKey(AccessKeyView), + AccessKeyList(AccessKeyList), } diff --git a/crates/sdk/libs/near/src/types.rs b/crates/sdk/libs/near/src/types.rs index 87c84c5b0..e48a25994 100644 --- a/crates/sdk/libs/near/src/types.rs +++ b/crates/sdk/libs/near/src/types.rs @@ -1,7 +1,11 @@ +use serde_with::base64::Base64; +use serde_with::serde_as; + pub type BlockHeight = u64; pub type BlockHash = String; pub type AccountId = String; pub type StorageUsage = u64; +pub type Nonce = u64; #[derive(Debug, Clone, serde::Serialize)] #[serde(untagged)] @@ -9,3 +13,13 @@ pub enum BlockId { Height(BlockHeight), Hash(BlockHash), } + +#[serde_as] +#[derive(serde::Deserialize, Clone, Debug)] +#[serde(transparent)] +pub struct StoreValue(#[serde_as(as = "Base64")] pub Vec); + +#[serde_as] +#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)] +#[serde(transparent)] +pub struct StoreKey(#[serde_as(as = "Base64")] pub Vec); diff --git a/crates/sdk/libs/near/src/views.rs b/crates/sdk/libs/near/src/views.rs index f571e4be7..a51d360fa 100644 --- a/crates/sdk/libs/near/src/views.rs +++ b/crates/sdk/libs/near/src/views.rs @@ -1,10 +1,33 @@ -use crate::types::{AccountId, BlockHeight, StorageUsage}; +use std::sync::Arc; + +use serde_with::base64::Base64; +use serde_with::serde_as; + +use crate::types::{AccountId, BlockHeight, Nonce, StorageUsage, StoreKey, StoreValue}; #[derive(serde::Serialize, Debug)] #[serde(tag = "request_type", rename_all = "snake_case")] pub enum QueryRequest { - ViewAccount { account_id: AccountId }, - ViewCode { account_id: AccountId }, + ViewAccount { + account_id: AccountId, + }, + ViewCode { + account_id: AccountId, + }, + ViewState { + account_id: AccountId, + #[serde(rename = "prefix_base64")] + prefix: StoreKey, + #[serde(default)] + include_proof: bool, + }, + ViewAccessKey { + account_id: AccountId, + public_key: String, + }, + ViewAccessKeyList { + account_id: AccountId, + }, } #[derive(serde::Deserialize, Debug, Clone)] @@ -16,9 +39,53 @@ pub struct AccountView { pub storage_paid_at: BlockHeight, } +#[serde_as] #[derive(serde::Deserialize, Debug, Clone)] pub struct ContractCodeView { #[serde(rename = "code_base64")] - pub code: String, + #[serde_as(as = "Base64")] + pub code: Vec, pub hash: String, } + +#[derive(serde::Deserialize, Debug, Clone)] +pub struct StateItem { + pub key: StoreKey, + pub value: StoreValue, +} + +#[serde_as] +#[derive(serde::Deserialize, Debug, Clone)] +pub struct ViewStateResult { + pub values: Vec, + #[serde_as(as = "Vec")] + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub proof: Vec>, +} + +#[derive(Debug, Clone, serde::Deserialize)] +pub struct AccessKeyView { + pub nonce: Nonce, + pub permission: AccessKeyPermissionView, +} + +#[derive(Debug, Clone, serde::Deserialize)] +pub enum AccessKeyPermissionView { + FunctionCall { + allowance: Option, + receiver_id: String, + method_names: Vec, + }, + FullAccess, +} + +#[derive(serde::Deserialize, Debug, Clone)] +pub struct AccessKeyList { + pub keys: Vec, +} + +#[derive(serde::Deserialize, Debug, Clone)] +pub struct AccessKeyInfoView { + pub public_key: String, + pub access_key: AccessKeyView, +}