Updated on 2026-08-14
This commit is contained in:
commit
6f91d23c2c
68 changed files with 1954 additions and 394 deletions
|
|
@ -10,20 +10,20 @@ import org.bitcoinj.script.ScriptBuilder
|
||||||
import java.math.BigDecimal
|
import java.math.BigDecimal
|
||||||
import java.math.BigInteger
|
import java.math.BigInteger
|
||||||
|
|
||||||
class BitcoinTransactionBuilder(
|
open class BitcoinTransactionBuilder(
|
||||||
private val walletPublicKey: ByteArray, private val testNet: Boolean = false
|
private val walletPublicKey: ByteArray, private val testNet: Boolean = false
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private lateinit var transaction: Transaction
|
private lateinit var transaction: Transaction
|
||||||
private var networkParameters: NetworkParameters? = null
|
protected var networkParameters: NetworkParameters? = null
|
||||||
var unspentOutputs: List<UnspentTransaction>? = null
|
var unspentOutputs: List<BitcoinUnspentOutput>? = null
|
||||||
|
|
||||||
fun buildToSign(
|
open fun buildToSign(
|
||||||
transactionData: TransactionData): Result<List<ByteArray>> {
|
transactionData: TransactionData): Result<List<ByteArray>> {
|
||||||
|
|
||||||
if (unspentOutputs == null) return Result.Failure(Exception("Currently there's an unconfirmed transaction"))
|
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 = if (testNet) {
|
||||||
NetworkParameters.fromID(NetworkParameters.ID_TESTNET)
|
NetworkParameters.fromID(NetworkParameters.ID_TESTNET)
|
||||||
|
|
@ -40,27 +40,13 @@ class BitcoinTransactionBuilder(
|
||||||
return Result.Success(hashesForSign)
|
return Result.Success(hashesForSign)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun calculateChange(transactionData: TransactionData): BigDecimal {
|
open fun buildToSend(signedTransaction: ByteArray): ByteArray {
|
||||||
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 {
|
|
||||||
for (index in transaction.inputs.indices) {
|
for (index in transaction.inputs.indices) {
|
||||||
transaction.inputs[index].scriptSig = createScript(index, signedTransaction, walletPublicKey)
|
transaction.inputs[index].scriptSig = createScript(index, signedTransaction, walletPublicKey)
|
||||||
}
|
}
|
||||||
return transaction.bitcoinSerialize()
|
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> {
|
fun getEstimateSize(transactionData: TransactionData): Result<Int> {
|
||||||
val buildTransactionResult = buildToSign(transactionData)
|
val buildTransactionResult = buildToSign(transactionData)
|
||||||
when (buildTransactionResult) {
|
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?,
|
internal fun TransactionData.toBitcoinJTransaction(networkParameters: NetworkParameters?,
|
||||||
unspentOutputs: List<UnspentTransaction>,
|
unspentOutputs: List<BitcoinUnspentOutput>,
|
||||||
change: BigDecimal): Transaction {
|
change: BigDecimal): Transaction {
|
||||||
val transaction = Transaction(networkParameters)
|
val transaction = Transaction(networkParameters)
|
||||||
for (utxo in unspentOutputs) {
|
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(
|
transaction.addOutput(
|
||||||
Coin.parseCoin(this.amount.value!!.toPlainString()),
|
Coin.parseCoin(this.amount.value!!.toPlainString()),
|
||||||
|
|
@ -93,9 +93,9 @@ internal fun TransactionData.toBitcoinJTransaction(networkParameters: NetworkPar
|
||||||
return transaction
|
return transaction
|
||||||
}
|
}
|
||||||
|
|
||||||
class UnspentTransaction(
|
class BitcoinUnspentOutput(
|
||||||
val amount: BigDecimal,
|
val amount: BigDecimal,
|
||||||
val outputIndex: Long,
|
val outputIndex: Long,
|
||||||
val hash: ByteArray,
|
val transactionHash: ByteArray,
|
||||||
val outputScript: ByteArray
|
val outputScript: ByteArray
|
||||||
)
|
)
|
||||||
|
|
@ -2,7 +2,7 @@ package com.tangem.blockchain.blockchains.bitcoin
|
||||||
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.tangem.blockchain.blockchains.bitcoin.network.BitcoinAddressResponse
|
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.common.*
|
||||||
import com.tangem.blockchain.extensions.Result
|
import com.tangem.blockchain.extensions.Result
|
||||||
import com.tangem.blockchain.extensions.SimpleResult
|
import com.tangem.blockchain.extensions.SimpleResult
|
||||||
|
|
@ -10,14 +10,14 @@ import com.tangem.common.CompletionResult
|
||||||
import com.tangem.common.extensions.toHexString
|
import com.tangem.common.extensions.toHexString
|
||||||
import java.math.BigDecimal
|
import java.math.BigDecimal
|
||||||
|
|
||||||
class BitcoinWalletManager(
|
open class BitcoinWalletManager(
|
||||||
cardId: String,
|
cardId: String,
|
||||||
wallet: Wallet,
|
wallet: Wallet,
|
||||||
private val transactionBuilder: BitcoinTransactionBuilder,
|
private val transactionBuilder: BitcoinTransactionBuilder,
|
||||||
private val networkManager: BitcoinNetworkManager
|
private val networkManager: BitcoinProvider
|
||||||
) : WalletManager(cardId, wallet), TransactionSender {
|
) : WalletManager(cardId, wallet), TransactionSender {
|
||||||
|
|
||||||
private val blockchain = wallet.blockchain
|
protected val blockchain = wallet.blockchain
|
||||||
|
|
||||||
override suspend fun update() {
|
override suspend fun update() {
|
||||||
val response = networkManager.getInfo(wallet.address)
|
val response = networkManager.getInfo(wallet.address)
|
||||||
|
|
@ -30,7 +30,7 @@ class BitcoinWalletManager(
|
||||||
private fun updateWallet(response: BitcoinAddressResponse) {
|
private fun updateWallet(response: BitcoinAddressResponse) {
|
||||||
Log.d(this::class.java.simpleName, "Balance is ${response.balance}")
|
Log.d(this::class.java.simpleName, "Balance is ${response.balance}")
|
||||||
wallet.amounts[AmountType.Coin]?.value = response.balance
|
wallet.amounts[AmountType.Coin]?.value = response.balance
|
||||||
transactionBuilder.unspentOutputs = response.unspentTransactions
|
transactionBuilder.unspentOutputs = response.unspentOutputs
|
||||||
if (response.hasUnconfirmed) {
|
if (response.hasUnconfirmed) {
|
||||||
if (wallet.transactions.isEmpty()) wallet.addIncomingTransaction()
|
if (wallet.transactions.isEmpty()) wallet.addIncomingTransaction()
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -44,8 +44,7 @@ class BitcoinWalletManager(
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun send(transactionData: TransactionData, signer: TransactionSigner): SimpleResult {
|
override suspend fun send(transactionData: TransactionData, signer: TransactionSigner): SimpleResult {
|
||||||
val buildTransactionResult = transactionBuilder.buildToSign(transactionData)
|
when (val buildTransactionResult = transactionBuilder.buildToSign(transactionData)) {
|
||||||
when (buildTransactionResult) {
|
|
||||||
is Result.Failure -> return SimpleResult.Failure(buildTransactionResult.error)
|
is Result.Failure -> return SimpleResult.Failure(buildTransactionResult.error)
|
||||||
is Result.Success -> {
|
is Result.Success -> {
|
||||||
when (val signerResponse = signer.sign(buildTransactionResult.data.toTypedArray(), cardId)) {
|
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>> {
|
override suspend fun getFee(amount: Amount, destination: String): Result<List<Amount>> {
|
||||||
when (val result = networkManager.getFee()) {
|
when (val feeResult = networkManager.getFee()) {
|
||||||
is Result.Failure -> return result
|
is Result.Failure -> return feeResult
|
||||||
is Result.Success -> {
|
is Result.Success -> {
|
||||||
val feeValue = BigDecimal.ONE.movePointLeft(blockchain.decimals())
|
val feeValue = BigDecimal.ONE.movePointLeft(blockchain.decimals())
|
||||||
amount.value = amount.value!! - feeValue
|
amount.value = amount.value!! - feeValue
|
||||||
|
|
@ -72,9 +71,9 @@ class BitcoinWalletManager(
|
||||||
is Result.Failure -> return sizeResult
|
is Result.Failure -> return sizeResult
|
||||||
is Result.Success -> {
|
is Result.Success -> {
|
||||||
val transactionSize = sizeResult.data.toBigDecimal()
|
val transactionSize = sizeResult.data.toBigDecimal()
|
||||||
val minFee = result.data.minimalPerKb.calculateFee(transactionSize)
|
val minFee = feeResult.data.minimalPerKb.calculateFee(transactionSize)
|
||||||
val normalFee = result.data.normalPerKb.calculateFee(transactionSize)
|
val normalFee = feeResult.data.normalPerKb.calculateFee(transactionSize)
|
||||||
val priorityFee = result.data.priorityPerKb.calculateFee(transactionSize)
|
val priorityFee = feeResult.data.priorityPerKb.calculateFee(transactionSize)
|
||||||
return Result.Success(
|
return Result.Success(
|
||||||
listOf(Amount(minFee, blockchain),
|
listOf(Amount(minFee, blockchain),
|
||||||
Amount(normalFee, blockchain),
|
Amount(normalFee, blockchain),
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package com.tangem.blockchain.blockchains.bitcoin.network
|
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.BlockchainInfoApi
|
||||||
import com.tangem.blockchain.blockchains.bitcoin.network.api.BlockcypherApi
|
import com.tangem.blockchain.blockchains.bitcoin.network.api.BlockcypherApi
|
||||||
import com.tangem.blockchain.blockchains.bitcoin.network.api.EstimatefeeApi
|
import com.tangem.blockchain.blockchains.bitcoin.network.api.EstimatefeeApi
|
||||||
|
|
@ -90,7 +90,7 @@ class BitcoinNetworkManager(private val isTestNet: Boolean = false) : BitcoinPro
|
||||||
data class BitcoinAddressResponse(
|
data class BitcoinAddressResponse(
|
||||||
val balance: BigDecimal,
|
val balance: BigDecimal,
|
||||||
val hasUnconfirmed: Boolean,
|
val hasUnconfirmed: Boolean,
|
||||||
val unspentTransactions: List<UnspentTransaction>?
|
val unspentOutputs: List<BitcoinUnspentOutput>?
|
||||||
)
|
)
|
||||||
|
|
||||||
data class BitcoinFee(
|
data class BitcoinFee(
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package com.tangem.blockchain.blockchains.bitcoin.network
|
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.BlockchainInfoApi
|
||||||
import com.tangem.blockchain.blockchains.bitcoin.network.api.EstimatefeeApi
|
import com.tangem.blockchain.blockchains.bitcoin.network.api.EstimatefeeApi
|
||||||
import com.tangem.blockchain.common.Blockchain
|
import com.tangem.blockchain.common.Blockchain
|
||||||
|
|
@ -29,7 +29,7 @@ class BlockchainInfoProvider(
|
||||||
val unconfirmedTransactions = addressData.transactions?.find { it.blockHeight == 0L } != null
|
val unconfirmedTransactions = addressData.transactions?.find { it.blockHeight == 0L } != null
|
||||||
|
|
||||||
val bitcoinUnspents = unspents.unspentOutputs.map {
|
val bitcoinUnspents = unspents.unspentOutputs.map {
|
||||||
UnspentTransaction(
|
BitcoinUnspentOutput(
|
||||||
it.amount!!.toBigDecimal().movePointLeft(decimals),
|
it.amount!!.toBigDecimal().movePointLeft(decimals),
|
||||||
it.outputIndex!!.toLong(),
|
it.outputIndex!!.toLong(),
|
||||||
it.hash!!.hexToBytes(),
|
it.hash!!.hexToBytes(),
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package com.tangem.blockchain.blockchains.bitcoin.network
|
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.BlockcypherApi
|
||||||
import com.tangem.blockchain.blockchains.bitcoin.network.api.BlockcypherBody
|
import com.tangem.blockchain.blockchains.bitcoin.network.api.BlockcypherBody
|
||||||
import com.tangem.blockchain.blockchains.bitcoin.network.response.BlockcypherFee
|
import com.tangem.blockchain.blockchains.bitcoin.network.response.BlockcypherFee
|
||||||
|
|
@ -26,7 +26,7 @@ class BlockcypherProvider(private val api: BlockcypherApi, isTestNet: Boolean) :
|
||||||
try {
|
try {
|
||||||
val addressData: BlockcypherResponse = retryIO { api.getAddressData(blockchain, network, address) }
|
val addressData: BlockcypherResponse = retryIO { api.getAddressData(blockchain, network, address) }
|
||||||
val unspents = addressData.txrefs?.map {
|
val unspents = addressData.txrefs?.map {
|
||||||
UnspentTransaction(
|
BitcoinUnspentOutput(
|
||||||
it.amount!!.toBigDecimal().movePointLeft(decimals),
|
it.amount!!.toBigDecimal().movePointLeft(decimals),
|
||||||
it.outputIndex!!.toLong(),
|
it.outputIndex!!.toLong(),
|
||||||
it.hash!!.hexToBytes(),
|
it.hash!!.hexToBytes(),
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,7 @@ package com.tangem.blockchain.common
|
||||||
|
|
||||||
import com.tangem.blockchain.blockchains.binance.BinanceAddressService
|
import com.tangem.blockchain.blockchains.binance.BinanceAddressService
|
||||||
import com.tangem.blockchain.blockchains.bitcoin.BitcoinAddressService
|
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.cardano.CardanoAddressService
|
||||||
import com.tangem.blockchain.blockchains.ethereum.EthereumAddressService
|
import com.tangem.blockchain.blockchains.ethereum.EthereumAddressService
|
||||||
import com.tangem.blockchain.blockchains.stellar.StellarAddressService
|
import com.tangem.blockchain.blockchains.stellar.StellarAddressService
|
||||||
|
|
@ -17,6 +18,7 @@ enum class Blockchain(
|
||||||
Unknown("", "", ""),
|
Unknown("", "", ""),
|
||||||
Bitcoin("BTC", "BTC", "Bitcoin"),
|
Bitcoin("BTC", "BTC", "Bitcoin"),
|
||||||
BitcoinTestnet("BTC/test", "BTCt", "Bitcoin Testnet"),
|
BitcoinTestnet("BTC/test", "BTCt", "Bitcoin Testnet"),
|
||||||
|
BitcoinCash("BCH", "BCH", "Bitcoin Cash"),
|
||||||
Ethereum("ETH", "ETH", "Ethereum"),
|
Ethereum("ETH", "ETH", "Ethereum"),
|
||||||
Rootstock("", "", ""),
|
Rootstock("", "", ""),
|
||||||
Cardano("CARDANO", "ADA", "Cardano"),
|
Cardano("CARDANO", "ADA", "Cardano"),
|
||||||
|
|
@ -32,7 +34,7 @@ enum class Blockchain(
|
||||||
}
|
}
|
||||||
|
|
||||||
fun decimals(): Int = when (this) {
|
fun decimals(): Int = when (this) {
|
||||||
Bitcoin, BitcoinTestnet, Binance, BinanceTestnet -> 8
|
Bitcoin, BitcoinTestnet, BitcoinCash, Binance, BinanceTestnet -> 8
|
||||||
Cardano, XRP -> 6
|
Cardano, XRP -> 6
|
||||||
Ethereum, Rootstock -> 18
|
Ethereum, Rootstock -> 18
|
||||||
Stellar -> 7
|
Stellar -> 7
|
||||||
|
|
@ -51,6 +53,7 @@ enum class Blockchain(
|
||||||
Unknown -> throw Exception("unsupported blockchain")
|
Unknown -> throw Exception("unsupported blockchain")
|
||||||
Bitcoin -> BitcoinAddressService()
|
Bitcoin -> BitcoinAddressService()
|
||||||
BitcoinTestnet -> BitcoinAddressService(true)
|
BitcoinTestnet -> BitcoinAddressService(true)
|
||||||
|
BitcoinCash -> BitcoinCashAddressService()
|
||||||
Ethereum -> EthereumAddressService()
|
Ethereum -> EthereumAddressService()
|
||||||
Rootstock -> throw Exception("unsupported blockchain")
|
Rootstock -> throw Exception("unsupported blockchain")
|
||||||
Cardano -> CardanoAddressService()
|
Cardano -> CardanoAddressService()
|
||||||
|
|
@ -70,6 +73,8 @@ enum class Blockchain(
|
||||||
fun getExploreUrl(address: String, token: Token? = null): String = when (this) {
|
fun getExploreUrl(address: String, token: Token? = null): String = when (this) {
|
||||||
Binance -> "https://explorer.binance.org/address/$address"
|
Binance -> "https://explorer.binance.org/address/$address"
|
||||||
Bitcoin -> "https://blockchain.info/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"
|
Cardano -> "https://cardanoexplorer.com/address/$address"
|
||||||
Ethereum -> if (token == null) {
|
Ethereum -> if (token == null) {
|
||||||
"https://etherscan.io/address/"
|
"https://etherscan.io/address/"
|
||||||
|
|
|
||||||
|
|
@ -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.BitcoinTransactionBuilder
|
||||||
import com.tangem.blockchain.blockchains.bitcoin.BitcoinWalletManager
|
import com.tangem.blockchain.blockchains.bitcoin.BitcoinWalletManager
|
||||||
import com.tangem.blockchain.blockchains.bitcoin.network.BitcoinNetworkManager
|
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.CardanoTransactionBuilder
|
||||||
import com.tangem.blockchain.blockchains.cardano.CardanoWalletManager
|
import com.tangem.blockchain.blockchains.cardano.CardanoWalletManager
|
||||||
import com.tangem.blockchain.blockchains.cardano.network.CardanoNetworkManager
|
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.XrpWalletManager
|
||||||
import com.tangem.blockchain.blockchains.xrp.network.XrpNetworkManager
|
import com.tangem.blockchain.blockchains.xrp.network.XrpNetworkManager
|
||||||
import com.tangem.commands.Card
|
import com.tangem.commands.Card
|
||||||
|
import com.tangem.common.extensions.toCompressedPublicKey
|
||||||
|
|
||||||
object WalletManagerFactory {
|
object WalletManagerFactory {
|
||||||
|
|
||||||
|
|
@ -50,6 +54,13 @@ object WalletManagerFactory {
|
||||||
BitcoinNetworkManager(true)
|
BitcoinNetworkManager(true)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Blockchain.BitcoinCash -> {
|
||||||
|
return BitcoinCashWalletManager(
|
||||||
|
card.cardId, wallet,
|
||||||
|
BitcoinCashTransactionBuilder(walletPublicKey.toCompressedPublicKey()),
|
||||||
|
BitcoinCashNetworkManager()
|
||||||
|
)
|
||||||
|
}
|
||||||
Blockchain.Ethereum -> {
|
Blockchain.Ethereum -> {
|
||||||
val chain = Chain.Mainnet
|
val chain = Chain.Mainnet
|
||||||
return EthereumWalletManager(
|
return EthereumWalletManager(
|
||||||
|
|
|
||||||
|
|
@ -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_RESERVE = "https://horizon.sui.li/"
|
||||||
const val API_STELLAR_TESTNET = "https://horizon-testnet.stellar.org/"
|
const val API_STELLAR_TESTNET = "https://horizon-testnet.stellar.org/"
|
||||||
const val API_BLOCKCHAIN_INFO = "https://blockchain.info/"
|
const val API_BLOCKCHAIN_INFO = "https://blockchain.info/"
|
||||||
const val API_ADALITE = "https://explorer3.adalite.io"
|
const val API_ADALITE = "https://explorer3.adalite.io/"
|
||||||
const val API_ADALITE_RESERVE = "https://nodes.southeastasia.cloudapp.azure.com"
|
const val API_ADALITE_RESERVE = "https://nodes.southeastasia.cloudapp.azure.com/"
|
||||||
const val API_RIPPLED = "https://s1.ripple.com:51234"
|
const val API_RIPPLED = "https://s1.ripple.com:51234/"
|
||||||
const val API_RIPPLED_RESERVE = "https://s2.ripple.com:51234"
|
const val API_RIPPLED_RESERVE = "https://s2.ripple.com:51234/"
|
||||||
|
const val API_BLOCKCHAIR = "https://api.blockchair.com/"
|
||||||
|
|
@ -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)
|
||||||
|
|
@ -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"
|
||||||
|
|
@ -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
|
||||||
|
)
|
||||||
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,6 +4,7 @@ import com.google.common.truth.Truth
|
||||||
import com.tangem.SessionEnvironment
|
import com.tangem.SessionEnvironment
|
||||||
import com.tangem.blockchain.blockchains.binance.BinanceWalletManager
|
import com.tangem.blockchain.blockchains.binance.BinanceWalletManager
|
||||||
import com.tangem.blockchain.blockchains.bitcoin.BitcoinWalletManager
|
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.cardano.CardanoWalletManager
|
||||||
import com.tangem.blockchain.blockchains.ethereum.EthereumWalletManager
|
import com.tangem.blockchain.blockchains.ethereum.EthereumWalletManager
|
||||||
import com.tangem.blockchain.blockchains.stellar.StellarWalletManager
|
import com.tangem.blockchain.blockchains.stellar.StellarWalletManager
|
||||||
|
|
@ -80,4 +81,15 @@ internal class WalletManagerFactoryTest {
|
||||||
Truth.assertThat(walletManager)
|
Truth.assertThat(walletManager)
|
||||||
.isInstanceOf(BinanceWalletManager::class.java)
|
.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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -21,7 +21,7 @@ data class SessionEnvironment(
|
||||||
var encryptionMode: EncryptionMode = EncryptionMode.NONE,
|
var encryptionMode: EncryptionMode = EncryptionMode.NONE,
|
||||||
var encryptionKey: ByteArray? = null,
|
var encryptionKey: ByteArray? = null,
|
||||||
val cvc: ByteArray? = null,
|
val cvc: ByteArray? = null,
|
||||||
var cardFilter: CardFilter
|
var cardFilter: CardFilter = CardFilter()
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun setPin1(pin1: String) {
|
fun setPin1(pin1: String) {
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ class ReadIssuerExtraDataResponse(
|
||||||
val issuerDataSignature: ByteArray?,
|
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]
|
* When flag [Settings.ProtectIssuerDataAgainstReplay] set in [SettingsMask]
|
||||||
* then this value is mandatory and must increase on each execution of [WriteIssuerDataCommand].
|
* then this value is mandatory and must increase on each execution of [WriteIssuerDataCommand].
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ class WriteUserDataResponse(
|
||||||
) : CommandResponse
|
) : 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.
|
* 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
|
* 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.
|
* from blockchain to accelerate preparing new transaction.
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,15 @@ package com.tangem.devkit._arch.structure
|
||||||
/**
|
/**
|
||||||
[REDACTED_AUTHOR]
|
[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
|
class StringId(val value: String) : Id
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.annotation.ColorRes
|
import androidx.annotation.ColorRes
|
||||||
import com.tangem.devkit.R
|
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.StringId
|
||||||
import com.tangem.devkit._arch.structure.StringResId
|
import com.tangem.devkit._arch.structure.StringResId
|
||||||
import com.tangem.devkit._arch.structure.abstraction.Item
|
import com.tangem.devkit._arch.structure.abstraction.Item
|
||||||
|
|
@ -37,6 +38,7 @@ abstract class BaseViewWidget(
|
||||||
init {
|
init {
|
||||||
subscribeToViewStateChanges(item.viewModel.viewState)
|
subscribeToViewStateChanges(item.viewModel.viewState)
|
||||||
initViewState(item.viewModel.viewState)
|
initViewState(item.viewModel.viewState)
|
||||||
|
view.tag = Id.getTag(item.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun subscribeToViewStateChanges(viewState: ViewState) {
|
protected open fun subscribeToViewStateChanges(viewState: ViewState) {
|
||||||
|
|
|
||||||
|
|
@ -63,15 +63,15 @@ class ActionListFragment : BaseFragment() {
|
||||||
ActionType.Scan,
|
ActionType.Scan,
|
||||||
ActionType.Sign,
|
ActionType.Sign,
|
||||||
ActionType.Personalize,
|
ActionType.Personalize,
|
||||||
ActionType.Depersonalize
|
ActionType.Depersonalize,
|
||||||
// ActionType.CreateWallet,
|
ActionType.CreateWallet,
|
||||||
// ActionType.PurgeWallet,
|
ActionType.PurgeWallet,
|
||||||
// ActionType.ReadIssuerData,
|
ActionType.ReadIssuerData,
|
||||||
// ActionType.WriteIssuerData,
|
ActionType.WriteIssuerData,
|
||||||
// ActionType.ReadIssuerExData,
|
ActionType.ReadIssuerExData,
|
||||||
// ActionType.WriteIssuerExData,
|
ActionType.WriteIssuerExData,
|
||||||
// ActionType.ReadUserData,
|
ActionType.ReadUserData,
|
||||||
// ActionType.WriteUserData
|
ActionType.WriteUserData
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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.domain.paramsManager.PayloadKey
|
||||||
import com.tangem.devkit.ucase.tunnel.ActionView
|
import com.tangem.devkit.ucase.tunnel.ActionView
|
||||||
import com.tangem.devkit.ucase.tunnel.ItemError
|
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.PersonalizationConfigConverter
|
||||||
import com.tangem.devkit.ucase.variants.personalize.converter.PersonalizationConfigToCardConfig
|
import com.tangem.devkit.ucase.variants.personalize.converter.PersonalizationConfigToCardConfig
|
||||||
import com.tangem.devkit.ucase.variants.personalize.dto.DefaultPersonalizationParams
|
import com.tangem.devkit.ucase.variants.personalize.dto.DefaultPersonalizationParams
|
||||||
|
|
@ -46,7 +46,7 @@ class PersonalizeAction : BaseAction() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkSeries(itemList: List<Item>): Boolean {
|
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
|
val data = seriesItem.getData() as? String ?: return false
|
||||||
|
|
||||||
seriesItem.setData(data.toUpperCase())
|
seriesItem.setData(data.toUpperCase())
|
||||||
|
|
@ -54,8 +54,8 @@ class PersonalizeAction : BaseAction() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkNumber(itemList: List<Item>): Boolean {
|
private fun checkNumber(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 numberItem = itemList.findItem(CardNumber.Number) as? NumberItem ?: return false
|
val numberItem = itemList.findItem(CardNumberId.Number) as? NumberItem ?: return false
|
||||||
val seriesData = seriesItem.getData() as? String ?: return false
|
val seriesData = seriesItem.getData() as? String ?: return false
|
||||||
val numberData = stringOf(numberItem.getData() as? Number)
|
val numberData = stringOf(numberItem.getData() as? Number)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
package com.tangem.devkit.ucase.domain.paramsManager.managers
|
package com.tangem.devkit.ucase.domain.paramsManager.managers
|
||||||
|
|
||||||
import com.tangem.devkit._arch.structure.impl.EditTextItem
|
import com.tangem.devkit._arch.structure.impl.EditTextItem
|
||||||
import com.tangem.devkit.ucase.domain.actions.DepersonalizeAction
|
import com.tangem.devkit.ucase.domain.actions.*
|
||||||
import com.tangem.devkit.ucase.domain.actions.ScanAction
|
|
||||||
import com.tangem.devkit.ucase.domain.actions.SignAction
|
|
||||||
import com.tangem.devkit.ucase.domain.paramsManager.triggers.changeConsequence.CardIdConsequence
|
import com.tangem.devkit.ucase.domain.paramsManager.triggers.changeConsequence.CardIdConsequence
|
||||||
import com.tangem.devkit.ucase.variants.TlvId
|
import com.tangem.devkit.ucase.variants.TlvId
|
||||||
|
|
||||||
|
|
@ -29,4 +27,78 @@ class SignItemsManager : BaseItemsManager(SignAction()) {
|
||||||
EditTextItem(TlvId.TransactionOutHash, "Data used for hashing")
|
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")
|
||||||
|
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -40,89 +40,89 @@ class PersonalizationResources() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initCardNumber(holder: TypedHolder<Id, Resources>) {
|
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(CardNumberId.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(CardNumberId.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.BatchId, Resources(R.string.pers_item_batch_id, R.string.info_pers_item_batch_id))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initCommon(holder: TypedHolder<Id, Resources>) {
|
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(CommonId.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(CommonId.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(CommonId.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(CommonId.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.CreateWallet, Resources(R.string.pers_item_create_wallet, R.string.info_pers_item_create_wallet))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initSigningMethod(holder: TypedHolder<Id, Resources>) {
|
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(SigningMethodId.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(SigningMethodId.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(SigningMethodId.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(SigningMethodId.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(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(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(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(SigningMethod.SignExternal, Resources(R.string.pers_item_sign_hash_ex, R.string.info_pers_item_sign_hash_ex))
|
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>) {
|
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(SignHashExPropId.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(SignHashExPropId.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(SignHashExPropId.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(SignHashExPropId.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.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>) {
|
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(TokenId.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(TokenId.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(TokenId.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.Decimal, Resources(R.string.pers_item_decimal, R.string.info_pers_item_decimal))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initProductMask(holder: TypedHolder<Id, Resources>) {
|
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(ProductMaskId.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(ProductMaskId.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(ProductMaskId.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.IdIssuerCard, Resources(R.string.pers_item_id_issuer_card, R.string.info_pers_item_id_issuer_card))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initSettingsMask(holder: TypedHolder<Id, Resources>) {
|
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(SettingsMaskId.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(SettingsMaskId.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(SettingsMaskId.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(SettingsMaskId.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(SettingsMaskId.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(SettingsMaskId.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(SettingsMaskId.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(SettingsMaskId.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(SettingsMaskId.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(SettingsMaskId.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(SettingsMaskId.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(SettingsMaskId.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(SettingsMaskId.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(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(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(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(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.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>) {
|
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(SettingsMaskProtocolEncId.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.AllowStaticEncryption, Resources(R.string.pers_item_allow_fast_encryption, R.string.info_pers_item_allow_fast_encryption))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initSettingsMaskNdef(holder: TypedHolder<Id, Resources>) {
|
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(SettingsMaskNdefId.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(SettingsMaskNdefId.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(SettingsMaskNdefId.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(SettingsMaskNdefId.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(SettingsMaskNdefId.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.Uri, Resources(R.string.pers_item_uri, R.string.info_pers_item_uri))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initPins(holder: TypedHolder<Id, Resources>) {
|
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(PinsId.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(PinsId.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(PinsId.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(PinsId.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.PauseBeforePin2, Resources(R.string.pers_item_pause_before_pin2, R.string.info_pers_item_pause_before_pin2))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3,10 +3,7 @@ package com.tangem.devkit.ucase.resources.initializers
|
||||||
import com.tangem.devkit.R
|
import com.tangem.devkit.R
|
||||||
import com.tangem.devkit.ucase.resources.MainResourceHolder
|
import com.tangem.devkit.ucase.resources.MainResourceHolder
|
||||||
import com.tangem.devkit.ucase.resources.Resources
|
import com.tangem.devkit.ucase.resources.Resources
|
||||||
import com.tangem.devkit.ucase.variants.responses.CardDataId
|
import com.tangem.devkit.ucase.variants.responses.*
|
||||||
import com.tangem.devkit.ucase.variants.responses.CardId
|
|
||||||
import com.tangem.devkit.ucase.variants.responses.DepersonalizeId
|
|
||||||
import com.tangem.devkit.ucase.variants.responses.SignId
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
[REDACTED_AUTHOR]
|
[REDACTED_AUTHOR]
|
||||||
|
|
@ -17,6 +14,13 @@ class ResponseResources {
|
||||||
initCardData(holder)
|
initCardData(holder)
|
||||||
initSignResponse(holder)
|
initSignResponse(holder)
|
||||||
initDepersonalizeResponse(holder)
|
initDepersonalizeResponse(holder)
|
||||||
|
initCreateWalletResponse(holder)
|
||||||
|
initPurgeWalletResponse(holder)
|
||||||
|
initReadIssuerDataResponse(holder)
|
||||||
|
initWriteIssuerDataResponse(holder)
|
||||||
|
initReadIssuerExtraDataResponse(holder)
|
||||||
|
initReadUserDataResponse(holder)
|
||||||
|
initWriteUserDataResponse(holder)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initCard(holder: MainResourceHolder) {
|
private fun initCard(holder: MainResourceHolder) {
|
||||||
|
|
@ -65,4 +69,46 @@ class ResponseResources {
|
||||||
private fun initDepersonalizeResponse(holder: MainResourceHolder) {
|
private fun initDepersonalizeResponse(holder: MainResourceHolder) {
|
||||||
holder.register(DepersonalizeId.isSuccess, Resources(R.string.response_depersonalize_is_success, R.string.info_response_depersonalize_is_success))
|
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))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -16,5 +16,9 @@ class TlvResources {
|
||||||
private fun initScan(holder: MainResourceHolder) {
|
private fun initScan(holder: MainResourceHolder) {
|
||||||
holder.register(TlvId.CardId, Resources(R.string.tlv_card_id, R.string.info_tlv_card_id))
|
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.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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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 inflater = LayoutInflater.from(where.context)
|
||||||
val view = inflater.inflate(R.layout.w_card_incoming_param, where, false)
|
val view = inflater.inflate(R.layout.w_card_incoming_param, where, false)
|
||||||
where.plusAssign(view)
|
where.plusAssign(view)
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@ class ParameterWidget(
|
||||||
btnAction.setText(getResNameId(ActionType.Scan))
|
btnAction.setText(getResNameId(ActionType.Scan))
|
||||||
toggleActionBtnVisibility()
|
toggleActionBtnVisibility()
|
||||||
initDescriptionWidget()
|
initDescriptionWidget()
|
||||||
|
parent.tag = Id.getTag(typedItem.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun changeParamValue(data: Any?, silent: Boolean = true) {
|
fun changeParamValue(data: Any?, silent: Boolean = true) {
|
||||||
|
|
|
||||||
|
|
@ -8,4 +8,8 @@ import com.tangem.devkit._arch.structure.Id
|
||||||
enum class TlvId : Id {
|
enum class TlvId : Id {
|
||||||
CardId,
|
CardId,
|
||||||
TransactionOutHash,
|
TransactionOutHash,
|
||||||
|
IssuerData,
|
||||||
|
Counter,
|
||||||
|
UserData,
|
||||||
|
ProtectedUserData
|
||||||
}
|
}
|
||||||
|
|
@ -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() }
|
||||||
|
}
|
||||||
|
|
@ -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() }
|
||||||
|
}
|
||||||
|
|
@ -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() }
|
||||||
|
}
|
||||||
|
|
@ -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() }
|
||||||
|
}
|
||||||
|
|
@ -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() }
|
||||||
|
}
|
||||||
|
|
@ -22,13 +22,13 @@ enum class BlockId : PersonalizationId {
|
||||||
Pins,
|
Pins,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class CardNumber : PersonalizationId {
|
enum class CardNumberId : PersonalizationId {
|
||||||
Series,
|
Series,
|
||||||
Number,
|
Number,
|
||||||
BatchId,
|
BatchId,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class Common : PersonalizationId {
|
enum class CommonId : PersonalizationId {
|
||||||
Curve,
|
Curve,
|
||||||
Blockchain,
|
Blockchain,
|
||||||
BlockchainCustom,
|
BlockchainCustom,
|
||||||
|
|
@ -36,7 +36,7 @@ enum class Common : PersonalizationId {
|
||||||
CreateWallet,
|
CreateWallet,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class SigningMethod : PersonalizationId {
|
enum class SigningMethodId : PersonalizationId {
|
||||||
SignTx,
|
SignTx,
|
||||||
SignTxRaw,
|
SignTxRaw,
|
||||||
SignValidatedTx,
|
SignValidatedTx,
|
||||||
|
|
@ -46,7 +46,7 @@ enum class SigningMethod : PersonalizationId {
|
||||||
SignExternal,
|
SignExternal,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class SignHashExProp : PersonalizationId {
|
enum class SignHashExPropId : PersonalizationId {
|
||||||
PinLessFloorLimit,
|
PinLessFloorLimit,
|
||||||
CryptoExKey,
|
CryptoExKey,
|
||||||
RequireTerminalCertSig,
|
RequireTerminalCertSig,
|
||||||
|
|
@ -54,21 +54,21 @@ enum class SignHashExProp : PersonalizationId {
|
||||||
CheckPin3,
|
CheckPin3,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class Token : PersonalizationId {
|
enum class TokenId : PersonalizationId {
|
||||||
ItsToken,
|
ItsToken,
|
||||||
Symbol,
|
Symbol,
|
||||||
ContractAddress,
|
ContractAddress,
|
||||||
Decimal
|
Decimal
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class ProductMask : PersonalizationId {
|
enum class ProductMaskId : PersonalizationId {
|
||||||
Note,
|
Note,
|
||||||
Tag,
|
Tag,
|
||||||
IdCard,
|
IdCard,
|
||||||
IdIssuerCard
|
IdIssuerCard
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class SettingsMask : PersonalizationId {
|
enum class SettingsMaskId : PersonalizationId {
|
||||||
IsReusable,
|
IsReusable,
|
||||||
NeedActivation,
|
NeedActivation,
|
||||||
ForbidPurge,
|
ForbidPurge,
|
||||||
|
|
@ -87,12 +87,12 @@ enum class SettingsMask : PersonalizationId {
|
||||||
RestrictOverwriteExtraIssuerData,
|
RestrictOverwriteExtraIssuerData,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class SettingsMaskProtocolEnc : PersonalizationId {
|
enum class SettingsMaskProtocolEncId : PersonalizationId {
|
||||||
AllowUnencrypted,
|
AllowUnencrypted,
|
||||||
AllowStaticEncryption
|
AllowStaticEncryption
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class SettingsMaskNdef : PersonalizationId {
|
enum class SettingsMaskNdefId : PersonalizationId {
|
||||||
UseNdef,
|
UseNdef,
|
||||||
DynamicNdef,
|
DynamicNdef,
|
||||||
DisablePrecomputedNdef,
|
DisablePrecomputedNdef,
|
||||||
|
|
@ -101,7 +101,7 @@ enum class SettingsMaskNdef : PersonalizationId {
|
||||||
Uri,
|
Uri,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class Pins : PersonalizationId {
|
enum class PinsId : PersonalizationId {
|
||||||
Pin,
|
Pin,
|
||||||
Pin2,
|
Pin2,
|
||||||
Pin3,
|
Pin3,
|
||||||
|
|
|
||||||
|
|
@ -14,63 +14,63 @@ class ConfigValuesHolder : BaseTypedHolder<Id, Value>() {
|
||||||
|
|
||||||
// All registered association values can't be objects
|
// All registered association values can't be objects
|
||||||
fun init(default: PersonalizationConfig) {
|
fun init(default: PersonalizationConfig) {
|
||||||
register(CardNumber.Series, Value(default.series))
|
register(CardNumberId.Series, Value(default.series))
|
||||||
register(CardNumber.Number, Value(default.startNumber))
|
register(CardNumberId.Number, Value(default.startNumber))
|
||||||
register(CardNumber.BatchId, Value(default.cardData.batch))
|
register(CardNumberId.BatchId, Value(default.cardData.batch))
|
||||||
register(Common.Curve, Value(default.curveID, Helper.listOfCurves()))
|
register(CommonId.Curve, Value(default.curveID, Helper.listOfCurves()))
|
||||||
register(Common.Blockchain, Value(default.cardData.blockchain, Helper.listOfBlockchain()))
|
register(CommonId.Blockchain, Value(default.cardData.blockchain, Helper.listOfBlockchain()))
|
||||||
register(Common.BlockchainCustom, Value(default.blockchainCustom))
|
register(CommonId.BlockchainCustom, Value(default.blockchainCustom))
|
||||||
register(Common.MaxSignatures, Value(default.MaxSignatures))
|
register(CommonId.MaxSignatures, Value(default.MaxSignatures))
|
||||||
register(Common.CreateWallet, Value(default.createWallet))
|
register(CommonId.CreateWallet, Value(default.createWallet))
|
||||||
register(SigningMethod.SignTx, Value(default.SigningMethod0))
|
register(SigningMethodId.SignTx, Value(default.SigningMethod0))
|
||||||
register(SigningMethod.SignTxRaw, Value(default.SigningMethod1))
|
register(SigningMethodId.SignTxRaw, Value(default.SigningMethod1))
|
||||||
register(SigningMethod.SignValidatedTx, Value(default.SigningMethod2))
|
register(SigningMethodId.SignValidatedTx, Value(default.SigningMethod2))
|
||||||
register(SigningMethod.SignValidatedTxRaw, Value(default.SigningMethod3))
|
register(SigningMethodId.SignValidatedTxRaw, Value(default.SigningMethod3))
|
||||||
register(SigningMethod.SignValidatedTxIssuer, Value(default.SigningMethod4))
|
register(SigningMethodId.SignValidatedTxIssuer, Value(default.SigningMethod4))
|
||||||
register(SigningMethod.SignValidatedTxRawIssuer, Value(default.SigningMethod5))
|
register(SigningMethodId.SignValidatedTxRawIssuer, Value(default.SigningMethod5))
|
||||||
register(SigningMethod.SignExternal, Value(default.SigningMethod6))
|
register(SigningMethodId.SignExternal, Value(default.SigningMethod6))
|
||||||
register(SignHashExProp.PinLessFloorLimit, Value(default.pinLessFloorLimit))
|
register(SignHashExPropId.PinLessFloorLimit, Value(default.pinLessFloorLimit))
|
||||||
register(SignHashExProp.CryptoExKey, Value(default.hexCrExKey))
|
register(SignHashExPropId.CryptoExKey, Value(default.hexCrExKey))
|
||||||
register(SignHashExProp.RequireTerminalCertSig, Value(default.requireTerminalCertSignature))
|
register(SignHashExPropId.RequireTerminalCertSig, Value(default.requireTerminalCertSignature))
|
||||||
register(SignHashExProp.RequireTerminalTxSig, Value(default.requireTerminalTxSignature))
|
register(SignHashExPropId.RequireTerminalTxSig, Value(default.requireTerminalTxSignature))
|
||||||
register(SignHashExProp.CheckPin3, Value(default.checkPIN3onCard))
|
register(SignHashExPropId.CheckPin3, Value(default.checkPIN3onCard))
|
||||||
register(Token.ItsToken, Value(default.itsToken))
|
register(TokenId.ItsToken, Value(default.itsToken))
|
||||||
register(Token.Symbol, Value(default.cardData.token_symbol))
|
register(TokenId.Symbol, Value(default.cardData.token_symbol))
|
||||||
register(Token.ContractAddress, Value(default.cardData.token_contract_address))
|
register(TokenId.ContractAddress, Value(default.cardData.token_contract_address))
|
||||||
register(Token.Decimal, Value(default.cardData.token_decimal))
|
register(TokenId.Decimal, Value(default.cardData.token_decimal))
|
||||||
register(ProductMask.Note, Value(default.cardData.product_note))
|
register(ProductMaskId.Note, Value(default.cardData.product_note))
|
||||||
register(ProductMask.Tag, Value(default.cardData.product_tag))
|
register(ProductMaskId.Tag, Value(default.cardData.product_tag))
|
||||||
register(ProductMask.IdCard, Value(default.cardData.product_id_card))
|
register(ProductMaskId.IdCard, Value(default.cardData.product_id_card))
|
||||||
register(ProductMask.IdIssuerCard, Value(default.cardData.product_id_issuer))
|
register(ProductMaskId.IdIssuerCard, Value(default.cardData.product_id_issuer))
|
||||||
register(SettingsMask.IsReusable, Value(default.isReusable))
|
register(SettingsMaskId.IsReusable, Value(default.isReusable))
|
||||||
register(SettingsMask.NeedActivation, Value(default.useActivation))
|
register(SettingsMaskId.NeedActivation, Value(default.useActivation))
|
||||||
register(SettingsMask.ForbidPurge, Value(default.forbidPurgeWallet))
|
register(SettingsMaskId.ForbidPurge, Value(default.forbidPurgeWallet))
|
||||||
register(SettingsMask.AllowSelectBlockchain, Value(default.allowSelectBlockchain))
|
register(SettingsMaskId.AllowSelectBlockchain, Value(default.allowSelectBlockchain))
|
||||||
register(SettingsMask.UseBlock, Value(default.useBlock))
|
register(SettingsMaskId.UseBlock, Value(default.useBlock))
|
||||||
register(SettingsMask.OneApdu, Value(default.useOneCommandAtTime))
|
register(SettingsMaskId.OneApdu, Value(default.useOneCommandAtTime))
|
||||||
register(SettingsMask.UseCvc, Value(default.useCVC))
|
register(SettingsMaskId.UseCvc, Value(default.useCVC))
|
||||||
register(SettingsMask.AllowSwapPin, Value(default.allowSwapPIN))
|
register(SettingsMaskId.AllowSwapPin, Value(default.allowSwapPIN))
|
||||||
register(SettingsMask.AllowSwapPin2, Value(default.allowSwapPIN2))
|
register(SettingsMaskId.AllowSwapPin2, Value(default.allowSwapPIN2))
|
||||||
register(SettingsMask.ForbidDefaultPin, Value(default.forbidDefaultPIN))
|
register(SettingsMaskId.ForbidDefaultPin, Value(default.forbidDefaultPIN))
|
||||||
register(SettingsMask.SmartSecurityDelay, Value(default.smartSecurityDelay))
|
register(SettingsMaskId.SmartSecurityDelay, Value(default.smartSecurityDelay))
|
||||||
register(SettingsMask.ProtectIssuerDataAgainstReplay, Value(default.protectIssuerDataAgainstReplay))
|
register(SettingsMaskId.ProtectIssuerDataAgainstReplay, Value(default.protectIssuerDataAgainstReplay))
|
||||||
register(SettingsMask.SkipSecurityDelayIfValidated, Value(default.skipSecurityDelayIfValidatedByIssuer))
|
register(SettingsMaskId.SkipSecurityDelayIfValidated, Value(default.skipSecurityDelayIfValidatedByIssuer))
|
||||||
register(SettingsMask.SkipPin2CvcIfValidated, Value(default.skipCheckPIN2andCVCIfValidatedByIssuer))
|
register(SettingsMaskId.SkipPin2CvcIfValidated, Value(default.skipCheckPIN2andCVCIfValidatedByIssuer))
|
||||||
register(SettingsMask.SkipSecurityDelayOnLinkedTerminal, Value(default.skipSecurityDelayIfValidatedByLinkedTerminal))
|
register(SettingsMaskId.SkipSecurityDelayOnLinkedTerminal, Value(default.skipSecurityDelayIfValidatedByLinkedTerminal))
|
||||||
register(SettingsMask.RestrictOverwriteExtraIssuerData, Value(default.restrictOverwriteIssuerDataEx))
|
register(SettingsMaskId.RestrictOverwriteExtraIssuerData, Value(default.restrictOverwriteIssuerDataEx))
|
||||||
register(SettingsMaskProtocolEnc.AllowUnencrypted, Value(default.protocolAllowUnencrypted))
|
register(SettingsMaskProtocolEncId.AllowUnencrypted, Value(default.protocolAllowUnencrypted))
|
||||||
register(SettingsMaskProtocolEnc.AllowStaticEncryption, Value(default.protocolAllowStaticEncryption))
|
register(SettingsMaskProtocolEncId.AllowStaticEncryption, Value(default.protocolAllowStaticEncryption))
|
||||||
register(SettingsMaskNdef.UseNdef, Value(default.useNDEF))
|
register(SettingsMaskNdefId.UseNdef, Value(default.useNDEF))
|
||||||
register(SettingsMaskNdef.DynamicNdef, Value(default.useDynamicNDEF))
|
register(SettingsMaskNdefId.DynamicNdef, Value(default.useDynamicNDEF))
|
||||||
register(SettingsMaskNdef.DisablePrecomputedNdef, Value(default.disablePrecomputedNDEF))
|
register(SettingsMaskNdefId.DisablePrecomputedNdef, Value(default.disablePrecomputedNDEF))
|
||||||
register(SettingsMaskNdef.Aar, Value(default.aar, Helper.aarList()))
|
register(SettingsMaskNdefId.Aar, Value(default.aar, Helper.aarList()))
|
||||||
register(SettingsMaskNdef.AarCustom, Value(default.aarCustom))
|
register(SettingsMaskNdefId.AarCustom, Value(default.aarCustom))
|
||||||
register(SettingsMaskNdef.Uri, Value(default.uri))
|
register(SettingsMaskNdefId.Uri, Value(default.uri))
|
||||||
register(Pins.Pin, Value(default.PIN))
|
register(PinsId.Pin, Value(default.PIN))
|
||||||
register(Pins.Pin2, Value(default.PIN2))
|
register(PinsId.Pin2, Value(default.PIN2))
|
||||||
register(Pins.Pin3, Value(default.PIN3))
|
register(PinsId.Pin3, Value(default.PIN3))
|
||||||
register(Pins.Cvc, Value(default.CVC))
|
register(PinsId.Cvc, Value(default.CVC))
|
||||||
register(Pins.PauseBeforePin2, Value(default.pauseBeforePIN2, Helper.pauseBeforePin()))
|
register(PinsId.PauseBeforePin2, Value(default.pauseBeforePIN2, Helper.pauseBeforePin()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,37 +11,37 @@ class ItemTypes {
|
||||||
BlockId.SettingsMaskNdef, BlockId.Pins
|
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(
|
val boolList = mutableListOf(
|
||||||
Common.CreateWallet, SigningMethod.SignTx, SigningMethod.SignTxRaw, SigningMethod.SignValidatedTx,
|
CommonId.CreateWallet, SigningMethodId.SignTx, SigningMethodId.SignTxRaw, SigningMethodId.SignValidatedTx,
|
||||||
SigningMethod.SignValidatedTxRaw, SigningMethod.SignValidatedTxIssuer,
|
SigningMethodId.SignValidatedTxRaw, SigningMethodId.SignValidatedTxIssuer,
|
||||||
SigningMethod.SignValidatedTxRawIssuer, SigningMethod.SignExternal, SignHashExProp.RequireTerminalCertSig,
|
SigningMethodId.SignValidatedTxRawIssuer, SigningMethodId.SignExternal, SignHashExPropId.RequireTerminalCertSig,
|
||||||
SignHashExProp.RequireTerminalTxSig, SignHashExProp.CheckPin3, Token.ItsToken,
|
SignHashExPropId.RequireTerminalTxSig, SignHashExPropId.CheckPin3, TokenId.ItsToken,
|
||||||
ProductMask.Note, ProductMask.Tag, ProductMask.IdCard, ProductMask.IdIssuerCard, SettingsMask.IsReusable, SettingsMask.NeedActivation,
|
ProductMaskId.Note, ProductMaskId.Tag, ProductMaskId.IdCard, ProductMaskId.IdIssuerCard, SettingsMaskId.IsReusable, SettingsMaskId.NeedActivation,
|
||||||
SettingsMask.ForbidPurge, SettingsMask.AllowSelectBlockchain, SettingsMask.UseBlock, SettingsMask.OneApdu,
|
SettingsMaskId.ForbidPurge, SettingsMaskId.AllowSelectBlockchain, SettingsMaskId.UseBlock, SettingsMaskId.OneApdu,
|
||||||
SettingsMask.UseCvc, SettingsMask.AllowSwapPin, SettingsMask.AllowSwapPin2, SettingsMask.ForbidDefaultPin,
|
SettingsMaskId.UseCvc, SettingsMaskId.AllowSwapPin, SettingsMaskId.AllowSwapPin2, SettingsMaskId.ForbidDefaultPin,
|
||||||
SettingsMask.SmartSecurityDelay, SettingsMask.ProtectIssuerDataAgainstReplay,
|
SettingsMaskId.SmartSecurityDelay, SettingsMaskId.ProtectIssuerDataAgainstReplay,
|
||||||
SettingsMask.SkipSecurityDelayIfValidated, SettingsMask.SkipPin2CvcIfValidated,
|
SettingsMaskId.SkipSecurityDelayIfValidated, SettingsMaskId.SkipPin2CvcIfValidated,
|
||||||
SettingsMask.SkipSecurityDelayOnLinkedTerminal, SettingsMask.RestrictOverwriteExtraIssuerData,
|
SettingsMaskId.SkipSecurityDelayOnLinkedTerminal, SettingsMaskId.RestrictOverwriteExtraIssuerData,
|
||||||
SettingsMaskProtocolEnc.AllowUnencrypted, SettingsMaskProtocolEnc.AllowStaticEncryption,
|
SettingsMaskProtocolEncId.AllowUnencrypted, SettingsMaskProtocolEncId.AllowStaticEncryption,
|
||||||
SettingsMaskNdef.UseNdef, SettingsMaskNdef.DynamicNdef, SettingsMaskNdef.DisablePrecomputedNdef
|
SettingsMaskNdefId.UseNdef, SettingsMaskNdefId.DynamicNdef, SettingsMaskNdefId.DisablePrecomputedNdef
|
||||||
)
|
)
|
||||||
|
|
||||||
val editTextList = mutableListOf(
|
val editTextList = mutableListOf(
|
||||||
CardNumber.Series, CardNumber.BatchId, Common.BlockchainCustom, SignHashExProp.CryptoExKey, Token.Symbol,
|
CardNumberId.Series, CardNumberId.BatchId, CommonId.BlockchainCustom, SignHashExPropId.CryptoExKey, TokenId.Symbol,
|
||||||
Token.ContractAddress, Pins.Pin, Pins.Pin2, Pins.Pin3, Pins.Cvc, SettingsMaskNdef.AarCustom, SettingsMaskNdef.Uri
|
TokenId.ContractAddress, PinsId.Pin, PinsId.Pin2, PinsId.Pin3, PinsId.Cvc, SettingsMaskNdefId.AarCustom, SettingsMaskNdefId.Uri
|
||||||
)
|
)
|
||||||
|
|
||||||
val numberList = mutableListOf(
|
val numberList = mutableListOf(
|
||||||
CardNumber.Number, Common.MaxSignatures, SignHashExProp.PinLessFloorLimit, Token.Decimal
|
CardNumberId.Number, CommonId.MaxSignatures, SignHashExPropId.PinLessFloorLimit, TokenId.Decimal
|
||||||
)
|
)
|
||||||
|
|
||||||
val hiddenList = mutableListOf<Id>(
|
val hiddenList = mutableListOf<Id>(
|
||||||
CardNumber.Series, CardNumber.BatchId, Pins.Pin3, SigningMethod.SignExternal,
|
CardNumberId.Series, CardNumberId.BatchId, PinsId.Pin3, SigningMethodId.SignExternal,
|
||||||
SignHashExProp.CryptoExKey, SignHashExProp.CheckPin3, SettingsMask.OneApdu,
|
SignHashExPropId.CryptoExKey, SignHashExPropId.CheckPin3, SettingsMaskId.OneApdu,
|
||||||
SettingsMask.UseBlock, SettingsMask.ProtectIssuerDataAgainstReplay,
|
SettingsMaskId.UseBlock, SettingsMaskId.ProtectIssuerDataAgainstReplay,
|
||||||
SignHashExProp.RequireTerminalCertSig, SignHashExProp.RequireTerminalTxSig
|
SignHashExPropId.RequireTerminalCertSig, SignHashExPropId.RequireTerminalTxSig
|
||||||
)
|
)
|
||||||
|
|
||||||
val oftenUsedList = listOf<Id>(
|
val oftenUsedList = listOf<Id>(
|
||||||
|
|
@ -56,11 +56,11 @@ class ItemTypes {
|
||||||
// BlockId.SettingsMaskProtocolEnc,
|
// BlockId.SettingsMaskProtocolEnc,
|
||||||
BlockId.SettingsMaskNdef,
|
BlockId.SettingsMaskNdef,
|
||||||
// BlockId.Pins,
|
// BlockId.Pins,
|
||||||
Common.Curve,
|
CommonId.Curve,
|
||||||
Common.Blockchain,
|
CommonId.Blockchain,
|
||||||
Common.BlockchainCustom,
|
CommonId.BlockchainCustom,
|
||||||
// Common.MaxSignatures,
|
// Common.MaxSignatures,
|
||||||
Common.CreateWallet,
|
CommonId.CreateWallet,
|
||||||
// SigningMethod.SignTx,
|
// SigningMethod.SignTx,
|
||||||
// SigningMethod.SignTxRaw,
|
// SigningMethod.SignTxRaw,
|
||||||
// SigningMethod.SignValidatedTx,
|
// SigningMethod.SignValidatedTx,
|
||||||
|
|
@ -79,10 +79,10 @@ class ItemTypes {
|
||||||
// Token.Symbol,
|
// Token.Symbol,
|
||||||
// Token.ContractAddress,
|
// Token.ContractAddress,
|
||||||
// Token.Decimal,
|
// Token.Decimal,
|
||||||
ProductMask.Note,
|
ProductMaskId.Note,
|
||||||
ProductMask.Tag,
|
ProductMaskId.Tag,
|
||||||
ProductMask.IdCard,
|
ProductMaskId.IdCard,
|
||||||
ProductMask.IdIssuerCard,
|
ProductMaskId.IdIssuerCard,
|
||||||
// SettingsMask.IsReusable,
|
// SettingsMask.IsReusable,
|
||||||
// SettingsMask.NeedActivation,
|
// SettingsMask.NeedActivation,
|
||||||
// SettingsMask.ForbidPurge,
|
// SettingsMask.ForbidPurge,
|
||||||
|
|
@ -104,14 +104,14 @@ class ItemTypes {
|
||||||
// SettingsMaskNdef.UseNdef,
|
// SettingsMaskNdef.UseNdef,
|
||||||
// SettingsMaskNdef.DynamicNdef,
|
// SettingsMaskNdef.DynamicNdef,
|
||||||
// SettingsMaskNdef.DisablePrecomputedNdef,
|
// SettingsMaskNdef.DisablePrecomputedNdef,
|
||||||
SettingsMaskNdef.Aar,
|
SettingsMaskNdefId.Aar,
|
||||||
SettingsMaskNdef.AarCustom,
|
SettingsMaskNdefId.AarCustom,
|
||||||
SettingsMaskNdef.Uri,
|
SettingsMaskNdefId.Uri,
|
||||||
// Pins.Pin,
|
// Pins.Pin,
|
||||||
// Pins.Pin2,
|
// Pins.Pin2,
|
||||||
// Pins.Pin3,
|
// Pins.Pin3,
|
||||||
// Pins.Cvc,
|
// Pins.Cvc,
|
||||||
Pins.PauseBeforePin2
|
PinsId.PauseBeforePin2
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,63 +50,63 @@ class ItemsToPersonalizationConfig : ItemsToModel<PersonalizationConfig> {
|
||||||
|
|
||||||
private fun createModel(): PersonalizationConfig {
|
private fun createModel(): PersonalizationConfig {
|
||||||
val export = PersonalizationConfig()
|
val export = PersonalizationConfig()
|
||||||
export.series = getTyped(CardNumber.Series)
|
export.series = getTyped(CardNumberId.Series)
|
||||||
export.startNumber = getTyped(CardNumber.Number)
|
export.startNumber = getTyped(CardNumberId.Number)
|
||||||
export.cardData.batch = getTyped(CardNumber.BatchId)
|
export.cardData.batch = getTyped(CardNumberId.BatchId)
|
||||||
export.curveID = getTyped(Common.Curve)
|
export.curveID = getTyped(CommonId.Curve)
|
||||||
export.cardData.blockchain = getTyped(Common.Blockchain)
|
export.cardData.blockchain = getTyped(CommonId.Blockchain)
|
||||||
export.blockchainCustom = getTyped(Common.BlockchainCustom)
|
export.blockchainCustom = getTyped(CommonId.BlockchainCustom)
|
||||||
export.MaxSignatures = getTyped(Common.MaxSignatures)
|
export.MaxSignatures = getTyped(CommonId.MaxSignatures)
|
||||||
export.createWallet = getTyped(Common.CreateWallet)
|
export.createWallet = getTyped(CommonId.CreateWallet)
|
||||||
export.SigningMethod0 = getTyped(SigningMethod.SignTx)
|
export.SigningMethod0 = getTyped(SigningMethodId.SignTx)
|
||||||
export.SigningMethod1 = getTyped(SigningMethod.SignTxRaw)
|
export.SigningMethod1 = getTyped(SigningMethodId.SignTxRaw)
|
||||||
export.SigningMethod2 = getTyped(SigningMethod.SignValidatedTx)
|
export.SigningMethod2 = getTyped(SigningMethodId.SignValidatedTx)
|
||||||
export.SigningMethod3 = getTyped(SigningMethod.SignValidatedTxRaw)
|
export.SigningMethod3 = getTyped(SigningMethodId.SignValidatedTxRaw)
|
||||||
export.SigningMethod4 = getTyped(SigningMethod.SignValidatedTxIssuer)
|
export.SigningMethod4 = getTyped(SigningMethodId.SignValidatedTxIssuer)
|
||||||
export.SigningMethod5 = getTyped(SigningMethod.SignValidatedTxRawIssuer)
|
export.SigningMethod5 = getTyped(SigningMethodId.SignValidatedTxRawIssuer)
|
||||||
export.SigningMethod6 = getTyped(SigningMethod.SignExternal)
|
export.SigningMethod6 = getTyped(SigningMethodId.SignExternal)
|
||||||
export.pinLessFloorLimit = getTyped(SignHashExProp.PinLessFloorLimit)
|
export.pinLessFloorLimit = getTyped(SignHashExPropId.PinLessFloorLimit)
|
||||||
export.hexCrExKey = getTyped(SignHashExProp.CryptoExKey)
|
export.hexCrExKey = getTyped(SignHashExPropId.CryptoExKey)
|
||||||
export.requireTerminalCertSignature = getTyped(SignHashExProp.RequireTerminalCertSig)
|
export.requireTerminalCertSignature = getTyped(SignHashExPropId.RequireTerminalCertSig)
|
||||||
export.requireTerminalTxSignature = getTyped(SignHashExProp.RequireTerminalTxSig)
|
export.requireTerminalTxSignature = getTyped(SignHashExPropId.RequireTerminalTxSig)
|
||||||
export.checkPIN3onCard = getTyped(SignHashExProp.CheckPin3)
|
export.checkPIN3onCard = getTyped(SignHashExPropId.CheckPin3)
|
||||||
export.itsToken = getTyped(Token.ItsToken)
|
export.itsToken = getTyped(TokenId.ItsToken)
|
||||||
export.cardData.token_symbol = getTyped(Token.Symbol)
|
export.cardData.token_symbol = getTyped(TokenId.Symbol)
|
||||||
export.cardData.token_contract_address = getTyped(Token.ContractAddress)
|
export.cardData.token_contract_address = getTyped(TokenId.ContractAddress)
|
||||||
export.cardData.token_decimal = getTyped(Token.Decimal)
|
export.cardData.token_decimal = getTyped(TokenId.Decimal)
|
||||||
export.cardData = export.cardData.apply { this.product_note = getTyped(ProductMask.Note) }
|
export.cardData = export.cardData.apply { this.product_note = getTyped(ProductMaskId.Note) }
|
||||||
export.cardData = export.cardData.apply { this.product_tag = getTyped(ProductMask.Tag) }
|
export.cardData = export.cardData.apply { this.product_tag = getTyped(ProductMaskId.Tag) }
|
||||||
export.cardData = export.cardData.apply { this.product_id_card = getTyped(ProductMask.IdCard) }
|
export.cardData = export.cardData.apply { this.product_id_card = getTyped(ProductMaskId.IdCard) }
|
||||||
export.cardData = export.cardData.apply { this.product_id_issuer = getTyped(ProductMask.IdIssuerCard) }
|
export.cardData = export.cardData.apply { this.product_id_issuer = getTyped(ProductMaskId.IdIssuerCard) }
|
||||||
export.isReusable = getTyped(SettingsMask.IsReusable)
|
export.isReusable = getTyped(SettingsMaskId.IsReusable)
|
||||||
export.useActivation = getTyped(SettingsMask.NeedActivation)
|
export.useActivation = getTyped(SettingsMaskId.NeedActivation)
|
||||||
export.forbidPurgeWallet = getTyped(SettingsMask.ForbidPurge)
|
export.forbidPurgeWallet = getTyped(SettingsMaskId.ForbidPurge)
|
||||||
export.allowSelectBlockchain = getTyped(SettingsMask.AllowSelectBlockchain)
|
export.allowSelectBlockchain = getTyped(SettingsMaskId.AllowSelectBlockchain)
|
||||||
export.useBlock = getTyped(SettingsMask.UseBlock)
|
export.useBlock = getTyped(SettingsMaskId.UseBlock)
|
||||||
export.useOneCommandAtTime = getTyped(SettingsMask.OneApdu)
|
export.useOneCommandAtTime = getTyped(SettingsMaskId.OneApdu)
|
||||||
export.useCVC = getTyped(SettingsMask.UseCvc)
|
export.useCVC = getTyped(SettingsMaskId.UseCvc)
|
||||||
export.allowSwapPIN = getTyped(SettingsMask.AllowSwapPin)
|
export.allowSwapPIN = getTyped(SettingsMaskId.AllowSwapPin)
|
||||||
export.allowSwapPIN2 = getTyped(SettingsMask.AllowSwapPin2)
|
export.allowSwapPIN2 = getTyped(SettingsMaskId.AllowSwapPin2)
|
||||||
export.forbidDefaultPIN = getTyped(SettingsMask.ForbidDefaultPin)
|
export.forbidDefaultPIN = getTyped(SettingsMaskId.ForbidDefaultPin)
|
||||||
export.smartSecurityDelay = getTyped(SettingsMask.SmartSecurityDelay)
|
export.smartSecurityDelay = getTyped(SettingsMaskId.SmartSecurityDelay)
|
||||||
export.protectIssuerDataAgainstReplay = getTyped(SettingsMask.ProtectIssuerDataAgainstReplay)
|
export.protectIssuerDataAgainstReplay = getTyped(SettingsMaskId.ProtectIssuerDataAgainstReplay)
|
||||||
export.skipSecurityDelayIfValidatedByIssuer = getTyped(SettingsMask.SkipSecurityDelayIfValidated)
|
export.skipSecurityDelayIfValidatedByIssuer = getTyped(SettingsMaskId.SkipSecurityDelayIfValidated)
|
||||||
export.skipCheckPIN2andCVCIfValidatedByIssuer = getTyped(SettingsMask.SkipPin2CvcIfValidated)
|
export.skipCheckPIN2andCVCIfValidatedByIssuer = getTyped(SettingsMaskId.SkipPin2CvcIfValidated)
|
||||||
export.skipSecurityDelayIfValidatedByLinkedTerminal = getTyped(SettingsMask.SkipSecurityDelayOnLinkedTerminal)
|
export.skipSecurityDelayIfValidatedByLinkedTerminal = getTyped(SettingsMaskId.SkipSecurityDelayOnLinkedTerminal)
|
||||||
export.restrictOverwriteIssuerDataEx = getTyped(SettingsMask.RestrictOverwriteExtraIssuerData)
|
export.restrictOverwriteIssuerDataEx = getTyped(SettingsMaskId.RestrictOverwriteExtraIssuerData)
|
||||||
export.protocolAllowUnencrypted = getTyped(SettingsMaskProtocolEnc.AllowUnencrypted)
|
export.protocolAllowUnencrypted = getTyped(SettingsMaskProtocolEncId.AllowUnencrypted)
|
||||||
export.protocolAllowStaticEncryption = getTyped(SettingsMaskProtocolEnc.AllowStaticEncryption)
|
export.protocolAllowStaticEncryption = getTyped(SettingsMaskProtocolEncId.AllowStaticEncryption)
|
||||||
export.useNDEF = getTyped(SettingsMaskNdef.UseNdef)
|
export.useNDEF = getTyped(SettingsMaskNdefId.UseNdef)
|
||||||
export.useDynamicNDEF = getTyped(SettingsMaskNdef.DynamicNdef)
|
export.useDynamicNDEF = getTyped(SettingsMaskNdefId.DynamicNdef)
|
||||||
export.disablePrecomputedNDEF = getTyped(SettingsMaskNdef.DisablePrecomputedNdef)
|
export.disablePrecomputedNDEF = getTyped(SettingsMaskNdefId.DisablePrecomputedNdef)
|
||||||
export.aar = getTyped(SettingsMaskNdef.Aar)
|
export.aar = getTyped(SettingsMaskNdefId.Aar)
|
||||||
export.aarCustom = getTyped(SettingsMaskNdef.AarCustom)
|
export.aarCustom = getTyped(SettingsMaskNdefId.AarCustom)
|
||||||
export.uri = getTyped(SettingsMaskNdef.Uri)
|
export.uri = getTyped(SettingsMaskNdefId.Uri)
|
||||||
export.PIN = getTyped(Pins.Pin)
|
export.PIN = getTyped(PinsId.Pin)
|
||||||
export.PIN2 = getTyped(Pins.Pin2)
|
export.PIN2 = getTyped(PinsId.Pin2)
|
||||||
export.PIN3 = getTyped(Pins.Pin3)
|
export.PIN3 = getTyped(PinsId.Pin3)
|
||||||
export.CVC = getTyped(Pins.Cvc)
|
export.CVC = getTyped(PinsId.Cvc)
|
||||||
export.pauseBeforePIN2 = getTyped(Pins.PauseBeforePin2)
|
export.pauseBeforePIN2 = getTyped(PinsId.PauseBeforePin2)
|
||||||
return export
|
return export
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -154,9 +154,9 @@ class PersonalizationConfigToItems : ModelToItems<PersonalizationConfig> {
|
||||||
private fun cardNumber(): ItemGroup {
|
private fun cardNumber(): ItemGroup {
|
||||||
val block = createGroup(BlockId.CardNumber)
|
val block = createGroup(BlockId.CardNumber)
|
||||||
mutableListOf(
|
mutableListOf(
|
||||||
CardNumber.Series,
|
CardNumberId.Series,
|
||||||
CardNumber.Number,
|
CardNumberId.Number,
|
||||||
CardNumber.BatchId
|
CardNumberId.BatchId
|
||||||
).forEach { createItem(block, it as Id) }
|
).forEach { createItem(block, it as Id) }
|
||||||
return block
|
return block
|
||||||
}
|
}
|
||||||
|
|
@ -164,12 +164,12 @@ class PersonalizationConfigToItems : ModelToItems<PersonalizationConfig> {
|
||||||
private fun common(): ItemGroup {
|
private fun common(): ItemGroup {
|
||||||
val block = createGroup(BlockId.Common)
|
val block = createGroup(BlockId.Common)
|
||||||
mutableListOf(
|
mutableListOf(
|
||||||
Common.Blockchain,
|
CommonId.Blockchain,
|
||||||
Common.BlockchainCustom,
|
CommonId.BlockchainCustom,
|
||||||
Common.Curve,
|
CommonId.Curve,
|
||||||
Common.MaxSignatures,
|
CommonId.MaxSignatures,
|
||||||
Common.CreateWallet,
|
CommonId.CreateWallet,
|
||||||
Pins.PauseBeforePin2
|
PinsId.PauseBeforePin2
|
||||||
).forEach { createItem(block, it as Id) }
|
).forEach { createItem(block, it as Id) }
|
||||||
return block
|
return block
|
||||||
}
|
}
|
||||||
|
|
@ -177,13 +177,13 @@ class PersonalizationConfigToItems : ModelToItems<PersonalizationConfig> {
|
||||||
private fun signingMethod(): ItemGroup {
|
private fun signingMethod(): ItemGroup {
|
||||||
val block = createGroup(BlockId.SigningMethod)
|
val block = createGroup(BlockId.SigningMethod)
|
||||||
mutableListOf(
|
mutableListOf(
|
||||||
SigningMethod.SignTx,
|
SigningMethodId.SignTx,
|
||||||
SigningMethod.SignTxRaw,
|
SigningMethodId.SignTxRaw,
|
||||||
SigningMethod.SignValidatedTx,
|
SigningMethodId.SignValidatedTx,
|
||||||
SigningMethod.SignValidatedTxRaw,
|
SigningMethodId.SignValidatedTxRaw,
|
||||||
SigningMethod.SignValidatedTxIssuer,
|
SigningMethodId.SignValidatedTxIssuer,
|
||||||
SigningMethod.SignValidatedTxRawIssuer,
|
SigningMethodId.SignValidatedTxRawIssuer,
|
||||||
SigningMethod.SignExternal
|
SigningMethodId.SignExternal
|
||||||
).forEach { createItem(block, it) }
|
).forEach { createItem(block, it) }
|
||||||
return block
|
return block
|
||||||
}
|
}
|
||||||
|
|
@ -191,11 +191,11 @@ class PersonalizationConfigToItems : ModelToItems<PersonalizationConfig> {
|
||||||
private fun signHashExProperties(): ItemGroup {
|
private fun signHashExProperties(): ItemGroup {
|
||||||
val block = createGroup(BlockId.SignHashExProp)
|
val block = createGroup(BlockId.SignHashExProp)
|
||||||
mutableListOf(
|
mutableListOf(
|
||||||
SignHashExProp.PinLessFloorLimit,
|
SignHashExPropId.PinLessFloorLimit,
|
||||||
SignHashExProp.CryptoExKey,
|
SignHashExPropId.CryptoExKey,
|
||||||
SignHashExProp.RequireTerminalCertSig,
|
SignHashExPropId.RequireTerminalCertSig,
|
||||||
SignHashExProp.RequireTerminalTxSig,
|
SignHashExPropId.RequireTerminalTxSig,
|
||||||
SignHashExProp.CheckPin3
|
SignHashExPropId.CheckPin3
|
||||||
).forEach { createItem(block, it) }
|
).forEach { createItem(block, it) }
|
||||||
return block
|
return block
|
||||||
}
|
}
|
||||||
|
|
@ -203,10 +203,10 @@ class PersonalizationConfigToItems : ModelToItems<PersonalizationConfig> {
|
||||||
private fun token(): ItemGroup {
|
private fun token(): ItemGroup {
|
||||||
val block = createGroup(BlockId.Token)
|
val block = createGroup(BlockId.Token)
|
||||||
mutableListOf(
|
mutableListOf(
|
||||||
Token.ItsToken,
|
TokenId.ItsToken,
|
||||||
Token.Symbol,
|
TokenId.Symbol,
|
||||||
Token.ContractAddress,
|
TokenId.ContractAddress,
|
||||||
Token.Decimal
|
TokenId.Decimal
|
||||||
).forEach { createItem(block, it) }
|
).forEach { createItem(block, it) }
|
||||||
return block
|
return block
|
||||||
}
|
}
|
||||||
|
|
@ -214,10 +214,10 @@ class PersonalizationConfigToItems : ModelToItems<PersonalizationConfig> {
|
||||||
private fun productMask(): ItemGroup {
|
private fun productMask(): ItemGroup {
|
||||||
val block = createGroup(BlockId.ProdMask)
|
val block = createGroup(BlockId.ProdMask)
|
||||||
mutableListOf(
|
mutableListOf(
|
||||||
ProductMask.Note,
|
ProductMaskId.Note,
|
||||||
ProductMask.Tag,
|
ProductMaskId.Tag,
|
||||||
ProductMask.IdCard,
|
ProductMaskId.IdCard,
|
||||||
ProductMask.IdIssuerCard
|
ProductMaskId.IdIssuerCard
|
||||||
).forEach { createItem(block, it) }
|
).forEach { createItem(block, it) }
|
||||||
return block
|
return block
|
||||||
}
|
}
|
||||||
|
|
@ -225,22 +225,22 @@ class PersonalizationConfigToItems : ModelToItems<PersonalizationConfig> {
|
||||||
private fun settingsMask(): ItemGroup {
|
private fun settingsMask(): ItemGroup {
|
||||||
val block = createGroup(BlockId.SettingsMask)
|
val block = createGroup(BlockId.SettingsMask)
|
||||||
mutableListOf(
|
mutableListOf(
|
||||||
SettingsMask.IsReusable,
|
SettingsMaskId.IsReusable,
|
||||||
SettingsMask.NeedActivation,
|
SettingsMaskId.NeedActivation,
|
||||||
SettingsMask.ForbidPurge,
|
SettingsMaskId.ForbidPurge,
|
||||||
SettingsMask.AllowSelectBlockchain,
|
SettingsMaskId.AllowSelectBlockchain,
|
||||||
SettingsMask.UseBlock,
|
SettingsMaskId.UseBlock,
|
||||||
SettingsMask.OneApdu,
|
SettingsMaskId.OneApdu,
|
||||||
SettingsMask.UseCvc,
|
SettingsMaskId.UseCvc,
|
||||||
SettingsMask.AllowSwapPin,
|
SettingsMaskId.AllowSwapPin,
|
||||||
SettingsMask.AllowSwapPin2,
|
SettingsMaskId.AllowSwapPin2,
|
||||||
SettingsMask.ForbidDefaultPin,
|
SettingsMaskId.ForbidDefaultPin,
|
||||||
SettingsMask.SmartSecurityDelay,
|
SettingsMaskId.SmartSecurityDelay,
|
||||||
SettingsMask.ProtectIssuerDataAgainstReplay,
|
SettingsMaskId.ProtectIssuerDataAgainstReplay,
|
||||||
SettingsMask.SkipSecurityDelayIfValidated,
|
SettingsMaskId.SkipSecurityDelayIfValidated,
|
||||||
SettingsMask.SkipPin2CvcIfValidated,
|
SettingsMaskId.SkipPin2CvcIfValidated,
|
||||||
SettingsMask.SkipSecurityDelayOnLinkedTerminal,
|
SettingsMaskId.SkipSecurityDelayOnLinkedTerminal,
|
||||||
SettingsMask.RestrictOverwriteExtraIssuerData
|
SettingsMaskId.RestrictOverwriteExtraIssuerData
|
||||||
).forEach { createItem(block, it) }
|
).forEach { createItem(block, it) }
|
||||||
return block
|
return block
|
||||||
}
|
}
|
||||||
|
|
@ -248,8 +248,8 @@ class PersonalizationConfigToItems : ModelToItems<PersonalizationConfig> {
|
||||||
private fun settingsMaskProtocolEnc(): ItemGroup {
|
private fun settingsMaskProtocolEnc(): ItemGroup {
|
||||||
val block = createGroup(BlockId.SettingsMaskProtocolEnc)
|
val block = createGroup(BlockId.SettingsMaskProtocolEnc)
|
||||||
mutableListOf(
|
mutableListOf(
|
||||||
SettingsMaskProtocolEnc.AllowUnencrypted,
|
SettingsMaskProtocolEncId.AllowUnencrypted,
|
||||||
SettingsMaskProtocolEnc.AllowStaticEncryption
|
SettingsMaskProtocolEncId.AllowStaticEncryption
|
||||||
).forEach { createItem(block, it) }
|
).forEach { createItem(block, it) }
|
||||||
return block
|
return block
|
||||||
}
|
}
|
||||||
|
|
@ -257,12 +257,12 @@ class PersonalizationConfigToItems : ModelToItems<PersonalizationConfig> {
|
||||||
private fun settingsMaskNdef(): ItemGroup {
|
private fun settingsMaskNdef(): ItemGroup {
|
||||||
val block = createGroup(BlockId.SettingsMaskNdef)
|
val block = createGroup(BlockId.SettingsMaskNdef)
|
||||||
mutableListOf(
|
mutableListOf(
|
||||||
SettingsMaskNdef.UseNdef,
|
SettingsMaskNdefId.UseNdef,
|
||||||
SettingsMaskNdef.DynamicNdef,
|
SettingsMaskNdefId.DynamicNdef,
|
||||||
SettingsMaskNdef.DisablePrecomputedNdef,
|
SettingsMaskNdefId.DisablePrecomputedNdef,
|
||||||
SettingsMaskNdef.Aar,
|
SettingsMaskNdefId.Aar,
|
||||||
SettingsMaskNdef.AarCustom,
|
SettingsMaskNdefId.AarCustom,
|
||||||
SettingsMaskNdef.Uri
|
SettingsMaskNdefId.Uri
|
||||||
).forEach { createItem(block, it) }
|
).forEach { createItem(block, it) }
|
||||||
return block
|
return block
|
||||||
}
|
}
|
||||||
|
|
@ -270,10 +270,10 @@ class PersonalizationConfigToItems : ModelToItems<PersonalizationConfig> {
|
||||||
private fun pins(): ItemGroup {
|
private fun pins(): ItemGroup {
|
||||||
val block = createGroup(BlockId.Pins)
|
val block = createGroup(BlockId.Pins)
|
||||||
mutableListOf(
|
mutableListOf(
|
||||||
Pins.Pin,
|
PinsId.Pin,
|
||||||
Pins.Pin2,
|
PinsId.Pin2,
|
||||||
Pins.Pin3,
|
PinsId.Pin3,
|
||||||
Pins.Cvc
|
PinsId.Cvc
|
||||||
).forEach { createItem(block, it) }
|
).forEach { createItem(block, it) }
|
||||||
return block
|
return block
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import com.tangem.KeyPair
|
||||||
import com.tangem.commands.personalization.entities.Acquirer
|
import com.tangem.commands.personalization.entities.Acquirer
|
||||||
import com.tangem.commands.personalization.entities.Issuer
|
import com.tangem.commands.personalization.entities.Issuer
|
||||||
import com.tangem.commands.personalization.entities.Manufacturer
|
import com.tangem.commands.personalization.entities.Manufacturer
|
||||||
|
import com.tangem.common.extensions.hexToBytes
|
||||||
|
|
||||||
/**
|
/**
|
||||||
[REDACTED_AUTHOR]
|
[REDACTED_AUTHOR]
|
||||||
|
|
@ -18,12 +19,14 @@ interface DefaultPersonalizationParams {
|
||||||
name = name,
|
name = name,
|
||||||
id = name + "\u0000",
|
id = name + "\u0000",
|
||||||
dataKeyPair = KeyPair(
|
dataKeyPair = KeyPair(
|
||||||
"".toByteArray(),
|
("045f16bd1d2eafe463e62a335a09e6b2bbcbd04452526885cb679fc4d27af1bd22f553c7deefb54fd3d4f" +
|
||||||
"11121314151617184771ED81F2BACF57479E4735EB1405083927372D40DA9E92".toByteArray()
|
"361d14e6dc3f11b7d4ea183250a60720ebdf9e110cd26").hexToBytes(),
|
||||||
|
"11121314151617184771ED81F2BACF57479E4735EB1405083927372D40DA9E92".hexToBytes()
|
||||||
),
|
),
|
||||||
transactionKeyPair = KeyPair(
|
transactionKeyPair = KeyPair(
|
||||||
"".toByteArray(),
|
("0484c5192e9bfa6c528a344f442137a92b89ea835bfef1d04cb4362eb906b508c5889846cfea71ba6dc7b" +
|
||||||
"11121314151617184771ED81F2BACF57479E4735EB1405081918171615141312".toByteArray()
|
"3120c2208df9c46127d3d85cb5cfbd1479e97133a39d8").hexToBytes(),
|
||||||
|
"11121314151617184771ED81F2BACF57479E4735EB1405081918171615141312".hexToBytes()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -34,8 +37,9 @@ interface DefaultPersonalizationParams {
|
||||||
name = name,
|
name = name,
|
||||||
id = name + "\u0000",
|
id = name + "\u0000",
|
||||||
keyPair = KeyPair(
|
keyPair = KeyPair(
|
||||||
"".toByteArray(),
|
("0456ad1a82b22bcb40c38fd08939f87e6b80e40dec5b3bdb351c55fcd709e47f9fb2ed00c2304d3a9" +
|
||||||
"21222324252627284771ED81F2BACF57479E4735EB1405083927372D40DA9E92".toByteArray()
|
"86f79c5ae0ac3c84e88da46dc8f513b7542c716af8c9a2daf").hexToBytes(),
|
||||||
|
"21222324252627284771ED81F2BACF57479E4735EB1405083927372D40DA9E92".hexToBytes()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import com.google.android.material.textfield.TextInputEditText
|
||||||
import com.google.android.material.textfield.TextInputLayout
|
import com.google.android.material.textfield.TextInputLayout
|
||||||
import com.tangem.devkit.R
|
import com.tangem.devkit.R
|
||||||
import com.tangem.devkit._arch.structure.impl.NumberItem
|
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.addInputFilter
|
||||||
import ru.dev.gbixahue.eu4d.lib.android._android.views.moveCursorToEnd
|
import ru.dev.gbixahue.eu4d.lib.android._android.views.moveCursorToEnd
|
||||||
import ru.dev.gbixahue.eu4d.lib.kotlin.stringOf
|
import ru.dev.gbixahue.eu4d.lib.kotlin.stringOf
|
||||||
|
|
@ -39,7 +39,7 @@ class NumberWidget(
|
||||||
tilItem.hint = getName()
|
tilItem.hint = getName()
|
||||||
|
|
||||||
//TODO: remove from Widget
|
//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.setText(stringOf(typedItem.getTypedData()))
|
||||||
etItem.addTextChangedListener(watcher)
|
etItem.addTextChangedListener(watcher)
|
||||||
|
|
|
||||||
|
|
@ -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() }
|
||||||
|
}
|
||||||
|
|
@ -53,4 +53,38 @@ enum class SignId : ResponseId {
|
||||||
|
|
||||||
enum class DepersonalizeId: ResponseId {
|
enum class DepersonalizeId: ResponseId {
|
||||||
isSuccess
|
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
|
||||||
}
|
}
|
||||||
|
|
@ -2,9 +2,7 @@ package com.tangem.devkit.ucase.variants.responses
|
||||||
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import com.tangem.commands.Card
|
import com.tangem.commands.*
|
||||||
import com.tangem.commands.CommandResponse
|
|
||||||
import com.tangem.commands.SignResponse
|
|
||||||
import com.tangem.commands.personalization.DepersonalizeResponse
|
import com.tangem.commands.personalization.DepersonalizeResponse
|
||||||
import com.tangem.devkit.R
|
import com.tangem.devkit.R
|
||||||
import com.tangem.devkit._arch.structure.abstraction.Item
|
import com.tangem.devkit._arch.structure.abstraction.Item
|
||||||
|
|
@ -44,6 +42,14 @@ class ResponseViewModel : ViewModel() {
|
||||||
is Card -> R.string.fg_name_response_personalization
|
is Card -> R.string.fg_name_response_personalization
|
||||||
is SignResponse -> R.string.fg_name_response_sign
|
is SignResponse -> R.string.fg_name_response_sign
|
||||||
is DepersonalizeResponse -> R.string.fg_name_response_depersonalization
|
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
|
else -> R.string.unknown
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package com.tangem.devkit.ucase.variants.responses.converter
|
package com.tangem.devkit.ucase.variants.responses.converter
|
||||||
|
|
||||||
import com.tangem.commands.Card
|
import com.tangem.commands.*
|
||||||
import com.tangem.commands.SignResponse
|
|
||||||
import com.tangem.commands.personalization.DepersonalizeResponse
|
import com.tangem.commands.personalization.DepersonalizeResponse
|
||||||
import ru.dev.gbixahue.eu4d.lib.kotlin.common.BaseTypedHolder
|
import ru.dev.gbixahue.eu4d.lib.kotlin.common.BaseTypedHolder
|
||||||
import java.lang.reflect.Type
|
import java.lang.reflect.Type
|
||||||
|
|
@ -12,5 +11,12 @@ class ConvertersStore : BaseTypedHolder<Type, Any>() {
|
||||||
register(SignResponse::class.java, SignResponseConverter())
|
register(SignResponse::class.java, SignResponseConverter())
|
||||||
register(Card::class.java, CardConverter())
|
register(Card::class.java, CardConverter())
|
||||||
register(DepersonalizeResponse::class.java, DepersonalizeResponseConverter())
|
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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
package com.tangem.devkit.ucase.variants.responses.converter
|
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.commands.personalization.DepersonalizeResponse
|
||||||
import com.tangem.devkit._arch.structure.abstraction.Item
|
import com.tangem.devkit._arch.structure.abstraction.Item
|
||||||
import com.tangem.devkit._arch.structure.impl.TextItem
|
import com.tangem.devkit._arch.structure.impl.TextItem
|
||||||
import com.tangem.devkit.ucase.variants.responses.DepersonalizeId
|
import com.tangem.devkit.ucase.variants.responses.*
|
||||||
import com.tangem.devkit.ucase.variants.responses.SignId
|
|
||||||
import ru.dev.gbixahue.eu4d.lib.kotlin.stringOf
|
import ru.dev.gbixahue.eu4d.lib.kotlin.stringOf
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -27,4 +26,74 @@ class DepersonalizeResponseConverter : BaseResponseConverter<DepersonalizeRespon
|
||||||
override fun convert(from: DepersonalizeResponse): List<Item> {
|
override fun convert(from: DepersonalizeResponse): List<Item> {
|
||||||
return listOf(TextItem(DepersonalizeId.isSuccess, stringOf(from.success)))
|
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)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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() }
|
||||||
|
}
|
||||||
|
|
@ -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() }
|
||||||
|
}
|
||||||
|
|
@ -85,51 +85,51 @@
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/nav_issuer_read_data"
|
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"
|
android:label="@string/action_issuer_read_data"
|
||||||
tools:layout="@layout/fg_action_issuer_read_data" />
|
tools:layout="@layout/fg_base_action_layout" />
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/nav_issuer_write_data"
|
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"
|
android:label="@string/action_issuer_write_data"
|
||||||
tools:layout="@layout/fg_action_issuer_write_data" />
|
tools:layout="@layout/fg_base_action_layout" />
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/nav_issuer_read_ex_data"
|
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"
|
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
|
<fragment
|
||||||
android:id="@+id/nav_issuer_write_ex_data"
|
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"
|
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
|
<fragment
|
||||||
android:id="@+id/nav_user_read_data"
|
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"
|
android:label="@string/action_user_read_data"
|
||||||
tools:layout="@layout/fg_action_user_read_data" />
|
tools:layout="@layout/fg_base_action_layout" />
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/nav_user_write_data"
|
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"
|
android:label="@string/action_user_write_data"
|
||||||
tools:layout="@layout/fg_action_user_write_data" />
|
tools:layout="@layout/fg_base_action_layout" />
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/nav_wallet_create"
|
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"
|
android:label="@string/action_wallet_create"
|
||||||
tools:layout="@layout/fg_action_wallet_create" />
|
tools:layout="@layout/fg_base_action_layout" />
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/nav_wallet_purge"
|
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"
|
android:label="@string/action_wallet_purge"
|
||||||
tools:layout="@layout/fg_action_wallet_purge" />
|
tools:layout="@layout/fg_base_action_layout" />
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/nav_card_response"
|
android:id="@+id/nav_card_response"
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,17 @@
|
||||||
<string name="error_nothing_to_load">Nothing to load</string>
|
<string name="error_nothing_to_load">Nothing to load</string>
|
||||||
|
|
||||||
<string name="fg_name_entry_point">@string/app_name</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_scan">Read Response</string>
|
||||||
<string name="fg_name_response_sign">Sign 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_personalization">Personalization Response</string>
|
||||||
<string name="fg_name_response_depersonalization">Depersonalization 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>
|
<string name="switch_description">Docs</string>
|
||||||
|
|
|
||||||
|
|
@ -5,27 +5,28 @@
|
||||||
<string name="action_card_sign">Sign</string>
|
<string name="action_card_sign">Sign</string>
|
||||||
<string name="action_personalize">Personalize</string>
|
<string name="action_personalize">Personalize</string>
|
||||||
<string name="action_depersonalize">Depersonalize</string>
|
<string name="action_depersonalize">Depersonalize</string>
|
||||||
<string name="action_wallet_create">Create wallet</string>
|
<string name="action_wallet_create">Create Wallet</string>
|
||||||
<string name="action_wallet_purge">Purge wallet</string>
|
<string name="action_wallet_purge">Purge Wallet</string>
|
||||||
<string name="action_issuer_read_data">Read issuer data</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_write_data">Write Issuer Data</string>
|
||||||
<string name="action_issuer_read_ex_data">Read issuer extra 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_issuer_write_ex_data">Write Issuer Extra Data</string>
|
||||||
<string name="action_user_read_data">Read user 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_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_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_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_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.
|
<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>
|
\nCommand available on SDK cards only</string>
|
||||||
<string name="info_action_wallet_create">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">SomeDescription</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">SomeDescription</string>
|
<string name="info_action_issuer_read_data">This command returns 512-byte Issuer Data field and its issuer’s signature.</string>
|
||||||
<string name="info_action_issuer_write_data">SomeDescription</string>
|
<string name="info_action_issuer_write_data">This command writes 512-byte Issuer Data field and its issuer’s signature to the card.</string>
|
||||||
<string name="info_action_issuer_read_ex_data">SomeDescription</string>
|
<string name="info_action_issuer_read_ex_data">This command retrieves Issuer Extra Data field and its issuer’s signature.</string>
|
||||||
<string name="info_action_issuer_write_ex_data">SomeDescription</string>
|
<string name="info_action_issuer_write_ex_data">This command writes Issuer Extra Data field and its issuer’s signature to the card.</string>
|
||||||
<string name="info_action_user_read_data">SomeDescription</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">SomeDescription</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>
|
</resources>
|
||||||
|
|
@ -155,4 +155,27 @@
|
||||||
|
|
||||||
<string name="info_response_depersonalize_is_success">Is success</string>
|
<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 user’s App (confirmed by PIN2)</string>
|
||||||
|
<string name="info_response_user_data_counter">Counter initialized by user’s App and increased on every signing of new transaction</string>
|
||||||
|
<string name="info_response_user_data_protected_counter">Counter initialized by user’s App (confirmed by PIN2) and increased on every signing of new transaction</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
@ -3,8 +3,16 @@
|
||||||
|
|
||||||
<string name="tlv_card_id">Card Id (CID)</string>
|
<string name="tlv_card_id">Card Id (CID)</string>
|
||||||
<string name="tlv_transaction_out_hash">Hash to sign</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_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_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>
|
</resources>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue