Skip to content
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

Refactor Eth Transaction for EIP2718 #1354

Merged
merged 20 commits into from
Jul 7, 2021
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 1 addition & 15 deletions src/Ethereum/RLP.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright © 2017-2020 Trust Wallet.
// Copyright © 2017-2021 Trust Wallet.
//
// This file is part of Trust. The full Trust copyright notice, including
// terms governing use, modification, and redistribution, is contained in the
Expand Down Expand Up @@ -39,20 +39,6 @@ Data RLP::encodeList(const Data& encoded) noexcept {
return result;
}

Data RLP::encode(const Transaction& transaction) noexcept {
auto encoded = Data();
append(encoded, encode(transaction.nonce));
append(encoded, encode(transaction.gasPrice));
append(encoded, encode(transaction.gasLimit));
append(encoded, encode(transaction.to));
append(encoded, encode(transaction.amount));
append(encoded, encode(transaction.payload));
append(encoded, encode(transaction.v));
append(encoded, encode(transaction.r));
append(encoded, encode(transaction.s));
return encodeList(encoded);
}

Data RLP::encode(const Data& data) noexcept {
if (data.size() == 1 && data[0] <= 0x7f) {
// Fits in single byte, no header
Expand Down
5 changes: 1 addition & 4 deletions src/Ethereum/RLP.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright © 2017-2020 Trust Wallet.
// Copyright © 2017-2021 Trust Wallet.
//
// This file is part of Trust. The full Trust copyright notice, including
// terms governing use, modification, and redistribution, is contained in the
Expand Down Expand Up @@ -49,9 +49,6 @@ struct RLP {

static Data encode(const uint256_t& number) noexcept;

/// Encodes a transaction.
static Data encode(const Transaction& transaction) noexcept;

/// Wraps encoded data as a list.
static Data encodeList(const Data& encoded) noexcept;

Expand Down
100 changes: 40 additions & 60 deletions src/Ethereum/Signer.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright © 2017-2020 Trust Wallet.
// Copyright © 2017-2021 Trust Wallet.
//
// This file is part of Trust. The full Trust copyright notice, including
// terms governing use, modification, and redistribution, is contained in the
Expand All @@ -17,23 +17,23 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept {
auto key = PrivateKey(Data(input.private_key().begin(), input.private_key().end()));
auto transaction = Signer::build(input);

signer.sign(key, transaction);
auto signature = signer.sign(key, transaction);

auto output = Proto::SigningOutput();

auto encoded = RLP::encode(transaction);
auto encoded = transaction->encoded(signature, signer.chainID);
output.set_encoded(encoded.data(), encoded.size());

auto v = store(transaction.v);
auto v = store(signature.v);
output.set_v(v.data(), v.size());

auto r = store(transaction.r);
auto r = store(signature.r);
output.set_r(r.data(), r.size());

auto s = store(transaction.s);
auto s = store(signature.s);
output.set_s(s.data(), s.size());

output.set_data(transaction.payload.data(), transaction.payload.size());
output.set_data(transaction->payload.data(), transaction->payload.size());

return output;
} catch (std::exception&) {
Expand All @@ -49,8 +49,7 @@ std::string Signer::signJSON(const std::string& json, const Data& key) {
return hex(output.encoded());
}

std::tuple<uint256_t, uint256_t, uint256_t> Signer::values(const uint256_t &chainID,
const Data& signature) noexcept {
SignatureRSV Signer::valuesRSV(const uint256_t& chainID, const Data& signature) noexcept {
boost::multiprecision::uint256_t r, s, v;
import_bits(r, signature.begin(), signature.begin() + 32);
import_bits(s, signature.begin() + 32, signature.begin() + 64);
Expand All @@ -64,13 +63,12 @@ std::tuple<uint256_t, uint256_t, uint256_t> Signer::values(const uint256_t &chai
} else {
newV = v;
}
return std::make_tuple(r, s, newV);
return SignatureRSV{r, s, newV};
}

std::tuple<uint256_t, uint256_t, uint256_t>
Signer::sign(const uint256_t &chainID, const PrivateKey &privateKey, const Data& hash) noexcept {
SignatureRSV Signer::sign(const uint256_t& chainID, const PrivateKey& privateKey, const Data& hash) noexcept {
auto signature = privateKey.sign(hash, TWCurveSECP256k1);
return values(chainID, signature);
return valuesRSV(chainID, signature);
}

// May throw
Expand All @@ -85,31 +83,34 @@ Data addressStringToData(const std::string& asString) {
return asData;
}

Transaction Signer::build(const Proto::SigningInput &input) {
std::shared_ptr<TransactionBase> Signer::build(const Proto::SigningInput& input) {
return buildLegacy(input);
optout21 marked this conversation as resolved.
Show resolved Hide resolved
}

std::shared_ptr<TransactionLegacy> Signer::buildLegacy(const Proto::SigningInput& input) {
Data toAddress = addressStringToData(input.to_address());
uint256_t nonce = load(input.nonce());
uint256_t gasPrice = load(input.gas_price());
uint256_t gasLimit = load(input.gas_limit());
assert(gasPrice != 0);
switch (input.transaction().transaction_oneof_case()) {
case Proto::Transaction::kTransfer:
{
auto transaction = Transaction(
/* nonce: */ nonce,
/* gasPrice: */ gasPrice,
/* gasLimit: */ gasLimit,
auto transaction = TransactionLegacy::buildNativeTransfer(
nonce,
gasPrice, gasLimit,
/* to: */ toAddress,
/* amount: */ load(input.transaction().transfer().amount()),
/* optionalTransaction: */ Data(input.transaction().transfer().data().begin(), input.transaction().transfer().data().end()));
/* optional data: */ Data(input.transaction().transfer().data().begin(), input.transaction().transfer().data().end()));
return transaction;
}

case Proto::Transaction::kErc20Transfer:
{
Data tokenToAddress = addressStringToData(input.transaction().erc20_transfer().to());
auto transaction = Transaction::buildERC20Transfer(
/* nonce: */ nonce,
/* gasPrice: */ gasPrice,
/* gasLimit: */ gasLimit,
auto transaction = TransactionLegacy::buildERC20Transfer(
nonce,
gasPrice, gasLimit,
/* tokenContract: */ toAddress,
/* toAddress */ tokenToAddress,
/* amount: */ load(input.transaction().erc20_transfer().amount()));
Expand All @@ -119,10 +120,9 @@ Transaction Signer::build(const Proto::SigningInput &input) {
case Proto::Transaction::kErc20Approve:
{
Data spenderAddress = addressStringToData(input.transaction().erc20_approve().spender());
auto transaction = Transaction::buildERC20Approve(
/* nonce: */ nonce,
/* gasPrice: */ gasPrice,
/* gasLimit: */ gasLimit,
auto transaction = TransactionLegacy::buildERC20Approve(
nonce,
gasPrice, gasLimit,
/* tokenContract: */ toAddress,
/* toAddress */ spenderAddress,
/* amount: */ load(input.transaction().erc20_approve().amount()));
Expand All @@ -133,10 +133,9 @@ Transaction Signer::build(const Proto::SigningInput &input) {
{
Data tokenToAddress = addressStringToData(input.transaction().erc721_transfer().to());
Data tokenFromAddress = addressStringToData(input.transaction().erc721_transfer().from());
auto transaction = Transaction::buildERC721Transfer(
/* nonce: */ nonce,
/* gasPrice: */ gasPrice,
/* gasLimit: */ gasLimit,
auto transaction = TransactionLegacy::buildERC721Transfer(
nonce,
gasPrice, gasLimit,
/* tokenContract: */ toAddress,
/* fromAddress: */ tokenFromAddress,
/* toAddress */ tokenToAddress,
Expand All @@ -148,10 +147,9 @@ Transaction Signer::build(const Proto::SigningInput &input) {
{
Data tokenToAddress = addressStringToData(input.transaction().erc1155_transfer().to());
Data tokenFromAddress = addressStringToData(input.transaction().erc1155_transfer().from());
auto transaction = Transaction::buildERC1155Transfer(
/* nonce: */ nonce,
/* gasPrice: */ gasPrice,
/* gasLimit: */ gasLimit,
auto transaction = TransactionLegacy::buildERC1155Transfer(
nonce,
gasPrice, gasLimit,
/* tokenContract: */ toAddress,
/* fromAddress: */ tokenFromAddress,
/* toAddress */ tokenToAddress,
Expand All @@ -165,10 +163,9 @@ Transaction Signer::build(const Proto::SigningInput &input) {
case Proto::Transaction::kContractGeneric:
default:
{
auto transaction = Transaction(
/* nonce: */ nonce,
/* gasPrice: */ gasPrice,
/* gasLimit: */ gasLimit,
auto transaction = TransactionLegacy::buildNativeTransfer(
nonce,
gasPrice, gasLimit,
/* to: */ toAddress,
/* amount: */ load(input.transaction().contract_generic().amount()),
/* transaction: */ Data(input.transaction().contract_generic().data().begin(), input.transaction().contract_generic().data().end()));
Expand All @@ -177,25 +174,8 @@ Transaction Signer::build(const Proto::SigningInput &input) {
}
}

void Signer::sign(const PrivateKey &privateKey, Transaction &transaction) const noexcept {
auto hash = this->hash(transaction);
auto tuple = Signer::sign(chainID, privateKey, hash);

transaction.r = std::get<0>(tuple);
transaction.s = std::get<1>(tuple);
transaction.v = std::get<2>(tuple);
}

Data Signer::hash(const Transaction &transaction) const noexcept {
auto encoded = Data();
append(encoded, RLP::encode(transaction.nonce));
append(encoded, RLP::encode(transaction.gasPrice));
append(encoded, RLP::encode(transaction.gasLimit));
append(encoded, RLP::encode(transaction.to));
append(encoded, RLP::encode(transaction.amount));
append(encoded, RLP::encode(transaction.payload));
append(encoded, RLP::encode(chainID));
append(encoded, RLP::encode(0));
append(encoded, RLP::encode(0));
return Hash::keccak256(RLP::encodeList(encoded));
SignatureRSV Signer::sign(const PrivateKey& privateKey, std::shared_ptr<TransactionBase> transaction) const noexcept {
auto hash = transaction->hash(chainID);
auto signature = Signer::sign(chainID, privateKey, hash);
return signature;
}
19 changes: 7 additions & 12 deletions src/Ethereum/Signer.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright © 2017-2020 Trust Wallet.
// Copyright © 2017-2021 Trust Wallet.
//
// This file is part of Trust. The full Trust copyright notice, including
// terms governing use, modification, and redistribution, is contained in the
Expand All @@ -16,8 +16,8 @@

#include <boost/multiprecision/cpp_int.hpp>
#include <cstdint>
#include <tuple>
#include <vector>
#include <memory>

namespace TW::Ethereum {

Expand All @@ -36,27 +36,22 @@ class Signer {
explicit Signer(uint256_t chainID) : chainID(std::move(chainID)) {}
optout21 marked this conversation as resolved.
Show resolved Hide resolved

/// Signs the given transaction.
void sign(const PrivateKey &privateKey, Transaction &transaction) const noexcept;
SignatureRSV sign(const PrivateKey& privateKey, std::shared_ptr<TransactionBase> transaction) const noexcept;

public:
/// build Transaction from signing input
static Transaction build(const Proto::SigningInput &input);
static std::shared_ptr<TransactionBase> build(const Proto::SigningInput& input);
static std::shared_ptr<TransactionLegacy> buildLegacy(const Proto::SigningInput& input);

/// Signs a hash with the given private key for the given chain identifier.
///
/// @returns the r, s, and v values of the transaction signature
static std::tuple<uint256_t, uint256_t, uint256_t>
sign(const uint256_t &chainID, const PrivateKey &privateKey, const Data& hash) noexcept;
static SignatureRSV sign(const uint256_t& chainID, const PrivateKey& privateKey, const Data& hash) noexcept;

/// R, S, and V values for the given chain identifier and signature.
///
/// @returns the r, s, and v values of the transaction signature
static std::tuple<uint256_t, uint256_t, uint256_t> values(const uint256_t &chainID,
const Data& signature) noexcept;

protected:
/// Computes the transaction hash.
Data hash(const Transaction &transaction) const noexcept;
static SignatureRSV valuesRSV(const uint256_t& chainID, const Data& signature) noexcept;
};

} // namespace TW::Ethereum
Expand Down
Loading