diff --git a/bindings/wasm/Cargo.toml b/bindings/wasm/Cargo.toml index 0ef83b3d..664c1351 100644 --- a/bindings/wasm/Cargo.toml +++ b/bindings/wasm/Cargo.toml @@ -11,14 +11,19 @@ crate-type = ["cdylib","rlib"] zklink_sdk_signers = { path = "../../signers" } zklink_sdk_types = { path = "../../types" } zklink_sdk_provider = { path = "../../provider" } +serde_json = "1.0" wasm-bindgen = { version = "0.2.87",features = ["serde-serialize"] } serde-wasm-bindgen = "0.5" getrandom = { version = "0.2.10", features = ["js"] } web-sys = "0.3" hex = "0.4.3" +reqwest = { version = "0.11", default-features = false, features = ["blocking", "json", "rustls-tls"] } [target.'cfg(target_arch = "wasm32")'.dependencies] wasm-bindgen-futures = "0.4" +jsonrpsee = { version = "0.20.1", features = ["macros","jsonrpsee-types","client-core"] } +uuid = "0.8" + [features] default = [] ffi = [] diff --git a/bindings/wasm/src/lib.rs b/bindings/wasm/src/lib.rs index 1a366db5..047377a2 100644 --- a/bindings/wasm/src/lib.rs +++ b/bindings/wasm/src/lib.rs @@ -1,7 +1,7 @@ #![cfg(target_arch = "wasm32")] pub mod crypto; -pub mod provider; -pub mod rpc; +pub mod rpc_client; +pub mod rpc_type_converter; pub mod tx_types; // pub mod wallet; // pub mod error; diff --git a/bindings/wasm/src/provider.rs b/bindings/wasm/src/provider.rs deleted file mode 100644 index 97712845..00000000 --- a/bindings/wasm/src/provider.rs +++ /dev/null @@ -1,240 +0,0 @@ -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::{ - 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::{AccountId, BlockNumber, ChainId, SubAccountId, TokenId}; -use zklink_sdk_types::prelude::ZkLinkAddress; - -#[wasm_bindgen] -pub struct Provider { - client: WasmRpcClient, -} - -#[wasm_bindgen] -impl Provider { - #[wasm_bindgen(constructor)] - pub fn new(network: &str) -> Provider { - Provider { - client: WasmRpcClient { - server_url: Network::from_str(network).unwrap().url().to_owned(), - }, - } - } - - #[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=getAccountSnapshot)] - pub async fn account_query( - &self, - account_query: AccountQueryParam, - sub_account_id: Option, - block_number: Option, - ) -> Result { - let result: AccountSnapshotResp = self - .client - .account_query( - account_query.into(), - sub_account_id.map(|id| SubAccountId(id)), - block_number.map(|number| BlockNumber(number)), - ) - .await?; - Ok(serde_wasm_bindgen::to_value(&result)?) - } - - #[wasm_bindgen(js_name=sendTransaction)] - pub async fn send_transaction( - &self, - tx: SignedTransaction, - l1_signature: Option, - l2_signature: Option, - ) -> Result { - let result: TxHash = self - .client - .send_transaction( - tx.into(), - l1_signature.map(|t| t.into()), - l2_signature.map(|s| ZkLinkSignature::from_hex(&s).unwrap()), - ) - .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_client.rs b/bindings/wasm/src/rpc_client.rs new file mode 100644 index 00000000..0b99e3f7 --- /dev/null +++ b/bindings/wasm/src/rpc_client.rs @@ -0,0 +1,321 @@ +use crate::rpc_type_converter::{AccountQueryParam, 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::{AccountInfoResp, AccountSnapshotResp, BlockNumberResp, BlockOnChainResp, BlockResp, ChainResp, FastWithdrawTxResp, ForwardTxResp, Page, SubAccountBalances, SubAccountOrders, TokenResp, TxHashOrDetailResp, TxResp, ZkLinkTxHistory, AccountQuery}; +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::{AccountId, BlockNumber, ChainId, SubAccountId, TokenId}; +use zklink_sdk_types::prelude::ZkLinkAddress; +use zklink_sdk_types::tx_type::zklink_tx::ZkLinkTxType; +use getrandom::getrandom; +use jsonrpsee::core::params::ArrayParams; +use jsonrpsee::core::traits::ToRpcParams; +use jsonrpsee::types::request::Request; +use jsonrpsee::types::Id; +use zklink_sdk_types::signatures::TxLayer1Signature; +use zklink_sdk_types::tx_type::zklink_tx::ZkLinkTx; + +macro_rules! 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($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 = serde_json::from_value::<$resp_type>(result.clone()); + match resp { + Ok(resp) => { + Ok(serde_wasm_bindgen::to_value(&resp)?) + }, + Err(_e) => { + Err(RpcError::ParseJsonError.into()) + } + } + } else { + Err(RpcError::ParseJsonError.into()) + } + }}; +} + +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() +} + +#[wasm_bindgen] +pub struct RpcClient { + server_url: String, +} + +#[wasm_bindgen] +impl RpcClient { + #[wasm_bindgen(constructor)] + pub fn new(network: &str) -> RpcClient { + RpcClient { + server_url: Network::from_str(network).unwrap().url().to_owned(), + } + } + + #[wasm_bindgen(js_name=getSupportTokens)] + pub async fn tokens(&self) -> Result { + let builder = ArrayParams::new(); + rpc_request!("getSupportTokens",builder,&self.server_url,HashMap) + } + + #[wasm_bindgen(js_name=getAccountSnapshot)] + pub async fn account_query( + &self, + account_query: AccountQueryParam, + sub_account_id: Option, + block_number: Option, + ) -> Result { + let mut builder = ArrayParams::new(); + let _ = builder.insert(AccountQuery::from(account_query)); + let _ = builder.insert(sub_account_id.map(|id| SubAccountId(id)),); + let _ = builder.insert(block_number.map(|number| BlockNumber(number))); + rpc_request!( + "getAccountSnapshot", + builder, + &self.server_url, + AccountSnapshotResp + ) + } + + #[wasm_bindgen(js_name=sendTransaction)] + pub async fn send_transaction( + &self, + tx: SignedTransaction, + l1_signature: Option, + l2_signature: Option, + ) -> Result { + let mut builder = ArrayParams::new(); + let _ = builder.insert(ZkLinkTx::from(tx)); + let _ = builder.insert(l1_signature.map(|t| TxLayer1Signature::from(t))); + let _ = builder.insert(l2_signature.map(|s| ZkLinkSignature::from_hex(&s).unwrap())); + rpc_request!("sendTransaction", builder, &self.server_url, TxHash) + } + + #[wasm_bindgen(js_name=getSupportChains)] + pub async fn get_support_chains(&self) -> Result { + let builder = ArrayParams::new(); + rpc_request!( + "getSupportChains", + builder, + &self.server_url, + Vec + ) + } + + #[wasm_bindgen(js_name=getLatestBlockNumber)] + pub async fn block_info(&self) -> Result { + let builder = ArrayParams::new(); + rpc_request!( + "getLatestBlockNumber", + builder, + &self.server_url, + BlockNumberResp + ) + } + + #[wasm_bindgen(js_name=getBlockByNumber)] + 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.map(|b| BlockNumber(b))); + let _ = builder.insert(include_tx); + let _ = builder.insert(include_update); + rpc_request!("getBlockByNumber", builder, &self.server_url, BlockResp) + } + + #[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 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); + rpc_request!( + "getPendingBlock", + builder, + &self.server_url, + Vec + ) + } + + #[wasm_bindgen(js_name=getBlockOnChainByNumber)] + pub async fn block_onchain_detail(&self, block_number: u32) -> Result { + let mut builder = ArrayParams::new(); + let _ = builder.insert(BlockNumber(block_number)); + rpc_request!( + "getBlockOnChainByNumber", + builder, + &self.server_url, + BlockOnChainResp + ) + } + + #[wasm_bindgen(js_name=getAccount)] + pub async fn account_info(&self, account_query: AccountQueryParam) -> Result { + let mut builder = ArrayParams::new(); + let _ = builder.insert(AccountQuery::from(account_query)); + rpc_request!("getAccount", builder, &self.server_url, AccountInfoResp) + } + + #[wasm_bindgen(js_name=getAccountBalances)] + pub async fn account_balances( + &self, + account_id: u32, + sub_account_id: Option, + ) -> Result { + let mut builder = ArrayParams::new(); + let _ = builder.insert(AccountId(account_id)); + let _ = builder.insert(sub_account_id.map(|id| SubAccountId(id))); + rpc_request!( + "getAccountBalances", + builder, + &self.server_url, + SubAccountBalances + ) + } + + #[wasm_bindgen(js_name=getAccountOrderSlots)] + pub async fn account_order_slots( + &self, + account_id: u32, + sub_account_id: Option, + ) -> Result { + let mut builder = ArrayParams::new(); + let _ = builder.insert(AccountId(account_id)); + let _ = builder.insert(sub_account_id.map(|id| SubAccountId(id))); + rpc_request!( + "getAccountOrderSlots", + builder, + &self.server_url, + SubAccountOrders + ) + } + + #[wasm_bindgen(js_name=getTokenReserve)] + pub async fn token_remain(&self, token_id: u32, mapping: bool) -> Result { + let mut builder = ArrayParams::new(); + let _ = builder.insert(TokenId(token_id)); + let _ = builder.insert(mapping); + rpc_request!("getTokenReserve",builder,&self.server_url,HashMap) + } + + #[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 mut builder = ArrayParams::new(); + let _ = builder.insert(hash); + let _ = builder.insert(include_update); + rpc_request!("getTransactionByHash", builder, &self.server_url, TxResp) + } + + #[wasm_bindgen(js_name=getAccountTransactionHistory)] + pub async fn tx_history( + &self, + tx_type: ZkLinkTxType, + address: String, + page_index: u64, + page_size: u32, + ) -> Result { + let address = + ZkLinkAddress::from_hex(&address).map_err(|_e| RpcError::InvalidInputParameter)?; + let mut builder = ArrayParams::new(); + let _ = builder.insert(tx_type); + let _ = builder.insert(address); + let _ = builder.insert(page_index); + let _ = builder.insert(page_size); + rpc_request!( + "getAccountTransactionHistory", + builder, + &self.server_url, + Page + ) + } + + #[wasm_bindgen(js_name=getFastWithdrawTxs)] + pub async fn tx_fast_withdraw( + &self, + last_tx_timestamp: u64, + max_txs: u32, + ) -> Result { + let mut builder = ArrayParams::new(); + let _ = builder.insert(last_tx_timestamp); + let _ = builder.insert(max_txs); + rpc_request!( + "getFastWithdrawTxs", + builder, + &self.server_url, + Vec + ) + } + + #[wasm_bindgen(js_name=pullForwardTxs)] + pub async fn pull_forward_txs( + &self, + sub_account_id: u8, + offset_id: i64, + limit: i64, + ) -> Result { + let mut builder = ArrayParams::new(); + let _ = builder.insert(SubAccountId(sub_account_id)); + let _ = builder.insert(offset_id); + let _ = builder.insert(limit); + rpc_request!( + "pullForwardTxs", + builder, + &self.server_url, + Vec + ) + } + + #[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 mut builder = ArrayParams::new(); + let _ = builder.insert(hash); + let _ = builder.insert(submitter_signature); + rpc_request!("confirmFullExit", builder, &self.server_url, bool) + } +} diff --git a/bindings/wasm/src/rpc.rs b/bindings/wasm/src/rpc_type_converter.rs similarity index 81% rename from bindings/wasm/src/rpc.rs rename to bindings/wasm/src/rpc_type_converter.rs index a170eb4f..cf9a2ef6 100644 --- a/bindings/wasm/src/rpc.rs +++ b/bindings/wasm/src/rpc_type_converter.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, ZkLinkTxType}; +use zklink_sdk_types::tx_type::zklink_tx::ZkLinkTx; #[wasm_bindgen] #[derive(Copy, Clone)] @@ -44,17 +44,6 @@ pub struct SignedTransaction { tx: JsValue, } -#[wasm_bindgen] -pub enum L2TxType { - Deposit, - FullExit, - ChangePubKey, - Transfer, - Withdraw, - ForcedExit, - OrderMatching, -} - #[wasm_bindgen] impl AccountQueryParam { #[wasm_bindgen(constructor)] @@ -130,18 +119,4 @@ 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, - } - } -} +} \ No newline at end of file diff --git a/bindings/wasm/tests/test_provider.rs b/bindings/wasm/tests/test_provider.rs index aa70ad1b..d3966fcd 100644 --- a/bindings/wasm/tests/test_provider.rs +++ b/bindings/wasm/tests/test_provider.rs @@ -12,8 +12,8 @@ use zklink_sdk_types::tx_builder::ChangePubKeyBuilder; use zklink_sdk_types::tx_type::change_pubkey::ChangePubKey; use zklink_sdk_types::tx_type::zklink_tx::ZkLinkTx; use zklink_sdk_types::tx_type::ZkSignatureTrait; -use zklink_sdk_wasm::provider::Provider; -use zklink_sdk_wasm::rpc::{AccountQueryParam, AccountQueryType, SignedTransaction}; +use zklink_sdk_wasm::rpc_client::{Provider, RpcClient}; +use zklink_sdk_wasm::rpc_type_converter::{AccountQueryParam, AccountQueryType, SignedTransaction}; wasm_bindgen_test_configure!(run_in_worker); #[wasm_bindgen_test] @@ -44,7 +44,7 @@ async fn test_account_query() { #[wasm_bindgen_test] async fn test_send_change_pubkey() { web_sys::console::log_1(&JsValue::from_str("123")); - let provider = Provider::new("testnet"); + let client = RpcClient::new("testnet"); let private_key = "be725250b123a39dab5b7579334d5888987c72a58f4508062545fe6e08ca94f4"; let eth_signer = EthSigner::try_from(private_key).unwrap(); let zklink_signer = ZkLinkSigner::new_from_hex_eth_signer(private_key).unwrap(); @@ -89,7 +89,7 @@ async fn test_send_change_pubkey() { tx.sign(&zklink_signer).unwrap(); let submitter_signature = tx.signature.as_hex(); //send to zklink - let ret = provider + let ret = client .send_transaction( SignedTransaction::new( ChangePubKey::TX_TYPE, diff --git a/examples/Javascript/js-example/rpc.js b/examples/Javascript/js-example/rpc.js index f435d8e3..19702a3c 100644 --- a/examples/Javascript/js-example/rpc.js +++ b/examples/Javascript/js-example/rpc.js @@ -2,57 +2,58 @@ 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) + let client = new wasm.RpcClient("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(); + let chains = await client.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 + console.log(chains.length) + // // 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); } diff --git a/provider/src/error.rs b/provider/src/error.rs index 80f33d75..ea73a27d 100644 --- a/provider/src/error.rs +++ b/provider/src/error.rs @@ -1,5 +1,6 @@ use jsonrpsee::core::error::Error as jsonrpseeError; use thiserror::Error; +use wasm_bindgen::JsValue; #[derive(Debug, Error)] pub enum RpcError { @@ -16,3 +17,10 @@ pub enum RpcError { #[error("Parse json value error")] ParseJsonError, } + + +impl From for JsValue { + fn from(error: RpcError) -> Self { + JsValue::from_str(&format!("error: {error}")) + } +} \ No newline at end of file diff --git a/provider/src/lib.rs b/provider/src/lib.rs index ef57f599..56f1f87a 100644 --- a/provider/src/lib.rs +++ b/provider/src/lib.rs @@ -4,8 +4,6 @@ pub mod response; #[cfg(not(feature = "ffi"))] #[cfg(not(target_arch = "wasm32"))] pub mod rpc; -#[cfg(target_arch = "wasm32")] -pub mod rpc_wasm; #[cfg(not(feature = "ffi"))] #[cfg(not(target_arch = "wasm32"))] diff --git a/provider/src/rpc_wasm.rs b/provider/src/rpc_wasm.rs deleted file mode 100644 index 9a3de3e8..00000000 --- a/provider/src/rpc_wasm.rs +++ /dev/null @@ -1,463 +0,0 @@ -use crate::error::RpcError; -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; -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::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, ZkLinkTxType}; - -impl From for JsValue { - fn from(error: RpcError) -> Self { - JsValue::from_str(&format!("error: {error}")) - } -} - -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($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: HashMap = - serde_json::from_value(result.clone()).map_err(|_e| RpcError::ParseJsonError)?; - Ok(resp) - } 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( - &self, - account_query: AccountQuery, - sub_account_id: Option, - block_number: Option, - ) -> Result { - let mut builder = ArrayParams::new(); - let _ = builder.insert(account_query); - let _ = builder.insert(sub_account_id); - let _ = builder.insert(block_number); - make_rpc_request!( - "getAccountSnapshot", - builder, - &self.server_url, - AccountSnapshotResp - ) - } - - pub async fn send_transaction( - &self, - tx: ZkLinkTx, - eth_signature: Option, - submitter_signature: Option, - ) -> Result { - let mut builder = ArrayParams::new(); - let _ = builder.insert(tx); - let _ = builder.insert(eth_signature); - let _ = builder.insert(submitter_signature); - 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) - } -} - -#[cfg(test)] -mod test { - use super::WasmRpcClient; - use crate::network::Network; - use crate::response::ZkLinkTxHistory; - use crate::rpc::ZkLinkRpcClient; - use crate::ZkLinkRpcProvider; - use std::str::FromStr; - use std::sync::Arc; - use std::time::Duration; - use zklink_sdk_signers::eth_signer::EthSigner; - use zklink_sdk_signers::zklink_signer::{PubKeyHash, ZkLinkSigner}; - use zklink_sdk_types::basic_types::BigUint; - 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; - use zklink_sdk_types::tx_type::transfer::Transfer; - use zklink_sdk_types::tx_type::zklink_tx::ZkLinkTx; - use zklink_sdk_types::tx_type::ZkSignatureTrait; - - #[tokio::test] - async fn test_tokens() { - let client = WasmRpcClient::new("https://api-v1.zk.link".to_owned()); - let ret = client.tokens().await.unwrap(); - 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"; - let eth_signer = EthSigner::try_from(private_key).unwrap(); - let zklink_signer = ZkLinkSigner::new_from_hex_eth_signer(private_key).unwrap(); - let main_contract = "0x5505a8cD4594Dbf79d8C59C0Df1414AB871CA896"; - let l1_client_id = 80001; - let new_pubkey_hash = "0xd8d5fb6a6caef06aa3dc2abdcdc240987e5330fe"; - let ts = 1696595303; - //auth type 'ECDSA' - let builder = ChangePubKeyBuilder { - chain_id: ChainId(1), - account_id: AccountId(10), - sub_account_id: SubAccountId(1), - new_pubkey_hash: PubKeyHash::from_hex(new_pubkey_hash).unwrap(), - fee_token: TokenId(18), - fee: BigUint::from(100000000000000u64), - nonce: Nonce(1), - eth_signature: None, - timestamp: TimeStamp(ts), - }; - let mut change_pubkey = ChangePubKey::new(builder); - let message = change_pubkey - .to_eip712_request_payload( - l1_client_id, - &ZkLinkAddress::from_str(&main_contract).unwrap(), - ) - .unwrap(); - let signature = eth_signer - .sign_message(message.raw_data.as_bytes()) - .unwrap(); - let builder_with_sig = ChangePubKeyBuilder { - chain_id: ChainId(1), - account_id: AccountId(10), - sub_account_id: SubAccountId(1), - new_pubkey_hash: PubKeyHash::from_hex(new_pubkey_hash).unwrap(), - fee_token: TokenId(18), - fee: BigUint::from(100000000000000u64), - nonce: Nonce(1), - eth_signature: Some(signature), - timestamp: TimeStamp(ts), - }; - let mut tx = ChangePubKey::new(builder_with_sig); - tx.sign(&zklink_signer).unwrap(); - - // for wasm - // let client = WasmRpcClient::new("https://aws-gw-v2.zk.link".to_owned()); - // client.send_transaction(ZkLinkTx::ChangePubKey(Box::new(tx.clone())),None,Some(tx.signature.clone())).await.unwrap(); - - //use jsonrpsee - let client = ZkLinkRpcProvider::new(Network::TestNet, Duration::from_secs(3)); - let ret = client - .tx_submit( - ZkLinkTx::ChangePubKey(Box::new(tx.clone())), - None, - Some(tx.signature.clone()), - ) - .await - .unwrap(); - } - - #[tokio::test] - async fn test_send_transfer() { - let private_key = "be725250b123a39dab5b7579334d5888987c72a58f4508062545fe6e08ca94f4"; - let eth_signer = EthSigner::try_from(private_key).unwrap(); - let zklink_signer = ZkLinkSigner::new_from_hex_eth_signer(private_key).unwrap(); - let to_address = "0x5505a8cD4594Dbf79d8C59C0Df1414AB871CA896"; - let l1_client_id = 80001; - let ts = 1696595303; - //auth type 'ECDSA' - let builder = TransferBuilder { - account_id: AccountId(10), - to_address: ZkLinkAddress::from_str(to_address).unwrap(), - from_sub_account_id: SubAccountId(1), - to_sub_account_id: SubAccountId(1), - token: TokenId(18), - fee: BigUint::from(100000000000000u64), - nonce: Nonce(1), - timestamp: TimeStamp(ts), - amount: BigUint::from(1000000000000000u64), - }; - let mut transfer = Transfer::new(builder); - let eth_signature = eth_signer - .sign_message(transfer.get_eth_sign_msg("USDT").as_bytes()) - .unwrap(); - transfer.sign(&zklink_signer).unwrap(); - - let submiiter_signature = transfer - .submitter_signature(Arc::new(zklink_signer)) - .unwrap(); - // for wasm - let client = WasmRpcClient::new("https://aws-gw-v2.zk.link".to_owned()); - client - .send_transaction( - ZkLinkTx::Transfer(Box::new(transfer.clone())), - Some(TxLayer1Signature::EthereumSignature(eth_signature)), - Some(submiiter_signature), - ) - .await - .unwrap(); - - //use jsonrpsee - // let client = ZkLinkRpcProvider::new(Network::TestNet, Duration::from_secs(3)); - // let ret = client.tx_submit( - // ZkLinkTx::Transfer(Box::new(transfer.clone())), - // None, - // Some(transfer.signature.clone()) - // ) - // .await.unwrap(); - } -} diff --git a/signers/src/eth_signer/pk_signer.rs b/signers/src/eth_signer/pk_signer.rs index 807f344a..d48deaed 100644 --- a/signers/src/eth_signer/pk_signer.rs +++ b/signers/src/eth_signer/pk_signer.rs @@ -7,7 +7,9 @@ use ethers::types::transaction::eip2718::TypedTransaction; use ethers::types::TxHash; use ethers::utils::hash_message; use k256::ecdsa::SigningKey; +use wasm_bindgen::prelude::wasm_bindgen; +#[wasm_bindgen] #[derive(Clone)] pub struct EthSigner { private_key: H256, diff --git a/types/Cargo.toml b/types/Cargo.toml index 8bd93081..fe776dba 100644 --- a/types/Cargo.toml +++ b/types/Cargo.toml @@ -14,6 +14,7 @@ thiserror = "1.0" validator = { version = "0.15", features = ["derive"] } zklink_sdk_signers = { path = "../signers" } zklink_sdk_utils = { path = "../utils" } +wasm-bindgen = { version = "0.2.87", features = ["serde-serialize"] } [dev-dependencies] diff --git a/types/src/tx_type/zklink_tx.rs b/types/src/tx_type/zklink_tx.rs index efb21123..052d35b5 100644 --- a/types/src/tx_type/zklink_tx.rs +++ b/types/src/tx_type/zklink_tx.rs @@ -10,8 +10,10 @@ use crate::tx_type::order_matching::OrderMatching; use crate::tx_type::transfer::Transfer; use crate::tx_type::withdraw::Withdraw; use crate::tx_type::TxTrait; +use wasm_bindgen::prelude::wasm_bindgen; /// A set of L2 transaction type supported by the zklink network. +#[wasm_bindgen] #[derive(Debug, Clone, Serialize, Deserialize)] pub enum ZkLinkTxType { Deposit,