1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-22 22:38:08 +00:00

nem2: Handle multisig transactions

This commit is contained in:
Saleem Rashid 2017-07-01 14:38:04 +01:00
parent 19033a459d
commit 563723a55f
5 changed files with 198 additions and 28 deletions

View File

@ -1149,14 +1149,39 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) {
CHECK_PARAM(msg->has_transaction, _("No common provided"));
CHECK_PARAM(msg->has_transfer, _("No transaction provided"));
bool cosigning = msg->has_cosigning && msg->cosigning;
const char *reason;
CHECK_PARAM(!(reason = nem_validate_common(&msg->transaction)), reason);
CHECK_PARAM(!(reason = nem_validate_common(&msg->transaction, false)), reason);
CHECK_PARAM(!(reason = nem_validate_transfer(&msg->transfer, msg->transaction.network)), reason);
if (msg->has_multisig) {
CHECK_PARAM(!(reason = nem_validate_common(&msg->multisig, true)), reason);
CHECK_PARAM(msg->transaction.network == msg->multisig.network, _("Inner transaction network is different"));
} else {
CHECK_PARAM(!cosigning, _("No multisig transaction to cosign"));
}
CHECK_INITIALIZED
CHECK_PIN
if (!nem_askTransfer(&msg->transaction, &msg->transfer)) {
const char *network = nem_network_name(msg->transaction.network);
if (msg->has_multisig) {
char address[NEM_ADDRESS_SIZE + 1];
nem_get_address(msg->multisig.signer.bytes, msg->multisig.network, address);
if (!nem_askMultisig(address, network, cosigning, msg->transaction.fee)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user"));
layoutHome();
return;
}
}
const NEMTransactionCommon *common = msg->has_multisig ? &msg->multisig : &msg->transaction;
if (msg->has_transfer && !nem_askTransfer(common, &msg->transfer, network)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user"));
layoutHome();
return;
@ -1167,12 +1192,31 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) {
HDNode *node = fsm_getDerivedNode(ED25519_KECCAK_NAME, msg->transaction.address_n, msg->transaction.address_n_count);
if (!node) return;
hdnode_fill_public_key(node);
nem_transaction_ctx context;
nem_transaction_start(&context, &node->public_key[1], resp->data.bytes, sizeof(resp->data.bytes));
if (!nem_fsmTransfer(&context, node, &msg->transaction, &msg->transfer)) {
layoutHome();
return;
if (msg->has_multisig) {
uint8_t buffer[sizeof(resp->data.bytes)];
nem_transaction_ctx inner;
nem_transaction_start(&inner, msg->multisig.signer.bytes, buffer, sizeof(buffer));
if (msg->has_transfer && !nem_fsmTransfer(&inner, NULL, &msg->multisig, &msg->transfer)) {
layoutHome();
return;
}
if (!nem_fsmMultisig(&context, &msg->transaction, &inner, cosigning)) {
layoutHome();
return;
}
} else {
if (msg->has_transfer && !nem_fsmTransfer(&context, node, &msg->transaction, &msg->transfer)) {
layoutHome();
return;
}
}
resp->has_data = true;

View File

@ -479,6 +479,27 @@ static inline void nemFormatAmount(bignum256 *amnt, uint64_t quantity, int divis
}
}
void layoutNEMDialog(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *address, const char *line5, const char *line6) {
static char first_third[NEM_ADDRESS_SIZE / 3 + 1];
strlcpy(first_third, address, sizeof(first_third));
static char second_third[NEM_ADDRESS_SIZE / 3 + 1];
strlcpy(second_third, &address[NEM_ADDRESS_SIZE / 3], sizeof(second_third));
const char *third_third = &address[NEM_ADDRESS_SIZE * 2 / 3];
layoutDialogSwipe(icon,
btnNo,
btnYes,
desc,
line1,
first_third,
second_third,
third_third,
line5,
line6);
}
void layoutNEMTransferXEM(const char *desc, uint64_t quantity, const bignum256 *mul, uint64_t fee) {
char str_out[32], str_fee[32];
bignum256 amnt;
@ -499,6 +520,30 @@ void layoutNEMTransferXEM(const char *desc, uint64_t quantity, const bignum256 *
NULL);
}
void layoutNEMNetworkFee(const char *desc, bool confirm, const char *fee1_desc, uint64_t fee1, const char *fee2_desc, uint64_t fee2) {
char str_fee1[32], str_fee2[32];
bignum256 amnt;
bn_read_uint64(fee1, &amnt);
bn_format(&amnt, NULL, " " NEM_XEM_TICKER, NEM_XEM_DIVISIBILITY, str_fee1, sizeof(str_fee1));
if (fee2_desc) {
bn_read_uint64(fee2, &amnt);
bn_format(&amnt, NULL, " " NEM_XEM_TICKER, NEM_XEM_DIVISIBILITY, str_fee2, sizeof(str_fee2));
}
layoutDialogSwipe(&bmp_icon_question,
_("Cancel"),
confirm ? _("Confirm") : _("Next"),
desc,
fee1_desc,
str_fee1,
fee2_desc,
fee2_desc ? str_fee2 : NULL,
NULL,
NULL);
}
void layoutNEMTransferMosaic(const char *namespace, const char *mosaic, uint64_t quantity, const bignum256 *mul) {
char mosaic_name[256];
strlcpy(mosaic_name, namespace, sizeof(mosaic_name));

View File

@ -47,9 +47,10 @@ void layoutPublicKey(const uint8_t *pubkey);
void layoutSignIdentity(const IdentityType *identity, const char *challenge);
void layoutDecryptIdentity(const IdentityType *identity);
void layoutU2FDialog(const char *verb, const char *appname, const BITMAP *appicon);
void layoutNEMDialog(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *address, const char *line5, const char *line6);
void layoutNEMTransferXEM(const char *desc, uint64_t quantity, const bignum256 *mul, uint64_t fee);
void layoutNEMNetworkFee(const char *desc, bool confirm, const char *fee1_desc, uint64_t fee1, const char *fee2_desc, uint64_t fee2);
void layoutNEMTransferMosaic(const char *namespace, const char *mosaic, uint64_t quantity, const bignum256 *mul);
void layoutNEMTransferPayload(const uint8_t *payload, size_t length, bool encrypted);
void layoutNEMTransferTo(const char *desc, const char *address);
#endif

View File

@ -26,16 +26,35 @@
#include "protect.h"
#include "rng.h"
const char *nem_validate_common(NEMTransactionCommon *common) {
const char *nem_validate_common(NEMTransactionCommon *common, bool inner) {
if (!common->has_network) {
common->has_network = true;
common->network = NEM_NETWORK_MAINNET;
}
if (nem_network_name(common->network) == NULL) return _("Invalid NEM network");
if (!common->has_timestamp) return _("No timestamp provided");
if (!common->has_fee) return _("No fee provided");
if (!common->has_deadline) return _("No deadline provided");
if (nem_network_name(common->network) == NULL) {
return inner ? _("Invalid NEM network in inner transaction") : _("Invalid NEM network");
}
if (!common->has_timestamp) {
return inner ? _("No timestamp provided in inner transaction") : _("No timestamp provided");
}
if (!common->has_fee) {
return inner ? _("No fee provided in inner transaction") : _("No fee provided");
}
if (!common->has_deadline) {
return inner ? _("No deadline provided in inner transaction") : _("No deadline provided");
}
if (inner != common->has_signer) {
return inner ? _("No signer provided in inner transaction") : _("Signer not allowed in outer transaction");
}
if (common->has_signer && common->signer.size != sizeof(ed25519_public_key)) {
return _("Invalid signer public key in inner transaction");
}
return NULL;
}
@ -43,29 +62,26 @@ const char *nem_validate_common(NEMTransactionCommon *common) {
const char *nem_validate_transfer(const NEMTransfer *transfer, uint8_t network) {
if (!transfer->has_recipient) return _("No recipient provided");
if (!transfer->has_amount) return _("No amount provided");
if (transfer->has_public_key && transfer->public_key.size != 32) return _("Invalid recipient public key");
if (transfer->has_public_key && transfer->public_key.size != sizeof(ed25519_public_key)) {
return _("Invalid recipient public key");
}
if (!nem_validate_address(transfer->recipient, network)) return _("Invalid recipient address");
for (size_t i = 0; i < transfer->mosaics_count; i++) {
const NEMMosaic *mosaic = &transfer->mosaics[i];
if (!mosaic->has_namespace) return "No mosaic namespace provided";
if (!mosaic->has_mosaic) return "No mosaic name provided";
if (!mosaic->has_quantity) return "No mosaic quantity provided";
if (!mosaic->has_namespace) return _("No mosaic namespace provided");
if (!mosaic->has_mosaic) return _("No mosaic name provided");
if (!mosaic->has_quantity) return _("No mosaic quantity provided");
}
return NULL;
}
bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *transfer) {
const char *network = nem_network_name(common->network);
if (network == NULL) {
return false;
}
bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *transfer, const char *desc) {
if (transfer->mosaics_count) {
bool done[transfer->mosaics_count];
memset(done, 0, sizeof(done));
@ -100,7 +116,7 @@ bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *tran
}
}
layoutNEMTransferXEM(network, xemQuantity == NULL ? 0 : *xemQuantity, &mul, common->fee);
layoutNEMTransferXEM(desc, xemQuantity == NULL ? 0 : *xemQuantity, &mul, common->fee);
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) {
return false;
}
@ -117,7 +133,7 @@ bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *tran
}
}
} else {
layoutNEMTransferXEM(network, transfer->amount, NULL, common->fee);
layoutNEMTransferXEM(desc, transfer->amount, NULL, common->fee);
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) {
return false;
}
@ -130,7 +146,14 @@ bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *tran
}
}
layoutNEMTransferTo(network, transfer->recipient);
layoutNEMDialog(&bmp_icon_question,
_("Cancel"),
_("Confirm"),
desc,
_("Confirm transfer to"),
transfer->recipient,
NULL,
NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) {
return false;
}
@ -203,10 +226,61 @@ bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEM
mosaic->quantity);
if (!ret) {
fsm_sendFailure(FailureType_Failure_ProcessError, "Failed to attach mosaics");
fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to attach mosaics"));
return false;
}
}
return true;
}
bool nem_askMultisig(const char *address, const char *desc, bool cosigning, uint64_t fee) {
layoutNEMDialog(&bmp_icon_question,
_("Cancel"),
_("Next"),
desc,
cosigning ? _("Cosign transaction for") : _("Initiate transaction for"),
address,
NULL,
NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) {
return false;
}
layoutNEMNetworkFee(desc, false, _("Confirm multisig fee"), fee, NULL, 0);
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) {
return false;
}
return true;
}
bool nem_fsmMultisig(nem_transaction_ctx *context, const NEMTransactionCommon *common, const nem_transaction_ctx *inner, bool cosigning) {
bool ret;
if (cosigning) {
ret = nem_transaction_create_multisig_signature(context,
common->network,
common->timestamp,
NULL,
common->fee,
common->deadline,
inner);
} else {
ret = nem_transaction_create_multisig(context,
common->network,
common->timestamp,
NULL,
common->fee,
common->deadline,
inner);
}
if (!ret) {
fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to create multisig transaction"));
return false;
}
return true;
}

View File

@ -27,10 +27,16 @@
#include <stdbool.h>
const char *nem_validate_common(NEMTransactionCommon *common);
const char *nem_validate_common(NEMTransactionCommon *common, bool inner);
const char *nem_validate_transfer(const NEMTransfer *transfer, uint8_t network);
bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *transfer);
bool nem_askTransaction(const char *desc, const NEMTransactionCommon *common, const NEMSignTx *msg);
bool nem_fsmTransaction(nem_transaction_ctx *context, const HDNode *node, const NEMTransactionCommon *common, const NEMSignTx *msg);
bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *transfer, const char *desc);
bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEMTransactionCommon *common, const NEMTransfer *transfer);
bool nem_askMultisig(const char *address, const char *desc, bool cosigning, uint64_t fee);
bool nem_fsmMultisig(nem_transaction_ctx *context, const NEMTransactionCommon *common, const nem_transaction_ctx *inner, bool cosigning);
#endif