diff --git a/cashtab/package-lock.json b/cashtab/package-lock.json --- a/cashtab/package-lock.json +++ b/cashtab/package-lock.json @@ -1,12 +1,12 @@ { "name": "cashtab", - "version": "2.36.2", + "version": "2.36.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "cashtab", - "version": "2.36.2", + "version": "2.36.3", "dependencies": { "@bitgo/utxo-lib": "^9.33.0", "@zxing/browser": "^0.1.4", diff --git a/cashtab/package.json b/cashtab/package.json --- a/cashtab/package.json +++ b/cashtab/package.json @@ -1,6 +1,6 @@ { "name": "cashtab", - "version": "2.36.2", + "version": "2.36.3", "private": true, "scripts": { "start": "node scripts/start.js", diff --git a/cashtab/src/chronik/fixtures/mocks.js b/cashtab/src/chronik/fixtures/mocks.js --- a/cashtab/src/chronik/fixtures/mocks.js +++ b/cashtab/src/chronik/fixtures/mocks.js @@ -10903,6 +10903,68 @@ ], }; +export const oneOutputReceivedTx = { + tx: { + txid: '0edd96775cc1dbc4c36dbf5f1773f937de3bdadd572265ad78bae931fec3f431', + version: 2, + inputs: [ + { + prevOut: { + txid: 'cd5731b4f5ec4ff2e12fe3187e37ce3dc544f5419df8f6c36f649e1236d7dcee', + outIdx: 0, + }, + inputScript: + '41246058dcfab4114536db638d064612e12e0cfff613b568535c278e544ec68ec3e02ffc94d09a0ffe0f4e6fd9ff9608b01aad46cad3765059c3fe45ea09898abe4121029bd5d9d9565b734188493dfd3b0fe985ccd55bb6bc1544cf6ed25a46076f045f', + value: 45553900000, + sequenceNo: 4294967294, + outputScript: + '76a914bb3f3669824acaf67902cbc8477f75ae5b139a0f88ac', + }, + { + prevOut: { + txid: '3719ef3aa2739da328a1a2916a422931fb7b0fa897183f3fd8f3c26864285e34', + outIdx: 0, + }, + inputScript: + '415d1ee0074f11a0adf5c35039167a731d008656eb0a33b5eec9144dd8614419e88866779cce3da0de8c9f839ddbb8d8ee8d24c82526a8900730ea8af8ef102c6d4121020b5c467c0276678df5f50cc932e81abf259f40477f815ed11f4d0fecab39f2d6', + value: 100000000, + sequenceNo: 4294967294, + outputScript: + '76a91409c388abff6922c7e97ef8ea58e9697b6637910c88ac', + }, + ], + outputs: [ + { + value: 45653899320, + outputScript: + '76a914601efc2aa406fe9eaedd41d2b5d95d1f4db9041d88ac', + spentBy: { + txid: 'b9aab1e26381457b390ad689c7577962cef1ec48de3a83d87db68968afb7e4cf', + outIdx: 54, + }, + }, + ], + lockTime: 0, + timeFirstSeen: 1714138690, + size: 326, + isCoinbase: false, + tokenEntries: [], + tokenFailedParsings: [], + tokenStatus: 'TOKEN_STATUS_NON_TOKEN', + block: { + height: 842022, + hash: '00000000000000000c331ba563d903d20ff670b18afd0d6cd4aadca854d294a6', + timestamp: 1714139968, + }, + }, + parsed: { + recipients: [], + satoshisSent: 45653899320, + stackArray: [], + xecTxType: 'Received', + }, +}; + /** * Mock chronik.token(tokenId) and chronik.tx(tokenId) for * several slpv1 tokens diff --git a/cashtab/src/chronik/fixtures/vectors.js b/cashtab/src/chronik/fixtures/vectors.js --- a/cashtab/src/chronik/fixtures/vectors.js +++ b/cashtab/src/chronik/fixtures/vectors.js @@ -42,6 +42,7 @@ SlpNftParentFanTx, SlpNftMint, SlpParentGenesisTxMock, + oneOutputReceivedTx, } from './mocks'; import { mockChronikUtxos, mockOrganizedUtxosByType } from './chronikUtxos'; import { getHashes } from 'wallet'; @@ -221,6 +222,12 @@ hashes: ['95e79f51d4260bc0dc3ba7fb77c7be92d0fbdd1d'], parsed: SlpV1Mint.parsed, }, + { + description: 'received xec tx with no change', + tx: oneOutputReceivedTx.tx, + hashes: ['601efc2aa406fe9eaedd41d2b5d95d1f4db9041d'], + parsed: oneOutputReceivedTx.parsed, + }, ], }, sortAndTrimChronikTxHistory: { diff --git a/cashtab/src/components/Home/Tx/__tests__/index.test.js b/cashtab/src/components/Home/Tx/__tests__/index.test.js --- a/cashtab/src/components/Home/Tx/__tests__/index.test.js +++ b/cashtab/src/components/Home/Tx/__tests__/index.test.js @@ -46,6 +46,7 @@ SlpNftParentFanTx, SlpNftMint, SlpParentGenesisTxMock, + oneOutputReceivedTx, } from 'chronik/fixtures/mocks'; import CashtabState from 'config/CashtabState'; import { MemoryRouter } from 'react-router-dom'; @@ -163,6 +164,49 @@ // We see the 'Confirming' text expect(screen.getByText('Confirming')).toBeInTheDocument(); }); + it('Incoming XEC no change', async () => { + render( + + + + , + + , + ); + + // We see the tx received icon + expect(screen.getByTitle('tx-received')).toBeInTheDocument(); + + // We see the tx received label + expect(screen.getByText(/Received from/)).toBeInTheDocument(); + + // For a tx with timeFirstSeen of 0, we render the block timestamp + expect(screen.getByText('Apr 26, 2024, 13:38:10')).toBeInTheDocument(); + + // We see the formatted XEC amount + expect(screen.getByText('456.54M XEC')).toBeInTheDocument(); + + // We see the formatted fiat amount + expect(screen.getByText('$13,696.17')).toBeInTheDocument(); + + // We do not see the avalanche finalized check + expect( + screen.queryByTitle('Finalized by Avalanche'), + ).not.toBeInTheDocument(); + + // We see two inline-loader elements + expect(screen.getAllByTitle('Loading')[1]).toBeInTheDocument(); + + // We see the 'Confirming' text + expect(screen.getByText('Confirming')).toBeInTheDocument(); + }); it('Outgoing XEC-only', async () => { render( diff --git a/cashtab/src/components/Home/Tx/index.js b/cashtab/src/components/Home/Tx/index.js --- a/cashtab/src/components/Home/Tx/index.js +++ b/cashtab/src/components/Home/Tx/index.js @@ -783,7 +783,8 @@ typeof knownRecipient === 'undefined' && typeof recipients[0] !== 'undefined'); - const isSelfSendTx = typeof recipients[0] === 'undefined'; + const isSelfSendTx = + typeof recipients[0] === 'undefined' && xecTxType !== 'Received'; return ( <>