Updated on 2026-08-14

This commit is contained in:
Tangem 2018-10-30 12:25:49 +03:00
parent f2fc3e9886
commit e122ccd0eb
20 changed files with 615 additions and 472 deletions

View file

@ -585,10 +585,16 @@ public class CardProtocol {
mCard.setWalletPublicKey(pkUncompressed);
mCard.setWalletPublicKeyRar(pkCompresses);
TangemContext ctx=new TangemContext(mCard);
CoinEngine engineCoin = CoinEngineFactory.create(ctx);
String wallet = engineCoin.calculateAddress(pkUncompressed);
mCard.setWallet(wallet);
TangemContext ctx = new TangemContext(mCard);
try {
CoinEngine engineCoin = CoinEngineFactory.create(ctx);
if( engineCoin==null ) throw new Exception("Can't create CoinEngine!");
String wallet = engineCoin.calculateAddress(pkUncompressed);
mCard.setWallet(wallet);
} catch (Exception e) {
e.printStackTrace();
throw new TangemException("Can't define wallet address");
}
//mCard.setWallet(Blockchain.calculateWalletAddress(mCard, pkUncompressed));
mCard.setRemainingSignatures(readResult.getTagAsInt(TLV.Tag.TAG_RemainingSignatures));

View file

@ -56,11 +56,7 @@ public class BalanceValidator {
TangemCard card=ctx.getCard();
CoinEngine engine=CoinEngineFactory.create(ctx);
if (ctx.getBlockchain() == Blockchain.Bitcoin || ctx.getBlockchain() == Blockchain.BitcoinTestNet) {
if( !engine.validateBalance(this) ) return;
} else if ((card.getBlockchain() == Blockchain.Ethereum) || (card.getBlockchain() == Blockchain.Token)) {
}
if( !engine.validateBalance(this) ) return;
// Verify card?
if (attest) {

View file

@ -19,13 +19,13 @@ public enum Blockchain {
Blockchain(String ID, String currency, double multiplier, int imageResource, String officialName) {
mID = ID;
mCurrency = currency;
mMultiplier = multiplier;
// mMultiplier = multiplier;
mImageResource = imageResource;
mOfficialName = officialName;
}
private String mID, mOfficialName;
private double mMultiplier;
//private double mMultiplier;
private String mCurrency;
private int mImageResource;
@ -37,9 +37,9 @@ public enum Blockchain {
return mOfficialName;
}
public double getMultiplier() {
return mMultiplier;
}
// public double getMultiplier() {
// return mMultiplier;
// }
public String getCurrency() {
return mCurrency;

View file

@ -13,6 +13,7 @@ import com.tangem.util.FormatUtil;
import com.tangem.util.Util;
import java.io.ByteArrayOutputStream;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.security.NoSuchAlgorithmException;
@ -27,15 +28,15 @@ import java.util.List;
public class BtcCashEngine extends CoinEngine {
public BtcData btcData = null;
public BtcData coinData = null;
public BtcCashEngine(TangemContext context) throws Exception {
super(context);
if (context.getCoinData() == null) {
btcData = new BtcData();
context.setCoinData(btcData);
coinData = new BtcData();
context.setCoinData(coinData);
} else if (context.getCoinData() instanceof BtcData) {
btcData = (BtcData) context.getCoinData();
coinData = (BtcData) context.getCoinData();
} else {
throw new Exception("Invalid type of Blockchain data for BtcEngine");
}
@ -45,21 +46,25 @@ public class BtcCashEngine extends CoinEngine {
}
private static int getDecimals() {
return 8;
}
private void checkBlockchainDataExists() throws Exception {
if (btcData == null) throw new Exception("No blockchain data");
if (coinData == null) throw new Exception("No blockchain data");
}
@Override
public boolean awaitingConfirmation(){
if( btcData==null ) return false;
return btcData.getBalanceUnconfirmed() != 0;
if( coinData ==null ) return false;
return coinData.getBalanceUnconfirmed() != 0;
}
@Override
public String getBalanceHTML() {
if (hasBalanceInfo()) {
Amount balance = convertToAmount(btcData.getBalanceInInternalUnits());
return balance.toString();
Amount balance=getBalance();
if( balance!=null ) {
return balance.toDescriptionString(getDecimals());
} else {
return "";
}
@ -67,7 +72,14 @@ public class BtcCashEngine extends CoinEngine {
@Override
public String getBalanceCurrencyHTML() {
return "mBCH";
return "BTH";
}
@Override
public String getOfflineBalanceHTML() {
InternalAmount offlineInternalAmount = convertToInternalAmount(ctx.getCard().getOfflineBalance());
Amount offlineAmount = convertToAmount(offlineInternalAmount);
return offlineAmount.toDescriptionString(getDecimals());
}
@Override
@ -78,30 +90,21 @@ public class BtcCashEngine extends CoinEngine {
@Override
public boolean isBalanceNotZero() {
if( btcData==null ) return false;
if (btcData.getBalanceInInternalUnits() == null) return false;
return btcData.getBalanceInInternalUnits().notZero();
}
@Override
public boolean checkAmount(Amount amount) throws Exception {
checkBlockchainDataExists();
if (amount.compareTo(convertToAmount(btcData.getBalanceInInternalUnits())) > 0) {
return false;
}
return true;
if( coinData ==null ) return false;
if (coinData.getBalanceInInternalUnits() == null) return false;
return coinData.getBalanceInInternalUnits().notZero();
}
@Override
public boolean hasBalanceInfo(){
if( btcData==null ) return false;
return btcData.hasBalanceInfo();
if( coinData ==null ) return false;
return coinData.hasBalanceInfo();
}
@Override
public boolean checkUnspentTransaction() throws Exception {
checkBlockchainDataExists();
return btcData.getUnspentTransactions().size() != 0;
return coinData.getUnspentTransactions().size() != 0;
}
@Override
@ -173,18 +176,27 @@ public class BtcCashEngine extends CoinEngine {
@Override
public InputFilter[] getAmountInputFilters() {
return new InputFilter[] { new DecimalDigitsInputFilter(8) };
return new InputFilter[] { new DecimalDigitsInputFilter(getDecimals()) };
}
@Override
public boolean checkAmountValue(String amountValue, String feeValue, InternalAmount minFeeInInternalUnits, Boolean isIncludeFee) {
public boolean checkNewTransactionAmount(Amount amount){
if( coinData ==null ) return false;
if (amount.compareTo(convertToAmount(coinData.getBalanceInInternalUnits())) > 0) {
return false;
}
return true;
}
@Override
public boolean checkNewTransactionAmountAndFee(Amount amountValue, Amount feeValue, Boolean isIncludeFee, InternalAmount minFeeInInternalUnits) {
InternalAmount fee;
InternalAmount amount;
try {
checkBlockchainDataExists();
amount = convertToInternalAmount(new Amount(amountValue, ctx.getBlockchain()));
fee = convertToInternalAmount(new Amount(feeValue, ctx.getBlockchain()));
amount = convertToInternalAmount(amountValue);
fee = convertToInternalAmount(feeValue);
} catch (Exception e) {
e.printStackTrace();
return false;
@ -196,10 +208,10 @@ public class BtcCashEngine extends CoinEngine {
if (fee.isZero() || amount.isZero())
return false;
if (isIncludeFee && amount.compareTo(btcData.getBalanceInInternalUnits())>0)
if (isIncludeFee && amount.compareTo(coinData.getBalanceInInternalUnits())>0)
return false;
if (!isIncludeFee && amount.add(fee).compareTo(btcData.getBalanceInInternalUnits())>0)
if (!isIncludeFee && amount.add(fee).compareTo(coinData.getBalanceInInternalUnits())>0)
return false;
return true;
@ -222,18 +234,18 @@ public class BtcCashEngine extends CoinEngine {
// return;
// }
if (btcData.getBalanceUnconfirmed() != 0) {
if (coinData.getBalanceUnconfirmed() != 0) {
balanceValidator.setScore(0);
balanceValidator.setFirstLine("Transaction in progress");
balanceValidator.setSecondLine("Wait for confirmation in blockchain");
return false;
}
if (btcData.isBalanceReceived() && btcData.isBalanceEqual()) {
if (coinData.isBalanceReceived() && coinData.isBalanceEqual()) {
balanceValidator.setScore(100);
balanceValidator.setFirstLine("Verified balance");
balanceValidator.setSecondLine("Balance confirmed in blockchain");
if (btcData.getBalanceInInternalUnits().isZero()) {
if (coinData.getBalanceInInternalUnits().isZero()) {
balanceValidator.setFirstLine("Empty wallet");
balanceValidator.setSecondLine("");
}
@ -248,7 +260,7 @@ public class BtcCashEngine extends CoinEngine {
// return;
// }
if ((ctx.getCard().getOfflineBalance() != null) && !btcData.isBalanceReceived() && (ctx.getCard().getRemainingSignatures() == ctx.getCard().getMaxSignatures()) && btcData.getBalanceInInternalUnits().notZero() ) {
if ((ctx.getCard().getOfflineBalance() != null) && !coinData.isBalanceReceived() && (ctx.getCard().getRemainingSignatures() == ctx.getCard().getMaxSignatures()) && coinData.getBalanceInInternalUnits().notZero() ) {
balanceValidator.setScore(80);
balanceValidator.setFirstLine("Verified offline balance");
balanceValidator.setSecondLine("Can't obtain balance from blockchain. Restore internet connection to be more confident. ");
@ -274,7 +286,7 @@ public class BtcCashEngine extends CoinEngine {
@Override
public Amount getBalance() {
return convertToAmount(btcData.getBalanceInInternalUnits());
return convertToAmount(coinData.getBalanceInInternalUnits());
}
@Override
@ -284,8 +296,8 @@ public class BtcCashEngine extends CoinEngine {
@Override
public String getBalanceEquivalent() {
if( btcData==null ) return "";
return btcData.getAmountEquivalentDescription(getBalance());
if( coinData ==null || !coinData.getAmountEquivalentDescriptionAvailable() ) return "";
return getBalance().toEquivalentString(coinData.getRate());
}
@Override
@ -325,12 +337,19 @@ public class BtcCashEngine extends CoinEngine {
@Override
public Amount convertToAmount(InternalAmount internalAmount) {
return null;
BigDecimal d=internalAmount.divide(new BigDecimal("100000000"));
return new Amount(d, getBalanceCurrencyHTML());
}
@Override
public Amount convertToAmount(String strAmount, String currency) {
return new Amount(strAmount, currency);
}
@Override
public InternalAmount convertToInternalAmount(Amount amount) throws Exception {
return null;
BigDecimal d=amount.multiply(new BigDecimal("100000000"));
return new InternalAmount(d, getBalanceCurrencyHTML());
}
@Override
@ -338,7 +357,7 @@ public class BtcCashEngine extends CoinEngine {
if (bytes == null) return null;
byte[] reversed = new byte[bytes.length];
for (int i = 0; i < bytes.length; i++) reversed[i] = bytes[bytes.length - i - 1];
return new InternalAmount(Util.byteArrayToLong(reversed));
return new InternalAmount(Util.byteArrayToLong(reversed),"Satoshi");
}
@Override
@ -356,7 +375,7 @@ public class BtcCashEngine extends CoinEngine {
@Override
public String getUnspentInputsDescription() {
return btcData.getUnspentInputsDescription();
return coinData.getUnspentInputsDescription();
}
// @Override
@ -372,8 +391,9 @@ public class BtcCashEngine extends CoinEngine {
}
}
public String getAmountEquivalentDescriptor(TangemCard mCard, String value) {
return getAmountEquivalentDescriptionBTC(Double.parseDouble(value), btcData.getRate());
public String getAmountEquivalentDescriptor(TangemCard card, String value) {
return getAmountEquivalentDescriptionBTC(Double.parseDouble(value), coinData.getRate());
}
@Override
@ -387,7 +407,7 @@ public class BtcCashEngine extends CoinEngine {
String changeAddress = myAddress;
// Build script for our address
List<BtcData.UnspentTransaction> rawTxList = btcData.getUnspentTransactions();
List<BtcData.UnspentTransaction> rawTxList = coinData.getUnspentTransactions();
byte[] outputScriptWeAreAbleToSpend = Transaction.Script.buildOutput(myAddress).bytes;
// Collect unspent
@ -409,7 +429,7 @@ public class BtcCashEngine extends CoinEngine {
}
if (amount + fees > fullAmount) {
throw new CardProtocol.TangemException_WrongAmount(String.format("Balance (%d) < amount (%d) + (%d)", fullAmount, change, amount));
throw new CardProtocol.TangemException_WrongAmount(String.format("Balance (%d) < change (%d) + amount (%d)", fullAmount, change, amount));
}
byte[][] dataForSign = new byte[unspentOutputs.size()][];

View file

@ -101,7 +101,7 @@ public class BtcData extends CoinData {
}
public CoinEngine.InternalAmount getBalanceInInternalUnits() {
return new CoinEngine.InternalAmount(BigDecimal.valueOf(balanceConfirmed).add(BigDecimal.valueOf(balanceUnconfirmed)));
return new CoinEngine.InternalAmount(BigDecimal.valueOf(balanceConfirmed).add(BigDecimal.valueOf(balanceUnconfirmed)),"Satoshi");
}
public Long getBalanceUnconfirmed() {

View file

@ -15,6 +15,7 @@ import com.tangem.util.FormatUtil;
import com.tangem.util.Util;
import java.io.ByteArrayOutputStream;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.security.NoSuchAlgorithmException;
@ -25,15 +26,15 @@ import java.util.List;
public class BtcEngine extends CoinEngine {
public BtcData btcData = null;
public BtcData coinData = null;
public BtcEngine(TangemContext context) throws Exception {
super(context);
if (context.getCoinData() == null) {
btcData = new BtcData();
context.setCoinData(btcData);
coinData = new BtcData();
context.setCoinData(coinData);
} else if (context.getCoinData() instanceof BtcData) {
btcData = (BtcData) context.getCoinData();
coinData = (BtcData) context.getCoinData();
} else {
throw new Exception("Invalid type of Blockchain data for BtcEngine");
}
@ -43,6 +44,10 @@ public class BtcEngine extends CoinEngine {
super();
}
private static int getDecimals() {
return 8;
}
private static String[] getBitcoinServiceHosts() {
return new String[]{
BitcoinNode.n1.getHost(),
@ -96,20 +101,20 @@ public class BtcEngine extends CoinEngine {
static int serviceIndex = 0;
private void checkBlockchainDataExists() throws Exception {
if (btcData == null) throw new Exception("No blockchain data");
if (coinData == null) throw new Exception("No blockchain data");
}
@Override
public boolean awaitingConfirmation(){
if( btcData==null ) return false;
return btcData.getBalanceUnconfirmed() != 0;
if( coinData ==null ) return false;
return coinData.getBalanceUnconfirmed() != 0;
}
@Override
public String getBalanceHTML() {
Amount balance=getBalance();
if( balance!=null ) {
return balance.toString();
return balance.toDescriptionString(getDecimals());
}else{
return "";
}
@ -124,7 +129,7 @@ public class BtcEngine extends CoinEngine {
public String getOfflineBalanceHTML() {
InternalAmount offlineInternalAmount = convertToInternalAmount(ctx.getCard().getOfflineBalance());
Amount offlineAmount = convertToAmount(offlineInternalAmount);
return offlineAmount.toString();
return offlineAmount.toDescriptionString(getDecimals());
}
@Override
@ -134,22 +139,22 @@ public class BtcEngine extends CoinEngine {
@Override
public boolean isBalanceNotZero() {
if( btcData==null ) return false;
if (btcData.getBalanceInInternalUnits() == null) return false;
return btcData.getBalanceInInternalUnits().notZero();
if( coinData ==null ) return false;
if (coinData.getBalanceInInternalUnits() == null) return false;
return coinData.getBalanceInInternalUnits().notZero();
}
@Override
public boolean hasBalanceInfo(){
if( btcData==null ) return false;
return btcData.hasBalanceInfo();
if( coinData ==null ) return false;
return coinData.hasBalanceInfo();
}
@Override
public boolean checkUnspentTransaction() throws Exception {
checkBlockchainDataExists();
return btcData.getUnspentTransactions().size() != 0;
return coinData.getUnspentTransactions().size() != 0;
}
@Override
@ -226,13 +231,13 @@ public class BtcEngine extends CoinEngine {
@Override
public InputFilter[] getAmountInputFilters() {
return new InputFilter[] { new DecimalDigitsInputFilter(8) };
return new InputFilter[] { new DecimalDigitsInputFilter(getDecimals()) };
}
@Override
public boolean checkNewTransactionAmount(Amount amount){
if( btcData==null ) return false;
if (amount.compareTo(convertToAmount(btcData.getBalanceInInternalUnits())) > 0) {
if( coinData ==null ) return false;
if (amount.compareTo(convertToAmount(coinData.getBalanceInInternalUnits())) > 0) {
return false;
}
return true;
@ -258,10 +263,10 @@ public class BtcEngine extends CoinEngine {
if (fee.isZero() || amount.isZero())
return false;
if (isIncludeFee && amount.compareTo(btcData.getBalanceInInternalUnits())>0)
if (isIncludeFee && amount.compareTo(coinData.getBalanceInInternalUnits())>0)
return false;
if (!isIncludeFee && amount.add(fee).compareTo(btcData.getBalanceInInternalUnits())>0)
if (!isIncludeFee && amount.add(fee).compareTo(coinData.getBalanceInInternalUnits())>0)
return false;
return true;
@ -284,18 +289,18 @@ public class BtcEngine extends CoinEngine {
// return;
// }
if (btcData.getBalanceUnconfirmed() != 0) {
if (coinData.getBalanceUnconfirmed() != 0) {
balanceValidator.setScore(0);
balanceValidator.setFirstLine("Transaction in progress");
balanceValidator.setSecondLine("Wait for confirmation in blockchain");
return false;
}
if (btcData.isBalanceReceived() && btcData.isBalanceEqual()) {
if (coinData.isBalanceReceived() && coinData.isBalanceEqual()) {
balanceValidator.setScore(100);
balanceValidator.setFirstLine("Verified balance");
balanceValidator.setSecondLine("Balance confirmed in blockchain");
if (btcData.getBalanceInInternalUnits().isZero()) {
if (coinData.getBalanceInInternalUnits().isZero()) {
balanceValidator.setFirstLine("Empty wallet");
balanceValidator.setSecondLine("");
}
@ -310,7 +315,7 @@ public class BtcEngine extends CoinEngine {
// return;
// }
if ((ctx.getCard().getOfflineBalance() != null) && !btcData.isBalanceReceived() && (ctx.getCard().getRemainingSignatures() == ctx.getCard().getMaxSignatures()) && btcData.getBalanceInInternalUnits().notZero() ) {
if ((ctx.getCard().getOfflineBalance() != null) && !coinData.isBalanceReceived() && (ctx.getCard().getRemainingSignatures() == ctx.getCard().getMaxSignatures()) && coinData.getBalanceInInternalUnits().notZero() ) {
balanceValidator.setScore(80);
balanceValidator.setFirstLine("Verified offline balance");
balanceValidator.setSecondLine("Can't obtain balance from blockchain. Restore internet connection to be more confident. ");
@ -336,18 +341,21 @@ public class BtcEngine extends CoinEngine {
@Override
public Amount getBalance() {
return convertToAmount(btcData.getBalanceInInternalUnits());
if( !hasBalanceInfo() ) return null;
return convertToAmount(coinData.getBalanceInInternalUnits());
}
@Override
public String evaluateFeeEquivalent(String fee) {
return getAmountEquivalentDescriptor(ctx.getCard(), fee);
if( !coinData.getAmountEquivalentDescriptionAvailable() ) return "";
Amount feeAmount=new Amount(fee, getFeeCurrencyHTML());
return feeAmount.toEquivalentString(coinData.getRate());
}
@Override
public String getBalanceEquivalent() {
if( btcData==null ) return "";
return btcData.getAmountEquivalentDescription(getBalance());
if( coinData ==null || !coinData.getAmountEquivalentDescriptionAvailable() ) return "";
return getBalance().toEquivalentString(coinData.getRate());
}
@Override
@ -386,20 +394,19 @@ public class BtcEngine extends CoinEngine {
@Override
public Amount convertToAmount(InternalAmount internalAmount) {
//TODO
return null;
BigDecimal d=internalAmount.divide(new BigDecimal("100000000"));
return new Amount(d, getBalanceCurrencyHTML());
}
@Override
public Amount convertToAmount(String strAmount) {
//TODO
return null;
public Amount convertToAmount(String strAmount, String currency) {
return new Amount(strAmount, currency);
}
@Override
public InternalAmount convertToInternalAmount(Amount amount) throws Exception {
//TODO
return null;
BigDecimal d=amount.multiply(new BigDecimal("100000000"));
return new InternalAmount(d, getBalanceCurrencyHTML());
}
@Override
@ -407,7 +414,7 @@ public class BtcEngine extends CoinEngine {
if (bytes == null) return null;
byte[] reversed = new byte[bytes.length];
for (int i = 0; i < bytes.length; i++) reversed[i] = bytes[bytes.length - i - 1];
return new InternalAmount(Util.byteArrayToLong(reversed));
return new InternalAmount(Util.byteArrayToLong(reversed),"Satoshi");
}
@Override
@ -425,25 +432,7 @@ public class BtcEngine extends CoinEngine {
@Override
public String getUnspentInputsDescription() {
return btcData.getUnspentInputsDescription();
}
// @Override
// public String getAmountDescription(TangemCard card, String amount) throws Exception {
// return card.getAmountDescription(Double.parseDouble(amount));
// }
public static String getAmountEquivalentDescriptionBTC(Double amount, float rate) {
if ((rate > 0) && (amount > 0)) {
return String.format("USD%.2f", amount * rate);
} else {
return "";
}
}
public String getAmountEquivalentDescriptor(TangemCard card, String value) {
return getAmountEquivalentDescriptionBTC(Double.parseDouble(value), btcData.getRate());
return coinData.getUnspentInputsDescription();
}
@Override
@ -457,7 +446,7 @@ public class BtcEngine extends CoinEngine {
String changeAddress = myAddress;
// Build script for our address
List<BtcData.UnspentTransaction> rawTxList = btcData.getUnspentTransactions();
List<BtcData.UnspentTransaction> rawTxList = coinData.getUnspentTransactions();
byte[] outputScriptWeAreAbleToSpend = Transaction.Script.buildOutput(myAddress).bytes;
// Collect unspent

View file

@ -7,7 +7,7 @@ import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.concurrent.atomic.AtomicInteger;
public class CoinData {
public abstract class CoinData {
public CoinData() {
}
@ -114,14 +114,6 @@ public class CoinData {
// return output + " " + getBlockchain().getCurrency();
// }
public String getAmountEquivalentDescription(CoinEngine.Amount amount) {
if (getBlockchain() == Blockchain.Ethereum || getBlockchain() == Blockchain.EthereumTestNet || getBlockchain() == Blockchain.Token) {
return EthEngine.getAmountEquivalentDescriptionETH(amount, rate);
}
return BtcEngine.getAmountEquivalentDescriptionBTC(amount.doubleValue(), rate);
}
public boolean getAmountEquivalentDescriptionAvailable() {
return rate > 0;
}

View file

@ -8,8 +8,10 @@ import com.tangem.domain.cardReader.CardProtocol;
import org.jetbrains.annotations.Nullable;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.text.DecimalFormat;
/**
* Created by Ilia on 15.02.2018.
@ -21,20 +23,26 @@ public abstract class CoinEngine {
public static final String EXTRA_ENGINE = "CoinEngine";
public static class InternalAmount extends BigDecimal {
private String currency;
public InternalAmount() {
super(0);
currency="";
}
public InternalAmount(String amountString) {
public InternalAmount(String amountString, String currency) {
super(amountString);
this.currency=currency;
}
public InternalAmount(long amount) {
public InternalAmount(long amount, String currency) {
super(amount);
this.currency=currency;
}
public InternalAmount(BigDecimal amount) {
public InternalAmount(BigDecimal amount, String currency) {
super(amount.unscaledValue(), amount.scale());
this.currency=currency;
}
public boolean notZero()
@ -45,38 +53,42 @@ public abstract class CoinEngine {
public boolean isZero() {
return compareTo(BigDecimal.ZERO)==0;
}
public String getCurrency() {
return currency;
}
}
public static class Amount extends BigDecimal {
private Blockchain blockchain;
private String currency;
public Amount() {
super(0);
blockchain = Blockchain.Unknown;
currency="";
}
public Amount(String amountString, Blockchain blockchain) {
public Amount(String amountString, String currency) {
super(amountString);
this.blockchain = blockchain;
this.currency = currency;
}
public Amount(Long amount, Blockchain blockchain) {
public Amount(Long amount, String currency) {
super(amount);
this.blockchain=blockchain;
this.currency = currency;
}
public Amount(BigDecimal amount, Blockchain blockchain) {
public Amount(BigDecimal amount, String currency) {
super(amount.unscaledValue(), amount.scale());
this.blockchain=blockchain;
this.currency = currency;
}
public String getCurrency() {
return blockchain.getCurrency();
return currency;
}
@Override
public String toString() {
return super.toString() + " " + blockchain.getCurrency();
return super.toString() + " " + currency;
}
public boolean notZero()
@ -84,10 +96,27 @@ public abstract class CoinEngine {
return compareTo(BigDecimal.ZERO)>0;
}
public String getStringToEdit() {
public String toDescriptionString(int decimals) {
String pattern = "#0.#######################################"; // If you like 4 zeros
DecimalFormat myFormatter = new DecimalFormat(pattern.substring(0,3+decimals));
return myFormatter.format(this) + " " + currency;
}
public String toEditString() {
return super.toString();
}
public String toEquivalentString(double rateValue) {
if (rateValue > 0) {
BigDecimal biRate = new BigDecimal(rateValue);
BigDecimal exchangeCurs = biRate.multiply(this);
exchangeCurs = exchangeCurs.setScale(2, RoundingMode.DOWN);
return "USD " + exchangeCurs.toString();
} else {
return "";
}
}
public boolean isZero() {
return compareTo(BigDecimal.ZERO)==0;
}
@ -156,8 +185,8 @@ public abstract class CoinEngine {
public abstract String calculateAddress(byte[] pkUncompressed) throws NoSuchProviderException, NoSuchAlgorithmException;
public abstract Amount convertToAmount(InternalAmount internalAmount);
public abstract Amount convertToAmount(String strAmount);
public abstract Amount convertToAmount(InternalAmount internalAmount) throws Exception;
public abstract Amount convertToAmount(String strAmount, String currency);
public abstract InternalAmount convertToInternalAmount(Amount amount) throws Exception;
public abstract InternalAmount convertToInternalAmount(byte[] bytes) throws Exception;

View file

@ -1,5 +1,7 @@
package com.tangem.domain.wallet;
import android.util.Log;
/**
* Created by Ilia on 15.02.2018.
*/
@ -25,16 +27,24 @@ public class CoinEngineFactory {
public static CoinEngine create(TangemContext context) {
CoinEngine result;
if (Blockchain.BitcoinCash == context.getBlockchain() || Blockchain.BitcoinCashTestNet == context.getBlockchain()) {
result = new BtcCashEngine(context);
} else if (Blockchain.Bitcoin == context.getBlockchain() || Blockchain.BitcoinTestNet == context.getBlockchain()) {
result = new BtcEngine(context);
} else if (Blockchain.Ethereum == context.getBlockchain() || Blockchain.EthereumTestNet == context.getBlockchain()) {
result = new EthEngine(context);
} else if (Blockchain.Token == context.getBlockchain()) {
result = new TokenEngine(context);
} else {
return null;
try {
if (Blockchain.BitcoinCash == context.getBlockchain() || Blockchain.BitcoinCashTestNet == context.getBlockchain()) {
result = new BtcCashEngine(context);
} else if (Blockchain.Bitcoin == context.getBlockchain() || Blockchain.BitcoinTestNet == context.getBlockchain()) {
result = new BtcEngine(context);
} else if (Blockchain.Ethereum == context.getBlockchain() || Blockchain.EthereumTestNet == context.getBlockchain()) {
result = new EthEngine(context);
} else if (Blockchain.Token == context.getBlockchain()) {
result = new TokenEngine(context);
} else {
return null;
}
}
catch (Exception e)
{
e.printStackTrace();
Log.e("CoinEngineFactory","Can't create CoinEngine!");
result=null;
}
return result;
}

View file

@ -2,14 +2,10 @@ package com.tangem.domain.wallet;
import android.os.Bundle;
import android.util.Log;
import java.math.BigDecimal;
import java.math.BigInteger;
public class EthData extends CoinData
{
private CoinEngine.InternalAmount balance=null;
private CoinEngine.InternalAmount balanceAlter=null;
public class EthData extends CoinData {
private CoinEngine.InternalAmount balance = null;
private BigInteger countConfirmedTX = null;
private BigInteger countUnconfirmedTX = BigInteger.valueOf(0);
@ -46,48 +42,24 @@ public class EthData extends CoinData
public void clearInfo() {
super.clearInfo();
balance = null;
balanceAlter = null;
}
public CoinEngine.InternalAmount getBalanceInInternalUnits() {
return balance;
}
public CoinEngine.InternalAmount getBalanceAlterInInternalUnits() {
return balanceAlter;
}
public void setBalanceInInternalUnits(CoinEngine.InternalAmount value) {
balance = value;
}
public void setBalanceAlterInInternalUnits(CoinEngine.InternalAmount value) {
balanceAlter = value;
}
public Long getBalanceETH() {
BigDecimal b = null;
if (balance != null) {
b = balance; // Returns ETH / token balance
} else if (balanceAlter != null) {
b = balanceAlter; // or ETH balance if there're no tokens on Token card
}
if (b != null) {
return b.longValue(); // Will leave only lower 64 bits for ETH and Tokens
} else {
return null;
}
}
@Override
public void loadFromBundle(Bundle B) {
super.loadFromBundle(B);
balance = new CoinEngine.InternalAmount(B.getString("BalanceDecimal"));
balanceAlter =new CoinEngine.InternalAmount(B.getString("BalanceDecimalAlter"));
String currency = B.getString("BalanceCurrency");
balance = new CoinEngine.InternalAmount(B.getString("BalanceDecimal"), currency);
if (B.containsKey("confirmTx"))
countConfirmedTX = new BigInteger(B.getString("confirmTx"), 16);
@ -97,9 +69,10 @@ public class EthData extends CoinData
@Override
public void saveToBundle(Bundle B) {
super.saveToBundle(B);
try {
B.putString("BalanceCurrency", balance.getCurrency());
B.putString("BalanceDecimal", balance.toString());
B.putString("BalanceDecimalAlter", balance.toString());
B.putString("confirmTx", getConfirmedTXCount().toString(16));
B.putString("unconfirmTx", getUnconfirmedTXCount().toString(16));
@ -110,5 +83,4 @@ public class EthData extends CoinData
}
}
}

View file

@ -17,28 +17,25 @@ import java.math.BigInteger;
import java.math.RoundingMode;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.text.DecimalFormat;
import java.util.Arrays;
import static com.tangem.util.FormatUtil.GetDecimalFormat;
/**
* Created by Ilia on 15.02.2018.
*/
public class EthEngine extends CoinEngine {
public EthData ethData = null;
public EthData coinData = null;
public EthEngine(TangemContext ctx) throws Exception {
super(ctx);
if (ctx.getCoinData() == null) {
ethData = new EthData();
ctx.setCoinData(ethData);
coinData = new EthData();
ctx.setCoinData(coinData);
} else if (ctx.getCoinData() instanceof BtcData) {
ethData = (EthData) ctx.getCoinData();
coinData = (EthData) ctx.getCoinData();
} else {
throw new Exception("Invalid type of Blockchain data for BtcEngine");
throw new Exception("Invalid type of Blockchain data for EthEngine");
}
}
@ -46,6 +43,9 @@ public class EthEngine extends CoinEngine {
super();
}
private static int getDecimals() {
return 18;
}
@Override
public boolean awaitingConfirmation(){
@ -57,14 +57,14 @@ public class EthEngine extends CoinEngine {
if (!hasBalanceInfo()) {
return null;
}
return convertToAmount(ethData.getBalanceInInternalUnits());
return convertToAmount(coinData.getBalanceInInternalUnits());
}
@Override
public String getBalanceHTML() {
Amount balance=getBalance();
if( balance!=null ) {
return balance.toString();
return balance.toDescriptionString(getDecimals());
}else{
return "";
}
@ -79,22 +79,22 @@ public class EthEngine extends CoinEngine {
public String getOfflineBalanceHTML() {
InternalAmount offlineInternalAmount = convertToInternalAmount(ctx.getCard().getOfflineBalance());
Amount offlineAmount = convertToAmount(offlineInternalAmount);
return offlineAmount.toString();
return offlineAmount.toDescriptionString(getDecimals());
}
@Override
public boolean isBalanceAlterNotZero() {
return true; //TODO ???
// if( ethData==null ) return false;
// if (ethData.getBalanceAlterInInternalUnits() == null) return false;
// return ethData.getBalanceAlterInInternalUnits().notZero();
// if( coinData==null ) return false;
// if (coinData.getBalanceAlterInInternalUnits() == null) return false;
// return coinData.getBalanceAlterInInternalUnits().notZero();
}
@Override
public boolean isBalanceNotZero() {
if( ethData==null ) return false;
if (ethData.getBalanceInInternalUnits() == null) return false;
return ethData.getBalanceInInternalUnits().notZero();
if( coinData ==null ) return false;
if (coinData.getBalanceInInternalUnits() == null) return false;
return coinData.getBalanceInInternalUnits().notZero();
}
@Override
@ -127,7 +127,6 @@ public class EthEngine extends CoinEngine {
@Override
public boolean validateAddress(String address) {
if (address == null || address.isEmpty()) {
return false;
}
@ -144,7 +143,7 @@ public class EthEngine extends CoinEngine {
}
// public String getBalanceValue(TangemCard mCard) {
// String dec = ethData.getBalanceInInternalUnits();
// String dec = coinData.getBalanceInInternalUnits();
// BigDecimal d = convertToEth(dec);
// String s = d.toString();
//
@ -154,19 +153,19 @@ public class EthEngine extends CoinEngine {
// return output;
// }
public static String getAmountEquivalentDescription(Amount amount, double rateValue) {
if (amount == null || amount.compareTo(BigDecimal.ZERO) == 0)
return "";
if (rateValue > 0) {
BigDecimal biRate = new BigDecimal(rateValue);
BigDecimal exchangeCurs = biRate.multiply(amount);
exchangeCurs = exchangeCurs.setScale(2, RoundingMode.DOWN);
return "USD " + exchangeCurs.toString();
} else {
return "";
}
}
// public static String getAmountEquivalentDescription(Amount amount, double rateValue) {
// if (amount == null || amount.compareTo(BigDecimal.ZERO) == 0)
// return "";
//
// if (rateValue > 0) {
// BigDecimal biRate = new BigDecimal(rateValue);
// BigDecimal exchangeCurs = biRate.multiply(amount);
// exchangeCurs = exchangeCurs.setScale(2, RoundingMode.DOWN);
// return "USD " + exchangeCurs.toString();
// } else {
// return "";
// }
// }
// public static String getAmountEquivalentDescriptionETH(Double amount, float rate) {
// if (amount == 0)
@ -183,23 +182,23 @@ public class EthEngine extends CoinEngine {
@Override
public String getBalanceEquivalent() {
return getAmountEquivalentDescription(getBalance(), ethData.getRate());
return getBalance().toEquivalentString(coinData.getRate());
}
@Override
public Amount convertToAmount(InternalAmount internalAmount) {
BigDecimal d = internalAmount.divide(new BigDecimal("1000000000000000000"), 8, RoundingMode.DOWN);
return new Amount(d, ctx.getBlockchain());
BigDecimal d = internalAmount.divide(new BigDecimal("1000000000000000000"), getDecimals(), RoundingMode.DOWN);
return new Amount(d, ctx.getBlockchain().getCurrency());
}
@Override
public Amount convertToAmount(String strAmount) {
return new Amount(strAmount, ctx.getBlockchain());
public Amount convertToAmount(String strAmount, String currency) {
return new Amount(strAmount, currency);
}
@Override
public InternalAmount convertToInternalAmount(Amount amount){
return new InternalAmount(amount.multiply(new BigDecimal("1000000000000000000")));
return new InternalAmount(amount.multiply(new BigDecimal("1000000000000000000")),"wei");
}
@Override
@ -216,7 +215,7 @@ public class EthEngine extends CoinEngine {
@Override
public boolean hasBalanceInfo() {
return ethData.getBalanceInInternalUnits()!=null;
return coinData.getBalanceInInternalUnits()!=null;
}
@Override
@ -243,12 +242,12 @@ public class EthEngine extends CoinEngine {
@Override
public InputFilter[] getAmountInputFilters() {
return new InputFilter[] { new DecimalDigitsInputFilter(18) };
return new InputFilter[] { new DecimalDigitsInputFilter(getDecimals()) };
}
@Override
public boolean checkNewTransactionAmount(Amount amount){
if( ethData==null ) return false;
if( coinData ==null ) return false;
Amount balance=getBalance();
if (balance==null || amount.compareTo(balance) > 0) {
return false;
@ -303,14 +302,14 @@ public class EthEngine extends CoinEngine {
return false;
}
if (!ethData.getUnconfirmedTXCount().equals(ethData.getConfirmedTXCount())) {
if (!coinData.getUnconfirmedTXCount().equals(coinData.getConfirmedTXCount())) {
balanceValidator.setScore(0);
balanceValidator.setFirstLine("Unguaranteed balance");
balanceValidator.setSecondLine("Transaction is in progress. Wait for confirmation in blockchain.");
return false;
}
if (ethData.isBalanceReceived()) {
if (coinData.isBalanceReceived()) {
balanceValidator.setScore(100);
balanceValidator.setFirstLine("Verified balance");
balanceValidator.setSecondLine("Balance confirmed in blockchain");
@ -320,7 +319,7 @@ public class EthEngine extends CoinEngine {
}
}
if ((ctx.getCard().getOfflineBalance() != null) && !ethData.isBalanceReceived() && (ctx.getCard().getRemainingSignatures() == ctx.getCard().getMaxSignatures()) && getBalance().notZero()) {
if ((ctx.getCard().getOfflineBalance() != null) && !coinData.isBalanceReceived() && (ctx.getCard().getRemainingSignatures() == ctx.getCard().getMaxSignatures()) && getBalance().notZero()) {
balanceValidator.setScore(80);
balanceValidator.setFirstLine("Verified offline balance");
balanceValidator.setSecondLine("Restore internet connection to obtain trusted balance from blockchain");
@ -332,8 +331,8 @@ public class EthEngine extends CoinEngine {
@Override
public String evaluateFeeEquivalent(String fee) {
Amount feeValue = new Amount(fee, ctx.getBlockchain());
return getAmountEquivalentDescription(feeValue, ethData.getRate());
Amount feeValue = new Amount(fee, ctx.getBlockchain().getCurrency());
return feeValue.toEquivalentString(coinData.getRate());
}
@Override
@ -360,7 +359,7 @@ public class EthEngine extends CoinEngine {
@Override
public byte[] sign(String feeValue, String amountValue, boolean IncFee, String toValue, CardProtocol protocol) throws Exception {
BigInteger nonceValue = ethData.getConfirmedTXCount();
BigInteger nonceValue = coinData.getConfirmedTXCount();
byte[] pbKey = ctx.getCard().getWalletPublicKey();
boolean flag = (ctx.getCard().getSigningMethod() == TangemCard.SigningMethod.Sign_Hash_Validated_By_Issuer);
Issuer issuer = ctx.getCard().getIssuer();

View file

@ -81,10 +81,13 @@ public class TangemContext {
tangemContext.card.loadFromBundle(bundle.getBundle(TangemCard.EXTRA_CARD));
}
if (tangemContext.getBlockchain() != null && bundle.containsKey(EXTRA_BLOCKCHAIN_DATA)) {
tangemContext.coinData=CoinData.fromBundle(tangemContext.getBlockchain(), bundle.getBundle(EXTRA_BLOCKCHAIN_DATA));
if (tangemContext.getBlockchain() != null) {
if (bundle.containsKey(EXTRA_BLOCKCHAIN_DATA)) {
tangemContext.coinData = CoinData.fromBundle(tangemContext.getBlockchain(), bundle.getBundle(EXTRA_BLOCKCHAIN_DATA));
} else {
tangemContext.coinData = CoinEngineFactory.create(tangemContext).createCoinData();
}
}
tangemContext.error = bundle.getString("Error");
tangemContext.message = bundle.getString("Message");
@ -108,7 +111,7 @@ public class TangemContext {
}
public String getString(int stringId) {
if( context!=null ) return getContext().getResources().getString(stringId);
return "context.resources.string["+stringId+"]";
if (context != null) return getContext().getResources().getString(stringId);
return "context.resources.string[" + stringId + "]";
}
}

View file

@ -0,0 +1,46 @@
package com.tangem.domain.wallet;
import android.os.Bundle;
import android.util.Log;
import java.math.BigDecimal;
import java.math.BigInteger;
public class TokenData extends EthData {
private CoinEngine.InternalAmount balanceAlter = null;
@Override
public void clearInfo() {
super.clearInfo();
balanceAlter = null;
}
public CoinEngine.InternalAmount getBalanceAlterInInternalUnits() {
return balanceAlter;
}
public void setBalanceAlterInInternalUnits(CoinEngine.InternalAmount value) {
balanceAlter = value;
}
@Override
public void loadFromBundle(Bundle B) {
super.loadFromBundle(B);
balanceAlter = new CoinEngine.InternalAmount(B.getString("BalanceDecimalAlter"),"ETH");
}
@Override
public void saveToBundle(Bundle B) {
super.saveToBundle(B);
try {
B.putString("BalanceDecimalAlter", balanceAlter.toString());
} catch (Exception e) {
Log.e("Can't save to bundle ", e.getMessage());
}
}
}

View file

@ -1,6 +1,7 @@
package com.tangem.domain.wallet;
import android.net.Uri;
import android.text.InputFilter;
import android.util.Log;
import com.google.common.base.Strings;
@ -8,6 +9,7 @@ import com.tangem.domain.cardReader.CardProtocol;
import com.tangem.domain.cardReader.TLV;
import com.tangem.util.BTCUtils;
import com.tangem.util.CryptoUtil;
import com.tangem.util.DecimalDigitsInputFilter;
import com.tangem.wallet.R;
import org.bitcoinj.core.ECKey;
@ -17,11 +19,7 @@ import java.math.BigInteger;
import java.math.RoundingMode;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.text.DecimalFormat;
import java.util.Arrays;
import java.util.Date;
import static com.tangem.util.FormatUtil.GetDecimalFormat;
/**
* Created by Ilia on 20.03.2018.
@ -29,47 +27,103 @@ import static com.tangem.util.FormatUtil.GetDecimalFormat;
public class TokenEngine extends CoinEngine {
@Override
public String getOfflineBalanceHTML() {
return ctx.getString(R.string.not_implemented);
}
public TokenData coinData = null;
public TokenEngine(TangemContext context) {
super(context);
public TokenEngine(TangemContext ctx) throws Exception {
super(ctx);
if (ctx.getCoinData() == null) {
coinData = new TokenData();
ctx.setCoinData(coinData);
} else if (ctx.getCoinData() instanceof BtcData) {
coinData = (TokenData) ctx.getCoinData();
} else {
throw new Exception("Invalid type of Blockchain data for TokenEngine");
}
}
public TokenEngine() {
super();
}
@Override
public boolean awaitingConfirmation() {
return false;
}
@Override
public Amount getBalance() {
if (!hasBalanceInfo()) {
return null;
}
try {
if (coinData.getBalanceInInternalUnits().notZero()) {
return convertToAmount(coinData.getBalanceInInternalUnits());
} else {
return convertToAmount(coinData.getBalanceAlterInInternalUnits());
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public String getBalanceCurrency(TangemCard card) {
String currency = card.getTokenSymbol();
@Override
public String getBalanceHTML() {
if (hasBalanceInfo()) {
try {
return " " + convertToAmount(coinData.getBalanceInInternalUnits()).toDescriptionString(getTokenDecimals()) + " <br><small><small> + " + convertToAmount(coinData.getBalanceAlterInInternalUnits()).toDescriptionString(getEthDecimals()) + " for gas</small></small>";
} catch (Exception e) {
e.printStackTrace();
return null;
}
} else {
return "";
}
}
@Override
public String getBalanceCurrencyHTML() {
String currency = ctx.getCard().getTokenSymbol();
if (Strings.isNullOrEmpty(currency))
return "NoN";
return currency;
if (hasBalanceInfo()) {
if (coinData.getBalanceInInternalUnits().notZero()) {
return currency;
} else {
return "ETH";
}
} else {
return currency;
}
}
public String getFeeCurrency() {
return "Gwei";
@Override
public InputFilter[] getAmountInputFilters() {
if (!hasBalanceInfo()) return null;
if (coinData.getBalanceInInternalUnits().notZero()) {
return new InputFilter[]{new DecimalDigitsInputFilter(getTokenDecimals())};
} else {
return new InputFilter[]{new DecimalDigitsInputFilter(getEthDecimals())};
}
}
BigDecimal convertToEth(String value) {
BigInteger m = new BigInteger(value, 10);
BigDecimal n = new BigDecimal(m);
BigDecimal d = n.divide(new BigDecimal("1000000000000000000"));
d = d.setScale(8, RoundingMode.DOWN);
return d;
@Override
public String getFeeCurrencyHTML() {
return "ETH";
}
@Override
public String getOfflineBalanceHTML() {
return ctx.getString(R.string.not_implemented);
}
public int getTokenDecimals(TangemCard card) {
return card.getTokensDecimal();
public static int getEthDecimals() {
return 18;
}
public int getTokenDecimals() {
return ctx.getCard().getTokensDecimal();
}
public String getContractAddress(TangemCard card) {
@ -80,7 +134,8 @@ public class TokenEngine extends CoinEngine {
return false;
}
public boolean validateAddress(String address, TangemCard card) {
@Override
public boolean validateAddress(String address) {
if (address == null || address.isEmpty()) {
return false;
}
@ -96,140 +151,40 @@ public class TokenEngine extends CoinEngine {
return true;
}
// public String GetBalanceAlterValue(TangemCard mCard) {
// String dec = mCard.getDecimalBalanceAlter();
// if(dec == null || dec.isEmpty()) return "";
// BigDecimal d = convertToEth(dec);
// String s = d.toString();
//
// String pattern = "#0.##################"; // If you like 4 zeros
// DecimalFormat myFormatter = new DecimalFormat(pattern);
// String output = myFormatter.format(d);
// return output;
// }
//
// public BigDecimal getBalanceAlterValueBigDecimal(TangemCard card) {
// String dec = card.getDecimalBalanceAlter();
// BigDecimal d = convertToEth(dec);
//// String s = d.toString();
//
//// String pattern = "#0.000"; // If you like 4 zeros
//// DecimalFormat myFormatter = new DecimalFormat(pattern);
//// String output = myFormatter.format(d);
// return d;
// }
//
// public String getBalanceValue(TangemCard mCard) {
// if (!hasBalanceInfo(mCard))
// return "";
//
// String dec = mCard.getDecimalBalance();
// BigDecimal d = new BigDecimal(dec);
// BigDecimal p = new BigDecimal(10);
// p = p.pow(getTokenDecimals(mCard));
// BigDecimal l = d.divide(p);
//
// String pattern = "#0.##################"; // If you like 4 zeros
// DecimalFormat myFormatter = new DecimalFormat(pattern);
// String output = myFormatter.format(l);
// return output;
// }
//
// public BigDecimal GetBalanceValueBigDecimal(TangemCard mCard) {
//
// String dec = mCard.getDecimalBalance();
// BigDecimal d = new BigDecimal(dec);
// BigDecimal p = new BigDecimal(10);
// p = p.pow(getTokenDecimals(mCard));
// BigDecimal l = d.divide(p);
//
// return l;
// }
public boolean checkAmount(TangemCard card, String amount) throws Exception {
DecimalFormat decimalFormat = GetDecimalFormat();
BigDecimal amountValue = (BigDecimal) decimalFormat.parse(amount); //new BigDecimal(strAmount);
BigDecimal maxValue = GetBalanceValueBigDecimal(card);
if (amountValue.compareTo(maxValue) > 0) {
return false;
}
return true;
}
public Long getBalanceLong(TangemCard mCard) {
return mCard.getBalance();
}
public boolean isBalanceAlterNotZero(TangemCard card) {
String balance = card.getDecimalBalanceAlter();
if (balance == null || balance == "")
return false;
BigDecimal bi = new BigDecimal(balance);
if (BigDecimal.ZERO.compareTo(bi) == 0)
return false;
return true;
}
public boolean isBalanceNotZero(TangemCard card) {
String balance = card.getDecimalBalance();
if (balance == null || balance == "")
return false;
BigDecimal bi = new BigDecimal(balance);
if (BigDecimal.ZERO.compareTo(bi) == 0)
return false;
return true;
}
public boolean hasBalanceInfo(TangemCard card) {
String balance = card.getDecimalBalance();
if (balance == null || balance == "")
return false;
String balanceEx = card.getDecimalBalanceAlter();
if (balanceEx == null || balanceEx == "")
return false;
return true;
@Override
public boolean isBalanceAlterNotZero() {
if (coinData == null) return false;
if (coinData.getBalanceAlterInInternalUnits() == null) return false;
return coinData.getBalanceAlterInInternalUnits().notZero();
}
@Override
public String getBalanceEquivalent(TangemCard mCard) {
if (!hasBalanceInfo(mCard)) {
public boolean isBalanceNotZero() {
if (coinData == null) return false;
if (coinData.getBalanceInInternalUnits() == null) return false;
return coinData.getBalanceInInternalUnits().notZero();
}
@Override
public String getBalanceEquivalent() {
if (!hasBalanceInfo()) {
return "";
}
try {
if (coinData.getBalanceInInternalUnits().notZero()) {
return convertToAmount(coinData.getBalanceInInternalUnits()).toEquivalentString(coinData.getRate());
} else {
return convertToAmount(coinData.getBalanceAlterInInternalUnits()).toEquivalentString(coinData.getRateAlter());
}
} catch (Exception e) {
e.printStackTrace();
return "";
}
String dec = mCard.getDecimalBalance();
BigDecimal d = convertToEth(dec);
return EthEngine.getAmountEquivalentDescriptionETH(d, mCard.getRate());
}
@Override
public String getBalance(TangemCard mCard) {
if (!hasBalanceInfo(mCard)) {
return "";
}
String output = getBalanceValue(mCard);
String s = output + " " + getBalanceCurrency(mCard);
return s;
}
public String getBalanceHTML(TangemCard mCard) {
//return getBalance(mCard) + "\n(" + GetBalanceAlterValue(mCard) + " ETH)";
if (GetBalanceAlterValue(mCard) != "") {
return " " + getBalance(mCard) + " <br><small><small> + " + GetBalanceAlterValue(mCard) + " ETH for gas</small></small>";
} else {
return "";
}
}
public String calculateAddress(TangemCard mCard, byte[] pkUncompressed) throws NoSuchProviderException, NoSuchAlgorithmException {
public String calculateAddress(byte[] pkUncompressed) throws NoSuchProviderException, NoSuchAlgorithmException {
Keccak256 kec = new Keccak256();
int lenPk = pkUncompressed.length;
if (lenPk < 2) {
@ -250,64 +205,124 @@ public class TokenEngine extends CoinEngine {
}
@Override
public String convertByteArrayToAmount(TangemCard mCard, byte[] bytes) throws Exception {
public Amount convertToAmount(InternalAmount internalAmount) throws Exception {
if (internalAmount.getCurrency().equals("wei")) {
BigDecimal d = internalAmount.divide(new BigDecimal("1000000000000000000"), getEthDecimals(), RoundingMode.DOWN);
return new Amount(d, "ETH");
} else if (internalAmount.getCurrency().equals(ctx.getCard().getTokenSymbol())) {
BigDecimal p = new BigDecimal(10);
p = p.pow(getTokenDecimals());
BigDecimal d = internalAmount.divide(p);
return new Amount(d, ctx.getCard().getTokenSymbol());
}
throw new Exception(String.format("Can't convert '%s' to '%s'", internalAmount.getCurrency(), ctx.getCard().getTokenSymbol()));
}
@Override
public Amount convertToAmount(String strAmount, String currency) {
return new Amount(strAmount, currency);
}
@Override
public InternalAmount convertToInternalAmount(Amount amount) throws Exception {
if (amount.getCurrency().equals("ETH")) {
BigDecimal d = amount.multiply(new BigDecimal("1000000000000000000"));
return new InternalAmount(d, "wei");
} else if (amount.getCurrency().equals(ctx.getCard().getTokenSymbol())) {
BigDecimal p = new BigDecimal(10);
p = p.pow(getTokenDecimals());
BigDecimal d = amount.multiply(p);
return new InternalAmount(d, ctx.getCard().getTokenSymbol());
}
throw new Exception(String.format("Can't convert '%s' to '%s'", amount.getCurrency(), ctx.getCard().getTokenSymbol()));
}
@Override
public InternalAmount convertToInternalAmount(byte[] bytes) throws Exception {
throw new Exception("Not implemented");
}
@Override
public byte[] convertAmountToByteArray(TangemCard mCard, String amount) throws Exception {
public byte[] convertToByteArray(InternalAmount amount) throws Exception {
throw new Exception("Not implemented");
}
@Override
public String getAmountDescription(TangemCard mCard, String amount) throws Exception {
throw new Exception("Not implemented");
public CoinData createCoinData() {
return new TokenData();
}
@Override
public String getUnspentInputsDescription() {
return "";
}
// @Override
// public String getFeeEquivalentDescriptor(String value) {
// BigDecimal d = new BigDecimal(value);
// return EthEngine.getAmountEquivalentDescription(d, coinData.getRateAlter());
// }
@Override
public boolean hasBalanceInfo() {
return coinData != null && coinData.getBalanceInInternalUnits() != null && coinData.getBalanceAlterInInternalUnits() != null;
}
public String getAmountEquivalentDescriptor(TangemCard mCard, String value) {
BigDecimal d = new BigDecimal(value);
return EthEngine.getAmountEquivalentDescriptionETH(d, mCard.getRate());
@Override
public Uri getShareWalletUriExplorer() {
return Uri.parse("https://etherscan.io/token/" + getContractAddress(ctx.getCard()) + "?a=" + ctx.getCard().getWallet());
}
public String getFeeEquivalentDescriptor(TangemCard card, String value) {
BigDecimal d = new BigDecimal(value);
return EthEngine.getAmountEquivalentDescriptionETH(d, card.getRateAlter());
}
public Uri getShareWalletUriExplorer(TangemCard mCard) {
return Uri.parse("https://etherscan.io/token/" + getContractAddress(mCard) + "?a=" + mCard.getWallet());
}
public Uri getShareWalletUri(TangemCard mCard) {
if (mCard.getDenomination() != null) {
return Uri.parse("ethereum:" + mCard.getWallet());// + "?value=" + mCard.getDenomination() +"e18");
@Override
public Uri getShareWalletUri() {
if (ctx.getCard().getDenomination() != null) {
return Uri.parse("ethereum:" + ctx.getCard().getWallet());// + "?value=" + mCard.getDenomination() +"e18");
} else {
return Uri.parse("ethereum:" + mCard.getWallet());
return Uri.parse("ethereum:" + ctx.getCard().getWallet());
}
}
public boolean checkUnspentTransaction(TangemCard mCard) {
@Override
public boolean checkUnspentTransaction() {
return true;
}
public boolean checkAmountValue(TangemCard card, String amountValue, String feeValue, Long minFeeInInternalUnits, Boolean incfee) {
Long fee;
BigDecimal amount;
@Override
public boolean checkNewTransactionAmount(Amount amount) {
if (!hasBalanceInfo()) return false;
Amount balance;
try {
amount = getBalanceAlterValueBigDecimal(card);//card.internalUnitsFromString(amountValue);
fee = card.internalUnitsFromString(feeValue);
} catch (Exception e) {
if (amount.getCurrency().equals(ctx.getCard().tokenSymbol)) {
balance = convertToAmount(coinData.getBalanceInInternalUnits());
} else if (amount.getCurrency().equals("ETH") && coinData.getBalanceInInternalUnits().isZero()) {
balance = convertToAmount(coinData.getBalanceInInternalUnits());
} else {
return false;
}
}
catch (Exception e)
{
e.printStackTrace();
return false;
}
return amount.compareTo(balance) <= 0;
}
if (fee == null || amount == null)
return false;
@Override
public boolean checkNewTransactionAmountAndFee(Amount amount, Amount fee, Boolean isFeeIncluded, InternalAmount minFeeInInternalUnits) {
if (!hasBalanceInfo()) return false;
if (fee == 0 || amount.compareTo(BigDecimal.ZERO) == 0)
return false;
try {
Amount balance = convertToAmount(coinData.getBalanceAlterInInternalUnits());
if (fee == null || amount == null || fee.isZero() || amount.isZero())
return false;
if (amount.getCurrency().equals(ctx.getCard().tokenSymbol)) {
// token transaction
//TODO ???
// BigDecimal tmpFee = new BigDecimal(feeValue);
// BigDecimal tmpAmount = amount;
// tmpAmount = tmpAmount.multiply(new BigDecimal("1000000000"));
@ -315,29 +330,94 @@ public class TokenEngine extends CoinEngine {
// if (tmpFee.compareTo(tmpAmount) > 0)
// return false;
} else if (amount.getCurrency().equals("ETH") && coinData.getBalanceInInternalUnits().isZero()) {
// standart ETH transaction
try {
BigDecimal cardBalance = getBalance();
if (isFeeIncluded && amount.compareTo(cardBalance) > 0)
return false;
if (!isFeeIncluded && amount.add(fee).compareTo(cardBalance) > 0)
return false;
} catch (NumberFormatException e) {
e.printStackTrace();
}
} else
{
return false;
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
public String evaluateFeeEquivalent(TangemCard mCard, String fee) {
BigDecimal gweFee = new BigDecimal(fee);
gweFee = gweFee.divide(new BigDecimal("1000000000"));
gweFee = gweFee.setScale(18, RoundingMode.DOWN);
return getFeeEquivalentDescriptor(mCard, gweFee.toString());
@Override
public boolean validateBalance(BalanceValidator balanceValidator) {
if (getBalance() == null) {
balanceValidator.setScore(0);
balanceValidator.setFirstLine("Unknown balance");
balanceValidator.setSecondLine("Balance cannot be verified. Swipe down to refresh.");
return false;
}
if (!coinData.getUnconfirmedTXCount().equals(coinData.getConfirmedTXCount())) {
balanceValidator.setScore(0);
balanceValidator.setFirstLine("Unguaranteed balance");
balanceValidator.setSecondLine("Transaction is in progress. Wait for confirmation in blockchain.");
return false;
}
if (coinData.isBalanceReceived()) {
balanceValidator.setScore(100);
balanceValidator.setFirstLine("Verified balance");
balanceValidator.setSecondLine("Balance confirmed in blockchain");
if (getBalance().isZero()) {
balanceValidator.setFirstLine("Empty wallet");
balanceValidator.setSecondLine("");
}
}
if ((ctx.getCard().getOfflineBalance() != null) && !coinData.isBalanceReceived() && (ctx.getCard().getRemainingSignatures() == ctx.getCard().getMaxSignatures()) && getBalance().notZero()) {
balanceValidator.setScore(80);
balanceValidator.setFirstLine("Verified offline balance");
balanceValidator.setSecondLine("Restore internet connection to obtain trusted balance from blockchain");
}
return true;
}
public byte[] sign(String feeValue, String amountValue, boolean IncFee, String toValue, TangemCard mCard, CardProtocol protocol) throws Exception {
BigInteger nonceValue = mCard.getConfirmedTXCount();
byte[] pbKey = mCard.getWalletPublicKey();
boolean flag = (mCard.getSigningMethod() == TangemCard.SigningMethod.Sign_Hash_Validated_By_Issuer);
Issuer issuer = mCard.getIssuer();
@Override
public String evaluateFeeEquivalent(String fee) {
Amount feeValue = new Amount(fee, getFeeCurrencyHTML());
return feeValue.toEquivalentString(coinData.getRate());
//
// BigDecimal gweFee = new BigDecimal(fee);
// gweFee = gweFee.divide(new BigDecimal("1000000000"));
// gweFee = gweFee.setScale(18, RoundingMode.DOWN);
// return getFeeEquivalentDescriptor(mCard, gweFee.toString());
}
@Override
public byte[] sign(String feeValue, String amountValue, boolean IncFee, String toValue, CardProtocol protocol) throws Exception {
BigInteger nonceValue = coinData.getConfirmedTXCount();
byte[] pbKey = ctx.getCard().getWalletPublicKey();
boolean flag = (ctx.getCard().getSigningMethod() == TangemCard.SigningMethod.Sign_Hash_Validated_By_Issuer);
Issuer issuer = ctx.getCard().getIssuer();
BigInteger fee = new BigInteger(feeValue, 10);
BigDecimal amountDecValue = new BigDecimal(amountValue);
int d = getTokenDecimals(mCard);
int d = getTokenDecimals();
BigDecimal amountDec = new BigDecimal("10");
amountDec = amountDec.pow(d);
amountDec = amountDecValue.multiply(amountDec);
@ -366,7 +446,7 @@ public class TokenEngine extends CoinEngine {
to = to.substring(2);
}
String contractAddress = getContractAddress(mCard);
String contractAddress = getContractAddress(ctx.getCard());
if (contractAddress.startsWith("0x") || contractAddress.startsWith("0X")) {
contractAddress = contractAddress.substring(2);