Skip to content

Commit

Permalink
fix: /v2/addresses/{addr}/transactions incorrect when address only …
Browse files Browse the repository at this point in the history
…involved with token events (#2033)

* fix: `/v2/addresses/{addr}/transactions` incorrect when address only involved with token events

* docs: specify recommended alternative endpoints in deprecated `/extended/v1/address/*` endpoints
  • Loading branch information
zone117x authored Jul 18, 2024
1 parent 815c16f commit 1d9d0a6
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 9 deletions.
11 changes: 8 additions & 3 deletions docs/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1938,9 +1938,11 @@ paths:
get:
summary: Get account transactions
description: |
Retrieves a list of all Transactions for a given Address or Contract Identifier. More information on Transaction types can be found [here](https://docs.stacks.co/understand-stacks/transactions#types).
**NOTE:** This endpoint is deprecated in favor of [Get address transactions](/api/get-address-transactions).
If you need to actively monitor new transactions for an address or contract id, we highly recommend subscribing to [WebSockets or Socket.io](https://github.com/hirosystems/stacks-blockchain-api/tree/master/client) for real-time updates.
Retrieves a list of all Transactions for a given Address or Contract Identifier. More information on Transaction types can be found [here](https://docs.stacks.co/understand-stacks/transactions#types).
If you need to actively monitor new transactions for an address or contract id, we highly recommend subscribing to [WebSockets or Socket.io](https://github.com/hirosystems/stacks-blockchain-api/tree/master/client) for real-time updates.
deprecated: true
tags:
- Accounts
Expand Down Expand Up @@ -2002,7 +2004,10 @@ paths:
/extended/v1/address/{principal}/{tx_id}/with_transfers:
get:
summary: Get account transaction information for specific transaction
description: Retrieves transaction details for a given Transaction Id `tx_id`, for a given account or contract Identifier.
description: |
**NOTE:** This endpoint is deprecated in favor of [Get events for an address transaction](/api/get-address-transaction-events).
Retrieves transaction details for a given Transaction Id `tx_id`, for a given account or contract Identifier.
deprecated: true
tags:
- Accounts
Expand Down
9 changes: 6 additions & 3 deletions src/datastore/pg-store-v2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,6 @@ export class PgStoreV2 extends BasePgStoreModule {
args: AddressParams & TransactionPaginationQueryParams
): Promise<DbPaginatedResult<DbTxWithAddressTransfers>> {
return await this.sqlTransaction(async sql => {
await assertAddressExists(sql, args.address);
const limit = args.limit ?? TransactionLimitParamSchema.default;
const offset = args.offset ?? 0;

Expand Down Expand Up @@ -461,7 +460,12 @@ export class PgStoreV2 extends BasePgStoreModule {
SELECT COALESCE(SUM(amount), 0)
FROM stx_events
WHERE ${eventCond} AND sender = ${args.address}
) + txs.fee_rate AS stx_sent,
) +
CASE
WHEN (txs.sponsored = false AND txs.sender_address = ${args.address})
OR (txs.sponsored = true AND txs.sponsor_address = ${args.address})
THEN txs.fee_rate ELSE 0
END AS stx_sent,
(
SELECT COALESCE(SUM(amount), 0)
FROM stx_events
Expand Down Expand Up @@ -526,7 +530,6 @@ export class PgStoreV2 extends BasePgStoreModule {
args: AddressTransactionParams & TransactionPaginationQueryParams
): Promise<DbPaginatedResult<DbAddressTransactionEvent>> {
return await this.sqlTransaction(async sql => {
await assertAddressExists(sql, args.address);
await assertTxIdExists(sql, args.tx_id);
const limit = args.limit ?? TransactionLimitParamSchema.default;
const offset = args.offset ?? 0;
Expand Down
57 changes: 54 additions & 3 deletions src/tests/address-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ describe('address tests', () => {
const testAddr2 = 'ST1HB64MAJ1MBV4CQ80GF01DZS4T1DSMX20ADCRA4';
const testContractAddr = 'ST27W5M8BRKA7C5MZE2R1S1F4XTPHFWFRNHA9M04Y.hello-world';
const testAddr4 = 'ST3DWSXBPYDB484QXFTR81K4AWG4ZB5XZNFF3H70C';
const testAddr5 = 'ST29H5FH57AZVJSBWHCTJB5ATS2ZAH9SXN1XJDNK';
const testTxId = '0x03807fdb726b3cb843e0330c564a4974037be8f9ea58ec7f8ebe03c34b890009';

const block: DbBlock = {
Expand Down Expand Up @@ -208,6 +209,23 @@ describe('address tests', () => {
createStxTx(testContractAddr, testAddr4, 15, true, 1, 1, 0),
createStxTx(testAddr2, testAddr4, 35, true, 3, 1, 2),
];

const tx1 = txs[0];
const addr3FtEvent: DbFtEvent = {
canonical: true,
event_type: DbEventTypeId.FungibleTokenAsset,
asset_event_type_id: DbAssetEventTypeId.Transfer,
asset_identifier: 'usdc',
event_index: 1234,
tx_id: tx1[0].tx_id,
tx_index: tx1[0].tx_index,
block_height: tx1[0].block_height,
amount: BigInt(12345),
recipient: testAddr5,
sender: 'STEH21DTN67ECXDRXG858XHBZMEBEBFE2FV79DEF',
};
tx1[2].push(addr3FtEvent);

await db.update({
block: block,
microblocks: [],
Expand Down Expand Up @@ -536,7 +554,7 @@ describe('address tests', () => {
mint: 0,
burn: 0,
});
expect(v2Fetch1Json.results[4].stx_sent).toBe('1234');
expect(v2Fetch1Json.results[4].stx_sent).toBe('0');
expect(v2Fetch1Json.results[4].stx_received).toBe('0');
expect(v2Fetch1Json.results[4].events.stx).toStrictEqual({
transfer: 0,
Expand All @@ -553,7 +571,7 @@ describe('address tests', () => {
mint: 0,
burn: 0,
});
expect(v2Fetch1Json.results[5].stx_sent).toBe('1234');
expect(v2Fetch1Json.results[5].stx_sent).toBe('0');
expect(v2Fetch1Json.results[5].stx_received).toBe('0');
expect(v2Fetch1Json.results[5].events.stx).toStrictEqual({
transfer: 0,
Expand All @@ -570,7 +588,7 @@ describe('address tests', () => {
mint: 0,
burn: 0,
});
expect(v2Fetch1Json.results[6].stx_sent).toBe('1234');
expect(v2Fetch1Json.results[6].stx_sent).toBe('0');
expect(v2Fetch1Json.results[6].stx_received).toBe('0');
expect(v2Fetch1Json.results[6].events.stx).toStrictEqual({
transfer: 1,
Expand Down Expand Up @@ -682,6 +700,39 @@ describe('address tests', () => {
total: 6,
});

// test address that only received ft balance from an ft event
const v2Fetch4 = await supertest(api.server).get(
`/extended/v2/addresses/${testAddr5}/transactions`
);
expect(v2Fetch4.status).toBe(200);
expect(v2Fetch4.type).toBe('application/json');
expect(v2Fetch4.body.total).toBe(1);
expect(v2Fetch4.body.results[0].events.ft).toStrictEqual({
transfer: 1,
mint: 0,
burn: 0,
});
expect(v2Fetch4.body.results[0].stx_sent).toBe('0');
expect(v2Fetch4.body.results[0].stx_received).toBe('0');

const v2Fetch4Events = await supertest(api.server).get(
`/extended/v2/addresses/${testAddr5}/transactions/${addr3FtEvent.tx_id}/events`
);
expect(v2Fetch4Events.status).toBe(200);
expect(v2Fetch4Events.type).toBe('application/json');
expect(v2Fetch4Events.body.total).toBe(1);
expect(v2Fetch4Events.body.results[0]).toStrictEqual({
type: 'ft',
event_index: addr3FtEvent.event_index,
data: {
type: 'transfer',
amount: addr3FtEvent.amount.toString(),
asset_identifier: addr3FtEvent.asset_identifier,
sender: addr3FtEvent.sender,
recipient: addr3FtEvent.recipient,
},
});

// testing single txs information based on given tx_id
const fetchSingleTxInformation = await supertest(api.server).get(
`/extended/v1/address/${testAddr4}/${testTxId}/with_transfers`
Expand Down

0 comments on commit 1d9d0a6

Please sign in to comment.