feat(core): SLIP-24 payment requests for Solana
What changed, and why it matters
This commit adds support for SLIP-24 payment requests when signing Solana transactions on Trezor devices. It is a feature implementation, not a security fix. The code introduces verification of payment request data against the transaction details and rejects cases with multiple token transfers when a payment request is present. There is no direct evidence in the commit of a vulnerability or security incident.
Review the PaymentRequestVerifier implementation and the Solana output matching logic in related commits to ensure the verification covers all edge cases (e.g., unknown instructions, system transfers, account ownership, and memo handling). Treat this as a normal feature review rather than an urgent security patch.
Security signals we found
New payment request verification path added to Solana signing
Multiple transfer instructions explicitly rejected for payment requests
Experimental feature flag set on new protobuf field
No changelog entry and no vendor security disclosure
Evidence from the diff
The commit extends the Solana signing flow to accept an optional PaymentRequest in SolanaSignTx. It wires the PaymentRequestVerifier into sign_tx.py, validates outputs against token transfer instructions, and adds a UI confirmation path (confirm_payment_request). It also rejects payment requests with multiple token transfers. The feature is marked experimental via the (experimental_field)=true protobuf option and tests are marked experimental. No security relevance is stated by the vendor, and no CVE or researcher attribution is present.
Changed components
core/src/apps/solana/sign_tx.pycore/src/apps/solana/predefined_transaction.pycore/src/apps/solana/layout.pycommon/protob/messages-solana.protopython/src/trezorlib/solana.pyrust/trezor-client/src/protos/generated/messages_solana.rsInspect captured patch +420 / −51
diff --git a/common/protob/messages-solana.proto b/common/protob/messages-solana.proto
index 4ab286b6..986eb513 100644
--- a/common/protob/messages-solana.proto
+++ b/common/protob/messages-solana.proto
@@ -1,6 +1,9 @@
syntax = "proto2";
package hw.trezor.messages.solana;
+import "messages-common.proto";
+import "options.proto";
+
/**
* Request: Ask device for public key corresponding to address_n path
* @start
@@ -69,6 +72,7 @@ message SolanaSignTx {
repeated uint32 address_n = 1; // BIP-32 path to derive the key to sign with
required bytes serialized_tx = 2; // serialized tx to be signed
optional SolanaTxAdditionalInfo additional_info = 3;
+ optional common.PaymentRequest payment_req = 4 [(experimental_field)=true]; // SLIP-24 payment request
}
/**
diff --git a/common/tests/fixtures/solana/sign_tx.payment_request.json b/common/tests/fixtures/solana/sign_tx.payment_request.json
new file mode 100644
index 00000000..df2e9723
--- /dev/null
+++ b/common/tests/fixtures/solana/sign_tx.payment_request.json
@@ -0,0 +1,128 @@
+{
+ "setup": {
+ "mnemonic": "all all all all all all all all all all all all",
+ "passphrase": ""
+ },
+ "tests": [
+ {
+ "skip_models": ["t2"],
+ "experimental": true,
+ "description": "Payment request",
+ "parameters": {
+ "payment_req": true,
+ "address": "m/44'/501'/0'/0'",
+ "construct": {
+ "version": null,
+ "header": {
+ "signers": 1,
+ "readonly_signers": 0,
+ "readonly_non_signers": 1
+ },
+ "accounts": [
+ "14CCvQzQzHCVgZM3j9soPnXuJXh1RmCfwLVUcdfbZVBS",
+ "ETxHeBBcuw9Yu4dGuP3oXrD12V5RECvmi8ogQ9PkjyVF",
+ "FUqrjRRtF1LiptdFqaFxipE8R3YfCE4k56xwm5n1piqX",
+ "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
+ ],
+ "blockhash": "2p4rYZAaFfV5Uk5ugdG5KPNty9Uda9B3b4gWB8qnNqak",
+ "instructions": [
+ {
+ "program_index": 3,
+ "accounts": {
+ "source_account": 2,
+ "token_mint": 0,
+ "destination_account": 0,
+ "owner": 0,
+ "multisig_signers": []
+ },
+ "data": {
+ "instruction_id": 12,
+ "amount": 200,
+ "decimals": 2
+ }
+ }
+ ],
+ "luts": []
+ },
+ "additional_info": {
+ "token": {
+ "symbol": "FAKE",
+ "mint": "14CCvQzQzHCVgZM3j9soPnXuJXh1RmCfwLVUcdfbZVBS",
+ "name": "Fake token"
+ }
+ }
+ },
+ "result": {
+ "expected_signature": "789bcc492ece698bc832d9d84c789de423763a6b331cf3894d1cc9363b41c3a187d1bbcdd2ca6d0f6702fc98a0484b5fb86e2bd4a2b3d36d89f70f43c9f9080d"
+ }
+ },
+ {
+ "skip_models": ["t2"],
+ "experimental": true,
+ "description": "Payment request - multiple transfers",
+ "parameters": {
+ "payment_req": true,
+ "address": "m/44'/501'/0'/0'",
+ "construct": {
+ "version": null,
+ "header": {
+ "signers": 1,
+ "readonly_signers": 0,
+ "readonly_non_signers": 1
+ },
+ "accounts": [
+ "14CCvQzQzHCVgZM3j9soPnXuJXh1RmCfwLVUcdfbZVBS",
+ "ETxHeBBcuw9Yu4dGuP3oXrD12V5RECvmi8ogQ9PkjyVF",
+ "FUqrjRRtF1LiptdFqaFxipE8R3YfCE4k56xwm5n1piqX",
+ "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
+ ],
+ "blockhash": "2p4rYZAaFfV5Uk5ugdG5KPNty9Uda9B3b4gWB8qnNqak",
+ "instructions": [
+ {
+ "program_index": 3,
+ "accounts": {
+ "source_account": 2,
+ "token_mint": 0,
+ "destination_account": 0,
+ "owner": 0,
+ "multisig_signers": []
+ },
+ "data": {
+ "instruction_id": 12,
+ "amount": 100,
+ "decimals": 2
+ }
+ },
+ {
+ "program_index": 3,
+ "accounts": {
+ "source_account": 3,
+ "token_mint": 0,
+ "destination_account": 0,
+ "owner": 0,
+ "multisig_signers": []
+ },
+ "data": {
+ "instruction_id": 12,
+ "amount": 300,
+ "decimals": 2
+ }
+ }
+ ],
+ "luts": []
+ },
+ "additional_info": {
+ "token": {
+ "symbol": "FAKE",
+ "mint": "14CCvQzQzHCVgZM3j9soPnXuJXh1RmCfwLVUcdfbZVBS",
+ "name": "Fake token"
+ }
+ }
+ },
+ "result": {
+ "error_message": "Multiple transfers not supported"
+ }
+ }
+
+ ]
+}
diff --git a/core/src/apps/solana/layout.py b/core/src/apps/solana/layout.py
index 30665e4b..a1637297 100644
--- a/core/src/apps/solana/layout.py
+++ b/core/src/apps/solana/layout.py
@@ -1,6 +1,6 @@
from typing import TYPE_CHECKING
-from trezor import TR
+from trezor import TR, wire
from trezor.crypto import base58
from trezor.enums import ButtonRequestType
from trezor.strings import format_amount, format_amount_unit
@@ -21,7 +21,7 @@ from .types import AddressType
if TYPE_CHECKING:
from typing import Sequence
- from trezor.messages import SolanaTokenInfo
+ from trezor.messages import PaymentRequest, SolanaTokenInfo
from trezor.ui.layouts import PropertyType
from .definitions import Definitions
@@ -525,3 +525,63 @@ async def confirm_transaction(
fee_title=fee_title,
items=fee_items,
)
+
+
+async def confirm_payment_request(
+ provider_address: str,
+ address_n: list[int],
+ amount: int,
+ decimals: int,
+ token: SolanaTokenInfo,
+ fee: Fee,
+ verified_payment_request: PaymentRequest,
+) -> None:
+ from trezor.ui.layouts import confirm_payment_request
+
+ total_amount = format_amount_unit(format_amount(amount, decimals), token.symbol)
+
+ texts: list[tuple[str | None, str]] = []
+ refunds: list[tuple[str, str | None, str | None]] = []
+ trades: list[tuple[str, str, str, str | None, str | None]] = []
+ for memo in verified_payment_request.memos:
+ if memo.text_memo is not None:
+ texts.append((None, memo.text_memo.text))
+ elif memo.text_details_memo is not None:
+ texts.append((memo.text_details_memo.title, memo.text_details_memo.text))
+ elif memo.refund_memo:
+ refund_account_path = address_n_to_str(memo.refund_memo.address_n)
+ refunds.append((memo.refund_memo.address, None, refund_account_path))
+ elif memo.coin_purchase_memo:
+ coin_purchase_account_path = address_n_to_str(
+ memo.coin_purchase_memo.address_n
+ )
+ trades.append(
+ (
+ f"-\u00A0{total_amount}",
+ f"+\u00A0{memo.coin_purchase_memo.amount}",
+ memo.coin_purchase_memo.address,
+ None,
+ coin_purchase_account_path,
+ )
+ )
+ else:
+ raise wire.DataError("Unrecognized memo type in payment request memo.")
+
+ account_path = address_n_to_str(address_n) if address_n else None
+ account_items = []
+ if account_path:
+ account_items.append((TR.address_details__derivation_path, account_path))
+
+ _, fee_str, fee_items = _fee_ui_info(fee)
+
+ await confirm_payment_request(
+ verified_payment_request.recipient_name,
+ provider_address,
+ texts,
+ refunds,
+ trades,
+ account_items,
+ fee_str,
+ fee_items,
+ None,
+ )
diff --git a/core/src/apps/solana/predefined_transaction.py b/core/src/apps/solana/predefined_transaction.py
index d3171900..3d29915e 100644
--- a/core/src/apps/solana/predefined_transaction.py
+++ b/core/src/apps/solana/predefined_transaction.py
@@ -1,6 +1,7 @@
from typing import TYPE_CHECKING
from trezor.crypto import base58
+from trezor.wire import ProcessError
from .transaction import Transaction
from .transaction.instructions import (
@@ -14,6 +15,8 @@ from .transaction.instructions import (
if TYPE_CHECKING:
from typing import Type
+ from trezor.messages import PaymentRequest
+
from .transaction import Fee
from .types import AdditionalTxInfo
@@ -122,9 +125,10 @@ async def try_confirm_token_transfer_transaction(
signer_path: list[int],
blockhash: bytes,
additional_info: AdditionalTxInfo,
+ verified_payment_request: PaymentRequest | None,
) -> bool:
from .definitions import unknown_token
- from .layout import confirm_token_transfer
+ from .layout import confirm_payment_request, confirm_token_transfer
from .token_account import try_get_token_account_base_address
visible_instructions = transaction.get_visible_instructions()
@@ -159,16 +163,31 @@ async def try_confirm_token_transfer_transaction(
is_unknown = token is None
if is_unknown:
token = unknown_token(token_mint)
- await confirm_token_transfer(
- token_account if base_address is None else base_address,
- token_account,
- token,
- is_unknown,
- total_token_amount,
- transfer_token_instructions[0].decimals,
- fee,
- blockhash,
- )
+
+ if verified_payment_request:
+ if len(transfer_token_instructions) > 1:
+ raise ProcessError("Multiple transfers not supported for payment requests")
+ provider_address = base58.encode(token_account)
+ await confirm_payment_request(
+ provider_address,
+ signer_path,
+ total_token_amount,
+ transfer_token_instructions[0].decimals,
+ token,
+ fee,
+ verified_payment_request,
+ )
+ else:
+ await confirm_token_transfer(
+ token_account if base_address is None else base_address,
+ token_account,
+ token,
+ is_unknown,
+ total_token_amount,
+ transfer_token_instructions[0].decimals,
+ fee,
+ blockhash,
+ )
return True
@@ -179,6 +198,7 @@ async def try_confirm_predefined_transaction(
signer_public_key: bytes,
blockhash: bytes,
additional_info: AdditionalTxInfo,
+ verified_payment_request: PaymentRequest | None,
) -> bool:
from .layout import confirm_system_transfer
from .transaction.instructions import SystemProgramTransferInstruction
@@ -214,6 +234,7 @@ async def try_confirm_predefined_transaction(
signer_path,
blockhash,
additional_info,
+ verified_payment_request,
)
diff --git a/core/src/apps/solana/sign_tx.py b/core/src/apps/solana/sign_tx.py
index 7e67dfb4..94d2a553 100644
--- a/core/src/apps/solana/sign_tx.py
+++ b/core/src/apps/solana/sign_tx.py
@@ -1,5 +1,6 @@
from typing import TYPE_CHECKING
+from trezor.crypto import base58
from trezor.wire import DataError
from apps.common.keychain import with_slip44_keychain
@@ -11,13 +12,15 @@ from .types import AdditionalTxInfo
if TYPE_CHECKING:
from trezor.messages import SolanaSignTx, SolanaTxSignature
- from apps.common.keychain import Keychain
+ from apps.common.keychain import Keychain as Slip21Keychain
-@with_slip44_keychain(*PATTERNS, slip44_id=SLIP44_ID, curve=CURVE)
+@with_slip44_keychain(
+ *PATTERNS, slip44_id=SLIP44_ID, curve=CURVE, slip21_namespaces=[[b"SLIP-0024"]]
+)
async def sign_tx(
msg: SolanaSignTx,
- keychain: Keychain,
+ keychain: Slip21Keychain,
) -> SolanaTxSignature:
from trezor import TR
from trezor.crypto.curve import ed25519
@@ -28,7 +31,10 @@ async def sign_tx(
from apps.common import seed
from .layout import confirm_transaction
- from .predefined_transaction import try_confirm_predefined_transaction
+ from .predefined_transaction import (
+ get_token_transfer_instructions,
+ try_confirm_predefined_transaction,
+ )
address_n = msg.address_n # local_cache_attribute
serialized_tx = msg.serialized_tx # local_cache_attribute
@@ -66,6 +72,20 @@ async def sign_tx(
msg.additional_info
)
+ if msg.payment_req:
+ from apps.common.payment_request import PaymentRequestVerifier
+
+ transfer_token_instructions = get_token_transfer_instructions(
+ transaction.get_visible_instructions()
+ )
+ verifier = PaymentRequestVerifier(msg.payment_req, SLIP44_ID, keychain)
+ for transfer_token_instruction in transfer_token_instructions:
+ verifier.add_output(
+ transfer_token_instruction.amount,
+ base58.encode(transfer_token_instruction.destination_account[0]),
+ )
+ verifier.verify()
+
if not await try_confirm_predefined_transaction(
transaction,
fee,
@@ -73,6 +93,7 @@ async def sign_tx(
signer_public_key,
transaction.blockhash,
additional_tx_info,
+ msg.payment_req,
):
await confirm_instructions(
address_n, signer_public_key, transaction, additional_tx_info
diff --git a/core/src/trezor/messages.py b/core/src/trezor/messages.py
index a9198c93..f7706e41 100644
--- a/core/src/trezor/messages.py
+++ b/core/src/trezor/messages.py
@@ -5454,6 +5454,7 @@ if TYPE_CHECKING:
address_n: "list[int]"
serialized_tx: "bytes"
additional_info: "SolanaTxAdditionalInfo | None"
+ payment_req: "PaymentRequest | None"
def __init__(
self,
@@ -5461,6 +5462,7 @@ if TYPE_CHECKING:
serialized_tx: "bytes",
address_n: "list[int] | None" = None,
additional_info: "SolanaTxAdditionalInfo | None" = None,
+ payment_req: "PaymentRequest | None" = None,
) -> None:
pass
diff --git a/python/src/trezorlib/messages.py b/python/src/trezorlib/messages.py
index 17eaea5d..7b63c43c 100644
--- a/python/src/trezorlib/messages.py
+++ b/python/src/trezorlib/messages.py
@@ -7067,6 +7067,7 @@ class SolanaSignTx(protobuf.MessageType):
1: protobuf.Field("address_n", "uint32", repeated=True, required=False, default=None),
2: protobuf.Field("serialized_tx", "bytes", repeated=False, required=True),
3: protobuf.Field("additional_info", "SolanaTxAdditionalInfo", repeated=False, required=False, default=None),
+ 4: protobuf.Field("payment_req", "PaymentRequest", repeated=False, required=False, default=None),
}
def __init__(
@@ -7075,10 +7076,12 @@ class SolanaSignTx(protobuf.MessageType):
serialized_tx: "bytes",
address_n: Optional[Sequence["int"]] = None,
additional_info: Optional["SolanaTxAdditionalInfo"] = None,
+ payment_req: Optional["PaymentRequest"] = None,
) -> None:
self.address_n: Sequence["int"] = address_n if address_n is not None else []
self.serialized_tx = serialized_tx
self.additional_info = additional_info
+ self.payment_req = payment_req
class SolanaTxSignature(protobuf.MessageType):
diff --git a/python/src/trezorlib/solana.py b/python/src/trezorlib/solana.py
index 27762211..ad576fb6 100644
--- a/python/src/trezorlib/solana.py
+++ b/python/src/trezorlib/solana.py
@@ -58,12 +58,14 @@ def sign_tx(
address_n: List[int],
serialized_tx: bytes,
additional_info: Optional[messages.SolanaTxAdditionalInfo],
+ payment_req: Optional[messages.PaymentRequest] = None,
) -> bytes:
return session.call(
messages.SolanaSignTx(
address_n=address_n,
serialized_tx=serialized_tx,
additional_info=additional_info,
+ payment_req=payment_req,
),
expect=messages.SolanaTxSignature,
).signature
diff --git a/rust/trezor-client/src/protos/generated/messages_solana.rs b/rust/trezor-client/src/protos/generated/messages_solana.rs
index 700d53f2..12c06cf5 100644
--- a/rust/trezor-client/src/protos/generated/messages_solana.rs
+++ b/rust/trezor-client/src/protos/generated/messages_solana.rs
@@ -1285,6 +1285,8 @@ pub struct SolanaSignTx {
pub serialized_tx: ::std::option::Option<::std::vec::Vec<u8>>,
// @@protoc_insertion_point(field:hw.trezor.messages.solana.SolanaSignTx.additional_info)
pub additional_info: ::protobuf::MessageField<SolanaTxAdditionalInfo>,
+ // @@protoc_insertion_point(field:hw.trezor.messages.solana.SolanaSignTx.payment_req)
+ pub payment_req: ::protobuf::MessageField<super::messages_common::PaymentRequest>,
// special fields
// @@protoc_insertion_point(special_field:hw.trezor.messages.solana.SolanaSignTx.special_fields)
pub special_fields: ::protobuf::SpecialFields,
@@ -1338,7 +1340,7 @@ impl SolanaSignTx {
}
fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
- let mut fields = ::std::vec::Vec::with_capacity(3);
+ let mut fields = ::std::vec::Vec::with_capacity(4);
let mut oneofs = ::std::vec::Vec::with_capacity(0);
fields.push(::protobuf::reflect::rt::v2::make_vec_simpler_accessor::<_, _>(
"address_n",
@@ -1355,6 +1357,11 @@ impl SolanaSignTx {
|m: &SolanaSignTx| { &m.additional_info },
|m: &mut SolanaSignTx| { &mut m.additional_info },
));
+ fields.push(::protobuf::reflect::rt::v2::make_message_field_accessor::<_, super::messages_common::PaymentRequest>(
+ "payment_req",
+ |m: &SolanaSignTx| { &m.payment_req },
+ |m: &mut SolanaSignTx| { &mut m.payment_req },
+ ));
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<SolanaSignTx>(
"SolanaSignTx",
fields,
@@ -1375,6 +1382,11 @@ impl ::protobuf::Message for SolanaSignTx {
return false;
}
};
+ for v in &self.payment_req {
+ if !v.is_initialized() {
+ return false;
+ }
+ };
true
}
@@ -1393,6 +1405,9 @@ impl ::protobuf::Message for SolanaSignTx {
26 => {
::protobuf::rt::read_singular_message_into_field(is, &mut self.additional_info)?;
},
+ 34 => {
+ ::protobuf::rt::read_singular_message_into_field(is, &mut self.payment_req)?;
+ },
tag => {
::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
},
@@ -1415,6 +1430,10 @@ impl ::protobuf::Message for SolanaSignTx {
let len = v.compute_size();
my_size += 1 + ::protobuf::rt::compute_raw_varint64_size(len) + len;
}
+ if let Some(v) = self.payment_req.as_ref() {
+ let len = v.compute_size();
+ my_size += 1 + ::protobuf::rt::compute_raw_varint64_size(len) + len;
+ }
my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
self.special_fields.cached_size().set(my_size as u32);
my_size
@@ -1430,6 +1449,9 @@ impl ::protobuf::Message for SolanaSignTx {
if let Some(v) = self.additional_info.as_ref() {
::protobuf::rt::write_message_field_with_cached_size(3, v, os)?;
}
+ if let Some(v) = self.payment_req.as_ref() {
+ ::protobuf::rt::write_message_field_with_cached_size(4, v, os)?;
+ }
os.write_unknown_fields(self.special_fields.unknown_fields())?;
::std::result::Result::Ok(())
}
@@ -1450,6 +1472,7 @@ impl ::protobuf::Message for SolanaSignTx {
self.address_n.clear();
self.serialized_tx = ::std::option::Option::None;
self.additional_info.clear();
+ self.payment_req.clear();
self.special_fields.clear();
}
@@ -1458,6 +1481,7 @@ impl ::protobuf::Message for SolanaSignTx {
address_n: ::std::vec::Vec::new(),
serialized_tx: ::std::option::Option::None,
additional_info: ::protobuf::MessageField::none(),
+ payment_req: ::protobuf::MessageField::none(),
special_fields: ::protobuf::SpecialFields::new(),
};
&instance
@@ -1643,26 +1667,29 @@ impl ::protobuf::reflect::ProtobufValue for SolanaTxSignature {
}
static file_descriptor_proto_data: &'static [u8] = b"\
- \n\x15messages-solana.proto\x12\x19hw.trezor.messages.solana\"T\n\x12Sol\
- anaGetPublicKey\x12\x1b\n\taddress_n\x18\x01\x20\x03(\rR\x08addressN\x12\
- !\n\x0cshow_display\x18\x02\x20\x01(\x08R\x0bshowDisplay\"0\n\x0fSolanaP\
- ublicKey\x12\x1d\n\npublic_key\x18\x01\x20\x02(\x0cR\tpublicKey\"n\n\x10\
- SolanaGetAddress\x12\x1b\n\taddress_n\x18\x01\x20\x03(\rR\x08addressN\
- \x12!\n\x0cshow_display\x18\x02\x20\x01(\x08R\x0bshowDisplay\x12\x1a\n\
- \x08chunkify\x18\x03\x20\x01(\x08R\x08chunkify\";\n\rSolanaAddress\x12\
- \x18\n\x07address\x18\x01\x20\x02(\tR\x07address\x12\x10\n\x03mac\x18\
- \x02\x20\x01(\x0cR\x03mac\"\xa6\x01\n\x18SolanaTxTokenAccountInfo\x12!\n\
- \x0cbase_address\x18\x01\x20\x02(\tR\x0bbaseAddress\x12#\n\rtoken_progra\
- m\x18\x02\x20\x02(\tR\x0ctokenProgram\x12\x1d\n\ntoken_mint\x18\x03\x20\
- \x02(\tR\ttokenMint\x12#\n\rtoken_account\x18\x04\x20\x02(\tR\x0ctokenAc\
- count\"\xa4\x01\n\x16SolanaTxAdditionalInfo\x12e\n\x14token_accounts_inf\
- os\x18\x01\x20\x03(\x0b23.hw.trezor.messages.solana.SolanaTxTokenAccount\
- InfoR\x12tokenAccountsInfos\x12#\n\rencoded_token\x18\x02\x20\x01(\x0cR\
- \x0cencodedToken\"\xac\x01\n\x0cSolanaSignTx\x12\x1b\n\taddress_n\x18\
- \x01\x20\x03(\rR\x08addressN\x12#\n\rserialized_tx\x18\x02\x20\x02(\x0cR\
- \x0cserializedTx\x12Z\n\x0fadditional_info\x18\x03\x20\x01(\x0b21.hw.tre\
- zor.messages.solana.SolanaTxAdditionalInfoR\x0eadditionalInfo\"1\n\x11So\
- lanaTxSignature\x12\x1c\n\tsignature\x18\x01\x20\x02(\x0cR\tsignature\
+ \n\x15messages-solana.proto\x12\x19hw.trezor.messages.solana\x1a\x15mess\
+ ages-common.proto\x1a\roptions.proto\"T\n\x12SolanaGetPublicKey\x12\x1b\
+ \n\taddress_n\x18\x01\x20\x03(\rR\x08addressN\x12!\n\x0cshow_display\x18\
+ \x02\x20\x01(\x08R\x0bshowDisplay\"0\n\x0fSolanaPublicKey\x12\x1d\n\npub\
+ lic_key\x18\x01\x20\x02(\x0cR\tpublicKey\"n\n\x10SolanaGetAddress\x12\
+ \x1b\n\taddress_n\x18\x01\x20\x03(\rR\x08addressN\x12!\n\x0cshow_display\
+ \x18\x02\x20\x01(\x08R\x0bshowDisplay\x12\x1a\n\x08chunkify\x18\x03\x20\
+ \x01(\x08R\x08chunkify\";\n\rSolanaAddress\x12\x18\n\x07address\x18\x01\
+ \x20\x02(\tR\x07address\x12\x10\n\x03mac\x18\x02\x20\x01(\x0cR\x03mac\"\
+ \xa6\x01\n\x18SolanaTxTokenAccountInfo\x12!\n\x0cbase_address\x18\x01\
+ \x20\x02(\tR\x0bbaseAddress\x12#\n\rtoken_program\x18\x02\x20\x02(\tR\
+ \x0ctokenProgram\x12\x1d\n\ntoken_mint\x18\x03\x20\x02(\tR\ttokenMint\
+ \x12#\n\rtoken_account\x18\x04\x20\x02(\tR\x0ctokenAccount\"\xa4\x01\n\
+ \x16SolanaTxAdditionalInfo\x12e\n\x14token_accounts_infos\x18\x01\x20\
+ \x03(\x0b23.hw.trezor.messages.solana.SolanaTxTokenAccountInfoR\x12token\
+ AccountsInfos\x12#\n\rencoded_token\x18\x02\x20\x01(\x0cR\x0cencodedToke\
+ n\"\xfe\x01\n\x0cSolanaSignTx\x12\x1b\n\taddress_n\x18\x01\x20\x03(\rR\
+ \x08addressN\x12#\n\rserialized_tx\x18\x02\x20\x02(\x0cR\x0cserializedTx\
+ \x12Z\n\x0fadditional_info\x18\x03\x20\x01(\x0b21.hw.trezor.messages.sol\
+ ana.SolanaTxAdditionalInfoR\x0eadditionalInfo\x12P\n\x0bpayment_req\x18\
+ \x04\x20\x01(\x0b2).hw.trezor.messages.common.PaymentRequestR\npaymentRe\
+ qB\x04\xc8\xf0\x19\x01\"1\n\x11SolanaTxSignature\x12\x1c\n\tsignature\
+ \x18\x01\x20\x02(\x0cR\tsignature\
";
/// `FileDescriptorProto` object which was a source for this generated file
@@ -1679,7 +1706,9 @@ pub fn file_descriptor() -> &'static ::protobuf::reflect::FileDescriptor {
static file_descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::FileDescriptor> = ::protobuf::rt::Lazy::new();
file_descriptor.get(|| {
let generated_file_descriptor = generated_file_descriptor_lazy.get(|| {
- let mut deps = ::std::vec::Vec::with_capacity(0);
+ let mut deps = ::std::vec::Vec::with_capacity(2);
+ deps.push(super::messages_common::file_descriptor().clone());
+ deps.push(super::options::file_descriptor().clone());
let mut messages = ::std::vec::Vec::with_capacity(8);
messages.push(SolanaGetPublicKey::generated_message_descriptor_data());
messages.push(SolanaPublicKey::generated_message_descriptor_data());
diff --git a/tests/common.py b/tests/common.py
index 8307ded7..cfdc8acd 100644
--- a/tests/common.py
+++ b/tests/common.py
@@ -112,9 +112,12 @@ def parametrize_using_common_fixtures(*paths: str) -> "MarkDecorator":
if skip_model == "t3t1":
skiplist.append(models.T3T1)
if skiplist:
- skip_marks = [pytest.mark.models(skip=skiplist)]
+ extra_marks = [pytest.mark.models(skip=skiplist)]
else:
- skip_marks = []
+ extra_marks = []
+
+ if test.get("experimental"):
+ extra_marks.append(pytest.mark.experimental)
tests.append(
pytest.param(
@@ -126,7 +129,7 @@ def parametrize_using_common_fixtures(*paths: str) -> "MarkDecorator":
mnemonic=fixture["setup"]["mnemonic"],
)
]
- + skip_marks,
+ + extra_marks,
id=test_id,
)
)
diff --git a/tests/device_tests/solana/test_sign_tx.py b/tests/device_tests/solana/test_sign_tx.py
index 5ed191d9..e495533c 100644
--- a/tests/device_tests/solana/test_sign_tx.py
+++ b/tests/device_tests/solana/test_sign_tx.py
@@ -16,14 +16,21 @@
import pytest
-from trezorlib import messages
+from trezorlib import btc, messages, misc
from trezorlib.debuglink import SessionDebugWrapper as Session
-from trezorlib.solana import sign_tx
+from trezorlib.exceptions import TrezorFailure
+from trezorlib.solana import get_authenticated_address, sign_tx
from trezorlib.tools import b58decode, parse_path
from ...common import parametrize_using_common_fixtures
from ...definitions import encode_solana_token
from ...input_flows import InputFlowConfirmAllWarnings
+from ..payment_req import (
+ CoinPurchaseMemo,
+ RefundMemo,
+ TextDetailsMemo,
+ make_payment_request,
+)
from .construct.instructions import PROGRAMS, UnknownInstruction
from .construct.transaction import Message, RawInstruction
@@ -40,6 +47,7 @@ pytestmark = [pytest.mark.altcoin, pytest.mark.solana, pytest.mark.models("core"
"solana/sign_tx.unknown_instructions.json",
"solana/sign_tx.predefined_transactions.json",
"solana/sign_tx.staking_transactions.json",
+ "solana/sign_tx.payment_request.json",
)
def test_solana_sign_tx(session: Session, parameters, result):
serialized_tx = _serialize_tx(parameters["construct"])
@@ -73,14 +81,66 @@ def test_solana_sign_tx(session: Session, parameters, result):
encoded_token=encoded_token,
)
- actual_result = sign_tx(
- session,
- address_n=parse_path(parameters["address"]),
- serialized_tx=serialized_tx,
- additional_info=additional_info,
- )
+ if parameters.get("payment_req"):
+ purchase_memo = CoinPurchaseMemo(
+ amount="0.00001 BTC",
+ coin_name="Bitcoin",
+ slip44=0,
+ address_n=parse_path("m/44h/0h/0h/0/0"),
+ )
+ purchase_memo.address_resp = btc.get_authenticated_address(
+ session, purchase_memo.coin_name, purchase_memo.address_n
+ )
+ refund_memo = RefundMemo(address_n=parse_path("m/44h/501h/0h/1h"))
+ refund_memo.address_resp = get_authenticated_address(
+ session, refund_memo.address_n, False
+ )
+ text_details_memo = TextDetailsMemo(
+ title="Are you sure...",
+ text="... you want to swap your valuable FAKE tokens for some sats?",
+ )
+ memos = [purchase_memo, refund_memo, text_details_memo]
+ nonce = misc.get_nonce(session)
+ payment_request = make_payment_request(
+ session,
+ recipient_name="trezor.io",
+ slip44=501,
+ outputs=[
+ (
+ i["data"]["amount"],
+ parameters["construct"]["accounts"][
+ i["accounts"]["destination_account"]
+ ],
+ )
+ for i in parameters["construct"]["instructions"]
+ ],
+ memos=memos,
+ nonce=nonce,
+ )
+ else:
+ payment_request = None
- assert actual_result == bytes.fromhex(result["expected_signature"])
+ if "expected_signature" in result:
+ actual_result = sign_tx(
+ session,
+ address_n=parse_path(parameters["address"]),
+ serialized_tx=serialized_tx,
+ additional_info=additional_info,
+ payment_req=payment_request,
+ )
+
+ assert actual_result == bytes.fromhex(result["expected_signature"])
+ elif "error_message" in result:
+ with pytest.raises(TrezorFailure, match=result["error_message"]):
+ sign_tx(
+ session,
+ address_n=parse_path(parameters["address"]),
+ serialized_tx=serialized_tx,
+ additional_info=additional_info,
+ payment_req=payment_request,
+ )
+ else:
+ assert False, "Invalid expected result"
def _serialize_tx(tx_construct):
diff --git a/tests/ui_tests/fixtures.json b/tests/ui_tests/fixtures.json
index 551be03e..94a1c762 100644
--- a/tests/ui_tests/fixtures.json
+++ b/tests/ui_tests/fixtures.json
@@ -11553,6 +11553,8 @@
"T3B1_cs_solana-test_sign_tx.py::test_solana_sign_tx[mint_to_checked_with_token_definition]": "91c7111dbcb35cc3a75f4cf184ea563af264ee392b06d3f7236cbcadbe7e83c2",
"T3B1_cs_solana-test_sign_tx.py::test_solana_sign_tx[multiple_claim_instructions]": "8c1eaaa7e3cd0187d4d6d08397e856b798c2cdf992347da92799211950d68b5f",
"T3B1_cs_solana-test_sign_tx.py::test_solana_sign_tx[multiple_unstake_instructions]": "692577954117a7e25df314113c4b6ec28005ce7f89088d43a26e6c451c1c19e4",
+"T3B1_cs_solana-test_sign_tx.py::test_solana_sign_tx[payment_request]": "75c67c009c6ac48773b3e28a9b69f28f58920f4cac4cf276fc99a0ccbb897527",
+"T3B1_cs_solana-test_sign_tx.py::test_solana_sign_tx[payment_request_-_multiple_transfers]": "92840d4624bb07440bb1ab5cb4b57251c9950388accbc8334a9a7d609ededb01",
"T3B1_cs_solana-test_sign_tx.py::test_solana_sign_tx[revoke]": "25869b974eea2a51c189d7bcf7804c5664e5e4344a0d2852bba6cb7e08c82c56",
"T3B1_cs_solana-test_sign_tx.py::test_solana_sign_tx[revoke_-_multisig]": "3d992346f277193dee653d54f0ebed1183d2a31e28ed2a5d419c17ec1b9dd809",
"T3B1_cs_solana-test_sign_tx.py::test_solana_sign_tx[set_authority]": "aa091f80f19b917689d87f770b348eef4a8d5046284c392790c4fbe832396039",
@@ -12989,6 +12991,8 @@
"T3B1_de_solana-test_sign_tx.py::test_solana_sign_tx[mint_to_checked_with_token_definition]": "44824b0a0087581e17726344c47532589ae0244edf9b200456107631a00ba80c",
"T3B1_de_solana-test_sign_tx.py::test_solana_sign_tx[multiple_claim_instructions]": "75b877b68fab91a49d3e67171b7f3aa84808457fe47eb139cee3d47941f4f5f9",
"T3B1_de_solana-test_sign_tx.py::test_solana_sign_tx[multiple_unstake_instructions]": "456527e0e7c8a50d5c4015a985b3f28aeb728903179da2b71806f43868c70f34",
+"T3B1_de_solana-test_sign_tx.py::test_solana_sign_tx[payment_request]": "ef8362ef0d18e3a1137f2daac9ce2678f47bc219615b51236f335c9475540fb0",
+"T3B1_de_solana-test_sign_tx.py::test_solana_sign_tx[payment_request_-_multiple_transfers]": "c92ee4e050daadcfc7cc95657b00deed76bb463d486eefcc66455bdbe60faa33",
"T3B1_de_solana-test_sign_tx.py::test_solana_sign_tx[revoke]": "507e53b72f6638739ab6b409d7bd1d204b088db0189fb6b284b6873cc9fc3a06",
"T3B1_de_solana-test_sign_tx.py::test_solana_sign_tx[revoke_-_multisig]": "97f92325e525106259f7e4490e8f2a2d8ff7d69b4fe76ffbd1e3a7e5a03ac899",
"T3B1_de_solana-test_sign_tx.py::test_solana_sign_tx[set_authority]": "8860c8df0d9bd330b55400d8ef6712449dae6f3b5a53c9367cde59a4127f25a5",
@@ -14425,6 +14429,8 @@
"T3B1_en_solana-test_sign_tx.py::test_solana_sign_tx[mint_to_checked_with_token_definition]": "6324e8586dabbecf189ba3493502e291724cdf2e18d573132dff1263dee0f1b0",
"T3B1_en_solana-test_sign_tx.py::test_solana_sign_tx[multiple_claim_instructions]": "b3658e04e89344c0d0f7f37228491952c85a1c91e7f6f52209820dcd6fea8492",
"T3B1_en_solana-test_sign_tx.py::test_solana_sign_tx[multiple_unstake_instructions]": "e11934f4bf5dca999dd18d7e88ef36eaaac835fc7d899143cc60105d9797bcfa",
+"T3B1_en_solana-test_sign_tx.py::test_solana_sign_tx[payment_request]": "e9f3ecd94bc3eebee5aad7e7fbe656bc95965fb4a5a7ff0d5ee3ffaa5a8c0b72",
+"T3B1_en_solana-test_sign_tx.py::test_solana_sign_tx[payment_request_-_multiple_transfers]": "1477d62e338f4d7c1bfac2fc5d2fc231218da5768666c11482dc1f83229506f3",
"T3B1_en_solana-test_sign_tx.py::test_solana_sign_tx[revoke]": "78f45f2625b3101fc796fae2b1b55383158dd4db3c8678ecd8ba00d0d45c7f0a",
"T3B1_en_solana-test_sign_tx.py::test_solana_sign_tx[revoke_-_multisig]": "2b2dc1d733ebb377880ce62682b76c9d3c108f4ec5a582d9a875012f4d3e0e11",
"T3B1_en_solana-test_sign_tx.py::test_solana_sign_tx[set_authority]": "a9f9f5c4bf205555e7f1a4f89012b06e36143f575c4e33f78d619124b433a846",
@@ -15861,6 +15867,8 @@
"T3B1_es_solana-test_sign_tx.py::test_solana_sign_tx[mint_to_checked_with_token_definition]": "02ac3699cddeb0f1d2b8770ce6c883ca5f2b26ca3d09c87e1399d05b08d37aa4",
"T3B1_es_solana-test_sign_tx.py::test_solana_sign_tx[multiple_claim_instructions]": "614e364e99f11367f3c4276a5ee68dfc5e0f8ccb73b8211480dc678fd1176eea",
"T3B1_es_solana-test_sign_tx.py::test_solana_sign_tx[multiple_unstake_instructions]": "c4ca90e08c201d200abe54bafcd3c7332301b4a5cf13f5258c8a7b3f49ac86d3",
+"T3B1_es_solana-test_sign_tx.py::test_solana_sign_tx[payment_request]": "4a4103876bfff46b1c0f924dbfd05e5b8104d4772cd89824df0709d5644db253",
+"T3B1_es_solana-test_sign_tx.py::test_solana_sign_tx[payment_request_-_multiple_transfers]": "211e7c3419bd48ceefc570971fc522f809b39614563be948fd1e545366506dee",
"T3B1_es_solana-test_sign_tx.py::test_solana_sign_tx[revoke]": "34255d61124f139d541268435d9164890340f2beb58dac3e47165be4ab66d807",
"T3B1_es_solana-test_sign_tx.py::test_solana_sign_tx[revoke_-_multisig]": "4b1b6cc2c9e0f075f6219becc7478a28178ab895a9bca139490f18278e9f91a9",
"T3B1_es_solana-test_sign_tx.py::test_solana_sign_tx[set_authority]": "cbdf1dff3320a80bf894c32d1da1f87e2a7db54a6220d23179e80ea625109c82",
@@ -17297,6 +17305,8 @@
"T3B1_fr_solana-test_sign_tx.py::test_solana_sign_tx[mint_to_checked_with_token_definition]": "38d67dbf1154ee7d59af3479a659667dff2b9864322f60b8a187227e16c112c2",
"T3B1_fr_solana-test_sign_tx.py::test_solana_sign_tx[multiple_claim_instructions]": "05da6aeb89a980b110fa52fed88511ac1448a36ac4f82b0c84ffa308aaae50ab",
"T3B1_fr_solana-test_sign_tx.py::test_solana_sign_tx[multiple_unstake_instructions]": "b643b9866a4c2f321d41425d18a40bd8ecdaa485a6634860347323710315feed",
+"T3B1_fr_solana-test_sign_tx.py::test_solana_sign_tx[payment_request]": "e42c41320ff53160d1d97cc4a37cdb47eafa5b5214b3188a756e7b423903c957",
+"T3B1_fr_solana-test_sign_tx.py::test_solana_sign_tx[payment_request_-_multiple_transfers]": "35c9c9529c59ca5c386ac05856f7452f26cde732203b5b61ec9321230b52df89",
"T3B1_fr_solana-test_sign_tx.py::test_solana_sign_tx[revoke]": "3c1a8f23b646a429f8d592931aa5c9cec8e873da088258522226129cf84a7e37",
"T3B1_fr_solana-test_sign_tx.py::test_solana_sign_tx[revoke_-_multisig]": "115f8ded8fc5691c6996ee5a3ef947a4665474b6a05d9e5a22c1ce76f39d5027",
"T3B1_fr_solana-test_sign_tx.py::test_solana_sign_tx[set_authority]": "8f285f4156a3bf70fe6aa37283984bf06e4aacb7e75553734a6a0934842db98c",
@@ -18733,6 +18743,8 @@
"T3B1_pt_solana-test_sign_tx.py::test_solana_sign_tx[mint_to_checked_with_token_definition]": "1864d6dc791ad4a8c4fcdc76fe4c672a694f7ecbb22217b2575684cf0459dca3",
"T3B1_pt_solana-test_sign_tx.py::test_solana_sign_tx[multiple_claim_instructions]": "8c34aca63818d60a790902ae7c75dca61552c1532749e8c5717393677cd03ee3",
"T3B1_pt_solana-test_sign_tx.py::test_solana_sign_tx[multiple_unstake_instructions]": "021ec8e4c3139993e9119648d6c8fa7c5a0e5115508074f2830f72117a14f298",
+"T3B1_pt_solana-test_sign_tx.py::test_solana_sign_tx[payment_request]": "96fb298e9406bfc79edfad1670cc6de4329d60e5f644696657aa9742f1da1abb",
+"T3B1_pt_solana-test_sign_tx.py::test_solana_sign_tx[payment_request_-_multiple_transfers]": "6ba5ca7223cd8ad675e081407f186acdfc8420304eea96de0fde5eda45ef0a57",
"T3B1_pt_solana-test_sign_tx.py::test_solana_sign_tx[revoke]": "af8d94625c6ab1b5f0a449cd16e916e0a2c80fd982d79cafcdf47bd72973420c",
"T3B1_pt_solana-test_sign_tx.py::test_solana_sign_tx[revoke_-_multisig]": "dfc9972865a3b5e6729ca7dd906df0e4f9ed70758306024e7860f9c87a184f01",
"T3B1_pt_solana-test_sign_tx.py::test_solana_sign_tx[set_authority]": "d1a70252abdeb71437b0e6c335be8bdc9dd461adcba31086181bb47f934255b4",
@@ -20564,6 +20576,8 @@
"T3T1_cs_solana-test_sign_tx.py::test_solana_sign_tx[mint_to_checked_with_token_definition]": "80d11619a044cfc2bc91ed8478e497233db299aed51ecd4ec5c0bf46a4cac7f8",
"T3T1_cs_solana-test_sign_tx.py::test_solana_sign_tx[multiple_claim_instructions]": "ab02c175a771f71bb1103f57dd441725e323b5b94725e38f89cce3b168837558",
"T3T1_cs_solana-test_sign_tx.py::test_solana_sign_tx[multiple_unstake_instructions]": "5d05ef09d7facf8e52c0d05330388f5a988e8ab32f53ea647005d5e3b4b9f97d",
+"T3T1_cs_solana-test_sign_tx.py::test_solana_sign_tx[payment_request]": "f98690bb374d10745d5793e1560d6fbfde80b89f732197d1481a09c14dc1fc01",
+"T3T1_cs_solana-test_sign_tx.py::test_solana_sign_tx[payment_request_-_multiple_transfers]": "592adf9c06f8f39132298b46037dd524fac99e58237a0c023197bf47df67d632",
"T3T1_cs_solana-test_sign_tx.py::test_solana_sign_tx[revoke]": "9e382c26d3fc79a6af7bcc1defa1a66acb42f4abe59366a9ee04deb216fcf03b",
"T3T1_cs_solana-test_sign_tx.py::test_solana_sign_tx[revoke_-_multisig]": "ba76529047037224215418dcf1683e67512abb1e98b48cf0630067c8ba68d7b2",
"T3T1_cs_solana-test_sign_tx.py::test_solana_sign_tx[set_authority]": "32c774e385efa98de355919dda4af1c11f0d606e2a24c25a3efceed5604c79e9",
@@ -22031,6 +22045,8 @@
"T3T1_de_solana-test_sign_tx.py::test_solana_sign_tx[mint_to_checked_with_token_definition]": "75cb83899e29d6a627eae83a843d5e8c94ebca0cecedc658077c248bca4f8240",
"T3T1_de_solana-test_sign_tx.py::test_solana_sign_tx[multiple_claim_instructions]": "39d2ca4c679d72665ad3ba735c2939b2c7186dd6d556777c9cb615e672507373",
"T3T1_de_solana-test_sign_tx.py::test_solana_sign_tx[multiple_unstake_instructions]": "ee964d60473df959a2b21e7baa7ed33818d237d61e4440b8808d892bb1dd26af",
+"T3T1_de_solana-test_sign_tx.py::test_solana_sign_tx[payment_request]": "d88ec983d198a7ad9ec2d1fc38978047dabfda7d47b7b5de70497df3ad0d7731",
+"T3T1_de_solana-test_sign_tx.py::test_solana_sign_tx[payment_request_-_multiple_transfers]": "f2fcbbd7ad83aff9adc0ee97fe98e7272d8bcfcc4a023798e2ab1c9895fda70f",
"T3T1_de_solana-test_sign_tx.py::test_solana_sign_tx[revoke]": "37634d1000b445ae3a53df09518f364a1f92451536e6ce25f9ee0ed10b8c127c",
"T3T1_de_solana-test_sign_tx.py::test_solana_sign_tx[revoke_-_multisig]": "f9f6c1f06577042adc46c3d808fc13e4b75017375c50810a2f8c5e0f001e10a4",
"T3T1_de_solana-test_sign_tx.py::test_solana_sign_tx[set_authority]": "fc1e6833b095fb704b2613d696604378a7c9ee63b2e5a60de4044278dd6df2a0",
@@ -23498,6 +23514,8 @@
"T3T1_en_solana-test_sign_tx.py::test_solana_sign_tx[mint_to_checked_with_token_definition]": "c47e5a1e0edae6eeee1497537205d59e29f1ce54715a0e54dc5134f7ad3d6caa",
"T3T1_en_solana-test_sign_tx.py::test_solana_sign_tx[multiple_claim_instructions]": "f15fcb894119775020822d50ba7bc10051e02f7ffab400ada4727c8740969682",
"T3T1_en_solana-test_sign_tx.py::test_solana_sign_tx[multiple_unstake_instructions]": "860c825de9e4537b4ea9b05493e35b488e121e7f0366667349fe497506292bc7",
+"T3T1_en_solana-test_sign_tx.py::test_solana_sign_tx[payment_request]": "b6b95f62ee69f6be7037a57be2be76cb975da7d094de62ee268fac92cc0594ea",
+"T3T1_en_solana-test_sign_tx.py::test_solana_sign_tx[payment_request_-_multiple_transfers]": "cb8641952bec9e793e7d19f281a85a0ca1be2c3397ca5c0cf4ee7ad905429984",
"T3T1_en_solana-test_sign_tx.py::test_solana_sign_tx[revoke]": "d8123617ae260a988401280b946b20891169638063b55cced80e3057e39e7b10",
"T3T1_en_solana-test_sign_tx.py::test_solana_sign_tx[revoke_-_multisig]": "ac29291b148066d9df72f216197cd82c6fd7dd68e51c04edee11cf9bdb6b5e19",
"T3T1_en_solana-test_sign_tx.py::test_solana_sign_tx[set_authority]": "f841510ae6a594e83121fd1b2a472a89baa76059bd12cce273106da5072ae554",
@@ -24965,6 +24983,8 @@
"T3T1_es_solana-test_sign_tx.py::test_solana_sign_tx[mint_to_checked_with_token_definition]": "065980cc1a32d2684de0abb8ab9028d8adaa309f1b6608219f637bd2da173567",
"T3T1_es_solana-test_sign_tx.py::test_solana_sign_tx[multiple_claim_instructions]": "ded3207b5505fc6152dde460bd1a7f683af2a6f046936ee488492780300dbca2",
"T3T1_es_solana-test_sign_tx.py::test_solana_sign_tx[multiple_unstake_instructions]": "73946b3aa13bfb97e5ccf71e1b21c3b9e31001c6080da60dead9c9ff58b7720c",
+"T3T1_es_solana-test_sign_tx.py::test_solana_sign_tx[payment_request]": "9f429a58ea864644c43c5004435f308837ea6bc4ff993fecb6d54d17c6a9d2dc",
+"T3T1_es_solana-test_sign_tx.py::test_solana_sign_tx[payment_request_-_multiple_transfers]": "c568b82943d9f63ad6b29b7dee6f5ed9dca78fc9610d4fa7f12bb8a061a6882a",
"T3T1_es_solana-test_sign_tx.py::test_solana_sign_tx[revoke]": "ad529e586b8f4b507462f320dcf59eea14db4ad8a05fa64f052fca97d37033a6",
"T3T1_es_solana-test_sign_tx.py::test_solana_sign_tx[revoke_-_multisig]": "b143026f07da2e29a65898a5475eb9ea8ea3fd640e9b113fc74be43a79e14f0c",
"T3T1_es_solana-test_sign_tx.py::test_solana_sign_tx[set_authority]": "7a888ae08eac518bf0c3d0b9cfb7cedeadc7a02757a4509fb47cc34465a8331a",
@@ -26432,6 +26452,8 @@
"T3T1_fr_solana-test_sign_tx.py::test_solana_sign_tx[mint_to_checked_with_token_definition]": "0cb5884da2104a6de759f7aae0ca106754bb72c0a8de2048393b6a672b95b558",
"T3T1_fr_solana-test_sign_tx.py::test_solana_sign_tx[multiple_claim_instructions]": "47b64f89d0b3ccb0e6aeb1421273a362c9f31b61af091557bc8d32439e08161d",
"T3T1_fr_solana-test_sign_tx.py::test_solana_sign_tx[multiple_unstake_instructions]": "e8a9909826f1bd6829685b0fb0b2dfaf5ab57f47b2b6c931ce065c4ce1e53e35",
+"T3T1_fr_solana-test_sign_tx.py::test_solana_sign_tx[payment_request]": "43b991cff87e4f311c2416d5f3c009b474f15dba3d98720e417812a505d0c9e7",
+"T3T1_fr_solana-test_sign_tx.py::test_solana_sign_tx[payment_request_-_multiple_transfers]": "c4dffa9195d175f9bc4a23e9e0f80b92f7c6687128918a5a70c14b4a6e7e3694",
"T3T1_fr_solana-test_sign_tx.py::test_solana_sign_tx[revoke]": "9830515d389dcd84c5ca2e7b60dc95a65144fb0d48f49d4d45b32a177d8c995f",
"T3T1_fr_solana-test_sign_tx.py::test_solana_sign_tx[revoke_-_multisig]": "51dfc41d100b665601f360ed8ff0c93768cc4e08f22c04ea00b78ad226343dd9",
"T3T1_fr_solana-test_sign_tx.py::test_solana_sign_tx[set_authority]": "8d1d50f486dc647df3f61f9984356f3543e91fea6fa7564beb22d9827b86a432",
@@ -27899,6 +27921,8 @@
"T3T1_pt_solana-test_sign_tx.py::test_solana_sign_tx[mint_to_checked_with_token_definition]": "5d0e6b53b283cd9d6187dd5484ba297f7ef5f3959c6d99b29e45148c7ea208e2",
"T3T1_pt_solana-test_sign_tx.py::test_solana_sign_tx[multiple_claim_instructions]": "74fba58b2e27603af9468df27f48274ff4329fce2aea7dd94bb33d9d67f20d8a",
"T3T1_pt_solana-test_sign_tx.py::test_solana_sign_tx[multiple_unstake_instructions]": "cd7c2838bc2564429b1e37ee1efa575c49d014aef16f9e9506fd4cde0cf0add0",
+"T3T1_pt_solana-test_sign_tx.py::test_solana_sign_tx[payment_request]": "fbb3066f72c48eaaf3ebf1238d421351d2330e24a524bcf5ad3595aabb2b0b78",
+"T3T1_pt_solana-test_sign_tx.py::test_solana_sign_tx[payment_request_-_multiple_transfers]": "c15216b8aa033bd81f0a8fb6415c6728320b0c30fe3150eeb8a1749ae0a1a83c",
"T3T1_pt_solana-test_sign_tx.py::test_solana_sign_tx[revoke]": "ea34f10049bcfb5455fc294ef528c831bb6772733798426be90e4a28f47c9e27",
"T3T1_pt_solana-test_sign_tx.py::test_solana_sign_tx[revoke_-_multisig]": "5de96dbcb81fdb6c4a7679298eb9266e388f8d66471c45bb2a8e351274066411",
"T3T1_pt_solana-test_sign_tx.py::test_solana_sign_tx[set_authority]": "7f52a77a9dc297b25b395237cbaad6c0a0d006e8e0d3207d10087503574a7cef",
@@ -29731,6 +29755,8 @@
"T3W1_cs_solana-test_sign_tx.py::test_solana_sign_tx[mint_to_checked_with_token_definition]": "ffa0b79acc59fc58256ab599cf5c6e7eccec22658ac755a390a856958d5abf26",
"T3W1_cs_solana-test_sign_tx.py::test_solana_sign_tx[multiple_claim_instructions]": "f623e176ca4488fd14a79e5f6bc9981fb002a31ae57aefb82cae76cea377e8b1",
"T3W1_cs_solana-test_sign_tx.py::test_solana_sign_tx[multiple_unstake_instructions]": "1d271a206bf42785dd77e538fbe4448e7f52994abef77140e72b6e45d86767f2",
+"T3W1_cs_solana-test_sign_tx.py::test_solana_sign_tx[payment_request]": "dcd8e55555469eacf439ab37247bbde84a96fe100069df2112c8840a93818747",
+"T3W1_cs_solana-test_sign_tx.py::test_solana_sign_tx[payment_request_-_multiple_transfers]": "535037bfe5f1459cfdf305915835d8bf2a9a427c3f60264a8cc3ca6f306a61b1",
"T3W1_cs_solana-test_sign_tx.py::test_solana_sign_tx[revoke]": "3b25f8cb6725ea8265fbfacd0f2e3047be0116df2a84b4a684c7ead4cd586810",
"T3W1_cs_solana-test_sign_tx.py::test_solana_sign_tx[revoke_-_multisig]": "5ee8ba6f2ac1532f7229affdf7673f4bb8217df2c3e41f6a8594d1c0581bd166",
"T3W1_cs_solana-test_sign_tx.py::test_solana_sign_tx[set_authority]": "6e5b4e63c7c3d5ef769aa714927a823e1161de2358d6652cd1c781b5b24765f6",
@@ -31188,6 +31214,8 @@
"T3W1_de_solana-test_sign_tx.py::test_solana_sign_tx[mint_to_checked_with_token_definition]": "3bc9c54a8e58126163c63cf9ae35db03f43f05c163513e73eb0649b8c5c562f5",
"T3W1_de_solana-test_sign_tx.py::test_solana_sign_tx[multiple_claim_instructions]": "44a1ef8041e9da2e1e7711d4bd5d01900983ba17b0fbde5e8da336b19a529e40",
"T3W1_de_solana-test_sign_tx.py::test_solana_sign_tx[multiple_unstake_instructions]": "bb12533678586085eee9d1bead9c349a6587f4f958505a70d384094cd06171c1",
+"T3W1_de_solana-test_sign_tx.py::test_solana_sign_tx[payment_request]": "8989f5a30b45cbbb500e9fee7bb4ec57badc12415003e264b1ab3b13d3f7686a",
+"T3W1_de_solana-test_sign_tx.py::test_solana_sign_tx[payment_request_-_multiple_transfers]": "2bf2200d3f158d1cffae639cd632a3b651fe53af5942b65eb881cfce12817592",
"T3W1_de_solana-test_sign_tx.py::test_solana_sign_tx[revoke]": "ed1559f1564f8cec398d874be58754d0f6ade48f21c3e1ee52676f7478966842",
"T3W1_de_solana-test_sign_tx.py::test_solana_sign_tx[revoke_-_multisig]": "a0f868ceb94f7dafe781229a78896bdcbab349987dd6c2cec2bb86964b207ec6",
"T3W1_de_solana-test_sign_tx.py::test_solana_sign_tx[set_authority]": "5fdb35ab9bf60d0a5ea5e62fce69b1d00648af3045036fe251c357f427e9f16c",
@@ -32645,6 +32673,8 @@
"T3W1_en_solana-test_sign_tx.py::test_solana_sign_tx[mint_to_checked_with_token_definition]": "300b28dcaa61fd9354b43b690da50ed781ba80f005b3d006eb9e34e3b8cab402",
"T3W1_en_solana-test_sign_tx.py::test_solana_sign_tx[multiple_claim_instructions]": "4f201aa0a83d8a23a40fc9fea894387aa214a5af8381565a582ec5450379a3d3",
"T3W1_en_solana-test_sign_tx.py::test_solana_sign_tx[multiple_unstake_instructions]": "2812c39ac876678b015d3e46efc17f4769cd9d71d31e38aa0d62879f693ecff0",
+"T3W1_en_solana-test_sign_tx.py::test_solana_sign_tx[payment_request]": "ca460060923e5edcdd18b92617b26cc64607c0815fb9b3ec8d123ce13d138ee9",
+"T3W1_en_solana-test_sign_tx.py::test_solana_sign_tx[payment_request_-_multiple_transfers]": "2b19d878184abddf53159d4acb504a1e86a7c2d5fd15de433495742ba7df9cc8",
"T3W1_en_solana-test_sign_tx.py::test_solana_sign_tx[revoke]": "32f7086d560a6b5727ae49ce802372ea30e6e87895498a792a7d1453599cdb62",
"T3W1_en_solana-test_sign_tx.py::test_solana_sign_tx[revoke_-_multisig]": "bacbb2337953f9c96784232a42db94dbded0f8ee5c7dc5c73de3401adbb38020",
"T3W1_en_solana-test_sign_tx.py::test_solana_sign_tx[set_authority]": "48f2820a80bbd2e3df3a3050ffc3b3460758f740c47b8ec564e94bde103046eb",
@@ -34102,6 +34132,8 @@
"T3W1_es_solana-test_sign_tx.py::test_solana_sign_tx[mint_to_checked_with_token_definition]": "c0f13053b235886ed25555712932358990f4aea87ca6af4e84073f8eaa014f3f",
"T3W1_es_solana-test_sign_tx.py::test_solana_sign_tx[multiple_claim_instructions]": "13dcebf651f91aa9c5e64aeac3676d7800628168a9725bfce7c70ca7c25fafb1",
"T3W1_es_solana-test_sign_tx.py::test_solana_sign_tx[multiple_unstake_instructions]": "f45d7aff9ea96b4cc5a373f0d20cf4ec102e94aeca2cece5ee31086dbb6c7ebc",
+"T3W1_es_solana-test_sign_tx.py::test_solana_sign_tx[payment_request]": "978894c8eb1ab4f1680817ca012580e7e66f48cb2dd4c6f17dc9f20da90d751f",
+"T3W1_es_solana-test_sign_tx.py::test_solana_sign_tx[payment_request_-_multiple_transfers]": "991c2fedae415c4284948d276edc08daeea466ca5849934ed2784cc8884ee589",
"T3W1_es_solana-test_sign_tx.py::test_solana_sign_tx[revoke]": "2a1d2508b8f6d28f5cbcba5fc48b60a8e994e3de14081f8883520680c74629ce",
"T3W1_es_solana-test_sign_tx.py::test_solana_sign_tx[revoke_-_multisig]": "f8cb2c66b12dbe36cbdbf66ebb95389d2f1f54697b7abd182c6063156d05e727",
"T3W1_es_solana-test_sign_tx.py::test_solana_sign_tx[set_authority]": "924ffd15c73443f797bb4963f6e14b99d7c8068c06aceb6d7de38707610d75fa",
@@ -35559,6 +35591,8 @@
"T3W1_fr_solana-test_sign_tx.py::test_solana_sign_tx[mint_to_checked_with_token_definition]": "ff7f67295fca9c03d9e1e5faa8b1ce22ab9a8f9566979014c883b6f775f974ae",
"T3W1_fr_solana-test_sign_tx.py::test_solana_sign_tx[multiple_claim_instructions]": "a4807debf4c234c907ab0d600b9f988743bd379ca54a4d838b1fd7e2da40a97b",
"T3W1_fr_solana-test_sign_tx.py::test_solana_sign_tx[multiple_unstake_instructions]": "a29237404ad61d11ecf10e729a3958b0388fedcf7be254c5773bb3838b0f2f76",
+"T3W1_fr_solana-test_sign_tx.py::test_solana_sign_tx[payment_request]": "7d74e81ea4a71c4cc7dd82d5b21ad26591e8c93e93b9db0304b0e2622637b8e9",
+"T3W1_fr_solana-test_sign_tx.py::test_solana_sign_tx[payment_request_-_multiple_transfers]": "250f727140e1737e1e25e4620b4557d886c40e53f8205987dacb8904050dc474",
"T3W1_fr_solana-test_sign_tx.py::test_solana_sign_tx[revoke]": "5af413eda1ce69dac248d4b70ff0fde44bc378fb7ae41a89cde32680bf06e220",
"T3W1_fr_solana-test_sign_tx.py::test_solana_sign_tx[revoke_-_multisig]": "115a2f9ae5643c3b1ce7a777c780e7e34397a5409790a44cf9821ba9e2f8983f",
"T3W1_fr_solana-test_sign_tx.py::test_solana_sign_tx[set_authority]": "b179e6beda3d68f0af3c52b54b272f633a91a5b1f17bcf22a31c23c023f4aeb6",
@@ -37016,6 +37050,8 @@
"T3W1_pt_solana-test_sign_tx.py::test_solana_sign_tx[mint_to_checked_with_token_definition]": "02465864c9355cab0359c338ba5dcdd8e5079327bb6794ca103c974aac5bfe74",
"T3W1_pt_solana-test_sign_tx.py::test_solana_sign_tx[multiple_claim_instructions]": "d44aa7a90c4dea7c695f86abbf7905de7ffd07f22ee19c524ea3092a5de0237c",
"T3W1_pt_solana-test_sign_tx.py::test_solana_sign_tx[multiple_unstake_instructions]": "6cd81cd168e95eb271c34dce48a97b9e1d8c7169224341e977c474b91e839d2d",
+"T3W1_pt_solana-test_sign_tx.py::test_solana_sign_tx[payment_request]": "835577d8e255f1e153449f93e81891067da2a55d48842d2b83ea82d75f5b0ce6",
+"T3W1_pt_solana-test_sign_tx.py::test_solana_sign_tx[payment_request_-_multiple_transfers]": "637658c0c6bbf3267f67895c12aeea91280f0471133d7865e4b0d19bdd1da874",
"T3W1_pt_solana-test_sign_tx.py::test_solana_sign_tx[revoke]": "f55d3072b7301380ff517be49979dd351d87603da73a658fcdf6bd6e0ad269c0",
"T3W1_pt_solana-test_sign_tx.py::test_solana_sign_tx[revoke_-_multisig]": "bbf4412a1fe76e5a19b5f7051f0bfe791f01f3b6fb05e9d20558da28c0bcd330",
"T3W1_pt_solana-test_sign_tx.py::test_solana_sign_tx[set_authority]": "899af6a7a3be0734c5cc4603d70a6324086002958b65a1907a2738f2a42652dd",
Why this scored 28/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.