Skip to content

Commit

Permalink
Handle create_account bundled with transfer token tx in swap context
Browse files Browse the repository at this point in the history
  • Loading branch information
fbeutin-ledger committed Jan 23, 2025
1 parent 768938d commit 9293b09
Show file tree
Hide file tree
Showing 10 changed files with 118 additions and 15 deletions.
47 changes: 33 additions & 14 deletions src/handle_sign_message.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ void handle_sign_message_parse_message(volatile unsigned int *tx) {
print_config.signer_pubkey = &header->pubkeys[signer_index];

if (G_command.non_confirm) {
PRINTF("G_command.non_confirm refused\n");
// Uncomment this to allow unattended signing.
//*tx = set_result_sign_message();
// THROW(ApduReplySuccess);
Expand All @@ -69,8 +70,14 @@ void handle_sign_message_parse_message(volatile unsigned int *tx) {
// Set the transaction summary
transaction_summary_reset();
if (process_message_body(parser.buffer, parser.buffer_length, &print_config) != 0) {
// Message not processed, throw if blind signing is not enabled
if (N_storage.settings.allow_blind_sign == BlindSignEnabled) {
// Message not processed, throw if blind signing is not enabled or in swap context
if (G_called_from_swap) {
PRINTF("Refuse to process blind transaction in swap context\n");
THROW(ApduReplySdkNotSupported);
} else if (N_storage.settings.allow_blind_sign != BlindSignEnabled) {
PRINTF("Blind signing is not enabled\n");
THROW(ApduReplySdkNotSupported);
} else {
SummaryItem *item = transaction_summary_primary_item();
summary_item_set_string(item, "Unrecognized", "format");

Expand All @@ -81,8 +88,6 @@ void handle_sign_message_parse_message(volatile unsigned int *tx) {

item = transaction_summary_general_item();
summary_item_set_hash(item, "Message Hash", &G_command.message_hash);
} else {
THROW(ApduReplySdkNotSupported);
}
}

Expand Down Expand Up @@ -157,15 +162,7 @@ static bool check_swap_validity_token(const SummaryItemKind_t kinds[MAX_TRANSACT
bool mint_ok = false;
bool dest_ata_ok = false;
bool dest_sol_address_ok = false;
uint8_t expected_steps = 5;

// Accept base step number + optional fee step
if (num_summary_steps != expected_steps && num_summary_steps != expected_steps + 1) {
PRINTF("%d steps expected for token transaction in swap context, not %u\n",
expected_steps,
num_summary_steps);
return false;
}
bool create_token_account_received = false;

if (!g_trusted_info.received) {
// This case should never happen because this is already checked at TX parsing
Expand Down Expand Up @@ -196,6 +193,10 @@ static bool check_swap_validity_token(const SummaryItemKind_t kinds[MAX_TRANSACT
PRINTF("check_swap_amount failed\n");
return false;
}
if (amount_ok) {
PRINTF("We have already parsed an amount, refusing signing multiple\n");
return false;
}
amount_ok = true;
break;

Expand All @@ -207,7 +208,25 @@ static bool check_swap_validity_token(const SummaryItemKind_t kinds[MAX_TRANSACT
break;

case SummaryItemPubkey:
if (strcmp(G_transaction_summary_title, "Token address") == 0) {
if (strcmp(G_transaction_summary_title, "Create token account") == 0) {
if (strcmp(g_trusted_info.encoded_token_address, G_transaction_summary_text) != 0) {
PRINTF("ATA address of create token account does not match with mint address in descriptor\n");
return false;
}
create_token_account_received = true;
} else if (strcmp(G_transaction_summary_title, "For") == 0) {
if (!create_token_account_received) {
PRINTF("'For' received out of create_token_account context\n");
return false;
}
break;
} else if (strcmp(G_transaction_summary_title, "Funded by") == 0) {
if (!create_token_account_received) {
PRINTF("'Funded by' received out of create_token_account context\n");
return false;
}
break;
} else if (strcmp(G_transaction_summary_title, "Token address") == 0) {
// MINT
if (strcmp(g_trusted_info.encoded_mint_address, G_transaction_summary_text) != 0) {
// This case should never happen because this is already checked at TX parsing
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
86 changes: 85 additions & 1 deletion tests/python/test_solana.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ def test_ledger_sign_offchain_message_utf8_expert_refused(self, backend, scenari
from solders.hash import Hash
from solders.message import Message as MessageSolders
from spl.token.constants import TOKEN_PROGRAM_ID
from spl.token.instructions import TransferCheckedParams, transfer_checked, get_associated_token_address
from spl.token.instructions import TransferCheckedParams, transfer_checked, get_associated_token_address, create_associated_token_account
from spl.token.constants import TOKEN_PROGRAM_ID
from .apps import solana_utils as SOL
from solders.keypair import Keypair
Expand Down Expand Up @@ -307,3 +307,87 @@ def test_solana_trusted_name(self, backend, scenario_navigator):
scenario_navigator.review_approve(path=ROOT_SCREENSHOT_PATH)
signature: bytes = sol.get_async_response().data
verify_signature(SOL.OWNED_PUBLIC_KEY, message, signature)


def test_solana_trusted_name_create(self, backend, scenario_navigator):

# Generate a keypair
keypair = Keypair()

# Extract the public key in both bytes and Base58 format
public_key_bytes = bytes(keypair.pubkey())
public_key_base58 = str(keypair.pubkey())
assert Pubkey.is_on_curve(keypair.pubkey())
print(public_key_bytes.hex())
print(public_key_base58)
# sol = SolanaClient(backend)

# from_public_key = sol.get_public_key(SOL_PACKED_DERIVATION_PATH)

# # Create message (SPL Token transfer)
# message: bytes = bytes.fromhex("0100030621a36fe74e1234c35e62bfd700fd247b92c4d4e0e538401ac51f5c4ae97657a7276497ba0bb8659172b72edd8c66e18f561764d9c86a610a3a7e0f79c0baf9dbc71573813ea96479a79e579af14646413602b9b3dcbdc51cbf8e064b5685ed120479d9c7cc1035de7211f99eb48c09d70b2bdf5bdf9e2e56b8a1fbb5a2ea332706ddf6e1d765a193d9cbe146ceeb79ac1cb485ed5f5b37913a8cf5857eff00a938b19525b109c0e2517df8786389e33365afe2dc6bfabeb65458fd24a1ab5b13000000000000000000000000000000000000000000000000000000000000000001040501030205000a0c020000000000000006")

# with sol.send_async_sign_message(SOL_PACKED_DERIVATION_PATH, message):
# scenario_navigator.review_approve(path=ROOT_SCREENSHOT_PATH)

# signature: bytes = sol.get_async_response().data
# verify_signature(from_public_key, message, signature)



# Get the sender public key
sender_public_key = Pubkey.from_string(SOL.OWNED_ADDRESS_STR)

# Get the associated token addresses for the sender
sender_ata = get_associated_token_address(sender_public_key, Pubkey.from_string(SOL.JUP_MINT_ADDRESS_STR))
# TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
destination = str(get_associated_token_address(
Pubkey.from_string(SOL.FOREIGN_ADDRESS_STR),
Pubkey.from_string(SOL.JUP_MINT_ADDRESS_STR)
))

# Create the transaction
create_instruction = create_associated_token_account(
payer=sender_ata,
owner=Pubkey.from_string(SOL.FOREIGN_ADDRESS_STR),
mint=Pubkey.from_string(SOL.JUP_MINT_ADDRESS_STR),
)
transfer_instruction = transfer_checked(
TransferCheckedParams(
program_id=TOKEN_PROGRAM_ID,
source=sender_ata,
mint=Pubkey.from_string(SOL.JUP_MINT_ADDRESS_STR),
dest=Pubkey.from_string(destination),
owner=sender_public_key,
amount=1,
decimals=6 # Number of decimals for JUP token
)
)

blockhash = Hash.default()
message = MessageSolders.new_with_blockhash([create_instruction, transfer_instruction], sender_public_key, blockhash)
tx = Transaction.new_unsigned(message)

# Dump the message embedded in the transaction
message = tx.message_data()

sol = SolanaClient(backend)
challenge = sol.get_challenge()

print(f"destination = {base58.b58decode(destination.encode('utf-8')).hex()}")
print(f"SOL.FOREIGN_PUBLIC_KEY = {SOL.FOREIGN_PUBLIC_KEY.hex()}")
print(f"SOL.JUP_MINT_PUBLIC_KEY = {SOL.JUP_MINT_PUBLIC_KEY.hex()}")
print(f"SOL.JUP_MINT_ADDRESS_STR = {SOL.JUP_MINT_ADDRESS_STR}")
print(f"SOL.JUP_MINT_ADDRESS = {SOL.JUP_MINT_ADDRESS.hex()}")

sol.provide_trusted_name(SOL.JUP_MINT_ADDRESS,
# "JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCNJUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCNJUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN".encode('utf-8'),
destination.encode('utf-8'),
SOL.FOREIGN_ADDRESS_STR.encode('utf-8'),
CHAIN_ID,
challenge=challenge)

with sol.send_async_sign_message(SOL.SOL_PACKED_DERIVATION_PATH, message):
scenario_navigator.review_approve(path=ROOT_SCREENSHOT_PATH)
signature: bytes = sol.get_async_response().data
verify_signature(SOL.OWNED_PUBLIC_KEY, message, signature)

0 comments on commit 9293b09

Please sign in to comment.