diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt
index 8bfe4dd5268..18ab0a98320 100644
--- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt
+++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt
@@ -83,5 +83,6 @@ class CoinAddressDerivationTests {
CARDANO -> assertEquals("addr1snpa4z7ntyfszv7ckquprdw75w4qjqh0qmya9jtkpxxlzxghlqyvv7l0yjamh8fxraw06p3ua8sj2g2gv98v4849s43t9g2999kquuu5egnprk", address)
NEO -> assertEquals("AT6w7PJvwPcSqHvtbNBY2aHPDv12eW5Uuf", address)
FILECOIN -> assertEquals("f1zzykebxldfcakj5wdb5n3n7priul522fnmjzori", address)
+ ELROND -> assertEquals("erd1jfcy8aeru6vlx4fe6h3pc3vlpe2cnnur5zetxdhp879yagq7vqvs8na4f8", address)
}
}
diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/elrond/TestElrondAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/elrond/TestElrondAddress.kt
new file mode 100644
index 00000000000..05c17837ddc
--- /dev/null
+++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/elrond/TestElrondAddress.kt
@@ -0,0 +1,49 @@
+// Copyright © 2017-2020 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.
+
+package com.trustwallet.core.app.blockchains.elrond
+
+import com.trustwallet.core.app.utils.toHex
+import com.trustwallet.core.app.utils.toHexByteArray
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import wallet.core.jni.*
+
+class TestElrondAddress {
+
+ init {
+ System.loadLibrary("TrustWalletCore")
+ }
+
+ private val aliceBech32 = "erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz"
+ private var aliceSeedHex = "1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf"
+ private var alicePubKeyHex = "0xfd691bb5e85d102687d81079dffce842d4dc328276d2d4c60d8fd1c3433c3293"
+
+ @Test
+ fun testAddressFromPrivateKey() {
+ val key = PrivateKey(aliceSeedHex.toHexByteArray())
+ val pubKey = key.publicKeyEd25519
+ val address = AnyAddress(pubKey, CoinType.ELROND)
+
+ assertEquals(alicePubKeyHex, pubKey.data().toHex())
+ assertEquals(aliceBech32, address.description())
+ }
+
+ @Test
+ fun testAddressFromPublicKey() {
+ val pubKey = PublicKey(alicePubKeyHex.toHexByteArray(), PublicKeyType.ED25519)
+ val address = AnyAddress(pubKey, CoinType.ELROND)
+
+ assertEquals(aliceBech32, address.description())
+ }
+
+ @Test
+ fun testAddressFromString() {
+ val address = AnyAddress(aliceBech32, CoinType.ELROND)
+
+ assertEquals(aliceBech32, address.description())
+ }
+}
diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/elrond/TestElrondSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/elrond/TestElrondSigner.kt
new file mode 100644
index 00000000000..160dd9d7765
--- /dev/null
+++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/elrond/TestElrondSigner.kt
@@ -0,0 +1,57 @@
+// Copyright © 2017-2020 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.
+
+package com.trustwallet.core.app.blockchains.elrond
+
+import com.google.protobuf.ByteString
+import com.trustwallet.core.app.utils.toHexByteArray
+import junit.framework.Assert.assertEquals
+import org.junit.Test
+import wallet.core.java.AnySigner
+import wallet.core.jni.CoinType
+import wallet.core.jni.PrivateKey
+import wallet.core.jni.proto.Elrond
+
+class TestElrondSigner {
+
+ init {
+ System.loadLibrary("TrustWalletCore")
+ }
+
+ val aliceBech32 = "erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz"
+ var aliceSeedHex = "1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf"
+ var alicePubKeyHex = "fd691bb5e85d102687d81079dffce842d4dc328276d2d4c60d8fd1c3433c3293"
+
+ val bobBech32 = "erd1cux02zersde0l7hhklzhywcxk4u9n4py5tdxyx7vrvhnza2r4gmq4vw35r"
+ var bobSeedHex = "e3a3a3d1ac40d42d8fd4c569a9749b65a1250dd3d10b6f4e438297662ea4850e"
+ var bobPubKeyHex = "c70cf50b238372fffaf7b7c5723b06b57859d424a2da621bcc1b2f317543aa36"
+
+ @Test
+ fun signTransaction() {
+ val transaction = Elrond.TransactionMessage.newBuilder()
+ .setNonce(0)
+ .setValue("0")
+ .setSender(aliceBech32)
+ .setReceiver(bobBech32)
+ .setGasPrice(200000000000000)
+ .setGasLimit(500000000)
+ .setData("foo")
+ .build()
+
+ val privateKey = ByteString.copyFrom(PrivateKey(aliceSeedHex.toHexByteArray()).data())
+
+ val signingInput = Elrond.SigningInput.newBuilder()
+ .setPrivateKey(privateKey)
+ .setTransaction(transaction)
+ .build()
+
+ val output = AnySigner.sign(signingInput, CoinType.ELROND, Elrond.SigningOutput.parser())
+ val expectedSignature = "b88ad2fe98a7316ea432a0a76c18cd87200fe75f27a8f053ea6532b40317dbec5136c5463aef132ae951b7e60d45d921caaa5903e70821dcda98f237d4ec4308"
+
+ assertEquals(expectedSignature, output.signature)
+ assertEquals("""{"nonce":0,"value":"0","receiver":"$bobBech32","sender":"$aliceBech32","gasPrice":200000000000000,"gasLimit":500000000,"data":"foo","signature":"$expectedSignature"}""", output.encoded)
+ }
+}
diff --git a/coins.json b/coins.json
index 18047f66535..175ef086de3 100644
--- a/coins.json
+++ b/coins.json
@@ -1330,5 +1330,27 @@
"clientPublic": "",
"clientDocs": "https://docs.lotu.sh"
}
+ },
+ {
+ "id": "elrond",
+ "name": "Elrond",
+ "symbol": "ERD",
+ "decimals": 18,
+ "blockchain": "ElrondNetwork",
+ "derivationPath": "m/44'/508'/0'/0'/0'",
+ "curve": "ed25519",
+ "publicKeyType": "ed25519",
+ "hrp": "erd",
+ "explorer": {
+ "url": "https://explorer.elrond.com",
+ "txPath": "/transactions/",
+ "accountPath": "/address/"
+ },
+ "info": {
+ "url": "https://elrond.com/",
+ "client": "https://github.com/ElrondNetwork/elrond-go",
+ "clientPublic": "https://api.elrond.com",
+ "clientDocs": "https://docs.elrond.com"
+ }
}
]
diff --git a/docs/coins.md b/docs/coins.md
index 2fae8caf2e8..c99e9d92157 100644
--- a/docs/coins.md
+++ b/docs/coins.md
@@ -43,6 +43,7 @@ This list is generated from [./coins.json](../coins.json)
| 461 | Filecoin | FIL |
| |
| 500 | Theta | THETA |
| |
| 501 | Solana | SOL |
| |
+| 508 | Elrond | ERD |
| |
| 714 | Binance | BNB |
| |
| 818 | VeChain | VET |
| |
| 820 | Callisto | CLO |
| |
diff --git a/include/TrustWalletCore/TWBlockchain.h b/include/TrustWalletCore/TWBlockchain.h
index 8b1b82d6028..6a174d8af7c 100644
--- a/include/TrustWalletCore/TWBlockchain.h
+++ b/include/TrustWalletCore/TWBlockchain.h
@@ -45,6 +45,7 @@ enum TWBlockchain {
TWBlockchainCardano = 30,
TWBlockchainNEO = 31,
TWBlockchainFilecoin = 32,
+ TWBlockchainElrondNetwork = 33,
};
TW_EXTERN_C_END
diff --git a/include/TrustWalletCore/TWCoinType.h b/include/TrustWalletCore/TWCoinType.h
index 0c2a152cec0..bf70c377ee9 100644
--- a/include/TrustWalletCore/TWCoinType.h
+++ b/include/TrustWalletCore/TWCoinType.h
@@ -79,6 +79,7 @@ enum TWCoinType {
TWCoinTypeKusama = 434,
TWCoinTypePolkadot = 354,
TWCoinTypeFilecoin = 461,
+ TWCoinTypeElrond = 508,
};
/// Returns the blockchain for a coin type.
diff --git a/src/Coin.cpp b/src/Coin.cpp
index c6135ddbec0..d0a0454d2ec 100644
--- a/src/Coin.cpp
+++ b/src/Coin.cpp
@@ -51,6 +51,7 @@
#include "Waves/Entry.h"
#include "Zcash/Entry.h"
#include "Zilliqa/Entry.h"
+#include "Elrond/Entry.h"
// end_of_coin_includes_marker_do_not_modify
using namespace TW;
@@ -100,6 +101,7 @@ void setupDispatchers() {
new Waves::Entry(),
new Zcash::Entry(),
new Zilliqa::Entry(),
+ new Elrond::Entry(),
}; // end_of_coin_entries_marker_do_not_modify
dispatchMap.clear();
diff --git a/src/Elrond/Address.cpp b/src/Elrond/Address.cpp
new file mode 100644
index 00000000000..1af84ace200
--- /dev/null
+++ b/src/Elrond/Address.cpp
@@ -0,0 +1,17 @@
+// Copyright © 2017-2020 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.
+
+#include
+
+#include "Address.h"
+
+using namespace TW::Elrond;
+
+const std::string Address::hrp = HRP_ELROND;
+
+bool Address::isValid(const std::string& string) {
+ return Bech32Address::isValid(string, hrp);
+}
diff --git a/src/Elrond/Address.h b/src/Elrond/Address.h
new file mode 100644
index 00000000000..1f96edc6700
--- /dev/null
+++ b/src/Elrond/Address.h
@@ -0,0 +1,38 @@
+// Copyright © 2017-2020 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.
+
+#pragma once
+
+#include "../Data.h"
+#include "../PublicKey.h"
+#include "../Bech32Address.h"
+
+#include
+
+namespace TW::Elrond {
+
+class Address : public Bech32Address {
+ public:
+ // The human-readable part of the address, as defined in "coins.json"
+ static const std::string hrp; // HRP_ELROND
+
+ /// Determines whether a string makes a valid address.
+ static bool isValid(const std::string& string);
+
+ Address() : Bech32Address(hrp) {}
+
+ /// Initializes an address with a key hash.
+ Address(Data keyHash) : Bech32Address(hrp, keyHash) {}
+
+ /// Initializes an address with a public key.
+ Address(const PublicKey& publicKey) : Bech32Address(hrp, publicKey.bytes) {}
+
+ static bool decode(const std::string& addr, Address& obj_out) {
+ return Bech32Address::decode(addr, obj_out, hrp);
+ }
+};
+
+} // namespace TW::Elrond
diff --git a/src/Elrond/Entry.cpp b/src/Elrond/Entry.cpp
new file mode 100644
index 00000000000..76b806ff128
--- /dev/null
+++ b/src/Elrond/Entry.cpp
@@ -0,0 +1,31 @@
+// Copyright © 2017-2020 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.
+
+#include "Entry.h"
+
+#include "Address.h"
+#include "Signer.h"
+
+using namespace TW::Elrond;
+using namespace std;
+
+// Note: avoid business logic from here, rather just call into classes like Address, Signer, etc.
+
+bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const {
+ return Address::isValid(address);
+}
+
+string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const {
+ return Address(publicKey).string();
+}
+
+void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const {
+ signTemplate(dataIn, dataOut);
+}
+
+string Entry::signJSON(TWCoinType coin, const std::string& json, const Data& key) const {
+ return Signer::signJSON(json, key);
+}
diff --git a/src/Elrond/Entry.h b/src/Elrond/Entry.h
new file mode 100644
index 00000000000..78a5f60a39f
--- /dev/null
+++ b/src/Elrond/Entry.h
@@ -0,0 +1,25 @@
+// Copyright © 2017-2020 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.
+
+#pragma once
+
+#include "../CoinEntry.h"
+
+namespace TW::Elrond {
+
+/// Entry point for implementation of Elrond coin.
+/// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file
+class Entry: public CoinEntry {
+public:
+ virtual std::vector coinTypes() const { return {TWCoinTypeElrond}; }
+ virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const;
+ virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const;
+ virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const;
+ virtual bool supportsJSONSigning() const { return true; }
+ virtual std::string signJSON(TWCoinType coin, const std::string& json, const Data& key) const;
+};
+
+} // namespace TW::Elrond
diff --git a/src/Elrond/Serialization.cpp b/src/Elrond/Serialization.cpp
new file mode 100644
index 00000000000..193daf5d210
--- /dev/null
+++ b/src/Elrond/Serialization.cpp
@@ -0,0 +1,67 @@
+// Copyright © 2017-2020 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.
+
+#include "Serialization.h"
+
+#include "../Elrond/Address.h"
+#include "../proto/Elrond.pb.h"
+#include "Base64.h"
+#include "PrivateKey.h"
+
+using namespace TW;
+
+std::map fields_order {
+ {"nonce", 1},
+ {"value", 2},
+ {"receiver", 3},
+ {"sender", 4},
+ {"gasPrice", 5},
+ {"gasLimit", 6},
+ {"data", 7},
+ {"signature", 8}
+};
+
+struct FieldsSorter {
+ bool operator() (const string& lhs, const string& rhs) const {
+ return fields_order[lhs] < fields_order[rhs];
+ }
+};
+
+template
+using sorted_map = std::map;
+using sorted_json = nlohmann::basic_json;
+
+string Elrond::serializeTransaction(const Proto::TransactionMessage& message) {
+ sorted_json payload {
+ {"nonce", json(message.nonce())},
+ {"value", json(message.value())},
+ {"receiver", json(message.receiver())},
+ {"sender", json(message.sender())},
+ {"gasPrice", json(message.gas_price())},
+ {"gasLimit", json(message.gas_limit())},
+ };
+
+ if (!message.data().empty()) {
+ payload["data"] = json(TW::Base64::encode(TW::data(message.data())));
+ }
+
+ return payload.dump();
+}
+
+string Elrond::serializeSignedTransaction(const Proto::TransactionMessage& message, string signature) {
+ sorted_json payload {
+ {"nonce", json(message.nonce())},
+ {"value", json(message.value())},
+ {"receiver", json(message.receiver())},
+ {"sender", json(message.sender())},
+ {"gasPrice", json(message.gas_price())},
+ {"gasLimit", json(message.gas_limit())},
+ {"data", json(message.data())},
+ {"signature", json(signature)},
+ };
+
+ return payload.dump();
+}
diff --git a/src/Elrond/Serialization.h b/src/Elrond/Serialization.h
new file mode 100644
index 00000000000..e56d8a5bf87
--- /dev/null
+++ b/src/Elrond/Serialization.h
@@ -0,0 +1,21 @@
+// Copyright © 2017-2020 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.
+
+#pragma once
+
+#include "../proto/Elrond.pb.h"
+#include "Data.h"
+#include
+
+using string = std::string;
+using json = nlohmann::json;
+
+namespace TW::Elrond {
+
+string serializeTransaction(const Proto::TransactionMessage& message);
+string serializeSignedTransaction(const Proto::TransactionMessage& message, string encodedSignature);
+
+} // namespace
diff --git a/src/Elrond/Signer.cpp b/src/Elrond/Signer.cpp
new file mode 100644
index 00000000000..20519c8b80a
--- /dev/null
+++ b/src/Elrond/Signer.cpp
@@ -0,0 +1,38 @@
+// Copyright © 2017-2020 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.
+
+#include "Signer.h"
+#include "Address.h"
+#include "Serialization.h"
+#include "../PublicKey.h"
+#include "HexCoding.h"
+
+#include
+
+using namespace TW;
+using namespace TW::Elrond;
+
+Proto::SigningOutput Signer::sign(const Proto::SigningInput &input) noexcept {
+ auto privateKey = PrivateKey(input.private_key());
+ auto signableAsString = serializeTransaction(input.transaction());
+ auto signableAsData = TW::data(signableAsString);
+ auto signature = privateKey.sign(signableAsData, TWCurveED25519);
+ auto encodedSignature = hex(signature);
+ auto encoded = serializeSignedTransaction(input.transaction(), encodedSignature);
+
+ auto protoOutput = Proto::SigningOutput();
+ protoOutput.set_signature(encodedSignature);
+ protoOutput.set_encoded(encoded);
+ return protoOutput;
+}
+
+std::string Signer::signJSON(const std::string& json, const Data& key) {
+ auto input = Proto::SigningInput();
+ google::protobuf::util::JsonStringToMessage(json, &input);
+ input.set_private_key(key.data(), key.size());
+ auto output = sign(input);
+ return output.encoded();
+}
diff --git a/src/Elrond/Signer.h b/src/Elrond/Signer.h
new file mode 100644
index 00000000000..046f5e52d67
--- /dev/null
+++ b/src/Elrond/Signer.h
@@ -0,0 +1,28 @@
+// Copyright © 2017-2020 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.
+
+#pragma once
+
+#include "../Data.h"
+#include "../PrivateKey.h"
+#include "../proto/Elrond.pb.h"
+
+namespace TW::Elrond {
+
+/// Helper class that performs Elrond transaction signing.
+class Signer {
+public:
+ /// Hide default constructor
+ Signer() = delete;
+
+ /// Signs a Proto::SigningInput transaction
+ static Proto::SigningOutput sign(const Proto::SigningInput& input) noexcept;
+
+ /// Signs a json Proto::SigningInput with private key
+ static std::string signJSON(const std::string& json, const Data& key);
+};
+
+} // namespace TW::Elrond
diff --git a/src/interface/TWAnyAddress.cpp b/src/interface/TWAnyAddress.cpp
index fcd2587ddf2..8fab7633d30 100644
--- a/src/interface/TWAnyAddress.cpp
+++ b/src/interface/TWAnyAddress.cpp
@@ -20,6 +20,7 @@
#include "../Cardano/AddressV3.h"
#include "../NEO/Address.h"
#include "../Nano/Address.h"
+#include "../Elrond/Address.h"
#include "../Coin.h"
#include "../HexCoding.h"
@@ -184,6 +185,16 @@ TWData* _Nonnull TWAnyAddressData(struct TWAnyAddress* _Nonnull address) {
data = Data(addr.bytes.begin(), addr.bytes.end());
break;
}
+
+ case TWCoinTypeElrond: {
+ Elrond::Address addr;
+ if (Elrond::Address::decode(string, addr)) {
+ data = addr.getKeyHash();
+ }
+
+ break;
+ }
+
default: break;
}
return TWDataCreateWithBytes(data.data(), data.size());
diff --git a/src/proto/Elrond.proto b/src/proto/Elrond.proto
new file mode 100644
index 00000000000..41b4a0efc06
--- /dev/null
+++ b/src/proto/Elrond.proto
@@ -0,0 +1,36 @@
+// Copyright © 2017-2020 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.
+
+syntax = "proto3";
+
+package TW.Elrond.Proto;
+option java_package = "wallet.core.jni.proto";
+
+// A transaction, typical balance transfer
+message TransactionMessage {
+ uint64 nonce = 1;
+ string value = 2;
+ string receiver = 3;
+ string sender = 4;
+ uint64 gas_price = 5;
+ uint64 gas_limit = 6;
+ string data = 7;
+}
+
+// Input data necessary to create a signed transaction.
+message SigningInput {
+ bytes private_key = 1;
+
+ oneof message_oneof {
+ TransactionMessage transaction = 2;
+ }
+}
+
+// Transaction signing output.
+message SigningOutput {
+ string encoded = 1;
+ string signature = 2;
+}
diff --git a/swift/Tests/Blockchains/ElrondTests.swift b/swift/Tests/Blockchains/ElrondTests.swift
new file mode 100644
index 00000000000..c3e3e5b4b8c
--- /dev/null
+++ b/swift/Tests/Blockchains/ElrondTests.swift
@@ -0,0 +1,51 @@
+// Copyright © 2017-2020 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 TrustWalletCore
+import XCTest
+
+class ElrondTests: XCTestCase {
+
+ let aliceBech32 = "erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz"
+ let aliceSeedHex = "1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf"
+ let alicePubKeyHex = "fd691bb5e85d102687d81079dffce842d4dc328276d2d4c60d8fd1c3433c3293"
+ let bobBech32 = "erd1cux02zersde0l7hhklzhywcxk4u9n4py5tdxyx7vrvhnza2r4gmq4vw35r"
+
+ func testAddress() {
+ let key = PrivateKey(data: Data(hexString: aliceSeedHex)!)!
+ let pubkey = key.getPublicKeyEd25519()
+ let address = AnyAddress(publicKey: pubkey, coin: .elrond)
+ let addressFromString = AnyAddress(string: aliceBech32, coin: .elrond)!
+
+ XCTAssertEqual(pubkey.data.hexString, alicePubKeyHex)
+ XCTAssertEqual(address.description, addressFromString.description)
+ }
+
+ func testSign() {
+ let privateKey = PrivateKey(data: Data(hexString: aliceSeedHex)!)!
+
+ let input = ElrondSigningInput.with {
+ $0.transaction = ElrondTransactionMessage.with {
+ $0.nonce = 0
+ $0.value = "0"
+ $0.sender = aliceBech32
+ $0.receiver = bobBech32
+ $0.gasPrice = 200000000000000
+ $0.gasLimit = 500000000
+ $0.data = "foo"
+ }
+
+ $0.privateKey = privateKey.data
+ }
+
+ let output: ElrondSigningOutput = AnySigner.sign(input: input, coin: .elrond)
+ let expectedSignature = "b88ad2fe98a7316ea432a0a76c18cd87200fe75f27a8f053ea6532b40317dbec5136c5463aef132ae951b7e60d45d921caaa5903e70821dcda98f237d4ec4308"
+ let expectedEncoded = #"{"nonce":0,"value":"0","receiver":"\#(bobBech32)","sender":"\#(aliceBech32)","gasPrice":200000000000000,"gasLimit":500000000,"data":"foo","signature":"\#(expectedSignature)"}"#
+
+ XCTAssertEqual(output.signature, expectedSignature)
+ XCTAssertEqual(output.encoded, expectedEncoded)
+ }
+}
diff --git a/swift/Tests/CoinAddressDerivationTests.swift b/swift/Tests/CoinAddressDerivationTests.swift
index 81b55b548ed..2a09ac50169 100644
--- a/swift/Tests/CoinAddressDerivationTests.swift
+++ b/swift/Tests/CoinAddressDerivationTests.swift
@@ -190,6 +190,9 @@ class CoinAddressDerivationTests: XCTestCase {
case .filecoin:
let expectedResult = "f1zzykebxldfcakj5wdb5n3n7priul522fnmjzori"
AssetCoinDerivation(coin, expectedResult, derivedAddress, address)
+ case .elrond:
+ let expectedResult = "erd1jfcy8aeru6vlx4fe6h3pc3vlpe2cnnur5zetxdhp879yagq7vqvs8na4f8"
+ AssetCoinDerivation(coin, expectedResult, derivedAddress, address)
@unknown default:
fatalError()
}
diff --git a/tests/Bech32AddressTests.cpp b/tests/Bech32AddressTests.cpp
index ff425cb7c4f..4b6024ecd5e 100644
--- a/tests/Bech32AddressTests.cpp
+++ b/tests/Bech32AddressTests.cpp
@@ -27,6 +27,10 @@ TEST(Bech32Address, Valid) {
ASSERT_TRUE(Bech32Address::isValid("io187wzp08vnhjjpkydnr97qlh8kh0dpkkytfam8j", "io"));
ASSERT_TRUE(Bech32Address::isValid("zil1fwh4ltdguhde9s7nysnp33d5wye6uqpugufkz7", "zil"));
+
+ ASSERT_TRUE(Bech32Address::isValid("erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz", "erd"));
+ ASSERT_TRUE(Bech32Address::isValid("erd1cux02zersde0l7hhklzhywcxk4u9n4py5tdxyx7vrvhnza2r4gmq4vw35r", "erd"));
+ ASSERT_TRUE(Bech32Address::isValid("erd19nu5t7hszckwah5nlcadmk5rlchtugzplznskffpwecygcu0520s9tnyy0", "erd"));
}
TEST(Bech32Address, Invalid) {
@@ -48,6 +52,10 @@ TEST(Bech32Address, Invalid) {
ASSERT_FALSE(Bech32Address::isValid(""));
ASSERT_FALSE(Bech32Address::isValid("0x"));
ASSERT_FALSE(Bech32Address::isValid("91cddcebe846ce4d47712287eee53cf17c2cfb7"));
+
+ ASSERT_FALSE(Bech32Address::isValid("", "erd"));
+ ASSERT_FALSE(Bech32Address::isValid("erd1cux02zersde0l7hhklzhywcxk4u9n4py5tdxyx7vrvhnza2r4gmq4vw35!", "erd"));
+ ASSERT_FALSE(Bech32Address::isValid("xerd19nu5t7hszckwah5nlcadmk5rlchtugzplznskffpwecygcu0520s9tnyy0", "erd"));
}
TEST(Bech32Address, InvalidWrongPrefix) {
diff --git a/tests/CoinAddressDerivationTests.cpp b/tests/CoinAddressDerivationTests.cpp
index 16ac09114df..1bf597c6d88 100644
--- a/tests/CoinAddressDerivationTests.cpp
+++ b/tests/CoinAddressDerivationTests.cpp
@@ -71,6 +71,7 @@ TEST(Coin, DeriveAddress) {
EXPECT_EQ(TW::deriveAddress(TWCoinTypeFilecoin, privateKey), "f1qsx7qwiojh5duxbxhbqgnlyx5hmpcf7mcz5oxsy");
EXPECT_EQ(TW::deriveAddress(TWCoinTypeNEAR, privateKey), "NEAR2p5878zbFhxnrm7meL7TmqwtvBaqcBddyp5eGzZbovZ5HYrdGj");
EXPECT_EQ(TW::deriveAddress(TWCoinTypeSolana, privateKey), "H4JcMPicKkHcxxDjkyyrLoQj7Kcibd9t815ak4UvTr9M");
+ EXPECT_EQ(TW::deriveAddress(TWCoinTypeElrond, privateKey), "erd1a6f6fan035ttsxdmn04ellxdlnwpgyhg0lhx5vjv92v6rc8xw9yq83344f");
}
} // namespace TW
diff --git a/tests/CoinAddressValidationTests.cpp b/tests/CoinAddressValidationTests.cpp
index 7b08cf9f61b..86a0d7f309a 100644
--- a/tests/CoinAddressValidationTests.cpp
+++ b/tests/CoinAddressValidationTests.cpp
@@ -373,4 +373,10 @@ TEST(Coin, ValidateAddressVeChain) {
EXPECT_EQ(normalizeAddress(TWCoinTypeVeChain, "0x9d8a62f656a8d1615c1294fd71e9cfb3e4855a4f"), "0x9d8A62f656a8d1615C1294fd71e9CFb3E4855A4F");
}
+TEST(Coin, ValidateAddressElrond) {
+ EXPECT_TRUE(validateAddress(TWCoinTypeElrond, "erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz"));
+ EXPECT_FALSE(validateAddress(TWCoinTypeElrond, "xerd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz"));
+}
+
+
} // namespace TW
diff --git a/tests/Elrond/AddressTests.cpp b/tests/Elrond/AddressTests.cpp
new file mode 100644
index 00000000000..3dd1fb6f166
--- /dev/null
+++ b/tests/Elrond/AddressTests.cpp
@@ -0,0 +1,79 @@
+// Copyright © 2017-2020 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.
+
+#include
+#include
+
+#include "HexCoding.h"
+#include "PublicKey.h"
+#include "PrivateKey.h"
+#include "Elrond/Address.h"
+#include "TestAccounts.h"
+
+using namespace TW;
+using namespace TW::Elrond;
+
+
+TEST(ElrondAddress, Valid) {
+ ASSERT_TRUE(Address::isValid(ALICE_BECH32));
+ ASSERT_TRUE(Address::isValid(BOB_BECH32));
+ ASSERT_TRUE(Address::isValid(CAROL_BECH32));
+}
+
+TEST(ElrondAddress, Invalid) {
+ ASSERT_FALSE(Address::isValid(""));
+ ASSERT_FALSE(Address::isValid("foo"));
+ ASSERT_FALSE(Address::isValid("10z9xdugayn528ksaesdwlhf006fw5sg2qmmm0h52fvxczwgesyvq5pwemr"));
+ ASSERT_FALSE(Address::isValid("xerd10z9xdugayn528ksaesdwlhf006fw5sg2qmmm0h52fvxczwgesyvq5pwemr"));
+ ASSERT_FALSE(Address::isValid("foo10z9xdugayn528ksaesdwlhf006fw5sg2qmmm0h52fvxczwgesyvq5pwemr"));
+ ASSERT_FALSE(Address::isValid(ALICE_PUBKEY_HEX));
+}
+
+TEST(ElrondAddress, FromString) {
+ Address alice, bob, carol;
+ ASSERT_TRUE(Address::decode(ALICE_BECH32, alice));
+ ASSERT_TRUE(Address::decode(BOB_BECH32, bob));
+ ASSERT_TRUE(Address::decode(CAROL_BECH32, carol));
+
+ ASSERT_EQ(ALICE_PUBKEY_HEX, hex(alice.getKeyHash()));
+ ASSERT_EQ(BOB_PUBKEY_HEX, hex(bob.getKeyHash()));
+ ASSERT_EQ(CAROL_PUBKEY_HEX, hex(carol.getKeyHash()));
+}
+
+TEST(ElrondAddress, FromData) {
+ const auto alice = Address(parse_hex(ALICE_PUBKEY_HEX));
+ const auto bob = Address(parse_hex(BOB_PUBKEY_HEX));
+ const auto carol = Address(parse_hex(CAROL_PUBKEY_HEX));
+
+ ASSERT_EQ(ALICE_BECH32, alice.string());
+ ASSERT_EQ(BOB_BECH32, bob.string());
+ ASSERT_EQ(CAROL_BECH32, carol.string());
+}
+
+TEST(ElrondAddress, FromPrivateKey) {
+ auto aliceKey = PrivateKey(parse_hex(ALICE_SEED_HEX));
+ auto alice = Address(aliceKey.getPublicKey(TWPublicKeyTypeED25519));
+ ASSERT_EQ(ALICE_BECH32, alice.string());
+
+ auto bobKey = PrivateKey(parse_hex(BOB_SEED_HEX));
+ auto bob = Address(bobKey.getPublicKey(TWPublicKeyTypeED25519));
+ ASSERT_EQ(BOB_BECH32, bob.string());
+
+ auto carolKey = PrivateKey(parse_hex(CAROL_SEED_HEX));
+ auto carol = Address(carolKey.getPublicKey(TWPublicKeyTypeED25519));
+ ASSERT_EQ(CAROL_BECH32, carol.string());
+}
+
+TEST(ElrondAddress, FromPublicKey) {
+ auto alice = PublicKey(parse_hex(ALICE_PUBKEY_HEX), TWPublicKeyTypeED25519);
+ ASSERT_EQ(ALICE_BECH32, Address(alice).string());
+
+ auto bob = PublicKey(parse_hex(BOB_PUBKEY_HEX), TWPublicKeyTypeED25519);
+ ASSERT_EQ(BOB_BECH32, Address(bob).string());
+
+ auto carol = PublicKey(parse_hex(CAROL_PUBKEY_HEX), TWPublicKeyTypeED25519);
+ ASSERT_EQ(CAROL_BECH32, Address(carol).string());
+}
diff --git a/tests/Elrond/SerializationTests.cpp b/tests/Elrond/SerializationTests.cpp
new file mode 100644
index 00000000000..80c048bb9da
--- /dev/null
+++ b/tests/Elrond/SerializationTests.cpp
@@ -0,0 +1,54 @@
+// Copyright © 2017-2020 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.
+
+#include
+#include
+#include "boost/format.hpp"
+
+#include "HexCoding.h"
+#include "Elrond/Serialization.h"
+#include "TestAccounts.h"
+
+using namespace TW;
+using namespace TW::Elrond;
+
+TEST(ElrondSerialization, SignableString) {
+ Proto::TransactionMessage message;
+ message.set_nonce(42);
+ message.set_value("43");
+ message.set_sender("alice");
+ message.set_receiver("bob");
+ message.set_data("foobar");
+
+ string jsonString = serializeTransaction(message);
+ ASSERT_EQ(R"({"nonce":42,"value":"43","receiver":"bob","sender":"alice","gasPrice":0,"gasLimit":0,"data":"Zm9vYmFy"})", jsonString);
+}
+
+TEST(ElrondSerialization, SignableStringWithRealData) {
+ Proto::TransactionMessage message;
+ message.set_nonce(15);
+ message.set_value("100");
+ message.set_sender(ALICE_BECH32);
+ message.set_receiver(BOB_BECH32);
+ message.set_gas_price(200000000000000);
+ message.set_gas_limit(500000000);
+ message.set_data("for dinner");
+
+ string expected = (boost::format(R"({"nonce":15,"value":"100","receiver":"%1%","sender":"%2%","gasPrice":200000000000000,"gasLimit":500000000,"data":"Zm9yIGRpbm5lcg=="})") % BOB_BECH32 % ALICE_BECH32).str();
+ string actual = serializeTransaction(message);
+ ASSERT_EQ(expected, actual);
+}
+
+TEST(ElrondSerialization, SignableStringWithoutData) {
+ Proto::TransactionMessage message;
+ message.set_nonce(42);
+ message.set_value("43");
+ message.set_sender("feed");
+ message.set_receiver("abba");
+
+ string jsonString = serializeTransaction(message);
+ ASSERT_EQ(R"({"nonce":42,"value":"43","receiver":"abba","sender":"feed","gasPrice":0,"gasLimit":0})", jsonString);
+}
diff --git a/tests/Elrond/SignerTests.cpp b/tests/Elrond/SignerTests.cpp
new file mode 100644
index 00000000000..adda6c83a4d
--- /dev/null
+++ b/tests/Elrond/SignerTests.cpp
@@ -0,0 +1,89 @@
+// Copyright © 2017-2020 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.
+
+#include
+#include "boost/format.hpp"
+
+#include "HexCoding.h"
+#include "PrivateKey.h"
+#include "PublicKey.h"
+#include "Elrond/Signer.h"
+#include "Elrond/Address.h"
+#include "TestAccounts.h"
+
+using namespace TW;
+using namespace TW::Elrond;
+
+
+TEST(ElrondSigner, Sign) {
+ auto input = Proto::SigningInput();
+ auto privateKey = PrivateKey(parse_hex(ALICE_SEED_HEX));
+ input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size());
+
+ input.mutable_transaction()->set_nonce(0);
+ input.mutable_transaction()->set_value("0");
+ input.mutable_transaction()->set_sender(ALICE_BECH32);
+ input.mutable_transaction()->set_receiver(BOB_BECH32);
+ input.mutable_transaction()->set_gas_price(200000000000000);
+ input.mutable_transaction()->set_gas_limit(500000000);
+ input.mutable_transaction()->set_data("foo");
+
+ auto output = Signer::sign(input);
+ auto signature = output.signature();
+ auto encoded = output.encoded();
+ auto expectedSignature = "b88ad2fe98a7316ea432a0a76c18cd87200fe75f27a8f053ea6532b40317dbec5136c5463aef132ae951b7e60d45d921caaa5903e70821dcda98f237d4ec4308";
+ auto expectedEncoded = (boost::format(R"({"nonce":0,"value":"0","receiver":"%1%","sender":"%2%","gasPrice":200000000000000,"gasLimit":500000000,"data":"foo","signature":"%3%"})") % BOB_BECH32 % ALICE_BECH32 % expectedSignature).str();
+
+ ASSERT_EQ(expectedSignature, signature);
+ ASSERT_EQ(expectedEncoded, encoded);
+}
+
+TEST(ElrondSigner, SignJSON) {
+ // Shuffle some fields, assume arbitrary order in the input
+ auto input = (boost::format(R"({"transaction" : {"data":"foo","value":"0","nonce":0,"receiver":"%1%","sender":"%2%","gasPrice":200000000000000,"gasLimit":500000000}})") % BOB_BECH32 % ALICE_BECH32).str();
+ auto privateKey = PrivateKey(parse_hex(ALICE_SEED_HEX));
+
+ auto encoded = Signer::signJSON(input, privateKey.bytes);
+ auto expectedSignature = "b88ad2fe98a7316ea432a0a76c18cd87200fe75f27a8f053ea6532b40317dbec5136c5463aef132ae951b7e60d45d921caaa5903e70821dcda98f237d4ec4308";
+ auto expectedEncoded = (boost::format(R"({"nonce":0,"value":"0","receiver":"%1%","sender":"%2%","gasPrice":200000000000000,"gasLimit":500000000,"data":"foo","signature":"%3%"})") % BOB_BECH32 % ALICE_BECH32 % expectedSignature).str();
+
+ ASSERT_EQ(expectedEncoded, encoded);
+}
+
+TEST(ElrondSigner, SignWithoutData) {
+ auto input = Proto::SigningInput();
+ auto privateKey = PrivateKey(parse_hex(ALICE_SEED_HEX));
+ input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size());
+
+ input.mutable_transaction()->set_nonce(0);
+ input.mutable_transaction()->set_value("0");
+ input.mutable_transaction()->set_sender(ALICE_BECH32);
+ input.mutable_transaction()->set_receiver(BOB_BECH32);
+ input.mutable_transaction()->set_gas_price(200000000000000);
+ input.mutable_transaction()->set_gas_limit(500000000);
+ input.mutable_transaction()->set_data("");
+
+ auto output = Signer::sign(input);
+ auto signature = output.signature();
+ auto encoded = output.encoded();
+ auto expectedSignature = "39ab0e18bfce04bf53c9610faa3b9e7cecfca919510a7631e529e9086279b70a4832df32a5d1b8fdceb4e9082f2995da97f9195532c8d611ee749bc312cbf90c";
+ auto expectedEncoded = (boost::format(R"({"nonce":0,"value":"0","receiver":"%1%","sender":"%2%","gasPrice":200000000000000,"gasLimit":500000000,"data":"","signature":"%3%"})") % BOB_BECH32 % ALICE_BECH32 % expectedSignature).str();
+
+ ASSERT_EQ(expectedSignature, signature);
+ ASSERT_EQ(expectedEncoded, encoded);
+}
+
+TEST(ElrondSigner, SignJSONWithoutData) {
+ // Shuffle some fields, assume arbitrary order in the input
+ auto input = (boost::format(R"({"transaction" : {"value":"0","nonce":0,"receiver":"%1%","sender":"%2%","gasPrice":200000000000000,"gasLimit":500000000}})") % BOB_BECH32 % ALICE_BECH32).str();
+ auto privateKey = PrivateKey(parse_hex(ALICE_SEED_HEX));
+
+ auto encoded = Signer::signJSON(input, privateKey.bytes);
+ auto expectedSignature = "39ab0e18bfce04bf53c9610faa3b9e7cecfca919510a7631e529e9086279b70a4832df32a5d1b8fdceb4e9082f2995da97f9195532c8d611ee749bc312cbf90c";
+ auto expectedEncoded = (boost::format(R"({"nonce":0,"value":"0","receiver":"%1%","sender":"%2%","gasPrice":200000000000000,"gasLimit":500000000,"data":"","signature":"%3%"})") % BOB_BECH32 % ALICE_BECH32 % expectedSignature).str();
+
+ ASSERT_EQ(expectedEncoded, encoded);
+}
diff --git a/tests/Elrond/TWAnySignerTests.cpp b/tests/Elrond/TWAnySignerTests.cpp
new file mode 100644
index 00000000000..f9366ab52ba
--- /dev/null
+++ b/tests/Elrond/TWAnySignerTests.cpp
@@ -0,0 +1,55 @@
+// Copyright © 2017-2020 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.
+
+#include
+#include "boost/format.hpp"
+
+#include
+#include "HexCoding.h"
+#include "../interface/TWTestUtilities.h"
+#include "Elrond/Signer.h"
+#include "TestAccounts.h"
+
+using namespace TW;
+using namespace TW::Elrond;
+
+
+TEST(TWAnySignerElrond, Sign) {
+ auto input = Proto::SigningInput();
+ auto privateKey = PrivateKey(parse_hex(ALICE_SEED_HEX));
+ input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size());
+
+ input.mutable_transaction()->set_nonce(0);
+ input.mutable_transaction()->set_value("0");
+ input.mutable_transaction()->set_sender(ALICE_BECH32);
+ input.mutable_transaction()->set_receiver(BOB_BECH32);
+ input.mutable_transaction()->set_gas_price(200000000000000);
+ input.mutable_transaction()->set_gas_limit(500000000);
+ input.mutable_transaction()->set_data("foo");
+
+ Proto::SigningOutput output;
+ ANY_SIGN(input, TWCoinTypeElrond);
+
+ auto signature = output.signature();
+ auto encoded = output.encoded();
+ auto expectedSignature = "b88ad2fe98a7316ea432a0a76c18cd87200fe75f27a8f053ea6532b40317dbec5136c5463aef132ae951b7e60d45d921caaa5903e70821dcda98f237d4ec4308";
+ auto expectedEncoded = (boost::format(R"({"nonce":0,"value":"0","receiver":"%1%","sender":"%2%","gasPrice":200000000000000,"gasLimit":500000000,"data":"foo","signature":"%3%"})") % BOB_BECH32 % ALICE_BECH32 % expectedSignature).str();
+
+ ASSERT_EQ(expectedSignature, signature);
+ ASSERT_EQ(expectedEncoded, encoded);
+}
+
+TEST(TWAnySignerElrond, SignJSON) {
+ // Shuffle some fields, assume arbitrary order in the input
+ auto input = STRING((boost::format(R"({"transaction" : {"data":"foo","value":"0","nonce":0,"receiver":"%1%","sender":"%2%","gasPrice":200000000000000,"gasLimit":500000000}})") % BOB_BECH32 % ALICE_BECH32).str().c_str());
+ auto privateKey = DATA(ALICE_SEED_HEX);
+ auto encoded = WRAPS(TWAnySignerSignJSON(input.get(), privateKey.get(), TWCoinTypeElrond));
+ auto expectedSignature = "b88ad2fe98a7316ea432a0a76c18cd87200fe75f27a8f053ea6532b40317dbec5136c5463aef132ae951b7e60d45d921caaa5903e70821dcda98f237d4ec4308";
+ auto expectedEncoded = (boost::format(R"({"nonce":0,"value":"0","receiver":"%1%","sender":"%2%","gasPrice":200000000000000,"gasLimit":500000000,"data":"foo","signature":"%3%"})") % BOB_BECH32 % ALICE_BECH32 % expectedSignature).str();
+
+ ASSERT_TRUE(TWAnySignerSupportsJSON(TWCoinTypeElrond));
+ assertStringsEqual(encoded, expectedEncoded.c_str());
+}
diff --git a/tests/Elrond/TWCoinTypeTests.cpp b/tests/Elrond/TWCoinTypeTests.cpp
new file mode 100644
index 00000000000..9e73e615721
--- /dev/null
+++ b/tests/Elrond/TWCoinTypeTests.cpp
@@ -0,0 +1,34 @@
+// Copyright © 2017-2020 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.
+//
+// This is a GENERATED FILE, changes made here MAY BE LOST.
+// Generated one-time (codegen/bin/cointests)
+//
+
+#include "../interface/TWTestUtilities.h"
+#include
+#include
+
+
+TEST(TWElrondCoinType, TWCoinType) {
+ auto symbol = WRAPS(TWCoinTypeConfigurationGetSymbol(TWCoinTypeElrond));
+ auto txId = TWStringCreateWithUTF8Bytes("1fc9785cb8bea0129a16cf7bddc97630c176a556ea566f0e72923c882b5cb3c8");
+ auto txUrl = WRAPS(TWCoinTypeConfigurationGetTransactionURL(TWCoinTypeElrond, txId));
+ auto accId = TWStringCreateWithUTF8Bytes("erd12yne790km8ezwetkz7m3hmqy9utdc6vdkgsunfzpwguec6v04p2qtk9uqj");
+ auto accUrl = WRAPS(TWCoinTypeConfigurationGetAccountURL(TWCoinTypeElrond, accId));
+ auto id = WRAPS(TWCoinTypeConfigurationGetID(TWCoinTypeElrond));
+ auto name = WRAPS(TWCoinTypeConfigurationGetName(TWCoinTypeElrond));
+
+ ASSERT_EQ(TWCoinTypeConfigurationGetDecimals(TWCoinTypeElrond), 18);
+ ASSERT_EQ(TWBlockchainElrondNetwork, TWCoinTypeBlockchain(TWCoinTypeElrond));
+ ASSERT_EQ(0x0, TWCoinTypeP2shPrefix(TWCoinTypeElrond));
+ ASSERT_EQ(0x0, TWCoinTypeStaticPrefix(TWCoinTypeElrond));
+ assertStringsEqual(symbol, "ERD");
+ assertStringsEqual(txUrl, "https://explorer.elrond.com/transactions/1fc9785cb8bea0129a16cf7bddc97630c176a556ea566f0e72923c882b5cb3c8");
+ assertStringsEqual(accUrl, "https://explorer.elrond.com/address/erd12yne790km8ezwetkz7m3hmqy9utdc6vdkgsunfzpwguec6v04p2qtk9uqj");
+ assertStringsEqual(id, "elrond");
+ assertStringsEqual(name, "Elrond");
+}
diff --git a/tests/Elrond/TestAccounts.h b/tests/Elrond/TestAccounts.h
new file mode 100644
index 00000000000..55060002abd
--- /dev/null
+++ b/tests/Elrond/TestAccounts.h
@@ -0,0 +1,17 @@
+// Copyright © 2017-2020 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.
+
+#pragma once
+
+const auto ALICE_BECH32 = "erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz";
+const auto ALICE_SEED_HEX = "1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf";
+const auto ALICE_PUBKEY_HEX = "fd691bb5e85d102687d81079dffce842d4dc328276d2d4c60d8fd1c3433c3293";
+const auto BOB_BECH32 = "erd1cux02zersde0l7hhklzhywcxk4u9n4py5tdxyx7vrvhnza2r4gmq4vw35r";
+const auto BOB_SEED_HEX = "e3a3a3d1ac40d42d8fd4c569a9749b65a1250dd3d10b6f4e438297662ea4850e";
+const auto BOB_PUBKEY_HEX = "c70cf50b238372fffaf7b7c5723b06b57859d424a2da621bcc1b2f317543aa36";
+const auto CAROL_BECH32 = "erd19nu5t7hszckwah5nlcadmk5rlchtugzplznskffpwecygcu0520s9tnyy0";
+const auto CAROL_SEED_HEX = "a926316cc3daf8ff25ba3e417797e6dfd51f62ae735ab07148234732f7314052";
+const auto CAROL_PUBKEY_HEX = "2cf945faf0162ceede93fe3addda83fe2ebe2041f8a70b2521767044638fa29f";
diff --git a/tests/interface/TWAnyAddressTests.cpp b/tests/interface/TWAnyAddressTests.cpp
index c35b6935a79..dbc77477d5d 100644
--- a/tests/interface/TWAnyAddressTests.cpp
+++ b/tests/interface/TWAnyAddressTests.cpp
@@ -119,4 +119,11 @@ TEST(AnyAddress, Data) {
auto keyHash = WRAPD(TWAnyAddressData(addr.get()));
assertHexEqual(keyHash, "172bdf43265c0adfe105a1a8c45b3f406a38362f24");
}
+ // elrond
+ {
+ auto string = STRING("erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz");
+ auto addr = WRAP(TWAnyAddress, TWAnyAddressCreateWithString(string.get(), TWCoinTypeElrond));
+ auto pubkey = WRAPD(TWAnyAddressData(addr.get()));
+ assertHexEqual(pubkey, "fd691bb5e85d102687d81079dffce842d4dc328276d2d4c60d8fd1c3433c3293");
+ }
}
diff --git a/tests/interface/TWHDWalletTests.cpp b/tests/interface/TWHDWalletTests.cpp
index 62f67695f0e..6b286eee3cb 100644
--- a/tests/interface/TWHDWalletTests.cpp
+++ b/tests/interface/TWHDWalletTests.cpp
@@ -231,6 +231,16 @@ TEST(HDWallet, DeriveAlgorand) {
assertHexEqual(privateKeyData, "ce0b7ac644e2b7d9d14d3928b11643f43e48c33d3e328d059fef8add7f070e82");
}
+TEST(HDWallet, DeriveElrond) {
+ auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(words.get(), passphrase.get()));
+ auto privateKey = WRAP(TWPrivateKey, TWHDWalletGetKeyForCoin(wallet.get(), TWCoinTypeElrond));
+ auto privateKeyData = WRAPD(TWPrivateKeyData(privateKey.get()));
+ auto address = WRAPS(TWCoinTypeDeriveAddress(TWCoinTypeElrond, privateKey.get()));
+
+ assertHexEqual(privateKeyData, "0eb593141de897d60a0883320793eb49e63d556ccdf783a87ec014f150d50453");
+ assertStringsEqual(address, "erd1a6l7q9cfvrgr80xuzm37tapdr4zm3mwrtl6vt8f45df45x7eadfs8ds5vv");
+}
+
TEST(HDWallet, ExtendedKeys) {
auto words = STRING("abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about");
auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(words.get(), STRING("").get()));
diff --git a/tests/interface/TWHRPTests.cpp b/tests/interface/TWHRPTests.cpp
index 11af1a19e50..3b04ad4f8c3 100644
--- a/tests/interface/TWHRPTests.cpp
+++ b/tests/interface/TWHRPTests.cpp
@@ -28,6 +28,7 @@ TEST(TWHRP, StringForHRP) {
ASSERT_STREQ(stringForHRP(TWHRPMonacoin), "mona");
ASSERT_STREQ(stringForHRP(TWHRPKava), "kava");
ASSERT_STREQ(stringForHRP(TWHRPCardano), "addr");
+ ASSERT_STREQ(stringForHRP(TWHRPElrond), "erd");
}
TEST(TWHRP, HRPForString) {
@@ -47,6 +48,7 @@ TEST(TWHRP, HRPForString) {
ASSERT_EQ(hrpForString("mona"), TWHRPMonacoin);
ASSERT_EQ(hrpForString("kava"), TWHRPKava);
ASSERT_EQ(hrpForString("addr"), TWHRPCardano);
+ ASSERT_EQ(hrpForString("erd"), TWHRPElrond);
}
TEST(TWHPR, HPRByCoinType) {
@@ -65,6 +67,7 @@ TEST(TWHPR, HPRByCoinType) {
ASSERT_EQ(TWHRPMonacoin, TWCoinTypeHRP(TWCoinTypeMonacoin));
ASSERT_EQ(TWHRPKava, TWCoinTypeHRP(TWCoinTypeKava));
ASSERT_EQ(TWHRPCardano, TWCoinTypeHRP(TWCoinTypeCardano));
+ ASSERT_EQ(TWHRPElrond, TWCoinTypeHRP(TWCoinTypeElrond));
ASSERT_EQ(TWHRPUnknown, TWCoinTypeHRP(TWCoinTypeAion));
ASSERT_EQ(TWHRPUnknown, TWCoinTypeHRP(TWCoinTypeCallisto));