From 8cdc06c1dd4d2a002bfe7e432f89fffccba4e6df Mon Sep 17 00:00:00 2001 From: nickwest Date: Sun, 8 Oct 2023 02:18:13 -0700 Subject: [PATCH] impl all rpc method in wasm --- bindings/wasm/src/error.rs | 55 ---- bindings/wasm/src/provider.rs | 180 +++++++++++- bindings/wasm/src/rpc.rs | 28 +- examples/Javascript/js-example/index.html | 3 +- examples/Javascript/js-example/index.js | 17 -- examples/Javascript/js-example/rpc.js | 62 ++++ provider/Cargo.toml | 2 + provider/src/error.rs | 2 + provider/src/response.rs | 1 + provider/src/rpc_wasm.rs | 327 +++++++++++++++++----- 10 files changed, 535 insertions(+), 142 deletions(-) delete mode 100644 bindings/wasm/src/error.rs delete mode 100644 examples/Javascript/js-example/index.js create mode 100644 examples/Javascript/js-example/rpc.js diff --git a/bindings/wasm/src/error.rs b/bindings/wasm/src/error.rs deleted file mode 100644 index 310fed7c..00000000 --- a/bindings/wasm/src/error.rs +++ /dev/null @@ -1,55 +0,0 @@ -use thiserror::Error; -use zklink_sdk_provider::RpcError; -use zklink_sdk_signers::eth_signer::error::EthSignerError; -use zklink_sdk_signers::zklink_signer::error::ZkSignerError; -use zklink_sdk_types::basic_types::ChainId; -use wasm_bindgen::JsValue; - -#[derive(Debug, Error)] -pub enum ClientError { - #[error("Network '{0}' is not supported")] - NetworkNotSupported(ChainId), - #[error("Unable to decode server response: {0}")] - MalformedResponse(String), - #[error("RPC error: {0:?}")] - RpcError(#[from] RpcError), - #[error("Network error: {0}")] - NetworkError(String), - - #[error("Provided account credentials are incorrect")] - IncorrectCredentials, - #[error("Seed too short, must be at least 32 bytes long")] - SeedTooShort, - #[error("Token is not supported by zkLink")] - UnknownToken, - #[error("Incorrect address")] - IncorrectAddress, - - #[error("Operation timeout")] - OperationTimeout, - #[error("Polling interval is too small")] - PollingIntervalIsTooSmall, - - #[error("EthSigning error: {0}")] - EthSigningError(#[from] EthSignerError), - #[error("ZkSigning error: {0}")] - ZkSigningError(#[from] ZkSignerError), - #[error("Missing required field for a transaction: {0}")] - MissingRequiredField(String), - - #[error("Ethereum private key was not provided for this wallet")] - NoEthereumPrivateKey, - - #[error("Provided value is not packable")] - NotPackableValue, - #[error("Non-zero subAccountId required submitter signer")] - MissSubmitterSigner, - #[error("Incorrect tx format")] - IncorrectTx, -} - -impl From for JsValue { - fn from(error: ClientError) -> Self { - JsValue::from_str(&format!("error: {error}")) - } -} diff --git a/bindings/wasm/src/provider.rs b/bindings/wasm/src/provider.rs index b69657fa..97712845 100644 --- a/bindings/wasm/src/provider.rs +++ b/bindings/wasm/src/provider.rs @@ -1,14 +1,21 @@ -use crate::rpc::{AccountQueryParam, SignedTransaction, TxL1Signature}; +use crate::rpc::{AccountQueryParam, L2TxType, SignedTransaction, TxL1Signature}; use std::collections::HashMap; use std::str::FromStr; use wasm_bindgen::prelude::wasm_bindgen; use wasm_bindgen::JsValue; +use zklink_sdk_provider::error::RpcError; use zklink_sdk_provider::network::Network; -use zklink_sdk_provider::response::{AccountSnapshotResp, TokenResp}; +use zklink_sdk_provider::response::{ + AccountInfoResp, AccountSnapshotResp, BlockNumberResp, BlockOnChainResp, BlockResp, ChainResp, + FastWithdrawTxResp, ForwardTxResp, Page, SubAccountBalances, SubAccountOrders, TokenResp, + TxHashOrDetailResp, TxResp, ZkLinkTxHistory, +}; use zklink_sdk_provider::rpc_wasm::WasmRpcClient; use zklink_sdk_signers::zklink_signer::ZkLinkSignature; +use zklink_sdk_types::basic_types::bigunit_wrapper::BigUintSerdeWrapper; use zklink_sdk_types::basic_types::tx_hash::TxHash; -use zklink_sdk_types::basic_types::{BlockNumber, SubAccountId, TokenId}; +use zklink_sdk_types::basic_types::{AccountId, BlockNumber, ChainId, SubAccountId, TokenId}; +use zklink_sdk_types::prelude::ZkLinkAddress; #[wasm_bindgen] pub struct Provider { @@ -26,13 +33,13 @@ impl Provider { } } - #[wasm_bindgen] + #[wasm_bindgen(js_name=getSupportTokens)] pub async fn tokens(&self) -> Result { let result: HashMap = self.client.tokens().await?; Ok(serde_wasm_bindgen::to_value(&result)?) } - #[wasm_bindgen(js_name=accountQuery)] + #[wasm_bindgen(js_name=getAccountSnapshot)] pub async fn account_query( &self, account_query: AccountQueryParam, @@ -67,4 +74,167 @@ impl Provider { .await?; Ok(result.as_hex()) } + + #[wasm_bindgen(js_name=getSupportChains)] + pub async fn get_support_chains(&self) -> Result { + let result: Vec = self.client.get_support_chains().await?; + Ok(serde_wasm_bindgen::to_value(&result)?) + } + + #[wasm_bindgen(js_name=getLatestBlockNumber)] + pub async fn block_info(&self) -> Result { + let result: BlockNumberResp = self.client.block_info().await?; + Ok(serde_wasm_bindgen::to_value(&result)?) + } + + #[wasm_bindgen(js_name=getBlockByNumber)] + pub async fn block_detail( + &self, + block_number: Option, + include_tx: bool, + include_update: bool, + ) -> Result { + let result: BlockResp = self + .client + .block_detail( + block_number.map(|b| BlockNumber(b)), + include_tx, + include_update, + ) + .await?; + Ok(serde_wasm_bindgen::to_value(&result)?) + } + + #[wasm_bindgen(js_name=getPendingBlock)] + pub async fn pending_block_detail( + &self, + last_tx_timestamp_micro: u64, + include_tx: bool, + include_update: bool, + limit: Option, + ) -> Result { + let result: Vec = self + .client + .pending_block_detail(last_tx_timestamp_micro, include_tx, include_update, limit) + .await?; + Ok(serde_wasm_bindgen::to_value(&result)?) + } + + #[wasm_bindgen(js_name=getBlockOnChainByNumber)] + pub async fn block_onchain_detail(&self, block_number: u32) -> Result { + let result: BlockOnChainResp = self + .client + .block_onchain_detail(BlockNumber(block_number)) + .await?; + Ok(serde_wasm_bindgen::to_value(&result)?) + } + + #[wasm_bindgen(js_name=getAccount)] + pub async fn account_info(&self, account_query: AccountQueryParam) -> Result { + let result: AccountInfoResp = self.client.account_info(account_query.into()).await?; + Ok(serde_wasm_bindgen::to_value(&result)?) + } + + #[wasm_bindgen(js_name=getAccountBalances)] + pub async fn account_balances( + &self, + account_id: u32, + sub_account_id: Option, + ) -> Result { + let result: SubAccountBalances = self + .client + .account_balances( + AccountId(account_id), + sub_account_id.map(|id| SubAccountId(id)), + ) + .await?; + Ok(serde_wasm_bindgen::to_value(&result)?) + } + + #[wasm_bindgen(js_name=getAccountOrderSlots)] + pub async fn account_order_slots( + &self, + account_id: u32, + sub_account_id: Option, + ) -> Result { + let result: SubAccountOrders = self + .client + .account_order_slots( + AccountId(account_id), + sub_account_id.map(|id| SubAccountId(id)), + ) + .await?; + Ok(serde_wasm_bindgen::to_value(&result)?) + } + + #[wasm_bindgen(js_name=getTokenReserve)] + pub async fn token_remain(&self, token_id: u32, mapping: bool) -> Result { + let result: HashMap = + self.client.token_remain(TokenId(token_id), mapping).await?; + Ok(serde_wasm_bindgen::to_value(&result)?) + } + + #[wasm_bindgen(js_name=getTransactionByHash)] + pub async fn tx_info(&self, hash: String, include_update: bool) -> Result { + let hash = TxHash::from_hex(&hash).map_err(|_e| RpcError::InvalidInputParameter)?; + let result: TxResp = self.client.tx_info(hash, include_update).await?; + Ok(serde_wasm_bindgen::to_value(&result)?) + } + + #[wasm_bindgen(js_name=getAccountTransactionHistory)] + pub async fn tx_history( + &self, + tx_type: L2TxType, + address: String, + page_index: u64, + page_size: u32, + ) -> Result { + let address = + ZkLinkAddress::from_hex(&address).map_err(|_e| RpcError::InvalidInputParameter)?; + let result: Page = self + .client + .tx_history(tx_type.into(), address, page_index, page_size) + .await?; + Ok(serde_wasm_bindgen::to_value(&result)?) + } + + #[wasm_bindgen(js_name=getFastWithdrawTxs)] + pub async fn tx_fast_withdraw( + &self, + last_tx_timestamp: u64, + max_txs: u32, + ) -> Result { + let result: Vec = self + .client + .tx_fast_withdraw(last_tx_timestamp, max_txs) + .await?; + Ok(serde_wasm_bindgen::to_value(&result)?) + } + + #[wasm_bindgen(js_name=pullForwardTxs)] + pub async fn pull_forward_txs( + &self, + sub_account_id: u8, + offset_id: i64, + limit: i64, + ) -> Result { + let result: Vec = self + .client + .pull_forward_txs(SubAccountId(sub_account_id), offset_id, limit) + .await?; + Ok(serde_wasm_bindgen::to_value(&result)?) + } + + #[wasm_bindgen(js_name=confirmFullExit)] + pub async fn confirm_full_exit( + &self, + tx_hash: String, + submitter_signature: String, + ) -> Result { + let hash = TxHash::from_hex(&tx_hash).map_err(|_e| RpcError::InvalidInputParameter)?; + let signature = ZkLinkSignature::from_hex(&submitter_signature) + .map_err(|_e| RpcError::InvalidInputParameter)?; + let result: bool = self.client.confirm_full_exit(hash, signature).await?; + Ok(result) + } } diff --git a/bindings/wasm/src/rpc.rs b/bindings/wasm/src/rpc.rs index 92826c5f..a170eb4f 100644 --- a/bindings/wasm/src/rpc.rs +++ b/bindings/wasm/src/rpc.rs @@ -9,7 +9,7 @@ use zklink_sdk_types::prelude::ZkLinkAddress; use zklink_sdk_types::signatures::TxLayer1Signature; use zklink_sdk_types::tx_type::change_pubkey::ChangePubKey; use zklink_sdk_types::tx_type::transfer::Transfer; -use zklink_sdk_types::tx_type::zklink_tx::ZkLinkTx; +use zklink_sdk_types::tx_type::zklink_tx::{ZkLinkTx, ZkLinkTxType}; #[wasm_bindgen] #[derive(Copy, Clone)] @@ -44,6 +44,17 @@ pub struct SignedTransaction { tx: JsValue, } +#[wasm_bindgen] +pub enum L2TxType { + Deposit, + FullExit, + ChangePubKey, + Transfer, + Withdraw, + ForcedExit, + OrderMatching, +} + #[wasm_bindgen] impl AccountQueryParam { #[wasm_bindgen(constructor)] @@ -102,6 +113,7 @@ impl SignedTransaction { SignedTransaction { tx_type, tx } } } + impl From for ZkLinkTx { fn from(tx: SignedTransaction) -> ZkLinkTx { match tx.tx_type { @@ -119,3 +131,17 @@ impl From for ZkLinkTx { } } } + +impl From for ZkLinkTxType { + fn from(tx_type: L2TxType) -> ZkLinkTxType { + match tx_type { + L2TxType::Deposit => ZkLinkTxType::Deposit, + L2TxType::Transfer => ZkLinkTxType::Transfer, + L2TxType::ChangePubKey => ZkLinkTxType::ChangePubKey, + L2TxType::OrderMatching => ZkLinkTxType::OrderMatching, + L2TxType::FullExit => ZkLinkTxType::FullExit, + L2TxType::ForcedExit => ZkLinkTxType::ForcedExit, + L2TxType::Withdraw => ZkLinkTxType::Withdraw, + } + } +} diff --git a/examples/Javascript/js-example/index.html b/examples/Javascript/js-example/index.html index 10de3d41..44271a6f 100644 --- a/examples/Javascript/js-example/index.html +++ b/examples/Javascript/js-example/index.html @@ -6,7 +6,8 @@ - \ No newline at end of file diff --git a/examples/Javascript/js-example/index.js b/examples/Javascript/js-example/index.js deleted file mode 100644 index 06167478..00000000 --- a/examples/Javascript/js-example/index.js +++ /dev/null @@ -1,17 +0,0 @@ -import init, { ZklinkSignerWasm } from "./web-dist/zklink-sdk-web.js"; - -async function main() { - await init(); - const signer = ZklinkSignerWasm.NewFromEthSigner("be725250b123a39dab5b7579334d5888987c72a58f4508062545fe6e08ca94f4"); - const msg_str = "hello world!"; - const msg = new TextEncoder().encode(msg_str); - try { - let signature = signer.sign(msg); - console.log(signature); - } catch (error) { - console.error(error); - } - -} - -main(); diff --git a/examples/Javascript/js-example/rpc.js b/examples/Javascript/js-example/rpc.js new file mode 100644 index 00000000..f435d8e3 --- /dev/null +++ b/examples/Javascript/js-example/rpc.js @@ -0,0 +1,62 @@ +import init, * as wasm from "./web-dist/zklink-sdk-web.js"; +async function main() { + await init(); + try { + let provider = new wasm.Provider("mainet"); + // 1.getSupportTokens + let tokens = await provider.getSupportTokens(); + console.log(tokens); + // 2.getAccountSnapshot + let account_id = new wasm.AccountQueryParam(wasm.AccountQueryType.AccountId, "5"); + let sub_account_id = 1; + // let block_number = 100; + let account_resp = await provider.getAccountSnapshot(account_id,sub_account_id,null); + console.log(account_resp); + // 3.sendTransaction(test on the tx example) + // 4.getSupportChains + let chains = await provider.getSupportChains(); + console.log(chains); + // 5.getLatestBlockNumber + let block_info = await provider.getLatestBlockNumber(); + console.log(block_info); + // 6.getBlockByNumber + let block_detail = await provider.getBlockByNumber(100,true,true); + console.log(block_detail); + // 7.getPendingBlock + let pending_block_info = await provider.getPendingBlock(1696743981000n,true,true,null); + console.log(pending_block_info); + // 8.getBlockOnChainByNumber + let on_chain_block_info = await provider.getBlockOnChainByNumber(100); + console.log(on_chain_block_info); + // 9.getAccount + let get_account_id = new wasm.AccountQueryParam(wasm.AccountQueryType.AccountId, "10"); + let account = await provider.getAccount(get_account_id); + console.log(account); + // 10.getAccountBalances + let balances = await provider.getAccountBalances(20,1); + console.log(balances); + // 11.getAccountOrderSlots + let slots = await provider.getAccountOrderSlots(20,1); + console.log(slots); + // 12.getTokenReserve + let reserve = await provider.getTokenReserve(18,false); + console.log(reserve); + // 13.getTransactionByHash + let tx_hash = "0x0cbeabac1a2257fb095c2465e148570e32793345442b39bf64cad4ed87475f9b"; + let tx_info = await provider.getTransactionByHash(tx_hash,false); + console.log(tx_info); + // 14.getAccountTransactionHistory + let history = await provider.getAccountTransactionHistory(wasm.L2TxType.Deposit,"0x12aFF993702B5d623977A9044686Fa1A2B0c2147",0n,5); + console.log(history); + // 15.getFastWithdrawTxs + let fast_withdraw_txs = await provider.getFastWithdrawTxs(1696743981000n,10); + console.log(fast_withdraw_txs); + // 16.pullForwardTxs + // 17.confirmFullExit + } catch (error) { + console.error(error); + } + +} + +main(); diff --git a/provider/Cargo.toml b/provider/Cargo.toml index 78ea8ef3..af31f504 100644 --- a/provider/Cargo.toml +++ b/provider/Cargo.toml @@ -20,6 +20,8 @@ jsonrpsee = { version = "0.20.1", features = ["http-client","macros"] } [target.'cfg(target_arch = "wasm32")'.dependencies] jsonrpsee = { version = "0.20.1", features = ["macros","jsonrpsee-types","client-core"] } +getrandom = { version = "0.2.10", features = ["js"] } +uuid = "0.8" [dev-dependencies] serde_json = "1.0" diff --git a/provider/src/error.rs b/provider/src/error.rs index 19a79a97..80f33d75 100644 --- a/provider/src/error.rs +++ b/provider/src/error.rs @@ -5,6 +5,8 @@ use thiserror::Error; pub enum RpcError { #[error("Invalid network")] InvalidNetwork, + #[error("Invalid input parameter")] + InvalidInputParameter, #[error("Parse params error: {0}")] ParseParamsError(jsonrpseeError), #[error("HTTP request error: {0}")] diff --git a/provider/src/response.rs b/provider/src/response.rs index a339ca32..49706a46 100644 --- a/provider/src/response.rs +++ b/provider/src/response.rs @@ -279,5 +279,6 @@ pub struct ZkLinkTxHistory { pub tx: ZkLinkTx, pub tx_hash: TxHash, pub tx_receipt: TxReceiptResp, + #[serde(with = "ts_microseconds")] pub created_at: DateTime, } diff --git a/provider/src/rpc_wasm.rs b/provider/src/rpc_wasm.rs index 0f05d66b..9a3de3e8 100644 --- a/provider/src/rpc_wasm.rs +++ b/provider/src/rpc_wasm.rs @@ -1,5 +1,10 @@ use crate::error::RpcError; -use crate::response::{AccountQuery, AccountSnapshotResp, TokenResp}; +use crate::response::{ + AccountInfoResp, AccountQuery, AccountSnapshotResp, BlockNumberResp, BlockOnChainResp, + BlockResp, ChainResp, FastWithdrawTxResp, ForwardTxResp, Page, SubAccountBalances, + SubAccountOrders, TokenResp, TxHashOrDetailResp, TxResp, ZkLinkTxHistory, +}; +use getrandom::getrandom; use jsonrpsee::core::params::ArrayParams; use jsonrpsee::core::traits::ToRpcParams; use jsonrpsee::types::request::Request; @@ -7,10 +12,13 @@ use jsonrpsee::types::Id; use std::collections::HashMap; use wasm_bindgen::JsValue; use zklink_sdk_signers::zklink_signer::ZkLinkSignature; -use zklink_sdk_types::basic_types::{BlockNumber, SubAccountId, TokenId}; +use zklink_sdk_types::basic_types::bigunit_wrapper::BigUintSerdeWrapper; +use zklink_sdk_types::basic_types::{ + AccountId, BlockNumber, ChainId, SubAccountId, TokenId, ZkLinkAddress, +}; use zklink_sdk_types::prelude::TxHash; use zklink_sdk_types::signatures::TxLayer1Signature; -use zklink_sdk_types::tx_type::zklink_tx::ZkLinkTx; +use zklink_sdk_types::tx_type::zklink_tx::{ZkLinkTx, ZkLinkTxType}; impl From for JsValue { fn from(error: RpcError) -> Self { @@ -18,19 +26,18 @@ impl From for JsValue { } } -pub struct WasmRpcClient { - pub server_url: String, -} - -impl WasmRpcClient { - pub fn new(server_url: String) -> Self { - Self { server_url } - } - - pub async fn tokens(&self) -> Result, RpcError> { - let request = Request::new("getSupportTokens".into(), None, Id::Number(1)); +macro_rules! make_rpc_request { + ($method:expr,$builder:expr, $server_url:expr, $resp_type: ty) => {{ + let params = $builder + .to_rpc_params() + .map_err(RpcError::ParseParamsError)?; + let request = Request::new( + $method.into(), + params.as_ref().map(|p| p.as_ref()), + Id::Str(uuid_str().into()), + ); let res = reqwest::Client::new() - .post(&self.server_url) + .post($server_url) .json(&request) .send() .await @@ -45,6 +52,33 @@ impl WasmRpcClient { } else { Err(RpcError::ParseJsonError) } + }}; +} + +pub fn uuid_str() -> String { + let mut bytes = [0; 16]; + getrandom(&mut bytes).expect("RNG failure!"); + + let uuid = uuid::Builder::from_bytes(bytes) + .set_variant(uuid::Variant::RFC4122) + .set_version(uuid::Version::Random) + .build(); + + uuid.to_string() +} + +pub struct WasmRpcClient { + pub server_url: String, +} + +impl WasmRpcClient { + pub fn new(server_url: String) -> Self { + Self { server_url } + } + + pub async fn tokens(&self) -> Result, RpcError> { + let builder = ArrayParams::new(); + make_rpc_request!("getSupportTokens",builder,&self.server_url,HashMap) } pub async fn account_query( @@ -57,30 +91,12 @@ impl WasmRpcClient { let _ = builder.insert(account_query); let _ = builder.insert(sub_account_id); let _ = builder.insert(block_number); - let params = builder - .to_rpc_params() - .map_err(RpcError::ParseParamsError)?; - let request = Request::new( - "getAccountSnapshot".into(), - params.as_ref().map(|p| p.as_ref()), - Id::Number(1), - ); - let res = reqwest::Client::new() - .post(&self.server_url) - .json(&request) - .send() - .await - .map_err(RpcError::RequestError)? - .json::>() - .await - .map_err(RpcError::ResponseError)?; - if let Some(&ref result) = res.get("result") { - let resp: AccountSnapshotResp = - serde_json::from_value(result.clone()).map_err(|_e| RpcError::ParseJsonError)?; - Ok(resp) - } else { - Err(RpcError::ParseJsonError) - } + make_rpc_request!( + "getAccountSnapshot", + builder, + &self.server_url, + AccountSnapshotResp + ) } pub async fn send_transaction( @@ -93,30 +109,198 @@ impl WasmRpcClient { let _ = builder.insert(tx); let _ = builder.insert(eth_signature); let _ = builder.insert(submitter_signature); - let params = builder - .to_rpc_params() - .map_err(RpcError::ParseParamsError)?; - let request = Request::new( - "sendTransaction".into(), - params.as_ref().map(|p| p.as_ref()), - Id::Number(0), - ); - let res = reqwest::Client::new() - .post(&self.server_url) - .json(&request) - .send() - .await - .map_err(RpcError::RequestError)? - .json::>() - .await - .map_err(RpcError::ResponseError)?; - if let Some(&ref result) = res.get("result") { - let resp: TxHash = - serde_json::from_value(result.clone()).map_err(|_e| RpcError::ParseJsonError)?; - Ok(resp) - } else { - Err(RpcError::ParseJsonError) - } + make_rpc_request!("sendTransaction", builder, &self.server_url, TxHash) + } + + pub async fn get_support_chains(&self) -> Result, RpcError> { + let builder = ArrayParams::new(); + make_rpc_request!( + "getSupportChains", + builder, + &self.server_url, + Vec + ) + } + + pub async fn block_info(&self) -> Result { + let builder = ArrayParams::new(); + make_rpc_request!( + "getLatestBlockNumber", + builder, + &self.server_url, + BlockNumberResp + ) + } + + pub async fn block_detail( + &self, + block_number: Option, + include_tx: bool, + include_update: bool, + ) -> Result { + let mut builder = ArrayParams::new(); + let _ = builder.insert(block_number); + let _ = builder.insert(include_tx); + let _ = builder.insert(include_update); + make_rpc_request!("getBlockByNumber", builder, &self.server_url, BlockResp) + } + + pub async fn pending_block_detail( + &self, + last_tx_timestamp_micro: u64, + include_tx: bool, + include_update: bool, + limit: Option, + ) -> Result, RpcError> { + let mut builder = ArrayParams::new(); + let _ = builder.insert(last_tx_timestamp_micro); + let _ = builder.insert(include_tx); + let _ = builder.insert(include_update); + let _ = builder.insert(limit); + make_rpc_request!( + "getPendingBlock", + builder, + &self.server_url, + Vec + ) + } + + pub async fn block_onchain_detail( + &self, + block_number: BlockNumber, + ) -> Result { + let mut builder = ArrayParams::new(); + let _ = builder.insert(block_number); + make_rpc_request!( + "getBlockOnChainByNumber", + builder, + &self.server_url, + BlockOnChainResp + ) + } + + pub async fn account_info( + &self, + account_query: AccountQuery, + ) -> Result { + let mut builder = ArrayParams::new(); + let _ = builder.insert(account_query); + make_rpc_request!("getAccount", builder, &self.server_url, AccountInfoResp) + } + + pub async fn account_balances( + &self, + account_id: AccountId, + sub_account_id: Option, + ) -> Result { + let mut builder = ArrayParams::new(); + let _ = builder.insert(account_id); + let _ = builder.insert(sub_account_id); + make_rpc_request!( + "getAccountBalances", + builder, + &self.server_url, + SubAccountBalances + ) + } + + pub async fn account_order_slots( + &self, + account_id: AccountId, + sub_account_id: Option, + ) -> Result { + let mut builder = ArrayParams::new(); + let _ = builder.insert(account_id); + let _ = builder.insert(sub_account_id); + make_rpc_request!( + "getAccountOrderSlots", + builder, + &self.server_url, + SubAccountOrders + ) + } + + pub async fn token_remain( + &self, + token_id: TokenId, + mapping: bool, + ) -> Result, RpcError> { + let mut builder = ArrayParams::new(); + let _ = builder.insert(token_id); + let _ = builder.insert(mapping); + make_rpc_request!("getTokenReserve",builder,&self.server_url,HashMap) + } + + pub async fn tx_info(&self, hash: TxHash, include_update: bool) -> Result { + let mut builder = ArrayParams::new(); + let _ = builder.insert(hash); + let _ = builder.insert(include_update); + make_rpc_request!("getTransactionByHash", builder, &self.server_url, TxResp) + } + + pub async fn tx_history( + &self, + tx_type: ZkLinkTxType, + address: ZkLinkAddress, + page_index: u64, + page_size: u32, + ) -> Result, RpcError> { + let mut builder = ArrayParams::new(); + let _ = builder.insert(tx_type); + let _ = builder.insert(address); + let _ = builder.insert(page_index); + let _ = builder.insert(page_size); + make_rpc_request!( + "getAccountTransactionHistory", + builder, + &self.server_url, + Page + ) + } + + pub async fn tx_fast_withdraw( + &self, + last_tx_timestamp: u64, + max_txs: u32, + ) -> Result, RpcError> { + let mut builder = ArrayParams::new(); + let _ = builder.insert(last_tx_timestamp); + let _ = builder.insert(max_txs); + make_rpc_request!( + "getFastWithdrawTxs", + builder, + &self.server_url, + Vec + ) + } + + pub async fn pull_forward_txs( + &self, + sub_account_id: SubAccountId, + offset_id: i64, + limit: i64, + ) -> Result, RpcError> { + let mut builder = ArrayParams::new(); + let _ = builder.insert(sub_account_id); + let _ = builder.insert(offset_id); + let _ = builder.insert(limit); + make_rpc_request!( + "pullForwardTxs", + builder, + &self.server_url, + Vec + ) + } + + pub async fn confirm_full_exit( + &self, + tx_hash: TxHash, + submitter_signature: ZkLinkSignature, + ) -> Result { + let mut builder = ArrayParams::new(); + let _ = builder.insert(tx_hash); + let _ = builder.insert(submitter_signature); + make_rpc_request!("confirmFullExit", builder, &self.server_url, bool) } } @@ -124,6 +308,7 @@ impl WasmRpcClient { mod test { use super::WasmRpcClient; use crate::network::Network; + use crate::response::ZkLinkTxHistory; use crate::rpc::ZkLinkRpcClient; use crate::ZkLinkRpcProvider; use std::str::FromStr; @@ -135,6 +320,7 @@ mod test { use zklink_sdk_types::basic_types::{ AccountId, ChainId, Nonce, SubAccountId, TimeStamp, TokenId, ZkLinkAddress, }; + use zklink_sdk_types::prelude::ZkLinkTxType; use zklink_sdk_types::signatures::TxLayer1Signature; use zklink_sdk_types::tx_builder::{ChangePubKeyBuilder, TransferBuilder}; use zklink_sdk_types::tx_type::change_pubkey::ChangePubKey; @@ -149,6 +335,21 @@ mod test { println!("{:?}", ret); } + #[tokio::test] + async fn test_tx_history() { + let client = WasmRpcClient::new("https://api-v1.zk.link".to_owned()); + let ret = client + .tx_history( + ZkLinkTxType::Deposit, + ZkLinkAddress::from_hex("0x12aFF993702B5d623977A9044686Fa1A2B0c2147").unwrap(), + 0, + 1, + ) + .await + .unwrap(); + println!("{:?}", ret); + } + #[tokio::test] async fn test_send_change_pubkey() { let private_key = "be725250b123a39dab5b7579334d5888987c72a58f4508062545fe6e08ca94f4";