1use crate::codec::*;
13
14pub const TAG_HANDSHAKE_REQ: u8 = 0;
20pub const TAG_HANDSHAKE_RESP: u8 = 1;
21pub const TAG_FEATURE_SUPPORTED_REQ: u8 = 2;
22pub const TAG_FEATURE_SUPPORTED_RESP: u8 = 3;
23pub const TAG_PUSH_NOTIFICATION_REQ: u8 = 4;
24pub const TAG_PUSH_NOTIFICATION_RESP: u8 = 5;
25pub const TAG_NAVIGATE_TO_REQ: u8 = 6;
26pub const TAG_NAVIGATE_TO_RESP: u8 = 7;
27pub const TAG_DEVICE_PERMISSION_REQ: u8 = 8;
28pub const TAG_DEVICE_PERMISSION_RESP: u8 = 9;
29pub const TAG_REMOTE_PERMISSION_REQ: u8 = 10;
30pub const TAG_REMOTE_PERMISSION_RESP: u8 = 11;
31pub const TAG_LOCAL_STORAGE_READ_REQ: u8 = 12;
32pub const TAG_LOCAL_STORAGE_READ_RESP: u8 = 13;
33pub const TAG_LOCAL_STORAGE_WRITE_REQ: u8 = 14;
34pub const TAG_LOCAL_STORAGE_WRITE_RESP: u8 = 15;
35pub const TAG_LOCAL_STORAGE_CLEAR_REQ: u8 = 16;
36pub const TAG_LOCAL_STORAGE_CLEAR_RESP: u8 = 17;
37pub const TAG_ACCOUNT_STATUS_START: u8 = 18;
39pub const TAG_ACCOUNT_STATUS_STOP: u8 = 19;
40pub const TAG_ACCOUNT_STATUS_INTERRUPT: u8 = 20;
41pub const TAG_ACCOUNT_STATUS_RECEIVE: u8 = 21;
42pub const TAG_ACCOUNT_GET_REQ: u8 = 22;
43pub const TAG_ACCOUNT_GET_RESP: u8 = 23;
44pub const TAG_ACCOUNT_GET_ALIAS_REQ: u8 = 24;
45pub const TAG_ACCOUNT_GET_ALIAS_RESP: u8 = 25;
46pub const TAG_ACCOUNT_CREATE_PROOF_REQ: u8 = 26;
47pub const TAG_ACCOUNT_CREATE_PROOF_RESP: u8 = 27;
48pub const TAG_GET_NON_PRODUCT_ACCOUNTS_REQ: u8 = 28;
49pub const TAG_GET_NON_PRODUCT_ACCOUNTS_RESP: u8 = 29;
50pub const TAG_CREATE_TRANSACTION_REQ: u8 = 30;
51pub const TAG_CREATE_TRANSACTION_RESP: u8 = 31;
52pub const TAG_CREATE_TX_NON_PRODUCT_REQ: u8 = 32;
53pub const TAG_CREATE_TX_NON_PRODUCT_RESP: u8 = 33;
54pub const TAG_SIGN_RAW_REQ: u8 = 34;
55pub const TAG_SIGN_RAW_RESP: u8 = 35;
56pub const TAG_SIGN_PAYLOAD_REQ: u8 = 36;
57pub const TAG_SIGN_PAYLOAD_RESP: u8 = 37;
58pub const TAG_CHAT_CREATE_ROOM_REQ: u8 = 38;
59pub const TAG_CHAT_CREATE_ROOM_RESP: u8 = 39;
60pub const TAG_CHAT_REGISTER_BOT_REQ: u8 = 40;
61pub const TAG_CHAT_REGISTER_BOT_RESP: u8 = 41;
62pub const TAG_CHAT_LIST_START: u8 = 42;
63pub const TAG_CHAT_LIST_STOP: u8 = 43;
64pub const TAG_CHAT_LIST_INTERRUPT: u8 = 44;
65pub const TAG_CHAT_LIST_RECEIVE: u8 = 45;
66pub const TAG_CHAT_POST_MSG_REQ: u8 = 46;
67pub const TAG_CHAT_POST_MSG_RESP: u8 = 47;
68pub const TAG_CHAT_ACTION_START: u8 = 48;
69pub const TAG_CHAT_ACTION_STOP: u8 = 49;
70pub const TAG_CHAT_ACTION_INTERRUPT: u8 = 50;
71pub const TAG_CHAT_ACTION_RECEIVE: u8 = 51;
72pub const TAG_CHAT_CUSTOM_MSG_START: u8 = 52;
73pub const TAG_CHAT_CUSTOM_MSG_STOP: u8 = 53;
74pub const TAG_CHAT_CUSTOM_MSG_INTERRUPT: u8 = 54;
75pub const TAG_CHAT_CUSTOM_MSG_RECEIVE: u8 = 55;
76pub const TAG_STATEMENT_STORE_START: u8 = 56;
77pub const TAG_STATEMENT_STORE_STOP: u8 = 57;
78pub const TAG_STATEMENT_STORE_INTERRUPT: u8 = 58;
79pub const TAG_STATEMENT_STORE_RECEIVE: u8 = 59;
80pub const TAG_STATEMENT_PROOF_REQ: u8 = 60;
81pub const TAG_STATEMENT_PROOF_RESP: u8 = 61;
82pub const TAG_STATEMENT_SUBMIT_REQ: u8 = 62;
83pub const TAG_STATEMENT_SUBMIT_RESP: u8 = 63;
84pub const TAG_PREIMAGE_LOOKUP_START: u8 = 64;
85pub const TAG_PREIMAGE_LOOKUP_STOP: u8 = 65;
86pub const TAG_PREIMAGE_LOOKUP_INTERRUPT: u8 = 66;
87pub const TAG_PREIMAGE_LOOKUP_RECEIVE: u8 = 67;
88pub const TAG_PREIMAGE_SUBMIT_REQ: u8 = 68;
89pub const TAG_PREIMAGE_SUBMIT_RESP: u8 = 69;
90pub const TAG_JSONRPC_SEND_REQ: u8 = 70;
91pub const TAG_JSONRPC_SEND_RESP: u8 = 71;
92pub const TAG_JSONRPC_SUB_START: u8 = 72;
93pub const TAG_JSONRPC_SUB_STOP: u8 = 73;
94pub const TAG_JSONRPC_SUB_INTERRUPT: u8 = 74;
95pub const TAG_JSONRPC_SUB_RECEIVE: u8 = 75;
96pub const TAG_CHAIN_HEAD_FOLLOW_START: u8 = 76;
98pub const TAG_CHAIN_HEAD_FOLLOW_STOP: u8 = 77;
99pub const TAG_CHAIN_HEAD_FOLLOW_INTERRUPT: u8 = 78;
100pub const TAG_CHAIN_HEAD_FOLLOW_RECEIVE: u8 = 79;
101pub const TAG_CHAIN_HEAD_HEADER_REQ: u8 = 80;
103pub const TAG_CHAIN_HEAD_HEADER_RESP: u8 = 81;
104pub const TAG_CHAIN_HEAD_BODY_REQ: u8 = 82;
106pub const TAG_CHAIN_HEAD_BODY_RESP: u8 = 83;
107pub const TAG_CHAIN_HEAD_STORAGE_REQ: u8 = 84;
109pub const TAG_CHAIN_HEAD_STORAGE_RESP: u8 = 85;
110pub const TAG_CHAIN_HEAD_CALL_REQ: u8 = 86;
112pub const TAG_CHAIN_HEAD_CALL_RESP: u8 = 87;
113pub const TAG_CHAIN_HEAD_UNPIN_REQ: u8 = 88;
115pub const TAG_CHAIN_HEAD_UNPIN_RESP: u8 = 89;
116pub const TAG_CHAIN_HEAD_CONTINUE_REQ: u8 = 90;
118pub const TAG_CHAIN_HEAD_CONTINUE_RESP: u8 = 91;
119pub const TAG_CHAIN_HEAD_STOP_OP_REQ: u8 = 92;
121pub const TAG_CHAIN_HEAD_STOP_OP_RESP: u8 = 93;
122pub const TAG_CHAIN_SPEC_GENESIS_REQ: u8 = 94;
124pub const TAG_CHAIN_SPEC_GENESIS_RESP: u8 = 95;
125pub const TAG_CHAIN_SPEC_NAME_REQ: u8 = 96;
127pub const TAG_CHAIN_SPEC_NAME_RESP: u8 = 97;
128pub const TAG_CHAIN_SPEC_PROPS_REQ: u8 = 98;
130pub const TAG_CHAIN_SPEC_PROPS_RESP: u8 = 99;
131pub const TAG_CHAIN_TX_BROADCAST_REQ: u8 = 100;
133pub const TAG_CHAIN_TX_BROADCAST_RESP: u8 = 101;
134pub const TAG_CHAIN_TX_STOP_REQ: u8 = 102;
136pub const TAG_CHAIN_TX_STOP_RESP: u8 = 103;
137
138pub const PROTOCOL_VERSION: u8 = 1;
140
141pub const PROTOCOL_DISCRIMINATOR: u8 = 0x01;
152
153pub fn is_host_sdk_message(data: &[u8]) -> bool {
159 data.first() == Some(&PROTOCOL_DISCRIMINATOR)
160}
161
162#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
168pub struct Account {
169 pub public_key: Vec<u8>,
171 pub name: Option<String>,
173}
174
175#[derive(Debug)]
177pub enum HostRequest {
178 Handshake {
179 version: u8,
180 },
181 GetNonProductAccounts,
182 FeatureSupported {
183 feature_data: Vec<u8>,
184 },
185 LocalStorageRead {
186 key: String,
187 },
188 LocalStorageWrite {
189 key: String,
190 value: Vec<u8>,
191 },
192 LocalStorageClear {
193 key: String,
194 },
195 SignPayload {
196 public_key: Vec<u8>,
197 payload: Vec<u8>,
198 },
199 SignRaw {
200 public_key: Vec<u8>,
201 data: Vec<u8>,
202 },
203 CreateTransaction {
204 payload: Vec<u8>,
205 },
206 NavigateTo {
207 url: String,
208 },
209 PushNotification {
210 text: String,
211 deeplink: Option<String>,
212 },
213 AccountConnectionStatusStart,
214 JsonRpcSend {
215 data: Vec<u8>,
216 },
217 JsonRpcSubscribeStart {
218 data: Vec<u8>,
219 },
220 ChainHeadFollowStart {
222 genesis_hash: Vec<u8>,
223 with_runtime: bool,
224 },
225 ChainHeadRequest {
228 tag: u8,
229 genesis_hash: Vec<u8>,
230 follow_sub_id: String,
231 data: serde_json::Value,
232 },
233 ChainSpecRequest {
235 tag: u8,
236 genesis_hash: Vec<u8>,
237 },
238 ChainTxBroadcast {
240 genesis_hash: Vec<u8>,
241 transaction: Vec<u8>,
242 },
243 ChainTxStop {
245 genesis_hash: Vec<u8>,
246 operation_id: String,
247 },
248 Unimplemented {
250 tag: u8,
251 },
252 Unknown {
254 tag: u8,
255 },
256}
257
258#[derive(Debug)]
260pub enum HostResponse {
261 HandshakeOk,
262 AccountList(Vec<Account>),
263 Error(String),
264}
265
266fn bytes_to_hex(bytes: &[u8]) -> String {
272 let mut s = String::with_capacity(2 + bytes.len() * 2);
273 s.push_str("0x");
274 for b in bytes {
275 s.push_str(&format!("{b:02x}"));
276 }
277 s
278}
279
280fn begin_message(buf: &mut Vec<u8>, request_id: &str) {
285 buf.push(PROTOCOL_DISCRIMINATOR);
286 encode_string(buf, request_id);
287}
288
289pub fn decode_message(data: &[u8]) -> Result<(String, u8, HostRequest), DecodeErr> {
294 let mut r = Reader::new(data);
295
296 let disc = r.read_u8()?;
298 if disc != PROTOCOL_DISCRIMINATOR {
299 return Err(DecodeErr::UnknownProtocol);
300 }
301
302 let request_id = r.read_string()?;
304
305 let tag = r.read_u8()?;
307
308 let req = match tag {
309 TAG_HANDSHAKE_REQ => {
310 let _version_tag = r.read_u8()?; let version = r.read_u8()?;
313 HostRequest::Handshake { version }
314 }
315 TAG_GET_NON_PRODUCT_ACCOUNTS_REQ => {
316 let _version_tag = r.read_u8()?;
318 HostRequest::GetNonProductAccounts
320 }
321 TAG_FEATURE_SUPPORTED_REQ => {
322 let _version_tag = r.read_u8()?;
323 let rest = r.remaining().to_vec();
324 r.skip_rest();
325 HostRequest::FeatureSupported { feature_data: rest }
326 }
327 TAG_LOCAL_STORAGE_READ_REQ => {
328 let _version_tag = r.read_u8()?;
329 let key = r.read_string()?;
330 HostRequest::LocalStorageRead { key }
331 }
332 TAG_LOCAL_STORAGE_WRITE_REQ => {
333 let _version_tag = r.read_u8()?;
334 let key = r.read_string()?;
335 let value = r.read_var_bytes()?;
336 HostRequest::LocalStorageWrite { key, value }
337 }
338 TAG_LOCAL_STORAGE_CLEAR_REQ => {
339 let _version_tag = r.read_u8()?;
340 let key = r.read_string()?;
341 HostRequest::LocalStorageClear { key }
342 }
343 TAG_SIGN_PAYLOAD_REQ => {
344 let _version_tag = r.read_u8()?;
345 let public_key = r.read_var_bytes()?;
346 let payload = r.remaining().to_vec();
347 r.skip_rest();
348 HostRequest::SignPayload {
349 public_key,
350 payload,
351 }
352 }
353 TAG_SIGN_RAW_REQ => {
354 let _version_tag = r.read_u8()?;
355 let public_key = r.read_var_bytes()?;
356 let data = r.remaining().to_vec();
357 r.skip_rest();
358 HostRequest::SignRaw { public_key, data }
359 }
360 TAG_CREATE_TRANSACTION_REQ => {
361 let _version_tag = r.read_u8()?;
362 let rest = r.remaining().to_vec();
363 r.skip_rest();
364 HostRequest::CreateTransaction { payload: rest }
365 }
366 TAG_NAVIGATE_TO_REQ => {
367 let _version_tag = r.read_u8()?;
368 let url = r.read_string()?;
369 HostRequest::NavigateTo { url }
370 }
371 TAG_ACCOUNT_STATUS_START => {
372 let _version_tag = r.read_u8()?;
373 HostRequest::AccountConnectionStatusStart
374 }
375 TAG_JSONRPC_SEND_REQ => {
376 let _version_tag = r.read_u8()?;
377 let rest = r.remaining().to_vec();
378 r.skip_rest();
379 HostRequest::JsonRpcSend { data: rest }
380 }
381 TAG_JSONRPC_SUB_START => {
382 let _version_tag = r.read_u8()?;
383 let rest = r.remaining().to_vec();
384 r.skip_rest();
385 HostRequest::JsonRpcSubscribeStart { data: rest }
386 }
387 TAG_CHAIN_HEAD_FOLLOW_START => {
388 let _version_tag = r.read_u8()?;
389 let genesis_hash = r.read_var_bytes()?;
390 let with_runtime = r.read_u8()? != 0;
391 HostRequest::ChainHeadFollowStart {
392 genesis_hash,
393 with_runtime,
394 }
395 }
396 TAG_CHAIN_HEAD_HEADER_REQ => {
397 let _version_tag = r.read_u8()?;
398 let genesis_hash = r.read_var_bytes()?;
399 let follow_sub_id = r.read_string()?;
400 let hash = r.read_var_bytes()?;
401 let hash_hex = bytes_to_hex(&hash);
402 HostRequest::ChainHeadRequest {
403 tag,
404 genesis_hash,
405 follow_sub_id,
406 data: serde_json::json!([hash_hex]),
407 }
408 }
409 TAG_CHAIN_HEAD_BODY_REQ => {
410 let _version_tag = r.read_u8()?;
411 let genesis_hash = r.read_var_bytes()?;
412 let follow_sub_id = r.read_string()?;
413 let hash = r.read_var_bytes()?;
414 let hash_hex = bytes_to_hex(&hash);
415 HostRequest::ChainHeadRequest {
416 tag,
417 genesis_hash,
418 follow_sub_id,
419 data: serde_json::json!([hash_hex]),
420 }
421 }
422 TAG_CHAIN_HEAD_STORAGE_REQ => {
423 let _version_tag = r.read_u8()?;
424 let genesis_hash = r.read_var_bytes()?;
425 let follow_sub_id = r.read_string()?;
426 let hash = r.read_var_bytes()?;
427 let hash_hex = bytes_to_hex(&hash);
428 let item_count = r.read_compact_u32()?;
430 let mut items = Vec::new();
431 for _ in 0..item_count {
432 let key = r.read_var_bytes()?;
433 let storage_type = r.read_u8()?; let type_str = match storage_type {
435 0 => "value",
436 1 => "hash",
437 2 => "closestDescendantMerkleValue",
438 3 => "descendantsValues",
439 4 => "descendantsHashes",
440 _ => "value",
441 };
442 items.push(serde_json::json!({
443 "key": bytes_to_hex(&key),
444 "type": type_str,
445 }));
446 }
447 let child_trie = r.read_option(|r| r.read_var_bytes())?;
449 let child_trie_hex = child_trie.map(|b| bytes_to_hex(&b));
450 HostRequest::ChainHeadRequest {
451 tag,
452 genesis_hash,
453 follow_sub_id,
454 data: serde_json::json!([hash_hex, items, child_trie_hex]),
455 }
456 }
457 TAG_CHAIN_HEAD_CALL_REQ => {
458 let _version_tag = r.read_u8()?;
459 let genesis_hash = r.read_var_bytes()?;
460 let follow_sub_id = r.read_string()?;
461 let hash = r.read_var_bytes()?;
462 let function = r.read_string()?;
463 let call_params = r.read_var_bytes()?;
464 HostRequest::ChainHeadRequest {
465 tag,
466 genesis_hash,
467 follow_sub_id,
468 data: serde_json::json!([
469 bytes_to_hex(&hash),
470 function,
471 bytes_to_hex(&call_params)
472 ]),
473 }
474 }
475 TAG_CHAIN_HEAD_UNPIN_REQ => {
476 let _version_tag = r.read_u8()?;
477 let genesis_hash = r.read_var_bytes()?;
478 let follow_sub_id = r.read_string()?;
479 let count = r.read_compact_u32()?;
481 let mut hashes = Vec::new();
482 for _ in 0..count {
483 let h = r.read_var_bytes()?;
484 hashes.push(serde_json::Value::String(bytes_to_hex(&h)));
485 }
486 HostRequest::ChainHeadRequest {
487 tag,
488 genesis_hash,
489 follow_sub_id,
490 data: serde_json::json!([hashes]),
491 }
492 }
493 TAG_CHAIN_HEAD_CONTINUE_REQ | TAG_CHAIN_HEAD_STOP_OP_REQ => {
494 let _version_tag = r.read_u8()?;
495 let genesis_hash = r.read_var_bytes()?;
496 let follow_sub_id = r.read_string()?;
497 let operation_id = r.read_string()?;
498 HostRequest::ChainHeadRequest {
499 tag,
500 genesis_hash,
501 follow_sub_id,
502 data: serde_json::json!([operation_id]),
503 }
504 }
505 TAG_CHAIN_SPEC_GENESIS_REQ | TAG_CHAIN_SPEC_NAME_REQ | TAG_CHAIN_SPEC_PROPS_REQ => {
506 let _version_tag = r.read_u8()?;
507 let genesis_hash = r.read_var_bytes()?;
508 HostRequest::ChainSpecRequest { tag, genesis_hash }
509 }
510 TAG_CHAIN_TX_BROADCAST_REQ => {
511 let _version_tag = r.read_u8()?;
512 let genesis_hash = r.read_var_bytes()?;
513 let transaction = r.read_var_bytes()?;
514 HostRequest::ChainTxBroadcast {
515 genesis_hash,
516 transaction,
517 }
518 }
519 TAG_CHAIN_TX_STOP_REQ => {
520 let _version_tag = r.read_u8()?;
521 let genesis_hash = r.read_var_bytes()?;
522 let operation_id = r.read_string()?;
523 HostRequest::ChainTxStop {
524 genesis_hash,
525 operation_id,
526 }
527 }
528 TAG_PUSH_NOTIFICATION_REQ => {
529 let _version_tag = r.read_u8()?;
530 let text = r.read_string()?;
531 let deeplink = r.read_option(|r| r.read_string())?;
532 HostRequest::PushNotification { text, deeplink }
533 }
534 TAG_DEVICE_PERMISSION_REQ
536 | TAG_REMOTE_PERMISSION_REQ
537 | TAG_ACCOUNT_GET_REQ
538 | TAG_ACCOUNT_GET_ALIAS_REQ
539 | TAG_ACCOUNT_CREATE_PROOF_REQ
540 | TAG_CREATE_TX_NON_PRODUCT_REQ
541 | TAG_CHAT_CREATE_ROOM_REQ
542 | TAG_CHAT_REGISTER_BOT_REQ
543 | TAG_CHAT_POST_MSG_REQ
544 | TAG_STATEMENT_PROOF_REQ
545 | TAG_STATEMENT_SUBMIT_REQ
546 | TAG_PREIMAGE_SUBMIT_REQ => HostRequest::Unimplemented { tag },
547 TAG_ACCOUNT_STATUS_STOP
549 | TAG_ACCOUNT_STATUS_INTERRUPT
550 | TAG_CHAT_LIST_STOP
551 | TAG_CHAT_LIST_INTERRUPT
552 | TAG_CHAT_ACTION_STOP
553 | TAG_CHAT_ACTION_INTERRUPT
554 | TAG_CHAT_CUSTOM_MSG_STOP
555 | TAG_CHAT_CUSTOM_MSG_INTERRUPT
556 | TAG_STATEMENT_STORE_STOP
557 | TAG_STATEMENT_STORE_INTERRUPT
558 | TAG_PREIMAGE_LOOKUP_STOP
559 | TAG_PREIMAGE_LOOKUP_INTERRUPT
560 | TAG_JSONRPC_SUB_STOP
561 | TAG_JSONRPC_SUB_INTERRUPT
562 | TAG_CHAIN_HEAD_FOLLOW_STOP
563 | TAG_CHAIN_HEAD_FOLLOW_INTERRUPT => HostRequest::Unimplemented { tag },
564 _ => HostRequest::Unknown { tag },
565 };
566
567 Ok((request_id, tag, req))
568}
569
570pub fn encode_response(request_id: &str, request_tag: u8, response: &HostResponse) -> Vec<u8> {
572 let mut buf = Vec::with_capacity(128);
573 begin_message(&mut buf, request_id);
574
575 match response {
576 HostResponse::HandshakeOk => {
577 encode_tag(&mut buf, TAG_HANDSHAKE_RESP);
579 encode_tag(&mut buf, 0);
581 encode_result_ok_void(&mut buf);
583 }
584
585 HostResponse::AccountList(accounts) => {
586 encode_tag(&mut buf, TAG_GET_NON_PRODUCT_ACCOUNTS_RESP);
588 encode_tag(&mut buf, 0);
590 encode_result_ok(&mut buf);
592 encode_vector_len(&mut buf, accounts.len() as u32);
594 for account in accounts {
595 encode_var_bytes(&mut buf, &account.public_key);
598 match &account.name {
600 None => encode_option_none(&mut buf),
601 Some(name) => {
602 encode_option_some(&mut buf);
603 encode_string(&mut buf, name);
604 }
605 }
606 }
607 }
608
609 HostResponse::Error(_reason) => {
610 let resp_tag = response_tag_for(request_tag);
611 encode_tag(&mut buf, resp_tag);
612 encode_tag(&mut buf, 0); encode_result_err(&mut buf);
614 encode_tag(&mut buf, 0);
619 }
620 }
621
622 buf
623}
624
625fn response_tag_for(request_tag: u8) -> u8 {
629 assert!(
630 !matches!(
631 request_tag,
632 TAG_ACCOUNT_STATUS_START
633 | TAG_CHAT_LIST_START
634 | TAG_CHAT_ACTION_START
635 | TAG_CHAT_CUSTOM_MSG_START
636 | TAG_STATEMENT_STORE_START
637 | TAG_PREIMAGE_LOOKUP_START
638 | TAG_JSONRPC_SUB_START
639 | TAG_CHAIN_HEAD_FOLLOW_START
640 ),
641 "response_tag_for called with subscription start tag {request_tag}"
642 );
643 request_tag + 1
644}
645
646pub fn encode_feature_response(request_id: &str, supported: bool) -> Vec<u8> {
648 let mut buf = Vec::with_capacity(32);
649 begin_message(&mut buf, request_id);
650 encode_tag(&mut buf, TAG_FEATURE_SUPPORTED_RESP);
651 encode_tag(&mut buf, 0); encode_result_ok(&mut buf);
653 buf.push(if supported { 1 } else { 0 }); buf
655}
656
657pub fn encode_account_status(request_id: &str, connected: bool) -> Vec<u8> {
659 let mut buf = Vec::with_capacity(32);
660 begin_message(&mut buf, request_id);
661 encode_tag(&mut buf, TAG_ACCOUNT_STATUS_RECEIVE);
662 encode_tag(&mut buf, 0); encode_tag(&mut buf, if connected { 1 } else { 0 });
665 buf
666}
667
668pub fn encode_storage_read_response(request_id: &str, value: Option<&[u8]>) -> Vec<u8> {
670 let mut buf = Vec::with_capacity(64);
671 begin_message(&mut buf, request_id);
672 encode_tag(&mut buf, TAG_LOCAL_STORAGE_READ_RESP);
673 encode_tag(&mut buf, 0); encode_result_ok(&mut buf);
675 match value {
676 None => encode_option_none(&mut buf),
677 Some(v) => {
678 encode_option_some(&mut buf);
679 encode_var_bytes(&mut buf, v);
680 }
681 }
682 buf
683}
684
685pub fn encode_storage_write_response(request_id: &str, is_clear: bool) -> Vec<u8> {
687 let mut buf = Vec::with_capacity(32);
688 begin_message(&mut buf, request_id);
689 let tag = if is_clear {
690 TAG_LOCAL_STORAGE_CLEAR_RESP
691 } else {
692 TAG_LOCAL_STORAGE_WRITE_RESP
693 };
694 encode_tag(&mut buf, tag);
695 encode_tag(&mut buf, 0); encode_result_ok_void(&mut buf);
697 buf
698}
699
700pub fn encode_navigate_response(request_id: &str) -> Vec<u8> {
702 let mut buf = Vec::with_capacity(32);
703 begin_message(&mut buf, request_id);
704 encode_tag(&mut buf, TAG_NAVIGATE_TO_RESP);
705 encode_tag(&mut buf, 0); encode_result_ok_void(&mut buf);
707 buf
708}
709
710pub fn encode_push_notification_response(request_id: &str) -> Vec<u8> {
712 let mut buf = Vec::with_capacity(32);
713 begin_message(&mut buf, request_id);
714 encode_tag(&mut buf, TAG_PUSH_NOTIFICATION_RESP);
715 encode_tag(&mut buf, 0); encode_result_ok_void(&mut buf);
717 buf
718}
719
720pub fn encode_sign_response(request_id: &str, is_raw: bool, signature: &[u8]) -> Vec<u8> {
723 let mut buf = Vec::with_capacity(128);
724 begin_message(&mut buf, request_id);
725 encode_tag(
726 &mut buf,
727 if is_raw {
728 TAG_SIGN_RAW_RESP
729 } else {
730 TAG_SIGN_PAYLOAD_RESP
731 },
732 );
733 encode_tag(&mut buf, 0); encode_result_ok(&mut buf);
735 encode_compact_u32(&mut buf, 0); encode_var_bytes(&mut buf, signature);
737 buf
738}
739
740pub fn encode_jsonrpc_send_response(request_id: &str, json_rpc_result: &str) -> Vec<u8> {
745 let mut buf = Vec::with_capacity(64 + json_rpc_result.len());
746 begin_message(&mut buf, request_id);
747 encode_tag(&mut buf, TAG_JSONRPC_SEND_RESP);
748 encode_tag(&mut buf, 0); encode_result_ok(&mut buf);
750 encode_string(&mut buf, json_rpc_result);
751 buf
752}
753
754pub fn encode_jsonrpc_send_error(request_id: &str) -> Vec<u8> {
756 let mut buf = Vec::with_capacity(32);
757 begin_message(&mut buf, request_id);
758 encode_tag(&mut buf, TAG_JSONRPC_SEND_RESP);
759 encode_tag(&mut buf, 0); encode_result_err(&mut buf);
761 encode_tag(&mut buf, 0); buf
763}
764
765pub fn encode_jsonrpc_sub_receive(request_id: &str, json_rpc_msg: &str) -> Vec<u8> {
771 let mut buf = Vec::with_capacity(64 + json_rpc_msg.len());
772 begin_message(&mut buf, request_id);
773 encode_tag(&mut buf, TAG_JSONRPC_SUB_RECEIVE);
774 encode_tag(&mut buf, 0); encode_string(&mut buf, json_rpc_msg);
776 buf
777}
778
779pub fn encode_sign_error(request_id: &str, is_raw: bool) -> Vec<u8> {
781 let mut buf = Vec::with_capacity(32);
782 begin_message(&mut buf, request_id);
783 encode_tag(
784 &mut buf,
785 if is_raw {
786 TAG_SIGN_RAW_RESP
787 } else {
788 TAG_SIGN_PAYLOAD_RESP
789 },
790 );
791 encode_tag(&mut buf, 0); encode_result_err(&mut buf);
793 encode_tag(&mut buf, 0); buf
795}
796
797#[cfg(test)]
798mod tests {
799 use super::*;
800
801 #[test]
802 fn decode_handshake_request() {
803 let mut msg = Vec::new();
805 msg.push(PROTOCOL_DISCRIMINATOR);
806 encode_string(&mut msg, "test");
807 msg.push(TAG_HANDSHAKE_REQ); msg.push(0); msg.push(PROTOCOL_VERSION); let (id, tag, req) = decode_message(&msg).unwrap();
812 assert_eq!(id, "test");
813 assert_eq!(tag, TAG_HANDSHAKE_REQ);
814 match req {
815 HostRequest::Handshake { version } => assert_eq!(version, 1),
816 _ => panic!("expected Handshake"),
817 }
818 }
819
820 #[test]
821 fn encode_handshake_response() {
822 let resp = encode_response("test", TAG_HANDSHAKE_REQ, &HostResponse::HandshakeOk);
823
824 let mut r = Reader::new(&resp);
826 assert_eq!(r.read_u8().unwrap(), PROTOCOL_DISCRIMINATOR);
827 let id = r.read_string().unwrap();
828 assert_eq!(id, "test");
829 let tag = r.read_u8().unwrap();
830 assert_eq!(tag, TAG_HANDSHAKE_RESP);
831 let v1_tag = r.read_u8().unwrap();
832 assert_eq!(v1_tag, 0);
833 let result_ok = r.read_u8().unwrap();
834 assert_eq!(result_ok, 0x00); assert_eq!(r.pos, resp.len()); }
837
838 #[test]
839 fn decode_get_non_product_accounts() {
840 let mut msg = Vec::new();
841 msg.push(PROTOCOL_DISCRIMINATOR);
842 encode_string(&mut msg, "req-42");
843 msg.push(TAG_GET_NON_PRODUCT_ACCOUNTS_REQ);
844 msg.push(0); let (id, tag, req) = decode_message(&msg).unwrap();
847 assert_eq!(id, "req-42");
848 assert_eq!(tag, TAG_GET_NON_PRODUCT_ACCOUNTS_REQ);
849 assert!(matches!(req, HostRequest::GetNonProductAccounts));
850 }
851
852 #[test]
853 fn encode_account_list_response() {
854 let accounts = vec![
855 Account {
856 public_key: vec![0xd4; 32],
857 name: Some("Alice".into()),
858 },
859 Account {
860 public_key: vec![0x8e; 32],
861 name: None,
862 },
863 ];
864 let resp = encode_response(
865 "req-42",
866 TAG_GET_NON_PRODUCT_ACCOUNTS_REQ,
867 &HostResponse::AccountList(accounts),
868 );
869
870 let mut r = Reader::new(&resp);
872 assert_eq!(r.read_u8().unwrap(), PROTOCOL_DISCRIMINATOR);
873 let id = r.read_string().unwrap();
874 assert_eq!(id, "req-42");
875 let tag = r.read_u8().unwrap();
876 assert_eq!(tag, TAG_GET_NON_PRODUCT_ACCOUNTS_RESP);
877 let v1 = r.read_u8().unwrap();
878 assert_eq!(v1, 0); let result = r.read_u8().unwrap();
880 assert_eq!(result, 0x00); let count = r.read_compact_u32().unwrap();
882 assert_eq!(count, 2);
883
884 let pk1 = r.read_var_bytes().unwrap();
886 assert_eq!(pk1.len(), 32);
887 assert_eq!(pk1[0], 0xd4);
888 let name1 = r.read_option(|r| r.read_string()).unwrap();
889 assert_eq!(name1.as_deref(), Some("Alice"));
890
891 let pk2 = r.read_var_bytes().unwrap();
893 assert_eq!(pk2.len(), 32);
894 assert_eq!(pk2[0], 0x8e);
895 let name2 = r.read_option(|r| r.read_string()).unwrap();
896 assert!(name2.is_none());
897
898 assert_eq!(r.pos, resp.len());
899 }
900
901 #[test]
902 fn handshake_round_trip() {
903 let mut req_msg = Vec::new();
905 req_msg.push(PROTOCOL_DISCRIMINATOR);
906 encode_string(&mut req_msg, "hsk-1");
907 req_msg.push(TAG_HANDSHAKE_REQ);
908 req_msg.push(0); req_msg.push(PROTOCOL_VERSION);
910
911 let (id, tag, req) = decode_message(&req_msg).unwrap();
912 assert!(matches!(req, HostRequest::Handshake { version: 1 }));
913
914 let resp_bytes = encode_response(&id, tag, &HostResponse::HandshakeOk);
915
916 let mut r = Reader::new(&resp_bytes);
918 assert_eq!(r.read_u8().unwrap(), PROTOCOL_DISCRIMINATOR);
919 assert_eq!(r.read_string().unwrap(), "hsk-1");
920 assert_eq!(r.read_u8().unwrap(), TAG_HANDSHAKE_RESP);
921 assert_eq!(r.read_u8().unwrap(), 0); assert_eq!(r.read_u8().unwrap(), 0); }
924
925 #[test]
933 fn golden_handshake_request() {
934 let expected: &[u8] = &[
936 0x01, 0x08, b't', b'1', 0x00, 0x00, 0x01, ];
942 let mut built = Vec::new();
943 built.push(PROTOCOL_DISCRIMINATOR);
944 encode_string(&mut built, "t1");
945 built.push(TAG_HANDSHAKE_REQ);
946 built.push(0);
947 built.push(PROTOCOL_VERSION);
948 assert_eq!(built, expected);
949 }
950
951 #[test]
952 fn golden_handshake_response_ok() {
953 let resp = encode_response("t1", TAG_HANDSHAKE_REQ, &HostResponse::HandshakeOk);
954 let expected: &[u8] = &[
955 0x01, 0x08, b't', b'1', 0x01, 0x00, 0x00, ];
961 assert_eq!(resp, expected);
962 }
963
964 #[test]
965 fn golden_get_accounts_request() {
966 let expected: &[u8] = &[
967 0x01, 0x08, b'a', b'1', 28, 0x00, ];
972 let mut built = Vec::new();
973 built.push(PROTOCOL_DISCRIMINATOR);
974 encode_string(&mut built, "a1");
975 built.push(TAG_GET_NON_PRODUCT_ACCOUNTS_REQ);
976 built.push(0);
977 assert_eq!(built, expected);
978 }
979
980 #[test]
981 fn golden_get_accounts_response_empty() {
982 let resp = encode_response(
983 "a1",
984 TAG_GET_NON_PRODUCT_ACCOUNTS_REQ,
985 &HostResponse::AccountList(vec![]),
986 );
987 let expected: &[u8] = &[
988 0x01, 0x08, b'a', b'1', 29, 0x00, 0x00, 0x00, ];
995 assert_eq!(resp, expected);
996 }
997
998 #[test]
999 fn golden_storage_write_response() {
1000 let resp = encode_storage_write_response("s1", false);
1001 let expected: &[u8] = &[
1002 0x01, 0x08, b's', b'1', 15, 0x00, 0x00, ];
1008 assert_eq!(resp, expected);
1009 }
1010
1011 #[test]
1012 fn golden_storage_clear_response() {
1013 let resp = encode_storage_write_response("s1", true);
1014 let expected: &[u8] = &[
1015 0x01, 0x08, b's', b'1', 17, 0x00, 0x00, ];
1021 assert_eq!(resp, expected);
1022 }
1023
1024 #[test]
1025 fn golden_feature_supported_response() {
1026 let resp = encode_feature_response("f1", false);
1027 let expected: &[u8] = &[
1028 0x01, 0x08, b'f', b'1', 3, 0x00, 0x00, 0x00, ];
1035 assert_eq!(resp, expected);
1036 }
1037
1038 #[test]
1039 fn golden_account_status_receive() {
1040 let resp = encode_account_status("c1", true);
1041 let expected: &[u8] = &[
1042 0x01, 0x08, b'c', b'1', 21, 0x00, 0x01, ];
1048 assert_eq!(resp, expected);
1049 }
1050
1051 #[test]
1052 fn golden_sign_payload_response_ok() {
1053 let sig = [0xAB; 64];
1054 let resp = encode_sign_response("s1", false, &sig);
1055 let mut r = Reader::new(&resp);
1056 assert_eq!(r.read_u8().unwrap(), PROTOCOL_DISCRIMINATOR);
1057 assert_eq!(r.read_string().unwrap(), "s1");
1058 assert_eq!(r.read_u8().unwrap(), TAG_SIGN_PAYLOAD_RESP);
1059 assert_eq!(r.read_u8().unwrap(), 0); assert_eq!(r.read_u8().unwrap(), 0); assert_eq!(r.read_compact_u32().unwrap(), 0); let sig_bytes = r.read_var_bytes().unwrap();
1063 assert_eq!(sig_bytes, vec![0xAB; 64]);
1064 assert_eq!(r.pos, resp.len());
1065 }
1066
1067 #[test]
1068 fn golden_sign_raw_response_ok() {
1069 let sig = [0xCD; 64];
1070 let resp = encode_sign_response("s2", true, &sig);
1071 let mut r = Reader::new(&resp);
1072 assert_eq!(r.read_u8().unwrap(), PROTOCOL_DISCRIMINATOR);
1073 assert_eq!(r.read_string().unwrap(), "s2");
1074 assert_eq!(r.read_u8().unwrap(), TAG_SIGN_RAW_RESP);
1075 assert_eq!(r.read_u8().unwrap(), 0); assert_eq!(r.read_u8().unwrap(), 0); assert_eq!(r.read_compact_u32().unwrap(), 0); let sig_bytes = r.read_var_bytes().unwrap();
1079 assert_eq!(sig_bytes, vec![0xCD; 64]);
1080 }
1081
1082 #[test]
1083 fn golden_sign_error_response() {
1084 let resp = encode_sign_error("s3", false);
1085 let expected: &[u8] = &[
1086 0x01, 0x08, b's', b'3', 37, 0x00, 0x01, 0x00, ];
1093 assert_eq!(resp, expected);
1094 }
1095
1096 #[test]
1097 fn decode_sign_payload_request() {
1098 let mut msg = Vec::new();
1099 msg.push(PROTOCOL_DISCRIMINATOR);
1100 encode_string(&mut msg, "sign-1");
1101 msg.push(TAG_SIGN_PAYLOAD_REQ);
1102 msg.push(0); encode_var_bytes(&mut msg, &[0xAA; 32]); msg.extend_from_slice(b"extrinsic-payload"); let (id, tag, req) = decode_message(&msg).unwrap();
1106 assert_eq!(id, "sign-1");
1107 assert_eq!(tag, TAG_SIGN_PAYLOAD_REQ);
1108 match req {
1109 HostRequest::SignPayload {
1110 public_key,
1111 payload,
1112 } => {
1113 assert_eq!(public_key, vec![0xAA; 32]);
1114 assert_eq!(payload, b"extrinsic-payload");
1115 }
1116 _ => panic!("expected SignPayload"),
1117 }
1118 }
1119
1120 #[test]
1121 fn decode_sign_raw_request() {
1122 let mut msg = Vec::new();
1123 msg.push(PROTOCOL_DISCRIMINATOR);
1124 encode_string(&mut msg, "sign-2");
1125 msg.push(TAG_SIGN_RAW_REQ);
1126 msg.push(0); encode_var_bytes(&mut msg, &[0xBB; 32]); msg.extend_from_slice(b"raw-data"); let (id, tag, req) = decode_message(&msg).unwrap();
1130 assert_eq!(id, "sign-2");
1131 assert_eq!(tag, TAG_SIGN_RAW_REQ);
1132 match req {
1133 HostRequest::SignRaw { public_key, data } => {
1134 assert_eq!(public_key, vec![0xBB; 32]);
1135 assert_eq!(data, b"raw-data");
1136 }
1137 _ => panic!("expected SignRaw"),
1138 }
1139 }
1140
1141 #[test]
1144 fn decode_push_notification_request_with_deeplink() {
1145 let mut msg = Vec::new();
1146 msg.push(PROTOCOL_DISCRIMINATOR);
1147 encode_string(&mut msg, "pn-1");
1148 msg.push(TAG_PUSH_NOTIFICATION_REQ);
1149 msg.push(0); encode_string(&mut msg, "Transfer complete");
1151 msg.push(0x01); encode_string(&mut msg, "https://app.example/tx/123");
1153
1154 let (id, tag, req) = decode_message(&msg).unwrap();
1155 assert_eq!(id, "pn-1");
1156 assert_eq!(tag, TAG_PUSH_NOTIFICATION_REQ);
1157 match req {
1158 HostRequest::PushNotification { text, deeplink } => {
1159 assert_eq!(text, "Transfer complete");
1160 assert_eq!(deeplink.as_deref(), Some("https://app.example/tx/123"));
1161 }
1162 _ => panic!("expected PushNotification"),
1163 }
1164 }
1165
1166 #[test]
1167 fn decode_push_notification_request_without_deeplink() {
1168 let mut msg = Vec::new();
1169 msg.push(PROTOCOL_DISCRIMINATOR);
1170 encode_string(&mut msg, "pn-2");
1171 msg.push(TAG_PUSH_NOTIFICATION_REQ);
1172 msg.push(0); encode_string(&mut msg, "Hello world");
1174 msg.push(0x00); let (id, tag, req) = decode_message(&msg).unwrap();
1177 assert_eq!(id, "pn-2");
1178 assert_eq!(tag, TAG_PUSH_NOTIFICATION_REQ);
1179 match req {
1180 HostRequest::PushNotification { text, deeplink } => {
1181 assert_eq!(text, "Hello world");
1182 assert!(deeplink.is_none());
1183 }
1184 _ => panic!("expected PushNotification"),
1185 }
1186 }
1187
1188 #[test]
1189 fn encode_push_notification_response_produces_ok() {
1190 let resp = encode_push_notification_response("pn-1");
1191 let mut r = Reader::new(&resp);
1192 assert_eq!(r.read_u8().unwrap(), PROTOCOL_DISCRIMINATOR);
1193 assert_eq!(r.read_string().unwrap(), "pn-1");
1194 assert_eq!(r.read_u8().unwrap(), TAG_PUSH_NOTIFICATION_RESP);
1195 assert_eq!(r.read_u8().unwrap(), 0); assert_eq!(r.read_u8().unwrap(), 0); assert_eq!(r.pos, resp.len());
1198 }
1199
1200 #[test]
1201 fn golden_push_notification_response_ok() {
1202 let resp = encode_push_notification_response("t1");
1203 let expected: &[u8] = &[
1204 0x01, 0x08, b't', b'1', 0x05, 0x00, 0x00, ];
1210 assert_eq!(resp, expected);
1211 }
1212
1213 #[test]
1214 fn push_notification_round_trip() {
1215 let mut req_msg = Vec::new();
1216 req_msg.push(PROTOCOL_DISCRIMINATOR);
1217 encode_string(&mut req_msg, "pn-rt");
1218 req_msg.push(TAG_PUSH_NOTIFICATION_REQ);
1219 req_msg.push(0); encode_string(&mut req_msg, "Test notification");
1221 req_msg.push(0x00); let (id, _tag, req) = decode_message(&req_msg).unwrap();
1224 assert!(matches!(req, HostRequest::PushNotification { .. }));
1225
1226 let resp_bytes = encode_push_notification_response(&id);
1227
1228 let mut r = Reader::new(&resp_bytes);
1229 assert_eq!(r.read_u8().unwrap(), PROTOCOL_DISCRIMINATOR);
1230 assert_eq!(r.read_string().unwrap(), "pn-rt");
1231 assert_eq!(r.read_u8().unwrap(), TAG_PUSH_NOTIFICATION_RESP);
1232 assert_eq!(r.read_u8().unwrap(), 0); assert_eq!(r.read_u8().unwrap(), 0); }
1235
1236 #[test]
1237 fn golden_storage_read_response_some() {
1238 let resp = encode_storage_read_response("s1", Some(b"hi"));
1239 let expected: &[u8] = &[
1240 PROTOCOL_DISCRIMINATOR,
1241 0x08,
1242 b's',
1243 b'1', 13, 0x00, 0x00, 0x01, 0x08,
1249 b'h',
1250 b'i', ];
1252 assert_eq!(resp, expected);
1253 }
1254
1255 #[test]
1256 fn golden_storage_read_response_none() {
1257 let resp = encode_storage_read_response("s1", None);
1258 let expected: &[u8] = &[
1259 PROTOCOL_DISCRIMINATOR,
1260 0x08,
1261 b's',
1262 b'1', 13, 0x00, 0x00, 0x00, ];
1268 assert_eq!(resp, expected);
1269 }
1270
1271 #[test]
1272 fn test_decode_rejects_missing_discriminator() {
1273 let mut msg = Vec::new();
1275 encode_string(&mut msg, "t1");
1276 msg.push(TAG_HANDSHAKE_REQ);
1277 msg.push(0);
1278 msg.push(PROTOCOL_VERSION);
1279 assert!(matches!(
1280 decode_message(&msg),
1281 Err(DecodeErr::UnknownProtocol)
1282 ));
1283 }
1284
1285 #[test]
1286 fn test_decode_rejects_wrong_discriminator() {
1287 let mut msg = vec![0x00]; encode_string(&mut msg, "t1");
1289 msg.push(TAG_HANDSHAKE_REQ);
1290 msg.push(0);
1291 msg.push(PROTOCOL_VERSION);
1292 assert!(matches!(
1293 decode_message(&msg),
1294 Err(DecodeErr::UnknownProtocol)
1295 ));
1296 }
1297
1298 #[test]
1299 fn test_decode_accepts_correct_discriminator() {
1300 let mut msg = vec![PROTOCOL_DISCRIMINATOR];
1301 encode_string(&mut msg, "t1");
1302 msg.push(TAG_HANDSHAKE_REQ);
1303 msg.push(0);
1304 msg.push(PROTOCOL_VERSION);
1305 let (req_id, tag, _) = decode_message(&msg).unwrap();
1306 assert_eq!(req_id, "t1");
1307 assert_eq!(tag, TAG_HANDSHAKE_REQ);
1308 }
1309
1310 #[test]
1311 fn test_is_host_sdk_message_true() {
1312 assert!(is_host_sdk_message(&[0x01, 0x08, b't', b'1', 0]));
1313 assert!(is_host_sdk_message(&[0x01])); }
1315
1316 #[test]
1317 fn test_is_host_sdk_message_false_empty() {
1318 assert!(!is_host_sdk_message(&[]));
1319 }
1320
1321 #[test]
1322 fn test_is_host_sdk_message_false_wrong_byte() {
1323 assert!(!is_host_sdk_message(&[0x00, 0x08]));
1324 assert!(!is_host_sdk_message(&[0x02, 0x08]));
1325 assert!(!is_host_sdk_message(&[0xFF]));
1326 }
1327
1328 #[test]
1329 fn test_all_encode_functions_start_with_discriminator() {
1330 let buf = encode_response("r", TAG_HANDSHAKE_REQ, &HostResponse::HandshakeOk);
1332 assert_eq!(buf[0], PROTOCOL_DISCRIMINATOR);
1333
1334 let buf = encode_response(
1336 "r",
1337 TAG_GET_NON_PRODUCT_ACCOUNTS_REQ,
1338 &HostResponse::AccountList(vec![]),
1339 );
1340 assert_eq!(buf[0], PROTOCOL_DISCRIMINATOR);
1341
1342 let buf = encode_response("r", TAG_HANDSHAKE_REQ, &HostResponse::Error("e".into()));
1344 assert_eq!(buf[0], PROTOCOL_DISCRIMINATOR);
1345
1346 assert_eq!(
1348 encode_feature_response("r", true)[0],
1349 PROTOCOL_DISCRIMINATOR
1350 );
1351 assert_eq!(
1352 encode_feature_response("r", false)[0],
1353 PROTOCOL_DISCRIMINATOR
1354 );
1355
1356 assert_eq!(encode_account_status("r", true)[0], PROTOCOL_DISCRIMINATOR);
1358
1359 assert_eq!(
1361 encode_storage_read_response("r", None)[0],
1362 PROTOCOL_DISCRIMINATOR
1363 );
1364 assert_eq!(
1365 encode_storage_read_response("r", Some(b"v"))[0],
1366 PROTOCOL_DISCRIMINATOR
1367 );
1368
1369 assert_eq!(
1371 encode_storage_write_response("r", false)[0],
1372 PROTOCOL_DISCRIMINATOR
1373 );
1374 assert_eq!(
1375 encode_storage_write_response("r", true)[0],
1376 PROTOCOL_DISCRIMINATOR
1377 );
1378
1379 assert_eq!(encode_navigate_response("r")[0], PROTOCOL_DISCRIMINATOR);
1381
1382 assert_eq!(
1384 encode_push_notification_response("r")[0],
1385 PROTOCOL_DISCRIMINATOR
1386 );
1387
1388 assert_eq!(
1390 encode_sign_response("r", false, &[0; 64])[0],
1391 PROTOCOL_DISCRIMINATOR
1392 );
1393 assert_eq!(
1394 encode_sign_response("r", true, &[0; 64])[0],
1395 PROTOCOL_DISCRIMINATOR
1396 );
1397
1398 assert_eq!(
1400 encode_jsonrpc_send_response("r", "{}")[0],
1401 PROTOCOL_DISCRIMINATOR
1402 );
1403
1404 assert_eq!(encode_jsonrpc_send_error("r")[0], PROTOCOL_DISCRIMINATOR);
1406
1407 assert_eq!(
1409 encode_jsonrpc_sub_receive("r", "{}")[0],
1410 PROTOCOL_DISCRIMINATOR
1411 );
1412
1413 assert_eq!(encode_sign_error("r", false)[0], PROTOCOL_DISCRIMINATOR);
1415 assert_eq!(encode_sign_error("r", true)[0], PROTOCOL_DISCRIMINATOR);
1416 }
1417}