Skip to content

Commit

Permalink
Return signed PSBT from ord wallet send (#3093)
Browse files Browse the repository at this point in the history
  • Loading branch information
raphjaph committed Feb 13, 2024
1 parent 989b763 commit 14116a4
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 26 deletions.
7 changes: 7 additions & 0 deletions crates/test-bitcoincore-rpc/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,4 +185,11 @@ pub trait Api {
sighash_type: Option<()>,
bip32derivs: Option<bool>,
) -> Result<WalletProcessPsbtResult, jsonrpc_core::Error>;

#[rpc(name = "finalizepsbt")]
fn finalize_psbt(
&self,
psbt: String,
extract: Option<bool>,
) -> Result<FinalizePsbtResult, jsonrpc_core::Error>;
}
17 changes: 9 additions & 8 deletions crates/test-bitcoincore-rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,15 @@ use {
Wtxid,
},
bitcoincore_rpc::json::{
Bip125Replaceable, CreateRawTransactionInput, Descriptor, EstimateMode, GetBalancesResult,
GetBalancesResultEntry, GetBlockHeaderResult, GetBlockchainInfoResult, GetDescriptorInfoResult,
GetNetworkInfoResult, GetRawTransactionResult, GetRawTransactionResultVout,
GetRawTransactionResultVoutScriptPubKey, GetTransactionResult, GetTransactionResultDetail,
GetTransactionResultDetailCategory, GetTxOutResult, GetWalletInfoResult, ImportDescriptors,
ImportMultiResult, ListDescriptorsResult, ListTransactionResult, ListUnspentResultEntry,
ListWalletDirItem, ListWalletDirResult, LoadWalletResult, SignRawTransactionInput,
SignRawTransactionResult, Timestamp, WalletProcessPsbtResult, WalletTxInfo,
Bip125Replaceable, CreateRawTransactionInput, Descriptor, EstimateMode, FinalizePsbtResult,
GetBalancesResult, GetBalancesResultEntry, GetBlockHeaderResult, GetBlockchainInfoResult,
GetDescriptorInfoResult, GetNetworkInfoResult, GetRawTransactionResult,
GetRawTransactionResultVout, GetRawTransactionResultVoutScriptPubKey, GetTransactionResult,
GetTransactionResultDetail, GetTransactionResultDetailCategory, GetTxOutResult,
GetWalletInfoResult, ImportDescriptors, ImportMultiResult, ListDescriptorsResult,
ListTransactionResult, ListUnspentResultEntry, ListWalletDirItem, ListWalletDirResult,
LoadWalletResult, SignRawTransactionInput, SignRawTransactionResult, Timestamp,
WalletProcessPsbtResult, WalletTxInfo,
},
jsonrpc_core::{IoHandler, Value},
jsonrpc_http_server::{CloseHandle, ServerBuilder},
Expand Down
37 changes: 34 additions & 3 deletions crates/test-bitcoincore-rpc/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -791,9 +791,6 @@ impl Api for Server {
sighash_type: Option<()>,
bip32derivs: Option<bool>,
) -> Result<WalletProcessPsbtResult, jsonrpc_core::Error> {
// we only call this function in `ord wallet send --dry-run` in which case
// we don't want to sign the PSBT, so we assert that sign is false.
assert_eq!(sign, Some(false));
assert!(sighash_type.is_none());
assert!(bip32derivs.is_none());

Expand All @@ -816,9 +813,43 @@ impl Api for Server {
);
}

if let Some(sign) = sign {
if sign {
for input in psbt.inputs.iter_mut() {
input.final_script_witness = Some(Witness::from_slice(&[&[0; 64]]));
}
}
}

Ok(WalletProcessPsbtResult {
psbt: base64::engine::general_purpose::STANDARD.encode(psbt.serialize()),
complete: false,
})
}

fn finalize_psbt(
&self,
psbt: String,
_extract: Option<bool>,
) -> Result<FinalizePsbtResult, jsonrpc_core::Error> {
let mut transaction = Psbt::deserialize(
&base64::engine::general_purpose::STANDARD
.decode(psbt)
.unwrap(),
)
.unwrap()
.unsigned_tx;

for input in &mut transaction.input {
if input.witness.is_empty() {
input.witness = Witness::from_slice(&[&[0; 64]]);
}
}

Ok(FinalizePsbtResult {
psbt: None,
hex: Some(serialize(&transaction)),
complete: true,
})
}
}
41 changes: 26 additions & 15 deletions src/subcommand/wallet/send.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,26 +67,37 @@ impl Send {
let bitcoin_client = wallet.bitcoin_client()?;
let unspent_outputs = wallet.get_unspent_outputs()?;

let txid = if self.dry_run {
unsigned_transaction.txid()
let (txid, psbt) = if self.dry_run {
let psbt = bitcoin_client
.wallet_process_psbt(
&base64::engine::general_purpose::STANDARD
.encode(Psbt::from_unsigned_tx(unsigned_transaction.clone())?.serialize()),
Some(false),
None,
None,
)?
.psbt;

(unsigned_transaction.txid(), psbt)
} else {
let psbt = bitcoin_client
.wallet_process_psbt(
&base64::engine::general_purpose::STANDARD
.encode(Psbt::from_unsigned_tx(unsigned_transaction.clone())?.serialize()),
Some(true),
None,
None,
)?
.psbt;

let signed_tx = bitcoin_client
.sign_raw_transaction_with_wallet(&unsigned_transaction.clone(), None, None)?
.hex;
.finalize_psbt(&psbt, None)?
.hex
.ok_or_else(|| anyhow!("unable to sign transaction"))?;

bitcoin_client.send_raw_transaction(&signed_tx)?
(bitcoin_client.send_raw_transaction(&signed_tx)?, psbt)
};

let psbt = bitcoin_client
.wallet_process_psbt(
&base64::engine::general_purpose::STANDARD
.encode(Psbt::from_unsigned_tx(unsigned_transaction.clone())?.serialize()),
Some(false),
None,
None,
)?
.psbt;

Ok(Some(Box::new(Output {
txid,
psbt,
Expand Down

0 comments on commit 14116a4

Please sign in to comment.