Skip to content

Commit

Permalink
Add support for Binance testnet addresses. (#2997)
Browse files Browse the repository at this point in the history
  • Loading branch information
andreibancioiu authored Mar 17, 2023
1 parent d67078d commit 27e0e57
Show file tree
Hide file tree
Showing 9 changed files with 100 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package com.trustwallet.core.app.blockchains.binance

import com.trustwallet.core.app.utils.toHexBytes
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
import wallet.core.jni.*
import com.trustwallet.core.app.utils.toHex
Expand All @@ -22,6 +24,23 @@ class TestBinanceAddress {
assertEquals("bnb1grpf0955h0ykzq3ar5nmum7y6gdfl6lxfn46h2", address.description())
}

@Test
fun testIsValid() {
assertTrue(AnyAddress.isValid("bnb12vtaxl9952zm6rwf7v8jerq74pvaf77fcmvzhw", CoinType.BINANCE));

assertFalse(AnyAddress.isValid("bad1devga6q804tx9fqrnx0vtu5r36kxgp9tqx8h9k", CoinType.BINANCE));
assertFalse(AnyAddress.isValid("tbnb1devga6q804tx9fqrnx0vtu5r36kxgp9t4ruzk2", CoinType.BINANCE));
}

@Test
fun testIsValidBech32() {
assertTrue(AnyAddress.isValidBech32("bnb12vtaxl9952zm6rwf7v8jerq74pvaf77fcmvzhw", CoinType.BINANCE, "bnb"));
assertTrue(AnyAddress.isValidBech32("tbnb1devga6q804tx9fqrnx0vtu5r36kxgp9t4ruzk2", CoinType.BINANCE, "tbnb"));

assertFalse(AnyAddress.isValidBech32("bnb12vtaxl9952zm6rwf7v8jerq74pvaf77fcmvzhw", CoinType.BINANCE, "tbnb"));
assertFalse(AnyAddress.isValidBech32("tbnb1devga6q804tx9fqrnx0vtu5r36kxgp9t4ruzk2", CoinType.BINANCE, "bnb"));
}

@Test
fun testBinanceMainnet() {
val wallet = HDWallet("rabbit tilt arm protect banner ill produce vendor april bike much identify pond upset front easily glass gallery address hair priority focus forest angle", "")
Expand All @@ -31,4 +50,15 @@ class TestBinanceAddress {
assertEquals("0x727f677b390c151caf9c206fd77f77918f56904b5504243db9b21e51182c4c06", key.data().toHex())
assertEquals("bnb1devga6q804tx9fqrnx0vtu5r36kxgp9tmk4xkm", address)
}

@Test
fun testBinanceTestnet() {
val wallet = HDWallet("rabbit tilt arm protect banner ill produce vendor april bike much identify pond upset front easily glass gallery address hair priority focus forest angle", "")
val privateKey = wallet.getKeyForCoin(CoinType.BINANCE)
val publicKey = privateKey.getPublicKeySecp256k1(true)
val address = AnyAddress(publicKey, CoinType.BINANCE, "tbnb")

assertEquals("0x727f677b390c151caf9c206fd77f77918f56904b5504243db9b21e51182c4c06", privateKey.data().toHex())
assertEquals("tbnb1devga6q804tx9fqrnx0vtu5r36kxgp9t4ruzk2", address.description())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,9 @@ class TestHDWallet {

val address2 = wallet.getAddressDerivation(coin, Derivation.BITCOINLEGACY)
assertEquals(address2, "1PeUvjuxyf31aJKX6kCXuaqxhmG78ZUdL1")

val address3 = wallet.getAddressDerivation(coin, Derivation.BITCOINTESTNET)
assertEquals(address3, "tb1qwgpxgwn33z3ke9s7q65l976pseh4edrzfmyvl0")
}

@Test
Expand Down
5 changes: 5 additions & 0 deletions src/Binance/Address.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ bool Address::isValid(const std::string& addr) {
return decode(addr, addrNotUsed);
}

bool Address::isValid(const std::string& addr, const std::string& hrp) {
Address addrNotUsed;
return Bech32Address::decode(addr, addrNotUsed, hrp);
}

bool Address::decode(const std::string& addr, Address& obj_out) {
for (const auto& hrp : validHrps) {
if (Bech32Address::decode(addr, obj_out, hrp)) {
Expand Down
2 changes: 2 additions & 0 deletions src/Binance/Address.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class Address: public Bech32Address {
static const std::string hrpValidator; // HRP_BINANCE

static bool isValid(const std::string& addr);
static bool isValid(const std::string& addr, const std::string& hrp);

Address() : Bech32Address(_hrp) {}

Expand All @@ -27,6 +28,7 @@ class Address: public Bech32Address {

/// Initializes an address with a public key.
Address(const PublicKey& publicKey) : Bech32Address(_hrp, Hash::HasherSha256ripemd, publicKey) {}
Address(const PublicKey& publicKey, const std::string hrp) : Bech32Address(hrp, Hash::HasherSha256ripemd, publicKey) {}

static bool decode(const std::string& addr, Address& obj_out);
};
Expand Down
10 changes: 9 additions & 1 deletion src/Binance/Entry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,19 @@
namespace TW::Binance {

bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const {
if (std::holds_alternative<Bech32Prefix>(addressPrefix)) {
if (const auto hrp = std::get<Bech32Prefix>(addressPrefix); hrp) {
return Address::isValid(address, hrp);
}
}

// Use the default validation, which handles a specific set of valid HRPs.
return Address::isValid(address);
}

std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, [[maybe_unused]] const PrefixVariant& addressPrefix) const {
return Address(publicKey).string();
const std::string hrp = getFromPrefixHrpOrDefault(addressPrefix, coin);
return Address(publicKey, hrp).string();
}

Data Entry::addressToData([[maybe_unused]] TWCoinType coin, const std::string& address) const {
Expand Down
25 changes: 25 additions & 0 deletions swift/Tests/Addresses/BinanceAddressTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright © 2017-2023 Trust Wallet.
//
// This file is part of Trust. The full Trust copyright notice, including
// terms governing use, modification, and redistribution, is contained in the
// file LICENSE at the root of the source code distribution tree.

import WalletCore
import XCTest

class BinanceAddressTests: XCTestCase {
func testIsValid() {
XCTAssertTrue(AnyAddress.isValid(string: "bnb12vtaxl9952zm6rwf7v8jerq74pvaf77fcmvzhw", coin: .binance))

XCTAssertFalse(AnyAddress.isValid(string: "bad1devga6q804tx9fqrnx0vtu5r36kxgp9tqx8h9k", coin: .binance))
XCTAssertFalse(AnyAddress.isValid(string: "tbnb1devga6q804tx9fqrnx0vtu5r36kxgp9t4ruzk2", coin: .binance))
}

func testIsValidBech32() {
XCTAssertTrue(AnyAddress.isValidBech32(string: "bnb12vtaxl9952zm6rwf7v8jerq74pvaf77fcmvzhw", coin: .binance, hrp: "bnb"));
XCTAssertTrue(AnyAddress.isValidBech32(string: "tbnb1devga6q804tx9fqrnx0vtu5r36kxgp9t4ruzk2", coin: .binance, hrp: "tbnb"));

XCTAssertFalse(AnyAddress.isValidBech32(string: "bnb12vtaxl9952zm6rwf7v8jerq74pvaf77fcmvzhw", coin: .binance, hrp: "tbnb"));
XCTAssertFalse(AnyAddress.isValidBech32(string: "tbnb1devga6q804tx9fqrnx0vtu5r36kxgp9t4ruzk2", coin: .binance, hrp: "bnb"));
}
}
10 changes: 10 additions & 0 deletions swift/Tests/Blockchains/BinanceChainTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,16 @@ class BinanceChainTests: XCTestCase {
XCTAssertEqual("bnb1devga6q804tx9fqrnx0vtu5r36kxgp9tmk4xkm", address.description)
}

func testBinanceTestnet() {
let wallet = HDWallet(mnemonic: "rabbit tilt arm protect banner ill produce vendor april bike much identify pond upset front easily glass gallery address hair priority focus forest angle", passphrase: "")!
let privateKey = wallet.getKeyForCoin(coin: .binance)
let publicKey = privateKey.getPublicKeySecp256k1(compressed: true)
let address = AnyAddress(publicKey: publicKey, coin: .binance, hrp: "tbnb")

XCTAssertEqual(privateKey.data.hexString, "727f677b390c151caf9c206fd77f77918f56904b5504243db9b21e51182c4c06")
XCTAssertEqual("tbnb1devga6q804tx9fqrnx0vtu5r36kxgp9t4ruzk2", address.description)
}

func testSignSendOrder() {
let privateKey = PrivateKey(data: Data(hexString: "95949f757db1f57ca94a5dff23314accbe7abee89597bf6a3c7382c84d7eb832")!)!
let publicKey = privateKey.getPublicKeySecp256k1(compressed: true)
Expand Down
12 changes: 12 additions & 0 deletions swift/Tests/HDWalletTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,9 @@ class HDWalletTests: XCTestCase {

let address2 = wallet.getAddressDerivation(coin: coin, derivation: .bitcoinLegacy)
XCTAssertEqual(address2, "1PeUvjuxyf31aJKX6kCXuaqxhmG78ZUdL1")

let address3 = wallet.getAddressDerivation(coin: coin, derivation: .bitcoinTestnet)
XCTAssertEqual(address3, "tb1qwgpxgwn33z3ke9s7q65l976pseh4edrzfmyvl0")
}

func testDerive() {
Expand Down Expand Up @@ -243,6 +246,15 @@ class HDWalletTests: XCTestCase {
XCTAssertEqual("bnb1wk7kxw0qrvxe2pj9mk6ydjx0t4j9jla8pja0td", address.description)
}

func testDeriveBinanceTestnet() {
let binance = CoinType.binance
let wallet = HDWallet.test
let key = wallet.getKeyForCoin(coin: binance)
let address = AnyAddress(publicKey: key.getPublicKeySecp256k1(compressed: true), coin: binance, hrp: "tbnb")

XCTAssertEqual("tbnb1wk7kxw0qrvxe2pj9mk6ydjx0t4j9jla8085ttu", address.description)
}

func testDeriveZcash() {
let zcash = CoinType.zcash
let wallet = HDWallet.test
Expand Down
5 changes: 4 additions & 1 deletion tests/common/CoinAddressValidationTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,10 @@ TEST(Coin, validateAddressBitcoin) {

TEST(Coin, ValidateAddressBinance) {
EXPECT_TRUE(validateAddress(TWCoinTypeBinance, "bnb12vtaxl9952zm6rwf7v8jerq74pvaf77fcmvzhw"));
EXPECT_FALSE(validateAddress(TWCoinTypeBinance, "tbnb12vtaxl9952zm6rwf7v8jerq74pvaf77fkw9xhl"));
EXPECT_TRUE(validateAddress(TWCoinTypeBinance, "tbnb1devga6q804tx9fqrnx0vtu5r36kxgp9t4ruzk2", "tbnb"));

EXPECT_FALSE(validateAddress(TWCoinTypeBinance, "tbnb1devga6q804tx9fqrnx0vtu5r36kxgp9t4ruzk2"));
EXPECT_FALSE(validateAddress(TWCoinTypeBinance, "bad1devga6q804tx9fqrnx0vtu5r36kxgp9tqx8h9k"));
}

TEST(Coin, ValidateAddressLitecoin) {
Expand Down

0 comments on commit 27e0e57

Please sign in to comment.