From 60c7aa6300fae76589555af8b4ac3c2709a548f7 Mon Sep 17 00:00:00 2001 From: Ivan Shumkov Date: Mon, 1 Dec 2025 18:24:52 +0700 Subject: [PATCH 1/7] feat(sdk): pre-fetch trusted address list --- packages/wasm-sdk/src/context_provider.rs | 23 + packages/wasm-sdk/src/dpns.rs | 64 +-- packages/wasm-sdk/src/sdk.rs | 501 +++------------------- 3 files changed, 94 insertions(+), 494 deletions(-) diff --git a/packages/wasm-sdk/src/context_provider.rs b/packages/wasm-sdk/src/context_provider.rs index aaea30430c8..2e1486a565d 100644 --- a/packages/wasm-sdk/src/context_provider.rs +++ b/packages/wasm-sdk/src/context_provider.rs @@ -134,6 +134,29 @@ impl WasmTrustedContext { }) } + pub async fn fetch_masternode_addresses( + &self, + ) -> Result { + let urls = self + .inner + .fetch_masternode_addresses() + .await + .map_err(|e| ContextProviderError::Generic(format!("Failed to fetch masternodes: {}", e)))?; + + let mut addresses = Vec::new(); + for url in urls { + let uri = dash_sdk::sdk::Uri::from_maybe_shared(url.to_string()).map_err(|e| { + ContextProviderError::Generic(format!("Invalid masternode URI '{}': {}", url, e)) + })?; + let address = rs_dapi_client::Address::try_from(uri).map_err(|e| { + ContextProviderError::Generic(format!("Invalid masternode address '{}': {}", url, e)) + })?; + addresses.push(address); + } + + Ok(rs_dapi_client::AddressList::from_iter(addresses)) + } + /// Add a data contract to the known contracts cache pub fn add_known_contract(&self, contract: DataContract) { self.inner.add_known_contract(contract); diff --git a/packages/wasm-sdk/src/dpns.rs b/packages/wasm-sdk/src/dpns.rs index 63ac7086701..2cd4a22d3f0 100644 --- a/packages/wasm-sdk/src/dpns.rs +++ b/packages/wasm-sdk/src/dpns.rs @@ -1,6 +1,6 @@ use crate::error::WasmSdkError; use crate::queries::utils::{deserialize_required_query, identifier_from_js}; -use crate::queries::{ProofInfoWasm, ProofMetadataResponseWasm, ResponseMetadataWasm}; +use crate::queries::ProofMetadataResponseWasm; use crate::sdk::WasmSdk; use dash_sdk::dpp::document::{Document, DocumentV0Getters}; use dash_sdk::dpp::identity::accessors::IdentityGettersV0; @@ -119,27 +119,6 @@ fn parse_dpns_usernames_query( }) } -#[wasm_bindgen(js_name = "DpnsUsernamesProofResponse")] -#[derive(Clone)] -pub struct DpnsUsernamesProofResponseWasm { - #[wasm_bindgen(getter_with_clone)] - pub usernames: Array, - #[wasm_bindgen(getter_with_clone)] - pub metadata: ResponseMetadataWasm, - #[wasm_bindgen(getter_with_clone)] - pub proof: ProofInfoWasm, -} - -#[wasm_bindgen(js_name = "DpnsUsernameProofResponse")] -#[derive(Clone)] -pub struct DpnsUsernameProofResponseWasm { - #[wasm_bindgen(getter_with_clone)] - pub username: JsValue, - #[wasm_bindgen(getter_with_clone)] - pub metadata: ResponseMetadataWasm, - #[wasm_bindgen(getter_with_clone)] - pub proof: ProofInfoWasm, -} impl WasmSdk { async fn prepare_dpns_usernames_query( &self, @@ -189,7 +168,7 @@ impl WasmSdk { &self, identity_id: Identifier, limit: Option, - ) -> Result { + ) -> Result { let query = self .prepare_dpns_usernames_query(identity_id, limit) .await?; @@ -197,11 +176,11 @@ impl WasmSdk { Document::fetch_many_with_metadata_and_proof(self.as_ref(), query, None).await?; let usernames_array = usernames_from_documents(documents_result); - Ok(DpnsUsernamesProofResponseWasm { - usernames: usernames_array, - metadata: metadata.into(), - proof: proof.into(), - }) + Ok(ProofMetadataResponseWasm::from_parts( + usernames_array.into(), + metadata.into(), + proof.into(), + )) } } @@ -480,43 +459,44 @@ impl WasmSdk { .map(Some) .ok_or_else(|| WasmSdkError::generic("DPNS username is not a string")) } - #[wasm_bindgen(js_name = "getDpnsUsernamesWithProofInfo")] + #[wasm_bindgen( + js_name = "getDpnsUsernamesWithProofInfo", + unchecked_return_type = "ProofMetadataResponseTyped>" + )] pub async fn get_dpns_usernames_with_proof_info( &self, query: DpnsUsernamesQueryJs, - ) -> Result { + ) -> Result { let params = parse_dpns_usernames_query(query)?; self.fetch_dpns_usernames_with_proof(params.identity_id, params.limit) .await } - #[wasm_bindgen(js_name = "getDpnsUsernameWithProofInfo")] + #[wasm_bindgen( + js_name = "getDpnsUsernameWithProofInfo", + unchecked_return_type = "ProofMetadataResponseTyped" + )] pub async fn get_dpns_username_with_proof_info( &self, #[wasm_bindgen(js_name = "identityId")] #[wasm_bindgen(unchecked_param_type = "IdentifierLike")] identity_id: JsValue, - ) -> Result { + ) -> Result { let identity_id_parsed = identifier_from_js(&identity_id, "identity ID")?; - let DpnsUsernamesProofResponseWasm { - usernames, - metadata, - proof, - } = self + let mut response = self .fetch_dpns_usernames_with_proof(identity_id_parsed, Some(1)) .await?; + let usernames = js_sys::Array::from(&response.data()); let username = if usernames.length() > 0 { usernames.get(0) } else { JsValue::NULL }; - Ok(DpnsUsernameProofResponseWasm { - username, - metadata, - proof, - }) + response.set_data(username); + + Ok(response) } } diff --git a/packages/wasm-sdk/src/sdk.rs b/packages/wasm-sdk/src/sdk.rs index 867c708848a..df54996c3ae 100644 --- a/packages/wasm-sdk/src/sdk.rs +++ b/packages/wasm-sdk/src/sdk.rs @@ -3,7 +3,7 @@ use crate::error::WasmSdkError; use dash_sdk::dpp::version::PlatformVersion; use dash_sdk::{Sdk, SdkBuilder}; use once_cell::sync::Lazy; -use rs_dapi_client::RequestSettings; +use rs_dapi_client::{Address, RequestSettings}; use std::ops::{Deref, DerefMut}; use std::sync::Mutex; use std::time::Duration; @@ -14,6 +14,26 @@ pub(crate) static MAINNET_TRUSTED_CONTEXT: Lazy< pub(crate) static TESTNET_TRUSTED_CONTEXT: Lazy< Mutex>, > = Lazy::new(|| Mutex::new(None)); +static MAINNET_DISCOVERED_ADDRESSES: Lazy>>> = + Lazy::new(|| Mutex::new(None)); +static TESTNET_DISCOVERED_ADDRESSES: Lazy>>> = + Lazy::new(|| Mutex::new(None)); + +async fn fetch_and_cache_addresses( + trusted_context: &crate::context_provider::WasmTrustedContext, + cache: &Lazy>>>, +) -> Result<(), WasmSdkError> { + let address_list = trusted_context + .fetch_masternode_addresses() + .await + .map_err(|e| WasmSdkError::generic(format!("Failed to fetch masternodes: {}", e)))?; + let addresses: Vec
= address_list + .into_iter() + .map(|(addr, _status)| addr) + .collect(); + *cache.lock().unwrap() = Some(addresses); + Ok(()) +} #[wasm_bindgen] pub struct WasmSdk(Sdk); @@ -75,6 +95,8 @@ impl WasmSdk { .await .map_err(|e| WasmSdkError::from(dash_sdk::Error::from(e)))?; + fetch_and_cache_addresses(&trusted_context, &MAINNET_DISCOVERED_ADDRESSES).await?; + // Store the context for later use *MAINNET_TRUSTED_CONTEXT.lock().unwrap() = Some(trusted_context); @@ -93,6 +115,8 @@ impl WasmSdk { .await .map_err(|e| WasmSdkError::from(dash_sdk::Error::from(e)))?; + fetch_and_cache_addresses(&trusted_context, &TESTNET_DISCOVERED_ADDRESSES).await?; + // Store the context for later use *TESTNET_TRUSTED_CONTEXT.lock().unwrap() = Some(trusted_context); @@ -143,7 +167,6 @@ impl WasmSdkBuilder { use crate::context_provider::WasmTrustedContext; use dash_sdk::dpp::dashcore::Network; use dash_sdk::sdk::Uri; - use rs_dapi_client::Address; // Parse and validate addresses if addresses.is_empty() { @@ -210,219 +233,9 @@ impl WasmSdkBuilder { #[wasm_bindgen(js_name = "mainnet")] pub fn new_mainnet() -> Self { - // Mainnet addresses from mnowatch.org - let mainnet_addresses = vec![ - "https://149.28.241.190:443".parse().unwrap(), - "https://198.7.115.48:443".parse().unwrap(), - "https://134.255.182.186:443".parse().unwrap(), - "https://93.115.172.39:443".parse().unwrap(), - "https://5.189.164.253:443".parse().unwrap(), - "https://178.215.237.134:443".parse().unwrap(), - "https://157.66.81.162:443".parse().unwrap(), - "https://173.212.232.90:443".parse().unwrap(), - "https://178.215.237.135:443".parse().unwrap(), - "https://5.182.33.231:443".parse().unwrap(), - "https://109.199.104.243:443".parse().unwrap(), - "https://37.60.236.212:443".parse().unwrap(), - "https://23.88.63.58:443".parse().unwrap(), - "https://207.244.247.40:443".parse().unwrap(), - "https://45.32.70.131:443".parse().unwrap(), - "https://158.220.122.76:443".parse().unwrap(), - "https://52.33.9.172:443".parse().unwrap(), - "https://194.163.166.185:443".parse().unwrap(), - "https://185.158.107.124:443".parse().unwrap(), - "https://185.198.234.17:443".parse().unwrap(), - "https://93.190.140.101:443".parse().unwrap(), - "https://194.163.153.225:443".parse().unwrap(), - "https://194.146.13.7:443".parse().unwrap(), - "https://158.247.208.247:443".parse().unwrap(), - "https://93.190.140.112:443".parse().unwrap(), - "https://75.119.132.2:443".parse().unwrap(), - "https://173.212.239.247:443".parse().unwrap(), - "https://51.38.142.61:443".parse().unwrap(), - "https://44.240.99.214:443".parse().unwrap(), - "https://5.75.133.148:443".parse().unwrap(), - "https://62.84.182.155:443".parse().unwrap(), - "https://89.35.131.149:443".parse().unwrap(), - "https://192.248.178.237:443".parse().unwrap(), - "https://45.77.11.194:443".parse().unwrap(), - "https://37.60.243.119:443".parse().unwrap(), - "https://46.254.241.7:443".parse().unwrap(), - "https://194.195.87.34:443".parse().unwrap(), - "https://43.163.251.51:443".parse().unwrap(), - "https://184.174.36.201:443".parse().unwrap(), - "https://85.239.244.103:443".parse().unwrap(), - "https://65.108.246.145:443".parse().unwrap(), - "https://194.163.170.55:443".parse().unwrap(), - "https://2.58.82.231:443".parse().unwrap(), - "https://5.252.55.187:443".parse().unwrap(), - "https://198.7.119.139:443".parse().unwrap(), - "https://213.199.44.112:443".parse().unwrap(), - "https://155.138.220.69:443".parse().unwrap(), - "https://209.145.48.154:443".parse().unwrap(), - "https://162.212.35.100:443".parse().unwrap(), - "https://185.239.209.6:443".parse().unwrap(), - "https://157.173.113.158:443".parse().unwrap(), - "https://134.255.182.185:443".parse().unwrap(), - "https://173.212.239.124:443".parse().unwrap(), - "https://144.126.141.62:443".parse().unwrap(), - "https://51.38.142.62:443".parse().unwrap(), - "https://157.10.199.77:443".parse().unwrap(), - "https://5.189.186.78:443".parse().unwrap(), - "https://164.68.118.37:443".parse().unwrap(), - "https://158.220.92.144:443".parse().unwrap(), - "https://192.248.175.198:443".parse().unwrap(), - "https://43.167.244.109:443".parse().unwrap(), - "https://146.59.45.235:443".parse().unwrap(), - "https://104.200.24.196:443".parse().unwrap(), - "https://146.59.153.204:443".parse().unwrap(), - "https://37.60.236.225:443".parse().unwrap(), - "https://172.233.66.70:443".parse().unwrap(), - "https://57.128.212.163:443".parse().unwrap(), - "https://82.208.20.153:443".parse().unwrap(), - "https://51.195.235.166:443".parse().unwrap(), - "https://158.220.122.74:443".parse().unwrap(), - "https://82.211.21.38:443".parse().unwrap(), - "https://93.115.172.37:443".parse().unwrap(), - "https://185.198.234.25:443".parse().unwrap(), - "https://84.247.187.76:443".parse().unwrap(), - "https://89.35.131.39:443".parse().unwrap(), - "https://93.115.172.38:443".parse().unwrap(), - "https://134.255.183.250:443".parse().unwrap(), - "https://85.190.243.3:443".parse().unwrap(), - "https://185.192.96.70:443".parse().unwrap(), - "https://134.255.183.248:443".parse().unwrap(), - "https://52.36.102.91:443".parse().unwrap(), - "https://139.99.201.103:443".parse().unwrap(), - "https://134.255.183.247:443".parse().unwrap(), - "https://213.199.34.250:443".parse().unwrap(), - "https://161.97.74.173:443".parse().unwrap(), - "https://45.135.180.79:443".parse().unwrap(), - "https://45.135.180.130:443".parse().unwrap(), - "https://173.212.251.130:443".parse().unwrap(), - "https://157.173.122.157:443".parse().unwrap(), - "https://49.13.237.193:443".parse().unwrap(), - "https://37.27.83.17:443".parse().unwrap(), - "https://45.135.180.114:443".parse().unwrap(), - "https://89.35.131.61:443".parse().unwrap(), - "https://86.107.101.74:443".parse().unwrap(), - "https://134.255.182.187:443".parse().unwrap(), - "https://157.173.202.14:443".parse().unwrap(), - "https://62.171.170.14:443".parse().unwrap(), - "https://5.252.55.190:443".parse().unwrap(), - "https://198.7.115.43:443".parse().unwrap(), - "https://157.173.122.158:443".parse().unwrap(), - "https://108.61.165.170:443".parse().unwrap(), - "https://157.10.199.79:443".parse().unwrap(), - "https://89.35.131.219:443".parse().unwrap(), - "https://185.166.217.154:443".parse().unwrap(), - "https://31.220.88.116:443".parse().unwrap(), - "https://149.202.78.214:443".parse().unwrap(), - "https://195.26.254.228:443".parse().unwrap(), - "https://217.77.12.101:443".parse().unwrap(), - "https://43.167.240.90:443".parse().unwrap(), - "https://157.10.199.82:443".parse().unwrap(), - "https://5.252.55.189:443".parse().unwrap(), - "https://167.86.93.21:443".parse().unwrap(), - "https://195.26.241.252:443".parse().unwrap(), - "https://161.97.170.251:443".parse().unwrap(), - "https://51.195.47.118:443".parse().unwrap(), - "https://45.135.180.70:443".parse().unwrap(), - "https://167.88.169.16:443".parse().unwrap(), - "https://62.169.17.112:443".parse().unwrap(), - "https://82.211.21.18:443".parse().unwrap(), - "https://52.10.213.198:443".parse().unwrap(), - "https://139.84.231.221:443".parse().unwrap(), - "https://51.75.60.227:443".parse().unwrap(), - "https://93.190.140.162:443".parse().unwrap(), - "https://198.7.115.38:443".parse().unwrap(), - "https://37.60.236.161:443".parse().unwrap(), - "https://37.60.244.220:443".parse().unwrap(), - "https://46.254.241.9:443".parse().unwrap(), - "https://167.86.94.138:443".parse().unwrap(), - "https://192.95.32.205:443".parse().unwrap(), - "https://95.179.241.182:443".parse().unwrap(), - "https://65.109.84.204:443".parse().unwrap(), - "https://93.115.172.36:443".parse().unwrap(), - "https://82.211.21.16:443".parse().unwrap(), - "https://158.220.89.188:443".parse().unwrap(), - "https://95.216.146.18:443".parse().unwrap(), - "https://167.114.153.110:443".parse().unwrap(), - "https://89.250.75.61:443".parse().unwrap(), - "https://185.194.216.84:443".parse().unwrap(), - "https://158.220.87.156:443".parse().unwrap(), - "https://31.220.84.93:443".parse().unwrap(), - "https://185.197.250.227:443".parse().unwrap(), - "https://162.250.188.207:443".parse().unwrap(), - "https://207.180.231.37:443".parse().unwrap(), - "https://207.180.231.39:443".parse().unwrap(), - "https://66.70.170.22:443".parse().unwrap(), - "https://149.28.247.165:443".parse().unwrap(), - "https://45.85.147.192:443".parse().unwrap(), - "https://157.173.122.156:443".parse().unwrap(), - "https://213.199.34.251:443".parse().unwrap(), - "https://95.171.21.131:443".parse().unwrap(), - "https://87.228.24.64:443".parse().unwrap(), - "https://5.189.151.7:443".parse().unwrap(), - "https://90.16.41.190:443".parse().unwrap(), - "https://38.242.231.212:443".parse().unwrap(), - "https://38.143.58.210:443".parse().unwrap(), - "https://157.66.81.130:443".parse().unwrap(), - "https://217.77.12.102:443".parse().unwrap(), - "https://157.10.199.125:443".parse().unwrap(), - "https://46.254.241.8:443".parse().unwrap(), - "https://49.12.102.105:443".parse().unwrap(), - "https://134.255.182.189:443".parse().unwrap(), - "https://81.17.101.141:443".parse().unwrap(), - "https://64.23.134.67:443".parse().unwrap(), - "https://93.190.140.190:443".parse().unwrap(), - "https://86.107.101.128:443".parse().unwrap(), - "https://54.69.95.118:443".parse().unwrap(), - "https://158.220.122.13:443".parse().unwrap(), - "https://82.211.25.69:443".parse().unwrap(), - "https://144.217.69.169:443".parse().unwrap(), - "https://93.190.140.111:443".parse().unwrap(), - "https://5.189.140.20:443".parse().unwrap(), - "https://93.190.140.114:443".parse().unwrap(), - "https://135.181.110.216:443".parse().unwrap(), - "https://207.180.213.141:443".parse().unwrap(), - "https://45.76.141.74:443".parse().unwrap(), - "https://185.194.216.38:443".parse().unwrap(), - "https://161.97.66.31:443".parse().unwrap(), - "https://188.245.90.255:443".parse().unwrap(), - "https://65.109.84.201:443".parse().unwrap(), - "https://164.68.114.36:443".parse().unwrap(), - "https://167.88.165.175:443".parse().unwrap(), - "https://43.167.239.145:443".parse().unwrap(), - "https://37.60.236.201:443".parse().unwrap(), - "https://185.239.208.110:443".parse().unwrap(), - "https://95.179.139.125:443".parse().unwrap(), - "https://213.199.34.248:443".parse().unwrap(), - "https://178.18.254.136:443".parse().unwrap(), - "https://82.211.21.40:443".parse().unwrap(), - "https://213.199.35.18:443".parse().unwrap(), - "https://38.102.124.86:443".parse().unwrap(), - "https://45.77.129.235:443".parse().unwrap(), - "https://81.0.249.58:443".parse().unwrap(), - "https://37.60.243.59:443".parse().unwrap(), - "https://37.60.236.247:443".parse().unwrap(), - "https://89.35.131.218:443".parse().unwrap(), - "https://5.189.145.80:443".parse().unwrap(), - "https://149.102.152.219:443".parse().unwrap(), - "https://77.221.148.204:443".parse().unwrap(), - "https://46.254.241.11:443".parse().unwrap(), - "https://207.180.218.245:443".parse().unwrap(), - "https://89.35.131.158:443".parse().unwrap(), - "https://5.252.55.188:443".parse().unwrap(), - "https://185.215.166.126:443".parse().unwrap(), - "https://164.132.55.103:443".parse().unwrap(), - "https://162.250.190.133:443".parse().unwrap(), - "https://157.66.81.218:443".parse().unwrap(), - "https://5.39.27.224:443".parse().unwrap(), - "https://213.159.77.221:443".parse().unwrap(), - "https://213.199.35.15:443".parse().unwrap(), - "https://114.132.172.215:443".parse().unwrap(), - ]; + let mainnet_addresses = MAINNET_DISCOVERED_ADDRESSES.lock().unwrap().clone().expect( + "Mainnet addresses not prefetched. Call prefetchTrustedQuorumsMainnet() first.", + ); let address_list = dash_sdk::sdk::AddressList::from_iter(mainnet_addresses); let sdk_builder = SdkBuilder::new(address_list) @@ -447,219 +260,15 @@ impl WasmSdkBuilder { .map_err(|e| WasmSdkError::from(dash_sdk::Error::from(e))) })?; - // Mainnet addresses from mnowatch.org - let mainnet_addresses = vec![ - "https://149.28.241.190:443".parse().unwrap(), - "https://198.7.115.48:443".parse().unwrap(), - "https://134.255.182.186:443".parse().unwrap(), - "https://93.115.172.39:443".parse().unwrap(), - "https://5.189.164.253:443".parse().unwrap(), - "https://178.215.237.134:443".parse().unwrap(), - "https://157.66.81.162:443".parse().unwrap(), - "https://173.212.232.90:443".parse().unwrap(), - "https://178.215.237.135:443".parse().unwrap(), - "https://5.182.33.231:443".parse().unwrap(), - "https://109.199.104.243:443".parse().unwrap(), - "https://37.60.236.212:443".parse().unwrap(), - "https://23.88.63.58:443".parse().unwrap(), - "https://207.244.247.40:443".parse().unwrap(), - "https://45.32.70.131:443".parse().unwrap(), - "https://158.220.122.76:443".parse().unwrap(), - "https://52.33.9.172:443".parse().unwrap(), - "https://194.163.166.185:443".parse().unwrap(), - "https://185.158.107.124:443".parse().unwrap(), - "https://185.198.234.17:443".parse().unwrap(), - "https://93.190.140.101:443".parse().unwrap(), - "https://194.163.153.225:443".parse().unwrap(), - "https://194.146.13.7:443".parse().unwrap(), - "https://158.247.208.247:443".parse().unwrap(), - "https://93.190.140.112:443".parse().unwrap(), - "https://75.119.132.2:443".parse().unwrap(), - "https://173.212.239.247:443".parse().unwrap(), - "https://51.38.142.61:443".parse().unwrap(), - "https://44.240.99.214:443".parse().unwrap(), - "https://5.75.133.148:443".parse().unwrap(), - "https://62.84.182.155:443".parse().unwrap(), - "https://89.35.131.149:443".parse().unwrap(), - "https://192.248.178.237:443".parse().unwrap(), - "https://45.77.11.194:443".parse().unwrap(), - "https://37.60.243.119:443".parse().unwrap(), - "https://46.254.241.7:443".parse().unwrap(), - "https://194.195.87.34:443".parse().unwrap(), - "https://43.163.251.51:443".parse().unwrap(), - "https://184.174.36.201:443".parse().unwrap(), - "https://85.239.244.103:443".parse().unwrap(), - "https://65.108.246.145:443".parse().unwrap(), - "https://194.163.170.55:443".parse().unwrap(), - "https://2.58.82.231:443".parse().unwrap(), - "https://5.252.55.187:443".parse().unwrap(), - "https://198.7.119.139:443".parse().unwrap(), - "https://213.199.44.112:443".parse().unwrap(), - "https://155.138.220.69:443".parse().unwrap(), - "https://209.145.48.154:443".parse().unwrap(), - "https://162.212.35.100:443".parse().unwrap(), - "https://185.239.209.6:443".parse().unwrap(), - "https://157.173.113.158:443".parse().unwrap(), - "https://134.255.182.185:443".parse().unwrap(), - "https://173.212.239.124:443".parse().unwrap(), - "https://144.126.141.62:443".parse().unwrap(), - "https://51.38.142.62:443".parse().unwrap(), - "https://157.10.199.77:443".parse().unwrap(), - "https://5.189.186.78:443".parse().unwrap(), - "https://164.68.118.37:443".parse().unwrap(), - "https://158.220.92.144:443".parse().unwrap(), - "https://192.248.175.198:443".parse().unwrap(), - "https://43.167.244.109:443".parse().unwrap(), - "https://146.59.45.235:443".parse().unwrap(), - "https://104.200.24.196:443".parse().unwrap(), - "https://146.59.153.204:443".parse().unwrap(), - "https://37.60.236.225:443".parse().unwrap(), - "https://172.233.66.70:443".parse().unwrap(), - "https://57.128.212.163:443".parse().unwrap(), - "https://82.208.20.153:443".parse().unwrap(), - "https://51.195.235.166:443".parse().unwrap(), - "https://158.220.122.74:443".parse().unwrap(), - "https://82.211.21.38:443".parse().unwrap(), - "https://93.115.172.37:443".parse().unwrap(), - "https://185.198.234.25:443".parse().unwrap(), - "https://84.247.187.76:443".parse().unwrap(), - "https://89.35.131.39:443".parse().unwrap(), - "https://93.115.172.38:443".parse().unwrap(), - "https://134.255.183.250:443".parse().unwrap(), - "https://85.190.243.3:443".parse().unwrap(), - "https://185.192.96.70:443".parse().unwrap(), - "https://134.255.183.248:443".parse().unwrap(), - "https://52.36.102.91:443".parse().unwrap(), - "https://139.99.201.103:443".parse().unwrap(), - "https://134.255.183.247:443".parse().unwrap(), - "https://213.199.34.250:443".parse().unwrap(), - "https://161.97.74.173:443".parse().unwrap(), - "https://45.135.180.79:443".parse().unwrap(), - "https://45.135.180.130:443".parse().unwrap(), - "https://173.212.251.130:443".parse().unwrap(), - "https://157.173.122.157:443".parse().unwrap(), - "https://49.13.237.193:443".parse().unwrap(), - "https://37.27.83.17:443".parse().unwrap(), - "https://45.135.180.114:443".parse().unwrap(), - "https://89.35.131.61:443".parse().unwrap(), - "https://86.107.101.74:443".parse().unwrap(), - "https://134.255.182.187:443".parse().unwrap(), - "https://157.173.202.14:443".parse().unwrap(), - "https://62.171.170.14:443".parse().unwrap(), - "https://5.252.55.190:443".parse().unwrap(), - "https://198.7.115.43:443".parse().unwrap(), - "https://157.173.122.158:443".parse().unwrap(), - "https://108.61.165.170:443".parse().unwrap(), - "https://157.10.199.79:443".parse().unwrap(), - "https://89.35.131.219:443".parse().unwrap(), - "https://185.166.217.154:443".parse().unwrap(), - "https://31.220.88.116:443".parse().unwrap(), - "https://149.202.78.214:443".parse().unwrap(), - "https://195.26.254.228:443".parse().unwrap(), - "https://217.77.12.101:443".parse().unwrap(), - "https://43.167.240.90:443".parse().unwrap(), - "https://157.10.199.82:443".parse().unwrap(), - "https://5.252.55.189:443".parse().unwrap(), - "https://167.86.93.21:443".parse().unwrap(), - "https://195.26.241.252:443".parse().unwrap(), - "https://161.97.170.251:443".parse().unwrap(), - "https://51.195.47.118:443".parse().unwrap(), - "https://45.135.180.70:443".parse().unwrap(), - "https://167.88.169.16:443".parse().unwrap(), - "https://62.169.17.112:443".parse().unwrap(), - "https://82.211.21.18:443".parse().unwrap(), - "https://52.10.213.198:443".parse().unwrap(), - "https://139.84.231.221:443".parse().unwrap(), - "https://51.75.60.227:443".parse().unwrap(), - "https://93.190.140.162:443".parse().unwrap(), - "https://198.7.115.38:443".parse().unwrap(), - "https://37.60.236.161:443".parse().unwrap(), - "https://37.60.244.220:443".parse().unwrap(), - "https://46.254.241.9:443".parse().unwrap(), - "https://167.86.94.138:443".parse().unwrap(), - "https://192.95.32.205:443".parse().unwrap(), - "https://95.179.241.182:443".parse().unwrap(), - "https://65.109.84.204:443".parse().unwrap(), - "https://93.115.172.36:443".parse().unwrap(), - "https://82.211.21.16:443".parse().unwrap(), - "https://158.220.89.188:443".parse().unwrap(), - "https://95.216.146.18:443".parse().unwrap(), - "https://167.114.153.110:443".parse().unwrap(), - "https://89.250.75.61:443".parse().unwrap(), - "https://185.194.216.84:443".parse().unwrap(), - "https://158.220.87.156:443".parse().unwrap(), - "https://31.220.84.93:443".parse().unwrap(), - "https://185.197.250.227:443".parse().unwrap(), - "https://162.250.188.207:443".parse().unwrap(), - "https://207.180.231.37:443".parse().unwrap(), - "https://207.180.231.39:443".parse().unwrap(), - "https://66.70.170.22:443".parse().unwrap(), - "https://149.28.247.165:443".parse().unwrap(), - "https://45.85.147.192:443".parse().unwrap(), - "https://157.173.122.156:443".parse().unwrap(), - "https://213.199.34.251:443".parse().unwrap(), - "https://95.171.21.131:443".parse().unwrap(), - "https://87.228.24.64:443".parse().unwrap(), - "https://5.189.151.7:443".parse().unwrap(), - "https://90.16.41.190:443".parse().unwrap(), - "https://38.242.231.212:443".parse().unwrap(), - "https://38.143.58.210:443".parse().unwrap(), - "https://157.66.81.130:443".parse().unwrap(), - "https://217.77.12.102:443".parse().unwrap(), - "https://157.10.199.125:443".parse().unwrap(), - "https://46.254.241.8:443".parse().unwrap(), - "https://49.12.102.105:443".parse().unwrap(), - "https://134.255.182.189:443".parse().unwrap(), - "https://81.17.101.141:443".parse().unwrap(), - "https://64.23.134.67:443".parse().unwrap(), - "https://93.190.140.190:443".parse().unwrap(), - "https://86.107.101.128:443".parse().unwrap(), - "https://54.69.95.118:443".parse().unwrap(), - "https://158.220.122.13:443".parse().unwrap(), - "https://82.211.25.69:443".parse().unwrap(), - "https://144.217.69.169:443".parse().unwrap(), - "https://93.190.140.111:443".parse().unwrap(), - "https://5.189.140.20:443".parse().unwrap(), - "https://93.190.140.114:443".parse().unwrap(), - "https://135.181.110.216:443".parse().unwrap(), - "https://207.180.213.141:443".parse().unwrap(), - "https://45.76.141.74:443".parse().unwrap(), - "https://185.194.216.38:443".parse().unwrap(), - "https://161.97.66.31:443".parse().unwrap(), - "https://188.245.90.255:443".parse().unwrap(), - "https://65.109.84.201:443".parse().unwrap(), - "https://164.68.114.36:443".parse().unwrap(), - "https://167.88.165.175:443".parse().unwrap(), - "https://43.167.239.145:443".parse().unwrap(), - "https://37.60.236.201:443".parse().unwrap(), - "https://185.239.208.110:443".parse().unwrap(), - "https://95.179.139.125:443".parse().unwrap(), - "https://213.199.34.248:443".parse().unwrap(), - "https://178.18.254.136:443".parse().unwrap(), - "https://82.211.21.40:443".parse().unwrap(), - "https://213.199.35.18:443".parse().unwrap(), - "https://38.102.124.86:443".parse().unwrap(), - "https://45.77.129.235:443".parse().unwrap(), - "https://81.0.249.58:443".parse().unwrap(), - "https://37.60.243.59:443".parse().unwrap(), - "https://37.60.236.247:443".parse().unwrap(), - "https://89.35.131.218:443".parse().unwrap(), - "https://5.189.145.80:443".parse().unwrap(), - "https://149.102.152.219:443".parse().unwrap(), - "https://77.221.148.204:443".parse().unwrap(), - "https://46.254.241.11:443".parse().unwrap(), - "https://207.180.218.245:443".parse().unwrap(), - "https://89.35.131.158:443".parse().unwrap(), - "https://5.252.55.188:443".parse().unwrap(), - "https://185.215.166.126:443".parse().unwrap(), - "https://164.132.55.103:443".parse().unwrap(), - "https://162.250.190.133:443".parse().unwrap(), - "https://157.66.81.218:443".parse().unwrap(), - "https://5.39.27.224:443".parse().unwrap(), - "https://213.159.77.221:443".parse().unwrap(), - "https://213.199.35.15:443".parse().unwrap(), - "https://114.132.172.215:443".parse().unwrap(), - ]; + let mainnet_addresses = MAINNET_DISCOVERED_ADDRESSES + .lock() + .unwrap() + .clone() + .ok_or_else(|| { + WasmSdkError::generic( + "Mainnet addresses not prefetched. Call prefetchTrustedQuorumsMainnet() first.", + ) + })?; let address_list = dash_sdk::sdk::AddressList::from_iter(mainnet_addresses); let sdk_builder = SdkBuilder::new(address_list) @@ -671,18 +280,9 @@ impl WasmSdkBuilder { #[wasm_bindgen(js_name = "testnet")] pub fn new_testnet() -> Self { - // Testnet addresses from https://quorums.testnet.networks.dash.org/masternodes - // Using HTTPS endpoints for ENABLED nodes with successful version checks - let testnet_addresses = vec![ - "https://52.12.176.90:1443".parse().unwrap(), // ENABLED, dapiVersion: 2.0.0-rc.17 - "https://35.82.197.197:1443".parse().unwrap(), // ENABLED, dapiVersion: 2.0.0-rc.17 - "https://44.240.98.102:1443".parse().unwrap(), // ENABLED, dapiVersion: 2.0.0-rc.17 - "https://52.34.144.50:1443".parse().unwrap(), // ENABLED, dapiVersion: 2.0.0-rc.17 - "https://44.239.39.153:1443".parse().unwrap(), // ENABLED, dapiVersion: 2.0.0-rc.17 - "https://34.214.48.68:1443".parse().unwrap(), // ENABLED, dapiVersion: 2.0.0-rc.17 - "https://54.149.33.167:1443".parse().unwrap(), // ENABLED, dapiVersion: 2.0.0-rc.17 - "https://52.24.124.162:1443".parse().unwrap(), // ENABLED, dapiVersion: 2.0.0-rc.17 - ]; + let testnet_addresses = TESTNET_DISCOVERED_ADDRESSES.lock().unwrap().clone().expect( + "Testnet addresses not prefetched. Call prefetchTrustedQuorumsTestnet() first.", + ); let address_list = dash_sdk::sdk::AddressList::from_iter(testnet_addresses); let sdk_builder = SdkBuilder::new(address_list) @@ -707,18 +307,15 @@ impl WasmSdkBuilder { .map_err(|e| WasmSdkError::from(dash_sdk::Error::from(e))) })?; - // Testnet addresses from https://quorums.testnet.networks.dash.org/masternodes - // Using HTTPS endpoints for ENABLED nodes with successful version checks - let testnet_addresses = vec![ - "https://52.12.176.90:1443".parse().unwrap(), // ENABLED, dapiVersion: 2.0.0-rc.17 - "https://35.82.197.197:1443".parse().unwrap(), // ENABLED, dapiVersion: 2.0.0-rc.17 - "https://44.240.98.102:1443".parse().unwrap(), // ENABLED, dapiVersion: 2.0.0-rc.17 - "https://52.34.144.50:1443".parse().unwrap(), // ENABLED, dapiVersion: 2.0.0-rc.17 - "https://44.239.39.153:1443".parse().unwrap(), // ENABLED, dapiVersion: 2.0.0-rc.17 - "https://34.214.48.68:1443".parse().unwrap(), // ENABLED, dapiVersion: 2.0.0-rc.17 - "https://54.149.33.167:1443".parse().unwrap(), // ENABLED, dapiVersion: 2.0.0-rc.17 - "https://52.24.124.162:1443".parse().unwrap(), // ENABLED, dapiVersion: 2.0.0-rc.17 - ]; + let testnet_addresses = TESTNET_DISCOVERED_ADDRESSES + .lock() + .unwrap() + .clone() + .ok_or_else(|| { + WasmSdkError::generic( + "Testnet addresses not prefetched. Call prefetchTrustedQuorumsTestnet() first.", + ) + })?; let address_list = dash_sdk::sdk::AddressList::from_iter(testnet_addresses); let sdk_builder = SdkBuilder::new(address_list) From b321db6c029b7cb10e7be693e478caef5168395f Mon Sep 17 00:00:00 2001 From: Ivan Shumkov Date: Mon, 1 Dec 2025 18:32:29 +0700 Subject: [PATCH 2/7] chore: missing provider --- .../src/provider.rs | 80 ++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/packages/rs-sdk-trusted-context-provider/src/provider.rs b/packages/rs-sdk-trusted-context-provider/src/provider.rs index ce80912a389..0cde23cea20 100644 --- a/packages/rs-sdk-trusted-context-provider/src/provider.rs +++ b/packages/rs-sdk-trusted-context-provider/src/provider.rs @@ -24,6 +24,7 @@ use dpp::version::PlatformVersion; use lru::LruCache; use reqwest::Client; +use serde::Deserialize; use std::collections::HashMap; use std::error::Error as StdError; #[cfg(not(target_arch = "wasm32"))] @@ -33,7 +34,6 @@ use std::sync::{Arc, Mutex}; #[cfg(not(target_arch = "wasm32"))] use std::time::Duration; use tracing::{debug, info}; -#[cfg(not(target_arch = "wasm32"))] use url::Url; /// A trusted HTTP-based context provider that fetches quorum information @@ -65,6 +65,20 @@ pub struct TrustedHttpContextProvider { refetch_if_not_found: bool, } +#[derive(Debug, Deserialize)] +struct MasternodeEntry { + address: String, + status: String, + #[serde(rename = "versionCheck")] + version_check: Option, +} + +#[derive(Debug, Deserialize)] +struct MasternodeDiscoveryResponse { + success: bool, + data: Vec, +} + impl TrustedHttpContextProvider { /// Verify that a URL's domain resolves #[cfg(not(target_arch = "wasm32"))] @@ -229,6 +243,70 @@ impl TrustedHttpContextProvider { current_count + previous_count } + /// Fetch DAPI HTTPS addresses from the masternode discovery endpoint + pub async fn fetch_masternode_addresses( + &self, + ) -> Result, TrustedContextProviderError> { + let url = format!("{}/masternodes", self.base_url); + debug!( + "Fetching masternode addresses from trusted resource: {}", + url + ); + + let response = self.client.get(&url).send().await?; + if !response.status().is_success() { + return Err(TrustedContextProviderError::NetworkError(format!( + "HTTP {} from {}", + response.status(), + url + ))); + } + + let body = response.text().await?; + let parsed: MasternodeDiscoveryResponse = serde_json::from_str(&body)?; + + if !parsed.success { + return Err(TrustedContextProviderError::NetworkError( + "Masternode discovery response indicated failure".to_string(), + )); + } + + let dapi_port = match self.network { + Network::Dash => 443, + Network::Testnet => 1443, + _ => 443, + }; + + let mut addresses = Vec::new(); + for entry in parsed + .data + .into_iter() + .filter(|m| m.status == "ENABLED" && m.version_check.as_deref() == Some("success")) + { + let host_port = entry.address; + let host = host_port + .rsplit_once(':') + .map(|(h, _)| h) + .unwrap_or(host_port.as_str()); + let https_url = format!("https://{}:{}", host, dapi_port); + let url = url::Url::parse(&https_url).map_err(|e| { + TrustedContextProviderError::NetworkError(format!( + "Invalid masternode URL '{}': {}", + https_url, e + )) + })?; + addresses.push(url); + } + + if addresses.is_empty() { + return Err(TrustedContextProviderError::NetworkError( + "No eligible masternode addresses discovered".to_string(), + )); + } + + Ok(addresses) + } + /// Fetch current quorums from the HTTP endpoint pub async fn fetch_current_quorums( &self, From 281f9d3cad2028adc19fbedd264532935bef01e8 Mon Sep 17 00:00:00 2001 From: Ivan Shumkov Date: Mon, 1 Dec 2025 18:33:43 +0700 Subject: [PATCH 3/7] style: fix formatting --- packages/wasm-sdk/src/context_provider.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/wasm-sdk/src/context_provider.rs b/packages/wasm-sdk/src/context_provider.rs index 2e1486a565d..481e2966ab5 100644 --- a/packages/wasm-sdk/src/context_provider.rs +++ b/packages/wasm-sdk/src/context_provider.rs @@ -137,11 +137,9 @@ impl WasmTrustedContext { pub async fn fetch_masternode_addresses( &self, ) -> Result { - let urls = self - .inner - .fetch_masternode_addresses() - .await - .map_err(|e| ContextProviderError::Generic(format!("Failed to fetch masternodes: {}", e)))?; + let urls = self.inner.fetch_masternode_addresses().await.map_err(|e| { + ContextProviderError::Generic(format!("Failed to fetch masternodes: {}", e)) + })?; let mut addresses = Vec::new(); for url in urls { @@ -149,7 +147,10 @@ impl WasmTrustedContext { ContextProviderError::Generic(format!("Invalid masternode URI '{}': {}", url, e)) })?; let address = rs_dapi_client::Address::try_from(uri).map_err(|e| { - ContextProviderError::Generic(format!("Invalid masternode address '{}': {}", url, e)) + ContextProviderError::Generic(format!( + "Invalid masternode address '{}': {}", + url, e + )) })?; addresses.push(address); } From cb1201d17c31dbf76610ec52e7d7e3957a0a4c0c Mon Sep 17 00:00:00 2001 From: Ivan Shumkov Date: Mon, 1 Dec 2025 18:43:34 +0700 Subject: [PATCH 4/7] chore: add default addresses --- packages/wasm-sdk/src/sdk.rs | 64 +++++++++++++++++++++++++++--------- 1 file changed, 48 insertions(+), 16 deletions(-) diff --git a/packages/wasm-sdk/src/sdk.rs b/packages/wasm-sdk/src/sdk.rs index df54996c3ae..1663e0836b5 100644 --- a/packages/wasm-sdk/src/sdk.rs +++ b/packages/wasm-sdk/src/sdk.rs @@ -4,6 +4,7 @@ use dash_sdk::dpp::version::PlatformVersion; use dash_sdk::{Sdk, SdkBuilder}; use once_cell::sync::Lazy; use rs_dapi_client::{Address, RequestSettings}; +use dash_sdk::sdk::Uri; use std::ops::{Deref, DerefMut}; use std::sync::Mutex; use std::time::Duration; @@ -19,6 +20,41 @@ static MAINNET_DISCOVERED_ADDRESSES: Lazy>>> = static TESTNET_DISCOVERED_ADDRESSES: Lazy>>> = Lazy::new(|| Mutex::new(None)); +fn parse_addresses(addresses: &[&str]) -> Vec
{ + addresses + .iter() + .filter_map(|addr| { + Uri::from_maybe_shared(addr.to_string()) + .ok() + .and_then(|uri| Address::try_from(uri).ok()) + }) + .collect() +} + +fn default_mainnet_addresses() -> Vec
{ + // Trimmed seed list to keep bundle size small; used only if no prefetched cache is available. + parse_addresses(&[ + "https://149.28.241.190:443", + "https://198.7.115.48:443", + "https://134.255.182.186:443", + "https://93.115.172.39:443", + "https://5.189.164.253:443", + ]) +} + +fn default_testnet_addresses() -> Vec
{ + parse_addresses(&[ + "https://52.12.176.90:1443", + "https://35.82.197.197:1443", + "https://44.240.98.102:1443", + "https://52.34.144.50:1443", + "https://44.239.39.153:1443", + "https://34.214.48.68:1443", + "https://54.149.33.167:1443", + "https://52.24.124.162:1443", + ]) +} + async fn fetch_and_cache_addresses( trusted_context: &crate::context_provider::WasmTrustedContext, cache: &Lazy>>>, @@ -233,9 +269,11 @@ impl WasmSdkBuilder { #[wasm_bindgen(js_name = "mainnet")] pub fn new_mainnet() -> Self { - let mainnet_addresses = MAINNET_DISCOVERED_ADDRESSES.lock().unwrap().clone().expect( - "Mainnet addresses not prefetched. Call prefetchTrustedQuorumsMainnet() first.", - ); + let mainnet_addresses = MAINNET_DISCOVERED_ADDRESSES + .lock() + .unwrap() + .clone() + .unwrap_or_else(default_mainnet_addresses); let address_list = dash_sdk::sdk::AddressList::from_iter(mainnet_addresses); let sdk_builder = SdkBuilder::new(address_list) @@ -264,11 +302,7 @@ impl WasmSdkBuilder { .lock() .unwrap() .clone() - .ok_or_else(|| { - WasmSdkError::generic( - "Mainnet addresses not prefetched. Call prefetchTrustedQuorumsMainnet() first.", - ) - })?; + .unwrap_or_else(default_mainnet_addresses); let address_list = dash_sdk::sdk::AddressList::from_iter(mainnet_addresses); let sdk_builder = SdkBuilder::new(address_list) @@ -280,9 +314,11 @@ impl WasmSdkBuilder { #[wasm_bindgen(js_name = "testnet")] pub fn new_testnet() -> Self { - let testnet_addresses = TESTNET_DISCOVERED_ADDRESSES.lock().unwrap().clone().expect( - "Testnet addresses not prefetched. Call prefetchTrustedQuorumsTestnet() first.", - ); + let testnet_addresses = TESTNET_DISCOVERED_ADDRESSES + .lock() + .unwrap() + .clone() + .unwrap_or_else(default_testnet_addresses); let address_list = dash_sdk::sdk::AddressList::from_iter(testnet_addresses); let sdk_builder = SdkBuilder::new(address_list) @@ -311,11 +347,7 @@ impl WasmSdkBuilder { .lock() .unwrap() .clone() - .ok_or_else(|| { - WasmSdkError::generic( - "Testnet addresses not prefetched. Call prefetchTrustedQuorumsTestnet() first.", - ) - })?; + .unwrap_or_else(default_testnet_addresses); let address_list = dash_sdk::sdk::AddressList::from_iter(testnet_addresses); let sdk_builder = SdkBuilder::new(address_list) From 494e803121be93b19f54cc77d86f5bf69bcb6d39 Mon Sep 17 00:00:00 2001 From: Ivan Shumkov Date: Mon, 1 Dec 2025 19:11:21 +0700 Subject: [PATCH 5/7] chore: fix formatting and warnings --- packages/wasm-sdk/src/sdk.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/wasm-sdk/src/sdk.rs b/packages/wasm-sdk/src/sdk.rs index 1663e0836b5..55cd2038288 100644 --- a/packages/wasm-sdk/src/sdk.rs +++ b/packages/wasm-sdk/src/sdk.rs @@ -1,10 +1,10 @@ use crate::context_provider::WasmContext; use crate::error::WasmSdkError; use dash_sdk::dpp::version::PlatformVersion; +use dash_sdk::sdk::Uri; use dash_sdk::{Sdk, SdkBuilder}; use once_cell::sync::Lazy; use rs_dapi_client::{Address, RequestSettings}; -use dash_sdk::sdk::Uri; use std::ops::{Deref, DerefMut}; use std::sync::Mutex; use std::time::Duration; @@ -20,11 +20,11 @@ static MAINNET_DISCOVERED_ADDRESSES: Lazy>>> = static TESTNET_DISCOVERED_ADDRESSES: Lazy>>> = Lazy::new(|| Mutex::new(None)); -fn parse_addresses(addresses: &[&str]) -> Vec
{ +fn parse_addresses(addresses: &'static [&str]) -> Vec
{ addresses .iter() .filter_map(|addr| { - Uri::from_maybe_shared(addr.to_string()) + Uri::from_maybe_shared(addr) .ok() .and_then(|uri| Address::try_from(uri).ok()) }) From 82f3b814ba128b08fe908ecf12aa82c81ab2a453 Mon Sep 17 00:00:00 2001 From: Ivan Shumkov Date: Mon, 1 Dec 2025 19:19:44 +0700 Subject: [PATCH 6/7] refactor: use ProofMetadataResponse --- packages/js-evo-sdk/src/dpns/facade.ts | 4 +- packages/wasm-sdk/src/queries/mod.rs | 77 +++++++++++++++++++++++++- 2 files changed, 78 insertions(+), 3 deletions(-) diff --git a/packages/js-evo-sdk/src/dpns/facade.ts b/packages/js-evo-sdk/src/dpns/facade.ts index d2daa0c8fcf..5f39b83a1dd 100644 --- a/packages/js-evo-sdk/src/dpns/facade.ts +++ b/packages/js-evo-sdk/src/dpns/facade.ts @@ -49,12 +49,12 @@ export class DpnsFacade { return w.getDpnsUsername(identityId); } - async usernamesWithProof(query: wasm.DpnsUsernamesQuery): Promise { + async usernamesWithProof(query: wasm.DpnsUsernamesQuery): Promise>> { const w = await this.sdk.getWasmSdkConnected(); return w.getDpnsUsernamesWithProofInfo(query); } - async usernameWithProof(identityId: wasm.IdentifierLike): Promise { + async usernameWithProof(identityId: wasm.IdentifierLike): Promise> { const w = await this.sdk.getWasmSdkConnected(); return w.getDpnsUsernameWithProofInfo(identityId); } diff --git a/packages/wasm-sdk/src/queries/mod.rs b/packages/wasm-sdk/src/queries/mod.rs index e9d6536be84..af044f4cf30 100644 --- a/packages/wasm-sdk/src/queries/mod.rs +++ b/packages/wasm-sdk/src/queries/mod.rs @@ -12,7 +12,7 @@ pub mod voting; // Re-export all query functions for easy access pub use group::*; -use js_sys::Uint8Array; +use js_sys::{Object, Reflect, Uint8Array}; use wasm_bindgen::prelude::*; use wasm_bindgen::JsValue; @@ -82,6 +82,39 @@ impl ResponseMetadataWasm { pub fn set_chain_id(&mut self, #[wasm_bindgen(js_name = "chainId")] chain_id: Uint8Array) { self.chain_id = chain_id.to_vec(); } + + #[wasm_bindgen(js_name = "toJSON")] + pub fn to_json(&self) -> JsValue { + let obj = Object::new(); + let _ = Reflect::set( + &obj, + &JsValue::from_str("height"), + &JsValue::from_f64(self.height as f64), + ); + let _ = Reflect::set( + &obj, + &JsValue::from_str("coreChainLockedHeight"), + &JsValue::from_f64(self.core_chain_locked_height as f64), + ); + let _ = Reflect::set( + &obj, + &JsValue::from_str("epoch"), + &JsValue::from_f64(self.epoch as f64), + ); + let _ = Reflect::set( + &obj, + &JsValue::from_str("timeMs"), + &JsValue::from_f64(self.time_ms as f64), + ); + let _ = Reflect::set( + &obj, + &JsValue::from_str("protocolVersion"), + &JsValue::from_f64(self.protocol_version as f64), + ); + let _ = Reflect::set(&obj, &JsValue::from_str("chainId"), &self.chain_id()); + + JsValue::from(obj) + } } // Helper function to convert platform ResponseMetadata to our ResponseMetadata @@ -188,6 +221,35 @@ impl ProofInfoWasm { ) { self.block_id_hash = block_id_hash.to_vec(); } + + #[wasm_bindgen(js_name = "toJSON")] + pub fn to_json(&self) -> JsValue { + let obj = Object::new(); + let _ = Reflect::set( + &obj, + &JsValue::from_str("grovedbProof"), + &self.grovedb_proof(), + ); + let _ = Reflect::set(&obj, &JsValue::from_str("quorumHash"), &self.quorum_hash()); + let _ = Reflect::set(&obj, &JsValue::from_str("signature"), &self.signature()); + let _ = Reflect::set( + &obj, + &JsValue::from_str("round"), + &JsValue::from_f64(self.round as f64), + ); + let _ = Reflect::set( + &obj, + &JsValue::from_str("blockIdHash"), + &self.block_id_hash(), + ); + let _ = Reflect::set( + &obj, + &JsValue::from_str("quorumType"), + &JsValue::from_f64(self.quorum_type as f64), + ); + + JsValue::from(obj) + } } // Helper function to convert platform Proof to our ProofInfo @@ -257,6 +319,19 @@ impl ProofMetadataResponseWasm { pub fn set_proof(&mut self, proof: ProofInfoWasm) { self.proof = proof; } + + #[wasm_bindgen(js_name = "toJSON")] + pub fn to_json(&self) -> JsValue { + let metadata_obj = self.metadata.to_json(); + let proof_obj = self.proof.to_json(); + + let obj = Object::new(); + let _ = Reflect::set(&obj, &JsValue::from_str("data"), &self.data); + let _ = Reflect::set(&obj, &JsValue::from_str("metadata"), &metadata_obj); + let _ = Reflect::set(&obj, &JsValue::from_str("proof"), &proof_obj); + + JsValue::from(obj) + } } impl ProofMetadataResponseWasm { From 2df13854b3a90586b37ac7b64c516c0cfa06cf08 Mon Sep 17 00:00:00 2001 From: Ivan Shumkov Date: Mon, 1 Dec 2025 20:10:54 +0700 Subject: [PATCH 7/7] revert: unnecessary changes --- packages/js-evo-sdk/src/dpns/facade.ts | 4 +- packages/wasm-sdk/src/dpns.rs | 64 +++++++++++++-------- packages/wasm-sdk/src/queries/mod.rs | 77 +------------------------- 3 files changed, 45 insertions(+), 100 deletions(-) diff --git a/packages/js-evo-sdk/src/dpns/facade.ts b/packages/js-evo-sdk/src/dpns/facade.ts index 5f39b83a1dd..d2daa0c8fcf 100644 --- a/packages/js-evo-sdk/src/dpns/facade.ts +++ b/packages/js-evo-sdk/src/dpns/facade.ts @@ -49,12 +49,12 @@ export class DpnsFacade { return w.getDpnsUsername(identityId); } - async usernamesWithProof(query: wasm.DpnsUsernamesQuery): Promise>> { + async usernamesWithProof(query: wasm.DpnsUsernamesQuery): Promise { const w = await this.sdk.getWasmSdkConnected(); return w.getDpnsUsernamesWithProofInfo(query); } - async usernameWithProof(identityId: wasm.IdentifierLike): Promise> { + async usernameWithProof(identityId: wasm.IdentifierLike): Promise { const w = await this.sdk.getWasmSdkConnected(); return w.getDpnsUsernameWithProofInfo(identityId); } diff --git a/packages/wasm-sdk/src/dpns.rs b/packages/wasm-sdk/src/dpns.rs index 2cd4a22d3f0..63ac7086701 100644 --- a/packages/wasm-sdk/src/dpns.rs +++ b/packages/wasm-sdk/src/dpns.rs @@ -1,6 +1,6 @@ use crate::error::WasmSdkError; use crate::queries::utils::{deserialize_required_query, identifier_from_js}; -use crate::queries::ProofMetadataResponseWasm; +use crate::queries::{ProofInfoWasm, ProofMetadataResponseWasm, ResponseMetadataWasm}; use crate::sdk::WasmSdk; use dash_sdk::dpp::document::{Document, DocumentV0Getters}; use dash_sdk::dpp::identity::accessors::IdentityGettersV0; @@ -119,6 +119,27 @@ fn parse_dpns_usernames_query( }) } +#[wasm_bindgen(js_name = "DpnsUsernamesProofResponse")] +#[derive(Clone)] +pub struct DpnsUsernamesProofResponseWasm { + #[wasm_bindgen(getter_with_clone)] + pub usernames: Array, + #[wasm_bindgen(getter_with_clone)] + pub metadata: ResponseMetadataWasm, + #[wasm_bindgen(getter_with_clone)] + pub proof: ProofInfoWasm, +} + +#[wasm_bindgen(js_name = "DpnsUsernameProofResponse")] +#[derive(Clone)] +pub struct DpnsUsernameProofResponseWasm { + #[wasm_bindgen(getter_with_clone)] + pub username: JsValue, + #[wasm_bindgen(getter_with_clone)] + pub metadata: ResponseMetadataWasm, + #[wasm_bindgen(getter_with_clone)] + pub proof: ProofInfoWasm, +} impl WasmSdk { async fn prepare_dpns_usernames_query( &self, @@ -168,7 +189,7 @@ impl WasmSdk { &self, identity_id: Identifier, limit: Option, - ) -> Result { + ) -> Result { let query = self .prepare_dpns_usernames_query(identity_id, limit) .await?; @@ -176,11 +197,11 @@ impl WasmSdk { Document::fetch_many_with_metadata_and_proof(self.as_ref(), query, None).await?; let usernames_array = usernames_from_documents(documents_result); - Ok(ProofMetadataResponseWasm::from_parts( - usernames_array.into(), - metadata.into(), - proof.into(), - )) + Ok(DpnsUsernamesProofResponseWasm { + usernames: usernames_array, + metadata: metadata.into(), + proof: proof.into(), + }) } } @@ -459,44 +480,43 @@ impl WasmSdk { .map(Some) .ok_or_else(|| WasmSdkError::generic("DPNS username is not a string")) } - #[wasm_bindgen( - js_name = "getDpnsUsernamesWithProofInfo", - unchecked_return_type = "ProofMetadataResponseTyped>" - )] + #[wasm_bindgen(js_name = "getDpnsUsernamesWithProofInfo")] pub async fn get_dpns_usernames_with_proof_info( &self, query: DpnsUsernamesQueryJs, - ) -> Result { + ) -> Result { let params = parse_dpns_usernames_query(query)?; self.fetch_dpns_usernames_with_proof(params.identity_id, params.limit) .await } - #[wasm_bindgen( - js_name = "getDpnsUsernameWithProofInfo", - unchecked_return_type = "ProofMetadataResponseTyped" - )] + #[wasm_bindgen(js_name = "getDpnsUsernameWithProofInfo")] pub async fn get_dpns_username_with_proof_info( &self, #[wasm_bindgen(js_name = "identityId")] #[wasm_bindgen(unchecked_param_type = "IdentifierLike")] identity_id: JsValue, - ) -> Result { + ) -> Result { let identity_id_parsed = identifier_from_js(&identity_id, "identity ID")?; - let mut response = self + let DpnsUsernamesProofResponseWasm { + usernames, + metadata, + proof, + } = self .fetch_dpns_usernames_with_proof(identity_id_parsed, Some(1)) .await?; - let usernames = js_sys::Array::from(&response.data()); let username = if usernames.length() > 0 { usernames.get(0) } else { JsValue::NULL }; - response.set_data(username); - - Ok(response) + Ok(DpnsUsernameProofResponseWasm { + username, + metadata, + proof, + }) } } diff --git a/packages/wasm-sdk/src/queries/mod.rs b/packages/wasm-sdk/src/queries/mod.rs index af044f4cf30..e9d6536be84 100644 --- a/packages/wasm-sdk/src/queries/mod.rs +++ b/packages/wasm-sdk/src/queries/mod.rs @@ -12,7 +12,7 @@ pub mod voting; // Re-export all query functions for easy access pub use group::*; -use js_sys::{Object, Reflect, Uint8Array}; +use js_sys::Uint8Array; use wasm_bindgen::prelude::*; use wasm_bindgen::JsValue; @@ -82,39 +82,6 @@ impl ResponseMetadataWasm { pub fn set_chain_id(&mut self, #[wasm_bindgen(js_name = "chainId")] chain_id: Uint8Array) { self.chain_id = chain_id.to_vec(); } - - #[wasm_bindgen(js_name = "toJSON")] - pub fn to_json(&self) -> JsValue { - let obj = Object::new(); - let _ = Reflect::set( - &obj, - &JsValue::from_str("height"), - &JsValue::from_f64(self.height as f64), - ); - let _ = Reflect::set( - &obj, - &JsValue::from_str("coreChainLockedHeight"), - &JsValue::from_f64(self.core_chain_locked_height as f64), - ); - let _ = Reflect::set( - &obj, - &JsValue::from_str("epoch"), - &JsValue::from_f64(self.epoch as f64), - ); - let _ = Reflect::set( - &obj, - &JsValue::from_str("timeMs"), - &JsValue::from_f64(self.time_ms as f64), - ); - let _ = Reflect::set( - &obj, - &JsValue::from_str("protocolVersion"), - &JsValue::from_f64(self.protocol_version as f64), - ); - let _ = Reflect::set(&obj, &JsValue::from_str("chainId"), &self.chain_id()); - - JsValue::from(obj) - } } // Helper function to convert platform ResponseMetadata to our ResponseMetadata @@ -221,35 +188,6 @@ impl ProofInfoWasm { ) { self.block_id_hash = block_id_hash.to_vec(); } - - #[wasm_bindgen(js_name = "toJSON")] - pub fn to_json(&self) -> JsValue { - let obj = Object::new(); - let _ = Reflect::set( - &obj, - &JsValue::from_str("grovedbProof"), - &self.grovedb_proof(), - ); - let _ = Reflect::set(&obj, &JsValue::from_str("quorumHash"), &self.quorum_hash()); - let _ = Reflect::set(&obj, &JsValue::from_str("signature"), &self.signature()); - let _ = Reflect::set( - &obj, - &JsValue::from_str("round"), - &JsValue::from_f64(self.round as f64), - ); - let _ = Reflect::set( - &obj, - &JsValue::from_str("blockIdHash"), - &self.block_id_hash(), - ); - let _ = Reflect::set( - &obj, - &JsValue::from_str("quorumType"), - &JsValue::from_f64(self.quorum_type as f64), - ); - - JsValue::from(obj) - } } // Helper function to convert platform Proof to our ProofInfo @@ -319,19 +257,6 @@ impl ProofMetadataResponseWasm { pub fn set_proof(&mut self, proof: ProofInfoWasm) { self.proof = proof; } - - #[wasm_bindgen(js_name = "toJSON")] - pub fn to_json(&self) -> JsValue { - let metadata_obj = self.metadata.to_json(); - let proof_obj = self.proof.to_json(); - - let obj = Object::new(); - let _ = Reflect::set(&obj, &JsValue::from_str("data"), &self.data); - let _ = Reflect::set(&obj, &JsValue::from_str("metadata"), &metadata_obj); - let _ = Reflect::set(&obj, &JsValue::from_str("proof"), &proof_obj); - - JsValue::from(obj) - } } impl ProofMetadataResponseWasm {