1121 lines
No EOL
34 KiB
Java
1121 lines
No EOL
34 KiB
Java
package com.tangem.domain.wallet;
|
||
|
||
import android.os.Bundle;
|
||
|
||
import com.google.common.base.Strings;
|
||
import com.tangem.domain.cardReader.SettingsMask;
|
||
import com.tangem.util.FormatUtil;
|
||
import com.tangem.util.Util;
|
||
|
||
import java.math.BigDecimal;
|
||
import java.math.BigInteger;
|
||
import java.util.ArrayList;
|
||
import java.util.Date;
|
||
import java.util.List;
|
||
import java.util.concurrent.atomic.AtomicInteger;
|
||
|
||
/**
|
||
* Created by dvol on 16.07.2017.
|
||
*/
|
||
|
||
public class TangemCard {
|
||
|
||
public static final String EXTRA_CARD = "Card";
|
||
public static final String EXTRA_UID = "UID";
|
||
|
||
private byte[] CID;
|
||
private Status status;
|
||
private String wallet;
|
||
private String UID;
|
||
private String error;
|
||
private String message;
|
||
private String balanceDecimal;
|
||
private String balanceDecimalAlter = "";
|
||
private Long balanceConfirmed, balanceUnconfirmed;
|
||
private String blockchainID;
|
||
private Manufacturer manufacturer = Manufacturer.Unknown;
|
||
private boolean manufacturerConfirmed = false;
|
||
private int maxSignatures;
|
||
private int remainingSignatures;
|
||
private String PIN;
|
||
private byte[] pbWalletKey = null;
|
||
private byte[] pbCardKey = null;
|
||
private byte[] pbWalletKeyRar = null;
|
||
private Date dtPersonalization = null;
|
||
private float rate = 0;
|
||
private float rateAlter = 0;
|
||
|
||
private BigInteger countConfirmedTX = null;
|
||
private BigInteger countUnconfirmedTX = BigInteger.valueOf(0);
|
||
|
||
public BigInteger getConfirmedTXCount() {
|
||
if (countConfirmedTX == null) {
|
||
countConfirmedTX = BigInteger.valueOf(0);
|
||
}
|
||
return countConfirmedTX;
|
||
}
|
||
|
||
public void setConfirmedTXCount(BigInteger count) {
|
||
countConfirmedTX = count;
|
||
}
|
||
|
||
public BigInteger getUnconfirmedTXCount() {
|
||
if (countUnconfirmedTX == null) {
|
||
countUnconfirmedTX = BigInteger.valueOf(0);
|
||
}
|
||
return countUnconfirmedTX;
|
||
}
|
||
|
||
public void setUnconfirmedTXCount(BigInteger count) {
|
||
countUnconfirmedTX = count;
|
||
}
|
||
|
||
public float getRate() {
|
||
return rate;
|
||
}
|
||
|
||
public float getRateAlter() {
|
||
return rateAlter;
|
||
}
|
||
|
||
public void setRate(float rate) {
|
||
this.rate = rate;
|
||
}
|
||
|
||
public void setRateAlter(float rate) {
|
||
this.rateAlter = rate;
|
||
}
|
||
|
||
public String getBlockchainID() {
|
||
return blockchainID;
|
||
}
|
||
|
||
public Blockchain getBlockchain() {
|
||
return Blockchain.fromId(blockchainID);
|
||
}
|
||
|
||
public void setBlockchainID(String blockchainID) {
|
||
this.blockchainID = blockchainID;
|
||
}
|
||
|
||
public void addTokenToBlockchainName() {
|
||
String token = getTokenSymbol();
|
||
if (Strings.isNullOrEmpty(token))
|
||
return;
|
||
String oldName = getBlockchain().getOfficialName();
|
||
String newName = String.format("%s (%s)", oldName, token);
|
||
setBlockchainName(newName);
|
||
}
|
||
|
||
private String blockchainName = "";
|
||
|
||
public void setBlockchainName(String name) {
|
||
blockchainName = name;
|
||
}
|
||
|
||
|
||
public String getBlockchainName() {
|
||
if (Strings.isNullOrEmpty(blockchainName))
|
||
return getBlockchain().getOfficialName();
|
||
return blockchainName;
|
||
}
|
||
|
||
public void setBlockchainIDFromCard(String blockchainID) {
|
||
|
||
if (Blockchain.fromId(blockchainID) != Blockchain.Ethereum && Blockchain.fromId(blockchainID) != Blockchain.EthereumTestNet)
|
||
this.blockchainID = blockchainID;
|
||
|
||
if (isToken()) {
|
||
this.blockchainID = Blockchain.Token.getID();
|
||
addTokenToBlockchainName();
|
||
} else {
|
||
this.blockchainID = blockchainID;
|
||
}
|
||
}
|
||
|
||
public void setWalletPublicKey(byte[] publicKey) {
|
||
pbWalletKey = publicKey;
|
||
}
|
||
|
||
public void setWalletPublicKeyRar(byte[] publicKey) {
|
||
pbWalletKeyRar = publicKey;
|
||
}
|
||
|
||
public byte[] getWalletPublicKey() {
|
||
return pbWalletKey;
|
||
}
|
||
|
||
public byte[] getWalletPublicKeyRar() {
|
||
return pbWalletKeyRar;
|
||
}
|
||
|
||
private boolean walletPublicKeyValid = false;
|
||
|
||
public void setWalletPublicKeyValid(boolean walletPublicKeyValid) {
|
||
this.walletPublicKeyValid = walletPublicKeyValid;
|
||
}
|
||
|
||
public boolean isWalletPublicKeyValid() {
|
||
return walletPublicKeyValid;
|
||
}
|
||
|
||
public void setCardPublicKey(byte[] publicKey) {
|
||
pbCardKey = publicKey;
|
||
}
|
||
|
||
public byte[] getCardPublicKey() {
|
||
return pbCardKey;
|
||
}
|
||
|
||
private boolean cardPublicKeyValid = false;
|
||
|
||
public void setCardPublicKeyValid(boolean cardPublicKeyValid) {
|
||
this.cardPublicKeyValid = cardPublicKeyValid;
|
||
}
|
||
|
||
public boolean isCardPublicKeyValid() {
|
||
return cardPublicKeyValid;
|
||
}
|
||
|
||
public Double amountFromInternalUnits(Long internalAmount) {
|
||
// TODO java.lang.NullPointerException: Attempt to invoke virtual method 'long java.lang.Long.longValue()' on a null object reference
|
||
return ((double) internalAmount) /
|
||
getBlockchain().getMultiplier();
|
||
}
|
||
|
||
public Double amountFromInternalUnits(Integer internalAmount) {
|
||
return ((double) internalAmount) / getBlockchain().getMultiplier();
|
||
}
|
||
|
||
// TODO разобраться с балансами, привести к единому интерфейсу
|
||
public Long internalUnitsFromString(String caption) {
|
||
try {
|
||
return FormatUtil.ConvertStringToLong(caption);
|
||
} catch (Exception e) {
|
||
return null;
|
||
}
|
||
}
|
||
|
||
public String getAmountDescription(Double amount) {
|
||
String output = FormatUtil.DoubleToString(amount);
|
||
return output + " " + getBlockchain().getCurrency();
|
||
}
|
||
|
||
public String getAmountEquivalentDescription(Double amount) {
|
||
if (getBlockchain() == Blockchain.Ethereum || getBlockchain() == Blockchain.EthereumTestNet || getBlockchain() == Blockchain.Token) {
|
||
return EthEngine.getAmountEquivalentDescriptionETH(amount, rate);
|
||
}
|
||
|
||
return BtcEngine.getAmountEquivalentDescriptionBTC(amount, rate);
|
||
}
|
||
|
||
public boolean getAmountEquivalentDescriptionAvailable() {
|
||
return rate > 0;
|
||
}
|
||
|
||
public String getAmountInGwei(String amount) {
|
||
BigInteger d = new BigInteger(amount, 10);
|
||
BigInteger m = d.divide(BigInteger.valueOf(1000000000L));
|
||
return m.toString(10);
|
||
}
|
||
|
||
public Manufacturer getManufacturer() {
|
||
return manufacturer;
|
||
}
|
||
|
||
public boolean isManufacturerConfirmed() {
|
||
return manufacturerConfirmed;
|
||
}
|
||
|
||
public void setManufacturer(Manufacturer manufacturer, boolean verified) {
|
||
if (this.manufacturer == manufacturer) {
|
||
this.manufacturerConfirmed |= verified;
|
||
} else {
|
||
this.manufacturer = manufacturer;
|
||
this.manufacturerConfirmed = verified;
|
||
}
|
||
}
|
||
|
||
private Boolean codeConfirmed;
|
||
|
||
public void setCodeConfirmed(Boolean codeConfirmed) {
|
||
this.codeConfirmed = codeConfirmed;
|
||
}
|
||
|
||
public Boolean isCodeConfirmed() {
|
||
return codeConfirmed;
|
||
}
|
||
|
||
private Boolean onlineVerified;
|
||
|
||
public void setOnlineVerified(Boolean verified) {
|
||
this.onlineVerified = verified;
|
||
}
|
||
|
||
public Boolean isOnlineVerified() {
|
||
return onlineVerified;
|
||
}
|
||
|
||
private Boolean onlineValidated;
|
||
|
||
public void setOnlineValidated(Boolean validated) {
|
||
this.onlineValidated = validated;
|
||
}
|
||
|
||
public Boolean isOnlineValidated() {
|
||
return onlineValidated;
|
||
}
|
||
|
||
public int getRemainingSignatures() {
|
||
return remainingSignatures;
|
||
}
|
||
|
||
public void setRemainingSignatures(int remainingSignatures) {
|
||
this.remainingSignatures = remainingSignatures;
|
||
}
|
||
|
||
public String getPIN() {
|
||
return PIN;
|
||
}
|
||
|
||
public void setPIN(String PIN) {
|
||
this.PIN = PIN;
|
||
}
|
||
|
||
public void clearInfo() {
|
||
balanceConfirmed = null;
|
||
balanceUnconfirmed = null;
|
||
unspentTransactions = null;
|
||
balanceDecimal = null;
|
||
balanceDecimalAlter = null;
|
||
setIsBalanceEqual(false);
|
||
if (tokenSymbol.length() > 1)
|
||
blockchainID = Blockchain.Token.getID(); // Reset blockchain to Token from ETH for token cards with zero token balance on it
|
||
}
|
||
|
||
public Date getPersonalizationDateTime() {
|
||
return dtPersonalization;
|
||
}
|
||
|
||
public void setPersonalizationDateTime(Date dtPersonalization) {
|
||
this.dtPersonalization = dtPersonalization;
|
||
}
|
||
|
||
public String getPersonalizationDateTimeDescription() {
|
||
return Util.formatDate(dtPersonalization);
|
||
|
||
}
|
||
|
||
private int health = 0;
|
||
|
||
public void setHealth(int health) {
|
||
if (health > this.health) this.health = health;
|
||
}
|
||
|
||
public boolean isHealthOK() {
|
||
return health == 0;
|
||
}
|
||
|
||
private Issuer issuer = Issuer.Unknown();
|
||
private byte[] issuerPublicDataKey = null;
|
||
|
||
// public void setIssuer(Issuer issuer) {
|
||
// this.issuer = issuer;
|
||
// }
|
||
|
||
public void setIssuer(String issuerID, byte[] issuerPublicDataKey) {
|
||
this.issuerPublicDataKey = issuerPublicDataKey;
|
||
this.issuer = Issuer.FindIssuer(issuerID, issuerPublicDataKey);
|
||
}
|
||
|
||
public Issuer getIssuer() {
|
||
return issuer;
|
||
}
|
||
|
||
public byte[] getIssuerPublicDataKey() {
|
||
return issuerPublicDataKey;
|
||
}
|
||
|
||
public String getIssuerDescription() {
|
||
return issuer.getOfficialName();
|
||
}
|
||
|
||
String contractAddress = "";
|
||
|
||
public void setContractAddress(String address) {
|
||
contractAddress = address;
|
||
}
|
||
|
||
public String getContractAddress() {
|
||
return contractAddress;
|
||
}
|
||
|
||
String tokenSymbol = "";
|
||
|
||
public void setTokenSymbol(String symbol) {
|
||
tokenSymbol = symbol;
|
||
}
|
||
|
||
public String getTokenSymbol() {
|
||
return tokenSymbol;
|
||
}
|
||
|
||
public boolean isToken() {
|
||
return !Strings.isNullOrEmpty(tokenSymbol);
|
||
}
|
||
|
||
int tokensDecimal = 18;
|
||
|
||
public void setTokensDecimal(int tokensDecimal) {
|
||
this.tokensDecimal = tokensDecimal;
|
||
}
|
||
|
||
public int getTokensDecimal() {
|
||
return tokensDecimal;
|
||
}
|
||
|
||
|
||
private byte[] issuerData;
|
||
private byte[] issuerDataSignature;
|
||
|
||
public byte[] getIssuerData() {
|
||
return issuerData;
|
||
}
|
||
|
||
public byte[] getIssuerDataSignature() {
|
||
return issuerDataSignature;
|
||
}
|
||
|
||
public void setIssuerData(byte[] value, byte[] signature) {
|
||
issuerData = value;
|
||
issuerDataSignature = signature;
|
||
}
|
||
|
||
private boolean needWriteIssuerData = false;
|
||
|
||
public boolean getNeedWriteIssuerData() {
|
||
return needWriteIssuerData;
|
||
}
|
||
|
||
public void setNeedWriteIssuerData(boolean value) {
|
||
needWriteIssuerData = value;
|
||
}
|
||
|
||
public String getIssuerDataDescription() {
|
||
return "";
|
||
}
|
||
|
||
private int pauseBeforePIN2 = 0;
|
||
|
||
public void setPauseBeforePIN2(int value) {
|
||
this.pauseBeforePIN2 = value;
|
||
}
|
||
|
||
public int getPauseBeforePIN2() {
|
||
return pauseBeforePIN2;
|
||
}
|
||
|
||
private AtomicInteger failedBalanceRequestCounter;
|
||
|
||
public int incFailedBalanceRequestCounter() {
|
||
if (failedBalanceRequestCounter == null)
|
||
failedBalanceRequestCounter = new AtomicInteger(0);
|
||
return failedBalanceRequestCounter.incrementAndGet();
|
||
}
|
||
|
||
public void resetFailedBalanceRequestCounter() {
|
||
failedBalanceRequestCounter = new AtomicInteger(0);
|
||
}
|
||
|
||
public int getFailedBalanceRequestCounter() {
|
||
if (failedBalanceRequestCounter == null)
|
||
return 0;
|
||
return failedBalanceRequestCounter.get();
|
||
}
|
||
|
||
Boolean balanceEqual;
|
||
|
||
public Boolean isBalanceEqual() {
|
||
return balanceEqual;
|
||
}
|
||
|
||
public void setIsBalanceEqual(boolean isEqual) {
|
||
balanceEqual = isEqual;
|
||
}
|
||
|
||
private Integer settingsMask = null;
|
||
|
||
public void setSettingsMask(int settingsMask) {
|
||
this.settingsMask = settingsMask;
|
||
}
|
||
|
||
public Boolean isReusable() {
|
||
if (settingsMask == null) return null;
|
||
return (settingsMask.intValue() & SettingsMask.IsReusable) != 0;
|
||
}
|
||
|
||
public Boolean allowSwapPIN() {
|
||
if (settingsMask == null) return null;
|
||
return (settingsMask.intValue() & SettingsMask.AllowSwapPIN) != 0;
|
||
}
|
||
|
||
public Boolean allowSwapPIN2() {
|
||
if (settingsMask == null) return null;
|
||
return (settingsMask.intValue() & SettingsMask.AllowSwapPIN2) != 0;
|
||
}
|
||
|
||
public Boolean needCVC() {
|
||
if (settingsMask == null) return null;
|
||
return (settingsMask.intValue() & SettingsMask.UseCVC) != 0;
|
||
}
|
||
|
||
public Boolean useDefaultPIN1() {
|
||
return PINStorage.isDefaultPIN(getPIN());
|
||
}
|
||
|
||
public Boolean useSmartSecurityDelay() {
|
||
if (settingsMask == null) return null;
|
||
return (settingsMask.intValue() & SettingsMask.SmartSecurityDelay) != 0;
|
||
}
|
||
|
||
public enum PIN2_Mode {Unchecked, DefaultPIN2, CustomPIN2}
|
||
|
||
public PIN2_Mode PIN2 = PIN2_Mode.Unchecked;
|
||
|
||
public Boolean useDefaultPIN2() {
|
||
if (PIN2 == PIN2_Mode.DefaultPIN2 || (PIN2 == PIN2_Mode.Unchecked && (needCVC() || (getPauseBeforePIN2() > 0)))) {
|
||
// define that we use default PIN2 if we try it or not try and security delay or CVC is used
|
||
return true;
|
||
} else {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
public void setUseDefaultPIN2(Boolean value) {
|
||
if (value != null) {
|
||
PIN2 = value ? PIN2_Mode.DefaultPIN2 : PIN2_Mode.CustomPIN2;
|
||
} else {
|
||
PIN2 = PIN2_Mode.Unchecked;
|
||
}
|
||
}
|
||
|
||
public Boolean supportNDEF() {
|
||
if (settingsMask == null) return null;
|
||
return (settingsMask.intValue() & SettingsMask.UseNDEF) != 0;
|
||
}
|
||
|
||
public Boolean supportOnlyOneCommandAtTime() {
|
||
if (settingsMask == null) return null;
|
||
return supportNDEF() && ((settingsMask.intValue() & SettingsMask.UseOneCommandAtTime) != 0);
|
||
}
|
||
|
||
public Boolean supportDynamicNDEF() {
|
||
if (settingsMask == null) return null;
|
||
return supportNDEF() && ((settingsMask.intValue() & SettingsMask.UseDynamicNDEF) != 0);
|
||
}
|
||
|
||
public Boolean supportBlock() {
|
||
if (settingsMask == null) return null;
|
||
return (settingsMask.intValue() & SettingsMask.UseBlock) != 0;
|
||
}
|
||
|
||
public int getMaxSignatures() {
|
||
return maxSignatures;
|
||
}
|
||
|
||
public void setMaxSignatures(int value) {
|
||
maxSignatures = value;
|
||
}
|
||
|
||
private String firmwareVersion;
|
||
|
||
public void setFirmwareVersion(String firmwareVersion) {
|
||
this.firmwareVersion = firmwareVersion;
|
||
}
|
||
|
||
public String getFirmwareVersion() {
|
||
return firmwareVersion;
|
||
}
|
||
|
||
public Boolean useDevelopersFirmware() {
|
||
return getFirmwareVersion().endsWith("d") || getFirmwareVersion().endsWith("SDK");
|
||
}
|
||
|
||
public static String getFirmwareVersionNumber(String version) throws Exception {
|
||
if (version == null || version.length() < 4) {
|
||
throw new Exception("Firmware version has unsupported format!");
|
||
}
|
||
if (version.endsWith("d SDK")) {
|
||
return version.substring(0, version.length() - 5);
|
||
} else if (version.endsWith("r")) {
|
||
return version.substring(0, version.length() - 1);
|
||
} else {
|
||
return version;
|
||
}
|
||
}
|
||
|
||
public static int[] getFirmwareVersionNumbers(String version) throws Exception {
|
||
String fwNumber = getFirmwareVersionNumber(version);
|
||
String[] strNumbers = fwNumber.split("\\.");
|
||
|
||
if (strNumbers.length != 2) throw new Exception("Firmware version has unsupported format!");
|
||
try {
|
||
int major = Integer.parseInt(strNumbers[0]), minor = Integer.parseInt(strNumbers[1]);
|
||
return new int[]{major, minor};
|
||
} catch (NumberFormatException e) {
|
||
e.printStackTrace();
|
||
throw new Exception("Firmware version has unsupported format!");
|
||
}
|
||
}
|
||
|
||
public Boolean isFirmwareOlder(String version) throws Exception {
|
||
int[] numbers1 = getFirmwareVersionNumbers(firmwareVersion), numbers2 = getFirmwareVersionNumbers(version);
|
||
return numbers1[0] < numbers2[0] || (numbers1[0] == numbers2[0] && numbers1[1] < numbers2[1]);
|
||
}
|
||
|
||
public Boolean isFirmwareNewer(String version) throws Exception {
|
||
int[] numbers1 = getFirmwareVersionNumbers(firmwareVersion), numbers2 = getFirmwareVersionNumbers(version);
|
||
return numbers1[0] > numbers2[0] || (numbers1[0] == numbers2[0] && numbers1[1] > numbers2[1]);
|
||
}
|
||
|
||
private String batch;
|
||
|
||
public void setBatch(String batch) {
|
||
this.batch = batch;
|
||
}
|
||
|
||
public String getBatch() {
|
||
return batch;
|
||
}
|
||
|
||
private String validationNodeDescription = "";
|
||
|
||
public String getValidationNodeDescription() {
|
||
return validationNodeDescription;
|
||
}
|
||
|
||
public void setValidationNodeDescription(String validationNodeDescription) {
|
||
this.validationNodeDescription = validationNodeDescription;
|
||
}
|
||
|
||
public enum SigningMethod {
|
||
Sign_Hash(0, "sign hash"),
|
||
Sign_Raw(1, "sign raw tx"),
|
||
Sign_Hash_Validated_By_Issuer(2, "sign hash validated by issuer"),
|
||
Sign_Raw_Validated_By_Issuer(3, "sign raw tx validated by issuer");
|
||
|
||
int ID;
|
||
String mDescription;
|
||
|
||
SigningMethod(int ID, String description) {
|
||
this.ID = ID;
|
||
mDescription = description;
|
||
}
|
||
|
||
static SigningMethod FindByID(int ID) {
|
||
SigningMethod[] methods = values();
|
||
for (SigningMethod m : methods) {
|
||
if (m.ID == ID) return m;
|
||
}
|
||
return SigningMethod.Sign_Hash;
|
||
}
|
||
|
||
public String getDescription() {
|
||
return mDescription;
|
||
}
|
||
}
|
||
|
||
private SigningMethod signingMethod;
|
||
|
||
public void setSigningMethod(int signingMethodID) {
|
||
this.signingMethod = SigningMethod.FindByID(signingMethodID);
|
||
}
|
||
|
||
public SigningMethod getSigningMethod() {
|
||
return signingMethod;
|
||
}
|
||
|
||
public static class UnspentTransaction {
|
||
public String txID;
|
||
public Integer Amount;
|
||
public Integer Height;
|
||
public String Raw = "";
|
||
|
||
public Bundle getAsBundle() {
|
||
Bundle B = new Bundle();
|
||
B.putString("txID", txID);
|
||
B.putInt("Amount", Amount);
|
||
B.putInt("Height", Height);
|
||
B.putString("Raw", Raw);
|
||
return B;
|
||
}
|
||
|
||
public void LoadFromBundle(Bundle B) {
|
||
txID = B.getString("txID");
|
||
Amount = B.getInt("Amount");
|
||
Height = B.getInt("Height");
|
||
Raw = B.getString("Raw");
|
||
|
||
}
|
||
}
|
||
|
||
private List<UnspentTransaction> unspentTransactions = null;
|
||
|
||
public List<UnspentTransaction> getUnspentTransactions() {
|
||
if (unspentTransactions == null) unspentTransactions = new ArrayList<>();
|
||
return unspentTransactions;
|
||
}
|
||
|
||
public TangemCard(String UID) {
|
||
this.UID = UID;
|
||
}
|
||
|
||
public void setStatus(Status status) {
|
||
this.status = status;
|
||
}
|
||
|
||
public Status getStatus() {
|
||
return status;
|
||
}
|
||
|
||
public byte[] getCID() {
|
||
return CID;
|
||
}
|
||
|
||
public void setCID(byte[] value) {
|
||
this.CID = value;
|
||
}
|
||
|
||
public String getCIDDescription() {
|
||
String strCID = Util.bytesToHex(CID);
|
||
try {
|
||
return strCID.substring(0, 4) + " " + strCID.substring(4, 8) + " " + strCID.substring(8, 12) + " " + strCID.substring(12, 16);
|
||
} catch (Exception e) {
|
||
return strCID;
|
||
}
|
||
}
|
||
|
||
public void setWallet(String wallet) {
|
||
this.wallet = wallet;
|
||
}
|
||
|
||
public String getWallet() {
|
||
return wallet;
|
||
}
|
||
|
||
public String getShortWalletString() {
|
||
if (wallet.length() < 22) {
|
||
return wallet;
|
||
} else {
|
||
return wallet.substring(0, 10) + "......" + wallet.substring(wallet.length() - 10, wallet.length());
|
||
}
|
||
}
|
||
|
||
public String getUID() {
|
||
return UID;
|
||
}
|
||
|
||
public void setUID(String UID) {
|
||
this.UID = UID;
|
||
}
|
||
|
||
public Long getBalance() {
|
||
|
||
BigDecimal balance = null;
|
||
|
||
if ((this.getBlockchain() == Blockchain.Bitcoin || this.getBlockchain() == Blockchain.BitcoinCash || this.getBlockchain() == Blockchain.BitcoinTestNet || this.getBlockchain() == Blockchain.BitcoinCashTestNet) && balanceConfirmed != null && balanceUnconfirmed != null) {
|
||
balance = BigDecimal.valueOf(balanceConfirmed + balanceUnconfirmed);
|
||
} else if (this.getBlockchain() == Blockchain.Ethereum || this.getBlockchain() == Blockchain.EthereumTestNet || this.getBlockchain() == Blockchain.Token) {
|
||
if (balanceDecimal != null) {
|
||
balance = new BigDecimal(balanceDecimal); // Returns ETH / token balance
|
||
} else if (balanceDecimalAlter != null) {
|
||
balance = new BigDecimal(balanceDecimalAlter); // or ETH balance if there're no tokens on Token card
|
||
}
|
||
}
|
||
|
||
if (balance != null) {
|
||
return balance.longValue(); // Will leave only lower 64 bits for ETH and Tokens
|
||
} else {
|
||
return null;
|
||
}
|
||
}
|
||
|
||
public Long getBalanceUnconfirmed() {
|
||
return balanceUnconfirmed;
|
||
}
|
||
|
||
public void setBalanceConfirmed(Long balance) {
|
||
this.balanceConfirmed = balance;
|
||
}
|
||
|
||
public void setBalanceUnconfirmed(Long balance) {
|
||
this.balanceUnconfirmed = balance;
|
||
}
|
||
|
||
public boolean hasBalanceInfo() {
|
||
return balanceConfirmed != null || balanceUnconfirmed != null || balanceDecimal != "" || balanceDecimalAlter != "";
|
||
}
|
||
|
||
public String getDecimalBalance() {
|
||
return balanceDecimal;
|
||
}
|
||
|
||
public String getDecimalBalanceAlter() {
|
||
return balanceDecimalAlter;
|
||
}
|
||
|
||
public void setDecimalBalance(String value) {
|
||
balanceDecimal = value;
|
||
}
|
||
|
||
public void setDecimalBalanceAlter(String value) {
|
||
balanceDecimalAlter = value;
|
||
}
|
||
|
||
private byte[] offlineBalance;
|
||
|
||
public void setOfflineBalance(byte[] offlineBalance) {
|
||
this.offlineBalance = offlineBalance;
|
||
}
|
||
|
||
public byte[] getOfflineBalance() {
|
||
return offlineBalance;
|
||
}
|
||
|
||
public void clearOfflineBalance() {
|
||
offlineBalance = null;
|
||
}
|
||
|
||
private byte[] Denomination;
|
||
private String DenominationText;
|
||
|
||
public void setDenomination(byte[] denomination, String denominationText) {
|
||
this.Denomination = denomination;
|
||
this.DenominationText = denominationText;
|
||
}
|
||
|
||
public void setDenomination(byte[] denomination) {
|
||
this.Denomination = denomination;
|
||
try {
|
||
this.DenominationText = CoinEngineFactory.create(getBlockchain()).convertByteArrayToAmount(this, denomination);
|
||
} catch (Exception e) {
|
||
e.printStackTrace();
|
||
this.DenominationText = "N/A";
|
||
}
|
||
}
|
||
|
||
public byte[] getDenomination() {
|
||
return Denomination;
|
||
}
|
||
|
||
public int SignedHashes = -1; // Will remain -1 if tag was not found on card (= not safe to accept)
|
||
|
||
public void setSignedHashes(int SignedHashes) {
|
||
this.SignedHashes = SignedHashes;
|
||
}
|
||
|
||
public int getSignedHashes() {
|
||
return SignedHashes;
|
||
}
|
||
|
||
|
||
public String getDenominationText() {
|
||
return DenominationText;
|
||
}
|
||
|
||
public void setDenominationText(String denominationText) {
|
||
DenominationText = denominationText;
|
||
}
|
||
|
||
public void clearDenomination() {
|
||
Denomination = null;
|
||
DenominationText = null;
|
||
}
|
||
|
||
public void setError(String error) {
|
||
this.error = error;
|
||
}
|
||
|
||
public String getError() {
|
||
return error;
|
||
}
|
||
|
||
public void setMessage(String value) {
|
||
this.message = value;
|
||
}
|
||
|
||
public String getMessage() {
|
||
return message;
|
||
}
|
||
|
||
public enum Status {
|
||
NotPersonalized(0), Empty(1), Loaded(2), Purged(3);
|
||
|
||
Status(int Code) {
|
||
mCode = Code;
|
||
}
|
||
|
||
private int mCode;
|
||
|
||
public int getCode() {
|
||
return mCode;
|
||
}
|
||
|
||
public static Status fromCode(int code) {
|
||
for (Status s : values()) {
|
||
if (s.getCode() == code) return s;
|
||
}
|
||
return null;
|
||
}
|
||
}
|
||
|
||
public Bundle getAsBundle() {
|
||
Bundle B = new Bundle();
|
||
SaveToBundle(B);
|
||
return B;
|
||
}
|
||
|
||
public void SaveToBundle(Bundle B) {
|
||
B.putString("UID", UID);
|
||
B.putByteArray("CID", CID);
|
||
B.putString("PIN", PIN);
|
||
B.putString("PIN2", PIN2.name());
|
||
B.putString("Status", status.name());
|
||
B.putString("Blockchain", blockchainID);
|
||
B.putString("BlockchainName", blockchainName);
|
||
B.putInt("TokensDecimal", tokensDecimal);
|
||
B.putString("TokenSymbol", tokenSymbol);
|
||
B.putString("ContractAddress", contractAddress);
|
||
B.putString("validationNodeDescription", validationNodeDescription);
|
||
if (dtPersonalization != null) B.putLong("dtPersonalization", dtPersonalization.getTime());
|
||
B.putInt("RemainingSignatures", remainingSignatures);
|
||
B.putInt("MaxSignatures", maxSignatures);
|
||
B.putInt("Health", health);
|
||
if (settingsMask != null) B.putInt("settingsMask", settingsMask);
|
||
B.putInt("pauseBeforePIN2", pauseBeforePIN2);
|
||
if (signingMethod != null) B.putString("signingMethod", signingMethod.name());
|
||
if (manufacturer != null) B.putString("Manufacturer", manufacturer.name());
|
||
if (encryptionMode != null) B.putString("EncryptionMode", encryptionMode.name());
|
||
if (issuer != null) B.putString("Issuer", issuer.getID());
|
||
if (issuerPublicDataKey != null) B.putByteArray("IssuerPublicDataKey", issuerPublicDataKey);
|
||
if (firmwareVersion != null) B.putString("FirmwareVersion", firmwareVersion);
|
||
if (balanceEqual != null) B.putBoolean("isBalanceEqual", balanceEqual);
|
||
if (batch != null) B.putString("Batch", batch);
|
||
B.putString("BalanceDecimal", balanceDecimal);
|
||
B.putString("BalanceDecimalAlter", balanceDecimalAlter);
|
||
B.putBoolean("ManufacturerConfirmed", manufacturerConfirmed);
|
||
B.putBoolean("CardPublicKeyValid", isCardPublicKeyValid());
|
||
B.putByteArray("CardPublicKey", getCardPublicKey());
|
||
|
||
if (failedBalanceRequestCounter != null)
|
||
B.putInt("FailedBalance", failedBalanceRequestCounter.get());
|
||
B.putInt("SignedHashes", getSignedHashes());
|
||
B.putString("Wallet", wallet);
|
||
B.putString("Error", error);
|
||
B.putBoolean("WalletPublicKeyValid", isWalletPublicKeyValid());
|
||
if (pbWalletKey != null)
|
||
B.putByteArray("PublicKey", pbWalletKey);
|
||
if (pbWalletKeyRar != null)
|
||
B.putByteArray("PublicKeyRar", pbWalletKeyRar);
|
||
if (balanceConfirmed != null) B.putLong("BalanceConfirmed", balanceConfirmed);
|
||
if (balanceUnconfirmed != null) B.putLong("BalanceUnconfirmed", balanceUnconfirmed);
|
||
|
||
if (getOfflineBalance() != null) B.putByteArray("OfflineBalance", getOfflineBalance());
|
||
|
||
if (getDenomination() != null) B.putByteArray("Denomination", getDenomination());
|
||
|
||
if (getIssuerData() != null && getIssuerDataSignature() != null) {
|
||
B.putByteArray("IssuerData", getIssuerData());
|
||
B.putByteArray("IssuerDataSignature", getIssuerDataSignature());
|
||
B.putBoolean("NeedWriteIssuerData", getNeedWriteIssuerData());
|
||
}
|
||
|
||
if (unspentTransactions != null) {
|
||
Bundle BB = new Bundle();
|
||
for (Integer i = 0; i < unspentTransactions.size(); i++) {
|
||
BB.putBundle(i.toString(), unspentTransactions.get(i).getAsBundle());
|
||
}
|
||
B.putBundle("UnspentTransactions", BB);
|
||
}
|
||
B.putFloat("rate", rate);
|
||
B.putFloat("rateAlter", rateAlter);
|
||
B.putString("confirmTx", getConfirmedTXCount().toString(16));
|
||
B.putString("unconfirmTx", getUnconfirmedTXCount().toString(16));
|
||
|
||
if (codeConfirmed != null)
|
||
B.putBoolean("codeConfirmed", codeConfirmed);
|
||
|
||
if (codeConfirmed != null)
|
||
B.putBoolean("codeConfirmed", codeConfirmed);
|
||
|
||
if (onlineVerified != null)
|
||
B.putBoolean("onlineVerified", onlineVerified);
|
||
|
||
B.putBoolean("balanceReceived", balanceReceived);
|
||
|
||
|
||
if (onlineValidated != null)
|
||
B.putBoolean("onlineValidated", onlineValidated);
|
||
|
||
|
||
if (codeConfirmed != null)
|
||
B.putBoolean("codeConfirmed", codeConfirmed);
|
||
|
||
if (codeConfirmed != null)
|
||
B.putBoolean("codeConfirmed", codeConfirmed);
|
||
|
||
if (onlineVerified != null)
|
||
B.putBoolean("onlineVerified", onlineVerified);
|
||
|
||
if (onlineValidated != null)
|
||
B.putBoolean("onlineValidated", onlineValidated);
|
||
|
||
}
|
||
|
||
public boolean isBalanceReceived() {
|
||
return balanceReceived;
|
||
}
|
||
|
||
private boolean balanceReceived = false;
|
||
|
||
public void setBalanceReceived(boolean value) {
|
||
balanceReceived = value;
|
||
}
|
||
|
||
public void loadFromBundle(Bundle B) {
|
||
UID = B.getString("UID");
|
||
CID = B.getByteArray("CID");
|
||
PIN = B.getString("PIN");
|
||
PIN2 = PIN2_Mode.valueOf(B.getString("PIN2"));
|
||
status = Status.valueOf(B.getString("Status"));
|
||
wallet = B.getString("Wallet");
|
||
error = B.getString("Error");
|
||
blockchainID = B.getString("Blockchain");
|
||
tokensDecimal = B.getInt("TokensDecimal", 18);
|
||
tokenSymbol = B.getString("TokenSymbol", "");
|
||
contractAddress = B.getString("ContractAddress", "");
|
||
if (B.containsKey("BlockchainName"))
|
||
blockchainName = B.getString("BlockchainName", "");
|
||
validationNodeDescription = B.getString("validationNodeDescription");
|
||
if (B.containsKey("dtPersonalization")) {
|
||
dtPersonalization = new Date(B.getLong("dtPersonalization"));
|
||
}
|
||
balanceDecimal = B.getString("BalanceDecimal");
|
||
balanceDecimalAlter = B.getString("BalanceDecimalAlter");
|
||
remainingSignatures = B.getInt("RemainingSignatures");
|
||
maxSignatures = B.getInt("MaxSignatures");
|
||
health = B.getInt("health");
|
||
if (B.containsKey("settingsMask")) settingsMask = B.getInt("settingsMask");
|
||
pauseBeforePIN2 = B.getInt("pauseBeforePIN2");
|
||
if (B.containsKey("signingMethod"))
|
||
signingMethod = SigningMethod.valueOf(B.getString("signingMethod"));
|
||
if (B.containsKey("Manufacturer"))
|
||
manufacturer = Manufacturer.valueOf(B.getString("Manufacturer"));
|
||
manufacturerConfirmed = B.getBoolean("ManufacturerConfirmed");
|
||
if (B.containsKey("EncryptionMode"))
|
||
encryptionMode = EncryptionMode.valueOf(B.getString("EncryptionMode"));
|
||
else
|
||
encryptionMode = null;
|
||
|
||
if (B.containsKey("SignedHashes")) setSignedHashes(B.getInt("SignedHashes"));
|
||
|
||
if (B.containsKey("FailedBalance"))
|
||
failedBalanceRequestCounter = new AtomicInteger(B.getInt("FailedBalance"));
|
||
if (B.containsKey("Issuer")) issuer = Issuer.FindIssuer(B.getString("Issuer"));
|
||
if (B.containsKey("IssuerPublicDataKey"))
|
||
issuerPublicDataKey = B.getByteArray("IssuerPublicDataKey");
|
||
|
||
if (B.containsKey("FirmwareVersion")) firmwareVersion = B.getString("FirmwareVersion");
|
||
if (B.containsKey("Batch")) batch = B.getString("Batch");
|
||
|
||
if (B.containsKey("isBalanceEqual")) setIsBalanceEqual(B.getBoolean("isBalanceEqual"));
|
||
cardPublicKeyValid = B.getBoolean("CardPublicKeyValid");
|
||
if (B.containsKey("CardPublicKey")) setCardPublicKey(B.getByteArray("CardPublicKey"));
|
||
|
||
if (B.containsKey("balanceReceived")) setBalanceReceived(B.getBoolean("balanceReceived"));
|
||
if (B.containsKey("BalanceConfirmed")) balanceConfirmed = B.getLong("BalanceConfirmed");
|
||
else balanceConfirmed = null;
|
||
if (B.containsKey("BalanceUnconfirmed"))
|
||
balanceUnconfirmed = B.getLong("BalanceUnconfirmed");
|
||
else balanceUnconfirmed = null;
|
||
|
||
if (B.containsKey("OfflineBalance")) setOfflineBalance(B.getByteArray("OfflineBalance"));
|
||
else clearOfflineBalance();
|
||
|
||
if (B.containsKey("Denomination")) setDenomination(B.getByteArray("Denomination"));
|
||
else clearDenomination();
|
||
|
||
if (B.containsKey("IssuerData") && B.containsKey("IssuerDataSignature"))
|
||
setIssuerData(B.getByteArray("IssuerData"), B.getByteArray("IssuerDataSignature"));
|
||
else setIssuerData(null, null);
|
||
|
||
if (B.containsKey("NeedWriteIssuerData"))
|
||
setNeedWriteIssuerData(B.getBoolean("NeedWriteIssuerData"));
|
||
|
||
walletPublicKeyValid = B.getBoolean("WalletPublicKeyValid");
|
||
if (B.containsKey("PublicKey")) {
|
||
pbWalletKey = B.getByteArray("PublicKey");
|
||
}
|
||
if (B.containsKey("PublicKeyRar")) {
|
||
pbWalletKeyRar = B.getByteArray("PublicKeyRar");
|
||
}
|
||
|
||
if (B.containsKey("UnspentTransactions")) {
|
||
unspentTransactions = new ArrayList<>();
|
||
Bundle BB = B.getBundle("UnspentTransactions");
|
||
Integer i = 0;
|
||
while (BB.containsKey(i.toString())) {
|
||
UnspentTransaction t = new UnspentTransaction();
|
||
t.LoadFromBundle(BB.getBundle(i.toString()));
|
||
unspentTransactions.add(t);
|
||
i++;
|
||
}
|
||
}
|
||
if (B.containsKey("rate"))
|
||
rate = B.getFloat("rate");
|
||
if (B.containsKey("rateAlter"))
|
||
rateAlter = B.getFloat("rateAlter");
|
||
if (B.containsKey("confirmTx"))
|
||
countConfirmedTX = new BigInteger(B.getString("confirmTx"), 16);
|
||
if (B.containsKey("unconfirmTx"))
|
||
countUnconfirmedTX = new BigInteger(B.getString("unconfirmTx"), 16);
|
||
|
||
if (B.containsKey("codeConfirmed"))
|
||
codeConfirmed = B.getBoolean("codeConfirmed");
|
||
|
||
if (B.containsKey("onlineVerified"))
|
||
onlineVerified = B.getBoolean("onlineVerified");
|
||
|
||
if (B.containsKey("onlineValidated"))
|
||
onlineValidated = B.getBoolean("onlineValidated");
|
||
}
|
||
|
||
private final static char[] hexArray = "0123456789ABCDEF".toCharArray();
|
||
|
||
public static String bytesToHex(byte[] bytes) {
|
||
if (bytes == null) return "";
|
||
char[] hexChars = new char[bytes.length * 2];
|
||
for (int j = 0; j < bytes.length; j++) {
|
||
int v = bytes[j] & 0xFF;
|
||
hexChars[j * 2] = hexArray[v >>> 4];
|
||
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
|
||
}
|
||
return new String(hexChars);
|
||
}
|
||
|
||
public enum EncryptionMode {
|
||
None((byte) 0x0), Fast((byte) 0x1), Strong((byte) 0x2);
|
||
|
||
private byte P;
|
||
|
||
EncryptionMode(byte P) {
|
||
this.P = P;
|
||
}
|
||
|
||
public int getP() {
|
||
return P;
|
||
}
|
||
}
|
||
|
||
public EncryptionMode encryptionMode = EncryptionMode.None;
|
||
} |