Updated on 2026-08-14

This commit is contained in:
Tangem 2018-07-16 12:43:30 +03:00
commit 4a2bb5f0bb
14 changed files with 627 additions and 31 deletions

View file

@ -610,6 +610,10 @@ public class CardProtocol {
mCard.setRemainingSignatures(readResult.getTagAsInt(TLV.Tag.TAG_RemainingSignatures));
if (readResult != null && readResult.getTLV(TLV.Tag.TAG_SignedHashes) != null) {
mCard.setSignHashes(readResult.getTLV(TLV.Tag.TAG_SignedHashes).Value);
}
} else {
mCard.setWallet("N/A");
}

View file

@ -0,0 +1,163 @@
package com.tangem.domain.wallet;
import android.util.Pair;
public class BalanceValidator {
private String firstLine;
private String secondLine;
private int score;
public String GetFirstLine()
{
return firstLine;
}
public String GetSecondLine()
{
if(score < 0) score = 0;
return score + "% safe. " + secondLine;
}
public void Check(TangemCard card)
{
String defaultFirstLine = "Unknown balance.";
String successFirstLine = "Verified balance.";
// rule 1
if(!CheckOfflineBalance(card) && !CheckOnlineBalance(card)) {
score = 0;
secondLine = "Do not accept. Balance cannot be verified.";
firstLine = defaultFirstLine;
return;
}
// rule 2.a
if(!VerificationWalletKey(card)) {
score = 0;
secondLine = "Do not accept. Wallet verification failed.";
firstLine = defaultFirstLine;
return;
}
// rule 2.c
if(!CheckAttestationServiceResult(card)) {
score = 0;
secondLine = "Do not accept. Tangem Attestation service says card is not genuine.";
firstLine = successFirstLine;
return;
}
// rule 3
if(CheckOnlineBalance(card) && !NotConfirmTransaction(card))
{
if(card.isBalanceRecieved() && card.isBalanceEqual()) {
score = 100;
firstLine = "Verified balance.";
secondLine += " Confirmed balance and banknote identity.";
}
if(card.getFailedBalanceRequestCounter()!=0) {
score = 100 - 10 * card.getFailedBalanceRequestCounter();
firstLine = "Verified balance.";
secondLine += " Not all nodes have returned balance. App is requesting more nodes to be 100% sure...";
if(score <= 0)
return;
}
if(card.isBalanceRecieved() && !card.isBalanceEqual()) {
score = 0;
firstLine = "Disputed balance.";
secondLine += " Cannot obtaine trusted balance at the moment. Try to tap and check this banknote later.";
return;
}
}
// rule 7
if(CheckOfflineBalance(card) && !CheckOnlineBalance(card))
{
score = -10;
String firstLine = "Virified offline balance.";
secondLine += " Restore internet connection to be more confidient.";
if(score <= 0)
return;
}
// rule 2.b
if(!CheckAttestationServiceAvailable(card))
{
score = -15;
secondLine += "Card identity was not verified. Cannot reach attestation service.";
firstLine = successFirstLine;
if(score <= 0)
return;
}
// rule 5
if(IsLostSecondRead(card))
{
score = -30;
secondLine += " Wallet and banknote keys were not verified (tap again).";
if(score <= 0)
return;
}
// rule 4
if(!CheckSignHashes(card))
{
score = -50;
secondLine = "Unguaranteed balance.";
firstLine += " Potential unsent transaction at the moment. Try to tap and check this banknote later.";
if(score <= 0)
return;
}
// rule 6
if(NotConfirmTransaction(card))
{
score = -50;
String firstLine = "Unguaranted balance.";
secondLine = " Loading in progress. Wait for full confirmation in blockchain.";
if(score <= 0)
return;
}
}
boolean CheckOfflineBalance(TangemCard card)
{
return card.getOfflineBalance() != null;
}
boolean CheckOnlineBalance(TangemCard card)
{
return card.isBalanceRecieved();
}
boolean VerificationWalletKey(TangemCard card)
{
return card.isWalletPublicKeyValid();
}
boolean CheckSignHashes(TangemCard card)
{
return card.getSignHashes()==null;
}
boolean CheckAttestationServiceAvailable(TangemCard card)
{
return card.isOnlineVerified() != null;
}
boolean CheckAttestationServiceResult(TangemCard card)
{
return card.isOnlineVerified() != null && card.isOnlineVerified() == true;
}
boolean NotConfirmTransaction(TangemCard card)
{
return card.getBalanceUnconfirmed()!=0;
}
boolean IsLostSecondRead(TangemCard card)
{
return card.isCodeConfirmed() != null;
}
}

View file

@ -117,4 +117,14 @@ public enum Issuer {
return Issuer.Unknown;
}
public static Issuer FindIssuer(String ID) {
Issuer[] issuers = Issuer.values();
for (int i = 1; i < issuers.length; i++) {
if (issuers[i].ID.equals(ID)) {
return issuers[i];
}
}
return Issuer.Unknown;
}
}

View file

