@@ -215,5 +215,88 @@ describe('CounterpartyParserService', () => {
215215 // CBOR-encoded fairminter payload (97 bytes, first byte was the type ID)
216216 expect ( result . getMessageData ( ) . length ) . toBe ( 97 ) ;
217217 } ) ;
218+
219+ // !! FAKE TRANSACTION -- NOT FROM MAINNET OR ANY TESTNET !!
220+ //
221+ // The "ord" inscription envelope (OP_FALSE OP_IF "ord" [7] "xcp" ... OP_ENDIF)
222+ // is used when composing with inscription=true (opt-in, defaults to false).
223+ // As of March 2026, zero transactions on mainnet, testnet3, or testnet4 use
224+ // this format. The Counterparty team confirmed inscription defaults to false
225+ // (GitHub issue #3179). No public testnet API is available to search.
226+ //
227+ // The envelope script below is constructed from the official Counterparty
228+ // composer unit test: counterparty-core/test/units/api/composertaproot_test.py
229+ // The CBOR metadata and content bytes are taken verbatim from that test.
230+ //
231+ // TODO: Replace with a real mainnet/testnet transaction when one exists.
232+ it ( 'should parse an ord inscription envelope (FAKE -- from Counterparty regtest test data)' , ( ) => {
233+ const txn = readTransaction ( 'counterparty_regtest_ord_envelope_fairminter' ) ;
234+ const result = CounterpartyParserService . parse ( txn ) ! ;
235+
236+ expect ( result . type ) . toBe ( DigitalArtifactType . Counterparty ) ;
237+ expect ( result . encoding ) . toBe ( 'p2tr' ) ;
238+ expect ( result . messageTypeId ) . toBe ( 90 ) ;
239+ expect ( result . messageType ) . toBe ( 'fairminter' ) ;
240+
241+ // The re-encoded CBOR contains: fairminter fields + "text/plain" + content bytes
242+ expect ( result . getMessageData ( ) . length ) . toBe ( 77 ) ;
243+ } ) ;
244+ } ) ;
245+
246+ // ===========================================================================
247+ // 4-byte message type ID (pre-short_tx_type_id, before block 489,956)
248+ // ===========================================================================
249+
250+ describe ( 'parse — 4-byte message type ID' , ( ) => {
251+ // Classic send (ID 0) via OP_RETURN -- uses 4-byte big-endian encoding (00 00 00 00)
252+ // Block 489,000 (before short_tx_type_id activation at 489,956)
253+ // Sends 2,100,000,000 TRIGGERS
254+ const CLASSIC_SEND_TXID = '6335eefb68f5e57eddb95b329c368615e53cf5efe346be14d271c88a63b5461e' ;
255+
256+ it ( 'should parse a classic send (ID 0, 4-byte encoding) via OP_RETURN' , ( ) => {
257+ const txn = readTransaction ( CLASSIC_SEND_TXID ) ;
258+ const result = CounterpartyParserService . parse ( txn ) ! ;
259+
260+ expect ( result . encoding ) . toBe ( 'opreturn' ) ;
261+ expect ( result . messageTypeId ) . toBe ( 0 ) ;
262+ expect ( result . messageType ) . toBe ( 'send' ) ;
263+
264+ // Classic send payload: asset_id (8 bytes BE) + quantity (8 bytes BE) = 16 bytes
265+ // API raw data: 20 bytes = 4 bytes type ID (00000000) + 16 bytes payload
266+ expect ( result . getMessageData ( ) . length ) . toBe ( 16 ) ;
267+ } ) ;
268+
269+ it ( 'should parse a broadcast (ID 30, 4-byte encoding) via multisig (OLGA)' , ( ) => {
270+ // OLGA predates short_tx_type_id -- uses 4-byte encoding even for ID 30
271+ // API raw data: 9136 bytes = 4 bytes type ID (0000001e) + 9132 bytes payload
272+ const txn = readTransaction ( OLGA_MULTISIG_TXID ) ;
273+ const result = CounterpartyParserService . parse ( txn ) ! ;
274+
275+ expect ( result . messageTypeId ) . toBe ( 30 ) ;
276+ expect ( result . getMessageData ( ) . length ) . toBe ( 9132 ) ;
277+ } ) ;
278+ } ) ;
279+
280+ // ===========================================================================
281+ // Early exit correctness — reject non-Counterparty OP_RETURN transactions
282+ // ===========================================================================
283+
284+ describe ( 'early exits' , ( ) => {
285+ // Rune OP_RETURN starts with 6a5d (OP_RETURN + OP_PUSHNUM_13)
286+ // Our code rejects byte[1] > 0x4e before ARC4 decryption
287+ const RUNE_TXID = '1af2a846befbfac4091bf540adad4fd1a86604c26c004066077d5fe22510e99b' ;
288+
289+ // Short OP_RETURN (8 hex chars = 4 bytes, below our 22 hex char minimum)
290+ const SHORT_OP_RETURN_TXID = '28baf9374797230174803b0c3f63fd39e22bb1972a25cc2af4e791ca8fc89dae' ;
291+
292+ it ( 'should reject a Rune transaction (OP_PUSHNUM_13 early exit)' , ( ) => {
293+ const txn = readTransaction ( RUNE_TXID ) ;
294+ expect ( CounterpartyParserService . parse ( txn ) ) . toBeNull ( ) ;
295+ } ) ;
296+
297+ it ( 'should reject a short OP_RETURN transaction (< 22 hex chars)' , ( ) => {
298+ const txn = readTransaction ( SHORT_OP_RETURN_TXID ) ;
299+ expect ( CounterpartyParserService . parse ( txn ) ) . toBeNull ( ) ;
300+ } ) ;
218301 } ) ;
219302} ) ;
0 commit comments