diff --git a/src/pg/helpers.ts b/src/pg/helpers.ts index e992a695..f156a2ac 100644 --- a/src/pg/helpers.ts +++ b/src/pg/helpers.ts @@ -1,4 +1,4 @@ -import { PgBytea, toEnumValue } from '@hirosystems/api-toolkit'; +import { PgBytea, logger, toEnumValue } from '@hirosystems/api-toolkit'; import { hexToBuffer, normalizedHexString, parseSatPoint } from '../api/util/helpers'; import { BadPayloadRequestError, @@ -98,12 +98,25 @@ function updateFromOrdhookInscriptionRevealed(args: { const satoshi = new OrdinalSatoshi(args.reveal.ordinal_number); const satpoint = parseSatPoint(args.reveal.satpoint_post_inscription); const recursive_refs = getInscriptionRecursion(args.reveal.content_bytes); - const contentType = removeNullBytes(args.reveal.content_type); + const content_type = removeNullBytes(args.reveal.content_type); + let transfer_type = DbLocationTransferType.transferred; + if (args.reveal.inscriber_address == null || args.reveal.inscriber_address == '') { + if (args.reveal.inscription_output_value == 0) { + if (args.reveal.inscription_pointer !== 0 && args.reveal.inscription_pointer !== null) { + logger.warn( + `Detected inscription reveal with no address and no output value but a valid pointer ${args.reveal.inscription_id}` + ); + } + transfer_type = DbLocationTransferType.spentInFees; + } else { + transfer_type = DbLocationTransferType.burnt; + } + } return { inscription: { genesis_id: args.reveal.inscription_id, - mime_type: contentType.split(';')[0], - content_type: contentType, + mime_type: content_type.split(';')[0], + content_type, content_length: args.reveal.content_length, number: args.reveal.inscription_number.jubilee, classic_number: args.reveal.inscription_number.classic, @@ -131,7 +144,7 @@ function updateFromOrdhookInscriptionRevealed(args: { prev_offset: null, value: args.reveal.inscription_output_value.toString(), timestamp: args.timestamp, - transfer_type: DbLocationTransferType.transferred, + transfer_type, }, recursive_refs, }; diff --git a/tests/brc-20/brc20.test.ts b/tests/brc-20/brc20.test.ts index efedf8c4..ff1b42bb 100644 --- a/tests/brc-20/brc20.test.ts +++ b/tests/brc-20/brc20.test.ts @@ -225,6 +225,104 @@ describe('BRC-20', () => { expect(brc20FromInscription(insert)).toBeUndefined(); }); + test('ignores inscriptions spent as fees', () => { + const content = Buffer.from( + JSON.stringify({ + p: 'brc-20', + op: 'deploy', + tick: 'PEPE', + max: '21000000', + }), + 'utf-8' + ); + const insert: InscriptionRevealData = { + inscription: { + genesis_id: '38c46a8bf7ec90bc7f6b797e7dc84baa97f4e5fd4286b92fe1b50176d03b18dci0', + number: 0, + classic_number: 0, + mime_type: 'application/json', + content_type: 'application/json', + content_length: content.length, + content: `0x${content.toString('hex')}`, + fee: '200', + curse_type: null, + sat_ordinal: '2000000', + sat_rarity: 'common', + sat_coinbase_height: 110, + recursive: false, + metadata: null, + parent: null, + }, + recursive_refs: [], + location: { + genesis_id: '38c46a8bf7ec90bc7f6b797e7dc84baa97f4e5fd4286b92fe1b50176d03b18dci0', + block_height: 830000, + block_hash: '00000000000000000002c5c0aba96f981642a6dca109e6b3564925c21a98aa3e', + tx_id: '38c46a8bf7ec90bc7f6b797e7dc84baa97f4e5fd4286b92fe1b50176d03b18dc', + tx_index: 0, + address: '', + output: '38c46a8bf7ec90bc7f6b797e7dc84baa97f4e5fd4286b92fe1b50176d03b18dc:0', + offset: '0', + prev_output: null, + prev_offset: null, + value: '0', + transfer_type: DbLocationTransferType.spentInFees, + block_transfer_index: null, + timestamp: 1091091019, + }, + }; + expect(brc20FromInscription(insert)).toBeUndefined(); + }); + + test('ignores burnt inscriptions', () => { + const content = Buffer.from( + JSON.stringify({ + p: 'brc-20', + op: 'deploy', + tick: 'PEPE', + max: '21000000', + }), + 'utf-8' + ); + const insert: InscriptionRevealData = { + inscription: { + genesis_id: '38c46a8bf7ec90bc7f6b797e7dc84baa97f4e5fd4286b92fe1b50176d03b18dci0', + number: 0, + classic_number: 0, + mime_type: 'application/json', + content_type: 'application/json', + content_length: content.length, + content: `0x${content.toString('hex')}`, + fee: '200', + curse_type: null, + sat_ordinal: '2000000', + sat_rarity: 'common', + sat_coinbase_height: 110, + recursive: false, + metadata: null, + parent: null, + }, + recursive_refs: [], + location: { + genesis_id: '38c46a8bf7ec90bc7f6b797e7dc84baa97f4e5fd4286b92fe1b50176d03b18dci0', + block_height: 830000, + block_hash: '00000000000000000002c5c0aba96f981642a6dca109e6b3564925c21a98aa3e', + tx_id: '38c46a8bf7ec90bc7f6b797e7dc84baa97f4e5fd4286b92fe1b50176d03b18dc', + tx_index: 0, + address: '', + output: '38c46a8bf7ec90bc7f6b797e7dc84baa97f4e5fd4286b92fe1b50176d03b18dc:0', + offset: '0', + prev_output: null, + prev_offset: null, + value: '1000', + transfer_type: DbLocationTransferType.burnt, + block_transfer_index: null, + timestamp: 1091091019, + }, + }; + expect(brc20FromInscription(insert)).toBeUndefined(); + }); + test('ignores incorrect p field', () => { const insert = testInsert({ p: 'brc20', // incorrect