Skip to content

Commit c4e3f33

Browse files
committed
refactor: change Material.metadata from string to Uint8Array
update TypeScript and Rust layers to use Uint8Array/Vec<u8> for metadata instead of hex strings. callers now pass raw bytes directly. changes: - TypeScript Material interface: metadata is now Uint8Array - Rust Material struct: metadata is now Vec<u8> - MaterialJs WASM wrapper: accepts &[u8] instead of &str - decode_metadata functions: work with bytes directly (no hex decoding) - test fixtures: added hexToUint8Array helper and getWestendMetadata() - custom serde deserializer: handles hex strings (JSON) and byte arrays (WASM) BTC-3085
1 parent b82cd04 commit c4e3f33

13 files changed

Lines changed: 105 additions & 338 deletions

File tree

package-lock.json

Lines changed: 0 additions & 294 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/wasm-dot/js/types.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ export interface Material {
2424
specVersion: number;
2525
/** Transaction format version */
2626
txVersion: number;
27-
/** Runtime metadata bytes (hex encoded) - required for encoding calls */
28-
metadata: string;
27+
/** Runtime metadata bytes - required for encoding calls */
28+
metadata: Uint8Array;
2929
}
3030

3131
/**

packages/wasm-dot/src/address.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ pub fn decode_ss58(address: &str) -> Result<(Vec<u8>, u16), WasmDotError> {
7777
/// Validate an SS58 address
7878
pub fn validate_address(address: &str, expected_prefix: Option<u16>) -> bool {
7979
match decode_ss58(address) {
80-
Ok((_, prefix)) => expected_prefix.map_or(true, |expected| prefix == expected),
80+
Ok((_, prefix)) => expected_prefix.is_none_or(|expected| prefix == expected),
8181
Err(_) => false,
8282
}
8383
}

packages/wasm-dot/src/builder/calls.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ fn account_id(address: &str) -> Result<Value<()>, WasmDotError> {
265265
v.len()
266266
))
267267
})?;
268-
Ok(Value::from_bytes(&bytes))
268+
Ok(Value::from_bytes(bytes))
269269
}
270270

271271
#[cfg(test)]

packages/wasm-dot/src/builder/mod.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,9 @@ pub fn build_transaction(
4646
Ok(tx)
4747
}
4848

49-
/// Decode metadata from hex string
50-
fn decode_metadata(metadata_hex: &str) -> Result<subxt_core::metadata::Metadata, WasmDotError> {
51-
let bytes = hex::decode(metadata_hex.trim_start_matches("0x"))
52-
.map_err(|e| WasmDotError::InvalidInput(format!("Invalid metadata hex: {}", e)))?;
53-
54-
subxt_core::metadata::decode_from(&bytes[..])
49+
/// Decode metadata from raw bytes
50+
fn decode_metadata(metadata_bytes: &[u8]) -> Result<subxt_core::metadata::Metadata, WasmDotError> {
51+
subxt_core::metadata::decode_from(metadata_bytes)
5552
.map_err(|e| WasmDotError::InvalidInput(format!("Failed to decode metadata: {}", e)))
5653
}
5754

@@ -60,7 +57,7 @@ fn compute_era(validity: &Validity) -> Era {
6057
if validity.max_duration == 0 {
6158
Era::Immortal
6259
} else {
63-
let period = validity.max_duration.next_power_of_two().min(65536).max(4);
60+
let period = validity.max_duration.next_power_of_two().clamp(4, 65536);
6461
let phase = validity.first_valid % period;
6562
Era::Mortal { period, phase }
6663
}

packages/wasm-dot/src/builder/types.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ mod tests {
205205
"specName": "polkadot",
206206
"specVersion": 9150,
207207
"txVersion": 9,
208-
"metadata": "0x00"
208+
"metadata": [0]
209209
},
210210
"validity": {
211211
"firstValid": 1000,

packages/wasm-dot/src/parser.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -99,12 +99,9 @@ pub fn parse_transaction(
9999
})
100100
}
101101

102-
/// Decode metadata from hex string (same pattern as builder)
103-
fn decode_metadata(metadata_hex: &str) -> Result<subxt_core::metadata::Metadata, WasmDotError> {
104-
let bytes = hex::decode(metadata_hex.trim_start_matches("0x"))
105-
.map_err(|e| WasmDotError::InvalidInput(format!("Invalid metadata hex: {}", e)))?;
106-
107-
subxt_core::metadata::decode_from(&bytes[..])
102+
/// Decode metadata from raw bytes
103+
fn decode_metadata(metadata_bytes: &[u8]) -> Result<subxt_core::metadata::Metadata, WasmDotError> {
104+
subxt_core::metadata::decode_from(metadata_bytes)
108105
.map_err(|e| WasmDotError::InvalidInput(format!("Failed to decode metadata: {}", e)))
109106
}
110107

packages/wasm-dot/src/transaction.rs

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -399,12 +399,9 @@ impl Transaction {
399399
// Helper functions
400400
// =============================================================================
401401

402-
/// Decode metadata from hex string
403-
fn decode_metadata(metadata_hex: &str) -> Result<Metadata, WasmDotError> {
404-
let bytes = hex::decode(metadata_hex.trim_start_matches("0x"))
405-
.map_err(|e| WasmDotError::InvalidInput(format!("Invalid metadata hex: {}", e)))?;
406-
407-
subxt_core::metadata::decode_from(&bytes[..])
402+
/// Decode metadata from raw bytes
403+
fn decode_metadata(metadata_bytes: &[u8]) -> Result<Metadata, WasmDotError> {
404+
subxt_core::metadata::decode_from(metadata_bytes)
408405
.map_err(|e| WasmDotError::InvalidInput(format!("Failed to decode metadata: {}", e)))
409406
}
410407

@@ -438,22 +435,22 @@ pub(crate) fn encode_era(era: &Era) -> Vec<u8> {
438435
}
439436
}
440437

438+
/// Parsed extrinsic data: (is_signed, sender, signature, era, nonce, tip, call_data)
439+
type ParsedExtrinsic = (
440+
bool,
441+
Option<[u8; 32]>,
442+
Option<[u8; 64]>,
443+
Era,
444+
u32,
445+
u128,
446+
Vec<u8>,
447+
);
448+
441449
/// Parse a raw extrinsic
442450
fn parse_extrinsic(
443451
bytes: &[u8],
444452
metadata: Option<&Metadata>,
445-
) -> Result<
446-
(
447-
bool,
448-
Option<[u8; 32]>,
449-
Option<[u8; 64]>,
450-
Era,
451-
u32,
452-
u128,
453-
Vec<u8>,
454-
),
455-
WasmDotError,
456-
> {
453+
) -> Result<ParsedExtrinsic, WasmDotError> {
457454
use parity_scale_codec::{Compact, Decode};
458455

459456
let mut cursor = 0;

packages/wasm-dot/src/types.rs

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,60 @@
22
33
use serde::{Deserialize, Serialize};
44

5+
/// Helper module for deserializing metadata from hex string or byte array
6+
mod metadata_serde {
7+
use serde::Deserializer;
8+
9+
pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
10+
where
11+
D: Deserializer<'de>,
12+
{
13+
use core::fmt;
14+
use serde::de::{self, Visitor};
15+
16+
struct MetadataVisitor;
17+
18+
impl<'de> Visitor<'de> for MetadataVisitor {
19+
type Value = Vec<u8>;
20+
21+
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
22+
formatter.write_str("a hex string or byte array")
23+
}
24+
25+
// Handle hex strings
26+
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
27+
where
28+
E: de::Error,
29+
{
30+
let s = v.strip_prefix("0x").unwrap_or(v);
31+
hex::decode(s).map_err(de::Error::custom)
32+
}
33+
34+
// Handle byte arrays (from serde_json or direct Vec<u8>)
35+
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
36+
where
37+
A: de::SeqAccess<'de>,
38+
{
39+
let mut bytes = Vec::new();
40+
while let Some(byte) = seq.next_element()? {
41+
bytes.push(byte);
42+
}
43+
Ok(bytes)
44+
}
45+
46+
// Handle byte slices (from serde_wasm_bindgen with Uint8Array)
47+
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
48+
where
49+
E: de::Error,
50+
{
51+
Ok(v.to_vec())
52+
}
53+
}
54+
55+
deserializer.deserialize_any(MetadataVisitor)
56+
}
57+
}
58+
559
/// Chain material metadata required for transaction encoding/decoding
660
#[derive(Debug, Clone, Serialize, Deserialize)]
761
#[serde(rename_all = "camelCase")]
@@ -16,9 +70,10 @@ pub struct Material {
1670
pub spec_version: u32,
1771
/// Transaction format version
1872
pub tx_version: u32,
19-
/// Runtime metadata bytes (hex encoded)
73+
/// Runtime metadata bytes
2074
/// Required for encoding calls - handles runtime upgrades automatically
21-
pub metadata: String,
75+
#[serde(deserialize_with = "metadata_serde::deserialize")]
76+
pub metadata: Vec<u8>,
2277
}
2378

2479
/// Validity window for mortal transactions

packages/wasm-dot/src/wasm/transaction.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ impl MaterialJs {
224224
spec_name: &str,
225225
spec_version: u32,
226226
tx_version: u32,
227-
metadata: &str,
227+
metadata: &[u8],
228228
) -> MaterialJs {
229229
MaterialJs {
230230
inner: Material {
@@ -233,7 +233,7 @@ impl MaterialJs {
233233
spec_name: spec_name.to_string(),
234234
spec_version,
235235
tx_version,
236-
metadata: metadata.to_string(),
236+
metadata: metadata.to_vec(),
237237
},
238238
}
239239
}

0 commit comments

Comments
 (0)