From 6aa5cd9f9fa0eb0b658b1ea64a0e46edb1c603ea Mon Sep 17 00:00:00 2001 From: pastaghost Date: Mon, 11 Apr 2022 05:13:29 -0400 Subject: [PATCH] wip: add support for cosmos staking/delegation --- include/keepkey/firmware/signtx_tendermint.h | 36 +- .../keepkey/transport/messages-cosmos.options | 27 +- .../transport/messages-tendermint.options | 21 + lib/firmware/fsm_msg_cosmos.h | 408 +++++++++++++++--- lib/firmware/signtx_tendermint.c | 348 ++++++++++++++- 5 files changed, 765 insertions(+), 75 deletions(-) diff --git a/include/keepkey/firmware/signtx_tendermint.h b/include/keepkey/firmware/signtx_tendermint.h index fad46d3dc..1ebaf112c 100644 --- a/include/keepkey/firmware/signtx_tendermint.h +++ b/include/keepkey/firmware/signtx_tendermint.h @@ -9,8 +9,40 @@ typedef struct _TendermintSignTx TendermintSignTx; -bool tendermint_signTxInit(const HDNode *_node, const void *_msg, const size_t msgsize, const char *denom); -bool tendermint_signTxUpdateMsgSend(const uint64_t amount, const char *to_address, const char *chainstr, const char *denom, const char *msgTypePrefix); +bool tendermint_signTxInit(const HDNode *_node, const void *_msg, + const size_t msgsize, const char *denom); +bool tendermint_signTxUpdateMsgSend(const uint64_t amount, + const char *to_address, + const char *chainstr, + const char *denom, + const char *msgTypePrefix); +bool tendermint_signTxUpdateMsgDelegate(const uint64_t amount, + const char *delegator_address, + const char *validator_address, + const char *chainstr, + const char *denom, + const char *msgTypePrefix); +bool tendermint_signTxUpdateMsgUndelegate(const uint64_t amount, + const char *delegator_address, + const char *validator_address, + const char *chainstr, + const char *denom, + const char *msgTypePrefix); +bool tendermint_signTxUpdateMsgRedelegate( + const uint64_t amount, const char *delegator_address, + const char *validator_src_address, const char *validator_dst_address, + const char *chainstr, const char *denom, const char *msgTypePrefix); +bool tendermint_signTxUpdateMsgRewards(const uint64_t amount, + const char *delegator_address, + const char *validator_address, + const char *chainstr, + const char *denom, + const char *msgTypePrefix); +bool tendermint_signTxUpdateMsgIBCTransfer( + const uint64_t amount, const char *sender, const char *receiver, + const char *source_channel, const char *source_port, + const char *revision_number, const char *revision_height, + const char *chainstr, const char *denom, const char *msgTypePrefix); bool tendermint_signTxFinalize(uint8_t *public_key, uint8_t *signature); bool tendermint_signingIsInited(void); bool tendermint_signingIsFinished(void); diff --git a/include/keepkey/transport/messages-cosmos.options b/include/keepkey/transport/messages-cosmos.options index 1dc37a610..ae8440127 100644 --- a/include/keepkey/transport/messages-cosmos.options +++ b/include/keepkey/transport/messages-cosmos.options @@ -1,13 +1,34 @@ CosmosGetAddress.address_n max_count:10 -CosmosAddress.address max_size:46 +CosmosAddress.address max_size:53 CosmosSignTx.address_n max_count:10 CosmosSignTx.chain_id max_size:32 CosmosSignTx.memo max_size:256 -CosmosMsgSend.from_address max_size:46 -CosmosMsgSend.to_address max_size:46 +CosmosMsgSend.from_address max_size:53 +CosmosMsgSend.to_address max_size:53 + +CosmosMsgDelegate.delegator_address max_size:53 +CosmosMsgDelegate.validator_address max_size:53 + +CosmosMsgUndelegate.delegator_address max_size:53 +CosmosMsgUndelegate.validator_address max_size:53 + +CosmosMsgRedelegate.delegator_address max_size:53 +CosmosMsgRedelegate.validator_src_address max_size:53 +CosmosMsgRedelegate.validator_dst_address max_size:53 + +CosmosMsgRewards.delegator_address max_size:53 +CosmosMsgRewards.validator_address max_size:53 + +CosmosMsgIBCTransfer.sender max_size:53 +CosmosMsgIBCTransfer.receiver max_size:53 +CosmosMsgIBCTransfer.source_channel max_size:32 +CosmosMsgIBCTransfer.source_port max_size:32 +CosmosMsgIBCTransfer.revision_height max_size:16 +CosmosMsgIBCTransfer.revision_number max_size:9 +CosmosMsgIBCTransfer.denom max_size:9 CosmosSignedTx.public_key max_size:33 CosmosSignedTx.signature max_size:64 diff --git a/include/keepkey/transport/messages-tendermint.options b/include/keepkey/transport/messages-tendermint.options index 5fc137f0e..eabae2fb0 100644 --- a/include/keepkey/transport/messages-tendermint.options +++ b/include/keepkey/transport/messages-tendermint.options @@ -18,5 +18,26 @@ TendermintSignTx.message_type_prefix max_length:24 TendermintMsgSend.from_address max_length:53 TendermintMsgSend.to_address max_length:53 +TendermintMsgDelegate.delegator_address max_size:53 +TendermintMsgDelegate.validator_address max_size:53 + +TendermintMsgUndelegate.delegator_address max_size:53 +TendermintMsgUndelegate.validator_address max_size:53 + +TendermintMsgRedelegate.delegator_address max_size:53 +TendermintMsgRedelegate.validator_src_address max_size:53 +TendermintMsgRedelegate.validator_dst_address max_size:53 + +TendermintMsgRewards.delegator_address max_size:53 +TendermintMsgRewards.validator_address max_size:53 + +TendermintMsgIBCTransfer.sender max_size:53 +TendermintMsgIBCTransfer.receiver max_size:53 +TendermintMsgIBCTransfer.source_channel max_size:32 +TendermintMsgIBCTransfer.source_port max_size:32 +TendermintMsgIBCTransfer.revision_height max_size:16 +TendermintMsgIBCTransfer.revision_number max_size:9 +TendermintMsgIBCTransfer.denom max_size:9 + TendermintSignedTx.public_key max_size:33 TendermintSignedTx.signature max_size:64 diff --git a/lib/firmware/fsm_msg_cosmos.h b/lib/firmware/fsm_msg_cosmos.h index 4f59ebfa8..7b1971aac 100644 --- a/lib/firmware/fsm_msg_cosmos.h +++ b/lib/firmware/fsm_msg_cosmos.h @@ -92,7 +92,8 @@ void fsm_msgCosmosSignTx(const CosmosSignTx *msg) { RESP_INIT(CosmosMsgRequest); - if (!tendermint_signTxInit(node, (void *)msg, sizeof(CosmosSignTx), "uatom")) { + if (!tendermint_signTxInit(node, (void *)msg, sizeof(CosmosSignTx), + "uatom")) { tendermint_signAbort(); memzero(node, sizeof(*node)); fsm_sendFailure(FailureType_Failure_FirmwareError, @@ -109,13 +110,6 @@ void fsm_msgCosmosSignTx(const CosmosSignTx *msg) { void fsm_msgCosmosMsgAck(const CosmosMsgAck *msg) { // Confirm transaction basics CHECK_PARAM(tendermint_signingIsInited(), "Signing not in progress"); - if (!msg->has_send || !msg->send.has_to_address || !msg->send.has_amount) { - tendermint_signAbort(); - fsm_sendFailure(FailureType_Failure_FirmwareError, - _("Invalid Cosmos Message Type")); - layoutHome(); - return; - } const CoinType *coin = fsm_getCoin(true, "Cosmos"); if (!coin) { @@ -124,52 +118,365 @@ void fsm_msgCosmosMsgAck(const CosmosMsgAck *msg) { const CosmosSignTx *sign_tx = (CosmosSignTx *)tendermint_getSignTx(); - switch (msg->send.address_type) { - case OutputAddressType_EXCHANGE: { - HDNode *root_node = fsm_getDerivedNode(SECP256K1_NAME, 0, 0, NULL); - if (!root_node) { - tendermint_signAbort(); - fsm_sendFailure(FailureType_Failure_FirmwareError, NULL); - layoutHome(); - return; + if (msg->has_send) { + if (!msg->send.has_to_address || !msg->send.has_amount) { + tendermint_signAbort(); + fsm_sendFailure(FailureType_Failure_FirmwareError, + _("Invalid Cosmos Message Type")); + layoutHome(); + return; + } + switch (msg->send.address_type) { + case OutputAddressType_EXCHANGE: { + HDNode *root_node = fsm_getDerivedNode(SECP256K1_NAME, 0, 0, NULL); + if (!root_node) { + tendermint_signAbort(); + fsm_sendFailure(FailureType_Failure_FirmwareError, NULL); + layoutHome(); + return; + } + + int ret = run_policy_compile_output(coin, root_node, (void *)&msg->send, + (void *)NULL, true); + if (ret < TXOUT_OK) { + memzero((void *)root_node, sizeof(*root_node)); + tendermint_signAbort(); + send_fsm_co_error_message(ret); + layoutHome(); + return; + } + + break; } - - int ret = run_policy_compile_output(coin, root_node, (void *)&msg->send, - (void *)NULL, true); - if (ret < TXOUT_OK) { - memzero((void *)root_node, sizeof(*root_node)); - tendermint_signAbort(); - send_fsm_co_error_message(ret); - layoutHome(); - return; + case OutputAddressType_TRANSFER: + default: { + char amount_str[32]; + bn_format_uint64(msg->send.amount, NULL, " ATOM", 6, 0, false, + amount_str, sizeof(amount_str)); + if (!confirm_transaction_output( + ButtonRequestType_ButtonRequest_ConfirmOutput, amount_str, + msg->send.to_address)) { + tendermint_signAbort(); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + break; } + } - break; - } - case OutputAddressType_TRANSFER: - default: { - char amount_str[32]; - bn_format_uint64(msg->send.amount, NULL, " ATOM", 6, 0, false, amount_str, - sizeof(amount_str)); - if (!confirm_transaction_output( - ButtonRequestType_ButtonRequest_ConfirmOutput, amount_str, - msg->send.to_address)) { - tendermint_signAbort(); - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } + if (!tendermint_signTxUpdateMsgSend(msg->send.amount, msg->send.to_address, + "cosmos", "uatom", "cosmos-sdk")) { + tendermint_signAbort(); + fsm_sendFailure(FailureType_Failure_SyntaxError, + "Failed to include send message in transaction"); + layoutHome(); + return; + } + } else if (msg->has_delegate) { + /** Confirm required transaction parameters exist */ + if (!msg->delegate.has_delegator_address || + !msg->delegate.has_validator_address || !msg->delegate.has_amount) { + tendermint_signAbort(); + fsm_sendFailure(FailureType_Failure_FirmwareError, + _("Invalid Cosmos Message Type")); + layoutHome(); + return; + } + /** Confirm transaction parameters on-screen */ + char amount_str[32]; + bn_format_uint64(msg->delegate.amount, NULL, " ATOM", 6, 0, false, + amount_str, sizeof(amount_str)); + + if (!confirm_address("Confirm delegator address", msg->delegate.delegator_address)) { + tendermint_signAbort(); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } - break; + if (!confirm_address("Confirm validator address", msg->delegate.validator_address)) { + tendermint_signAbort(); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; } - } - if (!tendermint_signTxUpdateMsgSend(msg->send.amount, msg->send.to_address, "cosmos", "uatom", "cosmos-sdk")) { - tendermint_signAbort(); - fsm_sendFailure(FailureType_Failure_SyntaxError, - "Failed to include send message in transaction"); - layoutHome(); - return; + if (!confirm_with_custom_layout( + &layout_notification_no_title_bold, + ButtonRequestType_ButtonRequest_ConfirmOutput, "", "Delegate %s?", + amount_str)) { + tendermint_signAbort(); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + if (!tendermint_signTxUpdateMsgDelegate( + msg->delegate.amount, msg->delegate.delegator_address, + msg->delegate.validator_address, "cosmos", "uatom", "cosmos-sdk")) { + tendermint_signAbort(); + fsm_sendFailure(FailureType_Failure_SyntaxError, + "Failed to include delegate message in transaction"); + layoutHome(); + return; + } + } else if (msg->has_undelegate) { + /** Confirm required transaction parameters exist */ + if (!msg->undelegate.has_delegator_address || + !msg->undelegate.has_validator_address || !msg->undelegate.has_amount) { + tendermint_signAbort(); + fsm_sendFailure(FailureType_Failure_FirmwareError, + _("Invalid Cosmos Message Type")); + layoutHome(); + return; + } + /** Confirm transaction parameters on-screen */ + char amount_str[32]; + bn_format_uint64(msg->undelegate.amount, NULL, " ATOM", 6, 0, false, + amount_str, sizeof(amount_str)); + + if (!confirm_address("Confirm delegator address", msg->undelegate.delegator_address)) { + tendermint_signAbort(); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + if (!confirm_address("Confirm validator address", msg->undelegate.validator_address)) { + tendermint_signAbort(); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + if (!confirm_with_custom_layout( + &layout_notification_no_title_bold, + ButtonRequestType_ButtonRequest_ConfirmOutput, "", "Undelegate %s?", + amount_str)) { + tendermint_signAbort(); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + if (!tendermint_signTxUpdateMsgUndelegate( + msg->undelegate.amount, msg->undelegate.delegator_address, + msg->undelegate.validator_address, "cosmos", "uatom", + "cosmos-sdk")) { + tendermint_signAbort(); + fsm_sendFailure(FailureType_Failure_SyntaxError, + "Failed to include undelegate message in transaction"); + layoutHome(); + return; + } + } else if (msg->has_redelegate) { + /** Confirm required transaction parameters exist */ + if (!msg->redelegate.has_delegator_address || + !msg->redelegate.has_validator_src_address || + !msg->redelegate.has_validator_dst_address || + !msg->redelegate.has_amount) { + tendermint_signAbort(); + fsm_sendFailure(FailureType_Failure_FirmwareError, + _("Invalid Cosmos Message Type")); + layoutHome(); + return; + } + /** Confirm transaction parameters on-screen */ + char amount_str[32]; + bn_format_uint64(msg->redelegate.amount, NULL, " ATOM", 6, 0, false, + amount_str, sizeof(amount_str)); + + if (!confirm_address("Confirm delegator address", msg->redelegate.delegator_address)) { + tendermint_signAbort(); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + if (!confirm_address("Confirm validator source address", + msg->redelegate.validator_src_address)) { + tendermint_signAbort(); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + if (!confirm_address("Confirm validator destination address", + msg->redelegate.validator_dst_address)) { + tendermint_signAbort(); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + if (!confirm_with_custom_layout( + &layout_notification_no_title_bold, + ButtonRequestType_ButtonRequest_ConfirmOutput, "", "Redelegate %s?", + amount_str)) { + tendermint_signAbort(); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + if (!tendermint_signTxUpdateMsgRedelegate( + msg->redelegate.amount, msg->redelegate.delegator_address, + msg->redelegate.validator_src_address, + msg->redelegate.validator_dst_address, "cosmos", "uatom", + "cosmos-sdk")) { + tendermint_signAbort(); + fsm_sendFailure(FailureType_Failure_SyntaxError, + "Failed to include redelegate message in transaction"); + layoutHome(); + return; + } + } else if (msg->has_rewards) { + /** Confirm required transaction parameters exist */ + if (!msg->rewards.has_delegator_address || + !msg->rewards.has_validator_address || !msg->rewards.has_amount) { + tendermint_signAbort(); + fsm_sendFailure(FailureType_Failure_FirmwareError, + _("Invalid Cosmos Message Type")); + layoutHome(); + return; + } + /** Confirm transaction parameters on-screen */ + char amount_str[32]; + bn_format_uint64(msg->rewards.amount, NULL, " ATOM", 6, 0, false, + amount_str, sizeof(amount_str)); + + if (!confirm_address("Confirm delegator address", msg->rewards.delegator_address)) { + tendermint_signAbort(); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + if (!confirm_address("Confirm validator address", msg->rewards.validator_address)) { + tendermint_signAbort(); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + if (!confirm_with_custom_layout( + &layout_notification_no_title_bold, + ButtonRequestType_ButtonRequest_ConfirmOutput, "", "Claim %s?", + amount_str)) { + tendermint_signAbort(); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + if (!confirm_transaction_output( + ButtonRequestType_ButtonRequest_ConfirmOutput, amount_str, + msg->send.to_address)) { + tendermint_signAbort(); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + if (!tendermint_signTxUpdateMsgRewards( + msg->rewards.amount, msg->rewards.delegator_address, + msg->rewards.validator_address, "cosmos", "uatom", "cosmos-sdk")) { + tendermint_signAbort(); + fsm_sendFailure(FailureType_Failure_SyntaxError, + "Failed to include rewards message in transaction"); + layoutHome(); + return; + } + } else if (msg->has_ibc_transfer) { + /** Confirm required transaction parameters exist */ + if (!msg->ibc_transfer.has_sender || + !msg->ibc_transfer.has_source_channel || + !msg->ibc_transfer.has_source_port || + !msg->ibc_transfer.has_revision_height || + !msg->ibc_transfer.has_revision_number || + !msg->ibc_transfer.has_denom) { + tendermint_signAbort(); + fsm_sendFailure(FailureType_Failure_FirmwareError, + _("Invalid Cosmos Message Type")); + layoutHome(); + return; + } + /** Confirm transaction parameters on-screen */ + char amount_str[32]; + bn_format_uint64(msg->ibc_transfer.amount, NULL, " ATOM", 6, 0, false, + amount_str, sizeof(amount_str)); + + if (!confirm_address("Confirm sender address", msg->ibc_transfer.sender)) { + tendermint_signAbort(); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + if (!confirm_with_custom_layout( + &layout_notification_no_title_bold, + ButtonRequestType_ButtonRequest_ConfirmOutput, "Source Channel", + "%s", msg->ibc_transfer.source_channel)) { + tendermint_signAbort(); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + if (!confirm_with_custom_layout( + &layout_notification_no_title_bold, + ButtonRequestType_ButtonRequest_ConfirmOutput, "Source Port", "%s", + msg->ibc_transfer.source_port)) { + tendermint_signAbort(); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + if (!confirm_with_custom_layout( + &layout_notification_no_title_bold, + ButtonRequestType_ButtonRequest_ConfirmOutput, "Revision Height", + "%s", msg->ibc_transfer.revision_height)) { + tendermint_signAbort(); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + if (!confirm_with_custom_layout( + &layout_notification_no_title_bold, + ButtonRequestType_ButtonRequest_ConfirmOutput, "Revision Number", + "%s", msg->ibc_transfer.revision_number)) { + tendermint_signAbort(); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + if (!confirm_with_custom_layout( + &layout_notification_no_title_bold, + ButtonRequestType_ButtonRequest_ConfirmOutput, "IBC Transfer", + "Transfer %s?", amount_str)) { + tendermint_signAbort(); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + if (!tendermint_signTxUpdateMsgIBCTransfer( + msg->ibc_transfer.amount, msg->ibc_transfer.sender, + msg->ibc_transfer.receiver, msg->ibc_transfer.source_channel, + msg->ibc_transfer.source_port, msg->ibc_transfer.revision_number, + msg->ibc_transfer.revision_height, "cosmos", "uatom", + "cosmos-sdk")) { + tendermint_signAbort(); + fsm_sendFailure(FailureType_Failure_SyntaxError, + "Failed to include send message in transaction"); + layoutHome(); + return; + } } if (!tendermint_signingIsFinished()) { @@ -208,7 +515,8 @@ void fsm_msgCosmosMsgAck(const CosmosMsgAck *msg) { RESP_INIT(CosmosSignedTx); - if (!tendermint_signTxFinalize(resp->public_key.bytes, resp->signature.bytes)) { + if (!tendermint_signTxFinalize(resp->public_key.bytes, + resp->signature.bytes)) { tendermint_signAbort(); fsm_sendFailure(FailureType_Failure_SyntaxError, "Failed to finalize signature"); @@ -223,4 +531,4 @@ void fsm_msgCosmosMsgAck(const CosmosMsgAck *msg) { tendermint_signAbort(); layoutHome(); msg_write(MessageType_MessageType_CosmosSignedTx, resp); -} +} \ No newline at end of file diff --git a/lib/firmware/signtx_tendermint.c b/lib/firmware/signtx_tendermint.c index a6baa4332..615f8c014 100644 --- a/lib/firmware/signtx_tendermint.c +++ b/lib/firmware/signtx_tendermint.c @@ -1,8 +1,8 @@ /* * This file is part of the Keepkey project. * - * Copyright (C) 2021 Shapeshift - * + * Copyright (C) 2021 Shapeshift + * * This library is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -41,7 +41,8 @@ static TendermintSignTx tmsg; const void *tendermint_getSignTx(void) { return (void *)&tmsg; } -bool tendermint_signTxInit(const HDNode *_node, const void *_msg, const size_t msgsize, const char *denom) { +bool tendermint_signTxInit(const HDNode *_node, const void *_msg, + const size_t msgsize, const char *denom) { initialized = true; msgs_remaining = ((TendermintSignTx *)_msg)->msg_count; has_message = false; @@ -49,11 +50,12 @@ bool tendermint_signTxInit(const HDNode *_node, const void *_msg, const size_t m memzero(&node, sizeof(node)); memcpy(&node, _node, sizeof(node)); -/* - _msg is expected to be of type TendermintSignTx, CosmosSignTx or ThorchainSignTx. These messages all have - common overlapping fields with TendermintSignTx having extra parameters. Copy the _msg memory into a static - TendermintSignTx type and parse from there. -*/ + /* + _msg is expected to be of type TendermintSignTx, CosmosSignTx or + ThorchainSignTx. These messages all have common overlapping fields with + TendermintSignTx having extra parameters. Copy the _msg memory into a static + TendermintSignTx type and parse from there. + */ if (msgsize > sizeof(tmsg)) { return false; @@ -82,11 +84,10 @@ bool tendermint_signTxInit(const HDNode *_node, const void *_msg, const size_t m tendermint_sha256UpdateEscaped(&ctx, tmsg.chain_id, strlen(tmsg.chain_id)); // 30 + ^10 + 11 + ^9 + 3 = ^63 - success &= - tendermint_snprintf(&ctx, buffer, sizeof(buffer), - "\",\"fee\":{\"amount\":[{\"amount\":\"%" PRIu32 - "\",\"denom\":\"%s\"}]", - tmsg.fee_amount, denom); + success &= tendermint_snprintf( + &ctx, buffer, sizeof(buffer), + "\",\"fee\":{\"amount\":[{\"amount\":\"%" PRIu32 "\",\"denom\":\"%s\"}]", + tmsg.fee_amount, denom); // 8 + ^10 + 2 = ^20 success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), @@ -105,8 +106,10 @@ bool tendermint_signTxInit(const HDNode *_node, const void *_msg, const size_t m return success; } -bool tendermint_signTxUpdateMsgSend(const uint64_t amount, const char *to_address, const char *chainstr, - const char *denom, const char *msgTypePrefix) { +bool tendermint_signTxUpdateMsgSend(const uint64_t amount, + const char *to_address, + const char *chainstr, const char *denom, + const char *msgTypePrefix) { char buffer[128]; size_t decoded_len; char hrp[45]; @@ -116,7 +119,8 @@ bool tendermint_signTxUpdateMsgSend(const uint64_t amount, const char *to_addres return false; } - if (strnlen(msgTypePrefix, 25) > 24 || strnlen(denom, 10) > 9 || strnlen(chainstr, 15) > 14) { + if (strnlen(msgTypePrefix, 25) > 24 || strnlen(denom, 10) > 9 || + strnlen(chainstr, 15) > 14) { return false; } @@ -133,12 +137,15 @@ bool tendermint_signTxUpdateMsgSend(const uint64_t amount, const char *to_addres bool success = true; // 9 + ^24 + 19 = ^52 - success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), "{\"type\":\"%s/MsgSend\",\"value\":{", msgTypePrefix); + success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), + "{\"type\":\"%s/MsgSend\",\"value\":{", + msgTypePrefix); // 21 + ^20 + 11 + ^9 + 3 = ^64 - success &= tendermint_snprintf( - &ctx, buffer, sizeof(buffer), - "\"amount\":[{\"amount\":\"%" PRIu64 "\",\"denom\":\"%s\"}]", amount, denom); + success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), + "\"amount\":[{\"amount\":\"%" PRIu64 + "\",\"denom\":\"%s\"}]", + amount, denom); // 17 + ^53 + 1 = ^71 success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), @@ -153,6 +160,307 @@ bool tendermint_signTxUpdateMsgSend(const uint64_t amount, const char *to_addres return success; } +bool tendermint_signTxUpdateMsgDelegate(const uint64_t amount, + const char *delegator_address, + const char *validator_address, + const char *chainstr, const char *denom, + const char *msgTypePrefix) { + char buffer[128]; + size_t decoded_len; + char hrp[45]; + uint8_t decoded[38]; + + if (!bech32_decode(hrp, decoded, &decoded_len, delegator_address)) { + return false; + } + + if (strnlen(msgTypePrefix, 25) > 24 || strnlen(denom, 10) > 9 || + strnlen(chainstr, 15) > 14) { + return false; + } + + // ^14 + 39 + 1 = ^54 + char from_address[54]; + if (!tendermint_getAddress(&node, chainstr, from_address)) { + return false; + } + + if (has_message) { + sha256_Update(&ctx, (uint8_t *)",", 1); + } + + bool success = true; + + // 9 + ^24 + 23 = ^56 + success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), + "{\"type\":\"%s/MsgDelegate\",\"value\":{", + msgTypePrefix); + + // 20 + ^20 + 11 + ^9 + 2 = ^62 + success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), + "\"amount\":{\"amount\":\"%" PRIu64 + "\",\"denom\":\"%s\"}", + amount, denom); + + // 22 + ^53 + 1 = ^76 + success &= + tendermint_snprintf(&ctx, buffer, sizeof(buffer), + ",\"delegator_address\":\"%s\"", delegator_address); + + // 22 + ^53 + 3 = ^76 + success &= + tendermint_snprintf(&ctx, buffer, sizeof(buffer), + ",\"validator_address\":\"%s\"}}", validator_address); + + has_message = true; + msgs_remaining--; + return success; +} +bool tendermint_signTxUpdateMsgUndelegate(const uint64_t amount, + const char *delegator_address, + const char *validator_address, + const char *chainstr, + const char *denom, + const char *msgTypePrefix) { + char buffer[128]; + size_t decoded_len; + char hrp[45]; + uint8_t decoded[38]; + + if (!bech32_decode(hrp, decoded, &decoded_len, delegator_address)) { + return false; + } + + if (strnlen(msgTypePrefix, 25) > 24 || strnlen(denom, 10) > 9 || + strnlen(chainstr, 15) > 14) { + return false; + } + + // ^14 + 39 + 1 = ^54 + char from_address[54]; + if (!tendermint_getAddress(&node, chainstr, from_address)) { + return false; + } + + if (has_message) { + sha256_Update(&ctx, (uint8_t *)",", 1); + } + + bool success = true; + + // 9 + ^24 + 25 = ^58 + success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), + "{\"type\":\"%s/MsgUndelegate\",\"value\":{", + msgTypePrefix); + + // 20 + ^20 + 11 + ^9 + 2 = ^62 + success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), + "\"amount\":{\"amount\":\"%" PRIu64 + "\",\"denom\":\"%s\"}", + amount, denom); + + // 22 + ^53 + 1 = ^76 + success &= + tendermint_snprintf(&ctx, buffer, sizeof(buffer), + ",\"delegator_address\":\"%s\"", delegator_address); + + // 22 + ^53 + 3 = ^76 + success &= + tendermint_snprintf(&ctx, buffer, sizeof(buffer), + ",\"validator_address\":\"%s\"}}", validator_address); + + has_message = true; + msgs_remaining--; + return success; +} + +bool tendermint_signTxUpdateMsgRedelegate( + const uint64_t amount, const char *delegator_address, + const char *validator_src_address, const char *validator_dst_address, + const char *chainstr, const char *denom, const char *msgTypePrefix) { + char buffer[128]; + size_t decoded_len; + char hrp[45]; + uint8_t decoded[38]; + + if (!bech32_decode(hrp, decoded, &decoded_len, delegator_address)) { + return false; + } + + if (strnlen(msgTypePrefix, 25) > 24 || strnlen(denom, 10) > 9 || + strnlen(chainstr, 15) > 14) { + return false; + } + + // ^14 + 39 + 1 = ^54 + char from_address[54]; + if (!tendermint_getAddress(&node, chainstr, from_address)) { + return false; + } + + if (has_message) { + sha256_Update(&ctx, (uint8_t *)",", 1); + } + + bool success = true; + + // 9 + ^24 + 30 = ^66 + success &= tendermint_snprintf( + &ctx, buffer, sizeof(buffer), + "{\"type\":\"%s/MsgBeginRedelegate\",\"value\":{", msgTypePrefix); + + // 20 + ^20 + 11 + ^9 + 2 = ^62 + success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), + "\"amount\":{\"amount\":\"%" PRIu64 + "\",\"denom\":\"%s\"}", + amount, denom); + + // 22 + ^53 + 1 = ^76 + success &= + tendermint_snprintf(&ctx, buffer, sizeof(buffer), + ",\"delegator_address\":\"%s\"", delegator_address); + + // 26 + ^53 + 2 = ^79 + success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), + ",\"validator_dst_address\":\"%s\",", + validator_dst_address); + + // 26 + ^53 + 3 = ^80 + success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), + ",\"validator_src_address\":\"%s\"}}", + validator_src_address); + + has_message = true; + msgs_remaining--; + return success; +} + +bool tendermint_signTxUpdateMsgRewards(const uint64_t amount, + const char *delegator_address, + const char *validator_address, + const char *chainstr, const char *denom, + const char *msgTypePrefix) { + char buffer[128]; + size_t decoded_len; + char hrp[45]; + uint8_t decoded[38]; + + if (!bech32_decode(hrp, decoded, &decoded_len, delegator_address)) { + return false; + } + + if (strnlen(msgTypePrefix, 25) > 24 || strnlen(denom, 10) > 9 || + strnlen(chainstr, 15) > 14) { + return false; + } + + // ^14 + 39 + 1 = ^54 + char from_address[54]; + if (!tendermint_getAddress(&node, chainstr, from_address)) { + return false; + } + + if (has_message) { + sha256_Update(&ctx, (uint8_t *)",", 1); + } + + bool success = true; + + // 9 + ^24 + 38 = ^72 + success &= tendermint_snprintf( + &ctx, buffer, sizeof(buffer), + "{\"type\":\"%s/MsgWithdrawDelegatorReward\",\"value\":{", msgTypePrefix); + + // 20 + ^20 + 11 + ^9 + 2 = ^64 + success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), + "\"amount\":{\"amount\":\"%" PRIu64 + "\",\"denom\":\"%s\"}", + amount, denom); + + // 22 + ^53 + 1 = ^76 + success &= + tendermint_snprintf(&ctx, buffer, sizeof(buffer), + ",\"delegator_address\":\"%s\"", delegator_address); + + // 22 + ^53 + 3 = ^76 + success &= + tendermint_snprintf(&ctx, buffer, sizeof(buffer), + ",\"validator_address\":\"%s\"}}", validator_address); + + has_message = true; + msgs_remaining--; + return success; +} + +bool tendermint_signTxUpdateMsgIBCTransfer( + const uint64_t amount, const char *sender, const char *receiver, + const char *source_channel, const char *source_port, + const char *revision_number, const char *revision_height, + const char *chainstr, const char *denom, const char *msgTypePrefix) { + char buffer[128]; + size_t decoded_len; + char hrp[45]; + uint8_t decoded[38]; + + if (!bech32_decode(hrp, decoded, &decoded_len, receiver)) { + return false; + } + + if (strnlen(msgTypePrefix, 25) > 24 || strnlen(denom, 10) > 9 || + strnlen(chainstr, 15) > 14) { + return false; + } + + // ^14 + 39 + 1 = ^54 + char from_address[54]; + if (!tendermint_getAddress(&node, chainstr, from_address)) { + return false; + } + + if (has_message) { + sha256_Update(&ctx, (uint8_t *)",", 1); + } + + bool success = true; + + // 9 + ^24 + 23 = ^56 + success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), + "{\"type\":\"%s/MsgTransfer\",\"value\":{", + msgTypePrefix); + + // 13 + ^53 + 1 = ^67 + success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), + ",\"receiver\":\"%s\"", receiver); + + // 11 + ^53 + 1 = ^65 + success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), + ",\"sender\":\"%s\"", sender); + + // 19 + ^32 + 1 = ^52 + success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), + ",\"source_channel\":\"%s\"", source_channel); + + // 16 + ^32 + 1 = ^39 + success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), + ",\"source_port\":\"%s\"", source_port); + + // 37 + ^16 + 21 + ^9 + 3 = ^86 + success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), + "\"timeout_height\":{\"revision_height\":\"%" + "s\",\"revision_number\":\"%s\"},", + revision_height, revision_number); + + // 20 + ^20 + 11 + ^9 + 3 = ^63 + success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), + "\"token\":{\"amount\":\"%" PRIu64 + "\",\"denom\":\"%s\"}}", + amount, denom); + + has_message = true; + msgs_remaining--; + return success; +} + bool tendermint_signTxFinalize(uint8_t *public_key, uint8_t *signature) { char buffer[128];