Skip to content

Commit

Permalink
Support Bitcoin testnet address (trustwallet#2621)
Browse files Browse the repository at this point in the history
* Support Bitcoin testnet address
* Put prefix in constant
  • Loading branch information
optout21 authored Oct 6, 2022
1 parent 61157af commit 269dd3a
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 0 deletions.
6 changes: 6 additions & 0 deletions registry.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@
"path": "m/44'/0'/0'/0/0",
"xpub": "xpub",
"xprv": "xprv"
},
{
"name": "testnet",
"path": "m/84'/1'/0'/0/0",
"xpub": "zpub",
"xprv": "zprv"
}
],
"curve": "secp256k1",
Expand Down
3 changes: 3 additions & 0 deletions src/Bitcoin/Entry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ std::string Entry::deriveAddress(TWCoinType coin, TWDerivation derivation, const
case TWDerivationLitecoinLegacy:
return Address(publicKey, p2pkh).string();

case TWDerivationBitcoinTestnet:
return SegwitAddress::createTestnetFromPublicKey(publicKey).string();

case TWDerivationBitcoinSegwit:
case TWDerivationDefault:
default:
Expand Down
6 changes: 6 additions & 0 deletions src/Bitcoin/SegwitAddress.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ class SegwitAddress {
/// Witness program.
Data witnessProgram;

// Prefix for Bitcoin Testnet Segwit addresses
static constexpr auto TestnetPrefix = "tb";

/// Determines whether a string makes a valid Bech32 address.
static bool isValid(const std::string& string);

Expand All @@ -47,6 +50,9 @@ class SegwitAddress {
/// Taproot (v>=1) is not supported by this method.
SegwitAddress(const PublicKey& publicKey, std::string hrp);

/// Create a testnet address
static SegwitAddress createTestnetFromPublicKey(const PublicKey& publicKey) { return SegwitAddress(publicKey, TestnetPrefix); }

/// Decodes a SegWit address.
///
/// \returns a tuple with the address, hrp, and a success flag.
Expand Down
42 changes: 42 additions & 0 deletions tests/Bitcoin/SegwitAddressTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include "Bech32.h"
#include "Bitcoin/SegwitAddress.h"
#include "HDWallet.h"
#include "HexCoding.h"

#include <string>
Expand Down Expand Up @@ -208,4 +209,45 @@ TEST(SegwitAddress, Equals) {
ASSERT_FALSE(addr1 == addr2);
}

TEST(SegwitAddress, TestnetAddress) {
const auto mnemonic1 = "ripple scissors kick mammal hire column oak again sun offer wealth tomorrow wagon turn fatal";
const auto passphrase = "";
const auto coin = TWCoinTypeBitcoin;
HDWallet wallet = HDWallet(mnemonic1, passphrase);

// default
{
const auto privKey = wallet.getKey(coin, TWDerivationDefault);
const auto pubKey = privKey.getPublicKey(TWPublicKeyTypeSECP256k1);
EXPECT_EQ(hex(pubKey.bytes), "02df9ef2a7a5552765178b181e1e1afdefc7849985c7dfe9647706dd4fa40df6ac");
EXPECT_EQ(SegwitAddress(pubKey, "bc").string(), "bc1qpsp72plnsqe6e2dvtsetxtww2cz36ztmfxghpd");
}

// testnet: different derivation path and hrp
{
const auto privKey = wallet.getKey(coin, TW::DerivationPath("m/84'/1'/0'/0/0"));
const auto pubKey = privKey.getPublicKey(TWPublicKeyTypeSECP256k1);
EXPECT_EQ(hex(pubKey.bytes), "03eb1a535b59f03894b99319f850c784cf4164f4de07620695c5cf0dc5c1ab2a54");
EXPECT_EQ(SegwitAddress::createTestnetFromPublicKey(pubKey).string(), "tb1qq8p994ak933c39d2jaj8n4sg598tnkhnyk5sg5");
// alternative with custom hrp
EXPECT_EQ(SegwitAddress(pubKey, "tb").string(), "tb1qq8p994ak933c39d2jaj8n4sg598tnkhnyk5sg5");
}

EXPECT_TRUE(SegwitAddress::isValid("tb1qq8p994ak933c39d2jaj8n4sg598tnkhnyk5sg5"));
}

TEST(SegwitAddress, SegwitDerivationHDWallet) {
const auto mnemonic1 = "ripple scissors kick mammal hire column oak again sun offer wealth tomorrow wagon turn fatal";
const auto passphrase = "";
const auto coin = TWCoinTypeBitcoin;
HDWallet wallet = HDWallet(mnemonic1, passphrase);

// addresses with different derivations
EXPECT_EQ(wallet.deriveAddress(coin), "bc1qpsp72plnsqe6e2dvtsetxtww2cz36ztmfxghpd");
EXPECT_EQ(wallet.deriveAddress(coin, TWDerivationDefault), "bc1qpsp72plnsqe6e2dvtsetxtww2cz36ztmfxghpd");
EXPECT_EQ(wallet.deriveAddress(coin, TWDerivationBitcoinSegwit), "bc1qpsp72plnsqe6e2dvtsetxtww2cz36ztmfxghpd");
EXPECT_EQ(wallet.deriveAddress(coin, TWDerivationBitcoinLegacy), "1GVb4mfQrvymPLz7zeZ3LnQ8sFv3NedZXe");
EXPECT_EQ(wallet.deriveAddress(coin, TWDerivationBitcoinTestnet), "tb1qq8p994ak933c39d2jaj8n4sg598tnkhnyk5sg5");
}

} // namespace TW::Bitcoin::tests

0 comments on commit 269dd3a

Please sign in to comment.