What changed, and why it matters
This commit adds a new on-screen display for Tron cryptocurrency swaps that use a memo starting with '=:' (called 'SwapKit' style). It shows the user extra details such as the destination asset, destination address, raw amount, memo, and expiration time before signing. The change is mostly a UI feature, but it also parses and displays user-controlled memo text, which could be abused to mislead the user if the memo contains crafted text. There is no evidence in the commit that this is a security fix or that the vendor called it a vulnerability.
Treat as a feature commit, but review the new memo-parsing UI path for spoofing risks. Ensure the memo field has strict length limits and that the parsed destination asset/address is clearly labeled as 'from memo' so users cannot be tricked by a malicious memo into approving an unintended swap. Consider fuzzing the memo parser and verifying that oversized or malformed memos do not crash the device or truncate security-critical labels.
Security signals we found
New UI path triggered by attacker-influenced memo prefix '=:'
Memo content is parsed with strchr on ':' and rendered as destination asset/address, creating a UI spoofing surface
No visible length/charset validation on memo before display
Signing flow unchanged; no cryptographic bypass introduced
Adds a 'Check the Vault Address' QR link to tronscan.org for swap destination addresses
Evidence from the diff
The patch introduces a dedicated ViewType::TronSwapTx / REMAPVIEW_TRX_SWAP path for Tron transactions whose memo begins with ‘=:’ (detected in rust/rust_c/src/common/ur_ext.rs). It extends the Rust parser to expose raw_value, memo, and expiration fields, wires them through FFI structs, and adds C UI callbacks (GetTrxSwapDstAsset, GetTrxSwapDstAddress, GetTrxMemo, etc.) plus a JSON page layout for the hardware wallet screen. The memo is split on ‘:’ characters to derive destination asset/address for display. The signing logic itself is unchanged; the same QR/UR signing helpers are reused. No input-length sanitization is visible in the new UI getters beyond the existing safe string copy helpers.
Changed components
rust/apps/tron/src/transaction/parser.rsrust/apps/tron/src/transaction/wrapped_tron.rsrust/rust_c/src/common/ur.rsrust/rust_c/src/common/ur_ext.rsrust/rust_c/src/tron/structs.rssrc/ui/gui_chain/multi/web3/gui_trx.csrc/ui/gui_chain/multi/web3/gui_trx.hsrc/ui/gui_analyze/multi/web3/gui_general_analyze.csrc/ui/gui_analyze/multi/web3/gui_general_analyze.hInspect captured patch +178 / −8
diff --git a/rust/apps/tron/src/transaction/parser.rs b/rust/apps/tron/src/transaction/parser.rs
index 49c3419..b2e25fc 100644
--- a/rust/apps/tron/src/transaction/parser.rs
+++ b/rust/apps/tron/src/transaction/parser.rs
@@ -20,12 +20,15 @@ pub struct OverviewTx {
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct DetailTx {
pub value: String,
+ pub raw_value: String,
pub method: String,
pub from: String,
pub to: String,
pub network: String,
pub token: String,
pub contract_address: String,
+ pub memo: String,
+ pub expiration: String,
}
pub trait TxParser {
@@ -49,12 +52,15 @@ impl TxParser for WrappedTron {
};
let detail = DetailTx {
value,
+ raw_value: self.value.clone(),
method,
from,
to,
network,
contract_address: self.contract_address.to_string(),
token: self.token.to_string(),
+ memo: self.memo.clone(),
+ expiration: self.expiration.clone(),
};
Ok(ParsedTx { overview, detail })
}
@@ -91,8 +97,8 @@ mod tests {
"TS5zPoC4XEBmHvDNAnnW2gH3MQhcRN6iRm".to_string(),
parsed_tx.detail.to
);
- assert_eq!("TRON".to_string(), parsed_tx.overview.network);
- assert_eq!("TRON".to_string(), parsed_tx.detail.network);
+ assert_eq!("Tron Mainnet".to_string(), parsed_tx.overview.network);
+ assert_eq!("Tron Mainnet".to_string(), parsed_tx.detail.network);
assert_eq!("0.000001 TRX".to_string(), parsed_tx.overview.value);
assert_eq!("0.000001 TRX".to_string(), parsed_tx.detail.value);
assert_eq!("TRX Transfer".to_string(), parsed_tx.detail.method);
@@ -125,8 +131,8 @@ mod tests {
"TS5zPoC4XEBmHvDNAnnW2gH3MQhcRN6iRm".to_string(),
parsed_tx.detail.to
);
- assert_eq!("TRON".to_string(), parsed_tx.overview.network);
- assert_eq!("TRON".to_string(), parsed_tx.detail.network);
+ assert_eq!("Tron Mainnet".to_string(), parsed_tx.overview.network);
+ assert_eq!("Tron Mainnet".to_string(), parsed_tx.detail.network);
assert_eq!("0.001 BTT".to_string(), parsed_tx.overview.value);
assert_eq!("0.001 BTT".to_string(), parsed_tx.detail.value);
assert_eq!("TRC-10 Transfer".to_string(), parsed_tx.detail.method);
@@ -160,8 +166,8 @@ mod tests {
"TS5zPoC4XEBmHvDNAnnW2gH3MQhcRN6iRm".to_string(),
parsed_tx.detail.to
);
- assert_eq!("TRON".to_string(), parsed_tx.overview.network);
- assert_eq!("TRON".to_string(), parsed_tx.detail.network);
+ assert_eq!("Tron Mainnet".to_string(), parsed_tx.overview.network);
+ assert_eq!("Tron Mainnet".to_string(), parsed_tx.detail.network);
assert_eq!("0.001987 USDT".to_string(), parsed_tx.overview.value);
assert_eq!("0.001987 USDT".to_string(), parsed_tx.detail.value);
assert_eq!("TRC-20 Transfer".to_string(), parsed_tx.detail.method);
diff --git a/rust/apps/tron/src/transaction/wrapped_tron.rs b/rust/apps/tron/src/transaction/wrapped_tron.rs
index 56b239b..ac6439c 100644
--- a/rust/apps/tron/src/transaction/wrapped_tron.rs
+++ b/rust/apps/tron/src/transaction/wrapped_tron.rs
@@ -38,6 +38,7 @@ pub struct WrappedTron {
pub(crate) divider: f64,
pub(crate) fee_limit: u64,
pub(crate) memo: String,
+ pub(crate) expiration: String,
}
#[macro_export]
@@ -431,10 +432,12 @@ impl WrappedTron {
} else {
0
};
+ let mut expiration = "".to_string();
if !tx.memo.is_empty() {
if let Some(ref mut raw) = tron_tx.raw_data {
raw.data = tx.memo.as_bytes().to_vec();
+ expiration = (raw.expiration).to_string();
}
}
@@ -452,6 +455,7 @@ impl WrappedTron {
token_short_name,
fee_limit,
memo: tx.memo.clone(),
+ expiration: expiration.clone(),
})
}
_ => Err(TronError::InvalidRawTxCryptoBytes(
@@ -520,7 +524,7 @@ impl WrappedTron {
}
pub const DIVIDER: f64 = 1000000_f64;
-pub const NETWORK: &str = "TRON";
+pub const NETWORK: &str = "Tron Mainnet";
#[cfg(test)]
mod tests {
diff --git a/rust/rust_c/src/common/ur.rs b/rust/rust_c/src/common/ur.rs
index 4b23ef5..7fcc212 100644
--- a/rust/rust_c/src/common/ur.rs
+++ b/rust/rust_c/src/common/ur.rs
@@ -228,6 +228,8 @@ pub enum ViewType {
TronTx,
#[cfg(feature = "tron")]
TronPersonalMessage,
+ #[cfg(feature = "tron")]
+ TronSwapTx,
#[cfg(feature = "solana")]
SolanaTx,
#[cfg(feature = "solana")]
diff --git a/rust/rust_c/src/common/ur_ext.rs b/rust/rust_c/src/common/ur_ext.rs
index 28060ba..2be63e6 100644
--- a/rust/rust_c/src/common/ur_ext.rs
+++ b/rust/rust_c/src/common/ur_ext.rs
@@ -268,7 +268,18 @@ fn get_view_type_from_keystone(bytes: Vec<u8>) -> Result<ViewType, URError> {
#[cfg(feature = "ethereum")]
"ETH" => ViewType::EthTx,
#[cfg(feature = "tron")]
- "TRON" => ViewType::TronTx,
+ "TRON" => {
+ if let Some(protoc::sign_transaction::Transaction::TronTx(tx)) = sign_tx_content.transaction {
+ if tx.memo.starts_with("=:")
+ {
+ ViewType::TronSwapTx
+ } else {
+ ViewType::TronTx
+ }
+ } else {
+ ViewType::TronTx
+ }
+ }
#[cfg(feature = "xrp")]
"XRP" => ViewType::XRPTx,
_ => {
diff --git a/rust/rust_c/src/tron/structs.rs b/rust/rust_c/src/tron/structs.rs
index 9595dac..a40be80 100644
--- a/rust/rust_c/src/tron/structs.rs
+++ b/rust/rust_c/src/tron/structs.rs
@@ -36,6 +36,9 @@ pub struct DisplayTronDetail {
network: PtrString,
token: PtrString,
contract_address: PtrString,
+ pub memo: PtrString,
+ pub expiration: PtrString,
+ pub raw_value: PtrString,
}
impl_c_ptr!(DisplayTronDetail);
@@ -62,6 +65,9 @@ impl From<DetailTx> for DisplayTronDetail {
network: convert_c_char(value.network),
token: convert_c_char(value.token),
contract_address: convert_c_char(value.contract_address),
+ memo: convert_c_char(value.memo),
+ expiration: convert_c_char(value.expiration),
+ raw_value: convert_c_char(value.raw_value),
}
}
}
@@ -93,6 +99,8 @@ impl Free for DisplayTronDetail {
free_str_ptr!(self.network);
free_str_ptr!(self.token);
free_str_ptr!(self.contract_address);
+ free_str_ptr!(self.memo);
+ free_str_ptr!(self.expiration);
}
}
diff --git a/src/ui/gui_analyze/gui_resolve_ur.c b/src/ui/gui_analyze/gui_resolve_ur.c
index 88a0fb5..4c2c4e7 100644
--- a/src/ui/gui_analyze/gui_resolve_ur.c
+++ b/src/ui/gui_analyze/gui_resolve_ur.c
@@ -36,6 +36,7 @@ static SetChainData_t g_chainViewArray[] = {
{REMAPVIEW_ETH_TYPEDDATA, (SetChainDataFunc)GuiSetEthUrData},
{REMAPVIEW_TRX, (SetChainDataFunc)GuiSetTrxUrData},
{REMAPVIEW_TRX_PERSONAL_MESSAGE, (SetChainDataFunc)GuiSetTrxUrData},
+ {REMAPVIEW_TRX_SWAP, (SetChainDataFunc)GuiSetTrxUrData},
{REMAPVIEW_COSMOS, (SetChainDataFunc)GuiSetCosmosUrData},
{REMAPVIEW_SUI, (SetChainDataFunc)GuiSetSuiUrData},
{REMAPVIEW_SUI_SIGN_MESSAGE_HASH, (SetChainDataFunc)GuiSetSuiUrData},
diff --git a/src/ui/gui_analyze/multi/web3/gui_general_analyze.c b/src/ui/gui_analyze/multi/web3/gui_general_analyze.c
index e269262..48bc3b3 100644
--- a/src/ui/gui_analyze/multi/web3/gui_general_analyze.c
+++ b/src/ui/gui_analyze/multi/web3/gui_general_analyze.c
@@ -128,6 +128,8 @@ lv_event_cb_t GuiOtherChainEventCbGet(char *type)
return EthContractLearnMore;
} else if (!strcmp(type, "EthContractCheckRawData")) {
return EthContractCheckRawData;
+ } else if (!strcmp(type, "TrxCheckVault")) {
+ return TrxCheckVault;
}
return NULL;
@@ -239,6 +241,7 @@ GetLabelDataFunc GuiOtherChainTextFuncGet(char *type, GuiRemapViewType remapInde
case REMAPVIEW_ETH_TYPEDDATA:
return GuiEthTypedDataTextFuncGet(type);
case REMAPVIEW_TRX:
+ case REMAPVIEW_TRX_SWAP:
return GuiTrxTextFuncGet(type);
case REMAPVIEW_TRX_PERSONAL_MESSAGE:
return GuiTrxPersonalMessageTextFuncGet(type);
@@ -452,6 +455,18 @@ static GetLabelDataFunc GuiTrxTextFuncGet(char *type)
return GetTrxContract;
} else if (!strcmp(type, "GetTrxToken")) {
return GetTrxToken;
+ } else if (!strcmp(type, "GetTrxSwapDstAsset")) {
+ return GetTrxSwapDstAsset;
+ } else if (!strcmp(type, "GetTrxSwapDstAddress")) {
+ return GetTrxSwapDstAddress;
+ } else if (!strcmp(type, "GetTrxNetwork")) {
+ return GetTrxNetwork;
+ } else if (!strcmp(type, "GetTrxExpiration")) {
+ return GetTrxExpiration;
+ } else if (!strcmp(type, "GetTrxValueRaw")) {
+ return GetTrxValueRaw;
+ } else if (!strcmp(type, "GetTrxMemo")) {
+ return GetTrxMemo;
}
return NULL;
}
diff --git a/src/ui/gui_analyze/multi/web3/gui_general_analyze.h b/src/ui/gui_analyze/multi/web3/gui_general_analyze.h
index 0753301..96b3535 100644
--- a/src/ui/gui_analyze/multi/web3/gui_general_analyze.h
+++ b/src/ui/gui_analyze/multi/web3/gui_general_analyze.h
@@ -37,6 +37,10 @@
"{\"table\":{\"utf8_message\":{\"type\":\"container\",\"pos\":[0,39],\"size\":[408,500],\"align\":2,\"bg_color\":16777215,\"bg_opa\":31,\"radius\":24,\"children\":[{\"type\":\"label\",\"text\":\"From\",\"pos\":[24,16],\"exist_func\":\"GetTrxMessageFromExist\",\"font\":\"openSansEnIllustrate\",\"text_opa\":144},{\"type\":\"label\",\"text_func\":\"GetTrxMessageFrom\",\"pos\":[24,54],\"text_width\":360,\"exist_func\":\"GetTrxMessageFromExist\",\"font\":\"openSansEnIllustrate\"},{\"type\":\"custom_container\",\"bg_color\":0,\"bg_opa\":0,\"exist_func\":\"GetTrxMessageFromNotExist\",\"pos\":[0,0],\"custom_show_func\":\"GuiCustomPathNotice\"},{\"type\":\"label\",\"text\":\"Message\",\"pos_func\":\"GetTrxMessagePos\",\"align_to\":-2,\"align\":13,\"text_color\":16777215,\"font\":\"openSansEnIllustrate\",\"text_opa\":144},{\"type\":\"container\",\"size\":[360,332],\"pos\":[0,11],\"align_to\":-2,\"align\":13,\"aflag\":16,\"bg_opa\":0,\"children\":[{\"type\":\"label\",\"text_func\":\"GetTrxMessageUtf8\",\"pos\":[0,0],\"text_width\":360,\"font\":\"openSansEnIllustrate\",\"text_color\":16777215}]}]},\"raw_message\":{\"type\":\"container\",\"pos\":[0,39],\"size\":[408,500],\"align\":2,\"bg_color\":16777215,\"bg_opa\":31,\"radius\":24,\"children\":[{\"type\":\"label\",\"text\":\"Raw Message\",\"pos\":[24,16],\"font\":\"openSansEnIllustrate\",\"text_opa\":144},{\"type\":\"container\",\"pos\":[24,54],\"size\":[360,450],\"align\":1,\"aflag\":16,\"bg_opa\":0,\"children\":[{\"type\":\"label\",\"text_func\":\"GetTrxMessageRaw\",\"pos\":[0,0],\"text_width\":360,\"font\":\"illustrate\"}]}]}}}", \
GuiGetTrxPersonalMessage,\
GetTrxPersonalMessageType,\
+ REMAPVIEW_TRX_SWAP,\
+ "{\"name\":\"trx_swap_page\",\"type\":\"tabview\",\"pos\":[36,0],\"size\":[408,900],\"bg_color\":0,\"children\":[{\"type\":\"tabview_child\",\"index\":1,\"tab_name\":\"Overview\",\"font\":\"openSansEnIllustrate\",\"children\":[{\"type\":\"container\",\"pos\":[0,12],\"size\":[408,190],\"bg_opa\":31,\"radius\":24,\"children\":[{\"type\":\"label\",\"text\":\"Swap\",\"pos\":[24,16],\"font\":\"openSansEnIllustrate\",\"text_opa\":144},{\"type\":\"label\",\"text_func\":\"GetTrxValue\",\"pos\":[24,50],\"text_color\":16090890,\"font\":\"openSansEnLittleTitle\"},{\"type\":\"label\",\"text\":\"To\",\"pos\":[24,110],\"font\":\"openSansEnIllustrate\",\"text_opa\":144},{\"type\":\"label\",\"text_func\":\"GetTrxSwapDstAsset\",\"pos\":[24,144],\"text_color\":16090890,\"font\":\"openSansEnLittleTitle\"}]},{\"type\":\"container\",\"pos\":[0,16],\"size\":[408,62],\"align_to\":-2,\"align\":13,\"bg_opa\":31,\"radius\":24,\"children\":[{\"type\":\"label\",\"text\":\"Network\",\"pos\":[24,16],\"font\":\"openSansEnIllustrate\",\"text_opa\":144},{\"type\":\"label\",\"text_func\":\"GetTrxNetwork\",\"pos\":[120,16],\"font\":\"openSansEnIllustrate\",\"text_color\":16777215}]},{\"type\":\"container\",\"pos\":[0,16],\"size\":[408,146],\"align_to\":-2,\"align\":13,\"bg_opa\":31,\"radius\":24,\"children\":[{\"type\":\"label\",\"text\":\"From\",\"pos\":[24,16],\"font\":\"openSansEnIllustrate\",\"text_opa\":144},{\"type\":\"label\",\"text_func\":\"GetTrxFromAddress\",\"text_width\":330,\"pos\":[24,54],\"font\":\"openSansEnIllustrate\",\"text_line_space\":8}]},{\"type\":\"container\",\"pos\":[0,16],\"size\":[408,146],\"align_to\":-2,\"align\":13,\"bg_opa\":31,\"radius\":24,\"children\":[{\"type\":\"label\",\"text\":\"Destination\",\"pos\":[24,16],\"font\":\"openSansEnIllustrate\",\"text_opa\":144},{\"type\":\"label\",\"text_func\":\"GetTrxSwapDstAddress\",\"text_width\":330,\"pos\":[24,54],\"font\":\"openSansEnIllustrate\",\"text_line_space\":8}]}]},{\"type\":\"tabview_child\",\"index\":2,\"tab_name\":\"Details\",\"font\":\"openSansEnIllustrate\",\"children\":[{\"type\":\"container\",\"pos\":[0,12],\"size\":[408,62],\"bg_opa\":31,\"radius\":24,\"children\":[{\"type\":\"label\",\"text\":\"Network\",\"pos\":[24,16],\"text_opa\":144},{\"type\":\"label\",\"text_func\":\"GetTrxNetwork\",\"pos\":[114,16],\"text_color\":16777215}]},{\"type\":\"container\",\"pos\":[0,16],\"size\":[408,62],\"align_to\":-2,\"align\":13,\"bg_opa\":31,\"radius\":24,\"children\":[{\"type\":\"label\",\"text\":\"Method\",\"pos\":[24,16],\"text_opa\":144},{\"type\":\"label\",\"text_func\":\"GetTrxMethod\",\"pos\":[114,16],\"text_color\":16777215}]},{\"type\":\"container\",\"pos\":[0,16],\"size\":[408,320],\"align_to\":-2,\"align\":13,\"bg_opa\":31,\"radius\":24,\"children\":[{\"type\":\"label\",\"text\":\"From\",\"pos\":[24,16],\"text_opa\":144},{\"type\":\"label\",\"text_func\":\"GetTrxFromAddress\",\"text_width\":360,\"pos\":[24,54],\"text_line_space\":4},{\"type\":\"label\",\"text\":\"To\",\"pos\":[24,130],\"text_opa\":144},{\"type\":\"label\",\"text_func\":\"GetTrxToAddress\",\"text_width\":360,\"pos\":[24,168],\"text_line_space\":4},{\"type\":\"container\",\"name\":\"v_btn\",\"pos\":[24,230],\"size\":[360,45],\"bg_opa\":0,\"cb\":\"TrxCheckVault\",\"children\":[{\"type\":\"label\",\"text\":\"Check the Vault Address\",\"pos\":[0,0],\"text_color\":1827014,\"text_decor\":1},{\"type\":\"img\",\"img_src\":\"imgQrcodeTurquoise\",\"pos\":[255,2]}]}]},{\"type\":\"container\",\"pos\":[0,16],\"size\":[408,106],\"align_to\":-2,\"align\":13,\"bg_opa\":31,\"radius\":24,\"exist_func\":\"GetTrxContractExist\",\"children\":[{\"type\":\"label\",\"text\":\"Contract Address\",\"pos\":[24,16],\"text_opa\":144},{\"type\":\"label\",\"text_func\":\"GetTrxContract\",\"text_width\":360,\"pos\":[24,54]}]},{\"type\":\"container\",\"pos\":[0,16],\"size\":[408,340],\"align_to\":-2,\"align\":13,\"bg_opa\":31,\"radius\":24,\"children\":[{\"type\":\"label\",\"text\":\"Amount\",\"pos\":[24,16],\"text_opa\":144},{\"type\":\"label\",\"text_func\":\"GetTrxValueRaw\",\"pos\":[24,50]},{\"type\":\"label\",\"text\":\"Memo\",\"pos\":[24,100],\"text_opa\":144},{\"type\":\"label\",\"text_func\":\"GetTrxMemo\",\"text_width\":360,\"pos\":[24,134],\"text_line_space\":4},{\"type\":\"label\",\"text\":\"Expiration\",\"pos\":[24,250],\"text_opa\":144},{\"type\":\"label\",\"text_func\":\"GetTrxExpiration\",\"pos\":[24,284]}]}]}]}",\
+ GuiGetTrxData,\
+ NULL,\
FreeTrxMemory,\
},\
{\
diff --git a/src/ui/gui_chain/gui_chain.c b/src/ui/gui_chain/gui_chain.c
index 8cc3716..7c1a681 100644
--- a/src/ui/gui_chain/gui_chain.c
+++ b/src/ui/gui_chain/gui_chain.c
@@ -67,6 +67,7 @@ static const ViewHandlerEntry g_viewHandlerMap[] = {
{EthBatchTx, GuiGetEthBatchTxSignQrCodeData, NULL, NULL, CHAIN_ETH, REMAPVIEW_ETH_BATCH_TX},
{TronTx, GuiGetTrxSignQrCodeData, GuiGetTrxSignUrDataUnlimited, GuiGetTrxCheckResult, CHAIN_TRX, REMAPVIEW_TRX},
{TronPersonalMessage, GuiGetTrxSignQrCodeData, GuiGetTrxSignUrDataUnlimited, GuiGetTrxCheckResult, CHAIN_TRX, REMAPVIEW_TRX_PERSONAL_MESSAGE},
+ {TronSwapTx, GuiGetTrxSignQrCodeData, GuiGetTrxSignUrDataUnlimited, GuiGetTrxCheckResult, CHAIN_TRX, REMAPVIEW_TRX_SWAP},
// avax
{AvaxTx, GuiGetAvaxSignQrCodeData, GuiGetAvaxSignUrDataUnlimited, GuiGetAvaxCheckResult, CHAIN_AVAX, REMAPVIEW_AVAX},
diff --git a/src/ui/gui_chain/gui_chain.h b/src/ui/gui_chain/gui_chain.h
index 6c1e256..2382891 100644
--- a/src/ui/gui_chain/gui_chain.h
+++ b/src/ui/gui_chain/gui_chain.h
@@ -113,6 +113,7 @@ typedef enum {
REMAPVIEW_ETH_BATCH_TX,
REMAPVIEW_TRX,
REMAPVIEW_TRX_PERSONAL_MESSAGE,
+ REMAPVIEW_TRX_SWAP,
REMAPVIEW_COSMOS,
REMAPVIEW_SUI,
REMAPVIEW_SUI_SIGN_MESSAGE_HASH,
diff --git a/src/ui/gui_chain/multi/web3/gui_trx.c b/src/ui/gui_chain/multi/web3/gui_trx.c
index 1ca0b16..313912c 100644
--- a/src/ui/gui_chain/multi/web3/gui_trx.c
+++ b/src/ui/gui_chain/multi/web3/gui_trx.c
@@ -130,6 +130,108 @@ void GetTrxToken(void *indata, void *param, uint32_t maxLen)
strcpy_s((char *)indata, maxLen, trx->detail->token);
}
+void GetTrxSwapDstAsset(void *indata, void *param, uint32_t maxLen)
+{
+ DisplayTron *trx = (DisplayTron *)param;
+ const char *memo = trx->detail->memo;
+ char *out = (char *)indata;
+
+ if (memo == NULL || strlen(memo) == 0) {
+ strcpy_s(out, maxLen, "Unknown");
+ return;
+ }
+
+ const char *first_colon = strchr(memo, ':');
+ if (!first_colon) {
+ strcpy_s(out, maxLen, "");
+ return;
+ }
+
+ const char *start = first_colon + 1;
+ const char *second_colon = strchr(start, ':');
+
+ if (second_colon) {
+ size_t len = second_colon - start;
+ if (len >= maxLen) len = maxLen - 1;
+ strncpy_s(out, maxLen, start, len);
+ } else {
+ strcpy_s(out, maxLen, start);
+ }
+}
+
+void GetTrxSwapDstAddress(void *indata, void *param, uint32_t maxLen)
+{
+ DisplayTron *trx = (DisplayTron *)param;
+ const char *memo = trx->detail->memo;
+ char *out = (char *)indata;
+
+ const char *first_colon = strchr(memo, ':');
+ if (first_colon) {
+ const char *second_colon = strchr(first_colon + 1, ':');
+ if (second_colon) {
+ const char *start = second_colon + 1;
+ const char *third_colon = strchr(start, ':');
+
+ if (third_colon) {
+ size_t len = third_colon - start;
+ if (len >= maxLen) len = maxLen - 1;
+ strncpy_s(out, maxLen, start, len);
+ return;
+ } else {
+ strcpy_s(out, maxLen, start);
+ return;
+ }
+ }
+ }
+ strcpy_s(out, maxLen, "");
+}
+
+void GetTrxMemo(void *indata, void *param, uint32_t maxLen)
+{
+ DisplayTron *trx = (DisplayTron *)param;
+ strcpy_s((char *)indata, maxLen, trx->detail->memo);
+}
+
+void GetTrxNetwork(void *indata, void *param, uint32_t maxLen)
+{
+ DisplayTron *trx = (DisplayTron *)param;
+ strcpy_s((char *)indata, maxLen, trx->detail->network);
+}
+
+void GetTrxExpiration(void *indata, void *param, uint32_t maxLen)
+{
+ DisplayTron *trx = (DisplayTron *)param;
+ strcpy_s((char *)indata, maxLen, trx->detail->expiration);
+}
+
+void GetTrxValueRaw(void *indata, void *param, uint32_t maxLen)
+{
+ DisplayTron *trx = (DisplayTron *)param;
+ strcpy_s((char *)indata, maxLen, trx->detail->raw_value);
+}
+
+void TrxCheckVault(lv_event_t *e)
+{
+ if (lv_event_get_code(e) == LV_EVENT_CLICKED) {
+ lv_obj_t *v_btn = lv_event_get_current_target(e);
+
+ lv_obj_t *address_card = lv_obj_get_parent(v_btn);
+ if (!address_card) return;
+
+ lv_obj_t *t_val_obj = lv_obj_get_child(address_card, 3);
+
+ if (t_val_obj) {
+ const char *address = lv_label_get_text(t_val_obj);
+ if (address && strlen(address) > 10) {
+ char url[256] = {0};
+ snprintf(url, sizeof(url), "https://tronscan.org/#/address/%s", address);
+ GuiQRCodeHintBoxOpen(url, _("SwapKit Tron Vault"), url);
+ }
+ }
+ }
+}
+
+
static UREncodeResult *GuiGetTrxSignUrDataDynamic(bool unLimit)
{
bool enable = IsPreviousLockScreenEnable();
diff --git a/src/ui/gui_chain/multi/web3/gui_trx.h b/src/ui/gui_chain/multi/web3/gui_trx.h
index 89f80c7..2a2c92b 100644
--- a/src/ui/gui_chain/multi/web3/gui_trx.h
+++ b/src/ui/gui_chain/multi/web3/gui_trx.h
@@ -12,6 +12,14 @@ bool GetTrxContractExist(void *indata, void *param);
void GetTrxContract(void *indata, void *param, uint32_t maxLen);
bool GetTrxTokenExist(void *indata, void *param);
void GetTrxToken(void *indata, void *param, uint32_t maxLen);
+void GetTrxSwapDstAsset(void *indata, void *param, uint32_t maxLen);
+void GetTrxSwapDstAddress(void *indata, void *param, uint32_t maxLen);
+void GetTrxNetwork(void *indata, void *param, uint32_t maxLen);
+void TrxCheckVault(lv_event_t *e);
+void GetTrxExpiration(void *indata, void *param, uint32_t maxLen);
+void GetTrxValueRaw(void *indata, void *param, uint32_t maxLen);
+void GetTrxMemo(void *indata, void *param, uint32_t maxLen);
+
UREncodeResult *GuiGetTrxSignQrCodeData(void);
UREncodeResult *GuiGetTrxSignUrDataUnlimited(void);
diff --git a/ui_simulator/simulator_model.h b/ui_simulator/simulator_model.h
index 1d6bb21..bb76bdb 100644
--- a/ui_simulator/simulator_model.h
+++ b/ui_simulator/simulator_model.h
@@ -111,6 +111,13 @@ extern bool g_reboot;
GetTrxPersonalMessageType, \
FreeTrxMemory, \
}, \
+ { \
+ REMAPVIEW_TRX_SWAP, \
+ PC_SIMULATOR_PATH "/page_trx_swap.json", \
+ GuiGetTrxData, \
+ NULL, \
+ FreeTrxMemory, \
+ }, \
{ \
REMAPVIEW_COSMOS, \
PC_SIMULATOR_PATH "/page_cosmos.json", \
Why this scored 27/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.