From 8be6fb3c0c2d16ebdaf07bfe7394817afd725232 Mon Sep 17 00:00:00 2001 From: smartgoo Date: Sun, 3 May 2026 19:22:21 -0400 Subject: [PATCH] add covenant binding support to payment output --- python/kaspa/__init__.pyi | 3 +++ src/consensus/client/covenant.rs | 8 ++++++++ src/wallet/core/tx/payment.rs | 31 +++++++++++++++++++++++++++---- 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/python/kaspa/__init__.pyi b/python/kaspa/__init__.pyi index 5d62ad84..da3ccd7d 100644 --- a/python/kaspa/__init__.pyi +++ b/python/kaspa/__init__.pyi @@ -376,6 +376,7 @@ class CovenantBinding: @covenant_id.setter def covenant_id(self, value: Hash) -> None: ... def __new__(cls, authorizing_input: builtins.int, covenant_id: Hash) -> CovenantBinding: ... + def __repr__(self) -> builtins.str: ... @typing.final class DerivationPath: @@ -1015,6 +1016,8 @@ class PaymentOutput: address: The address to send this output to. amount: The amount, in sompi, to send on this output. """ + @staticmethod + def with_covenant(address: Address, amount: builtins.int, covenant: CovenantBinding) -> PaymentOutput: ... def __eq__(self, other: PaymentOutput) -> builtins.bool: r""" Equality comparison. diff --git a/src/consensus/client/covenant.rs b/src/consensus/client/covenant.rs index 6e75b1c8..8cf41f0e 100644 --- a/src/consensus/client/covenant.rs +++ b/src/consensus/client/covenant.rs @@ -41,6 +41,14 @@ impl PyCovenantBinding { pub fn set_covenant_id(&mut self, value: PyHash) { self.0.set_covenant_id(value.into()); } + + pub fn __repr__(&self) -> String { + format!( + "CovenantBinding(authorizing_input={}, covenant_id={})", + self.0.get_authorizing_input(), + self.get_covenant_id().__repr__(), + ) + } } impl From for PyCovenantBinding { diff --git a/src/wallet/core/tx/payment.rs b/src/wallet/core/tx/payment.rs index 6bdc05f0..4f2dbc36 100644 --- a/src/wallet/core/tx/payment.rs +++ b/src/wallet/core/tx/payment.rs @@ -1,3 +1,4 @@ +use kaspa_consensus_client::CovenantBinding; use kaspa_wallet_core::tx::payment::PaymentOutput; use pyo3::{ exceptions::{PyException, PyKeyError}, @@ -6,7 +7,7 @@ use pyo3::{ }; use pyo3_stub_gen::derive::{gen_stub_pyclass, gen_stub_pymethods}; -use crate::address::PyAddress; +use crate::{address::PyAddress, consensus::client::covenant::PyCovenantBinding}; /// A payment destination with address and amount. /// @@ -30,6 +31,15 @@ impl PyPaymentOutput { Self(PaymentOutput::new(address.into(), amount)) } + #[staticmethod] + fn with_covenant(address: PyAddress, amount: u64, covenant: PyCovenantBinding) -> Self { + Self(PaymentOutput::with_covenant( + address.into(), + amount, + covenant.into(), + )) + } + /// Equality comparison. /// /// Args: @@ -51,9 +61,13 @@ impl PyPaymentOutput { /// str: The PaymentOutput as a repr string. fn __repr__(&self) -> String { format!( - "PaymentOutput(address='{}', amount={})", + "PaymentOutput(address='{}', amount={}, covenant={})", self.0.address.address_to_string(), - self.0.amount + self.0.amount, + match &self.0.covenant { + Some(covenant) => PyCovenantBinding::from(*covenant).__repr__(), + None => "None".to_string(), + } ) } } @@ -86,7 +100,16 @@ impl TryFrom<&Bound<'_, PyDict>> for PyPaymentOutput { .ok_or_else(|| PyKeyError::new_err("Key `amount` not present"))? .extract()?; - let inner = PaymentOutput::new(address.into(), amount); + let covenant_id = value + .as_any() + .get_item("covenant")? + .extract::>()?; + + let inner = PaymentOutput { + address: address.into(), + amount, + covenant: covenant_id.map(CovenantBinding::from), + }; Ok(Self(inner)) }