diff --git a/dlc-manager/src/contract/accepted_contract.rs b/dlc-manager/src/contract/accepted_contract.rs index c9e7ad24..f071b858 100644 --- a/dlc-manager/src/contract/accepted_contract.rs +++ b/dlc-manager/src/contract/accepted_contract.rs @@ -1,4 +1,5 @@ //! # AcceptedContract +use crate::Error; use super::offered_contract::OfferedContract; use super::AdaptorInfo; @@ -75,7 +76,7 @@ impl AcceptedContract { } /// Compute the profit and loss for this contract and an assciated cet index - pub fn compute_pnl(&self, cet: &Transaction) -> SignedAmount { + pub fn compute_pnl(&self, cet: &Transaction) -> Result { let offer = &self.offered_contract; let party_params = if offer.is_offer_party { &offer.offer_params @@ -95,7 +96,8 @@ impl AcceptedContract { } }) .unwrap_or(Amount::ZERO); - SignedAmount::from_sat(final_payout.to_sat() as i64 - collateral.to_sat() as i64) + Ok(final_payout.to_signed().map_err(|_| Error::OutOfRange)? + - collateral.to_signed().map_err(|_| Error::OutOfRange)?) } } @@ -113,11 +115,13 @@ mod tests { let accepted_contract: AcceptedContract = Readable::read(&mut Cursor::new(&buf)).unwrap(); let cets = &accepted_contract.dlc_transactions.cets; assert_eq!( - accepted_contract.compute_pnl(&cets[0]), + accepted_contract.compute_pnl(&cets[0]).unwrap(), SignedAmount::from_sat(90000000) ); assert_eq!( - accepted_contract.compute_pnl(&cets[cets.len() - 1]), + accepted_contract + .compute_pnl(&cets[cets.len() - 1]) + .unwrap(), SignedAmount::from_sat(-11000000) ); } diff --git a/dlc-manager/src/contract/ser.rs b/dlc-manager/src/contract/ser.rs index d05655ab..d8fee842 100644 --- a/dlc-manager/src/contract/ser.rs +++ b/dlc-manager/src/contract/ser.rs @@ -136,7 +136,7 @@ impl_dlc_writeable!(ClosedContract, { (contract_id, writeable), (temporary_contract_id, writeable), (counter_party_id, writeable), - (pnl, i64) + (pnl, SignedAmount) }); impl_dlc_writeable!(FailedAcceptContract, {(offered_contract, writeable), (accept_message, writeable), (error_message, string)}); impl_dlc_writeable!(FailedSignContract, {(accepted_contract, writeable), (sign_message, writeable), (error_message, string)}); diff --git a/dlc-manager/src/error.rs b/dlc-manager/src/error.rs index 9f0ff5c4..34388a7d 100644 --- a/dlc-manager/src/error.rs +++ b/dlc-manager/src/error.rs @@ -27,6 +27,8 @@ pub enum Error { DlcError(dlc::Error), /// An error occurred in the Secp library. SecpError(secp256k1_zkp::Error), + /// A computation was out of range. + OutOfRange, } impl fmt::Display for Error { @@ -43,6 +45,7 @@ impl fmt::Display for Error { Error::DlcError(ref e) => write!(f, "Dlc error {}", e), Error::OracleError(ref s) => write!(f, "Oracle error {}", s), Error::SecpError(_) => write!(f, "Secp error"), + Error::OutOfRange => write!(f, "Out of range error"), } } } @@ -98,6 +101,7 @@ impl std::error::Error for Error { Error::OracleError(_) => None, Error::DlcError(e) => Some(e), Error::SecpError(e) => Some(e), + Error::OutOfRange => None, } } } diff --git a/dlc-manager/src/manager.rs b/dlc-manager/src/manager.rs index 84dd666d..1722c76d 100644 --- a/dlc-manager/src/manager.rs +++ b/dlc-manager/src/manager.rs @@ -755,7 +755,7 @@ where pnl: contract .signed_contract .accepted_contract - .compute_pnl(&contract.signed_cet), + .compute_pnl(&contract.signed_cet)?, }; self.store .update_contract(&Contract::Closed(closed_contract))?; @@ -800,7 +800,7 @@ where let closed_contract = ClosedContract { attestations: Some(attestations.to_vec()), - pnl: contract.accepted_contract.compute_pnl(&signed_cet), + pnl: contract.accepted_contract.compute_pnl(&signed_cet)?, signed_cet: Some(signed_cet), contract_id: contract.accepted_contract.get_contract_id(), temporary_contract_id: contract.accepted_contract.offered_contract.id, @@ -883,7 +883,7 @@ where } else { Contract::Closed(ClosedContract { attestations: None, // todo in some cases we can get the attestations from the closing tx - pnl: contract.accepted_contract.compute_pnl(&closing_tx), + pnl: contract.accepted_contract.compute_pnl(&closing_tx)?, signed_cet: Some(closing_tx), contract_id: contract.accepted_contract.get_contract_id(), temporary_contract_id: contract.accepted_contract.offered_contract.id, diff --git a/dlc-manager/src/payout_curve.rs b/dlc-manager/src/payout_curve.rs index 90100121..411042a7 100644 --- a/dlc-manager/src/payout_curve.rs +++ b/dlc-manager/src/payout_curve.rs @@ -167,6 +167,7 @@ trait Evaluable { total_collateral: Amount, ) -> Result { let payout_double = self.evaluate(outcome); + let total_collateral_sats = total_collateral.to_sat(); if payout_double.is_sign_negative() || (payout_double != 0.0 && !payout_double.is_normal()) { return Err(Error::InvalidParameters(format!( @@ -175,7 +176,7 @@ trait Evaluable { ))); } - if payout_double.round() > total_collateral.to_sat() as f64 { + if payout_double.round() > total_collateral_sats as f64 { return Err(Error::InvalidParameters( "Computed payout is greater than total collateral".to_string(), )); @@ -184,7 +185,7 @@ trait Evaluable { // Ensure that we never round over the total collateral. Ok(Amount::from_sat(u64::min( rounding_intervals.round(outcome, payout_double), - total_collateral.to_sat(), + total_collateral_sats, ))) } @@ -309,14 +310,14 @@ impl Evaluable for PolynomialPayoutCurvePiece { // Optimizations for constant and linear cases. if nb_points == 2 { let (left_point, right_point) = (&self.payout_points[0], &self.payout_points[1]); + let right_point_payout_sats = right_point.outcome_payout.to_sat() as f64; + let left_point_payout_sats = left_point.outcome_payout.to_sat() as f64; return if left_point.outcome_payout == right_point.outcome_payout { - right_point.outcome_payout.to_sat() as f64 + right_point_payout_sats } else { - let slope = (right_point.outcome_payout.to_sat() as f64 - - left_point.outcome_payout.to_sat() as f64) + let slope = (right_point_payout_sats - left_point_payout_sats) / (right_point.event_outcome - left_point.event_outcome) as f64; - (outcome - left_point.event_outcome) as f64 * slope - + left_point.outcome_payout.to_sat() as f64 + (outcome - left_point.event_outcome) as f64 * slope + left_point_payout_sats }; } diff --git a/dlc-messages/src/ser_impls.rs b/dlc-messages/src/ser_impls.rs index f1e22455..1ba425d7 100644 --- a/dlc-messages/src/ser_impls.rs +++ b/dlc-messages/src/ser_impls.rs @@ -568,17 +568,22 @@ pub fn read_i32(reader: &mut R) -> Result { let v: [u8; 4] = Readable::read(reader)?; Ok(i32::from_be_bytes(v)) } -/// Writes an `i64` value to the given writer. -pub fn write_i64(i: &i64, writer: &mut W) -> Result<(), ::lightning::io::Error> { - let i = i.to_be_bytes(); +/// Writes a `SignedAmount` value to the given writer. +pub fn write_signed_amount( + i: &SignedAmount, + writer: &mut W, +) -> Result<(), ::lightning::io::Error> { + let i = i.to_sat().to_be_bytes(); for b in i { b.write(writer)?; } Ok(()) } -/// Reads an `i64` value from the given reader. -pub fn read_i64(reader: &mut R) -> Result { +/// Reads a `SignedAmount` value from the given reader. +pub fn read_signed_amount( + reader: &mut R, +) -> Result { let mut v = [0u8; 8]; for x in &mut v { *x = Readable::read(reader)?; diff --git a/dlc-messages/src/ser_macros.rs b/dlc-messages/src/ser_macros.rs index 94689a71..2c883c61 100644 --- a/dlc-messages/src/ser_macros.rs +++ b/dlc-messages/src/ser_macros.rs @@ -27,8 +27,8 @@ macro_rules! field_write { ($stream: expr, $field: expr, usize) => { $crate::ser_impls::write_usize(&$field, $stream)?; }; - ($stream: expr, $field: expr, i64) => { - $crate::ser_impls::write_i64(&$field.to_sat(), $stream)?; + ($stream: expr, $field: expr, SignedAmount) => { + $crate::ser_impls::write_signed_amount(&$field, $stream)?; }; ($stream: expr, $field: expr, {option_cb, $w_cb: expr, $r_cb: expr}) => { $crate::ser_impls::write_option_cb(&$field, $stream, &$w_cb)?; @@ -65,8 +65,8 @@ macro_rules! field_read { ($stream: expr, usize) => { $crate::ser_impls::read_usize($stream)? }; - ($stream: expr, i64) => { - $crate::ser_impls::read_i64($stream)? + ($stream: expr, SignedAmount) => { + $crate::ser_impls::read_signed_amount($stream)? }; ($stream: expr, {option_cb, $w_cb: expr, $r_cb: expr}) => { $crate::ser_impls::read_option_cb($stream, &$r_cb)?