Skip to content

Commit ef107a1

Browse files
authored
Add Cardano/Shelley address support, remove Cardano/Byron (#845)
* Cardano: Add Shelley address, remove Byron signer. * Switch to AnyAddress. * Add copy constructor, code quality. * Move copy ctor to CPP to satisfy codacy. * Remove some trailing spaces. * Adjust exception handling in AddressV3. * Add Cardano HRP to coins.json ("addr"). * Minor namespace adjustment.
1 parent 0f42c15 commit ef107a1

29 files changed

+582
-1209
lines changed

android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ class CoinAddressDerivationTests {
8181
KUSAMA -> assertEquals("DE2jNrgosggXWJXfYDmRgy1q8XKkbtzSxj2uWAy5fbBfZwT", address)
8282
POLKADOT -> assertEquals("1b97X8xTpFKMDzJpxiVhdYMNvekBDSfvGFf4DutxFkUjqfR", address)
8383
KAVA -> assertEquals("kava1drpa0x9ptz0fql3frv562rcrhj2nstuz3pas87", address)
84-
CARDANO -> assertEquals("Ae2tdPwUPEZJ2TwjFBMCnjz6t43pr4QVnBjCGSW8BMsttrt2WagC1D7LUWa", address)
84+
CARDANO -> assertEquals("addr1snpa4z7ntyfszv7ckquprdw75w4qjqh0qmya9jtkpxxlzxghlqyvv7l0yjamh8fxraw06p3ua8sj2g2gv98v4849s43t9g2999kquuu5egnprk", address)
8585
NEO -> assertEquals("AT6w7PJvwPcSqHvtbNBY2aHPDv12eW5Uuf", address)
8686
}
8787
}

android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/cardano/TestCardanoAddress.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class TestCardanoAddress {
2323
val key = PrivateKey("b0884d248cb301edd1b34cf626ba6d880bb3ae8fd91b4696446999dc4f0b5744309941d56938e943980d11643c535e046653ca6f498c014b88f2ad9fd6e71effbf36a8fa9f5e11eb7a852c41e185e3969d518e66e6893c81d3fc7227009952d4".toHexByteArray())
2424
val pubkey = key.publicKeyEd25519Extended
2525
val address = AnyAddress(pubkey, CoinType.CARDANO)
26-
val expected = AnyAddress("Ae2tdPwUPEZ6RUCnjGHFqi59k5WZLiv3HoCCNGCW8SYc5H9srdTzn1bec4W", CoinType.CARDANO)
26+
val expected = AnyAddress("addr1snpa4z7ntyfszv7ckquprdw75w4qjqh0qmya9jtkpxxlzxghlqyvv7l0yjamh8fxraw06p3ua8sj2g2gv98v4849s43t9g2999kquuu5egnprk", CoinType.CARDANO)
2727

2828
assertEquals(pubkey.data().toHex(), "0x57fd54be7b38bb8952782c2f59aa276928a4dcbb66c8c62ce44f9d623ecd5a03bf36a8fa9f5e11eb7a852c41e185e3969d518e66e6893c81d3fc7227009952d4")
2929
}

android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/cardano/TestCardanoSigner.kt

Lines changed: 0 additions & 51 deletions
This file was deleted.

