@@ -13,7 +13,7 @@ use soroban_rs::xdr::{
1313 AccountId , AlphaNum12 , AlphaNum4 , Asset , ChangeTrustAsset , ContractDataEntry , ContractId , Hash ,
1414 LedgerEntryData , LedgerKey , LedgerKeyContractData , Limits , Operation , Preconditions ,
1515 PublicKey as XdrPublicKey , ReadXdr , ScAddress , ScSymbol , ScVal , TimeBounds , TimePoint ,
16- TransactionEnvelope , TransactionMeta , Uint256 , VecM ,
16+ TransactionEnvelope , TransactionMeta , TransactionResult , Uint256 , VecM ,
1717} ;
1818use std:: str:: FromStr ;
1919use stellar_strkey:: ed25519:: PublicKey ;
@@ -266,8 +266,18 @@ pub fn i64_from_u64(value: u64) -> Result<i64, RelayerError> {
266266 i64:: try_from ( value) . map_err ( |_| RelayerError :: ProviderError ( "u64→i64 overflow" . into ( ) ) )
267267}
268268
269+ /// Decodes a base64-encoded `TransactionResult` XDR into a human-readable result code name.
270+ ///
271+ /// Returns the variant name of the `TransactionResultResult` (e.g., `"TxBadSeq"`,
272+ /// `"TxInsufficientBalance"`, `"TxFailed"`). Returns `None` if the XDR cannot be decoded.
273+ pub fn decode_tx_result_code ( error_result_xdr : & str ) -> Option < String > {
274+ TransactionResult :: from_xdr_base64 ( error_result_xdr, Limits :: none ( ) )
275+ . ok ( )
276+ . map ( |r| r. result . name ( ) . to_string ( ) )
277+ }
278+
269279/// Detects if an error is due to a bad sequence number.
270- /// Returns true if the error message contains indicators of sequence number mismatch .
280+ /// Checks both string matching on the error message and XDR decoding when available .
271281pub fn is_bad_sequence_error ( error_msg : & str ) -> bool {
272282 let error_lower = error_msg. to_lowercase ( ) ;
273283 error_lower. contains ( "txbadseq" )
@@ -1475,6 +1485,46 @@ mod tests {
14751485 }
14761486 }
14771487
1488+ mod decode_tx_result_code_tests {
1489+ use super :: * ;
1490+ use soroban_rs:: xdr:: { TransactionResult , TransactionResultResult , WriteXdr } ;
1491+
1492+ #[ test]
1493+ fn test_decodes_tx_bad_seq ( ) {
1494+ let result = TransactionResult {
1495+ fee_charged : 100 ,
1496+ result : TransactionResultResult :: TxBadSeq ,
1497+ ext : soroban_rs:: xdr:: TransactionResultExt :: V0 ,
1498+ } ;
1499+ let xdr = result. to_xdr_base64 ( Limits :: none ( ) ) . unwrap ( ) ;
1500+ assert_eq ! ( decode_tx_result_code( & xdr) , Some ( "TxBadSeq" . to_string( ) ) ) ;
1501+ }
1502+
1503+ #[ test]
1504+ fn test_decodes_tx_insufficient_balance ( ) {
1505+ let result = TransactionResult {
1506+ fee_charged : 100 ,
1507+ result : TransactionResultResult :: TxInsufficientBalance ,
1508+ ext : soroban_rs:: xdr:: TransactionResultExt :: V0 ,
1509+ } ;
1510+ let xdr = result. to_xdr_base64 ( Limits :: none ( ) ) . unwrap ( ) ;
1511+ assert_eq ! (
1512+ decode_tx_result_code( & xdr) ,
1513+ Some ( "TxInsufficientBalance" . to_string( ) )
1514+ ) ;
1515+ }
1516+
1517+ #[ test]
1518+ fn test_returns_none_for_invalid_xdr ( ) {
1519+ assert_eq ! ( decode_tx_result_code( "not-valid-xdr" ) , None ) ;
1520+ }
1521+
1522+ #[ test]
1523+ fn test_returns_none_for_empty_string ( ) {
1524+ assert_eq ! ( decode_tx_result_code( "" ) , None ) ;
1525+ }
1526+ }
1527+
14781528 mod is_insufficient_fee_error_tests {
14791529 use super :: * ;
14801530
0 commit comments