Updated on 2026-08-14

This commit is contained in:
Tangem 2019-12-16 14:40:19 +03:00
parent 40e7ee5764
commit 792ca79ebe
9 changed files with 176 additions and 28 deletions

View file

@ -26,7 +26,7 @@ android {
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
// implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation project(':tangem-core')
implementation project(':tangem-sdk')
@ -34,12 +34,13 @@ dependencies {
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.core:core-ktx:1.1.0'
implementation 'com.squareup.retrofit2:retrofit:2.6.0'
implementation 'com.squareup.retrofit2:retrofit:2.6.2'
implementation 'com.squareup.retrofit2:converter-moshi:2.6.0'
implementation 'com.squareup.moshi:moshi:1.9.2'
implementation 'org.bitcoinj:bitcoinj-core:0.15.2'
implementation 'com.github.komputing:kethereum:0.79.5'
implementation 'com.github.stellar:java-stellar-sdk:0.11.0'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.5.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'

View file

@ -2,6 +2,10 @@ package com.tangem.blockchain.common
import com.tangem.blockchain.bitcoin.BitcoinAddressFactory
import com.tangem.blockchain.bitcoin.BitcoinAddressValidator
import com.tangem.blockchain.eth.EthereumAddressFactory
import com.tangem.blockchain.eth.EthereumAddressValidator
import com.tangem.blockchain.stellar.StellarAddressFactory
import com.tangem.blockchain.stellar.StellarAddressValidator
import java.math.BigDecimal
enum class Blockchain(
@ -31,12 +35,12 @@ enum class Blockchain(
Unknown -> throw Exception("unsupported blockchain")
Bitcoin -> BitcoinAddressFactory.makeAddress(cardPublicKey)
BitcoinTestnet -> BitcoinAddressFactory.makeAddress(cardPublicKey, testNet = true)
// Ethereum -> EthereumAddressFactory.makeAddress(cardPublicKey)
// Rootstock -> RootstockAddressFactory.makeAddress(cardPublicKey)
// Cardano -> CardanoAddressFactory.makeAddress(cardPublicKey)
// Ripple -> RippleAddressFactory.makeAddress(cardPublicKey)
// Binance -> BinanceAddressFactory.makeAddress(cardPublicKey)
// Stellar -> StellarAddressFactory.makeAddress(cardPublicKey)
Ethereum -> EthereumAddressFactory.makeAddress(cardPublicKey)
Rootstock -> RootstockAddressFactory.makeAddress(cardPublicKey)
Cardano -> CardanoAddressFactory.makeAddress(cardPublicKey)
Ripple -> RippleAddressFactory.makeAddress(cardPublicKey)
Binance -> BinanceAddressFactory.makeAddress(cardPublicKey)
Stellar -> StellarAddressFactory.makeAddress(cardPublicKey)
}
}
@ -45,12 +49,12 @@ enum class Blockchain(
Unknown -> throw Exception("unsupported blockchain")
Bitcoin -> BitcoinAddressValidator.validate(address)
BitcoinTestnet -> BitcoinAddressValidator.validate(address, testNet = true)
// Ethereum -> EthereumAddressValidator.validate(address)
// Rootstock -> RootstockAddressValidator.validate(address)
// Cardano -> CardanoAddressValidator.validate(address)
// Ripple -> RippleAddressValidator.validate(address)
// Binance -> BinanceAddressValidator.validate(address)
// Stellar -> StellarAddressValidator.validate(address)
Ethereum -> EthereumAddressValidator.validate(address)
Rootstock -> RootstockAddressValidator.validate(address)
Cardano -> CardanoAddressValidator.validate(address)
Ripple -> RippleAddressValidator.validate(address)
Binance -> BinanceAddressValidator.validate(address)
Stellar -> StellarAddressValidator.validate(address)
}
}

View file

@ -18,12 +18,14 @@ class WalletConfig(
)
data class Amount(
val type: AmountType = AmountType.Coin,
val currencySymbol: String,
val value: BigDecimal
)
val value: BigDecimal?,
val address: String,
val decimals: Int,
val type: AmountType = AmountType.Coin
)
data class Transaction(
data class TransactionData(
val amount: Amount,
val fee: Amount?,
val sourceAddress: String,
@ -34,6 +36,6 @@ enum class AmountType { Coin, Token, Reserve }
enum class ValidationError { WrongAmount, WrongFee, WrongTotal }
interface TransactionValidator{
interface TransactionValidator {
fun validateTransaction(amount: Amount, fee: Amount?): EnumSet<ValidationError>
}

View file

@ -1,5 +1,8 @@
package com.tangem.blockchain.common
import com.tangem.commands.SignResponse
import com.tangem.tasks.TaskEvent
interface WalletManager {
var wallet: Wallet
val blockchain: Blockchain
@ -7,15 +10,18 @@ interface WalletManager {
fun update()
}
interface TransactionBuilder {
fun getEstimateSize(transaction: Transaction): Int
interface TransactionEstimator {
fun getEstimateSize(transactionData: TransactionData): Int
}
interface TransactionSender {
fun send(transaction: Transaction, signer: TransactionSigner)
fun send(transactionData: TransactionData, signer: TransactionSigner)
}
interface TransactionSigner
interface TransactionSigner {
fun sign(hashes: Array<ByteArray>, cardId: String,
callback: (result: TaskEvent<SignResponse>) -> Unit)
}
interface FeeProvider {
fun getFee(amount: Amount, source: String, destination: String): List<Amount>

View file

@ -0,0 +1,54 @@
package com.tangem.blockchain.common
import com.tangem.blockchain.bitcoin.BitcoinWalletManager
import com.tangem.blockchain.eth.EthereumWalletManager
import com.tangem.blockchain.stellar.StellarWalletManager
import com.tangem.commands.Card
object WalletManagerFactory {
fun makeWalletManager(card: Card): WalletManager? {
val walletPublicKey = card.walletPublicKey ?: return null
val blockchainName = card.cardData?.blockchainName ?: return null
when {
blockchainName.contains("btc") || blockchainName.contains("bitcoin") -> {
return BitcoinWalletManager(
cardId = card.cardId,
walletPublicKey = walletPublicKey,
walletConfig = WalletConfig(true, true),
isTestNet = blockchainName.contains("test"))
}
blockchainName.contains("eth") -> {
return EthereumWalletManager(
cardId = card.cardId,
walletPublicKey = walletPublicKey,
walletConfig = WalletConfig(true, true))
}
blockchainName.contains("xlm") -> {
val token = getToken(card)
return StellarWalletManager(
cardId = card.cardId,
walletPublicKey = walletPublicKey,
walletConfig = WalletConfig(true, token == null),
token = token,
isTestNet = blockchainName.contains("test"))
}
else -> return null
}
}
private fun getToken(card: Card): Token? {
val symbol = card.cardData?.tokenSymbol ?: return null
val contractAddress = card.cardData?.tokenContractAddress ?: return null
val decimals = card.cardData?.tokenDecimal ?: return null
return Token(symbol, contractAddress, decimals)
}
}
data class Token(
val symbol: String,
val contractAddress: String,
val decimals: Int
)

View file

@ -0,0 +1,15 @@
package com.tangem.blockchain.eth
import org.kethereum.crypto.toAddress
import org.kethereum.functions.isValid
import org.kethereum.model.Address
import org.kethereum.model.PublicKey
object EthereumAddressFactory {
fun makeAddress(cardPublicKey: ByteArray, testNet: Boolean = false): String =
PublicKey(cardPublicKey).toAddress().hex
}
object EthereumAddressValidator {
fun validate(address: String, testNet: Boolean = false): Boolean = Address(address).isValid()
}

View file

@ -0,0 +1,55 @@
package com.tangem.blockchain.eth
import com.tangem.blockchain.common.*
import com.tangem.blockchain.wallets.CurrencyWallet
import com.tangem.tasks.TaskEvent
class EthereumWalletManager(
private val cardId: String,
private val walletPublicKey: ByteArray,
walletConfig: WalletConfig
) : WalletManager,
TransactionEstimator,
TransactionSender,
FeeProvider {
override val blockchain: Blockchain = Blockchain.Ethereum
private val address = blockchain.makeAddress(walletPublicKey)
override var wallet: Wallet = CurrencyWallet(walletConfig, address)
override fun update() {
}
override fun getEstimateSize(transactionData: TransactionData): Int {
}
override fun send(transactionData: TransactionData, signer: TransactionSigner) {
val builder = EthereumTransactionBuilder()
val hashes = builder.buildToSign(transactionData, walletPublicKey)
signer.sign(hashes.toTypedArray(), cardId) {
when (it) {
is TaskEvent.Event -> builder.buildToSend(transactionData, it.data.signature)
}
}
}
override fun getFee(amount: Amount, source: String, destination: String): List<Amount> {
}
}
class EthereumTransactionBuilder {
fun buildToSign(transactionData: TransactionData, publicKey: ByteArray): List<ByteArray> {
}
fun buildToSend(transactionData: TransactionData, signature: ByteArray) {
}
}

View file

@ -0,0 +1,11 @@
package com.tangem.blockchain.extensions
import org.spongycastle.crypto.digests.RIPEMD160Digest
fun ByteArray.calculateRipemd160(): ByteArray {
val digest = RIPEMD160Digest()
digest.update(this, 0, this.size)
val out = ByteArray(20)
digest.doFinal(out, 0)
return out
}

View file

@ -6,10 +6,10 @@ import java.util.*
class CurrencyWallet(
override val config: WalletConfig,
override val address: String,
override val exploreUrl: String?,
override val shareUrl: String?,
val pendingTransactions: List<Transaction> = listOf(),
val balances: List<Amount> = listOf(),
override val exploreUrl: String? = null,
override val shareUrl: String? = null,
val pendingTransactions: List<TransactionData> = listOf(),
val balances: MutableList<Amount> = mutableListOf(),
val isTestnet: Boolean = false
) : Wallet, TransactionValidator {