diff --git a/prisma/migrations/20250922/01_dag_spend_txs_in_actions_view.sql b/prisma/migrations/20250922/01_dag_spend_txs_in_actions_view.sql index 2a79638..d7cb31b 100644 --- a/prisma/migrations/20250922/01_dag_spend_txs_in_actions_view.sql +++ b/prisma/migrations/20250922/01_dag_spend_txs_in_actions_view.sql @@ -14,7 +14,7 @@ UNION ALL 'SpendTransaction', dst.snapshot_hash, gs.ordinal, dst.destination_addr, null, dst.allow_spend_ref, null, currency_id FROM dag_spend_transactions dst - JOIN global_snapshots gs ON dst.snapshot_hash = gs.hash + JOIN global_snapshots gs ON dst.snapshot_hash = gs.hash and currency_id is null UNION ALL SELECT @@ -74,15 +74,12 @@ JOIN global_snapshots gs ON ms.global_snapshot_hash = gs.hash UNION ALL SELECT - mst.metagraph_id, mst.hash, mst.source_addr, mst.amount, mst.created_at, mst.updated_at, - 'SpendTransaction', mst.snapshot_hash as metagraph_snapshot_hash, ms.ordinal as metagraph_snapshot_ordinal, - mst.destination_addr, NULL, mst.allow_spend_ref, NULL, currency_id, - gs.hash AS global_snapshot_hash, gs.ordinal AS global_snapshot_ordinal -FROM metagraph_spend_transactions mst -JOIN metagraph_snapshots ms - ON mst.metagraph_id = ms.metagraph_id AND mst.snapshot_hash = ms.hash AND mst.currency_id is not null -JOIN global_snapshots gs - ON ms.global_snapshot_hash = gs.hash + currency_id, dst.hash, dst.source_addr, dst.amount, dst.created_at, dst.updated_at, + 'SpendTransaction', null, null, + dst.destination_addr, null, dst.allow_spend_ref, null, + currency_id, dst.snapshot_hash, gs.ordinal + FROM dag_spend_transactions dst + JOIN global_snapshots gs ON dst.snapshot_hash = gs.hash and currency_id is not null UNION ALL SELECT mest.metagraph_id, mest.hash, mest.source_addr, mest.amount, mest.created_at, mest.updated_at, diff --git a/prisma/schema.prisma b/prisma/schema.prisma index d2f06f1..6aca504 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -51,8 +51,8 @@ model metagraph_actions_view { created_at DateTime @default(now()) @db.Timestamp(6) updated_at DateTime @default(now()) @db.Timestamp(6) transaction_type String - metagraph_snapshot_hash String @db.VarChar - metagraph_snapshot_ordinal BigInt + metagraph_snapshot_hash String? @db.VarChar + metagraph_snapshot_ordinal BigInt? global_snapshot_hash String @db.VarChar global_snapshot_ordinal BigInt destination_addr String? @db.VarChar @@ -68,7 +68,7 @@ model metagraph_actions_view { metagraph_spend_transaction metagraph_spend_transactions? @relation(fields: [hash], references: [hash], map: "metagraph_spend_transaction_ref") metagraph_expired_spend_transaction metagraph_expired_spend_transactions? @relation(fields: [hash], references: [hash], map: "metagraph_expired_spend_transaction_ref") metagraph_fee_transaction metagraph_fee_transactions? @relation(fields: [hash], references: [hash], map: "metagraph_fee_transaction_ref") - metagraph_snapshot metagraph_snapshots @relation(fields: [metagraph_snapshot_hash], references: [hash], onDelete: Cascade, onUpdate: Restrict, map: "metagraph_actions_view_metagraph_snapshot_ref") + } model addresses { @@ -437,7 +437,6 @@ model metagraph_snapshots { metagraph_token_lock_blocks metagraph_token_lock_blocks[] metagraph_spend_transactions metagraph_spend_transactions[] metagraph_expired_spend_transactions metagraph_expired_spend_transactions[] - metagraph_actions_view metagraph_actions_view[] @@id([metagraph_id, hash], map: "metagraph_snapshot_pk") @@unique([metagraph_id, ordinal], map: "metagraph_snapshot_unique") diff --git a/prisma/seed.ts b/prisma/seed.ts index 7cf4950..fc2f12c 100644 --- a/prisma/seed.ts +++ b/prisma/seed.ts @@ -317,7 +317,7 @@ export const data_dag_allow_spends = [ }, { hash: "allowSpendHash5", - currency_id: "currency-2", + currency_id: data_metagraphs[0].id, source_addr: data_addresses[1].address, destination_addr: data_addresses[2].address, amount: 3000n, @@ -333,8 +333,8 @@ export const data_dag_allow_spends = [ export const data_dag_spend_transactions = [ { - hash: "spendTxHash1", - currency_id: data_dag_allow_spends[0].currency_id, + hash: "spendTxHash1a", + currency_id: null, source_addr: data_addresses[0].address, destination_addr: data_addresses[1].address, amount: 1000n, @@ -344,16 +344,38 @@ export const data_dag_spend_transactions = [ updated_at: new Date("2024-01-05T10:00:00Z"), }, { - hash: "spendTxHash5", + hash: "spendTxHash1b", currency_id: data_dag_allow_spends[4].currency_id, source_addr: data_addresses[2].address, destination_addr: data_addresses[1].address, amount: 3000n, + allow_spend_ref: null, + snapshot_hash: data_global_snapshots[2].hash, + created_at: new Date("2024-01-05T10:00:00Z"), + updated_at: new Date("2024-01-05T10:00:00Z"), + }, + { + hash: "spendTxHash5a", + currency_id: null, + source_addr: data_addresses[0].address, + destination_addr: data_addresses[1].address, + amount: 1000n, allow_spend_ref: data_dag_allow_spends[4].hash, snapshot_hash: data_global_snapshots[2].hash, created_at: new Date("2024-01-05T10:00:00Z"), updated_at: new Date("2024-01-05T10:00:00Z"), }, + { + hash: "spendTxHash5b", + currency_id: data_dag_allow_spends[4].currency_id, + source_addr: data_addresses[2].address, + destination_addr: data_addresses[0].address, + amount: 3000n, + allow_spend_ref: null, + snapshot_hash: data_global_snapshots[2].hash, + created_at: new Date("2024-01-05T10:00:00Z"), + updated_at: new Date("2024-01-05T10:00:00Z"), + }, ]; export const data_dag_expired_spend_transactions = [ @@ -701,7 +723,6 @@ export async function seed() { "DROP TABLE delegate_stake_total_rewards_view" ); await prisma.$executeRawUnsafe("DROP TABLE token_lock_total_rewards_view"); - // runSqlFromFile("./migrations/20250609/02_add_staking_to_actions.sql"); // ????????????????? runSqlFromFile("./migrations/20250606/01_total_rewards_view.sql"); runSqlFromFile("./migrations/20250922/01_dag_spend_txs_in_actions_view.sql"); } diff --git a/routes/allow-spends.yml b/routes/allow-spends.yml index d314b30..94663d2 100644 --- a/routes/allow-spends.yml +++ b/routes/allow-spends.yml @@ -111,7 +111,7 @@ ccyAddressAllowSpends: method: GET ccySnapshotSpendTransactions: - handler: src/handlers/allowSpendsHandler.currencySnapshotSpendTransactions + handler: src/handlers/allowSpendsHandler.currencySnapshotUnconfirmedSpendTransactions events: - httpApi: path: /currency/{metagraph_id}/snapshots/{hash_or_ordinal}/spend-transactions @@ -125,7 +125,7 @@ ccySpendTransactions: method: GET ccySpendTransaction: - handler: src/handlers/allowSpendsHandler.currencySpendTransaction + handler: src/handlers/allowSpendsHandler.currencyUnconfirmedSpendTransaction events: - httpApi: path: /currency/{metagraph_id}/spend-transactions/{hash} diff --git a/src/handlers/actionsHandler.ts b/src/handlers/actionsHandler.ts index 634e1e6..342f0e5 100644 --- a/src/handlers/actionsHandler.ts +++ b/src/handlers/actionsHandler.ts @@ -80,6 +80,10 @@ export const globalSnapshotActions = async ( const { term } = event.pathParameters || {}; const filter = extractHashOrdinal(term); + const dbFilter = filter.hash + ? { global_snapshot_hash: filter.hash } + : { global_snapshot_ordinal: filter.ordinal }; + const selectedTransactions = transactionFilter(event); return await paginatedQuery( @@ -88,7 +92,7 @@ export const globalSnapshotActions = async ( hashCursor, { where: { - global_snapshot: filter, + ...dbFilter, transaction_type: { in: selectedTransactions }, }, orderBy: [{ created_at: "desc" }, { hash: "desc" }], @@ -142,7 +146,7 @@ export const currencyActions = async ( hashCursor, { where: { - OR: [{ metagraph_id }, { currency_id: metagraph_id }], + metagraph_id, transaction_type: { in: selectedTransactions }, }, orderBy: [{ created_at: "desc" }, { hash: "desc" }], @@ -161,17 +165,19 @@ export const currencySnapshotActions = async ( try { const { metagraph_id, term } = event.pathParameters || {}; const filter = extractHashOrdinal(term); + const dbFilter = filter.hash + ? { metagraph_snapshot_hash: filter.hash } + : { metagraph_snapshot_ordinal: filter.ordinal }; const selectedTransactions = transactionFilter(event); - return await paginatedQuery( extractPagination(event), hashCursor, hashCursor, { where: { - OR: [{ metagraph_id }, { currency_id: metagraph_id }], - metagraph_snapshot: { ...filter }, + metagraph_id, + ...dbFilter, transaction_type: { in: selectedTransactions }, }, orderBy: [{ created_at: "desc" }, { hash: "desc" }], @@ -198,11 +204,9 @@ export const currencyAddressActions = async ( hashCursor, { where: { - AND: [ - { OR: [{ metagraph_id }, { currency_id: metagraph_id }] }, - { OR: [{ source_addr: address }, { destination_addr: address }] }, - { transaction_type: { in: selectedTransactions } }, - ], + metagraph_id, + OR: [{ source_addr: address }, { destination_addr: address }], + transaction_type: { in: selectedTransactions }, }, orderBy: [{ created_at: "desc" }, { hash: "desc" }], }, diff --git a/src/handlers/allowSpendsHandler.ts b/src/handlers/allowSpendsHandler.ts index cb3f216..dafd490 100644 --- a/src/handlers/allowSpendsHandler.ts +++ b/src/handlers/allowSpendsHandler.ts @@ -215,15 +215,13 @@ export const spendTransaction = async ( } }; -export const spendTransactions = async ( +const confirmedSpendTransactions = async ( + currency_id: string | null, + allow_spend_ref: string | undefined, event: APIGatewayProxyEvent ): Promise => { try { - const { allowSpendRef } = event.queryStringParameters || {}; - - const where = allowSpendRef - ? { allow_spend_ref: allowSpendRef } - : undefined; + const where = { currency_id, allow_spend_ref }; return await paginatedQuery( extractPagination(event), @@ -242,11 +240,19 @@ export const spendTransactions = async ( } }; -export const globalSnapshotSpendTransactions = async ( +export const spendTransactions = async ( + event: APIGatewayProxyEvent +): Promise => { + const { allowSpendRef } = event.queryStringParameters || {}; + return confirmedSpendTransactions(null, allowSpendRef, event); +}; + +const globalSnapshotConfirmedSpendTransactions = async ( + currency_id: string | null, + hash_or_ordinal: string | undefined, event: APIGatewayProxyEvent ): Promise => { try { - const { hash_or_ordinal } = event.pathParameters || {}; const filter = extractHashOrdinal(hash_or_ordinal); return await paginatedQuery( @@ -255,6 +261,7 @@ export const globalSnapshotSpendTransactions = async ( hashCursor, { where: { + currency_id, dag_allow_spend: { global_snapshot: filter }, }, include: dagInclude, @@ -268,18 +275,26 @@ export const globalSnapshotSpendTransactions = async ( } }; -export const addressSpendTransactions = async ( +export const globalSnapshotSpendTransactions = async ( event: APIGatewayProxyEvent ): Promise => { - try { - const { address } = event.pathParameters || {}; + const { hash_or_ordinal } = event.pathParameters || {}; + return globalSnapshotConfirmedSpendTransactions(null, hash_or_ordinal, event); +}; +const addressConfirmedSpendTransactions = async ( + currency_id: string | null, + address: string | undefined, + event: APIGatewayProxyEvent +): Promise => { + try { return await paginatedQuery( extractPagination(event), hashCursor, hashCursor, { where: { + currency_id, OR: [{ source_addr: address }, { destination_addr: address }], }, include: dagInclude, @@ -293,6 +308,13 @@ export const addressSpendTransactions = async ( } }; +export const addressSpendTransactions = async ( + event: APIGatewayProxyEvent +): Promise => { + const { address } = event.pathParameters || {}; + return addressConfirmedSpendTransactions(null, address, event); +}; + export const allowSpendExpirations = async ( event: APIGatewayProxyEvent ): Promise => { @@ -482,41 +504,22 @@ export const currencyAddressAllowSpends = async ( export const currencySpendTransactions = async ( event: APIGatewayProxyEvent ): Promise => { - try { - const { metagraph_id } = event.pathParameters || {}; + const metagraph_id = event.pathParameters?.metagraph_id || null; - const { allowSpendRef } = event.queryStringParameters || {}; + const { allowSpendRef } = event.queryStringParameters || {}; - const allowSpendWhere = allowSpendRef - ? { allow_spend_ref: allowSpendRef } - : undefined; - - return await paginatedQuery( - extractPagination(event), - hashCursor, - hashCursor, - { - where: { metagraph_id, ...allowSpendWhere, currency_id: { not: null } }, - include: metagraphInclude, - orderBy: [{ created_at: "desc" }, { hash: "asc" }], - }, - prisma.metagraph_spend_transactions.findMany, - spendTransactionResponses - ); - } catch (error) { - return handleError(error); - } + return confirmedSpendTransactions(metagraph_id, allowSpendRef, event); }; -export const currencySpendTransaction = async ( +export const currencyUnconfirmedSpendTransaction = async ( event: APIGatewayProxyEvent ): Promise => { try { - const { metagraph_id, hash } = event.pathParameters || {}; + const { metagraph_id: currency_id, hash } = event.pathParameters || {}; - const spend = await prisma.metagraph_spend_transactions.findUnique({ - where: { metagraph_id, hash, currency_id: { not: null } }, - include: metagraphInclude, + const spend = await prisma.dag_spend_transactions.findUnique({ + where: { currency_id, hash }, + include: dagInclude, }); return respond(spend, spendTransactionResponse); @@ -525,7 +528,8 @@ export const currencySpendTransaction = async ( } }; -export const currencySnapshotSpendTransactions = async ( +// returns all unconfirmed spend transactions for the metagraph contract +export const currencySnapshotUnconfirmedSpendTransactions = async ( event: APIGatewayProxyEvent ): Promise => { try { @@ -542,7 +546,6 @@ export const currencySnapshotSpendTransactions = async ( metagraph_allow_spend: { metagraph_snapshot: filter, }, - currency_id: { not: null }, }, include: metagraphInclude, orderBy: [{ created_at: "desc" }, { hash: "asc" }], @@ -558,27 +561,10 @@ export const currencySnapshotSpendTransactions = async ( export const currencyAddressSpendTransactions = async ( event: APIGatewayProxyEvent ): Promise => { - try { - const { address } = event.pathParameters || {}; + const metagraph_id = event.pathParameters?.metagraph_id || null; + const { address } = event.pathParameters || {}; - return await paginatedQuery( - extractPagination(event), - hashCursor, - hashCursor, - { - where: { - OR: [{ source_addr: address }, { destination_addr: address }], - currency_id: { not: null }, - }, - include: metagraphInclude, - orderBy: [{ created_at: "desc" }, { hash: "asc" }], - }, - prisma.metagraph_spend_transactions.findMany, - spendExpiredResponses - ); - } catch (error) { - return handleError(error); - } + return addressConfirmedSpendTransactions(metagraph_id, address, event); }; export const currencyAllowSpendExpirations = async ( diff --git a/tests/handlers/actionsHandler.test.ts b/tests/handlers/actionsHandler.test.ts index 91eb303..e40e57c 100644 --- a/tests/handlers/actionsHandler.test.ts +++ b/tests/handlers/actionsHandler.test.ts @@ -122,7 +122,7 @@ describe("actionsHandler", () => { expect(result.statusCode).toBe(200); const body = validatePaginatedResponse(result); - expect(body.data.length).toBe(11); + expect(body.data.length).toBe(12); body.data.forEach(validateAction); }); @@ -145,6 +145,7 @@ describe("actionsHandler", () => { expect(result.statusCode).toBe(200); const body = validatePaginatedResponse(result); + expect(body.data.length).toBe(13); body.data.forEach(validateAction); }); @@ -172,7 +173,7 @@ describe("actionsHandler", () => { expect(result.statusCode).toBe(200); const body = validatePaginatedResponse(result); - expect(body.data.length).toBe(4); + expect(body.data.length).toBe(3); body.data.forEach(validateAction); }); @@ -197,6 +198,7 @@ describe("actionsHandler", () => { expect(result.statusCode).toBe(200); const body = validatePaginatedResponse(result); + expect(body.data.length).toBe(9); body.data.forEach(validateAction); }); diff --git a/tests/handlers/allowSpendsHandler.test.ts b/tests/handlers/allowSpendsHandler.test.ts index 8bd904f..3a8a196 100644 --- a/tests/handlers/allowSpendsHandler.test.ts +++ b/tests/handlers/allowSpendsHandler.test.ts @@ -247,14 +247,14 @@ describe("AllowSpends Handler Integration Tests", () => { it("should return spend transaction for a allow spend ref", async () => { const event = createAPIGatewayEvent( {}, - { allowSpendRef: data_dag_spend_transactions[1].allow_spend_ref } + { allowSpendRef: data_dag_spend_transactions[2].allow_spend_ref } ); const response = await allowSpendsHandler.spendTransactions(event); expect(response.statusCode).toBe(200); const body = validatePaginatedResponse(response); expect(body.data.length).toBe(1); - expect(body.data[0].hash).toBe(data_dag_spend_transactions[1].hash); + expect(body.data[0].hash).toBe(data_dag_spend_transactions[2].hash); validateDagSpendTransaction(body.data[0]); }); @@ -360,7 +360,7 @@ describe("Metagraph AllowSpends Handler Integration Tests", () => { describe("currencySpendTransactions", () => { it("should return spend transactions", async () => { const event = createAPIGatewayEvent({ - metagraph_id: data_metagraphs[0].id, + metagraph_id: data_dag_allow_spends[4].currency_id, }); const response = await allowSpendsHandler.currencySpendTransactions( event @@ -369,13 +369,13 @@ describe("Metagraph AllowSpends Handler Integration Tests", () => { expect(response.statusCode).toBe(200); const body = validatePaginatedResponse(response); expect(body.data.length).toBe(2); - body.data.forEach(validateMgSpendTransaction); + body.data.forEach(validateDagSpendTransaction); }); it("should return spend transaction for a allow spend ref", async () => { const event = createAPIGatewayEvent( {}, - { allowSpendRef: data_metagraph_spend_transactions[1].allow_spend_ref } + { allowSpendRef: data_dag_spend_transactions[2].allow_spend_ref } ); const response = await allowSpendsHandler.currencySpendTransactions( event @@ -383,9 +383,10 @@ describe("Metagraph AllowSpends Handler Integration Tests", () => { expect(response.statusCode).toBe(200); const body = validatePaginatedResponse(response); + expect(body.data.length).toBe(1); - expect(body.data[0].hash).toBe(data_metagraph_spend_transactions[1].hash); - validateMgSpendTransaction(body.data[0]); + expect(body.data[0].hash).toBe(data_dag_spend_transactions[2].hash); + validateDagSpendTransaction(body.data[0]); }); it("should return empty for an invalid allow spend ref", async () => { @@ -470,7 +471,9 @@ describe("Metagraph AllowSpends Handler Integration Tests", () => { }); const response = - await allowSpendsHandler.currencySnapshotSpendTransactions(event); + await allowSpendsHandler.currencySnapshotUnconfirmedSpendTransactions( + event + ); expect(response.statusCode).toBe(200); const body = validatePaginatedResponse(response); expect(body.data.length).toBe(1); @@ -548,7 +551,7 @@ describe("Metagraph AllowSpends Handler Integration Tests", () => { describe("currencyAddressSpendTransactions", () => { it("should return spend transactions for an address", async () => { const event = createAPIGatewayEvent({ - metagraph_id: data_metagraphs[0].id, + metagraph_id: data_dag_spend_transactions[1].currency_id, address: data_addresses[1].address, });