Updated on 2026-08-14
This commit is contained in:
parent
40e7ee5764
commit
792ca79ebe
9 changed files with 176 additions and 28 deletions
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
)
|
||||
|
|
@ -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()
|
||||
}
|
||||
|
|
@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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 {
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue