thesimplekid 9 сар өмнө
parent
commit
60134c8860

+ 83 - 0
crates/cdk/src/amount.rs

@@ -21,6 +21,48 @@ impl Amount {
             })
             .collect()
     }
+
+    /// Split into parts that are powers of two by target
+    pub fn split_targeted(&self, target: &SplitTarget) -> Vec<Self> {
+        let mut parts = vec![];
+        let mut parts_total = Amount::ZERO;
+
+        match target {
+            &SplitTarget::Value(amount) => {
+                if self.le(&amount) {
+                    return self.split();
+                }
+
+                // The powers of two that are need to create target value
+                let parts_of_value = amount.split();
+
+                while parts_total.lt(self) {
+                    for part in parts_of_value.iter().copied() {
+                        if (part + parts_total).le(self) {
+                            parts.push(part);
+                        } else {
+                            let amount_left = *self - parts_total;
+                            parts.extend(amount_left.split());
+                        }
+
+                        parts_total = parts.clone().iter().copied().sum::<Amount>();
+
+                        if parts_total.eq(self) {
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+
+        parts.sort();
+        parts
+    }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
+pub enum SplitTarget {
+    Value(Amount),
 }
 
 impl Default for Amount {
@@ -102,4 +144,45 @@ mod tests {
             .collect();
         assert_eq!(Amount::from(255).split(), amounts);
     }
+
+    #[test]
+    fn test_split_target_amount() {
+        let amount = Amount(65);
+
+        let split = amount.split_targeted(&SplitTarget::Value(Amount(32)));
+        assert_eq!(vec![Amount(1), Amount(32), Amount(32)], split);
+
+        let amount = Amount(150);
+
+        let split = amount.split_targeted(&SplitTarget::Value(Amount::from(50)));
+        assert_eq!(
+            vec![
+                Amount(2),
+                Amount(2),
+                Amount(2),
+                Amount(16),
+                Amount(16),
+                Amount(16),
+                Amount(32),
+                Amount(32),
+                Amount(32)
+            ],
+            split
+        );
+
+        let amount = Amount::from(63);
+
+        let split = amount.split_targeted(&SplitTarget::Value(Amount::from(32)));
+        assert_eq!(
+            vec![
+                Amount(1),
+                Amount(2),
+                Amount(4),
+                Amount(8),
+                Amount(16),
+                Amount(32)
+            ],
+            split
+        );
+    }
 }

+ 2 - 13
crates/cdk/src/util/mod.rs

@@ -3,10 +3,7 @@
 #[cfg(not(target_arch = "wasm32"))]
 use std::time::{SystemTime, UNIX_EPOCH};
 
-use bitcoin::hashes::sha256::Hash as Sha256;
-use bitcoin::hashes::Hash;
-use bitcoin::secp256k1::rand::{self, RngCore};
-use bitcoin::secp256k1::{All, Secp256k1};
+use bitcoin::secp256k1::{rand, All, Secp256k1};
 #[cfg(target_arch = "wasm32")]
 use instant::SystemTime;
 use once_cell::sync::Lazy;
@@ -24,15 +21,7 @@ pub static SECP256K1: Lazy<Secp256k1<All>> = Lazy::new(|| {
     ctx
 });
 
-pub fn random_hash() -> Vec<u8> {
-    let mut rng = rand::thread_rng();
-    let mut random_bytes: [u8; 32] = [0u8; Sha256::LEN];
-    rng.fill_bytes(&mut random_bytes);
-
-    let hash = Sha256::hash(&random_bytes);
-    hash.to_byte_array().to_vec()
-}
-
+/// Seconds since unix epoch
 pub fn unix_time() -> u64 {
     SystemTime::now()
         .duration_since(UNIX_EPOCH)