Skip to content

Commit

Permalink
Uniffi funds recovery.
Browse files Browse the repository at this point in the history
  • Loading branch information
zhenlu committed Apr 11, 2024
1 parent e9e0b19 commit 7b9ea9a
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 19 deletions.
59 changes: 40 additions & 19 deletions src/funds_recovery_kit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ use bitcoin::{Amount, Script, Transaction};
use serde::{Deserialize, Serialize};
use std::str::FromStr;

use crate::signer;

#[derive(Serialize, Deserialize, Debug, Clone)]
struct Event {
commitment_tx: String,
Expand All @@ -37,12 +39,18 @@ struct Event {
counterparty_serialized_commitment_tx: Option<String>,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct StringTuple {
pub first: String,
pub second: String,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct Response {
pub commitment_tx: String,
pub sweep_tx: String,
pub htlc_inbound_tx: Vec<(String, String)>,
pub htlc_outbound_tx: Vec<(String, String)>,
pub htlc_inbound_tx: Vec<StringTuple>,
pub htlc_outbound_tx: Vec<StringTuple>,
pub counterparty_sweep_tx: String,
pub counterparty_htlc_inbound_tx: Vec<String>,
pub counterparty_htlc_outbound_tx: Vec<String>,
Expand All @@ -69,6 +77,12 @@ impl From<&str> for FundsRecoveryKitError {
}
}

impl FundsRecoveryKitError {
pub fn message(&self) -> String {
self.to_string()
}
}

fn tweak_key(
secret_key: SecretKey,
add_tweak: [u8; 32],
Expand Down Expand Up @@ -717,20 +731,16 @@ fn sign_transactions_impl(
sweep_tx: hex::encode(encode::serialize(&sweep_transaction)),
htlc_inbound_tx: all_htlc_inbound_transactions
.iter()
.map(|(tx, sweep_tx)| {
(
hex::encode(encode::serialize(&tx)),
hex::encode(encode::serialize(&sweep_tx)),
)
.map(|(tx, sweep_tx)| StringTuple {
first: hex::encode(encode::serialize(&tx)),
second: hex::encode(encode::serialize(&sweep_tx)),
})
.collect(),
htlc_outbound_tx: all_htlc_outbound_transactions
.iter()
.map(|(tx, sweep_tx)| {
(
hex::encode(encode::serialize(&tx)),
hex::encode(encode::serialize(&sweep_tx)),
)
.map(|(tx, sweep_tx)| StringTuple {
first: hex::encode(encode::serialize(&tx)),
second: hex::encode(encode::serialize(&sweep_tx)),
})
.collect(),
counterparty_sweep_tx,
Expand All @@ -748,8 +758,13 @@ fn sign_transactions_impl(
pub fn sign_transactions(
master_seed: String,
data: String,
network: bitcoin::Network,
network: signer::Network,
) -> Result<Response, FundsRecoveryKitError> {
let network = match network {
signer::Network::Bitcoin => bitcoin::Network::Bitcoin,
signer::Network::Testnet => bitcoin::Network::Testnet,
signer::Network::Regtest => bitcoin::Network::Regtest,
};
// For now, do not expose implementation errors as the kit should just be serialized and sent. If this fails we will have to look into it further.
sign_transactions_impl(master_seed, data, network).map_err(|_| FundsRecoveryKitError::from("Generating the funds recovery kit failed. The kit should only be serialized and sent without modification."))
}
Expand Down Expand Up @@ -788,7 +803,7 @@ mod tests {
fn test_funds_recovery_kit_basic() {
let data = r#"{"commitment_tx": "0200000000010187748372b3dfb3d47c2bb0a02848a327c77f5c982d036626c6de0a958af56069000000000025cee5800236ad03000000000016001415f586897037ded59858ccb1d24d4fbe7602692e90d00300000000002200204a30a8d4aba2d9d2e245052fc3566e1e18c49c1f364351481bfdd3e4d3a60da00400473044022066dbda605a766bc8143e15825c878b3b9444637b04678da42fe8f0c317c41fc70220482bb1a741497b14650c1e07ec4a00803855ff0f6a1434c88ae068f51567e94201004752210315496a93245ab6a7373b4e7297a30e2a20feefc50c59484dce93b6685e3ec0302103e65fcacf66816c0cb7d85726944463efe1466184a01d99949aed8a8b0676009a52aee1158720", "sweep_tx": "020000000001016d0d0c47799e62541fc4bb51461b4bed8a5ed978ebe4f52d4c168a5b950d6f5401000000009000000001fbb80300000000001600146b0009af85b18052eb83afbdc9c45521c552588f0300004d632102a299258a6ac6b9be6b7ee879a87aca8a30e05d15e915b7af722f09d44c5014a867029000b2752103c74ec665bd1547f4a3dccee02c104677c7e880c6b0bdaec0cea195680d3cb62768ac00000000", "htlc_tx": [], "serialized_htlc_sweep_tx": [], "channel_point": "6960f58a950adec62666032d985c7fc727a34828a0b02b7cd4b3dfb372837487:0", "sweep_tx_add_tweak": "201d490866cdcc50199497d98b699f4ae367b23e801ffe405f3f983deef42f56", "htlc_tx_add_tweak": "146d304968ba398899c7147fb641a6e20d4134b2c78abf4a2eb67e094fd730c1", "funding_private_key_derivation_path": "m/3/599143572/0", "delayed_payment_base_key_derivation_path": "m/3/599143572/3", "htlc_base_key_derivation_path": "m/3/599143572/4", "channel_capacity": 500000, "nonces": [], "commitment_number": 1}"#;
let master_seed = "f520e5271623fe21c76b0212f855c97a";
let resp = sign_transactions(master_seed.into(), data.into(), bitcoin::Network::Regtest)
let resp = sign_transactions(master_seed.into(), data.into(), signer::Network::Regtest)
.expect("Data should be valid");

// commitment transaction rust
Expand Down Expand Up @@ -838,7 +853,7 @@ mod tests {
fn test_funds_recovery_kit_with_counterparty_transactions() {
let data = r#"{"counterparty_sweep_tx": "020000000001013473c2a4e6c07675f5344f356a94d6e681ea7d98c848f5454de91230e5a82528010000000000000000012dbb0300000000001600146b0009af85b18052eb83afbdc9c45521c552588f0200210371796599c83e9fce1de1877047604d7a6e0b1ca672da7b5290f941b2f2806c5000000000", "counterparty_serialized_htlc_sweep_tx": [], "counterparty_htlc_tx_add_tweak": "cef67a943db83ff419a914492808640ae8894bd87f56efbb4ffa768627086ce0", "counterparty_nonces": [], "payment_key_derivation_path": "m/3/599143572/2", "counterparty_serialized_commitment_tx": "020000000187748372b3dfb3d47c2bb0a02848a327c77f5c982d036626c6de0a958af56069000000000025cee5800236ad030000000000220020c3f5a2a4985affb278fabe1efca88b967f361492c8e2bb178d1acbd90d9fb8dc90d0030000000000160014e7c08ed2ca1a6aad8864f6d3159f8ac9583622ece1158720", "commitment_tx": "0200000000010187748372b3dfb3d47c2bb0a02848a327c77f5c982d036626c6de0a958af56069000000000025cee5800236ad03000000000016001415f586897037ded59858ccb1d24d4fbe7602692e90d00300000000002200204a30a8d4aba2d9d2e245052fc3566e1e18c49c1f364351481bfdd3e4d3a60da00400473044022066dbda605a766bc8143e15825c878b3b9444637b04678da42fe8f0c317c41fc70220482bb1a741497b14650c1e07ec4a00803855ff0f6a1434c88ae068f51567e94201004752210315496a93245ab6a7373b4e7297a30e2a20feefc50c59484dce93b6685e3ec0302103e65fcacf66816c0cb7d85726944463efe1466184a01d99949aed8a8b0676009a52aee1158720", "sweep_tx": "020000000001016d0d0c47799e62541fc4bb51461b4bed8a5ed978ebe4f52d4c168a5b950d6f5401000000009000000001fbb80300000000001600146b0009af85b18052eb83afbdc9c45521c552588f0300004d632102a299258a6ac6b9be6b7ee879a87aca8a30e05d15e915b7af722f09d44c5014a867029000b2752103c74ec665bd1547f4a3dccee02c104677c7e880c6b0bdaec0cea195680d3cb62768ac00000000", "htlc_tx": [], "serialized_htlc_sweep_tx": [], "channel_point": "6960f58a950adec62666032d985c7fc727a34828a0b02b7cd4b3dfb372837487:0", "sweep_tx_add_tweak": "201d490866cdcc50199497d98b699f4ae367b23e801ffe405f3f983deef42f56", "htlc_tx_add_tweak": "146d304968ba398899c7147fb641a6e20d4134b2c78abf4a2eb67e094fd730c1", "funding_private_key_derivation_path": "m/3/599143572/0", "delayed_payment_base_key_derivation_path": "m/3/599143572/3", "htlc_base_key_derivation_path": "m/3/599143572/4", "channel_capacity": 500000, "nonces": [], "commitment_number": 1}"#;
let master_seed = "f520e5271623fe21c76b0212f855c97a";
let resp = sign_transactions(master_seed.into(), data.into(), bitcoin::Network::Regtest)
let resp = sign_transactions(master_seed.into(), data.into(), signer::Network::Regtest)
.expect("Data should be valid");

// commitment transaction rust
Expand Down Expand Up @@ -903,7 +918,7 @@ mod tests {
fn test_funds_recovery_kit_with_inbound_htlcs_and_counterparty_outbound_htlcs() {
let data = r#"{"commitment_tx": "0200000000010105186fe9040861e40860b2e140ff855c7fe83ee1d6820b551d5f3a645590c6d500000000000781c4800350c30000000000002200205819a33452804c9642b389697cedac5f8084d120a103fcdbade9bcceeca02b33301e020000000000160014242e85ae29b8f41d28c7357e6c2efb199cb0fb53e0930400000000002200209590a2001663edd66090460d1f471f9081d152fb9244e71c633463a44c3d3f0d040000483045022100c70ef515822f5c608ec5f656ee9f57f9f964940ee4a524d7b1b3430968e9281f02201910da8a02b7a00723476062fc0b903840850f79325b960c4e4cb9459b015ae301475221020e3b6f63b9f41093fe681ef8f0b40e55ad36499ff5c67c4d28d1d4085f7eb2f121023f693b74c445a2e1e6883579a8aacd1f025e3a146724579a3245da7454fb7cb952aeb014c720", "sweep_tx": "020000000001019297117bf9307b382fe3b828549ff5437fcaa3b26abbcf4601072b2902649dc7020000000090000000014b7c0400000000001600146b0009af85b18052eb83afbdc9c45521c552588f0300004d632103d097f8bde004f9be3166bb61fda07209cfece8af19fd1ca1154ecb74f4e98ffb67029000b275210313c27137b6458fef62f6f8d45145b1d2788381a990607e552013e2555fd8187568ac00000000", "htlc_tx": ["020000000001019297117bf9307b382fe3b828549ff5437fcaa3b26abbcf4601072b2902649dc700000000000000000001fda00000000000002200209590a2001663edd66090460d1f471f9081d152fb9244e71c633463a44c3d3f0d050047304402204467dc7ad1abaf9d00c93255ad0ec2b8293be4d0b9597128d3675f15e1abd25002204fffe0f61d88b882d048132e5eabafe0cd034d73fd257a173f36b0585608beec0100008b76a91467aa35a4cbee56bd2ab29fcdf75d720eb8a02b118763ac67210313932240cb488f8f6dffb5c43bd7e605078212a14439f4bac355cef32522a3257c8201208763a91490b2bd87c689ec31aed86574402095554b19412c88527c21033bd5d1f4d8277b6400e0e32ae8c3b28d7566908bc24420940b32dbf00d6c25b552ae677503ae9300b175ac686800000000"], "serialized_htlc_sweep_tx": ["020000000001012b7ac5288c38f024fc9683f64041f037671b4b552c81fd7e6e01ee46ad185e6b0000000000900000000168890000000000001600146b0009af85b18052eb83afbdc9c45521c552588f0300004d632103d097f8bde004f9be3166bb61fda07209cfece8af19fd1ca1154ecb74f4e98ffb67029000b275210313c27137b6458fef62f6f8d45145b1d2788381a990607e552013e2555fd8187568ac00000000"], "channel_point": "d5c69055643a5f1d550b82d6e13ee87f5c85ff40e1b26008e4610804e96f1805:0", "sweep_tx_add_tweak": "9cd9a5516e1f783e08a92f926a553c04d60b1b28d7c26336105fd2c2a8899d5b", "htlc_tx_add_tweak": "ca0a7f958fd3221def8983eff8f8cd1f0e51b227f1a10bdafbefbb45491cc0cb", "funding_private_key_derivation_path": "m/3/637642393/0", "delayed_payment_base_key_derivation_path": "m/3/637642393/3", "htlc_base_key_derivation_path": "m/3/637642393/4", "channel_capacity": 500000, "nonces": ["18541fe85c5126003c0dedb79e24987a3b36195c13d33ecb77f0728c2f841734"], "counterparty_sweep_tx": "02000000000101a8e7d890e135f4a5066e351b3035c0b11056107967b6e8220a24dbe2cebbe22f020000000000000000017d7e0400000000001600146b0009af85b18052eb83afbdc9c45521c552588f0200210211497bff8343b0566a3bf78d5bf0967a88aa039e9d30a5f9f1eeed38a38e20b800000000", "counterparty_serialized_htlc_sweep_tx": ["02000000000101a8e7d890e135f4a5066e351b3035c0b11056107967b6e8220a24dbe2cebbe22f00000000000000000001f1a20000000000001600146b0009af85b18052eb83afbdc9c45521c552588f0300008576a914c5a930dfd00a9165e9dbbee31326fb8a5d09612f8763ac67210363f80146fd3bdbe88e49a5b5f5a384e873e7423a8a4fb22a912893883795b7d37c820120876475527c2102e59e26ede9c3dd9dd6fa7dbce42467a53b04b86aa7c92fa385c7f9ffcd1bfe5f52ae67a91490b2bd87c689ec31aed86574402095554b19412c88ac686800000000"], "counterparty_htlc_tx_add_tweak": "87c4204be8bc682709f678a8fa4dfc2d672f4d1946ba436a40c6ef4564de97f9", "counterparty_nonces": ["18541fe85c5126003c0dedb79e24987a3b36195c13d33ecb77f0728c2f841734"], "payment_key_derivation_path": "m/3/637642393/2", "counterparty_serialized_commitment_tx": "020000000105186fe9040861e40860b2e140ff855c7fe83ee1d6820b551d5f3a645590c6d500000000000781c4800350c300000000000022002021b1ae8dd7084d0302c4c0b798474e4b1805b98f0fa9d6a17e5da323ba1041c6301e0200000000002200203e7452e0d1c5f0327609a046c1dcc0adfdb5bbd8e13095517c928e6b5ff31378e0930400000000001600146910c10e307c206562bf88ac9dea93d472f90f5ab014c720", "commitment_number": 1}"#;
let master_seed = "f520e5271623fe21c76b0212f855c97a";
let resp = sign_transactions(master_seed.into(), data.into(), bitcoin::Network::Regtest)
let resp = sign_transactions(master_seed.into(), data.into(), signer::Network::Regtest)
.expect("Data should be valid");

// commitment transaction rust
Expand Down Expand Up @@ -963,7 +978,10 @@ mod tests {
"650bb8a1c951e7fdb3748f4c393dfce778175f61f518a7258526b9acc5e7c046",
));

let (rust_htlc_transaction, rust_htlc_sweep_transaction) = resp.htlc_inbound_tx[0].clone();
let (rust_htlc_transaction, rust_htlc_sweep_transaction) = (
resp.htlc_inbound_tx[0].clone().first,
resp.htlc_inbound_tx[0].clone().second,
);
// inbound htlc transaction rust
assert!(verify_signature(
&rust_htlc_transaction,
Expand Down Expand Up @@ -1026,7 +1044,7 @@ mod tests {
fn test_funds_recovery_kit_with_outbound_htlcs_and_counterparty_inbound_htlcs() {
let data = r#"{"counterparty_sweep_tx": "02000000000101688e5e19da698bc61f8718a44b6e1333246026c7ed6c470faca1a30fd5f320ea00000000000000000001edad0000000000001600146b0009af85b18052eb83afbdc9c45521c552588f02002102ef9180a5eb2e375349e230f2d4db6f2d8640e551cc49268fa13cbc3d1974691d00000000", "counterparty_serialized_htlc_sweep_tx": ["02000000000101688e5e19da698bc61f8718a44b6e1333246026c7ed6c470faca1a30fd5f320ea01000000000000000001fda00000000000001600146b0009af85b18052eb83afbdc9c45521c552588f0300008b76a9146c5ab60ccb89adb2ee50711bbf0276322221a9bf8763ac67210253f0a86f34769a606dba7f8bbe840ed7af058230d0cfa3f19ed9a5c99c9b94ae7c8201208763a914f7b9d68089d95ffcb1aa468f9dfe2ea35efb608488527c21030e12b74fac45f57ea431ddedb26802ea71c7e3caef6bff2c684bc5e5e487824f52ae677503319e00b175ac6868319e0000"], "counterparty_htlc_tx_add_tweak": "7ffdd12ca53fd8ea3d69c4f24a9277b05f62186e8f1e7447845c1717add2ca93", "counterparty_nonces": [""], "payment_key_derivation_path": "m/3/833563776/2", "counterparty_serialized_commitment_tx": "0200000001f09eb2d66530f30845ad2ba16c32cb576b0f5d6aac47822c43f7d7109d753fc60100000000a91c67800350c30000000000001600144001c52674e9382e0a17142bdefbb76edb45e1ac50c30000000000002200207db96038aa3966ba586911dea677743e93a2ad6ef95368911d69ea14e1412629c0ee05000000000022002052f16313b8d8a34517e428cf9225b13d7a8c7325a34aaa2b3e4455e5f1d966b58f447320", "commitment_tx": "02000000000101f09eb2d66530f30845ad2ba16c32cb576b0f5d6aac47822c43f7d7109d753fc60100000000a91c67800350c300000000000022002027e12aecbf0ff9d2de7c0ab0a05f8437baa82e950dd9a3fa94657b46bcc9f23950c3000000000000220020d7c36a365eaaaee3d2ebfcbd24e9932148d5d8b7a21acd934ea2933a06f3fd72c0ee05000000000016001454141bdd6dab56d098d8bceec316330b54374bb00400473044022017f51ba19bcf6910b1b556d9fe6c101fa20734a8b119892914cc1aa55c5b9c2402206837a0acba5a06285ae477e9e815859d0232888d8bb88460fd22418fbc523f2b0100475221021b0861699c0754dc169ea80096e5d66f4ca528d5d7db5dbbd1a33d3f7f5e12ac21032f769f4418aa8b72dee19f0d440dcdc8bd26e5a67fbe0f6e4aa4dbb21586d75e52ae8f447320", "sweep_tx": "020000000001017208c29754db7f75e6b31ef6a986f2593b0f9f6a5592a50f0865bf92ea3d606101000000009000000001bbab0000000000001600146b0009af85b18052eb83afbdc9c45521c552588f0300004d632103efa27702961794d09480b6c9101a67880e45a254f51d139e170008588e7b122367029000b27521027100dc4ee38f2f877ca7c39b7ccba6e1febaf344e8fbd0649fd9200c761ace2768ac00000000", "htlc_tx": ["020000000001017208c29754db7f75e6b31ef6a986f2593b0f9f6a5592a50f0865bf92ea3d606100000000000000000001f1a2000000000000220020d7c36a365eaaaee3d2ebfcbd24e9932148d5d8b7a21acd934ea2933a06f3fd720500483045022100b1e3470ab59ce935aac350474856e831a1a1b21bbf0f80e4b198deb7ed9a97d3022000875eb6e995ecef78170f9afa062e494d16cb594d1835dcee6a9fe410b28a480100008576a914f76a8b93697ebca341901985c6644e5fce6050b38763ac6721026d0b8fc557042d47870c886e16193ec2a15f9bda8be7cbd305d3bacaf4d415e17c820120876475527c2102ee3dd778c31b9a11b11589f2cfbb58ddb4c8d20b386401c64ce1a4e4f9d59c2852ae67a914f7b9d68089d95ffcb1aa468f9dfe2ea35efb608488ac6868319e0000"], "serialized_htlc_sweep_tx": ["02000000000101f747320e858783f6e6a8e05e81c888cfd4defdde6b6560b6ad869a6331347d94000000000090000000015c8b0000000000001600146b0009af85b18052eb83afbdc9c45521c552588f0300004d632103efa27702961794d09480b6c9101a67880e45a254f51d139e170008588e7b122367029000b27521027100dc4ee38f2f877ca7c39b7ccba6e1febaf344e8fbd0649fd9200c761ace2768ac00000000"], "channel_point": "c63f759d10d7f7432c8247ac6a5d0f6b57cb326ca12bad4508f33065d6b29ef0:1", "sweep_tx_add_tweak": "ab823b1e6f52b50b11e69d888941a2a4b88c727e887af8323f2ef7b91d649fe8", "htlc_tx_add_tweak": "e10fe25fae09330c5fd211927fddc3756e9bcad238f3f2c07a8a24b8f7280afb", "funding_private_key_derivation_path": "m/3/833563776/0", "delayed_payment_base_key_derivation_path": "m/3/833563776/3", "htlc_base_key_derivation_path": "m/3/833563776/4", "channel_capacity": 500000, "nonces": [""], "commitment_number": 1}"#;
let master_seed = "f520e5271623fe21c76b0212f855c97a";
let resp = sign_transactions(master_seed.into(), data.into(), bitcoin::Network::Regtest)
let resp = sign_transactions(master_seed.into(), data.into(), signer::Network::Regtest)
.expect("Data should be valid");

// commitment transaction rust
Expand Down Expand Up @@ -1086,7 +1104,10 @@ mod tests {
"4a6c8a4c013dcb97d336614f75a7ad14e03593ac61901696102a65eb4e6e3907",
));

let (rust_htlc_transaction, rust_htlc_sweep_transaction) = resp.htlc_outbound_tx[0].clone();
let (rust_htlc_transaction, rust_htlc_sweep_transaction) = (
resp.htlc_outbound_tx[0].clone().first,
resp.htlc_outbound_tx[0].clone().second,
);
// outbount htlc transaction rust
assert!(verify_signature(
&rust_htlc_transaction,
Expand Down
9 changes: 9 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,14 @@ use signer::Network;
#[cfg(not(target_arch = "wasm32"))]
use signer::Seed;

#[cfg(not(target_arch = "wasm32"))]
use crate::funds_recovery_kit::sign_transactions;
#[cfg(not(target_arch = "wasm32"))]
use crate::funds_recovery_kit::FundsRecoveryKitError;
#[cfg(not(target_arch = "wasm32"))]
use funds_recovery_kit::Response;
#[cfg(not(target_arch = "wasm32"))]
use funds_recovery_kit::StringTuple;

#[cfg(not(target_arch = "wasm32"))]
uniffi::include_scaffolding!("lightspark_crypto");
27 changes: 27 additions & 0 deletions src/lightspark_crypto.udl
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,28 @@ namespace lightspark_crypto {
sequence<u8> master_seed_bytes,
Validation validation
);

[Throws=FundsRecoveryKitError]
Response sign_transactions(
string master_seed,
string data,
Network network
);
};

dictionary StringTuple {
string first;
string second;
};

dictionary Response {
string commitment_tx;
string sweep_tx;
sequence<StringTuple> htlc_inbound_tx;
sequence<StringTuple> htlc_outbound_tx;
string counterparty_sweep_tx;
sequence<string> counterparty_htlc_inbound_tx;
sequence<string> counterparty_htlc_outbound_tx;
};

dictionary RemoteSigningResponse {
Expand Down Expand Up @@ -66,6 +88,11 @@ enum LightsparkSignerError {
"EntropyLengthError",
};

[Traits=(Debug)]
interface FundsRecoveryKitError{
string message();
};

enum Network {
"Bitcoin",
"Testnet",
Expand Down

0 comments on commit 7b9ea9a

Please sign in to comment.