Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F13115919
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
27 KB
Subscribers
None
View Options
diff --git a/cashtab/extension/public/manifest.json b/cashtab/extension/public/manifest.json
index 1be7a35f9..a052f6a7f 100644
--- a/cashtab/extension/public/manifest.json
+++ b/cashtab/extension/public/manifest.json
@@ -2,7 +2,7 @@
"manifest_version": 3,
"name": "Cashtab",
"description": "A browser-integrated eCash wallet from Bitcoin ABC",
- "version": "4.14.0",
+ "version": "4.15.0",
"content_scripts": [
{
"matches": ["file://*/*", "http://*/*", "https://*/*"],
diff --git a/cashtab/package-lock.json b/cashtab/package-lock.json
index e0d76ea7e..3fddbb568 100644
--- a/cashtab/package-lock.json
+++ b/cashtab/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "cashtab",
- "version": "3.14.2",
+ "version": "3.15.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "cashtab",
- "version": "3.14.2",
+ "version": "3.15.0",
"dependencies": {
"@bitgo/utxo-lib": "^11.0.0",
"@zxing/browser": "^0.1.4",
diff --git a/cashtab/package.json b/cashtab/package.json
index 843892a96..31e778da6 100644
--- a/cashtab/package.json
+++ b/cashtab/package.json
@@ -1,6 +1,6 @@
{
"name": "cashtab",
- "version": "3.14.2",
+ "version": "3.15.0",
"private": true,
"scripts": {
"start": "node scripts/start.js",
diff --git a/cashtab/src/assets/firma-icon.png b/cashtab/src/assets/firma-icon.png
new file mode 100644
index 000000000..bf0bbe43b
Binary files /dev/null and b/cashtab/src/assets/firma-icon.png differ
diff --git a/cashtab/src/chronik/fixtures/mocks.js b/cashtab/src/chronik/fixtures/mocks.js
index e72d3311d..b2f1400c8 100644
--- a/cashtab/src/chronik/fixtures/mocks.js
+++ b/cashtab/src/chronik/fixtures/mocks.js
@@ -23331,3 +23331,413 @@ export const invalidXecxTx = {
xecTxType: 'Received',
},
};
+
+export const firmaYieldTx = {
+ tx: {
+ txid: '3c56595af9eb142e18390ae07ccd6f6174e9b15e835208990da3a0ab2c66bed5',
+ version: 2,
+ inputs: [
+ {
+ prevOut: {
+ txid: 'd199723b2ea022ea299d8785fcdedc4b8ee475e10a7f3402f3fad30ef380d5e2',
+ outIdx: 9,
+ },
+ inputScript:
+ '4125417d7c6b7ccc81eff94159e99cb533734433f38c3ee3b9a63e8cfbded5bd8114aad3331ada877d8aeea243f685485cc67690d49237075c55e1fc9082b034f1412103154e2dd365efda4d37f633a857eda739455e076de7c09ec59bc4f929f63b6d49',
+ sats: 546n,
+ sequenceNo: 4294967295,
+ token: {
+ tokenId:
+ '0387947fd575db4fb19a3e322f635dec37fd192b5941625b66bc4b2c3008cbf0',
+ tokenType: {
+ protocol: 'ALP',
+ type: 'ALP_TOKEN_TYPE_STANDARD',
+ number: 0,
+ },
+ atoms: 14n,
+ isMintBaton: false,
+ entryIdx: 0,
+ },
+ outputScript:
+ '76a91438d2e1501a485814e2849552093bb0588ed9acbb88ac',
+ },
+ {
+ prevOut: {
+ txid: 'b465eb1a20783a88554dcc95534c3fc2e5922cd7a8f1a83e6e442860b8764f0e',
+ outIdx: 1,
+ },
+ inputScript:
+ '41bc863737ec0613f49d39b3370a9c5974faa1eac5fa69a3b1a8d777bb4fcc7f2d138603ce959e3adfe504f0ce7231bf6ffb904e8d7cd28e04c4f69ebc9cfc77fa412103154e2dd365efda4d37f633a857eda739455e076de7c09ec59bc4f929f63b6d49',
+ sats: 546n,
+ sequenceNo: 4294967295,
+ token: {
+ tokenId:
+ '0387947fd575db4fb19a3e322f635dec37fd192b5941625b66bc4b2c3008cbf0',
+ tokenType: {
+ protocol: 'ALP',
+ type: 'ALP_TOKEN_TYPE_STANDARD',
+ number: 0,
+ },
+ atoms: 200487n,
+ isMintBaton: false,
+ entryIdx: 0,
+ },
+ outputScript:
+ '76a91438d2e1501a485814e2849552093bb0588ed9acbb88ac',
+ },
+ {
+ prevOut: {
+ txid: 'b465eb1a20783a88554dcc95534c3fc2e5922cd7a8f1a83e6e442860b8764f0e',
+ outIdx: 3,
+ },
+ inputScript:
+ '41aa40b355198a16381cc924539adf2843c57310d126ff82ce7b6829ed51b424a65cede15a08d66cad297e83d5ff1eb1f3d56abde79a16819d118b9953fc87c220412103154e2dd365efda4d37f633a857eda739455e076de7c09ec59bc4f929f63b6d49',
+ sats: 31249702n,
+ sequenceNo: 4294967295,
+ outputScript:
+ '76a91438d2e1501a485814e2849552093bb0588ed9acbb88ac',
+ },
+ ],
+ outputs: [
+ {
+ sats: 0n,
+ outputScript:
+ '6a504c79534c5032000453454e44f0cb08302c4bbc665b6241592b19fd37ec5d632f323e9ab14fdb75d57f9487030d6d0c03000000c30000000000b900000000006900000000005200000000002b00000000001900000000000f00000000000f00000000000d0000000000070000000000070000000000140000000000',
+ },
+ {
+ sats: 546n,
+ outputScript:
+ '76a914cf76d8e334b149cb49ad1f95de339c3e6e9ed54188ac',
+ token: {
+ tokenId:
+ '0387947fd575db4fb19a3e322f635dec37fd192b5941625b66bc4b2c3008cbf0',
+ tokenType: {
+ protocol: 'ALP',
+ type: 'ALP_TOKEN_TYPE_STANDARD',
+ number: 0,
+ },
+ atoms: 199789n,
+ isMintBaton: false,
+ entryIdx: 0,
+ },
+ },
+ {
+ sats: 546n,
+ outputScript:
+ '76a914a5417349420ec53b27522fed1a63b1672c0f28ff88ac',
+ token: {
+ tokenId:
+ '0387947fd575db4fb19a3e322f635dec37fd192b5941625b66bc4b2c3008cbf0',
+ tokenType: {
+ protocol: 'ALP',
+ type: 'ALP_TOKEN_TYPE_STANDARD',
+ number: 0,
+ },
+ atoms: 195n,
+ isMintBaton: false,
+ entryIdx: 0,
+ },
+ },
+ {
+ sats: 546n,
+ outputScript:
+ '76a914ee487276a59ab3ce397ca6894fac6698aba1b69688ac',
+ token: {
+ tokenId:
+ '0387947fd575db4fb19a3e322f635dec37fd192b5941625b66bc4b2c3008cbf0',
+ tokenType: {
+ protocol: 'ALP',
+ type: 'ALP_TOKEN_TYPE_STANDARD',
+ number: 0,
+ },
+ atoms: 185n,
+ isMintBaton: false,
+ entryIdx: 0,
+ },
+ },
+ {
+ sats: 546n,
+ outputScript:
+ '76a91495e79f51d4260bc0dc3ba7fb77c7be92d0fbdd1d88ac',
+ token: {
+ tokenId:
+ '0387947fd575db4fb19a3e322f635dec37fd192b5941625b66bc4b2c3008cbf0',
+ tokenType: {
+ protocol: 'ALP',
+ type: 'ALP_TOKEN_TYPE_STANDARD',
+ number: 0,
+ },
+ atoms: 105n,
+ isMintBaton: false,
+ entryIdx: 0,
+ },
+ spentBy: {
+ txid: '17fac4d29bb5e2ed5615f35ace4568adbb39555d871abde3cd9f2afd17980a8d',
+ outIdx: 0,
+ },
+ },
+ {
+ sats: 546n,
+ outputScript:
+ '76a914ec135a17f346b3f9daedf788cffbc3441ff0425388ac',
+ token: {
+ tokenId:
+ '0387947fd575db4fb19a3e322f635dec37fd192b5941625b66bc4b2c3008cbf0',
+ tokenType: {
+ protocol: 'ALP',
+ type: 'ALP_TOKEN_TYPE_STANDARD',
+ number: 0,
+ },
+ atoms: 82n,
+ isMintBaton: false,
+ entryIdx: 0,
+ },
+ },
+ {
+ sats: 546n,
+ outputScript:
+ '76a9149f88249247eba350d3b5ea61187fa1693e15524e88ac',
+ token: {
+ tokenId:
+ '0387947fd575db4fb19a3e322f635dec37fd192b5941625b66bc4b2c3008cbf0',
+ tokenType: {
+ protocol: 'ALP',
+ type: 'ALP_TOKEN_TYPE_STANDARD',
+ number: 0,
+ },
+ atoms: 43n,
+ isMintBaton: false,
+ entryIdx: 0,
+ },
+ },
+ {
+ sats: 546n,
+ outputScript:
+ '76a914a68be843583d8c053f64f1dbc800e8e78ec4fc7788ac',
+ token: {
+ tokenId:
+ '0387947fd575db4fb19a3e322f635dec37fd192b5941625b66bc4b2c3008cbf0',
+ tokenType: {
+ protocol: 'ALP',
+ type: 'ALP_TOKEN_TYPE_STANDARD',
+ number: 0,
+ },
+ atoms: 25n,
+ isMintBaton: false,
+ entryIdx: 0,
+ },
+ },
+ {
+ sats: 546n,
+ outputScript:
+ '76a914dee50f576362377dd2f031453c0bb09009acaf8188ac',
+ token: {
+ tokenId:
+ '0387947fd575db4fb19a3e322f635dec37fd192b5941625b66bc4b2c3008cbf0',
+ tokenType: {
+ protocol: 'ALP',
+ type: 'ALP_TOKEN_TYPE_STANDARD',
+ number: 0,
+ },
+ atoms: 15n,
+ isMintBaton: false,
+ entryIdx: 0,
+ },
+ },
+ {
+ sats: 546n,
+ outputScript:
+ '76a914bf095d9afbda5245d5f1e27e7b360ec22357d6f088ac',
+ token: {
+ tokenId:
+ '0387947fd575db4fb19a3e322f635dec37fd192b5941625b66bc4b2c3008cbf0',
+ tokenType: {
+ protocol: 'ALP',
+ type: 'ALP_TOKEN_TYPE_STANDARD',
+ number: 0,
+ },
+ atoms: 15n,
+ isMintBaton: false,
+ entryIdx: 0,
+ },
+ },
+ {
+ sats: 546n,
+ outputScript:
+ '76a9142a96944d06700882bbd984761d9c9e4215f2d78e88ac',
+ token: {
+ tokenId:
+ '0387947fd575db4fb19a3e322f635dec37fd192b5941625b66bc4b2c3008cbf0',
+ tokenType: {
+ protocol: 'ALP',
+ type: 'ALP_TOKEN_TYPE_STANDARD',
+ number: 0,
+ },
+ atoms: 13n,
+ isMintBaton: false,
+ entryIdx: 0,
+ },
+ },
+ {
+ sats: 546n,
+ outputScript:
+ '76a91428ef733a0427f54c95cc5efea72d95f99db8e48d88ac',
+ token: {
+ tokenId:
+ '0387947fd575db4fb19a3e322f635dec37fd192b5941625b66bc4b2c3008cbf0',
+ tokenType: {
+ protocol: 'ALP',
+ type: 'ALP_TOKEN_TYPE_STANDARD',
+ number: 0,
+ },
+ atoms: 7n,
+ isMintBaton: false,
+ entryIdx: 0,
+ },
+ },
+ {
+ sats: 546n,
+ outputScript:
+ '76a91476458db0ed96fe9863fc1ccec9fa2cfab884b0f688ac',
+ token: {
+ tokenId:
+ '0387947fd575db4fb19a3e322f635dec37fd192b5941625b66bc4b2c3008cbf0',
+ tokenType: {
+ protocol: 'ALP',
+ type: 'ALP_TOKEN_TYPE_STANDARD',
+ number: 0,
+ },
+ atoms: 7n,
+ isMintBaton: false,
+ entryIdx: 0,
+ },
+ },
+ {
+ sats: 546n,
+ outputScript:
+ '76a91438d2e1501a485814e2849552093bb0588ed9acbb88ac',
+ token: {
+ tokenId:
+ '0387947fd575db4fb19a3e322f635dec37fd192b5941625b66bc4b2c3008cbf0',
+ tokenType: {
+ protocol: 'ALP',
+ type: 'ALP_TOKEN_TYPE_STANDARD',
+ number: 0,
+ },
+ atoms: 20n,
+ isMintBaton: false,
+ entryIdx: 0,
+ },
+ },
+ {
+ sats: 31242653n,
+ outputScript:
+ '76a91438d2e1501a485814e2849552093bb0588ed9acbb88ac',
+ spentBy: {
+ txid: 'fa9b61637a7366d349cbfb3eab8df48a49f7df8f841572fac7ecb940704ba2e4',
+ outIdx: 0,
+ },
+ },
+ ],
+ lockTime: 0,
+ timeFirstSeen: 1740524404,
+ size: 1043,
+ isCoinbase: false,
+ tokenEntries: [
+ {
+ tokenId:
+ '0387947fd575db4fb19a3e322f635dec37fd192b5941625b66bc4b2c3008cbf0',
+ tokenType: {
+ protocol: 'ALP',
+ type: 'ALP_TOKEN_TYPE_STANDARD',
+ number: 0,
+ },
+ txType: 'SEND',
+ isInvalid: false,
+ burnSummary: '',
+ failedColorings: [],
+ actualBurnAtoms: 0n,
+ intentionalBurnAtoms: 0n,
+ burnsMintBatons: false,
+ },
+ ],
+ tokenFailedParsings: [],
+ tokenStatus: 'TOKEN_STATUS_NORMAL',
+ isFinal: true,
+ block: {
+ height: 885661,
+ hash: '000000000000000016bfc7ceeaa54b9c4a3000cb0c7527c1f5620cf1d83b1437',
+ timestamp: 1740524423,
+ },
+ },
+ // TODO confusing in mocks.js
+ // sendingHash is actually the hash of the active wallet
+ // So we can parse a "received" tx if this is from the received side
+ sendingHash: '38d2e1501a485814e2849552093bb0588ed9acbb',
+ receivingHash: 'a5417349420ec53b27522fed1a63b1672c0f28ff',
+ parsedSend: {
+ appActions: [],
+ parsedTokenEntries: [
+ {
+ renderedTokenType: 'ALP',
+ renderedTxType: 'SEND',
+ tokenId:
+ '0387947fd575db4fb19a3e322f635dec37fd192b5941625b66bc4b2c3008cbf0',
+ tokenSatoshis: '200481',
+ },
+ ],
+ recipients: [
+ 'ecash:qr8hdk8rxjc5nj6f450eth3nnslxa8k4gysrtyfxc5',
+ 'ecash:qzj5zu6fgg8v2we82gh76xnrk9njcreglum9ffspnr',
+ 'ecash:qrhysunk5kdt8n3e0jngjnavv6v2hgdkjcmsudvl92',
+ 'ecash:qz2708636snqhsxu8wnlka78h6fdp77ar59jrf5035',
+ 'ecash:qrkpxksh7drt87w6ahmc3nlmcdzpluzz2vpjvwuuxy',
+ 'ecash:qz0csfyjgl46x5xnkh4xzxrl595nu92jfch930m9sw',
+ 'ecash:qzngh6zrtq7ccpflvncahjqqarnca38uwumh845f6p',
+ 'ecash:qr0w2r6hvd3rwlwj7qc520qtkzgqnt90sypk26yd2u',
+ 'ecash:qzlsjhv6l0d9y3w47838u7ekpmpzx47k7qne9uv3t5',
+ 'ecash:qq4fd9zdqecq3q4mmxz8v8vunepptukh3czav3gjyt',
+ 'ecash:qq5w7ue6qsnl2ny4e300afedjhuemw8y35j2e9mf0h',
+ 'ecash:qpmytrdsakt0axrrlswvaj069nat3p9s7cjctmjasj',
+ ],
+ satoshisSent: 6552,
+ stackArray: [
+ '50',
+ '534c5032000453454e44f0cb08302c4bbc665b6241592b19fd37ec5d632f323e9ab14fdb75d57f9487030d6d0c03000000c30000000000b900000000006900000000005200000000002b00000000001900000000000f00000000000f00000000000d0000000000070000000000070000000000140000000000',
+ ],
+ xecTxType: 'Sent',
+ },
+ parsedReceive: {
+ appActions: [],
+ parsedTokenEntries: [
+ {
+ renderedTokenType: 'ALP',
+ renderedTxType: 'SEND',
+ tokenId:
+ '0387947fd575db4fb19a3e322f635dec37fd192b5941625b66bc4b2c3008cbf0',
+ tokenSatoshis: '195',
+ },
+ ],
+ recipients: [
+ 'ecash:qr8hdk8rxjc5nj6f450eth3nnslxa8k4gysrtyfxc5',
+ 'ecash:qrhysunk5kdt8n3e0jngjnavv6v2hgdkjcmsudvl92',
+ 'ecash:qz2708636snqhsxu8wnlka78h6fdp77ar59jrf5035',
+ 'ecash:qrkpxksh7drt87w6ahmc3nlmcdzpluzz2vpjvwuuxy',
+ 'ecash:qz0csfyjgl46x5xnkh4xzxrl595nu92jfch930m9sw',
+ 'ecash:qzngh6zrtq7ccpflvncahjqqarnca38uwumh845f6p',
+ 'ecash:qr0w2r6hvd3rwlwj7qc520qtkzgqnt90sypk26yd2u',
+ 'ecash:qzlsjhv6l0d9y3w47838u7ekpmpzx47k7qne9uv3t5',
+ 'ecash:qq4fd9zdqecq3q4mmxz8v8vunepptukh3czav3gjyt',
+ 'ecash:qq5w7ue6qsnl2ny4e300afedjhuemw8y35j2e9mf0h',
+ 'ecash:qpmytrdsakt0axrrlswvaj069nat3p9s7cjctmjasj',
+ 'ecash:qqud9c2srfy9s98zsj24yzfmkpvgakdvhv6xx7umh5',
+ ],
+ replyAddress: 'ecash:qqud9c2srfy9s98zsj24yzfmkpvgakdvhv6xx7umh5',
+ satoshisSent: 546,
+ stackArray: [
+ '50',
+ '534c5032000453454e44f0cb08302c4bbc665b6241592b19fd37ec5d632f323e9ab14fdb75d57f9487030d6d0c03000000c30000000000b900000000006900000000005200000000002b00000000001900000000000f00000000000f00000000000d0000000000070000000000070000000000140000000000',
+ ],
+ xecTxType: 'Received',
+ },
+};
diff --git a/cashtab/src/chronik/fixtures/vectors.js b/cashtab/src/chronik/fixtures/vectors.js
index a70cdaa16..a5f54c4a8 100644
--- a/cashtab/src/chronik/fixtures/vectors.js
+++ b/cashtab/src/chronik/fixtures/vectors.js
@@ -71,6 +71,7 @@ import {
offSpecCashtabMsg,
xecxTx,
invalidXecxTx,
+ firmaYieldTx,
} from './mocks';
import { mockChronikUtxos, mockOrganizedUtxosByType } from './chronikUtxos';
import { getHashes } from 'wallet';
@@ -517,6 +518,40 @@ export default {
genesisInfo: undefined,
returned: 'Received 312,503.71 XEC | Invalid XECX',
},
+ {
+ description: 'Firma yield tx (send)',
+ parsedTx: firmaYieldTx.parsedSend,
+ fiatPrice: null,
+ userLocale: 'en-US',
+ selectedFiatTicker: 'USD',
+ genesisInfo: {
+ tokenTicker: 'FIRMA',
+ tokenName: 'Firma',
+ url: 'firma.cash',
+ decimals: 4,
+ data: '',
+ authPubkey:
+ '03fba49912622cf8bb5b3729b1b5da3e72c6b57d369c8647f6cc7c6cbed510d105',
+ },
+ returned: 'Sent 20.0481 FIRMA',
+ },
+ {
+ description: 'Firma yield tx (receive)',
+ parsedTx: firmaYieldTx.parsedReceive,
+ fiatPrice: null,
+ userLocale: 'en-US',
+ selectedFiatTicker: 'USD',
+ genesisInfo: {
+ tokenTicker: 'FIRMA',
+ tokenName: 'Firma',
+ url: 'firma.cash',
+ decimals: 4,
+ data: '',
+ authPubkey:
+ '03fba49912622cf8bb5b3729b1b5da3e72c6b57d369c8647f6cc7c6cbed510d105',
+ },
+ returned: 'Received 0.0195 FIRMA',
+ },
],
},
parseTx: {
@@ -868,6 +903,18 @@ export default {
hashes: [invalidXecxTx.sendingHash],
parsed: invalidXecxTx.parsed,
},
+ {
+ description: 'Firma yield tx (send)',
+ tx: firmaYieldTx.tx,
+ hashes: [firmaYieldTx.sendingHash],
+ parsed: firmaYieldTx.parsedSend,
+ },
+ {
+ description: 'Firma yield tx (receive)',
+ tx: firmaYieldTx.tx,
+ hashes: [firmaYieldTx.receivingHash],
+ parsed: firmaYieldTx.parsedReceive,
+ },
],
},
sortAndTrimChronikTxHistory: {
diff --git a/cashtab/src/components/Common/CustomIcons.js b/cashtab/src/components/Common/CustomIcons.js
index 5b82bd18f..e9070e2dc 100644
--- a/cashtab/src/components/Common/CustomIcons.js
+++ b/cashtab/src/components/Common/CustomIcons.js
@@ -6,6 +6,7 @@ import * as React from 'react';
import styled from 'styled-components';
import PayButton from 'assets/paybutton.webp';
import XecxSrc from 'assets/xecx-logomark.png';
+import FirmaSrc from 'assets/firma-icon.png';
import { ReactComponent as QRCode } from 'assets/qrcode.svg';
import { ReactComponent as Send } from 'assets/send.svg';
import { ReactComponent as CopyPaste } from 'assets/copypaste.svg';
@@ -152,6 +153,7 @@ export const PayButtonIcon = () => (
<PayButtonImg src={PayButton} alt="tx-paybutton" />
);
export const XecxIcon = () => <img src={XecxSrc} alt="XECX reward" />;
+export const FirmaIcon = () => <img src={FirmaSrc} alt="Firma reward" />;
const PaywallPaymentIconWrapper = styled.div`
svg,
diff --git a/cashtab/src/components/Home/Tx/__tests__/index.test.js b/cashtab/src/components/Home/Tx/__tests__/index.test.js
index 2842ce45a..b33ccd434 100644
--- a/cashtab/src/components/Home/Tx/__tests__/index.test.js
+++ b/cashtab/src/components/Home/Tx/__tests__/index.test.js
@@ -72,6 +72,7 @@ import {
alpAgoraListingTx,
xecxTx,
invalidXecxTx,
+ firmaYieldTx,
} from 'chronik/fixtures/mocks';
import CashtabState from 'config/CashtabState';
import { MemoryRouter } from 'react-router-dom';
@@ -3836,4 +3837,92 @@ describe('<Tx />', () => {
// We see the invalid App Action
expect(screen.getByText('Invalid XECX EMPP')).toBeInTheDocument();
});
+ it('Outgoing FIRMA yield payment', async () => {
+ const thisMock = firmaYieldTx;
+ render(
+ <MemoryRouter>
+ <ThemeProvider theme={theme}>
+ <Tx
+ tx={{ ...thisMock.tx, parsed: thisMock.parsedSend }}
+ hashes={[thisMock.sendingHash]}
+ fiatPrice={0.00003}
+ fiatCurrency="usd"
+ cashtabState={{
+ ...new CashtabState(),
+ cashtabCache: {
+ tokens: new Map(),
+ },
+ }}
+ chaintipBlockheight={AVALANCHE_FINALIZED_CHAINTIP}
+ />
+ ,
+ </ThemeProvider>
+ </MemoryRouter>,
+ );
+
+ // We see a conventional tx-sent icon for the XEC action
+ expect(screen.getByTitle('tx-sent')).toBeInTheDocument();
+
+ // We see expected label
+ expect(screen.getByText(/Sent to/)).toBeInTheDocument();
+
+ // We render the timestamp
+ expect(screen.getByText('Feb 25, 2025, 23:00:04')).toBeInTheDocument();
+
+ // We see the expected sent amount
+ expect(screen.getByText('-65.52 XEC')).toBeInTheDocument();
+
+ // We see the a fiat amount
+ expect(screen.getByText('-$0.00')).toBeInTheDocument();
+
+ // We see Firma icon
+ expect(screen.getByAltText(`Firma reward`)).toBeInTheDocument();
+
+ // We see Firma yield app action
+ expect(screen.getByText(`Firma yield payment`)).toBeInTheDocument();
+ });
+ it('Incoming FIRMA yield payment', async () => {
+ const thisMock = firmaYieldTx;
+ render(
+ <MemoryRouter>
+ <ThemeProvider theme={theme}>
+ <Tx
+ tx={{ ...thisMock.tx, parsed: thisMock.parsedReceive }}
+ hashes={[thisMock.receivingHashHash]}
+ fiatPrice={0.00003}
+ fiatCurrency="usd"
+ cashtabState={{
+ ...new CashtabState(),
+ cashtabCache: {
+ tokens: new Map(),
+ },
+ }}
+ chaintipBlockheight={AVALANCHE_FINALIZED_CHAINTIP}
+ />
+ ,
+ </ThemeProvider>
+ </MemoryRouter>,
+ );
+
+ // We see a conventional tx-received icon for the XEC action
+ expect(screen.getByTitle('tx-received')).toBeInTheDocument();
+
+ // We see expected label
+ expect(screen.getByText(/Received from/)).toBeInTheDocument();
+
+ // We render the timestamp
+ expect(screen.getByText('Feb 25, 2025, 23:00:04')).toBeInTheDocument();
+
+ // We see the expected sent amount
+ expect(screen.getByText('5.46 XEC')).toBeInTheDocument();
+
+ // We see the a fiat amount
+ expect(screen.getByText('$0.00')).toBeInTheDocument();
+
+ // We see Firma icon
+ expect(screen.getByAltText(`Firma reward`)).toBeInTheDocument();
+
+ // We see Firma yield app action
+ expect(screen.getByText(`Firma yield payment`)).toBeInTheDocument();
+ });
});
diff --git a/cashtab/src/components/Home/Tx/index.tsx b/cashtab/src/components/Home/Tx/index.tsx
index 80d81a4bc..acac44446 100644
--- a/cashtab/src/components/Home/Tx/index.tsx
+++ b/cashtab/src/components/Home/Tx/index.tsx
@@ -65,6 +65,7 @@ import {
AgoraCancelIcon,
TokenSendIcon,
XecxIcon,
+ FirmaIcon,
} from 'components/Common/CustomIcons';
import CashtabSettings, {
supportedFiatCurrencies,
@@ -167,6 +168,30 @@ const Tx: React.FC<TxProps> = ({
}
const renderedAppActions: React.ReactNode[] = [];
+
+ // Add firma yield if applicable
+ // NB firma yield is not not identified by OP_RETURN
+ // But it is, semantically speaking, an "app action"
+
+ // A firma yield payment is identified as
+ // - received firma
+ // - sending address was firma yield wallet
+ const isFirmaYield =
+ !tx.isCoinbase &&
+ tx.inputs[0].outputScript ===
+ '76a91438d2e1501a485814e2849552093bb0588ed9acbb88ac' &&
+ typeof parsed.parsedTokenEntries[0] !== 'undefined' &&
+ parsed.parsedTokenEntries[0].tokenId ===
+ '0387947fd575db4fb19a3e322f635dec37fd192b5941625b66bc4b2c3008cbf0';
+ if (isFirmaYield) {
+ renderedAppActions.push(
+ <IconAndLabel>
+ <FirmaIcon />
+ <AppDescLabel noWordBreak>Firma yield payment</AppDescLabel>
+ </IconAndLabel>,
+ );
+ }
+
for (const appAction of appActions) {
const { lokadId, app, isValid, action } = appAction;
switch (lokadId) {
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sun, Mar 2, 12:42 (1 d, 12 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5187878
Default Alt Text
(27 KB)
Attached To
rABC Bitcoin ABC
Event Timeline
Log In to Comment