diff --git a/packages/api/README.md b/packages/api/README.md index 714924e8..5e956b8f 100644 --- a/packages/api/README.md +++ b/packages/api/README.md @@ -734,40 +734,15 @@ GET /identity/A1rgGVjRGuznRThdAA316VEEpKuVQ7mV8mBK1BFJvXnb/withdrawals?limit=5 }, resultSet: [ { - "timestamp": 1729096625509, - "sender": "A1rgGVjRGuznRThdAA316VEEpKuVQ7mV8mBK1BFJvXnb", - "id": "95eiiqMotMvH23f6cv3BPC4ykcHFWTy2g3baCTWZANAs", - "amount": 200000, - "status": 3 - }, - { - "timestamp": 1729096140465, - "sender": "A1rgGVjRGuznRThdAA316VEEpKuVQ7mV8mBK1BFJvXnb", - "id": "DJzb8nj7JTHwnvAGEGhyFc5hHLFa5Es9WFAyS4HhhNeF", - "amount": 200000, - "status": 3 - }, - { - "timestamp": 1729096636318, + "document": "95eiiqMotMvH23f6cv3BPC4ykcHFWTy2g3baCTWZANAs", "sender": "A1rgGVjRGuznRThdAA316VEEpKuVQ7mV8mBK1BFJvXnb", - "id": "E4gbWCQgqrz9DVrzCeDKhr4PVsfp6CeL5DUAYndRVWdk", + "status": "COMPLETE", "amount": 200000, - "status": 3 - }, - { - "timestamp": 1729096795042, - "sender": "A1rgGVjRGuznRThdAA316VEEpKuVQ7mV8mBK1BFJvXnb", - "id": "FouX2qY8Eaxj5rSBrH9uxbhAM16ozrUP4sJwdo9pL7Cr", - "amount": 200000, - "status": 3 + "timestamp": 1729096625509, + "withdrawalAddress": "yeRZBWYfeNE4yVUHV4ZLs83Ppn9aMRH57A", + "hash": "113F86F4D1F48159B0D6690F3C5F8F33E39243086C041CF016454A66AD63F025" }, - { - "timestamp": 1729097247874, - "sender": "A1rgGVjRGuznRThdAA316VEEpKuVQ7mV8mBK1BFJvXnb", - "id": "9VEpb2aJRnCxfi3LjFXWa1zshkBPfzzHHh5yqEkgqw1t", - "amount": 200000, - "status": 3 - } + ... ] } ``` diff --git a/packages/api/src/controllers/IdentitiesController.js b/packages/api/src/controllers/IdentitiesController.js index 1468e8fb..e9529c84 100644 --- a/packages/api/src/controllers/IdentitiesController.js +++ b/packages/api/src/controllers/IdentitiesController.js @@ -2,11 +2,13 @@ const IdentitiesDAO = require('../dao/IdentitiesDAO') const { WITHDRAWAL_CONTRACT_TYPE } = require('../constants') const WithdrawalsContract = require('../../data_contracts/withdrawals.json') const PaginatedResultSet = require('../models/PaginatedResultSet') +const { decodeStateTransition } = require('../utils') class IdentitiesController { - constructor (knex, dapi) { + constructor (client, knex, dapi) { this.identitiesDAO = new IdentitiesDAO(knex, dapi) this.dapi = dapi + this.client = client } getIdentityByIdentifier = async (request, response) => { @@ -83,17 +85,31 @@ class IdentitiesController { const documents = await this.dapi.getDocuments(WITHDRAWAL_CONTRACT_TYPE, WithdrawalsContract, identifier, limit) + if (documents.length === 0) { + return response.send(new PaginatedResultSet([], null, null, null)) + } + const timestamps = documents.map(document => new Date(document.timestamp).toISOString()) - const txHashes = await this.identitiesDAO.getIdentityWithdrawalsByTimestamps(identifier, timestamps) + const withdrawals = await this.identitiesDAO.getIdentityWithdrawalsByTimestamps(identifier, timestamps) - if (documents.length === 0) { - return response.status(404).send({ message: 'not found' }) - } + const decodedTx = await Promise.all(withdrawals.map(async withdrawal => ({ + ...await decodeStateTransition(this.client, withdrawal.data), + timestamp: withdrawal.timestamp + }))) const resultSet = documents.map(document => ({ - ...document, - hash: txHashes.find( + document: document.id ?? null, + sender: document.sender ?? null, + status: document.status ?? null, + timestamp: document.timestamp ?? null, + amount: document.amount ?? null, + withdrawalAddress: + decodedTx.find( + tx => tx.timestamp.getTime() === document.timestamp + )?.outputAddress ?? null, + + hash: withdrawals.find( hash => new Date(hash.timestamp).toISOString() === new Date(document.timestamp).toISOString())?.hash ?? null })) diff --git a/packages/api/src/dao/IdentitiesDAO.js b/packages/api/src/dao/IdentitiesDAO.js index fd302847..96e1d512 100644 --- a/packages/api/src/dao/IdentitiesDAO.js +++ b/packages/api/src/dao/IdentitiesDAO.js @@ -357,7 +357,7 @@ module.exports = class IdentitiesDAO { getIdentityWithdrawalsByTimestamps = async (identifier, timestamps = []) => { return this.knex('state_transitions') - .select('state_transitions.hash', 'blocks.timestamp as timestamp') + .select('state_transitions.hash', 'blocks.timestamp as timestamp', 'state_transitions.data as data') .whereIn( 'blocks.timestamp', timestamps diff --git a/packages/api/src/server.js b/packages/api/src/server.js index 691efa8d..dd949976 100644 --- a/packages/api/src/server.js +++ b/packages/api/src/server.js @@ -82,7 +82,7 @@ module.exports = { const transactionsController = new TransactionsController(client, knex, dapi) const dataContractsController = new DataContractsController(knex) const documentsController = new DocumentsController(knex) - const identitiesController = new IdentitiesController(knex, dapi) + const identitiesController = new IdentitiesController(client, knex, dapi) const validatorsController = new ValidatorsController(knex, dapi) const rateController = new RateController() diff --git a/packages/api/src/utils.js b/packages/api/src/utils.js index 208fed3c..d8e98a58 100644 --- a/packages/api/src/utils.js +++ b/packages/api/src/utils.js @@ -246,12 +246,16 @@ const decodeStateTransition = async (client, base64) => { break } case StateTransitionEnum.IDENTITY_CREDIT_WITHDRAWAL: { - decoded.outputAddress = dashcorelib.Script(stateTransition.getOutputScript()).toAddress(NETWORK).toString() - decoded.userFeeIncrease = stateTransition.getUserFeeIncrease() + decoded.outputAddress = stateTransition.getOutputScript() + ? dashcorelib + .Script(stateTransition.getOutputScript()) + .toAddress(NETWORK) + .toString() + : null + decoded.userFeeIncrease = stateTransition.getUserFeeIncrease() decoded.identityContractNonce = Number(stateTransition.getIdentityContractNonce()) decoded.identityNonce = parseInt(stateTransition.getNonce()) - decoded.senderId = stateTransition.getIdentityId().toString() decoded.amount = parseInt(stateTransition.getAmount()) decoded.outputScript = stateTransition.getOutputScript()?.toString('hex') ?? null diff --git a/packages/api/test/integration/identities.spec.js b/packages/api/test/integration/identities.spec.js index 1fe8e435..a452b86b 100644 --- a/packages/api/test/integration/identities.spec.js +++ b/packages/api/test/integration/identities.spec.js @@ -253,7 +253,8 @@ describe('Identities routes', () => { const transaction = await fixtures.transaction(knex, { block_hash: block.hash, type: StateTransitionEnum.IDENTITY_CREDIT_WITHDRAWAL, - owner: identity.owner + owner: identity.owner, + data: 'BQFh0z9HiTN5e+TeiDU8fC2EPCExD20A9u/zFCSnVu59+/0AAAB0alKIAAEAAAEAAUEf89R9GPHIX5QLD/HKJ1xjd86KrnTsfAOxPMxBNDO8cJkAT5yUhcl/sGbQYoHSuNVIZcVVTVnSsYMXIyimihp3Vw==' }) transactions.push({ transaction, block }) @@ -274,14 +275,23 @@ describe('Identities routes', () => { .expect(200) .expect('Content-Type', 'application/json; charset=utf-8') - assert.deepEqual(body.resultSet, withdrawals.map(withdrawal => ({ ...withdrawal, hash: withdrawal.id }))) + assert.deepEqual(body.resultSet, withdrawals.map(withdrawal => ({ + hash: withdrawal.id, + document: withdrawal.id, + sender: withdrawal.sender, + status: withdrawal.status, + timestamp: withdrawal.timestamp, + amount: withdrawal.amount, + withdrawalAddress: null + }))) }) it('should return 404 whe identity not exist', async () => { mock.method(DAPI.prototype, 'getDocuments', async () => []) - await client.get('/identity/1234123123PFdomuTVvNy3VRrvWgvkKPzqehEBpNf2nk6/withdrawals') - .expect(404) + const { body } = await client.get('/identity/1234123123PFdomuTVvNy3VRrvWgvkKPzqehEBpNf2nk6/withdrawals') .expect('Content-Type', 'application/json; charset=utf-8') + + assert.deepEqual(body.resultSet, []) }) }) diff --git a/packages/frontend/src/app/api/content.md b/packages/frontend/src/app/api/content.md index 02526c39..c0732996 100644 --- a/packages/frontend/src/app/api/content.md +++ b/packages/frontend/src/app/api/content.md @@ -701,40 +701,15 @@ GET /identity/A1rgGVjRGuznRThdAA316VEEpKuVQ7mV8mBK1BFJvXnb/withdrawals?limit=5 }, resultSet: [ { - "timestamp": 1729096625509, - "sender": "A1rgGVjRGuznRThdAA316VEEpKuVQ7mV8mBK1BFJvXnb", - "id": "95eiiqMotMvH23f6cv3BPC4ykcHFWTy2g3baCTWZANAs", - "amount": 200000, - "status": 3 - }, - { - "timestamp": 1729096140465, - "sender": "A1rgGVjRGuznRThdAA316VEEpKuVQ7mV8mBK1BFJvXnb", - "id": "DJzb8nj7JTHwnvAGEGhyFc5hHLFa5Es9WFAyS4HhhNeF", - "amount": 200000, - "status": 3 - }, - { - "timestamp": 1729096636318, + "document": "95eiiqMotMvH23f6cv3BPC4ykcHFWTy2g3baCTWZANAs", "sender": "A1rgGVjRGuznRThdAA316VEEpKuVQ7mV8mBK1BFJvXnb", - "id": "E4gbWCQgqrz9DVrzCeDKhr4PVsfp6CeL5DUAYndRVWdk", + "status": "COMPLETE", "amount": 200000, - "status": 3 - }, - { - "timestamp": 1729096795042, - "sender": "A1rgGVjRGuznRThdAA316VEEpKuVQ7mV8mBK1BFJvXnb", - "id": "FouX2qY8Eaxj5rSBrH9uxbhAM16ozrUP4sJwdo9pL7Cr", - "amount": 200000, - "status": 3 + "timestamp": 1729096625509, + "withdrawalAddress": "yeRZBWYfeNE4yVUHV4ZLs83Ppn9aMRH57A", + "hash": "113F86F4D1F48159B0D6690F3C5F8F33E39243086C041CF016454A66AD63F025" }, - { - "timestamp": 1729097247874, - "sender": "A1rgGVjRGuznRThdAA316VEEpKuVQ7mV8mBK1BFJvXnb", - "id": "9VEpb2aJRnCxfi3LjFXWa1zshkBPfzzHHh5yqEkgqw1t", - "amount": 200000, - "status": 3 - } + ... ] } ```