Skip to content

Commit 96aec67

Browse files
committed
refactor: implement Deref/DerefMut for BitcoinAmount
1 parent 19a6948 commit 96aec67

File tree

3 files changed

+60
-73
lines changed

3 files changed

+60
-73
lines changed

crates/primitives/src/l1.rs

Lines changed: 58 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::io::{self, ErrorKind};
22
use std::io::{Read, Write};
33
use std::iter::Sum;
4-
use std::ops::Add;
4+
use std::ops::{Add, Deref, DerefMut};
55
use std::str::FromStr;
66

77
use anyhow::{anyhow, Context};
@@ -10,7 +10,7 @@ use bitcoin::address::NetworkUnchecked;
1010
use bitcoin::consensus::serialize;
1111
use bitcoin::hashes::{sha256d, Hash};
1212
use bitcoin::key::TapTweak;
13-
use bitcoin::{Address, AddressType, Block, Network, OutPoint, XOnlyPublicKey};
13+
use bitcoin::{Address, AddressType, Amount, Block, Network, OutPoint, XOnlyPublicKey};
1414
use borsh::{BorshDeserialize, BorshSerialize};
1515
use reth_primitives::revm_primitives::FixedBytes;
1616
use serde::{Deserialize, Serialize};
@@ -292,75 +292,75 @@ impl BorshDeserialize for BitcoinAddress {
292292
}
293293
}
294294

295-
/// A wrapper for bitcoin amount in sats similar to the implementation in [`bitcoin::Amount`].
295+
/// A wrapper for [`bitcoin::Amount`].
296296
///
297297
/// NOTE: This wrapper has been created so that we can implement `Borsh*` traits on it.
298-
#[derive(
299-
Debug,
300-
Clone,
301-
Copy,
302-
Serialize,
303-
Deserialize,
304-
Eq,
305-
PartialEq,
306-
BorshSerialize,
307-
BorshDeserialize,
308-
Arbitrary,
309-
)]
310-
pub struct BitcoinAmount(u64);
311-
312-
impl BitcoinAmount {
313-
// The zero amount.
314-
pub const ZERO: BitcoinAmount = Self(0);
315-
/// The maximum value allowed as an amount. Useful for sanity checking.
316-
pub const MAX_MONEY: BitcoinAmount = Self::from_int_btc(21_000_000);
317-
/// The minimum value of an amount.
318-
pub const MIN: BitcoinAmount = Self::ZERO;
319-
/// The maximum value of an amount.
320-
pub const MAX: BitcoinAmount = Self(u64::MAX);
321-
/// The number of bytes that an amount contributes to the size of a transaction.
322-
pub const SIZE: usize = 8; // Serialized length of a u64.
323-
// The number of sats in 1 bitcoin.
324-
pub const SATS_FACTOR: u64 = 100_000_000;
325-
326-
/// Get the number of sats in this [`BitcoinAmount`].
327-
pub fn to_sat(&self) -> u64 {
328-
self.0
329-
}
330-
331-
/// Create a [`BitcoinAmount`] with sats precision and the given number of sats.
332-
pub const fn from_sat(value: u64) -> Self {
333-
Self(value)
334-
}
335-
336-
/// Convert from a value expressing integer values of bitcoins to a [`BitcoinAmount`]
337-
/// in const context.
338-
///
339-
/// ## Panics
340-
///
341-
/// The function panics if the argument multiplied by the number of sats
342-
/// per bitcoin overflows a u64 type.
343-
pub const fn from_int_btc(btc: u64) -> Self {
344-
match btc.checked_mul(Self::SATS_FACTOR) {
345-
Some(amount) => Self::from_sat(amount),
346-
None => {
347-
panic!("number of sats greater than u64::MAX");
348-
}
349-
}
298+
#[derive(Debug, Clone, Copy, Serialize, Deserialize, Eq, PartialEq)]
299+
pub struct BitcoinAmount(Amount);
300+
301+
impl From<Amount> for BitcoinAmount {
302+
fn from(value: Amount) -> Self {
303+
BitcoinAmount(value)
304+
}
305+
}
306+
307+
impl Deref for BitcoinAmount {
308+
type Target = Amount;
309+
310+
fn deref(&self) -> &Self::Target {
311+
&self.0
312+
}
313+
}
314+
315+
impl DerefMut for BitcoinAmount {
316+
fn deref_mut(&mut self) -> &mut Self::Target {
317+
&mut self.0
318+
}
319+
}
320+
321+
impl BorshSerialize for BitcoinAmount {
322+
fn serialize<W: Write>(&self, writer: &mut W) -> io::Result<()> {
323+
let sats = self.0.to_sat();
324+
325+
borsh::BorshSerialize::serialize(&sats, writer)
326+
}
327+
}
328+
329+
impl BorshDeserialize for BitcoinAmount {
330+
fn deserialize(buf: &mut &[u8]) -> io::Result<Self> {
331+
let sats = borsh::BorshDeserialize::deserialize(buf)?;
332+
333+
Ok(BitcoinAmount(Amount::from_sat(sats)))
334+
}
335+
336+
fn deserialize_reader<R: Read>(reader: &mut R) -> io::Result<Self> {
337+
let sats = borsh::BorshDeserialize::deserialize_reader(reader)?;
338+
339+
Ok(BitcoinAmount(Amount::from_sat(sats)))
340+
}
341+
}
342+
343+
impl<'a> Arbitrary<'a> for BitcoinAmount {
344+
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
345+
// Generate a random u64 value and convert it to Amount
346+
let sats: u64 = u.arbitrary()?;
347+
Ok(BitcoinAmount(Amount::from_sat(sats)))
350348
}
351349
}
352350

353351
impl Add for BitcoinAmount {
354352
type Output = BitcoinAmount;
355353

356354
fn add(self, rhs: Self) -> Self::Output {
357-
Self::from_sat(self.to_sat() + rhs.to_sat())
355+
BitcoinAmount(self.0 + rhs.0)
358356
}
359357
}
360358

361359
impl Sum for BitcoinAmount {
362360
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
363-
Self::from_sat(iter.map(|amt| amt.to_sat()).sum())
361+
let total_amt = iter.fold(Amount::ZERO, |acc, amt| acc + amt.0);
362+
363+
BitcoinAmount(total_amt)
364364
}
365365
}
366366

