Updated on 2026-08-14

This commit is contained in:
Tangem 2020-04-29 20:21:43 +03:00
commit 6f91d23c2c
68 changed files with 1954 additions and 394 deletions

View file

@ -10,20 +10,20 @@ import org.bitcoinj.script.ScriptBuilder
import java.math.BigDecimal
import java.math.BigInteger
class BitcoinTransactionBuilder(
open class BitcoinTransactionBuilder(
private val walletPublicKey: ByteArray, private val testNet: Boolean = false
) {
private lateinit var transaction: Transaction
private var networkParameters: NetworkParameters? = null
var unspentOutputs: List<UnspentTransaction>? = null
protected var networkParameters: NetworkParameters? = null
var unspentOutputs: List<BitcoinUnspentOutput>? = null
fun buildToSign(
open fun buildToSign(
transactionData: TransactionData): Result<List<ByteArray>> {
if (unspentOutputs == null) return Result.Failure(Exception("Currently there's an unconfirmed transaction"))
val change: BigDecimal = calculateChange(transactionData)
val change: BigDecimal = calculateChange(transactionData, unspentOutputs!!)
networkParameters = if (testNet) {
NetworkParameters.fromID(NetworkParameters.ID_TESTNET)
@ -40,27 +40,13 @@ class BitcoinTransactionBuilder(
return Result.Success(hashesForSign)
}
private fun calculateChange(transactionData: TransactionData): BigDecimal {
val fullAmount = unspentOutputs!!.map { it.amount }.reduce { acc, number -> acc + number }
return fullAmount - (transactionData.amount.value!! + (transactionData.fee?.value
?: 0.toBigDecimal()))
}
fun buildToSend(signedTransaction: ByteArray): ByteArray {
open fun buildToSend(signedTransaction: ByteArray): ByteArray {
for (index in transaction.inputs.indices) {
transaction.inputs[index].scriptSig = createScript(index, signedTransaction, walletPublicKey)
}
return transaction.bitcoinSerialize()
}
private fun createScript(index: Int, signedTransaction: ByteArray, publicKey: ByteArray): Script {
val r = BigInteger(1, signedTransaction.copyOfRange(index * 64, 32 + index * 64))
val s = BigInteger(1, signedTransaction.copyOfRange(32 + index * 64, 64 + index * 64))
val canonicalS = ECKey.ECDSASignature(r, s).toCanonicalised().s
val signature = TransactionSignature(r, canonicalS)
return ScriptBuilder.createInputScript(signature, ECKey.fromPublicOnly(publicKey))
}
fun getEstimateSize(transactionData: TransactionData): Result<Int> {
val buildTransactionResult = buildToSign(transactionData)
when (buildTransactionResult) {
@ -72,14 +58,28 @@ class BitcoinTransactionBuilder(
}
}
}
fun calculateChange(transactionData: TransactionData, unspentOutputs: List<BitcoinUnspentOutput>): BigDecimal {
val fullAmount = unspentOutputs!!.map { it.amount }.reduce { acc, number -> acc + number }
return fullAmount - (transactionData.amount.value!! + (transactionData.fee?.value
?: 0.toBigDecimal()))
}
open fun createScript(index: Int, signedTransaction: ByteArray, publicKey: ByteArray): Script {
val r = BigInteger(1, signedTransaction.copyOfRange(index * 64, 32 + index * 64))
val s = BigInteger(1, signedTransaction.copyOfRange(32 + index * 64, 64 + index * 64))
val canonicalS = ECKey.ECDSASignature(r, s).toCanonicalised().s
val signature = TransactionSignature(r, canonicalS)
return ScriptBuilder.createInputScript(signature, ECKey.fromPublicOnly(publicKey))
}
}
internal fun TransactionData.toBitcoinJTransaction(networkParameters: NetworkParameters?,
unspentOutputs: List<UnspentTransaction>,
unspentOutputs: List<BitcoinUnspentOutput>,
change: BigDecimal): Transaction {
val transaction = Transaction(networkParameters)
for (utxo in unspentOutputs) {
transaction.addInput(Sha256Hash.wrap(utxo.hash), utxo.outputIndex, Script(utxo.outputScript))
transaction.addInput(Sha256Hash.wrap(utxo.transactionHash), utxo.outputIndex, Script(utxo.outputScript))
}
transaction.addOutput(
Coin.parseCoin(this.amount.value!!.toPlainString()),
@ -93,9 +93,9 @@ internal fun TransactionData.toBitcoinJTransaction(networkParameters: NetworkPar
return transaction
}
class UnspentTransaction(
class BitcoinUnspentOutput(
val amount: BigDecimal,
val outputIndex: Long,
val hash: ByteArray,
val transactionHash: ByteArray,
val outputScript: ByteArray
)

View file

@ -2,7 +2,7 @@ package com.tangem.blockchain.blockchains.bitcoin
import android.util.Log
import com.tangem.blockchain.blockchains.bitcoin.network.BitcoinAddressResponse
import com.tangem.blockchain.blockchains.bitcoin.network.BitcoinNetworkManager
import com.tangem.blockchain.blockchains.bitcoin.network.BitcoinProvider
import com.tangem.blockchain.common.*
import com.tangem.blockchain.extensions.Result
import com.tangem.blockchain.extensions.SimpleResult
@ -10,14 +10,14 @@ import com.tangem.common.CompletionResult
import com.tangem.common.extensions.toHexString
import java.math.BigDecimal
class BitcoinWalletManager(
open class BitcoinWalletManager(
cardId: String,
wallet: Wallet,
private val transactionBuilder: BitcoinTransactionBuilder,
private val networkManager: BitcoinNetworkManager
private val networkManager: BitcoinProvider
) : WalletManager(cardId, wallet), TransactionSender {
private val blockchain = wallet.blockchain
protected val blockchain = wallet.blockchain
override suspend fun update() {
val response = networkManager.getInfo(wallet.address)
@ -30,7 +30,7 @@ class BitcoinWalletManager(
private fun updateWallet(response: BitcoinAddressResponse) {
Log.d(this::class.java.simpleName, "Balance is ${response.balance}")
wallet.amounts[AmountType.Coin]?.value = response.balance
transactionBuilder.unspentOutputs = response.unspentTransactions
transactionBuilder.unspentOutputs = response.unspentOutputs
if (response.hasUnconfirmed) {
if (wallet.transactions.isEmpty()) wallet.addIncomingTransaction()
} else {
@ -44,8 +44,7 @@ class BitcoinWalletManager(
}
override suspend fun send(transactionData: TransactionData, signer: TransactionSigner): SimpleResult {
val buildTransactionResult = transactionBuilder.buildToSign(transactionData)
when (buildTransactionResult) {
when (val buildTransactionResult = transactionBuilder.buildToSign(transactionData)) {
is Result.Failure -> return SimpleResult.Failure(buildTransactionResult.error)
is Result.Success -> {
when (val signerResponse = signer.sign(buildTransactionResult.data.toTypedArray(), cardId)) {
@ -60,8 +59,8 @@ class BitcoinWalletManager(
}
override suspend fun getFee(amount: Amount, destination: String): Result<List<Amount>> {
when (val result = networkManager.getFee()) {
is Result.Failure -> return result
when (val feeResult = networkManager.getFee()) {
is Result.Failure -> return feeResult
is Result.Success -> {
val feeValue = BigDecimal.ONE.movePointLeft(blockchain.decimals())
amount.value = amount.value!! - feeValue
@ -72,9 +71,9 @@ class BitcoinWalletManager(
is Result.Failure -> return sizeResult
is Result.Success -> {
val transactionSize = sizeResult.data.toBigDecimal()
val minFee = result.data.minimalPerKb.calculateFee(transactionSize)
val normalFee = result.data.normalPerKb.calculateFee(transactionSize)
val priorityFee = result.data.priorityPerKb.calculateFee(transactionSize)
val minFee = feeResult.data.minimalPerKb.calculateFee(transactionSize)
val normalFee = feeResult.data.normalPerKb.calculateFee(transactionSize)
val priorityFee = feeResult.data.priorityPerKb.calculateFee(transactionSize)
return Result.Success(
listOf(Amount(minFee, blockchain),
Amount(normalFee, blockchain),

View file

@ -1,6 +1,6 @@
package com.tangem.blockchain.blockchains.bitcoin.network
import com.tangem.blockchain.blockchains.bitcoin.UnspentTransaction
import com.tangem.blockchain.blockchains.bitcoin.BitcoinUnspentOutput
import com.tangem.blockchain.blockchains.bitcoin.network.api.BlockchainInfoApi
import com.tangem.blockchain.blockchains.bitcoin.network.api.BlockcypherApi
import com.tangem.blockchain.blockchains.bitcoin.network.api.EstimatefeeApi
@ -90,7 +90,7 @@ class BitcoinNetworkManager(private val isTestNet: Boolean = false) : BitcoinPro
data class BitcoinAddressResponse(
val balance: BigDecimal,
val hasUnconfirmed: Boolean,
val unspentTransactions: List<UnspentTransaction>?
val unspentOutputs: List<BitcoinUnspentOutput>?
)
data class BitcoinFee(

View file

@ -1,6 +1,6 @@
package com.tangem.blockchain.blockchains.bitcoin.network
import com.tangem.blockchain.blockchains.bitcoin.UnspentTransaction
import com.tangem.blockchain.blockchains.bitcoin.BitcoinUnspentOutput
import com.tangem.blockchain.blockchains.bitcoin.network.api.BlockchainInfoApi
import com.tangem.blockchain.blockchains.bitcoin.network.api.EstimatefeeApi
import com.tangem.blockchain.common.Blockchain
@ -29,7 +29,7 @@ class BlockchainInfoProvider(
val unconfirmedTransactions = addressData.transactions?.find { it.blockHeight == 0L } != null
val bitcoinUnspents = unspents.unspentOutputs.map {
UnspentTransaction(
BitcoinUnspentOutput(
it.amount!!.toBigDecimal().movePointLeft(decimals),
it.outputIndex!!.toLong(),
it.hash!!.hexToBytes(),

View file

@ -1,6 +1,6 @@
package com.tangem.blockchain.blockchains.bitcoin.network
import com.tangem.blockchain.blockchains.bitcoin.UnspentTransaction
import com.tangem.blockchain.blockchains.bitcoin.BitcoinUnspentOutput
import com.tangem.blockchain.blockchains.bitcoin.network.api.BlockcypherApi
import com.tangem.blockchain.blockchains.bitcoin.network.api.BlockcypherBody
import com.tangem.blockchain.blockchains.bitcoin.network.response.BlockcypherFee
@ -26,7 +26,7 @@ class BlockcypherProvider(private val api: BlockcypherApi, isTestNet: Boolean) :
try {
val addressData: BlockcypherResponse = retryIO { api.getAddressData(blockchain, network, address) }
val unspents = addressData.txrefs?.map {
UnspentTransaction(
BitcoinUnspentOutput(
it.amount!!.toBigDecimal().movePointLeft(decimals),
it.outputIndex!!.toLong(),
it.hash!!.hexToBytes(),

View file

@ -0,0 +1,23 @@
package com.tangem.blockchain.blockchains.bitcoincash
import com.tangem.blockchain.blockchains.bitcoincash.cashaddr.BitcoinCashAddressType
import com.tangem.blockchain.blockchains.bitcoincash.cashaddr.CashAddr
import com.tangem.blockchain.common.AddressService
import com.tangem.common.extensions.calculateRipemd160
import com.tangem.common.extensions.calculateSha256
import com.tangem.common.extensions.toCompressedPublicKey
class BitcoinCashAddressService() : AddressService {
override fun makeAddress(walletPublicKey: ByteArray): String {
val publicKeyHash = walletPublicKey.toCompressedPublicKey().calculateSha256().calculateRipemd160()
return CashAddr.toCashAddress(BitcoinCashAddressType.P2PKH, publicKeyHash)
}
override fun validate(address: String): Boolean {
return CashAddr.isValidCashAddress(address)
}
fun getPublicKeyHash(address: String): ByteArray {
return CashAddr.decodeCashAddress(address).hash
}
}

View file

@ -0,0 +1,33 @@
package com.tangem.blockchain.blockchains.bitcoincash
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.network.API_BLOCKCHAIR
import com.tangem.blockchain.network.blockchair.BlockchairApi
import com.tangem.blockchain.network.blockchair.BlockchairProvider
import com.tangem.blockchain.network.createRetrofitInstance
class BitcoinCashNetworkManager : BitcoinProvider {
private val blockchain: Blockchain = Blockchain.BitcoinCash
private val blockchairProvider by lazy {
val api = createRetrofitInstance(API_BLOCKCHAIR).create(BlockchairApi::class.java)
BlockchairProvider(api, blockchain)
}
override suspend fun getInfo(address: String): Result<BitcoinAddressResponse> {
return blockchairProvider.getInfo(address)
}
override suspend fun getFee(): Result<BitcoinFee> {
return blockchairProvider.getFee()
}
override suspend fun sendTransaction(transaction: String): SimpleResult {
return blockchairProvider.sendTransaction(transaction)
}
}

View file

@ -0,0 +1,110 @@
package com.tangem.blockchain.blockchains.bitcoincash;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.core.Sha256Hash;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.TransactionInput;
import org.bitcoinj.core.TransactionOutput;
import org.bitcoinj.core.UnsafeByteArrayOutputStream;
import org.bitcoinj.core.VarInt;
import org.bitcoinj.crypto.TransactionSignature;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.util.List;
import static org.bitcoinj.core.Utils.uint32ToByteStreamLE;
import static org.bitcoinj.core.Utils.uint64ToByteStreamLE;
// logic from https://github.com/pokkst/bitcoincashj
public class BitcoinCashTransaction extends Transaction {
// private ArrayList<TransactionInput> inputs;
// private ArrayList<TransactionOutput> outputs;
// private long version;
// private long lockTime;
public final byte SIGHASH_FORK_ID = 0x40;
public BitcoinCashTransaction(NetworkParameters params) {
super(params);
}
public synchronized Sha256Hash hashForSignatureWitness(
int inputIndex,
byte[] connectedScript,
Coin prevValue,
SigHash type,
boolean anyoneCanPay)
{
byte sigHashType = (byte) TransactionSignature.calcSigHashValue(type, anyoneCanPay);
sigHashType |= SIGHASH_FORK_ID;
ByteArrayOutputStream bos = new UnsafeByteArrayOutputStream(length == UNKNOWN_LENGTH ? 256 : length + 4);
try {
byte[] hashPrevouts = new byte[32];
byte[] hashSequence = new byte[32];
byte[] hashOutputs = new byte[32];
anyoneCanPay = (sigHashType & SIGHASH_ANYONECANPAY_VALUE) == SIGHASH_ANYONECANPAY_VALUE;
List<TransactionInput> inputs = getInputs();
List<TransactionOutput> outputs = getOutputs();
if (!anyoneCanPay) {
ByteArrayOutputStream bosHashPrevouts = new UnsafeByteArrayOutputStream(256);
for (int i = 0; i < inputs.size(); ++i) {
bosHashPrevouts.write(inputs.get(i).getOutpoint().getHash().getReversedBytes());
uint32ToByteStreamLE(inputs.get(i).getOutpoint().getIndex(), bosHashPrevouts);
}
hashPrevouts = Sha256Hash.hashTwice(bosHashPrevouts.toByteArray());
}
if (!anyoneCanPay && type != SigHash.SINGLE && type != SigHash.NONE) {
ByteArrayOutputStream bosSequence = new UnsafeByteArrayOutputStream(256);
for (int i = 0; i < inputs.size(); ++i) {
uint32ToByteStreamLE(inputs.get(i).getSequenceNumber(), bosSequence);
}
hashSequence = Sha256Hash.hashTwice(bosSequence.toByteArray());
}
if (type != SigHash.SINGLE && type != SigHash.NONE) {
ByteArrayOutputStream bosHashOutputs = new UnsafeByteArrayOutputStream(256);
for (int i = 0; i < outputs.size(); ++i) {
uint64ToByteStreamLE(
BigInteger.valueOf(outputs.get(i).getValue().getValue()),
bosHashOutputs
);
bosHashOutputs.write(new VarInt(outputs.get(i).getScriptBytes().length).encode());
bosHashOutputs.write(outputs.get(i).getScriptBytes());
}
hashOutputs = Sha256Hash.hashTwice(bosHashOutputs.toByteArray());
} else if (type == SigHash.SINGLE && inputIndex < outputs.size()) {
ByteArrayOutputStream bosHashOutputs = new UnsafeByteArrayOutputStream(256);
uint64ToByteStreamLE(
BigInteger.valueOf(outputs.get(inputIndex).getValue().getValue()),
bosHashOutputs
);
bosHashOutputs.write(new VarInt(outputs.get(inputIndex).getScriptBytes().length).encode());
bosHashOutputs.write(outputs.get(inputIndex).getScriptBytes());
hashOutputs = Sha256Hash.hashTwice(bosHashOutputs.toByteArray());
}
uint32ToByteStreamLE(getVersion(), bos);
bos.write(hashPrevouts);
bos.write(hashSequence);
bos.write(inputs.get(inputIndex).getOutpoint().getHash().getReversedBytes());
uint32ToByteStreamLE(inputs.get(inputIndex).getOutpoint().getIndex(), bos);
bos.write(new VarInt(connectedScript.length).encode());
bos.write(connectedScript);
uint64ToByteStreamLE(BigInteger.valueOf(prevValue.getValue()), bos);
uint32ToByteStreamLE(inputs.get(inputIndex).getSequenceNumber(), bos);
bos.write(hashOutputs);
uint32ToByteStreamLE(getLockTime(), bos);
uint32ToByteStreamLE(0x000000ff & sigHashType, bos);
} catch (IOException e) {
throw new RuntimeException(e); // Cannot happen.
}
return Sha256Hash.twiceOf(bos.toByteArray());
}
}

View file

@ -0,0 +1,82 @@
package com.tangem.blockchain.blockchains.bitcoincash
import com.tangem.blockchain.blockchains.bitcoin.BitcoinTransactionBuilder
import com.tangem.blockchain.blockchains.bitcoin.BitcoinUnspentOutput
import com.tangem.blockchain.common.TransactionData
import com.tangem.blockchain.extensions.Result
import com.tangem.common.extensions.isZero
import org.bitcoinj.core.*
import org.bitcoinj.core.LegacyAddress.fromPubKeyHash
import org.bitcoinj.crypto.TransactionSignature
import org.bitcoinj.script.Script
import org.bitcoinj.script.ScriptBuilder
import java.math.BigDecimal
import java.math.BigInteger
class BitcoinCashTransactionBuilder(private val walletPublicKey: ByteArray)
: BitcoinTransactionBuilder(walletPublicKey) {
private lateinit var transaction: BitcoinCashTransaction
override fun buildToSign(
transactionData: TransactionData): Result<List<ByteArray>> {
if (unspentOutputs == null) return Result.Failure(Exception("Currently there's an unconfirmed transaction"))
val change: BigDecimal = calculateChange(transactionData, unspentOutputs!!)
networkParameters = NetworkParameters.fromID(NetworkParameters.ID_MAINNET)
transaction = transactionData.toBitcoinCashTransaction(networkParameters, unspentOutputs!!, change)
val hashesForSign: MutableList<ByteArray> = MutableList(transaction.inputs.size) { byteArrayOf() }
for (input in transaction.inputs) {
val index = input.index
val value = Coin.parseCoin(unspentOutputs!![index].amount.toString())
hashesForSign[index] = transaction.hashForSignatureWitness(index, input.scriptBytes, value, Transaction.SigHash.ALL, false).bytes
}
return Result.Success(hashesForSign)
}
override fun buildToSend(signedTransaction: ByteArray): ByteArray {
for (index in transaction.inputs.indices) {
transaction.inputs[index].scriptSig = createScript(index, signedTransaction, walletPublicKey)
}
return transaction.bitcoinSerialize()
}
override fun createScript(index: Int, signedTransaction: ByteArray, publicKey: ByteArray): Script {
val r = BigInteger(1, signedTransaction.copyOfRange(index * 64, 32 + index * 64))
val s = BigInteger(1, signedTransaction.copyOfRange(32 + index * 64, 64 + index * 64))
val canonicalS = ECKey.ECDSASignature(r, s).toCanonicalised().s
val sigHash = 0x41
val signature = TransactionSignature(r, canonicalS, sigHash)
return ScriptBuilder.createInputScript(signature, ECKey.fromPublicOnly(publicKey))
}
}
internal fun TransactionData.toBitcoinCashTransaction(networkParameters: NetworkParameters?,
unspentOutputs: List<BitcoinUnspentOutput>,
change: BigDecimal): BitcoinCashTransaction {
val transaction = BitcoinCashTransaction(networkParameters)
for (utxo in unspentOutputs) {
transaction.addInput(Sha256Hash.wrap(utxo.transactionHash), utxo.outputIndex, Script(utxo.outputScript))
}
val addressService = BitcoinCashAddressService()
val sourceLegacyAddress =
fromPubKeyHash(networkParameters, addressService.getPublicKeyHash(this.sourceAddress))
val destinationLegacyAddress =
fromPubKeyHash(networkParameters, addressService.getPublicKeyHash(this.destinationAddress))
transaction.addOutput(
Coin.parseCoin(this.amount.value!!.toPlainString()),
destinationLegacyAddress
)
if (!change.isZero()) {
transaction.addOutput(
Coin.parseCoin(change.toPlainString()),
sourceLegacyAddress
)
}
return transaction
}

View file

@ -0,0 +1,28 @@
package com.tangem.blockchain.blockchains.bitcoincash
import com.tangem.blockchain.blockchains.bitcoin.BitcoinWalletManager
import com.tangem.blockchain.common.Amount
import com.tangem.blockchain.common.TransactionSender
import com.tangem.blockchain.common.Wallet
import com.tangem.blockchain.extensions.Result
import java.math.BigDecimal
class BitcoinCashWalletManager(
cardId: String,
wallet: Wallet,
private val transactionBuilder: BitcoinCashTransactionBuilder,
private val networkManager: BitcoinCashNetworkManager
) : BitcoinWalletManager(cardId, wallet, transactionBuilder, networkManager), TransactionSender {
override suspend fun getFee(amount: Amount, destination: String): Result<List<Amount>> {
val minimalFee = BigDecimal("0.00001")
when (val result = super.getFee(amount, destination)) {
is Result.Success -> {
for (fee in result.data) {
if (fee.value!! < minimalFee) fee.value = minimalFee
}
return result
}
is Result.Failure -> return result
}
}
}

View file

@ -0,0 +1,37 @@
package com.tangem.blockchain.blockchains.bitcoincash.cashaddr;
// Helper class for CashAddr
public class BitcoinCashAddressDecodedParts {
String prefix;
BitcoinCashAddressType addressType;
byte[] hash;
public String getPrefix() {
return prefix;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
public BitcoinCashAddressType getAddressType() {
return addressType;
}
public void setAddressType(BitcoinCashAddressType addressType) {
this.addressType = addressType;
}
public byte[] getHash() {
return hash;
}
public void setHash(byte[] hash) {
this.hash = hash;
}
}

View file

@ -0,0 +1,23 @@
package com.tangem.blockchain.blockchains.bitcoincash.cashaddr;
/**
* Copyright (c) 2018 Tobias Brandt
*
* Distributed under the MIT software license, see the accompanying file LICENSE
* or http://www.opensource.org/licenses/mit-license.php.
*/
public enum BitcoinCashAddressType {
P2PKH((byte) 0), P2SH((byte) 8);
private final byte versionByte;
BitcoinCashAddressType(byte versionByte) {
this.versionByte = versionByte;
}
public byte getVersionByte() {
return versionByte;
}
}

View file

@ -0,0 +1,74 @@
package com.tangem.blockchain.blockchains.bitcoincash.cashaddr;
import java.util.HashMap;
import java.util.Map;
/**
* Copyright (c) 2018 Tobias Brandt
*
* Distributed under the MIT software license, see the accompanying file LICENSE
* or http://www.opensource.org/licenses/mit-license.php.
*/
public class BitcoinCashBase32 {
public static final String CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
private static final char[] CHARS = CHARSET.toCharArray();
private static Map<Character, Integer> charPositionMap;
static {
charPositionMap = new HashMap<>();
for (int i = 0; i < CHARS.length; i++) {
charPositionMap.put(CHARS[i], i);
}
if (charPositionMap.size() != 32) {
throw new RuntimeException("The charset must contain 32 unique characters.");
}
}
/**
* Encode a byte array as base32 string. This method assumes that all bytes
* are only from 0-31
*
* @param byteArray
* @return
*/
public static String encode(byte[] byteArray) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < byteArray.length; i++) {
int val = (int) byteArray[i];
if (val < 0 || val > 31) {
throw new RuntimeException("This method assumes that all bytes are only from 0-31. Was: " + val);
}
sb.append(CHARS[val]);
}
return sb.toString();
}
/**
* Decode a base32 string back to the byte array representation
*
* @param base32String
* @return
*/
public static byte[] decode(String base32String) {
byte[] bytes = new byte[base32String.length()];
char[] charArray = base32String.toCharArray();
for (int i = 0; i < charArray.length; i++) {
Integer position = charPositionMap.get(charArray[i]);
if (position == null) {
throw new RuntimeException("There seems to be an invalid char: " + charArray[i]);
}
bytes[i] = (byte) ((int) position);
}
return bytes;
}
}

View file

@ -0,0 +1,60 @@
package com.tangem.blockchain.blockchains.bitcoincash.cashaddr;
/**
* Copyright (c) 2018 Tobias Brandt
*
* Copyright (c) 2017 Pieter Wuille
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
public class BitcoinCashBitArrayConverter {
public static byte[] convertBits(byte[] bytes8Bits, int from, int to, boolean strictMode) {
int length = (int) (strictMode ? Math.floor((double) bytes8Bits.length * from / to)
: Math.ceil((double) bytes8Bits.length * from / to));
int mask = ((1 << to) - 1) & 0xff;
byte[] result = new byte[length];
int index = 0;
int accumulator = 0;
int bits = 0;
for (int i = 0; i < bytes8Bits.length; i++) {
byte value = bytes8Bits[i];
accumulator = (((accumulator & 0xff) << from) | (value & 0xff));
bits += from;
while (bits >= to) {
bits -= to;
result[index] = (byte) ((accumulator >> bits) & mask);
++index;
}
}
if (!strictMode) {
if (bits > 0) {
result[index] = (byte) ((accumulator << (to - bits)) & mask);
++index;
}
} else {
if (!(bits < from && ((accumulator << (to - bits)) & mask) == 0)) {
throw new RuntimeException("Strict mode was used but input couldn't be converted without padding");
}
}
return result;
}
}

View file

@ -0,0 +1,225 @@
package com.tangem.blockchain.blockchains.bitcoincash.cashaddr;
import java.math.BigInteger;
import java.util.Arrays;
/**
* Copyright (c) 2018 Tobias Brandt
*
* Distributed under the MIT software license, see the accompanying file LICENSE
* or http://www.opensource.org/licenses/mit-license.php.
*/
public class CashAddr {
public static final String CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
private static final char[] CHARS = CHARSET.toCharArray();
public static final String SEPARATOR = ":";
public static final String MAIN_NET_PREFIX = "bitcoincash";
public static final String TEST_NET_PREFIX = "bchtest";
public static final String ASSUMED_DEFAULT_PREFIX = MAIN_NET_PREFIX;
private static final BigInteger[] POLYMOD_GENERATORS = new BigInteger[] { new BigInteger("98f2bc8e61", 16),
new BigInteger("79b76d99e2", 16), new BigInteger("f33e5fb3c4", 16), new BigInteger("ae2eabe2a8", 16),
new BigInteger("1e4f43e470", 16) };
private static final BigInteger POLYMOD_AND_CONSTANT = new BigInteger("07ffffffff", 16);
public static String toCashAddress(BitcoinCashAddressType addressType, byte[] hash) {
String prefixString = MAIN_NET_PREFIX;
byte[] prefixBytes = getPrefixBytes(prefixString);
byte[] payloadBytes = concatenateByteArrays(new byte[] { addressType.getVersionByte() }, hash);
payloadBytes = convertBits(payloadBytes, 8, 5, false);
byte[] allChecksumInput = concatenateByteArrays(
concatenateByteArrays(concatenateByteArrays(prefixBytes, new byte[] { 0 }), payloadBytes),
new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 });
byte[] checksumBytes = calculateChecksumBytesPolymod(allChecksumInput);
checksumBytes = convertBits(checksumBytes, 8, 5, true);
String cashAddress = BitcoinCashBase32.encode(concatenateByteArrays(payloadBytes, checksumBytes));
return prefixString + SEPARATOR + cashAddress;
}
public static BitcoinCashAddressDecodedParts decodeCashAddress(String bitcoinCashAddress) {
if (!isValidCashAddress(bitcoinCashAddress)) {
throw new RuntimeException("Address wasn't valid: " + bitcoinCashAddress);
}
BitcoinCashAddressDecodedParts decoded = new BitcoinCashAddressDecodedParts();
String[] addressParts = bitcoinCashAddress.split(SEPARATOR);
if (addressParts.length == 2) {
decoded.setPrefix(addressParts[0]);
} else {
decoded.setPrefix(MAIN_NET_PREFIX);
}
byte[] addressData = BitcoinCashBase32.decode(addressParts[addressParts.length - 1]);
addressData = Arrays.copyOfRange(addressData, 0, addressData.length - 8);
addressData = BitcoinCashBitArrayConverter.convertBits(addressData, 5, 8, true);
byte versionByte = addressData[0];
byte[] hash = Arrays.copyOfRange(addressData, 1, addressData.length);
decoded.setAddressType(getAddressTypeFromVersionByte(versionByte));
decoded.setHash(hash);
return decoded;
}
private static BitcoinCashAddressType getAddressTypeFromVersionByte(byte versionByte) {
for (BitcoinCashAddressType addressType : BitcoinCashAddressType.values()) {
if (addressType.getVersionByte() == versionByte) {
return addressType;
}
}
throw new RuntimeException("Unknown version byte: " + versionByte);
}
public static boolean isValidCashAddress(String bitcoinCashAddress ) {
try {
if (!isSingleCase(bitcoinCashAddress))
return false;
bitcoinCashAddress = bitcoinCashAddress.toLowerCase();
String prefix;
if (bitcoinCashAddress.contains(SEPARATOR)) {
String[] split = bitcoinCashAddress.split(SEPARATOR);
prefix = split[0];
if (!prefix.equals(MAIN_NET_PREFIX)) {return false;} //for now we use main net only
bitcoinCashAddress = split[1];
} else {
prefix = MAIN_NET_PREFIX;
}
if (!bitcoinCashAddress.startsWith("q")) {return false;} //for now we use P2PKH addresses only
byte[] checksumData = concatenateByteArrays(
concatenateByteArrays(getPrefixBytes(prefix ), new byte[] { 0x00 }),
BitcoinCashBase32.decode(bitcoinCashAddress));
byte[] calculateChecksumBytesPolymod = calculateChecksumBytesPolymod(checksumData);
return new BigInteger(calculateChecksumBytesPolymod).compareTo(BigInteger.ZERO) == 0;
} catch (RuntimeException re) {
return false;
}
}
private static boolean isSingleCase(String bitcoinCashAddress) {
if (bitcoinCashAddress.equals(bitcoinCashAddress.toLowerCase())) {
return true;
}
if (bitcoinCashAddress.equals(bitcoinCashAddress.toUpperCase())) {
return true;
}
return false;
}
/**
* @param checksumInput
* @return Returns a 40 bits checksum in form of 5 8-bit arrays. This still has
* to me mapped to 5-bit array representation
*/
private static byte[] calculateChecksumBytesPolymod(byte[] checksumInput) {
BigInteger c = BigInteger.ONE;
for (int i = 0; i < checksumInput.length; i++) {
byte c0 = c.shiftRight(35).byteValue();
c = c.and(POLYMOD_AND_CONSTANT).shiftLeft(5)
.xor(new BigInteger(String.format("%02x", checksumInput[i]), 16));
if ((c0 & 0x01) != 0)
c = c.xor(POLYMOD_GENERATORS[0]);
if ((c0 & 0x02) != 0)
c = c.xor(POLYMOD_GENERATORS[1]);
if ((c0 & 0x04) != 0)
c = c.xor(POLYMOD_GENERATORS[2]);
if ((c0 & 0x08) != 0)
c = c.xor(POLYMOD_GENERATORS[3]);
if ((c0 & 0x10) != 0)
c = c.xor(POLYMOD_GENERATORS[4]);
}
byte[] checksum = c.xor(BigInteger.ONE).toByteArray();
if (checksum.length == 5) {
return checksum;
} else {
byte[] newChecksumArray = new byte[5];
System.arraycopy(checksum, Math.max(0, checksum.length - 5), newChecksumArray,
Math.max(0, 5 - checksum.length), Math.min(5, checksum.length));
return newChecksumArray;
}
}
private static byte[] getPrefixBytes(String prefixString ) {
byte[] prefixBytes = new byte[prefixString.length()];
char[] charArray = prefixString.toCharArray();
for (int i = 0; i < charArray.length; i++) {
prefixBytes[i] = (byte) (charArray[i] & 0x1f);
}
return prefixBytes;
}
private static byte[] concatenateByteArrays(byte[] first, byte[] second) {
byte[] concatenatedBytes = new byte[first.length + second.length];
System.arraycopy(first, 0, concatenatedBytes, 0, first.length);
System.arraycopy(second, 0, concatenatedBytes, first.length, second.length);
return concatenatedBytes;
}
private static byte[] convertBits(byte[] bytes8Bits, int from, int to, boolean strictMode) {
//Copyright (c) 2017 Pieter Wuille
int length = (int) (strictMode ? Math.floor((double) bytes8Bits.length * from / to)
: Math.ceil((double) bytes8Bits.length * from / to));
int mask = ((1 << to) - 1) & 0xff;
byte[] result = new byte[length];
int index = 0;
int accumulator = 0;
int bits = 0;
for (int i = 0; i < bytes8Bits.length; i++) {
byte value = bytes8Bits[i];
accumulator = (((accumulator & 0xff) << from) | (value & 0xff));
bits += from;
while (bits >= to) {
bits -= to;
result[index] = (byte) ((accumulator >> bits) & mask);
++index;
}
}
if (!strictMode) {
if (bits > 0) {
result[index] = (byte) ((accumulator << (to - bits)) & mask);
++index;
}
} else {
if (!(bits < from && ((accumulator << (to - bits)) & mask) == 0)) {
throw new RuntimeException("Strict mode was used but input couldn't be converted without padding");
}
}
return result;
}
}

View file

@ -2,6 +2,7 @@ package com.tangem.blockchain.common
import com.tangem.blockchain.blockchains.binance.BinanceAddressService
import com.tangem.blockchain.blockchains.bitcoin.BitcoinAddressService
import com.tangem.blockchain.blockchains.bitcoincash.BitcoinCashAddressService
import com.tangem.blockchain.blockchains.cardano.CardanoAddressService
import com.tangem.blockchain.blockchains.ethereum.EthereumAddressService
import com.tangem.blockchain.blockchains.stellar.StellarAddressService
@ -17,6 +18,7 @@ enum class Blockchain(
Unknown("", "", ""),
Bitcoin("BTC", "BTC", "Bitcoin"),
BitcoinTestnet("BTC/test", "BTCt", "Bitcoin Testnet"),
BitcoinCash("BCH", "BCH", "Bitcoin Cash"),
Ethereum("ETH", "ETH", "Ethereum"),
Rootstock("", "", ""),
Cardano("CARDANO", "ADA", "Cardano"),
@ -32,7 +34,7 @@ enum class Blockchain(
}
fun decimals(): Int = when (this) {
Bitcoin, BitcoinTestnet, Binance, BinanceTestnet -> 8
Bitcoin, BitcoinTestnet, BitcoinCash, Binance, BinanceTestnet -> 8
Cardano, XRP -> 6
Ethereum, Rootstock -> 18
Stellar -> 7
@ -51,6 +53,7 @@ enum class Blockchain(
Unknown -> throw Exception("unsupported blockchain")
Bitcoin -> BitcoinAddressService()
BitcoinTestnet -> BitcoinAddressService(true)
BitcoinCash -> BitcoinCashAddressService()
Ethereum -> EthereumAddressService()
Rootstock -> throw Exception("unsupported blockchain")
Cardano -> CardanoAddressService()
@ -70,6 +73,8 @@ enum class Blockchain(
fun getExploreUrl(address: String, token: Token? = null): String = when (this) {
Binance -> "https://explorer.binance.org/address/$address"
Bitcoin -> "https://blockchain.info/address/$address"
BitcoinTestnet -> "https://live.blockcypher.com/btc-testnet/address/$address"
BitcoinCash -> "https://blockchair.com/bitcoin-cash/address/$address"
Cardano -> "https://cardanoexplorer.com/address/$address"
Ethereum -> if (token == null) {
"https://etherscan.io/address/"

View file

@ -6,6 +6,9 @@ import com.tangem.blockchain.blockchains.binance.network.BinanceNetworkManager
import com.tangem.blockchain.blockchains.bitcoin.BitcoinTransactionBuilder
import com.tangem.blockchain.blockchains.bitcoin.BitcoinWalletManager
import com.tangem.blockchain.blockchains.bitcoin.network.BitcoinNetworkManager
import com.tangem.blockchain.blockchains.bitcoincash.BitcoinCashNetworkManager
import com.tangem.blockchain.blockchains.bitcoincash.BitcoinCashTransactionBuilder
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
@ -21,6 +24,7 @@ import com.tangem.blockchain.blockchains.xrp.XrpTransactionBuilder
import com.tangem.blockchain.blockchains.xrp.XrpWalletManager
import com.tangem.blockchain.blockchains.xrp.network.XrpNetworkManager
import com.tangem.commands.Card
import com.tangem.common.extensions.toCompressedPublicKey
object WalletManagerFactory {
@ -50,6 +54,13 @@ object WalletManagerFactory {
BitcoinNetworkManager(true)
)
}
Blockchain.BitcoinCash -> {
return BitcoinCashWalletManager(
card.cardId, wallet,
BitcoinCashTransactionBuilder(walletPublicKey.toCompressedPublicKey()),
BitcoinCashNetworkManager()
)
}
Blockchain.Ethereum -> {
val chain = Chain.Mainnet
return EthereumWalletManager(

View file

@ -49,7 +49,8 @@ const val API_STELLAR = "https://horizon.stellar.org/"
const val API_STELLAR_RESERVE = "https://horizon.sui.li/"
const val API_STELLAR_TESTNET = "https://horizon-testnet.stellar.org/"
const val API_BLOCKCHAIN_INFO = "https://blockchain.info/"
const val API_ADALITE = "https://explorer3.adalite.io"
const val API_ADALITE_RESERVE = "https://nodes.southeastasia.cloudapp.azure.com"
const val API_RIPPLED = "https://s1.ripple.com:51234"
const val API_RIPPLED_RESERVE = "https://s2.ripple.com:51234"
const val API_ADALITE = "https://explorer3.adalite.io/"
const val API_ADALITE_RESERVE = "https://nodes.southeastasia.cloudapp.azure.com/"
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/"

View file

@ -0,0 +1,36 @@
package com.tangem.blockchain.network.blockchair
import com.squareup.moshi.JsonClass
import retrofit2.http.*
interface BlockchairApi {
@GET("{blockchain}/dashboards/address/{address}")
suspend fun getAddressData(
@Path("address") address: String,
@Path("blockchain") blockchain: String,
@Query("key") key: String
): BlockchairAddress
@GET("{blockchain}/dashboards/transaction/{transaction}")
suspend fun getTransaction(
@Path("transaction") transactionHash: String,
@Path("blockchain") blockchain: String,
@Query("key") key: String
): BlockchairTransaction
@GET("{blockchain}/stats")
suspend fun getBlockchainStats(
@Path("blockchain") blockchain: String,
@Query("key") key: String
): BlockchairStats
@POST("{blockchain}/push/transaction")
suspend fun sendTransaction(
@Body sendBody: BlockchairBody,
@Path("blockchain") blockchain: String,
@Query("key") key: String
)
}
@JsonClass(generateAdapter = true)
data class BlockchairBody(val data: String)

View file

@ -0,0 +1,96 @@
package com.tangem.blockchain.network.blockchair
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 java.math.BigDecimal
import java.math.RoundingMode
class BlockchairProvider(private val api: BlockchairApi, blockchain: Blockchain) : BitcoinProvider {
private val blockchainPath = when (blockchain) {
Blockchain.BitcoinCash -> "bitcoin-cash"
else -> throw Exception("${blockchain.fullName} blockchain is not supported by BlockchairProvider")
}
private val decimals = blockchain.decimals()
override suspend fun getInfo(address: String): Result<BitcoinAddressResponse> {
return try {
val blockchairAddress = retryIO { api.getAddressData(address, blockchainPath, API_KEY) }
val addressData = blockchairAddress.data!!.getValue(address)
val addressInfo = addressData.addressInfo!!
val script = addressInfo.script!!.hexToBytes()
val hasUnconfirmed = checkHasUnconfirmed(addressData)
val unspentTransactions = addressData.unspentOutputs!!.map {
BitcoinUnspentOutput(
amount = it.amount!!.toBigDecimal().movePointLeft(decimals),
outputIndex = it.index!!.toLong(),
transactionHash = it.transactionHash!!.hexToBytes(),
outputScript = script
)
}
Result.Success(BitcoinAddressResponse(
balance = addressInfo.balance!!.toBigDecimal().movePointLeft(decimals),
hasUnconfirmed = hasUnconfirmed,
unspentOutputs = unspentTransactions
))
} catch (error: Exception) {
Result.Failure(error)
}
}
private suspend fun checkHasUnconfirmed(addressData: BlockchairAddressData): Boolean {
for (utxo in addressData.unspentOutputs!!) { //check utxos first
if (utxo.block == -1) return true
}
return if (addressData.addressInfo!!.balance != 0L) { // if balance is not zero, unconfirmed tx should have unconfirmed utxo
false
} else {
if (addressData.transactions!!.isEmpty()) { // no transactions from this address ever
false
} else { // check last transaction in case it spent all funds
val lastTransactionHash = addressData.transactions[0]
val blockchairTransaction = retryIO {
api.getTransaction(lastTransactionHash, blockchainPath, API_KEY)
}
blockchairTransaction.data!!.getValue(lastTransactionHash).transaction!!.block == -1
}
}
}
override suspend fun getFee(): Result<BitcoinFee> {
return try {
val stats = retryIO { api.getBlockchainStats(blockchainPath, API_KEY) }
val feePerKb = (stats.data!!.feePerByte!! * 1024).toBigDecimal().movePointLeft(decimals)
Result.Success(BitcoinFee(
minimalPerKb = (feePerKb * BigDecimal.valueOf(0.8)).setScale(decimals, RoundingMode.DOWN),
normalPerKb = feePerKb.setScale(decimals, RoundingMode.DOWN),
priorityPerKb = (feePerKb * BigDecimal.valueOf(1.2)).setScale(decimals, RoundingMode.DOWN)
))
} catch (error: Exception) {
Result.Failure(error)
}
}
override suspend fun sendTransaction(transaction: String): SimpleResult {
return try {
retryIO { api.sendTransaction(BlockchairBody(transaction), blockchainPath, API_KEY) }
SimpleResult.Success
} catch (error: Exception) {
SimpleResult.Failure(error)
}
}
}
private const val API_KEY = "A___0Shpsu4KagE7oSabrw20DfXAqWlT"

View file

@ -0,0 +1,75 @@
package com.tangem.blockchain.network.blockchair
import com.google.gson.annotations.SerializedName
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class BlockchairAddress(
@Json(name = "data")
val data: Map<String, BlockchairAddressData>? = null
)
data class BlockchairAddressData(
@Json(name = "address")
val addressInfo: BlockchairAddressInfo? = null,
@Json(name = "utxo")
val unspentOutputs: List<BlockchairUnspentOutput>? = null,
@Json(name = "transactions")
val transactions: List<String>? = null
)
data class BlockchairAddressInfo(
@Json(name = "balance")
val balance: Long? = null,
@Json(name = "script_hex")
val script: String? = null,
@Json(name = "output_count")
val outputCount: Int? = null,
@Json(name = "unspent_output_count")
val unspentOutputCount: Int? = null
)
data class BlockchairUnspentOutput(
@Json(name = "block_id")
val block: Int? = null,
@Json(name = "transaction_hash")
val transactionHash: String? = null,
@Json(name = "index")
val index: Int? = null,
@Json(name = "value")
val amount: Long? = null
)
data class BlockchairTransaction(
@Json(name = "data")
val data: Map<String, BlockchairTransactionData>? = null
)
data class BlockchairTransactionData(
@Json(name = "transaction")
val transaction: BlockchairTransactionInfo? = null
)
data class BlockchairTransactionInfo(
@Json(name = "block_id")
val block: Int? = null
)
data class BlockchairStats(
@Json(name = "data")
val data: BlockchairStatsData? = null
)
data class BlockchairStatsData(
@Json(name = "suggested_transaction_fee_per_byte_sat")
val feePerByte: Int? = null
)

View file

@ -0,0 +1,27 @@
package com.tangem.blockchain.blockchains.bitcoincash
import com.google.common.truth.Truth
import com.tangem.common.extensions.hexToBytes
import com.tangem.common.extensions.toCompressedPublicKey
import org.junit.Test
class BitcoinCashAddressTest {
private val addressService = BitcoinCashAddressService()
@Test
fun makeAddressFromCorrectPublicKey() {
val walletPublicKey = "04BE37CD5251C8999EDBBFC759D800EB41E4DCB718289601EB15819404E1B2F2ED90FE50C2A481D06EC790D1EF6184974EB655ABAE4BE56A6D1C9E1A17B1EFDF02".hexToBytes()
val expected = "bitcoincash:qp7atyzvetwq8a0x02y2snvnns5jfwnzacf9vfa4x3"
Truth.assertThat(addressService.makeAddress(walletPublicKey.toCompressedPublicKey()))
.isEqualTo(expected)
}
@Test
fun validateCorrectAddress() {
val address = "bitcoincash:qp7atyzvetwq8a0x02y2snvnns5jfwnzacf9vfa4x3"
Truth.assertThat(addressService.validate(address))
.isTrue()
}
}

View file

@ -4,6 +4,7 @@ import com.google.common.truth.Truth
import com.tangem.SessionEnvironment
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.ethereum.EthereumWalletManager
import com.tangem.blockchain.blockchains.stellar.StellarWalletManager
@ -80,4 +81,15 @@ internal class WalletManagerFactoryTest {
Truth.assertThat(walletManager)
.isInstanceOf(BinanceWalletManager::class.java)
}
@Test
fun createBitcoinCashWalletManager() {
val data = "0108BB00000000000049200754414E47454D00020102800A322E3432642053444B00034104766A1586D164B436E5D420AED01FDAB41B2AE7EDF0C865D7AF1DA995D70AB297E5B94B761CFBB405084C21BC97C02B4A1EA9ED4F515576EAB4D83AD3A0DFAA8A0A04041E76310C618102FFFF8A0101820407E4041B830B54414E47454D2053444B00840342434886408058F0F628C2466B09ECEB13F2A8EFDD4558F5D2DBDA9BD0628EE8C8CC99A778FF0F1AECD35704B9F3518486EA5C1D20F9DFCBAA66184F4CCCD9282E2632882C3041045F16BD1D2EAFE463E62A335A09E6B2BBCBD04452526885CB679FC4D27AF1BD22F553C7DEEFB54FD3D4F361D14E6DC3F11B7D4EA183250A60720EBDF9E110CD26050A736563703235366B31000804000186A0070100604104BE37CD5251C8999EDBBFC759D800EB41E4DCB718289601EB15819404E1B2F2ED90FE50C2A481D06EC790D1EF6184974EB655ABAE4BE56A6D1C9E1A17B1EFDF0262040001869A6304000000060F01009000"
val responseApdu = ResponseApdu(data.hexToBytes())
val card = ReadCommand().deserialize(SessionEnvironment(), responseApdu)
val walletManager = WalletManagerFactory.makeWalletManager(card!!)
Truth.assertThat(walletManager)
.isInstanceOf(BitcoinCashWalletManager::class.java)
}
}

View file

@ -21,7 +21,7 @@ data class SessionEnvironment(
var encryptionMode: EncryptionMode = EncryptionMode.NONE,
var encryptionKey: ByteArray? = null,
val cvc: ByteArray? = null,
var cardFilter: CardFilter
var cardFilter: CardFilter = CardFilter()
) {
fun setPin1(pin1: String) {

View file

@ -44,7 +44,7 @@ class ReadIssuerExtraDataResponse(
val issuerDataSignature: ByteArray?,
/**
* An optional counter that protect issuer data against replay attack.
* 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].
*/

View file

@ -17,7 +17,7 @@ class WriteUserDataResponse(
) : CommandResponse
/**
* This command write some of User_Data, User_ProtectedData, User_Counter and User_ProtectedCounter fields.
* 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.

View file

@ -3,7 +3,15 @@ package com.tangem.devkit._arch.structure
/**
[REDACTED_AUTHOR]
*/
interface Id
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

View file

@ -7,6 +7,7 @@ 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
@ -37,6 +38,7 @@ abstract class BaseViewWidget(
init {
subscribeToViewStateChanges(item.viewModel.viewState)
initViewState(item.viewModel.viewState)
view.tag = Id.getTag(item.id)
}
protected open fun subscribeToViewStateChanges(viewState: ViewState) {

View file

@ -63,15 +63,15 @@ class ActionListFragment : BaseFragment() {
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.Depersonalize,
ActionType.CreateWallet,
ActionType.PurgeWallet,
ActionType.ReadIssuerData,
ActionType.WriteIssuerData,
ActionType.ReadIssuerExData,
ActionType.WriteIssuerExData,
ActionType.ReadUserData,
ActionType.WriteUserData
)
}
}

View file

@ -0,0 +1,23 @@
package com.tangem.devkit.ucase.domain.actions
import com.tangem.devkit._arch.structure.Id
import com.tangem.devkit._arch.structure.PayloadHolder
import com.tangem.devkit._arch.structure.abstraction.findItem
import com.tangem.devkit.ucase.domain.paramsManager.ActionCallback
import com.tangem.devkit.ucase.variants.TlvId
class CreateWalletAction : BaseAction() {
override fun executeMainAction(payload: PayloadHolder, attrs: AttrForAction, callback: ActionCallback) {
val item = attrs.itemList.findItem(TlvId.CardId) ?: return
val cardId = item.viewModel.data as? String ?: return
attrs.tangemSdk.createWallet(cardId) { handleResult(payload, it, null, attrs, callback) }
}
override fun getActionByTag(payload: PayloadHolder, id: Id, attrs: AttrForAction): ((ActionCallback) -> Unit)? {
return when (id) {
TlvId.CardId -> { callback -> ScanAction().executeMainAction(payload, attrs, callback) }
else -> null
}
}
}

View file

@ -9,7 +9,7 @@ import com.tangem.devkit.ucase.domain.paramsManager.ActionCallback
import com.tangem.devkit.ucase.domain.paramsManager.PayloadKey
import com.tangem.devkit.ucase.tunnel.ActionView
import com.tangem.devkit.ucase.tunnel.ItemError
import com.tangem.devkit.ucase.variants.personalize.CardNumber
import com.tangem.devkit.ucase.variants.personalize.CardNumberId
import com.tangem.devkit.ucase.variants.personalize.converter.PersonalizationConfigConverter
import com.tangem.devkit.ucase.variants.personalize.converter.PersonalizationConfigToCardConfig
import com.tangem.devkit.ucase.variants.personalize.dto.DefaultPersonalizationParams
@ -46,7 +46,7 @@ class PersonalizeAction : BaseAction() {
}
private fun checkSeries(itemList: List<Item>): Boolean {
val seriesItem = itemList.findItem(CardNumber.Series) as? EditTextItem ?: return false
val seriesItem = itemList.findItem(CardNumberId.Series) as? EditTextItem ?: return false
val data = seriesItem.getData() as? String ?: return false
seriesItem.setData(data.toUpperCase())
@ -54,8 +54,8 @@ class PersonalizeAction : BaseAction() {
}
private fun checkNumber(itemList: List<Item>): Boolean {
val seriesItem = itemList.findItem(CardNumber.Series) as? EditTextItem ?: return false
val numberItem = itemList.findItem(CardNumber.Number) as? NumberItem ?: return false
val seriesItem = itemList.findItem(CardNumberId.Series) as? EditTextItem ?: return false
val numberItem = itemList.findItem(CardNumberId.Number) as? NumberItem ?: return false
val seriesData = seriesItem.getData() as? String ?: return false
val numberData = stringOf(numberItem.getData() as? Number)

View file

@ -0,0 +1,23 @@
package com.tangem.devkit.ucase.domain.actions
import com.tangem.devkit._arch.structure.Id
import com.tangem.devkit._arch.structure.PayloadHolder
import com.tangem.devkit._arch.structure.abstraction.findItem
import com.tangem.devkit.ucase.domain.paramsManager.ActionCallback
import com.tangem.devkit.ucase.variants.TlvId
class PurgeWalletAction : BaseAction() {
override fun executeMainAction(payload: PayloadHolder, attrs: AttrForAction, callback: ActionCallback) {
val item = attrs.itemList.findItem(TlvId.CardId) ?: return
val cardId = item.viewModel.data as? String ?: return
attrs.tangemSdk.purgeWallet(cardId) { handleResult(payload, it, null, attrs, callback) }
}
override fun getActionByTag(payload: PayloadHolder, id: Id, attrs: AttrForAction): ((ActionCallback) -> Unit)? {
return when (id) {
TlvId.CardId -> { callback -> ScanAction().executeMainAction(payload, attrs, callback) }
else -> null
}
}
}

View file

@ -0,0 +1,23 @@
package com.tangem.devkit.ucase.domain.actions
import com.tangem.devkit._arch.structure.Id
import com.tangem.devkit._arch.structure.PayloadHolder
import com.tangem.devkit._arch.structure.abstraction.findItem
import com.tangem.devkit.ucase.domain.paramsManager.ActionCallback
import com.tangem.devkit.ucase.variants.TlvId
class ReadIssuerDataAction : BaseAction() {
override fun executeMainAction(payload: PayloadHolder, attrs: AttrForAction, callback: ActionCallback) {
val item = attrs.itemList.findItem(TlvId.CardId) ?: return
val cardId = item.viewModel.data as? String ?: return
attrs.tangemSdk.readIssuerData(cardId) { handleResult(payload, it, null, attrs, callback) }
}
override fun getActionByTag(payload: PayloadHolder, id: Id, attrs: AttrForAction): ((ActionCallback) -> Unit)? {
return when (id) {
TlvId.CardId -> { callback -> ScanAction().executeMainAction(payload, attrs, callback) }
else -> null
}
}
}

View file

@ -0,0 +1,23 @@
package com.tangem.devkit.ucase.domain.actions
import com.tangem.devkit._arch.structure.Id
import com.tangem.devkit._arch.structure.PayloadHolder
import com.tangem.devkit._arch.structure.abstraction.findItem
import com.tangem.devkit.ucase.domain.paramsManager.ActionCallback
import com.tangem.devkit.ucase.variants.TlvId
class ReadIssuerExtraDataAction : BaseAction() {
override fun executeMainAction(payload: PayloadHolder, attrs: AttrForAction, callback: ActionCallback) {
val item = attrs.itemList.findItem(TlvId.CardId) ?: return
val cardId = item.viewModel.data as? String ?: return
attrs.tangemSdk.readIssuerExtraData(cardId) { handleResult(payload, it, null, attrs, callback) }
}
override fun getActionByTag(payload: PayloadHolder, id: Id, attrs: AttrForAction): ((ActionCallback) -> Unit)? {
return when (id) {
TlvId.CardId -> { callback -> ScanAction().executeMainAction(payload, attrs, callback) }
else -> null
}
}
}

View file

@ -0,0 +1,23 @@
package com.tangem.devkit.ucase.domain.actions
import com.tangem.devkit._arch.structure.Id
import com.tangem.devkit._arch.structure.PayloadHolder
import com.tangem.devkit._arch.structure.abstraction.findItem
import com.tangem.devkit.ucase.domain.paramsManager.ActionCallback
import com.tangem.devkit.ucase.variants.TlvId
class ReadUserDataAction : BaseAction() {
override fun executeMainAction(payload: PayloadHolder, attrs: AttrForAction, callback: ActionCallback) {
val item = attrs.itemList.findItem(TlvId.CardId) ?: return
val cardId = item.viewModel.data as? String ?: return
attrs.tangemSdk.readUserData(cardId) { handleResult(payload, it, null, attrs, callback) }
}
override fun getActionByTag(payload: PayloadHolder, id: Id, attrs: AttrForAction): ((ActionCallback) -> Unit)? {
return when (id) {
TlvId.CardId -> { callback -> ScanAction().executeMainAction(payload, attrs, callback) }
else -> null
}
}
}

View file

@ -0,0 +1,37 @@
package com.tangem.devkit.ucase.domain.actions
import com.tangem.common.extensions.hexToBytes
import com.tangem.common.extensions.toByteArray
import com.tangem.crypto.sign
import com.tangem.devkit._arch.structure.Id
import com.tangem.devkit._arch.structure.PayloadHolder
import com.tangem.devkit._arch.structure.abstraction.findItem
import com.tangem.devkit.ucase.domain.paramsManager.ActionCallback
import com.tangem.devkit.ucase.variants.TlvId
import com.tangem.devkit.ucase.variants.personalize.dto.DefaultPersonalizationParams
import ru.dev.gbixahue.eu4d.lib.kotlin.stringOf
class WriteIssuerDataAction : BaseAction() {
override fun executeMainAction(payload: PayloadHolder, attrs: AttrForAction, callback: ActionCallback) {
val cardId = attrs.itemList.findItem(TlvId.CardId)?.viewModel?.data ?: return
val counter = (attrs.itemList.findItem(TlvId.Counter)?.viewModel?.data as? Int) ?: 1
val issuerDataItem = attrs.itemList.findItem(TlvId.IssuerData) ?: return
val issuerData = (issuerDataItem.getData() as? String)?.toByteArray() ?: return
val signedIssuerData = (
stringOf(cardId).hexToBytes() + issuerData + counter.toByteArray(4))
.sign(DefaultPersonalizationParams.issuer().dataKeyPair.privateKey)
attrs.tangemSdk.writeIssuerData(stringOf(cardId), issuerData, signedIssuerData, counter) {
handleResult(payload, it, null, attrs, callback)
}
}
override fun getActionByTag(payload: PayloadHolder, id: Id, attrs: AttrForAction): ((ActionCallback) -> Unit)? {
return when (id) {
TlvId.CardId -> { callback -> ScanAction().executeMainAction(payload, attrs, callback) }
else -> null
}
}
}

View file

@ -0,0 +1,45 @@
package com.tangem.devkit.ucase.domain.actions
import com.tangem.commands.WriteIssuerExtraDataCommand
import com.tangem.common.extensions.hexToBytes
import com.tangem.common.extensions.toByteArray
import com.tangem.crypto.CryptoUtils
import com.tangem.crypto.sign
import com.tangem.devkit._arch.structure.Id
import com.tangem.devkit._arch.structure.PayloadHolder
import com.tangem.devkit._arch.structure.abstraction.findItem
import com.tangem.devkit.ucase.domain.paramsManager.ActionCallback
import com.tangem.devkit.ucase.variants.TlvId
import com.tangem.devkit.ucase.variants.personalize.dto.DefaultPersonalizationParams
import ru.dev.gbixahue.eu4d.lib.kotlin.stringOf
class WriteIssuerExtraDataAction : BaseAction() {
override fun executeMainAction(payload: PayloadHolder, attrs: AttrForAction, callback: ActionCallback) {
val cardId = attrs.itemList.findItem(TlvId.CardId)?.viewModel?.data ?: return
val counter = (attrs.itemList.findItem(TlvId.Counter)?.viewModel?.data as? String)?.toInt() ?: 1
val issuerData = CryptoUtils.generateRandomBytes(WriteIssuerExtraDataCommand.SINGLE_WRITE_SIZE * 5)
val startingSignature = (
stringOf(cardId).hexToBytes() + counter.toByteArray(4) + issuerData.size.toByteArray(2))
.sign(DefaultPersonalizationParams.issuer().dataKeyPair.privateKey)
val finalizingSignature = (
stringOf(cardId).hexToBytes() + issuerData + counter.toByteArray(4))
.sign(DefaultPersonalizationParams.issuer().dataKeyPair.privateKey)
attrs.tangemSdk.writeIssuerExtraData(
stringOf(cardId), issuerData, startingSignature, finalizingSignature, counter
) {
handleResult(payload, it, null, attrs, callback)
}
}
override fun getActionByTag(payload: PayloadHolder, id: Id, attrs: AttrForAction): ((ActionCallback) -> Unit)? {
return when (id) {
TlvId.CardId -> { callback -> ScanAction().executeMainAction(payload, attrs, callback) }
else -> null
}
}
}

View file

@ -0,0 +1,31 @@
package com.tangem.devkit.ucase.domain.actions
import com.tangem.devkit._arch.structure.Id
import com.tangem.devkit._arch.structure.PayloadHolder
import com.tangem.devkit._arch.structure.abstraction.findItem
import com.tangem.devkit.ucase.domain.paramsManager.ActionCallback
import com.tangem.devkit.ucase.variants.TlvId
import ru.dev.gbixahue.eu4d.lib.kotlin.stringOf
class WriteUserDataAction : BaseAction() {
override fun executeMainAction(payload: PayloadHolder, attrs: AttrForAction, callback: ActionCallback) {
val userData = (attrs.itemList.findItem(TlvId.UserData)?.getData() as? String)?.toByteArray()
?: return
val protectedUserData = (attrs.itemList.findItem(TlvId.ProtectedUserData)?.getData() as? String)?.toByteArray()
?: return
val cardId = attrs.itemList.findItem(TlvId.CardId)?.viewModel?.data ?: return
val counter = (attrs.itemList.findItem(TlvId.Counter)?.viewModel?.data as? Int) ?: 1
attrs.tangemSdk.writeUserData(stringOf(cardId), userData, protectedUserData, counter, counter) {
handleResult(payload, it, null, attrs, callback)
}
}
override fun getActionByTag(payload: PayloadHolder, id: Id, attrs: AttrForAction): ((ActionCallback) -> Unit)? {
return when (id) {
TlvId.CardId -> { callback -> ScanAction().executeMainAction(payload, attrs, callback) }
TlvId.Counter -> { callback -> ReadUserDataAction().executeMainAction(payload, attrs, callback) }
else -> null
}
}
}

View file

@ -1,9 +1,7 @@
package com.tangem.devkit.ucase.domain.paramsManager.managers
import com.tangem.devkit._arch.structure.impl.EditTextItem
import com.tangem.devkit.ucase.domain.actions.DepersonalizeAction
import com.tangem.devkit.ucase.domain.actions.ScanAction
import com.tangem.devkit.ucase.domain.actions.SignAction
import com.tangem.devkit.ucase.domain.actions.*
import com.tangem.devkit.ucase.domain.paramsManager.triggers.changeConsequence.CardIdConsequence
import com.tangem.devkit.ucase.variants.TlvId
@ -29,4 +27,78 @@ class SignItemsManager : BaseItemsManager(SignAction()) {
EditTextItem(TlvId.TransactionOutHash, "Data used for hashing")
))
}
}
class CreateWalletItemsManager : BaseItemsManager(CreateWalletAction()) {
init {
setItemChangeConsequences(CardIdConsequence())
setItems(listOf(EditTextItem(TlvId.CardId, null)))
}
}
class PurgeWalletItemsManager : BaseItemsManager(PurgeWalletAction()) {
init {
setItemChangeConsequences(CardIdConsequence())
setItems(listOf(EditTextItem(TlvId.CardId, null)))
}
}
class ReadIssuerDataItemsManager : BaseItemsManager(ReadIssuerDataAction()) {
init {
setItemChangeConsequences(CardIdConsequence())
setItems(listOf(EditTextItem(TlvId.CardId, null)))
}
}
class WriteIssuerDataItemsManager : BaseItemsManager(WriteIssuerDataAction()) {
init {
setItemChangeConsequences(CardIdConsequence())
setItems(listOf(
EditTextItem(TlvId.CardId, null),
EditTextItem(TlvId.IssuerData, "Data to be written on a card as issuer data"),
EditTextItem(TlvId.Counter, "1")
))
}
}
class ReadIssuerExtraDataItemsManager : BaseItemsManager(ReadIssuerExtraDataAction()) {
init {
setItemChangeConsequences(CardIdConsequence())
setItems(listOf(EditTextItem(TlvId.CardId, null)))
}
}
class WriteIssuerExtraDataItemsManager : BaseItemsManager(WriteIssuerExtraDataAction()) {
init {
setItemChangeConsequences(CardIdConsequence())
setItems(listOf(
EditTextItem(TlvId.CardId, null),
EditTextItem(TlvId.Counter, "1")
))
}
}
class ReadUserDataItemsManager : BaseItemsManager(ReadUserDataAction()) {
init {
setItemChangeConsequences(CardIdConsequence())
setItems(listOf(EditTextItem(TlvId.CardId, null)))
}
}
class WriteUserDataItemsManager : BaseItemsManager(WriteUserDataAction()) {
init {
setItemChangeConsequences(CardIdConsequence())
setItems(listOf(
EditTextItem(TlvId.CardId, null),
EditTextItem(TlvId.Counter, "1"),
EditTextItem(TlvId.UserData, "User data to be written on a card"),
EditTextItem(TlvId.ProtectedUserData, "Protected user data to be written on a card")
))
}
}

View file

@ -40,89 +40,89 @@ class PersonalizationResources() {
}
private fun initCardNumber(holder: TypedHolder<Id, Resources>) {
holder.register(CardNumber.Series, Resources(R.string.pers_item_series, R.string.info_pers_item_series))
holder.register(CardNumber.Number, Resources(R.string.pers_item_number, R.string.info_pers_item_number))
holder.register(CardNumber.BatchId, Resources(R.string.pers_item_batch_id, R.string.info_pers_item_batch_id))
holder.register(CardNumberId.Series, Resources(R.string.pers_item_series, R.string.info_pers_item_series))
holder.register(CardNumberId.Number, Resources(R.string.pers_item_number, R.string.info_pers_item_number))
holder.register(CardNumberId.BatchId, Resources(R.string.pers_item_batch_id, R.string.info_pers_item_batch_id))
}
private fun initCommon(holder: TypedHolder<Id, Resources>) {
holder.register(Common.Curve, Resources(R.string.pers_item_curve, R.string.info_pers_item_curve))
holder.register(Common.Blockchain, Resources(R.string.pers_item_blockchain, R.string.info_pers_item_blockchain))
holder.register(Common.BlockchainCustom, Resources(R.string.pers_item_custom_blockchain, R.string.info_pers_item_custom_blockchain))
holder.register(Common.MaxSignatures, Resources(R.string.pers_item_max_signatures, R.string.info_pers_item_max_signatures))
holder.register(Common.CreateWallet, Resources(R.string.pers_item_create_wallet, R.string.info_pers_item_create_wallet))
holder.register(CommonId.Curve, Resources(R.string.pers_item_curve, R.string.info_pers_item_curve))
holder.register(CommonId.Blockchain, Resources(R.string.pers_item_blockchain, R.string.info_pers_item_blockchain))
holder.register(CommonId.BlockchainCustom, Resources(R.string.pers_item_custom_blockchain, R.string.info_pers_item_custom_blockchain))
holder.register(CommonId.MaxSignatures, Resources(R.string.pers_item_max_signatures, R.string.info_pers_item_max_signatures))
holder.register(CommonId.CreateWallet, Resources(R.string.pers_item_create_wallet, R.string.info_pers_item_create_wallet))
}
private fun initSigningMethod(holder: TypedHolder<Id, Resources>) {
holder.register(SigningMethod.SignTx, Resources(R.string.pers_item_sign_tx_hashes, R.string.info_pers_item_sign_tx_hashes))
holder.register(SigningMethod.SignTxRaw, Resources(R.string.pers_item_sign_raw_tx, R.string.info_pers_item_sign_raw_tx))
holder.register(SigningMethod.SignValidatedTx, Resources(R.string.pers_item_sign_validated_tx_hashes, R.string.info_pers_item_sign_validated_tx_hashes))
holder.register(SigningMethod.SignValidatedTxRaw, Resources(R.string.pers_item_sign_validated_raw_tx, R.string.info_pers_item_sign_validated_raw_tx))
holder.register(SigningMethod.SignValidatedTxIssuer, Resources(R.string.pers_item_sign_validated_tx_hashes_with_iss_data, R.string.info_pers_item_sign_validated_tx_hashes_with_iss_data))
holder.register(SigningMethod.SignValidatedTxRawIssuer, Resources(R.string.pers_item_sign_validated_raw_tx_with_iss_data, R.string.info_pers_item_sign_validated_raw_tx_with_iss_data))
holder.register(SigningMethod.SignExternal, Resources(R.string.pers_item_sign_hash_ex, R.string.info_pers_item_sign_hash_ex))
holder.register(SigningMethodId.SignTx, Resources(R.string.pers_item_sign_tx_hashes, R.string.info_pers_item_sign_tx_hashes))
holder.register(SigningMethodId.SignTxRaw, Resources(R.string.pers_item_sign_raw_tx, R.string.info_pers_item_sign_raw_tx))
holder.register(SigningMethodId.SignValidatedTx, Resources(R.string.pers_item_sign_validated_tx_hashes, R.string.info_pers_item_sign_validated_tx_hashes))
holder.register(SigningMethodId.SignValidatedTxRaw, Resources(R.string.pers_item_sign_validated_raw_tx, R.string.info_pers_item_sign_validated_raw_tx))
holder.register(SigningMethodId.SignValidatedTxIssuer, Resources(R.string.pers_item_sign_validated_tx_hashes_with_iss_data, R.string.info_pers_item_sign_validated_tx_hashes_with_iss_data))
holder.register(SigningMethodId.SignValidatedTxRawIssuer, Resources(R.string.pers_item_sign_validated_raw_tx_with_iss_data, R.string.info_pers_item_sign_validated_raw_tx_with_iss_data))
holder.register(SigningMethodId.SignExternal, Resources(R.string.pers_item_sign_hash_ex, R.string.info_pers_item_sign_hash_ex))
}
private fun initSignHashExProp(holder: TypedHolder<Id, Resources>) {
holder.register(SignHashExProp.PinLessFloorLimit, Resources(R.string.pers_item_pin_less_floor_limit, R.string.info_pers_item_pin_less_floor_limit))
holder.register(SignHashExProp.CryptoExKey, Resources(R.string.pers_item_cr_ex_key, R.string.info_pers_item_cr_ex_key))
holder.register(SignHashExProp.RequireTerminalCertSig, Resources(R.string.pers_item_require_terminal_cert_sig, R.string.info_pers_item_require_terminal_cert_sig))
holder.register(SignHashExProp.RequireTerminalTxSig, Resources(R.string.pers_item_require_terminal_tx_sig, R.string.info_pers_item_require_terminal_tx_sig))
holder.register(SignHashExProp.CheckPin3, Resources(R.string.pers_item_check_pin3_on_card, R.string.info_pers_item_check_pin3_on_card))
holder.register(SignHashExPropId.PinLessFloorLimit, Resources(R.string.pers_item_pin_less_floor_limit, R.string.info_pers_item_pin_less_floor_limit))
holder.register(SignHashExPropId.CryptoExKey, Resources(R.string.pers_item_cr_ex_key, R.string.info_pers_item_cr_ex_key))
holder.register(SignHashExPropId.RequireTerminalCertSig, Resources(R.string.pers_item_require_terminal_cert_sig, R.string.info_pers_item_require_terminal_cert_sig))
holder.register(SignHashExPropId.RequireTerminalTxSig, Resources(R.string.pers_item_require_terminal_tx_sig, R.string.info_pers_item_require_terminal_tx_sig))
holder.register(SignHashExPropId.CheckPin3, Resources(R.string.pers_item_check_pin3_on_card, R.string.info_pers_item_check_pin3_on_card))
}
private fun initToken(holder: TypedHolder<Id, Resources>) {
holder.register(Token.ItsToken, Resources(R.string.pers_item_its_token, R.string.info_pers_item_its_token))
holder.register(Token.Symbol, Resources(R.string.pers_item_symbol, R.string.info_pers_item_symbol))
holder.register(Token.ContractAddress, Resources(R.string.pers_item_contract_address, R.string.info_pers_item_contract_address))
holder.register(Token.Decimal, Resources(R.string.pers_item_decimal, R.string.info_pers_item_decimal))
holder.register(TokenId.ItsToken, Resources(R.string.pers_item_its_token, R.string.info_pers_item_its_token))
holder.register(TokenId.Symbol, Resources(R.string.pers_item_symbol, R.string.info_pers_item_symbol))
holder.register(TokenId.ContractAddress, Resources(R.string.pers_item_contract_address, R.string.info_pers_item_contract_address))
holder.register(TokenId.Decimal, Resources(R.string.pers_item_decimal, R.string.info_pers_item_decimal))
}
private fun initProductMask(holder: TypedHolder<Id, Resources>) {
holder.register(ProductMask.Note, Resources(R.string.pers_item_note, R.string.info_pers_item_note))
holder.register(ProductMask.Tag, Resources(R.string.pers_item_tag, R.string.info_pers_item_tag))
holder.register(ProductMask.IdCard, Resources(R.string.pers_item_id_card, R.string.info_pers_item_id_card))
holder.register(ProductMask.IdIssuerCard, Resources(R.string.pers_item_id_issuer_card, R.string.info_pers_item_id_issuer_card))
holder.register(ProductMaskId.Note, Resources(R.string.pers_item_note, R.string.info_pers_item_note))
holder.register(ProductMaskId.Tag, Resources(R.string.pers_item_tag, R.string.info_pers_item_tag))
holder.register(ProductMaskId.IdCard, Resources(R.string.pers_item_id_card, R.string.info_pers_item_id_card))
holder.register(ProductMaskId.IdIssuerCard, Resources(R.string.pers_item_id_issuer_card, R.string.info_pers_item_id_issuer_card))
}
private fun initSettingsMask(holder: TypedHolder<Id, Resources>) {
holder.register(SettingsMask.IsReusable, Resources(R.string.pers_item_is_reusable, R.string.info_pers_item_is_reusable))
holder.register(SettingsMask.NeedActivation, Resources(R.string.pers_item_need_activation, R.string.info_pers_item_need_activation))
holder.register(SettingsMask.ForbidPurge, Resources(R.string.pers_item_forbid_purge, R.string.info_pers_item_forbid_purge))
holder.register(SettingsMask.AllowSelectBlockchain, Resources(R.string.pers_item_allow_select_blockchain, R.string.info_pers_item_allow_select_blockchain))
holder.register(SettingsMask.UseBlock, Resources(R.string.pers_item_use_block, R.string.info_pers_item_use_block))
holder.register(SettingsMask.OneApdu, Resources(R.string.pers_item_one_apdu_at_once, R.string.info_pers_item_one_apdu_at_once))
holder.register(SettingsMask.UseCvc, Resources(R.string.pers_item_use_cvc, R.string.info_pers_item_use_cvc))
holder.register(SettingsMask.AllowSwapPin, Resources(R.string.pers_item_allow_swap_pin, R.string.info_pers_item_allow_swap_pin))
holder.register(SettingsMask.AllowSwapPin2, Resources(R.string.pers_item_allow_swap_pin2, R.string.info_pers_item_allow_swap_pin2))
holder.register(SettingsMask.ForbidDefaultPin, Resources(R.string.pers_item_forbid_default_pin, R.string.info_pers_item_forbid_default_pin))
holder.register(SettingsMask.SmartSecurityDelay, Resources(R.string.pers_item_smart_security_delay, R.string.info_pers_item_smart_security_delay))
holder.register(SettingsMask.ProtectIssuerDataAgainstReplay, Resources(R.string.pers_item_protect_issuer_data_against_replay, R.string.info_pers_item_protect_issuer_data_against_replay))
holder.register(SettingsMask.SkipSecurityDelayIfValidated, Resources(R.string.pers_item_skip_security_delay_if_validated, R.string.info_pers_item_skip_security_delay_if_validated))
holder.register(SettingsMask.SkipPin2CvcIfValidated, Resources(R.string.pers_item_skip_pin2_and_cvc_if_validated, R.string.info_pers_item_skip_pin2_and_cvc_if_validated))
holder.register(SettingsMask.SkipSecurityDelayOnLinkedTerminal, Resources(R.string.pers_item_skip_security_delay_on_linked_terminal, R.string.info_pers_item_skip_security_delay_on_linked_terminal))
holder.register(SettingsMask.RestrictOverwriteExtraIssuerData, Resources(R.string.pers_item_restrict_overwrite_ex_issuer_data, R.string.info_pers_item_restrict_overwrite_ex_issuer_data))
holder.register(SettingsMaskId.IsReusable, Resources(R.string.pers_item_is_reusable, R.string.info_pers_item_is_reusable))
holder.register(SettingsMaskId.NeedActivation, Resources(R.string.pers_item_need_activation, R.string.info_pers_item_need_activation))
holder.register(SettingsMaskId.ForbidPurge, Resources(R.string.pers_item_forbid_purge, R.string.info_pers_item_forbid_purge))
holder.register(SettingsMaskId.AllowSelectBlockchain, Resources(R.string.pers_item_allow_select_blockchain, R.string.info_pers_item_allow_select_blockchain))
holder.register(SettingsMaskId.UseBlock, Resources(R.string.pers_item_use_block, R.string.info_pers_item_use_block))
holder.register(SettingsMaskId.OneApdu, Resources(R.string.pers_item_one_apdu_at_once, R.string.info_pers_item_one_apdu_at_once))
holder.register(SettingsMaskId.UseCvc, Resources(R.string.pers_item_use_cvc, R.string.info_pers_item_use_cvc))
holder.register(SettingsMaskId.AllowSwapPin, Resources(R.string.pers_item_allow_swap_pin, R.string.info_pers_item_allow_swap_pin))
holder.register(SettingsMaskId.AllowSwapPin2, Resources(R.string.pers_item_allow_swap_pin2, R.string.info_pers_item_allow_swap_pin2))
holder.register(SettingsMaskId.ForbidDefaultPin, Resources(R.string.pers_item_forbid_default_pin, R.string.info_pers_item_forbid_default_pin))
holder.register(SettingsMaskId.SmartSecurityDelay, Resources(R.string.pers_item_smart_security_delay, R.string.info_pers_item_smart_security_delay))
holder.register(SettingsMaskId.ProtectIssuerDataAgainstReplay, Resources(R.string.pers_item_protect_issuer_data_against_replay, R.string.info_pers_item_protect_issuer_data_against_replay))
holder.register(SettingsMaskId.SkipSecurityDelayIfValidated, Resources(R.string.pers_item_skip_security_delay_if_validated, R.string.info_pers_item_skip_security_delay_if_validated))
holder.register(SettingsMaskId.SkipPin2CvcIfValidated, Resources(R.string.pers_item_skip_pin2_and_cvc_if_validated, R.string.info_pers_item_skip_pin2_and_cvc_if_validated))
holder.register(SettingsMaskId.SkipSecurityDelayOnLinkedTerminal, Resources(R.string.pers_item_skip_security_delay_on_linked_terminal, R.string.info_pers_item_skip_security_delay_on_linked_terminal))
holder.register(SettingsMaskId.RestrictOverwriteExtraIssuerData, Resources(R.string.pers_item_restrict_overwrite_ex_issuer_data, R.string.info_pers_item_restrict_overwrite_ex_issuer_data))
}
private fun initSettingsMaskProtocolEnc(holder: TypedHolder<Id, Resources>) {
holder.register(SettingsMaskProtocolEnc.AllowUnencrypted, Resources(R.string.pers_item_allow_unencrypted, R.string.info_pers_item_allow_unencrypted))
holder.register(SettingsMaskProtocolEnc.AllowStaticEncryption, Resources(R.string.pers_item_allow_fast_encryption, R.string.info_pers_item_allow_fast_encryption))
holder.register(SettingsMaskProtocolEncId.AllowUnencrypted, Resources(R.string.pers_item_allow_unencrypted, R.string.info_pers_item_allow_unencrypted))
holder.register(SettingsMaskProtocolEncId.AllowStaticEncryption, Resources(R.string.pers_item_allow_fast_encryption, R.string.info_pers_item_allow_fast_encryption))
}
private fun initSettingsMaskNdef(holder: TypedHolder<Id, Resources>) {
holder.register(SettingsMaskNdef.UseNdef, Resources(R.string.pers_item_use_ndef, R.string.info_pers_item_use_ndef))
holder.register(SettingsMaskNdef.DynamicNdef, Resources(R.string.pers_item_dynamic_ndef, R.string.info_pers_item_dynamic_ndef))
holder.register(SettingsMaskNdef.DisablePrecomputedNdef, Resources(R.string.pers_item_disable_precomputed_ndef, R.string.info_pers_item_disable_precomputed_ndef))
holder.register(SettingsMaskNdef.Aar, Resources(R.string.pers_item_aar, R.string.info_pers_item_aar))
holder.register(SettingsMaskNdef.AarCustom, Resources(R.string.pers_item_custom_aar_package_name, R.string.info_pers_item_custom_aar_package_name))
holder.register(SettingsMaskNdef.Uri, Resources(R.string.pers_item_uri, R.string.info_pers_item_uri))
holder.register(SettingsMaskNdefId.UseNdef, Resources(R.string.pers_item_use_ndef, R.string.info_pers_item_use_ndef))
holder.register(SettingsMaskNdefId.DynamicNdef, Resources(R.string.pers_item_dynamic_ndef, R.string.info_pers_item_dynamic_ndef))
holder.register(SettingsMaskNdefId.DisablePrecomputedNdef, Resources(R.string.pers_item_disable_precomputed_ndef, R.string.info_pers_item_disable_precomputed_ndef))
holder.register(SettingsMaskNdefId.Aar, Resources(R.string.pers_item_aar, R.string.info_pers_item_aar))
holder.register(SettingsMaskNdefId.AarCustom, Resources(R.string.pers_item_custom_aar_package_name, R.string.info_pers_item_custom_aar_package_name))
holder.register(SettingsMaskNdefId.Uri, Resources(R.string.pers_item_uri, R.string.info_pers_item_uri))
}
private fun initPins(holder: TypedHolder<Id, Resources>) {
holder.register(Pins.Pin, Resources(R.string.pers_item_pin, R.string.info_pers_item_pin))
holder.register(Pins.Pin2, Resources(R.string.pers_item_pin2, R.string.info_pers_item_pin2))
holder.register(Pins.Pin3, Resources(R.string.pers_item_pin3, R.string.info_pers_item_pin3))
holder.register(Pins.Cvc, Resources(R.string.pers_item_cvc, R.string.info_pers_item_cvc))
holder.register(Pins.PauseBeforePin2, Resources(R.string.pers_item_pause_before_pin2, R.string.info_pers_item_pause_before_pin2))
holder.register(PinsId.Pin, Resources(R.string.pers_item_pin, R.string.info_pers_item_pin))
holder.register(PinsId.Pin2, Resources(R.string.pers_item_pin2, R.string.info_pers_item_pin2))
holder.register(PinsId.Pin3, Resources(R.string.pers_item_pin3, R.string.info_pers_item_pin3))
holder.register(PinsId.Cvc, Resources(R.string.pers_item_cvc, R.string.info_pers_item_cvc))
holder.register(PinsId.PauseBeforePin2, Resources(R.string.pers_item_pause_before_pin2, R.string.info_pers_item_pause_before_pin2))
}
}

View file

@ -3,10 +3,7 @@ package com.tangem.devkit.ucase.resources.initializers
import com.tangem.devkit.R
import com.tangem.devkit.ucase.resources.MainResourceHolder
import com.tangem.devkit.ucase.resources.Resources
import com.tangem.devkit.ucase.variants.responses.CardDataId
import com.tangem.devkit.ucase.variants.responses.CardId
import com.tangem.devkit.ucase.variants.responses.DepersonalizeId
import com.tangem.devkit.ucase.variants.responses.SignId
import com.tangem.devkit.ucase.variants.responses.*
/**
[REDACTED_AUTHOR]
@ -17,6 +14,13 @@ class ResponseResources {
initCardData(holder)
initSignResponse(holder)
initDepersonalizeResponse(holder)
initCreateWalletResponse(holder)
initPurgeWalletResponse(holder)
initReadIssuerDataResponse(holder)
initWriteIssuerDataResponse(holder)
initReadIssuerExtraDataResponse(holder)
initReadUserDataResponse(holder)
initWriteUserDataResponse(holder)
}
private fun initCard(holder: MainResourceHolder) {
@ -65,4 +69,46 @@ class ResponseResources {
private fun initDepersonalizeResponse(holder: MainResourceHolder) {
holder.register(DepersonalizeId.isSuccess, Resources(R.string.response_depersonalize_is_success, R.string.info_response_depersonalize_is_success))
}
private fun initCreateWalletResponse(holder: MainResourceHolder) {
holder.register(CreateWalletId.cid, Resources(R.string.response_card_cid, R.string.info_response_card_cid))
holder.register(CreateWalletId.cardStatus, Resources(R.string.response_card_status, R.string.info_response_card_status))
holder.register(CreateWalletId.walletPublicKey, Resources(R.string.response_card_wallet_public_key, R.string.info_response_card_wallet_public_key))
}
private fun initPurgeWalletResponse(holder: MainResourceHolder) {
holder.register(PurgeWalletId.cid, Resources(R.string.response_card_cid, R.string.info_response_card_cid))
holder.register(PurgeWalletId.cardStatus, Resources(R.string.response_card_status, R.string.info_response_card_status))
}
private fun initReadIssuerDataResponse(holder: MainResourceHolder) {
holder.register(ReadIssuerDataId.cid, Resources(R.string.response_card_cid, R.string.info_response_card_cid))
holder.register(ReadIssuerDataId.issuerData, Resources(R.string.response_issuer_data, R.string.info_response_issuer_data))
holder.register(ReadIssuerDataId.issuerDataSignature, Resources(R.string.response_issuer_data_signature, R.string.info_response_issuer_data_signature))
holder.register(ReadIssuerDataId.issuerDataCounter, Resources(R.string.response_issuer_data_counter, R.string.info_response_issuer_data_counter))
}
private fun initWriteIssuerDataResponse(holder: MainResourceHolder) {
holder.register(ReadIssuerDataId.cid, Resources(R.string.response_card_cid, R.string.info_response_card_cid))
}
private fun initReadIssuerExtraDataResponse(holder: MainResourceHolder) {
holder.register(ReadIssuerExtraDataId.cid, Resources(R.string.response_card_cid, R.string.info_response_card_cid))
holder.register(ReadIssuerExtraDataId.size, Resources(R.string.response_issuer_data_size, R.string.info_response_issuer_data_size))
holder.register(ReadIssuerExtraDataId.issuerData, Resources(R.string.response_issuer_data, R.string.info_response_issuer_data))
holder.register(ReadIssuerExtraDataId.issuerDataSignature, Resources(R.string.response_issuer_data_signature, R.string.info_response_issuer_data_signature))
holder.register(ReadIssuerExtraDataId.issuerDataCounter, Resources(R.string.response_issuer_data_counter, R.string.info_response_issuer_data_counter))
}
private fun initReadUserDataResponse(holder: MainResourceHolder) {
holder.register(ReadUserDataId.cid, Resources(R.string.response_card_cid, R.string.info_response_card_cid))
holder.register(ReadUserDataId.userData, Resources(R.string.response_user_data, R.string.info_response_user_data))
holder.register(ReadUserDataId.userProtectedData, Resources(R.string.response_user_protected_data, R.string.info_response_user_protected_data))
holder.register(ReadUserDataId.userCounter, Resources(R.string.response_user_data_counter, R.string.info_response_user_data_counter))
holder.register(ReadUserDataId.userProtectedCounter, Resources(R.string.response_user_data_protected_counter, R.string.info_response_user_data_protected_counter))
}
private fun initWriteUserDataResponse(holder: MainResourceHolder) {
holder.register(ReadIssuerDataId.cid, Resources(R.string.response_card_cid, R.string.info_response_card_cid))
}
}

View file

@ -16,5 +16,9 @@ class TlvResources {
private fun initScan(holder: MainResourceHolder) {
holder.register(TlvId.CardId, Resources(R.string.tlv_card_id, R.string.info_tlv_card_id))
holder.register(TlvId.TransactionOutHash, Resources(R.string.tlv_transaction_out_hash, R.string.info_tlv_transaction_out_hash))
holder.register(TlvId.Counter, Resources(R.string.tlv_counter, R.string.info_tlv_counter))
holder.register(TlvId.IssuerData, Resources(R.string.tlv_issuer_data, R.string.info_tlv_issuer_data))
holder.register(TlvId.UserData, Resources(R.string.tlv_issuer_data, R.string.info_tlv_user_data))
holder.register(TlvId.ProtectedUserData, Resources(R.string.tlv_user_protected_data, R.string.info_tlv_protected_user_data))
}
}

View file

@ -140,7 +140,7 @@ abstract class BaseCardActionFragment : BaseFragment(), ActionView {
})
}
private fun inflateParamView(where: ViewGroup): ViewGroup {
protected fun inflateParamView(where: ViewGroup): ViewGroup {
val inflater = LayoutInflater.from(where.context)
val view = inflater.inflate(R.layout.w_card_incoming_param, where, false)
where.plusAssign(view)

View file

@ -56,6 +56,7 @@ class ParameterWidget(
btnAction.setText(getResNameId(ActionType.Scan))
toggleActionBtnVisibility()
initDescriptionWidget()
parent.tag = Id.getTag(typedItem.id)
}
fun changeParamValue(data: Any?, silent: Boolean = true) {

View file

@ -8,4 +8,8 @@ import com.tangem.devkit._arch.structure.Id
enum class TlvId : Id {
CardId,
TransactionOutHash,
IssuerData,
Counter,
UserData,
ProtectedUserData
}

View file

@ -0,0 +1,10 @@
package com.tangem.devkit.ucase.variants.createwallet.ui
import com.tangem.devkit.ucase.domain.paramsManager.ItemsManager
import com.tangem.devkit.ucase.domain.paramsManager.managers.CreateWalletItemsManager
import com.tangem.devkit.ucase.ui.BaseCardActionFragment
class CreateWalletActionFragment : BaseCardActionFragment() {
override val itemsManager: ItemsManager by lazy { CreateWalletItemsManager() }
}

View file

@ -0,0 +1,10 @@
package com.tangem.devkit.ucase.variants.issuerdata.ui
import com.tangem.devkit.ucase.domain.paramsManager.ItemsManager
import com.tangem.devkit.ucase.domain.paramsManager.managers.ReadIssuerDataItemsManager
import com.tangem.devkit.ucase.ui.BaseCardActionFragment
class ReadIssuerDataFragment : BaseCardActionFragment() {
override val itemsManager: ItemsManager by lazy { ReadIssuerDataItemsManager() }
}

View file

@ -0,0 +1,10 @@
package com.tangem.devkit.ucase.variants.issuerdata.ui
import com.tangem.devkit.ucase.domain.paramsManager.ItemsManager
import com.tangem.devkit.ucase.domain.paramsManager.managers.ReadIssuerExtraDataItemsManager
import com.tangem.devkit.ucase.ui.BaseCardActionFragment
class ReadIssuerExtraDataFragment : BaseCardActionFragment() {
override val itemsManager: ItemsManager by lazy { ReadIssuerExtraDataItemsManager() }
}

View file

@ -0,0 +1,10 @@
package com.tangem.devkit.ucase.variants.issuerdata.ui
import com.tangem.devkit.ucase.domain.paramsManager.ItemsManager
import com.tangem.devkit.ucase.domain.paramsManager.managers.WriteIssuerDataItemsManager
import com.tangem.devkit.ucase.ui.BaseCardActionFragment
class WriteIssuerDataFragment : BaseCardActionFragment() {
override val itemsManager: ItemsManager by lazy { WriteIssuerDataItemsManager() }
}

View file

@ -0,0 +1,10 @@
package com.tangem.devkit.ucase.variants.issuerdata.ui
import com.tangem.devkit.ucase.domain.paramsManager.ItemsManager
import com.tangem.devkit.ucase.domain.paramsManager.managers.WriteIssuerExtraDataItemsManager
import com.tangem.devkit.ucase.ui.BaseCardActionFragment
class WriteIssuerExtraDataFragment : BaseCardActionFragment() {
override val itemsManager: ItemsManager by lazy { WriteIssuerExtraDataItemsManager() }
}

View file

@ -22,13 +22,13 @@ enum class BlockId : PersonalizationId {
Pins,
}
enum class CardNumber : PersonalizationId {
enum class CardNumberId : PersonalizationId {
Series,
Number,
BatchId,
}
enum class Common : PersonalizationId {
enum class CommonId : PersonalizationId {
Curve,
Blockchain,
BlockchainCustom,
@ -36,7 +36,7 @@ enum class Common : PersonalizationId {
CreateWallet,
}
enum class SigningMethod : PersonalizationId {
enum class SigningMethodId : PersonalizationId {
SignTx,
SignTxRaw,
SignValidatedTx,
@ -46,7 +46,7 @@ enum class SigningMethod : PersonalizationId {
SignExternal,
}
enum class SignHashExProp : PersonalizationId {
enum class SignHashExPropId : PersonalizationId {
PinLessFloorLimit,
CryptoExKey,
RequireTerminalCertSig,
@ -54,21 +54,21 @@ enum class SignHashExProp : PersonalizationId {
CheckPin3,
}
enum class Token : PersonalizationId {
enum class TokenId : PersonalizationId {
ItsToken,
Symbol,
ContractAddress,
Decimal
}
enum class ProductMask : PersonalizationId {
enum class ProductMaskId : PersonalizationId {
Note,
Tag,
IdCard,
IdIssuerCard
}
enum class SettingsMask : PersonalizationId {
enum class SettingsMaskId : PersonalizationId {
IsReusable,
NeedActivation,
ForbidPurge,
@ -87,12 +87,12 @@ enum class SettingsMask : PersonalizationId {
RestrictOverwriteExtraIssuerData,
}
enum class SettingsMaskProtocolEnc : PersonalizationId {
enum class SettingsMaskProtocolEncId : PersonalizationId {
AllowUnencrypted,
AllowStaticEncryption
}
enum class SettingsMaskNdef : PersonalizationId {
enum class SettingsMaskNdefId : PersonalizationId {
UseNdef,
DynamicNdef,
DisablePrecomputedNdef,
@ -101,7 +101,7 @@ enum class SettingsMaskNdef : PersonalizationId {
Uri,
}
enum class Pins : PersonalizationId {
enum class PinsId : PersonalizationId {
Pin,
Pin2,
Pin3,

View file

@ -14,63 +14,63 @@ class ConfigValuesHolder : BaseTypedHolder<Id, Value>() {
// All registered association values can't be objects
fun init(default: PersonalizationConfig) {
register(CardNumber.Series, Value(default.series))
register(CardNumber.Number, Value(default.startNumber))
register(CardNumber.BatchId, Value(default.cardData.batch))
register(Common.Curve, Value(default.curveID, Helper.listOfCurves()))
register(Common.Blockchain, Value(default.cardData.blockchain, Helper.listOfBlockchain()))
register(Common.BlockchainCustom, Value(default.blockchainCustom))
register(Common.MaxSignatures, Value(default.MaxSignatures))
register(Common.CreateWallet, Value(default.createWallet))
register(SigningMethod.SignTx, Value(default.SigningMethod0))
register(SigningMethod.SignTxRaw, Value(default.SigningMethod1))
register(SigningMethod.SignValidatedTx, Value(default.SigningMethod2))
register(SigningMethod.SignValidatedTxRaw, Value(default.SigningMethod3))
register(SigningMethod.SignValidatedTxIssuer, Value(default.SigningMethod4))
register(SigningMethod.SignValidatedTxRawIssuer, Value(default.SigningMethod5))
register(SigningMethod.SignExternal, Value(default.SigningMethod6))
register(SignHashExProp.PinLessFloorLimit, Value(default.pinLessFloorLimit))
register(SignHashExProp.CryptoExKey, Value(default.hexCrExKey))
register(SignHashExProp.RequireTerminalCertSig, Value(default.requireTerminalCertSignature))
register(SignHashExProp.RequireTerminalTxSig, Value(default.requireTerminalTxSignature))
register(SignHashExProp.CheckPin3, Value(default.checkPIN3onCard))
register(Token.ItsToken, Value(default.itsToken))
register(Token.Symbol, Value(default.cardData.token_symbol))
register(Token.ContractAddress, Value(default.cardData.token_contract_address))
register(Token.Decimal, Value(default.cardData.token_decimal))
register(ProductMask.Note, Value(default.cardData.product_note))
register(ProductMask.Tag, Value(default.cardData.product_tag))
register(ProductMask.IdCard, Value(default.cardData.product_id_card))
register(ProductMask.IdIssuerCard, Value(default.cardData.product_id_issuer))
register(SettingsMask.IsReusable, Value(default.isReusable))
register(SettingsMask.NeedActivation, Value(default.useActivation))
register(SettingsMask.ForbidPurge, Value(default.forbidPurgeWallet))
register(SettingsMask.AllowSelectBlockchain, Value(default.allowSelectBlockchain))
register(SettingsMask.UseBlock, Value(default.useBlock))
register(SettingsMask.OneApdu, Value(default.useOneCommandAtTime))
register(SettingsMask.UseCvc, Value(default.useCVC))
register(SettingsMask.AllowSwapPin, Value(default.allowSwapPIN))
register(SettingsMask.AllowSwapPin2, Value(default.allowSwapPIN2))
register(SettingsMask.ForbidDefaultPin, Value(default.forbidDefaultPIN))
register(SettingsMask.SmartSecurityDelay, Value(default.smartSecurityDelay))
register(SettingsMask.ProtectIssuerDataAgainstReplay, Value(default.protectIssuerDataAgainstReplay))
register(SettingsMask.SkipSecurityDelayIfValidated, Value(default.skipSecurityDelayIfValidatedByIssuer))
register(SettingsMask.SkipPin2CvcIfValidated, Value(default.skipCheckPIN2andCVCIfValidatedByIssuer))
register(SettingsMask.SkipSecurityDelayOnLinkedTerminal, Value(default.skipSecurityDelayIfValidatedByLinkedTerminal))
register(SettingsMask.RestrictOverwriteExtraIssuerData, Value(default.restrictOverwriteIssuerDataEx))
register(SettingsMaskProtocolEnc.AllowUnencrypted, Value(default.protocolAllowUnencrypted))
register(SettingsMaskProtocolEnc.AllowStaticEncryption, Value(default.protocolAllowStaticEncryption))
register(SettingsMaskNdef.UseNdef, Value(default.useNDEF))
register(SettingsMaskNdef.DynamicNdef, Value(default.useDynamicNDEF))
register(SettingsMaskNdef.DisablePrecomputedNdef, Value(default.disablePrecomputedNDEF))
register(SettingsMaskNdef.Aar, Value(default.aar, Helper.aarList()))
register(SettingsMaskNdef.AarCustom, Value(default.aarCustom))
register(SettingsMaskNdef.Uri, Value(default.uri))
register(Pins.Pin, Value(default.PIN))
register(Pins.Pin2, Value(default.PIN2))
register(Pins.Pin3, Value(default.PIN3))
register(Pins.Cvc, Value(default.CVC))
register(Pins.PauseBeforePin2, Value(default.pauseBeforePIN2, Helper.pauseBeforePin()))
register(CardNumberId.Series, Value(default.series))
register(CardNumberId.Number, Value(default.startNumber))
register(CardNumberId.BatchId, Value(default.cardData.batch))
register(CommonId.Curve, Value(default.curveID, Helper.listOfCurves()))
register(CommonId.Blockchain, Value(default.cardData.blockchain, Helper.listOfBlockchain()))
register(CommonId.BlockchainCustom, Value(default.blockchainCustom))
register(CommonId.MaxSignatures, Value(default.MaxSignatures))
register(CommonId.CreateWallet, Value(default.createWallet))
register(SigningMethodId.SignTx, Value(default.SigningMethod0))
register(SigningMethodId.SignTxRaw, Value(default.SigningMethod1))
register(SigningMethodId.SignValidatedTx, Value(default.SigningMethod2))
register(SigningMethodId.SignValidatedTxRaw, Value(default.SigningMethod3))
register(SigningMethodId.SignValidatedTxIssuer, Value(default.SigningMethod4))
register(SigningMethodId.SignValidatedTxRawIssuer, Value(default.SigningMethod5))
register(SigningMethodId.SignExternal, Value(default.SigningMethod6))
register(SignHashExPropId.PinLessFloorLimit, Value(default.pinLessFloorLimit))
register(SignHashExPropId.CryptoExKey, Value(default.hexCrExKey))
register(SignHashExPropId.RequireTerminalCertSig, Value(default.requireTerminalCertSignature))
register(SignHashExPropId.RequireTerminalTxSig, Value(default.requireTerminalTxSignature))
register(SignHashExPropId.CheckPin3, Value(default.checkPIN3onCard))
register(TokenId.ItsToken, Value(default.itsToken))
register(TokenId.Symbol, Value(default.cardData.token_symbol))
register(TokenId.ContractAddress, Value(default.cardData.token_contract_address))
register(TokenId.Decimal, Value(default.cardData.token_decimal))
register(ProductMaskId.Note, Value(default.cardData.product_note))
register(ProductMaskId.Tag, Value(default.cardData.product_tag))
register(ProductMaskId.IdCard, Value(default.cardData.product_id_card))
register(ProductMaskId.IdIssuerCard, Value(default.cardData.product_id_issuer))
register(SettingsMaskId.IsReusable, Value(default.isReusable))
register(SettingsMaskId.NeedActivation, Value(default.useActivation))
register(SettingsMaskId.ForbidPurge, Value(default.forbidPurgeWallet))
register(SettingsMaskId.AllowSelectBlockchain, Value(default.allowSelectBlockchain))
register(SettingsMaskId.UseBlock, Value(default.useBlock))
register(SettingsMaskId.OneApdu, Value(default.useOneCommandAtTime))
register(SettingsMaskId.UseCvc, Value(default.useCVC))
register(SettingsMaskId.AllowSwapPin, Value(default.allowSwapPIN))
register(SettingsMaskId.AllowSwapPin2, Value(default.allowSwapPIN2))
register(SettingsMaskId.ForbidDefaultPin, Value(default.forbidDefaultPIN))
register(SettingsMaskId.SmartSecurityDelay, Value(default.smartSecurityDelay))
register(SettingsMaskId.ProtectIssuerDataAgainstReplay, Value(default.protectIssuerDataAgainstReplay))
register(SettingsMaskId.SkipSecurityDelayIfValidated, Value(default.skipSecurityDelayIfValidatedByIssuer))
register(SettingsMaskId.SkipPin2CvcIfValidated, Value(default.skipCheckPIN2andCVCIfValidatedByIssuer))
register(SettingsMaskId.SkipSecurityDelayOnLinkedTerminal, Value(default.skipSecurityDelayIfValidatedByLinkedTerminal))
register(SettingsMaskId.RestrictOverwriteExtraIssuerData, Value(default.restrictOverwriteIssuerDataEx))
register(SettingsMaskProtocolEncId.AllowUnencrypted, Value(default.protocolAllowUnencrypted))
register(SettingsMaskProtocolEncId.AllowStaticEncryption, Value(default.protocolAllowStaticEncryption))
register(SettingsMaskNdefId.UseNdef, Value(default.useNDEF))
register(SettingsMaskNdefId.DynamicNdef, Value(default.useDynamicNDEF))
register(SettingsMaskNdefId.DisablePrecomputedNdef, Value(default.disablePrecomputedNDEF))
register(SettingsMaskNdefId.Aar, Value(default.aar, Helper.aarList()))
register(SettingsMaskNdefId.AarCustom, Value(default.aarCustom))
register(SettingsMaskNdefId.Uri, Value(default.uri))
register(PinsId.Pin, Value(default.PIN))
register(PinsId.Pin2, Value(default.PIN2))
register(PinsId.Pin3, Value(default.PIN3))
register(PinsId.Cvc, Value(default.CVC))
register(PinsId.PauseBeforePin2, Value(default.pauseBeforePIN2, Helper.pauseBeforePin()))
}
}

View file

@ -11,37 +11,37 @@ class ItemTypes {
BlockId.SettingsMaskNdef, BlockId.Pins
)
val listItemList = mutableListOf(Common.Curve, Common.Blockchain, SettingsMaskNdef.Aar, Pins.PauseBeforePin2)
val listItemList = mutableListOf(CommonId.Curve, CommonId.Blockchain, SettingsMaskNdefId.Aar, PinsId.PauseBeforePin2)
val boolList = mutableListOf(
Common.CreateWallet, SigningMethod.SignTx, SigningMethod.SignTxRaw, SigningMethod.SignValidatedTx,
SigningMethod.SignValidatedTxRaw, SigningMethod.SignValidatedTxIssuer,
SigningMethod.SignValidatedTxRawIssuer, SigningMethod.SignExternal, SignHashExProp.RequireTerminalCertSig,
SignHashExProp.RequireTerminalTxSig, SignHashExProp.CheckPin3, Token.ItsToken,
ProductMask.Note, ProductMask.Tag, ProductMask.IdCard, ProductMask.IdIssuerCard, SettingsMask.IsReusable, SettingsMask.NeedActivation,
SettingsMask.ForbidPurge, SettingsMask.AllowSelectBlockchain, SettingsMask.UseBlock, SettingsMask.OneApdu,
SettingsMask.UseCvc, SettingsMask.AllowSwapPin, SettingsMask.AllowSwapPin2, SettingsMask.ForbidDefaultPin,
SettingsMask.SmartSecurityDelay, SettingsMask.ProtectIssuerDataAgainstReplay,
SettingsMask.SkipSecurityDelayIfValidated, SettingsMask.SkipPin2CvcIfValidated,
SettingsMask.SkipSecurityDelayOnLinkedTerminal, SettingsMask.RestrictOverwriteExtraIssuerData,
SettingsMaskProtocolEnc.AllowUnencrypted, SettingsMaskProtocolEnc.AllowStaticEncryption,
SettingsMaskNdef.UseNdef, SettingsMaskNdef.DynamicNdef, SettingsMaskNdef.DisablePrecomputedNdef
CommonId.CreateWallet, SigningMethodId.SignTx, SigningMethodId.SignTxRaw, SigningMethodId.SignValidatedTx,
SigningMethodId.SignValidatedTxRaw, SigningMethodId.SignValidatedTxIssuer,
SigningMethodId.SignValidatedTxRawIssuer, SigningMethodId.SignExternal, SignHashExPropId.RequireTerminalCertSig,
SignHashExPropId.RequireTerminalTxSig, SignHashExPropId.CheckPin3, TokenId.ItsToken,
ProductMaskId.Note, ProductMaskId.Tag, ProductMaskId.IdCard, ProductMaskId.IdIssuerCard, SettingsMaskId.IsReusable, SettingsMaskId.NeedActivation,
SettingsMaskId.ForbidPurge, SettingsMaskId.AllowSelectBlockchain, SettingsMaskId.UseBlock, SettingsMaskId.OneApdu,
SettingsMaskId.UseCvc, SettingsMaskId.AllowSwapPin, SettingsMaskId.AllowSwapPin2, SettingsMaskId.ForbidDefaultPin,
SettingsMaskId.SmartSecurityDelay, SettingsMaskId.ProtectIssuerDataAgainstReplay,
SettingsMaskId.SkipSecurityDelayIfValidated, SettingsMaskId.SkipPin2CvcIfValidated,
SettingsMaskId.SkipSecurityDelayOnLinkedTerminal, SettingsMaskId.RestrictOverwriteExtraIssuerData,
SettingsMaskProtocolEncId.AllowUnencrypted, SettingsMaskProtocolEncId.AllowStaticEncryption,
SettingsMaskNdefId.UseNdef, SettingsMaskNdefId.DynamicNdef, SettingsMaskNdefId.DisablePrecomputedNdef
)
val editTextList = mutableListOf(
CardNumber.Series, CardNumber.BatchId, Common.BlockchainCustom, SignHashExProp.CryptoExKey, Token.Symbol,
Token.ContractAddress, Pins.Pin, Pins.Pin2, Pins.Pin3, Pins.Cvc, SettingsMaskNdef.AarCustom, SettingsMaskNdef.Uri
CardNumberId.Series, CardNumberId.BatchId, CommonId.BlockchainCustom, SignHashExPropId.CryptoExKey, TokenId.Symbol,
TokenId.ContractAddress, PinsId.Pin, PinsId.Pin2, PinsId.Pin3, PinsId.Cvc, SettingsMaskNdefId.AarCustom, SettingsMaskNdefId.Uri
)
val numberList = mutableListOf(
CardNumber.Number, Common.MaxSignatures, SignHashExProp.PinLessFloorLimit, Token.Decimal
CardNumberId.Number, CommonId.MaxSignatures, SignHashExPropId.PinLessFloorLimit, TokenId.Decimal
)
val hiddenList = mutableListOf<Id>(
CardNumber.Series, CardNumber.BatchId, Pins.Pin3, SigningMethod.SignExternal,
SignHashExProp.CryptoExKey, SignHashExProp.CheckPin3, SettingsMask.OneApdu,
SettingsMask.UseBlock, SettingsMask.ProtectIssuerDataAgainstReplay,
SignHashExProp.RequireTerminalCertSig, SignHashExProp.RequireTerminalTxSig
CardNumberId.Series, CardNumberId.BatchId, PinsId.Pin3, SigningMethodId.SignExternal,
SignHashExPropId.CryptoExKey, SignHashExPropId.CheckPin3, SettingsMaskId.OneApdu,
SettingsMaskId.UseBlock, SettingsMaskId.ProtectIssuerDataAgainstReplay,
SignHashExPropId.RequireTerminalCertSig, SignHashExPropId.RequireTerminalTxSig
)
val oftenUsedList = listOf<Id>(
@ -56,11 +56,11 @@ class ItemTypes {
// BlockId.SettingsMaskProtocolEnc,
BlockId.SettingsMaskNdef,
// BlockId.Pins,
Common.Curve,
Common.Blockchain,
Common.BlockchainCustom,
CommonId.Curve,
CommonId.Blockchain,
CommonId.BlockchainCustom,
// Common.MaxSignatures,
Common.CreateWallet,
CommonId.CreateWallet,
// SigningMethod.SignTx,
// SigningMethod.SignTxRaw,
// SigningMethod.SignValidatedTx,
@ -79,10 +79,10 @@ class ItemTypes {
// Token.Symbol,
// Token.ContractAddress,
// Token.Decimal,
ProductMask.Note,
ProductMask.Tag,
ProductMask.IdCard,
ProductMask.IdIssuerCard,
ProductMaskId.Note,
ProductMaskId.Tag,
ProductMaskId.IdCard,
ProductMaskId.IdIssuerCard,
// SettingsMask.IsReusable,
// SettingsMask.NeedActivation,
// SettingsMask.ForbidPurge,
@ -104,14 +104,14 @@ class ItemTypes {
// SettingsMaskNdef.UseNdef,
// SettingsMaskNdef.DynamicNdef,
// SettingsMaskNdef.DisablePrecomputedNdef,
SettingsMaskNdef.Aar,
SettingsMaskNdef.AarCustom,
SettingsMaskNdef.Uri,
SettingsMaskNdefId.Aar,
SettingsMaskNdefId.AarCustom,
SettingsMaskNdefId.Uri,
// Pins.Pin,
// Pins.Pin2,
// Pins.Pin3,
// Pins.Cvc,
Pins.PauseBeforePin2
PinsId.PauseBeforePin2
)
}

View file

@ -50,63 +50,63 @@ class ItemsToPersonalizationConfig : ItemsToModel<PersonalizationConfig> {
private fun createModel(): PersonalizationConfig {
val export = PersonalizationConfig()
export.series = getTyped(CardNumber.Series)
export.startNumber = getTyped(CardNumber.Number)
export.cardData.batch = getTyped(CardNumber.BatchId)
export.curveID = getTyped(Common.Curve)
export.cardData.blockchain = getTyped(Common.Blockchain)
export.blockchainCustom = getTyped(Common.BlockchainCustom)
export.MaxSignatures = getTyped(Common.MaxSignatures)
export.createWallet = getTyped(Common.CreateWallet)
export.SigningMethod0 = getTyped(SigningMethod.SignTx)
export.SigningMethod1 = getTyped(SigningMethod.SignTxRaw)
export.SigningMethod2 = getTyped(SigningMethod.SignValidatedTx)
export.SigningMethod3 = getTyped(SigningMethod.SignValidatedTxRaw)
export.SigningMethod4 = getTyped(SigningMethod.SignValidatedTxIssuer)
export.SigningMethod5 = getTyped(SigningMethod.SignValidatedTxRawIssuer)
export.SigningMethod6 = getTyped(SigningMethod.SignExternal)
export.pinLessFloorLimit = getTyped(SignHashExProp.PinLessFloorLimit)
export.hexCrExKey = getTyped(SignHashExProp.CryptoExKey)
export.requireTerminalCertSignature = getTyped(SignHashExProp.RequireTerminalCertSig)
export.requireTerminalTxSignature = getTyped(SignHashExProp.RequireTerminalTxSig)
export.checkPIN3onCard = getTyped(SignHashExProp.CheckPin3)
export.itsToken = getTyped(Token.ItsToken)
export.cardData.token_symbol = getTyped(Token.Symbol)
export.cardData.token_contract_address = getTyped(Token.ContractAddress)
export.cardData.token_decimal = getTyped(Token.Decimal)
export.cardData = export.cardData.apply { this.product_note = getTyped(ProductMask.Note) }
export.cardData = export.cardData.apply { this.product_tag = getTyped(ProductMask.Tag) }
export.cardData = export.cardData.apply { this.product_id_card = getTyped(ProductMask.IdCard) }
export.cardData = export.cardData.apply { this.product_id_issuer = getTyped(ProductMask.IdIssuerCard) }
export.isReusable = getTyped(SettingsMask.IsReusable)
export.useActivation = getTyped(SettingsMask.NeedActivation)
export.forbidPurgeWallet = getTyped(SettingsMask.ForbidPurge)
export.allowSelectBlockchain = getTyped(SettingsMask.AllowSelectBlockchain)
export.useBlock = getTyped(SettingsMask.UseBlock)
export.useOneCommandAtTime = getTyped(SettingsMask.OneApdu)
export.useCVC = getTyped(SettingsMask.UseCvc)
export.allowSwapPIN = getTyped(SettingsMask.AllowSwapPin)
export.allowSwapPIN2 = getTyped(SettingsMask.AllowSwapPin2)
export.forbidDefaultPIN = getTyped(SettingsMask.ForbidDefaultPin)
export.smartSecurityDelay = getTyped(SettingsMask.SmartSecurityDelay)
export.protectIssuerDataAgainstReplay = getTyped(SettingsMask.ProtectIssuerDataAgainstReplay)
export.skipSecurityDelayIfValidatedByIssuer = getTyped(SettingsMask.SkipSecurityDelayIfValidated)
export.skipCheckPIN2andCVCIfValidatedByIssuer = getTyped(SettingsMask.SkipPin2CvcIfValidated)
export.skipSecurityDelayIfValidatedByLinkedTerminal = getTyped(SettingsMask.SkipSecurityDelayOnLinkedTerminal)
export.restrictOverwriteIssuerDataEx = getTyped(SettingsMask.RestrictOverwriteExtraIssuerData)
export.protocolAllowUnencrypted = getTyped(SettingsMaskProtocolEnc.AllowUnencrypted)
export.protocolAllowStaticEncryption = getTyped(SettingsMaskProtocolEnc.AllowStaticEncryption)
export.useNDEF = getTyped(SettingsMaskNdef.UseNdef)
export.useDynamicNDEF = getTyped(SettingsMaskNdef.DynamicNdef)
export.disablePrecomputedNDEF = getTyped(SettingsMaskNdef.DisablePrecomputedNdef)
export.aar = getTyped(SettingsMaskNdef.Aar)
export.aarCustom = getTyped(SettingsMaskNdef.AarCustom)
export.uri = getTyped(SettingsMaskNdef.Uri)
export.PIN = getTyped(Pins.Pin)
export.PIN2 = getTyped(Pins.Pin2)
export.PIN3 = getTyped(Pins.Pin3)
export.CVC = getTyped(Pins.Cvc)
export.pauseBeforePIN2 = getTyped(Pins.PauseBeforePin2)
export.series = getTyped(CardNumberId.Series)
export.startNumber = getTyped(CardNumberId.Number)
export.cardData.batch = getTyped(CardNumberId.BatchId)
export.curveID = getTyped(CommonId.Curve)
export.cardData.blockchain = getTyped(CommonId.Blockchain)
export.blockchainCustom = getTyped(CommonId.BlockchainCustom)
export.MaxSignatures = getTyped(CommonId.MaxSignatures)
export.createWallet = getTyped(CommonId.CreateWallet)
export.SigningMethod0 = getTyped(SigningMethodId.SignTx)
export.SigningMethod1 = getTyped(SigningMethodId.SignTxRaw)
export.SigningMethod2 = getTyped(SigningMethodId.SignValidatedTx)
export.SigningMethod3 = getTyped(SigningMethodId.SignValidatedTxRaw)
export.SigningMethod4 = getTyped(SigningMethodId.SignValidatedTxIssuer)
export.SigningMethod5 = getTyped(SigningMethodId.SignValidatedTxRawIssuer)
export.SigningMethod6 = getTyped(SigningMethodId.SignExternal)
export.pinLessFloorLimit = getTyped(SignHashExPropId.PinLessFloorLimit)
export.hexCrExKey = getTyped(SignHashExPropId.CryptoExKey)
export.requireTerminalCertSignature = getTyped(SignHashExPropId.RequireTerminalCertSig)
export.requireTerminalTxSignature = getTyped(SignHashExPropId.RequireTerminalTxSig)
export.checkPIN3onCard = getTyped(SignHashExPropId.CheckPin3)
export.itsToken = getTyped(TokenId.ItsToken)
export.cardData.token_symbol = getTyped(TokenId.Symbol)
export.cardData.token_contract_address = getTyped(TokenId.ContractAddress)
export.cardData.token_decimal = getTyped(TokenId.Decimal)
export.cardData = export.cardData.apply { this.product_note = getTyped(ProductMaskId.Note) }
export.cardData = export.cardData.apply { this.product_tag = getTyped(ProductMaskId.Tag) }
export.cardData = export.cardData.apply { this.product_id_card = getTyped(ProductMaskId.IdCard) }
export.cardData = export.cardData.apply { this.product_id_issuer = getTyped(ProductMaskId.IdIssuerCard) }
export.isReusable = getTyped(SettingsMaskId.IsReusable)
export.useActivation = getTyped(SettingsMaskId.NeedActivation)
export.forbidPurgeWallet = getTyped(SettingsMaskId.ForbidPurge)
export.allowSelectBlockchain = getTyped(SettingsMaskId.AllowSelectBlockchain)
export.useBlock = getTyped(SettingsMaskId.UseBlock)
export.useOneCommandAtTime = getTyped(SettingsMaskId.OneApdu)
export.useCVC = getTyped(SettingsMaskId.UseCvc)
export.allowSwapPIN = getTyped(SettingsMaskId.AllowSwapPin)
export.allowSwapPIN2 = getTyped(SettingsMaskId.AllowSwapPin2)
export.forbidDefaultPIN = getTyped(SettingsMaskId.ForbidDefaultPin)
export.smartSecurityDelay = getTyped(SettingsMaskId.SmartSecurityDelay)
export.protectIssuerDataAgainstReplay = getTyped(SettingsMaskId.ProtectIssuerDataAgainstReplay)
export.skipSecurityDelayIfValidatedByIssuer = getTyped(SettingsMaskId.SkipSecurityDelayIfValidated)
export.skipCheckPIN2andCVCIfValidatedByIssuer = getTyped(SettingsMaskId.SkipPin2CvcIfValidated)
export.skipSecurityDelayIfValidatedByLinkedTerminal = getTyped(SettingsMaskId.SkipSecurityDelayOnLinkedTerminal)
export.restrictOverwriteIssuerDataEx = getTyped(SettingsMaskId.RestrictOverwriteExtraIssuerData)
export.protocolAllowUnencrypted = getTyped(SettingsMaskProtocolEncId.AllowUnencrypted)
export.protocolAllowStaticEncryption = getTyped(SettingsMaskProtocolEncId.AllowStaticEncryption)
export.useNDEF = getTyped(SettingsMaskNdefId.UseNdef)
export.useDynamicNDEF = getTyped(SettingsMaskNdefId.DynamicNdef)
export.disablePrecomputedNDEF = getTyped(SettingsMaskNdefId.DisablePrecomputedNdef)
export.aar = getTyped(SettingsMaskNdefId.Aar)
export.aarCustom = getTyped(SettingsMaskNdefId.AarCustom)
export.uri = getTyped(SettingsMaskNdefId.Uri)
export.PIN = getTyped(PinsId.Pin)
export.PIN2 = getTyped(PinsId.Pin2)
export.PIN3 = getTyped(PinsId.Pin3)
export.CVC = getTyped(PinsId.Cvc)
export.pauseBeforePIN2 = getTyped(PinsId.PauseBeforePin2)
return export
}
@ -154,9 +154,9 @@ class PersonalizationConfigToItems : ModelToItems<PersonalizationConfig> {
private fun cardNumber(): ItemGroup {
val block = createGroup(BlockId.CardNumber)
mutableListOf(
CardNumber.Series,
CardNumber.Number,
CardNumber.BatchId
CardNumberId.Series,
CardNumberId.Number,
CardNumberId.BatchId
).forEach { createItem(block, it as Id) }
return block
}
@ -164,12 +164,12 @@ class PersonalizationConfigToItems : ModelToItems<PersonalizationConfig> {
private fun common(): ItemGroup {
val block = createGroup(BlockId.Common)
mutableListOf(
Common.Blockchain,
Common.BlockchainCustom,
Common.Curve,
Common.MaxSignatures,
Common.CreateWallet,
Pins.PauseBeforePin2
CommonId.Blockchain,
CommonId.BlockchainCustom,
CommonId.Curve,
CommonId.MaxSignatures,
CommonId.CreateWallet,
PinsId.PauseBeforePin2
).forEach { createItem(block, it as Id) }
return block
}
@ -177,13 +177,13 @@ class PersonalizationConfigToItems : ModelToItems<PersonalizationConfig> {
private fun signingMethod(): ItemGroup {
val block = createGroup(BlockId.SigningMethod)
mutableListOf(
SigningMethod.SignTx,
SigningMethod.SignTxRaw,
SigningMethod.SignValidatedTx,
SigningMethod.SignValidatedTxRaw,
SigningMethod.SignValidatedTxIssuer,
SigningMethod.SignValidatedTxRawIssuer,
SigningMethod.SignExternal
SigningMethodId.SignTx,
SigningMethodId.SignTxRaw,
SigningMethodId.SignValidatedTx,
SigningMethodId.SignValidatedTxRaw,
SigningMethodId.SignValidatedTxIssuer,
SigningMethodId.SignValidatedTxRawIssuer,
SigningMethodId.SignExternal
).forEach { createItem(block, it) }
return block
}
@ -191,11 +191,11 @@ class PersonalizationConfigToItems : ModelToItems<PersonalizationConfig> {
private fun signHashExProperties(): ItemGroup {
val block = createGroup(BlockId.SignHashExProp)
mutableListOf(
SignHashExProp.PinLessFloorLimit,
SignHashExProp.CryptoExKey,
SignHashExProp.RequireTerminalCertSig,
SignHashExProp.RequireTerminalTxSig,
SignHashExProp.CheckPin3
SignHashExPropId.PinLessFloorLimit,
SignHashExPropId.CryptoExKey,
SignHashExPropId.RequireTerminalCertSig,
SignHashExPropId.RequireTerminalTxSig,
SignHashExPropId.CheckPin3
).forEach { createItem(block, it) }
return block
}
@ -203,10 +203,10 @@ class PersonalizationConfigToItems : ModelToItems<PersonalizationConfig> {
private fun token(): ItemGroup {
val block = createGroup(BlockId.Token)
mutableListOf(
Token.ItsToken,
Token.Symbol,
Token.ContractAddress,
Token.Decimal
TokenId.ItsToken,
TokenId.Symbol,
TokenId.ContractAddress,
TokenId.Decimal
).forEach { createItem(block, it) }
return block
}
@ -214,10 +214,10 @@ class PersonalizationConfigToItems : ModelToItems<PersonalizationConfig> {
private fun productMask(): ItemGroup {
val block = createGroup(BlockId.ProdMask)
mutableListOf(
ProductMask.Note,
ProductMask.Tag,
ProductMask.IdCard,
ProductMask.IdIssuerCard
ProductMaskId.Note,
ProductMaskId.Tag,
ProductMaskId.IdCard,
ProductMaskId.IdIssuerCard
).forEach { createItem(block, it) }
return block
}
@ -225,22 +225,22 @@ class PersonalizationConfigToItems : ModelToItems<PersonalizationConfig> {
private fun settingsMask(): ItemGroup {
val block = createGroup(BlockId.SettingsMask)
mutableListOf(
SettingsMask.IsReusable,
SettingsMask.NeedActivation,
SettingsMask.ForbidPurge,
SettingsMask.AllowSelectBlockchain,
SettingsMask.UseBlock,
SettingsMask.OneApdu,
SettingsMask.UseCvc,
SettingsMask.AllowSwapPin,
SettingsMask.AllowSwapPin2,
SettingsMask.ForbidDefaultPin,
SettingsMask.SmartSecurityDelay,
SettingsMask.ProtectIssuerDataAgainstReplay,
SettingsMask.SkipSecurityDelayIfValidated,
SettingsMask.SkipPin2CvcIfValidated,
SettingsMask.SkipSecurityDelayOnLinkedTerminal,
SettingsMask.RestrictOverwriteExtraIssuerData
SettingsMaskId.IsReusable,
SettingsMaskId.NeedActivation,
SettingsMaskId.ForbidPurge,
SettingsMaskId.AllowSelectBlockchain,
SettingsMaskId.UseBlock,
SettingsMaskId.OneApdu,
SettingsMaskId.UseCvc,
SettingsMaskId.AllowSwapPin,
SettingsMaskId.AllowSwapPin2,
SettingsMaskId.ForbidDefaultPin,
SettingsMaskId.SmartSecurityDelay,
SettingsMaskId.ProtectIssuerDataAgainstReplay,
SettingsMaskId.SkipSecurityDelayIfValidated,
SettingsMaskId.SkipPin2CvcIfValidated,
SettingsMaskId.SkipSecurityDelayOnLinkedTerminal,
SettingsMaskId.RestrictOverwriteExtraIssuerData
).forEach { createItem(block, it) }
return block
}
@ -248,8 +248,8 @@ class PersonalizationConfigToItems : ModelToItems<PersonalizationConfig> {
private fun settingsMaskProtocolEnc(): ItemGroup {
val block = createGroup(BlockId.SettingsMaskProtocolEnc)
mutableListOf(
SettingsMaskProtocolEnc.AllowUnencrypted,
SettingsMaskProtocolEnc.AllowStaticEncryption
SettingsMaskProtocolEncId.AllowUnencrypted,
SettingsMaskProtocolEncId.AllowStaticEncryption
).forEach { createItem(block, it) }
return block
}
@ -257,12 +257,12 @@ class PersonalizationConfigToItems : ModelToItems<PersonalizationConfig> {
private fun settingsMaskNdef(): ItemGroup {
val block = createGroup(BlockId.SettingsMaskNdef)
mutableListOf(
SettingsMaskNdef.UseNdef,
SettingsMaskNdef.DynamicNdef,
SettingsMaskNdef.DisablePrecomputedNdef,
SettingsMaskNdef.Aar,
SettingsMaskNdef.AarCustom,
SettingsMaskNdef.Uri
SettingsMaskNdefId.UseNdef,
SettingsMaskNdefId.DynamicNdef,
SettingsMaskNdefId.DisablePrecomputedNdef,
SettingsMaskNdefId.Aar,
SettingsMaskNdefId.AarCustom,
SettingsMaskNdefId.Uri
).forEach { createItem(block, it) }
return block
}
@ -270,10 +270,10 @@ class PersonalizationConfigToItems : ModelToItems<PersonalizationConfig> {
private fun pins(): ItemGroup {
val block = createGroup(BlockId.Pins)
mutableListOf(
Pins.Pin,
Pins.Pin2,
Pins.Pin3,
Pins.Cvc
PinsId.Pin,
PinsId.Pin2,
PinsId.Pin3,
PinsId.Cvc
).forEach { createItem(block, it) }
return block
}

View file

@ -4,6 +4,7 @@ import com.tangem.KeyPair
import com.tangem.commands.personalization.entities.Acquirer
import com.tangem.commands.personalization.entities.Issuer
import com.tangem.commands.personalization.entities.Manufacturer
import com.tangem.common.extensions.hexToBytes
/**
[REDACTED_AUTHOR]
@ -18,12 +19,14 @@ interface DefaultPersonalizationParams {
name = name,
id = name + "\u0000",
dataKeyPair = KeyPair(
"".toByteArray(),
"11121314151617184771ED81F2BACF57479E4735EB1405083927372D40DA9E92".toByteArray()
("045f16bd1d2eafe463e62a335a09e6b2bbcbd04452526885cb679fc4d27af1bd22f553c7deefb54fd3d4f" +
"361d14e6dc3f11b7d4ea183250a60720ebdf9e110cd26").hexToBytes(),
"11121314151617184771ED81F2BACF57479E4735EB1405083927372D40DA9E92".hexToBytes()
),
transactionKeyPair = KeyPair(
"".toByteArray(),
"11121314151617184771ED81F2BACF57479E4735EB1405081918171615141312".toByteArray()
("0484c5192e9bfa6c528a344f442137a92b89ea835bfef1d04cb4362eb906b508c5889846cfea71ba6dc7b" +
"3120c2208df9c46127d3d85cb5cfbd1479e97133a39d8").hexToBytes(),
"11121314151617184771ED81F2BACF57479E4735EB1405081918171615141312".hexToBytes()
)
)
}
@ -34,8 +37,9 @@ interface DefaultPersonalizationParams {
name = name,
id = name + "\u0000",
keyPair = KeyPair(
"".toByteArray(),
"21222324252627284771ED81F2BACF57479E4735EB1405083927372D40DA9E92".toByteArray()
("0456ad1a82b22bcb40c38fd08939f87e6b80e40dec5b3bdb351c55fcd709e47f9fb2ed00c2304d3a9" +
"86f79c5ae0ac3c84e88da46dc8f513b7542c716af8c9a2daf").hexToBytes(),
"21222324252627284771ED81F2BACF57479E4735EB1405083927372D40DA9E92".hexToBytes()
)
)
}

View file

@ -8,7 +8,7 @@ import com.google.android.material.textfield.TextInputEditText
import com.google.android.material.textfield.TextInputLayout
import com.tangem.devkit.R
import com.tangem.devkit._arch.structure.impl.NumberItem
import com.tangem.devkit.ucase.variants.personalize.CardNumber
import com.tangem.devkit.ucase.variants.personalize.CardNumberId
import ru.dev.gbixahue.eu4d.lib.android._android.views.addInputFilter
import ru.dev.gbixahue.eu4d.lib.android._android.views.moveCursorToEnd
import ru.dev.gbixahue.eu4d.lib.kotlin.stringOf
@ -39,7 +39,7 @@ class NumberWidget(
tilItem.hint = getName()
//TODO: remove from Widget
if (item.id == CardNumber.Number) etItem.addInputFilter(InputFilter.LengthFilter(13))
if (item.id == CardNumberId.Number) etItem.addInputFilter(InputFilter.LengthFilter(13))
etItem.setText(stringOf(typedItem.getTypedData()))
etItem.addTextChangedListener(watcher)

View file

@ -0,0 +1,10 @@
package com.tangem.devkit.ucase.variants.purgewallet.ui
import com.tangem.devkit.ucase.domain.paramsManager.ItemsManager
import com.tangem.devkit.ucase.domain.paramsManager.managers.PurgeWalletItemsManager
import com.tangem.devkit.ucase.ui.BaseCardActionFragment
class PurgeWalletActionFragment : BaseCardActionFragment() {
override val itemsManager: ItemsManager by lazy { PurgeWalletItemsManager() }
}

View file

@ -53,4 +53,38 @@ enum class SignId : ResponseId {
enum class DepersonalizeId: ResponseId {
isSuccess
}
enum class CreateWalletId : ResponseId {
cid,
cardStatus,
walletPublicKey,
}
enum class PurgeWalletId : ResponseId {
cid,
cardStatus
}
enum class ReadIssuerDataId : ResponseId {
cid,
issuerData,
issuerDataSignature,
issuerDataCounter
}
enum class ReadIssuerExtraDataId : ResponseId {
cid,
size,
issuerData,
issuerDataSignature,
issuerDataCounter
}
enum class ReadUserDataId : ResponseId {
cid,
userData,
userProtectedData,
userCounter,
userProtectedCounter
}

View file

@ -2,9 +2,7 @@ package com.tangem.devkit.ucase.variants.responses
import android.view.View
import androidx.lifecycle.ViewModel
import com.tangem.commands.Card
import com.tangem.commands.CommandResponse
import com.tangem.commands.SignResponse
import com.tangem.commands.*
import com.tangem.commands.personalization.DepersonalizeResponse
import com.tangem.devkit.R
import com.tangem.devkit._arch.structure.abstraction.Item
@ -44,6 +42,14 @@ class ResponseViewModel : ViewModel() {
is Card -> R.string.fg_name_response_personalization
is SignResponse -> R.string.fg_name_response_sign
is DepersonalizeResponse -> R.string.fg_name_response_depersonalization
is CreateWalletResponse -> R.string.fg_name_response_create_wallet
is PurgeWalletResponse -> R.string.fg_name_response_purge_wallet
is ReadIssuerDataResponse -> R.string.fg_name_response_read_issuer_data
is WriteIssuerDataResponse -> R.string.fg_name_response_write_issuer_data
is ReadIssuerExtraDataResponse -> R.string.fg_name_response_read_issuer_extra_data
is ReadUserDataResponse -> R.string.fg_name_response_read_user_data
is WriteUserDataResponse -> R.string.fg_name_response_write_user_data
else -> R.string.unknown
}
}

View file

@ -1,7 +1,6 @@
package com.tangem.devkit.ucase.variants.responses.converter
import com.tangem.commands.Card
import com.tangem.commands.SignResponse
import com.tangem.commands.*
import com.tangem.commands.personalization.DepersonalizeResponse
import ru.dev.gbixahue.eu4d.lib.kotlin.common.BaseTypedHolder
import java.lang.reflect.Type
@ -12,5 +11,12 @@ class ConvertersStore : BaseTypedHolder<Type, Any>() {
register(SignResponse::class.java, SignResponseConverter())
register(Card::class.java, CardConverter())
register(DepersonalizeResponse::class.java, DepersonalizeResponseConverter())
register(CreateWalletResponse::class.java, CreateWalletResponseConverter())
register(PurgeWalletResponse::class.java, PurgeWalletResponseConverter())
register(ReadIssuerDataResponse::class.java, ReadIssuerDataResponseConverter())
register(ReadIssuerExtraDataResponse::class.java, ReadIssuerExtraDataResponseConverter())
register(WriteIssuerDataResponse::class.java, WriteIssuerDataResponseConverter())
register(ReadUserDataResponse::class.java, ReadUserDataResponseConverter())
register(WriteUserDataResponse::class.java, WriteUserDataResponseConverter())
}
}

View file

@ -1,11 +1,10 @@
package com.tangem.devkit.ucase.variants.responses.converter
import com.tangem.commands.SignResponse
import com.tangem.commands.*
import com.tangem.commands.personalization.DepersonalizeResponse
import com.tangem.devkit._arch.structure.abstraction.Item
import com.tangem.devkit._arch.structure.impl.TextItem
import com.tangem.devkit.ucase.variants.responses.DepersonalizeId
import com.tangem.devkit.ucase.variants.responses.SignId
import com.tangem.devkit.ucase.variants.responses.*
import ru.dev.gbixahue.eu4d.lib.kotlin.stringOf
/**
@ -27,4 +26,74 @@ class DepersonalizeResponseConverter : BaseResponseConverter<DepersonalizeRespon
override fun convert(from: DepersonalizeResponse): List<Item> {
return listOf(TextItem(DepersonalizeId.isSuccess, stringOf(from.success)))
}
}
class CreateWalletResponseConverter : BaseResponseConverter<CreateWalletResponse>() {
override fun convert(from: CreateWalletResponse): List<Item> {
return listOf(
TextItem(CreateWalletId.cid, from.cardId),
TextItem(CreateWalletId.cardStatus, valueToString(from.status)),
TextItem(CreateWalletId.walletPublicKey, fieldConverter.byteArray(from.walletPublicKey))
)
}
}
class PurgeWalletResponseConverter : BaseResponseConverter<PurgeWalletResponse>() {
override fun convert(from: PurgeWalletResponse): List<Item> {
return listOf(
TextItem(CreateWalletId.cid, from.cardId),
TextItem(CreateWalletId.cardStatus, valueToString(from.status))
)
}
}
class ReadIssuerDataResponseConverter : BaseResponseConverter<ReadIssuerDataResponse>() {
override fun convert(from: ReadIssuerDataResponse): List<Item> {
return listOf(
TextItem(ReadIssuerDataId.cid, from.cardId),
TextItem(ReadIssuerDataId.issuerData, fieldConverter.byteArray(from.issuerData)),
TextItem(ReadIssuerDataId.issuerDataSignature, fieldConverter.byteArray(from.issuerDataSignature)),
TextItem(ReadIssuerDataId.issuerDataCounter, valueToString(from.issuerDataCounter))
)
}
}
class ReadIssuerExtraDataResponseConverter : BaseResponseConverter<ReadIssuerExtraDataResponse>() {
override fun convert(from: ReadIssuerExtraDataResponse): List<Item> {
return listOf(
TextItem(ReadIssuerExtraDataId.cid, from.cardId),
TextItem(ReadIssuerExtraDataId.size, valueToString(from.size)),
TextItem(ReadIssuerExtraDataId.issuerData, fieldConverter.byteArray(from.issuerData)),
TextItem(ReadIssuerExtraDataId.issuerDataSignature, fieldConverter.byteArray(from.issuerDataSignature)),
TextItem(ReadIssuerExtraDataId.issuerDataCounter, valueToString(from.issuerDataCounter))
)
}
}
class WriteIssuerDataResponseConverter : BaseResponseConverter<WriteIssuerDataResponse>() {
override fun convert(from: WriteIssuerDataResponse): List<Item> {
return listOf(
TextItem(CardId.cardId, from.cardId)
)
}
}
class ReadUserDataResponseConverter : BaseResponseConverter<ReadUserDataResponse>() {
override fun convert(from: ReadUserDataResponse): List<Item> {
return listOf(
TextItem(ReadUserDataId.cid, from.cardId),
TextItem(ReadUserDataId.userData, fieldConverter.byteArray(from.userData)),
TextItem(ReadUserDataId.userProtectedData, fieldConverter.byteArray(from.userProtectedData)),
TextItem(ReadUserDataId.userCounter, valueToString(from.userCounter)),
TextItem(ReadUserDataId.userProtectedCounter, valueToString(from.userProtectedCounter))
)
}
}
class WriteUserDataResponseConverter : BaseResponseConverter<WriteUserDataResponse>() {
override fun convert(from: WriteUserDataResponse): List<Item> {
return listOf(
TextItem(CardId.cardId, from.cardId)
)
}
}

View file

@ -0,0 +1,10 @@
package com.tangem.devkit.ucase.variants.userdata.ui
import com.tangem.devkit.ucase.domain.paramsManager.ItemsManager
import com.tangem.devkit.ucase.domain.paramsManager.managers.ReadUserDataItemsManager
import com.tangem.devkit.ucase.ui.BaseCardActionFragment
class ReadUserDataFragment : BaseCardActionFragment() {
override val itemsManager: ItemsManager by lazy { ReadUserDataItemsManager() }
}

View file

@ -0,0 +1,10 @@
package com.tangem.devkit.ucase.variants.userdata.ui
import com.tangem.devkit.ucase.domain.paramsManager.ItemsManager
import com.tangem.devkit.ucase.domain.paramsManager.managers.WriteUserDataItemsManager
import com.tangem.devkit.ucase.ui.BaseCardActionFragment
class WriteUserDataFragment : BaseCardActionFragment() {
override val itemsManager: ItemsManager by lazy { WriteUserDataItemsManager() }
}

View file

@ -85,51 +85,51 @@
<fragment
android:id="@+id/nav_issuer_read_data"
android:name="com.tangem.devkit.ucase.ui.IssuerReadDataActionFragment"
android:name="com.tangem.devkit.ucase.variants.issuerdata.ui.ReadIssuerDataFragment"
android:label="@string/action_issuer_read_data"
tools:layout="@layout/fg_action_issuer_read_data" />
tools:layout="@layout/fg_base_action_layout" />
<fragment
android:id="@+id/nav_issuer_write_data"
android:name="com.tangem.devkit.ucase.ui.IssuerWriteDataActionFragment"
android:name="com.tangem.devkit.ucase.variants.issuerdata.ui.WriteIssuerDataFragment"
android:label="@string/action_issuer_write_data"
tools:layout="@layout/fg_action_issuer_write_data" />
tools:layout="@layout/fg_base_action_layout" />
<fragment
android:id="@+id/nav_issuer_read_ex_data"
android:name="com.tangem.devkit.ucase.ui.IssuerReadExDataActionFragment"
android:name="com.tangem.devkit.ucase.variants.issuerdata.ui.ReadIssuerExtraDataFragment"
android:label="@string/action_issuer_read_ex_data"
tools:layout="@layout/fg_action_issuer_read_ex_data" />
tools:layout="@layout/fg_base_action_layout" />
<fragment
android:id="@+id/nav_issuer_write_ex_data"
android:name="com.tangem.devkit.ucase.ui.IssuerWriteExDataActionFragment"
android:name="com.tangem.devkit.ucase.variants.issuerdata.ui.WriteIssuerExtraDataFragment"
android:label="@string/action_issuer_write_ex_data"
tools:layout="@layout/fg_action_issuer_write_ex_data" />
tools:layout="@layout/fg_base_action_layout" />
<fragment
android:id="@+id/nav_user_read_data"
android:name="com.tangem.devkit.ucase.ui.UserReadDataActionFragment"
android:name="com.tangem.devkit.ucase.variants.userdata.ui.ReadUserDataFragment"
android:label="@string/action_user_read_data"
tools:layout="@layout/fg_action_user_read_data" />
tools:layout="@layout/fg_base_action_layout" />
<fragment
android:id="@+id/nav_user_write_data"
android:name="com.tangem.devkit.ucase.ui.UserWriteDataActionFragment"
android:name="com.tangem.devkit.ucase.variants.userdata.ui.WriteUserDataFragment"
android:label="@string/action_user_write_data"
tools:layout="@layout/fg_action_user_write_data" />
tools:layout="@layout/fg_base_action_layout" />
<fragment
android:id="@+id/nav_wallet_create"
android:name="com.tangem.devkit.ucase.ui.WalletCreateActionFragment"
android:name="com.tangem.devkit.ucase.variants.createwallet.ui.CreateWalletActionFragment"
android:label="@string/action_wallet_create"
tools:layout="@layout/fg_action_wallet_create" />
tools:layout="@layout/fg_base_action_layout" />
<fragment
android:id="@+id/nav_wallet_purge"
android:name="com.tangem.devkit.ucase.ui.WalletPurgeActionFragment"
android:name="com.tangem.devkit.ucase.variants.purgewallet.ui.PurgeWalletActionFragment"
android:label="@string/action_wallet_purge"
tools:layout="@layout/fg_action_wallet_purge" />
tools:layout="@layout/fg_base_action_layout" />
<fragment
android:id="@+id/nav_card_response"

View file

@ -14,10 +14,17 @@
<string name="error_nothing_to_load">Nothing to load</string>
<string name="fg_name_entry_point">@string/app_name</string>
<string name="fg_name_response_scan">Read response</string>
<string name="fg_name_response_sign">Sign response</string>
<string name="fg_name_response_personalization">Personalization response</string>
<string name="fg_name_response_depersonalization">Depersonalization response</string>
<string name="fg_name_response_scan">Read Response</string>
<string name="fg_name_response_sign">Sign Response</string>
<string name="fg_name_response_personalization">Personalization Response</string>
<string name="fg_name_response_depersonalization">Depersonalization Response</string>
<string name="fg_name_response_create_wallet">Create Wallet Response</string>
<string name="fg_name_response_purge_wallet">Purge Wallet Response</string>
<string name="fg_name_response_read_issuer_data">Read Issuer Data Response</string>
<string name="fg_name_response_write_issuer_data">Write Issuer Data Response</string>
<string name="fg_name_response_read_issuer_extra_data">Read Issuer Extra Data Response</string>
<string name="fg_name_response_read_user_data">Read User Data Response</string>
<string name="fg_name_response_write_user_data">Write User Data Response</string>
<string name="switch_description">Docs</string>

View file

@ -5,27 +5,28 @@
<string name="action_card_sign">Sign</string>
<string name="action_personalize">Personalize</string>
<string name="action_depersonalize">Depersonalize</string>
<string name="action_wallet_create">Create wallet</string>
<string name="action_wallet_purge">Purge wallet</string>
<string name="action_issuer_read_data">Read issuer data</string>
<string name="action_issuer_write_data">Write issuer data</string>
<string name="action_issuer_read_ex_data">Read issuer extra data</string>
<string name="action_issuer_write_ex_data">Write issuer extra data</string>
<string name="action_user_read_data">Read user data</string>
<string name="action_user_write_data">Write user data</string>
<string name="action_wallet_create">Create Wallet</string>
<string name="action_wallet_purge">Purge Wallet</string>
<string name="action_issuer_read_data">Read Issuer Data</string>
<string name="action_issuer_write_data">Write Issuer Data</string>
<string name="action_issuer_read_ex_data">Read Issuer Extra Data</string>
<string name="action_issuer_write_ex_data">Write Issuer Extra Data</string>
<string name="action_user_read_data">Read User Data</string>
<string name="action_user_write_data">Write User Data</string>
<string name="info_action_card_scan">This command returns all data about the card and the wallet, including unique card number (CID) that has to be submitted while calling all other commands</string>
<string name="info_action_card_sign">Depending on Signing_Method parameter defined during personalization, this command signs data using Wallet_PrivateKey</string>
<string name="info_action_personalize">Personalization is an initialization procedure, required before start using a card. During this procedure all card setting are performed. During this procedure all data exchange are encrypted because it\'s usually done at the third-party factory.</string>
<string name="info_action_depersonalize">This command reset card to initial state - erase all data, writed during previous personalization and previous usage.
\nCommand available on SDK cards only</string>
<string name="info_action_wallet_create">SomeDescription</string>
<string name="info_action_wallet_purge">SomeDescription</string>
<string name="info_action_issuer_read_data">SomeDescription</string>
<string name="info_action_issuer_write_data">SomeDescription</string>
<string name="info_action_issuer_read_ex_data">SomeDescription</string>
<string name="info_action_issuer_write_ex_data">SomeDescription</string>
<string name="info_action_user_read_data">SomeDescription</string>
<string name="info_action_user_write_data">SomeDescription</string>
<string name="info_action_wallet_create">If the card has an Empty state, this command will create a new wallet, changing a state to Loaded.</string>
<string name="info_action_wallet_purge">This command deletes all wallet data. If IsReusable flag was enabled during personalization, the card changes state to Empty and a new wallet can be created by Create Wallet Command.</string>
<string name="info_action_issuer_read_data">This command returns 512-byte Issuer Data field and its issuers signature.</string>
<string name="info_action_issuer_write_data">This command writes 512-byte Issuer Data field and its issuers signature to the card.</string>
<string name="info_action_issuer_read_ex_data">This command retrieves Issuer Extra Data field and its issuers signature.</string>
<string name="info_action_issuer_write_ex_data">This command writes Issuer Extra Data field and its issuers signature to the card.</string>
<string name="info_action_user_read_data">This command returns User Data and User Protected Data (up to 512-byte each) and two counters: User Counter and User Protected Counter.</string>
<string name="info_action_user_write_data"> This command writes to the card any of User Data, User Protected Data, User Counter and User Protected Counter fields.
</string>
</resources>

View file

@ -155,4 +155,27 @@
<string name="info_response_depersonalize_is_success">Is success</string>
<!-- Field names - Response: Read Issuer (Extra) Data -->
<string name="response_issuer_data_size">Size of Issuer Data</string>
<string name="response_issuer_data">Issuer Data</string>
<string name="response_issuer_data_signature">Issuer Data Signature</string>
<string name="response_issuer_data_counter">Issuer Data Counter</string>
<string name="info_response_issuer_data_size">A size of issuer extra data written on a card.</string>
<string name="info_response_issuer_data">Data defined by the issuer.</string>
<string name="info_response_issuer_data_signature">Issuer data, signed by the issuer with issuer data private key.</string>
<string name="info_response_issuer_data_counter">An optional counter that protects issuer data against replay attack.</string>
<!-- Field names - Response: Read User Data -->
<string name="response_user_data">User Data</string>
<string name="response_user_protected_data">Protected User Data</string>
<string name="response_user_data_counter">User Data Counter</string>
<string name="response_user_data_protected_counter">Protected User Data Counter</string>
<string name="info_response_user_data">Data defined by user\'s App</string>
<string name="info_response_user_protected_data">Data defined by users App (confirmed by PIN2)</string>
<string name="info_response_user_data_counter">Counter initialized by users App and increased on every signing of new transaction</string>
<string name="info_response_user_data_protected_counter">Counter initialized by users App (confirmed by PIN2) and increased on every signing of new transaction</string>
</resources>

View file

@ -3,8 +3,16 @@
<string name="tlv_card_id">Card Id (CID)</string>
<string name="tlv_transaction_out_hash">Hash to sign</string>
<string name="tlv_issuer_data">Issuer Data</string>
<string name="tlv_user_data">User Data</string>
<string name="tlv_user_protected_data">Protected User Data</string>
<string name="tlv_counter">Counter</string>
<string name="info_tlv_card_id">Unique Tangem card ID number</string>
<string name="info_tlv_transaction_out_hash">Hashed transaction you want to be signed </string>
<string name="info_tlv_issuer_data">Issuer Data to be written by this command</string>
<string name="info_tlv_user_data">User Data to be written by this command</string>
<string name="info_tlv_protected_user_data">Protected User Data to be written by this command</string>
<string name="info_tlv_counter">Counter that protects this type of data against replay attack.</string>
</resources>