diff --git a/packages/blockchain-link-utils/src/ripple.ts b/packages/blockchain-link-utils/src/ripple.ts index 2129f3cbb08..643347ee60f 100644 --- a/packages/blockchain-link-utils/src/ripple.ts +++ b/packages/blockchain-link-utils/src/ripple.ts @@ -1,5 +1,13 @@ import type { Transaction } from '@trezor/blockchain-link-types'; +type RippleTransactionMetadata = { + AffectedNodes: any[]; + DeliveredAmount?: any[]; + TransactionIndex: number; + TransactionResult: string; + delivered_amount?: string; +}; + // export const transformServerInfo = (payload: GetServerInfoResponse) => { export const transformServerInfo = (payload: any) => ({ name: 'Ripple', @@ -15,20 +23,32 @@ export const transformServerInfo = (payload: any) => ({ // https://bitcoin.stackexchange.com/questions/23061/ripple-ledger-time-format/23065#23065 const BLOCKTIME_OFFSET = 946684800; -export const transformTransaction = (tx: any, descriptor?: string): Transaction => { +export const transformTransaction = ( + tx: any, + meta: RippleTransactionMetadata | null, + descriptor?: string, +): Transaction => { const blockTime = typeof tx.date === 'number' && tx.date > 0 ? tx.date + BLOCKTIME_OFFSET : tx.date; - const type = - tx.TransactionType !== 'Payment' || !descriptor - ? 'unknown' - : (tx.Account === descriptor && 'sent') || 'recv'; + + let txType: Transaction['type']; + + // https://xrpl.org/docs/references/protocol/transactions/transaction-results + if (meta != null && !meta.TransactionResult?.startsWith('tes')) { + txType = 'failed'; + } else if (tx.TransactionType !== 'Payment' || !descriptor) { + txType = 'unknown'; + } else { + txType = tx.Account === descriptor ? 'sent' : 'recv'; + } + const addresses = [tx.Destination]; const amount = tx.Amount; const fee = tx.Fee; // TODO: https://github.com/ripple/ripple-lib/blob/develop/docs/index.md#transaction-types return { - type, + type: txType, txid: tx.hash, amount, fee, @@ -36,7 +56,7 @@ export const transformTransaction = (tx: any, descriptor?: string): Transaction blockHeight: tx.ledger_index, blockHash: tx.hash, targets: - type === 'unknown' + txType === 'unknown' ? [] : [ { diff --git a/packages/blockchain-link/src/workers/ripple/index.ts b/packages/blockchain-link/src/workers/ripple/index.ts index f6d34d69435..357f8afe69b 100644 --- a/packages/blockchain-link/src/workers/ripple/index.ts +++ b/packages/blockchain-link/src/workers/ripple/index.ts @@ -166,7 +166,7 @@ const getAccountInfo = async (request: Request) => const api = await request.connect(); const transactionsData: RawTxData = await api.request('account_tx', requestOptions); account.history.transactions = transactionsData.transactions.map(raw => - utils.transformTransaction(raw.tx, payload.descriptor), + utils.transformTransaction(raw.tx, raw.meta, payload.descriptor), ); return { @@ -180,8 +180,8 @@ const getAccountInfo = async (request: Request) => const getTransaction = async ({ connect, payload }: Request) => { const api = await connect(); - const rawtx = await api.request('tx', { transaction: payload, binary: false }); - const tx = utils.transformTransaction(rawtx); + const rawTx = await api.request('tx', { transaction: payload, binary: false }); + const tx = utils.transformTransaction(rawTx, null); return { type: RESPONSES.GET_TRANSACTION, @@ -253,7 +253,7 @@ const onTransaction = ({ state, post }: Context, event: any) => { type: 'notification', payload: { descriptor, - tx: utils.transformTransaction({ ...event, ...tx }, descriptor), + tx: utils.transformTransaction({ ...event, ...tx }, null, descriptor), }, }, }); diff --git a/packages/blockchain-link/tests/unit/fixtures/getAccountInfo-ripple.ts b/packages/blockchain-link/tests/unit/fixtures/getAccountInfo-ripple.ts index 0b0c5283d22..1cd8cb96515 100644 --- a/packages/blockchain-link/tests/unit/fixtures/getAccountInfo-ripple.ts +++ b/packages/blockchain-link/tests/unit/fixtures/getAccountInfo-ripple.ts @@ -236,4 +236,98 @@ export default [ }, }, }, + { + description: 'With missing destination', + params: { + descriptor: 'rfkV3EoXimH6JrG1QAyofgbVhnyZZDjWSj', + details: 'txs', + }, + serverFixtures: [ + { + method: 'account_info', + response: xrpAccount.account_info.validated, + }, + { + method: 'account_info', + response: xrpAccount.account_info.current, + }, + { + method: 'account_tx', + response: { + status: 'success', + type: 'response', + result: { + account: 'rfkV3EoXimH6JrG1QAyofgbVhnyZZDjWSj', + transactions: [ + { + meta: { + TransactionResult: 'tecDST_TAG_NEEDED', + }, + tx: { + Account: 'r4eEbLKZGbVSBHnSUBZW8i5XaMjGLdqT4a', + Amount: '25718124', + Destination: 'rfkV3EoXimH6JrG1QAyofgbVhnyZZDjWSj', + Fee: '6000', + Flags: 2147483648, + LastLedgerSequence: 47457602, + Sequence: 157331, + SigningPubKey: + '038CF47114672A12B269AEE015BF7A8438609B994B0640E4B28B2F56E93D948B15', + TransactionType: 'Payment', + TxnSignature: + '30440220665BEB140619A36C737929487519B862D1592225568CBEBC248972AD8453D8EE0220020852427CE83EC4BD8A5BFB48B7DA573FFC042A1E3BE9A513FC04F3C3D45B12', + date: 611932692, + hash: '533A8A2EDBCE914159C5491429763FD39A1F0F19E0F82800C3B7909B67B166A7', + inLedger: 47455208, + ledger_index: 47455208, + }, + }, + ], + }, + }, + }, + ], + response: { + descriptor: 'rfkV3EoXimH6JrG1QAyofgbVhnyZZDjWSj', + balance: '20000000', + availableBalance: '10000000', + empty: false, + history: { + total: -1, + unconfirmed: 0, + transactions: [ + { + type: 'failed', + txid: '533A8A2EDBCE914159C5491429763FD39A1F0F19E0F82800C3B7909B67B166A7', + amount: '25718124', + fee: '6000', + blockTime: 1558617492, + blockHeight: 47455208, + blockHash: + '533A8A2EDBCE914159C5491429763FD39A1F0F19E0F82800C3B7909B67B166A7', + targets: [ + { + addresses: ['rfkV3EoXimH6JrG1QAyofgbVhnyZZDjWSj'], + isAddress: true, + amount: '25718124', + n: 0, + }, + ], + tokens: [], + internalTransfers: [], + feeRate: undefined, + details: { + vin: [], + vout: [], + size: 0, + totalInput: '0', + totalOutput: '0', + }, + }, + ], + }, + misc: { sequence: 2, reserve: '10000000' }, + marker: undefined, + }, + }, ];