@@ -416,10 +416,7 @@ impl XOnlyPk {
416416

417417
#[cfg(test)]
418418
mod tests {
419-
use super::{
420-
BitcoinAddress, BitcoinAmount, BorshDeserialize, BorshSerialize, OutPoint, OutputRef,
421-
XOnlyPk,
422-
};
419+
use super::{BitcoinAddress, BorshDeserialize, BorshSerialize, OutPoint, OutputRef, XOnlyPk};
423420
use arbitrary::{Arbitrary, Unstructured};
424421
use bitcoin::{
425422
hashes::Hash,
@@ -558,14 +555,6 @@ mod tests {
558555
);
559556
}
560557

561-
#[test]
562-
#[should_panic(expected = "number of sats greater than u64::MAX")]
563-
fn bitcoinamount_should_handle_sats_exceeding_u64_max() {
564-
let bitcoins: u64 = u64::MAX / BitcoinAmount::SATS_FACTOR + 1;
565-
566-
BitcoinAmount::from_int_btc(bitcoins);
567-
}
568-
569558
fn get_taproot_address(
570559
secp: &Secp256k1<All>,
571560
network: Network,

crates/rpc/api/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ use alpen_express_rpc_types::{
44
types::{BlockHeader, ClientStatus, DepositEntry, ExecUpdate, L1Status},
55
L2BlockId,
66
};
7+
use alpen_express_state::bridge_duties::BridgeDuties;
78
use alpen_express_state::bridge_state::OperatorIdx;
8-
use alpen_express_state::{bridge_duties::BridgeDuties, bridge_ops::WithdrawalBatch};
99
use express_bridge_txm::{DepositInfo, ReimbursementRequest};
1010

1111
use bitcoin::secp256k1::schnorr::Signature;
12-
use bitcoin::{OutPoint, Transaction, Txid};
12+
use bitcoin::{Transaction, Txid};
1313
use jsonrpsee::{core::RpcResult, proc_macros::rpc};
1414
use serde::{Deserialize, Serialize};
1515
use serde_with::serde_as;

crates/state/src/bridge_ops.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ use serde::{Deserialize, Serialize};
55

66
use alpen_express_primitives::l1::{BitcoinAmount, XOnlyPk};
77

8-
pub const WITHDRAWAL_DENOMINATION: BitcoinAmount = BitcoinAmount::from_int_btc(10);
9-
108
/// Describes an intent to withdraw that hasn't been dispatched yet.
119
#[derive(Clone, Debug, Eq, PartialEq, BorshDeserialize, BorshSerialize, Serialize, Deserialize)]
1210
pub struct WithdrawalIntent {

0 commit comments

Comments
 (0)