Skip to content

Commit

Permalink
Merge pull request #61 from twostack/interpreter-v2
Browse files Browse the repository at this point in the history
Interpreter v2. 

Ignoring CI. Local test build passes. CI has old incompatible dart compiler.
  • Loading branch information
stephanfeb authored Aug 17, 2023
2 parents bdd023f + 45ab90c commit 2038af2
Show file tree
Hide file tree
Showing 41 changed files with 5,735 additions and 4,639 deletions.
2 changes: 1 addition & 1 deletion lib/dartsv.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ export 'src/block/blockheader.dart';
export 'src/block/merkleblock.dart';
export 'src/script/svscript.dart';
export 'src/script/opcodes.dart';
export 'src/script/interpreter.dart';
export 'src/script/stack.dart';
export 'src/script/script_error.dart';
export 'src/script/script_chunk.dart';
Expand All @@ -41,6 +40,7 @@ export 'src/transaction/p2sh_builder.dart';
export 'src/transaction/unspendable_data_builder.dart';
export 'src/encoding/utils.dart';
export 'src/exceptions.dart';
export 'src/coin.dart';
export 'src/crypto/ecies.dart';


333 changes: 333 additions & 0 deletions lib/src/coin.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,333 @@
import 'dart:math';

import 'package:dartsv/src/transaction/preconditions.dart';
import 'package:decimal/decimal.dart';

