diff --git a/src/main/scala/org/bitcoins/core/currency/CurrencyUnits.scala b/src/main/scala/org/bitcoins/core/currency/CurrencyUnits.scala index 8f10173eef..52b4ff2fa7 100644 --- a/src/main/scala/org/bitcoins/core/currency/CurrencyUnits.scala +++ b/src/main/scala/org/bitcoins/core/currency/CurrencyUnits.scala @@ -1,5 +1,6 @@ package org.bitcoins.core.currency +import org.bitcoins.core.consensus.Consensus import org.bitcoins.core.number.{BaseNumbers, Int32, Int64, SignedNumber} import org.bitcoins.core.protocol.NetworkElement import org.bitcoins.core.serializers.{RawBitcoinSerializerHelper, RawSatoshisSerializer} @@ -10,41 +11,48 @@ sealed trait CurrencyUnit extends NetworkElement with BitcoinSLogger { type A def underlying : A + def satoshis: Satoshis + def >=(c : CurrencyUnit) : Boolean = { - CurrencyUnits.toSatoshis(this).underlying >= CurrencyUnits.toSatoshis(c).underlying + satoshis.underlying >= c.satoshis.underlying } def >(c : CurrencyUnit) : Boolean = { - CurrencyUnits.toSatoshis(this).underlying > CurrencyUnits.toSatoshis(c).underlying + satoshis.underlying > c.satoshis.underlying } def <(c : CurrencyUnit) : Boolean = { - CurrencyUnits.toSatoshis(this).underlying < CurrencyUnits.toSatoshis(c).underlying + satoshis.underlying < c.satoshis.underlying } def <=(c : CurrencyUnit) : Boolean = { - CurrencyUnits.toSatoshis(this).underlying <= CurrencyUnits.toSatoshis(c).underlying + satoshis.underlying <= c.satoshis.underlying } def !=(c : CurrencyUnit) : Boolean = !(this == c) def +(c : CurrencyUnit) : CurrencyUnit = { - Satoshis(CurrencyUnits.toSatoshis(this).underlying + CurrencyUnits.toSatoshis(c).underlying) + Satoshis(satoshis.underlying + c.satoshis.underlying) } def -(c : CurrencyUnit) : CurrencyUnit = { - Satoshis(CurrencyUnits.toSatoshis(this).underlying - CurrencyUnits.toSatoshis(c).underlying) + Satoshis(satoshis.underlying - c.satoshis.underlying) } def *(c : CurrencyUnit) : CurrencyUnit = { - Satoshis(CurrencyUnits.toSatoshis(this).underlying * CurrencyUnits.toSatoshis(c).underlying) + Satoshis(satoshis.underlying * c.satoshis.underlying) + } + + def unary_- : CurrencyUnit = { + Satoshis(- satoshis.underlying) } } sealed trait Satoshis extends CurrencyUnit { override type A = Int64 override def hex = RawSatoshisSerializer.write(this) + override def satoshis: Satoshis = this } object Satoshis extends Factory[Satoshis] with BaseNumbers[Satoshis] { @@ -60,14 +68,41 @@ object Satoshis extends Factory[Satoshis] with BaseNumbers[Satoshis] { def apply(int64: Int64): Satoshis = SatoshisImpl(int64) } -object CurrencyUnits { - def zero : CurrencyUnit = Satoshis.zero - def negativeSatoshi = Satoshis(Int64(-1)) - /** The number you need to multiply BTC by to get it's satoshis */ - def btcToSatoshiScalar = 100000000 +sealed trait Bitcoins extends CurrencyUnit { + override type A = BigDecimal + override def satoshis: Satoshis = { + val sat = underlying * CurrencyUnits.btcToSatoshiScalar + Satoshis(Int64(sat.toLongExact)) + } + override def hex = satoshis.hex +} - def oneBTC: CurrencyUnit = Satoshis(Int64(btcToSatoshiScalar)) - def toSatoshis(unit : CurrencyUnit): Satoshis = unit match { - case x : Satoshis => x +object Bitcoins extends BaseNumbers[Bitcoins] { + val min = Bitcoins((-Consensus.maxMoney).satoshis) + val max = Bitcoins(Consensus.maxMoney.satoshis) + val zero = Bitcoins(Satoshis.zero) + val one = Bitcoins(1) + private case class BitcoinsImpl(underlying: BigDecimal) extends Bitcoins + + def apply(underlying: BigDecimal): Bitcoins = BitcoinsImpl(underlying) + + def apply(satoshis: Satoshis): Bitcoins = { + val b = satoshis.underlying.underlying * CurrencyUnits.satoshisToBTCScalar + BitcoinsImpl(b) + } +} + + +object CurrencyUnits { + def zero: CurrencyUnit = Satoshis.zero + def negativeSatoshi = Satoshis(Int64(-1)) + /** The number you need to multiply BTC by to get it's satoshis */ + def btcToSatoshiScalar: Long = 100000000 + def satoshisToBTCScalar: BigDecimal = BigDecimal(1.0) / btcToSatoshiScalar + def oneBTC: CurrencyUnit = Satoshis(Int64(btcToSatoshiScalar)) + + def toSatoshis(unit : CurrencyUnit): Satoshis = unit match { + case b: Bitcoins => b.satoshis + case x: Satoshis => x } } diff --git a/src/main/scala/org/bitcoins/core/number/NumberType.scala b/src/main/scala/org/bitcoins/core/number/NumberType.scala index 6f60bff7a8..879df89597 100644 --- a/src/main/scala/org/bitcoins/core/number/NumberType.scala +++ b/src/main/scala/org/bitcoins/core/number/NumberType.scala @@ -82,6 +82,8 @@ sealed trait UInt32 extends UnsignedNumber with NumberOperations[UInt32] { def & (num : UInt32) : UInt32 = UInt32(underlying & num.underlying) + + override def hex = BitcoinSUtil.encodeHex(underlying).slice(8,16) override def toInt = { @@ -207,6 +209,7 @@ sealed trait Int32 extends SignedNumber with NumberOperations[Int32] { override def <= (num : Int32): Boolean = underlying <= num.underlying + def unary_- : Int32 = Int32(-underlying) def | (num : Int32) : Int32 = Int32(underlying | num.underlying) def & (num : Int32) : Int32 = Int32(underlying & num.underlying) @@ -261,6 +264,8 @@ sealed trait Int64 extends SignedNumber with NumberOperations[Int64] { override def <= (num : Int64): Boolean = underlying <= num.underlying + def unary_- : Int64 = Int64(-underlying) + def | (num : Int64) : Int64 = Int64(underlying | num.underlying) def & (num : Int64) : Int64 = Int64(underlying & num.underlying) diff --git a/src/test/scala/org/bitcoins/core/number/Int32Spec.scala b/src/test/scala/org/bitcoins/core/number/Int32Spec.scala index 3b9e200937..b74a0569df 100644 --- a/src/test/scala/org/bitcoins/core/number/Int32Spec.scala +++ b/src/test/scala/org/bitcoins/core/number/Int32Spec.scala @@ -1,6 +1,7 @@ package org.bitcoins.core.number import org.bitcoins.core.gen.NumberGenerator +import org.bitcoins.core.util.BitcoinSLogger import org.scalacheck.{Prop, Properties} import scala.util.Try @@ -8,8 +9,7 @@ import scala.util.Try /** * Created by chris on 6/21/16. */ -class Int32Spec extends Properties("Int32Spec") { - +class Int32Spec extends Properties("Int32Spec") with BitcoinSLogger { property("Serialization symmetry") = Prop.forAll(NumberGenerator.int32s) { int32: Int32 => @@ -86,4 +86,10 @@ class Int32Spec extends Properties("Int32Spec") { Prop.forAll(NumberGenerator.int32s, NumberGenerator.int32s) { (num1: Int32, num2: Int32) => Int32(num1.underlying & num2.underlying) == (num1 & num2) } + + property("negation") = { + Prop.forAll(NumberGenerator.int32s) { int32 => + -int32 == Int32(-int32.underlying) + } + } } diff --git a/src/test/scala/org/bitcoins/core/number/Int64Spec.scala b/src/test/scala/org/bitcoins/core/number/Int64Spec.scala index 277c4553a2..16753a6d5b 100644 --- a/src/test/scala/org/bitcoins/core/number/Int64Spec.scala +++ b/src/test/scala/org/bitcoins/core/number/Int64Spec.scala @@ -86,5 +86,12 @@ class Int64Spec extends Properties("Int64Spec") { Prop.forAll(NumberGenerator.int64s, NumberGenerator.int64s) { (num1: Int64, num2: Int64) => Int64(num1.underlying & num2.underlying) == (num1 & num2) } + + property("negation") = { + Prop.forAll(NumberGenerator.int64s) { int64 => + -int64 == Int64(-int64.underlying) + } + } + }