diff --git a/.msggen.json b/.msggen.json index 60de060a5..a9475fb0d 100644 --- a/.msggen.json +++ b/.msggen.json @@ -300,6 +300,30 @@ "DelInvoice.payment_hash": 6, "DelInvoice.status": 7 }, + "FundpsbtRequest": { + "FundPsbt.feerate": 2, + "FundPsbt.locktime": 6, + "FundPsbt.min_witness_weight": 7, + "FundPsbt.minconf": 4, + "FundPsbt.reserve": 5, + "FundPsbt.satoshi": 1, + "FundPsbt.startweight": 3 + }, + "FundpsbtReservations": { + "FundPsbt.reservations[].reserved": 4, + "FundPsbt.reservations[].reserved_to_block": 5, + "FundPsbt.reservations[].txid": 1, + "FundPsbt.reservations[].vout": 2, + "FundPsbt.reservations[].was_reserved": 3 + }, + "FundpsbtResponse": { + "FundPsbt.change_outnum": 5, + "FundPsbt.estimated_final_weight": 3, + "FundPsbt.excess_msat": 4, + "FundPsbt.feerate_per_kw": 2, + "FundPsbt.psbt": 1, + "FundPsbt.reservations[]": 6 + }, "GetinfoAddress": { "Getinfo.address[].address": 3, "Getinfo.address[].port": 2, @@ -717,6 +741,70 @@ "SendPay.route[].id": 2, "SendPay.route[].msatoshi": 1 }, + "SendpsbtRequest": { + "SendPsbt.psbt": 1 + }, + "SendpsbtResponse": { + "SendPsbt.tx": 1, + "SendPsbt.txid": 2 + }, + "SignpsbtRequest": { + "SignPsbt.psbt": 1, + "SignPsbt.signonly[]": 2 + }, + "SignpsbtResponse": { + "SignPsbt.signed_psbt": 1 + }, + "TxdiscardRequest": { + "TxDiscard.txid": 1 + }, + "TxdiscardResponse": { + "TxDiscard.txid": 2, + "TxDiscard.unsigned_tx": 1 + }, + "TxprepareRequest": { + "TxPrepare.feerate": 2, + "TxPrepare.minconf": 3, + "TxPrepare.outptus[]": 1, + "TxPrepare.utxos[]": 4 + }, + "TxprepareResponse": { + "TxPrepare.psbt": 1, + "TxPrepare.txid": 3, + "TxPrepare.unsigned_tx": 2 + }, + "TxsendRequest": { + "TxSend.txid": 1 + }, + "TxsendResponse": { + "TxSend.psbt": 1, + "TxSend.tx": 2, + "TxSend.txid": 3 + }, + "UtxopsbtRequest": { + "UtxoPsbt.feerate": 2, + "UtxoPsbt.locktime": 6, + "UtxoPsbt.min_witness_weight": 7, + "UtxoPsbt.reserve": 5, + "UtxoPsbt.satoshi": 1, + "UtxoPsbt.startweight": 3, + "UtxoPsbt.utxos[]": 4 + }, + "UtxopsbtReservations": { + "UtxoPsbt.reservations[].reserved": 4, + "UtxoPsbt.reservations[].reserved_to_block": 5, + "UtxoPsbt.reservations[].txid": 1, + "UtxoPsbt.reservations[].vout": 2, + "UtxoPsbt.reservations[].was_reserved": 3 + }, + "UtxopsbtResponse": { + "UtxoPsbt.change_outnum": 5, + "UtxoPsbt.estimated_final_weight": 3, + "UtxoPsbt.excess_msat": 4, + "UtxoPsbt.feerate_per_kw": 2, + "UtxoPsbt.psbt": 1, + "UtxoPsbt.reservations[]": 6 + }, "WaitanyinvoiceRequest": { "WaitAnyInvoice.lastpay_index": 1, "WaitAnyInvoice.timeout": 2 diff --git a/cln-grpc/proto/node.proto b/cln-grpc/proto/node.proto index a2023b1e6..f3a6dd23a 100644 --- a/cln-grpc/proto/node.proto +++ b/cln-grpc/proto/node.proto @@ -38,6 +38,13 @@ service Node { rpc NewAddr(NewaddrRequest) returns (NewaddrResponse) {} rpc Withdraw(WithdrawRequest) returns (WithdrawResponse) {} rpc KeySend(KeysendRequest) returns (KeysendResponse) {} + rpc FundPsbt(FundpsbtRequest) returns (FundpsbtResponse) {} + rpc SendPsbt(SendpsbtRequest) returns (SendpsbtResponse) {} + rpc SignPsbt(SignpsbtRequest) returns (SignpsbtResponse) {} + rpc UtxoPsbt(UtxopsbtRequest) returns (UtxopsbtResponse) {} + rpc TxDiscard(TxdiscardRequest) returns (TxdiscardResponse) {} + rpc TxPrepare(TxprepareRequest) returns (TxprepareResponse) {} + rpc TxSend(TxsendRequest) returns (TxsendResponse) {} } message GetinfoRequest { @@ -940,3 +947,106 @@ message KeysendResponse { optional string warning_partial_completion = 8; KeysendStatus status = 9; } + +message FundpsbtRequest { + Amount satoshi = 1; + Feerate feerate = 2; + sint64 startweight = 3; + optional sint64 minconf = 4; + optional sint64 reserve = 5; + optional sint64 locktime = 6; + optional uint32 min_witness_weight = 7; +} + +message FundpsbtResponse { + string psbt = 1; + uint32 feerate_per_kw = 2; + uint32 estimated_final_weight = 3; + Amount excess_msat = 4; + optional uint32 change_outnum = 5; + repeated FundpsbtReservations reservations = 6; +} + +message FundpsbtReservations { + bytes txid = 1; + uint32 vout = 2; + bool was_reserved = 3; + bool reserved = 4; + uint32 reserved_to_block = 5; +} + +message SendpsbtRequest { + string psbt = 1; +} + +message SendpsbtResponse { + bytes tx = 1; + bytes txid = 2; +} + +message SignpsbtRequest { + string psbt = 1; +} + +message SignpsbtResponse { + string signed_psbt = 1; +} + +message UtxopsbtRequest { + Amount satoshi = 1; + Feerate feerate = 2; + sint64 startweight = 3; + repeated Utxo utxos = 4; + optional sint64 reserve = 5; + optional sint64 locktime = 6; + optional uint32 min_witness_weight = 7; +} + +message UtxopsbtResponse { + string psbt = 1; + uint32 feerate_per_kw = 2; + uint32 estimated_final_weight = 3; + Amount excess_msat = 4; + optional uint32 change_outnum = 5; + repeated UtxopsbtReservations reservations = 6; +} + +message UtxopsbtReservations { + bytes txid = 1; + uint32 vout = 2; + bool was_reserved = 3; + bool reserved = 4; + uint32 reserved_to_block = 5; +} + +message TxdiscardRequest { + bytes txid = 1; +} + +message TxdiscardResponse { + bytes unsigned_tx = 1; + bytes txid = 2; +} + +message TxprepareRequest { + repeated OutputDesc outptus = 1; + optional Feerate feerate = 2; + optional uint32 minconf = 3; + repeated Utxo utxos = 4; +} + +message TxprepareResponse { + string psbt = 1; + bytes unsigned_tx = 2; + bytes txid = 3; +} + +message TxsendRequest { + bytes txid = 1; +} + +message TxsendResponse { + string psbt = 1; + bytes tx = 2; + bytes txid = 3; +} diff --git a/cln-grpc/src/convert.rs b/cln-grpc/src/convert.rs index 907cac989..61b09b814 100644 --- a/cln-grpc/src/convert.rs +++ b/cln-grpc/src/convert.rs @@ -725,6 +725,111 @@ impl From<&responses::KeysendResponse> for pb::KeysendResponse { } } +#[allow(unused_variables)] +impl From<&responses::FundpsbtReservations> for pb::FundpsbtReservations { + fn from(c: &responses::FundpsbtReservations) -> Self { + Self { + txid: hex::decode(&c.txid).unwrap(), // Rule #2 for type txid + vout: c.vout.clone(), // Rule #2 for type u32 + was_reserved: c.was_reserved.clone(), // Rule #2 for type boolean + reserved: c.reserved.clone(), // Rule #2 for type boolean + reserved_to_block: c.reserved_to_block.clone(), // Rule #2 for type u32 + } + } +} + +#[allow(unused_variables)] +impl From<&responses::FundpsbtResponse> for pb::FundpsbtResponse { + fn from(c: &responses::FundpsbtResponse) -> Self { + Self { + psbt: c.psbt.clone(), // Rule #2 for type string + feerate_per_kw: c.feerate_per_kw.clone(), // Rule #2 for type u32 + estimated_final_weight: c.estimated_final_weight.clone(), // Rule #2 for type u32 + excess_msat: Some(c.excess_msat.into()), // Rule #2 for type msat + change_outnum: c.change_outnum.clone(), // Rule #2 for type u32? + reservations: c.reservations.iter().map(|i| i.into()).collect(), + } + } +} + +#[allow(unused_variables)] +impl From<&responses::SendpsbtResponse> for pb::SendpsbtResponse { + fn from(c: &responses::SendpsbtResponse) -> Self { + Self { + tx: hex::decode(&c.tx).unwrap(), // Rule #2 for type hex + txid: hex::decode(&c.txid).unwrap(), // Rule #2 for type txid + } + } +} + +#[allow(unused_variables)] +impl From<&responses::SignpsbtResponse> for pb::SignpsbtResponse { + fn from(c: &responses::SignpsbtResponse) -> Self { + Self { + signed_psbt: c.signed_psbt.clone(), // Rule #2 for type string + } + } +} + +#[allow(unused_variables)] +impl From<&responses::UtxopsbtReservations> for pb::UtxopsbtReservations { + fn from(c: &responses::UtxopsbtReservations) -> Self { + Self { + txid: hex::decode(&c.txid).unwrap(), // Rule #2 for type txid + vout: c.vout.clone(), // Rule #2 for type u32 + was_reserved: c.was_reserved.clone(), // Rule #2 for type boolean + reserved: c.reserved.clone(), // Rule #2 for type boolean + reserved_to_block: c.reserved_to_block.clone(), // Rule #2 for type u32 + } + } +} + +#[allow(unused_variables)] +impl From<&responses::UtxopsbtResponse> for pb::UtxopsbtResponse { + fn from(c: &responses::UtxopsbtResponse) -> Self { + Self { + psbt: c.psbt.clone(), // Rule #2 for type string + feerate_per_kw: c.feerate_per_kw.clone(), // Rule #2 for type u32 + estimated_final_weight: c.estimated_final_weight.clone(), // Rule #2 for type u32 + excess_msat: Some(c.excess_msat.into()), // Rule #2 for type msat + change_outnum: c.change_outnum.clone(), // Rule #2 for type u32? + reservations: c.reservations.iter().map(|i| i.into()).collect(), + } + } +} + +#[allow(unused_variables)] +impl From<&responses::TxdiscardResponse> for pb::TxdiscardResponse { + fn from(c: &responses::TxdiscardResponse) -> Self { + Self { + unsigned_tx: hex::decode(&c.unsigned_tx).unwrap(), // Rule #2 for type hex + txid: hex::decode(&c.txid).unwrap(), // Rule #2 for type txid + } + } +} + +#[allow(unused_variables)] +impl From<&responses::TxprepareResponse> for pb::TxprepareResponse { + fn from(c: &responses::TxprepareResponse) -> Self { + Self { + psbt: c.psbt.clone(), // Rule #2 for type string + unsigned_tx: hex::decode(&c.unsigned_tx).unwrap(), // Rule #2 for type hex + txid: hex::decode(&c.txid).unwrap(), // Rule #2 for type txid + } + } +} + +#[allow(unused_variables)] +impl From<&responses::TxsendResponse> for pb::TxsendResponse { + fn from(c: &responses::TxsendResponse) -> Self { + Self { + psbt: c.psbt.clone(), // Rule #2 for type string + tx: hex::decode(&c.tx).unwrap(), // Rule #2 for type hex + txid: hex::decode(&c.txid).unwrap(), // Rule #2 for type txid + } + } +} + #[allow(unused_variables)] impl From<&pb::GetinfoRequest> for requests::GetinfoRequest { fn from(c: &pb::GetinfoRequest) -> Self { @@ -1074,3 +1179,81 @@ impl From<&pb::KeysendRequest> for requests::KeysendRequest { } } +#[allow(unused_variables)] +impl From<&pb::FundpsbtRequest> for requests::FundpsbtRequest { + fn from(c: &pb::FundpsbtRequest) -> Self { + Self { + satoshi: c.satoshi.as_ref().unwrap().into(), // Rule #1 for type msat + feerate: c.feerate.as_ref().unwrap().into(), // Rule #1 for type feerate + startweight: c.startweight.clone(), // Rule #1 for type number + minconf: c.minconf.clone(), // Rule #1 for type number? + reserve: c.reserve.clone(), // Rule #1 for type number? + locktime: c.locktime.clone(), // Rule #1 for type number? + min_witness_weight: c.min_witness_weight.clone(), // Rule #1 for type u32? + } + } +} + +#[allow(unused_variables)] +impl From<&pb::SendpsbtRequest> for requests::SendpsbtRequest { + fn from(c: &pb::SendpsbtRequest) -> Self { + Self { + psbt: c.psbt.clone(), // Rule #1 for type string + } + } +} + +#[allow(unused_variables)] +impl From<&pb::SignpsbtRequest> for requests::SignpsbtRequest { + fn from(c: &pb::SignpsbtRequest) -> Self { + Self { + psbt: c.psbt.clone(), // Rule #1 for type string + } + } +} + +#[allow(unused_variables)] +impl From<&pb::UtxopsbtRequest> for requests::UtxopsbtRequest { + fn from(c: &pb::UtxopsbtRequest) -> Self { + Self { + satoshi: c.satoshi.as_ref().unwrap().into(), // Rule #1 for type msat + feerate: c.feerate.as_ref().unwrap().into(), // Rule #1 for type feerate + startweight: c.startweight.clone(), // Rule #1 for type number + utxos: c.utxos.iter().map(|s| s.into()).collect(), + reserve: c.reserve.clone(), // Rule #1 for type number? + locktime: c.locktime.clone(), // Rule #1 for type number? + min_witness_weight: c.min_witness_weight.clone(), // Rule #1 for type u32? + } + } +} + +#[allow(unused_variables)] +impl From<&pb::TxdiscardRequest> for requests::TxdiscardRequest { + fn from(c: &pb::TxdiscardRequest) -> Self { + Self { + txid: hex::encode(&c.txid), // Rule #1 for type hex + } + } +} + +#[allow(unused_variables)] +impl From<&pb::TxprepareRequest> for requests::TxprepareRequest { + fn from(c: &pb::TxprepareRequest) -> Self { + Self { + outptus: c.outptus.iter().map(|s| s.into()).collect(), + feerate: c.feerate.as_ref().map(|a| a.into()), // Rule #1 for type feerate? + minconf: c.minconf.clone(), // Rule #1 for type u32? + utxos: c.utxos.iter().map(|s| s.into()).collect(), + } + } +} + +#[allow(unused_variables)] +impl From<&pb::TxsendRequest> for requests::TxsendRequest { + fn from(c: &pb::TxsendRequest) -> Self { + Self { + txid: hex::encode(&c.txid), // Rule #1 for type hex + } + } +} + diff --git a/cln-grpc/src/server.rs b/cln-grpc/src/server.rs index c0039c677..66e40d139 100644 --- a/cln-grpc/src/server.rs +++ b/cln-grpc/src/server.rs @@ -926,4 +926,214 @@ async fn key_send( } +async fn fund_psbt( + &self, + request: tonic::Request, +) -> Result, tonic::Status> { + let req = request.into_inner(); + let req: requests::FundpsbtRequest = (&req).into(); + debug!("Client asked for getinfo"); + let mut rpc = ClnRpc::new(&self.rpc_path) + .await + .map_err(|e| Status::new(Code::Internal, e.to_string()))?; + let result = rpc.call(Request::FundPsbt(req)) + .await + .map_err(|e| Status::new( + Code::Unknown, + format!("Error calling method FundPsbt: {:?}", e)))?; + match result { + Response::FundPsbt(r) => Ok( + tonic::Response::new((&r).into()) + ), + r => Err(Status::new( + Code::Internal, + format!( + "Unexpected result {:?} to method call FundPsbt", + r + ) + )), + } + +} + +async fn send_psbt( + &self, + request: tonic::Request, +) -> Result, tonic::Status> { + let req = request.into_inner(); + let req: requests::SendpsbtRequest = (&req).into(); + debug!("Client asked for getinfo"); + let mut rpc = ClnRpc::new(&self.rpc_path) + .await + .map_err(|e| Status::new(Code::Internal, e.to_string()))?; + let result = rpc.call(Request::SendPsbt(req)) + .await + .map_err(|e| Status::new( + Code::Unknown, + format!("Error calling method SendPsbt: {:?}", e)))?; + match result { + Response::SendPsbt(r) => Ok( + tonic::Response::new((&r).into()) + ), + r => Err(Status::new( + Code::Internal, + format!( + "Unexpected result {:?} to method call SendPsbt", + r + ) + )), + } + +} + +async fn sign_psbt( + &self, + request: tonic::Request, +) -> Result, tonic::Status> { + let req = request.into_inner(); + let req: requests::SignpsbtRequest = (&req).into(); + debug!("Client asked for getinfo"); + let mut rpc = ClnRpc::new(&self.rpc_path) + .await + .map_err(|e| Status::new(Code::Internal, e.to_string()))?; + let result = rpc.call(Request::SignPsbt(req)) + .await + .map_err(|e| Status::new( + Code::Unknown, + format!("Error calling method SignPsbt: {:?}", e)))?; + match result { + Response::SignPsbt(r) => Ok( + tonic::Response::new((&r).into()) + ), + r => Err(Status::new( + Code::Internal, + format!( + "Unexpected result {:?} to method call SignPsbt", + r + ) + )), + } + +} + +async fn utxo_psbt( + &self, + request: tonic::Request, +) -> Result, tonic::Status> { + let req = request.into_inner(); + let req: requests::UtxopsbtRequest = (&req).into(); + debug!("Client asked for getinfo"); + let mut rpc = ClnRpc::new(&self.rpc_path) + .await + .map_err(|e| Status::new(Code::Internal, e.to_string()))?; + let result = rpc.call(Request::UtxoPsbt(req)) + .await + .map_err(|e| Status::new( + Code::Unknown, + format!("Error calling method UtxoPsbt: {:?}", e)))?; + match result { + Response::UtxoPsbt(r) => Ok( + tonic::Response::new((&r).into()) + ), + r => Err(Status::new( + Code::Internal, + format!( + "Unexpected result {:?} to method call UtxoPsbt", + r + ) + )), + } + +} + +async fn tx_discard( + &self, + request: tonic::Request, +) -> Result, tonic::Status> { + let req = request.into_inner(); + let req: requests::TxdiscardRequest = (&req).into(); + debug!("Client asked for getinfo"); + let mut rpc = ClnRpc::new(&self.rpc_path) + .await + .map_err(|e| Status::new(Code::Internal, e.to_string()))?; + let result = rpc.call(Request::TxDiscard(req)) + .await + .map_err(|e| Status::new( + Code::Unknown, + format!("Error calling method TxDiscard: {:?}", e)))?; + match result { + Response::TxDiscard(r) => Ok( + tonic::Response::new((&r).into()) + ), + r => Err(Status::new( + Code::Internal, + format!( + "Unexpected result {:?} to method call TxDiscard", + r + ) + )), + } + +} + +async fn tx_prepare( + &self, + request: tonic::Request, +) -> Result, tonic::Status> { + let req = request.into_inner(); + let req: requests::TxprepareRequest = (&req).into(); + debug!("Client asked for getinfo"); + let mut rpc = ClnRpc::new(&self.rpc_path) + .await + .map_err(|e| Status::new(Code::Internal, e.to_string()))?; + let result = rpc.call(Request::TxPrepare(req)) + .await + .map_err(|e| Status::new( + Code::Unknown, + format!("Error calling method TxPrepare: {:?}", e)))?; + match result { + Response::TxPrepare(r) => Ok( + tonic::Response::new((&r).into()) + ), + r => Err(Status::new( + Code::Internal, + format!( + "Unexpected result {:?} to method call TxPrepare", + r + ) + )), + } + +} + +async fn tx_send( + &self, + request: tonic::Request, +) -> Result, tonic::Status> { + let req = request.into_inner(); + let req: requests::TxsendRequest = (&req).into(); + debug!("Client asked for getinfo"); + let mut rpc = ClnRpc::new(&self.rpc_path) + .await + .map_err(|e| Status::new(Code::Internal, e.to_string()))?; + let result = rpc.call(Request::TxSend(req)) + .await + .map_err(|e| Status::new( + Code::Unknown, + format!("Error calling method TxSend: {:?}", e)))?; + match result { + Response::TxSend(r) => Ok( + tonic::Response::new((&r).into()) + ), + r => Err(Status::new( + Code::Internal, + format!( + "Unexpected result {:?} to method call TxSend", + r + ) + )), + } + +} + } diff --git a/cln-rpc/src/model.rs b/cln-rpc/src/model.rs index 620b30e5e..9d767e310 100644 --- a/cln-rpc/src/model.rs +++ b/cln-rpc/src/model.rs @@ -46,6 +46,13 @@ pub enum Request { NewAddr(requests::NewaddrRequest), Withdraw(requests::WithdrawRequest), KeySend(requests::KeysendRequest), + FundPsbt(requests::FundpsbtRequest), + SendPsbt(requests::SendpsbtRequest), + SignPsbt(requests::SignpsbtRequest), + UtxoPsbt(requests::UtxopsbtRequest), + TxDiscard(requests::TxdiscardRequest), + TxPrepare(requests::TxprepareRequest), + TxSend(requests::TxsendRequest), } #[derive(Clone, Debug, Serialize, Deserialize)] @@ -82,6 +89,13 @@ pub enum Response { NewAddr(responses::NewaddrResponse), Withdraw(responses::WithdrawResponse), KeySend(responses::KeysendResponse), + FundPsbt(responses::FundpsbtResponse), + SendPsbt(responses::SendpsbtResponse), + SignPsbt(responses::SignpsbtResponse), + UtxoPsbt(responses::UtxopsbtResponse), + TxDiscard(responses::TxdiscardResponse), + TxPrepare(responses::TxprepareResponse), + TxSend(responses::TxsendResponse), } pub mod requests { @@ -490,6 +504,78 @@ pub mod requests { pub exemptfee: Option, } + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct FundpsbtRequest { + #[serde(alias = "satoshi")] + pub satoshi: Amount, + #[serde(alias = "feerate")] + pub feerate: Feerate, + #[serde(alias = "startweight")] + pub startweight: i64, + #[serde(alias = "minconf", skip_serializing_if = "Option::is_none")] + pub minconf: Option, + #[serde(alias = "reserve", skip_serializing_if = "Option::is_none")] + pub reserve: Option, + #[serde(alias = "locktime", skip_serializing_if = "Option::is_none")] + pub locktime: Option, + #[serde(alias = "min_witness_weight", skip_serializing_if = "Option::is_none")] + pub min_witness_weight: Option, + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct SendpsbtRequest { + #[serde(alias = "psbt")] + pub psbt: String, + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct SignpsbtRequest { + #[serde(alias = "psbt")] + pub psbt: String, + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct UtxopsbtRequest { + #[serde(alias = "satoshi")] + pub satoshi: Amount, + #[serde(alias = "feerate")] + pub feerate: Feerate, + #[serde(alias = "startweight")] + pub startweight: i64, + #[serde(alias = "utxos")] + pub utxos: Vec, + #[serde(alias = "reserve", skip_serializing_if = "Option::is_none")] + pub reserve: Option, + #[serde(alias = "locktime", skip_serializing_if = "Option::is_none")] + pub locktime: Option, + #[serde(alias = "min_witness_weight", skip_serializing_if = "Option::is_none")] + pub min_witness_weight: Option, + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct TxdiscardRequest { + #[serde(alias = "txid")] + pub txid: String, + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct TxprepareRequest { + #[serde(alias = "outptus")] + pub outptus: Vec, + #[serde(alias = "feerate", skip_serializing_if = "Option::is_none")] + pub feerate: Option, + #[serde(alias = "minconf", skip_serializing_if = "Option::is_none")] + pub minconf: Option, + #[serde(alias = "utxos")] + pub utxos: Vec, + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct TxsendRequest { + #[serde(alias = "txid")] + pub txid: String, + } + } @@ -1987,5 +2073,107 @@ pub mod responses { pub status: KeysendStatus, } + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct FundpsbtReservations { + #[serde(alias = "txid")] + pub txid: String, + #[serde(alias = "vout")] + pub vout: u32, + #[serde(alias = "was_reserved")] + pub was_reserved: bool, + #[serde(alias = "reserved")] + pub reserved: bool, + #[serde(alias = "reserved_to_block")] + pub reserved_to_block: u32, + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct FundpsbtResponse { + #[serde(alias = "psbt")] + pub psbt: String, + #[serde(alias = "feerate_per_kw")] + pub feerate_per_kw: u32, + #[serde(alias = "estimated_final_weight")] + pub estimated_final_weight: u32, + #[serde(alias = "excess_msat")] + pub excess_msat: Amount, + #[serde(alias = "change_outnum", skip_serializing_if = "Option::is_none")] + pub change_outnum: Option, + #[serde(alias = "reservations")] + pub reservations: Vec, + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct SendpsbtResponse { + #[serde(alias = "tx")] + pub tx: String, + #[serde(alias = "txid")] + pub txid: String, + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct SignpsbtResponse { + #[serde(alias = "signed_psbt")] + pub signed_psbt: String, + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct UtxopsbtReservations { + #[serde(alias = "txid")] + pub txid: String, + #[serde(alias = "vout")] + pub vout: u32, + #[serde(alias = "was_reserved")] + pub was_reserved: bool, + #[serde(alias = "reserved")] + pub reserved: bool, + #[serde(alias = "reserved_to_block")] + pub reserved_to_block: u32, + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct UtxopsbtResponse { + #[serde(alias = "psbt")] + pub psbt: String, + #[serde(alias = "feerate_per_kw")] + pub feerate_per_kw: u32, + #[serde(alias = "estimated_final_weight")] + pub estimated_final_weight: u32, + #[serde(alias = "excess_msat")] + pub excess_msat: Amount, + #[serde(alias = "change_outnum", skip_serializing_if = "Option::is_none")] + pub change_outnum: Option, + #[serde(alias = "reservations")] + pub reservations: Vec, + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct TxdiscardResponse { + #[serde(alias = "unsigned_tx")] + pub unsigned_tx: String, + #[serde(alias = "txid")] + pub txid: String, + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct TxprepareResponse { + #[serde(alias = "psbt")] + pub psbt: String, + #[serde(alias = "unsigned_tx")] + pub unsigned_tx: String, + #[serde(alias = "txid")] + pub txid: String, + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct TxsendResponse { + #[serde(alias = "psbt")] + pub psbt: String, + #[serde(alias = "tx")] + pub tx: String, + #[serde(alias = "txid")] + pub txid: String, + } + } diff --git a/contrib/msggen/msggen/__main__.py b/contrib/msggen/msggen/__main__.py index 766aa3680..a864940f0 100644 --- a/contrib/msggen/msggen/__main__.py +++ b/contrib/msggen/msggen/__main__.py @@ -70,6 +70,13 @@ def load_jsonrpc_service(): "NewAddr", "Withdraw", "KeySend", + "FundPsbt", + "SendPsbt", + "SignPsbt", + "UtxoPsbt", + "TxDiscard", + "TxPrepare", + "TxSend", # "decodepay", # "decode", # "delpay", @@ -110,15 +117,11 @@ def load_jsonrpc_service(): # "setchannelfee", # "signmessage", # "signpsbt", - # "txdiscard", - # "txprepare", - # "txsend", # "unreserveinputs", # "waitblockheight", # "ListConfigs", # "check", # No point in mapping this one # "Stop", # Breaks a core assumption (root is an object) can't map unless we change this - # "UtxoPsbt", # Breaks since the utxos array has dynamic keys which we can't map as is # "notifications", # No point in mapping this # "help", ] diff --git a/contrib/msggen/msggen/grpc.py b/contrib/msggen/msggen/grpc.py index 0e093d19f..e29e8312a 100644 --- a/contrib/msggen/msggen/grpc.py +++ b/contrib/msggen/msggen/grpc.py @@ -395,6 +395,7 @@ class GrpcUnconverterGenerator(GrpcConverterGenerator): 'pubkey?': f'c.{name}.clone().map(|v| hex::encode(v))', 'msat': f'c.{name}.as_ref().unwrap().into()', 'msat?': f'c.{name}.as_ref().map(|a| a.into())', + 'feerate': f'c.{name}.as_ref().unwrap().into()', 'feerate?': f'c.{name}.as_ref().map(|a| a.into())', }.get( typ, diff --git a/doc/schemas/fundpsbt.request.json b/doc/schemas/fundpsbt.request.json new file mode 100644 index 000000000..a23d1935a --- /dev/null +++ b/doc/schemas/fundpsbt.request.json @@ -0,0 +1,36 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "required": [ + "satoshi", + "feerate", + "startweight" + ], + "properties": { + "satoshi": { + "type": "msat" + }, + "feerate": { + "type": "feerate" + }, + "startweight": { + "type": "number" + }, + "minconf": { + "type": "number" + }, + "reserve": { + "type": "number", + "description": "reserve is a number: if non-zero number then reserveinputs is called (successfully, with exclusive true) on the returned PSBT for this number of blocks (default: 72)." + }, + "locktime": { + "type": "number" + }, + "min_witness_weight": { + "type": "u32" + }, + "excess_as_change": { + "type": "bool" + } + } +} diff --git a/doc/schemas/sendpsbt.request.json b/doc/schemas/sendpsbt.request.json new file mode 100644 index 000000000..f4f4ea988 --- /dev/null +++ b/doc/schemas/sendpsbt.request.json @@ -0,0 +1,15 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "required": [ + "psbt" + ], + "properties": { + "psbt": { + "type": "string" + }, + "reserve": { + "type": "bool" + } + } +} diff --git a/doc/schemas/signpsbt.request.json b/doc/schemas/signpsbt.request.json new file mode 100644 index 000000000..1c5ff0383 --- /dev/null +++ b/doc/schemas/signpsbt.request.json @@ -0,0 +1,12 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "required": [ + "psbt" + ], + "properties": { + "psbt": { + "type": "string" + } + } +} diff --git a/doc/schemas/txdiscard.request.json b/doc/schemas/txdiscard.request.json new file mode 100644 index 000000000..e69bf747d --- /dev/null +++ b/doc/schemas/txdiscard.request.json @@ -0,0 +1,12 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "required": [ + "txid" + ], + "properties": { + "txid": { + "type": "hex" + } + } +} diff --git a/doc/schemas/txprepare.request.json b/doc/schemas/txprepare.request.json new file mode 100644 index 000000000..0a161b327 --- /dev/null +++ b/doc/schemas/txprepare.request.json @@ -0,0 +1,27 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "required": [ + "outputs" + ], + "properties": { + "outptus": { + "type": "array", + "items": { + "type": "OutputDesc" + } + }, + "feerate": { + "type": "feerate" + }, + "minconf": { + "type": "u32" + }, + "utxos": { + "type": "array", + "items": { + "type": "utxo" + } + } + } +} diff --git a/doc/schemas/txsend.request.json b/doc/schemas/txsend.request.json new file mode 100644 index 000000000..e69bf747d --- /dev/null +++ b/doc/schemas/txsend.request.json @@ -0,0 +1,12 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "required": [ + "txid" + ], + "properties": { + "txid": { + "type": "hex" + } + } +} diff --git a/doc/schemas/utxopsbt.request.json b/doc/schemas/utxopsbt.request.json new file mode 100644 index 000000000..9d8541d09 --- /dev/null +++ b/doc/schemas/utxopsbt.request.json @@ -0,0 +1,43 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "required": [ + "satoshi", + "feerate", + "startweight", + "utxos" + ], + "properties": { + "satoshi": { + "type": "msat" + }, + "feerate": { + "type": "feerate" + }, + "startweight": { + "type": "number" + }, + "utxos": { + "type": "array", + "items": { + "type": "utxo" + } + }, + "reserve": { + "type": "number", + "description": "reserve is a number: if non-zero number then reserveinputs is called (successfully, with exclusive true) on the returned PSBT for this number of blocks (default: 72)." + }, + "reservedok": { + "type": "bool" + }, + "locktime": { + "type": "number" + }, + "min_witness_weight": { + "type": "u32" + }, + "excess_as_change": { + "type": "bool" + } + } +}