Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ path = "src/main.rs"

[dependencies]
bitcoin = { version = "0.27", features = ["base64", "use-serde"] }
revaultd = { git = "https://github.com/revault/revaultd", branch = "master", default-features = false}
revaultd = { git = "https://github.com/revault/revaultd", default-features = false}
backtrace = "0.3"

iced = { version = "0.4", default-features= false, features = ["tokio", "wgpu", "svg", "qr_code"] }
Expand Down
5 changes: 2 additions & 3 deletions contrib/tools/dummysigner/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion contrib/tools/dummysigner/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ edition = "2018"
[workspace]

[dependencies]
revault_tx = { version = "0.4.0", features = ["use-serde"] }
revault_tx = { git = "https://github.com/revault/revault_tx", features = ["use-serde"] }

base64 = "0.13.0"
iced = {version = "0.3", default-features = false, features = ["wgpu", "tokio"]}
Expand Down
6 changes: 3 additions & 3 deletions contrib/tools/dummysigner/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ If the signature request was refused the response looks like:

```json
{
"cancel_tx": "<base64 encoded psbt>",
"cancel_txs": ["<base64 encoded psbt>"],
"emergency_tx": "<base64 encoded psbt>",
"emergency_unvault_tx": "<base64 encoded psbt>"
}
Expand All @@ -94,7 +94,7 @@ If the signature request was refused the response looks like:

```json
{
"cancel_tx": "<base64 encoded psbt>",
"cancel_tx": ["<base64 encoded psbt>"],
"emergency_tx": "<base64 encoded psbt>",
"emergency_unvault_tx": "<base64 encoded psbt>"
}
Expand Down Expand Up @@ -124,7 +124,7 @@ This method requires the descriptors and the emergency address.
```json
[
{
"cancel_tx": "<base64 encoded psbt>",
"cancel_txs": ["<base64 encoded psbt>"],
"emergency_tx": "<base64 encoded psbt>",
"emergency_unvault_tx": "<base64 encoded psbt>"
},
Expand Down
42 changes: 40 additions & 2 deletions contrib/tools/dummysigner/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ pub struct DelegateBatch {

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RevocationTransactions {
#[serde(with = "bitcoin_psbt")]
pub cancel_tx: PartiallySignedTransaction,
#[serde(with = "bitcoin_psbt_array")]
pub cancel_txs: [PartiallySignedTransaction; 5],

#[serde(with = "bitcoin_psbt")]
pub emergency_tx: PartiallySignedTransaction,
Expand Down Expand Up @@ -121,3 +121,41 @@ mod bitcoin_psbt {
serializer.serialize_str(&base64::encode(encode::serialize(&psbt)))
}
}

mod bitcoin_psbt_array {
use revault_tx::bitcoin::{consensus::encode, util::psbt::PartiallySignedTransaction as Psbt};
use serde::{self, ser::SerializeSeq, Deserialize, Deserializer, Serializer};

pub fn deserialize<'de, D>(deserializer: D) -> Result<[Psbt; 5], D::Error>
where
D: Deserializer<'de>,
{
let array: [String; 5] = Deserialize::deserialize(deserializer)?;
let to_psbt = |s: &str| -> Result<Psbt, D::Error> {
let bytes: Vec<u8> = base64::decode(s).map_err(serde::de::Error::custom)?;
encode::deserialize(&bytes).map_err(serde::de::Error::custom)
};
Ok([
to_psbt(&array[0])?,
to_psbt(&array[1])?,
to_psbt(&array[2])?,
to_psbt(&array[3])?,
to_psbt(&array[4])?,
])
}

pub fn serialize<'se, S>(psbts: &[Psbt; 5], serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let array: Vec<String> = psbts
.iter()
.map(|psbt| base64::encode(encode::serialize(&psbt)))
.collect();
let mut seq = serializer.serialize_seq(Some(array.len()))?;
for element in array {
seq.serialize_element(&element)?;
}
seq.end()
}
}
14 changes: 7 additions & 7 deletions contrib/tools/dummysigner/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,9 +187,9 @@ impl Application for App {
self.signer
.sign_psbt(&selected_keys, &mut target.emergency_unvault_tx)
.unwrap();
self.signer
.sign_psbt(&selected_keys, &mut target.cancel_tx)
.unwrap();
for cancel_tx in &mut target.cancel_txs {
self.signer.sign_psbt(&selected_keys, cancel_tx).unwrap();
}
*signed = true;
return Command::perform(
server::respond(writer.clone(), json!(target)),
Expand All @@ -212,9 +212,9 @@ impl Application for App {
.sign_psbt(&selected_keys, &mut revocation_txs.emergency_tx)
.unwrap();

self.signer
.sign_psbt(&selected_keys, &mut revocation_txs.cancel_tx)
.unwrap();
for cancel_tx in &mut revocation_txs.cancel_txs {
self.signer.sign_psbt(&selected_keys, cancel_tx).unwrap();
}

self.signer
.sign_psbt(
Expand Down Expand Up @@ -443,7 +443,7 @@ impl Method {
)
.unwrap();
api::RevocationTransactions {
cancel_tx: txs.cancel_tx,
cancel_txs: txs.cancel_txs,
emergency_unvault_tx: txs.emergency_unvault_tx,
emergency_tx: txs.emergency_tx,
}
Expand Down
26 changes: 16 additions & 10 deletions contrib/tools/dummysigner/src/sign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,21 +135,27 @@ impl Signer {
.emergency_address
.as_ref()
.ok_or(Error("Wallet does not have emergency_address".to_string()))?;
let (_, cancel_tx, emergency_tx, emergency_unvault_tx) = transaction_chain(
let (_, cancel_txs, emergency_tx, emergency_unvault_tx) = transaction_chain(
outpoint,
amount,
&descriptors.deposit_descriptor,
&descriptors.unvault_descriptor,
&descriptors.cpfp_descriptor,
derivation_index,
emer_address.clone(),
0,
&self.curve,
)
.map_err(|e| Error(e.to_string()))?;
let cancel_txs = cancel_txs.all_feerates();

Ok(RevocationTransactions {
cancel_tx: cancel_tx.into_psbt(),
cancel_txs: [
cancel_txs[0].psbt().clone(),
cancel_txs[1].psbt().clone(),
cancel_txs[2].psbt().clone(),
cancel_txs[3].psbt().clone(),
cancel_txs[4].psbt().clone(),
],
emergency_tx: emergency_tx.into_psbt(),
emergency_unvault_tx: emergency_unvault_tx.into_psbt(),
})
Expand Down Expand Up @@ -179,15 +185,15 @@ impl Signer {
.derive(derivation_index, &self.curve);

let unvault_tx =
UnvaultTransaction::new(deposit_txin, &unvault_descriptor, &cpfp_descriptor, 0)
UnvaultTransaction::new(deposit_txin, &unvault_descriptor, &cpfp_descriptor)
.map_err(|e| Error(e.to_string()))?;

Ok(unvault_tx.into_psbt())
}
}

pub struct RevocationTransactions {
pub cancel_tx: PartiallySignedTransaction,
pub cancel_txs: [PartiallySignedTransaction; 5],
pub emergency_tx: PartiallySignedTransaction,
pub emergency_unvault_tx: PartiallySignedTransaction,
}
Expand Down Expand Up @@ -226,16 +232,16 @@ mod tests {
.unwrap();

assert_eq!(
base64::encode(encode::serialize(&revocation_txs.cancel_tx)).to_string(),
"cHNidP8BAF4CAAAAATdzv51EXeeNc1fv6E852OhRxc67KNaWd+BrA3qN1a/1AAAAAAD9////ARRLJgcAAAAAIgAgdfJpF3TIFneDGEawKCIA4oiyxZcQtY90MYPUklUH28UAAAAAAAEBK7iGJgcAAAAAIgAgSOjPZes2prPdrcgiv+IG1sjXyTCc4KDr9+C9F+xk6LwBAwSBAAAAAQVhIQICkzqxA36tCqSnhYxtSdZwXh+zvF9msAkYr3ufAOzVJqxRh2R2qRRyqV8ir5obrrhS+alScvjCHZjyZIisa3apFLbJrbicjJNybIPiobXZR4nXe5VhiKxsk1KHZ1iyaCIGAgKTOrEDfq0KpKeFjG1J1nBeH7O8X2awCRive58A7NUmCCUdYAkAAAAAIgYCWC3tv0T0ZWTl2M2wZ1NtYOvjTNHRgBz/Ubv516wom0MI1n1/6QAAAAAiBgNHBN7LVbWqiP/R710GNmJIwTFOGWVRE2/xTquLukpJDghyqV8iAAAAAAAiAgJYLe2/RPRlZOXYzbBnU21g6+NM0dGAHP9Ru/nXrCibQwjWfX/pAAAAACICA0cE3stVtaqI/9HvXQY2YkjBMU4ZZVETb/FOq4u6SkkOCHKpXyIAAAAAAA=="
base64::encode(encode::serialize(&revocation_txs.cancel_txs[0])).to_string(),
"cHNidP8BAF4CAAAAATdzv51EXeeNc1fv6E852OhRxc67KNaWd+BrA3qN1a/1AAAAAAD9////ASp5JgcAAAAAIgAgdfJpF3TIFneDGEawKCIA4oiyxZcQtY90MYPUklUH28UAAAAAAAEBK7iGJgcAAAAAIgAgSOjPZes2prPdrcgiv+IG1sjXyTCc4KDr9+C9F+xk6LwBBWEhAgKTOrEDfq0KpKeFjG1J1nBeH7O8X2awCRive58A7NUmrFGHZHapFHKpXyKvmhuuuFL5qVJy+MIdmPJkiKxrdqkUtsmtuJyMk3Jsg+KhtdlHidd7lWGIrGyTUodnWLJoIgYCApM6sQN+rQqkp4WMbUnWcF4fs7xfZrAJGK97nwDs1SYIJR1gCQAAAAAiBgJYLe2/RPRlZOXYzbBnU21g6+NM0dGAHP9Ru/nXrCibQwjWfX/pAAAAACIGA0cE3stVtaqI/9HvXQY2YkjBMU4ZZVETb/FOq4u6SkkOCHKpXyIAAAAAACICAlgt7b9E9GVk5djNsGdTbWDr40zR0YAc/1G7+desKJtDCNZ9f+kAAAAAIgIDRwTey1W1qoj/0e9dBjZiSMExThllURNv8U6ri7pKSQ4IcqlfIgAAAAAA"
);
assert_eq!(
base64::encode(encode::serialize(&revocation_txs.emergency_tx)).to_string(),
"cHNidP8BAF4CAAAAAUeuD/NEqc88sk3DoBrKoVKjXbN2xW8Jr/4GO5q87JqJAQAAAAD9////ATheJgcAAAAAIgAgy7Co1PHzwoce0hHQR5RHMS72lSZudTF3bYrNgqLbkDYAAAAAAAEBKwAOJwcAAAAAIgAgdfJpF3TIFneDGEawKCIA4oiyxZcQtY90MYPUklUH28UBAwSBAAAAAQVHUiECWC3tv0T0ZWTl2M2wZ1NtYOvjTNHRgBz/Ubv516wom0MhA0cE3stVtaqI/9HvXQY2YkjBMU4ZZVETb/FOq4u6SkkOUq4iBgJYLe2/RPRlZOXYzbBnU21g6+NM0dGAHP9Ru/nXrCibQwjWfX/pAAAAACIGA0cE3stVtaqI/9HvXQY2YkjBMU4ZZVETb/FOq4u6SkkOCHKpXyIAAAAAAAA="
"cHNidP8BAF4CAAAAAUeuD/NEqc88sk3DoBrKoVKjXbN2xW8Jr/4GO5q87JqJAQAAAAD9////ARDEJAcAAAAAIgAgy7Co1PHzwoce0hHQR5RHMS72lSZudTF3bYrNgqLbkDYAAAAAAAEBKwAOJwcAAAAAIgAgdfJpF3TIFneDGEawKCIA4oiyxZcQtY90MYPUklUH28UBBUdSIQJYLe2/RPRlZOXYzbBnU21g6+NM0dGAHP9Ru/nXrCibQyEDRwTey1W1qoj/0e9dBjZiSMExThllURNv8U6ri7pKSQ5SriIGAlgt7b9E9GVk5djNsGdTbWDr40zR0YAc/1G7+desKJtDCNZ9f+kAAAAAIgYDRwTey1W1qoj/0e9dBjZiSMExThllURNv8U6ri7pKSQ4IcqlfIgAAAAAAAA=="
);
assert_eq!(
base64::encode(encode::serialize(&revocation_txs.emergency_unvault_tx)).to_string(),
"cHNidP8BAF4CAAAAATdzv51EXeeNc1fv6E852OhRxc67KNaWd+BrA3qN1a/1AAAAAAD9////AWa7JQcAAAAAIgAgy7Co1PHzwoce0hHQR5RHMS72lSZudTF3bYrNgqLbkDYAAAAAAAEBK7iGJgcAAAAAIgAgSOjPZes2prPdrcgiv+IG1sjXyTCc4KDr9+C9F+xk6LwBAwSBAAAAAQVhIQICkzqxA36tCqSnhYxtSdZwXh+zvF9msAkYr3ufAOzVJqxRh2R2qRRyqV8ir5obrrhS+alScvjCHZjyZIisa3apFLbJrbicjJNybIPiobXZR4nXe5VhiKxsk1KHZ1iyaCIGAgKTOrEDfq0KpKeFjG1J1nBeH7O8X2awCRive58A7NUmCCUdYAkAAAAAIgYCWC3tv0T0ZWTl2M2wZ1NtYOvjTNHRgBz/Ubv516wom0MI1n1/6QAAAAAiBgNHBN7LVbWqiP/R710GNmJIwTFOGWVRE2/xTquLukpJDghyqV8iAAAAAAAA"
"cHNidP8BAF4CAAAAATdzv51EXeeNc1fv6E852OhRxc67KNaWd+BrA3qN1a/1AAAAAAD9////AfzgIwcAAAAAIgAgy7Co1PHzwoce0hHQR5RHMS72lSZudTF3bYrNgqLbkDYAAAAAAAEBK7iGJgcAAAAAIgAgSOjPZes2prPdrcgiv+IG1sjXyTCc4KDr9+C9F+xk6LwBBWEhAgKTOrEDfq0KpKeFjG1J1nBeH7O8X2awCRive58A7NUmrFGHZHapFHKpXyKvmhuuuFL5qVJy+MIdmPJkiKxrdqkUtsmtuJyMk3Jsg+KhtdlHidd7lWGIrGyTUodnWLJoIgYCApM6sQN+rQqkp4WMbUnWcF4fs7xfZrAJGK97nwDs1SYIJR1gCQAAAAAiBgJYLe2/RPRlZOXYzbBnU21g6+NM0dGAHP9Ru/nXrCibQwjWfX/pAAAAACIGA0cE3stVtaqI/9HvXQY2YkjBMU4ZZVETb/FOq4u6SkkOCHKpXyIAAAAAAAA="
);
}

Expand Down Expand Up @@ -264,7 +270,7 @@ mod tests {

assert_eq!(
base64::encode(encode::serialize(&unvault_tx)).to_string(),
"cHNidP8BAIkCAAAAAUeuD/NEqc88sk3DoBrKoVKjXbN2xW8Jr/4GO5q87JqJAQAAAAD9////AriGJgcAAAAAIgAgSOjPZes2prPdrcgiv+IG1sjXyTCc4KDr9+C9F+xk6LwwdQAAAAAAACIAIAjkMa8elv7dHUmYpDATWBtmMmpv9yyKFawMunvGQ1AMAAAAAAABASsADicHAAAAACIAIHXyaRd0yBZ3gxhGsCgiAOKIssWXELWPdDGD1JJVB9vFAQMEAQAAAAEFR1IhAlgt7b9E9GVk5djNsGdTbWDr40zR0YAc/1G7+desKJtDIQNHBN7LVbWqiP/R710GNmJIwTFOGWVRE2/xTquLukpJDlKuIgYCWC3tv0T0ZWTl2M2wZ1NtYOvjTNHRgBz/Ubv516wom0MI1n1/6QAAAAAiBgNHBN7LVbWqiP/R710GNmJIwTFOGWVRE2/xTquLukpJDghyqV8iAAAAAAAiAgICkzqxA36tCqSnhYxtSdZwXh+zvF9msAkYr3ufAOzVJgglHWAJAAAAACICAlgt7b9E9GVk5djNsGdTbWDr40zR0YAc/1G7+desKJtDCNZ9f+kAAAAAIgIDRwTey1W1qoj/0e9dBjZiSMExThllURNv8U6ri7pKSQ4IcqlfIgAAAAAAIgICUHL04HZXilyJ1B118e1Smr+S8c1qtja46Le7DzMCaUMI+93szQAAAAAA"
"cHNidP8BAIkCAAAAAUeuD/NEqc88sk3DoBrKoVKjXbN2xW8Jr/4GO5q87JqJAQAAAAD9////AriGJgcAAAAAIgAgSOjPZes2prPdrcgiv+IG1sjXyTCc4KDr9+C9F+xk6LwwdQAAAAAAACIAIAjkMa8elv7dHUmYpDATWBtmMmpv9yyKFawMunvGQ1AMAAAAAAABASsADicHAAAAACIAIHXyaRd0yBZ3gxhGsCgiAOKIssWXELWPdDGD1JJVB9vFAQVHUiECWC3tv0T0ZWTl2M2wZ1NtYOvjTNHRgBz/Ubv516wom0MhA0cE3stVtaqI/9HvXQY2YkjBMU4ZZVETb/FOq4u6SkkOUq4iBgJYLe2/RPRlZOXYzbBnU21g6+NM0dGAHP9Ru/nXrCibQwjWfX/pAAAAACIGA0cE3stVtaqI/9HvXQY2YkjBMU4ZZVETb/FOq4u6SkkOCHKpXyIAAAAAACICAgKTOrEDfq0KpKeFjG1J1nBeH7O8X2awCRive58A7NUmCCUdYAkAAAAAIgICWC3tv0T0ZWTl2M2wZ1NtYOvjTNHRgBz/Ubv516wom0MI1n1/6QAAAAAiAgNHBN7LVbWqiP/R710GNmJIwTFOGWVRE2/xTquLukpJDghyqV8iAAAAAAAiAgJQcvTgdleKXInUHXXx7VKav5LxzWq2Nrjot7sPMwJpQwj73ezNAAAAAAA="
);
}
}
22 changes: 14 additions & 8 deletions hwi/src/app/revault.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ pub trait RevaultHWI: HWI {
&mut self,
emergency_tx: &Psbt,
emergency_unvault_tx: &Psbt,
cancel_tx: &Psbt,
) -> Result<(Psbt, Psbt, Psbt), HWIError>;
cancel_tx: &[Psbt; 5],
) -> Result<(Psbt, Psbt, [Psbt; 5]), HWIError>;

/// Sign the unvault transaction required for delegation.
async fn sign_unvault_tx(&mut self, unvault_tx: &Psbt) -> Result<Psbt, HWIError>;
Expand All @@ -30,7 +30,7 @@ pub trait RevaultHWI: HWI {
async fn create_vaults(
&mut self,
deposits: &[(OutPoint, Amount, u32)],
) -> Result<Vec<(Psbt, Psbt, Psbt)>, HWIError>;
) -> Result<Vec<(Psbt, Psbt, [Psbt; 5])>, HWIError>;

/// Delegate a list of vaults by giving the utxos to an hardware wallet storing the
/// descriptors and deriving itself the unvault transactions.
Expand All @@ -52,12 +52,18 @@ impl<T: HWI + NoRevaultApp + Send> RevaultHWI for T {
&mut self,
emergency_tx: &Psbt,
emergency_unvault_tx: &Psbt,
cancel_tx: &Psbt,
) -> Result<(Psbt, Psbt, Psbt), HWIError> {
cancel_txs: &[Psbt; 5],
) -> Result<(Psbt, Psbt, [Psbt; 5]), HWIError> {
let emergency_tx = self.sign_tx(emergency_tx).await?;
let emergency_unvault_tx = self.sign_tx(emergency_unvault_tx).await?;
let cancel_tx = self.sign_tx(cancel_tx).await?;
Ok((emergency_tx, emergency_unvault_tx, cancel_tx))
let cancel_txs = [
self.sign_tx(&cancel_txs[0]).await?,
self.sign_tx(&cancel_txs[1]).await?,
self.sign_tx(&cancel_txs[2]).await?,
self.sign_tx(&cancel_txs[3]).await?,
self.sign_tx(&cancel_txs[4]).await?,
];
Ok((emergency_tx, emergency_unvault_tx, cancel_txs))
}

async fn sign_unvault_tx(&mut self, unvault_tx: &Psbt) -> Result<Psbt, HWIError> {
Expand All @@ -67,7 +73,7 @@ impl<T: HWI + NoRevaultApp + Send> RevaultHWI for T {
async fn create_vaults(
&mut self,
_deposits: &[(OutPoint, Amount, u32)],
) -> Result<Vec<(Psbt, Psbt, Psbt)>, HWIError> {
) -> Result<Vec<(Psbt, Psbt, [Psbt; 5])>, HWIError> {
Err(HWIError::UnimplementedMethod)
}

Expand Down
Loading