From c736d3455771a070367c306e5b403d6d0feb871d Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 8 May 2020 14:46:37 +0300 Subject: [PATCH 1/6] Updated on 2026-08-14 --- .../main/java/com/tangem/data/Blockchain.java | 1 + .../tangem/data/network/ServerApiBinance.java | 14 +- .../com/tangem/wallet/CoinEngineFactory.kt | 4 + .../java/com/tangem/wallet/TangemContext.java | 3 + .../wallet/binance/BinanceAssetData.java | 55 ++ .../wallet/binance/BinanceAssetEngine.java | 584 ++++++++++++++++++ 6 files changed, 660 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/com/tangem/wallet/binance/BinanceAssetData.java create mode 100644 app/src/main/java/com/tangem/wallet/binance/BinanceAssetEngine.java diff --git a/app/src/main/java/com/tangem/data/Blockchain.java b/app/src/main/java/com/tangem/data/Blockchain.java index 402348982e..3224ae7da0 100644 --- a/app/src/main/java/com/tangem/data/Blockchain.java +++ b/app/src/main/java/com/tangem/data/Blockchain.java @@ -23,6 +23,7 @@ public enum Blockchain { Ripple("XRP", "XRP", 1000000.0, R.drawable.ic_logo_xrp, "XRP"), Binance("BINANCE", "BNB", 100000000.0, R.drawable.ic_logo_binance, "Binance"), BinanceTestNet("BINANCE/test", "BNB", 100000000.0, R.drawable.ic_logo_binance, "Binance Testnet"), + BinanceAsset("BinanceAsset", "BNB", 100000000.0, R.drawable.ic_logo_binance, "Binance"), Matic("MATIC", "MTX", 1.0, R.drawable.tangem2, "Matic"), MaticTestNet("MATIC/test", "MTX", 1.0, R.drawable.tangem2, "Matic Testnet"), Stellar("XLM", "XLM", 10000000.0, R.drawable.ic_logo_stellar, "Stellar"), diff --git a/app/src/main/java/com/tangem/data/network/ServerApiBinance.java b/app/src/main/java/com/tangem/data/network/ServerApiBinance.java index b242100ae0..783d303add 100644 --- a/app/src/main/java/com/tangem/data/network/ServerApiBinance.java +++ b/app/src/main/java/com/tangem/data/network/ServerApiBinance.java @@ -4,6 +4,7 @@ import android.util.Log; import com.tangem.wallet.TangemContext; import com.tangem.wallet.Transaction; +import com.tangem.wallet.binance.BinanceAssetData; import com.tangem.wallet.binance.BinanceData; import com.tangem.wallet.binance.client.BinanceDexApiRestClient; import com.tangem.wallet.binance.client.domain.Account; @@ -57,6 +58,17 @@ public class ServerApiBinance { } } + if (binanceData instanceof BinanceAssetData) { + BinanceAssetData binanceAssetData = (BinanceAssetData) binanceData; + for (Balance balance : account.getBalances()) { + if (balance.getSymbol().equals(ctx.getCard().getContractAddress())) { + binanceAssetData.setBalanceReceived(true); + binanceAssetData.setAssetBalance(balance.getFree()); + break; + } + } + } + if (!binanceData.isBalanceReceived()) { binanceData.setBalanceReceived(true); binanceData.setBalance("0"); @@ -69,7 +81,7 @@ public class ServerApiBinance { @Override public void onError(Throwable e) { Log.e(TAG, "getBalance onError" + e.getMessage()); - if (e.getMessage().contains("code=404")) { + if (e.getMessage().contains("account not found")) { ((BinanceData)ctx.getCoinData()).setError404(true); responseListener.onFail(); } else { diff --git a/app/src/main/java/com/tangem/wallet/CoinEngineFactory.kt b/app/src/main/java/com/tangem/wallet/CoinEngineFactory.kt index 8bfbb7f361..0cf887e769 100644 --- a/app/src/main/java/com/tangem/wallet/CoinEngineFactory.kt +++ b/app/src/main/java/com/tangem/wallet/CoinEngineFactory.kt @@ -3,6 +3,7 @@ package com.tangem.wallet import android.util.Log import com.tangem.data.Blockchain import com.tangem.wallet.bch.BtcCashEngine +import com.tangem.wallet.binance.BinanceAssetEngine import com.tangem.wallet.binance.BinanceEngine import com.tangem.wallet.btc.BtcEngine import com.tangem.wallet.btcmultisig.BtcMultisigEngine @@ -52,6 +53,7 @@ object CoinEngineFactory { Blockchain.Cardano -> CardanoEngine() Blockchain.Ripple -> XrpEngine() Blockchain.Binance, Blockchain.BinanceTestNet -> BinanceEngine() + Blockchain.BinanceAsset -> BinanceAssetEngine() Blockchain.Matic, Blockchain.MaticTestNet -> MaticTokenEngine() Blockchain.StellarTestNet, Blockchain.Stellar -> XlmEngine() Blockchain.StellarAsset -> XlmAssetEngine() @@ -93,6 +95,8 @@ object CoinEngineFactory { XrpEngine(context) else if (Blockchain.Binance == context.blockchain || Blockchain.BinanceTestNet == context.blockchain) BinanceEngine(context) + else if (Blockchain.BinanceAsset == context.blockchain) + BinanceAssetEngine(context) else if (Blockchain.Matic == context.blockchain || Blockchain.MaticTestNet == context.blockchain) MaticTokenEngine(context) else if (Blockchain.Stellar == context.blockchain || Blockchain.StellarTestNet == context.blockchain) diff --git a/app/src/main/java/com/tangem/wallet/TangemContext.java b/app/src/main/java/com/tangem/wallet/TangemContext.java index a027d33f3b..09674de601 100644 --- a/app/src/main/java/com/tangem/wallet/TangemContext.java +++ b/app/src/main/java/com/tangem/wallet/TangemContext.java @@ -47,6 +47,9 @@ public class TangemContext { if (blockchain == Blockchain.Stellar && card.isToken()) { return Blockchain.StellarAsset; } + if (blockchain == Blockchain.Binance && card.isToken()) { + return Blockchain.BinanceAsset; + } return blockchain; } diff --git a/app/src/main/java/com/tangem/wallet/binance/BinanceAssetData.java b/app/src/main/java/com/tangem/wallet/binance/BinanceAssetData.java new file mode 100644 index 0000000000..6c06d4dd75 --- /dev/null +++ b/app/src/main/java/com/tangem/wallet/binance/BinanceAssetData.java @@ -0,0 +1,55 @@ +package com.tangem.wallet.binance; + +import android.os.Bundle; +import android.util.Log; + +import com.tangem.wallet.CoinEngine; + +public class BinanceAssetData extends BinanceData { + private String assetBalance; + private String assetSymbol; + + @Override + public void loadFromBundle(Bundle B) { + super.loadFromBundle(B); + + if (B.containsKey("AssetBalance")) assetBalance = B.getString("AssetBalance"); + else assetBalance = null; + if (B.containsKey("AssetSymbol")) assetSymbol = B.getString("AssetSymbol"); + else assetSymbol = null; + } + + @Override + public void saveToBundle(Bundle B) { + super.saveToBundle(B); + try { + if (assetBalance != null) B.putString("AssetBalance", assetBalance); + if (assetSymbol != null) B.putString("AssetSymbol", assetSymbol); + } catch (Exception e) { + Log.e("Can't save to bundle ", e.getMessage()); + } + } + + @Override + public void clearInfo() { + super.clearInfo(); + assetBalance = null; + } + + @Override + public boolean hasBalanceInfo() { + return super.hasBalanceInfo() || assetBalance != null; + } + + public CoinEngine.Amount getAssetBalance() { + return assetBalance == null ? null : new CoinEngine.Amount(assetBalance, assetSymbol); + } + + public void setAssetBalance(String assetBalance) { + this.assetBalance = assetBalance; + } + + public void setAssetSymbol(String assetSymbol) { + this.assetSymbol = assetSymbol; + } +} diff --git a/app/src/main/java/com/tangem/wallet/binance/BinanceAssetEngine.java b/app/src/main/java/com/tangem/wallet/binance/BinanceAssetEngine.java new file mode 100644 index 0000000000..d3dc0dc13e --- /dev/null +++ b/app/src/main/java/com/tangem/wallet/binance/BinanceAssetEngine.java @@ -0,0 +1,584 @@ +package com.tangem.wallet.binance; + +import android.net.Uri; +import android.text.InputFilter; +import android.util.Log; + +import androidx.annotation.NonNull; + +import com.tangem.App; +import com.tangem.data.Blockchain; +import com.tangem.data.network.BinanceApi; +import com.tangem.data.network.Server; +import com.tangem.data.network.ServerApiBinance; +import com.tangem.data.network.model.BinanceFees; +import com.tangem.tangem_card.data.TangemCard; +import com.tangem.tangem_card.reader.CardProtocol; +import com.tangem.tangem_card.tasks.SignTask; +import com.tangem.tangem_card.util.Util; +import com.tangem.util.CryptoUtil; +import com.tangem.util.DecimalDigitsInputFilter; +import com.tangem.wallet.BalanceValidator; +import com.tangem.wallet.CoinData; +import com.tangem.wallet.CoinEngine; +import com.tangem.wallet.R; +import com.tangem.wallet.TangemContext; +import com.tangem.wallet.binance.client.BinanceDexApiClientFactory; +import com.tangem.wallet.binance.client.BinanceDexApiRestClient; +import com.tangem.wallet.binance.client.BinanceDexEnvironment; +import com.tangem.wallet.binance.client.domain.broadcast.TransactionOption; +import com.tangem.wallet.binance.client.domain.broadcast.Transfer; +import com.tangem.wallet.binance.client.encoding.Bech32; +import com.tangem.wallet.binance.client.encoding.Crypto; +import com.tangem.wallet.binance.client.encoding.message.MessageType; +import com.tangem.wallet.binance.client.encoding.message.TransactionRequestAssemblerExtSign; +import com.tangem.wallet.binance.client.encoding.message.TransferMessage; + +import org.bitcoinj.core.Utils; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.math.RoundingMode; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; +import java.util.List; + +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; +import retrofit2.Retrofit; +import retrofit2.converter.gson.GsonConverterFactory; + +public class BinanceAssetEngine extends CoinEngine { + private static final String TAG = BinanceAssetEngine.class.getSimpleName(); + + public BinanceAssetData coinData = null; + private BinanceDexApiRestClient client = null; + + public BinanceAssetEngine(TangemContext context) throws Exception { + super(context); + if (context.getCoinData() == null) { + coinData = new BinanceAssetData(); + context.setCoinData(coinData); + } else if (context.getCoinData() instanceof BinanceAssetData) { + coinData = (BinanceAssetData) context.getCoinData(); + } else { + throw new Exception("Invalid type of Blockchain data for " + TAG); + } + client = BinanceDexApiClientFactory.newInstance().newRestClient(BinanceDexEnvironment.PROD.getBaseUrl()); + coinData.setChainId("Binance-Chain-Tigris"); + } + + public BinanceAssetEngine() { + super(); + } + + private static int getDecimals() { + return 8; + } + + private void checkBlockchainDataExists() throws Exception { + if (coinData == null) throw new Exception("No blockchain data"); + } + + @Override + public boolean awaitingConfirmation() { + return App.pendingTransactionsStorage.hasTransactions(ctx.getCard()); + } + + @Override + public String getBalanceHTML() { + Amount balance = getBalance(); + Amount assetBalance = coinData.getAssetBalance(); + if (balance != null) { + if (assetBalance != null) { + return assetBalance.toDescriptionString(getDecimals()) + "
+ " + balance.toDescriptionString(getDecimals()) + " for fee"; + } + return balance.toDescriptionString(getDecimals()); + } else { + return ""; + } + } + + @Override + public String getBalanceCurrency() { + if (hasBalanceInfo()) { + if (coinData.getAssetBalance() != null) { + return ctx.getCard().tokenSymbol; + } else { + return getFeeCurrency(); + } + } else { + return getFeeCurrency(); + } + } + + @Override + public boolean isBalanceNotZero() { + if (!hasBalanceInfo()) + return false; + return (coinData.getBalance() != null && coinData.getBalance().notZero()) || + (coinData.getAssetBalance() != null && coinData.getAssetBalance().notZero()); + } + + @Override + public boolean hasBalanceInfo() { + if (coinData == null) return false; + return coinData.hasBalanceInfo(); + } + + public boolean isExtractPossible() { + if (!hasBalanceInfo()) { + ctx.setMessage(R.string.loaded_wallet_error_obtaining_blockchain_data); + } else if (!isBalanceNotZero()) { + ctx.setMessage(R.string.general_wallet_empty); + } else if (awaitingConfirmation()) { + ctx.setMessage(R.string.loaded_wallet_message_wait); + } else { + return true; + } + return false; + } + + @Override + public String getFeeCurrency() { + return "BNB"; + } + + @Override + public boolean validateAddress(String address) { + if (address == null || address.isEmpty()) { + return false; + } + + try { + Crypto.decodeAddress(address); + } catch (Exception e) { + return false; + } + + if (ctx.getBlockchain() == Blockchain.Binance && !address.startsWith("bnb1")) { + return false; + } + + if (ctx.getBlockchain() == Blockchain.BinanceTestNet && !address.startsWith("tbnb1")) { + return false; + } + + return true; + } + + @Override + public boolean isNeedCheckNode() { + return true; + } + + @Override + public Uri getWalletExplorerUri() { + if (ctx.getBlockchain() == Blockchain.Binance) { + return Uri.parse("https://explorer.binance.org/address/" + ctx.getCoinData().getWallet()); + } else if (ctx.getBlockchain() == Blockchain.BinanceTestNet) { + return Uri.parse("https://testnet-explorer.binance.org/address/" + ctx.getCoinData().getWallet()); + } else { + Log.e(TAG, "Invalid blockchain for BinanceEngine"); + return Uri.parse("https://explorer.binance.org/address/" + ctx.getCoinData().getWallet()); + } + } + + public Uri getShareWalletUri() { + return Uri.parse(ctx.getCoinData().getWallet()); + } + + @Override + public InputFilter[] getAmountInputFilters() { + return new InputFilter[]{new DecimalDigitsInputFilter(getDecimals())}; + } + + @Override + public boolean checkNewTransactionAmount(Amount amount) { + if (!hasBalanceInfo()) return false; + Amount balance; + try { + if (amount.getCurrency().equals(ctx.getCard().tokenSymbol)) { + balance = coinData.getAssetBalance(); + } else if (amount.getCurrency().equals(getFeeCurrency())) { + balance = coinData.getBalance(); + } else { + return false; + } + } catch (Exception e) { + e.printStackTrace(); + return false; + } + return amount.compareTo(balance) <= 0; + } + + @Override + public boolean checkNewTransactionAmountAndFee(Amount amount, Amount fee, Boolean isFeeIncluded) { + if (!hasBalanceInfo()) return false; + + try { + Amount balance = coinData.getBalance(); + + if (fee == null || amount == null || fee.isZero() || amount.isZero()) + return false; + + + if (amount.getCurrency().equals(ctx.getCard().tokenSymbol)) { + // token transaction + if (fee.compareTo(balance) > 0) + return false; + } else if (amount.getCurrency().equals(getFeeCurrency())) { + // standard ETH transaction + if (isFeeIncluded && (amount.compareTo(balance) > 0 || fee.compareTo(balance) > 0)) + return false; + + if (!isFeeIncluded && amount.add(fee).compareTo(balance) > 0) + return false; + } else { + return false; + } + } catch (Exception e) { + e.printStackTrace(); + return false; + } + + return true; + } + + @Override + public boolean validateBalance(BalanceValidator balanceValidator) { + try { + if (((ctx.getCard().getOfflineBalance() == null) && !ctx.getCoinData().isBalanceReceived()) || (!ctx.getCoinData().isBalanceReceived() && (ctx.getCard().getRemainingSignatures() != ctx.getCard().getMaxSignatures()))) { + + if (coinData.isError404()) { + balanceValidator.setScore(0); + balanceValidator.setFirstLine(R.string.balance_validator_first_line_no_account); + balanceValidator.setSecondLine(R.string.balance_validator_second_line_create_account); + } else { + balanceValidator.setScore(0); + balanceValidator.setFirstLine(R.string.balance_validator_first_line_unknown_balance); + balanceValidator.setSecondLine(R.string.balance_validator_second_line_unverified_balance); + return false; + } + } + + if (coinData.isBalanceReceived()) { + balanceValidator.setScore(100); + balanceValidator.setFirstLine(R.string.balance_validator_first_line_verified_balance); + balanceValidator.setSecondLine(R.string.balance_validator_second_line_confirmed_in_blockchain); + if (coinData.getBalance().isZero() && (coinData.getAssetBalance() == null || coinData.getAssetBalance().isZero())) { + balanceValidator.setFirstLine(R.string.balance_validator_first_line_empty_wallet); + balanceValidator.setSecondLine(R.string.empty_string); + } + } + + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + @Override + public Amount getBalance() { + if (!hasBalanceInfo()) return null; + if (coinData.getAssetBalance() != null) { + return coinData.getAssetBalance(); + } else { + return coinData.getBalance(); + } + } + + @Override + public String evaluateFeeEquivalent(String fee) { + if (!coinData.getAmountEquivalentDescriptionAvailable()) return ""; + try { + Amount feeAmount = new Amount(fee, getFeeCurrency()); + return feeAmount.toEquivalentString(coinData.getRate()); + } catch (Exception e) { + return ""; + } + } + + @Override + public String getBalanceEquivalent() { + if (!hasBalanceInfo()) { + return ""; + } + try { + if (coinData.getAssetBalance().notZero()) { + return ""; + } else { + return coinData.getBalance().toEquivalentString(coinData.getRateAlter()); + } + } catch (Exception e) { + e.printStackTrace(); + return ""; + } + } + + public String calculateAddress(byte[] pkCompressed) throws Exception { + byte[] pubKeyHash = Utils.sha256hash160(pkCompressed); + return Bech32.encode("bnb", Crypto.convertBits(pubKeyHash, 0, pubKeyHash.length, 8, 5, false)); + } + + @Override + public Amount convertToAmount(InternalAmount internalAmount) { + return new Amount(internalAmount, getBalanceCurrency()); + } + + @Override + public Amount convertToAmount(String strAmount, String currency) { + return new Amount(strAmount, currency); + } + + @Override + public InternalAmount convertToInternalAmount(Amount amount) { + return new InternalAmount(amount, getBalanceCurrency()); + } + + @Override + public InternalAmount convertToInternalAmount(byte[] bytes) { + 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), getBalanceCurrency()); + } + + @Override + public byte[] convertToByteArray(InternalAmount internalAmount) { + return Util.longToByteArray(internalAmount.longValueExact()); + } + + @Override + public CoinData createCoinData() { + return new BinanceAssetData(); + } + + @Override + public String getUnspentInputsDescription() { + return ""; + } + + @Override + public void defineWallet() throws CardProtocol.TangemException { + try { + String wallet = calculateAddress(ctx.getCard().getWalletPublicKeyRar()); + ctx.getCoinData().setWallet(wallet); + coinData.setAssetSymbol(ctx.getCard().tokenSymbol); + } catch (Exception e) { + ctx.getCoinData().setWallet("ERROR"); + throw new CardProtocol.TangemException("Can't define wallet address"); + } + } + + @Override + public SignTask.TransactionToSign constructTransaction(Amount amountValue, Amount feeValue, boolean IncFee, String targetAddress) throws Exception { + checkBlockchainDataExists(); + + String amount; + + if (IncFee && amountValue.getCurrency().equals(getFeeCurrency())) { //Coin transfer only + amount = amountValue.subtract(feeValue).setScale(getDecimals(), RoundingMode.DOWN).toPlainString(); + } else { + amount = amountValue.setScale(getDecimals(), RoundingMode.DOWN).toPlainString(); + } + + byte[] pubKey = ctx.getCard().getWalletPublicKeyRar(); + byte[] pubKeyPrefix = MessageType.PubKey.getTypePrefixBytes(); + byte[] pubKeyForSign = new byte[pubKey.length + pubKeyPrefix.length + 1]; + System.arraycopy(pubKeyPrefix, 0, pubKeyForSign, 0, pubKeyPrefix.length); + pubKeyForSign[pubKeyPrefix.length] = (byte) 33; + System.arraycopy(pubKey, 0, pubKeyForSign, pubKeyPrefix.length + 1, pubKey.length); + + Transfer transfer = new Transfer(); + transfer.setCoin(amountValue.getCurrency().equals(getFeeCurrency()) ? getFeeCurrency() : ctx.getCard().getContractAddress()); + transfer.setFromAddress(ctx.getCoinData().getWallet()); + transfer.setToAddress(targetAddress); + transfer.setAmount(amount); + + TransactionOption options = TransactionOption.DEFAULT_INSTANCE; + + TransactionRequestAssemblerExtSign txAssembler = client.prepareTransfer(transfer, coinData, pubKeyForSign, options, true); + // TransactionRequestAssembler.buildTransfer as reference + TransferMessage msgBean = txAssembler.createTransferMessage(transfer); + byte[] msg = txAssembler.encodeTransferMessage(msgBean); + byte[] dataForSign = txAssembler.prepareForSign(msgBean); + + return new SignTask.TransactionToSign() { + + @Override + public boolean isSigningMethodSupported(TangemCard.SigningMethod signingMethod) { + return signingMethod == TangemCard.SigningMethod.Sign_Hash || signingMethod == TangemCard.SigningMethod.Sign_Raw; + } + + @Override + public byte[][] getHashesToSign() throws NoSuchAlgorithmException { + byte[][] hashForSign = new byte[1][]; + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + hashForSign[0] = digest.digest(dataForSign); + return hashForSign; + } + + @Override + public byte[] getRawDataToSign() { + return dataForSign; + } + + @Override + public String getHashAlgToSign() { + return "sha-256"; + } + + @Override + public byte[] getIssuerTransactionSignature(byte[] dataToSignByIssuer) throws Exception { + throw new Exception("Transaction validation by issuer not supported in this version"); + } + + @Override + public byte[] onSignCompleted(byte[] signFromCard) throws Exception { + int size = signFromCard.length / 2; + BigInteger r = new BigInteger(1, Arrays.copyOfRange(signFromCard, 0, size)); + BigInteger s = new BigInteger(1, Arrays.copyOfRange(signFromCard, size, size * 2)); + s = CryptoUtil.toCanonicalised(s); + + byte[] resultSig = new byte[64]; + System.arraycopy(Utils.bigIntegerToBytes(r, 32), 0, resultSig, 0, 32); + System.arraycopy(Utils.bigIntegerToBytes(s, 32), 0, resultSig, 32, 32); + + // TransactionRequestAssembler.buildTransfer as reference + byte[] signature = txAssembler.encodeSignature(resultSig); + byte[] txForSend = txAssembler.encodeStdTx(msg, signature); + + notifyOnNeedSendTransaction(txForSend); + return txForSend; + } + }; + } + + public void requestBalanceAndUnspentTransactions(BlockchainRequestsCallbacks blockchainRequestsCallbacks) { + try { + ServerApiBinance serverApiBinance = new ServerApiBinance(); + + ServerApiBinance.ResponseListener responseListener = new ServerApiBinance.ResponseListener() { + @Override + public void onSuccess() { + blockchainRequestsCallbacks.onComplete(true); + } + + @Override + public void onFail() { + blockchainRequestsCallbacks.onComplete(false); + } + }; + + serverApiBinance.setResponseListener(responseListener); + serverApiBinance.getBalance(ctx, client); + + coinData.setValidationNodeDescription(Server.ApiBinance.URL_BINANCE); + + } catch (Exception e) { + e.printStackTrace(); + Log.e(TAG, "FAIL Binance balance exception"); + ctx.setError(e.getMessage()); + blockchainRequestsCallbacks.onComplete(false); + } + } + + public void requestFee(BlockchainRequestsCallbacks blockchainRequestsCallbacks, String targetAddress, Amount amount) { + try { + String baseUrl = Server.ApiBinance.Method.API_V1; + + Retrofit retrofitBinance = new Retrofit.Builder() + .baseUrl(baseUrl) + .addConverterFactory(GsonConverterFactory.create()) + .build(); + + BinanceApi binanceApi = retrofitBinance.create(BinanceApi.class); + Call> call = binanceApi.binanceFees(); + call.enqueue(new Callback>() { + @Override + public void onResponse(@NonNull Call> call, @NonNull Response> response) { + if (response.code() == 200) { + for (BinanceFees fee : response.body()) { + if (fee.getFixed_fee_params() != null) { + Long longFee = Long.valueOf(fee.getFixed_fee_params().getFee()); + Amount feeAmount = new Amount(BigDecimal.valueOf(longFee).divide(BigDecimal.valueOf(100000000)).setScale(8, RoundingMode.DOWN), getFeeCurrency()); + coinData.minFee = coinData.normalFee = coinData.maxFee = feeAmount; + Log.i(TAG, "requestFee onResponse " + response.code()); + blockchainRequestsCallbacks.onComplete(true); + } + } + } else { + ctx.setError(response.code()); + Log.e(TAG, "requestFee onResponse " + response.code()); + blockchainRequestsCallbacks.onComplete(false); + } + } + + @Override + public void onFailure(@NonNull Call> call, @NonNull Throwable t) { + ctx.setError(t.getMessage()); + Log.e(TAG, "requestFee onFailure " + t.getMessage()); + blockchainRequestsCallbacks.onComplete(false); + } + }); + } catch (Exception e) { + ctx.setError(e.getMessage()); + e.printStackTrace(); + Log.e(TAG, "FAIL Binance fee exception"); + blockchainRequestsCallbacks.onComplete(false); + } + } + + public void requestSendTransaction(BlockchainRequestsCallbacks blockchainRequestsCallbacks, byte[] txForSend) { +// RequestBody requestBody = TransactionRequestAssemblerExtSign.createRequestBody(txForSend); + try { + ServerApiBinance serverApiBinance = new ServerApiBinance(); + + ServerApiBinance.ResponseListener responseListener = new ServerApiBinance.ResponseListener() { + @Override + public void onSuccess() { + ctx.setError(null); + blockchainRequestsCallbacks.onComplete(true); + } + + @Override + public void onFail() { + ctx.setError("Broadcast error"); + blockchainRequestsCallbacks.onComplete(false); + } + }; + + serverApiBinance.setResponseListener(responseListener); + serverApiBinance.sendTransaction(txForSend, client); + + } catch (Exception e) { + Log.e(TAG, e.getMessage()); + ctx.setError(e.getMessage()); + blockchainRequestsCallbacks.onComplete(false); + } + } + + @Override + public int pendingTransactionTimeoutInSeconds() { + return 9; + } + + @Override + public boolean allowSelectFeeLevel() { + return false; + } + + @Override + public boolean allowSelectFeeInclusion() { + return coinData.getAssetBalance() == null; + } + + @Override + public boolean needMultipleLinesForBalance() { + return true; + } +} From 256a7f50f02231286c23db00d5b08e7c32e8ceff Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 8 May 2020 19:34:41 +0300 Subject: [PATCH 2/6] Updated on 2026-08-14 --- .../binance/BinanceTransactionBuilder.kt | 6 ++++-- .../blockchains/binance/BinanceWalletManager.kt | 7 ++++--- .../binance/network/BinanceNetworkManager.kt | 14 +++++++++----- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/binance/BinanceTransactionBuilder.kt b/blockchain/src/main/java/com/tangem/blockchain/blockchains/binance/BinanceTransactionBuilder.kt index 49c7c20368..63743abc73 100644 --- a/blockchain/src/main/java/com/tangem/blockchain/blockchains/binance/BinanceTransactionBuilder.kt +++ b/blockchain/src/main/java/com/tangem/blockchain/blockchains/binance/BinanceTransactionBuilder.kt @@ -5,6 +5,7 @@ import com.tangem.blockchain.blockchains.binance.client.domain.broadcast.Transfe import com.tangem.blockchain.blockchains.binance.client.encoding.message.MessageType import com.tangem.blockchain.blockchains.binance.client.encoding.message.TransactionRequestAssemblerExtSign import com.tangem.blockchain.blockchains.binance.client.encoding.message.TransferMessage +import com.tangem.blockchain.common.AmountType import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.TransactionData import com.tangem.blockchain.extensions.Result @@ -28,13 +29,14 @@ class BinanceTransactionBuilder( private var transferMessage: TransferMessage? = null fun buildToSign(transactionData: TransactionData): Result { + val amount = transactionData.amount - if (!transactionData.amount.isAboveZero()) return Result.Failure(Exception("Transaction amount is not defined")) + if (!amount.isAboveZero()) return Result.Failure(Exception("Transaction amount is not defined")) val accountNumber = accountNumber ?: return Result.Failure(Exception("No account number")) val sequence = sequence ?: return Result.Failure(Exception("No sequence")) val transfer = Transfer() - transfer.coin = transactionData.amount.currencySymbol + transfer.coin = if (amount.type == AmountType.Coin) amount.currencySymbol else amount.address transfer.fromAddress = transactionData.sourceAddress transfer.toAddress = transactionData.destinationAddress transfer.amount = transactionData.amount.value!! diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/binance/BinanceWalletManager.kt b/blockchain/src/main/java/com/tangem/blockchain/blockchains/binance/BinanceWalletManager.kt index e8d2b759eb..7c0f42ba6b 100644 --- a/blockchain/src/main/java/com/tangem/blockchain/blockchains/binance/BinanceWalletManager.kt +++ b/blockchain/src/main/java/com/tangem/blockchain/blockchains/binance/BinanceWalletManager.kt @@ -1,12 +1,12 @@ package com.tangem.blockchain.blockchains.binance import android.util.Log -import com.tangem.blockchain.blockchains.binance.network.BinanceInfoResponse import com.tangem.blockchain.blockchains.binance.network.BinanceNetworkManager import com.tangem.blockchain.common.* import com.tangem.blockchain.extensions.Result import com.tangem.blockchain.extensions.SimpleResult import com.tangem.common.CompletionResult +import com.tangem.blockchain.blockchains.binance.network.BinanceInfoResponse as BinanceInfoResponse1 class BinanceWalletManager( cardId: String, @@ -18,16 +18,17 @@ class BinanceWalletManager( private val blockchain = wallet.blockchain override suspend fun update() { - val result = networkManager.getInfo(wallet.address) + val result = networkManager.getInfo(wallet.address, wallet.amounts[AmountType.Token]?.address) when (result) { is Result.Success -> updateWallet(result.data) is Result.Failure -> updateError(result.error) } } - private fun updateWallet(response: BinanceInfoResponse) { + private fun updateWallet(response: BinanceInfoResponse1) { Log.d(this::class.java.simpleName, "Balance is ${response.balance}") wallet.amounts[AmountType.Coin]?.value = response.balance + wallet.amounts[AmountType.Token]?.value = response.assetBalance transactionBuilder.accountNumber = response.accountNumber transactionBuilder.sequence = response.sequence diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/binance/network/BinanceNetworkManager.kt b/blockchain/src/main/java/com/tangem/blockchain/blockchains/binance/network/BinanceNetworkManager.kt index 92532a3ceb..2ccdd82ca5 100644 --- a/blockchain/src/main/java/com/tangem/blockchain/blockchains/binance/network/BinanceNetworkManager.kt +++ b/blockchain/src/main/java/com/tangem/blockchain/blockchains/binance/network/BinanceNetworkManager.kt @@ -25,20 +25,22 @@ class BinanceNetworkManager(isTestNet: Boolean = false) { ) } - suspend fun getInfo(address: String): Result { + suspend fun getInfo(address: String, assetCode: String? = null): Result { return try { val accountData = retryIO { client.getAccount(address) } var coinBalance = BigDecimal.ZERO + var assetBalance = BigDecimal.ZERO for (balance in accountData.balances) { - if (balance.symbol == "BNB") { - coinBalance = balance.free.toBigDecimal() - break + when (balance.symbol) { + "BNB" -> coinBalance = balance.free.toBigDecimal() + assetCode -> assetBalance = balance.free.toBigDecimal() } } Result.Success(BinanceInfoResponse( balance = coinBalance, + assetBalance = assetBalance, accountNumber = accountData.accountNumber.toLong(), sequence = accountData.sequence )) @@ -46,6 +48,7 @@ class BinanceNetworkManager(isTestNet: Boolean = false) { if (exception.message == "account not found") { Result.Success(BinanceInfoResponse( balance = BigDecimal.ZERO, //TODO check account not found logic + assetBalance = null, accountNumber = null, sequence = null )) @@ -88,7 +91,8 @@ class BinanceNetworkManager(isTestNet: Boolean = false) { } data class BinanceInfoResponse( - val balance: BigDecimal?, + val balance: BigDecimal, + val assetBalance: BigDecimal?, val accountNumber: Long?, val sequence: Long? ) \ No newline at end of file From 878581ca8e677c0c4bfe8442869d8e0daac92e91 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 12 May 2020 10:04:22 +0300 Subject: [PATCH 3/6] Updated on 2026-08-14 --- .../src/main/java/com/tangem/TangemSdk.kt | 38 +++++++++++++++---- .../com/tangem/devkit/TestUserDataActivity.kt | 4 +- .../_main/entryPoint/ActionListFragment.kt | 3 +- .../domain/actions/WriteUserDataAction.kt | 5 +-- .../actions/WriteUserProtectedDataAction.kt | 29 ++++++++++++++ .../paramsManager/managers/SimpleManagers.kt | 15 ++++++-- .../com/tangem/devkit/ucase/resources/Ids.kt | 1 + .../resources/initializers/ActionResources.kt | 1 + .../ui/WriteProtectedUserDataFragment.kt | 10 +++++ .../src/main/res/navigation/navigation.xml | 9 +++++ .../src/main/res/values/strings_action.xml | 6 ++- 11 files changed, 100 insertions(+), 21 deletions(-) create mode 100644 tangem-devkit/src/main/java/com/tangem/devkit/ucase/domain/actions/WriteUserProtectedDataAction.kt create mode 100644 tangem-devkit/src/main/java/com/tangem/devkit/ucase/variants/userdata/ui/WriteProtectedUserDataFragment.kt diff --git a/tangem-core/src/main/java/com/tangem/TangemSdk.kt b/tangem-core/src/main/java/com/tangem/TangemSdk.kt index 8fc1fb4e2e..880796d9e7 100644 --- a/tangem-core/src/main/java/com/tangem/TangemSdk.kt +++ b/tangem-core/src/main/java/com/tangem/TangemSdk.kt @@ -183,29 +183,51 @@ class TangemSdk( } /** - * This method launches a [WriteUserDataCommand] on a new thread. + * This method launches a [WriteUserDataCommand] on a new thread, writing UserData and UserCounter fields. * - * This command writes some of UserData, UserProtectedData, UserCounter and UserProtectedCounter fields. - * User_Data and User_ProtectedData are never changed or parsed by the executable code the Tangem COS. - * The App defines purpose of use, format and it's payload. For example, this field may contain cashed information + * User_Data is never changed or parsed by the executable code the Tangem COS. + * The App defines purpose of use, format and its payload. For example, this field may contain cashed information * from blockchain to accelerate preparing new transaction. - * User_Counter and User_ProtectedCounter are counters, that initial values can be set by App and increased on every signing + * The initial value of User_Counter can be set by an App and increased on every signing * of new transaction (on SIGN command that calculate new signatures). The App defines purpose of use. * For example, this fields may contain blockchain nonce value. * * Writing of UserCounter and UserData is protected only by PIN1. - * UserProtectedCounter and UserProtectedData need additionally PIN2 to confirmation. */ fun writeUserData( cardId: String, userData: ByteArray? = null, - userProtectedData: ByteArray? = null, userCounter: Int? = null, + initialMessage: Message? = null, + callback: (result: CompletionResult) -> Unit + ) { + val command = WriteUserDataCommand(userData = userData,userCounter = userCounter) + startSessionWithRunnable(command, cardId, initialMessage, callback) + } + + /** + * This method launches a [WriteUserDataCommand] on a new thread, + * writing UserProtectedData and UserProtectedCounter fields. + * + * User_ProtectedData is never changed or parsed by the executable code the Tangem COS. + * The App defines purpose of use, format and its payload. For example, this field may contain cashed information + * from blockchain to accelerate preparing new transaction. + * The initial value of User_ProtectedCounter can be set by an App and increased on every signing + * of a new transaction (on SIGN command that calculate new signatures). The App defines the purpose of use. + * For example, this fields may contain blockchain nonce value. + * + * UserProtectedCounter and UserProtectedData require PIN2 for confirmation. + */ + fun writeProtectedUserData( + cardId: String, + userProtectedData: ByteArray? = null, userProtectedCounter: Int? = null, initialMessage: Message? = null, callback: (result: CompletionResult) -> Unit ) { - val command = WriteUserDataCommand(userData, userProtectedData, userCounter, userProtectedCounter) + val command = WriteUserDataCommand( + userProtectedData = userProtectedData, userProtectedCounter = userProtectedCounter + ) startSessionWithRunnable(command, cardId, initialMessage, callback) } diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/TestUserDataActivity.kt b/tangem-devkit/src/main/java/com/tangem/devkit/TestUserDataActivity.kt index 1fd9eeedb6..5628c01f29 100644 --- a/tangem-devkit/src/main/java/com/tangem/devkit/TestUserDataActivity.kt +++ b/tangem-devkit/src/main/java/com/tangem/devkit/TestUserDataActivity.kt @@ -50,9 +50,7 @@ class TestUserDataActivity : AppCompatActivity() { tangemSdk.writeUserData( writeOptions.cardId!!, writeOptions.userData, - writeOptions.userProtectedData, - writeOptions.userCounter, - writeOptions.userProtectedCounter + writeOptions.userCounter ) { when (it) { is CompletionResult.Failure -> handleError(tv_write_result, it.error) diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/_main/entryPoint/ActionListFragment.kt b/tangem-devkit/src/main/java/com/tangem/devkit/_main/entryPoint/ActionListFragment.kt index 5a1008d717..2656204d6b 100644 --- a/tangem-devkit/src/main/java/com/tangem/devkit/_main/entryPoint/ActionListFragment.kt +++ b/tangem-devkit/src/main/java/com/tangem/devkit/_main/entryPoint/ActionListFragment.kt @@ -71,7 +71,8 @@ class ActionListFragment : BaseFragment() { ActionType.ReadIssuerExData, ActionType.WriteIssuerExData, ActionType.ReadUserData, - ActionType.WriteUserData + ActionType.WriteUserData, + ActionType.WriteProtectedUserData ) } } \ No newline at end of file diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/domain/actions/WriteUserDataAction.kt b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/domain/actions/WriteUserDataAction.kt index d7d6da6107..7727546c05 100644 --- a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/domain/actions/WriteUserDataAction.kt +++ b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/domain/actions/WriteUserDataAction.kt @@ -11,12 +11,10 @@ class WriteUserDataAction : BaseAction() { override fun executeMainAction(payload: PayloadHolder, attrs: AttrForAction, callback: ActionCallback) { val userData = (attrs.itemList.findItem(TlvId.UserData)?.getData() as? String)?.toByteArray() ?: return - val protectedUserData = (attrs.itemList.findItem(TlvId.ProtectedUserData)?.getData() as? String)?.toByteArray() - ?: return val cardId = attrs.itemList.findItem(TlvId.CardId)?.viewModel?.data ?: return val counter = (attrs.itemList.findItem(TlvId.Counter)?.viewModel?.data as? Int) ?: 1 - attrs.tangemSdk.writeUserData(stringOf(cardId), userData, protectedUserData, counter, counter) { + attrs.tangemSdk.writeUserData(stringOf(cardId), userData, counter) { handleResult(payload, it, null, attrs, callback) } } @@ -24,7 +22,6 @@ class WriteUserDataAction : BaseAction() { override fun getActionByTag(payload: PayloadHolder, id: Id, attrs: AttrForAction): ((ActionCallback) -> Unit)? { return when (id) { TlvId.CardId -> { callback -> ScanAction().executeMainAction(payload, attrs, callback) } - TlvId.Counter -> { callback -> ReadUserDataAction().executeMainAction(payload, attrs, callback) } else -> null } } diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/domain/actions/WriteUserProtectedDataAction.kt b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/domain/actions/WriteUserProtectedDataAction.kt new file mode 100644 index 0000000000..e315107b8b --- /dev/null +++ b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/domain/actions/WriteUserProtectedDataAction.kt @@ -0,0 +1,29 @@ +package com.tangem.devkit.ucase.domain.actions + +import com.tangem.devkit._arch.structure.Id +import com.tangem.devkit._arch.structure.PayloadHolder +import com.tangem.devkit._arch.structure.abstraction.findItem +import com.tangem.devkit.ucase.domain.paramsManager.ActionCallback +import com.tangem.devkit.ucase.variants.TlvId +import ru.dev.gbixahue.eu4d.lib.kotlin.stringOf + + +class WriteUserProtectedDataAction : BaseAction() { + override fun executeMainAction(payload: PayloadHolder, attrs: AttrForAction, callback: ActionCallback) { + val protectedUserData = (attrs.itemList.findItem(TlvId.ProtectedUserData)?.getData() as? String)?.toByteArray() + ?: return + val cardId = attrs.itemList.findItem(TlvId.CardId)?.viewModel?.data ?: return + val counter = (attrs.itemList.findItem(TlvId.Counter)?.viewModel?.data as? Int) ?: 1 + + attrs.tangemSdk.writeProtectedUserData(stringOf(cardId), protectedUserData, counter) { + handleResult(payload, it, null, attrs, callback) + } + } + + override fun getActionByTag(payload: PayloadHolder, id: Id, attrs: AttrForAction): ((ActionCallback) -> Unit)? { + return when (id) { + TlvId.CardId -> { callback -> ScanAction().executeMainAction(payload, attrs, callback) } + else -> null + } + } +} \ No newline at end of file diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/domain/paramsManager/managers/SimpleManagers.kt b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/domain/paramsManager/managers/SimpleManagers.kt index a5085dccb2..bb6b16540e 100644 --- a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/domain/paramsManager/managers/SimpleManagers.kt +++ b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/domain/paramsManager/managers/SimpleManagers.kt @@ -96,9 +96,18 @@ class WriteUserDataItemsManager : BaseItemsManager(WriteUserDataAction()) { setItems(listOf( EditTextItem(TlvId.CardId, null), EditTextItem(TlvId.Counter, "1"), - EditTextItem(TlvId.UserData, "User data to be written on a card"), - EditTextItem(TlvId.ProtectedUserData, "Protected user data to be written on a card") - + EditTextItem(TlvId.UserData, "User data to be written on a card") )) } +} + + class WriteProtectedUserDataItemsManager : BaseItemsManager(WriteUserProtectedDataAction()) { + init { + setItemChangeConsequences(CardIdConsequence()) + setItems(listOf( + EditTextItem(TlvId.CardId, null), + EditTextItem(TlvId.Counter, "1"), + EditTextItem(TlvId.ProtectedUserData, "Protected user data to be written on a card") + )) + } } \ No newline at end of file diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/resources/Ids.kt b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/resources/Ids.kt index 1daedb6326..90e2d54588 100644 --- a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/resources/Ids.kt +++ b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/resources/Ids.kt @@ -16,6 +16,7 @@ enum class ActionType : Id { WriteIssuerExData, ReadUserData, WriteUserData, + WriteProtectedUserData, Personalize, Depersonalize, Unknown, diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/resources/initializers/ActionResources.kt b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/resources/initializers/ActionResources.kt index 2d7adcea1c..7ca4301b5f 100644 --- a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/resources/initializers/ActionResources.kt +++ b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/resources/initializers/ActionResources.kt @@ -24,6 +24,7 @@ class ActionResources { holder.register(ActionType.WriteIssuerExData, ActionRes(R.string.action_issuer_write_ex_data, R.string.info_action_issuer_write_ex_data, R.id.action_nav_entry_point_to_nav_issuer_write_ex_data)) holder.register(ActionType.ReadUserData, ActionRes(R.string.action_user_read_data, R.string.info_action_user_read_data, R.id.action_nav_entry_point_to_nav_user_read_data)) holder.register(ActionType.WriteUserData, ActionRes(R.string.action_user_write_data, R.string.info_action_user_write_data, R.id.action_nav_entry_point_to_nav_user_write_data)) + holder.register(ActionType.WriteProtectedUserData, ActionRes(R.string.action_user_write_protected_data, R.string.info_action_user_write_protected_data, R.id.action_nav_entry_point_to_nav_user_write_protected_data)) // holder.register(ActionType.Unknown, getIfNotContains()) } } \ No newline at end of file diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/variants/userdata/ui/WriteProtectedUserDataFragment.kt b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/variants/userdata/ui/WriteProtectedUserDataFragment.kt new file mode 100644 index 0000000000..4962b4537a --- /dev/null +++ b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/variants/userdata/ui/WriteProtectedUserDataFragment.kt @@ -0,0 +1,10 @@ +package com.tangem.devkit.ucase.variants.userdata.ui + +import com.tangem.devkit.ucase.domain.paramsManager.ItemsManager +import com.tangem.devkit.ucase.domain.paramsManager.managers.WriteProtectedUserDataItemsManager +import com.tangem.devkit.ucase.ui.BaseCardActionFragment + +class WriteProtectedUserDataFragment : BaseCardActionFragment() { + + override val itemsManager: ItemsManager by lazy { WriteProtectedUserDataItemsManager() } +} \ No newline at end of file diff --git a/tangem-devkit/src/main/res/navigation/navigation.xml b/tangem-devkit/src/main/res/navigation/navigation.xml index a08466aff6..f89849a75c 100644 --- a/tangem-devkit/src/main/res/navigation/navigation.xml +++ b/tangem-devkit/src/main/res/navigation/navigation.xml @@ -44,6 +44,9 @@ + @@ -119,6 +122,12 @@ android:label="@string/action_user_write_data" tools:layout="@layout/fg_base_action_layout" /> + + Write Issuer Extra Data Read User Data Write User Data + Write Protected User DataThis command returns all data about the card and the wallet, including unique card number (CID) that has to be submitted while calling all other commands Depending on Signing_Method parameter defined during personalization, this command signs data using Wallet_PrivateKey @@ -26,7 +27,8 @@ This command retrieves Issuer Extra Data field and its issuer’s signature. This command writes Issuer Extra Data field and its issuer’s signature to the card. This command returns User Data and User Protected Data (up to 512-byte each) and two counters: User Counter and User Protected Counter. - This command writes to the card any of User Data, User Protected Data, User Counter and User Protected Counter fields. - + This command writes to the card User Data and User Counter fields. + This command writes to the card User Protected Data and User Protected Counter fields. + \ No newline at end of file From 1c1e5230a5e662e1e3c36dd261203faa88da8880 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 12 May 2020 13:27:40 +0300 Subject: [PATCH 4/6] Updated on 2026-08-14 --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 07bb7d859f..af2ce223fa 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -99,7 +99,7 @@ dependencies { implementation 'com.google.dagger:dagger:2.24' kapt 'com.google.dagger:dagger-compiler:2.21' annotationProcessor 'com.google.dagger:dagger-compiler:2.21' - implementation 'com.google.zxing:core:3.4.0' + implementation 'com.google.zxing:core:3.3.3' // Do not update to 3.4.0, it requires minSdk 24 implementation 'com.google.code.gson:gson:2.8.5' implementation 'com.madgag.spongycastle:core:1.56.0.0' implementation 'com.madgag.spongycastle:prov:1.56.0.0' From 5616d43eecd2af69679d377654cd11edaf99a700 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 12 May 2020 14:58:41 +0300 Subject: [PATCH 5/6] Updated on 2026-08-14 --- .../src/main/java/com/tangem/CardSession.kt | 6 ++-- .../src/main/java/com/tangem/TangemSdk.kt | 4 +-- .../main/java/com/tangem/TangemSdkError.kt | 30 +++++++++---------- 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/tangem-core/src/main/java/com/tangem/CardSession.kt b/tangem-core/src/main/java/com/tangem/CardSession.kt index 34f243fc4f..1a2505240e 100644 --- a/tangem-core/src/main/java/com/tangem/CardSession.kt +++ b/tangem-core/src/main/java/com/tangem/CardSession.kt @@ -37,7 +37,7 @@ interface CardSessionRunnable { * @property viewDelegate is an interface that allows interaction with users and shows relevant UI. * @property cardId ID, Unique Tangem card ID number. If not null, the SDK will check that you the card * with which you tapped a phone has this [cardId] and SDK will return - * the [TangemSdkError.WrongCard] otherwise. + * the [TangemSdkError.WrongCardNumber] otherwise. * @property initialMessage A custom description that will be shown at the beginning of the NFC session. * If null, a default header and text body will be used. */ @@ -133,8 +133,8 @@ class CardSession( is CompletionResult.Success -> { val receivedCardId = result.data.cardId if (cardId != null && receivedCardId != cardId) { - stopWithError(TangemSdkError.WrongCard()) - callback(CompletionResult.Failure(TangemSdkError.WrongCard())) + stopWithError(TangemSdkError.WrongCardNumber()) + callback(CompletionResult.Failure(TangemSdkError.WrongCardNumber())) return@run } val allowedCardTypes = environment.cardFilter.allowedCardTypes diff --git a/tangem-core/src/main/java/com/tangem/TangemSdk.kt b/tangem-core/src/main/java/com/tangem/TangemSdk.kt index 880796d9e7..ce0c0e8a47 100644 --- a/tangem-core/src/main/java/com/tangem/TangemSdk.kt +++ b/tangem-core/src/main/java/com/tangem/TangemSdk.kt @@ -347,7 +347,7 @@ class TangemSdk( * @runnable: A custom task, adopting [CardSessionRunnable] protocol * @cardId: CID, Unique Tangem card ID number. If not null, the SDK will check that you the card * with which you tapped a phone has this [cardId] and SDK will return - * the [TangemSdkError.WrongCard] otherwise. + * the [TangemSdkError.WrongCardNumber] otherwise. * @initialMessage: A custom description that shows at the beginning of the NFC session. * If null, default message will be used. * @callback: Standard [TangemSdk] callback. @@ -365,7 +365,7 @@ class TangemSdk( * @cardId: CID, Unique Tangem card ID number. If not null, the SDK will check that you the card * with which you tapped a phone has this [cardId] and SDK will return - * the [TangemSdkError.WrongCard] otherwise. + * the [TangemSdkError.WrongCardNumber] otherwise. * @initialMessage: A custom description that shows at the beginning of the NFC session. * If null, default message will be used. * @callback: At first, you should check that the [TangemSdkError] is not null, diff --git a/tangem-core/src/main/java/com/tangem/TangemSdkError.kt b/tangem-core/src/main/java/com/tangem/TangemSdkError.kt index 4ea2612c51..bf0e5842a8 100644 --- a/tangem-core/src/main/java/com/tangem/TangemSdkError.kt +++ b/tangem-core/src/main/java/com/tangem/TangemSdkError.kt @@ -67,16 +67,6 @@ sealed class TangemSdkError(val code: Int) : Exception(code.toString()) { //Read Errors class Pin1Required : TangemSdkError(40401) - /** - * This error is returned when a [Task] expects a user to use a particular card, - * but the user tries to use a different card. - */ - class WrongCard : TangemSdkError(40403) - /** - * This error is returned when a user scans a card of a [com.tangem.common.extensions.CardType] - * that is not specified in [Config.cardFilter]. - */ - class WrongCardType : TangemSdkError(40404) //CreateWallet Errors class AlreadyCreated : TangemSdkError(40501) @@ -128,11 +118,6 @@ sealed class TangemSdkError(val code: Int) : Exception(code.toString()) { class OverwritingDataIsProhibited : TangemSdkError(40008) class DataCannotBeWritten : TangemSdkError(40009) class MissingIssuerPubicKey : TangemSdkError(40010) - /** - * This error is returned when a [ScanTask] returns a [Card] without some of the essential fields. - */ - class CardError : TangemSdkError(40011) - //SDK Errors class UnknownError: TangemSdkError(50001) @@ -150,7 +135,20 @@ sealed class TangemSdkError(val code: Int) : Exception(code.toString()) { * is executed before performing other commands. */ class MissingPreflightRead : TangemSdkError(50004) - + /** + * This error is returned when a [Task] expects a user to use a particular card, + * but the user tries to use a different card. + */ + class WrongCardNumber : TangemSdkError(50005) + /** + * This error is returned when a user scans a card of a [com.tangem.common.extensions.CardType] + * that is not specified in [Config.cardFilter]. + */ + class WrongCardType : TangemSdkError(50006) + /** + * This error is returned when a [ScanTask] returns a [Card] without some of the essential fields. + */ + class CardError : TangemSdkError(50007) } From 2ae8afb3a7495a2fcbb83add4dd68758a0da3aeb Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 12 May 2020 16:09:58 +0300 Subject: [PATCH 6/6] Updated on 2026-08-14 --- .../blockchain/blockchains/binance/BinanceWalletManager.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/binance/BinanceWalletManager.kt b/blockchain/src/main/java/com/tangem/blockchain/blockchains/binance/BinanceWalletManager.kt index 7c0f42ba6b..4bb91c341f 100644 --- a/blockchain/src/main/java/com/tangem/blockchain/blockchains/binance/BinanceWalletManager.kt +++ b/blockchain/src/main/java/com/tangem/blockchain/blockchains/binance/BinanceWalletManager.kt @@ -6,7 +6,7 @@ import com.tangem.blockchain.common.* import com.tangem.blockchain.extensions.Result import com.tangem.blockchain.extensions.SimpleResult import com.tangem.common.CompletionResult -import com.tangem.blockchain.blockchains.binance.network.BinanceInfoResponse as BinanceInfoResponse1 +import com.tangem.blockchain.blockchains.binance.network.BinanceInfoResponse class BinanceWalletManager( cardId: String, @@ -25,7 +25,7 @@ class BinanceWalletManager( } } - private fun updateWallet(response: BinanceInfoResponse1) { + private fun updateWallet(response: BinanceInfoResponse) { Log.d(this::class.java.simpleName, "Balance is ${response.balance}") wallet.amounts[AmountType.Coin]?.value = response.balance wallet.amounts[AmountType.Token]?.value = response.assetBalance