From c736d3455771a070367c306e5b403d6d0feb871d Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 8 May 2020 14:46:37 +0300 Subject: [PATCH 01/28] 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 02/28] 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 03/28] 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 04/28] 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 05/28] 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 8c24ae20107210413ecd6b0703fb670960aeafa2 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 12 May 2020 15:30:17 +0300 Subject: [PATCH 06/28] Updated on 2026-08-14 --- tangem-core/src/main/java/com/tangem/CardSession.kt | 7 ++++++- .../main/java/com/tangem/common/tlv/TlvDecoder.kt | 12 ++++++++---- .../tangem_sdk_new/DefaultSessionViewDelegate.kt | 1 - .../java/com/tangem/tangem_sdk_new/nfc/NfcReader.kt | 7 ++++--- 4 files changed, 18 insertions(+), 9 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..39ee1cc750 100644 --- a/tangem-core/src/main/java/com/tangem/CardSession.kt +++ b/tangem-core/src/main/java/com/tangem/CardSession.kt @@ -166,6 +166,8 @@ class CardSession( * @param error An error that will be shown. */ private fun stopWithError(error: Exception) { + if (!isBusy) return + reader.closeSession() isBusy = false @@ -175,9 +177,12 @@ class CardSession( error.localizedMessage } if (error !is TangemSdkError.UserCancelled) { - Log.e("tag", "Finishing with error: $errorMessage") + Log.e(tag, "Finishing with error: $errorMessage") viewDelegate.onError(errorMessage) + } else { + Log.i(tag, "User cancelled NFC session") } + } fun send(apdu: CommandApdu, callback: (result: CompletionResult) -> Unit) { diff --git a/tangem-core/src/main/java/com/tangem/common/tlv/TlvDecoder.kt b/tangem-core/src/main/java/com/tangem/common/tlv/TlvDecoder.kt index 62c0899f2d..ac83d38b06 100644 --- a/tangem-core/src/main/java/com/tangem/common/tlv/TlvDecoder.kt +++ b/tangem-core/src/main/java/com/tangem/common/tlv/TlvDecoder.kt @@ -33,7 +33,7 @@ class TlvDecoder(val tlvList: List) { */ inline fun decodeOptional(tag: TlvTag): T? = try { - decode(tag) + decode(tag, false) } catch (exception: TangemSdkError.DecodingFailedMissingTag) { null } @@ -47,14 +47,18 @@ class TlvDecoder(val tlvList: List) { * * @return [Tlv] value converted to a nullable type [T]. * - * @throws [TaskError.MissingTag] exception if no [Tlv] is found by the Tag. + * @throws [TangemSdkError.DecodingFailedMissingTag] exception if no [Tlv] is found by the Tag. */ - inline fun decode(tag: TlvTag): T { + inline fun decode(tag: TlvTag, logError: Boolean = true): T { val tlvValue: ByteArray = tlvList.find { it.tag == tag }?.value ?: if (tag.valueType() == TlvValueType.BoolValue && T::class == Boolean::class) { return false as T } else { - Log.e(this::class.simpleName!!, "Tag $tag not found") + if (logError) { + Log.e(this::class.simpleName!!, "TLV $tag not found") + } else { + Log.v(this::class.simpleName!!, "TLV $tag not found") + } throw TangemSdkError.DecodingFailedMissingTag() } diff --git a/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/DefaultSessionViewDelegate.kt b/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/DefaultSessionViewDelegate.kt index 4b422c3687..a15f16521e 100644 --- a/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/DefaultSessionViewDelegate.kt +++ b/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/DefaultSessionViewDelegate.kt @@ -61,7 +61,6 @@ class DefaultSessionViewDelegate(private val reader: NfcReader) : SessionViewDel readingDialog?.setOnCancelListener { reader.readingCancelled = true reader.closeSession() - Log.i(this::class.simpleName!!, "readingCancelled is set to true") } readingDialog?.show() } diff --git a/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/nfc/NfcReader.kt b/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/nfc/NfcReader.kt index 225edfb595..9b42d5b108 100644 --- a/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/nfc/NfcReader.kt +++ b/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/nfc/NfcReader.kt @@ -26,7 +26,7 @@ class NfcReader : CardReader { if (field == null) { field = value // if tag is received, call connect first before transceiving data - connect() + if (value != null) connect() } if (value == null) field = value } @@ -46,6 +46,7 @@ class NfcReader : CardReader { private var callback: ((response: CompletionResult) -> Unit)? = null override fun openSession() { + Log.i(this::class.simpleName!!, "NFC reader is starting NFC session") readingActive = true readingCancelled = false manager?.disableReaderMode() @@ -85,7 +86,7 @@ class NfcReader : CardReader { return } if (rawResponse != null) { - Log.i(this::class.simpleName!!, "Nfc response is received") + Log.i(this::class.simpleName!!, "NFC response is received") data = null } rawResponse?.let { callback?.invoke(CompletionResult.Success(ResponseApdu(it))) } @@ -103,7 +104,7 @@ class NfcReader : CardReader { isoDep?.close() isoDep?.connect() isoDep?.timeout = 240000 - Log.i(this::class.simpleName!!, "Nfc session is started") + Log.i(this::class.simpleName!!, "NFC tag is connected") } private fun onNfcVDiscovered(nfcV: NfcV) { From 2ae8afb3a7495a2fcbb83add4dd68758a0da3aeb Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 12 May 2020 16:09:58 +0300 Subject: [PATCH 07/28] 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 From 432a46e98476a1e02b0c78407847f807d79432ab Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 12 May 2020 17:40:20 +0300 Subject: [PATCH 08/28] Updated on 2026-08-14 --- tangem-core/src/main/java/com/tangem/commands/Command.kt | 2 +- tangem-core/src/main/java/com/tangem/common/tlv/TlvBuilder.kt | 2 +- tangem-core/src/main/java/com/tangem/common/tlv/TlvDecoder.kt | 4 ++-- .../src/main/java/com/tangem/tangem_sdk_new/nfc/NfcReader.kt | 3 ++- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/tangem-core/src/main/java/com/tangem/commands/Command.kt b/tangem-core/src/main/java/com/tangem/commands/Command.kt index fad1b0d025..e7e90c5123 100644 --- a/tangem-core/src/main/java/com/tangem/commands/Command.kt +++ b/tangem-core/src/main/java/com/tangem/commands/Command.kt @@ -38,7 +38,7 @@ abstract class Command : CardSessionRunnable { abstract fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): T override fun run(session: CardSession, callback: (result: CompletionResult) -> Unit) { - Log.i("Command", "Sending ${this::class.java.simpleName}") + Log.i("Command", "Initializing ${this::class.java.simpleName}") if (session.environment.handleErrors) { if (performPreCheck(session, callback)) return } diff --git a/tangem-core/src/main/java/com/tangem/common/tlv/TlvBuilder.kt b/tangem-core/src/main/java/com/tangem/common/tlv/TlvBuilder.kt index 3cade3e92a..8c7ec12fad 100644 --- a/tangem-core/src/main/java/com/tangem/common/tlv/TlvBuilder.kt +++ b/tangem-core/src/main/java/com/tangem/common/tlv/TlvBuilder.kt @@ -14,7 +14,7 @@ class TlvBuilder { fun serialize(): ByteArray { Log.v("TLV", - "List of encoded TLVs:\n${tlvs.joinToString("\n")}") + "Data encoded to TLVs:\n${tlvs.joinToString("\n")}") return tlvs.serialize() } diff --git a/tangem-core/src/main/java/com/tangem/common/tlv/TlvDecoder.kt b/tangem-core/src/main/java/com/tangem/common/tlv/TlvDecoder.kt index ac83d38b06..866fbbd41c 100644 --- a/tangem-core/src/main/java/com/tangem/common/tlv/TlvDecoder.kt +++ b/tangem-core/src/main/java/com/tangem/common/tlv/TlvDecoder.kt @@ -20,7 +20,7 @@ class TlvDecoder(val tlvList: List) { init { Log.v("TLV", - "List of decoded TLVs:\n${tlvList.joinToString("\n")}") + "Decoding data from TLV:\n${tlvList.joinToString("\n")}") } /** @@ -57,7 +57,7 @@ class TlvDecoder(val tlvList: List) { if (logError) { Log.e(this::class.simpleName!!, "TLV $tag not found") } else { - Log.v(this::class.simpleName!!, "TLV $tag not found") + Log.v(this::class.simpleName!!, "TLV $tag not found, but it is not required") } throw TangemSdkError.DecodingFailedMissingTag() } diff --git a/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/nfc/NfcReader.kt b/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/nfc/NfcReader.kt index 9b42d5b108..8640e30abc 100644 --- a/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/nfc/NfcReader.kt +++ b/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/nfc/NfcReader.kt @@ -75,6 +75,7 @@ class NfcReader : CardReader { val rawResponse: ByteArray? try { + Log.i(this::class.simpleName!!, "Sending data to the card") rawResponse = isoDep?.transceive(data) } catch (exception: TagLostException) { callback?.invoke(CompletionResult.Failure(TangemSdkError.TagLost())) @@ -86,7 +87,7 @@ class NfcReader : CardReader { return } if (rawResponse != null) { - Log.i(this::class.simpleName!!, "NFC response is received") + Log.i(this::class.simpleName!!, "Data from the card was received") data = null } rawResponse?.let { callback?.invoke(CompletionResult.Success(ResponseApdu(it))) } From a38813b2bed09a9f91469ac31ef905cbada7fbd3 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 13 May 2020 11:47:56 +0300 Subject: [PATCH 09/28] Updated on 2026-08-14 --- .../ucase/variants/personalize/converter/DefaultValues.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/variants/personalize/converter/DefaultValues.kt b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/variants/personalize/converter/DefaultValues.kt index 7135d43975..4af4f57691 100644 --- a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/variants/personalize/converter/DefaultValues.kt +++ b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/variants/personalize/converter/DefaultValues.kt @@ -106,8 +106,8 @@ internal class Helper { KeyValue("RSK", "RSK"), KeyValue("XPR", "XPR"), KeyValue("CARDANO", "CARDANO"), - KeyValue("BNB", "BNB"), - KeyValue("XTZ", "XTZ"), + KeyValue("BNB", "BINANCE"), + KeyValue("XTZ", "TEZOS"), KeyValue("DUC", "DUC") ) } From 64f39a728d5f7f23723d01b9c8b5d870f4e63916 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 13 May 2020 13:23:04 +0300 Subject: [PATCH 10/28] Updated on 2026-08-14 --- .../main/java/com/tangem/wallet/binance/BinanceAssetEngine.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/tangem/wallet/binance/BinanceAssetEngine.java b/app/src/main/java/com/tangem/wallet/binance/BinanceAssetEngine.java index d3dc0dc13e..f5d4b8aeb7 100644 --- a/app/src/main/java/com/tangem/wallet/binance/BinanceAssetEngine.java +++ b/app/src/main/java/com/tangem/wallet/binance/BinanceAssetEngine.java @@ -89,7 +89,7 @@ public class BinanceAssetEngine extends CoinEngine { @Override public String getBalanceHTML() { - Amount balance = getBalance(); + Amount balance = coinData.getBalance(); Amount assetBalance = coinData.getAssetBalance(); if (balance != null) { if (assetBalance != null) { From 563322e9b10bdf325af901788e352c766c44fad6 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 13 May 2020 13:32:26 +0300 Subject: [PATCH 11/28] Updated on 2026-08-14 --- app/src/main/java/com/tangem/wallet/binance/BinanceEngine.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/tangem/wallet/binance/BinanceEngine.java b/app/src/main/java/com/tangem/wallet/binance/BinanceEngine.java index 48ae73ef42..ca6286a35d 100644 --- a/app/src/main/java/com/tangem/wallet/binance/BinanceEngine.java +++ b/app/src/main/java/com/tangem/wallet/binance/BinanceEngine.java @@ -120,7 +120,7 @@ public class BinanceEngine extends CoinEngine { @Override public boolean hasBalanceInfo() { if (coinData == null) return false; - return coinData.hasBalanceInfo(); + return coinData.hasBalanceInfo() || coinData.isError404(); } public boolean isExtractPossible() { From ba9506e48d77cd2871f90134a95b0026f1565568 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 13 May 2020 13:33:29 +0300 Subject: [PATCH 12/28] Updated on 2026-08-14 --- .../devkit/extensions/AndroidComponents.kt | 11 ++--- .../managers/PersonalizationItemsManager.kt | 24 ---------- .../PersonalizationConfigConverter.kt | 10 ++-- .../personalize/ui/PersonalizationFragment.kt | 48 ++++++++++++++++--- .../presets/PersonalizationPresetManager.kt | 32 +++++++++++-- .../src/main/res/drawable/ic_import.xml | 12 +++++ .../main/res/drawable/ic_share_white_18dp.xml | 4 +- .../dlg_personalization_preset_load.xml | 4 +- .../dlg_personalization_preset_save.xml | 1 - .../main/res/menu/menu_fg_peronalization.xml | 16 ++++++- .../src/main/res/menu/menu_fg_response.xml | 2 +- tangem-devkit/src/main/res/values/strings.xml | 2 + .../res/values/strings_personalization.xml | 7 +++ .../src/main/res/values/strings_response.xml | 2 - 14 files changed, 122 insertions(+), 53 deletions(-) create mode 100644 tangem-devkit/src/main/res/drawable/ic_import.xml diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/extensions/AndroidComponents.kt b/tangem-devkit/src/main/java/com/tangem/devkit/extensions/AndroidComponents.kt index c24ff4494c..d7ae706d37 100644 --- a/tangem-devkit/src/main/java/com/tangem/devkit/extensions/AndroidComponents.kt +++ b/tangem-devkit/src/main/java/com/tangem/devkit/extensions/AndroidComponents.kt @@ -4,7 +4,6 @@ import android.content.ClipData import android.content.ClipboardManager import android.content.Context import android.content.Intent -import androidx.activity.ComponentActivity import androidx.fragment.app.Fragment /** @@ -17,11 +16,7 @@ fun Context.copyToClipboard(value: Any, label: String = "") { clipboard.setPrimaryClip(clip) } -fun Fragment.shareText(text: String) { - requireActivity().shareText(text) -} - -fun ComponentActivity.shareText(text: String) { +fun Context.shareText(text: String) { val sendIntent: Intent = Intent().apply { action = Intent.ACTION_SEND putExtra(Intent.EXTRA_TEXT, text) @@ -29,4 +24,8 @@ fun ComponentActivity.shareText(text: String) { } val shareIntent = Intent.createChooser(sendIntent, null) startActivity(shareIntent) +} + +fun Fragment.shareText(text: String) { + requireContext().shareText(text) } \ No newline at end of file diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/domain/paramsManager/managers/PersonalizationItemsManager.kt b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/domain/paramsManager/managers/PersonalizationItemsManager.kt index 90a1ceab7b..a8125f2a51 100644 --- a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/domain/paramsManager/managers/PersonalizationItemsManager.kt +++ b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/domain/paramsManager/managers/PersonalizationItemsManager.kt @@ -7,10 +7,7 @@ import com.tangem.devkit.commons.Store import com.tangem.devkit.ucase.domain.actions.PersonalizeAction import com.tangem.devkit.ucase.domain.paramsManager.ActionCallback import com.tangem.devkit.ucase.variants.personalize.converter.PersonalizationConfigConverter -import com.tangem.devkit.ucase.variants.personalize.converter.PersonalizationJsonConverter import com.tangem.devkit.ucase.variants.personalize.dto.PersonalizationConfig -import com.tangem.devkit.ucase.variants.personalize.dto.PersonalizationJson -import ru.dev.gbixahue.eu4d.lib.android.global.log.Log /** [REDACTED_AUTHOR] @@ -30,27 +27,6 @@ class PersonalizationItemsManager( action.executeMainAction(this, getAttrsForAction(tangemSdk), callback) } - fun importJsonConfig(jsonString: String) { - if (jsonString.isEmpty()) return - - val jsonDto = try { - PersonalizationJson.getJsonConverter().fromJson(jsonString, PersonalizationJson::class.java) - } catch (ex: Exception) { - Log.e(this, "Can't convert imported string to Json object. Error: $ex") - return - } - - val config = PersonalizationJsonConverter().aToB(jsonDto) - updateByItemList(converter.convert(config)) - } - - fun exportJsonConfig(): String { - val config = converter.convert(itemList, PersonalizationConfig.default()) - val jsonDto = PersonalizationJsonConverter().bToA(config) - val jsonString = PersonalizationJson.getJsonConverter().toJson(jsonDto) - return jsonString - } - @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) fun onDestroy() { val config = converter.convert(itemList, PersonalizationConfig.default()) diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/variants/personalize/converter/PersonalizationConfigConverter.kt b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/variants/personalize/converter/PersonalizationConfigConverter.kt index e6733ed9f4..ce10098ef1 100644 --- a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/variants/personalize/converter/PersonalizationConfigConverter.kt +++ b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/variants/personalize/converter/PersonalizationConfigConverter.kt @@ -71,9 +71,9 @@ class ItemsToPersonalizationConfig : ItemsToModel { export.requireTerminalTxSignature = getTyped(SignHashExPropId.RequireTerminalTxSig) export.checkPIN3onCard = getTyped(SignHashExPropId.CheckPin3) export.itsToken = getTyped(TokenId.ItsToken) - export.cardData.token_symbol = getTyped(TokenId.Symbol) - export.cardData.token_contract_address = getTyped(TokenId.ContractAddress) - export.cardData.token_decimal = getTyped(TokenId.Decimal) + export.cardData.token_symbol = getTypedUnsafe(TokenId.Symbol) + export.cardData.token_contract_address = getTypedUnsafe(TokenId.ContractAddress) + export.cardData.token_decimal = getTypedUnsafe(TokenId.Decimal) export.cardData = export.cardData.apply { this.product_note = getTyped(ProductMaskId.Note) } export.cardData = export.cardData.apply { this.product_tag = getTyped(ProductMaskId.Tag) } export.cardData = export.cardData.apply { this.product_id_card = getTyped(ProductMaskId.IdCard) } @@ -114,6 +114,10 @@ class ItemsToPersonalizationConfig : ItemsToModel { return getTypedBy(valuesHolder, id)!! } + private inline fun getTypedUnsafe(id: Id): Type? { + return getTypedBy(valuesHolder, id) + } + private inline fun getTypedBy(holder: ConfigValuesHolder, id: Id): Type? { Log.d(this, "getTyped for id: $id") var typedValue = holder.get(id)?.get() diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/variants/personalize/ui/PersonalizationFragment.kt b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/variants/personalize/ui/PersonalizationFragment.kt index 76d0116ae3..bb5b708b86 100644 --- a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/variants/personalize/ui/PersonalizationFragment.kt +++ b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/variants/personalize/ui/PersonalizationFragment.kt @@ -14,6 +14,7 @@ import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import androidx.transition.Fade +import com.google.android.material.textfield.TextInputLayout import com.tangem.commands.Card import com.tangem.devkit.R import com.tangem.devkit._arch.structure.Id @@ -25,6 +26,7 @@ import com.tangem.devkit.commons.DialogController import com.tangem.devkit.commons.view.MultiActionView import com.tangem.devkit.commons.view.ViewAction import com.tangem.devkit.extensions.copyToClipboard +import com.tangem.devkit.extensions.shareText import com.tangem.devkit.extensions.view.beginDelayedTransition import com.tangem.devkit.ucase.domain.paramsManager.ItemsManager import com.tangem.devkit.ucase.domain.paramsManager.PayloadKey @@ -132,6 +134,7 @@ class PersonalizationFragment : BaseCardActionFragment(), PersonalizationPresetV fun initImportExportJson(parent: ViewGroup) { val tvJsonExport = parent.findViewById(R.id.et_json_export) val btnExportJson = parent.findViewById