Updated on 2026-08-14
This commit is contained in:
parent
bd67edae50
commit
2f79026f4f
7 changed files with 30 additions and 19 deletions
|
|
@ -9,6 +9,7 @@ public enum Blockchain {
|
|||
Unknown("", "", 1.0, R.drawable.ic_logo_unknown, ""),
|
||||
Bitcoin("BTC", "BTC", 100000000.0, R.drawable.ic_logo_bitcoin, "Bitcoin"),
|
||||
BitcoinTestNet("BTC/test", "BTC", 100000000.0, R.drawable.ic_logo_bitcoin_testnet, "Bitcoin Testnet"),
|
||||
BitcoinDual("BTC/dual", "BTC", 100000000.0, R.drawable.ic_logo_bitcoin, "Bitcoin"),
|
||||
Ethereum("ETH", "ETH", 1.0, R.drawable.ic_logo_ethereum, "Ethereum"),
|
||||
EthereumId("ETH/ID", "ETH", 1.0, R.drawable.ic_logo_ethereum, "Ethereum ID"),
|
||||
EthereumTestNet("ETH/test", "ETH", 1.0, R.drawable.ic_logo_ethereum_testnet, "Ethereum Testnet"),
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ public class ServerApiBlockcypher {
|
|||
network = "test3";
|
||||
}
|
||||
if (blockchainID.equals(Blockchain.Token.getID())) blockchain = "eth";
|
||||
if (blockchainID.equals(Blockchain.BitcoinDual.getID())) blockchain = "btc";
|
||||
|
||||
switch (method) {
|
||||
case BLOCKCYPHER_ADDRESS:
|
||||
|
|
|
|||
|
|
@ -364,7 +364,7 @@ class IdFragment : BaseFragment(), NfcAdapter.ReaderCallback,
|
|||
updateViews()
|
||||
|
||||
// Bitcoin, Litecoin, BitcoinCash, Stellar
|
||||
if (ctx.blockchain == Blockchain.Bitcoin || ctx.blockchain == Blockchain.BitcoinTestNet ||
|
||||
if (ctx.blockchain == Blockchain.Bitcoin || ctx.blockchain == Blockchain.BitcoinTestNet || ctx.blockchain == Blockchain.BitcoinDual ||
|
||||
ctx.blockchain == Blockchain.Litecoin || ctx.blockchain == Blockchain.BitcoinCash ||
|
||||
ctx.blockchain == Blockchain.Stellar || ctx.blockchain == Blockchain.StellarTestNet || ctx.blockchain == Blockchain.StellarAsset) {
|
||||
ctx.coinData.setIsBalanceEqual(true)
|
||||
|
|
|
|||
|
|
@ -707,7 +707,7 @@ class LoadedWalletFragment : BaseFragment(), NavigationResultListener, NfcAdapte
|
|||
updateViews()
|
||||
|
||||
// Bitcoin, Litecoin, BitcoinCash, Stellar
|
||||
if (ctx.blockchain == Blockchain.Bitcoin || ctx.blockchain == Blockchain.BitcoinTestNet ||
|
||||
if (ctx.blockchain == Blockchain.Bitcoin || ctx.blockchain == Blockchain.BitcoinTestNet || ctx.blockchain == Blockchain.BitcoinDual ||
|
||||
ctx.blockchain == Blockchain.Litecoin || ctx.blockchain == Blockchain.BitcoinCash ||
|
||||
ctx.blockchain == Blockchain.Stellar || ctx.blockchain == Blockchain.StellarTestNet || ctx.blockchain == Blockchain.StellarAsset) {
|
||||
ctx.coinData.setIsBalanceEqual(true)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import com.tangem.data.Blockchain
|
|||
import com.tangem.wallet.bch.BtcCashEngine
|
||||
import com.tangem.wallet.binance.BinanceEngine
|
||||
import com.tangem.wallet.btc.BtcEngine
|
||||
import com.tangem.wallet.btcmultisig.BtcMultisigEngine
|
||||
import com.tangem.wallet.cardano.CardanoData
|
||||
import com.tangem.wallet.cardano.CardanoEngine
|
||||
import com.tangem.wallet.ducatus.DucatusEngine
|
||||
|
|
@ -56,6 +57,7 @@ object CoinEngineFactory {
|
|||
Blockchain.Eos -> EosEngine()
|
||||
Blockchain.Ducatus -> DucatusEngine()
|
||||
Blockchain.Tezos -> TezosEngine()
|
||||
Blockchain.BitcoinDual -> BtcMultisigEngine()
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
|
@ -101,6 +103,8 @@ object CoinEngineFactory {
|
|||
DucatusEngine(context)
|
||||
else if (Blockchain.Tezos == context.blockchain)
|
||||
TezosEngine(context)
|
||||
else if (Blockchain.BitcoinDual == context.blockchain)
|
||||
BtcMultisigEngine(context)
|
||||
else
|
||||
return null
|
||||
} catch (e: Exception) {
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ public class BtcEngine extends CoinEngine {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (ctx.getBlockchain() != Blockchain.BitcoinTestNet && ctx.getBlockchain() != Blockchain.Bitcoin) {
|
||||
if (ctx.getBlockchain() != Blockchain.BitcoinTestNet && ctx.getBlockchain() != Blockchain.Bitcoin && ctx.getBlockchain() != Blockchain.BitcoinDual) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -190,7 +190,7 @@ public class BtcEngine extends CoinEngine {
|
|||
}
|
||||
} else {
|
||||
try {
|
||||
if (ctx.getBlockchain() == Blockchain.Bitcoin) {
|
||||
if (ctx.getBlockchain() == Blockchain.Bitcoin || ctx.getBlockchain() == Blockchain.BitcoinDual) {
|
||||
SegwitAddress.fromBech32(new MainNetParams(), address);
|
||||
} else if (ctx.getBlockchain() == Blockchain.BitcoinTestNet) {
|
||||
SegwitAddress.fromBech32(new TestNet3Params(), address);
|
||||
|
|
@ -213,7 +213,7 @@ public class BtcEngine extends CoinEngine {
|
|||
|
||||
@Override
|
||||
public Uri getWalletExplorerUri() {
|
||||
return Uri.parse((ctx.getBlockchain() == Blockchain.Bitcoin ? "https://www.blockchain.com/btc/address/" : "https://live.blockcypher.com/btc-testnet/address/") + ctx.getCoinData().getWallet());
|
||||
return Uri.parse((ctx.getBlockchain() == Blockchain.Bitcoin || ctx.getBlockchain() == Blockchain.BitcoinDual ? "https://www.blockchain.com/btc/address/" : "https://live.blockcypher.com/btc-testnet/address/") + ctx.getCoinData().getWallet());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -5,18 +5,22 @@ import com.tangem.tangem_card.data.TangemCard
|
|||
import com.tangem.tangem_card.reader.CardProtocol.TangemException
|
||||
import com.tangem.tangem_card.tasks.SignTask
|
||||
import com.tangem.tangem_card.util.Util
|
||||
import com.tangem.wallet.TangemContext
|
||||
import com.tangem.wallet.btc.BtcEngine
|
||||
import org.bitcoinj.core.*
|
||||
import org.bitcoinj.crypto.TransactionSignature
|
||||
import org.bitcoinj.params.MainNetParams
|
||||
import org.bitcoinj.script.Script
|
||||
import org.bitcoinj.script.ScriptBuilder
|
||||
import org.bitcoinj.script.ScriptPattern
|
||||
import java.math.BigInteger
|
||||
|
||||
class BtcMultisigEngine : BtcEngine() {
|
||||
class BtcMultisigEngine : BtcEngine {
|
||||
val networkParameters = MainNetParams.get()
|
||||
|
||||
constructor(): super()
|
||||
|
||||
constructor(context: TangemContext): super(context)
|
||||
|
||||
override fun defineWallet() {
|
||||
try {
|
||||
val wallet = calculateAddress(ctx.card.walletPublicKeyRar)
|
||||
|
|
@ -28,13 +32,14 @@ class BtcMultisigEngine : BtcEngine() {
|
|||
}
|
||||
|
||||
override fun calculateAddress(compressedPublicKey: ByteArray): String? {
|
||||
val script = createMultisigOutputScript(
|
||||
mutableListOf(compressedPublicKey, ctx.card.getUserData)
|
||||
)
|
||||
val scriptHash = ScriptPattern.extractHashFromP2SH(script)
|
||||
|
||||
val address = LegacyAddress.fromScriptHash(networkParameters, scriptHash)
|
||||
return address.toBase58()
|
||||
if (ctx.card.issuerData != null && ctx.card.issuerData.size == 33) {
|
||||
val script = createMultisigOutputScript()
|
||||
val scriptHash = Utils.sha256hash160(script.program)
|
||||
val address = LegacyAddress.fromScriptHash(networkParameters, scriptHash)
|
||||
return address.toBase58()
|
||||
} else {
|
||||
return Util.byteArrayToHexString(compressedPublicKey)
|
||||
}
|
||||
}
|
||||
|
||||
override fun constructTransaction(amountValue: Amount, feeValue: Amount, IncFee: Boolean, targetAddress: String): SignTask.TransactionToSign {
|
||||
|
|
@ -78,7 +83,8 @@ class BtcMultisigEngine : BtcEngine() {
|
|||
val hashesForSign: MutableList<ByteArray> = MutableList(transaction.inputs.size) { byteArrayOf() }
|
||||
for (input in transaction.inputs) {
|
||||
val index = input.index
|
||||
hashesForSign[index] = transaction.hashForSignature(index, input.scriptBytes, Transaction.SigHash.ALL, false).bytes
|
||||
val outputScript = createMultisigOutputScript()
|
||||
hashesForSign[index] = transaction.hashForSignature(index, outputScript, Transaction.SigHash.ALL, false).bytes
|
||||
}
|
||||
return hashesForSign.toTypedArray()
|
||||
}
|
||||
|
|
@ -116,13 +122,12 @@ class BtcMultisigEngine : BtcEngine() {
|
|||
val canonicalS = ECKey.ECDSASignature(r, s).toCanonicalised().s
|
||||
val signature = TransactionSignature(r, canonicalS)
|
||||
|
||||
val outputScript = createMultisigOutputScript(
|
||||
mutableListOf(ctx.card.walletPublicKeyRar, ctx.card.getUserData)
|
||||
)
|
||||
val outputScript = createMultisigOutputScript()
|
||||
return ScriptBuilder.createP2SHMultiSigInputScript(mutableListOf(signature), outputScript)
|
||||
}
|
||||
|
||||
private fun createMultisigOutputScript(publicKeys: MutableList<ByteArray>): Script {
|
||||
private fun createMultisigOutputScript(): Script {
|
||||
val publicKeys = mutableListOf(ctx.card.walletPublicKeyRar, ctx.card.issuerData)
|
||||
publicKeys.sortWith(UnsignedBytes.lexicographicalComparator())
|
||||
val publicEcKeys =
|
||||
MutableList(publicKeys.size) { i -> ECKey.fromPublicOnly(publicKeys[i]) }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue