fix(solana): use template for indexed cosigners [no changelog]
What changed, and why it matters
This commit fixes a minor user-interface wording issue in Trezor's Solana app. Previously, the device built the cosigner label by manually combining the word 'Cosigner' with a number, which could cause problems for translations. Now it uses a proper translation template 'Cosigner {0}'. There is no direct evidence this is a security vulnerability, but inconsistent or untranslatable labels could theoretically contribute to user confusion when reviewing multisig signers.
Treat as a routine UI/translation fix. No urgent security action is required. If auditing, verify that the new template is correctly translated in all supported languages and that the index calculation `i + (i < signer_index)` still accurately reflects the intended cosigner numbering for off-chain Solana message signing.
Security signals we found
UI label construction changed from runtime string concatenation to a translation template
No changes to signing logic, address validation, or transaction parsing
No vendor disclosure of security relevance in commit message or diff
No CVE, advisory, or researcher attribution present in supplied materials
Evidence from the diff
The change replaces an f-string concatenation f'{TR.address__title_cosigner} {i + (i < signer_index)}' with a formatted translation template TR.address__title_cosigner_template.format(i + (i < signer_index)). It adds the new translation key address__title_cosigner_template with value ‘Cosigner {0}’ across generated Rust translation tables, Python mocks, and JSON translation files, and updates translation signature metadata. The logic for selecting which cosigner index to display remains unchanged. No cryptographic, parsing, or authorization code is modified.
Changed components
core/src/apps/solana/layout.pycore/translations/en.jsoncore/translations/order.jsoncore/translations/signatures.jsoncore/embed/rust/librust_qstr.hcore/embed/rust/src/translations/generated/translated_string.rscore/mocks/trezortranslate_keys.pyiInspect captured patch +43 / −5
diff --git a/core/embed/rust/librust_qstr.h b/core/embed/rust/librust_qstr.h
index 4bd95103..cca33a69 100644
--- a/core/embed/rust/librust_qstr.h
+++ b/core/embed/rust/librust_qstr.h
@@ -106,6 +106,7 @@ static void _librust_qstrs(void) {
MP_QSTR_address__public_key_confirmed;
MP_QSTR_address__qr_code;
MP_QSTR_address__title_cosigner;
+ MP_QSTR_address__title_cosigner_template;
MP_QSTR_address__title_provider_address;
MP_QSTR_address__title_receive_address;
MP_QSTR_address__title_refund_address;
diff --git a/core/embed/rust/src/translations/generated/translated_string.rs b/core/embed/rust/src/translations/generated/translated_string.rs
index 8b35dab4..189c3ea7 100644
--- a/core/embed/rust/src/translations/generated/translated_string.rs
+++ b/core/embed/rust/src/translations/generated/translated_string.rs
@@ -1624,6 +1624,7 @@ pub enum TranslatedString {
#[cfg(feature = "universal_fw")]
solana__offchain_is_multisig = 1232, // "The following message requires multiple signers."
words__comm_continue = 1233, // "Communication with your connected device failed. It's safe to continue."
+ address__title_cosigner_template = 1234, // "Cosigner {0}"
}
impl TranslatedString {
@@ -2865,6 +2866,7 @@ impl TranslatedString {
"Application domain",
"The following message requires multiple signers.",
"Communication with your connected device failed. It's safe to continue.",
+ "Cosigner {0}",
);
#[cfg(all(feature = "debug", feature = "universal_fw"))]
@@ -4104,6 +4106,7 @@ impl TranslatedString {
19671,
19719,
19790,
+ 19802,
];
#[cfg(all(feature = "debug", not(feature = "universal_fw")))]
@@ -5342,6 +5345,7 @@ impl TranslatedString {
"Application domain",
"The following message requires multiple signers.",
"Communication with your connected device failed. It's safe to continue.",
+ "Cosigner {0}",
);
#[cfg(all(feature = "debug", not(feature = "universal_fw")))]
@@ -6581,6 +6585,7 @@ impl TranslatedString {
19671,
19719,
19790,
+ 19802,
];
#[cfg(all(not(feature = "debug"), feature = "universal_fw"))]
@@ -7819,6 +7824,7 @@ impl TranslatedString {
"Application domain",
"The following message requires multiple signers.",
"Communication with your connected device failed. It's safe to continue.",
+ "Cosigner {0}",
);
#[cfg(all(not(feature = "debug"), feature = "universal_fw"))]
@@ -9058,6 +9064,7 @@ impl TranslatedString {
19671,
19719,
19790,
+ 19802,
];
#[cfg(all(not(feature = "debug"), not(feature = "universal_fw")))]
@@ -10296,6 +10303,7 @@ impl TranslatedString {
"Application domain",
"The following message requires multiple signers.",
"Communication with your connected device failed. It's safe to continue.",
+ "Cosigner {0}",
);
#[cfg(all(not(feature = "debug"), not(feature = "universal_fw")))]
@@ -11535,6 +11543,7 @@ impl TranslatedString {
19671,
19719,
19790,
+ 19802,
];
} else if #[cfg(feature = "layout_caesar")] {
@@ -12774,6 +12783,7 @@ impl TranslatedString {
"Application domain",
"The following message requires multiple signers.",
"Communication with your connected device failed. It's safe to continue.",
+ "Cosigner {0}",
);
#[cfg(all(feature = "debug", feature = "universal_fw"))]
@@ -14013,6 +14023,7 @@ impl TranslatedString {
17609,
17657,
17728,
+ 17740,
];
#[cfg(all(feature = "debug", not(feature = "universal_fw")))]
@@ -15251,6 +15262,7 @@ impl TranslatedString {
"Application domain",
"The following message requires multiple signers.",
"Communication with your connected device failed. It's safe to continue.",
+ "Cosigner {0}",
);
#[cfg(all(feature = "debug", not(feature = "universal_fw")))]
@@ -16490,6 +16502,7 @@ impl TranslatedString {
17609,
17657,
17728,
+ 17740,
];
#[cfg(all(not(feature = "debug"), feature = "universal_fw"))]
@@ -17728,6 +17741,7 @@ impl TranslatedString {
"Application domain",
"The following message requires multiple signers.",
"Communication with your connected device failed. It's safe to continue.",
+ "Cosigner {0}",
);
#[cfg(all(not(feature = "debug"), feature = "universal_fw"))]
@@ -18967,6 +18981,7 @@ impl TranslatedString {
17609,
17657,
17728,
+ 17740,
];
#[cfg(all(not(feature = "debug"), not(feature = "universal_fw")))]
@@ -20205,6 +20220,7 @@ impl TranslatedString {
"Application domain",
"The following message requires multiple signers.",
"Communication with your connected device failed. It's safe to continue.",
+ "Cosigner {0}",
);
#[cfg(all(not(feature = "debug"), not(feature = "universal_fw")))]
@@ -21444,6 +21460,7 @@ impl TranslatedString {
17609,
17657,
17728,
+ 17740,
];
} else if #[cfg(feature = "layout_delizia")] {
@@ -22683,6 +22700,7 @@ impl TranslatedString {
"Application domain",
"The following message requires multiple signers.",
"Communication with your connected device failed. It's safe to continue.",
+ "Cosigner {0}",
);
#[cfg(all(feature = "debug", feature = "universal_fw"))]
@@ -23922,6 +23940,7 @@ impl TranslatedString {
19044,
19092,
19163,
+ 19175,
];
#[cfg(all(feature = "debug", not(feature = "universal_fw")))]
@@ -25160,6 +25179,7 @@ impl TranslatedString {
"Application domain",
"The following message requires multiple signers.",
"Communication with your connected device failed. It's safe to continue.",
+ "Cosigner {0}",
);
#[cfg(all(feature = "debug", not(feature = "universal_fw")))]
@@ -26399,6 +26419,7 @@ impl TranslatedString {
19044,
19092,
19163,
+ 19175,
];
#[cfg(all(not(feature = "debug"), feature = "universal_fw"))]
@@ -27637,6 +27658,7 @@ impl TranslatedString {
"Application domain",
"The following message requires multiple signers.",
"Communication with your connected device failed. It's safe to continue.",
+ "Cosigner {0}",
);
#[cfg(all(not(feature = "debug"), feature = "universal_fw"))]
@@ -28876,6 +28898,7 @@ impl TranslatedString {
19044,
19092,
19163,
+ 19175,
];
#[cfg(all(not(feature = "debug"), not(feature = "universal_fw")))]
@@ -30114,6 +30137,7 @@ impl TranslatedString {
"Application domain",
"The following message requires multiple signers.",
"Communication with your connected device failed. It's safe to continue.",
+ "Cosigner {0}",
);
#[cfg(all(not(feature = "debug"), not(feature = "universal_fw")))]
@@ -31353,6 +31377,7 @@ impl TranslatedString {
19044,
19092,
19163,
+ 19175,
];
} else if #[cfg(feature = "layout_eckhart")] {
@@ -32592,6 +32617,7 @@ impl TranslatedString {
"Application domain",
"The following message requires multiple signers.",
"Communication with your connected device failed. It's safe to continue.",
+ "Cosigner {0}",
);
#[cfg(all(feature = "debug", feature = "universal_fw"))]
@@ -33831,6 +33857,7 @@ impl TranslatedString {
20365,
20413,
20484,
+ 20496,
];
#[cfg(all(feature = "debug", not(feature = "universal_fw")))]
@@ -35069,6 +35096,7 @@ impl TranslatedString {
"Application domain",
"The following message requires multiple signers.",
"Communication with your connected device failed. It's safe to continue.",
+ "Cosigner {0}",
);
#[cfg(all(feature = "debug", not(feature = "universal_fw")))]
@@ -36308,6 +36336,7 @@ impl TranslatedString {
20365,
20413,
20484,
+ 20496,
];
#[cfg(all(not(feature = "debug"), feature = "universal_fw"))]
@@ -37546,6 +37575,7 @@ impl TranslatedString {
"Application domain",
"The following message requires multiple signers.",
"Communication with your connected device failed. It's safe to continue.",
+ "Cosigner {0}",
);
#[cfg(all(not(feature = "debug"), feature = "universal_fw"))]
@@ -38785,6 +38815,7 @@ impl TranslatedString {
20365,
20413,
20484,
+ 20496,
];
#[cfg(all(not(feature = "debug"), not(feature = "universal_fw")))]
@@ -40023,6 +40054,7 @@ impl TranslatedString {
"Application domain",
"The following message requires multiple signers.",
"Communication with your connected device failed. It's safe to continue.",
+ "Cosigner {0}",
);
#[cfg(all(not(feature = "debug"), not(feature = "universal_fw")))]
@@ -41262,6 +41294,7 @@ impl TranslatedString {
20365,
20413,
20484,
+ 20496,
];
}
@@ -41286,6 +41319,7 @@ impl TranslatedString {
(Qstr::MP_QSTR_address__public_key_confirmed, Self::address__public_key_confirmed),
(Qstr::MP_QSTR_address__qr_code, Self::address__qr_code),
(Qstr::MP_QSTR_address__title_cosigner, Self::address__title_cosigner),
+ (Qstr::MP_QSTR_address__title_cosigner_template, Self::address__title_cosigner_template),
(Qstr::MP_QSTR_address__title_provider_address, Self::address__title_provider_address),
(Qstr::MP_QSTR_address__title_receive_address, Self::address__title_receive_address),
(Qstr::MP_QSTR_address__title_refund_address, Self::address__title_refund_address),
diff --git a/core/mocks/trezortranslate_keys.pyi b/core/mocks/trezortranslate_keys.pyi
index 922e3d62..6d16f864 100644
--- a/core/mocks/trezortranslate_keys.pyi
+++ b/core/mocks/trezortranslate_keys.pyi
@@ -17,6 +17,7 @@ class TR:
address__public_key_confirmed: str = "Public key confirmed"
address__qr_code: str = "QR code"
address__title_cosigner: str = "Cosigner"
+ address__title_cosigner_template: str = "Cosigner {0}"
address__title_provider_address: str = "Provider address"
address__title_receive_address: str = "Receive address"
address__title_refund_address: str = "Refund address"
diff --git a/core/src/apps/solana/layout.py b/core/src/apps/solana/layout.py
index 7434b8ba..fe7dd17f 100644
--- a/core/src/apps/solana/layout.py
+++ b/core/src/apps/solana/layout.py
@@ -644,7 +644,7 @@ async def confirm_offchain_signverify(
for i, signer in enumerate(offchain_message.signers):
if i != signer_index:
await confirm_address(
- f"{TR.address__title_cosigner} {i + (i < signer_index)}",
+ TR.address__title_cosigner_template.format(i + (i < signer_index)),
base58.encode(signer),
verb=TR.buttons__continue,
chunkify=chunkify,
diff --git a/core/translations/en.json b/core/translations/en.json
index ff2fc303..f2522b7c 100644
--- a/core/translations/en.json
+++ b/core/translations/en.json
@@ -39,6 +39,7 @@
"address__public_key_confirmed": "Public key confirmed",
"address__qr_code": "QR code",
"address__title_cosigner": "Cosigner",
+ "address__title_cosigner_template": "Cosigner {0}",
"address__title_provider_address": "Provider address",
"address__title_receive_address": "Receive address",
"address__title_refund_address": "Refund address",
diff --git a/core/translations/order.json b/core/translations/order.json
index 96616f86..fe81ce50 100644
--- a/core/translations/order.json
+++ b/core/translations/order.json
@@ -1232,5 +1232,6 @@
"1230": "words__made_in",
"1231": "solana__app_domain",
"1232": "solana__offchain_is_multisig",
- "1233": "words__comm_continue"
+ "1233": "words__comm_continue",
+ "1234": "address__title_cosigner_template"
}
diff --git a/core/translations/signatures.json b/core/translations/signatures.json
index 931d1058..ac76bcf6 100644
--- a/core/translations/signatures.json
+++ b/core/translations/signatures.json
@@ -1,8 +1,8 @@
{
"current": {
- "merkle_root": "442ab359d22537bc706d94860d7dd6332ffb6baf6e33ecd5a52cde92c673fa78",
- "datetime": "2026-06-17T10:25:13.263038+00:00",
- "commit": "3a54a09ba9f1c7af38f7562117b7f641e91bdbf3"
+ "merkle_root": "ca9dcceae2906c2cceb083d3db5fd984756661cf5324ed40ea13b5b9e6383c13",
+ "datetime": "2026-06-20T09:22:14.358363+00:00",
+ "commit": "f542da297ee0e5fefd125b07b517f86fef61ac3e"
},
"history": [
{
Why this scored 16/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.