diff --git a/src/Tron/Protobuf/TronInternal.proto b/src/Tron/Protobuf/TronInternal.proto index f2be7207561..17e30c3a689 100644 --- a/src/Tron/Protobuf/TronInternal.proto +++ b/src/Tron/Protobuf/TronInternal.proto @@ -4,6 +4,7 @@ import "google/protobuf/any.proto"; package protocol; +// https://github.com/tronprotocol/protocol/blob/2a678934da3992b1a67f975769bbb2d31989451f/core/Tron.proto#L336 message Transaction { message Contract { enum ContractType { @@ -33,6 +34,8 @@ message Transaction { int64 ref_block_num = 3; bytes ref_block_hash = 4; int64 expiration = 8; + // transaction memo + bytes data = 10; //only support size = 1, repeated list here for extension repeated Contract contract = 11; int64 timestamp = 14; diff --git a/src/Tron/Serialization.cpp b/src/Tron/Serialization.cpp index 36e92b62878..989cac01ca2 100644 --- a/src/Tron/Serialization.cpp +++ b/src/Tron/Serialization.cpp @@ -291,6 +291,9 @@ json raw_dataJSON(const protocol::Transaction::raw& raw) { } raw_dataJSON["timestamp"] = raw.timestamp(); raw_dataJSON["expiration"] = raw.expiration(); + if (!raw.data().empty()) { + raw_dataJSON["data"] = hex(raw.data()); + } raw_dataJSON["contract"] = json::array({contractJSON(raw.contract(0))}); return raw_dataJSON; diff --git a/src/Tron/Signer.cpp b/src/Tron/Signer.cpp index 64ebaa22153..72e3783d079 100644 --- a/src/Tron/Signer.cpp +++ b/src/Tron/Signer.cpp @@ -386,6 +386,10 @@ protocol::Transaction buildTransaction(const Proto::SigningInput& input) noexcep *contract->mutable_parameter() = any; } + if (!input.transaction().memo().empty()) { + tx.mutable_raw_data()->set_data(input.transaction().memo()); + } + tx.mutable_raw_data()->set_timestamp(input.transaction().timestamp()); tx.mutable_raw_data()->set_expiration(input.transaction().expiration()); tx.mutable_raw_data()->set_fee_limit(input.transaction().fee_limit()); diff --git a/src/proto/Tron.proto b/src/proto/Tron.proto index 22abe490c8a..89e6fd6529d 100644 --- a/src/proto/Tron.proto +++ b/src/proto/Tron.proto @@ -228,9 +228,12 @@ message Transaction { // Transaction block header. BlockHeader block_header = 3; - // Transaction fee limit + // Transaction fee limit. int64 fee_limit = 4; + // Transaction memo. + string memo = 5; + // Contract. oneof contract_oneof { TransferContract transfer = 10; diff --git a/tests/chains/Tron/SignerTests.cpp b/tests/chains/Tron/SignerTests.cpp index f27150bb585..b62ac222b73 100644 --- a/tests/chains/Tron/SignerTests.cpp +++ b/tests/chains/Tron/SignerTests.cpp @@ -89,6 +89,40 @@ TEST(TronSigner, SignTransfer) { ASSERT_EQ(hex(output.signature()), "ede769f6df28aefe6a846be169958c155e23e7e5c9621d2e8dce1719b4d952b63e8a8bf9f00e41204ac1bf69b1a663dacdf764367e48e4a5afcd6b055a747fb200"); } +TEST(TronSigner, SignTransferWithMemo) { + // Successfully broadcasted https://tronscan.org/#/transaction/20321755964d6ec5bcfc9ebfb15faeb043787ae599fff44442962e12e1c357f1 + auto input = Proto::SigningInput(); + auto& transaction = *input.mutable_transaction(); + + auto& transfer = *transaction.mutable_transfer(); + transfer.set_owner_address("TFnYQCt892UNjn67pjAULTSTkB7YvqsnPp"); + transfer.set_to_address("TBUCzgc29vykkvFaEG2mgRtxKvaKe6skwX"); + transfer.set_amount(100000); + + transaction.set_timestamp(1730827017000); + transaction.set_expiration(1730827017000 + 10 * 60 * 60 * 1000); + transaction.set_memo("Test memo"); + + auto& blockHeader = *transaction.mutable_block_header(); + blockHeader.set_timestamp(1730827017000); + const auto txTrieRoot = parse_hex("a94f115089893f37336baf32dbf6cb7d06adc13cf6bf046d9bc22748bd72e7a6"); + blockHeader.set_tx_trie_root(txTrieRoot.data(), txTrieRoot.size()); + const auto parentHash = parse_hex("0000000003fa27db7d67f93920f64733532412ab6a71eb4089dc48c8ff5e182c"); + blockHeader.set_parent_hash(parentHash.data(), parentHash.size()); + blockHeader.set_number(66725852); + const auto witnessAddress = parse_hex("4167e39013be3cdd3814bed152d7439fb5b6791409"); + blockHeader.set_witness_address(witnessAddress.data(), witnessAddress.size()); + blockHeader.set_version(30); + + const auto privateKey = PrivateKey(parse_hex("7c2108a30f6f69f8dce72a7df897eabadfe9810eee6976b43bdf8c0b0d35337d")); + input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); + + const auto output = Signer::sign(input); + + EXPECT_EQ(hex(output.id()), "20321755964d6ec5bcfc9ebfb15faeb043787ae599fff44442962e12e1c357f1"); + EXPECT_EQ(hex(output.signature()), "6fcee79c61f660ec689299f77924f32b5020b4c41593056052ef07d640cc799325103fab130c8691e8a224c96cd0704a698ac356ff789a543c284605668bf38000"); +} + TEST(TronSigner, SignFreezeBalanceV2) { // Successfully broadcasted https://nile.tronscan.org/#/transaction/3a46321487ce1fd115da38b3431006ea529f65ef2507f19233f5a23c05abd01d auto input = Proto::SigningInput(); @@ -514,4 +548,5 @@ TEST(TronSigner, SignTransferTrc20Contract) { ASSERT_EQ(hex(output.id()), "0d644290e3cf554f6219c7747f5287589b6e7e30e1b02793b48ba362da6a5058"); ASSERT_EQ(hex(output.signature()), "bec790877b3a008640781e3948b070740b1f6023c29ecb3f7b5835433c13fc5835e5cad3bd44360ff2ddad5ed7dc9d7dee6878f90e86a40355b7697f5954b88c01"); } + } // namespace TW::Tron