From a061ddcfc6530d0492e0bdc37ad1b719e9b5241e Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Sat, 11 Apr 2020 18:26:33 +0000 Subject: [PATCH 01/25] Initial commit, add coin and generated files. --- .../blockchains/elrond/TestElrondAddress.kt | 33 +++++++++++++ .../blockchains/elrond/TestElrondSigner.kt | 45 +++++++++++++++++ coins.json | 21 ++++++++ docs/coins.md | 1 + include/TrustWalletCore/TWBlockchain.h | 1 + include/TrustWalletCore/TWCoinType.h | 1 + src/Coin.cpp | 2 + src/Elrond/Address.cpp | 31 ++++++++++++ src/Elrond/Address.h | 43 +++++++++++++++++ src/Elrond/Entry.cpp | 27 +++++++++++ src/Elrond/Entry.h | 25 ++++++++++ src/Elrond/Signer.cpp | 26 ++++++++++ src/Elrond/Signer.h | 30 ++++++++++++ src/proto/Elrond.proto | 32 +++++++++++++ swift/Tests/Blockchains/ElrondTests.swift | 28 +++++++++++ tests/Elrond/AddressTests.cpp | 48 +++++++++++++++++++ tests/Elrond/SignerTests.cpp | 34 +++++++++++++ tests/Elrond/TWAnyAddressTests.cpp | 19 ++++++++ tests/Elrond/TWAnySignerTests.cpp | 19 ++++++++ tests/Elrond/TWCoinTypeTests.cpp | 34 +++++++++++++ 20 files changed, 500 insertions(+) create mode 100644 android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/elrond/TestElrondAddress.kt create mode 100644 android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/elrond/TestElrondSigner.kt create mode 100644 src/Elrond/Address.cpp create mode 100644 src/Elrond/Address.h create mode 100644 src/Elrond/Entry.cpp create mode 100644 src/Elrond/Entry.h create mode 100644 src/Elrond/Signer.cpp create mode 100644 src/Elrond/Signer.h create mode 100644 src/proto/Elrond.proto create mode 100644 swift/Tests/Blockchains/ElrondTests.swift create mode 100644 tests/Elrond/AddressTests.cpp create mode 100644 tests/Elrond/SignerTests.cpp create mode 100644 tests/Elrond/TWAnyAddressTests.cpp create mode 100644 tests/Elrond/TWAnySignerTests.cpp create mode 100644 tests/Elrond/TWCoinTypeTests.cpp 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..190a6e53527 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/elrond/TestElrondAddress.kt @@ -0,0 +1,33 @@ +// 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") + } + + @Test + fun testAddress() { + // TODO: Check and finalize implementation + + val key = PrivateKey("__PRIVATE_KEY_DATA__".toHexByteArray()) + val pubkey = key.publicKeyEd25519 + val address = AnyAddress(pubkey, CoinType.ELROND) + val expected = AnyAddress("__EXPECTED_RESULT_ADDRESS__", CoinType.ELROND) + + assertEquals(pubkey.data().toHex(), "0x__EXPECTED_PUBKEY_DATA__") + assertEquals(address.description(), expected.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..a6ccb9395fb --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/elrond/TestElrondSigner.kt @@ -0,0 +1,45 @@ +// 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.Numeric +import com.trustwallet.core.app.utils.toHexByteArray +import com.trustwallet.core.app.utils.toHexBytes +import com.trustwallet.core.app.utils.toHexBytesInByteString +import junit.framework.Assert.assertEquals +import org.junit.Test +import wallet.core.jni.ElrondSigner +import wallet.core.jni.proto.Elrond + +class TestElrondSigner { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun ElrondTransactionSigning() { + // TODO: Finalize implementation + + //val transfer = Elrond.TransferMessage.newBuilder() + // .setTo("...") + // .setAmount(...) + // ... + // .build() + //val signingInput = Elrond.SigningInput.newBuilder() + // ... + // .build() + + //val output: Elrond.SigningOutput = ElrondSigner.sign(signingInput) + + //assertEquals( + // "__EXPECTED_RESULT_DATA__", + // Numeric.toHexString(output.encoded.toByteArray()) + //) + } +} diff --git a/coins.json b/coins.json index 18047f66535..e5aea55bc85 100644 --- a/coins.json +++ b/coins.json @@ -1330,5 +1330,26 @@ "clientPublic": "", "clientDocs": "https://docs.lotu.sh" } + }, + { + "id": "elrond", + "name": "Elrond", + "symbol": "ERD", + "decimals": 18, + "blockchain": "ElrondNetwork", + "derivationPath": "m/44'/2003'/0'", + "curve": "ed25519", + "publicKeyType": "ed25519", + "explorer": { + "url": "https://explorer.elrond.com", + "txPath": "/transactions/", + "accountPath": "/address/" + }, + "info": { + "url": "https://elrond.com/", + "client": "https://github.com/ElrondNetwork/elrond-go", + "clientPublic": "https://wallet-api.elrond.com", + "clientDocs": "https://docs.elrond.com" + } } ] diff --git a/docs/coins.md b/docs/coins.md index 2fae8caf2e8..34fc429d2ee 100644 --- a/docs/coins.md +++ b/docs/coins.md @@ -53,6 +53,7 @@ This list is generated from [./coins.json](../coins.json) | 1024 | Ontology | ONT | | | | 1729 | Tezos | XTZ | | | | 1815 | Cardano | ADA | | | +| 2003 | Elrond | ERD | | | | 2017 | Kin | KIN | | | | 2301 | Qtum | QTUM | | | | 2718 | Nebulas | NAS | | | 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..00f9d6b1e96 100644 --- a/include/TrustWalletCore/TWCoinType.h +++ b/include/TrustWalletCore/TWCoinType.h @@ -79,6 +79,7 @@ enum TWCoinType { TWCoinTypeKusama = 434, TWCoinTypePolkadot = 354, TWCoinTypeFilecoin = 461, + TWCoinTypeElrond = 2003, }; /// 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..1eb10d97e4a --- /dev/null +++ b/src/Elrond/Address.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 "Address.h" + +using namespace TW::Elrond; + +bool Address::isValid(const std::string& string) { + // TODO: Finalize implementation + return false; +} + +Address::Address(const std::string& string) { + // TODO: Finalize implementation + + if (!isValid(string)) { + throw std::invalid_argument("Invalid address string"); + } +} + +Address::Address(const PublicKey& publicKey) { + // TODO: Finalize implementation +} + +std::string Address::string() const { + // TODO: Finalize implementation + return "TODO"; +} diff --git a/src/Elrond/Address.h b/src/Elrond/Address.h new file mode 100644 index 00000000000..7f8b25e3d83 --- /dev/null +++ b/src/Elrond/Address.h @@ -0,0 +1,43 @@ +// 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 + +namespace TW::Elrond { + +class Address { + public: + // TODO: Complete class definition + + /// Determines whether a string makes a valid address. + static bool isValid(const std::string& string); + + /// Initializes a Elrond address with a string representation. + explicit Address(const std::string& string); + + /// Initializes a Elrond address with a public key. + explicit Address(const PublicKey& publicKey); + + /// Returns a string representation of the address. + std::string string() const; +}; + +inline bool operator==(const Address& lhs, const Address& rhs) { + // TODO: Complete equality operator + return true; +} + +} // namespace TW::Elrond + +/// Wrapper for C interface. +struct TWElrondAddress { + TW::Elrond::Address impl; +}; diff --git a/src/Elrond/Entry.cpp b/src/Elrond/Entry.cpp new file mode 100644 index 00000000000..6603fb08178 --- /dev/null +++ b/src/Elrond/Entry.cpp @@ -0,0 +1,27 @@ +// 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); +} diff --git a/src/Elrond/Entry.h b/src/Elrond/Entry.h new file mode 100644 index 00000000000..a5eebbc25a3 --- /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; + // normalizeAddress(): implement this if needed, e.g. Ethereum address is EIP55 checksummed + // plan(): implement this if the blockchain is UTXO based +}; + +} // namespace TW::Elrond diff --git a/src/Elrond/Signer.cpp b/src/Elrond/Signer.cpp new file mode 100644 index 00000000000..e6cdafb6293 --- /dev/null +++ b/src/Elrond/Signer.cpp @@ -0,0 +1,26 @@ +// 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 "../PublicKey.h" + +using namespace TW; +using namespace TW::Elrond; + + +Proto::SigningOutput Signer::sign(const Proto::SigningInput &input) noexcept { + // TODO: Check and finalize implementation + + auto protoOutput = Proto::SigningOutput(); + Data encoded; + // auto privateKey = PrivateKey(Data(input.private_key().begin(), input.private_key().end())); + // auto signature = privateKey.sign(payload, TWCurveED25519); + // encoded = encodeSignature(signature); + + protoOutput.set_encoded(encoded.data(), encoded.size()); + return protoOutput; +} diff --git a/src/Elrond/Signer.h b/src/Elrond/Signer.h new file mode 100644 index 00000000000..5dc9ed629b0 --- /dev/null +++ b/src/Elrond/Signer.h @@ -0,0 +1,30 @@ +// 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; +}; + +} // namespace TW::Elrond + +/// Wrapper for C interface. +struct TWElrondSigner { + TW::Elrond::Signer impl; +}; diff --git a/src/proto/Elrond.proto b/src/proto/Elrond.proto new file mode 100644 index 00000000000..042ed682126 --- /dev/null +++ b/src/proto/Elrond.proto @@ -0,0 +1,32 @@ +// 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"; + +// TODO: typical balance transfer, add more fields needed to sign +message TransferMessage { + int64 amount = 1; + int64 fee = 2; + string to = 3; +} + +// TODO: Input data necessary to create a signed transaction. +message SigningInput { + bytes private_key = 1; + + oneof message_oneof { + TransferMessage transfer = 2; + } +} + +// Transaction signing output. +message SigningOutput { + // Signed and encoded transaction bytes. + bytes encoded = 1; +} diff --git a/swift/Tests/Blockchains/ElrondTests.swift b/swift/Tests/Blockchains/ElrondTests.swift new file mode 100644 index 00000000000..0ed019d0bea --- /dev/null +++ b/swift/Tests/Blockchains/ElrondTests.swift @@ -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. + +import TrustWalletCore +import XCTest + +class ElrondTests: XCTestCase { + // TODO: Check and finalize implementation + + func testAddress() { + // TODO: Check and finalize implementation + + let key = PrivateKey(data: Data(hexString: "__PRIVATE_KEY_DATA__")!)! + let pubkey = key.getPublicKeyEd25519() + let address = AnyAddress(publicKey: pubkey, coin: .elrond) + let addressFromString = AnyAddress(string: "__ADDRESS_DATA__", coin: .elrond)! + + XCTAssertEqual(pubkey.data.hexString, "__EXPECTED_PUBKEY_DATA__") + XCTAssertEqual(address.description, addressFromString.description) + } + + func testSign() { + // TODO: Create implementation + } +} diff --git a/tests/Elrond/AddressTests.cpp b/tests/Elrond/AddressTests.cpp new file mode 100644 index 00000000000..d767240bac8 --- /dev/null +++ b/tests/Elrond/AddressTests.cpp @@ -0,0 +1,48 @@ +// 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 "HexCoding.h" +#include "Elrond/Address.h" +#include "PublicKey.h" +#include "PrivateKey.h" +#include +#include + +using namespace TW; +using namespace TW::Elrond; + +TEST(ElrondAddress, Valid) { + ASSERT_TRUE(Address::isValid("__ADD_VALID_ADDRESS_HERE__")); + + // TODO: Add more tests +} + +TEST(ElrondAddress, Invalid) { + ASSERT_FALSE(Address::isValid("__ADD_INVALID_ADDRESS_HERE__")); + + // TODO: Add more tests +} + +TEST(ElrondAddress, FromPrivateKey) { + // TODO: Check public key type, finalize implementation + + auto privateKey = PrivateKey(parse_hex("__PRIVATE_KEY_DATA__")); + auto address = Address(privateKey.getPublicKey(TWPublicKeyTypeED25519)); + ASSERT_EQ(address.string(), "__ADD_RESULTING_ADDRESS_HERE__"); +} + +TEST(ElrondAddress, FromPublicKey) { + // TODO: Check public key type, finalize implementation + + auto publicKey = PublicKey(parse_hex("__PUBLIC_KEY_DATS__"), TWPublicKeyTypeED25519); + auto address = Address(publicKey); + ASSERT_EQ(address.string(), "__ADD_RESULTING_ADDRESS_HERE__"); +} + +TEST(ElrondAddress, FromString) { + auto address = Address("__ADD_VALID_ADDRESS_HERE__"); + ASSERT_EQ(address.string(), "__ADD_SAME_VALID_ADDRESS_HERE__"); +} diff --git a/tests/Elrond/SignerTests.cpp b/tests/Elrond/SignerTests.cpp new file mode 100644 index 00000000000..dbc22168caf --- /dev/null +++ b/tests/Elrond/SignerTests.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. + +#include "Elrond/Signer.h" +#include "Elrond/Address.h" +#include "HexCoding.h" +#include "PrivateKey.h" +#include "PublicKey.h" + +#include + +using namespace TW; +using namespace TW::Elrond; + +// TODO: Add tests + +TEST(ElrondSigner, Sign) { + // TODO: Finalize test implementation + + //auto key = PrivateKey(parse_hex("__PRIVKEY_DATA__")); + //auto publicKey = key.getPublicKey(TWPublicKeyTypeED25519); + //auto from = Address(publicKey); + //auto to = Address("__TO_ADDRESS__"); + //... + //auto transaction = Transaction(...) + //auto signature = Signer::sign(key, transaction); + //auto result = transaction.serialize(signature); + + //ASSERT_EQ(hex(serialized), "__RESULT__"); + //ASSERT_EQ(...) +} diff --git a/tests/Elrond/TWAnyAddressTests.cpp b/tests/Elrond/TWAnyAddressTests.cpp new file mode 100644 index 00000000000..10ec72f026b --- /dev/null +++ b/tests/Elrond/TWAnyAddressTests.cpp @@ -0,0 +1,19 @@ +// 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 "HexCoding.h" + +#include "../interface/TWTestUtilities.h" +#include + +using namespace TW; + +// TODO: Finalize tests + +TEST(TWElrond, Address) { + // TODO: Finalize test implementation +} diff --git a/tests/Elrond/TWAnySignerTests.cpp b/tests/Elrond/TWAnySignerTests.cpp new file mode 100644 index 00000000000..ce4fbdd33ba --- /dev/null +++ b/tests/Elrond/TWAnySignerTests.cpp @@ -0,0 +1,19 @@ +// 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 "HexCoding.h" + +#include "../interface/TWTestUtilities.h" +#include + +using namespace TW; + +// TODO: Finalize tests + +TEST(TWAnySignerElrond, Sign) { + // TODO: Finalize test implementation +} diff --git a/tests/Elrond/TWCoinTypeTests.cpp b/tests/Elrond/TWCoinTypeTests.cpp new file mode 100644 index 00000000000..038ed3f9fc6 --- /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("t123"); + auto txUrl = WRAPS(TWCoinTypeConfigurationGetTransactionURL(TWCoinTypeElrond, txId)); + auto accId = TWStringCreateWithUTF8Bytes("a12"); + 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/t123"); + assertStringsEqual(accUrl, "https://explorer.elrond.com/address/a12"); + assertStringsEqual(id, "elrond"); + assertStringsEqual(name, "Elrond"); +} From d4bb0b8018e7291898431bfa371ff223de65eb5f Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Sun, 12 Apr 2020 00:46:26 +0300 Subject: [PATCH 02/25] Sketch addresses as bech32 addresses. Use cosmos & binance as examples. --- coins.json | 1 + src/Elrond/Address.cpp | 22 +++------------------- src/Elrond/Address.h | 26 +++++++++++++------------- 3 files changed, 17 insertions(+), 32 deletions(-) diff --git a/coins.json b/coins.json index e5aea55bc85..e49e6061e6f 100644 --- a/coins.json +++ b/coins.json @@ -1340,6 +1340,7 @@ "derivationPath": "m/44'/2003'/0'", "curve": "ed25519", "publicKeyType": "ed25519", + "hrp": "erd", "explorer": { "url": "https://explorer.elrond.com", "txPath": "/transactions/", diff --git a/src/Elrond/Address.cpp b/src/Elrond/Address.cpp index 1eb10d97e4a..75de3db570d 100644 --- a/src/Elrond/Address.cpp +++ b/src/Elrond/Address.cpp @@ -8,24 +8,8 @@ using namespace TW::Elrond; -bool Address::isValid(const std::string& string) { - // TODO: Finalize implementation - return false; -} - -Address::Address(const std::string& string) { - // TODO: Finalize implementation - - if (!isValid(string)) { - throw std::invalid_argument("Invalid address string"); - } -} - -Address::Address(const PublicKey& publicKey) { - // TODO: Finalize implementation -} +const std::string Address::hrp = HRP_ELROND; -std::string Address::string() const { - // TODO: Finalize implementation - return "TODO"; +bool Address::isValid(const std::string& string) { + Bech32Address::isValid(address, hrp); } diff --git a/src/Elrond/Address.h b/src/Elrond/Address.h index 7f8b25e3d83..6cef064daa8 100644 --- a/src/Elrond/Address.h +++ b/src/Elrond/Address.h @@ -8,32 +8,32 @@ #include "../Data.h" #include "../PublicKey.h" +#include "../Bech32Address.h" #include namespace TW::Elrond { -class Address { +class Address : public Bech32Address { public: - // TODO: Complete class definition + // 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); - /// Initializes a Elrond address with a string representation. - explicit Address(const std::string& string); + Address() : Bech32Address(hrp) {} - /// Initializes a Elrond address with a public key. - explicit Address(const PublicKey& publicKey); + /// Initializes an address with a key hash. + Address(Data keyHash) : Bech32Address(hrp, keyHash) {} - /// Returns a string representation of the address. - std::string string() const; -}; + /// Initializes an address with a public key. + Address(const PublicKey& publicKey) : Bech32Address(hrp, HASHER_SHA2_RIPEMD, publicKey) {} -inline bool operator==(const Address& lhs, const Address& rhs) { - // TODO: Complete equality operator - return true; -} + static bool decode(const std::string& addr, Address& obj_out) { + return Bech32Address::decode(addr, obj_out, hrp); + } +}; } // namespace TW::Elrond From 0fdac946c39ac6b4345f5bf8f864bc0fb69b7a87 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Sun, 12 Apr 2020 01:10:01 +0300 Subject: [PATCH 03/25] Add address tests. --- src/Elrond/Entry.h | 2 -- tests/Elrond/AddressTests.cpp | 27 +++++++++++---------------- 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/src/Elrond/Entry.h b/src/Elrond/Entry.h index a5eebbc25a3..7c7f4ee69e7 100644 --- a/src/Elrond/Entry.h +++ b/src/Elrond/Entry.h @@ -18,8 +18,6 @@ class Entry: public CoinEntry { 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; - // normalizeAddress(): implement this if needed, e.g. Ethereum address is EIP55 checksummed - // plan(): implement this if the blockchain is UTXO based }; } // namespace TW::Elrond diff --git a/tests/Elrond/AddressTests.cpp b/tests/Elrond/AddressTests.cpp index d767240bac8..0693ac2b7cc 100644 --- a/tests/Elrond/AddressTests.cpp +++ b/tests/Elrond/AddressTests.cpp @@ -15,34 +15,29 @@ using namespace TW; using namespace TW::Elrond; TEST(ElrondAddress, Valid) { - ASSERT_TRUE(Address::isValid("__ADD_VALID_ADDRESS_HERE__")); - - // TODO: Add more tests + ASSERT_TRUE(Address::isValid("erd10z9xdugayn528ksaesdwlhf006fw5sg2qmmm0h52fvxczwgesyvq5pwemr")); + ASSERT_TRUE(Address::isValid("erd1wcfp4v3c7k5qzurue2xq2n60dq362kj56ccu9qz4pgd95vm09gaqsmh2h9")); } TEST(ElrondAddress, Invalid) { - ASSERT_FALSE(Address::isValid("__ADD_INVALID_ADDRESS_HERE__")); - - // TODO: Add more tests + ASSERT_FALSE(Address::isValid("")); + ASSERT_FALSE(Address::isValid("foo")); + ASSERT_FALSE(Address::isValid("10z9xdugayn528ksaesdwlhf006fw5sg2qmmm0h52fvxczwgesyvq5pwemr")); } TEST(ElrondAddress, FromPrivateKey) { - // TODO: Check public key type, finalize implementation - - auto privateKey = PrivateKey(parse_hex("__PRIVATE_KEY_DATA__")); + auto privateKey = PrivateKey(parse_hex("6d893bc800f790261f814be252ee9bf51d6efc70e8c46dedc3f9357d06487b04")); auto address = Address(privateKey.getPublicKey(TWPublicKeyTypeED25519)); - ASSERT_EQ(address.string(), "__ADD_RESULTING_ADDRESS_HERE__"); + ASSERT_EQ(address.string(), "erd10z9xdugayn528ksaesdwlhf006fw5sg2qmmm0h52fvxczwgesyvq5pwemr"); } TEST(ElrondAddress, FromPublicKey) { - // TODO: Check public key type, finalize implementation - - auto publicKey = PublicKey(parse_hex("__PUBLIC_KEY_DATS__"), TWPublicKeyTypeED25519); + auto publicKey = PublicKey(parse_hex("788a66f11d24e8a3da1dcc1aefdd2f7e92ea410a06f7b7de8a4b0d8139198118"), TWPublicKeyTypeED25519); auto address = Address(publicKey); - ASSERT_EQ(address.string(), "__ADD_RESULTING_ADDRESS_HERE__"); + ASSERT_EQ(address.string(), "erd10z9xdugayn528ksaesdwlhf006fw5sg2qmmm0h52fvxczwgesyvq5pwemr"); } TEST(ElrondAddress, FromString) { - auto address = Address("__ADD_VALID_ADDRESS_HERE__"); - ASSERT_EQ(address.string(), "__ADD_SAME_VALID_ADDRESS_HERE__"); + auto address = Address("erd10z9xdugayn528ksaesdwlhf006fw5sg2qmmm0h52fvxczwgesyvq5pwemr"); + ASSERT_EQ(address.string(), "erd10z9xdugayn528ksaesdwlhf006fw5sg2qmmm0h52fvxczwgesyvq5pwemr"); } From 3a3acea1329d3e69fb4094ba600aa707974fde92 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Sun, 12 Apr 2020 16:34:27 +0000 Subject: [PATCH 04/25] Fix address tests. --- src/Elrond/Address.cpp | 4 +++- src/Elrond/Address.h | 2 +- tests/Elrond/AddressTests.cpp | 20 +++++++++++++------- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/Elrond/Address.cpp b/src/Elrond/Address.cpp index 75de3db570d..1af84ace200 100644 --- a/src/Elrond/Address.cpp +++ b/src/Elrond/Address.cpp @@ -4,6 +4,8 @@ // 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; @@ -11,5 +13,5 @@ using namespace TW::Elrond; const std::string Address::hrp = HRP_ELROND; bool Address::isValid(const std::string& string) { - Bech32Address::isValid(address, hrp); + return Bech32Address::isValid(string, hrp); } diff --git a/src/Elrond/Address.h b/src/Elrond/Address.h index 6cef064daa8..d56854cbc90 100644 --- a/src/Elrond/Address.h +++ b/src/Elrond/Address.h @@ -28,7 +28,7 @@ class Address : public Bech32Address { Address(Data keyHash) : Bech32Address(hrp, keyHash) {} /// Initializes an address with a public key. - Address(const PublicKey& publicKey) : Bech32Address(hrp, HASHER_SHA2_RIPEMD, publicKey) {} + 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); diff --git a/tests/Elrond/AddressTests.cpp b/tests/Elrond/AddressTests.cpp index 0693ac2b7cc..32402984fe6 100644 --- a/tests/Elrond/AddressTests.cpp +++ b/tests/Elrond/AddressTests.cpp @@ -25,19 +25,25 @@ TEST(ElrondAddress, Invalid) { ASSERT_FALSE(Address::isValid("10z9xdugayn528ksaesdwlhf006fw5sg2qmmm0h52fvxczwgesyvq5pwemr")); } +TEST(ElrondAddress, FromString) { + Address alice; + ASSERT_TRUE(Address::decode("erd10z9xdugayn528ksaesdwlhf006fw5sg2qmmm0h52fvxczwgesyvq5pwemr", alice)); + ASSERT_EQ("788a66f11d24e8a3da1dcc1aefdd2f7e92ea410a06f7b7de8a4b0d8139198118", hex(alice.getKeyHash())); +} + +TEST(ElrondAddress, FromData) { + const auto alice = Address(parse_hex("0x788a66f11d24e8a3da1dcc1aefdd2f7e92ea410a06f7b7de8a4b0d8139198118")); + ASSERT_EQ(alice.string(), "erd10z9xdugayn528ksaesdwlhf006fw5sg2qmmm0h52fvxczwgesyvq5pwemr"); +} + TEST(ElrondAddress, FromPrivateKey) { - auto privateKey = PrivateKey(parse_hex("6d893bc800f790261f814be252ee9bf51d6efc70e8c46dedc3f9357d06487b04")); + auto privateKey = PrivateKey(parse_hex("0x6d893bc800f790261f814be252ee9bf51d6efc70e8c46dedc3f9357d06487b04")); auto address = Address(privateKey.getPublicKey(TWPublicKeyTypeED25519)); ASSERT_EQ(address.string(), "erd10z9xdugayn528ksaesdwlhf006fw5sg2qmmm0h52fvxczwgesyvq5pwemr"); } TEST(ElrondAddress, FromPublicKey) { - auto publicKey = PublicKey(parse_hex("788a66f11d24e8a3da1dcc1aefdd2f7e92ea410a06f7b7de8a4b0d8139198118"), TWPublicKeyTypeED25519); + auto publicKey = PublicKey(parse_hex("0x788a66f11d24e8a3da1dcc1aefdd2f7e92ea410a06f7b7de8a4b0d8139198118"), TWPublicKeyTypeED25519); auto address = Address(publicKey); ASSERT_EQ(address.string(), "erd10z9xdugayn528ksaesdwlhf006fw5sg2qmmm0h52fvxczwgesyvq5pwemr"); } - -TEST(ElrondAddress, FromString) { - auto address = Address("erd10z9xdugayn528ksaesdwlhf006fw5sg2qmmm0h52fvxczwgesyvq5pwemr"); - ASSERT_EQ(address.string(), "erd10z9xdugayn528ksaesdwlhf006fw5sg2qmmm0h52fvxczwgesyvq5pwemr"); -} From 16cffa5c25cb832cc293e0c63ece01ae3112a23f Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Sun, 12 Apr 2020 20:57:25 +0000 Subject: [PATCH 05/25] Serialization, tests --- src/Elrond/Serialization.cpp | 61 +++++++++++++++++++++++++++++ src/Elrond/Serialization.h | 20 ++++++++++ src/Elrond/Signer.cpp | 1 + src/proto/Elrond.proto | 14 ++++--- tests/Elrond/SerializationTests.cpp | 36 +++++++++++++++++ 5 files changed, 127 insertions(+), 5 deletions(-) create mode 100644 src/Elrond/Serialization.cpp create mode 100644 src/Elrond/Serialization.h create mode 100644 tests/Elrond/SerializationTests.cpp diff --git a/src/Elrond/Serialization.cpp b/src/Elrond/Serialization.cpp new file mode 100644 index 00000000000..5993cf61607 --- /dev/null +++ b/src/Elrond/Serialization.cpp @@ -0,0 +1,61 @@ +// 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::Elrond; + +using string = std::string; + +std::map fields_order { + {"nonce", 1}, + {"value", 2}, + {"receiver", 3}, + {"sender", 4}, + {"gas_price", 5}, + {"gas_limit", 6}, + {"data", 7} +}; + +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; +using json = nlohmann::json; + +static string encodeTransactionData(string data) { + TW::Data buffer = TW::data(data); + string encoded = TW::Base64::encode(buffer); + return encoded; +} + +string TW::Elrond::serializeMessageToSignableString(const Proto::TransferMessage& message) { + sorted_json payload { + {"nonce", json(message.nonce())}, + {"value", json(message.value())}, + {"receiver", json(message.receiver())}, + {"sender", json(message.sender())}, + {"gas_price", json(message.gas_price())}, + {"gas_limit", json(message.gas_limit())} + }; + + if (!message.data().empty()) { + payload["data"] = json(encodeTransactionData(message.data())); + } + + string jsonString = payload.dump(); + return jsonString; +} diff --git a/src/Elrond/Serialization.h b/src/Elrond/Serialization.h new file mode 100644 index 00000000000..19b00f2d43b --- /dev/null +++ b/src/Elrond/Serialization.h @@ -0,0 +1,20 @@ +// 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 serializeMessageToSignableString(const Proto::TransferMessage& message); + +} // namespace diff --git a/src/Elrond/Signer.cpp b/src/Elrond/Signer.cpp index e6cdafb6293..ae1f6f8b73f 100644 --- a/src/Elrond/Signer.cpp +++ b/src/Elrond/Signer.cpp @@ -6,6 +6,7 @@ #include "Signer.h" #include "Address.h" +#include "Serialization.h" #include "../PublicKey.h" using namespace TW; diff --git a/src/proto/Elrond.proto b/src/proto/Elrond.proto index 042ed682126..06c1050465b 100644 --- a/src/proto/Elrond.proto +++ b/src/proto/Elrond.proto @@ -9,14 +9,18 @@ syntax = "proto3"; package TW.Elrond.Proto; option java_package = "wallet.core.jni.proto"; -// TODO: typical balance transfer, add more fields needed to sign +// Typical balance transfer message TransferMessage { - int64 amount = 1; - int64 fee = 2; - string to = 3; + uint64 nonce = 1; + string value = 2; + string receiver = 3; + string sender = 4; + uint64 gas_price = 5; + uint64 gas_limit = 6; + string data = 7; } -// TODO: Input data necessary to create a signed transaction. +// Input data necessary to create a signed transaction. message SigningInput { bytes private_key = 1; diff --git a/tests/Elrond/SerializationTests.cpp b/tests/Elrond/SerializationTests.cpp new file mode 100644 index 00000000000..824fe3349b5 --- /dev/null +++ b/tests/Elrond/SerializationTests.cpp @@ -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. + +#include "HexCoding.h" +#include "Elrond/Serialization.h" +#include +#include + +using namespace TW; +using namespace TW::Elrond; + +TEST(ElrondSerialization, TransactionPayloadIsCorrect) { + Proto::TransferMessage message; + message.set_nonce(42); + message.set_value("43"); + message.set_receiver("foo"); + message.set_sender("bar"); + + string jsonString = serializeMessageToSignableString(message); + ASSERT_EQ(R"({"nonce":42,"value":"43","receiver":"foo","sender":"bar","gas_price":0,"gas_limit":0})", jsonString); +} + +TEST(ElrondSerialization, TransactionPayloadWithDataIsCorrect) { + Proto::TransferMessage message; + message.set_nonce(42); + message.set_value("43"); + message.set_receiver("foo"); + message.set_sender("bar"); + message.set_data("hello"); + + string jsonString = serializeMessageToSignableString(message); + ASSERT_EQ(R"({"nonce":42,"value":"43","receiver":"foo","sender":"bar","gas_price":0,"gas_limit":0,"data":"aGVsbG8="})", jsonString); +} From a43c6f5b98ae865a0e10b41fe57c21e603d0c6ac Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Sun, 12 Apr 2020 22:20:23 +0000 Subject: [PATCH 06/25] Implement signing, add tests --- src/Elrond/Serialization.cpp | 14 ++++---- src/Elrond/Signer.cpp | 14 ++++---- src/proto/Elrond.proto | 2 +- tests/Elrond/SerializationTests.cpp | 12 +++---- tests/Elrond/SignerTests.cpp | 50 ++++++++++++++++++++--------- 5 files changed, 56 insertions(+), 36 deletions(-) diff --git a/src/Elrond/Serialization.cpp b/src/Elrond/Serialization.cpp index 5993cf61607..cfa4cd5a802 100644 --- a/src/Elrond/Serialization.cpp +++ b/src/Elrond/Serialization.cpp @@ -9,6 +9,7 @@ #include "../Elrond/Address.h" #include "../proto/Elrond.pb.h" #include "Base64.h" +#include "HexCoding.h" #include "PrivateKey.h" using namespace TW::Elrond; @@ -20,8 +21,8 @@ std::map fields_order { {"value", 2}, {"receiver", 3}, {"sender", 4}, - {"gas_price", 5}, - {"gas_limit", 6}, + {"gasPrice", 5}, + {"gasLimit", 6}, {"data", 7} }; @@ -46,12 +47,13 @@ string TW::Elrond::serializeMessageToSignableString(const Proto::TransferMessage sorted_json payload { {"nonce", json(message.nonce())}, {"value", json(message.value())}, - {"receiver", json(message.receiver())}, - {"sender", json(message.sender())}, - {"gas_price", json(message.gas_price())}, - {"gas_limit", json(message.gas_limit())} + {"gasPrice", json(message.gas_price())}, + {"gasLimit", json(message.gas_limit())} }; + payload["receiver"] = json(TW::Base64::encode(parse_hex(message.receiver()))); + payload["sender"] = json(TW::Base64::encode(parse_hex(message.sender()))); + if (!message.data().empty()) { payload["data"] = json(encodeTransactionData(message.data())); } diff --git a/src/Elrond/Signer.cpp b/src/Elrond/Signer.cpp index ae1f6f8b73f..8017171fded 100644 --- a/src/Elrond/Signer.cpp +++ b/src/Elrond/Signer.cpp @@ -8,20 +8,20 @@ #include "Address.h" #include "Serialization.h" #include "../PublicKey.h" +#include "HexCoding.h" using namespace TW; using namespace TW::Elrond; Proto::SigningOutput Signer::sign(const Proto::SigningInput &input) noexcept { - // TODO: Check and finalize implementation + auto privateKey = PrivateKey(input.private_key()); + string payload = Elrond::serializeMessageToSignableString(input.transfer()); + Data payloadAsData = TW::data(payload); + auto signature = privateKey.sign(payloadAsData, TWCurveED25519); + string encodedSignature = hex(signature); auto protoOutput = Proto::SigningOutput(); - Data encoded; - // auto privateKey = PrivateKey(Data(input.private_key().begin(), input.private_key().end())); - // auto signature = privateKey.sign(payload, TWCurveED25519); - // encoded = encodeSignature(signature); - - protoOutput.set_encoded(encoded.data(), encoded.size()); + protoOutput.set_encoded(encodedSignature); return protoOutput; } diff --git a/src/proto/Elrond.proto b/src/proto/Elrond.proto index 06c1050465b..171e5991b02 100644 --- a/src/proto/Elrond.proto +++ b/src/proto/Elrond.proto @@ -32,5 +32,5 @@ message SigningInput { // Transaction signing output. message SigningOutput { // Signed and encoded transaction bytes. - bytes encoded = 1; + string encoded = 1; } diff --git a/tests/Elrond/SerializationTests.cpp b/tests/Elrond/SerializationTests.cpp index 824fe3349b5..b705b3448bb 100644 --- a/tests/Elrond/SerializationTests.cpp +++ b/tests/Elrond/SerializationTests.cpp @@ -16,21 +16,21 @@ TEST(ElrondSerialization, TransactionPayloadIsCorrect) { Proto::TransferMessage message; message.set_nonce(42); message.set_value("43"); - message.set_receiver("foo"); - message.set_sender("bar"); + message.set_receiver("abba"); + message.set_sender("feed"); string jsonString = serializeMessageToSignableString(message); - ASSERT_EQ(R"({"nonce":42,"value":"43","receiver":"foo","sender":"bar","gas_price":0,"gas_limit":0})", jsonString); + ASSERT_EQ(R"({"nonce":42,"value":"43","receiver":"q7o=","sender":"/u0=","gasPrice":0,"gasLimit":0})", jsonString); } TEST(ElrondSerialization, TransactionPayloadWithDataIsCorrect) { Proto::TransferMessage message; message.set_nonce(42); message.set_value("43"); - message.set_receiver("foo"); - message.set_sender("bar"); + message.set_receiver("abba"); + message.set_sender("feed"); message.set_data("hello"); string jsonString = serializeMessageToSignableString(message); - ASSERT_EQ(R"({"nonce":42,"value":"43","receiver":"foo","sender":"bar","gas_price":0,"gas_limit":0,"data":"aGVsbG8="})", jsonString); + ASSERT_EQ(R"({"nonce":42,"value":"43","receiver":"q7o=","sender":"/u0=","gasPrice":0,"gasLimit":0,"data":"aGVsbG8="})", jsonString); } diff --git a/tests/Elrond/SignerTests.cpp b/tests/Elrond/SignerTests.cpp index dbc22168caf..2b335502990 100644 --- a/tests/Elrond/SignerTests.cpp +++ b/tests/Elrond/SignerTests.cpp @@ -15,20 +15,38 @@ using namespace TW; using namespace TW::Elrond; -// TODO: Add tests - -TEST(ElrondSigner, Sign) { - // TODO: Finalize test implementation - - //auto key = PrivateKey(parse_hex("__PRIVKEY_DATA__")); - //auto publicKey = key.getPublicKey(TWPublicKeyTypeED25519); - //auto from = Address(publicKey); - //auto to = Address("__TO_ADDRESS__"); - //... - //auto transaction = Transaction(...) - //auto signature = Signer::sign(key, transaction); - //auto result = transaction.serialize(signature); - - //ASSERT_EQ(hex(serialized), "__RESULT__"); - //ASSERT_EQ(...) + +TEST(ElrondSigner, SignWithoutData) { + auto input = Proto::SigningInput(); + auto privateKey = PrivateKey(parse_hex("aa137cb6a0022f18ea2d31f00025190fb09961deb624e18cf11f6e867ccb45d3")); + input.set_private_key(privateKey.bytes.data(), 32); + + input.mutable_transfer()->set_nonce(0); + input.mutable_transfer()->set_value("0"); + input.mutable_transfer()->set_sender("93ee6143cdc10ce79f15b2a6c2ad38e9b6021c72a1779051f47154fd54cfbd5e"); + input.mutable_transfer()->set_receiver("a967adb3d1574581a6f7ffe0cd6600fb488686704fcff944c88efc7c90b3b13b"); + input.mutable_transfer()->set_gas_price(200000000000000); + input.mutable_transfer()->set_gas_limit(500000000); + auto output = Signer::sign(input); + auto signature = output.encoded(); + + ASSERT_EQ("04e98acb3c844bcf49fcd07417fdfe5edc9df4419f7deed49262145d3759f687c1cda202cda51808ad0834b472ccf1f5334b952e3cb1fd0b98721c6bfca10d04", signature); +} + +TEST(ElrondSigner, SignWithData) { + auto input = Proto::SigningInput(); + auto privateKey = PrivateKey(parse_hex("aa137cb6a0022f18ea2d31f00025190fb09961deb624e18cf11f6e867ccb45d3")); + input.set_private_key(privateKey.bytes.data(), 32); + + input.mutable_transfer()->set_nonce(0); + input.mutable_transfer()->set_value("0"); + input.mutable_transfer()->set_sender("93ee6143cdc10ce79f15b2a6c2ad38e9b6021c72a1779051f47154fd54cfbd5e"); + input.mutable_transfer()->set_receiver("a967adb3d1574581a6f7ffe0cd6600fb488686704fcff944c88efc7c90b3b13b"); + input.mutable_transfer()->set_gas_price(200000000000000); + input.mutable_transfer()->set_gas_limit(500000000); + input.mutable_transfer()->set_data("foo"); + auto output = Signer::sign(input); + auto signature = output.encoded(); + + ASSERT_EQ("d0cc3a4d97aa80f37195e91f041163a2f6e9963e5db508b18f1103739892e6660fac5b015050b3ba1ba1bfb43c17f2a432c10386274e665c3d668a3c21723f04", signature); } From d9c6568a41d08c0c5e1fa740a24bf340aebb1d2f Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Wed, 15 Apr 2020 12:13:43 +0000 Subject: [PATCH 07/25] Fix serialization, improve tests. --- src/Elrond/Serialization.cpp | 41 ++++++++++++++++------------- src/Elrond/Serialization.h | 3 ++- src/Elrond/Signer.cpp | 12 +++++---- src/proto/Elrond.proto | 10 +++---- tests/Elrond/SerializationTests.cpp | 38 +++++++++++++++++--------- tests/Elrond/SignerTests.cpp | 30 ++++++++++----------- 6 files changed, 77 insertions(+), 57 deletions(-) diff --git a/src/Elrond/Serialization.cpp b/src/Elrond/Serialization.cpp index cfa4cd5a802..0a9e0dcc911 100644 --- a/src/Elrond/Serialization.cpp +++ b/src/Elrond/Serialization.cpp @@ -9,14 +9,11 @@ #include "../Elrond/Address.h" #include "../proto/Elrond.pb.h" #include "Base64.h" -#include "HexCoding.h" #include "PrivateKey.h" using namespace TW::Elrond; -using string = std::string; - -std::map fields_order { +std::map fields_order { {"nonce", 1}, {"value", 2}, {"receiver", 3}, @@ -35,29 +32,35 @@ struct FieldsSorter { template using sorted_map = std::map; using sorted_json = nlohmann::basic_json; -using json = nlohmann::json; - -static string encodeTransactionData(string data) { - TW::Data buffer = TW::data(data); - string encoded = TW::Base64::encode(buffer); - return encoded; -} -string TW::Elrond::serializeMessageToSignableString(const Proto::TransferMessage& message) { +string TW::Elrond::serializeTransactionToSignableString(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())} + {"gasLimit", json(message.gas_limit())}, }; - payload["receiver"] = json(TW::Base64::encode(parse_hex(message.receiver()))); - payload["sender"] = json(TW::Base64::encode(parse_hex(message.sender()))); - if (!message.data().empty()) { - payload["data"] = json(encodeTransactionData(message.data())); + payload["data"] = json(TW::Base64::encode(TW::data(message.data()))); } - string jsonString = payload.dump(); - return jsonString; + return payload.dump(); +} + +string TW::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 index 19b00f2d43b..8ae39d6c11b 100644 --- a/src/Elrond/Serialization.h +++ b/src/Elrond/Serialization.h @@ -15,6 +15,7 @@ using json = nlohmann::json; namespace TW::Elrond { -string serializeMessageToSignableString(const Proto::TransferMessage& message); +string serializeTransactionToSignableString(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 index 8017171fded..1004b65783e 100644 --- a/src/Elrond/Signer.cpp +++ b/src/Elrond/Signer.cpp @@ -16,12 +16,14 @@ using namespace TW::Elrond; Proto::SigningOutput Signer::sign(const Proto::SigningInput &input) noexcept { auto privateKey = PrivateKey(input.private_key()); - string payload = Elrond::serializeMessageToSignableString(input.transfer()); - Data payloadAsData = TW::data(payload); - auto signature = privateKey.sign(payloadAsData, TWCurveED25519); - string encodedSignature = hex(signature); + auto signableAsString = Elrond::serializeTransactionToSignableString(input.transaction()); + auto signableAsData = TW::data(signableAsString); + auto signature = privateKey.sign(signableAsData, TWCurveED25519); + auto encodedSignature = hex(signature); + auto serializedTransaction = Elrond::serializeSignedTransaction(input.transaction(), encodedSignature); auto protoOutput = Proto::SigningOutput(); - protoOutput.set_encoded(encodedSignature); + protoOutput.set_signature(encodedSignature); + protoOutput.set_signed_transaction(serializedTransaction); return protoOutput; } diff --git a/src/proto/Elrond.proto b/src/proto/Elrond.proto index 171e5991b02..a823a4aca27 100644 --- a/src/proto/Elrond.proto +++ b/src/proto/Elrond.proto @@ -9,8 +9,8 @@ syntax = "proto3"; package TW.Elrond.Proto; option java_package = "wallet.core.jni.proto"; -// Typical balance transfer -message TransferMessage { +// A transaction, typical balance transfer +message TransactionMessage { uint64 nonce = 1; string value = 2; string receiver = 3; @@ -25,12 +25,12 @@ message SigningInput { bytes private_key = 1; oneof message_oneof { - TransferMessage transfer = 2; + TransactionMessage transaction = 2; } } // Transaction signing output. message SigningOutput { - // Signed and encoded transaction bytes. - string encoded = 1; + string signed_transaction = 1; + string signature = 2; } diff --git a/tests/Elrond/SerializationTests.cpp b/tests/Elrond/SerializationTests.cpp index b705b3448bb..2f28df7fa17 100644 --- a/tests/Elrond/SerializationTests.cpp +++ b/tests/Elrond/SerializationTests.cpp @@ -12,25 +12,39 @@ using namespace TW; using namespace TW::Elrond; -TEST(ElrondSerialization, TransactionPayloadIsCorrect) { - Proto::TransferMessage message; +TEST(ElrondSerialization, SignableString) { + Proto::TransactionMessage message; message.set_nonce(42); message.set_value("43"); - message.set_receiver("abba"); - message.set_sender("feed"); + message.set_sender("alice"); + message.set_receiver("bob"); + message.set_data("foobar"); - string jsonString = serializeMessageToSignableString(message); - ASSERT_EQ(R"({"nonce":42,"value":"43","receiver":"q7o=","sender":"/u0=","gasPrice":0,"gasLimit":0})", jsonString); + string jsonString = serializeTransactionToSignableString(message); + ASSERT_EQ(R"({"nonce":42,"value":"43","receiver":"bob","sender":"alice","gasPrice":0,"gasLimit":0,"data":"Zm9vYmFy"})", jsonString); } -TEST(ElrondSerialization, TransactionPayloadWithDataIsCorrect) { - Proto::TransferMessage message; +TEST(ElrondSerialization, SignableStringWithRealData) { + Proto::TransactionMessage message; + message.set_nonce(15); + message.set_value("100"); + message.set_sender("erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz"); + message.set_receiver("erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr"); + message.set_gas_price(200000000000000); + message.set_gas_limit(500000000); + message.set_data("for dinner"); + + string jsonString = serializeTransactionToSignableString(message); + ASSERT_EQ(R"({"nonce":15,"value":"100","receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000,"data":"Zm9yIGRpbm5lcg=="})", jsonString); +} + +TEST(ElrondSerialization, SignableStringWithoutData) { + Proto::TransactionMessage message; message.set_nonce(42); message.set_value("43"); - message.set_receiver("abba"); message.set_sender("feed"); - message.set_data("hello"); + message.set_receiver("abba"); - string jsonString = serializeMessageToSignableString(message); - ASSERT_EQ(R"({"nonce":42,"value":"43","receiver":"q7o=","sender":"/u0=","gasPrice":0,"gasLimit":0,"data":"aGVsbG8="})", jsonString); + string jsonString = serializeTransactionToSignableString(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 index 2b335502990..d0bfd92f760 100644 --- a/tests/Elrond/SignerTests.cpp +++ b/tests/Elrond/SignerTests.cpp @@ -21,14 +21,14 @@ TEST(ElrondSigner, SignWithoutData) { auto privateKey = PrivateKey(parse_hex("aa137cb6a0022f18ea2d31f00025190fb09961deb624e18cf11f6e867ccb45d3")); input.set_private_key(privateKey.bytes.data(), 32); - input.mutable_transfer()->set_nonce(0); - input.mutable_transfer()->set_value("0"); - input.mutable_transfer()->set_sender("93ee6143cdc10ce79f15b2a6c2ad38e9b6021c72a1779051f47154fd54cfbd5e"); - input.mutable_transfer()->set_receiver("a967adb3d1574581a6f7ffe0cd6600fb488686704fcff944c88efc7c90b3b13b"); - input.mutable_transfer()->set_gas_price(200000000000000); - input.mutable_transfer()->set_gas_limit(500000000); + input.mutable_transaction()->set_nonce(0); + input.mutable_transaction()->set_value("0"); + input.mutable_transaction()->set_sender("93ee6143cdc10ce79f15b2a6c2ad38e9b6021c72a1779051f47154fd54cfbd5e"); + input.mutable_transaction()->set_receiver("a967adb3d1574581a6f7ffe0cd6600fb488686704fcff944c88efc7c90b3b13b"); + input.mutable_transaction()->set_gas_price(200000000000000); + input.mutable_transaction()->set_gas_limit(500000000); auto output = Signer::sign(input); - auto signature = output.encoded(); + auto signature = output.signature(); ASSERT_EQ("04e98acb3c844bcf49fcd07417fdfe5edc9df4419f7deed49262145d3759f687c1cda202cda51808ad0834b472ccf1f5334b952e3cb1fd0b98721c6bfca10d04", signature); } @@ -38,15 +38,15 @@ TEST(ElrondSigner, SignWithData) { auto privateKey = PrivateKey(parse_hex("aa137cb6a0022f18ea2d31f00025190fb09961deb624e18cf11f6e867ccb45d3")); input.set_private_key(privateKey.bytes.data(), 32); - input.mutable_transfer()->set_nonce(0); - input.mutable_transfer()->set_value("0"); - input.mutable_transfer()->set_sender("93ee6143cdc10ce79f15b2a6c2ad38e9b6021c72a1779051f47154fd54cfbd5e"); - input.mutable_transfer()->set_receiver("a967adb3d1574581a6f7ffe0cd6600fb488686704fcff944c88efc7c90b3b13b"); - input.mutable_transfer()->set_gas_price(200000000000000); - input.mutable_transfer()->set_gas_limit(500000000); - input.mutable_transfer()->set_data("foo"); + input.mutable_transaction()->set_nonce(0); + input.mutable_transaction()->set_value("0"); + input.mutable_transaction()->set_sender("93ee6143cdc10ce79f15b2a6c2ad38e9b6021c72a1779051f47154fd54cfbd5e"); + input.mutable_transaction()->set_receiver("a967adb3d1574581a6f7ffe0cd6600fb488686704fcff944c88efc7c90b3b13b"); + 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.encoded(); + auto signature = output.signature(); ASSERT_EQ("d0cc3a4d97aa80f37195e91f041163a2f6e9963e5db508b18f1103739892e6660fac5b015050b3ba1ba1bfb43c17f2a432c10386274e665c3d668a3c21723f04", signature); } From 586346a7aed2dee97ee68bf8c2f0b6f323827f08 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Wed, 15 Apr 2020 13:55:53 +0000 Subject: [PATCH 08/25] Add tests, fix signing --- src/Elrond/Serialization.cpp | 3 ++- tests/Elrond/AddressTests.cpp | 24 ++++++++++++++++++++---- tests/Elrond/SignerTests.cpp | 29 ++++++++++++++++++----------- 3 files changed, 40 insertions(+), 16 deletions(-) diff --git a/src/Elrond/Serialization.cpp b/src/Elrond/Serialization.cpp index 0a9e0dcc911..7e190dad1fa 100644 --- a/src/Elrond/Serialization.cpp +++ b/src/Elrond/Serialization.cpp @@ -20,7 +20,8 @@ std::map fields_order { {"sender", 4}, {"gasPrice", 5}, {"gasLimit", 6}, - {"data", 7} + {"data", 7}, + {"signature", 8} }; struct FieldsSorter { diff --git a/tests/Elrond/AddressTests.cpp b/tests/Elrond/AddressTests.cpp index 32402984fe6..a206a81163c 100644 --- a/tests/Elrond/AddressTests.cpp +++ b/tests/Elrond/AddressTests.cpp @@ -16,34 +16,50 @@ using namespace TW::Elrond; TEST(ElrondAddress, Valid) { ASSERT_TRUE(Address::isValid("erd10z9xdugayn528ksaesdwlhf006fw5sg2qmmm0h52fvxczwgesyvq5pwemr")); - ASSERT_TRUE(Address::isValid("erd1wcfp4v3c7k5qzurue2xq2n60dq362kj56ccu9qz4pgd95vm09gaqsmh2h9")); + ASSERT_TRUE(Address::isValid("erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz")); + ASSERT_TRUE(Address::isValid("erd19nu5t7hszckwah5nlcadmk5rlchtugzplznskffpwecygcu0520s9tnyy0")); } TEST(ElrondAddress, Invalid) { ASSERT_FALSE(Address::isValid("")); ASSERT_FALSE(Address::isValid("foo")); ASSERT_FALSE(Address::isValid("10z9xdugayn528ksaesdwlhf006fw5sg2qmmm0h52fvxczwgesyvq5pwemr")); + ASSERT_FALSE(Address::isValid("nerd10z9xdugayn528ksaesdwlhf006fw5sg2qmmm0h52fvxczwgesyvq5pwemr")); + ASSERT_FALSE(Address::isValid("foo10z9xdugayn528ksaesdwlhf006fw5sg2qmmm0h52fvxczwgesyvq5pwemr")); + ASSERT_FALSE(Address::isValid("788a66f11d24e8a3da1dcc1aefdd2f7e92ea410a06f7b7de8a4b0d8139198118")); } TEST(ElrondAddress, FromString) { - Address alice; + Address alice, bob, carol; ASSERT_TRUE(Address::decode("erd10z9xdugayn528ksaesdwlhf006fw5sg2qmmm0h52fvxczwgesyvq5pwemr", alice)); + ASSERT_TRUE(Address::decode("erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz", bob)); + ASSERT_TRUE(Address::decode("erd19nu5t7hszckwah5nlcadmk5rlchtugzplznskffpwecygcu0520s9tnyy0", carol)); + ASSERT_EQ("788a66f11d24e8a3da1dcc1aefdd2f7e92ea410a06f7b7de8a4b0d8139198118", hex(alice.getKeyHash())); + ASSERT_EQ("fd691bb5e85d102687d81079dffce842d4dc328276d2d4c60d8fd1c3433c3293", hex(bob.getKeyHash())); + ASSERT_EQ("2cf945faf0162ceede93fe3addda83fe2ebe2041f8a70b2521767044638fa29f", hex(carol.getKeyHash())); } TEST(ElrondAddress, FromData) { - const auto alice = Address(parse_hex("0x788a66f11d24e8a3da1dcc1aefdd2f7e92ea410a06f7b7de8a4b0d8139198118")); + const auto alice = Address(parse_hex("788a66f11d24e8a3da1dcc1aefdd2f7e92ea410a06f7b7de8a4b0d8139198118")); + const auto bob = Address(parse_hex("fd691bb5e85d102687d81079dffce842d4dc328276d2d4c60d8fd1c3433c3293")); + const auto carol = Address(parse_hex("2cf945faf0162ceede93fe3addda83fe2ebe2041f8a70b2521767044638fa29f")); + ASSERT_EQ(alice.string(), "erd10z9xdugayn528ksaesdwlhf006fw5sg2qmmm0h52fvxczwgesyvq5pwemr"); + ASSERT_EQ(bob.string(), "erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz"); + ASSERT_EQ(carol.string(), "erd19nu5t7hszckwah5nlcadmk5rlchtugzplznskffpwecygcu0520s9tnyy0"); } TEST(ElrondAddress, FromPrivateKey) { auto privateKey = PrivateKey(parse_hex("0x6d893bc800f790261f814be252ee9bf51d6efc70e8c46dedc3f9357d06487b04")); auto address = Address(privateKey.getPublicKey(TWPublicKeyTypeED25519)); ASSERT_EQ(address.string(), "erd10z9xdugayn528ksaesdwlhf006fw5sg2qmmm0h52fvxczwgesyvq5pwemr"); + // TODO-Elrond: add more tests } TEST(ElrondAddress, FromPublicKey) { - auto publicKey = PublicKey(parse_hex("0x788a66f11d24e8a3da1dcc1aefdd2f7e92ea410a06f7b7de8a4b0d8139198118"), TWPublicKeyTypeED25519); + auto publicKey = PublicKey(parse_hex("788a66f11d24e8a3da1dcc1aefdd2f7e92ea410a06f7b7de8a4b0d8139198118"), TWPublicKeyTypeED25519); auto address = Address(publicKey); ASSERT_EQ(address.string(), "erd10z9xdugayn528ksaesdwlhf006fw5sg2qmmm0h52fvxczwgesyvq5pwemr"); + // TODO-Elrond: add more tests } diff --git a/tests/Elrond/SignerTests.cpp b/tests/Elrond/SignerTests.cpp index d0bfd92f760..4e0bec2d47b 100644 --- a/tests/Elrond/SignerTests.cpp +++ b/tests/Elrond/SignerTests.cpp @@ -16,37 +16,44 @@ using namespace TW; using namespace TW::Elrond; -TEST(ElrondSigner, SignWithoutData) { +TEST(ElrondSigner, Sign) { auto input = Proto::SigningInput(); - auto privateKey = PrivateKey(parse_hex("aa137cb6a0022f18ea2d31f00025190fb09961deb624e18cf11f6e867ccb45d3")); + auto privateKey = PrivateKey(parse_hex("1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf")); input.set_private_key(privateKey.bytes.data(), 32); input.mutable_transaction()->set_nonce(0); input.mutable_transaction()->set_value("0"); - input.mutable_transaction()->set_sender("93ee6143cdc10ce79f15b2a6c2ad38e9b6021c72a1779051f47154fd54cfbd5e"); - input.mutable_transaction()->set_receiver("a967adb3d1574581a6f7ffe0cd6600fb488686704fcff944c88efc7c90b3b13b"); + input.mutable_transaction()->set_sender("erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz"); + input.mutable_transaction()->set_receiver("erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr"); 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 signedTransaction = output.signed_transaction(); - ASSERT_EQ("04e98acb3c844bcf49fcd07417fdfe5edc9df4419f7deed49262145d3759f687c1cda202cda51808ad0834b472ccf1f5334b952e3cb1fd0b98721c6bfca10d04", signature); + ASSERT_EQ("8912cd7310df084cffe67557ef93c8fd30048d00bb71ea5fe9f5ebb6d90194500122eab982d49c5c5c164e7012cb8d29279820f3e7e885a5fe31c5b2cce0e90a", signature); + ASSERT_EQ(R"({"nonce":0,"value":"0","receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000,"data":"foo","signature":"8912cd7310df084cffe67557ef93c8fd30048d00bb71ea5fe9f5ebb6d90194500122eab982d49c5c5c164e7012cb8d29279820f3e7e885a5fe31c5b2cce0e90a"})", signedTransaction); } -TEST(ElrondSigner, SignWithData) { +TEST(ElrondSigner, SignWithoutData) { auto input = Proto::SigningInput(); - auto privateKey = PrivateKey(parse_hex("aa137cb6a0022f18ea2d31f00025190fb09961deb624e18cf11f6e867ccb45d3")); + auto privateKey = PrivateKey(parse_hex("1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf")); input.set_private_key(privateKey.bytes.data(), 32); input.mutable_transaction()->set_nonce(0); input.mutable_transaction()->set_value("0"); - input.mutable_transaction()->set_sender("93ee6143cdc10ce79f15b2a6c2ad38e9b6021c72a1779051f47154fd54cfbd5e"); - input.mutable_transaction()->set_receiver("a967adb3d1574581a6f7ffe0cd6600fb488686704fcff944c88efc7c90b3b13b"); + input.mutable_transaction()->set_sender("erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz"); + input.mutable_transaction()->set_receiver("erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr"); input.mutable_transaction()->set_gas_price(200000000000000); input.mutable_transaction()->set_gas_limit(500000000); - input.mutable_transaction()->set_data("foo"); + input.mutable_transaction()->set_data(""); + auto output = Signer::sign(input); auto signature = output.signature(); + auto signedTransaction = output.signed_transaction(); - ASSERT_EQ("d0cc3a4d97aa80f37195e91f041163a2f6e9963e5db508b18f1103739892e6660fac5b015050b3ba1ba1bfb43c17f2a432c10386274e665c3d668a3c21723f04", signature); + ASSERT_EQ("4e160bcafb6cb8ab8fc3260d3faf24bf7ce1205b5685adb457803db6d67c648a614308d8354e40b40fbb90c227046d6997493f798b92acb1b4bc49173939e703", signature); + ASSERT_EQ(R"({"nonce":0,"value":"0","receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000,"data":"","signature":"4e160bcafb6cb8ab8fc3260d3faf24bf7ce1205b5685adb457803db6d67c648a614308d8354e40b40fbb90c227046d6997493f798b92acb1b4bc49173939e703"})", signedTransaction); } From 63326038e6df7cae4c3b662bcf54851fe3b4235c Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Thu, 16 Apr 2020 18:43:01 +0300 Subject: [PATCH 09/25] Add signJSON. --- src/Elrond/Entry.cpp | 4 ++++ src/Elrond/Entry.h | 2 ++ src/Elrond/Signer.cpp | 8 ++++++++ src/Elrond/Signer.h | 3 +++ tests/Elrond/SignerTests.cpp | 18 ++++++++++++++++++ 5 files changed, 35 insertions(+) diff --git a/src/Elrond/Entry.cpp b/src/Elrond/Entry.cpp index 6603fb08178..76b806ff128 100644 --- a/src/Elrond/Entry.cpp +++ b/src/Elrond/Entry.cpp @@ -25,3 +25,7 @@ string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byt 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 index 7c7f4ee69e7..78a5f60a39f 100644 --- a/src/Elrond/Entry.h +++ b/src/Elrond/Entry.h @@ -18,6 +18,8 @@ class Entry: public CoinEntry { 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/Signer.cpp b/src/Elrond/Signer.cpp index 1004b65783e..eb258c1c915 100644 --- a/src/Elrond/Signer.cpp +++ b/src/Elrond/Signer.cpp @@ -27,3 +27,11 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput &input) noexcept { protoOutput.set_signed_transaction(serializedTransaction); 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 = Signer::sign(input); + return output.signed_transaction(); +} diff --git a/src/Elrond/Signer.h b/src/Elrond/Signer.h index 5dc9ed629b0..3eda71ca9d0 100644 --- a/src/Elrond/Signer.h +++ b/src/Elrond/Signer.h @@ -20,6 +20,9 @@ class Signer { /// 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/tests/Elrond/SignerTests.cpp b/tests/Elrond/SignerTests.cpp index 4e0bec2d47b..795afc2d27d 100644 --- a/tests/Elrond/SignerTests.cpp +++ b/tests/Elrond/SignerTests.cpp @@ -37,6 +37,15 @@ TEST(ElrondSigner, Sign) { ASSERT_EQ(R"({"nonce":0,"value":"0","receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000,"data":"foo","signature":"8912cd7310df084cffe67557ef93c8fd30048d00bb71ea5fe9f5ebb6d90194500122eab982d49c5c5c164e7012cb8d29279820f3e7e885a5fe31c5b2cce0e90a"})", signedTransaction); } +TEST(ElrondSigner, SignJSON) { + // Shuffle some fields, assume arbitrary order in the input + auto input = (R"({"data":"foo","value":"0","nonce":0,"receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000})" + auto privateKey = PrivateKey(parse_hex("1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf")); + + auto signedTransaction = Signer::signJSON(input, privateKey); + ASSERT_EQ(R"({"nonce":0,"value":"0","receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000,"data":"foo","signature":"8912cd7310df084cffe67557ef93c8fd30048d00bb71ea5fe9f5ebb6d90194500122eab982d49c5c5c164e7012cb8d29279820f3e7e885a5fe31c5b2cce0e90a"})", signedTransaction); +} + TEST(ElrondSigner, SignWithoutData) { auto input = Proto::SigningInput(); auto privateKey = PrivateKey(parse_hex("1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf")); @@ -57,3 +66,12 @@ TEST(ElrondSigner, SignWithoutData) { ASSERT_EQ("4e160bcafb6cb8ab8fc3260d3faf24bf7ce1205b5685adb457803db6d67c648a614308d8354e40b40fbb90c227046d6997493f798b92acb1b4bc49173939e703", signature); ASSERT_EQ(R"({"nonce":0,"value":"0","receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000,"data":"","signature":"4e160bcafb6cb8ab8fc3260d3faf24bf7ce1205b5685adb457803db6d67c648a614308d8354e40b40fbb90c227046d6997493f798b92acb1b4bc49173939e703"})", signedTransaction); } + +TEST(ElrondSigner, SignJSONWithoutData) { + // Shuffle some fields, assume arbitrary order in the input + auto input = (R"({"data":"foo","value":"0","nonce":0,"receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000})" + auto privateKey = PrivateKey(parse_hex("1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf")); + + auto signedTransaction = Signer::signJSON(input, privateKey); + ASSERT_EQ(R"({"nonce":0,"value":"0","receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000,"data":"","signature":"4e160bcafb6cb8ab8fc3260d3faf24bf7ce1205b5685adb457803db6d67c648a614308d8354e40b40fbb90c227046d6997493f798b92acb1b4bc49173939e703"})", signedTransaction); +} From 7077452b487edc32e44d5ff480ba952e10670625 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Thu, 16 Apr 2020 19:12:39 +0300 Subject: [PATCH 10/25] Add AnySignerTests. --- tests/Elrond/SignerTests.cpp | 4 ++-- tests/Elrond/TWAnySignerTests.cpp | 29 +++++++++++++++++++++++++++-- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/tests/Elrond/SignerTests.cpp b/tests/Elrond/SignerTests.cpp index 795afc2d27d..96d3fe86b27 100644 --- a/tests/Elrond/SignerTests.cpp +++ b/tests/Elrond/SignerTests.cpp @@ -19,7 +19,7 @@ using namespace TW::Elrond; TEST(ElrondSigner, Sign) { auto input = Proto::SigningInput(); auto privateKey = PrivateKey(parse_hex("1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf")); - input.set_private_key(privateKey.bytes.data(), 32); + input.set_private_key(privateKey.bytes.data(), privateKey.size()); input.mutable_transaction()->set_nonce(0); input.mutable_transaction()->set_value("0"); @@ -49,7 +49,7 @@ TEST(ElrondSigner, SignJSON) { TEST(ElrondSigner, SignWithoutData) { auto input = Proto::SigningInput(); auto privateKey = PrivateKey(parse_hex("1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf")); - input.set_private_key(privateKey.bytes.data(), 32); + input.set_private_key(privateKey.bytes.data(), privateKey.size()); input.mutable_transaction()->set_nonce(0); input.mutable_transaction()->set_value("0"); diff --git a/tests/Elrond/TWAnySignerTests.cpp b/tests/Elrond/TWAnySignerTests.cpp index ce4fbdd33ba..18e36d7a8f9 100644 --- a/tests/Elrond/TWAnySignerTests.cpp +++ b/tests/Elrond/TWAnySignerTests.cpp @@ -12,8 +12,33 @@ using namespace TW; -// TODO: Finalize tests TEST(TWAnySignerElrond, Sign) { - // TODO: Finalize test implementation + auto input = Proto::SigningInput(); + auto privateKey = PrivateKey(parse_hex("1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf")); + input.set_private_key(privateKey.bytes.data(), privateKey.size()); + + input.mutable_transaction()->set_nonce(0); + input.mutable_transaction()->set_value("0"); + input.mutable_transaction()->set_sender("erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz"); + input.mutable_transaction()->set_receiver("erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr"); + 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); + + ASSERT_EQ("8912cd7310df084cffe67557ef93c8fd30048d00bb71ea5fe9f5ebb6d90194500122eab982d49c5c5c164e7012cb8d29279820f3e7e885a5fe31c5b2cce0e90a", output.signature()); + ASSERT_EQ(R"({"nonce":0,"value":"0","receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000,"data":"foo","signature":"8912cd7310df084cffe67557ef93c8fd30048d00bb71ea5fe9f5ebb6d90194500122eab982d49c5c5c164e7012cb8d29279820f3e7e885a5fe31c5b2cce0e90a"})", output.signed_transaction()); +} + +TEST(TWAnySignerElrond, SignJSON) { + // Shuffle some fields, assume arbitrary order in the input + auto input = (R"({"data":"foo","value":"0","nonce":0,"receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000})" + auto privateKey = PrivateKey(parse_hex("1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf")); + auto signedTransaction = TWAnySignerSignJSON(json.get(), privateKey.get(), TWCoinTypeElrond) + + ASSERT_TRUE(TWAnySignerSupportsJSON(TWCoinTypeElrond)); + ASSERT_EQ(R"({"nonce":0,"value":"0","receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000,"data":"foo","signature":"8912cd7310df084cffe67557ef93c8fd30048d00bb71ea5fe9f5ebb6d90194500122eab982d49c5c5c164e7012cb8d29279820f3e7e885a5fe31c5b2cce0e90a"})", signedTransaction); } From f6e34c79447c907d38f3ed467b7c7fca434ab1e2 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Thu, 16 Apr 2020 19:29:47 +0300 Subject: [PATCH 11/25] Improve tests. --- tests/Elrond/AddressTests.cpp | 55 +++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/tests/Elrond/AddressTests.cpp b/tests/Elrond/AddressTests.cpp index a206a81163c..868bf2a2a5b 100644 --- a/tests/Elrond/AddressTests.cpp +++ b/tests/Elrond/AddressTests.cpp @@ -14,10 +14,17 @@ using namespace TW; using namespace TW::Elrond; +const auto ALICE_BECH32 = "erd10z9xdugayn528ksaesdwlhf006fw5sg2qmmm0h52fvxczwgesyvq5pwemr"; +const auto ALICE_PUBKEY_HEX = "788a66f11d24e8a3da1dcc1aefdd2f7e92ea410a06f7b7de8a4b0d8139198118"; +const auto BOB_BECH32 = "erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz"; +const auto BOB_PUBKEY_HEX = "fd691bb5e85d102687d81079dffce842d4dc328276d2d4c60d8fd1c3433c3293"; +const auto CAROL_BECH32 = "erd19nu5t7hszckwah5nlcadmk5rlchtugzplznskffpwecygcu0520s9tnyy0"; +const auto CAROL_PUBKEY_HEX = "2cf945faf0162ceede93fe3addda83fe2ebe2041f8a70b2521767044638fa29f"; + TEST(ElrondAddress, Valid) { - ASSERT_TRUE(Address::isValid("erd10z9xdugayn528ksaesdwlhf006fw5sg2qmmm0h52fvxczwgesyvq5pwemr")); - ASSERT_TRUE(Address::isValid("erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz")); - ASSERT_TRUE(Address::isValid("erd19nu5t7hszckwah5nlcadmk5rlchtugzplznskffpwecygcu0520s9tnyy0")); + ASSERT_TRUE(Address::isValid(ALICE_BECH32)); + ASSERT_TRUE(Address::isValid(BOB_BECH32)); + ASSERT_TRUE(Address::isValid(CAROL_BECH32)); } TEST(ElrondAddress, Invalid) { @@ -26,40 +33,44 @@ TEST(ElrondAddress, Invalid) { ASSERT_FALSE(Address::isValid("10z9xdugayn528ksaesdwlhf006fw5sg2qmmm0h52fvxczwgesyvq5pwemr")); ASSERT_FALSE(Address::isValid("nerd10z9xdugayn528ksaesdwlhf006fw5sg2qmmm0h52fvxczwgesyvq5pwemr")); ASSERT_FALSE(Address::isValid("foo10z9xdugayn528ksaesdwlhf006fw5sg2qmmm0h52fvxczwgesyvq5pwemr")); - ASSERT_FALSE(Address::isValid("788a66f11d24e8a3da1dcc1aefdd2f7e92ea410a06f7b7de8a4b0d8139198118")); + ASSERT_FALSE(Address::isValid(ALICE_PUBKEY_HEX)); } TEST(ElrondAddress, FromString) { Address alice, bob, carol; - ASSERT_TRUE(Address::decode("erd10z9xdugayn528ksaesdwlhf006fw5sg2qmmm0h52fvxczwgesyvq5pwemr", alice)); - ASSERT_TRUE(Address::decode("erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz", bob)); - ASSERT_TRUE(Address::decode("erd19nu5t7hszckwah5nlcadmk5rlchtugzplznskffpwecygcu0520s9tnyy0", carol)); + ASSERT_TRUE(Address::decode(ALICE_BECH32, alice)); + ASSERT_TRUE(Address::decode(BOB_BECH32, bob)); + ASSERT_TRUE(Address::decode(CAROL_BECH32, carol)); - ASSERT_EQ("788a66f11d24e8a3da1dcc1aefdd2f7e92ea410a06f7b7de8a4b0d8139198118", hex(alice.getKeyHash())); - ASSERT_EQ("fd691bb5e85d102687d81079dffce842d4dc328276d2d4c60d8fd1c3433c3293", hex(bob.getKeyHash())); - ASSERT_EQ("2cf945faf0162ceede93fe3addda83fe2ebe2041f8a70b2521767044638fa29f", hex(carol.getKeyHash())); + 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("788a66f11d24e8a3da1dcc1aefdd2f7e92ea410a06f7b7de8a4b0d8139198118")); - const auto bob = Address(parse_hex("fd691bb5e85d102687d81079dffce842d4dc328276d2d4c60d8fd1c3433c3293")); - const auto carol = Address(parse_hex("2cf945faf0162ceede93fe3addda83fe2ebe2041f8a70b2521767044638fa29f")); + 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.string(), "erd10z9xdugayn528ksaesdwlhf006fw5sg2qmmm0h52fvxczwgesyvq5pwemr"); - ASSERT_EQ(bob.string(), "erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz"); - ASSERT_EQ(carol.string(), "erd19nu5t7hszckwah5nlcadmk5rlchtugzplznskffpwecygcu0520s9tnyy0"); + ASSERT_EQ(ALICE_BECH32, alice.string()); + ASSERT_EQ(BOB_BECH32, bob.string()); + ASSERT_EQ(CAROL_BECH32, carol.string()); } TEST(ElrondAddress, FromPrivateKey) { - auto privateKey = PrivateKey(parse_hex("0x6d893bc800f790261f814be252ee9bf51d6efc70e8c46dedc3f9357d06487b04")); + auto privateKey = PrivateKey(parse_hex(ALICE_PUBKEY_HEX)); auto address = Address(privateKey.getPublicKey(TWPublicKeyTypeED25519)); - ASSERT_EQ(address.string(), "erd10z9xdugayn528ksaesdwlhf006fw5sg2qmmm0h52fvxczwgesyvq5pwemr"); + ASSERT_EQ(ALICE_BECH32, address.string()); // TODO-Elrond: add more tests } TEST(ElrondAddress, FromPublicKey) { - auto publicKey = PublicKey(parse_hex("788a66f11d24e8a3da1dcc1aefdd2f7e92ea410a06f7b7de8a4b0d8139198118"), TWPublicKeyTypeED25519); - auto address = Address(publicKey); - ASSERT_EQ(address.string(), "erd10z9xdugayn528ksaesdwlhf006fw5sg2qmmm0h52fvxczwgesyvq5pwemr"); - // TODO-Elrond: add more tests + 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()); } From 11521d8bf5e94e8184d91b80a81f354418aa4de8 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Thu, 16 Apr 2020 17:33:52 +0000 Subject: [PATCH 12/25] Fix build, some tests --- src/Elrond/Signer.cpp | 2 ++ tests/Elrond/AddressTests.cpp | 27 +++++++++++++++++++-------- tests/Elrond/SignerTests.cpp | 16 ++++++++-------- tests/Elrond/TWAnySignerTests.cpp | 17 ++++++++++------- 4 files changed, 39 insertions(+), 23 deletions(-) diff --git a/src/Elrond/Signer.cpp b/src/Elrond/Signer.cpp index eb258c1c915..0e4aaf3fb52 100644 --- a/src/Elrond/Signer.cpp +++ b/src/Elrond/Signer.cpp @@ -10,6 +10,8 @@ #include "../PublicKey.h" #include "HexCoding.h" +#include + using namespace TW; using namespace TW::Elrond; diff --git a/tests/Elrond/AddressTests.cpp b/tests/Elrond/AddressTests.cpp index 868bf2a2a5b..ae1b4a53a20 100644 --- a/tests/Elrond/AddressTests.cpp +++ b/tests/Elrond/AddressTests.cpp @@ -14,13 +14,17 @@ using namespace TW; using namespace TW::Elrond; -const auto ALICE_BECH32 = "erd10z9xdugayn528ksaesdwlhf006fw5sg2qmmm0h52fvxczwgesyvq5pwemr"; -const auto ALICE_PUBKEY_HEX = "788a66f11d24e8a3da1dcc1aefdd2f7e92ea410a06f7b7de8a4b0d8139198118"; -const auto BOB_BECH32 = "erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz"; -const auto BOB_PUBKEY_HEX = "fd691bb5e85d102687d81079dffce842d4dc328276d2d4c60d8fd1c3433c3293"; +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"; + TEST(ElrondAddress, Valid) { ASSERT_TRUE(Address::isValid(ALICE_BECH32)); ASSERT_TRUE(Address::isValid(BOB_BECH32)); @@ -58,10 +62,17 @@ TEST(ElrondAddress, FromData) { } TEST(ElrondAddress, FromPrivateKey) { - auto privateKey = PrivateKey(parse_hex(ALICE_PUBKEY_HEX)); - auto address = Address(privateKey.getPublicKey(TWPublicKeyTypeED25519)); - ASSERT_EQ(ALICE_BECH32, address.string()); - // TODO-Elrond: add more tests + 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) { diff --git a/tests/Elrond/SignerTests.cpp b/tests/Elrond/SignerTests.cpp index 96d3fe86b27..7f82fdf1d56 100644 --- a/tests/Elrond/SignerTests.cpp +++ b/tests/Elrond/SignerTests.cpp @@ -19,7 +19,7 @@ using namespace TW::Elrond; TEST(ElrondSigner, Sign) { auto input = Proto::SigningInput(); auto privateKey = PrivateKey(parse_hex("1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf")); - input.set_private_key(privateKey.bytes.data(), privateKey.size()); + input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); input.mutable_transaction()->set_nonce(0); input.mutable_transaction()->set_value("0"); @@ -39,17 +39,17 @@ TEST(ElrondSigner, Sign) { TEST(ElrondSigner, SignJSON) { // Shuffle some fields, assume arbitrary order in the input - auto input = (R"({"data":"foo","value":"0","nonce":0,"receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000})" + auto input = R"({"data":"foo","value":"0","nonce":0,"receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000})"; auto privateKey = PrivateKey(parse_hex("1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf")); - auto signedTransaction = Signer::signJSON(input, privateKey); - ASSERT_EQ(R"({"nonce":0,"value":"0","receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000,"data":"foo","signature":"8912cd7310df084cffe67557ef93c8fd30048d00bb71ea5fe9f5ebb6d90194500122eab982d49c5c5c164e7012cb8d29279820f3e7e885a5fe31c5b2cce0e90a"})", signedTransaction); + auto signedTransaction = Signer::signJSON(input, privateKey.bytes); + //ASSERT_EQ(R"({"nonce":0,"value":"0","receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000,"data":"foo","signature":"8912cd7310df084cffe67557ef93c8fd30048d00bb71ea5fe9f5ebb6d90194500122eab982d49c5c5c164e7012cb8d29279820f3e7e885a5fe31c5b2cce0e90a"})", signedTransaction); } TEST(ElrondSigner, SignWithoutData) { auto input = Proto::SigningInput(); auto privateKey = PrivateKey(parse_hex("1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf")); - input.set_private_key(privateKey.bytes.data(), privateKey.size()); + input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); input.mutable_transaction()->set_nonce(0); input.mutable_transaction()->set_value("0"); @@ -69,9 +69,9 @@ TEST(ElrondSigner, SignWithoutData) { TEST(ElrondSigner, SignJSONWithoutData) { // Shuffle some fields, assume arbitrary order in the input - auto input = (R"({"data":"foo","value":"0","nonce":0,"receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000})" + auto input = R"({"data":"foo","value":"0","nonce":0,"receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000})"; auto privateKey = PrivateKey(parse_hex("1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf")); - auto signedTransaction = Signer::signJSON(input, privateKey); - ASSERT_EQ(R"({"nonce":0,"value":"0","receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000,"data":"","signature":"4e160bcafb6cb8ab8fc3260d3faf24bf7ce1205b5685adb457803db6d67c648a614308d8354e40b40fbb90c227046d6997493f798b92acb1b4bc49173939e703"})", signedTransaction); + auto signedTransaction = Signer::signJSON(input, privateKey.bytes); + //ASSERT_EQ(R"({"nonce":0,"value":"0","receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000,"data":"","signature":"4e160bcafb6cb8ab8fc3260d3faf24bf7ce1205b5685adb457803db6d67c648a614308d8354e40b40fbb90c227046d6997493f798b92acb1b4bc49173939e703"})", signedTransaction); } diff --git a/tests/Elrond/TWAnySignerTests.cpp b/tests/Elrond/TWAnySignerTests.cpp index 18e36d7a8f9..965d6d39261 100644 --- a/tests/Elrond/TWAnySignerTests.cpp +++ b/tests/Elrond/TWAnySignerTests.cpp @@ -10,13 +10,16 @@ #include "../interface/TWTestUtilities.h" #include +#include "Elrond/Signer.h" + using namespace TW; +using namespace TW::Elrond; TEST(TWAnySignerElrond, Sign) { auto input = Proto::SigningInput(); auto privateKey = PrivateKey(parse_hex("1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf")); - input.set_private_key(privateKey.bytes.data(), privateKey.size()); + input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); input.mutable_transaction()->set_nonce(0); input.mutable_transaction()->set_value("0"); @@ -34,11 +37,11 @@ TEST(TWAnySignerElrond, Sign) { } TEST(TWAnySignerElrond, SignJSON) { - // Shuffle some fields, assume arbitrary order in the input - auto input = (R"({"data":"foo","value":"0","nonce":0,"receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000})" - auto privateKey = PrivateKey(parse_hex("1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf")); - auto signedTransaction = TWAnySignerSignJSON(json.get(), privateKey.get(), TWCoinTypeElrond) + // // Shuffle some fields, assume arbitrary order in the input + // auto input = R"({"data":"foo","value":"0","nonce":0,"receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000})"; + // auto privateKey = PrivateKey(parse_hex("1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf")); + // auto signedTransaction = TWAnySignerSignJSON(input, &privateKey.bytes, TWCoinTypeElrond); - ASSERT_TRUE(TWAnySignerSupportsJSON(TWCoinTypeElrond)); - ASSERT_EQ(R"({"nonce":0,"value":"0","receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000,"data":"foo","signature":"8912cd7310df084cffe67557ef93c8fd30048d00bb71ea5fe9f5ebb6d90194500122eab982d49c5c5c164e7012cb8d29279820f3e7e885a5fe31c5b2cce0e90a"})", signedTransaction); + // ASSERT_TRUE(TWAnySignerSupportsJSON(TWCoinTypeElrond)); + // ASSERT_EQ(R"({"nonce":0,"value":"0","receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000,"data":"foo","signature":"8912cd7310df084cffe67557ef93c8fd30048d00bb71ea5fe9f5ebb6d90194500122eab982d49c5c5c164e7012cb8d29279820f3e7e885a5fe31c5b2cce0e90a"})", signedTransaction); } From 288498cd5cf8f73739c20c25ce9de22e34ef30a8 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Thu, 16 Apr 2020 18:03:28 +0000 Subject: [PATCH 13/25] Fix tests. --- tests/Elrond/SignerTests.cpp | 8 ++++---- tests/Elrond/TWAnySignerTests.cpp | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/Elrond/SignerTests.cpp b/tests/Elrond/SignerTests.cpp index 7f82fdf1d56..154109f5dcc 100644 --- a/tests/Elrond/SignerTests.cpp +++ b/tests/Elrond/SignerTests.cpp @@ -39,11 +39,11 @@ TEST(ElrondSigner, Sign) { TEST(ElrondSigner, SignJSON) { // Shuffle some fields, assume arbitrary order in the input - auto input = R"({"data":"foo","value":"0","nonce":0,"receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000})"; + auto input = R"({"transaction" : {"data":"foo","value":"0","nonce":0,"receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000}})"; auto privateKey = PrivateKey(parse_hex("1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf")); auto signedTransaction = Signer::signJSON(input, privateKey.bytes); - //ASSERT_EQ(R"({"nonce":0,"value":"0","receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000,"data":"foo","signature":"8912cd7310df084cffe67557ef93c8fd30048d00bb71ea5fe9f5ebb6d90194500122eab982d49c5c5c164e7012cb8d29279820f3e7e885a5fe31c5b2cce0e90a"})", signedTransaction); + ASSERT_EQ(R"({"nonce":0,"value":"0","receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000,"data":"foo","signature":"8912cd7310df084cffe67557ef93c8fd30048d00bb71ea5fe9f5ebb6d90194500122eab982d49c5c5c164e7012cb8d29279820f3e7e885a5fe31c5b2cce0e90a"})", signedTransaction); } TEST(ElrondSigner, SignWithoutData) { @@ -69,9 +69,9 @@ TEST(ElrondSigner, SignWithoutData) { TEST(ElrondSigner, SignJSONWithoutData) { // Shuffle some fields, assume arbitrary order in the input - auto input = R"({"data":"foo","value":"0","nonce":0,"receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000})"; + auto input = R"({"transaction" : {"value":"0","nonce":0,"receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000}})"; auto privateKey = PrivateKey(parse_hex("1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf")); auto signedTransaction = Signer::signJSON(input, privateKey.bytes); - //ASSERT_EQ(R"({"nonce":0,"value":"0","receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000,"data":"","signature":"4e160bcafb6cb8ab8fc3260d3faf24bf7ce1205b5685adb457803db6d67c648a614308d8354e40b40fbb90c227046d6997493f798b92acb1b4bc49173939e703"})", signedTransaction); + ASSERT_EQ(R"({"nonce":0,"value":"0","receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000,"data":"","signature":"4e160bcafb6cb8ab8fc3260d3faf24bf7ce1205b5685adb457803db6d67c648a614308d8354e40b40fbb90c227046d6997493f798b92acb1b4bc49173939e703"})", signedTransaction); } diff --git a/tests/Elrond/TWAnySignerTests.cpp b/tests/Elrond/TWAnySignerTests.cpp index 965d6d39261..04af3c19d6a 100644 --- a/tests/Elrond/TWAnySignerTests.cpp +++ b/tests/Elrond/TWAnySignerTests.cpp @@ -37,11 +37,11 @@ TEST(TWAnySignerElrond, Sign) { } TEST(TWAnySignerElrond, SignJSON) { - // // Shuffle some fields, assume arbitrary order in the input - // auto input = R"({"data":"foo","value":"0","nonce":0,"receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000})"; - // auto privateKey = PrivateKey(parse_hex("1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf")); - // auto signedTransaction = TWAnySignerSignJSON(input, &privateKey.bytes, TWCoinTypeElrond); + // Shuffle some fields, assume arbitrary order in the input + auto input = STRING(R"({"transaction" : {"data":"foo","value":"0","nonce":0,"receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000}})"); + auto privateKey = DATA("1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf"); + auto signedTransaction = WRAPS(TWAnySignerSignJSON(input.get(), privateKey.get(), TWCoinTypeElrond)); - // ASSERT_TRUE(TWAnySignerSupportsJSON(TWCoinTypeElrond)); - // ASSERT_EQ(R"({"nonce":0,"value":"0","receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000,"data":"foo","signature":"8912cd7310df084cffe67557ef93c8fd30048d00bb71ea5fe9f5ebb6d90194500122eab982d49c5c5c164e7012cb8d29279820f3e7e885a5fe31c5b2cce0e90a"})", signedTransaction); + ASSERT_TRUE(TWAnySignerSupportsJSON(TWCoinTypeElrond)); + assertStringsEqual(signedTransaction, R"({"nonce":0,"value":"0","receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000,"data":"foo","signature":"8912cd7310df084cffe67557ef93c8fd30048d00bb71ea5fe9f5ebb6d90194500122eab982d49c5c5c164e7012cb8d29279820f3e7e885a5fe31c5b2cce0e90a"})"); } From a7078fe4a0684322a7d6d9a37cdae7e99072dbec Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Thu, 16 Apr 2020 19:16:20 +0000 Subject: [PATCH 14/25] Improve tests, cleanup --- tests/Elrond/AddressTests.cpp | 18 +++------- tests/Elrond/SerializationTests.cpp | 16 +++++---- tests/Elrond/SignerTests.cpp | 52 ++++++++++++++++++----------- tests/Elrond/TWAnyAddressTests.cpp | 19 ----------- tests/Elrond/TWAnySignerTests.cpp | 30 +++++++++++------ tests/Elrond/TestAccounts.h | 11 ++++++ 6 files changed, 77 insertions(+), 69 deletions(-) delete mode 100644 tests/Elrond/TWAnyAddressTests.cpp create mode 100644 tests/Elrond/TestAccounts.h diff --git a/tests/Elrond/AddressTests.cpp b/tests/Elrond/AddressTests.cpp index ae1b4a53a20..936e66ade83 100644 --- a/tests/Elrond/AddressTests.cpp +++ b/tests/Elrond/AddressTests.cpp @@ -4,26 +4,18 @@ // 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 "Elrond/Address.h" #include "PublicKey.h" #include "PrivateKey.h" -#include -#include +#include "Elrond/Address.h" +#include "TestAccounts.h" using namespace TW; using namespace TW::Elrond; -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"; - TEST(ElrondAddress, Valid) { ASSERT_TRUE(Address::isValid(ALICE_BECH32)); diff --git a/tests/Elrond/SerializationTests.cpp b/tests/Elrond/SerializationTests.cpp index 2f28df7fa17..617601c24f5 100644 --- a/tests/Elrond/SerializationTests.cpp +++ b/tests/Elrond/SerializationTests.cpp @@ -4,10 +4,13 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "HexCoding.h" -#include "Elrond/Serialization.h" #include #include +#include "boost/format.hpp" + +#include "HexCoding.h" +#include "Elrond/Serialization.h" +#include "TestAccounts.h" using namespace TW; using namespace TW::Elrond; @@ -28,14 +31,15 @@ TEST(ElrondSerialization, SignableStringWithRealData) { Proto::TransactionMessage message; message.set_nonce(15); message.set_value("100"); - message.set_sender("erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz"); - message.set_receiver("erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr"); + 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 jsonString = serializeTransactionToSignableString(message); - ASSERT_EQ(R"({"nonce":15,"value":"100","receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000,"data":"Zm9yIGRpbm5lcg=="})", jsonString); + 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 = serializeTransactionToSignableString(message); + ASSERT_EQ(expected, actual); } TEST(ElrondSerialization, SignableStringWithoutData) { diff --git a/tests/Elrond/SignerTests.cpp b/tests/Elrond/SignerTests.cpp index 154109f5dcc..b74e30ac9f1 100644 --- a/tests/Elrond/SignerTests.cpp +++ b/tests/Elrond/SignerTests.cpp @@ -4,13 +4,15 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "Elrond/Signer.h" -#include "Elrond/Address.h" +#include +#include "boost/format.hpp" + #include "HexCoding.h" #include "PrivateKey.h" #include "PublicKey.h" - -#include +#include "Elrond/Signer.h" +#include "Elrond/Address.h" +#include "TestAccounts.h" using namespace TW; using namespace TW::Elrond; @@ -18,13 +20,13 @@ using namespace TW::Elrond; TEST(ElrondSigner, Sign) { auto input = Proto::SigningInput(); - auto privateKey = PrivateKey(parse_hex("1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf")); + 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("erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz"); - input.mutable_transaction()->set_receiver("erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr"); + 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"); @@ -32,29 +34,34 @@ TEST(ElrondSigner, Sign) { auto output = Signer::sign(input); auto signature = output.signature(); auto signedTransaction = output.signed_transaction(); + auto expectedSignature = "b88ad2fe98a7316ea432a0a76c18cd87200fe75f27a8f053ea6532b40317dbec5136c5463aef132ae951b7e60d45d921caaa5903e70821dcda98f237d4ec4308"; + auto expectedSignedTransaction = (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("8912cd7310df084cffe67557ef93c8fd30048d00bb71ea5fe9f5ebb6d90194500122eab982d49c5c5c164e7012cb8d29279820f3e7e885a5fe31c5b2cce0e90a", signature); - ASSERT_EQ(R"({"nonce":0,"value":"0","receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000,"data":"foo","signature":"8912cd7310df084cffe67557ef93c8fd30048d00bb71ea5fe9f5ebb6d90194500122eab982d49c5c5c164e7012cb8d29279820f3e7e885a5fe31c5b2cce0e90a"})", signedTransaction); + ASSERT_EQ(expectedSignature, signature); + ASSERT_EQ(expectedSignedTransaction, signedTransaction); } TEST(ElrondSigner, SignJSON) { // Shuffle some fields, assume arbitrary order in the input - auto input = R"({"transaction" : {"data":"foo","value":"0","nonce":0,"receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000}})"; - auto privateKey = PrivateKey(parse_hex("1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf")); + 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 signedTransaction = Signer::signJSON(input, privateKey.bytes); - ASSERT_EQ(R"({"nonce":0,"value":"0","receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000,"data":"foo","signature":"8912cd7310df084cffe67557ef93c8fd30048d00bb71ea5fe9f5ebb6d90194500122eab982d49c5c5c164e7012cb8d29279820f3e7e885a5fe31c5b2cce0e90a"})", signedTransaction); + auto expectedSignature = "b88ad2fe98a7316ea432a0a76c18cd87200fe75f27a8f053ea6532b40317dbec5136c5463aef132ae951b7e60d45d921caaa5903e70821dcda98f237d4ec4308"; + auto expectedSignedTransaction = (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(expectedSignedTransaction, signedTransaction); } TEST(ElrondSigner, SignWithoutData) { auto input = Proto::SigningInput(); - auto privateKey = PrivateKey(parse_hex("1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf")); + 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("erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz"); - input.mutable_transaction()->set_receiver("erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr"); + 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(""); @@ -62,16 +69,21 @@ TEST(ElrondSigner, SignWithoutData) { auto output = Signer::sign(input); auto signature = output.signature(); auto signedTransaction = output.signed_transaction(); + auto expectedSignature = "39ab0e18bfce04bf53c9610faa3b9e7cecfca919510a7631e529e9086279b70a4832df32a5d1b8fdceb4e9082f2995da97f9195532c8d611ee749bc312cbf90c"; + auto expectedSignedTransaction = (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("4e160bcafb6cb8ab8fc3260d3faf24bf7ce1205b5685adb457803db6d67c648a614308d8354e40b40fbb90c227046d6997493f798b92acb1b4bc49173939e703", signature); - ASSERT_EQ(R"({"nonce":0,"value":"0","receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000,"data":"","signature":"4e160bcafb6cb8ab8fc3260d3faf24bf7ce1205b5685adb457803db6d67c648a614308d8354e40b40fbb90c227046d6997493f798b92acb1b4bc49173939e703"})", signedTransaction); + ASSERT_EQ(expectedSignature, signature); + ASSERT_EQ(expectedSignedTransaction, signedTransaction); } TEST(ElrondSigner, SignJSONWithoutData) { // Shuffle some fields, assume arbitrary order in the input - auto input = R"({"transaction" : {"value":"0","nonce":0,"receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000}})"; - auto privateKey = PrivateKey(parse_hex("1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf")); + 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 signedTransaction = Signer::signJSON(input, privateKey.bytes); - ASSERT_EQ(R"({"nonce":0,"value":"0","receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000,"data":"","signature":"4e160bcafb6cb8ab8fc3260d3faf24bf7ce1205b5685adb457803db6d67c648a614308d8354e40b40fbb90c227046d6997493f798b92acb1b4bc49173939e703"})", signedTransaction); + auto expectedSignature = "39ab0e18bfce04bf53c9610faa3b9e7cecfca919510a7631e529e9086279b70a4832df32a5d1b8fdceb4e9082f2995da97f9195532c8d611ee749bc312cbf90c"; + auto expectedSignedTransaction = (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(expectedSignedTransaction, signedTransaction); } diff --git a/tests/Elrond/TWAnyAddressTests.cpp b/tests/Elrond/TWAnyAddressTests.cpp deleted file mode 100644 index 10ec72f026b..00000000000 --- a/tests/Elrond/TWAnyAddressTests.cpp +++ /dev/null @@ -1,19 +0,0 @@ -// 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 "HexCoding.h" - -#include "../interface/TWTestUtilities.h" -#include - -using namespace TW; - -// TODO: Finalize tests - -TEST(TWElrond, Address) { - // TODO: Finalize test implementation -} diff --git a/tests/Elrond/TWAnySignerTests.cpp b/tests/Elrond/TWAnySignerTests.cpp index 04af3c19d6a..0caa6df7970 100644 --- a/tests/Elrond/TWAnySignerTests.cpp +++ b/tests/Elrond/TWAnySignerTests.cpp @@ -4,13 +4,14 @@ // 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 - #include "Elrond/Signer.h" +#include "TestAccounts.h" using namespace TW; using namespace TW::Elrond; @@ -18,13 +19,13 @@ using namespace TW::Elrond; TEST(TWAnySignerElrond, Sign) { auto input = Proto::SigningInput(); - auto privateKey = PrivateKey(parse_hex("1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf")); + 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("erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz"); - input.mutable_transaction()->set_receiver("erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr"); + 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"); @@ -32,16 +33,23 @@ TEST(TWAnySignerElrond, Sign) { Proto::SigningOutput output; ANY_SIGN(input, TWCoinTypeElrond); - ASSERT_EQ("8912cd7310df084cffe67557ef93c8fd30048d00bb71ea5fe9f5ebb6d90194500122eab982d49c5c5c164e7012cb8d29279820f3e7e885a5fe31c5b2cce0e90a", output.signature()); - ASSERT_EQ(R"({"nonce":0,"value":"0","receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000,"data":"foo","signature":"8912cd7310df084cffe67557ef93c8fd30048d00bb71ea5fe9f5ebb6d90194500122eab982d49c5c5c164e7012cb8d29279820f3e7e885a5fe31c5b2cce0e90a"})", output.signed_transaction()); + auto signature = output.signature(); + auto signedTransaction = output.signed_transaction(); + auto expectedSignature = "b88ad2fe98a7316ea432a0a76c18cd87200fe75f27a8f053ea6532b40317dbec5136c5463aef132ae951b7e60d45d921caaa5903e70821dcda98f237d4ec4308"; + auto expectedSignedTransaction = (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(expectedSignedTransaction, signedTransaction); } TEST(TWAnySignerElrond, SignJSON) { // Shuffle some fields, assume arbitrary order in the input - auto input = STRING(R"({"transaction" : {"data":"foo","value":"0","nonce":0,"receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000}})"); - auto privateKey = DATA("1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf"); + 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 signedTransaction = WRAPS(TWAnySignerSignJSON(input.get(), privateKey.get(), TWCoinTypeElrond)); + auto expectedSignature = "b88ad2fe98a7316ea432a0a76c18cd87200fe75f27a8f053ea6532b40317dbec5136c5463aef132ae951b7e60d45d921caaa5903e70821dcda98f237d4ec4308"; + auto expectedSignedTransaction = (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(signedTransaction, R"({"nonce":0,"value":"0","receiver":"erd188nydpkagtpwvfklkl2tn0w6g40zdxkwfgwpjqc2a2m2n7ne9g8q2t22sr","sender":"erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz","gasPrice":200000000000000,"gasLimit":500000000,"data":"foo","signature":"8912cd7310df084cffe67557ef93c8fd30048d00bb71ea5fe9f5ebb6d90194500122eab982d49c5c5c164e7012cb8d29279820f3e7e885a5fe31c5b2cce0e90a"})"); + assertStringsEqual(signedTransaction, expectedSignedTransaction.c_str()); } diff --git a/tests/Elrond/TestAccounts.h b/tests/Elrond/TestAccounts.h new file mode 100644 index 00000000000..cdb46d6bc7d --- /dev/null +++ b/tests/Elrond/TestAccounts.h @@ -0,0 +1,11 @@ +#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"; \ No newline at end of file From e30ab996ecdeb2e5d1d7be95c0842d377698ea36 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Thu, 16 Apr 2020 19:39:39 +0000 Subject: [PATCH 15/25] Kotlin tests. --- .../blockchains/elrond/TestElrondAddress.kt | 29 +++++++--- .../blockchains/elrond/TestElrondSigner.kt | 53 +++++++++++++------ 2 files changed, 59 insertions(+), 23 deletions(-) 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 index 190a6e53527..15cdd2c1e9a 100644 --- 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 @@ -18,16 +18,33 @@ class TestElrondAddress { System.loadLibrary("TrustWalletCore") } - @Test - fun testAddress() { - // TODO: Check and finalize implementation + val aliceBech32 = "erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz" + var aliceSeedHex = "1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf" + var alicePubKeyHex = "fd691bb5e85d102687d81079dffce842d4dc328276d2d4c60d8fd1c3433c3293" - val key = PrivateKey("__PRIVATE_KEY_DATA__".toHexByteArray()) + @Test + fun testAddressFromPrivateKey() { + val key = PrivateKey(aliceSeedHex.toHexByteArray()) val pubkey = key.publicKeyEd25519 val address = AnyAddress(pubkey, CoinType.ELROND) - val expected = AnyAddress("__EXPECTED_RESULT_ADDRESS__", CoinType.ELROND) + val expected = AnyAddress(aliceBech32, CoinType.ELROND) - assertEquals(pubkey.data().toHex(), "0x__EXPECTED_PUBKEY_DATA__") + assertEquals(pubkey.data().toHex(), alicePubKey) assertEquals(address.description(), expected.description()) } + + @Test + fun testAddressFromPublicKey() { + val pubkey = PublicKey(alicePubKeyHex.toHexByteArray(), PublicKeyType.ED25519) + val address = AnyAddress(pubkey, CoinType.ELROND) + + assertEquals(address.description(), aliceBech32) + } + + @Test + fun testAddressFromString() { + val address = AnyAddress(aliceBech32, CoinType.ELROND) + + assertEquals(address.description(), aliceBech32) + } } 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 index a6ccb9395fb..f905191a32e 100644 --- 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 @@ -22,24 +22,43 @@ class TestElrondSigner { System.loadLibrary("TrustWalletCore") } + val aliceBech32 = "erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz" + var aliceSeedHex = "1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf" + var alicePubKeyHex = "fd691bb5e85d102687d81079dffce842d4dc328276d2d4c60d8fd1c3433c3293" + + val bobBech32 = "erd1cux02zersde0l7hhklzhywcxk4u9n4py5tdxyx7vrvhnza2r4gmq4vw35r" + var bobSeedHex = "e3a3a3d1ac40d42d8fd4c569a9749b65a1250dd3d10b6f4e438297662ea4850e" + var bobPubKeyHex = "c70cf50b238372fffaf7b7c5723b06b57859d424a2da621bcc1b2f317543aa36" + @Test fun ElrondTransactionSigning() { - // TODO: Finalize implementation - - //val transfer = Elrond.TransferMessage.newBuilder() - // .setTo("...") - // .setAmount(...) - // ... - // .build() - //val signingInput = Elrond.SigningInput.newBuilder() - // ... - // .build() - - //val output: Elrond.SigningOutput = ElrondSigner.sign(signingInput) - - //assertEquals( - // "__EXPECTED_RESULT_DATA__", - // Numeric.toHexString(output.encoded.toByteArray()) - //) + val transaction = Elrond.TransactionMessage.newBuilder() + .setNonce(0) + .setValue("0") + .setSender(aliceBech32) + .setReceiver(bobBech32) + .setGasPrice(200000000000000) + .setGasLimit(500000000) + .setData("foo) + .build() + + var aliceKey = ByteString.copyFrom(PrivateKey(aliceSeedHex.toHexByteArray()).data()) + + val signingInput = Elrond.SigningInput.newBuilder() + .setPrivateKey(aliceKey) + .setTransaction(transaction) + .build() + + val output: Elrond.SigningOutput = ElrondSigner.sign(signingInput) + + assertEquals( + "b88ad2fe98a7316ea432a0a76c18cd87200fe75f27a8f053ea6532b40317dbec5136c5463aef132ae951b7e60d45d921caaa5903e70821dcda98f237d4ec4308", + Numeric.toHexString(output.signature.toByteArray()) + ) + + // TODO: + // val sign = AnySigner.sign(signingInput.build(), ELROND, SigningOutput.parser()) + // val signBytes = sign.signature + // assertEquals(signBytes, "") } } From f6876b5d03677fcd4100734053934cf5d99ee9cc Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Thu, 16 Apr 2020 23:49:07 +0300 Subject: [PATCH 16/25] Fix kotlin tests. --- .../blockchains/CoinAddressDerivationTests.kt | 1 + .../blockchains/elrond/TestElrondAddress.kt | 22 +++++++------- .../blockchains/elrond/TestElrondSigner.kt | 29 +++++++------------ 3 files changed, 23 insertions(+), 29 deletions(-) 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..6916f633b04 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("erd1hwnmlzs8kvtsf248m7j7zp9hklncesemq8awv530y42r8s9y27rse5hfw0", 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 index 15cdd2c1e9a..692414cb28c 100644 --- 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 @@ -18,33 +18,33 @@ class TestElrondAddress { System.loadLibrary("TrustWalletCore") } - val aliceBech32 = "erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz" - var aliceSeedHex = "1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf" - var alicePubKeyHex = "fd691bb5e85d102687d81079dffce842d4dc328276d2d4c60d8fd1c3433c3293" + 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) + val pubKey = key.publicKeyEd25519 + val address = AnyAddress(pubKey, CoinType.ELROND) val expected = AnyAddress(aliceBech32, CoinType.ELROND) - assertEquals(pubkey.data().toHex(), alicePubKey) - assertEquals(address.description(), expected.description()) + assertEquals(alicePubKeyHex, pubKey.data().toHex()) + assertEquals(expected.description(), address.description()) } @Test fun testAddressFromPublicKey() { - val pubkey = PublicKey(alicePubKeyHex.toHexByteArray(), PublicKeyType.ED25519) - val address = AnyAddress(pubkey, CoinType.ELROND) + val pubKey = PublicKey(alicePubKeyHex.toHexByteArray(), PublicKeyType.ED25519) + val address = AnyAddress(pubKey, CoinType.ELROND) - assertEquals(address.description(), aliceBech32) + assertEquals(aliceBech32, address.description()) } @Test fun testAddressFromString() { val address = AnyAddress(aliceBech32, CoinType.ELROND) - assertEquals(address.description(), aliceBech32) + 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 index f905191a32e..1fd627122ca 100644 --- 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 @@ -7,13 +7,12 @@ package com.trustwallet.core.app.blockchains.elrond import com.google.protobuf.ByteString -import com.trustwallet.core.app.utils.Numeric import com.trustwallet.core.app.utils.toHexByteArray -import com.trustwallet.core.app.utils.toHexBytes -import com.trustwallet.core.app.utils.toHexBytesInByteString import junit.framework.Assert.assertEquals import org.junit.Test -import wallet.core.jni.ElrondSigner +import wallet.core.java.AnySigner +import wallet.core.jni.CoinType +import wallet.core.jni.PrivateKey import wallet.core.jni.proto.Elrond class TestElrondSigner { @@ -31,7 +30,7 @@ class TestElrondSigner { var bobPubKeyHex = "c70cf50b238372fffaf7b7c5723b06b57859d424a2da621bcc1b2f317543aa36" @Test - fun ElrondTransactionSigning() { + fun signTransaction() { val transaction = Elrond.TransactionMessage.newBuilder() .setNonce(0) .setValue("0") @@ -39,26 +38,20 @@ class TestElrondSigner { .setReceiver(bobBech32) .setGasPrice(200000000000000) .setGasLimit(500000000) - .setData("foo) + .setData("foo") .build() - var aliceKey = ByteString.copyFrom(PrivateKey(aliceSeedHex.toHexByteArray()).data()) + val privateKey = ByteString.copyFrom(PrivateKey(aliceSeedHex.toHexByteArray()).data()) val signingInput = Elrond.SigningInput.newBuilder() - .setPrivateKey(aliceKey) + .setPrivateKey(privateKey) .setTransaction(transaction) .build() - val output: Elrond.SigningOutput = ElrondSigner.sign(signingInput) + val output = AnySigner.sign(signingInput, CoinType.ELROND, Elrond.SigningOutput.parser()) + val expectedSignature = "b88ad2fe98a7316ea432a0a76c18cd87200fe75f27a8f053ea6532b40317dbec5136c5463aef132ae951b7e60d45d921caaa5903e70821dcda98f237d4ec4308" - assertEquals( - "b88ad2fe98a7316ea432a0a76c18cd87200fe75f27a8f053ea6532b40317dbec5136c5463aef132ae951b7e60d45d921caaa5903e70821dcda98f237d4ec4308", - Numeric.toHexString(output.signature.toByteArray()) - ) - - // TODO: - // val sign = AnySigner.sign(signingInput.build(), ELROND, SigningOutput.parser()) - // val signBytes = sign.signature - // assertEquals(signBytes, "") + assertEquals(expectedSignature, output.signature) + assertEquals("""{"nonce":0,"value":"0","receiver":"$bobBech32","sender":"$aliceBech32","gasPrice":200000000000000,"gasLimit":500000000,"data":"foo","signature":"$expectedSignature"}""", output.signedTransaction) } } From e1db311679666c6de4921d56af79b732692e866b Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Fri, 17 Apr 2020 09:34:45 +0000 Subject: [PATCH 17/25] Extend tests. --- swift/Tests/CoinAddressDerivationTests.swift | 3 +++ tests/interface/TWHRPTests.cpp | 3 +++ 2 files changed, 6 insertions(+) diff --git a/swift/Tests/CoinAddressDerivationTests.swift b/swift/Tests/CoinAddressDerivationTests.swift index 81b55b548ed..bb106e63025 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 = "erd1hwnmlzs8kvtsf248m7j7zp9hklncesemq8awv530y42r8s9y27rse5hfw0" + AssetCoinDerivation(coin, expectedResult, derivedAddress, address) @unknown default: fatalError() } 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)); From b2b46402f8e9c28f63894e14389727b1bebdab14 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Fri, 17 Apr 2020 09:46:09 +0000 Subject: [PATCH 18/25] Added test. --- tests/CoinAddressDerivationTests.cpp | 1 + 1 file changed, 1 insertion(+) 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 From 6a87793571213ca20dd09c451e6dbbdaf3fae0d2 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Fri, 17 Apr 2020 09:49:00 +0000 Subject: [PATCH 19/25] Add test. --- tests/CoinAddressValidationTests.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/CoinAddressValidationTests.cpp b/tests/CoinAddressValidationTests.cpp index 7b08cf9f61b..76d0f9fd36c 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, "terd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz")); +} + + } // namespace TW From d205f60129410fa1039403da7a5db1e1bef718c9 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Fri, 17 Apr 2020 12:37:20 +0000 Subject: [PATCH 20/25] Add test. --- tests/interface/TWHDWalletTests.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/interface/TWHDWalletTests.cpp b/tests/interface/TWHDWalletTests.cpp index 62f67695f0e..aef46e54518 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, "7a0b6d3ec4c1f0512be7304636bb7caad52e9c2eeb0d627022b659173f6ad502"); + assertStringsEqual(address, "erd140x7c0mcpveh2ln0r2egzg72mxe3a8h4xcc6s4t9mtuxerzt3nxsq5xq0v"); +} + 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())); From 57dbf7c837388c1c47b401766de77c9191c1f4d7 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Fri, 17 Apr 2020 12:52:10 +0000 Subject: [PATCH 21/25] Add test. --- tests/Bech32AddressTests.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/Bech32AddressTests.cpp b/tests/Bech32AddressTests.cpp index ff425cb7c4f..71e8f63274a 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("terd19nu5t7hszckwah5nlcadmk5rlchtugzplznskffpwecygcu0520s9tnyy0", "erd")); } TEST(Bech32Address, InvalidWrongPrefix) { From 6ce0131df8a3b7cc0b01254d66aa5c94f2bff08d Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Mon, 20 Apr 2020 14:48:11 +0000 Subject: [PATCH 22/25] Implementation and test for any address. --- src/interface/TWAnyAddress.cpp | 11 +++++++++++ tests/interface/TWAnyAddressTests.cpp | 7 +++++++ 2 files changed, 18 insertions(+) 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/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"); + } } From 569e1afa514ef5d769dbd361c4ebcb70659610ed Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Mon, 20 Apr 2020 15:16:50 +0000 Subject: [PATCH 23/25] Add tests in ElrondTests.swift. --- swift/Tests/Blockchains/ElrondTests.swift | 35 ++++++++++++++++++----- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/swift/Tests/Blockchains/ElrondTests.swift b/swift/Tests/Blockchains/ElrondTests.swift index 0ed019d0bea..c051c32facd 100644 --- a/swift/Tests/Blockchains/ElrondTests.swift +++ b/swift/Tests/Blockchains/ElrondTests.swift @@ -8,21 +8,42 @@ import TrustWalletCore import XCTest class ElrondTests: XCTestCase { - // TODO: Check and finalize implementation - func testAddress() { - // TODO: Check and finalize implementation + let aliceBech32 = "erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz" + let aliceSeedHex = "1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf" + let alicePubKeyHex = "fd691bb5e85d102687d81079dffce842d4dc328276d2d4c60d8fd1c3433c3293" + let bobBech32 = "erd1cux02zersde0l7hhklzhywcxk4u9n4py5tdxyx7vrvhnza2r4gmq4vw35r" - let key = PrivateKey(data: Data(hexString: "__PRIVATE_KEY_DATA__")!)! + func testAddress() { + let key = PrivateKey(data: Data(hexString: aliceSeedHex)!)! let pubkey = key.getPublicKeyEd25519() let address = AnyAddress(publicKey: pubkey, coin: .elrond) - let addressFromString = AnyAddress(string: "__ADDRESS_DATA__", coin: .elrond)! + let addressFromString = AnyAddress(string: aliceBech32, coin: .elrond)! - XCTAssertEqual(pubkey.data.hexString, "__EXPECTED_PUBKEY_DATA__") + XCTAssertEqual(pubkey.data.hexString, alicePubKeyHex) XCTAssertEqual(address.description, addressFromString.description) } func testSign() { - // TODO: Create implementation + 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" + + XCTAssertEqual(output.signature, expectedSignature) } } From 717e35cece58d8c95f6ae497dcff812e4749abf4 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Thu, 23 Apr 2020 11:00:58 +0000 Subject: [PATCH 24/25] Fix after review --- .../core/app/blockchains/CoinAddressDerivationTests.kt | 2 +- coins.json | 4 ++-- docs/coins.md | 2 +- include/TrustWalletCore/TWCoinType.h | 2 +- src/Elrond/Signer.cpp | 6 +++--- swift/Tests/CoinAddressDerivationTests.swift | 2 +- tests/Bech32AddressTests.cpp | 2 +- tests/CoinAddressValidationTests.cpp | 2 +- tests/Elrond/AddressTests.cpp | 2 +- tests/Elrond/TestAccounts.h | 2 +- tests/interface/TWHDWalletTests.cpp | 4 ++-- 11 files changed, 15 insertions(+), 15 deletions(-) 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 6916f633b04..810d8e30fc9 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,6 +83,6 @@ class CoinAddressDerivationTests { CARDANO -> assertEquals("addr1snpa4z7ntyfszv7ckquprdw75w4qjqh0qmya9jtkpxxlzxghlqyvv7l0yjamh8fxraw06p3ua8sj2g2gv98v4849s43t9g2999kquuu5egnprk", address) NEO -> assertEquals("AT6w7PJvwPcSqHvtbNBY2aHPDv12eW5Uuf", address) FILECOIN -> assertEquals("f1zzykebxldfcakj5wdb5n3n7priul522fnmjzori", address) - ELROND -> assertEquals("erd1hwnmlzs8kvtsf248m7j7zp9hklncesemq8awv530y42r8s9y27rse5hfw0", address) + ELROND -> assertEquals("erd1k3hzqq8yffrsr86238r3avwq6w0kfgtwrjwhf72n07kxyk4nzwxqvm47d2", address) } } diff --git a/coins.json b/coins.json index e49e6061e6f..9c309f1f57d 100644 --- a/coins.json +++ b/coins.json @@ -1337,7 +1337,7 @@ "symbol": "ERD", "decimals": 18, "blockchain": "ElrondNetwork", - "derivationPath": "m/44'/2003'/0'", + "derivationPath": "m/44'/508'/0'", "curve": "ed25519", "publicKeyType": "ed25519", "hrp": "erd", @@ -1349,7 +1349,7 @@ "info": { "url": "https://elrond.com/", "client": "https://github.com/ElrondNetwork/elrond-go", - "clientPublic": "https://wallet-api.elrond.com", + "clientPublic": "https://api.elrond.com", "clientDocs": "https://docs.elrond.com" } } diff --git a/docs/coins.md b/docs/coins.md index 34fc429d2ee..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 | | | @@ -53,7 +54,6 @@ This list is generated from [./coins.json](../coins.json) | 1024 | Ontology | ONT | | | | 1729 | Tezos | XTZ | | | | 1815 | Cardano | ADA | | | -| 2003 | Elrond | ERD | | | | 2017 | Kin | KIN | | | | 2301 | Qtum | QTUM | | | | 2718 | Nebulas | NAS | | | diff --git a/include/TrustWalletCore/TWCoinType.h b/include/TrustWalletCore/TWCoinType.h index 00f9d6b1e96..bf70c377ee9 100644 --- a/include/TrustWalletCore/TWCoinType.h +++ b/include/TrustWalletCore/TWCoinType.h @@ -79,7 +79,7 @@ enum TWCoinType { TWCoinTypeKusama = 434, TWCoinTypePolkadot = 354, TWCoinTypeFilecoin = 461, - TWCoinTypeElrond = 2003, + TWCoinTypeElrond = 508, }; /// Returns the blockchain for a coin type. diff --git a/src/Elrond/Signer.cpp b/src/Elrond/Signer.cpp index 0e4aaf3fb52..1e4257a5bd6 100644 --- a/src/Elrond/Signer.cpp +++ b/src/Elrond/Signer.cpp @@ -18,11 +18,11 @@ using namespace TW::Elrond; Proto::SigningOutput Signer::sign(const Proto::SigningInput &input) noexcept { auto privateKey = PrivateKey(input.private_key()); - auto signableAsString = Elrond::serializeTransactionToSignableString(input.transaction()); + auto signableAsString = serializeTransactionToSignableString(input.transaction()); auto signableAsData = TW::data(signableAsString); auto signature = privateKey.sign(signableAsData, TWCurveED25519); auto encodedSignature = hex(signature); - auto serializedTransaction = Elrond::serializeSignedTransaction(input.transaction(), encodedSignature); + auto serializedTransaction = serializeSignedTransaction(input.transaction(), encodedSignature); auto protoOutput = Proto::SigningOutput(); protoOutput.set_signature(encodedSignature); @@ -34,6 +34,6 @@ 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 = Signer::sign(input); + auto output = sign(input); return output.signed_transaction(); } diff --git a/swift/Tests/CoinAddressDerivationTests.swift b/swift/Tests/CoinAddressDerivationTests.swift index bb106e63025..b7dbcdaddbc 100644 --- a/swift/Tests/CoinAddressDerivationTests.swift +++ b/swift/Tests/CoinAddressDerivationTests.swift @@ -191,7 +191,7 @@ class CoinAddressDerivationTests: XCTestCase { let expectedResult = "f1zzykebxldfcakj5wdb5n3n7priul522fnmjzori" AssetCoinDerivation(coin, expectedResult, derivedAddress, address) case .elrond: - let expectedResult = "erd1hwnmlzs8kvtsf248m7j7zp9hklncesemq8awv530y42r8s9y27rse5hfw0" + let expectedResult = "erd1k3hzqq8yffrsr86238r3avwq6w0kfgtwrjwhf72n07kxyk4nzwxqvm47d2" AssetCoinDerivation(coin, expectedResult, derivedAddress, address) @unknown default: fatalError() diff --git a/tests/Bech32AddressTests.cpp b/tests/Bech32AddressTests.cpp index 71e8f63274a..4b6024ecd5e 100644 --- a/tests/Bech32AddressTests.cpp +++ b/tests/Bech32AddressTests.cpp @@ -55,7 +55,7 @@ TEST(Bech32Address, Invalid) { ASSERT_FALSE(Bech32Address::isValid("", "erd")); ASSERT_FALSE(Bech32Address::isValid("erd1cux02zersde0l7hhklzhywcxk4u9n4py5tdxyx7vrvhnza2r4gmq4vw35!", "erd")); - ASSERT_FALSE(Bech32Address::isValid("terd19nu5t7hszckwah5nlcadmk5rlchtugzplznskffpwecygcu0520s9tnyy0", "erd")); + ASSERT_FALSE(Bech32Address::isValid("xerd19nu5t7hszckwah5nlcadmk5rlchtugzplznskffpwecygcu0520s9tnyy0", "erd")); } TEST(Bech32Address, InvalidWrongPrefix) { diff --git a/tests/CoinAddressValidationTests.cpp b/tests/CoinAddressValidationTests.cpp index 76d0f9fd36c..86a0d7f309a 100644 --- a/tests/CoinAddressValidationTests.cpp +++ b/tests/CoinAddressValidationTests.cpp @@ -375,7 +375,7 @@ TEST(Coin, ValidateAddressVeChain) { TEST(Coin, ValidateAddressElrond) { EXPECT_TRUE(validateAddress(TWCoinTypeElrond, "erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz")); - EXPECT_FALSE(validateAddress(TWCoinTypeElrond, "terd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz")); + EXPECT_FALSE(validateAddress(TWCoinTypeElrond, "xerd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz")); } diff --git a/tests/Elrond/AddressTests.cpp b/tests/Elrond/AddressTests.cpp index 936e66ade83..3dd1fb6f166 100644 --- a/tests/Elrond/AddressTests.cpp +++ b/tests/Elrond/AddressTests.cpp @@ -27,7 +27,7 @@ TEST(ElrondAddress, Invalid) { ASSERT_FALSE(Address::isValid("")); ASSERT_FALSE(Address::isValid("foo")); ASSERT_FALSE(Address::isValid("10z9xdugayn528ksaesdwlhf006fw5sg2qmmm0h52fvxczwgesyvq5pwemr")); - ASSERT_FALSE(Address::isValid("nerd10z9xdugayn528ksaesdwlhf006fw5sg2qmmm0h52fvxczwgesyvq5pwemr")); + ASSERT_FALSE(Address::isValid("xerd10z9xdugayn528ksaesdwlhf006fw5sg2qmmm0h52fvxczwgesyvq5pwemr")); ASSERT_FALSE(Address::isValid("foo10z9xdugayn528ksaesdwlhf006fw5sg2qmmm0h52fvxczwgesyvq5pwemr")); ASSERT_FALSE(Address::isValid(ALICE_PUBKEY_HEX)); } diff --git a/tests/Elrond/TestAccounts.h b/tests/Elrond/TestAccounts.h index cdb46d6bc7d..501f60cfbec 100644 --- a/tests/Elrond/TestAccounts.h +++ b/tests/Elrond/TestAccounts.h @@ -8,4 +8,4 @@ const auto BOB_SEED_HEX = "e3a3a3d1ac40d42d8fd4c569a9749b65a1250dd3d10b6f4e43829 const auto BOB_PUBKEY_HEX = "c70cf50b238372fffaf7b7c5723b06b57859d424a2da621bcc1b2f317543aa36"; const auto CAROL_BECH32 = "erd19nu5t7hszckwah5nlcadmk5rlchtugzplznskffpwecygcu0520s9tnyy0"; const auto CAROL_SEED_HEX = "a926316cc3daf8ff25ba3e417797e6dfd51f62ae735ab07148234732f7314052"; -const auto CAROL_PUBKEY_HEX = "2cf945faf0162ceede93fe3addda83fe2ebe2041f8a70b2521767044638fa29f"; \ No newline at end of file +const auto CAROL_PUBKEY_HEX = "2cf945faf0162ceede93fe3addda83fe2ebe2041f8a70b2521767044638fa29f"; diff --git a/tests/interface/TWHDWalletTests.cpp b/tests/interface/TWHDWalletTests.cpp index aef46e54518..df8deb258cd 100644 --- a/tests/interface/TWHDWalletTests.cpp +++ b/tests/interface/TWHDWalletTests.cpp @@ -237,8 +237,8 @@ TEST(HDWallet, DeriveElrond) { auto privateKeyData = WRAPD(TWPrivateKeyData(privateKey.get())); auto address = WRAPS(TWCoinTypeDeriveAddress(TWCoinTypeElrond, privateKey.get())); - assertHexEqual(privateKeyData, "7a0b6d3ec4c1f0512be7304636bb7caad52e9c2eeb0d627022b659173f6ad502"); - assertStringsEqual(address, "erd140x7c0mcpveh2ln0r2egzg72mxe3a8h4xcc6s4t9mtuxerzt3nxsq5xq0v"); + assertHexEqual(privateKeyData, "1e6a08a0dc7cfcafdeea72949c3f6c1f8828536727e4b3d64232609c41cb8b3e"); + assertStringsEqual(address, "erd17vh5dwqrvnlxpmgwujewkuqk0rs9wkl2sgmnxgcp8ahjap5suwusqkuc5r"); } TEST(HDWallet, ExtendedKeys) { From d0eff049d688873c3aad242637138cf91812ccd8 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Thu, 23 Apr 2020 14:16:34 +0300 Subject: [PATCH 25/25] Fix after review. --- .../core/app/blockchains/elrond/TestElrondAddress.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 index 692414cb28c..05c17837ddc 100644 --- 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 @@ -27,10 +27,9 @@ class TestElrondAddress { val key = PrivateKey(aliceSeedHex.toHexByteArray()) val pubKey = key.publicKeyEd25519 val address = AnyAddress(pubKey, CoinType.ELROND) - val expected = AnyAddress(aliceBech32, CoinType.ELROND) assertEquals(alicePubKeyHex, pubKey.data().toHex()) - assertEquals(expected.description(), address.description()) + assertEquals(aliceBech32, address.description()) } @Test