coins.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1290,15 +1290,16 @@
12901290
"symbol": "ADA",
12911291
"decimals": 6,
12921292
"blockchain": "Cardano",
1293-
"derivationPath": "m/44'/1815'/0'/0/0",
1293+
"derivationPath": "m/1852'/1815'/0'/0/0",
12941294
"curve": "ed25519Extended",
12951295
"publicKeyType": "ed25519Extended",
1296+
"hrp": "addr",
12961297
"explorer": {
1297-
"url": "https://cardanoexplorer.com",
1298+
"url": "https://shelleyexplorer.cardano.org",
12981299
"txPath": "/tx/",
12991300
"accountPath": "/address/",
13001301
"sampleTx": "b7a6c5cadab0f64bdc89c77ee4a351463aba5c33f2cef6bbd6542a74a90a3af3",
1301-
"sampleAccount": "DdzFFzCqrhstpwKc8WMvPwwBb5oabcTW9zc5ykA37wJR4tYQucvsR9dXb2kEGNXkFJz2PtrpzfRiZkx8R1iNo8NYqdsukVmv7EAybFwC"
1302+
"sampleAccount": "addr1s3xuxwfetyfe7q9u3rfn6je9stlvcgmj8rezd87qjjegdtxm3y3f2mgtn87mrny9r77gm09h6ecslh3gmarrvrp9n4yzmdnecfxyu59jz29g8j"
13021303
},
13031304
"info": {
13041305
"url": "https://www.cardano.org",

include/TrustWalletCore/TWCardanoSigner.h

Lines changed: 0 additions & 25 deletions
This file was deleted.

include/TrustWalletCore/TWCoinType.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ enum TWCoinType {
2929
TWCoinTypeBitcoinCash = 145,
3030
TWCoinTypeBravoCoin = 282,
3131
TWCoinTypeCallisto = 820,
32-
TWCoinTypeCardano = 1815,
32+
TWCoinTypeCardano = 1815, // Note: Cardano Shelley testnet uses purpose 1852 (not 44) 1852/1815
3333
TWCoinTypeCosmos = 118,
3434
TWCoinTypeDash = 5,
3535
TWCoinTypeDecred = 42,

include/TrustWalletCore/TWPurpose.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ enum TWPurpose {
1919
TWPurposeBIP44 = 44,
2020
TWPurposeBIP49 = 49, // Derivation scheme for P2WPKH-nested-in-P2SH
2121
TWPurposeBIP84 = 84, // Derivation scheme for P2WPKH
22+
TWPurposeBIP1852 = 1852, // Derivation scheme used by Cardano-Shelley
2223
};
2324

2425
TW_EXTERN_C_END

src/Bech32.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ std::pair<std::string, Data> Bech32::decode(const std::string& str) {
110110
if (lower && upper)
111111
ok = false;
112112
size_t pos = str.rfind('1');
113-
if (ok && str.size() <= 90 && pos != str.npos && pos >= 1 && pos + 7 <= str.size()) {
113+
if (ok && str.size() <= 120 && pos != str.npos && pos >= 1 && pos + 7 <= str.size()) {
114114
Data values;
115115
values.resize(str.size() - 1 - pos);
116116
for (size_t i = 0; i < str.size() - 1 - pos; ++i) {

src/Cardano/Address.cpp renamed to src/Cardano/AddressV2.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
// terms governing use, modification, and redistribution, is contained in the
55
// file LICENSE at the root of the source code distribution tree.
66

7-
#include "Address.h"
7+
#include "AddressV2.h"
88
#include "../Cbor.h"
99
#include "../Data.h"
1010
#include "../Base58.h"
@@ -18,7 +18,7 @@ using namespace TW;
1818
using namespace TW::Cardano;
1919
using namespace std;
2020

21-
bool Address::parseAndCheck(const std::string& addr, Data& root_out, Data& attrs_out, byte& type_out) {
21+
bool AddressV2::parseAndCheck(const std::string& addr, Data& root_out, Data& attrs_out, byte& type_out) {
2222
// Decode Bas58, decode payload + crc, decode root, attr
2323
Data base58decoded = Base58::bitcoin.decode(addr);
2424
if (base58decoded.size() == 0) {
@@ -49,7 +49,7 @@ bool Address::parseAndCheck(const std::string& addr, Data& root_out, Data& attrs
4949
return true;
5050
}
5151

52-
bool Address::isValid(const std::string& string) {
52+
bool AddressV2::isValid(const std::string& string) {
5353
try {
5454
Data root;
5555
Data attrs;
@@ -62,14 +62,14 @@ bool Address::isValid(const std::string& string) {
6262
}
6363
}
6464

65-
Address::Address(const std::string& string) {
65+
AddressV2::AddressV2(const std::string& string) {
6666
if (!parseAndCheck(string, root, attrs, type)) {
6767
throw std::invalid_argument("Invalid address string");
6868
}
6969
// values stored
7070
}
7171

72-
Address::Address(const PublicKey& publicKey) {
72+
AddressV2::AddressV2(const PublicKey& publicKey) {
7373
// input is extended pubkey, 64-byte
7474
if (publicKey.type != TWPublicKeyTypeED25519Extended) {
7575
throw std::invalid_argument("Invalid public key type");
@@ -81,7 +81,7 @@ Address::Address(const PublicKey& publicKey) {
8181
attrs = emptyMap.encoded();
8282
}
8383

84-
Data Address::getCborData() const {
84+
Data AddressV2::getCborData() const {
8585
// put together string represenatation, CBOR representation
8686
// inner data: pubkey, attrs, type
8787
auto cbor1 = Cbor::Encode::array({
@@ -101,12 +101,12 @@ Data Address::getCborData() const {
101101
return cbor2.encoded();
102102
}
103103

104-
string Address::string() const {
104+
string AddressV2::string() const {
105105
// Base58 encode the CBOR data
106106
return Base58::bitcoin.encode(getCborData());
107107
}
108108

109-
Data Address::keyHash(const TW::Data& xpub) {
109+
Data AddressV2::keyHash(const TW::Data& xpub) {
110110
if (xpub.size() != 64) { throw invalid_argument("invalid xbub length"); }
111111
// hash of follwoing Cbor-array: [0, [0, xbub], {} ]
112112
// 3rd entry map is empty map for V2, contains derivation path for V1

src/Cardano/Address.h renamed to src/Cardano/AddressV2.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ namespace TW::Cardano {
3737
*/
3838

3939
/// A Cardano address. Type is 0 (public key).
40-
class Address {
40+
class AddressV2 {
4141
public:
4242
/// root key
4343
Data root;
@@ -54,10 +54,10 @@ class Address {
5454
static bool isValid(const std::string& string);
5555

5656
/// Initializes a Cardano address with a string representation. Throws if invalid.
57-
explicit Address(const std::string& string);
57+
explicit AddressV2(const std::string& string);
5858

5959
/// Initializes a V2, public key type Cardano address from an extended public key.
60-
explicit Address(const PublicKey& publicKey);
60+
explicit AddressV2(const PublicKey& publicKey);
6161

6262
/// Returns a string representation of the address.
6363
std::string string() const;
@@ -72,8 +72,13 @@ class Address {
7272
static bool parseAndCheck(const std::string& addr, TW::Data& root_out, TW::Data& attrs_out, TW::byte& type_out);
7373
};
7474

75-
inline bool operator==(const Address& lhs, const Address& rhs) {
75+
inline bool operator==(const AddressV2& lhs, const AddressV2& rhs) {
7676
return lhs.root == rhs.root && lhs.attrs == rhs.attrs && lhs.type == rhs.type;
7777
}
7878

7979
} // namespace TW::Cardano
80+
81+
/// Wrapper for C interface.
82+
struct TWCardanoAddressV2 {
83+
TW::Cardano::AddressV2 impl;
84+
};

0 commit comments

Comments
 (0)