package com.mygeopay.core.coins; import com.google.common.base.Charsets; import com.mygeopay.core.util.MonetaryFormat; import org.bitcoinj.core.Address; import org.bitcoinj.core.AddressFormatException; import org.bitcoinj.core.Coin; import org.bitcoinj.core.NetworkParameters; import org.bitcoinj.crypto.ChildNumber; import org.bitcoinj.crypto.HDUtils; import java.io.Serializable; import java.math.BigInteger; import java.util.List; import javax.annotation.Nullable; import javax.xml.soap.MessageFactory; import static com.google.common.base.Preconditions.checkNotNull; /** * @author John L. Jegutanis */ abstract public class CoinType extends NetworkParameters implements ValueType, Serializable { private static final long serialVersionUID = 1L; private static final String BIP_44_KEY_PATH = "44H/%dH/%dH"; protected String name; protected String fullname; protected String symbol; protected String uriScheme; protected Integer bip44Index; protected Integer unitExponent; protected Value feePerKb; protected Value minNonDust; protected Value softDustLimit; protected SoftDustPolicy softDustPolicy; protected FeePolicy feePolicy = FeePolicy.FEE_PER_KB; protected byte[] signedMessageHeader; private transient MonetaryFormat friendlyFormat; private transient MonetaryFormat plainFormat; private transient Value oneCoin; @Override public String getName() { return checkNotNull(name, "A coin failed to set a name"); } public String getFullname() {return checkNotNull(fullname, "A coin failed to set a name");} public boolean isTestnet() { return id.endsWith("test");} @Override public String getSymbol() { return checkNotNull(symbol, "A coin failed to set a symbol"); } public String getUriScheme() { return checkNotNull(uriScheme, "A coin failed to set a URI scheme"); } public int getBip44Index() { return checkNotNull(bip44Index, "A coin failed to set a BIP 44 index"); } @Override public int getUnitExponent() { return checkNotNull(unitExponent, "A coin failed to set a unit exponent"); } /** * @deprecated kept for backward compatibility * @return */ @Deprecated public Coin getFeePerKb() { return feePerKb().toCoin(); } public Value feePerKb() { return checkNotNull(feePerKb, "A coin failed to set a fee per kilobyte"); } /** * @deprecated kept for backward compatibility * @return */ @Deprecated public Coin getMinNonDust() { return minNonDust().toCoin(); } @Override public Value minNonDust() { return checkNotNull(minNonDust, "A coin failed to set a minimum amount to be considered not dust"); } /** * @deprecated kept for backward compatibility * @return */ @Deprecated public Coin getSoftDustLimit() { return softDustLimit().toCoin(); } public Value softDustLimit() { return checkNotNull(softDustLimit, "A coin failed to set a soft dust limit"); } public SoftDustPolicy getSoftDustPolicy() { return checkNotNull(softDustPolicy, "A coin failed to set a soft dust policy"); } public FeePolicy getFeePolicy() { return checkNotNull(feePolicy, "A coin failed to set a fee policy"); } public byte[] getSignedMessageHeader() { return checkNotNull(signedMessageHeader, "A coin failed to set signed message header bytes"); } public boolean canSignVerifyMessages() { return signedMessageHeader != null; } public boolean canHandleMessages() { return getMessagesFactory() != null; } @Nullable public MessageFactory getMessagesFactory() { return null; } protected static byte[] toBytes(String str) { return str.getBytes(Charsets.UTF_8);} public List<ChildNumber> getBip44Path(int account) { String path = String.format(BIP_44_KEY_PATH, bip44Index, account); return HDUtils.parsePath(path); } public Address address(String addressStr) throws AddressFormatException { return new Address(this, addressStr); } /** * @deprecated kept for backward compatibility * Returns a 1 coin of this type with the correct amount of units (satoshis) * Use {@linkcom.mygeopay.core.coins.CoinType:oneCoin} */ @Deprecated public Coin getOneCoin() { BigInteger units = BigInteger.TEN.pow(getUnitExponent()); return Coin.valueOf(units.longValue()); } @Override public Value oneCoin() { if (oneCoin == null) { BigInteger units = BigInteger.TEN.pow(getUnitExponent()); oneCoin = Value.valueOf(this, units.longValue()); } return oneCoin; } @Override public Value value(String string) { return Value.parse(this, string); } @Override public Value value(Coin coin) { return Value.valueOf(this, coin); } @Override public Value value(long units) { return Value.valueOf(this, units); } @Override public String getPaymentProtocolId() { throw new RuntimeException("Method not implemented"); } @Override public String toString() { return "Coin{" + "name='" + name + '\'' + ", symbol='" + symbol + '\'' + ", bip44Index=" + bip44Index + '}'; } @Override public MonetaryFormat getMonetaryFormat() { if (friendlyFormat == null) { friendlyFormat = new MonetaryFormat() .shift(0).minDecimals(2).code(0, symbol).postfixCode(); switch (unitExponent) { case 8: friendlyFormat = friendlyFormat.optionalDecimals(2, 2, 2); break; case 6: friendlyFormat = friendlyFormat.optionalDecimals(2, 2); break; case 4: friendlyFormat = friendlyFormat.optionalDecimals(2); break; default: friendlyFormat = friendlyFormat.minDecimals(unitExponent); } } return friendlyFormat; } @Override public MonetaryFormat getPlainFormat() { if (plainFormat == null) { plainFormat = new MonetaryFormat().shift(0) .minDecimals(0).repeatOptionalDecimals(1, unitExponent).noCode(); } return plainFormat; } @Override public boolean isEquals(ValueType obj) { return super.equals(obj); } }