Skip to content

Commit

Permalink
fix: transfers only usable once
Browse files Browse the repository at this point in the history
  • Loading branch information
rafaelcr committed Jun 15, 2023
1 parent dd8ec07 commit 542ec34
Show file tree
Hide file tree
Showing 2 changed files with 127 additions and 11 deletions.
24 changes: 15 additions & 9 deletions src/pg/pg-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,10 @@ export class PgStore extends BasePgStore {
}
}
}
await this.normalizeInscriptionLocations({
inscription_id: Array.from(updatedInscriptionIds),
});
});
await this.normalizeInscriptionLocations({ inscription_id: Array.from(updatedInscriptionIds) });
await this.refreshMaterializedView('chain_tip');
await this.refreshMaterializedView('inscription_count');
await this.refreshMaterializedView('mime_type_counts');
Expand Down Expand Up @@ -796,23 +798,27 @@ export class PgStore extends BasePgStore {
`;

// Is this a BRC-20 balance transfer? Check if we have a valid transfer inscription emitted by
// this address that hasn't been sent to another address before.
// this address that hasn't been sent to another address before. Use `LIMIT 3` as a quick way
// of checking if we have just inserted the first transfer for this inscription (genesis +
// transfer).
const brc20Transfer = await sql<DbBrc20Transfer[]>`
SELECT ${sql(BRC20_TRANSFERS_COLUMNS.map(c => `t.${c}`))}
FROM locations AS l
INNER JOIN brc20_transfers AS t ON t.inscription_id = l.inscription_id
WHERE
l.inscription_id = ${inscription_id}
AND l.address = ${args.location.address}
AND l.genesis = TRUE
AND l.current = TRUE
LIMIT 1
WHERE l.inscription_id = ${inscription_id}
LIMIT 3
`;
if (brc20Transfer.count > 0) {
if (brc20Transfer.count === 2) {
// This is the first time this BRC-20 transfer is being used. Apply the balance change.
await this.applyBrc20BalanceTransfer({
transfer: brc20Transfer[0],
location: args.location,
});
} else {
logger.debug(
{ genesis_id: args.location.genesis_id, block_height: args.location.block_height },
`PgStore [BRC-20] ignoring balance change for transfer that was already used`
);
}
});
return inscription_id;
Expand Down
114 changes: 112 additions & 2 deletions tests/brc20.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1347,13 +1347,99 @@ describe('BRC-20', () => {
)
.build()
);
await db.updateInscriptions(
new TestChainhookPayloadBuilder()
.apply()
.block({
height: 775620,
hash: '00000000000000000003feae13d107f0f2c4fb4dd08fb2a8b1ab553512e77f03',
})
.transaction({
hash: '7edaa48337a94da327b6262830505f116775a32db5ad4ad46e87ecea33f21bac',
})
.inscriptionTransferred({
inscription_number: 7,
inscription_id: 'eee52b22397ea4a4aefe6a39931315e93a157091f5a994216c0aa9c8c6fef47ai0',
ordinal_number: 0,
updated_address: address2,
satpoint_pre_transfer:
'eee52b22397ea4a4aefe6a39931315e93a157091f5a994216c0aa9c8c6fef47a:0:0',
satpoint_post_transfer:
'7edaa48337a94da327b6262830505f116775a32db5ad4ad46e87ecea33f21bac:0:0',
post_transfer_output_value: null,
})
.build()
);

const response1 = await fastify.inject({
method: 'GET',
url: `/ordinals/brc-20/balances?address=${address}`,
});
expect(response1.statusCode).toBe(200);
const json1 = response1.json();
expect(json1.total).toBe(1);
expect(json1.results).toStrictEqual([
{
available_balance: '1000',
overall_balance: '1000',
ticker: 'PEPE',
transferrable_balance: '0',
},
]);

const response2 = await fastify.inject({
method: 'GET',
url: `/ordinals/brc-20/balances?address=${address2}`,
});
expect(response2.statusCode).toBe(200);
const json2 = response2.json();
expect(json2.total).toBe(1);
expect(json2.results).toStrictEqual([
{
available_balance: '9000',
overall_balance: '9000',
ticker: 'PEPE',
transferrable_balance: '0',
},
]);
});

test('cannot spend valid transfer twice', async () => {
const address = 'bc1p3cyx5e2hgh53w7kpxcvm8s4kkega9gv5wfw7c4qxsvxl0u8x834qf0u2td';
const address2 = '3QNjwPDRafjBm9XxJpshgk3ksMJh3TFxTU';
await deployAndMintPEPE(address);
await db.updateInscriptions(
new TestChainhookPayloadBuilder()
.apply()
.block({
height: 775619,
hash: '00000000000000000002b14f0c5dde0b2fc74d022e860696bd64f1f652756674',
})
.transaction({
hash: 'eee52b22397ea4a4aefe6a39931315e93a157091f5a994216c0aa9c8c6fef47a',
})
.inscriptionRevealed(
brc20Reveal({
json: {
p: 'brc-20',
op: 'transfer',
tick: 'PEPE',
amt: '9000',
},
number: 7,
tx_id: 'eee52b22397ea4a4aefe6a39931315e93a157091f5a994216c0aa9c8c6fef47a',
address: address,
})
)
.build()
);
await db.updateInscriptions(
new TestChainhookPayloadBuilder()
.apply()
.block({
height: 775620,
hash: '000000000000000000016ddf56d0fe72476165acee9500d48d3e2aaf8412f489',
})
.transaction({
hash: '7edaa48337a94da327b6262830505f116775a32db5ad4ad46e87ecea33f21bac',
})
Expand All @@ -1370,7 +1456,33 @@ describe('BRC-20', () => {
})
.build()
);
// Attempt to transfer the same inscription back to the original address to change its
// balance.
await db.updateInscriptions(
new TestChainhookPayloadBuilder()
.apply()
.block({
height: 775621,
hash: '00000000000000000003feae13d107f0f2c4fb4dd08fb2a8b1ab553512e77f03',
})
.transaction({
hash: '55bec906eadc9f5c120cc39555ba46e85e562eacd6217e4dd0b8552783286d0e',
})
.inscriptionTransferred({
inscription_number: 7,
inscription_id: 'eee52b22397ea4a4aefe6a39931315e93a157091f5a994216c0aa9c8c6fef47ai0',
ordinal_number: 0,
updated_address: address,
satpoint_pre_transfer:
'7edaa48337a94da327b6262830505f116775a32db5ad4ad46e87ecea33f21bac:0:0',
satpoint_post_transfer:
'55bec906eadc9f5c120cc39555ba46e85e562eacd6217e4dd0b8552783286d0e:0:0',
post_transfer_output_value: null,
})
.build()
);

// Balances only reflect the first transfer.
const response1 = await fastify.inject({
method: 'GET',
url: `/ordinals/brc-20/balances?address=${address}`,
Expand Down Expand Up @@ -1403,7 +1515,5 @@ describe('BRC-20', () => {
},
]);
});

test.skip('cannot spend valid transfer twice', async () => {});
});
});

0 comments on commit 542ec34

Please sign in to comment.