Skip to content

Commit 8a208a3

Browse files
committed
populate atomicalOps + counterpartyMessages satellite arrays
Per-block satellite rows for the two protocols whose downstream charts want per-op / per-message-type breakdowns: atomicals.atomicalOps[] — one entry per atomical artifact, with (txId, operation, ticker). Ticker is args.request_ticker for FT-family ops, null otherwise. CBOR decode failure on getArgs() is swallowed; the op record still gets pushed. counterparty.counterpartyMessages[] — one entry per counterparty message, with (txId, messageType, messageTypeId, encoding). Mirrors what the backend's counterparty satellite table will store. Tests use real fixture txns: - Atomicals DFT mint of "atom" → ['dft', 'atom'] - Counterparty enhanced_send (messageTypeId 2, opreturn encoding) - CAT-21 genesis tx → both arrays empty
1 parent df53c9d commit 8a208a3

2 files changed

Lines changed: 87 additions & 1 deletion

File tree

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { readTransaction } from '../testdata/test.helper';
2+
import { DigitalArtifactAnalyserService } from './digital-artifact-analyser.service';
3+
import { TransactionSimplePlus } from './types/transaction-simple';
4+
5+
// Real mainnet atomicals DFT mint — operation 'dft', ticker 'atom'
6+
const ATOMICAL_DFT_TXID = '1d2f39f54320631d0432fa495a45a4f298a2ca1b18adef8e4356e327d003a694';
7+
8+
// Real mainnet Counterparty enhanced_send — message type ID 2
9+
const ENHANCED_SEND_TXID = 'f3981dac3d2d43abf6c3bb059fbd998bcd8f76c4174fd1e2668599b9713649c9';
10+
11+
describe('DigitalArtifactAnalyserService — satellite arrays', () => {
12+
13+
it('records every atomical operation in atomicalOps with operation + ticker', async () => {
14+
const tx = readTransaction(ATOMICAL_DFT_TXID) as unknown as TransactionSimplePlus;
15+
const stats = await DigitalArtifactAnalyserService.analyseTransactions([tx]);
16+
17+
expect(stats.atomicals.atomicalOps).toEqual([
18+
{ txId: ATOMICAL_DFT_TXID, operation: 'dft', ticker: 'atom' },
19+
]);
20+
});
21+
22+
it('records every counterparty message in counterpartyMessages with messageType + id + encoding', async () => {
23+
const tx = readTransaction(ENHANCED_SEND_TXID) as unknown as TransactionSimplePlus;
24+
const stats = await DigitalArtifactAnalyserService.analyseTransactions([tx]);
25+
26+
expect(stats.counterparty.counterpartyMessages).toHaveLength(1);
27+
const message = stats.counterparty.counterpartyMessages[0];
28+
expect(message.txId).toBe(ENHANCED_SEND_TXID);
29+
expect(message.messageType).toBe('enhanced_send');
30+
expect(message.messageTypeId).toBe(2);
31+
expect(message.encoding).toBe('opreturn');
32+
});
33+
34+
it('returns empty arrays when neither atomicals nor counterparty are present', async () => {
35+
// CAT-21 genesis tx: no atomical, no counterparty.
36+
const tx = readTransaction('98316dcb21daaa221865208fe0323616ee6dd84e6020b78bc6908e914ac03892') as unknown as TransactionSimplePlus;
37+
const stats = await DigitalArtifactAnalyserService.analyseTransactions([tx]);
38+
39+
expect(stats.atomicals.atomicalOps).toEqual([]);
40+
expect(stats.counterparty.counterpartyMessages).toEqual([]);
41+
});
42+
});

src/digital-artifact-analyser.service.ts

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,12 @@ import { isUncommonGoodsMint } from './rune/rune-parser.service.helper';
99
import { Src20ParserService } from './src20/src20-parser.service';
1010
import { DigitalArtifact, DigitalArtifactType } from './types/digital-artifact';
1111
import { ParsedAtomical } from './types/parsed-atomical';
12+
import { ParsedCounterparty } from './types/parsed-counterparty';
1213
import {
14+
AtomicalOp,
1315
Brc20DeployAttempt,
1416
Cat21Mint,
17+
CounterpartyMessage,
1518
getArtifactTypeMap,
1619
getEmptyInscriptionSizeAggregate,
1720
getEmptyStats,
@@ -231,6 +234,13 @@ export class DigitalArtifactAnalyserService {
231234
const brc20DeployAttempts: Brc20DeployAttempt[] = [];
232235
const src20DeployAttempts: Src20DeployAttempt[] = [];
233236

237+
// Per-tx satellite arrays. atomicalOps records every atomical operation
238+
// (mint or update); counterpartyMessages records every CNTRPRTY message.
239+
// The backend writes these to dedicated satellite tables for per-op /
240+
// per-message-type charts.
241+
const atomicalOps: AtomicalOp[] = [];
242+
const counterpartyMessages: CounterpartyMessage[] = [];
243+
234244
// index is zero-based, we start at -1 so that the 1st txn has number 0
235245
let txIndex = -1;
236246
for (const tx of transactions) {
@@ -377,12 +387,44 @@ export class DigitalArtifactAnalyserService {
377387
}
378388
}
379389

380-
// ** Atomical Fees
390+
// ** Atomical Fees + per-op satellite row
381391
if ((flags & OrdpoolTransactionFlags.ordpool_atomical) === OrdpoolTransactionFlags.ordpool_atomical) {
382392
if (!atomicalFeeAdded) {
383393
totalAtomicalFees += txFee;
384394
atomicalFeeAdded = true;
385395
}
396+
397+
// Record one row per atomical artifact for the satellite table.
398+
// Ticker comes from CBOR `args.request_ticker` (FT-family ops);
399+
// null for ops that don't carry one. getArgs() may return null
400+
// if CBOR decoding fails — defensive read.
401+
const atomical = artifact as ParsedAtomical;
402+
let ticker: string | null = null;
403+
try {
404+
const args = atomical.getArgs();
405+
const rawTicker = args?.['request_ticker'];
406+
if (typeof rawTicker === 'string' && rawTicker.length > 0) {
407+
ticker = rawTicker;
408+
}
409+
} catch {
410+
// CBOR decoding failed; leave ticker null, keep the op record.
411+
}
412+
atomicalOps.push({
413+
txId: tx.txid,
414+
operation: atomical.operation,
415+
ticker,
416+
});
417+
}
418+
419+
// ** Counterparty per-message satellite row
420+
if ((flags & OrdpoolTransactionFlags.ordpool_counterparty) === OrdpoolTransactionFlags.ordpool_counterparty) {
421+
const counterparty = artifact as ParsedCounterparty;
422+
counterpartyMessages.push({
423+
txId: tx.txid,
424+
messageType: counterparty.messageType,
425+
messageTypeId: counterparty.messageTypeId,
426+
encoding: counterparty.encoding,
427+
});
386428
}
387429

388430
// ** Inscription Mint Fees + extra stats for inscriptions
@@ -532,6 +574,8 @@ export class DigitalArtifactAnalyserService {
532574
stats.src20.src20DeployAttempts = src20DeployAttempts;
533575

534576
stats.cat21.cat21MintActivity = cat21MintActivity;
577+
stats.atomicals.atomicalOps = atomicalOps;
578+
stats.counterparty.counterpartyMessages = counterpartyMessages;
535579

536580
// CAT-21 block aggregates derived from the per-cat satellite array.
537581
// All NULLable for blocks without cats. Note: cat *numbers* are NOT

0 commit comments

Comments
 (0)