/**
* Represents a monetary Bitcoin value. This class is immutable.
*/
class Coin {

/**
* The number of satoshis of this monetary value.
*/
BigInt _satoshis;

Coin(this._satoshis);

/**
* Number of decimals for one Bitcoin. This constant is useful for quick adapting to other coins because a lot of
* constants derive from it.
*/
static final int SMALLEST_UNIT_EXPONENT = 8;


/**
* The number of satoshis equal to one bitcoin.
*/
static final BigInt COIN_VALUE = BigInt.from(pow(10, SMALLEST_UNIT_EXPONENT));

/**
* Zero Bitcoins.
*/
static final Coin ZERO = valueOf(BigInt.zero);

/**
* One Bitcoin.
*/
static final Coin COIN = Coin.valueOf(COIN_VALUE);

/**
* 0.01 Bitcoins. This unit is not really used much.
*/
static final Coin CENT = COIN.divide(BigInt.from(100));

/**
* 0.001 Bitcoins, also known as 1 mBTC.
*/
static final Coin MILLICOIN = COIN.divide(BigInt.from(1000));

/**
* 0.000001 Bitcoins, also known as 1 µBTC or 1 uBTC.
*/
static final Coin MICROCOIN = MILLICOIN.divide(BigInt.from(1000));

/**
* A satoshi is the smallest unit that can be transferred. 100 million of them fit into a Bitcoin.
*/
static final Coin SATOSHI = Coin.valueOf(BigInt.one);

static final Coin FIFTY_COINS = COIN.multiply(50);

/**
* Represents a monetary value of minus one satoshi.
*/
static final Coin NEGATIVE_SATOSHI = Coin.valueOf(-BigInt.one);


static Coin valueOf(final BigInt satoshis) {
return Coin(satoshis);
}


int smallestUnitExponent() {
return SMALLEST_UNIT_EXPONENT;
}

/**
* Returns the number of satoshis of this monetary value.
*/

BigInt getValue() {
return this._satoshis;
}

/**
* Convert an amount expressed in the way humans are used to into satoshis.
*/
// static Coin valueOf(final int coins, final int cents) {
// Preconditions.assertTrue(cents < 100);
// Preconditions.assertTrue(cents >= 0);
// Preconditions.assertTrue(coins >= 0);
// final Coin coin = COIN.multiply(coins).add(CENT.multiply(cents));
// return coin;
// }

/**<p>
* Parses an amount expressed in the way humans are used to.
* </p>
* This takes string in a format understood by {@link BigDecimal#BigDecimal(String)},
* for example "0", "1", "0.10", "1.23E3", "1234.5E-5".
*
* @throws IllegalArgumentException if you try to specify fractional satoshis, or a value out of range.
*/
static Coin parseCoin(final String str) {
try {
BigInt satoshis = Decimal.parse(str)
.shift(SMALLEST_UNIT_EXPONENT)
.toBigInt();
return Coin.valueOf(satoshis);
} on FormatException catch (e) {
throw ArgumentError(e); // Repackage exception to honor method contract
}
}

/**
* Convert a decimal amount of BTC into satoshis.
*
* @param coins number of coins
* @return number of satoshis
*/
static BigInt btcToSatoshi(Decimal coins) {
return coins.shift(SMALLEST_UNIT_EXPONENT).toBigInt();
}

/**
* Convert an amount in satoshis to an amount in BTC.
*
* @param satoshis number of satoshis
* @return number of bitcoins (in BTC)
*/
static Decimal satoshiToBtc(BigInt satoshis) {
return new Decimal.fromBigInt(satoshis).shift(SMALLEST_UNIT_EXPONENT);
}

/**
* Create a {@code Coin} from a decimal amount of BTC.
*
* @param coins number of coins (in BTC)
* @return {@code Coin} object containing value in satoshis
*/
static Coin ofBtc(Decimal coins) {
return Coin.valueOf(btcToSatoshi(coins));
}

/**
* Create a {@code Coin} from a int integer number of satoshis.
*
* @param satoshis number of satoshis
* @return {@code Coin} object containing value in satoshis
*/
static Coin ofSat(BigInt satoshis) {
return Coin.valueOf(satoshis);
}


/**
* Convert to number of bitcoin (in BTC)
*
* @return decimal number of bitcoin (in BTC)
*/
Decimal toBtc() {
return satoshiToBtc(this._satoshis);
}

/**
* Create a {@code Coin} by parsing a {@code String} amount expressed in "the way humans are used to".
* The amount is cut to satoshi precision.
*
* @param str string in a format understood by {@link BigDecimal#BigDecimal(String)}, for example "0", "1", "0.10",
* * "1.23E3", "1234.5E-5".
* @return {@code Coin} object containing value in satoshis
* @throws IllegalArgumentException
* if you try to specify a value out of range.
*/
static Coin parseCoinInexact(final String str) {
try {
BigInt satoshis = Decimal.parse(str)
.shift(SMALLEST_UNIT_EXPONENT)
.toBigInt();
return Coin.valueOf(satoshis);
} on FormatException catch (e) {
throw new ArgumentError(e); // Repackage exception to honor method contract
}
}

Coin add(final Coin value) {
return Coin(this._satoshis + value.getValue());
}

/** Alias for add */
Coin plus(Coin value) {
return add(value);
}

Coin subtract(final Coin value) {
return Coin(this._satoshis - value.getValue());
}

/** Alias for subtract */
Coin minus(final Coin value) {
return subtract(value);
}

Coin multiply(final int factor) {
return Coin(this._satoshis * BigInt.from(factor));
}

/** Alias for multiply */
Coin times(final int factor) {
return multiply(factor);
}

/** Alias for multiply */
// Coin times(final int factor) {
// return multiply(factor);
// }

Coin divide(final BigInt divisor) {
return Coin(this._satoshis ~/ divisor);
}

/** Alias for divide */
Coin div(final BigInt divisor) {
return divide(divisor);
}

List<Coin> divideAndRemainder(final BigInt divisor) {
return [ divide(divisor) , Coin(this._satoshis % divisor) ];
}

// int divide(final Coin divisor) {
// return this.value / divisor.value;
// }

/**
* Returns true if and only if this instance represents a monetary value greater than zero,
* otherwise false.
*/
bool isPositive() {
return !_satoshis.isNegative;
}

/**
* Returns true if and only if this instance represents a monetary value less than zero,
* otherwise false.
*/
bool isNegative() {
return _satoshis.isNegative;
}

/**
* Returns true if and only if this instance represents zero monetary value,
* otherwise false.
*/
bool isZero() {
return _satoshis == BigInt.zero;
}

/**
* Returns true if the monetary value represented by this instance is greater than that
* of the given other Coin, otherwise false.
*/
bool isGreaterThan(Coin other) {
return compareTo(other) > 0;
}

/**
* Returns true if the monetary value represented by this instance is less than that
* of the given other Coin, otherwise false.
*/
bool isLessThan(Coin other) {
return compareTo(other) < 0;
}

Coin shiftLeft(final int n) {
return Coin(this._satoshis << n);
}

Coin shiftRight(final int n) {
return new Coin(this._satoshis >> n);
}


Coin negate() {
return new Coin(-this._satoshis);
}

/**
* Returns the number of satoshis of this monetary value. It's deprecated in favour of accessing {@link #value}
* directly.
*/
int longValue() {
return this._satoshis.toInt();
}

// static final MonetaryFormat FRIENDLY_FORMAT = MonetaryFormat
// .BTC
// .minDecimals(2)
// .repeatOptionalDecimals(1, 6)
// .postfixCode();

/**
* Returns the value as a 0.12 type string. More digits after the decimal place will be used
* if necessary, but two will always be present.
*/
// String toFriendlyString() {
// return FRIENDLY_FORMAT.format(this).toString();
// }
//
// static final MonetaryFormat PLAIN_FORMAT = MonetaryFormat.BTC.minDecimals(0)
// .repeatOptionalDecimals(1, 8)
// .noCode();

/**
* <p>
* Returns the value as a plain string denominated in BTC.
* The result is unformatted with no trailing zeroes.
* For instance, a value of 150000 satoshis gives an output string of "0.0015" BTC
* </p>
*/
// String toPlainString() {
// return PLAIN_FORMAT.format(this).toString();
// }


String toString() {
return this._satoshis.toString();
}

int compareTo(final Coin other) {
return this._satoshis.compareTo(other.getValue());
}
}
Loading

0 comments on commit 2038af2

Please sign in to comment.