diff --git a/src/Greenfield/Protobuf/.gitignore b/src/Greenfield/Protobuf/.gitignore new file mode 100644 index 00000000000..c96d61208c0 --- /dev/null +++ b/src/Greenfield/Protobuf/.gitignore @@ -0,0 +1,3 @@ +*.cc +*.h + diff --git a/src/Greenfield/SignerEip712.cpp b/src/Greenfield/SignerEip712.cpp index dc7a1d7d794..7cf6a231ed0 100644 --- a/src/Greenfield/SignerEip712.cpp +++ b/src/Greenfield/SignerEip712.cpp @@ -7,6 +7,8 @@ #include "SignerEip712.h" #include "Ethereum/MessageSigner.h" +#include "Ethereum/ABI/ParamStruct.h" +#include "HexCoding.h" #include @@ -160,7 +162,18 @@ json SignerEip712::wrapTxToTypedData(const Proto::SigningInput& input) { } } +Data SignerEip712::preImageHash(const Proto::SigningInput& input) { + const auto txTypedData = wrapTxToTypedData(input); + return Ethereum::ABI::ParamStruct::hashStructJson(txTypedData.dump()); +} + Data SignerEip712::sign(const Proto::SigningInput& input) { + const PrivateKey privateKey(data(input.private_key())); + const auto txTypedData = wrapTxToTypedData(input).dump(); + const auto chainId = std::stoull(input.eth_chain_id()); + + const auto signatureStr = Ethereum::MessageSigner::signTypedData(privateKey, txTypedData, Ethereum::MessageType::Legacy, chainId); + return parse_hex(signatureStr); } } // namespace TW::Greenfield diff --git a/src/Greenfield/SignerEip712.h b/src/Greenfield/SignerEip712.h index 94b73198b6b..aef94542b88 100644 --- a/src/Greenfield/SignerEip712.h +++ b/src/Greenfield/SignerEip712.h @@ -23,6 +23,9 @@ class SignerEip712 { /// Returns an rsv signature. static Data sign(const Proto::SigningInput& input); + /// Returns a pre-image hash that needs to be signed. + static Data preImageHash(const Proto::SigningInput& input); + /// Packs the Tx input in a EIP712 object. static json wrapTxToTypedData(const Proto::SigningInput& input); diff --git a/tests/chains/Greenfield/SignerTests.cpp b/tests/chains/Greenfield/SignerTests.cpp index 56d8cc79cf5..353fdfaffec 100644 --- a/tests/chains/Greenfield/SignerTests.cpp +++ b/tests/chains/Greenfield/SignerTests.cpp @@ -14,7 +14,7 @@ namespace TW::Greenfield::tests { -TEST(GreenfieldSigner, Eip712TypedDataJson) { +TEST(GreenfieldSigner, SignerEip712) { Proto::SigningInput input; input.set_signing_mode(Proto::Eip712); input.set_account_number(15560); @@ -36,8 +36,8 @@ TEST(GreenfieldSigner, Eip712TypedDataJson) { amountOfFee->set_denom("BNB"); amountOfFee->set_amount("2000000000000000"); - auto actual = SignerEip712::wrapTxToTypedData(input); - auto expected = json::parse(R"( + auto typedData = SignerEip712::wrapTxToTypedData(input); + auto expectedJson = json::parse(R"( { "types": { "Coin": [ @@ -188,7 +188,18 @@ TEST(GreenfieldSigner, Eip712TypedDataJson) { } } )"); - EXPECT_EQ(actual, expected); + EXPECT_EQ(typedData, expectedJson); + + auto expectedPreHash = "b8c62654582ca96b37ca94966199682bf70ed934e740d2f874ff54675a0ac344"; + auto preHash = SignerEip712::preImageHash(input); + EXPECT_EQ(hex(preHash), expectedPreHash); + + auto privateKey = parse_hex("9066aa168c379a403becb235c15e7129c133c244e56a757ab07bc369288bcab0"); + input.set_private_key(privateKey.data(), privateKey.size()); + + auto signature = SignerEip712::sign(input); + auto expectedSignature = "cb3a4684a991014a387a04a85b59227ebb79567c2025addcb296b4ca856e9f810d3b526f2a0d0fad6ad1b126b3b9516f8b3be020a7cca9c03ce3cf47f4199b6d1b"; + EXPECT_EQ(hex(signature), expectedSignature); } } // namespace TW::Greenfield::tests