From 8930ff759436b4c2001bb1dfc644b3e95f5227ae Mon Sep 17 00:00:00 2001 From: SergeyG-Solicy Date: Mon, 24 Nov 2025 11:18:41 +0400 Subject: [PATCH 1/4] XRP send functionality implementation --- .../multichain/routines/executors/pay.ts | 51 ++++++++++++++----- 1 file changed, 39 insertions(+), 12 deletions(-) diff --git a/src/features/multichain/routines/executors/pay.ts b/src/features/multichain/routines/executors/pay.ts index 3ee2616f4..130db1f16 100644 --- a/src/features/multichain/routines/executors/pay.ts +++ b/src/features/multichain/routines/executors/pay.ts @@ -222,22 +222,49 @@ async function handleXRPLPay( console.log("[XMScript Parser] Ripple Pay: connected to the XRP network") try { - console.log("[XMScript Parser]: debugging operation") - console.log(operation.task) - console.log(JSON.stringify(operation.task)) - const result = await xrplInstance.sendTransaction( - operation.task.signedPayloads[0], - ) - console.log("[XMScript Parser] Ripple Pay: result: ") - console.log(result) + const signedTx = operation.task.signedPayloads[0] - return result + // Submit transaction and wait for validation + const res = await xrplInstance.provider.submitAndWait(signedTx.tx_blob) + + const txResult = res.result.meta?.TransactionResult || res.result.engine_result + const txHash = res.result.hash + + // Handle successful transactions + if (txResult === 'tesSUCCESS') { + return { + result: "success", + hash: txHash, + } + } + + // Handle already submitted or queued transactions + if (txResult === 'temREDUNDANT' || txResult === 'terQUEUED') { + return { + result: "success", + hash: signedTx.hash || txHash, + } + } + + // Handle applied transactions (tec codes indicate transaction was applied but claimed a fee) + if (txResult?.startsWith('tec')) { + return { + result: "success", + hash: txHash, + } + } + + // Transaction failed + return { + result: "error", + error: `${txResult}: ${res.result.engine_result_message || 'Unknown error'}`, + hash: txHash, + } } catch (error) { - console.log("[XMScript Parser] Ripple Pay: error: ") - console.log(error) + console.log("[XMScript Parser] Ripple Pay: error:", error) return { result: "error", - error: error, + error: error.toString(), } } } From 4bb41a83aa74c758bd96991ebb6175ad74c343be Mon Sep 17 00:00:00 2001 From: SergeyG-Solicy Date: Mon, 24 Nov 2025 12:57:40 +0400 Subject: [PATCH 2/4] Improved error handling --- .../multichain/routines/executors/pay.ts | 50 +++++++++++++++---- 1 file changed, 40 insertions(+), 10 deletions(-) diff --git a/src/features/multichain/routines/executors/pay.ts b/src/features/multichain/routines/executors/pay.ts index 130db1f16..02204ae38 100644 --- a/src/features/multichain/routines/executors/pay.ts +++ b/src/features/multichain/routines/executors/pay.ts @@ -229,8 +229,9 @@ async function handleXRPLPay( const txResult = res.result.meta?.TransactionResult || res.result.engine_result const txHash = res.result.hash + const resultMessage = res.result.engine_result_message || '' - // Handle successful transactions + // Only tesSUCCESS indicates actual success if (txResult === 'tesSUCCESS') { return { result: "success", @@ -238,27 +239,56 @@ async function handleXRPLPay( } } - // Handle already submitted or queued transactions - if (txResult === 'temREDUNDANT' || txResult === 'terQUEUED') { + // tec* codes: Transaction failed but fee was charged + // The transaction was applied to ledger but did not achieve its intended purpose + // Example: tecUNFUNDED_PAYMENT, tecINSUF_FEE, tecPATH_DRY + if (txResult?.startsWith('tec')) { return { - result: "success", - hash: signedTx.hash || txHash, + result: "error", + error: `Transaction failed (fee charged): ${txResult} - ${resultMessage}`, + hash: txHash, + extra: { code: txResult, validated: res.result.validated } } } - // Handle applied transactions (tec codes indicate transaction was applied but claimed a fee) - if (txResult?.startsWith('tec')) { + // tem* codes: Malformed transaction (not applied to ledger) + // Example: temREDUNDANT (sending to self), temBAD_FEE, temINVALID + if (txResult?.startsWith('tem')) { return { - result: "success", + result: "error", + error: `Malformed transaction: ${txResult} - ${resultMessage}`, + hash: txHash, + extra: { code: txResult, validated: res.result.validated } + } + } + + // ter* codes: Provisional/retryable result (not final) + // Example: terQUEUED (transaction queued for future ledger) + if (txResult?.startsWith('ter')) { + return { + result: "error", + error: `Transaction provisional/queued: ${txResult} - ${resultMessage}`, + hash: txHash, + extra: { code: txResult, validated: res.result.validated } + } + } + + // tef* codes: Local failure (not applied to ledger) + // Example: tefPAST_SEQ, tefMAX_LEDGER, tefFAILURE + if (txResult?.startsWith('tef')) { + return { + result: "error", + error: `Transaction rejected: ${txResult} - ${resultMessage}`, hash: txHash, + extra: { code: txResult, validated: res.result.validated } } } - // Transaction failed return { result: "error", - error: `${txResult}: ${res.result.engine_result_message || 'Unknown error'}`, + error: `Unknown transaction result: ${txResult} - ${resultMessage}`, hash: txHash, + extra: { code: txResult, validated: res.result.validated } } } catch (error) { console.log("[XMScript Parser] Ripple Pay: error:", error) From 60eb9e24855b18471933b9d37190c331163630e7 Mon Sep 17 00:00:00 2001 From: SergeyG-Solicy Date: Tue, 16 Dec 2025 12:29:05 +0400 Subject: [PATCH 3/4] Fixed qodo comments --- .../multichain/routines/executors/pay.ts | 51 +++++-------------- 1 file changed, 12 insertions(+), 39 deletions(-) diff --git a/src/features/multichain/routines/executors/pay.ts b/src/features/multichain/routines/executors/pay.ts index 02204ae38..e2aa99f54 100644 --- a/src/features/multichain/routines/executors/pay.ts +++ b/src/features/multichain/routines/executors/pay.ts @@ -239,48 +239,21 @@ async function handleXRPLPay( } } - // tec* codes: Transaction failed but fee was charged - // The transaction was applied to ledger but did not achieve its intended purpose - // Example: tecUNFUNDED_PAYMENT, tecINSUF_FEE, tecPATH_DRY - if (txResult?.startsWith('tec')) { - return { - result: "error", - error: `Transaction failed (fee charged): ${txResult} - ${resultMessage}`, - hash: txHash, - extra: { code: txResult, validated: res.result.validated } - } + // XRPL transaction result code prefixes and their meanings + const xrplErrorMessages: Record = { + tec: "Transaction failed (fee charged)", // tecUNFUNDED_PAYMENT, tecINSUF_FEE, tecPATH_DRY + tem: "Malformed transaction", // temREDUNDANT, temBAD_FEE, temINVALID + ter: "Transaction provisional/queued", // terQUEUED + tef: "Transaction rejected", // tefPAST_SEQ, tefMAX_LEDGER, tefFAILURE } - // tem* codes: Malformed transaction (not applied to ledger) - // Example: temREDUNDANT (sending to self), temBAD_FEE, temINVALID - if (txResult?.startsWith('tem')) { + const errorPrefix = txResult?.substring(0, 3) + if (errorPrefix && xrplErrorMessages[errorPrefix]) { return { result: "error", - error: `Malformed transaction: ${txResult} - ${resultMessage}`, + error: `${xrplErrorMessages[errorPrefix]}: ${txResult} - ${resultMessage}`, hash: txHash, - extra: { code: txResult, validated: res.result.validated } - } - } - - // ter* codes: Provisional/retryable result (not final) - // Example: terQUEUED (transaction queued for future ledger) - if (txResult?.startsWith('ter')) { - return { - result: "error", - error: `Transaction provisional/queued: ${txResult} - ${resultMessage}`, - hash: txHash, - extra: { code: txResult, validated: res.result.validated } - } - } - - // tef* codes: Local failure (not applied to ledger) - // Example: tefPAST_SEQ, tefMAX_LEDGER, tefFAILURE - if (txResult?.startsWith('tef')) { - return { - result: "error", - error: `Transaction rejected: ${txResult} - ${resultMessage}`, - hash: txHash, - extra: { code: txResult, validated: res.result.validated } + extra: { code: txResult, validated: res.result.validated }, } } @@ -288,13 +261,13 @@ async function handleXRPLPay( result: "error", error: `Unknown transaction result: ${txResult} - ${resultMessage}`, hash: txHash, - extra: { code: txResult, validated: res.result.validated } + extra: { code: txResult, validated: res.result.validated }, } } catch (error) { console.log("[XMScript Parser] Ripple Pay: error:", error) return { result: "error", - error: error.toString(), + error: error instanceof Error ? error.message : String(error), } } } From 644d0bd4926dbe7a2d2cc39aed10a4ccc5131b11 Mon Sep 17 00:00:00 2001 From: SergeyG-Solicy Date: Tue, 16 Dec 2025 12:41:25 +0400 Subject: [PATCH 4/4] Fixed qodo comment --- .../multichain/routines/executors/pay.ts | 38 +++++++++++++++++-- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/src/features/multichain/routines/executors/pay.ts b/src/features/multichain/routines/executors/pay.ts index e2aa99f54..e50c376de 100644 --- a/src/features/multichain/routines/executors/pay.ts +++ b/src/features/multichain/routines/executors/pay.ts @@ -222,14 +222,46 @@ async function handleXRPLPay( console.log("[XMScript Parser] Ripple Pay: connected to the XRP network") try { + // Validate signedPayloads exists and has at least one element + if (!operation.task.signedPayloads || operation.task.signedPayloads.length === 0) { + return { + result: "error", + error: `Missing signed payloads for XRPL operation (${operation.chain}.${operation.subchain})`, + } + } + const signedTx = operation.task.signedPayloads[0] + // Extract tx_blob - handle both string and object formats + let txBlob: string + if (typeof signedTx === "string") { + txBlob = signedTx + } else if (signedTx && typeof signedTx === "object" && "tx_blob" in signedTx) { + txBlob = (signedTx as { tx_blob: string }).tx_blob + } else { + return { + result: "error", + error: `Invalid signed payload format for XRPL operation (${operation.chain}.${operation.subchain}). Expected string or object with tx_blob property.`, + } + } + + if (!txBlob || typeof txBlob !== 'string') { + return { + result: "error", + error: `Invalid tx_blob value for XRPL operation (${operation.chain}.${operation.subchain}). Expected non-empty string.`, + } + } + // Submit transaction and wait for validation - const res = await xrplInstance.provider.submitAndWait(signedTx.tx_blob) + const res = await xrplInstance.provider.submitAndWait(txBlob) - const txResult = res.result.meta?.TransactionResult || res.result.engine_result + // Extract transaction result - handle different response formats + const meta = res.result.meta + const txResult = (typeof meta === "object" && meta !== null && "TransactionResult" in meta + ? (meta as { TransactionResult: string }).TransactionResult + : (res.result as any).engine_result) as string | undefined const txHash = res.result.hash - const resultMessage = res.result.engine_result_message || '' + const resultMessage = ((res.result as any).engine_result_message || '') as string // Only tesSUCCESS indicates actual success if (txResult === 'tesSUCCESS') {