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

[Greenfield]: Add support for Delegate and Undelegate messages #3421

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all 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
2 changes: 2 additions & 0 deletions src/Greenfield/Constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,7 @@ static constexpr auto* TIMEOUT_HEIGHT_STR = "0";
static constexpr auto* FEE_GRANTER = "";
static constexpr auto* MSG_SEND_TYPE = "/cosmos.bank.v1beta1.MsgSend";
static constexpr auto* MSG_TRANSFER_OUT_TYPE = "/greenfield.bridge.MsgTransferOut";
static constexpr auto* MSG_DELEGATE_TYPE = "/cosmos.staking.v1beta1.MsgDelegate";
static constexpr auto* MSG_UNDELEGATE_TYPE = "/cosmos.staking.v1beta1.MsgUndelegate";

} // namespace TW::Greenfield
23 changes: 23 additions & 0 deletions src/Greenfield/ProtobufSerialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "Cosmos/Protobuf/bank_tx.pb.h"
#include "Cosmos/Protobuf/greenfield_ethsecp256k1.pb.h"
#include "Cosmos/Protobuf/greenfield_tx.pb.h"
#include "Cosmos/Protobuf/staking_tx.pb.h"
#include "Cosmos/Protobuf/tx.pb.h"
#include "PrivateKey.h"

