diff --git a/packages/api/README.md b/packages/api/README.md index a6a57d1b7..ed05cc640 100644 --- a/packages/api/README.md +++ b/packages/api/README.md @@ -743,24 +743,76 @@ Return identity by given identifier GET /identity/GWRSAVFMjXx8HpQFaNJMqBV7MBgMK4br5UESsB4S31Ec { - identifier: "GWRSAVFMjXx8HpQFaNJMqBV7MBgMK4br5UESsB4S31Ec", - owner: "GWRSAVFMjXx8HpQFaNJMqBV7MBgMK4br5UESsB4S31Ec", - revision: 1, - balance: 1000000, - timestamp: "2024-03-18T10:13:54.150Z", - txHash: "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF", - totalTxs: 1, - totalTransfers: 0, - totalDocuments: 0, - totalDataContracts: 0, - isSystem: false, - aliases: [ - { - alias: "alias.dash", - status: "locked", - contested: true - } - ] + "identifier": "3igSMtXaaS9iRQHbWU1w4hHveKdxixwMpgmhLzjVhFZJ", + "revision": 0, + "balance": 49989647300, + "timestamp": "2024-10-12T18:51:44.592Z", + "txHash": "32FB988D87E4122A2FE030B5014A59A05786C1501FD97D765E2329F89A8AD01D", + "totalTxs": 13, + "totalTransfers": 7, + "totalDocuments": 5, + "totalDataContracts": 0, + "isSystem": false, + "aliases": [ + { + "alias": "owl352.dash", + "status": "ok", + "contested": false + } + ], + "totalGasSpent": 310352700, + "averageGasSpent": 23873285, + "topUpsGasSpent": 46350660, + "withdrawalsGasSpent": 0, + "lastWithdrawalHash": null, + "publicKeys": [ + { + "keyId": 0, + "type": 0, + "data": "0386067dea94b1cfb23bf252084a2020a4a6712df7e4ac16c211558a1dbb66904a", + "purpose": 0, + "securityLevel": 0, + "isReadOnly": false, + "isMaster": true, + "hash": "5501114f5842004d1ff6c7d04512c438afe0cb11", + "contractBounds": null + }, + { + "keyId": 1, + "type": 0, + "data": "038a09509830d2d04685294e920aa29c96d51f9bd81044e2f934a4c198b934b102", + "purpose": 0, + "securityLevel": 2, + "isReadOnly": false, + "isMaster": false, + "hash": "c563c11128b9e457ad3b7220315b4bf53c8af443", + "contractBounds": null + }, + { + "keyId": 2, + "type": 0, + "data": "027734bd9b8864964eb7504a77a986782e9d620e4c6d23e2bd80359e1e81790a1c", + "purpose": 0, + "securityLevel": 1, + "isReadOnly": false, + "isMaster": false, + "hash": "4bd1a43ea0cf7c18c1f90d1d9c0f08c63743ff1d", + "contractBounds": null + }, + { + "keyId": 3, + "type": 0, + "data": "03083620dea1216b47568aead0c7cb6302ae3ca8beaa40c51e25b20f1f02ae06d4", + "purpose": 3, + "securityLevel": 1, + "isReadOnly": false, + "isMaster": false, + "hash": "f6d941f2d7aa4bc9d90b90bc103bd583c5943af9", + "contractBounds": null + } + ], + "fundingCoreTx": "68d77e0d2da31e9cf2758d8f97547c1bc98b75c4e2cebe64dbcaae3bb5cb8a9c", + "owner": "3igSMtXaaS9iRQHbWU1w4hHveKdxixwMpgmhLzjVhFZJ" } ``` Response codes: diff --git a/packages/api/src/DAPI.js b/packages/api/src/DAPI.js index 04c9b2825..8649b4ad2 100644 --- a/packages/api/src/DAPI.js +++ b/packages/api/src/DAPI.js @@ -1,6 +1,8 @@ const Withdrawal = require('./models/Withdrawal') const { Identifier } = require('dash').PlatformProtocol +const { IdentityPublicKey } = require('@dashevo/wasm-dpp/dist/wasm/wasm_dpp') + class DAPI { dapi dpp @@ -76,6 +78,34 @@ class DAPI { ) return contestedResourceContenders } + + async getIdentityKeys (identifier, keysIds, limit) { + const { identityKeys } = await this.dapi.platform.getIdentityKeys(Identifier.from(identifier), keysIds, limit) + + return identityKeys.map(key => { + const serialized = IdentityPublicKey.fromBuffer(Buffer.from(key)) + + const { contractBounds } = IdentityPublicKey.fromBuffer(Buffer.from(key)).toObject() + + return { + keyId: serialized.getId(), + type: serialized.getType(), + data: Buffer.from(serialized.getData()).toString('hex'), + purpose: serialized.getPurpose(), + securityLevel: serialized.getSecurityLevel(), + isReadOnly: serialized.isReadOnly(), + isMaster: serialized.isMaster(), + hash: Buffer.from(serialized.hash()).toString('hex'), + contractBounds: contractBounds + ? { + type: contractBounds.type, + id: Identifier.from(Buffer.from(contractBounds.id)), + typeName: contractBounds.document_type_name + } + : null + } + }) + } } module.exports = DAPI diff --git a/packages/api/src/controllers/IdentitiesController.js b/packages/api/src/controllers/IdentitiesController.js index c5c872772..4644d2807 100644 --- a/packages/api/src/controllers/IdentitiesController.js +++ b/packages/api/src/controllers/IdentitiesController.js @@ -6,7 +6,7 @@ const { decodeStateTransition } = require('../utils') class IdentitiesController { constructor (client, knex, dapi) { - this.identitiesDAO = new IdentitiesDAO(knex, dapi) + this.identitiesDAO = new IdentitiesDAO(knex, dapi, client) this.dapi = dapi this.client = client } diff --git a/packages/api/src/dao/IdentitiesDAO.js b/packages/api/src/dao/IdentitiesDAO.js index c3064f4f3..09e350c81 100644 --- a/packages/api/src/dao/IdentitiesDAO.js +++ b/packages/api/src/dao/IdentitiesDAO.js @@ -4,13 +4,14 @@ const Transaction = require('../models/Transaction') const Document = require('../models/Document') const DataContract = require('../models/DataContract') const PaginatedResultSet = require('../models/PaginatedResultSet') -const { IDENTITY_CREDIT_WITHDRAWAL } = require('../enums/StateTransitionEnum') -const { getAliasInfo, getAliasStateByVote } = require('../utils') +const { IDENTITY_CREDIT_WITHDRAWAL, IDENTITY_TOP_UP } = require('../enums/StateTransitionEnum') +const { getAliasInfo, decodeStateTransition, getAliasStateByVote } = require('../utils') module.exports = class IdentitiesDAO { - constructor (knex, dapi) { + constructor (knex, dapi, client) { this.knex = knex this.dapi = dapi + this.client = client } getIdentityByIdentifier = async (identifier) => { @@ -52,19 +53,53 @@ module.exports = class IdentitiesDAO { .orWhere('recipient', identifier) .as('transfer_alias') - const rows = await this.knex.with('with_alias', lastRevisionIdentities) - .select('identifier', 'with_alias.owner as owner', 'revision', 'transfer_id', 'sender', - 'tx_hash', 'is_system', 'blocks.timestamp as timestamp', 'recipient', 'amount') - .leftJoin('state_transitions', 'state_transitions.hash', 'tx_hash') - .leftJoin('blocks', 'state_transitions.block_hash', 'blocks.hash') + const mainQuery = this.knex.with('with_alias', lastRevisionIdentities) + .select( + 'identifier', 'with_alias.owner as owner', 'revision', + 'transfer_id', 'sender', 'tx_hash', 'is_system', + 'blocks.timestamp as timestamp', 'recipient', 'amount', + 'state_transitions.data as tx_data' + ) .select(this.knex('state_transitions').count('*').where('owner', identifier).as('total_txs')) + .select(this.knex('state_transitions').sum('gas_used').where('owner', identifier).as('total_gas_spent')) .select(this.knex(documentsSubQuery).count('*').where('rank', 1).as('total_documents')) .select(this.knex(dataContractsSubQuery).count('*').where('rank', 1).as('total_data_contracts')) .select(this.knex(transfersSubquery).count('*').as('total_transfers')) .select(this.knex(aliasSubquery).select('aliases').limit(1).as('aliases')) + .leftJoin('state_transitions', 'state_transitions.hash', 'tx_hash') + .leftJoin('blocks', 'state_transitions.block_hash', 'blocks.hash') .from('with_alias') .limit(1) + const rows = await this.knex.with('with_alias', mainQuery) + .select( + 'identifier', 'owner', 'revision', + 'transfer_id', 'sender', 'tx_hash', + 'is_system', 'timestamp', 'recipient', + 'amount', 'total_txs', 'total_gas_spent', + 'total_documents', 'total_data_contracts', + 'total_transfers', 'aliases', 'tx_data', + this.knex.raw('ROUND(total_gas_spent/total_txs) as average_gas_spent') + ) + .select(this.knex('state_transitions') + .sum('gas_used') + .where('owner', identifier) + .andWhere('type', IDENTITY_TOP_UP) + .as('top_ups_gas_spent')) + .select(this.knex('state_transitions') + .sum('gas_used') + .where('owner', identifier) + .andWhere('type', IDENTITY_CREDIT_WITHDRAWAL) + .as('withdrawals_gas_spent')) + .select(this.knex('state_transitions') + .select('hash') + .where('owner', identifier) + .andWhere('type', IDENTITY_CREDIT_WITHDRAWAL) + .orderBy('id', 'desc') + .limit(1) + .as('last_withdrawal_hash')) + .from('with_alias') + if (!rows.length) { return null } @@ -83,11 +118,23 @@ module.exports = class IdentitiesDAO { return getAliasStateByVote(aliasInfo, alias, identifier) })) - return { + const publicKeys = await this.dapi.getIdentityKeys(identity.identifier) + + let fundingCoreTx = null + + if (row.tx_data) { + const { assetLockProof } = await decodeStateTransition(this.client, row.tx_data) + + fundingCoreTx = assetLockProof?.txid + } + + return Identity.fromObject({ ...identity, aliases, - balance: await this.dapi.getIdentityBalance(identity.identifier.trim()) - } + balance: await this.dapi.getIdentityBalance(identity.identifier), + publicKeys, + fundingCoreTx + }) } getIdentitiesByDPNSName = async (dpns) => { diff --git a/packages/api/src/models/Identity.js b/packages/api/src/models/Identity.js index dc6363ff2..2e3f1901e 100644 --- a/packages/api/src/models/Identity.js +++ b/packages/api/src/models/Identity.js @@ -10,8 +10,23 @@ module.exports = class Identity { totalDataContracts isSystem aliases + totalGasSpent + averageGasSpent + topUpsGasSpent + withdrawalsGasSpent + lastWithdrawalHash + publicKeys + fundingCoreTx - constructor (identifier, owner, revision, balance, timestamp, totalTxs, totalDataContracts, totalDocuments, totalTransfers, txHash, isSystem, aliases) { + constructor ( + identifier, owner, revision, + balance, timestamp, totalTxs, + totalDataContracts, totalDocuments, + totalTransfers, txHash, isSystem, + aliases, totalGasSpent, averageGasSpent, + topUpsGasSpent, withdrawalsGasSpent, + lastWithdrawalHash, publicKeys, fundingCoreTx + ) { this.identifier = identifier ? identifier.trim() : null this.owner = owner ? owner.trim() : null this.revision = revision ?? null @@ -24,14 +39,75 @@ module.exports = class Identity { this.txHash = txHash ?? null this.isSystem = isSystem ?? null this.aliases = aliases ?? [] + this.totalGasSpent = totalGasSpent ?? null + this.averageGasSpent = averageGasSpent ?? null + this.topUpsGasSpent = topUpsGasSpent ?? null + this.withdrawalsGasSpent = withdrawalsGasSpent ?? null + this.lastWithdrawalHash = lastWithdrawalHash ?? null + this.publicKeys = publicKeys ?? [] + this.fundingCoreTx = fundingCoreTx ?? null } - // eslint-disable-next-line camelcase - static fromRow ({ identifier, owner, revision, balance, timestamp, total_txs, total_data_contracts, total_documents, total_transfers, tx_hash, is_system, aliases }) { - return new Identity(identifier?.trim(), owner, revision, Number(balance), timestamp, Number(total_txs), Number(total_data_contracts), Number(total_documents), Number(total_transfers), tx_hash, is_system, aliases) + static fromObject ({ + identifier, owner, revision, + balance, timestamp, totalTxs, + totalDataContracts, totalDocuments, + totalTransfers, txHash, isSystem, + aliases, totalGasSpent, averageGasSpent, + topUpsGasSpent, withdrawalsGasSpent, + lastWithdrawalHash, publicKeys, fundingCoreTx + }) { + return new Identity( + identifier, + owner, + revision, + balance, + timestamp, + totalTxs, + totalDataContracts, + totalDocuments, + totalTransfers, + txHash, + isSystem, + aliases, + totalGasSpent, + averageGasSpent, + topUpsGasSpent, + withdrawalsGasSpent, + lastWithdrawalHash, + publicKeys, + fundingCoreTx + ) } - static fromObject ({ identifier, owner, revision, balance, timestamp, totalTxs, totalDataContracts, totalDocuments, totalTransfers, txHash, isSystem, aliases }) { - return new Identity(identifier, owner, revision, balance, timestamp, totalTxs, totalDataContracts, totalDocuments, totalTransfers, txHash, isSystem, aliases) + /* eslint-disable camelcase */ + static fromRow ({ + identifier, owner, revision, + balance, timestamp, total_txs, + total_data_contracts, total_documents, + total_transfers, tx_hash, is_system, + aliases, total_gas_spent, average_gas_spent, + top_ups_gas_spent, withdrawals_gas_spent, + last_withdrawal_hash + }) { + return new Identity( + identifier?.trim(), + owner, + revision, + Number(balance), + timestamp, + Number(total_txs), + Number(total_data_contracts), + Number(total_documents), + Number(total_transfers), + tx_hash, + is_system, + aliases, + Number(total_gas_spent), + Number(average_gas_spent), + Number(top_ups_gas_spent), + Number(withdrawals_gas_spent), + last_withdrawal_hash + ) } } diff --git a/packages/api/src/utils.js b/packages/api/src/utils.js index 3b5ff70c4..5e70bbc41 100644 --- a/packages/api/src/utils.js +++ b/packages/api/src/utils.js @@ -8,7 +8,7 @@ const { base58 } = require('@scure/base') const convertToHomographSafeChars = require('dash/build/utils/convertToHomographSafeChars').default const Intervals = require('./enums/IntervalsEnum') const dashcorelib = require('@dashevo/dashcore-lib') -const { InstantAssetLockProof, ChainAssetLockProof } = require('@dashevo/wasm-dpp') +const { InstantAssetLockProof, ChainAssetLockProof, Identifier } = require('@dashevo/wasm-dpp') const SecurityLevelEnum = require('./enums/SecurityLevelEnum') const KeyPurposeEnum = require('./enums/KeyPurposeEnum') const KeyTypeEnum = require('./enums/KeyTypeEnum') @@ -129,18 +129,28 @@ const decodeStateTransition = async (client, base64) => { decoded.identityId = stateTransition.getIdentityId().toString() decoded.signature = stateTransition.getSignature()?.toString('hex') ?? null decoded.raw = stateTransition.toBuffer().toString('hex') - // TODO: Add contract bounds - decoded.publicKeys = stateTransition.publicKeys.map(key => ({ - contractBounds: null, // key.toJSON().contractBounds, - id: key.getId(), - type: KeyTypeEnum[key.getType()], - data: Buffer.from(key.getData()).toString('hex'), - publicKeyHash: Buffer.from(key.hash()).toString('hex'), - purpose: KeyPurposeEnum[key.getPurpose()], - securityLevel: SecurityLevelEnum[key.getSecurityLevel()], - readOnly: key.isReadOnly(), - signature: Buffer.from(key.getSignature()).toString('hex') - })) + + decoded.publicKeys = stateTransition.publicKeys.map(key => { + const { contractBounds } = key.toObject() + + return { + contractBounds: contractBounds + ? { + type: contractBounds.type, + id: Identifier.from(Buffer.from(contractBounds.id)).toString(), + typeName: contractBounds.document_type_name + } + : null, + id: key.getId(), + type: KeyTypeEnum[key.getType()], + data: Buffer.from(key.getData()).toString('hex'), + publicKeyHash: Buffer.from(key.hash()).toString('hex'), + purpose: KeyPurposeEnum[key.getPurpose()], + securityLevel: SecurityLevelEnum[key.getSecurityLevel()], + readOnly: key.isReadOnly(), + signature: Buffer.from(key.getSignature()).toString('hex') + } + }) break } @@ -205,8 +215,38 @@ const decodeStateTransition = async (client, base64) => { decoded.revision = stateTransition.getRevision() // TODO: Add contract bounds decoded.publicKeysToAdd = stateTransition.getPublicKeysToAdd() - .map(key => ({ - contractBounds: null, // key.toJSON().contractBounds, + .map(key => { + const { contractBounds } = key.toObject() + + return { + contractBounds: contractBounds + ? { + type: contractBounds.type, + id: Identifier.from(Buffer.from(contractBounds.id)).toString(), + typeName: contractBounds.document_type_name + } + : null, + id: key.getId(), + type: KeyTypeEnum[key.getType()], + data: Buffer.from(key.getData()).toString('hex'), + publicKeyHash: Buffer.from(key.hash()).toString('hex'), + purpose: KeyPurposeEnum[key.getPurpose()], + securityLevel: SecurityLevelEnum[key.getSecurityLevel()], + readOnly: key.isReadOnly(), + signature: Buffer.from(key.getSignature()).toString('hex') + } + }) + decoded.setPublicKeyIdsToDisable = (stateTransition.getPublicKeyIdsToDisable() ?? []).map(key => { + const { contractBounds } = key.toObject() + + return { + contractBounds: contractBounds + ? { + type: contractBounds.type, + id: Identifier.from(Buffer.from(contractBounds.id)).toString(), + typeName: contractBounds.document_type_name + } + : null, id: key.getId(), type: KeyTypeEnum[key.getType()], data: Buffer.from(key.getData()).toString('hex'), @@ -215,18 +255,8 @@ const decodeStateTransition = async (client, base64) => { securityLevel: SecurityLevelEnum[key.getSecurityLevel()], readOnly: key.isReadOnly(), signature: Buffer.from(key.getSignature()).toString('hex') - })) - decoded.setPublicKeyIdsToDisable = (stateTransition.getPublicKeyIdsToDisable() ?? []).map(key => ({ - contractBounds: null, // key.toJSON().contractBounds, - id: key.getId(), - type: KeyTypeEnum[key.getType()], - data: Buffer.from(key.getData()).toString('hex'), - publicKeyHash: Buffer.from(key.hash()).toString('hex'), - purpose: KeyPurposeEnum[key.getPurpose()], - securityLevel: SecurityLevelEnum[key.getSecurityLevel()], - readOnly: key.isReadOnly(), - signature: Buffer.from(key.getSignature()).toString('hex') - })) + } + }) decoded.signature = stateTransition.getSignature().toString('hex') decoded.signaturePublicKeyId = stateTransition.toObject().signaturePublicKeyId decoded.raw = stateTransition.toBuffer().toString('hex') diff --git a/packages/api/test/integration/identities.spec.js b/packages/api/test/integration/identities.spec.js index 65e0d702a..ab717dea1 100644 --- a/packages/api/test/integration/identities.spec.js +++ b/packages/api/test/integration/identities.spec.js @@ -170,6 +170,8 @@ describe('Identities routes', () => { mock.method(DAPI.prototype, 'getContestedState', async () => null) + mock.method(DAPI.prototype, 'getIdentityKeys', async () => null) + mock.method(tenderdashRpc, 'getBlockByHeight', async () => ({ block: { header: { @@ -195,7 +197,18 @@ describe('Identities routes', () => { describe('getIdentityByIdentifier()', async () => { it('should return identity by identifier', async () => { const block = await fixtures.block(knex) - const identity = await fixtures.identity(knex, { block_hash: block.hash }) + const owner = await fixtures.identity(knex, { block_hash: block.hash }) + + const transaction = await fixtures.transaction(knex, { + block_hash: block.hash, + type: StateTransitionEnum.IDENTITY_CREATE, + owner: owner.identifier, + data: '' + }) + const identity = await fixtures.identity(knex, { + block_hash: block.hash, + state_transition_hash: transaction.hash + }) const { alias } = await fixtures.identity_alias(knex, { alias: 'test.dash', @@ -214,7 +227,7 @@ describe('Identities routes', () => { balance: 0, timestamp: block.timestamp.toISOString(), txHash: identity.txHash, - totalTxs: 1, + totalTxs: 0, totalTransfers: 0, totalDocuments: 0, totalDataContracts: 0, @@ -223,7 +236,14 @@ describe('Identities routes', () => { alias, contested: false, status: 'ok' - }] + }], + totalGasSpent: 0, + averageGasSpent: 0, + topUpsGasSpent: 0, + withdrawalsGasSpent: 0, + lastWithdrawalHash: null, + publicKeys: [], + fundingCoreTx: null } assert.deepEqual(body, expectedIdentity) @@ -384,7 +404,14 @@ describe('Identities routes', () => { isSystem: false, aliases: [ aliases.find((_alias) => _alias.identity_identifier === _identity.identity.identifier).alias - ].map(alias => ({ alias, status: 'ok', contested: false })) + ].map(alias => ({ alias, status: 'ok', contested: false })), + totalGasSpent: null, + averageGasSpent: null, + topUpsGasSpent: null, + withdrawalsGasSpent: null, + lastWithdrawalHash: null, + publicKeys: [], + fundingCoreTx: null })) assert.deepEqual(body.resultSet, expectedIdentities) @@ -426,7 +453,14 @@ describe('Identities routes', () => { isSystem: false, aliases: [ aliases.find((_alias) => _alias.identity_identifier === _identity.identity.identifier).alias - ].map(alias => ({ alias, status: 'ok', contested: false })) + ].map(alias => ({ alias, status: 'ok', contested: false })), + totalGasSpent: null, + averageGasSpent: null, + topUpsGasSpent: null, + withdrawalsGasSpent: null, + lastWithdrawalHash: null, + publicKeys: [], + fundingCoreTx: null })) assert.deepEqual(body.resultSet, expectedIdentities) @@ -469,7 +503,14 @@ describe('Identities routes', () => { isSystem: false, aliases: [ aliases.find((_alias) => _alias.identity_identifier === _identity.identity.identifier).alias - ].map(alias => ({ alias, status: 'ok', contested: false })) + ].map(alias => ({ alias, status: 'ok', contested: false })), + totalGasSpent: null, + averageGasSpent: null, + topUpsGasSpent: null, + withdrawalsGasSpent: null, + lastWithdrawalHash: null, + publicKeys: [], + fundingCoreTx: null })) assert.deepEqual(body.resultSet, expectedIdentities) @@ -513,7 +554,14 @@ describe('Identities routes', () => { isSystem: false, aliases: [ aliases.find((_alias) => _alias.identity_identifier === _identity.identity.identifier).alias - ].map(alias => ({ alias, status: 'ok', contested: false })) + ].map(alias => ({ alias, status: 'ok', contested: false })), + totalGasSpent: null, + averageGasSpent: null, + topUpsGasSpent: null, + withdrawalsGasSpent: null, + lastWithdrawalHash: null, + publicKeys: [], + fundingCoreTx: null })) assert.deepEqual(body.resultSet, expectedIdentities) @@ -572,7 +620,14 @@ describe('Identities routes', () => { isSystem: false, aliases: [ aliases.find((_alias) => _alias.identity_identifier === _identity.identity.identifier).alias - ].map(alias => ({ alias, status: 'ok', contested: false })) + ].map(alias => ({ alias, status: 'ok', contested: false })), + totalGasSpent: null, + averageGasSpent: null, + topUpsGasSpent: null, + withdrawalsGasSpent: null, + lastWithdrawalHash: null, + publicKeys: [], + fundingCoreTx: null })) assert.deepEqual(body.resultSet, expectedIdentities) @@ -643,7 +698,14 @@ describe('Identities routes', () => { isSystem: false, aliases: [ aliases.find((_alias) => _alias.identity_identifier === _identity.identity.identifier).alias - ].map(alias => ({ alias, status: 'ok', contested: false })) + ].map(alias => ({ alias, status: 'ok', contested: false })), + totalGasSpent: null, + averageGasSpent: null, + topUpsGasSpent: null, + withdrawalsGasSpent: null, + lastWithdrawalHash: null, + publicKeys: [], + fundingCoreTx: null })) assert.deepEqual(body.resultSet, expectedIdentities) diff --git a/packages/api/test/integration/main.spec.js b/packages/api/test/integration/main.spec.js index feea231d3..9ed3a7173 100644 --- a/packages/api/test/integration/main.spec.js +++ b/packages/api/test/integration/main.spec.js @@ -41,6 +41,8 @@ describe('Other routes', () => { mock.method(DAPI.prototype, 'getContestedState', async () => null) + mock.method(DAPI.prototype, 'getIdentityKeys', async () => null) + mock.method(tenderdashRpc, 'getBlockByHeight', async () => ({ block: { header: { @@ -69,6 +71,7 @@ describe('Other routes', () => { identityTransaction = await fixtures.transaction(knex, { block_hash: block.hash, type: StateTransitionEnum.IDENTITY_CREATE, + data: '', owner: identityIdentifier }) identity = await fixtures.identity(knex, { @@ -166,7 +169,7 @@ describe('Other routes', () => { blockHash: identityTransaction.block_hash, blockHeight: null, type: identityTransaction.type, - data: '{}', + data: '', timestamp: block.timestamp.toISOString(), gasUsed: 0, status: 'SUCCESS', @@ -357,7 +360,14 @@ describe('Other routes', () => { alias: 'dpns.dash', contested: false, status: 'ok' - }] + }], + totalGasSpent: 480000, + averageGasSpent: 9412, + topUpsGasSpent: 0, + withdrawalsGasSpent: 0, + lastWithdrawalHash: null, + publicKeys: [], + fundingCoreTx: null } assert.deepEqual({ identity: expectedIdentity }, body) diff --git a/packages/api/test/unit/mocks/identity_update.json b/packages/api/test/unit/mocks/identity_update.json index f5e0212ff..520586e16 100644 --- a/packages/api/test/unit/mocks/identity_update.json +++ b/packages/api/test/unit/mocks/identity_update.json @@ -1,3 +1,3 @@ { - "data": "BgAyBWaBbzZoA1F6frRNMxzLDkQvq2OW89asYxsQaargQQIDAgAFAgACAAAUwgje1tGvViuOU4fAKkRupui7Ml8AAAYAAAAAACECYhM4CTDJPEtT9t28WtxfUWUQLY+S99mklaj5xuYbMPBBH6+LDxYyDQ+eKcHbEqsNPsh5dLGfb8EYmpiM2FUD15+ETT/3eGeNf084KYkejo0Bg0VhlNn8du1m5QMVSZbu/gYAAABBHzQcjre4kPQWx6lwQG3TfaB42rXyxKqN0YN1UWkzsjSHMSeWXdcu4otzkvzYfijEv++JB5G1j6nDS86eltZTbLE=" + "data": "BgCJq5VMB9MR4JVtCuGSDgeH5c6cF7srhHbZoXYFw2sovAECAgAFAAEDAQEhg9fAj7DJvygNDNKZ/N8jWdubwwSLFkjsN3XxkOHHvQdjb250YWN0ACECO2On4jIdtj9dvSbgjjqh2pdEBP1rkwOQMZW+EP4S4rBBH1jVyO5Oh+bW//z+vKrcAwWZzE4Y5B89f3i9mTZm4UaXO+scpX4DZuzu8FEOO1WpfbdlEQ1P8HuWU9sjfYoCHVEABgACAwEBIYPXwI+wyb8oDQzSmfzfI1nbm8MEixZI7Dd18ZDhx70HY29udGFjdAAhAm6RicdvZnx3Talx1erO5XWs/XR8PqbKivNjb5Oshx9zQR/XU9v0Mfi+Vf5VRWeMBcqBobPPtnb/hf4iyvAEKyrYS0N8IDvxbq2NP2L3TYMtbKikkoBDQNNW8dADhWylDxcKAAAAQR8q7X3emMNvNeGlj6rBG07G+E9yzxUpQl8wgioJ8ichZxn+V2ocMDYbHMhqFJ39Lv8w8/1YkNyNHI93ifit4LXl" } diff --git a/packages/api/test/unit/utils.spec.js b/packages/api/test/unit/utils.spec.js index 56d887607..02a84ef28 100644 --- a/packages/api/test/unit/utils.spec.js +++ b/packages/api/test/unit/utils.spec.js @@ -229,38 +229,46 @@ describe('Utils', () => { assert.deepEqual(decoded, { type: 5, - identityContractNonce: 3, + identityContractNonce: 2, userFeeIncrease: 0, - identityId: '4NGALjtX2t3AXE3ZCqJiSmYuiWEY3ZPQNUBxNWWRrRSp', - revision: 2, + identityId: 'AGQc1dwAc46Js6fvSBSqV2Zi7fCq2YvoAwEb1SmYtXuM', + revision: 1, publicKeysToAdd: [ { - contractBounds: null, + contractBounds: { + type: 'documentType', + id: '3Fq4GuFDSaPm7qN2rG8chtif6jgZnqyY48rw9caUMGo6', + typeName: 'contact' + }, id: 5, - type: 'ECDSA_HASH160', - data: 'c208ded6d1af562b8e5387c02a446ea6e8bb325f', - publicKeyHash: 'c208ded6d1af562b8e5387c02a446ea6e8bb325f', - purpose: 'AUTHENTICATION', - securityLevel: 'HIGH', + type: 'ECDSA_SECP256K1', + data: '023b63a7e2321db63f5dbd26e08e3aa1da974404fd6b9303903195be10fe12e2b0', + publicKeyHash: 'aefbbefbbf99eee9e134c0657a13651a5692e98d', + purpose: 'ENCRYPTION', + securityLevel: 'MEDIUM', readOnly: false, - signature: '' + signature: '1f58d5c8ee4e87e6d6fffcfebcaadc030599cc4e18e41f3d7f78bd993666e146973beb1ca57e0366eceef0510e3b55a97db765110d4ff07b9653db237d8a021d51' }, { - contractBounds: null, + contractBounds: { + type: 'documentType', + id: '3Fq4GuFDSaPm7qN2rG8chtif6jgZnqyY48rw9caUMGo6', + typeName: 'contact' + }, id: 6, type: 'ECDSA_SECP256K1', - data: '026213380930c93c4b53f6ddbc5adc5f5165102d8f92f7d9a495a8f9c6e61b30f0', - publicKeyHash: 'd39eda042126256a372c388bd191532a7c9612ce', - purpose: 'AUTHENTICATION', - securityLevel: 'MASTER', + data: '026e9189c76f667c774da971d5eacee575acfd747c3ea6ca8af3636f93ac871f73', + publicKeyHash: '56db223d9e394d9a15db5064f9e19be3c40d20ff', + purpose: 'DECRYPTION', + securityLevel: 'MEDIUM', readOnly: false, - signature: '1faf8b0f16320d0f9e29c1db12ab0d3ec87974b19f6fc1189a988cd85503d79f844d3ff778678d7f4f3829891e8e8d0183456194d9fc76ed66e503154996eefe06' + signature: '1fd753dbf431f8be55fe5545678c05ca81a1b3cfb676ff85fe22caf0042b2ad84b437c203bf16ead8d3f62f74d832d6ca8a492804340d356f1d003856ca50f170a' } ], setPublicKeyIdsToDisable: [], - signature: '1f341c8eb7b890f416c7a970406dd37da078dab5f2c4aa8dd18375516933b234873127965dd72ee28b7392fcd87e28c4bfef890791b58fa9c34bce9e96d6536cb1', + signature: '1f2aed7dde98c36f35e1a58faac11b4ec6f84f72cf1529425f30822a09f227216719fe576a1c30361b1cc86a149dfd2eff30f3fd5890dc8d1c8f7789f8ade0b5e5', signaturePublicKeyId: 0, - raw: '0600320566816f366803517a7eb44d331ccb0e442fab6396f3d6ac631b1069aae0410203020005020002000014c208ded6d1af562b8e5387c02a446ea6e8bb325f000006000000000021026213380930c93c4b53f6ddbc5adc5f5165102d8f92f7d9a495a8f9c6e61b30f0411faf8b0f16320d0f9e29c1db12ab0d3ec87974b19f6fc1189a988cd85503d79f844d3ff778678d7f4f3829891e8e8d0183456194d9fc76ed66e503154996eefe06000000411f341c8eb7b890f416c7a970406dd37da078dab5f2c4aa8dd18375516933b234873127965dd72ee28b7392fcd87e28c4bfef890791b58fa9c34bce9e96d6536cb1' + raw: '060089ab954c07d311e0956d0ae1920e0787e5ce9c17bb2b8476d9a17605c36b28bc010202000500010301012183d7c08fb0c9bf280d0cd299fcdf2359db9bc3048b1648ec3775f190e1c7bd07636f6e746163740021023b63a7e2321db63f5dbd26e08e3aa1da974404fd6b9303903195be10fe12e2b0411f58d5c8ee4e87e6d6fffcfebcaadc030599cc4e18e41f3d7f78bd993666e146973beb1ca57e0366eceef0510e3b55a97db765110d4ff07b9653db237d8a021d51000600020301012183d7c08fb0c9bf280d0cd299fcdf2359db9bc3048b1648ec3775f190e1c7bd07636f6e746163740021026e9189c76f667c774da971d5eacee575acfd747c3ea6ca8af3636f93ac871f73411fd753dbf431f8be55fe5545678c05ca81a1b3cfb676ff85fe22caf0042b2ad84b437c203bf16ead8d3f62f74d832d6ca8a492804340d356f1d003856ca50f170a000000411f2aed7dde98c36f35e1a58faac11b4ec6f84f72cf1529425f30822a09f227216719fe576a1c30361b1cc86a149dfd2eff30f3fd5890dc8d1c8f7789f8ade0b5e5' }) }) diff --git a/packages/frontend/src/app/api/content.md b/packages/frontend/src/app/api/content.md index db08c3311..812978d93 100644 --- a/packages/frontend/src/app/api/content.md +++ b/packages/frontend/src/app/api/content.md @@ -710,24 +710,76 @@ Return identity by given identifier GET /identity/GWRSAVFMjXx8HpQFaNJMqBV7MBgMK4br5UESsB4S31Ec { - identifier: "GWRSAVFMjXx8HpQFaNJMqBV7MBgMK4br5UESsB4S31Ec", - owner: "GWRSAVFMjXx8HpQFaNJMqBV7MBgMK4br5UESsB4S31Ec", - revision: 1, - balance: 1000000, - timestamp: "2024-03-18T10:13:54.150Z", - txHash: "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF", - totalTxs: 1, - totalTransfers: 0, - totalDocuments: 0, - totalDataContracts: 0, - isSystem: false, - aliases: [ - { - alias: "alias.dash", - status: "locked", - contested: true - } - ] + "identifier": "3igSMtXaaS9iRQHbWU1w4hHveKdxixwMpgmhLzjVhFZJ", + "revision": 0, + "balance": 49989647300, + "timestamp": "2024-10-12T18:51:44.592Z", + "txHash": "32FB988D87E4122A2FE030B5014A59A05786C1501FD97D765E2329F89A8AD01D", + "totalTxs": 13, + "totalTransfers": 7, + "totalDocuments": 5, + "totalDataContracts": 0, + "isSystem": false, + "aliases": [ + { + "alias": "owl352.dash", + "status": "ok", + "contested": false + } + ], + "totalGasSpent": 310352700, + "averageGasSpent": 23873285, + "topUpsGasSpent": 46350660, + "withdrawalsGasSpent": 0, + "lastWithdrawalHash": null, + "publicKeys": [ + { + "keyId": 0, + "type": 0, + "data": "0386067dea94b1cfb23bf252084a2020a4a6712df7e4ac16c211558a1dbb66904a", + "purpose": 0, + "securityLevel": 0, + "isReadOnly": false, + "isMaster": true, + "hash": "5501114f5842004d1ff6c7d04512c438afe0cb11", + "contractBounds": null + }, + { + "keyId": 1, + "type": 0, + "data": "038a09509830d2d04685294e920aa29c96d51f9bd81044e2f934a4c198b934b102", + "purpose": 0, + "securityLevel": 2, + "isReadOnly": false, + "isMaster": false, + "hash": "c563c11128b9e457ad3b7220315b4bf53c8af443", + "contractBounds": null + }, + { + "keyId": 2, + "type": 0, + "data": "027734bd9b8864964eb7504a77a986782e9d620e4c6d23e2bd80359e1e81790a1c", + "purpose": 0, + "securityLevel": 1, + "isReadOnly": false, + "isMaster": false, + "hash": "4bd1a43ea0cf7c18c1f90d1d9c0f08c63743ff1d", + "contractBounds": null + }, + { + "keyId": 3, + "type": 0, + "data": "03083620dea1216b47568aead0c7cb6302ae3ca8beaa40c51e25b20f1f02ae06d4", + "purpose": 3, + "securityLevel": 1, + "isReadOnly": false, + "isMaster": false, + "hash": "f6d941f2d7aa4bc9d90b90bc103bd583c5943af9", + "contractBounds": null + } + ], + "fundingCoreTx": "68d77e0d2da31e9cf2758d8f97547c1bc98b75c4e2cebe64dbcaae3bb5cb8a9c", + "owner": "3igSMtXaaS9iRQHbWU1w4hHveKdxixwMpgmhLzjVhFZJ" } ``` Response codes: