From e34c4505d45ba99d7856f551f0ee2c8a20f4a357 Mon Sep 17 00:00:00 2001 From: Torkel Rogstad Date: Thu, 2 May 2019 13:49:35 +0200 Subject: [PATCH] Natural language syntax for currencies (#440) * Convert CurrencyUnit and LnCurrencyUnit Scalacheck to Scalatest * Add Int and Long syntax to LnCurrencyUnit, MilliSatoshis and CurrencyUnit * Tweak toString methods --- .../core/currency/CurrencyUnitTest.scala | 167 ++++++++++++++++++ .../ln/currency/LnCurrencyUnitTest.scala | 160 ++++++++++++++++- .../ln/currency/MilliSatoshisTest.scala | 34 +++- .../core/currency/CurrencyUnits.scala | 6 +- .../org/bitcoins/core/currency/package.scala | 40 +++++ .../protocol/ln/currency/LnCurrencyUnit.scala | 9 +- .../protocol/ln/currency/MilliSatoshis.scala | 6 +- .../core/protocol/ln/currency/package.scala | 81 +++++++++ 8 files changed, 484 insertions(+), 19 deletions(-) create mode 100644 core-test/src/test/scala/org/bitcoins/core/currency/CurrencyUnitTest.scala create mode 100644 core/src/main/scala/org/bitcoins/core/currency/package.scala create mode 100644 core/src/main/scala/org/bitcoins/core/protocol/ln/currency/package.scala diff --git a/core-test/src/test/scala/org/bitcoins/core/currency/CurrencyUnitTest.scala b/core-test/src/test/scala/org/bitcoins/core/currency/CurrencyUnitTest.scala new file mode 100644 index 0000000000..d06b522509 --- /dev/null +++ b/core-test/src/test/scala/org/bitcoins/core/currency/CurrencyUnitTest.scala @@ -0,0 +1,167 @@ +package org.bitcoins.core.currency + +import org.bitcoins.core.currency._ + +import org.bitcoins.testkit.util.BitcoinSUnitTest +import org.bitcoins.testkit.core.gen.CurrencyUnitGenerator +import scala.util.Try +import org.bitcoins.core.number.Int64 +import scala.util.Success +import scala.util.Failure +import org.scalacheck.Gen +import org.scalacheck.Shrink + +class CurrencyUnitTest extends BitcoinSUnitTest { + + behavior of "Satoshis" + + it must "have symmetry serialization" in { + forAll(CurrencyUnitGenerator.satoshis) { satoshis => + assert(Satoshis(satoshis.hex) == satoshis) + } + } + + it must "have Int syntax" in { + forAll(Gen.choose(0, Int.MaxValue)) { num => + assert(num.bitcoins == Bitcoins(num)) + assert(num.bitcoin == Bitcoins(num)) + assert(num.BTC == Bitcoins(num)) + + assert(num.satoshis == Satoshis(Int64(num))) + assert(num.satoshi == Satoshis(Int64(num))) + assert(num.sats == Satoshis(Int64(num))) + assert(num.sat == Satoshis(Int64(num))) + } + } + + it must "have Long syntax" in { + forAll(Gen.choose(0, Satoshis.max.toLong / 100000000)) { num => + assert(num.bitcoins == Bitcoins(num)) + assert(num.bitcoin == Bitcoins(num)) + assert(num.BTC == Bitcoins(num)) + } + + forAll(Gen.choose(0, Satoshis.max.toLong)) { num => + assert(num.satoshis == Satoshis(Int64(num))) + assert(num.satoshi == Satoshis(Int64(num))) + assert(num.sats == Satoshis(Int64(num))) + assert(num.sat == Satoshis(Int64(num))) + } + } + + it must "have additive identity" in { + forAll(CurrencyUnitGenerator.satoshis) { satoshis => + assert(satoshis + CurrencyUnits.zero == satoshis) + } + } + + it must "add satoshis" in { + forAll(CurrencyUnitGenerator.satoshis, CurrencyUnitGenerator.satoshis) { + (num1, num2) => (num1: Satoshis, num2: Satoshis) => + val result: Try[Int64] = Try(Int64(num1.toBigInt + num2.toBigInt)) + if (result.isSuccess && result.get >= Int64(Satoshis.min.toLong) && + result.get <= Int64(Satoshis.max.toLong)) + assert(num1 + num2 == Satoshis(result.get)) + else assert(Try(num1 + num2).isFailure) + } + } + + it must "have subtractive identity for satoshis" in { + forAll(CurrencyUnitGenerator.satoshis) { satoshis => + assert(satoshis - CurrencyUnits.zero == satoshis) + } + } + + it must "subtract satoshis " in { + forAll(CurrencyUnitGenerator.satoshis, CurrencyUnitGenerator.satoshis) { + (num1: Satoshis, num2: Satoshis) => + val result: Try[Int64] = Try(Int64(num1.toBigInt - num2.toBigInt)) + if (result.isSuccess && result.get >= Int64(Satoshis.min.toLong) && + result.get <= Int64(Satoshis.max.toLong)) + assert(num1 - num2 == Satoshis(result.get)) + else assert(Try(num1 - num2).isFailure) + } + } + + it must "multiply satoshis by zero" in { + forAll(CurrencyUnitGenerator.satoshis) { satoshis => + assert(satoshis * CurrencyUnits.zero == CurrencyUnits.zero) + } + } + + it must "have multiplicative identity" in { + forAll(CurrencyUnitGenerator.satoshis) { satoshis => + assert(satoshis * Satoshis.one == satoshis) + } + } + + it must "multiply satoshis" in { + forAll(CurrencyUnitGenerator.satoshis, CurrencyUnitGenerator.satoshis) { + (num1, num2) => + val result: Try[Int64] = Try(Int64(num1.toBigInt * num2.toBigInt)) + if (result.isSuccess && result.get >= Int64(Satoshis.min.toLong) && + result.get <= Int64(Satoshis.max.toLong)) + num1 * num2 == Satoshis(result.get) + else Try(num1 * num2).isFailure + } + } + + private val satoshiWithInt: Gen[(Satoshis, Int)] = for { + sat <- CurrencyUnitGenerator.satoshis + num <- Gen.choose(Int.MinValue, Int.MaxValue) + } yield (sat, num) + + it must "multiply a satoshi value with an int" in { + forAll(satoshiWithInt) { + case (sat, int) => + val safeProduct = sat.multiplySafe(int) + val underlyingProduct = sat.toBigInt * int + if (underlyingProduct < Satoshis.max.toBigInt && underlyingProduct > Satoshis.min.toBigInt) { + assert(safeProduct.isSuccess) + assert(safeProduct.get.satoshis.toBigInt == underlyingProduct) + } else { + assert(safeProduct.isFailure) + } + } + } + + it must "have '< & >=' property" in { + forAll(CurrencyUnitGenerator.satoshis, CurrencyUnitGenerator.satoshis) { + (num1, num2) => + assert((num1 < num2) || (num1 >= num2)) + } + } + + it must "have '<= & >' property" in { + forAll(CurrencyUnitGenerator.satoshis, CurrencyUnitGenerator.satoshis) { + (num1, num2) => + assert((num1 <= num2) || (num1 > num2)) + } + } + + it must "have '== & !=' property" in { + forAll(CurrencyUnitGenerator.satoshis, CurrencyUnitGenerator.satoshis) { + (num1, num2) => + assert((num1 == num2) || (num1 != num2)) + } + } + + it must "convert satoshis to bitcoin and then back to satoshis" in { + forAll(CurrencyUnitGenerator.satoshis) { satoshis => + val b = Bitcoins(satoshis) + assert(b.satoshis == satoshis) + } + } + + it must "be able to add two unique currency unit types" in { + forAll(CurrencyUnitGenerator.satoshis, CurrencyUnitGenerator.bitcoins) { + (sats: Satoshis, btc: Bitcoins) => + val result = + Try(Satoshis(Int64(sats.toBigInt + btc.satoshis.toBigInt))) + val expected = result.map(Bitcoins(_)) + val actual: Try[CurrencyUnit] = Try(sats + btc) + if (actual.isSuccess && expected.isSuccess) actual.get == expected.get + else actual.isFailure && expected.isFailure + } + } +} diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/ln/currency/LnCurrencyUnitTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/ln/currency/LnCurrencyUnitTest.scala index 3b058ad614..5aea55558b 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/ln/currency/LnCurrencyUnitTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/ln/currency/LnCurrencyUnitTest.scala @@ -1,10 +1,166 @@ package org.bitcoins.core.protocol.ln.currency +import org.bitcoins.core.protocol.ln.currency._ import org.bitcoins.core.currency.Satoshis import org.bitcoins.core.protocol.ln.LnPolicy -import org.scalatest.{FlatSpec, MustMatchers} +import org.bitcoins.testkit.util.BitcoinSUnitTest +import org.bitcoins.testkit.core.gen.ln.LnCurrencyUnitGen +import scala.util.Success +import scala.util.Failure +import scala.util.Try +import org.scalacheck.Gen +import org.bitcoins.core.number.Int64 + +class LnCurrencyUnitTest extends BitcoinSUnitTest { + + it must "have additive identity" in { + forAll(LnCurrencyUnitGen.lnCurrencyUnit) { lnUnit => + assert(lnUnit + LnCurrencyUnits.zero == lnUnit) + } + } + + it must "add to LnCurrencyUnits" in { + forAll(LnCurrencyUnitGen.lnCurrencyUnit, LnCurrencyUnitGen.lnCurrencyUnit) { + (num1, num2) => + val resultT: Try[LnCurrencyUnit] = Try(num1 + num2) + resultT match { + case Success(result) => + assert(PicoBitcoins.min <= result) + assert(result <= PicoBitcoins.max) + assert(num1 + num2 == result) + case Failure(exc) => succeed + } + } + } + + it must "have subtractive identity for LnCurrencyUnits" in { + forAll(LnCurrencyUnitGen.lnCurrencyUnit) { lnUnit => + assert(lnUnit - LnCurrencyUnits.zero == lnUnit) + } + } + + it must "subtract two LnCurrencyUnit values" in { + forAll(LnCurrencyUnitGen.lnCurrencyUnit, LnCurrencyUnitGen.lnCurrencyUnit) { + (num1, num2) => + val resultT: Try[LnCurrencyUnit] = Try(num1 - num2) + resultT match { + case Success(result) => + assert(PicoBitcoins.min <= result) + assert(result <= PicoBitcoins.max) + assert(num1 - num2 == result) + case Failure(exc) => succeed + } + } + } + + it must "multiply LnCurrencyUnit by zero" in { + forAll(LnCurrencyUnitGen.lnCurrencyUnit) { lnUnit => + assert(lnUnit * LnCurrencyUnits.zero == LnCurrencyUnits.zero) + } + } + + it must "have multiplicative identity for LnCurrencyUnits" in { + forAll(LnCurrencyUnitGen.lnCurrencyUnit) { lnUnit => + assert(lnUnit * PicoBitcoins.one == lnUnit) + } + } + + it must "multiply two LnCurrencyUnit values" in { + forAll(LnCurrencyUnitGen.lnCurrencyUnit, LnCurrencyUnitGen.lnCurrencyUnit) { + (num1, num2) => + val resultT: Try[LnCurrencyUnit] = Try(num1 * num2) + resultT match { + case Success(result) => + assert(result >= PicoBitcoins.min) + assert(result <= PicoBitcoins.max) + assert(num1 * num2 == result) + case Failure(exc) => succeed + } + } + } + + private val lnCurrWithInt: Gen[(LnCurrencyUnit, Int)] = for { + ln <- LnCurrencyUnitGen.lnCurrencyUnit + num <- Gen.choose(Int.MinValue, Int.MaxValue) + } yield (ln, num) + + it must "multiply a LnCurrencyUnit value with an int" in { + forAll(lnCurrWithInt) { + case (ln, int) => + val safeProduct = ln.multiplySafe(int) + val underlyingProduct = ln.toBigInt * int + if (underlyingProduct <= PicoBitcoins.min.toBigInt && underlyingProduct >= PicoBitcoins.max.toBigInt) { + assert(safeProduct.isSuccess) + safeProduct.get.toBigInt == underlyingProduct + } else { + safeProduct.isFailure + } + } + } + + it must "have property '< & >=''" in { + forAll(LnCurrencyUnitGen.lnCurrencyUnit, LnCurrencyUnitGen.lnCurrencyUnit) { + (num1, num2) => + assert((num1 < num2) || (num1 >= num2)) + } + } + + it must "have property '<= & >'" in { + forAll(LnCurrencyUnitGen.lnCurrencyUnit, LnCurrencyUnitGen.lnCurrencyUnit) { + (num1, num2) => + assert((num1 <= num2) || (num1 > num2)) + } + } + + it must "have property '== & !='" in { + forAll(LnCurrencyUnitGen.lnCurrencyUnit, LnCurrencyUnitGen.lnCurrencyUnit) { + (num1, num2) => + assert((num1 == num2) || (num1 != num2)) + } + } + + it must "have Int syntax" in { + forAll(Gen.choose(Int.MinValue, Int.MaxValue)) { num => + assert(num.millibitcoins == MilliBitcoins(num)) + assert(num.millibitcoin == MilliBitcoins(num)) + assert(num.mBTC == MilliBitcoins(num)) + + assert(num.microbitcoins == MicroBitcoins(num)) + assert(num.microbitcoin == MicroBitcoins(num)) + assert(num.uBTC == MicroBitcoins(num)) + + assert(num.nanobitcoins == NanoBitcoins(num)) + assert(num.nanobitcoin == NanoBitcoins(num)) + assert(num.nBTC == NanoBitcoins(num)) + + assert(num.picobitcoins == PicoBitcoins(num)) + assert(num.picobitcoin == PicoBitcoins(num)) + assert(num.pBTC == PicoBitcoins(num)) + } + } + + it must "have Long syntax" in { + forAll( + Gen.choose(LnPolicy.minMilliBitcoins.toLong, + LnPolicy.maxMilliBitcoins.toLong)) { num => + assert(num.millibitcoins == MilliBitcoins(num)) + assert(num.millibitcoin == MilliBitcoins(num)) + assert(num.mBTC == MilliBitcoins(num)) + + assert(num.microbitcoins == MicroBitcoins(num)) + assert(num.microbitcoin == MicroBitcoins(num)) + assert(num.uBTC == MicroBitcoins(num)) + + assert(num.nanobitcoins == NanoBitcoins(num)) + assert(num.nanobitcoin == NanoBitcoins(num)) + assert(num.nBTC == NanoBitcoins(num)) + + assert(num.picobitcoins == PicoBitcoins(num)) + assert(num.picobitcoin == PicoBitcoins(num)) + assert(num.pBTC == PicoBitcoins(num)) + } + } -class LnCurrencyUnitTest extends FlatSpec with MustMatchers { it must "serialize MilliBitcoins to string" in { val milliBitcoins = MilliBitcoins(1000) milliBitcoins.toEncodedString must be("1000m") diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/ln/currency/MilliSatoshisTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/ln/currency/MilliSatoshisTest.scala index 6ced760ef0..2d911df656 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/ln/currency/MilliSatoshisTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/ln/currency/MilliSatoshisTest.scala @@ -4,6 +4,7 @@ import org.bitcoins.testkit.core.gen.{CurrencyUnitGenerator, NumberGenerator} import org.bitcoins.testkit.core.gen.ln.LnCurrencyUnitGen import org.bitcoins.testkit.util.BitcoinSUnitTest import org.scalatest.prop.PropertyChecks +import org.scalacheck.Gen class MilliSatoshisTest extends BitcoinSUnitTest { behavior of "MilliSatoshis" @@ -26,7 +27,7 @@ class MilliSatoshisTest extends BitcoinSUnitTest { } it must "add millisatoshis" in { - PropertyChecks.forAll(LnCurrencyUnitGen.milliSatoshisPair) { + forAll(LnCurrencyUnitGen.milliSatoshisPair) { case (first, second) => val bigInt = first.toBigInt + second.toBigInt assert((first + second).toBigInt == bigInt) @@ -39,7 +40,7 @@ class MilliSatoshisTest extends BitcoinSUnitTest { } yield (msat, num) it must "multiply millisatoshis with an int" in { - PropertyChecks.forAll(msatWithNum) { + forAll(msatWithNum) { case (msat, bigint) => val underlyingCalc = msat.toBigInt * bigint assert((msat * bigint).toBigInt == underlyingCalc) @@ -47,7 +48,7 @@ class MilliSatoshisTest extends BitcoinSUnitTest { } it must "multiply millisatoshis with itself" in { - PropertyChecks.forAll(LnCurrencyUnitGen.milliSatoshisPair) { + forAll(LnCurrencyUnitGen.milliSatoshisPair) { case (first, second) => val safe = first.multiplySafe(second) val unsafe = first * second @@ -60,7 +61,7 @@ class MilliSatoshisTest extends BitcoinSUnitTest { } it must "subtract msats after adding them" in { - PropertyChecks.forAll(LnCurrencyUnitGen.milliSatoshisPair) { + forAll(LnCurrencyUnitGen.milliSatoshisPair) { case (first, second) => val added = first + second val subtracted = added - second @@ -69,7 +70,7 @@ class MilliSatoshisTest extends BitcoinSUnitTest { } it must "subtract msats" in { - PropertyChecks.forAll(LnCurrencyUnitGen.milliSatoshisPair) { + forAll(LnCurrencyUnitGen.milliSatoshisPair) { case (first, second) => val subtracted = first subtractSafe second val isPositive = (first.toBigInt - second.toBigInt) >= 0 @@ -83,8 +84,7 @@ class MilliSatoshisTest extends BitcoinSUnitTest { } it must "covert from a ln currency unit -> millisatoshis -> lnCurrencyUnit" in { - - PropertyChecks.forAll(LnCurrencyUnitGen.positivePicoBitcoin) { pb => + forAll(LnCurrencyUnitGen.positivePicoBitcoin) { pb => val underlying = pb.toBigInt //we lose the last digit of precision converting //PicoBitcoins -> MilliSatoshis @@ -103,10 +103,28 @@ class MilliSatoshisTest extends BitcoinSUnitTest { } it must "convert sat -> msat -> sat" in { - PropertyChecks.forAll(CurrencyUnitGenerator.positiveRealistic) { sat => + forAll(CurrencyUnitGenerator.positiveRealistic) { sat => val msat = MilliSatoshis(sat) assert(msat.toSatoshis == sat) } } + + it must "have Int syntax" in { + forAll(Gen.choose(0, Int.MaxValue)) { num => + assert(num.millisatoshis == MilliSatoshis(num)) + assert(num.millisatoshi == MilliSatoshis(num)) + assert(num.msats == MilliSatoshis(num)) + assert(num.msat == MilliSatoshis(num)) + } + } + + it must "have Long syntax" in { + forAll(Gen.choose(0L, Long.MaxValue)) { num => + assert(num.millisatoshis == MilliSatoshis(num)) + assert(num.millisatoshi == MilliSatoshis(num)) + assert(num.msats == MilliSatoshis(num)) + assert(num.msat == MilliSatoshis(num)) + } + } } diff --git a/core/src/main/scala/org/bitcoins/core/currency/CurrencyUnits.scala b/core/src/main/scala/org/bitcoins/core/currency/CurrencyUnits.scala index 77933ade30..f511dafa77 100644 --- a/core/src/main/scala/org/bitcoins/core/currency/CurrencyUnits.scala +++ b/core/src/main/scala/org/bitcoins/core/currency/CurrencyUnits.scala @@ -64,7 +64,11 @@ sealed abstract class CurrencyUnit sealed abstract class Satoshis extends CurrencyUnit { override type A = Int64 - override def toString: String = s"$toLong sat" + override def toString: String = { + val num = toLong + val postFix = if (num == 1) "sat" else "sats" + s"$num $postFix" + } override def bytes: ByteVector = RawSatoshisSerializer.write(this) diff --git a/core/src/main/scala/org/bitcoins/core/currency/package.scala b/core/src/main/scala/org/bitcoins/core/currency/package.scala new file mode 100644 index 0000000000..9d5eb91403 --- /dev/null +++ b/core/src/main/scala/org/bitcoins/core/currency/package.scala @@ -0,0 +1,40 @@ +package org.bitcoins.core + +import org.bitcoins.core.number.Int64 + +// We extend AnyVal to avoid runtime allocation of new +// objects. See the Scala documentation on value classes +// and universal traits for more: +// https://docs.scala-lang.org/overviews/core/value-classes.html +package object currency { + + /** Provides natural language syntax for bitcoins */ + implicit class BitcoinsInt(private val i: Int) extends AnyVal { + def bitcoins: Bitcoins = Bitcoins(i) + def bitcoin: Bitcoins = bitcoins + def BTC: Bitcoins = bitcoins + } + + /** Provides natural language syntax for bitcoins */ + implicit class BitcoinsLong(private val i: Long) extends AnyVal { + def bitcoins: Bitcoins = Bitcoins(i) + def bitcoin: Bitcoins = bitcoins + def BTC: Bitcoins = bitcoins + } + + /** Provides natural language syntax for satoshis */ + implicit class SatoshisInt(private val i: Int) extends AnyVal { + def satoshis: Satoshis = Satoshis(Int64(i)) + def satoshi: Satoshis = satoshis + def sats: Satoshis = satoshis + def sat: Satoshis = satoshis + } + + /** Provides natural language syntax for satoshis */ + implicit class SatoshisLong(private val i: Long) extends AnyVal { + def satoshis: Satoshis = Satoshis(Int64(i)) + def satoshi: Satoshis = satoshis + def sats: Satoshis = satoshis + def sat: Satoshis = satoshis + } +} diff --git a/core/src/main/scala/org/bitcoins/core/protocol/ln/currency/LnCurrencyUnit.scala b/core/src/main/scala/org/bitcoins/core/protocol/ln/currency/LnCurrencyUnit.scala index 16e12676c3..17ae3ee194 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/ln/currency/LnCurrencyUnit.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/ln/currency/LnCurrencyUnit.scala @@ -99,6 +99,8 @@ sealed abstract class LnCurrencyUnit def toEncodedString: String = { toBigInt + character.toString } + + override def toString(): String = s"$underlying ${character}BTC" } sealed abstract class MilliBitcoins extends LnCurrencyUnit { @@ -128,8 +130,6 @@ object MilliBitcoins extends BaseNumbers[MilliBitcoins] { require(underlying <= LnPolicy.maxMilliBitcoins, "Number was too big for MilliBitcoins, got: " + underlying) - override def toString: String = - s"${underlying / toPicoBitcoinMultiplier} mBTC" } } @@ -160,8 +160,6 @@ object MicroBitcoins extends BaseNumbers[MicroBitcoins] { require(underlying <= LnPolicy.maxMicroBitcoins, "Number was too big for MicroBitcoins, got: " + underlying) - override def toString: String = - s"${underlying / toPicoBitcoinMultiplier} uBTC" } } @@ -191,8 +189,6 @@ object NanoBitcoins extends BaseNumbers[NanoBitcoins] { require(underlying <= LnPolicy.maxNanoBitcoins, "Number was too big for NanoBitcoins, got: " + underlying) - override def toString: String = - s"${underlying / toPicoBitcoinMultiplier} nBTC" } } @@ -220,7 +216,6 @@ object PicoBitcoins extends BaseNumbers[PicoBitcoins] { require(underlying <= LnPolicy.maxPicoBitcoins, "Number was too big for PicoBitcoins, got: " + underlying) - override def toString: String = s"$toBigInt pBTC" } } diff --git a/core/src/main/scala/org/bitcoins/core/protocol/ln/currency/MilliSatoshis.scala b/core/src/main/scala/org/bitcoins/core/protocol/ln/currency/MilliSatoshis.scala index e7bd431014..8941b61956 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/ln/currency/MilliSatoshis.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/ln/currency/MilliSatoshis.scala @@ -27,7 +27,11 @@ sealed abstract class MilliSatoshis * 10 msat * }}} */ - override def toString: String = s"$toBigInt msat" + override def toString: String = { + val num = toBigInt + val postFix = if (num == 1) "msat" else "msats" + s"$num $postFix" + } def toBigInt: BigInt = underlying diff --git a/core/src/main/scala/org/bitcoins/core/protocol/ln/currency/package.scala b/core/src/main/scala/org/bitcoins/core/protocol/ln/currency/package.scala new file mode 100644 index 0000000000..f7fd459a0e --- /dev/null +++ b/core/src/main/scala/org/bitcoins/core/protocol/ln/currency/package.scala @@ -0,0 +1,81 @@ +package org.bitcoins.core.protocol.ln + +// We extend AnyVal to avoid runtime allocation of new +// objects. See the Scala documentation on value classes +// and universal traits for more: +// https://docs.scala-lang.org/overviews/core/value-classes.html +package object currency { + + /** Provides natural language syntax for millisatoshis */ + implicit class MilliSatoshisInt(private val i: Int) extends AnyVal { + def millisatoshis: MilliSatoshis = MilliSatoshis(i) + def millisatoshi: MilliSatoshis = millisatoshis + def msats: MilliSatoshis = millisatoshis + def msat: MilliSatoshis = millisatoshis + } + + /** Provides natural language syntax for millisatoshis */ + implicit class MilliSatoshisLong(private val i: Long) extends AnyVal { + def millisatoshis: MilliSatoshis = MilliSatoshis(i) + def millisatoshi: MilliSatoshis = millisatoshis + def msats: MilliSatoshis = millisatoshis + def msat: MilliSatoshis = millisatoshis + } + + /** Provides natural language syntax for millibitcoins */ + implicit class MilliBitcoinsInt(private val i: Int) extends AnyVal { + def millibitcoins: MilliBitcoins = MilliBitcoins(i) + def millibitcoin: MilliBitcoins = millibitcoins + def mBTC: MilliBitcoins = millibitcoins + } + + /** Provides natural language syntax for millibitcoins */ + implicit class MilliBitcoinsLong(private val i: Long) extends AnyVal { + def millibitcoins: MilliBitcoins = MilliBitcoins(i) + def millibitcoin: MilliBitcoins = millibitcoins + def mBTC: MilliBitcoins = millibitcoins + } + + /** Provides natural language syntax for microbitcoins */ + implicit class MicroBitcoinsInt(private val i: Int) extends AnyVal { + def microbitcoins: MicroBitcoins = MicroBitcoins(i) + def microbitcoin: MicroBitcoins = microbitcoins + def uBTC: MicroBitcoins = microbitcoins + } + + /** Provides natural language syntax for microbitcoins */ + implicit class MicroBitcoinsLong(private val i: Long) extends AnyVal { + def microbitcoins: MicroBitcoins = MicroBitcoins(i) + def microbitcoin: MicroBitcoins = microbitcoins + def uBTC: MicroBitcoins = microbitcoins + } + + /** Provides natural language syntax for nanobitcoins */ + implicit class NanoBitcoinsInt(private val i: Int) extends AnyVal { + def nanobitcoins: NanoBitcoins = NanoBitcoins(i) + def nanobitcoin: NanoBitcoins = nanobitcoins + def nBTC: NanoBitcoins = nanobitcoins + } + + /** Provides natural language syntax for nanobitcoins */ + implicit class NanoBitcoinsLong(private val i: Long) extends AnyVal { + def nanobitcoins: NanoBitcoins = NanoBitcoins(i) + def nanobitcoin: NanoBitcoins = nanobitcoins + def nBTC: NanoBitcoins = nanobitcoins + } + + /** Provides natural language syntax for picobitcoins */ + implicit class PicoitcoinsInt(private val i: Int) extends AnyVal { + def picobitcoins: PicoBitcoins = PicoBitcoins(i) + def picobitcoin: PicoBitcoins = picobitcoins + def pBTC: PicoBitcoins = picobitcoins + } + + /** Provides natural language syntax for picobitcoins */ + implicit class PicoitcoinsLong(private val i: Long) extends AnyVal { + def picobitcoins: PicoBitcoins = PicoBitcoins(i) + def picobitcoin: PicoBitcoins = picobitcoins + def pBTC: PicoBitcoins = picobitcoins + } + +}