@ -1,5 +1,6 @@
package com.tangem.domain.wallet;
import java.math.BigDecimal;
import java.util.concurrent.atomic.AtomicInteger;
/**
@ -14,8 +15,32 @@ public class SharedData
public int allRequest;
public AtomicInteger errorRequest;
public BigDecimal payload;
public synchronized boolean UpdatePayload(BigDecimal value)
{
if(payload == null || payload.compareTo(value)!=0)
{
boolean isChange = true;
if(payload == null)
isChange = false;
if(value!=BigDecimal.ZERO)
payload = value;
return isChange;
}
return false;
}
public void SetErrorRequest(int val)
{
errorRequest = new AtomicInteger(val);
}
public SharedData(int requstCount)
{
payload = BigDecimal.ZERO;
allRequest = requstCount;
errorRequest = new AtomicInteger(0);
requestCounter = new AtomicInteger(0);

View file

@ -11,10 +11,10 @@ import com.tangem.wallet.R;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Created by dvol on 16.07.2017.
@ -270,6 +270,42 @@ public class TangemCard {
}
}
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;
}
private boolean balanceRecieved = false;
public boolean isBalanceRecieved() {
return balanceRecieved;
}
public void setBalanceRecieved(boolean balanceRecieved)
{
this.balanceRecieved = balanceRecieved;
}
public int getRemainingSignatures() {
return remainingSignatures;
}
@ -666,6 +702,31 @@ public class TangemCard {
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) {
@ -1135,6 +1196,16 @@ public class TangemCard {
return Denomination;
}
public byte[] SignHashes;
public void setSignHashes(byte[] SignHashes) {
this.SignHashes = SignHashes;
}
public byte[] getSignHashes() {
return SignHashes;
}
public void clearDenomination() {
Denomination = null;
}
@ -1205,12 +1276,16 @@ public class TangemCard {
if (encryptionMode != null) B.putString("EncryptionMode", encryptionMode.name());
if (issuer != null) B.putString("Issuer", issuer.name());
if (firmwareVersion != null) B.putString("FirmwareVersion", firmwareVersion);
if(balanceEqual != null) B.putBoolean("isBalanceEqual", balanceEqual);
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());
if(getSignHashes()!=null) B.putByteArray("SignHashes", getSignHashes());
B.putString("Wallet", wallet);
B.putString("Error", error);
B.putBoolean("WalletPublicKeyValid", isWalletPublicKeyValid());
@ -1255,6 +1330,22 @@ public class TangemCard {
B.putFloat("rate", rate);
B.putFloat("rateAlter", rateAlter);
B.putString("confirmTx", GetConfirmTXCount().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("balanceRecieved", balanceRecieved);
if( onlineValidated!=null )
B.putBoolean("onlineValidated", onlineValidated);
}
public void LoadFromBundle(Bundle B) {
@ -1292,12 +1383,17 @@ public class TangemCard {
else
encryptionMode = null;
if (B.containsKey("Issuer")) issuer = Issuer.valueOf(B.getString("Issuer"));
if(B.containsKey("SignHashes")) setSignHashes(B.getByteArray("SignHashes"));
if(B.containsKey("FailedBalance")) failedBalanceRequestCounter = new AtomicInteger(B.getInt("FailedBalance"));
if (B.containsKey("Issuer")) issuer = Issuer.FindIssuer(B.getString("Issuer"));
if (B.containsKey("FirmwareVersion")) firmwareVersion = B.getString("FirmwareVersion");
if(B.containsKey("isBalanceEqual")) setIsBalanceEqual(B.getBoolean("isBalanceEqual"));
cardPublicKeyValid = B.getBoolean("CardPublicKeyValid");
if (B.containsKey("CardPublicKey")) setCardPublicKey(B.getByteArray("CardPublicKey"));
if(B.containsKey("balanceRecieved")) setBalanceRecieved(B.getBoolean("balanceRecieved"));
if (B.containsKey("BalanceConfirmed")) balanceConfirmed = B.getLong("BalanceConfirmed");
else balanceConfirmed = null;
if (B.containsKey("BalanceUnconfirmed"))
@ -1364,40 +1460,27 @@ public class TangemCard {
rateAlter = B.getFloat("rateAlter");
if (B.containsKey("confirmTx"))
countConfirmTX = new BigInteger(B.getString("confirmTx"), 16);
}
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);
if( B.containsKey("codeConfirmed") )
codeConfirmed=B.getBoolean("codeConfirmed");
if( B.containsKey("onlineVerified") )
onlineVerified=B.getBoolean("onlineVerified");
if( B.containsKey("onlineValidated") )
onlineValidated=B.getBoolean("onlineValidated");
}
public int getCardImageResource() {
switch (getBlockchainID()) {
case "BTC":
if ( bytesToHex(getDenomination()).equals("40420F0000000000") )
return R.drawable.card_btc001;
else if (bytesToHex(getDenomination()).equals("404B4C0000000000") )
return R.drawable.card_btc005;
else if (bytesToHex(getDenomination()).equals("0000000000000000") )
return R.drawable.card_btc_hk_s;
else
return R.drawable.card_default;
return R.drawable.card_btc001;
case "Token":
if (getTokenSymbol().equals("SEED"))
return R.drawable.card_seed;
else
return R.drawable.card_default;
case "ETH\\XTZ":
return R.drawable.card_seed;
default:
return R.drawable.card_default;
return R.drawable.card_btc001;
}
}