spark_sdk/wallet/internal_handlers/
utils.rs1use crate::constants::spark::TIME_LOCK_INTERVAL;
3use crate::error::SparkSdkError;
4
5use spark_protos::common::SigningCommitment as ProtoSigningCommitment;
7
8use crate::common_types::types::Transaction;
10
11use bitcoin::consensus::{self, Encodable};
13use frost_secp256k1_tr::round1::SigningCommitments as FrostSigningCommitments;
14
15pub(crate) fn frost_commitment_to_proto_commitment(
16 commitments: &FrostSigningCommitments,
17) -> Result<ProtoSigningCommitment, SparkSdkError> {
18 let hiding = commitments.hiding().serialize().unwrap();
19 let binding = commitments.binding().serialize().unwrap();
20
21 Ok(ProtoSigningCommitment { hiding, binding })
22}
23
24pub(crate) fn serialize_bitcoin_transaction(
25 transaction: &Transaction,
26) -> Result<Vec<u8>, SparkSdkError> {
27 let mut buf = Vec::new();
28 transaction.consensus_encode(&mut buf).map_err(|e| {
29 SparkSdkError::InvalidBitcoinTransaction(format!(
30 "Failed to serialize Bitcoin transaction: {}",
31 e
32 ))
33 })?;
34
35 Ok(buf)
36}
37
38pub(crate) fn bitcoin_tx_from_bytes(
39 transaction_bytes: &Vec<u8>,
40) -> Result<Transaction, SparkSdkError> {
41 if transaction_bytes.len() == 0 {
42 return Err(SparkSdkError::InvalidBitcoinTransaction(
43 "Cannot deserialize Bitcoin transaction: buffer is empty".to_string(),
44 ));
45 }
46
47 let transaction = consensus::deserialize(transaction_bytes)
48 .map_err(|_| SparkSdkError::InvalidBitcoinTransaction("Invalid transaction".to_string()))?;
49
50 Ok(transaction)
51}
52
53pub(crate) fn next_sequence(curr_sequence: u32) -> u32 {
54 let mask = curr_sequence & 0xFFFF;
55 if TIME_LOCK_INTERVAL >= mask {
56 return 0;
57 };
58
59 (1 << 30) | (mask - TIME_LOCK_INTERVAL)
60}
61
62pub(crate) mod parsers {
63
64 use crate::common_types::types::PublicKey;
65 use crate::common_types::types::SecretKey;
66 use crate::error::SparkSdkError;
67
68 pub fn parse_secret_key(bytes: &Vec<u8>) -> Result<SecretKey, SparkSdkError> {
69 let secret_key = bitcoin::secp256k1::SecretKey::from_slice(bytes).map_err(|e| {
70 SparkSdkError::InvalidArgument(format!("Private key is not valid: {}", e))
71 })?;
72
73 Ok(secret_key)
74 }
75
76 pub fn parse_public_key(bytes: &Vec<u8>) -> Result<PublicKey, SparkSdkError> {
77 let public_key = bitcoin::secp256k1::PublicKey::from_slice(bytes).map_err(|e| {
78 SparkSdkError::InvalidArgument(format!("Public key is not valid: {}", e))
79 })?;
80
81 Ok(public_key)
82 }
83}
84
85#[cfg(test)]
86mod next_sequence_tests {
87 use super::*;
88 use crate::constants::spark::TIME_LOCK_INTERVAL;
89
90 #[test]
91 fn test_next_sequence_returns_zero_when_timelock_greater_than_mask() {
92 let curr_sequence = TIME_LOCK_INTERVAL;
93 assert_eq!(next_sequence(curr_sequence), 0);
94 }
95
96 #[test]
97 fn test_next_sequence_returns_zero_when_timelock_equals_mask() {
98 let curr_sequence = TIME_LOCK_INTERVAL & 0xFFFF;
99 assert_eq!(next_sequence(curr_sequence), 0);
100 }
101
102 #[test]
103 fn test_next_sequence_decrements_by_timelock_interval() {
104 let curr_sequence = 100;
105 let expected = (1 << 30) | (100 - TIME_LOCK_INTERVAL);
106 assert_eq!(next_sequence(curr_sequence), expected);
107 }
108
109 #[test]
110 fn test_next_sequence_only_uses_lower_16_bits_of_input() {
111 let curr_sequence = 0xFFFFFFFF;
112 let mask = 0xFFFF;
113 let expected = (1 << 30) | ((mask - TIME_LOCK_INTERVAL) & 0xFFFF);
114 assert_eq!(next_sequence(curr_sequence), expected);
115 }
116}