Expand Down Expand Up @@ -71,6 +72,28 @@ static SigningResult<Any> convertMessage(const Proto::Message& msg) {
any.PackFrom(msgTransferOut, ProtobufAnyNamespacePrefix);
break;
}
case Proto::Message::kStakeMessage: {
const auto& stake = msg.stake_message();

auto msgDelegate = cosmos::staking::v1beta1::MsgDelegate();
msgDelegate.set_delegator_address(stake.delegator_address());
msgDelegate.set_validator_address(stake.validator_address());
*msgDelegate.mutable_amount() = convertCoin(stake.amount());

any.PackFrom(msgDelegate, ProtobufAnyNamespacePrefix);
break;
}
case Proto::Message::kUnstakeMessage: {
const auto& stake = msg.unstake_message();

auto msgDelegate = cosmos::staking::v1beta1::MsgUndelegate();
msgDelegate.set_delegator_address(stake.delegator_address());
msgDelegate.set_validator_address(stake.validator_address());
*msgDelegate.mutable_amount() = convertCoin(stake.amount());

any.PackFrom(msgDelegate, ProtobufAnyNamespacePrefix);
break;
}
default: {
return SigningResult<Any>::failure(Common::Proto::SigningError::Error_invalid_params);
}
Expand Down
87 changes: 85 additions & 2 deletions src/Greenfield/SignerEip712.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ json makeEip712Types(const TypesMap& msgTypes) {
// https://github.com/bnb-chain/greenfield-cosmos-sdk/blob/master/x/auth/tx/eip712.go#L90
// Please note that all parameters repeat the same scheme as `cosmos.bank.v1beta1.MsgSend`.
//
// Use `https://dcellar.io/` with MetaMask to get proper names of types and
// Use `https://dcellar.io/` with MetaMask to get proper names of types.
json msgSendTypes() {
// `MsgSend` specific types.
TypesMap msgTypes = {
Expand Down Expand Up @@ -91,7 +91,7 @@ json msgSendTypes() {
// https://github.com/bnb-chain/greenfield-cosmos-sdk/blob/master/x/auth/tx/eip712.go#L90
// Please note that all parameters repeat the same scheme as `greenfield.bridge.MsgTransferOut`.
//
// Use `https://dcellar.io/` with MetaMask to get proper names of types and
// Use `https://dcellar.io/` with MetaMask to get proper names of types.
json msgTransferOutTypes() {
// `MsgSend` specific types.
TypesMap msgTypes = {
Expand Down Expand Up @@ -120,6 +120,37 @@ json msgTransferOutTypes() {
return makeEip712Types(msgTypes);
}

// `TypeMsg1Amount` and `Msg1` type names are chosen automatically at the function:
// https://github.com/bnb-chain/greenfield-cosmos-sdk/blob/master/x/auth/tx/eip712.go#L90
// Please note that all parameters repeat the same scheme as `cosmos.staking.v1beta1.MsgDelegate` and `cosmos.staking.v1beta1.MsgUndelegate`.
json stakingMsgTypes() {
// `MsgSend` specific types.
TypesMap msgTypes = {
// `TypeMsg1Amount` type represents `cosmos.bank.v1beta1.MsgSend.amount`.
{"TypeMsg1Amount", json::array({
namedParam("amount", "string"),
namedParam("denom", "string"),
})},
{"Msg1", json::array({
namedParam("amount", "TypeMsg1Amount"),
namedParam("delegator_address", "string"),
namedParam("type", "string"),
namedParam("validator_address", "string")
})},
{"Tx", json::array({
namedParam("account_number", "uint256"),
namedParam("chain_id", "uint256"),
namedParam("fee", "Fee"),
namedParam("memo", "string"),
namedParam("msg1", "Msg1"),
namedParam("sequence", "uint256"),
namedParam("timeout_height", "uint256")
})}
};

return makeEip712Types(msgTypes);
}

} // namespace internal::types

json feeToJsonData(const Proto::SigningInput& input, const std::string& feePayer) {
Expand Down Expand Up @@ -218,6 +249,50 @@ json SignerEip712::wrapMsgTransferOutToTypedData(const Proto::SigningInput& inpu
};
}

template <typename StakingMsg>
json wrapStakingMsgToTypedData(const Proto::SigningInput& input, const StakingMsg& stakingMsg, const std::string& typePrefix) {
return json{
{"types", internal::types::stakingMsgTypes()},
{"primaryType", "Tx"},
{"domain", domainDataJson(input.eth_chain_id())},
{"message", json{
{"account_number", std::to_string(input.account_number())},
{"chain_id", input.eth_chain_id()},
{"fee", feeToJsonData(input, stakingMsg.delegator_address())},
{"memo", input.memo()},
{"msg1", json{
{"amount", json{
{"amount", stakingMsg.amount().amount()},
{"denom", stakingMsg.amount().denom()}
}},
{"delegator_address", stakingMsg.delegator_address()},
{"validator_address", stakingMsg.validator_address()},
{"type", typePrefix}
}},
{"sequence", std::to_string(input.sequence())},
{"timeout_height", TIMEOUT_HEIGHT_STR}
}}
};
}

// Returns a JSON data of the `EIP712Domain` type using `MsgDelegate` transaction.
json SignerEip712::wrapMsgDelegateToTypedData(const Proto::SigningInput& input, const Proto::Message_Delegate& msgDelegate) {
std::string typePrefix = MSG_DELEGATE_TYPE;
if (!msgDelegate.type_prefix().empty()) {
typePrefix = msgDelegate.type_prefix();
}
return wrapStakingMsgToTypedData(input, msgDelegate, typePrefix);
}

// Returns a JSON data of the `EIP712Domain` type using `MsgUndelegate` transaction.
json SignerEip712::wrapMsgUndelegateToTypedData(const Proto::SigningInput& input, const Proto::Message_Undelegate& msgUndelegate) {
std::string typePrefix = MSG_UNDELEGATE_TYPE;
if (!msgUndelegate.type_prefix().empty()) {
typePrefix = msgUndelegate.type_prefix();
}
return wrapStakingMsgToTypedData(input, msgUndelegate, typePrefix);
}

SigningResult<json> SignerEip712::wrapTxToTypedData(const Proto::SigningInput& input) {
if (input.messages_size() != 1) {
return SigningResult<json>::failure(Common::Proto::SigningError::Error_invalid_params);
Expand All @@ -228,6 +303,14 @@ SigningResult<json> SignerEip712::wrapTxToTypedData(const Proto::SigningInput& i
const auto &msgTransferOut = input.messages(0).bridge_transfer_out();
return SigningResult<json>::success(wrapMsgTransferOutToTypedData(input, msgTransferOut));
}
case Proto::Message::kStakeMessage: {
const auto& msgDelegate = input.messages(0).stake_message();
return SigningResult<json>::success(wrapMsgDelegateToTypedData(input, msgDelegate));
}
case Proto::Message::kUnstakeMessage: {
const auto& msgUndelegate = input.messages(0).unstake_message();
return SigningResult<json>::success(wrapMsgUndelegateToTypedData(input, msgUndelegate));
}
case Proto::Message::kSendCoinsMessage:
default: {
const auto& msgSendProto = input.messages(0).send_coins_message();
Expand Down
6 changes: 6 additions & 0 deletions src/Greenfield/SignerEip712.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ struct SignerEip712 {
/// Packs the `MsgTransferOut` Tx input in a EIP712 object.
static json wrapMsgTransferOutToTypedData(const Proto::SigningInput& input, const Proto::Message_BridgeTransferOut& msgTransferOut);

/// Packs the `MsgDelegate` Tx input in a EIP712 object.
static json wrapMsgDelegateToTypedData(const Proto::SigningInput& input, const Proto::Message_Delegate& msgDelegate);

/// Packs the `MsgUndelegate` Tx input in a EIP712 object.
static json wrapMsgUndelegateToTypedData(const Proto::SigningInput& input, const Proto::Message_Undelegate& msgUndelegate);

/// Prepares the given `signature` to make it Ethereum compatible.
static void prepareSignature(Data& signature);
};
Expand Down
18 changes: 18 additions & 0 deletions src/proto/Greenfield.proto
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,28 @@ message Message {
string type_prefix = 4;
}

// cosmos-sdk/MsgDelegate
message Delegate {
string delegator_address = 1;
string validator_address = 2;
Amount amount = 3;
string type_prefix = 4;
}

// cosmos-sdk/MsgUndelegate to unstake
message Undelegate {
string delegator_address = 1;
string validator_address = 2;
Amount amount = 3;
string type_prefix = 4;
}

// The payload message
oneof message_oneof {
Send send_coins_message = 1;
BridgeTransferOut bridge_transfer_out = 2;
Delegate stake_message = 3;
Undelegate unstake_message = 4;
}
}

Expand Down
Loading