diff --git a/packages/wasm-sdk/AI_REFERENCE.md b/packages/wasm-sdk/AI_REFERENCE.md
index 23531a9e085..596c2c39b61 100644
--- a/packages/wasm-sdk/AI_REFERENCE.md
+++ b/packages/wasm-sdk/AI_REFERENCE.md
@@ -763,7 +763,7 @@ Parameters:
- `assetLockProofPrivateKey` (string, required) - Asset Lock Proof Private Key
- WIF format private key
- `publicKeys` (string, required) - Public Keys
- - JSON array of public keys
+ - JSON array of public keys. Key requirements: ECDSA_SECP256K1 requires privateKeyHex or privateKeyWif for signing, BLS12_381 requires privateKeyHex for signing, ECDSA_HASH160 requires either the data field (base64-encoded 20-byte public key hash) or privateKeyHex (produces empty signatures).
Example:
```javascript
@@ -771,23 +771,25 @@ Example:
const assetLockProof = "a9147d3b... (hex-encoded)";
const assetLockProofPrivateKey = "XFfpaSbZq52HPy3WWwe1dXsZMiU1bQn8vQd34HNXkSZThevBWRn1"; // WIF format
-// Public keys array with proper key types
+// Public keys array with proper key types and private keys for signing/hashing
const publicKeys = JSON.stringify([
{
id: 0,
- type: 0, // ECDSA_SECP256K1 = 0, BLS12_381 = 1, ECDSA_HASH160 = 2
- purpose: 0, // AUTHENTICATION = 0, ENCRYPTION = 1, DECRYPTION = 2, TRANSFER = 3, etc.
- securityLevel: 0, // MASTER = 0, CRITICAL = 1, HIGH = 2, MEDIUM = 3
+ keyType: "ECDSA_SECP256K1",
+ purpose: "AUTHENTICATION",
+ securityLevel: "MASTER",
data: "A5GzYHPIolbHkFrp5l+s9IvF2lWMuuuSu3oWZB8vWHNJ", // Base64-encoded public key
- readOnly: false
+ readOnly: false,
+ privateKeyWif: "XBrZJKcW4ajWVNAU6yP87WQog6CjFnpbqyAKgNTZRqmhYvPgMNV2"
},
{
id: 1,
- type: 0,
- purpose: 0,
- securityLevel: 2,
- data: "AnotherBase64EncodedPublicKeyHere", // Base64-encoded public key
- readOnly: false
+ keyType: "ECDSA_HASH160",
+ purpose: "AUTHENTICATION",
+ securityLevel: "HIGH",
+ data: "ripemd160hash20bytes1234", // Base64-encoded 20-byte RIPEMD160 hash
+ readOnly: false,
+ // ECDSA_HASH160 keys produce empty signatures (not required/used for signing)
}
]);
diff --git a/packages/wasm-sdk/Cargo.toml b/packages/wasm-sdk/Cargo.toml
index ced15c058e2..9478867423d 100644
--- a/packages/wasm-sdk/Cargo.toml
+++ b/packages/wasm-sdk/Cargo.toml
@@ -25,7 +25,7 @@ token_reward_explanations = ["dash-sdk/token_reward_explanations"]
[dependencies]
dash-sdk = { path = "../rs-sdk", default-features = false }
-simple-signer = { path = "../simple-signer" }
+simple-signer = { path = "../simple-signer", features = ["state-transitions"] }
drive = { path = "../rs-drive", default-features = false, features = ["verify"] }
console_error_panic_hook = { version = "0.1.6" }
thiserror = { version = "2.0.12" }
diff --git a/packages/wasm-sdk/api-definitions.json b/packages/wasm-sdk/api-definitions.json
index 0953ed5407a..c2fcfc7bc43 100644
--- a/packages/wasm-sdk/api-definitions.json
+++ b/packages/wasm-sdk/api-definitions.json
@@ -1234,6 +1234,24 @@
],
"help": "Default adds standard keys for most Platform operations. Advanced allows custom key configuration."
},
+ {
+ "name": "keyType",
+ "type": "select",
+ "label": "Key Type",
+ "required": true,
+ "value": "ECDSA_HASH160",
+ "options": [
+ {
+ "value": "ECDSA_HASH160",
+ "label": "ECDSA_HASH160 (Dash Evo Tool default)"
+ },
+ {
+ "value": "ECDSA_SECP256K1",
+ "label": "ECDSA_SECP256K1 (Dash mobile wallet default)"
+ }
+ ],
+ "help": "Choose key type"
+ },
{
"name": "keyPreview",
"type": "keyPreview",
@@ -1261,10 +1279,10 @@
"type": "string",
"label": "Public Keys",
"required": true,
- "description": "JSON array of public keys"
+ "description": "JSON array of public keys. Key requirements: ECDSA_SECP256K1 requires privateKeyHex or privateKeyWif for signing, BLS12_381 requires privateKeyHex for signing, ECDSA_HASH160 requires either the data field (base64-encoded 20-byte public key hash) or privateKeyHex (produces empty signatures)."
}
],
- "sdk_example": "// Asset lock proof is a hex-encoded JSON object\nconst assetLockProof = \"a9147d3b... (hex-encoded)\";\nconst assetLockProofPrivateKey = \"XFfpaSbZq52HPy3WWwe1dXsZMiU1bQn8vQd34HNXkSZThevBWRn1\"; // WIF format\n\n// Public keys array with proper key types\nconst publicKeys = JSON.stringify([\n {\n id: 0,\n type: 0, // ECDSA_SECP256K1 = 0, BLS12_381 = 1, ECDSA_HASH160 = 2\n purpose: 0, // AUTHENTICATION = 0, ENCRYPTION = 1, DECRYPTION = 2, TRANSFER = 3, etc.\n securityLevel: 0, // MASTER = 0, CRITICAL = 1, HIGH = 2, MEDIUM = 3\n data: \"A5GzYHPIolbHkFrp5l+s9IvF2lWMuuuSu3oWZB8vWHNJ\", // Base64-encoded public key\n readOnly: false\n },\n {\n id: 1,\n type: 0,\n purpose: 0,\n securityLevel: 2,\n data: \"AnotherBase64EncodedPublicKeyHere\", // Base64-encoded public key\n readOnly: false\n }\n]);\n\nconst result = await sdk.identityCreate(assetLockProof, assetLockProofPrivateKey, publicKeys);"
+ "sdk_example": "// Asset lock proof is a hex-encoded JSON object\nconst assetLockProof = \"a9147d3b... (hex-encoded)\";\nconst assetLockProofPrivateKey = \"XFfpaSbZq52HPy3WWwe1dXsZMiU1bQn8vQd34HNXkSZThevBWRn1\"; // WIF format\n\n// Public keys array with proper key types and private keys for signing/hashing\nconst publicKeys = JSON.stringify([\n {\n id: 0,\n keyType: \"ECDSA_SECP256K1\",\n purpose: \"AUTHENTICATION\",\n securityLevel: \"MASTER\",\n data: \"A5GzYHPIolbHkFrp5l+s9IvF2lWMuuuSu3oWZB8vWHNJ\", // Base64-encoded public key\n readOnly: false,\n privateKeyWif: \"XBrZJKcW4ajWVNAU6yP87WQog6CjFnpbqyAKgNTZRqmhYvPgMNV2\"\n },\n {\n id: 1,\n keyType: \"ECDSA_HASH160\",\n purpose: \"AUTHENTICATION\",\n securityLevel: \"HIGH\",\n data: \"ripemd160hash20bytes1234\", // Base64-encoded 20-byte RIPEMD160 hash\n readOnly: false,\n // ECDSA_HASH160 keys produce empty signatures (not required/used for signing)\n }\n]);\n\nconst result = await sdk.identityCreate(assetLockProof, assetLockProofPrivateKey, publicKeys);"
},
"identityTopUp": {
"label": "Identity Top Up",
diff --git a/packages/wasm-sdk/docs.html b/packages/wasm-sdk/docs.html
index d2a533b9410..72df8131cee 100644
--- a/packages/wasm-sdk/docs.html
+++ b/packages/wasm-sdk/docs.html
@@ -1967,7 +1967,7 @@
Parameters:
Public Keys
string
(required)
-
JSON array of public keys
+
JSON array of public keys. Key requirements: ECDSA_SECP256K1 requires privateKeyHex or privateKeyWif for signing, BLS12_381 requires privateKeyHex for signing, ECDSA_HASH160 requires either the data field (base64-encoded 20-byte public key hash) or privateKeyHex (produces empty signatures).
@@ -1977,23 +1977,25 @@ Example
const assetLockProof = "a9147d3b... (hex-encoded)";
const assetLockProofPrivateKey = "XFfpaSbZq52HPy3WWwe1dXsZMiU1bQn8vQd34HNXkSZThevBWRn1"; // WIF format
-// Public keys array with proper key types
+// Public keys array with proper key types and private keys for signing/hashing
const publicKeys = JSON.stringify([
{
id: 0,
- type: 0, // ECDSA_SECP256K1 = 0, BLS12_381 = 1, ECDSA_HASH160 = 2
- purpose: 0, // AUTHENTICATION = 0, ENCRYPTION = 1, DECRYPTION = 2, TRANSFER = 3, etc.
- securityLevel: 0, // MASTER = 0, CRITICAL = 1, HIGH = 2, MEDIUM = 3
+ keyType: "ECDSA_SECP256K1",
+ purpose: "AUTHENTICATION",
+ securityLevel: "MASTER",
data: "A5GzYHPIolbHkFrp5l+s9IvF2lWMuuuSu3oWZB8vWHNJ", // Base64-encoded public key
- readOnly: false
+ readOnly: false,
+ privateKeyWif: "XBrZJKcW4ajWVNAU6yP87WQog6CjFnpbqyAKgNTZRqmhYvPgMNV2"
},
{
id: 1,
- type: 0,
- purpose: 0,
- securityLevel: 2,
- data: "AnotherBase64EncodedPublicKeyHere", // Base64-encoded public key
- readOnly: false
+ keyType: "ECDSA_HASH160",
+ purpose: "AUTHENTICATION",
+ securityLevel: "HIGH",
+ data: "ripemd160hash20bytes1234", // Base64-encoded 20-byte RIPEMD160 hash
+ readOnly: false,
+ // ECDSA_HASH160 keys produce empty signatures (not required/used for signing)
}
]);
diff --git a/packages/wasm-sdk/index.html b/packages/wasm-sdk/index.html
index 94d5cfb5438..d638e408697 100644
--- a/packages/wasm-sdk/index.html
+++ b/packages/wasm-sdk/index.html
@@ -3062,6 +3062,7 @@ Results
const seedPhrase = values.seedPhrase?.trim();
const identityIndex = parseInt(values.identityIndex || '0');
const keySelectionMode = values.keySelectionMode || 'default';
+ const selectedKeyType = values.keyType || 'ECDSA_HASH160';
if (!seedPhrase || !validate_mnemonic(seedPhrase)) {
throw new Error('Invalid seed phrase');
@@ -3089,10 +3090,11 @@ Results
// Create public key objects for the SDK
// Pass private keys so the SDK can derive the correct public key data using DPP
+ // Use the selected key type for all keys
publicKeys = [
{
id: 0,
- keyType: "ECDSA_HASH160",
+ keyType: selectedKeyType,
purpose: "AUTHENTICATION",
securityLevel: "MASTER",
privateKeyHex: masterKey.private_key_hex,
@@ -3100,7 +3102,7 @@ Results
},
{
id: 1,
- keyType: "ECDSA_HASH160",
+ keyType: selectedKeyType,
purpose: "AUTHENTICATION",
securityLevel: "HIGH",
privateKeyHex: authKey.private_key_hex,
@@ -3108,7 +3110,7 @@ Results
},
{
id: 2,
- keyType: "ECDSA_HASH160",
+ keyType: selectedKeyType,
purpose: "TRANSFER",
securityLevel: "CRITICAL",
privateKeyHex: transferKey.private_key_hex,
@@ -4293,6 +4295,7 @@ Results
const seedPhrase = dynamicInputs.querySelector('[name="seedPhrase"]')?.value?.trim();
const identityIndex = parseInt(dynamicInputs.querySelector('[name="identityIndex"]')?.value || '0');
const keySelectionMode = dynamicInputs.querySelector('[name="keySelectionMode"]')?.value || 'default';
+ const selectedKeyType = dynamicInputs.querySelector('[name="keyType"]')?.value || 'ECDSA_HASH160';
const previewContainer = document.getElementById('keyPreviewContainer');
if (!seedPhrase || !previewContainer) return;
@@ -4320,21 +4323,26 @@ Results
const transferKeyPath = `m/9'/${currentNetwork === 'mainnet' ? 5 : 1}'/5'/0'/0'/${identityIndex}'/2'`;
const transferKey = derive_key_from_seed_with_path(seedPhrase, undefined, transferKeyPath, currentNetwork);
+ // Show signature requirement info
+ const signatureInfo = selectedKeyType === 'ECDSA_SECP256K1'
+ ? ' (Individual signatures required)'
+ : ' (No individual signatures required)';
+
keysHtml += `
Master Key:
${masterKey.private_key_wif}
- Purpose: Authentication | Security: Master | Type: ECDSA_HASH160
+ Purpose: Authentication | Security: Master | Type: ${selectedKeyType}${signatureInfo}
Key 1:
${authKey.private_key_wif}
- Purpose: Authentication | Security: High | Type: ECDSA_HASH160
+ Purpose: Authentication | Security: High | Type: ${selectedKeyType}${signatureInfo}
Key 2:
${transferKey.private_key_wif}
- Purpose: Transfer | Security: Critical | Type: ECDSA_HASH160
+ Purpose: Transfer | Security: Critical | Type: ${selectedKeyType}${signatureInfo}
`;
@@ -4353,10 +4361,12 @@ Results
const seedInput = dynamicInputs.querySelector('[name="seedPhrase"]');
const indexInput = dynamicInputs.querySelector('[name="identityIndex"]');
const modeSelect = dynamicInputs.querySelector('[name="keySelectionMode"]');
+ const keyTypeSelect = dynamicInputs.querySelector('[name="keyType"]');
if (seedInput) seedInput.addEventListener('input', updateKeyPreview);
if (indexInput) indexInput.addEventListener('input', updateKeyPreview);
if (modeSelect) modeSelect.addEventListener('change', updateKeyPreview);
+ if (keyTypeSelect) keyTypeSelect.addEventListener('change', updateKeyPreview);
// Initial update
updateKeyPreview();
diff --git a/packages/wasm-sdk/src/state_transitions/identity/mod.rs b/packages/wasm-sdk/src/state_transitions/identity/mod.rs
index 995d43e94be..6538880d095 100644
--- a/packages/wasm-sdk/src/state_transitions/identity/mod.rs
+++ b/packages/wasm-sdk/src/state_transitions/identity/mod.rs
@@ -9,7 +9,7 @@ use dash_sdk::dpp::state_transition::identity_credit_transfer_transition::Identi
use dash_sdk::dpp::state_transition::identity_credit_transfer_transition::methods::IdentityCreditTransferTransitionMethodsV0;
use dash_sdk::platform::transition::broadcast::BroadcastStateTransition;
use dash_sdk::platform::Fetch;
-use simple_signer::SingleKeySigner;
+use simple_signer::{SingleKeySigner, signer::SimpleSigner};
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsValue;
use js_sys;
@@ -27,7 +27,17 @@ impl WasmSdk {
///
/// * `asset_lock_proof` - The asset lock proof (transaction hex)
/// * `asset_lock_proof_private_key` - The private key that controls the asset lock
- /// * `public_keys` - JSON array of public keys to add to the identity
+ /// * `public_keys` - JSON array of public keys to add to the identity. Each key object requirements:
+ /// - ECDSA_SECP256K1: Requires `privateKeyHex` or `privateKeyWif` for signing
+ /// - BLS12_381: Requires `privateKeyHex` for signing (WIF format not supported)
+ /// - ECDSA_HASH160: Accepts either `privateKeyHex` (to derive hash) or `data` field (base64-encoded 20-byte hash)
+ ///
+ /// # Implementation Notes
+ ///
+ /// This function uses SimpleSigner to provide individual signatures for each public key as required.
+ /// Each ECDSA_SECP256K1 key will be signed with its corresponding private key (from privateKeyHex or privateKeyWif),
+ /// and each BLS12_381 key will be signed with its corresponding private key (from privateKeyHex only),
+ /// ensuring unique signatures per key as required by DPP validation.
///
/// # Returns
///
@@ -80,8 +90,9 @@ impl WasmSdk {
let keys_array = keys_data.as_array()
.ok_or_else(|| JsValue::from_str("public_keys must be a JSON array"))?;
- // Create identity public keys
+ // Create identity public keys and collect private keys for signing
let mut identity_public_keys = std::collections::BTreeMap::new();
+ let mut signer = SimpleSigner::default();
let mut key_id = 0u32;
for key_data in keys_array {
@@ -122,31 +133,120 @@ impl WasmSdk {
_ => SecurityLevel::HIGH
};
- // Check if privateKeyHex is provided - if so, derive public key data from it
- let public_key_data = if let Some(private_key_hex) = key_data["privateKeyHex"].as_str() {
- // Decode private key from hex
- let private_key_bytes = hex::decode(private_key_hex)
- .map_err(|e| JsValue::from_str(&format!("Invalid private key hex: {}", e)))?;
-
- if private_key_bytes.len() != 32 {
- return Err(JsValue::from_str(&format!("Private key must be 32 bytes, got {}", private_key_bytes.len())));
+ // Handle key data based on key type
+ let (public_key_data, private_key_bytes) = match key_type {
+ KeyType::ECDSA_HASH160 => {
+ // Derive HASH160 data from the private key if provided
+ if let Some(private_key_hex) = key_data["privateKeyHex"].as_str() {
+ // Decode private key from hex
+ let bytes = hex::decode(private_key_hex)
+ .map_err(|e| JsValue::from_str(&format!("Invalid private key hex: {}", e)))?;
+
+ if bytes.len() != 32 {
+ return Err(JsValue::from_str(&format!(
+ "Private key must be 32 bytes, got {}",
+ bytes.len()
+ )));
+ }
+
+ let mut private_key_array = [0u8; 32];
+ private_key_array.copy_from_slice(&bytes);
+
+ // Derive HASH160 public key data from private key using network
+ let derived_data = key_type
+ .public_key_data_from_private_key_data(&private_key_array, self.network())
+ .map_err(|e| {
+ JsValue::from_str(&format!(
+ "Failed to derive ECDSA_HASH160 public key data: {}",
+ e
+ ))
+ })?;
+
+ // HASH160 keys are not used for signing during identity creation
+ (derived_data, [0u8; 32])
+ } else if let Some(data_str) = key_data["data"].as_str() {
+ let key_data_bytes = dash_sdk::dpp::dashcore::base64::decode(data_str)
+ .map_err(|e| JsValue::from_str(&format!("Invalid base64 key data: {}", e)))?;
+
+ // Enforce correct HASH160 size (20 bytes).
+ if key_data_bytes.len() != 20 {
+ return Err(JsValue::from_str(&format!(
+ "ECDSA_HASH160 key data must be 20 bytes, got {}",
+ key_data_bytes.len()
+ )));
+ }
+
+ (key_data_bytes, [0u8; 32])
+ } else {
+ return Err(JsValue::from_str(
+ "ECDSA_HASH160 requires either 'privateKeyHex' to derive from or 'data' (base64-encoded 20-byte hash)",
+ ));
+ }
+ },
+ KeyType::ECDSA_SECP256K1 => {
+ // For ECDSA signing keys, support both hex and WIF formats
+ let private_key_bytes = if let Some(private_key_hex) = key_data["privateKeyHex"].as_str() {
+ // Decode private key from hex
+ let bytes = hex::decode(private_key_hex)
+ .map_err(|e| JsValue::from_str(&format!("Invalid private key hex: {}", e)))?;
+
+ if bytes.len() != 32 {
+ return Err(JsValue::from_str(&format!("Private key must be 32 bytes, got {}", bytes.len())));
+ }
+
+ let mut private_key_array = [0u8; 32];
+ private_key_array.copy_from_slice(&bytes);
+ private_key_array
+ } else if let Some(private_key_wif) = key_data["privateKeyWif"].as_str() {
+ // Parse WIF format private key
+ let private_key = PrivateKey::from_wif(private_key_wif)
+ .map_err(|e| JsValue::from_str(&format!("Invalid WIF private key: {}", e)))?;
+ private_key.inner.secret_bytes()
+ } else {
+ return Err(JsValue::from_str("ECDSA_SECP256K1 keys require either privateKeyHex or privateKeyWif"));
+ };
+
+ // Derive public key data from private key
+ let public_key_data = key_type.public_key_data_from_private_key_data(
+ &private_key_bytes,
+ self.network()
+ ).map_err(|e| JsValue::from_str(&format!("Failed to derive ECDSA_SECP256K1 public key data: {}", e)))?;
+
+ (public_key_data, private_key_bytes)
+ },
+ KeyType::BLS12_381 => {
+ // BLS12_381 keys only support hex format (WIF is not valid for BLS keys)
+ if key_data["privateKeyWif"].is_string() {
+ return Err(JsValue::from_str("BLS12_381 keys do not support WIF format, use privateKeyHex only"));
+ }
+
+ let private_key_bytes = if let Some(private_key_hex) = key_data["privateKeyHex"].as_str() {
+ // Decode private key from hex
+ let bytes = hex::decode(private_key_hex)
+ .map_err(|e| JsValue::from_str(&format!("Invalid private key hex: {}", e)))?;
+
+ if bytes.len() != 32 {
+ return Err(JsValue::from_str(&format!("Private key must be 32 bytes, got {}", bytes.len())));
+ }
+
+ let mut private_key_array = [0u8; 32];
+ private_key_array.copy_from_slice(&bytes);
+ private_key_array
+ } else {
+ return Err(JsValue::from_str("BLS12_381 keys require privateKeyHex"));
+ };
+
+ // Derive public key data from private key
+ let public_key_data = key_type.public_key_data_from_private_key_data(
+ &private_key_bytes,
+ self.network()
+ ).map_err(|e| JsValue::from_str(&format!("Failed to derive BLS12_381 public key data: {}", e)))?;
+
+ (public_key_data, private_key_bytes)
+ },
+ _ => {
+ return Err(JsValue::from_str(&format!("Unsupported key type for identity creation: {}", key_type_str)));
}
-
- let mut private_key_array = [0u8; 32];
- private_key_array.copy_from_slice(&private_key_bytes);
-
- // Use DPP's built-in method to get the correct public key data for the key type
- // Use network from SDK configuration
- key_type.public_key_data_from_private_key_data(
- &private_key_array,
- self.network()
- ).map_err(|e| JsValue::from_str(&format!("Failed to derive public key data: {}", e)))?
- } else if let Some(data_str) = key_data["data"].as_str() {
- // Fall back to using provided data (base64 encoded)
- dash_sdk::dpp::dashcore::base64::decode(data_str)
- .map_err(|e| JsValue::from_str(&format!("Invalid base64 key data: {}", e)))?
- } else {
- return Err(JsValue::from_str("Either privateKeyHex or data must be provided"));
};
// Create the identity public key
@@ -162,6 +262,11 @@ impl WasmSdk {
disabled_at: None,
});
+ // Add the public key and its private key to the signer (only for signing key types)
+ if key_type != KeyType::ECDSA_HASH160 {
+ signer.add_key(public_key.clone(), private_key_bytes);
+ }
+
identity_public_keys.insert(key_id, public_key);
key_id += 1;
}
@@ -175,13 +280,8 @@ impl WasmSdk {
revision: 0,
});
- // Create signer from asset lock proof private key using SDK's network configuration
- let signer = SingleKeySigner::from_string(&asset_lock_proof_private_key, self.network())
- .map_err(|e| {
- let error_msg = format!("Invalid private key: {}", e);
- web_sys::console::error_1(&JsValue::from_str(&error_msg));
- JsValue::from_str(&error_msg)
- })?;
+ // Use the SimpleSigner we built with all the identity keys
+ // The signer now contains all private keys for signing each public key individually
// Put identity to platform and wait
let created_identity = match identity
diff --git a/packages/wasm-sdk/test/state-transitions.test.mjs b/packages/wasm-sdk/test/state-transitions.test.mjs
index 9f8fb34c371..9366a73cba4 100644
--- a/packages/wasm-sdk/test/state-transitions.test.mjs
+++ b/packages/wasm-sdk/test/state-transitions.test.mjs
@@ -20,7 +20,8 @@ if (!global.crypto) {
}
// Import WASM SDK
-import init, * as wasmSdk from '../pkg/wasm_sdk.js';
+import init, { generate_key_pair } from '../pkg/wasm_sdk.js';
+import * as wasmSdk from '../pkg/wasm_sdk.js';
// Initialize WASM
console.log('Initializing WASM SDK...');
@@ -81,6 +82,171 @@ await test('identity_create - requires funding', async () => {
}
});
+await test('identity_create with all SECP256K1 keys (common scenario)', async () => {
+ try {
+ // Generate unique keys for testing (1 asset lock + 3 identity keys)
+ const assetLockKey = generate_key_pair("testnet");
+ const secp256k1Key1 = generate_key_pair("testnet");
+ const secp256k1Key2 = generate_key_pair("testnet");
+ const secp256k1Key3 = generate_key_pair("testnet");
+
+ // Mock asset lock proof
+ const mockAssetLockProof = JSON.stringify({
+ coreChainLockedHeight: 1000000,
+ outPoint: "0000000000000000000000000000000000000000000000000000000000000000:0"
+ });
+
+ // Create public keys array with all SECP256K1 keys
+ const publicKeys = JSON.stringify([
+ {
+ keyType: "ECDSA_SECP256K1",
+ purpose: "AUTHENTICATION",
+ securityLevel: "MASTER",
+ privateKeyHex: secp256k1Key1.private_key_hex
+ },
+ {
+ keyType: "ECDSA_SECP256K1",
+ purpose: "AUTHENTICATION",
+ securityLevel: "CRITICAL",
+ privateKeyHex: secp256k1Key2.private_key_hex
+ },
+ {
+ keyType: "ECDSA_SECP256K1",
+ purpose: "ENCRYPTION",
+ securityLevel: "HIGH",
+ privateKeyHex: secp256k1Key3.private_key_hex
+ }
+ ]);
+
+ const result = await sdk.identityCreate(
+ mockAssetLockProof,
+ assetLockKey.private_key_wif,
+ publicKeys
+ );
+ throw new Error('Should fail with mock data');
+ } catch (error) {
+ const errorMessage = error.message || error.toString() || 'Unknown error';
+ if (errorMessage.includes('Should fail')) {
+ throw error;
+ }
+ // Check that it's NOT a signature verification error
+ if (errorMessage.includes('signature failed verification')) {
+ throw new Error('SIGNATURE VERIFICATION ERROR - SimpleSigner may not be working correctly');
+ }
+ console.log(' Expected error with mock data (not signature error)');
+ }
+});
+
+await test('identity_create with mixed key types (SECP256K1 and HASH160)', async () => {
+ try {
+ // Generate unique keys for testing (1 asset lock + 2 SECP256K1 + 1 HASH160)
+ const assetLockKey = generate_key_pair("testnet");
+ const secp256k1Key1 = generate_key_pair("testnet");
+ const secp256k1Key2 = generate_key_pair("testnet");
+ const hash160Key = generate_key_pair("testnet");
+
+ // Mock asset lock proof
+ const mockAssetLockProof = JSON.stringify({
+ coreChainLockedHeight: 1000000,
+ outPoint: "0000000000000000000000000000000000000000000000000000000000000001:0"
+ });
+
+ // Create mixed public keys array
+ const publicKeys = JSON.stringify([
+ {
+ keyType: "ECDSA_SECP256K1",
+ purpose: "AUTHENTICATION",
+ securityLevel: "MASTER",
+ privateKeyHex: secp256k1Key1.private_key_hex
+ },
+ {
+ keyType: "ECDSA_SECP256K1",
+ purpose: "AUTHENTICATION",
+ securityLevel: "CRITICAL",
+ privateKeyHex: secp256k1Key2.private_key_hex
+ },
+ {
+ keyType: "ECDSA_HASH160",
+ purpose: "TRANSFER",
+ securityLevel: "HIGH",
+ privateKeyHex: hash160Key.private_key_hex
+ }
+ ]);
+
+ const result = await sdk.identityCreate(
+ mockAssetLockProof,
+ assetLockKey.private_key_wif,
+ publicKeys
+ );
+ throw new Error('Should fail with mock data');
+ } catch (error) {
+ const errorMessage = error.message || error.toString() || 'Unknown error';
+ if (errorMessage.includes('Should fail')) {
+ throw error;
+ }
+ // Check that it's NOT a signature verification error
+ if (errorMessage.includes('signature failed verification')) {
+ throw new Error('SIGNATURE VERIFICATION ERROR - SimpleSigner may not be working correctly');
+ }
+ console.log(' Expected error with mock data (not signature error)');
+ }
+});
+
+await test('identity_create with only HASH160 keys', async () => {
+ try {
+ // Generate unique keys for testing (1 asset lock + 3 HASH160)
+ const assetLockKey = generate_key_pair("testnet");
+ const hash160Key1 = generate_key_pair("testnet");
+ const hash160Key2 = generate_key_pair("testnet");
+ const hash160Key3 = generate_key_pair("testnet");
+
+ // Mock asset lock proof
+ const mockAssetLockProof = JSON.stringify({
+ coreChainLockedHeight: 1000000,
+ outPoint: "0000000000000000000000000000000000000000000000000000000000000002:0"
+ });
+
+ // Create public keys array with all HASH160 keys
+ const publicKeys = JSON.stringify([
+ {
+ keyType: "ECDSA_HASH160",
+ purpose: "AUTHENTICATION",
+ securityLevel: "MASTER",
+ privateKeyHex: hash160Key1.private_key_hex
+ },
+ {
+ keyType: "ECDSA_HASH160",
+ purpose: "AUTHENTICATION",
+ securityLevel: "CRITICAL",
+ privateKeyHex: hash160Key2.private_key_hex
+ },
+ {
+ keyType: "ECDSA_HASH160",
+ purpose: "TRANSFER",
+ securityLevel: "HIGH",
+ privateKeyHex: hash160Key3.private_key_hex
+ }
+ ]);
+
+ const result = await sdk.identityCreate(
+ mockAssetLockProof,
+ assetLockKey.private_key_wif,
+ publicKeys
+ );
+ throw new Error('Should fail with mock data');
+ } catch (error) {
+ const errorMessage = error.message || error.toString() || 'Unknown error';
+ if (errorMessage.includes('Should fail')) {
+ throw error;
+ }
+ // Check that it's NOT a signature verification error
+ if (errorMessage.includes('signature failed verification')) {
+ throw new Error('SIGNATURE VERIFICATION ERROR - SimpleSigner may not be working correctly');
+ }
+ console.log(' Expected error with mock data (not signature error)');
+ }
+});
+
await test('identity_update - requires existing identity', async () => {
try {
const updateData = JSON.stringify({
@@ -144,18 +310,6 @@ await test('identity_withdraw - requires balance', async () => {
}
});
-await test('identity_put - causes panic in WASM', async () => {
- try {
- const result = await wasmSdk.identity_put(sdk);
- throw new Error('Should have panicked');
- } catch (error) {
- if (error.message.includes('Should have panicked')) {
- throw error;
- }
- console.log(' Expected panic (known issue)');
- }
-});
-
// Document State Transitions
describe('Document State Transitions');