-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Elrond blockchain #929
Changes from all commits
3585224
066c0d8
a7b5783
85eae4f
96e9465
c44400d
b26a49e
a76ecaa
ae0a056
09fef52
7ba3037
71b5023
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
// Copyright © 2017-2020 Trust Wallet. | ||
// | ||
// This file is part of Trust. The full Trust copyright notice, including | ||
// terms governing use, modification, and redistribution, is contained in the | ||
// file LICENSE at the root of the source code distribution tree. | ||
|
||
package com.trustwallet.core.app.blockchains.elrond | ||
|
||
import com.trustwallet.core.app.utils.toHex | ||
import com.trustwallet.core.app.utils.toHexByteArray | ||
import org.junit.Assert.assertEquals | ||
import org.junit.Test | ||
import wallet.core.jni.* | ||
|
||
class TestElrondAddress { | ||
|
||
init { | ||
System.loadLibrary("TrustWalletCore") | ||
} | ||
|
||
private val aliceBech32 = "erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz" | ||
private var aliceSeedHex = "1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf" | ||
private var alicePubKeyHex = "0xfd691bb5e85d102687d81079dffce842d4dc328276d2d4c60d8fd1c3433c3293" | ||
|
||
@Test | ||
fun testAddressFromPrivateKey() { | ||
val key = PrivateKey(aliceSeedHex.toHexByteArray()) | ||
val pubKey = key.publicKeyEd25519 | ||
val address = AnyAddress(pubKey, CoinType.ELROND) | ||
|
||
assertEquals(alicePubKeyHex, pubKey.data().toHex()) | ||
assertEquals(aliceBech32, address.description()) | ||
} | ||
|
||
@Test | ||
fun testAddressFromPublicKey() { | ||
val pubKey = PublicKey(alicePubKeyHex.toHexByteArray(), PublicKeyType.ED25519) | ||
val address = AnyAddress(pubKey, CoinType.ELROND) | ||
|
||
assertEquals(aliceBech32, address.description()) | ||
} | ||
|
||
@Test | ||
fun testAddressFromString() { | ||
val address = AnyAddress(aliceBech32, CoinType.ELROND) | ||
|
||
assertEquals(aliceBech32, address.description()) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
// Copyright © 2017-2020 Trust Wallet. | ||
// | ||
// This file is part of Trust. The full Trust copyright notice, including | ||
// terms governing use, modification, and redistribution, is contained in the | ||
// file LICENSE at the root of the source code distribution tree. | ||
|
||
package com.trustwallet.core.app.blockchains.elrond | ||
|
||
import com.google.protobuf.ByteString | ||
import com.trustwallet.core.app.utils.toHexByteArray | ||
import junit.framework.Assert.assertEquals | ||
import org.junit.Test | ||
import wallet.core.java.AnySigner | ||
import wallet.core.jni.CoinType | ||
import wallet.core.jni.PrivateKey | ||
import wallet.core.jni.proto.Elrond | ||
|
||
class TestElrondSigner { | ||
|
||
init { | ||
System.loadLibrary("TrustWalletCore") | ||
} | ||
|
||
val aliceBech32 = "erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz" | ||
var aliceSeedHex = "1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf" | ||
var alicePubKeyHex = "fd691bb5e85d102687d81079dffce842d4dc328276d2d4c60d8fd1c3433c3293" | ||
|
||
val bobBech32 = "erd1cux02zersde0l7hhklzhywcxk4u9n4py5tdxyx7vrvhnza2r4gmq4vw35r" | ||
var bobSeedHex = "e3a3a3d1ac40d42d8fd4c569a9749b65a1250dd3d10b6f4e438297662ea4850e" | ||
var bobPubKeyHex = "c70cf50b238372fffaf7b7c5723b06b57859d424a2da621bcc1b2f317543aa36" | ||
|
||
@Test | ||
fun signTransaction() { | ||
val transaction = Elrond.TransactionMessage.newBuilder() | ||
.setNonce(0) | ||
.setValue("0") | ||
.setSender(aliceBech32) | ||
.setReceiver(bobBech32) | ||
.setGasPrice(200000000000000) | ||
.setGasLimit(500000000) | ||
.setData("foo") | ||
.build() | ||
|
||
val privateKey = ByteString.copyFrom(PrivateKey(aliceSeedHex.toHexByteArray()).data()) | ||
|
||
val signingInput = Elrond.SigningInput.newBuilder() | ||
.setPrivateKey(privateKey) | ||
.setTransaction(transaction) | ||
.build() | ||
|
||
val output = AnySigner.sign(signingInput, CoinType.ELROND, Elrond.SigningOutput.parser()) | ||
val expectedSignature = "b88ad2fe98a7316ea432a0a76c18cd87200fe75f27a8f053ea6532b40317dbec5136c5463aef132ae951b7e60d45d921caaa5903e70821dcda98f237d4ec4308" | ||
|
||
assertEquals(expectedSignature, output.signature) | ||
assertEquals("""{"nonce":0,"value":"0","receiver":"$bobBech32","sender":"$aliceBech32","gasPrice":200000000000000,"gasLimit":500000000,"data":"foo","signature":"$expectedSignature"}""", output.encoded) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
// Copyright © 2017-2020 Trust Wallet. | ||
// | ||
// This file is part of Trust. The full Trust copyright notice, including | ||
// terms governing use, modification, and redistribution, is contained in the | ||
// file LICENSE at the root of the source code distribution tree. | ||
|
||
#include <TrustWalletCore/TWHRP.h> | ||
|
||
#include "Address.h" | ||
|
||
using namespace TW::Elrond; | ||
|
||
const std::string Address::hrp = HRP_ELROND; | ||
|
||
bool Address::isValid(const std::string& string) { | ||
return Bech32Address::isValid(string, hrp); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
// Copyright © 2017-2020 Trust Wallet. | ||
// | ||
// This file is part of Trust. The full Trust copyright notice, including | ||
// terms governing use, modification, and redistribution, is contained in the | ||
// file LICENSE at the root of the source code distribution tree. | ||
|
||
#pragma once | ||
|
||
#include "../Data.h" | ||
#include "../PublicKey.h" | ||
#include "../Bech32Address.h" | ||
|
||
#include <string> | ||
|
||
namespace TW::Elrond { | ||
|
||
class Address : public Bech32Address { | ||
public: | ||
// The human-readable part of the address, as defined in "coins.json" | ||
static const std::string hrp; // HRP_ELROND | ||
|
||
/// Determines whether a string makes a valid address. | ||
static bool isValid(const std::string& string); | ||
|
||
Address() : Bech32Address(hrp) {} | ||
|
||
/// Initializes an address with a key hash. | ||
Address(Data keyHash) : Bech32Address(hrp, keyHash) {} | ||
|
||
/// Initializes an address with a public key. | ||
Address(const PublicKey& publicKey) : Bech32Address(hrp, publicKey.bytes) {} | ||
|
||
static bool decode(const std::string& addr, Address& obj_out) { | ||
return Bech32Address::decode(addr, obj_out, hrp); | ||
} | ||
}; | ||
|
||
} // namespace TW::Elrond |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// Copyright © 2017-2020 Trust Wallet. | ||
// | ||
// This file is part of Trust. The full Trust copyright notice, including | ||
// terms governing use, modification, and redistribution, is contained in the | ||
// file LICENSE at the root of the source code distribution tree. | ||
|
||
#include "Entry.h" | ||
|
||
#include "Address.h" | ||
#include "Signer.h" | ||
|
||
using namespace TW::Elrond; | ||
using namespace std; | ||
|
||
// Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. | ||
|
||
bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { | ||
return Address::isValid(address); | ||
} | ||
|
||
string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { | ||
return Address(publicKey).string(); | ||
} | ||
|
||
void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { | ||
signTemplate<Signer, Proto::SigningInput>(dataIn, dataOut); | ||
} | ||
|
||
string Entry::signJSON(TWCoinType coin, const std::string& json, const Data& key) const { | ||
return Signer::signJSON(json, key); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<TWCoinType> coinTypes() const { return {TWCoinTypeElrond}; } | ||
virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; | ||
virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; | ||
virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; | ||
virtual bool supportsJSONSigning() const { return true; } | ||
virtual std::string signJSON(TWCoinType coin, const std::string& json, const Data& key) const; | ||
}; | ||
|
||
} // namespace TW::Elrond |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
// Copyright © 2017-2020 Trust Wallet. | ||
// | ||
// This file is part of Trust. The full Trust copyright notice, including | ||
// terms governing use, modification, and redistribution, is contained in the | ||
// file LICENSE at the root of the source code distribution tree. | ||
|
||
#include "Serialization.h" | ||
|
||
#include "../Elrond/Address.h" | ||
#include "../proto/Elrond.pb.h" | ||
#include "Base64.h" | ||
#include "PrivateKey.h" | ||
|
||
using namespace TW; | ||
|
||
std::map<string, int> fields_order { | ||
{"nonce", 1}, | ||
{"value", 2}, | ||
{"receiver", 3}, | ||
{"sender", 4}, | ||
{"gasPrice", 5}, | ||
{"gasLimit", 6}, | ||
{"data", 7}, | ||
{"signature", 8} | ||
}; | ||
|
||
struct FieldsSorter { | ||
bool operator() (const string& lhs, const string& rhs) const { | ||
return fields_order[lhs] < fields_order[rhs]; | ||
} | ||
}; | ||
|
||
template<class Key, class T, class Compare, class Allocator> | ||
using sorted_map = std::map<Key, T, FieldsSorter, Allocator>; | ||
using sorted_json = nlohmann::basic_json<sorted_map>; | ||
|
||
string Elrond::serializeTransaction(const Proto::TransactionMessage& message) { | ||
sorted_json payload { | ||
{"nonce", json(message.nonce())}, | ||
{"value", json(message.value())}, | ||
{"receiver", json(message.receiver())}, | ||
{"sender", json(message.sender())}, | ||
{"gasPrice", json(message.gas_price())}, | ||
{"gasLimit", json(message.gas_limit())}, | ||
}; | ||
|
||
if (!message.data().empty()) { | ||
payload["data"] = json(TW::Base64::encode(TW::data(message.data()))); | ||
andreibancioiu marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
return payload.dump(); | ||
} | ||
|
||
string Elrond::serializeSignedTransaction(const Proto::TransactionMessage& message, string signature) { | ||
sorted_json payload { | ||
{"nonce", json(message.nonce())}, | ||
{"value", json(message.value())}, | ||
{"receiver", json(message.receiver())}, | ||
{"sender", json(message.sender())}, | ||
{"gasPrice", json(message.gas_price())}, | ||
{"gasLimit", json(message.gas_limit())}, | ||
{"data", json(message.data())}, | ||
Comment on lines
+56
to
+62
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. looks duplicate code in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is duplication, indeed - a bit closer to accidental duplication though, and we would like to keep Indeed, the Is it acceptable on your side if we keep these as they are? |
||
{"signature", json(signature)}, | ||
}; | ||
|
||
return payload.dump(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
// Copyright © 2017-2020 Trust Wallet. | ||
// | ||
// This file is part of Trust. The full Trust copyright notice, including | ||
// terms governing use, modification, and redistribution, is contained in the | ||
// file LICENSE at the root of the source code distribution tree. | ||
|
||
#pragma once | ||
|
||
#include "../proto/Elrond.pb.h" | ||
#include "Data.h" | ||
#include <nlohmann/json.hpp> | ||
|
||
using string = std::string; | ||
using json = nlohmann::json; | ||
|
||
namespace TW::Elrond { | ||
|
||
string serializeTransaction(const Proto::TransactionMessage& message); | ||
string serializeSignedTransaction(const Proto::TransactionMessage& message, string encodedSignature); | ||
|
||
} // namespace |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logo.png is 404
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, we did not open a pull request against the repository
trustwallet/assets
yet, but we are bootstrapping this flow as well.