() {
+ @Override
+ public void onSuccess(PayIdResponse payIdResponse) {
+ try {
+ String resolvedAddress = null;
+ for (PayIdAddress address : payIdResponse.getAddresses()) {
+ if (address.getPaymentNetwork().equals("RSK") &&
+ address.getEnvironment().equals("MAINNET")) {
+ resolvedAddress = address.getAddressDetails().getAddress();
+ break;
+ }
+ }
+ if (validateAddress(resolvedAddress)) {
+ if (resolvedAddress.equals(coinData.getWallet())) {
+ ctx.setError("Resolved PayID address equals source address");
+ blockchainRequestsCallbacks.onComplete(false);
+ } else {
+ coinData.setResolvedPayIdAddress(resolvedAddress);
+ if (serverApiRootstock.isRequestsSequenceCompleted() && serverApiPayId.isRequestsSequenceCompleted()) {
+ blockchainRequestsCallbacks.onComplete(!ctx.hasError());
+ } else {
+ blockchainRequestsCallbacks.onProgress();
+ }
+ }
+ } else {
+ ctx.setError("Unknown address format in PayID response");
+ blockchainRequestsCallbacks.onComplete(false);
+ }
+ } catch (Exception e) {
+ ctx.setError("Unknown response format on PayID request");
+ blockchainRequestsCallbacks.onComplete(false);
+ }
+ if (serverApiRootstock.isRequestsSequenceCompleted() && serverApiPayId.isRequestsSequenceCompleted()) {
+ blockchainRequestsCallbacks.onComplete(!ctx.hasError());
+ } else {
+ blockchainRequestsCallbacks.onProgress();
+ }
+ }
+
+ @Override
+ public void onError(Throwable e) {
+ Log.i(TAG, "onFail: " + "payID" + " " + e.getMessage());
+ ctx.setError("PayID error:" + e.getMessage());
+ blockchainRequestsCallbacks.onComplete(false);
+ }
+ };
+
+ serverApiPayId.getAddress(targetAddress, ctx.getBlockchain(), observer);
+ }
serverApiRootstock.requestData(ServerApiRootstock.ROOTSTOCK_ETH_GAS_PRICE, 67, coinData.getWallet(), "", "");
}
diff --git a/app/src/main/java/com/tangem/wallet/token/TokenEngine.java b/app/src/main/java/com/tangem/wallet/token/TokenEngine.java
index 4fabf745ed..cae64f6f2b 100644
--- a/app/src/main/java/com/tangem/wallet/token/TokenEngine.java
+++ b/app/src/main/java/com/tangem/wallet/token/TokenEngine.java
@@ -209,7 +209,7 @@ public class TokenEngine extends CoinEngine {
if (coinData == null) return false;
if (coinData.getBalanceInInternalUnits() == null && coinData.getBalanceAlterInInternalUnits() == null)
return false;
- return (coinData.getBalanceInInternalUnits() != null && coinData.getBalanceInInternalUnits().notZero() ) ||
+ return (coinData.getBalanceInInternalUnits() != null && coinData.getBalanceInInternalUnits().notZero()) ||
(coinData.getBalanceAlterInInternalUnits() != null && coinData.getBalanceAlterInInternalUnits().notZero());
}
@@ -576,7 +576,10 @@ public class TokenEngine extends CoinEngine {
int gasLimitInt = 60000;
- if (amountValue.getCurrency().equals("DGX") || amountValue.getCurrency().equals("CGT")) {
+ if (amountValue.getCurrency().equals("DGX") ||
+ amountValue.getCurrency().equals("CGT") ||
+ amountValue.getCurrency().equals("AWG")
+ ) {
gasLimitInt = 300000;
}
@@ -740,7 +743,7 @@ public class TokenEngine extends CoinEngine {
public void onFail(String method, String message) {
Log.e(TAG, "onFail: " + method + " " + message);
ctx.setError(message);
- if (serverApiInfura.isRequestsSequenceCompleted()&& serverApiBlockcypher.isRequestsSequenceCompleted()) {
+ if (serverApiInfura.isRequestsSequenceCompleted() && serverApiBlockcypher.isRequestsSequenceCompleted()) {
blockchainRequestsCallbacks.onComplete(false);
} else {
blockchainRequestsCallbacks.onProgress();
@@ -775,7 +778,7 @@ public class TokenEngine extends CoinEngine {
Log.e(TAG, "FAIL BLOCKCYPHER_ADDRESS Exception");
}
- if (serverApiInfura.isRequestsSequenceCompleted()&& serverApiBlockcypher.isRequestsSequenceCompleted()) {
+ if (serverApiInfura.isRequestsSequenceCompleted() && serverApiBlockcypher.isRequestsSequenceCompleted()) {
blockchainRequestsCallbacks.onComplete(!ctx.hasError());
} else {
blockchainRequestsCallbacks.onProgress();
@@ -874,7 +877,7 @@ public class TokenEngine extends CoinEngine {
}
if (validateAddress(resolvedAddress)) {
if (resolvedAddress.equals(coinData.getWallet())) {
- ctx.setError(R.string.prepare_transaction_error_same_address);
+ ctx.setError("Resolved PayID address equals source address");
blockchainRequestsCallbacks.onComplete(false);
} else {
coinData.setResolvedPayIdAddress(resolvedAddress);
@@ -923,7 +926,7 @@ public class TokenEngine extends CoinEngine {
@Override
public void onSuccess(String method, InfuraResponse infuraResponse) {
if (method.equals(ServerApiInfura.INFURA_ETH_SEND_RAW_TRANSACTION)) {
- if (infuraResponse.getResult()==null || infuraResponse.getResult().isEmpty()) {
+ if (infuraResponse.getResult() == null || infuraResponse.getResult().isEmpty()) {
ctx.setError("Rejected by node: " + infuraResponse.getError());
blockchainRequestsCallbacks.onComplete(false);
} else {
@@ -961,5 +964,7 @@ public class TokenEngine extends CoinEngine {
return getBalance().getCurrency().equals(Blockchain.Ethereum.getCurrency());
}
- public int pendingTransactionTimeoutInSeconds() { return 10; }
+ public int pendingTransactionTimeoutInSeconds() {
+ return 10;
+ }
}
diff --git a/app/src/main/java/com/tangem/wallet/xlm/XlmAssetEngine.java b/app/src/main/java/com/tangem/wallet/xlm/XlmAssetEngine.java
index 06cfd560ef..0de8d22584 100644
--- a/app/src/main/java/com/tangem/wallet/xlm/XlmAssetEngine.java
+++ b/app/src/main/java/com/tangem/wallet/xlm/XlmAssetEngine.java
@@ -5,8 +5,11 @@ import android.text.InputFilter;
import android.util.Log;
import com.tangem.App;
+import com.tangem.data.network.ServerApiPayId;
import com.tangem.data.network.ServerApiStellar;
import com.tangem.data.network.StellarRequest;
+import com.tangem.data.network.model.PayIdAddress;
+import com.tangem.data.network.model.PayIdResponse;
import com.tangem.tangem_card.data.TangemCard;
import com.tangem.tangem_card.tasks.SignTask;
import com.tangem.tangem_card.util.Util;
@@ -31,6 +34,11 @@ import org.stellar.sdk.responses.operations.OperationResponse;
import java.io.IOException;
import java.math.BigDecimal;
+import io.reactivex.CompletableObserver;
+import io.reactivex.SingleObserver;
+import io.reactivex.observers.DisposableCompletableObserver;
+import io.reactivex.observers.DisposableSingleObserver;
+
/**
* Created by dvol on 7.01.2019.
*
@@ -116,7 +124,7 @@ public class XlmAssetEngine extends CoinEngine {
@Override
public boolean hasBalanceInfo() {
if (coinData == null) return false;
- return (coinData.getXlmBalance() != null && coinData.getAssetBalance() != null) || (coinData.isError404());
+ return coinData.getXlmBalance() != null || coinData.isError404();
}
@@ -143,6 +151,10 @@ public class XlmAssetEngine extends CoinEngine {
@Override
public boolean validateAddress(String address) {
+ if (address != null && address.contains("$")) { // PayID
+ return validatePayId(address);
+ }
+
try {
KeyPair kp = KeyPair.fromAccountId(address);
// TODO is it possible to check address testNet or not
@@ -379,6 +391,14 @@ public class XlmAssetEngine extends CoinEngine {
public SignTask.TransactionToSign constructTransaction(Amount amountValue, Amount feeValue, boolean IncFee, String targetAddress) throws Exception {
checkBlockchainDataExists();
+ String destination;
+ //PayID
+ if (coinData.getResolvedPayIdAddress() != null) {
+ destination = coinData.getResolvedPayIdAddress();
+ } else {
+ destination = targetAddress;
+ }
+
if (coinData.isAssetBalanceZero() && IncFee) {
amountValue = new Amount(amountValue.subtract(feeValue), amountValue.getCurrency());
}
@@ -388,12 +408,12 @@ public class XlmAssetEngine extends CoinEngine {
operation = new ChangeTrustOperation.Builder(Asset.createNonNativeAsset(ctx.getCard().getTokenSymbol(), KeyPair.fromAccountId(ctx.getCard().getContractAddress())), "900000000000.0000000").build();
} else {
if (!coinData.isAssetBalanceZero()) {
- operation = new PaymentOperation.Builder(KeyPair.fromAccountId(targetAddress), Asset.createNonNativeAsset(ctx.getCard().getTokenSymbol(), KeyPair.fromAccountId(ctx.getCard().getContractAddress())), amountValue.toValueString()).build();
+ operation = new PaymentOperation.Builder(KeyPair.fromAccountId(destination), Asset.createNonNativeAsset(ctx.getCard().getTokenSymbol(), KeyPair.fromAccountId(ctx.getCard().getContractAddress())), amountValue.toValueString()).build();
} else {
if (coinData.isTargetAccountCreated())
- operation = new PaymentOperation.Builder(KeyPair.fromAccountId(targetAddress), new AssetTypeNative(), amountValue.toValueString()).build();
+ operation = new PaymentOperation.Builder(KeyPair.fromAccountId(destination), new AssetTypeNative(), amountValue.toValueString()).build();
else
- operation = new CreateAccountOperation.Builder(KeyPair.fromAccountId(targetAddress), amountValue.toValueString()).build();
+ operation = new CreateAccountOperation.Builder(KeyPair.fromAccountId(destination), amountValue.toValueString()).build();
}
}
TransactionEx transaction = TransactionEx.buildEx(120, coinData.getAccountResponse(), operation);
@@ -564,9 +584,66 @@ public class XlmAssetEngine extends CoinEngine {
@Override
public void requestFee(BlockchainRequestsCallbacks blockchainRequestsCallbacks, String targetAddress, Amount amount) throws Exception {
- // TODO: get fee stats?
coinData.minFee = coinData.normalFee = coinData.maxFee = coinData.getBaseFee();
- checkTargetAccountCreated(blockchainRequestsCallbacks, targetAddress, amount);
+
+ CompletableObserver payIdObserver = new DisposableCompletableObserver() {
+ @Override
+ public void onComplete() {
+ checkTargetAccountCreated(blockchainRequestsCallbacks, coinData.getResolvedPayIdAddress(), amount);
+ }
+
+ @Override
+ public void onError(Throwable e) {
+ ctx.setError(e.getMessage());
+ blockchainRequestsCallbacks.onComplete(false);
+ }
+ };
+
+ if (targetAddress.contains("$")) { // PayID
+ resolvePayID(targetAddress, payIdObserver);
+ } else {
+ checkTargetAccountCreated(blockchainRequestsCallbacks, targetAddress, amount);
+ }
+ }
+
+ private void resolvePayID(String targetAddress, CompletableObserver observer) {
+ final ServerApiPayId serverApiPayId = new ServerApiPayId();
+
+ SingleObserver payIdObserver = new DisposableSingleObserver() {
+ @Override
+ public void onSuccess(PayIdResponse payIdResponse) {
+ try {
+ String resolvedAddress = null;
+ for (PayIdAddress address : payIdResponse.getAddresses()) {
+ if (address.getPaymentNetwork().equals(ctx.getBlockchain().getCurrency()) &&
+ address.getEnvironment().equals("MAINNET")) {
+ resolvedAddress = address.getAddressDetails().getAddress();
+ break;
+ }
+ }
+ if (validateAddress(resolvedAddress)) {
+ if (!resolvedAddress.equals(coinData.getWallet())) {
+ coinData.setResolvedPayIdAddress(resolvedAddress);
+ observer.onComplete();
+ } else {
+ observer.onError(new Exception("Resolved PayID address equals source address"));
+ }
+ } else {
+ observer.onError(new Exception("Unknown address format in PayID response"));
+ }
+ } catch (Exception e) {
+ observer.onError(new Exception("Unknown response format on PayID request"));
+ }
+ }
+
+ @Override
+ public void onError(Throwable e) {
+ Log.i(TAG, "onFail: " + "payID" + " " + e.getMessage());
+ observer.onError(new Exception("PayID error:" + e.getMessage()));
+ }
+ };
+
+ serverApiPayId.getAddress(targetAddress, ctx.getBlockchain(), payIdObserver);
}
@Override
diff --git a/app/src/main/java/com/tangem/wallet/xlm/XlmEngine.java b/app/src/main/java/com/tangem/wallet/xlm/XlmEngine.java
index 8476b33a37..cc8d377184 100644
--- a/app/src/main/java/com/tangem/wallet/xlm/XlmEngine.java
+++ b/app/src/main/java/com/tangem/wallet/xlm/XlmEngine.java
@@ -7,8 +7,11 @@ import android.util.Log;
import com.tangem.App;
import com.tangem.data.Blockchain;
+import com.tangem.data.network.ServerApiPayId;
import com.tangem.data.network.ServerApiStellar;
import com.tangem.data.network.StellarRequest;
+import com.tangem.data.network.model.PayIdAddress;
+import com.tangem.data.network.model.PayIdResponse;
import com.tangem.tangem_card.data.TangemCard;
import com.tangem.tangem_card.tasks.SignTask;
import com.tangem.tangem_card.util.Util;
@@ -31,6 +34,11 @@ import org.stellar.sdk.responses.operations.OperationResponse;
import java.io.IOException;
import java.math.BigDecimal;
+import io.reactivex.CompletableObserver;
+import io.reactivex.SingleObserver;
+import io.reactivex.observers.DisposableCompletableObserver;
+import io.reactivex.observers.DisposableSingleObserver;
+
/**
* Created by dvol on 7.01.2019.
*
@@ -123,6 +131,10 @@ public class XlmEngine extends CoinEngine {
@Override
public boolean validateAddress(String address) {
+ if (address != null && address.contains("$")) { // PayID
+ return validatePayId(address);
+ }
+
try {
KeyPair kp = KeyPair.fromAccountId(address);
// TODO is it possible to check address testNet or not
@@ -356,18 +368,26 @@ public class XlmEngine extends CoinEngine {
StrictMode.setThreadPolicy(policy);
+ String destination;
+ //PayID
+ if (coinData.getResolvedPayIdAddress() != null) {
+ destination = coinData.getResolvedPayIdAddress();
+ } else {
+ destination = targetAddress;
+ }
+
if (IncFee) {
amountValue = new Amount(amountValue.subtract(feeValue), amountValue.getCurrency());
}
Operation operation;
if (coinData.isTargetAccountCreated()) {
- operation = new PaymentOperation.Builder(KeyPair.fromAccountId(targetAddress), new AssetTypeNative(), amountValue.toValueString()).build();
+ operation = new PaymentOperation.Builder(KeyPair.fromAccountId(destination), new AssetTypeNative(), amountValue.toValueString()).build();
} else {
if (amountValue.compareTo(coinData.getReserve()) < 0) {
throw new IllegalArgumentException("Target account is not created. Send " + coinData.getReserve().toDescriptionString(getDecimals()) + " or more to create");
}
- operation = new CreateAccountOperation.Builder(KeyPair.fromAccountId(targetAddress), amountValue.toValueString()).build();
+ operation = new CreateAccountOperation.Builder(KeyPair.fromAccountId(destination), amountValue.toValueString()).build();
}
TransactionEx transaction = TransactionEx.buildEx(120, coinData.getAccountResponse(), operation);
@@ -541,7 +561,65 @@ public class XlmEngine extends CoinEngine {
@Override
public void requestFee(BlockchainRequestsCallbacks blockchainRequestsCallbacks, String targetAddress, Amount amount) throws Exception {
coinData.minFee = coinData.normalFee = coinData.maxFee = coinData.getBaseFee();
- checkTargetAccountCreated(blockchainRequestsCallbacks, targetAddress, amount); //TODO: move?
+
+ CompletableObserver payIdObserver = new DisposableCompletableObserver() {
+ @Override
+ public void onComplete() {
+ checkTargetAccountCreated(blockchainRequestsCallbacks, coinData.getResolvedPayIdAddress(), amount);
+ }
+
+ @Override
+ public void onError(Throwable e) {
+ ctx.setError(e.getMessage());
+ blockchainRequestsCallbacks.onComplete(false);
+ }
+ };
+
+ if (targetAddress.contains("$")) { // PayID
+ resolvePayID(targetAddress, payIdObserver);
+ } else {
+ checkTargetAccountCreated(blockchainRequestsCallbacks, targetAddress, amount);
+ }
+ }
+
+ private void resolvePayID(String targetAddress, CompletableObserver observer) {
+ final ServerApiPayId serverApiPayId = new ServerApiPayId();
+
+ SingleObserver payIdObserver = new DisposableSingleObserver() {
+ @Override
+ public void onSuccess(PayIdResponse payIdResponse) {
+ try {
+ String resolvedAddress = null;
+ for (PayIdAddress address : payIdResponse.getAddresses()) {
+ if (address.getPaymentNetwork().equals(ctx.getBlockchain().getCurrency()) &&
+ address.getEnvironment().equals("MAINNET")) {
+ resolvedAddress = address.getAddressDetails().getAddress();
+ break;
+ }
+ }
+ if (validateAddress(resolvedAddress)) {
+ if (!resolvedAddress.equals(coinData.getWallet())) {
+ coinData.setResolvedPayIdAddress(resolvedAddress);
+ observer.onComplete();
+ } else {
+ observer.onError(new Exception("Resolved PayID address equals source address"));
+ }
+ } else {
+ observer.onError(new Exception("Unknown address format in PayID response"));
+ }
+ } catch (Exception e) {
+ observer.onError(new Exception("Unknown response format on PayID request"));
+ }
+ }
+
+ @Override
+ public void onError(Throwable e) {
+ Log.i(TAG, "onFail: " + "payID" + " " + e.getMessage());
+ observer.onError(new Exception("PayID error:" + e.getMessage()));
+ }
+ };
+
+ serverApiPayId.getAddress(targetAddress, ctx.getBlockchain(), payIdObserver);
}
@Override
diff --git a/app/src/main/java/com/tangem/wallet/xrp/XrpData.java b/app/src/main/java/com/tangem/wallet/xrp/XrpData.java
index b54fe8c9e7..c2d33c62b8 100644
--- a/app/src/main/java/com/tangem/wallet/xrp/XrpData.java
+++ b/app/src/main/java/com/tangem/wallet/xrp/XrpData.java
@@ -19,7 +19,7 @@ public class XrpData extends CoinData {
private Boolean accountNotFound, targetAccountCreated = false;
- private String resolvedPayIdAddress, resolvedPayIdTag = null;
+ private String resolvedPayIdTag = null;
@Override
public void loadFromBundle(Bundle B) {
@@ -37,8 +37,6 @@ public class XrpData extends CoinData {
else accountNotFound = false;
if (B.containsKey("TargetAccountCreated")) targetAccountCreated = B.getBoolean("TargetAccountCreated");
else targetAccountCreated = false;
- if (B.containsKey("ResolvedPayIdAddress")) resolvedPayIdAddress = B.getString("ResolvedPayIdAddress");
- else resolvedPayIdAddress = null;
if (B.containsKey("ResolvedPayIdTag")) resolvedPayIdTag = B.getString("ResolvedPayIdTag");
else resolvedPayIdTag = null;
}
@@ -53,7 +51,6 @@ public class XrpData extends CoinData {
if (reserve != null) B.putLong("Reserve", reserve);
if (accountNotFound != null) B.putBoolean("AccoundNotFound", accountNotFound);
if (targetAccountCreated != null) B.putBoolean("TargetAccountCreated", targetAccountCreated);
- if (resolvedPayIdAddress != null) B.putString("ResolvedPayIdAddress", resolvedPayIdAddress);
if (resolvedPayIdTag != null) B.putString("ResolvedPayIdTag", resolvedPayIdTag);
} catch (Exception e) {
Log.e("Can't save to bundle ", e.getMessage());
@@ -69,7 +66,6 @@ public class XrpData extends CoinData {
reserve = 20000000L;
accountNotFound = false;
targetAccountCreated = false;
- resolvedPayIdAddress = null;
resolvedPayIdTag = null;
}
@@ -135,14 +131,6 @@ public class XrpData extends CoinData {
return hasBalanceInfo() && !balanceConfirmed.equals(balanceUnconfirmed);
}
- public String getResolvedPayIdAddress() {
- return resolvedPayIdAddress;
- }
-
- public void setResolvedPayIdAddress(String resolvedPayIdAddress) {
- this.resolvedPayIdAddress = resolvedPayIdAddress;
- }
-
public String getResolvedPayIdTag() {
return resolvedPayIdTag;
}
diff --git a/app/src/main/java/com/tangem/wallet/xrp/XrpEngine.java b/app/src/main/java/com/tangem/wallet/xrp/XrpEngine.java
index eb63be7a6b..6ea70b9d81 100644
--- a/app/src/main/java/com/tangem/wallet/xrp/XrpEngine.java
+++ b/app/src/main/java/com/tangem/wallet/xrp/XrpEngine.java
@@ -124,18 +124,7 @@ public class XrpEngine extends CoinEngine {
return false;
}
if (address.contains("$")) { // PayID
- String[] addressParts = address.split("\\$");
-
- if (addressParts.length != 2) {
- return false;
- }
- String addressURL = "https://" + addressParts[1] + "/" + addressParts[0];
- try {
- new URL(addressURL).toURI();
- return true;
- } catch (Exception e) {
- return false;
- }
+ return validatePayId(address);
}
try {
Addresses.decodeAccountID(address);
@@ -646,14 +635,14 @@ public class XrpEngine extends CoinEngine {
XrpXAddressDecoded xAddressDecoded = XrpXAddressService.Companion.decode(resolvedAddress);
if (xAddressDecoded == null) { // classic address
if (resolvedAddress.equals(coinData.getWallet())) {
- ctx.setError(R.string.prepare_transaction_error_same_address);
+ ctx.setError("Resolved PayID address equals source address");
blockchainRequestsCallbacks.onComplete(false);
} else {
serverApiRipple.requestData(ServerApiRipple.RIPPLE_ACCOUNT_INFO, resolvedAddress, "");
}
} else { // X-address
if (xAddressDecoded.getAddress().equals(coinData.getWallet())) {
- ctx.setError(R.string.prepare_transaction_error_same_address);
+ ctx.setError("Resolved PayID address equals source address");
blockchainRequestsCallbacks.onComplete(false);
} else {
serverApiRipple.requestData(ServerApiRipple.RIPPLE_ACCOUNT_INFO, xAddressDecoded.getAddress(), "");
diff --git a/app/src/tangemAccess/java/com/tangem/ui/PrepareTransactionFragment.kt b/app/src/tangemAccess/java/com/tangem/ui/PrepareTransactionFragment.kt
index 1e75eda210..387f992bb6 100644
--- a/app/src/tangemAccess/java/com/tangem/ui/PrepareTransactionFragment.kt
+++ b/app/src/tangemAccess/java/com/tangem/ui/PrepareTransactionFragment.kt
@@ -12,11 +12,13 @@ import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
import android.widget.Toast
import com.tangem.Constant
+import com.tangem.data.isPayIdSupported
import com.tangem.ui.activity.MainActivity
import com.tangem.ui.fragment.BaseFragment
import com.tangem.ui.fragment.qr.CameraPermissionManager
import com.tangem.ui.navigation.NavigationResultListener
import com.tangem.util.UtilHelper
+import com.tangem.util.extensions.isStart2CoinCard
import com.tangem.wallet.CoinEngineFactory
import com.tangem.wallet.R
import com.tangem.wallet.TangemContext
@@ -45,7 +47,9 @@ class PrepareTransactionFragment : BaseFragment(), NavigationResultListener, Nfc
Html.fromHtml(engine!!.balanceHTML)
tvBalance.text = html
- if (ctx.blockchain.isPayIdSupported) etWallet.hint = getString(R.string.prepare_transaction_hint_address_or_pay_id)
+ if (ctx.blockchain.isPayIdSupported() && !ctx.card.isStart2CoinCard()) {
+ etWallet.hint = getString(R.string.prepare_transaction_hint_address_or_pay_id)
+ }
if (!engine.allowSelectFeeInclusion()) {
rgIncFee.visibility = View.INVISIBLE
diff --git a/blockchain-demo/build.gradle b/blockchain-demo/build.gradle
index 6567a8b453..934f45b26c 100644
--- a/blockchain-demo/build.gradle
+++ b/blockchain-demo/build.gradle
@@ -45,10 +45,11 @@ android {
}
dependencies {
- implementation project(':tangem-core')
- implementation project(':tangem-sdk')
implementation project(':blockchain')
+ implementation 'com.tangem:core:0.10.4'
+ implementation 'com.tangem:sdk:0.10.4'
+
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$versions.kotlin"
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.core:core-ktx:1.2.0'
diff --git a/blockchain/build.gradle b/blockchain/build.gradle
index 24ee17af7f..31c5286f39 100644
--- a/blockchain/build.gradle
+++ b/blockchain/build.gradle
@@ -40,8 +40,7 @@ android {
dependencies {
// implementation fileTree(dir: 'libs', include: ['*.jar'])
- implementation project(':tangem-core')
- implementation project(':tangem-sdk')
+ implementation 'com.tangem:core:1.13'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$versions.kotlin"
implementation 'androidx.appcompat:appcompat:1.1.0'
diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/BitcoinAddressService.kt b/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/BitcoinAddressService.kt
index 1483284942..d05657d6ed 100644
--- a/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/BitcoinAddressService.kt
+++ b/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/BitcoinAddressService.kt
@@ -1,15 +1,18 @@
package com.tangem.blockchain.blockchains.bitcoin
+import com.tangem.blockchain.blockchains.ducatus.DucatusMainNetParams
import com.tangem.blockchain.blockchains.litecoin.LitecoinMainNetParams
import com.tangem.blockchain.common.AddressService
import com.tangem.blockchain.common.Blockchain
import com.tangem.common.extensions.calculateRipemd160
import com.tangem.common.extensions.calculateSha256
-import org.bitcoinj.core.*
+import org.bitcoinj.core.Base58
+import org.bitcoinj.core.LegacyAddress
+import org.bitcoinj.core.NetworkParameters
+import org.bitcoinj.core.SegwitAddress
import org.bitcoinj.params.MainNetParams
import org.bitcoinj.params.TestNet3Params
-import java.security.MessageDigest
class BitcoinAddressService(private val blockchain: Blockchain) : AddressService {
@@ -17,6 +20,7 @@ class BitcoinAddressService(private val blockchain: Blockchain) : AddressService
Blockchain.Bitcoin -> MainNetParams()
Blockchain.BitcoinTestnet -> TestNet3Params()
Blockchain.Litecoin -> LitecoinMainNetParams()
+ Blockchain.Ducatus -> DucatusMainNetParams()
else -> throw Exception("${blockchain.fullName} blockchain is not supported by ${this::class.simpleName}")
}
@@ -52,6 +56,7 @@ class BitcoinAddressService(private val blockchain: Blockchain) : AddressService
Blockchain.Bitcoin -> LegacyAddress.fromBase58(MainNetParams(), address)
Blockchain.BitcoinTestnet -> LegacyAddress.fromBase58(TestNet3Params(), address)
Blockchain.Litecoin -> LegacyAddress.fromBase58(LitecoinMainNetParams(), address)
+ Blockchain.Ducatus -> LegacyAddress.fromBase58(DucatusMainNetParams(), address)
else -> return false
}
true
diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/BitcoinTransactionBuilder.kt b/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/BitcoinTransactionBuilder.kt
index ede62d31a4..b829572b6f 100644
--- a/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/BitcoinTransactionBuilder.kt
+++ b/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/BitcoinTransactionBuilder.kt
@@ -1,5 +1,6 @@
package com.tangem.blockchain.blockchains.bitcoin
+import com.tangem.blockchain.blockchains.ducatus.DucatusMainNetParams
import com.tangem.blockchain.blockchains.litecoin.LitecoinMainNetParams
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.TransactionData
@@ -23,6 +24,7 @@ open class BitcoinTransactionBuilder(
Blockchain.Bitcoin, Blockchain.BitcoinCash -> MainNetParams()
Blockchain.BitcoinTestnet -> TestNet3Params()
Blockchain.Litecoin -> LitecoinMainNetParams()
+ Blockchain.Ducatus -> DucatusMainNetParams()
else -> throw Exception("${blockchain.fullName} blockchain is not supported by ${this::class.simpleName}")
}
var unspentOutputs: List? = null
@@ -64,7 +66,7 @@ open class BitcoinTransactionBuilder(
}
fun calculateChange(transactionData: TransactionData, unspentOutputs: List): BigDecimal {
- val fullAmount = unspentOutputs!!.map { it.amount }.reduce { acc, number -> acc + number }
+ val fullAmount = unspentOutputs.map { it.amount }.reduce { acc, number -> acc + number }
return fullAmount - (transactionData.amount.value!! + (transactionData.fee?.value
?: 0.toBigDecimal()))
}
diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/BitcoinWalletManager.kt b/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/BitcoinWalletManager.kt
index 2a723fe5f9..ac393ef37e 100644
--- a/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/BitcoinWalletManager.kt
+++ b/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/BitcoinWalletManager.kt
@@ -13,7 +13,7 @@ import java.math.BigDecimal
open class BitcoinWalletManager(
cardId: String,
wallet: Wallet,
- private val transactionBuilder: BitcoinTransactionBuilder,
+ protected val transactionBuilder: BitcoinTransactionBuilder,
private val networkManager: BitcoinProvider
) : WalletManager(cardId, wallet), TransactionSender {
diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/ducatus/DucatusMainNetParams.java b/blockchain/src/main/java/com/tangem/blockchain/blockchains/ducatus/DucatusMainNetParams.java
new file mode 100644
index 0000000000..c4373b88df
--- /dev/null
+++ b/blockchain/src/main/java/com/tangem/blockchain/blockchains/ducatus/DucatusMainNetParams.java
@@ -0,0 +1,69 @@
+package com.tangem.blockchain.blockchains.ducatus;
+
+import org.bitcoinj.core.Utils;
+import org.bitcoinj.params.AbstractBitcoinNetParams;
+import org.bitcoinj.params.MainNetParams;
+import org.spongycastle.util.encoders.Hex;
+
+import static com.google.common.base.Preconditions.checkState;
+
+
+public class DucatusMainNetParams extends AbstractBitcoinNetParams {
+ public static final int MAINNET_MAJORITY_WINDOW = MainNetParams.MAINNET_MAJORITY_WINDOW;
+ public static final int MAINNET_MAJORITY_REJECT_BLOCK_OUTDATED = MainNetParams.MAINNET_MAJORITY_REJECT_BLOCK_OUTDATED;
+ public static final int MAINNET_MAJORITY_ENFORCE_BLOCK_UPGRADE = MainNetParams.MAINNET_MAJORITY_ENFORCE_BLOCK_UPGRADE;
+
+ public DucatusMainNetParams() {
+ super();
+ id = "org.bitcoinj.ducatus_mainnet";
+ // Genesis hash is 12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2
+ packetMagic = 0xfbc0b6db;
+
+ maxTarget = Utils.decodeCompactBits(0x1e0fffffL);
+ port = 9333;
+ addressHeader = 49;
+ p2shHeader = 51; //TODO: is this right? Haven't seen Ducatus p2sh address ever
+ segwitAddressHrp = "duc"; //TODO: does Ducatus even have bech32 addresses? At least other blockchain's addresses won't pass
+ dumpedPrivateKeyHeader = 176;
+
+ spendableCoinbaseDepth = 100;
+ subsidyDecreaseBlockCount = 840000;
+
+ genesisBlock.setTime(1317972665L);
+ genesisBlock.setDifficultyTarget(0x1e0ffff0L);
+ genesisBlock.setNonce(2084524493);
+
+ String genesisHash = genesisBlock.getHashAsString();
+ checkState(genesisHash.equals("5155a7ed2219a75c0735c58b5d459c6d07d97917570e27b9d1d4546fb8431381"));
+ alertSigningKey = Hex.decode("040184710fa689ad5023690c80f3a49c8f13f8d45b8c857fbcbc8bc4a8e4d3eb4b10f4d4604fa08dce601aaf0f470216fe1b51850b4acf21b179c45070ac7b03a9");
+
+ majorityEnforceBlockUpgrade = MAINNET_MAJORITY_ENFORCE_BLOCK_UPGRADE;
+ majorityRejectBlockOutdated = MAINNET_MAJORITY_REJECT_BLOCK_OUTDATED;
+ majorityWindow = MAINNET_MAJORITY_WINDOW;
+
+ dnsSeeds = new String[]{
+ "dnsseed.litecointools.com",
+ "dnsseed.litecoinpool.org",
+ "dnsseed.ltc.xurious.com",
+ "dnsseed.koin-project.com",
+ "dnsseed.weminemnc.com"
+ };
+ bip32HeaderP2PKHpub = 0x0488B21E;
+ bip32HeaderP2PKHpriv = 0x0488ADE4;
+ }
+
+ @Override
+ public String getPaymentProtocolId() {
+ return PAYMENT_PROTOCOL_ID_MAINNET;
+ }
+
+
+ private static DucatusMainNetParams instance;
+
+ public static synchronized DucatusMainNetParams get() {
+ if (instance == null) {
+ instance = new DucatusMainNetParams();
+ }
+ return instance;
+ }
+}
diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/ducatus/DucatusWalletManager.kt b/blockchain/src/main/java/com/tangem/blockchain/blockchains/ducatus/DucatusWalletManager.kt
new file mode 100644
index 0000000000..06ea687cb2
--- /dev/null
+++ b/blockchain/src/main/java/com/tangem/blockchain/blockchains/ducatus/DucatusWalletManager.kt
@@ -0,0 +1,40 @@
+package com.tangem.blockchain.blockchains.ducatus
+
+import com.tangem.blockchain.blockchains.bitcoin.BitcoinTransactionBuilder
+import com.tangem.blockchain.blockchains.bitcoin.BitcoinWalletManager
+import com.tangem.blockchain.blockchains.ducatus.network.DucatusNetworkManager
+import com.tangem.blockchain.common.Amount
+import com.tangem.blockchain.common.TransactionData
+import com.tangem.blockchain.common.TransactionSender
+import com.tangem.blockchain.common.Wallet
+import com.tangem.blockchain.extensions.Result
+import java.math.BigDecimal
+
+class DucatusWalletManager(
+ cardId: String,
+ wallet: Wallet,
+ transactionBuilder: BitcoinTransactionBuilder,
+ networkManager: DucatusNetworkManager
+) : BitcoinWalletManager(cardId, wallet, transactionBuilder, networkManager), TransactionSender {
+ override suspend fun getFee(amount: Amount, destination: String): Result> {
+ val feeValue = BigDecimal.ONE.movePointLeft(blockchain.decimals())
+ val sizeResult = transactionBuilder.getEstimateSize(
+ TransactionData(amount, Amount(amount, feeValue), wallet.address, destination)
+ )
+ return when (sizeResult) {
+ is Result.Failure -> sizeResult
+ is Result.Success -> {
+ val transactionSize = sizeResult.data.toBigDecimal()
+ val minFee = BigDecimal.valueOf(0.00000089).multiply(transactionSize)
+ val normalFee = BigDecimal.valueOf(0.00000144).multiply(transactionSize)
+ val priorityFee = BigDecimal.valueOf(0.00000350).multiply(transactionSize)
+ val fees = listOf(
+ Amount(minFee, blockchain),
+ Amount(normalFee, blockchain),
+ Amount(priorityFee, blockchain)
+ )
+ Result.Success(fees)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/ducatus/network/DucatusNetworkManager.kt b/blockchain/src/main/java/com/tangem/blockchain/blockchains/ducatus/network/DucatusNetworkManager.kt
new file mode 100644
index 0000000000..7b08f99b72
--- /dev/null
+++ b/blockchain/src/main/java/com/tangem/blockchain/blockchains/ducatus/network/DucatusNetworkManager.kt
@@ -0,0 +1,8 @@
+package com.tangem.blockchain.blockchains.ducatus.network
+
+import com.tangem.blockchain.blockchains.ducatus.network.bitcore.BitcoreApi
+import com.tangem.blockchain.blockchains.ducatus.network.bitcore.BitcoreProvider
+import com.tangem.blockchain.network.API_DUCATUS
+import com.tangem.blockchain.network.createRetrofitInstance
+
+class DucatusNetworkManager() : BitcoreProvider(createRetrofitInstance(API_DUCATUS).create(BitcoreApi::class.java))
\ No newline at end of file
diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/ducatus/network/bitcore/BitcoreApi.kt b/blockchain/src/main/java/com/tangem/blockchain/blockchains/ducatus/network/bitcore/BitcoreApi.kt
new file mode 100644
index 0000000000..be7214c1ef
--- /dev/null
+++ b/blockchain/src/main/java/com/tangem/blockchain/blockchains/ducatus/network/bitcore/BitcoreApi.kt
@@ -0,0 +1,21 @@
+package com.tangem.blockchain.blockchains.ducatus.network.bitcore
+
+import com.squareup.moshi.JsonClass
+import retrofit2.http.Body
+import retrofit2.http.GET
+import retrofit2.http.POST
+import retrofit2.http.Path
+
+interface BitcoreApi {
+ @GET("api/DUC/mainnet/address/{address}/balance")
+ suspend fun getBalance(@Path("address") address: String): BitcoreBalance
+
+ @GET("api/DUC/mainnet/address/{address}/?unspent=true")
+ suspend fun getUnspents(@Path("address") address: String): List
+
+ @POST("api/DUC/mainnet/tx/send")
+ suspend fun sendTransaction(@Body body: BitcoreSendBody): BitcoreSendResponse
+}
+
+@JsonClass(generateAdapter = true)
+data class BitcoreSendBody(val rawTx: List)
\ No newline at end of file
diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/ducatus/network/bitcore/BitcoreProvider.kt b/blockchain/src/main/java/com/tangem/blockchain/blockchains/ducatus/network/bitcore/BitcoreProvider.kt
new file mode 100644
index 0000000000..39fb7fa213
--- /dev/null
+++ b/blockchain/src/main/java/com/tangem/blockchain/blockchains/ducatus/network/bitcore/BitcoreProvider.kt
@@ -0,0 +1,64 @@
+package com.tangem.blockchain.blockchains.ducatus.network.bitcore
+
+import com.tangem.blockchain.blockchains.bitcoin.BitcoinUnspentOutput
+import com.tangem.blockchain.blockchains.bitcoin.network.BitcoinAddressResponse
+import com.tangem.blockchain.blockchains.bitcoin.network.BitcoinFee
+import com.tangem.blockchain.blockchains.bitcoin.network.BitcoinProvider
+import com.tangem.blockchain.common.Blockchain
+import com.tangem.blockchain.extensions.Result
+import com.tangem.blockchain.extensions.SimpleResult
+import com.tangem.blockchain.extensions.retryIO
+import com.tangem.common.extensions.hexToBytes
+import kotlinx.coroutines.async
+import kotlinx.coroutines.coroutineScope
+
+open class BitcoreProvider(private val api: BitcoreApi) : BitcoinProvider{
+ private val decimals = Blockchain.Ducatus.decimals()
+
+ override suspend fun getInfo(address: String): Result {
+ return try {
+ coroutineScope {
+ val balanceDeferred = retryIO { async { api.getBalance(address) } }
+ val unspentsDeferred = retryIO { async { api.getUnspents(address) } }
+
+ val balanceData = balanceDeferred.await()
+ val unspents = unspentsDeferred.await()
+
+ val unspentTransactions = unspents.map {
+ BitcoinUnspentOutput(
+ amount = it.amount!!.toBigDecimal().movePointLeft(decimals),
+ outputIndex = it.index!!.toLong(),
+ transactionHash = it.transactionHash!!.hexToBytes(),
+ outputScript = it.script!!.hexToBytes()
+ )
+ }
+
+ Result.Success(BitcoinAddressResponse(
+ balance = balanceData.confirmed!!.toBigDecimal().movePointLeft(decimals),//only confirmed balance is returned right
+ hasUnconfirmed = balanceData.unconfirmed != null,
+ unspentOutputs = unspentTransactions
+ ))
+ }
+ } catch (error: Exception) {
+ Result.Failure(error)
+ }
+ }
+
+ override suspend fun getFee(): Result {
+ TODO("Not yet implemented")// bitcore is used only in ducatus and fee is hardcoded there
+ }
+
+
+ override suspend fun sendTransaction(transaction: String): SimpleResult {
+ return try {
+ val response = retryIO { api.sendTransaction(BitcoreSendBody(listOf(transaction))) }
+ if (response.txid != null) {
+ SimpleResult.Success
+ } else {
+ SimpleResult.Failure(Exception("Unknown send transaction error"))
+ }
+ } catch (error: Exception) {
+ SimpleResult.Failure(error)
+ }
+ }
+}
\ No newline at end of file
diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/ducatus/network/bitcore/BitcoreResponse.kt b/blockchain/src/main/java/com/tangem/blockchain/blockchains/ducatus/network/bitcore/BitcoreResponse.kt
new file mode 100644
index 0000000000..5b7cda90db
--- /dev/null
+++ b/blockchain/src/main/java/com/tangem/blockchain/blockchains/ducatus/network/bitcore/BitcoreResponse.kt
@@ -0,0 +1,34 @@
+package com.tangem.blockchain.blockchains.ducatus.network.bitcore
+
+import com.squareup.moshi.Json
+import com.squareup.moshi.JsonClass
+
+@JsonClass(generateAdapter = true)
+data class BitcoreBalance(
+ @Json(name = "confirmed")
+ var confirmed: Long? = null,
+
+ @Json(name = "unconfirmed")
+ var unconfirmed: Long? = null
+)
+
+@JsonClass(generateAdapter = true)
+data class BitcoreUtxo(
+ @Json(name = "mintTxid")
+ var transactionHash: String? = null,
+
+ @Json(name = "mintIndex")
+ var index: Int? = null,
+
+ @Json(name = "value")
+ var amount: Long? = null,
+
+ @Json(name = "script")
+ var script: String? = null
+)
+
+@JsonClass(generateAdapter = true)
+data class BitcoreSendResponse(
+ @Json(name = "txid")
+ var txid: String? = null
+)
\ No newline at end of file
diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/ethereum/EthereumWalletManager.kt b/blockchain/src/main/java/com/tangem/blockchain/blockchains/ethereum/EthereumWalletManager.kt
index 5ac19d6370..006ca87f77 100644
--- a/blockchain/src/main/java/com/tangem/blockchain/blockchains/ethereum/EthereumWalletManager.kt
+++ b/blockchain/src/main/java/com/tangem/blockchain/blockchains/ethereum/EthereumWalletManager.kt
@@ -1,8 +1,8 @@
package com.tangem.blockchain.blockchains.ethereum
import android.util.Log
-import com.tangem.blockchain.blockchains.ethereum.network.EthereumNetworkManager
import com.tangem.blockchain.blockchains.ethereum.network.EthereumInfoResponse
+import com.tangem.blockchain.blockchains.ethereum.network.EthereumNetworkManager
import com.tangem.blockchain.common.*
import com.tangem.blockchain.extensions.Result
import com.tangem.blockchain.extensions.SimpleResult
@@ -24,7 +24,11 @@ class EthereumWalletManager(
override suspend fun update() {
- val result = networkManager.getInfo(wallet.address, wallet.amounts[AmountType.Token]?.address)
+ val result = networkManager.getInfo(
+ wallet.address,
+ wallet.amounts[AmountType.Token]?.address,
+ wallet.amounts[AmountType.Token]?.decimals
+ )
when (result) {
is Result.Failure -> updateError(result.error)
is Result.Success -> updateWallet(result.data)
diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/ethereum/network/EthereumNetworkManager.kt b/blockchain/src/main/java/com/tangem/blockchain/blockchains/ethereum/network/EthereumNetworkManager.kt
index b5da72dd74..87da3d438e 100644
--- a/blockchain/src/main/java/com/tangem/blockchain/blockchains/ethereum/network/EthereumNetworkManager.kt
+++ b/blockchain/src/main/java/com/tangem/blockchain/blockchains/ethereum/network/EthereumNetworkManager.kt
@@ -10,7 +10,6 @@ import com.tangem.blockchain.network.createRetrofitInstance
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
-import org.kethereum.ETH_IN_WEI
import java.math.BigDecimal
import java.math.BigInteger
import java.math.RoundingMode
@@ -35,6 +34,7 @@ class EthereumNetworkManager(blockchain: Blockchain) {
}
private val provider: EthereumProvider by lazy { EthereumProvider(api, apiKey) }
+ private val decimals = Blockchain.Ethereum.decimals()
suspend fun sendTransaction(transaction: String): SimpleResult {
return try {
@@ -59,19 +59,20 @@ class EthereumNetworkManager(blockchain: Blockchain) {
}
}
- suspend fun getInfo(address: String, contractAddress: String? = null): Result {
+ suspend fun getInfo(address: String, contractAddress: String? = null, tokenDecimals: Int? = null)
+ : Result {
return try {
coroutineScope {
val balanceResponse = retryIO { async { provider.getBalance(address) } }
val txCountResponse = retryIO { async { provider.getTxCount(address) } }
val pendingTxCountResponse = retryIO { async { provider.getPendingTxCount(address) } }
var tokenBalanceResponse: Deferred? = null
- if (contractAddress != null) {
+ if (contractAddress != null && tokenDecimals != null) {
tokenBalanceResponse = retryIO { async { provider.getTokenBalance(address, contractAddress) } }
}
Result.Success(EthereumInfoResponse(
- balanceResponse.await().result!!.parseAmount(),
- tokenBalanceResponse?.await()?.result?.parseAmount(),
+ balanceResponse.await().result!!.parseAmount(decimals),
+ tokenBalanceResponse?.await()?.result?.parseAmount(tokenDecimals!!),
txCountResponse.await().result?.responseToNumber()?.toLong() ?: 0,
pendingTxCountResponse.await().result?.responseToNumber()?.toLong() ?: 0
))
@@ -87,20 +88,19 @@ class EthereumNetworkManager(blockchain: Blockchain) {
val normalFee = minFee.multiply(BigDecimal(1.2)).setScale(0, RoundingMode.HALF_UP)
val priorityFee = minFee.multiply(BigDecimal(1.5)).setScale(0, RoundingMode.HALF_UP)
return listOf(
- minFee.convertFeeToEth(),
- normalFee.convertFeeToEth(),
- priorityFee.convertFeeToEth()
+ minFee.movePointLeft(decimals),
+ normalFee.movePointLeft(decimals),
+ priorityFee.movePointLeft(decimals)
)
}
private fun String.responseToNumber(): BigInteger = this.substring(2).toBigInteger(16)
- private fun String.parseAmount(): BigDecimal =
- this.responseToNumber().toBigDecimal().divide(ETH_IN_WEI.toBigDecimal())
+ private fun String.parseAmount(decimals: Int): BigDecimal =
+ this.responseToNumber().toBigDecimal().movePointLeft(decimals)
private fun BigDecimal.convertFeeToEth(): BigDecimal {
- return this.divide(ETH_IN_WEI.toBigDecimal())
- .setScale(12, BigDecimal.ROUND_DOWN).stripTrailingZeros()
+ return this.movePointLeft(decimals).setScale(decimals, BigDecimal.ROUND_DOWN).stripTrailingZeros()
}
}
diff --git a/blockchain/src/main/java/com/tangem/blockchain/common/Blockchain.kt b/blockchain/src/main/java/com/tangem/blockchain/common/Blockchain.kt
index d7ba034407..f732d9d723 100644
--- a/blockchain/src/main/java/com/tangem/blockchain/common/Blockchain.kt
+++ b/blockchain/src/main/java/com/tangem/blockchain/common/Blockchain.kt
@@ -19,6 +19,7 @@ enum class Blockchain(
BitcoinTestnet("BTC/test", "BTCt", "Bitcoin Testnet"),
BitcoinCash("BCH", "BCH", "Bitcoin Cash"),
Litecoin("LTC", "LTC", "Litecoin"),
+ Ducatus("DUC", "DUC", "Ducatus"),
Ethereum("ETH", "ETH", "Ethereum"),
RSK("RSK", "RBTC", "RSK"),
Cardano("CARDANO", "ADA", "Cardano"),
@@ -29,7 +30,7 @@ enum class Blockchain(
Tezos("TEZOS", "XTZ", "Tezos");
fun decimals(): Int = when (this) {
- Bitcoin, BitcoinTestnet, BitcoinCash, Binance, BinanceTestnet, Litecoin -> 8
+ Bitcoin, BitcoinTestnet, BitcoinCash, Binance, BinanceTestnet, Litecoin, Ducatus -> 8
Cardano, XRP, Tezos -> 6
Ethereum, RSK -> 18
Stellar -> 7
@@ -45,8 +46,7 @@ enum class Blockchain(
fun validateAddress(address: String): Boolean = getAddressService().validate(address)
private fun getAddressService(): AddressService = when (this) {
- Unknown -> throw Exception("unsupported blockchain")
- Bitcoin, BitcoinTestnet, Litecoin -> BitcoinAddressService(this)
+ Bitcoin, BitcoinTestnet, Litecoin, Ducatus -> BitcoinAddressService(this)
BitcoinCash -> BitcoinCashAddressService()
Ethereum, RSK -> EthereumAddressService()
Cardano -> CardanoAddressService()
@@ -55,6 +55,7 @@ enum class Blockchain(
BinanceTestnet -> BinanceAddressService(true)
Stellar -> StellarAddressService()
Tezos -> TezosAddressService()
+ Unknown -> throw Exception("unsupported blockchain")
}
fun getShareUri(address: String): String = when (this) {
@@ -71,9 +72,10 @@ enum class Blockchain(
BitcoinTestnet -> "https://live.blockcypher.com/btc-testnet/address/$address"
BitcoinCash -> "https://blockchair.com/bitcoin-cash/address/$address"
Litecoin -> "https://live.blockcypher.com/ltc/address/$address"
+ Ducatus -> "https://insight.ducatus.io/#/DUC/mainnet/address/$address"
Cardano -> "https://cardanoexplorer.com/address/$address"
Ethereum -> if (token == null) {
- "https://etherscan.io/address/"
+ "https://etherscan.io/address/$address"
} else {
"https://etherscan.io/token/${token.contractAddress}?a=$address"
}
diff --git a/blockchain/src/main/java/com/tangem/blockchain/common/WalletManager.kt b/blockchain/src/main/java/com/tangem/blockchain/common/WalletManager.kt
index 3271af9575..37cde3b700 100644
--- a/blockchain/src/main/java/com/tangem/blockchain/common/WalletManager.kt
+++ b/blockchain/src/main/java/com/tangem/blockchain/common/WalletManager.kt
@@ -32,7 +32,7 @@ abstract class WalletManager(val cardId: String, var wallet: Wallet) {
}
private fun validateAmount(amount: Amount): Boolean {
- return !amount.isAboveZero() &&
+ return amount.isAboveZero() &&
wallet.fundsAvailable(amount.type) >= amount.value
}
}
diff --git a/blockchain/src/main/java/com/tangem/blockchain/common/WalletManagerFactory.kt b/blockchain/src/main/java/com/tangem/blockchain/common/WalletManagerFactory.kt
index 1c7af4e354..c47a0b1f86 100644
--- a/blockchain/src/main/java/com/tangem/blockchain/common/WalletManagerFactory.kt
+++ b/blockchain/src/main/java/com/tangem/blockchain/common/WalletManagerFactory.kt
@@ -12,6 +12,8 @@ import com.tangem.blockchain.blockchains.bitcoincash.BitcoinCashWalletManager
import com.tangem.blockchain.blockchains.cardano.CardanoTransactionBuilder
import com.tangem.blockchain.blockchains.cardano.CardanoWalletManager
import com.tangem.blockchain.blockchains.cardano.network.CardanoNetworkManager
+import com.tangem.blockchain.blockchains.ducatus.DucatusWalletManager
+import com.tangem.blockchain.blockchains.ducatus.network.DucatusNetworkManager
import com.tangem.blockchain.blockchains.ethereum.EthereumTransactionBuilder
import com.tangem.blockchain.blockchains.ethereum.EthereumWalletManager
import com.tangem.blockchain.blockchains.ethereum.network.EthereumNetworkManager
@@ -19,7 +21,6 @@ import com.tangem.blockchain.blockchains.litecoin.LitecoinNetworkManager
import com.tangem.blockchain.blockchains.litecoin.LitecoinWalletManager
import com.tangem.blockchain.blockchains.stellar.StellarNetworkManager
import com.tangem.blockchain.blockchains.stellar.StellarTransactionBuilder
-
import com.tangem.blockchain.blockchains.stellar.StellarWalletManager
import com.tangem.blockchain.blockchains.tezos.TezosTransactionBuilder
import com.tangem.blockchain.blockchains.tezos.TezosWalletManager
@@ -72,6 +73,13 @@ object WalletManagerFactory {
LitecoinNetworkManager()
)
}
+ Blockchain.Ducatus -> {
+ return DucatusWalletManager(
+ cardId, wallet,
+ BitcoinTransactionBuilder(walletPublicKey, blockchain),
+ DucatusNetworkManager()
+ )
+ }
Blockchain.Ethereum, Blockchain.RSK -> {
return EthereumWalletManager(
cardId, wallet,
diff --git a/blockchain/src/main/java/com/tangem/blockchain/network/RetrofitBuilder.kt b/blockchain/src/main/java/com/tangem/blockchain/network/RetrofitBuilder.kt
index 8573dff8a7..97e13c5643 100644
--- a/blockchain/src/main/java/com/tangem/blockchain/network/RetrofitBuilder.kt
+++ b/blockchain/src/main/java/com/tangem/blockchain/network/RetrofitBuilder.kt
@@ -55,4 +55,5 @@ const val API_RIPPLED = "https://s1.ripple.com:51234/"
const val API_RIPPLED_RESERVE = "https://s2.ripple.com:51234/"
const val API_BLOCKCHAIR = "https://api.blockchair.com/"
const val API_TEZOS = "https://teznode.letzbake.com"
-const val API_TEZOS_RESERVE = "https://mainnet.tezrpc.me"
\ No newline at end of file
+const val API_TEZOS_RESERVE = "https://mainnet.tezrpc.me"
+const val API_DUCATUS = "https://ducapi.rocknblock.io/"
\ No newline at end of file
diff --git a/blockchain/src/test/java/com/tangem/blockchain/blockchains/ducatus/DucatusAddressTest.kt b/blockchain/src/test/java/com/tangem/blockchain/blockchains/ducatus/DucatusAddressTest.kt
new file mode 100644
index 0000000000..528a0a199b
--- /dev/null
+++ b/blockchain/src/test/java/com/tangem/blockchain/blockchains/ducatus/DucatusAddressTest.kt
@@ -0,0 +1,28 @@
+package com.tangem.blockchain.blockchains.ducatus
+
+import com.google.common.truth.Truth
+import com.tangem.blockchain.blockchains.bitcoin.BitcoinAddressService
+import com.tangem.blockchain.common.Blockchain
+import com.tangem.common.extensions.hexToBytes
+import org.junit.Test
+
+class DucatusAddressTest {
+
+ private val addressService = BitcoinAddressService(Blockchain.Ducatus)
+
+ @Test
+ fun makeAddressFromCorrectPublicKey() {
+ val walletPublicKey = "0485D520C8B907F0BC5E03FCBBAC212CCD270764BBFF4990A28653A2FB0D656C342DF143C4D52C43582289E20A81D5D014C1384A1FFFEA1D121903AD7ED35A01EA".hexToBytes()
+ val expected = "Ly3SZetcgr5gkZMwiNwVrts2z2r3jYieAG"
+
+ Truth.assertThat(addressService.makeAddress(walletPublicKey))
+ .isEqualTo(expected)
+ }
+
+ @Test
+ fun validateCorrectAddress() {
+ val address = "Ly3SZetcgr5gkZMwiNwVrts2z2r3jYieAG"
+ Truth.assertThat(addressService.validate(address))
+ .isTrue()
+ }
+}
\ No newline at end of file
diff --git a/blockchain/src/test/java/com/tangem/blockchain/common/WalletManagerFactoryTest.kt b/blockchain/src/test/java/com/tangem/blockchain/common/WalletManagerFactoryTest.kt
index 33c6e97c89..af0e844c61 100644
--- a/blockchain/src/test/java/com/tangem/blockchain/common/WalletManagerFactoryTest.kt
+++ b/blockchain/src/test/java/com/tangem/blockchain/common/WalletManagerFactoryTest.kt
@@ -6,6 +6,7 @@ import com.tangem.blockchain.blockchains.binance.BinanceWalletManager
import com.tangem.blockchain.blockchains.bitcoin.BitcoinWalletManager
import com.tangem.blockchain.blockchains.bitcoincash.BitcoinCashWalletManager
import com.tangem.blockchain.blockchains.cardano.CardanoWalletManager
+import com.tangem.blockchain.blockchains.ducatus.DucatusWalletManager
import com.tangem.blockchain.blockchains.ethereum.EthereumWalletManager
import com.tangem.blockchain.blockchains.litecoin.LitecoinWalletManager
import com.tangem.blockchain.blockchains.stellar.StellarWalletManager
@@ -18,11 +19,13 @@ import org.junit.Test
internal class WalletManagerFactoryTest {
+ private val sessionEnvironment = SessionEnvironment()
+
@Test
fun createBitcoinWalletManager() {
val data = "0108bb00000000000304200754414e47454d00020102800a322e3432642053444b000341040876bdec26b89bd2159a668b9af3d9fe86370f318717c92b8d6c1186fb3648c32a5f9321998cc2d042901c91d40601e79a641e1cbcebe7a2358be6054e1b6e5d0a04041e76310c618102ffff8a0101820407e30b0d830b54414e47454d2053444b0084034254438640e17ceec48c5be36240c98019f95ad8b6e56acfebe60d11979c6279f715d607d76a860a137da8d109e805753f3f56b0130709f4bbf4cb9974b4c57b8469bf4b873041045f16bd1d2eafe463e62a335a09e6b2bbcbd04452526885cb679fc4d27af1bd22f553c7deefb54fd3d4f361d14e6dc3f11b7d4ea183250a60720ebdf9e110cd26050a736563703235366b310008040000006407010009020bb8604104752a727e14bba5bd73b6714d72500f61ffd11026ad1196d2e1c54577cbeeac3d11fc68a64700f8d533f4e311964ea8fb3aa26c588295f2133868d69c3e62869362040000005c6304000000090f01009000"
val responseApdu = ResponseApdu(data.hexToBytes())
- val card = ReadCommand().deserialize(SessionEnvironment(), responseApdu)
+ val card = ReadCommand().deserialize(sessionEnvironment, responseApdu)
val walletManager = WalletManagerFactory.makeWalletManager(card)
Truth.assertThat(walletManager)
@@ -33,7 +36,7 @@ internal class WalletManagerFactoryTest {
fun createEthereumWalletManager() {
val data = "0108bb00000000000536200754414e47454d00020102800a322e3432642053444b000341046c8aea0d5a850b0a608acf9a0c453c39ea86131e88bfa78800de3cfb5bf1007aeaa7b9ffc184212255758605c2461be343c0a661d73cabafa4c9c175b3f0e59a0a04041e76310c618102ffff8a0101820407e30b0d830b54414e47454d2053444b0084034554488640431b6244acfeac479becdff201a7f720a7d70a97edc4e019fb678596baf52dfe9d0e8faf08ceb4443b82d4e66815541f2dc8ec6dd3ff83eb42f06e5eab07f25f3041045f16bd1d2eafe463e62a335a09e6b2bbcbd04452526885cb679fc4d27af1bd22f553c7deefb54fd3d4f361d14e6dc3f11b7d4ea183250a60720ebdf9e110cd26050a736563703235366b3100080400000064070100090205dc60410464dddc3f356744aaecfa07427f9eb996ff537d65f20fb5be3abccf0354352a6b5f8a1942e0f8ddeea3a170eda78d060be8162ad60e94e4e91fbbdf0a7054785562040000005b6304000000090f01009000"
val responseApdu = ResponseApdu(data.hexToBytes())
- val card = ReadCommand().deserialize(SessionEnvironment(), responseApdu)
+ val card = ReadCommand().deserialize(sessionEnvironment, responseApdu)
val walletManager = WalletManagerFactory.makeWalletManager(card)
Truth.assertThat(walletManager)
@@ -44,7 +47,7 @@ internal class WalletManagerFactoryTest {
fun createStellarWalletManager() {
val data = "0108bb00000000000379200754414e47454d00020102800a322e3432642053444b0003410487d7bb51b189213e3cedc3fcfa3fc047b3b71b7805b5b215e14639b3a8ebb1952c9dd5ea4354441b6ada4e8b8327674bb102ddae69df55be69643a2c916edf650a04041e76310c618102ffff8a0101820407e30b0d830b54414e47454d2053444b008403584c4d86409a4bc2baf0e5836887da21167cf33458d5249d1a610bced0e31dc053f23729ed24d715912bf89e6804669430dfe396ed83274e0031f6803e2bdb8c041fa993413041045f16bd1d2eafe463e62a335a09e6b2bbcbd04452526885cb679fc4d27af1bd22f553c7deefb54fd3d4f361d14e6dc3f11b7d4ea183250a60720ebdf9e110cd2605086564323535313900080400000064070100090205dc6020e078212d58b2b9d0edc9c936830d10081cd38b90c31778c56dfb1171027e294e62040000003863040000002c0f01009000"
val responseApdu = ResponseApdu(data.hexToBytes())
- val card = ReadCommand().deserialize(SessionEnvironment(), responseApdu)
+ val card = ReadCommand().deserialize(sessionEnvironment, responseApdu)
val walletManager = WalletManagerFactory.makeWalletManager(card)
Truth.assertThat(walletManager)
@@ -55,7 +58,7 @@ internal class WalletManagerFactoryTest {
fun createCardanoWalletManager() {
val data = "0108bb00000000000502200754414e47454d00020102800a322e3432642053444b0003410402c1e39257d60583489da2d67d35d1cc2a1c005cc05c1021f44838edcaf25d5615cad7c9d11c2e23f5efa93e50904d33c88808d0e169060508df840992e31f4d0a04041e76310c658102ffff8a0101820407e30b0d830b54414e47454d2053444b00840743415244414e4f8640f24ef5c8c6eba0ff97560d5b013edb4a452594270db9647bd0a3543df8104dec75731d4db3ebe0fc493f2afee00195e560b51e3c41189b7c61ba7895d6434b9d3041045f16bd1d2eafe463e62a335a09e6b2bbcbd04452526885cb679fc4d27af1bd22f553c7deefb54fd3d4f361d14e6dc3f11b7d4ea183250a60720ebdf9e110cd2605086564323535313900080400000064070100090205dc60208a71161cfdf1e0a85d8e7ff372aa4a01136046292aceb5f9ad7ebdb98d3f60a86204000000646304000000000f01009000"
val responseApdu = ResponseApdu(data.hexToBytes())
- val card = ReadCommand().deserialize(SessionEnvironment(), responseApdu)
+ val card = ReadCommand().deserialize(sessionEnvironment, responseApdu)
val walletManager = WalletManagerFactory.makeWalletManager(card)
Truth.assertThat(walletManager)
@@ -66,7 +69,7 @@ internal class WalletManagerFactoryTest {
fun createXrpWalletManager() {
val data = "0108cb21000000002154200b534d4152542043415348000201028006322e31317200034104bdad63848f97c535da53cf8fd300d24fa33f0516d194aa78ec164a06994d00204bae243a424e316c6ec845e02d9b15eafae8c19018a926b0b7435e6e941cdadb0a0400007e210c5a81020028820407e30502830754414e47454d00840358525086400ed8734b877869722c7d0b37ffb154b9fef21c54bf2c6496feb1fb5c1fc28a2ac28e201dde84f27495fa7f08b3ca2be2fb4954bf0fe78af027d6cdc16c3eee923041048196aa4b410ac44a3b9cce18e7be226aea070acc83a9cf67540fac49af25129f6a538a28ad6341358e3c4f9963064f7e365372a651d374e5c23cdd37fd099bf2050a736563703235366b31000804000f4240070100090205dc604104d2b9fb288540d54e5b32ecaf0381cd571f97f6f1ecd036b66bb11aa52ffe9981110d883080e2e255c6b1640586f7765e6faa325d1340f49b56b83d9de56bc7ed6204000f42406304000000000f01009000"
val responseApdu = ResponseApdu(data.hexToBytes())
- val card = ReadCommand().deserialize(SessionEnvironment(), responseApdu)
+ val card = ReadCommand().deserialize(sessionEnvironment, responseApdu)
val walletManager = WalletManagerFactory.makeWalletManager(card)
Truth.assertThat(walletManager)
@@ -77,7 +80,7 @@ internal class WalletManagerFactoryTest {
fun createBinanceWalletManager() {
val data = "0108BB00000000000015200754414E47454D00020102800A322E3432642053444B0003410446D4155890B08BE217F0B1FA7DCCB16138C24B3E825A27315D5E4BBD6CAF76A28C7902007052BC1347355A78D54BD73216C9431D555CED827B54FD9255EB3A830A04041E76310C658102FFFF8A0101820407E40410830B54414E47454D2053444B00840742494E414E4345864029F115878EDC7B0CB2A6F4A4009447DCB43BBE922D7629AEBD0C9A910AD1E3BF15AE409C4F579700951ED2FE4D775171A86CFA8E50009A05938CE210D6D4A2583041045F16BD1D2EAFE463E62A335A09E6B2BBCBD04452526885CB679FC4D27AF1BD22F553C7DEEFB54FD3D4F361D14E6DC3F11B7D4EA183250A60720EBDF9E110CD26050A736563703235366B31000804000186A0070100604104E3F3BE3CE3D8284DB3BA073AD0291040093D83C11A277B905D5555C9EC41073E103F4D9D299EDEA8285C51C3356A8681A545618C174251B984DF841F49D2376F62040001869F6304000000010F01009000"
val responseApdu = ResponseApdu(data.hexToBytes())
- val card = ReadCommand().deserialize(SessionEnvironment(), responseApdu)
+ val card = ReadCommand().deserialize(sessionEnvironment, responseApdu)
val walletManager = WalletManagerFactory.makeWalletManager(card)
Truth.assertThat(walletManager)
@@ -88,7 +91,7 @@ internal class WalletManagerFactoryTest {
fun createBitcoinCashWalletManager() {
val data = "0108BB00000000000049200754414E47454D00020102800A322E3432642053444B00034104766A1586D164B436E5D420AED01FDAB41B2AE7EDF0C865D7AF1DA995D70AB297E5B94B761CFBB405084C21BC97C02B4A1EA9ED4F515576EAB4D83AD3A0DFAA8A0A04041E76310C618102FFFF8A0101820407E4041B830B54414E47454D2053444B00840342434886408058F0F628C2466B09ECEB13F2A8EFDD4558F5D2DBDA9BD0628EE8C8CC99A778FF0F1AECD35704B9F3518486EA5C1D20F9DFCBAA66184F4CCCD9282E2632882C3041045F16BD1D2EAFE463E62A335A09E6B2BBCBD04452526885CB679FC4D27AF1BD22F553C7DEEFB54FD3D4F361D14E6DC3F11B7D4EA183250A60720EBDF9E110CD26050A736563703235366B31000804000186A0070100604104BE37CD5251C8999EDBBFC759D800EB41E4DCB718289601EB15819404E1B2F2ED90FE50C2A481D06EC790D1EF6184974EB655ABAE4BE56A6D1C9E1A17B1EFDF0262040001869A6304000000060F01009000"
val responseApdu = ResponseApdu(data.hexToBytes())
- val card = ReadCommand().deserialize(SessionEnvironment(), responseApdu)
+ val card = ReadCommand().deserialize(sessionEnvironment, responseApdu)
val walletManager = WalletManagerFactory.makeWalletManager(card)
Truth.assertThat(walletManager)
@@ -99,7 +102,7 @@ internal class WalletManagerFactoryTest {
fun createLitecoinWalletManager() {
val data = "0108BB00000000000023200754414E47454D00020102800A322E3432642053444B000341043539F86A40ADD04CE165764A761FD3E4D251028615D2A573B1C3AE652E60AFDBFAF02E3239E89EF2C43FA448A327557ADC5AF36376A0574570F6DBD20113514A0A04041E76310C618102FFFF8A0101820407E40414830B54414E47454D2053444B0084034C5443864004BDEAD0117544886346CB47F7CA84ABA8C34239502F23D28595A4B16CAD72F7DE506BA818B86A649C2BB945986D4574993B3B755B47CBEE31C4FB931F6748183041045F16BD1D2EAFE463E62A335A09E6B2BBCBD04452526885CB679FC4D27AF1BD22F553C7DEEFB54FD3D4F361D14E6DC3F11B7D4EA183250A60720EBDF9E110CD26050A736563703235366B31000804000186A00701006041044A76C9A70422160F515F956D0F50C71BBBA4F9862A22913817D63F0B1EF7C2FAF512E1C91B1BE827560EFE24FB1652B47337E296C778DFB1014D080CDD35EF6562040001869D6304000000030F01009000"
val responseApdu = ResponseApdu(data.hexToBytes())
- val card = ReadCommand().deserialize(SessionEnvironment(), responseApdu)
+ val card = ReadCommand().deserialize(sessionEnvironment, responseApdu)
val walletManager = WalletManagerFactory.makeWalletManager(card)
Truth.assertThat(walletManager)
@@ -107,13 +110,24 @@ internal class WalletManagerFactoryTest {
}
@Test
- fun createLTezosWalletManager() {
+ fun createTezosWalletManager() {
val data = "0108BB00000000000080200754414E47454D00020102800A322E3432642053444B0003410436CFC5D0A11353AE6AFEEDC84A2D02B2635C044DEEE47F99913072B8D166D14E557230AC5FB5272F1A0E523332CCE1A744B51DB53102FF7D3FDE023DC3477C460A04041E76310C638102FFFF8A0101820407E40514830B54414E47454D2053444B00840554455A4F538640C752685B29333CFB0DB0A7347579A0AE763F2B5C4BB09FD68E0B81A06CD01EC51347001732815A3ECFFCD78DDE4E53877581B9E4914B069570629D0C40A771B93041045F16BD1D2EAFE463E62A335A09E6B2BBCBD04452526885CB679FC4D27AF1BD22F553C7DEEFB54FD3D4F361D14E6DC3F11B7D4EA183250A60720EBDF9E110CD26050865643235353139000804000186A0070100602098E0E504F3A5FDE704400302ABB0A2EFB0DF0F95C166C91D7F207DEDCE10CBA362040001869F6304000000010F01009000"
val responseApdu = ResponseApdu(data.hexToBytes())
- val card = ReadCommand().deserialize(SessionEnvironment(), responseApdu)
+ val card = ReadCommand().deserialize(sessionEnvironment, responseApdu)
val walletManager = WalletManagerFactory.makeWalletManager(card)
Truth.assertThat(walletManager)
.isInstanceOf(TezosWalletManager::class.java)
}
+
+ @Test
+ fun createDucatusWalletManager() {
+ val data = "0108BB00000000000098200754414E47454D00020102800A322E3432642053444B000341041B5FD7C590938E836B388B996AE451FDED54F625FF2CF05E26E5AADF6F690AEF125E3D0F23CB6B8D1F78040DF6F71B40D098F2D8BE504DDEE2E1F99BEADD90500A04041E76310C618102FFFF8A0101820407E40515830B54414E47454D2053444B00840344554386401B453C10A092A3448FA83CAFD4FC3D7EB5EA1BBBDD6A020CAAC8CED36BB2661F41EF0B0C7418214F670DFE1200DCE18597158119BEF6CC52A4FF3B7E021A53B93041045F16BD1D2EAFE463E62A335A09E6B2BBCBD04452526885CB679FC4D27AF1BD22F553C7DEEFB54FD3D4F361D14E6DC3F11B7D4EA183250A60720EBDF9E110CD26050A736563703235366B31000804000186A007010060410485D520C8B907F0BC5E03FCBBAC212CCD270764BBFF4990A28653A2FB0D656C342DF143C4D52C43582289E20A81D5D014C1384A1FFFEA1D121903AD7ED35A01EA62040001869D6304000000030F01009000"
+ val responseApdu = ResponseApdu(data.hexToBytes())
+ val card = ReadCommand().deserialize(sessionEnvironment, responseApdu)
+ val walletManager = WalletManagerFactory.makeWalletManager(card)
+
+ Truth.assertThat(walletManager)
+ .isInstanceOf(DucatusWalletManager::class.java)
+ }
}
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 40bc31028b..f1609ce70f 100644
--- a/build.gradle
+++ b/build.gradle
@@ -11,8 +11,9 @@ buildscript {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$versions.kotlin"
classpath "com.github.dcendents:android-maven-gradle-plugin:2.1"
classpath 'com.google.gms:google-services:4.3.3'
- classpath 'com.google.firebase:firebase-crashlytics-gradle:2.0.0-beta04'
+ classpath 'com.google.firebase:firebase-crashlytics-gradle:2.2.0'
classpath 'com.google.firebase:perf-plugin:1.3.1'
+ classpath 'com.squareup.sqldelight:gradle-plugin:1.4.0'
}
}
@@ -21,6 +22,7 @@ allprojects {
google()
jcenter()
maven { url 'https://jitpack.io' }
+ maven { url "https://api.bitbucket.org/2.0/repositories/tangem/maven_repository/src/releases" }
}
}
diff --git a/dependencies.gradle b/dependencies.gradle
index f61f047e5a..f451e17141 100644
--- a/dependencies.gradle
+++ b/dependencies.gradle
@@ -1,4 +1,4 @@
ext.versions = [
kotlin : '1.3.72',
- build_gradle: '4.0.0',
+ build_gradle: '4.0.1',
]
diff --git a/server-android/src/main/java/com/tangem/server_android/data/LocalStorage.kt b/server-android/src/main/java/com/tangem/server_android/data/LocalStorage.kt
index ed9371767b..a858e25318 100644
--- a/server-android/src/main/java/com/tangem/server_android/data/LocalStorage.kt
+++ b/server-android/src/main/java/com/tangem/server_android/data/LocalStorage.kt
@@ -47,7 +47,7 @@ class LocalStorage
artworks = HashMap()
}
- if (artworks.count() < 44) {
+ if (artworks.count() < 45) {
// forceSave=true only on the last one
putResourceArtworkToCatalog(R.drawable.card_default, false)
putResourceArtworkToCatalog(R.drawable.card_default_nft, false)
@@ -90,6 +90,7 @@ class LocalStorage
putResourceArtworkToCatalog(R.drawable.card_tg061, false)
putResourceArtworkToCatalog(R.drawable.card_tg062, false)
putResourceArtworkToCatalog(R.drawable.card_tg063, false)
+ putResourceArtworkToCatalog(R.drawable.card_tg073, false)
putResourceArtworkToCatalog(R.drawable.card_tgslix, false)
putResourceArtworkToCatalog(R.drawable.card_bc00, false)
putResourceArtworkToCatalog(R.drawable.card_ff32, true)
@@ -305,6 +306,7 @@ class LocalStorage
card.batch == "0050" -> R.drawable.card_tg061
card.batch == "0051" -> R.drawable.card_tg062
card.batch == "0052" -> R.drawable.card_tg063
+ card.batch == "0060" -> R.drawable.card_tg073
card.batch == "FF32" -> R.drawable.card_ff32
else -> null
diff --git a/server-android/src/main/res/drawable/card_tg073.png b/server-android/src/main/res/drawable/card_tg073.png
new file mode 100644
index 0000000000..205f99d631
Binary files /dev/null and b/server-android/src/main/res/drawable/card_tg073.png differ
diff --git a/settings.gradle b/settings.gradle
index 9a87107347..239e3ea7e9 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1 @@
-include ':app', ':tangem-sdk-old', ':server-android', ':tangem-card-old', ':tangem-core', ':tangem-sdk', ':tangem-devkit', ':blockchain', ':blockchain-demo'
\ No newline at end of file
+include ':app', ':tangem-sdk-old', ':server-android', ':tangem-card-old', ':blockchain', ':blockchain-demo'
\ No newline at end of file
diff --git a/tangem-core/.gitignore b/tangem-core/.gitignore
deleted file mode 100644
index 796b96d1c4..0000000000
--- a/tangem-core/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/build
diff --git a/tangem-core/build.gradle b/tangem-core/build.gradle
deleted file mode 100644
index 220c949038..0000000000
--- a/tangem-core/build.gradle
+++ /dev/null
@@ -1,59 +0,0 @@
-apply plugin: "kotlin"
-apply plugin: 'org.jetbrains.dokka'
-apply plugin: 'com.github.dcendents.android-maven'
-apply from: '../dependencies.gradle'
-apply from: '../jitpack.gradle'
-
-group = "$jitpackSdk.group"
-version "$jitpackSdk.version"
-
-dependencies {
- // kotlin
- implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$versions.kotlin"
- implementation "org.jetbrains.kotlin:kotlin-reflect:$versions.kotlin"
-
- // crypto
- implementation "com.madgag.spongycastle:core:1.58.0.0"
- implementation "com.madgag.spongycastle:prov:1.58.0.0"
- implementation 'net.i2p.crypto:eddsa:0.3.0'
-
- // misc
- implementation 'com.google.code.gson:gson:2.8.6'
-
- // tests
- testImplementation 'org.junit.jupiter:junit-jupiter-api:5.5.2'
- testImplementation "com.google.truth:truth:1.0"
-}
-
-sourceCompatibility = "8"
-targetCompatibility = "8"
-
-buildscript {
- ext.dokka_version = '0.10.0'
- repositories {
- mavenCentral()
- jcenter()
- }
- dependencies {
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$versions.kotlin"
- classpath "org.jetbrains.dokka:dokka-gradle-plugin:$dokka_version"
- }
-}
-repositories {
- mavenCentral()
- jcenter()
-}
-compileKotlin {
- kotlinOptions {
- jvmTarget = "1.8"
- }
-}
-compileTestKotlin {
- kotlinOptions {
- jvmTarget = "1.8"
- }
-}
-
-task dokkaJavadoc(type: org.jetbrains.dokka.gradle.DokkaTask) {
- outputFormat = 'markdown'
-}
diff --git a/tangem-core/src/main/java/com/tangem/CardFilter.kt b/tangem-core/src/main/java/com/tangem/CardFilter.kt
deleted file mode 100644
index d1275d1d1d..0000000000
--- a/tangem-core/src/main/java/com/tangem/CardFilter.kt
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.tangem
-
-import com.tangem.common.extensions.CardType
-import java.util.*
-
-/**
- * Filter that can be used to limit cards that can be interacted with in TangemSdk.
- *
- * @property allowedCardTypes Type of cards that are allowed to be interacted with in TangemSdk.
- */
-data class CardFilter(
-
- var allowedCardTypes: EnumSet = EnumSet.allOf(CardType::class.java)
-)
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/CardReader.kt b/tangem-core/src/main/java/com/tangem/CardReader.kt
deleted file mode 100644
index 2327e13fe6..0000000000
--- a/tangem-core/src/main/java/com/tangem/CardReader.kt
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.tangem
-
-import com.tangem.common.CompletionResult
-import com.tangem.common.apdu.CommandApdu
-import com.tangem.common.apdu.ResponseApdu
-
-/**
- * Allows interaction between the phone or any other terminal and Tangem card.
- *
- * Its default implementation, NfcCardReader, is in our tangem-sdk module.
- */
-interface CardReader {
-
- /**
- * Sends data to the card and receives the reply.
- *
- * @param apdu Data to be sent. [CommandApdu] serializes it to a [ByteArray]
- * @param callback Returns response from the card,
- * [ResponseApdu] Allows to convert raw data to [Tlv]
- */
- fun transceiveApdu(apdu: CommandApdu, callback: (response: CompletionResult) -> Unit)
-
- /**
- * Signals to [CardReader] to become ready to transceive data.
- */
- fun openSession()
-
- /**
- * Signals to [CardReader] that no further NFC transition is expected.
- */
- fun closeSession()
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/CardSession.kt b/tangem-core/src/main/java/com/tangem/CardSession.kt
deleted file mode 100644
index c7fa4559e7..0000000000
--- a/tangem-core/src/main/java/com/tangem/CardSession.kt
+++ /dev/null
@@ -1,260 +0,0 @@
-package com.tangem
-
-import com.tangem.commands.Card
-import com.tangem.commands.CommandResponse
-import com.tangem.commands.OpenSessionCommand
-import com.tangem.commands.ReadCommand
-import com.tangem.common.CompletionResult
-import com.tangem.common.apdu.CommandApdu
-import com.tangem.common.apdu.ResponseApdu
-import com.tangem.common.extensions.calculateSha256
-import com.tangem.common.extensions.getType
-import com.tangem.crypto.EncryptionHelper
-import com.tangem.crypto.FastEncryptionHelper
-import com.tangem.crypto.StrongEncryptionHelper
-import com.tangem.crypto.pbkdf2Hash
-
-/**
- * Basic interface for running tasks and [com.tangem.commands.Command] in a [CardSession]
- */
-interface CardSessionRunnable {
-
- val performPreflightRead: Boolean
-
- /**
- * The starting point for custom business logic.
- * Implement this interface and use [TangemSdk.startSessionWithRunnable] to run.
- * @param session run commands in this [CardSession].
- * @param callback trigger the callback to complete the task.
- */
- fun run(session: CardSession, callback: (result: CompletionResult) -> Unit)
-}
-
-/**
- * Allows interaction with Tangem cards. Should be opened before sending commands.
- *
- * @property environment
- * @property reader is an interface that is responsible for NFC connection and
- * transfer of data to and from the Tangem Card.
- * @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.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.
- */
-class CardSession(
- val environment: SessionEnvironment,
- private val reader: CardReader,
- val viewDelegate: SessionViewDelegate,
- private var cardId: String? = null,
- private val initialMessage: Message? = null
-) {
-
- private val tag = this.javaClass.simpleName
- /**
- * True if some operation is still in progress.
- */
- private var isBusy = false
-
- private var performPreflightRead = true
-
- /**
- * This metod starts a card session, performs preflight [ReadCommand],
- * invokes [CardSessionRunnable.run] and closes the session.
- * @param runnable [CardSessionRunnable] that will be performed in the session.
- * @param callback will be triggered with a [CompletionResult] of a session.
- */
- fun , R : CommandResponse> startWithRunnable(
- runnable: T, callback: (result: CompletionResult) -> Unit) {
-
- performPreflightRead = runnable.performPreflightRead
-
- start { session, error ->
- if (error != null) {
- callback(CompletionResult.Failure(error))
- return@start
- }
- if (runnable is ReadCommand) {
- callback(CompletionResult.Success(environment.card as R))
- return@start
- }
-
- runnable.run(this) { result ->
- when (result) {
- is CompletionResult.Success -> stop()
- is CompletionResult.Failure -> {
- if (result.error is TangemSdkError.ExtendedLengthNotSupported) {
- if (session.environment.terminalKeys != null) {
- session.environment.terminalKeys = null
- startWithRunnable(runnable, callback)
- return@run
- }
- }
- stopWithError(result.error)
- }
- }
- callback(result)
- }
- }
- }
-
- /**
- * Starts a card session and performs preflight [ReadCommand].
- * @param callback: callback with the card session. Can contain [TangemSdkError] if something goes wrong.
- */
- fun start(callback: (session: CardSession, error: TangemSdkError?) -> Unit) {
- try {
- startSession()
- } catch (error: TangemSdkError) {
- callback(this, error)
- }
-
- if (!performPreflightRead) {
- callback(this, null)
- return
- }
-
- preflightRead() { result ->
- when (result) {
- is CompletionResult.Failure -> {
- callback(this, result.error)
- stopWithError(result.error)
- }
- is CompletionResult.Success -> {
- callback(this, null)
- }
- }
- }
- }
-
- private fun startSession() {
- if (isBusy) throw TangemSdkError.Busy()
- isBusy = true
- viewDelegate.onNfcSessionStarted(cardId, initialMessage)
- reader.openSession()
- }
-
- private fun preflightRead(callback: (result: CompletionResult) -> Unit) {
- val readCommand = ReadCommand()
- readCommand.run(this) { result ->
- when (result) {
- is CompletionResult.Failure -> {
- tryHandleError(result.error) { handleErrorResult ->
- when (handleErrorResult) {
- is CompletionResult.Success -> preflightRead(callback)
- is CompletionResult.Failure -> {
- stopWithError(result.error)
- callback(CompletionResult.Failure(result.error))
- }
- }
- }
- }
- is CompletionResult.Success -> {
- val receivedCardId = result.data.cardId
- if (cardId != null && receivedCardId != cardId) {
- stopWithError(TangemSdkError.WrongCardNumber())
- callback(CompletionResult.Failure(TangemSdkError.WrongCardNumber()))
- return@run
- }
- val allowedCardTypes = environment.cardFilter.allowedCardTypes
- if (!allowedCardTypes.contains(result.data.getType())) {
- stopWithError(TangemSdkError.WrongCardType())
- callback(CompletionResult.Failure(TangemSdkError.WrongCardType()))
- return@run
- }
- environment.card = result.data
- cardId = receivedCardId
- callback(CompletionResult.Success(result.data))
- }
- }
- }
- }
-
- /**
- * Stops the current session with the text message.
- * @param message If null, the default message will be shown.
- */
- private fun stop(message: Message? = null) {
- reader.closeSession()
- viewDelegate.onNfcSessionCompleted(message)
- isBusy = false
- }
-
- /**
- * Stops the current session on error.
- * @param error An error that will be shown.
- */
- private fun stopWithError(error: TangemSdkError) {
- if (!isBusy) return
-
- reader.closeSession()
- isBusy = false
-
- val errorMessage = if (error is TangemSdkError) {
- "${error::class.simpleName}: ${error.code}"
- } else {
- error.localizedMessage
- }
- if (error !is TangemSdkError.UserCancelled) {
- Log.e(tag, "Finishing with error: $errorMessage")
- viewDelegate.onError(error)
- } else {
- Log.i(tag, "User cancelled NFC session")
- }
-
- }
-
- fun send(apdu: CommandApdu, callback: (result: CompletionResult) -> Unit) {
- reader.transceiveApdu(apdu, callback)
- }
-
- private fun tryHandleError(
- error: TangemSdkError, callback: (result: CompletionResult) -> Unit) {
-
- when (error) {
- is TangemSdkError.NeedEncryption -> {
- Log.i(tag, "Establishing encryption")
- when (environment.encryptionMode) {
- EncryptionMode.NONE -> {
- environment.encryptionKey = null
- environment.encryptionMode = EncryptionMode.FAST
- }
- EncryptionMode.FAST -> {
- environment.encryptionKey = null
- environment.encryptionMode = EncryptionMode.STRONG
- }
- EncryptionMode.STRONG -> {
- Log.e(tag, "Encryption doesn't work")
- callback(CompletionResult.Failure(TangemSdkError.NeedEncryption()))
- }
- }
- return establishEncryption(callback)
- }
- else -> callback(CompletionResult.Failure(TangemSdkError.UnknownError()))
- }
- }
-
- private fun establishEncryption(callback: (result: CompletionResult) -> Unit) {
- val encryptionHelper: EncryptionHelper =
- if (environment.encryptionMode == EncryptionMode.STRONG) {
- StrongEncryptionHelper()
- } else {
- FastEncryptionHelper()
- }
- val openSesssionCommand = OpenSessionCommand(encryptionHelper.keyA)
- openSesssionCommand.run(this) { result ->
- when (result) {
- is CompletionResult.Success -> {
- val uid = result.data.uid
- val protocolKey = environment.pin1.pbkdf2Hash(uid, 50)
- val secret = encryptionHelper.generateSecret(result.data.sessionKeyB)
- val sessionKey = (secret + protocolKey).calculateSha256()
- environment.encryptionKey = sessionKey
- callback(CompletionResult.Success(true))
- }
- is CompletionResult.Failure -> callback(CompletionResult.Failure(result.error))
- }
- }
- }
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/Config.kt b/tangem-core/src/main/java/com/tangem/Config.kt
deleted file mode 100644
index 45da4b6912..0000000000
--- a/tangem-core/src/main/java/com/tangem/Config.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.tangem
-
-class Config(
- /**
- * Enables or disables Linked Terminal feature.
-
- App can optionally generate ECDSA key pair Terminal_PrivateKey / Terminal_PublicKey.
- And then submit Terminal_PublicKey to the card in any SIGN command.
- Once SIGN is successfully executed by COS (Card Operation System),
- including PIN2 verification and/or completion of security delay, the submitted
- Terminal_PublicKey key is stored by COS. After that, the App instance is deemed trusted
- by COS and COS will allow skipping security delay for subsequent SIGN operations
- thus improving convenience without sacrificing security.
-
- In order to skip security delay, App should use Terminal_PrivateKey to compute the signature
- of the data being submitted to SIGN command for signing and transmit this signature in
- Terminal_Transaction_Signature parameter in the same SIGN command. COS will verify
- the correctness of Terminal_Transaction_Signature using previously stored Terminal_PublicKey
- and, if correct, will skip security delay for the current SIGN operation.
- */
- var linkedTerminal: Boolean = true,
-
- /**
- * If not null, it will be used to validate Issuer data and issuer extra data.
- * If null, issuerPublicKey from current card will be used.
- */
- var issuerPublicKey: ByteArray? = null,
-
- /**
- * Level of encryption used in communication with a Tangem Card.
- */
- var encryptionMode: EncryptionMode = EncryptionMode.NONE,
-
- /**
- * Filter that can be used to limit cards that can be interacted with in TangemSdk.
- */
- val cardFilter: CardFilter = CardFilter(),
-
- var handleErrors: Boolean = true
-
-)
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/Log.kt b/tangem-core/src/main/java/com/tangem/Log.kt
deleted file mode 100644
index b03303b1a5..0000000000
--- a/tangem-core/src/main/java/com/tangem/Log.kt
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.tangem
-
-object Log {
-
- private var loggerInstance: LoggerInterface? = null
-
- fun i(logTag: String, message: String) {
- loggerInstance?.i(logTag, message)
- }
-
- fun e(logTag: String, message: String) {
- loggerInstance?.e(logTag, message)
- }
-
- fun v(logTag: String, message: String) {
-
- loggerInstance?.v(logTag, message)
- }
-
- fun setLogger(logger: LoggerInterface) {
- loggerInstance = logger
- }
-}
-
-/**
- * Interface for logging events within the SDK.
- *
- * It allows to use Android logger or to choose another.
- */
-interface LoggerInterface {
- fun i(logTag: String, message: String)
- fun e(logTag: String, message: String)
- fun v(logTag: String, message: String)
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/SessionEnvironment.kt b/tangem-core/src/main/java/com/tangem/SessionEnvironment.kt
deleted file mode 100644
index 5f8734f685..0000000000
--- a/tangem-core/src/main/java/com/tangem/SessionEnvironment.kt
+++ /dev/null
@@ -1,55 +0,0 @@
-package com.tangem
-
-import com.tangem.commands.Card
-import com.tangem.commands.EllipticCurve
-import com.tangem.common.extensions.calculateSha256
-import com.tangem.crypto.CryptoUtils.generatePublicKey
-
-
-/**
- * Contains data relating to a Tangem card. It is used in constructing all the commands,
- * and commands can return modified [SessionEnvironment].
- *
- * @property card Current card, read by preflight [com.tangem.commands.ReadCommand].
- * @property terminalKeys generated terminal keys used in Linked Terminal feature.
- */
-data class SessionEnvironment(
- var pin1: ByteArray = DEFAULT_PIN.calculateSha256(),
- var pin2: ByteArray = DEFAULT_PIN2.calculateSha256(),
- var card: Card? = null,
- var terminalKeys: KeyPair? = null,
- var encryptionMode: EncryptionMode = EncryptionMode.NONE,
- var encryptionKey: ByteArray? = null,
- var cvc: ByteArray? = null,
- var cardFilter: CardFilter = CardFilter(),
- val handleErrors: Boolean = true
-) {
-
- fun setPin1(pin1: String) {
- this.pin1 = pin1.calculateSha256()
- }
-
- fun setPin2(pin2: String) {
- this.pin2 = pin2.calculateSha256()
- }
-
- companion object {
- const val DEFAULT_PIN = "000000"
- const val DEFAULT_PIN2 = "000"
- }
-}
-
-/**
- * All possible encryption modes.
- */
-enum class EncryptionMode(val code: Byte) {
- NONE(0x0),
- FAST(0x1),
- STRONG(0x2)
-}
-
-class KeyPair(val publicKey: ByteArray, val privateKey: ByteArray) {
-
- constructor(privateKey: ByteArray, curve: EllipticCurve = EllipticCurve.Secp256k1) :
- this(generatePublicKey(privateKey, curve), privateKey)
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/SessionViewDelegate.kt b/tangem-core/src/main/java/com/tangem/SessionViewDelegate.kt
deleted file mode 100644
index 969b147b8f..0000000000
--- a/tangem-core/src/main/java/com/tangem/SessionViewDelegate.kt
+++ /dev/null
@@ -1,55 +0,0 @@
-package com.tangem
-
-import com.tangem.common.CompletionResult
-
-/**
- * Allows interaction with users and shows visual elements.
- *
- * Its default implementation, DefaultCardManagerDelegate, is in our tangem-sdk module.
- */
-interface SessionViewDelegate {
-
- /**
- * It is called when user is expected to scan a Tangem Card with an Android device.
- */
- fun onNfcSessionStarted(cardId: String?, message: Message? = null)
-
- /**
- * It is called when security delay is triggered by the card.
- * A user is expected to hold the card until the security delay is over.
- */
- fun onSecurityDelay(ms: Int, totalDurationSeconds: Int)
-
- /**
- * It is called when long tasks are performed.
- * A user is expected to hold the card until the task is complete.
- */
- fun onDelay(total: Int, current: Int, step: Int)
-
- /**
- * It is called when user takes the card away from the Android device during the scanning
- * (for example when security delay is in progress) and the TagLostException is received.
- */
- fun onTagLost()
-
- /**
- * It is called when NFC session was completed and a user can take the card away from the Android device.
- */
- fun onNfcSessionCompleted(message: Message? = null)
-
- /**
- * It is called when some error occur during NFC session.
- */
- fun onError(error: TangemSdkError)
-
- /**
- * It is called when a user is expected to enter pin code.
- */
- fun onPinRequested(callback: (result: CompletionResult) -> Unit)
-
-}
-
-/**
- * Wrapper for a message that can be shown to user after a start of NFC session.
- */
-data class Message(val header: String? = null, val body: String? = null)
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/TangemSdk.kt b/tangem-core/src/main/java/com/tangem/TangemSdk.kt
deleted file mode 100644
index dc8f8dbe06..0000000000
--- a/tangem-core/src/main/java/com/tangem/TangemSdk.kt
+++ /dev/null
@@ -1,398 +0,0 @@
-package com.tangem
-
-import com.tangem.commands.*
-import com.tangem.commands.personalization.DepersonalizeCommand
-import com.tangem.commands.personalization.DepersonalizeResponse
-import com.tangem.commands.personalization.PersonalizeCommand
-import com.tangem.commands.personalization.entities.Acquirer
-import com.tangem.commands.personalization.entities.CardConfig
-import com.tangem.commands.personalization.entities.Issuer
-import com.tangem.commands.personalization.entities.Manufacturer
-import com.tangem.common.CompletionResult
-import com.tangem.common.TerminalKeysService
-import com.tangem.crypto.CryptoUtils
-import com.tangem.tasks.CreateWalletTask
-import com.tangem.tasks.ScanTask
-
-/**
- * The main interface of Tangem SDK that allows your app to communicate with Tangem cards.
- *
- * @property reader is an interface that is responsible for NFC connection and
- * transfer of data to and from the Tangem Card.
- * Its default implementation, NfcCardReader, is in our tangem-sdk module.
- * @property viewDelegate An interface that allows interaction with users and shows relevant UI.
- * Its default implementation, DefaultCardSessionViewDelegate, is in our tangem-sdk module.
- * @property config allows to change a number of parameters for communication with Tangem cards.
- * Do not change the default values unless you know what you are doing.
- */
-class TangemSdk(
- private val reader: CardReader,
- private val viewDelegate: SessionViewDelegate,
- var config: Config = Config()
-) {
-
- private var terminalKeysService: TerminalKeysService? = null
-
- init {
- CryptoUtils.initCrypto()
- }
-
- /**
- * This method launches a [ScanTask] on a new thread.
- *
- * To start using any card, you first need to read it using the scanCard() method.
- * This method launches an NFC session, and once it’s connected with the card,
- * it obtains the card data. Optionally, if the card contains a wallet (private and public key pair),
- * it proves that the wallet owns a private key that corresponds to a public one.
- *
- * @param callback is triggered on the completion of the [ScanTask] and provides card response
- * in the form of [Card] if the task was performed successfully or [TangemSdkError] in case of an error.
- */
- fun scanCard(initialMessage: Message? = null, callback: (result: CompletionResult) -> Unit) {
- startSessionWithRunnable(ScanTask(), null, initialMessage, callback)
- }
-
- /**
- * This method launches a [SignCommand] on a new thread.
- *
- * It allows you to sign one or multiple hashes.
- * Simultaneous signing of array of hashes in a single [SignCommand] is required to support
- * Bitcoin-type multi-input blockchains (UTXO).
- * The [SignCommand] will return a corresponding array of signatures.
- *
- * Please note that Tangem cards usually protect the signing with a security delay
- * that may last up to 90 seconds, depending on a card.
- * It is for [SessionViewDelegate] to notify users of security delay.
- *
- * @param hashes Array of transaction hashes. It can be from one or up to ten hashes of the same length.
- * @param cardId CID, Unique Tangem card ID number
- * @param callback is triggered on the completion of the [SignCommand] and provides card response
- * in the form of [SignResponse] if the task was performed successfully
- * or [TangemSdkError] in case of an error.
- */
- fun sign(hashes: Array, cardId: String? = null, initialMessage: Message? = null,
- callback: (result: CompletionResult) -> Unit) {
- startSessionWithRunnable(SignCommand(hashes), cardId, initialMessage, callback)
- }
-
- /**
- * This method launches a [ReadIssuerDataCommand] on a new thread.
-
- * This command returns 512-byte Issuer Data field and its issuer’s signature.
- * Issuer Data is never changed or parsed from within the Tangem COS. The issuer defines purpose of use,
- * format and payload of Issuer Data. For example, this field may contain information about
- * wallet balance signed by the issuer or additional issuer’s attestation data.
- *
- * @param cardId CID, Unique Tangem card ID number.
- * @param callback is triggered on the completion of the [ReadIssuerDataCommand] and provides
- * card response in the form of [ReadIssuerDataResponse] if the task was performed successfully
- * or [TangemSdkError] in case of an error.
- */
- fun readIssuerData(cardId: String? = null, initialMessage: Message? = null,
- callback: (result: CompletionResult) -> Unit) {
- startSessionWithRunnable(ReadIssuerDataCommand(config.issuerPublicKey), cardId, initialMessage, callback)
- }
-
- /**
- * This method launches a [ReadIssuerExtraDataCommand] on a new thread.
- *
- * This command retrieves Issuer Extra Data field and its issuer’s signature.
- * Issuer Extra Data is never changed or parsed from within the Tangem COS. The issuer defines purpose of use,
- * format and payload of Issuer Data. . For example, this field may contain photo or
- * biometric information for ID card product. Because of the large size of Issuer_Extra_Data,
- * a series of these commands have to be executed to read the entire Issuer_Extra_Data.
- *
- * @param cardId CID, Unique Tangem card ID number.
- * @param callback is triggered on the completion of the [ReadIssuerExtraDataCommand] and provides
- * card response in the form of [ReadIssuerExtraDataResponse] if the task was performed successfully
- * or [TangemSdkError] in case of an error.
- */
- fun readIssuerExtraData(cardId: String? = null,
- callback: (result: CompletionResult) -> Unit) {
- startSessionWithRunnable(ReadIssuerExtraDataCommand(config.issuerPublicKey), cardId, null, callback)
- }
-
- /**
- * This method launches a [WriteIssuerDataCommand] on a new thread.
- *
- * This command writes 512-byte Issuer Data field and its issuer’s signature.
- * Issuer Data is never changed or parsed from within the Tangem COS. The issuer defines purpose of use,
- * format and payload of Issuer Data. For example, this field may contain information about
- * wallet balance signed by the issuer or additional issuer’s attestation data.
- *
- * @param cardId CID, Unique Tangem card ID number.
- * @param issuerData Data provided by issuer.
- * @param issuerDataSignature Issuer’s signature of [issuerData] with Issuer Data Private Key.
- * @param issuerDataCounter An optional counter that protect issuer data against replay attack.
- * @param callback is triggered on the completion of the [WriteIssuerDataCommand] and provides
- * card response in the form of [WriteIssuerDataResponse] if the task was performed successfully
- * or [TangemSdkError] in case of an error.
- */
- fun writeIssuerData(cardId: String? = null,
- issuerData: ByteArray,
- issuerDataSignature: ByteArray,
- issuerDataCounter: Int? = null,
- initialMessage: Message? = null,
- callback: (result: CompletionResult) -> Unit) {
- val command = WriteIssuerDataCommand(
- issuerData,
- issuerDataSignature,
- issuerDataCounter,
- config.issuerPublicKey
- )
- startSessionWithRunnable(command, cardId, initialMessage, callback)
- }
-
- /**
- * This method launches a [WriteIssuerExtraDataCommand] on a new thread.
- *
- * This command writes Issuer Extra Data field and its issuer’s signature.
- * Issuer Extra Data is never changed or parsed from within the Tangem COS.
- * The issuer defines purpose of use, format and payload of Issuer Data.
- * For example, this field may contain a photo or biometric information for ID card products.
- * Because of the large size of IssuerExtraData, a series of these commands have to be executed
- * to write entire IssuerExtraData.
- *
- * @param cardId CID, Unique Tangem card ID number.
- * @param issuerData Data provided by issuer.
- * @param startingSignature Issuer’s signature with Issuer Data Private Key of [cardId],
- * [issuerDataCounter] (if flags Protect_Issuer_Data_Against_Replay and
- * Restrict_Overwrite_Issuer_Extra_Data are set in [SettingsMask]) and size of [issuerData].
- * @param finalizingSignature Issuer’s signature with Issuer Data Private Key of [cardId],
- * [issuerData] and [issuerDataCounter] (the latter one only if flags Protect_Issuer_Data_Against_Replay
- * andRestrict_Overwrite_Issuer_Extra_Data are set in [SettingsMask]).
- * @param issuerDataCounter An optional counter that protect issuer data against replay attack.
- * @param callback is triggered on the completion of the [WriteIssuerExtraDataCommand] and provides
- * card response in the form of [WriteIssuerDataResponse] if the task was performed successfully
- * or [TangemSdkError] in case of an error.
- */
- fun writeIssuerExtraData(cardId: String? = null,
- issuerData: ByteArray,
- startingSignature: ByteArray,
- finalizingSignature: ByteArray,
- issuerDataCounter: Int? = null,
- initialMessage: Message? = null,
- callback: (result: CompletionResult) -> Unit) {
- val command = WriteIssuerExtraDataCommand(
- issuerData,
- startingSignature, finalizingSignature,
- issuerDataCounter,
- config.issuerPublicKey
- )
- startSessionWithRunnable(command, cardId, initialMessage, callback)
- }
-
- /**
- * This method launches a [WriteUserDataCommand] on a new thread, writing UserData and UserCounter fields.
- *
- * 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.
- * 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.
- */
- fun writeUserData(
- cardId: String? = null,
- userData: 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? = null,
- userProtectedData: ByteArray? = null,
- userProtectedCounter: Int? = null,
- initialMessage: Message? = null,
- callback: (result: CompletionResult) -> Unit
- ) {
- val command = WriteUserDataCommand(
- userProtectedData = userProtectedData, userProtectedCounter = userProtectedCounter
- )
- startSessionWithRunnable(command, cardId, initialMessage, callback)
- }
-
- /**
- * This method launches a [ReadUserDataCommand] on a new thread.
- *
- * This command returns two up to 512-byte User_Data, User_Protected_Data and two counters User_Counter and
- * User_Protected_Counter 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
- * 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
- * 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.
- *
- * @param cardId CID, Unique Tangem card ID number.
- * @param callback is triggered on the completion of the [ReadUserDataCommand] and provides
- * card response in the form of [ReadUserDataResponse] if the task was performed successfully
- * or [TangemSdkError] in case of an error.
- */
- fun readUserData(cardId: String? = null, initialMessage: Message? = null,
- callback: (result: CompletionResult) -> Unit) {
- startSessionWithRunnable(ReadUserDataCommand(), cardId, initialMessage, callback)
- }
-
- /**
- * This method launches a [CreateWalletTask] on a new thread.
- *
- * This this will create a new wallet on the card having ‘Empty’ state with [CreateWalletCommand]
- * and will check the success of the operation by performing [CheckWalletCommand].
- * A key pair WalletPublicKey / WalletPrivateKey is generated and securely stored in the card.
- * App will need to obtain Wallet_PublicKey from the [CreateWalletResponse] or from the
- * response of [ReadCommand] and then transform it into an address of corresponding
- * blockchain wallet according to a specific blockchain algorithm.
- * WalletPrivateKey is never revealed by the card and will be used by [SignCommand] and [CheckWalletCommand].
- * RemainingSignature is set to MaxSignatures.
- *
- * @param cardId CID, Unique Tangem card ID number.
- * @param callback is triggered on the completion of the [CreateWalletTask] and provides
- * card response in the form of [CreateWalletResponse] if the task was performed successfully
- * or [TangemSdkError] in case of an error.
- */
- fun createWallet(cardId: String? = null, initialMessage: Message? = null,
- callback: (result: CompletionResult) -> Unit) {
- startSessionWithRunnable(CreateWalletTask(), cardId, initialMessage, callback)
- }
-
- /**
- * This method launches a [PurgeWalletCommand] on a new thread.
- *
- * This command deletes all wallet data. If IsReusable flag is enabled during personalization,
-
- * or [CreateWalletCommand].
- * If IsReusable flag is disabled, the card switches to ‘Purged’ state.
- * ‘Purged’ state is final, it makes the card useless.
- *
- * @param cardId CID, Unique Tangem card ID number.
- * @param callback is triggered on the completion of the [PurgeWalletCommand] and provides
- * card response in the form of [PurgeWalletResponse] if the task was performed successfully
- * or [TangemSdkError] in case of an error.
- */
- fun purgeWallet(cardId: String? = null, initialMessage: Message? = null,
- callback: (result: CompletionResult) -> Unit) {
- startSessionWithRunnable(PurgeWalletCommand(), cardId, initialMessage, callback)
- }
-
- /**
- * Command available on SDK cards only
- *
- * This method launches a [DepersonalizeCommand] on a new thread.
- *
- * This command resets card to initial state,
- * erasing all data written during personalization and usage.
- *
- * @param cardId CID, Unique Tangem card ID number.
- * @param callback is triggered on the completion of the [DepersonalizeCommand] and provides
- * card response in the form of [DepersonalizeResponse] if the task was performed successfully
- * or [TangemSdkError] in case of an error.
- * */
- fun depersonalize(cardId: String? = null, initialMessage: Message? = null,
- callback: (result: CompletionResult) -> Unit) {
- startSessionWithRunnable(DepersonalizeCommand(), cardId, initialMessage, callback)
- }
-
- /**
- * Command available on SDK cards only
- *
- * This method launches a [PersonalizeCommand] on a new thread.
- *
- * Personalization is an initialization procedure, required before starting using a card.
- * During this procedure a card setting is set up.
- * During this procedure all data exchange is encrypted.
- * @param config is a configuration file with all the card settings that are written on the card
- * during personalization.
- * @param issuer Issuer is a third-party team or company wishing to use Tangem cards.
- * @param manufacturer Tangem Card Manufacturer.
- * @param acquirer Acquirer is a trusted third-party company that operates proprietary
- * (non-EMV) POS terminal infrastructure and transaction processing back-end.
- * @param callback is triggered on the completion of the [PersonalizeCommand] and provides
- * card response in the form of [Card] if the command was performed successfully
- * or [TangemSdkError] in case of an error.
- */
- fun personalize(config: CardConfig,
- issuer: Issuer, manufacturer: Manufacturer, acquirer: Acquirer? = null,
- initialMessage: Message? = null,
- callback: (result: CompletionResult) -> Unit) {
- val command = PersonalizeCommand(config, issuer, manufacturer, acquirer)
- startSessionWithRunnable(command, null, initialMessage, callback)
- }
-
- /**
- * Allows running a custom bunch of commands in one [CardSession] by creating a custom task.
- * [TangemSdk] will start a card session, perform preflight [ReadCommand],
- * invoke [CardSessionRunnable.run] and close the session.
- * You can find the current card in the [CardSession.environment].
-
- * @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.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.
- */
- fun startSessionWithRunnable(
- runnable: CardSessionRunnable, cardId: String? = null, initialMessage: Message? = null,
- callback: (result: CompletionResult) -> Unit) {
- val cardSession = CardSession(buildEnvironment(), reader, viewDelegate, cardId, initialMessage)
- Thread().run { cardSession.startWithRunnable(runnable, callback) }
- }
-
- /**
- * Allows running a custom bunch of commands in one [CardSession] with lightweight closure syntax.
- * Tangem SDK will start a card sesion and perform preflight [ReadCommand].
-
- * @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.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,
- * then you can use the [CardSession] to interact with a card.
- */
- fun startSession(cardId: String? = null, initialMessage: Message? = null,
- callback: (session: CardSession, error: TangemSdkError?) -> Unit) {
- val cardSession = CardSession(buildEnvironment(), reader, viewDelegate, cardId, initialMessage)
- Thread().run { cardSession.start(callback) }
- }
-
- /**
- * Allows to set a particular [TerminalKeysService] to retrieve terminal keys.
- * Default implementation is provided in tangem-sdk module: [TerminalKeysStorage].
- */
- fun setTerminalKeysService(terminalKeysService: TerminalKeysService) {
- this.terminalKeysService = terminalKeysService
- }
-
- private fun buildEnvironment(): SessionEnvironment {
- val terminalKeys = if (config.linkedTerminal) terminalKeysService?.getKeys() else null
- return SessionEnvironment(
- terminalKeys = terminalKeys,
- cardFilter = config.cardFilter,
- handleErrors = config.handleErrors
- )
- }
-
- companion object
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/TangemSdkError.kt b/tangem-core/src/main/java/com/tangem/TangemSdkError.kt
deleted file mode 100644
index 4aabb3da6b..0000000000
--- a/tangem-core/src/main/java/com/tangem/TangemSdkError.kt
+++ /dev/null
@@ -1,162 +0,0 @@
-package com.tangem
-
-import com.tangem.commands.Card
-import com.tangem.commands.ReadCommand
-import com.tangem.common.apdu.StatusWord
-import com.tangem.tasks.ScanTask
-
-/**
- * An error class that represent typical errors that may occur when performing Tangem SDK tasks.
- * Errors are propagated back to the caller in callbacks.
- */
-sealed class TangemSdkError(val code: Int) : Exception(code.toString()) {
-
- /**
- * This error is returned when Android NFC reader loses a tag
- * (e.g. a user detaches card from the phone's NFC module) while the NFC session is in progress.
- */
- class TagLost : TangemSdkError(10001)
- /**
- * This error is returned when NFC driver on an Android device does not support sending more than 261 bytes.
- */
- class ExtendedLengthNotSupported : TangemSdkError(10002)
-
-
- class SerializeCommandError : TangemSdkError(20001)
- class DeserializeApduFailed : TangemSdkError(20002)
- class EncodingFailedTypeMismatch : TangemSdkError(20003)
- class EncodingFailed : TangemSdkError(20004)
- class DecodingFailedMissingTag : TangemSdkError(20005)
- class DecodingFailedTypeMismatch : TangemSdkError(20006)
- class DecodingFailed : TangemSdkError(20007)
-
- /**
- * This error is returned when unknown [StatusWord] is received from a card.
- */
- class UnknownStatus : TangemSdkError(30001)
- /**
- * This error is returned when a card's reply is [StatusWord.ErrorProcessingCommand].
- * The card sends this status in case of internal card error.
- */
- class ErrorProcessingCommand : TangemSdkError(30002)
- /**
- * This error is returned when a card's reply is [StatusWord.InvalidState].
- * The card sends this status when command can not be executed in the current state of a card.
- */
- class InvalidState : TangemSdkError(30003)
- /**
- * This error is returned when a card's reply is [StatusWord.InsNotSupported].
- * The card sends this status when the card cannot process the [com.tangem.common.apdu.Instruction].
- */
- class InsNotSupported : TangemSdkError(30004)
- /**
- * This error is returned when a card's reply is [StatusWord.InvalidParams].
- * The card sends this status when there are wrong or not sufficient parameters in TLV request,
- * or wrong PIN1/PIN2.
- * The error may be caused, for example, by wrong parameters of the [Task], [CommandSerializer],
- * mapping or serialization errors.
- */
- class InvalidParams : TangemSdkError(30005)
- /**
- * This error is returned when a card's reply is [StatusWord.NeedEncryption]
- * and the encryption was not established by TangemSdk.
- */
- class NeedEncryption : TangemSdkError(30006)
-
- //Personalization Errors
- class AlreadyPersonalized : TangemSdkError(40101)
-
- //Depersonalization Errors
- class CannotBeDepersonalized : TangemSdkError(40201)
-
- //Read Errors
- class Pin1Required : TangemSdkError(40401)
-
- //CreateWallet Errors
- class AlreadyCreated : TangemSdkError(40501)
-
- //PurgeWallet Errors
- class PurgeWalletProhibited : TangemSdkError(40601)
-
- //SetPin Errors
- class Pin1CannotBeChanged : TangemSdkError(40801)
- class Pin2CannotBeChanged : TangemSdkError(40802)
- class Pin1CannotBeDefault : TangemSdkError(40803)
-
- //Sign Errors
- class NoRemainingSignatures : TangemSdkError(40901)
- /**
- * This error is returned when a [com.tangem.commands.SignCommand]
- * receives only empty hashes for signature.
- */
- class EmptyHashes : TangemSdkError(40902)
- /**
- * This error is returned when a [com.tangem.commands.SignCommand]
- * receives hashes of different lengths for signature.
- */
- class HashSizeMustBeEqual : TangemSdkError(40903)
- class CardIsEmpty : TangemSdkError(40904)
- class SignHashesNotAvailable : TangemSdkError(40905)
- /**
- * Tangem cards can sign currently up to 10 hashes during one [com.tangem.commands.SignCommand].
- * This error is returned when a [com.tangem.commands.SignCommand] receives more than 10 hashes to sign.
- */
- class TooManyHashesInOneTransaction : TangemSdkError(40906)
-
- //Write Extra Issuer Data Errors
- class ExendedDataSizeTooLarge : TangemSdkError(41101)
-
- //General Errors
- class NotPersonalized() : TangemSdkError(40001)
- class NotActivated : TangemSdkError(40002)
- class CardIsPurged : TangemSdkError(40003)
- class Pin2OrCvcRequired : TangemSdkError(40004)
- /**
- * This error is returned when a [Task] checks unsuccessfully either
- * a card's ability to sign with its private key, or the validity of issuer data.
- */
- class VerificationFailed : TangemSdkError(40005)
- class DataSizeTooLarge : TangemSdkError(40006)
-
- /**
- * This error is returned when [ReadIssuerDataTask] or [ReadIssuerExtraDataTask] expects a counter
- * (when the card's requires it), but the counter is missing.
- */
- class MissingCounter : TangemSdkError(40007)
- class OverwritingDataIsProhibited : TangemSdkError(40008)
- class DataCannotBeWritten : TangemSdkError(40009)
- class MissingIssuerPubicKey : TangemSdkError(40010)
-
- //SDK Errors
- class UnknownError: TangemSdkError(50001)
- /**
- * This error is returned when a user manually closes NFC Reading Bottom Sheet Dialog.
- */
- class UserCancelled: TangemSdkError(50002)
- /**
- * This error is returned when [com.tangem.TangemSdk] was called with a new [Task],
- * while a previous [Task] is still in progress.
- */
- class Busy : TangemSdkError(50003)
- /**
- * This error is returned when a task (such as [ScanTask]) requires that [ReadCommand]
- * 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)
-
-}
-
diff --git a/tangem-core/src/main/java/com/tangem/commands/CheckWalletCommand.kt b/tangem-core/src/main/java/com/tangem/commands/CheckWalletCommand.kt
deleted file mode 100644
index e3cbdf970a..0000000000
--- a/tangem-core/src/main/java/com/tangem/commands/CheckWalletCommand.kt
+++ /dev/null
@@ -1,110 +0,0 @@
-package com.tangem.commands
-
-import com.tangem.CardSession
-import com.tangem.SessionEnvironment
-import com.tangem.TangemSdkError
-import com.tangem.common.CompletionResult
-import com.tangem.common.apdu.CommandApdu
-import com.tangem.common.apdu.Instruction
-import com.tangem.common.apdu.ResponseApdu
-import com.tangem.common.tlv.TlvBuilder
-import com.tangem.common.tlv.TlvDecoder
-import com.tangem.common.tlv.TlvTag
-import com.tangem.crypto.CryptoUtils
-
-/**
- * Deserialized response from the Tangem card after [CheckWalletCommand].
- *
- * @property cardId Unique Tangem card ID number
- * @property salt Random salt generated by the card.
- * @property walletSignature Challenge and salt signed with the wallet private key.
- */
-class CheckWalletResponse(
- val cardId: String,
- val salt: ByteArray,
- val walletSignature: ByteArray
-) : CommandResponse {
-
- fun verify(curve: EllipticCurve, publicKey: ByteArray, challenge: ByteArray): Boolean {
- return CryptoUtils.verify(
- publicKey,
- challenge + salt,
- walletSignature,
- curve)
- }
-}
-
-/**
- * This command proves that the wallet private key from the card corresponds to the wallet public key.
- * Standard challenge/response scheme is used.
- *
- * @property pin1 Hashed user’s pin 1 code to access the card. Default unhashed value: ‘000000’.
- * @property cardId Unique Tangem card ID number
- * @property challenge Random challenge generated by application
- */
-class CheckWalletCommand(
- private val curve: EllipticCurve, private val publicKey: ByteArray
-) : Command() {
-
- private val challenge = CryptoUtils.generateRandomBytes(16)
-
- override fun run(session: CardSession, callback: (result: CompletionResult) -> Unit) {
- super.run(session) { result ->
- when (result) {
- is CompletionResult.Failure -> {
- callback(CompletionResult.Failure(result.error))
- }
- is CompletionResult.Success -> {
- val verified = result.data.verify(
- curve,
- publicKey,
- challenge
- )
- if (verified) {
- callback(CompletionResult.Success(result.data))
- } else {
- callback(CompletionResult.Failure(TangemSdkError.VerificationFailed()))
- }
- }
- }
- }
- }
-
- override fun performPreCheck(
- session: CardSession,
- callback: (result: CompletionResult) -> Unit
- ): Boolean {
- if (session.environment.card?.status == CardStatus.NotPersonalized) {
- callback(CompletionResult.Failure(TangemSdkError.NotPersonalized()))
- return true
- }
- if (session.environment.card?.isActivated == true) {
- callback(CompletionResult.Failure(TangemSdkError.NotActivated()))
- return true
- }
- return false
- }
-
- override fun serialize(environment: SessionEnvironment): CommandApdu {
- val tlvBuilder = TlvBuilder()
- tlvBuilder.append(TlvTag.Pin, environment.pin1)
- tlvBuilder.append(TlvTag.CardId, environment.card?.cardId)
- tlvBuilder.append(TlvTag.Challenge, challenge)
- return CommandApdu(
- Instruction.CheckWallet, tlvBuilder.serialize(),
- environment.encryptionMode, environment.encryptionKey
- )
- }
-
- override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): CheckWalletResponse {
- val tlvData = apdu.getTlvData(environment.encryptionKey)
- ?: throw TangemSdkError.DeserializeApduFailed()
-
- val decoder = TlvDecoder(tlvData)
- return CheckWalletResponse(
- cardId = decoder.decode(TlvTag.CardId),
- salt = decoder.decode(TlvTag.Salt),
- walletSignature = decoder.decode(TlvTag.Signature)
- )
- }
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/commands/Command.kt b/tangem-core/src/main/java/com/tangem/commands/Command.kt
deleted file mode 100644
index 0b17642735..0000000000
--- a/tangem-core/src/main/java/com/tangem/commands/Command.kt
+++ /dev/null
@@ -1,138 +0,0 @@
-package com.tangem.commands
-
-import com.tangem.*
-import com.tangem.common.CompletionResult
-import com.tangem.common.apdu.CommandApdu
-import com.tangem.common.apdu.ResponseApdu
-import com.tangem.common.apdu.StatusWord
-import com.tangem.common.apdu.toTangemSdkError
-import com.tangem.common.extensions.toInt
-import com.tangem.common.tlv.TlvTag
-
-/**
- * Basic interface for a parsed response from [Command].
- */
-interface CommandResponse
-
-/**
- * Basic class for Tangem card commands
- */
-abstract class Command : CardSessionRunnable {
-
- override val performPreflightRead: Boolean = true
-
- /**
- * Serializes data into an array of [com.tangem.common.tlv.Tlv],
- * then creates [CommandApdu] with this data.
- * @param environment [SessionEnvironment] of the current card
- * @return command data converted to [CommandApdu] that allows to convert it to [ByteArray]
- * that can be sent to a Tangem card
- */
- abstract fun serialize(environment: SessionEnvironment): CommandApdu
-
- /**
- * Deserializes data received from a card and stored in [ResponseApdu]
- * into an array of [com.tangem.common.tlv.Tlv]. Then maps it into a [CommandResponse].
- * @param environment [SessionEnvironment] of the current card.
- * @param apdu received data.
- * @return Card response converted to a [CommandResponse] of a type [T]
- */
- abstract fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): T
-
- override fun run(session: CardSession, callback: (result: CompletionResult) -> Unit) {
- Log.i("Command", "Initializing ${this::class.java.simpleName}")
- if (session.environment.handleErrors) {
- if (performPreCheck(session, callback)) return
- }
- transceive(session) { result ->
- if (session.environment.handleErrors) {
- if (performAfterCheck(session, result, callback)) return@transceive
- }
- callback(result)
- }
- }
-
- open fun performPreCheck(session: CardSession,
- callback: (result: CompletionResult) -> Unit): Boolean {
- return false
- }
-
- open fun performAfterCheck(session: CardSession,
- result: CompletionResult,
- callback: (result: CompletionResult) -> Unit): Boolean {
- return false
- }
-
- fun transceive(session: CardSession, callback: (result: CompletionResult) -> Unit) {
- try {
- val apdu = serialize(session.environment)
- transceiveApdu(apdu, session) { result ->
- when (result) {
- is CompletionResult.Failure -> callback(CompletionResult.Failure(result.error))
- is CompletionResult.Success -> {
- val response = deserialize(session.environment, result.data)
- callback(CompletionResult.Success(response))
- }
- }
- }
- } catch (error: TangemSdkError) {
- callback(CompletionResult.Failure(error))
- }
- }
-
- private fun transceiveApdu(apdu: CommandApdu, session: CardSession, callback: (result: CompletionResult) -> Unit) {
- session.send(apdu) { result ->
-
- when (result) {
- is CompletionResult.Success -> {
- val responseApdu = result.data
- when (responseApdu.statusWord) {
- StatusWord.ProcessCompleted, StatusWord.Pin1Changed, StatusWord.Pin2Changed, StatusWord.PinsChanged
- -> callback(CompletionResult.Success(responseApdu))
- StatusWord.NeedPause -> {
- // NeedPause is returned from the card whenever security delay is triggered.
- val remainingTime = deserializeSecurityDelay(responseApdu, session.environment)
- if (remainingTime != null) {
- session.viewDelegate.onSecurityDelay(
- remainingTime,
- session.environment.card?.pauseBeforePin2 ?: 0)
- }
- Log.i(this::class.simpleName!!, "Nfc command ${this::class.simpleName!!} " +
- "triggered security delay of $remainingTime milliseconds")
- transceiveApdu(apdu, session, callback)
- }
- else -> {
- val error = responseApdu.statusWord.toTangemSdkError()
- if (error != null && !tryHandleError(error)) {
- callback(CompletionResult.Failure(error))
- } else {
- callback(CompletionResult.Failure(TangemSdkError.UnknownError()))
- }
- }
- }
- }
- is CompletionResult.Failure ->
- if (result.error is TangemSdkError.TagLost) {
- session.viewDelegate.onTagLost()
- } else {
- callback(CompletionResult.Failure(result.error))
- }
- }
- }
- }
-
- /**
- * Helper method to parse security delay information received from a card.
- *
- * @return Remaining security delay in milliseconds.
- */
- private fun deserializeSecurityDelay(responseApdu: ResponseApdu, environment: SessionEnvironment): Int? {
- val tlv = responseApdu.getTlvData()
- return tlv?.find { it.tag == TlvTag.Pause }?.value?.toInt()
- }
-
- private fun tryHandleError(error: TangemSdkError): Boolean {
- return false
- }
-
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/commands/CreateWalletCommand.kt b/tangem-core/src/main/java/com/tangem/commands/CreateWalletCommand.kt
deleted file mode 100644
index e0bf433c99..0000000000
--- a/tangem-core/src/main/java/com/tangem/commands/CreateWalletCommand.kt
+++ /dev/null
@@ -1,100 +0,0 @@
-package com.tangem.commands
-
-import com.tangem.CardSession
-import com.tangem.SessionEnvironment
-import com.tangem.TangemSdkError
-import com.tangem.common.CompletionResult
-import com.tangem.common.apdu.CommandApdu
-import com.tangem.common.apdu.Instruction
-import com.tangem.common.apdu.ResponseApdu
-import com.tangem.common.tlv.TlvBuilder
-import com.tangem.common.tlv.TlvDecoder
-import com.tangem.common.tlv.TlvTag
-
-class CreateWalletResponse(
- /**
- * CID, Unique Tangem card ID number.
- */
- val cardId: String,
- /**
- * Current status of the card [1 - Empty, 2 - Loaded, 3- Purged]
- */
- val status: CardStatus,
- /**
-
- */
- val walletPublicKey: ByteArray
-) : CommandResponse
-
-/**
- * This command will create a new wallet on the card having ‘Empty’ state.
- * A key pair WalletPublicKey / WalletPrivateKey is generated and securely stored in the card.
- * App will need to obtain Wallet_PublicKey from the response of [CreateWalletCommand] or [ReadCommand]
- * and then transform it into an address of corresponding blockchain wallet
- * according to a specific blockchain algorithm.
- * WalletPrivateKey is never revealed by the card and will be used by [SignCommand] and [CheckWalletCommand].
- * RemainingSignature is set to MaxSignatures.
- *
- * @property cardId CID, Unique Tangem card ID number.
- */
-class CreateWalletCommand : Command() {
-
- override fun performPreCheck(session: CardSession, callback: (result: CompletionResult) -> Unit): Boolean {
- if (session.environment.card?.status == CardStatus.NotPersonalized) {
- callback(CompletionResult.Failure(TangemSdkError.NotPersonalized()))
- return true
- }
- if (session.environment.card?.isActivated == true) {
- callback(CompletionResult.Failure(TangemSdkError.NotActivated()))
- return true
- }
- if (session.environment.card?.status == CardStatus.Purged) {
- callback(CompletionResult.Failure(TangemSdkError.CardIsPurged()))
- return true
- }
- if (session.environment.card?.status == CardStatus.Loaded) {
- callback(CompletionResult.Failure(TangemSdkError.AlreadyCreated()))
- return true
- }
- return false
- }
-
- override fun performAfterCheck(session: CardSession,
- result: CompletionResult,
- callback: (result: CompletionResult) -> Unit): Boolean {
- when (result) {
- is CompletionResult.Failure -> {
- if (result.error is TangemSdkError.InvalidParams) {
- callback(CompletionResult.Failure(TangemSdkError.Pin2OrCvcRequired()))
- return true
- }
- return false
- }
- else -> return false
- }
- }
-
- override fun serialize(environment: SessionEnvironment): CommandApdu {
- val tlvBuilder = TlvBuilder()
- tlvBuilder.append(TlvTag.Pin, environment.pin1)
- tlvBuilder.append(TlvTag.CardId, environment.card?.cardId)
- tlvBuilder.append(TlvTag.Pin2, environment.pin2)
- tlvBuilder.append(TlvTag.Cvc, environment.cvc)
- return CommandApdu(
- Instruction.CreateWallet, tlvBuilder.serialize(),
- environment.encryptionMode, environment.encryptionKey
- )
- }
-
- override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): CreateWalletResponse {
- val tlvData = apdu.getTlvData(environment.encryptionKey)
- ?: throw TangemSdkError.DeserializeApduFailed()
-
- val decoder = TlvDecoder(tlvData)
- return CreateWalletResponse(
- cardId = decoder.decode(TlvTag.CardId),
- status = decoder.decode(TlvTag.Status),
- walletPublicKey = decoder.decode(TlvTag.WalletPublicKey)
- )
- }
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/commands/OpenSessionCommand.kt b/tangem-core/src/main/java/com/tangem/commands/OpenSessionCommand.kt
deleted file mode 100644
index 891e28f3c1..0000000000
--- a/tangem-core/src/main/java/com/tangem/commands/OpenSessionCommand.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-package com.tangem.commands
-
-import com.tangem.SessionEnvironment
-import com.tangem.TangemSdkError
-import com.tangem.common.apdu.CommandApdu
-import com.tangem.common.apdu.Instruction
-import com.tangem.common.apdu.ResponseApdu
-import com.tangem.common.tlv.TlvBuilder
-import com.tangem.common.tlv.TlvDecoder
-import com.tangem.common.tlv.TlvTag
-
-class OpenSessionResponse(
- val sessionKeyB: ByteArray,
- val uid: ByteArray
-) : CommandResponse
-
-/**
- * In case of encrypted communication, App should setup a session before calling any further command.
- * [OpenSessionCommand] generates secret session_key that is used by both host and card
- * to encrypt and decrypt commands’ payload.
-
- */
-class OpenSessionCommand(private val sessionKeyA: ByteArray) : Command() {
- override fun serialize(environment: SessionEnvironment): CommandApdu {
- val tlvBuilder = TlvBuilder()
- tlvBuilder.append(TlvTag.SessionKeyA, sessionKeyA)
- return CommandApdu(
- Instruction.OpenSession, tlvBuilder.serialize(),
- encryptionMode = environment.encryptionMode
- )
- }
-
- override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): OpenSessionResponse {
- val tlvData = apdu.getTlvData()
- ?: throw TangemSdkError.DeserializeApduFailed()
-
- val decoder = TlvDecoder(tlvData)
- return OpenSessionResponse(
- sessionKeyB = decoder.decode(TlvTag.SessionKeyB),
- uid = decoder.decode(TlvTag.Uid)
- )
- }
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/commands/PurgeWalletCommand.kt b/tangem-core/src/main/java/com/tangem/commands/PurgeWalletCommand.kt
deleted file mode 100644
index bbc3edfbb2..0000000000
--- a/tangem-core/src/main/java/com/tangem/commands/PurgeWalletCommand.kt
+++ /dev/null
@@ -1,85 +0,0 @@
-package com.tangem.commands
-
-import com.tangem.CardSession
-import com.tangem.SessionEnvironment
-import com.tangem.TangemSdkError
-import com.tangem.common.CompletionResult
-import com.tangem.common.apdu.CommandApdu
-import com.tangem.common.apdu.Instruction
-import com.tangem.common.apdu.ResponseApdu
-import com.tangem.common.tlv.TlvBuilder
-import com.tangem.common.tlv.TlvDecoder
-import com.tangem.common.tlv.TlvTag
-
-class PurgeWalletResponse(
- /**
- * CID, Unique Tangem card ID number.
- */
- val cardId: String,
- /**
- * Current status of the card [1 - Empty, 2 - Loaded, 3- Purged]
- */
- val status: CardStatus
-) : CommandResponse
-
-/**
- * This command deletes all wallet data. If Is_Reusable flag is enabled during personalization,
-
- * If Is_Reusable flag is disabled, the card switches to ‘Purged’ state.
- * ‘Purged’ state is final, it makes the card useless.
- * @property cardId CID, Unique Tangem card ID number.
- */
-class PurgeWalletCommand : Command() {
-
- override fun performPreCheck(session: CardSession, callback: (result: CompletionResult) -> Unit): Boolean {
- if (session.environment.card?.status == CardStatus.NotPersonalized) {
- callback(CompletionResult.Failure(TangemSdkError.NotPersonalized()))
- return true
- }
- if (session.environment.card?.isActivated == true) {
- callback(CompletionResult.Failure(TangemSdkError.NotActivated()))
- return true
- }
- if (session.environment.card?.settingsMask?.contains(Settings.ProhibitPurgeWallet) == true) {
- callback(CompletionResult.Failure(TangemSdkError.PurgeWalletProhibited()))
- return true
- }
- return false
- }
-
- override fun performAfterCheck(session: CardSession,
- result: CompletionResult,
- callback: (result: CompletionResult) -> Unit): Boolean {
- when (result) {
- is CompletionResult.Failure -> {
- if (result.error is TangemSdkError.InvalidParams) {
- callback(CompletionResult.Failure(TangemSdkError.Pin2OrCvcRequired()))
- return true
- }
- return false
- }
- else -> return false
- }
- }
-
- override fun serialize(environment: SessionEnvironment): CommandApdu {
- val tlvBuilder = TlvBuilder()
- tlvBuilder.append(TlvTag.Pin, environment.pin1)
- tlvBuilder.append(TlvTag.CardId, environment.card?.cardId)
- tlvBuilder.append(TlvTag.Pin2, environment.pin2)
- return CommandApdu(
- Instruction.PurgeWallet, tlvBuilder.serialize(),
- environment.encryptionMode, environment.encryptionKey
- )
- }
-
- override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): PurgeWalletResponse {
- val tlvData = apdu.getTlvData(environment.encryptionKey)
- ?: throw TangemSdkError.DeserializeApduFailed()
-
- val decoder = TlvDecoder(tlvData)
- return PurgeWalletResponse(
- cardId = decoder.decode(TlvTag.CardId),
- status = decoder.decode(TlvTag.Status))
- }
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/commands/ReadCommand.kt b/tangem-core/src/main/java/com/tangem/commands/ReadCommand.kt
deleted file mode 100644
index c8bbda44ff..0000000000
--- a/tangem-core/src/main/java/com/tangem/commands/ReadCommand.kt
+++ /dev/null
@@ -1,454 +0,0 @@
-package com.tangem.commands
-
-import com.tangem.CardSession
-import com.tangem.SessionEnvironment
-import com.tangem.TangemSdkError
-import com.tangem.common.CompletionResult
-import com.tangem.common.apdu.CommandApdu
-import com.tangem.common.apdu.Instruction
-import com.tangem.common.apdu.ResponseApdu
-import com.tangem.common.tlv.Tlv
-import com.tangem.common.tlv.TlvBuilder
-import com.tangem.common.tlv.TlvDecoder
-import com.tangem.common.tlv.TlvTag
-import java.util.*
-
-/**
- * Determines which type of data is required for signing.
- */
-data class SigningMethodMask(val rawValue: Int) {
-
- fun contains(signingMethod: SigningMethod): Boolean {
- return if (rawValue and 0x80 == 0) {
- signingMethod.code == rawValue
- } else {
- rawValue and (0x01 shl signingMethod.code) != 0
- }
- }
-}
-
-enum class SigningMethod(val code: Int) {
- SignHash(0),
- SignRaw(1),
- SignHashValidateByIssuer(2),
- SignRawValidateByIssuer(3),
- SignHashValidateByIssuerWriteIssuerData(4),
- SignRawValidateByIssuerWriteIssuerData(5),
- SignPos(6)
-}
-
-class SigningMethodMaskBuilder() {
-
- private val signingMethods = mutableSetOf()
-
- fun add(signingMethod: SigningMethod) {
- signingMethods.add(signingMethod)
- }
-
- fun build(): SigningMethodMask {
- val rawValue: Int = when {
- signingMethods.count() == 0 -> {
- 0
- }
- signingMethods.count() == 1 -> {
- signingMethods.iterator().next().code
- }
- else -> {
- signingMethods.fold(
- 0x80, { acc, singingMethod -> acc + (0x01 shl singingMethod.code) }
- )
- }
- }
- return SigningMethodMask(rawValue)
- }
-}
-
-/**
- * Elliptic curve used for wallet key operations.
- */
-enum class EllipticCurve(val curve: String) {
- Secp256k1("secp256k1"),
- Ed25519("ed25519");
-
- companion object {
- private val values = values()
- fun byName(curve: String): EllipticCurve? = values.find { it.curve == curve }
- }
-}
-
-/**
- * Status of the card and its wallet.
- */
-enum class CardStatus(val code: Int) {
- NotPersonalized(0),
- Empty(1),
- Loaded(2),
- Purged(3);
-
- companion object {
- private val values = values()
- fun byCode(code: Int): CardStatus? = values.find { it.code == code }
- }
-}
-
-/**
- * Mask of products enabled on card
- * @property rawValue Products mask values,
- * while flags definitions and values are in [ProductMask.Companion] as constants.
- */
-data class ProductMask(val rawValue: Int) {
-
- fun contains(product: Product): Boolean = (rawValue and product.code) != 0
-
-}
-
-enum class Product(val code: Int) {
- Note(0x01),
- Tag(0x02),
- IdCard(0x04),
- IdIssuer(0x08)
-}
-
-class ProductMaskBuilder() {
-
- private var productMaskValue = 0
-
- fun add(product: Product) {
- productMaskValue = productMaskValue or product.code
- }
-
- fun build() = ProductMask(productMaskValue)
-
-}
-
-/**
- * Stores and maps Tangem card settings.
- *
- * @property rawValue Card settings in a form of flags,
- * while flags definitions and possible values are in [Settings].
- */
-data class SettingsMask(val rawValue: Int) {
- fun contains(settings: Settings): Boolean = (rawValue and settings.code) != 0
-}
-
-enum class Settings(val code: Int) {
- IsReusable(0x0001),
- UseActivation(0x0002),
- ProhibitPurgeWallet(0x0004),
- UseBlock(0x0008),
-
- AllowSwapPIN(0x0010),
- AllowSwapPIN2(0x0020),
- UseCVC(0x0040),
- ForbidDefaultPIN(0x0080),
-
- UseOneCommandAtTime(0x0100),
- UseNdef(0x0200),
- UseDynamicNdef(0x0400),
- SmartSecurityDelay(0x0800),
-
- ProtocolAllowUnencrypted(0x1000),
- ProtocolAllowStaticEncryption(0x2000),
-
- ProtectIssuerDataAgainstReplay(0x4000),
- RestrictOverwriteIssuerDataEx(0x00100000),
-
- AllowSelectBlockchain(0x8000),
-
- DisablePrecomputedNdef(0x00010000),
-
- SkipSecurityDelayIfValidatedByLinkedTerminal(0x00080000),
- SkipCheckPin2andCvcIfValidatedByIssuer(0x00040000),
- SkipSecurityDelayIfValidatedByIssuer(0x00020000),
-
- RequireTermTxSignature(0x01000000),
- RequireTermCertSignature(0x02000000),
- CheckPIN3onCard(0x04000000)
-}
-
-
-class SettingsMaskBuilder() {
-
- private var settingsMaskValue = 0
-
- fun add(settings: Settings) {
- settingsMaskValue = settingsMaskValue or settings.code
- }
-
- fun build() = SettingsMask(settingsMaskValue)
-
-}
-
-/**
- * Detailed information about card contents.
- */
-class CardData(
-
- /**
- * Tangem internal manufacturing batch ID.
- */
- val batchId: String?,
-
- /**
- * Timestamp of manufacturing.
- */
- val manufactureDateTime: Date?,
-
- /**
- * Name of the issuer.
- */
- val issuerName: String?,
-
- /**
- * Name of the blockchain.
- */
- val blockchainName: String?,
-
- /**
- * Signature of CardId with manufacturer’s private key.
- */
- val manufacturerSignature: ByteArray?,
-
- /**
- * Mask of products enabled on card.
- */
- val productMask: ProductMask?,
-
- /**
- * Name of the token.
- */
- val tokenSymbol: String?,
-
- /**
- * Smart contract address.
- */
- val tokenContractAddress: String?,
-
- /**
- * Number of decimals in token value.
- */
- val tokenDecimal: Int?
-)
-
-/**
- * Response for [ReadCommand]. Contains detailed card information.
- */
-class Card(
-
- /**
- * Unique Tangem card ID number.
- */
- val cardId: String,
-
- /**
- * Name of Tangem card manufacturer.
- */
- val manufacturerName: String,
-
- /**
- * Current status of the card.
- */
- val status: CardStatus?,
-
- /**
- * Version of Tangem COS.
- */
- val firmwareVersion: String?,
-
- /**
- * Public key that is used to authenticate the card against manufacturer’s database.
- * It is generated one time during card manufacturing.
- */
- val cardPublicKey: ByteArray?,
-
- /**
- * Card settings defined by personalization (bit mask: 0 – Enabled, 1 – Disabled).
- */
- val settingsMask: SettingsMask?,
-
- /**
- * Public key that is used by the card issuer to sign IssuerData field.
- */
- val issuerPublicKey: ByteArray?,
-
- /**
- * Explicit text name of the elliptic curve used for all wallet key operations.
- * Supported curves: ‘secp256k1’ and ‘ed25519’.
- */
- val curve: EllipticCurve?,
-
- /**
- * Total number of signatures allowed for the wallet when the card was personalized.
- */
- val maxSignatures: Int?,
-
- /**
- * Defines what data should be submitted to SIGN command.
- */
- val signingMethods: SigningMethodMask?,
-
- /**
- * Delay in seconds before COS executes commands protected by PIN2.
- */
- val pauseBeforePin2: Int?,
-
- /**
- * Public key of the blockchain wallet.
- */
- val walletPublicKey: ByteArray?,
-
- /**
- * Remaining number of [SignCommand] operations before the wallet will stop signing transactions.
- */
- val walletRemainingSignatures: Int?,
-
- /**
- * Total number of signed single hashes returned by the card in
- * [SignCommand] responses since card personalization.
- * Sums up array elements within all [SignCommand].
- */
- val walletSignedHashes: Int?,
-
- /**
- * Any non-zero value indicates that the card experiences some hardware problems.
- * User should withdraw the value to other blockchain wallet as soon as possible.
- * Non-zero Health tag will also appear in responses of all other commands.
- */
- val health: Int?,
-
- /**
- * Whether the card requires issuer’s confirmation of activation.
- */
- val isActivated: Boolean,
-
- /**
- * A random challenge generated by personalisation that should be signed and returned
- * to COS by the issuer to confirm the card has been activated.
- * This field will not be returned if the card is activated.
- */
- val activationSeed: ByteArray?,
-
- /**
- * Returned only if [SigningMethod.SignPos] enabling POS transactions is supported by card.
- */
- val paymentFlowVersion: ByteArray?,
-
- /**
- * This value can be initialized by terminal and will be increased by COS on execution of every [SignCommand].
- * For example, this field can store blockchain “nonce” for quick one-touch transaction on POS terminals.
- * Returned only if [SigningMethod.SignPos] enabling POS transactions is supported by card.
- */
- val userCounter: Int?,
-
- /**
- * This value can be initialized by App (with PIN2 confirmation) and will be increased by COS
- * with the execution of each [SignCommand]. For example, this field can store blockchain “nonce”
- * for a quick one-touch transaction on POS terminals. Returned only if [SigningMethod.SignPos].
- */
- val userProtectedCounter: Int?,
-
- /**
- * When this value is true, it means that the application is linked to the card,
- * and COS will not enforce security delay if [SignCommand] will be called
- * with [TlvTag.TerminalTransactionSignature] parameter containing a correct signature of raw data
- * to be signed made with [TlvTag.TerminalPublicKey].
- */
- val terminalIsLinked: Boolean,
-
- /**
- * Detailed information about card contents. Format is defined by the card issuer.
- * Cards complaint with Tangem Wallet application should have TLV format.
- */
- val cardData: CardData?
-) : CommandResponse
-
-/**
- * This command receives from the Tangem Card all the data about the card and the wallet,
- * including unique card number (CID or cardId) that has to be submitted while calling all other commands.
- */
-class ReadCommand : Command() {
-
- override fun performAfterCheck(session: CardSession, result: CompletionResult, callback: (result: CompletionResult) -> Unit): Boolean {
- when (result) {
- is CompletionResult.Failure -> {
- if (result.error is TangemSdkError.InvalidParams) {
- callback(CompletionResult.Failure(TangemSdkError.Pin1Required()))
- return true
- }
- return false
- }
- else -> return false
- }
- }
-
- override fun serialize(environment: SessionEnvironment): CommandApdu {
- val tlvBuilder = TlvBuilder()
- /**
- * [SessionEnvironment] stores the pin1 value. If no pin1 value was set, it will contain
- * default value of ‘000000’.
- * In order to obtain card’s data, [ReadCommand] should use the correct pin 1 value.
- * The card will not respond if wrong pin 1 has been submitted.
- */
- tlvBuilder.append(TlvTag.Pin, environment.pin1)
- tlvBuilder.append(TlvTag.TerminalPublicKey, environment.terminalKeys?.publicKey)
- return CommandApdu(
- Instruction.Read, tlvBuilder.serialize(),
- environment.encryptionMode, environment.encryptionKey
- )
- }
-
- override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): Card {
- val tlvData = apdu.getTlvData(environment.encryptionKey)
- ?: throw TangemSdkError.DeserializeApduFailed()
-
- val decoder = TlvDecoder(tlvData)
-
- return Card(
- cardId = decoder.decodeOptional(TlvTag.CardId) ?: "",
- manufacturerName = decoder.decodeOptional(TlvTag.ManufactureId) ?: "",
- status = decoder.decodeOptional(TlvTag.Status),
-
- firmwareVersion = decoder.decodeOptional(TlvTag.Firmware),
- cardPublicKey = decoder.decodeOptional(TlvTag.CardPublicKey),
- settingsMask = decoder.decodeOptional(TlvTag.SettingsMask),
- issuerPublicKey = decoder.decodeOptional(TlvTag.IssuerDataPublicKey),
- curve = decoder.decodeOptional(TlvTag.CurveId),
- maxSignatures = decoder.decodeOptional(TlvTag.MaxSignatures),
- signingMethods = decoder.decodeOptional(TlvTag.SigningMethod),
- pauseBeforePin2 = decoder.decodeOptional(TlvTag.PauseBeforePin2),
- walletPublicKey = decoder.decodeOptional(TlvTag.WalletPublicKey),
- walletRemainingSignatures = decoder.decodeOptional(TlvTag.RemainingSignatures),
- walletSignedHashes = decoder.decodeOptional(TlvTag.SignedHashes),
- health = decoder.decodeOptional(TlvTag.Health),
- isActivated = decoder.decode(TlvTag.IsActivated),
- activationSeed = decoder.decodeOptional(TlvTag.ActivationSeed),
- paymentFlowVersion = decoder.decodeOptional(TlvTag.PaymentFlowVersion),
- userCounter = decoder.decodeOptional(TlvTag.UserCounter),
- userProtectedCounter = decoder.decodeOptional(TlvTag.UserProtectedCounter),
- terminalIsLinked = decoder.decode(TlvTag.TerminalIsLinked),
-
- cardData = deserializeCardData(tlvData)
- )
- }
-
- private fun deserializeCardData(tlvData: List): CardData? {
- val cardDataTlvs = tlvData.find { it.tag == TlvTag.CardData }?.let {
- Tlv.deserialize(it.value)
- }
- if (cardDataTlvs.isNullOrEmpty()) return null
-
- val decoder = TlvDecoder(cardDataTlvs)
- return CardData(
- batchId = decoder.decodeOptional(TlvTag.Batch),
- manufactureDateTime = decoder.decodeOptional(TlvTag.ManufactureDateTime),
- issuerName = decoder.decodeOptional(TlvTag.IssuerId),
- blockchainName = decoder.decodeOptional(TlvTag.BlockchainId),
- manufacturerSignature = decoder.decodeOptional(TlvTag.ManufacturerSignature),
- productMask = decoder.decodeOptional(TlvTag.ProductMask),
-
- tokenSymbol = decoder.decodeOptional(TlvTag.TokenSymbol),
- tokenContractAddress = decoder.decodeOptional(TlvTag.TokenContractAddress),
- tokenDecimal = decoder.decodeOptional(TlvTag.TokenDecimal)
- )
- }
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/commands/ReadIssuerDataCommand.kt b/tangem-core/src/main/java/com/tangem/commands/ReadIssuerDataCommand.kt
deleted file mode 100644
index d01a3adbe8..0000000000
--- a/tangem-core/src/main/java/com/tangem/commands/ReadIssuerDataCommand.kt
+++ /dev/null
@@ -1,124 +0,0 @@
-package com.tangem.commands
-
-import com.tangem.CardSession
-import com.tangem.SessionEnvironment
-import com.tangem.TangemSdkError
-import com.tangem.commands.common.DefaultIssuerDataVerifier
-import com.tangem.commands.common.IssuerDataMode
-import com.tangem.commands.common.IssuerDataToVerify
-import com.tangem.commands.common.IssuerDataVerifier
-import com.tangem.common.CompletionResult
-import com.tangem.common.apdu.CommandApdu
-import com.tangem.common.apdu.Instruction
-import com.tangem.common.apdu.ResponseApdu
-import com.tangem.common.tlv.TlvBuilder
-import com.tangem.common.tlv.TlvDecoder
-import com.tangem.common.tlv.TlvTag
-
-class ReadIssuerDataResponse(
-
- /**
- * CID, Unique Tangem card ID number.
- */
- val cardId: String,
-
- /**
- * Data defined by issuer.
- */
- val issuerData: ByteArray,
-
- /**
- * Issuer’s signature of [issuerData] with Issuer Data Private Key (which is kept on card).
- * Issuer’s signature of SHA256-hashed [cardId] concatenated with [issuerData]:
- * SHA256([cardId] | [issuerData]).
- * When flag [Settings.ProtectIssuerDataAgainstReplay] set in [SettingsMask] then signature of
- * SHA256-hashed CID Issuer_Data concatenated with and [issuerDataCounter]:
- * SHA256([cardId] | [issuerData] | [issuerDataCounter]).
- */
- val issuerDataSignature: ByteArray,
-
- /**
- * An optional counter that protect issuer data against replay attack.
- * When flag [Settings.ProtectIssuerDataAgainstReplay] set in [SettingsMask]
- * then this value is mandatory and must increase on each execution of [WriteIssuerDataCommand].
- */
- val issuerDataCounter: Int?
-) : CommandResponse
-
-
-/**
- * This command returns 512-byte Issuer Data field and its issuer’s signature.
- * Issuer Data is never changed or parsed from within the Tangem COS. The issuer defines purpose of use,
- * format and payload of Issuer Data. For example, this field may contain information about
- * wallet balance signed by the issuer or additional issuer’s attestation data.
- * @property cardId CID, Unique Tangem card ID number.
- */
-class ReadIssuerDataCommand(
- val issuerPublicKey: ByteArray? = null,
- verifier: IssuerDataVerifier = DefaultIssuerDataVerifier()
-) : Command(), IssuerDataVerifier by verifier {
-
- override fun run(session: CardSession, callback: (result: CompletionResult) -> Unit) {
- val card = session.environment.card
- if (card == null) {
- callback(CompletionResult.Failure(TangemSdkError.MissingPreflightRead()))
- return
- }
- val publicKey = issuerPublicKey ?: card.issuerPublicKey
- if (publicKey == null) {
- callback(CompletionResult.Failure(TangemSdkError.MissingIssuerPubicKey()))
- return
- }
- super.run(session) { result ->
- when (result) {
- is CompletionResult.Failure -> callback(result)
- is CompletionResult.Success -> {
- if (result.data.issuerData.isEmpty()) {
- callback(result)
- return@run
- }
- val issuerDataToVerify = IssuerDataToVerify(
- card.cardId, result.data.issuerData, result.data.issuerDataCounter
- )
- if (verify(publicKey, result.data.issuerDataSignature, issuerDataToVerify)) {
- callback(result)
- } else {
- callback(CompletionResult.Failure(TangemSdkError.VerificationFailed()))
- }
- }
- }
- }
- }
-
- override fun performPreCheck(session: CardSession, callback: (result: CompletionResult) -> Unit): Boolean {
- if (session.environment.card?.status == CardStatus.NotPersonalized) {
- callback(CompletionResult.Failure(TangemSdkError.NotPersonalized()))
- return true
- }
- return false
- }
-
- override fun serialize(environment: SessionEnvironment): CommandApdu {
- val tlvBuilder = TlvBuilder()
- tlvBuilder.append(TlvTag.Pin, environment.pin1)
- tlvBuilder.append(TlvTag.CardId, environment.card?.cardId)
- tlvBuilder.append(TlvTag.Mode, IssuerDataMode.ReadData)
- return CommandApdu(
- Instruction.ReadIssuerData, tlvBuilder.serialize(),
- environment.encryptionMode, environment.encryptionKey
- )
- }
-
- override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): ReadIssuerDataResponse {
- val tlvData = apdu.getTlvData(environment.encryptionKey)
- ?: throw TangemSdkError.DeserializeApduFailed()
-
- val decoder = TlvDecoder(tlvData)
- return ReadIssuerDataResponse(
- cardId = decoder.decode(TlvTag.CardId),
- issuerData = decoder.decode(TlvTag.IssuerData),
- issuerDataSignature = decoder.decode(TlvTag.IssuerDataSignature),
- issuerDataCounter = decoder.decodeOptional(TlvTag.IssuerDataCounter)
- )
- }
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/commands/ReadIssuerExtraDataCommand.kt b/tangem-core/src/main/java/com/tangem/commands/ReadIssuerExtraDataCommand.kt
deleted file mode 100644
index 82e148a05d..0000000000
--- a/tangem-core/src/main/java/com/tangem/commands/ReadIssuerExtraDataCommand.kt
+++ /dev/null
@@ -1,183 +0,0 @@
-package com.tangem.commands
-
-import com.tangem.CardSession
-import com.tangem.SessionEnvironment
-import com.tangem.TangemSdkError
-import com.tangem.commands.common.DefaultIssuerDataVerifier
-import com.tangem.commands.common.IssuerDataMode
-import com.tangem.commands.common.IssuerDataToVerify
-import com.tangem.commands.common.IssuerDataVerifier
-import com.tangem.common.CompletionResult
-import com.tangem.common.apdu.CommandApdu
-import com.tangem.common.apdu.Instruction
-import com.tangem.common.apdu.ResponseApdu
-import com.tangem.common.tlv.TlvBuilder
-import com.tangem.common.tlv.TlvDecoder
-import com.tangem.common.tlv.TlvTag
-import java.io.ByteArrayOutputStream
-
-class ReadIssuerExtraDataResponse(
-
- /**
- * CID, Unique Tangem card ID number.
- */
- val cardId: String,
-
- /**
- * Size of all Issuer_Extra_Data field.
- */
- val size: Int?,
-
- /**
- * Data defined by issuer.
- */
- val issuerData: ByteArray,
-
- /**
- * Issuer’s signature of [issuerData] with Issuer Data Private Key (which is kept on card).
- * Issuer’s signature of SHA256-hashed [cardId] concatenated with [issuerData]:
- * SHA256([cardId] | [issuerData]).
- * When flag [Settings.ProtectIssuerDataAgainstReplay] set in [SettingsMask] then signature of
- * SHA256-hashed CID Issuer_Data concatenated with and [issuerDataCounter]:
- * SHA256([cardId] | [issuerData] | [issuerDataCounter]).
- */
- val issuerDataSignature: ByteArray?,
-
- /**
- * An optional counter that protects issuer data against replay attack.
- * When flag [Settings.ProtectIssuerDataAgainstReplay] set in [SettingsMask]
- * then this value is mandatory and must increase on each execution of [WriteIssuerDataCommand].
- */
- val issuerDataCounter: Int?
-) : CommandResponse
-
-
-/**
- * This command retrieves Issuer Extra Data field and its issuer’s signature.
- * Issuer Extra Data is never changed or parsed from within the Tangem COS. The issuer defines purpose of use,
- * format and payload of Issuer Data. . For example, this field may contain photo or
- * biometric information for ID card product. Because of the large size of Issuer_Extra_Data,
- * a series of these commands have to be executed to read the entire Issuer_Extra_Data.
- */
-class ReadIssuerExtraDataCommand(
- private val issuerPublicKey: ByteArray? = null,
- verifier: IssuerDataVerifier = DefaultIssuerDataVerifier()
-) : Command(), IssuerDataVerifier by verifier {
-
- private val issuerData = ByteArrayOutputStream()
- private var offset: Int = 0
- private var issuerDataSize: Int = 0
-
- override fun run(session: CardSession, callback: (result: CompletionResult) -> Unit) {
- val card = session.environment.card
- if (card == null) {
- callback(CompletionResult.Failure(TangemSdkError.MissingPreflightRead()))
- return
- }
- val publicKey = issuerPublicKey ?: card.issuerPublicKey
- if (publicKey == null) {
- callback(CompletionResult.Failure(TangemSdkError.MissingIssuerPubicKey()))
- return
- }
- if (session.environment.card?.status == CardStatus.NotPersonalized) {
- callback(CompletionResult.Failure(TangemSdkError.NotPersonalized()))
- return
- }
-
- readIssuerData(session, card.cardId, publicKey, callback)
- }
-
-
- private fun readIssuerData(
- session: CardSession,
- cardId: String, publicKey: ByteArray,
- callback: (result: CompletionResult) -> Unit) {
-
- if (issuerDataSize != 0) {
- session.viewDelegate.onDelay(
- issuerDataSize, offset, WriteIssuerExtraDataCommand.SINGLE_WRITE_SIZE
- )
- }
-
- transceive(session) { result ->
- when (result) {
- is CompletionResult.Success -> {
- if (result.data.size != null) {
- if (result.data.size == 0) {
- callback(CompletionResult.Success(result.data))
- return@transceive
- }
- issuerDataSize = result.data.size
- }
- issuerData.write(result.data.issuerData)
- if (result.data.issuerDataSignature == null) {
- offset = issuerData.size()
- readIssuerData(session, cardId, publicKey, callback)
- } else {
- completeTask(result.data, cardId, publicKey, callback)
- }
- }
- is CompletionResult.Failure -> {
- callback(CompletionResult.Failure(result.error))
- }
- }
- }
- }
-
- private fun completeTask(data: ReadIssuerExtraDataResponse,
- cardId: String, publicKey: ByteArray,
- callback: (result: CompletionResult) -> Unit) {
- val dataToVerify = IssuerDataToVerify(
- cardId,
- issuerData.toByteArray(),
- data.issuerDataCounter
- )
- if (verify(publicKey, data.issuerDataSignature!!, dataToVerify)) {
- val finalResult = ReadIssuerExtraDataResponse(
- data.cardId,
- issuerDataSize,
- issuerData.toByteArray(),
- data.issuerDataSignature,
- data.issuerDataCounter
- )
- callback(CompletionResult.Success(finalResult))
- } else {
- callback(CompletionResult.Failure(TangemSdkError.VerificationFailed()))
- }
- }
-
- override fun serialize(environment: SessionEnvironment): CommandApdu {
- val tlvBuilder = TlvBuilder()
- tlvBuilder.append(TlvTag.Pin, environment.pin1)
- tlvBuilder.append(TlvTag.CardId, environment.card?.cardId)
- tlvBuilder.append(TlvTag.Mode, IssuerDataMode.ReadExtraData)
- tlvBuilder.append(TlvTag.Offset, offset)
- return CommandApdu(
- Instruction.ReadIssuerData, tlvBuilder.serialize(),
- environment.encryptionMode, environment.encryptionKey
- )
- }
-
- override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): ReadIssuerExtraDataResponse {
- val tlvData = apdu.getTlvData(environment.encryptionKey)
- ?: throw TangemSdkError.DeserializeApduFailed()
-
-
- val decoder = TlvDecoder(tlvData)
- return ReadIssuerExtraDataResponse(
- cardId = decoder.decode(TlvTag.CardId),
- size = decoder.decodeOptional(TlvTag.Size),
- issuerData = decoder.decodeOptional(TlvTag.IssuerData) ?: byteArrayOf(),
- issuerDataSignature = decoder.decodeOptional(TlvTag.IssuerDataSignature),
- issuerDataCounter = decoder.decodeOptional(TlvTag.IssuerDataCounter)
- )
- }
-
- companion object {
- /**
- * This mode value specifies that this command retrieves Issuer EXTRA data from the card
- * (with value 0 the command will get instead simple Issuer Data from the card).
- */
- const val EXTRA_DATA_MODE = 1
- }
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/commands/ReadUserDataCommand.kt b/tangem-core/src/main/java/com/tangem/commands/ReadUserDataCommand.kt
deleted file mode 100644
index b8ee2022d6..0000000000
--- a/tangem-core/src/main/java/com/tangem/commands/ReadUserDataCommand.kt
+++ /dev/null
@@ -1,90 +0,0 @@
-package com.tangem.commands
-
-import com.tangem.CardSession
-import com.tangem.SessionEnvironment
-import com.tangem.TangemSdkError
-import com.tangem.common.CompletionResult
-import com.tangem.common.apdu.CommandApdu
-import com.tangem.common.apdu.Instruction
-import com.tangem.common.apdu.ResponseApdu
-import com.tangem.common.tlv.TlvBuilder
-import com.tangem.common.tlv.TlvDecoder
-import com.tangem.common.tlv.TlvTag
-
-class ReadUserDataResponse(
- /**
- * CID, Unique Tangem card ID number.
- */
- val cardId: String,
-
- /**
- * Data defined by user's App.
- */
- val userData: ByteArray,
-
- /**
- * Data defined by user's App (confirmed by PIN2).
- */
- val userProtectedData: ByteArray,
-
- /**
- * Counter initialized by user's App and increased on every signing of new transaction
- */
- val userCounter: Int,
-
- /**
- * Counter initialized by user's App (confirmed by PIN2) and increased on every signing of new transaction
- */
- val userProtectedCounter: Int
-
-) : CommandResponse
-
-/**
- * This command returns two up to 512-byte User_Data, User_Protected_Data and two counters User_Counter and
- * User_Protected_Counter 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
- * 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
- * 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.
- */
-class ReadUserDataCommand : Command() {
-
- override fun performPreCheck(session: CardSession, callback: (result: CompletionResult) -> Unit): Boolean {
- if (session.environment.card?.status == CardStatus.NotPersonalized) {
- callback(CompletionResult.Failure(TangemSdkError.NotPersonalized()))
- return true
- }
- if (session.environment.card?.isActivated == true) {
- callback(CompletionResult.Failure(TangemSdkError.NotActivated()))
- return true
- }
- return false
- }
-
- override fun serialize(environment: SessionEnvironment): CommandApdu {
- val builder = TlvBuilder()
- builder.append(TlvTag.CardId, environment.card?.cardId)
- builder.append(TlvTag.Pin, environment.pin1)
-
- return CommandApdu(
- Instruction.ReadUserData, builder.serialize(),
- environment.encryptionMode, environment.encryptionKey
- )
- }
-
- override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): ReadUserDataResponse {
- val tlvData = apdu.getTlvData(environment.encryptionKey)
- ?: throw TangemSdkError.DeserializeApduFailed()
-
- val decoder = TlvDecoder(tlvData)
- return ReadUserDataResponse(
- cardId = decoder.decode(TlvTag.CardId),
- userData = decoder.decode(TlvTag.UserData),
- userProtectedData = decoder.decode(TlvTag.UserProtectedData),
- userCounter = decoder.decode(TlvTag.UserCounter),
- userProtectedCounter = decoder.decode(TlvTag.UserProtectedCounter)
- )
- }
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/commands/SignCommand.kt b/tangem-core/src/main/java/com/tangem/commands/SignCommand.kt
deleted file mode 100644
index fc926be116..0000000000
--- a/tangem-core/src/main/java/com/tangem/commands/SignCommand.kt
+++ /dev/null
@@ -1,147 +0,0 @@
-package com.tangem.commands
-
-import com.tangem.CardSession
-import com.tangem.SessionEnvironment
-import com.tangem.TangemSdkError
-import com.tangem.common.CompletionResult
-import com.tangem.common.apdu.CommandApdu
-import com.tangem.common.apdu.Instruction
-import com.tangem.common.apdu.ResponseApdu
-import com.tangem.common.tlv.TlvBuilder
-import com.tangem.common.tlv.TlvDecoder
-import com.tangem.common.tlv.TlvTag
-import com.tangem.crypto.sign
-
-/**
- * @param cardId CID, Unique Tangem card ID number
- * @param signature Signed hashes (array of resulting signatures)
- * @param walletRemainingSignatures Remaining number of sign operations before the wallet will stop signing transactions.
- * @param walletSignedHashes Total number of signed single hashes returned by the card in sign command responses.
- * Sums up array elements within all SIGN commands
- */
-class SignResponse(
- val cardId: String,
- val signature: ByteArray,
- val walletRemainingSignatures: Int,
- val walletSignedHashes: Int
-) : CommandResponse
-
-/**
- * Signs transaction hashes using a wallet private key, stored on the card.
- *
- * @property hashes Array of transaction hashes.
- * @property cardId CID, Unique Tangem card ID number
- */
-class SignCommand(private val hashes: Array)
- : Command() {
-
- private val hashSizes = if (hashes.isNotEmpty()) hashes.first().size else 0
-
- override fun performPreCheck(session: CardSession, callback: (result: CompletionResult) -> Unit): Boolean {
- if (session.environment.card?.status == CardStatus.NotPersonalized) {
- callback(CompletionResult.Failure(TangemSdkError.NotPersonalized()))
- return true
- }
- if (session.environment.card?.isActivated == true) {
- callback(CompletionResult.Failure(TangemSdkError.NotActivated()))
- return true
- }
- if (session.environment.card?.status == CardStatus.Purged) {
- callback(CompletionResult.Failure(TangemSdkError.CardIsPurged()))
- return true
- }
- if (session.environment.card?.status == CardStatus.Empty) {
- callback(CompletionResult.Failure(TangemSdkError.CardIsEmpty()))
- return true
- }
- if (session.environment.card?.walletRemainingSignatures == 0) {
- callback(CompletionResult.Failure(TangemSdkError.NoRemainingSignatures()))
- return true
- }
- if (session.environment.card?.signingMethods?.contains(SigningMethod.SignHash) != true) {
- callback(CompletionResult.Failure(TangemSdkError.SignHashesNotAvailable()))
- return true
- }
- if (hashSizes == 0) {
- callback(CompletionResult.Failure(TangemSdkError.EmptyHashes()))
- return true
- }
- if (hashes.any { it.size != hashSizes }) {
- callback(CompletionResult.Failure(TangemSdkError.HashSizeMustBeEqual()))
- return true
- }
- return false
- }
-
- override fun performAfterCheck(session: CardSession,
- result: CompletionResult,
- callback: (result: CompletionResult) -> Unit): Boolean {
- when (result) {
- is CompletionResult.Failure -> {
- if (result.error is TangemSdkError.InvalidParams) {
- callback(CompletionResult.Failure(TangemSdkError.Pin2OrCvcRequired()))
- return true
- }
- return false
- }
- else -> return false
- }
- }
-
- override fun serialize(environment: SessionEnvironment): CommandApdu {
- val dataToSign = flattenHashes()
- val tlvBuilder = TlvBuilder()
- tlvBuilder.append(TlvTag.Pin, environment.pin1)
- tlvBuilder.append(TlvTag.Pin2, environment.pin2)
- tlvBuilder.append(TlvTag.CardId, environment.card?.cardId)
- tlvBuilder.append(TlvTag.TransactionOutHashSize, byteArrayOf(hashSizes.toByte()))
- tlvBuilder.append(TlvTag.TransactionOutHash, dataToSign)
- tlvBuilder.append(TlvTag.Cvc, environment.cvc)
-
- addTerminalSignature(environment, dataToSign, tlvBuilder)
- return CommandApdu(
- Instruction.Sign, tlvBuilder.serialize(),
- environment.encryptionMode, environment.encryptionKey
- )
- }
-
- private fun flattenHashes(): ByteArray {
- checkForErrors()
- return hashes.reduce { arr1, arr2 -> arr1 + arr2 }
- }
-
- private fun checkForErrors() {
- if (hashes.isEmpty()) throw TangemSdkError.EmptyHashes()
- if (hashes.size > 10) throw TangemSdkError.TooManyHashesInOneTransaction()
- if (hashes.any { it.size != hashSizes }) throw TangemSdkError.HashSizeMustBeEqual()
- }
-
- /**
- * Application can optionally submit a public key Terminal_PublicKey in [SignCommand].
- * Submitted key is stored by the Tangem card if it differs from a previous submitted Terminal_PublicKey.
- * The Tangem card will not enforce security delay if [SignCommand] will be called with
- * TerminalTransactionSignature parameter containing a correct signature of raw data to be signed made with TerminalPrivateKey
- * (this key should be generated and securily stored by the application).
- */
- private fun addTerminalSignature(
- environment: SessionEnvironment, dataToSign: ByteArray, tlvBuilder: TlvBuilder) {
- environment.terminalKeys?.let { terminalKeyPair ->
- val signedData = dataToSign.sign(terminalKeyPair.privateKey)
- tlvBuilder.append(TlvTag.TerminalTransactionSignature, signedData)
- tlvBuilder.append(TlvTag.TerminalPublicKey, terminalKeyPair.publicKey)
- }
- }
-
- override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): SignResponse {
- val tlvData = apdu.getTlvData(environment.encryptionKey)
- ?: throw TangemSdkError.DeserializeApduFailed()
-
- val decoder = TlvDecoder(tlvData)
- return SignResponse(
- cardId = decoder.decode(TlvTag.CardId),
- signature = decoder.decode(TlvTag.Signature),
- walletRemainingSignatures = decoder.decode(TlvTag.RemainingSignatures),
- walletSignedHashes = decoder.decode(TlvTag.SignedHashes)
- )
- }
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/commands/WriteIssuerDataCommand.kt b/tangem-core/src/main/java/com/tangem/commands/WriteIssuerDataCommand.kt
deleted file mode 100644
index 2574a2f4a6..0000000000
--- a/tangem-core/src/main/java/com/tangem/commands/WriteIssuerDataCommand.kt
+++ /dev/null
@@ -1,136 +0,0 @@
-package com.tangem.commands
-
-import com.tangem.CardSession
-import com.tangem.SessionEnvironment
-import com.tangem.TangemSdkError
-import com.tangem.commands.common.DefaultIssuerDataVerifier
-import com.tangem.commands.common.IssuerDataMode
-import com.tangem.commands.common.IssuerDataToVerify
-import com.tangem.commands.common.IssuerDataVerifier
-import com.tangem.common.CompletionResult
-import com.tangem.common.apdu.CommandApdu
-import com.tangem.common.apdu.Instruction
-import com.tangem.common.apdu.ResponseApdu
-import com.tangem.common.tlv.TlvBuilder
-import com.tangem.common.tlv.TlvDecoder
-import com.tangem.common.tlv.TlvTag
-
-class WriteIssuerDataResponse(
- /**
- * CID, Unique Tangem card ID number.
- */
- val cardId: String
-) : CommandResponse
-
-/**
- * This command writes 512-byte Issuer Data field and its issuer’s signature.
- * Issuer Data is never changed or parsed from within the Tangem COS. The issuer defines purpose of use,
- * format and payload of Issuer Data. For example, this field may contain information about
- * wallet balance signed by the issuer or additional issuer’s attestation data.
- * @property cardId CID, Unique Tangem card ID number.
- * @property issuerData Data provided by issuer.
- * @property issuerDataSignature Issuer’s signature of [issuerData] with Issuer Data Private Key (which is kept on card).
- * @property issuerDataCounter An optional counter that protect issuer data against replay attack.
- */
-class WriteIssuerDataCommand(
- private val issuerData: ByteArray,
- private val issuerDataSignature: ByteArray,
- private val issuerDataCounter: Int? = null,
- private val issuerPublicKey: ByteArray? = null,
- verifier: IssuerDataVerifier = DefaultIssuerDataVerifier()
-) : Command(), IssuerDataVerifier by verifier {
-
- override fun performPreCheck(session: CardSession, callback: (result: CompletionResult) -> Unit): Boolean {
- val card = session.environment.card
- if (card == null) {
- callback(CompletionResult.Failure(TangemSdkError.MissingPreflightRead()))
- return true
- }
- val publicKey = issuerPublicKey ?: card.issuerPublicKey
- if (publicKey == null) {
- callback(CompletionResult.Failure(TangemSdkError.MissingIssuerPubicKey()))
- return true
- }
- if (session.environment.card?.status == CardStatus.NotPersonalized) {
- callback(CompletionResult.Failure(TangemSdkError.NotPersonalized()))
- return true
- }
- if (session.environment.card?.isActivated == true) {
- callback(CompletionResult.Failure(TangemSdkError.NotActivated()))
- return true
- }
- if (issuerData.size > MAX_SIZE) {
- callback(CompletionResult.Failure(TangemSdkError.DataSizeTooLarge()))
- return true
- }
- if (!isCounterValid(issuerDataCounter, card)) {
- callback(CompletionResult.Failure(TangemSdkError.MissingCounter()))
- return true
- }
- if (!verifySignature(publicKey, card.cardId)) {
- callback(CompletionResult.Failure(TangemSdkError.VerificationFailed()))
- return true
- }
- return false
- }
-
- override fun performAfterCheck(session: CardSession,
- result: CompletionResult,
- callback: (result: CompletionResult) -> Unit
- ): Boolean {
- when (result) {
- is CompletionResult.Failure -> {
- if (result.error is TangemSdkError.InvalidParams &&
- isCounterRequired(session.environment.card)) {
- callback(CompletionResult.Failure(TangemSdkError.DataCannotBeWritten()))
- return true
- }
- return false
- }
- else -> return false
- }
- }
-
- private fun isCounterValid(issuerDataCounter: Int?, card: Card): Boolean =
- if (isCounterRequired(card)) issuerDataCounter != null else true
-
- private fun isCounterRequired(card: Card?): Boolean =
- card?.settingsMask?.contains(Settings.ProtectIssuerDataAgainstReplay) != false
-
- private fun verifySignature(publicKey: ByteArray, cardId: String): Boolean {
- return verify(
- publicKey,
- issuerDataSignature,
- IssuerDataToVerify(cardId, issuerData, issuerDataCounter)
- )
- }
-
- override fun serialize(environment: SessionEnvironment): CommandApdu {
- val tlvBuilder = TlvBuilder()
- tlvBuilder.append(TlvTag.Pin, environment.pin1)
- tlvBuilder.append(TlvTag.CardId, environment.card?.cardId)
- tlvBuilder.append(TlvTag.Mode, IssuerDataMode.WriteData)
- tlvBuilder.append(TlvTag.IssuerData, issuerData)
- tlvBuilder.append(TlvTag.IssuerDataSignature, issuerDataSignature)
- tlvBuilder.append(TlvTag.IssuerDataCounter, issuerDataCounter)
-
- return CommandApdu(
- Instruction.WriteIssuerData, tlvBuilder.serialize(),
- environment.encryptionMode, environment.encryptionKey
- )
- }
-
- override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): WriteIssuerDataResponse {
- val tlvData = apdu.getTlvData(environment.encryptionKey)
- ?: throw TangemSdkError.DeserializeApduFailed()
-
- val decoder = TlvDecoder(tlvData)
- return WriteIssuerDataResponse(
- cardId = decoder.decode(TlvTag.CardId)
- )
- }
-
- companion object {
- const val MAX_SIZE = 512
- }
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/commands/WriteIssuerExtraDataCommand.kt b/tangem-core/src/main/java/com/tangem/commands/WriteIssuerExtraDataCommand.kt
deleted file mode 100644
index 84e0b50851..0000000000
--- a/tangem-core/src/main/java/com/tangem/commands/WriteIssuerExtraDataCommand.kt
+++ /dev/null
@@ -1,213 +0,0 @@
-package com.tangem.commands
-
-import com.tangem.CardSession
-import com.tangem.SessionEnvironment
-import com.tangem.TangemSdkError
-import com.tangem.commands.common.DefaultIssuerDataVerifier
-import com.tangem.commands.common.IssuerDataMode
-import com.tangem.commands.common.IssuerDataToVerify
-import com.tangem.commands.common.IssuerDataVerifier
-import com.tangem.common.CompletionResult
-import com.tangem.common.apdu.CommandApdu
-import com.tangem.common.apdu.Instruction
-import com.tangem.common.apdu.ResponseApdu
-import com.tangem.common.tlv.TlvBuilder
-import com.tangem.common.tlv.TlvDecoder
-import com.tangem.common.tlv.TlvTag
-
-/**
- * This command writes Issuer Extra Data field and its issuer’s signature.
- * Issuer Extra Data is never changed or parsed from within the Tangem COS.
- * The issuer defines purpose of use, format and payload of Issuer Data.
- * For example, this field may contain a photo or biometric information for ID card products.
- * Because of the large size of Issuer_Extra_Data, a series of these commands have to be executed
- * to write entire Issuer_Extra_Data.
- * @param issuerData Data provided by issuer.
- * @param startingSignature Issuer’s signature with Issuer Data Private Key of [cardId],
- * [issuerDataCounter] (if flags Protect_Issuer_Data_Against_Replay and
- * Restrict_Overwrite_Issuer_Extra_Data are set in [SettingsMask]) and size of [issuerData].
- * @param finalizingSignature Issuer’s signature with Issuer Data Private Key of [cardId],
- * [issuerData] and [issuerDataCounter] (the latter one only if flags Protect_Issuer_Data_Against_Replay
- * andRestrict_Overwrite_Issuer_Extra_Data are set in [SettingsMask]).
- * @param issuerDataCounter An optional counter that protect issuer data against replay attack.
- */
-class WriteIssuerExtraDataCommand(
- private val issuerData: ByteArray,
- private val startingSignature: ByteArray,
- private val finalizingSignature: ByteArray,
- private val issuerDataCounter: Int? = null,
- private val issuerPublicKey: ByteArray? = null,
- verifier: IssuerDataVerifier = DefaultIssuerDataVerifier()
-) : Command(), IssuerDataVerifier by verifier {
-
- var mode: IssuerDataMode = IssuerDataMode.InitializeWritingExtraData
- var offset: Int = 0
-
- override fun run(session: CardSession, callback: (result: CompletionResult) -> Unit) {
- val card = session.environment.card
- if (card == null) {
- callback(CompletionResult.Failure(TangemSdkError.MissingPreflightRead()))
- return
- }
- val publicKey = issuerPublicKey ?: card.issuerPublicKey
- if (publicKey == null) {
- callback(CompletionResult.Failure(TangemSdkError.MissingIssuerPubicKey()))
- return
- }
-
- writeIssuerData(session, card.cardId, publicKey) { response ->
- when (response) {
- is CompletionResult.Success -> callback(response)
- is CompletionResult.Failure -> {
- if (response.error is TangemSdkError.InvalidParams && isCounterRequired(card)) {
- callback(CompletionResult.Failure(TangemSdkError.DataCannotBeWritten()))
- return@writeIssuerData
- }
- if (response.error is TangemSdkError.InvalidState &&
- card.settingsMask?.contains(Settings.ProtectIssuerDataAgainstReplay) != false) {
- callback(CompletionResult.Failure(TangemSdkError.OverwritingDataIsProhibited()))
- return@writeIssuerData
- }
- }
- }
- }
- }
-
- override fun performPreCheck(session: CardSession, callback: (result: CompletionResult) -> Unit): Boolean {
- val card = session.environment.card
- if (card == null) {
- callback(CompletionResult.Failure(TangemSdkError.MissingPreflightRead()))
- return true
- }
- val publicKey = issuerPublicKey ?: card.issuerPublicKey
- if (publicKey == null) {
- callback(CompletionResult.Failure(TangemSdkError.MissingIssuerPubicKey()))
- return true
- }
-
- if (session.environment.card?.status == CardStatus.NotPersonalized) {
- callback(CompletionResult.Failure(TangemSdkError.NotPersonalized()))
- return true
- }
- if (session.environment.card?.isActivated == true) {
- callback(CompletionResult.Failure(TangemSdkError.NotActivated()))
- return true
- }
- if (issuerData.size > MAX_SIZE) {
- callback(CompletionResult.Failure(TangemSdkError.ExendedDataSizeTooLarge()))
- return true
- }
- if (!isCounterValid(issuerDataCounter, card)) {
- callback(CompletionResult.Failure(TangemSdkError.MissingCounter()))
- return true
- }
- if (!verifySignatures(card.cardId, publicKey)) {
- callback(CompletionResult.Failure(TangemSdkError.VerificationFailed()))
- return true
- }
- return false
- }
-
- private fun isCounterValid(issuerDataCounter: Int?, card: Card): Boolean =
- if (isCounterRequired(card)) issuerDataCounter != null else true
-
- private fun isCounterRequired(card: Card): Boolean =
- card.settingsMask?.contains(Settings.ProtectIssuerDataAgainstReplay) != false
-
- private fun verifySignatures(cardId: String, publicKey: ByteArray): Boolean {
-
- val firstData = IssuerDataToVerify(cardId, null, issuerDataCounter, issuerData.size)
- val secondData = IssuerDataToVerify(cardId, issuerData, issuerDataCounter)
-
- return verify(publicKey, startingSignature, firstData) &&
- verify(publicKey, finalizingSignature, secondData)
- }
-
- private fun writeIssuerData(
- session: CardSession,
- cardId: String, publicKey: ByteArray,
- callback: (result: CompletionResult) -> Unit
- ) {
-
- if (mode == IssuerDataMode.WriteExtraData) {
- session.viewDelegate.onDelay(issuerData.size, offset, WriteIssuerExtraDataCommand.SINGLE_WRITE_SIZE)
- }
- transceive(session) { result ->
- when (result) {
- is CompletionResult.Success -> {
- when (mode) {
- IssuerDataMode.InitializeWritingExtraData -> {
- mode = IssuerDataMode.WriteExtraData
- writeIssuerData(session, cardId, publicKey, callback)
- return@transceive
- }
- IssuerDataMode.WriteExtraData -> {
- offset += WriteIssuerExtraDataCommand.SINGLE_WRITE_SIZE
- if (offset >= issuerData.size) {
- mode = IssuerDataMode.FinalizeExtraData
- }
- writeIssuerData(session, cardId, publicKey, callback)
- return@transceive
- }
- IssuerDataMode.FinalizeExtraData -> {
- callback(CompletionResult.Success(result.data))
- }
- }
- }
- is CompletionResult.Failure -> {
- callback(CompletionResult.Failure(result.error))
- }
- }
- }
-
-
- }
-
- override fun serialize(environment: SessionEnvironment): CommandApdu {
- val tlvBuilder = TlvBuilder()
-
- tlvBuilder.append(TlvTag.Pin, environment.pin1)
- tlvBuilder.append(TlvTag.CardId, environment.card?.cardId)
- tlvBuilder.append(TlvTag.Mode, mode)
-
- when (mode) {
- IssuerDataMode.InitializeWritingExtraData -> {
- tlvBuilder.append(TlvTag.Size, issuerData.size)
- tlvBuilder.append(TlvTag.IssuerDataSignature, startingSignature)
- tlvBuilder.append(TlvTag.IssuerDataCounter, issuerDataCounter)
- }
- IssuerDataMode.WriteExtraData -> {
- tlvBuilder.append(TlvTag.IssuerData, getDataToWrite())
- tlvBuilder.append(TlvTag.Offset, offset)
- }
- IssuerDataMode.FinalizeExtraData -> {
- tlvBuilder.append(TlvTag.IssuerDataSignature, finalizingSignature)
- }
- }
- return CommandApdu(
- Instruction.WriteIssuerData, tlvBuilder.serialize(),
- environment.encryptionMode, environment.encryptionKey
- )
- }
-
- private fun getDataToWrite(): ByteArray =
- issuerData.copyOfRange(offset, offset + calculatePartSize())
-
- private fun calculatePartSize(): Int {
- val bytesLeft = issuerData.size - offset
- return if (bytesLeft < SINGLE_WRITE_SIZE) bytesLeft else SINGLE_WRITE_SIZE
- }
-
- override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): WriteIssuerDataResponse {
- val tlvData = apdu.getTlvData(environment.encryptionKey)
- ?: throw TangemSdkError.DeserializeApduFailed()
-
- return WriteIssuerDataResponse(cardId = TlvDecoder(tlvData).decode(TlvTag.CardId)
- )
- }
-
- companion object {
- const val SINGLE_WRITE_SIZE = 1524
- const val MAX_SIZE = 32 * 1024
- }
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/commands/WriteUserDataCommand.kt b/tangem-core/src/main/java/com/tangem/commands/WriteUserDataCommand.kt
deleted file mode 100644
index fc0d0467ae..0000000000
--- a/tangem-core/src/main/java/com/tangem/commands/WriteUserDataCommand.kt
+++ /dev/null
@@ -1,95 +0,0 @@
-package com.tangem.commands
-
-import com.tangem.CardSession
-import com.tangem.SessionEnvironment
-import com.tangem.TangemSdkError
-import com.tangem.common.CompletionResult
-import com.tangem.common.apdu.CommandApdu
-import com.tangem.common.apdu.Instruction
-import com.tangem.common.apdu.ResponseApdu
-import com.tangem.common.tlv.TlvBuilder
-import com.tangem.common.tlv.TlvDecoder
-import com.tangem.common.tlv.TlvTag
-
-class WriteUserDataResponse(
- /**
- * CID, Unique Tangem card ID number.
- */
- val cardId: String
-) : CommandResponse
-
-/**
- * This command writes to the card any of User_Data, User_ProtectedData, User_Counter and User_ProtectedCounter 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
- * 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
- * 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 User_Counter and User_Data protected only by PIN1.
- * User_ProtectedCounter and User_ProtectedData additionaly need PIN2 to confirmation.
- */
-class WriteUserDataCommand(private val userData: ByteArray? = null, private val userProtectedData: ByteArray? = null,
- private val userCounter: Int? = null,
- private val userProtectedCounter: Int? = null) : Command() {
-
- override fun performPreCheck(session: CardSession, callback: (result: CompletionResult) -> Unit): Boolean {
- if (session.environment.card?.status == CardStatus.NotPersonalized) {
- callback(CompletionResult.Failure(TangemSdkError.NotPersonalized()))
- return true
- }
- if (session.environment.card?.isActivated == true) {
- callback(CompletionResult.Failure(TangemSdkError.NotActivated()))
- return true
- }
- if (userData?.size ?: 0 > MAX_SIZE || userProtectedData?.size ?: 0 > MAX_SIZE) {
- callback(CompletionResult.Failure(TangemSdkError.DataSizeTooLarge()))
- return true
- }
- return false
- }
-
- override fun performAfterCheck(session: CardSession,
- result: CompletionResult,
- callback: (result: CompletionResult) -> Unit
- ): Boolean {
- when (result) {
- is CompletionResult.Failure -> {
- if (result.error is TangemSdkError.InvalidParams) {
- callback(CompletionResult.Failure(TangemSdkError.Pin2OrCvcRequired()))
- return true
- }
- return false
- }
- else -> return false
- }
- }
-
- override fun serialize(environment: SessionEnvironment): CommandApdu {
- val builder = TlvBuilder()
- builder.append(TlvTag.CardId, environment.card?.cardId)
- builder.append(TlvTag.Pin, environment.pin1)
- builder.append(TlvTag.UserData, userData)
- builder.append(TlvTag.UserCounter, userCounter)
- builder.append(TlvTag.UserProtectedData, userProtectedData)
- builder.append(TlvTag.UserProtectedCounter, userProtectedCounter)
- if (userProtectedCounter != null || userProtectedData != null)
- builder.append(TlvTag.Pin2, environment.pin2)
-
- return CommandApdu(
- Instruction.WriteUserData, builder.serialize(),
- environment.encryptionMode, environment.encryptionKey
- )
- }
-
- override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): WriteUserDataResponse {
- val tlvData = apdu.getTlvData(environment.encryptionKey)
- ?: throw TangemSdkError.DeserializeApduFailed()
- return WriteUserDataResponse(TlvDecoder(tlvData).decode(TlvTag.CardId))
- }
-
- companion object{
- const val MAX_SIZE = 512
- }
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/commands/common/IssuerDataMode.kt b/tangem-core/src/main/java/com/tangem/commands/common/IssuerDataMode.kt
deleted file mode 100644
index 2ebded1b6d..0000000000
--- a/tangem-core/src/main/java/com/tangem/commands/common/IssuerDataMode.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.tangem.commands.common
-
-import com.tangem.commands.WriteIssuerExtraDataCommand
-
-/**
- * This enum specifies modes for [WriteIssuerExtraDataCommand].
- */
-enum class IssuerDataMode(val code: Byte) {
-
-
- /**
- * This mode is required to read issuer data from the card.
- */
- ReadData(0),
-
- /**
- * This mode is required to write issuer data to the card.
- */
- WriteData(0),
- /**
- * This mode is required to read issuer extra data from the card.
- */
- ReadExtraData(1),
- /**
- * This mode is required to initiate writing issuer extra data to the card.
- */
- InitializeWritingExtraData(1),
- /**
- * With this mode, the command writes part of issuer extra data
- * (block of a size [WriteIssuerExtraDataCommand.SINGLE_WRITE_SIZE]) to the card.
- */
- WriteExtraData(2),
- /**
- * This mode is used after the issuer extra data was fully written to the card.
- * Under this mode the command provides the issuer signature
- * to confirm the validity of data that was written to card.
- */
- FinalizeExtraData(3);
-
- companion object {
- private val values = values()
- fun byCode(code: Byte): IssuerDataMode? = values.find { it.code == code }
- }
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/commands/common/IssuerDataVerifier.kt b/tangem-core/src/main/java/com/tangem/commands/common/IssuerDataVerifier.kt
deleted file mode 100644
index 03bf58d56e..0000000000
--- a/tangem-core/src/main/java/com/tangem/commands/common/IssuerDataVerifier.kt
+++ /dev/null
@@ -1,40 +0,0 @@
-package com.tangem.commands.common
-
-import com.tangem.common.tlv.TlvEncoder
-import com.tangem.common.tlv.TlvTag
-import com.tangem.crypto.CryptoUtils
-import java.io.ByteArrayOutputStream
-
-interface IssuerDataVerifier {
- fun verify(
- issuerPublicKey: ByteArray, signature: ByteArray, issuerDataToVerify: IssuerDataToVerify
- ): Boolean
-}
-
-class IssuerDataToVerify(
- val cardId: String,
- val issuerData: ByteArray?,
- val issuerDataCounter: Int? = null,
- val issuerExtraDataSize: Int? = null
-)
-
-class DefaultIssuerDataVerifier : IssuerDataVerifier {
- override fun verify(
- issuerPublicKey: ByteArray,
- signature: ByteArray,
- issuerDataToVerify: IssuerDataToVerify
- ): Boolean {
-
- val tlvEncoder = TlvEncoder()
- val dataToVerify = ByteArrayOutputStream()
- dataToVerify.write(tlvEncoder.encodeValue(TlvTag.CardId, issuerDataToVerify.cardId))
- issuerDataToVerify.issuerData?.let { dataToVerify.write(it) }
- issuerDataToVerify.issuerDataCounter?.let { counter ->
- dataToVerify.write(tlvEncoder.encodeValue(TlvTag.IssuerDataCounter, counter))
- }
- issuerDataToVerify.issuerExtraDataSize?.let {
- dataToVerify.write(tlvEncoder.encodeValue(TlvTag.Size, it))
- }
- return CryptoUtils.verify(issuerPublicKey, dataToVerify.toByteArray(), signature)
- }
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/commands/common/ResponseConverter.kt b/tangem-core/src/main/java/com/tangem/commands/common/ResponseConverter.kt
deleted file mode 100644
index 54d38798a1..0000000000
--- a/tangem-core/src/main/java/com/tangem/commands/common/ResponseConverter.kt
+++ /dev/null
@@ -1,119 +0,0 @@
-package com.tangem.commands.common
-
-import com.google.gson.*
-import com.tangem.commands.*
-import com.tangem.common.extensions.print
-import com.tangem.common.extensions.toHexString
-import java.lang.reflect.Type
-import java.text.DateFormat
-import java.util.*
-
-/**
-[REDACTED_AUTHOR]
- */
-class ResponseConverter {
-
- val gson: Gson by lazy { init() }
-
- private val fieldConverter = ResponseFieldConverter()
-
- private fun init(): Gson {
- val builder = GsonBuilder().apply {
- registerTypeAdapter(ByteArray::class.java, ByteTypeAdapter(fieldConverter))
- registerTypeAdapter(SigningMethodMask::class.java, SigningMethodTypeAdapter(fieldConverter))
- registerTypeAdapter(SettingsMask::class.java, SettingsMaskTypeAdapter(fieldConverter))
- registerTypeAdapter(ProductMask::class.java, ProductMaskTypeAdapter(fieldConverter))
- registerTypeAdapter(Date::class.java, DateTypeAdapter())
- }
- builder.setPrettyPrinting()
- return builder.create()
- }
-
- fun convertResponse(response: CommandResponse?): String = gson.toJson(response)
-}
-
-class ByteTypeAdapter(
- private val fieldConverter: ResponseFieldConverter
-) : JsonSerializer {
- override fun serialize(src: ByteArray, typeOfSrc: Type, context: JsonSerializationContext): JsonElement {
- return JsonPrimitive(fieldConverter.byteArrayToHex(src))
- }
-}
-
-class SettingsMaskTypeAdapter(
- private val fieldConverter: ResponseFieldConverter
-) : JsonSerializer {
- override fun serialize(src: SettingsMask, typeOfSrc: Type, context: JsonSerializationContext): JsonElement {
- return JsonArray().apply {
- fieldConverter.settingsMaskList(src).forEach { add(it) }
- }
- }
-}
-
-class ProductMaskTypeAdapter(
- private val fieldConverter: ResponseFieldConverter
-) : JsonSerializer {
- override fun serialize(src: ProductMask, typeOfSrc: Type, context: JsonSerializationContext): JsonElement {
- return JsonArray().apply {
- fieldConverter.productMaskList(src).forEach { add(it) }
- }
- }
-}
-
-class SigningMethodTypeAdapter(
- private val fieldConverter: ResponseFieldConverter
-) : JsonSerializer {
- override fun serialize(src: SigningMethodMask, typeOfSrc: Type, context: JsonSerializationContext): JsonElement {
- return JsonArray().apply {
- fieldConverter.signingMethodList(src).forEach { add(it) }
- }
- }
-}
-
-class DateTypeAdapter : JsonSerializer {
- override fun serialize(src: Date, typeOfSrc: Type, context: JsonSerializationContext): JsonElement {
- val formatter = DateFormat.getDateInstance(DateFormat.DEFAULT, Locale("en_US"))
- return JsonPrimitive(formatter.format(src).toString())
- }
-}
-
-class ResponseFieldConverter {
-
- fun productMask(productMask: ProductMask?): String {
- return productMaskList(productMask).print(wrap = false)
- }
-
- fun productMaskList(productMask: ProductMask?): List {
- val mask = productMask ?: return emptyList()
-
- return Product.values().filter { mask.contains(it) }.map { it.name }
- }
-
- fun signingMethod(signingMask: SigningMethodMask?): String {
- return signingMethodList(signingMask).print(wrap = false)
- }
-
- fun signingMethodList(signingMask: SigningMethodMask?): List {
- val mask = signingMask ?: return emptyList()
-
- return SigningMethod.values().filter { mask.contains(it) }.map { it.name }
- }
-
- fun settingsMask(settingsMask: SettingsMask?): String {
- return settingsMaskList(settingsMask).print(wrap = false)
- }
-
- fun settingsMaskList(settingsMask: SettingsMask?): List {
- val masks = settingsMask ?: return emptyList()
-
- return Settings.values().filter { masks.contains(it) }.map { it.name }
- }
-
- fun byteArrayToHex(byteArray: ByteArray?): String? {
- return byteArray?.toHexString()
- }
-
- fun byteArrayToString(byteArray: ByteArray?): String? {
- return if (byteArray == null) null else String(byteArray)
- }
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/commands/personalization/DepersonalizeCommand.kt b/tangem-core/src/main/java/com/tangem/commands/personalization/DepersonalizeCommand.kt
deleted file mode 100644
index 00dccae6a1..0000000000
--- a/tangem-core/src/main/java/com/tangem/commands/personalization/DepersonalizeCommand.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-package com.tangem.commands.personalization
-
-import com.tangem.SessionEnvironment
-import com.tangem.commands.Command
-import com.tangem.commands.CommandResponse
-import com.tangem.common.apdu.CommandApdu
-import com.tangem.common.apdu.Instruction
-import com.tangem.common.apdu.ResponseApdu
-
-data class DepersonalizeResponse(val success: Boolean) : CommandResponse
-
-/**
- * Command available on SDK cards only
- *
- * This command resets card to initial state,
- * erasing all data written during personalization and usage.
- */
-class DepersonalizeCommand : Command() {
-
- override val performPreflightRead = false
-
-// override fun performPreCheck(session: CardSession, callback: (result: CompletionResult) -> Unit): Boolean {
-// if (session.environment.card?.status == CardStatus.NotPersonalized) {
-// callback(CompletionResult.Failure(TangemSdkError.NotPersonalized()))
-// return true
-// }
-// if (session.environment.card?.firmwareVersion?.contains("SDK") == false) {
-// callback(CompletionResult.Failure(TangemSdkError.CannotBeDepersonalized()))
-// return true
-// }
-// return false
-// }
-
- override fun serialize(environment: SessionEnvironment): CommandApdu {
- return CommandApdu(
- Instruction.Depersonalize, byteArrayOf()
- )
- }
-
- override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): DepersonalizeResponse {
- return DepersonalizeResponse(true)
- }
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/commands/personalization/NdefEncoder.kt b/tangem-core/src/main/java/com/tangem/commands/personalization/NdefEncoder.kt
deleted file mode 100644
index 6c6103556e..0000000000
--- a/tangem-core/src/main/java/com/tangem/commands/personalization/NdefEncoder.kt
+++ /dev/null
@@ -1,88 +0,0 @@
-package com.tangem.commands.personalization
-
-import com.tangem.commands.personalization.entities.NdefRecord
-import java.io.ByteArrayOutputStream
-import java.nio.charset.StandardCharsets
-
-/**
- * Encodes information that is to be written on the card as an Ndef Tag.
- */
-class NdefEncoder(private val ndefRecords: List, private val useDinamicNdef: Boolean) {
-
- fun encode(): ByteArray {
- val bs = ByteArrayOutputStream()
- // space for size
- bs.write(0)
- bs.write(0)
-
- for (i in ndefRecords.indices) {
- val headerValue = (if (i == 0) 0x80 else 0x00) or (if (!useDinamicNdef && i == ndefRecords.size - 1) 0x40 else 0x00)
- var value: ByteArray = ndefRecords[i].value.toByteArray(StandardCharsets.UTF_8)
- encodeValue(ndefRecords[i], headerValue, bs)
- }
-
- val result = bs.toByteArray()
- result[0] = (result.size - 2 shr 8).toByte()
- result[1] = (result.size - 2 and 0xFF).toByte()
- return result
-
- }
-
-
- private fun encodeValue(ndefRecord: NdefRecord, headerValue: Int, bs: ByteArrayOutputStream) {
- when (ndefRecord.type) {
- NdefRecord.Type.AAR -> {
- bs.write((headerValue or 0x14)) // NDEF Header
- bs.write(0x0F) // Length of the record type
- bs.write(ndefRecord.valueInBytes.size) // Length of the payload data
- bs.write(byteArrayOf(0x61.toByte(), 0x6E.toByte(), 0x64.toByte(), 0x72.toByte(), 0x6F.toByte(), 0x69.toByte(), 0x64.toByte(), 0x2E.toByte(), 0x63.toByte(), 0x6F.toByte(), 0x6D.toByte(), 0x3A.toByte(),
- 0x70.toByte(), 0x6B.toByte(), 0x67.toByte())) // type name
- bs.write(ndefRecord.valueInBytes)
- }
- NdefRecord.Type.URI -> {
- bs.write((headerValue or 0x11)) // NDEF Header
- bs.write(0x01) // Length of the record type
- val uriIdentifierCode: Byte
- val prefix: String
- when {
- ndefRecord.value.startsWith("http://www.") -> {
- uriIdentifierCode = 0x01.toByte()
- prefix = "http://www."
- }
- ndefRecord.value.startsWith("https://www.") -> {
- uriIdentifierCode = 0x02.toByte()
- prefix = "https://www."
- }
- ndefRecord.value.startsWith("http://") -> {
- uriIdentifierCode = 0x03.toByte()
- prefix = "http://"
- }
- ndefRecord.value.startsWith("https://") -> {
- uriIdentifierCode = 0x04.toByte()
- prefix = "https://"
- }
- else -> {
- throw Exception()
- }
- }
- val value = ndefRecord.value.substring(prefix.length).toByteArray()
- bs.write(value.size + 1) // Length of the payload data
- bs.write(0x55) // URI
- bs.write(uriIdentifierCode.toInt()) // ?
- bs.write(value)
- }
- NdefRecord.Type.TEXT -> {
- bs.write((headerValue or 0x11)) // NDEF Header
- bs.write(0x01) // Length of the record type
- bs.write(ndefRecord.valueInBytes.size.toByte() + 1 + "en".length) // Length of the payload data
- bs.write(0x54) // Text
- bs.write(0x02) // UTF8(MSB=0)|"en".length
- bs.write("en".toByteArray(StandardCharsets.US_ASCII))
- bs.write(ndefRecord.valueInBytes)
- }
- else -> throw Exception("Invalid NDEF record in config!")
- }
- }
-
-
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/commands/personalization/PersonalizeCommand.kt b/tangem-core/src/main/java/com/tangem/commands/personalization/PersonalizeCommand.kt
deleted file mode 100644
index 52d85278fa..0000000000
--- a/tangem-core/src/main/java/com/tangem/commands/personalization/PersonalizeCommand.kt
+++ /dev/null
@@ -1,168 +0,0 @@
-package com.tangem.commands.personalization
-
-import com.tangem.CardSession
-import com.tangem.SessionEnvironment
-import com.tangem.TangemSdkError
-import com.tangem.commands.Card
-import com.tangem.commands.CardData
-import com.tangem.commands.CardStatus
-import com.tangem.commands.Command
-import com.tangem.commands.personalization.entities.*
-import com.tangem.common.CompletionResult
-import com.tangem.common.apdu.CommandApdu
-import com.tangem.common.apdu.Instruction
-import com.tangem.common.apdu.ResponseApdu
-import com.tangem.common.extensions.calculateSha256
-import com.tangem.common.extensions.hexToBytes
-import com.tangem.common.tlv.Tlv
-import com.tangem.common.tlv.TlvBuilder
-import com.tangem.common.tlv.TlvDecoder
-import com.tangem.common.tlv.TlvTag
-import com.tangem.crypto.sign
-
-/**
- * Command available on SDK cards only
- *
- * Personalization is an initialization procedure, required before starting using a card.
- * During this procedure a card setting is set up.
- * During this procedure all data exchange is encrypted.
- * @property config is a configuration file with all the card settings that are written on the card
- * during personalization.
- * @property issuer Issuer is a third-party team or company wishing to use Tangem cards.
- * @property manufacturer Tangem Card Manufacturer.
- * @property acquirer Acquirer is a trusted third-party company that operates proprietary
- * (non-EMV) POS terminal infrastructure and transaction processing back-end.
- */
-class PersonalizeCommand(
- private val config: CardConfig,
- private val issuer: Issuer, private val manufacturer: Manufacturer,
- private val acquirer: Acquirer? = null
-) : Command() {
-
- override fun performPreCheck(session: CardSession, callback: (result: CompletionResult) -> Unit): Boolean {
- if (session.environment.card?.status != CardStatus.NotPersonalized) {
- callback(CompletionResult.Failure(TangemSdkError.AlreadyPersonalized()))
- return true
- }
- return false
- }
-
- override fun serialize(environment: SessionEnvironment): CommandApdu {
- return CommandApdu(
- Instruction.Personalize,
- serializePersonalizationData(config),
- encryptionKey = devPersonalizationKey
- )
- }
-
- override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): Card {
- val tlvData = apdu.getTlvData(devPersonalizationKey)
- ?: throw TangemSdkError.DeserializeApduFailed()
-
- val decoder = TlvDecoder(tlvData)
- return Card(
- cardId = decoder.decodeOptional(TlvTag.CardId) ?: "",
- manufacturerName = decoder.decodeOptional(TlvTag.ManufactureId) ?: "",
- status = decoder.decodeOptional(TlvTag.Status),
-
- firmwareVersion = decoder.decodeOptional(TlvTag.Firmware),
- cardPublicKey = decoder.decodeOptional(TlvTag.CardPublicKey),
- settingsMask = decoder.decodeOptional(TlvTag.SettingsMask),
- issuerPublicKey = decoder.decodeOptional(TlvTag.IssuerDataPublicKey),
- curve = decoder.decodeOptional(TlvTag.CurveId),
- maxSignatures = decoder.decodeOptional(TlvTag.MaxSignatures),
- signingMethods = decoder.decodeOptional(TlvTag.SigningMethod),
- pauseBeforePin2 = decoder.decodeOptional(TlvTag.PauseBeforePin2),
- walletPublicKey = decoder.decodeOptional(TlvTag.WalletPublicKey),
- walletRemainingSignatures = decoder.decodeOptional(TlvTag.RemainingSignatures),
- walletSignedHashes = decoder.decodeOptional(TlvTag.SignedHashes),
- health = decoder.decodeOptional(TlvTag.Health),
- isActivated = decoder.decode(TlvTag.IsActivated),
- activationSeed = decoder.decodeOptional(TlvTag.ActivationSeed),
- paymentFlowVersion = decoder.decodeOptional(TlvTag.PaymentFlowVersion),
- userCounter = decoder.decodeOptional(TlvTag.UserCounter),
- userProtectedCounter = decoder.decodeOptional(TlvTag.UserProtectedCounter),
- terminalIsLinked = decoder.decode(TlvTag.TerminalIsLinked),
-
- cardData = deserializeCardData(tlvData)
- )
- }
-
- private fun deserializeCardData(tlvData: List): CardData? {
- val cardDataTlvs = tlvData.find { it.tag == TlvTag.CardData }?.let {
- Tlv.deserialize(it.value)
- }
- if (cardDataTlvs.isNullOrEmpty()) return null
-
- val decoder = TlvDecoder(cardDataTlvs)
- return CardData(
- batchId = decoder.decodeOptional(TlvTag.Batch),
- manufactureDateTime = decoder.decodeOptional(TlvTag.ManufactureDateTime),
- issuerName = decoder.decodeOptional(TlvTag.IssuerId),
- blockchainName = decoder.decodeOptional(TlvTag.BlockchainId),
- manufacturerSignature = decoder.decodeOptional(TlvTag.ManufacturerSignature),
- productMask = decoder.decodeOptional(TlvTag.ProductMask),
-
- tokenSymbol = decoder.decodeOptional(TlvTag.TokenSymbol),
- tokenContractAddress = decoder.decodeOptional(TlvTag.TokenContractAddress),
- tokenDecimal = decoder.decodeOptional(TlvTag.TokenDecimal)
- )
- }
-
- private fun serializePersonalizationData(config: CardConfig): ByteArray {
- val cardId = config.createCardId() ?: throw TangemSdkError.SerializeCommandError()
-
- val tlvBuilder = TlvBuilder()
- tlvBuilder.append(TlvTag.CardId, cardId)
- tlvBuilder.append(TlvTag.CurveId, config.curveID)
- tlvBuilder.append(TlvTag.MaxSignatures, config.maxSignatures)
- tlvBuilder.append(TlvTag.SigningMethod, config.signingMethods)
- tlvBuilder.append(TlvTag.SettingsMask, config.createSettingsMask())
- tlvBuilder.append(TlvTag.PauseBeforePin2, config.pauseBeforePin2 / 10)
- tlvBuilder.append(TlvTag.Cvc, config.cvc.toByteArray())
- if (!config.ndefRecords.isNullOrEmpty())
- tlvBuilder.append(TlvTag.NdefData, serializeNdef(config))
-
- tlvBuilder.append(TlvTag.CreateWalletAtPersonalize, config.createWallet)
-
- tlvBuilder.append(TlvTag.NewPin, config.pin)
- tlvBuilder.append(TlvTag.NewPin2, config.pin2)
- tlvBuilder.append(TlvTag.NewPin3, config.pin3)
- tlvBuilder.append(TlvTag.CrExKey, config.hexCrExKey)
- tlvBuilder.append(TlvTag.IssuerDataPublicKey, issuer.dataKeyPair.publicKey)
- tlvBuilder.append(TlvTag.IssuerTransactionPublicKey, issuer.transactionKeyPair.publicKey)
-
- tlvBuilder.append(TlvTag.AcquirerPublicKey, acquirer?.keyPair?.publicKey)
-
- tlvBuilder.append(TlvTag.CardData, serializeCardData(cardId, config.cardData))
- return tlvBuilder.serialize()
- }
-
- private fun serializeNdef(config: CardConfig): ByteArray {
- return NdefEncoder(config.ndefRecords, config.useDynamicNdef).encode()
- }
-
- private fun serializeCardData(cardId: String, cardData: CardData): ByteArray {
- val tlvBuilder = TlvBuilder()
- tlvBuilder.append(TlvTag.Batch, cardData.batchId)
- tlvBuilder.append(TlvTag.ProductMask, cardData.productMask)
- tlvBuilder.append(TlvTag.ManufactureDateTime, cardData.manufactureDateTime)
- tlvBuilder.append(TlvTag.IssuerId, issuer.id)
- tlvBuilder.append(TlvTag.BlockchainId, cardData.blockchainName)
-
- if (cardData.tokenSymbol != null) {
- tlvBuilder.append(TlvTag.TokenSymbol, cardData.tokenSymbol)
- tlvBuilder.append(TlvTag.TokenContractAddress, cardData.tokenContractAddress)
- tlvBuilder.append(TlvTag.TokenDecimal, cardData.tokenDecimal)
- }
- tlvBuilder.append(
- TlvTag.CardIdManufacturerSignature,
- cardId.hexToBytes().sign(manufacturer.keyPair.privateKey)
- )
- return tlvBuilder.serialize()
- }
-
- companion object {
- val devPersonalizationKey = "1234".calculateSha256().copyOf(32)
- }
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/commands/personalization/entities/Acquirer.kt b/tangem-core/src/main/java/com/tangem/commands/personalization/entities/Acquirer.kt
deleted file mode 100644
index ec4cff04b0..0000000000
--- a/tangem-core/src/main/java/com/tangem/commands/personalization/entities/Acquirer.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-package com.tangem.commands.personalization.entities
-
-import com.tangem.KeyPair
-
-data class Acquirer(
- val keyPair: KeyPair,
- val name: String? = null,
- val id: String? = null
-)
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/commands/personalization/entities/CardConfig.kt b/tangem-core/src/main/java/com/tangem/commands/personalization/entities/CardConfig.kt
deleted file mode 100644
index 4417374a87..0000000000
--- a/tangem-core/src/main/java/com/tangem/commands/personalization/entities/CardConfig.kt
+++ /dev/null
@@ -1,71 +0,0 @@
-package com.tangem.commands.personalization.entities
-
-import com.tangem.commands.CardData
-import com.tangem.commands.EllipticCurve
-import com.tangem.commands.SigningMethodMask
-
-data class NdefRecord(
- val type: Type,
- val value: String
-) {
- enum class Type {
- URI, AAR, TEXT
- }
-
- @delegate:Transient
- val valueInBytes: ByteArray by lazy { value.toByteArray() }
-}
-
-/**
- * It is a configuration file with all the card settings that are written on the card
- * during [PersonalizeCommand].
- */
-data class CardConfig(
- val issuerName: String? = null,
- val acquirerName: String? = null,
- val series: String? = null,
- val startNumber: Long = 0,
- val count: Int = 0,
- val pin: String,
- val pin2: String,
- val pin3: String,
- val hexCrExKey: String?,
- val cvc: String,
- val pauseBeforePin2: Int,
- val smartSecurityDelay: Boolean,
- val curveID: EllipticCurve,
- val signingMethods: SigningMethodMask,
- val maxSignatures: Int,
- val isReusable: Boolean,
- val allowSwapPin: Boolean,
- val allowSwapPin2: Boolean,
- val useActivation: Boolean,
- val useCvc: Boolean,
- val useNdef: Boolean,
- val useDynamicNdef: Boolean,
- val useOneCommandAtTime: Boolean,
- val useBlock: Boolean,
- val allowSelectBlockchain: Boolean,
- val forbidPurgeWallet: Boolean,
- val protocolAllowUnencrypted: Boolean,
- val protocolAllowStaticEncryption: Boolean,
- val protectIssuerDataAgainstReplay: Boolean,
- val forbidDefaultPin: Boolean,
- val disablePrecomputedNdef: Boolean,
- val skipSecurityDelayIfValidatedByIssuer: Boolean,
- val skipCheckPIN2andCVCIfValidatedByIssuer: Boolean,
- val skipSecurityDelayIfValidatedByLinkedTerminal: Boolean,
-
- val restrictOverwriteIssuerDataEx: Boolean,
-
- val requireTerminalTxSignature: Boolean,
- val requireTerminalCertSignature: Boolean,
- val checkPin3onCard: Boolean,
-
- val createWallet: Boolean,
-
- val cardData: CardData,
- val ndefRecords: List
-) {
- companion object
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/commands/personalization/entities/CardConfigExtensions.kt b/tangem-core/src/main/java/com/tangem/commands/personalization/entities/CardConfigExtensions.kt
deleted file mode 100644
index 78e5709596..0000000000
--- a/tangem-core/src/main/java/com/tangem/commands/personalization/entities/CardConfigExtensions.kt
+++ /dev/null
@@ -1,81 +0,0 @@
-package com.tangem.commands.personalization.entities
-
-import com.tangem.commands.Settings
-import com.tangem.commands.SettingsMask
-import com.tangem.commands.SettingsMaskBuilder
-
-internal fun CardConfig.createSettingsMask(): SettingsMask {
- val builder = SettingsMaskBuilder()
-
- if (allowSwapPin) builder.add(Settings.AllowSwapPIN)
- if (allowSwapPin2) builder.add(Settings.AllowSwapPIN2)
- if (useCvc) builder.add(Settings.UseCVC)
- if (isReusable) builder.add(Settings.IsReusable)
-
- if (useOneCommandAtTime) builder.add(Settings.UseOneCommandAtTime)
- if (useNdef) builder.add(Settings.UseNdef)
- if (useDynamicNdef) builder.add(Settings.UseDynamicNdef)
- if (disablePrecomputedNdef) builder.add(Settings.DisablePrecomputedNdef)
-
- if (protocolAllowUnencrypted) builder.add(Settings.ProtocolAllowUnencrypted)
- if (protocolAllowStaticEncryption) builder.add(Settings.ProtocolAllowStaticEncryption)
-
- if (forbidDefaultPin) builder.add(Settings.ForbidDefaultPIN)
-
- if (useActivation) builder.add(Settings.UseActivation)
-
- if (useBlock) builder.add(Settings.UseBlock)
- if (smartSecurityDelay) builder.add(Settings.SmartSecurityDelay)
-
- if (protectIssuerDataAgainstReplay) builder.add(Settings.ProtectIssuerDataAgainstReplay)
-
- if (forbidPurgeWallet) builder.add(Settings.ProhibitPurgeWallet)
- if (allowSelectBlockchain) builder.add(Settings.AllowSelectBlockchain)
-
- if (skipCheckPIN2andCVCIfValidatedByIssuer) builder.add(Settings.SkipCheckPin2andCvcIfValidatedByIssuer)
- if (skipSecurityDelayIfValidatedByIssuer) builder.add(Settings.SkipSecurityDelayIfValidatedByIssuer)
-
- if (skipSecurityDelayIfValidatedByLinkedTerminal) builder.add(Settings.SkipSecurityDelayIfValidatedByLinkedTerminal)
- if (restrictOverwriteIssuerDataEx) builder.add(Settings.RestrictOverwriteIssuerDataEx)
-
- if (requireTerminalTxSignature) builder.add(Settings.RequireTermTxSignature)
-
- if (requireTerminalCertSignature) builder.add(Settings.RequireTermCertSignature)
-
- if (checkPin3onCard) builder.add(Settings.CheckPIN3onCard)
-
- return builder.build()
-}
-
-internal fun CardConfig.createCardId(): String? {
- if (series == null) return null
- if (startNumber <= 0 || (series.length != 2 && series.length != 4)) return null
-
- val Alf = "ABCDEF0123456789"
- fun checkSeries(series: String): Boolean {
- val containsList = series.filter { Alf.contains(it) }
- return containsList.length == series.length
- }
- if (!checkSeries(series)) return null
-
- val tail = if (series.length == 2) String.format("%013d", startNumber) else String.format("%011d", startNumber)
- var cardId = (series + tail).replace(" ", "")
- if (cardId.length != 15 || Alf.indexOf(cardId[0]) == -1 || Alf.indexOf(cardId[1]) == -1)
- return null
-
- cardId += "0"
- val length = cardId.length
- var sum = 0
- for (i in 0 until length) {
- // get digits in reverse order
- var digit: Int
- val cDigit = cardId[length - i - 1]
- digit = if (cDigit in '0'..'9') cDigit - '0' else cDigit - 'A'
-
- // every 2nd number multiply with 2
- if (i % 2 == 1) digit *= 2
- sum += if (digit > 9) digit - 9 else digit
- }
- val lunh = (10 - sum % 10) % 10
- return cardId.substring(0, 15) + String.format("%d", lunh)
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/commands/personalization/entities/Issuer.kt b/tangem-core/src/main/java/com/tangem/commands/personalization/entities/Issuer.kt
deleted file mode 100644
index ee7ab58fa7..0000000000
--- a/tangem-core/src/main/java/com/tangem/commands/personalization/entities/Issuer.kt
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.tangem.commands.personalization.entities
-
-import com.tangem.KeyPair
-
-data class Issuer(
- val name: String,
- val id: String,
- val dataKeyPair: KeyPair,
- val transactionKeyPair: KeyPair
-)
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/commands/personalization/entities/Manufacturer.kt b/tangem-core/src/main/java/com/tangem/commands/personalization/entities/Manufacturer.kt
deleted file mode 100644
index 9e30287bb0..0000000000
--- a/tangem-core/src/main/java/com/tangem/commands/personalization/entities/Manufacturer.kt
+++ /dev/null
@@ -1,8 +0,0 @@
-package com.tangem.commands.personalization.entities
-
-import com.tangem.KeyPair
-
-data class Manufacturer(
- val keyPair: KeyPair,
- val name: String? = null
-)
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/common/CompletionResult.kt b/tangem-core/src/main/java/com/tangem/common/CompletionResult.kt
deleted file mode 100644
index 52bf7a9351..0000000000
--- a/tangem-core/src/main/java/com/tangem/common/CompletionResult.kt
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.tangem.common
-
-import com.tangem.TangemSdkError
-import com.tangem.common.CompletionResult.Success
-
-/**
- * Response class encapsulating successful and failed results.
- * @param T Type of data that is returned in [Success].
- */
-sealed class CompletionResult {
- class Success(val data: T) : CompletionResult()
- class Failure(val error: TangemSdkError) : CompletionResult()
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/common/TerminalKeysService.kt b/tangem-core/src/main/java/com/tangem/common/TerminalKeysService.kt
deleted file mode 100644
index 3ba365247d..0000000000
--- a/tangem-core/src/main/java/com/tangem/common/TerminalKeysService.kt
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.tangem.common
-
-import com.tangem.KeyPair
-
-/**
- * Interface for a service for managing Terminal keypair, used for Linked Terminal feature.
- * Its implementation Needs to be provided to [com.tangem.TangemSdk]
- * by calling [com.tangem.TangemSdk.setTerminalKeysService].
- * Default implementation is provided in tangem-sdk module: [TerminalKeysStorage].
- * Linked Terminal feature can be disabled manually by editing [com.tangem.Config].
- */
-interface TerminalKeysService {
- fun getKeys(): KeyPair
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/common/apdu/CommandApdu.kt b/tangem-core/src/main/java/com/tangem/common/apdu/CommandApdu.kt
deleted file mode 100644
index e2d37df4bb..0000000000
--- a/tangem-core/src/main/java/com/tangem/common/apdu/CommandApdu.kt
+++ /dev/null
@@ -1,98 +0,0 @@
-package com.tangem.common.apdu
-
-import com.tangem.EncryptionMode
-import com.tangem.common.extensions.calculateCrc16
-import com.tangem.common.extensions.toByteArray
-import com.tangem.crypto.encrypt
-import java.io.ByteArrayOutputStream
-
-/**
- * Class that provides conversion of serialized request and Instruction code
- * to a raw data that can be sent to the card.
- *
- * @property ins Instruction code that determines the type of request for the card.
- * @property tlvs Tlvs encoded to a [ByteArray] that are to be sent to the card.
- */
-class CommandApdu(
-
- private val ins: Int,
- private val tlvs: ByteArray,
-
- private val le: Int = 0x00,
-
- private val encryptionMode: EncryptionMode = EncryptionMode.NONE,
- private val encryptionKey: ByteArray? = null,
-
- private val cla: Int = ISO_CLA) {
-
- constructor(
- instruction: Instruction,
- tlvs: ByteArray,
- encryptionMode: EncryptionMode = EncryptionMode.NONE,
- encryptionKey: ByteArray? = null
- ) : this(
- instruction.code,
- tlvs,
- encryptionMode = encryptionMode,
- encryptionKey = encryptionKey
- )
-
- private val p1: Int
- private val p2: Int
-
- init {
- if (ins == Instruction.OpenSession.code) {
- p1 = 0x00
- p2 = encryptionMode.code.toInt()
- } else {
- p1 = encryptionMode.code.toInt()
- p2 = 0x00
- }
- }
-
-
- /**
- * Request converted to a raw data
- */
- val apduData: ByteArray
-
- init {
- apduData = toBytes()
- }
-
-
- private fun toBytes(): ByteArray {
- val data = if (encryptionKey != null) tlvs.encrypt() else tlvs
-
- val byteStream = ByteArrayOutputStream()
- byteStream.write(cla)
- byteStream.write(ins)
- byteStream.write(p1)
- byteStream.write(p2)
- if (data.isNotEmpty()) {
- byteStream.writeLength(data.size)
- byteStream.write(data)
- }
- return byteStream.toByteArray()
- }
-
- private fun ByteArrayOutputStream.writeLength(lc: Int) {
- this.write(0)
- this.write(lc shr 8)
- this.write(lc and 0xFF)
- }
-
-
- private fun ByteArray.encrypt(): ByteArray {
- val crc: ByteArray = tlvs.calculateCrc16()
- val stream = ByteArrayOutputStream()
- stream.write(this.size.toByteArray(2))
- stream.write(crc)
- stream.write(this)
- return stream.toByteArray().encrypt(encryptionKey!!)
- }
-
- companion object {
- const val ISO_CLA = 0x00
- }
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/common/apdu/Instruction.kt b/tangem-core/src/main/java/com/tangem/common/apdu/Instruction.kt
deleted file mode 100644
index 46c8989535..0000000000
--- a/tangem-core/src/main/java/com/tangem/common/apdu/Instruction.kt
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.tangem.common.apdu
-
-/**
- * Instruction code that determines the type of the command that is sent to the Tangem card.
- * It is used in the construction of [com.tangem.common.apdu.CommandApdu].
- */
-enum class Instruction(var code: Int) {
- Unknown(0x00),
- Personalize(0xF1),
- Read(0xF2),
- VerifyCard(0xF3),
- ValidateCard(0xF4),
- VerifyCode(0xF5),
- WriteIssuerData(0xF6),
- ReadIssuerData(0xF7),
- CreateWallet(0xF8),
- CheckWallet(0xF9),
- SwapPIN(0xFA),
- Sign(0xFB),
- PurgeWallet(0xFC),
- Activate(0xFE),
- OpenSession(0xFF),
- WriteUserData(0xE0),
- ReadUserData(0xE1),
- Depersonalize(0xE3);
-
-
- companion object {
- private val values = values()
- fun byCode(code: Int): Instruction = values.find { it.code == code } ?: Unknown
- }
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/common/apdu/ResponseApdu.kt b/tangem-core/src/main/java/com/tangem/common/apdu/ResponseApdu.kt
deleted file mode 100644
index e7e8625384..0000000000
--- a/tangem-core/src/main/java/com/tangem/common/apdu/ResponseApdu.kt
+++ /dev/null
@@ -1,66 +0,0 @@
-package com.tangem.common.apdu
-
-import com.tangem.common.extensions.calculateCrc16
-import com.tangem.common.tlv.Tlv
-import com.tangem.crypto.decrypt
-import java.io.ByteArrayInputStream
-
-/**
- * Stores response data from the card and parses it to [Tlv] and [StatusWord].
- *
- * @property data Raw response from the card.
- * @property sw Status word code, reflecting the status of the response.
- * @property statusWord Parsed status word.
- */
-class ResponseApdu(private val data: ByteArray) {
-
- private val sw1: Int = 0x00FF and data[data.size - 2].toInt()
- private val sw2: Int = 0x00FF and data[data.size - 1].toInt()
-
- val sw: Int = sw1 shl 8 or sw2
-
- val statusWord: StatusWord = StatusWord.byCode(sw)
-
- /**
- * Converts raw response data to the list of TLVs.
- *
- * @param encryptionKey key to decrypt response.
- * (Encryption / decryption functionality is not implemented yet.)
- */
- fun getTlvData(encryptionKey: ByteArray? = null): List? {
- return if (data.size <= 2) {
- null
- } else {
- val responseData = data.copyOf(data.size - 2)
- return if (encryptionKey != null) {
- if (data.size >= 18) {
- val decryptedData = decrypt(responseData, encryptionKey)
- Tlv.deserialize(decryptedData)
- } else {
- null
- }
- } else {
- Tlv.deserialize(responseData)
- }
- }
- }
-
- private fun decrypt(responseData: ByteArray, encryptionKey: ByteArray): ByteArray {
- val decryptedData: ByteArray = responseData.decrypt(encryptionKey)
-
- val inputStream = ByteArrayInputStream(decryptedData)
- val baLength = ByteArray(2)
- inputStream.read(baLength)
- val length = (baLength[0].toInt() and 0xFF) * 256 + (baLength[1].toInt() and 0xFF)
- if (length > decryptedData.size - 4) throw Exception("Can't decrypt - data size invalid")
- val baCRC = ByteArray(2)
- inputStream.read(baCRC)
- val answerData = ByteArray(length)
- inputStream.read(answerData)
- val crc: ByteArray = answerData.calculateCrc16()
- if (!baCRC.contentEquals(crc)) throw Exception("Can't decrypt - crc invalid")
-
- return answerData
- }
-
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/common/apdu/StatusWord.kt b/tangem-core/src/main/java/com/tangem/common/apdu/StatusWord.kt
deleted file mode 100644
index 96daaa2826..0000000000
--- a/tangem-core/src/main/java/com/tangem/common/apdu/StatusWord.kt
+++ /dev/null
@@ -1,40 +0,0 @@
-package com.tangem.common.apdu
-
-import com.tangem.TangemSdkError
-
-/**
- * Part of a response from the card, shows the status of the operation
- */
-enum class StatusWord(val code: Int, val description: String) {
-
- ProcessCompleted(0x9000, "SW_PROCESS_COMPLETED"),
- InvalidParams(0x6A86, "SW_INVALID_PARAMS"),
- ErrorProcessingCommand(0x6286, "SW_ERROR_PROCESSING_COMMAND"),
- InvalidState(0x6985, "SW_INVALID_STATE"),
- Pin1Changed(ProcessCompleted.code + 0x0001, "SW_PIN1_CHANGED"),
- Pin2Changed(ProcessCompleted.code + 0x0002, "SW_PIN2_CHANGED"),
- PinsChanged(ProcessCompleted.code + 0x0003, "SW_PINS_CHANGED"),
- InsNotSupported(0x6D00, "SW_INS_NOT_SUPPORTED"),
- NeedEncryption(0x6982, "SW_NEED_ENCRYPTION"),
- NeedPause(0x9789, "SW_NEED_PAUSE"),
- Unknown(0x0000, "SW_UNKNOWN");
-
- companion object {
- private val values = values()
- fun byCode(code: Int): StatusWord = values.find { it.code == code } ?: Unknown
- }
-}
-
-fun StatusWord.toTangemSdkError(): TangemSdkError? {
- return when (this) {
- StatusWord.ProcessCompleted, StatusWord.Pin1Changed,
- StatusWord.Pin2Changed, StatusWord.PinsChanged -> null
- StatusWord.NeedPause -> null
- StatusWord.InvalidParams -> TangemSdkError.InvalidParams()
- StatusWord.ErrorProcessingCommand -> TangemSdkError.ErrorProcessingCommand()
- StatusWord.InvalidState -> TangemSdkError.InvalidState()
- StatusWord.InsNotSupported -> TangemSdkError.InsNotSupported()
- StatusWord.NeedEncryption -> TangemSdkError.NeedEncryption()
- StatusWord.Unknown -> TangemSdkError.UnknownStatus()
- }
-}
diff --git a/tangem-core/src/main/java/com/tangem/common/extensions/BigDecimal.kt b/tangem-core/src/main/java/com/tangem/common/extensions/BigDecimal.kt
deleted file mode 100644
index 6d23ffee09..0000000000
--- a/tangem-core/src/main/java/com/tangem/common/extensions/BigDecimal.kt
+++ /dev/null
@@ -1,7 +0,0 @@
-package com.tangem.common.extensions
-
-import java.math.BigDecimal
-
-fun BigDecimal.isZero() : Boolean {
- return this.compareTo(BigDecimal.ZERO) == 0
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/common/extensions/ByteArray.kt b/tangem-core/src/main/java/com/tangem/common/extensions/ByteArray.kt
deleted file mode 100644
index ac201f5fcb..0000000000
--- a/tangem-core/src/main/java/com/tangem/common/extensions/ByteArray.kt
+++ /dev/null
@@ -1,74 +0,0 @@
-package com.tangem.common.extensions
-
-import org.spongycastle.crypto.digests.RIPEMD160Digest
-import org.spongycastle.jce.ECNamedCurveTable
-import java.nio.ByteBuffer
-import java.security.MessageDigest
-import java.util.*
-import kotlin.experimental.and
-import kotlin.experimental.xor
-
-/**
- * Extension functions for [ByteArray].
- */
-
-fun ByteArray.toHexString(): String = joinToString("") { "%02x".format(it) }
-
-fun ByteArray.toUtf8(): String = String(this).removeSuffix("\u0000")
-
-fun ByteArray.toInt(): Int {
- return when (this.size) {
- 1 -> (this[0] and 0xFF.toByte()).toInt()
- 2 -> ByteBuffer.wrap(this).short.toInt()
- 4 -> ByteBuffer.wrap(this).int
- else -> throw IllegalArgumentException("Length must be 1,2 or 4. Length = " + this.size)
- }
-}
-
-fun ByteArray.toDate(): Date {
- val year = copyOfRange(0, 2).toInt()
- val month = if (this.size > 2) this[2] - 1 else 0
- val day = if (this.size > 3) this[3].toInt() else 0
- val cd = Calendar.getInstance()
- cd.set(year, month, day, 0, 0, 0)
- return cd.time
-}
-
-fun ByteArray.calculateSha512(): ByteArray = MessageDigest.getInstance("SHA-512").digest(this)
-
-fun ByteArray.calculateSha256(): ByteArray = MessageDigest.getInstance("SHA-256").digest(this)
-
-fun ByteArray.calculateRipemd160(): ByteArray {
- val digest = RIPEMD160Digest()
- digest.update(this, 0, this.size)
- val out = ByteArray(20)
- digest.doFinal(out, 0)
- return out
-}
-
-fun ByteArray.toCompressedPublicKey(): ByteArray {
- return if (this.size == 65) {
- val spec = ECNamedCurveTable.getParameterSpec("secp256k1")
- val publicKeyPoint = spec.curve.decodePoint(this)
- publicKeyPoint.getEncoded(true)
- } else {
- this
- }
-}
-
-fun ByteArray.calculateCrc16(): ByteArray {
- var chBlock: Byte
- // STEP 1 Initialize the CRC-16 value
- var wCRC = 0x6363 // ITU-V.41
- var i = 0
- // STEP 2 Update data and Calucuate their CRC
- do {
- chBlock = this.get(i++)
- chBlock = chBlock xor (wCRC and 0x00FF).toByte()
- val chBlockInt = (chBlock.toInt() xor (chBlock.toInt() shl 4))
- wCRC = wCRC shr 8 xor (chBlockInt and 0xFF shl 8) and 0xFFFF xor (chBlockInt and 0xFF shl 3 and 0xFFFF) xor (chBlockInt and 0xFF shr 4 and 0xFFFF)
- // (wCRC>>8)^((int)chBlock<<8)^((int) chBlock<<3)^((int)chBlock>>4);
- } while (i < this.size)
-
- return byteArrayOf((wCRC and 0xFF).toByte(), (wCRC and 0xFFFF shr 8).toByte())
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/common/extensions/Card.kt b/tangem-core/src/main/java/com/tangem/common/extensions/Card.kt
deleted file mode 100644
index 97243f3655..0000000000
--- a/tangem-core/src/main/java/com/tangem/common/extensions/Card.kt
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.tangem.common.extensions
-
-import com.tangem.commands.Card
-
-fun Card.getType(): CardType {
- val firmware = this.firmwareVersion ?: return CardType.Unknown
- return when {
- firmware.endsWith("d SDK") -> {
- CardType.Sdk
- }
- firmware.endsWith("r") -> {
- CardType.Release
- }
- else -> {
- CardType.Unknown
- }
- }
-}
-
-enum class CardType {
- Sdk, Release, Unknown
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/common/extensions/IntExtensions.kt b/tangem-core/src/main/java/com/tangem/common/extensions/IntExtensions.kt
deleted file mode 100644
index 0e8aa998da..0000000000
--- a/tangem-core/src/main/java/com/tangem/common/extensions/IntExtensions.kt
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.tangem.common.extensions
-
-import java.nio.ByteBuffer
-
-fun Int.toByteArray(size: Int = Int.SIZE_BYTES): ByteArray {
- if (size == Int.SIZE_BYTES) {
- val buffer = ByteBuffer.allocate(size)
- buffer.putInt(this)
- return buffer.array()
- } else if (size == Short.SIZE_BYTES){
- return byteArrayOf(
- (this ushr 8).toByte(),
- this.toByte())
- }
- return byteArrayOf()
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/common/extensions/List.kt b/tangem-core/src/main/java/com/tangem/common/extensions/List.kt
deleted file mode 100644
index 2579809de6..0000000000
--- a/tangem-core/src/main/java/com/tangem/common/extensions/List.kt
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.tangem.common.extensions
-
-fun List.print(delimiter: String = ", ", wrap: Boolean = true): String {
- val builder = StringBuilder()
- forEach { builder.append(it).append(delimiter) }
- val length = builder.length
- if (length > delimiter.length) {
- builder.delete(length - delimiter.length, length)
- }
- val result = builder.toString()
-
- return if (wrap) "[$result]" else result
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/common/extensions/String.kt b/tangem-core/src/main/java/com/tangem/common/extensions/String.kt
deleted file mode 100644
index fbddb5829c..0000000000
--- a/tangem-core/src/main/java/com/tangem/common/extensions/String.kt
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.tangem.common.extensions
-
-import java.nio.charset.Charset
-import java.security.MessageDigest
-
-/**
- * Extension functions for [String].
- */
-fun String.calculateSha256(): ByteArray {
- val sha256 = MessageDigest.getInstance("SHA-256")
- val data = this.toByteArray(Charset.forName("UTF-8"))
- return sha256.digest(data)
-}
-
-fun String.calculateSha512(): ByteArray {
- val sha = MessageDigest.getInstance("SHA-512")
- val data = this.toByteArray(Charset.forName("UTF-8"))
- return sha.digest(data)
-}
-
-fun String.hexToBytes(): ByteArray {
- return ByteArray(this.length / 2)
- { i ->
- Integer.parseInt(this.substring(2 * i, 2 * i + 2), 16).toByte()
- }
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/common/tlv/Tlv.kt b/tangem-core/src/main/java/com/tangem/common/tlv/Tlv.kt
deleted file mode 100644
index 5b0f5a47c5..0000000000
--- a/tangem-core/src/main/java/com/tangem/common/tlv/Tlv.kt
+++ /dev/null
@@ -1,105 +0,0 @@
-package com.tangem.common.tlv
-
-import com.tangem.Log
-import com.tangem.common.extensions.toHexString
-import java.io.ByteArrayInputStream
-import java.io.IOException
-
-/**
- * The data converted to the Tag Length Value protocol.
- */
-class Tlv {
-
- val tag: TlvTag
- val value: ByteArray
- val tagRaw: Int
-
- constructor(tagCode: Int, value: ByteArray = byteArrayOf()) {
- this.tag = TlvTag.byCode(tagCode)
- this.tagRaw = tagCode
- this.value = value
- }
-
- constructor(tag: TlvTag, value: ByteArray = byteArrayOf()) {
- this.tag = tag
- this.tagRaw = tag.code
- this.value = value
- }
-
-
- companion object {
- private fun tlvFromBytes(stream: ByteArrayInputStream): Tlv? {
- val code = stream.read()
- if (code == -1) return null
- var len = stream.read()
- if (len == -1)
- throw IOException("Can't read TLV")
- if (len == 0xFF) {
- val lenH = stream.read()
- if (lenH == -1)
- throw IOException("Can't read TLV")
- len = stream.read()
- if (len == -1)
- throw IOException("Can't read TLV")
- len = len or (lenH shl 8)
- }
- val value = ByteArray(len)
- if (len > 0) {
- if (len != stream.read(value)) {
- throw IOException("Can't read TLV")
- }
- }
- val tag = TlvTag.byCode(code)
- return if (tag == TlvTag.Unknown) Tlv(code, value) else Tlv(tag, value)
- }
-
-
- fun deserialize(data: ByteArray, nfcV: Boolean = false): List? {
- val tlvList = mutableListOf()
- val stream = ByteArrayInputStream(data)
- var tlv: Tlv?
- do {
- try {
- tlv = tlvFromBytes(stream)
- if (tlv != null) tlvList.add(tlv)
- } catch (e: IOException) {
- Log.e(this::class.java.simpleName,"TLVError: " + e.message)
- if (nfcV) break else return null
- }
-
- } while (tlv != null)
- return tlvList
- }
- }
-
- override fun toString(): String {
- return "${this.tag} ($tagRaw): ${value.toHexString()}"
- }
-
-}
-
-fun List.serialize(): ByteArray =
- this.map { it.serialize() }.reduce { arr1, arr2 -> arr1 + arr2 }
-
-fun Tlv.serialize(): ByteArray {
- val tag = byteArrayOf(this.tag.code.toByte())
- val length = getLengthInBytes(this.value.size)
- val value = if (this.value.isNotEmpty()) this.value else byteArrayOf(0x00)
- return tag + length + value
-}
-
-private fun getLengthInBytes(tlvLength: Int): ByteArray {
- return if (tlvLength > 0) {
- if (tlvLength > 0xFE) {
- byteArrayOf(
- 0xFF.toByte(),
- (tlvLength shr 8 and 0xFF).toByte(),
- (tlvLength and 0xFF).toByte()
- )
- } else {
- byteArrayOf((tlvLength and 0xFF).toByte())
- }
- } else {
- byteArrayOf()
- }
-}
\ No newline at end of file
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
deleted file mode 100644
index 8c7ec12fad..0000000000
--- a/tangem-core/src/main/java/com/tangem/common/tlv/TlvBuilder.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.tangem.common.tlv
-
-import com.tangem.Log
-
-class TlvBuilder {
- private val tlvs = mutableListOf()
- private val encoder = TlvEncoder()
-
- internal inline fun append(tag: TlvTag, value: T?) {
- if (value == null) return
-
- tlvs.add(encoder.encode(tag, value))
- }
-
- fun serialize(): ByteArray {
- Log.v("TLV",
- "Data encoded to TLVs:\n${tlvs.joinToString("\n")}")
- return tlvs.serialize()
- }
-
-}
\ No newline at end of file
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
deleted file mode 100644
index 866fbbd41c..0000000000
--- a/tangem-core/src/main/java/com/tangem/common/tlv/TlvDecoder.kt
+++ /dev/null
@@ -1,162 +0,0 @@
-package com.tangem.common.tlv
-
-import com.tangem.Log
-import com.tangem.TangemSdkError
-import com.tangem.commands.*
-import com.tangem.commands.common.IssuerDataMode
-import com.tangem.common.extensions.toDate
-import com.tangem.common.extensions.toHexString
-import com.tangem.common.extensions.toInt
-import com.tangem.common.extensions.toUtf8
-import java.util.*
-
-/**
- * Maps value fields in [Tlv] from raw [ByteArray] to concrete classes
- * according to their [TlvTag] and corresponding [TlvValueType].
- *
- * @property tlvList List of TLVs, which values are to be converted to particular classes.
- */
-class TlvDecoder(val tlvList: List) {
-
- init {
- Log.v("TLV",
- "Decoding data from TLV:\n${tlvList.joinToString("\n")}")
- }
-
- /**
- * Finds [Tlv] by its [TlvTag].
- * Returns null if [Tlv] is not found, otherwise converts its value to [T].
- *
- * @param tag [TlvTag] of a [Tlv] which value is to be returned.
- *
- * @return Value converted to a nullable type [T].
- */
- inline fun decodeOptional(tag: TlvTag): T? =
- try {
- decode(tag, false)
- } catch (exception: TangemSdkError.DecodingFailedMissingTag) {
- null
- }
-
- /**
- * Finds [Tlv] by its [TlvTag].
- * Throws [TaskError.MissingTag] if [Tlv] is not found,
- * otherwise converts [Tlv] value to [T].
- *
- * @param tag [TlvTag] of a [Tlv] which value is to be returned.
- *
- * @return [Tlv] value converted to a nullable type [T].
- *
- * @throws [TangemSdkError.DecodingFailedMissingTag] exception if no [Tlv] is found by the Tag.
- */
- 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 {
- if (logError) {
- Log.e(this::class.simpleName!!, "TLV $tag not found")
- } else {
- Log.v(this::class.simpleName!!, "TLV $tag not found, but it is not required")
- }
- throw TangemSdkError.DecodingFailedMissingTag()
- }
-
- return when (tag.valueType()) {
- TlvValueType.HexString, TlvValueType.HexStringToHash -> {
- typeCheck(tag)
- tlvValue.toHexString() as T
- }
- TlvValueType.Utf8String -> {
- typeCheck(tag)
- tlvValue.toUtf8() as T
- }
- TlvValueType.Uint16, TlvValueType.Uint32 -> {
- typeCheck(tag)
- try {
- tlvValue.toInt() as T
- } catch (exception: IllegalArgumentException) {
- Log.e(this::class.simpleName!!, exception.message ?: "")
- throw TangemSdkError.DecodingFailed()
- }
- }
- TlvValueType.BoolValue -> {
- typeCheck(tag)
- true as T
- }
- TlvValueType.ByteArray -> {
- typeCheck(tag)
- tlvValue as T
- }
- TlvValueType.EllipticCurve -> {
- typeCheck(tag)
- try {
- EllipticCurve.byName(tlvValue.toUtf8()) as T
- } catch (exception: Exception) {
- logException(tag, tlvValue.toUtf8(), exception)
- throw TangemSdkError.DecodingFailed()
- }
-
-
- }
- TlvValueType.DateTime -> {
- typeCheck(tag)
- try {
- tlvValue.toDate() as T
- } catch (exception: Exception) {
- logException(tag, tlvValue.toHexString(), exception)
- throw TangemSdkError.DecodingFailed()
- }
- }
- TlvValueType.ProductMask -> {
- typeCheck(tag)
- ProductMask(tlvValue.toInt()) as T
- }
- TlvValueType.SettingsMask -> {
- typeCheck(tag)
- SettingsMask(tlvValue.toInt()) as T
- }
- TlvValueType.CardStatus -> {
- typeCheck(tag)
- try {
- CardStatus.byCode(tlvValue.toInt()) as T
- } catch (exception: Exception) {
- logException(tag, tlvValue.toInt().toString(), exception)
- throw TangemSdkError.DecodingFailed()
- }
- }
- TlvValueType.SigningMethod -> {
- typeCheck(tag)
- try {
- SigningMethodMask(tlvValue.toInt()) as T
- } catch (exception: Exception) {
- logException(tag, tlvValue.toInt().toString(), exception)
- throw TangemSdkError.DecodingFailed()
- }
- }
- TlvValueType.IssuerDataMode -> {
- typeCheck(tag)
- try {
- IssuerDataMode.byCode(tlvValue.toInt().toByte()) as T
- } catch (exception: Exception) {
- logException(tag, tlvValue.toInt().toString(), exception)
- throw TangemSdkError.DecodingFailed()
- }
- }
- }
- }
-
- fun logException(tag: TlvTag, value: String, exception: Exception) {
- Log.e(this::class.simpleName!!,
- "Unknown ${tag.name} with value of: value, \n${exception.message}")
- }
-
- inline fun typeCheck(tag: TlvTag) {
- if (T::class != ExpectedT::class) {
- Log.e(this::class.simpleName!!,
- "Mapping error. Type for tag: $tag must be ${tag.valueType()}. It is ${T::class}")
- throw TangemSdkError.DecodingFailedTypeMismatch()
- }
- }
-
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/common/tlv/TlvEncoder.kt b/tangem-core/src/main/java/com/tangem/common/tlv/TlvEncoder.kt
deleted file mode 100644
index 99589b7d40..0000000000
--- a/tangem-core/src/main/java/com/tangem/common/tlv/TlvEncoder.kt
+++ /dev/null
@@ -1,112 +0,0 @@
-package com.tangem.common.tlv
-
-import com.tangem.Log
-import com.tangem.TangemSdkError
-import com.tangem.commands.*
-import com.tangem.commands.common.IssuerDataMode
-import com.tangem.common.extensions.calculateSha256
-import com.tangem.common.extensions.hexToBytes
-import com.tangem.common.extensions.toByteArray
-import java.util.*
-
-/**
- * Encodes information that is to be written on the card from parsed classes into [ByteArray]
- * (according to the provided [TlvTag] and corresponding [TlvValueType])
- * and then forms [Tlv] with the encoded values.
- */
-class TlvEncoder {
- /**
-
- * @param value information that is to be encoded into [Tlv].
- */
- internal inline fun encode(tag: TlvTag, value: T?): Tlv {
- if (value != null) {
- return Tlv(tag, encodeValue(tag, value))
- } else {
- Log.e(this::class.simpleName!!, "Encoding error. Value for tag $tag is null")
- throw TangemSdkError.EncodingFailed()
- }
- }
-
- internal inline fun encodeValue(tag: TlvTag, value: T): ByteArray {
- return when (tag.valueType()) {
- TlvValueType.HexString -> {
- typeCheck(tag)
- (value as String).hexToBytes()
- }
- TlvValueType.HexStringToHash -> {
- typeCheck(tag)
- (value as String).calculateSha256()
- }
- TlvValueType.Utf8String -> {
- typeCheck(tag)
- (value as String).toByteArray()
- }
- TlvValueType.Uint16 -> {
- typeCheck(tag)
- (value as Int).toByteArray(2)
- }
- TlvValueType.Uint32 -> {
- typeCheck(tag)
- (value as Int).toByteArray()
- }
- TlvValueType.BoolValue -> {
- typeCheck(tag)
- val booleanValue = value as Boolean
- if (booleanValue) byteArrayOf(1) else byteArrayOf(0)
- }
- TlvValueType.ByteArray -> {
- typeCheck(tag)
- value as ByteArray
- }
- TlvValueType.EllipticCurve -> {
- typeCheck(tag)
- (value as EllipticCurve).curve.toByteArray()
- }
- TlvValueType.DateTime -> {
- typeCheck(tag)
- val calendar = Calendar.getInstance().apply { time = (value as Date) }
- val year = calendar.get(Calendar.YEAR)
- val month = calendar.get(Calendar.MONTH) + 1
- val day = calendar.get(Calendar.DAY_OF_MONTH)
- return year.toByteArray(2) + month.toByte() + day.toByte()
- }
- TlvValueType.ProductMask -> {
- typeCheck(tag)
- byteArrayOf(
- (value as ProductMask).rawValue.toByte()
- )
- }
- TlvValueType.SettingsMask -> {
- typeCheck(tag)
- val rawValue = (value as SettingsMask).rawValue
- rawValue.toByteArray(determineByteArraySize(rawValue))
- }
- TlvValueType.CardStatus -> {
- typeCheck(tag)
- (value as CardStatus).code.toByteArray()
- }
- TlvValueType.SigningMethod -> {
- typeCheck(tag)
- byteArrayOf((value as SigningMethodMask).rawValue.toByte())
- }
- TlvValueType.IssuerDataMode -> {
- typeCheck(tag)
- byteArrayOf((value as IssuerDataMode).code)
- }
- }
- }
-
- private fun determineByteArraySize(value: Int): Int {
- val mask = 0xFFFF0000.toInt()
- return if ((value and mask) != 0) 4 else 2
- }
-
- private inline fun typeCheck(tag: TlvTag) {
- if (T::class != ExpectedT::class) {
- Log.e(this::class.simpleName!!,
- "Mapping error. Type for tag: $tag must be ${tag.valueType()}. It is ${T::class}")
- throw TangemSdkError.EncodingFailedTypeMismatch()
- }
- }
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/common/tlv/TlvTag.kt b/tangem-core/src/main/java/com/tangem/common/tlv/TlvTag.kt
deleted file mode 100644
index e3c9122c59..0000000000
--- a/tangem-core/src/main/java/com/tangem/common/tlv/TlvTag.kt
+++ /dev/null
@@ -1,151 +0,0 @@
-package com.tangem.common.tlv
-
-/**
- * Contains all possible value types that value for [TlvTag] can contain.
- */
-enum class TlvValueType {
- HexString,
- HexStringToHash,
- Utf8String,
- Uint16,
- Uint32,
- BoolValue,
- ByteArray,
- EllipticCurve,
- DateTime,
- ProductMask,
- SettingsMask,
- CardStatus,
- SigningMethod,
- IssuerDataMode
-}
-
-/**
- * Contains all TLV tags, with their code and descriptive name.
- */
-enum class TlvTag(val code: Int) {
- Unknown(0x00),
- CardId(0x01),
- Status(0x02),
- CardPublicKey(0x03),
- CardSignature(0x04),
- CurveId(0x05),
- HashAlgID(0x06),
- SigningMethod(0x07),
- MaxSignatures(0x08),
- PauseBeforePin2(0x09),
- SettingsMask(0x0A),
- CardData(0x0C),
- NdefData(0x0D),
- CreateWalletAtPersonalize(0x0E),
- Health(0x0F),
-
- Pin(0x10),
- Pin2(0x11),
- NewPin(0x12),
- NewPin2(0x13),
- NewPinHash(0x14),
- NewPin2Hash(0x15),
- Challenge(0x16),
- Salt(0x17),
- ValidationCounter(0x18),
- Cvc(0x19),
-
- SessionKeyA(0x1A),
- SessionKeyB(0x1B),
- Pause(0x1C),
- NewPin3(0x1E),
- CrExKey(0x1F),
-
- Uid(0x0B),
-
- ManufactureId(0x20),
- ManufacturerSignature(0x86),
-
- IssuerDataPublicKey(0x30),
- IssuerTransactionPublicKey(0x31),
- IssuerData(0x32),
- IssuerDataSignature(0x33),
- IssuerTransactionSignature(0x34),
- IssuerDataCounter(0x35),
- AcquirerPublicKey(0x37),
-
- Size(0x25),
- Mode(0x23),
- Offset(0x24),
-
- IsActivated(0x3A),
- ActivationSeed(0x3B),
- ResetPin(0x36),
-
- CodePageAddress(0x40),
- CodePageCount(0x41),
- CodeHash(0x42),
-
- TransactionOutHash(0x50),
- TransactionOutHashSize(0x51),
- TransactionOutRaw(0x52),
-
- WalletPublicKey(0x60),
- Signature(0x61),
- RemainingSignatures(0x62),
- SignedHashes(0x63),
-
- Firmware(0x80),
- Batch(0x81),
- ManufactureDateTime(0x82),
- IssuerId(0x83),
- BlockchainId(0x84),
- ManufacturerPublicKey(0x85),
- CardIdManufacturerSignature(0x86),
-
- ProductMask(0x8A),
- PaymentFlowVersion(0x54),
-
- TokenSymbol(0xA0),
- TokenContractAddress(0xA1),
- TokenDecimal(0xA2),
- Denomination(0xC0),
- ValidatedBalance(0xC1),
- LastSignDate(0xC2),
- DenominationText(0xC3),
-
- TerminalIsLinked(0x58),
- TerminalPublicKey(0x5C),
- TerminalTransactionSignature(0x57),
-
- UserData(0x2A),
- UserProtectedData(0x2B),
- UserCounter(0x2C),
- UserProtectedCounter(0x2D);
-
- /**
- * @return [TlvValueType] associated with a [TlvTag]
- */
- fun valueType(): TlvValueType {
- return when (this) {
- CardId, Batch, CrExKey -> TlvValueType.HexString
- NewPin, NewPin2, NewPin3 -> TlvValueType.HexStringToHash
- ManufactureId, Firmware, IssuerId, BlockchainId, TokenSymbol, TokenContractAddress ->
- TlvValueType.Utf8String
- CurveId -> TlvValueType.EllipticCurve
- PauseBeforePin2, RemainingSignatures, SignedHashes, Health, TokenDecimal,
- Offset, Size -> TlvValueType.Uint16
- MaxSignatures, UserCounter, UserProtectedCounter, IssuerDataCounter -> TlvValueType.Uint32
- IsActivated, TerminalIsLinked, CreateWalletAtPersonalize -> TlvValueType.BoolValue
- ManufactureDateTime -> TlvValueType.DateTime
- ProductMask -> TlvValueType.ProductMask
- SettingsMask -> TlvValueType.SettingsMask
- Status -> TlvValueType.CardStatus
- SigningMethod -> TlvValueType.SigningMethod
- Mode -> TlvValueType.IssuerDataMode
- else -> TlvValueType.ByteArray
- }
- }
-
- companion object {
- private val values = values()
- fun byCode(code: Int): TlvTag = values.find { it.code == code } ?: Unknown
- }
-}
-
diff --git a/tangem-core/src/main/java/com/tangem/crypto/CryptoUtils.kt b/tangem-core/src/main/java/com/tangem/crypto/CryptoUtils.kt
deleted file mode 100644
index af6f5e2b76..0000000000
--- a/tangem-core/src/main/java/com/tangem/crypto/CryptoUtils.kt
+++ /dev/null
@@ -1,121 +0,0 @@
-package com.tangem.crypto
-
-import com.tangem.commands.EllipticCurve
-import net.i2p.crypto.eddsa.EdDSASecurityProvider
-import org.spongycastle.jce.provider.BouncyCastleProvider
-import java.security.PublicKey
-import java.security.SecureRandom
-import java.security.Security
-import javax.crypto.Cipher
-import javax.crypto.spec.IvParameterSpec
-import javax.crypto.spec.SecretKeySpec
-
-
-object CryptoUtils {
-
- fun initCrypto() {
- Security.insertProviderAt(BouncyCastleProvider(), 1)
- Security.addProvider(EdDSASecurityProvider())
- }
-
- /**
- * Generates ByteArray of random bytes.
- * It is used, among other things, to generate helper private keys
- * (not the one for the blockchains, that one is generated on the card and does not leave the card).
- *
- * @param length length of the ByteArray that is to be generated.
- */
- fun generateRandomBytes(length: Int): ByteArray {
- val bytes = ByteArray(length)
- SecureRandom().nextBytes(bytes)
- return bytes
- }
-
- /**
- * Helper function to verify that the data was signed with a private key that corresponds
- * to the provided public key.
- *
- * @param publicKey Corresponding to the private key that was used to sing a message
- * @param message The data that was signed
- * @param signature Signed data
- * @param curve Elliptic curve used
- *
- * @return Result of a verification
- */
- fun verify(publicKey: ByteArray, message: ByteArray, signature: ByteArray,
- curve: EllipticCurve = EllipticCurve.Secp256k1): Boolean {
- return when (curve) {
- EllipticCurve.Secp256k1 -> Secp256k1.verify(publicKey, message, signature)
- EllipticCurve.Ed25519 -> Ed25519.verify(publicKey, message, signature)
- }
- }
-
- /**
- * Helper function that generates public key from a private key.
- *
- * @param privateKeyArray A private key from which a public key is generated
- * @param curve Elliptic curve used
- *
- * @return Public key [ByteArray]
- */
- fun generatePublicKey(
- privateKeyArray: ByteArray,
- curve: EllipticCurve = EllipticCurve.Secp256k1
- ): ByteArray {
- return when (curve) {
- EllipticCurve.Secp256k1 -> Secp256k1.generatePublicKey(privateKeyArray)
- EllipticCurve.Ed25519 -> Ed25519.generatePublicKey(privateKeyArray)
- }
- }
-
- fun loadPublicKey(
- publicKey: ByteArray,
- curve: EllipticCurve = EllipticCurve.Secp256k1
- ): PublicKey {
- return when (curve) {
- EllipticCurve.Secp256k1 -> Secp256k1.loadPublicKey(publicKey)
- EllipticCurve.Ed25519 -> Ed25519.loadPublicKey(publicKey)
- }
- }
-}
-
-/**
- * Extension function to sign a ByteArray with an elliptic curve cryptography.
- *
- * @param privateKeyArray Key to sign data
- * @param curve Elliptic curve that is used to sign data
- *
- * @return Signed data
- */
-fun ByteArray.sign(privateKeyArray: ByteArray, curve: EllipticCurve = EllipticCurve.Secp256k1): ByteArray {
- return when (curve) {
- EllipticCurve.Secp256k1 -> Secp256k1.sign(this, privateKeyArray)
- EllipticCurve.Ed25519 -> Ed25519.sign(this, privateKeyArray)
- }
-}
-
-fun ByteArray.encrypt(key: ByteArray, usePkcs7: Boolean = true): ByteArray {
- val spec = if (usePkcs7) ENCRYPTION_SPEC_PKCS7 else ENCRYPTION_SPEC_NO_PADDING
- val secretKeySpec = SecretKeySpec(key, spec)
- val cipher = Cipher.getInstance(spec, "SC")
- cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, IvParameterSpec(ByteArray(16)))
- return cipher.doFinal(this)
-}
-
-fun ByteArray.decrypt(key: ByteArray, usePkcs7: Boolean = true): ByteArray {
- val spec = if (usePkcs7) ENCRYPTION_SPEC_PKCS7 else ENCRYPTION_SPEC_NO_PADDING
- val secretKeySpec = SecretKeySpec(key, spec)
- val cipher = Cipher.getInstance(spec)
- cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, IvParameterSpec(ByteArray(16)))
- return cipher.doFinal(this.copyOfRange(0, this.size))
-}
-
-fun ByteArray.pbkdf2Hash(salt: ByteArray, iterations: Int): ByteArray {
- return Pbkdf2().deriveKey(this, salt, iterations)
-}
-
-private const val ENCRYPTION_SPEC_PKCS7 = "AES/CBC/PKCS7PADDING"
-private const val ENCRYPTION_SPEC_NO_PADDING = "AES/CBC/NOPADDING"
-
-
-
diff --git a/tangem-core/src/main/java/com/tangem/crypto/Ed25519.kt b/tangem-core/src/main/java/com/tangem/crypto/Ed25519.kt
deleted file mode 100644
index 5c07b5a4e9..0000000000
--- a/tangem-core/src/main/java/com/tangem/crypto/Ed25519.kt
+++ /dev/null
@@ -1,55 +0,0 @@
-package com.tangem.crypto
-
-import com.tangem.common.extensions.calculateSha512
-import net.i2p.crypto.eddsa.EdDSAEngine
-import net.i2p.crypto.eddsa.EdDSAPrivateKey
-import net.i2p.crypto.eddsa.EdDSAPublicKey
-import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable
-import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec
-import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec
-import java.security.MessageDigest
-import java.security.PublicKey
-
-object Ed25519 {
-
- internal fun verify(publicKey: ByteArray, message: ByteArray, signature: ByteArray): Boolean {
- val messageSha512 = message.calculateSha512()
- val loadedPublicKey = loadPublicKey(publicKey)
- val spec = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519)
- val signatureInstance = EdDSAEngine(MessageDigest.getInstance(spec.hashAlgorithm))
- signatureInstance.initVerify(loadedPublicKey)
-
- signatureInstance.update(messageSha512)
-
- return signatureInstance.verify(signature)
- }
-
- internal fun loadPublicKey(publicKeyArray: ByteArray): PublicKey {
- val spec = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519)
- val pubKey = EdDSAPublicKeySpec(publicKeyArray, spec)
- return EdDSAPublicKey(pubKey)
- }
-
- internal fun sign(data: ByteArray, privateKeyArray: ByteArray): ByteArray {
-
- val dataSha512 = data.calculateSha512()
- val spec = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519)
- val signatureInstance = EdDSAEngine(MessageDigest.getInstance(spec.hashAlgorithm))
-
- val privateKeySpec = EdDSAPrivateKeySpec(privateKeyArray, spec)
- val privateKey = EdDSAPrivateKey(privateKeySpec)
-
- signatureInstance.initSign(privateKey)
- signatureInstance.update(dataSha512)
-
- return signatureInstance.sign()
- }
-
- internal fun generatePublicKey(privateKeyArray: ByteArray): ByteArray {
- val spec = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519)
- val privateKeySpec = EdDSAPrivateKeySpec(privateKeyArray, spec)
- val publicKeySpec = EdDSAPublicKeySpec(privateKeySpec.a, spec)
- val publicKey = EdDSAPublicKey(publicKeySpec)
- return publicKey.abyte
- }
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/crypto/EncryptionHelper.kt b/tangem-core/src/main/java/com/tangem/crypto/EncryptionHelper.kt
deleted file mode 100644
index ab3d97445c..0000000000
--- a/tangem-core/src/main/java/com/tangem/crypto/EncryptionHelper.kt
+++ /dev/null
@@ -1,50 +0,0 @@
-package com.tangem.crypto
-
-import org.spongycastle.jce.interfaces.ECPublicKey
-import java.security.KeyPair
-import java.security.KeyPairGenerator
-import java.security.SecureRandom
-import java.security.spec.ECGenParameterSpec
-import javax.crypto.KeyAgreement
-
-interface EncryptionHelper {
- val keyA: ByteArray
-
- fun generateSecret(keyB: ByteArray): ByteArray
-}
-
-class StrongEncryptionHelper : EncryptionHelper {
- private val keyPair = generateKeyPair()
- private val keyAgreement = generateKeyAgreement(keyPair)
- override val keyA = provideKeyA(keyPair)
-
- override fun generateSecret(keyB: ByteArray): ByteArray {
- keyAgreement.doPhase(CryptoUtils.loadPublicKey(keyB), true)
- return keyAgreement.generateSecret()
- }
-
- private fun generateKeyPair(): KeyPair {
- val kpgen = KeyPairGenerator.getInstance("ECDH", "SC")
- kpgen.initialize(ECGenParameterSpec("secp256k1"), SecureRandom())
- return kpgen.generateKeyPair()
- }
-
- private fun generateKeyAgreement(keyPair: KeyPair): KeyAgreement {
- val keyAgreement = KeyAgreement.getInstance("ECDH", "SC")
- keyAgreement.init(keyPair.private)
- return keyAgreement
- }
-
- private fun provideKeyA(keyPair: KeyPair): ByteArray {
- val eckey = keyPair.public as ECPublicKey
- return eckey.q.getEncoded(false)
- }
-}
-
-class FastEncryptionHelper : EncryptionHelper {
- override val keyA = CryptoUtils.generateRandomBytes(16)
-
- override fun generateSecret(keyB: ByteArray): ByteArray {
- return keyA + keyB
- }
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/crypto/Pbkdf2.kt b/tangem-core/src/main/java/com/tangem/crypto/Pbkdf2.kt
deleted file mode 100644
index 4c532b3692..0000000000
--- a/tangem-core/src/main/java/com/tangem/crypto/Pbkdf2.kt
+++ /dev/null
@@ -1,88 +0,0 @@
-package com.tangem.crypto
-
-import org.spongycastle.crypto.CipherParameters
-import org.spongycastle.crypto.digests.SHA256Digest
-import org.spongycastle.crypto.macs.HMac
-import org.spongycastle.crypto.params.KeyParameter
-import java.security.InvalidKeyException
-import java.util.*
-import kotlin.experimental.xor
-import kotlin.math.min
-import kotlin.math.pow
-
-class Pbkdf2 {
- private val F: HMac = HMac(SHA256Digest())
-
- fun deriveKey(password: ByteArray, salt: ByteArray, iterations: Int): ByteArray {
-
- val macSize = F.macSize
- // Check key length
- if (macSize > (2.0.pow(32.0) - 1) * macSize) throw InvalidKeyException("Derived key to long")
-
- val derivedKey = ByteArray(macSize)
-
- val J = 0
- val K: Int = macSize
- val U: Int = macSize shl 1
- val B = K + U
- val workingArray = ByteArray(K + U + 4)
-
- // Initialize F
- val macParams: CipherParameters = KeyParameter(password)
- F.init(macParams)
-
- // Perform iterations
- var kpos = 0
- var blk = 1
- while (kpos < macSize) {
- storeInt32BE(blk, workingArray, B)
- F.update(salt, 0, salt.size)
- F.reset()
- F.update(salt, 0, salt.size)
- F.update(workingArray, B, 4)
- F.doFinal(workingArray, U)
- System.arraycopy(workingArray, U, workingArray, J, K)
- var i = 1
- var j = J
- var k = K
- while (i < iterations) {
- F.init(macParams)
- F.update(workingArray, j, K)
- F.doFinal(workingArray, k)
- var u = U
- var v = k
- while (u < B) {
- workingArray[u] = workingArray[u] xor workingArray[v]
- u++
- v++
- }
- val swp = k
- k = j
- j = swp
- i++
- }
- val tocpy = min(macSize - kpos, K)
- System.arraycopy(workingArray, U, derivedKey, kpos, tocpy)
- kpos += K
- blk++
- }
- Arrays.fill(workingArray, 0.toByte())
- return derivedKey
- }
-
- /**
- * Convert a 32-bit integer value into a big-endian byte array
- *
- * @param value The integer value to convert
- * @param bytes The byte array to store the converted value
- * @param offSet The offset in the output byte array
- */
- private fun storeInt32BE(value: Int, bytes: ByteArray, offSet: Int) {
- bytes[offSet + 3] = value.toByte()
- bytes[offSet + 2] = (value ushr 8).toByte()
- bytes[offSet + 1] = (value ushr 16).toByte()
- bytes[offSet] = (value ushr 24).toByte()
- }
-
-
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/crypto/Secp256k1.kt b/tangem-core/src/main/java/com/tangem/crypto/Secp256k1.kt
deleted file mode 100644
index 97eba2a81c..0000000000
--- a/tangem-core/src/main/java/com/tangem/crypto/Secp256k1.kt
+++ /dev/null
@@ -1,118 +0,0 @@
-package com.tangem.crypto
-
-import com.tangem.common.extensions.toHexString
-import org.spongycastle.asn1.ASN1EncodableVector
-import org.spongycastle.asn1.ASN1Integer
-import org.spongycastle.asn1.DERSequence
-import org.spongycastle.jce.ECNamedCurveTable
-import org.spongycastle.jce.spec.ECPrivateKeySpec
-import org.spongycastle.jce.spec.ECPublicKeySpec
-import java.math.BigInteger
-import java.security.KeyFactory
-import java.security.PublicKey
-import java.security.Signature
-
-object Secp256k1 {
-
- internal fun verify(publicKey: ByteArray, message: ByteArray, signature: ByteArray): Boolean {
- val signatureInstance = Signature.getInstance("SHA256withECDSA")
- val loadedPublicKey = loadPublicKey(publicKey)
- signatureInstance.initVerify(loadedPublicKey)
- signatureInstance.update(message)
-
- val v = ASN1EncodableVector()
- val size = signature.size / 2
- v.add(calculateR(signature, size))
- v.add(calculateS(signature, size))
- val sigDer = DERSequence(v).encoded
-
- return signatureInstance.verify(sigDer)
- }
-
- internal fun loadPublicKey(publicKeyArray: ByteArray): PublicKey {
-
- val spec = ECNamedCurveTable.getParameterSpec("secp256k1")
- val factory = KeyFactory.getInstance("EC", "SC")
-
- val p1 = spec.curve.decodePoint(publicKeyArray)
- val keySpec = ECPublicKeySpec(p1, spec)
-
- return factory.generatePublic(keySpec)
- }
-
- private fun calculateR(signature: ByteArray, size: Int): ASN1Integer =
- ASN1Integer(BigInteger(1, signature.copyOfRange(0, size)))
-
- private fun calculateS(signature: ByteArray, size: Int): ASN1Integer =
- ASN1Integer(BigInteger(1, signature.copyOfRange(size, size * 2)))
-
-
- internal fun sign(data: ByteArray, privateKeyArray: ByteArray): ByteArray {
-
- val spec = ECNamedCurveTable.getParameterSpec("secp256k1")
- val factory = KeyFactory.getInstance("EC", "SC")
-
- val keySpecP = ECPrivateKeySpec(BigInteger(1, privateKeyArray), spec)
-
- val signature = Signature.getInstance("SHA256withECDSA")
-
- val privateKey = factory.generatePrivate(keySpecP)
- signature.initSign(privateKey)
- signature.update(data)
-
- val enc = signature.sign()
- checkSignatureForErrors(enc)
-
- val res = toByte64(enc)
-
- if (!verify(generatePublicKey(privateKeyArray), data, res)) {
- throw Exception("Signature self verify failed - ,enc:" + enc.toHexString() + ",res:" + res.toHexString())
- }
-
- return res
- }
-
- private fun checkSignatureForErrors(enc: ByteArray) {
- if (enc[0].toInt() != 0x30) throw Exception("bad encoding 1")
- if (enc[1].toInt() and 0x80 != 0) throw Exception("unsupported length encoding 1")
- if (enc[2].toInt() != 0x02) throw Exception("bad encoding 2")
- if (enc[3].toInt() and 0x80 != 0) throw Exception("unsupported length encoding 2")
- var rLength = enc[3].toInt()
- if (enc[4 + rLength].toInt() != 0x02) throw Exception("bad encoding 3")
- if (enc[5 + rLength].toInt() and 0x80 != 0)
- throw Exception("unsupported length encoding 3")
- }
-
- private fun toByte64(enc: ByteArray): ByteArray {
-
- var rLength = enc[3].toInt()
- var sLength = enc[5 + rLength].toInt()
-
- val sPos = 6 + rLength
- val res = ByteArray(64)
- if (rLength <= 32) {
- System.arraycopy(enc, 4, res, 32 - rLength, rLength)
- rLength = 32
- } else if (rLength == 33 && enc[4].toInt() == 0) {
- rLength--
- System.arraycopy(enc, 5, res, 0, rLength)
- } else {
- throw Exception("unsupported r-length - r-length:" + rLength.toString() + ",s-length:" + sLength.toString() + ",enc:" + enc.toHexString())
- }
- if (sLength <= 32) {
- System.arraycopy(enc, sPos, res, rLength + 32 - sLength, sLength)
- sLength = 32
- } else if (sLength == 33 && enc[sPos].toInt() == 0) {
- System.arraycopy(enc, sPos + 1, res, rLength, sLength - 1)
- } else {
- throw Exception("unsupported s-length - r-length:" + rLength.toString() + ",s-length:" + sLength.toString() + ",enc:" + enc.toHexString())
- }
-
- return res
- }
-
- internal fun generatePublicKey(privateKeyArray: ByteArray): ByteArray {
- val spec = ECNamedCurveTable.getParameterSpec("secp256k1")
- return spec.g.multiply(BigInteger(1, privateKeyArray)).getEncoded(false)
- }
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/tasks/CreateWalletTask.kt b/tangem-core/src/main/java/com/tangem/tasks/CreateWalletTask.kt
deleted file mode 100644
index 317134af60..0000000000
--- a/tangem-core/src/main/java/com/tangem/tasks/CreateWalletTask.kt
+++ /dev/null
@@ -1,45 +0,0 @@
-package com.tangem.tasks
-
-import com.tangem.CardSession
-import com.tangem.CardSessionRunnable
-import com.tangem.TangemSdkError
-import com.tangem.commands.CardStatus
-import com.tangem.commands.CheckWalletCommand
-import com.tangem.commands.CreateWalletCommand
-import com.tangem.commands.CreateWalletResponse
-import com.tangem.common.CompletionResult
-
-class CreateWalletTask : CardSessionRunnable {
-
- override val performPreflightRead = true
-
- override fun run(session: CardSession, callback: (result: CompletionResult) -> Unit) {
- val curve = session.environment.card?.curve
- if (curve == null) {
- callback(CompletionResult.Failure(TangemSdkError.CardError()))
- return
- }
-
- val command = CreateWalletCommand()
- command.run(session) { createWalletResult ->
- when (createWalletResult) {
- is CompletionResult.Failure -> callback(createWalletResult)
- is CompletionResult.Success -> {
- if (createWalletResult.data.status != CardStatus.Loaded) {
- callback(CompletionResult.Failure(TangemSdkError.UnknownError()))
- } else {
- val checkWalletCommand = CheckWalletCommand(
- curve, createWalletResult.data.walletPublicKey
- )
- checkWalletCommand.run(session) { result ->
- when (result) {
- is CompletionResult.Failure -> callback(CompletionResult.Failure(result.error))
- is CompletionResult.Success -> callback(createWalletResult)
- }
- }
- }
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/tasks/ScanTask.kt b/tangem-core/src/main/java/com/tangem/tasks/ScanTask.kt
deleted file mode 100644
index c05384d5a1..0000000000
--- a/tangem-core/src/main/java/com/tangem/tasks/ScanTask.kt
+++ /dev/null
@@ -1,45 +0,0 @@
-package com.tangem.tasks
-
-import com.tangem.CardSession
-import com.tangem.CardSessionRunnable
-import com.tangem.TangemSdkError
-import com.tangem.commands.*
-import com.tangem.common.CompletionResult
-
-/**
- * Task that allows to read Tangem card and verify its private key.
- *
- * It performs two commands, [ReadCommand] and [CheckWalletCommand], subsequently.
- */
-internal class ScanTask : CardSessionRunnable {
-
- override val performPreflightRead = true
-
- override fun run(session: CardSession, callback: (result: CompletionResult) -> Unit) {
-
- val card = session.environment.card
-
- if (card == null) {
- callback(CompletionResult.Failure(TangemSdkError.MissingPreflightRead()))
-
- } else if (card.cardData?.productMask?.contains(Product.Tag) != false) {
- callback(CompletionResult.Success(card))
-
- } else if (card.status != CardStatus.Loaded) {
- callback(CompletionResult.Success(card))
-
- } else if (card.curve == null || card.walletPublicKey == null) {
- callback(CompletionResult.Failure(TangemSdkError.CardError()))
-
- } else {
- val checkWalletCommand = CheckWalletCommand(card.curve, card.walletPublicKey)
-
- checkWalletCommand.run(session) { result ->
- when (result) {
- is CompletionResult.Success -> callback(CompletionResult.Success(card))
- is CompletionResult.Failure -> callback(CompletionResult.Failure(result.error))
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/tangem-core/src/test/java/com/tangem/common/apdu/CommandApduTest.kt b/tangem-core/src/test/java/com/tangem/common/apdu/CommandApduTest.kt
deleted file mode 100644
index f879f65e6f..0000000000
--- a/tangem-core/src/test/java/com/tangem/common/apdu/CommandApduTest.kt
+++ /dev/null
@@ -1,54 +0,0 @@
-package com.tangem.common.apdu
-
-import com.google.common.truth.Truth.assertThat
-import com.tangem.SessionEnvironment
-import com.tangem.common.tlv.TlvBuilder
-import com.tangem.common.tlv.TlvTag
-import org.junit.Test
-
-
-class CommandApduTest {
-
- @Test
- fun `simple READ command to bytes`() {
- val sessionEnvironment = SessionEnvironment()
- val tlvBuilder = TlvBuilder()
- tlvBuilder.append(TlvTag.Pin, sessionEnvironment.pin1)
- val commandApdu = CommandApdu(
- Instruction.Read,
- tlvBuilder.serialize()
- )
- val expected = byteArrayOf(0, -14, 0, 0, 0, 0, 34, 16, 32, -111, -76, -47, 66, -126, 63, 125,
- 32, -59, -16, -115, -10, -111, 34, -34, 67, -13, 95, 5, 122, -104, -115, -106, 25, -10,
- -45, 19, -124, -123, -55, -94, 3)
-
- assertThat(commandApdu.apduData)
- .isEqualTo(expected)
- }
-
- @Test
- fun `READ with terminal key to bytes`() {
- val sessionEnvironment = SessionEnvironment()
- val terminalPublicKey = byteArrayOf(4, 80, -122, 58, -42, 74, -121, -82, -118, 47, -24, 60,
- 26, -15, -88, 64, 60, -75, 63, 83, -28, -122, -40, 81, 29, -83, -118, 4, -120, 126,
- 91, 35, 82, 44, -44, 112, 36, 52, 83, -94, -103, -6, -98, 119, 35, 119, 22, 16, 58,
- -68, 17, -95, -33, 56, -123, 94, -42, -14, -18, 24, 126, -100, 88, 43, -90)
- val tlvBuilder = TlvBuilder()
- tlvBuilder.append(TlvTag.Pin, sessionEnvironment.pin1)
- tlvBuilder.append(TlvTag.TerminalPublicKey, terminalPublicKey)
- val commandApdu = CommandApdu(
- Instruction.Read,
- tlvBuilder.serialize()
- )
-
- val expected = byteArrayOf(0, -14, 0, 0, 0, 0, 101, 16, 32, -111, -76, -47, 66, -126, 63,
- 125, 32, -59, -16, -115, -10, -111, 34, -34, 67, -13, 95, 5, 122, -104, -115, -106, 25,
- -10, -45, 19, -124, -123, -55, -94, 3, 92, 65, 4, 80, -122, 58, -42, 74, -121, -82, -118,
- 47, -24, 60, 26, -15, -88, 64, 60, -75, 63, 83, -28, -122, -40, 81, 29, -83, -118, 4, -120,
- 126, 91, 35, 82, 44, -44, 112, 36, 52, 83, -94, -103, -6, -98, 119, 35, 119, 22, 16, 58,
- -68, 17, -95, -33, 56, -123, 94, -42, -14, -18, 24, 126, -100, 88, 43, -90)
-
- assertThat(commandApdu.apduData)
- .isEqualTo(expected)
- }
-}
\ No newline at end of file
diff --git a/tangem-core/src/test/java/com/tangem/common/apdu/ResponseApduTest.kt b/tangem-core/src/test/java/com/tangem/common/apdu/ResponseApduTest.kt
deleted file mode 100644
index 0b6f7fc8b9..0000000000
--- a/tangem-core/src/test/java/com/tangem/common/apdu/ResponseApduTest.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.tangem.common.apdu
-
-import com.google.common.truth.Truth.assertThat
-import com.tangem.common.tlv.TlvTag
-import org.junit.Test
-
-class ResponseApduTest {
-
- @Test
- fun `get StatusWord returns Unknown`() {
- val corruptData = byteArrayOf(0, 0, 0, 0)
- val responseApdu = ResponseApdu(corruptData)
- assertThat(responseApdu.statusWord)
- .isEqualTo(StatusWord.Unknown)
- }
-
- @Test
- fun `get StatusWord returns ProcessCompleted`() {
- val data = byteArrayOf(0, 0, 0, 0, -112, 0)
- val responseApdu = ResponseApdu(data)
- assertThat(responseApdu.statusWord)
- .isEqualTo(StatusWord.ProcessCompleted)
- }
-
- @Test
- fun `corrupt response, getTlvData returns null`() {
- val corruptData = byteArrayOf(0, 0, 0)
- val responseApdu = ResponseApdu(corruptData)
- assertThat(responseApdu.getTlvData())
- .isNull()
- }
-
- @Test
- fun `response, getTlvData returns cardId`() {
- val data = byteArrayOf(1, 8, -53, 34, 0, 0, 0, 2, 115, 116, 32, 11, 83, 77, 65, 82, 84, 32, 67, 65, 83, 72, 0, 2, 1, 2, -128, 6, 50, 46, 49, 49, 114, 0, 3, 65, 4, -49, 11, -50, -66, -121, -25, -2, 65, 65, -13, 14, 49, 27, -82, -33, -85, -113, 65, 20, 8, -39, -75, 57, 45, 65, -31, 35, 44, 38, 40, 63, -44, 113, -45, -75, -95, -118, 118, 29, 65, 117, -24, -53, 82, -72, 91, -20, -96, -77, -103, -14, -63, 52, -127, -123, -27, -16, -128, -67, -3, -104, -26, -22, 65, 10, 4, 0, 0, 126, 33, 12, 90, -127, 2, 0, 41, -126, 4, 7, -29, 5, 2, -125, 7, 84, 65, 78, 71, 69, 77, 0, -124, 3, 69, 84, 72, -122, 64, 111, -103, 48, -114, -40, 18, -103, 26, -102, -12, -38, -78, -90, -9, -98, 88, -47, -100, -24, 24, -105, -70, -72, 6, 94, -96, -77, 11, -123, -28, -118, 37, 63, 107, -55, -11, 23, -12, 13, -23, -121, -63, 36, -59, 70, 116, 91, -125, -34, -69, 23, -112, 6, 17, 4, -49, 68, -56, 29, -45, 81, 10, 97, 83, 48, 65, 4, -127, -106, -86, 75, 65, 10, -60, 74, 59, -100, -50, 24, -25, -66, 34, 106, -22, 7, 10, -52, -125, -87, -49, 103, 84, 15, -84, 73, -81, 37, 18, -97, 106, 83, -118, 40, -83, 99, 65, 53, -114, 60, 79, -103, 99, 6, 79, 126, 54, 83, 114, -90, 81, -45, 116, -27, -62, 60, -35, 55, -3, 9, -101, -14, 5, 10, 115, 101, 99, 112, 50, 53, 54, 107, 49, 0, 8, 4, 0, 15, 66, 64, 7, 1, 0, 9, 2, 11, -72, 96, 65, 4, -42, -5, -41, -84, -23, 88, 2, 86, -63, -118, -123, -10, -66, -82, -107, -68, -93, 111, 47, 93, -20, -86, 74, 28, 21, 81, 93, -21, -124, -57, -102, 55, 17, 84, -66, -68, -22, -128, 126, -99, -65, -54, -42, 59, -25, -21, -124, 5, 59, -16, -72, 73, 48, 16, -27, 103, -112, -73, 2, 96, -51, 41, -42, 116, 98, 4, 0, 15, 66, 52, 99, 4, 0, 0, 0, 13, 15, 1, 0, -112, 0)
- val responseApdu = ResponseApdu(data)
- assertThat(responseApdu.getTlvData())
- .isNotNull()
- assertThat(responseApdu.getTlvData())
- .isNotEmpty()
- assertThat(responseApdu.getTlvData()?.filter { it.tag == TlvTag.Unknown })
- .isEmpty()
- }
-}
\ No newline at end of file
diff --git a/tangem-core/src/test/java/com/tangem/common/extensions/ByteArrayExtensionsTest.kt b/tangem-core/src/test/java/com/tangem/common/extensions/ByteArrayExtensionsTest.kt
deleted file mode 100644
index 224144afdb..0000000000
--- a/tangem-core/src/test/java/com/tangem/common/extensions/ByteArrayExtensionsTest.kt
+++ /dev/null
@@ -1,105 +0,0 @@
-package com.tangem.common.extensions
-
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import java.util.*
-
-
-class ByteArrayExtensionsTest {
-
- @Test
- fun `card Id to Hex String`() {
- val hex = "cb22000000027374"
- val bytes = byteArrayOf(-53, 34, 0, 0, 0, 2, 115, 116)
- assertThat(bytes.toHexString())
- .matches(hex)
- }
-
- @Test
- fun `batch Id to Hex String`() {
- val hex = "0029"
- val bytes = byteArrayOf(0, 41)
- assertThat(bytes.toHexString())
- .matches(hex)
- }
-
- @Test
- fun `curve name to Utf8`() {
- val bytes = byteArrayOf(115, 101, 99, 112, 50, 53, 54, 107, 49, 0)
- val expected = "secp256k1"
- val converted = bytes.toUtf8()
- assertThat(converted)
- .matches(expected)
- }
-
- @Test
- fun `empty byteArray to Utf8 returns empty String`() {
- val bytes = byteArrayOf()
- val expected = ""
- assertThat(bytes.toUtf8())
- .matches(expected)
- }
-
- @Test
- fun `blockchain name to Utf8`() {
- val bytes = byteArrayOf(69, 84, 72)
- val expected = "ETH"
- val converted = bytes.toUtf8()
- assertThat(converted)
- .matches(expected)
- }
-
- @Test
- fun `bytes to int`() {
- val bytes = byteArrayOf(0, 2, 106, 3)
- val expected = 158211
- assertThat(bytes.toInt())
- .isEqualTo(expected)
-
- val bytes1 = byteArrayOf(0, 0, 0, 13)
- val expected1 = 13
- assertThat(bytes1.toInt())
- .isEqualTo(expected1)
- }
-
- @Test
- fun `zero to int`() {
- val bytes = byteArrayOf(0)
- val expected = 0
- assertThat(bytes.toInt())
- .isEqualTo(expected)
- }
-
- @Test
- fun toDate() {
- val bytes1 = byteArrayOf(7, -30, 7, 27)
- val expected1 = Calendar.getInstance().apply { this.set(2018, 6, 27, 0, 0, 0) }.time
- val converted1 = bytes1.toDate()
- assertThat(converted1.toString())
- .isEqualTo(expected1.toString())
-
- val bytes2 = byteArrayOf(7, -30, 7, 27, 30)
- val expected2 = Calendar.getInstance().apply { this.set(2018, 6, 27, 0, 0, 0) }.time
- val converted2 = bytes2.toDate()
- assertThat(converted2.toString())
- .isEqualTo(expected2.toString())
-
- val bytes3 = byteArrayOf(7, -30, 7)
- val expected3 = Calendar.getInstance().apply { this.set(2018, 6, 0, 0, 0, 0) }.time
- val converted3 = bytes3.toDate()
- assertThat(converted3.toString())
- .isEqualTo(expected3.toString())
- }
-
- @Test
- fun `calculate sha512`() {
- val bytes = ByteArray(64) { 5 }
- val expected = byteArrayOf(
- -123, 96, 121, 57, -117, -23, -108, 57, 25, -119, -22, 97, 11, -91,
- 74, -19, -88, 21, -108, -116, -100, 111, 6, -78, 114, -115, 70, -121, 29, 102, 104, 65,
- -21, -68, -111, 121, -51, 109, -94, -24, -40, 108, -25, 70, -26, 61, 38, 12, -127, -34,
- -77, -81, 81, -32, -89, -112, -31, -33, 91, 114, 89, 127, -123, -58)
- assertThat(bytes.calculateSha512())
- .isEqualTo(expected)
- }
-}
\ No newline at end of file
diff --git a/tangem-core/src/test/java/com/tangem/common/extensions/IntExtensionsTest.kt b/tangem-core/src/test/java/com/tangem/common/extensions/IntExtensionsTest.kt
deleted file mode 100644
index 710f817e28..0000000000
--- a/tangem-core/src/test/java/com/tangem/common/extensions/IntExtensionsTest.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.tangem.common.extensions
-
-import com.google.common.truth.Truth.assertThat
-import org.junit.jupiter.api.Test
-
-
-class IntExtensionsTest {
-
- @Test
- fun `small int toByteArray`() {
- val int = 13
- val expected = byteArrayOf(0, 0, 0, 13)
- assertThat(int.toByteArray())
- .isEqualTo(expected)
- }
-
- @Test
- fun `int toByteArray`() {
- val int = 999
- val expected = byteArrayOf(0, 0, 3, -25)
- assertThat(int.toByteArray())
- .isEqualTo(expected)
- }
-}
\ No newline at end of file
diff --git a/tangem-core/src/test/java/com/tangem/common/extensions/StringExtensionsTest.kt b/tangem-core/src/test/java/com/tangem/common/extensions/StringExtensionsTest.kt
deleted file mode 100644
index ba5b3add73..0000000000
--- a/tangem-core/src/test/java/com/tangem/common/extensions/StringExtensionsTest.kt
+++ /dev/null
@@ -1,53 +0,0 @@
-package com.tangem.common.extensions
-
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-
-class StringExtensionsTest {
-
- @Test
- fun `calculate SHA 256 for default PIN 1`() {
- val pin = "000000"
- val expected = byteArrayOf(-111, -76, -47, 66, -126, 63, 125, 32, -59, -16, -115, -10, -111,
- 34, -34, 67, -13, 95, 5, 122, -104, -115, -106, 25, -10, -45, 19, -124, -123, -55, -94, 3)
- assertThat(pin.calculateSha256())
- .isEqualTo(expected)
- }
-
- @Test
- fun `calculate SHA 256 for default PIN 2`() {
- val pin = "000"
- val expected = byteArrayOf(42, -55, -90, 116, 106, -54, 84, 58, -8, -33, -13, -104, -108, -49,
- -24, 23, 58, -5, -94, 30, -80, 28, 111, -82, 51, -43, 41, 71, 34, 40, 85, -17)
- assertThat(pin.calculateSha256())
- .isEqualTo(expected)
- }
-
- @Test
- fun `calculate SHA 256 for a sample PIN 1`() {
- val pin = "999999"
- val expected = byteArrayOf(-109, 115, 119, -16, 86, 22, 15, -60, -79, 94, 11, 119, 12, 103,
- 19, 106, 95, 3, -63, 82, 5, -76, -45, -65, -111, -126, 104, -2, -6, 44, 109, 10)
- assertThat(pin.calculateSha256())
- .isEqualTo(expected)
- }
-
- @Test
- fun `calculate SHA 256 for a sample PIN 2`() {
- val pin = "999"
- val expected = byteArrayOf(-125, -49, -117, 96, -99, -26, 0, 54, -88, 39, 123, -48, -23, 97,
- 53, 117, 27, -68, 7, -21, 35, 66, 86, -44, -74, 91, -119, 51, 96, 101, 27, -14)
- assertThat(pin.calculateSha256())
- .isEqualTo(expected)
- }
-
- @Test
- fun `card ID hex to bytes`() {
- val cardId = "cb22000000027374"
- val expected = byteArrayOf(-53, 34, 0, 0, 0, 2, 115, 116)
- assertThat(cardId.hexToBytes())
- .isEqualTo(expected)
- }
-
-
-}
\ No newline at end of file
diff --git a/tangem-core/src/test/java/com/tangem/common/tlv/TlvDecoderTest.kt b/tangem-core/src/test/java/com/tangem/common/tlv/TlvDecoderTest.kt
deleted file mode 100644
index 8f7bd0b91e..0000000000
--- a/tangem-core/src/test/java/com/tangem/common/tlv/TlvDecoderTest.kt
+++ /dev/null
@@ -1,192 +0,0 @@
-package com.tangem.common.tlv
-
-import com.google.common.truth.Truth.assertThat
-import com.tangem.TangemSdkError
-import com.tangem.commands.*
-import com.tangem.common.extensions.hexToBytes
-import org.junit.Test
-import org.junit.jupiter.api.assertThrows
-import java.util.*
-
-class TlvDecoderTest {
-
- private val rawData = byteArrayOf(1, 8, -53, 34, 0, 0, 0, 2, 115, 116, 32, 11, 83, 77, 65, 82, 84, 32, 67, 65, 83, 72, 0, 2, 1, 2, -128, 6, 50, 46, 49, 49, 114, 0, 3, 65, 4, -49, 11, -50, -66, -121, -25, -2, 65, 65, -13, 14, 49, 27, -82, -33, -85, -113, 65, 20, 8, -39, -75, 57, 45, 65, -31, 35, 44, 38, 40, 63, -44, 113, -45, -75, -95, -118, 118, 29, 65, 117, -24, -53, 82, -72, 91, -20, -96, -77, -103, -14, -63, 52, -127, -123, -27, -16, -128, -67, -3, -104, -26, -22, 65, 10, 4, 0, 0, 126, 33, 12, 90, -127, 2, 0, 41, -126, 4, 7, -29, 5, 2, -125, 7, 84, 65, 78, 71, 69, 77, 0, -124, 3, 69, 84, 72, -122, 64, 111, -103, 48, -114, -40, 18, -103, 26, -102, -12, -38, -78, -90, -9, -98, 88, -47, -100, -24, 24, -105, -70, -72, 6, 94, -96, -77, 11, -123, -28, -118, 37, 63, 107, -55, -11, 23, -12, 13, -23, -121, -63, 36, -59, 70, 116, 91, -125, -34, -69, 23, -112, 6, 17, 4, -49, 68, -56, 29, -45, 81, 10, 97, 83, 48, 65, 4, -127, -106, -86, 75, 65, 10, -60, 74, 59, -100, -50, 24, -25, -66, 34, 106, -22, 7, 10, -52, -125, -87, -49, 103, 84, 15, -84, 73, -81, 37, 18, -97, 106, 83, -118, 40, -83, 99, 65, 53, -114, 60, 79, -103, 99, 6, 79, 126, 54, 83, 114, -90, 81, -45, 116, -27, -62, 60, -35, 55, -3, 9, -101, -14, 5, 10, 115, 101, 99, 112, 50, 53, 54, 107, 49, 0, 8, 4, 0, 15, 66, 64, 7, 1, 0, 9, 2, 11, -72, 96, 65, 4, -42, -5, -41, -84, -23, 88, 2, 86, -63, -118, -123, -10, -66, -82, -107, -68, -93, 111, 47, 93, -20, -86, 74, 28, 21, 81, 93, -21, -124, -57, -102, 55, 17, 84, -66, -68, -22, -128, 126, -99, -65, -54, -42, 59, -25, -21, -124, 5, 59, -16, -72, 73, 48, 16, -27, 103, -112, -73, 2, 96, -51, 41, -42, 116, 98, 4, 0, 15, 66, 52, 99, 4, 0, 0, 0, 13, 15, 1, 0)
-
- private val tlvData = Tlv.deserialize(rawData)
-
- private val tlvMapper = TlvDecoder(tlvData!!)
-
- private val cardDataRaw: ByteArray = tlvMapper.decode(TlvTag.CardData)
- private val cardDataMapper = TlvDecoder(Tlv.deserialize(cardDataRaw)!!)
-
- @Test
- fun `map optional when value is present`() {
- val settingsMask: SettingsMask? = tlvMapper.decodeOptional(TlvTag.SettingsMask)
- assertThat(settingsMask)
- .isNotNull()
- }
-
- @Test
- fun `map optional when no tag returns null`() {
- val tokenSymbol: String? = tlvMapper.decodeOptional(TlvTag.TokenSymbol)
- assertThat(tokenSymbol)
- .isNull()
- }
-
- @Test
- fun `map when value is null throws MissingTagException`() {
- assertThrows {
- tlvMapper.decode(TlvTag.TokenSymbol)
- }
- }
-
- @Test
- fun `map optional to wrong type throws WrongTypeException`() {
- assertThrows {
- tlvMapper.decodeOptional(TlvTag.CardData)
- }
- }
-
- @Test
- fun `map to wrong type throws WrongTypeException`() {
- assertThrows {
- tlvMapper.decode(TlvTag.CardData)
- }
- }
-
- @Test
- fun `map boolean missing flag returns false`() {
- val terminalIsLinked: Boolean = tlvMapper.decode(TlvTag.TerminalIsLinked)
- assertThat(terminalIsLinked)
- .isFalse()
- }
-
- @Test
- fun `map SettingsMask returns correct value`() {
- val settingsMask: SettingsMask = tlvMapper.decode(TlvTag.SettingsMask)
- assertThat(settingsMask)
- .isNotNull()
- assertThat(settingsMask.rawValue)
- .isEqualTo(32289)
- assertThat(settingsMask.contains(Settings.SkipSecurityDelayIfValidatedByLinkedTerminal))
- .isFalse()
- assertThat(settingsMask.contains(Settings.IsReusable))
- .isTrue()
- assertThat(settingsMask.contains(Settings.AllowSwapPIN2))
- .isTrue()
- assertThat(settingsMask.contains(Settings.UseDynamicNdef))
- .isTrue()
- assertThat(settingsMask.contains(Settings.ProhibitPurgeWallet))
- .isFalse()
- }
-
- @Test
- fun `map SigningMethods single value returns correct value`() {
- val signingMethods: SigningMethodMask = tlvMapper.decode(TlvTag.SigningMethod)
- assertThat(signingMethods.contains(SigningMethod.SignHash))
- .isTrue()
- }
-
- @Test
- fun `map SigningMethods set of methods returns correct value`() {
- val localMapper = TlvDecoder(Tlv.deserialize("070195".hexToBytes())!!)
-
- val signingMethods: SigningMethodMask = localMapper.decode(TlvTag.SigningMethod)
- assertThat(signingMethods.contains(SigningMethod.SignHash))
- .isTrue()
- assertThat(signingMethods.contains(SigningMethod.SignHashValidateByIssuer))
- .isTrue()
- assertThat(signingMethods.contains(SigningMethod.SignHashValidateByIssuerWriteIssuerData))
- .isTrue()
- assertThat(signingMethods.contains(SigningMethod.SignRaw))
- .isFalse()
- assertThat(signingMethods.contains(SigningMethod.SignRawValidateByIssuer))
- .isFalse()
- assertThat(signingMethods.contains(SigningMethod.SignRawValidateByIssuerWriteIssuerData))
- .isFalse()
- assertThat(signingMethods.contains(SigningMethod.SignPos))
- .isFalse()
- }
-
- @Test
- fun `map CardStatus returns correct value`() {
- val cardStatus: CardStatus = tlvMapper.decode(TlvTag.Status)
- assertThat(cardStatus)
- .isEqualTo(CardStatus.Loaded)
- }
-
- @Test
- fun `map ProductMask with raw value 5 returns correct value`() {
- val localMapper = TlvDecoder(listOf(Tlv(TlvTag.ProductMask, byteArrayOf(5))))
- val productMask: ProductMask = localMapper.decode(TlvTag.ProductMask)
- assertThat(productMask.contains(Product.Note) && productMask.contains(Product.IdCard))
- .isTrue()
- }
-
- @Test
- fun `map ProductMask with raw value 1 returns correct value`() {
- val localMapper = TlvDecoder(listOf(Tlv(TlvTag.ProductMask, byteArrayOf(1))))
- val productMask: ProductMask = localMapper.decode(TlvTag.ProductMask)
- assertThat(productMask.contains(Product.Note))
- .isTrue()
- }
-
- @Test
- fun `map Enum with unknown code throws ConversionException error`() {
- val localMapper = TlvDecoder(listOf(Tlv(TlvTag.CurveId, "test".toByteArray())))
- assertThrows {
- localMapper.decode(TlvTag.CurveId)
- }
- }
-
- @Test
- fun `map DateTime returns correct value`() {
- val date: Date = cardDataMapper.decode(TlvTag.ManufactureDateTime)
- val expected = Calendar.getInstance().apply { this.set(2019, 4, 2, 0, 0, 0) }.time
- assertThat(date.toString())
- .isEqualTo(expected.toString())
- }
-
- @Test
- fun `map EllipticCurve returns correct value`() {
- val ellipticCurve: EllipticCurve = tlvMapper.decode(TlvTag.CurveId)
- assertThat(ellipticCurve)
- .isEqualTo(EllipticCurve.Secp256k1)
- }
-
- @Test
- fun `map ByteArray returns correctly`() {
- val cardPublicKey: ByteArray = tlvMapper.decode(TlvTag.CardPublicKey)
- assertThat(cardPublicKey)
- .isInstanceOf(ByteArray::class.java)
- }
-
- @Test
- fun `map Int returns correct value`() {
- val signedHashes: Int = tlvMapper.decode(TlvTag.SignedHashes)
- assertThat(signedHashes)
- .isEqualTo(13)
- }
-
- @Test
- fun `map Int with wrong value throws ConversionException`() {
- val localMapper = TlvDecoder(listOf(Tlv(TlvTag.SignedHashes, byteArrayOf(1, 2, 3, 4, 5))))
- assertThrows {
- localMapper.decode(TlvTag.SignedHashes)
- }
- }
-
- @Test
- fun `map UTF8 returns correct value`() {
- val blockchainId: String = cardDataMapper.decode(TlvTag.BlockchainId)
- assertThat(blockchainId)
- .isEqualTo("ETH")
- }
-
- @Test
- fun `map Hex returns correct value`() {
- val cardId: String = tlvMapper.decode(TlvTag.CardId)
- assertThat(cardId)
- .isEqualTo("cb22000000027374")
- }
-}
\ No newline at end of file
diff --git a/tangem-core/src/test/java/com/tangem/common/tlv/TlvTest.kt b/tangem-core/src/test/java/com/tangem/common/tlv/TlvTest.kt
deleted file mode 100644
index c2d1e0e09d..0000000000
--- a/tangem-core/src/test/java/com/tangem/common/tlv/TlvTest.kt
+++ /dev/null
@@ -1,111 +0,0 @@
-package com.tangem.common.tlv
-
-import com.google.common.truth.Truth.assertThat
-import com.tangem.common.extensions.calculateSha256
-import com.tangem.common.extensions.hexToBytes
-import org.junit.Test
-
-
-class TlvTest {
-
- @Test
- fun `TLVs to bytes, only PIN`() {
- val tlvs = listOf(
- Tlv(TlvTag.Pin, "000000".calculateSha256())
- )
- val expected = byteArrayOf(16, 32, -111, -76, -47, 66, -126, 63, 125, 32, -59, -16, -115,
- -10, -111, 34, -34, 67, -13, 95, 5, 122, -104, -115, -106, 25, -10, -45, 19, -124,
- -123, -55, -94, 3)
-
- assertThat(tlvs.serialize())
- .isEqualTo(expected)
- }
-
- @Test
- fun `TLVs to bytes, check wallet`() {
- val tlvs = listOf(
- Tlv(TlvTag.Pin, "000000".calculateSha256()),
- Tlv(TlvTag.CardId, "cb22000000027374".hexToBytes()),
- Tlv(TlvTag.Challenge, byteArrayOf(-82, -78, -31, 34, 66, -19, -86, -1, 26, 8, 100, -126, -74, 20, -28, 83))
- )
-
- val expected = byteArrayOf(16, 32, -111, -76, -47, 66, -126, 63, 125, 32, -59, -16, -115, -10,
- -111, 34, -34, 67, -13, 95, 5, 122, -104, -115, -106, 25, -10, -45, 19, -124, -123,
- -55, -94, 3, 1, 8, -53, 34, 0, 0, 0, 2, 115, 116, 22, 16, -82, -78, -31, 34, 66, -19,
- -86, -1, 26, 8, 100, -126, -74, 20, -28, 83)
-
- assertThat(tlvs.serialize())
- .isEqualTo(expected)
- }
-
- @Test
- fun `Bytes to Tlvs, only PIN`() {
- val bytes = byteArrayOf(16, 32, -111, -76, -47, 66, -126, 63, 125, 32, -59, -16, -115,
- -10, -111, 34, -34, 67, -13, 95, 5, 122, -104, -115, -106, 25, -10, -45, 19, -124,
- -123, -55, -94, 3)
-
- val tlvs = Tlv.deserialize(bytes)
-
- assertThat(tlvs)
- .isNotNull()
- assertThat(tlvs)
- .isNotEmpty()
-
- val pin = tlvs!!.find { it.tag == TlvTag.Pin }?.value
- val pinExpected = "000000".calculateSha256()
-
- assertThat(pin)
- .isEqualTo(pinExpected)
- }
-
- @Test
- fun `Bytes to TLVs, check wallet TLVs`() {
- val bytes = byteArrayOf(16, 32, -111, -76, -47, 66, -126, 63, 125, 32, -59, -16, -115, -10,
- -111, 34, -34, 67, -13, 95, 5, 122, -104, -115, -106, 25, -10, -45, 19, -124, -123,
- -55, -94, 3, 1, 8, -53, 34, 0, 0, 0, 2, 115, 116, 22, 16, -82, -78, -31, 34, 66, -19,
- -86, -1, 26, 8, 100, -126, -74, 20, -28, 83)
-
- val tlvs = Tlv.deserialize(bytes)
-
- assertThat(tlvs)
- .isNotNull()
- assertThat(tlvs)
- .isNotEmpty()
-
- val pin = tlvs!!.find { it.tag == TlvTag.Pin }?.value
- val pinExpected = "000000".calculateSha256()
- assertThat(pin)
- .isEqualTo(pinExpected)
-
- val cardId = tlvs.find { it.tag == TlvTag.CardId }?.value
- val cardIdExpected = "cb22000000027374".hexToBytes()
- assertThat(cardId)
- .isEqualTo(cardIdExpected)
-
- val challenge = tlvs.find { it.tag == TlvTag.Challenge }?.value
- val challengeExpected = byteArrayOf(-82, -78, -31, 34, 66, -19, -86, -1, 26, 8, 100, -126, -74, 20, -28, 83)
- assertThat(challenge)
- .isEqualTo(challengeExpected)
- }
-
- @Test
- fun `Bytes to TLVs, wrong values`() {
- val bytes = byteArrayOf(0)
- val tlvs = Tlv.deserialize(bytes)
- assertThat(tlvs)
- .isNull()
-
- val bytes1 = byteArrayOf(0, 0, 0, 0, 0, 0, 0)
- val tlvs1 = Tlv.deserialize(bytes1)
- assertThat(tlvs1)
- .isNull()
- }
-
- @Test
- fun `parse Slix tag response`() {
- val response = "03ff010f91010b550474616e67656d2e636f6d140f11616e64726f69642e636f6d3a706b67636f6d2e74616e67656d2e77616c6c65745411c974616e67656d2e636f6d3a77616c6c657490000c618102ffff8a0102820407e40109830b54414e47454d2053444b008403584c4d86400e71c1f060387029688254320b90abeae471bcafbbe8ea3880903bdb8d1cc389d032b982e1ffd7ef49e66f1780123b763dd2f3a9a9494eb0fad4ae8cf306672c60207c967a51077c14fc49d867f23b8d0eaf60cad479a56587e894571b7fb33690176140345fbe53f5be0ec871e91c317cde2bd0396d47e4b945c138c153b0271f636a73cf531df1bc54ac4fcdbce42f81b40d58e0265d34e28121a4c50fdfe329a97f6000fe000000000000000000000000000000000000000000000000000000000000000000000000000000"
- val tlvs = Tlv.deserialize(response.hexToBytes(), true)
- assertThat(tlvs)
- .isNotEmpty()
- }
-}
\ No newline at end of file
diff --git a/tangem-core/src/test/java/com/tangem/crypto/CryptoUtilsTest.kt b/tangem-core/src/test/java/com/tangem/crypto/CryptoUtilsTest.kt
deleted file mode 100644
index afdb6da581..0000000000
--- a/tangem-core/src/test/java/com/tangem/crypto/CryptoUtilsTest.kt
+++ /dev/null
@@ -1,50 +0,0 @@
-package com.tangem.crypto
-
-import com.google.common.truth.Truth.assertThat
-import com.tangem.commands.EllipticCurve
-import com.tangem.crypto.CryptoUtils.generatePublicKey
-import com.tangem.crypto.CryptoUtils.generateRandomBytes
-import com.tangem.crypto.CryptoUtils.verify
-import org.junit.jupiter.api.BeforeEach
-import org.junit.jupiter.api.Test
-
-
-class CryptoUtilsTest {
-
- @BeforeEach
- internal fun setUp() {
- CryptoUtils.initCrypto()
- }
-
- @Test
- fun generateRandomBytesTest() {
- val privateKey: ByteArray = generateRandomBytes(32)
- assertThat(privateKey)
- .hasLength(32)
- assertThat(privateKey.sum())
- .isNotEqualTo(0)
- }
-
- @Test
- internal fun verifyEd25519Test() {
- val verified = verifySignature_withSampleData(EllipticCurve.Ed25519)
- assertThat(verified)
- .isTrue()
- }
-
- @Test
- internal fun verifySecp256k1Test() {
- val verified = verifySignature_withSampleData(EllipticCurve.Secp256k1)
- assertThat(verified)
- .isTrue()
- }
-
- private fun verifySignature_withSampleData(curve: EllipticCurve): Boolean {
- val privateKey = ByteArray(32) { 1 }
- val publicKey = generatePublicKey(privateKey, curve)
- val message = ByteArray(64) { 5 }
- val signature = message.sign(privateKey, curve)
- return verify(publicKey, message, signature, curve)
- }
-
-}
\ No newline at end of file
diff --git a/tangem-devkit/.gitignore b/tangem-devkit/.gitignore
deleted file mode 100644
index 796b96d1c4..0000000000
--- a/tangem-devkit/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/build
diff --git a/tangem-devkit/build.gradle b/tangem-devkit/build.gradle
deleted file mode 100644
index fd35b8f7ed..0000000000
--- a/tangem-devkit/build.gradle
+++ /dev/null
@@ -1,56 +0,0 @@
-apply plugin: 'com.android.application'
-apply plugin: 'kotlin-android'
-apply plugin: 'kotlin-android-extensions'
-android {
- compileSdkVersion 29
- buildToolsVersion "29.0.3"
-
- defaultConfig {
- applicationId "com.tangem.devkit"
- minSdkVersion 21
- targetSdkVersion 29
- versionCode 4
- versionName "1.2"
-
- testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
- }
-
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
- }
- }
- compileOptions {
- sourceCompatibility JavaVersion.VERSION_1_8
- targetCompatibility JavaVersion.VERSION_1_8
- }
- kotlinOptions {
- jvmTarget = '1.8'
- }
-}
-
-dependencies {
- implementation project(':tangem-core')
- implementation project(':tangem-sdk')
- implementation fileTree(dir: 'libs', include: ['*.jar'])
-
- testImplementation 'junit:junit:4.12'
- androidTestImplementation 'androidx.test:runner:1.2.0'
- androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
-
- implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$versions.kotlin"
-
- implementation 'androidx.appcompat:appcompat:1.1.0'
- implementation 'androidx.core:core-ktx:1.2.0'
- implementation "androidx.constraintlayout:constraintlayout:2.0.0-beta4"
- implementation "androidx.navigation:navigation-fragment-ktx:2.2.1"
- implementation "androidx.navigation:navigation-ui-ktx:2.2.1"
- implementation "androidx.recyclerview:recyclerview:1.2.0-alpha02"
- implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
- implementation "com.google.android.material:material:1.2.0-alpha05"
- implementation "androidx.viewpager2:viewpager2:1.0.0"
-
- implementation 'com.google.code.gson:gson:2.8.6'
- implementation 'com.github.gbIxaHue:eu4d:0.3.8'
-}
diff --git a/tangem-devkit/proguard-rules.pro b/tangem-devkit/proguard-rules.pro
deleted file mode 100644
index f1b424510d..0000000000
--- a/tangem-devkit/proguard-rules.pro
+++ /dev/null
@@ -1,21 +0,0 @@
-# Add project specific ProGuard rules here.
-# You can control the set of applied configuration files using the
-# proguardFiles setting in build.gradle.
-#
-# For more details, see
-# http://developer.android.com/guide/developing/tools/proguard.html
-
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-# public *;
-#}
-
-# Uncomment this to preserve the line number information for
-# debugging stack traces.
-#-keepattributes SourceFile,LineNumberTable
-
-# If you keep the line number information, uncomment this to
-# hide the original source file name.
-#-renamesourcefileattribute SourceFile
diff --git a/tangem-devkit/src/main/AndroidManifest.xml b/tangem-devkit/src/main/AndroidManifest.xml
deleted file mode 100644
index e0749468f0..0000000000
--- a/tangem-devkit/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,78 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/tangem-devkit/src/main/ic_launcher-playstore.png b/tangem-devkit/src/main/ic_launcher-playstore.png
deleted file mode 100644
index 6e5af9f8f6..0000000000
Binary files a/tangem-devkit/src/main/ic_launcher-playstore.png and /dev/null differ
diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/AppTangemDemo.kt b/tangem-devkit/src/main/java/com/tangem/devkit/AppTangemDemo.kt
deleted file mode 100644
index 60ee3d4564..0000000000
--- a/tangem-devkit/src/main/java/com/tangem/devkit/AppTangemDemo.kt
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.tangem.devkit
-
-import android.app.Application
-import android.content.Context
-import android.content.SharedPreferences
-import com.tangem.devkit._arch.structure.ILog
-import com.tangem.devkit._arch.structure.ItemLogger
-import com.tangem.devkit.commons.TangemLogger
-import ru.dev.gbixahue.eu4d.lib.android.global.log.Log
-
-/**
-[REDACTED_AUTHOR]
- */
-class AppTangemDemo : Application() {
-
- override fun onCreate() {
- super.onCreate()
-
- AppTangemDemo.appInstance = this
- setupLoggers()
- }
-
- private fun setupLoggers() {
- Log.setLogger(TangemLogger())
- ILog.setLogger(ItemLogger())
- }
-
- fun sharedPreferences(name: String = "DevKitApp", mode: Int = Context.MODE_PRIVATE): SharedPreferences {
- return getSharedPreferences(name, mode)
- }
-
- companion object {
- lateinit var appInstance: AppTangemDemo
- }
-}
diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/Old_MainActivity.kt b/tangem-devkit/src/main/java/com/tangem/devkit/Old_MainActivity.kt
deleted file mode 100644
index ffccc70603..0000000000
--- a/tangem-devkit/src/main/java/com/tangem/devkit/Old_MainActivity.kt
+++ /dev/null
@@ -1,143 +0,0 @@
-package com.tangem.devkit
-
-import android.content.Intent
-import android.os.Bundle
-import androidx.appcompat.app.AppCompatActivity
-import com.tangem.TangemSdk
-import com.tangem.common.CompletionResult
-import com.tangem.tangem_sdk_new.extensions.init
-import kotlinx.android.synthetic.main.old_activity_main.*
-
-class Old_MainActivity : AppCompatActivity() {
-
- private lateinit var tangemSdk: TangemSdk
- private lateinit var cardId: String
- private lateinit var issuerData: ByteArray
- private lateinit var issuerDataSignature: ByteArray
- private var issuerDataCounter: Int = 1
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.old_activity_main)
-
- tangemSdk = TangemSdk.init(this)
-
- btn_scan?.setOnClickListener { _ ->
- tangemSdk.scanCard { taskEvent ->
- when (taskEvent) {
- is CompletionResult.Success -> {
- // Handle returned card data
- val card = taskEvent.data
- cardId = card.cardId
- runOnUiThread {
- tv_card_cid?.text = cardId
- btn_create_wallet.isEnabled = true
- tv_card_cid?.text = cardId
- btn_sign.isEnabled = true
- btn_read_issuer_data.isEnabled = true
- btn_read_issuer_extra_data.isEnabled = true
- btn_write_issuer_data.isEnabled = true
- btn_purge_wallet.isEnabled = true
- btn_create_wallet.isEnabled = true
-
- }
- }
- }
- }
- }
- btn_sign?.setOnClickListener { _ ->
- tangemSdk.sign(
- createSampleHashes(),
- cardId) {
- when (it) {
- is CompletionResult.Failure -> {
- runOnUiThread { tv_card_cid?.text = it.error::class.simpleName }
- }
- is CompletionResult.Success -> runOnUiThread { tv_card_cid?.text = cardId + "was used to sign sample hashes." }
- }
- }
- }
- btn_read_issuer_data?.setOnClickListener { _ ->
- tangemSdk.readIssuerData(cardId) {
- when (it) {
- is CompletionResult.Failure -> {
- runOnUiThread { tv_card_cid?.text = it.error::class.simpleName }
- }
- is CompletionResult.Success -> runOnUiThread {
- btn_write_issuer_data.isEnabled = true
- tv_card_cid?.text = it.data.issuerData.contentToString()
- issuerData = it.data.issuerData
- issuerDataSignature = it.data.issuerDataSignature
- }
- }
- }
- }
- btn_write_issuer_data?.setOnClickListener { _ ->
- tangemSdk.writeIssuerData(
- cardId,
- issuerData,
- issuerDataSignature) {
- when (it) {
- is CompletionResult.Failure -> {
- runOnUiThread { tv_card_cid?.text = it.error::class.simpleName }
- }
- is CompletionResult.Success -> runOnUiThread {
- tv_card_cid?.text = it.data.cardId
- }
- }
- }
- }
- btn_read_issuer_extra_data?.setOnClickListener { _ ->
- tangemSdk.readIssuerExtraData(cardId) {
- when (it) {
- is CompletionResult.Failure -> {
- runOnUiThread { tv_card_cid?.text = it.error::class.simpleName }
- }
- is CompletionResult.Success -> runOnUiThread {
- issuerDataCounter = (it.data.issuerDataCounter ?: 0) + 1
- btn_write_issuer_data.isEnabled = true
- tv_card_cid?.text = "Read ${it.data.issuerData.size} bytes of data."
- }
- }
- }
- }
- btn_purge_wallet?.setOnClickListener { _ ->
- tangemSdk.purgeWallet(
- cardId) {
- when (it) {
- is CompletionResult.Failure -> {
- runOnUiThread { tv_card_cid?.text = it.error::class.simpleName }
- }
- is CompletionResult.Success -> runOnUiThread {
- tv_card_cid?.text = it.data.status.name
- }
- }
- }
- }
- btn_create_wallet?.setOnClickListener { _ ->
- tangemSdk.createWallet(
- cardId) {
- when (it) {
- is CompletionResult.Failure -> {
- runOnUiThread { tv_card_cid?.text = it.error::class.simpleName }
- }
- is CompletionResult.Success -> runOnUiThread {
- tv_card_cid?.text = it.data.status.name
- btn_sign.isEnabled = true
- btn_read_issuer_data.isEnabled = true
- btn_purge_wallet.isEnabled = true
- btn_create_wallet.isEnabled = false
-
- }
- }
- }
- }
- btn_read_write_user_data?.setOnClickListener { startActivity(Intent(this, TestUserDataActivity::class.java)) }
- }
-
- private fun createSampleHashes(): Array {
- val hash1 = ByteArray(32) { 1 }
- val hash2 = ByteArray(32) { 2 }
- return arrayOf(hash1, hash2)
- }
-}
\ No newline at end of file
diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/TestUserDataActivity.kt b/tangem-devkit/src/main/java/com/tangem/devkit/TestUserDataActivity.kt
deleted file mode 100644
index 5628c01f29..0000000000
--- a/tangem-devkit/src/main/java/com/tangem/devkit/TestUserDataActivity.kt
+++ /dev/null
@@ -1,147 +0,0 @@
-package com.tangem.devkit
-
-import android.os.Bundle
-import android.view.View
-import android.widget.CompoundButton
-import android.widget.TextView
-import androidx.appcompat.app.AppCompatActivity
-import com.tangem.SessionEnvironment
-import com.tangem.TangemSdk
-import com.tangem.TangemSdkError
-import com.tangem.common.CompletionResult
-import com.tangem.tangem_sdk_new.extensions.init
-import kotlinx.android.synthetic.main.activity_test_user_data.*
-import java.nio.charset.StandardCharsets
-
-/**
-[REDACTED_AUTHOR]
- */
-class TestUserDataActivity : AppCompatActivity() {
-
- private lateinit var tangemSdk: TangemSdk
- private lateinit var writeOptions: WriteOptions
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_test_user_data)
-
- init()
- initWriteOptions()
- }
-
- private fun init() {
- tangemSdk = TangemSdk.init(this)
-
- btn_scan?.setOnClickListener { _ ->
- tangemSdk.scanCard { taskEvent ->
- when (taskEvent) {
- is CompletionResult.Success -> {
- // Handle returned card data
- writeOptions.cardId = taskEvent.data.cardId
- runOnUiThread { showReadWriteSection(true) }
- }
- }
- }
- }
-
- btn_write.setOnClickListener {
- if (writeOptions.cardId == null) return@setOnClickListener
-
- tangemSdk.writeUserData(
- writeOptions.cardId!!,
- writeOptions.userData,
- writeOptions.userCounter
- ) {
- when (it) {
- is CompletionResult.Failure -> handleError(tv_write_result, it.error)
- is CompletionResult.Success -> {
- runOnUiThread { tv_write_result?.text = "Success" }
- }
- }
- }
- }
-
- btn_read.setOnClickListener {
- if (writeOptions.cardId == null) return@setOnClickListener
-
- tangemSdk.readUserData(writeOptions.cardId!!) {
- when (it) {
- is CompletionResult.Failure -> handleError(tv_write_result, it.error)
- is CompletionResult.Success -> {
- runOnUiThread {
-
- tv_read_result?.text = "Success"
-
- writeOptions.userData = it.data.userData
- writeOptions.userProtectedData = it.data.userProtectedData
- writeOptions.userCounter = it.data.userCounter
- writeOptions.userProtectedCounter = it.data.userProtectedCounter
-
- tv_card_cid.text = it.data.cardId
- tv_data.text = String(it.data.userData, StandardCharsets.US_ASCII)
- tv_protected_data.text = String(it.data.userProtectedData, StandardCharsets.US_ASCII)
- tv_counter.text = it.data.userCounter.toString()
- tv_protected_counter.text = it.data.userProtectedCounter.toString()
- }
-
- }
- }
- }
- }
- }
-
- private fun handleError(tv: TextView, error: TangemSdkError) {
- if (error is TangemSdkError.UserCancelled) return
-
- runOnUiThread { tv.text = error::class.simpleName }
- }
-
- private fun initWriteOptions() {
- writeOptions = WriteOptions()
-
- chb_with_ud.setOnCheckedChangeListener { buttonView, isChecked -> writeOptions.updateData(buttonView) }
- chb_with_ud_protected.setOnCheckedChangeListener { buttonView, isChecked -> writeOptions.updateProtectedData(buttonView) }
- chb_with_counter.setOnCheckedChangeListener { buttonView, isChecked -> writeOptions.updateCounter(buttonView) }
- chb_with_protected_counter.setOnCheckedChangeListener { buttonView, isChecked -> writeOptions.updateProtectedCounter(buttonView) }
- chb_with_pin2.setOnCheckedChangeListener { buttonView, isChecked -> writeOptions.updatePin2(buttonView) }
- }
-
- private fun showReadWriteSection(show: Boolean) {
- val state = if (show) View.VISIBLE else View.GONE
- cl_read_write.visibility = state
- }
-}
-
-class WriteOptions {
- var cardId: String? = null
- var userData: ByteArray? = null
- var userProtectedData: ByteArray? = null
- var userCounter: Int? = null
- var userProtectedCounter: Int? = null
- var pin2: String? = null
-
- fun updateData(chbx: CompoundButton) {
- val value = "simple user data".toByteArray()
- userData = if (chbx.isChecked) value else null
- }
-
- fun updateProtectedData(chbx: CompoundButton) {
- val value = "protected user data".toByteArray()
- userProtectedData = if (chbx.isChecked) value else null
- }
-
- fun updateCounter(chbx: CompoundButton) {
- val value = if (userCounter == null) 0 else userCounter!! + 1
- userCounter = if (chbx.isChecked) value else null
- }
-
- fun updateProtectedCounter(chbx: CompoundButton) {
- val value = if (userProtectedCounter == null) 0 else userProtectedCounter!! + 1
- userProtectedCounter = if (chbx.isChecked) value else null
- }
-
- fun updatePin2(chbx: CompoundButton) {
- val value = SessionEnvironment.DEFAULT_PIN2
- pin2 = if (chbx.isChecked) value else null
- }
-}
\ No newline at end of file
diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/_arch/SingleLiveEvent.kt b/tangem-devkit/src/main/java/com/tangem/devkit/_arch/SingleLiveEvent.kt
deleted file mode 100644
index 1e6ed8667e..0000000000
--- a/tangem-devkit/src/main/java/com/tangem/devkit/_arch/SingleLiveEvent.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.tangem.devkit._arch
-
-import android.util.Log
-import androidx.annotation.MainThread
-import androidx.annotation.Nullable
-import androidx.lifecycle.LifecycleOwner
-import androidx.lifecycle.MutableLiveData
-import androidx.lifecycle.Observer
-import java.util.concurrent.atomic.AtomicBoolean
-
-/**
-[REDACTED_AUTHOR]
- */
-class SingleLiveEvent : MutableLiveData() {
- private val mPending: AtomicBoolean = AtomicBoolean(false)
-
- override fun observe(owner: LifecycleOwner, observer: Observer) {
- if (hasActiveObservers()) {
- Log.w(TAG, "Multiple observers registered but only one will be notified of changes.")
- }
-
- // Observe the internal MutableLiveData
- super.observe(owner, Observer {
- if (mPending.compareAndSet(true, false)) {
- observer.onChanged(it)
- }
- })
- }
-
- @MainThread
- override fun setValue(@Nullable t: T?) {
- mPending.set(true)
- super.setValue(t)
- }
-
- @MainThread
- fun call() {
- setValue(null)
- }
-
- companion object {
- private const val TAG = "SingleLiveEvent"
- }
-}
\ No newline at end of file
diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/_arch/structure/HelpAbstracts.kt b/tangem-devkit/src/main/java/com/tangem/devkit/_arch/structure/HelpAbstracts.kt
deleted file mode 100644
index 018e074061..0000000000
--- a/tangem-devkit/src/main/java/com/tangem/devkit/_arch/structure/HelpAbstracts.kt
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.tangem.devkit._arch.structure
-
-/**
-[REDACTED_AUTHOR]
- */
-typealias Payload = MutableMap
-
-interface PayloadHolder {
- val payload: Payload
-
- fun get(key: String): Any? = payload[key]
- fun remove(key: String): Any? = payload.remove(key)
- fun set(key: String, value: Any?) {
- payload[key] = value
- }
-}
\ No newline at end of file
diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/_arch/structure/Ids.kt b/tangem-devkit/src/main/java/com/tangem/devkit/_arch/structure/Ids.kt
deleted file mode 100644
index bc05f80fca..0000000000
--- a/tangem-devkit/src/main/java/com/tangem/devkit/_arch/structure/Ids.kt
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.tangem.devkit._arch.structure
-
-/**
-[REDACTED_AUTHOR]
- */
-interface Id {
-
- companion object {
- fun getTag(id: Id): String {
- val className = id.javaClass.simpleName
- return if (id is Enum<*>) "$className.${id.name}" else className
- }
- }
-}
-
-class StringId(val value: String) : Id
-
-class StringResId(val value: Int) : Id
-
-enum class Additional : Id {
- UNDEFINED,
- JSON_INCOMING,
- JSON_OUTGOING,
- JSON_TAILS,
-}
\ No newline at end of file
diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/_arch/structure/Logger.kt b/tangem-devkit/src/main/java/com/tangem/devkit/_arch/structure/Logger.kt
deleted file mode 100644
index 5ba36bbbaa..0000000000
--- a/tangem-devkit/src/main/java/com/tangem/devkit/_arch/structure/Logger.kt
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.tangem.devkit._arch.structure
-
-import ru.dev.gbixahue.eu4d.lib.android.global.log.Logger
-import ru.dev.gbixahue.eu4d.lib.android.global.log.TagLogger
-import ru.dev.gbixahue.eu4d.lib.android.global.log.profiling.SimpleLogProfiler
-import ru.dev.gbixahue.eu4d.lib.kotlin.stringOf
-
-/**
-[REDACTED_AUTHOR]
- */
-object ILog {
-
- private var logger: Logger? = null
-
- fun setLogger(logger: Logger) {
- ILog.logger = logger
- }
-
- fun d(from: Any, msg: Any?, value: Any? = null) {
- logger?.d(from, stringOf(msg), value)
- }
-
- fun w(from: Any, msg: Any?, value: Any? = null) {
- logger?.w(from, stringOf(msg), value)
- }
-
- fun e(from: Any, msg: Any?, value: Any? = null) {
- logger?.e(from, stringOf(msg), value)
- }
-}
-
-class ItemLogger : TagLogger("ITEM") {
- init {
- msProfiler = SimpleLogProfiler()
- }
-}
\ No newline at end of file
diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/_arch/structure/abstraction/Extension.kt b/tangem-devkit/src/main/java/com/tangem/devkit/_arch/structure/abstraction/Extension.kt
deleted file mode 100644
index 41a4aab5ae..0000000000
--- a/tangem-devkit/src/main/java/com/tangem/devkit/_arch/structure/abstraction/Extension.kt
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.tangem.devkit._arch.structure.abstraction
-
-import com.tangem.devkit._arch.structure.Id
-
-/**
-[REDACTED_AUTHOR]
- */
-fun List- .findItem(id: Id): Item? {
- var foundItem: Item? = null
- iterate {
- if (it.id == id) {
- foundItem = it
- return@iterate
- }
- }
- return foundItem
-}
-
-fun List
- .iterate(func: (Item) -> Unit) {
- forEach {
- when (it) {
- is BaseItem -> func(it)
- is ItemGroup -> {
- func(it)
- it.itemList.iterate(func)
- }
- }
- }
-}
\ No newline at end of file
diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/_arch/structure/abstraction/Item.kt b/tangem-devkit/src/main/java/com/tangem/devkit/_arch/structure/abstraction/Item.kt
deleted file mode 100644
index d1fae9c535..0000000000
--- a/tangem-devkit/src/main/java/com/tangem/devkit/_arch/structure/abstraction/Item.kt
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.tangem.devkit._arch.structure.abstraction
-
-import com.tangem.devkit._arch.structure.Id
-
-/**
-[REDACTED_AUTHOR]
- */
-
-interface UpdateBy{
- fun update(value: B)
-}
-
-interface Item: UpdateBy
- {
- val id: Id
- var parent: Item?
- var viewModel: ItemViewModel
-
- fun added(parent: Item) {
- this.parent = parent
- }
-
- fun removed(parent: Item) {
- this.parent = null
- }
-
- fun getData(): D? = viewModel.data as? D
-
- fun setData(value: Any?) {
- viewModel.data = value
- }
-
- fun restoreDefaultData() {
- setData(viewModel.defaultData)
- }
-}
-
-open class BaseItem(
- override val id: Id,
- override var viewModel: ItemViewModel
-) : Item {
-
- override var parent: Item? = null
-
- override fun update(value: Item) {
- viewModel.update(value.viewModel)
- }
-}
\ No newline at end of file
diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/_arch/structure/abstraction/ItemGroup.kt b/tangem-devkit/src/main/java/com/tangem/devkit/_arch/structure/abstraction/ItemGroup.kt
deleted file mode 100644
index 1d38ba6f6d..0000000000
--- a/tangem-devkit/src/main/java/com/tangem/devkit/_arch/structure/abstraction/ItemGroup.kt
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.tangem.devkit._arch.structure.abstraction
-
-import com.tangem.devkit._arch.structure.ILog
-import com.tangem.devkit._arch.structure.Id
-
-/**
-[REDACTED_AUTHOR]
- */
-interface ItemGroup : Item {
- val itemList: MutableList
-
-
- fun setItems(list: MutableList
- )
- fun getItems(): MutableList
-
- fun addItem(item: Item)
- fun removeItem(item: Item)
- fun clear()
-}
-
-open class SimpleItemGroup(
- override val id: Id,
- override var viewModel: ItemViewModel = BaseItemViewModel()
-) : ItemGroup {
-
- override var parent: Item? = null
- override val itemList: MutableList
- = mutableListOf()
-
- override fun setItems(list: MutableList
- ) {
- ILog.d(this, "setItems into: $id, count: ${list.size}")
- itemList.forEach { it.removed(this) }
- itemList.clear()
- list.forEach { addItem(it) }
- }
-
- override fun getItems(): MutableList
- = itemList
-
- override fun addItem(item: Item) {
- ILog.d(this, "addItem into: $id, who: ${item.id}")
- itemList.add(item)
- item.added(this)
- }
-
- override fun removeItem(item: Item) {
- ILog.d(this, "removeItem from: $id, which: ${item.id}")
- itemList.remove(item)
- item.removed(this)
- }
-
- override fun clear() {
- ILog.d(this, "clear $id")
- itemList.clear()
- }
-
- override fun update(value: Item) {
- // nothing to do
- }
-}
\ No newline at end of file
diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/_arch/structure/abstraction/ItemViewModel.kt b/tangem-devkit/src/main/java/com/tangem/devkit/_arch/structure/abstraction/ItemViewModel.kt
deleted file mode 100644
index eead6c8e3d..0000000000
--- a/tangem-devkit/src/main/java/com/tangem/devkit/_arch/structure/abstraction/ItemViewModel.kt
+++ /dev/null
@@ -1,115 +0,0 @@
-package com.tangem.devkit._arch.structure.abstraction
-
-import com.tangem.devkit._arch.structure.ILog
-import com.tangem.devkit._arch.structure.Payload
-import com.tangem.devkit._arch.structure.PayloadHolder
-
-
-/**
-[REDACTED_AUTHOR]
- */
-typealias ValueChanged = (V?) -> Unit
-typealias SafeValueChanged = (V) -> Unit
-
-class KeyValue(val key: String, val value: Any)
-
-class ViewState(
- isVisible: Boolean? = null,
- bgColor: Int? = -1
-) : UpdateBy {
-
- class State(
- stateValue: T,
- var onValueChanged: SafeValueChanged? = null
- ) {
- var value = stateValue
- set(value) {
- if (preventSameChanges && field == value) return
-
- field = value
- onValueChanged?.invoke(value)
- }
-
- internal var preventSameChanges = true
- }
-
- var isVisibleState = State(isVisible)
- var backgroundColor = State(bgColor)
- var descriptionVisibility = State(0x00000008)
-
- internal fun preventSameChanges(isPrevented: Boolean) {
- val states = listOf(isVisibleState, backgroundColor, descriptionVisibility)
- states.forEach { it.preventSameChanges = isPrevented }
- }
-
- override fun update(value: ViewState) {
-// isVisibleState.update(value.isVisibleState)
-// backgroundColor.update(value.backgroundColor)
-// descriptionVisibility.update(value.descriptionVisibility)
- }
-}
-
-interface ItemViewModel : PayloadHolder, UpdateBy {
- val viewState: ViewState
- var data: Any?
- var defaultData: Any?
- var onDataUpdated: ValueChanged?
-
- fun updateDataByView(data: Any?)
-}
-
-open class BaseItemViewModel(
- value: Any? = null,
- override val viewState: ViewState = ViewState()
-) : ItemViewModel {
-
- override val payload: Payload = mutableMapOf()
-
- // Don't update it directly from a View. Use for it updateDataByView()
- override var data: Any? = value
- set(value) {
- if (handleDataUpdates(value)) field = value
- }
-
- // Data for restoring initial value
- override var defaultData: Any? = value
- set(value) {
- field = value
- data = value
- }
-
- // Use it for handling data updates in View
- override var onDataUpdated: ValueChanged? = null
-
- // When data updates directly it invokes onDataUpdated
- // return true = data will update
- // return false = data won't update
- protected open fun handleDataUpdates(value: Any?): Boolean {
- ILog.d(this, "handleDateUpdates: $value")
- onDataUpdated?.invoke(value)
- return true
- }
-
- // Use it to update the data from a View. It disables onDataUpdated to prevent a callback loop
- override fun updateDataByView(data: Any?) {
- ILog.d(this, "data changed: $data")
- val callback = onDataUpdated
- onDataUpdated = null
- this.data = data
- onDataUpdated = callback
- }
-
- override fun update(value: ItemViewModel) {
- viewState.update(value.viewState)
- defaultData = value.defaultData
- data = value.data
- payload.clear()
- payload.putAll(value.payload)
- }
-}
-
-class ListViewModel(
- val itemList: List,
- var selectedItem: Any?,
- override val viewState: ViewState = ViewState()
-) : BaseItemViewModel(selectedItem)
\ No newline at end of file
diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/_arch/structure/abstraction/ModelConverter.kt b/tangem-devkit/src/main/java/com/tangem/devkit/_arch/structure/abstraction/ModelConverter.kt
deleted file mode 100644
index 30c69cd6b2..0000000000
--- a/tangem-devkit/src/main/java/com/tangem/devkit/_arch/structure/abstraction/ModelConverter.kt
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.tangem.devkit._arch.structure.abstraction
-
-import ru.dev.gbixahue.eu4d.lib.kotlin.common.Converter
-
-/**
-[REDACTED_AUTHOR]
- */
-interface DefaultConverter {
- fun convert(from: A, default: B): B
-}
-
-interface TwoWayConverter {
- fun aToB(from: A): B
- fun bToA(from: B): A
-}
-
-interface ItemsToModel : DefaultConverter
, M>
-interface ModelToItems : Converter>
-
-interface ModelConverter : DefaultConverter, M>, Converter>
\ No newline at end of file
diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/_arch/structure/abstraction/Plugin.kt b/tangem-devkit/src/main/java/com/tangem/devkit/_arch/structure/abstraction/Plugin.kt
deleted file mode 100644
index aaa6254d7c..0000000000
--- a/tangem-devkit/src/main/java/com/tangem/devkit/_arch/structure/abstraction/Plugin.kt
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.tangem.devkit._arch.structure.abstraction
-
-/**
-[REDACTED_AUTHOR]
- */
-typealias PluginCallBackResult = (Any?) -> Item
-
-interface Plugin : Item {
- fun invoke(data: Any?, asyncCallback: PluginCallBackResult? = null): Any?
-}
\ No newline at end of file
diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/_arch/structure/impl/Items.kt b/tangem-devkit/src/main/java/com/tangem/devkit/_arch/structure/impl/Items.kt
deleted file mode 100644
index 80145d31e4..0000000000
--- a/tangem-devkit/src/main/java/com/tangem/devkit/_arch/structure/impl/Items.kt
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.tangem.devkit._arch.structure.impl
-
-import com.tangem.devkit._arch.structure.Id
-import com.tangem.devkit._arch.structure.abstraction.*
-
-/**
-[REDACTED_AUTHOR]
- */
-
-open class TypedItem(id: Id, viewModel: ItemViewModel) : BaseItem(id, viewModel) {
- open fun getTypedData(): D? = viewModel.data as? D
-}
-
-open class TextItem(id: Id, viewModel: ItemViewModel) : TypedItem(id, viewModel) {
- constructor(id: Id, value: String? = null, viewState: ViewState = ViewState())
- : this(id, BaseItemViewModel(value, viewState))
-}
-
-open class NumberItem(id: Id, viewModel: ItemViewModel) : TypedItem(id, viewModel) {
- constructor(id: Id, value: Number? = null, viewState: ViewState = ViewState())
- : this(id, BaseItemViewModel(value, viewState))
-}
-
-open class BoolItem(id: Id, viewModel: ItemViewModel) : TypedItem(id, viewModel) {
- constructor(id: Id, value: Boolean? = null, viewState: ViewState = ViewState())
- : this(id, BaseItemViewModel(value, viewState))
-}
-
-
-open class EditTextItem(id: Id, viewModel: ItemViewModel) : TypedItem(id, viewModel) {
- constructor(id: Id, value: String? = null, viewState: ViewState = ViewState())
- : this(id, BaseItemViewModel(value, viewState))
-}
-
-
-open class SpinnerItem(id: Id, viewModel: ListViewModel) : TypedItem(id, viewModel) {
- constructor(id: Id, list: List, selectedValue: Any?, viewState: ViewState = ViewState())
- : this(id, ListViewModel(list, selectedValue, viewState))
-}
\ No newline at end of file
diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/_arch/widget/ItemWidgetBuilder.kt b/tangem-devkit/src/main/java/com/tangem/devkit/_arch/widget/ItemWidgetBuilder.kt
deleted file mode 100644
index 4659c0ac49..0000000000
--- a/tangem-devkit/src/main/java/com/tangem/devkit/_arch/widget/ItemWidgetBuilder.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.tangem.devkit._arch.widget
-
-import android.view.ViewGroup
-import com.tangem.devkit._arch.structure.abstraction.BaseItem
-import com.tangem.devkit._arch.widget.abstraction.ViewWidget
-
-/**
-[REDACTED_AUTHOR]
- */
-interface ItemWidgetBuilder {
- fun build(item: BaseItem, parent: ViewGroup): ViewWidget?
-}
\ No newline at end of file
diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/_arch/widget/WidgetBuilder.kt b/tangem-devkit/src/main/java/com/tangem/devkit/_arch/widget/WidgetBuilder.kt
deleted file mode 100644
index cb39aa9072..0000000000
--- a/tangem-devkit/src/main/java/com/tangem/devkit/_arch/widget/WidgetBuilder.kt
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.tangem.devkit._arch.widget
-
-import android.view.ViewGroup
-import com.tangem.devkit._arch.structure.abstraction.BaseItem
-import com.tangem.devkit._arch.structure.abstraction.Item
-import com.tangem.devkit._arch.structure.abstraction.ItemGroup
-import com.tangem.devkit._arch.widget.abstraction.ViewWidget
-import com.tangem.devkit._arch.widget.impl.LinearGroupWidget
-import com.tangem.devkit._arch.widget.impl.StubWidget
-
-/**
-[REDACTED_AUTHOR]
- */
-class WidgetBuilder(
- private val itemBuilder: ItemWidgetBuilder
-) {
-
- fun build(item: Item, parent: ViewGroup): ViewWidget? {
- return when (item) {
- is ItemGroup -> buildBlock(item, parent)
- is BaseItem -> itemBuilder.build(item, parent)
- else -> StubWidget(item.id, parent)
- }
- }
-
- private fun buildBlock(itemGroup: ItemGroup, parent: ViewGroup): ViewWidget {
- return when (itemGroup) {
- is ItemGroup -> {
- val linearBlock = LinearGroupWidget(parent, itemGroup)
- itemGroup.getItems().forEach { build(it, linearBlock.view as ViewGroup) }
- linearBlock
- }
- else -> StubWidget(itemGroup.id, parent)
- }
- }
-}
\ No newline at end of file
diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/_arch/widget/abstraction/ViewWidget.kt b/tangem-devkit/src/main/java/com/tangem/devkit/_arch/widget/abstraction/ViewWidget.kt
deleted file mode 100644
index e414e89cf7..0000000000
--- a/tangem-devkit/src/main/java/com/tangem/devkit/_arch/widget/abstraction/ViewWidget.kt
+++ /dev/null
@@ -1,81 +0,0 @@
-package com.tangem.devkit._arch.widget.abstraction
-
-import android.graphics.drawable.ColorDrawable
-import android.graphics.drawable.Drawable
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import androidx.annotation.ColorRes
-import com.tangem.devkit.R
-import com.tangem.devkit._arch.structure.Id
-import com.tangem.devkit._arch.structure.StringId
-import com.tangem.devkit._arch.structure.StringResId
-import com.tangem.devkit._arch.structure.abstraction.Item
-import com.tangem.devkit._arch.structure.abstraction.ViewState
-import ru.dev.gbixahue.eu4d.lib.android._android.views.colorFrom
-import ru.dev.gbixahue.eu4d.lib.kotlin.common.LayoutHolder
-
-/**
-[REDACTED_AUTHOR]
- */
-interface ViewWidget : LayoutHolder {
- val view: View
- var item: Item
-
- fun getName(): String
- fun setBackgroundColor(@ColorRes colorId: Int?)
-}
-
-abstract class BaseViewWidget(
- parent: ViewGroup,
- override var item: Item
-) : ViewWidget {
-
- override val view: View = inflate(getLayoutId(), parent)
-
- private var defaultBackground: Drawable? = view.background
-
- init {
- subscribeToViewStateChanges(item.viewModel.viewState)
- initViewState(item.viewModel.viewState)
- view.tag = Id.getTag(item.id)
- }
-
- protected open fun subscribeToViewStateChanges(viewState: ViewState) {
- viewState.isVisibleState.onValueChanged = { state ->
- state?.let { view.visibility = if (it) View.VISIBLE else View.GONE }
- }
- viewState.backgroundColor.onValueChanged = { setBackgroundColor(it) }
- }
-
- protected open fun initViewState(viewState: ViewState) {
- viewState.preventSameChanges(false)
- viewState.isVisibleState.value = viewState.isVisibleState.value
- if (viewState.backgroundColor.value != -1) setBackgroundColor(viewState.backgroundColor.value)
- viewState.preventSameChanges(true)
- }
-
- override fun getName(): String {
- return when (val id = item.id) {
- is StringId -> id.value
- is StringResId -> view.resources.getString(id.value)
- else -> view.resources.getString(R.string.unknown)
- }
- }
-
- override fun setBackgroundColor(colorId: Int?) {
- val background = when {
- colorId == null -> null
- colorId == -1 -> defaultBackground
- else -> ColorDrawable(view.colorFrom(colorId))
- }
- view.background = background
- }
-}
-
-internal fun inflate(id: Int, parent: ViewGroup): View {
- val layoutId = if (id <= 0) R.layout.w_empty else id
- val inflatedView = LayoutInflater.from(parent.context).inflate(layoutId, parent, false)
- parent.addView(inflatedView)
- return inflatedView
-}
\ No newline at end of file
diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/_arch/widget/impl/LinearGroupWidget.kt b/tangem-devkit/src/main/java/com/tangem/devkit/_arch/widget/impl/LinearGroupWidget.kt
deleted file mode 100644
index 54948387de..0000000000
--- a/tangem-devkit/src/main/java/com/tangem/devkit/_arch/widget/impl/LinearGroupWidget.kt
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.tangem.devkit._arch.widget.impl
-
-import android.view.ViewGroup
-import com.tangem.devkit.R
-import com.tangem.devkit._arch.structure.abstraction.ItemGroup
-import com.tangem.devkit._arch.widget.abstraction.BaseViewWidget
-
-/**
-[REDACTED_AUTHOR]
- */
-class LinearGroupWidget(
- parent: ViewGroup,
- itemGroup: ItemGroup
-) : BaseViewWidget(parent, itemGroup) {
-
- override fun getLayoutId(): Int = R.layout.w_personilize_block
-
-}
\ No newline at end of file
diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/_arch/widget/impl/StubWidget.kt b/tangem-devkit/src/main/java/com/tangem/devkit/_arch/widget/impl/StubWidget.kt
deleted file mode 100644
index 0edc41b3be..0000000000
--- a/tangem-devkit/src/main/java/com/tangem/devkit/_arch/widget/impl/StubWidget.kt
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.tangem.devkit._arch.widget.impl
-
-import android.view.ViewGroup
-import com.tangem.devkit.R
-import com.tangem.devkit._arch.structure.Id
-import com.tangem.devkit._arch.structure.abstraction.BaseItem
-import com.tangem.devkit._arch.structure.abstraction.BaseItemViewModel
-import com.tangem.devkit._arch.widget.abstraction.BaseViewWidget
-
-/**
-[REDACTED_AUTHOR]
- */
-class StubWidget(id: Id, parent: ViewGroup) : BaseViewWidget(parent, BaseItem(id, BaseItemViewModel())) {
- override fun getLayoutId(): Int = R.layout.w_empty
-}
\ No newline at end of file
diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/_main/MainActivity.kt b/tangem-devkit/src/main/java/com/tangem/devkit/_main/MainActivity.kt
deleted file mode 100644
index dbfd82105f..0000000000
--- a/tangem-devkit/src/main/java/com/tangem/devkit/_main/MainActivity.kt
+++ /dev/null
@@ -1,75 +0,0 @@
-package com.tangem.devkit._main
-
-import android.content.res.Resources
-import android.os.Bundle
-import android.view.Menu
-import android.view.MenuItem
-import androidx.activity.viewModels
-import androidx.appcompat.app.AppCompatActivity
-import androidx.appcompat.widget.Toolbar
-import androidx.navigation.findNavController
-import androidx.navigation.fragment.NavHostFragment
-import androidx.navigation.ui.AppBarConfiguration
-import androidx.navigation.ui.navigateUp
-import androidx.navigation.ui.setupWithNavController
-import com.tangem.devkit.R
-import ru.dev.gbixahue.eu4d.lib.android.global.log.Log
-
-/**
-[REDACTED_AUTHOR]
- */
-class MainActivity : AppCompatActivity() {
-
- private val mainVM: MainViewModel by viewModels()
- private lateinit var appBarConfiguration: AppBarConfiguration
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.a_main)
-
- val toolbar = findViewById(R.id.toolbar)
- setSupportActionBar(toolbar)
-
- val host: NavHostFragment = supportFragmentManager
- .findFragmentById(R.id.nav_host_fragment) as NavHostFragment? ?: return
-
- val navController = host.navController
- appBarConfiguration = AppBarConfiguration(navController.graph)
- toolbar.setupWithNavController(navController, appBarConfiguration)
-
- navController.addOnDestinationChangedListener { _, destination, _ ->
- val dest: String = try {
- resources.getResourceName(destination.id)
- } catch (e: Resources.NotFoundException) {
- destination.id.toString()
- }
- Log.d(this, "Navigated to $dest")
- }
- }
-
- override fun onSupportNavigateUp(): Boolean {
- return findNavController(R.id.nav_host_fragment).navigateUp(appBarConfiguration)
- }
-
- override fun onCreateOptionsMenu(menu: Menu): Boolean {
- menuInflater.inflate(R.menu.menu_activity_main, menu)
- return true
- }
-
- override fun onPrepareOptionsMenu(menu: Menu): Boolean {
- val switchItem = menu.findItem(R.id.action_toggle_description_visibility)
- switchItem.isChecked = mainVM.descriptionSwitchState
- return super.onPrepareOptionsMenu(menu)
- }
-
- override fun onOptionsItemSelected(item: MenuItem): Boolean {
- val result = when (item.itemId) {
- R.id.action_toggle_description_visibility -> {
- item.isChecked = !item.isChecked
- mainVM.switchToggled(item.isChecked)
- }
- else -> null
- }
- return if (result == null) super.onOptionsItemSelected(item) else true
- }
-}
\ No newline at end of file
diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/_main/MainViewModel.kt b/tangem-devkit/src/main/java/com/tangem/devkit/_main/MainViewModel.kt
deleted file mode 100644
index 6766c6d77f..0000000000
--- a/tangem-devkit/src/main/java/com/tangem/devkit/_main/MainViewModel.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.tangem.devkit._main
-
-import androidx.lifecycle.MutableLiveData
-import androidx.lifecycle.ViewModel
-import com.tangem.commands.CommandResponse
-import ru.dev.gbixahue.eu4d.lib.android.global.log.Log
-
-/**
-[REDACTED_AUTHOR]
- */
-class MainViewModel : ViewModel() {
- val ldDescriptionSwitch = MutableLiveData(false)
- var descriptionSwitchState = false
-
- var commandResponse: CommandResponse? = null
-
- fun switchToggled(state: Boolean) {
- descriptionSwitchState = state
- ldDescriptionSwitch.postValue(state)
- }
-
- fun changeResponseEvent(commandResponse: CommandResponse?) {
- Log.d(this, "changeResponseEvent")
- val response = commandResponse ?: return
-
- this.commandResponse = response
- }
-}
\ No newline at end of file
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
deleted file mode 100644
index 2656204d6b..0000000000
--- a/tangem-devkit/src/main/java/com/tangem/devkit/_main/entryPoint/ActionListFragment.kt
+++ /dev/null
@@ -1,78 +0,0 @@
-package com.tangem.devkit._main.entryPoint
-
-import android.os.Bundle
-import android.view.View
-import androidx.fragment.app.activityViewModels
-import androidx.lifecycle.Observer
-import androidx.recyclerview.widget.DividerItemDecoration
-import androidx.recyclerview.widget.LinearLayoutManager
-import androidx.recyclerview.widget.RecyclerView
-import com.tangem.devkit.R
-import com.tangem.devkit._main.MainViewModel
-import com.tangem.devkit.extensions.view.beginDelayedTransition
-import com.tangem.devkit.ucase.getDefaultNavigationOptions
-import com.tangem.devkit.ucase.resources.ActionType
-import com.tangem.devkit.ucase.resources.MainResourceHolder
-import com.tangem.devkit.ucase.ui.BaseFragment
-import kotlinx.android.synthetic.main.fg_entry_point.*
-
-/**
-[REDACTED_AUTHOR]
- */
-class ActionListFragment : BaseFragment() {
-
- private lateinit var rvActions: RecyclerView
-
- private val mainActivityVM: MainViewModel by activityViewModels()
-
- override fun getLayoutId(): Int = R.layout.fg_entry_point
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
- initRecyclerView()
- }
-
- private fun initRecyclerView() {
- val layoutManager = LinearLayoutManager(activity)
- rvActions = rv_actions
- rvActions.layoutManager = layoutManager
- rvActions.addItemDecoration(DividerItemDecoration(activity, layoutManager.orientation))
-
- val vhDataWrapper = VhExDataWrapper(MainResourceHolder, false)
-
- rvActions.adapter = RvActionsAdapter(vhDataWrapper) { type, position, data ->
- navigateTo(data, options = getDefaultNavigationOptions())
- }
- mainActivityVM.ldDescriptionSwitch.observe(viewLifecycleOwner, Observer {
- vhDataWrapper.descriptionIsVisible = it
- rvActions.beginDelayedTransition()
- rvActions.adapter?.notifyDataSetChanged()
- })
- }
-
- override fun onResume() {
- super.onResume()
- val adapter: RvActionsAdapter = rvActions.adapter as? RvActionsAdapter ?: return
-
- adapter.setItemList(getNavigateOptions())
- adapter.notifyDataSetChanged()
- }
-
- private fun getNavigateOptions(): MutableList {
- return mutableListOf(
- ActionType.Scan,
- ActionType.Sign,
- ActionType.Personalize,
- ActionType.Depersonalize,
- ActionType.CreateWallet,
- ActionType.PurgeWallet,
- ActionType.ReadIssuerData,
- ActionType.WriteIssuerData,
- ActionType.ReadIssuerExData,
- ActionType.WriteIssuerExData,
- ActionType.ReadUserData,
- ActionType.WriteUserData,
- ActionType.WriteProtectedUserData
- )
- }
-}
\ No newline at end of file
diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/_main/entryPoint/RvActions.kt b/tangem-devkit/src/main/java/com/tangem/devkit/_main/entryPoint/RvActions.kt
deleted file mode 100644
index 01162d2eee..0000000000
--- a/tangem-devkit/src/main/java/com/tangem/devkit/_main/entryPoint/RvActions.kt
+++ /dev/null
@@ -1,67 +0,0 @@
-package com.tangem.devkit._main.entryPoint
-
-import android.view.View
-import android.view.ViewGroup
-import android.widget.TextView
-import androidx.annotation.StringRes
-import androidx.recyclerview.widget.RecyclerView
-import com.tangem.devkit.R
-import com.tangem.devkit.ucase.resources.ActionRes
-import com.tangem.devkit.ucase.resources.ActionType
-import com.tangem.devkit.ucase.resources.MainResourceHolder
-import ru.dev.gbixahue.eu4d.lib.android._android.views.inflate
-import ru.dev.gbixahue.eu4d.lib.android._android.views.recycler_view.RvBaseAdapter
-import ru.dev.gbixahue.eu4d.lib.android._android.views.recycler_view.RvBaseVH
-import ru.dev.gbixahue.eu4d.lib.android._android.views.recycler_view.RvCallback
-
-/**
-[REDACTED_AUTHOR]
- */
-class RvActionsAdapter(
- private val wrapper: VhExDataWrapper,
- private val callback: RvCallback
-) : RvBaseAdapter() {
-
- override fun onBindViewHolder(holder: RvActionsVH, position: Int) {
- holder.bindData(itemList[position])
- }
-
- override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RvActionsVH {
- val view = parent.inflate(R.layout.vh_actions, false)
- return RvActionsVH(view, wrapper, callback)
- }
-
-}
-
-class VhExDataWrapper(
- val resHolder: MainResourceHolder,
- var descriptionIsVisible: Boolean
-)
-
-class RvActionsVH(
- itemView: View,
- private val wrapper: VhExDataWrapper,
- private val callback: RvCallback?
-) : RvBaseVH(itemView) {
-
- private val tvAction = itemView.findViewById(R.id.tv_title)
- private val containerDescription = itemView.findViewById(R.id.container_description)
- private val tvDescription = itemView.findViewById(R.id.tv_description)
-
- override fun bindData(data: ActionType) {
- val res: ActionRes = wrapper.resHolder.safeGet(data)
- tvAction.text = getString(res.resName)
- tvDescription.text = getString(res.resDescription)
-
- itemView.setOnClickListener {
- res.resNavigation?.let { callback?.invoke(itemViewType, adapterPosition, it) }
- }
-
- containerDescription.visibility = if (wrapper.descriptionIsVisible) View.VISIBLE else View.GONE
- }
-}
-
-fun RecyclerView.ViewHolder.getString(@StringRes id: Int?, ifNull: String = ""): String {
- val reqId = id ?: return ifNull
- return itemView.context.getString(reqId)
-}
\ No newline at end of file
diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/commons/Abstractions.kt b/tangem-devkit/src/main/java/com/tangem/devkit/commons/Abstractions.kt
deleted file mode 100644
index 3a1776e7c6..0000000000
--- a/tangem-devkit/src/main/java/com/tangem/devkit/commons/Abstractions.kt
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.tangem.devkit.commons
-
-/**
-[REDACTED_AUTHOR]
- */
-interface Store {
- fun save(value: M)
- fun restore(): M
-}
-
-interface KeyedStore {
- fun save(key: String, value: M)
- fun restore(key: String): M
- fun restoreAll(): MutableMap
- fun delete(key: String)
-}
\ No newline at end of file
diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/commons/DialogController.kt b/tangem-devkit/src/main/java/com/tangem/devkit/commons/DialogController.kt
deleted file mode 100644
index 5d4c924409..0000000000
--- a/tangem-devkit/src/main/java/com/tangem/devkit/commons/DialogController.kt
+++ /dev/null
@@ -1,76 +0,0 @@
-package com.tangem.devkit.commons
-
-import android.app.Activity
-import android.app.Dialog
-import android.view.LayoutInflater
-import android.view.View
-import androidx.appcompat.app.AlertDialog
-
-class DialogController {
- var onDismissCallback: (() -> Unit)? = null
- var onShowCallback: (() -> Unit)? = null
- var view: View? = null
-
- private var rawDialog: Dialog? = null
-
- private var inShowingProcess = false
- private var inDismissingProcess = false
- private var autoReleaseOnDismiss = false
-
- fun createAlert(context: Activity, resLayout: Int): AlertDialog {
- view = LayoutInflater.from(context).inflate(resLayout, null)
- rawDialog = AlertDialog.Builder(context).setView(view).create().apply {
- setOnShowListener { onShow() }
- setOnDismissListener { onDismiss() }
- }
- return rawDialog as AlertDialog
- }
-
- fun set(dialog: Dialog) {
- rawDialog = dialog
- dialog.setOnShowListener { onShow() }
- dialog.setOnDismissListener { onDismiss() }
- }
-
- private fun onShow() {
- inShowingProcess = false
- onShowCallback?.invoke()
- }
-
- private fun onDismiss() {
- inDismissingProcess = false
- if (autoReleaseOnDismiss) release()
- onDismissCallback?.invoke()
- }
-
- fun show() {
- val dialog = rawDialog ?: return
- if (inShowingProcess) return
- if (dialog.isShowing) return
-
- inShowingProcess = true
- dialog.show()
- }
-
- fun dismiss(autoRelease: Boolean = true) {
- val dialog = rawDialog ?: return
- if (inDismissingProcess) return
- if (!dialog.isShowing) return
-
- autoReleaseOnDismiss = autoRelease
- inDismissingProcess = true
- dialog.dismiss()
- }
-
- fun release() {
- onDismissCallback = null
- onShowCallback = null
-
- inShowingProcess = false
- inDismissingProcess = false
- autoReleaseOnDismiss = false
-
- view = null
- rawDialog = null
- }
-}
\ No newline at end of file
diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/commons/GlobalFunctions.kt b/tangem-devkit/src/main/java/com/tangem/devkit/commons/GlobalFunctions.kt
deleted file mode 100644
index 0f80ba2e83..0000000000
--- a/tangem-devkit/src/main/java/com/tangem/devkit/commons/GlobalFunctions.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-package com.tangem.devkit.commons
-
-/**
-[REDACTED_AUTHOR]
- */
-fun performAction(a: A?, b: B?, action: (A, B) -> Unit, onFail: (() -> Unit)? = null) {
- if (a != null && b != null) action(a, b)
- else onFail?.invoke()
-}
\ No newline at end of file
diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/commons/Logger.kt b/tangem-devkit/src/main/java/com/tangem/devkit/commons/Logger.kt
deleted file mode 100644
index 94e709455a..0000000000
--- a/tangem-devkit/src/main/java/com/tangem/devkit/commons/Logger.kt
+++ /dev/null
@@ -1,8 +0,0 @@
-package com.tangem.devkit.commons
-
-import ru.dev.gbixahue.eu4d.lib.android.global.log.TagLogger
-
-/**
-[REDACTED_AUTHOR]
- */
-class TangemLogger : TagLogger("TangemDemo")
\ No newline at end of file
diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/commons/view/MultiActionView.kt b/tangem-devkit/src/main/java/com/tangem/devkit/commons/view/MultiActionView.kt
deleted file mode 100644
index 4e134e0336..0000000000
--- a/tangem-devkit/src/main/java/com/tangem/devkit/commons/view/MultiActionView.kt
+++ /dev/null
@@ -1,85 +0,0 @@
-package com.tangem.devkit.commons.view
-
-import android.widget.TextView
-import androidx.annotation.StringRes
-import com.tangem.devkit._arch.structure.Id
-import com.tangem.devkit._arch.structure.StringId
-import com.tangem.devkit._arch.structure.abstraction.SafeValueChanged
-import ru.dev.gbixahue.eu4d.lib.android.global.log.Log
-import ru.dev.gbixahue.eu4d.lib.kotlin.stringOf
-
-/**
-[REDACTED_AUTHOR]
- */
-open class MultiActionView(
- stateActionList: MutableList,
- val child: V
-) {
-
- interface State {
- val id: Id
-
- fun getAction(): SimpleFunction
- fun getResNameId(): Int
- }
-
- var afterAction: SafeValueChanged? = null
-
- var state: Id = DefaultId.default
- set(value) {
- if (field == value) return
-
- field = value
- Log.d(this, "state changed to: ${getKey(value)}")
- btnState = stateHolder[getKey(value)]
- }
-
- init {
- child.setOnClickListener {
- val state = btnState ?: return@setOnClickListener
-
- Log.d(this, "child handled OnClick for: ${getKey(state.id)}")
- state.getAction().invoke()
- afterAction?.invoke(state.id)
- }
- }
-
- protected var btnState: State? = null
- set(value) {
- if (value == null) return
-
- field = value
- Log.d(this, "btnState changed to: ${getKey(value.id)}")
- child.setText(value.getResNameId())
- }
-
- protected val stateHolder: MutableMap = stateActionList.associateBy { getKey(it.id) }.toMutableMap()
-
- fun performAction(id: Id) {
- Log.d(this, "performAction ${getKey(id)}")
- state = id
- child.performClick()
- }
-
- protected open fun getKey(id: Id): String {
- return when (id) {
- is StringId -> id.value
- else -> stringOf(id)
- }
- }
-}
-
-enum class DefaultId : Id { default }
-
-typealias SimpleFunction = () -> Unit
-
-class ViewAction(
- override val id: Id,
- @StringRes val name: Int,
- private val action: SimpleFunction
-) : MultiActionView.State {
-
- override fun getAction(): SimpleFunction = action
-
- override fun getResNameId(): Int = name
-}
\ No newline at end of file
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
deleted file mode 100644
index d7ae706d37..0000000000
--- a/tangem-devkit/src/main/java/com/tangem/devkit/extensions/AndroidComponents.kt
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.tangem.devkit.extensions
-
-import android.content.ClipData
-import android.content.ClipboardManager
-import android.content.Context
-import android.content.Intent
-import androidx.fragment.app.Fragment
-
-/**
-[REDACTED_AUTHOR]
- */
-fun Context.copyToClipboard(value: Any, label: String = "") {
- val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as? ClipboardManager ?: return
-
- val clip: ClipData = ClipData.newPlainText(label, value.toString())
- clipboard.setPrimaryClip(clip)
-}
-
-fun Context.shareText(text: String) {
- val sendIntent: Intent = Intent().apply {
- action = Intent.ACTION_SEND
- putExtra(Intent.EXTRA_TEXT, text)
- type = "text/plain"
- }
- 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/extensions/List.kt b/tangem-devkit/src/main/java/com/tangem/devkit/extensions/List.kt
deleted file mode 100644
index f40be815b4..0000000000
--- a/tangem-devkit/src/main/java/com/tangem/devkit/extensions/List.kt
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.tangem.devkit.extensions
-
-/**
-[REDACTED_AUTHOR]
- */
-fun List.print(delimiter: String = ", ", wrap: Boolean = true): String {
- val builder = StringBuilder()
- forEach { builder.append(it).append(delimiter) }
- val length = builder.length
- if (length > delimiter.length) {
- builder.delete(length - delimiter.length, length)
- }
- val result = builder.toString()
-
- return if (wrap) "[$result]" else result
-}
\ No newline at end of file
diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/extensions/view/Transitions.kt b/tangem-devkit/src/main/java/com/tangem/devkit/extensions/view/Transitions.kt
deleted file mode 100644
index 1a6762eca0..0000000000
--- a/tangem-devkit/src/main/java/com/tangem/devkit/extensions/view/Transitions.kt
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.tangem.devkit.extensions.view
-
-import android.view.ViewGroup
-import androidx.transition.AutoTransition
-import androidx.transition.Transition
-import androidx.transition.TransitionManager
-
-/**
-[REDACTED_AUTHOR]
- */
-fun ViewGroup.beginDelayedTransition(transition: Transition = AutoTransition()) {
- TransitionManager.beginDelayedTransition(this, transition)
-}
\ No newline at end of file
diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/NavigationOp.kt b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/NavigationOp.kt
deleted file mode 100644
index c006bf6aa4..0000000000
--- a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/NavigationOp.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.tangem.devkit.ucase
-
-import androidx.navigation.NavOptions
-import androidx.navigation.navOptions
-import com.tangem.devkit.R
-
-/**
-[REDACTED_AUTHOR]
- */
-fun getDefaultNavigationOptions(): NavOptions {
- return navOptions {
- anim {
- enter = R.anim.slide_in_right
- exit = R.anim.slide_out_left
- popEnter = R.anim.slide_in_left
- popExit = R.anim.slide_out_right
- }
- }
-}
\ No newline at end of file
diff --git a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/domain/actions/Action.kt b/tangem-devkit/src/main/java/com/tangem/devkit/ucase/domain/actions/Action.kt
deleted file mode 100644
index f0c92ad43e..0000000000
--- a/tangem-devkit/src/main/java/com/tangem/devkit/ucase/domain/actions/Action.kt
+++ /dev/null
@@ -1,48 +0,0 @@
-package com.tangem.devkit.ucase.domain.actions
-
-import com.tangem.TangemSdk
-import com.tangem.common.CompletionResult
-import com.tangem.devkit._arch.structure.Id
-import com.tangem.devkit._arch.structure.Payload
-import com.tangem.devkit._arch.structure.PayloadHolder
-import com.tangem.devkit._arch.structure.abstraction.Item
-import com.tangem.devkit.ucase.domain.paramsManager.ActionCallback
-import com.tangem.devkit.ucase.domain.paramsManager.triggers.afterAction.AfterActionModification
-import com.tangem.devkit.ucase.domain.paramsManager.triggers.changeConsequence.ItemsChangeConsequence
-
-/**
-[REDACTED_AUTHOR]
- *
- * The Card Action class family is designed for calling Card Manager functions
- * and then processing the response. It also allows you to extract the main action as a lambda expression
- */
-data class AttrForAction(
- val tangemSdk: TangemSdk,
- val itemList: List